Files
rpmroute/tests/route/test_fixed_wiring.py
T

109 lines
5.0 KiB
Python

"""Tracks and vias already on the board (the DSN's wiring) are fixed copper."""
from __future__ import annotations
from freeroute.board import build_board
from freeroute.dsn import parse_dsn
from freeroute.route.pipeline import route_dsn_board_exact
_DSN = """(pcb wired (parser) (resolution um 10) (unit um)
(structure
(layer F.Cu (type signal)) (layer B.Cu (type signal))
(boundary (path pcb 0 0 0 30000 0 30000 -20000 0 -20000 0 0))
(via "Via[0-1]_600:300_um") (rule (width 250) (clearance 200)))
(placement (component S (place A1 5000 -10000 front 0) (place A2 25000 -10000 front 0)))
(library
(image S (pin smd 1 0 0))
(padstack smd (shape (rect F.Cu -400 -400 400 400)) (attach off))
(padstack "Via[0-1]_600:300_um" (shape (circle F.Cu 600)) (shape (circle B.Cu 600)) (attach off)))
(network (net SIG (pins A1-1 A2-1)) (net GND))
(wiring
(wire (path F.Cu 400 15000 0 15000 -20000) (net GND) (type route))
(via "Via[0-1]_600:300_um" 8000 -14000 (net GND) (type route))))"""
def test_wiring_is_read_with_its_nets():
dsn = parse_dsn(_DSN)
assert [(w.net, w.layer, w.width) for w in dsn.wires] == [("GND", "F.Cu", 400.0)]
assert [(v.net, v.x, v.y) for v in dsn.vias] == [("GND", 8000.0, -14000.0)]
def test_wiring_is_fixed_copper_and_not_a_connection_to_route():
board = build_board(parse_dsn(_DSN))
copper = board.get_fixed_copper()
gnd = next(n.net_number for n in board.nets if n.name == "GND")
assert copper and all(net == gnd for net, _, _ in copper)
assert not any(gnd in p.net_nos for p in board.get_pins())
def test_other_nets_route_around_a_fixed_track():
dsn = parse_dsn(_DSN)
exact, scale, names = route_dsn_board_exact(dsn, resolution=2)
sig = next(i + 1 for i, n in enumerate(dsn.nets) if n.name == "SIG")
assert sig in exact.result.routed_net_numbers
assert exact.drc_clean
wall = 15000 * scale
for layer, pts in exact.result.wires.get(sig, []):
if names[layer] != "F.Cu":
continue
for p, q in zip(pts, pts[1:], strict=False):
assert not (min(p.x, q.x) < wall < max(p.x, q.x)), "crossed the GND track on F.Cu"
# --- fixed wiring as connectivity ------------------------------------------
_FANOUT = """(pcb fanout (parser) (resolution um 10) (unit um)
(structure
(layer F.Cu (type signal)) (layer In1.Cu (type power)) (layer In2.Cu (type power))
(layer B.Cu (type signal))
(boundary (path pcb 0 0 0 30000 0 30000 -20000 0 -20000 0 0))
(plane GND (polygon In1.Cu 0 500 -500 29500 -500 29500 -19500 500 -19500 500 -500))
(via "Via[0-3]_600:300_um") (rule (width 150) (clearance 150)))
(placement (component S (place G1 5000 -10000 front 0) (place A 10000 -10000 front 0)
(place B 25000 -11500 back 0)))
(library
(image S (pin smd 1 0 0))
(padstack smd (shape (rect F.Cu -300 -300 300 300)) (attach off))
(padstack "Via[0-3]_600:300_um" (shape (circle F.Cu 600)) (shape (circle B.Cu 600)) (attach off)))
(network (net GND (pins G1-1)) (net SIG (pins A-1 B-1)))
(wiring
(wire (path F.Cu 150 5000 -10000 5000 -11500) (net GND) (type route))
(via "Via[0-3]_600:300_um" 5000 -11500 (net GND) (type route))
(wire (path F.Cu 150 10000 -10000 10000 -11500) (net SIG) (type route))
(via "Via[0-3]_600:300_um" 10000 -11500 (net SIG) (type route))
(wire (path F.Cu 300 2000 -2000 8000 -2000) (net GND) (type route))))"""
def test_a_pad_fanned_out_to_its_plane_needs_no_route():
dsn = parse_dsn(_FANOUT)
exact, _scale, _names = route_dsn_board_exact(dsn, resolution=2)
gnd = next(i + 1 for i, n in enumerate(dsn.nets) if n.name == "GND")
assert exact.result.failed == []
assert not exact.result.vias.get(gnd) and not exact.result.wires.get(gnd)
def test_a_fanned_out_signal_is_routed_from_its_via():
# B is on the bottom face, level with A's fan-out via: starting from that
# via on B.Cu is the cheapest way, and needs no via of its own
dsn = parse_dsn(_FANOUT)
exact, scale, names = route_dsn_board_exact(dsn, resolution=2)
sig = next(i + 1 for i, n in enumerate(dsn.nets) if n.name == "SIG")
assert sig in exact.result.routed_net_numbers
assert not exact.result.vias.get(sig), "the fan-out via is already there"
assert {names[layer] for layer, _ in exact.result.wires[sig]} == {"B.Cu"}
def test_the_session_never_repeats_copper_already_on_the_board():
# the JAR writes the DSN's wiring back into its session, and an applier
# then adds it a second time on top of itself; freeroute writes only
# what it routed
from freeroute.route.pipeline import build_exact_routing_result
fixed_vias = {(5000.0, -11500.0), (10000.0, -11500.0)}
fixed_paths = {(5000.0, -10000.0, 5000.0, -11500.0), (10000.0, -10000.0, 10000.0, -11500.0),
(2000.0, -2000.0, 8000.0, -2000.0)}
result = build_exact_routing_result(parse_dsn(_FANOUT), resolution=2)
for net in result.nets:
assert not {(v.x, v.y) for v in net.vias} & fixed_vias
assert not {tuple(w.coords) for w in net.wires} & fixed_paths