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