100% found this document useful (4 votes)
4K views186 pages

UVM Class Notes Deepak Kumar Panda

UVM (Universal Verification Methodology) is a standardized methodology for functional verification using SystemVerilog. It provides reusable base classes and features like phasing, configuration, and TLM connections to help build modular, scalable verification environments. Some key components include drivers, monitors, sequencers, and a transaction library to streamline stimulus generation and response checking.

Uploaded by

Srimon Dey
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
100% found this document useful (4 votes)
4K views186 pages

UVM Class Notes Deepak Kumar Panda

UVM (Universal Verification Methodology) is a standardized methodology for functional verification using SystemVerilog. It provides reusable base classes and features like phasing, configuration, and TLM connections to help build modular, scalable verification environments. Some key components include drivers, monitors, sequencers, and a transaction library to streamline stimulus generation and response checking.

Uploaded by

Srimon Dey
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 186

Introduction to UVM

What is Methodology?
.❖ Best practices by verification experts
l

❖ Base Class Library

❖ Standard communication mechanism to achieve interoperability

❖ Configuration of the testbench from the top level

❖ Generate scenarios independent of testbench environment

❖ Achieve Reusability in plug and play manner


What is UVM?
• Universal Verification Methodology (UVM) is a standard to enable faster development and reuse of
verification environments and verification IP (VIP) throughout the industry.
• It is a set of class libraries defined using the syntax and semantics of SystemVerilog (IEEE
1800) and is now an IEEE standard.
• The main idea behind UVM is to help companies develop modular, reusable, and scalable
testbench structures by providing an API framework that can be deployed across multiple
projects.
• UVM is mainly derived from Open Verification Methodology (OVM) and is supported by
multiple EDA vendors like Synopsys, Cadence, Mentor and Aldec.
• The UVM class library provides generic utilities like configuration databases, TLM and
component hierarchy in addition to data automation features like copy, print, and compare.

• It brings in a layer of abstraction where every component in the verification environment


has a specific role.
• For example, a driver class object will be responsible only for driving signals to the design,
while a monitor simply monitors the design interface and does not drive signals to that
interface.
• These components already have the necessary code that will let them connect between
each other, handle data packets and work synchronously with others.
Evolution of UVM
.❖ Major EDA vendors had their own methodologies
l

➢ Mentor graphics - AVM for System Verilog


➢ Cadence - eRM for Spaceman e, uRM for System Verilog
➢ Synopsys - VMM for System Verilog

❖ Open Verification Methodology (OVM)


➢ Joint development initiative by Mentor graphics and Cadence
➢ Open, interoperable, System Verilog based Methodology

❖ Universal Verification Methodology (UVM)


➢ Common Methodology by Mentor graphics, Cadence and Synopsys
➢ Interoperability - Multi language support
➢ Based on OVM proven library
➢ Scales from Block level to System level
What is UVM ?

• SystemVerilog is a language just like Verilog and has its own


constructs, syntax and features, but UVM is a framework of
SystemVerilog classes from which fully functional testbenches can
be built.
• There's only one prerequisite to learn UVM, and that is
SystemVerilog because it is the foundation for the tower that is
UVM.
Why do we need UVM ?

• The primary advantage is that the methodology specifies and lays out a set of
guidelines to be followed for creation of verification testbenches.
• This will ensure testbench uniformity between different verification teams,
cross-compatability between IP and standalone environment integration,
flexibility and ease of maintaining testbenches.
• For example, there can be many different ways to implement display messages
and control verbosity with different settings such as warning, error and debug.
• In UVM, the underlying reporting mechanism has been standardized and made
available so that engineers can instead focus on the most important part of their
job which is design verification.
• Another example is that the sequencer-driver handshake mechanism is taken
care of under the hood so that only stimulus needs to be written.
• This saves quite a lot of time in setting up a testbench structure since the
foundation itself is well defined.
How does UVM help ?

• Every verification testbench has a few key components like


drivers, monitors, stimulus generators, and scoreboards.
• UVM provides a base class for each of these components with
standardized functions to instantiate, connect and build the
testbench environment.
• These are static entities called components in a verification
environment that exist throughout a simulation just like buildings
in a city.
• These components operate and process on some kind of data
that flows around the
• environment similar to people and vehicles in the city.
• The data or transactions are called objects or sequence items
since they appear and disappear at various times in the
simulation and is more dynamic in nature.
What is the UVM class hierarchy ?

• UVM provides a set of base classes from which more complex


classes can be built by inheritance and adding onto it certain
functions required for verification environment.
• For example, a new driver class for Wishbone protocol can be
built by extending from the UVM base class uvm_driver .
• Stimulus for the protocol can be written by extending from
uvm_sequence_item .
• How this sequence is built, and handed over to the driver is
taken care of internally by the UVM framework.
• uvm_void is the base of all classes, but it is primarily empty.
• uvm_object is the main class in which common functions to
print, copy, and compare two objects of the same class are
defined.
What is the UVM class hierarchy ?

• There are two branches in the hierarchy.


• The first one contains classes that define verification components like driver, monitor
and the rest shown in the diagram as everything underneath uvm_report_object .
• The second one defines data objects consumed and operated upon by verification
components shown in the diagram as everything underneath uvm_transaction .
Major UVM class categories UVM Objects

• The idea behind UVM is to enhance flexibility and reuse code so that the same testbench
can be configured in different ways to build different components, and provide different
stimulus.
• These new user defined configuration classes are recommended to be derived from
uvm_object .
• For example, a configuration class object can be built to have certain settings that define
how the testbench environment has to be built.
UVM Sequence

• UVM also introduces the concept of a sequence which is nothing but a


container for the actual stimulus to the design.
• If you put different stimuli into different sequences, it enhances the ability to
reuse and drive these sequences in random order to get more coverage and
verification results.
• All new user defined stimulus classes are recommended to be inherited
from uvm_sequence .
• Each sequence can be used inside other sequences to create different
scenarios.
• For example, individual sequences can be created, one each for "read" and
"write" transactions.
• They can be used in a random pattern in some other sequence to perform
R->W->R->W,or R->R->R->W, W->W->R->R and other similar patterns.
UVM Sequence Items

