1、FIFO 概念FIFO是英文First In First Out 的缩写,是一种先进先出的数据缓存器,他与普通存储器的区别是没有外部读写地址线,这样使用起来非常简单,但缺点就是只能顺序写入数据,顺序的读出数据,其数据地址由内部读写指针自动加1完成,不能像普通存储器那样可以由地址线决定读取或写入某个指定的地址。FIFO 用法FIFO一般用于不同时钟域之间的数据传输,比如FIFO的一端时AD数据采集,另一端时计算机的PCI总线,假设其AD采集的速率为16位 100K SPS,那么每秒的数据量为100K16bit=1.6Mbps,而PCI总线的速度为33MHz,总线宽度32bit,其最大传输速率为1
2、056Mbps,在两个不同的时钟域间就可以采用FIFO来作为数据缓冲。另外对于不同宽度的数据接口也可以用FIFO,例如单片机为8位数据输出,而DSP可能是16位数据输入,在单片机与DSP连接时就可以使用FIFO来达到数据匹配的目的。FIFO的一些重要参数 FIFO的宽度:也就是英文资料里常看到的THE WIDTH,它只的是FIFO一次读写操作的数据位,就像MCU有8位和16位,ARM 32位等等,FIFO的宽度在单片成品IC中是固定的,也有可选择的,如果用FPGA自己实现一个FIFO,其数据位,也就是宽度是可以自己定义的。FIFO的一些重要参数 FIFO的深度:THE DEEPTH,它指的是F
3、IFO可以存储多少个N位的数据(如果宽度为N)。如一个8位的FIFO,若深度为8,它可以存储8个8位的数据,深度为12,就可以存储12个8位的数据,FIFO的深度可大可小,FIFO深度的计算并无一个固定的公式。在FIFO实际工作中,其数据的满/空标志可以控制数据的继续写入或读出。在一个具体的应用中也不可能由一些参数算数精确的所需FIFO深度为多少,这在写速度大于读速度的理想状态下是可行的,但在实际中用到的FIFO深度往往要大于计算值。一般来说根据电路的具体情况,在兼顾系统性能和FIFO成本的情况下估算一个大概的宽度和深度就可以了。而对于写速度慢于读速度的应用,FIFO的深度要根据读出的数据结构
4、和读出数据的由那些具体的要求来确定。FIFO的一些重要参数 满标志满标志:FIFO已满或将要满时由FIFO的状态电路送出的一个信号,以阻止FIFO的写操作继续向FIFO中写数据而造成溢出(overflow)。空标志空标志:FIFO已空或将要空时由FIFO的状态电路送出的一个信号,以阻止FIFO的读操作继续从FIFO中读出数据而造成无效数据的读出(underflow)。读时钟读时钟:读操作所遵循的时钟,在每个时钟沿来临时读数据。写时钟写时钟:写操作所遵循的时钟,在每个时钟沿来临时写数据。读指针读指针:指向下一个读出地址。读完后自动加1。写指针写指针:指向下一个要写入的地址的,写完自动加1。读写指
5、针其实就是读写的地址,只不过这个地址不能任意选择,而是连续的。FIFO的分类 根据FIFO工作的时钟域,可以将FIFO分为同步FIFO和异步FIFO。同步FIFO是指读时钟和写时钟为同一个时钟。在时钟沿来临时同时发生读写操作。异步FIFO是指读写时钟不一致,读写时钟是互相独立的。FIFO设计的难点 FIFO设计的难点在于怎样判断FIFO的空/满状态。为了保证数据正确的写入或读出,而不发生溢出或读空的状态出现,必须保证FIFO在满的情况下,不能进行写操作。在空的状态下不能进行读操作。怎样判断FIFO的满/空就成了FIFO设计的核心问题。在用到触发器的设计中,不可避免的会遇到亚稳态的问题。在涉及到
6、触发器的电路中,亚稳态无法彻底消除,只能想办法将其发生的概率将到最低。同步FIFO功能定义 用64*8 RAM实现一个同步先进先出(FIFO)队列设计。由写使能端控制该数据流的写入FIFO,并由读使能控制FIFO中数据的读出。写入和读出的操作由时钟的上升沿触发。当FIFO的数据满和空的时候分别设置相应的高电平加以指示。顶层信号定义:信号名称I/OI/O功能描述源/目标备注RstRstIn全局复位(低有效)管脚ClkClkIn全局时钟管脚频率10Mhz;占空比:50%Wr_enWr_enIn低有效写使能管脚Rd_enRd_enIn低有效读使能管脚Data_in7Data_in7:00In数据输入
7、端管脚Data_out7Data_out7:00 Out数据输出端管脚EmptyEmptyOut空指示信号管脚为高时表示fifo空FullFullOut满指示信号管脚为高时表示fifo满顶层模块划分及功能实现n该同步fifo可划分为如下四个模块,如图1所示:存储器模块(RAM)用于存放及输出数据;读地址模块(rd_addr)用于读地址的产生;写地址模块(wr_addr)用于写地址的产生标志模块(flag_gen)-用于产生FIFO当前空满状态。同步FIFO的模块划分 RAMRD_addr_genWR_addr_genwr_addr3:0rd_addr3:0wr_enrd_enclkclkful
8、lemptyrd_enwr_enclkflag_genclkrstrd_enwr_enemptyfulldata_in7:0data_out7:0顶层模块划分及功能实现nRAM模块本设计中的FIFO采用采用64*8双口RAM,以循环读写的方式实现;n根据rd_addr_gen模块产生的读地址,在读使能(rd_en)为高电平的时候,将RAM中rd_addr3:0地址中的对应单元的数据在时钟上升沿到来的时候,读出到data_out7:0中。n根据wr_addr_gen产生的写地址和在写使能(wr_en)为高电平的时候,将输入数据(data_in7:0)在时钟上升沿到来的时候,写入wr_addr3:
9、0地址对应的单元。顶层模块划分及功能实现nwr_addr_gen:该模块用于产生FIFO写数据时所用的地址。由于64个RAM单元可以用6位地址线寻址。本模块用6位计数器(wr_addr5:0)实现写地址的产生。n在复位时(rst=0),写地址值为0。n如果FIFO未满(full)且有写使能(wr_en)有效,则wr_addr5:0加1;否则不变。顶层模块划分及功能实现nrd_addr_gen:该模块用于产生FIFO读数据时所用的地址。由于64个RAM单元可以用6位地址线寻址。本模块用6位计数器(rd_addr5:0)实现读地址的产生。n在复位时(rst=0),读地址值为0。n如果FIFO未空(
10、empty)且有读使能(rd_en)有效,则rd_addr5:0加1;否则不变。顶层模块划分及功能实现n flag_gen模块flag_gen模块产生FIFO空满标志。本模块设计并不用读写地址判定FIFO是否空满。设计一个计数器,该计数器(pt_cnt)用于指示当前周期中FIFO中数据的个数。由于FIFO中最多只有64个数据,因此采用6位计数器来指示FIFO中数据个数。具体计算如下:n复位的时候,pt_cnt=0;n如果wr_en和rd_en同时有效的时候,pt_cnt不加也不减;表示同时对FIFO进行读写操作的时候,FIFO中的数据个数不变。n如果wr_en有效且full=0,则pt_con
11、t+1;表示写操作且FIFO未满时候,FIFO中的数据个数增加了1;n如果rd_en有效且empty=0,则pt_cont-1;表示读操作且FIFO未满时候,FIFO中的数据个数减少了1;n如果pt_cnt=0的时候,表示FIFO空,需要设置empty=1;如果pt_cnt=64的时候,表示FIFO现在已经满,需要设置full=1。验证方案1)测试用例1:测试FIFO在正常状态下,是否能写入和读出;full和empty的标志位均为0;2)测试用例2:测试FIFO在满的情况下,是否将full标志位置为1;在满的情况下读,full标志是否被复位到0;3)测试用例3:测试FIFO在空的情况下,是否将empty标志位置为1;在空的情况下读,empty标志是否被复位到0;4)测试用例4:异步复位后,FIFO是否可以正常工作;