aboutsummaryrefslogtreecommitdiffstats
path: root/generic
diff options
context:
space:
mode:
authorgatecat <gatecat@ds0.me>2021-12-30 09:08:02 +0000
committergatecat <gatecat@ds0.me>2021-12-30 11:54:08 +0000
commit59874188a6800fbaa03ec21e3578160e963c2eb5 (patch)
tree28463b159ce424cdf7780174f1fffb421d04bf88 /generic
parentc272d28e575bde2675a6ae7090a0d5f0f4c9c88f (diff)
downloadnextpnr-59874188a6800fbaa03ec21e3578160e963c2eb5.tar.gz
nextpnr-59874188a6800fbaa03ec21e3578160e963c2eb5.tar.bz2
nextpnr-59874188a6800fbaa03ec21e3578160e963c2eb5.zip
generic: Refactor for faster performance
This won't affect Python-built arches significantly; but will be useful for the future 'viaduct' functionality where generic routing graphs can be built on the C++ side; too. Signed-off-by: gatecat <gatecat@ds0.me>
Diffstat (limited to 'generic')
-rw-r--r--generic/arch.cc274
-rw-r--r--generic/arch.h78
-rw-r--r--generic/arch_pybindings.cc64
-rw-r--r--generic/arch_pybindings.h67
-rw-r--r--generic/archdefs.h39
-rw-r--r--generic/examples/write_fasm.py2
6 files changed, 319 insertions, 205 deletions
diff --git a/generic/arch.cc b/generic/arch.cc
index 0695ec98..d899bd0b 100644
--- a/generic/arch.cc
+++ b/generic/arch.cc
@@ -28,46 +28,27 @@
NEXTPNR_NAMESPACE_BEGIN
-WireInfo &Arch::wire_info(IdStringList wire)
+WireId Arch::addWire(IdStringList name, IdString type, int x, int y)
{
- auto w = wires.find(wire);
- if (w == wires.end())
- NPNR_ASSERT_FALSE_STR("no wire named " + wire.str(getCtx()));
- return w->second;
-}
-
-PipInfo &Arch::pip_info(IdStringList pip)
-{
- auto p = pips.find(pip);
- if (p == pips.end())
- NPNR_ASSERT_FALSE_STR("no pip named " + pip.str(getCtx()));
- return p->second;
-}
-
-BelInfo &Arch::bel_info(IdStringList bel)
-{
- auto b = bels.find(bel);
- if (b == bels.end())
- NPNR_ASSERT_FALSE_STR("no bel named " + bel.str(getCtx()));
- return b->second;
-}
-
-void Arch::addWire(IdStringList name, IdString type, int x, int y)
-{
- NPNR_ASSERT(wires.count(name) == 0);
- WireInfo &wi = wires[name];
+ NPNR_ASSERT(wire_by_name.count(name) == 0);
+ WireId wire(wires.size());
+ wire_by_name[name] = wire;
+ wires.emplace_back();
+ WireInfo &wi = wires.back();
wi.name = name;
wi.type = type;
wi.x = x;
wi.y = y;
-
- wire_ids.push_back(name);
+ return wire;
}
-void Arch::addPip(IdStringList name, IdString type, IdStringList srcWire, IdStringList dstWire, delay_t delay, Loc loc)
+PipId Arch::addPip(IdStringList name, IdString type, WireId srcWire, WireId dstWire, delay_t delay, Loc loc)
{
- NPNR_ASSERT(pips.count(name) == 0);
- PipInfo &pi = pips[name];
+ NPNR_ASSERT(pip_by_name.count(name) == 0);
+ PipId pip(pips.size());
+ pip_by_name[name] = pip;
+ pips.emplace_back();
+ PipInfo &pi = pips.back();
pi.name = name;
pi.type = type;
pi.srcWire = srcWire;
@@ -75,9 +56,8 @@ void Arch::addPip(IdStringList name, IdString type, IdStringList srcWire, IdStri
pi.delay = delay;
pi.loc = loc;
- wire_info(srcWire).downhill.push_back(name);
- wire_info(dstWire).uphill.push_back(name);
- pip_ids.push_back(name);
+ wire_info(srcWire).downhill.push_back(pip);
+ wire_info(dstWire).uphill.push_back(pip);
if (int(tilePipDimZ.size()) <= loc.x)
tilePipDimZ.resize(loc.x + 1);
@@ -88,13 +68,17 @@ void Arch::addPip(IdStringList name, IdString type, IdStringList srcWire, IdStri
gridDimX = std::max(gridDimX, loc.x + 1);
gridDimY = std::max(gridDimY, loc.x + 1);
tilePipDimZ[loc.x][loc.y] = std::max(tilePipDimZ[loc.x][loc.y], loc.z + 1);
+ return pip;
}
-void Arch::addBel(IdStringList name, IdString type, Loc loc, bool gb, bool hidden)
+BelId Arch::addBel(IdStringList name, IdString type, Loc loc, bool gb, bool hidden)
{
- NPNR_ASSERT(bels.count(name) == 0);
+ NPNR_ASSERT(bel_by_name.count(name) == 0);
NPNR_ASSERT(bel_by_loc.count(loc) == 0);
- BelInfo &bi = bels[name];
+ BelId bel(bels.size());
+ bel_by_name[name] = bel;
+ bels.emplace_back();
+ BelInfo &bi = bels.back();
bi.name = name;
bi.type = type;
bi.x = loc.x;
@@ -103,8 +87,7 @@ void Arch::addBel(IdStringList name, IdString type, Loc loc, bool gb, bool hidde
bi.gb = gb;
bi.hidden = hidden;
- bel_ids.push_back(name);
- bel_by_loc[loc] = name;
+ bel_by_loc[loc] = bel;
if (int(bels_by_tile.size()) <= loc.x)
bels_by_tile.resize(loc.x + 1);
@@ -112,7 +95,7 @@ void Arch::addBel(IdStringList name, IdString type, Loc loc, bool gb, bool hidde
if (int(bels_by_tile[loc.x].size()) <= loc.y)
bels_by_tile[loc.x].resize(loc.y + 1);
- bels_by_tile[loc.x][loc.y].push_back(name);
+ bels_by_tile[loc.x][loc.y].push_back(bel);
if (int(tileBelDimZ.size()) <= loc.x)
tileBelDimZ.resize(loc.x + 1);
@@ -123,49 +106,50 @@ void Arch::addBel(IdStringList name, IdString type, Loc loc, bool gb, bool hidde
gridDimX = std::max(gridDimX, loc.x + 1);
gridDimY = std::max(gridDimY, loc.x + 1);
tileBelDimZ[loc.x][loc.y] = std::max(tileBelDimZ[loc.x][loc.y], loc.z + 1);
+ return bel;
}
-void Arch::addBelInput(IdStringList bel, IdString name, IdStringList wire)
+void Arch::addBelInput(BelId bel, IdString name, WireId wire)
{
- NPNR_ASSERT(bel_info(bel).pins.count(name) == 0);
- PinInfo &pi = bel_info(bel).pins[name];
+ auto &bi = bel_info(bel);
+ NPNR_ASSERT(bi.pins.count(name) == 0);
+ PinInfo &pi = bi.pins[name];
pi.name = name;
pi.wire = wire;
pi.type = PORT_IN;
- wire_info(wire).downhill_bel_pins.push_back(BelPin{bel, name});
wire_info(wire).bel_pins.push_back(BelPin{bel, name});
}
-void Arch::addBelOutput(IdStringList bel, IdString name, IdStringList wire)
+void Arch::addBelOutput(BelId bel, IdString name, WireId wire)
{
- NPNR_ASSERT(bel_info(bel).pins.count(name) == 0);
- PinInfo &pi = bel_info(bel).pins[name];
+ auto &bi = bel_info(bel);
+ NPNR_ASSERT(bi.pins.count(name) == 0);
+ PinInfo &pi = bi.pins[name];
pi.name = name;
pi.wire = wire;
pi.type = PORT_OUT;
- wire_info(wire).uphill_bel_pin = BelPin{bel, name};
wire_info(wire).bel_pins.push_back(BelPin{bel, name});
}
-void Arch::addBelInout(IdStringList bel, IdString name, IdStringList wire)
+void Arch::addBelInout(BelId bel, IdString name, WireId wire)
{
- NPNR_ASSERT(bel_info(bel).pins.count(name) == 0);
- PinInfo &pi = bel_info(bel).pins[name];
+ auto &bi = bel_info(bel);
+ NPNR_ASSERT(bi.pins.count(name) == 0);
+ PinInfo &pi = bi.pins[name];
pi.name = name;
pi.wire = wire;
pi.type = PORT_INOUT;
- wire_info(wire).downhill_bel_pins.push_back(BelPin{bel, name});
wire_info(wire).bel_pins.push_back(BelPin{bel, name});
}
-void Arch::addGroupBel(IdStringList group, IdStringList bel) { groups[group].bels.push_back(bel); }
+void Arch::addGroupBel(IdStringList group, BelId bel) { groups[group].bels.push_back(bel); }
-void Arch::addGroupWire(IdStringList group, IdStringList wire) { groups[group].wires.push_back(wire); }
+void Arch::addGroupWire(IdStringList group, WireId wire) { groups[group].wires.push_back(wire); }
-void Arch::addGroupPip(IdStringList group, IdStringList pip) { groups[group].pips.push_back(pip); }
+void Arch::addGroupPip(IdStringList group, PipId pip) { groups[group].pips.push_back(pip); }
void Arch::addGroupGroup(IdStringList group, IdStringList grp) { groups[group].groups.push_back(grp); }
@@ -177,19 +161,19 @@ void Arch::addDecalGraphic(DecalId decal, const GraphicElement &graphic)
void Arch::setWireDecal(WireId wire, DecalXY decalxy)
{
- wire_info(wire).decalxy = decalxy;
+ wires.at(wire.index).decalxy = decalxy;
refreshUiWire(wire);
}
void Arch::setPipDecal(PipId pip, DecalXY decalxy)
{
- pip_info(pip).decalxy = decalxy;
+ pips.at(pip.index).decalxy = decalxy;
refreshUiPip(pip);
}
void Arch::setBelDecal(BelId bel, DecalXY decalxy)
{
- bel_info(bel).decalxy = decalxy;
+ bels.at(bel.index).decalxy = decalxy;
refreshUiBel(bel);
}
@@ -199,14 +183,11 @@ void Arch::setGroupDecal(GroupId group, DecalXY decalxy)
refreshUiGroup(group);
}
-void Arch::setWireAttr(IdStringList wire, IdString key, const std::string &value)
-{
- wire_info(wire).attrs[key] = value;
-}
+void Arch::setWireAttr(WireId wire, IdString key, const std::string &value) { wire_info(wire).attrs[key] = value; }
-void Arch::setPipAttr(IdStringList pip, IdString key, const std::string &value) { pip_info(pip).attrs[key] = value; }
+void Arch::setPipAttr(PipId pip, IdString key, const std::string &value) { pip_info(pip).attrs[key] = value; }
-void Arch::setBelAttr(IdStringList bel, IdString key, const std::string &value) { bel_info(bel).attrs[key] = value; }
+void Arch::setBelAttr(BelId bel, IdString key, const std::string &value) { bel_info(bel).attrs[key] = value; }
void Arch::setLutK(int K) { args.K = K; }
@@ -268,16 +249,19 @@ void IdString::initialize_arch(const BaseCtx *ctx) {}
BelId Arch::getBelByName(IdStringList name) const
{
- if (bels.count(name))
- return name;
- return BelId();
+ if (name.size() == 0)
+ return BelId();
+ auto fnd = bel_by_name.find(name);
+ if (fnd == bel_by_name.end())
+ NPNR_ASSERT_FALSE_STR("no bel named " + name.str(getCtx()));
+ return fnd->second;
}
-IdStringList Arch::getBelName(BelId bel) const { return bel; }
+IdStringList Arch::getBelName(BelId bel) const { return bel_info(bel).name; }
Loc Arch::getBelLocation(BelId bel) const
{
- auto &info = bels.at(bel);
+ auto &info = bel_info(bel);
return Loc(info.x, info.y, info.z);
}
@@ -291,7 +275,7 @@ BelId Arch::getBelByLocation(Loc loc) const
const std::vector<BelId> &Arch::getBelsByTile(int x, int y) const { return bels_by_tile.at(x).at(y); }
-bool Arch::getBelGlobalBuf(BelId bel) const { return bels.at(bel).gb; }
+bool Arch::getBelGlobalBuf(BelId bel) const { return bel_info(bel).gb; }
uint32_t Arch::getBelChecksum(BelId bel) const
{
@@ -301,7 +285,7 @@ uint32_t Arch::getBelChecksum(BelId bel) const
void Arch::bindBel(BelId bel, CellInfo *cell, PlaceStrength strength)
{
- bels.at(bel).bound_cell = cell;
+ bel_info(bel).bound_cell = cell;
cell->bel = bel;
cell->belStrength = strength;
refreshUiBel(bel);
@@ -309,40 +293,41 @@ void Arch::bindBel(BelId bel, CellInfo *cell, PlaceStrength strength)
void Arch::unbindBel(BelId bel)
{
- bels.at(bel).bound_cell->bel = BelId();
- bels.at(bel).bound_cell->belStrength = STRENGTH_NONE;
- bels.at(bel).bound_cell = nullptr;
+ auto &bi = bel_info(bel);
+ bi.bound_cell->bel = BelId();
+ bi.bound_cell->belStrength = STRENGTH_NONE;
+ bi.bound_cell = nullptr;
refreshUiBel(bel);
}
-bool Arch::checkBelAvail(BelId bel) const { return bels.at(bel).bound_cell == nullptr; }
+bool Arch::checkBelAvail(BelId bel) const { return bel_info(bel).bound_cell == nullptr; }
-CellInfo *Arch::getBoundBelCell(BelId bel) const { return bels.at(bel).bound_cell; }
+CellInfo *Arch::getBoundBelCell(BelId bel) const { return bel_info(bel).bound_cell; }
-CellInfo *Arch::getConflictingBelCell(BelId bel) const { return bels.at(bel).bound_cell; }
+CellInfo *Arch::getConflictingBelCell(BelId bel) const { return bel_info(bel).bound_cell; }
-const std::vector<BelId> &Arch::getBels() const { return bel_ids; }
+linear_range<BelId> Arch::getBels() const { return linear_range<BelId>(bels.size()); }
-IdString Arch::getBelType(BelId bel) const { return bels.at(bel).type; }
+IdString Arch::getBelType(BelId bel) const { return bel_info(bel).type; }
-bool Arch::getBelHidden(BelId bel) const { return bels.at(bel).hidden; }
+bool Arch::getBelHidden(BelId bel) const { return bel_info(bel).hidden; }
-const std::map<IdString, std::string> &Arch::getBelAttrs(BelId bel) const { return bels.at(bel).attrs; }
+const std::map<IdString, std::string> &Arch::getBelAttrs(BelId bel) const { return bel_info(bel).attrs; }
WireId Arch::getBelPinWire(BelId bel, IdString pin) const
{
- const auto &bdata = bels.at(bel);
+ const auto &bdata = bel_info(bel);
if (!bdata.pins.count(pin))
log_error("bel '%s' has no pin '%s'\n", getCtx()->nameOfBel(bel), pin.c_str(this));
return bdata.pins.at(pin).wire;
}
-PortType Arch::getBelPinType(BelId bel, IdString pin) const { return bels.at(bel).pins.at(pin).type; }
+PortType Arch::getBelPinType(BelId bel, IdString pin) const { return bel_info(bel).pins.at(pin).type; }
std::vector<IdString> Arch::getBelPins(BelId bel) const
{
std::vector<IdString> ret;
- for (auto &it : bels.at(bel).pins)
+ for (auto &it : bel_info(bel).pins)
ret.push_back(it.first);
return ret;
}
@@ -356,26 +341,25 @@ const std::vector<IdString> &Arch::getBelPinsForCellPin(const CellInfo *cell_inf
WireId Arch::getWireByName(IdStringList name) const
{
- if (wires.count(name))
- return name;
- return WireId();
+ if (name.size() == 0)
+ return WireId();
+ auto fnd = wire_by_name.find(name);
+ if (fnd == wire_by_name.end())
+ NPNR_ASSERT_FALSE_STR("no wire named " + name.str(getCtx()));
+ return fnd->second;
}
-IdStringList Arch::getWireName(WireId wire) const { return wire; }
+IdStringList Arch::getWireName(WireId wire) const { return wire_info(wire).name; }
-IdString Arch::getWireType(WireId wire) const { return wires.at(wire).type; }
+IdString Arch::getWireType(WireId wire) const { return wire_info(wire).type; }
-const std::map<IdString, std::string> &Arch::getWireAttrs(WireId wire) const { return wires.at(wire).attrs; }
+const std::map<IdString, std::string> &Arch::getWireAttrs(WireId wire) const { return wire_info(wire).attrs; }
-uint32_t Arch::getWireChecksum(WireId wire) const
-{
- // FIXME
- return 0;
-}
+uint32_t Arch::getWireChecksum(WireId wire) const { return wire.index; }
void Arch::bindWire(WireId wire, NetInfo *net, PlaceStrength strength)
{
- wires.at(wire).bound_net = net;
+ wire_info(wire).bound_net = net;
net->wires[wire].pip = PipId();
net->wires[wire].strength = strength;
refreshUiWire(wire);
@@ -383,55 +367,54 @@ void Arch::bindWire(WireId wire, NetInfo *net, PlaceStrength strength)
void Arch::unbindWire(WireId wire)
{
- auto &net_wires = wires.at(wire).bound_net->wires;
+ auto &net_wires = wire_info(wire).bound_net->wires;
auto pip = net_wires.at(wire).pip;
if (pip != PipId()) {
- pips.at(pip).bound_net = nullptr;
+ pip_info(pip).bound_net = nullptr;
refreshUiPip(pip);
}
net_wires.erase(wire);
- wires.at(wire).bound_net = nullptr;
+ wire_info(wire).bound_net = nullptr;
refreshUiWire(wire);
}
-bool Arch::checkWireAvail(WireId wire) const { return wires.at(wire).bound_net == nullptr; }
+bool Arch::checkWireAvail(WireId wire) const { return wire_info(wire).bound_net == nullptr; }
-NetInfo *Arch::getBoundWireNet(WireId wire) const { return wires.at(wire).bound_net; }
+NetInfo *Arch::getBoundWireNet(WireId wire) const { return wire_info(wire).bound_net; }
-NetInfo *Arch::getConflictingWireNet(WireId wire) const { return wires.at(wire).bound_net; }
+NetInfo *Arch::getConflictingWireNet(WireId wire) const { return wire_info(wire).bound_net; }
-const std::vector<BelPin> &Arch::getWireBelPins(WireId wire) const { return wires.at(wire).bel_pins; }
+const std::vector<BelPin> &Arch::getWireBelPins(WireId wire) const { return wire_info(wire).bel_pins; }
-const std::vector<WireId> &Arch::getWires() const { return wire_ids; }
+linear_range<WireId> Arch::getWires() const { return linear_range<WireId>(wires.size()); }
// ---------------------------------------------------------------
PipId Arch::getPipByName(IdStringList name) const
{
- if (pips.count(name))
- return name;
- return PipId();
+ if (name.size() == 0)
+ return PipId();
+ auto fnd = pip_by_name.find(name);
+ if (fnd == pip_by_name.end())
+ NPNR_ASSERT_FALSE_STR("no pip named " + name.str(getCtx()));
+ return fnd->second;
}
-IdStringList Arch::getPipName(PipId pip) const { return pip; }
+IdStringList Arch::getPipName(PipId pip) const { return pip_info(pip).name; }
-IdString Arch::getPipType(PipId pip) const { return pips.at(pip).type; }
+IdString Arch::getPipType(PipId pip) const { return pip_info(pip).type; }
-const std::map<IdString, std::string> &Arch::getPipAttrs(PipId pip) const { return pips.at(pip).attrs; }
+const std::map<IdString, std::string> &Arch::getPipAttrs(PipId pip) const { return pip_info(pip).attrs; }
-uint32_t Arch::getPipChecksum(PipId wire) const
-{
- // FIXME
- return 0;
-}
+uint32_t Arch::getPipChecksum(PipId pip) const { return pip.index; }
void Arch::bindPip(PipId pip, NetInfo *net, PlaceStrength strength)
{
- WireId wire = pips.at(pip).dstWire;
- pips.at(pip).bound_net = net;
- wires.at(wire).bound_net = net;
+ WireId wire = pip_info(pip).dstWire;
+ pip_info(pip).bound_net = net;
+ wire_info(wire).bound_net = net;
net->wires[wire].pip = pip;
net->wires[wire].strength = strength;
refreshUiPip(pip);
@@ -440,41 +423,44 @@ void Arch::bindPip(PipId pip, NetInfo *net, PlaceStrength strength)
void Arch::unbindPip(PipId pip)
{
- WireId wire = pips.at(pip).dstWire;
- wires.at(wire).bound_net->wires.erase(wire);
- pips.at(pip).bound_net = nullptr;
- wires.at(wire).bound_net = nullptr;
+ WireId wire = pip_info(pip).dstWire;
+ wire_info(wire).bound_net->wires.erase(wire);
+ pip_info(pip).bound_net = nullptr;
+ wire_info(wire).bound_net = nullptr;
refreshUiPip(pip);
refreshUiWire(wire);
}
-bool Arch::checkPipAvail(PipId pip) const { return pips.at(pip).bound_net == nullptr; }
+bool Arch::checkPipAvail(PipId pip) const { return pip_info(pip).bound_net == nullptr; }
bool Arch::checkPipAvailForNet(PipId pip, NetInfo *net) const
{
- NetInfo *bound_net = pips.at(pip).bound_net;
+ NetInfo *bound_net = pip_info(pip).bound_net;
return bound_net == nullptr || bound_net == net;
}
-NetInfo *Arch::getBoundPipNet(PipId pip) const { return pips.at(pip).bound_net; }
+NetInfo *Arch::getBoundPipNet(PipId pip) const { return pip_info(pip).bound_net; }
-NetInfo *Arch::getConflictingPipNet(PipId pip) const { return pips.at(pip).bound_net; }
+NetInfo *Arch::getConflictingPipNet(PipId pip) const { return pip_info(pip).bound_net; }
-WireId Arch::getConflictingPipWire(PipId pip) const { return pips.at(pip).bound_net ? pips.at(pip).dstWire : WireId(); }
+WireId Arch::getConflictingPipWire(PipId pip) const
+{
+ return pip_info(pip).bound_net ? pip_info(pip).dstWire : WireId();
+}
-const std::vector<PipId> &Arch::getPips() const { return pip_ids; }
+linear_range<PipId> Arch::getPips() const { return linear_range<PipId>(pips.size()); }
-Loc Arch::getPipLocation(PipId pip) const { return pips.at(pip).loc; }
+Loc Arch::getPipLocation(PipId pip) const { return pip_info(pip).loc; }
-WireId Arch::getPipSrcWire(PipId pip) const { return pips.at(pip).srcWire; }
+WireId Arch::getPipSrcWire(PipId pip) const { return pip_info(pip).srcWire; }
-WireId Arch::getPipDstWire(PipId pip) const { return pips.at(pip).dstWire; }
+WireId Arch::getPipDstWire(PipId pip) const { return pip_info(pip).dstWire; }
-DelayQuad Arch::getPipDelay(PipId pip) const { return DelayQuad(pips.at(pip).delay); }
+DelayQuad Arch::getPipDelay(PipId pip) const { return DelayQuad(pip_info(pip).delay); }
-const std::vector<PipId> &Arch::getPipsDownhill(WireId wire) const { return wires.at(wire).downhill; }
+const std::vector<PipId> &Arch::getPipsDownhill(WireId wire) const { return wire_info(wire).downhill; }
-const std::vector<PipId> &Arch::getPipsUphill(WireId wire) const { return wires.at(wire).uphill; }
+const std::vector<PipId> &Arch::getPipsUphill(WireId wire) const { return wire_info(wire).uphill; }
// ---------------------------------------------------------------
@@ -502,8 +488,8 @@ const std::vector<GroupId> &Arch::getGroupGroups(GroupId group) const { return g
delay_t Arch::estimateDelay(WireId src, WireId dst) const
{
- const WireInfo &s = wires.at(src);
- const WireInfo &d = wires.at(dst);
+ const WireInfo &s = wire_info(src);
+ const WireInfo &d = wire_info(dst);
int dx = abs(s.x - d.x);
int dy = abs(s.y - d.y);
return (dx + dy) * args.delayScale + args.delayOffset;
@@ -527,10 +513,10 @@ ArcBounds Arch::getRouteBoundingBox(WireId src, WireId dst) const
{
ArcBounds bb;
- int src_x = wires.at(src).x;
- int src_y = wires.at(src).y;
- int dst_x = wires.at(dst).x;
- int dst_y = wires.at(dst).y;
+ int src_x = wire_info(src).x;
+ int src_y = wire_info(src).y;
+ int dst_x = wire_info(dst).x;
+ int dst_y = wire_info(dst).y;
bb.x0 = src_x;
bb.y0 = src_y;
@@ -611,11 +597,11 @@ const std::vector<GraphicElement> &Arch::getDecalGraphics(DecalId decal) const
return decal_graphics.at(decal);
}
-DecalXY Arch::getBelDecal(BelId bel) const { return bels.at(bel).decalxy; }
+DecalXY Arch::getBelDecal(BelId bel) const { return bel_info(bel).decalxy; }
-DecalXY Arch::getWireDecal(WireId wire) const { return wires.at(wire).decalxy; }
+DecalXY Arch::getWireDecal(WireId wire) const { return wire_info(wire).decalxy; }
-DecalXY Arch::getPipDecal(PipId pip) const { return pips.at(pip).decalxy; }
+DecalXY Arch::getPipDecal(PipId pip) const { return pip_info(pip).decalxy; }
DecalXY Arch::getGroupDecal(GroupId group) const { return groups.at(group).decalxy; }
diff --git a/generic/arch.h b/generic/arch.h
index 7f574f31..885089ca 100644
--- a/generic/arch.h
+++ b/generic/arch.h
@@ -60,8 +60,6 @@ struct WireInfo
std::map<IdString, std::string> attrs;
NetInfo *bound_net;
std::vector<PipId> downhill, uphill;
- BelPin uphill_bel_pin;
- std::vector<BelPin> downhill_bel_pins;
std::vector<BelPin> bel_pins;
DecalXY decalxy;
int x, y;
@@ -111,23 +109,40 @@ struct CellTiming
dict<IdString, std::vector<TimingClockingInfo>> clockingInfo;
};
+template <typename TId> struct linear_range
+{
+ struct iterator
+ {
+ explicit iterator(int32_t index) : index(index){};
+ int32_t index;
+ bool operator==(const iterator &other) const { return index == other.index; }
+ bool operator!=(const iterator &other) const { return index != other.index; }
+ void operator++() { ++index; }
+ TId operator*() const { return TId(index); }
+ };
+ explicit linear_range(int32_t size) : size(size){};
+ int32_t size;
+ iterator begin() const { return iterator(0); }
+ iterator end() const { return iterator(size); }
+};
+
struct ArchRanges
{
using ArchArgsT = ArchArgs;
// Bels
- using AllBelsRangeT = const std::vector<BelId> &;
+ using AllBelsRangeT = linear_range<BelId>;
using TileBelsRangeT = const std::vector<BelId> &;
using BelAttrsRangeT = const std::map<IdString, std::string> &;
using BelPinsRangeT = std::vector<IdString>;
using CellBelPinRangeT = const std::vector<IdString> &;
// Wires
- using AllWiresRangeT = const std::vector<WireId> &;
+ using AllWiresRangeT = linear_range<WireId>;
using DownhillPipRangeT = const std::vector<PipId> &;
using UphillPipRangeT = const std::vector<PipId> &;
using WireBelPinRangeT = const std::vector<BelPin> &;
using WireAttrsRangeT = const std::map<IdString, std::string> &;
// Pips
- using AllPipsRangeT = const std::vector<PipId> &;
+ using AllPipsRangeT = linear_range<PipId>;
using PipAttrsRangeT = const std::map<IdString, std::string> &;
// Groups
using AllGroupsRangeT = std::vector<GroupId>;
@@ -147,17 +162,22 @@ struct Arch : ArchAPI<ArchRanges>
{
std::string chipName;
- dict<IdStringList, WireInfo> wires;
- dict<IdStringList, PipInfo> pips;
- dict<IdStringList, BelInfo> bels;
+ std::vector<WireInfo> wires;
+ std::vector<PipInfo> pips;
+ std::vector<BelInfo> bels;
dict<GroupId, GroupInfo> groups;
- // These functions include useful errors if not found
- WireInfo &wire_info(IdStringList wire);
- PipInfo &pip_info(IdStringList wire);
- BelInfo &bel_info(IdStringList wire);
+ WireInfo &wire_info(WireId wire) { return wires.at(wire.index); }
+ PipInfo &pip_info(PipId pip) { return pips.at(pip.index); }
+ BelInfo &bel_info(BelId bel) { return bels.at(bel.index); }
+
+ const WireInfo &wire_info(WireId wire) const { return wires.at(wire.index); }
+ const PipInfo &pip_info(PipId pip) const { return pips.at(pip.index); }
+ const BelInfo &bel_info(BelId bel) const { return bels.at(bel.index); }
- std::vector<IdStringList> bel_ids, wire_ids, pip_ids;
+ dict<IdStringList, WireId> wire_by_name;
+ dict<IdStringList, PipId> pip_by_name;
+ dict<IdStringList, BelId> bel_by_name;
dict<Loc, BelId> bel_by_loc;
std::vector<std::vector<std::vector<BelId>>> bels_by_tile;
@@ -170,17 +190,17 @@ struct Arch : ArchAPI<ArchRanges>
dict<IdString, CellTiming> cellTiming;
- void addWire(IdStringList name, IdString type, int x, int y);
- void addPip(IdStringList name, IdString type, IdStringList srcWire, IdStringList dstWire, delay_t delay, Loc loc);
+ WireId addWire(IdStringList name, IdString type, int x, int y);
+ PipId addPip(IdStringList name, IdString type, WireId srcWire, WireId dstWire, delay_t delay, Loc loc);
- void addBel(IdStringList name, IdString type, Loc loc, bool gb, bool hidden);
- void addBelInput(IdStringList bel, IdString name, IdStringList wire);
- void addBelOutput(IdStringList bel, IdString name, IdStringList wire);
- void addBelInout(IdStringList bel, IdString name, IdStringList wire);
+ BelId addBel(IdStringList name, IdString type, Loc loc, bool gb, bool hidden);
+ void addBelInput(BelId bel, IdString name, WireId wire);
+ void addBelOutput(BelId bel, IdString name, WireId wire);
+ void addBelInout(BelId bel, IdString name, WireId wire);
- void addGroupBel(IdStringList group, IdStringList bel);
- void addGroupWire(IdStringList group, IdStringList wire);
- void addGroupPip(IdStringList group, IdStringList pip);
+ void addGroupBel(IdStringList group, BelId bel);
+ void addGroupWire(IdStringList group, WireId wire);
+ void addGroupPip(IdStringList group, PipId pip);
void addGroupGroup(IdStringList group, IdStringList grp);
void addDecalGraphic(DecalId decal, const GraphicElement &graphic);
@@ -189,9 +209,9 @@ struct Arch : ArchAPI<ArchRanges>
void setBelDecal(BelId bel, DecalXY decalxy);
void setGroupDecal(GroupId group, DecalXY decalxy);
- void setWireAttr(IdStringList wire, IdString key, const std::string &value);
- void setPipAttr(IdStringList pip, IdString key, const std::string &value);
- void setBelAttr(IdStringList bel, IdString key, const std::string &value);
+ void setWireAttr(WireId wire, IdString key, const std::string &value);
+ void setPipAttr(PipId pip, IdString key, const std::string &value);
+ void setBelAttr(BelId bel, IdString key, const std::string &value);
void setLutK(int K);
void setDelayScaling(double scale, double offset);
@@ -234,7 +254,7 @@ struct Arch : ArchAPI<ArchRanges>
bool checkBelAvail(BelId bel) const override;
CellInfo *getBoundBelCell(BelId bel) const override;
CellInfo *getConflictingBelCell(BelId bel) const override;
- const std::vector<BelId> &getBels() const override;
+ linear_range<BelId> getBels() const override;
IdString getBelType(BelId bel) const override;
bool getBelHidden(BelId bel) const override;
const std::map<IdString, std::string> &getBelAttrs(BelId bel) const override;
@@ -255,7 +275,7 @@ struct Arch : ArchAPI<ArchRanges>
WireId getConflictingWireWire(WireId wire) const override { return wire; }
NetInfo *getConflictingWireNet(WireId wire) const override;
DelayQuad getWireDelay(WireId wire) const override { return DelayQuad(0); }
- const std::vector<WireId> &getWires() const override;
+ linear_range<WireId> getWires() const override;
const std::vector<BelPin> &getWireBelPins(WireId wire) const override;
PipId getPipByName(IdStringList name) const override;
@@ -270,7 +290,7 @@ struct Arch : ArchAPI<ArchRanges>
NetInfo *getBoundPipNet(PipId pip) const override;
WireId getConflictingPipWire(PipId pip) const override;
NetInfo *getConflictingPipNet(PipId pip) const override;
- const std::vector<PipId> &getPips() const override;
+ linear_range<PipId> getPips() const override;
Loc getPipLocation(PipId pip) const override;
WireId getPipSrcWire(PipId pip) const override;
WireId getPipDstWire(PipId pip) const override;
@@ -307,7 +327,7 @@ struct Arch : ArchAPI<ArchRanges>
{
pool<IdString> cell_types;
for (auto bel : bels) {
- cell_types.insert(bel.second.type);
+ cell_types.insert(bel.type);
}
return std::vector<IdString>{cell_types.begin(), cell_types.end()};
diff --git a/generic/arch_pybindings.cc b/generic/arch_pybindings.cc
index df59b4fe..92c78252 100644
--- a/generic/arch_pybindings.cc
+++ b/generic/arch_pybindings.cc
@@ -42,6 +42,10 @@ void arch_wrap_python(py::module &m)
{
using namespace PythonConversion;
+ typedef linear_range<BelId> BelRange;
+ typedef linear_range<WireId> WireRange;
+ typedef linear_range<PipId> AllPipRange;
+
auto arch_cls = py::class_<Arch, BaseCtx>(m, "Arch").def(py::init<ArchArgs>());
auto dxy_cls = py::class_<ContextualWrapper<DecalXY>>(m, "DecalXY_");
@@ -74,8 +78,8 @@ void arch_wrap_python(py::module &m)
conv_from_str<BelId>>::def_wrap(ctx_cls, "getBoundBelCell");
fn_wrapper_1a<Context, decltype(&Context::getConflictingBelCell), &Context::getConflictingBelCell,
deref_and_wrap<CellInfo>, conv_from_str<BelId>>::def_wrap(ctx_cls, "getConflictingBelCell");
- fn_wrapper_0a<Context, decltype(&Context::getBels), &Context::getBels,
- wrap_context<const std::vector<BelId> &>>::def_wrap(ctx_cls, "getBels");
+ fn_wrapper_0a<Context, decltype(&Context::getBels), &Context::getBels, wrap_context<BelRange>>::def_wrap(ctx_cls,
+ "getBels");
fn_wrapper_2a<Context, decltype(&Context::getBelPinWire), &Context::getBelPinWire, conv_to_str<WireId>,
conv_from_str<BelId>, conv_from_str<IdString>>::def_wrap(ctx_cls, "getBelPinWire");
@@ -96,11 +100,11 @@ void arch_wrap_python(py::module &m)
fn_wrapper_1a<Context, decltype(&Context::getConflictingWireNet), &Context::getConflictingWireNet,
deref_and_wrap<NetInfo>, conv_from_str<WireId>>::def_wrap(ctx_cls, "getConflictingWireNet");
- fn_wrapper_0a<Context, decltype(&Context::getWires), &Context::getWires,
- wrap_context<const std::vector<WireId> &>>::def_wrap(ctx_cls, "getWires");
+ fn_wrapper_0a<Context, decltype(&Context::getWires), &Context::getWires, wrap_context<WireRange>>::def_wrap(
+ ctx_cls, "getWires");
- fn_wrapper_0a<Context, decltype(&Context::getPips), &Context::getPips,
- wrap_context<const std::vector<PipId> &>>::def_wrap(ctx_cls, "getPips");
+ fn_wrapper_0a<Context, decltype(&Context::getPips), &Context::getPips, wrap_context<AllPipRange>>::def_wrap(
+ ctx_cls, "getPips");
fn_wrapper_1a<Context, decltype(&Context::getPipChecksum), &Context::getPipChecksum, pass_through<uint32_t>,
conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipChecksum");
fn_wrapper_3a_v<Context, decltype(&Context::bindPip), &Context::bindPip, conv_from_str<PipId>,
@@ -156,50 +160,50 @@ void arch_wrap_python(py::module &m)
"name"_a, "type"_a, "x"_a,
"y"_a);
fn_wrapper_6a_v<Context, decltype(&Context::addPip), &Context::addPip, conv_from_str<IdStringList>,
- conv_from_str<IdString>, conv_from_str<IdStringList>, conv_from_str<IdStringList>,
- pass_through<delay_t>, pass_through<Loc>>::def_wrap(ctx_cls, "addPip", "name"_a, "type"_a,
- "srcWire"_a, "dstWire"_a, "delay"_a, "loc"_a);
+ conv_from_str<IdString>, conv_from_str<WireId>, conv_from_str<WireId>, pass_through<delay_t>,
+ pass_through<Loc>>::def_wrap(ctx_cls, "addPip", "name"_a, "type"_a, "srcWire"_a, "dstWire"_a,
+ "delay"_a, "loc"_a);
fn_wrapper_5a_v<Context, decltype(&Context::addBel), &Context::addBel, conv_from_str<IdStringList>,
conv_from_str<IdString>, pass_through<Loc>, pass_through<bool>,
pass_through<bool>>::def_wrap(ctx_cls, "addBel", "name"_a, "type"_a, "loc"_a, "gb"_a, "hidden"_a);
- fn_wrapper_3a_v<Context, decltype(&Context::addBelInput), &Context::addBelInput, conv_from_str<IdStringList>,
- conv_from_str<IdString>, conv_from_str<IdStringList>>::def_wrap(ctx_cls, "addBelInput", "bel"_a,
- "name"_a, "wire"_a);
- fn_wrapper_3a_v<Context, decltype(&Context::addBelOutput), &Context::addBelOutput, conv_from_str<IdStringList>,
- conv_from_str<IdString>, conv_from_str<IdStringList>>::def_wrap(ctx_cls, "addBelOutput", "bel"_a,
- "name"_a, "wire"_a);
- fn_wrapper_3a_v<Context, decltype(&Context::addBelInout), &Context::addBelInout, conv_from_str<IdStringList>,
- conv_from_str<IdString>, conv_from_str<IdStringList>>::def_wrap(ctx_cls, "addBelInout", "bel"_a,
- "name"_a, "wire"_a);
+ fn_wrapper_3a_v<Context, decltype(&Context::addBelInput), &Context::addBelInput, conv_from_str<BelId>,
+ conv_from_str<IdString>, conv_from_str<WireId>>::def_wrap(ctx_cls, "addBelInput", "bel"_a, "name"_a,
+ "wire"_a);
+ fn_wrapper_3a_v<Context, decltype(&Context::addBelOutput), &Context::addBelOutput, conv_from_str<BelId>,
+ conv_from_str<IdString>, conv_from_str<WireId>>::def_wrap(ctx_cls, "addBelOutput", "bel"_a,
+ "name"_a, "wire"_a);
+ fn_wrapper_3a_v<Context, decltype(&Context::addBelInout), &Context::addBelInout, conv_from_str<BelId>,
+ conv_from_str<IdString>, conv_from_str<WireId>>::def_wrap(ctx_cls, "addBelInout", "bel"_a, "name"_a,
+ "wire"_a);
fn_wrapper_2a_v<Context, decltype(&Context::addGroupBel), &Context::addGroupBel, conv_from_str<IdStringList>,
- conv_from_str<IdStringList>>::def_wrap(ctx_cls, "addGroupBel", "group"_a, "bel"_a);
+ conv_from_str<BelId>>::def_wrap(ctx_cls, "addGroupBel", "group"_a, "bel"_a);
fn_wrapper_2a_v<Context, decltype(&Context::addGroupWire), &Context::addGroupWire, conv_from_str<IdStringList>,
- conv_from_str<IdStringList>>::def_wrap(ctx_cls, "addGroupWire", "group"_a, "wire"_a);
+ conv_from_str<WireId>>::def_wrap(ctx_cls, "addGroupWire", "group"_a, "wire"_a);
fn_wrapper_2a_v<Context, decltype(&Context::addGroupPip), &Context::addGroupPip, conv_from_str<IdStringList>,
- conv_from_str<IdStringList>>::def_wrap(ctx_cls, "addGroupPip", "group"_a, "pip"_a);
- fn_wrapper_2a_v<Context, decltype(&Context::addGroupGroup), &Context::addGroupPip, conv_from_str<IdStringList>,
+ conv_from_str<PipId>>::def_wrap(ctx_cls, "addGroupPip", "group"_a, "pip"_a);
+ fn_wrapper_2a_v<Context, decltype(&Context::addGroupGroup), &Context::addGroupGroup, conv_from_str<IdStringList>,
conv_from_str<IdStringList>>::def_wrap(ctx_cls, "addGroupGroup", "group"_a, "grp"_a);
fn_wrapper_2a_v<Context, decltype(&Context::addDecalGraphic), &Context::addDecalGraphic, conv_from_str<DecalId>,
pass_through<GraphicElement>>::def_wrap(ctx_cls, "addDecalGraphic", (py::arg("decal"), "graphic"));
- fn_wrapper_2a_v<Context, decltype(&Context::setWireDecal), &Context::setWireDecal, conv_from_str<DecalId>,
+ fn_wrapper_2a_v<Context, decltype(&Context::setWireDecal), &Context::setWireDecal, conv_from_str<WireId>,
unwrap_context<DecalXY>>::def_wrap(ctx_cls, "setWireDecal", "wire"_a, "decalxy"_a);
- fn_wrapper_2a_v<Context, decltype(&Context::setPipDecal), &Context::setPipDecal, conv_from_str<DecalId>,
+ fn_wrapper_2a_v<Context, decltype(&Context::setPipDecal), &Context::setPipDecal, conv_from_str<PipId>,
unwrap_context<DecalXY>>::def_wrap(ctx_cls, "setPipDecal", "pip"_a, "decalxy"_a);
- fn_wrapper_2a_v<Context, decltype(&Context::setBelDecal), &Context::setBelDecal, conv_from_str<DecalId>,
+ fn_wrapper_2a_v<Context, decltype(&Context::setBelDecal), &Context::setBelDecal, conv_from_str<BelId>,
unwrap_context<DecalXY>>::def_wrap(ctx_cls, "setBelDecal", "bel"_a, "decalxy"_a);
fn_wrapper_2a_v<Context, decltype(&Context::setGroupDecal), &Context::setGroupDecal, conv_from_str<DecalId>,
unwrap_context<DecalXY>>::def_wrap(ctx_cls, "setGroupDecal", "group"_a, "decalxy"_a);
- fn_wrapper_3a_v<Context, decltype(&Context::setWireAttr), &Context::setWireAttr, conv_from_str<DecalId>,
+ fn_wrapper_3a_v<Context, decltype(&Context::setWireAttr), &Context::setWireAttr, conv_from_str<WireId>,
conv_from_str<IdString>, pass_through<std::string>>::def_wrap(ctx_cls, "setWireAttr", "wire"_a,
"key"_a, "value"_a);
- fn_wrapper_3a_v<Context, decltype(&Context::setBelAttr), &Context::setBelAttr, conv_from_str<DecalId>,
+ fn_wrapper_3a_v<Context, decltype(&Context::setBelAttr), &Context::setBelAttr, conv_from_str<BelId>,
conv_from_str<IdString>, pass_through<std::string>>::def_wrap(ctx_cls, "setBelAttr", "bel"_a,
"key"_a, "value"_a);
- fn_wrapper_3a_v<Context, decltype(&Context::setPipAttr), &Context::setPipAttr, conv_from_str<DecalId>,
+ fn_wrapper_3a_v<Context, decltype(&Context::setPipAttr), &Context::setPipAttr, conv_from_str<PipId>,
conv_from_str<IdString>, pass_through<std::string>>::def_wrap(ctx_cls, "setPipAttr", "pip"_a,
"key"_a, "value"_a);
@@ -254,6 +258,10 @@ void arch_wrap_python(py::module &m)
pass_through<bool>, conv_from_str<IdString>, conv_from_str<BelId>>::def_wrap(ctx_cls,
"isValidBelForCellType");
+ WRAP_RANGE(m, Bel, conv_to_str<BelId>);
+ WRAP_RANGE(m, Wire, conv_to_str<WireId>);
+ WRAP_RANGE(m, AllPip, conv_to_str<PipId>);
+
WRAP_MAP_UPTR(m, CellMap, "IdCellMap");
WRAP_MAP_UPTR(m, NetMap, "IdNetMap");
WRAP_MAP(m, HierarchyMap, wrap_context<HierarchicalCell &>, "HierarchyMap");
diff --git a/generic/arch_pybindings.h b/generic/arch_pybindings.h
index 9a573540..72d688dc 100644
--- a/generic/arch_pybindings.h
+++ b/generic/arch_pybindings.h
@@ -26,6 +26,73 @@
NEXTPNR_NAMESPACE_BEGIN
+namespace PythonConversion {
+
+template <> struct string_converter<BelId>
+{
+ BelId from_str(Context *ctx, std::string name) { return ctx->getBelByNameStr(name); }
+
+ std::string to_str(Context *ctx, BelId id)
+ {
+ if (id == BelId())
+ throw bad_wrap();
+ return ctx->getBelName(id).str(ctx);
+ }
+};
+
+template <> struct string_converter<WireId>
+{
+ WireId from_str(Context *ctx, std::string name) { return ctx->getWireByNameStr(name); }
+
+ std::string to_str(Context *ctx, WireId id)
+ {
+ if (id == WireId())
+ throw bad_wrap();
+ return ctx->getWireName(id).str(ctx);
+ }
+};
+
+template <> struct string_converter<const WireId>
+{
+ WireId from_str(Context *ctx, std::string name) { return ctx->getWireByNameStr(name); }
+
+ std::string to_str(Context *ctx, WireId id)
+ {
+ if (id == WireId())
+ throw bad_wrap();
+ return ctx->getWireName(id).str(ctx);
+ }
+};
+
+template <> struct string_converter<PipId>
+{
+ PipId from_str(Context *ctx, std::string name) { return ctx->getPipByNameStr(name); }
+
+ std::string to_str(Context *ctx, PipId id)
+ {
+ if (id == PipId())
+ throw bad_wrap();
+ return ctx->getPipName(id).str(ctx);
+ }
+};
+
+template <> struct string_converter<BelPin>
+{
+ BelPin from_str(Context *ctx, std::string name)
+ {
+ NPNR_ASSERT_FALSE("string_converter<BelPin>::from_str not implemented");
+ }
+
+ std::string to_str(Context *ctx, BelPin pin)
+ {
+ if (pin.bel == BelId())
+ throw bad_wrap();
+ return ctx->getBelName(pin.bel).str(ctx) + "/" + pin.pin.str(ctx);
+ }
+};
+
+} // namespace PythonConversion
+
NEXTPNR_NAMESPACE_END
#endif
#endif
diff --git a/generic/archdefs.h b/generic/archdefs.h
index c46fba93..2d46c0a2 100644
--- a/generic/archdefs.h
+++ b/generic/archdefs.h
@@ -27,9 +27,42 @@ NEXTPNR_NAMESPACE_BEGIN
typedef float delay_t;
-typedef IdStringList BelId;
-typedef IdStringList WireId;
-typedef IdStringList PipId;
+struct BelId
+{
+ BelId() : index(-1){};
+ explicit BelId(int32_t index) : index(index){};
+ int32_t index = -1;
+
+ bool operator==(const BelId &other) const { return index == other.index; }
+ bool operator!=(const BelId &other) const { return index != other.index; }
+ bool operator<(const BelId &other) const { return index < other.index; }
+ unsigned int hash() const { return index; }
+};
+
+struct WireId
+{
+ WireId() : index(-1){};
+ explicit WireId(int32_t index) : index(index){};
+ int32_t index = -1;
+
+ bool operator==(const WireId &other) const { return index == other.index; }
+ bool operator!=(const WireId &other) const { return index != other.index; }
+ bool operator<(const WireId &other) const { return index < other.index; }
+ unsigned int hash() const { return index; }
+};
+
+struct PipId
+{
+ PipId() : index(-1){};
+ explicit PipId(int32_t index) : index(index){};
+ int32_t index = -1;
+
+ bool operator==(const PipId &other) const { return index == other.index; }
+ bool operator!=(const PipId &other) const { return index != other.index; }
+ bool operator<(const PipId &other) const { return index < other.index; }
+ unsigned int hash() const { return index; }
+};
+
typedef IdStringList GroupId;
typedef IdStringList DecalId;
typedef IdString BelBucketId;
diff --git a/generic/examples/write_fasm.py b/generic/examples/write_fasm.py
index ede8f16b..057e779c 100644
--- a/generic/examples/write_fasm.py
+++ b/generic/examples/write_fasm.py
@@ -29,7 +29,7 @@ def write_fasm(ctx, paramCfg, f):
for nname, net in sorted(ctx.nets, key=lambda x: str(x[1].name)):
print("# Net %s" % nname, file=f)
for wire, pip in sorted(net.wires, key=lambda x: str(x[1])):
- if pip.pip != "":
+ if pip.pip is not None:
print("%s" % pip.pip, file=f)
print("", file=f)
for cname, cell in sorted(ctx.cells, key=lambda x: str(x[1].name)):