~ruther/jesd204b-vhdl

cec550fc53f85eb3d1a28270168e4ee4e94d6a1f — Rutherther 2 years ago 87f51b4 + 06ed055
Merge pull request #14 from Rutherther/feat/add-frame-clock

Add frame clock handling
M src/data_link/frame_alignment.vhd => src/data_link/frame_alignment.vhd +96 -74
@@ 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,51 @@ 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;
  signal next_adjusted_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');
      buffer_align_to <= -1;
    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 127,76 @@ 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 + buffer_read_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 not 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_adjusted_octet_index <= (buffer_write_position - buffer_read_position - buffer_adjust_position) mod F;
  next_octet_index <= (buffer_write_position - buffer_read_position) mod F;
  next_is_last_octet <= '1' when next_adjusted_octet_index = F - 1 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;

A src/data_link/ring_buffer.vhd => src/data_link/ring_buffer.vhd +78 -0
@@ 0,0 1,78 @@
library ieee;
use work.data_link_pkg.all;
use ieee.std_logic_1164.all;

entity ring_buffer is

  generic (
    CHARACTER_SIZE : integer := 8;
    BUFFER_SIZE : integer;
    READ_SIZE : integer);      -- The size of the buffer

  port (
    ci_clk             : in  std_logic;   -- The clock
    ci_reset           : in  std_logic;   -- The reset (active low)
    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
    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
                                        -- the buffer
    co_write_position  : out integer;   -- The current write position
                                        -- next character will be written to
    co_filled          : out std_logic);  -- Whether the buffer is full

end entity ring_buffer;

architecture a1 of ring_buffer is
    signal buff : std_logic_vector(CHARACTER_SIZE*BUFFER_SIZE-1 downto 0);
    signal buff_triple : std_logic_vector(3*CHARACTER_SIZE*BUFFER_SIZE-1 downto 0);
    signal next_read : std_logic_vector(CHARACTER_SIZE*BUFFER_SIZE-1 downto 0);
    signal read_position : integer := 0;
    signal adjusted_read_position : integer := 0;
    signal write_position : integer := 0;
    signal reg_size : integer := 0;
    signal size : integer := 0;
begin  -- architecture a1
    -- purpose: Adjust read position and read next character
    -- type   : sequential
    -- inputs : ci_clk, ci_reset
    -- outputs: read_position, write_position, buff
    read: process (ci_clk, ci_reset) is
    begin  -- process read
        if ci_reset = '0' then          -- asynchronous reset (active low)
            buff <= (others => '0');
            read_position <= 0;
            write_position <= 0;
            reg_size <= 0;
            co_read_position <= 0;
        elsif ci_clk'event and ci_clk = '1' then  -- rising clock edge
            if ci_read = '1' and size >= READ_SIZE + ci_adjust_position then
                read_position <= (read_position + ci_adjust_position + READ_SIZE) mod BUFFER_SIZE;
                co_read_position <= read_position + ci_adjust_position;
                reg_size <= size - READ_SIZE - ci_adjust_position + 1;
                co_read <= buff_triple(2*CHARACTER_SIZE*BUFFER_SIZE - 1 - (read_position + ci_adjust_position)*CHARACTER_SIZE downto 2*CHARACTER_SIZE*BUFFER_SIZE - (read_position + ci_adjust_position + READ_SIZE)*CHARACTER_SIZE);
            else
                reg_size <= reg_size + 1;
            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;
            write_position <= (write_position + 1) mod BUFFER_SIZE;
        end if;
    end process read;

    co_write_position <= write_position;
    co_size <= size;
    size <= BUFFER_SIZE when reg_size > BUFFER_SIZE else
               reg_size;
    buff_triple(3*CHARACTER_SIZE*BUFFER_SIZE - 1 downto 2*CHARACTER_SIZE*BUFFER_SIZE) <= buff;
    buff_triple(2*CHARACTER_SIZE*BUFFER_SIZE - 1 downto CHARACTER_SIZE*BUFFER_SIZE) <= buff;
    buff_triple(CHARACTER_SIZE*BUFFER_SIZE - 1 downto 0) <= buff;

    co_filled <=  '1' when reg_size > BUFFER_SIZE else
                  '0';

end architecture a1;

M src/transport/octets_to_sample.vhd => src/transport/octets_to_sample.vhd +64 -58
@@ 16,23 16,23 @@ use work.transport_pkg.all;
entity octets_to_samples is
  generic (
    CS : integer := 1;                  -- Number of control bits per sample
    M : integer := 1;                   -- Number of converters
    S : integer := 1;                   -- Number of samples
    L : integer := 1;                   -- Number of lanes
    F : integer := 2;                  -- Number of octets in a frame
    M  : integer := 1;                  -- Number of converters
    S  : integer := 1;                  -- Number of samples
    L  : integer := 1;                  -- Number of lanes
    F  : integer := 2;                  -- Number of octets in a frame
    CF : integer := 0;                  -- Number of control words
    N : integer := 12;                  -- Size of a sample
    Nn : integer := 16);                 -- Size of a word (sample + ctrl if CF
    N  : integer := 12;                 -- Size of a sample
    Nn : integer := 16);                -- Size of a word (sample + ctrl if CF
                                        -- =0
  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)
    di_lanes_data : in frame_character_array(0 to L-1);  -- Data from the lanes
                                        -- bits
    co_correct_data : out std_logic;    -- Whether output is correct
    do_samples_data : out samples_array(0 to M - 1, 0 to S - 1));  -- The
                                                                   -- output samples
    ci_frame_clk    : in  std_logic;    -- Frame clock
    ci_reset        : in  std_logic;    -- Reset (asynchronous, active low)
    di_lanes_data   : in  lane_character_array(0 to L-1)(F*8-1 downto 0);  -- Data from the lanes
                                                                     -- bits
    ci_frame_states  : in frame_state_array(0 to L-1);
    co_frame_state  : out frame_state;
    do_samples_data : out samples_array(0 to M - 1, 0 to S - 1));    -- The
                                        -- output samples
end entity octets_to_samples;

architecture a1 of octets_to_samples is


@@ 45,62 45,68 @@ architecture a1 of octets_to_samples is
  signal next_samples_data : samples_array
  (0 to M - 1, 0 to S - 1)
    (data(N - 1 downto 0), ctrl_bits(CS - 1 downto 0));

  signal reg_all_user_data : std_logic;  -- if '0', set correct_data to '0'.
  signal next_correct_data : std_logic;  -- if '0', set correct_data to '0'.
  signal reg_error         : std_logic;  -- if err, repeat last samples.
  signal new_frame         : std_logic;  -- Whether current frame is new frame
  signal current_frame_state : frame_state;

  signal reg_buffered_data : std_logic_vector(L*F*8-1 downto 0) := (others => '0');
  signal current_buffered_data : std_logic_vector(L*F*8-1 downto 0) := (others => '0');
  signal buffered_data : std_logic_vector(L*F*8-1 downto 0) := (others => '0');
  signal reg_state_user_data : std_logic_vector(L-1 downto 0);
  signal reg_state_invalid_character : std_logic_vector(L-1 downto 0);
  signal reg_state_not_enough_data : std_logic_vector(L-1 downto 0);
  signal reg_state_ring_buffer_overflow : std_logic_vector(L-1 downto 0);
  signal reg_state_disparity_error : std_logic_vector(L-1 downto 0);
  signal reg_state_not_in_table_error : std_logic_vector(L-1 downto 0);
  signal reg_state_wrong_alignment : std_logic_vector(L-1 downto 0);
  signal reg_state_last_frame_repeated : std_logic_vector(L-1 downto 0);

  signal any_error : std_logic := '0';

  constant all_ones : std_logic_vector(L-1 downto 0) := (others => '1');
  constant all_zeros : std_logic_vector(L-1 downto 0) := (others => '0');
