Sync FIFO

below is an implementation for sync fifo which:

  • utilize two pointers for recording write/read position

  • implemente a counter to record used space

  • follow handshake protocol. req_rdy LOW -> full, ack_vld LOW -> empty

  • support user defined payload

  • non-reset mem

//////////////////////////////////////////////////////////////////////////////////
// Company: URBADASS.LTD
// Engineer: zick
//
// Create Date: 02/26/2023 09:01:54 PM
// Design Name: sync fifo handshake
// Module Name: sync_fifo
// Project Name: sync fifo
// Description:
//              a handshake based sync fifo for serialized data
// Dependencies:
//
// Revision:
//              Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module sync_fifo #(
    parameter   int unsigned DEPTH    = 8             ,
    parameter   type         PLD_TYPE = logic[32-1:0] ,
    localparam  int unsigned AWIDTH   = $clog2(DEPTH)
)(
    input   logic               clk    ,
    input   logic               rst_n  ,
    // Req
    input   logic               req_vld,
    output  logic               req_rdy,
    input   PLD_TYPE            req_pld,
    // ACK
    output  logic               ack_vld,
    input   logic               ack_rdy,
    output  PLD_TYPE            ack_pld
);

//=================================================================
// Internal Signal
//=================================================================
    PLD_TYPE                    pld_mem  [DEPTH-1:0];
    logic       [AWIDTH-1  :0]  wr_ptr              ;
    logic       [AWIDTH-1  :0]  rd_ptr              ;
    logic                       rd_en               ;
    logic                       wr_en               ;
    logic       [AWIDTH    :0]  fifo_cnt            ;
    logic                       fifo_full           ;
    logic                       fifo_empty          ;

//=================================================================
// WR/RD enable
//=================================================================
    assign wr_en = req_vld && req_rdy;
    assign rd_en = ack_vld && ack_rdy;

//=================================================================
// depth counter
//=================================================================
    always_ff @(posedge clk or negedge rst_n) begin
        if (~rst_n) begin
            fifo_cnt <= {AWIDTH+1{1'b0}};
        end
        else begin
            case ({rd_en, wr_en})
                {1'b1, 1'b0}: fifo_cnt <= (AWIDTH+1)'(fifo_cnt - 1'b1); // read, old version vcs/xrun does not support type(fifo_cnt)'
                {1'b0, 1'b1}: fifo_cnt <= (AWIDTH+1)'(fifo_cnt + 1'b1); // write
                default     : fifo_cnt <= fifo_cnt;        // no operation or read, write simultaneously
            endcase
        end
    end

//=================================================================
// Empty & Full
//=================================================================
    assign fifo_empty = ~|fifo_cnt;
    assign fifo_full  = fifo_cnt == DEPTH;

//=================================================================
// Handshake
//=================================================================
    assign ack_vld = ~fifo_empty;
    assign req_rdy = ~fifo_full;

//=================================================================
// WR/RD control
//=================================================================
    always_ff @(posedge clk or negedge rst_n) begin
        if (~rst_n) begin
            wr_ptr <= {AWIDTH{1'b0}};
        end
        else if (wr_en) begin
            if (wr_ptr < DEPTH-1)
                wr_ptr <= AWIDTH'(wr_ptr + 1'b1);
            else
                wr_ptr <= {AWIDTH{1'b0}};
        end
    end

    always_ff @(posedge clk or negedge rst_n) begin
        if (~rst_n) begin
            rd_ptr <= {AWIDTH{1'b0}};
        end
        else if (rd_en) begin
            if (rd_ptr < DEPTH-1)
                rd_ptr <= AWIDTH'(rd_ptr + 1'b1);
            else
                rd_ptr <= {AWIDTH{1'b0}};
        end
    end

//=================================================================
// Mem access
//=================================================================
    always_ff @(posedge clk) begin
        if (wr_en) pld_mem[wr_ptr] <= req_pld;
    end
    assign ack_pld = pld_mem[rd_ptr];

endmodule