Vous êtes sur la page 1sur 19

UVM Factory and Configuration

Database
At the end of this module
you will be able to:

 Understand the need of UVM Factory.


 Understand how to override using factory.
 Understand the usage of UVM Configuration Database

Session Plan:
 Introduction to UVM Factory
 Need of UVM Factory
 Factory Registration
 Overriding Components / Objects
 Factory Override - Precedence
 UVM Configuration
 Configuration Object
 Work Sheet.

1 | Verification Engineer UTL Technologies Ltd


Module Overview
In this module we are going to understand purpose and usage of UVM Factory and configuration

 Introduction to UVM Factory


o Type based
o Name based
o UVM Highlights
 Need of UVM Factory
 Factory Registration
o Create object / component
 Overriding Components / Objects
o Component Overrides
o Component Type Overrides
o Component Instance Overrides
o Object Overrides
o Type vs. Name Overrides
 Factory Override - Precedence
 UVM Configuration
o Uvm_config_db – set method
o Uvm_config_db – get method
 Configuration Object
o Using a configuration object

2 | UVM Factory and Configuration Database


Introduction to UVM Factory

Introduction to UVM Factory:-


As the name implies, uvm_factory is used to manufacture (create) UVM objects and components.
Only one instance of the factory is present in a given simulation (termed a singleton). Object and
component types are registered with the factory using lightweight proxies to the actual objects
and components being created.
The factory provides both name-based and type-based interfaces.
Type-based:
The type-based interface is far less prone to errors in usage. When errors do occur, they are
caught at compile-time.
Name-based:
The name-based interface is dominated by string arguments that can be misspelled and provided
in the wrong order. Errors in name-based requests might only be caught at the time of the call, if
at all. Further, the name-based interface is not portable across simulators when used with
parameterized classes.
Usage of Factory involves three basic operations

• Register class types with the factory


• Creating component / object using factory
• Overriding components / objects

Need of UVM Factory:-

The purpose of the UVM factory is to allow an object of one type to be substituted with an object
of a derived type without having to change the structure of the testbench or edit the testbench
code.

The mechanism used is referred to as an override and the override can be by instance or type.
This functionality is useful for changing sequence functionality or for changing one version of a
component for another.

Any components which are to be swapped must be polymorphically compatible. This includes
having all the same TLM interface handles and TLM objects must be created by the new
replacement component. Additionally, in order to take advantage of the factory certain coding
conventions need to be followed.

Factory Registration:-
UVM methodology dictates that engineers should simply invoke the appropriate factory
registration macro when defining <uvm_object> and <uvm_component>-based classes. Use of
macros is required to ensure portability across different vendors' simulators.

3 | Verification Engineer UTL Technologies Ltd


Objects that are not parameterized are can be registered to factory as
/* Program 1.1 Sample non parameterized object factory registration */
class packet extends uvm_object;

`uvm_object_utils(packet)

endclass

class packetD extends packet;

`uvm_object_utils(packetD)

endclass
/* Program 1.2 Sample parameterized object factory registration */

class packet #(type T=int, int WIDTH=32) extends uvm_object;

`uvm_object_param_utils(packet #(T,WIDTH))

endclass
/* Program 1.3 Sample non parameterized component factory registration
*/

class comp extends uvm_component;

`uvm_component_utils(comp)

endclass
/* Program 1.4 Sample parameterized component factory registration */

class comp #(type T=int, int WIDTH=32) extends uvm_component;

`uvm_component_param_utils(comp #(T,WIDTH))

endclass

The `uvm_*_utils macros for simple, non-parameterized classes will register the type with the
factory and define the get_type, get_type_name, and create virtual methods inherited from
<uvm_object>. It will also define a static type_name variable in the class, which will allow you to
determine the type without having to allocate an instance.

The `uvm_*_param_utils macros for parameterized classes differ from `uvm_*_utils classes in the
following ways:

• The get_type_name method and static type_name variable are not defined. You will need
to implement these manually.
• A type name is not associated with the type when registeriing with the factory, so the
factory's *_by_name operations will not work with parameterized classes.
• The factory's <print>, <debug_create_by_type>, and <debug_create_by_name> methods,
which depend on type names to convey information, will list parameterized types as
<unknown>.

