Source code for uvm.seq.uvm_sequencer_param_base

#//------------------------------------------------------------------------------
#//   Copyright 2007-2011 Mentor Graphics Corporation
#//   Copyright 2007-2011 Cadence Design Systems, Inc.
#//   Copyright 2010-2011 Synopsys, Inc.
#//   Copyright 2019 Tuomas Poikela (tpoikela)
#//   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.
#//------------------------------------------------------------------------------

from .uvm_sequencer_base import UVMSequencerBase
from .uvm_sequencer_analysis_fifo import UVMSequencerAnalysisFIFO
from ..base.uvm_queue import UVMQueue
from ..tlm1.uvm_tlm_fifos import UVMTLMFIFO
from ..tlm1 import (UVMAnalysisExport)
from ..macros.uvm_message_defines import uvm_fatal
from ..base.uvm_globals import *
from ..base.sv import sv

ERR_MSG2 = ("Concurrent calls to get_next_item() not supported. Consider "
    + "using a semaphore to ensure that concurrent processes take turns in the driver")

INFO_MSG1 = ("Dropping response for sequence %0d, sequence not found.  Probable"
    + "cause: sequence exited or has been killed")



[docs]class UVMSequencerParamBase(UVMSequencerBase): """ CLASS: uvm_sequencer_param_base #(REQ,RSP) Extends <uvm_sequencer_base> with an API depending on specific request (REQ) and response (RSP) types. Port (UVMAnalysisExport): rsp_export Drivers or monitors can connect to this port to send responses to the sequencer. Alternatively, a driver can send responses via its seq_item_port:: seq_item_port.item_done(response) seq_item_port.put(response) rsp_port.write(response) <--- via this export The rsp_port in the driver and/or monitor must be connected to the rsp_export in this sequencer in order to send responses through the response analysis port. """ def __init__(self, name, parent): """ Creates and initializes an instance of this class using the normal constructor arguments for uvm_component: name is the name of the instance, and parent is the handle to the hierarchical parent, if any. Args: name: parent: """ UVMSequencerBase.__init__(self, name, parent) self.m_last_req_buffer = UVMQueue() self.m_last_rsp_buffer = UVMQueue() self.m_num_last_reqs = 1 self.num_last_items = self.m_num_last_reqs self.m_num_last_rsps = 1 self.m_num_reqs_sent = 0 self.m_num_rsps_received = 0 # TODO Adding self as 2nd arg makes the sim fail, it does not advance # properly. This is uvm_phase issue most likely #self.m_req_fifo = UVMTLMFIFO(name + "__" + "m_req_fifo", None) self.m_req_fifo = UVMTLMFIFO(name + "__" + "m_req_fifo", self) # uvm_tlm_fifo self.m_req_fifo.print_enabled = False self.rsp_export = UVMAnalysisExport("rsp_export", self) self.sqr_rsp_analysis_fifo = UVMSequencerAnalysisFIFO("sqr_rsp_analysis_fifo", self) self.sqr_rsp_analysis_fifo.print_enabled = 0
[docs] def send_request(self, sequence_ptr, t, rerandomize=False): """ The send_request function may only be called after a wait_for_grant call. This call will send the request item, t, to the sequencer pointed to by sequence_ptr. The sequencer will forward it to the driver. If rerandomize is set, the item will be randomized before being sent to the driver. Args: sequence_ptr (UVMSequenceBase): t (UVMSequenceItem): rerandomize (bool): """ param_t = None # REQ if sequence_ptr is None: self.uvm_report_fatal("SNDREQ", "Send request sequence_ptr is null", UVM_NONE) if sequence_ptr.m_wait_for_grant_semaphore < 1: self.uvm_report_fatal("SNDREQ", "Send request called without wait_for_grant", UVM_NONE) sequence_ptr.m_wait_for_grant_semaphore -= 1 #if ($cast(param_t, t)): param_t = t if rerandomize is True: if param_t.randomize() is False: self.uvm_report_warning("SQRSNDREQ", "Failed to rerandomize sequence item in send_request") if param_t.get_transaction_id() == -1: param_t.set_transaction_id(sequence_ptr.m_next_transaction_id) sequence_ptr.m_next_transaction_id += 1 self.m_last_req_push_front(param_t) #end else begin # uvm_report_fatal(get_name(),$sformatf("send_request failed to cast sequence item"), UVM_NONE) #end param_t.set_sequence_id(sequence_ptr.m_get_sqr_sequence_id(self.m_sequencer_id, 1)) t.set_sequencer(self) if self.m_req_fifo.try_put(param_t) is False: uvm_fatal(self.get_full_name(), ERR_MSG2) self.m_num_reqs_sent += 1 # Grant any locks as soon as possible self.grant_queued_locks()
[docs] def get_current_item(self): """ Returns the request_item currently being executed by the sequencer. If the sequencer is not currently executing an item, this method will return `null`. The sequencer is executing an item from the time that get_next_item or peek is called until the time that get or item_done is called. Note that a driver that only calls get() will never show a current item, since the item is completed at the same time as it is requested. Returns: UVMSequenceItem: Request item currently being executed """ t = [] if not self.m_req_fifo.try_peek(t): return None return t[0]
[docs] def get_num_reqs_sent(self): """ Returns the number of requests that have been sent by this sequencer. Returns: int: Number of requests sent. """ return self.m_num_reqs_sent
# // Function: set_num_last_reqs # // # // Sets the size of the last_requests buffer. Note that the maximum buffer # // size is 1024. If max is greater than 1024, a warning is issued, and the # // buffer is set to 1024. The default value is 1. # // # extern function void set_num_last_reqs(int unsigned max)
[docs] def set_num_last_reqs(self, max_val): if max_val > 1024: self.uvm_report_warning("HSTOB", sv.sformatf("Invalid last size; 1024 is the maximum and will be used")) max_val = 1024 # shrink the buffer if necessary while ((self.m_last_req_buffer.size() != 0) and (self.m_last_req_buffer.size() > max_val)): self.m_last_req_buffer.pop_back() self.m_num_last_reqs = max_val self.num_last_items = max_val
[docs] def get_num_last_reqs(self): """ Function: get_num_last_reqs Returns the size of the last requests buffer, as set by set_num_last_reqs. extern function int unsigned get_num_last_reqs() Returns: """ return self.m_num_last_reqs
# // Function: last_req # // # // Returns the last request item by default. If n is not 0, then it will get # // the n�th before last request item. If n is greater than the last request # // buffer size, the function will return ~null~. # // # function REQ last_req(int unsigned n = 0) # if(n > m_num_last_reqs): # uvm_report_warning("HSTOB", # $sformatf("Invalid last access (%0d), the max history is %0d", n, # m_num_last_reqs)) # return null # end # if(n == m_last_req_buffer.size()) # return null # # return m_last_req_buffer[n] # endfunction # //----------------- # // Group: Responses # //-----------------
[docs] def get_num_rsps_received(self): """ Returns the number of responses received thus far by this sequencer. Returns: """ return self.m_num_rsps_received
# // Function: set_num_last_rsps # // # // Sets the size of the last_responses buffer. The maximum buffer size is # // 1024. If max is greater than 1024, a warning is issued, and the buffer is # // set to 1024. The default value is 1. # // # extern function void set_num_last_rsps(int unsigned max)
[docs] def get_num_last_rsps(self): """ Function: get_num_last_rsps Returns the max size of the last responses buffer, as set by set_num_last_rsps. extern function int unsigned get_num_last_rsps() Returns: """ return self.m_num_last_rsps
# // Function: last_rsp # // # // Returns the last response item by default. If n is not 0, then it will # // get the nth-before-last response item. If n is greater than the last # // response buffer size, the function will return ~null~. # // # function RSP last_rsp(int unsigned n = 0) # if(n > m_num_last_rsps): # uvm_report_warning("HSTOB", # $sformatf("Invalid last access (%0d), the max history is %0d", n, # m_num_last_rsps)) # return null # end # if(n == m_last_rsp_buffer.size()) # return null # # return m_last_rsp_buffer[n] # endfunction # // Internal methods and variables; do not use directly, not part of standard
[docs] def m_last_rsp_push_front(self, item): """ /* local */ extern function void m_last_rsp_push_front(RSP item) Args: item: """ if self.m_num_last_rsps == 0: return if self.m_last_rsp_buffer.size() == self.m_num_last_rsps: self.m_last_rsp_buffer.pop_back() # self.m_last_rsp_buffer.push_front(item)
[docs] def put_response(self, t): """ /* local */ extern function void put_response (RSP t) Args: t: """ sequence_ptr = None # # uvm_sequence_base if t is None: self.uvm_report_fatal("SQRPUT", "Driver put a null response", UVM_NONE) self.m_last_rsp_push_front(t) self.m_num_rsps_received += 1 # Check that set_id_info was called if t.get_sequence_id() == -1: #`ifndef CDNS_NO_SQR_CHK_SEQ_ID self.uvm_report_fatal("SQRPUT", "Driver put a response with null sequence_id", UVM_NONE) #`endif return sequence_ptr = self.m_find_sequence(t.get_sequence_id()) if sequence_ptr is not None: # If the response_handler is enabled for this sequence, then call the response handler if sequence_ptr.get_use_response_handler() == 1: sequence_ptr.response_handler(t) return sequence_ptr.put_response(t) else: self.uvm_report_info("Sequencer", sv.sformatf(INFO_MSG1, t.get_sequence_id()))
#endfunction
[docs] def build_phase(self, phase): """ /* local */ extern virtual function void build_phase(uvm_phase phase) Args: phase: """ super().build_phase(phase) self.sqr_rsp_analysis_fifo.sequencer_ptr = self
[docs] def connect_phase(self, phase): """ /* local */ extern virtual function void connect_phase(uvm_phase phase) Args: phase: """ super().connect_phase(phase) self.rsp_export.connect(self.sqr_rsp_analysis_fifo.analysis_export)
# /* local */ extern virtual function void do_print (uvm_printer printer) # /* local */ extern virtual function void analysis_write(uvm_sequence_item t)
[docs] def m_last_req_push_front(self, item): """ /* local */ extern function void m_last_req_push_front(REQ item) Args: item: """ if self.m_num_last_reqs == 0: return if self.m_last_req_buffer.size() == self.m_num_last_reqs: self.m_last_req_buffer.pop_back() self.m_last_req_buffer.push_front(item)
#//------------------------------------------------------------------------------ #// IMPLEMENTATION #//------------------------------------------------------------------------------ # #// do_print #// -------- # #function void uvm_sequencer_param_base::do_print (uvm_printer printer) # super.do_print(printer) # printer.print_field_int("num_last_reqs", m_num_last_reqs, $bits(m_num_last_reqs), UVM_DEC) # printer.print_field_int("num_last_rsps", m_num_last_rsps, $bits(m_num_last_rsps), UVM_DEC) #endfunction # # # #// analysis_write #// -------------- # #function void uvm_sequencer_param_base::analysis_write(uvm_sequence_item t) # RSP response # # if (!$cast(response, t)): # uvm_report_fatal("ANALWRT", "Failure to cast analysis port write item", UVM_NONE) # end # put_response(response) #endfunction # # # # # # #// set_num_last_rsps #// ----------------- # #function void uvm_sequencer_param_base::set_num_last_rsps(int unsigned max) # if(max > 1024): # uvm_report_warning("HSTOB", # $sformatf("Invalid last size; 1024 is the maximum and will be used")) # max = 1024 # end # # //shrink the buffer # while((m_last_rsp_buffer.size() != 0) && (m_last_rsp_buffer.size() > max)): # void'(m_last_rsp_buffer.pop_back()) # end # # m_num_last_rsps = max # #endfunction