FPGA(三)Block RAM
3.1 BRAM资源介绍
每个BRAM的大小为36Kb,有两个完全独立的端口,每个端口位宽最多72。
每个端口都可以配置为(深度 × 位宽):32K × 1, 16K × 2, 8K × 4, 4K × 9 (or 8), 2K × 18 (or 16), 1K × 36 (or 32), 512 × 72 (or 64)。且两个端口的深度和位宽可以不一样,只要乘积相等。
每个BRAM还可以拆分为两个完全独立的18Kb的BRAM,可以配置为16K × 1至512 × 36。
3.2 IP核使用
注意使用的是
Block Memory Generator。
3.2.1 Basic配置

Interface Type:可以选择
Native或AXI4。Memory Type:支持5种类型的存储(图片与下面5种一一对应)。

Single-port RAM(单端口RAM):仅通过A端口读写。
Simple Dual-port RAM(简单双端口RAM、伪双端口RAM):A端口写,B端口读。
Ture Dual-port RAM(真双端口RAM):A端口和B端口都可以读写。
Single-port ROM(单端口ROM)
Dual-port ROM(双端口ROM)
ECC Options:只有存储类型为
Simple Dual-port RAM时才可用。数据位宽小于等于64时,可以使用额外的8位来进行单比特纠错和双比特错误检测。Write Enable:设置是否启用字节写入。启用时,字节位宽可选为8位(无奇偶校验位)或9位(有奇偶校验位),此时数据位宽应是字节位宽的倍数。启用后,原来1位的
wea信号会变为多位,每8/9位数据对应1位使能。Algorithm Options:选择实现的内存算法。
- Minimum Area Algorithm:使用最少数量的原语生成IP核;
- Low Power Algorithm:低功耗算法,在读或写操作期间启用最小数量的块RAM原语;
- Fixed Primitive Algorithm:固定单元算法,连接一个基本内存单元来生成IP核,在下拉列表中选择要使用的单元类型。
3.2.2 Port配置
以下图
Ture Dual-port RAM配置为例。

Width和Depth:根据需求填即可。
Operating Mode:有
Write First、Read First和No Change三种模式,将在3.3 工作模式中详细讲解。Enable Port Type:端口使能控制。默认
Use ENA Pin,端口列表中会有一个ena信号;如果选择Always Enabled则没有该信号。Optional Output Rregisters:选择是否在输出端添加寄存器。输出波形如下,如果勾选了Primitives或Core则会多延迟一周期,都勾选则多延迟两周期。一般推荐选Primitives,对时序要求高则都选。
- Primitives Output Register:在BRAM原语内部添加一级寄存器。
- Core Output Register:在BRAM原语外部添加一级寄存器。

Output Reset Options:配置复位信号,少用。
3.2.3 其他配置
主要用于初始化RAM/ROM存储,使用的coe文件格式如下,vector中的数据换不换行都可以。
memory_initialization_radix=16;
memory_initialization_vector=
1111,
2222,
3333,
4444,
5555,
6666,
aaaa,
bbbb;3.3 工作模式
3.3.1 Write First
写操作时,输出端口会将当前写的数据输出。也称Write Through。

等价代码:
//write port
always @(posedge clk) begin
if(en && we)
RAM[addr] <= di;
end
//read port
always @(posedge clk) begin
if(en)
if(we)
dout <= di;
else
dout <= RAM[addr];
end3.3.2 Read First
写操作时,输出端口会将当前写地址的原数据输出。

等价代码:
//write port
always @(posedge clk) begin
if(en && we)
RAM[addr] <= di;
end
//read port
always @(posedge clk) begin
if(en)
dout <= RAM[addr];
end3.3.3 No Change
写操作时,输出端口会保持原值不变(有个寄存器暂存)。只有在读操作的过程中输出端口才会变化。

等价代码:
//write port
always @(posedge clk) begin
if(en && we)
RAM[addr] <= di;
end
//read port
always @(posedge clk) begin
if(en && !we)
dout <= RAM[addr];
end3.3.4 仿真验证
使用的是
Single-port RAM,位宽16,深度8,RAM默认值为0~7。

`timescale 1ns / 1ps
module tb_test;
logic clk;
logic ena;
logic wea;
logic [ 2:0] addra;
logic [15:0] dina;
wire [15:0] douta;
blk_mem_gen_0 single_port_ram_u (
.clka(clk), // input wire clka
.ena(ena), // input wire ena
.wea(wea), // input wire [0 : 0] wea
.addra(addra), // input wire [2 : 0] addra
.dina(dina), // input wire [15 : 0] dina
.douta(douta) // output wire [15 : 0] douta
);
initial begin
clk = 1;
ena = 0;
wea = 0;
addra = 3'd0;
dina = 16'h0;
#15 ena = 1;
#10 wea = 1;
#20 wea = 0;
end
always #5 clk = ~clk;
always @(posedge clk) begin
if (addra == 3'd7) addra <= addra;
else addra <= addra + 3'd1;
end
always @(posedge clk) begin
if (dina == 16'hffff) dina <= dina;
else dina <= dina + 16'h1111;
end
endmodule