ALTERA在LPM(library of parameterized mudules)库中提供了参数可配置的单时钟FIFO(SCFIFO)和双时钟FIFO(DCFIFO)。FIFO主要应用在需要数据缓冲且数据符合先进先出规律的同步或异步场合。LPM中的FIFO包含以下几种:
1.SCFIFO:单时钟FIFO;
2.DCFIFO:双时钟FIFO,数据输入和输出的宽度相同;
3.DCFIFO_MIXED_WIDTHS:双时钟FIFO,输入输出数据位宽可以不同。
配置不细说,直接看时序来理解。
1. 同步FIFO验证时序
IP核设置说明:
开辟空间8bits*8words;almost_full设置为“6”;almost_empty设置为“2”;采用普通同步FIFO模式(the data becomes available before “rdreq” is asserted)。
引脚说明:
- aclr和sclr:
aclr为异步清零,不管何时,只要出现上升沿,立刻清除q中数据,q<=8’bx。emtpy为1;full为0;almost_empty为1(根据参数判断);almost_full为0。
sclr为同步清零,只有sclr在clock上升沿时为“1”才能执行清除,效果同aclr。 - wrreq和rdreq:读写使能,高电平有效,clock上升沿执行读、写操作。
- full:当写入数据量达到最大空间时,clock上升沿写入最后一个数据同时full拉高;读取数据时随clock上升沿触发同时拉低。
- empty:与full相反。写入数据同时拉低;读到最后一个数据同时拉高。
- almost_full:当usedw的数值≥almost_full参数设置值almost_full_value时为1,其余时刻保持0(不管是读操作还是写操作,只与数值比较有关)。
- almost_empty:当usedw的数<almost_empty参数设置值almost_empty_value时为1,其余时刻保持0(不管是读操作还是写操作,只与数值比较有关)。
- usedw:显示当前FIFO中已存数据个数,与写入数据的个数是同步的,即写第一个数据时就置1,空或满时值为0(满是因为寄存器溢出)。
2. 异步FIFO验证时序
从时序图上说明DCFIFO的工作情况,虽然网上也有相关的时序图,但是写得不是很清晰。
建立一个位宽为8位,深度为4的DCFIFO。wr_clk与系统时钟同频,但是相移180°(反向)。rd_clk = 2*wr_clk。先写满,再读空的方式验证。从时序图上看,感觉DCFIFO内部存在两个存储空间,接下来解释。
T1时刻,写使能wr置高。
T2时刻,第一个wr_clk上升沿到来,第一个数据8’h01写入到FIFO中,此时wr_empty立即拉低,表明此刻FIFO不为空(写部分)。wr_usedw此时还是为0,与单时钟FIFO(SCFIFO)不同的是,SCFIFO第一个数据写入的时候,usedw会为1,说明wr_usedw有1个时钟周期的滞后(user guide里面说wrreq to wrusedw会滞后2个wr_clk,不太明白这与写入数据有什么之间的联系)。写满时usedw溢出后变为0。
T3时刻,rd_empty也被拉低,这就有点像“写”部分的存储空间的数据copy到了“读”部分的存储空间,而延迟时间正好就是T2与T3之间的时间间隔。随即rdusedw开始从0递增,但是递增周期感觉是以wr_clk为基准。
T4时刻,最后一个数据8’h04写入FIFO,wr_full被拉高,表明FIFO(写入部分)已经满了。wr_usedw计数为3。随后结束写使能,即wr拉低。
T5时刻,“写”部分的存储空间的数据全部copy至“读”部分的存储空间,此时rd_full也就被拉高了。
T6时刻,读使能信号拉高,即rd信号拉高。
T7时刻,读时钟信号rd_clk的第一个有效上升沿到来,读出第一个数据8’h01。此时“读”存储空间的满信号rd_full被拉低,表明“读”空间不满。
T8时刻,“写”存储空间的满信号wr_full才被拉低,表明与“读”存储空间之间有延迟。
T9时刻,最后一个数据8’h04被读出,此时“读”存储空间的空信号rd_empty立即被拉高,表明已经空了。rdusedw滞后1个rd_clk减为0。
T10时刻,在“读”存储空间已经空了之后,经过一定时间的延迟,“写”存储空间才知道FIFO已空。注意在T10时刻前后,可能存在wrusedw的不稳定,在wr_empty重新拉高一个周期之后,wrusedw才重新置零。
经过上述时序的“直译”,发现DCFIFO的读和写像是两个独立的内部存储空间,存在一个“copy”或者握手的过程,所以导致双方的空、满信号存在一定的延迟。这就需要考虑,在实际项目中要用到DCFIFO时,采用什么信号来判断,此刻FIFO能否安全的读写(也可以将almost相关的信号添加进来)。DCFIFO的优势在于写端和读端时钟不一样,安全的边写边读,但是得注意读写时钟频率差异,以便控制FIFO深度以及相应的控制信号。
rd_clk = 2*wr_clk,不写满,读空
rd_clk = 3*wr_clk时
3、遇到问题
在实际设计中,有个模块控制FIFO写入数据A,假设全局时钟global_clk以时序逻辑的方式驱动FIFO的写使能(fifo_wr)和写数据(data),而FIFO的时钟信号就直接赋上global_clk,那么就会得到如图1所示的时序图。
写使能和数据都在global_clk上升沿发生变化。
那么问题就来了,按道理说,FIFO写入数据是在wr拉高前提下,在fifo_clk上升沿写入数据。那么是不是这样设计就不满足数据的保持时间?
换一种设计,FIFO的写使能(fifo_wr)和写数据(data)依然基于global_clk的时序逻辑,但是fifo_clk相对于global_clk有个相移,比如说反相。那么就得到了图2的时序图,这样就满足设计需求了吗?
我想请问的是,一般工程设计,怎样设计FIFO的时序(主要是时钟吧)是怎样的呢?