FIFO is an important structure where data is stored and received in ‘First In First Out’ format. Consider an example of students entering a classroom by gate ‘A’ in line, and exiting through gate ‘B’ in the same line. The first student who entered will be the first one to exit the class. This format is referred as ‘first in first out‘.
Let us assume a FIFO has a depth of 8 words and width of 32 bits, the FIFO will be structured as follows:
This data moves in a FIFO in following sequence:
- When there is no data in FIFO, it is called EMPTY. First data is stored into the first FIFO address, second data on second address and so on.
- The data can be stored until FIFO has 8 words. Since the depth of FIFO is 8 words, the FIFO will be flagged as ‘FULL’ after storing 8 words.
- The first data read from the FIFO is from first (0) address, second data from second address and so on.
- The data can be read until FIFO has no data left and the FIFO will be flagged as ‘EMPTY’.
- No data can be written into the FIFO when FIFO is FULL.
- No data can be read from FIFO when FIFO is EMPTY.
There are two kinds of FIFO:
- Synchronous: The read clock and write clock is same. This FIFO is read and written in one clock domain.
- Asynchronous: The read clock is different than write clock. This type of FIFO is used for handling clock domain crossings.
We will concentrate on the Verilog code for Synchronous FIFOs in this article.
1. Define the module name and list the ports.
module sync_fifo (data_in, data_out, clock, reset, wn, rn, full, empty);
2. Mention the direction and type of ports
output reg [7:0] data_out;
output full, empty;
input [7:0] data_in;
input clock, reset;
input wn, rn;
//wn and rn refers to ‘write enable’ and ‘read enable’ signal which indicates if the data is ready to be written into fifo or read from fifo
3. Mention the internal variables to be used while designing the FIFO.
reg [3:0] wptr, rptr; //write and read pointer initialization to keep track of FIFO address
reg [7:0] mem [15:0]; //Memory of Depth ’16’ and Width 8 bits is initialized
reg [3:0] count; //Variable to keep count of the number of elements in FIFO
integer i; //Variable used for iteration in loops
reg w_en, r_en; // Variable which checks ‘full’ and ’empty’ condition
4. Assign values to internal signals as per respective requirements.
//’count‘ is a variable which tracks the number of elements in a FIFO. Hence, ‘full’ and ’empty’ are assigned as follows, based on the value of ‘count’. The FIFO depth is 16 (marked by locations 0:15)
assign full = (count == 15) ? 1 : 0;
assign empty = (count == 0) ? 1 : 0;
//The FIFO should not be written when it is FULL, ‘w_en’ ensures this condition
assign w_en = wn & !full;
// The FIFO should not be read when it is EMPTY, ‘r_en’ ensures this condition
assign r_en = rn & !empty;
5. Write the ‘always’ block which writes into the fifo and reads from it.
always@(posedge clock, negedge reset) begin
if(!reset) begin //Initialize the variables for reset condition (all Os here)
for (i=0;i<16;i=i+1) begin
mem[i] <= 0;
end
data_out <= 0;
wptr <= 0;
rptr <= 0;
end
else begin
if(w_en) begin // Check for FIFO write signal
if (wptr == 4'b1111) begin // Increment the write pointer value
wptr <= 0; // Assign the value of wptr to 0 if it is 15 already
end else begin
wptr <= wptr + 1;
end
mem[wptr] <= data_in; //Write the incoming data into memory at wptr
end else if (r_en) begin // Check for FIFO read signal
if (rptr == 4'b1111) begin // Increment the read pointer value
rptr <= 0; // Assign the value of rptr to 0 if it is 15 already
end else begin
rptr <= rptr + 1;
end
data_out <= mem[rptr]; // Read the rptr memory location
end
end
end
6. Write the second ‘always’ block to keep a check on the number of elements in the FIFO. This helps in checking ‘full’ and ’empty’ condition as seen in step 4.
always@(posedge clock, negedge reset) begin
if(!reset) begin // Reset value of count is 0
count <= 0;
end else begin
if(w_en & !r_en) begin // Condition to indicate WRITE and NOT READ
count <= count + 1; // count is incremented to add written element
end else if(r_en & !w_en) begin // READ and NOT WRITE
count <= count - 1; //count decremented to remove value which was read
end
end
end
endmodule
If you wish to implement this code, just copy the code in ‘blue’ and add a testbench to test it. This is a simple Verilog code. Asynchronous FIFO is more complicated and will be discussed in future articles.
Leave a reply to Anonymous Cancel reply