Source code for jitxexamples.substrates.generic_20layer

"""Generic 20-layer substrate.

Explicit-symmetry stack: 20 conductor layers about a thick core, one
generic dielectric (Dk 3.0) throughout, 0.5 oz copper on every layer,
0.8 mm core. The upper half (L1..L10) interleaves ground/signal planes
with L1 as outer ground and L10 adjacent to the core as a power plane;
L11..L20 are the explicit mirror. The substrate exposes the HDI via
families needed for top-side BGA escape via the ``signal_via`` and
``gnd_via`` accessors so designs query the substrate instead of
mirroring tables.
"""

from jitx.stackup import Stackup, Conductor, Dielectric
from jitx.substrate import Substrate, FabricationConstraints
from jitx.via import Via, ViaType
from jitx.si import PinModel
from jitx.layerindex import Side
from jitxlib.physics import phase_velocity


# -----------------------------------------------------------------------------
# Materials
# -----------------------------------------------------------------------------


[docs] class GenericDielectric(Dielectric): """Generic low-loss dielectric -- Dk 3.0, tan delta 0.004.""" dielectric_coefficient = 3.0 loss_tangent = 0.004
[docs] class SolderMask(Dielectric): """Generic soldermask.""" dielectric_coefficient = 3.8 loss_tangent = 0.02
[docs] class GenericCopper(Conductor): """0.5 oz copper -- 0.0175 mm thick. ``roughness`` is intentionally left unset, so no per-conductor surface-roughness boundary is generated. Set it when modelling fab-grade conductor loss (a Hammerstad ratio, or a Huray ``(nodule_radius_m, area_ratio)`` tuple)."""
VEL_STRIPLINE = phase_velocity(3.0) # ----------------------------------------------------------------------------- # Stackup: explicit 20-layer mirror about the thick core dielectric. # -----------------------------------------------------------------------------
[docs] class Generic_Stackup(Stackup): """Explicit 20-conductor stack with one generic dielectric throughout.""" top_mask = SolderMask(thickness=0.0127) # Upper half: L1 (outer ground) -> L10 (power, adjacent to core) L1_Ground1 = GenericCopper(thickness=0.0175, name="L1-Ground1") d_1_2 = GenericDielectric(thickness=0.1) L2_Signal1 = GenericCopper(thickness=0.0175, name="L2-Signal1") d_2_3 = GenericDielectric(thickness=0.1) L3_Ground2 = GenericCopper(thickness=0.0175, name="L3-Ground2") d_3_4 = GenericDielectric(thickness=0.1) L4_Signal2 = GenericCopper(thickness=0.0175, name="L4-Signal2") d_4_5 = GenericDielectric(thickness=0.1) L5_Ground3 = GenericCopper(thickness=0.0175, name="L5-Ground3") d_5_6 = GenericDielectric(thickness=0.1) L6_Signal3 = GenericCopper(thickness=0.0175, name="L6-Signal3") d_6_7 = GenericDielectric(thickness=0.1) L7_Ground4 = GenericCopper(thickness=0.0175, name="L7-Ground4") d_7_8 = GenericDielectric(thickness=0.1) L8_Signal4 = GenericCopper(thickness=0.0175, name="L8-Signal4") d_8_9 = GenericDielectric(thickness=0.1) L9_Ground5 = GenericCopper(thickness=0.0175, name="L9-Ground5") d_9_10 = GenericDielectric(thickness=0.1) L10_Power1 = GenericCopper(thickness=0.0175, name="L10-Power1") # Center dielectric: thick core. d_center = GenericDielectric(thickness=0.8, name="Core") # Lower half: explicit mirror of the upper half. Layer N+10 mirrors # layer 11-N; e.g. L11_Power1 mirrors L10_Power1, L20_Ground1 mirrors # L1_Ground1. L11_Power1 = GenericCopper(thickness=0.0175, name="L11-Power1") d_11_12 = GenericDielectric(thickness=0.1) L12_Ground5 = GenericCopper(thickness=0.0175, name="L12-Ground5") d_12_13 = GenericDielectric(thickness=0.1) L13_Signal4 = GenericCopper(thickness=0.0175, name="L13-Signal4") d_13_14 = GenericDielectric(thickness=0.1) L14_Ground4 = GenericCopper(thickness=0.0175, name="L14-Ground4") d_14_15 = GenericDielectric(thickness=0.1) L15_Signal3 = GenericCopper(thickness=0.0175, name="L15-Signal3") d_15_16 = GenericDielectric(thickness=0.1) L16_Ground3 = GenericCopper(thickness=0.0175, name="L16-Ground3") d_16_17 = GenericDielectric(thickness=0.1) L17_Signal2 = GenericCopper(thickness=0.0175, name="L17-Signal2") d_17_18 = GenericDielectric(thickness=0.1) L18_Ground2 = GenericCopper(thickness=0.0175, name="L18-Ground2") d_18_19 = GenericDielectric(thickness=0.1) L19_Signal1 = GenericCopper(thickness=0.0175, name="L19-Signal1") d_19_20 = GenericDielectric(thickness=0.1) L20_Ground1 = GenericCopper(thickness=0.0175, name="L20-Ground1") bottom_mask = SolderMask(thickness=0.0127)
# ----------------------------------------------------------------------------- # Fabrication constraints # -----------------------------------------------------------------------------
[docs] class Generic_FabRules(FabricationConstraints): # HDI-class fab floors tight enough that the routing structure's # neckdown ``clearance=0.05`` isn't clamped up by the fab rule. min_copper_width = 0.04 min_copper_copper_space = 0.05 min_copper_hole_space = 0.05 min_copper_edge_space = 0.15 min_annular_ring = 0.04 min_drill_diameter = 0.05 min_hole_to_hole = 0.3 min_pitch_leaded = 0.2 min_pitch_bga = 0.4 max_board_width = 500 max_board_height = 400 min_silkscreen_width = 0.1 min_silk_solder_mask_space = 0.05 min_silkscreen_text_height = 0.6 solder_mask_registration = 0.025 min_soldermask_opening = 0.025 min_soldermask_bridge = 0.04 min_th_pad_expand_outer = 0.08 min_pth_pin_solder_clearance = 0.0
# ----------------------------------------------------------------------------- # Substrate definition: vias + introspection accessors. # -----------------------------------------------------------------------------
[docs] class Generic_Substrate(Substrate): """Generic 20-layer substrate. Truly reusable: holds materials, stackup, fab rules, and HDI vias only; design-specific tags, routing structures, and fence-via rules attach in a design subclass. """ stackup = Generic_Stackup() constraints = Generic_FabRules() # --- HDI signal-launch vias (L1 -> signal layer) -----------------------
[docs] class uVia_L1_L2(Via): type = ViaType.LaserDrill start_layer = 0 stop_layer = 1 diameter = 0.25 hole_diameter = 0.1 filled = True via_in_pad = True models = {(0, 1): PinModel(0.0, 0.0)}
[docs] class uVia_L1_L4(Via): type = ViaType.LaserDrill start_layer = 0 stop_layer = 3 diameter = 0.25 hole_diameter = 0.1 filled = True via_in_pad = True models = {(0, 3): PinModel(0.0, 0.0)}
[docs] class uVia_L1_L6(Via): type = ViaType.LaserDrill start_layer = 0 stop_layer = 5 diameter = 0.25 hole_diameter = 0.1 filled = True via_in_pad = True models = {(0, 5): PinModel(0.0, 0.0)}
[docs] class uVia_L1_L8(Via): type = ViaType.LaserDrill start_layer = 0 stop_layer = 7 diameter = 0.25 hole_diameter = 0.1 filled = True via_in_pad = True models = {(0, 7): PinModel(0.0, 0.0)}
# --- GND fence uVias from L1 to the lower reference plane of each signal
[docs] class uGnd_L1_L3(Via): type = ViaType.LaserDrill start_layer = 0 stop_layer = 2 diameter = 0.25 hole_diameter = 0.1 filled = True
[docs] class uGnd_L1_L5(Via): type = ViaType.LaserDrill start_layer = 0 stop_layer = 4 diameter = 0.25 hole_diameter = 0.1 filled = True
[docs] class uGnd_L1_L7(Via): type = ViaType.LaserDrill start_layer = 0 stop_layer = 6 diameter = 0.25 hole_diameter = 0.1 filled = True
[docs] class uGnd_L1_L9(Via): type = ViaType.LaserDrill start_layer = 0 stop_layer = 8 diameter = 0.25 hole_diameter = 0.1 filled = True
# --- Routing-structure fence vias: one per signal layer, spanning the # stripline's two reference planes. ``Lk_Lm`` is (upper, lower) # reference layer index for the diff-pair stripline on signal Lk.
[docs] class uFence_L1_L3(Via): type = ViaType.LaserDrill start_layer = 0 stop_layer = 2 diameter = 0.25 hole_diameter = 0.1 filled = True
[docs] class uFence_L3_L5(Via): type = ViaType.LaserDrill start_layer = 2 stop_layer = 4 diameter = 0.25 hole_diameter = 0.1 filled = True
[docs] class uFence_L5_L7(Via): type = ViaType.LaserDrill start_layer = 4 stop_layer = 6 diameter = 0.25 hole_diameter = 0.1 filled = True
[docs] class uFence_L7_L9(Via): type = ViaType.LaserDrill start_layer = 6 stop_layer = 8 diameter = 0.25 hole_diameter = 0.1 filled = True
# Bottom-half mirror fence vias for the symmetric stack. ``start/stop`` are # negative indices so they track the mirrored stripline reference planes.
[docs] class uFence_L18_L20(Via): type = ViaType.LaserDrill start_layer = -3 stop_layer = -1 diameter = 0.25 hole_diameter = 0.1 filled = True
[docs] class uFence_L16_L18(Via): type = ViaType.LaserDrill start_layer = -5 stop_layer = -3 diameter = 0.25 hole_diameter = 0.1 filled = True
[docs] class uFence_L14_L16(Via): type = ViaType.LaserDrill start_layer = -7 stop_layer = -5 diameter = 0.25 hole_diameter = 0.1 filled = True
[docs] class uFence_L12_L14(Via): type = ViaType.LaserDrill start_layer = -9 stop_layer = -7 diameter = 0.25 hole_diameter = 0.1 filled = True
# Mechanical through-hole via for stitching + PTH components.
[docs] class TH_Via(Via): type = ViaType.MechanicalDrill start_layer = Side.Top stop_layer = Side.Bottom diameter = 0.5 hole_diameter = 0.25 filled = True
# Top-half GND stitch via: L1 (outer GND pour) down to L9 (Ground5). # Gives reference-plane continuity across the inner-layer escape # without crossing the core.
[docs] class uStitch_L1_L9(Via): type = ViaType.LaserDrill start_layer = 0 stop_layer = 8 diameter = 0.25 hole_diameter = 0.1 filled = True via_in_pad = True
# Mirror stitch via for the bottom half: L20 <-> L12.
[docs] class uStitch_L12_L20(Via): type = ViaType.LaserDrill start_layer = -9 stop_layer = -1 diameter = 0.25 hole_diameter = 0.1 filled = True via_in_pad = True
# --- Introspection accessors ------------------------------------------ # Designs query these instead of restating substrate-shaped tables. @property def signal_via(self) -> dict[int, type[Via]]: """Signal-launch via class keyed by signal-layer index (1..4).""" return { 1: self.uVia_L1_L2, 2: self.uVia_L1_L4, 3: self.uVia_L1_L6, 4: self.uVia_L1_L8, } @property def gnd_via(self) -> dict[int, type[Via]]: """Matching GND fence-via class keyed by signal-layer index (1..4). Returns the via that spans L1 to the signal's lower reference plane.""" return { 1: self.uGnd_L1_L3, 2: self.uGnd_L1_L5, 3: self.uGnd_L1_L7, 4: self.uGnd_L1_L9, } @property def n_conductors(self) -> int: """Total number of conductor layers in the stackup.""" return len(self.stackup.conductors)