Check plane and in-pad vias where they will actually go
A start that was already a plane end joined the plane at once, with no check that its via fits: under a sensor's via keepout the via went in the pad and the exact check refused it. A via leaving or reaching a walled-in pin goes in that pin's pad, but was only checked at the grid cell's centre; it is now checked exactly at the pin against via keepouts and other nets' pads and fixed copper.
This commit is contained in:
@@ -311,6 +311,9 @@ class GridRouter:
|
||||
self._via_edge_block: set[Cell] = set()
|
||||
# wire keepouts as boxes, to check a pin stub the way the exact engine will
|
||||
self._keepout_boxes: dict[int, list[tuple[IntBox, bool]]] = {}
|
||||
# via keepouts as boxes, and other copper a via in a pad must clear
|
||||
self._via_keepout_boxes: list[tuple[IntBox, bool]] = []
|
||||
self._static_copper: list[tuple[IntBox, int]] | None = None
|
||||
# pin end nodes no wire can reach without entering a keepout
|
||||
self._via_only: set[Node] = set()
|
||||
if outline is not None:
|
||||
@@ -360,6 +363,8 @@ class GridRouter:
|
||||
self._keepout.add((*cell, item.layer))
|
||||
if item.blocks_vias:
|
||||
self._via_keepout.add((*cell, item.layer))
|
||||
if item.blocks_vias:
|
||||
self._via_keepout_boxes.append((box, item.clearance))
|
||||
|
||||
def _rasterize_fixed_copper(self) -> None:
|
||||
"""Tracks and vias already on the board: copper of their net, which
|
||||
@@ -452,7 +457,14 @@ class GridRouter:
|
||||
goals = self._group_ends(conn.b_group, conn.net_no, conns)
|
||||
if not starts or not goals:
|
||||
return None
|
||||
common = sorted(set(starts) & set(goals))
|
||||
# A start that is already an end joins at once, except that ending on
|
||||
# a plane there needs a via: one that cannot be placed (a via keepout,
|
||||
# another net's pad) is no end, and the search goes on from there.
|
||||
common = [
|
||||
n for n in sorted(set(starts) & set(goals))
|
||||
if not isinstance(goals[n], ConductionArea)
|
||||
or self._via_placeable((n[0], n[1]), conn.net_no, conns)
|
||||
]
|
||||
if common:
|
||||
conn.a_end, conn.b_end = starts[common[0]], goals[common[0]]
|
||||
return [common[0]]
|
||||
@@ -485,6 +497,12 @@ class GridRouter:
|
||||
ok = via_ok.get(cell)
|
||||
if ok is None:
|
||||
ok = via_ok[cell] = self._via_placeable(cell, net_no, conns)
|
||||
# a via leaving or reaching a walled-in pin goes in its pad
|
||||
# (see _commit), so it has to fit there exactly
|
||||
for node, ends in ((source, starts), (target, goals)):
|
||||
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:
|
||||
self._relax(source, target, g_via, goal_cell, g_score, came_from, open_heap)
|
||||
continue
|
||||
@@ -548,6 +566,29 @@ class GridRouter:
|
||||
# copper too, or a stub ends up closer than clearance to a trace in the
|
||||
# cell beside it.
|
||||
|
||||
def _walled(self, node: Node) -> bool:
|
||||
"""A pin end no wire may leave or reach: only a via in its pad will do."""
|
||||
return node in self._keepout or node in self._via_only
|
||||
|
||||
def _via_fits_at(self, point: IntPoint, net_no: int) -> bool:
|
||||
"""A via centred exactly on ``point`` clears every via keepout and all
|
||||
other nets' pads and fixed copper (what a via in a pad must meet)."""
|
||||
via = IntBox(point.x - self.via_half, point.y - self.via_half,
|
||||
point.x + self.via_half, point.y + self.via_half)
|
||||
grown = via.offset(self.clearance)
|
||||
for box, needs in self._via_keepout_boxes:
|
||||
if box.overlaps(grown if needs else via):
|
||||
return False
|
||||
if self._static_copper is None:
|
||||
copper = [
|
||||
(p.shape.bounding_box(), p.net_nos[0] if p.net_nos else -1)
|
||||
for p in self.board.get_pins()
|
||||
if p.shape is not None and any(layer in self.layers for layer in p.layers)
|
||||
]
|
||||
copper += [(box, net) for net, _, box in self.board.get_fixed_copper()]
|
||||
self._static_copper = copper
|
||||
return not any(net != net_no and box.overlaps(grown) for box, net in self._static_copper)
|
||||
|
||||
def _stub_cells(self, pin_location: IntPoint, cell: Cell) -> list[Cell]:
|
||||
"""Cells where another net's trace would come too close to the stub."""
|
||||
from freeroute.board.outline import _point_segment
|
||||
|
||||
Reference in New Issue
Block a user