UVM Questions and Answers: Suman Halder
UVM Questions and Answers: Suman Halder
UVM Questions and Answers: Suman Halder
Answers
Suman Halder
1) What are the three main types of UVM classes
UVM Classes
uvm_object
uvm_transaction
uvm_component
uvm_object
Core class based operational methods (create, copy, clone, compare, print, record, etc..), instance identification fields (name, type name,
unique id, etc.) and random seeding were defined in it.
All uvm_transaction and uvm_component were derived from the uvm_object.
uvm_transaction
uvm_component
Components are quasi-static objects that exist throughout the simulation.
Every uvm_component is uniquely addressable via a hierarchical path name, e.g. 'env.agent.driver'.
The uvm_component also defines a phased test flow, that components follow during the course of the simulation. Each phase(build,
connect, run, etc.) is defined by a callback that is executed in precise order.
The uvm_component also defines configuration, reporting, transaction recording, and factory interfaces.
2) Write a simple UVM code which will print values using 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;
//Simple TestBench to create and randomize sequence item
//Payload Information //-------------------------------------------------------------------------
rand bit [7:0] wdata;
//Analysis Information module seq_item_tb;
bit [7:0] rdata;
//::TODO:: comment the any of the `uvm_field_* macro and observe the
output of methods. i.e o/p of print(), copy(), compare() etc
//instance
//Utility and Field macros, mem_seq_item seq_item;
`uvm_object_utils_begin(mem_seq_item)
`uvm_field_int(addr,UVM_ALL_ON)
`uvm_field_int(wr_en,UVM_ALL_ON) initial begin
`uvm_field_int(rd_en, 2UVM_ALL_ON) //create method
`uvm_field_int(wdata,UVM_ALL_ON)
`uvm_object_utils_end seq_item = mem_seq_item::type_id::create();
//Constructor
function new(string name = "mem_seq_item");
//randomizing the seq_item
super.new(name); seq_item.randomize();
endfunction
//constaint, to generate any one among write and read //printing the seq_item
constraint wr_rd_c { wr_en != rd_en; }; seq_item.print();
endclass end
endmodule
3) Explain with example how clone() method works.
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.
example:
class write_sequence extends uvm_sequence #(mem_seq_item);
....
....
endclass
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.
5) How UVM sequence is executed ?? Explain briefly.
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);
There are Methods, macros and pre-defined callbacks associated with uvm_sequence.
Users can define the methods(task or function) to pre-defined callbacks. these methods will get executed
automatically upon calling the start of the sequence.
These methods should not be called directly by the user.
Starting The Sequence:
Communication between the Sequence and driver involves below
Logic to generate and send the sequence_item will be written inside the body() method of the sequence. steps,
The handshake between the sequence, sequencer and driver to send the sequence_item is given below. 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.
Writing UVM Sequence
create() is skipped, rest all other steps are executed along with constraints defined in second
argument.
m_sequencer,
The m_sequencer handle contains the reference to the sequencer(default
sequencer) on which the sequence is running.
This is determined by,
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)
8) What is UVM Sequencer ??
The sequencer controls the flow of request and response sequence items between sequences and the driver.
Sequencer and driver uses TLM Interface to communicate transactions.
uvm_sequencer and uvm_driver base classes have seq_item_export and seq_item_port defined respectively.
User needs to connect them using TLM connect method.
Example:
driver.seq_item_port.connect(sequencer.seq_item_export);
A sequencer can be written by extending the uvm_sequencer parameterized with the seq_item type.
uvm_config_db::set and uvm_config_db::get methods are used to store and retrieve the information from the database respectively.
uvm config db set method
void uvm_config_db#(type T = int)::set(uvm_component cntxt, string inst_name, string field_name, T value);
Where,
T is the type of element being configured.
Type can be scalar objects, class handles, queues, lists, or even virtual interfaces).
cntxt is the hierarchical starting point of where the database entry is accessible.
inst_name is a hierarchical path that limits the accessibility of the database entry.
example:
top.env.agent.monitor
top.* - all of the scopes whose top-level component is top.
top.env.*.monitor - all of the scopes in env that end in the monitor;
field_name is the label used as a lookup for the database entry.
value is the value to be stored in the database.
value is the variable to which the value is to be retrieved from the database.
* The other fields are the same as in set method.
The method returns 1 if it is successful and 0 if there is no such resource of this type in the database.
Below example shows. Using the get method to get a virtual interface handle from a database and assigns it to mem_vif. If the get method fails, the fatal message will be displayed.
UVM_Driver Methods
get_next_item
This method blocks until a REQ sequence_item is available in the sequencer.
try_next_item
This is a non-blocking variant of the get_next_item() method. It will return a
null pointer if there is no REQ sequence_item available in the sequencer.
item_done
The non-blocking item_done() method completes the driver-sequencer
handshake and it should be called after a get_next_item() or a successful
try_next_item() call.
put
The put() method is non-blocking and is used to place an RSP
sequence_item in the sequencer.
// run phase
virtual task run_phase(uvm_phase phase);
forever begin
seq_item_port.get_next_item(req);
class mem_driver extends uvm_driver #(mem_seq_item); //respond_to_transfer(req);
drive();
// Virtual Interface seq_item_port.item_done();
virtual mem_if vif; end
endtask : run_phase
`uvm_component_utils(mem_driver) // drive
virtual task drive();
//uvm_analysis_port #(mem_seq_item) Drvr2Sb_port; req.print();
`DRIV_IF.wr_en <= 0;
// Constructor `DRIV_IF.rd_en <= 0;
function new (string name, uvm_component parent); @(posedge vif.DRIVER.clk);
super.new(name, parent); `DRIV_IF.addr <= req.addr;
endfunction : new if(req.wr_en) begin
` `DRIV_IF.wr_en <= req.wr_en;
`DRIV_IF.wdata <= req.wdata;
function void build_phase(uvm_phase phase); //$display("\tADDR = %0h \tWDATA = %0h",req.addr,trans.wdata);
super.build_phase(phase); @(posedge vif.DRIVER.clk);
if(! end
uvm_config_db#(virtual mem_if)::get(this, "", "vif", vif)) if(req.rd_en) begin
`uvm_fatal("NO_VIF",{"virtual interface must be set for: `DRIV_IF.rd_en <= req.rd_en;
",get_full_name(),".vif"}); @(posedge vif.DRIVER.clk);
endfunction: build_phase `DRIV_IF.rd_en <= 0;
@(posedge vif.DRIVER.clk);
req.rdata = `DRIV_IF.rdata;
// $display("\tADDR = %0h \tRDATA = %0h",trans.addr,`DRIV_IF.rdata);
end
$display("-----------------------------------------");
endtask : drive
endclass : mem_driver
12) What is UVM
class mem_monitor extends uvm_monitor;
monitor??
// Virtual Interface
The user-defined monitor is extended from virtual mem_if vif;
uvm_monitor, uvm_monitor is inherited by
uvm_component.
uvm_analysis_port #(mem_seq_item) item_collected_port;
A monitor is a passive entity that samples the DUT
signals through the virtual interface and converts the // Placeholder to capture transaction information.
signal level activity to the transaction level.
mem_seq_item trans_collected;
Monitor samples DUT signals but does not drive
them. `uvm_component_utils(mem_monitor)
The monitor should have an analysis port (TLM port)
and a virtual interface handle that points to DUT // new - constructor
signals function new (string name, uvm_component parent);
super.new(name, parent);
trans_collected = new();
item_collected_port = new("item_collected_port", this);
endfunction : new
function void build_phase(uvm_phase phase);
super.build_phase(phase);
if(!uvm_config_db#(virtual mem_if)::get(this, "", "vif", vif))
`uvm_fatal("NOVIF",{"virtual interface must be set for: ",get_full_name(),".vif"});
endfunction: build_phase
// run phase
virtual task run_phase(uvm_phase phase);
item_collected_port.write(trans_collected);
endtask : run_phase
endclass : mem_monitor
13) What is UVM Agent ?? What is Active agent and Passive
Agent??
a user-defined agent is extended from uvm_agent, uvm_agent is class mem_agent extends uvm_agent;
inherited by uvm_component. //declaring agent components
mem_driver driver;
An agent typically contains a driver, a sequencer, and a monitor. mem_sequencer sequencer;
mem_monitor monitor;
Agents can be configured either active or passive.
Active agent: // UVM automation macros for general components
`uvm_component_utils(mem_agent)
Active agents generate stimulus and drive to DUT. // constructor
function new (string name, uvm_component parent);
An active agent shall consists of all the three components driver, super.new(name, parent);
sequencer, and monitor. endfunction : new
Passive agent: // build_phase
function void build_phase(uvm_phase phase);
Passive agents sample DUT signals but do not drive them. super.build_phase(phase);
A passive agent consists of only the monitor. if(get_is_active() == UVM_ACTIVE) begin
driver = mem_driver::type_id::create("driver", this);
get_is_active() Method: sequencer = mem_sequencer::type_id::create("sequencer", this);
end
get_is_active() Returns UVM_ACTIVE if the agent is acting as an active monitor = mem_monitor::type_id::create("monitor", this);
agent and UVM_PASSIVE if the agent acting as a passive agent endfunction : build_phase
// connect_phase
function void connect_phase(uvm_phase phase);
if(get_is_active() == UVM_ACTIVE) begin
driver.seq_item_port.connect(sequencer.seq_item_export);
end
endfunction : connect_phase
endclass : mem_agent
14) What is the purpose of class mem_scoreboard extends uvm_scoreboard;
UVM scoreboard?? How it
`uvm_component_utils(mem_scoreboard)
can be use in code?? uvm_analysis_imp#(mem_seq_item, mem_scoreboard) item_collec
The user-defined scoreboard is extended from uvm_scoreboard, ted_export;
uvm_scoreboard is inherited by uvm_component.
the scoreboard will check the correctness of the DUT by comparing
the DUT output with the expected values. // new - constructor
the scoreboard will receive the transactions from the Monitors function new (string name, uvm_component parent);
implemented inside agents. super.new(name, parent);
Monitor and scoreboard will communicate via TLM ports and exports. endfunction : new
Scoreboard shall compare the DUT output values with,
function void build_phase(uvm_phase phase);
The golden reference values.
super.build_phase(phase);
The values Generated from the reference model. item_collected_export = new("item_collected_export", this);
endfunction: build_phase
// write
virtual function void write(mem_seq_item pkt);
$display("SCB:: Pkt recived");
pkt.print();
endfunction : write
endclass : mem_scoreboard