UVM Register Defines

Register defines

UVM register library has the defines declared in it. these are being used in the RAL model base classes, user can override these defines.

uvm_reg_defines are,

  • `UVM_REG_ADDR_WIDTH
  • `UVM_REG_DATA_WIDTH
  • `UVM_REG_BYTENABLE_WIDTH
  • `UVM_REG_CVR_WIDTH

UVM_REG_ADDR_WIDTH

  • Maximum address width in bits
    Default value is 64
  • Used to define the uvm_reg_addr_t type

UVM_REG_DATA_WIDTH

  • Maximum data width in bits
    Default value is 64
  • Used to define the uvm_reg_data_t type

UVM_REG_BYTENABLE_WIDTH

  • Maximum number of byte enable bits
  • Default value is one per byte in `UVM_REG_DATA_WIDTH
  • Used to define the
    uvm_reg_byte_en_t type

UVM_REG_CVR_WIDTH

  • Maximum number of bits in a uvm_reg_cvr_t coverage model set
  • Default value is 32

❮ Previous Next ❯

Packaging and Integrating Register Model

Packaging and Integrating a Register Model

Packaging a Register Model

The following practices are recommended, but not required.

  • Block types, and all the register, register file, and memory types they require, should be located in separate packages
  • Register, register file, and memory types shared by more than one block type should be located in separate packages
  • A header file, with all the required import statements to use the register model, should be generated
  • A lengthy build() method may be split into several, shorter sub-methods. The sub-methods shall be declared local and called by the build() method

Integrating a Register Model

  • A register model must be integrated with the bus agent
  • The integration with the bus agent must only be done on root blocks
  • Root blocks model the entire DUT and they are the only ones who have access to and knowledge of the externally-visible address maps.i.e in the environment of the testbench
class tb_env extends uvm_env;
  reg_model  regmodel;
  subblk_env subblk;

  virtual function void build_phase(uvm_phase phase);
    if (regmodel == null) begin
      regmodel = reg_model::type_id::create(“regmodel”, this);
      regmodel.build();
      regmodel.lock_model();
    end
    subblk = subblk_env::type_id::create(“subblk”, this);
    subblk.regmodel = regmodel.subblk;
  endfunction
endclass

❮ Previous Next ❯

Constructing Register Model

Constructing Register Model

This section describes how to construct a UVM register model for register and memory access.

Register Field

Register fields are declared with uvm_reg_field class type.

uvm_reg_field reg_name;
  • Register fields are declared in register class
  • The field name must be unique within the scope of its declaration
  • The access policy of a field is specified using the uvm_reg_field::configure() method
  • Configure method has to be called from the build() method of the register that instantiates it (refer to register example)

Pre-defined Field Access Policies

Access Policy Description Effect of a Write on Current Field Value Effect of a Read on Current Field Value Read back Value
RO Read Only No effet No effet Current Value
RW Read, Write Changed to the written value No effet Current Value
RC Read Clears All No effet Sets all bits to 0’s Current Value
WRC Write, Read Clears All Changed to the written value Sets all bits to 0’s Current Value
WC Write Clears All Sets all bits to 0’s No effet Current Value
W1C Write 1 to Clear If the bit in the written value is a 1, the corresponding bit in the field is set to 0. Otherwise, the field bit is not affected No effet Current Value
W0C Write 0 to Clear If the bit in the written value is a 0, the corresponding bit in the field is set to 0. Otherwise, the field bit is not affected No effet Current Value

Reserved Fields

  • There is no pre-defined field access policy for reserved fields
  • Reserved fields should be left unmodelled, where they will be assumed to be RO fields filled with 0’s

Register

The register is constructed by writing a class extended from the uvm_reg class. There must be one class per unique register type

class my_reg extends uvm_reg;
  rand uvm_reg_field Field_0;
  rand uvm_reg_field Field_1;
endclass
  • The name of the register type class must be unique within the scope of its declaration
  • The uvm_reg_field::configure() method shall be called from the register type build method
class my_reg extends uvm_reg;
  virtual function build();
    this.Field_0 = my_reg::type_id::create(
      .name(“Field_0”),
      .parent(null),
      .contxt(get_full_name()));
    this.Field_0.configure(this, ...);
  endfunction
endclass

Register File

A register file type is constructed by writing a class extended from the uvm_reg_file class

class my_reg_file extends uvm_reg_file;
  `uvm_object_utils(my_reg_file)
endclass
  • The name of the register file type class must be unique within the scope of its declaration
  • Register files can contain other register files.
  • The build() method shall call the configure() method for all register and register file class properties
  • specifying get_block() for the parent block and this for the parent register file
class reg_file extends uvm_reg_file;

virtual function build();
  uvm_reg_block blk = get_block();
  this.rf = reg_file_0::type_id::create(
             .name($psprintf(“%s.rf1”, get_name())),
             .parent(null),
             .contxt(blk.get_full_name()));
  this.rf.configure(get_block(), this, ...);
  this.rf.build();
  this.rf.add_hdl_path();
endfunction

endclass

map() Method

  • A virtual map() function, with uvm_reg_map and address offset arguments map() method shall call uvm_reg_map::add_reg() for all register class properties, adding the value of the address offset argument to the offset of the register in the register file map() method shall call the map() method of all register file class properties, adding the value of the address offset argument to the offset of the register file base offset
  • The map() method may call the add_hdl_path() method for all register or register file class properties
