aboutsummaryrefslogtreecommitdiffstats
path: root/nexus/pack.cc
diff options
context:
space:
mode:
authorDavid Shah <dave@ds0.me>2020-10-12 11:41:26 +0100
committerDavid Shah <dave@ds0.me>2020-11-30 08:45:27 +0000
commit518ead2e2dd11ba3bcd19085c2c91178ba9e458c (patch)
treea72fa90ff7db0a19ed383349166a78d32a7c700e /nexus/pack.cc
parent69b449c8759efa15f52add21b1c7f6dc1ceada3a (diff)
downloadnextpnr-518ead2e2dd11ba3bcd19085c2c91178ba9e458c.tar.gz
nextpnr-518ead2e2dd11ba3bcd19085c2c91178ba9e458c.tar.bz2
nextpnr-518ead2e2dd11ba3bcd19085c2c91178ba9e458c.zip
nexus: IO pre-packing
Signed-off-by: David Shah <dave@ds0.me>
Diffstat (limited to 'nexus/pack.cc')
-rw-r--r--nexus/pack.cc58
1 files changed, 58 insertions, 0 deletions
diff --git a/nexus/pack.cc b/nexus/pack.cc
index 688d74ab..3b53ea55 100644
--- a/nexus/pack.cc
+++ b/nexus/pack.cc
@@ -473,6 +473,64 @@ struct NexusPacker
}
}
+ void prepare_io()
+ {
+ // Find the actual IO buffer corresponding to a port; and copy attributes across to it
+ // Note that this relies on Yosys to do IO buffer inference, to match vendor tooling behaviour
+ // In all cases the nextpnr-inserted IO buffers are removed as redundant.
+ for (auto &port : sorted_ref(ctx->ports)) {
+ if (!ctx->cells.count(port.first))
+ log_error("Port '%s' doesn't seem to have a corresponding top level IO\n", ctx->nameOf(port.first));
+ CellInfo *ci = ctx->cells.at(port.first).get();
+
+ PortRef top_port;
+ top_port.cell = nullptr;
+ bool is_npnr_iob = false;
+
+ 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);
+ if (o == nullptr)
+ ;
+ else if (o->users.size() > 1)
+ log_error("Top level '%s' has multiple input buffers\n", ctx->nameOf(port.first));
+ else if (o->users.size() == 1)
+ top_port = o->users.at(0);
+ }
+ 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);
+ if (i == nullptr && i->driver.cell != nullptr) {
+ if (top_port.cell != nullptr)
+ log_error("Top level '%s' has multiple input/output buffers\n", ctx->nameOf(port.first));
+ top_port = i->driver;
+ }
+ }
+ if (!is_npnr_iob)
+ log_error("Port '%s' doesn't seem to have a corresponding top level IO (internal cell type mismatch)\n",
+ ctx->nameOf(port.first));
+
+ if (top_port.cell == nullptr) {
+ log_info("Trimming port '%s' as it is unused.\n", ctx->nameOf(port.first));
+ } else {
+ // Copy attributes to real IO buffer
+ if (ctx->io_attr.count(port.first)) {
+ for (auto &kv : ctx->io_attr.at(port.first)) {
+ top_port.cell->attrs[kv.first] = kv.second;
+ }
+ }
+ // Make sure that top level net is set correctly
+ 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);
+ ctx->cells.erase(port.first);
+ }
+ }
+
void pack_io()
{
for (auto cell : sorted(ctx->cells)) {