begin  -- architecture a
  set_data: process (ci_char_clk, ci_reset) is
  set_data: process (ci_frame_clk, ci_reset) is
  begin  -- process set_data
    if ci_reset = '0' then              -- asynchronous reset (active low)
      co_correct_data <= '0';
      reg_all_user_data <= '1';
      reg_error <= '0';
      reg_buffered_data <= (others => '0');
      next_correct_data <= '0';
    elsif ci_char_clk'event and ci_char_clk = '1' then  -- rising clock edge
      if di_lanes_data(0).octet_index = 0 then
        reg_all_user_data <= '1';
      end if;
    elsif ci_frame_clk'event and ci_frame_clk = '1' then  -- rising clock edge
      do_samples_data <= next_samples_data;
      co_correct_data <= next_correct_data;
      if new_frame = '1' then
        if reg_error = '1' then
          next_samples_data <= prev_samples_data;
        else
          next_samples_data <= samples_data;
          prev_samples_data <= samples_data;
        end if;
      co_frame_state <= current_frame_state;

        reg_buffered_data <= (others => '0');
        next_correct_data <= reg_all_user_data;
        reg_all_user_data <= '1';
        reg_error <= '0';
      else
        for i in 0 to L-1 loop
          reg_buffered_data(L*F*8 - 1 - i*F*8 - 8*di_lanes_data(i).octet_index downto L*F*8 - 1 - i*F*8 - 8*di_lanes_data(i).octet_index - 7) <= di_lanes_data(i).d8b;

          if di_lanes_data(i).user_data = '0' or di_lanes_data(i).disparity_error = '1' or di_lanes_data(i).missing_error = '1' then
            reg_all_user_data <= '0';
          end if;
        end loop;  -- i
      if any_error = '0' then
        prev_samples_data <= samples_data;
      end if;

      for i in 0 to L-1 loop
        reg_buffered_data(L*F*8 - 1 - i*F*8 downto L*F*8 - (i + 1)*F*8) <= di_lanes_data(i);
        reg_state_user_data(i) <= ci_frame_states(i).user_data;
        reg_state_invalid_character(i) <= ci_frame_states(i).invalid_characters;
        reg_state_not_enough_data(i) <= ci_frame_states(i).not_enough_data;
        reg_state_ring_buffer_overflow(i) <= ci_frame_states(i).ring_buffer_overflow;
        reg_state_disparity_error(i) <= ci_frame_states(i).disparity_error;
        reg_state_not_in_table_error(i) <= ci_frame_states(i).not_in_table_error;
        reg_state_wrong_alignment(i) <= ci_frame_states(i).wrong_alignment;
        reg_state_last_frame_repeated(i) <= ci_frame_states(i).last_frame_repeated;
      end loop;  -- i
    end if;
  end process set_data;

  new_frame <= '1' when di_lanes_data(0).octet_index = F - 1 else '0';

  last_octet_data: for i in 0 to L-1 generate
    current_buffered_data(L*F*8 - 1 - i*F*8 - (F - 1)*8 downto L*F*8 - 1 - i*F*8 - (F - 1)*8 - 7) <= di_lanes_data(i).d8b;
  end generate last_octet_data;
  -- set output error in case any lane has an error
  current_frame_state.user_data <= '1' when reg_state_user_data = all_ones else '0';
  current_frame_state.invalid_characters <= '0' when reg_state_invalid_character = all_zeros else '1';
  current_frame_state.not_enough_data <= '0' when reg_state_not_enough_data = all_zeros else '1';
  current_frame_state.ring_buffer_overflow <= '0' when reg_state_ring_buffer_overflow = all_zeros else '1';
  current_frame_state.disparity_error <= '0' when reg_state_disparity_error = all_zeros else '1';
  current_frame_state.not_in_table_error <= '0' when reg_state_not_in_table_error = all_zeros else '1';
  current_frame_state.wrong_alignment <= '0' when reg_state_wrong_alignment = all_zeros else '1';
  current_frame_state.last_frame_repeated <= '1' when any_error = '1' else '0';

  buffered_data <= current_buffered_data or reg_buffered_data;
  any_error <= '1' when current_frame_state.invalid_characters = '1' or
               current_frame_state.not_enough_data = '1' or
               current_frame_state.ring_buffer_overflow = '1' or
               current_frame_state.disparity_error = '1' or
               current_frame_state.not_in_table_error = '1' or
               current_frame_state.wrong_alignment = '1' else '0';
  next_samples_data <= samples_data when any_error = '0' else prev_samples_data;

  -- for one or multiple lanes if CF = 0
  -- (no control words)


@@ 108,10 114,10 @@ begin  -- architecture a
  multi_lane_no_cf: if CF = 0 generate
    converters: for ci in 0 to M - 1 generate
      samples: for si in 0 to S - 1 generate
        samples_data(ci, si).data <= buffered_data(L*F*8 - 1 - ci*Nn*S - si*Nn downto L*F*8 - 1 - ci*Nn*S - si*Nn - N + 1);
        samples_data(ci, si).data <= reg_buffered_data(L*F*8 - 1 - ci*Nn*S - si*Nn downto L*F*8 - 1 - ci*Nn*S - si*Nn - N + 1);

        control_bits: if CS > 0 generate
          samples_data(ci, si).ctrl_bits <= buffered_data(L*F*8 - 1 - ci*Nn*S - si*Nn - N downto L*F*8 - 1 - ci*Nn*S - si*Nn - N - CS + 1);
          samples_data(ci, si).ctrl_bits <= reg_buffered_data(L*F*8 - 1 - ci*Nn*S - si*Nn - N downto L*F*8 - 1 - ci*Nn*S - si*Nn - N - CS + 1);
        end generate control_bits;
      end generate samples;
    end generate converters;


@@ 123,10 129,10 @@ begin  -- architecture a
    cf_groups: for cfi in 0 to CF-1 generate
      converters: for ci in 0 to M/CF-1 generate
        samples: for si in 0 to S - 1 generate
          samples_data(ci + cfi*M/CF, si).data <= buffered_data(L*F*8 - 1 - cfi*F*8*L/CF - ci*Nn*S - si*Nn downto L*F*8 - 1 - cfi*F*8*L/CF - ci*Nn*S - si*Nn - N + 1);
          samples_data(ci + cfi*M/CF, si).data <= reg_buffered_data(L*F*8 - 1 - cfi*F*8*L/CF - ci*Nn*S - si*Nn downto L*F*8 - 1 - cfi*F*8*L/CF - ci*Nn*S - si*Nn - N + 1);

          control_bits: if CS > 0 generate
            samples_data(ci + cfi*M/CF, si).ctrl_bits <= buffered_data(L*F*8 - 1 - cfi*F*8*L/CF - (M/CF)*S*Nn - ci*S*CS - si*CS downto L*F*8 - 1 - cfi*F*8*L/CF - (M/CF)*Nn*S - ci*S*CS - si*CS - CS + 1);
            samples_data(ci + cfi*M/CF, si).ctrl_bits <= reg_buffered_data(L*F*8 - 1 - cfi*F*8*L/CF - (M/CF)*S*Nn - ci*S*CS - si*CS downto L*F*8 - 1 - cfi*F*8*L/CF - (M/CF)*Nn*S - ci*S*CS - si*CS - CS + 1);
          end generate control_bits;
        end generate samples;
      end generate converters;

