From d7408384753cca0edc6a9e78f4fe2859258fab8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franti=C5=A1ek=20Boh=C3=A1=C4=8Dek?= Date: Sun, 13 Nov 2022 21:57:13 +0100 Subject: [PATCH] feat(link): implement ilas parser --- src/data_link/ilas_parser.vhd | 139 ++++++++++++++++++++----- testbench/data_link/ilas_parser_tb.vhd | 93 +++++++++++------ 2 files changed, 173 insertions(+), 59 deletions(-) diff --git a/src/data_link/ilas_parser.vhd b/src/data_link/ilas_parser.vhd index 37095fe..7e6ac3c 100644 --- a/src/data_link/ilas_parser.vhd +++ b/src/data_link/ilas_parser.vhd @@ -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; diff --git a/testbench/data_link/ilas_parser_tb.vhd b/testbench/data_link/ilas_parser_tb.vhd index 42ff4b3..75bc99b 100644 --- a/testbench/data_link/ilas_parser_tb.vhd +++ b/testbench/data_link/ilas_parser_tb.vhd @@ -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; -- 2.49.0