~ruther/jesd204b-vhdl

99b0946252fc5f69082672317ab0affefdd5d515 — František Boháček 2 years ago 186db20
feat(link): output frame_character from data link, add user_data to character
M src/data_link/8b10b_decoder.vhd => src/data_link/8b10b_decoder.vhd +2 -0
@@ 172,6 172,7 @@ begin  -- architecture a1
      do_char.disparity_error <= '0';
      do_char.missing_error <= '0';
      do_char.kout <= '0';
      do_char.user_data <= '0';
      reg_do_8b <= (others => '0');
      reg_rd <= '0';
    elsif ci_char_clk'event and ci_char_clk = '1' then  -- rising clock edge


@@ 179,6 180,7 @@ begin  -- architecture a1
      do_char.disparity_error <= next_disparity_error;
      do_char.missing_error <= next_missing_error;
      do_char.kout <= next_kout;
      do_char.user_data <= '0';
      reg_do_8b <= next_do_8b;
      reg_rd <= next_rd;
    end if;

M src/data_link/data_link_pkg.vhd => src/data_link/data_link_pkg.vhd +11 -0
@@ 8,8 8,19 @@ package data_link_pkg is
    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
    user_data      : std_logic;
  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;
    frame_index    : integer range 0 to 32;
    user_data      : std_logic;
  end record frame_character;

  type link_state is (
    INIT,
    CGS,

M src/data_link/frame_alignment.vhd => src/data_link/frame_alignment.vhd +25 -12
@@ 20,9 20,7 @@ entity frame_alignment is
    di_char           : in  character_vector;       -- The received character
    co_aligned        : out std_logic;
    co_misaligned     : out std_logic;
    co_octet_index    : out integer range 0 to 256;  -- The index of the octet in current frame
    co_frame_index    : out integer range 0 to 32;  -- The index of the frame in current multiframe
    do_char           : out character_vector);      -- The output character
    do_char           : out frame_character);      -- The output character
end entity frame_alignment;

architecture a1 of frame_alignment is


@@ 47,17 45,22 @@ architecture a1 of frame_alignment is

  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");
  signal next_char : character_vector := ('0', '0', '0', "00000000", '0');
