aboutsummaryrefslogtreecommitdiffstats
path: root/ecp5
diff options
context:
space:
mode:
authorDavid Shah <dave@ds0.me>2020-04-14 18:55:55 +0100
committerDavid Shah <dave@ds0.me>2020-04-14 19:20:13 +0100
commit64d3e3e1e8aa6da3fc99df57d0dbd7bfbd49e899 (patch)
tree93de79fd5b9bba2695aa8ab9ac0533c8ae8ddb70 /ecp5
parent96c14abd1f79a152f3e5a1b4897ca2e7a91e7b27 (diff)
downloadnextpnr-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.cc81
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