【问题标题】:How to initialize contents of inferred Block RAM (BRAM) in Verilog如何在 Verilog 中初始化推断的 Block RAM (BRAM) 的内容
【发布时间】:2016-04-13 22:15:12
【问题描述】:

我在 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 进行编程。

【问题讨论】:

    标签: verilog fpga xilinx vivado


    【解决方案1】:

    您应该在初始块内使用$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] 等等。您还可以使用///* */ 在十六进制文件中包含cmets。最后,您可以使用@ 符号为以下数字指定一个地址,如下所示:

    @0002
    0101
    0A0A
    ...
    

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

    【讨论】:

    • 合成或实现后有什么方法可以确认吗?
    • @tollinjose 不确定我是否知道一种确保 HEX 文件的内容实际进入 RAM 的好方法,而无需直接在综合后模拟器中进行测试或在 FPGA 或其他东西上运行它像那样。根据综合工具,您可以尝试查看其资源(即,任何 RTL 显示工具或输出文件),以查看您的 HEX 文件中的数据是否进入了欣赏位置。
    【解决方案2】:

    除了@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

    【讨论】:

    • 这会在实现的设计中初始化推断的 bram 还是仅在仿真中初始化?
    • @Mah35h 提到初始块是可合成的,因此它适用于推断实现的 ram 以及模拟。
    【解决方案3】:

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

    1. 准确导出 FPGA 上内存资源的硬件功能(即,让您清楚地考虑内存端口等限制)。

    2. 保证内存原语在模拟和台式机中具有正确的相同行为。

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

    4. 易于微调(启用或禁用内部流水线阶段等)。

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

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

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

    【讨论】:

    • 对于 vivado,请查看语言模板,特别是示例模块 -> RAM 以查看示例 verilog 或 VHDL 代码,这些代码可以推断出所需的硬件,并具有避免 xilinx 特定宏的所有优势
    【解决方案4】:
    integer j;
    initial 
      for(j = 0; j < DEPTH; j = j+1) 
        ram[j] = j;
    

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多