Tour/Configuration



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/Connections
Nav-home.png Tour/Cookbook Next Page in Tour:
Tour/Registers
Nav-next.png

Contents

Introduction

One of the key tenets of designing reusable testbenches is to make testbenches as configurable as possible. Doing this means that the testbench and its constituent parts can easily be reused and quickly modified.

In a testbench, there are any number of values that you might normally write as literals - values such as for-loop limits, string names, randomization weights and other constraint expression values, coverage bin values. These values can be represented by SystemVerilog variables, which can be set (and changed) at runtime, or SystemVerilog parameters, which must be set at compile time. Because of the flexibility they offer, variables organised into configuration objects and accessed using the uvm_config_db API should always be used where possible.

However, bus widths have to be fixed at compile time, so cannot be implemented as configuration objects. There are a number of articles on handling parameters in the UVM :

  • Parameterized Tests shows how to use parameterized tests with the UVM factory
  • The test parameter package article shows how to centralize the parameters shared between DUT and testbench
  • The Parameters and reuse article shows how to pass large numbers of parameters down through the uvm_component hierarchy.

Configuration Objects

Configuration objects are an efficient, reusable mechanism for organizing configuration variables. In a typical testbench, there will in general be several configuration objects, each tied to a component. They are created as a subclass of uvm_object and group together all related configuration parameters for a given branch of the test structural hierarchy. There can also be an additional, single configuration object that holds global configuration parameters.

The UVM configuration database takes care of the scope and storage of the object. Below is the code for a typical configuration object for an agent. It has a virtual interface, which is used to point to the interface that the agent is connected to, and a number of variables used to describe and control that interface.

// configuration class
class wb_config extends uvm_object;
  `uvm_object_utils( wb_config );
 
// Configuration Parameters
  virtual wishbone_bus_syscon_if v_wb_bus_if; // virtual wb_bus_if
 
  int m_wb_id;                       // Wishbone bus ID
  int m_wb_master_id;                // Wishbone bus master id for wishone agent
  int m_mac_id;                      // id of MAC WB master
  int unsigned m_mac_wb_base_addr;   // Wishbone base address of MAC
  bit [47:0]   m_mac_eth_addr;       // Ethernet address of MAC
  bit [47:0]   m_tb_eth_addr;        // Ethernet address of testbench for sends/receives
  int m_mem_slave_size;              // Size of slave memory in bytes
  int unsigned m_s_mem_wb_base_addr; // base address of wb memory for MAC frame buffers
  int m_mem_slave_wb_id;             // Wishbone ID of slave memory
  int m_wb_verbosity;                // verbosity level for wishbone messages
 
 
  function new( string name = "" );
    super.new( name );
  endfunction
 
endclass

Using a Configuration Object

Any component that requires configuration should perform the following steps:

  • get its own configuration
  • create its own internal structure and behavior based on its configuration
  • configure its children

The test component, as the top-level component, gets its configuration values from either a test parameter package or from the UVM configuration database (e.g. for a virtual interface handle). It then sets test-specific configuration parameters for components in the environment.

class test_mac_simple_duplex extends uvm_test;
...
 
  wb_config wb_config_0;  // config object for WISHBONE BUS
  ...
 
  function void set_wishbone_config_params();
    //set configuration info
    // NOTE   The MAC is WISHBONE slave 0, mem_slave_0 is WISHBONE slave 1
    // MAC is WISHBONE master 0,  wb_master is WISHBONE master 1
    wb_config_0 = new();
 
    wb_config_0.v_wb_bus_if =
      uvm_container #(virtual wishbone_bus_syscon_if)::get_value_from_config(this, "WB_BUS_IF");  // virtual interface
 
    wb_config_0.m_wb_id = 0;  // WISHBONE 0
    wb_config_0.m_mac_id = 0;   // the ID of the MAC master
    wb_config_0.m_mac_eth_addr = 48'h000BC0D0EF00;
    wb_config_0.m_mac_wb_base_addr = 32'h00100000;
    wb_config_0.m_wb_master_id = 1; // the ID of the wb master
    wb_config_0.m_tb_eth_addr = 48'h000203040506;
    wb_config_0.m_s_mem_wb_base_addr = 32'h00000000; 
    wb_config_0.m_mem_slave_size = 32'h00100000; // 1 Mbyte
    wb_config_0.m_mem_slave_wb_id = 0;  // the ID of slave mem
    wb_config_0.m_wb_verbosity = 350;
 
    uvm_config_db #( wb_config )::set( this , "*" , "wb_config" , wb_config_0 );
  endfunction
  ...
 
  function void build_phase( uvm_phase );
    super.build_phase( phase );
 
    set_wishbone_config_params();
    ...
  endfunction
  ...
 
endclass

The components that use the configuration object get it by using uvm_config_db::get. In this example, the drivers get the virtual interface handle, ID, and verbosity from the object.

class wb_m_bus_driver extends uvm_driver  #(wb_txn, wb_txn);
...
 
  virtual wishbone_bus_syscon_if m_v_wb_bus_if;
  bit [2:0] m_id;  // Wishbone bus master ID
  wb_config m_config;
  ...
 
  function void build_phase( uvm_phase phase );
    super.build_phase( phase );
 
    if( !uvm_config_db #( wb_config )::get( this , "" , "wb_config" , m_config ) ) begin
      `uvm_error(...)
    end 
    m_id = m_config.m_wb_master_id;
    ...
  endfunction
 
  function void connect_phase( uvm_phase phase );
    super.connect_phase( phase );
    m_v_wb_bus_if = m_config.v_wb_bus_if; // set local virtual if property
  endfunction 
 
  function void end_of_elaboration();
    set_report_verbosity_level_hier(m_config.m_wb_wb_verbosity);
  endfunction  
  ...
 
endclass

Configuring sequences

There is a separate article on Configuring Sequences here.

Configuring DUT connections

Setting up DUT-to-Testbench connections is one kind of configuration activity that is always necessary. An SV module ( usually the top level module but sometimes a ProtocolModules ) has to add a virtual interface into the configuration space. On the testbench side the test component gets the virtual interface handle from the UVM config database and applies it to appropriate configuration objects:

class test_mac_simple_duplex extends uvm_test;
  ...
 
  function void set_wishbone_config_params();
    wb_config_0 = new();
 
    // Get the virtual interface handle that was set in the top module or protocol module
    if( !uvm_config_db #( virtual wishbone_bus_syscon_if )::get( this , "" , "WB_BUS_IF" , wb_config_0.v_wb_bus_if ) ) begin
      `uvm_error(...)
    end
    ...
    uvm_config_db #( wb_config )::set( this , "*","wb_config",wb_config_0, 0); // put in config
  endfunction
  ...
 
endclass

Example source code




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