0% found this document useful (0 votes)
214 views

Uvm Assignment-1: Some of The Benefits of Using UVM Are

The document discusses various concepts related to UVM (Universal Verification Methodology) and TLM (Transaction Level Modeling) such as: 1. Benefits of UVM include modularity, reusability, and better control of stimulus generation. 2. TLM models a system using function calls that define transactions over channels, allowing faster simulation than RTL. 3. TLM ports define communication APIs and exports implement them, connecting model components.

Uploaded by

venkatesh
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
214 views

Uvm Assignment-1: Some of The Benefits of Using UVM Are

The document discusses various concepts related to UVM (Universal Verification Methodology) and TLM (Transaction Level Modeling) such as: 1. Benefits of UVM include modularity, reusability, and better control of stimulus generation. 2. TLM models a system using function calls that define transactions over channels, allowing faster simulation than RTL. 3. TLM ports define communication APIs and exports implement them, connecting model components.

Uploaded by

venkatesh
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 12

UVM ASSIGNMENT-1

1) What are some of the benefits of UVM methodology?

Some of the benefits of using UVM are:


a. Modularity and Reusability – The methodology is designed as modular
components (Driver, Sequencer, Agents , env etc) which enables reusing
components across unit level to multi-unit or chip level verification as well
as across projects.
b. Separating Tests from Test benches – Tests in terms of
stimulus/sequencers are kept separate from the actual test bench hierarchy
and hence there can be reuse of stimulus across different units or across
projects.
c. Simulator independent – The base class library and the methodology is
supported by all simulators and hence there is no dependence on any
specific simulator.
d. Better control on Stimulus generation – Sequence methodology gives
good control on stimulus generation. There are several ways in which
sequences can be developed which includes randomization, layered
sequences, virtual sequences etc which provides a good control and rich
stimulus generation capability.
e. Easy configuration – Config mechanisms simplify configuration of
objects with deep hierarchy. The configuration mechanism helps in easily
configuring different test bench components based on which verification
environment uses it and without worrying about how deep any component
is in test bench hierarchy.
f. Factory mechanism – Factory mechanisms simplifies modification of
components easily. Creating each components using factory enables them
to be overridden in different tests or environments without changing
underlying code base.

2) What is the concept of Transaction Level Modelling?


Transaction-level modelling (TLM) is a technique for describing a system by using
function calls that define a set of transactions over a set of channels.
TLM descriptions can be more abstract, and therefore simulate more quickly than the
register-transfer level (RTL) descriptions more traditionally used as a starting point
for IC implementations. However TLM can still be used to define designs in a less
abstract, more detailed way. More recently, it is increasingly used to encapsulate
existing detailed functional block descriptions, creating consistent frameworks
( ‘virtual platforms’), for integrating and simulating various components in system
designs that are evolving at many levels of abstraction.

TLM as a concept is not tied to one language. Early implementations, such as those
used to develop mainframe computers, relied on proprietary languages. As a standard
API for system modeling, TLM is implemented as a layer on top of SystemC, a
modeling language and simulation environment built on top of C++ as a class library.
One problem encountered by early adopters of SystemC and TLM was a lack of
consistency among and across models, which made it difficult for companies to
exchange them. TLM 2.0, released in June 2008, defined interfaces that have
improved compatibility between models that have been developed by different teams
3) What are TLM ports and exports?
In Transaction Level Modelling, different components or modules communicate using
transaction objects. A TLM port defines a set of methods (API) used for a particular
connection while the actual implementation of these methods are called TLM exports.
A connection between the TLM port and the export establishes a mechanism of
communication between two components.
Here is a simple example of how a producer can communicate to a consumer using a
simple TLM port. The producer can create a transaction and “put” to the TLM port,
while the implementation of “put” method which is also called TLM export would be
in the consumer that reads the transaction created by the producer, thus establishing a
channel of communication.
4) What are TLM FIFOs?
A TLM FIFO is used for Transactional communication if both the producing
component and the consuming component need to operate independently. In this case
(as shown below), the producing component generates transactions and “puts” into
FIFO, while the consuming component gets one transaction at a time from the FIFO
and processes it.
5) What is the difference between a get() and peek() operation on a TLM FIFO?
The get() operation will return a transaction (if available) from the TLM FIFO and
also removes the item from the FIFO. If no items are available in the FIFO, it will
block and wait until the FIFO has at least one entry.
The peek() operation will return a transaction (if available) from the TLM FIFO
without actually removing the item from the FIFO. It is also a blocking call that waits
if FIFO has no available entry.
6) What is the difference between a get() and try_get() operation on a TLM FIFO?
get() is ablocking call to get a transaction from TLM FIFO. Since it is blocking, the
task get() will wait if no items are available in the FIFO stalling execution.
On the other hand, try_get() is a nonblocking call which will return immediately even
if no items are available in the FIFO. The return value of try_get() indicates if a valid
item is returned or not.
Following are two equivalent implementations using get() and try_get()
1)Using the blocking method - get()
class consumer extends uvm_component;
uvm_get_port #(simple_trans) get_port;
task run;
for(int i=0; i<10; i++) begin
t = get(); //blocks until a transaction is returned //Do something with it.
end
endtask
endclass
2) Equivalent implementation using nonblocking method - try_get()
class consumer extends uvm_component;
uvm_get_port #(simple_trans) get_port;
task run;
for(int i=0; i<10; i++) begin
//Try get is nonblocking. So keep attempting
//on every cycle until you get something
//when it returns true
while(!get_port.try_get(t)) begin
wait_cycle(1);
//Task that waits one clock cycle
end
//Do something with it
End
Endtask
endclass
7) What is the difference between analysis ports and TLM ports? And what is the
difference between analysis FIFOs and TLM FIFOs? Where are the analysis
ports/FIFOs used?
The TLM ports/FIFOs are used for transaction level communication between two
components that have a communication channel established using put/get methods.

