------------------------------------------------------------------------------- -- Title : ilas parser ------------------------------------------------------------------------------- -- File : ilas_parser.vhd ------------------------------------------------------------------------------- -- Description: Parses ilas, outputs it's config and checks -- that everything is correct. ------------------------------------------------------------------------------- library ieee; use work.data_link_pkg.all; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity ilas_parser is generic ( F : integer range 1 to 256; -- Number of octets in a frame K : integer range 1 to 32; -- Number of frames in a multiframe K_character : std_logic_vector(7 downto 0) := "10111100"; -- Character -- for syncing R_character : std_logic_vector(7 downto 0) := "00011100"; -- ILAS -- multiframe -- start character A_character : std_logic_vector(7 downto 0) := "01111100"; -- ILAS -- multiframe -- end character Q_character : std_logic_vector(7 downto 0) := "10011100"; -- ILAS 2nd -- multiframe -- 2nd character multiframes_count : integer range 1 to 32 := 4); port ( ci_char_clk : in std_logic; -- Character clock ci_reset : in std_logic; -- Reset (asynchonous, active low) ci_state : in link_state; -- State of the lane di_char : in character_vector; -- Character from 8b10b decoder do_config : out link_config; -- Config found in ILAS co_finished : out std_logic; -- The ILAS was received correctly co_error : out std_logic; -- The ILAS was not received correctly co_wrong_chksum : out std_logic; -- There was a wrong checksum in the ILAS co_unexpected_char : out std_logic); -- There was a character at -- unexpected location in the ILAS end entity ilas_parser; architecture a1 of ilas_parser is constant link_config_length : integer := 112; signal octets_in_multiframe : integer range 0 to 8192 := 0; signal link_config_data : std_logic_vector(link_config_length-1 downto 0) := (others => '0'); signal reg_processing_ilas : std_logic := '0'; signal reg_multiframe_index : integer range 0 to multiframes_count+1 := 0; signal reg_octet_index : integer range 0 to F*K+5 := 0; signal next_processing_ilas : std_logic := '0'; signal next_multiframe_index : integer range 0 to multiframes_count+1 := 0; signal next_octet_index : integer range 0 to F*K+5 := 0; signal finished : std_logic := '0'; signal err : std_logic := '0'; function getOctetUpIndex ( octet_index : integer range 0 to F*K+5) return integer is begin -- function getByteUpIndex return link_config_length - 1 - 8 * octet_index; end function getOctetUpIndex; function getDataByIndex ( data : std_logic_vector(link_config_length-1 downto 0); octet_index : integer range 0 to F*K+5; bit_index : integer range 0 to 7; length : integer range 1 to 8) return std_logic_vector is variable up_index : integer; begin -- function getDataByIndex up_index := getOctetUpIndex(octet_index); return data(up_index - 7 + bit_index + length - 1 downto up_index - 7 + bit_index); end function getDataByIndex; function getBitByIndex ( data : std_logic_vector(link_config_length-1 downto 0); octet_index : integer range 0 to F*K+5; bit_index : integer range 0 to 7) return std_logic is variable up_index : integer; begin -- function getBitByIndex up_index := getOctetUpIndex(octet_index); return data(up_index - 7 + bit_index); end function getBitByIndex; begin -- architecture a1 octets_in_multiframe <= F * K; -- ILAS -- one multiframe is sent -- 4 frames in a multiframe -- second frame contains ILAS at third character -- each start of a frame should have /R/ -- each end of a frame should have /A/ -- second frame: -- second_character: /K28.0/ -- third_character: starts ILAS -- if anything does not match (/R/, /A/, /K28.0/, checksum), set error -- and co_wrong_chksum or co_unexpected_char. Stop processing. -- The controller will then request new synchronization try. set_next: process (ci_char_clk, ci_reset) is begin -- process set_next if ci_reset = '0' then -- asynchronous reset (active low) reg_octet_index <= 0; reg_multiframe_index <= 0; reg_processing_ilas <= '0'; elsif ci_char_clk'event and ci_char_clk = '1' then -- rising clock edge reg_octet_index <= next_octet_index; reg_multiframe_index <= next_multiframe_index; reg_processing_ilas <= next_processing_ilas; end if; end process set_next; check_chars: process (ci_char_clk, ci_reset) is variable up_index : integer range 7 to link_config_length-1; variable processing_ilas : std_logic; begin -- process check_chars processing_ilas := next_processing_ilas or reg_processing_ilas; if ci_reset = '0' then -- asynchronous reset (active low) err <= '0'; co_unexpected_char <= '0'; co_wrong_chksum <= '0'; finished <= '0'; link_config_data <= (others => '0'); elsif ci_char_clk'event and ci_char_clk = '1' and (processing_ilas = '0' or ci_state = INIT) then err <= '0'; co_unexpected_char <= '0'; co_wrong_chksum <= '0'; if ci_state /= DATA and ci_state /= ILS then link_config_data <= (others => '0'); finished <= '0'; end if; elsif ci_char_clk'event and ci_char_clk = '1' and err = '1' then if next_processing_ilas = '0' then err <= '0'; co_unexpected_char <= '0'; co_wrong_chksum <= '0'; end if; -- If there is an error, stop processing. elsif ci_char_clk'event and ci_char_clk = '1' and processing_ilas = '1' then -- rising clock edge if reg_octet_index = 0 then -- Should be /R/ if di_char.d8b /= R_character or di_char.kout = '0' then err <= '1'; co_unexpected_char <= '1'; end if; elsif di_char.d8b = R_character and di_char.kout = '1' then err <= '1'; co_unexpected_char <= '1'; elsif reg_octet_index = octets_in_multiframe - 1 then if di_char.d8b /= A_character or di_char.kout = '0' then -- Should be /A/ err <= '1'; co_unexpected_char <= '1'; elsif reg_multiframe_index = 3 and err = '0' then finished <= '1'; end if; elsif di_char.d8b = A_character and di_char.kout = '1' then err <= '1'; co_unexpected_char <= '1'; elsif reg_multiframe_index = 1 then if reg_octet_index = 1 and (di_char.d8b /= Q_character or di_char.kout = '0') then -- Should be /Q/ err <= '1'; co_unexpected_char <= '1'; elsif reg_octet_index > 1 and reg_octet_index < 16 then -- This is config data up_index := getOctetUpIndex(reg_octet_index - 2); link_config_data(up_index downto up_index - 7) <= di_char.d8b; end if; if reg_octet_index = 15 then -- This is a checksum -- TODO: calculate checksum. Probably not necessary checksum will be -- precalculated and has to be matched, we do not need to calculate it -- if di_char.d8b = "00000000" then -- co_wrong_chksum <= '1'; -- err <= '1'; -- end if; end if; elsif reg_multiframe_index > 3 then err <= '1'; end if; end if; end process check_chars; co_finished <= '1' when finished = '1' or (di_char.kout = '1' and di_char.d8b = A_character and reg_octet_index = octets_in_multiframe - 1 and reg_multiframe_index = 3) else '0'; co_error <= '1' when err = '1' and ci_state = ILS else '0'; next_processing_ilas <= '0' when ci_state = INIT or finished = '1' else '0' when ci_state = CGS and reg_processing_ilas = '1' else '0' when reg_multiframe_index = 3 and reg_octet_index = octets_in_multiframe - 1 else '1' when ci_state = CGS and not (di_char.d8b = K_character and di_char.kout = '1') else '1' when reg_processing_ilas = '1' or ci_state = ILS else '0'; -- octet, multiframe index next_multiframe_index <= 0 when reg_processing_ilas = '0' and next_processing_ilas = '0' else (reg_multiframe_index + 1) when reg_octet_index = octets_in_multiframe - 1 else reg_multiframe_index; next_octet_index <= 0 when (next_processing_ilas = '0' and reg_processing_ilas = '0') or (next_processing_ilas = '0' and reg_processing_ilas = '1') else (reg_octet_index + 1) mod octets_in_multiframe; -- config do_config.DID <= to_integer(unsigned(getDataByIndex(link_config_data, 0, 0, 8))); do_config.ADJDIR <= getBitByIndex(link_config_data, 2, 6); do_config.ADJCNT <= to_integer(unsigned(getDataByIndex(link_config_data, 1, 4, 4))); do_config.BID <= to_integer(unsigned(getDataByIndex(link_config_data, 1, 0, 4))); do_config.PHADJ <= getBitByIndex(link_config_data, 2, 5); do_config.LID <= to_integer(unsigned(getDataByIndex(link_config_data, 2, 0, 5))); do_config.SCR <= getBitByIndex(link_config_data, 3, 7); do_config.L <= to_integer(unsigned(getDataByIndex(link_config_data, 3, 0, 5))) + 1; do_config.F <= to_integer(unsigned(getDataByIndex(link_config_data, 4, 0, 8))) + 1; do_config.K <= to_integer(unsigned(getDataByIndex(link_config_data, 5, 0, 5))) + 1; do_config.M <= to_integer(unsigned(getDataByIndex(link_config_data, 6, 0, 8))) + 1; do_config.CS <= to_integer(unsigned(getDataByIndex(link_config_data, 7, 6, 2))); do_config.N <= to_integer(unsigned(getDataByIndex(link_config_data, 7, 0, 5))) + 1; do_config.SUBCLASSV <= to_integer(unsigned(getDataByIndex(link_config_data, 8, 5, 3))); do_config.Nn <= to_integer(unsigned(getDataByIndex(link_config_data, 8, 0, 5))) + 1; do_config.JESDV <= to_integer(unsigned(getDataByIndex(link_config_data, 9, 5, 3))); do_config.S <= to_integer(unsigned(getDataByIndex(link_config_data, 9, 0, 5))) + 1; do_config.HD <= getBitByIndex(link_config_data, 10, 7); do_config.CF <= to_integer(unsigned(getDataByIndex(link_config_data, 9, 0, 5))); do_config.RES1 <= getDataByIndex(link_config_data, 11, 0, 8); do_config.RES2 <= getDataByIndex(link_config_data, 12, 0, 8); do_config.CHKSUM <= to_integer(unsigned(getDataByIndex(link_config_data, 13, 0, 8))); do_config.X <= getBitByIndex(link_config_data, 2, 7) & getDataByIndex(link_config_data, 3, 5, 2) & getDataByIndex(link_config_data, 5, 5, 3) & getBitByIndex(link_config_data, 7, 5) & getDataByIndex(link_config_data, 10, 5, 2); end architecture a1;