AXI4-Stream Slave with UVVM Light


In a previous post we set up a simple testbench to generate data using an AXI4-Stream Bus Functional Model from the UVVM Light library. In this post we will expand that test bench to include a slave interface that receives and validates the data sent by the master.

We start by adding a record for the slave AXI4-Stream interface, as well as an array that will serve as our expected data. For our first test the expected data will be identical to the data sent by the master AXI4-Stream interface.

VHDL
-- Record definition for the AXI4-Stream bus
subtype t_axistream is t_axistream_if (
  tdata (7 downto 0),
  tkeep (0 downto 0),
  tuser (0 downto 0),
  tstrb (0 downto 0),
  tid   (0 downto 0),
  tdest (0 downto 0)
);
signal m_axistream : t_axistream;
signal s_axistream : t_axistream;
-- AXI4-Stream Data
signal tdata_array : t_slv_array(0 to 15) (7 downto 0) := (
  x"00", x"11", x"22", x"33",
  x"44", x"55", x"66", x"77",
  x"88", x"99", x"AA", x"BB",
  x"CC", x"DD", x"EE", x"FF"
);
signal tdata_expected_array : t_slv_array(0 to 15) (7 downto 0) := (
  x"00", x"11", x"22", x"33",
  x"44", x"55", x"66", x"77",
  x"88", x"99", x"AA", x"BB",
  x"CC", x"DD", x"EE", x"FF"
);

Next, we will add the configuration constant for the slave interface. This configuration is identical to that of the master interface, with the exception that, in the slave interface, we set the ‘ready’ signal to be driven low randomly throughout the transmission of the data.

VHDL
-- Configure the AXI4-Stream Slave BFM
constant C_AXISTREAM_SLAVE_BFM_CONFIG_DEFAULT : t_axistream_bfm_config := (
  max_wait_cycles                => 100,
  max_wait_cycles_severity       => ERROR,
  clock_period                   => -1 ns,
  clock_period_margin            => 0 ns,
  clock_margin_severity          => TB_ERROR,
  setup_time                     => -1 ns,
  hold_time                      => -1 ns,
  bfm_sync                       => SYNC_ON_CLOCK_ONLY,
  match_strictness               => MATCH_EXACT,
  byte_endianness                => LOWER_BYTE_LEFT,
  valid_low_at_word_num          => 0,
  valid_low_multiple_random_prob => 0.5,
  valid_low_duration             => 0,
  valid_low_max_random_duration  => 5,
  check_packet_length            => false,
  protocol_error_severity        => ERROR,
  ready_low_at_word_num          => C_MULTIPLE_RANDOM,
  ready_low_multiple_random_prob => 0.5,
  ready_low_duration             => C_RANDOM,
  ready_low_max_random_duration  => 5,
  ready_default_value            => '0',
  id_for_bfm                     => ID_BFM
);

We now connect our master and slave interfaces to each other. In a real-world testbench the interfaces would be connected to a DUT instead of to each other, but for the purposes of our demonstration a DUT is not required.

VHDL
-- Connect the interfaces to each other
s_axistream.tdata    <= m_axistream.tdata;
s_axistream.tkeep    <= m_axistream.tkeep;
s_axistream.tuser    <= m_axistream.tuser;
s_axistream.tvalid   <= m_axistream.tvalid;
s_axistream.tlast    <= m_axistream.tlast;
m_axistream.tready   <= s_axistream.tready;
s_axistream.tstrb    <= m_axistream.tstrb;
s_axistream.tid      <= m_axistream.tid;
s_axistream.tdest    <= m_axistream.tdest;

The logic for generating the AXI4-Stream data remains unchanged, so we are ready to add the code for checking the data with the slave interface. Because the UVVM BFMs are blocking, we need to add a separate process for this purpose.

VHDL
check_data : process
  constant C_SCOPE : string := "CHECK PROCESS";
begin
  -- Check data over AXI4-Stream
  axistream_expect( tdata_expected_array, "Check AXI4-Stream data", clk, s_axistream,
                    WARNING, C_SCOPE, msg_id_panel, C_AXISTREAM_SLAVE_BFM_CONFIG_DEFAULT);
  log(ID_LOG_HDR, "AXI4-Stream Data checked", C_SCOPE);  
  wait;
end process check_data;

The UVVM AXI4-Stream BFM package offers two options for capturing data: the ‘axistream_expect’ procedure and the ‘axistream_receive’ procedure. The ‘axistream_expect’ procedure takes mostly the same parameters as the ‘axistream_transmit’ we used earlier, with two key differences:

  1. Instead of the data to be transmitted, we must indicate the expected data against which the received data will be compared.
  2. We must indicate the severity level with which mismatches between the expected and received data will be reported. We use warnings in this example so the simulation can continue after finding the discrepancies in the data.

We can now run our simulation. This time instead of compiling the libraries and linking them to Modelsim in a separate step, we will compile the UVVM Light sources together with our test bench code. This not only makes it easier to run this example by removing the previous compilation requirement, but it also enables us to parameterize the UVVM packages to fit our needs.

The commands to compile the UVVM Light sources are taken from the UVVM own’s compilation script for ModelSim and Questa, which is available in the ‘script’ folder of the UVVM Light repository. There are three sets of files that must be compiled: the utility sources, the BFM sources and our testbench source.

