Add gate-optimal placement and shove-in-rooms to the room router
Both upgrades sit behind an opt-in shove=False flag, so the default code path is byte-for-byte the foundation router (existing room tests are unchanged by construction). With shove=True: - Gate placement becomes occupancy-aware: each edge gate is projected into the largest other-net-free sub-span of the door, with the reserved intervals read straight from the search tree. With margin = clearance + half_width the room decomposition already keeps doors clearance-clear, so this reduces exactly to the old midpoint clamp where no other-net copper crosses the door. - When a net would be dropped, a transactional shove-in-rooms recovery nudges the committed trace(s) blocking it aside with the exact shove primitive and re-verifies against the clearance oracle, so both nets fit through one channel. Every moved trace is journaled and rolled back to its exact original tiles and wires on any failure -- the room engine mutates already-committed nets, so the rollback is real rather than the exact track's no-op. The board-wide has_violation(clearance) gate stays the final assertion. Thread the flag through pipeline.route_dsn_board_rooms / build_rooms_routing_result / route(engine='room', shove=...).
This commit is contained in:
@@ -141,23 +141,26 @@ def build_exact_routing_result(
|
||||
|
||||
|
||||
def route_dsn_board_rooms(
|
||||
dsn: DsnBoard, *, layers: list[int] | None = None
|
||||
dsn: DsnBoard, *, layers: list[int] | None = None, shove: bool = False
|
||||
) -> tuple[ExactRouteResult, int, list[str]]:
|
||||
"""Route a parsed :class:`DsnBoard` with the continuous expansion-room track;
|
||||
return the result, the scale, and layer names."""
|
||||
return the result, the scale, and layer names. ``shove`` enables occupancy-
|
||||
aware gate placement and shove-in-rooms recovery of otherwise-dropped nets."""
|
||||
board = build_board(dsn)
|
||||
scale = max(dsn.resolution.value, 1)
|
||||
width_board = round(_rule_width_dsn(dsn) * scale)
|
||||
clearance_board = round(_rule_clearance_dsn(dsn) * scale)
|
||||
rooms = route_board_rooms(
|
||||
board, trace_width=width_board, clearance=clearance_board, layers=layers
|
||||
board, trace_width=width_board, clearance=clearance_board, layers=layers, shove=shove
|
||||
)
|
||||
return rooms, scale, [layer.name for layer in dsn.layers]
|
||||
|
||||
|
||||
def build_rooms_routing_result(dsn: DsnBoard, *, layers: list[int] | None = None) -> RoutingResult:
|
||||
def build_rooms_routing_result(
|
||||
dsn: DsnBoard, *, layers: list[int] | None = None, shove: bool = False
|
||||
) -> RoutingResult:
|
||||
"""Route ``dsn`` (room track) and convert to a DSN-unit RoutingResult."""
|
||||
rooms, scale, layer_names = route_dsn_board_rooms(dsn, layers=layers)
|
||||
rooms, scale, layer_names = route_dsn_board_rooms(dsn, layers=layers, shove=shove)
|
||||
return _to_routing_result(rooms.result, dsn, scale, layer_names)
|
||||
|
||||
|
||||
@@ -171,13 +174,14 @@ def route(
|
||||
``"exact"`` (orthogonal, exact-geometry, DRC-verified — cleaner output where
|
||||
it succeeds), or ``"room"`` (continuous expansion-room — exact free-space
|
||||
decomposition, routes off-grid channels the grid/exact tracks cannot).
|
||||
``shove`` (exact engine only) tries moving existing traces aside.
|
||||
``shove`` (exact and room engines) tries moving existing traces aside; on the
|
||||
room engine it also turns on occupancy-aware gate placement.
|
||||
"""
|
||||
dsn = parse_dsn(dsn_text)
|
||||
if engine == "exact":
|
||||
result = build_exact_routing_result(dsn, layers=layers, shove=shove)
|
||||
elif engine == "room":
|
||||
result = build_rooms_routing_result(dsn, layers=layers)
|
||||
result = build_rooms_routing_result(dsn, layers=layers, shove=shove)
|
||||
else:
|
||||
result = build_routing_result(dsn, layers=layers)
|
||||
return write_ses(dsn, result)
|
||||
|
||||
Reference in New Issue
Block a user