diff options
34 files changed, 765 insertions, 768 deletions
diff --git a/common/basectx.cc b/common/basectx.cc index b55cd072..83a2deea 100644 --- a/common/basectx.cc +++ b/common/basectx.cc @@ -22,7 +22,6 @@ #include <boost/algorithm/string.hpp> #include "context.h" -#include "design_utils.h" #include "log.h" NEXTPNR_NAMESPACE_BEGIN @@ -223,13 +222,23 @@ void BaseCtx::connectPort(IdString net, IdString cell, IdString port) { NetInfo *net_info = getNetByAlias(net); CellInfo *cell_info = cells.at(cell).get(); - connect_port(getCtx(), net_info, cell_info, port); + cell_info->connectPort(port, net_info); } void BaseCtx::disconnectPort(IdString cell, IdString port) { CellInfo *cell_info = cells.at(cell).get(); - disconnect_port(getCtx(), cell_info, port); + cell_info->disconnectPort(port); +} + +void BaseCtx::renameNet(IdString old_name, IdString new_name) +{ + NetInfo *net = nets.at(old_name).get(); + NPNR_ASSERT(!nets.count(new_name)); + nets[new_name]; + std::swap(nets.at(net->name), nets.at(new_name)); + nets.erase(net->name); + net->name = new_name; } void BaseCtx::ripupNet(IdString name) diff --git a/common/basectx.h b/common/basectx.h index 507f29cd..21d6d63a 100644 --- a/common/basectx.h +++ b/common/basectx.h @@ -226,6 +226,7 @@ struct BaseCtx void disconnectPort(IdString cell, IdString port); void ripupNet(IdString name); void lockNetRouting(IdString name); + void renameNet(IdString old_name, IdString new_name); CellInfo *createCell(IdString name, IdString type); void copyBelPorts(IdString cell, BelId bel); diff --git a/common/design_utils.cc b/common/design_utils.cc index 9432b6cd..f52cc304 100644 --- a/common/design_utils.cc +++ b/common/design_utils.cc @@ -25,42 +25,6 @@ #include "util.h" NEXTPNR_NAMESPACE_BEGIN -void replace_port(CellInfo *old_cell, IdString old_name, CellInfo *rep_cell, IdString rep_name) -{ - if (!old_cell->ports.count(old_name)) - return; - PortInfo &old = old_cell->ports.at(old_name); - - // Create port on the replacement cell if it doesn't already exist - if (!rep_cell->ports.count(rep_name)) { - rep_cell->ports[rep_name].name = rep_name; - rep_cell->ports[rep_name].type = old.type; - } - - PortInfo &rep = rep_cell->ports.at(rep_name); - NPNR_ASSERT(old.type == rep.type); - - rep.net = old.net; - old.net = nullptr; - if (rep.type == PORT_OUT) { - if (rep.net != nullptr) { - rep.net->driver.cell = rep_cell; - rep.net->driver.port = rep_name; - } - } else if (rep.type == PORT_IN) { - if (rep.net != nullptr) { - for (PortRef &load : rep.net->users) { - if (load.cell == old_cell && load.port == old_name) { - load.cell = rep_cell; - load.port = rep_name; - } - } - } - } else { - NPNR_ASSERT(false); - } -} - // Print utilisation of a design void print_utilisation(const Context *ctx) { @@ -85,111 +49,4 @@ void print_utilisation(const Context *ctx) log_break(); } -// Connect a net to a port -void connect_port(const Context *ctx, NetInfo *net, CellInfo *cell, IdString port_name) -{ - if (net == nullptr) - return; - PortInfo &port = cell->ports.at(port_name); - NPNR_ASSERT(port.net == nullptr); - port.net = net; - if (port.type == PORT_OUT) { - NPNR_ASSERT(net->driver.cell == nullptr); - net->driver.cell = cell; - net->driver.port = port_name; - } else if (port.type == PORT_IN || port.type == PORT_INOUT) { - PortRef user; - user.cell = cell; - user.port = port_name; - net->users.push_back(user); - } else { - NPNR_ASSERT_FALSE("invalid port type for connect_port"); - } -} - -void disconnect_port(const Context *ctx, CellInfo *cell, IdString port_name) -{ - if (!cell->ports.count(port_name)) - return; - PortInfo &port = cell->ports.at(port_name); - if (port.net != nullptr) { - port.net->users.erase(std::remove_if(port.net->users.begin(), port.net->users.end(), - [cell, port_name](const PortRef &user) { - return user.cell == cell && user.port == port_name; - }), - port.net->users.end()); - if (port.net->driver.cell == cell && port.net->driver.port == port_name) - port.net->driver.cell = nullptr; - port.net = nullptr; - } -} - -void connect_ports(Context *ctx, CellInfo *cell1, IdString port1_name, CellInfo *cell2, IdString port2_name) -{ - PortInfo &port1 = cell1->ports.at(port1_name); - if (port1.net == nullptr) { - // No net on port1; need to create one - NetInfo *p1net = ctx->createNet(ctx->id(cell1->name.str(ctx) + "$conn$" + port1_name.str(ctx))); - connect_port(ctx, p1net, cell1, port1_name); - } - connect_port(ctx, port1.net, cell2, port2_name); -} - -void rename_port(Context *ctx, CellInfo *cell, IdString old_name, IdString new_name) -{ - if (!cell->ports.count(old_name)) - return; - PortInfo pi = cell->ports.at(old_name); - if (pi.net != nullptr) { - if (pi.net->driver.cell == cell && pi.net->driver.port == old_name) - pi.net->driver.port = new_name; - for (auto &usr : pi.net->users) - if (usr.cell == cell && usr.port == old_name) - usr.port = new_name; - } - cell->ports.erase(old_name); - pi.name = new_name; - cell->ports[new_name] = pi; -} - -void rename_net(Context *ctx, NetInfo *net, IdString new_name) -{ - if (net == nullptr) - return; - NPNR_ASSERT(!ctx->nets.count(new_name)); - ctx->nets[new_name]; - std::swap(ctx->nets.at(net->name), ctx->nets.at(new_name)); - ctx->nets.erase(net->name); - net->name = new_name; -} - -void replace_bus(Context *ctx, CellInfo *old_cell, IdString old_name, int old_offset, bool old_brackets, - CellInfo *new_cell, IdString new_name, int new_offset, bool new_brackets, int width) -{ - for (int i = 0; i < width; i++) { - IdString old_port = ctx->id(stringf(old_brackets ? "%s[%d]" : "%s%d", old_name.c_str(ctx), i + old_offset)); - IdString new_port = ctx->id(stringf(new_brackets ? "%s[%d]" : "%s%d", new_name.c_str(ctx), i + new_offset)); - replace_port(old_cell, old_port, new_cell, new_port); - } -} - -void copy_port(Context *ctx, CellInfo *old_cell, IdString old_name, CellInfo *new_cell, IdString new_name) -{ - if (!old_cell->ports.count(old_name)) - return; - new_cell->ports[new_name].name = new_name; - new_cell->ports[new_name].type = old_cell->ports.at(old_name).type; - connect_port(ctx, old_cell->ports.at(old_name).net, new_cell, new_name); -} - -void copy_bus(Context *ctx, CellInfo *old_cell, IdString old_name, int old_offset, bool old_brackets, - CellInfo *new_cell, IdString new_name, int new_offset, bool new_brackets, int width) -{ - for (int i = 0; i < width; i++) { - IdString old_port = ctx->id(stringf(old_brackets ? "%s[%d]" : "%s%d", old_name.c_str(ctx), i + old_offset)); - IdString new_port = ctx->id(stringf(new_brackets ? "%s[%d]" : "%s%d", new_name.c_str(ctx), i + new_offset)); - copy_port(ctx, old_cell, old_port, new_cell, new_port); - } -} - NEXTPNR_NAMESPACE_END diff --git a/common/design_utils.h b/common/design_utils.h index 82c9ac45..63cb71d7 100644 --- a/common/design_utils.h +++ b/common/design_utils.h @@ -89,34 +89,8 @@ inline bool port_used(CellInfo *cell, IdString port_name) return port_fnd != cell->ports.end() && port_fnd->second.net != nullptr; } -// Connect a net to a port -void connect_port(const Context *ctx, NetInfo *net, CellInfo *cell, IdString port_name); - -// Disconnect a net from a port -void disconnect_port(const Context *ctx, CellInfo *cell, IdString port_name); - -// Connect two ports together -void connect_ports(Context *ctx, CellInfo *cell1, IdString port1_name, CellInfo *cell2, IdString port2_name); - -// Rename a port if it exists on a cell -void rename_port(Context *ctx, CellInfo *cell, IdString old_name, IdString new_name); - -// Rename a net without invalidating pointers to it -void rename_net(Context *ctx, NetInfo *net, IdString new_name); - void print_utilisation(const Context *ctx); -// Disconnect a bus of nets (if connected) from old, and connect it to the new ports -void replace_bus(Context *ctx, CellInfo *old_cell, IdString old_name, int old_offset, bool old_brackets, - CellInfo *new_cell, IdString new_name, int new_offset, bool new_brackets, int width); - -// Copy a bus of nets (if connected) from old, and connect it to the new ports -void copy_bus(Context *ctx, CellInfo *old_cell, IdString old_name, int old_offset, bool old_brackets, - CellInfo *new_cell, IdString new_name, int new_offset, bool new_brackets, int width); - -// Copy a port from one cell to another -void copy_port(Context *ctx, CellInfo *old_cell, IdString old_name, CellInfo *new_cell, IdString new_name); - NEXTPNR_NAMESPACE_END #endif diff --git a/common/nextpnr_types.cc b/common/nextpnr_types.cc index 3deed46f..c89a0071 100644 --- a/common/nextpnr_types.cc +++ b/common/nextpnr_types.cc @@ -18,6 +18,8 @@ */ #include "nextpnr_types.h" +#include "context.h" +#include "log.h" #include "nextpnr_namespaces.h" @@ -49,4 +51,135 @@ bool CellInfo::testRegion(BelId bel) const return region == nullptr || !region->constr_bels || region->bels.count(bel); } +void CellInfo::connectPort(IdString port_name, NetInfo *net) +{ + if (net == nullptr) + return; + PortInfo &port = ports.at(port_name); + NPNR_ASSERT(port.net == nullptr); + port.net = net; + if (port.type == PORT_OUT) { + NPNR_ASSERT(net->driver.cell == nullptr); + net->driver.cell = this; + net->driver.port = port_name; + } else if (port.type == PORT_IN || port.type == PORT_INOUT) { + PortRef user; + user.cell = this; + user.port = port_name; + net->users.push_back(user); + } else { + NPNR_ASSERT_FALSE("invalid port type for connect_port"); + } +} + +void CellInfo::disconnectPort(IdString port_name) +{ + if (!ports.count(port_name)) + return; + PortInfo &port = ports.at(port_name); + if (port.net != nullptr) { + port.net->users.erase(std::remove_if(port.net->users.begin(), port.net->users.end(), + [this, port_name](const PortRef &user) { + return user.cell == this && user.port == port_name; + }), + port.net->users.end()); + if (port.net->driver.cell == this && port.net->driver.port == port_name) + port.net->driver.cell = nullptr; + port.net = nullptr; + } +} + +void CellInfo::connectPorts(IdString port, CellInfo *other, IdString other_port) +{ + PortInfo &port1 = ports.at(port); + if (port1.net == nullptr) { + // No net on port1; need to create one + NetInfo *p1net = ctx->createNet(ctx->id(name.str(ctx) + "$conn$" + port.str(ctx))); + connectPort(port, p1net); + } + other->connectPort(other_port, port1.net); +} + +void CellInfo::movePortTo(IdString port, CellInfo *other, IdString other_port) +{ + if (!ports.count(port)) + return; + PortInfo &old = ports.at(port); + + // Create port on the replacement cell if it doesn't already exist + if (!other->ports.count(other_port)) { + other->ports[other_port].name = other_port; + other->ports[other_port].type = old.type; + } + + PortInfo &rep = other->ports.at(other_port); + NPNR_ASSERT(old.type == rep.type); + + rep.net = old.net; + old.net = nullptr; + if (rep.type == PORT_OUT) { + if (rep.net != nullptr) { + rep.net->driver.cell = other; + rep.net->driver.port = other_port; + } + } else if (rep.type == PORT_IN) { + if (rep.net != nullptr) { + for (PortRef &load : rep.net->users) { + if (load.cell == this && load.port == port) { + load.cell = other; + load.port = other_port; + } + } + } + } else { + NPNR_ASSERT(false); + } +} + +void CellInfo::renamePort(IdString old_name, IdString new_name) +{ + if (!ports.count(old_name)) + return; + PortInfo pi = ports.at(old_name); + if (pi.net != nullptr) { + if (pi.net->driver.cell == this && pi.net->driver.port == old_name) + pi.net->driver.port = new_name; + for (auto &usr : pi.net->users) + if (usr.cell == this && usr.port == old_name) + usr.port = new_name; + } + ports.erase(old_name); + pi.name = new_name; + ports[new_name] = pi; +} + +void CellInfo::movePortBusTo(IdString old_name, int old_offset, bool old_brackets, CellInfo *new_cell, + IdString new_name, int new_offset, bool new_brackets, int width) +{ + for (int i = 0; i < width; i++) { + IdString old_port = ctx->id(stringf(old_brackets ? "%s[%d]" : "%s%d", old_name.c_str(ctx), i + old_offset)); + IdString new_port = ctx->id(stringf(new_brackets ? "%s[%d]" : "%s%d", new_name.c_str(ctx), i + new_offset)); + movePortTo(old_port, new_cell, new_port); + } +} + +void CellInfo::copyPortTo(IdString port, CellInfo *other, IdString other_port) +{ + if (!ports.count(port)) + return; + other->ports[other_port].name = other_port; + other->ports[other_port].type = ports.at(port).type; + other->connectPort(other_port, ports.at(port).net); +} + +void CellInfo::copyPortBusTo(IdString old_name, int old_offset, bool old_brackets, CellInfo *new_cell, + IdString new_name, int new_offset, bool new_brackets, int width) +{ + for (int i = 0; i < width; i++) { + IdString old_port = ctx->id(stringf(old_brackets ? "%s[%d]" : "%s%d", old_name.c_str(ctx), i + old_offset)); + IdString new_port = ctx->id(stringf(new_brackets ? "%s[%d]" : "%s%d", new_name.c_str(ctx), i + new_offset)); + copyPortTo(old_port, new_cell, new_port); + } +} + NEXTPNR_NAMESPACE_END diff --git a/common/nextpnr_types.h b/common/nextpnr_types.h index 6debd2b8..cf93a071 100644 --- a/common/nextpnr_types.h +++ b/common/nextpnr_types.h @@ -187,6 +187,27 @@ struct CellInfo : ArchCellInfo void unsetAttr(IdString name); // check whether a bel complies with the cell's region constraint bool testRegion(BelId bel) const; + + NetInfo *getPort(IdString name) + { + auto found = ports.find(name); + return (found == ports.end()) ? nullptr : found->second.net; + } + const NetInfo *getPort(IdString name) const + { + auto found = ports.find(name); + return (found == ports.end()) ? nullptr : found->second.net; + } + void connectPort(IdString port, NetInfo *net); + void disconnectPort(IdString port); + void connectPorts(IdString port, CellInfo *other, IdString other_port); + void movePortTo(IdString port, CellInfo *other, IdString other_port); + void renamePort(IdString old_name, IdString new_name); + void movePortBusTo(IdString old_name, int old_offset, bool old_brackets, CellInfo *new_cell, IdString new_name, + int new_offset, bool new_brackets, int width); + void copyPortTo(IdString port, CellInfo *other, IdString other_port); + void copyPortBusTo(IdString old_name, int old_offset, bool old_brackets, CellInfo *new_cell, IdString new_name, + int new_offset, bool new_brackets, int width); }; enum TimingPortClass diff --git a/ecp5/arch_place.cc b/ecp5/arch_place.cc index a1f8aa1f..b1849ee6 100644 --- a/ecp5/arch_place.cc +++ b/ecp5/arch_place.cc @@ -124,10 +124,10 @@ void Arch::permute_luts() for (int i = 0; i < 4; i++) { IdString p = port_names.at(i); // log_info("%s %s %f\n", p.c_str(ctx), port_names.at(inputs.at(i).second).c_str(ctx), inputs.at(i).first); - disconnect_port(getCtx(), ci, p); + ci->disconnectPort(p); ci->ports.at(p).net = nullptr; if (orig_nets.at(inputs.at(i).second) != nullptr) { - connect_port(getCtx(), orig_nets.at(inputs.at(i).second), ci, p); + ci->connectPort(p, orig_nets.at(inputs.at(i).second)); ci->params[id(p.str(this) + "MUX")] = p.str(this); } else { ci->params[id(p.str(this) + "MUX")] = std::string("1"); diff --git a/ecp5/bitstream.cc b/ecp5/bitstream.cc index 11a855ec..a23e4cd2 100644 --- a/ecp5/bitstream.cc +++ b/ecp5/bitstream.cc @@ -1043,7 +1043,7 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex if (trimux_tsreg != "PADDT") cc.tiles[pic_tile].add_enum(pio + ".TRIMUX_TSREG", trimux_tsreg); } else if (ci->type == id_DCCA) { - const NetInfo *cen = get_net_or_empty(ci, id_CE); + const NetInfo *cen = ci->getPort(id_CE); if (cen != nullptr) { std::string belname = ctx->loc_info(bel)->bel_data[bel.index].name.get(); Loc loc = ctx->getBelLocation(bel); @@ -1347,13 +1347,13 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex tg.config.add_enum("CLKOS_TRIM_DELAY", intstr_or_default(ci->params, id_CLKOS_TRIM_DELAY, "0")); tg.config.add_enum("OUTDIVIDER_MUXA", str_or_default(ci->params, id_OUTDIVIDER_MUXA, - get_net_or_empty(ci, id_CLKOP) ? "DIVA" : "REFCLK")); + ci->getPort(id_CLKOP) ? "DIVA" : "REFCLK")); tg.config.add_enum("OUTDIVIDER_MUXB", str_or_default(ci->params, id_OUTDIVIDER_MUXB, - get_net_or_empty(ci, id_CLKOP) ? "DIVB" : "REFCLK")); + ci->getPort(id_CLKOP) ? "DIVB" : "REFCLK")); tg.config.add_enum("OUTDIVIDER_MUXC", str_or_default(ci->params, id_OUTDIVIDER_MUXC, - get_net_or_empty(ci, id_CLKOP) ? "DIVC" : "REFCLK")); + ci->getPort(id_CLKOP) ? "DIVC" : "REFCLK")); tg.config.add_enum("OUTDIVIDER_MUXD", str_or_default(ci->params, id_OUTDIVIDER_MUXD, - get_net_or_empty(ci, id_CLKOP) ? "DIVD" : "REFCLK")); + ci->getPort(id_CLKOP) ? "DIVD" : "REFCLK")); tg.config.add_word("PLL_LOCK_MODE", int_to_bitvector(int_or_default(ci->params, id_PLL_LOCK_MODE, 0), 3)); @@ -1404,7 +1404,7 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex else cc.tiles[pic_tile].add_enum(prim + "." + param.first.str(ctx), param.second.as_string()); } - if (get_net_or_empty(ci, id_LOADN) != nullptr) { + if (ci->getPort(id_LOADN) != nullptr) { cc.tiles[pic_tile].add_enum(prim + ".LOADNMUX", "LOADN"); } } else if (ci->type == id_DCUA) { @@ -1481,14 +1481,12 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex lo_del_value = (256 - lo_del_value) & 0xFF; tg.config.add_word("DQS.DQS_LI_DEL_VAL", int_to_bitvector(li_del_value, 8)); tg.config.add_word("DQS.DQS_LO_DEL_VAL", int_to_bitvector(lo_del_value, 8)); - tg.config.add_enum("DQS.WRLOADN_USED", get_net_or_empty(ci, id_WRLOADN) != nullptr ? "YES" : "NO"); - tg.config.add_enum("DQS.RDLOADN_USED", get_net_or_empty(ci, id_RDLOADN) != nullptr ? "YES" : "NO"); - tg.config.add_enum("DQS.PAUSE_USED", get_net_or_empty(ci, id_PAUSE) != nullptr ? "YES" : "NO"); + tg.config.add_enum("DQS.WRLOADN_USED", ci->getPort(id_WRLOADN) != nullptr ? "YES" : "NO"); + tg.config.add_enum("DQS.RDLOADN_USED", ci->getPort(id_RDLOADN) != nullptr ? "YES" : "NO"); + tg.config.add_enum("DQS.PAUSE_USED", ci->getPort(id_PAUSE) != nullptr ? "YES" : "NO"); tg.config.add_enum("DQS.READ_USED", - (get_net_or_empty(ci, id_READ0) != nullptr || get_net_or_empty(ci, id_READ1) != nullptr) - ? "YES" - : "NO"); - tg.config.add_enum("DQS.DDRDEL", get_net_or_empty(ci, id_DDRDEL) != nullptr ? "DDRDEL" : "0"); + (ci->getPort(id_READ0) != nullptr || ci->getPort(id_READ1) != nullptr) ? "YES" : "NO"); + tg.config.add_enum("DQS.DDRDEL", ci->getPort(id_DDRDEL) != nullptr ? "DDRDEL" : "0"); tg.config.add_enum("DQS.GSR", str_or_default(ci->params, id_GSR, "DISABLED")); cc.tilegroups.push_back(tg); } else if (ci->type == id_ECLKSYNCB) { @@ -1496,14 +1494,14 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex bool r = loc.x > 5; std::string eclksync = ctx->loc_info(bel)->bel_data[bel.index].name.get(); std::string tile = ctx->get_tile_by_type(std::string("ECLK_") + (r ? "R" : "L")); - if (get_net_or_empty(ci, id_STOP) != nullptr) + if (ci->getPort(id_STOP) != nullptr) cc.tiles[tile].add_enum(eclksync + ".MODE", "ECLKSYNCB"); } else if (ci->type == id_ECLKBRIDGECS) { Loc loc = ctx->getBelLocation(ci->bel); bool r = loc.x > 5; std::string eclkb = ctx->loc_info(bel)->bel_data[bel.index].name.get(); std::string tile = ctx->get_tile_by_type(std::string("ECLK_") + (r ? "R" : "L")); - if (get_net_or_empty(ci, id_STOP) != nullptr) + if (ci->getPort(id_STOP) != nullptr) cc.tiles[tile].add_enum(eclkb + ".MODE", "ECLKBRIDGECS"); } else if (ci->type == id_DDRDLL) { Loc loc = ctx->getBelLocation(ci->bel); diff --git a/ecp5/cells.cc b/ecp5/cells.cc index 6d88af75..a5d484ff 100644 --- a/ecp5/cells.cc +++ b/ecp5/cells.cc @@ -217,7 +217,7 @@ static void replace_port_safe(bool has_ff, CellInfo *ff, IdString ff_port, CellI [ff, ff_port](PortRef port) { return port.cell == ff && port.port == ff_port; }), ffnet->users.end()); } else { - replace_port(ff, ff_port, lc, lc_port); + ff->movePortTo(ff_port, lc, lc_port); } } @@ -242,21 +242,21 @@ void ff_to_slice(Context *ctx, CellInfo *ff, CellInfo *lc, int index, bool drive if (ff->ports.find(id_CE) != ff->ports.end()) replace_port_safe(has_ff, ff, id_CE, lc, id_CE); - replace_port(ff, id_Q, lc, ctx->id("Q" + std::to_string(index))); - if (get_net_or_empty(ff, id_M) != nullptr) { + ff->movePortTo(id_Q, lc, ctx->id("Q" + std::to_string(index))); + if (ff->getPort(id_M) != nullptr) { // PRLD FFs that use both M and DI NPNR_ASSERT(!driven_by_lut); // As M is used; must route DI through a new LUT lc->params[ctx->id(reg + "_SD")] = std::string("1"); lc->params[ctx->id("LUT" + std::to_string(index) + "_INITVAL")] = Property(0xFF00, 16); - replace_port(ff, id_DI, lc, ctx->id("D" + std::to_string(index))); - replace_port(ff, id_M, lc, ctx->id("M" + std::to_string(index))); - connect_ports(ctx, lc, ctx->id("F" + std::to_string(index)), lc, ctx->id("DI" + std::to_string(index))); + ff->movePortTo(id_DI, lc, ctx->id("D" + std::to_string(index))); + ff->movePortTo(id_M, lc, ctx->id("M" + std::to_string(index))); + lc->connectPorts(ctx->id("F" + std::to_string(index)), lc, ctx->id("DI" + std::to_string(index))); } else { if (driven_by_lut) { - replace_port(ff, id_DI, lc, ctx->id("DI" + std::to_string(index))); + ff->movePortTo(id_DI, lc, ctx->id("DI" + std::to_string(index))); } else { - replace_port(ff, id_DI, lc, ctx->id("M" + std::to_string(index))); + ff->movePortTo(id_DI, lc, ctx->id("M" + std::to_string(index))); } } } @@ -267,11 +267,11 @@ void lut_to_slice(Context *ctx, CellInfo *lut, CellInfo *lc, int index) lc->hierpath = lut->hierpath; lc->params[ctx->id("LUT" + std::to_string(index) + "_INITVAL")] = get_or_default(lut->params, id_INIT, Property(0, 16)); - replace_port(lut, id_A, lc, ctx->id("A" + std::to_string(index))); - replace_port(lut, id_B, lc, ctx->id("B" + std::to_string(index))); - replace_port(lut, id_C, lc, ctx->id("C" + std::to_string(index))); - replace_port(lut, id_D, lc, ctx->id("D" + std::to_string(index))); - replace_port(lut, id_Z, lc, ctx->id("F" + std::to_string(index))); + lut->movePortTo(id_A, lc, ctx->id("A" + std::to_string(index))); + lut->movePortTo(id_B, lc, ctx->id("B" + std::to_string(index))); + lut->movePortTo(id_C, lc, ctx->id("C" + std::to_string(index))); + lut->movePortTo(id_D, lc, ctx->id("D" + std::to_string(index))); + lut->movePortTo(id_Z, lc, ctx->id("F" + std::to_string(index))); } void ccu2c_to_slice(Context *ctx, CellInfo *ccu, CellInfo *lc) @@ -285,22 +285,22 @@ void ccu2c_to_slice(Context *ctx, CellInfo *ccu, CellInfo *lc) lc->params[id_CCU2_INJECT1_0] = str_or_default(ccu->params, id_INJECT1_0, "YES"); lc->params[id_CCU2_INJECT1_1] = str_or_default(ccu->params, id_INJECT1_1, "YES"); - replace_port(ccu, id_CIN, lc, id_FCI); + ccu->movePortTo(id_CIN, lc, id_FCI); - replace_port(ccu, id_A0, lc, id_A0); - replace_port(ccu, id_B0, lc, id_B0); - replace_port(ccu, id_C0, lc, id_C0); - replace_port(ccu, id_D0, lc, id_D0); + ccu->movePortTo(id_A0, lc, id_A0); + ccu->movePortTo(id_B0, lc, id_B0); + ccu->movePortTo(id_C0, lc, id_C0); + ccu->movePortTo(id_D0, lc, id_D0); - replace_port(ccu, id_A1, lc, id_A1); - replace_port(ccu, id_B1, lc, id_B1); - replace_port(ccu, id_C1, lc, id_C1); - replace_port(ccu, id_D1, lc, id_D1); + ccu->movePortTo(id_A1, lc, id_A1); + ccu->movePortTo(id_B1, lc, id_B1); + ccu->movePortTo(id_C1, lc, id_C1); + ccu->movePortTo(id_D1, lc, id_D1); - replace_port(ccu, id_S0, lc, id_F0); - replace_port(ccu, id_S1, lc, id_F1); + ccu->movePortTo(id_S0, lc, id_F0); + ccu->movePortTo(id_S1, lc, id_F1); - replace_port(ccu, id_COUT, lc, id_FCO); + ccu->movePortTo(id_COUT, lc, id_FCO); } void dram_to_ramw(Context *ctx, CellInfo *ram, CellInfo *lc) @@ -308,15 +308,15 @@ void dram_to_ramw(Context *ctx, CellInfo *ram, CellInfo *lc) if (lc->hierpath == IdString()) lc->hierpath = ram->hierpath; lc->params[id_MODE] = std::string("RAMW"); - replace_port(ram, ctx->id("WAD[0]"), lc, id_D0); - replace_port(ram, ctx->id("WAD[1]"), lc, id_B0); - replace_port(ram, ctx->id("WAD[2]"), lc, id_C0); - replace_port(ram, ctx->id("WAD[3]"), lc, id_A0); - - replace_port(ram, ctx->id("DI[0]"), lc, id_C1); - replace_port(ram, ctx->id("DI[1]"), lc, id_A1); - replace_port(ram, ctx->id("DI[2]"), lc, id_D1); - replace_port(ram, ctx->id("DI[3]"), lc, id_B1); + ram->movePortTo(ctx->id("WAD[0]"), lc, id_D0); + ram->movePortTo(ctx->id("WAD[1]"), lc, id_B0); + ram->movePortTo(ctx->id("WAD[2]"), lc, id_C0); + ram->movePortTo(ctx->id("WAD[3]"), lc, id_A0); + + ram->movePortTo(ctx->id("DI[0]"), lc, id_C1); + ram->movePortTo(ctx->id("DI[1]"), lc, id_A1); + ram->movePortTo(ctx->id("DI[2]"), lc, id_D1); + ram->movePortTo(ctx->id("DI[3]"), lc, id_B1); } static unsigned get_dram_init(const Context *ctx, const CellInfo *ram, int bit) @@ -367,45 +367,45 @@ void dram_to_ram_slice(Context *ctx, CellInfo *ram, CellInfo *lc, CellInfo *ramw lc->params[id_LUT1_INITVAL] = Property(permuted_init1, 16); if (ram->ports.count(ctx->id("RAD[0]"))) { - connect_port(ctx, ram->ports.at(ctx->id("RAD[0]")).net, lc, id_D0); - connect_port(ctx, ram->ports.at(ctx->id("RAD[0]")).net, lc, id_D1); + lc->connectPort(id_D0, ram->ports.at(ctx->id("RAD[0]")).net); + lc->connectPort(id_D1, ram->ports.at(ctx->id("RAD[0]")).net); } if (ram->ports.count(ctx->id("RAD[1]"))) { - connect_port(ctx, ram->ports.at(ctx->id("RAD[1]")).net, lc, id_B0); - connect_port(ctx, ram->ports.at(ctx->id("RAD[1]")).net, lc, id_B1); + lc->connectPort(id_B0, ram->ports.at(ctx->id("RAD[1]")).net); + lc->connectPort(id_B1, ram->ports.at(ctx->id("RAD[1]")).net); } if (ram->ports.count(ctx->id("RAD[2]"))) { - connect_port(ctx, ram->ports.at(ctx->id("RAD[2]")).net, lc, id_C0); - connect_port(ctx, ram->ports.at(ctx->id("RAD[2]")).net, lc, id_C1); + lc->connectPort(id_C0, ram->ports.at(ctx->id("RAD[2]")).net); + lc->connectPort(id_C1, ram->ports.at(ctx->id("RAD[2]")).net); } if (ram->ports.count(ctx->id("RAD[3]"))) { - connect_port(ctx, ram->ports.at(ctx->id("RAD[3]")).net, lc, id_A0); - connect_port(ctx, ram->ports.at(ctx->id("RAD[3]")).net, lc, id_A1); + lc->connectPort(id_A0, ram->ports.at(ctx->id("RAD[3]")).net); + lc->connectPort(id_A1, ram->ports.at(ctx->id("RAD[3]")).net); } if (ram->ports.count(id_WRE)) - connect_port(ctx, ram->ports.at(id_WRE).net, lc, id_WRE); + lc->connectPort(id_WRE, ram->ports.at(id_WRE).net); if (ram->ports.count(id_WCK)) - connect_port(ctx, ram->ports.at(id_WCK).net, lc, id_WCK); + lc->connectPort(id_WCK, ram->ports.at(id_WCK).net); - connect_ports(ctx, ramw, id_WADO0, lc, id_WAD0); - connect_ports(ctx, ramw, id_WADO1, lc, id_WAD1); - connect_ports(ctx, ramw, id_WADO2, lc, id_WAD2); - connect_ports(ctx, ramw, id_WADO3, lc, id_WAD3); + ramw->connectPorts(id_WADO0, lc, id_WAD0); + ramw->connectPorts(id_WADO1, lc, id_WAD1); + ramw->connectPorts(id_WADO2, lc, id_WAD2); + ramw->connectPorts(id_WADO3, lc, id_WAD3); if (index == 0) { - connect_ports(ctx, ramw, id_WDO0, lc, id_WD0); - connect_ports(ctx, ramw, id_WDO1, lc, id_WD1); + ramw->connectPorts(id_WDO0, lc, id_WD0); + ramw->connectPorts(id_WDO1, lc, id_WD1); - replace_port(ram, ctx->id("DO[0]"), lc, id_F0); - replace_port(ram, ctx->id("DO[1]"), lc, id_F1); + ram->movePortTo(ctx->id("DO[0]"), lc, id_F0); + ram->movePortTo(ctx->id("DO[1]"), lc, id_F1); } else if (index == 1) { - connect_ports(ctx, ramw, id_WDO2, lc, id_WD0); - connect_ports(ctx, ramw, id_WDO3, lc, id_WD1); + ramw->connectPorts(id_WDO2, lc, id_WD0); + ramw->connectPorts(id_WDO3, lc, id_WD1); - replace_port(ram, ctx->id("DO[2]"), lc, id_F0); - replace_port(ram, ctx->id("DO[3]"), lc, id_F1); + ram->movePortTo(ctx->id("DO[2]"), lc, id_F0); + ram->movePortTo(ctx->id("DO[3]"), lc, id_F1); } else { NPNR_ASSERT_FALSE("bad DPRAM index"); } @@ -416,21 +416,21 @@ void nxio_to_tr(Context *ctx, CellInfo *nxio, CellInfo *trio, std::vector<std::u { if (nxio->type == ctx->id("$nextpnr_ibuf")) { trio->params[id_DIR] = std::string("INPUT"); - replace_port(nxio, id_O, trio, id_O); + nxio->movePortTo(id_O, trio, id_O); } else if (nxio->type == ctx->id("$nextpnr_obuf")) { trio->params[id_DIR] = std::string("OUTPUT"); - replace_port(nxio, id_I, trio, id_I); + nxio->movePortTo(id_I, trio, id_I); } else if (nxio->type == ctx->id("$nextpnr_iobuf")) { // N.B. tristate will be dealt with below - NetInfo *i = get_net_or_empty(nxio, id_I); + NetInfo *i = nxio->getPort(id_I); if (i == nullptr || i->driver.cell == nullptr) trio->params[id_DIR] = std::string("INPUT"); else { log_info("%s: %s.%s\n", ctx->nameOf(i), ctx->nameOf(i->driver.cell), ctx->nameOf(i->driver.port)); trio->params[id_DIR] = std::string("BIDIR"); } - replace_port(nxio, id_I, trio, id_I); - replace_port(nxio, id_O, trio, id_O); + nxio->movePortTo(id_I, trio, id_I); + nxio->movePortTo(id_O, trio, id_O); } else { NPNR_ASSERT(false); } @@ -438,9 +438,11 @@ void nxio_to_tr(Context *ctx, CellInfo *nxio, CellInfo *trio, std::vector<std::u // Rename I/O nets to avoid conflicts if (donet != nullptr && donet->name == nxio->name) - rename_net(ctx, donet, ctx->id(donet->name.str(ctx) + "$TRELLIS_IO_OUT")); + if (donet) + ctx->renameNet(donet->name, ctx->id(donet->name.str(ctx) + "$TRELLIS_IO_OUT")); if (dinet != nullptr && dinet->name == nxio->name) - rename_net(ctx, dinet, ctx->id(dinet->name.str(ctx) + "$TRELLIS_IO_IN")); + if (dinet) + ctx->renameNet(dinet->name, ctx->id(dinet->name.str(ctx) + "$TRELLIS_IO_IN")); if (ctx->nets.count(nxio->name)) { int i = 0; @@ -448,7 +450,8 @@ void nxio_to_tr(Context *ctx, CellInfo *nxio, CellInfo *trio, std::vector<std::u do { new_name = ctx->id(nxio->name.str(ctx) + "$rename$" + std::to_string(i++)); } while (ctx->nets.count(new_name)); - rename_net(ctx, ctx->nets.at(nxio->name).get(), new_name); + if (ctx->nets.at(nxio->name).get()) + ctx->renameNet(ctx->nets.at(nxio->name).get()->name, new_name); } // Create a new top port net for accurate IO timing analysis and simulation netlists @@ -458,7 +461,7 @@ void nxio_to_tr(Context *ctx, CellInfo *nxio, CellInfo *trio, std::vector<std::u ctx->net_aliases.erase(tn_netname); NetInfo *toplevel_net = ctx->createNet(tn_netname); toplevel_net->name = tn_netname; - connect_port(ctx, toplevel_net, trio, id_B); + trio->connectPort(id_B, toplevel_net); ctx->ports[nxio->name].net = toplevel_net; } @@ -466,12 +469,12 @@ void nxio_to_tr(Context *ctx, CellInfo *nxio, CellInfo *trio, std::vector<std::u ctx, donet, [](const Context *ctx, const CellInfo *cell) { return cell->type == ctx->id("$_TBUF_"); }, id_Y); if (tbuf) { - replace_port(tbuf, id_A, trio, id_I); + tbuf->movePortTo(id_A, trio, id_I); // Need to invert E to form T std::unique_ptr<CellInfo> inv_lut = create_ecp5_cell(ctx, id_LUT4, trio->name.str(ctx) + "$invert_T"); - replace_port(tbuf, id_E, inv_lut.get(), id_A); + tbuf->movePortTo(id_E, inv_lut.get(), id_A); inv_lut->params[id_INIT] = Property(21845, 16); - connect_ports(ctx, inv_lut.get(), id_Z, trio, id_T); + inv_lut->connectPorts(id_Z, trio, id_T); created_cells.push_back(std::move(inv_lut)); if (donet->users.size() > 1) { diff --git a/ecp5/globals.cc b/ecp5/globals.cc index 844c596b..7b48e693 100644 --- a/ecp5/globals.cc +++ b/ecp5/globals.cc @@ -399,7 +399,7 @@ class Ecp5GlobalRouter { BelId best_bel; WireId best_bel_pclkcib; - bool using_ce = get_net_or_empty(dcc, id_CE) != nullptr; + bool using_ce = dcc->getPort(id_CE) != nullptr; wirelen_t best_wirelen = 9999999; bool dedicated_routing = false; for (auto bel : ctx->getBels()) { @@ -533,7 +533,7 @@ class Ecp5GlobalRouter } for (auto ci : dcsc_cells) { for (auto port : {id_CLK0, id_CLK1}) { - NetInfo *net = get_net_or_empty(ci, port); + NetInfo *net = ci->getPort(port); if (net != nullptr) insert_dcc(net, ci); } @@ -609,7 +609,7 @@ class Ecp5GlobalRouter pins.push_back(id_CLK1); } for (auto pin : pins) { - NetInfo *ni = get_net_or_empty(ci, pin); + NetInfo *ni = ci->getPort(pin); if (ni == nullptr) continue; log_info(" trying dedicated routing for edge clock source %s\n", ctx->nameOf(ni)); diff --git a/ecp5/pack.cc b/ecp5/pack.cc index d49dbdf3..2b069db0 100644 --- a/ecp5/pack.cc +++ b/ecp5/pack.cc @@ -112,7 +112,7 @@ class Ecp5Packer if (znet != nullptr) { CellInfo *ff = net_only_drives(ctx, znet, is_ff, id_DI, false); // Can't combine preload FF with LUT due to conflict on M - if (ff != nullptr && get_net_or_empty(ff, id_M) == nullptr) { + if (ff != nullptr && ff->getPort(id_M) == nullptr) { lutffPairs[ci->name] = ff->name; fflutPairs[ff->name] = ci->name; } @@ -124,9 +124,9 @@ class Ecp5Packer // Check if a flipflop is available in a slice bool is_ff_available(CellInfo *slice, int ff) { - if (get_net_or_empty(slice, (ff == 1) ? id_Q1 : id_Q0) != nullptr) + if (slice->getPort((ff == 1) ? id_Q1 : id_Q0) != nullptr) return false; - if (get_net_or_empty(slice, (ff == 1) ? id_M1 : id_M0) != nullptr) + if (slice->getPort((ff == 1) ? id_M1 : id_M0) != nullptr) return false; return true; } @@ -146,8 +146,8 @@ class Ecp5Packer if (wremux != lsrmux && !(wremux == "WRE" && lsrmux == "LSR")) return false; } - bool has_ff0 = get_net_or_empty(slice, id_Q0) != nullptr; - bool has_ff1 = get_net_or_empty(slice, id_Q1) != nullptr; + bool has_ff0 = slice->getPort(id_Q0) != nullptr; + bool has_ff1 = slice->getPort(id_Q1) != nullptr; if (!has_ff0 && !has_ff1) return true; if (str_or_default(ff->params, id_GSR, "DISABLED") != str_or_default(slice->params, id_GSR, "DISABLED")) @@ -224,7 +224,7 @@ class Ecp5Packer // Return true if a FF can be added to a DPRAM slice bool can_pack_ff_dram(CellInfo *dpram, CellInfo *ff) { - if (get_net_or_empty(ff, id_M) != nullptr) + if (ff->getPort(id_M) != nullptr) return false; // skip PRLD FFs due to M/DI conflict std::string wckmux = str_or_default(dpram->params, id_WCKMUX, "WCK"); std::string clkmux = str_or_default(ff->params, id_CLKMUX, "CLK"); @@ -452,7 +452,7 @@ class Ecp5Packer // No IO buffer insertion in out-of-context mode, just remove the nextpnr buffer // and leave the top level port for (auto &port : ci->ports) - disconnect_port(ctx, ci, port.first); + ci->disconnectPort(port.first); } else if (trio != nullptr) { // Trivial case, TRELLIS_IO used. Just remove the IOBUF log_info("%s feeds TRELLIS_IO %s, removing %s %s.\n", ci->name.c_str(ctx), trio->name.c_str(ctx), @@ -498,7 +498,7 @@ class Ecp5Packer trio = new_cells.back().get(); } for (auto port : ci->ports) - disconnect_port(ctx, ci, port.first); + ci->disconnectPort(port.first); packed_cells.insert(ci->name); if (trio != nullptr) { for (const auto &attr : ci->attrs) @@ -546,16 +546,16 @@ class Ecp5Packer log_error("PFUMX '%s' has ALUT driven by cell other than a LUT\n", ci->name.c_str(ctx)); if (ctx->verbose) log_info(" mux '%s' forms part of a LUT5\n", cell.first.c_str(ctx)); - replace_port(lut0, id_A, packed.get(), id_A0); - replace_port(lut0, id_B, packed.get(), id_B0); - replace_port(lut0, id_C, packed.get(), id_C0); - replace_port(lut0, id_D, packed.get(), id_D0); - replace_port(lut1, id_A, packed.get(), id_A1); - replace_port(lut1, id_B, packed.get(), id_B1); - replace_port(lut1, id_C, packed.get(), id_C1); - replace_port(lut1, id_D, packed.get(), id_D1); - replace_port(ci, id_C0, packed.get(), id_M0); - replace_port(ci, id_Z, packed.get(), id_OFX0); + lut0->movePortTo(id_A, packed.get(), id_A0); + lut0->movePortTo(id_B, packed.get(), id_B0); + lut0->movePortTo(id_C, packed.get(), id_C0); + lut0->movePortTo(id_D, packed.get(), id_D0); + lut1->movePortTo(id_A, packed.get(), id_A1); + lut1->movePortTo(id_B, packed.get(), id_B1); + lut1->movePortTo(id_C, packed.get(), id_C1); + lut1->movePortTo(id_D, packed.get(), id_D1); + ci->movePortTo(id_C0, packed.get(), id_M0); + ci->movePortTo(id_Z, packed.get(), id_OFX0); packed->params[id_LUT0_INITVAL] = get_or_default(lut0->params, id_INIT, Property(0, 16)); packed->params[id_LUT1_INITVAL] = get_or_default(lut1->params, id_INIT, Property(0, 16)); @@ -611,10 +611,10 @@ class Ecp5Packer } if (ctx->verbose) log_info(" mux '%s' forms part of a LUT6\n", cell.first.c_str(ctx)); - replace_port(ci, id_D0, slice1, id_FXA); - replace_port(ci, id_D1, slice1, id_FXB); - replace_port(ci, id_SD, slice1, id_M1); - replace_port(ci, id_Z, slice1, id_OFX1); + ci->movePortTo(id_D0, slice1, id_FXA); + ci->movePortTo(id_D1, slice1, id_FXB); + ci->movePortTo(id_SD, slice1, id_M1); + ci->movePortTo(id_Z, slice1, id_OFX1); slice0->constr_z = 1; slice0->constr_x = 0; slice0->constr_y = 0; @@ -676,10 +676,10 @@ class Ecp5Packer slice3->name.c_str(ctx), fxa_1->driver.cell->name.c_str(ctx), fxa_1->driver.port.c_str(ctx)); - replace_port(ci, id_D0, slice2, id_FXA); - replace_port(ci, id_D1, slice2, id_FXB); - replace_port(ci, id_SD, slice2, id_M1); - replace_port(ci, id_Z, slice2, id_OFX1); + ci->movePortTo(id_D0, slice2, id_FXA); + ci->movePortTo(id_D1, slice2, id_FXB); + ci->movePortTo(id_SD, slice2, id_M1); + ci->movePortTo(id_Z, slice2, id_OFX1); for (auto slice : {slice0, slice1, slice2, slice3}) { slice->constr_children.clear(); @@ -747,12 +747,12 @@ class Ecp5Packer return user.port == chain_in.port && user.cell == chain_in.cell; }), carry->users.end()); - connect_port(ctx, carry, feedin.get(), id_A0); + feedin->connectPort(id_A0, carry); NetInfo *new_carry = ctx->createNet(ctx->id(feedin->name.str(ctx) + "$COUT")); - connect_port(ctx, new_carry, feedin.get(), id_COUT); + feedin->connectPort(id_COUT, new_carry); chain_in.cell->ports[chain_in.port].net = nullptr; - connect_port(ctx, new_carry, chain_in.cell, chain_in.port); + chain_in.cell->connectPort(chain_in.port, new_carry); CellInfo *feedin_ptr = feedin.get(); IdString feedin_name = feedin->name; @@ -772,16 +772,16 @@ class Ecp5Packer PortRef carry_drv = carry->driver; carry->driver.cell = nullptr; - connect_port(ctx, carry, feedout.get(), id_S0); + feedout->connectPort(id_S0, carry); NetInfo *new_cin = ctx->createNet(ctx->id(feedout->name.str(ctx) + "$CIN")); new_cin->driver = carry_drv; carry_drv.cell->ports.at(carry_drv.port).net = new_cin; - connect_port(ctx, new_cin, feedout.get(), id_CIN); + feedout->connectPort(id_CIN, new_cin); if (chain_next) { // Loop back into LUT4_1 for feedthrough - connect_port(ctx, carry, feedout.get(), id_A1); + feedout->connectPort(id_A1, carry); carry->users.erase(std::remove_if(carry->users.begin(), carry->users.end(), [chain_next](const PortRef &user) { @@ -790,10 +790,10 @@ class Ecp5Packer carry->users.end()); NetInfo *new_cout = ctx->createNet(ctx->id(feedout->name.str(ctx) + "$COUT")); - connect_port(ctx, new_cout, feedout.get(), id_COUT); + feedout->connectPort(id_COUT, new_cout); chain_next->cell->ports[chain_next->port].net = nullptr; - connect_port(ctx, new_cout, chain_next->cell, chain_next->port); + chain_next->cell->connectPort(chain_next->port, new_cout); } CellInfo *feedout_ptr = feedout.get(); @@ -970,13 +970,13 @@ class Ecp5Packer dram_to_ram_slice(ctx, ci, ram1_slice.get(), ramw_slice.get(), 1); // Disconnect ports of original cell after packing - disconnect_port(ctx, ci, id_WCK); - disconnect_port(ctx, ci, id_WRE); + ci->disconnectPort(id_WCK); + ci->disconnectPort(id_WRE); - disconnect_port(ctx, ci, ctx->id("RAD[0]")); - disconnect_port(ctx, ci, ctx->id("RAD[1]")); - disconnect_port(ctx, ci, ctx->id("RAD[2]")); - disconnect_port(ctx, ci, ctx->id("RAD[3]")); + ci->disconnectPort(ctx->id("RAD[0]")); + ci->disconnectPort(ctx->id("RAD[1]")); + ci->disconnectPort(ctx->id("RAD[2]")); + ci->disconnectPort(ctx->id("RAD[3]")); // Attempt to pack FFs into RAM slices std::vector<std::tuple<CellInfo *, CellInfo *, int>> ff_packing; @@ -1159,7 +1159,7 @@ class Ecp5Packer CellInfo *ci = cell.second.get(); if (is_ff(ctx, ci)) { bool pack_dense = used_slices > (dense_pack_mode_thresh * available_slices); - bool requires_m = get_net_or_empty(ci, id_M) != nullptr; + bool requires_m = ci->getPort(id_M) != nullptr; if (pack_dense && !requires_m) { // If dense packing threshold exceeded; always try and pack the FF into an existing slice // Find a SLICE with space "near" the flipflop in the netlist @@ -1421,8 +1421,8 @@ class Ecp5Packer auto rename_bus = [&](CellInfo *c, const std::string &oldname, const std::string &newname, int width, int oldoffset, int newoffset) { for (int i = 0; i < width; i++) - rename_port(ctx, c, ctx->id(oldname + std::to_string(i + oldoffset)), - ctx->id(newname + std::to_string(i + newoffset))); + c->renamePort(ctx->id(oldname + std::to_string(i + oldoffset)), + ctx->id(newname + std::to_string(i + newoffset))); }; auto rename_param = [&](CellInfo *c, const std::string &oldname, const std::string &newname) { IdString o = ctx->id(oldname), n = ctx->id(newname); @@ -1446,11 +1446,11 @@ class Ecp5Packer rename_bus(ci, "DI", "DIB", 18, 18, 0); rename_bus(ci, "DO", "DOA", 18, 18, 0); rename_bus(ci, "DO", "DOB", 18, 0, 0); - rename_port(ctx, ci, id_CLKW, id_CLKA); - rename_port(ctx, ci, id_CLKR, id_CLKB); - rename_port(ctx, ci, id_CEW, id_CEA); - rename_port(ctx, ci, id_CER, id_CEB); - rename_port(ctx, ci, id_OCER, id_OCEB); + ci->renamePort(id_CLKW, id_CLKA); + ci->renamePort(id_CLKR, id_CLKB); + ci->renamePort(id_CEW, id_CEA); + ci->renamePort(id_CER, id_CEB); + ci->renamePort(id_OCER, id_OCEB); rename_param(ci, "CLKWMUX", "CLKAMUX"); if (str_or_default(ci->params, id_CLKAMUX) == "CLKW") ci->params[id_CLKAMUX] = std::string("CLKA"); @@ -1468,9 +1468,9 @@ class Ecp5Packer autocreate_empty_port(ci, id_RSTA); autocreate_empty_port(ci, id_RSTB); NetInfo *rst = ci->ports.at(id_RST).net; - connect_port(ctx, rst, ci, id_RSTA); - connect_port(ctx, rst, ci, id_RSTB); - disconnect_port(ctx, ci, id_RST); + ci->connectPort(id_RSTA, rst); + ci->connectPort(id_RSTB, rst); + ci->disconnectPort(id_RST); ci->ports.erase(id_RST); } ci->type = id_DP16KD; @@ -1721,12 +1721,12 @@ class Ecp5Packer // Disconnect these ports if connected to constant to prevent routing failure for (auto ndport : {id_D_TXBIT_CLKP_FROM_ND, id_D_TXBIT_CLKN_FROM_ND, id_D_SYNC_ND, id_D_TXPLL_LOL_FROM_ND, id_CH0_HDINN, id_CH0_HDINP, id_CH1_HDINN, id_CH1_HDINP}) { - const NetInfo *net = get_net_or_empty(ci, ndport); + const NetInfo *net = ci->getPort(ndport); if (net == nullptr || net->driver.cell == nullptr) continue; IdString ct = net->driver.cell->type; if (ct == id_GND || ct == id_VCC) { - disconnect_port(ctx, ci, ndport); + ci->disconnectPort(ndport); ci->ports.erase(ndport); } } @@ -1814,9 +1814,9 @@ class Ecp5Packer for (auto &cell : ctx->cells) { CellInfo *ci = cell.second.get(); if (ci->type == id_USRMCLK) { - rename_port(ctx, ci, id_USRMCLKI, id_PADDO); - rename_port(ctx, ci, id_USRMCLKTS, id_PADDT); - rename_port(ctx, ci, id_USRMCLKO, id_PADDI); + ci->renamePort(id_USRMCLKI, id_PADDO); + ci->renamePort(id_USRMCLKTS, id_PADDT); + ci->renamePort(id_USRMCLKO, id_PADDI); } else if (ci->type == id_GSR || ci->type == id_SGSR) { ci->params[id_MODE] = std::string("ACTIVE_LOW"); ci->params[id_SYNCMODE] = ci->type == id_SGSR ? std::string("SYNC") : std::string("ASYNC"); @@ -1959,8 +1959,8 @@ class Ecp5Packer eclkbuf->attrs[id_BEL] = ctx->getBelName(target_bel).str(ctx); - connect_port(ctx, ecknet, eclkbuf.get(), id_ECLKI); - connect_port(ctx, eclk.buf, eclkbuf.get(), id_ECLKO); + eclkbuf->connectPort(id_ECLKI, ecknet); + eclkbuf->connectPort(id_ECLKO, eclk.buf); found_eclk = free_eclk; eclk.buffer = eclkbuf.get(); new_cells.push_back(std::move(eclkbuf)); @@ -1968,9 +1968,9 @@ class Ecp5Packer } auto &eclk = eclks[std::make_pair(bank, found_eclk)]; - disconnect_port(ctx, usr_cell, usr_port.name); + usr_cell->disconnectPort(usr_port.name); usr_port.net = nullptr; - connect_port(ctx, eclk.buf, usr_cell, usr_port.name); + usr_cell->connectPort(usr_port.name, eclk.buf); // Simple ECLK router WireId userWire = ctx->getBelPinWire(usr_bel, usr_port.name); @@ -2024,8 +2024,8 @@ class Ecp5Packer auto zero_cell = std::make_unique<CellInfo>(ctx, name, id_GND); NetInfo *zero_net = ctx->createNet(name); zero_cell->addOutput(id_GND); - connect_port(ctx, zero_net, zero_cell.get(), id_GND); - connect_port(ctx, zero_net, ci, port); + zero_cell->connectPort(id_GND, zero_net); + ci->connectPort(port, zero_net); new_cells.push_back(std::move(zero_cell)); } @@ -2136,11 +2136,11 @@ class Ecp5Packer log_error("IOLOGIC '%s' has conflicting clocks '%s' and '%s'\n", iol->name.c_str(ctx), iol->ports[id_CLK].net->name.c_str(ctx), sclk->name.c_str(ctx)); } else { - connect_port(ctx, sclk, iol, id_CLK); + iol->connectPort(id_CLK, sclk); } } if (prim->ports.count(port) && disconnect) - disconnect_port(ctx, prim, port); + prim->disconnectPort(port); }; auto set_iologic_eclk = [&](CellInfo *iol, CellInfo *prim, IdString port) { @@ -2155,10 +2155,10 @@ class Ecp5Packer log_error("IOLOGIC '%s' has conflicting ECLKs '%s' and '%s'\n", iol->name.c_str(ctx), iol->ports[id_ECLK].net->name.c_str(ctx), eclk->name.c_str(ctx)); } else { - connect_port(ctx, eclk, iol, id_ECLK); + iol->connectPort(id_ECLK, eclk); } if (prim->ports.count(port)) - disconnect_port(ctx, prim, port); + prim->disconnectPort(port); }; auto set_iologic_lsr = [&](CellInfo *iol, CellInfo *prim, IdString port, bool input, bool disconnect = true) { @@ -2174,11 +2174,11 @@ class Ecp5Packer log_error("IOLOGIC '%s' has conflicting LSR signals '%s' and '%s'\n", iol->name.c_str(ctx), iol->ports[id_LSR].net->name.c_str(ctx), lsr->name.c_str(ctx)); } else if (iol->ports[id_LSR].net == nullptr) { - connect_port(ctx, lsr, iol, id_LSR); + iol->connectPort(id_LSR, lsr); } } if (prim->ports.count(port) && disconnect) - disconnect_port(ctx, prim, port); + prim->disconnectPort(port); }; bool warned_oddrx_iddrx = false; @@ -2245,7 +2245,7 @@ class Ecp5Packer log_error("IOLOGIC '%s' has conflicting %s signals '%s' and '%s'\n", iol->name.c_str(ctx), port.c_str(ctx), iol->ports[port].net->name.c_str(ctx), sig->name.c_str(ctx)); } - disconnect_port(ctx, prim, port); + prim->disconnectPort(port); } else { bool dqsr; int dqsgroup; @@ -2263,7 +2263,7 @@ class Ecp5Packer "%cDQ%d\n", port.c_str(ctx), prim->name.c_str(ctx), dqsr ? 'R' : 'L', dqsgroup, sig->driver.cell->name.c_str(ctx), driver_group.first ? 'R' : 'L', driver_group.second); - replace_port(prim, port, iol, port); + prim->movePortTo(port, iol, port); } }; @@ -2284,18 +2284,18 @@ class Ecp5Packer if (drives_iologic) { // Reconnect to PIO which the packer expects later on NetInfo *input_net = ci->ports.at(id_A).net, *dly_net = ci->ports.at(id_Z).net; - disconnect_port(ctx, i_pio, id_O); + i_pio->disconnectPort(id_O); i_pio->ports.at(id_O).net = nullptr; - disconnect_port(ctx, ci, id_A); + ci->disconnectPort(id_A); ci->ports.at(id_A).net = nullptr; - disconnect_port(ctx, ci, id_Z); + ci->disconnectPort(id_Z); ci->ports.at(id_Z).net = nullptr; - connect_port(ctx, dly_net, i_pio, id_O); - connect_port(ctx, input_net, iol, id_INDD); - connect_port(ctx, input_net, iol, id_DI); + i_pio->connectPort(id_O, dly_net); + iol->connectPort(id_INDD, input_net); + iol->connectPort(id_DI, input_net); } else { - replace_port(ci, id_A, iol, id_PADDI); - replace_port(ci, id_Z, iol, id_INDD); + ci->movePortTo(id_A, iol, id_PADDI); + ci->movePortTo(id_Z, iol, id_INDD); } packed_cells.insert(cell.first); } else if (o_pio != nullptr) { @@ -2307,22 +2307,22 @@ class Ecp5Packer input_net->driver.port == id_Q) driven_by_iol = true; if (driven_by_iol) { - disconnect_port(ctx, o_pio, id_I); + o_pio->disconnectPort(id_I); o_pio->ports.at(id_I).net = nullptr; - disconnect_port(ctx, ci, id_A); + ci->disconnectPort(id_A); ci->ports.at(id_A).net = nullptr; - disconnect_port(ctx, ci, id_Z); + ci->disconnectPort(id_Z); ci->ports.at(id_Z).net = nullptr; - connect_port(ctx, input_net, o_pio, id_I); + o_pio->connectPort(id_I, input_net); ctx->nets.erase(dly_net->name); } else { - replace_port(ci, id_A, iol, id_TXDATA0); - replace_port(ci, id_Z, iol, id_IOLDO); + ci->movePortTo(id_A, iol, id_TXDATA0); + ci->movePortTo(id_Z, iol, id_IOLDO); if (!o_pio->ports.count(id_IOLDO)) { o_pio->ports[id_IOLDO].name = id_IOLDO; o_pio->ports[id_IOLDO].type = PORT_IN; } - replace_port(o_pio, id_I, o_pio, id_IOLDO); + o_pio->movePortTo(id_I, o_pio, id_IOLDO); } packed_cells.insert(cell.first); } else { @@ -2336,19 +2336,19 @@ class Ecp5Packer std::string(ci->params.at(id_DEL_VALUE).as_string()).substr(0, 5) != "DELAY")) iol->params[ctx->id("DELAY.DEL_VALUE")] = ci->params.at(id_DEL_VALUE); if (ci->ports.count(id_LOADN)) - replace_port(ci, id_LOADN, iol, id_LOADN); + ci->movePortTo(id_LOADN, iol, id_LOADN); else tie_zero(iol, id_LOADN); if (ci->ports.count(id_MOVE)) - replace_port(ci, id_MOVE, iol, id_MOVE); + ci->movePortTo(id_MOVE, iol, id_MOVE); else tie_zero(iol, id_MOVE); if (ci->ports.count(id_DIRECTION)) - replace_port(ci, id_DIRECTION, iol, id_DIRECTION); + ci->movePortTo(id_DIRECTION, iol, id_DIRECTION); else tie_zero(iol, id_DIRECTION); if (ci->ports.count(id_CFLAG)) - replace_port(ci, id_CFLAG, iol, id_CFLAG); + ci->movePortTo(id_CFLAG, iol, id_CFLAG); } } @@ -2365,11 +2365,11 @@ class Ecp5Packer else iol = create_pio_iologic(pio, ci); set_iologic_mode(iol, "IDDRX1_ODDRX1"); - replace_port(ci, id_D, iol, id_PADDI); + ci->movePortTo(id_D, iol, id_PADDI); set_iologic_sclk(iol, ci, id_SCLK, true); set_iologic_lsr(iol, ci, id_RST, true); - replace_port(ci, id_Q0, iol, id_RXDATA0); - replace_port(ci, id_Q1, iol, id_RXDATA1); + ci->movePortTo(id_Q0, iol, id_RXDATA0); + ci->movePortTo(id_Q1, iol, id_RXDATA1); iol->params[id_GSR] = str_or_default(ci->params, id_GSR, "DISABLED"); packed_cells.insert(cell.first); } else if (ci->type == id_ODDRX1F) { @@ -2383,17 +2383,17 @@ class Ecp5Packer else iol = create_pio_iologic(pio, ci); set_iologic_mode(iol, "IDDRX1_ODDRX1"); - replace_port(ci, id_Q, iol, id_IOLDO); + ci->movePortTo(id_Q, iol, id_IOLDO); if (!pio->ports.count(id_IOLDO)) { pio->ports[id_IOLDO].name = id_IOLDO; pio->ports[id_IOLDO].type = PORT_IN; } - replace_port(pio, id_I, pio, id_IOLDO); + pio->movePortTo(id_I, pio, id_IOLDO); pio->params[id_DATAMUX_ODDR] = std::string("IOLDO"); set_iologic_sclk(iol, ci, id_SCLK, false); set_iologic_lsr(iol, ci, id_RST, false); - replace_port(ci, id_D0, iol, id_TXDATA0); - replace_port(ci, id_D1, iol, id_TXDATA1); + ci->movePortTo(id_D0, iol, id_TXDATA0); + ci->movePortTo(id_D1, iol, id_TXDATA1); iol->params[id_GSR] = str_or_default(ci->params, id_GSR, "DISABLED"); packed_cells.insert(cell.first); } else if (ci->type == id_ODDRX2F || ci->type == id_ODDR71B) { @@ -2407,28 +2407,28 @@ class Ecp5Packer else iol = create_pio_iologic(pio, ci); set_iologic_mode(iol, "ODDRXN"); - replace_port(ci, id_Q, iol, id_IOLDO); + ci->movePortTo(id_Q, iol, id_IOLDO); if (!pio->ports.count(id_IOLDO)) { pio->ports[id_IOLDO].name = id_IOLDO; pio->ports[id_IOLDO].type = PORT_IN; } - replace_port(pio, id_I, pio, id_IOLDO); + pio->movePortTo(id_I, pio, id_IOLDO); set_iologic_sclk(iol, ci, id_SCLK, false, false); set_iologic_sclk(iol, ci, id_SCLK, true); set_iologic_eclk(iol, ci, id_ECLK); set_iologic_lsr(iol, ci, id_RST, false, false); set_iologic_lsr(iol, ci, id_RST, true); - replace_port(ci, id_D0, iol, id_TXDATA0); - replace_port(ci, id_D1, iol, id_TXDATA1); - replace_port(ci, id_D2, iol, id_TXDATA2); - replace_port(ci, id_D3, iol, id_TXDATA3); + ci->movePortTo(id_D0, iol, id_TXDATA0); + ci->movePortTo(id_D1, iol, id_TXDATA1); + ci->movePortTo(id_D2, iol, id_TXDATA2); + ci->movePortTo(id_D3, iol, id_TXDATA3); if (ci->type == id_ODDR71B) { Loc loc = ctx->getBelLocation(ctx->getBelByNameStr(pio->attrs.at(id_BEL).as_string())); if (loc.z % 2 == 1) log_error("ODDR71B '%s' can only be used at 'A' or 'C' locations\n", ci->name.c_str(ctx)); - replace_port(ci, id_D4, iol, id_TXDATA4); - replace_port(ci, id_D5, iol, id_TXDATA5); - replace_port(ci, id_D6, iol, id_TXDATA6); + ci->movePortTo(id_D4, iol, id_TXDATA4); + ci->movePortTo(id_D5, iol, id_TXDATA5); + ci->movePortTo(id_D6, iol, id_TXDATA6); iol->params[ctx->id("ODDRXN.MODE")] = std::string("ODDR71"); } else { iol->params[ctx->id("ODDRXN.MODE")] = std::string("ODDRX2"); @@ -2447,22 +2447,22 @@ class Ecp5Packer else iol = create_pio_iologic(pio, ci); set_iologic_mode(iol, "IDDRXN"); - replace_port(ci, id_D, iol, id_PADDI); + ci->movePortTo(id_D, iol, id_PADDI); set_iologic_sclk(iol, ci, id_SCLK, true); set_iologic_eclk(iol, ci, id_ECLK); set_iologic_lsr(iol, ci, id_RST, true); - replace_port(ci, id_Q0, iol, id_RXDATA0); - replace_port(ci, id_Q1, iol, id_RXDATA1); - replace_port(ci, id_Q2, iol, id_RXDATA2); - replace_port(ci, id_Q3, iol, id_RXDATA3); + ci->movePortTo(id_Q0, iol, id_RXDATA0); + ci->movePortTo(id_Q1, iol, id_RXDATA1); + ci->movePortTo(id_Q2, iol, id_RXDATA2); + ci->movePortTo(id_Q3, iol, id_RXDATA3); if (ci->type == id_IDDR71B) { Loc loc = ctx->getBelLocation(ctx->getBelByNameStr(pio->attrs.at(id_BEL).as_string())); if (loc.z % 2 == 1) log_error("IDDR71B '%s' can only be used at 'A' or 'C' locations\n", ci->name.c_str(ctx)); - replace_port(ci, id_Q4, iol, id_RXDATA4); - replace_port(ci, id_Q5, iol, id_RXDATA5); - replace_port(ci, id_Q6, iol, id_RXDATA6); - replace_port(ci, id_ALIGNWD, iol, id_SLIP); + ci->movePortTo(id_Q4, iol, id_RXDATA4); + ci->movePortTo(id_Q5, iol, id_RXDATA5); + ci->movePortTo(id_Q6, iol, id_RXDATA6); + ci->movePortTo(id_ALIGNWD, iol, id_SLIP); iol->params[ctx->id("IDDRXN.MODE")] = std::string("IDDR71"); } else { iol->params[ctx->id("IDDRXN.MODE")] = std::string("IDDRX2"); @@ -2480,18 +2480,18 @@ class Ecp5Packer else iol = create_pio_iologic(pio, ci); set_iologic_mode(iol, "MIDDRX_MODDRX"); - replace_port(ci, id_Q, iol, id_IOLDO); + ci->movePortTo(id_Q, iol, id_IOLDO); if (!pio->ports.count(id_IOLDO)) { pio->ports[id_IOLDO].name = id_IOLDO; pio->ports[id_IOLDO].type = PORT_IN; } - replace_port(pio, id_I, pio, id_IOLDO); + pio->movePortTo(id_I, pio, id_IOLDO); set_iologic_sclk(iol, ci, id_SCLK, false); set_iologic_eclk(iol, ci, id_ECLK); set_iologic_lsr(iol, ci, id_RST, false, false); set_iologic_lsr(iol, ci, id_RST, true); - replace_port(ci, id_D0, iol, id_TXDATA0); - replace_port(ci, id_D1, iol, id_TXDATA2); + ci->movePortTo(id_D0, iol, id_TXDATA0); + ci->movePortTo(id_D1, iol, id_TXDATA2); iol->params[id_GSR] = str_or_default(ci->params, id_GSR, "DISABLED"); iol->params[ctx->id("MODDRX.MODE")] = std::string("MOSHX2"); pio->params[id_DATAMUX_MDDR] = std::string("IOLDO"); @@ -2507,20 +2507,20 @@ class Ecp5Packer else iol = create_pio_iologic(pio, ci); set_iologic_mode(iol, "MIDDRX_MODDRX"); - replace_port(ci, id_Q, iol, id_IOLDO); + ci->movePortTo(id_Q, iol, id_IOLDO); if (!pio->ports.count(id_IOLDO)) { pio->ports[id_IOLDO].name = id_IOLDO; pio->ports[id_IOLDO].type = PORT_IN; } - replace_port(pio, id_I, pio, id_IOLDO); + pio->movePortTo(id_I, pio, id_IOLDO); set_iologic_sclk(iol, ci, id_SCLK, false); set_iologic_eclk(iol, ci, id_ECLK); set_iologic_lsr(iol, ci, id_RST, false, false); set_iologic_lsr(iol, ci, id_RST, true); - replace_port(ci, id_D0, iol, id_TXDATA0); - replace_port(ci, id_D1, iol, id_TXDATA1); - replace_port(ci, id_D2, iol, id_TXDATA2); - replace_port(ci, id_D3, iol, id_TXDATA3); + ci->movePortTo(id_D0, iol, id_TXDATA0); + ci->movePortTo(id_D1, iol, id_TXDATA1); + ci->movePortTo(id_D2, iol, id_TXDATA2); + ci->movePortTo(id_D3, iol, id_TXDATA3); iol->params[id_GSR] = str_or_default(ci->params, id_GSR, "DISABLED"); iol->params[ctx->id("MODDRX.MODE")] = std::string("MODDRX2"); iol->params[ctx->id("MIDDRX_MODDRX.WRCLKMUX")] = @@ -2539,15 +2539,15 @@ class Ecp5Packer else iol = create_pio_iologic(pio, ci); set_iologic_mode(iol, "MIDDRX_MODDRX"); - replace_port(ci, id_D, iol, id_PADDI); + ci->movePortTo(id_D, iol, id_PADDI); set_iologic_sclk(iol, ci, id_SCLK, true); set_iologic_eclk(iol, ci, id_ECLK); set_iologic_lsr(iol, ci, id_RST, true); - replace_port(ci, id_Q0, iol, id_RXDATA0); - replace_port(ci, id_Q1, iol, id_RXDATA1); - replace_port(ci, id_Q2, iol, id_RXDATA2); - replace_port(ci, id_Q3, iol, id_RXDATA3); - replace_port(ci, id_QWL, iol, id_INFF); + ci->movePortTo(id_Q0, iol, id_RXDATA0); + ci->movePortTo(id_Q1, iol, id_RXDATA1); + ci->movePortTo(id_Q2, iol, id_RXDATA2); + ci->movePortTo(id_Q3, iol, id_RXDATA3); + ci->movePortTo(id_QWL, iol, id_INFF); iol->params[id_GSR] = str_or_default(ci->params, id_GSR, "DISABLED"); iol->params[ctx->id("MIDDRX.MODE")] = std::string("MIDDRX2"); process_dqs_port(ci, pio, iol, id_DQSR90); @@ -2569,17 +2569,17 @@ class Ecp5Packer else iol = create_pio_iologic(pio, ci); set_iologic_mode(iol, "MIDDRX_MODDRX"); - replace_port(ci, id_Q, iol, id_IOLTO); + ci->movePortTo(id_Q, iol, id_IOLTO); if (!pio->ports.count(id_IOLTO)) { pio->ports[id_IOLTO].name = id_IOLTO; pio->ports[id_IOLTO].type = PORT_IN; } - replace_port(pio, id_T, pio, id_IOLTO); + pio->movePortTo(id_T, pio, id_IOLTO); set_iologic_sclk(iol, ci, id_SCLK, false); set_iologic_eclk(iol, ci, id_ECLK); set_iologic_lsr(iol, ci, id_RST, false); - replace_port(ci, id_T0, iol, id_TSDATA0); - replace_port(ci, id_T1, iol, id_TSDATA1); + ci->movePortTo(id_T0, iol, id_TSDATA0); + ci->movePortTo(id_T1, iol, id_TSDATA1); process_dqs_port(ci, pio, iol, ci->type == id_TSHX2DQSA ? id_DQSW : id_DQSW270); iol->params[id_GSR] = str_or_default(ci->params, id_GSR, "DISABLED"); iol->params[ctx->id("MTDDRX.MODE")] = std::string("MTSHX2"); @@ -2595,7 +2595,7 @@ class Ecp5Packer std::string mode = str_or_default(ci->attrs, id_ioff_dir, ""); if (mode != "output") { // See if it can be packed as an input ff - NetInfo *d = get_net_or_empty(ci, id_DI); + NetInfo *d = ci->getPort(id_DI); CellInfo *pio = net_driven_by(ctx, d, is_trellis_io, id_O); if (pio != nullptr && d->users.size() == 1) { // Input FF @@ -2613,10 +2613,10 @@ class Ecp5Packer if (str_or_default(ci->params, id_CEMUX, "CE") == "CE") { iol->params[id_CEIMUX] = std::string("CEMUX"); iol->params[id_CEMUX] = std::string("CE"); - if (get_net_or_empty(ci, id_CE) == nullptr) - replace_port(ci, id_CE, iol, id_CE); + if (ci->getPort(id_CE) == nullptr) + ci->movePortTo(id_CE, iol, id_CE); else - disconnect_port(ctx, ci, id_CE); + ci->disconnectPort(id_CE); } else { iol->params[id_CEIMUX] = std::string("1"); } @@ -2625,8 +2625,8 @@ class Ecp5Packer iol->params[ctx->id("FF.REGSET")] = str_or_default(ci->params, id_REGSET, "RESET"); iol->params[id_SRMODE] = str_or_default(ci->params, id_SRMODE, "ASYNC"); iol->params[id_GSR] = str_or_default(ci->params, id_GSR, "DISABLED"); - replace_port(ci, id_DI, iol, id_PADDI); - replace_port(ci, id_Q, iol, id_INFF); + ci->movePortTo(id_DI, iol, id_PADDI); + ci->movePortTo(id_Q, iol, id_INFF); packed_cells.insert(cell.first); continue; } @@ -2645,21 +2645,21 @@ class Ecp5Packer iol = create_pio_iologic(pio, ci); set_iologic_mode(iol, "IREG_OREG"); // Connection between FF and PIO - replace_port(ci, id_Q, iol, tri ? id_IOLTO : id_IOLDO); + ci->movePortTo(id_Q, iol, tri ? id_IOLTO : id_IOLDO); if (tri) { if (!pio->ports.count(id_IOLTO)) { pio->ports[id_IOLTO].name = id_IOLTO; pio->ports[id_IOLTO].type = PORT_IN; } pio->params[id_TRIMUX_TSREG] = std::string("IOLTO"); - replace_port(pio, id_T, pio, id_IOLTO); + pio->movePortTo(id_T, pio, id_IOLTO); } else { if (!pio->ports.count(id_IOLDO)) { pio->ports[id_IOLDO].name = id_IOLDO; pio->ports[id_IOLDO].type = PORT_IN; } pio->params[id_DATAMUX_OREG] = std::string("IOLDO"); - replace_port(pio, id_I, pio, id_IOLDO); + pio->movePortTo(id_I, pio, id_IOLDO); } set_iologic_sclk(iol, ci, id_CLK, false); @@ -2671,10 +2671,10 @@ class Ecp5Packer if (str_or_default(ci->params, id_CEMUX, "CE") == "CE") { iol->params[id_CEOMUX] = std::string("CEMUX"); iol->params[id_CEMUX] = std::string("CE"); - if (get_net_or_empty(ci, id_CE) == nullptr) - replace_port(ci, id_CE, iol, id_CE); + if (ci->getPort(id_CE) == nullptr) + ci->movePortTo(id_CE, iol, id_CE); else - disconnect_port(ctx, ci, id_CE); + ci->disconnectPort(id_CE); } else { iol->params[id_CEOMUX] = std::string("1"); } @@ -2684,7 +2684,7 @@ class Ecp5Packer str_or_default(ci->params, id_REGSET, "RESET"); iol->params[id_SRMODE] = str_or_default(ci->params, id_SRMODE, "ASYNC"); // Data input - replace_port(ci, id_DI, iol, tri ? id_TSDATA0 : id_TXDATA0); + ci->movePortTo(id_DI, iol, tri ? id_TSDATA0 : id_TXDATA0); iol->params[id_GSR] = str_or_default(ci->params, id_GSR, "DISABLED"); packed_cells.insert(cell.first); continue; @@ -2699,8 +2699,7 @@ class Ecp5Packer CellInfo *ci = cell.second.get(); if (ci->type == id_ECLKBRIDGECS) { Loc loc; - NetInfo *i0 = get_net_or_empty(ci, id_CLK0), *i1 = get_net_or_empty(ci, id_CLK1), - *o = get_net_or_empty(ci, id_ECSOUT); + NetInfo *i0 = ci->getPort(id_CLK0), *i1 = ci->getPort(id_CLK1), *o = ci->getPort(id_ECSOUT); for (NetInfo *input : {i0, i1}) { if (input == nullptr) continue; @@ -2753,7 +2752,7 @@ class Ecp5Packer for (auto user2 : o->users) { // Set side hint to ensure edge clock choice is routeable if (user2.cell->type == id_ECLKSYNCB && user2.port == id_ECLKI) { - NetInfo *synco = get_net_or_empty(user2.cell, id_ECLKO); + NetInfo *synco = user2.cell->getPort(id_ECLKO); if (synco != nullptr) bridge_side_hint[synco] = (loc.x > 1) ? 0 : 1; } diff --git a/fpga_interchange/arch_pack_clusters.cc b/fpga_interchange/arch_pack_clusters.cc index b003812e..31e0522b 100644 --- a/fpga_interchange/arch_pack_clusters.cc +++ b/fpga_interchange/arch_pack_clusters.cc @@ -901,7 +901,7 @@ void Arch::prepare_cluster(const ClusterPOD *cluster, uint32_t index) // reachable due to the fixed dedicated interconnect. // E.g.: The CI input of carry chains in 7series corresponds to the CIN bel port, // which can only be connected to the COUT output of the tile below. - disconnect_port(ctx, ci, sink_port); + ci->disconnectPort(sink_port); } } diff --git a/fpga_interchange/macros.cc b/fpga_interchange/macros.cc index aa7d3184..8f7f8231 100644 --- a/fpga_interchange/macros.cc +++ b/fpga_interchange/macros.cc @@ -99,9 +99,9 @@ void Arch::expand_macros() // TODO: case of multiple top level ports on the same net? NPNR_ASSERT(net == nullptr); // Use the corresponding pre-expansion port net - net = get_net_or_empty(cell, IdString(net_port.port)); + net = cell->getPort(IdString(net_port.port)); // Disconnect the original port pre-expansion - disconnect_port(ctx, cell, IdString(net_port.port)); + cell->disconnectPort(IdString(net_port.port)); } // If not on a top level port, create a new net if (net == nullptr) @@ -115,7 +115,7 @@ void Arch::expand_macros() ctx->cells.at(derived_name(ctx, cell->name, IdString(net_port.instance))).get(); inst_cell->ports[port_name].name = port_name; inst_cell->ports[port_name].type = PortType(net_port.dir); - connect_port(ctx, net, inst_cell, port_name); + inst_cell->connectPort(port_name, net); } } diff --git a/fpga_interchange/site_router.cc b/fpga_interchange/site_router.cc index 08e950e2..4e3d460a 100644 --- a/fpga_interchange/site_router.cc +++ b/fpga_interchange/site_router.cc @@ -953,7 +953,7 @@ static void apply_constant_routing(Context *ctx, const SiteArch &site_arch, NetI new_cell->belStrength = STRENGTH_PLACER; ctx->tileStatus.at(inverting_bel.tile).boundcells[inverting_bel.index] = new_cell; - connect_port(ctx, net_before_inverter, new_cell, id_I); + new_cell->connectPort(id_I, net_before_inverter); // The original BEL pin is now routed, but only through the inverter. // Because the cell/net model doesn't allow for multiple source pins diff --git a/frontend/frontend_base.h b/frontend/frontend_base.h index ed9354b6..8ac61bbe 100644 --- a/frontend/frontend_base.h +++ b/frontend/frontend_base.h @@ -484,7 +484,7 @@ template <typename FrontendType> struct GenericFrontend log_error("Net '%s' is multiply driven by cell ports %s.%s and %s.%s\n", ctx->nameOf(net), ctx->nameOf(net->driver.cell), ctx->nameOf(net->driver.port), ctx->nameOf(inst_name), port_bit_name.c_str()); - connect_port(ctx, net, ci, port_bit_ids); + ci->connectPort(port_bit_ids, net); } }); // Import attributes and parameters @@ -578,12 +578,12 @@ template <typename FrontendType> struct GenericFrontend } NPNR_ASSERT(net->driver.cell == nullptr); // Connect IBUF output and net - connect_port(ctx, net, iobuf, ctx->id("O")); + iobuf->connectPort(ctx->id("O"), net); } else if (dir == PORT_OUT) { iobuf->type = ctx->id("$nextpnr_obuf"); iobuf->addInput(ctx->id("I")); // Connect IBUF input and net - connect_port(ctx, net, iobuf, ctx->id("I")); + iobuf->connectPort(ctx->id("I"), net); } else if (dir == PORT_INOUT) { iobuf->type = ctx->id("$nextpnr_iobuf"); @@ -597,16 +597,16 @@ template <typename FrontendType> struct GenericFrontend NetInfo *split_iobuf_i = ctx->createNet(unique_name("", "$" + name + "$iobuf_i", true)); auto drv = net->driver; if (drv.cell != nullptr) { - disconnect_port(ctx, drv.cell, drv.port); + drv.cell->disconnectPort(drv.port); drv.cell->ports[drv.port].net = nullptr; - connect_port(ctx, split_iobuf_i, drv.cell, drv.port); + drv.cell->connectPort(drv.port, split_iobuf_i); } - connect_port(ctx, split_iobuf_i, iobuf, ctx->id("I")); + iobuf->connectPort(ctx->id("I"), split_iobuf_i); NPNR_ASSERT(net->driver.cell == nullptr); - connect_port(ctx, net, iobuf, ctx->id("O")); + iobuf->connectPort(ctx->id("O"), net); } else { iobuf->addInout(ctx->id("IO")); - connect_port(ctx, net, iobuf, ctx->id("IO")); + iobuf->connectPort(ctx->id("IO"), net); } } @@ -669,7 +669,7 @@ template <typename FrontendType> struct GenericFrontend if (net->driver.cell != nullptr) log_error("Net '%s' is multiply driven by port %s.%s and constant '%c'\n", ctx->nameOf(net), ctx->nameOf(net->driver.cell), ctx->nameOf(net->driver.port), constval); - connect_port(ctx, net, cc, ctx->id("Y")); + cc->connectPort(ctx->id("Y"), net); } // Merge two nets - e.g. if one net in a submodule bifurcates to two output bits and therefore two different diff --git a/generic/arch.cc b/generic/arch.cc index ad054efd..c4814bab 100644 --- a/generic/arch.cc +++ b/generic/arch.cc @@ -721,7 +721,7 @@ void Arch::assignArchInfo() CellInfo *ci = cell.second.get(); if (ci->type == id("GENERIC_SLICE")) { ci->is_slice = true; - ci->slice_clk = get_net_or_empty(ci, id("CLK")); + ci->slice_clk = ci->getPort(id("CLK")); } else { ci->is_slice = false; } diff --git a/generic/cells.cc b/generic/cells.cc index c14ddf73..76d6474f 100644 --- a/generic/cells.cc +++ b/generic/cells.cc @@ -66,19 +66,19 @@ void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff) for (int i = 0; i < lut_k; i++) { IdString port = ctx->id("I[" + std::to_string(i) + "]"); - replace_port(lut, port, lc, port); + lut->movePortTo(port, lc, port); } if (no_dff) { lc->params[ctx->id("FF_USED")] = 0; - replace_port(lut, ctx->id("Q"), lc, ctx->id("F")); + lut->movePortTo(ctx->id("Q"), lc, ctx->id("F")); } } void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut) { lc->params[ctx->id("FF_USED")] = 1; - replace_port(dff, ctx->id("CLK"), lc, ctx->id("CLK")); + dff->movePortTo(ctx->id("CLK"), lc, ctx->id("CLK")); if (pass_thru_lut) { // Fill LUT with alternating 10 @@ -89,26 +89,26 @@ void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_l init.append("10"); lc->params[ctx->id("INIT")] = Property::from_string(init); - replace_port(dff, ctx->id("D"), lc, ctx->id("I[0]")); + dff->movePortTo(ctx->id("D"), lc, ctx->id("I[0]")); } - replace_port(dff, ctx->id("Q"), lc, ctx->id("Q")); + dff->movePortTo(ctx->id("Q"), lc, ctx->id("Q")); } void nxio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *iob, pool<IdString> &todelete_cells) { if (nxio->type == ctx->id("$nextpnr_ibuf")) { iob->params[ctx->id("INPUT_USED")] = 1; - replace_port(nxio, ctx->id("O"), iob, ctx->id("O")); + nxio->movePortTo(ctx->id("O"), iob, ctx->id("O")); } else if (nxio->type == ctx->id("$nextpnr_obuf")) { iob->params[ctx->id("OUTPUT_USED")] = 1; - replace_port(nxio, ctx->id("I"), iob, ctx->id("I")); + nxio->movePortTo(ctx->id("I"), iob, ctx->id("I")); } else if (nxio->type == ctx->id("$nextpnr_iobuf")) { // N.B. tristate will be dealt with below iob->params[ctx->id("INPUT_USED")] = 1; iob->params[ctx->id("OUTPUT_USED")] = 1; - replace_port(nxio, ctx->id("I"), iob, ctx->id("I")); - replace_port(nxio, ctx->id("O"), iob, ctx->id("O")); + nxio->movePortTo(ctx->id("I"), iob, ctx->id("I")); + nxio->movePortTo(ctx->id("O"), iob, ctx->id("O")); } else { NPNR_ASSERT(false); } @@ -118,8 +118,8 @@ void nxio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *iob, pool<IdString> &to ctx->id("Y")); if (tbuf) { iob->params[ctx->id("ENABLE_USED")] = 1; - replace_port(tbuf, ctx->id("A"), iob, ctx->id("I")); - replace_port(tbuf, ctx->id("E"), iob, ctx->id("EN")); + tbuf->movePortTo(ctx->id("A"), iob, ctx->id("I")); + tbuf->movePortTo(ctx->id("E"), iob, ctx->id("EN")); if (donet->users.size() > 1) { for (auto user : donet->users) diff --git a/generic/pack.cc b/generic/pack.cc index 8bdbbed0..cb3f5897 100644 --- a/generic/pack.cc +++ b/generic/pack.cc @@ -242,7 +242,7 @@ static void pack_io(Context *ctx) } else if (bool_or_default(ctx->settings, ctx->id("disable_iobs"))) { // No IO buffer insertion; just remove nextpnr_[io]buf for (auto &p : ci->ports) - disconnect_port(ctx, ci, p.first); + ci->disconnectPort(p.first); } else { // Create a GENERIC_IOB buffer std::unique_ptr<CellInfo> ice_cell = diff --git a/generic/viaduct/example/example.cc b/generic/viaduct/example/example.cc index 3d1c201c..49b36792 100644 --- a/generic/viaduct/example/example.cc +++ b/generic/viaduct/example/example.cc @@ -253,10 +253,10 @@ struct ExampleImpl : ViaductAPI CellInfo *ci = cell.second.get(); auto &fc = fast_cell_info.at(ci->flat_index); if (ci->type == id_LUT4) { - fc.lut_f = get_net_or_empty(ci, id_F); - fc.lut_i3_used = (get_net_or_empty(ci, ctx->id(stringf("I[%d]", K - 1))) != nullptr); + fc.lut_f = ci->getPort(id_F); + fc.lut_i3_used = (ci->getPort(ctx->id(stringf("I[%d]", K - 1))) != nullptr); } else if (ci->type == id_DFF) { - fc.ff_d = get_net_or_empty(ci, id_D); + fc.ff_d = ci->getPort(id_D); } } } diff --git a/generic/viaduct_helpers.cc b/generic/viaduct_helpers.cc index e9f7fa60..10c3b802 100644 --- a/generic/viaduct_helpers.cc +++ b/generic/viaduct_helpers.cc @@ -59,13 +59,13 @@ void ViaductHelpers::remove_nextpnr_iobs(const pool<CellTypePort> &top_ports) auto &ci = *cell.second; if (!ci.type.in(ctx->id("$nextpnr_ibuf"), ctx->id("$nextpnr_obuf"), ctx->id("$nextpnr_iobuf"))) continue; - NetInfo *i = get_net_or_empty(&ci, ctx->id("I")); + NetInfo *i = ci.getPort(ctx->id("I")); if (i && i->driver.cell) { if (!top_ports.count(CellTypePort(i->driver))) log_error("Top-level port '%s' driven by illegal port %s.%s\n", ctx->nameOf(&ci), ctx->nameOf(i->driver.cell), ctx->nameOf(i->driver.port)); } - NetInfo *o = get_net_or_empty(&ci, ctx->id("O")); + NetInfo *o = ci.getPort(ctx->id("O")); if (o) { for (auto &usr : o->users) { if (!top_ports.count(CellTypePort(usr))) @@ -73,8 +73,8 @@ void ViaductHelpers::remove_nextpnr_iobs(const pool<CellTypePort> &top_ports) ctx->nameOf(usr.cell), ctx->nameOf(usr.port)); } } - disconnect_port(ctx, &ci, ctx->id("I")); - disconnect_port(ctx, &ci, ctx->id("O")); + ci.disconnectPort(ctx->id("I")); + ci.disconnectPort(ctx->id("O")); to_remove.push_back(ci.name); } for (IdString cell_name : to_remove) diff --git a/gowin/arch.cc b/gowin/arch.cc index b104013d..af851467 100644 --- a/gowin/arch.cc +++ b/gowin/arch.cc @@ -1600,9 +1600,9 @@ void Arch::assignArchInfo() ci->is_slice = true; ci->ff_used = ci->params.at(id_FF_USED).as_bool(); ci->ff_type = id(ci->params.at(id_FF_TYPE).as_string()); - ci->slice_clk = get_net_or_empty(ci, id_CLK); - ci->slice_ce = get_net_or_empty(ci, id_CE); - ci->slice_lsr = get_net_or_empty(ci, id_LSR); + ci->slice_clk = ci->getPort(id_CLK); + ci->slice_ce = ci->getPort(id_CE); + ci->slice_lsr = ci->getPort(id_LSR); // add timing paths addCellTimingClock(cname, id_CLK); diff --git a/gowin/cells.cc b/gowin/cells.cc index aef34f53..d862458c 100644 --- a/gowin/cells.cc +++ b/gowin/cells.cc @@ -93,12 +93,12 @@ void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff) IdString sim_names[4] = {id_I0, id_I1, id_I2, id_I3}; IdString wire_names[4] = {id_A, id_B, id_C, id_D}; for (int i = 0; i < 4; i++) { - replace_port(lut, sim_names[i], lc, wire_names[i]); + lut->movePortTo(sim_names[i], lc, wire_names[i]); } if (no_dff) { lc->params[id_FF_USED] = 0; - replace_port(lut, id_F, lc, id_F); + lut->movePortTo(id_F, lc, id_F); } } @@ -106,12 +106,12 @@ void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_l { lc->params[id_FF_USED] = 1; lc->params[id_FF_TYPE] = dff->type.str(ctx); - replace_port(dff, id_CLK, lc, id_CLK); - replace_port(dff, id_CE, lc, id_CE); - replace_port(dff, id_SET, lc, id_LSR); - replace_port(dff, id_RESET, lc, id_LSR); - replace_port(dff, id_CLEAR, lc, id_LSR); - replace_port(dff, id_PRESET, lc, id_LSR); + dff->movePortTo(id_CLK, lc, id_CLK); + dff->movePortTo(id_CE, lc, id_CE); + dff->movePortTo(id_SET, lc, id_LSR); + dff->movePortTo(id_RESET, lc, id_LSR); + dff->movePortTo(id_CLEAR, lc, id_LSR); + dff->movePortTo(id_PRESET, lc, id_LSR); if (pass_thru_lut) { // Fill LUT with alternating 10 const int init_size = 1 << 4; @@ -121,10 +121,10 @@ void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_l init.append("10"); lc->params[id_INIT] = Property::from_string(init); - replace_port(dff, id_D, lc, id_A); + dff->movePortTo(id_D, lc, id_A); } - replace_port(dff, id_Q, lc, id_Q); + dff->movePortTo(id_Q, lc, id_Q); } void gwio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *iob, pool<IdString> &todelete_cells) @@ -132,29 +132,29 @@ void gwio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *iob, pool<IdString> &to if (nxio->type == id_IBUF) { if (iob->type == id_IOBS) { // VCC -> OEN - connect_port(ctx, ctx->nets[ctx->id("$PACKER_VCC_NET")].get(), iob, id_OEN); + iob->connectPort(id_OEN, ctx->nets[ctx->id("$PACKER_VCC_NET")].get()); } iob->params[id_INPUT_USED] = 1; - replace_port(nxio, id_O, iob, id_O); + nxio->movePortTo(id_O, iob, id_O); } else if (nxio->type == id_OBUF) { if (iob->type == id_IOBS) { // VSS -> OEN - connect_port(ctx, ctx->nets[ctx->id("$PACKER_GND_NET")].get(), iob, id_OEN); + iob->connectPort(id_OEN, ctx->nets[ctx->id("$PACKER_GND_NET")].get()); } iob->params[id_OUTPUT_USED] = 1; - replace_port(nxio, id_I, iob, id_I); + nxio->movePortTo(id_I, iob, id_I); } else if (nxio->type == id_TBUF) { iob->params[id_ENABLE_USED] = 1; iob->params[id_OUTPUT_USED] = 1; - replace_port(nxio, id_I, iob, id_I); - replace_port(nxio, id_OEN, iob, id_OEN); + nxio->movePortTo(id_I, iob, id_I); + nxio->movePortTo(id_OEN, iob, id_OEN); } else if (nxio->type == id_IOBUF) { iob->params[id_ENABLE_USED] = 1; iob->params[id_INPUT_USED] = 1; iob->params[id_OUTPUT_USED] = 1; - replace_port(nxio, id_I, iob, id_I); - replace_port(nxio, id_O, iob, id_O); - replace_port(nxio, id_OEN, iob, id_OEN); + nxio->movePortTo(id_I, iob, id_I); + nxio->movePortTo(id_O, iob, id_O); + nxio->movePortTo(id_OEN, iob, id_OEN); } else { NPNR_ASSERT(false); } diff --git a/gowin/pack.cc b/gowin/pack.cc index 1201e310..268f26ef 100644 --- a/gowin/pack.cc +++ b/gowin/pack.cc @@ -96,7 +96,7 @@ static void pack_alus(Context *ctx) log_info("packed ALU head into %s. CIN net is %s\n", ctx->nameOf(packed_head.get()), ctx->nameOf(cin_netId)); } - connect_port(ctx, ctx->nets[ctx->id("$PACKER_VCC_NET")].get(), packed_head.get(), id_C); + packed_head->connectPort(id_C, ctx->nets[ctx->id("$PACKER_VCC_NET")].get()); if (cin_netId == ctx->id("$PACKER_GND_NET")) { // CIN = 0 packed_head->params[id_ALU_MODE] = std::string("C2L"); @@ -106,8 +106,8 @@ static void pack_alus(Context *ctx) packed_head->params[id_ALU_MODE] = std::string("ONE2C"); } else { // CIN from logic - connect_port(ctx, ctx->nets[cin_netId].get(), packed_head.get(), id_B); - connect_port(ctx, ctx->nets[cin_netId].get(), packed_head.get(), id_D); + packed_head->connectPort(id_B, ctx->nets[cin_netId].get()); + packed_head->connectPort(id_D, ctx->nets[cin_netId].get()); packed_head->params[id_ALU_MODE] = std::string("0"); // ADD } } @@ -123,9 +123,9 @@ static void pack_alus(Context *ctx) packed_cells.insert(ci->name); // CIN/COUT are hardwired, delete - disconnect_port(ctx, ci, id_CIN); + ci->disconnectPort(id_CIN); NetInfo *cout = ci->ports.at(id_COUT).net; - disconnect_port(ctx, ci, id_COUT); + ci->disconnectPort(id_COUT); std::unique_ptr<CellInfo> packed = create_generic_cell(ctx, id_SLICE, ci->name.str(ctx) + "_ALULC"); if (ctx->verbose) { @@ -135,9 +135,9 @@ static void pack_alus(Context *ctx) int mode = int_or_default(ci->params, id_ALU_MODE); packed->params[id_ALU_MODE] = mode; if (mode == 9) { // MULT - connect_port(ctx, ctx->nets[ctx->id("$PACKER_GND_NET")].get(), packed.get(), id_C); + packed->connectPort(id_C, ctx->nets[ctx->id("$PACKER_GND_NET")].get()); } else { - connect_port(ctx, ctx->nets[ctx->id("$PACKER_VCC_NET")].get(), packed.get(), id_C); + packed->connectPort(id_C, ctx->nets[ctx->id("$PACKER_VCC_NET")].get()); } // add to cluster @@ -149,30 +149,30 @@ static void pack_alus(Context *ctx) ++alu_idx; // connect all remainig ports - replace_port(ci, id_SUM, packed.get(), id_F); + ci->movePortTo(id_SUM, packed.get(), id_F); switch (mode) { case 0: // ADD - replace_port(ci, id_I0, packed.get(), id_B); - replace_port(ci, id_I1, packed.get(), id_D); + ci->movePortTo(id_I0, packed.get(), id_B); + ci->movePortTo(id_I1, packed.get(), id_D); break; case 1: // SUB - replace_port(ci, id_I0, packed.get(), id_A); - replace_port(ci, id_I1, packed.get(), id_D); + ci->movePortTo(id_I0, packed.get(), id_A); + ci->movePortTo(id_I1, packed.get(), id_D); break; case 5: // LE - replace_port(ci, id_I0, packed.get(), id_A); - replace_port(ci, id_I1, packed.get(), id_B); + ci->movePortTo(id_I0, packed.get(), id_A); + ci->movePortTo(id_I1, packed.get(), id_B); break; case 9: // MULT - replace_port(ci, id_I0, packed.get(), id_A); - replace_port(ci, id_I1, packed.get(), id_B); - disconnect_port(ctx, packed.get(), id_D); - connect_port(ctx, ctx->nets[ctx->id("$PACKER_VCC_NET")].get(), packed.get(), id_D); + ci->movePortTo(id_I0, packed.get(), id_A); + ci->movePortTo(id_I1, packed.get(), id_B); + packed->disconnectPort(id_D); + packed->connectPort(id_D, ctx->nets[ctx->id("$PACKER_VCC_NET")].get()); break; default: - replace_port(ci, id_I0, packed.get(), id_A); - replace_port(ci, id_I1, packed.get(), id_B); - replace_port(ci, id_I3, packed.get(), id_D); + ci->movePortTo(id_I0, packed.get(), id_A); + ci->movePortTo(id_I1, packed.get(), id_B); + ci->movePortTo(id_I3, packed.get(), id_D); } new_cells.push_back(std::move(packed)); @@ -191,7 +191,7 @@ static void pack_alus(Context *ctx) ctx->nameOf(cout)); } packed_tail->params[id_ALU_MODE] = std::string("C2L"); - connect_port(ctx, cout, packed_tail.get(), id_F); + packed_tail->connectPort(id_F, cout); // add to cluster packed_tail->cluster = packed_head->name; packed_tail->constr_z = alu_idx % 6; @@ -275,8 +275,8 @@ static void pack_mux2_lut5(Context *ctx, CellInfo *ci, pool<IdString> &packed_ce packed->constr_children.clear(); // reconnect MUX ports - replace_port(ci, id_O, packed.get(), id_OF); - replace_port(ci, id_I1, packed.get(), id_I1); + ci->movePortTo(id_O, packed.get(), id_OF); + ci->movePortTo(id_I1, packed.get(), id_I1); // remove cells packed_cells.insert(ci->name); @@ -320,10 +320,10 @@ static void pack_mux2_lut5(Context *ctx, CellInfo *ci, pool<IdString> &packed_ce packed->constr_children.clear(); // reconnect MUX ports - replace_port(ci, id_O, packed.get(), id_OF); - replace_port(ci, id_S0, packed.get(), id_SEL); - replace_port(ci, id_I0, packed.get(), id_I0); - replace_port(ci, id_I1, packed.get(), id_I1); + ci->movePortTo(id_O, packed.get(), id_OF); + ci->movePortTo(id_S0, packed.get(), id_SEL); + ci->movePortTo(id_I0, packed.get(), id_I0); + ci->movePortTo(id_I1, packed.get(), id_I1); // remove cells packed_cells.insert(ci->name); @@ -394,10 +394,10 @@ static void pack_mux2_lut(Context *ctx, CellInfo *ci, bool (*pred)(const BaseCtx packed->constr_children.push_back(mux1); // reconnect MUX ports - replace_port(ci, id_O, packed.get(), id_OF); - replace_port(ci, id_S0, packed.get(), id_SEL); - replace_port(ci, id_I0, packed.get(), id_I0); - replace_port(ci, id_I1, packed.get(), id_I1); + ci->movePortTo(id_O, packed.get(), id_OF); + ci->movePortTo(id_S0, packed.get(), id_SEL); + ci->movePortTo(id_I0, packed.get(), id_I0); + ci->movePortTo(id_I1, packed.get(), id_I1); // remove cells packed_cells.insert(ci->name); @@ -711,7 +711,7 @@ static void pack_io(Context *ctx) // delete the $nexpnr_[io]buf for (auto &p : iob->ports) { IdString netname = p.second.net->name; - disconnect_port(ctx, iob, p.first); + iob->disconnectPort(p.first); delete_nets.insert(netname); } packed_cells.insert(iob->name); diff --git a/ice40/arch.cc b/ice40/arch.cc index cf7e99a5..b36c82d5 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -1219,17 +1219,17 @@ void Arch::assignCellInfo(CellInfo *cell) cell->lcInfo.dffEnable = bool_or_default(cell->params, id_DFF_ENABLE); cell->lcInfo.carryEnable = bool_or_default(cell->params, id_CARRY_ENABLE); cell->lcInfo.negClk = bool_or_default(cell->params, id_NEG_CLK); - cell->lcInfo.clk = get_net_or_empty(cell, id_CLK); - cell->lcInfo.cen = get_net_or_empty(cell, id_CEN); - cell->lcInfo.sr = get_net_or_empty(cell, id_SR); + cell->lcInfo.clk = cell->getPort(id_CLK); + cell->lcInfo.cen = cell->getPort(id_CEN); + cell->lcInfo.sr = cell->getPort(id_SR); cell->lcInfo.inputCount = 0; - if (get_net_or_empty(cell, id_I0)) + if (cell->getPort(id_I0)) cell->lcInfo.inputCount++; - if (get_net_or_empty(cell, id_I1)) + if (cell->getPort(id_I1)) cell->lcInfo.inputCount++; - if (get_net_or_empty(cell, id_I2)) + if (cell->getPort(id_I2)) cell->lcInfo.inputCount++; - if (get_net_or_empty(cell, id_I3)) + if (cell->getPort(id_I3)) cell->lcInfo.inputCount++; } else if (cell->type == id_SB_IO) { cell->ioInfo.lvds = str_or_default(cell->params, id_IO_STANDARD, "SB_LVCMOS") == "SB_LVDS_INPUT"; diff --git a/ice40/cells.cc b/ice40/cells.cc index a8d30347..b5f759b2 100644 --- a/ice40/cells.cc +++ b/ice40/cells.cc @@ -340,12 +340,12 @@ void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff) if (lc->hierpath == IdString()) lc->hierpath = lut->hierpath; lc->params[id_LUT_INIT] = lut->params[id_LUT_INIT].extract(0, 16, Property::State::S0); - replace_port(lut, id_I0, lc, id_I0); - replace_port(lut, id_I1, lc, id_I1); - replace_port(lut, id_I2, lc, id_I2); - replace_port(lut, id_I3, lc, id_I3); + lut->movePortTo(id_I0, lc, id_I0); + lut->movePortTo(id_I1, lc, id_I1); + lut->movePortTo(id_I2, lc, id_I2); + lut->movePortTo(id_I3, lc, id_I3); if (no_dff) { - replace_port(lut, id_O, lc, id_O); + lut->movePortTo(id_O, lc, id_O); lc->params[id_DFF_ENABLE] = Property::State::S0; } } @@ -357,7 +357,7 @@ void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_l lc->params[id_DFF_ENABLE] = Property::State::S1; std::string config = dff->type.str(ctx).substr(6); auto citer = config.begin(); - replace_port(dff, id_C, lc, id_CLK); + dff->movePortTo(id_C, lc, id_CLK); if (citer != config.end() && *citer == 'N') { lc->params[id_NEG_CLK] = Property::State::S1; @@ -367,7 +367,7 @@ void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_l } if (citer != config.end() && *citer == 'E') { - replace_port(dff, id_E, lc, id_CEN); + dff->movePortTo(id_E, lc, id_CEN); ++citer; } @@ -382,12 +382,12 @@ void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_l if (*citer == 'S') { citer++; - replace_port(dff, id_S, lc, id_SR); + dff->movePortTo(id_S, lc, id_SR); lc->params[id_SET_NORESET] = Property::State::S1; } else { NPNR_ASSERT(*citer == 'R'); citer++; - replace_port(dff, id_R, lc, id_SR); + dff->movePortTo(id_R, lc, id_SR); lc->params[id_SET_NORESET] = Property::State::S0; } } @@ -396,10 +396,10 @@ void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_l if (pass_thru_lut) { lc->params[id_LUT_INIT] = Property(2, 16); - replace_port(dff, id_D, lc, id_I0); + dff->movePortTo(id_D, lc, id_I0); } - replace_port(dff, id_Q, lc, id_O); + dff->movePortTo(id_Q, lc, id_O); } void nxio_to_sb(Context *ctx, CellInfo *nxio, CellInfo *sbio, pool<IdString> &todelete_cells) @@ -409,13 +409,13 @@ void nxio_to_sb(Context *ctx, CellInfo *nxio, CellInfo *sbio, pool<IdString> &to auto pu_attr = nxio->attrs.find(id_PULLUP); if (pu_attr != nxio->attrs.end()) sbio->params[id_PULLUP] = pu_attr->second; - replace_port(nxio, id_O, sbio, id_D_IN_0); + nxio->movePortTo(id_O, sbio, id_D_IN_0); } else if (nxio->type == ctx->id("$nextpnr_obuf")) { sbio->params[id_PIN_TYPE] = 25; - replace_port(nxio, id_I, sbio, id_D_OUT_0); + nxio->movePortTo(id_I, sbio, id_D_OUT_0); } else if (nxio->type == ctx->id("$nextpnr_iobuf")) { // N.B. tristate will be dealt with below - NetInfo *i = get_net_or_empty(nxio, id_I); + NetInfo *i = nxio->getPort(id_I); if (i == nullptr || i->driver.cell == nullptr) sbio->params[id_PIN_TYPE] = 1; else @@ -423,8 +423,8 @@ void nxio_to_sb(Context *ctx, CellInfo *nxio, CellInfo *sbio, pool<IdString> &to auto pu_attr = nxio->attrs.find(id_PULLUP); if (pu_attr != nxio->attrs.end()) sbio->params[id_PULLUP] = pu_attr->second; - replace_port(nxio, id_I, sbio, id_D_OUT_0); - replace_port(nxio, id_O, sbio, id_D_IN_0); + nxio->movePortTo(id_I, sbio, id_D_OUT_0); + nxio->movePortTo(id_O, sbio, id_D_IN_0); } else { NPNR_ASSERT(false); } @@ -432,9 +432,11 @@ void nxio_to_sb(Context *ctx, CellInfo *nxio, CellInfo *sbio, pool<IdString> &to // Rename I/O nets to avoid conflicts if (donet != nullptr && donet->name == nxio->name) - rename_net(ctx, donet, ctx->id(donet->name.str(ctx) + "$SB_IO_OUT")); + if (donet) + ctx->renameNet(donet->name, ctx->id(donet->name.str(ctx) + "$SB_IO_OUT")); if (dinet != nullptr && dinet->name == nxio->name) - rename_net(ctx, dinet, ctx->id(dinet->name.str(ctx) + "$SB_IO_IN")); + if (dinet) + ctx->renameNet(dinet->name, ctx->id(dinet->name.str(ctx) + "$SB_IO_IN")); if (ctx->nets.count(nxio->name)) { int i = 0; @@ -442,7 +444,8 @@ void nxio_to_sb(Context *ctx, CellInfo *nxio, CellInfo *sbio, pool<IdString> &to do { new_name = ctx->id(nxio->name.str(ctx) + "$rename$" + std::to_string(i++)); } while (ctx->nets.count(new_name)); - rename_net(ctx, ctx->nets.at(nxio->name).get(), new_name); + if (ctx->nets.at(nxio->name).get()) + ctx->renameNet(ctx->nets.at(nxio->name).get()->name, new_name); } // Create a new top port net for accurate IO timing analysis and simulation netlists @@ -451,7 +454,7 @@ void nxio_to_sb(Context *ctx, CellInfo *nxio, CellInfo *sbio, pool<IdString> &to NPNR_ASSERT(!ctx->nets.count(tn_netname)); ctx->net_aliases.erase(tn_netname); NetInfo *toplevel_net = ctx->createNet(tn_netname); - connect_port(ctx, toplevel_net, sbio, id_PACKAGE_PIN); + sbio->connectPort(id_PACKAGE_PIN, toplevel_net); ctx->ports[nxio->name].net = toplevel_net; } @@ -460,8 +463,8 @@ void nxio_to_sb(Context *ctx, CellInfo *nxio, CellInfo *sbio, pool<IdString> &to id_Y); if (tbuf) { sbio->params[id_PIN_TYPE] = 41; - replace_port(tbuf, id_A, sbio, id_D_OUT_0); - replace_port(tbuf, id_E, sbio, id_OUTPUT_ENABLE); + tbuf->movePortTo(id_A, sbio, id_D_OUT_0); + tbuf->movePortTo(id_E, sbio, id_OUTPUT_ENABLE); if (donet->users.size() > 1) { for (auto user : donet->users) diff --git a/ice40/pack.cc b/ice40/pack.cc index 0220d4fe..4244f192 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -227,8 +227,8 @@ static void pack_carries(Context *ctx) ++carry_only; } carry_lc->params[id_CARRY_ENABLE] = Property::State::S1; - replace_port(ci, id_CI, carry_lc, id_CIN); - replace_port(ci, id_CO, carry_lc, id_COUT); + ci->movePortTo(id_CI, carry_lc, id_CIN); + ci->movePortTo(id_CO, carry_lc, id_COUT); if (i0_net) { auto &i0_usrs = i0_net->users; i0_usrs.erase(std::remove_if(i0_usrs.begin(), i0_usrs.end(), [ci, ctx](const PortRef &pr) { @@ -300,7 +300,7 @@ static void pack_ram(Context *ctx) newname = "RCLK"; else if (pi.name == id_WCLKN) newname = "WCLK"; - replace_port(ci, ctx->id(pi.name.c_str(ctx)), packed.get(), ctx->id(newname)); + ci->movePortTo(ctx->id(pi.name.c_str(ctx)), packed.get(), ctx->id(newname)); } new_cells.push_back(std::move(packed)); } @@ -442,7 +442,7 @@ static std::unique_ptr<CellInfo> create_padin_gbuf(Context *ctx, CellInfo *cell, gb->attrs[id_BEL] = ctx->getBelName(gb_bel).str(ctx); // Reconnect the net to that port for easier identification it's a global net - replace_port(cell, port_name, gb.get(), id_GLOBAL_BUFFER_OUTPUT); + cell->movePortTo(port_name, gb.get(), id_GLOBAL_BUFFER_OUTPUT); return gb; } @@ -514,7 +514,7 @@ static void pack_io(Context *ctx) } else if (rgb != nullptr) { log_info("%s use by SB_RGBA_DRV/SB_RGB_DRV %s, not creating SB_IO\n", ci->name.c_str(ctx), rgb->name.c_str(ctx)); - disconnect_port(ctx, ci, id_I); + ci->disconnectPort(id_I); packed_cells.insert(ci->name); continue; } else { @@ -525,7 +525,7 @@ static void pack_io(Context *ctx) sb = new_cells.back().get(); } for (auto port : ci->ports) - disconnect_port(ctx, ci, port.first); + ci->disconnectPort(port.first); packed_cells.insert(ci->name); for (auto &attr : ci->attrs) sb->attrs[attr.first] = attr.second; @@ -1138,13 +1138,13 @@ static void pack_special(Context *ctx) std::unique_ptr<CellInfo> packed = create_ice_cell(ctx, id_ICESTORM_LFOSC, ci->name.str(ctx) + "_OSC"); packed_cells.insert(ci->name); cell_place_unique(ctx, packed.get()); - replace_port(ci, id_CLKLFEN, packed.get(), id_CLKLFEN); - replace_port(ci, id_CLKLFPU, packed.get(), id_CLKLFPU); + ci->movePortTo(id_CLKLFEN, packed.get(), id_CLKLFEN); + ci->movePortTo(id_CLKLFPU, packed.get(), id_CLKLFPU); if (bool_or_default(ci->attrs, id_ROUTE_THROUGH_FABRIC)) { - replace_port(ci, id_CLKLF, packed.get(), id_CLKLF_FABRIC); + ci->movePortTo(id_CLKLF, packed.get(), id_CLKLF_FABRIC); set_period(ctx, packed.get(), id_CLKLF_FABRIC, 100000000); // 10kHz } else { - replace_port(ci, id_CLKLF, packed.get(), id_CLKLF); + ci->movePortTo(id_CLKLF, packed.get(), id_CLKLF); std::unique_ptr<CellInfo> gb = create_padin_gbuf(ctx, packed.get(), id_CLKLF, "$gbuf_" + ci->name.str(ctx) + "_lfosc"); set_period(ctx, gb.get(), id_GLOBAL_BUFFER_OUTPUT, 100000000); // 10kHz @@ -1157,11 +1157,11 @@ static void pack_special(Context *ctx) cell_place_unique(ctx, packed.get()); packed->params[id_TRIM_EN] = str_or_default(ci->params, id_TRIM_EN, "0b0"); packed->params[id_CLKHF_DIV] = str_or_default(ci->params, id_CLKHF_DIV, "0b00"); - replace_port(ci, id_CLKHFEN, packed.get(), id_CLKHFEN); - replace_port(ci, id_CLKHFPU, packed.get(), id_CLKHFPU); + ci->movePortTo(id_CLKHFEN, packed.get(), id_CLKHFEN); + ci->movePortTo(id_CLKHFPU, packed.get(), id_CLKHFPU); for (int i = 0; i < 10; i++) { auto port = ctx->id("TRIM" + std::to_string(i)); - replace_port(ci, port, packed.get(), port); + ci->movePortTo(port, packed.get(), port); } std::string div = packed->params[id_CLKHF_DIV].as_string(); int frequency; @@ -1176,10 +1176,10 @@ static void pack_special(Context *ctx) else log_error("Invalid HFOSC divider value '%s' - expecting 0b00, 0b01, 0b10 or 0b11\n", div.c_str()); if (bool_or_default(ci->attrs, id_ROUTE_THROUGH_FABRIC)) { - replace_port(ci, id_CLKHF, packed.get(), id_CLKHF_FABRIC); + ci->movePortTo(id_CLKHF, packed.get(), id_CLKHF_FABRIC); set_period(ctx, packed.get(), id_CLKHF_FABRIC, 1000000 / frequency); } else { - replace_port(ci, id_CLKHF, packed.get(), id_CLKHF); + ci->movePortTo(id_CLKHF, packed.get(), id_CLKHF); std::unique_ptr<CellInfo> gb = create_padin_gbuf(ctx, packed.get(), id_CLKHF, "$gbuf_" + ci->name.str(ctx) + "_hfosc"); set_period(ctx, gb.get(), id_GLOBAL_BUFFER_OUTPUT, 1000000 / frequency); @@ -1198,7 +1198,7 @@ static void pack_special(Context *ctx) if (bpos != std::string::npos) { newname = newname.substr(0, bpos) + "_" + newname.substr(bpos + 1, (newname.size() - bpos) - 2); } - replace_port(ci, ctx->id(pi.name.c_str(ctx)), packed.get(), ctx->id(newname)); + ci->movePortTo(ctx->id(pi.name.c_str(ctx)), packed.get(), ctx->id(newname)); } new_cells.push_back(std::move(packed)); } else if (is_sb_mac16(ctx, ci)) { @@ -1216,7 +1216,7 @@ static void pack_special(Context *ctx) if (bpos != std::string::npos) { newname = newname.substr(0, bpos) + "_" + newname.substr(bpos + 1, (newname.size() - bpos) - 2); } - replace_port(ci, ctx->id(pi.name.c_str(ctx)), packed.get(), ctx->id(newname)); + ci->movePortTo(ctx->id(pi.name.c_str(ctx)), packed.get(), ctx->id(newname)); } new_cells.push_back(std::move(packed)); } else if (is_sb_rgba_drv(ctx, ci) || is_sb_rgb_drv(ctx, ci)) { @@ -1410,7 +1410,7 @@ void pack_plls(Context *ctx) } } } - replace_port(ci, ctx->id(pi.name.c_str(ctx)), packed.get(), ctx->id(newname)); + ci->movePortTo(ctx->id(pi.name.c_str(ctx)), packed.get(), ctx->id(newname)); } // Compute derive constraints diff --git a/machxo2/cells.cc b/machxo2/cells.cc index 1c4f753b..c5464892 100644 --- a/machxo2/cells.cc +++ b/machxo2/cells.cc @@ -131,10 +131,10 @@ void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff) for (std::string i : {"A", "B", "C", "D"}) { IdString lut_port = ctx->id(i); IdString lc_port = ctx->id(i + "0"); - replace_port(lut, lut_port, lc, lc_port); + lut->movePortTo(lut_port, lc, lc_port); } - replace_port(lut, id_Z, lc, id_F0); + lut->movePortTo(id_Z, lc, id_F0); } void dff_to_lc(Context *ctx, CellInfo *dff, CellInfo *lc, LutType lut_type) @@ -142,26 +142,26 @@ void dff_to_lc(Context *ctx, CellInfo *dff, CellInfo *lc, LutType lut_type) // FIXME: This will have to change once we support FFs with reset value of 1. lc->params[id_REG0_REGSET] = std::string("RESET"); - replace_port(dff, id_CLK, lc, id_CLK); - replace_port(dff, id_LSR, lc, id_LSR); - replace_port(dff, id_Q, lc, id_Q0); + dff->movePortTo(id_CLK, lc, id_CLK); + dff->movePortTo(id_LSR, lc, id_LSR); + dff->movePortTo(id_Q, lc, id_Q0); if (lut_type == LutType::PassThru) { // If a register's DI port is fed by a constant, options for placing are // limited. Use the LUT to get around this. // LUT output will go to F0, which will feed back to DI0 input. lc->params[id_LUT0_INITVAL] = Property(0xAAAA, 16); - replace_port(dff, id_DI, lc, id_A0); - connect_ports(ctx, lc, id_F0, lc, id_DI0); + dff->movePortTo(id_DI, lc, id_A0); + lc->connectPorts(id_F0, lc, id_DI0); } else if (lut_type == LutType::None) { // If there is no LUT, use the M0 input because DI0 requires // going through the LUTs. lc->params[id_REG0_SD] = std::string("0"); - replace_port(dff, id_DI, lc, id_M0); + dff->movePortTo(id_DI, lc, id_M0); } else { // Otherwise, there's a LUT being used in the slice and mapping DI to // DI0 input is fine. - replace_port(dff, id_DI, lc, id_DI0); + dff->movePortTo(id_DI, lc, id_DI0); } } diff --git a/machxo2/pack.cc b/machxo2/pack.cc index de607865..5051a981 100644 --- a/machxo2/pack.cc +++ b/machxo2/pack.cc @@ -286,7 +286,7 @@ static void pack_io(Context *ctx) log_info("Removing top-level IOBUF '%s' of type '%s'\n", ci->name.c_str(ctx), ci->type.c_str(ctx)); for (auto &p : ci->ports) - disconnect_port(ctx, ci, p.first); + ci->disconnectPort(p.first); packed_cells.insert(ci->name); } else if (is_facade_iob(ctx, ci)) { // If FACADE_IO has LOC attribute, convert the LOC (pin) to a BEL diff --git a/mistral/bitstream.cc b/mistral/bitstream.cc index e18d1413..35c1303a 100644 --- a/mistral/bitstream.cc +++ b/mistral/bitstream.cc @@ -86,8 +86,7 @@ struct MistralBitgen void write_io_cell(CellInfo *ci, int x, int y, int bi) { - bool is_output = - (ci->type == id_MISTRAL_OB || (ci->type == id_MISTRAL_IO && get_net_or_empty(ci, id_OE) != nullptr)); + bool is_output = (ci->type == id_MISTRAL_OB || (ci->type == id_MISTRAL_IO && ci->getPort(id_OE) != nullptr)); auto pos = CycloneV::xy2pos(x, y); // TODO: configurable pull, IO standard, etc cv->bmux_b_set(CycloneV::GPIO, pos, CycloneV::USE_WEAK_PULLUP, bi, false); @@ -229,8 +228,8 @@ struct MistralBitgen cv->bmux_m_set(block_type, pos, clk_sel[i / 2], alm, clk_choice[ce_idx]); if (ff->ffInfo.ctrlset.clk.inverted) cv->bmux_b_set(block_type, pos, clk_inv[ce_idx], 0, true); - if (get_net_or_empty(ff, id_ENA) != nullptr) { // not using ffInfo.ctrlset, this has a fake net always to - // ensure different constants don't collide + if (ff->getPort(id_ENA) != nullptr) { // not using ffInfo.ctrlset, this has a fake net always to + // ensure different constants don't collide cv->bmux_b_set(block_type, pos, en_en[ce_idx], 0, true); cv->bmux_b_set(block_type, pos, en_ninv[ce_idx], 0, ff->ffInfo.ctrlset.ena.inverted); } else { @@ -262,7 +261,7 @@ struct MistralBitgen cv->bmux_m_set(block_type, pos, clk_sel[1], alm, clk_choice[ce_idx]); if (lut->combInfo.wclk.inverted) cv->bmux_b_set(block_type, pos, clk_inv[ce_idx], 0, true); - if (get_net_or_empty(lut, id_A1EN) != nullptr) { + if (lut->getPort(id_A1EN) != nullptr) { cv->bmux_b_set(block_type, pos, en_en[ce_idx], 0, true); cv->bmux_b_set(block_type, pos, en_ninv[ce_idx], 0, lut->combInfo.we.inverted); } else { diff --git a/mistral/lab.cc b/mistral/lab.cc index 4f6b9b00..4b66ed0c 100644 --- a/mistral/lab.cc +++ b/mistral/lab.cc @@ -212,7 +212,7 @@ namespace { ControlSig get_ctrlsig(const Context *ctx, const CellInfo *cell, IdString port, bool explicit_const = false) { ControlSig result; - result.net = get_net_or_empty(cell, port); + result.net = cell->getPort(port); if (result.net == nullptr && explicit_const) { // For ENA, 1 (and 0) are explicit control set choices even though they aren't routed, as "no ENA" still // consumes a clock+ENA pair @@ -278,10 +278,10 @@ void Arch::assign_comb_info(CellInfo *cell) const cell->combInfo.lut_input_count = 5; cell->combInfo.lut_bits_count = 32; for (int i = 0; i < 5; i++) - cell->combInfo.lut_in[i] = get_net_or_empty(cell, id(stringf("B1ADDR[%d]", i))); + cell->combInfo.lut_in[i] = cell->getPort(id(stringf("B1ADDR[%d]", i))); auto key = get_mlab_key(cell); cell->combInfo.mlab_group = mlab_groups(key); - cell->combInfo.comb_out = get_net_or_empty(cell, id_B1DATA); + cell->combInfo.comb_out = cell->getPort(id_B1DATA); } else if (cell->type == id_MISTRAL_ALUT_ARITH) { cell->combInfo.is_carry = true; cell->combInfo.lut_input_count = 5; @@ -292,14 +292,14 @@ void Arch::assign_comb_info(CellInfo *cell) const { int i = 0; for (auto pin : arith_pins) { - cell->combInfo.lut_in[i++] = get_net_or_empty(cell, pin); + cell->combInfo.lut_in[i++] = cell->getPort(pin); } } - const NetInfo *ci = get_net_or_empty(cell, id_CI); - const NetInfo *co = get_net_or_empty(cell, id_CO); + const NetInfo *ci = cell->getPort(id_CI); + const NetInfo *co = cell->getPort(id_CO); - cell->combInfo.comb_out = get_net_or_empty(cell, id_SO); + cell->combInfo.comb_out = cell->getPort(id_SO); cell->combInfo.carry_start = (ci == nullptr) || (ci->driver.cell == nullptr); cell->combInfo.carry_end = (co == nullptr) || (co->users.empty()); @@ -308,10 +308,10 @@ void Arch::assign_comb_info(CellInfo *cell) const const CellInfo *prev = ci->driver.cell; if (prev != nullptr) { for (int i = 0; i < 5; i++) { - const NetInfo *a = get_net_or_empty(cell, arith_pins[i]); + const NetInfo *a = cell->getPort(arith_pins[i]); if (a == nullptr) continue; - const NetInfo *b = get_net_or_empty(prev, arith_pins[i]); + const NetInfo *b = prev->getPort(arith_pins[i]); if (a == b) ++cell->combInfo.chain_shared_input_count; } @@ -323,28 +323,28 @@ void Arch::assign_comb_info(CellInfo *cell) const switch (cell->type.index) { case ID_MISTRAL_ALUT6: ++cell->combInfo.lut_input_count; - cell->combInfo.lut_in[5] = get_net_or_empty(cell, id_F); + cell->combInfo.lut_in[5] = cell->getPort(id_F); [[fallthrough]]; case ID_MISTRAL_ALUT5: ++cell->combInfo.lut_input_count; - cell->combInfo.lut_in[4] = get_net_or_empty(cell, id_E); + cell->combInfo.lut_in[4] = cell->getPort(id_E); [[fallthrough]]; case ID_MISTRAL_ALUT4: ++cell->combInfo.lut_input_count; - cell->combInfo.lut_in[3] = get_net_or_empty(cell, id_D); + cell->combInfo.lut_in[3] = cell->getPort(id_D); [[fallthrough]]; case ID_MISTRAL_ALUT3: ++cell->combInfo.lut_input_count; - cell->combInfo.lut_in[2] = get_net_or_empty(cell, id_C); + cell->combInfo.lut_in[2] = cell->getPort(id_C); [[fallthrough]]; case ID_MISTRAL_ALUT2: ++cell->combInfo.lut_input_count; - cell->combInfo.lut_in[1] = get_net_or_empty(cell, id_B); + cell->combInfo.lut_in[1] = cell->getPort(id_B); [[fallthrough]]; case ID_MISTRAL_BUF: // used to route through to FFs etc case ID_MISTRAL_NOT: // used for inverters that map to LUTs ++cell->combInfo.lut_input_count; - cell->combInfo.lut_in[0] = get_net_or_empty(cell, id_A); + cell->combInfo.lut_in[0] = cell->getPort(id_A); [[fallthrough]]; case ID_MISTRAL_CONST: // MISTRAL_CONST is a nextpnr-inserted cell type for 0-input, constant-generating LUTs @@ -375,8 +375,8 @@ void Arch::assign_ff_info(CellInfo *cell) const cell->ffInfo.ctrlset.sload.inverted = false; } - cell->ffInfo.sdata = get_net_or_empty(cell, id_SDATA); - cell->ffInfo.datain = get_net_or_empty(cell, id_DATAIN); + cell->ffInfo.sdata = cell->getPort(id_SDATA); + cell->ffInfo.datain = cell->getPort(id_DATAIN); } // Validity checking functions @@ -883,7 +883,7 @@ void Arch::reassign_alm_inputs(uint32_t lab, uint8_t alm) auto &bel_pins = luts[i]->pin_data[log].bel_pins; bel_pins.clear(); - NetInfo *net = get_net_or_empty(luts[i], log); + NetInfo *net = luts[i]->getPort(log); if (net == nullptr) { // Disconnected inputs don't need to be allocated a pin, because the router won't be routing these continue; @@ -922,10 +922,10 @@ void Arch::reassign_alm_inputs(uint32_t lab, uint8_t alm) rt_lut->addInput(id_A); rt_lut->addOutput(id_Q); // Disconnect the original data input to the FF, and connect it to the route-thru LUT instead - NetInfo *datain = get_net_or_empty(ff, id_DATAIN); - disconnect_port(getCtx(), ff, id_DATAIN); - connect_port(getCtx(), datain, rt_lut, id_A); - connect_ports(getCtx(), rt_lut, id_Q, ff, id_DATAIN); + NetInfo *datain = ff->getPort(id_DATAIN); + ff->disconnectPort(id_DATAIN); + rt_lut->connectPort(id_A, datain); + rt_lut->connectPorts(id_Q, ff, id_DATAIN); // Assign route-thru LUT physical ports, input goes to the first half-specific input rt_lut->pin_data[id_A].bel_pins.push_back(i ? id_D : id_C); rt_lut->pin_data[id_Q].bel_pins.push_back(id_COMBOUT); @@ -1050,7 +1050,7 @@ uint64_t Arch::compute_lut_mask(uint32_t lab, uint8_t alm) else if (state == PIN_1) index |= (1 << init_idx); // Ignore if no associated physical pin - if (get_net_or_empty(lut, log_pin) == nullptr || lut->pin_data.at(log_pin).bel_pins.empty()) + if (lut->getPort(log_pin) == nullptr || lut->pin_data.at(log_pin).bel_pins.empty()) continue; // ALM inputs appear to be inverted by default (TODO: check!) // so only invert if an inverter has _not_ been folded into the pin diff --git a/mistral/pack.cc b/mistral/pack.cc index 4b434015..c4b3afe3 100644 --- a/mistral/pack.cc +++ b/mistral/pack.cc @@ -41,13 +41,13 @@ struct MistralPacker vcc_drv->addOutput(id_Q); gnd_net = ctx->createNet(ctx->id("$PACKER_GND_NET")); vcc_net = ctx->createNet(ctx->id("$PACKER_VCC_NET")); - connect_port(ctx, gnd_net, gnd_drv, id_Q); - connect_port(ctx, vcc_net, vcc_drv, id_Q); + gnd_drv->connectPort(id_Q, gnd_net); + vcc_drv->connectPort(id_Q, vcc_net); } CellPinState get_pin_needed_muxval(CellInfo *cell, IdString port) { - NetInfo *net = get_net_or_empty(cell, port); + NetInfo *net = cell->getPort(port); if (net == nullptr || net->driver.cell == nullptr) { // Pin is disconnected // If a mux value exists already, honour it @@ -78,14 +78,14 @@ struct MistralPacker void uninvert_port(CellInfo *cell, IdString port) { // Rewire a port so it is driven by the input to an inverter - NetInfo *net = get_net_or_empty(cell, port); + NetInfo *net = cell->getPort(port); NPNR_ASSERT(net != nullptr && net->driver.cell != nullptr && net->driver.cell->type == id_MISTRAL_NOT); CellInfo *inv = net->driver.cell; - disconnect_port(ctx, cell, port); + cell->disconnectPort(port); - NetInfo *inv_a = get_net_or_empty(inv, id_A); + NetInfo *inv_a = inv->getPort(id_A); if (inv_a != nullptr) { - connect_port(ctx, inv_a, cell, port); + cell->connectPort(port, inv_a); } } @@ -117,12 +117,12 @@ struct MistralPacker // Pin is tied to a constant // If there is a hard constant option; use it if ((pin_style & int(req_mux)) == req_mux) { - disconnect_port(ctx, cell, port_name); + cell->disconnectPort(port_name); cell->pin_data[port_name].state = req_mux; } else { - disconnect_port(ctx, cell, port_name); + cell->disconnectPort(port_name); // There is no hard constant, we need to connect it to the relevant soft-constant net - connect_port(ctx, (req_mux == PIN_1) ? vcc_net : gnd_net, cell, port_name); + cell->connectPort(port_name, (req_mux == PIN_1) ? vcc_net : gnd_net); } } } @@ -138,7 +138,7 @@ struct MistralPacker if (ci->type != id_MISTRAL_NOT && ci->type != id_GND && ci->type != id_VCC) continue; IdString port = (ci->type == id_MISTRAL_NOT) ? id_Q : id_Y; - NetInfo *out = get_net_or_empty(ci, port); + NetInfo *out = ci->getPort(port); if (out == nullptr) { trim_cells.push_back(ci->name); continue; @@ -146,7 +146,7 @@ struct MistralPacker if (!out->users.empty()) continue; - disconnect_port(ctx, ci, id_A); + ci->disconnectPort(id_A); trim_cells.push_back(ci->name); trim_nets.push_back(out->name); @@ -174,7 +174,7 @@ struct MistralPacker continue; if (ci->get_pin_state(id_SLOAD) != PIN_0) continue; - disconnect_port(ctx, ci, id_SDATA); + ci->disconnectPort(id_SDATA); } // Remove superfluous inverters and constant drivers trim_design(); @@ -197,7 +197,7 @@ struct MistralPacker if (ci->type == ctx->id("$nextpnr_ibuf") || ci->type == ctx->id("$nextpnr_iobuf")) { // Might have an input buffer (IB etc) connected to it is_npnr_iob = true; - NetInfo *o = get_net_or_empty(ci, id_O); + NetInfo *o = ci->getPort(id_O); if (o == nullptr) ; else if (o->users.size() > 1) @@ -208,7 +208,7 @@ struct MistralPacker if (ci->type == ctx->id("$nextpnr_obuf") || ci->type == ctx->id("$nextpnr_iobuf")) { // Might have an output buffer (OB etc) connected to it is_npnr_iob = true; - NetInfo *i = get_net_or_empty(ci, id_I); + NetInfo *i = ci->getPort(id_I); if (i != nullptr && i->driver.cell != nullptr) { if (top_port.cell != nullptr) log_error("Top level pin '%s' has multiple input/output buffers\n", ctx->nameOf(port.first)); @@ -245,8 +245,8 @@ struct MistralPacker port.second.net = top_port.cell->ports.at(top_port.port).net; } // Now remove the nextpnr-inserted buffer - disconnect_port(ctx, ci, id_I); - disconnect_port(ctx, ci, id_O); + ci->disconnectPort(id_I); + ci->disconnectPort(id_O); ctx->cells.erase(port.first); } } @@ -290,14 +290,14 @@ struct MistralPacker CellInfo *ci = cell.second.get(); if (ci->type != id_MISTRAL_ALUT_ARITH) continue; - const NetInfo *cin = get_net_or_empty(ci, id_CI); + const NetInfo *cin = ci->getPort(id_CI); if (cin != nullptr && cin->driver.cell != nullptr) continue; // not the start of a chain std::vector<CellInfo *> chain; CellInfo *cursor = ci; while (true) { chain.push_back(cursor); - const NetInfo *co = get_net_or_empty(cursor, id_CO); + const NetInfo *co = cursor->getPort(id_CO); if (co == nullptr || co->users.empty()) break; if (co->users.size() > 1) @@ -327,7 +327,7 @@ struct MistralPacker for (int i = 0; i < int(chain.size()); i++) { auto &c = chain.at(i); log_info(" i=%d cell=%s dy=%d z=%d ci=%s co=%s\n", i, ctx->nameOf(c), c->constr_y, c->constr_z, - ctx->nameOf(get_net_or_empty(c, id_CI)), ctx->nameOf(get_net_or_empty(c, id_CO))); + ctx->nameOf(c->getPort(id_CI)), ctx->nameOf(c->getPort(id_CO))); } } } @@ -338,7 +338,7 @@ struct MistralPacker continue; if (ci->cluster == ClusterId()) log_error("Failed to include arith cell '%s' in any chain (CI=%s)\n", ctx->nameOf(ci), - ctx->nameOf(get_net_or_empty(ci, id_CI))); + ctx->nameOf(ci->getPort(id_CI))); } } diff --git a/nexus/fasm.cc b/nexus/fasm.cc index 4aaecdf4..c460e14b 100644 --- a/nexus/fasm.cc +++ b/nexus/fasm.cc @@ -421,7 +421,7 @@ struct NexusFasmWriter BelId bel = cell->bel; used_io.insert(bel); push_bel(bel); - const NetInfo *t = get_net_or_empty(cell, id_T); + const NetInfo *t = cell->getPort(id_T); auto tmux = ctx->get_cell_pinmux(cell, id_T); bool is_input = false, is_output = false; if (tmux == PINMUX_0) { @@ -444,7 +444,7 @@ struct NexusFasmWriter used_io.insert(bel); push_bel(bel); push("SEIO18"); - const NetInfo *t = get_net_or_empty(cell, id_T); + const NetInfo *t = cell->getPort(id_T); auto tmux = ctx->get_cell_pinmux(cell, id_T); bool is_input = false, is_output = false; if (tmux == PINMUX_0) { @@ -481,7 +481,7 @@ struct NexusFasmWriter bank.diff_used = true; - const NetInfo *t = get_net_or_empty(cell, id_T); + const NetInfo *t = cell->getPort(id_T); auto tmux = ctx->get_cell_pinmux(cell, id_T); bool is_input = false, is_output = false; if (tmux == PINMUX_0) { @@ -843,7 +843,7 @@ struct NexusFasmWriter if (!ci->attrs.count(id_IO_TYPE)) continue; // VccO only concerns outputs - const NetInfo *t = get_net_or_empty(ci, id_T); + const NetInfo *t = ci->getPort(id_T); auto tmux = ctx->get_cell_pinmux(ci, id_T); if (tmux == PINMUX_1 || (tmux != PINMUX_0 && t == nullptr)) continue; diff --git a/nexus/pack.cc b/nexus/pack.cc index 13522c78..5509d997 100644 --- a/nexus/pack.cc +++ b/nexus/pack.cc @@ -126,12 +126,12 @@ struct NexusPacker for (auto pname : orig_port_names) { if (rule.port_multixform.count(pname)) { auto old_port = ci->ports.at(pname); - disconnect_port(ctx, ci, pname); + ci->disconnectPort(pname); ci->ports.erase(pname); for (auto new_name : rule.port_multixform.at(pname)) { ci->ports[new_name].name = new_name; ci->ports[new_name].type = old_port.type; - connect_port(ctx, old_port.net, ci, new_name); + ci->connectPort(new_name, old_port.net); } } else { IdString new_name; @@ -145,7 +145,7 @@ struct NexusPacker new_name = ctx->id(stripped_name); } if (new_name != pname) { - rename_port(ctx, ci, pname, new_name); + ci->renamePort(pname, new_name); } } } @@ -307,7 +307,7 @@ struct NexusPacker CellInfo *ci = cell.second.get(); if (ci->type != type) continue; - NetInfo *z = get_net_or_empty(ci, id_Z); + NetInfo *z = ci->getPort(id_Z); if (z == nullptr) continue; return z; @@ -316,13 +316,13 @@ struct NexusPacker NetInfo *new_net = ctx->createNet(ctx->id(stringf("$CONST_%s_NET_", type.c_str(ctx)))); CellInfo *new_cell = ctx->createCell(ctx->id(stringf("$CONST_%s_DRV_", type.c_str(ctx))), type); new_cell->addOutput(id_Z); - connect_port(ctx, new_net, new_cell, id_Z); + new_cell->connectPort(id_Z, new_net); return new_net; } CellPinMux get_pin_needed_muxval(CellInfo *cell, IdString port) { - NetInfo *net = get_net_or_empty(cell, port); + NetInfo *net = cell->getPort(port); if (net == nullptr || net->driver.cell == nullptr) { // Pin is disconnected // If a mux value exists already, honour it @@ -353,14 +353,14 @@ struct NexusPacker void uninvert_port(CellInfo *cell, IdString port) { // Rewire a port so it is driven by the input to an inverter - NetInfo *net = get_net_or_empty(cell, port); + NetInfo *net = cell->getPort(port); NPNR_ASSERT(net != nullptr && net->driver.cell != nullptr && net->driver.cell->type == id_INV); CellInfo *inv = net->driver.cell; - disconnect_port(ctx, cell, port); + cell->disconnectPort(port); - NetInfo *inv_a = get_net_or_empty(inv, id_A); + NetInfo *inv_a = inv->getPort(id_A); if (inv_a != nullptr) { - connect_port(ctx, inv_a, cell, port); + cell->connectPort(port, inv_a); } } @@ -373,7 +373,7 @@ struct NexusPacker CellInfo *ci = cell.second.get(); if (ci->type != id_INV && ci->type != id_VLO && ci->type != id_VHI && ci->type != id_VCC_DRV) continue; - NetInfo *z = get_net_or_empty(ci, id_Z); + NetInfo *z = ci->getPort(id_Z); if (z == nullptr) { trim_cells.push_back(ci->name); continue; @@ -381,7 +381,7 @@ struct NexusPacker if (!z->users.empty()) continue; - disconnect_port(ctx, ci, id_A); + ci->disconnectPort(id_A); trim_cells.push_back(ci->name); trim_nets.push_back(z->name); @@ -415,7 +415,7 @@ struct NexusPacker for (IdString port : port_names) { IdString new_name = ctx->id(remove_brackets(port.str(ctx))); if (new_name != port) - rename_port(ctx, cell, port, new_name); + cell->renamePort(port, new_name); } } @@ -453,17 +453,17 @@ struct NexusPacker if ((cell->type == id_OXIDE_COMB) && (req_mux == PINMUX_1)) { // We need to add a connection to the dedicated Vcc resource that can feed these cell ports - disconnect_port(ctx, cell, port_name); - connect_port(ctx, dedi_vcc_net, cell, port_name); + cell->disconnectPort(port_name); + cell->connectPort(port_name, dedi_vcc_net); continue; } - disconnect_port(ctx, cell, port_name); + cell->disconnectPort(port_name); ctx->set_cell_pinmux(cell, port_name, req_mux); } else if (port.second.net == nullptr) { // If the port is disconnected; and there is no hard constant // then we need to connect it to the relevant soft-constant net - connect_port(ctx, (req_mux == PINMUX_1) ? vcc_net : gnd_net, cell, port_name); + cell->connectPort(port_name, (req_mux == PINMUX_1) ? vcc_net : gnd_net); } } } @@ -486,7 +486,7 @@ struct NexusPacker if (ci->type == ctx->id("$nextpnr_ibuf") || ci->type == ctx->id("$nextpnr_iobuf")) { // Might have an input buffer (IB etc) connected to it is_npnr_iob = true; - NetInfo *o = get_net_or_empty(ci, id_O); + NetInfo *o = ci->getPort(id_O); if (o == nullptr) ; else if (o->users.size() > 1) @@ -497,7 +497,7 @@ struct NexusPacker if (ci->type == ctx->id("$nextpnr_obuf") || ci->type == ctx->id("$nextpnr_iobuf")) { // Might have an output buffer (OB etc) connected to it is_npnr_iob = true; - NetInfo *i = get_net_or_empty(ci, id_I); + NetInfo *i = ci->getPort(id_I); if (i != nullptr && i->driver.cell != nullptr) { if (top_port.cell != nullptr) log_error("Top level pin '%s' has multiple input/output buffers\n", ctx->nameOf(port.first)); @@ -534,8 +534,8 @@ struct NexusPacker port.second.net = top_port.cell->ports.at(top_port.port).net; } // Now remove the nextpnr-inserted buffer - disconnect_port(ctx, ci, id_I); - disconnect_port(ctx, ci, id_O); + ci->disconnectPort(id_I); + ci->disconnectPort(id_O); ctx->cells.erase(port.first); } } @@ -635,13 +635,13 @@ struct NexusPacker // For non-bidirectional IO, we also need to configure tristate and rename B if (ci->type == id_IB) { ctx->set_cell_pinmux(ci, id_T, PINMUX_1); - rename_port(ctx, ci, id_I, id_B); + ci->renamePort(id_I, id_B); } else if (ci->type == id_OB) { ctx->set_cell_pinmux(ci, id_T, PINMUX_0); - rename_port(ctx, ci, id_O, id_B); + ci->renamePort(id_O, id_B); } else if (ci->type == id_OBZ) { ctx->set_cell_pinmux(ci, id_T, PINMUX_SIG); - rename_port(ctx, ci, id_O, id_B); + ci->renamePort(id_O, id_B); } // Get the IO bel BelId bel = get_bel_attr(ci); @@ -760,7 +760,7 @@ struct NexusPacker if (cell->attrs.count(id_BEL)) return false; - NetInfo *pin_net = get_net_or_empty(cell, pin); + NetInfo *pin_net = cell->getPort(pin); if (pin_net == nullptr) return false; @@ -827,7 +827,7 @@ struct NexusPacker buffer->addInput(i); buffer->addOutput(o); // Drive the buffered net with the buffer - connect_port(ctx, buffered_net, buffer, o); + buffer->connectPort(o, buffered_net); // Filter users std::vector<PortRef> remaining_users; @@ -843,7 +843,7 @@ struct NexusPacker std::swap(net->users, remaining_users); // Connect buffer input to original net - connect_port(ctx, net, buffer, i); + buffer->connectPort(i, net); return buffer; } @@ -936,56 +936,56 @@ struct NexusPacker combs.push_back( ctx->createCell(ctx->id(stringf("%s$lutram_comb[%d]$", ctx->nameOf(ci), i)), id_OXIDE_COMB)); // Rewiring - external WCK and WRE - replace_port(ci, id_WCK, ramw, id_CLK); - replace_port(ci, id_WRE, ramw, id_LSR); + ci->movePortTo(id_WCK, ramw, id_CLK); + ci->movePortTo(id_WRE, ramw, id_LSR); // Internal WCK and WRE signals ramw->addOutput(id_WCKO); ramw->addOutput(id_WREO); NetInfo *int_wck = ctx->createNet(ctx->id(stringf("%s$lutram_wck$", ctx->nameOf(ci)))); NetInfo *int_wre = ctx->createNet(ctx->id(stringf("%s$lutram_wre$", ctx->nameOf(ci)))); - connect_port(ctx, int_wck, ramw, id_WCKO); - connect_port(ctx, int_wre, ramw, id_WREO); + ramw->connectPort(id_WCKO, int_wck); + ramw->connectPort(id_WREO, int_wre); uint64_t initval = ctx->parse_lattice_param(ci, id_INITVAL, 64, 0).as_int64(); // Rewiring - buses for (int i = 0; i < 4; i++) { // Write address - external - replace_port(ci, bus("WAD", i), ramw, ramw_wado[i]); + ci->movePortTo(bus("WAD", i), ramw, ramw_wado[i]); // Write data - external - replace_port(ci, bus("DI", i), ramw, ramw_wdo[i]); + ci->movePortTo(bus("DI", i), ramw, ramw_wdo[i]); // Read data - replace_port(ci, bus("DO", i), combs[i], id_F); + ci->movePortTo(bus("DO", i), combs[i], id_F); // Read address - NetInfo *rad = get_net_or_empty(ci, bus("RAD", i)); + NetInfo *rad = ci->getPort(bus("RAD", i)); if (rad != nullptr) { for (int j = 0; j < 4; j++) { IdString port = (j % 2) ? comb1_rad[i] : comb0_rad[i]; combs[j]->addInput(port); - connect_port(ctx, rad, combs[j], port); + combs[j]->connectPort(port, rad); } - disconnect_port(ctx, ci, bus("RAD", i)); + ci->disconnectPort(bus("RAD", i)); } // Write address - internal NetInfo *int_wad = ctx->createNet(ctx->id(stringf("%s$lutram_wad[%d]$", ctx->nameOf(ci), i))); ramw->addOutput(bus_flat("WADO", i)); - connect_port(ctx, int_wad, ramw, bus_flat("WADO", i)); + ramw->connectPort(bus_flat("WADO", i), int_wad); for (int j = 0; j < 4; j++) { combs[j]->addInput(bus_flat("WAD", i)); - connect_port(ctx, int_wad, combs[j], bus_flat("WAD", i)); + combs[j]->connectPort(bus_flat("WAD", i), int_wad); } // Write data - internal NetInfo *int_wd = ctx->createNet(ctx->id(stringf("%s$lutram_wd[%d]$", ctx->nameOf(ci), i))); ramw->addOutput(bus_flat("WDO", i)); - connect_port(ctx, int_wd, ramw, bus_flat("WDO", i)); + ramw->connectPort(bus_flat("WDO", i), int_wd); combs[i]->addInput(id_WDI); - connect_port(ctx, int_wd, combs[i], id_WDI); + combs[i]->connectPort(id_WDI, int_wd); // Write clock and enable - internal combs[i]->addInput(id_WCK); combs[i]->addInput(id_WRE); - connect_port(ctx, int_wck, combs[i], id_WCK); - connect_port(ctx, int_wre, combs[i], id_WRE); + combs[i]->connectPort(id_WCK, int_wck); + combs[i]->connectPort(id_WRE, int_wre); // Remap init val uint64_t split_init = 0; for (int j = 0; j < 16; j++) @@ -1178,7 +1178,7 @@ struct NexusPacker base->params[param.first] = param.second; } for (auto &port : mergee->ports) { - replace_port(mergee, port.first, base, port.first); + mergee->movePortTo(port.first, base, port.first); } ctx->cells.erase(mergee->name); } @@ -1191,13 +1191,13 @@ struct NexusPacker if (ci->type != id_IOLOGIC) continue; CellInfo *iob = nullptr; - NetInfo *di = get_net_or_empty(ci, id_DI); + NetInfo *di = ci->getPort(id_DI); if (di != nullptr && di->driver.cell != nullptr) iob = di->driver.cell; - NetInfo *dout = get_net_or_empty(ci, id_DOUT); + NetInfo *dout = ci->getPort(id_DOUT); if (dout != nullptr && dout->users.size() == 1) iob = dout->users.at(0).cell; - NetInfo *tout = get_net_or_empty(ci, id_TOUT); + NetInfo *tout = ci->getPort(id_TOUT); if (tout != nullptr && tout->users.size() == 1) iob = tout->users.at(0).cell; if (iob == nullptr || @@ -1251,20 +1251,20 @@ struct NexusPacker ctx->createCell(ctx->id(stringf("%s$widefn_comb[%d]$", ctx->nameOf(ci), i)), id_OXIDE_COMB)); for (int i = 0; i < 2; i++) { - replace_port(ci, bus_flat("A", i), combs[i], id_A); - replace_port(ci, bus_flat("B", i), combs[i], id_B); - replace_port(ci, bus_flat("C", i), combs[i], id_C); - replace_port(ci, bus_flat("D", i), combs[i], id_D); + ci->movePortTo(bus_flat("A", i), combs[i], id_A); + ci->movePortTo(bus_flat("B", i), combs[i], id_B); + ci->movePortTo(bus_flat("C", i), combs[i], id_C); + ci->movePortTo(bus_flat("D", i), combs[i], id_D); } - replace_port(ci, id_SEL, combs[0], id_SEL); - replace_port(ci, id_Z, combs[0], id_OFX); + ci->movePortTo(id_SEL, combs[0], id_SEL); + ci->movePortTo(id_Z, combs[0], id_OFX); NetInfo *f1 = ctx->createNet(ctx->id(stringf("%s$widefn_f1$", ctx->nameOf(ci)))); combs[0]->addInput(id_F1); combs[1]->addOutput(id_F); - connect_port(ctx, f1, combs[1], id_F); - connect_port(ctx, f1, combs[0], id_F1); + combs[1]->connectPort(id_F, f1); + combs[0]->connectPort(id_F1, f1); combs[0]->params[id_INIT] = ctx->parse_lattice_param(ci, id_INIT0, 16, 0); combs[1]->params[id_INIT] = ctx->parse_lattice_param(ci, id_INIT1, 16, 0); @@ -1290,7 +1290,7 @@ struct NexusPacker CellInfo *ci = cell.second.get(); if (ci->type != id_CCU2) continue; - if (get_net_or_empty(ci, id_CIN) != nullptr) + if (ci->getPort(id_CIN) != nullptr) continue; roots.push_back(ci); } @@ -1309,16 +1309,16 @@ struct NexusPacker // Rewire LUT ports for (int i = 0; i < 2; i++) { combs[i]->params[id_MODE] = std::string("CCU2"); - replace_port(ci, bus_flat("A", i), combs[i], id_A); - replace_port(ci, bus_flat("B", i), combs[i], id_B); - replace_port(ci, bus_flat("C", i), combs[i], id_C); - replace_port(ci, bus_flat("D", i), combs[i], id_D); - replace_port(ci, bus_flat("S", i), combs[i], id_F); + ci->movePortTo(bus_flat("A", i), combs[i], id_A); + ci->movePortTo(bus_flat("B", i), combs[i], id_B); + ci->movePortTo(bus_flat("C", i), combs[i], id_C); + ci->movePortTo(bus_flat("D", i), combs[i], id_D); + ci->movePortTo(bus_flat("S", i), combs[i], id_F); } // External carry chain - replace_port(ci, id_CIN, combs[0], id_FCI); - replace_port(ci, id_COUT, combs[1], id_FCO); + ci->movePortTo(id_CIN, combs[0], id_FCI); + ci->movePortTo(id_COUT, combs[1], id_FCO); // Copy parameters if (ci->params.count(id_INJECT)) @@ -1330,8 +1330,8 @@ struct NexusPacker NetInfo *int_cy = ctx->createNet(ctx->id(stringf("%s$widefn_int_cy$", ctx->nameOf(ci)))); combs[0]->addOutput(id_FCO); combs[1]->addInput(id_FCI); - connect_port(ctx, int_cy, combs[0], id_FCO); - connect_port(ctx, int_cy, combs[1], id_FCI); + combs[0]->connectPort(id_FCO, int_cy); + combs[1]->connectPort(id_FCI, int_cy); // Relative constraints for (int i = 0; i < 2; i++) { @@ -1355,7 +1355,7 @@ struct NexusPacker ctx->cells.erase(ci->name); // Find next cell in chain, if it exists - NetInfo *fco = get_net_or_empty(combs[1], id_FCO); + NetInfo *fco = combs[1]->getPort(id_FCO); ci = nullptr; if (fco != nullptr) { if (fco->users.size() > 1) @@ -1443,13 +1443,13 @@ struct NexusPacker continue; // Skip pins that are already in use - if (get_net_or_empty(other_cell, bp.pin) != nullptr) + if (other_cell->getPort(bp.pin) != nullptr) continue; // Create the input if it doesn't exist if (!other_cell->ports.count(bp.pin)) other_cell->addInput(bp.pin); // Make the connection - connect_ports(ctx, cell, port.first, other_cell, bp.pin); + cell->connectPorts(port.first, other_cell, bp.pin); if (ctx->debug) log_info(" found %s.%s\n", ctx->nameOf(other_cell), ctx->nameOf(bp.pin)); @@ -1729,31 +1729,31 @@ struct NexusPacker if (mt.wide > 0) { // Dot-product mode special case - copy_bus(ctx, ci, ctx->id(stringf("B%d", (i * 9) / mt.wide)), (i * 9) % mt.wide, true, preadd9[i], - id_B, 0, false, 9); - copy_bus(ctx, ci, ctx->id(stringf("A%d", (i * 9) / mt.wide)), (i * 9) % mt.wide, true, mult9[i], - id_A, 0, false, 9); - copy_port(ctx, ci, id_CLK, mult9[i], id_CLK); - copy_port(ctx, ci, (i > 1) ? id_CEA2A3 : id_CEA0A1, mult9[i], id_CEA); - copy_port(ctx, ci, (i > 1) ? id_RSTA2A3 : id_RSTA0A1, mult9[i], id_RSTA); - copy_port(ctx, ci, id_CLK, preadd9[i], id_CLK); - copy_port(ctx, ci, (i > 1) ? id_CEB2B3 : id_CEB0B1, preadd9[i], id_CEB); - copy_port(ctx, ci, (i > 1) ? id_RSTB2B3 : id_RSTB0B1, preadd9[i], id_RSTB); + ci->copyPortBusTo(ctx->id(stringf("B%d", (i * 9) / mt.wide)), (i * 9) % mt.wide, true, preadd9[i], + id_B, 0, false, 9); + ci->copyPortBusTo(ctx->id(stringf("A%d", (i * 9) / mt.wide)), (i * 9) % mt.wide, true, mult9[i], + id_A, 0, false, 9); + ci->copyPortTo(id_CLK, mult9[i], id_CLK); + ci->copyPortTo((i > 1) ? id_CEA2A3 : id_CEA0A1, mult9[i], id_CEA); + ci->copyPortTo((i > 1) ? id_RSTA2A3 : id_RSTA0A1, mult9[i], id_RSTA); + ci->copyPortTo(id_CLK, preadd9[i], id_CLK); + ci->copyPortTo((i > 1) ? id_CEB2B3 : id_CEB0B1, preadd9[i], id_CEB); + ci->copyPortTo((i > 1) ? id_RSTB2B3 : id_RSTB0B1, preadd9[i], id_RSTB); // Copy register configuration copy_param(ci, ctx->id(stringf("REGINPUTAB%d", i)), mult9[i], id_REGBYPSA1); copy_param(ci, ctx->id(stringf("REGINPUTAB%d", i)), preadd9[i], id_REGBYPSBR0); } else { // B input split across pre-adders - copy_bus(ctx, ci, id_B, b_start, true, preadd9[i], id_B, 0, false, 9); + ci->copyPortBusTo(id_B, b_start, true, preadd9[i], id_B, 0, false, 9); // A input split across MULT9s - copy_bus(ctx, ci, id_A, a_start, true, mult9[i], id_A, 0, false, 9); + ci->copyPortBusTo(id_A, a_start, true, mult9[i], id_A, 0, false, 9); // Connect control set signals - copy_port(ctx, ci, id_CLK, mult9[i], id_CLK); - copy_port(ctx, ci, id_CEA, mult9[i], id_CEA); - copy_port(ctx, ci, id_RSTA, mult9[i], id_RSTA); - copy_port(ctx, ci, id_CLK, preadd9[i], id_CLK); - copy_port(ctx, ci, id_CEB, preadd9[i], id_CEB); - copy_port(ctx, ci, id_RSTB, preadd9[i], id_RSTB); + ci->copyPortTo(id_CLK, mult9[i], id_CLK); + ci->copyPortTo(id_CEA, mult9[i], id_CEA); + ci->copyPortTo(id_RSTA, mult9[i], id_RSTA); + ci->copyPortTo(id_CLK, preadd9[i], id_CLK); + ci->copyPortTo(id_CEB, preadd9[i], id_CEB); + ci->copyPortTo(id_RSTB, preadd9[i], id_RSTB); // Copy register configuration copy_param(ci, id_REGINPUTA, mult9[i], id_REGBYPSA1); copy_param(ci, id_REGINPUTB, preadd9[i], id_REGBYPSBR0); @@ -1761,12 +1761,12 @@ struct NexusPacker // Connect and configure pre-adder if it isn't bypassed if (mt.has_preadd) { - copy_bus(ctx, ci, id_C, 9 * i, true, preadd9[i], id_C, 0, false, 9); + ci->copyPortBusTo(id_C, 9 * i, true, preadd9[i], id_C, 0, false, 9); if (i == (mt.N9x9 - 1)) - copy_port(ctx, ci, id_SIGNEDC, preadd9[i], id_C9); + ci->copyPortTo(id_SIGNEDC, preadd9[i], id_C9); copy_param(ci, id_REGINPUTC, preadd9[i], id_REGBYPSBL); - copy_port(ctx, ci, id_CEC, preadd9[i], id_CECL); - copy_port(ctx, ci, id_RSTC, preadd9[i], id_RSTCL); + ci->copyPortTo(id_CEC, preadd9[i], id_CECL); + ci->copyPortTo(id_RSTC, preadd9[i], id_RSTCL); // Enable preadder preadd9[i]->params[id_BYPASS_PREADD9] = std::string("USED"); preadd9[i]->params[id_OPC] = std::string("INPUT_C_AS_PREADDER_OPERAND"); @@ -1774,14 +1774,14 @@ struct NexusPacker preadd9[i]->params[id_PREADDCAS_EN] = std::string("ENABLED"); } else if (mt.has_addsub) { // Connect only for routeability reasons - copy_bus(ctx, ci, id_C, 10 * i + ((i >= 4) ? 14 : 0), true, preadd9[i], id_C, 0, false, 10); + ci->copyPortBusTo(id_C, 10 * i + ((i >= 4) ? 14 : 0), true, preadd9[i], id_C, 0, false, 10); } // Connect up signedness for the most significant nonet if (((b_start + 9) == mt.b_width) || (mt.wide > 0)) - copy_port(ctx, ci, mt.has_addsub ? id_SIGNED : id_SIGNEDB, preadd9[i], id_BSIGNED); + ci->copyPortTo(mt.has_addsub ? id_SIGNED : id_SIGNEDB, preadd9[i], id_BSIGNED); if (((a_start + 9) == mt.a_width) || (mt.wide > 0)) - copy_port(ctx, ci, mt.has_addsub ? id_SIGNED : id_SIGNEDA, mult9[i], id_ASIGNED); + ci->copyPortTo(mt.has_addsub ? id_SIGNED : id_SIGNEDA, mult9[i], id_ASIGNED); } bool mult36_used = (mt.a_width >= 36) && (mt.b_width >= 36) && !(mt.wide > 0); @@ -1800,11 +1800,11 @@ struct NexusPacker for (int i = 0; i < Nreg18; i++) { // Output split across reg18s if (!mt.has_addsub) - replace_bus(ctx, ci, id_Z, i * 18, true, reg18[i], id_PP, 0, false, 18); + ci->movePortBusTo(id_Z, i * 18, true, reg18[i], id_PP, 0, false, 18); // Connect control set signals - copy_port(ctx, ci, id_CLK, reg18[i], id_CLK); - copy_port(ctx, ci, mt.has_addsub ? id_CEPIPE : id_CEOUT, reg18[i], id_CEP); - copy_port(ctx, ci, mt.has_addsub ? id_RSTPIPE : id_RSTOUT, reg18[i], id_RSTP); + ci->copyPortTo(id_CLK, reg18[i], id_CLK); + ci->copyPortTo(mt.has_addsub ? id_CEPIPE : id_CEOUT, reg18[i], id_CEP); + ci->copyPortTo(mt.has_addsub ? id_RSTPIPE : id_RSTOUT, reg18[i], id_RSTP); // Copy register configuration copy_param(ci, mt.has_addsub ? id_REGPIPELINE : id_REGOUTPUT, reg18[i], id_REGBYPS); } @@ -1817,35 +1817,35 @@ struct NexusPacker acc54[i] = create_dsp_cell(ci->name, id_ACC54_CORE, preadd9[0], (i * 4) + 2, 5); for (int i = 0; i < Nacc54; i++) { // C addsub input - copy_bus(ctx, ci, id_C, 54 * i, true, acc54[i], id_CINPUT, 0, false, 54); + ci->copyPortBusTo(id_C, 54 * i, true, acc54[i], id_CINPUT, 0, false, 54); // Output - replace_bus(ctx, ci, id_Z, i * 54, true, acc54[i], id_SUM0, 0, false, 36); - replace_bus(ctx, ci, id_Z, i * 54 + 36, true, acc54[i], id_SUM1, 0, false, 18); + ci->movePortBusTo(id_Z, i * 54, true, acc54[i], id_SUM0, 0, false, 36); + ci->movePortBusTo(id_Z, i * 54 + 36, true, acc54[i], id_SUM1, 0, false, 18); // Control set - copy_port(ctx, ci, id_CLK, acc54[i], id_CLK); - copy_port(ctx, ci, id_RSTCTRL, acc54[i], id_RSTCTRL); - copy_port(ctx, ci, id_CECTRL, acc54[i], id_CECTRL); - copy_port(ctx, ci, id_RSTCIN, acc54[i], id_RSTCIN); - copy_port(ctx, ci, id_CECIN, acc54[i], id_CECIN); - copy_port(ctx, ci, id_RSTOUT, acc54[i], id_RSTO); - copy_port(ctx, ci, id_CEOUT, acc54[i], id_CEO); - copy_port(ctx, ci, id_RSTC, acc54[i], id_RSTC); - copy_port(ctx, ci, id_CEC, acc54[i], id_CEC); + ci->copyPortTo(id_CLK, acc54[i], id_CLK); + ci->copyPortTo(id_RSTCTRL, acc54[i], id_RSTCTRL); + ci->copyPortTo(id_CECTRL, acc54[i], id_CECTRL); + ci->copyPortTo(id_RSTCIN, acc54[i], id_RSTCIN); + ci->copyPortTo(id_CECIN, acc54[i], id_CECIN); + ci->copyPortTo(id_RSTOUT, acc54[i], id_RSTO); + ci->copyPortTo(id_CEOUT, acc54[i], id_CEO); + ci->copyPortTo(id_RSTC, acc54[i], id_RSTC); + ci->copyPortTo(id_CEC, acc54[i], id_CEC); // Add/acc control if (i == 0) - copy_port(ctx, ci, id_CIN, acc54[i], id_CIN); + ci->copyPortTo(id_CIN, acc54[i], id_CIN); else ctx->set_cell_pinmux(acc54[i], id_CIN, PINMUX_1); if (i == (Nacc54 - 1)) - copy_port(ctx, ci, id_SIGNED, acc54[i], id_SIGNEDI); + ci->copyPortTo(id_SIGNED, acc54[i], id_SIGNEDI); if (mt.wide > 0) { - replace_bus(ctx, ci, id_ADDSUB, 0, true, acc54[i], id_ADDSUB, 0, false, 2); - replace_bus(ctx, ci, id_ADDSUB, 2, true, acc54[i], id_M9ADDSUB, 0, false, 2); + ci->movePortBusTo(id_ADDSUB, 0, true, acc54[i], id_ADDSUB, 0, false, 2); + ci->movePortBusTo(id_ADDSUB, 2, true, acc54[i], id_M9ADDSUB, 0, false, 2); } else { - copy_port(ctx, ci, id_ADDSUB, acc54[i], id_ADDSUB0); - copy_port(ctx, ci, id_ADDSUB, acc54[i], id_ADDSUB1); + ci->copyPortTo(id_ADDSUB, acc54[i], id_ADDSUB0); + ci->copyPortTo(id_ADDSUB, acc54[i], id_ADDSUB1); } - copy_port(ctx, ci, id_LOADC, acc54[i], id_LOAD); + ci->copyPortTo(id_LOADC, acc54[i], id_LOAD); // Configuration copy_param(ci, id_REGINPUTC, acc54[i], id_CREGBYPS1); copy_param(ci, id_REGADDSUB, acc54[i], id_ADDSUBSIGNREGBYPS1); @@ -1881,7 +1881,7 @@ struct NexusPacker for (auto cell : to_remove) { for (auto &port : cell->ports) - disconnect_port(ctx, cell, port.first); + cell->disconnectPort(port.first); ctx->cells.erase(cell->name); } } @@ -2042,9 +2042,9 @@ struct NexusPacker CellInfo *ci = cell.second.get(); if (ci->type == id_PLL_CORE) { // Extra log to phys rules - rename_port(ctx, ci, id_PLLPOWERDOWN_N, id_PLLPDN); - rename_port(ctx, ci, id_LMMIWRRD_N, id_LMMIWRRDN); - rename_port(ctx, ci, id_LMMIRESET_N, id_LMMIRESETN); + ci->renamePort(id_PLLPOWERDOWN_N, id_PLLPDN); + ci->renamePort(id_LMMIWRRD_N, id_LMMIWRRDN); + ci->renamePort(id_LMMIRESET_N, id_LMMIRESETN); for (auto &defparam : pll_defaults) if (!ci->params.count(defparam.first)) ci->params[defparam.first] = defparam.second; @@ -2086,7 +2086,7 @@ struct NexusPacker { // Get the net - NetInfo *net = get_net_or_empty(iob, port); + NetInfo *net = iob->getPort(port); if (net == nullptr) { return nullptr; } @@ -2099,8 +2099,8 @@ struct NexusPacker // Get clock nets of IOLOGIC and the flip-flop if (iol != nullptr) { - NetInfo *iol_c = get_net_or_empty(iol, id_SCLKOUT); - NetInfo *ff_c = get_net_or_empty(ff, id_CLK); + NetInfo *iol_c = iol->getPort(id_SCLKOUT); + NetInfo *ff_c = ff->getPort(id_CLK); // If one of them is floating or it is not the same net then abort if (iol_c == nullptr || ff_c == nullptr) { @@ -2113,8 +2113,8 @@ struct NexusPacker // Get reset nets of IOLOGIC and the flip-flop if (iol != nullptr) { - NetInfo *iol_r = get_net_or_empty(iol, id_LSROUT); - NetInfo *ff_r = get_net_or_empty(ff, id_LSR); + NetInfo *iol_r = iol->getPort(id_LSROUT); + NetInfo *ff_r = ff->getPort(id_LSR); // If one of them is floating or it is not the same net then abort. // But both can be floating. @@ -2155,17 +2155,17 @@ struct NexusPacker bool isODDR = false; CellInfo *iob = nullptr; - NetInfo *di = get_net_or_empty(iol, id_DI); + NetInfo *di = iol->getPort(id_DI); if (di != nullptr && di->driver.cell != nullptr) { iob = di->driver.cell; isIDDR = true; } - NetInfo *dout = get_net_or_empty(iol, id_DOUT); + NetInfo *dout = iol->getPort(id_DOUT); if (dout != nullptr && dout->users.size() == 1) { iob = dout->users.at(0).cell; isODDR = true; } - NetInfo *tout = get_net_or_empty(iol, id_TOUT); + NetInfo *tout = iol->getPort(id_TOUT); if (tout != nullptr && tout->users.size() == 1) { iob = tout->users.at(0).cell; isODDR = true; // FIXME: Not sure @@ -2205,9 +2205,9 @@ struct NexusPacker // same ned as SEIO33_CORE.I. // // - NetInfo *iob_t = get_net_or_empty(iob, id_T); + NetInfo *iob_t = iob->getPort(id_T); if (iob_t != nullptr && isODDR) { - NetInfo *iol_t = get_net_or_empty(iol, id_TOUT); + NetInfo *iol_t = iol->getPort(id_TOUT); // SIOLOGIC.TOUT is not driving SEIO33_CORE.T if ((iol_t == nullptr) || (iol_t != nullptr && iol_t->users.empty()) || @@ -2216,7 +2216,7 @@ struct NexusPacker // In this case if SIOLOGIC.TSDATA0 is not connected // to the same net as SEIO33_CORE.T and is not // floating then that configuration is illegal. - NetInfo *iol_ti = get_net_or_empty(iol, id_TSDATA0); + NetInfo *iol_ti = iol->getPort(id_TSDATA0); if (iol_ti != nullptr && (iol_ti->name != iob_t->name) && (iol_ti->name != gnd_net->name)) { log_error("Cannot have %s.TSDATA0 and %s.T driven by different nets (%s vs. %s)\n", ctx->nameOf(iol), ctx->nameOf(iob), ctx->nameOf(iol_ti), ctx->nameOf(iob_t)); @@ -2227,8 +2227,8 @@ struct NexusPacker if (!iol->ports.count(id_TSDATA0)) { iol->addInput(id_TSDATA0); } - disconnect_port(ctx, iol, id_TSDATA0); - connect_port(ctx, iob_t, iol, id_TSDATA0); + iol->disconnectPort(id_TSDATA0); + iol->connectPort(id_TSDATA0, iob_t); if (ctx->debug) { log_info(" Reconnecting %s.TSDATA0 to %s\n", ctx->nameOf(iol), ctx->nameOf(iob_t)); @@ -2256,10 +2256,10 @@ struct NexusPacker for (auto &it : tff_map) { CellInfo *ff = ctx->cells.at(it.first).get(); - NetInfo *ff_d = get_net_or_empty(ff, id_M); // FIXME: id_D or id_M ?! + NetInfo *ff_d = ff->getPort(id_M); // FIXME: id_D or id_M ?! NPNR_ASSERT(ff_d != nullptr); - NetInfo *ff_q = get_net_or_empty(ff, id_Q); + NetInfo *ff_q = ff->getPort(id_Q); NPNR_ASSERT(ff_q != nullptr); for (auto &ios : it.second) { @@ -2269,12 +2269,12 @@ struct NexusPacker log_info(" Integrating %s into %s\n", ctx->nameOf(ff), ctx->nameOf(iol)); // Disconnect "old" T net - disconnect_port(ctx, iol, id_TSDATA0); - disconnect_port(ctx, iob, id_T); + iol->disconnectPort(id_TSDATA0); + iob->disconnectPort(id_T); // Connect the "new" one - connect_port(ctx, ff_d, iol, id_TSDATA0); - connect_port(ctx, ff_d, iob, id_T); + iol->connectPort(id_TSDATA0, ff_d); + iob->connectPort(id_T, ff_d); // Propagate parameters iol->params[id_SRMODE] = ff->params.at(id_SRMODE); @@ -2288,7 +2288,7 @@ struct NexusPacker // Disconnect the flip-flop for (auto &port : ff->ports) { - disconnect_port(ctx, ff, port.first); + ff->disconnectPort(port.first); } // Check if the flip-flop can be removed @@ -2316,9 +2316,9 @@ struct NexusPacker ctrlset.clkmux = ctx->id(str_or_default(cell->params, id_CLKMUX, "CLK")).index; ctrlset.cemux = ctx->id(str_or_default(cell->params, id_CEMUX, "CE")).index; ctrlset.lsrmux = ctx->id(str_or_default(cell->params, id_LSRMUX, "LSR")).index; - ctrlset.clk = get_net_or_empty(cell, id_CLK); - ctrlset.ce = get_net_or_empty(cell, id_CE); - ctrlset.lsr = get_net_or_empty(cell, id_LSR); + ctrlset.clk = cell->getPort(id_CLK); + ctrlset.ce = cell->getPort(id_CE); + ctrlset.lsr = cell->getPort(id_LSR); return ctrlset; } @@ -2353,7 +2353,7 @@ struct NexusPacker // Get input net // At the packing stage all inputs go to M - NetInfo *di = get_net_or_empty(ff, id_M); + NetInfo *di = ff->getPort(id_M); if (di == nullptr || di->driver.cell == nullptr) { continue; } @@ -2373,7 +2373,7 @@ struct NexusPacker } // The FF must not use M and DI at the same time - if (get_net_or_empty(ff, id_DI)) { + if (ff->getPort(id_DI)) { continue; } @@ -2445,7 +2445,7 @@ struct NexusPacker } // Reconnect M to DI - rename_port(ctx, ff, id_M, id_DI); + ff->renamePort(id_M, id_DI); ff->params[id_SEL] = std::string("DL"); // Store FF settings of the cluster @@ -2528,8 +2528,8 @@ void Arch::assignCellInfo(CellInfo *cell) cell->lutInfo.is_memory = str_or_default(cell->params, id_MODE, "LOGIC") == "DPRAM"; cell->lutInfo.is_carry = str_or_default(cell->params, id_MODE, "LOGIC") == "CCU2"; cell->lutInfo.mux2_used = port_used(cell, id_OFX); - cell->lutInfo.f = get_net_or_empty(cell, id_F); - cell->lutInfo.ofx = get_net_or_empty(cell, id_OFX); + cell->lutInfo.f = cell->getPort(id_F); + cell->lutInfo.ofx = cell->getPort(id_OFX); if (cell->lutInfo.is_carry) { cell->tmg_portmap[id_A] = id_A0; cell->tmg_portmap[id_B] = id_B0; @@ -2551,11 +2551,11 @@ void Arch::assignCellInfo(CellInfo *cell) cell->ffInfo.ctrlset.clkmux = id(str_or_default(cell->params, id_CLKMUX, "CLK")).index; cell->ffInfo.ctrlset.cemux = id(str_or_default(cell->params, id_CEMUX, "CE")).index; cell->ffInfo.ctrlset.lsrmux = id(str_or_default(cell->params, id_LSRMUX, "LSR")).index; - cell->ffInfo.ctrlset.clk = get_net_or_empty(cell, id_CLK); - cell->ffInfo.ctrlset.ce = get_net_or_empty(cell, id_CE); - cell->ffInfo.ctrlset.lsr = get_net_or_empty(cell, id_LSR); - cell->ffInfo.di = get_net_or_empty(cell, id_DI); - cell->ffInfo.m = get_net_or_empty(cell, id_M); + cell->ffInfo.ctrlset.clk = cell->getPort(id_CLK); + cell->ffInfo.ctrlset.ce = cell->getPort(id_CE); + cell->ffInfo.ctrlset.lsr = cell->getPort(id_LSR); + cell->ffInfo.di = cell->getPort(id_DI); + cell->ffInfo.m = cell->getPort(id_M); cell->tmg_index = get_cell_timing_idx(id_OXIDE_FF, id("PPP:SYNC")); } else if (cell->type == id_RAMW) { cell->ffInfo.ctrlset.async = true; @@ -2564,9 +2564,9 @@ void Arch::assignCellInfo(CellInfo *cell) cell->ffInfo.ctrlset.clkmux = id(str_or_default(cell->params, id_CLKMUX, "CLK")).index; cell->ffInfo.ctrlset.cemux = ID_CE; cell->ffInfo.ctrlset.lsrmux = ID_INV; - cell->ffInfo.ctrlset.clk = get_net_or_empty(cell, id_CLK); + cell->ffInfo.ctrlset.clk = cell->getPort(id_CLK); cell->ffInfo.ctrlset.ce = nullptr; - cell->ffInfo.ctrlset.lsr = get_net_or_empty(cell, id_LSR); + cell->ffInfo.ctrlset.lsr = cell->getPort(id_LSR); cell->ffInfo.di = nullptr; cell->ffInfo.m = nullptr; cell->tmg_index = get_cell_timing_idx(id_RAMW); diff --git a/nexus/post_place.cc b/nexus/post_place.cc index f42c0f18..289f82b2 100644 --- a/nexus/post_place.cc +++ b/nexus/post_place.cc @@ -94,12 +94,12 @@ struct NexusPostPlaceOpt if (ff->type != id_OXIDE_FF) continue; // Check M ('fabric') input net - NetInfo *m = get_net_or_empty(ff, id_M); + NetInfo *m = ff->getPort(id_M); if (m == nullptr) continue; // Ignore FFs that need both DI and M (PRLD mode) - if (get_net_or_empty(ff, id_DI) != nullptr) + if (ff->getPort(id_DI) != nullptr) continue; const auto &drv = m->driver; @@ -118,7 +118,7 @@ struct NexusPostPlaceOpt if (dest_ff != ff->bel) { // If dest_ff is already placed *and* using direct 'DI' input, don't touch it CellInfo *dest_ff_cell = ctx->getBoundBelCell(dest_ff); - if (dest_ff_cell != nullptr && get_net_or_empty(dest_ff_cell, id_DI) != nullptr) + if (dest_ff_cell != nullptr && dest_ff_cell->getPort(id_DI) != nullptr) continue; // Attempt the swap bool swap_result = swap_cell_placement(ff, dest_ff); @@ -126,7 +126,7 @@ struct NexusPostPlaceOpt continue; } // Use direct interconnect - rename_port(ctx, ff, id_M, id_DI); + ff->renamePort(id_M, id_DI); ff->params[id_SEL] = std::string("DL"); ++moves_made; continue; |