--
-- Downlink Cmd7 Generator
--
-- Another non-optimal hack, not for an ASIC
--
-- Matt Warren Aug 2016
--
--


library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

library downlink;
use downlink.lcb_pkg_globals.all;


entity lcbtst_cmd7_gen is
  port(

    cmdfrm_ready_i   : in  std_logic;
    cmd7_gen_busy_o : out std_logic;
    cmdfrm_i         : in  std_logic_vector(48 downto 0);

    -----------------------
    cmd7_o       : out std_logic_vector(6 downto 0);
    cmd7_start_o : out std_logic;
    cmd7_ready_o : out std_logic;
    cmd7_end_o  : out std_logic;
    cmd7_ack_i   : in  std_logic;

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

    -- Infra
    --clk160 : in std_logic;
    clk40 : in std_logic;               --40MHz BCO
    rst   : in std_logic
    );

-- Declarations

end lcbtst_cmd7_gen;

---------------------------------------------------------------------------
architecture rtl of lcbtst_cmd7_gen is




  signal cmd7_array : slv7_array(0 to 6);
  signal wcount     : integer range 0 to 6;
  signal wcount_clr : std_logic;
  signal wcount_inc : std_logic;


  type states is (SendStart, SendWord, SendEnd, --NextWord,
                  Idle);
  signal state, nstate : states;

begin


  g_cmd7_array : for n in 0 to 6 generate
    cmd7_array(n) <= cmdfrm_i((42-n*7+6) downto 42-n*7+0);
  end generate;


  -- frame decoder/sequencer
  --==========================================================


  prc_sm_sync_part : process (clk40)
  begin
    if rising_edge(clk40) then
      if (rst = '1') then
        state <= Idle;
      else
        state <= nstate;
      end if;
    end if;
  end process;

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

  prc_sm_async : process (cmdfrm_ready_i, cmd7_ack_i, state, wcount)

  begin


    -- defaults
    cmd7_gen_busy_o <= '0';
    cmd7_ready_o    <= '0';
    cmd7_start_o    <= '0';
    cmd7_end_o      <= '0';

    wcount_clr <= '0';
    wcount_inc <= '0';

    case state is

      -- Wait for locked and correct position if frame cycle
      when Idle =>
        nstate     <= Idle;
        wcount_clr <= '1';

        if (cmdfrm_ready_i = '1') then
          nstate <= SendStart;
        end if;


      when SendStart =>
        nstate <= SendStart;
        cmd7_start_o    <= '1';
        cmd7_gen_busy_o <= '1';
        if (cmd7_ack_i = '1') then
          nstate <= SendWord;
        end if;


      when SendWord =>
        nstate <= SendWord;
        cmd7_ready_o    <= '1';
        cmd7_gen_busy_o <= '1';
        if (cmd7_ack_i = '1') then
           wcount_inc      <= '1';
           if (wcount = 6) then
             nstate <= SendEnd;
           end if;
       end if;

      --when NextWord =>
      --  nstate <= SendWord;
      --  cmd7_gen_busy_o <= '1';

      when SendEnd =>
        nstate <= SendEnd;
        cmd7_end_o      <= '1';
        cmd7_gen_busy_o <= '1';
        if (cmd7_ack_i = '1') then
          nstate <= Idle;
        end if;


    end case;
  end process;


  cmd7_o <= cmd7_array(wcount);






  prc_counts : process (clk40)
  begin
    if rising_edge(clk40) then
      if (rst = '1') then
        wcount <= 0;

      else

        if (wcount_clr = '1') then
          wcount <= 0;


        elsif(wcount_inc = '1') and (wcount /= 6) then
          wcount <= wcount + 1;

        end if;

      end if;
    end if;
  end process;



end rtl;