Sunday, 23 July 2017

Advantage of uvm_event over SV event and how to disable uvm_event using callback

The uvm_event#(type T = uvm_object) class is an extension of the abstract uvm_event_base class. The optional parameter T allows the user to define a data type which can be passed during an event trigger. uvm_event class is an abstract wrapper class around SystemVerilog event construct.

It provides additional services such as over traditional SystemVerilog event like,
1) pass data when event is triggered,
A traditional Systemverilog event does not have functionality to pass data when event is triggered. While uvm_event adds this functionality. So, you can pass the transaction class handle when some event is triggered.
By calling trigger task we can trigger the event and optionally give the data which we want to pass using uvm_event.
By calling wait_trigger()/wait_ptrigger() task of uvm_event we can wait for event to be trigger and then by calling get_trigger_data() function we can get data.
or we can directly use only one task wait_trigger_data()/wait_ptrigger_data() of uvm_event to wait for event to be triggered and to get the data.

2) setting callbacks,
We can also add callbacks whenever an event is triggered. This is done by registering a callback class with particular event.

3) maintaining the number of waiters,
We can get the number of processes waiting on the event (using get_num_waiters() function).

4) maintaining the time when event was triggered,
We can get the time that this event was last triggered (using get_trigger_time() function)

Like SystemVerilog event has trigger (@event) and persistent trigger (wait(event.triggered)) mode, uvm_event also has trigger (wait_trigger task) and persistent trigger (wait_ptrigger task).


Let's go through below example and see how we can transfer data using uvm_event and how we can disable uvm_event from triggering using callbacks of uvm_event.

-------------------------------------------------------------------
`include "uvm_macros.svh"
import uvm_pkg::*;
//-----------------------------------------------------------------------------
// Interface
//-----------------------------------------------------------------------------
interface my_interface(input logic clk);
bit valid;
logic [7 : 0] addr;
reg data_reg;
wire data;
assign data = data_reg;
endinterface : my_interface
typedef virtual my_interface my_vif;
//-----------------------------------------------------------------------------
// Sequence Item Class
//-----------------------------------------------------------------------------
class my_seq_item extends uvm_sequence_item;
rand logic [7:0] addr;
rand logic [7:0] data;
int unsigned pkt_id;
constraint addr_range_cn {
addr inside {[10:20]};
}
constraint data_range_cn {
data inside {[100:200]};
}
`uvm_object_utils_begin(my_seq_item)
`uvm_field_int(pkt_id, UVM_ALL_ON| UVM_DEC)
`uvm_field_int(addr, UVM_ALL_ON| UVM_HEX)
`uvm_field_int(data, UVM_ALL_ON| UVM_HEX)
`uvm_object_utils_end
function new(string name="my_seq_item");
super.new(name);
endfunction : new
virtual function string convert2string();
convert2string =
$sformatf("pkt_id:%0d, addr=0x%0h, data=0x%0h", pkt_id, addr, data);
endfunction : convert2string
endclass : my_seq_item
//-----------------------------------------------------------------------
// Sequencer Class
//-----------------------------------------------------------------------
typedef class my_agent;
class my_sequencer extends uvm_sequencer #(my_seq_item);
my_agent parent;
`uvm_component_utils (my_sequencer)
function new (string name="my_sequencer", uvm_component parent=null);
super.new(name, parent);
if(!$cast(this.parent, parent)) begin
`uvm_fatal(get_name(), $sformatf("Casting failed from"))
end
endfunction : new
endclass : my_sequencer
view raw uvm_event_1.sv hosted with ❤ by GitHub
-------------------------------------------------------------------

