From 535723f414a77eb4aa43b794627bbd4aca56f6f0 Mon Sep 17 00:00:00 2001 From: gatecat Date: Wed, 10 Feb 2021 12:28:40 +0000 Subject: Start making use of getBelPinsForCellPin API This replaces getNetinfoSinkWire with 3 new functions for different use cases. At the moment all existing code has been moved to getNetinfoSinkWire with phys_idx=0 so the build doesn't break; but this won't yet function properly with more than one sink. But it provides a base on which to work on refactoring the routers to support this case. Signed-off-by: gatecat --- common/nextpnr.cc | 92 ++++++++++++++++++++++++++++++++++++++++--------------- common/nextpnr.h | 4 ++- common/router1.cc | 10 +++--- common/router2.cc | 12 ++++---- common/timing.cc | 2 +- 5 files changed, 83 insertions(+), 37 deletions(-) (limited to 'common') diff --git a/common/nextpnr.cc b/common/nextpnr.cc index 880e0344..11acf991 100644 --- a/common/nextpnr.cc +++ b/common/nextpnr.cc @@ -354,19 +354,59 @@ WireId Context::getNetinfoSourceWire(const NetInfo *net_info) const if (src_bel == BelId()) return WireId(); - IdString driver_port = net_info->driver.port; - return getBelPinWire(src_bel, driver_port); + auto bel_pins = getBelPinsForCellPin(net_info->driver.cell, net_info->driver.port); + auto iter = bel_pins.begin(); + if (iter == bel_pins.end()) + return WireId(); + WireId driver = getBelPinWire(src_bel, *iter); + ++iter; + NPNR_ASSERT(iter == bel_pins.end()); // assert there is only one driver bel pin; + return driver; } -WireId Context::getNetinfoSinkWire(const NetInfo *net_info, const PortRef &user_info) const +SSOArray Context::getNetinfoSinkWires(const NetInfo *net_info, const PortRef &user_info) const { auto dst_bel = user_info.cell->bel; - if (dst_bel == BelId()) - return WireId(); + return SSOArray(0, WireId()); + size_t bel_pin_count = 0; + // We use an SSOArray here because it avoids any heap allocation for the 99.9% case of 1 or 2 sink wires + // but as SSOArray doesn't (currently) support resizing to keep things simple it does mean we have to do + // two loops + for (auto s : getBelPinsForCellPin(user_info.cell, user_info.port)) { + (void)s; // unused + ++bel_pin_count; + } + SSOArray result(bel_pin_count, WireId()); + bel_pin_count = 0; + for (auto pin : getBelPinsForCellPin(user_info.cell, user_info.port)) { + result[bel_pin_count++] = getBelPinWire(dst_bel, pin); + } + return result; +} - IdString user_port = user_info.port; - return getBelPinWire(dst_bel, user_port); +size_t Context::getNetinfoSinkWireCount(const NetInfo *net_info, const PortRef &sink) const +{ + size_t count = 0; + for (auto s : getNetinfoSinkWires(net_info, sink)) { + (void)s; // unused + ++count; + } + return count; +} + +WireId Context::getNetinfoSinkWire(const NetInfo *net_info, const PortRef &sink, size_t phys_idx) const +{ + size_t count = 0; + for (auto s : getNetinfoSinkWires(net_info, sink)) { + if (count == phys_idx) + return s; + ++count; + } + /* TODO: This should be an assertion failure, but for the zero-wire case of unplaced sinks; legacy code currently + assumes WireId Remove once the refactoring process is complete. + */ + return WireId(); } delay_t Context::getNetinfoRouteDelay(const NetInfo *net_info, const PortRef &user_info) const @@ -383,29 +423,33 @@ delay_t Context::getNetinfoRouteDelay(const NetInfo *net_info, const PortRef &us if (src_wire == WireId()) return 0; - WireId dst_wire = getNetinfoSinkWire(net_info, user_info); - WireId cursor = dst_wire; - delay_t delay = 0; + delay_t max_delay = 0; - while (cursor != WireId() && cursor != src_wire) { - auto it = net_info->wires.find(cursor); + for (auto dst_wire : getNetinfoSinkWires(net_info, user_info)) { + WireId cursor = dst_wire; + delay_t delay = 0; - if (it == net_info->wires.end()) - break; + while (cursor != WireId() && cursor != src_wire) { + auto it = net_info->wires.find(cursor); - PipId pip = it->second.pip; - if (pip == PipId()) - break; + if (it == net_info->wires.end()) + break; - delay += getPipDelay(pip).maxDelay(); - delay += getWireDelay(cursor).maxDelay(); - cursor = getPipSrcWire(pip); - } + PipId pip = it->second.pip; + if (pip == PipId()) + break; - if (cursor == src_wire) - return delay + getWireDelay(src_wire).maxDelay(); + delay += getPipDelay(pip).maxDelay(); + delay += getWireDelay(cursor).maxDelay(); + cursor = getPipSrcWire(pip); + } - return predictDelay(net_info, user_info); + if (cursor == src_wire) + max_delay = std::max(max_delay, delay + getWireDelay(src_wire).maxDelay()); // routed + else + max_delay = std::max(max_delay, predictDelay(net_info, user_info)); // unrouted + } + return max_delay; } static uint32_t xorshift32(uint32_t x) diff --git a/common/nextpnr.h b/common/nextpnr.h index cf04f831..cb4dbc28 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -1494,7 +1494,9 @@ struct Context : Arch, DeterministicRNG // -------------------------------------------------------------- WireId getNetinfoSourceWire(const NetInfo *net_info) const; - WireId getNetinfoSinkWire(const NetInfo *net_info, const PortRef &sink) const; + SSOArray getNetinfoSinkWires(const NetInfo *net_info, const PortRef &sink) const; + size_t getNetinfoSinkWireCount(const NetInfo *net_info, const PortRef &sink) const; + WireId getNetinfoSinkWire(const NetInfo *net_info, const PortRef &sink, size_t phys_idx) const; delay_t getNetinfoRouteDelay(const NetInfo *net_info, const PortRef &sink) const; // provided by router1.cc diff --git a/common/router1.cc b/common/router1.cc index d2816c1e..51a356bc 100644 --- a/common/router1.cc +++ b/common/router1.cc @@ -144,7 +144,7 @@ struct Router1 int user_idx = arc.user_idx; auto src_wire = ctx->getNetinfoSourceWire(net_info); - auto dst_wire = ctx->getNetinfoSinkWire(net_info, net_info->users[user_idx]); + auto dst_wire = ctx->getNetinfoSinkWire(net_info, net_info->users[user_idx], 0); arc_queue_insert(arc, src_wire, dst_wire); } @@ -302,7 +302,7 @@ struct Router1 log_assert(src_wire != WireId()); for (int user_idx = 0; user_idx < int(net_info->users.size()); user_idx++) { - auto dst_wire = ctx->getNetinfoSinkWire(net_info, net_info->users[user_idx]); + auto dst_wire = ctx->getNetinfoSinkWire(net_info, net_info->users[user_idx], 0); log_assert(dst_wire != WireId()); arc_key arc; @@ -375,7 +375,7 @@ struct Router1 ctx->nameOf(dst_to_arc.at(src_wire).net_info), dst_to_arc.at(src_wire).user_idx); for (int user_idx = 0; user_idx < int(net_info->users.size()); user_idx++) { - auto dst_wire = ctx->getNetinfoSinkWire(net_info, net_info->users[user_idx]); + auto dst_wire = ctx->getNetinfoSinkWire(net_info, net_info->users[user_idx], 0); if (dst_wire == WireId()) log_error("No wire found for port %s on destination cell %s.\n", @@ -443,7 +443,7 @@ struct Router1 int user_idx = arc.user_idx; auto src_wire = ctx->getNetinfoSourceWire(net_info); - auto dst_wire = ctx->getNetinfoSinkWire(net_info, net_info->users[user_idx]); + auto dst_wire = ctx->getNetinfoSinkWire(net_info, net_info->users[user_idx], 0); ripup_flag = false; if (ctx->debug) { @@ -934,7 +934,7 @@ bool Context::checkRoutedDesign() const std::unordered_map dest_wires; for (int user_idx = 0; user_idx < int(net_info->users.size()); user_idx++) { - auto dst_wire = ctx->getNetinfoSinkWire(net_info, net_info->users[user_idx]); + auto dst_wire = ctx->getNetinfoSinkWire(net_info, net_info->users[user_idx], 0); log_assert(dst_wire != WireId()); dest_wires[dst_wire] = user_idx; diff --git a/common/router2.cc b/common/router2.cc index 49d5fdec..d1e4e347 100644 --- a/common/router2.cc +++ b/common/router2.cc @@ -150,7 +150,7 @@ struct Router2 for (size_t j = 0; j < ni->users.size(); j++) { auto &usr = ni->users.at(j); - WireId src_wire = ctx->getNetinfoSourceWire(ni), dst_wire = ctx->getNetinfoSinkWire(ni, usr); + WireId src_wire = ctx->getNetinfoSourceWire(ni), dst_wire = ctx->getNetinfoSinkWire(ni, usr, 0); nets.at(i).src_wire = src_wire; if (ni->driver.cell == nullptr) src_wire = dst_wire; @@ -405,7 +405,7 @@ struct Router2 void reserve_wires_for_arc(NetInfo *net, size_t i) { WireId src = ctx->getNetinfoSourceWire(net); - WireId sink = ctx->getNetinfoSinkWire(net, net->users.at(i)); + WireId sink = ctx->getNetinfoSinkWire(net, net->users.at(i), 0); if (sink == WireId()) return; std::unordered_set rsv; @@ -479,7 +479,7 @@ struct Router2 auto &usr = net->users.at(i); ROUTE_LOG_DBG("Routing arc %d of net '%s' (%d, %d) -> (%d, %d)\n", int(i), ctx->nameOf(net), ad.bb.x0, ad.bb.y0, ad.bb.x1, ad.bb.y1); - WireId src_wire = ctx->getNetinfoSourceWire(net), dst_wire = ctx->getNetinfoSinkWire(net, usr); + WireId src_wire = ctx->getNetinfoSourceWire(net), dst_wire = ctx->getNetinfoSinkWire(net, usr, 0); if (src_wire == WireId()) ARC_LOG_ERR("No wire found for port %s on source cell %s.\n", ctx->nameOf(net->driver.port), ctx->nameOf(net->driver.cell)); @@ -726,7 +726,7 @@ struct Router2 if (check_arc_routing(net, i)) continue; auto &usr = net->users.at(i); - WireId dst_wire = ctx->getNetinfoSinkWire(net, usr); + WireId dst_wire = ctx->getNetinfoSinkWire(net, usr, 0); // Case of arcs that were pre-routed strongly (e.g. clocks) if (net->wires.count(dst_wire) && net->wires.at(dst_wire).strength > STRENGTH_STRONG) return ARC_SUCCESS; @@ -751,7 +751,7 @@ struct Router2 if (res2 != ARC_SUCCESS) log_error("Failed to route arc %d of net '%s', from %s to %s.\n", int(i), ctx->nameOf(net), ctx->nameOfWire(ctx->getNetinfoSourceWire(net)), - ctx->nameOfWire(ctx->getNetinfoSinkWire(net, net->users.at(i)))); + ctx->nameOfWire(ctx->getNetinfoSinkWire(net, net->users.at(i), 0))); } } } @@ -803,7 +803,7 @@ struct Router2 // Skip routes with no source if (src == WireId()) return true; - WireId dst = ctx->getNetinfoSinkWire(net, usr); + WireId dst = ctx->getNetinfoSinkWire(net, usr, 0); // Skip routes where the destination is already bound if (dst == WireId() || ctx->getBoundWireNet(dst) == net) return true; diff --git a/common/timing.cc b/common/timing.cc index 9fb14a33..a741c6ee 100644 --- a/common/timing.cc +++ b/common/timing.cc @@ -869,7 +869,7 @@ void timing_analysis(Context *ctx, bool print_histogram, bool print_fmax, bool p log_info(" Sink %s.%s\n", sink_cell->name.c_str(ctx), sink->port.c_str(ctx)); if (ctx->verbose) { auto driver_wire = ctx->getNetinfoSourceWire(net); - auto sink_wire = ctx->getNetinfoSinkWire(net, *sink); + auto sink_wire = ctx->getNetinfoSinkWire(net, *sink, 0); log_info(" prediction: %f ns estimate: %f ns\n", ctx->getDelayNS(ctx->predictDelay(net, *sink)), ctx->getDelayNS(ctx->estimateDelay(driver_wire, sink_wire))); -- cgit v1.2.3