PCIe 物理层基础:差分信号、8b/10b 编码、帧格式与符号结构

大家好。这一章咱们聊聊 PCIe 物理层的基础。嗯,别看这层名字带“物理”二字就觉得枯燥,其实理解它才能真正看懂 TS1/TS2 在干什么。我个人习惯是先摸透物理层再做协议分析,不然你会觉得链路训练像个黑盒子。

我记得刚接触 PCIe 时,有个项目信号走线没处理好,差分对等长差了十几 mil,结果链路死活上不去 Gen3。最后查了三天,发现是物理层问题。说白了,物理层不稳,上层协议再漂亮也没用。

差分信号:不是两根线那么简单

PCIe 用的是低压差分信号,也就是 LVDS。一对线,一个叫 S+,一个叫 S-。接收端看的不是单端电压,而是两个信号的差值。

  • 抗共模干扰:外界噪声同时耦合到两根线上,差值不变。这个特性在实际项目中非常靠谱。
  • 低摆幅:电压差只有几百毫伏,功耗低,速度快。
  • 等长要求:两条走线长度必须一致。我在项目中遇到过,等长差 50 mil,眼图就明显闭合。
我曾经遇到过一根走线长了 30 mil,链路的误码率直接翻了两倍。后来补了蛇形线才解决。做 layout 时千万别忽略等长。

8b/10b 编码:效率与稳定性的平衡

为什么要编这个码?原始 8 位数据直接发,可能连串连续 0 或连续 1,接收端容易丢失时钟同步。8b/10b 编码把 8 位数据变成 10 位符号,保证直流平衡和足够多的跳变。

你想想看,原本 8 位只有 256 种组合,变成 10 位后多了 768 种冗余组合。这些冗余用来做控制符号,比如 TS1/TS2 里的 COM、STS 等。

原始 8 位数据 编码后 10 位符号 备注
0x00 K28.1 逗号符号,用于字节对齐
0x1C K28.5 COM 符号,TS1/TS2 起始标志
0xBC K28.7 符号边界检测用
任意数据 D.x.y 普通数据符号
我个人习惯在调试时先看符号是否对齐到 COM。如果解码出一堆乱码,八成是字节对齐出了问题。8b/10b 的失步检测也在物理层里。

帧格式与符号结构:数据的骨架

PCIe 的数据不是一股脑儿往外发,而是组织成一个个有序的符号序列。每个符号 10 位,经过串行化后发送。帧格式说白了就是这些符号的排列规则。

一个典型数据帧包括:STP(开始)、序列号、数据负载、CRC、END(结束)。但你得知道,TS1/TS2 这种链路管理序列没有数据负载,它们用的是特定的符号组合。

符号类型 长度 说明
STP 1 符号 帧开始,标识 TLP 起始
SDP 1 符号 数据负载开始,紧接在 STP 后
END 1 符号 帧结束,可能带错误标识
COM 1 符号 逗号符号,用于对齐和训练序列
STS 1 符号 训练序列中的控制符号

嗯,这里要注意:帧的起始和结束符号都是唯一的,接收端靠它们找到数据边界。我在做协议分析时,经常先抓一串原始符号,然后手工定位 COM 符号的位置。只要 COM 对了,后面的 TS1/TS2 结构就很好拆。

核心要点:物理层的符号结构是协议分析的基石。不理解 STP/COM/END 的区别,你连 TS1 的起始都找不到。
PCIe 物理层发送流程 编码层 帧层 物理层 原始数据(8-bit) 8b/10b 编码器 帧组装 (STP/序列/数据/END) 符号加扰(可选) 差分发送(S+/S-)

这张图展示了数据从原始字节到差分信号的完整路径。编码层做 8b/10b 转换,帧层把符号组织成帧结构,物理层最终通过差分对发出去。TS1/TS2 训练序列也走这条路径,只不过它们的符号是预设好的,不是普通数据。

我曾经调试一个 Gen3 降速问题,发现 8b/10b 编码层的失步导致接收端把 TS1 的控制符号当成了数据。后来在物理层寄存器里加了失步计数,才锁定问题。