From b0c05c7f751cf68165849a8f28d389541456f956 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Sat, 14 Jul 2018 18:50:37 +0100 Subject: Revert "Refactor proxies to nextpnr." This reverts commit 9b17fe385cf7e8d3025747b5f7c7822ac2d99920. --- common/nextpnr.cc | 11 --- common/nextpnr.h | 170 +++++++++-------------------------------------- common/place_common.cc | 2 +- common/place_common.h | 2 +- common/placer1.cc | 4 +- common/router1.cc | 4 +- ice40/arch.cc | 77 ++++++++++++--------- ice40/arch.h | 130 ++++++++++++++++++++++++++++-------- ice40/arch_place.cc | 6 +- ice40/place_legaliser.cc | 6 +- 10 files changed, 194 insertions(+), 218 deletions(-) diff --git a/common/nextpnr.cc b/common/nextpnr.cc index 54df5de1..3861e5fe 100644 --- a/common/nextpnr.cc +++ b/common/nextpnr.cc @@ -21,17 +21,6 @@ NEXTPNR_NAMESPACE_BEGIN -MutateContext BaseCtx::rwproxy(void) -{ - return MutateContext(reinterpret_cast(this)); -} - -ReadContext BaseCtx::rproxy(void) const -{ - return ReadContext(reinterpret_cast(this)); -} - - 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), expr_str(expr_str), filename(filename), line(line) diff --git a/common/nextpnr.h b/common/nextpnr.h index c3fb913c..efcab9fc 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -26,7 +26,6 @@ #include #include #include -#include #ifndef NEXTPNR_H #define NEXTPNR_H @@ -249,37 +248,21 @@ struct UIUpdatesRequired std::unordered_set groupUIReload; }; -class ReadContext; -class MutateContext; -class BaseReadCtx; -class BaseMutateCtx; - -// Data that every architecture object should contain. -class BaseCtx +struct 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 belUiReload; - std::unordered_set wireUiReload; - std::unordered_set pipUiReload; - std::unordered_set groupUiReload; + mutable std::unordered_map *idstring_str_to_idx; + mutable std::vector *idstring_idx_to_str; -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> nets; std::unordered_map> cells; - mutable std::unordered_map *idstring_str_to_idx; - mutable std::vector *idstring_idx_to_str; BaseCtx() { @@ -303,83 +286,41 @@ public: // -------------------------------------------------------------- - // Get a readwrite proxy to arch - this will keep a readwrite lock on the - // entire architecture until the proxy object goes out of scope. - MutateContext 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. - ReadContext rproxy(void) const; - -}; - -// State-accessing read-only methods that every architecture object should -// contain. -class BaseReadCtx -{ -protected: - const BaseCtx *base_; -public: - BaseReadCtx(const BaseCtx *base) : base_(base) {} -}; - -// State-accesssing read/write methods that every architecture object should -// contain. -class BaseMutateCtx -{ -protected: - BaseCtx *base_; - -public: - BaseMutateCtx(BaseCtx *base) : base_(base) {} + bool allUiReload = false; + bool frameUiReload = false; + std::unordered_set belUiReload; + std::unordered_set wireUiReload; + std::unordered_set pipUiReload; + std::unordered_set groupUiReload; - void refreshUi(void) - { - base_->allUiReload = true; - } + void refreshUi() { allUiReload = true; } - void refreshUiFrame(void) - { - base_->frameUiReload = true; - } + void refreshUiFrame() { frameUiReload = true; } - void refreshUiBel(BelId bel) - { - base_->belUiReload.insert(bel); - } + void refreshUiBel(BelId bel) { belUiReload.insert(bel); } - void refreshUiWire(WireId wire) - { - base_->wireUiReload.insert(wire); - } + void refreshUiWire(WireId wire) { wireUiReload.insert(wire); } - void refreshUiPip(PipId pip) - { - base_->pipUiReload.insert(pip); - } + void refreshUiPip(PipId pip) { pipUiReload.insert(pip); } - void refreshUiGroup(GroupId group) - { - base_->groupUiReload.insert(group); - } + void refreshUiGroup(GroupId group) { groupUiReload.insert(group); } UIUpdatesRequired getUIUpdatesRequired(void) { UIUpdatesRequired req; - req.allUIReload = base_->allUiReload; - req.frameUIReload = base_->frameUiReload; - req.belUIReload = base_->belUiReload; - req.wireUIReload = base_->wireUiReload; - req.pipUIReload = base_->pipUiReload; - req.groupUIReload = base_->groupUiReload; - - base_->allUiReload = false; - base_->frameUiReload = false; - base_->belUiReload.clear(); - base_->wireUiReload.clear(); - base_->pipUiReload.clear(); - base_->groupUiReload.clear(); + req.allUIReload = allUiReload; + req.frameUIReload = frameUiReload; + req.belUIReload = belUiReload; + req.wireUIReload = wireUiReload; + req.pipUIReload = pipUiReload; + req.groupUIReload = groupUiReload; + + allUiReload = false; + frameUiReload = false; + belUiReload.clear(); + wireUiReload.clear(); + pipUiReload.clear(); + groupUiReload.clear(); return req; } }; @@ -390,53 +331,6 @@ NEXTPNR_NAMESPACE_END 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 { bool verbose = false; diff --git a/common/place_common.cc b/common/place_common.cc index 9694b6fe..48416370 100644 --- a/common/place_common.cc +++ b/common/place_common.cc @@ -26,7 +26,7 @@ NEXTPNR_NAMESPACE_BEGIN // 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; int iters = 25; diff --git a/common/place_common.h b/common/place_common.h index 96ac48a9..57e82510 100644 --- a/common/place_common.h +++ b/common/place_common.h @@ -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 -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 diff --git a/common/placer1.cc b/common/placer1.cc index 78515ece..0e3a84f7 100644 --- a/common/placer1.cc +++ b/common/placer1.cc @@ -275,7 +275,7 @@ class SAPlacer private: // Initial random placement - void place_initial(MutateContext &proxy, CellInfo *cell) + void place_initial(ArchRWProxy &proxy, CellInfo *cell) { bool all_placed = false; int iters = 25; @@ -325,7 +325,7 @@ class SAPlacer } // 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 update; static std::vector> new_lengths; diff --git a/common/router1.cc b/common/router1.cc index f7a7e8a2..0d26a36d 100644 --- a/common/router1.cc +++ b/common/router1.cc @@ -74,7 +74,7 @@ struct RipupScoreboard std::unordered_map, 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(); std::vector pips; @@ -115,7 +115,7 @@ struct Router delay_t maxDelay = 0.0; WireId failedDest; - void route(MutateContext &proxy, const std::unordered_map &src_wires, WireId dst_wire) + void route(ArchRWProxy &proxy, const std::unordered_map &src_wires, WireId dst_wire) { std::priority_queue, QueuedWire::Greater> queue; diff --git a/ice40/arch.cc b/ice40/arch.cc index 790167e9..547dbcd6 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -29,6 +29,18 @@ 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 { if (type == TYPE_ICESTORM_LC) @@ -522,7 +534,7 @@ DecalXY Arch::getGroupDecal(GroupId group) const return decalxy; }; -std::vector ArchReadMethods::getDecalGraphics(DecalId decal) const +std::vector ArchRProxyMethods::getDecalGraphics(DecalId decal) const { std::vector 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()); return bel_to_cell[bel.index] == IdString(); } -IdString ArchReadMethods::getBoundBelCell(BelId bel) const +IdString ArchRProxyMethods::getBoundBelCell(BelId bel) const { NPNR_ASSERT(bel != BelId()); return bel_to_cell[bel.index]; } -IdString ArchReadMethods::getConflictingBelCell(BelId bel) const +IdString ArchRProxyMethods::getConflictingBelCell(BelId bel) const { NPNR_ASSERT(bel != BelId()); return bel_to_cell[bel.index]; } -WireId ArchReadMethods::getWireBelPin(BelId bel, PortPin pin) const +WireId ArchRProxyMethods::getWireBelPin(BelId bel, PortPin pin) const { WireId ret; @@ -756,7 +768,7 @@ WireId ArchReadMethods::getWireBelPin(BelId bel, PortPin pin) const return ret; } -WireId ArchReadMethods::getWireByName(IdString name) const +WireId ArchRProxyMethods::getWireByName(IdString name) const { WireId ret; @@ -772,25 +784,25 @@ WireId ArchReadMethods::getWireByName(IdString name) const return ret; } -bool ArchReadMethods::checkWireAvail(WireId wire) const +bool ArchRProxyMethods::checkWireAvail(WireId wire) const { NPNR_ASSERT(wire != WireId()); return wire_to_net[wire.index] == IdString(); } -IdString ArchReadMethods::getBoundWireNet(WireId wire) const +IdString ArchRProxyMethods::getBoundWireNet(WireId wire) const { NPNR_ASSERT(wire != WireId()); return wire_to_net[wire.index]; } -IdString ArchReadMethods::getConflictingWireNet(WireId wire) const +IdString ArchRProxyMethods::getConflictingWireNet(WireId wire) const { NPNR_ASSERT(wire != WireId()); return wire_to_net[wire.index]; } -PipId ArchReadMethods::getPipByName(IdString name) const +PipId ArchRProxyMethods::getPipByName(IdString name) const { PipId ret; @@ -809,25 +821,25 @@ PipId ArchReadMethods::getPipByName(IdString name) const return ret; } -bool ArchReadMethods::checkPipAvail(PipId pip) const +bool ArchRProxyMethods::checkPipAvail(PipId pip) const { NPNR_ASSERT(pip != PipId()); 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()); return pip_to_net[pip.index]; } -IdString ArchReadMethods::getConflictingPipNet(PipId pip) const +IdString ArchRProxyMethods::getConflictingPipNet(PipId pip) const { NPNR_ASSERT(pip != PipId()); 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; @@ -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_to_cell[bel.index] == IdString()); bel_to_cell[bel.index] = cell; parent_->cells[cell]->bel = bel; 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_to_cell[bel.index] != IdString()); parent_->cells[bel_to_cell[bel.index]]->bel = BelId(); parent_->cells[bel_to_cell[bel.index]]->belStrength = STRENGTH_NONE; 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_to_net[wire.index] == IdString()); @@ -873,10 +885,10 @@ void ArchMutateMethods::bindWire(WireId wire, IdString net, PlaceStrength streng wire_to_net[wire.index] = net; parent_->nets[net]->wires[wire].pip = PipId(); 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_to_net[wire.index] != IdString()); @@ -889,15 +901,15 @@ void ArchMutateMethods::unbindWire(WireId wire) if (pip != PipId()) { pip_to_net[pip.index] = IdString(); switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString(); - refreshUiPip(pip); + parent_->refreshUiPip(pip); } net_wires.erase(it); 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_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].strength = strength; - refreshUiPip(pip); - refreshUiWire(dst); + parent_->refreshUiPip(pip); + parent_->refreshUiWire(dst); } -void ArchMutateMethods::unbindPip(PipId pip) +void ArchRWProxyMethods::unbindPip(PipId pip) { NPNR_ASSERT(pip != PipId()); NPNR_ASSERT(pip_to_net[pip.index] != IdString()); @@ -932,13 +944,18 @@ void ArchMutateMethods::unbindPip(PipId pip) pip_to_net[pip.index] = IdString(); switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString(); - refreshUiPip(pip); - refreshUiWire(dst); + parent_->refreshUiPip(pip); + parent_->refreshUiWire(dst); } -CellInfo *ArchMutateMethods::getCell(IdString cell) +CellInfo *ArchRWProxyMethods::getCell(IdString cell) { return parent_->cells.at(cell).get(); } +UIUpdatesRequired ArchRWProxyMethods::getUIUpdatesRequired(void) +{ + return parent_->getUIUpdatesRequired(); +} + NEXTPNR_NAMESPACE_END diff --git a/ice40/arch.h b/ice40/arch.h index 5d4eaedf..4311f4a5 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -22,6 +22,9 @@ #error Include "arch.h" via "nextpnr.h" only. #endif +#include +#include + NEXTPNR_NAMESPACE_BEGIN /**** Everything in this section must be kept in sync with chipdb.py ****/ @@ -327,8 +330,11 @@ struct ArchArgs /// Forward declare proxy classes for Arch. -class ArchMutateMethods; -class ArchReadMethods; +class ArchRWProxyMethods; +class ArchRProxyMethods; +class ArchRWProxy; +class ArchRProxy; + /// Arch/Context // 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 { // We let proxy methods access our state. - friend class ArchMutateMethods; - friend class ArchReadMethods; + friend class ArchRWProxyMethods; + friend class ArchRProxyMethods; + // We let proxy objects access our mutex. + friend class ArchRWProxy; + friend class ArchRProxy; private: // All of the following... std::vector bel_to_cell; @@ -353,6 +362,9 @@ private: mutable std::unordered_map wire_by_name; mutable std::unordered_map pip_by_name; + // ... are guarded by the following lock: + mutable boost::shared_mutex mtx_; + public: const ChipInfoPOD *chip_info; const PackageInfoPOD *package_info; @@ -360,6 +372,15 @@ public: 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(); IdString archId() const { return id("ice40"); } @@ -611,9 +632,22 @@ public: }; // 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: 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 std::vector &bel_to_cell; const std::vector &wire_to_net; @@ -622,17 +656,8 @@ private: std::unordered_map &bel_by_name; std::unordered_map &wire_by_name; std::unordered_map &pip_by_name; - public: - ~ArchReadMethods() 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_) {} + ~ArchRProxyMethods() noexcept { } /// Perform placement validity checks, returning false on failure (all implemented in arch_place.cc) @@ -668,11 +693,44 @@ public: std::vector 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. -class ArchMutateMethods : public BaseMutateCtx { - friend class MutateContext; +class ArchRWProxyMethods { + // We let proxy objects access our private constructors. + friend class ArchRWProxy; private: 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; std::vector &bel_to_cell; std::vector &wire_to_net; @@ -681,17 +739,8 @@ private: std::unordered_map &bel_by_name; std::unordered_map &wire_by_name; std::unordered_map &pip_by_name; - public: - ArchMutateMethods(Arch *parent) : BaseMutateCtx(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) {} - ArchMutateMethods(ArchMutateMethods &&other) : ArchMutateMethods(other.parent_) {} - ArchMutateMethods(const ArchMutateMethods &other) : ArchMutateMethods(other.parent_) {} - ~ArchMutateMethods() {} + ~ArchRWProxyMethods() {} void unbindWire(WireId wire); void unbindPip(PipId pip); @@ -701,6 +750,33 @@ public: void bindBel(BelId bel, IdString cell, PlaceStrength strength); // Returned pointer is valid as long as Proxy object exists. 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 diff --git a/ice40/arch_place.cc b/ice40/arch_place.cc index 42efceab..cb7c44b8 100644 --- a/ice40/arch_place.cc +++ b/ice40/arch_place.cc @@ -25,7 +25,7 @@ NEXTPNR_NAMESPACE_BEGIN -bool ArchReadMethods::logicCellsCompatible(const std::vector &cells) const +bool ArchRProxyMethods::logicCellsCompatible(const std::vector &cells) const { bool dffs_exist = false, dffs_neg = false; const NetInfo *cen = nullptr, *clk = nullptr, *sr = nullptr; @@ -76,7 +76,7 @@ bool ArchReadMethods::logicCellsCompatible(const std::vector & return locals_count <= 32; } -bool ArchReadMethods::isBelLocationValid(BelId bel) const +bool ArchRProxyMethods::isBelLocationValid(BelId bel) const { if (parent_->getBelType(bel) == TYPE_ICESTORM_LC) { std::vector 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) { NPNR_ASSERT(parent_->getBelType(bel) == TYPE_ICESTORM_LC); diff --git a/ice40/place_legaliser.cc b/ice40/place_legaliser.cc index fcb47cfd..10a6f3ff 100644 --- a/ice40/place_legaliser.cc +++ b/ice40/place_legaliser.cc @@ -253,7 +253,7 @@ class PlacementLegaliser } // Find Bel closest to a location, meeting chain requirements - std::tuple find_closest_bel(MutateContext &proxy, float target_x, float target_y, CellChain &chain) + std::tuple find_closest_bel(ArchRWProxy &proxy, float target_x, float target_y, CellChain &chain) { std::tuple best_origin = std::make_tuple(-1, -1, -1); wirelen_t best_wirelength = std::numeric_limits::max(); @@ -283,7 +283,7 @@ class PlacementLegaliser } // Split a carry chain into multiple legal chains - std::vector split_carry_chain(const ReadContext &proxy, CellChain &carryc) + std::vector split_carry_chain(const ArchRProxy &proxy, CellChain &carryc) { bool start_of_chain = true; std::vector chains; @@ -335,7 +335,7 @@ class PlacementLegaliser } // 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); NPNR_ASSERT(!loc.second); -- cgit v1.2.3