--
-- ABC130 Deserialiser
--
-- Deserialises 160Mb HCC streams. HSIO still operates at 80MHz so
-- data arrives in on 2 streams and is then combined. Packet detection
-- operates on both "sides" of the stream.
-- 
--
-- Log:
-- 30/11/2012 - File born!
-- 18/02/2015 - Added demux option using STREAM_ID to steer.


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 ro13_deser is
  generic(
    STREAM_ID  : integer := 0;
    SUBSTRM_ID : integer := 0
    );
  port(
    -- In
    link4x_i        : in  slv4;
    -- Pkt Out
    packet_o        : out std_logic_vector (63 downto 0);  --t_packet;
    pkt_valid_o     : out std_logic;
    pkt_rdack_i     : in  std_logic;
    --
    dropped_pkts_o  : out std_logic_vector (7 downto 0);
    capture_mode_i  : in  std_logic;
    capture_start_i : in  std_logic;
    capture_len_i   : in  std_logic_vector (9 downto 0);
    -- infra
    mode_i          : in  std_logic_vector (1 downto 0);
    mode_abc_i      : in  std_logic;
    en              : in  std_logic;
    s40             : in  std_logic;
    clk             : in  std_logic;
    rst             : in  std_logic
    );

-- Declarations

end ro13_deser;

--
architecture rtl of ro13_deser is

  signal s40m40  : std_logic;

  signal ser_in  : slv68;
  signal sublink : slv2;
  signal sdet    : slv64_array(1 downto 0);


  signal hpktdet_true  : slv2;
  signal hpktdet_false : slv2;
  signal hpktdet       : slv2;
  signal apktdet_true  : slv2;
  signal apktdet_false : slv2;
  signal apktdet       : slv2;
  signal pktdet_true   : slv2;
  signal pktdet_false  : slv2;
  signal pktdet        : slv2;

  signal hcc_reg_sel : slv2;

  signal pkt_valid  : std_logic;
  signal pkt_we     : slv2;
  signal hpacket    : slv64_array(1 downto 0);  --t_packet_array(1 downto 0);
  signal apacket    : slv64_array(1 downto 0);  --t_packet_array(1 downto 0);
  signal packet     : slv64_array(1 downto 0);  --t_packet_array(1 downto 0);
  signal cap_packet : slv64;

  signal bcount            : integer range 0 to 63;
  signal bcount_clr        : std_logic;
  signal bcount_max        : integer;
  signal bcount_max_minus1 : integer;
  signal bcount_max_minus2 : integer;
  signal bc_max_hcc        : integer;
  signal bc_max_m1_hcc     : integer;
  signal bc_max_m2_hcc     : integer;
  signal bc_max_abc        : integer;
  signal bc_max_m1_abc     : integer;
  signal bc_max_m2_abc     : integer;
  signal bc_max_cap        : integer;
  signal bc_max_m1_cap     : integer;
  signal bc_max_m2_cap     : integer;

  signal dropped_pkts_count : slv8;
  signal dropped_pkts_inc   : sl;

  signal cap_count     : slv10;
  signal cap_count_max : slv10;
  signal cap_count_inc : sl;
  signal cap_count_clr : sl;
  signal cap_pkt_we    : std_logic;
  signal dbg_cap_pkt   : std_logic_vector(59 downto 0);


  -- G : gap (need to check this on final chip)
  -- S : start bit
  -- C : chipid
  -- T : type
  -- L : l1id
  -- B : bcid
  -- P : payload
  -- s : stop bit

  -- HCC specific
  -- h : HL_SLCT (wha?)
  -- e : HCC Error
  -- c : HL_LR (high priority?)
  -- l : Loop (which ABC130 chain)


  -- HCC Mode
  -------------------------------------------------------------------------------------------------
  --                             "7777777766666666555555554444444433333333222222221111111100000000"
  --                             "---6---------5---------4---------3---------2---------1---------0"
  --                             "3210987654321098765432109876543210987654321098765432109876543210"
  --                             "SheclCCCCCTTTTLLLLLLLLBBBBBBBBPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPs"
  constant HDETMASK_T : slv64 := "1000000000000000000000000000000000000000000000000000000000000001";
  constant HDETBITS_T : slv64 := "1000000000000000000000000000000000000000000000000000000000000001";
  -- *** skipping non-zero chip id and type checking for now
