ROM:只读存储器。在用FPGA对其他设备进行配置时,有时我们需要配置数据固定下来不去频繁的修改,这是我们就可以使用quartus自带的ROM ip核来实现这一目的。以下将以quartus13.1为例介绍ROM ip核的使用方法。
1.ROM初始化文件的生成
在创建ROM 之前我们需要先准备好ROM初始化文件。初始化文件的获取有两种方法。
a.用quartue生成。
方法一:在quartue点击file -> new -> Hexadecimal(Intel-Format) File/Memory Initialization File。(如果你选则的是Hexadecimal(Intel-Format) File你最终将得到.hex格式的文件,如果你选择的是Memory Initialization File你将得到.mif文件)
在Number of words中填写你要存储的数据个数,在Word size里填写每个对应数据的位数。图中的配置代表,我要存储256个数据,每个数据由8位二进制数组成。在完成此设置后,会打开一个类似下图的表格
在表格中特定单元填上你要存储的数据即可。(鼠标右击ASCII字样可以修改地址和存储数据的显示格式。)
b.用记事本直接编写mif文件
在存储数据比较多的时候后,且数据存在较多的连续重复时,用a中提到的方法进行ROM初始化文件的生成就不免显的繁琐,此时我们就可以使用记事本直接生成mif文件。
新建一个记事本,修改文件名,文件名命名规则与Verilog模块命名规则一致,随后打开记事本输入与以下内容类似的信息。
WIDTH=3;
DEPTH=64;
ADDRESS_RADIX=HEX;
DATA_RADIX=HEX;
CONTENT BEGIN
0:1;
1:1;
[02..03]:5;
[04..05]:6;
[06..07]:5;
[08..09]:4;
[0A..0B]:3;
[0C..0D]:2;
[0E..0F]:1;
[10..11]:5;
[12..13]:4;
[14..15]:3;
[16..17]:2;
[18..19]:5;
[1A..1B]:4;
[1C..1D]:3;
[1E..1F]:2;
[20..21]:5;
[22..23]:4;
[24..25]:3;
[26..27]:2;
[28..29]:1;
[2A..2B]:5;
[2C..2D]:6;
[2E..2F]:5;
[30..31]:4;
[32..33]:3;
[34..35]:2;
[36..37]:1;
[38..3F]:0;
END;
其中WIDTH为数据宽度即一个数据有多少个二进制数组成,DEPTH 代表数据深度,代表总的数据个数(此处的位数和个数应该与后续在quartueii中配置的ROM ip核的对应信息一致)。ADDRESS_RADIX=HEX;代表地址应该用16进制数表示;DATA_RADIX=HEX;代表数据用16进制数表示。0:1表示地址为0的单位内存储的数据为1.[38..3F]:0;表示地址从38到3f对应的单元内存储的数据均为0.
在完成上诉信息的配置后,保存并关闭记事本文件,随后将记事本文件的文件后缀改为.mif即可获得ROM的初始化mif文件。如下图所示:
2.ROM ip核的参数配置
在quartue中点击tool -> MegaWizard Plug-In Manager 打开如下页面
选择create a new custom magafunction variation 点击NEXT打开IP核选择界面
在Memory Compiler中找到我们要的ROM类型,其中ROM:1-PORT为一个地址输入口和一个数据输出口类型的ROM,ROM:2-PORT为两个地址输入口和两个输出口类型的ROM(相对于两个ROM:1-PORT因此以下仅介绍ROM:1-PORT的配置。),在单击选中你所需要的在蓝色箭头标识的地方填写ip核名称,例如我的ip核名称就为my_rom1。随后点击NEST。
How wide shuold the ‘q’ output bus be?后填写你的存储的每个数据由多少个二级制数组成
how many x-bit words of memory ? 后填写一共你要存储数据个数。
What clocking method would you like to use?下的选项表示要使用的时钟形式,其中Single clock表示地址输入和数据输出用的是同一个时钟,Dual clock 表示地址输入和数据输出采用不同的时钟。
Creat one clock enable signal for...表示为所有时钟创建一个使能端,只有clken有效时,时钟才能被输入模块里。
Create an ‘aclr’ asynchronous...表示为所有的地址和输出寄存器设置一个异步清0信号,当该信号有效时,地址和输出寄存器清零。
Create a 'rden' read enable signal,表示创建一个读使能信号,只有该信号有效时才能从ROM中读出数据
在此页面点击Browse选择你之前创建的初始化文件
随后一直点NEXT到以下页面选择你需要的模块引用格式
3.仿真结果
verilog 测试模块代码:
module ROM_TEST
(input clk,rstn,
output [2:0] q );
reg [4:0]addr;
always @(negedge clk or negedge rstn)
begin
if (!rstn)
begin
addr<=5'd0;
end
else
begin
addr<=addr+5'd1;
end
end
my_rom my_rom_inst (
.address ( addr ),
.clock ( clk ),
.q ( q )
);
endmodule
testbench:
`timescale 1us/1us
module testbench ();
reg clk,rstn;
wire [2:0]q;
always #10 clk=~clk;
initial begin
clk=1;rstn=1;
#50 rstn=0;
#50 rstn=1;
end
ROM_TEST u0(clk,rstn,
q );
endmodule
仿真波形图: