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

How to initialize contents of inferred Block RAM (BRAM) in Verilog

我在 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

我已经 运行 进入命令 $readmemh。但是,它的文档似乎很少。我应该如何格式化包含数据的文件?另外,如何在实例化此模块时将文件作为参数传递,以便我可以从不同的文件加载此模块的不同实例?

我希望初始化的内容可用于模拟和实际实施。因此 FPGA 已经在 RAM 中使用此内容启动。

我正在使用 Vivado 2015.4 对 Kintex xc7k70 FPGA 进行编程。

您应该在初始块中使用 $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
...

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

@0002
0101
0A0A
...

在上面的文件中,ram[0]ram[1] 将未初始化,而 ram[2] 将得到 14'h0101。这些是 hex 文件格式的所有主要结构,尽管您也可以像在其他 Verilog 数字中一样使用 _xz,并且您可以阅读更多规则在上面的部分中。

除了@Unn 的优秀答案,我想补充一点,如果你只想用所有位初始化你的内存到 1'b11'b0,那么你可以只输入以下代码,

integer j;
initial 
  for(j = 0; j < DEPTH; j = j+1) 
    ram[j] = {WIDTH{MEM_INIT_VAL}};

对于您的情况,WIDTH=14,而 MEM_INIT_VAL 可能是 1'b11'b0

integer j;
initial 
  for(j = 0; j < DEPTH; j = j+1) 
    ram[j] = j;

这在调试的情况下可能很容易,其中位置的值是它的位置编号。

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

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

  1. 准确导出FPGA上内存资源的硬件能力(即让你清楚内存端口等限制)。

  2. 保证在内存基元的模拟和基准测试中纠正相同的行为。

  3. 您可以让 Vivado 根据您的设计约束在综合时选择最高效的内存实现(BRAM、UltraRAM、分布式 RAM、触发器)。

  4. 易于微调(启用或禁用内部管道阶段等)。

话虽如此,纯粹的推断记忆通常更容易编码。但是,熟悉 Xilinx-provided 内存原语仍然是值得的,这样您就可以更清楚地了解 Vivado 可以轻松合成什么,不能合成什么。

如需了解更多信息,请参阅 UG573,《Vivado 内存资源用户指南》:

https://www.xilinx.com/support/documentation/user_guides/ug573-ultrascale-memory-resources.pdf