很全很详细的FIFO Generator IP核的使用规则

**

FIFO Generator IP核的使用

**

1 概述

(1)最大支持500M
(2)支持三种接口:Native interface FIFOs、 AXI Memory Mapped interface FIFOs、 AXI4-Stream interface FIFOs
(3)读写数据时,在数据上升沿采样

2 FIFO规则

2.1 empty/full信号

实际上即使有数据写入到fifo中,empty还是为高,等一些周期之后才会拉低,具体多少个周期之后不一定,不知道。就理解成fifo的反应有点慢就行了。
如图:
在这里插入图片描述
不管fifo的empty信号什么时候拉低,咱们不用管,咱们使用者只要知道,当empty信号拉低以后,就可以将读请求rd_en拉高读取数据,当empty拉高后,就不能使能rd_en了。

同样,对于full信号,只有当full为低的时候,才能使wr_en置1。
在这里插入图片描述
如图所示,当full置1了,写使能信号wreq拉低了,记住是上升沿采样,所以5这个值没有写进去.

注意:
(1)对于full信号,当full为1后,绝对不能再写入数据。
(2)empty为1后,绝对不要进行读数据
(3)无任何说明,绝对不能丢失数据,也不能多读数据
(4)当异步的时候,full信号是和写时钟域同步的,empty信号时和读时钟域同步的,这一点要记得,再写verilog代码时候需要考虑进来。还有rd_data_count和wr_data_count也是不同时钟域的,需要注意。

2.2 almost_full /almost_empty
almost_empty:表明fifo中的数据几乎要空了,只有一笔数据可以进行读取了。
almost_full:表明fifo中的数据几乎要满了,最多能再写一笔数据进去了。

2.3 rd_data_count/wr_data_count
这个就很坑了!
一直以为rd_data_count指的是从fifo中读出了几个数据,wr_data_count指的是向fifo中写入了几个数据,,,,,其实完全不是那样的。两个值都指的是fifo中存了多少数据,而在异步fifo时候,两个信号的时钟域不同,所以波形中两者不是同时出现的。
也就是说rd_data_count和wr_data_count指的是同一个东西。

基于这一点,本人做了一个实验:
在这里插入图片描述
如图,一直往FIFO中写数据,可以看到wr_data_count一直在计数。但是rd_en一直为0,但是rd_data_count却也有数据在变化。这就说明了rd_data_count并不是指的是从fifo中读出来了多少数据。

看PG057解释:
在这里插入图片描述
也是上面所说fifo中有多少数据,而不是写入或者读出了多少数据。

注意:
(1)rd_data_count和wr_data_count也只是个大概值,并不完全准确。rd_data_count小于等于实际上fifo中的数,以免没数据的时候进行数据读取,相反,wr_data_count大于等于实际上fifo中数,以免溢出。
(2)写入写接口的数据要经过一些周期才能在读接口中被读出。
(3)还有一点需要重点强调的就是,rd_data_count/wr_data_count的值不是fifo中数据多少个字节,而是多少笔。
怎么理解呢?
举例来说,我设置写入的位宽为32bit,那么写入fifo一笔就是4个字节,但wr_data_count是1而不是4。如图所示,位宽为32bit,写了64个字节,需要16笔,wr_data_count计数为16.在这里插入图片描述
2.4 读写隔离
FIFO的读写隔离是实践总结出来的经验,在官方文档中并没有提及。使用fifo时候最好能够符合读写隔离。

什么是读写隔离呢?
读写隔离指的是,读写控制信号间是独立的,他们之间除了用fifo交流信息外,不能有任何信息交流。意思就是说,读FIFO的状态不能根据写fifo的信号来决定,写fifo也不能根据读fifo中的数据或状态来决定。
在这里插入图片描述
在这里插入图片描述
例:写侧的din_data写入FIFO时,其中包文包括了200个字节,使用din_vld作为读写使能,有可能出现读写不同步,因为你存入时就是你读出时;也有可能来了个短包文,存储完立马来了长包文,那么此时到底是写还是读?长包文未读完,来了短包文,此时FIFO就不知道如何处理。读写两侧应使用独立信号而不是互连信号。

2.5 读使能用组合逻辑
读使能必须判断空状态,并且要用组合逻辑产生。
在这里插入图片描述
这里指的是First-Word Fall-Fhrough模式,其实还是时序问题,不然可以导致多读一个,具体波形出来了以后具体分析吧。

2.6 因果关系
因果关系和上面的读写隔离其实是差不多的意思。

例如当判断rd_data_count达到某个值以后,令写使能wr_en置位继续往fifo中写数据,写入的数据又会导致rd_data_count的值变化,这要就造成了死循环。
真正的因果关系是,empty导致wr_en进行写数据,所以rd_data_count增加。

2.7 位宽转换
FIFO作为转换位宽时,高位优先出(将宽bit转窄bit);先进置于高位(窄bit转宽bit)。

2.8 rst信号
一定要注意:FIFO复位后的几个周期(2、3个周期)是无法进行写操作的,可能原因就是FIFO进入工作状态也需要一定时间的,如果此时就进行数据写入,可能导致某些数据丢失!!!

这一点一定要注意,而且在实际应用中,最好在fifo复位之后多空一些周期之后再进行写操作。
比如本人复位之后空了5个周期才进行写数据,写16笔数据,但是此时数据依旧有丢失了,只写进去了15笔。后来复位之后空了8个周期才进行写数据,16笔数据全部写进去了。
2.9 valid/wr_ack信号
(1)wr_ack的工作模式,即写入成功时,wr_ack将在下一周期拉高。也就是说,wr_ack反映的是上一周期的写操作。

