一、异步FIFO理解
1.1异步FIFO结构
由图可见,异步FIFO的核心部件就是一个 Simple Dual Port RAM ;左右两边的长条矩形是地址控制器,负责控制地址自增、将二进制地址转为格雷码以及解格雷码;下面的两对D触发器 sync_r2w 和 sync_w2r 是同步器,负责将写地址同步至读时钟域、将读地址同步至写时钟域。
1.2异步FIFO空满的判断
在同步FIFO设计中,fifo_num是由写地址减去读地址所得到,利用fifo_num 来作为FIFO空或满的判断依据。而对于异步FIFO而言,数据是由某一个时钟域的控制信号写入FIFO,而由另一个时钟域的控制信号将数据读出FIFO。也就是说,读写指针的变化动作是由不同的时钟产生的,处在不同的时钟域上,所以不能直接相减。因此,对FIFO空或满的判断也是跨时钟域的,我们首先需要解决的就是如何进行异步FIFO空满的判断。
对于异步FIFO 而言,我们用wr_num和rd_num(对应同步FIFO中的fifo_num)作为读写时钟域各自维护的一套数据计数器。wr_num作为FIFO写满的判断依据,rd_num作为FIFO读空的判断依据。为了得到wr_num,写地址wr_ptr_exp与其处于同一时钟域(写时钟域),然后,读地址rd_ptr_exp则需要从读时钟域同步到写时钟域才能使用,若没有同步,wr_num则会出现亚稳态,从而影响full和almost_full的指示信号,造成数据的丢失。同理,对于rd_num来讲,我们需要将写地址同步到读时钟域来进行rd_num的计算。
- “写满”的判断:需要将读指针同步到写时钟域,再与写指针判断
- “读空”的判断:需要将写指针同步到读时钟域,再与读指针判断
1.2.1跨时钟域:读慢写快 、 读快写慢
- 判断写满:(虚满:因为实际读地址>=同步后的地址)
(1)读慢写快:读地址同步到写时钟域后(快时钟采样慢时钟信号),经过两级触发器的时间消耗,实际的读地址一定是大于等于同步到写时钟域之后的读地址(用于wr_num计算,判断FIFO是否读满),此时若wr_num判断FIFO写满(实际写指针未超过读指针一圈),即满非真满。可以想象一下,假设一个深度为100的FIFO,在写到第98个数据的时候就报了“写满”,会引起什么后果?答案是不会造成功能错误,只会造成性能损失(2%),大不了FIFO的深度我少用一点点就是的。只会造成性能损失。
- 判断读空:(虚空:实际写地址>=同步后的地址)
(1)读快写慢:同理,写地址同步到读时钟域后(快时钟采样慢时钟信号),实际的写地址一定是大于等于同步到读时钟域之后的写地址(用于rd_num计算,判断FIFO是否读空),此时若rd_num判断FIFO读空(实际读指针未赶上写指针),即空非真空。可以想象一下,假设某个FIFO,在读到还剩2个数据的时候就报了“读空”,会引起什么后果?答案是不会造成功能错误,只会造成性能损失(2%),大不了我先不读了,等数据多了再读就是的。
上面两种情况都是慢时钟域信号同步到快时钟域,我们采取打两拍可以正常进行FIFO功能,但是对于快同步到慢是否会有问题,即快时钟域的信号同步到慢时钟域造成的漏采 ?
- 判断写满: (虚满:漏掉读指针,对于写满来说,实际读指针跑到了前面)
(2)读快写慢: 进行写满判断的时候需要将读指针同步到写时钟域,因为读快写慢,所以当写时钟同步读指针的时候,必然会漏掉一部分读指针,我们不用关心那到底会漏掉哪些读指针,我们在乎的是漏掉的指针会对FIFO的写满产生影响吗?比如读指针从0读到10,期间写时钟域只同步捕捉到了3、5、8这三个读指针而漏掉了其他指针。当同步到8这个读指针时,真实的读指针可能已经读到10 ,相当于在写时钟域还没来得及觉察的情况下,读时钟域可能从FIFO读了数据出来,这样在判断它是不是满的时候会出现不是真正满的情况,漏掉的指针也没有对FIFO的逻辑操作产生影响。
- 判断读空:(虚空:漏掉写指针,对于读空来说。实际的写指针跑到了前面)
(2)读慢写快: 进行读空判断的时候需要将写指针同步到读指针 ,因为读慢写快,所以当读时钟同步写指针的时候,必然会漏掉一