Tour/Testbench



Welcome to the Demo Tour of the UVM/OVM Cookbook on Mentor's Verification Academy.
This is an overview of the pages in the cookbook - there are hundreds of articles that are available to you,
including real example code on the article pages and for offline download, once you register for full access.

 Navigation: 
Nav-prev.png Previous Page in Tour:
Tour/Contents
Nav-home.png Tour/Cookbook Next Page in Tour:
Tour/Phasing
Nav-next.png

Contents

How an UVM testbench differs from a traditional module based testbench

In Verilog or VHDL, a testbench consists of a hierarchy of modules containing testbench code that are connected to the design under test (DUT). The modules contain stimulus and response checking code which is loaded into simulator memory along with the DUT at the beginning of the simulation and is present for the duration of the simulation. Therefore, the classic Verilog testbench wrapped around a DUT consists of what are known as static objects.

SystemVerilog builds on top of Verilog by adding abstract language constructs targetted at helping the verification process. One of the key additions to the language was the class. SystemVerilog classes allow Object Orientated Programming (OOP) techniques to be applied to testbenches. The UVM itself is a library of base classes which facilitate the creation of structured testbenches using code which is open source and can be run on any SystemVerilog IEEE 1800 simulator.

Like classes in any other OOP language such as C++ and Java, SystemVerilog class definitions are templates for an object that is constructed in memory. Once created, that object persists in memory until it is de-referenced and garbage collected by an automatic background process. The class template defines the members of the class which can either be data variables or methods. In SystemVerilog, the methods can either be functions which are non-time consuming, or tasks which can consume time. Since a class object has to be constructed before it exists in memory the creation of a class hierarchy in a SystemVerilog testbench has to be initiated from a module since a module is a static object that is present at the beginning of the simulation. For the same reason, a class cannot contain a module. Classes are referred to as dynamic objects because they can come and go during the life time of a simulation.

//
// Example to show how a class is constructed from within a static object (a module)
//
 
//
// Example class that contains a message and some convenience methods
//
class example;
 
string message;
 
function void set_message(string ip_string);
 message = ip_string;
endfunction: set_message
 
function void print();
 $display("%s", message);
endfunction: print
 
endclass: example
 
//
// Module that uses the class - class is constructed, used and dereferenced
// in the initial block, after the simulation starts
//
module tb;
 
example C; // Null handle after elaboration
 
initial begin
 C = new(); // Handle points to C object in memory
 C.set_message("This ojbect has been created");
 #10;
 C.print(); 
 C = null; // C has been deferenced, object can be garbage collected
end
 
endmodule: tb

The UVM Package

The UVM package contains a class library that comprises three main types of classes, uvm_components which are used to construct a class based hierarchical testbench structure, uvm_objects which are used as data structures for configuration of the testbench and uvm_transactions which are used in stimulus generation and analysis.

An UVM testbench will always have a top level module which contains the DUT and the testbench connections to it. The process of connecting a DUT to an UVM class based testbench is described in the article on DUT- testbench connections.

The top level module will also contain an initial block which will contain a call to the UVM run_test() method. This method starts the execution of the UVM phases, which controls the order in which the testbench is built, stimulus is generated and then reports on the results of the simulation.

UVM testbench Hierarchy

UVM testbenches are built from classes derived from the uvm_component base class. The testbench hierarchy is determined by a series of 'has-a' class relationships, in other words which components contain which other components. The top level class in an UVM testbench is usually known as the test class and this class is responsible for configuring the testbench, initiating the construction process by building the next level down in the hierarchy and by initiating the stimulus by starting the main sequence. For a given verification environment, the testbench hierararchy below the test class is reasonably consistent, and each test case is implemented by extending a test base class.

The UVM testbench architecture is modular to facilitate the reuse of groups of verification components either in different projects (horizontal reuse) or at a higher level of integration in the same project (vertical reuse). There are two main collective component types used to enable reuse - the env (short for environment) and the agent.

The Agent

Most DUTs have a number of different signal interfaces, each of which have their own protocol. The UVM agent collects together a group of uvm_components focused around a specific pin-level interface. The purpose of the agent is to provide a verification component which allows users to generate and monitor pin level transactions. A SystemVerilog package is used to gather all the classes associated with an agent together in one namespace.

Active agent.gif

