| |
面试官在问异步FIFO问题之前,总是会问一个问题做铺垫:
跨时钟域数据传输时的基本方法为:两级或多级D触发器、异步FIFO、握手信号(如果有同学对这几个点不清楚需要好好做功课了,后续公众号也会为大家进行分析)。当你下意识答出这三点的时候,恭喜你,你已经进入了面试官的套路了。面试官下一个问题:
请讲讲什么是异步FIFO?
异步FIFO是指一个FIFO设计,其中数据值从一个时钟域写入FIFO缓冲区,同时数据值从另一个时钟域的相同FIFO缓冲区中读取,其中两个时钟域彼此异步,简而言之,就是FIFO的读、写时钟域不同。
与异步FIFO相对的是同步FIFO,顾名思义,FIFO缓冲器的写入和读取在同一时钟域中进行。
为了理解FIFO设计,我们需要了解FIFO指针的工作原理。FIFO中的指针分为写指针和读指针,写指针总是指向要写入的下一个字。在复位时,两个指针都设置为零,这也恰好是要写入的下一个FIFO字位置。在FIFO写操作中,写指针所指向的存储单元被写入,然后写指针递增并指向要写入的下一个位置。
类似地,读指针总是指向要读取的当前FIFO字。在复位时,两个指针都复位为零,FIFO为空,读指针指向无效数据(因为FIFO为空,空标志置位)。一旦第一个数据字写入FIFO,写指针递增,空标志就会清零,但是读指针仍指向第一个FIFO存储字内容,与此同时将第一个有效字驱动到FIFO的数据输出端口,由接收器逻辑读取。读指针始终指向要读取的下一个FIFO字的事实意味着接收器逻辑不必使用两个时钟周期来读取数据字。
当读指针和写指针都相等时,FIFO为empty。这种情形出现在复位操作期读写指针复位为零时,或者当读指针赶上写指针时,此时读取FIFO中的最后一个字。
当指针再次相等时,即当写指针已回环一圈(指到达地址边界后,从起始位开始递增)并追赶到读指针时,FIFO处于full状态。
这时核心问题来了,当指针相等时,FIFO是到底empty的还是full的?
一种用于区分full和empty的设计方法是为每个指针添加一个额外的位。当写指针超过最后的FIFO地址时,写指针将使未使用的MSB(Most Significant Bit的缩写,指最高有效位)递增,同时将其余的位设置为零,如图1所示(FIFO已经回环并翻转指针的MSB位)。
图1 空满状态判别
读指针的操作与此类似,如果两个指针的MSB不同,则意味着写指针已经发生了回环。如果两个指针的MSB相同,则意味着两个指针都回环了相同的次数。
使用n位指针,其中(n-1)是访问整个FIFO存储器缓冲区所需的地址位数,将写时钟域的写指针同步到读时钟域,当两个指针(包括MSB)相等时,FIFO为空。 将读时钟域的读指针同步到写时钟域,当两个指针(MSB除外)相等时,FIFO就会满(面试陷阱:请各位童鞋思考为什么是这样,反之是否可以)。
尝试将二进制指针值从一个时钟域同步到另一个时钟域是有问题的,因为n位指针的每个位可以同时改变。例如,二进制数中的7-> 8是0111->1000,所有位都改变了,实际中可能出现的情形有16种,即0111-> 1000的变化可能出现0111-> 1001、0111->1011等(请童鞋们思考原因哦,这是Cisco 19年的面试题)。
为了解决亚稳态问题引起指针同步异常,引入了格雷码。
图2 Gray码变化图
回到之前二进制数中的7-> 8变化的例子,二进制数变化为0111->1000,此时使用了格雷码的变化是0100->1100,即只有最高位发生了变化。使用了格雷码后的递增变化可能的情形有2种,即0100->1100或0100->0100,异常情形为0100->0100。异常情形为指针未发生正常跳变,带来的影响为判断空满状态时出现了“假空”或者“假满”。
假设写指针为为7->8跳转,读指针为6->7跳转。写指针由于异常情形出现了7->7的跳转,将写指针同步到读时钟域,读写指针都指向7,出现了“假空”。“假满”与之类似,不再赘述。“假空”和“假满”的出现降低了FIFO的性能,但是避免了亚稳态的问题,是可以接受的。
课后思考题:如果读时钟域速度较快、写时钟域速度较慢(或者写、读时钟域速度相差较大)会出现什么情况?(19华为面试题)