跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
编程语言

FPGA 实现 NVMe 硬盘读写功能详解

FPGA 作为 PCIe Root Complex 对接 NVMe SSD,需完成链路建立、配置空间枚举及控制器初始化。核心步骤包括 RC/EP 两端 BAR 与 MSI-X 中断配置,以及 NVMe Admin 队列(Identify、Create SQ/CQ)和 IO 命令的交互流程。实测显示在 Gen2 x4 环境下,读写速率可达 1GB/s 以上。

星辰大海发布于 2026/4/5更新于 2026/10/22129 浏览
FPGA 实现 NVMe 硬盘读写功能详解

一、开发流程概述

在 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 硬盘的配置空间初始化需手动操作:

  1. 获取 Capabilities 信息:从偏移 0x34 读取 Capability Pointer,遍历链表获取所有能力结构。
  2. 配置能力结构:如 Cap ID=0x10 为 PCIe 能力,需配置 Device Control 等寄存器。
  3. 配置 BAR 基地址:消费级 NVMe 通常一页 4KByte。通过 CfgWr 设置 TYPE0 配置空间偏移 0x04 的 BAR0,确保 4K 对齐。
  4. 配置 MSI-X 中断:MSI-X 支持独立的中断向量表(Table)和 Pending 表,存放在 BAR 空间中。需配置 Table BIR、Table Offset 及 Message Control 寄存器(使能位、Mask 位、Table Size)。
1.3.3 NVMe 控制器寄存器配置

完成 PCIe 配置后,需配置 NVMe 控制器寄存器(位于 BAR0/1 映射空间):

  1. 等待 CSTS.RDY 变为 0(若不满足则配置使其就绪)。
  2. 配置 AQA(Admin 队列属性)、ASQ(Admin SQ 基址)、ACQ(Admin CQ 基址)。
  3. 配置 CC(控制器配置)寄存器,设置队列元素大小、页大小等。
  4. 置 CC.EN 为 1 使能控制器。
  5. 等待 CSTS.RDY 置 1。

关键寄存器说明:

  • CAP:控制器能力(页大小范围、DB 步长等)。
  • CC:当前配置(CAP 的子集,重启可换)。
  • AQA/ASQ/ACQ:定义 Admin 队列。
  • DoorBell (0x1000+):提交队列(SQ)和完成队列(CQ)的门铃寄存器,Host 写入新尾指针通知 Controller。

1.4 NVMe 协议命令

NVMe 命令分为 Admin 命令和 IO 命令,均封装为 16 DW 的 TLP 包。

Dword字段
0CID、传输方式、聚合操作、操作码
1NID(命名空间 ID)
2-3保留
4-5元数据指针 (MPTR)
6-9数据指针 (DPTR)
10-15命令特定参数
1.4.1 Admin 命令

Admin 命令仅提交到 Admin SQ/CQ,用于管理控制器。常用指令如下:

操作码指令作用
00h删除 I/O SQ释放 SQ 空间
01h创建 I/O SQ分配地址、优先级、大小
02h获取日志返回日志页
04h删除 I/O CQ释放 CQ 空间
05h创建 I/O CQ分配地址、中断向量、大小
06hIdentify返回 Controller/Namespace 数据结构
09hSet Features设置特性
0AhGet Features获取特性
80hFormat擦除 LB 内容

注意:先创建 CQ 再创建 SQ。Admin 队列通过 ASQ 等寄存器创建。

1.4.2 IO 命令

IO 命令负责数据传输,以 LB(逻辑块)为单位。常用指令:

操作码指令作用
00hFlush提交数据到 NVM
01hWrite写入 NVM
02hRead读取 NVM
04hWrite Uncorrectable标记无效块
05hCompare比较数据
1.4.3 命令交互过程
  1. Host 准备命令:将 16 DW 命令写入分配的 SQ 中。
  2. 更新 DoorBell:Host 通过 MWr 向 Controller 的 SQ DB 寄存器(BAR0+0x1000)写入尾指针增量。
  3. Controller 取命令:Controller 通过 DMA 从 ASQ 读取命令。
  4. 执行命令:Controller 处理数据。
  5. 返回完成:Controller 通过 DMA 将 4 DW 完成包写入 Host 的 CQ 基址(ACQ)。
  6. 中断通知:Controller 发起 MSI-X 中断(需检查未屏蔽)。
  7. Host 响应:Host 接收中断,更新 CQ DoorBell(BAR0+0x1004)告知已处理完成。
