~ruther/jesd204b-vhdl

ce19c85c740b00215122da8c2311b31421204db6 — František Boháček 2 years ago 3e9599e feat/link-channel-width
feat: partially implement channel widths
M src/data_link/char_alignment.vhd => src/data_link/char_alignment.vhd +35 -34
@@ 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;

M src/data_link/data_link_layer.vhd => src/data_link/data_link_layer.vhd +43 -30
@@ 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,

M src/data_link/data_link_pkg.vhd => src/data_link/data_link_pkg.vhd +1 -12
@@ 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

M src/data_link/frame_alignment.vhd => src/data_link/frame_alignment.vhd +21 -18
@@ 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

M src/data_link/ilas_parser.vhd => src/data_link/ilas_parser.vhd +9 -5
@@ 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';

M src/data_link/lane_alignment.vhd => src/data_link/lane_alignment.vhd +33 -18
@@ 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;

M src/data_link/link_controller.vhd => src/data_link/link_controller.vhd +53 -28
@@ 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;

M src/data_link/ring_buffer.vhd => src/data_link/ring_buffer.vhd +3 -2
@@ 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;

M testbench/data_link/char_alignment_tb.vhd => testbench/data_link/char_alignment_tb.vhd +9 -9
@@ 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;

Do not follow this link