This repository contains JITX Python implementations of high-speed protocol bundles, signal integrity constraints, and component validation utilities. It demonstrates how to define and constrain memory and serial interfaces in hardware designs.
- Overview
- Quick Start
- Protocols
- Protocol Examples
- Resistor Validation
- Common Infrastructure
- Development
This library provides:
-
Protocol Bundles: Port definitions for memory interfaces (DDR4, LPDDR4, LPDDR5, GDDR7) and high-speed serial interfaces (PCIe, SATA, SFP/QSFP)
-
Signal Integrity Constraints: Timing skew, insertion loss, and impedance constraints that can be applied to protocol connections
-
Example Designs: Complete working examples showing controller-to-memory and device-to-device connections with SI constraints
-
Resistor Validation: Utilities to validate resistor values against E-series standards and check power dissipation limits
# Build all designs
./.venv/bin/python -m jitx build-all
# Expected output: 8 designs, all status: okDDR4 SDRAM interface supporting x16 width with single or dual rank configurations.
Bundle Structure:
DDR4
├── data: DDR4Data
│ ├── DQ[16] - 16-bit data bus
│ ├── DQS[2] - Data strobes (DiffPair per byte lane)
│ └── DM_n[2] - Data masks
└── acc: DDR4ACC
├── A[17] - Address bus
├── BA[2] - Bank address
├── BG[2] - Bank group
├── CK[2] - Clock (DiffPair per chip)
├── CKE[1-2] - Clock enable
├── CS_n[1-2] - Chip select
├── ODT[1-2] - On-die termination
├── ACT_n - Activate
├── RESET_n - Reset
├── PAR - Parity
└── ALERT_n - Alert
Constraint Parameters (DDR4ConstraintParams):
| Parameter | Default | Description |
|---|---|---|
skew_ck |
±2.5ps | CK intra-pair skew |
skew_dqs |
±2.5ps | DQS intra-pair skew |
skew_ck_dqs |
-300ps to +500ps | CK to DQS timing |
skew_dqs_dq |
±10ps | DQS to DQ/DM skew |
loss |
5.0dB | Maximum insertion loss |
Low-power DDR4 for mobile applications. Supports x16, x32, and x64 widths with 1-3 ranks.
Bundle Structure:
LPDDR4
└── ch[1-4]: LPDDR4_X16 - x16 channels
├── d[2]: LPDDR4Lane - Byte lanes
│ ├── dq[8] - Data bits
│ ├── dqs (DiffPair) - Data strobe
│ └── dmi - Data mask/inversion
├── ck (DiffPair) - Clock
├── cke[ranks] - Clock enable
├── cs[ranks] - Chip select
└── ca[6] - Command/address
Constraint Parameters (LPDDR4ConstraintParams):
| Parameter | Default | Description |
|---|---|---|
skew_ck |
±2.0ps | CK intra-pair skew |
skew_ck_cke |
±8.0ps | CK to CKE skew |
skew_ck_cs |
±8.0ps | CK to CS skew |
skew_ck_ca |
±8.0ps | CK to CA skew |
skew_ck_dqs |
-500ps to +2500ps | CK to DQS skew |
skew_dqs |
±2.0ps | DQS intra-pair skew |
skew_dqs_dq |
±5.0ps | DQS to DQ/DMI skew |
loss |
5.0dB | Maximum insertion loss |
LPDDR5/LPDDR5X for high-bandwidth mobile applications. Supports x32 and x64 widths.
Key Differences from LPDDR4:
- Separate Write Clock (WCK) and Read Data Strobe (RDQS)
- 7-bit Command/Address bus
- Tighter timing constraints
Bundle Structure:
LPDDR5
├── d[channels][2]: LPDDR5DataLane
│ ├── dq[8] - Data bits
│ ├── wck (DiffPair) - Write clock
│ ├── rdqs (DiffPair) - Read data strobe
│ └── dmi - Data mask/inversion
├── cs[channels][ranks] - Chip selects
├── ck[channels] (DiffPair) - Clocks
├── ca[channels][7] - Command/address
└── reset_n - Shared reset
Graphics DDR7 for high-performance GPU memory. Fixed 4-channel architecture.
Bundle Structure:
GDDR7
├── data[4]: GDDR7DataChannel
│ ├── DQ[10] - 10-bit data (PAM3/NRZ)
│ ├── RCK (DiffPair) - Read clock
│ ├── WCK (DiffPair) - Write clock
│ ├── CA[5] - Command/address
│ ├── DQE - Error detection
│ └── ERR - Error flag
└── control: GDDR7ControlChannel
├── RESET_n - Reset
├── ZQ_AB - Impedance cal (A/B)
└── ZQ_CD - Impedance cal (C/D)
Constraint Parameters (GDDR7ConstraintParams):
| Parameter | Default | Description |
|---|---|---|
skew_rck |
±10fs | RCK intra-pair skew |
skew_wck |
±10fs | WCK intra-pair skew |
skew_rck_wck |
±20ps | RCK to WCK skew |
skew_dq_dqe |
±5ps | DQ to DQE skew |
loss |
5.0dB | Maximum insertion loss |
PCI Express supporting Gen1 through Gen6, x1 through x16 widths.
Bundle Structure:
PCIe
├── data: PCIeData
│ └── lane[width]: PCIeLane
│ ├── TX (DiffPair) - Transmit pair
│ └── RX (DiffPair) - Receive pair
└── ctrl: PCIeControl (optional)
├── REFCLK (DiffPair) - Reference clock
├── PERST_n - Reset
├── CLKREQ_n - Clock request
├── WAKE_n - Wake
└── PRSNT - Presence detect
Usage Modes:
xover=False(default): Straight-through (TX→TX, RX→RX) for card-edge connectorsxover=True: Crossover (TX→RX, RX→TX) for IC-to-IC connections
Helper Function:
connect_pcie_null_modem(a: PCIe, b: PCIe) -> listCreates crossover topology connections for null-modem (IC-to-IC) configurations.
Serial ATA interface for storage devices.
Bundle Structure:
SATA
└── lane: SATALane
├── TX (DiffPair) - Transmit pair
└── RX (DiffPair) - Receive pair
Constraint Notes:
- Always uses crossover topology (TX→RX)
- 100Ω differential impedance
- Insertion loss ≤5.0dB
Small Form-factor Pluggable interfaces for optical/copper networking.
Variants:
| Type | Lanes | Description |
|---|---|---|
SFP |
1 | Standard SFP/SFP+ |
SFP_DD |
2 | SFP Double Density |
QSFP |
4 | Quad SFP |
QSFP_DD |
8 | QSFP Double Density |
Bundle Structure:
SFP_Lane (base for all variants)
└── lanes[n]: SFPLink
├── TX (DiffPair) - Transmit pair
└── RX (DiffPair) - Receive pair
All examples are in test_protocols/examples/protocols/ and demonstrate:
- Component definition with landpatterns and pad mappings
- Memory/controller circuits with direct ports or Provide() patterns
- Topology connections using
>>for SI constraint propagation - Application of protocol-specific constraints
Demonstrates DDR4 x16 fly-by topology with two Micron MT40A1G16TB memory chips.
Components:
MT40A1G16TB_062E_F: Real Micron DDR4 memory with FBGA96 split-BGA landpatternDDR4ControllerComponent2: Generic controller with Provide() pattern
Key Features:
- Split-BGA landpattern generator for DDR4 package
- Fly-by topology:
io.DQ → mem0.DQ → mem1.DQ - Per-chip clock and control signals
Samsung K4FBE3D4HB-KHCL x32 dual-rank memory connected to controller.
Components:
K4FBE3D4HB_KHCL: Samsung LPDDR4 memory (22x12 BGA)LPDDR4ControllerComponent: Controller with Provide() pattern
Key Features:
- Dual x16 channels (A and B)
- Dual rank support with per-rank CKE/CS
Micron MT62F4G32D8DV-026_AIT_B LPDDR5X memory (automotive grade).
Components:
MT62F4G32D8DV_026_AIT_B: 16GB LPDDR5X (315-ball LFBGA)LPDDR5ControllerCircuit: Controller with Provide() pattern
Key Features:
- x32 DualRank configuration
- Separate WCK and RDQS per lane
- 7-bit CA bus per channel
GPU IC to GDDR7 memory connection with 4-channel interface.
Components:
GDDR7MemoryComponent: FBGA266 split-BGA memoryGDDR7ICComponent: 30x30 BGA GPU/IC with checkerboard ground pattern
Key Features:
- 4 data channels with 10-bit PAM3 data
- RCK/WCK clock pairs per channel
- Checkerboard signal/ground ball pattern for IC
PCIe Gen3 x2 with AC coupling and null-modem topology.
Features:
DiffPairCoupler: AC coupling circuit using blocking caps- Card-edge mode (straight-through) and IC-to-IC mode (crossover)
connect_pcie_null_modem()helper for null-modem connections
SATA host-to-device and IC-to-IC connections.
Features:
- TX→RX crossover topology
- AC coupling with blocking capacitors
Single-lane SFP and 4-lane QSFP connections.
Features:
- TX→RX crossover topology (optical-style)
- AC coupling on TX paths
Validates that resistance values conform to standard E-series (E96 by default).
from eseries_check import check_eseries_value, ESeriesResult
# Check if 10kΩ is E96 standard
result = check_eseries_value(10000) # ok=True, severity="ok"
# Check non-standard value
result = check_eseries_value(47500) # ok=False, severity="error"
# Allow non-standard as warning
result = check_eseries_value(47500, allow_warning=True) # severity="warning"Return Object (ESeriesResult):
| Field | Type | Description |
|---|---|---|
ok |
bool | True if value matches E-series |
severity |
str | "ok", "warning", or "error" |
value_ohms |
float | Input value |
series |
str | E-series checked (e.g., "E96") |
nearest_standard_ohms |
float | Nearest E-series value |
rel_error |
float | Relative error from nearest |
message |
str | Human-readable result |
Validates that resistor power dissipation (P = I²R) is within package limits.
from resistor_power_check import check_resistor_power, ResistorPowerResult
# Check 1kΩ resistor with 10mA in 0603 package
result = check_resistor_power(
size="0603",
resistance_ohms=1000,
current_amps=0.01,
derating_factor=0.8, # 80% derating
design_margin=2.0, # 2x safety margin
)Package Power Ratings:
| Imperial | Metric | Power (W) |
|---|---|---|
| 01005 | 0402 | 0.031 |
| 0201 | 0603 | 0.050 |
| 0402 | 1005 | 0.062 |
| 0603 | 1608 | 0.100 |
| 0805 | 2012 | 0.125 |
| 1206 | 3216 | 0.250 |
| 1210 | 3225 | 0.500 |
| 1812 | 4532 | 0.750 |
| 2010 | 5025 | 0.750 |
| 2512 | 6332 | 1.000 |
Size Normalization:
- Ambiguous sizes (0402, 0603) default to imperial
- Use explicit prefix for clarity:
I0402(imperial) orM1005(metric)
Combines E-series validation with optional power check.
from resistor_rules import check_resistor, ResistorRuleResult
# E-series only (power check skipped)
result = check_resistor(size="0603", resistance_ohms=10000)
# E-series + power check
result = check_resistor(
size="0603",
resistance_ohms=10000,
current_amps=0.005,
derating_factor=0.8,
design_margin=2.0,
)
# Allow non-standard as warning
result = check_resistor(
size="0603",
resistance_ohms=9950, # Not E96
allow_nonstandard_warning=True,
)Return Object (ResistorRuleResult):
| Field | Type | Description |
|---|---|---|
ok |
bool | All enforced rules pass |
severity |
str | "ok", "warning", or "error" |
summary |
str | Single-line status |
issues |
list[str] | All messages (info/warning/error) |
eseries |
ESeriesResult | E-series validation result |
power |
ResistorPowerResult | Power check result (or None if skipped) |
Provides a 6-layer PCB stackup suitable for high-speed designs.
Stackup:
Top Soldermask (13µm)
Layer 0 - Signal (30µm Cu)
Prepreg (60µm)
Layer 1 - Inner (25µm Cu)
Prepreg (60µm)
Layer 2 - Signal (15µm Cu)
Core (70µm FR4)
Layer 3 - Signal (25µm Cu)
Prepreg (60µm)
Layer 4 - Inner (25µm Cu)
Prepreg (60µm)
Layer 5 - Signal (30µm Cu)
Bottom Soldermask (13µm)
Routing Structures:
| Structure | Impedance | Use Case |
|---|---|---|
SE40RoutingStructure |
40Ω | LPDDR4 |
SE45RoutingStructure |
45Ω | DDR4 |
SE50RoutingStructure |
50Ω | General SE |
diff_85 |
85Ω diff | LPDDR4 CK/DQS |
diff_90 |
90Ω diff | DDR4 CK/DQS |
diff_100 |
100Ω diff | PCIe, SATA, SFP |
Via Definitions:
MicroViaTop1-4: Laser-drilled microvias to inner layersDefaultTHVia: Mechanical through-hole via
Components with pin models for SI topology propagation.
BlockingCapacitor:
- 0201 package blocking capacitor for AC coupling
BridgingPinModelallows SI constraints to propagate through
PullUpResistor:
- 0201 package pull-up resistor
BridgingPinModelfor SI propagation
# Activate virtual environment
source .venv/bin/activate
# Build all designs
python -m jitx build-alltest_protocols/
├── protocols/ # Protocol bundle definitions
│ ├── memory/
│ │ ├── ddr4.py # DDR4 bundle + constraints
│ │ ├── lpddr4.py # LPDDR4 bundle + constraints
│ │ ├── lpddr5.py # LPDDR5 bundle + constraints
│ │ └── gddr7.py # GDDR7 bundle + constraints
│ ├── pcie.py # PCIe bundle + constraints
│ ├── sata.py # SATA bundle + constraints
│ └── sfp.py # SFP/QSFP bundle + constraints
├── examples/protocols/ # Example designs
│ ├── memory/
│ │ ├── ddr4_components.py
│ │ ├── ddr4_example.py
│ │ ├── lpddr4_components.py
│ │ ├── lpddr4_example.py
│ │ ├── lpddr5_components.py
│ │ ├── lpddr5_example.py
│ │ ├── MT62F4G32D8DV_026_AIT_B.py
│ │ ├── gddr7_components.py
│ │ └── gddr7_example.py
│ ├── pcie/
│ ├── sata/
│ └── sfp/
├── common/ # Shared infrastructure
│ ├── example_board.py # Board, stackup, vias
│ └── example_components.py # Blocking caps, pull-ups
├── eseries_check.py # E-series validation
├── resistor_power_check.py # Power dissipation check
└── resistor_rules.py # Combined resistor validation
Topology Connections:
Use >> operator to preserve topology for SI constraints:
# Correct - preserves topology
self.topos.append(self.io.dq[i] >> self.mem.DQ[i])
# Incorrect - loses topology information
self.nets.append(self.io.dq[i] + self.mem.DQ[i])Direct Port vs Provide:
- Memory components: Use direct ports (
io = LPDDR5(...)) for fixed pin assignments - Controller components: Use
Provide()for flexible pin assignment
Crossover Topology: For SFP/SATA/PCIe IC-to-IC connections:
# TX from source connects to RX on destination
topos.append(src.lane.TX >> dst.lane.RX)
topos.append(dst.lane.TX >> src.lane.RX)See LICENSE file for details.