--
-- TLU Interface
--
-- Matt Warren 2014
--

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

library utils;
use utils.pkg_types.all;

library hsio;
use hsio.pkg_core_globals.all;



entity trig_tlu_if is
-- generic(
-- SIM_MODE : integer := 0
-- );
  port(
    trig_tlu_o      : out std_logic;
    tlu_trig_sync_i : in  std_logic;    -- syncronised, but not l2p
    --busy_i          : in  std_logic;
    busy_tlu_o      : out std_logic;
    tlu_tclk_o      : out std_logic;
    --tick_tclk_i     : in  std_logic;
    tog_i           : in  std_logic_vector(34 downto 0);
    trid_tlu_o      : out std_logic_vector(15 downto 0);
    trid_valid_o    : out std_logic;
    trid_new_o      : out std_logic;
--    debug_mode_i    : in  std_logic;
    debug_trig_i    : in  std_logic;
    l0id16_i        : in  std_logic_vector(15 downto 0);
    reg_tlu_ctl_i   : in  std_logic_vector(15 downto 0);
    s40             : in  std_logic;
    --en              : in  std_logic;
    clk             : in  std_logic;
    rst             : in  std_logic
    );

-- Declarations

end trig_tlu_if;

--
architecture rtl of trig_tlu_if is

  signal en : std_logic;


  signal bcount     : integer range 0 to 16 := 0;
  signal bcount_clr : std_logic;
  signal bcount_inc : std_logic;

  signal trid       : std_logic_vector(15 downto 0);
--  signal trid_shift : std_logic;
  signal trid_valid : std_logic;
  signal trid_new   : std_logic;
  signal trid_clr   : std_logic;

  signal tog_tclk : std_logic;
  signal tog_sel  : std_logic_vector(1 downto 0);

  signal tlu_tclk0     : std_logic;
  signal tlu_tclk_en   : std_logic;
  signal tick_tclk     : std_logic;
  signal tlu_tclk_tick : std_logic;

  signal tog_tclk_q : std_logic;

  signal trig_tlu0 : std_logic;

  signal trig_in   : std_logic;
  signal busy_tlu0 : std_logic;

  signal rx_delay : std_logic_vector(5 downto 0);

  signal rx_shiften_pipe : std_logic_vector(31 downto 0);
  signal rx_shiften      : std_logic;
  signal rx_count        : integer range 0 to 16 := 0;

  signal debug_mode :  std_logic;


  type states is (TrigOut0, TrigOut1,
                  WaitTrigLo, WaitTick0, WaitTick1,
                  SendTCLKs, LastTClk, WaitRX,
                  WaitState0, WaitState1,
                  Start, Idle
                  );

  signal state, nstate : states;