M src/transport/transport_layer.vhd => src/transport/transport_layer.vhd +6 -8
@@ 27,13 27,10 @@ entity transport_layer is
    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)
    di_lanes_data : in frame_character_array(0 to L - 1);  -- Data from the lanes

    co_correct_data : out std_logic;    -- Whether the current data are correct
                                        -- user data
    do_samples_data : out samples_array(0 to M - 1, 0 to S - 1));  -- Samples
                                                                   -- in the
                                                                   -- given frame
    ci_frame_states  : in frame_state_array(0 to L-1);
    co_frame_state  : out frame_state;
    do_samples_data : out samples_array(0 to M - 1, 0 to S - 1));    -- The
                                        -- output samples
end entity transport_layer;

architecture a1 of transport_layer is


@@ 54,8 51,9 @@ begin  -- architecture a1
      ci_char_clk     => ci_char_clk,
      ci_frame_clk    => ci_frame_clk,
      ci_reset        => ci_reset,
      ci_frame_states => ci_frame_states,
      di_lanes_data   => di_lanes_data,
      co_correct_data => co_correct_data,
      co_frame_state  => co_frame_staet,
      do_samples_data => do_samples_data);

end architecture a1;

M src/transport/transport_pkg.vhd => src/transport/transport_pkg.vhd +20 -1
@@ 11,8 11,27 @@ package transport_pkg is
    ctrl_bits : std_logic_vector;
  end record sample;

  type frame_state is record           -- An errors passed from data_link to transport
    user_data            : std_logic;   -- All characters are user_data
    invalid_characters   : std_logic;   -- Any of the charachers should not be
                                        -- there (ie. there is a control)
    not_enough_data      : std_logic;   -- There is not enough data in the
                                        -- buffer, data will be sent on next
                                        -- frame clock
    ring_buffer_overflow : std_logic;   -- Buffer storing characters has overflowed,
                                        -- meaning frame clock is too slow
    disparity_error      : std_logic;   -- Any character had disparity error
    not_in_table_error   : std_logic;   -- Any character not in table
    wrong_alignment      : std_logic;   -- Alignment character was detected to
                                        -- be on wrong position, possible misalignment
    last_frame_repeated  : std_logic;   -- Whether last frame was repeated
                                        -- instead of new frame
  end record frame_state;

  type frame_state_array is array (natural range <>) of frame_state;

  -- Array of frame characters (characters in one frame)
  type frame_character_array is array (natural range <>) of frame_character;
  type lane_character_array is array (natural range <>) of std_logic_vector;

  -- Array of samples in one frame by converter and by sample (used with oversampling)
  type samples_array is array (natural range <>, natural range <>) of sample;

M testbench/data_link/frame_alignment_tb.vhd => testbench/data_link/frame_alignment_tb.vhd +72 -60
@@ 2,18 2,20 @@ library ieee;
use ieee.std_logic_1164.all;
use work.testing_functions.all;
use work.data_link_pkg.all;
use work.transport_pkg.all;

entity frame_alignment_tb is
end entity frame_alignment_tb;

architecture a1 of frame_alignment_tb is
  constant F : integer range 0 to 256 := 5;
  constant K : integer range 0 to 32 := 4;

  type test_vector is record
    ci_request_sync : std_logic;
    ci_scrambled : std_logic;
    ci_realign : std_logic;
    di_char : character_vector;

    expected_char : frame_character;
    expected_aligned : std_logic;
    expected_error : std_logic;



