~ruther/jesd204b-vhdl

d7408384753cca0edc6a9e78f4fe2859258fab8f — František Boháček 2 years ago f3e6e2d
feat(link): implement ilas parser
2 files changed, 173 insertions(+), 59 deletions(-)

M src/data_link/ilas_parser.vhd
M testbench/data_link/ilas_parser_tb.vhd
M src/data_link/ilas_parser.vhd => src/data_link/ilas_parser.vhd +111 -28
@@ 1,19 1,20 @@
library ieee;
use work.data_link_pkg.all;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.data_link_pkg.all;

entity ilas_parser is
  generic (
    R_character  : std_logic_vector(7 downto 0) := "00011100";
    A_character  : std_logic_vector(7 downto 0) := "01111100";
    Q_character  : std_logic_vector(7 downto 0) := "01011100";
    frames_count : integer                      := 4);
    Q_character  : std_logic_vector(7 downto 0) := "10011100";  -- 9C
    multiframes_count : integer                      := 4);

  port (
    ci_char_clk        : in  std_logic;
    ci_reset           : in  std_logic;
    ci_F               : in  integer range 0 to 256;
    ci_K               : in  integer range 0 to 32;
    ci_state           : in  link_state;
    di_char            : in  character_vector;
    do_config          : out link_config;


@@ 25,36 26,53 @@ entity ilas_parser is
end entity ilas_parser;

architecture a1 of ilas_parser is
  constant link_config_length : integer := 111;
  signal link_config_data : std_logic_vector(link_config_length downto 0) := (others => '0');
  constant link_config_length : integer := 112;
  signal octets_in_multiframe : integer range 0 to 8192 := 0;
  signal link_config_data : std_logic_vector(link_config_length-1 downto 0) := (others => '0');
  signal reg_processing_ilas : std_logic := '0';
  signal reg_frame_index : integer := 0;
  signal reg_multiframe_index : integer := 0;
  signal reg_octet_index : integer := 0;

  signal next_processing_ilas : std_logic := '0';
  signal next_multiframe_index : integer := 0;
  signal next_octet_index : integer := 0;

  signal finished : std_logic := '0';
  signal err : std_logic := '0';

  signal processing_ilas : std_logic := '0';

  function getOctetUpIndex (
    octet_index : integer)
    return integer is
  begin  -- function getByteUpIndex
    return link_config_length - 1 - 8 * octet_index;
  end function getByteUpIndex;
  end function getOctetUpIndex;

  function getDataByIndex (
    data        : std_logic_vector(link_config_length downto 0);
    data        : std_logic_vector(link_config_length-1 downto 0);
    octet_index : integer;
    bit_index   : integer;
    length      : integer)
    return std_logic_vector is
    variable up_index : integer;
  begin  -- function getDataByIndex
    up_index := getOctetUpIndex(data, octet_index);
    return data(up_index downto up_index - 7)(bit_index + length downto bit_index);
    up_index := getOctetUpIndex(octet_index);
    return data(up_index - 7 + bit_index + length - 1 downto up_index - 7 + bit_index);
  end function getDataByIndex;
begin  -- architecture a1

  function getBitByIndex (
    data        : std_logic_vector(link_config_length-1 downto 0);
    octet_index : integer;
    bit_index   : integer)
    return std_logic is
    variable up_index : integer;
  begin  -- function getBitByIndex
    up_index := getOctetUpIndex(octet_index);
    return data(up_index - 7 + bit_index);
  end function getBitByIndex;
begin  -- architecture a1
  --octets_in_multiframe <= ci_F * CI_K;
  octets_in_multiframe <= 17;
  -- ILAS
    -- one multiframe is sent
    -- 4 frames in a multiframe


@@ 65,37 83,67 @@ begin  -- architecture a1
      -- second_character: /K28.0/
      -- third_character: starts ILAS

  -- if anything does not match (/R/, /A/, /K28.0/, checksum), set co_error
  -- if anything does not match (/R/, /A/, /K28.0/, checksum), set error
  -- and co_wrong_chksum or co_unexpected_char. Stop processing.
  -- The controller will then request new synchronization try.

  set_next: process (ci_char_clk, ci_reset) is
  begin  -- process set_next
    if ci_reset = '0' then              -- asynchronous reset (active low)
      reg_octet_index <= 0;
      reg_multiframe_index <= 0;
      reg_processing_ilas <= '0';
    elsif ci_char_clk'event and ci_char_clk = '1' then  -- rising clock edge
      reg_octet_index <= next_octet_index;
      reg_multiframe_index <= next_multiframe_index;
      reg_processing_ilas <=  next_processing_ilas;
    end if;
  end process set_next;

  check_chars: process (ci_char_clk, ci_reset) is
    variable up_index : integer;
    variable processing_ilas : std_logic;
  begin  -- process check_chars
    processing_ilas := next_processing_ilas or reg_processing_ilas;
    if ci_reset = '0' then              -- asynchronous reset (active low)
      co_error <= '0';
      err <= '0';
      co_unexpected_char <= '0';
      co_wrong_chksum <= '0';
      finished <= '0';
      link_config_data <= (others => '0');
    elsif ci_char_clk'event and ci_char_clk = '1' and processing_ilas = '0' then
      co_error <= '0';
    elsif ci_char_clk'event and ci_char_clk = '1' and (processing_ilas = '0' or ci_state = INIT) then
      err <= '0';
      co_unexpected_char <= '0';
      co_wrong_chksum <= '0';
      link_config_data <= (others => '0');

      if ci_state /= DATA then
        link_config_data <= (others => '0');
        finished <= '0';
      end if;
    elsif err = '1' then
      -- If there is an error, stop processing.
    elsif ci_char_clk'event and ci_char_clk = '1' and processing_ilas = '1' then  -- rising clock edge
      if reg_octet_index = 0 then       -- Should be /R/
        if di_char.d8b /= R_character then
          co_error <= '1';
          err <= '1';
          co_unexpected_char <= '1';
        end if;
      elsif reg_octet_index = ci_F - 1 then
      elsif di_char.d8b = R_character then
        err <= '1';
        co_unexpected_char <= '1';
      elsif reg_octet_index = octets_in_multiframe - 1 then
        if di_char.d8b /= A_character then  -- Should be /A/
          co_error <= '1';
          err <= '1';
          co_unexpected_char <= '1';
        elsif reg_multiframe_index = 3 and err = '0' then
          finished <= '1';
        end if;
      elsif reg_frame_index = 1 then
      elsif di_char.d8b = A_character then
        err <= '1';
        co_unexpected_char <= '1';
      elsif reg_multiframe_index = 1 then
        if reg_octet_index = 1 and di_char.d8b /= Q_character then  -- Should be /Q/
          co_error <= '1';
          err <= '1';
          co_unexpected_char <= '1';
        elsif reg_octet_index > 1 and reg_octet_index < 16 then    -- This is config data
          up_index := getOctetUpIndex(reg_octet_index - 2);


@@ 103,20 151,55 @@ begin  -- architecture a1
        end if;

        if reg_octet_index = 15 then    -- This is a checksum

          -- TODO: calculate checksum
          if di_char.d8b = "00000000" then
            co_wrong_chksum <=  '1';
            err <= '1';
          end if;
        end if;
      elsif reg_multiframe_index > multiframes_count - 1 then
        err <= '1';
      end if;
    end if;
  end process check_chars;

  processing_ilas <= next_processing_ilas or reg_processing_ilas;
  co_finished <= finished;
  co_error <= err;

  next_processing_ilas <= '0' when ci_state = INIT else
  next_processing_ilas <= '0' when ci_state = INIT or finished = '1' else
                          '0' when reg_multiframe_index = 3 and reg_octet_index = octets_in_multiframe - 1 else
                          '1' when reg_processing_ilas = '1' or ci_state = ILAS
                          else '0';

  -- config
  do_config.ADJCNT <= to_integer(unsigned(getDataByIndex(link_config_data, 0, 0, 8)));
  do_config.ADJDIR <= getDataByIndex(link_config_data, 2, 6, 1);
  -- octet, multiframe index
  next_multiframe_index <= 0 when reg_processing_ilas = '0' and next_processing_ilas = '0' else
                           (reg_multiframe_index + 1) when reg_octet_index = octets_in_multiframe - 1 else
                           reg_multiframe_index;
  next_octet_index <= 0 when next_processing_ilas = '0' and reg_processing_ilas = '0' else
                      (reg_octet_index + 1) mod octets_in_multiframe;

  -- config
  do_config.DID <= to_integer(unsigned(getDataByIndex(link_config_data, 0, 0, 8)));
  do_config.ADJDIR <= getBitByIndex(link_config_data, 2, 6);
  do_config.ADJCNT <= to_integer(unsigned(getDataByIndex(link_config_data, 1, 4, 4)));
  do_config.BID <= to_integer(unsigned(getDataByIndex(link_config_data, 1, 0, 4)));
  do_config.PHADJ <= getBitByIndex(link_config_data, 2, 5);
  do_config.LID <= to_integer(unsigned(getDataByIndex(link_config_data, 2, 0, 5)));
  do_config.SCR <= getBitByIndex(link_config_data, 3, 7);
  do_config.L <= to_integer(unsigned(getDataByIndex(link_config_data, 3, 0, 5))) + 1;
  do_config.F <= to_integer(unsigned(getDataByIndex(link_config_data, 4, 0, 8))) + 1;
  do_config.K <= to_integer(unsigned(getDataByIndex(link_config_data, 5, 0, 5))) + 1;
  do_config.M <= to_integer(unsigned(getDataByIndex(link_config_data, 6, 0, 8))) + 1;
  do_config.CS <= to_integer(unsigned(getDataByIndex(link_config_data, 7, 6, 2)));
  do_config.N <= to_integer(unsigned(getDataByIndex(link_config_data, 7, 0, 5))) + 1;
  do_config.SUBCLASSV <= to_integer(unsigned(getDataByIndex(link_config_data, 8, 5, 3)));
  do_config.Nn <= to_integer(unsigned(getDataByIndex(link_config_data, 8, 0, 5))) + 1;
  do_config.JESDV <= to_integer(unsigned(getDataByIndex(link_config_data, 9, 5, 3)));
  do_config.S <= to_integer(unsigned(getDataByIndex(link_config_data, 9, 0, 5))) + 1;
  do_config.HD <= getBitByIndex(link_config_data, 10, 7);
  do_config.CF <= to_integer(unsigned(getDataByIndex(link_config_data, 9, 0, 5)));
  do_config.RES1 <= getDataByIndex(link_config_data, 11, 0, 8);
  do_config.RES2 <= getDataByIndex(link_config_data, 12, 0, 8);
  do_config.CHKSUM <= to_integer(unsigned(getDataByIndex(link_config_data, 13, 0, 8)));
  do_config.X <=  getBitByIndex(link_config_data, 2, 7) & getDataByIndex(link_config_data, 3, 5, 2) & getDataByIndex(link_config_data, 5, 5, 3) & getBitByIndex(link_config_data, 7, 5) & getDataByIndex(link_config_data, 10, 5, 2);
end architecture a1;

M testbench/data_link/ilas_parser_tb.vhd => testbench/data_link/ilas_parser_tb.vhd +62 -31
@@ 21,28 21,56 @@ architecture a1 of ilas_parser_tb is
  type config_array is array (natural range<>) of link_config;
  constant config_vectors : config_array :=
  (
    -- DID = 10101010
    -- ADJCNT = 0111
    -- BID = 1110
    -- ADJDIR = 1
    -- PHADJ = 0
    -- LID 01010
    -- SCR = 1
    -- L = 11110
    -- F = 11001100
    -- K = 11111
    -- M = 00110011
    -- CS = 10
    -- N = 00011
    -- SUBCLASSV = 1
    -- Nn = 11101
    -- JESDV = 0
    -- S = 0
    -- HD = 0
    -- CF = 0
    -- RES1 = 11111111
    -- RES2 = 00000000
    -- X = 010010000
    (
      DID => 170,
      ADJCNT =>  7,
      BID => 14,
      ADJDIR => '1',
      PHADJ => '1',
      LID => 10,
      SCR => '1',
      L => 31,
      F => 205,
      K => 32,
      M => 52,
      CS => 2,
      N => 4,
      SUBCLASSV => 1,
      Nn => 30,
      JESDV => 0,
      S => 1,
      HD => '0',
      CF =>  0,
      RES1 => "11111111",
      RES2 => "00000000",
      X => "010010000",
      CHKSUM => 48
    ),
    (
      DID => 170,
      ADJCNT =>  7,
      BID => 14,
      ADJDIR => '1',
      PHADJ => '1',
      LID => 10,
      SCR => '1',
      L => 31,
      F => 205,
      K => 32,
      M => 52,
      CS => 2,
      N => 4,
      SUBCLASSV => 1,
      Nn => 30,
      JESDV => 0,
      S => 1,
      HD => '0',
      CF =>  0,
      RES1 => "11111111",
      RES2 => "11111111",
      X => "010010000",
      CHKSUM => 48
    )
  );

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


@@ 75,7 103,7 @@ architecture a1 of ilas_parser_tb is
    (ILAS, ('1', '0', '0', "10011100"), '0', '0', '0', '0', -1),  -- 28.4
    (ILAS, ('0', '0', '0', "10101010"), '0', '0', '0', '0', -1),  -- DID
    (ILAS, ('0', '0', '0', "01111110"), '0', '0', '0', '0', -1),  -- ADJCNT,BID
    (ILAS, ('0', '0', '0', "01001010"), '0', '0', '0', '0', -1),  -- X,ADJDIR,PHADJ,LID
    (ILAS, ('0', '0', '0', "01101010"), '0', '0', '0', '0', -1),  -- X,ADJDIR,PHADJ,LID
    (ILAS, ('0', '0', '0', "11011110"), '0', '0', '0', '0', -1),  -- SCR,X,L
    (ILAS, ('0', '0', '0', "11001100"), '0', '0', '0', '0', -1),  -- F
    (ILAS, ('0', '0', '0', "01011111"), '0', '0', '0', '0', -1),  -- X, K


@@ 89,7 117,7 @@ architecture a1 of ilas_parser_tb is
    (ILAS, ('0', '0', '0', "00110000"), '0', '0', '0', '0', -1),
    (ILAS, ('1', '0', '0', "01111100"), '0', '0', '0', '0',  0),  -- A
    (ILAS, ('1', '0', '0', "00011100"), '0', '0', '0', '0',  0),  -- R
    (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0', -1),
    (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0',  0),
    (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0',  0),
    (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0',  0),
    (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0',  0),


@@ 106,7 134,6 @@ architecture a1 of ilas_parser_tb is
    (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0',  0),
    (ILAS, ('1', '0', '0', "01111100"), '0', '0', '0', '0',  0),  -- A
    (ILAS, ('1', '0', '0', "00011100"), '0', '0', '0', '0',  0),  -- R, 2 mult
    (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0', -1),
    (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0',  0),
    (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0',  0),
    (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0',  0),


@@ 121,7 148,8 @@ architecture a1 of ilas_parser_tb is
    (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0',  0),
    (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0',  0),
    (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0',  0),
    (ILAS, ('1', '0', '0', "01111100"), '0', '0', '0', '0',  0),  -- A
    (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0',  0),
    (ILAS, ('1', '0', '0', "01111100"), '1', '0', '0', '0',  0),  -- A
    (DATA, ('0', '0', '0', "00000001"), '1', '0', '0', '0',  0),
    (DATA, ('0', '0', '0', "00000010"), '1', '0', '0', '0',  0),
    (DATA, ('0', '0', '0', "00000011"), '1', '0', '0', '0',  0),


@@ 147,7 175,7 @@ architecture a1 of ilas_parser_tb is
    (ILAS, ('1', '0', '0', "00011100"), '0', '0', '0', '0', -1),  -- R, 0 mult
    (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0', -1),
    (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0', -1),
    (ILAS, ('1', '0', '0', "01111100"), '0', '1', '0', '1',  0),  -- A
    (ILAS, ('1', '0', '0', "01111100"), '0', '1', '0', '1', -1),  -- A
    (ILAS, ('0', '0', '0', "00000000"), '0', '1', '0', '1', -1),
    (ILAS, ('0', '0', '0', "00000000"), '0', '1', '0', '1', -1),
    (INIT, ('0', '0', '0', "00000000"), '0', '0', '0', '0', -1),


@@ 158,7 186,7 @@ architecture a1 of ilas_parser_tb is
    (CGS,  ('0', '0', '0', "10111100"), '0', '0', '0', '0', -1),
    (CGS,  ('0', '0', '0', "10111100"), '0', '0', '0', '0', -1),
    (ILAS, ('1', '0', '0', "00011100"), '0', '0', '0', '0', -1),  -- R, 0 mult
    (ILAS, ('1', '0', '0', "00011100"), '0', '0', '0', '0', -1),  -- R, 0 mult
    (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0', -1),
    (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0', -1),
    (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0', -1),
    (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0', -1),


@@ 189,18 217,20 @@ architecture a1 of ilas_parser_tb is
    (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0', -1),
    (ILAS, ('0', '0', '0', "11111111"), '0', '0', '0', '0', -1),
    (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0', -1),
    (ILAS, ('0', '0', '0', "00000000"), '0', '0', '0', '0', -1),
    (ILAS, ('0', '0', '0', "00000000"), '0', '1', '1', '0', -1),
    (ILAS, ('1', '0', '0', "01111100"), '0', '1', '1', '0', -1),  -- A
    (ILAS, ('0', '0', '0', "00000000"), '0', '1', '1', '0', -1),
    (ILAS, ('0', '0', '0', "00000000"), '0', '1', '1', '0', -1),
    (ILAS, ('0', '0', '0', "00000000"), '0', '1', '1', '0', -1),
    (ILAS, ('0', '0', '0', "00000000"), '0', '1', '1', '0', -1),
    (ILAS, ('0', '0', '0', "00000000"), '0', '1', '1', '0', -1)
    (ILAS, ('0', '0', '0', "00000000"), '0', '1', '1', '0', -1),
    (INIT, ('0', '0', '0', "00000000"), '0', '1', '1', '0', -1)
  );

  constant clk_period : time := 1 ns;

  constant F : integer range 0 to 256 := 17;
  constant K : integer range 0 to 32 := 1;

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


@@ 223,6 253,7 @@ begin  -- architecture a1
      ci_char_clk => clk,
      ci_reset    => reset,
      ci_F        => F,
      ci_K        => K,
      ci_state    =>  ci_state,
      di_char     => di_char,
      do_config   => do_config,


@@ 250,7 281,7 @@ begin  -- architecture a1
        prev_test_vec := test_vectors(i - 1);

        if prev_test_vec.expected_config_index > -1 then
          assert co_config = config_vectors(prev_test_vec.expected_config_index) report "The config does not match. Index: " & integer'image(i-1) severity error;
        assert do_config = config_vectors(prev_test_vec.expected_config_index) report "The config does not match. Index: " & integer'image(i-1) severity error;
        end if;

        assert co_error = prev_test_vec.expected_error report "The error does not match. Index: " & integer'image(i-1) severity error;

Do not follow this link