rtl/ucie_link_ctrl.sv — UCIe Die-to-Die Link Training FSM
Models the bring-up sequence of a UCIe link at the state-name level of the spec, without bit-accurate PHY/eye-training.
Where it fits
Two instances in system_top.sv: cpu_link_ctrl_inst and npu_link_ctrl_inst, each with TRAIN_CYCLES=4. Each instance's link_up output gates every ucie_chan on that physical link.
Parameters
| Parameter | Default | Meaning |
|---|---|---|
TRAIN_CYCLES |
4 | Cycles held in each pre-ACTIVE state before advancing |
Ports
| Direction | Name | Width | Description |
|---|---|---|---|
| in | clk, rst_n |
1, 1 | Clock / reset |
| out | link_up |
1 | 1 once state == LT_ACTIVE |
| out | train_state |
3 | Debug/observability only — current FSM state |
Functionality
Sequential 7-state FSM, one state transition per TRAIN_CYCLES cycles until ACTIVE:
RESET → SBINIT → PARAM → MBINIT → MBTRAIN → LINKINIT → ACTIVE
| State | Real-world stand-in |
|---|---|
RESET |
link held down out of chip reset |
SBINIT |
sideband initialization (low-speed always-on lane bring-up) |
PARAM |
parameter exchange (widths, speed, module IDs — stubbed) |
MBINIT |
mainband initialization |
MBTRAIN |
mainband training (SerDes lock, eye training — stubbed) |
LINKINIT |
final link initialization handshake |
ACTIVE |
link up; ucie_chan instances on this link may pass flits — sticky, no dynamic retrain or L1/L2 low-power entry modeled (the state encoding leaves room for it) |
Example
With TRAIN_CYCLES=4 (the value used everywhere in this repo), a link takes exactly 6 × 4 = 24 cycles after reset deasserts before link_up goes high — every testbench's reset_dut() holds rst_n low for several cycles and then simply proceeds; the first few instructions dispatched after reset queue up behind tx_ready=0 until both links finish training, which every test in this repo already tolerates because send_instruction() just waits on net_ready.
Related
- ucie_chan.md — every channel this controller gates
- chiplets.md — full link-training writeup