//----------------------------------------------------------------------
// Copyright 2007-2011 Mentor Graphics Corporation
// Copyright 2007-2011 Cadence Design Systems, Inc.
// Copyright 2010 Synopsys, Inc.
// Copyright 2014 NVIDIA Corporation
// All Rights Reserved Worldwide
//
// Licensed under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of
// the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in
// writing, software distributed under the License is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See
// the License for the specific language governing
// permissions and limitations under the License.
//----------------------------------------------------------------------
//------------------------------------------------------------------------------
//
// CLASS: uvm_sequencer #(REQ,RSP)
//
//------------------------------------------------------------------------------
class [docs]uvm_sequencer #(type REQ=uvm_sequence_item, RSP=REQ)
extends uvm_sequencer_param_base #(REQ, RSP);
typedef uvm_sequencer #( REQ , RSP) this_type;
bit sequence_item_requested;
bit get_next_item_called;
`uvm_component_param_utils(this_type)
// Function: new
//
// Standard component constructor that creates an instance of this class
// using the given ~name~ and ~parent~, if any.
//
extern function [docs]new (string name, uvm_component parent=null);
// Function: stop_sequences
//
// Tells the sequencer to kill all sequences and child sequences currently
// operating on the sequencer, and remove all requests, locks and responses
// that are currently queued. This essentially resets the sequencer to an
// idle state.
//
extern virtual function void [docs]stop_sequences();
extern virtual function string [docs]get_type_name();
// Group: Sequencer Interface
// This is an interface for communicating with sequencers.
//
// The interface is defined as:
//| Requests:
//| virtual task get_next_item (output REQ request);
//| virtual task try_next_item (output REQ request);
//| virtual task get (output REQ request);
//| virtual task peek (output REQ request);
//| Responses:
//| virtual function void item_done (input RSP response=null);
//| virtual task put (input RSP response);
//| Sync Control:
//| virtual task wait_for_sequences ();
//| virtual function bit has_do_available ();
//
// See <uvm_sqr_if_base #(REQ,RSP)> for information about this interface.
// Variable: seq_item_export
//
// This export provides access to this sequencer's implementation of the
// sequencer interface.
//
uvm_seq_item_pull_imp #(REQ, RSP, this_type) seq_item_export;
// Task: get_next_item
// Retrieves the next available item from a sequence.
//
extern virtual task [docs]get_next_item (output REQ t);
// Task: try_next_item
// Retrieves the next available item from a sequence if one is available.
//
extern virtual task [docs]try_next_item (output REQ t);
// Function: item_done
// Indicates that the request is completed.
//
extern virtual function void [docs]item_done (RSP item = null);
// Task: put
// Sends a response back to the sequence that issued the request.
//
extern virtual task [docs]put (RSP t);
// Task: get
// Retrieves the next available item from a sequence.
//
extern task [docs]get (output REQ t);
// Task: peek
// Returns the current request item if one is in the FIFO.
//
extern task [docs]peek (output REQ t);
/// Documented here for clarity, implemented in uvm_sequencer_base
// Task: wait_for_sequences
// Waits for a sequence to have a new item available.
//
// Function: has_do_available
// Returns 1 if any sequence running on this sequencer is ready to supply
// a transaction, 0 otherwise.
//
//-----------------
// Internal Methods
//-----------------
// Do not use directly, not part of standard
extern function void [docs]item_done_trigger(RSP item = null);
function RSP [docs]item_done_get_trigger_data();
return last_rsp(0);
endfunction
extern protected virtual function int m_find_number_driver_connections();
endclass
typedef uvm_sequencer #(uvm_sequence_item) [docs]uvm_virtual_sequencer;
//------------------------------------------------------------------------------
// IMPLEMENTATION
//------------------------------------------------------------------------------
function uvm_sequencer::new (string name, uvm_component parent=null);
super.new(name, parent);
seq_item_export = new ("seq_item_export", this);
endfunction
// Function- stop_sequences
//
// Tells the sequencer to kill all sequences and child sequences currently
// operating on the sequencer, and remove all requests, locks and responses
// that are currently queued. This essentially resets the sequencer to an
// idle state.
//
function void uvm_sequencer::stop_sequences();
REQ t;
super.stop_sequences();
sequence_item_requested = 0;
get_next_item_called = 0;
// Empty the request fifo
if (m_req_fifo.used()) begin
uvm_report_info(get_full_name(), "Sequences stopped. Removing request from sequencer fifo");
while (m_req_fifo.try_get(t));
end
endfunction
function string uvm_sequencer::get_type_name();
return "uvm_sequencer";
endfunction
//-----------------
// Internal Methods
//-----------------
// m_find_number_driver_connections
// --------------------------------
// Counting the number of of connections is done at end of
// elaboration and the start of run. If the user neglects to
// call super in one or the other, the sequencer will still
// have the correct value
function int uvm_sequencer::m_find_number_driver_connections();
uvm_port_component_base provided_to_port_list[string];
uvm_port_component_base seq_port_base;
// Check that the seq_item_pull_port is connected
seq_port_base = seq_item_export.get_comp();
seq_port_base.get_provided_to(provided_to_port_list);
return provided_to_port_list.num();
endfunction
// get_next_item
// -------------
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);
endtask
// try_next_item
// -------------
task uvm_sequencer::try_next_item(output REQ t);
int selected_sequence;
time arb_time;
uvm_sequence_base seq;
if (get_next_item_called == 1) begin
uvm_report_error(get_full_name(), "get_next_item/try_next_item called twice without item_done or get in between", UVM_NONE);
return;
end
// allow state from last transaction to settle such that sequences'
// relevancy can be determined with up-to-date information
wait_for_sequences();
// choose the sequence based on relevancy
selected_sequence = m_choose_next_request();
// return if none available
if (selected_sequence == -1) begin
t = null;
return;
end
// now, allow chosen sequence to resume
m_set_arbitration_completed(arb_sequence_q[selected_sequence].request_id);
seq = arb_sequence_q[selected_sequence].sequence_ptr;
arb_sequence_q.delete(selected_sequence);
m_update_lists();
sequence_item_requested = 1;
get_next_item_called = 1;
// give it one NBA to put a new item in the fifo
wait_for_sequences();
// attempt to get the item; if it fails, produce an error and return
if (!m_req_fifo.try_peek(t))
uvm_report_error("TRY_NEXT_BLOCKED", {"try_next_item: the selected sequence '",
seq.get_full_name(), "' did not produce an item within an NBA delay. ",
"Sequences should not consume time between calls to start_item and finish_item. ",
"Returning null item."}, UVM_NONE);
endtask
// item_done
// ---------
function void uvm_sequencer::item_done(RSP item = null);
REQ t;
// Set flag to allow next get_next_item or peek to get a new sequence_item
sequence_item_requested = 0;
get_next_item_called = 0;
if (m_req_fifo.try_get(t) == 0) begin
uvm_report_fatal(get_full_name(), {"Item_done() called with no outstanding requests.",
" Each call to item_done() must be paired with a previous call to get_next_item()."});
end else begin
m_wait_for_item_sequence_id = t.get_sequence_id();
m_wait_for_item_transaction_id = t.get_transaction_id();
end
if (item != null) begin
seq_item_export.put_response(item);
end
// Grant any locks as soon as possible
grant_queued_locks();
endfunction
// put
// ---
task uvm_sequencer::put (RSP t);
put_response(t);
endtask
// get
// ---
task uvm_sequencer::get(output REQ t);
if (sequence_item_requested == 0) begin
m_select_sequence();
end
sequence_item_requested = 1;
m_req_fifo.peek(t);
item_done();
endtask
// peek
// ----
task uvm_sequencer::peek(output REQ t);
if (sequence_item_requested == 0) begin
m_select_sequence();
end
// Set flag indicating that the item has been requested to ensure that item_done or get
// is called between requests
sequence_item_requested = 1;
m_req_fifo.peek(t);
endtask
// item_done_trigger
// -----------------
function void uvm_sequencer::item_done_trigger(RSP item = null);
item_done(item);
endfunction