• 同步电路与跨时钟域电路设计2——多bit信号的跨时钟域传输(FIFO)


            多个控制信号跨时钟域 仅仅通过简单的同步器 同步有可能是不安全的 。

    例子:传递两个同时需要的信号

    如何传递两个同时需要的信号(b_loadb_en)?

            将 b_loadb_en同步至a_clk时钟域,

            如果 b_loadb_en这两个信号有一个小的skew,

            将导致在 a_clk时钟域中两个信号并不是在同一时刻起作用,与在b_clk中的逻辑关系不 同

    解决方法

            将b_loadb_en信号在b_clk时钟域中合并成一个信号b_lden,然后同步至a_clk中。

     问题:遇到不能合并的情况,怎么办?

    例子:译码信号

    如果bdec[0]bdec[1]间存在 skew将导致同步至a_clk中后 译码错误,出现误码。

             在这种情况下,建议加入另一个控制信号,确保bdec[0]bec[1]稳定时采信号。

            例如,在bdec[0]bec[1]稳定输出后一到两个周期b_clk域输出一个en信号,通知 a_clk域此时可以采bdec[0]bec[1]信号。

            这样可确保正确采样。

    多bit数据流跨时钟域传输

    问题:多bit数据流跨时钟域如何传输?

    数据流和指示信号不同:

    • 数据流大多具有连续性,即背靠背传输;
    • 数据流要求信号具有较快的传输速度;

    解决传输的两个方法:

    1. 两个时钟域通过SRAM来缓冲
    2. 使用FIFO

    同步策略 — FIFO

            FIFO( first in first out )是一种先进先出的储存结构

    FIFO与普通存储器的区别:

            没有外部读写地址线 ,使用简单。

    FIFO缺点:

            只能顺序写入数据,顺序的读出数据,其数据地址 由内部读写指针自动加1完成,不能像普通存储器那 样可以由地址线决定读取或写入某个指定的地址。

    FIFO的应用:

            随着IC的发展,模块与模块之间的通信设计中,多时钟的情况已经不可避免;数据在不同时钟域之间的传输很容易引起亚稳态;异步FIFO就是一种简单、快捷的解决方案。

    FIFO的功能:

             FIFO的功能类似于一个调节上下游水量的一个蓄水池。

    FIFO 的上游结点是FIFO的数据输入端,

            在写信号有效时,数据将被写入FIFO,由FIFO内部的写指针控制,并且在FIFO内部,写指针递增一个单元,同时FIFO的满信号(FIFO fulll Signal)将控制上游结点是否发送数据;

    FIFO的下游节点是FIFO 的数据输出端,

            当读信号有效时,FIFO中的数据将被读出,由FIFO内部的读指针控制,并且在FIFO内部读指针递增一个单元,同时FIFO空信号(FIFO empty Signal)将控制下游节点是否读出数据。

    FIFO内部的空间已经被写满

            如果FIFO内部的空间已经被写满,则实时生成满信号,以反压上游节点,上游节点停止写新的数据进来,否则就会把已经写好的数据冲掉。

    FIFO内部的数据全部被读

            如果FIFO内部的数据全部被读,则实时生成空信号,控制下游节点不再进行数据读操作。否则,下游节点就会将读过的数据重新再读一遍。

    从这里也可以看出,空信号和满信号对于FIFO的控制非常重要。

    FIFO用途:

            FIFO主要用来调节上下游数据的吞吐量。

    用途1:异步FIFO读写分别采用相互异步的不同时钟

            在现代集成电路芯片中,随着设计规模的不断扩大,一个系统中往往含有数个时钟, 多时钟域带来的一个问题就是,如何设计异步时钟之间的接口电路。异步FIFO是这个问题的一种简便、快捷的解决方案,使用异步FIFO可以在两个不同时钟系统之间快速而方便地传输实时数据。

    用途2:对于不同宽度的数据接口也可以用FIFO

            例如,单片机位8位数据输出,而DSP可能是16位数据输入,在单片机与DSP连接时就可以使用FIFO来达到数据匹配的目的。

    FIFO分类:

    FIFO通常来说分为:

    • 同步FIFO:指读时钟和写时钟为同一个时钟,在时钟沿 来临时同时发生读写操作;
    • 异步FIFO:读写时钟不一致,读写时钟是互相独立的,这种结构用途最广。

    FIFO常见参数:

    FIFO的宽度即FIFO一次读写操作的数据位

    FIFO的深度指的是FIFO可以存储多少个N位的数据(如果宽度为N)。FIFO 的深度相当于蓄水池的容量,如果过小,则上游节点总是接收满信号,使得系统的数据吞吐量降低。如果过大,则浪费空间太多。因此,FIFO的深度是一个很关键的参数。

    满标志FIFO已满或将要满时由FIFO的状态电路送出的一个信号,以阻止FIFO的写操作继续向FIFO中写数据而造成溢出(overflow)。

    空标志FIFO已空或将要空时由FIFO的状态电路送出的一个信号,以阻止FIFO的读操作继续从FIFO中读出数据而造成无效数据的读出(underflow)。

    读时钟读操作所遵循的时钟,在每个时钟沿来临时读数据。

    写时钟写操作所遵循的时钟,在每个时钟沿来临时写数据。(在FIFO中,读写两个时钟通常都不相同,而且基本上是异步时钟。)

    FIFO结构:

     双端口SRAM

            用来存储上游节点写入的数据wdata,下游节点用rdata将其读出。

            SRAM的读写地址采用了每次只递增1的机制,保证了写入和读出按顺序进行,写和读到最高地址后,重新返回零地址。

    满信号生成电路

            在上游节点和SRAM之间有一个满信号生成电路。

            这个电路通过判断写时钟域下,写指针和读指针的关系,然后实时生成满信号wfull,以通知上游节点停止写操作。

    空信号生成电路

            在下游节点和SRAM之间有一个空信号生成电路,

            这个电路通过判断读时钟域下,写指针和读指针的关系,然后实时生成空信号rempty,以通知下游节点停止读操作。

    注意:

            将读指针传递到写时钟域才能产生满信号,将写指针传递到读时钟域才能产生空信号,因此,这里就涉及到如何处理信号传输的亚稳态问题。

    FIFO空满状态的判断:

            正确的产生空满标志是任何FIFO设计的关键。

            空满状态产生的原则是:写满而不溢出,能读空而不多读。

    空满状态的判断:

    空状态:

            当读写地址相等时,说明已经写入的数据,已经全部被读走,此时,FIFO还尚未有新的数据写入,说明FIFO为空。

    空状态情况发生:

    • 复位操作时,
    • 当读地址读出FIFO中最后一个字后,追赶上了写地址。

    判断条件: 

            如果两个指针的MSB相同,则说明两个指针折回的次数相等。其余位相等,说明FIFO为空。

    满状态:

            当写地址超过读地址,写到最高地址后,重新从零开始写,再次追上了读地址。此时,读地址已经读过的地址空间,再一次被写地址写入。而读地址到最高地址之间的数据,还尚未被读。说明此时FIFO处于满的状态。

    判断条件:

            如果两个指针的最高有效位MSB不同,说明写指针比读指针多折回了一次;

            如r_addr=0000,而w_addr = 1000,为满。

    区分满状态、空状态方法:

            在地址位中添加一个额外的位(extra bit)。

            当写指针增加并越过最后一个FIFO地址时,就将写指针这个未用的MSB加1,其它位回零.

            对读指针也进行同样的 操作。

            此时,对于深度为2^{n}的FIFO,需要的读/写指针位宽为(n+1)位,

    例子:深度为8的FIFO

            需要采用4bit的计数器, 0000~1000、 1001~1111,

            MSB作为折回标志位,而低3位作为地址指针。

    满状态判断条件:

             如果两个指针的MSB不同,说明写指针比读指针多折回了一 次。

            例子:r_addr=0000,而w_addr = 1000,为满。

    空状态判断条件:

            如果两个指针的MSB相同,则说明两个指针折回的次数相等。 其余位相等,说明FIFO为空。

    空满标志生成的前提:

            读指针被传递到了写时钟域,写指针被传递到了读时钟域。

           如下图电路所示,各自采用两级同步器来对信号进行同步。

    FIFO使用二进制读写指针的问题及解决(格雷码)

            二进制的读写指针位宽通常超过了1bit。

            多bit信号是不可以使用两级同步器的。(比如刚开头的例子)

     解决方法:使用格雷码 

     格雷码的特点:

    1. 格雷码相邻的2个数值之间只会有一位发生变化,其余各位都相 同
    2. 格雷码是一种循环码,0和最大数(2的n次方减1)之间也只有一位不同

             引用格雷码之后,相邻数值只有1位发生翻转,1位翻转所引起的亚稳态的概率远 远要小于几位同时翻转所引起的概率。因此,格雷码能很好的亚稳态出现的概率。

            所以,传输读写指针之前,需要将其先由二进制转为格雷码,然后再发送到对方的时钟域下。

    二进制码和格雷码的转换:

    二进制码转化为格雷码:

            从最右边第一位开始,依次将每一位与左邻 一位异或(XOR),作为对应格雷码该位的值,最左边一位不变。

    格雷码转化为二进制码:

            从左边第二位起,将每位与左边一位解码后的 值异或(XOR),作为该位解码后的值(最左边一位依然不变)。

    FIFO 使用gray码判断“空”与“满”

    “空”状态的判断:

             空 :依据二者完全相等(包括MSB)(和二进制码判断一样)

    “满”的判断:

           由于 gray码除了MSB外,具有镜像对称的特点,当读指针指向7,写指针指向8时,注意地址增加到最大地址7时,然后会返回0,所以此处8和0虽然轮次不同,但是实际上是同一个地址。此时,除了MSB,其余位皆相同,就不能说它为满。

     在gray码上判断为满必须同时满足以下3条:

    • wptr和同步过来的rptr的MSB不相等, 因为wptr必须比rptr多折回一次
    • wptr与rptr的次高位不相等,如上图位置 7和位置15,转化为二进制对应的是 0111和1111,MSB不同说明多折回一 次, 111相同代表同一位置。)
    • 剩下的其余位完全相等 

    设计FIFO深度:

    设计之前要清楚:

    分析清楚数据轻载和重载时数据的传输任务
    如果FIFO能在重载的时候满足需求,轻载的时候,肯定可以胜任。

    例子:

    假设FIFO的写时钟为100MHz,读时钟为80MHz。在FIFO输入侧,每100个写时钟,写入80个数据;读数据侧,假定每个时钟读走一个数据。

    请问FIFO深度设置多少可以保证FIFO不会上溢出和下溢出?

    在FIFO的输入侧 每100个写时钟,写入80个数据。

    其数据传输分布可能有如图所示的几种情况:

    重载时数据的传输任务(要求缓存能力最高的情况)

            背靠背的情况:

            第一段的100个写时钟周期中,数据传输发生在后80个;

            第二段的100个写时钟周期中,数据传输发生在前80个。

    这样就会有160个周期,在连续传输数据。其他情形下,都没有这么重负荷的数据的传输任务。

    分析重载情况:

    连续传输数据的周期称为 burst长度。

            重载情况下,burst=160。在 burst长度内,写入端写入160个数据。

    burst持续时间=160*写时钟周期

     这段时间内能读出数据的个数=burst持续时间/读时钟周期数

     FIFO depth= burst长度 - 读出数据的长度

    所以FIFO深度至少大于等于32才可以。

    FIFO深度计算总结: 

    • 写时钟频率: WCLK     写时钟周期=1/WCLK
    • 读时钟频率: RCLK      读时钟周期=1/RCLK
    • 写时每B个时钟周期内会有 A个数据写入FIFO (写入效率A/B)
    • 读时每Y个时钟周期内会有 X个数据读出FIFO(读出效率X/Y)

    连续传输数据的周期称为 burst长度burst_length表示这段时间写入的数据量

    burst的持续时间:burst长度*写时钟周期 (burst_length / W LK )

    读的实际速度:(RCLK*(X/Y)),

    burst的持续时间这段时间读出的数据量:burst的持续时间*读的实际速度

                             (burst_length / W LK )*(RCLK*(X/Y))

    理论上的 FIFO的最小深度: 写入和读出两者之差为FIFO中残留的数据

                    burst_length  -    (burst_length / W LK )*(RCLK*(X/Y))

    FIFO设计总结

    FIFO设计中的两个关键问题:

    • 格雷码问题
    • 亚稳态问题

    这两个问题主要在FIFO结构中的下面红色方框模块中 

    读写指针使用格雷码 

     为什么需要格雷码做读写指针?

            由于异步FIFO是工作在两个不同的时钟域。

            如果某个时刻,读地址从0111->1000转变

            同时,写时钟要在这个时刻采样读地址,得到的值有可能是0000~1111中的任一个值

            这个不确定的读地址值会导致空满状态判断错误。

     格雷码的特点:

    1. 格雷码相邻的2个数值之间只会有一位发生变化,其余各位都相 同
    2. 格雷码是一种循环码,0和最大数(2的n次方减1)之间也只有一位不同

    例子: 

    假设FIFO深度为8,则读写指针可采用格雷码进行编码

    采用格雷码,指针每次只变化一次。地址7与地址0,也是每次只变化一次。

     问题:

            假设FIFO深度为6,如果读写指针继续采用格雷码,那么当前首尾指针的所有比特位都不相同。(首地址的指针 000 尾地址的指针 111)

            此时,如果从尾部返回首部,则无法实现消除亚稳态的目的。 

    如何解决?

            可将地址为5的指针设定为100,此时其与首地址的指针 “000”相差一个bit位,与地址为4的指针“110”也相差一 个bit位,满足消除亚稳态的要求。

    问题1: 如何在2次幂和非2次幂深 度下设计相应的读写指 针?

    问题2:什么情况下,需要用格雷 码来进行读写指针编码?

    问题3:什么时候不可以使用格雷码

            并不是一定要用格雷码做读写指针,而是当FIFO深度为2次幂的时候,刚好格雷码满足消除亚稳态的需求;在非2次幂FIFO深度情况下,格雷码已经不再适用。

    非2次幂FIFO深度情况的解决方法 通常有:

    若FIFO深度为偶数,可采用最接近的2次幂的格雷码编码,在此基础上修改;

    FIFO深度为一般数值时,可自行设计一种逻辑电路,或者查找表,以实现指针每次只跳变一次的功能

    ③ 以上方法通常在设计层面较为复杂,若无特定需求,可将FIFO深度设置为2次幂,浪费一些存储空间,来化简控制电路的复杂度。

    FIFO中的亚稳态问题 

    问题1:FIFO中的亚稳态是否能够真正消除?

            亚稳态不能从根本上消除,但可以通过采取一定的措施使其对电路造成的影响降低。



    问题2:若无法消除亚稳态,为什么FIFO还能正确运行?

    如果指针为格雷码,失效的后果?

    格雷码一次只有一位数据发生变化,这样在进行地址同步的时候,只有两种情况

    • 地址同步正确
    • 地址同步出错,但是只有1位出错

    分析地址同步出错 

            假设写地址 000->001         读地址同步出错           写地址变成 000->000

            也就是地址没有发生跳变。

            但是用这个错误的写地址去做空判断不会出错, 最多是让空标志在FIFO不是真正空的时候产生,而不会出现空读的情形。

            gray码:

            保证的是同步后的读写地址即使在出错的情形下依然能够保证 FIFO功能的正确性,当然同步后的读写地址出错总是存在的。

    注意:

            gray码 只是在相邻两次跳变之间才会出现只有1位数据不一致的情形 ,超过两个周期则不一定。

            所以,地址总线bus skew一定不能超过一个周期,否则可能出现gray码多位数据跳变的情况,这个时候gray码就失去了作用,因为这时候同步后的地址已经不能保证只有1位跳变了。


    问题3:两拍同步或者多拍同步的差异?

             将地址总线连续打两拍 ,为了避免亚稳态传播。

            理论上打两拍不能消除亚稳态现象,因为时钟异步,亚稳态不可避免,但是可以极大降低亚稳态传播的概率。

            多拍能够将亚稳态出现的概率进一步降低。

    FIFO静态时序分析:

    低频情况下

          STA不需要分析这里的异步时序,因为寄存器都可以在一拍内将亚稳态消除,恢复到正常0/1态。

    高频情况下(尤其在28nm工艺以下)

           需要检查两级触发器的延迟,保证延迟低,这样可以系统的MTBF。

    问题4:空满标志的判断方法是否有漏洞(虚空、虚满)?

             rptr同步两个“wclk”后,在wclk时钟域与wprt进行比较,生成full信号

            wptr同步两个“rclk”后,在rclk时钟域与rprt进行比较,生成empty信号

    分析FIFO空满标志: 

             假设,读指针rptr地址为3,在写时钟控制下,同步两个时钟进入写时钟域,即信号rptr_sync_2

            这时,在写时钟域下,刚好满足“满”的条件,生成满信号。

            但是,此时rptr的值已经更新为5。

            即在FIFO认为自己已经满的时候,读地址,又从里面读走了两个数据。实际FIFO并没有真正的满,只是接近满“虚满”。

    结论:

    •  对于full信号的生成机制,同步后的读地址一定是小于或者等于当前的 读地址,所以此时判断FIFO为满不一定是真满,这样更保守;
    • Empty信号的机制同样成立, “空”时,不一定是真“空”

    总结:

            异步FIFO通过比较读写地址进行满空判断,但是读写地址属于不同的时钟域,所以在比较之前需要先将读写地址进行同步处理,此机制保证 了FIFO在空满极限情况下,依然留有余量,存在一定的冗余空间。

            这种方法使得FIFO不会发生写满溢出、读空多读的情况。


    对FIFO进行逻辑综合、静态时序分析

     从电路结构上分析, FIFO主要包括

    • memory
    • 写时钟域电路
    • 读时钟域电路
    • 跨时钟域同步器

    在逻辑综合阶段,这几部分都需要单独处理。

    逻辑综合阶段处理:

    Memory:需要例化memory compiler生成的库文件。

    写时钟域电路、读时钟域电路:分别定义不同的时钟。

    静态时序分析:

    • 低频情况下,跨时钟域同步器需要设置wclk和rclk之间的false path。
    • 高频情况下,尤其在28nm工艺以下,需要检查两级触发器的延迟,保证延迟低。

    布局布线:

            P&R时,要注意将两级同步器放置在一起,不要被工具自动分开。


     参考视频:

    芯动力——硬件加速设计方法(3.2、3.3、3.4)

  • 相关阅读:
    WiFi连接满格信号但是不能上网?
    Mac 通过 brew安装的 ffmpeg 切换版本
    基于A4988/DRV8825的四路步进电机驱动器
    2023老博会|山东老龄产业展|老年用品展|适老度假与旅游展
    【C++入门】命名空间&缺省参数&函数重载&引用
    PX4仿真添加world模型文件,并使用yolov8进行跟踪
    设计模式 - 享元模式
    我服了,SpringBoot升级后这服务我一个星期都没跑起来(上)
    强化学习中的基本术语
    Linux centOS yum install MySQL5.7
  • 原文地址:https://blog.csdn.net/weixin_41788560/article/details/125339168