UVM Macros, Messaging and UVM Reporting:

Macros: The UVM Library has built-in utility and field automation macros that allow objects to be created by the factory and have access to common functions such as copy( ) or clone( ). To understand how the macros work, let’s build a simple data packet for the DUT. If we were not using the UVM, a typical packet may have looked like the following:

class packet;
  rand bit enable;
  rand bit [14:0] data_in;
  rand bit [14:0] data_out;
  rand int delay;
  
  constraint timing {delay inside {[0 : 10]};}
endclass : packet

Here is a standard SystemVerilog class with several random data members and one constraint block. Now, let’s build the UVM version of above mentioned packet class

class packet extends uvm_sequence_item;
  rand bit enable;
  rand bit [14:0] data_in;
  rand bit [14:0] data_out;
  rand int delay;
  
  constraint timing {delay inside {[0 : 10]};}
  
  `uvm_object_utils_begin(packet)
    `uvm_field_int(enable,   UVM_DEFAULT)
    `uvm_field_int(data_in,  UVM_DEFAULT)
    `uvm_field_int(data_out, UVM_DEFAULT)
    `uvm_field_int(delay,    UVM_DEFAULT)
  `uvm_object_utils_end
  
  function new(string name = "packet");
    super.new(name);
  endfunction
  
endclass : packet

The class is now derived from uvm_sequence_item. Every data item that you create must be derived from this base class directly or indirectly. In addition to our data members, we added the utility and field automation macros.

Adding the macros looks like extra code, but it allows lots of other UVM library code to copy, clone, etc. this object. Now, if you were to cut and paste this code into your favorite editor and then try and compile with your favorite simulation tool, you would receive a whole host of errors. As is, the compiler has no idea of where to find uvm_sequence_item, or ‘uvm_object_utils, etc. To compile code with UVM objects

you must do two things: import and include. You must import the uvm_pkg and include the uvm_macros. Let’s review the updated compile-friendly code:

Import uvm_pkg::*;
`include “uvm_macros.svh”

Class packet extends uvm_sequence_item;
…
…
…
endclass

The utility macro `uvm_object_utils registers this class with the factory, which we will discuss later, and allows access to the create method which is needed for cloning. After the utility macro are the field automation macros in the form ‘uvm_field_*(data member, flag). They allow access to the functions copy, compare, pack, unpack, record, print, and sprint. Essentially, these macros work together to implement

clone( ), print(), and the other methods that would be tedious and repetitive to code manually. There are macros for the various data types such as integers, enumerations, queues, etc. I recommend reviewing the UVM Reference Guide for an exhaustive list of all of the macros. The flag indicates what type of automation to enable for that data member. Multiple flag values can be used by using a bit-wise OR. They

can also be added using the ‘+’ sign. Here is a table with the flags and their descriptions.  

UVM_ALL_ONSet all operations on (default).
UVM_DEFAULTUse the default flag settings.
UVM_NOCOPYDo not copy this field.
UVM_NOCOMPAREDo not compare this field.
UVM_NOPRINTDo not print this field.
UVM_NODEFPRINTDo not print the field if it is the same as its
UVM_NOPACKDo not pack or unpack this field.
UVM_PHYSICALTreat as a physical field. Use physical setting in policy class for this field.
UVM_ABSTRACTTreat as an abstract field. Use the abstract setting in the policy class for this field.
UVM_READONLYDo not allow setting of this field from the set_*_local methods.
UVM_BINPrint / record the field in binary (base-2).
UVM_DECPrint / record the field in decimal (base-10).
UVM_UNSIGNEDPrint / record the field in unsigned decimal (base-10).
UVM_OCTPrint / record the field in octal (base-8).
UVM_HEXPrint / record the field in hexadecimal (base-16).
UVM_STRINGPrint / record the field in string format.
UVM_TIMEPrint / record the field in time format.

If you did not need to use the field macros in your class, then your utility macro would simply be ‘uvm_object_utils (or ‘uvm_component_utils for extensions of UVM components) without the _begin and _end.  

