--
-- Synchro LocalLink MUX Controller
--
-- Original author Barry Green
-- re-worked (not nessesarily for the better) by Matt Warren.
--
-- At some point we should start thinking about timeouts when waiting for EOFs
--

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 ll_mux_ctrl256 is
   port(
      s_lls_i   : in     t_llsrc_array (255 downto 0);
      s_lldr_o  : out    std_logic_vector (255 downto 0);
      dst_rdy_i : in     std_logic;
      freeze_o  : out    std_logic;
      sel_o     : out    std_logic_vector (7 downto 0);
      rst       : in     std_logic;
      clk       : in     std_logic
   );

-- Declarations

end ll_mux_ctrl256 ;

--
architecture rtl of ll_mux_ctrl256 is

  type states is(
    WaitEOF,
    WaitState,
    Idle);
  signal state, nstate : states;

  --signal scount          : std_logic_vector(8 downto 0); --***2015
  --signal SCOUNT_MAX      : std_logic_vector(8 downto 0); --***2015
  signal scount          : std_logic_vector(7 downto 0);
  signal SCOUNT_MAX      : std_logic_vector(7 downto 0);
  signal selected_stream : integer range 255 downto 0;

  signal stream_inc : std_logic;
  signal sel_update : std_logic;


begin

  freeze_o <= not(dst_rdy_i);

  -- SM Clocked
  -------------------------------------------------------
  prc_sm_clocked : process(clk)
  begin
    if rising_edge(clk) then
      if (rst = '1') then
        state <= Idle;
      else
        state <= nstate;
      end if;
    end if;
  end process;


  -- SM Async
  -------------------------------------------------------
  prc_sm_async : process (state, s_lls_i, dst_rdy_i, selected_stream)
  begin

    -- defaults
    nstate     <= Idle;
    stream_inc <= '0';
    sel_update <= '0';
    s_lldr_o <= (others => '0');

    case state is

      when Idle =>
        nstate     <= Idle;
        stream_inc <= '1';
        if (s_lls_i(selected_stream).src_rdy = '1') then
          stream_inc <= '0';
          sel_update <= '1';
          nstate     <= WaitEOF;
        end if;


      when WaitEOF =>
        nstate <= WaitEOF;

        if (dst_rdy_i = '1') then
          s_lldr_o(selected_stream) <= '1';

          if (s_lls_i(selected_stream).eof = '1') then
            --nstate <= Idle;
            nstate <= WaitState;
          end if;
        end if;

      when WaitState =>
        nstate <= Idle;

    end case;

  end process;


  -- Port select counter
  -- The ordering could be more complicated with priority ports etc


  SCOUNT_MAX <= (others => '1');

  prc_port_sel_counter : process(clk)
  begin
    if rising_edge(clk) then
      if (rst = '1') then
        scount <= (others => '0');

      else
        if (stream_inc = '1') then
          if (scount = (SCOUNT_MAX-1)) then  -- don't need to double count Ack
            scount <= (others => '0');
          else
            scount <= scount + '1';
          end if;

        end if;
      end if;
    end if;
  end process;

  --***2015selected_stream <= conv_integer(scount(8 downto 1)) when (scount(0) = '0') else 255;
  selected_stream <= conv_integer(scount);

  prc_sel_out : process (clk)
  begin
    if rising_edge(clk) then
      if (rst = '1') then
        sel_o <= (others => '0');

      else
        if (sel_update = '1') then
          sel_o <= conv_std_logic_vector(selected_stream, 8);

        end if;
      end if;
    end if;
  end process;

end architecture rtl;