UVVM stands for Universal VHDL Verification Methodology. UVM and SystemVerilog are the latest in market with their Advanced ASIC & FPGA Verification benefits, but they are definitely not the answer to all FPGA projects. For almost all companies using VHDL for their FPGA development it does not make sense to change to UVM for Verification. Hence, UVVM has been introduced specifically for VHDL which comprises of all the features and benefits that UVM/SystemVerilog offers. In fact, it provides an added major improvement called VHDL Verification Components (VVC).
VHDL2008 has been a major improvement on the language itself. OSVVM (Open Source VHDL Verification Methodology), which is an open source library, has excellent support for advanced random generation and functional coverage. Although we have both these critical features, debugging remains the most important aspect for large designs and debugging features are severely lacking in VHDL2008 and OSVVM. UVVM fills this gap. The Bitvis Utility library, which is also open source, provides great support for logging/reporting, verbosity control, alert handling, and pre-defined value and event checkers. Now, the Bitvis UVVM (Universal VHDL Verification Methodology) provides the most important verification methodology aspect, the Verification Component. A basic VHDL testbench using UVVM Utility library includes the following:
Logging and Verbosity Control
One of the advantages offered by UVVM is the ability to run simulation with greater or fewer simulation messages without the need to re-compile the design or test-bench. With UVVM messages, the user specifies Verbosity, not priority. The verbosity control helps users eye their designs and testbenches in depth with very little added code.
For example, log(msg_id,msg[…]); prints the message with the particular message_id if and only if that message_id’s verbosity has been enabled.
Alert Handling including optional positive acknowledge
This is another feature of UVVM which provides hierarchical alert reports for a hierarchy tree defined during run time. The alert summary is shown as a tree of defined scopes. The alert counter propagates up the tree to the top level and provides information to the users and thus keeps them updated.
For example, error(msg,[scope]); prints the error message if the simulation violates the scope.
Randomization is very important. It is nothing but driving random stimulus to the DUT by changing the characteristics of the data. Via randomization, hard to test corner cases can be reached. In UVVM, randomization can be done using very simple commands.
For example, command v_int = random(min_value,max_value); It generates an integer number between the range provided in the command.
BFM Support and Examples
To understand and go through the BFM examples and support, let’s first understand the definition of BFM. BFM stands for Bus Functional Model. It is a non-synthesizable software model of an integrated circuit component having one or more external buses. BFMs are usually defined as tasks in Hardware Description Languages, which applies stimulus to the DUT via complex waveforms and protocols. BFMs are often used as reusable building blocks to create simulation test-benches, where the signal ports on a design under test are connected to the appropriate BFMs in the test-bench for the purpose of simulation. They are also referred to as Transaction Level Models. Thus, BFM related support and examples too have been included as part of the UVVM package.
The basic idea of how coding changes using UVVM is given below using an example:
Handling transactions at a higher level (e.g. Read, Write, Send Packet, Configuration, etc…) becomes easy. So, if someone wants to write a 0xF0 into a register at address 0x22, it takes 7 steps to do so using normal vhdl while we can achieve that using UVVM in just 1 step. Below in Table 1 we can see that.
Thus, UVVM provides a simple bus interface. Apart from this, when it comes to bigger and complex designs, we need more interfaces, more simultaneous activities on interfaces ,value related corner cases and cycle related corner cases. All these cases cannot be achieved with the help of OSVVM alone as it does not support VVC. When we talk about the corner cases, to find them out using verification, we need more logic. Making it simpler, it would be nice if we have the freedom to :
Code any number of interfaces in a structured manner
Reuse major testbench elements between module testbenches.
Read the test sequencer almost as simply as pseudo code.
Recognize the verification specification in the test sequencer.
Understand the sequence of events just from looking at a single test sequencer.
To achieve all this, UVVM provides a structure called VHDL Verification Component. You should wonder what it is and how is it helpful! Let’s go through it.
A VVC is a self-contained verification solution for a particular protocol interface or logic function, compatible with UVVM. It is procedural, and at the same time provides Transaction level modeling. VHDL Verification Component basically works as an interface which takes commands from a sequencer and depending on the command, executes it towards the receiver end. VVC is a VHDL entity/component. It allows multiple threads, autonomous operation. It is controllable via commands and at the same time encapsulated. Thus, helps hiding the important information that we would not want to be disclosed via our testbench.
Fig 1 - VVC in a block-diagram
A sequencer command using VVC : sbi_write(SBI_VVCT,C_ADDR_TX,x”2A”); results in a BFM being executed from a VVC towards the DUT. VVC also allows simultaneous execution of BFMs on different interfaces. Specifically, the BFM procedure is a blocking transaction while VVC is a non-blocking transaction. Also, it is important to understand the subtle difference between the VHDL Verification Component and Bus Functional Model. VVC basically follows Command Distribution Method (CDM). So, the BFM is executed towards the physical DUT immediately, whereas a CDM is always used to only distribute executable commands to a VVC for execution there (often via BFM inside the VVC)- immediately or later. Hence, a CDM is never wiggling signals on a physical DUT.
A VVC is made up into 3 stages. Interpreter, Command Queue, and Executor. Interpreter is the one who receives the command from the sequencer. It checks whether the command is to be queued or not. If the command is to be queued then it is passed on to the 2nd stage Command Queue. From the Command Queue stage, it is passed on to the Executor stage where the command calls the relevant BFM and executes the transaction. The biggest advantage of such workings in the VVC is the fact that more than 90% of code and its structure remain same in interpreters and executor both apart from BFM calls.
Fig 2 - VVC Architecture
The first step to get started with UVVM in Riviera-PRO is to download UVVM. You can download UVVM from the Bitvis website. Here is the link to download UVVM’s latest version. http://bitvis.no/products/uvvm-vvc-framework/. The latest version of UVVM includes a VVC Framework and Utility library, Various VHDL Verification Components, UVVM-OSVVM Support, Test-bench overview and coordination and many more. The following are the exact steps one needs to take in order to download UVVM and run it successfully.
Go to the link provided above and download the latest UVVM version available.
Unzip the UVVM download which you obtained from the UVVM website.
Open Riviera-PRO -> Create a Workspace -> Create a Design and compile files.
Note :- This document reflects the working of UVVM in Riviera-PRO. If you need introduction with the licensing/downloading/features of the Riviera-PRO then click on the link below to know more. https://www.aldec.com/en/products/functional_verification/riviera-pro
To know more about Riviera-PRO, Click below. https://www.aldec.com/en/support/resources/documentation/articles?type=&products=2&category=1&sub_category=&submit=Browse
In Riviera-PRO, individual designs along with their resources can be grouped together as a workspace. The workspace allows adding and working with several designs simultaneously.
Go to File | New and click Workspace. The new Workspace wizard starts.
Type the workspace name and select the location where you want to create the project.
Click the OK button when you are done.
Fig 3 - Creating a Workspace named 'work'
A new workspace will be created. Now right-click on the workspace option and go to Add | New Design. The following window will pop up.
Fig 4 - Creating a design named 'work'
Click the Finish button when you are done.
The Design Manager now shows a workspace name and a new design attached to it.
Fig 5 - Design Manager
To create a new file, existing file or to create a directory, right click anywhere into the design manager window and click Add | New file.
You can also use File | New menu to open a new file and save it to design.
In our case, we are using the example provided by Bitvis called ‘bitvis_irqc’. To open it, right click in the design menu, Add -> Existing File and change directory to where you have downloaded the UVVM files and add it to your current design.
Fig 6 - Adding a new file
After you add every design files and testbench, also make sure to add necessary libraries provided as part of the VVC_Framework download. Now, once you attach those libraries to the library configuration of Riviera-PRO, it is important to refresh those libraries as they may be pre-compiled with an older version of Riviera-PRO.
Compilation is a process of analysis of a source file. Analyzed design units contained within the files are placed into the working library in a format understandable to the simulator.
If you want to compile a single file, go to the Files in the Design Manager, right click the file and choose compile from the shortcut menu.
If you choose compile all by right clicking the Design tab for a given design, the compiler automatically reorders the source files to ensure proper sequence in which design units are compiled.
Fig 7 - Compilation Message in Console Window
Once all needed design units have been compiled successfully, you can initialize simulation. Before you initialize simulation, make sure that:
You have selected the top level design unit.
If you run the simulation without any top-level unit selected, simulator will prompt you with a dialog box to select one.
To begin the simulation process, you must choose Initialize Simulation from the Simulation window. The command launches elaboration and initialization of the simulation model. During elaboration, the simulator loads design units and builds the simulation model in the computer memory. During the initialization, all objects in the model acquire their initial values and all concurrent processes are executed once until their suspension.
Fig 8 - Simulation Initialization
Fig 9 - Hierarchy Window
Go to Debug window and set your testbench as your top-level hierarchy. Once you choose that, the Hierarchy window will pop up.
Once you get that, right click on your testbench module and choose Add to | Waveforms option. The waveform window will pop up.
You can run the simulation by choosing the run option from the Waveform window options.
To finish the simulation session, choose Stop simulation from the simulation menu.
You can restart the simulation by selecting Restart option from the simulation menu.
Fig 10 - Stopping/Restarting Simulation
After following all the steps above, you might see the results into a waveform file as per below.
To save a waveform file or to manipulate the current waveform settings, you can go and select the Waveform menu options.
Fig 11 - Waveform Viewer
 Espen Tallaksen, “What is UVVM?”, Bitvis, Asker, Norway,2016
 Espen Tallaksen, “UVVM now includes OSVVM”, Bitvis , Asker, Norway,2016