《同步FIFO设计详解及代码分享.docx》由会员分享,可在线阅读,更多相关《同步FIFO设计详解及代码分享.docx(7页珍藏版)》请在第一文库网上搜索。
1、同步FIFO设计详解及代码分享1.FIFO简介FIFO(先入先出,FirstInFirstOut)存储器,在FPGA和数字IC设计中非常常用。根据接入的时钟信号,可以分为同步FIFO和异步FIFOo*FIFO底层基于双口幽J*,同步FIFO的读写时钟一致,异步FIFO读时钟和写时钟不同。同步时钟主要应用于速率匹配(数据缓冲),类似于乒乓存储提高性能的思想,可以让后级不必等待前级过多时间;异步FIFO主要用于多bit信号的跨时钟域处理。本文讨论同步FIFO的结构及控制逻辑设计,并给出代码。2 .同步FIFO接口对于同步FIFO,包含必要的接口如下图所示:(1) e1k:时钟信号,读写共用;(2)
2、 rst_n:复位信号,视具体设计和皿采用同步复位还是异步复位,此处默认使用异步低电平复位;(3) Wdata:写数据信号,信号后带“”表示是多bit信号;(4) rdata:读数据信号,信号后带“”表示是多bit信号;(5) Wfu11:满信号,指示FIR)写满了,不能再写了,如果再写会覆盖掉还没读出的写入数据,造成数据丢失;(6) rempty:空信号,指示FIFO读空了,不能在读了,如果再读相当于有的数据重复读了第二遍,造成数据错误;(7) wine:写使能信号,写使能有效时表示希望能写入数据;(8) rinc:读使能信号,读使能有效时表示希望能读出数据;3 .双口RAM接口在实现FIF
3、O时,无论是同步FIFO还是异步FIFO,通常会通过双口RAM(Dua1PortRAM)并添加一些必要的逻辑来实现。双口RAM的接口如下图所示。*左侧全部是写时钟域的,包括写时钟、写数据、写地址和写使能信号;*右侧全部是读时钟域的,包括读时钟、读数据、读地址和读使能信号;4,基于双口RAM的同步FIFO结构根据同步FIFO的接口和双口RAM的接口,在借助双口RAM实现同步FIFO时,如下图所示结构,只需要加入读、写控制逻辑即可。在写逻辑中,用于产生写地址和写满信号;在读逻辑中,用于产生读地址和读空信号。读写控制逻辑还需要受到读写使能信号的控制。5 .读写地址产生逻辑读写地址什么时候能够递增?显
4、然,对于写地址必须满足:(1)写使能有效(要写入);(2)没写满(能写入);即:a1ways(posedgee1kornegedgerst_n)beginif(rstn)beginwaddr=,b;ende1sebeginif(wine&vfu11)beginwaddr=waddr+1,b1;ende1sebeginwaddr=waddr;endendend对于读地址必须满足:(1)读使能有效(要读出);(2)没读空(能读出);即:a1ways(posedgee1kornegedgerst_n)beginif(rst_n)beginraddr=,b;ende1sebeginif(rinc&re
5、mpty)beginraddr=raddr+b1;ende1sebeginraddr=raddr;endendend6 .空满信号产生逻辑搞定了读写地址的控制逻辑,还差最后一步也是最关键的信号:空满信号如何产生。空:读空,读地址追上写地址;满:写满,写地址追上读地址。问题来了:怎么判地址断追上了呢?如果地址相等那应该是追上了,即raadr=WaCIC1r或者WcIdr=raddr。如果按照这种判断,显然这两个地址追上对方的判断是等效的,无法区分出来到底是写追上读还是读追上写。可以考虑:使用1个标志位f1ag来额外指示写追上读还是读追上写。参考前人的文献,判断空满的方式有多种,非常常用的一种是C
6、1iffordE.Cummings文章中提到的扩展1bit的读写地址方法,也就是说,将前面提到的f1ag指示信号和原本N位的读写地址结合,使用N+1位的读写地址,其中最高位用于判断空满信号,其余低位还是正常用于读写地址索引。以一个4深度的FIFO实例来说明,4深度原本需要2bit的读写地址,现在扩展成3bito使用低2位来进行双口RAM的地址索引,高位用于判断空满。对于空信号,可以知道当FIFO里没有待读出的数据时产生。*也就是说,此时读追上了写,把之前写的数据刚刚全部都出,读地址和写地址此时指向相同的位置,读地址-写地址二0*,即raddr=waddr对于写满信号,*当写入后还没被读出的数据
7、恰好是FIFO深度的时候,产生满信号,即写地址-读地址=FIFO深度=4。对照下图可以发现,此时对于双口RAM的2bit的地址来说,读写地址一致;对于最高位来所,写是1而读是0。再考虑下图所示的一种情况,写入待读出的数据仍然是4个,此时也是4深度的FIFO已经满了。读写地址的低位相同,高位是写。读1。对于写满的2种情况,总结下来,都是低位相同,最高位相反。即:raddrN二二vaddrNraddrN-1:0二二waddrN-1:0也就是:raddr=vaddrN,waddrN-1:0所以,空满逻辑产生的代码为:a1ways(posedgee1kornegedgerst_n)beginif(rs
8、t_n)beginwfu11=,b;rempty=,b;ende1sebeginwfu11=(raddr=addrADDRJVIDTH,waddrADDRJVIDTH-1:0);rempty=(raddr=waddr);endend7 .全部代码timesca1e1ns1ns/FPGA探索者modu1eSfifO#(parameterparameter)(inputinputinputinputinputWIDTH=8,DEPTH=16e1k,rst_n,wine,rinc,WIDTH-1:0wdata,outputregoutputregoutputwire);wfu11,rempty,WI
9、DTH-1:0rdata/用IOCaIParam定义一个参数,可以在文件内使用Ioca1paramADDRJVIDTH=$c1og2(DEPTH);regADDRJVIDTH:0waddr;regADDRJVIDTH:0raddr;a1ways(posedgee1kornegedgerst_n)beginif(rst_n)beginwaddr=,b;ende1sebeginif(wine&vfu11)beginwaddr=waddr+b1;ende1sebeginwaddr=waddr;endendenda1ways(posedgee1kornegedgerst_n)beginif(rst_n
10、)beginraddr=,b;ende1sebeginif(rinc&rempty)beginraddr=raddr+b1;ende1sebeginraddr=raddr;endendenda1ways(posedgee1kornegedgerst_n)beginif(rst_n)beginwfu11=,b;rempty=,b;ende1sebeginwfu11=(raddr=addrDDR,WIDT1waddrADDR_WIDTH-1:o);rempty=(raddr=waddr);endend/带有parameter参数的例化格式dua1_port_RAM#(.DEPTH(DEPTH),.
11、Width(Width)dua1_port_RAM_U0(.wc1k(c1k),.wenc(wine),.waddr(waddrDDRWIDTH-1:0),.wdata(wdata),.rc1k(c1k),.renc(rinc),.raddr(raddrADDR_WIDTH-1:0),.rdata(rdata);endmodu1e/*RAM子模块*/modu1edua1_portRAM#(parameterDEPTH=16,parameterWIDTH=8)(inputwcIk,inputwenc,input$c1og2(DEPTH)-1:0waddr深度对2取对数,得到地址的位宽。,inputWIDTH-1:0wdata数据写入,inputrc1k,inputrenc,inputJc1og2(DEPTH)-1:0raddr深度对2取对数,得到地址的位宽。,outputregWIDTH-1:0rdata数据输出);regWIDTH-1:0RAMMEM0:DEPTH-1;a1ways(posedgewc1k)beginif(wenc)RAM_MEMwaddr=wdata;enda1ways(posedgerc1k)beginif(renc)rdata=RAM_MEMraddr;endendmodu1e