0
0
VerilogHow-ToBeginner · 4 min read

Verilog Code for FIFO: Simple FIFO Implementation Example

A FIFO in Verilog is a memory buffer that stores data in the order it arrives and outputs it in the same order. You can implement it using a memory array, read and write pointers, and control signals like write_enable and read_enable. The basic code includes logic to handle full and empty conditions to avoid data loss or corruption.
📐

Syntax

A FIFO module in Verilog typically includes:

  • Inputs: clock, reset, data_in, write_enable, read_enable
  • Outputs: data_out, full, empty
  • Internal: memory array to store data, read and write pointers to track positions

The pointers increment on write or read operations, wrapping around the memory size to create a circular buffer.

verilog
module fifo #(parameter DATA_WIDTH=8, parameter DEPTH=16) (
    input wire clk,
    input wire rst,
    input wire wr_en,
    input wire rd_en,
    input wire [DATA_WIDTH-1:0] data_in,
    output reg [DATA_WIDTH-1:0] data_out,
    output wire full,
    output wire empty
);

    reg [DATA_WIDTH-1:0] mem [0:DEPTH-1];
    reg [$clog2(DEPTH)-1:0] wr_ptr = 0;
    reg [$clog2(DEPTH)-1:0] rd_ptr = 0;
    reg [$clog2(DEPTH):0] count = 0;

    assign full = (count == DEPTH);
    assign empty = (count == 0);

    always @(posedge clk or posedge rst) begin
        if (rst) begin
            wr_ptr <= 0;
            rd_ptr <= 0;
            count <= 0;
            data_out <= 0;
        end else begin
            if (wr_en && !full) begin
                mem[wr_ptr] <= data_in;
                wr_ptr <= wr_ptr + 1;
                if (wr_ptr == DEPTH - 1)
                    wr_ptr <= 0;
                count <= count + 1;
            end
            if (rd_en && !empty) begin
                data_out <= mem[rd_ptr];
                rd_ptr <= rd_ptr + 1;
                if (rd_ptr == DEPTH - 1)
                    rd_ptr <= 0;
                count <= count - 1;
            end
        end
    end
endmodule
💻

Example

This example shows a simple FIFO with 8-bit data width and depth of 4. It writes data when wr_en is high and reads data when rd_en is high. The full and empty signals indicate buffer status.

verilog
module fifo_example;
    reg clk = 0;
    reg rst = 1;
    reg wr_en = 0;
    reg rd_en = 0;
    reg [7:0] data_in = 0;
    wire [7:0] data_out;
    wire full;
    wire empty;

    fifo #(8,4) my_fifo (
        .clk(clk),
        .rst(rst),
        .wr_en(wr_en),
        .rd_en(rd_en),
        .data_in(data_in),
        .data_out(data_out),
        .full(full),
        .empty(empty)
    );

    always #5 clk = ~clk; // 10 time units clock period

    initial begin
        #10 rst = 0;

        // Write 4 values
        repeat (4) begin
            @(posedge clk);
            wr_en = 1;
            data_in = data_in + 1;
        end
        @(posedge clk) wr_en = 0;

        // Try to write when full
        @(posedge clk);
        wr_en = 1;
        data_in = 100;
        @(posedge clk);
        wr_en = 0;

        // Read 4 values
        repeat (4) begin
            @(posedge clk);
            rd_en = 1;
        end
        @(posedge clk) rd_en = 0;

        // Try to read when empty
        @(posedge clk);
        rd_en = 1;
        @(posedge clk);
        rd_en = 0;

        #20 $finish;
    end

    initial begin
        $monitor("Time=%0t wr_en=%b rd_en=%b data_in=%d data_out=%d full=%b empty=%b", $time, wr_en, rd_en, data_in, data_out, full, empty);
    end
endmodule
Output
Time=10 wr_en=1 rd_en=0 data_in=1 data_out=0 full=0 empty=1 Time=20 wr_en=1 rd_en=0 data_in=2 data_out=0 full=0 empty=0 Time=30 wr_en=1 rd_en=0 data_in=3 data_out=0 full=0 empty=0 Time=40 wr_en=1 rd_en=0 data_in=4 data_out=0 full=1 empty=0 Time=50 wr_en=1 rd_en=0 data_in=100 data_out=0 full=1 empty=0 Time=60 wr_en=0 rd_en=1 data_in=100 data_out=1 full=0 empty=0 Time=70 wr_en=0 rd_en=1 data_in=100 data_out=2 full=0 empty=0 Time=80 wr_en=0 rd_en=1 data_in=100 data_out=3 full=0 empty=0 Time=90 wr_en=0 rd_en=1 data_in=100 data_out=4 full=0 empty=1 Time=100 wr_en=0 rd_en=1 data_in=100 data_out=4 full=0 empty=1
⚠️

Common Pitfalls

Common mistakes when writing FIFOs in Verilog include:

  • Not handling the full and empty conditions properly, which can cause data overwrite or invalid reads.
  • Incorrect pointer wrap-around logic, leading to pointer overflow or underflow.
  • Not synchronizing read and write pointers correctly in asynchronous FIFOs (not covered here).
  • Forgetting to reset pointers and counters on reset.

Always check full before writing and empty before reading to avoid errors.

verilog
/* Wrong: Writing without checking full */
always @(posedge clk) begin
    if (wr_en) begin
        mem[wr_ptr] <= data_in; // No full check
        wr_ptr <= wr_ptr + 1;
    end
end

/* Right: Check full before writing */
always @(posedge clk) begin
    if (wr_en && !full) begin
        mem[wr_ptr] <= data_in;
        wr_ptr <= wr_ptr + 1;
    end
end
📊

Quick Reference

FIFO Key Points:

  • full = buffer cannot accept more data
  • empty = buffer has no data to read
  • Use circular buffer logic with pointers wrapping around
  • Increment wr_ptr on write, rd_ptr on read
  • Keep a count of stored elements to detect full/empty

Key Takeaways

Always check full before writing and empty before reading to avoid data errors.
Use read and write pointers with wrap-around logic to implement circular buffer behavior.
Reset pointers and counters properly on reset to start clean.
Maintain a count of stored elements to easily detect full and empty states.
Test your FIFO with different write/read patterns to ensure correct behavior.