crazybird

【原创】基于两种模式下的同步FIFO设计

1
阅读(6786)

    所谓FIFO就是先进先出的意思,通俗的说,就像数据从一个管道的一端进去而从管道的另一端输出。FIFO是一个没有地址端口的存储器,它依靠内部写指针(指定写数据的位置)和读指针(指定读数据的位置)来进行数据的存储或读取。

    FIFO有同步FIFO和异步FIFO之分。它们的区别是同步FIFO数据的读写受同一时钟源的控制,而异步FIFO的读写则可以受不同时钟源控制。在这里,我将要介绍的是基于同步的FIFO设计。下面分别介绍基于移位寄存器模式和基于双端口RAM模式的同步FIFO设计。

1、基于移位寄存器的同步FIFO设计

    基于移位寄存器的同步FIFO只需一个读指针,指示FIFO中第一个有效数据,如图1所示。

 基于移位寄存器的FIFO设计.jpg

图1  基于移位寄存器的FIFO读写数据过程

    这里设计一个数据位宽和FIFO深度都可设置的简单FIFO,其实现电路如下所示:

/***************************Copyright*******************************
**                          CrazyBird
**             http://blog.chinaaet.com/crazybird
**
**----------------------File Infomation-----------------------------
** FileName     :   syn_fifo.v
** Author       :   CrazyBird
** Data         :   2015-11-14
** Version      :   v1.0
** Description  :   Synchronous FIFO design based on shift register
**                      
*******************************************************************/
// synopsys translate_off
`timescale 1 ns / 1 ps
// synopsys translate_on
module syn_fifo
#(
    parameter   DATA_WIDTH = 8,
    parameter   FIFO_DEPTH = 8
)
(
    input                           rst_n,
    input                           clk,
    input       [DATA_WIDTH-1:0]    din,
    input                           push,
    input                           pop,
    output      [DATA_WIDTH-1:0]    dout,
    output reg                      full,
    output reg                      empty
);
//------------------------------------------------------------------
//  Parameter definition
localparam  A_EMPTY = 0;
localparam  A_FULL  = FIFO_DEPTH - 2;

//------------------------------------------------------------------
//  Variable definition
reg     [DATA_WIDTH-1:0]    mem [0:FIFO_DEPTH-1];
integer                     read_cnt;
//------------------------------------------------------------------
//  Write data
always @(posedge clk)
begin : shift_reg
    integer i;
    if((push & ~full) == 1'b1)
    begin
        for(i = 0;i < FIFO_DEPTH-1;i = i+1)
            mem[i+1] <= mem[i];
        mem[0] <= din;
    end
end

//------------------------------------------------------------------
//  Read pointer
always @(posedge clk)
begin
    if(rst_n == 1'b0)
        read_cnt <= FIFO_DEPTH-1'b1;
    else if((push & ~pop & ~full) == 1'b1)
    begin
        if(read_cnt == FIFO_DEPTH-1'b1)
            read_cnt <= 0;
        else
            read_cnt <= read_cnt + 1'b1;
    end
    else if((~push & pop & ~empty) == 1'b1)
    begin
        if(read_cnt == A_EMPTY)
            read_cnt <= FIFO_DEPTH-1;
        else
            read_cnt <= read_cnt -1'b1;
    end
end

//------------------------------------------------------------------
//  Empty indicator
always @(posedge clk)
begin
    if(rst_n == 1'b0)
        empty <= 1'b1;
    else if((~push & pop & (read_cnt==A_EMPTY)) == 1'b1)
        empty <= 1'b1;
    else if((push & ~pop) == 1'b1)
        empty <= 1'b0;
end

//------------------------------------------------------------------
//  Full indicator
always @(posedge clk)
begin
    if(rst_n == 1'b0)
        full <= 1'b0;
    else if((push & ~pop & (read_cnt==A_FULL)) == 1'b1)
        full <= 1'b1;
    else if((~push & pop) == 1'b1)
        full <= 1'b0;
end

//------------------------------------------------------------------
//  Data output
assign  dout = (FIFO_DEPTH==1) ? mem[0] : mem[read_cnt];

endmodule
/**************************End File*********************************

    FIFO写仿真波形如图2所示。

移位1.png

图2  FIFO写数据

    FIFO读仿真波形如图3所示。

 移位2.png

图3  FIFO读数据

    此外,该设计还支持同时读写FIFO,但有两个限制。第一个限制是,当FIFO为空时,只支持写操作,不支持同时读写操作;第二个限制是,当为FIFO为满时,只支持读操作,不支持同时读写操作。

2、基于双端口RAM的同步FIFO设计

    基于双端口RAM的同步FIFO需要读指针和写指针两个指针,分别指示读取数据和写数据的位置,如图4所示。

 基于双端口RAM的FIFO设计.jpg

图4  基于双端口RAM的FIFO读写数据过程

    这里设计一个数据位宽和FIFO深度都可设置的简单FIFO,其实现电路如下所示:

/***************************Copyright*******************************
**                          CrazyBird
**             http://blog.chinaaet.com/crazybird
**
**----------------------File Infomation-----------------------------
** FileName     :   syn_fifo.v
** Author       :   CrazyBird
** Data         :   2015-11-14
** Version      :   v1.0
** Description  :   Synchronous FIFO design based on dual port RAM
**                      
*******************************************************************/
// synopsys translate_off
`timescale 1 ns / 1 ps
// synopsys translate_on
module syn_fifo
#(
    parameter   DATA_WIDTH = 8,
    parameter   FIFO_DEPTH = 8
)
(
    input                           rst_n,
    input                           clk,
    input       [DATA_WIDTH-1:0]    din,
    input                           push,
    input                           pop,
    output      [DATA_WIDTH-1:0]    dout,
    output                          full,
    output                          empty
);
//------------------------------------------------------------------
//  Variable definition
reg     [DATA_WIDTH-1:0]    mem [0:FIFO_DEPTH-1];
integer                     read_cnt;
integer                     write_cnt;
integer                     count;

