VHDL coding tips and tricks: Basic model of FIFO Queue in VHDL
Contact me for VHDL or Verilog projects and assignments

Wednesday, March 10, 2010

Basic model of FIFO Queue in VHDL

   CODE UPDATED AFTER DEBUGGING ON 23rd Oct 2017!

Here is a basic model of FIFO(first in first out) queue. The code is generic, that means the size of the FIFO can be changed easily without altering the code too much.

FIFO's are generally used in communication systems, to transfer data between two modules, running at different speeds. Based on the difference between the speeds, the depth of FIFO has to be set properly. The more the speed difference, the bigger the fifo should be.

The fifo has two enable signals, enw and enr, used for writing and  reading respectively. Two status bits indicates whether the FIFO is full or empty. Its up to the user, to watch these status signals before reading or writing the fifo.

The code is commented well, and I hope it is easy to understand.


library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity fifo is
generic (depth : integer := 16);  --depth of fifo
port (    clk : in std_logic;
          reset : in std_logic;
          enr : in std_logic;   --enable read,should be '0' when not in use.
          enw : in std_logic;    --enable write,should be '0' when not in use.
          data_in : in std_logic_vector (7 downto 0);     --input data
          data_out : out std_logic_vector(7 downto 0);    --output data
          fifo_empty : out std_logic;     --set as '1' when the queue is empty
          fifo_full : out std_logic     --set as '1' when the queue is full
         );
end fifo;

architecture Behavioral of fifo is

type memory_type is array (0 to depth-1) of std_logic_vector(7 downto 0);
signal memory : memory_type :=(others => (others => '0'));   --memory for queue.
signal readptr,writeptr : integer := 0;  --read and write pointers.
signal empty,full : std_logic := '0';

begin

fifo_empty <= empty;
fifo_full <= full;

process(Clk,reset)
--this is the number of elements stored in fifo at a time.
--this variable is used to decide whether the fifo is empty or full.
variable num_elem : integer := 0;  
begin
if(reset = '1') then
    data_out <= (others => '0');
    empty <= '0';
    full <= '0';
    readptr <= 0;
    writeptr <= 0;
    num_elem := 0;
