当前位置:网站首页 > 技术博客 > 正文

异步fifo使用



        FIFO:即First In First Out,是一种先进先出的数据存储、缓冲器。

        存储方式:FIFO的数据按照写入的先后被顺序性存储,并在需要时被顺序地读出。因此FIFO只能顺序写入和读取数据,而不能像普通存储器(RAM)那样随机读写任意存储单元。

        地址生成:FIFO无外部读写地址线,通过内部的计数器实现地址的自增来控制读写。每当有一个数据被写入或读出时,计数器就会加一,从而生成下一个要写入或读出的数据的地址。

        同步FIFO:写/读时钟为同一时钟,内部所有逻辑都是同步逻辑。常用于交互数据的缓冲。(如数据采集端速度飞快,但数据处理端较慢,故可用FIFO做数据缓冲。反之亦然)

        异步FIFO:写/读时钟为异步时钟,内部的写逻辑和读逻辑的交互需要异步处理。常用于跨时钟域的数据交互,实现不同时钟域之间的数据同步。

        参数与端口:

信号 端口 说明 w_clk input 写时钟(同步共用一个clk) r_clk input 读时钟(同步共用一个clk) rst_n input 复位信号 wr_en input 写使能 rd_en input 读使能 [7:0]wdata input 写入数据输入(8bit) [7:0]rdata output 读取数据输出(8bit) full output 写满信号 empty output 读空信号

        不难想到:当FIFO内填满了写入的数据但都没有被读取时,再写入数据会覆盖需要读取的数据。反之当FIFO内写入的数据被读空时,再读数据会读过头,读取到错误的数据。因此FIFO的设计关键在于 “读空” “写满” 的判断:

        法1:拓展高位法(深度为2^n)

        在读写地址wr_addr、rd_addr 基础上拓展一个高位MSB作为读写指针w_ptr、r_ptr。当指针越过最后一个FIFO地址时,就将MSB加1,其它位回零。

以深度为8的FIFO为例:wr_addr、rd_addr 地址位只需要3位,拓展一位MSB作为折回标志位,此时读写指针w_ptr、r_ptr 为4位,其中低3位作为地址。

写满时,两指针MSB不同,地址位相同:即指针仅高位不同,写比读指针多折回一次,如rd_ptr=0000,而wr_ptr = 1000 此时写指针比读快一轮,为写满状态

读空时,两指针所有位相同:两指针的折回次数相同,如rd_ptr=0110,而wr_ptr = 0110 此时读指针追上了写,为写满状态

        法2:数据计数法

        定义data_counter 用于计数,每当写入一个数据计数器加1,每读出一个数据减1。此时当data_counter = 0时FIFO读空,data_counter = FIFO深度时则写满。缺点:计数器会占用额外资源,当FIFO较大时,可能会降低FIFO的读写速度。

        

 
  
 
  

1.复位时一直为读空状态(没有数据读)

2.同时使能读写时,每写入一个数据,就读出一个数据

3.写入的数据依次存进FIFO存储单元(data)

        为什么同步:由于读写操作分别由不同时钟控制,直接交互可能会导致数据冲突、时序违规以及亚稳态问题,从而影响FIFO的正确性和稳定性。这里要同步读写两部分,不仅需要考虑如何同步,还需考虑信号同步到哪个时钟域的问题,

         亚稳态问题:由于两个指针的变化不同步,当它们被直接比较时,可能会因为时钟边沿的不同步导致采样到的信号值不稳定。这种不稳定状态被称为亚稳态,它可能导致比较结果错误。

        如何同步:首先同步还需要避免亚稳态,一般采取打拍同步的方式解决,打两拍就可以很好的降低亚稳态发生概率。同时指针转换为格雷码再打拍同步,格雷码每次只变一位,有效的避免跨时钟域情况下亚稳态问题发生概率。例如二进制的 0111→1000,4位都会变化,而格雷码 0100→1100 仅第四位变化 ,进一步减小亚稳态发生概率。

        同步到哪个时钟域:举个例子,判断写满时,写指针每变化一次就需要和读指针比较,判断有没写满以决定能不能继续写数据,所以需要将读指针在写指针变化时拿来比较,即读指针同步到写时钟域下比较。

        综上可以得出结论:

如何同步

将二进制指针转化成格雷码后,再打两拍同步

同步到哪个时钟域

 判断读空:将写指针同步到读时钟域

 判断写满:将读指针同步到写时钟域

(提一句:打两拍会有两个周期的延迟,比如判断读空时,同步到读时钟域的写指针实际上是前面隔两个读时钟周期的同步进来的写指针,所以判断出读空时可能是”假读空”,即没读空就提前判断为读空。但是这种情况不影响FIFO的功能,无非是降低了点性能,属于保守设计,保证运行稳定)

        不同于同步FIFO,异步FIFO读写指针在转化为格雷码同步后,再作比较,因此关键是如何通过格雷码判断读空写满。这种情况适用拓展高位法:

        与同步FIFO同理,先将二进制的读写地址拓展一位MSB,接着将拓展后的二进制指针转化为雷格码。深度为8的FIFO为例:wr_addr、rd_addr 地址位只需3位,拓展一位作为折回标志位,此时读写指针w_ptr、r_ptr 为4位。然后拓展后的二进制指针转化为雷格码指针wr_ptr_gray、rd_ptr_gray。指针转化结果见下图(8-15表示已折回一次)。

写满时,两指针高两位不同,其余位相同:如rd_ptr_gray = 0100,wr_ptr_gray = 1000 此时写指针比读快一轮,写满。

读空时,两指针所有位相同:如rd_ptr_gray = 0111,wr_ptr_gray = 0111 此时读指针追上写,读空

 
  
 
  

1.复位时一直为读空状态(没有数据读)

2.先使能写,写完第8个数据后为写满状态,后续数据无法写入

3.后使能读,发现读几个数据后,不再为写满状态,数据又可以继续写入(提一句:为什么不是读一个数据就结束写满状态,是因为判断写满时,同步过来的的读指针格雷码有两拍延迟,这个时候实际上是“假写满”属于保守设计,图中最后一个信号就是两拍同步后的读指针格雷码,可以看到延迟了两个写时钟才变化)

4.因为读时钟快,波形后半段读追上写,读数据需要等待数据写入才能读,读空信号此时反复变化

  • 上一篇: 树莓派3b+介绍
  • 下一篇: flowable springboot2.0
  • 版权声明


    相关文章:

  • 树莓派3b+介绍2025-06-26 22:30:01
  • jmeter怎么连接数据库2025-06-26 22:30:01
  • 铁威马的nas怎么样2025-06-26 22:30:01
  • java juc是什么2025-06-26 22:30:01
  • 用usermod命令修改用户2025-06-26 22:30:01
  • flowable springboot2.02025-06-26 22:30:01
  • 介绍计算机的发展历程2025-06-26 22:30:01
  • pycharm 单元测试2025-06-26 22:30:01
  • redis category2025-06-26 22:30:01
  • linux性能监控系统2025-06-26 22:30:01