同步FIFO

本文介绍了同步FIFO的工作原理,包括时序和空满判断,以及使用Verilog语言编写的代码实例。通过仿真分析了不同操作模式下的行为。适合FPGA学习者理解FIFO在设计中的应用。

FIFO系列:FPGA中FIFO的应用
完整工程已上传至优快云下载链接


一、概述

FIFO

📄FIFO(First In First Out)是一种先进先出的数据缓存器,先进入FIFO的数据会先输出。FIFO通常可分为同步FIFO和异步FIFO两类。

FIFO 设计的关键:产生可靠的 FIFO 读写指针和生成 FIFO“空”/“满”状态标志。

FIFO 本质上是由 (伪双口)RAM 加读写控制逻辑构成的。
在这里插入图片描述

FIFO的优点:没有读写地址线,顺序写入、读出数据,数据地址由内部读写指针自动+1完成,使用起来简单方便。
FIFO的缺点:不能像RAM或ROM那样读取或写入某个指定的地址。

同步FIFO

📄同步FIFO:其读写受同一时钟控制,一般用于数据的缓冲、传输速率匹配等。

参数意义
时钟读写采用同一时钟
FIFO的宽度FIFO一次读写的数据位宽
FIFO的深度FIFO中存储的数据个数
空标志FIFO已空时发出空信号,以阻止读操作继续读取无效数据
满标志FIFO已满时发出满信号,以阻止写操作继续向FIFO中写数据而导致FIFO溢出

二、工作原理

2.1 工作时序

  • 在写使能有效且FIFO非满时,对FIFO进行写;写地址由自增产生,将数据写入该地址 ,初始为0。
  • 在读使能有效且FIFO非空时,对FIFO进行读;读地址由自增产生,将数据从该地址读出,初始为0。

在这里插入图片描述

2.2 空满判断

📄FIFO空满判断主要有计数器法高位扩展法两种,这里先说明计数器法。

计数器法:添加一个计数器data_cnt指示FIFO中数据的个数:

  • 当写使能有效且FIFO非满时data_cnt+1;
  • 当读使能有效且FIFO非空时data_cnt-1;
  • 当读写使能同时有效时data_cnt不变;
  • data_cnt==0时,FIFO读空,产生空标志;
  • data_cnt==FIFO深度时,FIFO写满,产生满标志。

三、程序

`timescale 1ns / 1ps

module fifo_syn
#(parameter FIFO_WIDTH=8,
  parameter FIFO_DEPTH=16)

(
    input                        clk    ,
    input                        rstn   ,
    input                        wr_en  ,
    input                        rd_en  ,
    input       [FIFO_WIDTH-1:0] din    ,
    output                       empty  ,
    output                       full   ,
    output reg  [FIFO_WIDTH-1:0] dout
    );

reg [$clog2(FIFO_DEPTH)-1:0] wr_addr;
reg [$clog2(FIFO_DEPTH)-1:0] rd_addr;
reg [$clog2(FIFO_DEPTH):0] data_cnt;//由于FIFO赋值和地址自增相差1周期,需多计数1周期

reg [FIFO_WIDTH-1:0] fifo [0:FIFO_DEPTH-1];

assign empty=(data_cnt==0) ? 1'b1 : 1'b0;
assign full=(data_cnt==FIFO_DEPTH) ? 1'b1: 1'b0;
//写FIFO
always@(posedge clk or negedge rstn)begin
    if(!rstn)begin
        wr_addr<='b0;       
    end
    else if(wr_en&&!full)begin
        wr_addr<=wr_addr+1'b1;
        fifo[wr_addr]<=din;        
    end
    else begin
        wr_addr<=wr_addr;
    end
end

//读FIFO
always@(posedge clk or negedge rstn)begin
    if(!rstn)begin
        rd_addr<='b0;
        dout<='b0;
    end
    else if(rd_en&&!empty)begin
        rd_addr<=rd_addr+1'b1;
        dout<=fifo[rd_addr];        
    end
    else begin
        rd_addr<=rd_addr;
    end
end
//数据状态变化
always@(posedge clk or negedge rstn)begin
    if(!rstn)begin
        data_cnt<='b0;
    end
    else begin
        case({wr_en,rd_en})
            2'b10:
            if(data_cnt!=FIFO_DEPTH)//空满时计数器不变
                data_cnt<=data_cnt+1'b1;
            2'b01:
            if(data_cnt!=0)
                data_cnt<=data_cnt-1'b1;
            default:
                data_cnt<=data_cnt; 
        endcase
    end
end
endmodule

四、仿真

📄仿真中主要是产生读写使能信号和要写入的数据。这里编写几个简单的任务来产生读写使能信号,为保证数据稳定,在时钟的下降沿赋值。

`timescale 1ns / 1ps

module tb();

parameter FIFO_WIDTH=8;
reg clk;
reg rstn;
reg wr_en;
reg rd_en;
reg [FIFO_WIDTH-1:0] din;
wire empty;
wire full;
wire [FIFO_WIDTH-1:0] dout;

initial begin
    clk=1'b0;
    rstn=1'b0;
    wr_en=1'b0;
    rd_en=1'b0;
    din='b0;
    #15;
    rstn=1'b1;
    repeat(20)begin
        wr_only;
    end
    repeat(20)begin
        rd_only;
    end
    repeat(5)begin
        wr_only;
    end
    repeat(5)begin
        wr_rd;
    end
end

always #10 clk=~clk;
//只写的任务
task wr_only;
begin
    @(negedge clk)begin
        wr_en=1'b1;
        rd_en=1'b0;
        din={$random}%(2^FIFO_WIDTH);//生成0~2^FIFO_WIDTH-1的随机数
    end
end
endtask
//只读的任务
task rd_only;
begin
    @(negedge clk)begin
        rd_en=1'b1;
        wr_en=1'b0;
    end
end
endtask
//读写的任务
task wr_rd;
begin
    @(negedge clk)begin
        rd_en=1'b1;
        wr_en=1'b1;
        din={$random}%(2^FIFO_WIDTH);
   end 
end
endtask
fifo_syn fifo_syn_u
(
    . clk    (clk),
    . rstn   (rstn),
    . wr_en  (wr_en),
    . rd_en  (rd_en),
    . din    (din),
    . empty  (empty),
    . full   (full),
    . dout   (dout)
    );
endmodule

{$random}%(2^FIFO_WIDTH)表示产生范围为0—2 ^ FIFO_WIDTH-1的随机数。
有关$random更详细的用法,可参考这篇文章: $random的用法详解

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hi小瑞同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值