0
votes

I don't know what is wrong in my code. Refer to the /* status */ comment near the full and empty logic.

I have write pointer wrapping around catching up with read pointer, then wr_addr[3] == ~rd_addr[3] and wr_addr[2:0] == rd_addr[2:0], I have a full condition.

I have read pointer catching up with write pointer, then wr_addr[3:0] == rd_addr[3:0], I have empty.

Please check my code and give me some advice.

I also provide the code on edaplayground (for those of you who have an account there).

module fifo(input clk, rst,
            input wr, rd,
            input [3:0] din,
            output logic [3:0] dout,
            output fifo_full, fifo_empty
);

logic [3:0] w_ptr, r_ptr;
logic w_en, r_en;

status_pointer ptr(clk, rst, wr, rd, w_en, r_en, w_ptr, r_ptr, fifo_full, fifo_empty);
memory mem(clk, w_en, r_en, w_ptr, r_ptr, din, dout);

endmodule

module memory(input clk, we, oe,
          input [3:0] w_ptr, r_ptr,
              input [3:0] din,
              output logic [3:0] dout
);

logic [3:0] mem [7:0];

always_ff @(posedge clk) begin
    if(we & (~ oe)) begin
        mem[w_ptr[2:0]] <= din;
    end
    
    else if((~ we) & oe) begin
        dout <= mem[r_ptr[2:0]];
    end
    
    else if(we & oe) begin
      mem[w_ptr[3:0]] <= din;
      dout <= mem[r_ptr[2:0]];
    end
    
end

endmodule

module status_pointer(input clk, rst,
                input wr, rd,
                output w_en, r_en, 
                output logic [3:0] w_ptr, r_ptr,
                output logic fifo_full, fifo_empty
);


/* status */
always @(posedge clk) begin
        if(rst) begin
            fifo_full <= 0;
            fifo_empty <= 0;
        end
        
        else begin
            if(w_ptr[2:0] == r_ptr[2:0]) begin
                if(w_ptr[3] == r_ptr[3])
                    fifo_empty <= 1;
                else
                    fifo_full <= 1;
            end
            
            else begin
                fifo_full <= fifo_full;
                fifo_empty <= 0;
            end
        end
end


/* pointer */
assign w_en = (fifo_full == 0) & wr;
assign r_en = (fifo_empty == 0) & rd;

always_ff @(posedge clk, posedge rst) begin
        if(rst) begin
            w_ptr <= 4'b0;
            r_ptr <= 4'b0;
        end
        
        else if(w_en & (!r_en)) begin
            w_ptr <= w_ptr + 4'b001;
        end
        
        else if(r_en & (!w_en)) begin
            r_ptr <= r_ptr + 4'b001;
        end
        
        else if(w_en & r_en) begin
            w_ptr <= w_ptr + 4'b001;
            r_ptr <= r_ptr + 4'b001;
        end
        
        else begin
            w_ptr <= w_ptr;
            r_ptr <= r_ptr;
        end
end


endmodule

//// test bench ////

module tb_fifo();

logic clk, rst, wr, rd;
logic [3:0] din, dout;
logic fifo_full, fifo_empty;
logic [4:0] counter;

fifo dut_fifo(clk, rst, wr, rd, din, dout, fifo_full, fifo_empty);

always begin
    clk = 1; #4;
    clk = 0; #4;
end

initial begin
    counter = 5'b00000;
    rst = 0; #240; rst = 1;
end

always @(posedge clk) begin
    if(~ rst) begin
        counter <= counter + 5'b00001;
            
            if(counter == 5'b00000) begin
                wr = 1; rd = 0; din = counter[3:0];
            end
            
            else if(counter == 5'b00001) begin
                wr = 1; rd = 1; din = counter[3:0];
            end
            
            else if(counter == 5'b00010) begin
                wr = 0; rd = 1; din = counter[3:0];
            end
            
            else if(counter == 5'b00011) begin
                wr = 1; rd = 1; din = counter[3:0];
            end
            
            else if(counter == 5'b00100) begin        // [3]
                wr = 1; rd = 0; din = counter[3:0];
            end
            
            else if(counter == 5'b00101) begin        // [3]
                wr = 1; rd = 0; din = counter[3:0];
            end
            
            else if(counter == 5'b00110) begin        // [3]
                wr = 1; rd = 1; din = counter[3:0];
            end
            
            else if(counter == 5'b00111) begin        // [3]
                wr = 1; rd = 1; din = counter[3:0];
            end
            
            else if(counter == 5'b01000) begin        // [3]
                wr = 1; rd = 1; din = counter[3:0];
            end
            
            else if(counter == 5'b01001) begin        // [3]
                wr = 0; rd = 1; din = counter[3:0];
            end
            
            else if(counter == 5'b01010) begin        // [3]
                wr = 0; rd = 1; din = counter[4:1];
            end
            
            else if(counter == 5'b01011) begin        // [3]
                wr = 1; rd = 1; din = counter[3:0];
            end
            
            else if(counter == 5'b01100) begin        // [3]
                wr = 1; rd = 1; din = counter[4:1];
            end
            
            else if(counter == 5'b01101) begin        // [3]
                wr = 0; rd = 1; din = counter[3:0];
            end
            
            else if(counter == 5'b01110) begin        // [3]
                wr = 0; rd = 1; din = counter[3:0];
            end
            
            else if(counter == 5'b01111) begin        // [3]
                wr = 1; rd = 0; din = counter[3:0];
            end
            
            else if(counter == 5'b11111) begin
                $stop;
            end
            
            else begin
                wr = 0; rd = 0;
            end
    end
    
    else begin
        counter <= 5'b00000;
        wr = 0; rd = 0;
    end
end
endmodule
1

1 Answers

0
votes

There is a problem in your testbench. Your design expects an active-high reset. You need to drive rst high starting at time 0 to reset the design, then drop it low after a delay. Just invert how you drive rst. Change:

rst = 0; #240; rst = 1;

to:

rst = 1; #240; rst = 0;