feat(link): implement ilas parser
2 files changed, 173 insertions(+), 59 deletions(-) M src/data_link/ilas_parser.vhd M testbench/data_link/ilas_parser_tb.vhd
M src/data_link/ilas_parser.vhd => src/data_link/ilas_parser.vhd +111 -28
@@ 1,19 1,20 @@ library ieee; use work.data_link_pkg.all; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use work.data_link_pkg.all; entity ilas_parser is generic ( R_character : std_logic_vector(7 downto 0) := "00011100"; A_character : std_logic_vector(7 downto 0) := "01111100"; Q_character : std_logic_vector(7 downto 0) := "01011100"; frames_count : integer := 4); Q_character : std_logic_vector(7 downto 0) := "10011100"; -- 9C multiframes_count : integer := 4); port ( ci_char_clk : in std_logic; ci_reset : in std_logic; ci_F : in integer range 0 to 256; ci_K : in integer range 0 to 32; ci_state : in link_state; di_char : in character_vector; @@ do_config : out link_config; 25,36 26,53 @@ entity ilas_parser is end entity ilas_parser; architecture a1 of ilas_parser is constant link_config_length : integer := 111; signal link_config_data : std_logic_vector(link_config_length downto 0) := (others => '0'); 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_frame_index : integer := 0; signal reg_multiframe_index : integer := 0; signal reg_octet_index : integer := 0; signal next_processing_ilas : std_logic := '0'; signal next_multiframe_index : integer := 0; signal next_octet_index : integer := 0; signal finished : std_logic := '0'; signal err : std_logic := '0'; signal processing_ilas : std_logic := '0'; function getOctetUpIndex ( octet_index : integer) return integer is begin -- function getByteUpIndex return link_config_length - 1 - 8 * octet_index; end function getByteUpIndex; end function getOctetUpIndex; function getDataByIndex ( data : std_logic_vector(link_config_length downto 0); data : std_logic_vector(link_config_length-1 downto 0); octet_index : integer; bit_index : integer; length : integer) return std_logic_vector is variable up_index : integer; begin -- function getDataByIndex up_index := getOctetUpIndex(data, octet_index); return data(up_index downto up_index - 7)(bit_index + length downto bit_index); up_index := getOctetUpIndex(octet_index); return data(up_index - 7 + bit_index + length - 1 downto up_index - 7 + bit_index); end function getDataByIndex; begin -- architecture a1 function getBitByIndex ( data : std_logic_vector(link_config_length-1 downto 0); octet_index : integer; bit_index : integer) 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 <= ci_F * CI_K; octets_in_multiframe <= 17; -- ILAS -- one multiframe is sent @@ -- 4 frames in a multiframe 65,37 83,67 @@ begin -- architecture a1 -- second_character: /K28.0/ -- third_character: starts ILAS -- if anything does not match (/R/, /A/, /K28.0/, checksum), set co_error -- 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; 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) co_error <= '0'; 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' then co_error <= '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'; link_config_data <= (others => '0'); if ci_state /= DATA then link_config_data <= (others => '0'); finished <= '0'; end if; elsif err = '1' then -- 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 then co_error <= '1'; err <= '1'; co_unexpected_char <= '1'; end if; elsif reg_octet_index = ci_F - 1 then elsif di_char.d8b = R_character then err <= '1'; co_unexpected_char <= '1'; elsif reg_octet_index = octets_in_multiframe - 1 then if di_char.d8b /= A_character then -- Should be /A/ co_error <= '1'; err <= '1'; co_unexpected_char <= '1'; elsif reg_multiframe_index = 3 and err = '0' then finished <= '1'; end if; elsif reg_frame_index = 1 then elsif di_char.d8b = A_character then err <= '1'; co_unexpected_char <= '1'; elsif reg_multiframe_index = 1 then if reg_octet_index = 1 and di_char.d8b /= Q_character then -- Should be /Q/ co_error <= '1'; 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); 103,20 151,55 @@ begin -- architecture a1 end if; if reg_octet_index = 15 then -- This is a checksum -- TODO: calculate checksum if di_char.d8b = "00000000" then co_wrong_chksum <= '1'; err <= '1'; end if; end if; elsif reg_multiframe_index > multiframes_count - 1 then err <= '1'; end if; end if; end process check_chars; processing_ilas <= next_processing_ilas or reg_processing_ilas; co_finished <= finished; co_error <= err; next_processing_ilas <= '0' when ci_state = INIT else next_processing_ilas <= '0' when ci_state = INIT or finished = '1' else '0' when reg_multiframe_index = 3 and reg_octet_index = octets_in_multiframe - 1 else '1' when reg_processing_ilas = '1' or ci_state = ILAS else '0'; -- config do_config.ADJCNT <= to_integer(unsigned(getDataByIndex(link_config_data, 0, 0, 8))); do_config.ADJDIR <= getDataByIndex(link_config_data, 2, 6, 1); -- 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' 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;
M testbench/data_link/ilas_parser_tb.vhd => testbench/data_link/ilas_parser_tb.vhd +62 -31
@@ 21,28 21,56 @@ architecture a1 of ilas_parser_tb is type config_array is array (natural range<>) of link_config; constant config_vectors : config_array := ( -- DID = 10101010 -- ADJCNT = 0111 -- BID = 1110 -- ADJDIR = 1 -- PHADJ = 0 -- LID 01010 -- SCR = 1 -- L = 11110 -- F = 11001100 -- K = 11111 -- M = 00110011 -- CS = 10 -- N = 00011 -- SUBCLASSV = 1 -- Nn = 11101 -- JESDV = 0 -- S = 0 -- HD = 0 -- CF = 0 -- RES1 = 11111111 -- RES2 = 00000000 -- X = 010010000 ( DID => 170, ADJCNT => 7, BID => 14, ADJDIR => '1', PHADJ => '1', LID => 10, SCR => '1', L => 31, F => 205, K => 32, M => 52, CS => 2, N => 4, SUBCLASSV => 1, Nn => 30, JESDV => 0, S => 1, HD => '0', CF => 0, RES1 => "11111111", RES2 => "00000000", X => "010010000", CHKSUM => 48 ), ( DID => 170, ADJCNT => 7, BID => 14, ADJDIR => '1', PHADJ => '1', LID => 10, SCR => '1', L => 31, F => 205, K => 32, M => 52, CS => 2, N => 4, SUBCLASSV => 1, Nn => 30, JESDV => 0, S => 1, HD => '0', CF => 0, RES1 => "11111111", RES2 => "11111111", X => "010010000", CHKSUM => 48 ) ); @@ type test_vector_array is array (natural range<>) of test_vector; 75,7 103,7 @@ architecture a1 of ilas_parser_tb is (ILAS, ('1', '0', '0', "10011100"), '0', '0', '0', '0', -1), -- 28.4 (ILAS, ('0', '0', '0', "10101010"), '0', '0', '0', '0', -1), -- DID (ILAS, ('0', '0', '0', "01111110"), '0', '0', '0', '0', -1), -- ADJCNT,BID (ILAS, ('0', '0', '0', "01001010"), '0', '0', '0', '0', -1), -- X,ADJDIR,PHADJ,LID (ILAS, ('0', '0', '0', "01101010"), '0', '0', '0', '0', -1), -- X,ADJDIR,PHADJ,LID (ILAS, ('0', '0', '0', "11011110"), '0', '0', '0', '0', -1), -- SCR,X,L (ILAS, ('0', '0', '0', "11001100"), '0', '0', '0', '0', -1), -- F @@ (ILAS, ('0', '0', '0', "01011111"), '0', '0', '0', '0', -1), -- X, K 89,7 117,7 @@ architecture a1 of ilas_parser_tb is (ILAS, ('0', '0', '0', "00110000"), '0', '0', '0', '0', -1), (ILAS, ('1', '0', '0', "01111100"), '0', '0', '0', '0', 0), -- A (ILAS, ('1', '0', '0', "00011100"), '0', '0', '0', '0', 0), -- R (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0', -1), (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0', 0), (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0', 0), (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0', 0), @@ (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0', 0), 106,7 134,6 @@ architecture a1 of ilas_parser_tb is (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0', 0), (ILAS, ('1', '0', '0', "01111100"), '0', '0', '0', '0', 0), -- A (ILAS, ('1', '0', '0', "00011100"), '0', '0', '0', '0', 0), -- R, 2 mult (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0', -1), (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0', 0), (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0', 0), @@ (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0', 0), 121,7 148,8 @@ architecture a1 of ilas_parser_tb is (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0', 0), (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0', 0), (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0', 0), (ILAS, ('1', '0', '0', "01111100"), '0', '0', '0', '0', 0), -- A (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0', 0), (ILAS, ('1', '0', '0', "01111100"), '1', '0', '0', '0', 0), -- A (DATA, ('0', '0', '0', "00000001"), '1', '0', '0', '0', 0), (DATA, ('0', '0', '0', "00000010"), '1', '0', '0', '0', 0), @@ (DATA, ('0', '0', '0', "00000011"), '1', '0', '0', '0', 0), 147,7 175,7 @@ architecture a1 of ilas_parser_tb is (ILAS, ('1', '0', '0', "00011100"), '0', '0', '0', '0', -1), -- R, 0 mult (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0', -1), (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0', -1), (ILAS, ('1', '0', '0', "01111100"), '0', '1', '0', '1', 0), -- A (ILAS, ('1', '0', '0', "01111100"), '0', '1', '0', '1', -1), -- A (ILAS, ('0', '0', '0', "00000000"), '0', '1', '0', '1', -1), (ILAS, ('0', '0', '0', "00000000"), '0', '1', '0', '1', -1), @@ (INIT, ('0', '0', '0', "00000000"), '0', '0', '0', '0', -1), 158,7 186,7 @@ architecture a1 of ilas_parser_tb is (CGS, ('0', '0', '0', "10111100"), '0', '0', '0', '0', -1), (CGS, ('0', '0', '0', "10111100"), '0', '0', '0', '0', -1), (ILAS, ('1', '0', '0', "00011100"), '0', '0', '0', '0', -1), -- R, 0 mult (ILAS, ('1', '0', '0', "00011100"), '0', '0', '0', '0', -1), -- R, 0 mult (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0', -1), (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0', -1), (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0', -1), @@ (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0', -1), 189,18 217,20 @@ architecture a1 of ilas_parser_tb is (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0', -1), (ILAS, ('0', '0', '0', "11111111"), '0', '0', '0', '0', -1), (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0', -1), (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0', -1), (ILAS, ('0', '0', '0', "00000000"), '0', '1', '1', '0', -1), (ILAS, ('1', '0', '0', "01111100"), '0', '1', '1', '0', -1), -- A (ILAS, ('0', '0', '0', "00000000"), '0', '1', '1', '0', -1), (ILAS, ('0', '0', '0', "00000000"), '0', '1', '1', '0', -1), (ILAS, ('0', '0', '0', "00000000"), '0', '1', '1', '0', -1), (ILAS, ('0', '0', '0', "00000000"), '0', '1', '1', '0', -1), (ILAS, ('0', '0', '0', "00000000"), '0', '1', '1', '0', -1) (ILAS, ('0', '0', '0', "00000000"), '0', '1', '1', '0', -1), (INIT, ('0', '0', '0', "00000000"), '0', '1', '1', '0', -1) ); constant clk_period : time := 1 ns; constant F : integer range 0 to 256 := 17; constant K : integer range 0 to 32 := 1; signal clk : std_logic := '0'; @@ signal reset : std_logic := '0'; 223,6 253,7 @@ begin -- architecture a1 ci_char_clk => clk, ci_reset => reset, ci_F => F, ci_K => K, ci_state => ci_state, di_char => di_char, @@ do_config => do_config, 250,7 281,7 @@ begin -- architecture a1 prev_test_vec := test_vectors(i - 1); if prev_test_vec.expected_config_index > -1 then assert co_config = config_vectors(prev_test_vec.expected_config_index) report "The config does not match. Index: " & integer'image(i-1) severity error; assert do_config = config_vectors(prev_test_vec.expected_config_index) report "The config does not match. Index: " & integer'image(i-1) severity error; end if; assert co_error = prev_test_vec.expected_error report "The error does not match. Index: " & integer'image(i-1) severity error;