Files
rpmroute/tests/route/test_negotiate.py
T
rsp2k 09c58ea630 --negotiate: PathFinder rounds on the empty board before routing
Every connection is routed N times on the empty board, where routes may
share cells at a price that doubles each round for every other net on a
cell, and a cell that stays shared gains history. The real routing then
pays that history on free cells, so the first routes stop taking the space
later routes (a fine-pitch part's escapes) have no way round. Off by
default.

The old history term never steered: it only accrued at rip-up fights,
after the first routes had claimed the contested space, and routed
connections are never revisited in later passes.
2026-10-03 14:45:59 -06:00

66 lines
2.5 KiB
Python

"""--negotiate: PathFinder-style rounds on the empty board before routing."""
from __future__ import annotations
from pathlib import Path
import pytest
from freeroute.board import build_board
from freeroute.dsn import parse_dsn
from freeroute.route.grid_router import GridRouter
from freeroute.route.pipeline import _rule_clearance_dsn, _rule_width_dsn, route_dsn_board
FIXTURES = Path(__file__).resolve().parent.parent / "dsn" / "fixtures"
def _router(name, negotiate):
dsn = parse_dsn((FIXTURES / name).read_text())
s = dsn.resolution.value
return GridRouter(
build_board(dsn),
trace_width=round(_rule_width_dsn(dsn) * s),
clearance=round(_rule_clearance_dsn(dsn) * s),
negotiate=negotiate,
)
def test_negotiation_leaves_the_board_empty_and_the_ends_as_they_were():
router = _router("true_density.dsn", 3)
conns = router._conns = router._build_connections()
ends = [(c.a_end, c.b_end) for c in conns]
router._negotiate(list(conns), conns)
assert router._history # a dense board has contested cells
assert not router._cell_owner and not router._halo and not router._via_claims
assert not any(c.routed for c in conns)
assert [(c.a_end, c.b_end) for c in conns] == ends
assert router._present is None
def test_sharing_is_priced_only_for_other_nets():
router = _router("true_density.dsn", 1)
node = (3, 4, 0)
router._history[node] = 2.0
router._present, router._present_cost = {node: {7: 1, 9: 2}}, 0.5
assert router._congestion(node, 7) == pytest.approx(2.5) # one other net
assert router._congestion(node, 5) == pytest.approx(3.0) # two other nets
router._present = None
assert router._congestion(node, 5) == pytest.approx(2.0) # history only, after
@pytest.mark.parametrize("name", ["ripup_needed.dsn", "true_density.dsn", "kicad_routable.dsn"])
def test_negotiated_routing_keeps_the_occupancy_honest(name):
"""Only routed connections hold cells afterwards, as without negotiation."""
router = _router(name, 3)
router.route()
conns = router._conns
assert all(conns[i].routed for i in router._cell_owner.values())
assert all(conns[i].routed for claims in router._halo.values() for i in claims)
def test_option_reaches_the_router_and_is_off_by_default():
text = (FIXTURES / "kicad_routable.dsn").read_text()
plain, _, _ = route_dsn_board(parse_dsn(text))
again, _, _ = route_dsn_board(parse_dsn(text), negotiate=0)
assert plain.unrouted == again.unrouted