-- ==============================================================
-- FILE : HE_MSG_MSTR.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_MSG_MSTR
--  Date        : 08/02/2006
--  Author      : K.Chircop - HUNT ENGINEERING
--  Description : HUNT Serial Bus interface message mastering
--
-- ==============================================================
--
--  Ver     Modified By      Date      Changes
--  ---     -----------      ----      -------
--  1.0     K. Chircop     08-02-06   First Written for using the
--                                    new format USER message
--                                    interface.
--
-- ==============================================================


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_MSG_MSTR is
  port (
    -- PADS
    SFF           : in  std_logic;
    SACK          : in  std_logic;
    SCLK          : out std_logic;
    SDAT          : out std_logic;
    -- I/O module
    RST           : in  std_logic;
    CLK           : in  std_logic;
    CID           : in  std_logic_vector(3 downto 0);
    MID           : in  std_logic_vector(2 downto 0);
    MSG_SEND_MSG  : in  std_logic;
    MSG_SEND_ID   : in  std_logic;
    MSG_LAST_BYTE : in  std_logic;
    MSG_DOUT      : in  std_logic_vector(7 downto 0);
    MSG_DONE      : out std_logic;
    MSG_COUNT     : out std_logic;
    MSG_CLEAR     : out std_logic
  );
end HE_MSG_MSTR;


architecture Behavioral of HE_MSG_MSTR 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);

  signal state       : state_type;

  signal SFF_rg      : std_logic;
  signal SACK_rg     : std_logic;
  signal CLOCK       : std_logic;
  signal CKEN        : std_logic;
  signal CKEN_S      : std_logic;
  signal LOAD        : std_logic;
  signal BIT_CLR     : std_logic;
  signal BIT_TC      : std_logic;
  signal ID          : std_logic_vector(7 downto 0);
  signal DATA_OUT    : std_logic_vector(16 downto 0);

  signal BIT_CNT     : std_logic_vector(4 downto 0);
  signal BIT_CNT_RG  : std_logic_vector(4 downto 0);

  signal CLK_HI_TC   : std_logic;
  signal CLK_LO_TC   : std_logic;
  signal CLK_CNT_EN  : std_logic;
  signal CLK_CNT     : std_logic_vector(3 downto 0);

  signal GND         : std_logic;

begin

  GND <= '0';

  iSFF  : FDCP port map (Q=>SFF_rg,  C=>CLK, CLR=>GND, D=>SFF,  PRE=>RST);
  iSACK : FDCP port map (Q=>SACK_rg, C=>CLK, CLR=>GND, D=>SACK, PRE=>RST);

  ID <= '0' & CID & MID;

  process(CLK)
  begin
    if RST = '1' then
      BIT_CNT <= (others => '0');
    elsif rising_edge(CLK) then
      if BIT_CLR = '1' then
        BIT_CNT <= (others => '0');
      elsif CKEN = '1' then
        BIT_CNT <= BIT_CNT + 1;
      end if;
   end if;
  end process;

  process(CLK)
  begin
    if rising_edge(CLK) then
      BIT_CNT_RG <= BIT_CNT;
    end if;
  end process;

  BIT_TC <= '1' when BIT_CNT = 16 else '0';

  process(CLK)
  begin
    if rising_edge(CLK) then
      SCLK <= CLOCK;
    end if;
  end process;

  SDAT <= DATA_OUT(16);

  process(CLK)
  begin
    if RST = '1' then
      DATA_OUT(16 downto 0) <= (others => '0');
    elsif rising_edge(CLK) then
      if LOAD = '1' then
        DATA_OUT(8)            <= MSG_SEND_ID;
        DATA_OUT(9)            <= MSG_LAST_BYTE;
        DATA_OUT(16 downto 10) <= (others => '0');
        if MSG_SEND_ID = '0' then
          DATA_OUT(7 downto 0) <= MSG_DOUT;
        else
          DATA_OUT(7 downto 0) <= ID;
        end if;
      elsif CKEN = '1' then
        DATA_OUT(16 downto 0)  <= DATA_OUT(15 downto 0) & '0';
      end if;
    end if;
  end process;

  process(CLK)
  begin
    if RST = '1' then
      CLK_CNT <= (others => '0');
    elsif rising_edge(CLK) then
      if CLK_CNT_EN = '1' then
        CLK_CNT <= CLK_CNT + 1;
      else
        CLK_CNT <= (others => '0');
      end if;
   end if;
  end process;

  CLK_HI_TC <= '1' when CLK_CNT = "0100" else '0';
  CLK_LO_TC <= '1' when CLK_CNT = "1001" else '0';

  CKEN <= CKEN_S AND (NOT CLK_CNT(3)) AND (NOT CLK_CNT(2)) AND (NOT CLK_CNT(1)) AND CLK_CNT(0);

  process(RST, CLK)
  begin
    if RST='1' then
      state <= s1;
    elsif rising_edge(CLK) then
      case state is
        when s1  => if    MSG_SEND_MSG='1' and SFF_rg = '1'                then state <=  s2;
                    else                                                        state <=  s1;
                    end if;
        when s2  => if    CLK_HI_TC = '0'                                  then state <=  s2;
                    else                                                        state <=  s3;
                    end if;
        when s3  => if    CLK_LO_TC = '0'                                  then state <=  s3;
                    elsif BIT_TC='0'                                       then state <=  s2;
                    else                                                        state <=  s4;
                    end if;
        when s4  =>                                                             state <=  s5;
        when s5  =>                                                             state <=  s6;
        when s6  =>                                                             state <=  s7;
        when s7  =>                                                             state <=  s8;
        when s8  => if    SFF_rg='1' and SACK_rg='1' and MSG_LAST_BYTE='0' then state <=  s2;
                    elsif SFF_rg='1' and SACK_rg='1' and MSG_LAST_BYTE='1' then state <=  s9;
                    else                                                        state <=  s8;
                    end if;
        when s9  => if    CLK_HI_TC = '0'                                  then state <=  s9;
                    else                                                        state <= s10;
                    end if;
        when s10 => if    CLK_LO_TC = '0'                                  then state <= s10;
                    elsif BIT_TC='0'                                       then state <=  s9;
                    else                                                        state <= s11;
                    end if;
        when s11 =>                                                             state <= s12;
        when s12 =>                                                             state <= s13;
        when s13 => if    MSG_SEND_MSG='0'                                 then state <=  s1;
                    else                                                        state <= s13;
                    end if;
      end case;
    end if;
  end process;

  process(state)
  begin
    case state is
      when s1  => CLOCK      <= '0'; BIT_CLR   <= '1'; LOAD      <= '1';
                  MSG_DONE   <= '0'; MSG_COUNT <= '0'; MSG_CLEAR <= '0';
                  CLK_CNT_EN <= '0'; CKEN_S    <= '0';
