refactor: New member functions to replace design_utils

Signed-off-by: gatecat <gatecat@ds0.me>
This commit is contained in:
gatecat 2022-02-18 10:52:37 +00:00
parent 61d1db16be
commit 6a32aca4ac
34 changed files with 764 additions and 767 deletions

View File

@ -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)

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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");

View File

@ -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);

View File

@ -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);
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);
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("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) {

View File

@ -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));

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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)

View File

@ -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 =

View File

@ -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);
}
}
}

View File

@ -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)

View File

@ -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);

View File

@ -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);
}

View File

@ -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);

View File

@ -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";

View File

@ -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)

View File

@ -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

View File

@ -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);
}
}

View File

@ -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

View File

@ -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 {

View File

@ -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

View File

@ -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)));
}
}

View File

@ -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;

View File

@ -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);

View File

@ -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;