~ruther/jesd204b-vhdl

e9ed12fe1be809f26e5804e2b38f5de5a1e09cd2 — František Boháček 1 year, 11 months ago b92aa37
chore: remove octets_to_sample, put its behavior to transport_layer
5 files changed, 112 insertions(+), 171 deletions(-)

D src/transport/octets_to_sample.vhd
M src/transport/transport_layer.vhd
R testbench/transport/{octets_to_samples_fc_tb.vhd => transport_layer_fc_tb.vhd}
R testbench/transport/{octets_to_samples_multi_cf_tb.vhd => transport_layer_multi_cf_tb.vhd}
R testbench/transport/{octets_to_samples_simp_tb.vhd => transport_layer_simp_tb.vhd}
D src/transport/octets_to_sample.vhd => src/transport/octets_to_sample.vhd +0 -141
@@ 1,141 0,0 @@
-------------------------------------------------------------------------------
-- Title      : octets to samples mapping
-------------------------------------------------------------------------------
-- File       : octets_to_sample.vhd
-------------------------------------------------------------------------------
-- Description: Maps octets from lanes from data link to samples.
-- In case of any error in the data, last frame will be streamed again.
-- The data from wrong frame will be dropped.
-------------------------------------------------------------------------------

library ieee;
use ieee.std_logic_1164.all;
use work.data_link_pkg.all;
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
    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
                                        -- =0
  port (
    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
  signal samples_data : samples_array
    (0 to M - 1, 0 to S - 1)
    (data(N - 1 downto 0), ctrl_bits(CS - 1 downto 0));
  signal prev_samples_data : samples_array
    (0 to M - 1, 0 to S - 1)
    (data(N - 1 downto 0), ctrl_bits(CS - 1 downto 0));
  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_error         : std_logic;  -- if err, repeat last samples.
  signal current_frame_state : frame_state;

  signal reg_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_frame_clk, ci_reset) is
  begin  -- process set_data
    if ci_reset = '0' then              -- asynchronous reset (active low)
      reg_error <= '0';
      reg_buffered_data <= (others => '0');
    elsif ci_frame_clk'event and ci_frame_clk = '1' then  -- rising clock edge
      do_samples_data <= next_samples_data;
      co_frame_state <= current_frame_state;

      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;

  -- 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';

  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)
  -- (control chars are right after sample)
  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 <= 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 <= 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;
  end generate multi_lane_no_cf;

  -- for one or mutliple lanes if CF != 0
  -- (control words are present)
  multi_lane_cf: if CF > 0 generate
    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 <= 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 <= 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;
    end generate cf_groups;
  end generate multi_lane_cf;
end architecture a1;

M src/transport/transport_layer.vhd => src/transport/transport_layer.vhd +100 -18
@@ 34,25 34,107 @@ entity transport_layer is
end entity transport_layer;

architecture a1 of transport_layer is
  signal samples_data : samples_array
    (0 to M - 1, 0 to S - 1)
    (data(N - 1 downto 0), ctrl_bits(CS - 1 downto 0));
  signal prev_samples_data : samples_array
    (0 to M - 1, 0 to S - 1)
    (data(N - 1 downto 0), ctrl_bits(CS - 1 downto 0));
  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_error         : std_logic;  -- if err, repeat last samples.
  signal current_frame_state : frame_state;

  signal reg_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 a1
  set_data: process (ci_frame_clk, ci_reset) is
  begin  -- process set_data
    if ci_reset = '0' then              -- asynchronous reset (active low)
      reg_error <= '0';
      reg_buffered_data <= (others => '0');
    elsif ci_frame_clk'event and ci_frame_clk = '1' then  -- rising clock edge
      do_samples_data <= next_samples_data;
      co_frame_state <= current_frame_state;

      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;

  -- 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';

  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)
  -- (control chars are right after sample)
  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 <= 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 <= 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;
  end generate multi_lane_no_cf;

  -- for one or mutliple lanes if CF != 0
  -- (control words are present)
  multi_lane_cf: if CF > 0 generate
    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 <= 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);

  -- maps data from lanes to samples
  octets_to_samples: entity work.octets_to_samples
    generic map (
      CS => CS,
      M => M,
      S => S,
      L => L,
      F => F,
      CF => CF,
      N => N,
      Nn => Nn)
    port map (
      ci_frame_clk    => ci_frame_clk,
      ci_reset        => ci_reset,
      ci_frame_states => ci_frame_states,
      di_lanes_data   => di_lanes_data,
      co_frame_state  => co_frame_state,
      do_samples_data => do_samples_data);
          control_bits: if CS > 0 generate
            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;
    end generate cf_groups;
  end generate multi_lane_cf;

