VHDL Register based FIFO
This module is a register-based FIFO. A register based FIFO means that the FIFO will be created using distributed logic or registers throughout the FPGA. This is different from using a Block RAM to store a FIFO. In general, a register-based FIFO should be used for small FIFOs (say under 32 words deep) and a Block RAM based FIFO should be used for larger FIFOs.
This page shows two versions of the code. The first version does not use any programmable Almost Full (AF) and Almost Empty (AE) Flags. The second version does include the flags. Whether or not you need them is up to you as the FPGA designer. Note that this has not been tested on hardware, but it has been simulated (testbench is below) and basic functionality has been checked. Additionally, it uses assert statements to ensure that the user does not overflow or underflow the FIFO. Note that the assert statements are not synthesizable, they are only helpful in simulation.
For the first version of the FIFO, the only way to know when it is ready to accept more data is to check that it is not full. To know if it is ready to receive more data you should check the empty flag. The second FIFO allows the use of the Almost flags which are more versatile.
FIFO without Almost-Full, Almost-Empty Flags:
module_fifo_regs_no_flags.vhd:
------------------------------------------------------------------------------- -- File Downloaded from http://www.nandland.com -- -- Description: Creates a Synchronous FIFO made out of registers. -- Generic: g_WIDTH sets the width of the FIFO created. -- Generic: g_DEPTH sets the depth of the FIFO created. -- -- Total FIFO register usage will be width * depth -- Note that this fifo should not be used to cross clock domains. -- (Read and write clocks NEED TO BE the same clock domain) -- -- FIFO Full Flag will assert as soon as last word is written. -- FIFO Empty Flag will assert as soon as last word is read. -- -- FIFO is 100% synthesizable. It uses assert statements which do -- not synthesize, but will cause your simulation to crash if you -- are doing something you shouldn't be doing (reading from an -- empty FIFO or writing to a full FIFO). -- -- No Flags = No Almost Full (AF)/Almost Empty (AE) Flags -- There is a separate module that has programmable AF/AE flags. ------------------------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity module_fifo_regs_no_flags is generic ( g_WIDTH : natural := 8; g_DEPTH : integer := 32 ); port ( i_rst_sync : in std_logic; i_clk : in std_logic; -- FIFO Write Interface i_wr_en : in std_logic; i_wr_data : in std_logic_vector(g_WIDTH-1 downto 0); o_full : out std_logic; -- FIFO Read Interface i_rd_en : in std_logic; o_rd_data : out std_logic_vector(g_WIDTH-1 downto 0); o_empty : out std_logic ); end module_fifo_regs_no_flags; architecture rtl of module_fifo_regs_no_flags is type t_FIFO_DATA is array (0 to g_DEPTH-1) of std_logic_vector(g_WIDTH-1 downto 0); signal r_FIFO_DATA : t_FIFO_DATA := (others => (others => '0')); signal r_WR_INDEX : integer range 0 to g_DEPTH-1 := 0; signal r_RD_INDEX : integer range 0 to g_DEPTH-1 := 0; -- # Words in FIFO, has extra range to allow for assert conditions signal r_FIFO_COUNT : integer range -1 to g_DEPTH+1 := 0; signal w_FULL : std_logic; signal w_EMPTY : std_logic; begin p_CONTROL : process (i_clk) is begin if rising_edge(i_clk) then if i_rst_sync = '1' then r_FIFO_COUNT <= 0; r_WR_INDEX <= 0; r_RD_INDEX <= 0; else -- Keeps track of the total number of words in the FIFO if (i_wr_en = '1' and i_rd_en = '0') then r_FIFO_COUNT <= r_FIFO_COUNT + 1; elsif (i_wr_en = '0' and i_rd_en = '1') then r_FIFO_COUNT <= r_FIFO_COUNT - 1; end if; -- Keeps track of the write index (and controls roll-over) if (i_wr_en = '1' and w_FULL = '0') then if r_WR_INDEX = g_DEPTH-1 then r_WR_INDEX <= 0; else r_WR_INDEX <= r_WR_INDEX + 1; end if; end if; -- Keeps track of the read index (and controls roll-over) if (i_rd_en = '1' and w_EMPTY = '0') then if r_RD_INDEX = g_DEPTH-1 then r_RD_INDEX <= 0; else r_RD_INDEX <= r_RD_INDEX + 1; end if; end if; -- Registers the input data when there is a write if i_wr_en = '1' then r_FIFO_DATA(r_WR_INDEX) <= i_wr_data; end if; end if; -- sync reset end if; -- rising_edge(i_clk) end process p_CONTROL; o_rd_data <= r_FIFO_DATA(r_RD_INDEX); w_FULL <= '1' when r_FIFO_COUNT = g_DEPTH else '0'; w_EMPTY <= '1' when r_FIFO_COUNT = 0 else '0'; o_full <= w_FULL; o_empty <= w_EMPTY; -- ASSERTION LOGIC - Not synthesized -- synthesis translate_off p_ASSERT : process (i_clk) is begin if rising_edge(i_clk) then if i_wr_en = '1' and w_FULL = '1' then report "ASSERT FAILURE - MODULE_REGISTER_FIFO: FIFO IS FULL AND BEING WRITTEN " severity failure; end if; if i_rd_en = '1' and w_EMPTY = '1' then report "ASSERT FAILURE - MODULE_REGISTER_FIFO: FIFO IS EMPTY AND BEING READ " severity failure; end if; end if; end process p_ASSERT; -- synthesis translate_on end rtl;
Testbench, module_fifo_regs_no_flags_tb.vhd:>
------------------------------------------------------------------------------- -- File Downloaded from http://www.nandland.com ------------------------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity module_fifo_regs_no_flags_tb is end module_fifo_regs_no_flags_tb; architecture behave of module_fifo_regs_no_flags_tb is constant c_DEPTH : integer := 4; constant c_WIDTH : integer := 8; signal r_RESET : std_logic := '0'; signal r_CLOCK : std_logic := '0'; signal r_WR_EN : std_logic := '0'; signal r_WR_DATA : std_logic_vector(c_WIDTH-1 downto 0) := X"A5"; signal w_FULL : std_logic; signal r_RD_EN : std_logic := '0'; signal w_RD_DATA : std_logic_vector(c_WIDTH-1 downto 0); signal w_EMPTY : std_logic; component module_fifo_regs_no_flags is generic ( g_WIDTH : natural := 8; g_DEPTH : integer := 32 ); port ( i_rst_sync : in std_logic; i_clk : in std_logic; -- FIFO Write Interface i_wr_en : in std_logic; i_wr_data : in std_logic_vector(g_WIDTH-1 downto 0); o_full : out std_logic; -- FIFO Read Interface i_rd_en : in std_logic; o_rd_data : out std_logic_vector(g_WIDTH-1 downto 0); o_empty : out std_logic ); end component module_fifo_regs_no_flags; begin MODULE_FIFO_REGS_NO_FLAGS_INST : module_fifo_regs_no_flags generic map ( g_WIDTH => c_WIDTH, g_DEPTH => c_DEPTH ) port map ( i_rst_sync => r_RESET, i_clk => r_CLOCK, i_wr_en => r_WR_EN, i_wr_data => r_WR_DATA, o_full => w_FULL, i_rd_en => r_RD_EN, o_rd_data => w_RD_DATA, o_empty => w_EMPTY ); r_CLOCK <= not r_CLOCK after 5 ns; p_TEST : process is begin wait until r_CLOCK = '1'; r_WR_EN <= '1'; wait until r_CLOCK = '1'; wait until r_CLOCK = '1'; wait until r_CLOCK = '1'; wait until r_CLOCK = '1'; r_WR_EN <= '0'; r_RD_EN <= '1'; wait until r_CLOCK = '1'; wait until r_CLOCK = '1'; wait until r_CLOCK = '1'; wait until r_CLOCK = '1'; r_RD_EN <= '0'; r_WR_EN <= '1'; wait until r_CLOCK = '1'; wait until r_CLOCK = '1'; r_RD_EN <= '1'; wait until r_CLOCK = '1'; wait until r_CLOCK = '1'; wait until r_CLOCK = '1'; wait until r_CLOCK = '1'; wait until r_CLOCK = '1'; wait until r_CLOCK = '1'; wait until r_CLOCK = '1'; wait until r_CLOCK = '1'; r_WR_EN <= '0'; wait until r_CLOCK = '1'; wait until r_CLOCK = '1'; wait until r_CLOCK = '1'; wait until r_CLOCK = '1'; end process; end behave;
FIFO with Almost-Full, Almost-Empty Flags:
module_fifo_regs_with_flags.vhd:
------------------------------------------------------------------------------- -- File Downloaded from http://www.nandland.com -- -- Description: Creates a Synchronous FIFO made out of registers. -- Generic: g_WIDTH sets the width of the FIFO created. -- Generic: g_DEPTH sets the depth of the FIFO created. -- -- Total FIFO register usage will be width * depth -- Note that this fifo should not be used to cross clock domains. -- (Read and write clocks NEED TO BE the same clock domain) -- -- FIFO Full Flag will assert as soon as last word is written. -- FIFO Empty Flag will assert as soon as last word is read. -- -- FIFO is 100% synthesizable. It uses assert statements which do -- not synthesize, but will cause your simulation to crash if you -- are doing something you shouldn't be doing (reading from an -- empty FIFO or writing to a full FIFO). -- -- With Flags = Has Almost Full (AF)/Almost Empty (AE) Flags -- These are settable via Generics: g_AF_LEVEL and g_AE_LEVEL -- g_AF_LEVEL: Goes high when # words in FIFO is > this number. -- g_AE_LEVEL: Goes high when # words in FIFO is < this number. ------------------------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity module_fifo_regs_with_flags is generic ( g_WIDTH : natural := 8; g_DEPTH : integer := 32; g_AF_LEVEL : integer := 28; g_AE_LEVEL : integer := 4 ); port ( i_rst_sync : in std_logic; i_clk : in std_logic; -- FIFO Write Interface i_wr_en : in std_logic; i_wr_data : in std_logic_vector(g_WIDTH-1 downto 0); o_af : out std_logic; o_full : out std_logic; -- FIFO Read Interface i_rd_en : in std_logic; o_rd_data : out std_logic_vector(g_WIDTH-1 downto 0); o_ae : out std_logic; o_empty : out std_logic ); end module_fifo_regs_with_flags; architecture rtl of module_fifo_regs_with_flags is type t_FIFO_DATA is array (0 to g_DEPTH-1) of std_logic_vector(g_WIDTH-1 downto 0); signal r_FIFO_DATA : t_FIFO_DATA := (others => (others => '0')); signal r_WR_INDEX : integer range 0 to g_DEPTH-1 := 0; signal r_RD_INDEX : integer range 0 to g_DEPTH-1 := 0; -- # Words in FIFO, has extra range to allow for assert conditions signal r_FIFO_COUNT : integer range -1 to g_DEPTH+1 := 0; signal w_FULL : std_logic; signal w_EMPTY : std_logic; begin p_CONTROL : process (i_clk) is begin if rising_edge(i_clk) then if i_rst_sync = '1' then r_FIFO_COUNT <= 0; r_WR_INDEX <= 0; r_RD_INDEX <= 0; else -- Keeps track of the total number of words in the FIFO if (i_wr_en = '1' and i_rd_en = '0') then r_FIFO_COUNT <= r_FIFO_COUNT + 1; elsif (i_wr_en = '0' and i_rd_en = '1') then r_FIFO_COUNT <= r_FIFO_COUNT - 1; end if; -- Keeps track of the write index (and controls roll-over) if (i_wr_en = '1' and w_FULL = '0') then if r_WR_INDEX = g_DEPTH-1 then r_WR_INDEX <= 0; else r_WR_INDEX <= r_WR_INDEX + 1; end if; end if; -- Keeps track of the read index (and controls roll-over) if (i_rd_en = '1' and w_EMPTY = '0') then if r_RD_INDEX = g_DEPTH-1 then r_RD_INDEX <= 0; else r_RD_INDEX <= r_RD_INDEX + 1; end if; end if; -- Registers the input data when there is a write if i_wr_en = '1' then r_FIFO_DATA(r_WR_INDEX) <= i_wr_data; end if; end if; -- sync reset end if; -- rising_edge(i_clk) end process p_CONTROL; o_rd_data <= r_FIFO_DATA(r_RD_INDEX); w_FULL <= '1' when r_FIFO_COUNT = g_DEPTH else '0'; w_EMPTY <= '1' when r_FIFO_COUNT = 0 else '0'; o_af <= '1' when r_FIFO_COUNT > g_AF_LEVEL else '0'; o_ae <= '1' when r_FIFO_COUNT < g_AE_LEVEL else '0'; o_full <= w_FULL; o_empty <= w_EMPTY; ----------------------------------------------------------------------------- -- ASSERTION LOGIC - Not synthesized ----------------------------------------------------------------------------- -- synthesis translate_off p_ASSERT : process (i_clk) is begin if rising_edge(i_clk) then if i_wr_en = '1' and w_FULL = '1' then report "ASSERT FAILURE - MODULE_REGISTER_FIFO: FIFO IS FULL AND BEING WRITTEN " severity failure; end if; if i_rd_en = '1' and w_EMPTY = '1' then report "ASSERT FAILURE - MODULE_REGISTER_FIFO: FIFO IS EMPTY AND BEING READ " severity failure; end if; end if; end process p_ASSERT; -- synthesis translate_on end rtl;
Testbench, module_fifo_regs_with_flags_tb.vhd
------------------------------------------------------------------------------- -- File Downloaded from http://www.nandland.com ------------------------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity module_fifo_regs_with_flags_tb is end module_fifo_regs_with_flags_tb; architecture behave of module_fifo_regs_with_flags_tb is constant c_DEPTH : integer := 4; constant c_WIDTH : integer := 8; constant c_AF_LEVEL : integer := 2; constant c_AE_LEVEL : integer := 2; signal r_RESET : std_logic := '0'; signal r_CLOCK : std_logic := '0'; signal r_WR_EN : std_logic := '0'; signal r_WR_DATA : std_logic_vector(c_WIDTH-1 downto 0) := X"A5"; signal w_AF : std_logic; signal w_FULL : std_logic; signal r_RD_EN : std_logic := '0'; signal w_RD_DATA : std_logic_vector(c_WIDTH-1 downto 0); signal w_AE : std_logic; signal w_EMPTY : std_logic; component module_fifo_regs_with_flags is generic ( g_WIDTH : natural := 8; g_DEPTH : integer := 32; g_AF_LEVEL : integer := 28; g_AE_LEVEL : integer := 4 ); port ( i_rst_sync : in std_logic; i_clk : in std_logic; -- FIFO Write Interface i_wr_en : in std_logic; i_wr_data : in std_logic_vector(g_WIDTH-1 downto 0); o_af : out std_logic; o_full : out std_logic; -- FIFO Read Interface i_rd_en : in std_logic; o_rd_data : out std_logic_vector(g_WIDTH-1 downto 0); o_ae : out std_logic; o_empty : out std_logic ); end component module_fifo_regs_with_flags; begin MODULE_FIFO_REGS_WITH_FLAGS_INST : module_fifo_regs_with_flags generic map ( g_WIDTH => c_WIDTH, g_DEPTH => c_DEPTH, g_AF_LEVEL => c_AF_LEVEL, g_AE_LEVEL => c_AE_LEVEL ) port map ( i_rst_sync => r_RESET, i_clk => r_CLOCK, i_wr_en => r_WR_EN, i_wr_data => r_WR_DATA, o_af => w_AF, o_full => w_FULL, i_rd_en => r_RD_EN, o_rd_data => w_RD_DATA, o_ae => w_AE, o_empty => w_EMPTY ); r_CLOCK <= not r_CLOCK after 5 ns; p_TEST : process is begin wait until r_CLOCK = '1'; r_WR_EN <= '1'; wait until r_CLOCK = '1'; wait until r_CLOCK = '1'; wait until r_CLOCK = '1'; wait until r_CLOCK = '1'; r_WR_EN <= '0'; r_RD_EN <= '1'; wait until r_CLOCK = '1'; wait until r_CLOCK = '1'; wait until r_CLOCK = '1'; wait until r_CLOCK = '1'; r_RD_EN <= '0'; r_WR_EN <= '1'; wait until r_CLOCK = '1'; wait until r_CLOCK = '1'; r_RD_EN <= '1'; wait until r_CLOCK = '1'; wait until r_CLOCK = '1'; wait until r_CLOCK = '1'; wait until r_CLOCK = '1'; wait until r_CLOCK = '1'; wait until r_CLOCK = '1'; wait until r_CLOCK = '1'; wait until r_CLOCK = '1'; r_WR_EN <= '0'; wait until r_CLOCK = '1'; wait until r_CLOCK = '1'; wait until r_CLOCK = '1'; wait until r_CLOCK = '1'; end process; end behave;
Leave A Comment