@@ 23,55 25,58 @@ architecture a1 of frame_alignment_tb is
  constant test_vectors : test_vector_array :=
  (
  -- rq  scra real  kout  der mer   data   expec kout  der  mer  data       aler oct fram
    ('0', '0', '0', ('1', '0', '0', "10111100", '0'), ('1', '0', '0', "10111100", 0, 0, '0'), '0', '0'),
    ('0', '0', '0', ('0', '0', '0', "00000000", '0'), ('0', '0', '0', "00000000", 0, 0, '0'), '1', '0'),
    ('0', '0', '0', ('0', '0', '0', "10101010", '0'), ('0', '0', '0', "10101010", 1, 0, '0'), '1', '0'),
    ('0', '0', '0', ('0', '0', '0', "01010101", '0'), ('0', '0', '0', "01010101", 2, 0, '0'), '1', '0'),
    ('0', '0', '0', ('0', '0', '0', "01010101", '0'), ('0', '0', '0', "01010101", 3, 0, '0'), '1', '0'),
    ('0', '0', '0', ('0', '0', '0', "01010101", '0'), ('0', '0', '0', "01010101", 4, 0, '0'), '1', '0'),
    ('0', '0', '0', ('0', '0', '0', "11111111", '0'), ('0', '0', '0', "11111111", 0, 1, '0'), '1', '0'),
    ('0', '0', '0', ('0', '0', '0', "11111111", '0'), ('0', '0', '0', "11111111", 1, 1, '0'), '1', '0'),
    ('0', '0', '0', ('0', '0', '0', "11111111", '0'), ('0', '0', '0', "11111111", 2, 1, '0'), '1', '0'),
    ('0', '0', '0', ('0', '0', '0', "11111111", '0'), ('0', '0', '0', "11111111", 3, 1, '0'), '1', '0'),
    ('0', '0', '0', ('1', '0', '0', "11111100", '0'), ('0', '0', '0', "01010101", 4, 1, '0'), '1', '0'),
    ('0', '0', '0', ('1', '0', '0', "11111100", '0'), ('0', '0', '0', "01010101", 0, 2, '0'), '0', '1'),
    ('0', '0', '0', ('1', '0', '0', "11111100", '0'), ('0', '0', '0', "01010101", 1, 2, '0'), '0', '1'),
    ('0', '0', '0', ('0', '0', '0', "11110000", '0'), ('0', '0', '0', "11110000", 2, 2, '0'), '0', '1'),
    ('0', '0', '0', ('0', '0', '0', "11110000", '0'), ('0', '0', '0', "11110000", 3, 2, '0'), '0', '1'),
    ('0', '0', '0', ('1', '0', '0', "11111100", '0'), ('0', '0', '0', "01010101", 4, 2, '0'), '1', '0'),
    ('1', '1', '1', ('0', '0', '0', "11111100", '0'), ('0', '0', '0', "11111100", 0, 0, '0'), '0', '0'),
    ('0', '1', '1', ('1', '0', '0', "10111100", '0'), ('1', '0', '0', "10111100", 0, 0, '0'), '0', '0'),
    ('0', '1', '1', ('0', '0', '0', "00000000", '0'), ('0', '0', '0', "00000000", 0, 0, '0'), '1', '0'),
    ('0', '1', '1', ('0', '0', '0', "00000000", '0'), ('0', '0', '0', "00000000", 1, 0, '0'), '1', '0'),
    ('0', '1', '1', ('0', '0', '0', "00000000", '0'), ('0', '0', '0', "00000000", 2, 0, '0'), '1', '0'),
    ('0', '1', '1', ('0', '0', '0', "00000000", '0'), ('0', '0', '0', "00000000", 3, 0, '0'), '1', '0'),
    ('0', '1', '1', ('0', '0', '0', "00000000", '0'), ('0', '0', '0', "00000000", 4, 0, '0'), '1', '0'),
    ('0', '1', '1', ('0', '0', '0', "00000000", '0'), ('0', '0', '0', "00000000", 0, 1, '0'), '1', '0'),
    ('0', '1', '1', ('0', '0', '0', "00000000", '0'), ('0', '0', '0', "00000000", 1, 1, '0'), '1', '0'),
    ('0', '1', '1', ('0', '0', '0', "00000000", '0'), ('0', '0', '0', "00000000", 2, 1, '0'), '1', '0'),
    ('0', '1', '1', ('0', '0', '0', "00000000", '0'), ('0', '0', '0', "00000000", 3, 1, '0'), '1', '0'),
    ('0', '1', '1', ('1', '0', '0', "11111100", '0'), ('0', '0', '0', "11111100", 4, 1, '0'), '1', '0'),
    ('0', '1', '1', ('1', '0', '0', "01111100", '0'), ('0', '0', '0', "01111100", 0, 2, '0'), '0', '1'),
    ('0', '1', '1', ('0', '0', '0', "01111100", '0'), ('0', '0', '0', "01111100", 0, 3, '0'), '1', '0'),
    ('0', '1', '1', ('0', '0', '0', "11111111", '0'), ('0', '0', '0', "11111111", 1, 3, '0'), '1', '0'),
    ('0', '1', '1', ('0', '0', '0', "11111111", '0'), ('0', '0', '0', "11111111", 2, 3, '0'), '1', '0'),
    ('0', '1', '1', ('0', '0', '0', "11111111", '0'), ('0', '0', '0', "11111111", 3, 3, '0'), '1', '0')
    ('1', '0', ('1', '0', '0', "10111100", '0'), '0', '0'),
    ('1', '0', ('1', '0', '0', "10111100", '0'), '0', '0'),
    ('0', '0', ('1', '0', '0', "10111100", '0'), '0', '0'),
    ('0', '0', ('1', '0', '0', "10111100", '0'), '0', '0'),
    ('0', '0', ('0', '0', '0', "11000001", '1'), '0', '0'),  -- frame begins
    ('0', '0', ('0', '0', '0', "11000010", '1'), '0', '0'),
    ('0', '0', ('0', '0', '0', "11000011", '1'), '0', '0'),
    ('0', '0', ('0', '0', '0', "11000100", '1'), '0', '0'),
    ('0', '0', ('1', '0', '0', "11111100", '1'), '0', '0'),  -- frame ends
    ('0', '0', ('0', '0', '0', "00000001", '1'), '1', '0'),
    ('0', '0', ('1', '0', '0', "00000010", '1'), '1', '0'),
    ('0', '0', ('0', '0', '0', "00000011", '1'), '1', '0'),
    ('0', '0', ('0', '0', '0', "00000100", '1'), '1', '0'),
    ('0', '0', ('0', '0', '0', "00000000", '1'), '1', '0'),  -- frame ends
    ('0', '0', ('1', '0', '0', "11111100", '1'), '0', '1'),  -- frame begins, /A/
    ('0', '0', ('1', '0', '0', "11111100", '1'), '0', '1'),  -- frame begins, /A/
    ('0', '0', ('0', '0', '0', "01000001", '1'), '0', '1'),
    ('0', '0', ('0', '0', '0', "01000010", '1'), '0', '1'),
    ('0', '0', ('0', '0', '0', "01000011", '1'), '0', '1'),
    ('0', '0', ('0', '0', '0', "01000100", '1'), '0', '1'),
    ('0', '0', ('1', '0', '0', "11111100", '1'), '0', '1'),
    ('0', '1', ('0', '0', '0', "00100001", '1'), '1', '0'),
    ('0', '0', ('0', '0', '0', "00100010", '1'), '1', '0'),
    ('0', '0', ('0', '0', '0', "00100011", '1'), '1', '0'),
    ('0', '0', ('0', '0', '0', "00100100", '1'), '1', '0'),
    ('0', '0', ('0', '0', '0', "10000101", '1'), '1', '0'),
    ('0', '0', ('0', '0', '0', "01000001", '1'), '1', '0'), -- frame begins
    ('0', '0', ('0', '0', '0', "01000010", '1'), '1', '0'),
    ('0', '0', ('0', '0', '0', "01000011", '1'), '1', '0'),
    ('0', '0', ('0', '0', '0', "01000100", '1'), '1', '0'),
    ('0', '0', ('0', '0', '0', "01000101", '1'), '1', '0'),
    ('0', '0', ('0', '0', '0', "00100001", '1'), '1', '0'),
    ('0', '0', ('0', '0', '0', "00100010", '1'), '1', '0'),
    ('0', '0', ('0', '0', '0', "00100011", '1'), '1', '0'),
    ('0', '0', ('0', '0', '0', "00100100", '1'), '1', '0'),
    ('0', '0', ('1', '0', '0', "11111100", '1'), '1', '0'),
    ('0', '0', ('0', '0', '0', "00000000", '1'), '1', '0')
  );

  constant clk_period : time := 1 ns;

  constant F : integer range 0 to 256 := 5;
  constant K : integer range 0 to 32 := 4;
  constant char_clk_period : time := 1 ns;
  constant frame_clk_period : time := 1 ns * F;

  signal clk : std_logic := '0';
  signal char_clk : std_logic := '0';
  signal frame_clk : std_logic := '0';
  signal reset : std_logic := '0';

  signal di_char : character_vector;
  signal do_char : frame_character;
  signal do_aligned_chars : std_logic_vector(8*F - 1 downto 0);
  signal co_frame_state : frame_state;

  signal ci_request_sync : std_logic;
  signal ci_realign : std_logic;
  signal ci_scrambled : std_logic;
  signal co_aligned : std_logic;
  signal co_error : std_logic;



@@ 79,28 84,37 @@ architecture a1 of frame_alignment_tb is

begin  -- architecture a1
  uut : entity work.frame_alignment
    generic map (
      SCRAMBLED => false,
      F         => F,
      K         => K)
    port map (
      ci_char_clk     => clk,
      ci_reset        => reset,
      ci_F            => F,
      ci_K            => K,
      ci_scrambled    => ci_scrambled,
      ci_request_sync => ci_request_sync,
      ci_realign      => ci_realign,
      di_char         => di_char,
      co_aligned      => co_aligned,
      co_error        => co_error,
      do_char         => do_char);
      ci_frame_clk     => frame_clk,
      ci_char_clk      => char_clk,
      ci_reset         => reset,
      ci_request_sync  => ci_request_sync,
      ci_realign       => ci_realign,
      di_char          => di_char,
      co_aligned       => co_aligned,
      co_error         => co_error,
      do_aligned_chars => do_aligned_chars,
      co_frame_state   => co_frame_state);

  clk_gen: process is
  begin -- process clk_gen
    wait for clk_period/2;
	 clk <= not clk;
    wait for char_clk_period/2;
    char_clk <= not char_clk;
  end process clk_gen;

  frame_clk_gen: process is
  begin -- process clk_gen
    wait for frame_clk_period/2;
    frame_clk <= not frame_clk;
  end process frame_clk_gen;
  
  reset_gen: process is
  begin -- process reset_gen
    wait for clk_period*2;
    wait for char_clk_period*2;
    reset <= '1';
  end process reset_gen;



