An environment instantiates reusable verification components and defines their default configuration as required by the application. It is NOT good to instantiate individual verification components directly inside the test class, and has the following drawbacks :

  • Test writer should know how to configure the environment
  • Changes to the topology will require updating of multiple test files, which can take a lot of time
  • Tests are not reusable because they rely on a specific environment structure

Hence, it is always recommended to build the testbench class from uvm_env, which can then be instantiated within multiple tests. This will allow changes in environment topology to be reflected in all the tests. Moreover, the environment should have knobs to configure, enable or disable different verification components for the desired task.


This environment has 2 agents, 3 sub-environments and a scoreboard as represented in the block diagram shown above.

class my_top_env extends uvm_env;
   `uvm_component_utils (my_env)
   agent_apb          m_apb_agt;
   agent_wishbone     m_wb_agt;
   env_register       m_reg_env;
   env_analog         m_analog_env [2];
   scoreboard         m_scbd;
   function new (string name = "my_env", uvm_component parent); (name, parent);
   virtual function void build_phase (uvm_phase phase);
      super.build_phase (phase);
      // Instantiate different agents and environments here
      m_apb_agt = agent_apb::type_id::create ("m_apb_agt", this);
      m_wb_agt  = agent_wishbone::type_id::create ("m_wb_agt", this);
      m_reg_env = env_register::type_id::create ("m_reg_env", this);
      foreach (m_analog_env[i]) 
        m_analog_env[i] = env_analog::type_id::create ($sformatf("m_analog_env%0d",m_analog_env[i]), this);
      m_scbd = scoreboard::type_id::create ("m_scbd", this);
   virtual function void connect_phase (uvm_phase phase);
        // Connect between different environments, agents, analysis ports, and scoreboard here

Note that env_analog or env_register environments can have other nested environments and agents within it. You can see how powerful UVM becomes in terms of reusability because of this hierarchical structure and TLM interfaces within each component.

What to expect going forward ...

However, for our code examples in GitHub and in the following sessions of the Basics series, we'll look at a simpler testbench structure which instantiates a single agent and a scoreboard, as shown in the block diagram below.


The testbench structure translates to the following code.

class my_env extends uvm_env ;
   `uvm_component_utils (my_env)
   my_agent             m_agnt0;
   my_scoreboard        m_scbd0;
   function new (string name, uvm_component parent); (name, parent);
   endfunction : new
   virtual function void build_phase (uvm_phase phase);
      super.build_phase (phase);
      m_agnt0 = my_agent::type_id::create ("my_agent", this);
      m_scbd0 = my_scoreboard::type_id::create ("my_scoreboard", this);
   endfunction : build_phase
   virtual function void connect_phase (uvm_phase phase);
      // Connect the scoreboard with the agent
      m_agnt0.m_mon0.item_collected_port.connect (m_scbd0.data_export); 
endclass : my_env  

Note that the analysis port of the monitor is connected to the export of the scoreboard in connect_phase() method.

Other Details

uvm_env is the base class for hierarchical containers of other components that make up a complete environment. It can be reused as a sub-component in a larger environment or even as a stand-alone verification environment that can instantiated directly in various tests.


Check Class Definitions for more information on method declarations.

Was this article helpful ?