3. PCIe 3.0 革命:128b/130b 编码与电平变化

聊到 PCIe 3.0,我脑海里第一个蹦出来的词就是“革命”。为什么这么说?因为它在物理层动了一个大手术——从 8b/10b 编码换成了 128b/130b,连带信号电平也砍了一刀。你别小看这两个改动,整个吞吐量翻倍、功耗降下来,靠的就是它们。

这章我们就把这事拆开来看。我会结合自己当年调板子的经历,把 128b/130b 怎么工作、电平怎么变、实际设计里要避哪些坑,统统讲透。

3.1 为什么非换不可?——8b/10b 的瓶颈

先回忆一下 PCIe 1.0/2.0 用的 8b/10b 编码。它的开销是 20%——每发 8 位有效数据,实际线上要传 10 位。到了 5 GT/s(Gen2),每 lane 带宽只有 4 Gb/s 有效。你想想看,如果继续用 8b/10b 往 8 GT/s 走,那开销依然 20%,通道利用率上不去,功耗也压不住。

另一个问题是信号完整性。随着速率升高,传统 NRZ 电平下的眼图越来越小。我当时在一个项目里测 Gen2 长走线,眼高只剩 200 mV 不到,再用 8b/10b 的编码模式,时钟恢复锁不住。说白了,物理层跟不上数据率了。

所以 PCI-SIG 在 Gen3 做了两件事:

  • 编码上:换 128b/130b,开销从 20% 降到 1.5%
  • 电平上:发射幅度从 800-1200 mV 降到 800-1000 mV,还引入去加重(De-emphasis)预加重机制

好,我们先看编码。

3.2 128b/130b 编码:是怎么省出来那 18.5% 的?

128b/130b 的意思很简单:每 128 位用户数据,在线路上只多传 2 位控制位(一个同步头)。总数 130 位,开销 2/130 ≈ 1.54%。比起 8b/10b 的 20%,这简直是天壤之别。

但问题来了——没有冗余位的保证,数据里出现长连 0 或长连 1 怎么办?时钟怎么恢复?

答案在 加扰(Scrambling)。PCIe 3.0 在发射端用一个 LFSR(线性反馈移位寄存器)对数据进行 XOR 加扰,确保数据流的转换密度在统计上足够高。接收端同样用同一个 LFSR 解扰。我调试高速板时遇到过加扰种子不同步导致的链路训练失败,那感觉就像……嗯,查了一整天最后发现是 FPGA 里 LFSR 复位时序差了 1 个 cycle。从此我养成了习惯:加扰模块的复位逻辑一定要和协议规定的对齐窗口严格匹配。

128b/130b 与 8b/10b 对比

特性 8b/10b 128b/130b
开销 20% 1.54%
有效带宽(@8 GT/s per lane) ~6.4 Gb/s ~7.88 Gb/s
DC 平衡保证 内置(运行游程差 ≤ 2) 依靠加扰(统计平衡)
时钟恢复 靠编码保证转换密度 靠加扰保证转换密度
同步方式 逗号字符(K28.5) 块同步头(2 bit)

你可以看到,128b/130b 的做法更“精简”,但依赖加扰来维持时钟恢复。还好加扰算法是标准化的,仿真和实测都能提前验证。

3.3 电平变化:信号摆幅与预加重

除了编码,PCIe 3.0 的另一个大改动是 发射幅度 和 去加重策略。

先看幅度。Gen1/Gen2 允许 800-1200 mV 峰峰值差动摆幅,Gen3 则收窄到 800-1000 mV。为什么要缩?因为速率高了,大的摆幅反而造成过冲和 ISI(码间干扰)。我测过一条 10 英寸走线,在 8 GT/s 下,你猜怎么着?把幅度从 1000 mV 降到 900 mV,眼高反而从 180 mV 涨到 220 mV——因为反射减小了。

然后是预加重/去加重。Gen3 强制发射器在第一位(传递位)用高摆幅,后续同极性位用低摆幅(-3.5 dB 或 -6 dB)。这相当于在发射端对高频分量做提升,补偿通道的低通特性。接收端的 CTLE 和 DFE 再进一步处理。

我给你的建议: 在做 PCB 走线时,Gen3 的通道损耗预算通常按 -20 dB @ 4 GHz 来设计。预留 3 dB 的预加重余量,否则眼图闭合。我吃过亏:有次仿真 pass 了,实测因为过孔 stub 太大,损耗多 2 dB,怎么调预加重都救不回来,最后只能改叠层。

