在做集创赛项目时使用到了异步fifo,查找了很久才发现了漏数据的问题,因此再次补习了一下异步FIFO知识。
1.同步FIFO和异步FIFO
FIFO作为数字电路中的常客经常用于数据的缓冲存储(当然也是面试笔试中的常考问题)。对于同步FIFIO,主要是实现速率匹配,起到数据缓冲的作用。对于异步FIFO,主要是实现不同时钟域之间的数据交互,涉及到指针跨时钟域的问题,处理起来更复杂一些,因此本篇主要讨论异步fifo的问题。
2.为什么需要异步FIFO
如前面所说,在实际的数字电路项目中,往往存在很多个时钟源,不同时钟源的数据需要进行传输互通。如果是单bit数据,可以通过打两拍寄存,展宽等方式进行同步,异步fifo主要解决的是多bit数据的跨时钟传输问题。
3.异步fifo中的读写指针,为什么需要格雷码?
我们都知道fifo中的关键变量是读写指针,读写指针决定了将往fifo中写入或者读出的位置。异步fifo在处理跨时钟信号时,采用的是将读指针和写指针转化为格雷码的形式,这时候一定会有初学者产生疑问:为什么采用格雷码的形式可以有效改善亚稳态的问题?
3.1fifo空满和读写指针的逻辑
要理解采用格雷码的原因,首先要明白fifo的“写满”和“读空”逻辑是怎样生成的。
注意:指针的定义位宽比fifo实际深度会多出一位,例如深度为32的fifo读指针和写指针的位宽都为6位,这样当读写指针的低五位都相同时,可以根据最高位判断写指针究竟是超了读指针一圈还是两者完全相同。
读指针rd_ptr指向fifo读出的地址,写指针wr_ptr则指向下一个讲写入的地址,那就不难理解用指针来判断写满和读空的逻辑:
当读指针等于(追上)写指针时,证明此时fifo已经读空,需要停止继续向外读数,避免一直读0。
当写指针超过读指针一圈赶上读指针时,此时fifo已经写满,需要停止继续写入数据,造出数据丢失。
显然,满和空的关键在于指针比较的判断,在同步fifo中这很容易处理,因为是相同的时钟源只需要直接比较即可。但在异步fifo中,我们需要将读写指针同步到一个时钟源中进行比较。
具体来说,对“读空”的判断要将写指针同步到读时钟域中进行比较,对“写满”的判断要将读指针同步到写时钟域进行比较。这其实也很好理解,同步到另一个时钟域需要打拍消耗时间,以读空举例,在写指针同步的这段时间,实际的写指针可能已经继续向前,所以当同步完成后,同步的写指针一定小于等于实际写时钟域的写指针。这会造成什么情况?由于读指针始终处于读时钟域不需要同步,所以读指针一定采样的是正确的数据;而进行比较的写指针有可能小于真正的写指针,因此存在可能:实际上读指针并没有追上写指针,但在