多个bit信号的跨时钟域仅仅通过简单的同步器同步时不安全的。
如下图:
虽然信号都同步到目的时钟域,可完成的功能却与设计的初衷不相符。
解决方案之一为对信号进行格雷码编码,但此方案只适用于连续变化的信号。另一种方案为增加新的控制信号en,确保传输信号稳定时采样。比如在传输信号稳定输出1、2个clk后再进行采样。
一、异步FIFO
上面说到的为多bit指示信号传输,而数据流的传输与指示信号不同在于:数据流大多具有连续性,及背靠背传输;数据流要求信号具有较快的传输速度。主要的方案是利用FIFO进行传输。
异步FIFO结构如下:
1、FIFO的参数
- 宽度:一次读写操作的数据位
- 深度:可以存储的N位数据的数目(宽度为N)
- 满标志:FIFO已满或将要满时,由FIFO的状态电路送出的信号,阻止FIFO写操作
- 空标志:FIFO已空或将要空时,由FIFO的状态电路送出的信号,阻止FIFO读操作
- 读时钟:读操作所遵循的时钟
- 写时钟:写操作所遵循的时钟
2、设计空满标志位电路
正确产生空满信号是任何FIFO设计的关键。其设计原则是:能写满而不溢出,能读空而不多读。
- 在写时钟域下,判断读写指针的关系,生成满标志
- 在读时钟域下,判断读写指针的关系,生成空标志
对于空满判断,可看下图
在判断空和满的情况下,都会有读写指针相等的情况,可采用以下方法进行区分:
在地址中额外添加一个位,当写指针增加并越过最后一个地址位时,就将这个额外的位(MSB)加一,其他位回0。读指针也进行同样的操作。额外的位作为折回标志位。如果两个指针的MSB不同,其余位相等,说明读指针比写指针少折回了一次,这种情况下,FIFO为满。而读写指针所有位都相等,说明折回次数相等,此时FIFO为空。
解决空满判断后,则是读写指针同步的问题。二进制的读写指针通常位宽超过了1bit,而多比特信号是不可以直接使用两级同步器的。这时,考虑到FIFO地址是连续变化的,我们使用格雷码来进行传输。格雷码相邻两个数值只有一位发生变化,0和最大数之间也只有一位不同。
而转换为格雷码进行传输后,如何进行空满判断?如下图:
至于为什么选择格雷码进行传输,我们来看格雷码传输失效的情况:
格雷码传输失效,只有一位同步出错,此时地址没有跳变。如果是写地址同步失效,用这个错误的写地址在读时钟域进行空判断时不会出错,最多是让空标志在FIFO不是真正空的时候产生,而不会产生空读的情况。格雷码保证的是同步后的读写地址即使在出错的情况下依然能够保证FIFO功能的正确性。
3、设计FIFO的深度
先从一个例题入手,
假设FIFO的写时钟为100MHZ,读时钟为80MHZ。在FIFO输入侧,每100个时钟,写入80个数据;FIFO读入测,每个时钟读取一个数据。设计合理的FIFO深度,使FIFO不会溢出。
我们需要考虑数据轻载和重载的情况,对缓存能力要求最高的情况为背靠背传输,则FIFO深度为160-(160/100)*80=32
我们将问题一般化:
- 写时钟频率WCLK
- 读时钟频率RCLK
- 写入测每B个时钟周期有A个数据写入
- 读取测每Y个时钟周期有X个数据读出
则FIFO的深度为,其中burst_length与写入测情况有关。