数字部分 2.6 Dll Dlcmsm

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_InitDL_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

  1. 观测 DLCMSM
    • rdlh_rtlh_link_state 直接绑到 LA;四种状态的 Gray code 编码天然避免毛刺。
  2. 掉线/热插拔 测试
    • 在 DL_Active 注入 smlh_link_up=0,验证 Transaction Layer 是否立即收到 DL_Down 并清空 outstanding TLP。
  3. 重放压力测试
    • 强制门控 PHY RX 使每隔 N 包丢一包,观察 xdlh_retry_req → rbuf_reply_req → xdlh_in_reply 延迟是否符合 cfg_ack_latency_timer
  4. 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 都有所助益。