-- ==============================================================
-- FILE : HE_USER.VHD  -  DO NOT EDIT THIS FILE
-- ==============================================================
--
-- This file is part of the Hardware Interface Layer (H.I.L) of
-- your project when using your HERON-FPGA14 module.
--
-- This file must NOT be modified by users of the Module.
--
-- ==============================================================
--
--  Module      : HE_USER
--  Date        : 28/02/2002
--  Author      : R. Williams - HUNT ENGINEERING
--  Description : HUNT Serial Bus interface
--
-- ==============================================================
--
--  Ver     Modified By      Date      Changes
--  ---     -----------      ----      -------
--  1.0     R. Williams    28-02-02    First Written
--  1.1     R. Williams    08-05-02    Syntax change made to all
--                                     instanciated components,
--                                     (changed '0' to GND)
--                                     for compatibility with
--                                     ModelSim5.5b.
--  1.2     R. Williams    11-06-02    Added 1ns delay on paths
--                                     from inferred flip-flops
--                                     to instantiated flip-flops
--                                     to prevent setup violations
--                                     in functional simulation.
--  2.0     R. Williams    10-10-02    New components added for
--                                     interfacing to all six HERON
--                                     input FIFOs and all six HERON
--                                     output FIFOs at the same time.
--                                     Added component HE_RD_6F in
--                                     place of component HE_RD_1F.
--                                     Added component HE_WR_6F in
--                                     place of component HE_WR_1F.
--  2.1     R. Williams    20-01-03    Changes made to the HSB
--                                     mastering functions, and 
--                                     additional registering added
--                                     to the AE flag to ensure
--                                     correct reading from HEPC8s.
--  3.0     K. Chircop     08-02-06    Adapted to use the new format
--                                     USER message interface.
--  3.1     R. Williams    16-10-07    Added address enable to
--                                     user message interface to
--                                     improve response to bursts.
--
-- ==============================================================


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

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

entity HE_USER is
  port (
    -- PADS
    UADSTRB   : in  std_logic;
    UAD       : in  std_logic;
    URDWR     : in  std_logic;
    UAD_IN    : in  std_logic_vector(3 downto 0);
    UAD_EN    : out std_logic;
    UDONE     : out std_logic;
    UAD_OUT   : out std_logic_vector(3 downto 0);
    -- I/O module
    RST       : in  std_logic;
    CLK       : in  std_logic;
    MSG_READY : in  std_logic;
    MSG_DOUT  : in  std_logic_vector(7 downto 0);
    MSG_AEN   : out std_logic;
    MSG_WEN   : out std_logic;
    MSG_REN   : out std_logic;
    MSG_ADDR  : out std_logic_vector(7 downto 0);
    MSG_DIN   : out std_logic_vector(7 downto 0)
  );
end HE_USER;


architecture Behavioral of HE_USER is

  component FDCP
    port (
      Q   : out std_logic;
      C   : in  std_logic;
      CLR : in  std_logic;
      D   : in  std_logic;
      PRE : in  std_logic
    );
  end component;

  type state_type is (s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14);

  signal state       : state_type;

  signal CNT         : std_logic;
  signal CNT_RG      : std_logic;
  signal CLR         : std_logic;
  signal TOGGLE      : std_logic;
  signal CKEN_OUT    : std_logic;
  signal ADEN        : std_logic;
  signal DATAEN      : std_logic;
  signal UADSTRB_rg1 : std_logic;
  signal UADSTRB_rg2 : std_logic;
  signal AD_TRI      : std_logic;

  signal GND         : std_logic;

