第一部分:PCIe的第一性原理 - “网络化”的总线
要从根本上理解PCIe,必须抛弃传统并行总线(如PCI)的“共享总线”思维。PCIe的革命性在于它将网络通信的思想引入了板级互连。
1. 核心模型:点对点的串行链路 (Point-to-Point Serial Links)
抛弃共享: PCIe总线上没有共享的数据线。每个PCIe设备都通过一个或多个独立的、点对点的链路连接到一个交换机 (Switch)(通常集成在CPU的Root Complex中)。
串行差分: 每条链路的基础是一对差分信号线(`Tx+`/`Tx-`用于发送,`Rx+`/`Rx-`用于接收),构成一个Lane。这种结构抗干扰能力强,能以极高的频率(数GHz)传输数据。
可扩展性 (Express): 多个Lane可以聚合在一起形成更宽的链路(x1, x2, x4, x8, x16, x32),从而线性地提升带宽。一个x16的PCIe插槽就有16对独立的收发通道。
全双工: 发送和接收是独立通道,可以同时进行。
类比: 传统的PCI总线像一条单车道的乡村公路,所有车辆(设备)都要在上面抢道。而PCIe则像一个现代化的立交桥系统,每个目的地之间都有专属的高速匝道。
2. 核心机制:分层协议栈 (Layered Protocol Stack)
PCIe借鉴了OSI网络模型,将复杂的通信过程分解为三个清晰的层次。数据从上到下逐层打包,从下到上逐层解包。
事务层 (Transaction Layer):“做什么?”- 这一层是用户逻辑的接口。它定义了通信的目的和内容。例如,“从内存地址A读取32字节数据”或“向设备B的配置寄存器写入数据C”。它将这些请求打包成事务层包 (Transaction Layer Packet - TLP)。
数据链路层 (Data Link Layer):“如何保证可靠?”- 这一层是通信的“交通警察”。它为上层下来的TLP包添加序列号 (Sequence Number)和CRC校验码 (LCRC),确保数据在链路上传输的完整性和顺序。如果接收方发现CRC错误或序列号丢失,它会通过专用的DLLP包请求重传。
物理层 (Physical Layer):“如何传输比特?”- 这是“铺路工”。它负责将数据包进行8b/10b或128b/130b编码(以保证直流平衡和时钟恢复),然后串行化,最终通过差分对以电信号的形式发送出去。它还负责链路的初始化、速度协商和电源管理。
3. 核心通信方式:基于内存映射的包交换 (Memory-Mapped Packet Switching)
包 (Packet): PCIe中没有传统意义上的“数据总线”和“地址总线”。所有的信息,无论是地址、数据还是控制命令,都被封装在数据包 (Packets)中进行传输。
内存映射 (Memory-Mapped): 从CPU的角度看,FPGA卡上的存储器(BRAM、DDR4)和寄存器就像是主系统内存的一部分。CPU访问`0x80001000`这个地址,可能实际上是访问FPGA卡上某个FIFO的地址。这个地址到设备的映射由操作系统和BIOS在启动时配置。
交换 (Switching): 当CPU想读取FPGA上的数据时,CPU的Root Complex会生成一个带有地址的“内存读请求”TLP包。这个包经过PCIe交换机,像快递一样被路由到FPGA卡。FPGA的PCIe端点(Endpoint)接收到这个包,解析出地址,从内部存储器取出数据,然后封装成一个“完成”TLP包,再通过链路发回给CPU。
第二部分:PCIe协议详解 - 三层解构
1. 事务层 (Transaction Layer)
事务层包 (TLP): 是PCIe通信的核心。一个TLP主要由Header (包头), Data Payload (数据载荷), 和ECRC (端到端CRC)构成。
TLP类型: 主要分为四种请求/完成对:
内存读/写 (Memory Read/Write - MRd/MWr): 用于访问FPGA上的大块内存(如DDR4)。这是最大量、最主要的通信。
IO读/写 (I/O Read/Write): 访问遗留的I/O空间,现在已不常用。
配置读/写 (Configuration Read/Write - CfgRd/CfgWr): 用于系统启动时,由BIOS/OS读写PCIe设备的配置空间,以识别设备、分配地址空间和中断。
消息 (Messages): 用于传递电源管理、中断、错误信号等特殊事件。
地址空间与BAR (Base Address Register):
在配置空间中,有几个特殊的寄存器叫做BAR。系统启动时,操作系统会向BAR中写入一个物理基地址。
这个BAR就告诉FPGA:“从现在开始,CPU/系统内存中从这个基地址开始的一大块地址空间(例如1GB),就映射到你内部的资源上了。”
当一个内存请求TLP到达FPGA时,FPGA的PCIe核心会检查TLP中的地址是否落在BAR定义的范围内,如果是,就将这个请求转发给你的应用逻辑。
2. 数据链路层 (Data Link Layer)
这一层对用户逻辑通常是透明的,由PCIe硬核IP自动处理。但理解它有助于调试。
ACK/NACK协议:
发送方发出的每个TLP都有一个唯一的序列号。
接收方正确接收到TLP后,会回送一个ACK DLLP(数据链路层包),告知发送方“已收到,请发送下一个”。
如果接收方检测到CRC错误,会回送一个NACK DLLP,请求“请重发序列号为X的包”。
发送方内部有一个“重传缓冲区(Retry Buffer)”,在收到ACK之前,它会一直保留已发送的TLP副本。
流控 (Flow Control): 接收方会周期性地通过DLLP告知发送方自己接收缓冲区的剩余空间,避免发送方发送过快导致数据丢失。
3. 物理层 (Physical Layer)
这一层也对用户逻辑完全透明,由PCIe硬核IP中的高速收发器 (SerDes - Serializer/Deserializer)自动处理。
链路训练 (Link Training): 当系统上电或链路复位时,两个PCIe设备之间会进行一个复杂的握手过程,称为LTSSM (Link Training and Status State Machine)。它们会:
协商链路宽度(使用x1, x4, x8还是x16)。
协商链路速度(Gen1: 2.5 GT/s, Gen2: 5.0 GT/s, Gen3: 8.0 GT/s, Gen4: 16.0 GT/s, Gen5: 32.0 GT/s)。
进行信号均衡(Equalization)调整,以补偿PCB走线带来的信号衰减。