Monday 19 February 2018

Developing & Delivering KnowHow


The Easier UVM Code Generator Tutorial Part 4:
Hierarchical Verification Environments



This tutorial gives you the opportunity to experiment with an example that contains multiple agents and interfaces, and in particular to explore the features of the code generator that give you a degree of control over the hierarchical structure of the verification environment. By setting parameters in the code generator template files you can, amongst other things, set agents to run in active or passive mode and select whether each agent is instantiated in its own environment, in the top-level environment, or on the same environment as another agent. This tutorial also illustrates how the code generator uses configuration objects.

You can download the files for this example. The files are in the directory named ./multi_if.

The example used in this tutorial has four interfaces/agents, two of which use the register layer (bus1 and bus2) and two of which do not (clkndata and serial). The interface template file for each of these four interfaces includes the following lines, initially all commented out:

Filename *.tpl
#uvm_seqr_class = yes
#agent_is_active = UVM_PASSIVE
#agent_has_env = yes
#additional_agent = serial

uvm_seqr_class

The parameter uvm_seqr_class can be set to yes or no. The default is no, which means that the sequencer type for this particular agent will be defined using a simple typedef:

Filename clkndata_sequencer.sv
typedef uvm_sequencer #(data_tx) clkndata_sequencer_t;

If the parameter is set to yes, the code generator will create a new sequencer class:

