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



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

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


entity FIFO_CONTROL is
  port (
    RESET      : in  std_logic;
    CLOCK      : in  std_logic;
    FIFO_WR    : in  std_logic;
    FIFO_RD    : in  std_logic;
    WRITE_FULL : out std_logic;
    READ_EMPTY : out std_logic
  );
end FIFO_CONTROL;


architecture RTL of FIFO_CONTROL is

  signal COUNT_EN         : std_logic;
  signal COUNT_DIR        : std_logic;

  signal FIFO_WR_DEL      : std_logic;
  signal FIFO_RD_DEL      : std_logic;

  signal DATA_COUNT       : std_logic_vector(23 downto 0);
  signal DATA_COUNT_PLUS  : std_logic_vector(23 downto 0);
  signal DATA_COUNT_MINUS : std_logic_vector(23 downto 0);
  signal DATA_COUNT_DELAY : std_logic_vector(23 downto 0);

begin

  COUNT_EN  <= FIFO_WR XOR FIFO_RD;
  COUNT_DIR <= FIFO_WR;

  process(RESET, CLOCK)
  begin
    if RESET='1' then
      FIFO_WR_DEL <= '0';
      FIFO_RD_DEL <= '0';
    elsif rising_edge(CLOCK) then
      FIFO_WR_DEL <= FIFO_WR;
      FIFO_RD_DEL <= FIFO_RD;
    end if;
  end process;

  process(RESET, CLOCK)
  begin
    if RESET='1' then
      DATA_COUNT_PLUS  <= (others=>'0');
      DATA_COUNT_MINUS <= (others=>'0');
      DATA_COUNT_DELAY <= (others=>'0');
    elsif rising_edge(CLOCK) then
      DATA_COUNT_PLUS  <= DATA_COUNT + 1;
      DATA_COUNT_MINUS <= DATA_COUNT - 1;
      DATA_COUNT_DELAY <= DATA_COUNT;
    end if;
  end process;

  process(RESET, CLOCK)
  begin
    if RESET='1' then
      DATA_COUNT <= (others=>'0');
    elsif rising_edge(CLOCK) then
      if COUNT_EN='1' then
        if COUNT_DIR='1' then
          if (FIFO_RD_DEL='1' and FIFO_WR_DEL='0') then
            DATA_COUNT <= DATA_COUNT_DELAY;
          else
            DATA_COUNT <= DATA_COUNT_PLUS;
          end if;
        else
          if (FIFO_WR_DEL='1' and FIFO_RD_DEL='0') then
            DATA_COUNT <= DATA_COUNT_DELAY;
          else
            DATA_COUNT <= DATA_COUNT_MINUS;
          end if;
        end if;
      end if;
    end if;
  end process;

  WRITE_FULL <= DATA_COUNT(23);

  READ_EMPTY <= '1' when DATA_COUNT="000000000000000000000000" else '0';

end RTL;
