详解Xilinx 使用BMG核调用BRAM


一、BRAM简介

   BRAM是“Block RAM”的缩写,指的是在FPGA中常见的存储器类型,用于存储数据和指令。BRAM通常由一系列存储单元组成,可用于在FPGA中实现存储器功能。

二、BMG简介和特点

   Xilinx提供 BMG(Block Memory Generator )IP核,方便用户调用BRAM资源来构成用户想要的存储器类型。例如:单端口 RAM、简单双端口 RAM、真正的双端口 RAM、单端口 ROM 和双端口 ROM 。对于双端口存储器,每个端口独立运行。每个端口均可选择工作模式、时钟频率、可选输出寄存器和可选引脚(简单双端口不能选工作模式)。

  1. BMG 可选存储器算法内核配置Block RAM 原语并使用以下算法之一将它们连接在一起:
  • 最小面积算法:使用最小数量的Block RAM 原语生成存储器。

  • 低功耗算法:生成存储器时,在读或写操作期间启用最少数量的块RAM 原语;

  • 固定原语算法:仅使用一种类型的Block RAM 原语生成内存;

  1. 每个端口可选择的操作模式:WRITE FIRST、READ FIRST 和 NO CHANGE,每个端口都可以分配其自己的操作模式。

  2. 可选端口宽高比:A 端口宽度可能与 B 端口宽度相差 1、2、4、8、16 或 32 倍。

  3. 可选的字节写入使能:提供字节写入支持,内存宽度是八位(无奇偶校验)或九位(有奇偶校验)的倍数。

  4. 可选流水线级:内核在 MUX 内提供可选流水线级,仅当存储器内核输出处的寄存器启用且仅适用于特定配置时才可用。

三、操作模式

  1. Write First 模式:在 WRITE_FIRST 模式下,输入数据同时写入存储器并驱动数据输出,如下图所示:
    在这里插入图片描述

   写操作:当 WEA 为 1 写入当前地址的数据,在下一个时钟 DOUTA 会输出这个地址新写入的数据。
   读操作:当 WEA 为 0 读出当前地址的数据,在下一个时钟 DOUTA 会输出这个地址的数据。

  1. Read First 模式:在 READ_FIRST 模式下,先前存储在写地址的数据出现在数据输出上,而输入数据则存储在内存中,如下图所示:

在这里插入图片描述
   写操作:当 WEA 为 1 写入当前地址的数据,而且在下一个时钟 DOUTA 会输出这个地址的原先的数据。
   读操作:当 WEA 为 0 读出当前地址的数据,在下一个时钟 DOUTA 会输出这个地址的数据。

  1. No Change模式:在 NO CHANGE 模式下,输出寄存器在写操作期间保持不变。输出的数据仍然是之前的Read数据,不受同端口Write操作的影响,如下图所示:

在这里插入图片描述
   写操作:当 WEA 为 1 写入当前地址的数据,和前面两种方式不一样,DOUT 保存不变。
   读操作:当 WEA 为 0 读出当前地址的数据,在下一个时钟 DOUTA 会输出这个地址的数据。

四、端口位宽不一致

  BMG IP核支持的端口纵横比为 1:32、1:16、1:8、1:4、1:2、1:1、2:1、4:1、8:1、16 :1 和 32:1。端口 A 数据宽度最多可以比端口 B 数据宽度大 32 倍,反之亦然。

  以下是AB端口位宽不一致的情况, 以下为32x2048 的真正双端口 RAM,即 A 端口宽度和深度。从8位B端口的角度来看,深度为8192。addra总线为11位,而addrb总线为13位。An 是相对于 A 端口的地址 n 处的数据字; Bn 是相对于 B 端口的地址 n 处的数据字;A0 由 B3、B2、B1 和 B0 组成。

在这里插入图片描述
  对于B端口,第B0地址为A0地址所在32位数据的低8位,以此类推。

五、字节写

  BMG IP核提供字节写入支持。字节写入可使用 8 位或 9 位字节大小。当使用 8 位字节大小时,不使用奇偶校验位,并且存储器宽度限制为 8 位的倍数。当使用 9 位字节大小时,每个字节都包含一个奇偶校验位,并且存储器宽度被限制为 9 位的倍数。

在这里插入图片描述
  从上面时序图可以看出,只要控制 WEA 就可以控制对具体哪一个 BYTE 进行写控制,例如当WEA[2:0]=011时候,就选取DINA[23:0]低两位字节写入到当前地址中。

