diff options
author | David Shah <dave@ds0.me> | 2020-04-14 18:55:55 +0100 |
---|---|---|
committer | David Shah <dave@ds0.me> | 2020-04-14 19:20:13 +0100 |
commit | 64d3e3e1e8aa6da3fc99df57d0dbd7bfbd49e899 (patch) | |
tree | 93de79fd5b9bba2695aa8ab9ac0533c8ae8ddb70 /ecp5 | |
parent | 96c14abd1f79a152f3e5a1b4897ca2e7a91e7b27 (diff) | |
download | nextpnr-64d3e3e1e8aa6da3fc99df57d0dbd7bfbd49e899.tar.gz nextpnr-64d3e3e1e8aa6da3fc99df57d0dbd7bfbd49e899.tar.bz2 nextpnr-64d3e3e1e8aa6da3fc99df57d0dbd7bfbd49e899.zip |
ecp5: Use dedicated routing for ECLKs where possible
Signed-off-by: David Shah <dave@ds0.me>
Diffstat (limited to 'ecp5')
-rw-r--r-- | ecp5/globals.cc | 81 |
1 files changed, 80 insertions, 1 deletions
diff --git a/ecp5/globals.cc b/ecp5/globals.cc index 6dbd7b6b..65b1710f 100644 --- a/ecp5/globals.cc +++ b/ecp5/globals.cc @@ -517,8 +517,87 @@ class Ecp5GlobalRouter route_logic_tile_global(clocks.at(user.second), user.second, *user.first); } } + + void route_eclk_sources() + { + // Try and use dedicated paths if possible + for (auto cell : sorted(ctx->cells)) { + CellInfo *ci = cell.second; + if (ci->type == id_ECLKSYNCB || ci->type == id_TRELLIS_ECLKBUF || ci->type == id_ECLKBRIDGECS) { + std::vector<IdString> pins; + if (ci->type == id_ECLKSYNCB || ci->type == id_TRELLIS_ECLKBUF) { + pins.push_back(id_ECLKI); + } else { + pins.push_back(id_CLK0); + pins.push_back(id_CLK1); + } + for (auto pin : pins) { + NetInfo *ni = get_net_or_empty(ci, pin); + if (ni == nullptr) + continue; + log_info(" trying dedicated routing for edge clock source %s\n", ctx->nameOf(ni)); + WireId src = ctx->getNetinfoSourceWire(ni); + WireId dst = ctx->getBelPinWire(ci->bel, pin); + std::queue<WireId> visit; + std::unordered_map<WireId, PipId> backtrace; + visit.push(dst); + int iter = 0; + WireId cursor; + bool success = false; + // This is a best-effort pass, if it fails then still try general routing later + const int iter_max = 1000; + while (iter < iter_max && !visit.empty()) { + cursor = visit.front(); + visit.pop(); + ++iter; + NetInfo *bound = ctx->getBoundWireNet(cursor); + if (bound != nullptr) { + if (bound == ni) { + success = true; + break; + } else { + continue; + } + } + if (cursor == src) { + ctx->bindWire(cursor, ni, STRENGTH_LOCKED); + success = true; + break; + } + for (auto uh : ctx->getPipsUphill(cursor)) { + if (!ctx->checkPipAvail(uh)) + continue; + WireId src = ctx->getPipSrcWire(uh); + if (backtrace.count(src)) + continue; + IdString basename = ctx->getWireBasename(src); + // "ECLKCIB" wires are the junction with general routing + if (basename.str(ctx).find("ECLKCIB") != std::string::npos) + continue; + visit.push(src); + backtrace[src] = uh; + } + } + if (success) { + while (cursor != dst) { + PipId pip = backtrace.at(cursor); + ctx->bindPip(pip, ni, STRENGTH_LOCKED); + cursor = ctx->getPipDstWire(pip); + } + } else { + log_info(" no route found, general routing will be used.\n"); + } + } + } + } + } }; void promote_ecp5_globals(Context *ctx) { Ecp5GlobalRouter(ctx).promote_globals(); } -void route_ecp5_globals(Context *ctx) { Ecp5GlobalRouter(ctx).route_globals(); } +void route_ecp5_globals(Context *ctx) +{ + Ecp5GlobalRouter router(ctx); + router.route_globals(); + router.route_eclk_sources(); +} NEXTPNR_NAMESPACE_END |