From d43138b022c84efc01895f51f15244d8a42a5156 Mon Sep 17 00:00:00 2001 From: David Shah Date: Sun, 29 Jul 2018 10:35:05 +0200 Subject: ecp5: Global routing algorithm up to TAPs Signed-off-by: David Shah --- ecp5/globals.cc | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 75 insertions(+), 10 deletions(-) (limited to 'ecp5/globals.cc') diff --git a/ecp5/globals.cc b/ecp5/globals.cc index 770eb7e2..9d51316c 100644 --- a/ecp5/globals.cc +++ b/ecp5/globals.cc @@ -17,8 +17,14 @@ * */ -#include "nextpnr.h" #include +#include +#include +#include "nextpnr.h" + +#include "log.h" + +#define fmt_str(x) (static_cast(std::ostringstream() << x).str()) NEXTPNR_NAMESPACE_BEGIN @@ -26,15 +32,16 @@ class Ecp5GlobalRouter { public: Ecp5GlobalRouter(Context *ctx) : ctx(ctx){}; - private: - bool is_clock_port(const PortRef &user) { + private: + bool is_clock_port(const PortRef &user) + { if (user.cell->type == ctx->id("TRELLIS_LC") && user.port == ctx->id("CLK")) return true; return false; } - std::vector get_clocks() + std::vector get_clocks() { std::unordered_map clockCount; for (auto &net : ctx->nets) { @@ -45,13 +52,11 @@ class Ecp5GlobalRouter clockCount[ni->name]++; } } - std::vector clocks; + std::vector clocks; while (clocks.size() < 16) { - auto max = std::max_element(clockCount.begin(), clockCount.end(), []( - const decltype(clockCount)::value_type &a, const decltype(clockCount)::value_type &b - ) { - return a.second < b.second; - }); + auto max = std::max_element(clockCount.begin(), clockCount.end(), + [](const decltype(clockCount)::value_type &a, + const decltype(clockCount)::value_type &b) { return a.second < b.second; }); if (max == clockCount.end() || max->second < 3) break; clocks.push_back(ctx->nets.at(max->first).get()); @@ -77,6 +82,66 @@ class Ecp5GlobalRouter return *(ctx->getPipsUphill(tap_wire).begin()); } + void route_logic_tile_global(IdString net, int global_index, PortRef user) + { + WireId userWire = ctx->getBelPinWire(user.cell->bel, ctx->portPinFromId(user.port)); + WireId globalWire; + IdString global_name = ctx->id(fmt_str("G_HPBX" << std::setw(2) << std::setfill('0') << global_index << "00")); + std::queue upstream; + std::unordered_map backtrace; + upstream.push(userWire); + bool already_routed = false; + // Search back from the pin until we reach the global network + while (true) { + WireId next = upstream.front(); + upstream.pop(); + + if (ctx->getBoundWireNet(next) == net) { + already_routed = true; + globalWire = next; + break; + } + + if (ctx->getWireBasename(next) == global_name) { + globalWire = next; + break; + } + if (ctx->checkWireAvail(next)) { + for (auto pip : ctx->getPipsUphill(next)) { + WireId src = ctx->getPipSrcWire(pip); + backtrace[src] = pip; + upstream.push(src); + } + } + if (upstream.size() > 3000) { + log_error("failed to route HPBX%02d00 to %s.%s\n", global_index, + ctx->getBelName(user.cell->bel).c_str(ctx), user.port.c_str(ctx)); + } + } + // Set all the pips we found along the way + WireId cursor = userWire; + while (true) { + auto fnd = backtrace.find(cursor); + if (fnd == backtrace.end()) + break; + ctx->bindPip(fnd->second, net, STRENGTH_LOCKED); + cursor = ctx->getPipSrcWire(fnd->second); + } + // If the global network inside the tile isn't already set up, + // we also need to bind the buffers along the way + if (!already_routed) { + ctx->bindWire(cursor, net, STRENGTH_LOCKED); + PipId tap_pip = find_tap_pip(cursor); + IdString tap_net = ctx->getBoundPipNet(tap_pip); + if (tap_net == IdString()) { + ctx->bindPip(tap_pip, net, STRENGTH_LOCKED); + // TODO: SPINE + } else { + NPNR_ASSERT(tap_net == net); + } + } + } + Context *ctx; }; -- cgit v1.2.3