4 | UVM Factory and Configuration Database


It is worth noting that environments that exclusively use the type-based factory methods
(*_by_type) do not require type registration. The factory's type-based methods will register the
types involved "on the fly," when first used. However, registering with the `uvm_*_utils macros
enables name-based factory usage and implements some useful utility functions.

Creating Object / Component:-

Having registered your objects and components with the factory, you can now make requests for
new objects and components via the factory. Using the factory instead of allocating them directly
(via new) allows different objects to be substituted for the original without modifying the
requesting class.

Standard constructor defaults for component is as below,


function new(string name, uvm_component parent=null);
super.new(name, parent);
endfunction

Standard constructor defaults for object is as below,

function new(string name);

super.new(name);

endfunction

The following code defines a driver class that is parameterized and how to create instance of it.
/* Program 1.5 Parameterized driver class */
class driverB #(type T=uvm_object) extends uvm_driver;
`uvm_component_param_utils(driverB #(T))
function new(string name, uvm_component parent=null);
super.new(name,parent);
endfunction
// get_type_name not implemented by macro for parameterized
classes
const static string type_name = {"driverB
#(",T::type_name,")"};
virtual function string get_type_name();
return type_name;
endfunction
endclass
// using the factory allows pkt overrides from outside the class
virtual function void build_phase(uvm_phase phase);
pkt = packet::type_id::create("pkt",this);
endfunction

5 | Verification Engineer UTL Technologies Ltd


Overriding Components / Objects:-

The UVM factory allows a class to be substituted with another class of a derived type when it is
constructed. This can be useful for changing the behavior of a testbench by substituting one class
for another without having to edit or re-compile the testbench code. In order for factory override
process to work there are a number of coding convention pre-requisites that need to be followed,
these are explained in earlier sections.

The UVM factory can be thought of as a lookup table. When "normal" component construction
takes place using the <type>::type_id::create("<name>", <parent>) approach, what
happens is that the type_id is used to pick the factory component wrapper for the class, construct
its contents and pass the resultant handle back again. The factory override changes the way in
which the lookup happens so that looking up the original type_id results in a different type_id
being used. Consequently, a handle to a different type of constructed object is returned. This
technique relies on polymorphism which is the ability to be able to refer to derived types using a
base type handle. In practice, an override will only work when a parent class is overridden by one
of its descendents in the class extension hierarchy.

Component Overrides:

There are two types of component overrides in the UVM - type overrides and instance overrides.

Component Type Overrides

A type override means that every time a component class type is created in a testbench hierarchy,
a substitute type is created in its place. This applies to all instances of that component type i.e.,
type overrides apply for whole testbench.

Component type override can be implemented in two ways, one is by overriding by type and
other one is overriding by name. These are best explained in following examples.
• set_type_override_by_type(arg1,arg2,arg3);
– Arg1 is original type
• Handle.get_type()
• Class_name::get_type()
– Arg2 is overriding type
– Arg3 is replace
• If 1, replace any previous overrides on original type with current override
• If 0, checks for previous overrides. If exists, ignores current override, else
current override takes effect.
– Eg: set_type_override_by_type( env1::get_type(),
env2::get_type(),
1);

• set_type_override_by_name(arg1, arg2, arg3);

– Arg1
• String, name of the original type
– Arg2

6 | UVM Factory and Configuration Database


• String, name of the override type.
– Arg3
If 1, replace any previous overrides on original type with current override

If 0, checks for previous overrides. If exists, ignores current override, else

current override takes effect.
– set_type_override_by_name( “env1”,
”env2”,
1);
/* Program 1.6 Sample code fragments illustrate type override by type
and name */
// Component type override example
// Color parent class
class color extends uvm_component;
`uvm_component_utils(color)
// etc
endclass: color
// Red child class
class red extends color;
`uvm_component_utils(red)

//etc
endclass: red
class dark_red extends color;
`uvm_component_utils(dark_red)

//etc
endclass: dark_red

// Override color with red type by type.


set_type_override_by_type( color::get_type(),

red::get_type(),

1);
// This means that the following creation line returns a red,
rather than a color.
pixel = color::type_id::create("pixel", this);

// Override color with dark_red type by name.


set_type_override_by_name( color,

dark_red,

1);
// This means that the following creation line returns a dark_red,
rather than a red.
pixel = color::type_id::create("pixel", this);

7 | Verification Engineer UTL Technologies Ltd


Component Instance Overrides
A specific component instance can be overridden by specifying its position in the uvm component
hierarchy. Again, this approach can be used with parameterized classes provided care is taken to
match the parameterization of the two class types involved in the override.
Component Instance override can be implemented in two ways, one is by overriding specific
instance by type and other one is overriding specific instance by name. These are best explained
in following examples.
• set_inst_override_by_type(arg1, arg2, arg3);
– Arg1 is full instance path
– Arg2 is original type

• Handle.get_type()

• Class_name::get_type()
– Arg3 is overriding type

– set_inst_override_by_type( "agent1.driver1“,

B_driver::get_type(),

D2_driver::get_type());

• set_inst_override_by_name(arg1, arg2, arg3);


– Arg1
• Arg1 is full instance path
– Arg2
• String, name of the original type..
– Arg3
• String, name of the override type
– set_type_override_by_name( "agent1.driver1“,
“B_driver”,
” D2_drive”);
The following code fragments illustrate the method calls for parameterized component override
at specific instance by type and name:
/* Program 1.7 Sample code fragments illustrate parameterized component
override at specific instance by type and name */

class driverB #(type T=uvm_object) extends uvm_driver;


// parameterized classes must use the _param_utils version
`uvm_component_param_utils(driverB #(T))

// our packet type; this can be overridden via the factory


T pkt;

// standard component constructor


function new(string name, uvm_component parent=null);
super.new(name,parent);
endfunction

// get_type_name not implemented by macro for parameterized


classes
const static string type_name = {"driverB #(",T::type_name,")"};
virtual function string get_type_name();

8 | UVM Factory and Configuration Database


return type_name;
endfunction

virtual function void build_phase(uvm_phase phase);


pkt = packet::type_id::create("pkt",this);
endfunction

// etc;

endclass

/* For purposes of illustrating type and instance overrides, we define


two subtypes of the ~driverB~ class. The subtypes are also
parameterized, so we must again provide an implementation for
<uvm_object::get_type_name>, which we recommend writing in terms of a
static string constant. */

class driverD1 #(type T=uvm_object) extends driverB #(T);


`uvm_component_param_utils(driverD1 #(T))

function new(string name, uvm_component parent=null);


super.new(name parent);
endfunction

const static string type_name = {"driverD1 #(",T::type_name,")"};

virtual function string get_type_name();


return type_name;
endfunction
endclass

class driverD2 #(type T=uvm_object) extends driverB #(T);

`uvm_component_param_utils(driverD2 #(T))

function new(string name, uvm_component parent=null);


super.new(name, parent);
endfunction

const static string type_name = {"driverD2 #(",T::type_name,")"};

virtual function string get_type_name();


return type_name;
endfunction

endclass

// typedef some specializations for convenience


typedef driverB #(packet) B_driver; // the base driver
typedef driverD1 #(packet) D1_driver; // a derived driver
typedef driverD2 #(packet) D2_driver; // another derived driver

/* Next, we'll define a agent component, which requires a utils macro


for non-parameterized types. Before creating the drivers using the
factory, we override ~driver0~'s packet type to be ~packetD~. */
class agent extends uvm_agent;
`uvm_component_utils(agent)
...
B_driver driver0;
B_driver driver1;

9 | Verification Engineer UTL Technologies Ltd


function new(string name, uvm_component parent=null);
super.new(name,parent);
endfunction

virtual function void build_phase(uvm_phase phase);


// override the packet type for driver0 and below
packet::type_id::set_inst_override(packetD::get_type(),"driv
er0.*");

// create using the factory; actual driver types may be


different
driver0 = B_driver::type_id::create("driver0",this);
driver1 = B_driver::type_id::create("driver1",this);
endfunction

endclass

/* Finally we define an environment class, also not parameterized. Its


build method shows three methods for setting an instance override on a
grandchild component with relative path name, ~agent1.driver1~, all
equivalent. */

class env extends uvm_env;

`uvm_component_utils(env)

agent agent0;
agent agent1;

function new(string name, uvm_component parent=null);


super.new(name,parent);
endfunction

virtual function void build_phase(uvm_phase phase);

// three methods to set an instance override for


agent1.driver1
// - via component convenience method...
set_inst_override_by_type("agent1.driver1",
B_driver::get_type(),
D2_driver::get_type());
// create agents using the factory; actual agent types may
be different
agent0 = agent::type_id::create("agent0",this);
agent1 = agent::type_id::create("agent1",this);
endfunction

endclass

/* Configuring the factory with type and instance overrides:


In the previous step, we demonstrated setting instance overrides and
creating components using the factory within component classes. Here, we
will demonstrate setting overrides from outside components, as when
initializing the environment prior to running the test. */

10 | UVM Factory and Configuration Database


module top;
env env0;

initial begin

// Being registered first, the following overrides take


precedence
// over any overrides made within env0's construction &
build.

// Replace all base drivers with derived drivers...


B_driver::type_id::set_type_override( D_driver::get_type());

// ...except for agent0.driver0, whose type remains a base


driver.

// instance override by instance


set_inst_override_by_type( {get_full_name(),
"env0.agent0.driver0"},
B_driver::get_type(),
B_driver::get_type());

// now, create the environment; our factory configuration


will
// govern what topology gets created
env0 = new("env0");
//|
// run the test (will execute build phase)
run_test();
end

endmodule

When the above example is run, the resulting topology (displayed via a call to
<uvm_root::print_topology> method) is similar to the following:
# UVM_INFO @ 0 [RNTST] Running test ...
# UVM_INFO @ 0 [UVMTOP] UVM testbench topology:
# ----------------------------------------------------------------
# Name Type Size
Value
# ----------------------------------------------------------------
# env env - env0@2
# agent0 agent - agent0@4
# driver0 driverB #(packet) - driver0@8
# pkt packet - pkt@21
# driver1 driverD #(packet) - driver1@14
# pkt packet - pkt@23
# agent1 agent - agent1@6
# driver0 driverD #(packet) - driver0@24
# pkt packet - pkt@37
# driver1 driverD2 #(packet)- driver1@30
# pkt packet - pkt@39
# ----------------------------------------------------------------

11 | Verification Engineer UTL Technologies Ltd


Object Overrides:

Objects can also be overridden by type or instance. But objects or sequence related objects are
generally only used with type overrides since the instance override approach relates to a position
in the UVM testbench component hierarchy which objects do not take part in.

However there is a coding trick which can be used to override specific "instances" of an object
and this is explained in the session on uvm sequences. The code for an object override follows
the same form as the component override.

Type vs. Name Overrides:

• Type-based
– The type-based interface is far less prone to errors in usage.
– When errors do occur, they are caught at compile-time.
• Name-based
– The name-based interface is dominated by string arguments that can be
misspelled and provided in the wrong order.
– Errors in name-based requests might only be caught at the time of the call, if at
all.
– Further, the name-based interface is not portable across simulators when used
with parameterized classes.

Factory Override - Precedence:-

In real time scenarios, multiple factory overrides at various hierarchy levels are used. To keep
factory override deterministic, few precedence rules are defined.

• Always instance overrides take precedence over type overrides


• Among type overrides, the last override takes precedence
• Among instance overrides, the first override takes precedence.

UVM Configuration
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 System Verilog variables, which
can be set (and changed) at runtime, or System Verilog parameters, which must be set at compile
time. Because of the flexibility they offer, variables organized 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

12 | UVM Factory and Configuration Database


• The Parameters and reuse article shows how to pass large numbers of parameters down
through the uvm_component hierarchy.

The uvm_config_db class is the recommended way to access the resource database. A resource is
any piece of information that is shared between more than one component or object. We use
uvm_config_db::set to put something into the database and uvm_config_db::get to retrieve
information from the database. The uvm_config_db class is parameterized, so the database
behaves as if it is partitioned into many type-specific "mini databases." There are no limitations on
the type - it could be a class, a uvm_object, a built in type such as a bit, byte, or a virtual interface.

There are two typical uses for uvm_config_db. The first is to pass virtual interfaces from the DUT
to the test, and the second is to pass configuration classes down through the testbench.

uvm_config_db – set method:-


The full signature of the set method is,
void uvm_config_db #( type T = int )::set(uvm_component cntxt ,
string inst_name ,
string field_name ,
T value );
• T is the type of the element being configured - usually a virtual interface or a
configuration object.
• cntxt and inst_name together form a scope that is used to locate the resource within the
database. The scope is formed by appending the instance name to the full hierarchical
name of the context, i.e. {cntxt.get_full_name(),".",inst_name}.
• Field_name supplies the name of the resource
• value is the thing which is actually going to be put into the database.

/* Program 1.8 Sample code fragments illustrate putting virtual


interfaces from top module into the configuration database */
// Defining the interfaces

interface ahb_if data_port_if( clk , reset );


interface ahb_if control_port_if( clk , reset );
...
// set interfaces to configuration database
uvm_config_db #( virtual ahb_if )::set( null , "uvm_test_top" ,
"data_port" , data_port_if );

uvm_config_db #( virtual ahb_if )::set( null , "uvm_test_top" ,


"control_port" , control_port_if );

This code puts two AHB interfaces into the configuration database at the hierarchical location
"uvm_test_top", which is the default location for the top level test component created by
run_test(). The two different interfaces are put into the database using two distinct names,
"data_port" and "control_port". Two things to note about this code are:
• We use "uvm_test_top" because it is more precise and more efficient than "*". This will
always work unless your top level test does something other than super.new( name ,
parent ) in the constructor of your test component. If you do something different in your
test component, you will have to adjust the instance name accordingly.

13 | Verification Engineer UTL Technologies Ltd


• We use "null" in the first argument because this code is in a top level module not a
component.

/* Program 1.9 Sample code fragments illustrate configuring agents


inside an env */

class env extends uvm_env;


//
ahb_agent_config ahb_agent_config_h;
//
function void build_phase( uvm_phase phase );
...
m_ahb_agent = ahb_agent::type_id::create("m_ahb_agent"
, this );
...
uvm_config_db #( ahb_agent_config )::set( this ,
"m_ahb_agent*",
"ahb_agent_config"
,
ahb_agent_config_h
);
...
endfunction
endclass
This code sets the configuration for the ahb agent and all its children. Two things to note about
this code are:
• We use "this" as our first argument, so we can be sure that we have only
configured this env's agent and not any other ahb agent in the component hierarchy.
• We use "m_ahb_agent*" to ensure that we config both the agent and its children.
Without the '*' we would only configure the agent itself and not the driver, sequencer and
monitor inside it.

