-- ==============================================================
-- FILE : FIFO16x32.VHD  -  may be modified by the USER
-- ==============================================================
--
-- This file is part of Example 2, for the HERON-FPGA14 module.
--
-- This file may be modified by the user.
--
-- ==============================================================
--
--  Date        : 06/04/2006
--  Author      : R. Williams - HUNT ENGINEERING
--  Description : FIFO for interfacing to SDRAM Interface
--
-- ==============================================================
--
--  Ver     Modified By      Date      Changes
--  ---     -----------      ----      -------
--  1.0     R. Williams    06-04-06    Taken from FPGA12 Example 2.
--
-- ==============================================================



library IEEE;
  use IEEE.std_logic_1164.all;
  use IEEE.std_logic_arith.all;
  use IEEE.std_logic_unsigned.all;

-- pragma translate_off
library UNISIM;
  use UNISIM.vcomponents.all;
-- pragma translate_on


entity FIFO16x32 is
  port (
    RESET    : in  std_logic;
    CLOCK    : in  std_logic;
    DIN      : in  std_logic_vector(31 downto 0);
    WR_EN    : in  std_logic;
    RD_EN    : in  std_logic;
    DOUT     : out std_logic_vector(31 downto 0);
    FULL     : out std_logic;
    EMPTY    : out std_logic;
    WR_COUNT : out std_logic_vector(4 downto 0);
    RD_COUNT : out std_logic_vector(4 downto 0)
  );
end FIFO16x32;


architecture RTL of FIFO16x32 is

  component RAM16X1D
    -- pragma translate_off
    generic (
      -- RAM initialization for functional simulation:
      INIT : bit_vector := X"0000"
    );
    -- pragma translate_on
    port (
      D     : in  std_logic;
      WE    : in  std_logic;
      WCLK  : in  std_logic;
      A0    : in  std_logic;
      A1    : in  std_logic;
      A2    : in  std_logic;
      A3    : in  std_logic;
      DPRA0 : in  std_logic;
      DPRA1 : in  std_logic;
      DPRA2 : in  std_logic;
      DPRA3 : in  std_logic;
      SPO   : out std_logic;
      DPO   : out std_logic
    ); 
  end component;

  attribute INIT: string;

  attribute INIT of iRAM0  : label is "0000";
  attribute INIT of iRAM1  : label is "0000";
  attribute INIT of iRAM2  : label is "0000";
  attribute INIT of iRAM3  : label is "0000";
  attribute INIT of iRAM4  : label is "0000";
  attribute INIT of iRAM5  : label is "0000";
  attribute INIT of iRAM6  : label is "0000";
  attribute INIT of iRAM7  : label is "0000";
  attribute INIT of iRAM8  : label is "0000";
  attribute INIT of iRAM9  : label is "0000";
  attribute INIT of iRAM10 : label is "0000";
  attribute INIT of iRAM11 : label is "0000";
  attribute INIT of iRAM12 : label is "0000";
  attribute INIT of iRAM13 : label is "0000";
  attribute INIT of iRAM14 : label is "0000";
  attribute INIT of iRAM15 : label is "0000";
  attribute INIT of iRAM16 : label is "0000";
  attribute INIT of iRAM17 : label is "0000";
  attribute INIT of iRAM18 : label is "0000";
  attribute INIT of iRAM19 : label is "0000";
  attribute INIT of iRAM20 : label is "0000";
  attribute INIT of iRAM21 : label is "0000";
  attribute INIT of iRAM22 : label is "0000";
  attribute INIT of iRAM23 : label is "0000";
  attribute INIT of iRAM24 : label is "0000";
  attribute INIT of iRAM25 : label is "0000";
  attribute INIT of iRAM26 : label is "0000";
  attribute INIT of iRAM27 : label is "0000";
  attribute INIT of iRAM28 : label is "0000";
  attribute INIT of iRAM29 : label is "0000";
  attribute INIT of iRAM30 : label is "0000";
  attribute INIT of iRAM31 : label is "0000";

  signal READ_ADDR   : std_logic_vector(3 downto 0);
  signal WRITE_ADDR  : std_logic_vector(3 downto 0);
  signal WRITE_ALLOW : std_logic;
  signal READ_ALLOW  : std_logic;

  signal WRITE_COUNT : std_logic_vector(4 downto 0);
  signal READ_COUNT  : std_logic_vector(4 downto 0);
  signal COUNT_EN    : std_logic;
  signal COUNT_DIR   : std_logic;

  signal FFc         : std_logic;
  signal EFc         : std_logic;
  signal FF          : std_logic;
  signal EF          : std_logic;
  signal AF          : std_logic;
  signal AE          : std_logic;

