Source code for uvm.base.uvm_tr_stream

#//
#//-----------------------------------------------------------------------------
#//   Copyright 2007-2011 Mentor Graphics Corporation
#//   Copyright 2007-2011 Cadence Design Systems, Inc.
#//   Copyright 2010 Synopsys, Inc.
#//   Copyright 2013 NVIDIA Corporation
#//   Copyright 2019-2020 Tuomas Poikela
#//   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 .sv import sv
from ..dap.uvm_set_before_get_dap import uvm_set_before_get_dap
from .uvm_object import UVMObject
from ..macros.uvm_object_defines import uvm_object_utils
from ..macros.uvm_message_defines import uvm_error, uvm_warning
from .uvm_globals import uvm_sim_time

from .uvm_recorder import UVMTextRecorder

#//------------------------------------------------------------------------------
#// File: Transaction Recording Streams
#//
#
#// class- m_uvm_tr_stream_cfg
#// Undocumented helper class for storing stream
#// initialization values.

[docs]class m_uvm_tr_stream_cfg(): def __init__(self): self.db = None # uvm_tr_database db self.scope = "" self.stream_type_name = ""
#endclass : m_uvm_tr_stream_cfg # #typedef class uvm_set_before_get_dap #typedef class uvm_text_recorder #//------------------------------------------------------------------------------ #// #// CLASS: UVMTrStream #// #// The ~UVMTrStream~ base class is a representation of a stream of records #// within a <uvm_tr_database>. #// #// The record stream is intended to hide the underlying database implementation #// from the end user, as these details are often vendor or tool-specific. #// #// The ~UVMTrStream~ class is pure virtual, and must be extended with an #// implementation. A default text-based implementation is provided via the #// <UVMTextTrStream> class. #// #virtual class UVMTrStream extends uvm_object
[docs]class UVMTrStream(UVMObject): # # // Variable- m_cfg_dap # // Data access protected reference to the DB # local uvm_set_before_get_dap#(m_uvm_tr_stream_cfg) m_cfg_dap # # # // Variable- m_warn_null_cfg # // Used to limit the number of warnings # local bit m_warn_null_cfg # # // Variable- m_is_opened # // Used to indicate stream is open # local bit m_is_opened # # // Variable- m_is_closed # // Used to indicate stream is closed # local bit m_is_closed # # // !m_is_opened && !m_is_closed == m_is_freed # def __init__(self, name="unnamed-UVMTrStream"): """ Function: new Constructor Parameters: name - Stream instance name Args: name: """ UVMObject.__init__(self, name) self.m_cfg_dap = uvm_set_before_get_dap("cfg_dap") # // Variable- m_records # // Active records in the stream (active == open or closed) self.m_records = {} # bit [uvm_recorder] self.m_warn_null_cfg = 0 # // Variable- m_ids_by_stream # // An associative array of integers, indexed by uvm_tr_streams. This # // provides a unique 'id' or 'handle' for each stream, which can be # // used to identify the stream. # // # // By default, neither ~m_ids_by_stream~ or ~m_streams_by_id~ are # // used. Streams are only placed in the arrays when the user # // attempts to determine the id for a stream. # local static integer m_ids_by_stream[UVMTrStream] m_ids_by_stream = {}
[docs] def get_db(self): """ Group: Configuration API Function: get_db Returns a reference to the database which contains this stream. A warning will be asserted if get_db is called prior to the stream being initialized via `do_open`. Returns: """ m_cfg = [] # m_uvm_tr_stream_cfg m_cfg if not self.m_cfg_dap.try_get(m_cfg): if self.m_warn_null_cfg == 1: uvm_warning("UVM/REC_STR/NO_CFG", sv.sformatf("attempt to retrieve DB from '%s' before it was set!", self.get_name())) self.m_warn_null_cfg = 0 return None return m_cfg[0].db
# // Function: get_scope # // Returns the ~scope~ supplied when opening this stream. # // # // A warning will be asserted if get_scope is called prior to # // the stream being initialized via <do_open>. # function string get_scope() # m_uvm_tr_stream_cfg m_cfg # if (!m_cfg_dap.try_get(m_cfg)) begin # if (m_warn_null_cfg == 1) # `uvm_warning("UVM/REC_STR/NO_CFG", # $sformatf("attempt to retrieve scope from '%s' before it was set!", # get_name())) # m_warn_null_cfg = 0 # return "" # end # return m_cfg.scope # endfunction : get_scope # # // Function: get_stream_type_name # // Returns a reference to the database which contains this # // stream. # // # // A warning will be asserted if get_stream_type_name is called prior to # // the stream being initialized via <do_open>. # function string get_stream_type_name() # m_uvm_tr_stream_cfg m_cfg # if (!m_cfg_dap.try_get(m_cfg)) begin # if (m_warn_null_cfg == 1) # `uvm_warning("UVM/REC_STR/NO_CFG", # $sformatf("attempt to retrieve STREAM_TYPE_NAME from '%s' before it was set!", # get_name())) # m_warn_null_cfg = 0 # return "" # end # return m_cfg.stream_type_name # endfunction : get_stream_type_name # # // Group: Stream API # // # // Once a stream has been opened via <uvm_tr_database::open_stream>, the user # // can ~close~ the stream. # // # // Due to the fact that many database implementations will require crossing # // a language boundary, an additional step of ~freeing~ the stream is required. # // # // A ~link~ can be established within the database any time between "Open" and # // "Free", however it is illegal to establish a link after "Freeing" the stream. # // # # // Function: close # // Closes this stream. # // # // Closing a stream closes all open recorders in the stream. # // # // This method will trigger a <do_close> call, followed by # // <uvm_recorder::close> on all open recorders within the # // stream. # function void close() # if (!is_open()) # return # # do_close() # # foreach (m_records[idx]) # if (idx.is_open()) # idx.close() # # m_is_opened = 0 # m_is_closed = 1 # endfunction : close # # // Function: free # // Frees this stream. # // # // Freeing a stream indicates that the database can free any # // references to the stream (including references to records # // within the stream). # // # // This method will trigger a <do_free> call, followed by # // <uvm_recorder::free> on all recorders within the stream. # function void free() # process p # string s # uvm_tr_database db # if (!is_open() && !is_closed()) # return # # if (is_open()) # close() # # do_free() # # foreach (m_records[idx]) # idx.free() # # // Clear out internal state # db = get_db() # m_is_closed = 0 # p = process::self() # if(p != None) # s = p.get_randstate() # m_cfg_dap = new("cfg_dap") # if(p != None) # p.set_randstate(s) # m_warn_null_cfg = 1 # if (m_ids_by_stream.exists(this)) # m_free_id(m_ids_by_stream[this]) # # // Clear out DB state # if (db != None) # db.m_free_stream(this) # endfunction : free
[docs] def m_do_open(self, db, scope="", stream_type_name=""): """ Function- m_do_open Initializes the state of the stream Parameters- db - Database which the stream belongs to scope - Optional scope stream_type_name - Optional type name for the stream This method will trigger a `do_open` call. An error will be asserted if- - m_do_open is called more than once without the stream being `freed` between. - m_do_open is passed a `None` db function void m_do_open(uvm_tr_database db, string scope="", string stream_type_name="") Args: db: scope: stream_type_name: """ m_cfg = [] # m_uvm_tr_stream_cfg m_db = None # uvm_tr_database if db is None: uvm_error("UVM/REC_STR/NULL_DB", sv.sformatf("Illegal attempt to set DB for '%s' to '<None>'", self.get_full_name())) return if self.m_cfg_dap.try_get(m_cfg): uvm_error("UVM/REC_STR/RE_CFG", sv.sformatf("Illegal attempt to re-open '%s'", self.get_full_name())) else: # Never set before m_cfg = m_uvm_tr_stream_cfg() m_cfg.db = db m_cfg.scope = scope m_cfg.stream_type_name = stream_type_name self.m_cfg_dap.set(m_cfg) self.m_is_opened = True self.do_open(db, scope, stream_type_name)
[docs] def is_open(self): """ Function: is_open Returns true if this `UVMTrStream` was opened on the database, but has not yet been closed. Returns: """ return self.m_is_opened
[docs] def is_closed(self): """ Function: is_closed Returns true if this `UVMTrStream` was closed on the database, but has not yet been freed. Returns: """ return self.m_is_closed
# // Group: Transaction Recorder API # // # // New recorders can be opened prior to the stream being ~closed~. # // # // Once a stream has been closed, requests to open a new recorder # // will be ignored (<open_recorder> will return ~None~). # // #
[docs] def open_recorder(self, name, open_time=0, type_name=""): """ Function: open_recorder Marks the opening of a new transaction recorder on the stream. Parameters: name - A name for the new transaction open_time - Optional time to record as the opening of this transaction type_name - Optional type name for the transaction If `open_time` is omitted (or set to 0), then the stream will use the current time. This method will trigger a `do_open_recorder` call. If `do_open_recorder` returns a non-`None` value, then the <uvm_recorder::do_open> method will be called in the recorder. Transaction recorders can only be opened if the stream is `open` on the database (per `is_open`). Otherwise the request will be ignored, and `None` will be returned. Args: name: open_time: type_name: Returns: """ m_time = open_time if open_time == 0: m_time = sv.time() # Check to make sure we're open if not self.is_open(): return None else: #process p = process::self() p = None s = "" if p is not None: s = p.get_randstate() open_recorder = self.do_open_recorder(name, m_time, type_name) if open_recorder is not None: self.m_records[open_recorder] = 1 open_recorder.m_do_open(self, m_time, type_name) if p is not None: p.set_randstate(s) return open_recorder
# endfunction : open_recorder
[docs] def m_free_recorder(self, recorder): """ Function- m_free_recorder Removes recorder from the internal array Args: recorder: """ if recorder in self.m_records: del self.m_records[recorder]
# # // Function: get_recorders # // Provides a queue of all transactions within the stream. # // # // Parameters: # // q - A reference to the queue of <uvm_recorder>s # // # // The <get_recorders> method returns the size of the queue, # // such that the user can conditionally process the elements. # // # // | uvm_recorder tr_q[$] # // | if (my_stream.get_recorders(tr_q)) begin # // | // Process the queue... # // | end # // # function unsigned get_recorders(ref uvm_recorder q[$]) # // Clear out the queue first... # q.delete() # // Fill in the values # foreach (m_records[idx]) # q.push_back(idx) # // Finally return the size of the queue # return q.size() # endfunction : get_recorders # # // Group: Handles # # // Variable- m_streams_by_id # // A corollary to ~m_ids_by_stream~, this indexes the streams by their # // unique ids. # local static UVMTrStream m_streams_by_id[integer] m_streams_by_id = {}
[docs] def get_handle(self): """ Function: get_handle Returns a unique ID for this stream. A value of `0` indicates that the recorder has been `freed`, and no longer has a valid ID. Returns: """ m_streams_by_id = UVMTrStream.m_streams_by_id m_ids_by_stream = UVMTrStream.m_ids_by_stream if self.is_open() is False and self.is_closed() is False: return 0 else: handle = self.get_inst_id() # Check for the weird case where our handle changed. if self in m_ids_by_stream and m_ids_by_stream[self] != handle: key = m_ids_by_stream[self] del m_streams_by_id[key] m_streams_by_id[handle] = self m_ids_by_stream[self] = handle return handle
# endfunction : get_handle # # // Function- m_get_handle # // Provided to allow implementation-specific handles which are not # // identical to the built-in handles. # // # // This is an implementation detail of the UVM library, which allows # // for vendors to (optionally) put vendor-specific methods into the library. # virtual function integer m_get_handle() # return get_handle() # endfunction : m_get_handle # # // Function: get_stream_from_handle # // Static accessor, returns a stream reference for a given unique id. # // # // If no stream exists with the given ~id~, or if the # // stream with that ~id~ has been freed, then ~None~ is # // returned. # // # static function UVMTrStream get_stream_from_handle(integer id) # if (id == 0) # return None # # if ($isunknown(id) || !m_streams_by_id.exists(id)) # return None # # return m_streams_by_id[id] # endfunction : get_stream_from_handle # # // Function- m_free_id # // Frees the id/stream link (memory cleanup) # // # static function void m_free_id(integer id) # UVMTrStream stream # if (!$isunknown(id) && m_streams_by_id.exists(id)) # stream = m_streams_by_id[id] # # if (stream != None) begin # m_streams_by_id.delete(id) # m_ids_by_stream.delete(stream) # end # endfunction : m_free_id # # // Group: Implementation Agnostic API # // # # // Function: do_open # // Callback triggered via <uvm_tr_database::open_stream>. # // # // Parameters: # // db - Database which the stream belongs to # // scope - Optional scope # // stream_type_name - Optional type name for the stream # // # // The ~do_open~ callback can be used to initialize any internal # // state within the stream, as well as providing a location to # // record any initial information about the stream. # protected virtual function void do_open(uvm_tr_database db, # string scope, # string stream_type_name) # endfunction : do_open # # // Function: do_close # // Callback triggered via <close>. # // # // The ~do_close~ callback can be used to set internal state # // within the stream, as well as providing a location to # // record any closing information. # protected virtual function void do_close() # endfunction : do_close # # // Function: do_free # // Callback triggered via <free>. # // # // The ~do_free~ callback can be used to release the internal # // state within the stream, as well as providing a location # // to record any "freeing" information. # protected virtual function void do_free() # endfunction : do_free # # // Function: do_open_recorder # // Marks the beginning of a new record in the stream. # // # // Backend implementation of <open_recorder> # protected virtual function uvm_recorder do_open_recorder(string name, # time open_time, # string type_name) # return None # endfunction : do_open_recorder # #endclass : UVMTrStream # #//------------------------------------------------------------------------------ #// #// CLASS: UVMTextTrStream #// #// The ~UVMTextTrStream~ is the default stream implementation for the #// <uvm_text_tr_database>. #// #// # #class UVMTextTrStream extends UVMTrStream
[docs]class UVMTextTrStream(UVMTrStream): def __init__(self, name="unnamed-UVMTextTrStream"): UVMTrStream.__init__(self, name) # // Variable- m_text_db # // Internal reference to the text-based backend self.m_text_db = None # // Group: Implementation Agnostic API
[docs] def do_open(self, db, scope, stream_type_name): """ Function: do_open Callback triggered via <uvm_tr_database::open_stream>. protected virtual function void do_open(uvm_tr_database db, string scope, string stream_type_name) Args: db: scope: stream_type_name: """ # $cast(m_text_db, db) self.m_text_db = db if self.m_text_db.open_db(): sv.fdisplay(self.m_text_db.m_file, " CREATE_STREAM @%0t [NAME:%s T:%s SCOPE:%s STREAM:%0d]", uvm_sim_time(), self.get_name(), stream_type_name, scope, self.get_handle())
# // Function: do_close # // Callback triggered via <UVMTrStream::close>. # protected virtual function void do_close() # if (m_text_db.open_db()) # $fdisplay(m_text_db.m_file, # " CLOSE_STREAM @%0t {NAME:%s T:%s SCOPE:%s STREAM:%0d}", # $time, # this.get_name(), # this.get_stream_type_name(), # this.get_scope(), # this.get_handle()) # endfunction : do_close # # // Function: do_free # // Callback triggered via <UVMTrStream::free>. # // # protected virtual function void do_free() # if (m_text_db.open_db()) # $fdisplay(m_text_db.m_file, # " FREE_STREAM @%0t {NAME:%s T:%s SCOPE:%s STREAM:%0d}", # $time, # this.get_name(), # this.get_stream_type_name(), # this.get_scope(), # this.get_handle()) # m_text_db = None # return # endfunction : do_free #
[docs] def do_open_recorder(self, name, open_time, type_name): """ Function: do_open_recorder Marks the beginning of a new record in the stream Text-backend specific implementation. Args: name: open_time: type_name: Returns: """ if self.m_text_db.open_db(): return UVMTextRecorder.type_id.create(name) return None
#endclass : UVMTextTrStream uvm_object_utils(UVMTextTrStream)