FPGA-BRAM
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核总体设计

这个模块是一个 双端口 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 个端口 | 只读 | 可独立时钟 | 是(两端同时读)并行读取性能高 |
这样做的好处:
- 支持两个时钟域;
- 支持并行访问(例如一个写入,一个读取,但是需要两端访问不同地址,防止冲突);
这里每个引脚的意义:
- 端口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=1 且 wea=1 时:写操作(dina → BRAM[addra])
当 ena=1 且 wea=0 时:读操作(BRAM[addra] → douta)
但是这个端口A设置为了只写不读,所以后者就用不到。
- 端口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口只读 的一种“简化双口结构”。

这三种配置模式:
| 模式 | 名称 | 写入同周期时的输出行为 | 典型含义 |
|---|---|---|---|
| Read First | 先读后写 | 当写入某地址时,输出端口会先输出旧数据,再写入新数据 | 读出旧值 |
| Write First | 先写后读 | 当写入某地址时,输出端口立即输出新写入的数据 | 读出新值 |
| No Change | 不变 | 写入期间输出保持上一个周期的值,不变 | 输出保持 |
这三种模式只影响同周期内同时发生写和读时的输出结果。
那为什么 Simple Dual Port 也能选 Read First?
虽然 Simple Dual Port RAM 通常用于:
- Port A 写入
- Port B 读取
但 Xilinx 的实现结构上,Port A 仍然保留了完整的读出通路(douta),
只是默认在界面里不显示 / 没启用,但在底层电路配置中依然存在。
