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 Wishbone 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_void is the base of all classes, but it is primarily empty.
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. The first one contains classes that define verification components like driver, monitor and the rest shown in the diagram as everything underneath
uvm_report_object. The second one defines data objects consumed and operated upon by verification components shown in the diagram as everything underneath
Major UVM class categories
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.
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
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.
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.
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.
| ||Drive signals to DUT|
| ||Monitor signals at DUT output port|
| ||Create different test patterns|
| ||Contains the Sequencer, Driver and Monitor|
| ||Contains all other verification components|
| ||Checker that determines if test Passed/Failed|
| ||Subscribes to activities of other components|
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.
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.
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.
Recap on major classes
| ||Define methods for common operations like copy, compare and print. Typically used to build testbench and testcase configurations.|
| ||All testbench components like driver, monitor, scoreboards, etc are indirectly derived from this class|
| ||All sequence items that need to be sent to a driver to be driven onto the bus are extended from this class|
| ||All sequences that define the stimulus or testcase are extended from this class|