异步fifo_面试必杀技:异步FIFO(下) CDC的那些事(6)

本文深入探讨了异步FIFO的设计,包括使用Gray Code同步read和write pointer,以及FIFO内存的实现。文章还讨论了在面试中常见的异步FIFO问题,如如何处理假满和假空情况,以及如何设计非2的幂次深度的FIFO。此外,作者提醒在实际工作中应避免自定义2flop synchronizer,而应使用预建的CDC库元件。
摘要由CSDN通过智能技术生成

上一篇老李介绍了异步FIFO的基础部分,包括为什么用Gray Code来同步read pointer, write pointer。这一篇咱们从头一起过一遍异步FIFO的具体设计,然后再讨论几个常见的问题。

有的面试官可能上来让你先画异步FIFO的框图,老李建议大家自己手画一下,能够记住。

9b26b4403715f5a20fa3077455bd779f.png

要注意,wptr和rptr都是gray code,在上一篇我们已经讨论过gray code是可以直接利用2flop synchronizer来同步的。而用来读写实际的memory必须是binary address,在FIFO write control和FIFO read control 里面我们进行binary to gray code的转换。

下面是上图中间fifo memory部分的简单实现

f3002ba481485f9bfce7c8bd8f298ec9.png

上面的code简化了rdata的逻辑,如果使用SRAM,可能需要加一级flop来存储SRAM读出来的值。

这里插一句,在设计异步FIFO或者使用异步FIFO的时候,需要计算清楚FIFO的深度,(如何FIFO的深度计算老李打算以后单独开一篇文章来讨论)然后要比较使用SRAM和flop array的cost。依据老李的经验,目前较新的7nm/5nm的工艺下,当存储位大于2k bit,使用vendor的compile memory在面积上开始划算起来,低于2k bit,使用flop array划算。这个部分需要大家在实际工作中自己去比较计算。

b5310f7ec67a4fa756bdadb6c4cbdef1.png

关于read pointer和write pointer 的同步很简单,用2flop synchronizer即可,老李这里要强调一下,大家在实际工作中不要自作聪明去用verilog的behaivor code去实现2flop syncronzier(上面注释掉的行),而是要直接例化现成的cdc库元件。只要你不是在创立不到一个月的创业公司,这种cdc library一定是你们公司已经有的,轮子已经造出来了,千万别自己再造。

下面我们再看一下write control部分的RTL实现。

aafc931a98450429e2b8ab2f9815738f.png

这里的满的判断用到了我们上一篇讲的判断逻辑,即高两位相反,低位都相同。下面是read side判断空的逻辑。

7c8014b84c2dc23ea999e1e75079c243.png

下面我们来讨论几个面试中常见的问题。

问题:假设wclk速度比rclk快,那么当raddr+1,再同步到wclk后,如果这期间有了push操作,那会不会使得wptr超过了rptr,造成FIFO overflow呢?

回答:不会,当rptr在传过去之前,如果wptr已经追上了rptr-1,那么wfull已经是1了,FIFO是不允许在FIFO 满的时候进行push操作的(在实际工程中我们通常要利用assertion来check保证在wfull为1的时候push不能为1)。而如果这个时候有了pop操作,raddr+1,这个时候实际上FIFO有了一个free entry,但是push这一侧看到的FIFO依然是满的。这就是我们所说的异步FIFO的假满。相应的,FIFO的empty为1时,也可能FIFO此时有个push操作,导致FIFO为假空。假空和假满并不会影响FIFO的正确性,无非就是早一点告诉push side停止push,或者早一点告诉pop side停止pop,但是FIFO是不会产生overflow和underflow的。如果要说有什么缺点的话,就是在性能上有一些损失,当FIFO的深度很大的时候,这通常不是什么问题。

问题:如何判断FIFO是真空/真满呢?

回答:判断假空假满刚好相反,在push side我们来判断空,在pop side来判断满,为什么要这样留给大家自己思考。

问题:设计一个depth=1的异步FIFO

回答:这个大家就是要活学活用了,不能死板套用。只需要考虑一个问题,只有1个entry,那么需要几位的address 或者pointer呢?当然是1位就够了,那我们真的还需要一个pointer吗?因为只有一个entry,当一次push,FIFO就满了,一次pop,FIFO就空了。1个bit用来表示满和空就足够了。其实这样的FIFO我们已经见过了,老李在多bit信号跨时钟域怎么办?-- CDC的那些事(4)里面讲到的带反馈的asynchronous load其实就是depth=1的异步FIFO!

问题:如何设计depth不是2的幂次的异步FIFO?

回答:我们在上一讲里面看到的gray code,只有当depth=2的幂次个数的时候,才能做到wrap around时继续保持gray code的性质:即连续两个码之间只有1位不同。下面这个图是表示depth=8的时候我们利用16个gray code来表示pointer。

fc37b596a7a007c4e03906d281b30cd3.png

比如从4‘d15到4’d0,也只有1位不同。但是如果不是2的幂次,比如DEPTH=7,那我们怎么样来利用Gray code呢?直接从4'b0000到4'b0101肯定是不行的,因为4'b0101变到4'b0000有两个bit发生了变化,这样我们就没法利用2flop synchronizer来同步了。解决这个办法的诀窍其实就是老李上一篇提到的gray code的第二个性质:gray code每一位是有个对称轴的。我们可以这样编码,addr==0的时候gray code不从4'b0000开始,而是从4‘b0001开始,直到4’b1001来wrap around,这样从4'b1001->4'b0001依然只有一个bit翻转。同理,如果是depth=6,那么我们继续往里收缩1位,只利用gray code关于对称轴两侧的部分编码,从4'b0011到4'b1011,我们可以看到,这样的编码依然可以保证相邻两个码之间只会有1位变化。

54625e71e8ea99acd88af98f04b37e72.png

注意,利用这种编码,FIFO的满判断逻辑就不是简单的高两位取反,低位相同了,比如depth=7, rd_ptr=4'b0001, wr_ptr=4'b1100表示7个entry已经满了,如何得出正确的满判断逻辑就交给大家思考吧,欢迎大家在评论区留言讨论。

下一篇老李会带大家过一下工业界最常用的CDC tool Spyglass CDC的基本介绍,同时会奉上一些工程经验总结,敬请期待。

如果你觉得这篇文章对你有所帮助,不妨点个右下角的“在看”,最好能够分享到群里或者朋友圈,你的支持就是老李更新的动力!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值