An alternative approach to generating full and empty flags in a synchronous FIFO involves extending the read and write pointers by one bit. This method eliminates the need for a separate data counter, relying instead on the pointer arithmetic to determine the FIFO status.
When both the extended read and write pointers are iedntical—including the most significant bit (MSB) and all lower bits—the FIFO contains no data, and the empty flag is asserted. Converse, when the MSBs of the extended pointers differ but the remaining lower bits match, the write pointer has wrapped around exactly one more time than the read pointer. This condition indicates that the FIFO is completely filled, asserting the full flag.
RTL Implementation
module s_fifo #(
parameter W = 8,
parameter D = 16,
parameter A = 4
)(
input wire clk,
input wire rst_n,
input wire push_req,
input wire [W-1:0] push_data,
input wire pop_req,
output reg [W-1:0] pop_data,
output wire is_full,
output wire is_empty
);
reg [A:0] wr_ptr_ext, rd_ptr_ext;
wire [A-1:0] wr_idx = wr_ptr_ext[A-1:0];
wire [A-1:0] rd_idx = rd_ptr_ext[A-1:0];
reg [W-1:0] buffer [D-1:0];
wire push_active = push_req & ~is_full;
wire pop_active = pop_req & ~is_empty;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
wr_ptr_ext <= 0;
end else if (push_active) begin
buffer[wr_idx] <= push_data;
wr_ptr_ext <= wr_ptr_ext + 1'b1;
end
end
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
rd_ptr_ext <= 0;
pop_data <= 0;
end else if (pop_active) begin
pop_data <= buffer[rd_idx];
rd_ptr_ext <= rd_ptr_ext + 1'b1;
end
end
assign is_empty = (rd_ptr_ext == wr_ptr_ext);
assign is_full = (wr_ptr_ext[A] != rd_ptr_ext[A]) &
(wr_ptr_ext[A-1:0] == rd_ptr_ext[A-1:0]);
endmodule
Verification Testbench
`timescale 1ns/1ps
module s_fifo_validator;
parameter W = 8, D = 16, A = 4, T = 10;
reg clk, rst_n, push_req, pop_req;
reg [W-1:0] push_data;
wire is_full, is_empty;
wire [W-1:0] pop_data;
s_fifo u_fifo (
.clk (clk),
.rst_n (rst_n),
.push_req (push_req),
.push_data (push_data),
.pop_req (pop_req),
.pop_data (pop_data),
.is_full (is_full),
.is_empty (is_empty)
);
initial begin
rst_n = 0; clk = 0;
#5 rst_n = 1;
end
always #T clk = ~clk;
initial begin
push_req = 0; pop_req = 0; push_data = 0;
#20;
// Fill the FIFO buffer
push_req = 1;
repeat(D) begin
push_data = push_data + 1;
#(2*T);
end
push_req = 0;
#(2*T);
// Drain the FIFO buffer
pop_req = 1;
repeat(D) begin
#(2*T);
end
pop_req = 0;
#(2*T);
$finish;
end
endmodule