The first thing that we think about is how to print out messages. In SystemVerilog, we had a very simple method to print out messages to the console.
$display ("%t addr = 0x%0h data = 0x%0h", addr, data);
The problem here is how to distinguish if a message is informational, debug, warning, error or fatal. Also, it's difficult to maintain consistent format across different files. The reporting classes provide a facility for issuing reports with consistent formatting. Users can configure what actions to take and what files to send output to based on
report severity, ID, or both severity and ID. Users can also filter messages based on their verbosity settings.
The basic building blocks for any verification environment are the components (drivers, sequencers, monitors ...) and the transactions (class objects that contain actual data) they use to communicate. From the UVM hierarchy, we can see that most of the classes in UVM are derived from a set of core classes that are described below.
Most projects try to re-use verification components that are already developed. But, inorder for them to just plug-in an existing piece of code, it should be compatible with the current testbench set-up. Let's say you have written a driver class that can only drive signals to follow PCI Express, then you cannot use the same class to drive signals to follow AXI protocol. To make the driver class re-usable, you probably need to have a function that can accept an argument that specifies the protocol the driver needs to follow. That's how you make it re-usable in simple terms. The main component of any testbench is the data/transaction that all verification components use to send and receive from DUV.
Modeling Data Items for Generation
Every user defined data item must be derived directly or in-directly from uvm_sequence_item
.
uvm_void
virtual class uvm_void;
What is UVM ?
SystemVerilog is a language just like Verilog and has its own constructs, syntax and features, but UVM is a framework of SystemVerilog classes from which fully functional testbenches can be built. There's only one prerequisite to learn UVM, and that is SystemVerilog because it is the foundation for the tower that is UVM.
Click here to refresh concepts in SystemVerilog !
Why do we need UVM ?
The primary advantage is that the methodology specifies and lays out a set of guidelines to be followed for creation of verification testbenches. This will ensure testbench uniformity between different verification teams, cross-compatability between IP and standalone environment integration, flexibility and ease of maintaining testbenches.
For example, there can be many different ways to implement display messages and control verbosity with different settings such as warning, error and debug. In UVM, the underlying reporting mechanism has been standardized and made available so that engineers can instead focus on the most important part of their job which is design verification. Another example is that the sequencer-driver handshake mechanism is taken care of under the hood so that only stimulus needs to be written. This saves quite a lot of time in setting up a testbench structure since the foundation itself is well defined.
How does UVM help ?
Every verification testbench has a few key components like drivers, monitors, stimulus generators, and scoreboards. UVM provides a base class for each of these components with standardized functions to instantiate, connect and build the testbench environment. These are static entities called components in a verification environment that exist throughout a simulation just like buildings in a city. These components operate and process on some kind of data that flows around the environment similar to people and vehicles in the city. The data or transactions are called objects or sequence items since they appear and disappear at various times in the simulation and is more dynamic in nature.
What is the UVM class hierarchy ?
UVM provides a set of base classes from which more complex classes can be built by inheritance and adding onto it certain functions required for verification environment. For example, a new driver class for AXI bus protocol can be built by extending from the UVM base class uvm_driver
. Stimulus for the protocol can be written by extending from uvm_sequence_item
. How this sequence is built, and handed over to the driver is taken care of internally by the UVM framework.
uvm_object is the main class in which common functions to print, copy, and compare two objects of the same class are defined.
There are two branches in the hierarchy :
- Under uvm_component: Classes that define verification components like driver, monitor and agents.
- Under uvm_transaction: Classes that define data objects consumed and operated upon by verification components.
Major UVM class categories
UVM Objects
The idea behind UVM is to enhance flexibility and reuse code so that the same testbench can be configured in different ways to build different components, and provide different stimulus. These new user defined configuration classes are recommended to be derived from uvm_object
. For example, a configuration class object can be built to have certain settings that define how the testbench environment has to be built.
Read more about UVM Object !
UVM Sequence
UVM also introduces the concept of a sequence which is nothing but a container for the actual stimulus to the design. If you put different stimuli into different sequences, it enhances the ability to reuse and drive these sequences in random order to get more coverage and verification results. All new user defined stimulus classes are recommended to be inherited from uvm_sequence
.
Each sequence can be used inside other sequences to create different scenarios. For example, individual sequences can be created, one each for "read" and "write" transactions. They can be used in a random pattern in some other sequence to perform R->W->R->W, or R->R->R->W, W->W->R->R and other similar patterns.
Read more about UVM Sequence !
UVM Sequence Items
Data objects that have to be driven to DUT are generally called as sequence items and are recommended to be inherited from uvm_sequence_item
. For example, a sequence item class can be defined for an APB transaction that defines what the address, write/read data and access type should be and send it to an APB driver to drive the transaction to DUT.
UVM Components
All major testbench components are derived from the corresponding base class. For example, all new user defined driver classes are recommended to be inherited from uvm_driver
and monitor classes from uvm_monitor
and so on. A brief description of what each UVM component does is given in the table below.
Component | Purpose |
---|---|
uvm_driver | Drive signals to DUT |
uvm_monitor | Monitor signals at DUT output port |
uvm_sequencer | Create different test patterns |
uvm_agent | Contains the Sequencer, Driver and Monitor |
uvm_env | Contains all other verification components |
uvm_scoreboard | Checker that determines if test Passed/Failed |
uvm_subscriber | Subscribes to activities of other components |
Read more about UVM Component !
Register Layer
Digital designs support control registers that can be configured by software, and this has been very challenging in a SystemVerilog testbench, because for each project you had to build a separate set of classes that can store and configure these registers. UVM has an extensive set of classes to make that task relatively simpler and belong to something known as a register model. This is very useful in the verification of IPs that can be reused in various SoC designs.
Read more about UVM Register Layer !
TLM Connections
Another really smart feature is the use of TLM from System C. TLM helps to send data between components in the form of transactions and class objects. It also brings a way to broadcast a packet to its listeners without having to create specific channels and attach to it.
Read more about UVM TLM !
UVM Phases
Another main feature that verification components inherit from their parent class uvm_component
is Phasing. This enables every component to sync with each other before proceeding to the next phase. Phases are covered in the next chapter. Every component goes through the build phase where it gets instantiated, connects with each other during the connect phase, consumes simulation time during the run phase and stops together in the final phase.
Read more about UVM Phases !
Summary
Class | Description |
---|---|
uvm_object | Define methods for common operations like copy, compare and print. Typically used to build testbench and testcase configurations. |
uvm_component | All testbench components like driver, monitor, scoreboards, etc are indirectly derived from this class |
uvm_sequence_item | All sequence items that need to be sent to a driver to be driven onto the bus are extended from this class |
uvm_sequence | All sequences that define the stimulus or testcase are extended from this class |