Verilog Code for FIFO: Simple FIFO Implementation Example
A FIFO in Verilog is a memory buffer that stores data in the order it arrives and outputs it in the same order. You can implement it using a memory array, read and write pointers, and control signals like
write_enable and read_enable. The basic code includes logic to handle full and empty conditions to avoid data loss or corruption.Syntax
A FIFO module in Verilog typically includes:
- Inputs: clock, reset, data_in, write_enable, read_enable
- Outputs: data_out, full, empty
- Internal: memory array to store data, read and write pointers to track positions
The pointers increment on write or read operations, wrapping around the memory size to create a circular buffer.
verilog
module fifo #(parameter DATA_WIDTH=8, parameter DEPTH=16) ( input wire clk, input wire rst, input wire wr_en, input wire rd_en, input wire [DATA_WIDTH-1:0] data_in, output reg [DATA_WIDTH-1:0] data_out, output wire full, output wire empty ); reg [DATA_WIDTH-1:0] mem [0:DEPTH-1]; reg [$clog2(DEPTH)-1:0] wr_ptr = 0; reg [$clog2(DEPTH)-1:0] rd_ptr = 0; reg [$clog2(DEPTH):0] count = 0; assign full = (count == DEPTH); assign empty = (count == 0); always @(posedge clk or posedge rst) begin if (rst) begin wr_ptr <= 0; rd_ptr <= 0; count <= 0; data_out <= 0; end else begin if (wr_en && !full) begin mem[wr_ptr] <= data_in; wr_ptr <= wr_ptr + 1; if (wr_ptr == DEPTH - 1) wr_ptr <= 0; count <= count + 1; end if (rd_en && !empty) begin data_out <= mem[rd_ptr]; rd_ptr <= rd_ptr + 1; if (rd_ptr == DEPTH - 1) rd_ptr <= 0; count <= count - 1; end end end endmodule
Example
This example shows a simple FIFO with 8-bit data width and depth of 4. It writes data when wr_en is high and reads data when rd_en is high. The full and empty signals indicate buffer status.
verilog
module fifo_example;
reg clk = 0;
reg rst = 1;
reg wr_en = 0;
reg rd_en = 0;
reg [7:0] data_in = 0;
wire [7:0] data_out;
wire full;
wire empty;
fifo #(8,4) my_fifo (
.clk(clk),
.rst(rst),
.wr_en(wr_en),
.rd_en(rd_en),
.data_in(data_in),
.data_out(data_out),
.full(full),
.empty(empty)
);
always #5 clk = ~clk; // 10 time units clock period
initial begin
#10 rst = 0;
// Write 4 values
repeat (4) begin
@(posedge clk);
wr_en = 1;
data_in = data_in + 1;
end
@(posedge clk) wr_en = 0;
// Try to write when full
@(posedge clk);
wr_en = 1;
data_in = 100;
@(posedge clk);
wr_en = 0;
// Read 4 values
repeat (4) begin
@(posedge clk);
rd_en = 1;
end
@(posedge clk) rd_en = 0;
// Try to read when empty
@(posedge clk);
rd_en = 1;
@(posedge clk);
rd_en = 0;
#20 $finish;
end
initial begin
$monitor("Time=%0t wr_en=%b rd_en=%b data_in=%d data_out=%d full=%b empty=%b", $time, wr_en, rd_en, data_in, data_out, full, empty);
end
endmoduleOutput
Time=10 wr_en=1 rd_en=0 data_in=1 data_out=0 full=0 empty=1
Time=20 wr_en=1 rd_en=0 data_in=2 data_out=0 full=0 empty=0
Time=30 wr_en=1 rd_en=0 data_in=3 data_out=0 full=0 empty=0
Time=40 wr_en=1 rd_en=0 data_in=4 data_out=0 full=1 empty=0
Time=50 wr_en=1 rd_en=0 data_in=100 data_out=0 full=1 empty=0
Time=60 wr_en=0 rd_en=1 data_in=100 data_out=1 full=0 empty=0
Time=70 wr_en=0 rd_en=1 data_in=100 data_out=2 full=0 empty=0
Time=80 wr_en=0 rd_en=1 data_in=100 data_out=3 full=0 empty=0
Time=90 wr_en=0 rd_en=1 data_in=100 data_out=4 full=0 empty=1
Time=100 wr_en=0 rd_en=1 data_in=100 data_out=4 full=0 empty=1
Common Pitfalls
Common mistakes when writing FIFOs in Verilog include:
- Not handling the
fullandemptyconditions properly, which can cause data overwrite or invalid reads. - Incorrect pointer wrap-around logic, leading to pointer overflow or underflow.
- Not synchronizing read and write pointers correctly in asynchronous FIFOs (not covered here).
- Forgetting to reset pointers and counters on reset.
Always check full before writing and empty before reading to avoid errors.
verilog
/* Wrong: Writing without checking full */ always @(posedge clk) begin if (wr_en) begin mem[wr_ptr] <= data_in; // No full check wr_ptr <= wr_ptr + 1; end end /* Right: Check full before writing */ always @(posedge clk) begin if (wr_en && !full) begin mem[wr_ptr] <= data_in; wr_ptr <= wr_ptr + 1; end end
Quick Reference
FIFO Key Points:
full= buffer cannot accept more dataempty= buffer has no data to read- Use circular buffer logic with pointers wrapping around
- Increment
wr_ptron write,rd_ptron read - Keep a
countof stored elements to detect full/empty
Key Takeaways
Always check full before writing and empty before reading to avoid data errors.
Use read and write pointers with wrap-around logic to implement circular buffer behavior.
Reset pointers and counters properly on reset to start clean.
Maintain a count of stored elements to easily detect full and empty states.
Test your FIFO with different write/read patterns to ensure correct behavior.