//------------------------------------------------------------------
//  Write data
always @(posedge clk)
begin
    if((push & ~full) == 1'b1)
        mem[write_cnt] <= din;
end

//------------------------------------------------------------------
//  Read and write pointer,number of data in fifo
always @(posedge clk)
begin
    if(rst_n == 1'b0)
    begin
        read_cnt  <= 0;
        write_cnt <= 0;
        count     <= 0;
    end
    else
    begin
        case({push,pop})
            2'b10 : 
            begin
                if(count < FIFO_DEPTH)
                begin
                    count <= count + 1'b1;
                    if(write_cnt < FIFO_DEPTH-1)
                        write_cnt  0)
                begin
                    count <= count - 1'b1;
                    if(read_cnt < FIFO_DEPTH-1)
                        read_cnt <= read_cnt + 1'b1;
                    else
                        read_cnt <= 0;
                end
            end
            2'b11 :
            begin
                if(write_cnt < FIFO_DEPTH-1)
                    write_cnt <= write_cnt + 1'b1;
                else
                    write_cnt <= 0;
                if(read_cnt < FIFO_DEPTH-1)
                    read_cnt <= read_cnt + 1'b1;
                else
                    read_cnt <= 0;
            end
            default : ;
        endcase
    end
end

//------------------------------------------------------------------
//  Data output
assign  full  = (count == FIFO_DEPTH);
assign  empty = (count == 0);
assign  dout  = mem[read_cnt];

endmodule
/**************************End File*********************************

    FIFO写仿真波形如图5所示。

 双1.png

图5  FIFO写数据

    FIFO读仿真波形如图6所示。

 双2.png

图6  FIFO读数据

    该设计也是有一个限制的,就是当为FIFO为满时,只支持读操作,不支持同时读写操作。

3、总结

    由于在设计中我们规定了FIFO满后就不能再写数据,所以导致了基于移位寄存器的FIFO的第二个限制和基于双端口RAM的FIFO的限制。如果想去掉这个限制,节将写FIFO的条件由if((push & ~full) == 1'b1)改为if(push == 1'b1)即可。