-- -- LCB 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_decoder is generic( ASIC_IS_ABC : integer := 1 -- else HCC ); port( hccid_i : in std_logic_vector (4 downto 0); par4_i : in std_logic_vector (3 downto 0); locked_i : in std_logic; frame_sync_i : in std_logic_vector (1 downto 0); decoder_err_o : out std_logic; par4_o : out std_logic_vector (3 downto 0); -- Signals/data out ------------------------------ l0a_o : out std_logic; l0a_tag_o : out std_logic_vector (6 downto 0); --l0a_tag_valid_o : out std_logic; bcr_o : out std_logic; cbus_data_o : out std_logic_vector (6 downto 0); cbus_valid_o : out std_logic; -- cmd_ignore_o : out std_logic; cbus_sof_o : out std_logic; cbus_eof_o : out std_logic; cbus_all_o : out std_logic_vector (8 downto 0); fast_cmd_o : out std_logic_vector (3 downto 0); -- Infra clk40 : in std_logic; --40MHz BCO rst : in std_logic ); -- Declarations end lcb_decoder; --------------------------------------------------------------------------- architecture rtl of lcb_decoder is --signal par4_sr : slv4_array(3 downto 0); signal par4_sr : slv4_array(2 downto 0); signal alt_hccid_insert : std_logic; signal alt_hccid_insert_q : std_logic; signal symbol_in : std_logic_vector(7 downto 0); signal symbol_sync : std_logic; signal dec_6b : std_logic_vector(5 downto 0); signal dec_k : std_logic_vector(3 downto 0); signal dec_err : std_logic; signal dec_bcr : std_logic; signal dec_l0a_map : std_logic_vector(3 downto 0); signal dec_tag_msb : std_logic; signal dec_tag_lsbs : std_logic_vector(5 downto 0); signal dec_is_k : std_logic; signal dec_is_cmd : std_logic; signal dec_cmd_hccid : std_logic_vector(4 downto 0); signal dec_cmd_ignore : std_logic; signal dec_cmd_hccid_ok : std_logic; signal bcr0 : std_logic; signal bcr_q : std_logic_vector(5 downto 0); signal l0a_sr : std_logic_vector(3 downto 0); signal l0a_delayed : std_logic_vector(3 downto 0); signal l0a_load_go : std_logic; signal tag_counter : std_logic_vector(6 downto 0); --signal tag_valid : std_logic; signal tag_load : std_logic; signal tag_msb : std_logic; signal tag_msb_store_en : std_logic; signal cmd_ignore : std_logic; signal cmd_ignore_set : std_logic; signal cmd_sof_set : std_logic; signal cbus_valid : std_logic; --signal cbus_sof : std_logic; signal cbus_eof : std_logic; signal cbus_valid_q : std_logic; signal cbus_sof_q : std_logic; signal cbus_eof_q : std_logic; signal cbus_data_q : std_logic_vector(6 downto 0); signal k3_bc : std_logic_vector(1 downto 0); signal k3_data : std_logic_vector(3 downto 0); signal k3_go : std_logic; signal k3_in_progress : std_logic; signal k3_is_cmd_done : std_logic; signal dbg_symb0_sync : std_logic; signal dbg_symb1_sync : std_logic; signal dbg_symb0 : std_logic_vector(7 downto 0); signal dbg_symb1 : std_logic_vector(7 downto 0); signal dbg_dec_6b0 : std_logic_vector(5 downto 0); signal dbg_dec_6b1 : std_logic_vector(5 downto 0); signal dbg_bcr : std_logic; signal dbg_l0a_map : std_logic_vector(3 downto 0); signal dbg_tag : std_logic_vector(6 downto 0); type states is (Idle, Symbol0, WaitTag, WaitCmd, WaitCmdStart, WaitK3); signal state, nstate : states; begin symbol_sync <= frame_sync_i(0); -- low latency sr, just in case par4_sr(0) <= par4_i; prc_par4_sr : process (clk40) begin if rising_edge(clk40) then alt_hccid_insert_q <= alt_hccid_insert; if (alt_hccid_insert = '1') then --par4_sr(3) <= par4_sr(2); par4_sr(2) <= SYMB_CMD_IGNORE(7 downto 4); par4_sr(1) <= par4_sr(0); elsif (alt_hccid_insert_q = '1') then --par4_sr(3) <= par4_sr(2); par4_sr(2) <= SYMB_CMD_IGNORE(3 downto 0); par4_sr(1) <= par4_sr(0); else --par4_sr(3 downto 1) <= par4_sr(2 downto 0); par4_sr(2 downto 1) <= par4_sr(1 downto 0); end if; end if; end process; par4_o <= par4_sr(2); symbol_in <= par4_sr(1) & par4_sr(0); -- 8b/6b symbol decoder -- decoder output must be strobed by frame_sync process(symbol_in) begin --defaults dec_err <= '0'; dec_6b <= "000000"; dec_k <= "0000"; case symbol_in is when "01011001" => dec_6b <= "000000"; when "01110001" => dec_6b <= "000001"; when "01110010" => dec_6b <= "000010"; when "11000011" => dec_6b <= "000011"; when "01100101" => dec_6b <= "000100"; when "11000101" => dec_6b <= "000101"; when "11000110" => dec_6b <= "000110"; when "10000111" => dec_6b <= "000111"; when "01101001" => dec_6b <= "001000"; when "11001001" => dec_6b <= "001001"; when "11001010" => dec_6b <= "001010"; when "10001011" => dec_6b <= "001011"; when "11001100" => dec_6b <= "001100"; when "10001101" => dec_6b <= "001101"; when "10001110" => dec_6b <= "001110"; when "01001011" => dec_6b <= "001111"; when "01010011" => dec_6b <= "010000"; when "11010001" => dec_6b <= "010001"; when "11010010" => dec_6b <= "010010"; when "10010011" => dec_6b <= "010011"; when "11010100" => dec_6b <= "010100"; when "10010101" => dec_6b <= "010101"; when "10010110" => dec_6b <= "010110"; when "00010111" => dec_6b <= "010111"; when "11011000" => dec_6b <= "011000"; when "10011001" => dec_6b <= "011001"; when "10011010" => dec_6b <= "011010"; when "00011011" => dec_6b <= "011011"; when "10011100" => dec_6b <= "011100"; when "00011101" => dec_6b <= "011101"; when "00011110" => dec_6b <= "011110"; when "01011100" => dec_6b <= "011111"; when "01100011" => dec_6b <= "100000"; when "11100001" => dec_6b <= "100001"; when "11100010" => dec_6b <= "100010"; when "10100011" => dec_6b <= "100011"; when "11100100" => dec_6b <= "100100"; when "10100101" => dec_6b <= "100101"; when "10100110" => dec_6b <= "100110"; when "00100111" => dec_6b <= "100111"; when "11101000" => dec_6b <= "101000"; when "10101001" => dec_6b <= "101001"; when "10101010" => dec_6b <= "101010"; when "00101011" => dec_6b <= "101011"; when "10101100" => dec_6b <= "101100"; when "00101101" => dec_6b <= "101101"; when "00101110" => dec_6b <= "101110"; when "01101100" => dec_6b <= "101111"; when "01110100" => dec_6b <= "110000"; when "10110001" => dec_6b <= "110001"; when "10110010" => dec_6b <= "110010"; when "00110011" => dec_6b <= "110011"; when "10110100" => dec_6b <= "110100"; when "00110101" => dec_6b <= "110101"; when "00110110" => dec_6b <= "110110"; when "01010110" => dec_6b <= "110111"; when "10111000" => dec_6b <= "111000"; when "00111001" => dec_6b <= "111001"; when "00111010" => dec_6b <= "111010"; when "01011010" => dec_6b <= "111011"; when "00111100" => dec_6b <= "111100"; when "01001101" => dec_6b <= "111101"; when "01001110" => dec_6b <= "111110"; when "01100110" => dec_6b <= "111111"; when "01000111" => dec_k(0) <= '1'; when "01010101" => dec_k(1) <= '1'; when "01111000" => dec_k(2) <= '1'; when "01101010" => dec_k(3) <= '1'; when others => dec_err <= '1'; end case; end process; decoder_err_o <= (dec_err and symbol_sync) when rising_edge(clk40); -- These mappings are not valid all the time -- Must use in conjunction with frame_sync dec_bcr <= dec_6b(5); dec_l0a_map <= dec_6b(4 downto 1); dec_tag_msb <= dec_6b(0); dec_tag_lsbs <= dec_6b; dec_is_k <= '1' when (dec_k /= "0000") else '0'; dec_is_cmd <= '1' when (dec_6b(5 downto 1) = "00000") and (dec_is_k = '0') else '0'; dec_cmd_hccid <= dec_6b(4 downto 0); dec_cmd_ignore <= dec_6b(5); dec_cmd_hccid_ok <= '1' when (dec_cmd_hccid = hccid_i) or (dec_cmd_hccid = "11111") else '0'; k3_is_cmd_done <= '1' when dec_6b(3 downto 0) = "0001" else '0'; -- lots of debug - not for synth, of course dbg_symb0_sync <= '1' when (frame_sync_i = FSYNC_SYMB0) else '0'; dbg_symb1_sync <= '1' when (frame_sync_i = FSYNC_FRAME) else '0'; dbg_symb0 <= symbol_in when rising_edge(dbg_symb0_sync); dbg_symb1 <= symbol_in when rising_edge(dbg_symb1_sync); dbg_dec_6b0 <= dec_6b when rising_edge(dbg_symb0_sync); dbg_dec_6b1 <= dec_6b when rising_edge(dbg_symb1_sync); dbg_bcr <= dbg_dec_6b0(5); dbg_l0a_map <= dbg_dec_6b0(4 downto 1); dbg_tag <= dbg_dec_6b0(0) & dbg_dec_6b1 when (frame_sync_i = FSYNC_FRAME); -- 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 (cmd_ignore, dec_bcr, dec_cmd_hccid_ok, dec_cmd_ignore, dec_is_cmd, dec_k(2), dec_k(3), dec_l0a_map, frame_sync_i, k3_is_cmd_done, locked_i, state) begin -- defaults bcr0 <= '0'; l0a_load_go <= '0'; tag_msb_store_en <= '0'; tag_load <= '0'; cbus_valid <= '0'; cmd_ignore_set <= '0'; cmd_sof_set <= '0'; cbus_eof <= '0'; alt_hccid_insert <= '0'; k3_go <= '0'; case state is -- Wait for locked and correct position if frame cycle when Idle => nstate <= Idle; if (locked_i = '1') and (frame_sync_i = FSYNC_NIB0) then nstate <= Symbol0; end if; -- first symbol processing ----------------------------------------------------- when Symbol0 => -- aka FSYNC_SYMB0 tag_msb_store_en <= '1'; if (dec_bcr = '1') then bcr0 <= '1'; end if; if (dec_l0a_map /= "0000") then l0a_load_go <= '1'; end if; if (dec_k(2) = '1') then -- CMD header nstate <= WaitCmdStart; elsif (dec_k(3) = '1') then nstate <= WaitK3; elsif (dec_is_cmd = '1') then nstate <= WaitCmd; else nstate <= WaitTag; end if; -- second symbol/frame processing ------------------------------------------------------- when WaitTag => nstate <= WaitTag; if (frame_sync_i = FSYNC_FRAME) then tag_load <= '1'; nstate <= Idle; end if; when WaitCmd => nstate <= WaitCmd; if (frame_sync_i = FSYNC_FRAME) then tag_load <= '1'; if (cmd_ignore = '0') then cbus_valid <= '1'; end if; nstate <= Idle; end if; when WaitCmdStart => nstate <= WaitCmdStart; if (frame_sync_i = FSYNC_FRAME) then if (ASIC_IS_ABC = 1) then if (dec_cmd_ignore = '1') then cmd_ignore_set <= '1'; else cmd_sof_set <= '1'; end if; else -- ASIC_IS_HCC if (dec_cmd_hccid_ok = '0') then alt_hccid_insert <= '1'; cmd_ignore_set <= '1'; else cmd_sof_set <= '1'; end if; end if; nstate <= Idle; end if; when WaitK3 => nstate <= WaitK3; if (frame_sync_i = FSYNC_FRAME) then k3_go <= '1'; if (k3_is_cmd_done = '1') then cbus_eof <= '1'; cbus_valid <= '1'; end if; nstate <= Idle; end if; end case; end process; -- L0A processing ---------------------------------------------------- prc_l0a_sr : process (clk40) begin if rising_edge(clk40) then if (rst = '1') then l0a_sr <= (others => '0'); l0a_delayed <= (others => '0'); tag_counter <= (others => '0'); tag_msb <= '0'; else if (tag_msb_store_en = '1') then tag_msb <= dec_tag_msb; end if; if (l0a_load_go = '1') then l0a_sr <= dec_l0a_map; else l0a_sr <= l0a_sr(2 downto 0) & '0'; end if; l0a_delayed <= l0a_delayed(2 downto 0) & l0a_sr(3); -- tag counter ---------------------------------- if (tag_load = '1') then tag_counter <= tag_msb & dec_tag_lsbs; else if (l0a_delayed(1) = '1') then -- *** adjust tap as needed if (tag_counter = "1111111") then tag_counter <= "0000000"; else tag_counter <= tag_counter + '1'; end if; end if; end if; end if; end if; end process; l0a_o <= l0a_delayed(1); l0a_tag_o <= tag_counter; --l0a_tag_valid_o <= l0a_delayed(1); -- *** adjust as per above cbus_data_q <= tag_counter; -- uses same field, and is already registered; -- BCR "processing" ---------------------------------------------------- prc_bcr : process (clk40) begin if rising_edge(clk40) then if (rst = '1') then bcr_o <= '0'; bcr_q <= (others => '0'); else bcr_q <= bcr_q(4 downto 0) & bcr0; -- delay to put BCR in known phase wrt frame bcr_o <= bcr_q(4); end if; end if; end process; -- CMD "processing" ---------------------------------------------------- prc_cmd : process (clk40) begin if rising_edge(clk40) then if (rst = '1') then cmd_ignore <= '0'; cbus_valid_q <= '0'; cbus_sof_q <= '0'; cbus_eof_q <= '0'; else if (cmd_ignore_set = '1') then cmd_ignore <= '1'; elsif (cbus_eof = '1') then cmd_ignore <= '0'; end if; -- "latch" sof state until first cmd data sent if (cmd_sof_set = '1') then cbus_sof_q <= '1'; elsif (cbus_valid_q = '1') then cbus_sof_q <= '0'; end if; cbus_valid_q <= cbus_valid; cbus_eof_q <= cbus_eof; end if; end if; end process; --cmd_ignore_o <= cmd_ignore; cbus_sof_o <= cbus_sof_q; -- in sync with first cmd7 word cbus_eof_o <= cbus_eof_q; -- in sync with last cmd7 word cbus_data_o <= cbus_data_q; cbus_valid_o <= cbus_valid_q; cbus_all_o <= cbus_sof_q & cbus_eof_q & cbus_data_q; -- K3 (fast_command) "processing" ---------------------------------------------------- prc_k3 : process (clk40) begin if rising_edge(clk40) then if (rst = '1') then k3_bc <= "00"; k3_data <= "0000"; k3_in_progress <= '0'; else -- default fast_cmd_o <= "0000"; if (k3_go = '1') then k3_bc <= dec_6b(5 downto 4); k3_data <= dec_6b(3 downto 0); -- doing first one here to save a clock if (dec_6b(5 downto 4) = "00") then fast_cmd_o <= dec_6b(3 downto 0); end if; elsif (k3_in_progress = '1') then if (frame_sync_i = k3_bc) then fast_cmd_o <= k3_data; end if; if (frame_sync_i = "11") then k3_in_progress <= '0'; end if; end if; end if; end if; end process; end rtl;