end architecture a1;

R testbench/transport/octets_to_samples_fc_tb.vhd => testbench/transport/transport_layer_fc_tb.vhd +4 -4
@@ 4,10 4,10 @@ use work.data_link_pkg.all;
use work.transport_pkg.all;
use work.testing_functions.all;

entity octets_to_samples_fc_tb is
end entity octets_to_samples_fc_tb;
entity transport_layer_fc_tb is
end entity transport_layer_fc_tb;

architecture a1 of octets_to_samples_fc_tb is
architecture a1 of transport_layer_fc_tb is
  constant CONTROL_SIZE : integer := 1;  -- Size in bits of the control bits
  constant M            : integer := 4;  -- Count of converters
  constant S            : integer := 1;  -- Count of samples


@@ 87,7 87,7 @@ architecture a1 of octets_to_samples_fc_tb is

  signal test_data_index : integer := 0;
begin  -- architecture a1
  uut : entity work.octets_to_samples
  uut : entity work.transport_layer
    generic map (
      CS => CONTROL_SIZE,
      M  => M,

R testbench/transport/octets_to_samples_multi_cf_tb.vhd => testbench/transport/transport_layer_multi_cf_tb.vhd +4 -4
@@ 4,10 4,10 @@ use work.data_link_pkg.all;
use work.transport_pkg.all;
use work.testing_functions.all;

entity octets_to_samples_multi_fc_tb is
end entity octets_to_samples_multi_fc_tb;
entity transport_layer_multi_fc_tb is
end entity transport_layer_multi_fc_tb;

architecture a1 of octets_to_samples_multi_fc_tb is
architecture a1 of transport_layer_multi_fc_tb is
  constant CONTROL_SIZE : integer := 2;  -- Size in bits of the control bits
  constant M            : integer := 4;  -- Count of converters
  constant S            : integer := 2;  -- Count of samples


@@ 85,7 85,7 @@ architecture a1 of octets_to_samples_multi_fc_tb is
  signal test_data_index : integer := 0;
begin  -- architecture a1

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

R testbench/transport/octets_to_samples_simp_tb.vhd => testbench/transport/transport_layer_simp_tb.vhd +4 -4
@@ 4,10 4,10 @@ use work.data_link_pkg.all;
use work.transport_pkg.all;
use work.testing_functions.all;

entity octets_to_samples_simp_tb is
end entity octets_to_samples_simp_tb;
entity transport_layer_simp_tb is
end entity transport_layer_simp_tb;

architecture a1 of octets_to_samples_simp_tb is
architecture a1 of transport_layer_simp_tb is
  constant CONTROL_SIZE : integer := 1;  -- Size in bits of the control bits
  constant M            : integer := 4;  -- Count of converters
  constant S            : integer := 1;  -- Count of samples


@@ 98,7 98,7 @@ architecture a1 of octets_to_samples_simp_tb is

  signal test_data_index : integer := 0;
begin  -- architecture a1
  uut : entity work.octets_to_samples
  uut : entity work.transport_layer
    generic map (
      CS => CONTROL_SIZE,
      M  => M,

Do not follow this link