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:可以选择NativeAXI4

  • 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配置为例。

  • WidthDepth:根据需求填即可。

  • Operating Mode:有Write FirstRead FirstNo 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];
end

3.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];
end

3.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];
end

3.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

FPGA(三)Block RAM
https://shuusui.site/blog/2025/11/26/fpga-3/
作者
Shuusui
发布于
2025年11月26日
更新于
2025年11月27日
许可协议