3.4 从 8b/10b 到 128b/130b:链路训练有何不同?

Gen3 的链路训练也变了。因为在 128b/130b 模式下没有逗号字符,所以初始同步靠发送 EIOS(Electrical Idle Ordered Set) 和 SKP OS(Skip Ordered Set) 来对齐。接收端通过检测同步头的 2 bit 来找到块边界。

我记得调试第一块 Gen3 交换芯片时,链路一直卡在 Detect 状态。后来用逻辑分析仪抓 LTSSM 状态机,发现是发射端把电气空闲退出条件搞错了。你看,协议细节一个都不能错。

下面我把链路训练中的关键有序集罗列一下:

  1. TS1/TS2:沿用自 Gen2,用于位锁定和块同步
  2. EIOS:告诉接收端要进入电气空闲
  3. SKP OS:补偿两个器件之间的时钟频率差(弹性缓冲)
  4. FTS(Fast Training Sequence):用于从低功耗状态 L1/L2 快速恢复

这里有个坑:SKP OS 的插入位置有严格规则。有些芯片实现了灵活插入,结果导致兼容性问题。我在实验室里见过两个不同厂商的端设备,因为 SKP 插入频率不对,链路跑几分钟就掉线。解决方案是:按协议规范里的“每 20 µs 至少插入一次 SKP”,同时留一点弹性。

3.5 链路宽度与数据速率变化

Gen3 每个 lane 的数据速率从 5 GT/s 提升到 8 GT/s。编码效率提升,有效带宽从 4 Gb/s(Gen2)跃升到约 7.88 Gb/s。你想想看,如果 x16 宽度的链路,双向总带宽接近 16 GB/s。这为后来的 CXL 等互联打下基础。

下面这张 SVG 图展示了从 Gen1 到 Gen3 在编码和电平上的关键变化路径,你可以看到电平幅度和预加重要求的变化。

PCIe Gen1→Gen3 编码与电平演进 PCIe 1.0 → 3.0 编码与电平演进 PCIe 1.0/2.0 8b/10b 编码 摆幅 800-1200 mV PCIe 3.0 128b/130b 编码 摆幅 800-1000 mV 速率提升至 8 GT/s 开销对比 8b/10b: 20% 开销 → 128b/130b: 1.54% 开销 预加重要求 Gen2: 无强制预加重 Gen3: 强制去加重 -3.5dB 或 -6dB 时钟恢复保障 128b/130b 依赖 LFSR 加扰保证转换密度

3.6 实操要点与避坑指南

在实际项目中,我总结了几条核心原则:

  • 仿真一定要用 128b/130b 加扰数据:有些工程师偷懒用 PRBS 代替,但 PRBS 的统计特性与加扰后的数据不同,容易低估抖动。
  • 去加重系数不是越大越好:我曾经试过 -6 dB 去加重,结果接收端因为低频分量太少,DFE 收敛失败。通常 -3.5 dB 够用,除非通道特别差。
  • 留意 SKP 处理:在 FPGA 里实现弹性缓冲时,SKP 符号的删除/添加逻辑一定要考虑延迟变化。我有次没处理好导致上游数据断流,掉了好多包。
  • 电气空闲检测阈值:Gen3 的电气空闲检测电压阈值比 Gen2 更严格(约 50 mV vs 100 mV)。如果接收端灵敏度不够,收不到 EIOS 会导致链路卡死。

警告: PCIe 3.0 的 128b/130b 编码与 Gen1/2 完全不兼容。当你混合使用不同代设备时,链路只能退化到最低公共代。例如 Gen3 端设备与 Gen2 端设备连接,双方协商退回到 Gen2 的 8b/10b 模式。设计系统时一定要确保所有器件支持目标代际,否则会损失带宽。

总的来说,PCIe 3.0 通过 128b/130b 和电平优化,把单 lane 有效带宽推到了 7.88 Gb/s,同时把信号完整性风险控制住。这为后来的 Gen4/Gen5 铺了路。你想想看,如果没有这次编码革命,后面 16 GT/s、32 GT/s 根本不可能用 NRZ 做到。这部分知识,搞 CXL 设计的同学也绕不开,因为 CXL 的基础高速链路就是 PCIe 物理层,而 Gen3 是最早采用 128b/130b 的版本。

一句话总结: 128b/130b 用 1.54% 的开销换 98.5% 的线效率,加上去加权重的电平控制,让 8 GT/s 成为现实。搞硬件设计的,必须把加扰、去加重、SKP 处理这三个细节刻在脑子里。