Skip to main content

FIFO(First In First Out) Buffer in Verilog

A FIFO(First in First Out) buffer is an elastic storage usually used between two subsystems. As the name indicates the memory that is first written into the FIFO is the first to be read or processed. A FIFO has two control signals i.e. write and read. When write is enabled data is written into the buffer and when read is enabled data is "removed" from the buffer to make room for more data. This concept of write and read (remove) can be best understood from the conceptual diagram of a FIFO below:

As can be seen, once the data is read, it can be considered as removed and thus allowing more data to be written into the buffer.

Implementation of FIFO in Verilog

To implement FIFO in verilog imagine the memory components to be arranged in a circular queue fashion with two pointers; write and read. The write pointer points to the start of the circle whereas the read pointer points to the end of the circle. Both these pointers increment themselves by one after each read or write operation.
This buffer will also consist of two flags; empty and full. These will help in indicating when the FIFO is full (cannot be written to) or empty (cannot be read from). This circular implementation can be seen from the following figure:


The size of the FIFO buffer greatly depends on the number of address bits. As the number of words in fifo = 2^(number of address bits). The FIFO I will be coding here will consist of 16 memory elements ( 4 bits in each memory element and 3 address bits). This can be easily changed by changing the parameters in the code, by doing so you can create a buffer of any size. The parameters can be changed from the following line:

module fifo # (parameter abits = 4, dbits = 3)

At reset the empty flag is set to high whereas the full flag is set to low to allow new data to be written. The positions of the read and write pointers are also initialized to 0. The verilog code is shown below. It has been commented in detail so I hope each step is clear.

module fifo # (parameter abits = 4, dbits = 3)(
    input clock,
    input reset,
    input wr,
    input rd,
  input [dbits-1:0] din,
    output empty,
    output full,
  output [dbits-1:0] dout
    );

wire db_wr, db_rd;
reg dffw1, dffw2, dffr1, dffr2;
reg [dbits-1:0] out;

always @ (posedge clock) dffw1 <= wr; 
always @ (posedge clock) dffw2 <= dffw1;

assign db_wr = ~dffw1 & dffw2; //monostable multivibrator to detect only one pulse of the button

always @ (posedge clock) dffr1 <= rd;
always @ (posedge clock) dffr2 <= dffr1;

assign db_rd = ~dffr1 & dffr2; //monostable multivibrator to detect only one pulse of the button


reg [dbits-1:0] regarray[2**abits-1:0]; //number of words in fifo = 2^(number of address bits)
reg [abits-1:0] wr_reg, wr_next, wr_succ; //points to the register that needs to be written to
reg [abits-1:0] rd_reg, rd_next, rd_succ; //points to the register that needs to be read from
reg full_reg, empty_reg, full_next, empty_next;

assign wr_en = db_wr & ~full; //only write if write signal is high and fifo is not full

//always block for write operation
always @ (posedge clock)
 begin
  if(wr_en)
   regarray[wr_reg] <= din;  //at wr_reg location of regarray store what is given at din

 end
 
//always block for read operation
always @ (posedge clock)
 begin
  if(db_rd)
   out <= regarray[rd_reg];
 end
 

always @ (posedge clock or posedge reset)
 begin
  if (reset)
   begin
   wr_reg <= 0;
   rd_reg <= 0;
   full_reg <= 1'b0;
   empty_reg <= 1'b1;
   end
  
  else
   begin
   wr_reg <= wr_next; //created the next registers to avoid the error of mixing blocking and non blocking assignment to the same signal
   rd_reg <= rd_next;
   full_reg <= full_next;
   empty_reg <= empty_next;
   end
 end
 
always @(*)
 begin
  wr_succ = wr_reg + 1; //assigned to new value as wr_next cannot be tested for in same always block
  rd_succ = rd_reg + 1; //assigned to new value as rd_next cannot be tested for in same always block
  wr_next = wr_reg;  //defaults state stays the same
  rd_next = rd_reg;  //defaults state stays the same
  full_next = full_reg;  //defaults state stays the same
  empty_next = empty_reg;  //defaults state stays the same
  
   case({db_wr,db_rd})
    //2'b00: do nothing LOL..
    
    2'b01: //read
     begin
      if(~empty) //if fifo is not empty continue
       begin
        rd_next = rd_succ;
        full_next = 1'b0;
       if(rd_succ == wr_reg) //all data has been read
         empty_next = 1'b1;  //its empty again
       end
     end
    
    2'b10: //write
     begin
      
      if(~full) //if fifo is not full continue
       begin
        wr_next = wr_succ;
        empty_next = 1'b0;
        if(wr_succ == (2**abits-1)) //all registers have been written to
         full_next = 1'b1;   //its full now
       end
     end
     
    2'b11: //read and write
     begin
      wr_next = wr_succ;
      rd_next = rd_succ;
     end
     //no empty or full flag will be checked for or asserted in this state since data is being written to and read from together it can  not get full in this state.
    endcase
   

 end

