aboutsummaryrefslogtreecommitdiffstats
path: root/ice40
diff options
context:
space:
mode:
authorSergiusz Bazanski <q3k@q3k.org>2018-07-13 18:57:55 +0100
committerSergiusz Bazanski <q3k@q3k.org>2018-07-13 18:58:59 +0100
commit89809a8b810dd57f50f365d70a0ce547705f8dbb (patch)
tree3ae30e1c48cb71cc927ad399f31486d8273471e7 /ice40
parent9e4f97290a50fc5d9dc0cbe6ead945840b9811b1 (diff)
downloadnextpnr-89809a8b810dd57f50f365d70a0ce547705f8dbb.tar.gz
nextpnr-89809a8b810dd57f50f365d70a0ce547705f8dbb.tar.bz2
nextpnr-89809a8b810dd57f50f365d70a0ce547705f8dbb.zip
Introduce proxies for locked access to ctx
Diffstat (limited to 'ice40')
-rw-r--r--ice40/arch.cc357
-rw-r--r--ice40/arch.h387
-rw-r--r--ice40/arch_place.cc75
-rw-r--r--ice40/place_legaliser.cc73
4 files changed, 520 insertions, 372 deletions
diff --git a/ice40/arch.cc b/ice40/arch.cc
index 6c00f0d2..7c6af263 100644
--- a/ice40/arch.cc
+++ b/ice40/arch.cc
@@ -2,6 +2,7 @@
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2018 Clifford Wolf <clifford@symbioticeda.com>
+ * Copyright (C) 2018 Serge Bazanski <q3k@symbioticeda.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -28,6 +29,16 @@
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
@@ -239,28 +250,6 @@ IdString Arch::archArgsToId(ArchArgs args) const
// -----------------------------------------------------------------------
-BelId Arch::getBelByName(IdString name) const
-{
- boost::lock_guard<boost::shared_mutex> lock(mtx_);
- return getBelByNameUnlocked(name);
-}
-
-BelId Arch::getBelByNameUnlocked(IdString name) const
-{
- BelId ret;
-
- if (bel_by_name.empty()) {
- for (int i = 0; i < chip_info->num_bels; i++)
- bel_by_name[id(chip_info->bel_data[i].name.get())] = i;
- }
-
- auto it = bel_by_name.find(name);
- if (it != bel_by_name.end())
- ret.index = it->second;
-
- return ret;
-}
-
BelRange Arch::getBelsAtSameTile(BelId bel) const
{
BelRange br;
@@ -279,81 +268,105 @@ BelRange Arch::getBelsAtSameTile(BelId bel) const
return br;
}
-WireId Arch::getWireBelPin(BelId bel, PortPin pin) const
+// -----------------------------------------------------------------------
+// Shorthands to ArchProxy
+
+BelId Arch::getBelByName(IdString name) const
{
- boost::shared_lock_guard<boost::shared_mutex> lock(mtx_);
- return getWireBelPinUnlocked(bel, pin);
+ return rproxy().getBelByName(name);
}
-WireId Arch::getWireBelPinUnlocked(BelId bel, PortPin pin) const
+void Arch::bindWire(WireId wire, IdString net, PlaceStrength strength)
{
- WireId ret;
+ rwproxy().bindWire(wire, net, strength);
+}
- NPNR_ASSERT(bel != BelId());
+void Arch::unbindWire(WireId wire)
+{
+ rwproxy().unbindWire(wire);
+}
- int num_bel_wires = chip_info->bel_data[bel.index].num_bel_wires;
- const BelWirePOD *bel_wires = chip_info->bel_data[bel.index].bel_wires.get();
+void Arch::bindBel(BelId bel, IdString cell, PlaceStrength strength) {
+ rwproxy().bindBel(bel, cell, strength);
+}
- for (int i = 0; i < num_bel_wires; i++)
- if (bel_wires[i].port == pin) {
- ret.index = bel_wires[i].wire_index;
- break;
- }
+void Arch::unbindBel(BelId bel)
+{
+ rwproxy().unbindBel(bel);
+}
- return ret;
+bool Arch::checkBelAvail(BelId bel) const
+{
+ return rproxy().checkBelAvail(bel);
}
-// -----------------------------------------------------------------------
+IdString Arch::getBoundBelCell(BelId bel) const
+{
+ return rproxy().getBoundBelCell(bel);
+}
-WireId Arch::getWireByName(IdString name) const
+IdString Arch::getConflictingBelCell(BelId bel) const
{
- boost::shared_lock_guard<boost::shared_mutex> lock(mtx_);
- return getWireByNameUnlocked(name);
+ return rproxy().getConflictingBelCell(bel);
}
-WireId Arch::getWireByNameUnlocked(IdString name) const
+WireId Arch::getWireByName(IdString name) const
{
- WireId ret;
+ return rproxy().getWireByName(name);
+}
- if (wire_by_name.empty()) {
- for (int i = 0; i < chip_info->num_wires; i++)
- wire_by_name[id(chip_info->wire_data[i].name.get())] = i;
- }
+WireId Arch::getWireBelPin(BelId bel, PortPin pin) const
+{
+ return rproxy().getWireBelPin(bel, pin);
+}
- auto it = wire_by_name.find(name);
- if (it != wire_by_name.end())
- ret.index = it->second;
+bool Arch::checkWireAvail(WireId wire) const
+{
+ return rproxy().checkWireAvail(wire);
+}
- return ret;
+IdString Arch::getBoundWireNet(WireId wire) const
+{
+ return rproxy().getBoundWireNet(wire);
}
-// -----------------------------------------------------------------------
+IdString Arch::getConflictingWireNet(WireId wire) const
+{
+ return rproxy().getConflictingWireNet(wire);
+}
PipId Arch::getPipByName(IdString name) const
{
- boost::shared_lock_guard<boost::shared_mutex> lock(mtx_);
- return getPipByNameUnlocked(name);
+ return rproxy().getPipByName(name);
}
-PipId Arch::getPipByNameUnlocked(IdString name) const
+void Arch::bindPip(PipId pip, IdString net, PlaceStrength strength)
{
- PipId ret;
+ return rwproxy().bindPip(pip, net, strength);
+}
- if (pip_by_name.empty()) {
- for (int i = 0; i < chip_info->num_pips; i++) {
- PipId pip;
- pip.index = i;
- pip_by_name[getPipName(pip)] = i;
- }
- }
+void Arch::unbindPip(PipId pip)
+{
+ return rwproxy().unbindPip(pip);
+}
- auto it = pip_by_name.find(name);
- if (it != pip_by_name.end())
- ret.index = it->second;
+bool Arch::checkPipAvail(PipId pip) const
+{
+ return rproxy().checkPipAvail(pip);
+}
- return ret;
+IdString Arch::getBoundPipNet(PipId pip) const
+{
+ return rproxy().getBoundPipNet(pip);
}
+IdString Arch::getConflictingPipNet(PipId pip) const
+{
+ return rproxy().getConflictingPipNet(pip);
+}
+
+// -----------------------------------------------------------------------
+
IdString Arch::getPipName(PipId pip) const
{
NPNR_ASSERT(pip != PipId());
@@ -682,4 +695,216 @@ bool Arch::isGlobalNet(const NetInfo *net) const
return net->driver.cell != nullptr && net->driver.port == id_glb_buf_out;
}
+// -----------------------------------------------------------------------
+
+bool ArchRProxyMethods::checkBelAvail(BelId bel) const
+{
+ NPNR_ASSERT(bel != BelId());
+ return parent_->bel_to_cell[bel.index] == IdString();
+}
+
+IdString ArchRProxyMethods::getBoundBelCell(BelId bel) const
+{
+ NPNR_ASSERT(bel != BelId());
+ return parent_->bel_to_cell[bel.index];
+}
+
+IdString ArchRProxyMethods::getConflictingBelCell(BelId bel) const
+{
+ NPNR_ASSERT(bel != BelId());
+ return parent_->bel_to_cell[bel.index];
+}
+
+WireId ArchRProxyMethods::getWireBelPin(BelId bel, PortPin pin) const
+{
+ WireId ret;
+
+ NPNR_ASSERT(bel != BelId());
+
+ int num_bel_wires = parent_->chip_info->bel_data[bel.index].num_bel_wires;
+ const BelWirePOD *bel_wires = parent_->chip_info->bel_data[bel.index].bel_wires.get();
+
+ for (int i = 0; i < num_bel_wires; i++)
+ if (bel_wires[i].port == pin) {
+ ret.index = bel_wires[i].wire_index;
+ break;
+ }
+
+ return ret;
+}
+
+WireId ArchRProxyMethods::getWireByName(IdString name) const
+{
+ WireId ret;
+
+ if (parent_->wire_by_name.empty()) {
+ for (int i = 0; i < parent_->chip_info->num_wires; i++)
+ parent_->wire_by_name[parent_->id(parent_->chip_info->wire_data[i].name.get())] = i;
+ }
+
+ auto it = parent_->wire_by_name.find(name);
+ if (it != parent_->wire_by_name.end())
+ ret.index = it->second;
+
+ return ret;
+}
+
+bool ArchRProxyMethods::checkWireAvail(WireId wire) const
+{
+ NPNR_ASSERT(wire != WireId());
+ return parent_->wire_to_net[wire.index] == IdString();
+}
+
+IdString ArchRProxyMethods::getBoundWireNet(WireId wire) const
+{
+ NPNR_ASSERT(wire != WireId());
+ return parent_->wire_to_net[wire.index];
+}
+
+IdString ArchRProxyMethods::getConflictingWireNet(WireId wire) const
+{
+ NPNR_ASSERT(wire != WireId());
+ return parent_->wire_to_net[wire.index];
+}
+
+PipId ArchRProxyMethods::getPipByName(IdString name) const
+{
+ PipId ret;
+
+ if (parent_->pip_by_name.empty()) {
+ for (int i = 0; i < parent_->chip_info->num_pips; i++) {
+ PipId pip;
+ pip.index = i;
+ parent_->pip_by_name[parent_->getPipName(pip)] = i;
+ }
+ }
+
+ auto it = parent_->pip_by_name.find(name);
+ if (it != parent_->pip_by_name.end())
+ ret.index = it->second;
+
+ return ret;
+}
+
+bool ArchRProxyMethods::checkPipAvail(PipId pip) const
+{
+ NPNR_ASSERT(pip != PipId());
+ return parent_->switches_locked[parent_->chip_info->pip_data[pip.index].switch_index] == IdString();
+}
+
+IdString ArchRProxyMethods::getBoundPipNet(PipId pip) const
+{
+ NPNR_ASSERT(pip != PipId());
+ return parent_->pip_to_net[pip.index];
+}
+
+IdString ArchRProxyMethods::getConflictingPipNet(PipId pip) const
+{
+ NPNR_ASSERT(pip != PipId());
+ return parent_->switches_locked[parent_->chip_info->pip_data[pip.index].switch_index];
+}
+
+BelId ArchRProxyMethods::getBelByName(IdString name) const
+{
+ BelId ret;
+
+ if (parent_->bel_by_name.empty()) {
+ for (int i = 0; i < parent_->chip_info->num_bels; i++)
+ parent_->bel_by_name[parent_->id(parent_->chip_info->bel_data[i].name.get())] = i;
+ }
+
+ auto it = parent_->bel_by_name.find(name);
+ if (it != parent_->bel_by_name.end())
+ ret.index = it->second;
+
+ return ret;
+}
+
+// -----------------------------------------------------------------------
+
+void ArchRWProxyMethods::bindWire(WireId wire, IdString net, PlaceStrength strength)
+{
+ NPNR_ASSERT(wire != WireId());
+ NPNR_ASSERT(parent_->wire_to_net[wire.index] == IdString());
+
+ parent_->wire_to_net[wire.index] = net;
+ parent_->nets[net]->wires[wire].pip = PipId();
+ parent_->nets[net]->wires[wire].strength = strength;
+}
+
+void ArchRWProxyMethods::bindBel(BelId bel, IdString cell, PlaceStrength strength)
+{
+ NPNR_ASSERT(bel != BelId());
+ NPNR_ASSERT(parent_->bel_to_cell[bel.index] == IdString());
+ parent_->bel_to_cell[bel.index] = cell;
+ parent_->cells[cell]->bel = bel;
+ parent_->cells[cell]->belStrength = strength;
+}
+
+void ArchRWProxyMethods::unbindBel(BelId bel)
+{
+ NPNR_ASSERT(bel != BelId());
+ NPNR_ASSERT(parent_->bel_to_cell[bel.index] != IdString());
+ parent_->cells[parent_->bel_to_cell[bel.index]]->bel = BelId();
+ parent_->cells[parent_->bel_to_cell[bel.index]]->belStrength = STRENGTH_NONE;
+ parent_->bel_to_cell[bel.index] = IdString();
+}
+
+void ArchRWProxyMethods::unbindWire(WireId wire)
+{
+ NPNR_ASSERT(wire != WireId());
+ NPNR_ASSERT(parent_->wire_to_net[wire.index] != IdString());
+
+ auto &net_wires = parent_->nets[parent_->wire_to_net[wire.index]]->wires;
+ auto it = net_wires.find(wire);
+ NPNR_ASSERT(it != net_wires.end());
+
+ auto pip = it->second.pip;
+ if (pip != PipId()) {
+ parent_->pip_to_net[pip.index] = IdString();
+ parent_->switches_locked[parent_->chip_info->pip_data[pip.index].switch_index] = IdString();
+ }
+
+ net_wires.erase(it);
+ parent_->wire_to_net[wire.index] = IdString();
+}
+
+void ArchRWProxyMethods::bindPip(PipId pip, IdString net, PlaceStrength strength)
+{
+ NPNR_ASSERT(pip != PipId());
+ NPNR_ASSERT(parent_->pip_to_net[pip.index] == IdString());
+ NPNR_ASSERT(parent_->switches_locked[parent_->chip_info->pip_data[pip.index].switch_index] == IdString());
+
+ parent_->pip_to_net[pip.index] = net;
+ parent_->switches_locked[parent_->chip_info->pip_data[pip.index].switch_index] = net;
+
+ WireId dst;
+ dst.index = parent_->chip_info->pip_data[pip.index].dst;
+ NPNR_ASSERT(parent_->wire_to_net[dst.index] == IdString());
+ parent_->wire_to_net[dst.index] = net;
+ parent_->nets[net]->wires[dst].pip = pip;
+ parent_->nets[net]->wires[dst].strength = strength;
+}
+
+void ArchRWProxyMethods::unbindPip(PipId pip)
+{
+ NPNR_ASSERT(pip != PipId());
+ NPNR_ASSERT(parent_->pip_to_net[pip.index] != IdString());
+ NPNR_ASSERT(parent_->switches_locked[parent_->chip_info->pip_data[pip.index].switch_index] != IdString());
+
+ WireId dst;
+ dst.index = parent_->chip_info->pip_data[pip.index].dst;
+ NPNR_ASSERT(parent_->wire_to_net[dst.index] != IdString());
+ parent_->wire_to_net[dst.index] = IdString();
+ parent_->nets[parent_->pip_to_net[pip.index]]->wires.erase(dst);
+
+ parent_->pip_to_net[pip.index] = IdString();
+ parent_->switches_locked[parent_->chip_info->pip_data[pip.index].switch_index] = IdString();
+}
+
+CellInfo *ArchRWProxyMethods::getCell(IdString cell)
+{
+ return parent_->cells.at(cell).get();
+}
+
NEXTPNR_NAMESPACE_END
diff --git a/ice40/arch.h b/ice40/arch.h
index ab66e7d8..4462ce9e 100644
--- a/ice40/arch.h
+++ b/ice40/arch.h
@@ -2,6 +2,7 @@
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2018 Clifford Wolf <clifford@symbioticeda.com>
+ * Copyright (C) 2018 Serge Bazanski <q3k@symbioticeda.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -327,27 +328,40 @@ struct ArchArgs
std::string package;
};
+class ArchRWProxyMethods;
+class ArchRProxyMethods;
+class ArchRWProxy;
+class ArchRProxy;
+
class Arch : public BaseCtx
{
+ friend class ArchRWProxyMethods;
+ friend class ArchRProxyMethods;
+ friend class ArchRWProxy;
+ friend class ArchRProxy;
private:
// All of the following...
std::vector<IdString> bel_to_cell;
std::vector<IdString> wire_to_net;
std::vector<IdString> pip_to_net;
std::vector<IdString> switches_locked;
+ mutable std::unordered_map<IdString, int> bel_by_name;
+ 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;
- mutable std::unordered_map<IdString, int> bel_by_name;
- mutable std::unordered_map<IdString, int> wire_by_name;
- mutable std::unordered_map<IdString, int> pip_by_name;
-
ArchArgs args;
Arch(ArchArgs args);
+ ArchRWProxy rwproxy(void);
+ ArchRProxy rproxy(void) const;
+
std::string getChipName();
IdString archId() const { return id("ice40"); }
@@ -361,8 +375,33 @@ public:
// -------------------------------------------------
+ /// Wrappers around getting a r(w)proxy and calling a single method.
+ // Deprecated: please acquire a proxy yourself and call the methods
+ // you want on it.
+ void unbindWire(WireId wire);
+ void unbindPip(PipId pip);
+ void unbindBel(BelId bel);
+ void bindWire(WireId wire, IdString net, PlaceStrength strength);
+ void bindPip(PipId pip, IdString net, PlaceStrength strength);
+ void bindBel(BelId bel, IdString cell, PlaceStrength strength);
+ bool checkWireAvail(WireId wire) const;
+ bool checkPipAvail(PipId pip) const;
+ bool checkBelAvail(BelId bel) const;
+ WireId getWireByName(IdString name) const;
+ WireId getWireBelPin(BelId bel, PortPin pin) const;
+ PipId getPipByName(IdString name) const;
+ IdString getConflictingWireNet(WireId wire) const;
+ IdString getConflictingPipNet(PipId pip) const;
+ IdString getConflictingBelCell(BelId bel) const;
+ IdString getBoundWireNet(WireId wire) const;
+ IdString getBoundPipNet(PipId pip) const;
+ IdString getBoundBelCell(BelId bel) const;
BelId getBelByName(IdString name) const;
- BelId getBelByNameUnlocked(IdString name) const;
+
+ // -------------------------------------------------
+
+ /// Methods to get chip info - don't need to use a wrapper, as these are
+ /// static per lifetime of object.
IdString getBelName(BelId bel) const
{
@@ -370,71 +409,9 @@ public:
return id(chip_info->bel_data[bel.index].name.get());
}
- uint32_t getBelChecksum(BelId bel) const { return bel.index; }
-
- void bindBel(BelId bel, IdString cell, PlaceStrength strength) {
- boost::lock_guard<boost::shared_mutex> lock(mtx_);
- bindBelUnlocked(bel, cell, strength);
- }
-
- void bindBelUnlocked(BelId bel, IdString cell, PlaceStrength strength)
- {
- NPNR_ASSERT(bel != BelId());
- NPNR_ASSERT(bel_to_cell[bel.index] == IdString());
- bel_to_cell[bel.index] = cell;
- cells[cell]->bel = bel;
- cells[cell]->belStrength = strength;
- }
-
- void unbindBel(BelId bel)
+ uint32_t getBelChecksum(BelId bel) const
{
- boost::lock_guard<boost::shared_mutex> lock(mtx_);
- unbindBelUnlocked(bel);
- }
-
- void unbindBelUnlocked(BelId bel)
- {
- NPNR_ASSERT(bel != BelId());
- NPNR_ASSERT(bel_to_cell[bel.index] != IdString());
- cells[bel_to_cell[bel.index]]->bel = BelId();
- cells[bel_to_cell[bel.index]]->belStrength = STRENGTH_NONE;
- bel_to_cell[bel.index] = IdString();
- }
-
- bool checkBelAvail(BelId bel) const
- {
- boost::shared_lock_guard<boost::shared_mutex> lock(mtx_);
- return checkBelAvailUnlocked(bel);
- }
-
- bool checkBelAvailUnlocked(BelId bel) const
- {
- NPNR_ASSERT(bel != BelId());
- return bel_to_cell[bel.index] == IdString();
- }
-
- IdString getBoundBelCell(BelId bel) const
- {
- boost::shared_lock_guard<boost::shared_mutex> lock(mtx_);
- return getBoundBelCellUnlocked(bel);
- }
-
- IdString getBoundBelCellUnlocked(BelId bel) const
- {
- NPNR_ASSERT(bel != BelId());
- return bel_to_cell[bel.index];
- }
-
- IdString getConflictingBelCell(BelId bel) const
- {
- boost::shared_lock_guard<boost::shared_mutex> lock(mtx_);
- return getConflictingBelCellUnlocked(bel);
- }
-
- IdString getConflictingBelCellUnlocked(BelId bel) const
- {
- NPNR_ASSERT(bel != BelId());
- return bel_to_cell[bel.index];
+ return bel.index;
}
BelRange getBels() const
@@ -467,8 +444,6 @@ public:
return chip_info->bel_data[bel.index].type;
}
- WireId getWireBelPin(BelId bel, PortPin pin) const;
- WireId getWireBelPinUnlocked(BelId bel, PortPin pin) const;
BelPin getBelPinUphill(WireId wire) const
{
@@ -494,9 +469,6 @@ public:
// -------------------------------------------------
- WireId getWireByName(IdString name) const;
- WireId getWireByNameUnlocked(IdString name) const;
-
IdString getWireName(WireId wire) const
{
NPNR_ASSERT(wire != WireId());
@@ -505,82 +477,6 @@ public:
uint32_t getWireChecksum(WireId wire) const { return wire.index; }
- void bindWire(WireId wire, IdString net, PlaceStrength strength)
- {
- boost::lock_guard<boost::shared_mutex> lock(mtx_);
- bindWireUnlocked(wire, net, strength);
- }
-
- void bindWireUnlocked(WireId wire, IdString net, PlaceStrength strength)
- {
- NPNR_ASSERT(wire != WireId());
- NPNR_ASSERT(wire_to_net[wire.index] == IdString());
-
- wire_to_net[wire.index] = net;
- nets[net]->wires[wire].pip = PipId();
- nets[net]->wires[wire].strength = strength;
- }
-
- void unbindWire(WireId wire)
- {
- boost::lock_guard<boost::shared_mutex> lock(mtx_);
- unbindWireUnlocked(wire);
- }
-
- void unbindWireUnlocked(WireId wire)
- {
- NPNR_ASSERT(wire != WireId());
- NPNR_ASSERT(wire_to_net[wire.index] != IdString());
-
- auto &net_wires = nets[wire_to_net[wire.index]]->wires;
- auto it = net_wires.find(wire);
- NPNR_ASSERT(it != net_wires.end());
-
- auto pip = it->second.pip;
- if (pip != PipId()) {
- pip_to_net[pip.index] = IdString();
- switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString();
- }
-
- net_wires.erase(it);
- wire_to_net[wire.index] = IdString();
- }
-
- bool checkWireAvail(WireId wire) const
- {
- boost::shared_lock_guard<boost::shared_mutex> lock(mtx_);
- return checkWireAvailUnlocked(wire);
- }
-
- bool checkWireAvailUnlocked(WireId wire) const
- {
- NPNR_ASSERT(wire != WireId());
- return wire_to_net[wire.index] == IdString();
- }
-
- IdString getBoundWireNet(WireId wire) const
- {
- boost::shared_lock_guard<boost::shared_mutex> lock(mtx_);
- return getBoundWireNetUnlocked(wire);
- }
-
- IdString getBoundWireNetUnlocked(WireId wire) const
- {
- NPNR_ASSERT(wire != WireId());
- return wire_to_net[wire.index];
- }
-
- IdString getConflictingWireNet(WireId wire) const
- {
- boost::shared_lock_guard<boost::shared_mutex> lock(mtx_);
- return getConflictingWireNetUnlocked(wire);
- }
-
- IdString getConflictingWireNetUnlocked(WireId wire) const
- {
- NPNR_ASSERT(wire != WireId());
- return wire_to_net[wire.index];
- }
WireRange getWires() const
{
@@ -592,93 +488,10 @@ public:
// -------------------------------------------------
- PipId getPipByName(IdString name) const;
- PipId getPipByNameUnlocked(IdString name) const;
IdString getPipName(PipId pip) const;
uint32_t getPipChecksum(PipId pip) const { return pip.index; }
- void bindPip(PipId pip, IdString net, PlaceStrength strength)
- {
- boost::lock_guard<boost::shared_mutex> lock(mtx_);
- bindPipUnlocked(pip, net, strength);
- }
-
- void bindPipUnlocked(PipId pip, IdString net, PlaceStrength strength)
- {
- NPNR_ASSERT(pip != PipId());
- NPNR_ASSERT(pip_to_net[pip.index] == IdString());
- NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString());
-
- pip_to_net[pip.index] = net;
- switches_locked[chip_info->pip_data[pip.index].switch_index] = net;
-
- WireId dst;
- dst.index = chip_info->pip_data[pip.index].dst;
- NPNR_ASSERT(wire_to_net[dst.index] == IdString());
- wire_to_net[dst.index] = net;
- nets[net]->wires[dst].pip = pip;
- nets[net]->wires[dst].strength = strength;
- }
-
- void unbindPip(PipId pip)
- {
- boost::lock_guard<boost::shared_mutex> lock(mtx_);
- unbindPipUnlocked(pip);
- }
-
- void unbindPipUnlocked(PipId pip)
- {
- NPNR_ASSERT(pip != PipId());
- NPNR_ASSERT(pip_to_net[pip.index] != IdString());
- NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] != IdString());
-
- WireId dst;
- dst.index = chip_info->pip_data[pip.index].dst;
- NPNR_ASSERT(wire_to_net[dst.index] != IdString());
- wire_to_net[dst.index] = IdString();
- nets[pip_to_net[pip.index]]->wires.erase(dst);
-
- pip_to_net[pip.index] = IdString();
- switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString();
- }
-
- bool checkPipAvail(PipId pip) const
- {
- boost::shared_lock_guard<boost::shared_mutex> lock(mtx_);
- return checkPipAvailUnlocked(pip);
- }
-
- bool checkPipAvailUnlocked(PipId pip) const
- {
- NPNR_ASSERT(pip != PipId());
- return switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString();
- }
-
- IdString getBoundPipNet(PipId pip) const
- {
- boost::shared_lock_guard<boost::shared_mutex> lock(mtx_);
- return getBoundPipNetUnlocked(pip);
- }
-
- IdString getBoundPipNetUnlocked(PipId pip) const
- {
- NPNR_ASSERT(pip != PipId());
- return pip_to_net[pip.index];
- }
-
- IdString getConflictingPipNet(PipId pip) const
- {
- boost::shared_lock_guard<boost::shared_mutex> lock(mtx_);
- return getConflictingPipNetUnlocked(pip);
- }
-
- IdString getConflictingPipNetUnlocked(PipId pip) const
- {
- NPNR_ASSERT(pip != PipId());
- return switches_locked[chip_info->pip_data[pip.index].switch_index];
- }
-
AllPipRange getPips() const
{
AllPipRange range;
@@ -789,7 +602,26 @@ public:
// -------------------------------------------------
- // Perform placement validity checks, returning false on failure (all implemented in arch_place.cc)
+ IdString id_glb_buf_out;
+ IdString id_icestorm_lc, id_sb_io, id_sb_gb;
+ IdString id_cen, id_clk, id_sr;
+ IdString id_i0, id_i1, id_i2, id_i3;
+ IdString id_dff_en, id_neg_clk;
+};
+
+class ArchRProxyMethods {
+ friend class ArchRProxy;
+ friend class ArchRWProxy;
+private:
+ const Arch *parent_;
+ ArchRProxyMethods(const Arch *parent) : parent_(parent) {}
+ ArchRProxyMethods(ArchRProxyMethods &&other) noexcept : parent_(other.parent_) {}
+ ArchRProxyMethods(const ArchRProxyMethods &other) : parent_(other.parent_) {}
+
+public:
+ ~ArchRProxyMethods() noexcept { }
+
+ /// Perform placement validity checks, returning false on failure (all implemented in arch_place.cc)
// Whether or not a given cell can be placed at a given Bel
// This is not intended for Bel type checks, but finer-grained constraints
@@ -802,11 +634,88 @@ public:
// Helper function for above
bool logicCellsCompatible(const std::vector<const CellInfo *> &cells) const;
- IdString id_glb_buf_out;
- IdString id_icestorm_lc, id_sb_io, id_sb_gb;
- IdString id_cen, id_clk, id_sr;
- IdString id_i0, id_i1, id_i2, id_i3;
- IdString id_dff_en, id_neg_clk;
+ bool checkWireAvail(WireId wire) const;
+ bool checkPipAvail(PipId pip) const;
+ bool checkBelAvail(BelId bel) const;
+
+ WireId getWireByName(IdString name) const;
+ WireId getWireBelPin(BelId bel, PortPin pin) const;
+ PipId getPipByName(IdString name) const;
+
+
+ IdString getConflictingWireNet(WireId wire) const;
+ IdString getConflictingPipNet(PipId pip) const;
+ IdString getConflictingBelCell(BelId bel) const;
+
+ IdString getBoundWireNet(WireId wire) const;
+ IdString getBoundPipNet(PipId pip) const;
+ IdString getBoundBelCell(BelId bel) const;
+
+ BelId getBelByName(IdString name) const;
+};
+
+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;
+ }
+};
+
+class ArchRWProxyMethods {
+ friend class ArchRWProxy;
+private:
+ Arch *parent_;
+ ArchRWProxyMethods(Arch *parent) : parent_(parent) {}
+ ArchRWProxyMethods(ArchRWProxyMethods &&other) : parent_(other.parent_) {}
+ ArchRWProxyMethods(const ArchRWProxyMethods &other) : parent_(other.parent_) {}
+public:
+ ~ArchRWProxyMethods() {}
+
+ void unbindWire(WireId wire);
+ void unbindPip(PipId pip);
+ void unbindBel(BelId bel);
+ void bindWire(WireId wire, IdString net, PlaceStrength strength);
+ void bindPip(PipId pip, IdString net, PlaceStrength strength);
+ void bindBel(BelId bel, IdString cell, PlaceStrength strength);
+ CellInfo *getCell(IdString cell);
+};
+
+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 c9dd26c5..cb7c44b8 100644
--- a/ice40/arch_place.cc
+++ b/ice40/arch_place.cc
@@ -3,6 +3,7 @@
*
* Copyright (C) 2018 Clifford Wolf <clifford@symbioticeda.com>
* Copyright (C) 2018 David Shah <david@symbioticeda.com>
+ * Copyright (C) 2018 Serge Bazanski <q3k@symbioticeda.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -24,44 +25,44 @@
NEXTPNR_NAMESPACE_BEGIN
-bool Arch::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;
int locals_count = 0;
for (auto cell : cells) {
- if (bool_or_default(cell->params, id_dff_en)) {
+ if (bool_or_default(cell->params, parent_->id_dff_en)) {
if (!dffs_exist) {
dffs_exist = true;
- cen = get_net_or_empty(cell, id_cen);
- clk = get_net_or_empty(cell, id_clk);
- sr = get_net_or_empty(cell, id_sr);
+ cen = get_net_or_empty(cell, parent_->id_cen);
+ clk = get_net_or_empty(cell, parent_->id_clk);
+ sr = get_net_or_empty(cell, parent_->id_sr);
- if (!isGlobalNet(cen) && cen != nullptr)
+ if (!parent_->isGlobalNet(cen) && cen != nullptr)
locals_count++;
- if (!isGlobalNet(clk) && clk != nullptr)
+ if (!parent_->isGlobalNet(clk) && clk != nullptr)
locals_count++;
- if (!isGlobalNet(sr) && sr != nullptr)
+ if (!parent_->isGlobalNet(sr) && sr != nullptr)
locals_count++;
- if (bool_or_default(cell->params, id_neg_clk)) {
+ if (bool_or_default(cell->params, parent_->id_neg_clk)) {
dffs_neg = true;
}
} else {
- if (cen != get_net_or_empty(cell, id_cen))
+ if (cen != get_net_or_empty(cell, parent_->id_cen))
return false;
- if (clk != get_net_or_empty(cell, id_clk))
+ if (clk != get_net_or_empty(cell, parent_->id_clk))
return false;
- if (sr != get_net_or_empty(cell, id_sr))
+ if (sr != get_net_or_empty(cell, parent_->id_sr))
return false;
- if (dffs_neg != bool_or_default(cell->params, id_neg_clk))
+ if (dffs_neg != bool_or_default(cell->params, parent_->id_neg_clk))
return false;
}
}
- const NetInfo *i0 = get_net_or_empty(cell, id_i0), *i1 = get_net_or_empty(cell, id_i1),
- *i2 = get_net_or_empty(cell, id_i2), *i3 = get_net_or_empty(cell, id_i3);
+ const NetInfo *i0 = get_net_or_empty(cell, parent_->id_i0), *i1 = get_net_or_empty(cell, parent_->id_i1),
+ *i2 = get_net_or_empty(cell, parent_->id_i2), *i3 = get_net_or_empty(cell, parent_->id_i3);
if (i0 != nullptr)
locals_count++;
if (i1 != nullptr)
@@ -75,57 +76,57 @@ bool Arch::logicCellsCompatible(const std::vector<const CellInfo *> &cells) cons
return locals_count <= 32;
}
-bool Arch::isBelLocationValid(BelId bel) const
+bool ArchRProxyMethods::isBelLocationValid(BelId bel) const
{
- if (getBelType(bel) == TYPE_ICESTORM_LC) {
+ if (parent_->getBelType(bel) == TYPE_ICESTORM_LC) {
std::vector<const CellInfo *> bel_cells;
- for (auto bel_other : getBelsAtSameTile(bel)) {
- IdString cell_other = getBoundBelCellUnlocked(bel_other);
+ for (auto bel_other : parent_->getBelsAtSameTile(bel)) {
+ IdString cell_other = getBoundBelCell(bel_other);
if (cell_other != IdString()) {
- const CellInfo *ci_other = cells.at(cell_other).get();
+ const CellInfo *ci_other = parent_->cells.at(cell_other).get();
bel_cells.push_back(ci_other);
}
}
return logicCellsCompatible(bel_cells);
} else {
- IdString cellId = getBoundBelCellUnlocked(bel);
+ IdString cellId = getBoundBelCell(bel);
if (cellId == IdString())
return true;
else
- return isValidBelForCell(cells.at(cellId).get(), bel);
+ return isValidBelForCell(parent_->cells.at(cellId).get(), bel);
}
}
-bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const
+bool ArchRProxyMethods::isValidBelForCell(CellInfo *cell, BelId bel) const
{
- if (cell->type == id_icestorm_lc) {
- NPNR_ASSERT(getBelType(bel) == TYPE_ICESTORM_LC);
+ if (cell->type == parent_->id_icestorm_lc) {
+ NPNR_ASSERT(parent_->getBelType(bel) == TYPE_ICESTORM_LC);
std::vector<const CellInfo *> bel_cells;
- for (auto bel_other : getBelsAtSameTile(bel)) {
- IdString cell_other = getBoundBelCellUnlocked(bel_other);
+ for (auto bel_other : parent_->getBelsAtSameTile(bel)) {
+ IdString cell_other = getBoundBelCell(bel_other);
if (cell_other != IdString() && bel_other != bel) {
- const CellInfo *ci_other = cells.at(cell_other).get();
+ const CellInfo *ci_other = parent_->cells.at(cell_other).get();
bel_cells.push_back(ci_other);
}
}
bel_cells.push_back(cell);
return logicCellsCompatible(bel_cells);
- } else if (cell->type == id_sb_io) {
- return getBelPackagePin(bel) != "";
- } else if (cell->type == id_sb_gb) {
+ } else if (cell->type == parent_->id_sb_io) {
+ return parent_->getBelPackagePin(bel) != "";
+ } else if (cell->type == parent_->id_sb_gb) {
bool is_reset = false, is_cen = false;
- NPNR_ASSERT(cell->ports.at(id_glb_buf_out).net != nullptr);
- for (auto user : cell->ports.at(id_glb_buf_out).net->users) {
- if (is_reset_port(this, user))
+ NPNR_ASSERT(cell->ports.at(parent_->id_glb_buf_out).net != nullptr);
+ for (auto user : cell->ports.at(parent_->id_glb_buf_out).net->users) {
+ if (is_reset_port(parent_, user))
is_reset = true;
- if (is_enable_port(this, user))
+ if (is_enable_port(parent_, user))
is_cen = true;
}
- IdString glb_net = getWireName(getWireBelPin(bel, PIN_GLOBAL_BUFFER_OUTPUT));
- int glb_id = std::stoi(std::string("") + glb_net.str(this).back());
+ IdString glb_net = parent_->getWireName(getWireBelPin(bel, PIN_GLOBAL_BUFFER_OUTPUT));
+ int glb_id = std::stoi(std::string("") + glb_net.str(parent_).back());
if (is_reset && is_cen)
return false;
else if (is_reset)
diff --git a/ice40/place_legaliser.cc b/ice40/place_legaliser.cc
index d42188f0..10a6f3ff 100644
--- a/ice40/place_legaliser.cc
+++ b/ice40/place_legaliser.cc
@@ -119,13 +119,17 @@ class PlacementLegaliser
bool legalise()
{
- log_info("Legalising design..\n");
+ log_info("Legalising logic cells...\n");
init_logic_cells();
+ log_info("Legalising carries...\n");
bool legalised_carries = legalise_carries();
if (!legalised_carries && !ctx->force)
return false;
+ log_info("Legalising others...\n");
legalise_others();
+ log_info("Legalising logic tiles...\n");
legalise_logic_tiles();
+ log_info("Replacing cells...\n");
bool replaced_cells = replace_cells();
return legalised_carries && replaced_cells;
}
@@ -133,6 +137,7 @@ class PlacementLegaliser
private:
void init_logic_cells()
{
+ auto &&proxy = ctx->rproxy();
for (auto bel : ctx->getBels()) {
// Initialise the logic bels vector with unavailable invalid bels, dimensions [0..width][0..height[0..7]
logic_bels.resize(ctx->chip_info->width + 1,
@@ -143,7 +148,7 @@ class PlacementLegaliser
// Using the non-standard API here to get (x, y, z) rather than just (x, y)
auto bi = ctx->chip_info->bel_data[bel.index];
int x = bi.x, y = bi.y, z = bi.z;
- IdString cell = ctx->getBoundBelCellUnlocked(bel);
+ IdString cell = proxy.getBoundBelCell(bel);
if (cell != IdString() && ctx->cells.at(cell)->belStrength >= STRENGTH_FIXED)
logic_bels.at(x).at(y).at(z) = std::make_pair(bel, true); // locked out of use
else
@@ -195,28 +200,33 @@ class PlacementLegaliser
}
}
bool success = true;
+
// Find midpoints for all chains, before we start tearing them up
std::vector<CellChain> all_chains;
- for (auto &base_chain : carry_chains) {
- if (ctx->verbose) {
- log_info("Found carry chain: \n");
- for (auto entry : base_chain.cells)
- log_info(" %s\n", entry->name.c_str(ctx));
- log_info("\n");
- }
- std::vector<CellChain> split_chains = split_carry_chain(base_chain);
- for (auto &chain : split_chains) {
- get_chain_midpoint(ctx, chain, chain.mid_x, chain.mid_y);
- all_chains.push_back(chain);
+ {
+ auto &&proxy = ctx->rproxy();
+ for (auto &base_chain : carry_chains) {
+ if (ctx->verbose) {
+ log_info("Found carry chain: \n");
+ for (auto entry : base_chain.cells)
+ log_info(" %s\n", entry->name.c_str(ctx));
+ log_info("\n");
+ }
+ std::vector<CellChain> split_chains = split_carry_chain(proxy, base_chain);
+ for (auto &chain : split_chains) {
+ get_chain_midpoint(ctx, chain, chain.mid_x, chain.mid_y);
+ all_chains.push_back(chain);
+ }
}
}
// Actual chain placement
+ auto &&proxy = ctx->rwproxy();
for (auto &chain : all_chains) {
if (ctx->verbose)
log_info("Placing carry chain starting at '%s'\n", chain.cells.front()->name.c_str(ctx));
float base_x = chain.mid_x, base_y = chain.mid_y - (chain.cells.size() / 16.0f);
// Find Bel meeting requirements closest to the target base, returning location as <x, y, z>
- auto chain_origin_bel = find_closest_bel(base_x, base_y, chain);
+ auto chain_origin_bel = find_closest_bel(proxy, base_x, base_y, chain);
int place_x = std::get<0>(chain_origin_bel), place_y = std::get<1>(chain_origin_bel),
place_z = std::get<2>(chain_origin_bel);
if (place_x == -1) {
@@ -233,7 +243,7 @@ class PlacementLegaliser
// Place carry chain
for (int i = 0; i < int(chain.cells.size()); i++) {
int target_z = place_y * 8 + place_z + i;
- place_lc(chain.cells.at(i), place_x, target_z / 8, target_z % 8);
+ place_lc(proxy, chain.cells.at(i), place_x, target_z / 8, target_z % 8);
if (ctx->verbose)
log_info(" Cell '%s' placed at (%d, %d, %d)\n", chain.cells.at(i)->name.c_str(ctx), place_x,
target_z / 8, target_z % 8);
@@ -243,7 +253,7 @@ class PlacementLegaliser
}
// Find Bel closest to a location, meeting chain requirements
- std::tuple<int, int, int> find_closest_bel(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();
@@ -260,7 +270,7 @@ class PlacementLegaliser
valid = false;
break;
} else {
- wirelen += get_cell_wirelength_at_bel(ctx, chain.cells.at(k), lb.first);
+ wirelen += get_cell_wirelength_at_bel(proxy, ctx, chain.cells.at(k), lb.first);
}
}
if (valid && wirelen < best_wirelength) {
@@ -273,7 +283,7 @@ class PlacementLegaliser
}
// Split a carry chain into multiple legal chains
- std::vector<CellChain> split_carry_chain(CellChain &carryc)
+ std::vector<CellChain> split_carry_chain(const ArchRProxy &proxy, CellChain &carryc)
{
bool start_of_chain = true;
std::vector<CellChain> chains;
@@ -298,7 +308,7 @@ class PlacementLegaliser
}
tile.push_back(cell);
chains.back().cells.push_back(cell);
- bool split_chain = (!ctx->logicCellsCompatible(tile)) || (int(chains.back().cells.size()) > max_length);
+ bool split_chain = (!proxy.logicCellsCompatible(tile)) || (int(chains.back().cells.size()) > max_length);
if (split_chain) {
CellInfo *passout = make_carry_pass_out(cell->ports.at(ctx->id("COUT")));
tile.pop_back();
@@ -325,22 +335,22 @@ class PlacementLegaliser
}
// Place a logic cell at a given grid location, handling rip-up etc
- void place_lc(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);
BelId bel = loc.first;
// Check if there is a cell presently at the location, which we will need to rip up
- IdString existing = ctx->getBoundBelCellUnlocked(bel);
+ IdString existing = proxy.getBoundBelCell(bel);
if (existing != IdString()) {
// TODO: keep track of the previous position of the ripped up cell, as a hint
rippedCells.insert(existing);
- ctx->unbindBelUnlocked(bel);
+ proxy.unbindBel(bel);
}
if (cell->bel != BelId()) {
- ctx->unbindBelUnlocked(cell->bel);
+ proxy.unbindBel(cell->bel);
}
- ctx->bindBelUnlocked(bel, cell->name, STRENGTH_LOCKED);
+ proxy.bindBel(bel, cell->name, STRENGTH_LOCKED);
rippedCells.erase(cell->name); // If cell was ripped up previously, no need to re-place
loc.second = true; // Bel is now unavailable for further use
}
@@ -423,19 +433,20 @@ class PlacementLegaliser
// Legalise logic tiles
void legalise_logic_tiles()
{
+ auto &&proxy = ctx->rwproxy();
int width = ctx->chip_info->width, height = ctx->chip_info->height;
for (int x = 1; x < width; x++) {
for (int y = 1; y < height; y++) {
BelId tileBel = logic_bels.at(x).at(y).at(0).first;
if (tileBel != BelId()) {
bool changed = true;
- while (!ctx->isBelLocationValid(tileBel) && changed) {
+ while (!proxy.isBelLocationValid(tileBel) && changed) {
changed = false;
int max_score = 0;
CellInfo *target = nullptr;
for (int z = 0; z < 8; z++) {
BelId bel = logic_bels.at(x).at(y).at(z).first;
- IdString cell = ctx->getBoundBelCellUnlocked(bel);
+ IdString cell = proxy.getBoundBelCell(bel);
if (cell != IdString()) {
CellInfo *ci = ctx->cells.at(cell).get();
if (ci->belStrength >= STRENGTH_STRONG)
@@ -448,7 +459,7 @@ class PlacementLegaliser
}
}
if (target != nullptr) {
- ctx->unbindBelUnlocked(target->bel);
+ proxy.unbindBel(target->bel);
rippedCells.insert(target->name);
changed = true;
}
@@ -461,13 +472,14 @@ class PlacementLegaliser
// Legalise other tiles
void legalise_others()
{
+ auto &&proxy = ctx->rwproxy();
std::vector<CellInfo *> legalised_others;
for (auto cell : sorted(ctx->cells)) {
CellInfo *ci = cell.second;
if (!is_lc(ctx, ci)) {
if (ci->belStrength < STRENGTH_STRONG && ci->bel != BelId()) {
- if (!ctx->isValidBelForCell(ci, ci->bel)) {
- place_single_cell(ctx, ci, true);
+ if (!proxy.isValidBelForCell(ci, ci->bel)) {
+ place_single_cell(proxy, ctx, ci, true);
}
legalised_others.push_back(ci);
}
@@ -482,10 +494,11 @@ class PlacementLegaliser
// Replace ripped-up cells
bool replace_cells()
{
+ auto &&proxy = ctx->rwproxy();
bool success = true;
for (auto cell : sorted(rippedCells)) {
CellInfo *ci = ctx->cells.at(cell).get();
- bool placed = place_single_cell(ctx, ci, true);
+ bool placed = place_single_cell(proxy, ctx, ci, true);
if (!placed) {
if (ctx->force) {
log_warning("failed to place cell '%s' of type '%s'\n", cell.c_str(ctx), ci->type.c_str(ctx));