Inferred FIFO

From Hamsterworks Wiki!

Jump to: navigation, search

This FPGA Project was completed in October 2014.

The Xilinx CoreGen FIFO generator can generate a whole heap of different FIFOs - block ram based, LUT based, common clocks, different clocks and they are all guaranteed to work. So why would I want to write my own FIFO?

a) The copyright on the generated files are owned by Xilinx, and should not be given to anybody who hasn't agreed to the Xilinx licensing.

b) If you need to change anything the CoreGen takes are really long time to regenerate FIFO - long enough to make a cup of coffee.

c) The resulting FIFO is not tied to the Xilinx platform, so can be moved to other FPGAs with ease.

d) Just because - so I can say I've written my own FIFO.

e) I've now got quite a few different FPGA families that I work with, and want to move projects between devices without the long regenerate core process.

f) If you

Design and verification of FIFOs that cross clock domains is a lot of work, but when a FIFO is in the same clock domain writing a FIFO isn't that hard at all.

So here are two ways to create a 32 entry, 9 bit wide FIFO I wrote for a project I'm working on.

The first uses dual-port RAM to make a circular buffer, using two pointers to keep track of where data is to be read or written. It is ideally matched to using dual-ported block ram to store the data for longer FIFOs.

The second way the data is held in a shift register, and the indexed by just a read pointer.

Neither of these have been fully verified, but both work for my current application (which never completely fills a FIFO).

Source files

my_fifo.vhd (using distributed RAM)

NOTE - This is FIFO is effectively only 31 entries deep...

----------------------------------------------------------------------------------
-- Engineer:  Mike Field <hamster@snap.net.nz> 
-- 
-- Create Date:    21:33:42 09/25/2014 
--
-- Module Name:    my_fifo - Behavioral 
-- Description: A 32 x 9 FIFO using inferred storage
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity my_fifo is
    Port ( clk   : in  STD_LOGIC;
           wr    : in  STD_LOGIC;
           din   : in  STD_LOGIC_VECTOR(8 downto 0);
           empty : out STD_LOGIC;
           full  : out STD_LOGIC;
           rd    : in  STD_LOGIC;
           dout  : out STD_LOGIC_VECTOR(8 downto 0));
end my_fifo;

architecture Behavioral of my_fifo is
   signal i_full : std_logic;
   signal i_empty : std_logic;
   
   type mem_array is array(31 downto 0) of std_logic_vector(8 downto 0);
   signal memory : mem_array;
   signal wr_ptr : unsigned(4 downto 0) := (others => '0');
   signal rd_ptr : unsigned(4 downto 0) := (others => '0');
   
begin
    full  <= i_full;
    empty <= i_empty;

flag_proc: process(wr_ptr, rd_ptr)
    begin
        if wr_ptr = rd_ptr then
            i_empty <= '1';
        else
            i_empty <= '0';
        end if;

        if wr_ptr+1 = rd_ptr then
            i_full <= '1';
        else
            i_full <= '0';
        end if;
    end process;

clk_proc: process(clk)
    begin
        if rising_edge(clk) then
            if rd = '1' then
                if wr = '1' then
                    if i_empty = '0' then
                        dout <= memory(to_integer(rd_ptr));
                        rd_ptr <= rd_ptr + 1;
                    end if;
                    
                    memory(to_integer(wr_ptr)) <= din;
                    wr_ptr <= wr_ptr + 1;
                    
                elsif i_empty = '0' then
                    dout <= memory(to_integer(rd_ptr));
                    rd_ptr <= rd_ptr + 1;
                end if;
            elsif wr = '1' then
                if i_full = '0' then
                    memory(to_integer(wr_ptr)) <= din;
                    wr_ptr <= wr_ptr + 1;
                end if;           
            end if;
        end if;
    end process;
end Behavioral;

my_fifo.vhd (using shift registers

The above code works quite well on Artix-7 devices due to a 32x8 RAM primative, but uses quite a lot of resources if implemented on a Spartan 3E chip. Here is a version that implements far better on these devices.


----------------------------------------------------------------------------------
-- Engineer:  Mike Field <hamster@snap.net.nz> 
-- 
-- Create Date:    21:33:42 09/25/2014 
--
-- Module Name:    my_fifo - Behavioral 
-- Description: A 32 x 9 FIFO using inferred storage -this time shift register based
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity my_fifo is
    Port ( clk   : in  STD_LOGIC;
           wr    : in  STD_LOGIC;
           din   : in  STD_LOGIC_VECTOR(8 downto 0);
           empty : out STD_LOGIC;
           full  : out STD_LOGIC;
           rd    : in  STD_LOGIC;
           dout  : out STD_LOGIC_VECTOR(8 downto 0));
end my_fifo;

architecture Behavioral of my_fifo is
   signal i_full  : std_logic := '0';
   signal i_empty : std_logic := '1';
   
   type mem_array is array(31 downto 0) of std_logic_vector(8 downto 0);
   signal memory : mem_array;
   
   signal rd_ptr : unsigned(4 downto 0) := (others => '0');
   
begin
    full  <= i_full;
    empty <= i_empty;

clk_proc: process(clk)
    begin
        if rising_edge(clk) then
            if rd = '1' and i_empty = '0' then
               dout <= memory(to_integer(rd_ptr));
            end if;
            
            if wr = '1' and i_full = '0' then
                memory(31 downto 1) <= memory(30 downto 0);
                memory(0) <= din;
            end if;
            
            if rd = '1' and i_empty = '0' then
                -- The read is actionable
                if wr = '0' or i_full = '1' then
                    -- no write this cycle, so decrement the  
                    -- pointer or mark the fifo as empty
                    if rd_ptr = 0 then
                        i_empty <= '1'; -- fifo is now empty
                    else
                        rd_ptr <= rd_ptr - 1;
                    end if;
                    i_full <= '0';  -- can no longer be full
                end if;
            elsif wr = '1' and i_full = '0' then
                -- the just write is actionable
                if rd_ptr = 30 then
                    i_full <= '1';
                else
                    i_full <= '0';
                end if;
                
                if i_empty = '0' then
                    rd_ptr <= rd_ptr + 1;
                end if;
                i_empty <= '0';
            end if;
        end if;
    end process;
end Behavioral;

Personal tools