--
-- CMOS H35 Deserialiser
-- Very much like the ABC130 version
--
-- Deserialises 160Mb streams. Operates at 80MHz so
-- data arrives in on 2 streams and is then combined. 
-- Packet detection operates as byte>0
-- Alignment is vi delays
-- 
--
-- Log:
-- 13/10/2014 - File re-born!
-- 30/1/2015 -- Type field changed from 4 to 8

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 h35_deser is
--  generic(
--    LINK_ID : integer := 0
--  );
  port(
    ts_count_i : std_logic_vector(39 downto 0);
    bco_mode20_i : std_logic;
    s20_i : std_logic;
    s40_i : std_logic;
    delay160_i : std_logic_vector(2 downto 0);
    mode_i : std_logic_vector(1 downto 0);

    -- 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
    en              : in  std_logic;
    clk             : in  std_logic;
    rst             : in  std_logic
    );

-- Declarations

end h35_deser;

--
architecture rtl of h35_deser is

  constant  BCOUNT_MAX        : integer := 31;
  constant  BCOUNT_MAX_M1 : integer:= BCOUNT_MAX-1;
  constant BCOUNT_MAX_M2 : integer := BCOUNT_MAX-2;

  constant  BCCAP_MAX        : integer := 59;
  constant  BCCAP_MAX_M1 : integer:= BCOUNT_MAX-1;
  constant BCCAP_MAX_M2 : integer := BCOUNT_MAX-2;

  constant OS : integer := 4;

  signal si   : slv8_array(1 downto 0);
  signal pre_ser_in   : slv2;
  signal ser_in : slv68;
  signal sdet   : slv64_array(1 downto 0);

  signal pkt_valid : std_logic;
  signal pkt_we    : std_logic;

  signal packet01  : slv64_array(1 downto 0);
  signal packet    : slv64;
  signal pkt_dbg  : slv64_array(1 downto 0);

  signal bcid    : slv20;
  signal byte_data    : slv8;
  signal byte_strb    : std_logic;
  signal byte_data_strobed    : slv8;
  signal delay80    : integer range 0 to 7;

  signal bcount            : integer range 0 to 63;
  signal bcount_clr        : std_logic;

  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 sublink : slv2;

  type states is ( PacketRdy, Wait_Packet, Idle_Cap, Wait_End_Cap, Idle );
  signal state, nstate : states;

begin

  bcid <= ts_count_i(20 downto 1) when (bco_mode20_i = '1') else
          ts_count_i(19 downto 0);

  -- *** this should be mode_i related ...
  byte_strb <= s20_i when (bco_mode20_i = '1') else s40_i;


  prc_link_mode : process (mode_i, link4x_i)
  begin
    case mode_i is
      when M320 => null; -- more work needed.

      when others => -- M160 is the default, no M80
        sublink(0) <= link4x_i(0);
        sublink(1) <= link4x_i(2);

    end case;
  end process;


  si(0)(0) <= sublink(0);
  si(1)(0) <= sublink(1);


  prc_pre_ser_in : process (clk)
  begin
    if rising_edge(clk) then
      if (rst = '1') then
        si(0)(7 downto 1)  <= (others => '0');
		  si(1)(7 downto 1)  <= (others => '0');

      else
        si(0)(7 downto 1)  <= si(0)(6 downto 0);
        si(1)(7 downto 1)  <= si(1)(6 downto 0);

      end if;
    end if;
  end process;

  delay80 <= conv_integer(delay160_i(2 downto 1));

  pre_ser_in(0) <= si(0)(delay80);
  pre_ser_in(1) <= si(1)(delay80);

  prc_ser_in : process (clk)
  begin
    if rising_edge(clk) then
      if (rst = '1') then
        ser_in     <= (others => '0');
      else
        if (en = '1') then
          -- *** I'm sure 0 then 1 is wrong! Also see swap for iserdes out
          -- ser_in <= ser_in(65 downto 0) & pre_ser_in(0) & pre_ser_in(1);
          ser_in <= ser_in(65 downto 0) & pre_ser_in(1) & pre_ser_in(0); -- ***note swapped
        end if;
      end if;
    end if;
  end process;


  -- Deserialise
  -------------------------------------------------------------------------

  -- Generate 160Mb offset packets for use by delay lsb
  -- Will have 4 streams for 320Mb


  gen_pkt_ser_in : for n in 0 to 1 generate
  begin
    pkt_dbg(n) <=
      x"8" & ser_in(59+OS-n downto 0+OS-n) when (capture_mode_i = '1') else
      x"8" & bcid & ser_in(39+OS-n downto 0+OS-n);

    packet01(n)(63 downto 0) <=
      x"8" & ser_in(59+OS-n downto 0+OS-n) when (capture_mode_i = '1') else
      x"8" & bcid & ser_in(39+OS-n downto 0+OS-n);

  end generate;

  packet <= packet01(0) when (delay160_i(0) = '1') else
            packet01(1);

  byte_data <= packet(31 downto 24);

  byte_data_strobed <= byte_data when (rising_edge(clk) and (byte_strb='1'));

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

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

      end if;
    end if;
  end process;


  prc_sm_deser_async : process (en, bcount, byte_strb, byte_data,
                                capture_mode_i, capture_start_i, cap_count, cap_count_max,
                                state)
  begin

    -- defaults
    bcount_clr    <= '0';
    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 (byte_strb = '1') then
              if (byte_data /= x"00") then
                nstate <= PacketRdy;
              end if;
            end if;
          end if;
        end if;


      when PacketRdy =>
        pkt_we <= '1';
        nstate    <= Wait_Packet;


      when Wait_Packet =>
        nstate   <= Wait_Packet;
        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 = BCCAP_MAX_M2) then
        --if (bcount = BCCAP_MAX_M1) then
        --if (bcount = BCCAP_MAX) then
          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';

      else
        -- default
        dropped_pkts_inc <= '0';

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

        end if;

        if (pkt_we = '1') then
          pkt_valid <= '1';

          --check if last one was read
          if (pkt_valid = '1') then
            dropped_pkts_inc <= '0';
          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') then
          bcount <= 0;

      elsif (capture_mode_i = '0') and (bcount = BCOUNT_MAX) then
          bcount <= 0;

      elsif (capture_mode_i = '1') and (bcount = BCCAP_MAX) then
        bcount <= 0;

      else
        bcount <= bcount + 1;

      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');

      elsif (dropped_pkts_count < x"ff") and (dropped_pkts_inc = '1') then
        dropped_pkts_count <= dropped_pkts_count + '1';

      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 (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 process;

end architecture rtl;