mirror of https://github.com/YosysHQ/nextpnr.git
router2: fix no-op ripup of constant-net arcs
ripup_arc walks from the sink wire back to the net source, unbinding pips as it goes. For nets with constant_value set, the walk condition required every wire on the path to itself carry that constant value (getWireConstantValue(cursor) == net->constant_value). This is false for all general-purpose routing wires, so the walk terminated at the sink immediately and ripup never unbound anything. Consequences on congested designs with const routing (observed on himbaechel/xilinx, where GND/VCC use const-net mode): - re-routing the arc rebound the same path on top of itself, leaking one wire refcount per ripup/re-route cycle - congestion on contested constant tap wires could never resolve; the router livelocked with a handful of wires stuck overused for thousands of iterations Constant-net arc trees root at a tap wire bound with a null pip (the const_mode midpoint bind in route_arc), so terminate the walk there instead: walk to the net source as usual, and stop at the first null-pip binding. Hardware-verified on xc7a100t: a MEGA65 core port (~34k LCs) that previously livelocked (>3000 iterations, 6 wires pinned overused) now routes to 0 overused wires in ~30 iterations. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
68c1acd80a
commit
35cbbaec1f
|
|
@ -447,10 +447,19 @@ struct Router2
|
||||||
return;
|
return;
|
||||||
WireId src = nets.at(net->udata).src_wire;
|
WireId src = nets.at(net->udata).src_wire;
|
||||||
WireId cursor = ad.sink_wire;
|
WireId cursor = ad.sink_wire;
|
||||||
while (cursor != src &&
|
while (cursor != src) {
|
||||||
(net->constant_value == IdString() || ctx->getWireConstantValue(cursor) == net->constant_value)) {
|
|
||||||
PipId pip = nd.wires.at(cursor).first;
|
PipId pip = nd.wires.at(cursor).first;
|
||||||
unbind_pip_internal(nd, user, cursor);
|
unbind_pip_internal(nd, user, cursor);
|
||||||
|
// Constant nets have no global source; each arc's tree roots at a
|
||||||
|
// tap wire carrying the right constant value, bound with a null
|
||||||
|
// pip (see the const_mode midpoint bind in route_arc). The old
|
||||||
|
// condition here tested the const value on every wire from the
|
||||||
|
// sink up - false for all general routing - so the walk stopped
|
||||||
|
// immediately and ripup never unbound anything: rebinding the
|
||||||
|
// same path each iteration leaked one refcount per iteration and
|
||||||
|
// congestion on contested taps could never resolve.
|
||||||
|
if (pip == PipId())
|
||||||
|
break;
|
||||||
cursor = ctx->getPipSrcWire(pip);
|
cursor = ctx->getPipSrcWire(pip);
|
||||||
}
|
}
|
||||||
ad.routed = false;
|
ad.routed = false;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue