Uvm Assignment-1: Some of The Benefits of Using UVM Are
Uvm Assignment-1: Some of The Benefits of Using UVM Are
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.
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)
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
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.
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;
apb_master apb_master(.pclk(pclk),*);
initial begin
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.
`uvm_component_utils(apb_env);
//Build phase - Construct agent and get virtual interface handle from test and
begin
end
endfunction: build_phase
endclass : apb_env