Keep a route's own vias apart while it is searched
Committed vias were checked for hole spacing, but a route's own vias are not committed until it is done, so a route hopping layers (more of them on 6 layers) could put two of its vias 0.41 mm apart, as th-eda's 6-layer flight controller showed. A via is now also checked against layer changes earlier on its own route.
This commit is contained in:
@@ -538,6 +538,26 @@ class GridRouter:
|
||||
return False
|
||||
return self._holes_clear(cell, net_no)
|
||||
|
||||
def _near_path_via(self, node: Node, cell: Cell, came_from: dict) -> bool:
|
||||
"""A layer change earlier on the route that reaches ``node`` sits
|
||||
within hole spacing of ``cell`` (and is not the same through via).
|
||||
Committed vias are checked elsewhere; a route's own are not yet
|
||||
committed while it is searched. Looks back far enough to cover the
|
||||
hole spacing twice over, not along the whole route."""
|
||||
limit = 4 * (math.ceil(self._hole_need / self.step) + 1)
|
||||
need = self._hole_need / self.step
|
||||
steps = 0
|
||||
while node in came_from and steps < limit:
|
||||
prev = came_from[node]
|
||||
changes_layer = prev[:2] == node[:2] and prev[2] != node[2]
|
||||
if changes_layer and node[:2] != cell and (
|
||||
math.hypot(node[0] - cell[0], node[1] - cell[1]) < need
|
||||
):
|
||||
return True
|
||||
node = prev
|
||||
steps += 1
|
||||
return False
|
||||
|
||||
def _via_nets_at(self, cell: Cell) -> set[int]:
|
||||
nets = {net for net, n in self._via_nets.get(cell, {}).items() if n > 0}
|
||||
fixed = self._fixed_vias.get(cell)
|
||||
@@ -664,6 +684,8 @@ class GridRouter:
|
||||
pin = ends.get(node)
|
||||
if ok and isinstance(pin, Pin) and self._walled(node):
|
||||
ok = self._via_fits_at(pin.location, net_no)
|
||||
if ok and self._near_path_via(source, cell, came_from):
|
||||
ok = False # too close to a via earlier on this same route
|
||||
if ok:
|
||||
self._relax(source, target, g_via, goal_cell, g_score, came_from, open_heap)
|
||||
continue
|
||||
@@ -675,6 +697,8 @@ class GridRouter:
|
||||
ok = via_ok.get(cell)
|
||||
if ok is None:
|
||||
ok = via_ok[cell] = self._via_placeable(cell, net_no, conns)
|
||||
if ok and self._near_path_via(current, cell, came_from):
|
||||
ok = False
|
||||
else:
|
||||
ok = True
|
||||
if ok:
|
||||
|
||||
@@ -124,3 +124,13 @@ def test_hole_spacing_from_a_fixed_via_is_measured_from_where_it_really_is():
|
||||
assert not router._holes_clear(cell, 1), f"{d / s:.0f} um from the fixed via"
|
||||
elif 560 * s < d < 700 * s and cell not in router._tht_block:
|
||||
assert router._holes_clear(cell, 1)
|
||||
|
||||
|
||||
def test_a_route_keeps_its_own_vias_apart():
|
||||
# a route that changed layer at (10, 10) may not change layer again one
|
||||
# cell away; the same cell is the same through via, and far is fine
|
||||
router, _s = _router(_THT)
|
||||
came_from = {(10, 10, 1): (10, 10, 0), (11, 10, 1): (10, 10, 1), (12, 10, 1): (11, 10, 1)}
|
||||
assert router._near_path_via((12, 10, 1), (11, 10), came_from)
|
||||
assert not router._near_path_via((12, 10, 1), (10, 10), came_from)
|
||||
assert not router._near_path_via((12, 10, 1), (40, 10), came_from)
|
||||
|
||||
Reference in New Issue
Block a user