Design Articles

A Practical Guide to Adopting the Universal Verification Methodology—Part 1

This article is excerpted from Chapter 4: UVM Library Basics from the newly published book A Practical Guide to Adopting the Universal Verification Methodology by Sharon Rosenberg and Kathleen A. Meade (Copyright 2010 by Cadence Design Systems). New installments of this chapter will appear every Monday for the next four weeks. If you can't wait--or want to learn more--the book is available at

By Sharon Rosenberg and Kathleen A. Meade, Cadence Design Systems

uvm book

The UVM is first and foremost a methodology and collection of best practices for functional verification. As mentioned before, the UVM library is a capable and mature enabler of this high-level methodology. While the library classes and engines can be used in arbitrary ways, we highly recommend following the UVM as prescribed in the following chapters, as they suggest a proven recipe for successful verification.

This chapter covers the mechanics and basic facilities of the library. It focuses on the features that are needed for most verification environments and their use model.
Note For simplification and educational purposes, the examples here do not necessarily follow UVM-recommended architecture or methodology.
The topics that are covered in the chapter are:

  • Using the UVM Library
  • Library Base Classes
  • TLM ports
  • Factory
  • Messages and reporting facilities
  • Configuration mechanism

4.1 Using the UVM Library

To use the UVM Library, a user needs to:

  • Compile the UVM package top file
  • Import the uvm _pkg into the desired scope
  • Include the UVM macros
4.1.1 Hello World Example
The following example displays the message “Hello World!” to the screen:

1 // Compile the UVM package
2 `include “”
3 module hello_world_example;
4    // Import the UVM library and include the UVM macros
5    import uvm_pkg::*;
6    `include “uvm_macros.svh”
7    initial begin
8        `uvm _info (“info1”,“Hello World!”, UVM _LOW)
9     end
10 endmodule: hello_world_example

Lines 1-2: The comment is a reminder to compile the UVM library. The is the top UVM library file that includes the rest of the UVM files into a single SystemVerilog package. Note that SystemVeriog packages need to be compiled outside of modules or other scopes. We recommend using a command line to compile it, as packages tend to be shared by multiple scopes and you do not want to bind the compilation of the package to a specific scope.

Line 5: When the library has been compiled, the user imports the package into any scopes that use the library features.<br>

Line 6: The UVM macros need to be included separately because they are compiler directives that do not survive multiple compilation steps. To avoid recompiling the entire library multiple times, they are included separately.

Line 8: The `uvm _info macro is part of the UVM message capabilities that allow printing, formatting and controlling screen messages. In this case, we just print the message “Hello World!”

4.1.2 Guidelines for Using the UVM Library
  • To prevent name collisions, avoid importing the uvm_pkg into the global scope. This is true for any package being imported.
  • The top UVM files are typically enclosed by the following:

`ifndef <FILE _NAME> _SVH
`define <FILE _NAME> _SVH
... body of the file

This allows including the UVM library from multiple locations and avoids multiple declarations by compiling the files only once. We recommend using this technique in the user’s UVC files.

  • To run this test on the Cadence® Incisive® Enterprise Simulator (IES) with the UVM package that is delivered with IES:

% irun -uvm

To use an alternate UVM, use:

% irun -uvmhome $UVM _HOME

4.2 Library Base Classes

The Figure 4-1 class diagram below represents selected classes of the UVM library. These classes provide automation that can be leveraged by deriving user-defined classes and customizing their behavior. In addition to automation, the base classes provide an API that enables uniformity and thus reuse.

uvm figure 1

Note We do not show the uvm _transaction class in this diagram. While this class is still part of the library, it was voted to be deprecated by the Accellera TSC.

In the following sections, we discuss the uvm _obj ect and uvm_component abstract classes.

4.3 The uvm_object Class

The abstract uvm_obj ect class is the base class for all UVM data and hierarchical classes. Its primary role is to define and automate a set of methods for common operations such as create, copy, pack/unpack, compare, print, and record. Classes deriving from uvm _obj ect must implement the pure virtual methods such as create() and get _type _name () . The code below demonstrates a simple example of an AMBA advanced peripheral bus (APB) transfer class definition that does not use the UVM object class definition.

Example 4–1 Non-UVM Class Definition

