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
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
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.
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.
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). ❮ PreviousNext ❯
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.
The below diagram shows the detailed components and connection of RAL with testbench.
For Detailed description on RAL Concepts refer to UVM RAL TUTORIAL.
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 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.
* 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.
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.
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.
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) ❮ PreviousNext ❯
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.
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,
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
---------------------------------------
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
-------------------------------------
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
-------------------------------------
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
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
-------------------------------------
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
-------------------------------------
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.
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,
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.
We use cookies to ensure that we give you the best experience on our website. If you continue to use this site we will assume that you are happy with it.Ok