TCL
# Compile UVVM Utils
quietly set compdirectives "-quiet -suppress 1346,1236,1090,1246 -2008 -work uvvm_util"
quietly set uvvm_utils_dir "./uvvm_light/src_util"
eval vcom $compdirectives $uvvm_utils_dir/types_pkg.vhd
eval vcom $compdirectives $uvvm_utils_dir/adaptations_pkg.vhd
eval vcom $compdirectives $uvvm_utils_dir/string_methods_pkg.vhd
eval vcom $compdirectives $uvvm_utils_dir/protected_types_pkg.vhd
eval vcom $compdirectives $uvvm_utils_dir/global_signals_and_shared_variables_pkg.vhd
eval vcom $compdirectives $uvvm_utils_dir/hierarchy_linked_list_pkg.vhd
eval vcom $compdirectives $uvvm_utils_dir/alert_hierarchy_pkg.vhd
eval vcom $compdirectives $uvvm_utils_dir/license_pkg.vhd
eval vcom $compdirectives $uvvm_utils_dir/methods_pkg.vhd
eval vcom $compdirectives $uvvm_utils_dir/bfm_common_pkg.vhd
eval vcom $compdirectives $uvvm_utils_dir/generic_queue_pkg.vhd
eval vcom $compdirectives $uvvm_utils_dir/data_queue_pkg.vhd
eval vcom $compdirectives $uvvm_utils_dir/data_fifo_pkg.vhd
eval vcom $compdirectives $uvvm_utils_dir/data_stack_pkg.vhd
eval vcom $compdirectives $uvvm_utils_dir/rand_pkg.vhd
eval vcom $compdirectives $uvvm_utils_dir/func_cov_pkg.vhd
eval vcom $compdirectives $uvvm_utils_dir/uvvm_util_context.vhd
# Compile UVVM BFMs
quietly set uvvm_bfm_dir "./uvvm_light/src_bfm"
eval vcom $compdirectives $uvvm_bfm_dir/*.vhd
# Compile the design
vlib work
vcom -2008 ./uvvm_axistream_slave_bfm.vhd
vsim uvvm_axistream_slave_bfm
add wave -position insertpoint sim:/uvvm_axistream_slave_bfm/*
run -all

The waveform shows that the slave BFM randomly de-asserts its ‘ready’ signal. Together with the random de-assertion of the ‘valid’ signal by the master interface, the UVVM BFM allows us to model the ready/valid handshake of the AXI4-Stream protocol with minimal effort.

In the simulation logs we can see the confirmation from the slave BFM that the received data matches the expected data. Of course, we knew this would be the case because we used identical arrays for the master and slave interfaces.

We now rerun our simulation after changing two or more values in the expected data array, and we can see that the slave BFM reports the mismatch. We can notice two interesting behaviors here:

  • The ‘axistream_expect’ procedure reports the number of mismatching bits between the received and expected arrays. It does so by flattening the arrays and comparing the bits one by one. One disadvantage of this approach is that it removes the word-based abstraction, that is, it is not possible to know at first glance which and how many words in the received array differ from the expected values.
  • The ‘axistream_expect’ procedure only reports the index of the first mismatching word in each AXI4-Stream packet. This can make it difficult to find patterns during the debugging process, because we would have to fix each error one by one.

If we would like to have more control over how the received data is checked against the expected data, we can replace the ‘axistream_expect’ procedure with the ‘axistream_receive’ procedure. In this case the BFM returns an array with the values sent by the master interface, but it is up to us to compare that data with the expected values. This gives us a much higher degree of control over how the checking is made, but it requires us to implement more custom logic.

VHDL
receive_data : process
  variable tdata_received_array_v         : t_slv_array(0 to 15) (7 downto 0);
  variable tdata_received_packet_length_v : natural;
  variable tuser_received_array_v         : t_user_array(0 to 15);
  variable tstrb_received_array_v         : t_strb_array(0 to 15);
  variable tid_received_array_v           : t_id_array(0 to 15);
  variable tdest_received_array_v         : t_dest_array(0 to 15);
  constant C_SCOPE                        : string := "RECEIVE PROCESS";
begin
  -- Receive data over AXI4-Stream
  axistream_receive(tdata_received_array_v, tdata_received_packet_length_v,
                    tuser_received_array_v, tstrb_received_array_v,
                    tid_received_array_v, tdest_received_array_v,
                    "Receive first packet of AXI4-Stream data", clk, s_axistream,
                    C_SCOPE, msg_id_panel, C_AXISTREAM_SLAVE_BFM_CONFIG_DEFAULT);
  -- Check the received data against the expected data
  for i in 0 to 15 loop
    if tdata_received_array_v(i) /= tdata_expected_array(i) then
      warning("Mismatch while checking the AXI4-Stream packet, Word " & to_string(i) &
              ". Expected 0x" & to_hstring(tdata_expected_array(i)) & ", received 0x"
              & to_hstring(tdata_received_array_v(i)), C_SCOPE);
    end if;
  end loop;
  log(ID_LOG_HDR, "AXI4-Stream Data received", C_SCOPE);
  wait;
end process receive_data;

The simulation transcript now shows one warning for each of the mismatches found in the AXI4-Stream packet, as well as the index of each mismatching word. This would be much more useful in a real-world debugging scenario.

Regardless of whether one chooses the ‘expect’ or ‘receive’ procedures, having a third-party, open-source, high-quality BFM for sending and capturing AXI4-Stream data is a great tool in our verification arsenal.

Cheers,

Isaac


Leave a Reply

Your email address will not be published. Required fields are marked *