上次文章写道uvm_do macro,主要涉及sequence与sequencer的交互,这次讲driver与sequencer的交互。
在driver中会调用sequencer的task get_next_item,其主要包括task m_select_sequence
task uvm_sequencer::get_next_item(output REQ t);
REQ req_item;
// If a sequence_item has already been requested, then get_next_item()
// should not be called again until item_done() has been called.
if (get_next_item_called == 1)
uvm_report_error(get_full_name(),
"Get_next_item called twice without item_done or get in between", UVM_NONE);
if (!sequence_item_requested)
m_select_sequence();
// Set flag indicating that the item has been requested to ensure that item_done or get
// is called between requests
sequence_item_requested = 1;
get_next_item_called = 1;
m_req_fifo.peek(t);//在finish_item中send_request把request item放入m_req_fifo中,在item_done中pop出
endtask
task uvm_sequencer_base::m_select_sequence();
int selected_sequence;
// Select a sequence
do begin
wait_for_sequences();
selected_sequence = m_choose_next_request();
if (selected_sequence == -1) begin
m_wait_for_available_sequence();
end
end while (selected_sequence == -1);
// issue grant
if (selected_sequence >= 0) begin
m_set_arbitration_completed(arb_sequence_q[selected_sequence].request_id);
arb_sequence_q.delete(selected_sequence);
m_update_lists();
end
endtask
此task 的核心是m_choose_next_request,用于选择合适的request,主要根据指定优先级,lock,grab等方式进行选择
function int uvm_sequencer_base::m_choose_next_request();
int i, temp;
int avail_sequence_count;
int sum_priority_val;
integer avail_sequences[$];
integer highest_sequences[$];
int highest_pri;
string s;
avail_sequence_count = 0;
grant_queued_locks();
for (i = 0; i < arb_sequence_q.size(); i++) begin
if((arb_sequence_q[i].process_id.status == process::KILLED)||
(arb_sequence_q[i].process_id.status == process::FINISHED))begin
`uvm_error("SEQREQZMB",$sformatf("The task reponsible for requesting a wait_for_grant on sequencer '%s' for sequence '%s' has been killed,to avoid a deadlock the sequence will be removed from the arbitration queues",this,get_full_name(),arb_sequence_q[i].sequence_ptr.get_full_name))
remove_sequence_from_queues(arb_sequence_q[i].sequence_ptr);
continue;
end
// Search for available sequences. If in SEQ_ARB_FIFO arbitration,
// then just return the first available sequence. Otherwise,
// create a list for arbitration purposes.
if (i < arb_sequence_q.size())
if (arb_sequence_q[i].request == SEQ_TYPE_REQ)
if (is_blocked(arb_sequence_q[i].sequence_ptr) == 0)
if (arb_sequence_q[i].sequence_ptr.is_relevant() == 1) begin
if (m_arbitration == SEQ_ARB_FIFO) begin
return i;
end
else avail_sequences.push_back(i);
end
end
// Return immediately if there are 0 or 1 available sequences
if (m_arbitration == SEQ_ARB_FIFO) begin
return -1;
end
if (avail_sequences.size() < 1) begin
return -1;
end
if (avail_sequences.size() == 1) begin
return avail_sequences[0];
end
// If any locks are in place, then the available queue must
// be checked to see if a lock prevents any sequence from proceeding
if (lock_list.size() > 0) begin
for (i = 0; i < avail_sequences.size(); i++) begin
if (is_blocked(arb_sequence_q[avail_sequences[i]].sequence_ptr) != 0) begin
avail_sequences.delete(i);
i--;
end
end
if (avail_sequences.size() < 1)
return -1;
if (avail_sequences.size() == 1)
return avail_sequences[0];
end
// Weighted Priority Distribution
// Pick an available sequence based on weighted priorities of available sequences
if (m_arbitration == SEQ_ARB_WEIGHTED) begin
sum_priority_val = 0;
for (i = 0; i < avail_sequences.size(); i++) begin
sum_priority_val += m_get_seq_item_priority(arb_sequence_q[avail_sequences[i]]);
end
temp = $urandom_range(sum_priority_val-1, 0);
sum_priority_val = 0;
for (i = 0; i < avail_sequences.size(); i++) begin
if ((m_get_seq_item_priority(arb_sequence_q[avail_sequences[i]]) +
sum_priority_val) > temp) begin
return avail_sequences[i];
end
sum_priority_val += m_get_seq_item_priority(arb_sequence_q[avail_sequences[i]]);
end
uvm_report_fatal("Sequencer", "UVM Internal error in weighted arbitration code", UVM_NONE);
end
// Random Distribution
if (m_arbitration == SEQ_ARB_RANDOM) begin
i = $urandom_range(avail_sequences.size()-1, 0);
return avail_sequences[i];
end
// Strict Fifo
if ((m_arbitration == SEQ_ARB_STRICT_FIFO) || m_arbitration == SEQ_ARB_STRICT_RANDOM) begin
highest_pri = 0;
// Build a list of sequences at the highest priority
for (i = 0; i < avail_sequences.size(); i++) begin
if (m_get_seq_item_priority(arb_sequence_q[avail_sequences[i]]) > highest_pri) begin
// New highest priority, so start new list
highest_sequences.delete();
highest_sequences.push_back(avail_sequences[i]);
highest_pri = m_get_seq_item_priority(arb_sequence_q[avail_sequences[i]]);
end
else if (m_get_seq_item_priority(arb_sequence_q[avail_sequences[i]]) == highest_pri) begin
highest_sequences.push_back(avail_sequences[i]);
end
end
// Now choose one based on arbitration type
if (m_arbitration == SEQ_ARB_STRICT_FIFO) begin
return(highest_sequences[0]);
end
i = $urandom_range(highest_sequences.size()-1, 0);
return highest_sequences[i];
end
if (m_arbitration == SEQ_ARB_USER) begin
i = user_priority_arbitration( avail_sequences);
// Check that the returned sequence is in the list of available sequences. Failure to
// use an available sequence will cause highly unpredictable results.
highest_sequences = avail_sequences.find with (item == i);
if (highest_sequences.size() == 0) begin
uvm_report_fatal("Sequencer",
$sformatf("Error in User arbitration, sequence %0d not available\n%s",
i, convert2string()), UVM_NONE);
end
return(i);
end
uvm_report_fatal("Sequencer", "Internal error: Failed to choose sequence", UVM_NONE);
endfunction