@@ 108,13 122,12 @@ begin  -- architecture a1
    variable test_vec : test_vector;
    variable prev_test_vec : test_vector;
  begin  -- process test
    wait for clk_period*2;
    wait for char_clk_period*2;

    for i in test_vectors'range loop
      test_data_index <= i;
      test_vec := test_vectors(i);
      di_char <= test_vec.di_char;
      ci_scrambled <= test_vec.ci_scrambled;
      ci_realign <= test_vec.ci_realign;
      ci_request_sync <= test_vec.ci_request_sync;



@@ 123,10 136,9 @@ begin  -- architecture a1

        assert co_aligned = prev_test_vec.expected_aligned report "The aligned does not match. Expected: " & std_logic'image(prev_test_vec.expected_aligned) &", Index: " & integer'image(i-1) severity error;
        assert co_error = prev_test_vec.expected_error report "The error does not match. Index: " & integer'image(i-1) severity error;
        assert do_char = prev_test_vec.expected_char report "The character does not match. Index: " & integer'image(i-1) severity error;
      end if;

      wait for clk_period;
      wait for char_clk_period;
    end loop;  -- i
    wait for 100 ms;
  end process test;

A testbench/data_link/ring_buffer_tb.vhd => testbench/data_link/ring_buffer_tb.vhd +99 -0
@@ 0,0 1,99 @@
library ieee;
use ieee.std_logic_1164.all;
use work.testing_functions.all;
use work.data_link_pkg.all;

entity ring_buffer_tb is

end entity ring_buffer_tb;

architecture a1 of ring_buffer_tb is
  type test_vector is record
    di_character : std_logic_vector(7 downto 0);
    ci_read      : std_logic;
    ci_adjust_position      : integer;
  end record test_vector;

  type test_vector_array is array (natural range <>) of test_vector;

  constant test_vectors : test_vector_array :=
  (
      ("00000000", '0', 0),
      ("00000001", '0', 0),
      ("00000010", '0', 0),
      ("00000011", '0', 0),
      ("00000100", '0', 0),
      ("11111111", '0', 0),
      ("00000110", '0', 0),
      ("00000111", '1', 2),
      ("00001000", '0', 0),
      ("00001001", '0', 0),
      ("11111111", '0', 0),
      ("00000001", '0', 0),
      ("00000010", '1', 0),
      ("00000011", '0', 0),
      ("00000100", '0', 0),
      ("11111111", '0', 0),
      ("00000000", '0', 0),
      ("00000000", '1', 0),
      ("01000000", '0', 0),
      ("01000000", '0', 0),
      ("11111111", '0', 0),
      ("01000000", '0', 0),
      ("01000000", '0', 0),
      ("01000000", '0', 0),
      ("01000000", '0', 0),
      ("11111111", '1', 0),
      ("01000000", '0', 0),
      ("01000000", '1', 0),
      ("01000000", '0', 0)
  );
  signal F : integer := 5;

  constant clk_period : time := 1 ns;
  signal clk : std_logic := '0';
  signal reset : std_logic := '0';
  signal ci_read : std_logic;
  signal ci_adjust_position : integer;
  signal di_character : std_logic_vector(7 downto 0);
  signal co_read : std_logic_vector(F*8-1 downto 0);
  signal co_size : integer;
  signal co_filled : std_logic;

  signal test_data_index : integer := 0;
begin  -- architecture a1
  uut : entity work.ring_buffer
    generic map (
      READ_SIZE   => F,
      BUFFER_SIZE => 2*F
    )
    port map (
      ci_clk             => clk,
      ci_reset           => reset,
      di_character       => di_character,
      ci_adjust_position => ci_adjust_position,
      ci_read            => ci_read,
      co_read            => co_read,
      co_size            => co_size,
      co_filled          => co_filled);

  clk <= not clk after clk_period/2;
  reset <= '1' after clk_period*2;

  test: process is
  begin  -- process test
    wait for clk_period*2;

    for i in test_vectors'range loop
      test_data_index <= i;
      di_character <= test_vectors(i).di_character;
      ci_read <= test_vectors(i).ci_read;
      ci_adjust_position <= test_vectors(i).ci_adjust_position;

      wait for clk_period;
    end loop;  -- i

    wait for 100 ms;
  end process test;

end architecture a1;

