diff options
author | David Shah <dave@ds0.me> | 2020-10-09 21:41:55 +0100 |
---|---|---|
committer | David Shah <dave@ds0.me> | 2020-10-09 21:41:55 +0100 |
commit | 576baa994f4b9e1746a231469bfd9e65d1d5a2b4 (patch) | |
tree | 5eb38c5ff4296be9c2d9d1e4f660d47c71c03fb3 | |
parent | b5054f0d7777b7f831d2223479628372e968e89a (diff) | |
download | nextpnr-576baa994f4b9e1746a231469bfd9e65d1d5a2b4.tar.gz nextpnr-576baa994f4b9e1746a231469bfd9e65d1d5a2b4.tar.bz2 nextpnr-576baa994f4b9e1746a231469bfd9e65d1d5a2b4.zip |
ecp5: Fix some tricky ECLKSYNCB/CLKDIVF packing cases
Signed-off-by: David Shah <dave@ds0.me>
-rw-r--r-- | ecp5/pack.cc | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/ecp5/pack.cc b/ecp5/pack.cc index fa92cc15..58737bfe 100644 --- a/ecp5/pack.cc +++ b/ecp5/pack.cc @@ -2653,6 +2653,7 @@ class Ecp5Packer } } flush_cells(); + std::unordered_set<BelId> used_eclksyncb; for (auto cell : sorted(ctx->cells)) { CellInfo *ci = cell.second; if (ci->type == id_CLKDIVF) { @@ -2687,6 +2688,7 @@ class Ecp5Packer Loc loc = ctx->getBelLocation(bel); ci->attrs[ctx->id("BEL")] = ctx->getBelName(ctx->getBelByLocation(Loc(loc.x, loc.y, 15))).str(ctx); + used_eclksyncb.insert(bel); goto eclksync_done; } } @@ -2702,6 +2704,7 @@ class Ecp5Packer Loc loc = ctx->getBelLocation(bel); if (loc.x == eckbuf_loc.x && loc.y == eckbuf_loc.y && loc.z == eckbuf_loc.z - 2) { ci->attrs[ctx->id("BEL")] = ctx->getBelName(bel).str(ctx); + used_eclksyncb.insert(bel); goto eclksync_done; } } @@ -2768,6 +2771,67 @@ class Ecp5Packer } } + for (auto cell : sorted(ctx->cells)) { + CellInfo *ci = cell.second; + if (ci->type == id_ECLKSYNCB) { + // **All** ECLKSYNCBs must be constrained + // Most will be dealt with above, but there might be some rogue cases + if (ci->attrs.count(ctx->id("BEL"))) + continue; + for (BelId bel : ctx->getBels()) { + if (ctx->getBelType(bel) != id_ECLKSYNCB) + continue; + // Might there be a better way to pick?? + if (used_eclksyncb.count(bel)) + continue; + log_info("Constraining ECLKSYNCB '%s' to bel '%s'\n", ctx->nameOf(ci), ctx->nameOfBel(bel)); + ci->attrs[ctx->id("BEL")] = ctx->getBelName(bel).str(ctx); + goto eclksync_ii_done; + } + if (0) { + eclksync_ii_done: + continue; + } + log_error("Failed to constrain ECLKSYNCB '%s'\n", ctx->nameOf(ci)); + } + } + + for (auto cell : sorted(ctx->cells)) { + CellInfo *ci = cell.second; + if (ci->type == id_CLKDIVF) { + if (ci->attrs.count(ctx->id("BEL"))) + continue; + // Case of a CLKDIVF driven by an ECLKSYNC constrained above; without the input being used elsewhere as + // an edge clock + const NetInfo *clki = net_or_nullptr(ci, id_CLKI); + if (clki == nullptr || clki->driver.cell == nullptr) + continue; + CellInfo *drv = clki->driver.cell; + if (drv->type != id_ECLKSYNCB || !drv->attrs.count(ctx->id("BEL"))) + continue; + BelId bel = ctx->getBelByName(ctx->id(drv->attrs.at(ctx->id("BEL")).as_string())); + // Find a CLKDIVF that is routeable from the ECLKSYNC + std::queue<WireId> visit; + visit.push(ctx->getBelPinWire(bel, id_ECLKO)); + while (!visit.empty()) { + WireId cursor = visit.front(); + visit.pop(); + for (BelPin bp : ctx->getWireBelPins(cursor)) { + if (ctx->getBelType(bp.bel) != id_CLKDIVF || bp.pin != id_CLKI) + continue; + ci->attrs[ctx->id("BEL")] = ctx->getBelName(bp.bel).str(ctx); + log_info("Constraining CLKDIVF '%s' to bel '%s' based on ECLKSYNCB.\n", ctx->nameOf(ci), + ctx->nameOfBel(bp.bel)); + goto clkdiv_ii_done; + } + for (PipId pip : ctx->getPipsDownhill(cursor)) + visit.push(ctx->getPipDstWire(pip)); + } + clkdiv_ii_done: + continue; + } + } + flush_cells(); }; |