• Data objects that have to be driven to DUT are


generally called as sequence items and are
recommended to be inherited from
uvm_sequence_item .

• For example, a sequence item class can be defined


for an APB transaction that defines what the address,
write/read data and access type should be and send it
to an APB driver to drive the transaction to DUT.
UVM Components

• All major testbench components are derived from the


corresponding base class.
• For example, all new user defined driver classes are
recommended to be inherited
• from uvm_driver and monitor classes from uvm_monitor and so
on.
• A brief description of what each UVM component does is given in
the table below.
Register Layer

• Digital designs support control registers that can be configured


by software, and this has been very challenging in a
SystemVerilog testbench, because for each project you had to
build a separate set of classes that can store and configure
these registers.
• UVM has an extensive set of classes to make that task
relatively simpler and belong to something known as a register
model.
• This is very useful in the verification of IPs that can be reused
in various SoC designs.
TLM Connections

• Another really smart feature is the use of TLM from


System C.
• TLM helps to send data between components in the
form of transactions and class objects.
• It also brings a way to broadcast a packet to its
listeners without having to create specific channels
and attach to it.
UVM Phases

• Another main feature that verification components inherit from


their parent class uvm_component is Phasing.
• This enables every component to sync with each other before
proceeding to the next phase.
UVM Testbench Overview
.1.
l
UVM stand for the Universal Verification Methodology.
2. Created by Accellera based on the OVM (Open Verification
Methodology) version 2.1.1.
3. UVM is a methodology for functional verification using
SystemVerilog, complete with a supporting library of SystemVerilog
code.
4. UVM is a methodology for the functional verification of digital
hardware, primarily using simulation.
5. UVM is explicitly simulation-oriented, but UVM can also be used
alongside assertion-based verification, hardware acceleration or
emulation.
Why UVM Class Library?

The UVM Class Library provides generic utilities, such as

❖ component hierarchy,

❖ transaction library model (TLM),

❖ configuration database,

which enable the user to create virtually any structure for the
testbench.
Features of uvm_component Class

❖ hierarchy searching,

❖ phasing,

❖ configuration,

❖ reporting,

❖ factory,

❖ transaction recording
UVM Building Blocks

.
l

UVM UVM
UVM env
Components test

Main Building blocks of a UVM Test Bench


UVM Testbench

❖ Typical UVM Testbench Hierarchy


UVM Testbench Architecture

UVM Testbench
.
l

UVM Test

Sequences
UVM Environment
UVM Agent

UVM
Sequencer UVM Agent Design
UVM
Under Test
UVM
Scoreboard Environment ( DUT )
UVM
Config/Factory Environment
Overrides
UVM Testbench Architecture
Module TOP
UVM Test
UVM Env
Agent [0]

Sequencer Config
Config Interface
Sequencer [0]
Scoreboard 0
Scoreboard 0 Driver Driver

MonitorMonitor

Agent [1]
Config
Config Interface
Sequencer
Sequencer
[1]
Scoreboard 1
Scoreboard 1 Driver Driver

MonitorMonitor

Sequence 1 Sequence 2 Sequence 3 Run (task)


UVM Testbench

➢ Instantiate
● Design under Test (DUT) module
● UVM Test class

➢ Configure connection between DUT and Test Class

➢ Dynamically Instantiate
● UVM Test

➢ Advantage
● compiled once
● run with many different tests.
UVM Test

➢ The test is the topmost class. the test is responsible for,

● configuring the testbench.

● Initiate the testbench components construction process by building


the next level down in the hierarchy ex: env.

● Initiate the stimulus by starting the sequence.


UVM Test

class user_defined_test extends uvm_test;

----------------------

endclass

➢ uvm_test is the base class from UVM class library.

➢ uvm_test extends uvm_component.

➢ So uvm_test is a component.
UVM Environment

Agent/UVC
Mem Controller Agent DUT
Component
Repository
UVM
UVM Driver
Sequencer Memory
Controller

UVM Monitor

Peripheral Agent
UVM
UVM Driver
Sequencer
Peripheral

UVM Monitor
UVM Environment

➢ Env or environment: The environment is a container component for


grouping higher level components like agent’s and scoreboard.

➢ It is a hierarchical component which is extended from


uvm_component.

➢ It groups together other verification components that are interrelated.

➢ uvm_env is used to create and connect the uvm_components like


driver, monitors, sequencers, UVM Scoreboards etc.

➢ A environment class can also be used as sub-environment in another


environment.
UVM Environment

class user_defined_env extends uvm_env;

----------------------

endclass

➢ uvm_env is the base class from UVM class library.

➢ uvm_env extends uvm_component.

➢ So uvm_env is a component.
UVM Environment (Example)

➢ In a typical system on a chip (SoC) UVM Environment,


● one UVM Environment per IP
■ PCIe Environment,
■ USB Environment,
■ Memory Controller Environment, etc.).

➢ IP Environments are grouped together into Cluster Environments


● IO Environment,
● Processor Environment

These are grouped together eventually into SoC Environment.


What is UVM Agent?

➢ UVM agent groups the uvm_components specific to an interface or protocol.


➢ example: groups the components associated with BFM(Bus Functional Model).
➢ The components of an agent are,

➢ UVM Agent
● Encapsulated, Ready to use, Configurable components
● Reusable - plug and play

➢ UVM environment contains one or more agents.


● Agent - Driver, Monitor and Sequencer

➢ Agent can be configurable

➢ Testbench infrastructure can have more than one agents

➢ Also known as UVC (Universal Verification Component)


UVM Agent

Sequence
UVM Agent

UVM
UVM Driver
Sequencer

DUT
UVM Monitor interface
UVM Agent

➢ Verification Component includes


