第1章:PCIe协议概述

各位同学,咱们今天正式开讲PCIe。说实话,我第一次接触PCIe的时候,也被它那套分层模型搞得有点晕。但别担心,跟着我的节奏走,你会发现这东西其实挺有意思的。

1.1 PCIe总线架构

PCIe,全称是Peripheral Component Interconnect Express。说白了,就是电脑内部各个设备之间通信的高速公路。我习惯把它理解成「点对点的串行连接」——每个设备都有自己的专用通道,不像老式PCI那样大家挤一条总线。

为什么叫Express?因为它快啊!从最初的2.5GT/s(Gen1),到现在的32GT/s(Gen5),速度翻了十几倍。我在做Gen3项目的时候,就深刻体会到:速度越快,设计越要小心。

核心要点:PCIe是串行总线,不是并行总线。这一点和传统的PCI完全不同。串行意味着数据是一位一位传的,但频率可以跑得非常高。

1.2 拓扑结构

PCIe的拓扑结构,我画个图给你看:

Root Complex (RC)
    │
    ├── PCIe Switch
    │       ├── Endpoint (显卡)
    │       ├── Endpoint (网卡)
    │       └── Endpoint (SSD)
    │
    └── PCIe Bridge (转接老设备)

这个结构里,Root Complex是老大,它连接CPU和内存。Switch相当于交换机,负责数据转发。Endpoint就是各种外设——显卡、网卡、SSD等等。

嗯,这里要注意:Switch不是软件概念,它是实实在在的硬件芯片。我曾经在一个项目里,因为Switch的端口配置搞错了,导致数据死活传不过去。排查了整整两天才发现是配置寄存器写错了。

1.3 分层模型

PCIe的分层模型,是我觉得最值得讲清楚的部分。它分为三层:

层次 主要功能 数据单元
事务层 处理读写请求、完成包 TLP (Transaction Layer Packet)
数据链路层 错误检测、重传、流量控制 DLLP (Data Link Layer Packet)
物理层 串行化、解串、电气特性 PLP (Physical Layer Packet)

事务层

事务层是离软件最近的一层。你写的驱动程序,最终会生成各种TLP包。比如你要读一个地址的数据,事务层就会生成一个Memory Read TLP。

我个人习惯把TLP分成两类:

  • 非Posted请求:需要对方回复的,比如读请求
  • Posted请求:不需要回复的,比如写请求

为什么要有这个区分?你想想看,写数据的时候,如果每次都要等对方确认,那效率得多低?所以写操作是Posted的,发出去就不管了。读操作必须等回复,所以是非Posted的。

小技巧:在FPGA实现中,我建议把Posted和Non-Posted请求分开处理。用两个FIFO来管理,可以避免死锁。我曾经因为没注意这个,导致系统在高压下卡死,教训深刻啊。

数据链路层

数据链路层,说白了就是给TLP加个「信封」。它会在TLP前面加上序列号,后面加上CRC校验。这样接收方就能检查数据有没有传错。

这一层还负责流量控制。每个设备都会告诉对方:「我还能收多少个包」。如果对方发得太快,就会触发重传机制。嗯,这个机制在FPGA实现时特别容易出问题——我建议你先把Credit初始化做好,不然后面调试起来很痛苦。

物理层

物理层是最底层的,负责把数据变成电信号。它分为两个子层:

  • 逻辑子层:做8b/10b编码(Gen1/Gen2)或128b/130b编码(Gen3+)
  • 电气子层:处理差分信号、时钟恢复等

我记得第一次调试Gen3的时候,发现链路老是训练失败。后来用示波器一看,原来是差分信号的摆幅不够。物理层的问题,很多时候要靠仪器才能定位。

避坑指南:千万不要忽视物理层的信号完整性。我曾经在一个项目里,因为PCB走线没做好,导致Gen3链路只能跑在Gen2速率。后来重新布线才解决。记住:PCIe速率越高,对PCB的要求越严格。

1.4 链路训练

链路训练是PCIe设备上电后的第一步。两个设备会互相协商:

  1. 确定链路宽度(x1、x2、x4、x8、x16)
  2. 确定速率(Gen1、Gen2、Gen3...)
  3. 交换能力信息

这个过程完全由硬件自动完成,不需要软件干预。但作为FPGA工程师,你必须理解它的原理。因为如果链路训练失败,你的设备就根本没法用。

我遇到过最奇葩的情况是:一块FPGA板卡,插在某些主板上能正常工作,插在其他主板上就不行。最后发现是链路训练时的电气参数不匹配。解决方案是在物理层配置里调整去加重(De-emphasis)的幅度。

1.5 小结

这一章我们讲了PCIe的架构、拓扑和分层模型。说白了,PCIe就是一套标准化的通信协议,让不同厂家的设备能互相通信。作为FPGA工程师,你不需要记住所有细节,但一定要理解分层的思想——每一层各司其职,上层只管发数据,下层只管传数据。

下一章,我们会深入事务层,看看TLP到底长什么样。到时候我会拿一个实际的读请求例子,带你一步步分析。准备好了吗?

课后思考:为什么PCIe要采用分层模型?如果让你设计一个简化版的PCIe,你会保留哪些层?去掉哪些层?