【数字IC】基于FPGA的异步FIFO实现

一、简介

异步FIFO主要是由双端口存储器写指针产生逻辑读指针产生逻辑空满标志产生逻辑4部分组成。读写操作是由两个完全不同时钟域的时钟所控制。在写时钟域部分,由写指针所产生逻辑生成写端口所需要的写地址和写控制信号;在读时钟域部分,由读指针产生逻辑生成读断口所需要的读地址和读控制信号;在空满标志产生部分,通常是把写指针与读指针相互比较产生空满标志
异步FIFO架构图片描述
读写指针属于不同的时钟域,如何同步异步信号,使触发器不产生亚稳态及如何正确地设计空、满信号的控制电路,使FIFO不会溢出,造成数据丢失是异步FIFO设计的两个难点

二、读/写指针产生逻辑

使用格雷码方式实现指针
格雷码相对于二进制的优势在于:格雷码从一个数变为下一个数时只有一位发生变化
在格雷码实现FIFO指针时需要注意,对于写逻辑部分,产生写满信号需要对读指针(格雷码)进行同步;对于读逻辑部分,产生读空信号需要对写指针(格雷码)进行同步。使用两级同步器对指针同步时,不可避免会产生两个时钟的延迟。

指针实现方法

  • 格雷码计数器
    格雷码计数器
    步骤1:根据条件递增二进制值;
    步骤2:将二进制值保存到寄存器中,同时将二进制值转换为格雷码;
    步骤3:将计数器的最终格雷码值保存到寄存器中。

  • 二进制到格雷码转换的Verilog代码如下:
    可以通过逐位异或,或者将二进制码右移后与自身异或的操作,计算出对应的格雷码。

module bin_to_gray(bin,gray);
parameter SIZE=4;
input  [SIZE-1:0]   bin;
output [SIZE-1:0]   gray;

assign gray = (bin>>1) ^ bin;
endmodule
  • 格雷码计数器实现
    根据格雷码和二进制码的特点可以发现,格雷码和二进制码的最高位是相同的,所以只需对低三位进行格雷码的转换。以写指针为例,具体实现方式如下:
parameter   SIZE=4;
reg  [SIZE:0] wbin,wbnext;
reg  [SIZE:0] wptr,wgnext;

always @(posedge wclk ornegedge rst_n) begin
    if(!rst_n) begin
        wbin           <= 'h0;
        wptr[SIZE-1:0] <= 'h0;
    end
    elsebegin
        wbin           <= wbnext;
        wptr[SIZE-1:0] <= wgnext[SIZE-1:0];
    end
end

always @(*) wptr[SIZE] = wbin[SIZE];

assign wbnext = !wfull ? wbin+winc : wbin;
assign wgnext[SIZE-1:0] = (wbnext[SIZE-1:0]>>1) ^ wbnext[SIZE-1:0];

将二进制值的结果保存在一组额外的寄存器中,虽然增加了电路的面积(这点面积基本没有影响),但避免了复杂的组合逻辑,可以提高系统工作频率。

三、空满信号产生逻辑

空满标志的产生是异步FIFO设计的核心。如何正确设计此部分的逻辑,会直接影响到FIFO的性能。空满标志的产生原则是:写满不溢出,读空不多读。

以16x16异步FIFO为例,写指针wptr[4:0],读指针rptr[4:0],其中低三位为真正的读写地址,最高位用来区分空满。

若读写指针完全相等,表示读地址追上了写地址,此时FIFO为若最高位相反但其余位相同,表示写地址领先读地址一个周期,此时FIFO为

读写指针比较产生空满标志rempty和wfull,将写指针同步到读时钟域,产生读空信号rempty控制异步FIFO的读操作;将读指针同步到写时钟域,产生写满信号wfull控制异步FIFO的写操作。

  • 空满信号的Verilog实现如下:
wire            wfull;
wire            rempty;
reg  [SIZE:0]   wptr_reg1;
reg  [SIZE:0]   wptr_reg2;
reg  [SIZE:0]   rptr_reg1;
reg  [SIZE:0]   rptr_reg2;

// 写指针在读时钟域的两级同步
always @(posedge rclk ornegedge rst_n) begin
    if(!rst_n) begin
        wptr_reg1 <= 'h0;
        wptr_reg2 <= 'h0;
    end
    elsebegin
        wptr_reg1 <= wptr;
        wptr_reg2 <= wptr_reg1;
    end
end
// 读指针在写时钟域的两级同步
always @(posedge wclk ornegedge rst_n) begin
    if(!rst_n) begin
        rptr_reg1 <= 'h0;
        rptr_reg2 <= 'h0;
    end
    elsebegin
        rptr_reg1 <= rptr;
        rptr_reg2 <= rptr_reg1;
    end
end

//空满标志产生
assign wfull  = ({!wptr[SIZE],wptr[SIZE-1:0]}==rptr_reg2)? 1'b1 : 1'b0;
assign rempty = (wptr_reg2==rptr)? 1'b1:1'b0;
  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值