Global training solutions for engineers creating the world's electronics

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 in the Reference Guide.

Prev    Next