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;
|
||||
WireId src = nets.at(net->udata).src_wire;
|
||||
WireId cursor = ad.sink_wire;
|
||||
while (cursor != src &&
|
||||
(net->constant_value == IdString() || ctx->getWireConstantValue(cursor) == net->constant_value)) {
|
||||
while (cursor != src) {
|
||||
PipId pip = nd.wires.at(cursor).first;
|
||||
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);
|
||||
}
|
||||
ad.routed = false;
|
||||
|
|
|
|||
Loading…
Reference in New Issue