How OOP Features of DVT Eclipse IDE Help With UVM Development
Overview
UVM makes extensive use of the object-oriented programming capabilities of SystemVerilog.
This video walks you trough the abundance of DVT features that help you survive and thrive in OOP code, with an emphasis on how to employ them in the development and debugging of UVM testbenches.
Explore the design and verification tools: https://www.dvteclipse.com
Or request a license: https://www.dvteclipse.com/request-license
This video was shot using DVT 20.1.31
Details
The DVT Eclipse IDE has a lot of features specifically designed for working with UVM testbenches. The UVM Browser and Verification Hierarchy views serve as main entry points for navigating, exploring, and understanding a UVM-based testbench. The UVM Sequence Call Tree helps you quickly understand and visualize how a complex sequence unfolds. Various visualization techniques are also available. UVM Component Diagrams help you understand the composition of the testbench, and the UVM Reg Bitfield Diagrams conveniently illustrate how the fields of a register come together. In the realm of editing capabilities, the UVM Field Editor helps you instantly create and update field registration macros.
But is this all the help you get from DVT when dealing with UVM test benches? Of course not. Even the basic features of DVT are of great value in the context of a complex verification environment, all the more so in a UVM-based one. The UVM library makes extensive use of the object-oriented capabilities of SystemVerilog, and DVT has loads of features helping you survive and thrive in OOP code.
Browsing Type Hierarchies
Using the Quick Type Hierarchy View
To see the type hierarchy of a class, simply place the editor cursor on its name and press Ctrl+T
. This brings up the Quick Type Hierarchy view, which shows you all its parents and children. Type just a few letters to filter the view, move up and down using the arrow keys, and press Enter
to go to source.
Many other views that DVT provides are also available in this quick mode, especially convenient when you are in a heavy coding phase and perhaps working with maximized editors that fill up all the screen space. In such a context, the quick views can help you move and peek around with minimal distraction. The view can also be brought up from the editor's context menu, under the Show section. By the way, this stands for most of the views provided by DVT, and is perhaps the most convenient route until you get familiar with the shortcuts.
Using the Type Hierarchy View
Now let's also take a look at the Type Hierarchy view, which is populated using the F4
keyboard shortcut. The upper panel is similar to the Quick Types view, with a few extra twists and turns. You can choose to see only the superclasses or only the subclasses of the selected one. Superclass hierarchy is particularly interesting when working with interface classes, since an entire tree of implemented interfaces can unfold above a class.
Anyhow, going back to the particularities of UVM, let's look at an example which combines inheritance with parameterization. Type parameters can make an inheritance chain pretty hard to follow. Let's look at the case of a uvm_sequencer
. The extended type is actually parameterizable, and the view shows each individual parameterization. Similarly, for the uvm_reg_sequence
, which actually extends a type parameter. Although such a hierarchy is pretty mind-twisting and requires thorough knowledge of the codebase to fully understand, it becomes manageable when presented in the Type Hierarchy view.
The lower part of the view shows all the fields, methods, and events of the class which is currently selected in the upper panel. You also have the option to include all the inherited members, basically listing all the API available in a class. The quick search bar will come in handy at this point. Where does the get_initiator()
API of the sequence come from? The declaration of each member in the list is conveniently displayed between square brackets, and the answer to our question is immediately available: it's the uvm_transaction
.
You can also configure what types of members are shown in the lower panel. For example, you can focus only on the fields. Furthermore, you can control the visibility of predefined API. And you can easily filter out the non-public members, such as this protected function, for example. By the way, a tiny colored square on the top left of each icon indicates the class member's visibility level: red for local, blue for protected, and green for public.
Since we're talking about filters, there's also a quick way to filter out the UVM-related members, for example, all the bits and pieces behind UVM registration macros. Unless you are specifically digging through the UVM internals, these entries are just cluttering up the view. Simply press the Content Filters toolbar button to throw them away, or to bring them back whenever needed.
Using UML Diagrams
As the saying goes, an image is worth a thousand words, and DVT excels when it comes to visualization techniques. The Unified Modeling Language (UML) was devised in the software world to provide a standard way for visualizing classes, along with their members, as well as relationships among classes, such as inheritance and association.
To see the UML diagram of a class, simply place the editor cursor on its name, right-click and choose Show Diagram. The selected class is highlighted in yellow. Parents and children are connected with a solid arrow, while associations are shown with a dotted arrow.
Customizing UML Diagrams
To customize the diagram, click on the Preferences toolbar button. For example, you can show all parents and children, leaving out associations, in order to get a plain inheritance diagram. Right-click on any white box, say the uvm_monitor
, and choose Select Type to dynamically expand the diagram. In this example, we obtained the inheritance tree of all monitors. Or you can use the Selected Types toolbar button to fully configure the selection of classes included in the diagram. For example, all the *_env
classes and the apb_subsystem_tb
class.
Double-click on the diagram's title bar to maximize it.
Now let's say you want to switch focus to associations instead of inheritance. Include all public methods and draw the diagram from left to right. From the context menu, you can also jump to the definition in the source code. Or you can activate the embedded Inspect panel, which conveniently shows a source code snippet with the declaration of the currently selected diagram element.
Apart from the visual exploration benefit, you can also use the UML diagrams for documentation purposes. Click the Save As toolbar button to export the diagram to a file, which you can share or embed in a document.
Working with Method Overrides
Browsing Method Overrides
Now let's head back to the editing capabilities of DVT. An essential feature of SystemVerilog is the ability to override the behavior of virtual class methods. This capability stands at the core of UVM and is probably the main mechanism used for customizing the behavior of testbench components.
However, across an inheritance chain, not all the children provide customized implementations. Many times you might wonder if there are any subclasses overriding a specific function or task, or where exactly in the upper hierarchy is another implementation provided. Let's take this run_phase()
, for example. To quickly get an answer, use the Quick Type Hierarchy shortcut — Ctrl+T
— but on the method name this time. The view pops up, presenting the hierarchy of all the classes relevant for the method. The class where the method is declared and all the classes that provide an override are colored, while the others are shown in gray.
Now, let's see if we can do this faster. Hold down the Ctrl
key and hover over the method name, or place the editor cursor on it and press Ctrl+F3
. A pop-up shows various navigation options, including two convenient shortcuts for Open Super Implementation and Open Child Implementation. The latter takes you directly to the child implementation if there's only one, or pops up the Quick Type Hierarchy if multiple are available.
Another fast indication for method overrides is available right in the editor to the left side of methods. Like you can see in this group of methods, some have green triangles pointing up, and some don't. At just a glance, you can tell which are overrides — the annotated ones. Hover the annotation with the mouse cursor to get more information, or click to jump to the overridden method.
Overriding Methods Using Autocomplete
Typically, when you develop a UVM component, you need to override some of the UVM phases. This is something you probably do tens of times while building a verification environment, so here's how to quickly do it in DVT: place the cursor in the component where you want to insert the phase task, type a few letters of the phase you wish to override, press Ctrl+Space
, pick the method you wish to override and hit Enter
. A method stub is inserted in the editor, with the full method signature automatically computed. Furthermore, a reminder is conveniently placed in the body of the method, so you don't forget to fill in the actual functionality.
DVT scans the code for pragmas such as TODO
, or FIXME
, or even custom user-defined pragmas, and centralizes all of them in the Tasks view.
Overriding Methods Using the Wizard
When you want to override a bunch of methods at once, it's best to use a more sophisticated UI — the Override Methods Wizard. Type a few letters of the method or methods you wish to override, say phase
in our case, press Ctrl+Space
, then pick the first entry in the list. This wizard presents you all the virtual methods that you may want to override (of course, excluding the ones which are already overridden) from across the whole upper inheritance chain of the current class. However, the word we've started from is used to filter out the list. Of course, you can clear the filter, or trigger the wizard without typing anything, or even trigger it from the editor's context menu to see all the methods you might want to override. Notice that by unchecking Show Only Virtual Methods, you can also create methods that shadow their superclass non-virtual counterparts. This is generally not considered good practice, but in case you ever need to do it, DVT won't have you write it by hand.
As always, there are some exceptions to the rules. Although not per se virtual methods, pre_randomize()
, post_randomize()
, and new()
are always shown in the list, since they are possible candidates for implementation. The other checkbox in this wizard allows you to control how the new methods will be inserted in the code: within the class body, or as an extern
declaration plus out-of-body implementation. As you can see, multiple methods can be overridden at once, making for a very efficient time saver.
Conclusion
The object-oriented capabilities of SystemVerilog make it a very powerful language. The UVM builds even further on top of this solid foundation. Writing and debugging a complex verification environment can prove to be quite a challenging task. DVT Eclipse provides an abundance of features that help you quickly and efficiently understand, visualize, navigate, and write code.