前言
对于主机而言,FPGA-PCIe 设备通过其 BAR(Base Address Register)被识别和访问。主机必须通过读写 BAR 所映射的地址空间,才能与 FPGA-PCIe 正确通信。这相当于将 FPGA-PCIe 内部的地址区域映射到主机的内存空间中,主机通过访问这段内存来完成数据收发。
readl(dif->bar0_mapped_addr + (offset<<2));//read data from bar0,trans to TLP packetwritel(val, dif->bar0_mapped_addr + (offset<<2));//val is data,write data to bar0,trans to TLP packet
BAR的定义

每个 Endpoint(EP)设备都包含一个 Type 0 型配置空间,其中最多可分配 6 个 BAR。若某个 BAR 未被使用,硬件会将其固定为 0。
BAR 的低 4 位决定了其地址空间的类型与属性:
-
• Bit 0:指示该空间用于接收 Memory 请求还是 I/O 请求。在现代 PCIe 体系中,I/O 方式已基本被 MMIO 取代,因此该位通常设为 0。
-
• Bit [2:1] :表示地址空间的大小类型:
-
•
00表示 32 位地址,可寻址 4 GB 空间; -
•
10表示 64 位地址,可支持极大地址范围。具体选择取决于 PCIe 系统所需的 MMIO 寄存器空间大小,或 DMA 数据缓存的大小。 -
• Bit 3:控制是否启用预取(Prefetchable)。对于寄存器类资源(如具备“读清”特性的状态寄存器),不应开启预取,否则可能误清状态。此外,对带宽和实时性不敏感的寄存器进行预取并无实际意义。然而,对于一些高性能网卡类FPGA 应用,其内部的tx/rx队列会被映射到用户态,用户态软件能直接写入队列描述符,主机可以连续读写这些队列,预取能有效降低PCIe延迟:抑或是FPGA设计中暴露连续可读的数据缓冲区如实时采样数据或状态阵列,若由 FPGA 主动发送,数据包可能被拆分为多个小包;而启用预取后,主机可合并访问连续地址,一次性读取大量数据,显著提升传输性能。
BAR的大小
BAR 所映射地址空间的实际大小由其低位中硬编码为 0 的区域决定。如上文所述,主机在枚举时会向 BAR 写入全 1 值,而那些被硬件固定为 0 的位则无法被修改。通过读取回的值,主机可识别出该 BAR 的有效地址范围大小。
例如,若回读值的低 12 位为全0,表示该 BAR 请求的空间大小为4 KB。随后,主机将在高位分配一个基地址(如 0xF9000),并将其与 BAR 中确定的大小范围组合,最终形成完整的设备地址空间,例如:0xF9000000 ~ 0xF9000FFF。
写在最后
FPGA-PCIe 设备通过 BAR 将内部资源映射到主机地址空间,主机对这些地址的 readl/writel 都会转换为 PCIe TLP,从而完成与设备的交互。BAR 的类型由低位编码决定,其中最关键的是 Prefetchable 属性:
- • 寄存器类区域(状态寄存器、控制寄存器)不可预取,否则可能读到旧值或误清状态。
- • 连续可读写的缓冲区/队列(如网卡的 RX/TX 队列、FPGA 数据窗口)适合设置为可预取,主机可一次读取多个 cacheline,减少 TLP 包数量,显著降低访问延迟。
此外,BAR 的实际大小由硬件硬编码的低位 0 决定,系统在枚举时写全 1 并回读即可识别其大小并完成内存映射。
评论区
登录后即可参与讨论
立即登录