Minimal OSVVM Verification Environment
In this post we create a minimal, single-file verification environment using the OSVVM AXI-Stream Transmitter Verification Component.
In a previous post, we discussed how to get started with the OSVVM libraries for VHDL verification. We compiled the OSVVM libraries, ran one of the built-in AXI-Stream tests, and examined the architecture and file structure of the included test benches and test cases.
In this post, we will create a minimal, single-file verification environment using the OSVVM AXI-Stream Transmitter Verification Component (VC). By the end of this post, we'll be able to use OSVVM VCs in a custom testbench, without any dependencies on the other OSVVM components.
Compiling the OSVVM Libraries
We start by compiling the OSVVM libraries. You can find the instructions for that in the 'Compiling the OSVVM Libraries' section of the 'Getting Started with the OSVVM' post.
Running an example AXI-Stream Test
Next, we will create a local copy of the simulation files for an existing testcase. We will use the AXI-Stream 'SendGetRandom1' testcase. We need four files, all of which are included in the OSVVM sources:
- The DUT is described in the 'AxiStreamDut.vhd' file in the 'OsvvmLibraries/AXI4/AxiStream/testbench' folder
- The testbench is described in the 'TbStream.vhd' file in the 'OsvvmLibraries/AXI4/AxiStream/testbench' folder
- The testcase entity is declared in the 'TestCtrl_e.vhd' file in the 'OsvvmLibraries/AXI4/AxiStream/testbench' folder
- The testcase architecture is described in the 'TbStream_SendGetRandom1.vhd' file in the 'OsvvmLibraries/AXI4/AxiStream/testCases' folder
The working directory for our simulation should look like this:

Because we won't use the OSVVM simulation scripts to run our simulation, we will create our own script in the 'sim.do' file. However, before we do that, we need to make changes to two of the simulation sources:
- In the 'TestCtrl_e.vhd' file, we must remove the reference to the 'OsvvmTestCommonPkg'. This package does not exist as a standalone VHDL source; instead, the OSVVM test case simulation script creates it.
- In the 'TbStream_SendGetRandom1.vhd' file, we must remove the lines associated with the file logging and reporting:
TranscriptClose ;
if CHECK_TRANSCRIPT then
-- AffirmIfTranscriptsMatch(PATH_TO_VALIDATED_RESULTS) ;
end if ;
EndOfTestReports(TimeOut => (now >= 35 ms)) ; We have now lost the built-in reporting functionality, which is consistent with our goal of achieving a minimal testbench.
Now we must create a simulation script to run the simulation using our minimal file set.
vlib work
vcom AxiStreamDut.vhd -2008
vcom TestCtrl_e.vhd -2008
vcom TbStream.vhd -2008
vcom TbStream_SendGetRandom1.vhd -2008
vopt TbStream -o TbStream_opt
vsim TbStream_opt
run -allWe can now run the simulation from Questa's command line window. It is essential to have opened Questa in the same directory where we compiled the OSVVM sources, so that we can ensure the compiled libraries are mapped correctly.

