异步FIFO原理



一,FIFO概念及用途


FIFO即英文First In First Out 的缩写,是一种先进先出的数据缓存器,与普通存储器的区别是没有外部读写地址线,这样使用起来非常简单,但缺点就是只能顺序写入数据,顺序的读出数据,其数据地址由内部读写指针自动加1完成,不能像普通存储器那样可以由地址线决定读取或写入某个指定的地址。按读写是否为相同时钟域分为同步和异步FIFO,这里主要介绍异步FIFO,主要用于跨时钟域传输数据。


二,FIFO的常见参数


宽度:THE WIDTH,FIFO一次读写操作的数据位,


深度:THE DEEPTH,FIFO可以存储多少个N位的数据(如果宽度为N)。


满标志:FIFO已满或将要满时由FIFO的状态电路送出的一个信号,以阻止FIFO的写操作继续向FIFO中写数据而造成溢出(overflow)。


  空标志:FIFO已空或将要空时由FIFO的状态电路送出的一个信号,以阻止FIFO的读操作继续从FIFO中读出数据而造成无效数据的读出(underflow)。


  读时钟:读操作所遵循的时钟,在每个时钟沿来临时读数据。


  写时钟:写操作所遵循的时钟,在每个时钟沿来临时写数据。


  读指针:指向下一个读出地址,读完后自动加1。


  写指针:指向下一个要写入的地址的,写完自动加1。


读写指针其实就是读写的地址,只不过这个地址不能任意选择,而是连续的。


三,FIFO的关键:读写指针和空满标志


1,当读写指针相等时,表明FIFO为空:


swift gcd异步 异步fifo是什么_swift gcd异步


2,当写指针转了一圈又追上了读指针,当读写指针再次相等时,表明FIFO为满:

swift gcd异步 异步fifo是什么_数据_02

所以空满都是读写指针相等,如何区分呢?对于二进制数来说,解决方法就是读写指针的位宽分别增加一个bit,当最高位相同,其余位相同认为是读空;当最高位不同,其余位相同认为是写满。但是这里会引入一个新的问题,就是读写指针位于不同的时钟域,二者需要同步后才可以比较,同步的过程有两个:

(1)将写时钟域的写指针同步到读时钟域,将同步后的写指针与读时钟域的读指针进行比较产生读空信号;

(2)将读时钟域的读指针同步到写时钟域,将同步后的读指针与写时钟域的写指针进行比较产生写满信号;

异步FIFO的写指针和读指针分属不同时钟域,这样指针在进行同步过程中很容易出错,比如写指针在从0111到1000跳变时4位同时改变,这样读时钟在进行写指针同步后得到的写指针可能是0000-1111的某个值,一共有2^4个可能的情况,而这些都是不可控制的,并不能确定会出现哪个值,那出错的概率非常大,怎么办呢?到了格雷码发挥作用的时候了,而格雷码的编码特点是相邻位每次只有 1 位发生变化, 这样在进行指针同步的时候,只有两种可能出现的情况:1.指针同步正确,正是我们所要的;2.指针同步出错。举例假设格雷码写指针从000->001,将写指针同步到读时钟域同步出错,出错的结果只可能是000->000,因为相邻位的格雷码每次只有一位变化,这个出错结果实际上也就是写指针没有跳变保持不变,那么这个错误会不会导致读空判断出错?答案是不会,最多是让空标志在FIFO不是真正空的时候产生,而不会出现空读的情形。所以gray码保证的是同步后的读写指针即使在出错的情形下依然能够保证FIFO功能的正确性。

四,格雷码

swift gcd异步 异步fifo是什么_swift gcd异步_03

(1)二进制码转换成格雷码,其法则是保留二进制码的最高位作为格雷码的最高位,而次高位格雷码为二进制码的高位与次高位相异或,而格雷码其余各位与次高位的求法相类似。

swift gcd异步 异步fifo是什么_时钟周期_04

(2)格雷码转换成二进制码,其法则是保留格雷码的最高位作为自然二进制码的最高位,而次高位自然二进制码为高位自然二进制码与次高位格雷码相异或,而自然二进制码的其余各位与次高位自然二进制码的求法相类似。

swift gcd异步 异步fifo是什么_写数据_05

使用gray码同时也带来另一个问题,即在格雷码域如何判断空与满。对于“空”的判断依然依据二者完全相等;而对于“满”的判断,如下图,由于gray码除了最高位外,具有镜像对称的特点,当读指针指向7,写指针指向8时,除了最高位,其余位皆相同,不能说它为满。因此不能单纯的只检测最高位了,在gray码上判断为满必须同时满足以下3条:

(1)读指针和写指针的最高位不相等

(2)读指针和写指针的次高位也不相等

(3)剩下的其余位完全相等。如下图位置7和位置15,转化为二进制对应的是0111和1111

swift gcd异步 异步fifo是什么_swift gcd异步_06

五,补充问题:由于设计的时候读写指针用了至少两级寄存器同步,同步会消耗至少两个时钟周期,势必会使得判断空或满有所延迟,这会不会导致设计出错呢?
异步FIFO通过比较读写指针进行空满判断,但是读写指针属于不同的时钟域,所以在比较之前需要先将读写指针进行同步处理,将写指针同步到读时钟域再和读指针比较进行FIFO空状态判断,因为在同步写指针时需要时间,而在这个同步的时间内有可能还会写入新的数据,因此同步后的写指针一定是小于或者等于当前实际的写指针,所以此时判断FIFO为空不一定是真空,这样更加保守,一定不会出现空读的情况,虽然会影响FIFO的性能,但是并不会出错。同理将读指针同步到写时钟域再和写指针比较进行FIFO满状态判断,同步后的读指针一定是小于或者等于当前的读指针,所以此时判断FIFO为满不一定是真满,也不会出现满写的情况。所以FIFO空之后不能继续读取,FIFO满之后不能继续写入的原则依然可以得到保证。总结来说异步逻辑转到同步逻辑不可避免需要额外的时钟开销,这会导致满空趋于保守,但是保守并不等于错误,这么写会稍微有性能损失,但是不会出错。

六,FIFO功能点简单总结

  1. 同时读写,读写数据正确检查
  2. FIFO满标志位检查
  3. FIFO空标志位检查
  4. 写过程中发生写复位,写数据和FIFO满标志位被清空
  5. 读过程中发生读复位,读数据和FIFO空标志位被清空
  6. 读写时钟相位相同,异步FIFO能正常工作
  7. 读写时钟相位不同,异步FIFO能正常工作
  8. 写时钟等于读时钟,异步FIFO能正常工作
  9. 写时钟快于读时钟,异步FIFO能正常工作
  10. 写时钟慢于读时种,异步FIFO能正常工作
  11. 写过程中发生写复位以后,异步FIFO能继续正常工作
  12. 读过程中发生读复位以后,异步FIFO能继续正常工作
  13. FIFO满以后,继续往FIFO写数据,异步FIFO不会被卡死,数据被读走以后,异步FIFO能继续正常工作
  14. FIFO空以后,继续从FIFO读数据,异步FIFO不会被卡死。继续往FIFO写数据,异步FIFO能继续正常工作