PCIe SerDes 全流程实战
数字部分——DLL-DLCMSM
本项目聚焦于高速串行通信本身。PCIe 作为广泛应用的高速串行通信协议,其历史悠久,协议栈层次多、设计复杂;Synopsys IP 更是在工业级别上对 PCIe 协议做了完整实现。
因此,本文 不 针对数字逻辑的每一个细节展开说明;若需深入,可结合 SystemVerilog 代码与波形自行学习。
以下内容为O3-Pro对system verilog代码和标准文档的深度总结
1 概述:为什么要理解 DLCMSM?
在 PCI Express 高速串行总线里,Data Link Layer 既要保障 包的可靠传输,又要对上(Transaction Layer)和对下(Physical Layer)隐藏链路瞬时波动。
其核心就是 Data Link Control and Management State Machine (DLCMSM),它决定了链路什么时候可以收发 TLP / DLLP、什么时候要做流控初始化、以及发生掉链等异常时如何快速复原。
在官方规范(PCI Express Base Specification r6.0)第 3 章里,对 DLCMSM 的四个状态有如下描述 (原文):
DL_Inactive – Physical Layer reporting Link is non‑operational …
DL_Feature – … perform the Data Link Feature Exchange
DL_Init – … initialize Flow Control for Virtual Channel 0
DL_Active – Normal operation mode …
Status Outputs: DL_Down / DL_Up
— PCI Express Base Specification, 3.2
下文我们将把这段规范与 Synopsys IP(DWC_pcie_ctl 5.60a
)的源代码一一对照,并在每个环节给出“为什么要这样设计”与“高速串行链路里这样做解决了什么问题”的思考。
2 状态机在代码里的落地
2.1 状态编码
在 Receive‑DLH Link Control 模块(ku5p_rdlh_link_cntrl.sv
)里,状态被宏展开为:
`define S_DL_INACTIVE 2'b00
`define S_DL_FC_INIT 2'b01
`define S_DL_ACTIVE 2'b11
`define S_DL_FEATURE 2'b10 // Gen 4+ 可选
可以看到,Synopsys 把 DL_Init 拆成更可读的 S_DL_FC_INIT
;而 DL_Feature 只有在实现了可选 Data Link Feature Exchange 时才启用(规范里的 “optional” 与实现保持一致)。
2.2 关键转移逻辑
摘自同一文件:
case (rdlh_dlcntrl_state)
`S_DL_INACTIVE: begin
if (smlh_link_up & cfg_dll_lnk_en)
r_rdlh_dlcntrl_state <= `S_DL_FC_INIT;
end
`S_DL_FC_INIT: begin
if(!smlh_link_up)
r_rdlh_dlcntrl_state <= `S_DL_INACTIVE;
else if(rtlh_fci_done)
r_rdlh_dlcntrl_state <= `S_DL_ACTIVE;
end
`S_DL_ACTIVE: begin
if(!smlh_link_up)
r_rdlh_dlcntrl_state <= `S_DL_INACTIVE;
end
endcase
对比规范的 Exit 条件:
- 只有当 Physical LinkUp = 1 且 软件未禁用 Link 时,才能离开 DL_Inactive。
↳ 这里使用smlh_link_up
(来自 PHY)和cfg_dll_lnk_en
(软件位)共同判定。 - 从 DL_Init 到 DL_Active 的前提是 Flow Control initialisation completes。
↳ 在代码里由rtlh_fci_done
触发。
这一对照让我们确认:硬件 FSM 严格依赖 规范定义的握手信号,不会过早认为链路已就绪,从而避免 Transaction Layer 误发 TLP。
3 四个状态的详细流程与代码剖析
DLCMSM 状态 | 规范任务 | 代码片段 | 深层机制解读 |
---|---|---|---|
DL_Inactive | 清零所有 DLL 状态;报告 DL_Down | Reset all Data Link Layer state information 在代码中体现在 !core_rst_n 或 !link_rdy4dllp 分支里把几乎所有寄存器清 0 |
热插拔 / 掉线 下,必须让 Transaction Layer 立即丢弃任何已在途事务,避免数据跨设备漂移 |
DL_Feature(可选) | 发送/接收 Data Link Feature DLLP | ku5p_xdlh_dllp_gen 根据 cfg_other_msg_request 组帧;ku5p_rdlh_dlp_extract 识别 dllp_rcvd_dllp_content |
在 Gen4+,可用来协商 replay timer 宽度、最大并发 DLLP 等链路特性,提高后向兼容性 |
DL_Init | VC0 Flow Control 初始化;状态输出在 FC_INIT1/2 切换时由 DL_Down→DL_Up |
rtlh_fci1_fci2 进入 2‑phase 流控握手;ku5p_rdlh_link_cntrl 用它来拉高 rdlh_link_up |
通过 “先标记再放行” 的两相协议保证双方 Buffer Credit 精确对齐,从硬件层面拔除“发多/发少”隐患 |
DL_Active | 正常收发 TLP / DLLP;监控 LinkDown;处理 Surprise Down 等异常 | 接收侧:ku5p_rdlh_tlp_extract 、...dlp_extract ;发送侧:ku5p_xdlh_* 系列 |
覆盖 LCRC 计算、序号追踪、重复包 ACK、NAK 与重放(REPLAY) 计时器 等机制,后文详述 |
4 ACK/NAK 协议与重放(Replay)机制
4.1 序号比较的数学细节
在 ku5p_rdlh_dlp_extract.sv
里,判断 ACK/NACK 是否 落在窗口内 的核心一行:
dllp_seq_less[i] = (dllp_seq_diff < 2048) && (dllp_expected_seq_diff <= 2048);
“Sequence numbers are compared mod 4096; the valid forward window is ±2048.”
— PCI Express Base Spec. 3.3.1
硬件直接将差值与 2048 比较,无需取模,原因是 两个 12 位无符号数相减天然就是 mod 4096 差值。这一做法既省逻辑,也天然抗溢出。
4.2 CRC 翻转 (Inverted LCRC) 的意义
Extract 模块在计算 CRC 后,如果发现 crc_match_inv_vec
为 1 且 tlp_aligned_badeot
也为 1,则把该 TLP 判定为 nullified;否则认为是硬错误并触发 NAK。
nullified_tlp = crc_match_inv_vec & tlp_aligned_badeot;
翻转 LCRC(规范称 “Bad EoT + inverted CRC”)是对 上层请求撤销已发出的 TLP 的硬件加速路径,比起发送 Obsolete TLP 再靠事务层过滤,省时省带宽。
5 Retry Buffer、Replay Timer 与突发错误的自愈
发送侧 ku5p_xdlh_retrybuf.sv
负责所有 重传 相关逻辑。几个值得深挖的细节:
现象 | 关键代码 | 机制意义 |
---|---|---|
重放计时器 一直跑到 0 | replay_timer >= cfg_bus_replay_timer_value 触发 replay_timer_expired |
遵循规范“若最长 Ack Latency 超时则强制 Re‑play”——对 偶发掉包 免疫 |
三次 Replay 仍未收敛 时请求 PHY 重新训练 | replay_num==3'b11 时拉高 xdlh_smlh_start_link_retrain |
避免因为电气噪声导致的“永远 NAK”死循环;利用 LTSSM 重新协商电压摆动、EQ 等参数 |
Retry RAM / SOT RAM 全程带奇偶校验 | retryram_xdlh_parerr , retrysotram_xdlh_parerr |
即使内部 RAM 比特翻转也能检测,防止发送畸形 TLP 损坏下游设备 |
6 高速串行链路里的“背压”与停顿 (HALT)
链路进入 L0 后,Physical Layer 仍可能因为 Elastic Buffer 饱和 等原因暂时 “撑不住”。规范 §3.2.1 Implementation Note 提醒:
“The Data Link Layer must provide mechanisms for the Physical Layer to communicate this condition, and for TLPs and DLLPs to be temporarily blocked.”
Synopsys 在 ku5p_xdlh_control_32b.sv
里用双向 halt 信号实现了背压:
assign xdctrl_tlp_halt = !((arb_decision_en && insert_tlp_en) || …);
而在接收侧 ku5p_rdlh_tlp_extract
则通过 dlyd_int_halt
把 HALT 反馈到返回路径,避免数据对齐错位。
这种 周期级别的停-放 比传统 FIFO “写指针追上读指针再硬停” 更灵活,最大化链路利用率,同时对序号/CRC 逻辑透明。
7 实战提示与调试 Tricks
- 观测 DLCMSM
- 把
rdlh_rtlh_link_state
直接绑到 LA;四种状态的 Gray code 编码天然避免毛刺。
- 把
- 掉线/热插拔 测试
- 在 DL_Active 注入
smlh_link_up=0
,验证 Transaction Layer 是否立即收到 DL_Down 并清空 outstanding TLP。
- 在 DL_Active 注入
- 重放压力测试
- 强制门控 PHY RX 使每隔 N 包丢一包,观察
xdlh_retry_req
→rbuf_reply_req
→xdlh_in_reply
延迟是否符合cfg_ack_latency_timer
。
- 强制门控 PHY RX 使每隔 N 包丢一包,观察
- CRC 错误注入
- 利用
cfg_corrupt_crc_pattern
单比特翻转 LCRC,检查接收侧rdlh_bad_tlp_err
与 NAK 触发逻辑。
- 利用
8 结语
DLCMSM 乍看只是四个简单状态,但它把 逻辑链路的生死、流控同步、特性协商、以及 错误恢复 串成了一条闭环:
“Link management is performed cooperatively by all three PCIe layers,
but the state machine in the Data Link Layer is the conductor.”
掌握了 DLCMSM 的每一条转移与它背后的物理/协议意义,才算真正理解了 PCI Express 高速串行通信在毫微秒尺度上如何自组织、自修复。希望本文对你撰写中文培训材料并指导同事读码、查 Spec 都有所助益。