--constant HDETMASK_F : slv64 := "0000001111111100000000000000000000000000000000000000000000000000";
--constant HDETBITS_F : slv64 := "0000000000000000000000000000000000000000000000000000000000000000";
  constant HDETMASK_F : slv64 := "0000000000000000000000000000000000000000000000000000000000000000";
  constant HDETBITS_F : slv64 := "1111111111111111111111111111111111111111111111111111111111111111";


  -- ABC130 Mode
  -------------------------------------------------------------------------------------------------
  --
  --                             "7777777766666666555555554444444433333333222222221111111100000000"
  --                             "---6---------5---------4---------3---------2---------1---------0"
  --                             "3210987654321098765432109876543210987654321098765432109876543210"
  --                             "0000SCCCCCTTTTLLLLLLLLBBBBBBBBPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPs"
  constant ADETMASK_T : slv64 := "0001100000000000000000000000000000000000000000000000000000000000";
  constant ADETBITS_T : slv64 := "0000100000000000000000000000000000000000000000000000000000000000";
  -- *** skipping non-zero chip id and type checking for now
--constant ADETMASK_F : slv64 := "0000111111111000000000000000000000000000000000000000000000000000";
--constant ADETBITS_F : slv64 := "0000000000000000000000000000000000000000000000000000000000000000";
  constant ADETMASK_F : slv64 := "0000000000000000000000000000000000000000000000000000000000000000";
  constant ADETBITS_F : slv64 := "1111111111111111111111111111111111111111111111111111111111111111";

  signal OS             : integer := 4;  -- constant, but assigned in-code
  signal SUBSTRM_ID_SLV : std_logic_vector(3 downto 0);

  signal hpkt_dbg : slv64_array(1 downto 0);
  signal apkt_dbg : slv64_array(1 downto 0);
  --signal pkt_dbg  : slv64_array(1 downto 0);
  signal pkt_dbg  : slv64;


  signal strm_id_slv : slv8;

  type   states is (Packet0, Packet1, Wait_Packet0, Wait_Packet1, Idle_Cap, Wait_End_Cap, Idle);
  signal state, nstate : states;