Analysis ports/FIFOs are another transactional communication channel which are


meant for a component to distribute (or broadcast) transaction to more than one
component.
TLM ports/FIFOs are used for connection between driver and sequencer while
analysis ports/FIFOs are used by monitor to broadcast transactions which can be
received by scoreboard or coverage collecting components.

8) What is the difference between a uvm_transaction and a uvm_sequence_item?


A sequence item is an object that models the information being transmitted between
two components (sometimes it can also be called a transaction).
For Example: consider memory access from a CPU to the main memory where CPU
can do a memory read or a memory write, and each of the transaction will have some
information like the address, data and read/write type.
A sequence can be thought of a defined pattern of sequence items that can be send
to the driver for injecting into the design. The pattern of sequence items is defined
by how the body() method is implemented in sequence.
For Example: Extending above example, we can define a sequence of 10
transactions of reads to incremental memory addresses. In this case, the body()
method will be implemented to generate sequence items 10 times, and send them to
driver while say incrementing or randomizing address before next item.

9) What is the difference between copy(), clone(), and create() method in a


component class?
1) The create() method is used to construct an object.
2) The copy() method is used to copy an object to another object.
3) The clone() method is a one-step command to create and copy an existing object to
a new object handle. It will first create an object by calling the create() method and
then calls the copy() method to copy existing object to the new handle.

10) What is a factory?

UCM Factory is used to manufacture (create) UVM objects and components. Apart
from creating the UVM objects and components the factory concept essentially means
that you can modify or substitute the nature of the components created by the factory
without making changes to the test bench. 
For example, if you have written two driver classes, and the environment uses only
one of them. By registering both the drivers with the factory, you can ask the factory
to substitute the existing driver in environment with the other type. The code needed
to achieve this is minimal, and can be written in the test.

