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.

2 comments:

  1. This is an awesome post.Really very informative and creative contents. These concept is a good way to enhance the knowledge.I like it and help me to development very well.Thank you for this brief explanation and very nice information.Well, got a good knowledge.
    Php projects with source code
    Online examination system in php
    Student management system in php
    Php projects for students
    Free source code for academic
    Academic projects provider in nashik
    Academic project free download

    ReplyDelete