M testbench/transport/octets_to_samples_fc_tb.vhd => testbench/transport/octets_to_samples_fc_tb.vhd +25 -34
@@ 16,83 16,74 @@ architecture a1 of octets_to_samples_fc_tb is
  constant CF           : integer := 1;  -- Count of control word bits
  constant N            : integer := 4;  -- Sample size
  constant Nn           : integer := 4;
  constant CLK_PERIOD   : time    := 1 ns;
  constant CLK_PERIOD   : time    := 5 ns;

  constant DUMMY_FC : frame_character := ('1', '1', '1', "11111111", 0, 0, '1');
  constant DUMMY_S : sample := ("0000", "0");
  type test_vector is record
    di_lanes_data : frame_character_array (0 to L - 1);
    di_lanes_data : lane_character_array (0 to L - 1) (F*8-1 downto 0);
    ci_frame_states : frame_state_array (0 to L - 1);
    expected_result : integer;
  end record test_vector;

  type result_vector is record
    co_correct_data : std_logic;
    do_samples_data : samples_array (0 to M - 1, 0 to S - 1)(data(M - 1 downto 0), ctrl_bits(CONTROL_SIZE - 1 downto 0));
    co_frame_state : frame_state;
  end record result_vector;

  constant dummy_frame_state : frame_state := ('0', '0', '0', '0', '0', '0', '0', '0');

  type test_vector_array is array (natural range<>) of test_vector;
  constant test_vectors : test_vector_array :=
  (
    ((('1', '0', '0', "00000000", 0, 0, '0'), others => DUMMY_FC), -1),
    ((('1', '0', '0', "00000000", 0, 0, '0'), others => DUMMY_FC), -1),
    ((('1', '0', '0', "00000000", 0, 0, '0'), others => DUMMY_FC), -1),
    ((('1', '0', '0', "00000000", 0, 0, '0'), others => DUMMY_FC), -1),
    ((('0', '0', '0', "10111110", 0, 0, '1'), others => DUMMY_FC), -1),
    ((('0', '0', '0', "00010100", 1, 0, '1'), others => DUMMY_FC), -1),
    ((('0', '0', '0', "10100000", 2, 0, '1'), others => DUMMY_FC), -1),
    ((('0', '0', '0', "00010001", 0, 1, '1'), others => DUMMY_FC), 0),
    ((('0', '0', '0', "00010001", 1, 1, '1'), others => DUMMY_FC), 0),
    ((('0', '0', '0', "11110000", 2, 1, '1'), others => DUMMY_FC), 0),
    ((('0', '0', '0', "11101110", 0, 2, '1'), others => DUMMY_FC), 1),
    ((('0', '0', '0', "11101110", 1, 2, '1'), others => DUMMY_FC), 1),
    ((('0', '0', '0', "00000000", 2, 2, '1'), others => DUMMY_FC), 1),
    ((('0', '0', '0', "00000000", 0, 3, '1'), others => DUMMY_FC), 2),
    ((('0', '0', '0', "11100000", 1, 3, '1'), others => DUMMY_FC), 2),
    ((('0', '0', '0', "11100000", 2, 3, '1'), others => DUMMY_FC), 2)
    (("000000000000000000000000", others => (others => '0')), (('0', '0', '0', '0', '0', '0', '0', '0'), others => dummy_frame_state), -1),
    (("101111100001010010100000", others => (others => '0')), (('1', '0', '0', '0', '0', '0', '0', '0'), others => dummy_frame_state), -1),
    (("000100010001000111110000", others => (others => '0')), (('1', '0', '0', '0', '0', '0', '0', '0'), others => dummy_frame_state),  0),
    (("111011101110111000000000", others => (others => '0')), (('1', '0', '0', '0', '0', '0', '0', '0'), others => dummy_frame_state),  1),
    (("000000001110000011100000", others => (others => '0')), (('1', '0', '0', '0', '0', '0', '0', '0'), others => dummy_frame_state),  2)
  );

  type result_vector_array is array (natural range<>) of result_vector;
  constant result_vectors : result_vector_array :=
  (
    (
      '1',
      (
        (("1011", "1"), others => DUMMY_S),
        (("1110", "0"), others => DUMMY_S),
        (("0001", "1"), others => DUMMY_S),
        (("0100", "0"), others => DUMMY_S)
      )
      ),
      ('1', '0', '0', '0', '0', '0', '0', '0')
    ),
    (
      '1',
      (
        (("0001", "1"), others => DUMMY_S),
        (("0001", "1"), others => DUMMY_S),
        (("0001", "1"), others => DUMMY_S),
        (("0001", "1"), others => DUMMY_S)
        )
      ),
      ('1', '0', '0', '0', '0', '0', '0', '0')
    ),
    (
      '1',
      (
        (("1110", "0"), others => DUMMY_S),
        (("1110", "0"), others => DUMMY_S),
        (("1110", "0"), others => DUMMY_S),
        (("1110", "0"), others => DUMMY_S)
      )
      ),
      ('1', '0', '0', '0', '0', '0', '0', '0')
    )
  );

  signal ci_char_clk : std_logic := '0';
  signal ci_frame_clk : std_logic := '0';
  signal ci_reset : std_logic := '0';

  signal di_lanes_data : frame_character_array(0 to L - 1);
  signal di_lanes_data : lane_character_array (0 to L - 1)(F*8-1 downto 0);
  signal ci_frame_states : frame_state_array (0 to L - 1);

  signal do_samples_data : samples_array
    (0 to M - 1, 0 to S - 1)
    (data(N - 1 downto 0), ctrl_bits(CONTROL_SIZE - 1 downto 0));
  signal co_correct_data : std_logic;
  signal co_frame_state : frame_state;

  signal test_data_index : integer := 0;
begin  -- architecture a1


@@ 107,14 98,14 @@ begin  -- architecture a1
      N  => N,
      Nn => Nn)
    port map (
      ci_char_clk     => ci_char_clk,
      ci_reset        => ci_reset,
      ci_frame_clk    => ci_frame_clk,
      di_lanes_data   => di_lanes_data,
      co_correct_data => co_correct_data,
      ci_frame_states => ci_frame_states,
      co_frame_state => co_frame_state,
      do_samples_data => do_samples_data);

  ci_char_clk <= not ci_char_clk after CLK_PERIOD/2;
  ci_frame_clk <= not ci_frame_clk after CLK_PERIOD/2;
  ci_reset <= '1' after CLK_PERIOD*2;

  test: process is


@@ 128,13 119,13 @@ begin  -- architecture a1
      test_data_index <= i;
      test_vec := test_vectors(i);
      di_lanes_data <= test_vec.di_lanes_data;
      ci_frame_states <= test_vec.ci_frame_states;

      if i > 0 then
        prev_test_vec := test_vectors(i - 1);

        if prev_test_vec.expected_result /= -1 then
          assert co_correct_data = result_vectors(prev_test_vec.expected_result).co_correct_data report "The correct data does not match, Index: " & integer'image(i-1) severity error;

          assert co_frame_state = result_vectors(prev_test_vec.expected_result).co_frame_state report "The frame state does not match, index: " & integer'image(prev_test_vec.expected_result) severity error;
          for ci in 0 to M - 1 loop
            for si in 0 to S - 1 loop
              assert do_samples_data(ci, si).data = result_vectors(prev_test_vec.expected_result).do_samples_data(ci, si).data report "The samples data do not match, expected: " & vec2str(result_vectors(prev_test_vec.expected_result).do_samples_data(ci, si).data) & ", got: " & vec2str(dummy) & ", index: " & integer'image(i-1) & ", ci: " & integer'image(ci) & ", si: " & integer'image(si) severity error;

