--window-reroute N: route a finer grid around each connection still stuck
After the exact engine, every net routed wholly inside a window around a stuck connection's pins is ripped, the rest of the board is laid down as fixed copper, and the window alone is routed again at --window-resolution (default 4) with the stuck net and the ripped nets only. The result is kept only if fewer connections are left unrouted; each round doubles the margin. The grid and exact routers gain only_nets and bounds for it. Off by default.
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
"""Window re-route: a finer grid around a stuck connection, kept only when
|
||||
it leaves fewer connections unrouted."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from freeroute.board import build_board
|
||||
from freeroute.dsn import parse_dsn
|
||||
from freeroute.geometry import IntBox
|
||||
from freeroute.route.grid_router import GridRouter
|
||||
from freeroute.route.pipeline import _rule_clearance_dsn, _rule_width_dsn, route_dsn_board_exact
|
||||
|
||||
|
||||
def _slot(gap: int = 640, far: bool = False) -> str:
|
||||
"""A wall across the board with a slot in it. A trace fits the slot
|
||||
only along a narrow band of heights that the board's 1x grid has no row
|
||||
in and a 4x grid does. ``far`` adds a second net nowhere near the wall."""
|
||||
yc = -5000
|
||||
lo, hi = yc - gap // 2, yc + gap // 2
|
||||
extra_place = "(place Q1 2000 -1000 front 0) (place Q2 6000 -1000 front 0)" if far else ""
|
||||
extra_net = "(net M (pins Q1-1 Q2-1))" if far else ""
|
||||
return f"""(pcb "slot.dsn"
|
||||
(parser (string_quote ") (space_in_quoted_tokens on) (host_cad "t") (host_version "1"))
|
||||
(resolution um 10)
|
||||
(unit um)
|
||||
(structure
|
||||
(layer F.Cu (type signal) (property (index 0)))
|
||||
(boundary (path pcb 0 0 0 20000 0 20000 -10000 0 -10000 0 0))
|
||||
(keepout "" (rect F.Cu 9000 -10000 11000 {lo}))
|
||||
(keepout "" (rect F.Cu 9000 {hi} 11000 0))
|
||||
(rule (width 200) (clearance 200))
|
||||
)
|
||||
(library
|
||||
(padstack Rect_Pad (shape (rect F.Cu -100 -100 100 100)) (attach off))
|
||||
(image PAD (pin Rect_Pad 1 0 0))
|
||||
)
|
||||
(placement
|
||||
(component PAD
|
||||
(place P1 3000 {yc} front 0)
|
||||
(place P2 17000 {yc} front 0)
|
||||
{extra_place}
|
||||
)
|
||||
)
|
||||
(network
|
||||
(net N (pins P1-1 P2-1))
|
||||
{extra_net}
|
||||
(class default (rule (width 200) (clearance 200)))
|
||||
)
|
||||
(wiring)
|
||||
)
|
||||
"""
|
||||
|
||||
|
||||
def _route(text: str, rounds: int):
|
||||
exact, _scale, _layers = route_dsn_board_exact(
|
||||
parse_dsn(text), resolution=1, window_reroute=rounds, window_resolution=4,
|
||||
)
|
||||
return exact.result
|
||||
|
||||
|
||||
def test_the_board_grid_misses_the_slot_and_a_finer_window_finds_it():
|
||||
plain = _route(_slot(), 0)
|
||||
assert len(plain.failed) == 1
|
||||
windowed = _route(_slot(), 1)
|
||||
assert windowed.failed == []
|
||||
assert windowed.wires # and the copper it found is in the result
|
||||
|
||||
|
||||
def test_a_window_that_cannot_help_leaves_the_board_as_it_was():
|
||||
plain = _route(_slot(gap=500, far=True), 0) # too narrow for any grid
|
||||
windowed = _route(_slot(gap=500, far=True), 2)
|
||||
assert len(windowed.failed) == len(plain.failed) == 1
|
||||
assert windowed.wires == plain.wires
|
||||
assert windowed.vias == plain.vias
|
||||
|
||||
|
||||
def test_copper_outside_the_window_is_kept_as_it_was():
|
||||
plain = _route(_slot(far=True), 0)
|
||||
windowed = _route(_slot(far=True), 1)
|
||||
assert windowed.failed == []
|
||||
far_net = 2 # M, the second net in the DSN
|
||||
assert windowed.wires[far_net] == plain.wires[far_net]
|
||||
|
||||
|
||||
def test_a_router_limited_to_some_nets_and_a_box_builds_only_those():
|
||||
dsn = parse_dsn(_slot(far=True))
|
||||
s = dsn.resolution.value
|
||||
board = build_board(dsn)
|
||||
whole = GridRouter(board, trace_width=round(_rule_width_dsn(dsn) * s),
|
||||
clearance=round(_rule_clearance_dsn(dsn) * s), orthogonal=True)
|
||||
part = GridRouter(board, trace_width=round(_rule_width_dsn(dsn) * s),
|
||||
clearance=round(_rule_clearance_dsn(dsn) * s), orthogonal=True,
|
||||
only_nets=frozenset({2}), bounds=IntBox(0, -20000, 80000, 0))
|
||||
assert {c.net_no for c in whole._build_connections()} == {1, 2}
|
||||
assert {c.net_no for c in part._build_connections()} == {2}
|
||||
assert part.cols * part.rows < whole.cols * whole.rows
|
||||
Reference in New Issue
Block a user