3. PCIe协议基础与Versal实现映射
PCIe 的协议栈可以粗略分为事务层、数据链路层和物理层。对 Versal 的 PCIe 硬核来说,理解这三层的关键,不是背协议名词,而是搞清楚“协议里的每一种包和机制,在硬核里由谁产生、由谁消费、软件能碰到的接口在哪里”。本节围绕 TLP、DLLP、物理层有序集、配置空间、BAR、MSI/MSI-X 六类对象,逐一映射到 Versal PCIe 硬核的对应机制。
TLP:事务层包与硬核的收发路径
TLP(Transaction Layer Packet)是 PCIe 事务层的基本传输单元,承载存储器读写、配置读写、完成(Completion)、消息(Message)等事务。一个 TLP 由头部、可选数据载荷和可选 ECRC 组成,头部中的 Fmt/Type 字段决定事务类型,Requester ID、Tag、Length 决定请求与完成的匹配关系。
在 Versal 中,TLP 的组装与解析由 PCIe 硬核内部的事务层完成,用户逻辑并不直接拼装 TLP 字节流。对作为 Endpoint 的 Versal 而言,外部 RC 发来的 MemWr/MemRd/CfgWr/CfgRd TLP 被硬核解析后,通过 AXI 或 AXI-Stream 接口呈现给用户逻辑;用户逻辑产生的读写请求,则由硬核封装成 TLP 发出。这里最需要建立的概念是:TLP 的“事务语义”在硬核边界被翻译成 AXI 事务,例如一个 128 字节的 MemWr TLP 可能对应一段 AXI 写突发,而 Tag 与 Completion 的匹配由硬核内部跟踪,用户逻辑通常只看到 AXI 的响应通道。
需要特别注意的是 TLP 的排序与流量控制。硬核内部维护 Credit 计数,只有当对端通告的 Credit 足够时才会发出 TLP;如果用户逻辑持续向硬核灌数据而 Credit 不足,AXI 写通道会出现反压。因此在实际设计中,不能假设“写进去就一定立刻发出去”,必须按 AXI 握手规则处理 ready/valid。
DLLP:链路层的确认与电源管理
DLLP(Data Link Layer Packet)由数据链路层产生和消费,不携带事务数据,主要用于 Ack/Nak 确认、流量控制 Credit 更新和电源管理。它由硬核自动处理,用户逻辑完全不可见。对设计者而言,DLLP 的意义在于:链路的可靠性(重传)和流控(Credit)是硬核自治的,不需要软件或用户逻辑干预。
但 DLLP 相关的状态会间接影响用户逻辑。例如当链路进入 L0s/L1 低功耗状态时,硬核会暂停 TLP 收发,AXI 接口上的事务会被延迟。因此如果系统对延迟敏感,需要在软件侧通过配置空间中的 Link Control 寄存器禁止或限制 ASPM,而不是试图在用户逻辑里“绕过”DLLP 机制。
物理层有序集:链路训练与状态机
物理层有序集(Ordered Set)是物理层在链路训练和状态切换时发送的特殊符号序列,包括 TS1/TS2、SKP、EIEOS、SDS 等。它们不经过数据链路层和事务层,直接在 SerDes 链路上传输。Versal 的 PCIe 硬核集成了 PCS/PMA,链路训练、位锁定、符号锁定、通道对齐、速率协商全部由硬核自动完成。
对用户来说,物理层有序集对应的可观测对象是硬核输出的链路状态信号,例如 LTSSM 状态、当前链路速率和链路宽度。在调试链路无法建立时,通常先看 LTSSM 停在哪个状态:停在 Detect 说明对端未上电或参考时钟异常;停在 Polling 说明 TS1/TS2 交换失败;停在 Configuration 说明通道映射或宽度协商有问题。这些判断依据来自物理层有序集的交互结果,而不是软件寄存器配置。
配置空间:Type0头与硬核寄存器映射
PCIe 配置空间是 4KB 的地址空间,前 256 字节为 PCI 兼容区,其中前 64 字节是标准头。Endpoint 使用 Type0 头,包含 Vendor ID、Device ID、Command、Status、BAR、Capabilities Pointer 等字段。Versal PCIe 硬核在作为 Endpoint 时,配置空间由硬核内部实现,软件通过 CfgRd/CfgWr TLP 访问。
在 Versal 中,配置空间的一部分字段是硬核固定的,例如 Vendor ID 和 Device ID 由硬核配置决定;另一部分可以通过硬核的配置接口或软件写入。实际调试时,最常关注的是 Command 寄存器中的 Memory Space Enable 和 Bus Master Enable:前者必须置 1,BAR 译码才会响应 MemWr/MemRd;后者必须置 1,Endpoint 才能发起 DMA 读写。如果软件发现 BAR 写不进去或 DMA 不工作,首先检查这两个位。
BAR:地址译码与地址窗口
BAR(Base Address Register)定义了 Endpoint 在系统地址空间中的窗口。Type0 头有 6 个 BAR,每个 BAR 可以是 32 位或 64 位,支持存储器或 I/O 空间。BAR 的“探测”过程是:软件向 BAR 写入全 1,读回后根据低位不可写位判断窗口大小和对齐要求,再写入实际基地址。
Versal 硬核的 BAR 实现有一个关键点:BAR 译码后的访问会被硬核转换成 AXI 事务,送到用户逻辑的指定地址区间。因此 BAR 的大小和地址映射必须与用户逻辑的 AXI 地址规划一致。例如,若 BAR0 配置为 1MB 的 64 位存储器 BAR,基地址为 0xA000_0000,则主机访问 0xA000_0000~0xA00F_FFFF 的 MemWr/MemRd 会被硬核转换为 AXI 事务,用户逻辑需要在该地址范围内提供对应的寄存器或存储器。
实际配置时,BAR 的地址分配由 RC 在枚举阶段完成,Endpoint 侧不能自行决定基地址。但 Endpoint 可以通过 BAR 的 sizing 结果确认窗口大小是否符合预期。如果 BAR 探测返回的大小与设计不符,通常是因为硬核配置中 BAR 的位宽或类型设置错误。
MSI/MSI-X:中断机制与硬核中断接口
MSI 和 MSI-X 是 PCIe 的消息信号中断机制。MSI 通过向指定地址写入指定数据来产生中断,MSI-X 则使用独立的表项,每个表项包含地址、数据和掩码,支持更多中断向量和更灵活的路由。相比传统 INTx 引脚中断,MSI/MSI-X 没有共享中断线的问题,延迟更低。
在 Versal 硬核中,MSI/MSI-X 的配置空间和中断表由硬核管理。用户逻辑产生中断请求后,硬核根据 MSI-X 表项中的地址和数据,自动生成一个 MemWr TLP 发往 RC。用户逻辑需要做的是:在硬核的中断接口上给出中断向量号或触发信号,硬核负责后续的 TLP 组装和发送。
实际使用 MSI-X 时,软件流程通常是:使能 MSI-X Capability 中的 MSI-X Enable 位,配置每个表项的地址和数据(通常由 RC 分配),清除 Mask 位,然后用户逻辑触发中断。如果中断不产生,检查顺序是:MSI-X Enable 是否置 1、对应表项 Mask 是否清除、用户逻辑是否真的拉高了中断触发信号、硬核的中断接口是否已使能。
从协议到实现的检查顺序
在 Versal PCIe 设计中,建议按以下顺序建立映射关系:先确认物理层链路是否建立(LTSSM 到 L0、速率和宽度符合预期),再确认配置空间是否可访问(CfgRd 能读到正确的 Vendor/Device ID),然后确认 BAR 译码是否生效(Command 寄存器 Memory Space Enable 置 1 后能读写 BAR 空间),最后确认 MSI-X 中断是否能正常上报。这个顺序与协议栈从下到上的层次一致,也符合硬核内部的处理路径。
需要强调的是,Versal PCIe 硬核把协议栈的大部分复杂性封装在内部,用户逻辑和软件看到的是经过抽象的事务接口和状态信号。理解 TLP、DLLP、有序集、配置空间、BAR、MSI/MSI-X 在硬核中的对应关系,目的不是去操作这些底层对象,而是在出现问题时能判断问题出在哪一层,以及应该检查哪个接口或寄存器。