uvm_config_db – get method:-


The full signature of the get method is,
bit uvm_config_db #( type T = int )::get( uvm_component cntxt ,
string inst_name ,
string field_name ,
ref T value );

• T is the type of the element being configured - usually a virtual interface or a


configuration object.
• cntxt and inst_name together form a scope that is used to locate the resource within the
database. The scope is formed by appending the instance name to the full hierarchical
name of the context, i.e. {cntxt.get_full_name(),".",inst_name}.
• Field_name supplies the name of the resource.
• value is the thing which is going to be retreived from the database. If the call to get is
successful, this value will be overwritten.
• The method returns 1 if it is successful and 0 if there is no such resource of this type at
this location.

14 | UVM Factory and Configuration Database


/* Program 1.10 Sample code fragments illustrate getting virtual
interfaces from the configuration database */

class test extends uvm_test;


...
function void build_phase( uvm_phase phase );
...
if( !uvm_config_db #( virtual ahb_if )::get( this ,
"" ,
"data_port" ,
m_cfg.m_data_port_config.m_ahb_if))
begin
`uvm_error("Config Error" , " #( virtual ahb_if )::get can’t
find resource" ) )
end
...
endfunction
...
endclass

The code attempts to get the virtual interface for the AHB dataport and put it into the correct
agent's configuration class. If this attempt does not succeed, we provide a meaningful error
message.
/* Program 1.11 Sample code fragments illustrate getting a configuration
class in a transactor */
class ahb_monitor extends uvm_monitor;
ahb_agent_config m_cfg;
function void build_phase( uvm_phase phase );
...
if( !uvm_config_db #( ahb_agent_config )::get( this ,
"" ,
"ahb_agent_config”,
m_cfg)) begin
`uvm_error("Config Error" ,
"#( ahb_get_config )::get can’t find resource"" )
end
...
endfunction
endclass

This code gets the configuration for the ahb agent and all its children. Two things to note about
this code are:

• We always use this as the context


• We usually use "" as the instance name
• We always check to see if the call to get has succeeded. If it doesn't, we produce a
reasonable error message.

15 | Verification Engineer UTL Technologies Ltd


Configuration Object:-
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.
/* Program 1.12 Sample code fragments illustrate configuration object */
class env_config extends uvm_object;
`uvm_object_utils(env_config)
// Configuration Parameters
iic_slave_agent_config m_iic_slave_agent_config;
wb_agent_config m_wb_agent_config;
int m_wb_verbosity; // verbosity level for wishbone messages
int m_iic_verbosity; // verbosity level for wishbone messages

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

/* Program 1.12 Sample code fragments illustrate using configuration


object */
class iic_test extends uvm_test;
`uvm_component_utils(iic_test)
iic_slave_agent_config m_iic_slave_agent_config;
wb_agent_config m_wb_agent_config;
env_config m__env_config;
virtual iicIf m_iicIf;
virtual wbIf m_wbIf;

// Methods
function void build_phase(uvm_phase phase);
super.build_phase(phase);
`uvm_info(get_type_name(),"START Build_Phase",UVM_DEBUG)
// get virtual interface from config_cb set by top
if(!uvm_config_db#(virtual iicIf)::get(this, "", "iicIf", m_iicIf))

16 | UVM Factory and Configuration Database


`uvm_error("iic_test ", "Could not get iic interface handle
handle #1.")
if(!uvm_config_db#(virtual wbIf)::get(this, "", "wbIf", m_wbIf))
`uvm_error("iic_test ", "Could not get wishbone interface
handle handle.")
// build sub-components
m_iic_slave_agent_config =
iic_slave_agent_config::type_id::create("m_iic_slave_agent_config"
);
m_wb_agent_config =
wb_agent_config::type_id::create("m_wb_agent_config");
m_env_config =
iic_env_config::type_id::create("m_iic_env_config");
m_wb_agent_config.m_wbFrequency = P_DEFAULTWBFREQUENCY;
m_iic_slave_agent_config.m_iicIf = m_iicIf1;
m_wb_agent_config.m_wbIf = m_wbIf;
m_env_config.m_wb_agent_config = m_wb_agent_config;
m_env_config.m_iic_slave_agent_config =
m_iic_slave_agent_config;
uvm_config_db #( env_config )::set( this , "*" , "env_config" ,
m__env_config );
`uvm_info("iic_test”, "END Build_Phase",UVM_DEBUG)
endfunction

endclass

17 | Verification Engineer UTL Technologies Ltd


LAB
1. Create the following hierarchy,
uvm_test_top test

env1_h env2
agnt1_h agnt1

agnt2_h agnt2
env2_h env2
agnt1_h agnt1

agnt2_h agnt2

Experiment various ways of overriding agnt1 with agent2. Print topology for every
attempt and observe results.

2. Configure some data from Test case and retrieve the configuration information at various
sub-component levels

18 | UVM Factory and Configuration Database


Key Learning's
 UVM Factory is a singleton class <True/False>
 UVM Factory registration is done using ______________________ macros.
 Usage of create method without using factory registration results in _________
 Usage of get_config_db on a variable before setting its value returns ____________
 Configuration is set at ________________phase.

Worksheet

 List the advantages of using UVM Factory.


_______________________________________________________________________________________________
_______________________________________________________________________________________________

 Explain various ways of overriding a component.


_______________________________________________________________________________________________
_______________________________________________________________________________________________

 List the advantages of UVM Configuration Database


________________________________________________________________________________
________________________________________________________________________________

 Explain Factory Override precedence


_______________________________________________________________________________
_______________________________________________________________________________

 Explain Configuration precedence


_______________________________________________________________________________
_______________________________________________________________________________

19 | Verification Engineer UTL Technologies Ltd