提问人:superb ranjeet 提问时间:11/3/2023 最后编辑:toolicsuperb ranjeet 更新时间:11/6/2023 访问量:219
如何将数据写入 bram 并从 bram 读取数据?
How to write data into bram and read data from bram?
问:
我试图理解在某些控制情况下,写作和阅读是如何在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编码中做到这一点时,我失败了。
答:
该答案是对 @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 推理的编码风格。有几个示例可以剪切和粘贴,然后根据上下文需求进行自定义。
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
注意:存储器没有复位引脚。如果您想要一个带复位功能的存储器,请使用寄存器。
评论