Synchronous FIFO

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:

  1. 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.
  2. 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.
  3. The first data read from the FIFO is from first (0) address, second data from second address and so on.
  4. The data can be read until FIFO has no data left and the FIFO will be flagged as ‘EMPTY’.
  5. No data can be written into the FIFO when FIFO is FULL.
  6. 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.


Comments

6 responses to “Synchronous FIFO”

  1. satyam singh Avatar
    satyam singh

    I have a doubt on this about width and depth. This current implementation has 16 depth and 8-bit width. Please correct me If I understand it incorrectly. Thank you for the informative post.

    Liked by 1 person

    1. richamittal10 Avatar
      richamittal10

      Yes you are right, I need to correct the typo.

      Like

    2.  Avatar
      Anonymous

      1%2527%2522

      Like

  2. Good. I would recommend going for parametrized fifo design. the design needs to be scalable.

    Like

    1. richamittal10 Avatar
      richamittal10

      Yes, this isn’t the best design but simple one.

      Like

  3. Varada Akhil Kumar Avatar
    Varada Akhil Kumar

    Mam please keep these type of posts regarding verilog. Thank u ma.

    Liked by 1 person

Leave a reply to Varada Akhil Kumar Cancel reply