Tuesday, 6 November 2018

Drop all objection manually in UVM


Test requirement is like,
1) When polling for more than one interrupts by continuously reading different registers in parallel and based on some indication move to next phase of UVM
2) Waiting for some timer to be expired and then moving to next phase of UVM

Let’s take one scenario where,
Driver is raising objection but never dropping objection and requirement is to move to next phase (extract_phase) after #50 timeunit. But because all the objection are not dropped in run_phase, simulation is not going to extract_phase.
Let’s go through example.
-------------------------------------------------------------------------
class my_seq_item extends uvm_sequence_item;
rand bit [31:0] data;
rand bit [7:0] addr;
`uvm_object_utils_begin(my_seq_item)
`uvm_field_int(addr, UVM_DEFAULT | UVM_HEX)
`uvm_field_int(data, UVM_DEFAULT | UVM_HEX)
`uvm_object_utils_end
function new (string name = "my_seq_item");
super.new(name);
endfunction : new
function string convert2string();
convert2string = $sformatf("addr:0x%h, data:0x%h", addr, data);
return convert2string;
endfunction : convert2string
endclass : my_seq_item
class my_seq extends uvm_sequence#(my_seq_item);
`uvm_object_utils(my_seq)
function new (string name = "my_seq");
super.new(name);
endfunction : new
task body();
`uvm_create(req)
start_item(req);
if (!req.randomize()) begin
`uvm_fatal(get_name(), $sformatf("Randomization of %s failed", req.get_type_name()))
end
finish_item(req);
endtask : body
endclass : my_seq
class my_seqr extends uvm_sequencer#(my_seq_item);
`uvm_component_utils(my_seqr)
function new (string name = "my_seqr", uvm_component parent = null);
super.new(name, parent);
endfunction : new
endclass : my_seqr
class my_driver extends uvm_driver#(my_seq_item);
`uvm_component_utils(my_driver)
function new (string name = "my_driver", uvm_component parent = null);
super.new(name, parent);
endfunction : new
function void build_phase(uvm_phase phase);
super.build_phase(phase);
endfunction : build_phase
task run_phase(uvm_phase phase);
forever begin
seq_item_port.get_next_item(req);
drive(phase);
seq_item_port.item_done();
end
endtask : run_phase
task drive(uvm_phase phase);
phase.raise_objection(this);
#5;
`uvm_info(get_name(), $sformatf("in drive method req:\n%s", req.convert2string()), UVM_LOW)
// Objection is not dropped
//phase.drop_objection(this);
endtask : drive
endclass : my_driver
class my_agent extends uvm_agent;
my_seqr seqr;
my_driver drv;
`uvm_component_utils(my_agent)
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);
seqr = my_seqr :: type_id :: create ("seqr", 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(seqr.seq_item_export);
endfunction : connect_phase
endclass : my_agent
class my_test extends uvm_test;
my_agent agent;
`uvm_component_utils(my_test)
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);
agent = my_agent :: type_id :: create ("agent", this);
endfunction : build_phase
task run_phase(uvm_phase phase);
my_seq seq;
seq = my_seq :: type_id :: create("seq");
phase.raise_objection(this);
seq.start(agent.seqr);
phase.drop_objection(this);
endtask : run_phase
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 no_objection_drop.sv(67) @ 5: uvm_test_top.agent.drv [drv] in drive method req:
// addr:0x82, data:0x5455120d
// UVM_FATAL /opt/uvm-1.2/src/base/uvm_phase.svh(1489) @ 9200000000000: reporter [PH_TIMEOUT] Default timeout of 9200000000000 hit, indicating a probable testbench issue
-------------------------------------------------------------------------


