Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Issues with sync FIFO Implementation in SystemVerilog – Incorrect Data Read & Flag Behavior

naajap

Newbie
Newbie level 1
Joined
Dec 5, 2013
Messages
1
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Activity points
1,286
I'm working on a 4-depth, 8-bit wide FIFO in SystemVerilog. I’ve written both the FIFO module and the testbench, but I’m encountering unexpected behavior in data read operations and flag updates.
Code:
module fifo #(
    parameter DEPTH = 4,  // Depth of the FIFO
    parameter WIDTH = 8   // Width of each entry
)(
    input logic clk,
    input logic rst,
    input logic [WIDTH-1:0] data_in,
    input logic wr_en,
    input logic rd_en,
    output logic [WIDTH-1:0] data_out,
    output logic full,
    output logic empty
);
    logic [WIDTH-1:0] mem [0 : DEPTH-1]; // FIFO memory
    logic [1:0] wr_ptr;  // Write pointer (2-bit for DEPTH=4)
    logic [1:0] rd_ptr;  // Read pointer (2-bit for DEPTH=4)
    logic [2:0] count;   // Counter to track elements (needs 3 bits for DEPTH=4)

    always_ff @(posedge clk or posedge rst) begin
        if (rst) begin
            wr_ptr <= 0;
            rd_ptr <= 0;
            count <= 0;
            full <= 0;
            empty <= 1;
        end else begin
            // Handle simultaneous read and write
            if (wr_en && !full && rd_en && !empty) begin
                mem[wr_ptr] <= data_in; // Write new data
                wr_ptr <= (wr_ptr + 1) % DEPTH;
                rd_ptr <= (rd_ptr + 1) % DEPTH; // Read from FIFO
            end
            // Only write
            else if (wr_en && !full) begin
                mem[wr_ptr] <= data_in;
                wr_ptr <= (wr_ptr + 1) % DEPTH;
                count <= count + 1;
            end
            // Only read
            else if (rd_en && !empty) begin
                data_out <= mem[rd_ptr];
                rd_ptr <= (rd_ptr + 1) % DEPTH;
                count <= count - 1;
            end
         
            // Correctly update full and empty flags
            full <= (count == DEPTH - 1);
            empty <= (count == 0);
        end
    end
endmodule

Code:
module test_fifo;
    // Declare signals
    logic clk;
    logic rst;
    logic [7:0] data_in;
    logic wr_en;
    logic rd_en;
    logic [7:0] data_out;
    logic full;
    logic empty;

    // Instantiate FIFO DUT
    fifo #(4, 8) dut (
        .clk(clk),
        .rst(rst),
        .data_in(data_in),
        .data_out(data_out),
        .wr_en(wr_en),
        .rd_en(rd_en),
        .full(full),
        .empty(empty)
    );

    // Clock generation
    initial begin
        clk = 0;
        forever #5 clk = ~clk;
    end

    // Reset generation
    initial begin
        rst = 1;
        #20 rst = 0;
    end

    // Test sequence
    initial begin
        // Initialize signals
        data_in = 0;
        wr_en = 0;
        rd_en = 0;

        // Wait for reset to complete
        @(negedge rst);

        // Test 1: Write data to FIFO
        $display("Test 1: Writing data to FIFO");
        for (int i = 0; i < 4; i++) begin
            @(posedge clk);
            data_in = i;
            wr_en = 1;
            rd_en = 0;
            $display("Write Data: %h, Full: %b, Empty: %b", data_in, full, empty);
        end
        @(posedge clk);
        wr_en = 0;

        // Test 2: Read data from FIFO
        $display("Test 2: Reading data from FIFO");
        for (int i = 0; i < 4; i++) begin
            @(posedge clk);
            wr_en = 0;
            rd_en = 1;
            $display("Read Data: %h, Full: %b, Empty: %b", data_out, full, empty);
        end
        @(posedge clk);
        rd_en = 0;

        // Test 3: Simultaneous read and write
        $display("Test 3: Simultaneous read and write");
        for (int i = 0; i < 4; i++) begin
            @(posedge clk);
            data_in = i + 4;
            wr_en = 1;
            rd_en = 1;
            $display("Write Data: %h, Read Data: %h, Full: %b, Empty: %b", data_in, data_out, full, empty);
        end
        @(posedge clk);
        wr_en = 0;
        rd_en = 0;

        // Test 4: Test FIFO full condition
        $display("Test 4: Testing FIFO full condition");
        for (int i = 0; i < 5; i++) begin
            @(posedge clk);
            data_in = i + 8;
            wr_en = 1;
            rd_en = 0;
            $display("Write Data: %h, Full: %b, Empty: %b", data_in, full, empty);
        end
        @(posedge clk);
        wr_en = 0;

        // Test 5: Test FIFO empty condition
        $display("Test 5: Testing FIFO empty condition");
        for (int i = 0; i < 5; i++) begin
            @(posedge clk);
            wr_en = 0;
            rd_en = 1;
            $display("Read Data: %h, Full: %b, Empty: %b", data_out, full, empty);
        end
        @(posedge clk);
        rd_en = 0;

        // End simulation
        $display("Simulation completed.");
        $finish;
    end
  endmodule

