Learn to verify complex RTL designs using Python, cocotb, and pyuvm.
Python for RTL Verification by Ray Salemi uses downloadable code examples to teach you the basics of Python, testbench development with cocotb, and advanced verification using pyuvm.
Learn the dominant Universal Verification Methodology (UVM) using Python, the world's most popular programming language. Prepare for your next verification interview by being able to develop advanced testbenches in Python and quickly understand SystemVerilog/UVM testbenches.
Read Python for RTL Verification today and add this popular language to your verification arsenal.
Buy Python for RTL Verification at Amazon in Kindle and Paperback
Since it was released in 2011, the SystemVerilog version of the Universal Verification Methodology (UVM) has become the de facto standard in RTL verification. The UVM allows engineers to reuse testbenches, testbench components, and their testbench expertise across the industry. If you're applying for a job as an RTL verification engineer, it is likely that you'll be tested on your UVM knowledge.
While the UVM was originally designed with SystemVerilog in mind, that decision limits its accessibility and growth. SystemVerilog is a large and difficult language. It is a combination of Verilog, e, Vera, and a subset of object-oriented (OOP) concepts. It runs only on expensive simulators, so it is difficult to learn and run.
However, the IEEE 1800.2 standard does not have to be implemented in SystemVerilog. It can be implemented in Python. And so pyuvm was born. It combines a fresh implementation of IEEE 1800.2 with the popular cocotb package to allow you to write UVM that runs Python with almost any RTL simulator.
I've implemented a UVM driver in both SystemVerilog UVM (SV-UVM) and pyuvm. ( A driver is part of the UVM sequencing system and something that you'll likely be tested on in a job interview. ) We'll use this component to discuss elements of pyuvm and the differences from SystemVerilog UVM.
The sequence system in the UVM is critical for creating reusable stimulus and verification IP (VIP). pyuvm implements this critical functionality. Because pyuvm is a clean implementation of IEEE 1800.2 (vs. a script-generated copy), I was able to refactor some systems, such as sequences in Python, to make them simpler and more supportable.
The UVM sequencing system in pyuvm acts exactly like the SV-UVM sequencing system.
The drivers in both SV-UVM and pyuvm extend uvm_driver. However, the pyuvm version does not have to declare the sequence_item type using parameterization.
The SystemVerilog driver needs the `uvm_component_utils macro to register the driver class with the factory and provide other features. pyuvm registers all classes that extend uvm_void with the factory automatically, and Python provides the other features.
Python does not have mandatory typing, so you don't need to declare variables such as bfm in this example.
This line uses a long, parameterized incantation that reads a handle to the BFM from the uvm_config database. pyuvm refactors the uvm_config_db into a class named ConfigDB that implements the same behavior more easily. If this code were written in Python with pyuvm it would look like this:
self.bfm = ConfigDB().get(self, "", "bfm")
The Driver class in this example does not use the ConfigDB to get the TinyAluBfm object. Instead, it instantiates the object knowing that the TinyAluBfm uses the pyuvm.Singleton metaclass.
class TinyAluBfm(metaclass=pyuvm.Singleton):
def __init__(self):
self.dut = cocotb.top
<snip>
Using the pyuvm.Singleton metaclass means that the first time you instantiate a TinyAluBfm, you get a new object, but subsequent instantiations get the same object. This is a clean way to share an object across the testbench. Also, notice that the TinyAluBfm gets a handle to the RTL top from cocotb instead of the uvm_config_db.
The SystemVerilog task keyword and Python async keyword both designate functions that consume time. Since pyuvm implements the UVM, all pyuvm uvm_components implement a run_phase. Both implementations use the uvm_item_port.get_next_item() task to get the next uvm_sequence_item. The fact that get_next_item() can block is clearer in Python because of the await keyword.
Both implementations use the bfm.send_op() task to send the command to the ALU, though the Python version does not wait for the result. Both get the result back from the BFM and use seq_item_port.item_done() to request the next item.
(SV Line 38) Spurious new() function in SV-UVM
All components and objects in SV-UVM need a new() function because they cannot inherit new() from their parent class. Python does not need this.
These resources augment Python for RTL Verification to help you get started using pyuvm.
Download and run all the code examples in the book using Linux, Windows, or MacOS (Icarus!)
Clone the example repository from GitHub and pull new versions
Visit the example repository to download the latest version of the examples.
You can download the latest version of pyuvm and participate in its development by going to http://www.github.com/pyuvm/pyuvm.
Github Pages contains the latest documentation for pyuvm, including a complete API reference guide.
Subscribe to the Ray Salemi on RTL Verifiation substack to get notified of updates to the examples, and to receive insights about RTL Verification.
Get your Python, cocotb, and pyuvm questions answered on the Python for RTL Verification Github discussion group.