-- -- Downlink Decoder -- -- This attempts to be fast and minimise FF usage -- May not have succeeded ... -- -- 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 lcb_regblock_if is port( abcid_i : in std_logic_vector(3 downto 0); -- RegBlock interface rb_addr_o : out std_logic_vector(7 downto 0); rb_rnw_o : out std_logic; rb_init_o : out std_logic; rb_load_o : out std_logic; rb_sdat_o : out std_logic; rb_shen_o : out std_logic; rb_busy_i : in std_logic; -- CmdFIFO cfifo_all_i : in std_logic_vector(8 downto 0); cfifo_empty_i : in std_logic; cfifo_re_o : out std_logic; -- Infra clk40 : in std_logic; --40MHz BCO rstb : in std_logic ); end lcb_regblock_if; --------------------------------------------------------------------------- architecture rtl of lcb_regblock_if is constant C_RST_REG_ADDR : std_logic_vector(7 downto 0) := x"00"; signal cfifo_data : std_logic_vector(6 downto 0); signal cfifo_sof : std_logic; signal cfifo_eof : std_logic; signal cfifo_data_abcid : std_logic_vector(3 downto 0); signal cfifo_re : std_logic; -- signal rb_addr : std_logic_vector(7 downto 0); -- signal rb_rnw : std_logic; signal rb_init : std_logic; signal rb_sdat : std_logic; signal rb_shen : std_logic; signal rb_load : std_logic; signal addr_store0 : std_logic; signal addr_store1 : std_logic; type states is ( Header0, Header1, CheckSendDat6, SendDat5, SendDat4, SendDat3, SendDat2, SendDat1, SendDat0, WaitNextWord, WaitEoF, Idle ); signal state, nstate : states; ------------------------------------------------------------------------------- begin -- Mappings cfifo_re_o <= cfifo_re; cfifo_sof <= cfifo_all_i(8); cfifo_eof <= cfifo_all_i(7); cfifo_data <= cfifo_all_i(6 downto 0); cfifo_data_abcid <= cfifo_data(5 downto 2); -- cmd frame decoder/sequencer --============================================================================= prc_ser_sm_sync_part : process (clk40, rstb) begin if (rstb = '0') then state <= Idle; elsif rising_edge(clk40) then state <= nstate; end if; end process; prc_ser_sm_async_part : process (abcid_i, cfifo_data, cfifo_data_abcid, cfifo_empty_i, cfifo_eof, cfifo_sof, rb_busy_i, state) begin -- defaults cfifo_re <= '0'; addr_store0 <= '0'; addr_store1 <= '0'; rb_init <= '0'; rb_load <= '0'; rb_sdat <= '0'; rb_shen <= '0'; case state is when Idle => nstate <= Idle; if (cfifo_empty_i = '0') then if (cfifo_sof = '1') then nstate <= Header0; else cfifo_re <= '1'; end if; end if; when Header0 => -- check abcid nstate <= Header0; if (cfifo_data_abcid = abcid_i) or (cfifo_data_abcid = "1111") then addr_store0 <= '1'; if (cfifo_empty_i = '0') then cfifo_re <= '1'; nstate <= Header1; end if; else nstate <= WaitEoF; -- not for me wait 'til done; end if; when Header1 => nstate <= Header1; if (cfifo_empty_i = '0') and (rb_busy_i = '0') then addr_store1 <= '1'; rb_init <= '1'; cfifo_re <= '1'; nstate <= SendDat3; -- first chunk has only 4b data end if; ---------------------------------------------------- when CheckSendDat6 => nstate <= CheckSendDat6; rb_sdat <= cfifo_data(6); if (rb_busy_i = '0') then if (cfifo_eof = '1') then rb_load <= '1'; nstate <= Idle; else rb_shen <= '1'; nstate <= SendDat5; end if; end if; when SendDat5 => nstate <= SendDat5; rb_sdat <= cfifo_data(5); if (rb_busy_i = '0') then rb_shen <= '1'; nstate <= SendDat4; end if; when SendDat4 => nstate <= SendDat4; rb_sdat <= cfifo_data(4); if (rb_busy_i = '0') then rb_shen <= '1'; nstate <= SendDat3; end if; when SendDat3 => nstate <= SendDat3; rb_sdat <= cfifo_data(3); if (rb_busy_i = '0') then rb_shen <= '1'; nstate <= SendDat2; end if; when SendDat2 => nstate <= SendDat2; rb_sdat <= cfifo_data(2); if (rb_busy_i = '0') then rb_shen <= '1'; nstate <= SendDat1; end if; when SendDat1 => nstate <= SendDat1; rb_sdat <= cfifo_data(1); if (rb_busy_i = '0') then rb_shen <= '1'; nstate <= SendDat0; end if; when SendDat0 => nstate <= SendDat0; rb_sdat <= cfifo_data(0); if (rb_busy_i = '0') then rb_shen <= '1'; if (cfifo_empty_i = '1') then nstate <= WaitNextWord; else cfifo_re <= '1'; nstate <= CheckSendDat6; end if; end if; ---------------------------- when WaitNextWord => nstate <= WaitNextWord; if (cfifo_empty_i = '0') then --cfifo_re <= '1'; nstate <= CheckSendDat6; end if; ---------------------------- when WaitEoF => nstate <= WaitEoF; if (cfifo_empty_i = '0') then cfifo_re <= '1'; end if; if (cfifo_eof = '1') then nstate <= Idle; end if; end case; end process; prc_stores : process (clk40, rstb) begin if (rstb = '0') then rb_rnw_o <= '0'; rb_addr_o <= x"00"; elsif rising_edge(clk40) then if (addr_store0 = '1') then rb_rnw_o <= cfifo_data(6); rb_addr_o(7 downto 6) <= cfifo_data(1 downto 0); end if; if (addr_store1 = '1') then rb_addr_o(5 downto 0) <= cfifo_data(6 downto 1); end if; -- clock these to make things tidy rb_init_o <= rb_init; rb_load_o <= rb_load; rb_sdat_o <= rb_sdat; rb_shen_o <= rb_shen; end if; end process; end rtl;