在UG057上也有说:代表上一个周期写入成功
在这里插入图片描述
(2)valid和wr_ack类似,代表的是读数据成功。不过此处和wr_ack不同的是代表当前周期读到数据成功,而不是上一个周期,切记。在这里插入图片描述

3 IP核配置

3.1 basic在这里插入图片描述
interface type
如图,支持三种类型的接口。

Fifo implementation:
1,时钟,由FIFO的作用可知大部分都是读写不同步的,这里我们也选择异步模式,即读写的时钟不同。
2,存储器类型,这里主要是block RAM和distribute RAM之间的区别。简而言之,block RAM是FPGA中定制的ram资源,而distribute RAM则是由LUT构成的RAM资源。由此区别表明,当FIFO较大时应选择block RAM,当FIFO较小时,选择distribute RAM.另外一个很重要的就是block RAM支持读写不同宽度,而distribute不支持。在这里为了更全面的了解FIFO,选择block RAM以拥有非对称方向速率的特性。

同步fifo资源较少,结构简单。异步fifo的资源占用较多,结构复杂。

3.2 native ports
在这里插入图片描述
read mode
(1)读模式有两种选择,一般选择标准模式,当rd_en使能后,下一个clk出第一个数据。
在这里插入图片描述
如图,三个蓝框代表三个时钟,第一时钟rd_en拉高了,到第二个时钟就是第一个数据ebeae9d8,第三个时钟就是第二个数据。

(2)First-Word Fall-Fhrough:指的就是rd_en还没使能的时候,第一个数据就已经在读数据线dout上了,当rd_en使能后,清除上一个数据,此时第二个数据D1就出来了,当下一个clk时候,rd_en还是1的话,就将D1清除了,D2就出来了。
在这里插入图片描述
data port parameters
写数据宽度定义为32位,写深度定义为1024,读宽度定义为32位,而读深度将根据以上几个参数自动计算。但我们需要注意的是,在data port parameters处,有actual write depth和actual read depth,他们都比我们设置的要小,其意义以及原因将在例程中说明。

data port parameters处,有actual write depth和actual read depth,他们都比我们设置的要小,在实际的工程应用中,FIFO深度确实要比预设的小1,即当写入了Write Width-1个数据之后,FIFO的满信号full会拉高,这个时候如果还要写入数据,则写入的数据丢失。同理,读出Read Width-1个数据后,FIFO的空信号empty会拉高,此时读出信号无效。

initialization
(1)enable reset synchronization:选中后FIFO中的读端口和写端口同时复位,不选中,就会有两个复位信号需要连接。
(2)enable safety circuit:选中后会有两个信号:wr_rst_busy、rd_rst_busy
(3)Full Flags Reset Value:该值指的是full信号在FIFO复位时候的值为多少。这里注意,不是full一个信号,指的是关于full的所有信号(full/almost_full/prog_full)。

如图,当Full Flags Reset Value设为0的时候,rst_n为0的时候对fifo进行复位,可以看到关于full的三个信号都为0。
在这里插入图片描述
如图,当Full Flags Reset Value设为1时,rst_n为0的时候对fifo进行复位,此时三个信号都为1。但是复位完成以后,经过了好几个时钟周期以后full信号才会自动拉低,这样就很容易出现一些问题。比如上面所说,fifo复位以后等几个周期再进行写入操作,如果等的周期不够,此时full信号又是1,那么还是会丢数据。
所以,没有特殊要求,建议还是将当Full Flags Reset Value的值设置为0好一点。
在这里插入图片描述
3.3 status flag在这里插入图片描述
Optional Flags
almost full flags:就是fifo马上满了,还能再写入一笔数据。
almost empty flags:fifo马上空了,再读一笔数据就空了。

Programmable Flags
Programmable full type:有五个选项在这里插入图片描述
选择第一个就不启用program full。
选择第二个就启用program full,然后再full threshold assert value中设置一个阀值,达到这个阀值,就进行program full就置1。
选择第四个,也启用program full信号,也可以设置阀值,但是不是再vivado这个UI界面设置,而是会多出一个prog_full_threshole信号,用户在verilog代码中自己设置,这样就更加灵活了,也就是说,full threshold assert value选项中也就设置不了。在这里插入图片描述
第三个意思应该是可以设置两个触发条件,当fifo中的数据在full threshold assert value和full threshold negate value之间时候,program full就置1。但是不确定,还没试过在这里插入图片描述
第五个类似,用户可以在verilog中设置阀值。

3.4 data counts在这里插入图片描述
这界面就没啥好说的,一看就会系列。

4 参考链接

链接1:(关于FIFO使用总结)
https://www.cnblogs.com/limanjihe/p/9771370.html
链接2:(xilinx FIFO的使用及各信号的讨论)
https://blog.csdn.net/xuexiaokkk/article/details/47753459

这两个链接必看,网上再搜一搜关于fifo使用的经验总结,不然只知道规则,在编程中依旧很容易出现问题,具体遇到了再说吧。

声明:文章用于个人知识学习积累与回顾,同时做个分享,个人能力有限,如有错误,欢迎指正。 联系:个人微博:东巴克。公众号:巴客小屋。文章有帮到你,也欢迎你来关注一波,谢谢。