Creating a minimal Testbench
After simulating with our custom script, our next step will be to create a custom, single-file testbench.
We begin by including all necessary libraries and declaring our Entity and Architecture.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.numeric_std_unsigned.all;
library std;
use std.env.stop;
library osvvm;
context osvvm.OsvvmContext;
library osvvm_AXI4;
context osvvm_AXI4.AxiStreamContext;
entity osvvm_axi_stream_tb is
end entity osvvm_axi_stream_tb;
architecture behavioral of osvvm_axi_stream_tb is
...
begin
...
end architecture behavioral;Then we add the signals and constants associated with the clock and reset.
-- Clok and Reset
signal clock : std_logic := '0';
signal reset_n : std_logic := '1';
constant CLOCK_PERIOD : time := 10 ns;
constant TPD : time := 1 ns;We now declare the data-related AXI-Stream constants and signals.
-- AXI-Stream constants
constant AXI_DATA_WIDTH : integer := 32;
constant AXI_BYTE_WIDTH : integer := AXI_DATA_WIDTH/8;
constant TID_MAX_WIDTH : integer := 1;
constant TDEST_MAX_WIDTH : integer := 1;
constant TUSER_MAX_WIDTH : integer := 1;
constant AXI_PARAM_WIDTH : integer := TID_MAX_WIDTH + TDEST_MAX_WIDTH + TUSER_MAX_WIDTH + 1;
constant INIT_ID : std_logic_vector(TID_MAX_WIDTH-1 downto 0) := (others => '0');
constant INIT_DEST : std_logic_vector(TDEST_MAX_WIDTH-1 downto 0) := (others => '0');
constant INIT_USER : std_logic_vector(TUSER_MAX_WIDTH-1 downto 0) := (others => '0');
-- AXI-Stream signals
signal tvalid : std_logic;
signal tready : std_logic := '1';
signal tid : std_logic_vector(TID_MAX_WIDTH-1 downto 0);
signal tdest : std_logic_vector(TDEST_MAX_WIDTH-1 downto 0);
signal tuser : std_logic_vector(TUSER_MAX_WIDTH-1 downto 0);
signal tdata : std_logic_vector(AXI_DATA_WIDTH-1 downto 0);
signal tstrb : std_logic_vector(AXI_BYTE_WIDTH-1 downto 0);
signal tkeep : std_logic_vector(AXI_BYTE_WIDTH-1 downto 0);
signal tlast : std_logic;We also declare the Stream Record signals, which we'll use to send transactions to (and retrieve transactions from) the AXI-Stream VCs.
signal stream_tx_rec : StreamRecType(
DataToModel (AXI_DATA_WIDTH-1 downto 0),
DataFromModel (AXI_DATA_WIDTH-1 downto 0),
ParamToModel (AXI_PARAM_WIDTH-1 downto 0),
ParamFromModel(AXI_PARAM_WIDTH-1 downto 0)
);
signal stream_rx_rec : StreamRecType(
DataToModel (AXI_DATA_WIDTH-1 downto 0),
DataFromModel (AXI_DATA_WIDTH-1 downto 0),
ParamToModel (AXI_PARAM_WIDTH-1 downto 0),
ParamFromModel(AXI_PARAM_WIDTH-1 downto 0)
);Now that the constants and signals have been declared, we can start describing our testbench logic. First, we generate our clock.
clock_gen : process
begin
wait for CLOCK_PERIOD/2;
clock <= not clock;
end process clock_gen;Then we instantiate the AXI-Stream Transmitter VC.
axi_stream_transmitter : AxiStreamTransmitter
generic map(
INIT_ID => INIT_ID,
INIT_DEST => INIT_DEST,
INIT_USER => INIT_USER,
INIT_LAST => 0,
tperiod_Clk => CLOCK_PERIOD,
tpd_Clk_TValid => TPD,
tpd_Clk_TID => TPD,
tpd_Clk_TDest => TPD,
tpd_Clk_TUser => TPD,
tpd_Clk_TData => TPD,
tpd_Clk_TStrb => TPD,
tpd_Clk_TKeep => TPD,
tpd_Clk_TLast => TPD
)
port map(
-- Clock, Reset
Clk => clock,
nReset => reset_n,
-- AXI Stream Interface
TValid => tvalid,
TReady => '1',
TID => tid,
TDest => tdest,
TUser => tuser,
TData => tdata,
TStrb => tstrb,
TKeep => tkeep,
TLast => tlast,
-- Testbench Transaction Interface
TransRec => stream_tx_rec
);And finally, we can write the main process, from where we will control the AXI-Stream Transmitter VC. First, we declare the auxiliary variables that we'll need.
axi_stream_transmission_proc : process
variable DelayCoverageID, DelayCovID_Random : DelayCoverageIDType;
variable base_word, burst_word : std_logic_vector(31 downto 0) := 32x"0";
begin
...
end process axi_stream_transmission_proc;Then we assert the reset signal for a few clock periods.
reset_n <= '0';
wait until rising_edge(clock);
wait until rising_edge(clock);
wait until rising_edge(clock);
reset_n <= '1';
wait until rising_edge(clock);Now we can start sending data. First, we call the 'SetRandomDelays' function to make sure that the AXI-Stream Transmitter VC inserts random reassertions of its 'tvalid' signal. Then we use the 'Send' function to pass the data that we want the VC to send to the DUT. TODO: what about TLAST? Finally, we wait a couple of cycles before stopping the simulation.
SetUseRandomDelays(stream_tx_rec, TRUE);
report "Transmit 256 words";
base_word := base_word + 32x"00010000";
for i in 1 to 256 loop
Send(stream_tx_rec, base_word + i);
end loop;
wait until rising_edge(clock);
wait until rising_edge(clock);
stop;Creating the Simulation Script
We use a different simulation script, which only contains the single-file test bench we just described.
vlib work
vcom -2008 osvvm_axi_stream_tb.vhd
vopt osvvm_axi_stream_tb -o osvvm_axi_stream_tb_opt
vsim osvvm_axi_stream_tb_opt
add wave -position insertpoint sim:/osvvm_axi_stream_tb/*
run -allRunning the Simulation
We can now run the simulation from Questa's command-line window. In the 'sim' panel on the upper left side, we can see that, instead of the example OSVVM testbench and test case, our minimal, single-file 'osvvm_axi_stream_tb' entity with the AXI-Stream Transmitter VC was simulated.

Cheers,
Isaac