Fix multi-pin wire/owner desync in shove-in-rooms recovery
_shove_recover_room clobbered a net's _Accepted with a fresh one whose wire_owners held only the just-recovered wire, while its wires list (the shared result.wires[net_no]) already held earlier committed connections. That left wire_owners shorter than the parallel wires list, so a later net's shove either removed the wrong wire's copper from the search tree (a silent different-net short: copper stayed in the emitted SES but vanished from the tree, and has_violation falsely certified it clean) or raised IndexError and aborted the whole route. Reuse the net's existing _Accepted on recovery so wire_owners stays parallel to wires. Fixes both the silent DRC violation and the crash sibling without touching the DRC-clean or determinism invariants. Also correct the overstated "density win" framing of the shove_channel fixture: its plain-routing net drop is an artifact of greedy net order, not a density limit (the same board routes both nets with zero shoves under a reorder or with the cosmetic seals removed). Reframed the test and docstring; the genuine sub-cell win remains the wide_door occupancy packing (shoves == 0). Regression tests assert the invariant against the emitted output directly (reconstructed copper tiles), not just the tree that the bug fooled, plus determinism, no-crash, and the ordering-artifact bound.
This commit is contained in:
@@ -742,12 +742,20 @@ def _shove_recover_room(
|
||||
return 0
|
||||
|
||||
owners = force_place_owners(net_no, layer, corners, tree, owner, half_width)
|
||||
acc = _Accepted(
|
||||
wires=result.wires.setdefault(net_no, []), vias=result.vias.setdefault(net_no, [])
|
||||
)
|
||||
# Reuse this net's existing registry if it already committed connections, so
|
||||
# ``wire_owners`` stays parallel to ``wires``. Clobbering with a fresh
|
||||
# ``_Accepted`` here would leave ``wire_owners`` shorter than ``wires`` (its
|
||||
# ``result.wires[net_no]`` list already holds the earlier connections),
|
||||
# desyncing the two lists and making a later shove remove the wrong wire's
|
||||
# copper from the tree while it stays in the emitted route.
|
||||
acc = accepted.get(net_no) if accepted is not None else None
|
||||
if acc is None:
|
||||
acc = _Accepted(
|
||||
wires=result.wires.setdefault(net_no, []), vias=result.vias.setdefault(net_no, [])
|
||||
)
|
||||
accepted[net_no] = acc
|
||||
result.add_wire(net_no, layer, corners)
|
||||
acc.wire_owners.append(owners)
|
||||
accepted[net_no] = acc
|
||||
return len(journal) + 1
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user