-------------------------------------------------------------------
//-----------------------------------------------------------------------
// Driver Class
//-----------------------------------------------------------------------
class my_driver extends uvm_driver #(my_seq_item);
my_agent parent;
uvm_event PKT_TX_CMPLT_EV;
uvm_event_pool my_event_pool;
`uvm_component_utils (my_driver)
function new (string name="my_driver", uvm_component parent=null);
super.new(name, parent);
if(!$cast(this.parent, parent)) begin
`uvm_fatal(get_name(), $sformatf("Casting failed from"))
end
endfunction : new
function void build_phase (uvm_phase phase);
super.build_phase(phase);
my_event_pool = uvm_event_pool::get_global_pool();
// Returns the item with the given key.
// If no item exists by that key, a new item is created with that key and returned.
if (!$cast(PKT_TX_CMPLT_EV, my_event_pool.get($sformatf("DRV_EVENT")))) begin
// OR, you can directly use add method
// PKT_TX_CMPLT_EV = my_event_pool.add($sformatf("DRV_EVENT"));
`uvm_fatal(get_name(), $sformatf("casting failed from uvm_object to uvm_event"))
end
endfunction : build_phase
task run_phase(uvm_phase phase);
forever begin
seq_item_port.get_next_item(req);
`uvm_info(get_name(),
$sformatf("After get_next_item, my_seq_item : %s", req.convert2string()), UVM_LOW)
// Item done is non-blocking
seq_item_port.item_done();
for (int unsigned i=0; i<8; i ++) begin
@(posedge parent.vif.clk);
if (i == 0) begin
parent.vif.valid <= 1'b1;
parent.vif.addr[7:0] <= req.addr[7:0];
end
parent.vif.data_reg <= req.data[i];
end
@(posedge parent.vif.clk);
parent.vif.valid <= 1'b0;
PKT_TX_CMPLT_EV.trigger(req);
end
endtask : run_phase
endclass : my_driver
//-----------------------------------------------------------------------
// Agent Class
//-----------------------------------------------------------------------
class my_agent extends uvm_agent;
my_sequencer sqr;
my_driver drv;
my_vif vif;
`uvm_component_utils_begin (my_agent)
`uvm_field_object(sqr, UVM_DEFAULT)
`uvm_field_object(drv, UVM_DEFAULT)
`uvm_component_utils_end
function new (string name="my_agent", uvm_component parent=null);
super.new(name, parent);
endfunction : new
function void build_phase (uvm_phase phase);
super.build_phase(phase);
if(!uvm_config_db#(my_vif) :: get(this, "", $sformatf("vif"), this.vif)) begin
`uvm_fatal(get_name(), $sformatf("Failed to get virtual interface"))
end
sqr = my_sequencer :: type_id :: create("sqr", this);
drv = my_driver :: type_id :: create("drv", this);
endfunction : build_phase
function void connect_phase (uvm_phase phase);
super.connect_phase(phase);
drv.seq_item_port.connect(sqr.seq_item_export);
endfunction : connect_phase
endclass : my_agent
//-----------------------------------------------------------------------
// UVM event callback class
//-----------------------------------------------------------------------
class my_event_callback extends uvm_event_callback;
`uvm_object_utils(my_event_callback)
function new(string name="my_event_callback");
super.new(name);
endfunction : new
// Called just before triggering the associated event.
// If this function returns 1, then the event will not trigger
// and the post-trigger callback is not called.
// This provides a way for a callback to prevent the event from triggering.
// e - is the uvm_event#(T=uvm_object) that is being triggered.
// data - is the optional data associated with the event trigger.
virtual function bit pre_trigger (uvm_event e, uvm_object data);
my_seq_item obj;
if(!$cast(obj, data)) begin
`uvm_fatal(get_name(), $sformatf("Casting failed"))
end
else begin
if(obj.pkt_id == 3) begin
`uvm_info(get_name(),
$sformatf("pre_trigger: discarding packet from event:%s, pkt:%s",
e.get_name(), obj.convert2string()), UVM_LOW)
return 1;
end
else begin
`uvm_info(get_name(),
$sformatf("pre_trigger: pkt:%s", obj.convert2string()), UVM_LOW)
return 0;
end
end
endfunction : pre_trigger
// Called after triggering the associated event.
// e - is the uvm_event#(T=uvm_object) that is being triggered.
// data - is the optional data associated with the event trigger.
virtual function void post_trigger (uvm_event e, uvm_object data);
my_seq_item obj;
if(!$cast(obj, data)) begin
`uvm_fatal(get_name(), $sformatf("Casting failed"))
end
else begin
`uvm_info(get_name(),
$sformatf("post_trigger: pkt:%s", obj.convert2string()), UVM_LOW)
end
endfunction : post_trigger
endclass : my_event_callback
view raw uvm_event_2.sv hosted with ❤ by GitHub
-------------------------------------------------------------------
As shown in above code, one uvm_event named PKT_TX_CMPLT_EV is taken in driver.
In build phase of driver we get global handle of event pool using static method get_event_pool of uvm_event_pool class.
Then PKT_TX_CMPLT_EV is added into associative array of uvm_event_pool using get/add method of uvm_event_pool. Note that here PKT_TX_CMPLT_EV event is added in associative array of uvm_event_pool using key (in string format) DRV_EVENT.
In run phase of driver when stimulus is driven, trigger method of uvm_event is called and transaction class is passed in argument of trigger method.

uvm_event also provides facility of callback when event is triggered.
In code my_event_callback (callback for uvm_event) class which extended from uvm_event_callback.
uvm_event_callback provides two hookups, 1) pre_trigger, 2) post_trigger.

pre_trigger:
Called just before triggering the associated event. If this function returns 1, then the event will not trigger and the post-trigger callback is not called.

post_trigger:
Called after triggering the associated event.

-------------------------------------------------------------------
//-----------------------------------------------------------------------
// Sequence Class
//-----------------------------------------------------------------------
class my_seq extends uvm_sequence #(my_seq_item);
uvm_event my_event;
int unsigned pkt_id;
my_event_callback my_event_cb;
`uvm_object_utils (my_seq)
`uvm_declare_p_sequencer(my_sequencer)
function new(string name="my_seq");
super.new(name);
endfunction : new
task get_event(input string event_key,
output uvm_event e);
uvm_event_pool my_event_pool;
my_event_pool = uvm_event_pool::get_global_pool();
e = my_event_pool.get(event_key);
endtask : get_event
task get_event_data(ref uvm_event e, ref my_seq_item my_item);
uvm_object item;
// This method calls wait_ptrigger followed by get_trigger_data (Recommanded)
`uvm_info(get_name(), $sformatf("before wait_ptrigger_data"), UVM_LOW)
e.wait_ptrigger_data(item);
`uvm_info(get_name(), $sformatf("after wait_ptrigger_data"), UVM_LOW)
if (item == null) begin
`uvm_error(get_name(),
$sformatf("Got NULL item from event"))
end
else begin
if ($cast(my_item, item)) begin
`uvm_info(get_name(),
$sformatf("Got the item from event %s", my_item.convert2string()), UVM_LOW)
end
else begin
`uvm_error(get_name(),
$sformatf("Casting failed from %s to %s", item.get_type_name(), my_item.get_type_name()))
end
end
endtask : get_event_data
task send_tr(input int unsigned pkt_id = 0);
my_seq_item req;
`uvm_create_on(req, p_sequencer)
if(!req.randomize()) begin
`uvm_fatal(get_name(), $sformatf("Randomization failed"))
end
req.pkt_id = pkt_id;
`uvm_info (get_name(),
$sformatf("After randomizating, my_seq_item : %s",
req.convert2string()), UVM_LOW)
// Sequence will comout from `uvm_send as item_done in driver is non blocking
`uvm_send(req)
endtask : send_tr
task body ();
my_seq_item my_data;
pkt_id ++;
send_tr(pkt_id);
get_event("DRV_EVENT", my_event);
get_event_data(my_event, my_data);
// do manipulation on my_data
my_data = null;
my_event_cb = my_event_callback :: type_id :: create ("my_event_cb");
my_event.add_callback(my_event_cb);
`uvm_info(get_name(),
$sformatf("%s event_callback is added for %s event",
my_event_cb.get_name(), my_event.get_name()), UVM_LOW)
#200;
pkt_id ++;
send_tr(pkt_id);
get_event("DRV_EVENT", my_event);
get_event_data(my_event, my_data);
// do manipulation on my_data
my_data = null;
#200;
pkt_id ++;
send_tr(pkt_id);
begin
fork
begin
get_event("DRV_EVENT", my_event);
get_event_data(my_event, my_data);
my_data = null;
end
begin
repeat (50) begin
@(posedge p_sequencer.parent.vif.clk);
end
`uvm_info(get_name(), $sformatf("event is not triggered"), UVM_LOW)
end
join_any
disable fork;
end
my_event.delete_callback(my_event_cb);
`uvm_info(get_name(),
$sformatf("%s event_callback is deleted for %s event",
my_event_cb.get_name(), my_event.get_name()), UVM_LOW)
#200;
pkt_id ++;
send_tr(pkt_id);
get_event("DRV_EVENT", my_event);
get_event_data(my_event, my_data);
endtask : body
endclass : my_seq
//-----------------------------------------------------------------------
// Test Class
//-----------------------------------------------------------------------
class my_test extends uvm_test;
my_agent agent;
my_vif vif;
`uvm_component_utils_begin (my_test)
`uvm_field_object(agent, UVM_DEFAULT)
`uvm_component_utils_end
function new (string name="my_test", uvm_component parent=null);
super.new(name, parent);
endfunction : new
function void build_phase (uvm_phase phase);
super.build_phase(phase);
if(!uvm_config_db#(my_vif) :: get(this, "", $sformatf("vif"), this.vif)) begin
`uvm_fatal(get_name(), $sformatf("Failed to get virtual interface"))
end
agent = my_agent::type_id::create("agent", this);
uvm_config_db#(my_vif) :: set(this, "agent", $sformatf("vif"), this.vif);
endfunction : build_phase
task run_phase(uvm_phase phase);
my_seq seq;
phase.raise_objection(this);
seq = my_seq::type_id::create ("seq");
//seq.set_starting_phase(phase);
#150;
seq.start(agent.sqr);
#150;
phase.drop_objection(this);
endtask : run_phase
endclass : my_test
// Top module
module top();
bit clk;
my_interface intf(clk);
initial begin
uvm_config_db#(my_vif) :: set(uvm_root::get(), "uvm_test_top", "vif", intf);
forever begin
#5 clk = ~clk;
end
end
initial begin
run_test("my_test");
end
endmodule : top
view raw uvm_event_3.sv hosted with ❤ by GitHub
-------------------------------------------------------------------
As shown in above code, in sequence, event callback is registered with associated event using add_callback method of uvm_event and also deleted using delete_callback method of uvm_event

-------------------------------------------------------------------
Output:
UVM_INFO @ 0: reporter [RNTST] Running test my_test...
UVM_INFO uvm_event_3.sv(55) @ 150: uvm_test_top.agent.sqr@@seq [seq] After randomizating, my_seq_item : pkt_id:1, addr=0x13, data=0x8c
UVM_INFO uvm_event_2.sv(33) @ 150: uvm_test_top.agent.drv [drv] After get_next_item, my_seq_item : pkt_id:1, addr=0x13, data=0x8c
UVM_INFO uvm_event_3.sv(26) @ 150: uvm_test_top.agent.sqr@@seq [seq] before wait_ptrigger_data
UVM_INFO uvm_event_3.sv(28) @ 235: uvm_test_top.agent.sqr@@seq [seq] after wait_ptrigger_data
UVM_INFO uvm_event_3.sv(37) @ 235: uvm_test_top.agent.sqr@@seq [seq] Got the item from event pkt_id:1, addr=0x13, data=0x8c
UVM_INFO uvm_event_3.sv(74) @ 235: uvm_test_top.agent.sqr@@seq [seq] my_event_cb event_callback is added for DRV_EVENT event
UVM_INFO uvm_event_3.sv(55) @ 435: uvm_test_top.agent.sqr@@seq [seq] After randomizating, my_seq_item : pkt_id:2, addr=0xd, data=0x6e
UVM_INFO uvm_event_2.sv(33) @ 435: uvm_test_top.agent.drv [drv] After get_next_item, my_seq_item : pkt_id:2, addr=0xd, data=0x6e
UVM_INFO uvm_event_3.sv(26) @ 435: uvm_test_top.agent.sqr@@seq [seq] before wait_ptrigger_data
UVM_INFO uvm_event_2.sv(111) @ 525: reporter [my_event_cb] pre_trigger: pkt:pkt_id:2, addr=0xd, data=0x6e
UVM_INFO uvm_event_2.sv(127) @ 525: reporter [my_event_cb] post_trigger: pkt:pkt_id:2, addr=0xd, data=0x6e
UVM_INFO uvm_event_3.sv(28) @ 525: uvm_test_top.agent.sqr@@seq [seq] after wait_ptrigger_data
UVM_INFO uvm_event_3.sv(37) @ 525: uvm_test_top.agent.sqr@@seq [seq] Got the item from event pkt_id:2, addr=0xd, data=0x6e
UVM_INFO uvm_event_3.sv(55) @ 725: uvm_test_top.agent.sqr@@seq [seq] After randomizating, my_seq_item : pkt_id:3, addr=0x12, data=0xa3
UVM_INFO uvm_event_2.sv(33) @ 725: uvm_test_top.agent.drv [drv] After get_next_item, my_seq_item : pkt_id:3, addr=0x12, data=0xa3
UVM_INFO uvm_event_3.sv(26) @ 725: uvm_test_top.agent.sqr@@seq [seq] before wait_ptrigger_data
UVM_INFO uvm_event_2.sv(106) @ 815: reporter [my_event_cb] pre_trigger: discarding packet from event:DRV_EVENT, pkt:pkt_id:3, addr=0x12, data=0xa3
UVM_INFO uvm_event_3.sv(98) @ 1225: uvm_test_top.agent.sqr@@seq [seq] event is not triggered
UVM_INFO uvm_event_3.sv(107) @ 1225: uvm_test_top.agent.sqr@@seq [seq] my_event_cb event_callback is deleted for DRV_EVENT event
UVM_INFO uvm_event_3.sv(55) @ 1425: uvm_test_top.agent.sqr@@seq [seq] After randomizating, my_seq_item : pkt_id:4, addr=0x14, data=0xa5
UVM_INFO uvm_event_2.sv(33) @ 1425: uvm_test_top.agent.drv [drv] After get_next_item, my_seq_item : pkt_id:4, addr=0x14, data=0xa5
UVM_INFO uvm_event_3.sv(26) @ 1425: uvm_test_top.agent.sqr@@seq [seq] before wait_ptrigger_data
UVM_INFO uvm_event_3.sv(28) @ 1515: uvm_test_top.agent.sqr@@seq [seq] after wait_ptrigger_data
UVM_INFO uvm_event_3.sv(37) @ 1515: uvm_test_top.agent.sqr@@seq [seq] Got the item from event pkt_id:4, addr=0x14, data=0xa5
UVM_INFO uvm_objection.svh(1271) @ 1665: reporter [TEST_DONE] 'run' phase is ready to proceed to the 'extract' phase
UVM_INFO uvm_report_server.svh(847) @ 1665: reporter [UVM/REPORT/SERVER]
-------------------------------------------------------------------


FAQ:
Through uvm_event we can pass data(transaction class) when event is triggered, then why do we need TLM/Analysis ports in UVM?
Ans:
If event is triggered again before receiver gets the data then data will be overwritten.

Reset Testing using Phase Jump in UVM

Reset testing is a crucial element of functional sign-off for any chip. The architectural components of the entire verification environment need to be correctly synchronized to be made aware of the reset condition. Scoreboards, drivers and monitors need to be tidied up, and the complex stimulus generation needs to be killed gracefully.

As we know, in UVM, there are twelve phases parallel to run_phase:
  1. pre_reset_phase(), reset_phase(), post_reset_phase(): Phases involved in reset activity.
  2. pre_configure_phase(), configure_phase(), post_configure_phase(): Phases involved in configuring DUT.
  3. pre_main_phase(), main_phase(), post_main_phase(): Phases involved in driving main stimulus to the DUT.
  4. pre_shutdown_phase(), shutdown_phase and post_shutdown_phase(): Phases involved in settling down the DUT after driving main stimulus.

Using these phases instead of using only run_phase, we can achieve synchronization between all components of verification environment also easily test reset functionality.

In reset testing, user drives random sequence to the DUT and in between data transmission, reset is applied followed by driving restart sequence. We will see how the reset functionality could be easily tested using phases parallel to run_phase and phase jump feature of UVM.

Let’s go through complete example to understand how it is achieved using UVM phases and Phase jump feature.
----------------------------------------------------------------------
`timescale 1ns/1ps
`include "uvm_macros.svh"
import uvm_pkg :: *;
`define ADDR_WIDTH_IN_BITS 8
`define DATA_WIDTH_IN_BITS 8
//-----------------------------------------------------------------------------
// Interface
//-----------------------------------------------------------------------------
interface my_interface(input logic clk,
input logic rstn /* Active Low Reset */);
bit valid;
logic [`ADDR_WIDTH_IN_BITS - 1 : 0] start_addr;
reg [`DATA_WIDTH_IN_BITS - 1 : 0] data_reg;
wire [`DATA_WIDTH_IN_BITS - 1 : 0] data;
int unsigned length_in_bytes;
assign data = data_reg;
endinterface : my_interface
typedef virtual my_interface my_vif;
typedef class my_agent;
//-----------------------------------------------------------------------------
// Agent Configuration Class
//-----------------------------------------------------------------------------
class my_agent_cfg extends uvm_object;
// virtual interface
my_vif vif;
// The length of time, in ps, that reset will stay active
int unsigned reset_time_ps = 10;
// Minimum length of payload data
int unsigned min_payload_length = 5;
// Maximum length of payload data
int unsigned max_payload_length = 100;
uvm_active_passive_enum is_active = UVM_ACTIVE;
`uvm_object_utils_begin(my_agent_cfg)
`uvm_field_enum(uvm_active_passive_enum, is_active, UVM_DEFAULT)
`uvm_field_int(reset_time_ps, UVM_DEFAULT | UVM_DEC)
`uvm_field_int(min_payload_length, UVM_DEFAULT | UVM_DEC)
`uvm_field_int(max_payload_length, UVM_DEFAULT | UVM_DEC)
`uvm_object_utils_end
function new(string name="my_agent_cfg");
super.new(name);
endfunction : new
function void is_valid();
if (max_payload_length < min_payload_length) begin
`uvm_error(get_name(),
$sformatf("Value of max_payload_length is shall be greater or equal to value of min_payload_length, configured values of max_payload_length:%0d, min_payload_length:%0d",
max_payload_length, min_payload_length))
end
if (reset_time_ps <= 0) begin
`uvm_error(get_name(), $sformatf("reset_time_ps shall be greater than 0"))
end
endfunction : is_valid
endclass : my_agent_cfg
//-----------------------------------------------------------------------------
// Sequence Item Class
//-----------------------------------------------------------------------------
class my_seq_item extends uvm_sequence_item;
// Random varialbes
rand logic [`ADDR_WIDTH_IN_BITS - 1 : 0] start_addr;
rand logic [`DATA_WIDTH_IN_BITS - 1 : 0] data[];
rand int unsigned payload_length;
// Non random variables
my_agent_cfg cfg;
`uvm_object_utils_begin(my_seq_item)
`uvm_field_int (start_addr, UVM_DEFAULT | UVM_HEX)
`uvm_field_int (payload_length, UVM_DEFAULT | UVM_DEC)
`uvm_field_array_int (data, UVM_DEFAULT | UVM_HEX)
`uvm_object_utils_end
constraint length_cn {
payload_length inside {[cfg.min_payload_length : cfg.max_payload_length]};
data.size == payload_length;
}
constraint order_cn {
solve payload_length before data;
}
function new(string name="my_seq_item");
super.new(name);
endfunction : new
function string convert2string();
convert2string = $sformatf("start_addr:%0h, payload_length:%0d, data[0]:%0h, data[%0d]:%0h",
start_addr, payload_length, data[0], payload_length-1, data[payload_length-1]);
endfunction : convert2string
endclass : my_seq_item
view raw phase_jump_1.sv hosted with ❤ by GitHub
----------------------------------------------------------------------
----------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Sequencer Class
//-----------------------------------------------------------------------------
class my_sequencer extends uvm_sequencer#(my_seq_item);
my_agent parent;
`uvm_component_utils(my_sequencer)
function new(string name="my_sequencer", uvm_component parent=null);
super.new(name, parent);
if (parent == null) begin
`uvm_fatal(get_name(),
$sformatf("NULL handle is provided in parent argument of constructor"))
end
else begin
if (!$cast(this.parent, parent)) begin
`uvm_fatal(get_name(),
$sformatf("Casting Failed, provide parent of valid type"))
end
end
endfunction : new
endclass : my_sequencer
//-----------------------------------------------------------------------------
// Driver Class
//-----------------------------------------------------------------------------
class my_driver extends uvm_driver#(my_seq_item);
my_agent parent;
event reset_driver;
`uvm_component_utils_begin(my_driver)
`uvm_component_utils_end
function new(string name="my_driver", uvm_component parent=null);
super.new(name, parent);
if (parent == null) begin
`uvm_fatal(get_name(),
$sformatf("NULL handle is provided in parent argument of constructor"))
end
else begin
if (!$cast(this.parent, parent)) begin
`uvm_fatal(get_name(),
$sformatf("Casting Failed, provide parent of valid type"))
end
end
endfunction : new
function void build_phase (uvm_phase phase);
super.build_phase(phase);
endfunction : build_phase
task pre_reset_phase(uvm_phase phase);
// De-assert valid signal after enterring into pre_reset_phase
parent.cfg.vif.valid <= 1'b0;
endtask : pre_reset_phase
// Wait for Reset to assert and
// Do something you want to do after reset is asserted
task reset_phase(uvm_phase phase);
phase.raise_objection(this);
wait (parent.cfg.vif.rstn == 1'b0);
`uvm_info(get_name(),
$sformatf("after waiting for rstn to be asserted"), UVM_LOW)
phase.drop_objection(this);
endtask : reset_phase
// Wait for Reset to de-assert
task post_reset_phase(uvm_phase phase);
phase.raise_objection(this);
wait (parent.cfg.vif.rstn == 1'b1);
`uvm_info(get_name(),
$sformatf("after waiting for rstn to be deasserted"), UVM_LOW)
phase.drop_objection(this);
endtask : post_reset_phase
// Drive stimulus on interface and in parallel
// wait for reset to be asserted
task main_phase(uvm_phase phase);
`uvm_info(get_name(), $sformatf("enter in main_phase"), UVM_LOW)
forever begin
fork
begin
drive();
end
begin
wait (reset_driver.triggered);
`uvm_info(get_name(),
$sformatf("after wait for reset_driver event to be triggered"), UVM_LOW)
end
join_any
disable fork;
end
endtask : main_phase
task drive();
my_seq_item tr;
`uvm_info(get_name(), $sformatf("Before get_next_item"), UVM_LOW)
seq_item_port.get_next_item(tr);
`uvm_info(get_name(),
$sformatf("After get_next_item tr:\n%s", tr.convert2string()), UVM_LOW)
@(posedge parent.cfg.vif.clk);
parent.cfg.vif.valid <= 1'b1;
parent.cfg.vif.length_in_bytes <= tr.payload_length;
parent.cfg.vif.start_addr <= tr.start_addr;
for (int unsigned i=0; i<tr.payload_length; i ++) begin
parent.cfg.vif.data_reg <= tr.data[i];
@(posedge parent.cfg.vif.clk);
if (i == tr.payload_length - 1) begin
parent.cfg.vif.valid <= 1'b0;
end
end
seq_item_port.item_done(tr);
`uvm_info(get_name(), $sformatf("item_done is called"), UVM_LOW)
endtask : drive
endclass : my_driver
//-----------------------------------------------------------------------------
// Monitor Class
//-----------------------------------------------------------------------------
class my_monitor extends uvm_monitor;
my_agent parent;
`uvm_component_utils_begin(my_monitor)
`uvm_component_utils_end
function new(string name="my_monitor", uvm_component parent=null);
super.new(name, parent);
if (parent == null) begin
`uvm_fatal(get_name(), $sformatf("NULL handle is provided in parent argument of constructor"))
end
else begin
if (!$cast(this.parent, parent)) begin
`uvm_fatal(get_name(), $sformatf("Casting Failed, provide parent of valid type"))
end
end
endfunction : new
function void build_phase (uvm_phase phase);
super.build_phase(phase);
endfunction : build_phase
task pre_reset_phase(uvm_phase phase);
endtask : pre_reset_phase
// Wait for reset to de-assert
task reset_phase(uvm_phase phase);
@(posedge parent.cfg.vif.rstn);
`uvm_info(get_name(), $sformatf("rstn deassertion detected"), UVM_LOW)
endtask : reset_phase
// Sample interface signals and form packet and
// in parallel wait for reset to be asserted
task main_phase(uvm_phase phase);
my_seq_item tr;
forever begin
fork
begin
receive(tr);
end
begin
@(negedge parent.cfg.vif.rstn);
`uvm_info(get_name(), $sformatf("rstn is asserted during reception of data"), UVM_LOW)
`uvm_info(get_name(), $sformatf(" tr:\n%s", tr.convert2string()), UVM_LOW)
end
join_any
disable fork;
// put tr into analysis port
tr = null;
end
endtask : main_phase
task receive(ref my_seq_item tr);
@(negedge parent.cfg.vif.clk);
if (parent.cfg.vif.valid == 1'b1) begin
`uvm_info(get_name(), $sformatf("valid is detected"), UVM_LOW)
tr = new("tr");
tr.payload_length = parent.cfg.vif.length_in_bytes;
tr.start_addr = parent.cfg.vif.start_addr;
tr.data = new[tr.payload_length];
for (int unsigned i=0; i<tr.payload_length; i ++) begin
tr.data[i] = parent.cfg.vif.data;
if (i != tr.payload_length - 1) begin
@(negedge parent.cfg.vif.clk);
end
end
`uvm_info(get_name(), $sformatf("Complete tr:\n%s", tr.convert2string()), UVM_LOW)
end
endtask : receive
endclass : my_monitor
//-----------------------------------------------------------------------------
// Agent Class
//-----------------------------------------------------------------------------
class my_agent extends uvm_agent;
my_agent_cfg cfg;
my_sequencer sqr;
my_driver drv;
my_monitor mon;
`uvm_component_utils_begin(my_agent)
`uvm_field_object(cfg, UVM_DEFAULT)
`uvm_field_object(sqr, UVM_DEFAULT)
`uvm_field_object(drv, UVM_DEFAULT)
`uvm_field_object(mon, UVM_DEFAULT)
`uvm_component_utils_end
function new(string name="my_agent", uvm_component parent=null);
super.new(name, parent);
endfunction : new
function void build_phase (uvm_phase phase);
super.build_phase(phase);
if (!uvm_config_db#(my_agent_cfg) :: get(this, "", "cfg", this.cfg) &&
this.cfg != null) begin
`uvm_fatal(get_name(), $sformatf("configuration object of type:%s is not set for this instance", this.cfg.get_type()))
end
if (!uvm_config_db#(my_vif) :: get(this, "", "vif", this.cfg.vif)) begin
`uvm_fatal(get_name(), $sformatf("Interface is not passed to agent"))
end
cfg.is_valid();
if (cfg.is_active == UVM_ACTIVE) begin
sqr = my_sequencer :: type_id :: create ("sqr", this);
drv = my_driver :: type_id :: create ("drv", this);
end
mon = my_monitor :: type_id :: create ("mon", this);
endfunction : build_phase
function void connect_phase (uvm_phase phase);
super.connect_phase(phase);
if (cfg.is_active == UVM_ACTIVE) begin
drv.seq_item_port.connect(sqr.seq_item_export);
end
endfunction : connect_phase
task pre_reset_phase(uvm_phase phase);
if(cfg.is_active == UVM_ACTIVE) begin
// Tells the sequencer to kill all sequences and child sequences currently
// operating on the sequencer, and remove all requests, locks and responses
// that are currently queued.
// This essentially resets the sequencer to an idle state.
sqr.stop_sequences();
// Indicates Driver that reset is asserted
->drv.reset_driver;
`uvm_info(get_name(), $sformatf("reset_driver event is triggered"), UVM_LOW)
end
endtask : pre_reset_phase
endclass : my_agent
view raw phase_jump_2.sv hosted with ❤ by GitHub
----------------------------------------------------------------------
As shown in above code,
Driver is waiting for Reset to be asserted (in reset_phase) by raising objection and then perform action which user want on assertion of Reset signal and at last drop the objection and move to post_reset_phase. In post_reset_phase driver is waiting for Reset to de-assert and then move to main_phase. In main_phase driver drives stimulus on interface and in parallel to that wait for indication from agent about assertion of reset.

Components such as monitors that attach to signaling interfaces should be designed to be phase independent because they are intended to mimic other real devices in the system. These components should watch the reset signal associated with their interface and reset themselves accordingly.

You may find that the driver, the sequencer, and their currently running sequences will squawk with errors if they are not synchronized properly. UVM requires that the sequencer first stop its sequences and then the driver must be certain to not call item_done on any outstanding sequences.  However, the order that a simulator executes threads in the various components is indeterminate. To synchronize these operations, the containing agent has a pre_reset_phase such as the above.

----------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Sequence Class
//-----------------------------------------------------------------------------
class my_base_sequence extends uvm_sequence#(my_seq_item);
int unsigned payload_length;
`uvm_object_utils(my_base_sequence)
`uvm_declare_p_sequencer(my_sequencer)
function new(string name="my_base_sequence");
super.new(name);
endfunction : new
task body();
endtask : body
endclass : my_base_sequence
class my_sequence extends my_base_sequence;
`uvm_object_utils(my_sequence)
function new(string name="my_sequence");
super.new(name);
endfunction : new
task body();
my_seq_item req;
my_seq_item rsp;
`uvm_create(req)
req.cfg = p_sequencer.parent.cfg;
if (!req.randomize() with {payload_length == local::payload_length;}) begin
`uvm_fatal(get_name(), $sformatf("Randomization failed"))
end
else begin
`uvm_info(get_name(),
$sformatf("After randomization tr in seq:\n%s", req.convert2string()), UVM_LOW)
end
`uvm_send(req)
get_response(rsp);
`uvm_info(get_name(),
$sformatf("Got response from driver"), UVM_LOW)
endtask : body
endclass : my_sequence
//-----------------------------------------------------------------------------
// Test Class
//-----------------------------------------------------------------------------
class my_test extends uvm_test;
my_vif act_vif;
my_vif psv_vif;
my_agent act_agent;
my_agent psv_agent;
my_agent_cfg act_agent_cfg;
my_agent_cfg psv_agent_cfg;
// The number of times the test has run so far
int unsigned run_count;
`uvm_component_utils_begin(my_test)
`uvm_field_int(run_count, UVM_DEFAULT | UVM_DEC)
`uvm_field_object(act_agent, UVM_DEFAULT)
`uvm_field_object(act_agent_cfg, UVM_DEFAULT)
`uvm_field_object(psv_agent, UVM_DEFAULT)
`uvm_field_object(psv_agent_cfg, UVM_DEFAULT)
`uvm_component_utils_end
function new(string name="my_test", uvm_component parent=null);
super.new(name, parent);
endfunction : new
function void build_phase (uvm_phase phase);
super.build_phase(phase);
if (!uvm_config_db#(my_vif) :: get(this, "", $sformatf("act_vif"), act_vif)) begin
`uvm_fatal(get_name(), $sformatf("act_vif is not set for this class from top module"))
end
if (!uvm_config_db#(my_vif) :: get(this, "", $sformatf("psv_vif"), psv_vif)) begin
`uvm_fatal(get_name(), $sformatf("psv_vif is not set for this class from top module"))
end
act_agent = my_agent :: type_id :: create ($sformatf("act_agent"), this);
psv_agent = my_agent :: type_id :: create ($sformatf("psv_agent"), this);
act_agent_cfg = my_agent_cfg :: type_id :: create ($sformatf("act_agent_cfg"), this);
act_agent_cfg.is_active = UVM_ACTIVE;
psv_agent_cfg = my_agent_cfg :: type_id :: create ($sformatf("psv_agent_cfg"), this);
psv_agent_cfg.is_active = UVM_PASSIVE;
uvm_config_db#(my_vif) :: set(this, $sformatf("act_agent"), "vif", act_vif);
uvm_config_db#(my_vif) :: set(this, $sformatf("psv_agent"), "vif", psv_vif);
uvm_config_db#(my_agent_cfg) :: set(this, $sformatf("act_agent"), "cfg", act_agent_cfg);
uvm_config_db#(my_agent_cfg) :: set(this, $sformatf("psv_agent"), "cfg", psv_agent_cfg);
endfunction : build_phase
task main_phase (uvm_phase phase);
phase.raise_objection(this);
if (run_count == 0) begin
fork
begin
// Run sequence
my_sequence seq;
seq = my_sequence :: type_id :: create ("seq");
seq.payload_length = 50;
seq.start(act_agent.sqr);
`uvm_info(get_name(), $sformatf("finished first seq"), UVM_LOW)
#1000;
`uvm_info(get_name(),
$sformatf("finished thread parallel to waiting for rstn"), UVM_LOW)
end
begin
@(negedge act_vif.rstn);
`uvm_info(get_name(), $sformatf("rstn assertion detected"), UVM_LOW)
end
join_any
disable fork;
end
else if (run_count == 1) begin
// Run sequence
my_sequence seq;
seq = my_sequence :: type_id :: create ("seq");
seq.payload_length = 40;
seq.start(act_agent.sqr);
#100;
end
if (run_count == 0) begin
phase.get_objection().set_report_severity_id_override(UVM_WARNING, "OBJTN_CLEAR", UVM_INFO);
phase.jump(uvm_pre_reset_phase::get());
end
else begin
phase.drop_objection(this);
end
run_count ++;
endtask : main_phase
endclass : my_test
//-----------------------------------------------------------------------------
// TB TOP module
//-----------------------------------------------------------------------------
module top();
bit clk;
logic rstn;
my_interface act_if (clk, rstn);
my_interface psv_if (clk, rstn);
initial begin
run_test("my_test");
end
assign psv_if.length_in_bytes = act_if.length_in_bytes;
assign psv_if.start_addr = act_if.start_addr;
assign psv_if.data_reg = act_if.data_reg;
assign psv_if.valid = act_if.valid;
initial begin
uvm_config_db#(virtual my_interface) :: set(uvm_root::get(), "uvm_test_top", $sformatf("act_vif"), act_if);
uvm_config_db#(my_vif) :: set(uvm_root::get(), "uvm_test_top", $sformatf("psv_vif"), psv_if);
end
initial begin
forever begin
#5 clk = !clk;
end
end
initial begin
#7 rstn = 1'b1;
# 30 rstn = 1'b0;
#100 rstn = 1'b1;
#270 rstn = 1'b0;
#70 rstn = 1'b1;
#1000 $finish;
end
endmodule : top
view raw phase_jump_3.sv hosted with ❤ by GitHub
----------------------------------------------------------------------
When test enters main_phase initially first time at that time run_count is 0, so on assertion of Reset test will do phase.jump method and move to pre_reset_phase from main_phase.
When test enters main_phase second time at that time run_count is 1, so at that time it will not do phase jumping.

Note: It is not good to use a phase jumping feature in case any of the components of testbench don’t use the sub-phases of UVM.

Reference:

Saturday, 22 July 2017

Extend run_phase using set_drain_time and all_dropped callback after all objection drops

It is more often that two or more components in verification environment are not in sync with each other. And there may be a case where driver/transmitter finish it's job first and call item_done. After item_done is called from driver and if there is no action pending in sequence then start method of sequence finishes and objection is also dropped.
But we want that simulation (more precisely we can say run_phase) should extend to some more time after all objection are dropped, so that other components which are late with respect to driver can finish it's job. We can achieve this by using set_drain_time in UVM.

Let's go through example and see how we can achieve this using set_drain_time in UVM.
--------------------------------------------------------------------
`timescale 1ns/1ns
`include "uvm.sv"
import uvm_pkg::*;
`include "uvm_macros.svh"
// In this example, a drain time of 10 is set on the component.
// The component then forks 4 processes which consume different
// amounts of time. When the last process is done (time 85),
// the drain time takes effect. The test is completed at time 95.
class my_agent extends uvm_agent;
`uvm_component_utils(my_agent)
function new (string name="my_agent", uvm_component parent=null);
super.new(name, parent);
endfunction : new
virtual task run_phase(uvm_phase phase);
// Run a bunch of processes in parallel
fork
doit(phase, 85);
doit(phase, 55);
join
endtask : run_phase
// A simple task that consumes some time.
task doit (uvm_phase phase, time delay);
static int s_inst = 0;
int inst = s_inst++;
//Raise an objection before starting the activity
phase.raise_objection(this);
uvm_report_info(get_name(), $sformatf("Starting doit (%0d) with delay %0t", inst, delay), UVM_NONE);
#delay;
uvm_report_info(get_name(), $sformatf("Ending doit (%0d)", inst), UVM_NONE);
//Drop the objection when done
phase.drop_objection(this);
endtask : doit
endclass : my_agent
class my_env extends uvm_test;
my_agent agent;
`uvm_component_utils(my_env)
function new (string name="my_env", uvm_component parent=null);
super.new(name, parent);
endfunction : new
function void build_phase (uvm_phase phase);
super.build_phase(phase);
agent = my_agent :: type_id :: create ("agent", this);
endfunction : build_phase
virtual task run_phase(uvm_phase phase);
// Run a bunch of processes in parallel
fork
doit(phase, 35);
doit(phase, 60);
join
endtask : run_phase
// A simple task that consumes some time.
task doit (uvm_phase phase, time delay);
static int s_inst = 0;
int inst = s_inst++;
//Raise an objection before starting the activity
phase.raise_objection(this);
uvm_report_info(get_name(), $sformatf("Starting doit (%0d) with delay %0t", inst, delay), UVM_NONE);
#delay;
uvm_report_info(get_name(), $sformatf("Ending doit (%0d)", inst), UVM_NONE);
//Drop the objection when done
phase.drop_objection(this);
endtask : doit
endclass : my_env
class my_test extends uvm_test;
my_env env;
`uvm_component_utils(my_test)
function new (string name, uvm_component parent);
super.new(name, parent);
endfunction : new
function void build_phase (uvm_phase phase);
super.build_phase(phase);
env = my_env :: type_id::create("env", this);
endfunction : build_phase
virtual task run_phase(uvm_phase phase);
// Set a drain time on the objection if needed
`uvm_info("drain", "Setting drain time of 10", UVM_NONE)
// uvm-1.1d or earlier (depricated in uvm-1.2
//uvm_test_done.set_drain_time(this,10);
// uvm-1.2
phase.phase_done.set_drain_time(this,10);
// Run a bunch of processes in parallel
fork
doit(phase, 25);
doit(phase, 50);
join
endtask : run_phase
// A simple task that consumes some time.
task doit (uvm_phase phase, time delay);
static int s_inst = 0;
int inst = s_inst++;
//Raise an objection before starting the activity
phase.raise_objection(
this, // uvm_object obj
"", // string description=""
1 // int count=1, default value = 1 which increment objection count by 1
);
uvm_report_info(get_name(), $sformatf("Starting doit (%0d) with delay %0t", inst, delay), UVM_NONE);
#delay;
uvm_report_info(get_name(), $sformatf("Ending doit (%0d)", inst), UVM_NONE);
//Drop the objection when done
phase.drop_objection(
this, // uvm_object obj
"", // string description=""
1 // int count=1, default value = 1 which decrement objection count by 1
);
endtask : doit
endclass : my_test
module top;
initial begin
run_test("my_test");
end
endmodule : top
// Output:
// UVM_INFO @ 0: reporter [RNTST] Running test my_test...
// UVM_INFO top.sv(98) @ 0: uvm_test_top [drain] Setting drain time of 10
// UVM_INFO @ 0: uvm_test_top [uvm_test_top] Starting doit (0) with delay 25
// UVM_INFO @ 0: uvm_test_top [uvm_test_top] Starting doit (1) with delay 50
// UVM_INFO @ 0: uvm_test_top.env [env] Starting doit (0) with delay 35
// UVM_INFO @ 0: uvm_test_top.env [env] Starting doit (1) with delay 60
// UVM_INFO @ 0: uvm_test_top.env.agent [agent] Starting doit (0) with delay 85
// UVM_INFO @ 0: uvm_test_top.env.agent [agent] Starting doit (1) with delay 55
// UVM_INFO @ 25: uvm_test_top [uvm_test_top] Ending doit (0)
// UVM_INFO @ 35: uvm_test_top.env [env] Ending doit (0)
// UVM_INFO @ 50: uvm_test_top [uvm_test_top] Ending doit (1)
// UVM_INFO @ 55: uvm_test_top.env.agent [agent] Ending doit (1)
// UVM_INFO @ 60: uvm_test_top.env [env] Ending doit (1)
// UVM_INFO @ 85: uvm_test_top.env.agent [agent] Ending doit (0)
// UVM_INFO /home/shahs/gotcha/uvm/uvm-1.2/src/base/uvm_objection.svh(1271) @ 95: reporter [TEST_DONE] 'run' phase is ready to proceed to the 'extract' phase
// UVM_INFO /home/shahs/gotcha/uvm/uvm-1.2/src/base/uvm_report_server.svh(847) @ 95: reporter [UVM/REPORT/SERVER]

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


UVM also provides callback hookups when every objection raises and drops and when all objection drops.
Let's go through example and see how it works,

--------------------------------------------------------------------
`timescale 1ns/1ns
`include "uvm.sv"
import uvm_pkg::*;
`include "uvm_macros.svh"
// In this example, a drain time of 10 is set on the component.
// The component then forks 4 processes which consume different
// amounts of time. When the last process is done (time 85),
// the drain time takes effect. The test is completed at time 95.
// After drain time finished, all_dopped callback takes effect
// which takes 50 timeunit and it is completed at time (at time 145)
class my_agent extends uvm_agent;
`uvm_component_utils(my_agent)
function new (string name="my_agent", uvm_component parent=null);
super.new(name, parent);
endfunction : new
virtual task run_phase(uvm_phase phase);
// Run a bunch of processes in parallel
fork
doit(phase, 85);
doit(phase, 55);
join
endtask : run_phase
// A simple task that consumes some time.
task doit (uvm_phase phase, time delay);
static int s_inst = 0;
int inst = s_inst++;
//Raise an objection before starting the activity
phase.raise_objection(this);
uvm_report_info(get_name(), $sformatf("Starting doit (%0d) with delay %0t", inst, delay), UVM_NONE);
#delay;
uvm_report_info(get_name(), $sformatf("Ending doit (%0d)", inst), UVM_NONE);
//Drop the objection when done
phase.drop_objection(this);
endtask : doit
endclass : my_agent
class my_env extends uvm_test;
my_agent agent;
`uvm_component_utils(my_env)
function new (string name="my_env", uvm_component parent=null);
super.new(name, parent);
endfunction : new
function void build_phase (uvm_phase phase);
super.build_phase(phase);
agent = my_agent :: type_id :: create ("agent", this);
endfunction : build_phase
virtual task run_phase(uvm_phase phase);
// Run a bunch of processes in parallel
fork
doit(phase, 35);
doit(phase, 60);
join
endtask : run_phase
// A simple task that consumes some time.
task doit (uvm_phase phase, time delay);
static int s_inst = 0;
int inst = s_inst++;
//Raise an objection before starting the activity
phase.raise_objection(this);
uvm_report_info(get_name(), $sformatf("Starting doit (%0d) with delay %0t", inst, delay), UVM_NONE);
#delay;
uvm_report_info(get_name(), $sformatf("Ending doit (%0d)", inst), UVM_NONE);
//Drop the objection when done
phase.drop_objection(this);
endtask : doit
endclass : my_env
class my_test extends uvm_test;
my_env env;
`uvm_component_utils(my_test)
function new (string name, uvm_component parent);
super.new(name, parent);
endfunction : new
function void build_phase (uvm_phase phase);
super.build_phase(phase);
env = my_env :: type_id::create("env", this);
endfunction : build_phase
virtual task run_phase(uvm_phase phase);
// Set a drain time on the objection if needed
`uvm_info("drain", "Setting drain time of 10", UVM_NONE)
// uvm-1.1d or earlier (depricated in uvm-1.2
//uvm_test_done.set_drain_time(this,10);
// uvm-1.2
phase.phase_done.set_drain_time(this,10);
// Run a bunch of processes in parallel
fork
doit(phase, 25);
doit(phase, 50);
join
endtask : run_phase
// A simple task that consumes some time.
task doit (uvm_phase phase, time delay);
static int s_inst = 0;
int inst = s_inst++;
//Raise an objection before starting the activity
phase.raise_objection(
this, // uvm_object obj
"", // string description=""
1 // int count=1, default value = 1 which increment objection count by 1
);
uvm_report_info(get_name(), $sformatf("Starting doit (%0d) with delay %0t", inst, delay), UVM_NONE);
#delay;
uvm_report_info(get_name(), $sformatf("Ending doit (%0d)", inst), UVM_NONE);
//Drop the objection when done
phase.drop_objection(
this, // uvm_object obj
"", // string description=""
1 // int count=1, default value = 1 which decrement objection count by 1
);
endtask : doit
// Called when this or a descendant of this component instance raises the specified objection.
// source_obj - the object that originally raised the objection.
// description - optionally provided by the source_obj to give a reason for raising the objection.
// count - indicates the number of objections raised by the source_obj.
virtual function void raised (uvm_objection objection,
uvm_object source_obj,
string description, // 2nd argument of phase.raise_objection method
int count);
`uvm_info("raised", $sformatf("%d objection(s) raised from %s, total count is now %0d",
count, source_obj.get_full_name, objection.get_objection_total(this)), UVM_NONE)
// description is empty
//`uvm_info("raised", $sformatf("description=%s", description), UVM_LOW)
endfunction : raised
// Called when this or a descendant of this component instance drops the specified objection.
// source_obj - the object that originally dropped the objection.
// description - optionally provided by the source_obj to give a reason for dropping the objection.
// count - indicates the number of objections dropped by the source_obj.
virtual function void dropped (uvm_objection objection,
uvm_object source_obj,
string description, // 2nd argument of phase.drop_objection method
int count);
`uvm_info("dropped", $sformatf("%d objection(s) dropped from %s, total count is now %0d",
count, source_obj.get_full_name, objection.get_objection_total(this)), UVM_NONE)
endfunction : dropped
// Called when all objections have been dropped by this component and all its descendants.
// source_obj - the object that dropped the last objection.
// description - optionally provided by the source_obj to give a reason for dropping the objection.
// count - indicates the number of objections dropped by the source_obj.
virtual task all_dropped (uvm_objection objection,
uvm_object source_obj,
string description, // 2nd argument of phase.drop_objection method
int count);
`uvm_info("all_dropped", $sformatf("Last %d objection(s) dropped from %s, total count is now %0d",
count, source_obj.get_full_name, objection.get_objection_total(this)), UVM_NONE)
#50;
endtask : all_dropped
endclass : my_test
module top;
initial begin
run_test("my_test");
end
endmodule : top
view raw all_dropped.sv hosted with ❤ by GitHub

--------------------------------------------------------------------
--------------------------------------------------------------------
//Output:
// UVM_INFO @ 0: reporter [RNTST] Running test my_test...
// UVM_INFO top.sv(94) @ 0: uvm_test_top [drain] Setting drain time of 10
// UVM_INFO top.sv(140) @ 0: uvm_test_top [raised] 1 objection(s) raised from uvm_test_top, total count is now 1
// UVM_INFO @ 0: uvm_test_top [uvm_test_top] Starting doit (0) with delay 25
// UVM_INFO top.sv(140) @ 0: uvm_test_top [raised] 1 objection(s) raised from uvm_test_top, total count is now 2
// UVM_INFO @ 0: uvm_test_top [uvm_test_top] Starting doit (1) with delay 50
// UVM_INFO top.sv(140) @ 0: uvm_test_top [raised] 1 objection(s) raised from uvm_test_top.env, total count is now 3
// UVM_INFO @ 0: uvm_test_top.env [env] Starting doit (0) with delay 35
// UVM_INFO top.sv(140) @ 0: uvm_test_top [raised] 1 objection(s) raised from uvm_test_top.env, total count is now 4
// UVM_INFO @ 0: uvm_test_top.env [env] Starting doit (1) with delay 60
// UVM_INFO top.sv(140) @ 0: uvm_test_top [raised] 1 objection(s) raised from uvm_test_top.env.agent, total count is now 5
// UVM_INFO @ 0: uvm_test_top.env.agent [agent] Starting doit (0) with delay 85
// UVM_INFO top.sv(140) @ 0: uvm_test_top [raised] 1 objection(s) raised from uvm_test_top.env.agent, total count is now 6
// UVM_INFO @ 0: uvm_test_top.env.agent [agent] Starting doit (1) with delay 55
// UVM_INFO @ 25: uvm_test_top [uvm_test_top] Ending doit (0)
// UVM_INFO top.sv(154) @ 25: uvm_test_top [dropped] 1 objection(s) dropped from uvm_test_top, total count is now 5
// UVM_INFO @ 35: uvm_test_top.env [env] Ending doit (0)
// UVM_INFO top.sv(154) @ 35: uvm_test_top [dropped] 1 objection(s) dropped from uvm_test_top.env, total count is now 4
// UVM_INFO @ 50: uvm_test_top [uvm_test_top] Ending doit (1)
// UVM_INFO top.sv(154) @ 50: uvm_test_top [dropped] 1 objection(s) dropped from uvm_test_top, total count is now 3
// UVM_INFO @ 55: uvm_test_top.env.agent [agent] Ending doit (1)
// UVM_INFO top.sv(154) @ 55: uvm_test_top [dropped] 1 objection(s) dropped from uvm_test_top.env.agent, total count is now 2
// UVM_INFO @ 60: uvm_test_top.env [env] Ending doit (1)
// UVM_INFO top.sv(154) @ 60: uvm_test_top [dropped] 1 objection(s) dropped from uvm_test_top.env, total count is now 1
// UVM_INFO @ 85: uvm_test_top.env.agent [agent] Ending doit (0)
// UVM_INFO top.sv(154) @ 85: uvm_test_top [dropped] 1 objection(s) dropped from uvm_test_top.env.agent, total count is now 0
// UVM_INFO top.sv(166) @ 95: uvm_test_top [all_dropped] Last 1 objection(s) dropped from uvm_test_top.env.agent, total count is now 0
// UVM_INFO /home/shahs/gotcha/uvm/uvm-1.2/src/base/uvm_objection.svh(1271) @ 145: reporter [TEST_DONE] 'run' phase is ready to proceed to the 'extract' phase
// UVM_INFO /home/shahs/gotcha/uvm/uvm-1.2/src/base/uvm_report_server.svh(847) @ 145: reporter [UVM/REPORT/SERVER]

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

Once all the objections are dropped, Drain time takes effect. After Drain time is finished, all_dropped callback takes effect.

Pros and Cons of Pointers in C

Advantages of Pointer:

1) Pointers allow us to perform dynamic memory allocation and deallocation
2) Using pointer we can return more than one value from the function
3) Using pointer can pass array or string more efficiency
4) Pointer helps us to build complex data structure like linked-list, stack, tree, graphs etc.
5) Pointers permit references to functions and thereby facilitating passing of functions as arguments to other functions.
6) Use function call by reference.
4) Increase the execution speed of program. how?


Drawback of Pointer:

1) Uninitialized pointers might cause segmentation fault.
2) Dynamically allocated block needs to be freed explicitly.  Otherwise, it would lead to memory leak.
3) If pointers are updated with incorrect values, it might lead to memory corruption.
4) Pointer bugs are difficult to debug.