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

entity ro13_datagen80 is
  generic(
    DOFFSET       :     std_logic_vector(15 downto 0) := x"0100"
    );
  port(
    mode_abc_i       : in  std_logic;
    start_i       : in  std_logic;
    abc130_data_o : out slv2;
    len_i         : in  std_logic_vector (11 downto 0);
    en            : in  std_logic;
    clk           : in  std_logic;
    rst           : in  std_logic
    );

-- Declarations

end ro13_datagen80;

--
architecture rtl of ro13_datagen80 is


  signal data_count : slv8;
  signal bcount     : slv6;
  signal bcount_set : std_logic;
  signal bit_count  : slv4;


  constant BCOUNT_MAX : slv5 := "11111";

  signal up_down  : slv2;
  signal gen_done : std_logic;

  constant DELTA_STARTS_MAX : integer := 15;
  signal   delta_starts     : integer range 0 to DELTA_STARTS_MAX;

  signal hpkt     : slv64;
  signal apkt     : slv64;
  signal pkt     : slv64;

  signal dp : slv64;
  signal dbg_pkt : slv64;

  signal dcount     : slv16;
  signal dcount_inc : std_logic;
  signal dcount_clr : std_logic;

  signal pcount     : integer range 0 to 255;
  signal pcount_max     : integer range 0 to 255;
  signal pcount_inc : std_logic;
  signal pcount_clr : std_logic;

  signal in_packet : sl;
  signal pkt_debug_mode : sl;



  type states is (SendData, Reset, Gap, Idle);

  signal state, nstate : states;



begin

  pcount_max <= conv_integer(len_i(7 downto 0));


  pkt_debug_mode <= '0';

  hpkt <= x"9080f081c082c083" when pkt_debug_mode = '1' else
          "10" &                        -- SS
--        dcount(13 downto 5) & '1'     -- *** Could check for non-zero type, but not yet
--        & dcount(3 downto 0) &        --   HHHCCCCCTTTTLL  KKHHHCCCCCTTTTLL   Typ must be non zero
          dcount(13 downto 0) &         --   HHHCCCCCTTTTLL  KKHHHCCCCCTTTTLL
          dcount(15 downto 0) &         -- LLLLLLBBBBBBBBPP  LLLLLLBBBBBBBBPP
          dcount(15 downto 0) &         -- PPPPPPPPPPPPPPPP  PPPPPPPPPPPPPPPP
          dcount(15 downto 0);          -- PPPPPPPPPPPPPPPs  PPPPPPPPPPPPPPPs


  apkt <= x"0983a082b081c080" when pkt_debug_mode = '1' else
          "00001" &                     -- 0000S
--        dcount(13 downto 5) & '1'     -- *** Could check for non-zero type, but not yet
--        & dcount(3 downto 0) &        --      CCCCCTTTTLL  KK000CCCCCTTTTLL   Typ must be non zero
          dcount(10 downto 0) &         --      CCCCCTTTTLL  KK000CCCCCTTTTLL
          dcount(15 downto 0) &         -- LLLLLLBBBBBBBBPP  LLLLLLBBBBBBBBPP
          dcount(15 downto 0) &         -- PPPPPPPPPPPPPPPP  PPPPPPPPPPPPPPPP
          dcount(15 downto 0);          -- PPPPPPPPPPPPPPPs  PPPPPPPPPPPPPPPs


  pkt   <= hpkt when (mode_abc_i = '0') else apkt;

  abc130_data_o(0) <= pkt(conv_integer(bcount)) and in_packet;
  abc130_data_o(1) <= pkt(conv_integer(bcount)) and in_packet;


  prc_dbg_pkt : process(clk)
  begin
    if rising_edge(clk) then
      if (in_packet = '1') then

        case bcount(4 downto 3) is
          when "11" => dp(63 downto 48) <= pkt(63 downto 48);
          when "10" => dp(47 downto 32) <= pkt(47 downto 32);
          when "01" => dp(31 downto 16) <= pkt(31 downto 16);
          when "00" => dbg_pkt          <= dp(63 downto 16) & pkt(15 downto 0);

          when others => null;
        end case;
      end if;
    end if;
  end process;

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


  prc_sm_sync : process (clk)
  begin
    if rising_edge(clk) then
      if (rst = '1') or (en = '0') then
        state <= Reset;

      else
        state <= nstate;

      end if;
    end if;
  end process;


  prc_sm_async : process (state, delta_starts, bcount, bit_count, pcount, pcount_max )
  begin

-- defaults
    gen_done   <= '0';
    bcount_set <= '0';
    dcount_clr <= '0';
    dcount_inc <= '0';
    pcount_clr <= '0';
    pcount_inc <= '0';
    in_packet  <= '0';

    case state is

      when Reset =>
        dcount_clr <= '1';
        pcount_clr <= '1';
        nstate     <= Idle;

      when Idle =>
        nstate       <= Idle;
        bcount_set   <= '1';
        pcount_clr <= '1';
        if (delta_starts > 0) then
          in_packet  <= '1';
          bcount_set <= '0';
          nstate     <= SendData;
        end if;


      when SendData =>
        nstate       <= SendData;
        in_packet    <= '1';
        if (bcount = 0) then
          dcount_inc <= '1';
          if (pcount < pcount_max) then
             pcount_inc <= '1';
          else
            gen_done   <= '1';
            nstate <= Gap;
          end if;
        elsif (bit_count = "0000") then
          dcount_inc <= '1';
        end if;


      when Gap =>
          nstate <= Gap;
          if (bcount = 0) then
            nstate <= Idle;
          end if;

    end case;
  end process;


  -- bit/byte counter
  -------------------

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

      else
        if (bcount_set = '1') or (bcount = "000000") then
          bcount <= (others => '1');

        else
          bcount <= bcount - '1';

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

  bit_count <= bcount(3 downto 0);


  -- pkt counter
  -------------------

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

      else
        if (pcount_clr = '1') then
          pcount <= 0;

        elsif (pcount_inc = '1') then
          pcount <= pcount + 1;

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


  -- data counter
  -------------------

  prc_dcount : process (clk)
  begin
    if rising_edge(clk) then
      if (rst = '1') or (en = '0') then
        dcount <= DOFFSET;

      else

        if (dcount_inc = '1') then
          dcount <= dcount + '1';

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




-- pkts to send counter
---------------------------------------------------------------

  up_down <= start_i & gen_done;

  prc_start_counter : process (clk)
  begin
    if rising_edge(clk) then
      if (rst = '1') or (en = '0') then
        delta_starts <= 0;

      else

        if (up_down = "01") and (delta_starts > 0) then
          delta_starts <= delta_starts - 1;

        elsif (up_down = "10") and (delta_starts < DELTA_STARTS_MAX) then
          delta_starts <= delta_starts + 1;

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



end architecture rtl;