Source code for jitxexamples.demos.si_bga_optimization.bga_escape

"""BGA escape-port design.

Top-level circuit + design for an HDI BGA fanout experiment. Each
signal row-pair on the BGA gets a per-lane ``EscapeLane`` child Circuit
that owns the lane-local geometric features: signal-via antipad
``KeepOut`` list, deskew ``OverlappableCopper`` pair, and the deskew-
antipad ``KeepOut``. Every cross-lane JITX object — diff-pair ``Net``,
signal-via and pair/insertion-control ``PortAttachment``s,
``PairPoint`` / ``PairInsertion`` / ``Route`` triple, the deskew-copper
``VirtualConnection``s, and the upper-reference and deskew fence
``Pour``s — is constructed and owned
by ``BGALink``, since JITX requires each ``Net`` / ``PortAttachment`` /
``Pour`` to live on the common ancestor of every ``Port`` it touches
and the BGA Component sits at ``BGALink`` level. The diff pairs carry
the 85 ohm differential routing structure via a tag rule
(``StriplineDiffPairTag``) rather than an explicit ``>>`` topology, so
no far-end terminal component is needed.

The design-specific code is split by concern across this package:
design-rule tags and the antipad fence-via ``design_constraint`` rules
in ``constraints``, the substrate specialization (``BGAEscapeSubstrate``
with its routing structures and launch profiles, anchoring those rules)
in ``substrate``, and per-lane geometry constants and helpers —
including the HFSS-instrumented-lane override — in ``si_geometry``.
This file owns the per-lane ``EscapeLane`` and top-level ``BGALink``
circuit assembly plus the buildable ``bga_optimization_design`` entry
point.
"""

import jitx
from jitx import KeepOut, LayerSet, Pour
from jitx.circuit import Circuit, Route
from jitx.controlpoint import PairInsertion, PairPoint
from jitx.constraints import design_constraint
from jitx.net import Net, PortAttachment
from jitx.sample import SampleDesign
from jitx.shapes.composites import rectangle
from jitx.shapes.shapely import ShapelyGeometry
from jitx.via import Via
from jitx.virtual import VirtualConnection
from . import generic_bga as bga
from .constraints import StriplineDiffPairTag
from .deskew import deskew_pair
from .generic_bga import GenericHexGridBGA
from .si_geometry import (
    DESKEW_EXIT_ABOVE_LOWER_BALL,
    DESKEW_PAIR_SPACING,
    DESKEW_TRACE_WIDTH,
    DESKEW_VIA_PAD_TO_TRACE_GAP,
    INSTRUMENTED_SIGNAL2_L1_D_OUTWARD_RADIUS,
    INSTRUMENTED_SIGNAL2_SPLIT_ANTIPAD_RADIUS,
    SIGNAL_VIA_FENCE_RADIUS,
    SIGNAL_VIA_KEEPOUT_RADIUS,
    SIGNAL_VIA_PAD_DIAMETER,
    deskew_antipad_keepout_and_pour_shape,
    deskew_knobs,
    gnd_pad_via_sites,
    instrumented_l1_d_keepouts,
    is_instrumented_lane,
    make_si_cutout,
    signal_via_pair_antipad_keepouts,
    signal_via_pair_capsule,
)
from .substrate import BGAEscapeSubstrate, PerSignalLayerSpec


# -----------------------------------------------------------------------------
# Per-lane circuit + top-level assembly.
# -----------------------------------------------------------------------------


