[1] Clifford E. Cummings, “Simulationand Synthesis Techniques for Asynchronous FIFO Design,” SNUG 2002 (Synopsys UsersGroup Conference, San Jose, CA, 2002) User Papers, March 2002, Section TB2,2nd paper. Alsoavailable at www.sunburst-design.com/papers
下载链接:https://pan.baidu.com/s/1T9eyMHXcveWei8BowKWk3w 密码:ny20
注:代码请见参考资料[1]:pp 13-19
★“大规模ASIC或FPGA设计中,多时钟系统往往是不可避免的,这样就产生了不同时钟域数据传输的问题,其中一个比较好的解决方案就是使用异步FIFO来作不同时钟域数据传输的缓冲区,这样既可以使相异时钟域数据传输的时序要求变得宽松,也提高了它们之间的传输效率。”(摘自:https://www.toutiao.com/a6329245604338450690/)
★无论是快时钟域到慢时钟域还是慢时钟域到快时钟域都可以用异步fifo
★异步fifo可以解决多个比特数据跨时钟域进行传输的问题。
●跨时钟域的方法有(摘自:http://dengkanwen.com/238.html):
★打两拍(用于单比特数据传输)
▼握手信号:使用多级触发器,然后用组合电路产生采样使能信号。(缺点:不能解决采样时钟比数据时钟慢很多的情况)
可以把快时钟域的数据拉长,但这相当于是放慢了快时钟域的时钟,跟慢时钟域传数据到快时钟域的实质是一样的。
(https://www.cnblogs.com/IClearner/p/6579754.html)
★异步双口ram或者异步fifo(用于多比特数据传输)
其实,双口ram就是异步fifo里面存储数据的单元。
★格雷码转换(其实是为了降低出错概率)
使用格雷码传读写地址的原因:减小亚稳态出现的概率;
●异步FIFO:
读指针和写指针位于不同的时钟域的FIFO
●作用:
将数据从一个时钟域传到另外一个时钟域
●难点:
设计异步FIFO很容易出错,而且是概率性出错。比如,一个设计出来的异步FIFO很有可能99%的情况下是正常工作的,但是1%的情况下会出错,这样的错误很不容易被发现。
设计异步FIFO的主要难点有:
★产生FIFO指针
★判断FIFO的“空”与“满”。
为什么异步fifo容易出错?
▼存在多个信号跨时钟域然后交汇,存在节拍上的不确定性。
●写指针:总是指向下一个要写的字节的位置。
●读指针:总是指向下一个要读的字节的位置。
Reset的时候,写指针和读指针都指向0(FIFO初始的位置),但读指针指向的是无效数据,因为此时FIFO里面根本就没有数据,此时FIFO的EMPTY位有效。
也就是说,当FIFO为空的时候,读指针不能是有效的;当FIFO为满的时候,写指针不能是有效的;
●Empty:当读指针和写指针指向同一个位置的时候,FIFO为空。
●Full:当读指针和写指针指向同一个位置的时候,FIFO为满。
那么问题来了:
解决方案,增加一个额外的地址比特(一般作为地址的MSB),当写指针套了读指针一圈时,将写指针的该比特取反,表示当前状态为“满”。如下图:
也就是说,raddr和waddr的最高位只用于判断fifo的空与满,当raddr和waddr的最高位相同的时候,fifo判断为空,否则为满。
●一个待解决的问题:二进制指针计数值在增加时,可能有多个比特同时变化。
★例如:计数值从7(0111)增加到8(1000)时,4个比特都发生了变化。
★计数值多个比特变化会带来什么问题呢?
▼首先,读写指针同步是为了判断FIFO的“空”或者“满”。
▼毛刺是异步电路杀手:一个毛刺被触发器采样后会被放大传播。
▼实现电路时不可能实现所有的地址总线等长。
★方法一:保持寄存器
◆用一个寄存器对二进制计数值进行存储,然后使用同步后的ready和acknowledge信号进行握手,从而将存储的二进制计数值传到新的时钟域。
▼因为有ready和acknowledge信号交互消耗时钟周期,所以不是所有的二进制计数值都可以进入新的时钟域。
▼这种方法不会产生Overflow和Underflow。
★方法二:格雷码
◆格雷码每次只允许一个比特发生变化,从而回避了多个比特同时变化的问题。
★FIFO在RTL仿真中理想地工作,但是在具体实现后会出现巨大的问题。
★下面代码展示了一个RTL仿真中理想工作但是在实际情况中会出现问题的电路。
上述代码的问题主要在于:在读写指针变化的时候会有多个bits同时发生变化。
★格雷码与二进制的互换方法(摘自:https://blog.csdn.net/jingfengvae/article/details/51691124)
格雷码产生电路(可以同时产生n bit 和(n-1) bit的格雷码)
问题:用格雷码的地址,buffer“空”或“满”的状态不好判断
解决办法:用格雷码来同步,但依然用二进制码来存地址(如下图):
整个FIFO的结构:
★判断异步FIFO为空:同步过后的写指针(rq2_wptr)跟下一个将要存入读指针寄存器的格雷码(rgraynext)作比较。
▼代码:
★判断异步FIFO为满:
★从快时钟域到满时钟域的问题:
▼问题1:在慢时钟域的一个周期中,经历了两次或多次快时钟域的上升沿,那么对应的格雷码就会有两个或多个bits发生变化,会不会产生多个bits同步的问题?
答:不会,假如在慢时钟域的一个时钟周期中,快时钟有n个bits发生了变化,但是一定有(n-1)个bits变化是发生在慢时钟域时钟上升沿到来之前的,在慢时钟域时钟上升沿到来的时候还是只有一个bit在发生变化,所以不存在多个bits同步的问题。
▼问题2:会不会有Overflow和Underflow产生?
答:不会,因为Overflow和Underflow发生的条件只有一个:就是本时钟域的指针超过了对面时钟域的指针,而从对面时钟域同步过来的指针本来就是对面时钟域指针的延迟,所以本时钟域的指针永远没办法超过对面时钟域同步过来的指针
★读与写时钟域使用的是不同的Reset信号
★在reset的时候,FIFO中的数据也被清空,变为无效数据,所以reset是同步的
★但是读写两端的set是异步的