概述
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
手撕IP核系列——Xilinx FIFO IP核-异步FIFO
- 前言
- IP核设置
- IP核标志信号研究
- 代码要点
前言
以前从来没有这么细扣过,认识比较肤浅,通过几天对Xilinx IP核的仿制,对异步FIFO有了更深刻的认识。一开始,我是希望做到时序完全一模一样的,在某些间隔读和间隔写的场景中,也确实做到了输出时序完全一模一样,但发现在有些读和写同时进行的场景,有些输出就是与异步FIFO IP核会有差距。尽管最终我还是放弃追求完全和IP核的时序保持一致了,但通过这几天的手写和研究,也能写出功能正确的异步FIFO出来
下面,将描述实现的一些过程,我们以一个IP核的设置作为参考
IP核设置
设置卡片1
设置卡片2
设置卡片3
设置卡片4
设置卡片5
总结卡片
引脚图示:
IP核标志信号研究
我们先研究下IP输出的几个标志信号
FIFO写入阶段分析,(读使能保持为0)
1、 Wr_data_count
连续写模式
间隔写模式
Wr_data_count计数器相对于wr_en延迟了一个CLK
2、 Full almostfull
连续写模式:
间隔写模式:
Wr_data_count 最大数只会到3f,不会出现同步FIFO data_count的00。
full 会提前拉高,这里是3e处且wr_en为高时下一个时钟full拉高
almostfull 会提前拉高,这里是3d处且wr_en为高时下一个时钟almostfull拉高
rd_data_count
连续写模式:
间隔写模式
两种模式同样的规律都是:
Empty 只要rd_data_count 不为0了,立刻拉低
Almost_Empty 只要rd_data_count 不为1了,立刻拉低
上面是FIFO写入阶段,下面FIFO读出阶段。
1、 Wr_data_count、fill、almostfull
Wr_data_count从63变化到62时候,full立刻拉低
Wr_data_count从62变化到61时候,almostfull立刻拉低
2、rd_data_count empty almost empty
empty 会提前拉高,这里是01处且rd_en为高时下一个时钟empty拉高
almost empty 会提前拉高,这里是02处且rd_en为高时下一个时钟almostempty拉高
可以发现,这几个读写信号有种对称的规律。得好好体会。
此外,还有其他规律,
1、 FIFO最多只能容纳63个数据,因为会提前报full
2、 读写指针格雷码交互时钟域大致在3-4个clk时间,这个多设置几个时钟组合来摸索一下规律
知道了这些规律,就可以开干了
代码要点
1、异步FIFO设计最重要的地方在于读写指针的时钟域转化,需要借助于格雷码
2、处于读时钟域的读指针通过格雷码跨越到写时钟域,参与wr_data_count的计算
3、处于写时钟域的写指针通过格雷码跨越到读时钟域,参与rd_data_count的计算
4、wr_data_count用于产生满标识,rd_data_count用于产生空标识
用一下条件分别进行仿真,看会不会丢数
always @(posedge wr_clk)
r_cnt <= r_cnt + 1;
always @(posedge rd_clk)
r_cnt1 <= r_cnt1 + 1;
assign i_wr_en = r_cnt > 1000 ? ~fifo_full: 0;
always @(posedge wr_clk)
if(i_wr_en == 1)
begin
i_din <= i_din +1;
end
assign rd_en = r_cnt1 > 1000 ? ~fifo_empty : 0;
assign i_wr_en1 = r_cnt > 1000 ? ~fifo_full1: 0;
always @(posedge wr_clk)
if(i_wr_en1 == 1)
begin
i_din1 <= i_din1 +1;
end
assign rd_en1 = r_cnt1 > 1000 ? ~fifo_empty1: 0;
r_cnt > 1000 是因为IP核在一开始有一段busy的时间,空满都会拉高
1、读快写慢,写满则停,不满则写,非空则读,空了就不读
always #5 wr_clk = ~wr_clk;
always #4 rd_clk = ~rd_clk;
IP核和手写FIFO对比:写慢,所以输入是连续的,读快,所以读会存在不连续的情况,但数据是没有丢失的,只是比IP核的提前了一个时钟周期,而,rd_data_cnt 和 wr_data_cnt 的统计方式就有一点差别了,但这个不重要,只要数据没有丢就行了
2、读慢写块,写满则停,不满则写,非空则读,空了就不读
always #4 wr_clk = ~wr_clk;
always #5 rd_clk = ~rd_clk;
IP核和手写FIFO对比:读慢,所以输出是连续的,写快,所以写会存在不连续的情况,但同样输入输出的数据是没有丢失的
3、外部不进行空满判断,随机读和写,验证与IP核输出的数据是否一致。间隔写和间隔读
时序基本是一致的,有几个有1个clk的错位
(一开始我还想时序也完全一致,但折腾了好久,臣妾实在做不到呀)
所谓的时序一致就是希望
dout
empty
full
wr_data_count
rd_data_count
这几个输出信号,能和IP核时序完全一摸一样,但我实在时没有猜透IP里面的count empty full。某些场景能够弄成一致,结果换个场景又不行,所以我后面还是按照自己的想法来,只要功能对了就行吧。手撕一半吧姑且叫做,哈哈
最后说明:
资源备份:百度网盘-Xilinx设计-Xilinx异步FIFO
执行srcs中tb_async_fifo.tcl 文件即可直接仿真
最后
以上就是缓慢星星为你收集整理的手撕IP核系列——Xilinx FIFO IP核-异步FIFO前言IP核设置IP核标志信号研究代码要点的全部内容,希望文章能够帮你解决手撕IP核系列——Xilinx FIFO IP核-异步FIFO前言IP核设置IP核标志信号研究代码要点所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复