1.IP核 ROM简介
FPGA 本身是 SRAM 架构的,断电之后,程序就消失,我们可以利用 FPGA 内部的 RAM 资源实现 ROM,但不是真正意义上的 ROM,而是每次上电都会把初始化的值先写入 RAM.
2.实验: 配置单端口 ROM
1) 创建 ROM 初始化文件
既然是 ROM,那么我们就必须提前给它准备好数据,然后在 FPGA 实际运行时,我们直接读取这些 ROM 中预存储好的数据就行。Xilinx FPGA 的片内 ROM 支持初始化数据配置。如下图所示,我们可以创建一个名为 rom_init.coe 的文件,注意后缀一定是“.coe”。
ROM 初始化文件的内容格式很简单, 如下图所示。第一行为定义数据格式, 16 代表 ROM 的数据格式为 16 进制。从第 3 行开始到第 34 行,是这个 32*8bit 大小 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_init.coe 编写完成后保存一下, 接下去我们开始设计和配置 ROM IP 核。
2) 添加 ROM IP 核
|
|
|
|
点击 ok,点击 Generate 生成 ip 核。
3) 编写测试程序
module ip_rom(
input clk,
input rst_n
);
reg [4:0] rom_rd_addr;
wire [7:0] rom_rd_data;
//读地址信号
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
rom_rd_addr <= 1'b0;
else if(rom_rd_addr == 5'd31)
rom_rd_addr <= 1'b0;
else
rom_rd_addr <= rom_rd_addr + 1'b1;
end
blk_mem_gen_0 u_blk_mem_gen_0 (
.clka(clk), // input wire clka
.addra(rom_rd_addr), // input wire [4 : 0] addra
.douta(rom_rd_data) // output wire [7 : 0] douta
);
endmodule
4) 编写激励文件
`timescale 1ns / 1ps
module tb_ip_rom();
reg clk;
reg rst_n;
initial begin
clk = 1'b0;
rst_n = 1'b0;
#200
rst_n = 1'b1;
end
always #10 clk = ~clk;
ip_rom u_ip_rom(
.clk (clk),
.rst_n (rst_n)
);
endmodule
5) 仿真测试
仿真结果如下,符合预期,与 RAM 的读取数据一样,数据也是滞后于地址一个周期。
6) ILA测试
添加 ILA IP 核,将 rom_rd_addr和 ram_rd_data 信号添加至观察列表中。
|
|
ILA 的时钟和探针信号连接到顶层设计中,例化 ILA IP 核的代码如下:
ila_0 u_ila_0(
.clk(clk), // input wire clk
.probe0(rom_rd_addr), // input wire [4:0] probe0
.probe1(rom_rd_data) // input wire [7:0] probe1
);
最后为工程添加 IO 管脚约束,对应的 XDC 约束语句如下所示:
set_property -dict {PACKAGE_PIN U18 IOSTANDARD LVCMOS33} [get_ports clk]
set_property -dict {PACKAGE_PIN J15 IOSTANDARD LVCMOS33} [get_ports rst_n]
生成比特流之后,直接点击“Program”,此时 Vivado 会自动打开 ILA 的调试窗口,如下图所示