uvm_sequencer -> uvm_sequencer_param_base -> uvm_sequencer_base -> uvm_sequencer_base -> uvm_component -> uvm_object
When running each phases which extends class uvm_task_phase, it will call the function start_phase_sequence of the sequencer and then the sequencer will lookup for the default sequence for that phase and call seq.start(this).
virtual class uvm_task_phase extends uvm_phase;
function void m_traverse(uvm_component comp,
uvm_phase phase,
uvm_phase_state state);
...
if (phase_domain == uvm_domain::get_common_domain() ||
phase_domain == comp_domain) begin
case (state)
UVM_PHASE_STARTED: begin
comp.m_current_phase = phase;
comp.m_apply_verbosity_settings(phase);
comp.phase_started(phase);
if ($cast(seqr, comp))
seqr.start_phase_sequence(phase);
end
...
endcase
end
endfunction
endclass
class uvm_sequencer_base extends uvm_component;
function void uvm_sequencer_base::start_phase_sequence(uvm_phase phase);
...
rq = rp.lookup_name({get_full_name(), ".", phase.get_name(), "_phase"},"default_sequence", null, 0);
...
`uvm_info("PHASESEQ", {"Starting default sequence '",
seq.get_type_name(),"' for phase '", phase.get_name(),"'"}, UVM_FULL)
seq.print_sequence_info = 1;
seq.set_sequencer(this);
seq.reseed();
seq.set_starting_phase(phase);
if (!seq.do_not_randomize && !seq.randomize()) begin
`uvm_warning("STRDEFSEQ", {"Randomization failed for default sequence '",
seq.get_type_name(),"' for phase '", phase.get_name(),"'"})
return;
end
fork begin
uvm_sequence_process_wrapper w = new();
// reseed this process for random stability
w.pid = process::self();
w.seq = seq;
w.pid.srandom(uvm_create_random_seed(seq.get_type_name(), this.get_full_name()));
m_default_sequences[phase] = w;
// this will either complete naturally, or be killed later
seq.start(this);
m_default_sequences.delete(phase);
end
join_none
endfunction
endclass
seq.start(this) will call pre_start(), pre_body(), body(), post_body() and post_start(). In the body of extended sequence class of uvm_sequence, we will realize the detailed sequences by using `uvm_do, etc.
class uvm_sequence_base extends uvm_sequence_item;
int this_priority = -1,
bit call_pre_post = 1);
bit old_automatic_phase_objection;
set_item_context(parent_sequence, sequencer);
if (!(m_sequence_state inside {UVM_CREATED,UVM_STOPPED,UVM_FINISHED})) begin
uvm_report_fatal("SEQ_NOT_DONE",
{"Sequence ", get_full_name(), " already started"},UVM_NONE);
end
if (m_parent_sequence != null) begin
m_parent_sequence.children_array[this] = 1;
end
if (this_priority < -1) begin
uvm_report_fatal("SEQPRI", $sformatf("Sequence %s start has illegal priority: %0d",
get_full_name(),
this_priority), UVM_NONE);
end
if (this_priority < 0) begin
if (parent_sequence == null) this_priority = 100;
else this_priority = parent_sequence.get_priority();
end
// Check that the response queue is empty from earlier runs
clear_response_queue();
m_priority = this_priority;
if (m_sequencer != null) begin
integer handle;
uvm_tr_stream stream;
if (m_parent_sequence == null) begin
stream = m_sequencer.get_tr_stream(get_name(), "Transactions");
handle = m_sequencer.begin_tr(this, get_name());
m_tr_recorder = uvm_recorder::get_recorder_from_handle(handle);
end else begin
stream = m_sequencer.get_tr_stream(get_root_sequence_name(), "Transactions");
handle = m_sequencer.begin_child_tr(this,
(m_parent_sequence.m_tr_recorder == null) ? 0 : m_parent_sequence.m_tr_recorder.get_handle(),
get_root_sequence_name());
m_tr_recorder = uvm_recorder::get_recorder_from_handle(handle);
end
end
// Ensure that the sequence_id is intialized in case this sequence has been stopped previously
set_sequence_id(-1);
// Remove all sqr_seq_ids
m_sqr_seq_ids.delete();
// Register the sequence with the sequencer if defined.
if (m_sequencer != null) begin
void'(m_sequencer.m_register_sequence(this));
end
// Change the state to PRE_START, do this before the fork so that
// the "if (!(m_sequence_state inside {...}" works
m_sequence_state = UVM_PRE_START;
fork
begin
m_sequence_process = process::self();
// absorb delta to ensure PRE_START was seen
#0;
// Raise the objection if enabled
// (This will lock the uvm_get_to_lock_dap)
if (get_automatic_phase_objection()) begin
m_safe_raise_starting_phase("automatic phase objection");
end
pre_start();
if (call_pre_post == 1) begin
m_sequence_state = UVM_PRE_BODY;
#0;
pre_body();
end
if (parent_sequence != null) begin
parent_sequence.pre_do(0); // task
parent_sequence.mid_do(this); // function
end
m_sequence_state = UVM_BODY;
#0;
body();
m_sequence_state = UVM_ENDED;
#0;
if (parent_sequence != null) begin
parent_sequence.post_do(this);
end
if (call_pre_post == 1) begin
m_sequence_state = UVM_POST_BODY;
#0;
post_body();
end
m_sequence_state = UVM_POST_START;
#0;
post_start();
// Drop the objection if enabled
if (get_automatic_phase_objection()) begin
m_safe_drop_starting_phase("automatic phase objection");
end
m_sequence_state = UVM_FINISHED;
#0;
end
join
if (m_sequencer != null) begin
m_sequencer.end_tr(this);
end
// Clean up any sequencer queues after exiting; if we
// were forcibly stoped, this step has already taken place
if (m_sequence_state != UVM_STOPPED) begin
if (m_sequencer != null)
m_sequencer.m_sequence_exiting(this);
end
#0; // allow stopped and finish waiters to resume
if ((m_parent_sequence != null) && (m_parent_sequence.children_array.exists(this))) begin
m_parent_sequence.children_array.delete(this);
end
old_automatic_phase_objection = get_automatic_phase_objection();
m_init_phase_daps(1);
set_automatic_phase_objection(old_automatic_phase_objection);
endtask
endclass
virtual task start (uvm_sequencer_base sequencer,
uvm_sequence_base parent_sequence = null,int this_priority = -1,
bit call_pre_post = 1);
bit old_automatic_phase_objection;
set_item_context(parent_sequence, sequencer);
if (!(m_sequence_state inside {UVM_CREATED,UVM_STOPPED,UVM_FINISHED})) begin
uvm_report_fatal("SEQ_NOT_DONE",
{"Sequence ", get_full_name(), " already started"},UVM_NONE);
end
if (m_parent_sequence != null) begin
m_parent_sequence.children_array[this] = 1;
end
if (this_priority < -1) begin
uvm_report_fatal("SEQPRI", $sformatf("Sequence %s start has illegal priority: %0d",
get_full_name(),
this_priority), UVM_NONE);
end
if (this_priority < 0) begin
if (parent_sequence == null) this_priority = 100;
else this_priority = parent_sequence.get_priority();
end
// Check that the response queue is empty from earlier runs
clear_response_queue();
m_priority = this_priority;
if (m_sequencer != null) begin
integer handle;
uvm_tr_stream stream;
if (m_parent_sequence == null) begin
stream = m_sequencer.get_tr_stream(get_name(), "Transactions");
handle = m_sequencer.begin_tr(this, get_name());
m_tr_recorder = uvm_recorder::get_recorder_from_handle(handle);
end else begin
stream = m_sequencer.get_tr_stream(get_root_sequence_name(), "Transactions");
handle = m_sequencer.begin_child_tr(this,
(m_parent_sequence.m_tr_recorder == null) ? 0 : m_parent_sequence.m_tr_recorder.get_handle(),
get_root_sequence_name());
m_tr_recorder = uvm_recorder::get_recorder_from_handle(handle);
end
end
// Ensure that the sequence_id is intialized in case this sequence has been stopped previously
set_sequence_id(-1);
// Remove all sqr_seq_ids
m_sqr_seq_ids.delete();
// Register the sequence with the sequencer if defined.
if (m_sequencer != null) begin
void'(m_sequencer.m_register_sequence(this));
end
// Change the state to PRE_START, do this before the fork so that
// the "if (!(m_sequence_state inside {...}" works
m_sequence_state = UVM_PRE_START;
fork
begin
m_sequence_process = process::self();
// absorb delta to ensure PRE_START was seen
#0;
// Raise the objection if enabled
// (This will lock the uvm_get_to_lock_dap)
if (get_automatic_phase_objection()) begin
m_safe_raise_starting_phase("automatic phase objection");
end
pre_start();
if (call_pre_post == 1) begin
m_sequence_state = UVM_PRE_BODY;
#0;
pre_body();
end
if (parent_sequence != null) begin
parent_sequence.pre_do(0); // task
parent_sequence.mid_do(this); // function
end
m_sequence_state = UVM_BODY;
#0;
body();
m_sequence_state = UVM_ENDED;
#0;
if (parent_sequence != null) begin
parent_sequence.post_do(this);
end
if (call_pre_post == 1) begin
m_sequence_state = UVM_POST_BODY;
#0;
post_body();
end
m_sequence_state = UVM_POST_START;
#0;
post_start();
// Drop the objection if enabled
if (get_automatic_phase_objection()) begin
m_safe_drop_starting_phase("automatic phase objection");
end
m_sequence_state = UVM_FINISHED;
#0;
end
join
if (m_sequencer != null) begin
m_sequencer.end_tr(this);
end
// Clean up any sequencer queues after exiting; if we
// were forcibly stoped, this step has already taken place
if (m_sequence_state != UVM_STOPPED) begin
if (m_sequencer != null)
m_sequencer.m_sequence_exiting(this);
end
#0; // allow stopped and finish waiters to resume
if ((m_parent_sequence != null) && (m_parent_sequence.children_array.exists(this))) begin
m_parent_sequence.children_array.delete(this);
end
old_automatic_phase_objection = get_automatic_phase_objection();
m_init_phase_daps(1);
set_automatic_phase_objection(old_automatic_phase_objection);
endtask
endclass
SEQ_OR_ITEM may be an object of a class which extends uvm_sequence or REQ which is an object of a class which extends uvm_sequence_item.
If SEQ_OR_ITEM is an object of a class which extends uvm_sequence, SEQ_OR_ITEM may call another object of extension of uvm_sequence through `uvm_do, etc.
REQ is the final atomic transaction which is defined by us.
So if SEQ_OR_ITEM is an object of a class which extends uvm_sequence, $cast(__seq, SEQ_OR_ITEM) will succeed as uvm_sequence extends uvm_sequence_base. Then it will call the start function of the SEQ_OR_ITEM, which will go through SEQ_OR_ITEM's steps and run that SEQ_OR_ITEM 's body(). Using this way, SEQ_OR_ITEM will recursively go to the final uvm_sequence, which will do `uvm_do on REQ.
If SEQ_OR_ITEM is REQ, $cast(__seq, SEQ_OR_ITEM) will fail and function finish_item will be called.
`define uvm_do(SEQ_OR_ITEM) \
`uvm_do_on_pri_with(SEQ_OR_ITEM, m_sequencer, -1, {})
`define uvm_do_on_pri_with(SEQ_OR_ITEM, SEQR, PRIORITY, CONSTRAINTS) \
begin \
uvm_sequence_base __seq; \
`uvm_create_on(SEQ_OR_ITEM, SEQR) \
if (!$cast(__seq,SEQ_OR_ITEM)) start_item(SEQ_OR_ITEM, PRIORITY);\
if ((__seq == null || !__seq.do_not_randomize) && !SEQ_OR_ITEM.randomize() with CONSTRAINTS ) begin \
`uvm_warning("RNDFLD", "Randomization failed in uvm_do_with action") \
end\
if (!$cast(__seq,SEQ_OR_ITEM)) finish_item(SEQ_OR_ITEM, PRIORITY); \
else __seq.start(SEQR, this, PRIORITY, 0); \
end
`define uvm_create_on(SEQ_OR_ITEM, SEQR) \
begin \
uvm_object_wrapper w_; \
w_ = SEQ_OR_ITEM.get_type(); \
$cast(SEQ_OR_ITEM , create_item(w_, SEQR, `"SEQ_OR_ITEM`"));\
end
virtual task start_item (uvm_sequence_item item,
int set_priority = -1,
uvm_sequencer_base sequencer=null);
uvm_sequence_base seq;
if(item == null) begin
uvm_report_fatal("NULLITM",
{"attempting to start a null item from sequence '",
get_full_name(), "'"}, UVM_NONE);
return;
end
if($cast(seq, item)) begin
uvm_report_fatal("SEQNOTITM",
{"attempting to start a sequence using start_item() from sequence '",
get_full_name(), "'. Use seq.start() instead."}, UVM_NONE);
return;
end
if (sequencer == null)
sequencer = item.get_sequencer();
if(sequencer == null)
sequencer = get_sequencer();
if(sequencer == null) begin
uvm_report_fatal("SEQ",{"neither the item's sequencer nor dedicated sequencer has been supplied to start item in ",get_full_name()},UVM_NONE);
return;
end
item.set_item_context(this, sequencer);
if (set_priority < 0)
set_priority = get_priority();
sequencer.wait_for_grant(this, set_priority);
if (sequencer.is_auto_item_recording_enabled()) begin
void'(sequencer.begin_child_tr(item,
(m_tr_recorder == null) ? 0 : m_tr_recorder.get_handle(),
item.get_root_sequence_name(), "Transactions"));
end
pre_do(1);
endtask
virtual task finish_item (uvm_sequence_item item,
int set_priority = -1);
uvm_sequencer_base sequencer;
sequencer = item.get_sequencer();
if (sequencer == null) begin
uvm_report_fatal("STRITM", "sequence_item has null sequencer", UVM_NONE);
end
mid_do(item);
sequencer.send_request(this, item);
sequencer.wait_for_item_done(this, -1);
if (sequencer.is_auto_item_recording_enabled()) begin
sequencer.end_tr(item);
end
post_do(item);
endtask
No comments:
Post a Comment