--
-- LocalLink Ack Packet Generator
--
-- Tiny block for simple Ack sending
-- Has advanced extra functions for larger payloads:
--  send_i: leave high to indicate more data available
--  busy_o: if send_i high, used for flow control
--

-- SIMPLE ACK MODE:
--
-- clk ^\__/^^\__/^^\__/^^\__/^^\__/^^\__/^^\__/^^\__/^^\__/
--
-- send_i _/^^^^^\__________________________________________
--
-- busy_o _______/^^^^^^^^^^^^^^^^^^^^^^^\__________________
--
-- data_o _______/ opc | seq | siz | pay \__________________
--
--
-- ADVANCED MODE:
-- Hold send high, busy acts as eoheader signal,
-- then flow control for payload data
--
-- clk \__/^^\__/^^\__/^^\__/^^\__/^^\__/^^\__/^^\__/^^\__/^^\__/ ... _/^^\__
--
-- send_i _/^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... ^^^^^\_
--
-- busy_o _______/^^^^^^^^^^^\_____/^^^^^^^^^^^\_____/^^^^^^^^^^^ ... ^^^^^\_
--
-- data_o _______/ opc | seq | siz | pa0 | pa1 |    pa2    | pa3  ...  paZ \_
--
--


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_ack_gen is
  port(
    -- input interface
    opcode_i  : in    slv16;
    ocseq_i   : in    slv16;
    ocsize_i  : in    slv16;
    payload_i : in    slv16;
    send_i    : in    std_logic;
    busy_o    : out   std_logic;
    -- locallink tx interface
    lls_o              : out t_llsrc;
    lld_i              : in std_logic;
    -- infrastucture
    clk       : in    std_logic;
    rst       : in    std_logic
    );

-- Declarations

end ll_ack_gen;


architecture rtl of ll_ack_gen is


  type states is (SrcRdy, OpcodeSOF, OCSeq, Size,
                  PayloadEOF, AdvPayloadEOF,
                  Idle);

  signal state, nstate : states;

  attribute keep : string;
  attribute keep of state : signal is "true";

begin

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

  prc_sm_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_async : process (lld_i, send_i,
                          opcode_i, ocseq_i, ocsize_i, payload_i,
                          state)
  begin

    -- defaults
    nstate    <= Idle;
    busy_o    <= '1';
    lls_o.src_rdy <= '1';
    lls_o.sof     <= '0';
    lls_o.eof     <= '0';
    lls_o.data    <= opcode_i;


    case state is


      when Idle =>
        nstate    <= Idle;
        busy_o    <= '0';
        lls_o.src_rdy <= '0';
        if (send_i = '1') then
          busy_o <= '1';
          nstate <= SrcRdy;
        end if;


      when SrcRdy =>
        nstate <= SrcRdy;
        if (lld_i = '1') then
          nstate <= OpcodeSOF;
        end if;


      when OpcodeSOF =>
        nstate <= OpcodeSOF;
        lls_o.sof  <= '1';
        lls_o.data <= opcode_i;
        if (lld_i = '1') then
          nstate <= OCSeq;
        end if;


      when OCSeq =>
        nstate <= OCSeq;
        lls_o.data <= ocseq_i;
        if (lld_i = '1') then
          nstate <= Size;
        end if;


      when Size =>
        nstate <= Size;
        lls_o.data <= ocsize_i;
        if (send_i = '1') then  -- send=1 here =  advanced mode, busy=0 signals end-of-header
          if (lld_i = '1') then
            busy_o <= '0';
            nstate <= AdvPayloadEOF;
          end if;
        else
          if (lld_i = '1') then
            nstate <= PayloadEOF;
          end if;
        end if;



      when PayloadEOF =>
        nstate <= PayloadEOF;
        lls_o.data <= payload_i;
        lls_o.eof  <= '1';
        if (lld_i = '1') then
          nstate <= Idle;
        end if;



        ------------------------------------
      when AdvPayloadEOF =>
        nstate <= AdvPayloadEOF;
        lls_o.data <= payload_i;
        busy_o <= not(lld_i);
        if (send_i = '0') then
          lls_o.eof <= '1';
          if (lld_i = '1') then
            nstate <= Idle;
          end if;
        end if;


    end case;
  end process;



-----------------------------------------------------------------------------------
end architecture;