assign full = full_reg;
assign empty = empty_reg;
assign dout = out;
endmodule

Comments

  1. Thank you, this was very well explained, and useful code too :)

    ReplyDelete
  2. Well explained and quite useful article, Let me know how i can help you in return !!!

    ReplyDelete
  3. Well explained article and quite useful !!, You should be rewarded

    ReplyDelete
  4. sir ....i need a help...........ur code was so useful............but i m not understanding some portion of ur code.....

    so i have modified the code according to what i understand and this code is working also............i am pasting my code below.........i just want you to tell me whether this code will work on my fpga..........should i change something according to my fpga clock generator 20Mhz...........


    module fifoo(wr,rd,clock,reset,din,dout);
    input wr,rd,clock,reset;
    input [2:0] din;
    output reg [2:0] dout;
    reg full,empty;
    reg [2:0] wr_ptr,rd_ptr;
    reg [2:0] regarray [2**2-1:0];

    assign wr_en=wr&(~full);
    always@(posedge clock)
    begin
    if(wr_en)
    begin
    regarray[wr_ptr]=din;
    #1 $display("written %b %b",wr_ptr,regarray[wr_ptr]);
    wr_ptr=wr_ptr+1'b1;
    end
    end

    assign rd_en=rd&(~empty);
    always@(posedge clock)
    begin
    if(rd_en)
    begin
    dout=regarray[rd_ptr];
    #1 $display("read %b %b",rd_ptr,regarray[rd_ptr]);
    rd_ptr=rd_ptr+1'b1;
    end
    end

    always@(posedge reset)
    begin
    wr_ptr=1'b0;
    rd_ptr=1'b0;
    full=1'b0;
    empty=1'b1;
    end

    always@(*)
    begin
    case({rd,wr})
    2'b01: //write
    begin
    if(~full)
    begin
    empty=1'b0;
    if(wr_ptr==2**2)
    begin
    full=1'b1;
    $display("fifo full............cannot write");
    end
    end
    end
    2'b10: //read
    begin
    if(~empty)
    begin
    full=1'b0;
    if(rd_ptr==2**2)
    begin
    empty=1'b1;
    $display("fifo empty............cannot read");
    end
    end
    end
    endcase
    end
    endmodule

    module tb_fifoo();
    wire [2:0] dout;
    reg wr,rd,clock,reset;
    reg [2:0] din;
    fifoo mm(wr,rd,clock,reset,din,dout);
    initial
    begin
    clock=1'b0;
    reset=1'b1;
    wr=1'b1;
    rd=1'b0;
    din=3'b111;
    #2;
    clock=1'b1;
    reset=1'b0;
    wr=1'b1;
    rd=1'b0;
    din=3'b111;
    #2;
    clock=1'b0;
    reset=1'b0;
    wr=1'b1;
    rd=1'b0;
    din=3'b101;
    #2;
    clock=1'b1;
    reset=1'b0;
    wr=1'b1;
    rd=1'b0;
    din=3'b101;
    #2;
    clock=1'b0;
    reset=1'b0;
    wr=1'b1;
    rd=1'b0;
    din=3'b110;
    #2;
    clock=1'b1;
    reset=1'b0;
    wr=1'b1;
    rd=1'b0;
    din=3'b110;
    #2;
    clock=1'b0;
    reset=1'b0;
    wr=1'b1;
    rd=1'b0;
    din=3'b101;
    #2;
    clock=1'b1;
    reset=1'b0;
    wr=1'b1;
    rd=1'b0;
    din=3'b101;
    #2;
    clock=1'b0;
    reset=1'b0;
    wr=1'b1;
    rd=1'b0;
    din=3'b101;
    #2;
    clock=1'b1;
    reset=1'b0;
    wr=1'b1;
    rd=1'b0;
    din=3'b101;
    #2;
    clock=1'b0;
    reset=1'b0;
    wr=1'b1;
    rd=1'b0;
    din=3'b110;
    #2;
    clock=1'b1;
    reset=1'b0;
    wr=1'b1;
    rd=1'b0;
    din=3'b110;
    #2;
    clock=1'b0;
    reset=1'b0;
    wr=1'b0;
    rd=1'b1;
    #2;
    clock=1'b1;
    reset=1'b0;
    wr=1'b0;
    rd=1'b1;
    #2;
    clock=1'b0;
    reset=1'b0;
    wr=1'b0;
    rd=1'b1;
    #2;
    clock=1'b1;
    reset=1'b0;
    wr=1'b0;
    rd=1'b1;
    #2
    clock=1'b0;
    reset=1'b0;
    wr=1'b0;
    rd=1'b1;
    #2;
    clock=1'b1;
    reset=1'b0;
    wr=1'b0;
    rd=1'b1;
    #2
    clock=1'b0;
    reset=1'b0;
    wr=1'b0;
    rd=1'b1;
    #2;
    clock=1'b1;
    reset=1'b0;
    wr=1'b0;
    rd=1'b1;
    #2;
    clock=1'b0;
    reset=1'b0;
    wr=1'b0;
    rd=1'b1;
    #2;
    clock=1'b1;
    reset=1'b0;
    wr=1'b0;
    rd=1'b1;
    #2;
    clock=1'b0;
    reset=1'b0;
    wr=1'b1;
    rd=1'b0;
    din=3'b101;
    #2;
    clock=1'b1;
    reset=1'b0;
    wr=1'b1;
    rd=1'b0;
    din=3'b101;
    #2;
    clock=1'b0;
    reset=1'b0;
    wr=1'b0;
    rd=1'b1;
    #2;
    clock=1'b1;
    reset=1'b0;
    wr=1'b0;
    rd=1'b1;
    #2;
    clock=1'b0;
    reset=1'b1;
    wr=1'b0;
    rd=1'b1;
    #2;
    clock=1'b1;
    reset=1'b0;
    wr=1'b0;
    rd=1'b1;
    #2;
    clock=1'b0;
    reset=1'b0;
    wr=1'b1;
    rd=1'b0;
    din=3'b101;
    #2;
    clock=1'b1;
    reset=1'b0;
    wr=1'b1;
    rd=1'b0;
    din=3'b101;
    #2;
    clock=1'b0;
    reset=1'b0;
    wr=1'b0;
    rd=1'b1;
    #2;
    clock=1'b1;
    reset=1'b0;
    wr=1'b0;
    rd=1'b1;
    end
    endmodule

    ReplyDelete
    Replies
    1. Since this code has nothing to do with timekeeping, unlike the stopwatch code, then in my opinion the frequency of the clock should not have any effect on it. This should work the same on your 20MHz board the same as it is working on my 50MHz board.

      Delete
  5. Hello Sir ,I just want to know why have you used the dffr1 and dffr2

    ReplyDelete
    Replies
    1. dffr1 and dffr2 are used to prevent multiple button press detections per clock cycle. In other words it is a very simple debouncing circuit

      Delete
  6. Could you help to simulate this code on xilinx ise project navigator PSE.20131013

    ReplyDelete
  7. Hi! Thank you for your code, it is really helpful for me because i'm new in verilog description. I didn't get one point, how could you check the content of empty signal, that is an output for the module, and make a condition on its value in the case statement? Thank you in advance for your reply, I mean the if(~empty) check.

    ReplyDelete

