FPGA 本身是 SRAM 架构的,断电之后程序就会消失,那么如何利用 FPGA 实现一个 ROM 呢,我们可以利用 FPGA 内部的 RAM 资源实现 ROM,但这不是真正意义上的 ROM,而是每次上电都会把初始化的值先写入 RAM。Vivado 软件中提供了 ROM 的 IP 核 , 我们只需通过 IP 核例化一个 ROM,根据 ROM 的读时序来读取 ROM 中存储的数据。本节将介绍如何使用 FPGA 内部的 ROM 以及程序对该 ROM 的数据读操作。该实验与 FPGA 片内 RAM 读写测试实验操作类似,可以参考一下。
对于 ROM,我们需要提前准备好数据,这样在 FPGA 实际运行时,就可以直接读取 ROM 中预存好的数据了。Xilinx FPGA 的片内 ROM 支持初始化数据配置,我这里创建一个名为 “rom_init.coe” 的 ROM 初始化文件,后面会用得到。
将下面的内容拷贝进去:
MEMORY_INITIALIZATION_RADIX=16; //表示ROM内容的数据格式是16进制
MEMORY_INITIALIZATION_VECTOR=
11,
22,
33,
44,
55,
66,
77,
88,
99,
aa,
bb,
cc,
dd,
ee,
ff,
00,
a1,
a2,
a3,
a4,
a5,
a6,
a7,
a8,
b1,
b2,
b3,
b4,
b5,
b6,
b7,
b8; //每个数据后面用逗号或者空格或者换行符隔开,最后一个数据后面加分号
ROM 初始化文件的内容格式比较简单,其中第 1 行为定义的数据格式,第 3 行到第 34 行是这个 32*8bit 大小ROM的初始化数据,每行数字后面用逗号,最后一行数字结束时用分号。
新建一个 rom_test 的工程
将刚刚的 rom_init.coe 文件放到当前工程目录中
①、 点击下图中 IP Catalog ,在右侧弹出的界面中搜索 rom ,找到 Block Memory Generator,双击打开。
②、Basic 选项栏按照下图进行配置
③、Port A Option 选项栏按照下图进行配置
把 Primitives Output Register 取消勾选,其功能是在输出数据上加寄存器,这可以有效改善时序 ,但读出的数据会落后地址两个周期,因此在很多情况下,不用这项功能,保持读出的数据落后地址一个周期即可。
④、在 Other Options 下勾选 Load Init File,然后点击 Browse 查找第一步中创建好的文件 rom_init.coe,并点击 OK
⑤、在弹出的对话框中点击 Generate 就可以生成 ROM IP。
①、点击左侧 PROJECT MANAGER 栏 –> IP Catalog 或者菜单栏下 Window –> IP Catalog 然后在右侧出现的 IP Catalog 窗口下搜索 ILA,双击选择 Debug 下的 ILA 进行 IP 配置操作步骤如下图所示
②、General Option 添加两个探针去采集我们读的地址和数据,采样数据的深度我们设置大一些,如下图所示
③、Probe_Ports(0…7) 中PROBE0 用来采集 5 位地址,PROBE1 用来采集 8 位数据,并点击 OK,如下图所示
④、点击 OK,再点击 Generate,生成 ILA IP
新建 rom_test.v 源文件并将下面的程序块拷贝过去
rom_test.v
`timescale 1ns / 1ps
module rom_test(
input sys_clk, //50MHz时钟
input rst_n //复位,低电平有效
);
wire [7:0] rom_data; //ROM读出数据
reg [4:0] rom_addr; //ROM输入地址
//产生ROM地址读取数据
always @ (posedge sys_clk or negedge rst_n)
begin
if(!rst_n)
rom_addr <= 10'd0;
else
rom_addr <= rom_addr+1'b1;
end
//实例化ROM
rom_ip rom_ip_inst
(
.clka (sys_clk), //inoput clka
.addra (rom_addr), //input [4:0] addra
.douta (rom_data) //output [7:0] douta
);
//实例化逻辑分析仪
ila_0 ila_m0
(
.clk (sys_clk),
.probe0 (rom_addr),
.probe1 (rom_data)
);
endmodule
新建 vtf_rom_tb.v 仿真文件并将下面的程序块拷贝过去
vtf_rom_tb.v
`timescale 1ns / 1ps
module vtf_rom_tb;
// Inputs
reg sys_clk;
reg rst_n;
// Instantiate the Unit Under Test (UUT)
rom_test uut (
.sys_clk (sys_clk),
.rst_n (rst_n)
);
initial
begin
// Initialize Inputs
sys_clk = 0;
rst_n = 0;
// Wait 100 ns for global reset to finish
#100;
rst_n = 1;
end
always #10 sys_clk = ~ sys_clk; //20ns一个周期,产生50MHz时钟源
endmodule
1、点击 Run Simulation -> Run Behavioral Simulation,进行仿真
2、将 ROM 里面地址和数据信号拖拽进观察窗口
3、点击 Run for 200us,可以看到如下图仿真波形
可以看到地址 0 对应数据 0x11,地址 1 对应于数据 0x22 …,与我们之前的 “rom_init.coe” 的 ROM 初始化文件一致
1、引脚约束及时序约束
rst_n -> T11
clk -> U18
新建引脚约束文件 rom.xdc,将下面语句拷贝过去并保存
set_property PACKAGE_PIN T11 [get_ports rst_n]
set_property IOSTANDARD LVCMOS33 [get_ports rst_n]
set_property PACKAGE_PIN U18 [get_ports sys_clk]
set_property IOSTANDARD LVCMOS33 [get_ports sys_clk]
create_clock -period 20.000 -name sys_clk -waveform {0.000 10.000} [get_ports sys_clk]
2、生成比特文件
点击 “Generate Bitstream”,直接生成 bit 文件
3、下载程序
连接上 JTAG 以及电源线,将板子上电,下载程序
4、逻辑分析仪分析波形
以 10 进制方式查看读取的内存及数据,设置触发条件为 “rom 地址为 0”,可以看到地址 0 的数据为 0x11,rom 地址 31 时的数据为 0xb8,可见满足了预期结果。
FPGA片内ROM测试实验
我的qq:2442391036,欢迎交流!