1 typedef enum bit { APB _READ, APB_WRITE} apb _direction _enum;
2 class apb_transfer;
3     rand bit [ 31:0] addr;
4     rand bit [ 31:0] data;
5     rand apb _direction _enum direction;
6    function void print();
7  $display("%s transfer: addr=%h data=%h",, addr,
8  endfunction : print
9 endclass : apb_transfer

The simple example above includes a print() method common to almost all transactions. Most data items require print, copy, compare, pack, unpack, and other utility functions. Leaving it up to the class developer to define the signatures of these services is an obstacle to reuse. The environment integrator will have to learn the signatures (names, parameters, return values) and behaviors of multiple classes coming from different resources. The UVM library solves this issue by introducing the uvm_obj ect base class that defines the signature of these commonly needed services. All objects in the testbench should be directly or indirectly derived from uvm _obj ect. The UVM SystemVerilog class library also includes macros that automatically implement the print, copy, clone, compare, pack, and unpack methods, and more.

Example 4–2 below shows the APB transfer class derived from UVM object.

Example 4–2 APB Transfer Derived from uvm_object

1 typedef enum bit { APB _READ, APB_WRITE} apb_direction_enum;
2 class apb_transfer extends uvm_object;
3     rand bit [ 31:0] addr;
4     rand bit [ 31:0] data;
5    rand apb_direction_enum direction;
6    // Control field - does not translate into signal data
7    rand int unsigned transmit_delay; //delay between transfers
8    //UVM automation macros for data items
9     `uvm_object_utils_begin (apb_transfer)
10      `uvm _field _int (addr, UVM _DEFAULT)
11      `uvm _field _int (data, UVM _DEFAULT)
12      `uvm _field _enum(apb _direction _enum, direction, UVM _DEFAULT)
13      `uvm _field _int(transmit _delay, UVM _DEFAULT | UVM_NOCOMPARE)
14    `uvm_obj ect_utils_end
15   // Constructor - required UVM syntax
16   function new (string name="apb _transfer");
18   endfunction : new
19 endclass : apb_transfer

Lines 9-14: The UVM automation macros

Lines 16-18: The constructor is not mandatory in data objects. If the constructor is used, it must have defaults for all of the arguments.

4.3.1 UVM Field Automation
The `uvm _obj ect _utils _begin (TYPE) and `uvm _obj ect _utils _end macros are used to declare
common operations declared for UVM objects.

  • Implements get _type _name () which returns the object type as a string
  • Implements create() which allocates an object of the specified type by calling its constructor
  • Registers the type with the factory so it can be overridden elsewhere in the testbench (more details on this later)
  • Implements a static get _type () method needed for the factory operation

The `uvm _field _* macros include the given fields in implementations of the print(), copy(), clone(), pack(), unpack(), compare(), and record() methods for an object. The automation supports nested objects and user customization. The syntax of the macros is:

Syntax: `uvm_field_*(fi el d_name, flags)

The field_name must be an existing property identifier of the class and flags specifies the automation required for that field. Flags are numeric and can be combined using the bitwise OR “|” or plus “+” operators. Syntax exists for objects, strings, events, real numbers, queues, and different types of arrays.

A wide variety of field automation macros is available; they are described in the UVM Reference Manual.

4.3.2 uvm_object Definition Guidelines
  • It is desirable to derive objects from uvm _sequence _item. Such derivation adds a few extra fields to the object, but allows the object to be randomized as part of a uvm _sequence.
  • Use UVM _DEFAULT as the flag argument (instead of UVM _ALL _ON) for all `uvm _field _* macros. This allows the UVM architects to add automation that by default might not be enabled by default. Other flags are used to remove undesired automation.
  • Set the class name as the default value in the constructor argument.
  • Do not forget to call super. new (name) as the first statement in every constructor declaration.
  • There is a different macro for classes that have type parameters `uvm_obj ect_param_utils*
  • `uvm_field_obj ect defaults to deep operations. If you are using a reference to another object, make sure to use the UVM _REFERENCE flag so that deep operations are not done.

Example 4–3 demonstrates additional usage of the field automation, including class composition and dynamic arrays. In this example, the yapp _packet has a pkt _header field.

Example 4–3 uvm_object Fields Automation

1 class packet_header extends uvm_object;  // Packet Header class
2     rand bit [ 5:0] length;
3     rand bit [ 1:0] addr;
4     `uvm_object_utils_begin (packet_header)
5       `uvm_field_int (length, UVM _DEFAULT)
6       `uvm _field _int(addr, UVM _DEFAULT)
7     `uvm_object_utils_end
8 endclass : packet_header
9 typedef enum bit { BAD _PARITY, GOOD _PARITY } parity_e;
10 class yapp_packet extends uvm_object;
11   // Physical Data
12    rand packet_header header; // pkt_header class contains: addr, length
13    rand bit [7:0] payload [] ;  // dynamic array in the range [1:63]
14    bit     [7:0]  parity;    // calculated in post _randomize()
15   // Control Knob
16    rand parity_e parity_type;  // randomized to determine parity type
17   rand int packet_delay;
18 // UVM macros for built-in automation - These declarations enable
19   // of the data_item fields and implement create() and get _type _name()
20    `uvm_object_utils_begin (yapp_packet)
21      `uvm _field _object (header, UVM _DEFAULT)
22      `uvm _field _array _int (payload, UVM _DEFAULT)
23      `uvm _field _int (parity, UVM _DEFAULT)
24      `uvm_field_enum(parity_e, parity_type, UVM _DEFAULT)
25      `uvm _field _int(packet _delay, UVM _DEFAULT | UVM_DEC | UVM_NOCOMPARE)
26    `uvm_object_utils_end
27   // Constructor - required syntax for UVM automation and utilities
28   function new (string name = "yapp_packet");
30 header = packet_header::type_id::create("header"); // allocation
using the factory
31    endfunction : new
32   endclass : yapp_packet

Line 1: header_packet is derived from uvm _obj ect

Line 21: If this were just a reference object, we would use the UVM _REFERENCE flag to avoid deep operations. The payload is a dynamic array and uses a special macro to print all the array items.

Line 24: Enumeration types syntax has an extra parameter: `uvm _field _enum(<enum _type>, <field_name>, <flags>)

Line 30: Instead of using “header = new ("header") ” we use the factory. The create() implementation is achieved by the `uvm_obj ect _utils macros and allows extending the transaction in other projects or tests. For more information about this, see “UVM Factory” on page 62.

4.3.3 UVM Object Automation Usage Examples
The following example demonstrates the built-in automation features in the UVM library. It assumes that apb_transfer was defined as shown in Example 4–2.

Example 4–4 UVM Object Automation Usage

1 module automation_example;
2    // Import the UVM library and include the UVM macros
3     import uvm_pkg: :*;
4    `include “uvm_macros.svh”
5    // Include the APB transfer class
6    `include “”
7    apb_transfer my_xfer, tx1, tx2, tx3;
8    initial begin
9       my_xfer = apb_transfer: :type _id: :create("my_xfer");
10      if (!my_xfer.randomize())
11       `uvm_fatal(“RANDFAIL”,”can not randomize my_xfer”)
12      tx1 = my_xfer;          // tx1 and my_xfer share the same memory
13     // Create a new apb_transfer
14      tx2 = apb_transfer: :type _id: :create("tx2");
15      tx2.copy(tx1);          // Copies fields from tx1 to tx2
16      $cast(tx3, tx1.clone()); // Creates a new apb_transfer and copy all
17                                //   specified fields from tx1 to tx3
18     if(!
19       `uvm_error(“CompareFailed”, “The comparison failed”)
20      my_xfer.print();        // Prints my_xfer in a table format
21      my_xfer.print(uvm_default_tree_printer); // Prints in “tree” format
22    end
23 endmodule: automation_example

To use the UVM library, you need to import the UVM package and include the uvm_macros.svh.

The example creates, randomizes, copies, clones, and prints an apb_transfer using the example code above. The macros will automatically implement a print() method for a table format and a tree format:

Default table format:


Name Type Size Value
my_xfer apb_transfer - @560
addr integral 32 'hb2cbb864
data integral 32 'heba598d7
direction apb_direction_enum 1 APB _WRITE
transmit_delay integral 32 'h6

Default tree format:

my_xfer: (apb_transfer@560) {
addr: 'hb2cbb864 data: 'heba598d7 direction: APB _WRITE
transmit_delay: 'h6

The printout below shows a randomized yapp_packet from Example 4–3 on page 40. The packet includes a header class object and a dynamic array for the payload. These values are easily formatted and printed in the table below.












































'hf 3





















The field automation macros will also implement a string print method, sprint(), which returns a string that can be used in a formatted display statement. The print formats are customizable; see the UVM Reference Manual for more details.

Note The table printer uses the most formatting and therefore is the most expensive in run time. If your simulation will be printing a large number of transactions, it is a good idea to use the tree format.

4.3.4 Using UVM Field Automation
Using the UVM field automation is optional. Though users can implement the set of routines on their own, we recommend using the automation macros. Using the macros provide:

  • Productivity—It takes time to implement the routines and the rich set of control options that they provide.
  • Extensibility—Adding a field in case of nested objects requires understanding the UVC original implementation and sometimes the logic is tricky, as opposed to the single line of field declaration of the macros.
  • Implementation consistency that is important for reuse—For example, if each developer implements their own format for the print() method, the poor integrator who uses multiple packages will have to analyze an inconsistent log file, where the field headers, values, radices, and structure are subject to the developer’s imagination.
  • Maintainability—Maintaining fewer lines of code simplifies the UVC developer’s job.
  • Code correctness—For large data objects, it is difficult to get all the logic for all the routines correct. A bug may show up at an inopportune time.

Keep in mind that these macros are an internal implementation of the library, are very mature, and should never be debugged by users. Debugging the default object print() methods is equivalent to debugging the internal $display function in the Verilog simulator.

In summary, we have seen users who initially were concerned about the usage of macros, but later became fans once they tried them, saying, “They just work!”

Next Week: the uvm_component Class

Bookmark and Share

Insert your comment

Author Name(required):

Author Web Site:

Author email address(required):


Please Introduce Secure Code: