aboutsummaryrefslogtreecommitdiffstats
path: root/ecp5/pack.cc
diff options
context:
space:
mode:
authorDavid Shah <dave@ds0.me>2018-11-09 15:17:26 +0000
committerDavid Shah <dave@ds0.me>2018-11-15 11:30:27 +0000
commit36178a571354302cfb3166f7bf83f91cf754ef70 (patch)
tree01d2413f75e2910199a8fc6da0a94ceb4a497aac /ecp5/pack.cc
parente9fe444dc7dd5bf09f50ef6c742a637f6bc24f41 (diff)
downloadnextpnr-36178a571354302cfb3166f7bf83f91cf754ef70.tar.gz
nextpnr-36178a571354302cfb3166f7bf83f91cf754ef70.tar.bz2
nextpnr-36178a571354302cfb3166f7bf83f91cf754ef70.zip
ecp5: Trim IO connected to top level ports
Signed-off-by: David Shah <dave@ds0.me>
Diffstat (limited to 'ecp5/pack.cc')
-rw-r--r--ecp5/pack.cc88
1 files changed, 73 insertions, 15 deletions
diff --git a/ecp5/pack.cc b/ecp5/pack.cc
index 66428e95..ab31a8f3 100644
--- a/ecp5/pack.cc
+++ b/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;
-
- 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));
+ 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));
+ }
+ trio->attrs[ctx->id("BEL")] = ctx->getBelName(pinBel).str(ctx);
}
- trio->attrs[ctx->id("BEL")] = ctx->getBelName(pinBel).str(ctx);
}
+
}
}
flush_cells();