● Sequence_item
■ Data item based on the DUT protocol
■ Also known as stimulus

● Sequencer
■ Manage stimulus flow
■ Route sequence_items from a sequence to the driver

● Driver
■ It converts sequence_item into the pin level for DUT

● Monitor
■ It converts pin level data to the transactions for use in scoreboard, coverage
models, etc
UVM Agent

➢ Verification Component includes


● Configuration object
■ A container object, used to pass information to the agent which affects what
it does and how it is built and connected

● Sequencers and Drivers are connected using TLM ports

● Other components
■ coverage collectors,
■ protocol checkers,
■ TLM mode
UVM Agent

class user_defined_agent extends uvm_agent;

----------------------

endclass

➢ uvm_agent is the base class from UVM class library.

➢ uvm_agent extends uvm_component.

➢ So uvm_agent is a component.
UVM Agent

Interface
Config
DUT is_active = 0
UVM
Agent Monitor
vi

(Passive)

UVM
UVM
Sequen vi
Driver
Interface

cer
Config
DUT
is_active = 1
UVM
Agent Monitor
vi

(Active)
UVM Agent

➢ Needs to operate both in

● an active mode

It is capable of generating stimulus

● a passive mode

It only monitors the interface without controlling it.


UVM Sequencer

➢ Serves as an arbiter for controlling transaction flow from multiple


stimulus sequences.

➢ UVM Sequencer controls the flow of UVM Sequence Items


transactions generated by one or more UVM Sequences.
➢ Responsible for routing the data packet’s(sequence_item) generated in
sequence to the driver or vice verse.
UVM Sequencer

class user_defined_sequencer extends uvm_sequencer #(REQ, RSP);

----------------------

endclass

➢ uvm_sequencer is the base class from UVM class library.

➢ uvm_sequencer extends uvm_component.

➢ So uvm_sequencer is a component.
UVM Sequence

➢ It is an object that contains a behavior for generating stimulus.


➢ Defines the sequence in which the data items need to be generated and
sent/received to/from the driver.

➢ UVM Sequences are not part of the component hierarchy.

➢ A UVM Sequence instance can come into existence for a single


transaction.

➢ It may drive stimulus for the duration of the simulation, or anywhere in


between.
UVM Sequence

➢ Can operate hierarchically with one sequence, called a parent


sequence, invoking another sequence, called a child sequence.

➢ Each UVM Sequence is eventually bound to a UVM Sequencer.

➢ Multiple UVM Sequence instances can be bound to the same UVM


Sequencer.
UVM Sequence

class user_defined_sequence extends uvm_sequence #(REQ, RSP);

----------------------

endclass

➢ uvm_sequence is the base class from UVM class library.

➢ uvm_sequence extends uvm_object.

➢ So uvm_sequence is a object.
UVM Driver

➢ The UVM Driver receives individual UVM Sequence Item transactions


from the UVM Sequencer and applies (drives) it on the DUT Interface.

➢ A UVM Driver spans abstraction levels by converting transaction-level


stimulus into pin-level stimulus.

➢ TLM port
● Receive transactions from the Sequencer
● Access to the DUT interface in order to drive the signals.
UVM Driver

class user_defined_driver extends uvm_driver;

----------------------

endclass

➢ uvm_driver is the base class from UVM class library.

➢ uvm_driver extends uvm_cmponent.

➢ So uvm_driver is a component.
UVM Monitor

➢ Observes pin level activity on interface signals and converts into


packet level which is sent to components such as scoreboards.

➢ It samples the DUT interface and captures the information therein


transactions that are sent out to the rest of the UVM Testbench for
further analysis.

➢ It spans abstraction levels by converting pin-level activity to


transactions.

➢ It has TLM analysis port to broadcast the created transactions through.

➢ Perform coverage collection, checking, logging, recording, etc. or can


delegate that to dedicated components connected to the monitor's
analysis port.
UVM Monitor

class user_defined_monitor extends uvm_monitor;

----------------------

endclass

➢ uvm_monitor is the base class from UVM class library.

➢ uvm_monitor extends uvm_component.

➢ So uvm_sequence is a component.
UVM Scoreboard

• Receives data item’s from monitor’s and compares with expected values.
Summary : UVM Testbench Overview
.1. UVM Testbench
l

2. UVM Test
3. UVM Environment
4. UVM Agent
5. UVM Sequencer
6. UVM Sequence
7. UVM Driver
8. UVM Monitor
Thank You

Questions ??
UVM Sequencer

• The sequencer controls the flow of request and response


sequence items between sequences and the driver
• Sequencer and driver uses TLM Interface to communicate
transactions
• uvm_sequencer and uvm_driver base classes have
seq_item_export and seq_item_port defined respectively. User
needs to connect them using TLM connect method.
The DUT

• The DUT used is a simple ALU, limited to a single operation: the add
operation. The inputs and outputs are represented in Figure.
• This DUT takes two values of 2 bits each, ina and inb, sums them and
sends the result to the output out.
• The inputs are sampled to the signal of en_i and the output is sent at
the same time en_o is signalled.
• Right now, we have a DUT and we will have to interact with it in
order to test its functionality, so we need to stimulate it.
• To achieve this, we will need a block that generates sequences
of bits to be transmitted to the DUT, this block is going to be
named sequencer.

• Usually sequencers are unaware of the communication bus,


they are responsible for generating generic sequences of data
and they pass that data to another block that takes care of the
communication with the DUT. This block will be the driver.

• While the driver maintains activity with the DUT by feeding it


data generated from the sequencers, it doesn’t do any
validation of the responses to the stimuli. We need another
block that listens to the communication between the driver and
the DUT and evaluates the responses from the DUT. This block
is the monitor.
• Monitors sample the inputs and the outputs of the DUT, they try
to make a prediction of the expected result and send the
prediction and result of the DUT to another block,
the scoreboard, in order to be compared and evaluated.

• All these blocks constitute a typical system used for verification


