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.
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
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.
In my testbench, the first read operation outputs xx, even though data should have been correctly written into the FIFO.
When performing simultaneous read and write operations, I observe unexpected outputs in the Read Data
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 ensurefull
/empty
flags update properly, especially during simultaneous operations?Any insights or suggestions would be greatly appreciated.
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.
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
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.
In my testbench, the first read operation outputs xx, even though data should have been correctly written into the FIFO.
When performing simultaneous read and write operations, I observe unexpected outputs in the Read Data
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 ensurefull
/empty
flags update properly, especially during simultaneous operations?Any insights or suggestions would be greatly appreciated.
1 Answer
Reset to default 0Any insights or suggestions would be greatly appreciated.
From the comments on the question, it looks like you already fixed the testbench timing problems.
To help with debugging, you should always add the simulation time to the $display
statements. For example:
$display($time, " Write Data: %h, Full: %b, Empty: %b", data_in, full, empty);
For designs like this, it is insufficient to debug only using $display
statements. You must view simulation waveforms.
You have bugs in the fifo
design logic, specifically the flags and the pointers. Essentially, you need to redesign the FIFO.
The % DEPTH
code looks suspect; I don't think you need that since the pointers are only 2-bit.
With read and write pointers, I don't think there is any need for a separate counter (count
).
I recommend looking at other Verilog FIFO code on the internet. For example: FIFO on the VLSI Verify site.
negedge
of the clock makes it easer to debug the simulation. – dave_59 Commented Feb 6 at 5:22