Now let’s take another scenario,
Here driver is dropping objection after #105 timeunit. So simulation will move to next phase after #105. But the requirement is to move to next phase which is extract_phase after #50.
Let’s go through example.
-------------------------------------------------------------------------
class my_seq_item extends uvm_sequence_item;
rand bit [31:0] data;
rand bit [7:0] addr;
`uvm_object_utils_begin(my_seq_item)
`uvm_field_int(addr, UVM_DEFAULT | UVM_HEX)
`uvm_field_int(data, UVM_DEFAULT | UVM_HEX)
`uvm_object_utils_end
function new (string name = "my_seq_item");
super.new(name);
endfunction : new
function string convert2string();
convert2string = $sformatf("addr:0x%h, data:0x%h", addr, data);
return convert2string;
endfunction : convert2string
endclass : my_seq_item
class my_seq extends uvm_sequence#(my_seq_item);
`uvm_object_utils(my_seq)
function new (string name = "my_seq");
super.new(name);
endfunction : new
task body();
`uvm_create(req)
start_item(req);
if (!req.randomize()) begin
`uvm_fatal(get_name(), $sformatf("Randomization of %s failed", req.get_type_name()))
end
finish_item(req);
endtask : body
endclass : my_seq
class my_seqr extends uvm_sequencer#(my_seq_item);
`uvm_component_utils(my_seqr)
function new (string name = "my_seqr", uvm_component parent = null);
super.new(name, parent);
endfunction : new
endclass : my_seqr
class my_driver extends uvm_driver#(my_seq_item);
`uvm_component_utils(my_driver)
function new (string name = "my_driver", uvm_component parent = null);
super.new(name, parent);
endfunction : new
function void build_phase(uvm_phase phase);
super.build_phase(phase);
endfunction : build_phase
task run_phase(uvm_phase phase);
forever begin
seq_item_port.get_next_item(req);
drive(phase);
seq_item_port.item_done();
end
endtask : run_phase
task drive(uvm_phase phase);
phase.raise_objection(this);
#5;
`uvm_info(get_name(), $sformatf("in drive method req:\n%s", req.convert2string()), UVM_LOW)
//Dropping objection from driver after #105 timeunit
fork
begin
#100;
`uvm_info(get_name(), $sformatf("in drive, dropping objection"), UVM_LOW)
phase.drop_objection(this);
end
join_none
endtask : drive
endclass : my_driver
class my_agent extends uvm_agent;
my_seqr seqr;
my_driver drv;
`uvm_component_utils(my_agent)
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);
seqr = my_seqr :: type_id :: create ("seqr", 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(seqr.seq_item_export);
endfunction : connect_phase
endclass : my_agent
class my_test extends uvm_test;
my_agent agent;
`uvm_component_utils(my_test)
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);
agent = my_agent :: type_id :: create ("agent", this);
endfunction : build_phase
task run_phase(uvm_phase phase);
my_seq seq;
fork
begin
#50; //Timer
// After #50 timeunit wants to move to next phase (extract_phase)
end
join_none
seq = my_seq :: type_id :: create("seq");
phase.raise_objection(this);
seq.start(agent.seqr);
phase.drop_objection(this);
endtask : run_phase
function void extract_phase(uvm_phase phase);
// Expecting to execute at timeunit #50, but executing at #105
`uvm_info(get_name(), $sformatf("Executing extract_phase"), UVM_LOW)
endfunction : extract_phase
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 objection_dropped_after_timeout.sv(67) @ 5: uvm_test_top.agent.drv [drv] in drive method req:
// addr:0x82, data:0x5455120d
// UVM_INFO objection_dropped_after_timeout.sv(73) @ 105: uvm_test_top.agent.drv [drv] in drive, dropping objection
// UVM_INFO /opt/uvm-1.2/src/base/uvm_objection.svh(1270) @ 105: reporter [TEST_DONE] 'run' phase is ready to proceed to the 'extract' phase
// UVM_INFO objection_dropped_after_timeout.sv(132) @ 105: uvm_test_top [uvm_test_top] Executing extract_phase
-------------------------------------------------------------------------


To fulfill the requirement we need to any how drop the pending objection after #50 to move to next phase after #50.
We can do this by getting list of all uvm_components (through get_objector method of uvm_objection class) who raised objection and then we can manually drop the objection after #50 timeunit.
Let’s go through example.
-------------------------------------------------------------------------
class my_seq_item extends uvm_sequence_item;
rand bit [31:0] data;
rand bit [7:0] addr;
`uvm_object_utils_begin(my_seq_item)
`uvm_field_int(addr, UVM_DEFAULT | UVM_HEX)
`uvm_field_int(data, UVM_DEFAULT | UVM_HEX)
`uvm_object_utils_end
function new (string name = "my_seq_item");
super.new(name);
endfunction : new
function string convert2string();
convert2string = $sformatf("addr:0x%h, data:0x%h", addr, data);
return convert2string;
endfunction : convert2string
endclass : my_seq_item
class my_seq extends uvm_sequence#(my_seq_item);
`uvm_object_utils(my_seq)
function new (string name = "my_seq");
super.new(name);
endfunction : new
task body();
`uvm_create(req)
start_item(req);
if (!req.randomize()) begin
`uvm_fatal(get_name(), $sformatf("Randomization of %s failed", req.get_type_name()))
end
finish_item(req);
endtask : body
endclass : my_seq
class my_seqr extends uvm_sequencer#(my_seq_item);
`uvm_component_utils(my_seqr)
function new (string name = "my_seqr", uvm_component parent = null);
super.new(name, parent);
endfunction : new
endclass : my_seqr
class my_driver extends uvm_driver#(my_seq_item);
`uvm_component_utils(my_driver)
function new (string name = "my_driver", uvm_component parent = null);
super.new(name, parent);
endfunction : new
function void build_phase(uvm_phase phase);
super.build_phase(phase);
endfunction : build_phase
task run_phase(uvm_phase phase);
forever begin
seq_item_port.get_next_item(req);
drive(phase);
seq_item_port.item_done();
end
endtask : run_phase
task drive(uvm_phase phase);
phase.raise_objection(this);
#5;
`uvm_info(get_name(), $sformatf("in drive method req:\n%s", req.convert2string()), UVM_LOW)
// Objection is not dropped
//phase.drop_objection(this);
endtask : drive
endclass : my_driver
class my_agent extends uvm_agent;
my_seqr seqr;
my_driver drv;
`uvm_component_utils(my_agent)
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);
seqr = my_seqr :: type_id :: create ("seqr", 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(seqr.seq_item_export);
endfunction : connect_phase
endclass : my_agent
class my_test extends uvm_test;
my_agent agent;
`uvm_component_utils(my_test)
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);
agent = my_agent :: type_id :: create ("agent", this);
endfunction : build_phase
task run_phase(uvm_phase phase);
my_seq seq;
fork
begin
#50; //Timer
drop_all_objection(phase);
end
join_none
seq = my_seq :: type_id :: create("seq");
phase.raise_objection(this);
seq.start(agent.seqr);
phase.drop_objection(this);
endtask : run_phase
function void drop_all_objection(uvm_phase phase);
uvm_objection objection;
uvm_object object_q[$];
// Get objection handle for current phase
objection = phase.get_objection();
// Get list of the uvm_components which doesn't drop the objection
objection.get_objectors(object_q);
// Dropping all the objection from all the objectors
foreach(object_q[i]) begin
while (objection.get_objection_count(object_q[i]) > 0) begin
`uvm_info(get_type_name(),$sformatf("Dropping objection:%0d for object:%s", i, object_q[i].get_full_name()), UVM_LOW)
objection.drop_objection(object_q[i]);
end
end
endfunction : drop_all_objection
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 drop_all_objection.sv(67) @ 5: uvm_test_top.agent.drv [drv] in drive method req:
// addr:0x82, data:0x5455120d
// UVM_INFO drop_all_objection.sv(137) @ 50: uvm_test_top [my_test] Dropping objection:1 for object:uvm_test_top.agent.drv
// UVM_INFO /opt/uvm-1.2/src/base/uvm_objection.svh(1270) @ 50: reporter [TEST_DONE] 'run' phase is ready to proceed to the 'extract' phase
-------------------------------------------------------------------------

Reference:
1) uvm_objection.svh file 

4 comments:

  1. with
    objection.get_objectors(object_q);
    will we get component names only where the objection is not dropped or we'll get all the component name where either objection is raised or dropped or both.

    ReplyDelete
  2. You will get all the component names.

    ReplyDelete
  3. 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
  4. Amazing Blog, Thanks for shraring this informative post with us.
    Hipla is an all-in-one-workplace automation platform making your workplace smarter, safer & secure. We are one of the leading service providers of Visitor Management Systems Software.
    For more information:
    Call us: +918527718300
    Email: info@hipla.io

    ReplyDelete