Messaging and UVM_Reporting

Messaging and UVM Reporting has the concepts of Severity, Verbosity and Simulation Handing Behavior. Each of them can be independently specified and controlled. Now lets see what each of these indicates:

  • Severity
    • Severity indicates importance
    • Examples are Fatal, Error, Warning & Info
  • Verbosity
    • Verbosity indicates filter level
    • Examples are None, Low, Medium, High, Full & Debug
  • Simulation Handling Behavior
    • Simulation handling behavior controls simulator behavior
    • Examples are Exit, Count, Display, Log, Call Hook & No Action

Simulation Handling Behavior in-fact is the Action taken by the Simulator which is dependent on Severity being produced by the Verification Environment.

The testbench needs the ability to report informative messages and debug information. The following macros provide that capability.

`uvm_info(ID, MSG, VERBOSITY)

`uvm_warning(ID, MSG)

`uvm_error(ID, MSG)

`uvm_fatal(ID, MSG)

With `uvm_info, you not only provide a string ID and string MSG, but you also provide an integer verbosity level. The ID field is simply a tag that you can easily identify in the log. The MSG field is the message you want printed and the verbosity indicates when you want that message printed. If the message’s verbosity level is lower or equal to the current verbosity level of that simulation run, then the message is displayed. The verbosity levels, in order of smallest to largest are, UVM_NONE, UVM_LOW, UVM_MEDIUM, UVM_HIGH, UVM_FULL, and UVM_DEBUG.

As an example, let’s add a task to the packet that displays the current values of the data members.

virtual function void displayAll();
  `uvm_info("DP", $sformatf("enable = %0h data_in = %0h data_out = %0h delay = %0d", enable, data_in, data_out, delay), UVM_LOW)
endfunction : displayAll

This message will always print when this task is called because it has the lowest verbosity level, provided the user did not set verbosity to UVM_NONE. If there are messages you only want to print for debug, you would give them a higher verbosity such as UVM_HIGH or UVM_DEBUG.

You can change that from the command line with +UVM_VERBOSITY=UVM_<VERBOSITY_LEVEL>. It is important to note that macro invocations do not end with a semicolon.  

Modify Simulator Default Action:

As mentioned above, UVM allows to bind a Reporting Severity with a particular valid Simulator Action. Usually it’s done inside the start_of_simulation() phase.

Actions can be assigned using set_report_*_action() functions. These can be done for one or all in the priority order from lowest to highest.

  • set_report_severity_action(Severity, Action);[Lowest Priority]
  • set_report_id_action(ID, Action);
  • set_report_severity_id_action(Severity, ID, Action);[Highest Priority]

Example:

virtual function void start_of_simulation_phase (uvm_phase phase);
   set_report_severity_action(UVM_FATAL | UVM_LOG, UVM_DISPLAY);
   set_report_id_action("CFG_ERROR", UVM_NO_ACTION);
   set_report_severity_id_action(UVM_ERROR, "CFG_ERROR", UVM_EXIT);
endfunction: start_of_simulation_phase

Controlling Messages Verbosity:

Fundamentally the Verbosity level describes how verbose a Testbench can be. The default Verbosity is UVM_MEDIUM. There are different Verbosity level being supported by UVM. These are UVM_NONE, UVM_LOW, UVM_MEDIUM (Default), UVM_HIGH, UVM_FULL, UVM_DEBUG. In case of default Verbosity level i.e. UVM_MEDIUM, any messages with UVM_HIGH or above are filtered out.

UVM_reporting__3

Different Verbosity Levels

Important Notes:

  • A message with the Verbosity level UVM_NONE can not be disabled.
  • `uvm_fatal, `uvm_error & `uvm_warning can not be filtered out via Verbosity level.

We can set the Verbosity level of a uvm_component individually or hierarchically using the following commands:

drv.set_report_verbosity_level(UVM_HIGH);
env.set_report_verbosity_level_hier(UVM_FULL);

on Facebook on Google+