[docs] class EscapeLane(Circuit): """One BGA escape lane. Owns the lane-local geometric features: signal-via antipad ``KeepOut`` list, deskew ``OverlappableCopper`` pair, and the deskew-antipad ``KeepOut``. These have no port references and live cleanly inside this child Circuit. Every other JITX object that touches a lane — the diff-pair ``Net``, the signal-via and pair/insertion-control ``PortAttachment``s, the ``PairPoint`` / ``PairInsertion`` / ``Route`` triple, and the upper-reference / deskew fence ``Pour``s — is constructed and owned by ``BGALink``. JITX's structural rules require these objects to live on the common ancestor of every ``Port`` they touch (``BGALink`` for objects that reference the BGA's diff-pair Ports; the Net's owner for Pours), and control / route elements turn out not to be valid inside a non-net-owning child Circuit either. Each lane exposes the data ``BGALink`` needs (``p_pad``, ``n_pad``, ``spec``, ``signal_via_fence_shape``, ``deskew_fence_pour_shape``, ``deskew_left_exit``, ``deskew_right_exit``) — plain Python values that JITX does not walk as structural children. Built from the lane's signal-via pad coordinates, the per-signal- layer launch ``spec``, and the deskew-arc parameters (caller derives these from ``deskew_knobs(lane_index)``). The instrumented- lane override (mirrored L1 D-cuts plus enlarged L2/L3 circular cuts) is enabled by ``is_instrumented``. """ def __init__( self, *, p_pad: tuple[float, float], n_pad: tuple[float, float], spec: PerSignalLayerSpec, theta_exit_deg: float, right_r_wrap: float, is_instrumented: bool = False, ): # Expose the launch parameters for ``BGALink`` to read when # building the Nets, PortAttachments, control points, Routes, # and Pours that must live on the common ancestor. These are # non-JITX data attributes (ints, tuples of floats, references # to module-level types). self.p_pad = p_pad self.n_pad = n_pad self.spec = spec # Signal-via antipad: capsule keepout at the baseline radius, # plus per-via circular cuts on the upper reference planes when # ``split_antipad_layers`` is set (default for Signal2+). The # instrumented lane on Signal2 swaps the L1 row for mirrored # D-cuts (decoupling L1 from the L2/L3 circular pair) and # enlarges the L2/L3 circles to the physics-sized radius. keepout_shape = signal_via_pair_capsule(p_pad, n_pad, SIGNAL_VIA_KEEPOUT_RADIUS) split_keepout_radius = SIGNAL_VIA_KEEPOUT_RADIUS split_antipad_layers = spec.split_antipad_layers fence_radius = SIGNAL_VIA_FENCE_RADIUS deskew_antipad_radius = fence_radius extra_keepouts: list[KeepOut] = [] if is_instrumented: split_keepout_radius = INSTRUMENTED_SIGNAL2_SPLIT_ANTIPAD_RADIUS split_antipad_layers = LayerSet(1, 2) fence_radius = INSTRUMENTED_SIGNAL2_L1_D_OUTWARD_RADIUS # Decouple the L4 deskew antipad from the enlarged reference- # plane fence perimeter so the L4 cut stays sized to actual # deskew copper + buffer. deskew_antipad_radius = SIGNAL_VIA_KEEPOUT_RADIUS extra_keepouts = instrumented_l1_d_keepouts(p_pad, n_pad) fence_shape = signal_via_pair_capsule(p_pad, n_pad, fence_radius) deskew_antipad_shape = ( fence_shape if deskew_antipad_radius == fence_radius else signal_via_pair_capsule(p_pad, n_pad, deskew_antipad_radius) ) antipad_keepouts = signal_via_pair_antipad_keepouts( keepout_shape, spec, p_pad=p_pad, n_pad=n_pad, split_keepout_radius=split_keepout_radius, split_antipad_layers=split_antipad_layers, ) antipad_keepouts.extend(extra_keepouts) self.antipad_keepouts = antipad_keepouts # Exposed for ``BGALink`` to use when constructing the upper- # reference fence Pour. ``None`` for Signal1 (no via spans above # its launch layer); see ``PerSignalLayerSpec``. self.signal_via_fence_shape: ShapelyGeometry | None = ( fence_shape if spec.upper_ref_fence_pour_layer is not None else None ) # Deskew geometry. ``deskew_pair`` returns a transient bundle of # copper + exit coordinates; destructure its fields into named # members so JITX's structural walk discovers the copper directly. deskew = deskew_pair( right_pad=p_pad, left_pad=n_pad, theta_exit_deg=theta_exit_deg, right_r_wrap=right_r_wrap, exit_above_lower=DESKEW_EXIT_ABOVE_LOWER_BALL, exit_ball_clearance=DESKEW_VIA_PAD_TO_TRACE_GAP - SIGNAL_VIA_PAD_DIAMETER / 2, layer=spec.deskew_layer, trace_w=DESKEW_TRACE_WIDTH, pair_spacing=DESKEW_PAIR_SPACING, ) self.right_deskew_copper = deskew.right_copper self.left_deskew_copper = deskew.left_copper self.deskew_antipad_keepout, self.deskew_fence_pour_shape = ( deskew_antipad_keepout_and_pour_shape( deskew.right_copper, deskew.left_copper, deskew_antipad_shape, fence_shape, spec, ) ) # Expose the deskew exit coordinates so ``BGALink`` can place # the ``PairPoint`` (at the exit midpoint) and ``PairInsertion`` # (at the board edge below) on the deskew layer. self.deskew_right_exit = deskew.right_exit self.deskew_left_exit = deskew.left_exit
# Pour ranks resolve which pour renders when two overlap on the same # layer; higher wins. Independent from constraint ``priority`` (which # resolves fence-via dedup at coincident XY). _ANTIPAD_FENCE_POUR_RANK = 4 _DESKEW_ANTIPAD_FENCE_POUR_RANK = _ANTIPAD_FENCE_POUR_RANK + 10
[docs] class bga_optimization_design(SampleDesign): substrate = BGAEscapeSubstrate() circuit = BGALink()