FPGA-BRAM(pg058)

一、什么是BRAM

Xlinx 系列FPGA,包含两种RAM:Block RAM 和分布式RAM(Distributed RAM),他们的区别在于:

  • Block RAM是内嵌专用的RAM,具有更高的时序性能;

  • Distributed RAM 需要消耗珍贵的逻辑资源组成,由于分布在不通的位置,延迟较大。

二、FPGA中为什么要用BRAM

在 FPGA 设计中,存储资源 是非常关键的一部分。不同于传统 CPU 或 MCU 中统一规划的内存结构,FPGA 内部的存储需要由设计者自行规划与分配。Xilinx 系列 FPGA 中的 BRAM便是为了解决片上高速存储需求而设计的专用存储单元。

2.1 数据访问速度快

BRAM 位于 FPGA 的内部逻辑区域,距离计算单元(如 DSP、ALU、逻辑单元)非常近,可以在 1~2 个时钟周期 内完成数据读写。
相比之下,如果从外部 DDR、SRAM 等访问数据,通常需要几十甚至上百个时钟周期。
因此,在高速信号处理、滤波、图像缓存、波束形成等场景中,BRAM 可以显著降低延迟。

2.2 降低对外部存储的依赖

在许多设计中,外部存储(DDR/SDRAM)带宽有限,而数据访问往往是高频并行的。
通过在 FPGA 内部使用 BRAM 作为 片上缓存(On-Chip Buffer),可以实现数据分片存取、并行访问、流水线处理等操作,从而降低外部带宽压力。

2.3 读写灵活

BRAM 支持多种配置方式(这些在后面也有提及):

  • 单口 RAM(Single Port)
  • 简单双口 RAM(Simple Dual Port)
  • 真双口 RAM(True Dual Port)
  • ROM 模式

这使得它可以根据设计需求灵活使用,例如:

  • 一端写入、一端读取(如采集-处理结构)
  • 双核共享访问(如双通道 DSP)
  • 固定系数查表(ROM 模式)

2.4 节省LUT

如果不使用 BRAM,而在逻辑单元(LUT)中构建存储(即 Distributed RAM),将会消耗大量可编程逻辑资源。BRAM 提供了一个面积效率更高、速度更快的专用存储块,可以显著降低资源利用率,留出更多逻辑单元用于主功能模块。

2.5 支持多时钟域与高带宽访问!

True Dual Port BRAM 允许两个端口分别使用独立时钟(clka / clkb),在多时钟域系统中非常实用。
它可用于跨时钟数据交换、异步 FIFO 或并行总线接口缓冲,实现高速而安全的数据传输。

三、怎么用BRAM

3.1 使用IP核(Block Memory Generator)

3.1.1 IP核总体设计

image-20251011103605199

这个模块是一个 双端口 Block RAM,即在同一块存储空间上提供两个独立的读写接口(A端口和B端口),它们可以同时读写不同地址的数据。

图中Memory Type设置为Simple Dual Port RAM,为A端口写入,B端口读取。下表中列出了所有设置对应的情况

类型名称 端口数 读写特性 时钟独立性 是否支持同时读写
Single Port RAM 1 个端口 同一个端口读/写 单时钟 否(同一时钟周期只能读或写)
Simple Dual Port RAM 2 个端口(A写/B读) A端口写入,B端口读取 可独立时钟(clka/clkb) 是(A写入同时B读取)
True Dual Port RAM 2 个完全独立端口 两端口均可读写 可独立时钟 是(但写冲突需避免)
Single Port ROM 1 个端口 只读 单时钟
Dual Port ROM 2 个端口 只读 可独立时钟 是(两端同时读)并行读取性能高

这样做的好处:

  • 支持两个时钟域;
  • 支持并行访问(例如一个写入,一个读取,但是需要两端访问不同地址,防止冲突);

这里每个引脚的意义:

  1. 端口A:
信号名 位宽 方向 说明
addra[9:0] 10位 输入 地址线,控制 A 端口访问的存储单元(2¹⁰=1024 深度)
clka 1 输入 时钟信号,驱动 A 端口所有寄存操作
dina[31:0] 32位 输入 要写入的数据输入线
ena 1 输入 端口使能信号,为 1 时该端口工作
wea[0:0] 1 输入 写使能信号,高电平时写入 dina 到地址 addra

ena=1wea=1 时:写操作(dina → BRAM[addra])

ena=1wea=0 时:读操作(BRAM[addra] → douta

但是这个端口A设置为了只写不读,所以后者就用不到。

  1. 端口B:
信号名 位宽 方向 说明
addrb[9:0] 10位 输入 地址线,控制 B 端口读取哪个存储单元
clkb 1 输入 时钟信号,驱动 B 端口读出逻辑
doutb[31:0] 32位 输出 从 BRAM 读出的数据
enb 1 输入 端口使能信号,为 1 时允许输出有效数据

enb=1 时,B 端口会在 clkb 上升沿输出 doutb = BRAM[addrb]

enb=0,则保持上次输出或无效。

3.1.2 Operating Mode选项

对于Simple Dual Port RAM模式下的端口A,如下图显示,可以看到其Operating Mode有三种工作模式,那既然如上所述,这个A口是写口,为什么还要有这种功能选择呢?其实Vivado 的 “Simple Dual Port RAM” 并不是完全“写专用 + 读专用”,而是实现为A口可写也可读(但主要用于写),B口只读 的一种“简化双口结构”。

image-20251011105008864

这三种配置模式:

模式 名称 写入同周期时的输出行为 典型含义
Read First 先读后写 当写入某地址时,输出端口会先输出旧数据,再写入新数据 读出旧值
Write First 先写后读 当写入某地址时,输出端口立即输出新写入的数据 读出新值
No Change 不变 写入期间输出保持上一个周期的值,不变 输出保持

这三种模式只影响同周期内同时发生写和读时的输出结果。

那为什么 Simple Dual Port 也能选 Read First?

虽然 Simple Dual Port RAM 通常用于:

  • Port A 写入
  • Port B 读取

但 Xilinx 的实现结构上,Port A 仍然保留了完整的读出通路(douta)
只是默认在界面里不显示 / 没启用,但在底层电路配置中依然存在。