第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设备上电后的第一步。两个设备会互相协商:
- 确定链路宽度(x1、x2、x4、x8、x16)
- 确定速率(Gen1、Gen2、Gen3...)
- 交换能力信息
这个过程完全由硬件自动完成,不需要软件干预。但作为FPGA工程师,你必须理解它的原理。因为如果链路训练失败,你的设备就根本没法用。
我遇到过最奇葩的情况是:一块FPGA板卡,插在某些主板上能正常工作,插在其他主板上就不行。最后发现是链路训练时的电气参数不匹配。解决方案是在物理层配置里调整去加重(De-emphasis)的幅度。
1.5 小结
这一章我们讲了PCIe的架构、拓扑和分层模型。说白了,PCIe就是一套标准化的通信协议,让不同厂家的设备能互相通信。作为FPGA工程师,你不需要记住所有细节,但一定要理解分层的思想——每一层各司其职,上层只管发数据,下层只管传数据。
下一章,我们会深入事务层,看看TLP到底长什么样。到时候我会拿一个实际的读请求例子,带你一步步分析。准备好了吗?
课后思考:为什么PCIe要采用分层模型?如果让你设计一个简化版的PCIe,你会保留哪些层?去掉哪些层?