Test 1: Writing data to FIFO
Write Data: 00, Full: 0, Empty: 1
Write Data: 01, Full: 0, Empty: 1
Write Data: 02, Full: 0, Empty: 0
Write Data: 03, Full: 0, Empty: 0
Test 2: Reading data from FIFO
Read Data: xx, Full: 0, Empty: 0
Read Data: 00, Full: 0, Empty: 0
Read Data: 01, Full: 1, Empty: 0
Read Data: 02, Full: 0, Empty: 0
Test 3: Simultaneous read and write
Write Data: 04, Read Data: 03, Full: 0, Empty: 1
Write Data: 05, Read Data: 03, Full: 0, Empty: 1
Write Data: 06, Read Data: 03, Full: 0, Empty: 0
Write Data: 07, Read Data: 03, Full: 0, Empty: 0
Test 4: Testing FIFO full condition
Write Data: 08, Full: 0, Empty: 0
Write Data: 09, Full: 0, Empty: 0
Write Data: 0a, Full: 1, Empty: 0
Write Data: 0b, Full: 0, Empty: 0
Write Data: 0c, Full: 0, Empty: 0
Test 5: Testing FIFO empty condition
Read Data: 03, Full: 0, Empty: 0
Read Data: 0b, Full: 0, Empty: 0
Read Data: 0c, Full: 0, Empty: 0
Read Data: 08, Full: 0, Empty: 0
Read Data: 09, Full: 1, Empty: 0
Simulation completed.
  1. In my testbench, the first read operation outputs xx, even though data should have been correctly written into the FIFO.
  2. When performing simultaneous read and write operations, I observe unexpected outputs in the Read Data
  3. In Test 4 (FIFO full condition), full is sometimes not asserted when the FIFO is full, and in Test 5, empty remains 0 even when all elements are read.
    Request for Help: How can I ensure that the first read correctly outputs the first written value (00 instead of xx)? Why is the read pointer (rd_ptr) seemingly stuck at 03 during simultaneous read/write? How can I ensure full/empty flags update properly, especially during simultaneous operations?
    Any insights or suggestions would be greatly appreciated. Thanks in advance!
 
Just take a quick look at your RTL code. There's some bugs.
1): doesn't update data_out at this condiction:
1738838029909.png


2): empty, full flag will be 2T delay of FIFO read/write operation.
1738838157299.png

You can choose to use another always block to generate full/empty flag using combination logic.

3): If you want to describe data_out at the same always block, you'd better also give reset value to data_dout (make sure your code is synthesiable).

1738838300404.png



PS: you'd better have deeper understanding of digital circuit before using verilog/sv to coding it.
Digital IC/FPGA Design Part 1: CMOS Gates and Arithmetic Datapath: https://www.udemy.com/course/digita...c-datapath/?referralCode=005DA1FEF9D390C0CCB7
Digital IC/FPGA Design P3: Common Used Hardware Architectures: https://www.udemy.com/course/digita...hitectures/?referralCode=365C67358DCDD5237CCD
 

LaTeX Commands Quick-Menu:

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top