11) What is the difference between creating an object using new() and create()
methods?
We all know about new () method that is use to allocate memory to an object instance. In
UVM (and OVM), the create () method causes an object instance to be created from the
factory. This allows you to use factory overrides to replace the desired object with an object
of a different type without having to recode.
12) How do we register an uvm_component class and uvm_sequence class with
factory?
The uvm_sequence class is registered with the factory using uvm_object_utils()
macro and passing the class name as an argument.
An example below:
class test_seq_c extends uvm_sequence;
`uvm_object_utils(test_seq_c)

he uvm_component class is registered with the factory using uvm_component_utils()


macro and passing the class name as argument.
An Example below:
class test_driver_c extends uvm_component;
`uvm_component_utils(test_driver_c)
13) Why should we register a class with factory?
A factory is a special look-up table used in UVM for creating objects of component or
transaction types. The benefit of object creation using the factory is that a testbench
build process can decide at run-time which type of object has to be created. Based on
this, a class type could be substituted with another derived class type without any real
code change. To ensure this feature and capability, all classes are recommended to be
registered with the factory. If you do not register a class with the factory, then you
will not be able to use the factory method::type_id::create() to construct an object.
14) What is meant by factory override?
The UVM factory allows a class to be substituted with another derived class at the
point of construction. This can be useful for changing the behaviour of a testbench by
substituting one class for another without having the need to edit or re-compile the
testbench code.
15) What is the difference between instance override and type override?
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. On the other hand, an instance override means,
overriding only a specific instance of a component class. A specific instance of a
component is referenced by the position of that component in the UVM component
hierarchy. Since only UVM component classes can have a hierarchy in UVM test
benches, only component classes can be overridden on an instance granularity while
sequences (or UVM objects) can be the only type overridden.
16) What is the concept of phasing in UVM methodology?
Unlike a module-based testbench (in which all modules exist statically in a hierarchy),
a class-based testbench needs to manage the creation of different objects and
execution of various tasks and functions in those objects. Phasing is an important
concept in class-based testbenches to have a consistent testbench execution flow. Test
execution can be conceptually divided into the following tasks – configuration,
creation of testbench components, runtime stimulus, and end of test checks. UVM
defines standard phases for each of these as part of the methodology.
17) What are the different phases of a UVM component? What are the subphases for
the UVM run_phase()?
UVM uses standard phases to order the major steps that take place during simulation.
There are three groups of phases, which are executed in the following order.

1. Build phases – In the build phases; the testbench is configured and constructed. It
has following sub-phases which are all implemented as virtual methods in
uvm_component

base class.
1) build_phase()
2) connect_phase()
3) end_of_elaboration()
2. Run time phases – These phases can consume time and this is where most
of the test execution happens.
1) start_of_simulation()
2) run_phase()
The run_phase() is further divided into 12 sub-phases as below:
1) pre_reset
2) reset
3) post_reset
4) pre_configure
5) configure
6) post_configure
7) pre_main
8) main
9) post_main
10) pre_shutdown
11) shutdown
12) post_shutdown

18) Why is build_phase() executed top down in uvm_component hierarchy?


In UVM, all the testbench components like a test, Env, Agent, Driver, Sequencer are
based on the uvm_component class and there is always a hierarchy for the testbench
components. The build_phase() method is part of the uvm_component class and is
used to construct all the child components from the parent component. So, to build the
testbench hierarchy you always need to have a parent object first, which can then
construct its children, and that can further construct its children using build_phase.
Hence, build_phase() is always executed top-down.

For Example: The top level uvm_test class calls build_phase which should construct
all the uvm_env components part of this test, and the build_phase() of each uvm_env
class should construct all the uvm_agent components that are part of that uvm_env,
and this goes on. For all other phases it really doesn’t matter in which order it is
called. The run_phase() for all components runs in parallel.

19) i) Explain the concept of Agent in UVM methodology.

ii) What all different components can a UVM agent have?


20) i) How is ACTIVE agent different from PASSIVE agent?
An ACTIVE agent is an agent that can generate activity at the pin level interface on
which it operates. This means, the components like driver and sequencer would be
connected and there would be a sequence running on it to generate activity.
A PASSIVE agent is an agent that doesn’t generate any activity but can only monitor
activity happening on the interface. This means, in a passive agent the driver and
sequencer will not be created.
An Agent is normally configured ACTIVE in a block level verification environment
where stimulus is required to be generated. Same agent can be configured PASSIVE
as we move from block level to chip level verification environment in which no
stimulus generation is needed, but we still can use same for monitoring activity in
terms of debug or coverage.

ii) How is an Agent configured as ACTIVE or PASSIVE


UVM agents have a variable of type UVM_ACTIVE_PASSIVE_e which defines
whether the agent is active (UVM_ACTIVE) with the sequencer and the driver
constructed, or passive (UVM_PASSIVE) with neither the driver nor the sequencer
constructed. This parameter is called active and by default, it is set to
UVM_ACTIVE. This can be changed using set_config_int() while the agent is
created in the environment class. The build phase of the agent should then have the
code as below to selectively construct driver and sequencer.
function void build_phase(uvm_phase phase);
if(m_cfg.active == UVM_ACTIVE)
begin //create driver, sequencer
end
endfunction
21) What is a sequencer and a driver, and why are they needed?

