In order to understand UVM certain points, I create a simple UVM codes as follow:
module top;
import uvm_pkg::*;
`include "uvm_macros.svh"
typedef class packet;
typedef uvm_sequencer#(packet) pkt_sequencer;
class packet extends uvm_sequence_item;
rand bit[7:0] pkt_id;
function new(string name="packet");
super.new(name);
endfunction
`uvm_object_utils_begin(packet)
`uvm_field_int(pkt_id, UVM_ALL_ON)
`uvm_object_utils_end
endclass // packet
class pkt_sequence extends uvm_sequence#(packet);
`uvm_object_utils(pkt_sequence)
function new(string name="pkt_sequence");
super.new(name);
endfunction // new
virtual task pre_body();
if(starting_phase != null) begin
`uvm_info(get_type_name(), $sformatf("%s pre_body() raise objection[if], %s", get_sequence_path(), starting_phase.get_name()), UVM_LOW)
starting_phase.raise_objection(this);
end
else begin
`uvm_info(get_type_name(), $sformatf("%s pre_body() raise objection[else]", get_sequence_path()), UVM_LOW)
end
endtask // pre_body
virtual task post_body();
if(starting_phase != null) begin
`uvm_info(get_type_name(), $sformatf("%s post_body() raise objection[if], %s", get_sequence_path(), starting_phase.get_name()), UVM_LOW)
starting_phase.drop_objection(this);
end
else begin
`uvm_info(get_type_name(), $sformatf("%s post_body() raise objection[else]", get_sequence_path()), UVM_LOW)
end
endtask // post_body
virtual task body();
`uvm_info(get_type_name(), $sformatf("%s body() Starting sequence ...", get_sequence_path), UVM_LOW)
`uvm_do_with(req, {pkt_id == 'hff;})
endtask // body
endclass // pkt_sequence
class test1 extends uvm_test;
pkt_sequence m_seq;
pkt_sequencer m_seqr;
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
m_seqr = pkt_sequencer::type_id::create("m_pkt_sequencer", this);
//Method 1
uvm_config_wrapper::set(
.cntxt(this),
.inst_name("*.run_phase"), //which exactly path
.field_name("default_sequence"),
.value(pkt_sequence::type_id::get())
);
//Method 1
endfunction // build_phase
virtual task run_phase(uvm_phase phase);
super.run_phase(phase);
fork
begin
phase.raise_objection(this);
//Method 2
// m_seq = pkt_sequence::type_id::create("m_pkt_sequence", this);
// m_seq.start(m_seqr);
//Method 2
#10;
phase.drop_objection(this);
end
begin
packet req;
m_seqr.get_next_item(req);
`uvm_info(get_type_name(), $sformatf("%s",req.sprint()), UVM_LOW)
end
join
endtask // run_phase
`uvm_component_utils(test1)
function new(string name="test1", uvm_component parent);
super.new(name, parent);
endfunction
endclass // test1
initial begin
run_test("test1");
end
endmodule
I have 3 questions about this:
1.When I use Method 1(set default_sequence) to start a sequence, in pre_body()/post_body(), if_branch get executed. However, when I use Method 2(sequence start sequencer) to start a sequence, in pre_body()/post_body(), else_branch get executed. In other words, method 1 starting_phase is non-null object; method 2 starting_phase is null object. Why this cause starting_phase to behave differently?
2.What the exact path when I choose Method 1 to set default_sequence? Is there an easy way to get that exact full path?
uvm_config_wrapper::set(
.cntxt(this),
.inst_name(“*.run_phase”), //what exactly path???
.field_name(“default_sequence”),
.value(pkt_sequence::type_id::get())
);
*3.Why in the end, I got a PH_TIMEOUT UVM_FATAL? How to call item_done() in sequence body()?
UVM_FATAL UVM1.1d/sv/src/base/uvm_phase.svh(1265) @ 9200000000000: reporter [PH_TIMEOUT] Default timeout of 9200000000000 hit, indicating a probable testbench issue