FPGA Basis FIFO

FPGA Basis FIFO

想来想去,今天最开心的事情还是学习了Sunburst Design提供的论文《Simulation and Synthesis Techniques for Asynchronous FIFO Design》。内心很明白,Xilinx的IP以及XPM Macro确实好用,自己忽略了很多设计的细节, 如果真的需要自己设计一个FIFO,估计就凉了。借用大神的一句话,离开了平台,什么是属于你自己的?
下面按照论文的思路来复习FIFO是如何设计的。

介绍

异步FIFO的定义:读写不是同一个时钟的FIFO,称之为异步FIFO
论文中这段话说的挺好的,一个接近正确的设计在99%的时间工作正常,但是这种设计是最难debug的!其实停用有道理的,当认为不会出错的地方隐藏了bug,确实让人抓狂。

用途

在两个时钟域之间安全传输多比特的时候,使用异步FIFO实现。
异步FIFO实现的难点在于:

  • 读写指针的控制
  • 稳定的产生空满信号

介绍异步FIFO设计之前,作者首先顺带介绍了同步FIFO指针的控制
在同步FIFO中,读写在同一个时钟域,所以在同一个时间只存在以下3种情形:

operation modeSituation
incrementWrite but no Read
decrementRead but no Write
holdWrite and Read / no read and no write

作者承上启下提出,在异步FIFO设计中不能使用1个指针完成以上操作,因为存在2个时钟域。

异步FIFO的指针设计

下面作者开始重点介绍如何设计异步FIFO的指针设计

write pointer:永远指向下一个被写入的地址,在复位时清零

read pointer:指向当前从FIFO中被读出的内容,在复位时清理,FIFO为空,empty信号有效,读指针对应的数据无效。

当第一个数据写入到FIFO中,empty信号被clear,读指针依旧指向FIFO中的第一个数据,并把FIFO中第一个数据挂到输出端口上,接收逻辑可以不需要使用2个时钟周期完成读操作,有助于效率的提高。

FIFO为空的条件:读写指针相同

FIFO为满的条件:读写指针再次相同,即写指针写满一圈后又要和读指针相同。

通过在读写指针上增加额外1比特,当写指针到底后,MSB做乒乓操作。当读写指正的MSB相同时,表示读写操作经过了相同的权数,否认,必然是读领先写。

用n比特指针,实质上n-1比特用于表示FIFO存储的深度。

FIFO为空的条件MSB相同,且低n-1位相同
FIFO为满的条件MSB不同,且低n-1位相同

比较不同时钟域的读写指针,是时候格雷码出场了,特点

  • 格雷码相邻码字只有1比特不同
  • 格雷码用于统计2 ( ( (n)))个数的统计

Dual n-bit Gray code counter
同时产生n比特格雷码,起低n-1比特仍为格雷码
在这里插入图片描述

为什么要这么设计???
n比特格雷码的读写指针分别需要通过2级寄存器到对方的时钟域,但是其中低n-1比特的格雷码可以直接用来指示存储器的地址。