A Driver is a component that converts a transaction or sequence item into a set of pin
level toggling based on the signal interface protocol. A Sequencer is a component that
routes sequence items from a sequence to a driver and routes responses back from
driver to sequence. The sequencer also takes care of
arbitration between multiple sequences (if present) trying to access driver to stimulate
the design interface. These components are needed as in a TLM methodology like
UVM, stimulus generation is abstracted in terms of transactions and the sequencer and
driver are the components that route them and translate them to actual toggling of
pins.

22) What is the concept of objections and where are they useful?
The uvm_objection class provides a means for sharing a counter between multiple
components and sequences. Each component/sequence may “raise” and “drop”
objections asynchronously, which increases or decreases the counter value. When the
counter reaches zero (from a non-zero value), an “all dropped” condition is said to
occur. The objection mechanism is most commonly used in the UVM phasing
mechanism to coordinate the end of each run-time phase. User-processes started in a
phase raises an objection first and drops the objection once the process completes.
When all processes in a phase drops the objects, the phase’s objection count goes to
zero. This “all dropped” condition indicates to the phasing mechanism that every
participant agrees the phase should be ended.
23) i) What is uvm_config_db and what is it used for?
The UVM configuration mechanism supports sharing of configurations and
parameters across different testbench components. This is enabled using a
configuration database called uvm_config_db. Any testbench component can populate
the configuration database with variables, parameters, object handles, etc. Other
testbench components can get access to these variables, parameters, object handles
from the configuration database without really knowing where it exists in the
hierarchy. For Example, a top-level testbench module can store a virtual interface
pointer to the uvm_config_db. Then any uvm_driver or a uvm_monitor component
can query the uvm_config_db to get a handle to this virtual interface and use it for
actually accessing the signals through the interface.
ii) How do we use the get() and set() methods of uvm_config_db?
The get() and set() are the primary methods used to populate or retrieve information
from the uvm_config_db. Any verification component can use the set() method to
populate the config_db with some configuration information and can also control
which other components will have visibility to the same information. It could be set
to have global visibility or visible only to one or more specific testbench
components. The get() function checks for a shared configuration from the database
matching the parameters.
The syntax for the get() and set() methods are as follows:
uvm_config_db#(<type>)::set(uvm_component context, string
inst_name, string field_name,<type> value)
uvm_config_db#(<type>)::get(uvm_component context, string
inst_name, string field_name, ref value)
The context specifies the current class or component from which get/set is called.
The inst_name is the name of the instance of component from which get/set is
called.
The field_name is the name of the object or parameter or variable which is set/get in
config_db.
The <type> identifies the type of the configuration information set/get in
config_db. For object handles, this will have the class name while for other variables;
it will be the type of that variable.
24) Is it possible for a component lower in testbench hierarchy to pass a handle to a
component in higher level of hierarchy using get/set config methods?
25) What is the recommended way of assigning virtual interfaces to different
components in a UVM verification methodology
The top-level testbench module which instantiates the DUT and interfaces will set the
virtual interface in the uvm_config_db. A test class or any other component in the
UVM component hierarchy can then query the uvm_config_db using the get() method
to get handles to this virtual interface and use them for accessing signals. The
following shows an example of how this is done. The module test actually instantiates
a DUT and physical interface for an APB bus master. It then sets the virtual interface
handle to the uvm_config_db.

module test;

logic pclk;

logic [31:0] paddr;

//Instantiate an APB bus master DUT

apb_master apb_master(.pclk(pclk),*);

//Instantiate a physical interface for APB interface

apb_if apb_if(.pclk(pclk), *);

initial begin

//Pass this physical interface to test class top

//which will further pass it down to env->agent->drv/sqr/mon

uvm_config_db#(virtual apb_if)::set(null, “uvm_test_top”, “vif”, apb_if);

end

endmodule

Following shows a APB Env class that uses the get() method in uvm_config_db to

retrieve the virtual interface that was set in the top level test module.

class apb_env extends uvm_env;

`uvm_component_utils(apb_env);

//ENV class will have agent as its sub component


apb_agent agt;

//virtual interface for APB interface

virtual apb_if vif;

//Build phase - Construct agent and get virtual interface handle from test and

pass it down to agent

function void build_phase(uvm_phase phase);

agt = apb_agent::type_id::create(“agt”, this);

if (!uvm_config_db#(virtual apb_if)::get(this, ””, “vif”, vif))

begin

`uvm_fatal(“config_db_err”, “No virtual interface specified for this env


instance”)

end

uvm_config_db#(virtual apb_if)::set( this, “agt”, “vif”, vif);

endfunction: build_phase

endclass : apb_env

You might also like