begin

  strm_id_slv <= conv_std_logic_vector(STREAM_ID, 8);

  SUBSTRM_ID_SLV <= conv_std_logic_vector(SUBSTRM_ID, 4);

  bc_max_hcc    <= 63 when (mode_i = M80) or (mode_i = M40) else 31;
  bc_max_m1_hcc <= 62 when (mode_i = M80) or (mode_i = M40) else 30;
  bc_max_m2_hcc <= 61 when (mode_i = M80) or (mode_i = M40) else 29;

  bc_max_abc    <= 59 when (mode_i = M80) or (mode_i = M40) else 29;
  bc_max_m1_abc <= 58 when (mode_i = M80) or (mode_i = M40) else 28;
  bc_max_m2_abc <= 57 when (mode_i = M80) or (mode_i = M40) else 27;

  bcount_max        <= bc_max_abc    when (mode_abc_i = '1') else bc_max_hcc;
  bcount_max_minus1 <= bc_max_m1_abc when (mode_abc_i = '1') else bc_max_m1_hcc;
  bcount_max_minus2 <= bc_max_m2_abc when (mode_abc_i = '1') else bc_max_m2_hcc;

  bc_max_cap    <= 59 when (mode_i = M80) or (mode_i = M40) else 29;
  bc_max_m1_cap <= 58 when (mode_i = M80) or (mode_i = M40) else 28;
  bc_max_m2_cap <= 57 when (mode_i = M80) or (mode_i = M40) else 27;


  prc_link_mode : process (mode_i, strm_id_slv, link4x_i)
  begin
    case mode_i is
      when M320 =>
        if (strm_id_slv(0) = '0') then
          sublink(0) <= link4x_i(0);
          sublink(1) <= link4x_i(2);
        else                            -- odd stream
          sublink(0) <= link4x_i(1);
          sublink(1) <= link4x_i(3);
        end if;

      when M160 =>
        sublink(0) <= link4x_i(0);
        sublink(1) <= link4x_i(2);

      when M80 =>
        if (strm_id_slv(0) = '0') then
          sublink(0) <= link4x_i(0);
        else
          sublink(0) <= link4x_i(2);
        end if;
        sublink(1) <= '0';

      when M40 =>                       -- Note same as M80 for now
        if (strm_id_slv(0) = '0') then
          sublink(0) <= link4x_i(0);
        else
          sublink(0) <= link4x_i(2);
        end if;
        sublink(1) <= '0';


      when others => null;

    end case;
  end process;


  s40m40 <= not(s40) when (mode_i = M40) else '1';

  prc_ser_in : process (clk)
  begin
    if rising_edge(clk) then
      if (rst = '1') then
        ser_in <= (others => '0');
      else
        if (en = '1') then
          if (mode_i = M80) then
            --ser_in <= ser_in(66 downto 0) & ser_i(conv_integer(strm_id_slv(0)));
            ser_in <= ser_in(66 downto 0) & sublink(0);

          elsif (mode_i = M40) then
            --ser_in <= ser_in(66 downto 0) & ser_i(conv_integer(strm_id_slv(0)));
            if (s40 = '0') then
              ser_in <= ser_in(66 downto 0) & sublink(0);
            end if;

          else                          -- mode160
            --ser_in <= ser_in(65 downto 0) & ser_i(0) & ser_i(1);  
            ser_in <= ser_in(65 downto 0) & sublink(1 downto 0);  -- ***note order swap
          end if;
        end if;
      end if;
    end if;
  end process;


  -- Packet detect and deserialise
  -------------------------------------------------------------------------

  -- Need to check odd and even 80Mb streams for 160Mb operation

  -- Offset, assigned here for legi
  OS <= 3;


  gen_pkt_ser_in : for n in 0 to 1 generate
  begin

    sdet(n) <= ser_in(64-n downto 1-n);

    -- Detect packet
    ----------------------------------------------------------
    hpktdet_true(n)  <= '1' when ((sdet(n) and HDETMASK_T) = HDETBITS_T)  else '0';
    hpktdet_false(n) <= '1' when ((sdet(n) and HDETMASK_F) /= HDETBITS_F) else '0';
    hpktdet(n)       <= (hpktdet_true(n) and hpktdet_false(n)) or capture_mode_i;

    apktdet_true(n)  <= '1' when ((sdet(n) and ADETMASK_T) = ADETBITS_T)  else '0';
    apktdet_false(n) <= '1' when ((sdet(n) and ADETMASK_F) /= ADETBITS_F) else '0';
    apktdet(n)       <= (apktdet_true(n) and apktdet_false(n)) or capture_mode_i;

    --  pktdet(n) <= hpktdet(n) when (mode_abc_i = '0') else apktdet(n);


    -- Build packets
    ----------------------------------------------------------

    -- HCC
    ---------------------------------------------------
    hpkt_dbg(n) <= ser_in(63+OS-n downto 0+OS-n);

    hpacket(n)(63)           <= '0';    -- DAQ-Type = HCC/ABC packet
    hpacket(n)(62 downto 61) <= SUBSTRM_ID_SLV(1 downto 0);  -- Link ID
    hpacket(n)(60)           <= ser_in(60+OS-n);             -- HL_LR
    hpacket(n)(59)           <= ser_in(59+OS-n);             -- LOOP
    hpacket(n)(58)           <= ser_in(61+OS-n);             -- HCC Error
    hpacket(n)(57 downto 1)  <= ser_in(58+OS-n downto 2+OS-n);

    hcc_reg_sel(n) <= ser_in(62+OS-n);
    hpacket(n)(0)  <= '0' when (hcc_reg_sel(n) = '1') else  -- HCC mode (2b trailer), add 0
                      ser_in(1+OS-n);   -- ABC mode (only 1b trailer)

    --with  hcc_reg_sel(n) select hpacket(n)(57 downto 0) <=  -- HS_SLCT bit 
    -- ser_in(58+OS-n downto 2+OS-n) & '0' when '1', -- HCC remove 2b trailer, add 0 
    -- ser_in(58+OS-n downto 1+OS-n) when others;    -- ABC remove 1b trailer 


    -- ABC (single chip)
    ---------------------------------------------------
    apkt_dbg(n)              <= "0000" & ser_in(59+OS+1-n downto 0+OS+1-n);
    apacket(n)(63 downto 60) <= '0' & SUBSTRM_ID_SLV(1 downto 0) & '0';
    apacket(n)(59 downto 0)  <= ser_in(59+OS-n downto 0+OS-n);


    -- Capture
    ---------------------------------------------------
    cap_packet <= '0' & SUBSTRM_ID_SLV(1 downto 0) & '0' &
                  ser_in(59+OS downto 0+OS);


  end generate;

  pktdet <= hpktdet when (mode_abc_i = '0') else apktdet;
  packet <= hpacket when (mode_abc_i = '0') else apacket;


  ---------------------------------------------------------------
  -- Deser Machine
  ---------------------------------------------------------------

  prc_sm_deser_sync : process (clk)
  begin
    if rising_edge(clk) then
      if (rst = '1') then
        state <= Idle;
      else
        if (s40m40 = '1') then

          state <= nstate;

        end if;

      end if;
    end if;
  end process;


  prc_sm_deser_async : process (en, pktdet, mode_i,
                                bcount, bcount_max, bcount_max_minus1, bcount_max_minus2,
                                capture_mode_i, capture_start_i, cap_count, cap_count_max,
                                bc_max_cap,
                                state)
  begin

    -- defaults
    bcount_clr    <= '0';
    pkt_we        <= "00";
    cap_pkt_we    <= '0';
    cap_count_clr <= '0';
    cap_count_inc <= '0';

    case state is

      when Idle =>
        nstate     <= Idle;
        bcount_clr <= '1';
        if (capture_mode_i = '1') then
          nstate <= Idle_Cap;
        else
          if (en = '1') then

            if (mode_i = M80) or (mode_i = M40) then
              if (pktdet(0) = '1') then
                nstate <= Packet1;  -- this 0=1 thing is to compensate for SR step=2
              end if;

              --elsif (mode_i = M40) then
              --  if (s40 = '0') then
              --  if (pktdet(0) = '1') then
              --    nstate <= Packet1;  -- this 0=1 thing is to compensate for SR step=2
              --  end if;
              --  end if;

            else
              if (pktdet(0) = '1') then
                nstate <= Packet0;
              elsif (pktdet(1) = '1') then
                nstate <= Packet1;
              end if;

            end if;
          end if;
        end if;


      when Packet0 =>
        pkt_we(0) <= '1';
        nstate    <= Wait_Packet0;


      when Packet1 =>
        pkt_we(1) <= '1';
        nstate    <= Wait_Packet1;


      when Wait_Packet0 =>
        nstate <= Wait_Packet0;
        if (bcount = bcount_max_minus1) then
          nstate <= Idle;
        end if;

      when Wait_Packet1 =>
        nstate <= Wait_Packet1;
        if (bcount = bcount_max) then
          nstate <= Idle;
        end if;


        -- Capture Mode
        ----------------------------------------------
      when Idle_Cap =>
        nstate        <= Idle_Cap;
        cap_count_clr <= '1';
        bcount_clr    <= '1';
        if (capture_mode_i = '0') then
          nstate <= Idle;
        elsif (capture_start_i = '1') and (en = '1') then
          nstate <= Wait_End_Cap;
        end if;


      when Wait_End_Cap =>
        nstate <= Wait_End_Cap;

        if (bcount = bc_max_cap) then
          cap_pkt_we    <= '1';
          bcount_clr    <= '1';
          cap_count_inc <= '1';

          if (cap_count = cap_count_max) then
            nstate <= Idle_Cap;
          end if;
        end if;


    end case;
  end process;





  -- Packet output interface
  -------------------------------------------------------------------------

  prc_packet_out : process(clk)
  begin
    if rising_edge(clk) then
      if (rst = '1') then
        packet_o         <= (others => '0');
        pkt_valid        <= '0';
        dbg_cap_pkt      <= (others => '0');
        dropped_pkts_inc <= '0';

      else

        -- default
        dropped_pkts_inc <= '0';

        if (pkt_we(0) = '1') then
          packet_o <= packet(0);

          if (mode_abc_i = '0') then
            pkt_dbg <= hpkt_dbg(0);
          else
            pkt_dbg <= apkt_dbg(0);
          end if;


        elsif (pkt_we(1) = '1') then
          packet_o <= packet(1);
          if (mode_abc_i = '0') then
            pkt_dbg <= hpkt_dbg(1);
          else
            pkt_dbg <= apkt_dbg(1);
          end if;


        elsif (cap_pkt_we = '1') then
          packet_o    <= cap_packet;
          dbg_cap_pkt <= ser_in(59 downto 0);
        end if;

        if (pkt_we(0) = '1') or (pkt_we(1) = '1') or (cap_pkt_we = '1') then
          pkt_valid <= '1';

          --check if last one was read
          if (pkt_valid = '1') then
            dropped_pkts_inc <= '1';
          end if;

        elsif (pkt_rdack_i = '1') then
          pkt_valid <= '0';

        end if;


      end if;
    end if;

  end process;



  pkt_valid_o <= pkt_valid;


  -- Bit counter (2 bits per tick)
  -------------------------------------------------

  prc_bcount : process (clk)
  begin
    if rising_edge(clk) then
      if (rst = '1') then
        bcount <= 0;

        --elsif (bcount_clr = '1') or (bcount = bcount_max) then
      else
        if (s40m40 = '1') then

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

          else
            bcount <= bcount + 1;

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


  -- Dropped packet counter
  -----------------------------------------------------

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

      else
        if (s40m40 = '1') then
          if (dropped_pkts_count < x"ff") and (dropped_pkts_inc = '1') then
            dropped_pkts_count <= dropped_pkts_count + '1';

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


  dropped_pkts_o <= dropped_pkts_count;


  -- Capture mode len counter
  -----------------------------------------------------

  cap_count_max <= capture_len_i;       -- byte val converted to 64b words

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

      else
        if (s40m40 = '1') then
          if (cap_count_clr = '1') then
            cap_count <= (others => '0');

          elsif (cap_count_inc = '1') then
            cap_count <= cap_count + '1';

          end if;
        end if;

      end if;
    end if;
  end process;

end architecture rtl;