一、开发流程概述
在 FPGA 外挂 NVMe 硬盘的场景中,通常将 FPGA 配置为 Root Complex (RC),而 NVMe SSD 作为 Endpoint (EP)。NVMe 协议基于 PCIe 总线,属于其特殊应用。开发核心在于 PCIe 链路的建立、配置空间枚举以及 NVMe 控制器的初始化与命令交互。
1.1 PCIe 基础机制
PCIe 协议涉及两种机制(请求与完成)、三层结构(事务层、链路层、物理层)及四种事务类型(内存、I/O、配置、消息)。数据交换采用请求 - 响应模式,用户主要关注事务层 TLP 包的构造与解析。
TLP 包头部包含 Fmt(格式位,区分 3DW/4DW)和 Type(传输类型),两者结合确定数据包属性。开发过程中常用的事务类型包括 MRd(内存读)、MWr(内存写)、CfgRd0/CfgWr0(配置读写)、Cpl/CplD(完成包)及 Msg(消息)。
1.1.1 PCIe 配置空间
RC 与 EP 均需访问各自的 PCIe 配置空间(共 4KB)。每个 Function 对应一个配置空间:
- 0-3Fh:PCI 兼容头(Type 0 用于 PCIe 设备,Type 1 用于桥)。
- 40h-FFh:能力结构体(Capability Structures),如 MSI/MSI-X 中断相关。
- 100h-FFFh:扩展配置空间。
扫描能力结构体是必须的步骤。通过 Header 中的 Capability Pointer 寄存器遍历链表,直至指针为 0。不同设备类型的 Capability ID 不同,例如 0x11 代表 MSI-X 中断。
1.2 建链与枚举
1.2.1 建链
上电后,FPGA 与 NVMe 设备根据 PCIe 协议进入 LTSSM 状态机,自动协商速率和宽度。若无硬件问题,两端应最终稳定在 L0 状态。可通过 PCIe IP 核的接口参数检测链路状态(Link Up, Width, Rate)。
1.2.2 枚举
Active 状态下开始设备枚举。RC 通过 CfgRd 访问 EP 的 BDF(Bus, Device, Function),读取 Vendor ID、Device ID 等寄存器确认设备存在。若收到 CPLD 完成包且 ClassCode 符合(如 NVMe 为 0x010802),则枚举成功。
1.3 RC 与 EP 初始化流程
在读写前,需按顺序完成 PCIe 配置空间初始化及 NVMe 控制器寄存器配置。
1.3.1 RC 端初始化
FPGA 端的 PCIe 配置空间(ID、BAR、能力结构等)通常由 IP 核设置自动完成。访问与重配置可通过核的配置管理接口(CMI)实现。
1.3.2 EP 端初始化
NVMe 硬盘的配置空间初始化需手动操作:
- 获取 Capabilities 信息:从偏移 0x34 读取 Capability Pointer,遍历链表获取所有能力结构。
- 配置能力结构:如 Cap ID=0x10 为 PCIe 能力,需配置 Device Control 等寄存器。
- 配置 BAR 基地址:消费级 NVMe 通常一页 4KByte。通过 CfgWr 设置 TYPE0 配置空间偏移 0x04 的 BAR0,确保 4K 对齐。
- 配置 MSI-X 中断:MSI-X 支持独立的中断向量表(Table)和 Pending 表,存放在 BAR 空间中。需配置 Table BIR、Table Offset 及 Message Control 寄存器(使能位、Mask 位、Table Size)。
1.3.3 NVMe 控制器寄存器配置
完成 PCIe 配置后,需配置 NVMe 控制器寄存器(位于 BAR0/1 映射空间):
- 等待 CSTS.RDY 变为 0(若不满足则配置使其就绪)。
- 配置 AQA(Admin 队列属性)、ASQ(Admin SQ 基址)、ACQ(Admin CQ 基址)。
- 配置 CC(控制器配置)寄存器,设置队列元素大小、页大小等。
- 置 CC.EN 为 1 使能控制器。
- 等待 CSTS.RDY 置 1。
关键寄存器说明:
- CAP:控制器能力(页大小范围、DB 步长等)。


