你真的理解异步FIFO读写中的空满现象吗?
一、前言
我们的都知道FIFO中有两个特别重要的信号,那就是空满信号。在异步FIFO中,空满信号的判断要比同步FIFO稍微复杂一些,因为它的地址使用的是格雷码。具体如何判断空满可以参考之前的一篇文章:手写异步FIFO。
看完之后可能你会觉得也没那么复杂,其实如果只是单纯的写一个异步FIFO,那么会按照文章中介绍的方法进行判断就够了。但是这里面还有一些问题需要注意:那就是假空和假满现象,以及为什么要在写时钟域进行判满操作,在读时钟域进行判空操作。
二、假空假满现象
无论是wclk和rclk谁快谁慢,都可能产生假空假满现象,但是情况稍有不同,因此下面我们分两种情况进行讨论。需要注意的是,之所以会产生假空假满现象,主要是因为wptr和rptr的同步问题导致的。因为无论是将wptr同步到rclk时钟域还是将rptr同步到wclk时钟域都有一定的延迟。
1、假设wclk比rclk快
- 假满现象:当wclk比较快时,rptr很快就能同步到wclk时钟域,在同步过程中认为不会再有读数据的操作。但是如果同步的这个rptr刚好是FIFO满之后变化的新值,也即FIFO满后又有了读数据操作,此时FIFO已经不满了;那么由于在rptr同步过来之前的这段时间,wclk时钟域的rptr的值仍然是上一次同步过来的,也就是符合满条件的值,此时就会出现假满现象!
- 假空现象:当rclk比较慢时,在wptr同步到rclk时钟域之前,可能又会有写数据的操作。如果同步的这个wptr刚好符合空条件,那么在wptr同步过来之后就会判断为空。在将wptr同步过来之前的这段时间里,由于又有了写操作,wptr其实已经变化了,此时FIFO是不空的,此时就出现了假空现象!
2、假设wclk比rclk慢
- 假满现象:当wclk比较慢时,在rptr同步到wclk时钟域之前,可能又会有读数据的操作。如果同步的这个rptr刚好符合FIFO满条件,那么在rptr同步过来之后就会判断为满。在将rptr同步过来之前的这段时间里,由于又有了读操作,rptr其实已经变化了,此时FIFO是不满的,此时就出现了假满现象!
- 假空现象:当rclk比较快时,wptr很快就能同步到rclk时钟域,在同步过程中认为不会再有写数据的操作。但是如果同步的这个wptr刚好是FIFO空之后变化的新值,也即FIFO空后又有了写数据操作,此时FIFO已经不空了;那么由于在wptr同步过来之前的这段时间,rclk时钟域的wptr的值仍然是上一次同步过来的,也就是符合空条件的值,此时就会出现假空现象!
其实假空假满都不影响FIFO正常工作,最多只是影响其性能。因为假满就是提前告诉了写数据端不要再写数据了,由于这段时间不能写数据,所以wptr不变,当过一会rptr同步过来时,再由wptr和rptr判断的结果就是FIFO不满了,就又可以写数据了。而假空也只是告诉读数据端不要再读数据了,由于这段时间不能读数据,所以rptr不变,当过一会wptr同步过来时,再由wptr和rptr判断的结果就是FIFO不空了,就又可以读数据了。
有可能你会有疑问,这不是好多情况都没有讨论到吗?但其实你把其他情况都考虑进去你会发现,都是一些正常状态,并且最后都会到达假空或者假满状态。
三、为什么在wclk时钟域判断是否满,而在rclk时钟域判断是否空?
对于这个问题,我们可以按以下的思路去考虑:
1、如果在wclk时钟域判空:
- 当wclk比较快时,rptr很快就能同步到wclk时钟域,在同步过程中认为不会再有读数据的操作。但是由于rptr同步过来仍然是需要时间的,如果被同步的rptr刚好是一个符合空条件的值,那么在同步过来之前这段时间内,rptr仍然是上一个符合非空条件的值。也就是说此时FIFO实际上已经空了,但是还是会报非空,这就会影响FIFO的正常工作了!
- 当wclk比较慢时,在rptr同步到wclk时钟域之前,可能又会有读数据的操作。如果同步的这个rptr不符合FIFO空条件,那么在rptr同步过来之后就会判断为非空。然而在将rptr同步过来之前的这段时间里,由于又有了读操作,rptr其实已经变化了,此时FIFO有可能是空的。也就是说此时FIFO实际上已经空了,但是还是会报非空,这就会影响FIFO的正常工作了。
2、如果在rclk时钟域判满:
- 当rclk比较快时,wptr很快就能同步到rclk时钟域,在同步过程中认为不会再有写数据的操作。但是由于wptr同步过来仍然是需要时间的,如果被同步的rptr刚好是一个符合满条件的值,那么在同步过来之前这段时间内,wptr仍然是上一个符合非满条件的值。也就是说此时FIFO实际上已经满了,但是还是会报非满,这就会影响FIFO的正常工作了!
- 当rclk比较慢时,在wptr同步到rclk时钟域之前,可能又会有写数据的操作。如果同步的这个wptr不符合FIFO满条件,那么在wptr同步过来之后就会判断为非满。然而在将wptr同步过来之前的这段时间里,由于又有了写操作,wptr其实已经变化了,此时FIFO有可能是满的。也就是说此时FIFO实际上已经满了,但是还是会报非满,这就会影响FIFO的正常工作了。
可以看到,当在wclk时钟域判空或者在rclk时钟域判满时,会出现以上几种影响FIFO正常工作的情况,所以我们是在wclk时钟域判断是否满,而在rclk时钟域判断是否空。
四、假设wclk速度比rclk快,那么当raddr+1,再同步到wclk后,如果这期间有了push操作,那会不会使得wptr超过了rptr,造成FIFO overflow呢?
在raddr + 1传到wclk时钟域之前,wclk端看到的值还是raddr,它有以下可能情况:
- wptr还没有赶上rptr,此时FIFO是非满的,那么如果有push操作是可以正常进行的,并且wptr会加1,等raddr+1同步过来后,仍然是非满状态!
- wptr已经赶上了rptr,那么此时full应该是拉高的,就不会允许push操作,所以wptr也不会加1!等raddr+1同步过来后,wptr又落后于rptr了,此时就会是非满状态!题目中说由于wclk速度快,在同步raddr+1期间又有了push操作,所以wptr与raddr+1对应的rptr对比得出的空满状态才是真的状态,因此在同步过来之前的这段时间里的满状态其实是假满!但是最多只是可以push但没有允许push,也即提前告诉了push端不要写数据了,其实并没有影响FIFO的正常工作!
通过上述两种情况就可以看出,wptr是不会超过rptr的。