aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSergiusz Bazanski <q3k@q3k.org>2018-07-14 18:50:37 +0100
committerSergiusz Bazanski <q3k@q3k.org>2018-07-14 18:50:37 +0100
commitb0c05c7f751cf68165849a8f28d389541456f956 (patch)
treebf1da8454839d625b1c06392db384561b3dd9cee
parentd9c3c117a38c8bc42cfb96255b4762965bc1611b (diff)
downloadnextpnr-b0c05c7f751cf68165849a8f28d389541456f956.tar.gz
nextpnr-b0c05c7f751cf68165849a8f28d389541456f956.tar.bz2
nextpnr-b0c05c7f751cf68165849a8f28d389541456f956.zip
Revert "Refactor proxies to nextpnr."
This reverts commit 9b17fe385cf7e8d3025747b5f7c7822ac2d99920.
-rw-r--r--common/nextpnr.cc11
-rw-r--r--common/nextpnr.h170
-rw-r--r--common/place_common.cc2
-rw-r--r--common/place_common.h2
-rw-r--r--common/placer1.cc4
-rw-r--r--common/router1.cc4
-rw-r--r--ice40/arch.cc77
-rw-r--r--ice40/arch.h130
-rw-r--r--ice40/arch_place.cc6
-rw-r--r--ice40/place_legaliser.cc6
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<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)
: 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 <unordered_map>
#include <unordered_set>
#include <vector>
-#include <boost/thread/shared_mutex.hpp>
#ifndef NEXTPNR_H
#define NEXTPNR_H
@@ -249,37 +248,21 @@ struct UIUpdatesRequired
std::unordered_set<GroupId> 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<BelId> belUiReload;
- std::unordered_set<WireId> wireUiReload;
- std::unordered_set<PipId> pipUiReload;
- std::unordered_set<GroupId> groupUiReload;
+ mutable std::unordered_map<std::string, int> *idstring_str_to_idx;
+ mutable std::vector<const std::string *> *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<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::vector<const std::string *> *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<BelId> belUiReload;
+ std::unordered_set<WireId> wireUiReload;
+ std::unordered_set<PipId> pipUiReload;
+ std::unordered_set<GroupId> 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<NetInfo *> update;
static std::vector<std::pair<IdString, wirelen_t>> 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<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();
std::vector<PipId> pips;
@@ -115,7 +115,7 @@ struct Router
delay_t maxDelay = 0.0;
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;
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<GraphicElement> ArchReadMethods::getDecalGraphics(DecalId decal) const
+std::vector<GraphicElement> ArchRProxyMethods::getDecalGraphics(DecalId decal) const
{
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());
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 <boost/thread/shared_lock_guard.hpp>
+#include <boost/thread/shared_mutex.hpp>
+
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<IdString> bel_to_cell;
@@ -353,6 +362,9 @@ private:
mutable std::unordered_map<IdString, int> wire_by_name;
mutable std::unordered_map<IdString, int> 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<IdString> &bel_to_cell;
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> &wire_by_name;
std::unordered_map<IdString, int> &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<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.
-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<IdString> &bel_to_cell;
std::vector<IdString> &wire_to_net;
@@ -681,17 +739,8 @@ private:
std::unordered_map<IdString, int> &bel_by_name;
std::unordered_map<IdString, int> &wire_by_name;
std::unordered_map<IdString, int> &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<const CellInfo *> &cells) const
+bool ArchRProxyMethods::logicCellsCompatible(const std::vector<const CellInfo *> &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<const CellInfo *> &
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<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) {
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<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);
wirelen_t best_wirelength = std::numeric_limits<wirelen_t>::max();
@@ -283,7 +283,7 @@ class PlacementLegaliser
}
// 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;
std::vector<CellChain> 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);