Add coordinated multi-trace channel packing to the room track
Greedy per-net room routing sends each net through a shared obstacle gap on its own independently chosen path; the paths collide and some nets drop even when the gap is physically wide enough for all of them. shove cannot fix this -- it relocates blockers into existing space, it does not pack lanes. Add an opt-in pre-pass (pack=True, independent of shove) that groups 2-pin nets which must cross a common gap, assigns each a parallel lane across the gap's usable width (pad-ordered so lanes never cross, spaced >= width + clearance) with staggered fan-in trunks so the converge/diverge jogs never overlap, and realizes each as an orthogonal trace verified exactly DRC-clean. Packing is all-or-nothing per group, so it never leaves a channel worse than greedy. With pack=False the pre-pass is skipped and the output is unchanged. Scope: single-layer 2-pin nets through one axis-aligned gap, with enough fan depth to stack the trunks. Threaded through route_dsn_board_rooms / build_rooms_routing_result / route(engine="room").
This commit is contained in:
@@ -141,31 +141,42 @@ def build_exact_routing_result(
|
||||
|
||||
|
||||
def route_dsn_board_rooms(
|
||||
dsn: DsnBoard, *, layers: list[int] | None = None, shove: bool = False
|
||||
dsn: DsnBoard, *, layers: list[int] | None = None, shove: bool = False, pack: 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. ``shove`` enables occupancy-
|
||||
aware gate placement and shove-in-rooms recovery of otherwise-dropped nets."""
|
||||
aware gate placement and shove-in-rooms recovery of otherwise-dropped nets.
|
||||
``pack`` enables the coordinated multi-trace channel packer."""
|
||||
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, shove=shove
|
||||
board,
|
||||
trace_width=width_board,
|
||||
clearance=clearance_board,
|
||||
layers=layers,
|
||||
shove=shove,
|
||||
pack=pack,
|
||||
)
|
||||
return rooms, scale, [layer.name for layer in dsn.layers]
|
||||
|
||||
|
||||
def build_rooms_routing_result(
|
||||
dsn: DsnBoard, *, layers: list[int] | None = None, shove: bool = False
|
||||
dsn: DsnBoard, *, layers: list[int] | None = None, shove: bool = False, pack: 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, shove=shove)
|
||||
rooms, scale, layer_names = route_dsn_board_rooms(dsn, layers=layers, shove=shove, pack=pack)
|
||||
return _to_routing_result(rooms.result, dsn, scale, layer_names)
|
||||
|
||||
|
||||
def route(
|
||||
dsn_text: str, *, layers: list[int] | None = None, engine: str = "grid", shove: bool = False
|
||||
dsn_text: str,
|
||||
*,
|
||||
layers: list[int] | None = None,
|
||||
engine: str = "grid",
|
||||
shove: bool = False,
|
||||
pack: bool = False,
|
||||
) -> str:
|
||||
"""Route a Specctra DSN string and return the routed SES string.
|
||||
|
||||
@@ -181,7 +192,7 @@ def route(
|
||||
if engine == "exact":
|
||||
result = build_exact_routing_result(dsn, layers=layers, shove=shove)
|
||||
elif engine == "room":
|
||||
result = build_rooms_routing_result(dsn, layers=layers, shove=shove)
|
||||
result = build_rooms_routing_result(dsn, layers=layers, shove=shove, pack=pack)
|
||||
else:
|
||||
result = build_routing_result(dsn, layers=layers)
|
||||
return write_ses(dsn, result)
|
||||
|
||||
Reference in New Issue
Block a user