--
      when s2  => CLOCK      <= '0'; BIT_CLR   <= '0'; LOAD      <= '0';
                  MSG_DONE   <= '0'; MSG_COUNT <= '0'; MSG_CLEAR <= '0';
                  CLK_CNT_EN <= '1'; CKEN_S    <= '1';
--
      when s3  => CLOCK      <= '1'; BIT_CLR   <= '0'; LOAD      <= '0';
                  MSG_DONE   <= '0'; MSG_COUNT <= '0'; MSG_CLEAR <= '0';
                  CLK_CNT_EN <= '1'; CKEN_S    <= '0';
--
      when s4  => CLOCK      <= '0'; BIT_CLR   <= '0'; LOAD      <= '0';
                  MSG_DONE   <= '0'; MSG_COUNT <= '1'; MSG_CLEAR <= '0';
                  CLK_CNT_EN <= '0'; CKEN_S    <= '0';
--
      when s5  => CLOCK      <= '0'; BIT_CLR   <= '0'; LOAD      <= '0';
                  MSG_DONE   <= '0'; MSG_COUNT <= '0'; MSG_CLEAR <= '0';
                  CLK_CNT_EN <= '0'; CKEN_S    <= '0';
--
      when s6  => CLOCK      <= '0'; BIT_CLR   <= '0'; LOAD      <= '1';
                  MSG_DONE   <= '0'; MSG_COUNT <= '0'; MSG_CLEAR <= '0';
                  CLK_CNT_EN <= '0'; CKEN_S    <= '0';
--
      when s7  => CLOCK      <= '0'; BIT_CLR   <= '0'; LOAD      <= '1';
                  MSG_DONE   <= '0'; MSG_COUNT <= '0'; MSG_CLEAR <= '0';
                  CLK_CNT_EN <= '0'; CKEN_S    <= '0';
--
      when s8  => CLOCK      <= '0'; BIT_CLR   <= '1'; LOAD      <= '0';
                  MSG_DONE   <= '0'; MSG_COUNT <= '0'; MSG_CLEAR <= '0';
                  CLK_CNT_EN <= '0'; CKEN_S    <= '0';
--
      when s9  => CLOCK      <= '0'; BIT_CLR   <= '0'; LOAD      <= '0';
                  MSG_DONE   <= '0'; MSG_COUNT <= '0'; MSG_CLEAR <= '0';
                  CLK_CNT_EN <= '1'; CKEN_S    <= '1';
--
      when s10 => CLOCK      <= '1'; BIT_CLR   <= '0'; LOAD      <= '0';
                  MSG_DONE   <= '0'; MSG_COUNT <= '0'; MSG_CLEAR <= '0';
                  CLK_CNT_EN <= '1'; CKEN_S    <= '0';
--
      when s11 => CLOCK      <= '0'; BIT_CLR   <= '0'; LOAD      <= '0';
                  MSG_DONE   <= '0'; MSG_COUNT <= '1'; MSG_CLEAR <= '0';
                  CLK_CNT_EN <= '0'; CKEN_S    <= '0';
--
      when s12 => CLOCK      <= '0'; BIT_CLR   <= '1'; LOAD      <= '0';
                  MSG_DONE   <= '0'; MSG_COUNT <= '0'; MSG_CLEAR <= '0';
                  CLK_CNT_EN <= '0'; CKEN_S    <= '0';
--
      when s13 => CLOCK      <= '0'; BIT_CLR   <= '1'; LOAD      <= '0';
                  MSG_DONE   <= '1'; MSG_COUNT <= '0'; MSG_CLEAR <= '1';
                  CLK_CNT_EN <= '0'; CKEN_S    <= '0';
    end case;
  end process;

end Behavioral;
