ecp5: Use dedicated routing for ECLKs where possible
Signed-off-by: David Shah <dave@ds0.me>
This commit is contained in:
parent
96c14abd1f
commit
64d3e3e1e8
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user