异步FIFO实现

异步时钟可以在两个不同的时钟系统之间快速而方便的传输数据,是一种先进先出的数据缓存器,与普通的存储器区别是没有外部独写地址线,使用起来非常简单,但缺点就是只能顺序的写入数据,顺序的读出数据,其数据地址由内部的读写指针自动完成,不能像普通存储器通过地址线来进行读取指定地址的数据;对于不同位宽的数据接口也可以使用FIFO,以达到数据匹配的目的;
 

FIFO的分类
同步FIFO:是指的读时钟和写时钟是同一个时钟,在时钟沿到来时同时发生读写操作;

异步FIFO:是指的读写时钟不一致,读写时钟之间是相互独立的;

读写指针的工作原理
写指针:总是指向下一个要写入的单元,复位时,读指针指向第一个单元;

读指针:总是指向下一个要被读出的数据的地址,复位时,读指针指向第一个单元;

FIFO的空满检测
当读写地址相等时,表示FIFO为空,这种情况发生在复位操作时,或者当读指针读出FIFO中最后一个字后,追赶上了写指针时,表示FIFO为空;

当读写指针再次相等时,表示FIFO为满,这种情况发生在,当写指针转了一圈,折回来又追上了读指针时;

为了区别是满状态还是空状态,可以采用下面的方法;

方法1:在指针中添加一个额外的位,当写指针增加并越过最后一个FIFO地址时,将写指针的额外位(MSB)加1,其他位回零。对读指针也继续同样的操作。对于深度为2^n的FIFO,需要的读写指针为n+1位,例如对于深度为8的FIFO,需要采用4bit的计数器,MSB(最高位)作为折回标志位,低三位作为地址指针;

如果两个指针的MSB不同,说明写指针比读指针多折回了一次,如read_addr = 0000,则w_addr=1000,为满状态;

如果两个地址的MSB相同,则说明两个指针折回的次数相等,其余位相等,说明读指针追上了写指针,FIFO此时为空状态;

由于异步FIFO的设计,读写时钟不一样,在产生读空信号和写满信号时,会涉及到跨时钟域的问题。需要将读指针和写指针进行比较,需要在进行同步处理之后再进行比较

解决方法:格雷码+两级寄存器同步;

FIFO指针考虑
将二进制的计数器值从一个时钟域同步到另一个时钟域的时候很容易出现问题,因为二进制计数器所有位可能同时变化,在一个时钟上升沿同步多个信号的变化会产生亚稳态问题。而使用格雷码只有一位变化,因此在时钟域之间同步多个位时不会出现问题,所以需要有一个二进制转格雷码的转化电路,将地址值转化位对应的格雷码,然后将格雷码同步到另外一个时钟域下进行对比,作为FIFO空满状态的检测;

FIFO的速率控制,最小深度计算
 

当读速率慢于写速率时,FIFO便可以作为系统中的缓冲原件或队列;在写快读慢的场景下,规则如下

(读写同时进行,且读写连续)


FIFO深度/(写入速率-读出速率)> {FIFO被填满的时时间到下一次数据包的写传送时间}

例:A/D采样率50MHz,dsp读A/D读的速率40MHz,要不丢失地将10万个采样数据送入DSP,在A/D在和DSP之间至少加多大容量(深度)的FIFO才行?

100000/50M = 100000/50000000 = 0.002s = 2ms;

2ms*(50M-40M) = 20k

即在2ms的时间内不能溢出,2ms*(写速率-读速率)即为FIFO的最小深度;

异步FIFO最小深度计算公式

(读写同时进行,突发型)
写时钟频率w_clk,读时钟频率 r_clk,写时钟周期里,每B个时钟周期会有A个数据写入FIFO,读时钟周期里,每Y个时钟周期会有X个数据读出FIFO,则FIFO的最小深度是? 计算公式如下: fifo_depth = burst_length - burst_length * X/Y * r_clk/w_clk;

 如果100个写时钟周期可以写入80个数据,10个读时钟可以读出8个数据。令wclk=rclk ,考虑背靠背(20个clk不发数据+80clk发数据+80clk发数据+20个clk不发数据的200个clk)代入公式可计算FIFO的深度 fifo_depth = 160-160X(80%)=160-128=32      如果令wclk=200mhz,改为100个wclk里写入40个,rclk=100mhz,10个rclk里读出8个。那么fifo深度为48 计算如下fifo_depth =80-80X(80%)X(100/200)=80-32=48 注:将 fifo_depth = burst_length - burst_length * (X/Y) * (r_clk/w_clk) 作个变形,得到 fifo_depth = burst_length -[(burst_length *(1/w_clk))]/[(Y*(1/r_clk))/X] 其中[(burst_length *(1/w_clk))] 表示这个burst的持续时间,[(Y*(1/r_clk))/X] 表示读出每个数据所需的时间(即:读的实际速度)。两者相除自然就是这段时间读出的数据量。显然burst_length表示这 段时间写入的数据量,两者的差为fifo中残留的数据,这个也就是理论上的fifo的最小深度。实际应用中往往是以半空半满信号来指示fifo的空满状态的,所以实际设计fifo的时候会至少留下一个数据空间的深度裕量。

读写不是同时进行
这种情况下,需要设置FIFO的深度为突发的个数;

异步FIFO最小深度计算实例
SDRAM应用:

设置fifo深度时,一般设置FIFO的深度为操作数据长度的2倍足以;因为SDRAM的读写速度肯定快于写FIFO的速度;(一般场景)

如:两个异步时钟域数据接口,假如读写是同时进行的,一般这时设置FIFO情况就是写时钟大于读时钟。这个时候设置FIFO的深度就要对应两个时钟以及对应写最大的突发数据。假设写时钟频率是40MHz,读时钟为25Mhz,在写端最大突发写数据个数为100个数据。对应设置深度计算:100(1-25/40)=37.5,对应深度设置至少为38。(用第二点所述公式计算)

100-100*1/1*25/40 = 37.5     假如读写不是同时的,这就需要设置深度为写数据最大突发个数,如上例中,对应最大突发个数为100个,则深度设置为100。

异步FIFO代码实现

多位二进制码转化位格雷码

 

verilog实现如下图所示

在格雷码中检测空满状态

使用格雷码解决了计数器值同步的问题,但需要在格雷码中判断空与满状态;

如上图所示

读空:读时钟域的格雷码和被同步到读时钟域的写指针每一位完全相同;

写满:写时钟域的格雷码和被同步到写时钟域的读指针高两位不相同,其余各位完全相同;

 

异步FIFO的verilog实现如上图所示
————————————————
版权声明:本文为CSDN博主「观芯」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/w1152715961/article/details/111597679

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值