文章目录
FPGA设计中RAM和ROM作为存储器用来存储可变或不可变类型的数据。
ROM初始化一般是加载固定数据,RAM声明时默认为不定态数据,初始化时可以让数据为全1或者全0。
一、初始化方式
-
复位时按地址写入初值
verilogalways@ (posedge clk_in or negedge rst_n_in ) begin if( !rst_n_in ) begin ram_reg[0] <= xxx; ram_reg[1] <= xxx; ... ram_reg[n-1] <= xxx; end else begin ... end end
-
使用initial 和 for循环来初始化
用于初始化为有规律的数据,RAM初始化常使用这种方式。veriloginitial begin : ram_init integer i; for(i=0;i<n;i++) begin ram_reg[i] = xxx; end end
变量的定义必须在命名块中,因此这里需要使用命名的initial块。
-
通过读文件的方式初始化
将数据存储在.dat文件中,通过读文件实现初始化。
这种方式RAM使用较少,一般ROM初始化时喜欢采用这种做法。veriloginitial begin $readmemh("filepath",rom_reg); end
二、测试
方式1的正确性不言而喻。
方式2和方式3中,initial块一般来说是用在仿真中的,对其能否综合,编写如下的测试代码:
-
定义了两块寄存器,用来实现RAM
-
ram_1通过方式2初始化
-
ram_2通过方式3初始化,dat文件内容从0x0f ~ 0x08
-
循环对ram中的内容进行读取
-
调用ila核,来抓取读取的数据
verilog
`timescale 1ns / 1ps
//
// Engineer: wkk
// Create Date: 2023/12/23 20:50:45
// Module Name: init_value_test
//
module init_value_test(
input clk_in ,
input rst_n_in ,
output nc_out
);
reg [7:0] ram_1 [7:0];
reg [7:0] ram_2 [7:0];
reg [2:0] ram_addr ;
wire [7:0] ram_1_out;
wire [7:0] ram_2_out;
initial begin : init_ram1
integer i;
for( i=0;i<7;i = i+1 ) begin
ram_1[i] = i+1;
end
end
initial begin : init_ram2
$readmemh("E:/FPGA/init_value_test/init_value_test.srcs/data/ram_data.dat",ram_2);
end
always @( posedge clk_in or negedge rst_n_in ) begin
if( !rst_n_in ) begin
ram_addr <= 'b0;
end else begin
ram_addr <= ram_addr + 1'b1;
end
end
assign ram_1_out = ram_1[ram_addr];
assign ram_2_out = ram_2[ram_addr];
ila_0 ila_0_inst (
.clk(clk_in), // input wire clk
.probe0(ram_1_out), // input wire [7:0] probe0
.probe1(ram_2_out), // input wire [7:0] probe1
.probe2(ram_addr) // input wire [2:0] probe2
);
endmodule
增加了一个nc_out 端口,实际上是没有什么作用的,但是必须要加,否则会报错:
shell
[Place 30-494] The design is empty
Resolution: Check if opt_design has removed all the leaf cells of your design. Check whether you have instantiated and connected all of the top level ports.
原因:顶层文件没有输出接口
测试结果
通过ila核抓出的数据,表明方式2和方式3成功的实现了初始化操作。