当前位置:网站首页>从底层结构开始学习FPGA----FIFO IP的定制与测试
从底层结构开始学习FPGA----FIFO IP的定制与测试
2022-07-06 17:39:00 【孤独的单刀】
文章目录
系列目录与传送门
在定制一个FIFO IP核之前,强烈建议您先阅读:从底层结构开始学习FPGA----FIFO IP核及其关键参数介绍
在这篇文章中,已经对FIFO IP核的各个关键因素做了详细的讲解。
1、FIFO IP的定制
- 在新建一个工程后, 点击IP Catalog
- 点击后会出现 IP Catalog 页面,在 IP 核的搜索框中搜索 fifo
- 根据筛选,双击选择fifo核“FIFO Generator”
①、第一页
②、第二页
③、第三页
④、第四页
⑤、第五页
2、FIFO IP的例化与测试
2.1、例化一个FIFO IP核
按上述步骤生成IP后,复制 IP核自带的例化模板。
2.2、RTL
我们编写一个RTL代码来验证一下这个FIFO IP,并学习一下它的时序逻辑。
由于是异步FIFO,所以还例化了一个PLL来生成写时钟50M,读时钟75M。RTL代码使用了一个简单的状态机,以实现如下逻辑:
- 等待PLL稳定
- PLL稳定后对FIFO进行复位,时长10个周期以上
- FIFO复位完成后,写入数据直到写满,写入数据分别为0,1,2···14,共15个数据
- 写完数据后,从FIFO中读取数据,观察读取数据是否与写入数据一致
module fifot_test(
(* MARK_DEBUG="true" *) input sys_clk,
(* MARK_DEBUG="true" *) input sys_rst_n
);
(* MARK_DEBUG="true" *)reg fifo_rst ; //自己生成一个FIFO的复位信号
(* MARK_DEBUG="true" *)reg [3:0] din ;
(* MARK_DEBUG="true" *)reg [3:0] rst_cnt ; //复位计数器
(* MARK_DEBUG="true" *)reg wr_en ;
(* MARK_DEBUG="true" *)reg rd_en ;
(* MARK_DEBUG="true" *)reg [2:0] state ;
reg [2:0] state_rd1 ;
reg [2:0] state_rd2 ;
(* MARK_DEBUG="true" *)wire locked ;
(* MARK_DEBUG="true" *)wire rst_n ;
(* MARK_DEBUG="true" *)wire rd_clk ;
(* MARK_DEBUG="true" *)wire wr_clk ;
(* MARK_DEBUG="true" *)wire [3 : 0] dout ;
(* MARK_DEBUG="true" *)wire full ;
(* MARK_DEBUG="true" *)wire almost_full ;
(* MARK_DEBUG="true" *)wire wr_ack ;
(* MARK_DEBUG="true" *)wire overflow ;
(* MARK_DEBUG="true" *)wire empty ;
(* MARK_DEBUG="true" *)wire almost_empty ;
(* MARK_DEBUG="true" *)wire valid ;
(* MARK_DEBUG="true" *)wire underflow ;
(* MARK_DEBUG="true" *)wire [3 : 0] rd_data_count ;
(* MARK_DEBUG="true" *)wire [3 : 0] wr_data_count ;
(* MARK_DEBUG="true" *)wire prog_full ;
(* MARK_DEBUG="true" *)wire prog_empty ;
(* MARK_DEBUG="true" *)wire wr_rst_busy ;
(* MARK_DEBUG="true" *)wire rd_rst_busy ;
assign rst_n = sys_rst_n && locked; //在locked拉高之前一直复位
//PLL输出波形后,开始计数直到1111
always @(posedge sys_clk or negedge rst_n)begin
if(~rst_n)
rst_cnt <= 1'b0;
else if(&rst_cnt) //rst_cnt == 1111
rst_cnt <= rst_cnt;
else
rst_cnt <= rst_cnt + 1;
end
always @(posedge sys_clk or negedge rst_n)begin
if(~rst_n)
fifo_rst <= 1'b1;
else if(&rst_cnt)
fifo_rst <= 1'b0;
else
fifo_rst <= 1'b1;
end
always @(posedge sys_clk or negedge rst_n)begin
if(~rst_n)
state <= 3'd0;
else begin
case(state)
3'd0:begin
if(~fifo_rst)
state <= 3'd1;
else
state <= state;
end
3'd1:begin
if(~wr_rst_busy && ~full)
state <= 3'd2;
else
state <= state;
end
3'd2:begin
if(almost_full)
state <= 3'd3;
else
state <= state;
end
3'd3:begin
if(~rd_rst_busy && ~empty)
state <= 3'd4;
else
state <= state;
end
3'd4:begin
if(almost_empty)
state <= 3'd5;
else
state <= state;
end
3'd5:begin
state <= state;
end
default:state <= 3'd0;
endcase
end
end
//写使能
always @(posedge wr_clk or negedge rst_n)begin
if(~rst_n)
wr_en <= 1'b0;
else if(state == 3'd2)
wr_en <= 1'b1;
else
wr_en <= 1'b0;
end
//写数据
always @(posedge wr_clk or negedge rst_n)begin
if(~rst_n)
din <= 4'd0;
else if(wr_en)
din <= din + 1;
end
//把状态state同步到读时钟域
always @(posedge rd_clk or negedge rst_n)begin
if(~rst_n)begin
state_rd1 <= 3'd0;
state_rd2 <= 3'd0;
end
else begin
state_rd1 <= state;
state_rd2 <= state_rd1;
end
end
//读使能
always @(posedge rd_clk or negedge rst_n)begin
if(~rst_n)
rd_en <= 1'b0;
else if(state_rd2 == 3'd4)
rd_en <= 1'b1;
else
rd_en <= 1'b0;
end
clk_wiz_0 clk_wiz_0_inst
(
.clk_in1 (sys_clk ),
.clk_out1 (wr_clk ), //50M
.clk_out2 (rd_clk ), //75M
.resetn (sys_rst_n ),
.locked (locked )
);
//例化FIFO
fifo_w4_d16 fifo_w4_d16_inst(
.rst (fifo_rst),
.wr_clk (wr_clk),
.din (din),
.wr_en (wr_en),
.wr_rst_busy (wr_rst_busy),
.wr_data_count (wr_data_count),
.prog_full (prog_full),
.full (full),
.almost_full (almost_full),
.wr_ack (wr_ack),
.overflow (overflow),
.rd_clk (rd_clk),
.rd_en (rd_en),
.empty (empty),
.almost_empty (almost_empty),
.valid (valid),
.rd_data_count (rd_data_count),
.dout (dout),
.underflow (underflow),
.prog_empty (prog_empty),
.rd_rst_busy (rd_rst_busy)
);
endmodule
2.3、仿真测试与测试结果
由于测试逻辑都在RTL中实现了,所以testbench就比较简单了,只需要例化被测模块和实现时钟和复位即可。
`timescale 1 ns / 1 ns
module tb_fifo_test();
reg sys_clk;
reg sys_rst_n;
initial begin
sys_clk = 0;
sys_rst_n = 0;
#60
sys_rst_n = 1;
#6000
$finish; //停止仿真
end
always #10 sys_clk = ~ sys_clk;
fifot_test fifot_test_inst(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n )
);
endmodule
使用vivado自带的仿真工具simulator运行仿真,仿真结果如下:
(1)整体
(2)PLL从不稳定到稳定
(3)FIFO复位完成后需要一定的时间才可以操作
(4)写FIFO操作
(5)读FIFO操作
写入数据0-14共15个数据,读出数据也是0-14共15个数据。写、读一致,功能验证无误。
2.4、下板实测
把代码下载到开发板,用ILA观察一下,观察结果和仿真结果是一致的,不赘述,只放几张图:
(1)PLL稳定及FIFO复位
(2)写FIFO操作,写入数据0-14
(3)读FIFO操作,读取数据0-14
3、总结与参考
- FIFO的使用要注意实际深度
- FIFO使用需要先复位,复位时间要足够长,且复位后需要一定的时间才能使用FIFO
- 同步FIFO的使用会比较简单,因为其没有异步FIFO所需要的同步时钟域导致的延迟问题
- 不同资源实现的FIFO在各个功能特性上会有细微的区别,使用之前一定要认真测试,总结时序
- 异步FIFO的计数器不是精确的,只能作为大致的参考,以实现例如半空半满、1/4空满等判断
- 可编程空满的实现是依赖计数器的,其值同样不够精确
参考资料1:pg057-fifo-generator
- 博客主页:wuzhikai.blog.csdn.net
- 本文由 孤独的单刀 原创,首发于CSDN平台
- 文章还在持续更新,您有任何问题,都可以在评论区和我交流!
- 创作不易,您的支持是我持续更新的最大动力!如果本文对您有帮助,还请多多点赞、评论和收藏!
边栏推荐
- 交叉验证如何防止过拟合
- 【案例分享】网络环路检测基本功能配置
- 负载均衡性能参数如何测评?
- boot - prometheus-push gateway 使用
- BFS realizes breadth first traversal of adjacency matrix (with examples)
- Meet in the middle
- AI 从代码中自动生成注释文档
- [JS] obtain the N days before and after the current time or the n months before and after the current time (hour, minute, second, year, month, day)
- Spark TPCDS Data Gen
- 7.6模拟赛总结
猜你喜欢
[HFCTF2020]BabyUpload session解析引擎
Niuke cold training camp 6B (Freund has no green name level)
Body mass index program, entry to write dead applet project
2022 Google CTF segfault Labyrinth WP
免费白嫖的图床对比
黑马笔记---创建不可变集合与Stream流
Force buckle 1037 Effective boomerang
[牛客] [NOIP2015]跳石头
JTAG principle of arm bare board debugging
JTAG debugging experience of arm bare board debugging
随机推荐
The MySQL database in Alibaba cloud was attacked, and finally the data was found
Oracle:CDB限制PDB资源实战
Js逆向——捅了【马蜂窝】的ob混淆与加速乐
UI控件Telerik UI for WinForms新主题——VS2022启发式主题
阿里云中mysql数据库被攻击了,最终数据找回来了
[batch dos-cmd command - summary and summary] - string search, search, and filter commands (find, findstr), and the difference and discrimination between find and findstr
【JVM调优实战100例】04——方法区调优实战(上)
Informatics Orsay Ibn YBT 1172: find the factorial of n within 10000 | 1.6 14: find the factorial of n within 10000
boot - prometheus-push gateway 使用
微信公众号发送模板消息
THREE. AxesHelper is not a constructor
Supersocket 1.6 creates a simple socket server with message length in the header
The cost of returning tables in MySQL
736. Lisp 语法解析 : DFS 模拟题
Go zero micro service practical series (IX. ultimate optimization of seckill performance)
如何管理分布式团队?
Installation of gazebo & connection with ROS
What are the differences between Oracle Linux and CentOS?
Using the entry level of DVA in taro3.*
Tensorflow GPU installation