首页 > 编程知识 正文

fifo 格雷码,异步fifo 格雷码

时间:2023-05-04 19:13:24 阅读:276629 作者:3491

异步FIFO:为什么要用格雷码

对于异步FIFO,一个最最基本的要求就是:满了不能写,空了不能读。为了满足这两条要求(实际上是同一类),对于跨时钟域问题,必须做保守判断。

即读指针在不断追赶写指针的时候,对于读时钟域,必须保证此时获取的写指针比真实的写指针要慢,比如读指针为3,获取的写指针为5,但是实际的写指针已经到8了,这样读指针到5的时候就会停下来,这么做是安全的。

对于写指针来说,也是一个追赶读时钟的过程,只不过多绕一圈而已。
之前在学习FIFO的时候,看到了坛子上这样的一个问题:异步FIFO读时钟是写时钟的100倍,或者写是读的100倍会出现什么问题?
帖子讨论很热烈,都19年了还有人在跟帖。

CSDN上也有人写了这方面的博客,说会出问题。真的会出问题吗,那差异到多少会出问题呢?99倍?98倍?……那10倍会不会出问题?
会不会在这当中,有个“度”的存在,大于它就有问题,小于它就没有?
那么多的教科书上都没说。既然没有说,就应该不会有问题,否则这个设计是失败的。

在看到这个问题之前,我一直都有个疑惑:异步FIFO为什么要使用格雷码?
我知道格雷码比二进制码更安全,因为它变动的次数更少,每次只会变动一位,减小了亚稳态发生的概率。但是,难道这样就不会出一点问题了么?如果在跨时钟DFF输入端的setup time内有两位以上的变化,这不就跟二进制的没有区别了吗?

比如,从0000变到0011,有两位的变动,如果这两位的变动刚好处在Setup time内,那么它们的值是随机的,有可能出现0010这样超前了的值,是不安全的。
如果会出现一丁点的问题,这样的方法就是不能用在电路里面的,需要用更安全的握手协议,当然,握手协议的转换数据速度要低一些,这是安全换来的代价。
跨时钟域问题的最有保障的方法是使用握手协议,而FIFO没有用。为什么?
看到了论坛下一个评论后,恍然大悟。

问题的关键在于在同一个setup time内不可能出现两位以上的变化。
也就是,格雷码的关键不在于发生亚稳态的概率小了,而在于——即使发生了亚稳态,也没问题。
写模块和读模块是在同一个芯片上的,用的是同样的触发器,既然快时钟域的时序满足:
Tclock-to-q+Tcomb+Tsetup<Tperiod
(这里的Tcomb至少是一个mux和一个binary-to-gray转换器的组合路径延时加上线延时)
那么,在慢时钟域,如果这一次的transition发生了亚稳态问题,一定有:
Tlast_change≈Tperiod>>Tsetup
即上一次变化的那位一定是满足Setup time的!

也就是说,使用了格雷码之后,在慢时钟域,产生亚稳态问题的只可能有一位,这一位是随机的,但不管这一位是0还是1,要么是变化后的值,要么是变化前的值,这两个值都是历史上出现过的!然后这个信号再经过两级的同步触发器,达到判断空满标志的模块中,此时,也许我们的快时钟域的指针还在不断向前奔波,但我们要的就是保守判断,只要够保守,就不会有问题。
这也正是格雷码设计的初衷——不会检测到中间态,如果是二进制,从0111到1000,当发生了亚稳态的时候,有可能会经过既不是0111又不是1000的中间态,这个中间态有可能会超前,也有可能滞后,总之不是我们想要的,都有可能会引起问题。

那么华为的面试题究竟想问什么?
我觉得,要么跟后端的wire delay有关系(不过这也是能通过设计搞定的,线延迟的差距只要不是太离谱就行),要么跟数据传输的效率有关系,比如有人提到的分级传输。涉及到经验方面,不是我们初学者能考虑的,不管结论如何,对于我这种初学者,要感谢这个题引发的讨论和思考。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。