From 4bace44306f007ff569fec667f7c77e56ad9c46a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franti=C5=A1ek=20Boh=C3=A1=C4=8Dek?= Date: Wed, 22 Feb 2023 19:52:37 +0100 Subject: [PATCH] feat: rewrite frame alignment to use ring buffer --- src/data_link/frame_alignment.vhd | 167 +++++++++++++++++------------- 1 file changed, 93 insertions(+), 74 deletions(-) diff --git a/src/data_link/frame_alignment.vhd b/src/data_link/frame_alignment.vhd index a93738f..7135fe3 100644 --- a/src/data_link/frame_alignment.vhd +++ b/src/data_link/frame_alignment.vhd @@ -15,9 +15,13 @@ library ieee; use ieee.std_logic_1164.all; use work.data_link_pkg.all; +use work.transport_pkg.all; entity frame_alignment is generic ( + SCRAMBLED : boolean; -- 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 sync_char : std_logic_vector(7 downto 0) := "10111100"; -- K -- character -- for syncing @@ -31,11 +35,9 @@ entity frame_alignment is 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_frame_clk : in std_logic; -- Frame clock ci_reset : in std_logic; -- Reset (asynchronous, active low) - ci_F : in integer range 0 to 256; -- The number of octets in a frame - ci_K : in integer range 0 to 32; -- The number of frames in a multiframe ci_request_sync : in std_logic; -- Whether sync is requested - ci_scrambled : in std_logic; -- Whether the data is scrambled ci_realign : in std_logic; -- Whether to realign to last -- alignment character di_char : in character_vector; -- The received character @@ -44,14 +46,25 @@ entity frame_alignment is -- the alignment co_correct_sync_chars : out integer; -- Number of alignment characters on -- same position in a row - do_char : out frame_character); -- The output character - -- (going to transport layer) + do_aligned_chars : out std_logic_vector(8*F - 1 downto 0); + co_frame_state : out frame_state); -- Errors for current or next frame + -- a characters in a frame end entity frame_alignment; architecture a1 of frame_alignment is - type alignment_state is (INIT, RECEIVED_K, ALIGNED, MISALIGNED); + type alignment_state is (INIT, ALIGNED, MISALIGNED); signal reg_state : alignment_state := INIT; + signal next_frame_state : frame_state; + + signal buffer_character : std_logic_vector(7 downto 0) := "00000000"; + signal buffer_raw_adjust_position : integer := 0; + signal buffer_adjust_position : integer := 0; + signal buffer_align_to : integer := 0; + signal buffer_read_position : integer := 0; + signal buffer_write_position : integer := 0; + signal buffer_filled : std_logic := '0'; + signal reg_last_frame_data : std_logic_vector(7 downto 0) := "00000000"; signal next_is_last_octet : std_logic := '0'; @@ -62,31 +75,49 @@ architecture a1 of frame_alignment is signal is_wrong_char : std_logic := '0'; - signal reg_octet_index : integer range 0 to 256 := 0; - signal reg_frame_index : integer range 0 to 32 := 0; 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 256 := 0; - signal next_frame_index : integer range 0 to 32 := 0; - signal next_char : character_vector := ('0', '0', '0', "00000000", '0'); + signal next_octet_index : integer := 0; begin -- architecture a1 - set_next: process (ci_char_clk, ci_reset) is + data_buffer: entity work.ring_buffer + generic map ( + BUFFER_SIZE => F*2, + READ_SIZE => F, + 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); + + next_frame: process (ci_frame_clk) is + begin -- process next_frame + if ci_reset = '0' then + co_frame_state <= ('0', '0', '0', '0', '0', '0', '0', '0'); + elsif ci_frame_clk'event and ci_frame_clk = '1' then -- rising clock edge + co_frame_state <= next_frame_state; + end if; + end process next_frame; + + set_next: process (ci_char_clk, ci_frame_clk, ci_reset) is begin -- process set_next - if ci_reset = '0' then -- asynchronous reset (active low) - reg_frame_index <= 0; - reg_octet_index <= 0; - do_char <= ('0', '0', '0', "00000000", 0, 0, '0'); + if ci_reset = '1' and ci_frame_clk'event and ci_frame_clk = '1' then + if reg_state /= INIT then + next_frame_state <= ('1', '0', '0', '0', '0', '0', '0', '0'); + end if; + end if; + + if ci_reset = '0' then -- asynchronous reset (active reg_state <= INIT; - reg_correct_sync_chars <= 0; + reg_last_frame_data <= (others => '0'); + next_frame_state <= ('0', '0', '0', '0', '0', '0', '0', '0'); elsif ci_char_clk'event and ci_char_clk = '1' then -- rising clock edge - do_char.kout <= next_char.kout; - do_char.d8b <= next_char.d8b; - do_char.disparity_error <= next_char.disparity_error; - do_char.missing_error <= next_char.missing_error; - do_char.user_data <= next_char.user_data; - do_char.frame_index <= reg_frame_index; - -- set last_frame_data if this is the last frame and not /F/ or /A/ if next_is_last_octet = '1' and not (is_f = '1' or is_a = '1') then reg_last_frame_data <= di_char.d8b; @@ -94,87 +125,75 @@ begin -- architecture a1 if ci_request_sync = '1' then reg_state <= INIT; - reg_frame_index <= 0; - reg_octet_index <= 0; - do_char.octet_index <= 0; - do_char.frame_index <= 0; - elsif di_char.kout = '1' and di_char.d8b = sync_char then - reg_state <= RECEIVED_K; - reg_frame_index <= 0; - reg_octet_index <= 0; - do_char.octet_index <= 0; - do_char.frame_index <= 0; + next_frame_state <= ('0', '0', '0', '0', '0', '0', '0', '0'); elsif reg_state = INIT then - reg_frame_index <= 0; - reg_octet_index <= 0; - do_char.octet_index <= 0; - do_char.frame_index <= 0; - elsif reg_state = RECEIVED_K then - reg_frame_index <= 0; - reg_octet_index <= 0; - do_char.octet_index <= 0; - do_char.frame_index <= 0; - - if di_char.d8b /= sync_char or di_char.kout = '0' then + next_frame_state <= ('0', '0', '0', '0', '0', '0', '0', '0'); + -- if a or f, align to it and move to aligned + if is_a = '1' or is_f = '1' then + -- align to current character. + buffer_align_to <= next_octet_index; + next_frame_state <= ('1', '0', '0', '0', '0', '0', '0', '0'); reg_state <= ALIGNED; - end if; -- switch to aligned + end if; else - reg_frame_index <= next_frame_index; - reg_octet_index <= next_octet_index; - do_char.octet_index <= next_octet_index; - do_char.frame_index <= next_frame_index; + if di_char.kout = '1' and not (is_a = '1' or is_f = '1') then + next_frame_state.invalid_characters <= '1'; + end if; + if di_char.disparity_error = '1' then + next_frame_state.disparity_error <= '1'; + end if; + if di_char.missing_error then + next_frame_state.not_in_table_error <= '1'; + end if; + if di_char.user_data = '0' then + next_frame_state.user_data <= '0'; + end if; if reg_state = ALIGNED then if is_wrong_char = '1' then + next_frame_state.wrong_alignment <= '1'; reg_state <= MISALIGNED; reg_correct_sync_chars <= 1; - reg_known_sync_char_position <= reg_octet_index; + reg_known_sync_char_position <= next_octet_index; end if; elsif reg_state = MISALIGNED then + next_frame_state.wrong_alignment <= '1'; if is_wrong_char = '1' then - if reg_known_sync_char_position = reg_octet_index then + if reg_known_sync_char_position = next_octet_index then reg_correct_sync_chars <= reg_correct_sync_chars + 1; else - reg_known_sync_char_position <= reg_octet_index; + reg_known_sync_char_position <= next_octet_index; reg_correct_sync_chars <= 1; end if; elsif is_wrong_char = '0' and (is_f = '1' or is_a = '1') then reg_correct_sync_chars <= 0; reg_state <= ALIGNED; elsif ci_realign = '1' then - reg_correct_sync_chars <= 0; - reg_octet_index <= (reg_octet_index + ((ci_F - 1) - reg_known_sync_char_position)) mod ci_F; - do_char.octet_index <= (reg_octet_index + ((ci_F - 1) - reg_known_sync_char_position)) mod ci_F; - - reg_frame_index <= reg_frame_index + 1; - do_char.frame_index <= reg_frame_index + 1; + -- align to last known sync char position + buffer_align_to <= reg_known_sync_char_position; reg_state <= ALIGNED; end if; end if; - end if; -- in RECEIVED_K + end if; end if; -- clk, reset end process set_next; - is_wrong_char <= (is_f and not next_is_last_octet) or (is_a and not (next_is_last_octet and next_is_last_frame)); - next_char.kout <= di_char.kout when is_f = '0' and is_a = '0' else '0'; - next_char.d8b <= di_char.d8b when is_f = '0' and is_a = '0' else - reg_last_frame_data when ci_scrambled = '0' else + co_correct_sync_chars <= reg_correct_sync_chars; + buffer_raw_adjust_position <= (buffer_align_to + 1 - buffer_read_position) mod F; + buffer_adjust_position <= buffer_raw_adjust_position when buffer_raw_adjust_position < F/2 + 1 + else buffer_raw_adjust_position - F; + + is_wrong_char <= (is_f and not next_is_last_octet) or (is_a and not next_is_last_octet); + buffer_character <= di_char.d8b when is_f = '0' and is_a = '0' else + reg_last_frame_data when SCRAMBLED else F_replace_data when is_f = '1' else A_replace_data; - next_char.disparity_error <= di_char.disparity_error; - next_char.missing_error <= di_char.missing_error; - next_char.user_data <= di_char.user_data; - next_is_last_octet <= '1' when next_octet_index = ci_F - 1 else '0'; - next_is_last_frame <= '1' when next_frame_index = ci_K - 1 else '0'; + next_octet_index <= buffer_write_position mod F; + next_is_last_octet <= '1' when F = 1 or next_octet_index = F - 2 else '0'; is_f <= '1' when di_char.d8b = F_char and di_char.kout = '1' else '0'; is_a <= '1' when di_char.d8b = A_char and di_char.kout = '1' else '0'; - next_frame_index <= reg_frame_index when reg_octet_index < (ci_F - 1) else - (reg_frame_index + 1) mod ci_K; - next_octet_index <= (reg_octet_index + 1) mod ci_F; - - co_correct_sync_chars <= reg_correct_sync_chars; co_error <= '1' when reg_state = MISALIGNED else '0'; co_aligned <= '1' when reg_state = ALIGNED else '0'; end architecture a1; -- 2.48.1