M testbench/transport/octets_to_samples_multi_cf_tb.vhd => testbench/transport/octets_to_samples_multi_cf_tb.vhd +23 -33
@@ 18,83 18,73 @@ architecture a1 of octets_to_samples_multi_fc_tb is
  constant Nn           : integer := 4;
  constant CLK_PERIOD   : time    := 1 ns;

  constant DUMMY_FC : frame_character := ('1', '1', '1', "11111111", 0, 0, '1');
  constant DUMMY_S : sample := ("0000", "0");
  type test_vector is record
    di_lanes_data : frame_character_array (0 to L - 1);
    di_lanes_data : lane_character_array (0 to L - 1) (F*8-1 downto 0);
    ci_frame_states : frame_state_array (0 to L - 1);
    expected_result : integer;
  end record test_vector;

  type result_vector is record
    co_correct_data : std_logic;
    do_samples_data : samples_array (0 to M - 1, 0 to S - 1)(data(M - 1 downto 0), ctrl_bits(CONTROL_SIZE - 1 downto 0));
    co_frame_state : frame_state;
  end record result_vector;

  type test_vector_array is array (natural range<>) of test_vector;
  constant test_vectors : test_vector_array :=
  (
    ((('1', '0', '0', "00000000", 0, 0, '0'), ('1', '0', '0', "00000000", 0, 0, '0')), -1),
    ((('1', '0', '0', "00000000", 0, 0, '0'), ('1', '0', '0', "00000000", 0, 0, '0')), -1),
    ((('1', '0', '0', "00000000", 0, 0, '0'), ('1', '0', '0', "00000000", 0, 0, '0')), -1),
    ((('0', '0', '0', "00010101", 0, 0, '1'), ('0', '0', '0', "00110111", 0, 0, '1')), -1),
    ((('0', '0', '0', "00100110", 1, 0, '1'), ('0', '0', '0', "01001000", 1, 0, '1')), -1),
    ((('0', '0', '0', "01011010", 2, 0, '1'), ('0', '0', '0', "11110000", 2, 0, '1')), -1),
    ((('0', '0', '0', "00111111", 0, 1, '1'), ('0', '0', '0', "00001010", 0, 1, '1')), 0),
    ((('0', '0', '0', "11000101", 1, 1, '1'), ('0', '0', '0', "11110000", 1, 1, '1')), 0),
    ((('0', '0', '0', "00101101", 2, 1, '1'), ('0', '0', '0', "00101101", 2, 1, '1')), 0),
    ((('0', '0', '0', "00010101", 0, 1, '1'), ('0', '0', '0', "00110111", 0, 1, '1')), 1),
    ((('0', '0', '0', "00100110", 1, 1, '1'), ('0', '0', '0', "01001000", 1, 1, '1')), 1),
    ((('0', '0', '0', "01011010", 2, 1, '1'), ('0', '0', '0', "11110000", 2, 1, '1')), 1),
    ((('0', '0', '0', "00010101", 0, 1, '1'), ('0', '0', '0', "00110111", 0, 1, '1')), 2),
    ((('0', '0', '0', "00100110", 1, 1, '1'), ('0', '0', '0', "01001000", 1, 1, '1')), 2),
    ((('0', '0', '0', "01011010", 2, 1, '1'), ('0', '0', '0', "11110000", 2, 1, '1')), 2)
    (("000000000000000000000000", "000000000000000000000000"), (('0', '0', '0', '0', '0', '0', '0', '0'), ('0', '0', '0', '0', '0', '0', '0', '0')), -1),
    (("000101010010011001011010", "001101110100100011110000"), (('1', '0', '0', '0', '0', '0', '0', '0'), ('1', '0', '0', '0', '0', '0', '0', '0')), -1),
    (("001111111100010100101101", "000010101111000000101101"), (('1', '0', '0', '0', '0', '0', '0', '0'), ('1', '0', '0', '0', '0', '0', '0', '0')), 0),
    (("000101010010011001011010", "001101110100100011110000"), (('1', '0', '0', '0', '0', '0', '0', '0'), ('1', '0', '0', '0', '0', '0', '0', '0')), 1),
    (("000101010010011001011010", "001101110100100011110000"), (('1', '0', '0', '0', '0', '0', '0', '0'), ('1', '0', '0', '0', '0', '0', '0', '0')), 2)
  );

  type result_vector_array is array (natural range<>) of result_vector;
  constant result_vectors : result_vector_array :=
  (
    (
      '1',
      (
        (("0001", "01"), ("0101", "01")),
        (("0010", "10"), ("0110", "10")),
        (("0011", "11"), ("0111", "11")),
        (("0100", "00"), ("1000", "00"))
      )
      ),
      ('1', '0', '0', '0', '0', '0', '0', '0')
    ),
    (
      '1',
      (
        (("0011", "00"), ("1111", "10")),
        (("1100", "11"), ("0101", "01")),
        (("0000", "00"), ("1010", "10")),
        (("1111", "11"), ("0000", "01"))
      )
      ),
      ('1', '0', '0', '0', '0', '0', '0', '0')
    ),
    (
      '1',
      (
        (("0001", "01"), ("0101", "01")),
        (("0010", "10"), ("0110", "10")),
        (("0011", "11"), ("0111", "11")),
        (("0100", "00"), ("1000", "00"))
      )
      ),
      ('1', '0', '0', '0', '0', '0', '0', '0')
    )
  );

  signal ci_char_clk : std_logic := '0';
  signal ci_frame_clk : std_logic := '0';
  signal ci_reset : std_logic := '0';

  signal di_lanes_data : frame_character_array(0 to L - 1);
  signal di_lanes_data : lane_character_array (0 to L - 1)(F*8-1 downto 0);
  signal ci_frame_states : frame_state_array (0 to L - 1);

  signal do_samples_data : samples_array
    (0 to M - 1, 0 to S - 1)
    (data(N - 1 downto 0), ctrl_bits(CONTROL_SIZE - 1 downto 0));
  signal co_correct_data : std_logic;
  signal co_frame_state : frame_state;

  signal test_data_index : integer := 0;
begin  -- architecture a1

  uut : entity work.octets_to_samples
    generic map (
      CS => CONTROL_SIZE,


@@ 106,14 96,14 @@ begin  -- architecture a1
      N  => N,
      Nn => Nn)
    port map (
      ci_char_clk     => ci_char_clk,
      ci_reset        => ci_reset,
      ci_frame_clk    => ci_frame_clk,
      di_lanes_data   => di_lanes_data,
      co_correct_data => co_correct_data,
      ci_frame_states => ci_frame_states,
      co_frame_state => co_frame_state,
      do_samples_data => do_samples_data);

  ci_char_clk <= not ci_char_clk after CLK_PERIOD/2;
  ci_frame_clk <= not ci_frame_clk after CLK_PERIOD/2;
  ci_reset <= '1' after CLK_PERIOD*2;

  test: process is


@@ 127,13 117,13 @@ begin  -- architecture a1
      test_data_index <= i;
      test_vec := test_vectors(i);
      di_lanes_data <= test_vec.di_lanes_data;
      ci_frame_states <= test_vec.ci_frame_states;

      if i > 0 then
        prev_test_vec := test_vectors(i - 1);

        if prev_test_vec.expected_result /= -1 then
          assert co_correct_data = result_vectors(prev_test_vec.expected_result).co_correct_data report "The correct data does not match, Index: " & integer'image(i-1) severity error;

          assert co_frame_state = result_vectors(prev_test_vec.expected_result).co_frame_state report "The frame state does not match, index: " & integer'image(prev_test_vec.expected_result) severity error;
          for ci in 0 to M - 1 loop
            for si in 0 to S - 1 loop
              assert do_samples_data(ci, si).data = result_vectors(prev_test_vec.expected_result).do_samples_data(ci, si).data report "The samples data do not match, expected: " & vec2str(result_vectors(prev_test_vec.expected_result).do_samples_data(ci, si).data) & ", got: " & vec2str(dummy) & ", index: " & integer'image(i-1) & ", ci: " & integer'image(ci) & ", si: " & integer'image(si) severity error;

