ecp5: Fix some tricky ECLKSYNCB/CLKDIVF packing cases

Signed-off-by: David Shah <dave@ds0.me>
This commit is contained in:
David Shah 2020-10-09 21:41:55 +01:00
parent b5054f0d77
commit 576baa994f

View File

@ -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();
};