From 36178a571354302cfb3166f7bf83f91cf754ef70 Mon Sep 17 00:00:00 2001 From: David Shah Date: Fri, 9 Nov 2018 15:17:26 +0000 Subject: ecp5: Trim IO connected to top level ports Signed-off-by: David Shah --- ecp5/pack.cc | 88 +++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 73 insertions(+), 15 deletions(-) (limited to 'ecp5') 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 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(); -- cgit v1.2.3