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 <gatecat@ds0.me>
This commit is contained in:
gatecat 2021-02-10 12:28:40 +00:00
parent 85bb108ba4
commit 535723f414
6 changed files with 85 additions and 39 deletions

View File

@ -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<WireId, 2> 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<WireId, 2>(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<WireId, 2> 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;
delay += getPipDelay(pip).maxDelay();
delay += getWireDelay(cursor).maxDelay();
cursor = getPipSrcWire(pip);
}
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
}
if (cursor == src_wire)
return delay + getWireDelay(src_wire).maxDelay();
return predictDelay(net_info, user_info);
return max_delay;
}
static uint32_t xorshift32(uint32_t x)

View File

@ -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<WireId, 2> 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

View File

@ -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<WireId, int> 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;

View File

@ -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<WireId> 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;

View File

@ -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)));

View File

@ -53,7 +53,7 @@ struct NexusGlobalRouter
// Lookup source and destination wires
WireId src = ctx->getNetinfoSourceWire(net);
WireId dst = ctx->getNetinfoSinkWire(net, net->users.at(user_idx));
WireId dst = ctx->getNetinfoSinkWire(net, net->users.at(user_idx), 0);
if (src == WireId())
log_error("Net '%s' has an invalid source port %s.%s\n", ctx->nameOf(net), ctx->nameOf(net->driver.cell),