UVM and Python
The Universal Verification Methodology (UVM) grew out of the Open Verification Methodology (OVM) which grew out of the Advanced Verification Methdology (AVM) which leveraged the SystemVerilog programming language.
Though this long lineage suggests that the UVM must be implemented in SystemVerilog, this is not the case. The UVM is a class library, and a class library can be implemented in any object oriented programming language.
pyuvm implements the UVM using Python. Creating testbenches using Python has several advantages over SystemVerilog:
The Python ecosystem is larger than the SystemVerilog ecosystem. More developers understand Python than SystemVerilog, and Python has a long tradition of being the language of choice for large-scale object oriented projects.
Python is object-oriented, even more so than SystemVerilog, and so it is easier to deliver functions such as overridable factories in Python than SystemVerilog.
Python runs without a simulator, and so is faster than SystemVerilog.
Python forces the testbench developer to separate simulated and timed RTL code from testbench code. This means that testbenches written with Python support accelerated testbenches with little, if any, modification.
While Python is an excellent testbench development language, the UVM is an excellent Verification Library. Implementing the UVM using Python gives us the best of both worlds.
Pythonizing the UVM
Much of the UVM specification in IEEE-1800.2-2017 is driven by elements of the SystemVerilog programming language. Blindly implementing all that is in the UVM specification is not only impossible (there are no parameters in Class declarations, for example), but also unwise.
Many elements of Python make it much easier to create testbench code using Python than SystemVerilog. For example, there are no arcane issues of typing, and Python readily provides generic tools for logging and interprocess communication.
Rather than attempting to mimic the UVM completely, this implementation focuses on delivering the functionality of the UVM, even if this changes the details of how functionality is delivered. This section examines some differences between the implementations.
Static Typing vs. Duck Typing
SystemVerilog is a statically typed language. You declare variables to be of
a certain type in the source code before using them. It is a relatively
weakly typed languaged (relative to VHDL). You can declare a variable to be
a short int
and another to be an integer
and still add them with no problem.
Python using Duck Typing, which is form of dynamic typing. Duck typing says
that if something looks like a duck, and acts like a duck, then we’ll consider it
a duck. That means we don’t declare a variable to be of type duck
, instead we
call duck.quack()
and see if we get an exception.
The UVM can be difficult to write because of its static typing. A lot of energy goes into parameterizing classes to get the behavior you want, that problem goes away in Python. Instead, you see runtime errors if you mess up the typing.
Exception Handling
Unlike SystemVerilog, Python provides the ability to raise and catch exceptions. While a SystemVerilog programmer needs to check to be sure that an action will work before attempting it, a Python programmer is more likely to try the action and catch an exception if it arises.
Uncaught exceptions rise through the call stack and eventually cause the Python to dump out the stack trace information and exit. Catching exceptions keeps the program from terminating.
pyuvm Exceptions
Review the documentation for the error_classes
module to see the Exceptions defined in pyuvm.
Coding differences between SystemVerilog UVM and pyuvm
The topics outline above lead to differences between the way pyuvm implements behaviors vs. how SystemVerilog does it. This section highlights these differences.
Underscore Naming
Python programs use camel casing to define classes, but pyuvm uses underscore
naming to match the IEEE specification. uvm_object
is named uvm_object
not UvmObject
.
Decorators and Accessor Functions
SystemVerilog UVM sets and gets variable values using accessor functions such
as set_name()
and get_name
. Python implements similar functionality using
the @property
decorator.
While pyuvm could have changed all the accessor functions to properties, it implements the IEEE 1800.2 spec and keeps the accessor functions.
uvm_object_wrapper
and Factories
SystemVerilog has relatively poor class manipulation mechanisms. Most of the class information has already been determined at compile time and dynamically creating objects of different classes, or overriding one class with another, requires considerable gymnastics.
Python, on the other hand easily handles classes. Classes are objects just like everything else in the language.
As a result, pyuvm does not need the macros we use in SystemVerilog to
register classes with the factory. It does not have uvm_object_utils or uvm_component_utils
macros. It registers all classes that extend uvm_void
with the factory.
Using Python functionality instead of UVM functions
The UVM defines methods that make up for SystemVerilog’s relative
immaturity relative to Python. For example uvm_object
defines
a get_type() method to get the type of an object. Python has a type()
function that does the same thing for all objects.
Therefore, pyuvm raises UsePythonMethod
if you call get_type()
.
uvm_policy
Class
The uvm_policy
Classes provide functionality that is built into
Python with the setattr
and getattr
methods.
There are no field macros and thus no need to implement this class.
Reporting Classes
We use Python logging instead of the UVM reporting system.