Filename clkndata.tpl
...
uvm_seqr_class = yes
...
Filename clkndata_sequencer.sv
class clkndata_sequencer extends uvm_sequencer #(data_tx);

  `uvm_component_utils(clkndata_sequencer)
  ...
endclass

You could modify or extend this sequencer class, although you would have to take steps to ensure that the modified code is not overwritten when the code generator is re-run. (Unlike some other parts of the generated code, these particular changes would not be preserved automatically when the code generator is re-run.)

agent_is_active

The parameter agent_is_active can be set to UVM_ACTIVE or UVM_PASSIVE. The default is UVM_ACTIVE. This flag gives us the opportunity to take a look at how the code generator deals with the configuration of generated components. Setting the agent_is_active flag to UVM_PASSIVE has the direct effect of modifying the value of a field in a top-level configuration object that is set from the top-level module and is used to configure the top-level environment.

Filename clkndata.tpl
...
agent_is_active = UVM_PASSIVE
...
Filename top_tb.sv
module top_tb;
  ...
  top_config env_config;
  
  initial
  begin
    env_config = new("env_config");
    ...
    env_config.is_active_clkndata = UVM_PASSIVE;
    ...
    uvm_config_db #(top_config)::set(null, "uvm_test_top.m_env", "config", env_config);

As you can see above, there is a single configuration object that is used to configure the entire top-level verification environment. The values of the appropriate fields will be copied from the top-level configuration object to the configuration objects for the individual agents, clkndata in this case, in the build_phase method of the env:

Filename top_env.sv
class top_env extends uvm_env;
  ...
  clkndata_config   m_clkndata_config;
  top_config        m_config;
  ...
endclass

function void top_env::build_phase(uvm_phase phase);
  if (!uvm_config_db #(clkndata_config)::get(this, "", "config", m_config))
    ...
  m_clkndata_config           = new("m_clkndata_config");
  ...
  m_clkndata_config.is_active = m_config.is_active_clkndata;
  ...
  uvm_config_db #(clkndata_config)::set(this, "m_clkndata_agent", "config", m_clkndata_config);

The build_phase method above is getting values from its own configuration object (m_config) and is setting those same values in the configuration objects of its children (such as m_clkndata_config). In other words, the values of the configuration parameters are being passed down through the UVM component hierarchy encapsulated within configuration objects that are associated with the components.

Finally, the value of this field is retrieved from the configuration database by the agent and is checked to determine whether the agent is to be built in active or passive mode. This is done by overriding the get_is_active method of the agent:

Filename clkndata_agent.sv
function void clkndata_agent::build_phase(uvm_phase phase);
  if (!uvm_config_db #(clkndata_config)::get(this, "", "config", m_config))
    ...
  ...
  if (get_is_active() == UVM_ACTIVE)
  begin
    m_driver    = clkndata_driver::type_id::create("m_driver", this);
    m_sequencer = clkndata_sequencer::type_id::create("m_sequencer", this);
  end
endfunction
function uvm_active_passive_enum clkndata_agent::get_is_active();
  ...
  m_is_active = m_config.is_active;
  ...
  return uvm_active_passive_enum'(m_is_active);
endfunction

agent_has_env

The parameter agent_has_env can be set to yes or no. The default is no, which means that the this particular agent will be instantiated from the top-level environment, unless it is accessed through a register model, in which case it will be instantiated within its own environment regardless of the value of this flag. If agent_has_env is set to yes, the agent will be instantiated in its own environment, which will be instantiated from the top-level environment.

By default, agents that are accessed through a register model will be instantiated in their own environments and all other agents will be instantiated from the top-level env:

Filename top_env.sv
class top_env extends uvm_env:
  ...
  // Child environments and associated objects
  bus1_env         m_bus1_env;
  bus2_env         m_bus2_env;
  
  bus1_env_config  m_bus1_env_config;
  bus2_env_config  m_bus2_env_config;
  
  // Child agents and associated objects
  clkndata_config    m_clkndata_config;
  clkndata_agent     m_clkndata_agent;
  clkndata_coverage  m_clkndata_coverage;
  
  serial_config      m_serial_config;
  serial_agent       m_serial_agent;
  serial_coverage    m_serial_coverage;
  ...  
endclass

Setting agent_has_env to yes in the corresponding template file will move the clkndata agent into its own env:

Filename clkndata.tpl
...
agent_has_env = yes
...
Filename top_env.sv
class top_env extends uvm_env:
  ...
  // Child environments and associated objects
  clkndata_env     m_clkndata_env;
  bus1_env         m_bus1_env;
  bus2_env         m_bus2_env;

  clkndata_config  m_clkndata_config;
  bus1_env_config  m_bus1_env_config;
  bus2_env_config  m_bus2_env_config;
  
  // Child agents and associated objects
  serial_config    m_serial_config;
  serial_agent     m_serial_agent;
  serial_coverage  m_serial_coverage;
  ...  
endclass

If we now do the same for the one remaining agent (serial) then every agent will be put into its own env:

Filename serial.tpl
...
agent_has_env = yes
...
Filename top_env.sv
class top_env extends uvm_env:
  ...
  // Child environments and associated objects
  clkndata_env     m_clkndata_env;
  bus1_env         m_bus1_env;
  bus2_env         m_bus2_env;
  serial_env       m_serial_env;

  clkndata_config  m_clkndata_config;
  bus1_env_config  m_bus1_env_config;
  bus2_env_config  m_bus2_env_config;
  serial_config    m_serial_config;
  ...  
endclass

Note that in each case the top-level env creates a separate configuration object for each child env or agent. We saw earlier in this tutorial that the top-level env copies configuration parameters from its own configuration object to the configuration objects belonging to the individual agents.

additional_agent

If an agent has its own environment, the parameter additional_agent can be used to specify an additional agent to be instantiated in that environment, as opposed to being instantiated in its own environment or being instantiated at the top-level. An environment can instantiate any number of additional agents, each specified using its own additional_agent line in the template file. Note that an environment that instantiates a register model cannot contain additional agents.

For example, assuming that serial does not have its own env, it can be instantiated in the env of the clkndata agent:

Filename clkndata.tpl
...
agent_has_env = yes
additional_agent = serial
...
Filename clkndata_env.sv
class clkndata_env extends uvm_env:
  ...
  clkndata_config    m_clkndata_config;
  clkndata_agent     m_clkndata_agent;
  clkndata_coverage  m_clkndata_coverage;
  
  serial_config      m_serial_config;
  serial_agent       m_serial_agent;
  serial_coverage    m_serial_coverage;
  ...  
endclass

You can now experiment with the values of the above parameters in the four template files bus1.tpl, bus2.tpl, clkndata.tpl, and serial.tpl, re-running the code generator after each change to see their effect. You need to be aware that additional_agent has several limitations, as described here in the Reference Guide.




Links

Easier UVM Coding Guidelines
Introduction to the Easier UVM Coding Guidelines
Summary of the Easier UVM Coding Guidelines
Detailed Explanation of the Easier UVM Coding Guidelines
Easier UVM Glossary
Easier UVM Coding Guidelines - Download

Easier UVM - Deeper Explanations
Coverage-Driven Verification Methodology
Requests, Responses, Layered Protocols and Layered Agents
How to Access a Parameterized SystemVerilog Interface from UVM

Easier UVM Code Generator
Easier UVM Code Generator - Download
Easier UVM Code Generator - Tutorial Part 1: Getting Started
Easier UVM Code Generator - Tutorial Part 2: Adding User-Defined Code
Easier UVM Code Generator - Tutorial Part 3: Adding the Register Layer
Easier UVM Code Generator - Tutorial Part 4: Hierarchical Verification Environments
Easier UVM Code Generator - Tutorial Part 5: Split Transactors
Easier UVM Code Generator - Frequently Asked Questions (FAQ)
Easier UVM Code Generator - Reference Guide

Easier UVM Video Tutorial
Introducing Easier UVM
Easier UVM - The Big Picture
Key Concepts of the Easier UVM Code Generator
Running Easier UVM in EDA Playground
Easier UVM - Components and Phases
Easier UVM - Configuration
TLM Connections in UVM
Easier UVM - Transaction Classes
Easier UVM - Sequences
Easier UVM - Tests
Easier UVM - Reporting
Easier UVM - Register Layer
Easier UVM - Parameterized Interfaces
Easier UVM - Scoreboards
The Finer Points of UVM Sequences (Recorded Webinar)
UVM Run-Time Phasing (Recorded Webinar)

A YouTube playlist with all the above videos and more

Easier UVM Paper and Poster
Easier UVM - Coding Guidelines and Code Generation - as presented at DVCon 2014

Easier UVM Q&A Forum
Easier UVM Google Group

Easier UVM Examples Ready-to-Run on EDA Playground
Minimal example with driver
Minimal example with coverage in a subscriber as well as driver and monitor.
Minimal example with register sequence and register block
Example with four interfaces/agents, two of which use a register model.
Minimal example with dual-top modules and split transactors
Minimal example showing a UVM sequence getting information from the config database
Minimal example showing features of objections and the command line processor
Minimal example showing the reporting features of UVM.
Example that drops an objection when coverage exceeds some threshold
Example that sends a response transaction from the driver back to the uvm_reg_adapter
Example that uses a frontdoor sequence to pass a response object back to the register sequence that called read/write
Example of a parameterized interface generated from an Easier UVM interface template file
Example that pulls in a user-defined parameterized interface
Example of a reference model with the Syosil scoreboard

Back to the full list of UVM Resources

Privacy Policy Site Map Contact Us