1. PCIe 协议概述与层次结构归纳总结

我记得到公司第一天,前辈扔给我一本 PCIe 规范,厚得能垫显示器。他说:“搞信号完整性,先得知道协议长什么样。” 后来我踩了不少坑,才明白这句话有多重。

PCI Express,简称 PCIe,本质上是串行高速总线。它替代了并行的 PCI 和 PCI-X。为什么要串行?说白了,并行总线跑快了,信号歪得没法看。你想想看,几百根线同时翻转,串扰、时序偏差…… 我当年调试 PCI 时,光是等长布线就折腾了两周。

PCIe 的核心思路:用差分对传数据,一条发送、一条接收,跑在高速上,而且支持扩展。一传一收构成一条 lane,一个设备可以用 ×1、×4、×8、×16 甚至 ×32 条 lane 来提升带宽。

1.1 层次结构总览

PCIe 协议把通信拆成三个主要的层,外加一个配置管理层。每层只管自己的事,向上提供接口,向下屏蔽细节。好比快递公司:事务层管包裹种类和收件地址;数据链路层管运输包裹时不出错;物理层管车辆和路况。嗯,这个比喻我常用在培训课上。

PCIe 协议层次结构 事务层 (Transaction Layer) TLP 封装 · 存储器/IO/配置/消息事务 · 流量控制 数据链路层 (Data Link Layer) DLLP · Ack/Nak重传 · CRC校验 · 序列号 物理层 (Physical Layer) 逻辑子层 · 电气子层 · 编码 (8b/10b 或 128b/130b) 配置管理层 (Configuration & Management) 向下传递,向上解析

我的一点经验:做 SI 仿真时,很多人只盯着物理层的眼图和抖动,忽略了数据链路层的重传机制。其实链路层 CRC 校验失败会触发重传,重传包又改变相位,间接影响眼图闭合。所以仿真时,最好把物理层和链路层的交互一起建模。

1.2 事务层(Transaction Layer)

事务层是 PCIe 的大脑。它把应用层发来的数据打包成 TLP(事务层包),然后交给下面。反过来,收到 TLP 后拆包,识别这是读请求还是写完成。

TLP 包含三类核心信息:

  • Header:描述包类型、地址、长度、标签等
  • Data Payload:实际数据,最大可达 4096 字节(Gen3 以上)
  • 摘要 (可选):ECRC 等端到端校验

PCIe 定义了四种事务类型:

事务类型 用途 例子
存储器 (Memory) 读写系统内存、显存 GPU 读写帧缓冲
IO (I/O) 访问传统 IO 空间 旧设备控制寄存器
配置 (Configuration) 枚举设备、配置 BAR 等 BIOS 初始化
消息 (Message) 中断、电源管理、错误报告 MSI 中断

我记得有一次排查 NVMe SSD 不掉电场景下的数据损坏。抓 Link 上 TLP 发现有个写请求的地址写错了,导致数据写到了不该去的地方。后来才知道,事务层的地址翻译在虚拟化场景下很容易配错——这是纯协议问题,跟物理层眼图一点关系没有。

1.3 数据链路层(Data Link Layer)

这一层做的事很实在:确保 TLP 可靠传输。它给每个 TLP 加序列号和 LCRC(链路层 CRC),然后接收方要回 Ack 或 Nak DLLP。如果 Nak 或者超时没收到 Ack,发送方就会重传。

核心机制:Ack/Nak 重传 + 流控 (Flow Control)

流控不是调速度,而是信用量 (Credit) 管理。接收方告诉发送方:“我还有多少个 Buffer 能收。” 发送方没拿到信用,就不发。这能防止接收方被撑爆。

⚠ 避坑指南:我曾经在一款 FPGA 的 PCIe 核上调 OCN(片上网络)仲裁。发现数据链路层老是超时重传,带宽上不去。查了三天,居然是流控初期信用值没配够,导致发送方被自己憋死了。后来我把 VC0 的信用初始值改大,问题解决。所以做 SI 仿真前,先确认链路层配置参数是不是对的,否则眼图再好,协议层也会限速。

