目录
1.简介
xilinx提供了两个ip用于生成ROM存储空间。一个是 Distributed Memory Generator,另一个是Block Memory Generator,两者最主要的差别是生成的 Core所占用的 FPGA 资源不一样,从 Distributed Memory Generator 生成的 ROM/RAM Core 占用的资源是 LUT(查找表,查找表本质就是一个小的 RAM);从 Block Memory Generator 生成的 ROM/RAM Core 占用的资源是 Block Memory(嵌入式的硬件 RAM),因此在实际项目中的应用要看具体硬件的情况。通常ROM用于做初始化配置,或者接口验证。本文通过仿真介绍该IP的使用,并创建一个用于接口验证的实际案例,即将ROM中的数据显示到LVDS显示屏上。用以验证LVDS显示时序正常。上述两个IP使用的差别不大,也都不仅能生成ROM,还可以生成双口RAM等,本文只讨论ROM。本文内容参考xilinx官方手册PG058 Block Memory Generator v8.4 product guide。
2.仿真1
2.1IP核配置
第一套仿真代码和配置如下,只关注常规接口的时序。
②设置数据位宽是10,存储深度是32,端口使能信号类型设置,一个是一直使能,一个是通过一个ENA信号管脚控制,这里选择 Always Enable。勾选Primitives Output Register,其含义如下图所示,内部的一个寄存器将数据打一拍,性能会更好。关于REGCEA pin复位的是寄存器中的值,而不是ROM中的值,通常也不用。
③第三页 勾选初始化文件,选择Edit将可以手动创建COE文件或者导入准备好的文件,手动设置如下第二张图,16进制的形式初始化了11个数据。设置完成可以validation并且保存。勾选Fill选项指未初始化的数据将初始化成指定位宽。
④第四页,可以看到当前latency=2,指地址线与数据线之间有一个时钟周期的延时。
2.2仿真代码如下
`define CLK_PERIOD 20
module Sim_romip();
reg clk;
reg [5:0]addr;
reg rsta;
reg ena;
initial clk = 1;
always #(`CLK_PERIOD/2) clk = ~clk;
wire [9:0]sim_rom;
//第一段仿真代码
blk_mem_gen_0 rom (
.clka(clk),
.addra(addr), // output wire [4 : 0] spo
.douta(sim_rom) // output wire [9 : 0] qspo
);
initial begin
addr = 0;
#21;
#(`CLK_PERIOD*5);
addr = addr + 1'b1;
#(`CLK_PERIOD*2);
addr = addr + 1'b1;
#`CLK_PERIOD;
addr = addr + 1'b1;
#`CLK_PERIOD;
addr = 10;
#`CLK_PERIOD;
addr = 11;
#`CLK_PERIOD;
addr = 31;
#`CLK_PERIOD;
addr = 32;
#`CLK_PERIOD;
addr = 33;
#(`CLK_PERIOD * 30);
$stop;
end
2.3仿真结果分析
以地址线addr=2举例,t0时刻,addr=2,而地址2对应的数据12在t1-t2时刻才更新,因此在当前配置下,地址线与数据之间有1个时钟周期的延迟,Latency=2,Latentcy 指的是相对于某个时钟起始位的1个或多个时钟后数据才有效。
地址与数据映射是从0开始,也就是地址0对应一个数据,即手动填写的10;由此32的深度中,最后一个数据的地址应该是31。在之前的IP配置中手动填写了11个数据,因此从地址11-31都是填充数据12。如果地址线addr位宽够大,例如此处为6位宽,实际ip接口只有5位宽,因此addr=32时,ip接收低5位为0又显示第一个地址。另外,当未点击填充数据时,未初始化的数据默认为0。
3. 仿真代码2
主要是看Core Output Register和Enable Port Type以及RSTA Pin。
3.1修改第二页配置如下
其余配置一样,使能ENA管脚,勾选Core output Register,勾选RSTA Pin,并设置复位时端口值为16.
3.2仿真代码
`define CLK_PERIOD 20
module Sim_romip();
reg clk;
reg [5:0]addr;
reg rsta;
reg ena;
initial clk = 1;
always #(`CLK_PERIOD/2) clk = ~clk;
wire [9:0]sim_rom;
blk_mem_gen_0 your_instance_name (
.clka(clk), // input wire clka
.rsta(rsta), // input wire rsta
.ena(ena), // input wire ena
.addra(addr), // input wire [4 : 0] addra
.douta(sim_rom) // output wire [9 : 0] douta
);
initial begin
addr = 0;
rsta = 1;
ena = 0;
#(`CLK_PERIOD*5);
rsta = 0;
#21;
#(`CLK_PERIOD*5);
ena = 1;
addr = addr + 1'b1;
#(`CLK_PERIOD*2);
addr = addr + 2;
#`CLK_PERIOD;
addr = addr + 5;
#`CLK_PERIOD;
addr = 10;
#`CLK_PERIOD;
addr = 11;
#`CLK_PERIOD;
addr = 31;
#`CLK_PERIOD;
addr = 32;
ena = 0;
#`CLK_PERIOD;
ena = 1;
addr = 33;
#(`CLK_PERIOD * 30);
$stop;
end
endmodule
3.3仿真结果分析
复位信号是高电平有效,复位器件数据线上数据通过IP配置。注意,此处的值为16进制。
T0时刻,是第一个地址线上数据进入,在t2-t3时刻地址线addr=1的数据0x11才出来,此时的latency=3;此处要正确理解ena的含义,地址线addr=10是打出来的最后一个数据0x20,因为在0x20该出来的时刻(图中椭圆对应的上升沿时刻)ena是有效的。因此当前时刻数据是否有效有两个因素决定,一个是两个周期之前的地址是否正确写入,一个是当前时刻ena数据有效信号是否有效。当二者有一个不满足时,该数据被pass。该结论下图看的更清楚。
4.ROM存储图片数据显示到液晶屏
① 确认片上资源XC7A35T仅有1.8Mbit,一张图片的大小为1024*600*8=17.57Mbit。因此计划将一张图片的1/12写入到ROM,coe中,据此验证数据流与上位机。
②使用QT生成COE文件,可参考Qt生成ROM IP核使用的COE文件,需要注意的是这里处理的是RGB格式的图像,需要将bits获取的指针强制转换成QRGB类型才能正确获取RGB分量信息。注意这里只能写图片得十二分之一也就是600/12=50行。另外要按照coe文件格式输出。
③依据LVDS接口LCD显示彩图测试,在这个工程中实现了LVDS显示屏显示彩图,并预留了数据接口。修改数据来源即可将rom中的数据打到屏幕上,需要注意的是,由于rom ip地址与数据之间有一个时钟周期的延时,因此应该将数据同步。
④原图与屏幕显示的图对比效果如下,
5.传送门
我的主页https://blog.csdn.net/weixin_40615338?type=blog
END
💎文章原创,首发于CSDN论坛。
💎欢迎点赞💖收藏✨打赏💷!
💎欢迎评论区🎤或私信指出错误🎤,🗣️提出宝贵意见或疑问。