如何在Verilog中初始化推断块RAM(BRAM)的内容

如何在Verilog中初始化推断块RAM(BRAM)的内容,verilog,fpga,xilinx,vivado,Verilog,Fpga,Xilinx,Vivado,在Verilog中初始化推断ram的内容时遇到问题。ram的代码如下所示: module ram( input clock, // System clock input we, // When high RAM sets data in input lines to given address input [13:0] data_in, // Data lines to write to memory input [10:0] ad

在Verilog中初始化推断ram的内容时遇到问题。ram的代码如下所示:

module ram(
        input clock, // System clock
        input we, // When high RAM sets data in input lines to given address
        input [13:0] data_in, // Data lines to write to memory
        input [10:0] addr_in, // Address lines for saving data to memory
        input [10:0] addr_out, // Address for reading from ram
        output reg data_out // Data out
);

reg [13:0] ram[2047:0];

// Initialize RAM from file
// WHAT SHOULD GO HERE?

always @(posedge clock) begin
    // Save data to RAM
    if (we) begin
        ram[addr_in] <= data_in;
    end

    // Place data from RAM
    data_out <= ram[addr_out];
end        
endmodule
模块ram(
输入时钟,//系统时钟
input we,//当高RAM将输入行中的数据设置为给定地址时
在,//数据行中输入[13:0]数据\以写入内存
在,//地址行中输入[10:0]addr\u,用于将数据保存到内存中
输入[10:0]addr\u out,//从ram读取的地址
输出注册表数据输出//数据输出
);
reg[13:0]ram[2047:0];
//从文件初始化RAM
//这里应该放什么?
始终@(posedge时钟)开始
//将数据保存到RAM
如果我们开始

ram[addr_in]您应该在初始块中使用
$readmemh
,这是正确的。为了使模块的不同实例可以具有不同的初始化文件,应使用如下参数:

parameter MEM_INIT_FILE = "";
...
initial begin
  if (MEM_INIT_FILE != "") begin
    $readmemh(MEM_INIT_FILE, ram);
  end
end
格式见IEEE1800-2012规范第21.4节;通常,该文件只是一组包含正确位长度的十六进制数的行,如下所示:

0001
1234
3FFF
1B34
...
@0002
0101
0A0A
...
请注意,没有“0x”前缀,每行表示一个相邻地址(或任何分隔的空白)。在上面的例子中,
$readmemh
14'h0001
放入
ram[0]
14'h1234
放入
ram[1]
14'h3FFF
放入
ram[2]
等等。您还可以使用
/
/***/
在十六进制文件中包含注释。最后,您可以使用
@
符号指定以下号码的地址,如下所示:

0001
1234
3FFF
1B34
...
@0002
0101
0A0A
...

在上面的文件中,
ram[0]
ram[1]
将被取消初始化,
ram[2]
将获得
14'h0101
。这些都是十六进制文件格式的主要结构,尽管您也可以像在其他Verilog数字中一样使用
\uuu
x
z
,在上面的部分中还有一些规则可以阅读。

除了@Unn出色的ans之外,我想补充一点,如果您只想将所有位初始化为
1'b1
1'b0
,则只需输入以下代码

integer j;
initial 
  for(j = 0; j < DEPTH; j = j+1) 
    ram[j] = {WIDTH{MEM_INIT_VAL}};
整数j;
首字母
对于(j=0;j<深度;j=j+1)
ram[j]={WIDTH{MEM_INIT_VAL};
对于您的情况,WIDTH=14,MEM_INIT_VAL可能是
1'b1
1'b0

整数j;
integer j;
initial 
  for(j = 0; j < DEPTH; j = j+1) 
    ram[j] = j;
首字母 对于(j=0;j<深度;j=j+1) ram[j]=j;
在调试的情况下,这可能很容易,其中位置的值是其位置号


此外,我建议您不要初始化RAM。它将帮助您在模拟中捕获bug(如果有),因为如果RAM未初始化并且可以轻松捕获,那么数据驱动将是'x'

由于您的问题引用了#xilinx和#vivado标记,我想建议您也可以使用
xpm_memory
原语族来实例化参数化内存。这种方法的优点是:

  • 精确导出FPGA上内存资源的硬件功能(即,使您清楚地考虑内存端口等限制)

  • 保证内存原语在模拟和台式机中的正确相同行为

  • 您可以允许Vivado在合成时根据您的设计约束选择最有效的内存实现(BRAM、UltraRAM、分布式RAM、触发器)

  • 易于微调(启用或禁用内部管道级等)

  • 也就是说,纯推断的记忆通常更容易编码。但是,仍然有必要熟悉Xilinx提供的内存原语,这样您就可以更清楚地了解Vivado可以轻松合成什么,以及它不能合成什么

    有关更多信息,请参阅UG573,Vivado内存资源用户指南:


    在合成或实现后有什么方法可以确认吗?@tollinjose我不知道有什么好方法可以确保十六进制文件的内容真正进入RAM,而无需在合成后模拟器中直接测试或在FPGA或类似设备上运行。根据合成工具的不同,您可以尝试查看其资源(即任何RTL显示工具或输出文件),以查看您的十六进制文件中的数据是否进入了可欣赏的位置。对于vivado,请查看语言模板,特别是,Examples Modules->RAM以查看exampl verilog或VHDL代码,这些代码可以推断出所需的硬件,并具有避免xilinx特定宏的所有优点。这会在已实现的设计中初始化推断出的bram还是仅在模拟中初始化推断出的bram?@Mah35h提到的初始块是可合成的,因此它也适用于推断出的已实现RAM至于模拟。