1.4.4 执行顺序

RC 读写前需按序执行 Admin 命令:

  1. Identify(获取数据结构)。
  2. Set Features(申请 IO 队列数量)。
  3. 创建 IO CQ。
  4. 创建 IO SQ。

创建的队列数需与 AQA 寄存器中的 ACQS/ASQS 及 Set Features 申请值一致(最大 4K,最小 2 个)。

二、读写测试与结果

2.1 硬件环境

测试需 FPGA 板卡(如 7 系列)、M.2 接口及 NVMe 硬盘。PCIe Gen2 x4 理论上限约 2GB/s。本次测试使用拆机 M.2 NVMe 盘(512GB,LB 512B,LBA 约 10 亿个)。建议测试时选用高性能盘(如三星 980/990)以获得更准确带宽表现。

2.2 文件系统

NVMe 支持 NTFS/exFAT 等,但 FPGA 纯逻辑实现文件系统较为繁琐。本测试跳过文件系统层,直接通过 LB 地址进行读写,适用于数据采集回放等场景。

2.3 状态监控

程序启动后可读取以下关键状态:

  • w_Namespace_Size:LB 数目。
  • w_lb_size:单 LB 字节数(2^lb_size)。
  • w_nvme_config_done:配置完成标志。
  • w_link_width/rate:链路宽度与速率(如 x4, 5.0GT/s)。
  • w_pl_ltssm_state:LTSSM 状态(应为 L0)。
2.4 测速结果

通过 VIO 控制读写,BAR 设置为 4K 对齐。分别测试 1GB 至 100GB 数据量的读写速率:

测试数据量写速率读速率
1GB1094 MB/S1251 MB/S
10GB920 MB/S1261 MB/S
50GB843 MB/S1262 MB/S
100GB836 MB/S1261 MB/S

写 1GB 耗时约 116938546 个时钟周期(125MHz),读 1GB 耗时约 102270401 个时钟周期。整体性能受限于 PCIe 通道带宽及 SSD 自身性能。

目录

  1. 一、开发流程概述
  2. 1.1 PCIe 基础机制
  3. 1.1.1 PCIe 配置空间
  4. 1.2 建链与枚举
  5. 1.2.1 建链
  6. 1.2.2 枚举
  7. 1.3 RC 与 EP 初始化流程
  8. 1.3.1 RC 端初始化
  9. 1.3.2 EP 端初始化
  10. 1.3.3 NVMe 控制器寄存器配置
  11. 1.4 NVMe 协议命令
  12. 1.4.1 Admin 命令
  13. 1.4.2 IO 命令
  14. 1.4.3 命令交互过程
  15. 1.4.4 执行顺序
  16. 二、读写测试与结果
  17. 2.1 硬件环境
  18. 2.2 文件系统
  19. 2.3 状态监控
  20. 2.4 测速结果

更多推荐文章

查看全部
  • Go Channel 深入解析
  • JVM 常见垃圾回收算法详解:Parallel、CMS 与 G1
  • 基于 LangChain 实现数据库问答机器人
  • GitHub Copilot 学生认证指南:免费获取 Pro 版权益
  • FPGA DDR4 读写基础:MIG IP 核控制信号详解
  • 算法基础:一维前缀和
  • 大模型技术入门与进阶学习指南
  • 路径类动态规划入门:3 道经典例题全解
  • AI 产品经理必修:神经网络核心原理与应用解析
  • Mastering GitHub Copilot 课程点评:免费版与 Pro 版差异解析
  • LangChain 大模型对话记忆模块实战与 Web 应用搭建
  • OpenClaw 相关开源 AI 项目汇总
  • OpenDroneMap 无人机影像三维重建:安装与实战指南
  • Python FastAPI 入门实战:从环境搭建到数据模型
  • Python 数据可视化绘图基础与实战指南
  • Python AI 入门指南:从线性回归到图像分类
  • 毕业论文全流程通用 AI 指令清单(21 条)
  • VS Code 下载、安装与配置指南
  • Vue3 ElementUI TypeScript 设置 style 属性类型检查失败解决方案
  • 浏览器 F5 刷新机制深度解析

相关免费在线工具

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online

  • JSON 压缩

    通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online

  • JSON美化和格式化

    将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online