Using a verification framework can dramatically improve the quality of our designs. However, setting up a verification framework from scratch can be quite daunting. Luckily, there are open-source libraries that handle most of the infrastructure required for creating, running and managing our tests, so that we can focus on the parts of our testbench that are unique to our design and add value to our development process.
What is VUnit?
VUnit is a open-source unit-testing framework for digital systems design with VHDL and SystemVerilog. It provides the infrastructure for creating and managing verification environments so we can focus on writing meaningful tests. At its core, VUnit provides a Python-based test runner that manages our test cases, handles compilation dependencies, and produces structured test reports.
In addition to automating the simulation runs and test management, VUnit also provides several libraries to help write our testcases. These libraries include verification components, logging echanisms, check procedures, and randomization. By leveraging these pre-built components we can make the testcase-creation process more efficient, less error-prone, and - quite frankly - more enjoyable.
Prerequisites for Setting up a Verification Environment with VUnit
There are two prerequisites for using VUnit: we must have a supported VHDL simulator and we must have a Python installation (including a package manager and a tool for creating virtual environments).
VUnit supports several simulators, a comprehensive list can be found in the VUnit documentation. For this example we will use GHDL. In Ubuntu 24.04.1 LTS we can install GHDL using the Snap packet manager.
|
|
Once we have our simulator, we can install the VUnit Python module. The recommended way to do this is within a Python virtual environent. If we’re using venv
we can do this from the terminal by moving into the folder where we’ll run our simulations and using the commands shown below.
|
|
We are now ready to create our verification environemnt.
Setting up a minimal Verification Environment with VUnit
A VUnit verification environment includes, at the very least, two files: a testbench and a simulation script.
This is what a VUnit testbench in its simplest form looks like, as described in the VUnit User Guide.
|
|
We must pair our testbench with a simulation script, which in its minimal form looks like this:
|
|
We can run the simulation script from the command line.
|
|
The terminal output confirms that the test was run succesfully. Line 4 shows the location of the file where all the messages in our testbench are logged.
|
|
Our testcase executed a single statement - printing “Hello World!” to the output file.
|
|
Using AXI-Stream Verification Components
In a future post we will use this simulation environment to test an audio processing pipeline using AXI-Stream buses to transfer the audio data between modules. VUnit includes Verification Components with support for several standard interfaces, including AXI-Stream.
To get started, we include the vu.add_verification_components()
statement in our simulation script to add support for the Verification Components.
|
|
We can now expand our existing testbench by adding one AXI-Stream Master and one AXI-Stream Slave Verification Component. First we add all the signals and constants that we’ll use to configure and connect the verification components.
|
|
Then we can add the Verification Components themselves.
|
|
We are now ready to generate - and capture - data over the AXI-Stream bus. To do this we must expand our ‘main’ process to start the data transmission and reception in the AXI-Stream Verification Components.
|
|
At this point we can simulate our expanded testbench. Because I’m using GHDL as my simulator, I’ll include an argument that creates a VCD waveform in the simulation script.
|
|
Wer can finally see the results of our simulation. For this example I’m using Surfer as a waveform viewer. Surfer is a VSCode extension, which allows us to visualize our waveforms without leaving the code editor.
Zooming in at the start of the simulation, we can see that the tvalid
and tready
signals of the AXI-Stream bus are toggled by the Verification Components. For this they use the parameters we set when we declared the m_axis
and s_axis
constants for the AXI-Stream Master and Slave interfaces, respectively.
Summary
The goal of this post was to create a minimal simulation environment with VUnit that included driving a monitoring AXI-Stream interfaces.
We started with a minimal VHDL testbench and Python simulation script, which we used to create a bare-bones ‘Helo World!’ simulation. We then expanded the simulation script to include the VUnit verification components in our environment and added the logic required for instantiating, connecting, and using the Verification Components in our testbench. Finally, we ran our simulation and confirmed that our verification environment worked by inspecting the generated waveform.
Cheers,
Isaac