begin

  FULL  <= FF;
  EMPTY <= EF;

  WR_COUNT <= WRITE_COUNT;
  RD_COUNT <= READ_COUNT;

  WRITE_ALLOW <= WR_EN AND FF;
  READ_ALLOW  <= RD_EN AND EF;

  FFc <= '1' when WRITE_COUNT="00000" else '0';
  EFc <= '1' when  READ_COUNT="00000" else '0';

  AF <= '1' when WRITE_COUNT="00001" else '0';
  AE <= '1' when  READ_COUNT="00001" else '0';

  -- Active Low FIFO Flags
  process(RESET, CLOCK)
  begin
    if RESET='1' then
      FF <= '0';
      EF <= '0';
    elsif rising_edge(CLOCK) then
      FF <= '1';
      EF <= '1';
      if FFc='1' or (AF='1' and WRITE_ALLOW='1') then
        FF <= '0';
      end if;
      if EFc='1' or (AE='1' and READ_ALLOW='1') then
        EF <= '0';
      end if;
    end if;
  end process;

  process(RESET, CLOCK)
  begin
    if RESET='1' then
      READ_ADDR <= (others=>'0');
    elsif rising_edge(CLOCK) then
      if READ_ALLOW='1' then
        READ_ADDR <= READ_ADDR + 1;
      end if;
    end if;
  end process;

  process(RESET, CLOCK)
  begin
    if RESET='1' then
      WRITE_ADDR <= (others=>'0');
    elsif rising_edge(CLOCK) then
      if WRITE_ALLOW='1' then
        WRITE_ADDR <= WRITE_ADDR + 1;
      end if;
    end if;
  end process;

  COUNT_EN  <= WRITE_ALLOW XOR READ_ALLOW;
  COUNT_DIR <= WRITE_ALLOW;

  process(RESET, CLOCK)
  begin
    if RESET='1' then
      READ_COUNT  <= "00000";
      WRITE_COUNT <= "10000";
    elsif rising_edge(CLOCK) then
      if COUNT_EN='1' then
        if COUNT_DIR='1' then
          READ_COUNT  <= READ_COUNT  + 1;
          WRITE_COUNT <= WRITE_COUNT - 1;
        else
          READ_COUNT  <= READ_COUNT  - 1;
          WRITE_COUNT <= WRITE_COUNT + 1;
        end if;
      end if;
    end if;
  end process;

  iRAM0 : RAM16X1D
    port map (
      D     => din(0),
      WE    => WRITE_ALLOW,
      WCLK  => CLOCK,
      A0    => WRITE_ADDR(0),
      A1    => WRITE_ADDR(1),
      A2    => WRITE_ADDR(2),
      A3    => WRITE_ADDR(3),
      DPRA0 => READ_ADDR(0),
      DPRA1 => READ_ADDR(1),
      DPRA2 => READ_ADDR(2),
      DPRA3 => READ_ADDR(3),
      SPO   => open,
      DPO   => dout(0) );

  iRAM1 : RAM16X1D
    port map (
      D     => din(1),
      WE    => WRITE_ALLOW,
      WCLK  => CLOCK,
      A0    => WRITE_ADDR(0),
      A1    => WRITE_ADDR(1),
      A2    => WRITE_ADDR(2),
      A3    => WRITE_ADDR(3),
      DPRA0 => READ_ADDR(0),
      DPRA1 => READ_ADDR(1),
      DPRA2 => READ_ADDR(2),
      DPRA3 => READ_ADDR(3),
      SPO   => open,
      DPO   => dout(1) );

  iRAM2 : RAM16X1D
    port map (
      D     => din(2),
      WE    => WRITE_ALLOW,
      WCLK  => CLOCK,
      A0    => WRITE_ADDR(0),
      A1    => WRITE_ADDR(1),
      A2    => WRITE_ADDR(2),
      A3    => WRITE_ADDR(3),
      DPRA0 => READ_ADDR(0),
      DPRA1 => READ_ADDR(1),
      DPRA2 => READ_ADDR(2),
      DPRA3 => READ_ADDR(3),
      SPO   => open,
      DPO   => dout(2) );

  iRAM3 : RAM16X1D
    port map (
      D     => din(3),
      WE    => WRITE_ALLOW,
      WCLK  => CLOCK,
      A0    => WRITE_ADDR(0),
      A1    => WRITE_ADDR(1),
      A2    => WRITE_ADDR(2),
      A3    => WRITE_ADDR(3),
      DPRA0 => READ_ADDR(0),
      DPRA1 => READ_ADDR(1),
      DPRA2 => READ_ADDR(2),
      DPRA3 => READ_ADDR(3),
      SPO   => open,
      DPO   => dout(3) );

  iRAM4 : RAM16X1D
    port map (
      D     => din(4),
      WE    => WRITE_ALLOW,
      WCLK  => CLOCK,
      A0    => WRITE_ADDR(0),
      A1    => WRITE_ADDR(1),
      A2    => WRITE_ADDR(2),
      A3    => WRITE_ADDR(3),
      DPRA0 => READ_ADDR(0),
      DPRA1 => READ_ADDR(1),
      DPRA2 => READ_ADDR(2),
      DPRA3 => READ_ADDR(3),
      SPO   => open,
      DPO   => dout(4) );

  iRAM5 : RAM16X1D
    port map (
      D     => din(5),
      WE    => WRITE_ALLOW,
      WCLK  => CLOCK,
      A0    => WRITE_ADDR(0),
      A1    => WRITE_ADDR(1),
      A2    => WRITE_ADDR(2),
      A3    => WRITE_ADDR(3),
      DPRA0 => READ_ADDR(0),
      DPRA1 => READ_ADDR(1),
      DPRA2 => READ_ADDR(2),
      DPRA3 => READ_ADDR(3),
      SPO   => open,
      DPO   => dout(5) );

  iRAM6 : RAM16X1D
    port map (
      D     => din(6),
      WE    => WRITE_ALLOW,
      WCLK  => CLOCK,
      A0    => WRITE_ADDR(0),
      A1    => WRITE_ADDR(1),
      A2    => WRITE_ADDR(2),
      A3    => WRITE_ADDR(3),
      DPRA0 => READ_ADDR(0),
      DPRA1 => READ_ADDR(1),
      DPRA2 => READ_ADDR(2),
      DPRA3 => READ_ADDR(3),
      SPO   => open,
      DPO   => dout(6) );

  iRAM7 : RAM16X1D
    port map (
      D     => din(7),
      WE    => WRITE_ALLOW,
      WCLK  => CLOCK,
      A0    => WRITE_ADDR(0),
      A1    => WRITE_ADDR(1),
      A2    => WRITE_ADDR(2),
      A3    => WRITE_ADDR(3),
      DPRA0 => READ_ADDR(0),
      DPRA1 => READ_ADDR(1),
      DPRA2 => READ_ADDR(2),
      DPRA3 => READ_ADDR(3),
      SPO   => open,
      DPO   => dout(7) );

  iRAM8 : RAM16X1D
    port map (
      D     => din(8),
      WE    => WRITE_ALLOW,
      WCLK  => CLOCK,
      A0    => WRITE_ADDR(0),
      A1    => WRITE_ADDR(1),
      A2    => WRITE_ADDR(2),
      A3    => WRITE_ADDR(3),
      DPRA0 => READ_ADDR(0),
      DPRA1 => READ_ADDR(1),
      DPRA2 => READ_ADDR(2),
      DPRA3 => READ_ADDR(3),
      SPO   => open,
      DPO   => dout(8) );

  iRAM9 : RAM16X1D
    port map (
      D     => din(9),
      WE    => WRITE_ALLOW,
      WCLK  => CLOCK,
      A0    => WRITE_ADDR(0),
      A1    => WRITE_ADDR(1),
      A2    => WRITE_ADDR(2),
      A3    => WRITE_ADDR(3),
      DPRA0 => READ_ADDR(0),
      DPRA1 => READ_ADDR(1),
      DPRA2 => READ_ADDR(2),
      DPRA3 => READ_ADDR(3),
      SPO   => open,
      DPO   => dout(9) );

  iRAM10 : RAM16X1D
    port map (
      D     => din(10),
      WE    => WRITE_ALLOW,
      WCLK  => CLOCK,
      A0    => WRITE_ADDR(0),
      A1    => WRITE_ADDR(1),
      A2    => WRITE_ADDR(2),
      A3    => WRITE_ADDR(3),
      DPRA0 => READ_ADDR(0),
      DPRA1 => READ_ADDR(1),
      DPRA2 => READ_ADDR(2),
      DPRA3 => READ_ADDR(3),
      SPO   => open,
      DPO   => dout(10) );

  iRAM11 : RAM16X1D
    port map (
      D     => din(11),
      WE    => WRITE_ALLOW,
      WCLK  => CLOCK,
      A0    => WRITE_ADDR(0),
      A1    => WRITE_ADDR(1),
      A2    => WRITE_ADDR(2),
      A3    => WRITE_ADDR(3),
      DPRA0 => READ_ADDR(0),
      DPRA1 => READ_ADDR(1),
      DPRA2 => READ_ADDR(2),
      DPRA3 => READ_ADDR(3),
      SPO   => open,
      DPO   => dout(11) );

  iRAM12 : RAM16X1D
    port map (
      D     => din(12),
      WE    => WRITE_ALLOW,
      WCLK  => CLOCK,
      A0    => WRITE_ADDR(0),
      A1    => WRITE_ADDR(1),
      A2    => WRITE_ADDR(2),
      A3    => WRITE_ADDR(3),
      DPRA0 => READ_ADDR(0),
      DPRA1 => READ_ADDR(1),
      DPRA2 => READ_ADDR(2),
      DPRA3 => READ_ADDR(3),
      SPO   => open,
      DPO   => dout(12) );

  iRAM13 : RAM16X1D
    port map (
      D     => din(13),
      WE    => WRITE_ALLOW,
      WCLK  => CLOCK,
      A0    => WRITE_ADDR(0),
      A1    => WRITE_ADDR(1),
      A2    => WRITE_ADDR(2),
      A3    => WRITE_ADDR(3),
      DPRA0 => READ_ADDR(0),
      DPRA1 => READ_ADDR(1),
      DPRA2 => READ_ADDR(2),
      DPRA3 => READ_ADDR(3),
      SPO   => open,
      DPO   => dout(13) );

  iRAM14 : RAM16X1D
    port map (
      D     => din(14),
      WE    => WRITE_ALLOW,
      WCLK  => CLOCK,
      A0    => WRITE_ADDR(0),
      A1    => WRITE_ADDR(1),
      A2    => WRITE_ADDR(2),
      A3    => WRITE_ADDR(3),
      DPRA0 => READ_ADDR(0),
      DPRA1 => READ_ADDR(1),
      DPRA2 => READ_ADDR(2),
      DPRA3 => READ_ADDR(3),
      SPO   => open,
      DPO   => dout(14) );

  iRAM15 : RAM16X1D
    port map (
      D     => din(15),
      WE    => WRITE_ALLOW,
      WCLK  => CLOCK,
      A0    => WRITE_ADDR(0),
      A1    => WRITE_ADDR(1),
      A2    => WRITE_ADDR(2),
      A3    => WRITE_ADDR(3),
      DPRA0 => READ_ADDR(0),
      DPRA1 => READ_ADDR(1),
      DPRA2 => READ_ADDR(2),
      DPRA3 => READ_ADDR(3),
      SPO   => open,
      DPO   => dout(15) );

  iRAM16 : RAM16X1D
    port map (
      D     => din(16),
      WE    => WRITE_ALLOW,
      WCLK  => CLOCK,
      A0    => WRITE_ADDR(0),
      A1    => WRITE_ADDR(1),
      A2    => WRITE_ADDR(2),
      A3    => WRITE_ADDR(3),
      DPRA0 => READ_ADDR(0),
      DPRA1 => READ_ADDR(1),
      DPRA2 => READ_ADDR(2),
      DPRA3 => READ_ADDR(3),
      SPO   => open,
      DPO   => dout(16) );

  iRAM17 : RAM16X1D
    port map (
      D     => din(17),
      WE    => WRITE_ALLOW,
      WCLK  => CLOCK,
      A0    => WRITE_ADDR(0),
      A1    => WRITE_ADDR(1),
      A2    => WRITE_ADDR(2),
      A3    => WRITE_ADDR(3),
      DPRA0 => READ_ADDR(0),
      DPRA1 => READ_ADDR(1),
      DPRA2 => READ_ADDR(2),
      DPRA3 => READ_ADDR(3),
      SPO   => open,
      DPO   => dout(17) );

  iRAM18 : RAM16X1D
    port map (
      D     => din(18),
      WE    => WRITE_ALLOW,
      WCLK  => CLOCK,
      A0    => WRITE_ADDR(0),
      A1    => WRITE_ADDR(1),
      A2    => WRITE_ADDR(2),
      A3    => WRITE_ADDR(3),
      DPRA0 => READ_ADDR(0),
      DPRA1 => READ_ADDR(1),
      DPRA2 => READ_ADDR(2),
      DPRA3 => READ_ADDR(3),
      SPO   => open,
      DPO   => dout(18) );

  iRAM19 : RAM16X1D
    port map (
      D     => din(19),
      WE    => WRITE_ALLOW,
      WCLK  => CLOCK,
      A0    => WRITE_ADDR(0),
      A1    => WRITE_ADDR(1),
      A2    => WRITE_ADDR(2),
      A3    => WRITE_ADDR(3),
      DPRA0 => READ_ADDR(0),
      DPRA1 => READ_ADDR(1),
      DPRA2 => READ_ADDR(2),
      DPRA3 => READ_ADDR(3),
      SPO   => open,
      DPO   => dout(19) );

  iRAM20 : RAM16X1D
    port map (
      D     => din(20),
      WE    => WRITE_ALLOW,
      WCLK  => CLOCK,
      A0    => WRITE_ADDR(0),
      A1    => WRITE_ADDR(1),
      A2    => WRITE_ADDR(2),
      A3    => WRITE_ADDR(3),
      DPRA0 => READ_ADDR(0),
      DPRA1 => READ_ADDR(1),
      DPRA2 => READ_ADDR(2),
      DPRA3 => READ_ADDR(3),
      SPO   => open,
      DPO   => dout(20) );

  iRAM21 : RAM16X1D
    port map (
      D     => din(21),
      WE    => WRITE_ALLOW,
      WCLK  => CLOCK,
      A0    => WRITE_ADDR(0),
      A1    => WRITE_ADDR(1),
      A2    => WRITE_ADDR(2),
      A3    => WRITE_ADDR(3),
      DPRA0 => READ_ADDR(0),
      DPRA1 => READ_ADDR(1),
      DPRA2 => READ_ADDR(2),
      DPRA3 => READ_ADDR(3),
      SPO   => open,
      DPO   => dout(21) );

  iRAM22 : RAM16X1D
    port map (
      D     => din(22),
      WE    => WRITE_ALLOW,
      WCLK  => CLOCK,
      A0    => WRITE_ADDR(0),
      A1    => WRITE_ADDR(1),
      A2    => WRITE_ADDR(2),
      A3    => WRITE_ADDR(3),
      DPRA0 => READ_ADDR(0),
      DPRA1 => READ_ADDR(1),
      DPRA2 => READ_ADDR(2),
      DPRA3 => READ_ADDR(3),
      SPO   => open,
      DPO   => dout(22) );

  iRAM23 : RAM16X1D
    port map (
      D     => din(23),
      WE    => WRITE_ALLOW,
      WCLK  => CLOCK,
      A0    => WRITE_ADDR(0),
      A1    => WRITE_ADDR(1),
      A2    => WRITE_ADDR(2),
      A3    => WRITE_ADDR(3),
      DPRA0 => READ_ADDR(0),
      DPRA1 => READ_ADDR(1),
      DPRA2 => READ_ADDR(2),
      DPRA3 => READ_ADDR(3),
      SPO   => open,
      DPO   => dout(23) );

  iRAM24 : RAM16X1D
    port map (
      D     => din(24),
      WE    => WRITE_ALLOW,
      WCLK  => CLOCK,
      A0    => WRITE_ADDR(0),
      A1    => WRITE_ADDR(1),
      A2    => WRITE_ADDR(2),
      A3    => WRITE_ADDR(3),
      DPRA0 => READ_ADDR(0),
      DPRA1 => READ_ADDR(1),
      DPRA2 => READ_ADDR(2),
      DPRA3 => READ_ADDR(3),
      SPO   => open,
      DPO   => dout(24) );

  iRAM25 : RAM16X1D
    port map (
      D     => din(25),
      WE    => WRITE_ALLOW,
      WCLK  => CLOCK,
      A0    => WRITE_ADDR(0),
      A1    => WRITE_ADDR(1),
      A2    => WRITE_ADDR(2),
      A3    => WRITE_ADDR(3),
      DPRA0 => READ_ADDR(0),
      DPRA1 => READ_ADDR(1),
      DPRA2 => READ_ADDR(2),
      DPRA3 => READ_ADDR(3),
      SPO   => open,
      DPO   => dout(25) );

  iRAM26 : RAM16X1D
    port map (
      D     => din(26),
      WE    => WRITE_ALLOW,
      WCLK  => CLOCK,
      A0    => WRITE_ADDR(0),
      A1    => WRITE_ADDR(1),
      A2    => WRITE_ADDR(2),
      A3    => WRITE_ADDR(3),
      DPRA0 => READ_ADDR(0),
      DPRA1 => READ_ADDR(1),
      DPRA2 => READ_ADDR(2),
      DPRA3 => READ_ADDR(3),
      SPO   => open,
      DPO   => dout(26) );

  iRAM27 : RAM16X1D
    port map (
      D     => din(27),
      WE    => WRITE_ALLOW,
      WCLK  => CLOCK,
      A0    => WRITE_ADDR(0),
      A1    => WRITE_ADDR(1),
      A2    => WRITE_ADDR(2),
      A3    => WRITE_ADDR(3),
      DPRA0 => READ_ADDR(0),
      DPRA1 => READ_ADDR(1),
      DPRA2 => READ_ADDR(2),
      DPRA3 => READ_ADDR(3),
      SPO   => open,
      DPO   => dout(27) );

  iRAM28 : RAM16X1D
    port map (
      D     => din(28),
      WE    => WRITE_ALLOW,
      WCLK  => CLOCK,
      A0    => WRITE_ADDR(0),
      A1    => WRITE_ADDR(1),
      A2    => WRITE_ADDR(2),
      A3    => WRITE_ADDR(3),
      DPRA0 => READ_ADDR(0),
      DPRA1 => READ_ADDR(1),
      DPRA2 => READ_ADDR(2),
      DPRA3 => READ_ADDR(3),
      SPO   => open,
      DPO   => dout(28) );

  iRAM29 : RAM16X1D
    port map (
      D     => din(29),
      WE    => WRITE_ALLOW,
      WCLK  => CLOCK,
      A0    => WRITE_ADDR(0),
      A1    => WRITE_ADDR(1),
      A2    => WRITE_ADDR(2),
      A3    => WRITE_ADDR(3),
      DPRA0 => READ_ADDR(0),
      DPRA1 => READ_ADDR(1),
      DPRA2 => READ_ADDR(2),
      DPRA3 => READ_ADDR(3),
      SPO   => open,
      DPO   => dout(29) );

  iRAM30 : RAM16X1D
    port map (
      D     => din(30),
      WE    => WRITE_ALLOW,
      WCLK  => CLOCK,
      A0    => WRITE_ADDR(0),
      A1    => WRITE_ADDR(1),
      A2    => WRITE_ADDR(2),
      A3    => WRITE_ADDR(3),
      DPRA0 => READ_ADDR(0),
      DPRA1 => READ_ADDR(1),
      DPRA2 => READ_ADDR(2),
      DPRA3 => READ_ADDR(3),
      SPO   => open,
      DPO   => dout(30) );

  iRAM31 : RAM16X1D
    port map (
      D     => din(31),
      WE    => WRITE_ALLOW,
      WCLK  => CLOCK,
      A0    => WRITE_ADDR(0),
      A1    => WRITE_ADDR(1),
      A2    => WRITE_ADDR(2),
      A3    => WRITE_ADDR(3),
      DPRA0 => READ_ADDR(0),
      DPRA1 => READ_ADDR(1),
      DPRA2 => READ_ADDR(2),
      DPRA3 => READ_ADDR(3),
      SPO   => open,
      DPO   => dout(31) );

end RTL;