and it’s the same structure used for UVM testbenches.
• Usually, sequencers, drivers and monitors compose an agent.
• An agent and a scoreboard compose an environment.
• All these blocks are controlled by a greater block denominated
of test.
• The test block controls all the blocks and sub blocks of the
testbench.
• This means that just by changing a few lines of code, we could
add, remove and override blocks in our testbench and build
different environments without rewriting the whole test.
To illustrate the advantage of this feature, let’s imagine a situation
where we are testing a another DUT that uses SPI for
communication.
If, by any chance, we want to test a similar DUT but with I2C
instead, we would just need to add a monitor and a driver for I2C
and override the existing SPI blocks, the sequencer and the
scoreboard could reused just fine.
UVM Classes

• .It’s very easy to replace components without having


to modify the entire testbench, but it’s also due to the
concept of classes and objects from SystemVerilog.
• In UVM, all the mentioned blocks are represented as
objects that are derived from the already existent
classes.
UVM Phases

• All these classes have simulation phases.


• Phases are ordered steps of execution implemented as
methods.
• When we derive a new class, the simulation of our testbench
will go through these different steps in order to construct,
configure and connect the testbench component hierarchy
• The build phase is used to construct components of the
hierarchy. For example, the build phase of the agent class will
construct the classes for the monitor, for the sequencer and for
the driver.
• The connect is used to connect the different sub components of
a class. Using the same example, the connect phase of the
agent would connect the driver to the sequencer and it would
connect the monitor to an external port.
• The run phase is the main phase of the execution, this is where
the actual code of a simulation will execute.
• And at last, the report phase is the phase used to display the
results of the simulation.
• There are many more phases but none of them are mandatory.
If we don’t need to have one in a particular class, we can just
omit it and UVM will ignore it.
UVM Macros

• Another important aspect of UVM are the macros.


• These macros implement some useful methods in classes and
in variables. they are optional, but recommended.
• The most common ones are:
• `uvm_component_utils – This macro registers the new class
type. It’s usually used when deriving new classes like a new
agent, driver, monitor and so on.
• `uvm_field_int – This macro registers a variable in the UVM
factory and implements some functions like copy(), compare()
and print().
• `uvm_info – This a very useful macro to print messages from
the UVM environment during simulation time.
Typical UVM class
Top Block

• In a normal project, the development of the DUT is done


separately from the development of the testbench, so there are
two components that connects both of them:
• The top block of the testbench
• A virtual interface
• The top block will create instances of the DUT and of the
testbench and the virtual interface will act as a bridge between
them.
• The interface is a module that holds all the signals of the DUT.
• The monitor, the driver and the DUT are all going to be
connected to this module.
• After we have an interface, we will need the top block.
• This block will be a normal SystemVerilog module and it will be
responsible for:
• Connecting the DUT to the test class, using the interface
defined before.
• Generating the clock for the DUT.
• Registering the interface in the UVM factory. This is necessary
in order to pass this interface to all other classes that will be
instantiated in the testbench. It will be registered in the UVM
factory by using the uvm_resource_db method and every block
that will use the same interface, will need to get it by calling the
same method. It might start to look complex, but for now we
won’t need to worry about it too much.
• Running the test.
• The lines 2 and 3 include the DUT and the interface into the top
block, the line 5 imports the UVM library, lines 11 to 16 connect
the interface signals to the DUT.
• Line 21 registers the interface in the factory database with the
name simpleadder_if.
• Line 24 runs one of the test classes defined at compilation
runtime. This name is specified in the Makefile.
• Line 34 generates the clock with a period of 10 timeunits. The
timeunit is also defined in the Makefile.
Sequences and sequencers

• The first step in verifying a RTL design is defining what kind of


data should be sent to the DUT.
• While the driver deals with signal activities at the bit level, it
doesn’t make sense to keep this level of abstraction as we move
away from the DUT, so the concept of transaction was created.
• A transaction is a class object, usually extended
from uvm_transaction or uvm_sequence_item classes, which
includes the information needed to model the communication
between two or more components.
• Transactions are the smallest data transfers that can be executed
in a verification model.
• They can include variables, constraints and even methods for
operating on themselves.
• Due to their high abstraction level, they aren’t aware of the
communication protocol between the components, so they can
be reused and extended for different kind of tests if correctly
programmed.
1

• In order to drive a stimulus into the DUT, a driver component


converts transactions into pin wiggles, while a monitor
component performs the reverse operation, converting pin
wiggles into transactions.
• After a basic transaction has been specified, the verification
environment will need to generate a collection of them and get
them ready to be sent to the driver. This is a job for
the sequence.
• Sequences are an ordered collection of transactions, they
shape transactions to our needs and generate as many as we
want.
• This means if we want to test just a specific set of addresses in
a master-slave communication topology, we could restrict the
randomization to that set of values instead of wasting
simulation time in invalid values.
• Sequences are extended from uvm_sequence and their main
job is generating multiple transactions.
• After generating those transactions, there is another class that
takes them to the driver: the sequencer.
• The code for the sequencer is usually very simple and in simple
environments, the default class from UVM is enough to cover
most of the cases.
UVM utility & field macros

• UVM uses the concept of factory where all the objects are
registered with it so that it can return an object of the
requested type when required.
• The utility macros help to register each object with the factory.
• UVM also introduces a bunch of automation mechanisms for
implementing print (/uvm/uvm-object-print) , copy (/uvm/uvm-
object-copy-clone) , and compare (/uvm/uvmobject-compare)
objects and are defined using the field macros.
Utility Macros

• The utils macro is used primarily to register an object or


component with the factory and is required for it to function
correctly.
• It is required to be used inside every user-defined class that is
derived from uvm_object which includes all types of sequence
items and components.
Object Utility
• All classes derived directly from uvm_object or
uvm_transaction require them to be registered using
`uvm_object_utils macro.
• Note that it is mandatory for the new function to be explicitly
defined for every class, and takes the name of the class
instance as an argument.
Component Utility

