//---------------------------------------------------------------------- // Copyright 2007-2011 Mentor Graphics Corporation // Copyright 2007-2011 Cadence Design Systems, Inc. // Copyright 2010 Synopsys, Inc. // 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 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) // Variable: seq_item_export // // This export provides access to this sequencer's implementation of the // sequencer interface, , which defines the following // methods: // //| 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 for information about this interface. uvm_seq_item_pull_imp #(REQ, RSP, this_type) seq_item_export; // Function: new // // Standard component constructor that creates an instance of this class // using the given ~name~ and ~parent~, if any. // extern function 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 stop_sequences(); extern virtual function string get_type_name(); //----------------- // Internal Methods //----------------- // Do not use directly; not part of standard // Access to following internal methods provided via seq_item_export extern virtual task get_next_item (output REQ t); extern virtual task try_next_item (output REQ t); extern virtual function void item_done (RSP item = null); extern virtual task put (RSP t); extern task get (output REQ t); extern task peek (output REQ t); extern function void item_done_trigger(RSP item = null); function RSP 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) 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