如何在 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 数字中一样使用 _
、x
和 z
,并且您可以阅读更多规则在上面的部分中。
除了@Unn 的优秀答案,我想补充一点,如果你只想用所有位初始化你的内存到 1'b1
或 1'b0
,那么你可以只输入以下代码,
integer j;
initial
for(j = 0; j < DEPTH; j = j+1)
ram[j] = {WIDTH{MEM_INIT_VAL}};
对于您的情况,WIDTH=14,而 MEM_INIT_VAL 可能是 1'b1
或 1'b0
。
integer j;
initial
for(j = 0; j < DEPTH; j = j+1)
ram[j] = j;
这在调试的情况下可能很容易,其中位置的值是它的位置编号。
此外,我建议您不要初始化 RAM。它将帮助您在模拟中捕获错误(如果有的话),因为如果 RAM 未初始化并且可以轻松捕获,则驱动的数据将为 'x。
由于您的问题引用了#xilinx 和#vivado 标签,我想建议您也可以使用xpm_memory
基元族来实例化参数化存储器。这种方法的优点:
准确导出FPGA上内存资源的硬件能力(即让你清楚内存端口等限制)。
保证在内存基元的模拟和基准测试中纠正相同的行为。
您可以让 Vivado 根据您的设计约束在综合时选择最高效的内存实现(BRAM、UltraRAM、分布式 RAM、触发器)。
易于微调(启用或禁用内部管道阶段等)。
话虽如此,纯粹的推断记忆通常更容易编码。但是,熟悉 Xilinx-provided 内存原语仍然是值得的,这样您就可以更清楚地了解 Vivado 可以轻松合成什么,不能合成什么。
如需了解更多信息,请参阅 UG573,《Vivado 内存资源用户指南》:
https://www.xilinx.com/support/documentation/user_guides/ug573-ultrascale-memory-resources.pdf
我在 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 数字中一样使用 _
、x
和 z
,并且您可以阅读更多规则在上面的部分中。
除了@Unn 的优秀答案,我想补充一点,如果你只想用所有位初始化你的内存到 1'b1
或 1'b0
,那么你可以只输入以下代码,
integer j;
initial
for(j = 0; j < DEPTH; j = j+1)
ram[j] = {WIDTH{MEM_INIT_VAL}};
对于您的情况,WIDTH=14,而 MEM_INIT_VAL 可能是 1'b1
或 1'b0
。
integer j;
initial
for(j = 0; j < DEPTH; j = j+1)
ram[j] = j;
这在调试的情况下可能很容易,其中位置的值是它的位置编号。
此外,我建议您不要初始化 RAM。它将帮助您在模拟中捕获错误(如果有的话),因为如果 RAM 未初始化并且可以轻松捕获,则驱动的数据将为 'x。
由于您的问题引用了#xilinx 和#vivado 标签,我想建议您也可以使用xpm_memory
基元族来实例化参数化存储器。这种方法的优点:
准确导出FPGA上内存资源的硬件能力(即让你清楚内存端口等限制)。
保证在内存基元的模拟和基准测试中纠正相同的行为。
您可以让 Vivado 根据您的设计约束在综合时选择最高效的内存实现(BRAM、UltraRAM、分布式 RAM、触发器)。
易于微调(启用或禁用内部管道阶段等)。
话虽如此,纯粹的推断记忆通常更容易编码。但是,熟悉 Xilinx-provided 内存原语仍然是值得的,这样您就可以更清楚地了解 Vivado 可以轻松合成什么,不能合成什么。
如需了解更多信息,请参阅 UG573,《Vivado 内存资源用户指南》:
https://www.xilinx.com/support/documentation/user_guides/ug573-ultrascale-memory-resources.pdf