begin  -- architecture a1
  set_next: process (ci_char_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");
      do_char <= ('0', '0', '0', "00000000", 0, 0, '0');
      reg_state <= INIT;
    elsif ci_char_clk'event and ci_char_clk = '1' then  -- rising clock edge
      do_char <= next_char;
      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


@@ 68,16 71,24 @@ begin  -- architecture a1
        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;
      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
          reg_state <= ALIGNED;


@@ 85,6 96,8 @@ begin  -- architecture a1
      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 reg_state = ALIGNED then
          if is_wrong_char = '1' then
            reg_state <= MISALIGNED;


@@ 94,6 107,7 @@ begin  -- architecture a1

            if ci_enable_realign = '1' then
              reg_octet_index <= ci_F - 1;
              do_char.octet_index <= ci_F - 1;
            else
              reg_state <= WRONG_ALIGNMENT;
            end if;


@@ 104,7 118,8 @@ begin  -- architecture a1
          if is_wrong_char = '0' and (is_f = '1' or is_a = '1') then
            reg_state <= MISALIGNED;
          elsif ci_enable_realign = '1' and (is_f = '1' or is_a = '1') then
            reg_frame_index <= ci_F - 1;
            do_char.octet_index <= ci_F - 1;
            reg_octet_index <= ci_F - 1;
          end if;
        end if;
      end if; -- in RECEIVED_K


@@ 119,6 134,7 @@ begin  -- architecture a1
                 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';


@@ 127,12 143,9 @@ begin  -- architecture a1
  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 when reg_frame_index < (ci_K - 1) else
                      0;
  next_octet_index <= reg_octet_index + 1 when reg_octet_index < (ci_F - 1) else 0;
                      (reg_frame_index + 1) mod ci_K;
  next_octet_index <= (reg_octet_index + 1) mod ci_F;

  co_misaligned <= '1' when reg_state = WRONG_ALIGNMENT else '0';
  co_aligned <= '1' when reg_state = ALIGNED or reg_state = MISALIGNED else '0';
  co_octet_index <= reg_octet_index;
  co_frame_index <= reg_frame_index;
end architecture a1;

M src/data_link/lane_alignment.vhd => src/data_link/lane_alignment.vhd +5 -4
@@ 6,7 6,7 @@ entity lane_alignment is
  generic (
    buffer_size     : integer          := 256;
    alignment_character : std_logic_vector(7 downto 0) := "01111100";
    dummy_character : character_vector := ('1', '0', '0', "10111100"));
    dummy_character : character_vector := ('1', '0', '0', "10111100", '0'));

  port (
    ci_char_clk : in std_logic;


@@ 25,7 25,7 @@ end entity lane_alignment;

architecture a1 of lane_alignment is
  type buffer_array is array (0 to buffer_size) of character_vector;
  signal buff : buffer_array := (others => ('0', '0', '0', "00000000"));
  signal buff : buffer_array := (others => ('0', '0', '0', "00000000", '0'));

  signal reg_ready : std_logic := '0';
  signal reg_started : std_logic := '0';


@@ 48,7 48,7 @@ begin  -- architecture a1
      reg_ready       <= '0';
      reg_started     <= '0';
      reg_error       <= '0';
      buff            <= (others => ('0', '0', '0', "00000000"));
      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;


@@ 69,7 69,7 @@ begin  -- architecture a1
                     0;

  next_ready <= '0' when ci_state = INIT else
                '1' when reg_ready = '1' or (di_char.kout = '1' and di_char.d8b = alignment_character and (ci_state = CGS or ci_state = ILAS)) else
                '1' when reg_ready = '1' or (di_char.kout = '1' and di_char.d8b = alignment_character and (ci_state = CGS or ci_state = ILS)) else
                '0';
  next_started <= '0' when reg_ready = '0' else
                  '1' when reg_ready = '1' and (ci_start = '1' or reg_started = '1') else


@@ 82,5 82,6 @@ begin  -- architecture a1

  do_char <= dummy_character when ci_state = INIT or reg_started = '0' else
             buff(reg_read_index);
  do_char.user_data <= '1' when ci_state = DATA and reg_started = '1' else '0';

end architecture a1;

M testbench/data_link/frame_alignment_tb.vhd => testbench/data_link/frame_alignment_tb.vhd +35 -43
@@ 13,11 13,9 @@ architecture a1 of frame_alignment_tb is
    ci_enable_realign : std_logic;
    di_char : character_vector;

    expected_char : character_vector;
    expected_char : frame_character;
    expected_aligned : std_logic;
    expected_misaligned : std_logic;
    expected_octet_index : integer range 0 to 256;
    expected_frame_index : integer range 0 to 32;

  end record test_vector;



@@ 25,39 23,39 @@ 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       almisal oct fram
    ('0', '0', '0', ('1', '0', '0', "10111100"), ('1', '0', '0', "10111100"), '0', '0', 0, 0),
    ('0', '0', '0', ('0', '0', '0', "00000000"), ('0', '0', '0', "00000000"), '1', '0', 0, 0),
    ('0', '0', '0', ('0', '0', '0', "10101010"), ('0', '0', '0', "10101010"), '1', '0', 1, 0),
    ('0', '0', '0', ('0', '0', '0', "01010101"), ('0', '0', '0', "01010101"), '1', '0', 2, 0),
    ('0', '0', '0', ('0', '0', '0', "01010101"), ('0', '0', '0', "01010101"), '1', '0', 3, 0),
    ('0', '0', '0', ('0', '0', '0', "01010101"), ('0', '0', '0', "01010101"), '1', '0', 4, 0),
    ('0', '0', '0', ('0', '0', '0', "11111111"), ('0', '0', '0', "11111111"), '1', '0', 0, 1),
    ('0', '0', '0', ('0', '0', '0', "11111111"), ('0', '0', '0', "11111111"), '1', '0', 1, 1),
    ('0', '0', '0', ('0', '0', '0', "11111111"), ('0', '0', '0', "11111111"), '1', '0', 2, 1),
    ('0', '0', '0', ('0', '0', '0', "11111111"), ('0', '0', '0', "11111111"), '1', '0', 3, 1),
    ('0', '0', '0', ('1', '0', '0', "11111100"), ('0', '0', '0', "01010101"), '1', '0', 4, 1),
    ('0', '0', '0', ('1', '0', '0', "11111100"), ('0', '0', '0', "01010101"), '1', '0', 0, 2),
    ('0', '0', '0', ('1', '0', '0', "11111100"), ('0', '0', '0', "01010101"), '0', '1', 1, 2),
    ('0', '0', '0', ('0', '0', '0', "11110000"), ('0', '0', '0', "11110000"), '0', '1', 2, 2),
    ('0', '0', '0', ('0', '0', '0', "11110000"), ('0', '0', '0', "11110000"), '0', '1', 3, 2),
    ('0', '0', '0', ('1', '0', '0', "11111100"), ('0', '0', '0', "01010101"), '1', '0', 4, 2),
    ('1', '1', '1', ('0', '0', '0', "11111100"), ('0', '0', '0', "11111100"), '0', '0', 0, 0),
    ('0', '1', '1', ('1', '0', '0', "10111100"), ('1', '0', '0', "10111100"), '0', '0', 0, 0),
    ('0', '1', '1', ('0', '0', '0', "00000000"), ('0', '0', '0', "00000000"), '1', '0', 0, 0),
    ('0', '1', '1', ('0', '0', '0', "00000000"), ('0', '0', '0', "00000000"), '1', '0', 1, 0),
    ('0', '1', '1', ('0', '0', '0', "00000000"), ('0', '0', '0', "00000000"), '1', '0', 2, 0),
    ('0', '1', '1', ('0', '0', '0', "00000000"), ('0', '0', '0', "00000000"), '1', '0', 3, 0),
    ('0', '1', '1', ('0', '0', '0', "00000000"), ('0', '0', '0', "00000000"), '1', '0', 4, 0),
    ('0', '1', '1', ('0', '0', '0', "00000000"), ('0', '0', '0', "00000000"), '1', '0', 0, 1),
    ('0', '1', '1', ('0', '0', '0', "00000000"), ('0', '0', '0', "00000000"), '1', '0', 1, 1),
    ('0', '1', '1', ('0', '0', '0', "00000000"), ('0', '0', '0', "00000000"), '1', '0', 2, 1),
    ('0', '1', '1', ('0', '0', '0', "00000000"), ('0', '0', '0', "00000000"), '1', '0', 3, 1),
    ('0', '1', '1', ('1', '0', '0', "11111100"), ('0', '0', '0', "11111100"), '1', '0', 4, 1),
    ('0', '1', '1', ('1', '0', '0', "01111100"), ('0', '0', '0', "01111100"), '1', '0', 0, 2),
    ('0', '1', '1', ('1', '0', '0', "01111100"), ('0', '0', '0', "01111100"), '1', '0', 4, 2),
    ('0', '1', '1', ('0', '0', '0', "11111111"), ('0', '0', '0', "11111111"), '1', '0', 0, 3),
    ('0', '1', '1', ('0', '0', '0', "11111111"), ('0', '0', '0', "11111111"), '1', '0', 1, 3),
    ('0', '1', '1', ('0', '0', '0', "11111111"), ('0', '0', '0', "11111111"), '1', '0', 2, 3)
    ('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'), '1', '0'),
    ('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'), '1', '0'),
    ('0', '1', '1', ('1', '0', '0', "01111100", '0'), ('0', '0', '0', "01111100", 4, 2, '0'), '1', '0'),
    ('0', '1', '1', ('0', '0', '0', "11111111", '0'), ('0', '0', '0', "11111111", 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')
  );

  constant clk_period : time := 1 ns;


@@ 69,15 67,13 @@ architecture a1 of frame_alignment_tb is
  signal reset : std_logic := '0';

  signal di_char : character_vector;
  signal do_char : character_vector;
  signal do_char : frame_character;

  signal ci_request_sync : std_logic;
  signal ci_enable_realign : std_logic;
  signal ci_scrambled : std_logic;
  signal co_aligned : std_logic;
  signal co_misaligned : std_logic;
  signal co_octet_index : integer range 0 to 256;
  signal co_frame_index : integer range 0 to 32;

  signal test_data_index : integer := 0;



@@ 94,8 90,6 @@ begin  -- architecture a1
      di_char           => di_char,
      co_aligned        => co_aligned,
      co_misaligned     => co_misaligned,
      co_octet_index    => co_octet_index,
      co_frame_index    => co_frame_index,
      do_char           => do_char);

  clk <= not clk after clk_period/2;


@@ 120,8 114,6 @@ 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_misaligned = prev_test_vec.expected_misaligned report "The misaligned does not match. Index: " & integer'image(i-1) severity error;
        assert co_octet_index = prev_test_vec.expected_octet_index report "The octet index does not match. Expected: " & integer'image(prev_test_vec.expected_octet_index) & ", got: " & integer'image(co_octet_index) & ", index: " & integer'image(i-1) severity error;
        assert co_frame_index = prev_test_vec.expected_frame_index report "The frame index does not match. Expected: " & integer'image(prev_test_vec.expected_frame_index) & ", got: " & integer'image(co_frame_index) & ", 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;


Do not follow this link