前言
ROM在FPGA设计中也有一些常用的应用场景,其中典型的有两类:一是初始化配置数据,二是查表法寻址取数。
ROM相比RAM或者FIFO,显然是没有后两者灵活的,因为ROM在初始化IP核时就已经从外部导入了ROM表,数据只可读出却不能写入,但是ROM也因此具有了掉电保存数据的特殊功能。
在使用很多外设的时候,或多或少基本都需要配置一些外部的硬件寄存器,比如CMOS摄像头、WM8731音频芯片等等,这些数据通常来说都是固定的,然后通过IIC或者SPI通信方式去写入相关寄存器,开机配置一次即可。这时候如果初始化需要配置数据很多的话,那么可以把这些数据事先写入ROM表中,硬件上电后,按照对应的时序逻辑输出ROM表中的数据即可。
ROM内部数据初始化所用的.coe文件
memory_initialization_radix=16; //进制的格式
memory_initialization_vector= //初始化的数值
ff,
fe,
fd,
fc,
fb,
fa,
f9,
f8,
f7,
f6,
f5,
f4,
f3,
f2,
f1,
f0,
ef,
ee,
ed,
ec,
eb,
ea,
e9,
4,
3,
2,
1,
0,
ed,
ec,
eb,
ea;
IP核配置
记得初始化装载初始化ROM文件
剩下的两页保持默认。
tst.v文件配置
- ROM内的数据在IP核初始化的时候就已经配置好,只要输入地址就可以在数据输出线上取出。
- 做一个循环累加的cnt,在cnt固定的区间,ROM的地址累加,用来取ROM中的地址。
module rom_tst(
input sys_clk,
input sys_rst_n,
output [ 7: 0 ] rom_data
);
reg wea = 0;
reg dina; //数据输入
reg [ 4: 0 ] addra; //读rom的地址
reg [ 9: 0 ] cnt;
my_rom my_rom0(
.clka( sys_clk ), // input clka
.wea( wea ), // input [0 : 0] wea
.addra( addra ), // input [4 : 0] addra
.dina( dina ), // input [7 : 0] dina
.douta( rom_data ) // output [7 : 0] douta
);
always@( posedge sys_clk or negedge sys_rst_n )
begin
if ( !sys_rst_n )
cnt <= 0;
else if ( cnt <= 120 )
cnt <= cnt + 1;
else
cnt <= 0;
end
always@( posedge sys_clk or negedge sys_rst_n )
begin
if ( ( 50 <= cnt ) && ( cnt < 83 ) )
addra <= addra + 1;
else
addra <= 0;
end
endmodule
仿真的结果
局部放大:
通过局部放大后的数据可以观察到在地址线上给出地址以后的一个时钟,数据线上出现了对应的数据