如何将数据写入 bram 并从 bram 读取数据?

How to write data into bram and read data from bram?

提问人:superb ranjeet 提问时间:11/3/2023 最后编辑:toolicsuperb ranjeet 更新时间:11/6/2023 访问量:219

问:

我试图理解在某些控制情况下,写作和阅读是如何在BRAM记忆中发生的。请告诉我我的代码中是否有任何概念错误:

module bram_dual(wrt_data,addr_w,rst,clk,wr_en,read_data,rd_en);

input [17:0]wrt_data;
input clk,rst,wr_en;
input [4:0]addr_w;
output [17:0]read_data;
output  rd_en;

reg [17:0]ram[0:23];
integer i;

always@(posedge clk) begin
    if(rst)begin 
       for (i=0;i<23;i=i+1)begin  
          ram[i]<={24{1'b0}};
            
       end 
     end 
     else 
       if(wr_en) begin
          ram[addr_w]<=wrt_data;
       end 
end 

assign read_data=rd_en ? ram[addr_w]:0;
    
endmodule

测试台:

module tb_bram;

reg [17:0]wrt_data;
reg clk,rst,wr_en;
reg [4:0]addr_w;
wire  [17:0]read_data;
wire  rd_en;


integer j;

bram_dual dut1 (.wrt_data(wrt_data),
                .clk(clk),
                .rst(rst),
                .wr_en(wr_en),
                .addr_w(addr_w),
                .read_data(read_data),
                .rd_en(rd_en)
                
                ); 
 
 

 initial begin
  
  rst<=1;
  clk<=0;
  
  #20; 
  rst <=0;
  
  end
always@(posedge clk) begin
       if (rst) begin 
          wr_en<=0;
          wrt_data<=0;
          addr_w<=0;
       end 
       else begin 
         if (wr_en) begin
            for (j=0;j<23;j=j+1) begin
               wrt_data<=j;
               addr_w<=j;
            end 
          end   
         else begin 
             wrt_data<=0;
         end 
       end 
end    
 
always #10 clk=~clk;

endmodule

我有与将数据写入 bram memroy 和从 bram 内存读取数据相关的问题。

我可以使用两个信号将数据写入 bram 并从 bram 读取数据吗?

就像在写入操作期间一样: 通过此信号将数据写入 BRAM -> write_enable ,address_write

读取操作: read_enable , address_read

我可以使用单独的使能信号进行写和读操作吗? 同样,我们也可以为地址做吗?

从理论上讲,我知道我可以,但从逻辑上讲,当我尝试在Verilog编码中做到这一点时,我失败了。

Verilog System-Verilog FPGA RAM Xilinx

评论


答:

0赞 Mikef 11/3/2023 #1

该答案是对 @toolic 提供的答案的补充,与 RTL 综合流程中块内存的推理有关。我之所以添加这个,是因为问题标题包含术语“bram”,通常表示块内存,并使用 Xilinx 标签,即物理硬件。

块内存是许多物理FPGA设备中发现的一种特定类型的存储器。
块 ram 没有复位引脚(它们提供任何使用输入引脚清除 RAM 内容的方法)。

该代码位使用复位输入(复位引脚)对复位进行建模,因此此代码不会推断出块内存。

if(rst)begin 
   for (i=0;i<23;i=i+1)begin  
      ram[i]<={24{1'b0}};
   end

包含此截图的发布代码非常笼统地对内存进行建模,但是它将由寄存器和组合逻辑组成,而不是块内存。此结构称为寄存器文件,而不是内存。在这种情况下,读取端只是所有寄存器的多路复用器。

要使用初始值正确建模和推断FPGA综合中的模块RAM,请删除或注释该模块,然后使用if(rst)

initial 
   $readmemh("file_with_initial_values.txt",ram);

根据指定为系统任务参数的文件的内容初始化内存。这是 bram 的一次性初始化,它发生在物理设备配置接近尾声时(WRT 时间),通常在托管 FPGA 的电路板首次上电时发生。任务 $readmemh() 在 SystemVerilog 标准
IEEE SV 1800-2017 第 21.4 节 从文件加载内存阵列数据 中进行了描述。

或者,如果您需要写入由复位输入动态触发的硬编码值(如 0),并且需要块 ram,则注释或删除复位块,并设计一个状态机 (SM) 控制器,该控制器根据需要生成任意数量的同步写入事务,以便在置位复位输入时将值写入每个位置。请注意,执行 n 次写入需要 n 个时钟(它不是单个时钟操作)。在您的情况下,这将涉及 SM 在数据中输入 24 个 0,同时写入使能保持活动状态,并在复位输入为真时将地址递增 23 次,从 0 开始。SM 完成后,将写入数据、写入启用和写入地址返回到其正常行为。

Xilinx 文档 UG901 综合指南的第 4 章包含存储器建模的编码风格建议,包括块 ram 推理的编码风格。有几个示例可以剪切和粘贴,然后根据上下文需求进行自定义。

0赞 Tushar 11/6/2023 #2
always@(posedge clk) begin
  if(wr_en) ram[addr_w]<=wrt_data;
  if (rd_en) read_data <= ram[addr_w];
end

就是这样,这就是你的 BRAM,你应该查看综合结果,看看该工具已经将内存推断为 BRAM。如果该工具无法将其识别为 BRAM,则可以使用 verilog 中声明 RAM 寄存器的原语来指示该工具,如下所示:

(* ram_style = "bram" *) reg [data_size-1:0] myram [2**addr_size-1:0];

更多细节在这里: https://docs.xilinx.com/r/en-US/ug901-vivado-synthesis/Single-Port-RAM-with-Read-First-VHDL

注意:存储器没有复位引脚。如果您想要一个带复位功能的存储器,请使用寄存器。