Revert "Refactor proxies to nextpnr."

This reverts commit 9b17fe385c.
This commit is contained in:
Sergiusz Bazanski 2018-07-14 18:50:37 +01:00
parent d9c3c117a3
commit b0c05c7f75
10 changed files with 197 additions and 221 deletions

View File

@ -21,17 +21,6 @@
NEXTPNR_NAMESPACE_BEGIN NEXTPNR_NAMESPACE_BEGIN
MutateContext BaseCtx::rwproxy(void)
{
return MutateContext(reinterpret_cast<Arch *>(this));
}
ReadContext BaseCtx::rproxy(void) const
{
return ReadContext(reinterpret_cast<const Arch *>(this));
}
assertion_failure::assertion_failure(std::string msg, std::string expr_str, std::string filename, int line) assertion_failure::assertion_failure(std::string msg, std::string expr_str, std::string filename, int line)
: runtime_error("Assertion failure: " + msg + " (" + filename + ":" + std::to_string(line) + ")"), msg(msg), : runtime_error("Assertion failure: " + msg + " (" + filename + ":" + std::to_string(line) + ")"), msg(msg),
expr_str(expr_str), filename(filename), line(line) expr_str(expr_str), filename(filename), line(line)

View File

@ -26,7 +26,6 @@
#include <unordered_map> #include <unordered_map>
#include <unordered_set> #include <unordered_set>
#include <vector> #include <vector>
#include <boost/thread/shared_mutex.hpp>
#ifndef NEXTPNR_H #ifndef NEXTPNR_H
#define NEXTPNR_H #define NEXTPNR_H
@ -249,38 +248,22 @@ struct UIUpdatesRequired
std::unordered_set<GroupId> groupUIReload; std::unordered_set<GroupId> groupUIReload;
}; };
class ReadContext; struct BaseCtx
class MutateContext;
class BaseReadCtx;
class BaseMutateCtx;
// Data that every architecture object should contain.
class BaseCtx
{ {
friend class ReadContext; // --------------------------------------------------------------
friend class MutateContext;
friend class BaseReadCtx;
friend class BaseMutateCtx;
private:
mutable boost::shared_mutex mtx_;
bool allUiReload = false;
bool frameUiReload = false;
std::unordered_set<BelId> belUiReload;
std::unordered_set<WireId> wireUiReload;
std::unordered_set<PipId> pipUiReload;
std::unordered_set<GroupId> groupUiReload;
public:
IdString id(const std::string &s) const { return IdString(this, s); }
IdString id(const char *s) const { return IdString(this, s); }
// TODO(q3k): These need to be made private.
std::unordered_map<IdString, std::unique_ptr<NetInfo>> nets;
std::unordered_map<IdString, std::unique_ptr<CellInfo>> cells;
mutable std::unordered_map<std::string, int> *idstring_str_to_idx; mutable std::unordered_map<std::string, int> *idstring_str_to_idx;
mutable std::vector<const std::string *> *idstring_idx_to_str; mutable std::vector<const std::string *> *idstring_idx_to_str;
IdString id(const std::string &s) const { return IdString(this, s); }
IdString id(const char *s) const { return IdString(this, s); }
// --------------------------------------------------------------
std::unordered_map<IdString, std::unique_ptr<NetInfo>> nets;
std::unordered_map<IdString, std::unique_ptr<CellInfo>> cells;
BaseCtx() BaseCtx()
{ {
idstring_str_to_idx = new std::unordered_map<std::string, int>; idstring_str_to_idx = new std::unordered_map<std::string, int>;
@ -303,83 +286,41 @@ public:
// -------------------------------------------------------------- // --------------------------------------------------------------
// Get a readwrite proxy to arch - this will keep a readwrite lock on the bool allUiReload = false;
// entire architecture until the proxy object goes out of scope. bool frameUiReload = false;
MutateContext rwproxy(void); std::unordered_set<BelId> belUiReload;
// Get a read-only proxy to arch - this will keep a read lock on the std::unordered_set<WireId> wireUiReload;
// entire architecture until the proxy object goes out of scope. Other read std::unordered_set<PipId> pipUiReload;
// locks can be taken while this one still exists. Ie., the UI can draw std::unordered_set<GroupId> groupUiReload;
// elements while the PnR is going a RO operation.
ReadContext rproxy(void) const;
}; void refreshUi() { allUiReload = true; }
// State-accessing read-only methods that every architecture object should void refreshUiFrame() { frameUiReload = true; }
// contain.
class BaseReadCtx
{
protected:
const BaseCtx *base_;
public:
BaseReadCtx(const BaseCtx *base) : base_(base) {}
};
// State-accesssing read/write methods that every architecture object should void refreshUiBel(BelId bel) { belUiReload.insert(bel); }
// contain.
class BaseMutateCtx
{
protected:
BaseCtx *base_;
public: void refreshUiWire(WireId wire) { wireUiReload.insert(wire); }
BaseMutateCtx(BaseCtx *base) : base_(base) {}
void refreshUi(void) void refreshUiPip(PipId pip) { pipUiReload.insert(pip); }
{
base_->allUiReload = true;
}
void refreshUiFrame(void) void refreshUiGroup(GroupId group) { groupUiReload.insert(group); }
{
base_->frameUiReload = true;
}
void refreshUiBel(BelId bel)
{
base_->belUiReload.insert(bel);
}
void refreshUiWire(WireId wire)
{
base_->wireUiReload.insert(wire);
}
void refreshUiPip(PipId pip)
{
base_->pipUiReload.insert(pip);
}
void refreshUiGroup(GroupId group)
{
base_->groupUiReload.insert(group);
}
UIUpdatesRequired getUIUpdatesRequired(void) UIUpdatesRequired getUIUpdatesRequired(void)
{ {
UIUpdatesRequired req; UIUpdatesRequired req;
req.allUIReload = base_->allUiReload; req.allUIReload = allUiReload;
req.frameUIReload = base_->frameUiReload; req.frameUIReload = frameUiReload;
req.belUIReload = base_->belUiReload; req.belUIReload = belUiReload;
req.wireUIReload = base_->wireUiReload; req.wireUIReload = wireUiReload;
req.pipUIReload = base_->pipUiReload; req.pipUIReload = pipUiReload;
req.groupUIReload = base_->groupUiReload; req.groupUIReload = groupUiReload;
base_->allUiReload = false; allUiReload = false;
base_->frameUiReload = false; frameUiReload = false;
base_->belUiReload.clear(); belUiReload.clear();
base_->wireUiReload.clear(); wireUiReload.clear();
base_->pipUiReload.clear(); pipUiReload.clear();
base_->groupUiReload.clear(); groupUiReload.clear();
return req; return req;
} }
}; };
@ -390,53 +331,6 @@ NEXTPNR_NAMESPACE_END
NEXTPNR_NAMESPACE_BEGIN NEXTPNR_NAMESPACE_BEGIN
// Read proxy to access ReadMethods while holding lock on underlying BaseCtx.
class ReadContext : public ArchReadMethods
{
friend class BaseCtx;
private:
boost::shared_mutex *lock_;
ReadContext(const Arch *parent) : ArchReadMethods(parent), lock_(&parent->mtx_)
{
lock_->lock_shared();
}
public:
~ReadContext()
{
if (lock_ != nullptr) {
lock_->unlock_shared();
}
}
ReadContext(ReadContext &&other): ArchReadMethods(other), lock_(other.lock_)
{
other.lock_ = nullptr;
}
};
// Read proxy to access MutateMethods while holding lock on underlying BaseCtx.
class MutateContext : public ArchReadMethods, public ArchMutateMethods
{
friend class BaseCtx;
private:
boost::shared_mutex *lock_;
MutateContext(Arch *parent) : ArchReadMethods(parent), ArchMutateMethods(parent), lock_(&parent->mtx_)
{
lock_->lock();
}
public:
~MutateContext()
{
if (lock_ != nullptr) {
lock_->unlock();
}
}
MutateContext(MutateContext &&other): ArchReadMethods(other), ArchMutateMethods(other), lock_(other.lock_)
{
other.lock_ = nullptr;
}
};
struct Context : Arch struct Context : Arch
{ {
bool verbose = false; bool verbose = false;

View File

@ -26,7 +26,7 @@
NEXTPNR_NAMESPACE_BEGIN NEXTPNR_NAMESPACE_BEGIN
// Placing a single cell // Placing a single cell
bool place_single_cell(MutateContext &proxy, Context *ctx, CellInfo *cell, bool require_legality) bool place_single_cell(ArchRWProxy &proxy, Context *ctx, CellInfo *cell, bool require_legality)
{ {
bool all_placed = false; bool all_placed = false;
int iters = 25; int iters = 25;

View File

@ -109,7 +109,7 @@ wirelen_t get_cell_wirelength_at_bel(const T &proxy, const Context *ctx, CellInf
} }
// Place a single cell in the lowest wirelength Bel available, optionally requiring validity check // Place a single cell in the lowest wirelength Bel available, optionally requiring validity check
bool place_single_cell(MutateContext &proxy, Context *ctx, CellInfo *cell, bool require_legality); bool place_single_cell(ArchRWProxy &proxy, Context *ctx, CellInfo *cell, bool require_legality);
NEXTPNR_NAMESPACE_END NEXTPNR_NAMESPACE_END

View File

@ -275,7 +275,7 @@ class SAPlacer
private: private:
// Initial random placement // Initial random placement
void place_initial(MutateContext &proxy, CellInfo *cell) void place_initial(ArchRWProxy &proxy, CellInfo *cell)
{ {
bool all_placed = false; bool all_placed = false;
int iters = 25; int iters = 25;
@ -325,7 +325,7 @@ class SAPlacer
} }
// Attempt a SA position swap, return true on success or false on failure // Attempt a SA position swap, return true on success or false on failure
bool try_swap_position(MutateContext &proxy, CellInfo *cell, BelId newBel) bool try_swap_position(ArchRWProxy &proxy, CellInfo *cell, BelId newBel)
{ {
static std::unordered_set<NetInfo *> update; static std::unordered_set<NetInfo *> update;
static std::vector<std::pair<IdString, wirelen_t>> new_lengths; static std::vector<std::pair<IdString, wirelen_t>> new_lengths;

View File

@ -74,7 +74,7 @@ struct RipupScoreboard
std::unordered_map<std::pair<IdString, PipId>, int, hash_id_pip> netPipScores; std::unordered_map<std::pair<IdString, PipId>, int, hash_id_pip> netPipScores;
}; };
void ripup_net(MutateContext &proxy, Context *ctx, IdString net_name) void ripup_net(ArchRWProxy &proxy, Context *ctx, IdString net_name)
{ {
auto net_info = ctx->nets.at(net_name).get(); auto net_info = ctx->nets.at(net_name).get();
std::vector<PipId> pips; std::vector<PipId> pips;
@ -115,7 +115,7 @@ struct Router
delay_t maxDelay = 0.0; delay_t maxDelay = 0.0;
WireId failedDest; WireId failedDest;
void route(MutateContext &proxy, const std::unordered_map<WireId, delay_t> &src_wires, WireId dst_wire) void route(ArchRWProxy &proxy, const std::unordered_map<WireId, delay_t> &src_wires, WireId dst_wire)
{ {
std::priority_queue<QueuedWire, std::vector<QueuedWire>, QueuedWire::Greater> queue; std::priority_queue<QueuedWire, std::vector<QueuedWire>, QueuedWire::Greater> queue;

View File

@ -29,6 +29,18 @@
NEXTPNR_NAMESPACE_BEGIN NEXTPNR_NAMESPACE_BEGIN
ArchRWProxy Arch::rwproxy(void) {
ArchRWProxy res(this);
return res;
}
ArchRProxy Arch::rproxy(void) const {
ArchRProxy res(this);
return res;
}
// -----------------------------------------------------------------------
IdString Arch::belTypeToId(BelType type) const IdString Arch::belTypeToId(BelType type) const
{ {
if (type == TYPE_ICESTORM_LC) if (type == TYPE_ICESTORM_LC)
@ -522,7 +534,7 @@ DecalXY Arch::getGroupDecal(GroupId group) const
return decalxy; return decalxy;
}; };
std::vector<GraphicElement> ArchReadMethods::getDecalGraphics(DecalId decal) const std::vector<GraphicElement> ArchRProxyMethods::getDecalGraphics(DecalId decal) const
{ {
std::vector<GraphicElement> ret; std::vector<GraphicElement> ret;
@ -720,25 +732,25 @@ bool Arch::isGlobalNet(const NetInfo *net) const
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
bool ArchReadMethods::checkBelAvail(BelId bel) const bool ArchRProxyMethods::checkBelAvail(BelId bel) const
{ {
NPNR_ASSERT(bel != BelId()); NPNR_ASSERT(bel != BelId());
return bel_to_cell[bel.index] == IdString(); return bel_to_cell[bel.index] == IdString();
} }
IdString ArchReadMethods::getBoundBelCell(BelId bel) const IdString ArchRProxyMethods::getBoundBelCell(BelId bel) const
{ {
NPNR_ASSERT(bel != BelId()); NPNR_ASSERT(bel != BelId());
return bel_to_cell[bel.index]; return bel_to_cell[bel.index];
} }
IdString ArchReadMethods::getConflictingBelCell(BelId bel) const IdString ArchRProxyMethods::getConflictingBelCell(BelId bel) const
{ {
NPNR_ASSERT(bel != BelId()); NPNR_ASSERT(bel != BelId());
return bel_to_cell[bel.index]; return bel_to_cell[bel.index];
} }
WireId ArchReadMethods::getWireBelPin(BelId bel, PortPin pin) const WireId ArchRProxyMethods::getWireBelPin(BelId bel, PortPin pin) const
{ {
WireId ret; WireId ret;
@ -756,7 +768,7 @@ WireId ArchReadMethods::getWireBelPin(BelId bel, PortPin pin) const
return ret; return ret;
} }
WireId ArchReadMethods::getWireByName(IdString name) const WireId ArchRProxyMethods::getWireByName(IdString name) const
{ {
WireId ret; WireId ret;
@ -772,25 +784,25 @@ WireId ArchReadMethods::getWireByName(IdString name) const
return ret; return ret;
} }
bool ArchReadMethods::checkWireAvail(WireId wire) const bool ArchRProxyMethods::checkWireAvail(WireId wire) const
{ {
NPNR_ASSERT(wire != WireId()); NPNR_ASSERT(wire != WireId());
return wire_to_net[wire.index] == IdString(); return wire_to_net[wire.index] == IdString();
} }
IdString ArchReadMethods::getBoundWireNet(WireId wire) const IdString ArchRProxyMethods::getBoundWireNet(WireId wire) const
{ {
NPNR_ASSERT(wire != WireId()); NPNR_ASSERT(wire != WireId());
return wire_to_net[wire.index]; return wire_to_net[wire.index];
} }
IdString ArchReadMethods::getConflictingWireNet(WireId wire) const IdString ArchRProxyMethods::getConflictingWireNet(WireId wire) const
{ {
NPNR_ASSERT(wire != WireId()); NPNR_ASSERT(wire != WireId());
return wire_to_net[wire.index]; return wire_to_net[wire.index];
} }
PipId ArchReadMethods::getPipByName(IdString name) const PipId ArchRProxyMethods::getPipByName(IdString name) const
{ {
PipId ret; PipId ret;
@ -809,25 +821,25 @@ PipId ArchReadMethods::getPipByName(IdString name) const
return ret; return ret;
} }
bool ArchReadMethods::checkPipAvail(PipId pip) const bool ArchRProxyMethods::checkPipAvail(PipId pip) const
{ {
NPNR_ASSERT(pip != PipId()); NPNR_ASSERT(pip != PipId());
return switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString(); return switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString();
} }
IdString ArchReadMethods::getBoundPipNet(PipId pip) const IdString ArchRProxyMethods::getBoundPipNet(PipId pip) const
{ {
NPNR_ASSERT(pip != PipId()); NPNR_ASSERT(pip != PipId());
return pip_to_net[pip.index]; return pip_to_net[pip.index];
} }
IdString ArchReadMethods::getConflictingPipNet(PipId pip) const IdString ArchRProxyMethods::getConflictingPipNet(PipId pip) const
{ {
NPNR_ASSERT(pip != PipId()); NPNR_ASSERT(pip != PipId());
return switches_locked[chip_info->pip_data[pip.index].switch_index]; return switches_locked[chip_info->pip_data[pip.index].switch_index];
} }
BelId ArchReadMethods::getBelByName(IdString name) const BelId ArchRProxyMethods::getBelByName(IdString name) const
{ {
BelId ret; BelId ret;
@ -845,27 +857,27 @@ BelId ArchReadMethods::getBelByName(IdString name) const
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
void ArchMutateMethods::bindBel(BelId bel, IdString cell, PlaceStrength strength) void ArchRWProxyMethods::bindBel(BelId bel, IdString cell, PlaceStrength strength)
{ {
NPNR_ASSERT(bel != BelId()); NPNR_ASSERT(bel != BelId());
NPNR_ASSERT(bel_to_cell[bel.index] == IdString()); NPNR_ASSERT(bel_to_cell[bel.index] == IdString());
bel_to_cell[bel.index] = cell; bel_to_cell[bel.index] = cell;
parent_->cells[cell]->bel = bel; parent_->cells[cell]->bel = bel;
parent_->cells[cell]->belStrength = strength; parent_->cells[cell]->belStrength = strength;
refreshUiBel(bel); parent_->refreshUiBel(bel);
} }
void ArchMutateMethods::unbindBel(BelId bel) void ArchRWProxyMethods::unbindBel(BelId bel)
{ {
NPNR_ASSERT(bel != BelId()); NPNR_ASSERT(bel != BelId());
NPNR_ASSERT(bel_to_cell[bel.index] != IdString()); NPNR_ASSERT(bel_to_cell[bel.index] != IdString());
parent_->cells[bel_to_cell[bel.index]]->bel = BelId(); parent_->cells[bel_to_cell[bel.index]]->bel = BelId();
parent_->cells[bel_to_cell[bel.index]]->belStrength = STRENGTH_NONE; parent_->cells[bel_to_cell[bel.index]]->belStrength = STRENGTH_NONE;
bel_to_cell[bel.index] = IdString(); bel_to_cell[bel.index] = IdString();
refreshUiBel(bel); parent_->refreshUiBel(bel);
} }
void ArchMutateMethods::bindWire(WireId wire, IdString net, PlaceStrength strength) void ArchRWProxyMethods::bindWire(WireId wire, IdString net, PlaceStrength strength)
{ {
NPNR_ASSERT(wire != WireId()); NPNR_ASSERT(wire != WireId());
NPNR_ASSERT(wire_to_net[wire.index] == IdString()); NPNR_ASSERT(wire_to_net[wire.index] == IdString());
@ -873,10 +885,10 @@ void ArchMutateMethods::bindWire(WireId wire, IdString net, PlaceStrength streng
wire_to_net[wire.index] = net; wire_to_net[wire.index] = net;
parent_->nets[net]->wires[wire].pip = PipId(); parent_->nets[net]->wires[wire].pip = PipId();
parent_->nets[net]->wires[wire].strength = strength; parent_->nets[net]->wires[wire].strength = strength;
refreshUiWire(wire); parent_->refreshUiWire(wire);
} }
void ArchMutateMethods::unbindWire(WireId wire) void ArchRWProxyMethods::unbindWire(WireId wire)
{ {
NPNR_ASSERT(wire != WireId()); NPNR_ASSERT(wire != WireId());
NPNR_ASSERT(wire_to_net[wire.index] != IdString()); NPNR_ASSERT(wire_to_net[wire.index] != IdString());
@ -889,15 +901,15 @@ void ArchMutateMethods::unbindWire(WireId wire)
if (pip != PipId()) { if (pip != PipId()) {
pip_to_net[pip.index] = IdString(); pip_to_net[pip.index] = IdString();
switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString(); switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString();
refreshUiPip(pip); parent_->refreshUiPip(pip);
} }
net_wires.erase(it); net_wires.erase(it);
wire_to_net[wire.index] = IdString(); wire_to_net[wire.index] = IdString();
refreshUiWire(wire); parent_->refreshUiWire(wire);
} }
void ArchMutateMethods::bindPip(PipId pip, IdString net, PlaceStrength strength) void ArchRWProxyMethods::bindPip(PipId pip, IdString net, PlaceStrength strength)
{ {
NPNR_ASSERT(pip != PipId()); NPNR_ASSERT(pip != PipId());
NPNR_ASSERT(pip_to_net[pip.index] == IdString()); NPNR_ASSERT(pip_to_net[pip.index] == IdString());
@ -913,11 +925,11 @@ void ArchMutateMethods::bindPip(PipId pip, IdString net, PlaceStrength strength)
parent_->nets[net]->wires[dst].pip = pip; parent_->nets[net]->wires[dst].pip = pip;
parent_->nets[net]->wires[dst].strength = strength; parent_->nets[net]->wires[dst].strength = strength;
refreshUiPip(pip); parent_->refreshUiPip(pip);
refreshUiWire(dst); parent_->refreshUiWire(dst);
} }
void ArchMutateMethods::unbindPip(PipId pip) void ArchRWProxyMethods::unbindPip(PipId pip)
{ {
NPNR_ASSERT(pip != PipId()); NPNR_ASSERT(pip != PipId());
NPNR_ASSERT(pip_to_net[pip.index] != IdString()); NPNR_ASSERT(pip_to_net[pip.index] != IdString());
@ -932,13 +944,18 @@ void ArchMutateMethods::unbindPip(PipId pip)
pip_to_net[pip.index] = IdString(); pip_to_net[pip.index] = IdString();
switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString(); switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString();
refreshUiPip(pip); parent_->refreshUiPip(pip);
refreshUiWire(dst); parent_->refreshUiWire(dst);
} }
CellInfo *ArchMutateMethods::getCell(IdString cell) CellInfo *ArchRWProxyMethods::getCell(IdString cell)
{ {
return parent_->cells.at(cell).get(); return parent_->cells.at(cell).get();
} }
UIUpdatesRequired ArchRWProxyMethods::getUIUpdatesRequired(void)
{
return parent_->getUIUpdatesRequired();
}
NEXTPNR_NAMESPACE_END NEXTPNR_NAMESPACE_END

View File

@ -22,6 +22,9 @@
#error Include "arch.h" via "nextpnr.h" only. #error Include "arch.h" via "nextpnr.h" only.
#endif #endif
#include <boost/thread/shared_lock_guard.hpp>
#include <boost/thread/shared_mutex.hpp>
NEXTPNR_NAMESPACE_BEGIN NEXTPNR_NAMESPACE_BEGIN
/**** Everything in this section must be kept in sync with chipdb.py ****/ /**** Everything in this section must be kept in sync with chipdb.py ****/
@ -327,8 +330,11 @@ struct ArchArgs
/// Forward declare proxy classes for Arch. /// Forward declare proxy classes for Arch.
class ArchMutateMethods; class ArchRWProxyMethods;
class ArchReadMethods; class ArchRProxyMethods;
class ArchRWProxy;
class ArchRProxy;
/// Arch/Context /// Arch/Context
// Arch is the main state class of the PnR algorithms. It keeps note of mapped // Arch is the main state class of the PnR algorithms. It keeps note of mapped
@ -341,8 +347,11 @@ class ArchReadMethods;
class Arch : public BaseCtx class Arch : public BaseCtx
{ {
// We let proxy methods access our state. // We let proxy methods access our state.
friend class ArchMutateMethods; friend class ArchRWProxyMethods;
friend class ArchReadMethods; friend class ArchRProxyMethods;
// We let proxy objects access our mutex.
friend class ArchRWProxy;
friend class ArchRProxy;
private: private:
// All of the following... // All of the following...
std::vector<IdString> bel_to_cell; std::vector<IdString> bel_to_cell;
@ -353,6 +362,9 @@ private:
mutable std::unordered_map<IdString, int> wire_by_name; mutable std::unordered_map<IdString, int> wire_by_name;
mutable std::unordered_map<IdString, int> pip_by_name; mutable std::unordered_map<IdString, int> pip_by_name;
// ... are guarded by the following lock:
mutable boost::shared_mutex mtx_;
public: public:
const ChipInfoPOD *chip_info; const ChipInfoPOD *chip_info;
const PackageInfoPOD *package_info; const PackageInfoPOD *package_info;
@ -360,6 +372,15 @@ public:
ArchArgs args; ArchArgs args;
Arch(ArchArgs args); Arch(ArchArgs args);
// Get a readwrite proxy to arch - this will keep a readwrite lock on the
// entire architecture until the proxy object goes out of scope.
ArchRWProxy rwproxy(void);
// Get a read-only proxy to arch - this will keep a read lock on the
// entire architecture until the proxy object goes out of scope. Other read
// locks can be taken while this one still exists. Ie., the UI can draw
// elements while the PnR is going a RO operation.
ArchRProxy rproxy(void) const;
std::string getChipName(); std::string getChipName();
IdString archId() const { return id("ice40"); } IdString archId() const { return id("ice40"); }
@ -611,9 +632,22 @@ public:
}; };
// Read-only methods on Arch that require state access. // Read-only methods on Arch that require state access.
class ArchReadMethods : public BaseReadCtx { class ArchRProxyMethods {
// We let proxy objects access our private constructors.
friend class ArchRProxy;
friend class ArchRWProxy;
private: private:
const Arch *parent_; const Arch *parent_;
ArchRProxyMethods(const Arch *parent) : parent_(parent), chip_info(parent->chip_info),
bel_to_cell(parent->bel_to_cell), wire_to_net(parent->wire_to_net),
pip_to_net(parent->pip_to_net), switches_locked(parent->switches_locked),
bel_by_name(parent->bel_by_name), wire_by_name(parent->wire_by_name),
pip_by_name(parent->pip_by_name) {}
ArchRProxyMethods(ArchRProxyMethods &&other) noexcept : ArchRProxyMethods(other.parent_) {}
ArchRProxyMethods(const ArchRProxyMethods &other) : ArchRProxyMethods(other.parent_) {}
// Let methods access hot members directly without having to go through
// parent_.
const ChipInfoPOD *chip_info; const ChipInfoPOD *chip_info;
const std::vector<IdString> &bel_to_cell; const std::vector<IdString> &bel_to_cell;
const std::vector<IdString> &wire_to_net; const std::vector<IdString> &wire_to_net;
@ -622,17 +656,8 @@ private:
std::unordered_map<IdString, int> &bel_by_name; std::unordered_map<IdString, int> &bel_by_name;
std::unordered_map<IdString, int> &wire_by_name; std::unordered_map<IdString, int> &wire_by_name;
std::unordered_map<IdString, int> &pip_by_name; std::unordered_map<IdString, int> &pip_by_name;
public: public:
~ArchReadMethods() noexcept { } ~ArchRProxyMethods() noexcept { }
ArchReadMethods(const Arch *parent) : BaseReadCtx(parent), parent_(parent),
chip_info(parent->chip_info), bel_to_cell(parent->bel_to_cell),
wire_to_net(parent->wire_to_net), pip_to_net(parent->pip_to_net),
switches_locked(parent->switches_locked),
bel_by_name(parent->bel_by_name), wire_by_name(parent->wire_by_name),
pip_by_name(parent->pip_by_name) {}
ArchReadMethods(ArchReadMethods &&other) noexcept : ArchReadMethods(other.parent_) {}
ArchReadMethods(const ArchReadMethods &other) : ArchReadMethods(other.parent_) {}
/// Perform placement validity checks, returning false on failure (all implemented in arch_place.cc) /// Perform placement validity checks, returning false on failure (all implemented in arch_place.cc)
@ -668,11 +693,44 @@ public:
std::vector<GraphicElement> getDecalGraphics(DecalId decal) const; std::vector<GraphicElement> getDecalGraphics(DecalId decal) const;
}; };
// A proxy object that keeps an Arch shared/readonly lock until it goes out
// of scope. All const/read-only ArchRProxyMethods are available on it.
class ArchRProxy : public ArchRProxyMethods {
friend class Arch;
friend class ArchRWProxy;
private:
boost::shared_mutex *lock_;
ArchRProxy(const Arch *parent) : ArchRProxyMethods(parent), lock_(&parent->mtx_)
{
lock_->lock_shared();
}
public:
~ArchRProxy() {
if (lock_ != nullptr) {
lock_->unlock_shared();
}
}
ArchRProxy(ArchRProxy &&other) : ArchRProxyMethods(other), lock_(other.lock_)
{
other.lock_ = nullptr;
}
};
// State mutating methods on Arch. // State mutating methods on Arch.
class ArchMutateMethods : public BaseMutateCtx { class ArchRWProxyMethods {
friend class MutateContext; // We let proxy objects access our private constructors.
friend class ArchRWProxy;
private: private:
Arch *parent_; Arch *parent_;
ArchRWProxyMethods(Arch *parent) : parent_(parent), chip_info(parent->chip_info),
bel_to_cell(parent->bel_to_cell), wire_to_net(parent->wire_to_net),
pip_to_net(parent->pip_to_net), switches_locked(parent->switches_locked),
bel_by_name(parent->bel_by_name), wire_by_name(parent->wire_by_name),
pip_by_name(parent->pip_by_name) {}
ArchRWProxyMethods(ArchRWProxyMethods &&other) : ArchRWProxyMethods(other.parent_) {}
ArchRWProxyMethods(const ArchRWProxyMethods &other) : ArchRWProxyMethods(other.parent_) {}
const ChipInfoPOD *chip_info; const ChipInfoPOD *chip_info;
std::vector<IdString> &bel_to_cell; std::vector<IdString> &bel_to_cell;
std::vector<IdString> &wire_to_net; std::vector<IdString> &wire_to_net;
@ -681,17 +739,8 @@ private:
std::unordered_map<IdString, int> &bel_by_name; std::unordered_map<IdString, int> &bel_by_name;
std::unordered_map<IdString, int> &wire_by_name; std::unordered_map<IdString, int> &wire_by_name;
std::unordered_map<IdString, int> &pip_by_name; std::unordered_map<IdString, int> &pip_by_name;
public: public:
ArchMutateMethods(Arch *parent) : BaseMutateCtx(parent), parent_(parent), ~ArchRWProxyMethods() {}
chip_info(parent->chip_info), bel_to_cell(parent->bel_to_cell),
wire_to_net(parent->wire_to_net), pip_to_net(parent->pip_to_net),
switches_locked(parent->switches_locked),
bel_by_name(parent->bel_by_name), wire_by_name(parent->wire_by_name),
pip_by_name(parent->pip_by_name) {}
ArchMutateMethods(ArchMutateMethods &&other) : ArchMutateMethods(other.parent_) {}
ArchMutateMethods(const ArchMutateMethods &other) : ArchMutateMethods(other.parent_) {}
~ArchMutateMethods() {}
void unbindWire(WireId wire); void unbindWire(WireId wire);
void unbindPip(PipId pip); void unbindPip(PipId pip);
@ -701,6 +750,33 @@ public:
void bindBel(BelId bel, IdString cell, PlaceStrength strength); void bindBel(BelId bel, IdString cell, PlaceStrength strength);
// Returned pointer is valid as long as Proxy object exists. // Returned pointer is valid as long as Proxy object exists.
CellInfo *getCell(IdString cell); CellInfo *getCell(IdString cell);
// Methods to be used by UI for detecting whether we need to redraw.
UIUpdatesRequired getUIUpdatesRequired(void);
};
// A proxy object that keeps an Arch readwrite lock until it goes out of scope.
// All ArchRProxyMethods and ArchRWProxyMethods are available on it.
class ArchRWProxy : public ArchRProxyMethods, public ArchRWProxyMethods {
friend class Arch;
private:
boost::shared_mutex *lock_;
ArchRWProxy(Arch *parent) : ArchRProxyMethods(parent), ArchRWProxyMethods(parent), lock_(&parent->mtx_) {
lock_->lock();
}
public:
ArchRWProxy(ArchRWProxy &&other) : ArchRProxyMethods(other), ArchRWProxyMethods(other), lock_(other.lock_)
{
other.lock_ = nullptr;
}
~ArchRWProxy()
{
if (lock_ != nullptr) {
lock_->unlock();
}
}
}; };
NEXTPNR_NAMESPACE_END NEXTPNR_NAMESPACE_END

View File

@ -25,7 +25,7 @@
NEXTPNR_NAMESPACE_BEGIN NEXTPNR_NAMESPACE_BEGIN
bool ArchReadMethods::logicCellsCompatible(const std::vector<const CellInfo *> &cells) const bool ArchRProxyMethods::logicCellsCompatible(const std::vector<const CellInfo *> &cells) const
{ {
bool dffs_exist = false, dffs_neg = false; bool dffs_exist = false, dffs_neg = false;
const NetInfo *cen = nullptr, *clk = nullptr, *sr = nullptr; const NetInfo *cen = nullptr, *clk = nullptr, *sr = nullptr;
@ -76,7 +76,7 @@ bool ArchReadMethods::logicCellsCompatible(const std::vector<const CellInfo *> &
return locals_count <= 32; return locals_count <= 32;
} }
bool ArchReadMethods::isBelLocationValid(BelId bel) const bool ArchRProxyMethods::isBelLocationValid(BelId bel) const
{ {
if (parent_->getBelType(bel) == TYPE_ICESTORM_LC) { if (parent_->getBelType(bel) == TYPE_ICESTORM_LC) {
std::vector<const CellInfo *> bel_cells; std::vector<const CellInfo *> bel_cells;
@ -97,7 +97,7 @@ bool ArchReadMethods::isBelLocationValid(BelId bel) const
} }
} }
bool ArchReadMethods::isValidBelForCell(CellInfo *cell, BelId bel) const bool ArchRProxyMethods::isValidBelForCell(CellInfo *cell, BelId bel) const
{ {
if (cell->type == parent_->id_icestorm_lc) { if (cell->type == parent_->id_icestorm_lc) {
NPNR_ASSERT(parent_->getBelType(bel) == TYPE_ICESTORM_LC); NPNR_ASSERT(parent_->getBelType(bel) == TYPE_ICESTORM_LC);

View File

@ -253,7 +253,7 @@ class PlacementLegaliser
} }
// Find Bel closest to a location, meeting chain requirements // Find Bel closest to a location, meeting chain requirements
std::tuple<int, int, int> find_closest_bel(MutateContext &proxy, float target_x, float target_y, CellChain &chain) std::tuple<int, int, int> find_closest_bel(ArchRWProxy &proxy, float target_x, float target_y, CellChain &chain)
{ {
std::tuple<int, int, int> best_origin = std::make_tuple(-1, -1, -1); std::tuple<int, int, int> best_origin = std::make_tuple(-1, -1, -1);
wirelen_t best_wirelength = std::numeric_limits<wirelen_t>::max(); wirelen_t best_wirelength = std::numeric_limits<wirelen_t>::max();
@ -283,7 +283,7 @@ class PlacementLegaliser
} }
// Split a carry chain into multiple legal chains // Split a carry chain into multiple legal chains
std::vector<CellChain> split_carry_chain(const ReadContext &proxy, CellChain &carryc) std::vector<CellChain> split_carry_chain(const ArchRProxy &proxy, CellChain &carryc)
{ {
bool start_of_chain = true; bool start_of_chain = true;
std::vector<CellChain> chains; std::vector<CellChain> chains;
@ -335,7 +335,7 @@ class PlacementLegaliser
} }
// Place a logic cell at a given grid location, handling rip-up etc // Place a logic cell at a given grid location, handling rip-up etc
void place_lc(MutateContext &proxy, CellInfo *cell, int x, int y, int z) void place_lc(ArchRWProxy &proxy, CellInfo *cell, int x, int y, int z)
{ {
auto &loc = logic_bels.at(x).at(y).at(z); auto &loc = logic_bels.at(x).at(y).at(z);
NPNR_ASSERT(!loc.second); NPNR_ASSERT(!loc.second);