The contents of an agent package will usually include:

  • A Sequence_item -The agent will have one or more sequence items which are used to either define what pin level activity will be generated by the agent or to report on what pin level activity has been observed by the agent.
  • A Driver - The driver is responsible for converting the data inside a series of sequence_items into pin level transactions.
  • A Sequencer - The role of the sequencer is to route sequence_items from a sequence where they are generated to/from a driver.
  • A Monitor - The monitor observes pin level activity and converts its observations into sequence_items which are sent to components such as scoreboards which use them to analyse what is happening in the testbench.
  • Configuration object - A container object, used to pass information to the agent which affects what it does and how it is built and connected.

Each agent should have a configuration object, this will contain a reference to the virtual interface which the driver and the monitor use to access pin level signals. The configuration object will also contain other data members which will control which of the agents sub-components are built, and it may also contain information that affects the behaviour of the agents components (e.g. error injection, or support for a protocol variant)

The agent configuration object contains an active bit which can be used to select whether the agent is passive - i.e. the driver and sequencer are not required, or active. It may also contain other fields which control whether other sub-component classes such as functional coverage monitors or scoreboards get built or not.

Other classes that might be included in an agent package:

  • Functional coverage monitor - to collect protocol specific functional coverage information
  • Scoreboard - usually of limited use
  • A responder - A driver that responds to bus events rather than creating them (i.e. a slave version of the driver rather than a master version).
  • (API) Sequences - Utility sequences likely to be of general use, often implementing an API layer for the driver.

The env

The environment, or env, is a container component for grouping together sub-components orientated around a block, or around a collection of blocks at higher levels of integration.

Block Level env

In a block level UVM testbench, the environment, or env, is used to collect together the agents needed for the DUTs interfaces together. Like the agent, the different classes associated with the env are organised into a SystemVerilog package, which will import the agent packages. In addition to the agents the env will also contain some or all of the following types of components:

Block level uvm hierarchy
  • Configuration object - The env will have a configuration object that enables the test writer to control which of the environments sub-components are built. The env configuration object should also contain a handle for the configuration object for each of the agents that it contains. These are then assigned to the envs agents using set_config_object.
  • Scoreboards - A scoreboard is an analysis component that checks that the DUT is behaving correctly. UVM scoreboards use analysis transactions from the monitors implemented inside agents. A scoreboard will usually compare transactions from at least two agents, which is why it is usually present in the env.
  • Predictors - A predictor is a component that computes the response expected from the stimulus, it is generally used in conjunction with other components such as the scoreboard.
  • Functional Coverage Monitors - A functional coverage monitor analysis component contains one or more covergroups which are used to gather functional coverage information relating to what has happened in a <span style="background-color: navy; color: white;" />testbench during a test case. A functional coverage monitor is usually specific to a DUT.
  • Virtual Sequencers - A virtual sequencer is used in the stimulus generation process to allow a single sequence to control activity via several agents.

The diagram shows a block level testbench which consists of a series of tests which build an env which contains several analysis components and two agents.

Integration Level env

When blocks are integrated to create a sub-system, vertical reuse can be achieved by reusing the envs used in each of the block level testbenches merged together into a higher level env. The block level envs provide all of the structures required to test each block, but as a result of the integration process, not all the block level interfaces are exposed at the boundary and so some of the functionality of the block level envs will be redundant. The integration level env then needs to be configured to make agents connected to internal interfaces passive, or possibly even not to include an agent at all. This configuration is done in the test, and the configuration object for each sub-env is nested inside the configuration object for the env at the next level of hiearchy.

Integration level uvm hierarchy.gif

As an illustration, the diagram shows a first level of integration where two block level environments have been merged together to test the peripheral file. The 'greyed out' components in the envs are components that are no longer used in the integration level envrionment. The configuration object for the integration level contains the rest of the configuration objects nested inside it.

Further levels of integration can be accomodated by layering multiple integration level envs inside eachother.

The UVM testbench Build And Connection Process

Before an UVM testbench can start to apply stimulus its component hierarchy has to be built and the connections between the verification components has to be made. The process for configuring and building agents, block level and integration level UVM testbenches is described in the article on building UVM testbenches.


 Navigation: 
Nav-prev.png Previous Page in Tour:
Tour/Contents
Nav-home.png Tour/Cookbook Next Page in Tour:
Tour/Phasing
Nav-next.png