zoukankan      html  css  js  c++  java
  • 异步-同步-fifo

      异步fifo、格雷码以及空满判断

      一直以来都有两个做法,第一个是多bit信号利用异步fifo或者ram做跨时钟域同步,还有一个就是利用格雷码。

      实际上有些异步fifo就是用的ram+格雷码实现的,因为fifo的读写指针是递增的。当然也有些fifo没用格雷码,这是后话。我们先看看异步FIFO不用格雷码的一般实现。

      首先,读取的时候要判断FIFO是不是空了,所以读取的时候要把写入指针同步到读时钟域下,与读指针比较。写入正好反过来,为了判断是否已满,需要把读时钟同步到写时钟域下进行比较。

      一般来说,这个指针同步也是要消耗时钟周期的,最简单的两级同步也要消耗两个周期(Xilinx的用Block ram实现的双口FIFO核是可以选择同步周期的,最短2,选上Safety Circuit是为了控制信号经过同步寄存器寄存),那么很有可能我们同步得到的指针拿来比较的时候,和当前时间的真实指针有差值。举个例子,读取地址为5,现在要写入,那么我们同步读取地址过来是5,当我们拿5和写入指针比较的时候,真实的读取可能已经到7了,所以就有可能出现假满和假空。假满出现时,FIFO仍然有写入空间,假空出现时,FIFO内部仍有数据。这样相当于降低了FIFO的容量,也会降低读写的效率。

      假如我们考虑异步时钟两边频率相差较大的话,事情会更加复杂。假如写入频率是读取的10倍,那么读取指针同步到写时钟域问题不大,不可能出现假满,但是把写指针同步到读时钟域就有很大可能出现假空,而且空很多。

      解决假空和假满的思路也很简单,我反过来同步不就行了?不行,这样会出现读写溢出

      这里还要提一下地址的编码,假如有16位深度,我们可以用5位作为读写指针的编码,当5位全部一致,证明读追上了写,空。当最高位不同,其它四位一样,证明写追上了读,满。当然,以前学数据结构的时候用的是 读+1=写 则读空,写+1=读 则写满,这样也可以。

      两级同步除了会出现假空假满,还可以解释一个问题就是为什么fifo的Empty和Full的消失不是立刻的,而是有数个周期延迟。当我们判断读写指针完全一致时,认为读空,此时如果写指针增加,写入新的数据,那么我们会等待至少2(具体取决于几级同步)个周期才会判断读写指针不同从而撤销Empty信号,Full同理不在赘述。

      那么用上格雷码有什么好处呢?

      用上格雷码编码可以解释为什么FIFO深度都是2的幂级数,以及解决普通FIFO地址指针同步时出现亚稳态的问题。

      但是当FIFO同时读写时,还是会出现提前读空和写满的情况。

      下面首先说格雷码和FIFO深度,格雷码相邻两个码元之间只有一个跳变。以下是原文引用,总结一下就是格雷码编码的机制导致了深度为2的次幂的FIFO是最合适的。

    The second fact to remember about a Gray code counter is that most useful Gray code counters must have power-of-2 counts in the sequence. It is possible to make a Gray code counter that counts an even number of sequences but conversions to and from these sequences are generally not as simple to do as the standard Gray code. Also note that there are no odd-count-length Gray code sequences so one cannot make a 23-deep Gray code. This means that the technique described in this paper is used to make a FIFO that is 2n deep.”

      而最开始讲的普通FIFO,在异步读写时,同步读写指针就很有可能出现亚稳态,因为相邻两个地址的跳变有可能在所有位上产生。如果出现亚稳态,那么得到的地址就很有可能出现逻辑错误(即使我们已经通过两级同步把亚稳态传递的几率降到极低),毕竟亚稳态的恢复结果是随机的。而我们使用格雷码,相邻地址跳变只有一位(也不准确,因为我们用的并非真正的格雷码,而是为了迁就空满判断规则而制作的格雷码改),即使出现亚稳态,最坏情况也就是同步到了前一时刻的地址,结果无非就是提前判空或者满。

      那么改良格雷码是什么呢?

      前面说过我们判断读空和写满是依照最高位,但是对于格雷码,我们判断写满就不能这样用。读空很好理解,对于8位深度的FIFO,4位地址完全一致则是读空,而我们考察写满则会发现问题。

      可以看到,如果我们照搬之前的法则,MSB(Most Significant Bit)不一致,后面一致,那么我们会发现,10和5,7和8,0和15(序号相加等于15的)等等都是满的标识,明显与实际情况不符合。那么我们就需要改一下格雷码的编码,变成右边那种,那么观察一下就会发现,如果MSB和次高位都不一样,其他低位都一样,那么就写满了,这样我们就正常了。不过也就带来了一个问题,从0100跳变道1000和1100跳变到0000就一次变了两位,我们就有可能出现逻辑错误

       如果对指针进行了采样并且在两个时钟域之间使用了握手控制信号来安全地传递采样的二进制计数值,也可以可以使用二进制指针进行FIFO设计。

        使用二进制编码深度就变得灵活,而且只是多了4个寄存器(给握手信号用的,Ready和Acknowledge各两个)

        几乎空和几乎满也很容易实现(读写地址直接做减法)

        但是握手周期延迟就高了,那么空满状态的清除就更慢了。

      同步FIFO很简单了,直接将FIFO读写分为三个状态,读,写,读写同步。设置一个计数器,读递减,写递增,同时则不变,计数到了给出对应空满信号。

      除此之外还有一种异步FIFO设计,作者在第二种里面用了两位来做空满和方向判断,用了更少的FF实现,具体细节我有时间再补充。

  • 相关阅读:
    http://www.jdon.com/jivejdon/thread/37340
    我的英语死在类似的问题上
    Linux之read命令使用
    SIP注册呼叫流程简介
    sh里的变量 $0 $1 $$ $#
    LTE 逻辑分层和接口协议
    LTE语音业务VOLTE
    shell编程——if语句 if z n f eq ne lt
    高通QXDM抓modem log
    LTE与VOLTE基础知识
  • 原文地址:https://www.cnblogs.com/aliothx/p/13527371.html
Copyright © 2011-2022 走看看