数据链路层还负责 DLLP(数据链路层包)。DLLP 不是 TLP,它只能在相邻设备间交换,不经过事务层。典型的 DLLP 有:Ack、Nak、InitFC1、UpdateFC 等。你如果想监控链路健康,看 DLLP 错误统计是个好入口。

1.4 物理层(Physical Layer)

物理层是 SI 仿真和测试的主战场。它分为两个子层:

  • 逻辑子层:包括 8b/10b(Gen1/2)或 128b/130b(Gen3及以上)编码、加扰、弹性缓冲、符号对齐
  • 电气子层:差分驱动、接收均衡、时钟恢复、去加重、LTI 行为等

编码的作用是什么?举个例,8b/10b 能把 1 和 0 的数量平衡,减少直流偏移,方便时钟恢复。我刚开始做 Gen2 仿真时,以为只要调好差分阻抗就够了,结果眼图张开度怎么也上不去。后来发现是编码后的码流里“连0”太多,锁相环丢失锁定。唉,当时要是早点关注编码改变后的频谱峰值就好了。

物理层还有 LTSSM(链路训练与状态机),它负责链路上电、复位、速率协商、宽度协商、电源状态转换。做一致性测试时,LTSSM 的各个状态跳转必须符合规范。比如从 L0 进入 L0s 时,如果发送端过早停掉 Refclk,接收端可能直接掉到 Detect——这问题我在某个 PCIe 背板上碰到过两次。

1.5 配置与管理

PCIe 每个功能都有一组配置空间,大小 4KB。软件通过配置读写来发现设备、分配内存地址(BAR)、设置中断等。我经常在测试中用 Bus/Pin/Function 三元组来定位问题,比用符号名快多了。配置空间里还有能力结构,比如 AER(高级错误报告)、ACS(访问控制服务),这些都是 SI 仿真不需要管,但系统级测试必须验证的内容。

1.6 层次间互动 —— 一个实际例子

假设 CPU 要读 GPU 的显存(内存读请求)。

  1. 事务层构建一个 Memory Read TLP,填写地址、长度、标签,加上 Header 和 ECRC,转给数据链路层。
  2. 数据链路层加上序列号和 LCRC,缓存一份副本(万一要重传),然后交给物理层。
  3. 物理层编码、加扰、串行化,从差分线发出去。接收端物理层恢复时钟、解码、去扰,往上送。
  4. 数据链路层收到后检查 CRC,回复 Ack,把 TLP 递交给事务层。
  5. 事务层解析 TLP,把数据给到应用层。

你做 SI 仿真时,通常只关心物理层的信号质量。但如果你发现链路层 CRC 错误率异常高,别急着换 PCB 材料——先查一下是不是流控信用耗尽导致的重传风暴。嗯,这个坑我替你们试过了。

1.7 到底什么是“层次化一致性测试”?

一致性测试不是只测眼图。协议栈有三个层,每一层都有合规点:

  • 物理层:眼图模板、抖动、阻抗、S参数、预加重、TX/RX EQ
  • 数据链路层:重传超时、信用更新周期、DLLP 格式
  • 事务层:TLP 格式、完成超时、标签管理

很多公司只测物理层,觉得过了眼图就 OK。实际系统联调时,要么协议分析仪报链路层错误,要么事务层超时导致驱动蓝屏。所以我的建议是:至少把物理层和链路层的测试覆盖做全,事务层用软件仿真验证。

总结:PCIe 就是三段式结构:事务层 → 数据链路层 → 物理层。每层封装、各有职责。SI 仿真集中在物理层,但理解全栈才能定位真问题。希望这个开头没把你劝退。如果你熟悉了这三个层的协作,后面的仿真和测试你就知道该测什么、该怎么分析。