六、输出寄存器

  BMG IP核可选的输出寄存器,这可能会提高内核的性能;可以选择在两个位置包含寄存器:BLOCK RAM 原语的输出处和内核的输出处。Block RAM 原语输出处的寄存器减少了原语的时钟到输出延迟的影响。内核输出端的寄存器通过输出多路复用器隔离延迟,从而改善块内存生成器内核的时钟到输出延迟。两个可选寄存器级中的每一个都可以分别为端口 A 和端口 B 选择。

  使用的每个可选寄存器级都会为读取操作增加一个额外的时钟周期延迟。

在这里插入图片描述
  下图显示了没有使用输出寄存器时的读数据 (LATCH) 和读使能 (en) 延迟, LATCH 信号是原语输出处的数据:

在这里插入图片描述
  下图显示了使用原语输出寄存器读取数据和读取使能延迟:
在这里插入图片描述
  下图显示了使用两级流水线寄存器的读取数据和读取使能延迟:
在这里插入图片描述

七、调用BRAM并仿真测试

7.1 单端口ROM的仿真测试

在这里插入图片描述

  单端口 ROM 允许通过单个端口对存储空间进行读访问

在这里插入图片描述
在这里插入图片描述
  首先生成好coe文件,从1累加到256的数据。
在这里插入图片描述

控制代码如下:

`timescale 1ns / 1ps

module bram_test(
    input                                               rd_clk  ,
    input                                               wr_clk  ,
    input                                               rst_n   
    );

    reg             [7:0]                               addra   ;
    wire            [8:0]                               douta   ;

always @(posedge rd_clk or negedge rst_n) begin
    if(rst_n == 1'b0)
        addra <= 'd0;
    else
        addra <= addra + 1'b1;   
end

u_bram u_bram (
  .clka(rd_clk ),    
  .addra(addra),  
  .douta(douta)  
);

endmodule

  仿真结果如下:
在这里插入图片描述
  时钟上升沿时刻输入地址信号,在下一时钟上升沿输出数据。

7.2 双端口ROM的仿真测试

在这里插入图片描述
  双端口 ROM 允许通过两个端口对内存空间进行读访问。还是以同样的配置方式,稍微修改以下控制程序,打开仿真:

`timescale 1ns / 1ps

module bram_test(
    input                                               rd_clk1  ,
    input                                               rd_clk2  ,
    input                                               rst_n   
    );

    reg             [7:0]                               addra   ;
    wire            [8:0]                               douta   ;
    reg             [7:0]                               addrb   ;
    wire            [8:0]                               doutb    ;
    

