From 576baa994f4b9e1746a231469bfd9e65d1d5a2b4 Mon Sep 17 00:00:00 2001 From: David Shah Date: Fri, 9 Oct 2020 21:41:55 +0100 Subject: ecp5: Fix some tricky ECLKSYNCB/CLKDIVF packing cases Signed-off-by: David Shah --- ecp5/pack.cc | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) (limited to 'ecp5') 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 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 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(); }; -- cgit v1.2.3