From a48acec92edb0fb4be384e90981a8379a42fb0bc Mon Sep 17 00:00:00 2001 From: Lofty Date: Tue, 16 Sep 2025 11:00:44 +0100 Subject: [PATCH] route clocks from source to sink --- himbaechel/uarch/gatemate/route_clock.cc | 163 ++++++++++++----------- 1 file changed, 86 insertions(+), 77 deletions(-) diff --git a/himbaechel/uarch/gatemate/route_clock.cc b/himbaechel/uarch/gatemate/route_clock.cc index 5fe67fc3..e7f3be5b 100644 --- a/himbaechel/uarch/gatemate/route_clock.cc +++ b/himbaechel/uarch/gatemate/route_clock.cc @@ -112,7 +112,8 @@ void GateMateImpl::route_clock() for (auto clk_net : clk_nets) { log_info(" routing net '%s' to %d users\n", clk_net->name.c_str(ctx), clk_net->users.entries()); - ctx->bindWire(ctx->getNetinfoSourceWire(clk_net), clk_net, STRENGTH_LOCKED); + auto src_wire = ctx->getNetinfoSourceWire(clk_net); + ctx->bindWire(src_wire, clk_net, STRENGTH_LOCKED); auto clk_plane = 0; switch (clk_net->driver.port.index) { @@ -130,18 +131,85 @@ void GateMateImpl::route_clock() break; } + auto sink_wires = dict{}; + auto sink_wires_to_do = pool{}; for (auto &usr : clk_net->users) { - std::priority_queue, std::greater> visit; - dict backtrace; - WireId dest = WireId(); - if (!feeds_clk_port(usr) && !feeds_ddr_port(clk_net, usr)) continue; - auto cpe_loc = ctx->getBelLocation(usr.cell->bel); - auto is_glb_clk = clk_net->driver.cell->type == id_GLBOUT; - auto sink_wire = ctx->getNetinfoSinkWire(clk_net, usr, 0); + + sink_wires.insert({sink_wire, usr}); + sink_wires_to_do.insert(sink_wire); + } + + std::priority_queue, std::greater> visit; + dict backtrace; + + //auto cpe_loc = ctx->getBelLocation(usr.cell->bel); + auto is_glb_clk = clk_net->driver.cell->type == id_GLBOUT; + + visit.push(QueuedWire(src_wire)); + while (!visit.empty()) { + QueuedWire curr = visit.top(); + visit.pop(); + if (sink_wires_to_do.count(curr.wire)) { + if (ctx->debug) { + auto sink_wire_name = "(uninitialized)"; + if (curr.wire != WireId()) + sink_wire_name = ctx->nameOfWire(curr.wire); + log_info(" -> %s (%.3fns)\n", sink_wire_name, ctx->getDelayNS(curr.delay)); + } + sink_wires_to_do.erase(curr.wire); + if (sink_wires_to_do.empty()) + break; + } + + for (auto dh : ctx->getPipsDownhill(curr.wire)) { + if (!ctx->checkPipAvailForNet(dh, clk_net)) + continue; + WireId dst = ctx->getPipDstWire(dh); + if (backtrace.count(dst)) + continue; + if (!ctx->checkWireAvail(dst) && ctx->getBoundWireNet(dst) != clk_net) + continue; + // Has this wire been reserved for another net? + auto reserved = reserved_wires.find(dst); + if (reserved != reserved_wires.end() && reserved->second != clk_net->name) + continue; + auto pip_loc = ctx->getPipLocation(dh); + // Use only a specific plane to minimise congestion for global clocks. + /*if (is_glb_clk && (pip_loc.x != cpe_loc.x || pip_loc.y != cpe_loc.y)) { + // Plane 9 is the clock plane, so it should only ever use itself. + if (clk_plane == 9 && pip_plane(dh) != 9) + continue; + // Plane 10 is the enable plane. + // When there's a set/reset, we want to use the switchbox X23 pip to change directly to plane 9. + if (clk_plane == 10 && pip_plane(dh) != 9 && pip_plane(dh) != 10) + continue; + // Plane 11 is the set/reset plane; we want to use the switchbox X14 pip to go to plane 12, then + // use the IM to switch to plane 9. + if (clk_plane == 11 && pip_plane(dh) == 10) + continue; + // Plane 12 is the spare plane; we can use the IM to change directly to plane 9. + if (clk_plane == 12 && pip_plane(dh) != 9 && pip_plane(dh) != 12) + continue; + }*/ + backtrace[dst] = dh; + auto delay = ctx->getPipDelay(dh).maxDelay() + ctx->getWireDelay(dst).maxDelay() + + ctx->getDelayEpsilon(); + visit.push(QueuedWire(dst, curr.delay + delay)); + } + } + for (auto sink_wire : sink_wires_to_do) { + log_info(" failed to find a route using dedicated resources. %s -> %s\n", + clk_net->driver.cell->name.c_str(ctx), ctx->nameOfWire(sink_wire)); + } + for (auto pair : sink_wires) { + auto sink_wire = pair.first; + auto usr = pair.second; + auto src = sink_wire; + if (ctx->debug) { auto sink_wire_name = "(uninitialized)"; if (sink_wire != WireId()) @@ -149,84 +217,25 @@ void GateMateImpl::route_clock() log_info(" routing arc to %s.%s (wire %s):\n", usr.cell->name.c_str(ctx), usr.port.c_str(ctx), sink_wire_name); } - visit.push(QueuedWire(sink_wire)); - while (!visit.empty()) { - QueuedWire curr = visit.top(); - visit.pop(); - if (curr.wire == ctx->getNetinfoSourceWire(clk_net)) { - if (ctx->debug) - log_info(" (%.3fns)\n", ctx->getDelayNS(curr.delay)); - dest = curr.wire; - break; - } - PipId bound_pip; - auto fnd_wire = clk_net->wires.find(curr.wire); - if (fnd_wire != clk_net->wires.end()) { - bound_pip = fnd_wire->second.pip; - } - - for (auto uh : ctx->getPipsUphill(curr.wire)) { - if (!ctx->checkPipAvailForNet(uh, clk_net)) - continue; - WireId src = ctx->getPipSrcWire(uh); - if (backtrace.count(src)) - continue; - if (!ctx->checkWireAvail(src) && ctx->getBoundWireNet(src) != clk_net) - continue; - if (bound_pip != PipId() && uh != bound_pip) - continue; - // Has this wire been reserved for another net? - auto reserved = reserved_wires.find(src); - if (reserved != reserved_wires.end() && reserved->second != clk_net->name) - continue; - auto pip_loc = ctx->getPipLocation(uh); - // Use only a specific plane to minimise congestion for global clocks. - if (is_glb_clk && (pip_loc.x != cpe_loc.x || pip_loc.y != cpe_loc.y)) { - // Plane 9 is the clock plane, so it should only ever use itself. - if (clk_plane == 9 && pip_plane(uh) != 9) - continue; - // Plane 10 is the enable plane. - // When there's a set/reset, we want to use the switchbox X23 pip to change directly to plane 9. - if (clk_plane == 10 && pip_plane(uh) != 9 && pip_plane(uh) != 10) - continue; - // Plane 11 is the set/reset plane; we want to use the switchbox X14 pip to go to plane 12, then - // use the IM to switch to plane 9. - if (clk_plane == 11 && pip_plane(uh) == 10) - continue; - // Plane 12 is the spare plane; we can use the IM to change directly to plane 9. - if (clk_plane == 12 && pip_plane(uh) != 9 && pip_plane(uh) != 12) - continue; - } - backtrace[src] = uh; - auto delay = ctx->getPipDelay(uh).maxDelay() + ctx->getWireDelay(src).maxDelay() + - ctx->getDelayEpsilon(); - visit.push(QueuedWire(src, curr.delay + delay)); - } - } - if (dest == WireId()) { - log_info(" failed to find a route using dedicated resources. %s -> %s\n", - clk_net->driver.cell->name.c_str(ctx), usr.cell->name.c_str(ctx)); - } - while (backtrace.count(dest)) { - auto uh = backtrace[dest]; - dest = ctx->getPipDstWire(uh); - if (ctx->getBoundWireNet(dest) == clk_net) { - NPNR_ASSERT(clk_net->wires.at(dest).pip == uh); + while (backtrace.count(src)) { + auto uh = backtrace[src]; + if (ctx->getBoundWireNet(src) == clk_net) { if (ctx->debug) log_info(" pip %s --> %s (plane %hhd)\n", ctx->nameOfPip(uh), - ctx->nameOfWire(dest), pip_plane(uh)); - } else if (ctx->getBoundWireNet(dest) == nullptr) { - ctx->bindPip(uh, clk_net, STRENGTH_LOCKED); + ctx->nameOfWire(src), pip_plane(uh)); + } else if (ctx->getBoundWireNet(src) == nullptr) { if (ctx->debug) log_info(" bind pip %s --> %s (plane %hhd)\n", ctx->nameOfPip(uh), - ctx->nameOfWire(dest), pip_plane(uh)); + ctx->nameOfWire(src), pip_plane(uh)); + ctx->bindPip(uh, clk_net, STRENGTH_LOCKED); } else { log_error("Can't bind pip %s because wire %s is already bound\n", ctx->nameOfPip(uh), - ctx->nameOfWire(dest)); + ctx->nameOfWire(src)); } - if (dest == sink_wire) + if (src == src_wire) break; + src = ctx->getPipSrcWire(uh); } } }