• All classes derived directly or indirectly from uvm_component


require them to be registered with the factory using
`uvm_component_utils macro.
• Note that it is mandatory for the new function to be explicitly
defined for every class derived directly or indirectly from
uvm_component and takes the name of the class instance and
a handle to the parent class where this object is instantiated.
Creation of class object

• It is recommended that all class objects are created by


calling the type_id::create() method which is already
defined using the macro `m_uvm_object_create_func .
• This makes any child class object to be created and
returned using factory mechanism and promotes
testbench flexibility and reusability.
Field Macros

• `uvm_field_* macros that were used between *_begin


and *_end utility macros are basically called field
macros since they operate on class properties and
provide automatic implementations of core methods
like copy, compare and print.
• This helps the user save some time from
implementing custom do_copy , do_compare and
do_print functions for each and every class.
UVM_Sequence_item

• The sequence-item is written by extending the


uvm_sequence_item, uvm_sequence_item inherits from the
uvm_object via the uvm_transaction class. therefore
uvm_sequence_item is of an object type.
• uvm_object concepts required to write
uvm_sequence_item,
• The uvm_object has a number of virtual methods that
are used to implement common data object functions
(copy, clone, compare, print, transaction, and
recording)
• these should be implemented to make the
sequence_item more general purpose. uvm_Object
has macros defined in it, mainly Utility Macros and
Field Macros.
UVM Utility Macros

• The utility macros provide implementations of the create


method (needed for cloning) and the get_type_name method
(needed for debugging), etc.

• objects with no field macros,

• objects with field macros,


UVM Field Macros

• The `uvm_field_* macros are invoked inside of the


