mirror of
https://github.com/YosysHQ/nextpnr.git
synced 2026-01-11 23:53:21 +00:00
route clocks from source to sink
This commit is contained in:
parent
efff6f90f3
commit
a48acec92e
@ -112,7 +112,8 @@ void GateMateImpl::route_clock()
|
|||||||
|
|
||||||
for (auto clk_net : clk_nets) {
|
for (auto clk_net : clk_nets) {
|
||||||
log_info(" routing net '%s' to %d users\n", clk_net->name.c_str(ctx), clk_net->users.entries());
|
log_info(" routing net '%s' to %d users\n", clk_net->name.c_str(ctx), clk_net->users.entries());
|
||||||
ctx->bindWire(ctx->getNetinfoSourceWire(clk_net), clk_net, STRENGTH_LOCKED);
|
auto src_wire = ctx->getNetinfoSourceWire(clk_net);
|
||||||
|
ctx->bindWire(src_wire, clk_net, STRENGTH_LOCKED);
|
||||||
|
|
||||||
auto clk_plane = 0;
|
auto clk_plane = 0;
|
||||||
switch (clk_net->driver.port.index) {
|
switch (clk_net->driver.port.index) {
|
||||||
@ -130,18 +131,85 @@ void GateMateImpl::route_clock()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto sink_wires = dict<WireId, PortRef>{};
|
||||||
|
auto sink_wires_to_do = pool<WireId>{};
|
||||||
for (auto &usr : clk_net->users) {
|
for (auto &usr : clk_net->users) {
|
||||||
std::priority_queue<QueuedWire, std::vector<QueuedWire>, std::greater<QueuedWire>> visit;
|
|
||||||
dict<WireId, PipId> backtrace;
|
|
||||||
WireId dest = WireId();
|
|
||||||
|
|
||||||
if (!feeds_clk_port(usr) && !feeds_ddr_port(clk_net, usr))
|
if (!feeds_clk_port(usr) && !feeds_ddr_port(clk_net, usr))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto cpe_loc = ctx->getBelLocation(usr.cell->bel);
|
|
||||||
auto is_glb_clk = clk_net->driver.cell->type == id_GLBOUT;
|
|
||||||
|
|
||||||
auto sink_wire = ctx->getNetinfoSinkWire(clk_net, usr, 0);
|
auto sink_wire = ctx->getNetinfoSinkWire(clk_net, usr, 0);
|
||||||
|
|
||||||
|
sink_wires.insert({sink_wire, usr});
|
||||||
|
sink_wires_to_do.insert(sink_wire);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::priority_queue<QueuedWire, std::vector<QueuedWire>, std::greater<QueuedWire>> visit;
|
||||||
|
dict<WireId, PipId> backtrace;
|
||||||
|
|
||||||
|
//auto cpe_loc = ctx->getBelLocation(usr.cell->bel);
|
||||||
|
auto is_glb_clk = clk_net->driver.cell->type == id_GLBOUT;
|
||||||
|
|
||||||
|
visit.push(QueuedWire(src_wire));
|
||||||
|
while (!visit.empty()) {
|
||||||
|
QueuedWire curr = visit.top();
|
||||||
|
visit.pop();
|
||||||
|
if (sink_wires_to_do.count(curr.wire)) {
|
||||||
|
if (ctx->debug) {
|
||||||
|
auto sink_wire_name = "(uninitialized)";
|
||||||
|
if (curr.wire != WireId())
|
||||||
|
sink_wire_name = ctx->nameOfWire(curr.wire);
|
||||||
|
log_info(" -> %s (%.3fns)\n", sink_wire_name, ctx->getDelayNS(curr.delay));
|
||||||
|
}
|
||||||
|
sink_wires_to_do.erase(curr.wire);
|
||||||
|
if (sink_wires_to_do.empty())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto dh : ctx->getPipsDownhill(curr.wire)) {
|
||||||
|
if (!ctx->checkPipAvailForNet(dh, clk_net))
|
||||||
|
continue;
|
||||||
|
WireId dst = ctx->getPipDstWire(dh);
|
||||||
|
if (backtrace.count(dst))
|
||||||
|
continue;
|
||||||
|
if (!ctx->checkWireAvail(dst) && ctx->getBoundWireNet(dst) != clk_net)
|
||||||
|
continue;
|
||||||
|
// Has this wire been reserved for another net?
|
||||||
|
auto reserved = reserved_wires.find(dst);
|
||||||
|
if (reserved != reserved_wires.end() && reserved->second != clk_net->name)
|
||||||
|
continue;
|
||||||
|
auto pip_loc = ctx->getPipLocation(dh);
|
||||||
|
// Use only a specific plane to minimise congestion for global clocks.
|
||||||
|
/*if (is_glb_clk && (pip_loc.x != cpe_loc.x || pip_loc.y != cpe_loc.y)) {
|
||||||
|
// Plane 9 is the clock plane, so it should only ever use itself.
|
||||||
|
if (clk_plane == 9 && pip_plane(dh) != 9)
|
||||||
|
continue;
|
||||||
|
// Plane 10 is the enable plane.
|
||||||
|
// When there's a set/reset, we want to use the switchbox X23 pip to change directly to plane 9.
|
||||||
|
if (clk_plane == 10 && pip_plane(dh) != 9 && pip_plane(dh) != 10)
|
||||||
|
continue;
|
||||||
|
// Plane 11 is the set/reset plane; we want to use the switchbox X14 pip to go to plane 12, then
|
||||||
|
// use the IM to switch to plane 9.
|
||||||
|
if (clk_plane == 11 && pip_plane(dh) == 10)
|
||||||
|
continue;
|
||||||
|
// Plane 12 is the spare plane; we can use the IM to change directly to plane 9.
|
||||||
|
if (clk_plane == 12 && pip_plane(dh) != 9 && pip_plane(dh) != 12)
|
||||||
|
continue;
|
||||||
|
}*/
|
||||||
|
backtrace[dst] = dh;
|
||||||
|
auto delay = ctx->getPipDelay(dh).maxDelay() + ctx->getWireDelay(dst).maxDelay() +
|
||||||
|
ctx->getDelayEpsilon();
|
||||||
|
visit.push(QueuedWire(dst, curr.delay + delay));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto sink_wire : sink_wires_to_do) {
|
||||||
|
log_info(" failed to find a route using dedicated resources. %s -> %s\n",
|
||||||
|
clk_net->driver.cell->name.c_str(ctx), ctx->nameOfWire(sink_wire));
|
||||||
|
}
|
||||||
|
for (auto pair : sink_wires) {
|
||||||
|
auto sink_wire = pair.first;
|
||||||
|
auto usr = pair.second;
|
||||||
|
auto src = sink_wire;
|
||||||
|
|
||||||
if (ctx->debug) {
|
if (ctx->debug) {
|
||||||
auto sink_wire_name = "(uninitialized)";
|
auto sink_wire_name = "(uninitialized)";
|
||||||
if (sink_wire != WireId())
|
if (sink_wire != WireId())
|
||||||
@ -149,84 +217,25 @@ void GateMateImpl::route_clock()
|
|||||||
log_info(" routing arc to %s.%s (wire %s):\n", usr.cell->name.c_str(ctx), usr.port.c_str(ctx),
|
log_info(" routing arc to %s.%s (wire %s):\n", usr.cell->name.c_str(ctx), usr.port.c_str(ctx),
|
||||||
sink_wire_name);
|
sink_wire_name);
|
||||||
}
|
}
|
||||||
visit.push(QueuedWire(sink_wire));
|
|
||||||
while (!visit.empty()) {
|
|
||||||
QueuedWire curr = visit.top();
|
|
||||||
visit.pop();
|
|
||||||
if (curr.wire == ctx->getNetinfoSourceWire(clk_net)) {
|
|
||||||
if (ctx->debug)
|
|
||||||
log_info(" (%.3fns)\n", ctx->getDelayNS(curr.delay));
|
|
||||||
dest = curr.wire;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
PipId bound_pip;
|
while (backtrace.count(src)) {
|
||||||
auto fnd_wire = clk_net->wires.find(curr.wire);
|
auto uh = backtrace[src];
|
||||||
if (fnd_wire != clk_net->wires.end()) {
|
if (ctx->getBoundWireNet(src) == clk_net) {
|
||||||
bound_pip = fnd_wire->second.pip;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto uh : ctx->getPipsUphill(curr.wire)) {
|
|
||||||
if (!ctx->checkPipAvailForNet(uh, clk_net))
|
|
||||||
continue;
|
|
||||||
WireId src = ctx->getPipSrcWire(uh);
|
|
||||||
if (backtrace.count(src))
|
|
||||||
continue;
|
|
||||||
if (!ctx->checkWireAvail(src) && ctx->getBoundWireNet(src) != clk_net)
|
|
||||||
continue;
|
|
||||||
if (bound_pip != PipId() && uh != bound_pip)
|
|
||||||
continue;
|
|
||||||
// Has this wire been reserved for another net?
|
|
||||||
auto reserved = reserved_wires.find(src);
|
|
||||||
if (reserved != reserved_wires.end() && reserved->second != clk_net->name)
|
|
||||||
continue;
|
|
||||||
auto pip_loc = ctx->getPipLocation(uh);
|
|
||||||
// Use only a specific plane to minimise congestion for global clocks.
|
|
||||||
if (is_glb_clk && (pip_loc.x != cpe_loc.x || pip_loc.y != cpe_loc.y)) {
|
|
||||||
// Plane 9 is the clock plane, so it should only ever use itself.
|
|
||||||
if (clk_plane == 9 && pip_plane(uh) != 9)
|
|
||||||
continue;
|
|
||||||
// Plane 10 is the enable plane.
|
|
||||||
// When there's a set/reset, we want to use the switchbox X23 pip to change directly to plane 9.
|
|
||||||
if (clk_plane == 10 && pip_plane(uh) != 9 && pip_plane(uh) != 10)
|
|
||||||
continue;
|
|
||||||
// Plane 11 is the set/reset plane; we want to use the switchbox X14 pip to go to plane 12, then
|
|
||||||
// use the IM to switch to plane 9.
|
|
||||||
if (clk_plane == 11 && pip_plane(uh) == 10)
|
|
||||||
continue;
|
|
||||||
// Plane 12 is the spare plane; we can use the IM to change directly to plane 9.
|
|
||||||
if (clk_plane == 12 && pip_plane(uh) != 9 && pip_plane(uh) != 12)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
backtrace[src] = uh;
|
|
||||||
auto delay = ctx->getPipDelay(uh).maxDelay() + ctx->getWireDelay(src).maxDelay() +
|
|
||||||
ctx->getDelayEpsilon();
|
|
||||||
visit.push(QueuedWire(src, curr.delay + delay));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (dest == WireId()) {
|
|
||||||
log_info(" failed to find a route using dedicated resources. %s -> %s\n",
|
|
||||||
clk_net->driver.cell->name.c_str(ctx), usr.cell->name.c_str(ctx));
|
|
||||||
}
|
|
||||||
while (backtrace.count(dest)) {
|
|
||||||
auto uh = backtrace[dest];
|
|
||||||
dest = ctx->getPipDstWire(uh);
|
|
||||||
if (ctx->getBoundWireNet(dest) == clk_net) {
|
|
||||||
NPNR_ASSERT(clk_net->wires.at(dest).pip == uh);
|
|
||||||
if (ctx->debug)
|
if (ctx->debug)
|
||||||
log_info(" pip %s --> %s (plane %hhd)\n", ctx->nameOfPip(uh),
|
log_info(" pip %s --> %s (plane %hhd)\n", ctx->nameOfPip(uh),
|
||||||
ctx->nameOfWire(dest), pip_plane(uh));
|
ctx->nameOfWire(src), pip_plane(uh));
|
||||||
} else if (ctx->getBoundWireNet(dest) == nullptr) {
|
} else if (ctx->getBoundWireNet(src) == nullptr) {
|
||||||
ctx->bindPip(uh, clk_net, STRENGTH_LOCKED);
|
|
||||||
if (ctx->debug)
|
if (ctx->debug)
|
||||||
log_info(" bind pip %s --> %s (plane %hhd)\n", ctx->nameOfPip(uh),
|
log_info(" bind pip %s --> %s (plane %hhd)\n", ctx->nameOfPip(uh),
|
||||||
ctx->nameOfWire(dest), pip_plane(uh));
|
ctx->nameOfWire(src), pip_plane(uh));
|
||||||
|
ctx->bindPip(uh, clk_net, STRENGTH_LOCKED);
|
||||||
} else {
|
} else {
|
||||||
log_error("Can't bind pip %s because wire %s is already bound\n", ctx->nameOfPip(uh),
|
log_error("Can't bind pip %s because wire %s is already bound\n", ctx->nameOfPip(uh),
|
||||||
ctx->nameOfWire(dest));
|
ctx->nameOfWire(src));
|
||||||
}
|
}
|
||||||
if (dest == sink_wire)
|
if (src == src_wire)
|
||||||
break;
|
break;
|
||||||
|
src = ctx->getPipSrcWire(uh);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user