fifo设计
fifo设计主要包括
- 存储部分
- 写时钟域电路部分
- 读时钟域电路部分
- 跨时钟域电路部分
fifo设计需要注意的几个关键部分
-
fifo设计读写指针与格雷码
-
由于fifo是工作在两个不同的时钟域中读地址在某一个时刻将地址跳变
0111--->1000
-
如果读时钟恰好在这个时刻读取数据,得到的地址有可能是
0000~1111
中的任何一个值这个不确定的读地址值会导致空满状态判断错误 -
引用格雷码后,相邻数值只有1位发生翻转,1位翻转所引起亚稳态的概率远远小于几位同时翻转所引起亚稳态的概率,因此,格雷码能很好的控制亚稳态出现的概率
-
并不是一定要用格雷码做读写指针,而是当深度为2次幂的时候,刚好满足消除亚稳态的需求,而fifo中亚稳态不能从根本上消除,只是采用格雷码会大大降低亚稳态出现的频率
-
格雷码的特点
-
相邻的两个数值之前只会有一位发生变化,其余各位都相同
-
格雷码是一种循环码,0和最大数($2^n-1$)之间也只有一位不同
-
假设fifo的的深度为8,则读写指针可采用格雷码进行编码,
0~7 ==>000,001,011,010,110,111,101,100
-
那么当fifo深度为6,如果读写指针继续采用格雷码,则无法实现消除亚稳态的目的
-
可以如下表所示设置读写指针
-
0 1 2 3 4 5 000 001 011 010 110 111 000 001 011 010 110 100 -
在非二次幂深度的情况下,格雷码已经不再使用,此时解决方法有如下三种
- 若深度为偶数,可采用最接近处的2次幂的格雷码编码,在此基础上修改
- 深度为一般数值时,自行设计一种逻辑电路,或查找表,已实现指针每次只能跳变一次的功能
- 当设计方法过于复杂时,在没有特定需求的情况下,可以将fifo深度设置为2次幂,浪费空降,简化电路
-
-
格雷码失效的后果
- 地址同步出错,但只有1位出错,在这种情形下,依然能够保证fifo功能的正确性
- 格雷码在相邻两个周期跳变会出错但不会使fifo不能工作,但是超过两个周期时就不一定了,因为这时不止一位会出错
- 所以地址总线的偏斜一定不能超过1个周期,否则格雷码失去作用
- 将地址总线打两拍同步或者多拍同步的差异
- 地址总线打两拍,避免亚稳态传播,不能消除亚稳态现象(时钟异步,亚稳态不可以避免)
- 多拍可以将亚稳态出现的概率进一步降低,提高系统MTBF
-
二进制码转换格雷码,从最左边第一位开始,一次将每一位与左邻一位异或(XOR),作为对应格雷码该位的值,最左一位不变
-
格雷码转换二进制码,从左边第二位起,将每位与左边一位解码后的值异或(XOR)作为改为解码后的值(最左边一位不变)
-
-
空满标志的判断方法
- 通过比较读写地址进行空满判断,但是读写地址属于不同的时钟域,所以比较之前需要先将读写地址进行同步处理,此机制保证了fifo在空满极限情况下,依然留有余量,存在一定的冗余空间,即保守的来说,满不一定是真满,空不一定是真空,实现写满而不溢出,读空而不多读
- 区分空满状态可以在地址中增加一个额外的位,参考数据结构中设置标志位
- 当写指针怎建并越过最后一个fifo地址时,就将这个未用的MSB加1,其他位回零
- 对读指针也进行同样的操作,此时对于深度为$2^n$的fifo,需要读写指针位宽为n+1位
- 如果读写指针的MSB不同,说明写指针比读指针多折回了一次
- 如果两个指针的MSB相同,说明两个指针折回的次数相同,其余为相等的情况下,说明fifo为空
- 使用格雷码如何判断空满标志
- 空标志的判断方法不变,依然是读写指针相同
- 对于满标志,当各类码除了MSB外,具有镜像对称的特点
- 判断满的条件
- wptr和同步过来的rtpr的MSB不相等,因为wptr必须必rptr多折回一次
- wptr和rptr的次高位不相等
- 例
- 参照上图,当读指针指向7,写指针指向8除了MSB完全相同,当不能说他为满
- 上图位置7和15,转化为二进制对应的是0111和1111,MSB不同说明多折回一次,1111代表同一位
-
fifo深度设置
- 例
- $f_{wrclk} = 100MHz,f_{rdclk} = 80MHz$
- fifo写数据侧每100 个写时钟周期写入80个数据
- fifo读数据侧每100 个读时钟周期读出100个数据
- 根据上面的例子
- 数据如果背靠背传输会连续的突发写入160个数据,这时我们成为重载,轻载与之相对,在100个写时钟内写入80个数据
- 数据重载的时间 $b_t = b_l / f_{wrclk} = 160/100$
- 数据重载时间所能读出数据的个数 $d_{rnum} = b_t *f_{rdclk} * r_x = 160/100 * 80 * 100/100 = 128$
- fifo内参与的数据个数也就是fifo所需要的深度即 $depth = b_l - d_{rnum} =160 -128 = 32$
- 为了便于设计fifo得出同一化的公式,将问题一般化
- 写时钟频率:$f_{wclk}$;读时钟频率:$f_{rclk}$
- 写的时候每b个时钟会有a个数据写入fifo;读的时候每y个时钟会有x个数据读出fifo
- $depth = b_l - (b_l/f_{wclk}) * f_{rclk} * x/y = b_l - b_t * f_{rclk} * x/y = b_l-b_t*r_x$
- 例
tips
- 缩写
- 突发读/写长度 $b_l = brustlength$
- 突发读/写时间 $b_t = brust time$
- 读数据的效率$r_x = 读时钟频率 * (读出数据个数/所用周期数)$
- 重载时读出数据的个数$d_{rnum} = data read number$
- 深度 depth
- fifo设计参考