`uvm_*_utils_begin and `uvm_*_utils_end, for the
implementations of the methods: copy, compare, pack, unpack,
record, print, and etc.
• Each `uvm_field_* macro is named to correspond to a
particular data type: integrals, strings, objects, queues, etc.,
and each has at least two arguments: FIELD and FLAG.
UVM-Flag

FLAG Description

UVM_ALL_ON Set all operations on (default)


UVM_DEFAULT Use the default flag settings
UVM_NOCOPY Do not copy this field
UVM_NOCOMPARE Do not compare this field
UVM_NOPRINT Do not print this field

UVM_NODEFPRINT Do not print the field if it is the same as its

UVM_NOPACK Do not pack or unpack this field


Treat as a physical field. Use physical setting in
UVM_PHYSICAL
policy class for this field

Treat as an abstract field. Use the abstract setting


UVM_ABSTRACT
in the policy class for this field

Do not allow the setting of this field from the


UVM_READONLY
set_*_local methods
A radix for printing and recording can be specified by OR’ing one of the following
constants in the FLAG argument

UVM_BIN Print/record the field in binary (base-2)

UVM_DEC Print/record the field in decimal (base-10)

Print/record the field in unsigned decimal


UVM_UNSIGNED
(base-10)

UVM_OCT Print/record the field in octal (base-8).

Print/record the field in hexadecimal (base-


UVM_HEX
16)

UVM_STRING Print/record the field in string format

UVM_TIME Print/record the field in time format


Sequence item:

• The sequence-item consist of data fields required for


generating the stimulus.
• In order to generate the stimulus, the sequence items are
randomized in sequences.
• Therefore data properties in sequence items should generally
be declared as rand and can have constraints defined.

Data fields represent the following types of information,

• Control Information  – a type of transfer, transfer size, etc


• Payload Information  –  data content of the transfer
• Configuration Information – mode of operation, error behavior, etc
• Analysis Information – fields used to capture information from DUT, ex:
read data, response, etc
Sequence item example:
UVM Sequence item Methods

create():
• The create method allocates a new object of the same type as
this object and returns it via a base uvm_object handle.

print():
• The print method deep-prints this object’s properties in a format
and manner governed by the given printer argument;
How to write uvm sequence

• A sequence generates a series of sequence_item’s and sends it


to the driver via sequencer, Sequence is written by extending
the uvm_sequence.
• A uvm_sequence is derived from an uvm_sequence_item
• a sequence is parameterized with the type of
sequence_item, this defines the type of the item sequence
that will send/receive to/from the driver.
Sequence Execution

Most important properties of a sequence are,


• body method
• m_sequencer handle

body Method:
• body method defines, what the sequence does.
m_sequencer Handle:
• The m_sequencer handle contains the reference to the
sequencer on which the sequence is running.
• The sequence will get executed upon calling the start of the
sequence from the test

sequence_name.start(sequencer_name);
sequencer_name specifies on which sequencer sequence has to
run.
• There are Methods, macros and pre-defined callbacks
associated with uvm_sequence.
• Users can define the methods(task or function) to pre-defined
callbacks.
• these methods will get executed automatically upon calling the
start of the sequence.
• These methods should not be called directly by the user.
Starting The Sequence:
Communication between the Sequence and driver
involves below steps,
1.create_item() / create req.
2.wait_for_grant().
3.randomize the req.
4.send the req.
5.wait for item done.
6.get response.
Method Call Description
Create and initialize* a sequence_item or
create_item() sequence
req = **_seq_item::type_id::create(“req”); *initialize – initialized to communicate with the
specified sequencer
This method call is
blocking, Execution will be blocked until the
method returns.
1.This method issues a request to the current
wait_for_grant()
sequencer
2.The sequencer grants on getting
get_next_item() request
from driver
This method is to randomize the
req.randomize()
sequence_item
Send the request item to the sequencer,
send_request(req,re-randomize) which will forward it to the driver.
re-randomize = 0 or If the re-randomize the bit is set, the item will
re-randomize = 1; be randomized before being sent to the
driver.
This call is optional.
wait_for_item_done() This task will block until the driver calls
item_done or put.
Returns the request item currently being
executed by the sequencer.
get_current_item()
If the sequencer is not currently executing an
item, this method will return null.
get_response(rsp) receives the response from driver.
• The sequence englobes a group of transactions and the
sequencer takes a transaction from the sequence and takes it
to the driver.
• To test our DUT we are going to define a simple transaction,
extended from uvm_sequence_item.
• It will include the following variables:
 rand bit[1:0] ina
 rand bit[1:0] inb
 bit[2:0] out

• The variables ina and inb are going to be random values to be driven to the


inputs of the DUT and the variable out is going to store the result.
• To demonstrate the reuse capabilities of UVM, let’s imagine a
situation where we would want to test a similar adder with a
third input, a port named inc.
• Instead of rewriting a different transaction to include a variable
for this port, it would be easier just to extend the previous class
to support the new input.
Sequence

Now that we have a transaction, the next step is to create a


sequence.
• An explanation of the code will follow:
• Line 8 starts the task body(), which is the main task of a
sequence
• Line 11 starts a cycle in order to generate 15 transactions
• Line 12 initializes a blank transaction
• Line 14 is a call that blocks until the driver accesses the
transaction being created
• Line 15 triggers the rand keyword of the transaction and
randomizes the variables of the transaction to be sent to the
driver
• Line 16 is another blocking call which blocks until the driver has
completed the operation for the current transaction
Sequencer

• The only thing missing is the sequencer. The sequence will be


extended from the class uvm_sequencer and it will be
responsible for sending the sequences to the driver.
• The sequencer gets extended from uvm_sequencer. 

• The code for the sequencer is very simple, this line will tell UVM to
create a basic sequencer with the default API because we don’t
need to add anything else.
• You might have noticed two things missing:
• How does the sequence connects to the sequencer?
• How does the sequencer connects to the driver
• The connection between the sequence and the
sequencer is made by the test block, we will come to
this later on chapter 10, and the connection between
the sequencer and the driver will be explained on 
chapter 7.
Driver

• The driver is a block whose role is to interact with the DUT.


• The driver pulls transactions from the sequencer and sends
them repetitively to the signal-level interface.
• This interaction will be observed and evaluated by another
block, the monitor, and as a result, the driver’s functionality
should only be limited to send the necessary data to the DUT.
• In order to interact with our adder, the driver will execute the
following operations: control the en_i signal, send the
transactions pulled from the sequencer to the DUT inputs and
wait for the adder to finish the operation.
So, we are going to follow these steps:
• Derive the driver class from the uvm_driver base class
• Connect the driver to the signal interface
• Get the item data from the sequencer, drive it to the interface
and wait for the DUT execution
• Add UVM macros
• Line 1 derives a class named simpleadder_driver from the
UVM class uvm_driver. The #(simpleadder_transaction) is a
SystemVerilog parameter and it represents the data type that it
will be retrieved from the sequencer.
• Line 2 refers to the UVM utilities macro explained on chapter 2.
• Lines 7 to 9 are the class constructor.
• Line 11 starts the build phase of the class, this phase is
executed before the run phase.
• Line 13 gets the interface from the factory database. This is the
same interface we instantiated earlier in the top block.
• Line 16 is the run phase, where the code of the driver will be
executed.
• Now that the driver class was explained, you might be
wondering: “What exactly should I write in the run phase?”
• Consulting the state machine from the chapter 1, we can see
that the DUT waits for the signal en_i to be triggered before
listening to the ina and inb inputs, so we need to emulate the
states 0 and 1.
• Although we don’t intend to sample  the output of the DUT with
the driver, we still need to respect it, which means, before we
send another sequence, we need to wait for the DUT to output
the result.
To sum up, in the run phase the following actions must be taken
into account:
• Get a sequence item
• Control the en_i signal
• Drive the sequence item to the bus
• Wait a few cycles for a possible DUT response and tell the
sequencer to send the next sequence item
Creating the driver as a normal testbench
• The ports of the DUT are acessed through the virtual interface
with vif.<signal> as can be seen in lines 4 to 6.
• Lines 12 and 50 use a special variable from UVM,
the seq_item_port to communicate with the sequencer.
• The driver calls the method get_next_item() to get a new
transaction and once the operation is finished with the current
transaction, it calls the method item_done().
• If the driver calls get_next_item() but the sequencer doesn’t
have any transactions left to transmit, the current task returns.
• This variable is actually a UVM port and it connects to the
export from the sequencer named seq_item_export.
UVM Config db

• The configuration database provides access to a centralized


database, where type specific information can be stored and
received.
• config_db can contain scalar objects, class handles, queues,
lists, or even virtual interfaces.
• The database has both a name table and a type table and
each resource is entered into both.
• Resources are stored in a database so that each resource can
be retrieved by name or by type, and the database is globally
accessible.
uvm config db get and set

• uvm_config_db::set and uvm_config_db::get methods are used


to store and retrieve the information from the database
respectively.

• T  is the type of element being configured. Type can be scalar objects, class
handles, queues, lists, or even virtual interfaces)
• cntxt is the hierarchical starting point of where the database entry is
accessible.
• inst_name is a hierarchical path that limits the accessibility of the database
entry.
example:
• top.env.agent.monitor
top.*               – all of the scopes whose top-level
component is top.
top.env.*.monitor   – all of the scopes in env that end
in the monitor;
• field_name is the label used as a lookup for the
database entry
• value is the value to be stored in the database
uvm_config_db set example
uvm config db get method

• value is the variable to which the value is to be retrieved from the database

• The method returns 1 if it is successful and 0 if there is no such resource of this type
in the database.

UVM_CONFIG_DB GET EXAMPLE

• .Using the get method to get a virtual interface handle from a database and assigns it to mem_vif.
• If the get method fails, the fatal message will be displayed.
UVM Phases top down

• UVM Phases are a synchronizing mechanism for the


environment
• Phases are represented by callback methods, A set of
predefined phases and corresponding callbacks are provided in
uvm_component. The Method can be either a function or task.
• Any class deriving from uvm_component may implement any or
all of these callbacks, which are executed in a particular order
The UVM Phases are,
• build
• connect
• end of elaboration
• start of simulation
• run
• extract
• check
• report

• the run phase is implemented as a task and remaining all are function.
• Phases can be grouped into 3 categories,
1. Build Phases

• build phase, connect phase and end_of_elobaration phase


belongs to this category.
• Phases in this categorize are executed at the start of the UVM
testbench simulation, where the testbench components are
constructed, configured and testbench components are
connected.
• All the build phase methods are functions and therefore
execute in zero simulation time.
2. Run-time Phases
• start of simulation and run phase belongs to run-time phases,
the run phase will get executed from the start of simulation to
till the end of the simulation.
• the run phase is time-consuming, where the testcase is running
3. Clean up Phases
• extract, check, report and final belong to this category.
where the results of the testcase are collected and reported.
• example: the number of error’s during the simulation is
reported.
Phase Description Execution Order

Used to construct the


build top-down
testbenchcomponents

Used to connect TLM ports of


connect bottom-up
components

Used to make any final adjustments to


the structure, configuration or
end_of_elaboration bottom-up
connectivity of the testbench before
simulation starts

used for printing testbench topology or


start_of_simulation bottom-up
configuration information

Used for stimulus generation, driving,


run parallel
monitoring, and checking

Used to retrieve and process


extract information from scoreboards and
functional coverage monitors

Used to check that the DUT behaved


correctly and to identify any errors that
check
may have occurred during the
execution of the test bench

Used to display the results of the


report
simulation or to write the results to file

Used to complete any other


final outstanding actions that the test bench final
has not already completed
Phase Description
the pre_reset phase starts at the same time as the run
phase. Its purpose is to take care of any activity that
pre_reset
should occur before the reset, such as waiting for a power-
good signal to go active
The reset phase is reserved for DUT or interface specific
reset behavior. For example, this phase would be used to
reset
generate a reset and to put an interface into its default
state
Intended for any activity required immediately the following
post_reset
reset
pre_configure phase is intended for anything that is
pre_configure required to prepare for the DUT’s configuration process
after reset is completed
configure phase is used to program the DUT and any
configure memories in the testbench so that it is ready for the start of
the test case
post_configure phase is used to wait for the effects of
configuration to propagate through the DUT, or for it to
post_configure
reach a state where it is ready to start the main test
stimulus
pre_main phase is used to ensure that all required
pre_main
components are ready to start generating stimulus
This is where the stimulus specified by the test case is
main generated and applied to the DUT. It completes when
either all stimulus is exhausted or a timeout occurs
This phase is used to take care of any finalization of the
post_main
main phase
This phase is a buffer for any DUT stimulus that needs to
UVM Driver

• A driver is written by extending the uvm_driver


• uvm_driver is inherited from uvm_component,
Methods and TLM port (seq_item_port) are defined for
communication between sequencer and driver
• The uvm_driver is a parameterized class and it is
parameterized with the type of the request
sequence_item and the type of the response
sequence_item
UVM_Driver Methods

get_next_item
• This method blocks until a REQ sequence_item is available in
the sequencer.
try_next_item
• This is a non-blocking variant of the get_next_item() method. It
will return a null pointer if there is no REQ sequence_item
available in the sequencer.
item_done
• The non-blocking item_done() method completes the driver-
sequencer handshake and it should be called after a
get_next_item() or a successful try_next_item() call.
put
• The put() method is non-blocking and is used to place an RSP
sequence_item in the sequencer.
 Writing Driver :

1. A driver is written by extending the UVM_DRIVER

2. Declare the virtual interface,

3. Get the interface handle using get config_db,


4. Will place the get config_db in the build_phase,

5. Add driving logic. get the seq_item and drive to DUT signals,
complete drive code
1. The monitor is written by extending the UVM_MONITOR,

2. Declare virtual interface,


3. Connect interface to Virtual interface by using get method,

4. Declare analysis port,

5. Declare seq_item handle, Used as a place holder for sampled signal activity,
UVM Monitor

• The user-defined monitor is extended from uvm_monitor,


uvm_monitor is inherited by uvm_component
• A monitor is a passive entity that samples the DUT signals
through the virtual interface and converts the signal level
activity to the transaction level
• Monitor samples DUT signals but does not drive them

• The monitor should have an analysis port (TLM port) and a


virtual interface handle that points to DUT signals.
6. Add Sampling logic in run_phase,
7. After sampling, by using the write method send the
sampled transaction packet to the scoreboard,
 Complete monitor code,
UVM Agent

• a user-defined agent is extended from uvm_agent, uvm_agent


is inherited by uvm_component
• An agent typically contains a driver, a sequencer, and a monitor
• Agents can be configured either active or passive

Active agent

• Active agents generate stimulus and drive to DUT


• An active agent shall consists of all the three components driver,
sequencer, and monitor
Passive agent

• Passive agents sample DUT signals but do not drive them


A passive agent consists of only the monitor

• An agent can be configured as ACTIVE/PASSIVE by using a set config method, the


default agent will be ACTIVE. the set config can be done in the env or test.
get_is_active() Method

get_is_active() Returns UVM_ACTIVE if the agent is acting as an active agent and


UVM_PASSIVE if the agent acting as a passive agent.
Writing UVM Agent

1. An agent is written by extending UVM_agent,

2. Declare driver, sequencer and monitor instance,


3. Depending on Agent type, create agent components in the build phase, driver and sequencer will be created
only for the active agent.

4. Connect the driver seq_item_port to sequencer seq_item_export for communication between driver and
sequencer in the connect phase.
 Complete Agent code,
UVM Scoreboard

The user-defined scoreboard is extended from uvm_scoreboard,


uvm_scoreboard is inherited by uvm_component.

Writing Scoreboard
The scoreboard is written by extending the UVM_SCOREBOARD.
• the scoreboard will check the correctness of the DUT by
comparing the DUT output with the expected values
• the scoreboard will receive the transactions from the Monitors
implemented inside agents
• Monitor and scoreboard will communicate via TLM ports and
exports

Scoreboard shall compare the DUT output values with,


• The golden reference values
• The values Generated from the reference model
Declare and Create TLM Analysis port, ( to receive transaction pkt from Monitor).

analysis export of Scoreboard is connected to Monitor port


uvm scoreboard write function

write method of the scoreboard will receive the transaction packet from the
monitor, on calling write method from the monitor.
UVM scoreboard code
UVM Environment

• The user-defined environment is derived from uvm_env,


uvm_env is inherited from uvm_component.
• The environment is the container class, It contains one or more
agents, as well as other components such as the scoreboard,
top-level monitor, and checker.
Writing Environment

1. The environment is written by extending UVM_ENV,

2. Declare the agent,

3. Create an agent,
Complete environment code
UVM Test

• The user-defined test is derived from uvm_test, uvm_test is


inherited from uvm_component.
• The test defines the test scenario for the testbench
• test class contains the environment, configuration properties,
class overrides etc
• A sequence/sequences are created and started in the test

The UVM testbench is activated when the run_test() method is called, the global
run_test() task should be specified inside an initial block.
Writing Test

1. The test is written by extending the UVM_TEST,

2. Declare env and sequence,


• There can be many user-defined test cases.Among multiple test cases, a
particular test case can be selected and execute on two methods,
1. by specifying the test name as an argument to run_test();
example: run_test("mem_model_test");
2. by providing the UVM_TESTNAME command line argument
example: <SIMULATION_COMMANDS>
+UVM_TESTNAME=mem_model_test
3. Create env and sequence,

4. Start the sequence,


Complete Test code,
Monitor

• The monitor is a self-contained model that observes the


communication of the DUT with the testbench.
• At most, it should observe the outputs of the design and, in
case of not respecting the protocol’s rules, the monitor must
return an error.
• The monitor is a passive component, it doesn’t drive any
signals into the DUT, its purpose is to extract signal information
and translate it into meaningful information to be evaluated by
other components.
• A verification environment isn’t limited to just one monitor, it
can have multiple of them.
The monitors should cover:
• The outputs of the DUT for protocol adherence
• The inputs of the DUT for functional coverage analysis
• The approach we are going to follow for this
verification plan is: sample both inputs, make a
prediction of the expected result and compare it with
the result of the DUT.
• Consequently, we are going to create two different
monitors:
• The first monitor, monitor_before, will look solely for
the output of the device and it will pass the result to
the scoreboard.
•  The second monitor, monitor_after, will get both
inputs and make a prediction of the expected result.
The scoreboard will get this predicted result as well
and make a comparison between the two values.
Transactions Overview

• Transaction is an abstraction of information transfer.


• If you have a problem with the term transaction, try to
replace it with message.
• In languages supporting OOP transaction is typically
executed by calling method of some design object. In
other languages it can be a procedure/function call.
• In UVM a transaction is a class object
(uvm_transaction), that includes whatever information
is needed to model the communication between two
components.
Basic TLM Communication

• The most basic transaction-level operation allows one


component to put a transaction to another
• The producer generates transactions and sends them out
through its port (green square).

• The actual implementation of the transaction is supplied by the


consumer.
• The transaction implementation (in consumer) connects with
requester via export (red circle).
Put vs. Get

• If directions of data and control flow agree, producer puts transaction into
consumer:

• If directions of data and control flow disagree, consumer gets transaction from the
producer:

No matter if it is put or get situation, the process with export (the executor) is
responsible for implementation of the transaction; requester is using its port
to call services of the executor.
TLM Fifo [uvm_tlm_fifo]

• Assume data rate of the sender is much faster than the rate at which the
receiver can get packets.
• A FIFO element is required in between to store packets so that it allows
both the sender and the receiver to independently operate.
• TLM FIFO is used to synchronize data flow between producer and
consumer.
• Depth of the FIFO is typically calculated based on the rate of data transfer.
A TLM FIFO is placed in between testbench components that transfer data
objects at different rates.
TLM Analysis Port
Agent

• We have both monitors, the sequencer and the driver, so the


next step is to connect them up.
• This is a job for the agent.
• An agent doesn’t require a run phase, there is no simulation
code to be executed in this block but there will be a connect
phase, besides of the build phase.

• We will construct the monitors, the sequencer and the driver in


the build phase.
• We will also need to create two analysis ports, these ports will
act as proxies for the monitors to be connect to an external
scoreboard through the agent’s ports.
UVM_VERBOSITY definitions

• There are predefined UVM verbosity settings built into UVM (and
OVM).
• The settings actually have integer values that increment by 100 as
shown below.
• By default, when running a UVM simulation, all messages with
verbosity settings of UVM_MEDIUM or lower (UVM_MEDIUM,
UVM_LOW and UVM_NONE) will print.
Scoreboard

• The scoreboard is a crucial element in a self-checking


environment, it verifies the proper operation of a design at a
functional level.
• This component is the most difficult one to write, it varies from
project to project and from designer to designer.
Test

• At last, we need to create one more block: the test.


• This block will derive from the uvm_test class and it will have
two purposes:
• Create the env block
• Connect the sequencer to the sequence

• You might be wondering why are we connecting the sequencer


and the sequence in this block, instead of the agent block or
the sequence block.

• The reason is very simple: by specifying in the test class which


sequence will be going to be generated in the sequencer, we
can easily change the kind of data is transmitted to the DUT
without messing with the agent’s or sequence’s code.
• In the typical UVM code we raise objections in the
run_phase of the uvm_test then the test will finish
after the body() of the sequence is executed, but if
we do not raise any objection then the test will be
finishes without waiting for the sequence body() to
execute.

• Generally when we do this it is meant for start the


sequencer and for handshaking method between
driver and sequence.

• phase.raise_objection(this);
• seq.start(sa_seqr);
• phase.drop_objection(this);

• where seq is an instantiation of sequence.

You might also like