begin

  en         <= reg_tlu_ctl_i(bTLU_ENA);
  debug_mode <= reg_tlu_ctl_i(bTLU_DEBUG);


  trig_in <= tlu_trig_sync_i when (debug_mode = '0') else
             debug_trig_i;


  -- clock it out
  trid_valid_o <= trid_valid                      when rising_edge(clk);
  trid_new_o   <= trid_new                        when rising_edge(clk);
  trig_tlu_o   <= (trig_tlu0 and not(debug_mode)) when rising_edge(clk);
  busy_tlu_o   <= busy_tlu0                       when rising_edge(clk);

  tlu_tclk_o <= tlu_tclk0 when rising_edge(clk);


  tog_sel <= reg_tlu_ctl_i(bTLU_TCLK_RATEh downto bTLU_TCLK_RATEl);
  --tog_sel <= reg_tlu_ctl_i(15 downto 14);

  with tog_sel select tog_tclk <=
    tog_i(T_1MHz) when "11",
    tog_i(T_2MHz) when "10",
    tog_i(T_4MHz) when "01",
    tog_i(T_8MHz) when others;          -- "00"


  tog_tclk_q <= tog_tclk when rising_edge(clk);
  tick_tclk  <= tog_tclk and not(tog_tclk_q);


  -- State Machine
  --------------------------------------------------------
  prc_sync_part : process (clk)
  begin
    if rising_edge(clk) then
      if (rst = '1') or (en = '0') then
        state <= Start;
      else
        state <= nstate;

      end if;
    end if;
  end process;


  prc_async_machine : process (trig_in, tick_tclk, tog_tclk, bcount,
                               rx_shiften, rx_count,
                               s40, state
                               )
  begin

    -- defaults
    busy_tlu0     <= '1';
    bcount_clr    <= '0';
    bcount_inc    <= '0';
    --trid_shift    <= '0';
    trid_valid    <= '0';
    trid_new      <= '0';
    trid_clr      <= '0';
    trig_tlu0     <= '0';
    tlu_tclk_en   <= '0';
    tlu_tclk_tick <= '0';


    case state is

      -------------------------------------------------------------
      --- start same as Idle, but with trid_valid = '0'

      when Start =>
        nstate     <= Start;
        busy_tlu0  <= '0';
        bcount_clr <= '1';
        if (trig_in = '1') and (s40 = '1') then
          nstate <= TrigOut0;
        end if;


      when Idle =>
        nstate     <= Idle;
        busy_tlu0  <= '0';
        bcount_clr <= '1';
        trid_valid <= '1';
        if (trig_in = '1') and (s40 = '1') then
          nstate <= TrigOut0;
        end if;


      when TrigOut0 =>
        trig_tlu0 <= '1';
        trid_clr  <= '1';
        nstate    <= TrigOut1;


      when TrigOut1 =>
        trig_tlu0 <= '1' after 1 ns;
        nstate    <= WaitTrigLo;


      when WaitTrigLo =>
        nstate <= WaitTrigLo;
        if (trig_in = '0') then
          nstate <= WaitTick0;
        end if;


      when WaitTick0 =>
        nstate <= WaitTick0;
        if (tick_tclk = '1') then
          nstate <= WaitTick1;
        end if;


      when WaitTick1 =>
        nstate <= WaitTick1;
        if (tick_tclk = '1') then
          tlu_tclk_en <= '1';
          nstate <= SendTCLKs;
        end if;


      when SendTCLKs =>
        nstate      <= SendTCLKs;
        tlu_tclk_en <= '1';
        if (tick_tclk = '1') then
          bcount_inc    <= '1';
          tlu_tclk_tick <= '1';
          if (bcount = 14) then
            nstate <= LastTClk;
          end if;
        end if;

      when LastTClk =>
        nstate      <= LastTClk;
        tlu_tclk_en <= '1';
        if (tick_tclk = '1') then
          tlu_tclk_tick <= '1';
          tlu_tclk_en <= '0';
          nstate        <= WaitRX;
        end if;

      when WaitRX =>
        nstate     <= WaitRX;
        if (rx_count = 16) then
          trid_new      <= '1';
          nstate <= WaitState0;
        end if;

      when WaitState0 =>
        nstate     <= WaitState0;
        trid_valid <= '1';
        if (tick_tclk = '1') then
          nstate <= WaitState1;
        end if;


      when WaitState1 =>
        nstate     <= WaitState1;
        trid_valid <= '1';
        if (tick_tclk = '1') and (trig_in = '0') then
          nstate <= Idle;
        end if;

    end case;
  end process;


  ----------------------------------------------------------------------

  prc_bcount : process (clk)
  begin
    if rising_edge(clk) then

      -- tclk bit counter generate

      if (bcount_clr = '1') then
        bcount <= 0;

      elsif (bcount_inc = '1') then
        bcount <= bcount + 1;
      end if;

      -- tclk generate
      tlu_tclk0 <= tog_tclk and tlu_tclk_en;


    end if;
  end process;


  rx_delay <= reg_tlu_ctl_i(bTLU_TCLK_RXDELh downto bTLU_TCLK_RXDELl);
  --rx_delay <= reg_tlu_ctl_i(13 downto 8);

  rx_shiften_pipe <= rx_shiften_pipe(30 downto 0) & tlu_tclk_tick when rising_edge(clk);
  rx_shiften      <= rx_shiften_pipe(conv_integer(rx_delay));


  prc_trid : process (clk)
  begin
    if rising_edge(clk) then

      if (trid_clr = '1') then
        --trid <= "001" & x"234";         -- good for debug mode
        trid     <= (others => '0');
        rx_count <= 0;

      elsif (rx_shiften = '1') then
        trid <= tlu_trig_sync_i & trid(15 downto 1);

        rx_count <= rx_count + 1;

      end if;
    end if;
  end process;

  trid_tlu_o <= trid when (debug_mode = '0') else
                l0id16_i;


end architecture rtl;