ecp5: Trim IO connected to top level ports
Signed-off-by: David Shah <dave@ds0.me>
This commit is contained in:
parent
e9fe444dc7
commit
36178a5713
86
ecp5/pack.cc
86
ecp5/pack.cc
@ -235,6 +235,43 @@ class Ecp5Packer
|
||||
}
|
||||
}
|
||||
|
||||
// Return true if an port is a top level port that provides its own IOBUF
|
||||
bool is_top_port(PortRef &port) {
|
||||
if (port.cell == nullptr)
|
||||
return false;
|
||||
if (port.cell->type == id_DCUA) {
|
||||
return port.port == id_CH0_HDINP || port.port == id_CH0_HDINN || port.port == id_CH0_HDOUTP ||
|
||||
port.port == id_CH0_HDOUTN ||
|
||||
port.port == id_CH1_HDINP || port.port == id_CH1_HDINN || port.port == id_CH1_HDOUTP ||
|
||||
port.port == id_CH1_HDOUTN;
|
||||
} else if (port.cell->type == id_EXTREFB) {
|
||||
return port.port == id_REFCLKP || port.port == id_REFCLKN;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Return true if a net only drives a top port
|
||||
bool drives_top_port(NetInfo *net, PortRef &tp) {
|
||||
if (net == nullptr)
|
||||
return false;
|
||||
for (auto user : net->users) {
|
||||
if (is_top_port(user)) {
|
||||
if (net->users.size() > 1)
|
||||
log_error(" port %s.%s must be connected to (and only to) a top level pin\n", user.cell->name.c_str(ctx), user.port.c_str(ctx));
|
||||
tp = user;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (net->driver.cell != nullptr && is_top_port(net->driver)) {
|
||||
if (net->users.size() > 1)
|
||||
log_error(" port %s.%s must be connected to (and only to) a top level pin\n", net->driver.cell->name.c_str(ctx), net->driver.port.c_str(ctx));
|
||||
tp = net->driver;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Simple "packer" to remove nextpnr IOBUFs, this assumes IOBUFs are manually instantiated
|
||||
void pack_io()
|
||||
{
|
||||
@ -244,10 +281,14 @@ class Ecp5Packer
|
||||
CellInfo *ci = cell.second;
|
||||
if (is_nextpnr_iob(ctx, ci)) {
|
||||
CellInfo *trio = nullptr;
|
||||
NetInfo *ionet = nullptr;
|
||||
PortRef tp;
|
||||
if (ci->type == ctx->id("$nextpnr_ibuf") || ci->type == ctx->id("$nextpnr_iobuf")) {
|
||||
trio = net_only_drives(ctx, ci->ports.at(ctx->id("O")).net, is_trellis_io, ctx->id("B"), true, ci);
|
||||
ionet = ci->ports.at(ctx->id("O")).net;
|
||||
trio = net_only_drives(ctx, ionet, is_trellis_io, ctx->id("B"), true, ci);
|
||||
|
||||
} else if (ci->type == ctx->id("$nextpnr_obuf")) {
|
||||
ionet = ci->ports.at(ctx->id("I")).net;
|
||||
trio = net_only_drives(ctx, ci->ports.at(ctx->id("I")).net, is_trellis_io, ctx->id("B"), true, ci);
|
||||
}
|
||||
if (trio != nullptr) {
|
||||
@ -266,6 +307,20 @@ class Ecp5Packer
|
||||
ctx->nets.erase(net2->name);
|
||||
}
|
||||
}
|
||||
} else if (drives_top_port(ionet, tp)) {
|
||||
log_info("%s feeds %s %s.%s, removing %s %s.\n", ci->name.c_str(ctx), tp.cell->type.c_str(ctx), tp.cell->name.c_str(ctx),
|
||||
tp.port.c_str(ctx),
|
||||
ci->type.c_str(ctx), ci->name.c_str(ctx));
|
||||
if (ionet != nullptr) {
|
||||
ctx->nets.erase(ionet->name);
|
||||
tp.cell->ports.at(tp.port).net = nullptr;
|
||||
}
|
||||
if (ci->type == ctx->id("$nextpnr_iobuf")) {
|
||||
NetInfo *net2 = ci->ports.at(ctx->id("I")).net;
|
||||
if (net2 != nullptr) {
|
||||
ctx->nets.erase(net2->name);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Create a TRELLIS_IO buffer
|
||||
std::unique_ptr<CellInfo> tr_cell =
|
||||
@ -276,22 +331,25 @@ class Ecp5Packer
|
||||
}
|
||||
|
||||
packed_cells.insert(ci->name);
|
||||
for (const auto &attr : ci->attrs)
|
||||
trio->attrs[attr.first] = attr.second;
|
||||
if (trio != nullptr) {
|
||||
for (const auto &attr : ci->attrs)
|
||||
trio->attrs[attr.first] = attr.second;
|
||||
|
||||
auto loc_attr = trio->attrs.find(ctx->id("LOC"));
|
||||
if (loc_attr != trio->attrs.end()) {
|
||||
std::string pin = loc_attr->second;
|
||||
BelId pinBel = ctx->getPackagePinBel(pin);
|
||||
if (pinBel == BelId()) {
|
||||
log_error("IO pin '%s' constrained to pin '%s', which does not exist for package '%s'.\n",
|
||||
trio->name.c_str(ctx), pin.c_str(), ctx->args.package.c_str());
|
||||
} else {
|
||||
log_info("pin '%s' constrained to Bel '%s'.\n", trio->name.c_str(ctx),
|
||||
ctx->getBelName(pinBel).c_str(ctx));
|
||||
auto loc_attr = trio->attrs.find(ctx->id("LOC"));
|
||||
if (loc_attr != trio->attrs.end()) {
|
||||
std::string pin = loc_attr->second;
|
||||
BelId pinBel = ctx->getPackagePinBel(pin);
|
||||
if (pinBel == BelId()) {
|
||||
log_error("IO pin '%s' constrained to pin '%s', which does not exist for package '%s'.\n",
|
||||
trio->name.c_str(ctx), pin.c_str(), ctx->args.package.c_str());
|
||||
} else {
|
||||
log_info("pin '%s' constrained to Bel '%s'.\n", trio->name.c_str(ctx),
|
||||
ctx->getBelName(pinBel).c_str(ctx));
|
||||
}
|
||||
trio->attrs[ctx->id("BEL")] = ctx->getBelName(pinBel).str(ctx);
|
||||
}
|
||||
trio->attrs[ctx->id("BEL")] = ctx->getBelName(pinBel).str(ctx);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
flush_cells();
|
||||
|
Loading…
Reference in New Issue
Block a user