M testbench/transport/octets_to_samples_simp_tb.vhd => testbench/transport/octets_to_samples_simp_tb.vhd +29 -43
@@ 18,98 18,83 @@ architecture a1 of octets_to_samples_simp_tb is
  constant Nn : integer := 8;
  constant CLK_PERIOD : time := 1 ns;

  constant DUMMY_FC : frame_character := ('1', '1', '1', "11111111", 0, 0, '1');
  constant DUMMY_S : sample := ("0000", "0");
  type test_vector is record
    di_lanes_data : frame_character_array (0 to L - 1);
    di_lanes_data : lane_character_array (0 to L - 1) (F*8-1 downto 0);
    ci_frame_states : frame_state_array (0 to L - 1);
    expected_result : integer;
  end record test_vector;

  type result_vector is record
    co_correct_data : std_logic;
    do_samples_data : samples_array (0 to M - 1, 0 to S - 1)(data(M - 1 downto 0), ctrl_bits(CONTROL_SIZE - 1 downto 0));
    co_frame_state : frame_state;
  end record result_vector;

  constant dummy_frame_state : frame_state := ('0', '0', '0', '0', '0', '0', '0', '0');

  type test_vector_array is array (natural range<>) of test_vector;
  constant test_vectors : test_vector_array :=
  (
    ((('1', '0', '0', "00000000", 0, 0, '0'), others => DUMMY_FC), -1),
    ((('1', '0', '0', "00000000", 0, 0, '0'), others => DUMMY_FC), -1),
    ((('1', '0', '0', "00000000", 0, 0, '0'), others => DUMMY_FC), -1),
    ((('1', '0', '0', "00000000", 0, 0, '0'), others => DUMMY_FC), -1),
    ((('0', '0', '0', "10111000", 0, 0, '1'), others => DUMMY_FC), -1),
    ((('0', '0', '0', "11100000", 1, 0, '1'), others => DUMMY_FC), -1),
    ((('0', '0', '0', "00011000", 2, 0, '1'), others => DUMMY_FC), -1),
    ((('0', '0', '0', "01000000", 3, 0, '1'), others => DUMMY_FC), -1),
    ((('0', '0', '0', "00011000", 0, 1, '1'), others => DUMMY_FC), 0),
    ((('0', '0', '0', "00011000", 1, 1, '1'), others => DUMMY_FC), 0),
    ((('0', '0', '0', "00011000", 2, 1, '1'), others => DUMMY_FC), 0),
    ((('0', '0', '0', "00011000", 3, 1, '1'), others => DUMMY_FC), 0),
    ((('0', '0', '0', "11100000", 0, 2, '1'), others => DUMMY_FC), 1),
    ((('0', '0', '0', "11100000", 1, 2, '1'), others => DUMMY_FC), 1),
    ((('0', '0', '0', "11100000", 2, 2, '1'), others => DUMMY_FC), 1),
    ((('0', '0', '0', "11100000", 3, 2, '1'), others => DUMMY_FC), 1),
    ((('0', '0', '0', "11100000", 0, 3, '0'), others => DUMMY_FC), 2),
    ((('0', '0', '0', "11100000", 1, 3, '1'), others => DUMMY_FC), 2),
    ((('0', '0', '0', "11100000", 2, 3, '1'), others => DUMMY_FC), 2),
    ((('0', '0', '0', "11100000", 3, 3, '1'), others => DUMMY_FC), 2),
    ((('0', '0', '0', "11100000", 0, 3, '0'), others => DUMMY_FC), 3),
    ((('0', '0', '0', "11100000", 1, 3, '1'), others => DUMMY_FC), 3),
    ((('0', '0', '0', "11100000", 2, 3, '1'), others => DUMMY_FC), 3),
    ((('0', '0', '0', "11100000", 3, 3, '1'), others => DUMMY_FC), 3)
    (("00000000000000000000000000000000", others => (others => '0')), (('0', '0', '0', '0', '0', '0', '0', '0'), others => dummy_frame_state), -1),
    (("10111000111000000001100001000000", others => (others => '0')), (('1', '0', '0', '0', '0', '0', '0', '0'), others => dummy_frame_state), -1),
    (("00011000000110000001100000011000", others => (others => '0')), (('1', '0', '0', '0', '0', '0', '0', '0'), others => dummy_frame_state), 0),
    (("11100000111000001110000011100000", others => (others => '0')), (('1', '0', '0', '0', '0', '0', '0', '0'), others => dummy_frame_state), 1),
    (("00000000000000000000000000000000", others => (others => '0')), (('1', '1', '0', '0', '0', '1', '0', '0'), others => dummy_frame_state), 2),
    (("11100000111000001110000011100000", others => (others => '0')), (('1', '1', '0', '0', '0', '1', '0', '0'), others => dummy_frame_state), 3),
    (("00000000000000000000000000000000", others => (others => '0')), (('1', '1', '0', '0', '0', '1', '0', '0'), others => dummy_frame_state), -1)
  );

  type result_vector_array is array (natural range<>) of result_vector;
  constant result_vectors : result_vector_array :=
  (
    (
      '1',
      (
        (("1011", "1"), others => DUMMY_S),
        (("1110", "0"), others => DUMMY_S),
        (("0001", "1"), others => DUMMY_S),
        (("0100", "0"), others => DUMMY_S)
      )
      ),
      ('1', '0', '0', '0', '0', '0', '0', '0')
    ),
    (
      '1',
      (
        (("0001", "1"), others => DUMMY_S),
        (("0001", "1"), others => DUMMY_S),
        (("0001", "1"), others => DUMMY_S),
        (("0001", "1"), others => DUMMY_S)
        )
      ),
      ('1', '0', '0', '0', '0', '0', '0', '0')
    ),
    (
      '1',
      (
        (("1110", "0"), others => DUMMY_S),
        (("1110", "0"), others => DUMMY_S),
        (("1110", "0"), others => DUMMY_S),
        (("1110", "0"), others => DUMMY_S)
      )
      ),
      ('1', '0', '0', '0', '0', '0', '0', '0')
    ),
    (
      '0',
      (
        (("1110", "0"), others => DUMMY_S),
        (("1110", "0"), others => DUMMY_S),
        (("1110", "0"), others => DUMMY_S),
        (("1110", "0"), others => DUMMY_S)
        )
      ),
      ('1', '1', '0', '0', '0', '1', '0', '1')
    )
  );

  signal ci_char_clk : std_logic := '0';
  signal ci_frame_clk : std_logic := '0';
  signal ci_reset : std_logic := '0';

  signal di_lanes_data : frame_character_array(0 to L - 1);
  signal di_lanes_data : lane_character_array (0 to L - 1)(F*8-1 downto 0);
  signal ci_frame_states : frame_state_array (0 to L - 1);

  signal do_samples_data : samples_array
    (0 to M - 1, 0 to S - 1)
    (data(N - 1 downto 0), ctrl_bits(CONTROL_SIZE - 1 downto 0));
  signal co_correct_data : std_logic;
  signal co_frame_state : frame_state;

  signal test_data_index : integer := 0;
begin  -- architecture a1


@@ 124,16 109,17 @@ begin  -- architecture a1
      N  => N,
      Nn => Nn)
    port map (
      ci_char_clk     => ci_char_clk,
      ci_reset        => ci_reset,
      ci_frame_clk    => ci_frame_clk,
      di_lanes_data   => di_lanes_data,
      co_correct_data => co_correct_data,
      ci_frame_states => ci_frame_states,
      co_frame_state => co_frame_state,
      do_samples_data => do_samples_data);

  ci_char_clk <= not ci_char_clk after CLK_PERIOD/2;
  ci_frame_clk <= not ci_frame_clk after CLK_PERIOD/2;
  ci_reset <= '1' after CLK_PERIOD*2;


  test: process is
    variable test_vec : test_vector;
    variable prev_test_vec : test_vector;


@@ 145,13 131,13 @@ begin  -- architecture a1
      test_data_index <= i;
      test_vec := test_vectors(i);
      di_lanes_data <= test_vec.di_lanes_data;
      ci_frame_states <= test_vec.ci_frame_states;

      if i > 0 then
        prev_test_vec := test_vectors(i - 1);

        if prev_test_vec.expected_result /= -1 then
          assert co_correct_data = result_vectors(prev_test_vec.expected_result).co_correct_data report "The correct data does not match, Index: " & integer'image(i-1) severity error;

          assert co_frame_state = result_vectors(prev_test_vec.expected_result).co_frame_state report "The frame state does not match, index: " & integer'image(prev_test_vec.expected_result) severity error;
          for ci in 0 to M - 1 loop
            for si in 0 to S - 1 loop
              assert do_samples_data(ci, si).data = result_vectors(prev_test_vec.expected_result).do_samples_data(ci, si).data report "The samples data do not match, expected: " & vec2str(result_vectors(prev_test_vec.expected_result).do_samples_data(ci, si).data) & ", got: " & vec2str(dummy) & ", index: " & integer'image(i-1) & ", ci: " & integer'image(ci) & ", si: " & integer'image(si) severity error;

Do not follow this link