always @(posedge rd_clk1 or negedge rst_n) begin
    if(rst_n == 1'b0)
        addra <= 'd0;
    else
        addra <= addra + 1'b1;   
end

always @(posedge rd_clk2 or negedge rst_n) begin
    if(rst_n == 1'b0)
        addrb <= 'd0;
    else
        addrb <= addrb + 1'b1;   
end


u_bram u_bram (
  .clka(rd_clk1),   
  .addra(addra), 
  .douta(douta), 
  .clkb(rd_clk2),       
  .addrb(addrb), 
  .doutb(doutb)  
);

endmodule

在这里插入图片描述
  仿真结果依然和单口ROM一致;时钟上升沿时刻输入地址信号,在下一时钟上升沿输出数据。

7.3 单口RAM的仿真测试

在这里插入图片描述
  单端口 RAM 允许通过单个端口对存储器进行读写访问,wea = 1为写,wea=0为读。设置步骤如下:
在这里插入图片描述
在这里插入图片描述
  控制程序如下:

`timescale 1ns / 1ps

module bram_test(
    input                                               clk1  ,
    input                                               rst_n   
    );

    reg             [7:0]                               addra   ;
    reg             [8:0]                               dina    ;
    wire            [8:0]                               douta   ;
    reg                                                 wea ;

    reg             [7:0]                               addrb   ;
    reg             [8:0]                               dinb    ;
    wire            [8:0]                               doutb    ;
    

always @(posedge clk1 or negedge rst_n) begin
    if(rst_n == 1'b0)begin
        addra <= 'd0;
        wea <= 1'b1;
        dina <= 'd0;
    end
    else if(addra == 'd200)begin
        addra <= 'd0;
        wea <= 1'b0;
    end
    else begin
        addra <= addra + 1'b1;   
        dina <= dina + 1'b1;
    end
end

u_bram u_bram (
  .clka(clk1),      
  .wea(wea),        
  .addra(addra),    
  .dina(dina),      
  .douta(douta)     
);

endmodule

在这里插入图片描述
  当wea=1时,执行写操作,从地址0到200写入0到200的数据。

在这里插入图片描述
  当wea=0时,执行读操作,从地址0到200延迟一拍后读出数据。

7.4 简单双端口RAM的仿真测试

在这里插入图片描述
  简单双端口 RAM 提供两个端口 A 和 B,允许通过端口 A 对存储器进行写访问,并允许通过端口 B 进行读访问。

  还是按照上面的配置步骤,选择简单双端口RAM,宽度9,深度256。稍微修改一下控制程序,然后打开仿真:

`timescale 1ns / 1ps

module bram_test(
    input                                               clka  ,
    input                                               clkb  ,
    input                                               rst_n   
    );

    reg             [7:0]                               addra   ;
    reg             [8:0]                               dina    ;
    wire            [8:0]                               douta   ;
    reg                                                 wea ;

    reg             [7:0]                               addrb   ;
    reg             [8:0]                               dinb    ;
    wire            [8:0]                               doutb    ;
    

always @(posedge clka or negedge rst_n) begin
    if(rst_n == 1'b0)begin
        addra <= 'd0;
        wea <= 1'b1;
        dina <= 'd0;
        addrb <= 'd0;
    end
    else if(addra == 'd200)begin
        addra <= 'd0;
        addrb <= 'd0;
        wea <= 1'b0;
    end
    else begin
        addra <= addra + 1'b1;   
        addrb <= addrb + 1'b1;
        dina <= dina + 1'b1;
    end
end

u_bram u_bram (
  .clka(clka),    
  .wea(wea),      
  .addra(addra),  
  .dina(dina),    
  .clkb(clkb),    
  .addrb(addrb),  
  .doutb(doutb)   
);

endmodule

在这里插入图片描述

  开始端口A先进行写操作,从地址0写到200。数据从0开始累加到200。

在这里插入图片描述
  当端口A写满到200地址后拉低wea信号,然后开始端口B读操作,数据延迟端口B地址一拍出来。

7.5 真双端口RAM的仿真测试

在这里插入图片描述
  真双端口 RAM 提供两个端口 A 和 B任一端口都允许对存储器进行读和写访问。

  还是按照上面的配置步骤,选择真双端口RAM,宽度9,深度256。稍微修改一下控制程序,然后打开仿真:

`timescale 1ns / 1ps

module bram_test(
    input                                               clka  ,
    input                                               clkb  ,
    input                                               rst_n   
    );

    reg             [7:0]                               addra   ;
    reg             [8:0]                               dina    ;
    wire            [8:0]                               douta   ;
    reg                                                 wea ;

    reg             [7:0]                               addrb   ;
    reg             [8:0]                               dinb    ;
    wire            [8:0]                               doutb    ;
    reg                                                 web ;
    

always @(posedge clka or negedge rst_n) begin
    if(rst_n == 1'b0)begin
        addra <= 'd0;
        wea <= 1'b1;
        dina <= 'd0;
    end
    else if(addra == 'd200)begin
        addra <= 'd0;
        wea <= 1'b0;
    end
    else begin
        addra <= addra + 1'b1;   
        dina <= dina + 1'b1;
    end
end

always @(posedge clkb or negedge rst_n) begin
    if(rst_n == 1'b0)begin
        addrb <= 'd0;
        web <= 1'b1;
        dinb <= 'd0;
    end
    else if(addrb == 'd200)begin
        addrb <= 'd0;
        web <= 1'b0;
    end
    else begin
        addrb <= addrb + 1'b1;   
        dinb <= dinb + 1'b1;
    end
end


u_bram u_bram (
  .clka(clka),    
  .wea(wea),      
  .addra(addra),  
  .dina(dina),    
  .douta(douta),  
  .clkb(clkb),    
  .web(web),      
  .addrb(addrb),  
  .dinb(dinb),    
  .doutb(doutb)   
);

endmodule

在这里插入图片描述

  上面可以看出,端口A和B操作都和单端口一致,端口A和端口B的时钟可以异步,但是不能同时对一个地址进行操作,否者会出错。

参考

《PG058》

  • 22
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱奔跑的虎子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值