begin

  GND <= '0';

  iADSTRB1 : FDCP port map (Q=>UADSTRB_rg1, C=>CLK, CLR=>GND, D=>UADSTRB,     PRE=>RST);
  iADSTRB2 : FDCP port map (Q=>UADSTRB_rg2, C=>CLK, CLR=>GND, D=>UADSTRB_rg1, PRE=>RST);

  UAD_EN <= AD_TRI;

  process(RST, CLK)
  begin
    if RST = '1' then
      CNT <= '0';
    elsif rising_edge(CLK) then
      if CLR='1' then
        CNT <= '0';
      elsif TOGGLE='1' then
        CNT <= '0';
        if CNT='0' then
          CNT <= '1';
        end if;
      end if;
    end if;
  end process;

  process(CLK)
  begin
    if RST = '1' then
      MSG_DIN <= (others => '0');
    elsif rising_edge(CLK) then
      if DATAEN = '1' then
        if CNT = '0' then
          MSG_DIN(7 downto 4) <= UAD_IN;
        else
          MSG_DIN(3 downto 0) <= UAD_IN;
        end if;
      end if;
    end if;
  end process;

  process(CLK)
  begin
    if RST = '1' then
      UAD_OUT <= (others => '0');
    elsif rising_edge(CLK) then
      if CKEN_OUT = '1' then
        if CNT = '0' then
          UAD_OUT <= MSG_DOUT(7 downto 4);
        else
          UAD_OUT <= MSG_DOUT(3 downto 0);
        end if;
      end if;
    end if;
  end process;

  process(CLK)
  begin
    if RST = '1' then
      MSG_ADDR <= (others => '0');
    elsif rising_edge(CLK) then
      if ADEN = '1' then
        if CNT = '0' then
          MSG_ADDR(7 downto 4) <= UAD_IN;
        else
          MSG_ADDR(3 downto 0) <= UAD_IN;
        end if;
      end if;
    end if;
  end process;

  process(RST, CLK)
  begin
    if RST='1' then
      MSG_AEN <= '0';
    elsif rising_edge(CLK) then
      MSG_AEN <= '0';
      if ((ADEN = '1') and (CNT = '1')) then
        MSG_AEN <= '1';
      end if;
    end if;
  end process;

  process(RST, CLK)
  begin
    if RST='1' then
      state <= s1;
    elsif rising_edge(CLK) then
      case state is
        when s1  => if    UADSTRB_rg2='0' and UAD = '1' and URDWR = '0' then state <=  s2;
                    else                                                     state <=  s1;
                    end if;
        when s2  =>                                                          state <=  s3;
        when s3  => if    UADSTRB_rg2='0'                               then state <=  s3;
                    else                                                     state <=  s4;
                    end if;
        when s4  => if    UADSTRB_rg2='1'                               then state <=  s4;
                    elsif CNT='1'                                       then state <=  s2;
                    else                                                     state <=  s5;
                    end if;
        when s5  => if    URDWR='0'                                     then state <=  s6;
                    else                                                     state <= s10;
                    end if;
        when s6  =>                                                          state <=  s7;
        when s7  => if    UADSTRB_rg2='0'                               then state <=  s7;
                    elsif CNT='0'                                       then state <=  s8;
                    else                                                     state <=  s9;
                    end if;
        when s8  => if    MSG_READY = '0'                               then state <=  s8;
                    else                                                     state <=  s9;
                    end if;
        when s9  => if    UADSTRB_rg2='1'                               then state <=  s9;
                    elsif UAD='0'                                       then state <=  s6;
                    else                                                     state <=  s1;
                    end if;
        when s10 => if    MSG_READY = '0'                               then state <= s10;
                    else                                                     state <= s11;
                    end if;
        when s11 =>                                                          state <= s12;
        when s12 => if    UADSTRB_rg2='0'                               then state <= s12;
                    else                                                     state <= s13;
                    end if;
        when s13 =>                                                          state <= s14;
        when s14 => if    UADSTRB_rg2='1'                               then state <= s14;
                    elsif UAD='0' and CNT = '1'                         then state <= s11;
                    elsif UAD='0' and CNT = '0'                         then state <= s10;
                    else                                                     state <=  s1;
                    end if;
      end case;
    end if;
  end process;

  process(state)
  begin
    case state is
      when s1  => UDONE <= '1'; MSG_WEN <= '0'; MSG_REN  <= '0';
                  ADEN  <= '0'; DATAEN  <= '0'; CKEN_OUT <= '0';
                  CLR   <= '1'; TOGGLE  <= '0'; AD_TRI   <= '1';
