代码来自asic world 和paper“ Simulation and Synthesis Techniques for Asynchronous FIFO Design”,文章解说均为自己的理解,如果有错误欢迎纠正~
What is FIFO?
FIFO 是一个满足“先进先出”的储存数据的结构,如果我以“A->B->C”的顺序存入数据,由于我先存入的C,那么我先读取的内容依然是C,最后读取到A。
Introduction:
异步fifo可以满足不同时钟域的数据读写问题,在fpga等时钟不止一个的系统里,当数据从(faster domain)快时钟域传递到慢的时钟域时(slow domain),需要fifo来满足数据的降频率读。所以异步fifo的设计非常重要。
对于同步FIFO(FIFO的读和写都发生于同一个时钟沿0。用一个counter计算写入的数量:递增(FIFO仅写入),递减(FIFO仅读)或保持(不写入和读取,或同时写入和读取操作)。当FIFO计数器达到预定的满值时,将FIFO的信号置为“满”,当FIFO计数器为零时FIFO为空。由于读和写都发生在相同的时钟,所以可以当作普通的储存器使用。
对于异步FIFO设计,则不能使用递增 - 递减FIFO计数器,因为它需要两个不同的异步时钟来控制计数器。要确定异步FIFO设计的满和空状态,必须比较写和读指针。
Principle:
要想理解FIFO设计,需先了解FIFO指针的工作原理。写指针总是指向要写入的下一个字;因此,在复位时,读写指针都清零,这也恰好是要写入的下一个FIFO字位置。在FIFO写操作中,写指针所指向的存储单元被写入,然后写指针递增以指向要写入的下一个位置。 类似地,读指针总是指向要读取的当前FIFO字。再次复位时,两个指针都复位为零,FIFO为空,读指针指向无效数据(因为FIFO为空,空标志置位)。一旦第一个数据字写入FIFO,写指针就会递增,空标志被清除,此时正在寻址第一个FIFO存储字内容的读指针会立即将第一个有效字传到FIFO的数据输出端口,由接收器逻辑读取。
但是,当读指针和写指针都相等时,FIFO有可能为空,也有可能为满:当两个指针在复位操作期间被复位为零时,或者当读指针赶上写指针时,读取了FIFO中的最后一个字,fifo空。当写指针写了一圈并再次赶上读指针,与其相等时,fifo为满。
这里介绍了两种常见的异步fifo设计方法。第一种的代码比较简单,第二种的综合出的电路更加安全。
The key topic here is figuring out the full and empty status of Asyn FIFO
设计理念一:
如何判断fifo的满和空:
Using least significant bits as an extra mark:
用最左边的位来区分满和空:当读指针读到最后一位,且马上追上写指针时,将“预设空”变量设为1。 当写指针写到最后一位,且马上追上读指针时,写指针已经多跑了一圈了,将“预设满”变量设为1。原理如下图:
如果写指针指向“1000”,读指针指向“0000”,此时写指针最高位“1”和读指针次高位“0”不同,写指针次高位“0”和读指针最高位“0”相同时,写指针马上追上读指针,即将达到fifio“预设满”状态。反之如果读指针此时为1000, 写指针此时为0000, 那么读指针即将追上写指针,fifo内容马上被读完,此时将“预设空”变量设为1。实现代码如下: