aboutsummaryrefslogtreecommitdiffstats
path: root/ecp5
diff options
context:
space:
mode:
authorDavid Shah <dave@ds0.me>2020-10-09 21:41:55 +0100
committerDavid Shah <dave@ds0.me>2020-10-09 21:41:55 +0100
commit576baa994f4b9e1746a231469bfd9e65d1d5a2b4 (patch)
tree5eb38c5ff4296be9c2d9d1e4f660d47c71c03fb3 /ecp5
parentb5054f0d7777b7f831d2223479628372e968e89a (diff)
downloadnextpnr-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>
Diffstat (limited to 'ecp5')
-rw-r--r--ecp5/pack.cc64
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();
};