多bit数据流跨时钟域传输
数据流和指示信号不同:
- 数据流大多具有连续性,即背靠背传输;
- 数据流要求信号具有较快的传输速度
解决方法:
FIFO(first in first out)
FIFO 是一种先进先出的储存结构 与普通存储器的区别:
缺点
- 只能顺序写入数据,顺序的读出数据,其数据地址由内部读写指针自动加1完成,不能像普通存储器那样可以由地址线决定读取或写入某个指定的地址。
在IC设计中,模块与模块之间的通信设计中,多时钟的情况已经不可避免;数据在不同时钟域之间的传输很容易引起亚稳态;异步FIFO就是一种简单、快捷的解决方案。
FIFO的功能类似于一个调节上下游水量的一个 蓄水池 。FIFO的上游结点是FIFO的数据输入端,在写信号有效时,数据将被写入FIFO,由FIFO内部的写指针控制,并且在FIFO内部,写指针递增一个单元,同时FIFO的满信号(FIFO full Signal)将控制上游结点是否发送数据;FIFO的下游节点是FIFO的数据输出端,当读信号有效时,FIFO中的数据将被读出,由FIFO内部的读指针控制,并且在FIFO内部读指针递增一个单元,同时FIFO空信号(FIFO empty Signal))将控制下游节点是否读出数据。如果FIFO内部的空间已经被写满,则实时生成满信号,以反压上游节点,上游节点停止写新的数据进来,否则就会把已经写好的数据冲掉。如果FIFO内部的数据全部被读,则实时生成空信号,控制下游节点不再进行数据读操作。否则,下游节点就会将读过的数据重新再读一遍。从这里也可以看出,空信号和满信号对于FIFO的控制非常重要。
FIFO用途
- 用异步FIFO读写分别采用相互异步的不同时钟
在现代集成电路芯片中,随着设计规模的不断扩大,一个系统中往往含有数个时钟多时钟域带来的一个问题就是,如何设计异步时钟之间的接口电路。异步FIFO是这个问题的一种简便、快捷的解决方案,使用异步FIFO可以在两个不同时钟系统之间快速而方便地传输实时数据。
- 对于不同宽度的数据接口也可以用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的总体结构
结构如下:
image-20221009122620242
- 双端口SRAM,用来存储上游节点写入的数据wdata,下游节点用rdata将其读出.SRAM的 读写地址采用了每次只递增1的机制 ,保证了写入和读出按顺序进行,写和读到最高地址后,重新返回零地址。
- 在上游节点和SRAM之间有一个 满信号生成电路 ,这个电路通过判断写时钟域下,写指针和读指针的关系,然后实时生成满信号w1,以通知上游节点停止写操作。
- 同样地,在下游节点和SRAM之间有一个 空信号生成电路 ,这个电路通过判断读时钟域下,写指针和读指针的关系,然后实时生成空信号empty,以通知下游节点停止读操作。
- 这两个模块的工作机制是我们要重点关注的。这里还需要注意的是,将读 指针传递到写时钟域才能产生满信号 ,将 写指针传递到读时钟域才能产生空信号 ,因此,这里就涉及到如何处理信号传输的亚稳态问题。
设计关键:
- 亚稳态的消除
- 空满状态的判断-> 正确的产生空满标志是任何FIFO设计的关键
- 空满状态产生的原则是:写满而不溢出,能读空而不多读。
空满状态的判断
读写指针相等 会触发满还是空,得看读写的指针方向是怎样的
空状态
当读写指针相等时,表明FIFO为空,这种情况发生在复位操作时或者当读指针读出FIFO中最后一个字后,追赶上了写指针;
当读写地址相等时,说明已经写入的数据,已经全部被读走,此时,FIFO还尚未有新的数据写入,说明FIFO为空,这种情况发生在复位操作时,或者当读地址读出FIFO中最后一个字后,追赶上了写地址。如果两个指针的MSB相同,则说明两个指针折回的次数相等。其余位相等,说明FIFO为空
满状态
满状态。当写地址超过读地址,写到最高地址后,重新从0开始写,再次追上了读地址。此时,读地址已经读过的地址空间,再一次被写地址写入。而读地址到最高地址之间的数据,还尚未被读。说明此时FIFO处于满的状态。如果两个指针的MSB不同,说明写指针比读指针多折回了一次;如raddr=0000,而w_addr=1000,为满。
区别满和空状态
- 在地址中添加一个额外的位(extra bit),当 写指针增加并越过最后一个FIFO地址时,就将写指针这个未用的MSB加1 , 其它位回零 。对读指针也进行同样的操作。此时,对于深度为2”的FIFO,需要的读/写指针位宽为(n+1)位,如对于深度为8的FIFO,需要采用4bit的计数器,0000
1000、100111111 MSB作为折回标志位,而低3位作为地址指针。
- 如果两个指针的MSB不同,说明写指针比读指针多折回了一次;如r_addr=0000,而w_addr = 1000,为满。
- 如果两个指针的MSB相同,则说明两个指针折回的次数相等。其余位相等,说明FIFO为空。
- 空满标志生成的前提是:
- 读指针被传递到了写时钟域
- 写指针被传递到了读时钟域
介入格雷码
在上一节中说过, 多bit信号是不能直接通过这种打两拍进行同步的 ,所以我们需要采用格雷码进行传输。传输读写指针之前,需要将其先由二进制转为格雷码,然后再发送到对方的时钟域下。
格雷码特点:
- 格雷码相邻的2个数值之间只会有一位发生变化,其余各位都相同 ;
- 格雷码是一种循环码和最大数(2的n次方减1)之间也只有一位不同。
引用格雷码之后,相邻值只有1位发生翻转,1位翻转所引起的亚稳态的概率远远要小于几位同时翻转所引起的概率;因此, 格雷码能很好的亚稳态出现的概率 。
转化方法:
- 二进制码转化为格雷码:从最右边第一位开始,依次将每一位与左邻一位异或(XOR),作为对应格雷码该位的值,最左边一位不变;
- 格雷码转化为二进制码:从左边第二位起,将每位与左边一位解码后的值异或(XOR),作为该位解码后的值(最左边一位依然不变)。
格雷码下的空满判断
- 如果采用格雷码,对于“空"的判断依然依据二者完全相等。
- 对于“满"的判断,由于格雷码除了MSB外,具有镜像对称的特点,当读指针指向7,写指针指向8时,注意地址增加到最大地址7时,然后会返回0, 所以此处8和0虽然轮次不同,但是实际上是同一个地址 。此时,除了MSB,其余位皆相同,就不能说它为满。在格雷码上判断为满必须同时满足以下3条:wptr和同步过来的rptr的MSB不相等,因为wptr必须比rptr多折回一次;wptr与rptr的次高位不相等;剩下的其余位完全相等。
所以在gray码上判断为满必须同时满足以下三条:
- wptr和同步过来的rptr的MSB不相等,因为wptr必须比rptr多折回一次。
- wptr与rptr的次高位不相等,如上图位置7和位置15,转化为二进制对应的是0111和1111,MSB不同说明多折回一次,111相同代表同一位置。
- 剩下的其余位完全相等。
当FIFO深度不为2的次幂时
当FIFO深度不为2的次幂时,格雷码的翻转变化就不是1 bit了
假设FIFO深度为8,则读写指针可采用格雷码进行编码;
假设FIFO深度为6,如果读写指针继续采用格雷码,那么当前首尾指针的所有比特位都不相同,此时,如果从尾部返回首部,则无法实现消除亚稳态的目的。
此时,首地址是000,尾地址为111,没办法消除亚稳态。解决方法:
- 可将地址为5的指针设定为100,此时其与首地址的指针“000”相差一个bit位,与地址为4的指针“110”也相差一个bit位,满足消除亚稳态的要求。
怎么设计读写指针的编码
- 并不是一定要用格雷码做读写指针,而是当深度为2次幂的时候,刚好格雷码满足消除亚稳态的需求;
- 在非2次幂深度情况下,格雷码已经不再适用,此时的解决方法通常有:
- 若深度为偶数,可采用最接近的2次幂的格雷码编码,在此基础上修改;
- 深度为一般数值时,可自行设计一种逻辑电路,或者查找表,以实现指针每次只跳变一次的功能;
- 以上方法通常在设计层面较为复杂,若无特定需求,可将FIFO深度设置为2次幂,浪费一些存储空间,来化简控制电路的复杂度。
FIFO深度设计
面试题++
例题1
假设FIFO的写时钟为100 MHz,读时钟为80 MHz。在FIFO输入侧,每100个写时钟,写入80个数据;读数据侧,假定每个时钟读走一个数据。
请问FIFO深度设置多少可以保证FIFO不会上溢出和下溢出?
对图,先找到最重载的情况:
最长burst写入时间为:
这段时间能 最小读走的数据量 :
这样就可以得到在 最差情况下留在FIFO中的数据 :
抽象一下:
写时钟频率为WCLK:读时钟频率为RCLK:写时每B个时钟周期内会有A个数据写入FIFO,说明写入效率是A/B,读时每Y个时钟周期内会有X个数据读出FIFO,说明读出效率是X/Y。这种情况下,FIFO的最小深度是多少?
(burst_length/WCLK)表示这个burst的持续时间,持续时间乘以读时钟频率,可知道读数据在效率100%的时候的读出数据个数,然后再乘以读数据效率X/Y)则可知道在bust时间段内读出了多少数据。burst length与这个读出数据的差值,FIFO中残留的数据,这个也就是理论上的FIFO的最小深度。
FIFO中的亚稳态问题
这里会结合上一节对异步FIFO进行分析:
- 亚稳态不能从根本上消除 ,但可以通过采取一定的措施使其对电路造成的影响降低。
为什么优先用格雷码做读写指针编码
如果指针为格雷码,失效的后果?
格雷码一次只有一位数据发生变化,这样在进行地址同步的时候,只有两种情况:
也就是地址没有跳变,但是用这个错误的写地址去做空判断不会出错,最多是让空标志在FIFO不是真正空的时候产生,而不会出现空读的情形。
所以,gray码保证的是同步后的读写地址即使在出错的情形下依然能够保证FIFO功能的正确性,当然同步后的读写地址出错总是存在的。
需要注意gray码只是在相邻两次跳变之间才会出现只有1位数据不一致的情形超过两个周期则不一定,所以,地址总线bus skew一定不能超过一个周期,否则可能出现gray码多位数据跳变的情况,这个时候gray码就失去了作用,因为这时候同步后的地址已经不能保证只有1位跳变了。
两拍同步或多拍同步的差异
将地址总线打两拍 -> 为了避免亚稳态传播
但是并不能消除亚稳态:
- 因为时钟异步,亚稳态不可避免,但是可以极大降低亚稳态传播的概率,
在低频情况下:
STA不需要分析这里的异步时序,因为寄存器都可以在一拍内将亚稳态消除,恢复到正常0/1态。
在高频情况下:
不一定,尤其在 28nm工艺以下,需要检查两级触发器的延迟 ,保证延迟低,提高系统MTBF。
对多拍同步,能够进一步将亚稳态出现的概率降低
空满标志的判断方法是否漏洞
对打两拍后,读写指针的动作为:
- rptr同步**两个“wclk”**后,在wclk时钟域与wptr进行比较,生成full信号
- wptr同步**两个“rclk”**后,在rclk时钟域与rptr进行比较,生成empty信号
假设读写时钟频率接近
这个时候看满的时候并不是真满,因为此时又都走了两个数据
结论:
- 对于full信号的生成机制,同步后的读地址一定是小于或者等于当前的读地址,所以此时判断FIFO为满不一定是真满,这样更保守;
- Empty信号的机制同样成立,“空”时,不一定是真“空”。
- 异步FIFO通过比较读写地址进行满空判断,但是读写地址属于不同的时钟域,所以在比较之前需要先将读写地址进行同步处理,此机制保证了FIFO在空满极限情况下,依然留有余量,存在一定的冗余空间。
频率相差较大时,同步时间可以
如何对FIFO进行逻辑综合和静态时序分析
模块划分:
在低频情况:
在高频情况下:
- 尤其在28 nm工艺以下,需要检查两级触发器的延迟,保证延迟低;
在布局布线(P&R)时