--
      when s2  => UDONE <= '1'; MSG_WEN <= '0'; MSG_REN  <= '0';
                  ADEN  <= '1'; DATAEN  <= '0'; CKEN_OUT <= '0';
                  CLR   <= '0'; TOGGLE  <= '1'; AD_TRI   <= '1';
--
      when s3  => UDONE <= '0'; MSG_WEN <= '0'; MSG_REN  <= '0';
                  ADEN  <= '0'; DATAEN  <= '0'; CKEN_OUT <= '0';
                  CLR   <= '0'; TOGGLE  <= '0'; AD_TRI   <= '1';
--
      when s4  => UDONE <= '1'; MSG_WEN <= '0'; MSG_REN  <= '0';
                  ADEN  <= '0'; DATAEN  <= '0'; CKEN_OUT <= '0';
                  CLR   <= '0'; TOGGLE  <= '0'; AD_TRI   <= '1';
--
      when s5  => UDONE <= '1'; MSG_WEN <= '0'; MSG_REN  <= '0';
                  ADEN  <= '0'; DATAEN  <= '0'; CKEN_OUT <= '0';
                  CLR   <= '1'; TOGGLE  <= '0'; AD_TRI   <= '1';
--
      when s6  => UDONE <= '1'; MSG_WEN <= '0'; MSG_REN  <= '0';
                  ADEN  <= '0'; DATAEN  <= '1'; CKEN_OUT <= '0';
                  CLR   <= '0'; TOGGLE  <= '1'; AD_TRI   <= '1';
--
      when s7  => UDONE <= '0'; MSG_WEN <= '0'; MSG_REN  <= '0';
                  ADEN  <= '0'; DATAEN  <= '0'; CKEN_OUT <= '0';
                  CLR   <= '0'; TOGGLE  <= '0'; AD_TRI   <= '1';
--
      when s8  => UDONE <= '0'; MSG_WEN <= '1'; MSG_REN  <= '0';
                  ADEN  <= '0'; DATAEN  <= '0'; CKEN_OUT <= '0';
                  CLR   <= '0'; TOGGLE  <= '0'; AD_TRI   <= '1';
--
      when s9  => UDONE <= '1'; MSG_WEN <= '0'; MSG_REN  <= '0';
                  ADEN  <= '0'; DATAEN  <= '0'; CKEN_OUT <= '0';
                  CLR   <= '0'; TOGGLE  <= '0'; AD_TRI   <= '1';

--
      when s10 => UDONE <= '1'; MSG_WEN <= '0'; MSG_REN  <= '1';
                  ADEN  <= '0'; DATAEN  <= '0'; CKEN_OUT <= '0';
                  CLR   <= '0'; TOGGLE  <= '0'; AD_TRI   <= '1';
--
      when s11 => UDONE <= '1'; MSG_WEN <= '0'; MSG_REN  <= '0';
                  ADEN  <= '0'; DATAEN  <= '0'; CKEN_OUT <= '1';
                  CLR   <= '0'; TOGGLE  <= '0'; AD_TRI   <= '0';
--
      when s12 => UDONE <= '0'; MSG_WEN <= '0'; MSG_REN  <= '0';
                  ADEN  <= '0'; DATAEN  <= '0'; CKEN_OUT <= '0';
                  CLR   <= '0'; TOGGLE  <= '0'; AD_TRI   <= '0';
--
      when s13 => UDONE <= '1'; MSG_WEN <= '0'; MSG_REN  <= '0';
                  ADEN  <= '0'; DATAEN  <= '0'; CKEN_OUT <= '0';
                  CLR   <= '0'; TOGGLE  <= '1'; AD_TRI   <= '0';
--
      when s14 => UDONE <= '1'; MSG_WEN <= '0'; MSG_REN  <= '0';
                  ADEN  <= '0'; DATAEN  <= '0'; CKEN_OUT <= '0';
                  CLR   <= '0'; TOGGLE  <= '0'; AD_TRI   <= '1';
    end case;
  end process;

end Behavioral;
