从底层结构开始学习FPGA----Xilinx ROM IP的定制与测试

作者:孤独的单刀,文章来源:CSDN博客

1、什么是ROM?
本文介绍一种在FPGA开发中非常常用的存储类 IP 核——ROM 的使用方法。

ROM 是只读存储器(Read-Only Memory)的简称,是一种只能读出事先所存数据的固态半导体存储器。其特性是一旦储存资料就无法再将之改变或删除,且资料不会因为电源关闭而消失。而事实上在 FPGA 中通过 IP 核生成的 ROM 或 RAM调用的都是 FPGA 内部的 BRAM 资源,掉电内容都会丢失(这也很容易解释,FPGA 芯片内部本来就没有掉电非易失存储器单元)。

用 IP 核生成的 ROM 模块只是提前添加了数据文件(.coe 格式),在 FPGA 运行时通过数据文件给 ROM 模块初始化,才使得 ROM 模块像个“真正”的掉电非易失存储器;也正是这个原因,ROM 模块的内容必须提前在数据文件中写死,无法在电路中修改。

简单地讲,RAM是一个可写、可读的IP核;而ROM只是一个可读却不可写的IP核。所以可以把ROM看成一个是“青春版”的RAM,其本身只具备RAM的读取功能。事实上,在xilinx的FPGA开发中,RAM与ROM均是用BRAM资源实现(定制IP也是同一个),只不过对外接口封装不同。

在RAM IP章节,我们知道了RAM的组成形式有三种:
单口RAM(Single-port RAM)
简单双口RAM(Simple Dual-port RAM,也叫伪双端口RAM)
真双口RAM(True Dual-port RAM)

那么ROM的组成形式有几种呢?

不难推断,单口ROM肯定是可以实现的,即一个端口来读。那么双口ROM会不会有两种?不会,因为ROM只读不写的特性就注定了只有一种双口ROM,即两个端口都可读的ROM。如下:
单端口 ROM(Single-Port Rom)
双端口ROM(Dual-Port ROM)

(1)单端口 ROM:不可实现写操作,只可使用一个端口实现读操作

(2)双端口ROM:不可实现写操作,可以使用两个端口实现读操作,两个端口读取数据的位宽可以不同,但必须是整数倍关系

2、ROM IP核的定制
ROM IP核的定制和RAM IP核的定制过程非常相似,但是需要关注的参数更少,所以实现更简单。接下来将展示定制一个位宽4bit,深度16的单口ROM的过程。

准备
新建一个 ROM 工程后点击箭头所指的 IP Catalog
点击后会出现 IP Catalog 页面,在 IP 核的搜索框中搜索 block
根据筛序,双击箭头所指的 RAM & ROM 核“Block Memory Generator”,双击之后会出现配置界面

①、第一页

②、第二页

③、第三页

关于载入的初始文件(.coe文件),可以按如下格式编写,然后在上面点击 Browse 选取:

也可以点击,Edit,然后新创建一个.coe文件后,编写自己的内容(需要注意的是,不要使用;来结束):

当然了,上面载入的都是一些比较简单的,有规律的数据。如果您要载入的数据比较复杂,建议使用MATLAB或者其他脚本软件来生成,然后保存为coe文件再载入。

④、第四页

3、ROM IP的例化与仿真测试
3.1、例化一个ROM IP核
按上述步骤生成IP后,复制 IP核 自带的例化模板。


然后在我们的RTL代码中,例化该ROM。RTL不做其他功能,只例化ROM即可。

module rom_test(
input clk, //输入时钟
input en, //使能信号
input [3:0] addr, //地址
output [3:0] data_out //输出数据
);

//例化ROM IP核
rom_w4_d16 rom_w4_d16_inst (
.clka (clk),
.ena (en),
.addra (addr),
.douta (data_out)
);

endmodule

3.2、仿真测试
写个testbench,对ROM IP测试一下。

测试行为:之前编写初始化文件(.coe)的时候已经说了,载入的内容分别为0、1、2······F。所以稳定后从地址0-15读取数据,观察读出的数据是否与初始化内容一致。
`timescale 1ns / 1ns
module tb_rom_test();

reg clk;
reg en;
reg [3:0] addr;
wire [3:0] data_out;

initial begin
clk = 0;
en = 0;
addr = 0;

#110
en = 1; //开始读取数据
repeat(18) begin //从地址0-15读取数据(加上延迟3)
#10 addr = addr + 1;
end
en = 0; //停止读取数据

#20 $finish; //结束仿真
end

always #5 clk = ~clk; //生成时钟,周期10ns

//例化被测模块rom_test
rom_test rom_test_inst(
.clk (clk ),
.en (en ),
.addr (addr ),
.data_out (data_out )
);

endmodule

使用vivado自带的仿真工具simulator运行仿真,仿真结果如下:

在3个时钟周期的延迟后,读出的数据分别为0、1、2······、F,符合预期结果。

4、总结与参考
可以看到ROM IP的定制非常简单,基本就是一个“青春版”的RAM IP。

创作不易,如果本文对您有帮助,还请多多点赞、评论和收藏。您的支持是我持续更新的最大动力!

参考资料1:Block Memory Generator v8.4

最新文章

最新文章