1.简介
定义:
FIFO(First In First Out)一种先入先出(读写数据是只能顺序写入顺序读出)的数据缓存器,读写数据时,其内部读写指针自动加1,因此没有外部地址线,使用简单。
分类:
FIFO可以分为同步FIFO和异步FIFO。同步FIFO的写入时钟和读取时钟完全一样,内核时一个简单双口RAM(Simple Dual Port RAM);异步FIFO写入时钟和读取时钟不同,不仅需要真双口RAM(True Dual Port RAM),还需要专门的握手信号进行跨时钟域的数据传递。
用途:
1)使用异步FIFO进行跨时钟域交互数据;2)进行不同数据宽度的读写匹配;3)对高速突发数据进行平均处理,降低瞬时处理速率。
使用场景:
1)AXI总线工作在1GHz以上,而USB2.0工作在480MHz时,就需要内嵌异步FIFO;2)AD采样为24位,而传输协议为8位时,可以使用FIFO进行不同数据宽度的读写匹配...
2.空满原理
空或满时应满足:读写指针相等。当复位后,或者读指针读出FIFO中最后的数据后追上了写指针则说明FIFO为空;当写指针写满一圈后又追上读指针则说明满。但是随之而来又有一个问题,当读写指针相等时,到底是空还是满呢?对此,目前采用的方法有两种:1)指针中增加一个额外的位用于确定满或空。2)采用格雷码完成FIFO空/满判断。
法1)在异步FIFO中容易出现问题(将一个二进制的计数值从一个时钟域同步到另一个时钟域时容易出现问题),例如1111在下一刻变成0000,但在实际电路中这个过程可能会持续较长时间,实际需要4个状态才能实现(例如1111=>1011=>1001=>1000=>0000),若写时钟而在这个期间采样,得出的指针就会是错误的。
法2)则能解决这个问题,因为格雷码每次变换只有一位发生改变。
3.创建
一般来说,现在使用FIFO时,可以直接使用公司自带的IP核实现,此处以ISE为例(新建项目就不说了,直接新建文件)。
(1)New Source
(2)选择IP 并填写文件名
(3)在Memories&Storage Elements中找到FIFOs
(4)接下来程序会自动打开FIFO Generator
(5)此处选择读写公用时钟还是独立时钟,采用块RAM还是分布RAM,(我选择的是独立时钟,Block RAM)
(6)接下来选择写宽度,写深度,读深度,读宽度。(因为本文举例的FIFO实在实际工程中,因此根据实际要求做了选择)
(7)接下来还有一些可选项,可以依照自己的需求选择。
(8)在生成之后点击View HDL Instantiation Template便可以查看接口信息,方便实例化;同时在
(9)同时在自定义的目录下会生成相关的文件与文件夹,如下图;其中simulation包含仿真信息。
4.使用(无具体代码,介绍方法)
fifo_da U2_0_2_F0(
.rst(!rst_n), // FIFO复位信号,高电平有效
.wr_clk(wr_clk), // 写FIFO时钟
.wr_en(u_rd_en), // 写FIFO使能
.din(din), // 写入FIFO的数据
//写入:wr_en为高电平时wr_clk的上升沿会把din写入fifo中;(同步写入)
.rd_clk(rd_clk), // 读FIFO时钟
.rd_en(rd_en), // 读FIFO使能
.dout(dout), // 读出FIFO的数据
.full(full), // output full
.empty(empty) // output empty
//读出:rd_en为高电平时,会在下一个rd_clk的上升沿会把fifo的数据读出;(下一个时钟数据读出)
);
5.相关
1)二进制码转格雷码
binarycode = graycode^(graycode>>1);
2)格雷码转二进制码
1 always@(geraycode)begin 2 3 for(i=0;i1;i=i+1) 4 5 binarycode[i]=^(geraycode>>i); 6 7 end
5.参考资料
1)《通信IC设计》李庆华著