diff options
author | gatecat <gatecat@ds0.me> | 2021-02-10 14:43:49 +0000 |
---|---|---|
committer | gatecat <gatecat@ds0.me> | 2021-02-10 15:14:44 +0000 |
commit | 7c7d69e1d2030dc983d0ddbc0e04f6765d51bbbc (patch) | |
tree | e01f2194626c7032124fcd2902f4c655b1b13aa6 /common | |
parent | 7dafc64f78270ec37e2155c609da7cbf2ae18028 (diff) | |
download | nextpnr-7c7d69e1d2030dc983d0ddbc0e04f6765d51bbbc.tar.gz nextpnr-7c7d69e1d2030dc983d0ddbc0e04f6765d51bbbc.tar.bz2 nextpnr-7c7d69e1d2030dc983d0ddbc0e04f6765d51bbbc.zip |
router2: Support for multiple bel pins per cell pin
Signed-off-by: gatecat <gatecat@ds0.me>
Diffstat (limited to 'common')
-rw-r--r-- | common/router2.cc | 180 |
1 files changed, 95 insertions, 85 deletions
diff --git a/common/router2.cc b/common/router2.cc index d1e4e347..a2023f47 100644 --- a/common/router2.cc +++ b/common/router2.cc @@ -58,7 +58,7 @@ struct Router2 struct PerNetData { WireId src_wire; - std::vector<PerArcData> arcs; + std::vector<std::vector<PerArcData>> arcs; ArcBounds bb; // Coordinates of the center of the net, used for the weight-to-average int cx, cy, hpwl; @@ -150,26 +150,30 @@ 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, 0); - nets.at(i).src_wire = src_wire; - if (ni->driver.cell == nullptr) - src_wire = dst_wire; - if (ni->driver.cell == nullptr && dst_wire == WireId()) - continue; - if (src_wire == WireId()) - log_error("No wire found for port %s on source cell %s.\n", ctx->nameOf(ni->driver.port), - ctx->nameOf(ni->driver.cell)); - if (dst_wire == WireId()) - log_error("No wire found for port %s on destination cell %s.\n", ctx->nameOf(usr.port), - ctx->nameOf(usr.cell)); - nets.at(i).arcs.at(j).sink_wire = dst_wire; - // Set bounding box for this arc - nets.at(i).arcs.at(j).bb = ctx->getRouteBoundingBox(src_wire, dst_wire); - // Expand net bounding box to include this arc - nets.at(i).bb.x0 = std::min(nets.at(i).bb.x0, nets.at(i).arcs.at(j).bb.x0); - nets.at(i).bb.x1 = std::max(nets.at(i).bb.x1, nets.at(i).arcs.at(j).bb.x1); - nets.at(i).bb.y0 = std::min(nets.at(i).bb.y0, nets.at(i).arcs.at(j).bb.y0); - nets.at(i).bb.y1 = std::max(nets.at(i).bb.y1, nets.at(i).arcs.at(j).bb.y1); + WireId src_wire = ctx->getNetinfoSourceWire(ni); + for (auto &dst_wire : ctx->getNetinfoSinkWires(ni, usr)) { + nets.at(i).src_wire = src_wire; + if (ni->driver.cell == nullptr) + src_wire = dst_wire; + if (ni->driver.cell == nullptr && dst_wire == WireId()) + continue; + if (src_wire == WireId()) + log_error("No wire found for port %s on source cell %s.\n", ctx->nameOf(ni->driver.port), + ctx->nameOf(ni->driver.cell)); + if (dst_wire == WireId()) + log_error("No wire found for port %s on destination cell %s.\n", ctx->nameOf(usr.port), + ctx->nameOf(usr.cell)); + nets.at(i).arcs.at(j).emplace_back(); + auto &ad = nets.at(i).arcs.at(j).back(); + ad.sink_wire = dst_wire; + // Set bounding box for this arc + ad.bb = ctx->getRouteBoundingBox(src_wire, dst_wire); + // Expand net bounding box to include this arc + nets.at(i).bb.x0 = std::min(nets.at(i).bb.x0, ad.bb.x0); + nets.at(i).bb.x1 = std::max(nets.at(i).bb.x1, ad.bb.x1); + nets.at(i).bb.y0 = std::min(nets.at(i).bb.y0, ad.bb.y0); + nets.at(i).bb.y1 = std::max(nets.at(i).bb.x1, ad.bb.y1); + } // Add location to centroid sum Loc usr_loc = ctx->getBelLocation(usr.cell->bel); nets.at(i).cx += usr_loc.x; @@ -254,7 +258,7 @@ struct Router2 // Nets that failed routing std::vector<NetInfo *> failed_nets; - std::vector<int> route_arcs; + std::vector<std::pair<size_t, size_t>> route_arcs; std::priority_queue<QueuedWire, std::vector<QueuedWire>, QueuedWire::Greater> queue; // Special case where one net has multiple logical arcs to the same physical sink @@ -317,9 +321,9 @@ struct Router2 } } - void ripup_arc(NetInfo *net, size_t user) + void ripup_arc(NetInfo *net, size_t user, size_t phys_pin) { - auto &ad = nets.at(net->udata).arcs.at(user); + auto &ad = nets.at(net->udata).arcs.at(user).at(phys_pin); if (!ad.routed) return; WireId src = nets.at(net->udata).src_wire; @@ -333,7 +337,7 @@ struct Router2 ad.routed = false; } - float score_wire_for_arc(NetInfo *net, size_t user, WireId wire, PipId pip) + float score_wire_for_arc(NetInfo *net, size_t user, size_t phys_pin, WireId wire, PipId pip) { auto &wd = wire_data(wire); auto &nd = nets.at(net->udata); @@ -350,7 +354,7 @@ struct Router2 for (auto &bound : wd.bound_nets) if (bound.first != net->udata) max_bound_crit = std::max(max_bound_crit, nets.at(bound.first).max_crit); - if (max_bound_crit >= 0.8 && nd.arcs.at(user).arc_crit < (max_bound_crit + 0.01)) { + if (max_bound_crit >= 0.8 && nd.arcs.at(user).at(phys_pin).arc_crit < (max_bound_crit + 0.01)) { present_cost *= 1.5; } } @@ -372,9 +376,9 @@ struct Router2 return (ctx->getDelayNS(ctx->estimateDelay(wd.w, sink)) / (1 + source_uses)) + cfg.ipin_cost_adder; } - bool check_arc_routing(NetInfo *net, size_t usr) + bool check_arc_routing(NetInfo *net, size_t usr, size_t phys_pin) { - auto &ad = nets.at(net->udata).arcs.at(usr); + auto &ad = nets.at(net->udata).arcs.at(usr).at(phys_pin); WireId src_wire = nets.at(net->udata).src_wire; WireId cursor = ad.sink_wire; while (wire_data(cursor).bound_nets.count(net->udata)) { @@ -405,35 +409,34 @@ 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), 0); - if (sink == WireId()) - return; - std::unordered_set<WireId> rsv; - WireId cursor = sink; - bool done = false; - if (ctx->debug) - log("reserving wires for arc %d of net %s\n", int(i), ctx->nameOf(net)); - while (!done) { - auto &wd = wire_data(cursor); + for (auto sink : ctx->getNetinfoSinkWires(net, net->users.at(i))) { + std::unordered_set<WireId> rsv; + WireId cursor = sink; + bool done = false; if (ctx->debug) - log(" %s\n", ctx->nameOfWire(cursor)); - wd.reserved_net = net->udata; - if (cursor == src) - break; - WireId next_cursor; - for (auto uh : ctx->getPipsUphill(cursor)) { - WireId w = ctx->getPipSrcWire(uh); - if (is_wire_undriveable(w)) - continue; - if (next_cursor != WireId()) { - done = true; + log("reserving wires for arc %d of net %s\n", int(i), ctx->nameOf(net)); + while (!done) { + auto &wd = wire_data(cursor); + if (ctx->debug) + log(" %s\n", ctx->nameOfWire(cursor)); + wd.reserved_net = net->udata; + if (cursor == src) break; + WireId next_cursor; + for (auto uh : ctx->getPipsUphill(cursor)) { + WireId w = ctx->getPipSrcWire(uh); + if (is_wire_undriveable(w)) + continue; + if (next_cursor != WireId()) { + done = true; + break; + } + next_cursor = w; } - next_cursor = w; + if (next_cursor == WireId()) + break; + cursor = next_cursor; } - if (next_cursor == WireId()) - break; - cursor = next_cursor; } } @@ -471,15 +474,15 @@ struct Router2 } bool was_visited(int wire) { return flat_wires.at(wire).visit.visited; } - ArcRouteResult route_arc(ThreadContext &t, NetInfo *net, size_t i, bool is_mt, bool is_bb = true) + ArcRouteResult route_arc(ThreadContext &t, NetInfo *net, size_t i, size_t phys_pin, bool is_mt, bool is_bb = true) { auto &nd = nets[net->udata]; - auto &ad = nd.arcs[i]; + auto &ad = nd.arcs.at(i).at(phys_pin); 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, 0); + WireId src_wire = ctx->getNetinfoSourceWire(net), dst_wire = ctx->getNetinfoSinkWire(net, usr, phys_pin); 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)); @@ -650,7 +653,7 @@ struct Router2 if (!thread_test_wire(t, nwd)) continue; // thread safety issue WireScore next_score; - next_score.cost = curr.score.cost + score_wire_for_arc(net, i, next, dh); + next_score.cost = curr.score.cost + score_wire_for_arc(net, i, phys_pin, next, dh); next_score.delay = curr.score.delay + ctx->getPipDelay(dh).maxDelay() + ctx->getWireDelay(next).maxDelay(); next_score.togo_cost = cfg.estimate_weight * get_togo_cost(net, i, next_idx, dst_wire); @@ -720,22 +723,26 @@ struct Router2 bool have_failures = false; t.processed_sinks.clear(); t.route_arcs.clear(); + auto &nd = nets.at(net->udata); for (size_t i = 0; i < net->users.size(); i++) { - // Ripup failed arcs to start with - // Check if arc is already legally routed - if (check_arc_routing(net, i)) - continue; - auto &usr = net->users.at(i); - 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; - // Ripup arc to start with - ripup_arc(net, i); - t.route_arcs.push_back(i); + auto &ad = nd.arcs.at(i); + for (size_t j = 0; j < ad.size(); j++) { + // Ripup failed arcs to start with + // Check if arc is already legally routed + if (check_arc_routing(net, i, j)) + continue; + auto &usr = net->users.at(i); + WireId dst_wire = ctx->getNetinfoSinkWire(net, usr, j); + // 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; + // Ripup arc to start with + ripup_arc(net, i, j); + t.route_arcs.emplace_back(i, j); + } } - for (auto i : t.route_arcs) { - auto res1 = route_arc(t, net, i, is_mt, true); + for (auto a : t.route_arcs) { + auto res1 = route_arc(t, net, a.first, a.second, is_mt, true); if (res1 == ARC_FATAL) return false; // Arc failed irrecoverably else if (res1 == ARC_RETRY_WITHOUT_BB) { @@ -744,14 +751,14 @@ struct Router2 have_failures = true; } else { // Attempt a re-route without the bounding box constraint - ROUTE_LOG_DBG("Rerouting arc %d of net '%s' without bounding box, possible tricky routing...\n", - int(i), ctx->nameOf(net)); - auto res2 = route_arc(t, net, i, is_mt, false); + ROUTE_LOG_DBG("Rerouting arc %d.%d of net '%s' without bounding box, possible tricky routing...\n", + int(a.first), int(a.second), ctx->nameOf(net)); + auto res2 = route_arc(t, net, a.first, a.second, is_mt, false); // If this also fails, no choice but to give up 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), 0))); + log_error("Failed to route arc %d.%d of net '%s', from %s to %s.\n", int(a.first), + int(a.second), ctx->nameOf(net), ctx->nameOfWire(ctx->getNetinfoSourceWire(net)), + ctx->nameOfWire(ctx->getNetinfoSinkWire(net, net->users.at(a.first), a.second))); } } } @@ -789,7 +796,7 @@ struct Router2 } } - bool bind_and_check(NetInfo *net, int usr_idx) + bool bind_and_check(NetInfo *net, int usr_idx, int phys_pin) { #ifdef ARCH_ECP5 if (net->is_global) @@ -797,13 +804,13 @@ struct Router2 #endif bool success = true; auto &nd = nets.at(net->udata); - auto &ad = nd.arcs.at(usr_idx); + auto &ad = nd.arcs.at(usr_idx).at(phys_pin); auto &usr = net->users.at(usr_idx); WireId src = ctx->getNetinfoSourceWire(net); // Skip routes with no source if (src == WireId()) return true; - WireId dst = ctx->getNetinfoSinkWire(net, usr, 0); + WireId dst = ctx->getNetinfoSinkWire(net, usr, phys_pin); // Skip routes where the destination is already bound if (dst == WireId() || ctx->getBoundWireNet(dst) == net) return true; @@ -849,7 +856,7 @@ struct Router2 for (auto tb : to_bind) ctx->bindPip(tb, net, STRENGTH_WEAK); } else { - ripup_arc(net, usr_idx); + ripup_arc(net, usr_idx, phys_pin); failed_nets.insert(net->udata); } return success; @@ -875,9 +882,11 @@ struct Router2 ctx->unbindWire(w); // Bind the arcs using the routes we have discovered for (size_t i = 0; i < net->users.size(); i++) { - if (!bind_and_check(net, i)) { - ++arch_fail; - success = false; + for (size_t phys_pin = 0; phys_pin < nets.at(net->udata).arcs.at(i).size(); phys_pin++) { + if (!bind_and_check(net, i, phys_pin)) { + ++arch_fail; + success = false; + } } } } @@ -1123,7 +1132,8 @@ struct Router2 continue; for (int i = 0; i < int(fnd->second.criticality.size()); i++) { float c = fnd->second.criticality.at(i); - net.arcs.at(i).arc_crit = c; + for (auto &a : net.arcs.at(i)) + a.arc_crit = c; net.max_crit = std::max(net.max_crit, c); } } |