We have seen in previous sessions that by instantiating the environment inside each testcase, we have the ability to tweak environment parameters to enable multiple scenarios. A test writer may not have the knowledge of how verification components are hooked-up with each other or how they interact with each other. Hence, it becomes important to hide those details and only present the test writer with ways to tweak the environment for each testcase and here are a few ways to do that.


Use Configurable Parameters

In order to give maximum flexibility to the testbench, it is recommended to add certain knobs to verification components such that they can be controlled from a testcase. Parameters that affect how the testbench is constructed or behaves, can be made a standard across different testbench structures:

  • An agent can be configured to operate in either ACTIVE or PASSIVE mode. In active mode, the agent will instantiate a driver and sequencer and will drive transactions to the DUT, while in passive mode, it will only monitor the signal changes happening in DUT interface. This can be done by using a knob variable of type uvm_active_passive_enum. See Agent for example.
  • Similarly, coverage collection and protocol checkers in a monitor can be enabled/disabled from testcase by adding similar knob variables. See Monitor for example.



uvm_active_passive_enum

Other design specific configurations such as the ones below can also be parameterized.

  • Number of master and slave agents in an AHB environment
  • Speeds and modes of operation of a bus


UVM Configuration Mechanism

Imagine that there's an internal 2-column table within UVM where the first column stores a variable name, and the second column stores the value for that particular variable. If all the components in the environment can access the table, then it becomes very easy to pass information between them. For example, the test component can store a virtual interface variable which can then be accessed by the driver and monitor for their own use. This is the mechanism implemented via uvm_config_db and uvm_resource_db.

uvm_config_db

Sometimes, we do not want all the components to access the table. For example, an analog interface need not be passed to an AHB driver. Such restrictions are put in place by the hierarchical path in uvm_config_db. It essentially makes the object available to whatever is specified in the path. If the path contains a single element, then only that particular element will be able to retrieve the object by using uvm_config_db::get() method.



uvm_config_db #(int) :: set (this, "*.wbSlaves[0]", "slave_id", 0);
uvm_config_db #(virtual dut_if)::set (null, "uvm_test_top", "dut_if", dut_if1);

uvm_resource_db #(myObj) :: set ("test", "shared_config", data, this);

Note that uvm_config_db is a type specific configuration mechanism that offers a way to specify a hierachical path to control which components can access the database object.

In the first example above, only those components below wbSlaves[0] can get the slave_id from the database. All others will result in an error, since the object is not visible to them. The second example shows how a virtual interface can be stored inside the database which is made available to all components beneath the top-level test component. uvm_resource_object is used in the final example to show how data can be made avaialable for access by any object anywhere in the hierarchy.



Use a Configuration Class

You can also put in all the configuration related tweaks and variables inside a separate class, and pass the class object via uvm_config_db to the database, and allow a hierarchical path that allows the object to trickle down to each level. For example, the configuration object can be set into the database at the test top level, which can be retrieved by the environment and passed to other agents and components in the same way.

config-object

Check our code on GitHub to see how this is done

The advantage to creating a class is that you can derive future versions of the class by inheritance and also randomize the variables and constrain them appropriately for valid scenarios.