virtual function map(uvm_reg_map mp, uvm_reg_addr_t offset);
  mp.add_reg(this.reg_0, base_addr + 'h0);
  mp.add_reg(this.reg_1, base_addr + 'h4;
  this.rf.map(mp, base_addr + 'h100);
endfunction

set_offset() Method

  • A virtual set_offset() function, with a uvm_reg_map and address offset arguments, may also be implemented
  • The set_offset() method shall call the set_offset() method for all register and register file class properties
virtual function set_offset(uvm_reg_map mp, uvm_reg_addr_t offset);
  this.reg_0.set_offset(mp, base_addr + 'h0);
  this.reg_1.set_offset(mp, base_addr + 'h4);
  this.rf.set_offset(mp, base_addr + 'h100);
endfunction

Memory Types

  • A memory type is constructed using a class extended from the uvm_mem class
  • The name of the memory type class must be unique within the scope of its declaration
class my_mem extends uvm_mem;
  `uvm_object_utils(my_mem)
endclass

Register Block

  • A block is constructed by writing a class extended from the uvm_reg_block class
  • The name of the block type class must be unique within the scope of its declaration
class my_blk extends uvm_reg_block;
  `uvm_object_utils(my_blk)
endclass

The block type must contain a class property for each,

  • named address map
  • register
  • register file
  • memory
  • sub-block
  • These shall have the rand attribute
  • The build() method shall instantiate all named address maps by calling the uvm_reg_block::create_map() method

❮ Previous Next ❯

UVM RAL Overview

UVM Register Model Overview

The register model is composed of a hierarchy of blocks that map to the design hierarchy, which means the RAL model consists of equivalent which will refer to the design register fields, registers, and memory.

Blocks can contain,

  • registers
  • register files
  • memories
  • other blocks

UVM RAL library provides the base class of each and each class has the default builtin methods in it.

Refer to UVM RAL Base Classes for a detailed description of UVM RAL Base Classes and its Methods.

Register classes cant be used as it is, they must be specialized via extensions to provide an abstract view that corresponds to the design registers and memories.

UVM RAL Building blocks
UVM RAL Building blocks

Above block diagram shows that,

  • uvm_reg shall consist of one or more uvm_reg_field
  • uvm_reg_file shall consist of one or more uvm_reg
  • uvm_reg_block shall consist of one or more uvm_reg_file or uvm_mem

Below block diagram shows the mapping of register model components to the environmental components.

UVM RAL Structure
UVM RAL Structure

Due to a large number of registers in design, this specialization shall be done by a register model generator.

register model generator

Register model generators are outside the scope of the UVM library.

A register model can be written or it can be created using a register generator application. Writing or Generating the register model is based on a design register specification.

Writing a register model is easy, but complex designs will be having hundreds or thousands of registers. in that case, writing the register model is tedious. The easiest way to construct a register model is by using a register generation application or automation tool.

Automation tools will generate the register model by taking register specification as input, this includes reg name, width, register fields, access permissions, etc.

There are paid and free register generators available. some of them are RGM – Register and Memory Package by Cadence, ralgen by Synopsys, Semifore’s RDL, Duolog’s graphical Bitwise, Agnisys’ IDesignSpec, Mentor Graphics’ Certes Testbench Studio, and  Magillem MRV (Magillem Register View).
❮ Previous Next ❯

Why UVM RAL required

What is UVM RAL model why it is required?

What is the RAL Concept, What are the Benefits of it?

The UVM Register Layer provides a standard base class libraries that enable users to implement the object-oriented model to access the DUT registers and memories. UVM Register Layer is also referred to as UVM Register Abstraction Layer (UVM RAL).

For register access, can’t we proceed without RAL?

Yes, we can. But as mentioned above, RAL provides a set of base classes and methods with a set of rules which easies the effort required for register access.

Advantages of UVM RAL

The advantages of UVM RAL Model are,

  • Provides high-level abstraction for reading and writing DUT registers. i.e, registers can be accessed with its names
  • UVM provides a register test sequence library containing predefined test cases these can be used to verify the registers and memories
  • register layer classes support front-door and back-door access
  • Design registers can be accessed independently of the physical bus interface. i.e by calling read/write methods
  • The register model can be accessed from multiple concurrent threads. it internally serializes the access to the register.
  • Reusability, RAL packages can be directly reused in other environments
  • Uniformity, Defines the set of rules or methodology on register access, which can be followed across the industry
  • Automated RAL model generations, Tools or open-source scripts are available for RAL Model generation

Below block diagram shows using RAL in the verification testbench.

testbench with UVM RAL
testbench with UVM RAL

The below diagram shows the detailed components and connection of RAL with testbench.

UVM RAL TestBench
UVM RAL TestBench

For Detailed description on RAL Concepts refer to UVM RAL TUTORIAL.

UVM Sequence

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.

UVM Sequence
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 base class

 virtual class uvm_sequence #( type REQ = uvm_sequence_item,
                               type RSP = REQ ) extends uvm_sequence_base

example:

class write_sequence extends uvm_sequence #(mem_seq_item);
....
....
endclass

the sequence has handle req and rsp of mem_seq_item.

 

request/req:

A transaction that provides information to initiate the processing of a particular operation.

response/rsp:

A transaction that provides information about the completion or status of a particular operation.

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.

Below block diagram shows the order in which the methods will get called on calling the start of a sequence.

uvm sequence phases
uvm sequence phases

* mid_do and post_do are functions, All other are tasks

Starting The Sequence:

Logic to generate and send the sequence_item will be written inside the body() method of the sequence.
The handshake between the sequence, sequencer and driver to send the sequence_item is given below.

sequence driver communication
sequence driver communication

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.

* Step 5 and 6 are optional.

seq driver communication without response stage
seq driver communication without response stage
Method Call Description
create_item()
req = **_seq_item::type_id::create(“req”);
Create and initialize* a sequence_item or sequence
*initialize – initialized to communicate with the specified sequencer
wait_for_grant() This method call is
blocking, Execution will be blocked until the method returns.
1.This method issues a request to the current sequencer
2.The sequencer grants on getting get_next_item() request
from driver
req.randomize() This method is to randomize the sequence_item
send_request(req,re-randomize)
re-randomize = 0 or
re-randomize = 1;
Send the request item to the sequencer, which will forward it to the driver.
If the re-randomize the bit is set, the item will be randomized before being sent to the driver.
wait_for_item_done() This call is optional.
This task will block until the driver calls item_done or put.
get_current_item() Returns the request item currently being executed by the sequencer.
If the sequencer is not currently executing an item, this method will return null.
get_response(rsp) receives the response from driver.

Writing UVM Sequence

class mem_sequence extends uvm_sequence#(mem_seq_item);
  
  `uvm_object_utils(mem_sequence)
   
  //Constructor
  function new(string name = "mem_sequence");
    super.new(name);
  endfunction
  
  virtual task body();

    req = mem_seq_item::type_id::create("req");  //create the req (seq item)
    wait_for_grant();                            //wait for grant
    assert(req.randomize());                     //randomize the req                    
    send_request(req);                           //send req to driver
    wait_for_item_done();                        //wait for item done from driver
    get_response(rsp);                           //get response from driver

  endtask
endclass

Note: assert(req.randomize());, will return the assertion error on randomization failure.

UVM Sequence macros

These macros are used to start sequences and sequence items on default sequencer, m_sequencer.

Macro Description
`uvm_do(Item/Seq) This macro takes seq_item or sequence as argument.
On calling `uvm_do() the above-defined 6 steps will be executed.
`uvm_create(Item/Seq) This macro creates the item or sequence.
`uvm_send(Item/Seq) create() and randomize() are skipped, rest all other steps are executed.
`uvm_rand_send(Item/Seq) Only create() is skipped, rest all other steps are executed.
`uvm_do_with(Item/Seq,Constraints) This macro performs above 6 steps along with constraints defined in second argument.
`uvm_rand_send_with(Item/Seq,Constraints) create() is skipped, rest all other steps are executed along with constraints defined in second argument.
`uvm_do_pri(Item/Seq,Priority ) Performs `uvm_do() with priority mentioned.
`uvm_do_pri_with(Item/Seq,Constraints,Priority) Performs `uvm_do() along with constraints defined and priority mentioned.
`uvm_send_pri(Item/Seq,Priority) create() and randomize() are skipped, rest all other steps are executed with priority mentioned.
`uvm_rand_send_pri(Item/Seq,Priority) Only create() is skipped, rest all other steps are executed with priority mentioned.
`uvm_rand_send_pri_with(Item/Seq,Priority, Constraints) create() is skipped, rest all other steps are executed along with constraints defined with priority mentioned.
`uvm_declare_p_sequencer(SEQUENCER) This macro is used to declare a variable p_sequencer whose type is specified by SEQUENCER. by using p_sequencer handle, properties of sequencer can be accessed.

Writing the sequence using Macro’s

`uvm_do()

class mem_sequence extends uvm_sequence#(mem_seq_item);
  
  `uvm_object_utils(mem_sequence)
   
  //Constructor
  function new(string name = "mem_sequence");
    super.new(name);
  endfunction
  
  virtual task body();
    `uvm_do(req)
  endtask
  
endclass

`uvm_create() and `uvm_send()

class mem_sequence extends uvm_sequence#(mem_seq_item);
  
  `uvm_object_utils(mem_sequence)
   
  //Constructor
  function new(string name = "mem_sequence");
    super.new(name);
  endfunction
  
  virtual task body();
    `uvm_create(req)
    assert(req.randomize());
    `uvm_send(req);
  endtask
  
endclass

`uvm_rand_send()

class mem_sequence extends uvm_sequence#(mem_seq_item);
  
  `uvm_object_utils(mem_sequence)
   
  //Constructor
  function new(string name = "mem_sequence");
    super.new(name);
  endfunction
  
  virtual task body();
    `uvm_create(req)
    `uvm_rand_send(req)
  endtask
  
endclass

`uvm_do_with()

class write_sequence extends uvm_sequence#(mem_seq_item);
  
  `uvm_object_utils(write_sequence)
   
  //Constructor
  function new(string name = "write_sequence");
    super.new(name);
  endfunction
  
  virtual task body();
    `uvm_do_with(req,{req.wr_en == 1;})
  endtask
  
endclass

`uvm_rand_send_with()

class read_sequence extends uvm_sequence#(mem_seq_item);
  
  `uvm_object_utils(read_sequence)
   
  //Constructor
  function new(string name = "read_sequence");
    super.new(name);
  endfunction
  
  virtual task body();
    `uvm_create(req)
    `uvm_rand_send_with(req,{req.rd_en == 1;})
  endtask
  
endclass

Calling sequence’s inside the sequence

class wr_rd_seq extends uvm_sequence#(mem_seq_item);
  
  write_sequence wr_seq;
  read_sequence  rd_seq;
  
  `uvm_object_utils(wr_rd_seq)
   
  //Constructor
  function new(string name = "wr_rd_seq");
    super.new(name);
  endfunction
  
  virtual task body();
    `uvm_do(wr_seq)
    `uvm_do(rd_seq)
  endtask
  
endclass

difference between m_sequencer and p_sequencer:

m_sequencer,

The m_sequencer handle contains the reference to the sequencer(default sequencer) on which the sequence is running.
This is determined by,

  • the sequencer handle provided in the start method
  • the sequencer used by the parent sequence
  • the sequencer that was set using the set_sequencer method

p_sequencer,

The p_sequencer is a variable, used as a handle to access the sequencer properties.
p_sequencer is defined using the macro `uvm_declare_p_sequencer(SEQUENCER_NAME)
❮ Previous Next ❯

UVM Sequence item

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 sequence item
uvm sequence item

Before moving to uvm_sequence_item will look into 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) and these should be implemented to make the sequence_item more general purpose.also, 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,

`uvm_object_utils(TYPE)

objects with field macros,

`uvm_object_utils_begin(TYPE)
    `uvm_field_*(FIELD,FLAG)
`uvm_object_utils_end

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_field_*(FIELD,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
UVM_PHYSICAL Treat as a physical field. Use physical setting in policy class for this field
UVM_ABSTRACT Treat as an abstract field. Use the abstract setting in the policy class for this field
UVM_READONLY Do not allow the setting of this field from the 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)
UVM_UNSIGNED Print/record the field in unsigned decimal (base-10)
UVM_OCT Print/record the field in octal (base-8).
UVM_HEX Print/record the field in hexadecimal (base-16)
UVM_STRING Print/record the field in string format
UVM_TIME Print/record the field in time format

*detailed description on macros is described in later pages.

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

as analysis information fields will be used for capturing response, except these fields the other fields can be declared as rand and can have constraints associated with it.

Sequence item example:

class mem_seq_item extends uvm_sequence_item;
  //Control Information
  rand bit [3:0] addr;
  rand bit       wr_en;
  rand bit       rd_en;
  
  //Payload Information 
  rand bit [7:0] wdata;
  
  //Analysis Information
       bit [7:0] rdata;
    
  //Utility and Field macros,
  `uvm_object_utils_begin(mem_seq_item)
    `uvm_field_int(addr,UVM_ALL_ON)
    `uvm_field_int(wr_en,UVM_ALL_ON)
    `uvm_field_int(rd_en,UVM_ALL_ON)
    `uvm_field_int(wdata,UVM_ALL_ON)
  `uvm_object_utils_end
  
  //Constructor
  function new(string name = "mem_seq_item");
    super.new(name);
  endfunction
  
  //constaint, to generate any one among write and read
  constraint wr_rd_c { wr_en != rd_en; }; 
  
endclass

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;

Create() and Print() Method

class mem_seq_item extends uvm_sequence_item;
  //Control Information
  rand bit [3:0] addr;
  rand bit       wr_en;
  rand bit       rd_en;
  
  //Payload Information 
  rand bit [7:0] wdata;
  
  //Analysis Information
       bit [7:0] rdata;
  
  //Utility and Field macros,
  `uvm_object_utils_begin(mem_seq_item)
    `uvm_field_int(addr,UVM_ALL_ON)
    `uvm_field_int(wr_en,UVM_ALL_ON)
    `uvm_field_int(rd_en,UVM_ALL_ON)
    `uvm_field_int(wdata,UVM_ALL_ON)
  `uvm_object_utils_end
  
  //Constructor
  function new(string name = "mem_seq_item");
    super.new(name);
  endfunction
  
  //constaint, to generate any one among write and read
  constraint wr_rd_c { wr_en != rd_en; }; 
  
endclass

//-------------------------------------------------------------------------
//Simple TestBench to create and randomize sequence item
//-------------------------------------------------------------------------
module seq_item_tb;
  
  //instance
  mem_seq_item seq_item;
  
  initial begin
    //create method
    seq_item = mem_seq_item::type_id::create(); 
    
    //randomizing the seq_item
    seq_item.randomize();
    
    //printing the seq_item
    seq_item.print();   
  end  
endmodule

Simulator Output:

---------------------------------------
Name Type Size Value
---------------------------------------
mem_seq_item mem_seq_item - @334 
addr integral 4 'h4 
wr_en integral 1 'h1 
rd_en integral 1 'h0 
wdata integral 8 'h88 
---------------------------------------

Click to execute on    eda_png

copy:

The copy makes this object a copy of the specified object.

Copy() Method

class mem_seq_item extends uvm_sequence_item;
  //Control Information
  rand bit [3:0] addr;
  rand bit       wr_en;
  rand bit       rd_en;
  
  //Payload Information 
  rand bit [7:0] wdata;
  
  //Analysis Information
       bit [7:0] rdata;
  
  //Utility and Field macros,
  `uvm_object_utils_begin(mem_seq_item)
    `uvm_field_int(addr,UVM_ALL_ON)
    `uvm_field_int(wr_en,UVM_ALL_ON)
    `uvm_field_int(rd_en,UVM_ALL_ON)
    `uvm_field_int(wdata,UVM_ALL_ON)
  `uvm_object_utils_end
  
  //Constructor
  function new(string name = "mem_seq_item");
    super.new(name);
  endfunction
  
  //constaint, to generate any one among write and read
  constraint wr_rd_c { wr_en != rd_en; }; 
  
endclass

//-------------------------------------------------------------------------
//Simple TestBench to access sequence item
//-------------------------------------------------------------------------
module seq_item_tb;
  
  //instance
  mem_seq_item seq_item_0;
  mem_seq_item seq_item_1;
  
  initial begin
    //create method
    seq_item_0 = mem_seq_item::type_id::create("seq_item_0"); 
    seq_item_1 = mem_seq_item::type_id::create("seq_item_1");
    
    seq_item_0.randomize(); //randomizing the seq_item   
    seq_item_0.print();     //printing the seq_item_0
    
    //copy method
    seq_item_1.copy(seq_item_0); //copy seq_item_0 to seq_item_1
    seq_item_1.print();          //printing the seq_item_1
    
  end  
endmodule

Simulator Output:

-------------------------------------
Name Type Size Value
-------------------------------------
seq_item_0 mem_seq_item - @334 
addr integral 4 'h4 
wr_en integral 1 'h1 
rd_en integral 1 'h0 
wdata integral 8 'h88 
-------------------------------------
-------------------------------------
Name Type Size Value
-------------------------------------
seq_item_1 mem_seq_item - @338 
addr integral 4 'h4 
wr_en integral 1 'h1 
rd_en integral 1 'h0 
wdata integral 8 'h88 
-------------------------------------

Click to execute on    eda_png

clone

The clone method creates and returns an exact copy of this object. clone = create() + copy();

Clone() Method

class mem_seq_item extends uvm_sequence_item;
  //data and control fields
  rand bit [3:0] addr;
  rand bit       wr_en;
  rand bit       rd_en;
  rand bit [7:0] wdata;
       bit [7:0] rdata;
  
  //Utility and Field macros,
  `uvm_object_utils_begin(mem_seq_item)
    `uvm_field_int(addr,UVM_ALL_ON)
    `uvm_field_int(wr_en,UVM_ALL_ON)
    `uvm_field_int(rd_en,UVM_ALL_ON)
    `uvm_field_int(wdata,UVM_ALL_ON)
  `uvm_object_utils_end
  
  //Constructor
  function new(string name = "mem_seq_item");
    super.new(name);
  endfunction
  
  //constaint, to generate any one among write and read
  constraint wr_rd_c { wr_en != rd_en; }; 
  
endclass

//-------------------------------------------------------------------------
//Simple TestBench to access sequence item
//-------------------------------------------------------------------------
module seq_item_tb;
  
  //instance
  mem_seq_item seq_item_0;
  mem_seq_item seq_item_1;
  
  initial begin
    //create method
    seq_item_0 = mem_seq_item::type_id::create("seq_item_0"); 
    
    seq_item_0.randomize(); //randomizing the seq_item   
    seq_item_0.print();     //printing the seq_item_0
    
    //clone method
    $cast(seq_item_1,seq_item_0.clone()); //create seq_item_1 and copy seq_item_0 to seq_item_1
    
    //changing the seq_item_1 values will not reflect on seq_item_0 values.
    seq_item_1.addr  = 8;
    seq_item_1.wdata = 'h56;
    `uvm_info("","Printing seq_item_0", UVM_LOW)
    seq_item_0.print();          //printing the seq_item_0
    `uvm_info("","Printing seq_item_1", UVM_LOW)
    seq_item_1.print();          //printing the seq_item_1
    
    //Note:: name of seq_item_1 will be printed as seq_item_0, because there is no option to pass argument to create method while calling the clone method.
  end  
endmodule

Simulator Output:

-------------------------------------
Name Type Size Value
-------------------------------------
seq_item_0 mem_seq_item - @334 
addr integral 4 'h4 
wr_en integral 1 'h1 
rd_en integral 1 'h0 
wdata integral 8 'h88 
-------------------------------------
UVM_INFO testbench.sv(52) @ 0: reporter [] Printing seq_item_0
-------------------------------------
Name Type Size Value
-------------------------------------
seq_item_0 mem_seq_item - @334 
addr integral 4 'h4 
wr_en integral 1 'h1 
rd_en integral 1 'h0 
wdata integral 8 'h88 
-------------------------------------
UVM_INFO testbench.sv(54) @ 0: reporter [] Printing seq_item_1
-------------------------------------
Name Type Size Value
-------------------------------------
seq_item_0 mem_seq_item - @338 
addr integral 4 'h8 
wr_en integral 1 'h1 
rd_en integral 1 'h0 
wdata integral 8 'h56 
-------------------------------------

Click to execute on    eda_png

compare

Deep compares members of this data object with those of the object provided in the RHS (right-hand side) argument, returning 1 on a match, 0 otherwise.

Compare Method

class mem_seq_item extends uvm_sequence_item;
  //data and control fields
  rand bit [3:0] addr;
  rand bit       wr_en;
  rand bit       rd_en;
  rand bit [7:0] wdata;
       bit [7:0] rdata;
  
  //Utility and Field macros,
  `uvm_object_utils_begin(mem_seq_item)
    `uvm_field_int(addr,UVM_ALL_ON)
    `uvm_field_int(wr_en,UVM_ALL_ON)
    `uvm_field_int(rd_en,UVM_ALL_ON)
    `uvm_field_int(wdata,UVM_ALL_ON)
  `uvm_object_utils_end
  
  //Constructor
  function new(string name = "mem_seq_item");
    super.new(name);
  endfunction
  
  //constaint, to generate any one among write and read
  constraint wr_rd_c { wr_en != rd_en; }; 
  
endclass

//-------------------------------------------------------------------------
//Simple TestBench to access sequence item
//-------------------------------------------------------------------------
module seq_item_tb;
  
  //instance
  mem_seq_item seq_item_0;
  mem_seq_item seq_item_1;
  
  initial begin
    //create method
    seq_item_0 = mem_seq_item::type_id::create("seq_item_0"); 
    seq_item_1 = mem_seq_item::type_id::create("seq_item_1");    
    
    //---------------Mismatch Case------------------------------  
    seq_item_0.randomize(); //randomizing the seq_item_0  
    seq_item_1.randomize(); //randomizing the seq_item_1  
    
    seq_item_0.print();     //printing the seq_item_0
    seq_item_1.print();     //printing the seq_item_1
    
    //compare method
    if(seq_item_0.compare(seq_item_1))
      `uvm_info("","seq_item_0 matching with seq_item_1", UVM_LOW)
    else
      `uvm_error("","seq_item_0 is not matching with seq_item_1")
    
    //---------------Matching Case------------------------------  
    seq_item_1.copy(seq_item_0); //copy seq_item_0 to seq_item_1
    //compare method
    if(seq_item_0.compare(seq_item_1))
      `uvm_info("","seq_item_0 matching with seq_item_1", UVM_LOW)
    else
      `uvm_error("","seq_item_0 is not matching with seq_item_1")     
      
  end  
endmodule

Simulator Output:

-------------------------------------
Name Type Size Value
-------------------------------------
seq_item_0 mem_seq_item - @334 
addr integral 4 'h4 
wr_en integral 1 'h1 
rd_en integral 1 'h0 
wdata integral 8 'h88 
-------------------------------------
-------------------------------------
Name Type Size Value
-------------------------------------
seq_item_1 mem_seq_item - @338 
addr integral 4 'h5 
wr_en integral 1 'h0 
rd_en integral 1 'h1 
wdata integral 8 'h33 
-------------------------------------
UVM_INFO @ 0: reporter [MISCMP] Miscompare for seq_item_0.addr: lhs = 'h4 : rhs = 'h5
UVM_INFO @ 0: reporter [MISCMP] 1 Miscompare(s) for object seq_item_1@338 vs. seq_item_0@334
UVM_ERROR testbench.sv(54) @ 0: reporter [] seq_item_0 is not matching with seq_item_1
UVM_INFO testbench.sv(59) @ 0: reporter [] seq_item_0 matching with seq_item_1

Click to execute on    eda_png

pack, pack_bytes, pack_ints

The pack methods bitwise-concatenate this object’s properties into an array of bits, bytes, or ints.

unpack,unpack_bytes,unpack_ints

The unpack methods extract property values from an array of bits, bytes, or ints.

pack/unpack to/from Array of bit type

class mem_seq_item extends uvm_sequence_item;
  //data and control fields
  rand bit [3:0] addr;
  rand bit       wr_en;
  rand bit       rd_en;
  rand bit [7:0] wdata;
       bit [7:0] rdata;
  
  //Utility and Field macros,
  `uvm_object_utils_begin(mem_seq_item)
    `uvm_field_int(addr,UVM_ALL_ON)
    `uvm_field_int(wr_en,UVM_ALL_ON)
    `uvm_field_int(rd_en,UVM_ALL_ON)
    `uvm_field_int(wdata,UVM_ALL_ON)
  `uvm_object_utils_end
  
  //Constructor
  function new(string name = "mem_seq_item");
    super.new(name);
  endfunction
  
  //constaint, to generate any one among write and read
  constraint wr_rd_c { wr_en != rd_en; }; 
  
endclass

//-------------------------------------------------------------------------
//Simple TestBench to access sequence item
//-------------------------------------------------------------------------
module seq_item_tb;
  
  //instance
  mem_seq_item seq_item_0;
  mem_seq_item seq_item_1;
  bit bit_packed_data[];
  
  initial begin
    //create method
    seq_item_0 = mem_seq_item::type_id::create("seq_item_0");
    seq_item_1 = mem_seq_item::type_id::create("seq_item_1");
    
    //---------------------- PACK  ------------------------------  
    seq_item_0.randomize(); //randomizing the seq_item_0
    seq_item_0.print();     //printing the seq_item_0
    
    seq_item_0.pack(bit_packed_data);    //pack method
    foreach(bit_packed_data[i]) 
      `uvm_info("PACK",$sformatf("bit_packed_data[%0d] = %b",i,bit_packed_data[i]), UVM_LOW)
      
    //---------------------- UNPACK ------------------------------
    `uvm_info("UNPACK","Before UnPack", UVM_LOW)
    seq_item_1.print();     //printing the seq_item_1
    seq_item_1.unpack(bit_packed_data);     //unpack method
    `uvm_info("UNPACK","After UnPack", UVM_LOW)
    seq_item_1.print();     //printing the seq_item_1

  end  
endmodule

Simulator Output:

-------------------------------------
Name Type Size Value
-------------------------------------
seq_item_0 mem_seq_item - @334 
addr integral 4 'h4 
wr_en integral 1 'h1 
rd_en integral 1 'h0 
wdata integral 8 'h88 
-------------------------------------
UVM_INFO testbench.sv(51) @ 0: reporter [PACK] pack_data[0] = 0
UVM_INFO testbench.sv(51) @ 0: reporter [PACK] pack_data[1] = 1
UVM_INFO testbench.sv(51) @ 0: reporter [PACK] pack_data[2] = 0
UVM_INFO testbench.sv(51) @ 0: reporter [PACK] pack_data[3] = 0
UVM_INFO testbench.sv(51) @ 0: reporter [PACK] pack_data[4] = 1
UVM_INFO testbench.sv(51) @ 0: reporter [PACK] pack_data[5] = 0
UVM_INFO testbench.sv(51) @ 0: reporter [PACK] pack_data[6] = 1
UVM_INFO testbench.sv(51) @ 0: reporter [PACK] pack_data[7] = 0
UVM_INFO testbench.sv(51) @ 0: reporter [PACK] pack_data[8] = 0
UVM_INFO testbench.sv(51) @ 0: reporter [PACK] pack_data[9] = 0
UVM_INFO testbench.sv(51) @ 0: reporter [PACK] pack_data[10] = 1
UVM_INFO testbench.sv(51) @ 0: reporter [PACK] pack_data[11] = 0
UVM_INFO testbench.sv(51) @ 0: reporter [PACK] pack_data[12] = 0
UVM_INFO testbench.sv(51) @ 0: reporter [PACK] pack_data[13] = 0
UVM_INFO testbench.sv(54) @ 0: reporter [UNPACK] Before UnPack
-------------------------------------
Name Type Size Value
-------------------------------------
seq_item_1 mem_seq_item - @338 
addr integral 4 'h0 
wr_en integral 1 'h0 
rd_en integral 1 'h0 
wdata integral 8 'h0 
-------------------------------------
UVM_INFO testbench.sv(57) @ 0: reporter [UNPACK] After UnPack
-------------------------------------
Name Type Size Value
-------------------------------------
seq_item_1 mem_seq_item - @338 
addr integral 4 'h4 
wr_en integral 1 'h1 
rd_en integral 1 'h0 
wdata integral 8 'h88 
-------------------------------------

Click to execute on    eda_png

pack/unpack to/from Array of byte type

class mem_seq_item extends uvm_sequence_item;
  //data and control fields
  rand bit [3:0] addr;
  rand bit       wr_en;
  rand bit       rd_en;
  rand bit [7:0] wdata;
       bit [7:0] rdata;
  
  //Utility and Field macros,
  `uvm_object_utils_begin(mem_seq_item)
    `uvm_field_int(addr,UVM_ALL_ON)
    `uvm_field_int(wr_en,UVM_ALL_ON)
    `uvm_field_int(rd_en,UVM_ALL_ON)
    `uvm_field_int(wdata,UVM_ALL_ON)
  `uvm_object_utils_end
  
  //Constructor
  function new(string name = "mem_seq_item");
    super.new(name);
  endfunction
  
  //constaint, to generate any one among write and read
  constraint wr_rd_c { wr_en != rd_en; }; 
  
endclass

//-------------------------------------------------------------------------
//Simple TestBench to access sequence item
//-------------------------------------------------------------------------
module seq_item_tb;
  
  //instance
  mem_seq_item seq_item_0;
  mem_seq_item seq_item_1;
  byte unsigned byte_packed_data[];
  
  initial begin
    //create method
    seq_item_0 = mem_seq_item::type_id::create("seq_item_0");
    seq_item_1 = mem_seq_item::type_id::create("seq_item_1");
    
    //---------------------- PACK  ------------------------------  
    seq_item_0.randomize(); //randomizing the seq_item_0
    seq_item_0.print();     //printing the seq_item_0
    
    seq_item_0.pack_bytes(byte_packed_data);    //pack method
    
    foreach(byte_packed_data[i]) 
      `uvm_info("PACK",$sformatf("byte_packed_data[%0d] = %b",i,byte_packed_data[i]), UVM_LOW)
      
    //---------------------- UNPACK ------------------------------
    `uvm_info("UNPACK","Before UnPack", UVM_LOW)
    seq_item_1.print();     //printing the seq_item_1
    
    seq_item_1.unpack_bytes(byte_packed_data);     //unpack method
    
    `uvm_info("UNPACK","After UnPack", UVM_LOW)
    seq_item_1.print();     //printing the seq_item_1

  end  
endmodule

Simulator Output:

-------------------------------------
Name Type Size Value
-------------------------------------
seq_item_0 mem_seq_item - @334 
addr integral 4 'h4 
wr_en integral 1 'h1 
rd_en integral 1 'h0 
wdata integral 8 'h88 
-------------------------------------

UVM_INFO testbench.sv(51) @ 0: reporter [PACK] byte_packed_data[0] = 01001010
UVM_INFO testbench.sv(51) @ 0: reporter [PACK] byte_packed_data[1] = 00100000
UVM_INFO testbench.sv(54) @ 0: reporter [UNPACK] Before UnPack

-------------------------------------
Name Type Size Value
-------------------------------------
seq_item_1 mem_seq_item - @338 
addr integral 4 'h0 
wr_en integral 1 'h0 
rd_en integral 1 'h0 
wdata integral 8 'h0 
-------------------------------------

UVM_INFO testbench.sv(57) @ 0: reporter [UNPACK] After UnPack

-------------------------------------
Name Type Size Value
-------------------------------------
seq_item_1 mem_seq_item - @338 
addr integral 4 'h4 
wr_en integral 1 'h1 
rd_en integral 1 'h0 
wdata integral 8 'h88 
-------------------------------------

Click to execute on    eda_png

pack/unpack to/from Array of int type

class mem_seq_item extends uvm_sequence_item;
  //data and control fields
  rand bit [3:0] addr;
  rand bit       wr_en;
  rand bit       rd_en;
  rand bit [7:0] wdata;
       bit [7:0] rdata;
  
  //Utility and Field macros,
  `uvm_object_utils_begin(mem_seq_item)
    `uvm_field_int(addr,UVM_ALL_ON)
    `uvm_field_int(wr_en,UVM_ALL_ON)
    `uvm_field_int(rd_en,UVM_ALL_ON)
    `uvm_field_int(wdata,UVM_ALL_ON)
  `uvm_object_utils_end
  
  //Constructor
  function new(string name = "mem_seq_item");
    super.new(name);
  endfunction
  
  //constaint, to generate any one among write and read
  constraint wr_rd_c { wr_en != rd_en; }; 
  
endclass

//-------------------------------------------------------------------------
//Simple TestBench to access sequence item
//-------------------------------------------------------------------------
module seq_item_tb;
  
  //instance
  mem_seq_item seq_item_0;
  mem_seq_item seq_item_1;
  int unsigned int_packed_data[];
  
  initial begin
    //create method
    seq_item_0 = mem_seq_item::type_id::create("seq_item_0");
    seq_item_1 = mem_seq_item::type_id::create("seq_item_1");
    
    //---------------------- PACK  ------------------------------  
    seq_item_0.randomize(); //randomizing the seq_item_0
    seq_item_0.print();     //printing the seq_item_0
    
    seq_item_0.pack_ints(int_packed_data);    //pack method
    
    foreach(int_packed_data[i]) 
      `uvm_info("PACK",$sformatf("int_packed_data[%0d] = %b",i,int_packed_data[i]), UVM_LOW)
      
    //---------------------- UNPACK ------------------------------
    `uvm_info("UNPACK","Before UnPack", UVM_LOW)
    seq_item_1.print();     //printing the seq_item_1
    
    seq_item_1.unpack_ints(int_packed_data);     //unpack method
    
    `uvm_info("UNPACK","After UnPack", UVM_LOW)
    seq_item_1.print();     //printing the seq_item_1

  end  
endmodule

 Simulator Output: 

-------------------------------------
Name Type Size Value
-------------------------------------
seq_item_0 mem_seq_item - @334 
addr integral 4 'h4 
wr_en integral 1 'h1 
rd_en integral 1 'h0 
wdata integral 8 'h88 
-------------------------------------
UVM_INFO testbench.sv(52) @ 0: reporter [PACK] int_packed_data[0] = 01001010001000000000000000000000
UVM_INFO testbench.sv(55) @ 0: reporter [UNPACK] Before UnPack
-------------------------------------
Name Type Size Value
-------------------------------------
seq_item_1 mem_seq_item - @338 
addr integral 4 'h0 
wr_en integral 1 'h0 
rd_en integral 1 'h0 
wdata integral 8 'h0 
-------------------------------------
UVM_INFO testbench.sv(60) @ 0: reporter [UNPACK] After UnPack
-------------------------------------
Name Type Size Value
-------------------------------------
seq_item_1 mem_seq_item - @338 
addr integral 4 'h4 
wr_en integral 1 'h1 
rd_en integral 1 'h0 
wdata integral 8 'h88 
-------------------------------------

Click to execute on    eda_png

❮ Previous Next ❯

UVM Tutorial

UVM tutorial for beginners

Introduction Introduction to UVM
UVM TestBench TestBecnh Hierarchy and BlockDiagram
UVM Sequence item Utility & Field Macros
Methods with example Create Print
Copy Clone
Compare Pack
UnPack
UVM Sequence Sequence Methods Sequence Macros Sequence Example codes
UVM Sequence control
UVM Sequencer UVM Sequencer with Example
UVM Config db UVM Config db Set Method Get Method
UVM Phases UVM Phases in detail
UVM Driver UVM Driver with example
UVM Monitor UVM Monitor with example
UVM Agent UVM Agent with example
UVM Scoreboard UVM Scoreboard with example
UVM Environment UVM Environment with example
UVM Test UVM Test with example
UVM TestBench Top UVM TestBench Top with example
UVM TestBench Example UVM TestBench examples

 

UVM Callback Tutorial UVM Callback UVM Callback add method UVM Callback example
UVM Callback in UVM Sequence
UVM Event Tutorial UVM Event Tutorial
UVM TLM Tuorial TLM Tutorial
UVM RAL Tuorial RAL Tutorial
UVM Barrier UVM Barrier UVM Barrier examples
UVM HeartBeat UVM HeartBeat UVM HeartBeat examples

uvm heartbeat example

uvm_heartbeat example

Adding uvm_heratbeat logic to the testbench

  • The testbench in the below example consists of a component comp_a
  • In the run phase of comp_a, a loop is running with a delay of 50
  • This example shows the implementation of the uvm heartbeat, to monitor the idle condition of comp_a
Testbench hierarchy is,

———————————————–
Name          Type
———————————————–
uvm_test_top      basic_test
env                  environment
comp_a       component_a
———————————————–

component_a code

Below is the complete code of component_a,
which has a loop in run_phase which raises the objection with a 50ns delay between the iterations.

*Objection is declared in the top file.

class component_a extends uvm_component;
  
  `uvm_component_utils(component_a)
  
  //--------------------------------------- 
  // Constructor
  //---------------------------------------
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction : new
   
  //---------------------------------------
  // run_phase 
  //---------------------------------------
  virtual task run_phase(uvm_phase phase);
    phase.raise_objection(this);
    `uvm_info(get_type_name(),$sformatf(" [ Comp-A ] 
                              Objection raised "),UVM_LOW)
    
    for(int i=0;i<10;i++) begin //{
      `uvm_info(get_type_name(),$sformatf(" [ Comp-A ] 
                                Idx-%0d raising obje objection",i),UVM_LOW)
      obje.raise_objection(this);
      #50;
    end //}   
    
    phase.drop_objection(this);
  endtask : run_phase

endclass : component_a

env code without a heartbeat logic

Below is the environment code without heartbeat logic.

class environment extends uvm_env;
  
  //---------------------------------------
  // Components Instantiation
  //---------------------------------------
  component_a comp_a;
  
  `uvm_component_utils(environment)
  
  //--------------------------------------- 
  // Constructor
  //---------------------------------------
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction : new

  //---------------------------------------
  // build_phase - Create the components
  //---------------------------------------
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);

    comp_a = component_a::type_id::create("comp_a", this);
  endfunction : build_phase
endclass : environment

env code with a heartbeat logic

Below are the steps to set up the uvm heartbeat,

Declare the heartbeat and event

The event is the event at which the heartbeat monitor looks for idleness of components

  uvm_heartbeat heart_beat;
  uvm_event     hb_event;

Create the heartbeat and event

    heart_beat = new("heart_beat", this, obje);
    hb_event   = new("hb_event");

Set the mode

This will tell the heartbeat about the active condition of the testbench

UVM_ALL_ACTIVE – all components
UVM_ONE_ACTIVE – exactly one component
UVM_ANY_ACTIVE – any component

  heart_beat.set_mode(UVM_ALL_ACTIVE);

Setup the heartbeat event

  heart_beat.set_heartbeat(hb_event,hb);

Add the components to be monitored

By using the add method, the component can be added for monitoring.

  heart_beat.add(comp_a);

Start the heartbeat

  heart_beat.start(hb_event);

Trigger the event to monitor

  virtual task run_phase(uvm_phase phase);
    heart_beat.start(hb_event);
    
    repeat(10) begin //{
      #100;
      `uvm_info(get_type_name(),$sformatf(" [ Env ] Triggering hb_event"),UVM_LOW)
      hb_event.trigger();
    end //}
  endtask : run_phase  

Complete env code,

class environment extends uvm_env;
  
  //---------------------------------------
  // Components Instantiation
  //---------------------------------------
  component_a comp_a;
  
  uvm_heartbeat heart_beat;
  uvm_event     hb_event;
  
  `uvm_component_utils(environment)
  
  //--------------------------------------- 
  // Constructor
  //---------------------------------------
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction : new

  //---------------------------------------
  // build_phase - Create the components
  //---------------------------------------
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);

    comp_a = component_a::type_id::create("comp_a", this);
    
    heart_beat = new("heart_beat", this, obje);
    hb_event   = new("hb_event");
  endfunction : build_phase
  
  //---------------------------------------
  // Connect_phase 
  //---------------------------------------
  function void connect_phase(uvm_phase phase);
    uvm_component hb[$];
    heart_beat.set_mode(UVM_ALL_ACTIVE);
    heart_beat.set_heartbeat(hb_event,hb);
    heart_beat.add(comp_a);
  endfunction : connect_phase
  
  //---------------------------------------
  // run_phase 
  //---------------------------------------
  virtual task run_phase(uvm_phase phase);
    heart_beat.start(hb_event);
    
    repeat(10) begin //{
      #100;
      `uvm_info(get_type_name(),$sformatf(" [ Env ] Triggering hb_event"),UVM_LOW)
      hb_event.trigger();
    end //}
  endtask : run_phase  
endclass : environment

Simulator Output

UVM_INFO @ 0: reporter [RNTST] Running test basic_test...
--------------------------------------
Name Type Size Value
--------------------------------------
uvm_test_top basic_test - @1858
 env environment - @1927
 comp_a component_a - @1959
--------------------------------------
UVM_INFO component_a.sv(21) @ 0: uvm_test_top.env.comp_a [component_a] [ Comp-A ] Objection raised 
UVM_INFO component_a.sv(24) @ 0: uvm_test_top.env.comp_a [component_a] [ Comp-A ] Idx-0 raising obje objection
UVM_INFO component_a.sv(24) @ 50: uvm_test_top.env.comp_a [component_a] [ Comp-A ] Idx-1 raising obje objection
UVM_INFO environment.sv(55) @ 100: uvm_test_top.env [environment] [ Env ] Triggering hb_event
UVM_INFO component_a.sv(24) @ 100: uvm_test_top.env.comp_a [component_a] [ Comp-A ] Idx-2 raising obje objection
UVM_INFO component_a.sv(24) @ 150: uvm_test_top.env.comp_a [component_a] [ Comp-A ] Idx-3 raising obje objection
UVM_INFO environment.sv(55) @ 200: uvm_test_top.env [environment] [ Env ] Triggering hb_event
UVM_INFO component_a.sv(24) @ 200: uvm_test_top.env.comp_a [component_a] [ Comp-A ] Idx-4 raising obje objection
UVM_INFO component_a.sv(24) @ 250: uvm_test_top.env.comp_a [component_a] [ Comp-A ] Idx-5 raising obje objection
UVM_INFO environment.sv(55) @ 300: uvm_test_top.env [environment] [ Env ] Triggering hb_event
UVM_INFO component_a.sv(24) @ 300: uvm_test_top.env.comp_a [component_a] [ Comp-A ] Idx-6 raising obje objection
UVM_INFO component_a.sv(24) @ 350: uvm_test_top.env.comp_a [component_a] [ Comp-A ] Idx-7 raising obje objection
UVM_INFO environment.sv(55) @ 400: uvm_test_top.env [environment] [ Env ] Triggering hb_event
UVM_INFO component_a.sv(24) @ 400: uvm_test_top.env.comp_a [component_a] [ Comp-A ] Idx-8 raising obje objection
UVM_INFO component_a.sv(24) @ 450: uvm_test_top.env.comp_a [component_a] [ Comp-A ] Idx-9 raising obje objection
UVM_INFO environment.sv(55) @ 500: uvm_test_top.env [environment] [ Env ] Triggering hb_event
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_objection.svh(1271) @ 500: reporter [TEST_DONE] 
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_report_server.svh(847) @ 500: reporter [UVM/REPORT/SERVER]

Click to execute on   

Output Analysis

In the above simulation result, we could see that there is no FATAL message from the uvm_heartbeat, this is because the comp_a is always active between the heartbeat the event triggers.

comp_a loop delay value is 50 and the event trigger interval is 100.

So between the heartbeat event trigger, there will be one iteration of the loop.

Fatal From HeartBeat Monitor / Detecting Inactive condition of the testbench

This example is same as the previous example, the comp_a is shown as inactive to the uvm heartbeat so that the uvm heartbeat should detect the same.

As mentioned before, UVM_heartbeat watches for an activity in the comp_a and if it finds that there is no activity in the specified interval of time (between the event triggering), then uvm_heratbeat issue a fatal message which leads to the end of the simulation.

In order to make no activity within the heartbeat event triggering time, let’s make the delay of loop more than the heartbeat event triggering time.

comp_a delay modification

  virtual task run_phase(uvm_phase phase);
    phase.raise_objection(this);
    `uvm_info(get_type_name(),$sformatf(" [ Comp-A ] 
                              Objection raised "),UVM_LOW)
    
    for(int i=0;i< 10;i++) begin //{
      `uvm_info(get_type_name(),$sformatf(" [ Comp-A ] 
                                Idx-%0d raising obje objection",i),UVM_LOW)
      obje.raise_objection(this);
      
      //Variable delay
      #(50*i);
    end //}   
    
    phase.drop_objection(this);
  endtask : run_phase

Simulator Output

UVM_INFO @ 0: reporter [RNTST] Running test basic_test...
--------------------------------------
Name Type Size Value
--------------------------------------
uvm_test_top basic_test - @1858
 env environment - @1927
 comp_a component_a - @1959
--------------------------------------
UVM_INFO component_a.sv(21) @ 0: uvm_test_top.env.comp_a [component_a] [ Comp-A ] Objection raised 
UVM_INFO component_a.sv(24) @ 0: uvm_test_top.env.comp_a [component_a] [ Comp-A ] Idx-0 raising obje objection
UVM_INFO component_a.sv(24) @ 0: uvm_test_top.env.comp_a [component_a] [ Comp-A ] Idx-1 raising obje objection
UVM_INFO component_a.sv(24) @ 50: uvm_test_top.env.comp_a [component_a] [ Comp-A ] Idx-2 raising obje objection
UVM_INFO environment.sv(55) @ 100: uvm_test_top.env [environment] [ Env ] Triggering hb_event
UVM_INFO component_a.sv(24) @ 150: uvm_test_top.env.comp_a [component_a] [ Comp-A ] Idx-3 raising obje objection
UVM_INFO environment.sv(55) @ 200: uvm_test_top.env [environment] [ Env ] Triggering hb_event
UVM_INFO component_a.sv(24) @ 300: uvm_test_top.env.comp_a [component_a] [ Comp-A ] Idx-4 raising obje objection
UVM_INFO environment.sv(55) @ 300: uvm_test_top.env [environment] [ Env ] Triggering hb_event
UVM_INFO environment.sv(55) @ 400: uvm_test_top.env [environment] [ Env ] Triggering hb_event
UVM_FATAL @ 400: uvm_test_top.env [HBFAIL] Did not recieve an update of obje for component uvm_test_top.env.comp_a since 
last event trigger at time 300 : last update time was 300
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_report_server.svh(847) @ 400: reporter [UVM/REPORT/SERVER] 

Click to execute on   

Adding multiple components to uvm_heartbeat

In the previous example, only one component comp_a is monitored by the uvm_heartbeat. In this example along with the comp_a will add one more component comp_b to the heartbeat monitor.

Testbench hierarchy is,

———————————————–
Name          Type
———————————————–
uvm_test_top      basic_test
env                  environment
comp_a       component_a
comp_b       component_b
———————————————–

On comparing to the previous example, the only extra code w.r.t heartbeat is adding comp_b to monitor.

By using the add method, component comp_b can be added for monitoring.

  heart_beat.add(comp_b);

As there are two components, we will set the mode as any component is active,

  heart_beat.set_mode(UVM_ANY_ACTIVE);

Complete env code,

class environment extends uvm_env;
  
  //---------------------------------------
  // Components Instantiation
  //---------------------------------------
  component_a comp_a;
  component_b comp_b;
  
  uvm_heartbeat heart_beat;
  uvm_event     hb_event;
  
  `uvm_component_utils(environment)
  
  //--------------------------------------- 
  // Constructor
  //---------------------------------------
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction : new

  //---------------------------------------
  // build_phase - Create the components
  //---------------------------------------
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);

    comp_a = component_a::type_id::create("comp_a", this);
    comp_b = component_b::type_id::create("comp_b", this);
    
    heart_beat = new("heart_beat", this, obje);
    hb_event   = new("hb_event");
  endfunction : build_phase
  
  //---------------------------------------
  // Connect_phase 
  //---------------------------------------
  function void connect_phase(uvm_phase phase);
    uvm_component hb[$];
    heart_beat.set_mode(UVM_ANY_ACTIVE);
    heart_beat.set_heartbeat(hb_event,hb);
    heart_beat.add(comp_a);
    heart_beat.add(comp_b);
  endfunction : connect_phase
  
  //---------------------------------------
  // run_phase 
  //---------------------------------------
  virtual task run_phase(uvm_phase phase);
    
    heart_beat.start(hb_event);
    
    repeat(20) begin //{
      #60;
      hb_event.trigger();
      `uvm_info(get_type_name(),$sformatf(" [ Env ] Triggering hb_event"),UVM_LOW)
    end //}

  endtask : run_phase  
endclass : environment

Simulator Output

UVM_INFO @ 0: reporter [RNTST] Running test basic_test...
--------------------------------------
Name Type Size Value
--------------------------------------
uvm_test_top basic_test - @1861
 env environment - @1930
 comp_a component_a - @1962
 comp_b component_b - @1993
--------------------------------------
UVM_INFO component_b.sv(21) @ 0: uvm_test_top.env.comp_b [component_b] [ Comp-B ] Objection raised 
UVM_INFO component_b.sv(24) @ 0: uvm_test_top.env.comp_b [component_b] [ Comp-B ] Idx-0 raising obje objection
UVM_INFO component_a.sv(21) @ 0: uvm_test_top.env.comp_a [component_a] [ Comp-A ] Objection raised 
UVM_INFO component_a.sv(24) @ 0: uvm_test_top.env.comp_a [component_a] [ Comp-A ] Idx-0 raising obje objection
UVM_INFO component_b.sv(24) @ 30: uvm_test_top.env.comp_b [component_b] [ Comp-B ] Idx-1 raising obje objection
UVM_INFO component_a.sv(24) @ 50: uvm_test_top.env.comp_a [component_a] [ Comp-A ] Idx-1 raising obje objection
UVM_INFO environment.sv(61) @ 60: uvm_test_top.env [environment] [ Env ] Triggering hb_event
UVM_INFO component_b.sv(24) @ 60: uvm_test_top.env.comp_b [component_b] [ Comp-B ] Idx-2 raising obje objection
UVM_INFO component_b.sv(24) @ 90: uvm_test_top.env.comp_b [component_b] [ Comp-B ] Idx-3 raising obje objection
UVM_INFO component_a.sv(24) @ 100: uvm_test_top.env.comp_a [component_a] [ Comp-A ] Idx-2 raising obje objection
UVM_INFO environment.sv(61) @ 120: uvm_test_top.env [environment] [ Env ] Triggering hb_event
UVM_INFO component_b.sv(24) @ 120: uvm_test_top.env.comp_b [component_b] [ Comp-B ] Idx-4 raising obje objection
UVM_INFO component_a.sv(24) @ 150: uvm_test_top.env.comp_a [component_a] [ Comp-A ] Idx-3 raising obje objection
UVM_INFO component_b.sv(24) @ 150: uvm_test_top.env.comp_b [component_b] [ Comp-B ] Idx-5 raising obje objection
UVM_INFO environment.sv(61) @ 180: uvm_test_top.env [environment] [ Env ] Triggering hb_event
UVM_INFO component_b.sv(24) @ 180: uvm_test_top.env.comp_b [component_b] [ Comp-B ] Idx-6 raising obje objection
UVM_INFO component_a.sv(24) @ 200: uvm_test_top.env.comp_a [component_a] [ Comp-A ] Idx-4 raising obje objection
UVM_INFO component_b.sv(24) @ 210: uvm_test_top.env.comp_b [component_b] [ Comp-B ] Idx-7 raising obje objection
UVM_INFO environment.sv(61) @ 240: uvm_test_top.env [environment] [ Env ] Triggering hb_event
UVM_INFO component_b.sv(24) @ 240: uvm_test_top.env.comp_b [component_b] [ Comp-B ] Idx-8 raising obje objection
UVM_INFO component_b.sv(24) @ 270: uvm_test_top.env.comp_b [component_b] [ Comp-B ] Idx-9 raising obje objection
UVM_INFO environment.sv(61) @ 300: uvm_test_top.env [environment] [ Env ] Triggering hb_event
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_objection.svh(1271) @ 300: reporter [TEST_DONE] 
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_report_server.svh(847) @ 300: reporter [UVM/REPORT/SERVER] 

Click to execute on   

Heartbeat with All Components active mode

This example is same as the previous example, the only change is monitoring mode.

The monitoring mode is changed to monitor all the components. i.e, comp_a and comp_b if one of the components is inactive then the heartbeat will give the FATAL message.

Setting the heartbeat mode as ALL_ACTIVE.

heart_beat.set_mode(UVM_ALL_ACTIVE);

Complete env code,

class environment extends uvm_env;
  
  //---------------------------------------
  // Components Instantiation
  //---------------------------------------
  component_a comp_a;
  component_b comp_b;
  
  uvm_heartbeat heart_beat;
  uvm_event     hb_event;
  
  `uvm_component_utils(environment)
  
  //--------------------------------------- 
  // Constructor
  //---------------------------------------
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction : new

  //---------------------------------------
  // build_phase - Create the components
  //---------------------------------------
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);

    comp_a = component_a::type_id::create("comp_a", this);
    comp_b = component_b::type_id::create("comp_b", this);
    
    heart_beat = new("heart_beat", this, obje);
    hb_event   = new("hb_event");
  endfunction : build_phase
  
  //---------------------------------------
  // Connect_phase 
  //---------------------------------------
  function void connect_phase(uvm_phase phase);
    uvm_component hb[$];
    heart_beat.set_mode(UVM_ALL_ACTIVE);
    heart_beat.set_heartbeat(hb_event,hb);
    heart_beat.add(comp_a);
    heart_beat.add(comp_b);
  endfunction : connect_phase
  
  //---------------------------------------
  // run_phase 
  //---------------------------------------
  virtual task run_phase(uvm_phase phase);
    
    heart_beat.start(hb_event);
    
    repeat(20) begin //{
      #60;
      hb_event.trigger();
      `uvm_info(get_type_name(),$sformatf(" [ Env ] Triggering hb_event"),UVM_LOW)
    end //}

  endtask : run_phase  
endclass : environment

Simulator Output

UVM_INFO @ 0: reporter [RNTST] Running test basic_test...
--------------------------------------
Name Type Size Value
--------------------------------------
uvm_test_top basic_test - @1861
 env environment - @1930
 comp_a component_a - @1962
 comp_b component_b - @1993
--------------------------------------
UVM_INFO component_b.sv(21) @ 0: uvm_test_top.env.comp_b [component_b] [ Comp-B ] Objection raised 
UVM_INFO component_b.sv(24) @ 0: uvm_test_top.env.comp_b [component_b] [ Comp-B ] Idx-0 raising obje objection
UVM_INFO component_a.sv(21) @ 0: uvm_test_top.env.comp_a [component_a] [ Comp-A ] Objection raised 
UVM_INFO component_a.sv(24) @ 0: uvm_test_top.env.comp_a [component_a] [ Comp-A ] Idx-0 raising obje objection
UVM_INFO component_b.sv(24) @ 30: uvm_test_top.env.comp_b [component_b] [ Comp-B ] Idx-1 raising obje objection
UVM_INFO component_a.sv(24) @ 50: uvm_test_top.env.comp_a [component_a] [ Comp-A ] Idx-1 raising obje objection
UVM_INFO environment.sv(61) @ 60: uvm_test_top.env [environment] [ Env ] Triggering hb_event
UVM_INFO component_b.sv(24) @ 60: uvm_test_top.env.comp_b [component_b] [ Comp-B ] Idx-2 raising obje objection
UVM_INFO component_b.sv(24) @ 90: uvm_test_top.env.comp_b [component_b] [ Comp-B ] Idx-3 raising obje objection
UVM_INFO component_a.sv(24) @ 100: uvm_test_top.env.comp_a [component_a] [ Comp-A ] Idx-2 raising obje objection
UVM_INFO environment.sv(61) @ 120: uvm_test_top.env [environment] [ Env ] Triggering hb_event
UVM_INFO component_b.sv(24) @ 120: uvm_test_top.env.comp_b [component_b] [ Comp-B ] Idx-4 raising obje objection
UVM_INFO component_a.sv(24) @ 150: uvm_test_top.env.comp_a [component_a] [ Comp-A ] Idx-3 raising obje objection
UVM_INFO component_b.sv(24) @ 150: uvm_test_top.env.comp_b [component_b] [ Comp-B ] Idx-5 raising obje objection
UVM_INFO environment.sv(61) @ 180: uvm_test_top.env [environment] [ Env ] Triggering hb_event
UVM_INFO component_b.sv(24) @ 180: uvm_test_top.env.comp_b [component_b] [ Comp-B ] Idx-6 raising obje objection
UVM_INFO component_a.sv(24) @ 200: uvm_test_top.env.comp_a [component_a] [ Comp-A ] Idx-4 raising obje objection
UVM_INFO component_b.sv(24) @ 210: uvm_test_top.env.comp_b [component_b] [ Comp-B ] Idx-7 raising obje objection
UVM_INFO environment.sv(61) @ 240: uvm_test_top.env [environment] [ Env ] Triggering hb_event
UVM_INFO component_b.sv(24) @ 240: uvm_test_top.env.comp_b [component_b] [ Comp-B ] Idx-8 raising obje objection
UVM_INFO component_b.sv(24) @ 270: uvm_test_top.env.comp_b [component_b] [ Comp-B ] Idx-9 raising obje objection
UVM_INFO environment.sv(61) @ 300: uvm_test_top.env [environment] [ Env ] Triggering hb_event
UVM_FATAL @ 300: uvm_test_top.env [HBFAIL] Did not recieve an update of obje for component uvm_test_top.env.comp_a 
since last event trigger at time 240 : last update time was 200
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_report_server.svh(847) @ 300: reporter [UVM/REPORT/SERVER]

Click to execute on   

❮ Previous Next ❯