elsif(rising_edge(Clk)) then
    if(enr = '1and empty = '0') then  --read
        data_out <= memory(readptr);
        readptr <= readptr + 1;      
        num_elem := num_elem-1;
    end if;
    if(enw ='1and full = '0') then    --write
        memory(writeptr) <= data_in;
        writeptr <= writeptr + 1;  
        num_elem := num_elem+1;
    end if;
    --rolling over of the indices.
    if(readptr = depth-1) then      --resetting read pointer.
        readptr <= 0;
    end if;
    if(writeptr = depth-1) then        --resetting write pointer.
        writeptr <= 0;
    end if; 
    --setting empty and full flags.
    if(num_elem = 0) then
        empty <= '1';
    else
        empty <= '0';
    end if;
    if(num_elem = depth) then
        full <= '1';
    else
        full <= '0';
    end if;
end if; 
end process;

end Behavioral;


The above program shows an approach towards modeling a FIFO.The actual FIFO used in communication protocols etc is more complex than the one given here.I recommend you to use CoreGen software from Xilinx for,generating code for complex FIFO's.

The following testbench, tests the design with few inputs. Please note that, the code might still have some bugs. In that case, please put down a comment so that I can rectify it. Thanks.

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.std_logic_arith.ALL;

ENTITY fifo_tb IS
END fifo_tb;

ARCHITECTURE behavior OF fifo_tb IS 
   --Inputs and outputs
   signal Clk,reset,enr,enw,empty,full : std_logic := '0';
   signal data_in,data_out : std_logic_vector(7 downto 0) := (others => '0');
    --temporary signals
    signal i : integer := 0;
   -- Clock period definitions
   constant Clk_period : time := 10 ns;
    constant depth : integer := 16;  --specify depth of fifo here.

BEGIN

    -- Instantiate the Unit Under Test (UUT)
   uut: entity work.fifo generic map(depth => depth) PORT MAP (clk,reset,enr,enw,data_in,data_out,empty,full);

   -- Clock process definitions
   Clk_process :process
   begin
        Clk <= '0';
        wait for Clk_period/2;
        Clk <= '1';
        wait for Clk_period/2;
   end process;

   -- Stimulus process
   stim_proc: process
   begin        
        reset <= '1';  --apply reset for one clock cycle.
        wait for clk_period;
        reset <= '0';
        wait for clk_period*3;  --wait for 3 clock periods(simply)
        enw <= '1';     enr <= '0';         --write 10 values to fifo.
      for i in 1 to 10 loop  
            Data_In <= conv_std_logic_vector(i,8);
            wait for clk_period;
      end loop; 
        enw <= '0';     enr <= '1';         --read 4 values from fifo.
      wait for clk_period*4;
        enw <= '0';     enr <= '0'; 
        wait for clk_period*10;  --wait for some clock cycles.
        enw <= '1';     enr <= '0';         --write 10 values to fifo.
      for i in 11 to 20 loop  
            Data_In <= conv_std_logic_vector(i,8);
            wait for clk_period;
      end loop; 
        enw <= '0';     enr <= '0'; 
        wait for clk_period*10;  --wait for some clock cycles.
        enw <= '0';     enr <= '1';         --read 4 values from fifo.
      wait for clk_period*4;
        enw <= '0';     enr <= '0';
        wait for clk_period;
        enw <= '0';     enr <= '1';         --read 4 values from fifo.
      wait for clk_period*8;
        enw <= '0';     enr <= '0'; 
        wait for clk_period;
        enw <= '0';     enr <= '1';         --read 8 values from fifo.
      wait for clk_period*4;
        enw <= '0';     enr <= '0'; 
        wait for clk_period;
        enw <= '0';     enr <= '1';         --read 4 values from fifo.
      wait for clk_period*4;
        enw <= '0';     enr <= '0';     
        wait;
   end process;

END;

The design was tested successfully using Xilinx ISE 14.6. Synthesizing the design for Virtex 6 fpga, showed a maximum clock frequency of 250 MHz.  

11 comments:

  1. --these are evil:
    use IEEE.STD_LOGIC_ARITH.ALL;
    use IEEE.STD_LOGIC_UNSIGNED.ALL;

    --use this instead:
    use ieee.numeric_std.all;

    ReplyDelete
  2. @anonymous : please see this post,
    http://vhdlguru.blogspot.com/2010/03/why-library-numericstd-is-preferred.html

    ReplyDelete
  3. library IEEE;
    use IEEE.STD_LOGIC_1164.ALL;
    use IEEE.STD_LOGIC_ARITH.ALL;
    use IEEE.STD_LOGIC_UNSIGNED.ALL;

    entity fifo is
    GENERIC
    (
    ADDRESS_WIDTH : integer:=8;---8 bit
    DATA_WIDTH : integer:=32 ---32 bit
    );

    port ( clk : in std_logic;
    reset : in std_logic;
    enr : in std_logic; --enable read,should be '0' when not in use.
    enw : in std_logic; --enable write,should be '0' when not in use.
    dataout : out std_logic_vector(DATA_WIDTH-1 downto 0); --output data
    datain : in std_logic_vector (DATA_WIDTH-1 downto 0); --input data
    empty : out std_logic; --set as '1' when the queue is empty
    err : out std_logic;
    full : out std_logic --set as '1' when the queue is full
    );
    end fifo;

    architecture Behavioral of fifo is

    type memory_type is array (0 to ((2**ADDRESS_WIDTH)-1)) of std_logic_vector(DATA_WIDTH-1 downto 0);


    -----distributed-------
    signal memory : memory_type ;-- :=(others => (others => '0')); --memory for queue.-----
    signal readptr,writeptr : std_logic_vector(ADDRESS_WIDTH-1 downto 0); --read and write pointers.
    signal full0 : std_logic;
    signal empty0 : std_logic;

    begin
    full <= full0;
    empty <= empty0;

    fifo0: process(clk,reset)
    begin
    if reset='1' then

    readptr <= (others => '0');
    writeptr <= (others => '0');
    empty0 <='1';
    full0<='0';
    err<='0';


    elsif rising_edge(clk) then

    if (writeptr + '1' = readptr) then
    full0<='1';
    else
    full0<='0';
    end if ;

    if (readptr = writeptr ) then
    empty0<='1';
    else
    empty0<='0';
    end if ;

    if (empty0='0' and enr='1') or (full0='0' and enw='1') then
    err<='1';
    end if ;

    if enw='1' and full0='0' then
    memory (conv_integer(writeptr)) <= datain ;
    writeptr <= writeptr + '1' ;
    end if ;

    if enr='1' and empty0='0' then
    dataout <= memory (conv_integer(readptr));
    readptr <= readptr + '1' ;
    end if ;

    end if;

    end process;
    end Behavioral;




    fix fifo doal port ram

    ReplyDelete
  4. it is ram block and not distributed in my comment

    ReplyDelete
  5. This example is wrong, please correct or remove it; many people have copied it from your website and are wasting a lot of time wondering why it does not work.

    One of the reasons why it is wrong: to generate the "empty" and "full" flags, signals "readptr" and "writeptr" should be compared with one another, and NOT with absolute values. Cohen's example above is on the right direction.

    To be fair, the presented code is a FIFO in the sense that the first value in is the first value out, but it requires a reset every 256 elements. This is *not* what people want, in 99.99% of the cases.

    ReplyDelete
  6. Agree with Jasinski. The FIFO full/empty conditions should be more like the following: (note that in this example, the pointers are definted as integers by the ieee.numeric.std)

    if(writeptr = readptr) then
    FIFO_EMPTY <='1';
    else
    FIFO_EMPTY <='0';
    end if;

    if(writeptr = (readptr - 1)) then
    FIFO_FULL <='1';
    else
    FIFO_FULL <='0';
    end if;

    The empty condition occurs when you read the last value written, hence comparing them to each other. Full occurs when you write so many values that you fill up to one less than the last value read.

    ReplyDelete
  7. roei cohen variant is mostly correct except one thing: active "full" value will be sensed by wrighting block on 1 clk later, so it will try to write data to FIFO when it's already restricted.

    ReplyDelete
  8. I think in stead of error <=0; ,enr<=0; will be there;

    ReplyDelete
  9. hi I need a READY QUEUE with priority any help?????????

    ReplyDelete