论文中给出了判断读空写满的代码,看起来非常简洁,美观。

    module rptr_empty #(parameter ADDRSIZE = 4)(
    output		reg			  	    rempty  ,
    output      reg [ADDRSIZE-1:0]  raddr   ,  // 给RAM的读地址
    output      reg [ADDRSIZE  :0]  rptr    ,  //    
    input           [ADDRSIZE  :0]  rq2_wptr,  //经过2级寄存器同步的写指针
    input                           rinc    ,
    input                           rclk    ,
    input                           rrst_n 
    );
    
    reg [ADDRSIZE:0] rbin;
    reg [ADDRSIZE:0] rgraynext, rbinnext;
    
    //格雷码指针
    always@(posedge rclk or negedge rrst_n)
    if(!rrst_n) {rbin, rptr} <= 0;
    else        {rbin, rptr} <= {rbinnext, rgraynext};
    
    //存储空间的读指针
    assign raddr = rbin[ADDRSIZE-1:0];
    
    assign rbinnext = rbin + {rinc & ~rempty};
    assign rgraynext = (rbinnext>>1)^rbinnext;
    
    //FIFO为空的条件
    assign  rempty_val = (rgraynext = rq2_wptr);
    
    always@(posedge rclk or negedge rrst_n)
    if(!rrst_n) rempty <= 1'b1;
    else        rempty <= rempty_val;
    endmoudle
    module wptr_full #(parameter ADDRSIZE = 4)(
    output reg                	 wfull   ,
    output     [ADDRSIZE-1:0]	 waddr   ,
    output reg [ADDRSIZE  :0] 	 wptr    ,
    input      [ADDRSIZE  :0]	 wq2_rptr,//经过2级寄存器同步的写指针
    input                    	 winc    , 
    input                    	 wclk    ,
    input                    	 wrst_n
    );
    reg  [ADDRSIZE:0]  wbin;
    wire [ADDRSIZE:0]  wgraynext, wbinnext;
    
    //格雷码指针
    always @(posedge wclk or negedge wrst_n)
    if (!wrst_n) {wbin, wptr} <= 0;
    else {wbin, wptr} <= {wbinnext, wgraynext};
    
    //存储空间写地址
    assign waddr = wbin[ADDRSIZE-1:0];
    assign wbinnext = wbin + (winc & ~wfull);
    assign wgraynext = (wbinnext>>1) ^ wbinnext;  //生成格雷码
    
    //------------------------------------------------------------------
    // 判断FIFO为满的3个条件
    // assign wfull_val=((wgnext[ADDRSIZE] !=wq2_rptr[ADDRSIZE] ) &&
    // (wgnext[ADDRSIZE-1] !=wq2_rptr[ADDRSIZE-1]) &&
    // (wgnext[ADDRSIZE-2:0]==wq2_rptr[ADDRSIZE-2:0]));
    //------------------------------------------------------------------
    
    assign wfull_val = (wgraynext=={~wq2_rptr[ADDRSIZE:ADDRSIZE-1],
                                     wq2_rptr[ADDRSIZE-2:0]});
    always @(posedge wclk or negedge wrst_n)
    if (!wrst_n) wfull <= 1'b0;
    else wfull <= wfull_val;
        
    endmodule
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FPGA 同步 FIFO 是一种用于在 FPGA 设备中实现数据缓冲和数据转移的组件。它由一个读取指针和一个写入指针组成,可以实现读写操作的同步和互斥。 使用 FPGA 同步 FIFO 的一个常见场景是在不同频率的数据传输之间进行数据缓冲和同步。当输入以不同频率产生数据时,为了保证数据的可靠传输和处理,可以使用同步 FIFO 来缓冲输入数据,并在输出端以相同或不同的频率读取数据。 FPGA 同步 FIFO 的实现可以采用 FPGA 内部的存储单元,如 Block RAM 或 Distributed RAM。写入操作将数据写入 FIFO 的写入指针所指向的位置,并将写入指针前移。读取操作将数据从 FIFO 的读取指针所指向的位置读取出来,并将读取指针前移。读写指针的移动是同步的,以保证数据的正确性和完整性。 FPGA 同步 FIFO 的大小通常取决于数据传输的需求和 FPGA 设备的资源限制。可以根据数据产生和处理的速度来确定 FIFO 的大小,并且需要根据需要调整读写指针的顺序和移动策略,以满足数据的传输需求。 尽管 FPGA 同步 FIFO 在数据传输中起到了重要的作用,但同时也会增加设计的复杂性和资源消耗。在使用 FPGA 同步 FIFO 时,需要注意处理数据的同步和互斥问题,以及避免出现数据丢失、溢出等异常情况。 总之,FPGA 同步 FIFO 是一种用于实现数据缓冲和转移的组件,在不同频率的数据传输中发挥了关键作用。它可以通过读写指针的同步移动来保证数据的可靠性和完整性,并且可根据需求和硬件资源进行灵活调整。但同时也需要注意处理同步和互斥问题,以确保数据的正确传输。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值