--fanout: only packages of --fanout-min-pins or more; supply-only mode; vias for signals that change layer
This commit is contained in:
@@ -43,6 +43,10 @@ class FanoutRules:
|
||||
edge_clearance: int
|
||||
signal_layers: list[int]
|
||||
via_padstack: str
|
||||
#: smallest package fanned out (a big dense part is where pins get walled in)
|
||||
min_pins: int = 32
|
||||
#: fan out plane pins only (a stub and a via each), as a person would first
|
||||
supply_only: bool = False
|
||||
|
||||
|
||||
def plan_fanout(board: BasicBoard, rules: FanoutRules) -> list:
|
||||
@@ -54,7 +58,12 @@ def plan_fanout(board: BasicBoard, rules: FanoutRules) -> list:
|
||||
if z.net_nos and not board.layer_structure.arr[z.layer].is_signal:
|
||||
planes.setdefault(z.net_nos[0], []).append(z)
|
||||
placed = _Placed(board, rules)
|
||||
by_net: dict[int, list[Pin]] = {}
|
||||
for pin in board.get_pins():
|
||||
for n in pin.net_nos:
|
||||
by_net.setdefault(n, []).append(pin)
|
||||
items: list = []
|
||||
pitch = 2 * rules.via_half + rules.hole_to_hole
|
||||
for pins in _packages(board, rules).values():
|
||||
centre = IntPoint(
|
||||
sum(p.location.x for p in pins) // len(pins), sum(p.location.y for p in pins) // len(pins)
|
||||
@@ -68,22 +77,27 @@ def plan_fanout(board: BasicBoard, rules: FanoutRules) -> list:
|
||||
reach = _pad_reach(pin, direction) + rules.clearance + half + rules.trace_width
|
||||
end = _step(pin.location, direction, reach)
|
||||
plane = planes.get(net)
|
||||
if plane is not None:
|
||||
# stagger the via of every other pin along the side outward
|
||||
pitch = 2 * rules.via_half + rules.hole_to_hole
|
||||
options = [reach + rules.via_half + rules.clearance + (k % 2) * pitch,
|
||||
reach + rules.via_half + rules.clearance + ((k + 1) % 2) * pitch]
|
||||
for d in options:
|
||||
at = _step(pin.location, direction, d)
|
||||
if not any(z.polygon is not None and z.polygon.contains(at) for z in plane):
|
||||
continue
|
||||
if placed.stub_fits(pin.location, at, layer, net, half) and placed.via_fits(at, net):
|
||||
items.append(placed.add_stub(pin.location, at, layer, net, half))
|
||||
items.append(placed.add_via(at, net))
|
||||
break
|
||||
partners = [q for q in by_net.get(net, []) if q is not pin]
|
||||
# a signal whose other pins are all on other layers has to change
|
||||
# layer somewhere: do it at the stub's end, away from the pads
|
||||
elsewhere = bool(partners) and all(layer not in q.layers for q in partners)
|
||||
if plane is None and (rules.supply_only or not elsewhere):
|
||||
if not rules.supply_only and placed.stub_fits(pin.location, end, layer, net, half):
|
||||
items.append(placed.add_stub(pin.location, end, layer, net, half))
|
||||
continue
|
||||
if placed.stub_fits(pin.location, end, layer, net, half):
|
||||
items.append(placed.add_stub(pin.location, end, layer, net, half))
|
||||
# stagger the via of every other pin along the side outward
|
||||
options = [reach + rules.via_half + rules.clearance + (k % 2) * pitch,
|
||||
reach + rules.via_half + rules.clearance + ((k + 1) % 2) * pitch]
|
||||
for d in options:
|
||||
at = _step(pin.location, direction, d)
|
||||
if plane is not None and not any(
|
||||
z.polygon is not None and z.polygon.contains(at) for z in plane
|
||||
):
|
||||
continue
|
||||
if placed.stub_fits(pin.location, at, layer, net, half) and placed.via_fits(at, net):
|
||||
items.append(placed.add_stub(pin.location, at, layer, net, half))
|
||||
items.append(placed.add_via(at, net))
|
||||
break
|
||||
return items
|
||||
|
||||
|
||||
@@ -100,7 +114,7 @@ def _packages(board: BasicBoard, rules: FanoutRules) -> dict[str, list[Pin]]:
|
||||
fine = _FINE_PITCH_FACTOR * (rules.trace_width + 2 * rules.clearance)
|
||||
out = {}
|
||||
for ref, pins in by_ref.items():
|
||||
if len(pins) < _MIN_PINS:
|
||||
if len(pins) < max(rules.min_pins, _MIN_PINS):
|
||||
continue
|
||||
close = sum(
|
||||
1 for p in pins
|
||||
|
||||
Reference in New Issue
Block a user