Implementing a FIFO using Verilog
A FIFO or Queue is an array of memory commonly used in
hardware to transfer transfer data between two circuits with different
clocks. There are many other use of FIFO also. FIFO uses a dual port memory and there will be two pointers to point
read and write addresses. Here is a generalized block diagram of FIFO.
Generally fifos are implemented using rotating pointers.
We can call write and read pointers of a FIFO as head and tail of data area.
Initially read and write pointers of the FIFO will point to the same
location. In a fifo with n locations, after writing data to 'n'th location,
write pointer points to 0th location.
Here is an
example to explain how FIFO uses the memory. This is a fifo of length 8, WP
and RP are the locations where write pointer and read pointer points. Shaded
area in the diagram is filled with data.
One
data pushed to fifo: |
RP |
WP |
|
|
|
|
|
|
5
more data pushed to fifo |
RP |
|
|
|
|
|
WP |
|
3
data popped from fifo |
|
|
|
RP |
|
|
WP |
|
3
more data pushed to fifo |
|
WP |
|
RP |
|
|
|
|
2
more data pushed to fifo: fifo full |
|
|
|
WP, RP |
|
|
|
|
6
data popped from fifo |
|
RP |
|
WP |
|
|
|
|
A FIFO may
be synchronous or asynchronous. There is no clock in asynchronous fifo. In
synchronous fifo, there may be 1 or 2 clocks since some FIFOs have separate
clocks for read and write. Asynchronous fifos are not used commonly now a
days because synchronous FIFOs have improved interface timing.
`define BUF_WIDTH 3 // BUF_SIZE = 16 -> BUF_WIDTH = 4, no. of bits to be used in pointer
`define BUF_SIZE ( 1<<`BUF_WIDTH )
module fifo( clk, rst, buf_in, buf_out, wr_en, rd_en, buf_empty, buf_full, fifo_counter );
input rst, clk, wr_en, rd_en;
// reset, system clock, write enable and read enable.
input [7:0] buf_in;
// data input to be pushed to buffer
output[7:0] buf_out;
// port to output the data using pop.
output buf_empty, buf_full;
// buffer empty and full indication
output[`BUF_WIDTH :0] fifo_counter;
// number of data pushed in to buffer
reg[7:0] buf_out;
reg buf_empty, buf_full;
reg[`BUF_WIDTH :0] fifo_counter;
reg[`BUF_WIDTH -1:0] rd_ptr, wr_ptr; // pointer to read and write addresses
reg[7:0] buf_mem[`BUF_SIZE -1 : 0]; //
always @(fifo_counter)
begin
buf_empty = (fifo_counter==0);
buf_full = (fifo_counter== `BUF_SIZE | |