Post a Comment

Popular posts from this blog

To Code a Stopwatch in Verilog

The stopwatch coded here will be able to keep time till 10 minutes. It will be a 4 digit stopwatch counting from 0:00:0 till 9:59:9. The right most digit will be incremented every 0.1 second, when it reaches 9 it will increment the middle two digits, which represent the second count. When it reaches 59 seconds it will increment the right most minute display. The stopwatch will be in the format M:SS:D. How to Create an Accurate Delay in Verilog: To make the stop watch an accurate device we need to be able to produce an accurate 0.1 second delay. I have already explained how to do this before in my decimal counter in verilog post. But since it is of great importance to the design will be explained in more detail here. Since we know that the BASYS2 (the one I am using, yours may be different) has a 50 MHz clock which means that the clock cycle is repeated 50M times in one second. So to create a 0.1 second delay we multiply the clock with the required time: 50MHz * 0.1 sec = ...

Seven Segment LED Multiplexing Circuit in Verilog

The seven segment LED circuit uses seven different and individual LED's to display a hexadecimal symbol. It has 7 wires to control the individual LED's one wire to control the decimal point and one enable wire. The demo board I am using here consists of four such 7-segment LED's(As do any other demo board). To reduce the number of wires a multiplexing circuit is used to control the display. Using the multiplexing circuit the number of wires required to light up all 4 displays are reduced from 32 to 12 (8 data bits and 4 enable bits). All bits here are active low, such that to enable them a '0' is required. For example the figure below shows how to display a 3 on the seven segment. The multiplexing circuit can take 4 inputs and have only one output. But the inputs should be displayed on the output fast enough to fool the viewer into thinking all outputs are enabled individually and simultaneously. This is achieved by having an enable signal that changes so fast t...

Random Number Generator in Verilog | FPGA

In verilog a random number can be generated by using the $random keyword but that works only for simulation purposes and cannot be implemented. So when we need a random number for implementation i.e. in hardware it can be achieved using an LFSR (Liner Feedback Shift Register). An LFSR is simply a shift register with some of its bits (known as taps) XOR'd with themselves to create a feedback term. When implementing an LFSR it's width and it's repeatability must be kept under consideration .An N-bit LFSR will be able to generate (2**N) - 1 random bits before it starts repeating. For example a 30 bit LFSR will have 1073741823 random states before repeating, so for most practical purposes this can be considered true random. In an LFSR the MSB will always be the feedback point also the main thing to take care of while coding an LFSR is to know which bits are the taps (to be selected for XOR ). This is confusing as the taps are different for different size registers. For e...