From ce19c85c740b00215122da8c2311b31421204db6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franti=C5=A1ek=20Boh=C3=A1=C4=8Dek?= Date: Wed, 12 Apr 2023 08:09:22 +0200 Subject: [PATCH] feat: partially implement channel widths --- src/data_link/char_alignment.vhd | 69 +++++++++---------- src/data_link/data_link_layer.vhd | 73 +++++++++++--------- src/data_link/data_link_pkg.vhd | 13 +--- src/data_link/frame_alignment.vhd | 39 ++++++----- src/data_link/ilas_parser.vhd | 14 ++-- src/data_link/lane_alignment.vhd | 51 +++++++++----- src/data_link/link_controller.vhd | 81 +++++++++++++++-------- src/data_link/ring_buffer.vhd | 5 +- testbench/data_link/char_alignment_tb.vhd | 18 ++--- 9 files changed, 207 insertions(+), 156 deletions(-) diff --git a/src/data_link/char_alignment.vhd b/src/data_link/char_alignment.vhd index 6ea67e9..2d38c35 100644 --- a/src/data_link/char_alignment.vhd +++ b/src/data_link/char_alignment.vhd @@ -17,47 +17,48 @@ use ieee.std_logic_1164.all; entity char_alignment is generic ( - sync_char : std_logic_vector(9 downto 0) := "0011111010" -- The character used for synchronization (positive RD) + CHANNEL_WIDTH : integer := 1; + sync_char : std_logic_vector(9 downto 0) := "0011111010" -- The character used for synchronization (positive RD) ); port ( - ci_char_clk: in std_logic; -- The character clock - ci_reset : in std_logic; -- The reset, active high. - di_10b : in std_logic_vector(9 downto 0); -- The 8b/10b encoded input data from physical layer - ci_synced : in std_logic; -- Whether the receiver is currently synchronized - do_10b : out std_logic_vector(9 downto 0); -- The 8b/10b encoded data aligned with a character (if co_aligned is true, otherwise unknown) - co_aligned : out std_logic); -- Whether the output is currently aligned + ci_link_clk : in std_logic; -- The character clock + ci_reset : in std_logic; -- The reset, active high. + di_chars : in std_logic_vector(10*CHANNEL_WIDTH-1 downto 0); -- The 8b/10b encoded input data from physical layer + ci_synced : in std_logic; -- Whether the receiver is currently synchronized + do_chars : out std_logic_vector(10*CHANNEL_WIDTH-1 downto 0); -- The 8b/10b encoded data aligned with a character (if co_aligned is true, otherwise unknown) + co_aligned : out std_logic); -- Whether the output is currently aligned end entity char_alignment; architecture a1 of char_alignment is - signal next_cache_10b : std_logic_vector(19 downto 0) := (others => '0'); -- The next value of cache_10b - signal next_do_10b : std_logic_vector(9 downto 0) := (others => '0'); -- The next value of do_10b - signal next_co_aligned : std_logic := '0'; + signal next_cache_chars : std_logic_vector(2*10*CHANNEL_WIDTH-1 downto 0) := (others => '0'); -- The next value of cache_10b + signal next_do_chars : std_logic_vector(10*CHANNEL_WIDTH-1 downto 0) := (others => '0'); -- The next value of do_10b + signal next_co_aligned : std_logic := '0'; - signal reg_found_sync_char : std_logic := '0'; -- Whether sync char was found - signal reg_cache_10b : std_logic_vector(19 downto 0) := (others => '0'); -- The cache of 10b characters. - signal reg_do_10b : std_logic_vector(9 downto 0) := (others => '0'); - signal reg_alignment_index : integer range 0 to 16 := 0; -- Where the character starts in the cache, if aligned. - signal reg_last_synced : std_logic := '0'; -- The last value of ci_synced - signal reg_co_aligned : std_logic := '0'; -- Whether aligned + signal reg_found_sync_char : std_logic := '0'; -- Whether sync char was found + signal reg_cache_chars : std_logic_vector(2*10*CHANNEL_WIDTH-1 downto 0) := (others => '0'); -- The cache of 10b characters. + signal reg_do_chars : std_logic_vector(10*CHANNEL_WIDTH-1 downto 0) := (others => '0'); + signal reg_alignment_index : integer range 0 to 16 := 0; -- Where the character starts in the cache, if aligned. + signal reg_last_synced : std_logic := '0'; -- The last value of ci_synced + signal reg_co_aligned : std_logic := '0'; -- Whether aligned begin -- architecture a1 -- purpose: Set next signals - -- type : combinational + -- type : sequential -- inputs : clk, reset -- outputs: alignment_index, cache_10b, do_10b, co_aligned - set_next: process (ci_char_clk, ci_reset) is + set_next : process (ci_link_clk, ci_reset) is begin -- process set_next if ci_reset = '0' then reg_last_synced <= '0'; - reg_co_aligned <= '0'; - reg_cache_10b <= (others => '0'); - reg_do_10b <= (others => '0'); - elsif rising_edge(ci_char_clk) then + reg_co_aligned <= '0'; + reg_cache_chars <= (others => '0'); + reg_do_chars <= (others => '0'); + elsif rising_edge(ci_link_clk) then reg_last_synced <= ci_synced; - reg_co_aligned <= next_co_aligned; - reg_cache_10b <= next_cache_10b; - reg_do_10b <= next_do_10b; + reg_co_aligned <= next_co_aligned; + reg_cache_chars <= next_cache_chars; + reg_do_chars <= next_do_chars; end if; end process set_next; @@ -65,12 +66,12 @@ begin -- architecture a1 -- type : sequential -- inputs : ci_char_clk, ci_reset, di_10b, ci_synced -- outputs: reg_found_sync_char, reg_alignment_index - find_sync_char: process (ci_char_clk, ci_reset) is + find_sync_char: process (ci_link_clk, ci_reset) is begin -- process find_sync_char if ci_reset = '0' then -- asynchronous reset (active low) reg_alignment_index <= 0; reg_found_sync_char <= '0'; - elsif rising_edge(ci_char_clk) then -- rising clock edge + elsif rising_edge(ci_link_clk) then -- rising clock edge if reg_found_sync_char = '1' then reg_found_sync_char <= '0'; end if; @@ -78,10 +79,10 @@ begin -- architecture a1 -- will be set by 8b10b_decoder) if ci_synced = '0' then -- Try to find /K/ (sync_char) in either RD (either sync_char or not sync_char). - for i in 0 to 9 loop - if reg_cache_10b(i+9 downto i) = sync_char or reg_cache_10b(i+9 downto i) = not sync_char then + for i in 0 to (2*CHANNEL_WIDTH-1)*10-1 loop + if reg_cache_chars(i+9 downto i) = sync_char or reg_cache_chars(i+9 downto i) = not sync_char then reg_found_sync_char <= '1'; - reg_alignment_index <= i; + reg_alignment_index <= i mod 10; end if; end loop; -- i end if; @@ -89,9 +90,9 @@ begin -- architecture a1 end process find_sync_char; co_aligned <= reg_co_aligned; - do_10b <= reg_do_10b; + do_chars <= reg_do_chars; - next_co_aligned <= (reg_found_sync_char or reg_co_aligned) and not (reg_last_synced and not ci_synced); - next_do_10b(9 downto 0) <= reg_cache_10b(reg_alignment_index+9 downto reg_alignment_index); - next_cache_10b(19 downto 0) <= reg_cache_10b(9 downto 0) & di_10b(9 downto 0); + next_co_aligned <= (reg_found_sync_char or reg_co_aligned) and not (reg_last_synced and not ci_synced); + next_do_chars(CHANNEL_WIDTH*10-1 downto 0) <= reg_cache_chars(reg_alignment_index+CHANNEL_WIDTH*10-1 downto reg_alignment_index); + next_cache_chars(2*CHANNEL_WIDTH*10-1 downto 0) <= reg_cache_chars(CHANNEL_WIDTH*10-1 downto 0) & di_chars(CHANNEL_WIDTH*10-1 downto 0); end architecture a1; diff --git a/src/data_link/data_link_layer.vhd b/src/data_link/data_link_layer.vhd index dc38169..69a74bd 100644 --- a/src/data_link/data_link_layer.vhd +++ b/src/data_link/data_link_layer.vhd @@ -28,6 +28,10 @@ entity data_link_layer is A_character : std_logic_vector(7 downto 0) := "01111100"; -- multiframe end Q_character : std_logic_vector(7 downto 0) := "10011100"; -- 2nd ILAS frame -- 2nd character + CHANNEL_WIDTH : integer := 1; -- How many + -- characters are on + -- the input of the + -- layer ALIGN_BUFFER_SIZE : integer := 255; -- Size of a -- buffer that is -- used for @@ -39,7 +43,7 @@ entity data_link_layer is F : integer range 1 to 256 := 2; -- Number of octets in a frame K : integer range 1 to 32 := 1); -- Number of frames in a mutliframe port ( - ci_char_clk : in std_logic; -- Character clock + ci_link_clk : in std_logic; -- Link clk (character clk divided by CHANNEL_WIDTH) ci_frame_clk : in std_logic; -- Frame clock ci_reset : in std_logic; -- Reset (asynchronous, active low) @@ -53,15 +57,15 @@ entity data_link_layer is -- input, output co_synced : out std_logic; -- Whether the lane is synced - di_10b : in std_logic_vector(9 downto 0); -- The 10b input character + di_chars : in std_logic_vector(10*CHANNEL_WIDTH-1 downto 0); -- The 10b input characters do_aligned_chars : out std_logic_vector(8*F - 1 downto 0); co_frame_state : out frame_state); -- The aligned frame output character end entity data_link_layer; architecture a1 of data_link_layer is - signal char_alignment_do_10b : std_logic_vector(9 downto 0); + signal char_alignment_do_chars : std_logic_vector(10*CHANNEL_WIDTH-1 downto 0); - signal decoder_do_char : character_vector; + signal decoder_do_chars : character_array(0 to CHANNEL_WIDTH-1); signal error_handler_co_request_sync : std_logic; @@ -69,7 +73,7 @@ architecture a1 of data_link_layer is signal lane_alignment_co_aligned : std_logic; signal lane_alignment_co_error : std_logic; signal lane_alignment_co_ready : std_logic; - signal lane_alignment_do_char : character_vector; + signal lane_alignment_do_char : character_array(0 to CHANNEL_WIDTH-1); signal lane_alignment_co_correct_sync_chars : integer; signal frame_alignment_ci_request_sync : std_logic; @@ -123,12 +127,13 @@ begin -- architecture a1 link_controller_ci_resync <= error_handler_co_request_sync or ci_request_sync; link_controller : entity work.link_controller generic map ( - SUBCLASSV => SUBCLASSV, - F => F, - K => K) + CHANNEL_WIDTH => CHANNEL_WIDTH, + SUBCLASSV => SUBCLASSV, + F => F, + K => K) port map ( ci_frame_clk => ci_frame_clk, - ci_char_clk => ci_char_clk, + ci_link_clk => ci_link_clk, ci_reset => ci_reset, ci_resync => link_controller_ci_resync, ci_lane_alignment_error => lane_alignment_co_error, @@ -136,36 +141,43 @@ begin -- architecture a1 ci_lane_alignment_ready => lane_alignment_co_ready, ci_frame_alignment_error => frame_alignment_co_error, ci_frame_alignment_aligned => frame_alignment_co_aligned, - di_char => decoder_do_char, + di_chars => decoder_do_chars, co_synced => link_controller_co_synced, co_state => link_controller_co_state, do_config => link_controller_do_config); -- char alignment - char_alignment: entity work.char_alignment + char_alignment : entity work.char_alignment + generic map ( + CHANNEL_WIDTH => CHANNEL_WIDTH) port map ( - ci_char_clk => ci_char_clk, + ci_link_clk => ci_link_clk, ci_reset => ci_reset, ci_synced => link_controller_co_synced, - di_10b => di_10b, - do_10b => char_alignment_do_10b); - - -- 8b10b decoder - an8b10b_decoder: entity work.an8b10b_decoder - port map ( - ci_char_clk => ci_char_clk, - ci_reset => ci_reset, - di_10b => char_alignment_do_10b, - do_char => decoder_do_char); + di_chars => di_chars, + do_chars => char_alignment_do_chars); + + -- 8b10b decoders (for each character) + decode : for i in 0 to CHANNEL_WIDTH - 1 generate + constant lower_bit_position : integer := CHANNEL_WIDTH*10 - (i + 1)*10; + begin + an8b10b_decoder : entity work.an8b10b_decoder + port map ( + ci_link_clk => ci_link_clk, + ci_reset => ci_reset, + di_chars => char_alignment_do_chars(lower_bit_position + 9 downto lower_bit_position), + do_chars => decoder_do_chars(i)); + end generate decode; -- lane alignment lane_alignment : entity work.lane_alignment generic map ( - BUFFER_SIZE => ALIGN_BUFFER_SIZE, - F => F, - K => K) + CHANNEL_WIDTH => CHANNEL_WIDTH, + BUFFER_SIZE => ALIGN_BUFFER_SIZE, + F => F, + K => K) port map ( - ci_char_clk => ci_char_clk, + ci_link_clk => ci_link_clk, ci_reset => ci_reset, ci_state => link_controller_co_state, ci_realign => lane_alignment_ci_realign, @@ -178,11 +190,12 @@ begin -- architecture a1 -- frame alignment frame_alignment : entity work.frame_alignment generic map ( - SCRAMBLING => SCRAMBLING, - F => F, - K => K) + CHANNEL_WIDTH => CHANNEL_WIDTH, + SCRAMBLING => SCRAMBLING, + F => F, + K => K) port map ( - ci_char_clk => ci_char_clk, + ci_link_clk => ci_link_clk, ci_frame_clk => ci_frame_clk, ci_reset => ci_reset, co_frame_state => frame_alignment_co_frame_state, diff --git a/src/data_link/data_link_pkg.vhd b/src/data_link/data_link_pkg.vhd index 3de1250..9b50d9c 100644 --- a/src/data_link/data_link_pkg.vhd +++ b/src/data_link/data_link_pkg.vhd @@ -11,18 +11,7 @@ package data_link_pkg is user_data : std_logic; -- Whether the data is user data (in -- DATA state, false otherwise) end record character_vector; - - type frame_character is record - kout : std_logic; -- Whether the character is a control character - disparity_error : std_logic; -- Whether there was a disparity error (if this is true, the character will still be correct) - missing_error : std_logic; -- Whether the character was not found in the table - d8b : std_logic_vector(7 downto 0); -- The decoded data - octet_index : integer range 0 to 256; -- The position of the octet in a - -- frame - frame_index : integer range 0 to 32; -- The position of the frame in multiframe - user_data : std_logic; -- Whether the data is user data (in - -- DATA state, false otherwise) - end record frame_character; + type character_array is array (natural range <>) of character_vector; type link_state is ( INIT, -- Initial state, waiting for /K/ characters diff --git a/src/data_link/frame_alignment.vhd b/src/data_link/frame_alignment.vhd index ed9d1fa..2fa7b52 100644 --- a/src/data_link/frame_alignment.vhd +++ b/src/data_link/frame_alignment.vhd @@ -19,22 +19,24 @@ use work.transport_pkg.all; entity frame_alignment is generic ( - SCRAMBLING : std_logic; -- Whether data are scrambled - F : integer range 0 to 256 := 8; -- Number of octets in a frame - K : integer range 0 to 32 := 1; -- Number of frames in a multiframe + CHANNEL_WIDTH : integer := 1; + SCRAMBLING : std_logic; -- Whether data are scrambled + F : integer range 0 to 256 := 8; -- Number of octets in a frame + K : integer range 0 to 32 := 1; -- Number of frames in a multiframe + BUFFER_SIZE : integer := 2*F; sync_char : std_logic_vector(7 downto 0) := "10111100"; -- K -- character - -- for syncing + -- for syncing A_char : std_logic_vector(7 downto 0) := "01111100"; -- Last -- character - -- in multiframe + -- in multiframe F_char : std_logic_vector(7 downto 0) := "11111100"; -- Last -- character -- in frame F_replace_data : std_logic_vector(7 downto 0) := "11111100"; -- The character to replace with upon receiving /F/ with scrambled data A_replace_data : std_logic_vector(7 downto 0) := "01111100"); -- The character to replace with upon receiving /A/ with scrambled data port ( - ci_char_clk : in std_logic; -- Character clock + ci_link_clk : in std_logic; -- Character clock ci_frame_clk : in std_logic; -- Frame clock ci_reset : in std_logic; -- Reset (asynchronous, active low) ci_request_sync : in std_logic; -- Whether sync is requested @@ -78,24 +80,25 @@ architecture a1 of frame_alignment is signal reg_correct_sync_chars : integer := 0; signal reg_known_sync_char_position : integer range 0 to 256; - signal next_octet_index : integer range 0 to F := 0; + signal next_octet_index : integer range 0 to F := 0; signal next_adjusted_octet_index : integer range 0 to F := 0; begin -- architecture a1 - data_buffer: entity work.ring_buffer + data_buffer : entity work.ring_buffer generic map ( - BUFFER_SIZE => F*2, + BUFFER_SIZE => BUFFER_SIZE, READ_SIZE => F, + WRITE_SIZE => CHANNEL_WIDTH, CHARACTER_SIZE => 8) port map ( - ci_clk => ci_char_clk, - ci_reset => ci_reset, - ci_adjust_position => buffer_adjust_position, - ci_read => ci_frame_clk, - di_character => buffer_character, - co_read => do_aligned_chars, - co_read_position => buffer_read_position, - co_write_position => buffer_write_position, - co_filled => buffer_filled); + ci_clk => ci_link_clk, + ci_reset => ci_reset, + ci_adjust_position => buffer_adjust_position, + ci_read => ci_frame_clk, + di_character => buffer_character, + co_read => do_aligned_chars, + co_read_position => buffer_read_position, + co_write_position => buffer_write_position, + co_filled => buffer_filled); next_frame: process (ci_frame_clk) is begin -- process next_frame diff --git a/src/data_link/ilas_parser.vhd b/src/data_link/ilas_parser.vhd index 61ca948..53fb7ff 100644 --- a/src/data_link/ilas_parser.vhd +++ b/src/data_link/ilas_parser.vhd @@ -14,6 +14,7 @@ use ieee.numeric_std.all; entity ilas_parser is generic ( + CHANNEL_WIDTH : integer := 1; 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 @@ -30,7 +31,7 @@ entity ilas_parser is multiframes_count : integer range 1 to 32 := 4); port ( - ci_char_clk : in std_logic; -- Character clock + ci_link_clk : in std_logic; -- Link 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 @@ -58,7 +59,6 @@ architecture a1 of ilas_parser is signal finished : std_logic := '0'; signal err : std_logic := '0'; - function getOctetUpIndex ( octet_index : integer range 0 to F*K+5) return integer is @@ -104,7 +104,7 @@ begin -- architecture a1 -- 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 + set_next: process (ci_link_clk, ci_reset) is begin -- process set_next if ci_reset = '0' then -- asynchronous reset (active low) reg_octet_index <= 0; @@ -117,10 +117,14 @@ begin -- architecture a1 end if; end process set_next; - check_chars: process (ci_char_clk, ci_reset) is + check_chars: process (ci_link_clk, ci_reset) is variable up_index : integer range 7 to link_config_length-1; variable processing_ilas : std_logic; begin -- process check_chars + -- if in CGS, find first non /K/ character after 4 /K/ characters, + -- then move to ILS + -- take care that /R/ may be at any position, not just the first one. + -- store some kind of position information of the next link dta processing_ilas := next_processing_ilas or reg_processing_ilas; if ci_reset = '0' then -- asynchronous reset (active low) err <= '0'; @@ -128,7 +132,7 @@ begin -- architecture a1 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 + elsif ci_link_clk'event and ci_link_clk = '1' and (processing_ilas = '0' or ci_state = INIT) then err <= '0'; co_unexpected_char <= '0'; co_wrong_chksum <= '0'; diff --git a/src/data_link/lane_alignment.vhd b/src/data_link/lane_alignment.vhd index bf0d66f..c42141b 100644 --- a/src/data_link/lane_alignment.vhd +++ b/src/data_link/lane_alignment.vhd @@ -15,6 +15,7 @@ use work.data_link_pkg.all; entity lane_alignment is generic ( + CHANNEL_WIDTH : integer := 1; F : integer range 1 to 256; -- Number of octets in a frame K : integer range 1 to 32; -- Number of frames in a multiframe BUFFER_SIZE : integer := 256; -- How many octets to keep @@ -23,21 +24,21 @@ entity lane_alignment is -- Character to send before the buffer is ready and started port ( - ci_char_clk : in std_logic; -- Character clock + ci_link_clk : in std_logic; -- Link clock ci_reset : in std_logic; -- Reset (asynchronous, active low) ci_start : in std_logic; -- Start sending the data from the -- buffer. - ci_state : in link_state; -- State of the lane + ci_state : in link_state; -- State of the lane ci_realign : in std_logic; -- Whether to realign to the last -- found alignment character - di_char : in character_vector; -- Character from 8b10b decoder + di_chars : in character_array; -- Character from 8b10b decoder co_ready : out std_logic; -- Whether /A/ was received and -- waiting for start co_aligned : out std_logic; -- Whether the alignment is still correct - co_correct_sync_chars : out integer; -- How many alignment characters on - -- correct place were found in a row + co_correct_sync_chars : out integer; -- How many alignment characters on + -- correct place were found in a row co_error : out std_logic; -- Whether there is an error - do_char : out character_vector); -- The aligned output character + do_chars : out character_array); -- The aligned output character end entity lane_alignment; @@ -59,6 +60,7 @@ architecture a1 of lane_alignment is signal next_error : std_logic := '0'; begin -- architecture a1 set_next : process (ci_char_clk, ci_reset) is + variable ready : std_logic := '0'; begin -- process set_next if ci_reset = '0' then -- asynchronous reset (active low) reg_write_index <= 0; @@ -68,16 +70,29 @@ begin -- architecture a1 reg_error <= '0'; buff <= (others => ('0', '0', '0', "00000000", '0')); elsif ci_char_clk'event and ci_char_clk = '1' then -- rising clock edge - reg_write_index <= next_write_index; - reg_read_index <= next_read_index; - reg_ready <= next_ready; - reg_started <= next_started; - reg_error <= next_error; - buff(reg_write_index).d8b <= di_char.d8b; - buff(reg_write_index).kout <= di_char.kout; - buff(reg_write_index).disparity_error <= di_char.disparity_error; - buff(reg_write_index).missing_error <= di_char.missing_error; - buff(reg_write_index).user_data <= '1' when ci_state = DATA else '0'; + ready := reg_ready; + if ci_state = INIT or reg_ready = '0' then + ready := '0'; + reg_read_index <= 0; + reg_write_index <= 0; + end if; + + reg_write_index <= reg_write_index + CHANNEL_WIDTH; + reg_read_index <= reg_read_index + CHANNEL_WIDTH; + reg_ready <= ready; + reg_started <= next_started; + reg_error <= next_error; + for i in 0 to CHANNEL_WIDTH - 1 loop + -- if CGS, look for /R/, if /R/, set that as starting index + if ci_state = CGS then + + end if; + buff((reg_write_index + i) mod BUFFER_SIZE).d8b <= di_chars(i).d8b; + buff((reg_write_index + i) mod BUFFER_SIZE).kout <= di_chars(i).kout; + buff((reg_write_index + i) mod BUFFER_SIZE).disparity_error <= di_chars(i).disparity_error; + buff((reg_write_index + i) mod BUFFER_SIZE).missing_error <= di_chars(i).missing_error; + buff((reg_write_index + i) mod BUFFER_SIZE).user_data <= '1' when ci_state = DATA else '0'; + end loop; -- i end if; end process set_next; @@ -102,7 +117,7 @@ begin -- architecture a1 '1' when reg_ready = '1' and reg_started = '0' and (reg_write_index = 0) else '0'; - do_char <= dummy_character when ci_state = INIT or reg_started = '0' else - buff(reg_read_index); + do_chars <= dummy_characters when ci_state = INIT or reg_started = '0' else + buff(reg_read_index to reg_read_index + CHANNEL); end architecture a1; diff --git a/src/data_link/link_controller.vhd b/src/data_link/link_controller.vhd index 263e3b7..aab520f 100644 --- a/src/data_link/link_controller.vhd +++ b/src/data_link/link_controller.vhd @@ -20,15 +20,15 @@ use work.data_link_pkg.all; entity link_controller is generic ( - SUBCLASSV : integer range 0 to 1 := 0; - 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"); -- Sync character + CHANNEL_WIDTH : integer := 1; -- Number of characters going in at once + 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"); -- Sync character port ( - ci_frame_clk : in std_logic; -- Frame clock - ci_char_clk : in std_logic; -- Character clock - ci_reset : in std_logic; -- Reset (asynchronous, active low) - di_char : in character_vector; -- Output character from 8b10b decoder + ci_frame_clk : in std_logic; -- Frame clock + ci_link_clk : in std_logic; -- Link clock + ci_reset : in std_logic; -- Reset (asynchronous, active low) + di_chars : in character_array(0 to CHANNEL_WIDTH-1); -- Output character from 8b10b decoder do_config : out link_config; -- Config found in ILAS @@ -71,36 +71,64 @@ architecture a1 of link_controller is signal reg_state : link_state := INIT; signal reg_k_counter : integer range 0 to 15 := 0; - signal ilas_finished : std_logic := '0'; - signal ilas_error : std_logic := '0'; - signal ilas_wrong_chksum : std_logic := '0'; + signal ilas_finished : std_logic := '0'; + signal ilas_error : std_logic := '0'; + signal ilas_wrong_chksum : std_logic := '0'; signal ilas_unexpected_char : std_logic := '0'; + + signal any_missing_error : std_logic; + signal any_disparity_error : std_logic; begin -- architecture a1 - ilas: entity work.ilas_parser + ilas : entity work.ilas_parser generic map ( - F => F, - K => K) + CHANNEL_WIDTH => CHANNEL_WIDTH, + F => F, + K => K) port map ( ci_char_clk => ci_char_clk, ci_reset => ci_reset, ci_state => reg_state, - di_char => di_char, + di_chars => di_chars, do_config => do_config, co_finished => ilas_finished, co_error => ilas_error, co_wrong_chksum => ilas_wrong_chksum, co_unexpected_char => ilas_unexpected_char); - set_state: process (ci_char_clk, ci_reset) is - variable char_error : std_logic; + set_state: process (ci_link_clk, ci_reset) is + variable chars_error : std_logic := '0'; + variable chars_missing_error : std_logic := '0'; + variable chars_disparity_error : std_logic := '0'; + variable k_count : integer := 0; begin -- process set_state if ci_reset = '0' then -- asynchronous reset (active low) reg_state <= INIT; - elsif ci_char_clk'event and ci_char_clk = '1' then -- rising clock edge - char_error := di_char.disparity_error or di_char.missing_error; + reg_k_counter <= '0'; + correct_8b10b_characters <= 0; + elsif ci_link_clk'event and ci_link_clk = '1' then -- rising clock edge + k_count := reg_k_counter; + for i in 0 to CHANNEL_WIDTH - 1 loop + if di_chars(i).disparity_error = '1' then + chars_disparity_error := '1'; + end if; + if di_chars(i).missing_error = '1' then + chars_missing_error := '1'; + end if; + + if di_chars(i).d8b = K_character and di_chars(i).kout = '1' then + k_count := k_count + 1; + else + k_count := 0; + end if; + end loop; -- i + chars_error := chars_missing_error or chars_disparity_error; if correct_8b10b_characters < FULL_SYNCHRONIZATION_AFTER and char_error = '0' then - correct_8b10b_characters <= correct_8b10b_characters + 1; + if correct_8b10b_characters + CHANNEL_WIDTH > FULL_SYNCHRONIZATION_AFTER then + correct_8b10b_characters <= FULL_SYNCHRONIZATION_AFTER; + else + correct_8b10b_characters <= correct_8b10b_characters + CHANNEL_WIDTH; + end if; end if; if ci_resync = '1' or (full_synchronization = '0' and char_error = '1') then @@ -109,15 +137,11 @@ begin -- architecture a1 elsif reg_state = CGS then if reg_k_counter < SYNC_COUNT then correct_8b10b_characters <= 1; - if di_char.d8b = K_character and di_char.kout = '1' then - reg_k_counter <= reg_k_counter + 1; - else - reg_k_counter <= 0; - end if; - elsif di_char.d8b /= K_character or di_char.kout = '0' then + reg_k_counter <= k_count; + elsif k_count = 0 then reg_state <= ILS; end if; - elsif di_char.d8b = K_character and di_char.kout = '1' then + elsif k_count > 0 then reg_state <= CGS; reg_k_counter <= 0; elsif reg_state = ILS then @@ -137,9 +161,10 @@ begin -- architecture a1 co_synced <= synced; co_state <= reg_state; + -- TODO: add ILAS errors, add CGS error in case sync does not happen for long -- time - co_error <= ci_lane_alignment_error or ci_frame_alignment_error or di_char.missing_error or di_char.disparity_error; + co_error <= ci_lane_alignment_error or ci_frame_alignment_error or any_missing_error or any_disparity_error; co_uncorrectable_error <= ilas_error; end architecture a1; diff --git a/src/data_link/ring_buffer.vhd b/src/data_link/ring_buffer.vhd index c0cc765..02d1a18 100644 --- a/src/data_link/ring_buffer.vhd +++ b/src/data_link/ring_buffer.vhd @@ -7,6 +7,7 @@ entity ring_buffer is generic ( CHARACTER_SIZE : integer := 8; BUFFER_SIZE : integer; + WRITE_SIZE : integer := 1; READ_SIZE : integer); -- The size of the buffer port ( @@ -15,7 +16,7 @@ entity ring_buffer is ci_adjust_position : in integer range -READ_SIZE/2-1 to READ_SIZE/2+1; ci_read : in std_logic; -- One to read in current cycle, Zero -- to stay on current reading position - di_character : in std_logic_vector(CHARACTER_SIZE-1 downto 0); -- The character to save on next clock + di_character : in std_logic_vector(CHARACTER_SIZE*WRITE_SIZE-1 downto 0); -- The character to save on next clock co_read : out std_logic_vector(CHARACTER_SIZE*READ_SIZE - 1 downto 0); -- The output characters read from the buffer co_size : out integer; -- The current count of filled data co_read_position : out integer; -- The current read position inside of @@ -68,7 +69,7 @@ begin -- architecture a1 end if; adjusted_read_position <= read_position + ci_adjust_position; - buff(CHARACTER_SIZE*BUFFER_SIZE-1 - CHARACTER_SIZE*write_position downto CHARACTER_SIZE*BUFFER_SIZE - CHARACTER_SIZE*(write_position + 1)) <= di_character; + buff(CHARACTER_SIZE*BUFFER_SIZE-1 - CHARACTER_SIZE*WRITE_SIZE*write_position downto CHARACTER_SIZE*BUFFER_SIZE - CHARACTER_SIZE*WRITE_SIZE*(write_position + 1)) <= di_character; write_position <= (write_position + 1) mod BUFFER_SIZE; end if; end process read; diff --git a/testbench/data_link/char_alignment_tb.vhd b/testbench/data_link/char_alignment_tb.vhd index f8edb6c..ee47df8 100644 --- a/testbench/data_link/char_alignment_tb.vhd +++ b/testbench/data_link/char_alignment_tb.vhd @@ -31,9 +31,9 @@ architecture a1 of char_alignment_tb is data_count => 10, synced_after => 4, expected_aligned_after => 4, - expected_alignment_index => 2, - data => (0 => "1111101000", 1 => "0000010100", 2 => "1010101011", 3 => "0101010110", 4 => "1110000001", 5 => "0001111111", 6 => "0000000000", others => "0000000000"), - expected_data => (0 => "0011111010", 1 => "1100000101", 2 => "1010101010", 3 => "0101010101", 4 => "1111100000", 5 => "0000011111", others => "0000000000") + expected_alignment_index => 1, + data => (0 => "0111110100", 1 => "0000010100", 2 => "1010101011", 3 => "0101010101", 4 => "1111000000", 5 => "0000111110", 6 => "0000000000", others => "0000000000"), + expected_data => (0 => "0011111010", 1 => "0000001010", 2 => "0101010101", 3 => "1010101010", 4 => "1111100000", 5 => "0000011111", others => "0000000000") ) ); @@ -51,14 +51,14 @@ architecture a1 of char_alignment_tb is signal cycle_num : integer := 0; begin -- architecture a1 - uut: entity work.char_alignment + uut : entity work.char_alignment port map ( - ci_char_clk => clk, + ci_link_clk => clk, ci_reset => reset, - di_10b => di_10b, - do_10b => do_10b, + di_chars => di_10b, + do_chars => do_10b, ci_synced => ci_synced, - co_aligned => co_aligned); + co_aligned => co_aligned); clk_gen: process is begin -- process clk_gen @@ -94,7 +94,7 @@ begin -- architecture a1 end if; if cycle >= test_vec.synced_after then - assert (do_10b = test_vec.expected_data(cycle - 3)) report "The data does not match, data index: " & integer'image(i) & ", expected: " & vec2str(test_vec.expected_data(cycle - 2)) & ", got: " & vec2str(do_10b) severity error; + assert (do_10b = test_vec.expected_data(cycle - 2)) report "The data does not match, data index: " & integer'image(i) & ", expected: " & vec2str(test_vec.expected_data(cycle - 2)) & ", got: " & vec2str(do_10b) severity error; end if; wait for clk_period; -- 2.48.1