Source code for uvm.base.uvm_recorder

#//
#//-----------------------------------------------------------------------------
#//   Copyright 2007-2011 Mentor Graphics Corporation
#//   Copyright 2007-2011 Cadence Design Systems, Inc.
#//   Copyright 2010 Synopsys, Inc.
#//   Copyright 2013 NVIDIA Corporation
#//   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 ..dap import uvm_set_before_get_dap
from .uvm_object import UVMObject
from .uvm_object_globals import *
from .uvm_misc import uvm_bitstream_to_string, uvm_integral_to_string
from .sv import sv
from ..macros import uvm_object_utils, uvm_warning, uvm_error
from .uvm_scope_stack import UVMScopeStack
from .uvm_globals import uvm_string_to_bits


"""
File: UVM Recorders

The `UVMRecorder` class serves two purposes:
 - Firstly, it is an abstract representation of a record within a
   `UVMTrStream`.
 - Secondly, it is a policy object for recording fields ~into~ that
   record within the ~stream~.

"""



[docs]class UVMRecorder(UVMObject): """ CLASS: UVMRecorder Abstract class which defines the ~recorder~ API. """ # // Variable- m_ids_by_recorder # // A dict of integers, indexed by `UVMRecorder`s. This # // provides a unique 'id' or 'handle' for each recorder, which can be # // used to identify the recorder. # // # // By default, neither ~m_ids_by_recorder~ or ~m_recorders_by_id~ are # // used. Recorders are only placed in the arrays when the user # // attempts to determine the id for a recorder. # local static integer m_ids_by_recorder[uvm_recorder] m_ids_by_recorder = {} def __init__(self, name="uvm_recorder"): UVMObject.__init__(self, name) # // Variable- m_stream_dap # // Data access protected reference to the stream # uvm_set_before_get_dap#(uvm_tr_stream) m_stream_dap self.m_stream_dap = uvm_set_before_get_dap("stream_dap") # // Variable- m_warn_null_stream # // Used to limit the number of warnings self.m_warn_null_stream = True # # // Variable- m_is_opened # // Used to indicate recorder is open self.m_is_opened = False # # // Variable- m_is_closed # // Used to indicate recorder is closed self.m_is_closed = False # # // !m_is_opened && !m_is_closed == m_is_freed # # // Variable- m_open_time # // Used to store the open_time self.m_open_time = 0 # # // Variable- m_close_time # // Used to store the close_time self.m_close_time = 0 # # // Variable- recording_depth self.recording_depth = 0 # # // Variable: default_radix # // # // This is the default radix setting if <record_field> is called without # // a radix. # self.default_radix = UVM_HEX # # // Variable: physical # // # // This bit provides a filtering mechanism for fields. # // # // The <abstract> and physical settings allow an object to distinguish between # // two different classes of fields. # // # // It is up to you, in the <uvm_object::do_record> method, to test the # // setting of this field if you want to use the physical trait as a filter. # self.physical = True # # # // Variable: abstract # // # // This bit provides a filtering mechanism for fields. # // # // The abstract and physical settings allow an object to distinguish between # // two different classes of fields. # // # // It is up to you, in the <uvm_object::do_record> method, to test the # // setting of this field if you want to use the abstract trait as a filter. # self.abstract = True # # # // Variable: identifier # // # // This bit is used to specify whether or not an object's reference should be # // recorded when the object is recorded. # self.identifier = 1 # # # // Variable: recursion_policy # // # // Sets the recursion policy for recording objects. # // # // The default policy is deep (which means to recurse an object). ## uvm_recursion_policy_enum self.policy = UVM_DEFAULT_POLICY #
[docs] def get_stream(self): """ Group: Configuration API Function: get_stream Returns a reference to the stream which created this record. A warning will be asserted if get_stream is called prior to the record being initialized via `do_open`. Returns: """ astr = [] if not self.m_stream_dap.try_get(astr): if self.m_warn_null_stream == 1: uvm_warning("UVM/REC/NO_CFG", sv.sformatf("attempt to retrieve STREAM from '%s' before it was set!", self.get_name())) self.m_warn_null_stream = 0 if len(astr): return astr[0]
# // Group: Transaction Recorder API # // # // Once a recorder has been opened via <uvm_tr_stream::open_recorder>, the user # // can ~close~ the recorder. # // # // Due to the fact that many database implementations will require crossing # // a language boundary, an additional step of ~freeing~ the recorder 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 recorder. # //
[docs] def close(self, close_time=0): """ Function: close Closes this recorder. Closing a recorder marks the end of the transaction in the stream. Parameters: close_time - Optional time to record as the closing time of this transaction. This method will trigger a `do_close` call. Args: close_time: """ if (close_time == 0): close_time = sv.realtime() if self.is_open() is False: return self.do_close(close_time) self.m_is_opened = 0 self.m_is_closed = 1 self.m_close_time = close_time
[docs] def free(self, close_time=0): """ Function: free Frees this recorder Freeing a recorder indicates that the stream and database can release any references to the recorder. If a recorder has not yet been closed (via a call to `close`), then `close` will automatically be called, and passed the `close_time`. If the recorder has already been closed, then the `close_time` will be ignored. This method will trigger a `do_free` call. Args: close_time (int): Optional time to record as the closing time of this transaction. """ # process p=process::self() p = None s = "" stream = None # uvm_tr_stream if not self.is_open() and not self.is_closed(): return if self.is_open(): self.close(close_time) self.do_free() # Clear out internal state stream = self.get_stream() self.m_is_closed = 0 if p is not None: s = p.get_randstate() self.m_stream_dap = uvm_set_before_get_dap("stream_dap") if p is not None: p.set_randstate(s) self.m_warn_null_stream = 1 if self in UVMRecorder.m_ids_by_recorder: UVMRecorder.m_free_id(UVMRecorder.m_ids_by_recorder[self]) # Clear out stream state if stream is not None: stream.m_free_recorder(self)
[docs] def is_open(self): """ Function: is_open Returns true if this `uvm_recorder` was opened on its stream, but has not yet been closed. Returns: """ return self.m_is_opened
[docs] def get_open_time(self): """ Function: get_open_time Returns the `open_time` Returns: """ return self.m_open_time
[docs] def is_closed(self): """ Function: is_closed Returns true if this `uvm_recorder` was closed on its stream, but has not yet been freed. Returns: """ return self.m_is_closed
[docs] def get_close_time(self): """ Function: get_close_time Returns the `close_time` Returns: """ return self.m_close_time
[docs] def m_do_open(self, stream, open_time, type_name): """ Function- m_do_open Initializes the internal state of the recorder. Parameters: stream - The stream which spawned this recorder This method will trigger a `do_open` call. An error will be asserted if: - `m_do_open` is called more than once without the recorder being `freed` in between. - `stream` is `null` Args: stream: open_time: type_name: """ m_stream = [] if stream is None: uvm_error("UVM/REC/NULL_STREAM", sv.sformatf("Illegal attempt to set STREAM for '%s' to '<null>'", self.get_name())) return if self.m_stream_dap.try_get(m_stream): uvm_error("UVM/REC/RE_INIT", sv.sformatf("Illegal attempt to re-initialize '%s'", self.get_name())) return self.m_stream_dap.set(stream) self.m_open_time = open_time self.m_is_opened = 1 self.do_open(stream, open_time, type_name)
# // Group: Handles # // Variable- m_recorders_by_id # // A corollary to ~m_ids_by_recorder~, this indexes the recorders by their # // unique ids. # local static uvm_recorder m_recorders_by_id[integer] m_recorders_by_id = {} # // Variable- m_id # // Static int marking the last assigned id. # local static integer m_id
[docs] @classmethod def m_free_id(cls, id): """ Function- m_free_id Frees the id/recorder link (memory cleanup) Args: cls: id: """ recorder = None # uvm_recorder if ((not sv.isunknown(id)) and (id in cls.m_recorders_by_id)): recorder = cls.m_recorders_by_id[id] if recorder is not None: del cls.m_recorders_by_id[id] del cls.m_ids_by_recorder[recorder]
[docs] def get_handle(self): """ Function: get_handle Returns a unique ID for this recorder. A value of `0` indicates that the recorder has been `freed`, and no longer has a valid ID. Returns: """ if (self.is_open() is False and self.is_closed() is False): return 0 else: handle = self.get_inst_id() m_ids_by_rec = UVMRecorder.m_ids_by_recorder # Check for the weird case where our handle changed. if self in m_ids_by_rec and m_ids_by_rec[self] != handle: this_id = UVMRecorder.m_ids_by_recorder[self] del UVMRecorder.m_recorders_by_id[this_id] UVMRecorder.m_recorders_by_id[handle] = self UVMRecorder.m_ids_by_recorder[self] = handle return handle
# endfunction : get_handle
[docs] @classmethod def get_recorder_from_handle(cls, id): """ Static accessor, returns a recorder reference for a given unique id. If no recorder exists with the given `id`, or if the recorder with that `id` has been freed, then `null` is returned. This method can be used to access the recorder associated with a call to `UVMTransaction.begin_tr` or `UVMComponent.begin_tr`. .. code-block:: python handle = tr.begin_tr() recorder = UVMRecorder.get_recorder_from_handle(handle) if recorder is not None: recorder.record_string("begin_msg", "Started recording transaction!") Args: cls: id: Returns: UVMRecorder: """ if id == 0: return None if sv.isunknown(id) or id not in cls.m_recorders_by_id: return None return cls.m_recorders_by_id[id]
# // Group: Attribute Recording # # // Function: record_field # // Records an integral field (less than or equal to 4096 bits). # // # // Parameters: # // name - Name of the field # // value - Value of the field to record. # // size - Number of bits of the field which apply (Usually obtained via $bits). # // radix - The <uvm_radix_enum> to use. # // # // This method will trigger a <do_record_field> call.
[docs] def record_field(self, name, value, size, radix=UVM_NORADIX): if self.get_stream() is None: return self.do_record_field(name, value, size, radix)
# // Function: record_field_int # // Records an integral field (less than or equal to 64 bits). # // # // This optimized version of <record_field> is useful for sizes up # // to 64 bits. # // # // Parameters: # // name - Name of the field # // value - Value of the field to record # // size - Number of bits of the wfield which apply (Usually obtained via $bits). # // radix - The <uvm_radix_enum> to use. # // # // This method will trigger a <do_record_field_int> call.
[docs] def record_field_int(self,name, value, size, radix=UVM_NORADIX): if self.get_stream() is None: return self.do_record_field_int(name, value, size, radix)
# // Function: record_field_real # // Records a real field. # // # // Parameters: # // name - Name of the field # // value - Value of the field to record # // # // This method will trigger a <do_record_field_real> call. # function void record_field_real(string name, # real value) # if (get_stream() is None): # return # end # do_record_field_real(name, value) # endfunction : record_field_real # // Function: record_object # // Records an object field. # // # // Parameters: # // name - Name of the field # // value - Object to record # // # // The implementation must use the <recursion_policy> and <identifier> to # // determine exactly what should be recorded.
[docs] def record_object(self, name, value): if (self.get_stream() is None): return self.do_record_object(name, value)
# // Function: record_string # // Records a string field. # // # // Parameters: # // name - Name of the field # // value - Value of the field # //
[docs] def record_string(self, name, value): if (self.get_stream() is None): return self.do_record_string(name, value)
# // Function: record_time # // Records a time field. # // # // Parameters: # // name - Name of the field # // value - Value of the field # // # function void record_time(string name, # time value) # if (get_stream() is None): # return # end # # do_record_time(name, value) # endfunction : record_time # # // Function: record_generic # // Records a name/value pair, where ~value~ has been converted to a string. # // # // For example: # //| recorder.record_generic("myvar","var_type", sv.sformatf("%0d",myvar), 32) # // # // Parameters: # // name - Name of the field # // value - Value of the field # // type_name - ~optional~ Type name of the field # function void record_generic(string name, # string value, # string type_name="") # if (get_stream() is None): # return # end # # do_record_generic(name, value, type_name) # endfunction : record_generic # // Function: use_record_attribute # // # // Indicates that this recorder does (or does not) support usage of # // the <`uvm_record_attribute> macro. # // # // The default return value is ~0~ (not supported), developers can # // optionally extend ~uvm_recorder~ and set the value to ~1~ if they # // support the <`uvm_record_attribute> macro.
[docs] def use_record_attribute(self): return 0
# // Function: get_record_attribute_handle # // Provides a tool-specific handle which is compatible with <`uvm_record_attribute>. # // # // By default, this method will return the same value as <get_handle>, # // however tool vendors can override this method to provide tool-specific handles # // which will be passed to the <`uvm_record_attribute> macro. # // # virtual function integer get_record_attribute_handle() # return get_handle() # endfunction : get_record_attribute_handle # # // Group: Implementation Agnostic API #
[docs] def do_open(self, stream, open_time, type_name): """ Function: do_open Callback triggered via <uvm_tr_stream::open_recorder>. The `do_open` callback can be used to initialize any internal state within the recorder, as well as providing a location to record any initial information. Args: stream: open_time: type_name: """ pass
# # // Function: do_close # // Callback triggered via <close>. # // # // The ~do_close~ callback can be used to set internal state # // within the recorder, as well as providing a location to # // record any closing information.
[docs] def do_close(self, close_time): pass
# // Function: do_free # // Callback triggered via <free>. # // # // The ~do_free~ callback can be used to release the internal # // state within the recorder, as well as providing a location # // to record any "freeing" information.
[docs] def do_free(self): pass
# // Function: do_record_field # // Records an integral field (less than or equal to 4096 bits). # // # // ~Mandatory~ Backend implementation of <record_field> # pure virtual protected function void do_record_field(string name, # uvm_bitstream_t value, # int size, # uvm_radix_enum radix) # // Function: do_record_field_int # // Records an integral field (less than or equal to 64 bits). # // # // ~Mandatory~ Backend implementation of <record_field_int> # pure virtual protected function void do_record_field_int(string name, # uvm_integral_t value, # int size, # uvm_radix_enum radix) # # // Function: do_record_field_real # // Records a real field. # // # // ~Mandatory~ Backend implementation of <record_field_real> # pure virtual protected function void do_record_field_real(string name, # real value) # # // Function: do_record_object # // Records an object field. # // # // ~Mandatory~ Backend implementation of <record_object> # pure virtual protected function void do_record_object(string name, # uvm_object value) # # // Function: do_record_string # // Records a string field. # // # // ~Mandatory~ Backend implementation of <record_string> # pure virtual protected function void do_record_string(string name, # string value) # # // Function: do_record_time # // Records a time field. # // # // ~Mandatory~ Backend implementation of <record_time> # pure virtual protected function void do_record_time(string name, # time value) # # // Function: do_record_generic # // Records a name/value pair, where ~value~ has been converted to a string. # // # // ~Mandatory~ Backend implementation of <record_generic> # pure virtual protected function void do_record_generic(string name, # string value, # string type_name) # # # // The following code is primarily for backwards compat. purposes. "Transaction # // Handles" are useful when connecting to a backend, but when passing the information # // back and forth within simulation, it is safer to user the ~recorder~ itself # // as a reference to the transaction within the database. # # //------------------------------ # // Group- Vendor-Independent API # //------------------------------ # # # // UVM provides only a text-based default implementation. # // Vendors provide subtype implementations and overwrite the # // <uvm_default_recorder> handle. # # # // Function- open_file # // # // Opens the file in the <filename> property and assigns to the # // file descriptor <file>. # // # virtual function bit open_file() # return 0 # endfunction # # // Function- create_stream # // # // # virtual function integer create_stream (string name, # string t, # string scope) # return -1 # endfunction # # # // Function- m_set_attribute # // # // # virtual function void m_set_attribute (integer txh, # string nm, # string value) # endfunction # # # // Function- set_attribute # // # virtual function void set_attribute (integer txh, # string nm, # logic [1023:0] value, # uvm_radix_enum radix, # integer numbits=1024) # endfunction # # # // Function- check_handle_kind # // # // # virtual function integer check_handle_kind (string htype, integer handle) # return 0 # endfunction # # # // Function- begin_tr # // # // # virtual function integer begin_tr(string txtype, # integer stream, # string nm, # string label="", # string desc="", # time begin_time=0) # return -1 # endfunction # # # // Function- end_tr # // # // # virtual function void end_tr (integer handle, time end_time=0) # endfunction # # # // Function- link_tr # // # // # virtual function void link_tr(integer h1, # integer h2, # string relation="") # endfunction # # # # // Function- free_tr # // # // # virtual function void free_tr(integer handle) # endfunction # #endclass // uvm_recorder # #//------------------------------------------------------------------------------ #// #// CLASS: uvm_text_recorder #// #// The ~uvm_text_recorder~ is the default recorder implementation for the #// <uvm_text_tr_database>. #//
[docs]class UVMTextRecorder(UVMRecorder): def __init__(self, name="unnamed-uvm_text_recorder"): """ Function: new Constructor Parameters: name - Instance name Args: name: """ super().__init__(name) # Variable- m_text_db # Reference to the text database backend self.m_text_db = None # # uvm_text_tr_database # Variable- scope # Imeplementation detail self.scope = UVMScopeStack()
[docs] def do_open(self, stream, open_time, type_name): """ Group: Implementation Agnostic API Function: do_open Callback triggered via <uvm_tr_stream::open_recorder>. Text-backend specific implementation. Args: stream: open_time: type_name: """ self. m_text_db = stream.get_db() if self.m_text_db.open_db(): sv.fdisplay(self.m_text_db.m_file, " OPEN_RECORDER @%0t {{TXH:%0d STREAM:%0d NAME:%s TIME:%0t TYPE=\"%0s\"}}", sv.realtime(), self.get_handle(), stream.get_handle(), self.get_name(), open_time, type_name)
[docs] def do_close(self, close_time): """ Function: do_close Callback triggered via <uvm_recorder::close>. Text-backend specific implementation. Args: close_time: """ if self.m_text_db.open_db(): sv.fdisplay(self.m_text_db.m_file, " CLOSE_RECORDER @%0t {{TXH:%0d TIME=%0t}}", sv.realtime(), self.get_handle(), close_time)
[docs] def do_free(self): """ Function: do_free Callback triggered via <uvm_recorder::free>. Text-backend specific implementation. """ if self.m_text_db.open_db(): sv.fdisplay(self.m_text_db.m_file, " FREE_RECORDER @%0t {{TXH:%0d}}", sv.realtime(), self.get_handle()) self.m_text_db = None
# // Function: do_record_field # // Records an integral field (less than or equal to 4096 bits). # // # // Text-backend specific implementation. # protected virtual function void do_record_field(string name, # uvm_bitstream_t value, # int size, # uvm_radix_enum radix)
[docs] def do_record_field(self, name, value, size, radix): self.scope.set_arg(name) if not radix: radix = self.default_radix self.write_attribute(self.scope.get(), value, radix, size)
# // Function: do_record_field_int # // Records an integral field (less than or equal to 64 bits). # // # // Text-backend specific implementation.
[docs] def do_record_field_int(self, name, value, size, radix): self.scope.set_arg(name) if not radix: radix = self.default_radix self.write_attribute_int(self.scope.get(), value, radix, size)
# // Function: do_record_field_real # // Record a real field. # // # // Text-backened specific implementation. # protected virtual function void do_record_field_real(string name, # real value) # bit [63:0] ival = $realtobits(value) # scope.set_arg(name) # # write_attribute_int(scope.get(), # ival, # UVM_REAL, # 64) # endfunction : do_record_field_real # # // Function: do_record_object # // Record an object field. # // # // Text-backend specific implementation. # // # // The method uses ~identifier~ to determine whether or not to # // record the object instance id, and ~recursion_policy~ to # // determine whether or not to recurse into the object.
[docs] def do_record_object(self, name, value): v = 0 _str = "" if self.identifier: if value is not None: _str = str(value.get_inst_id()) v = int(_str) self.scope.set_arg(name) self.write_attribute_int(self.scope.get(), v, UVM_DEC, 32) if self.policy != UVM_REFERENCE: if value is not None: if value in value._m_uvm_status_container.cycle_check: return value._m_uvm_status_container.cycle_check[value] = 1 self.scope.down(name) value.record(self) self.scope.up() del value._m_uvm_status_container.cycle_check[value]
# // Function: do_record_string # // Records a string field. # // # // Text-backend specific implementation.
[docs] def do_record_string(self, name, value): self.scope.set_arg(name) if self.m_text_db.open_db(): sv.fdisplay(self.m_text_db.m_file, " SET_ATTR @%0t {{TXH:%0d NAME:%s VALUE:%s RADIX:%s BITS=%0d}}", sv.realtime(), self.get_handle(), self.scope.get(), value, "UVM_STRING", 8 + len(value))
# // Function: do_record_time # // Records a time field. # // # // Text-backend specific implementation.
[docs] def do_record_time(self, name,value): self.scope.set_arg(name) self.write_attribute_int(self.scope.get(), value, UVM_TIME, 64)
# // Function: do_record_generic # // Records a name/value pair, where ~value~ has been converted to a string. # // # // Text-backend specific implementation.
[docs] def do_record_generic(self, name, value, type_name): self.scope.set_arg(name) self.write_attribute(self.scope.get(), uvm_string_to_bits(value), UVM_STRING, 8+len(value))
# // Group: Implementation Specific API # // Function: write_attribute # // Outputs an integral attribute to the textual log # // # // Parameters: # // nm - Name of the attribute # // value - Value # // radix - Radix of the output # // numbits - number of valid bits # function void write_attribute(string nm, # uvm_bitstream_t value, # uvm_radix_enum radix, # integer numbits=$bits(uvm_bitstream_t))
[docs] def write_attribute(self, nm, value, radix, numbits=32): if self.m_text_db.open_db(): sv.fdisplay(self.m_text_db.m_file, " SET_ATTR @%0t {{TXH:%0d NAME:%s VALUE:%s RADIX:%s BITS=%0d}}", sv.realtime(), self.get_handle(), nm, uvm_bitstream_to_string(value, numbits, radix), UVM_RADIX_TO_STRING_DICT[radix], numbits)
# // Function: write_attribute_int # // Outputs an integral attribute to the textual log # // # // Parameters: # // nm - Name of the attribute # // value - Value # // radix - Radix of the output # // numbits - number of valid bits
[docs] def write_attribute_int(self, nm, value, radix, numbits=32): if self.m_text_db.open_db(): sv.fdisplay(self.m_text_db.m_file, " SET_ATTR @%0t {{TXH:%0d NAME:%s VALUE:%s RADIX:%s BITS=%0d}}", sv.realtime(), self.get_handle(), nm, uvm_integral_to_string(value, numbits, radix), UVM_RADIX_TO_STRING_DICT[radix], numbits)
# // UVM provides only a text-based default implementation. # // Vendors provide subtype implementations and overwrite the # // <uvm_default_recorder> handle. # # string filename # bit filename_set # # // Function- open_file # // # // Opens the file in the <filename> property and assigns to the # // file descriptor <file>. # // # virtual function bit open_file() # if (!filename_set): # m_text_db.set_file_name(filename) # end # return m_text_db.open_db() # endfunction # // Function- create_stream # // # // # virtual function integer create_stream (string name, # string t, # string scope) # uvm_text_tr_stream stream # if (open_file()): # $cast(stream,m_text_db.open_stream(name, scope, t)) # return stream.get_handle() # end # return 0 # endfunction # // Function- m_set_attribute # // # // # virtual function void m_set_attribute (integer txh, # string nm, # string value) # if (open_file()): # UVM_FILE file = m_text_db.m_file # $fdisplay(file," SET_ATTR @%0t {TXH:%0d NAME:%s VALUE:%s}", $realtime,txh,nm,value) # end # endfunction # # # // Function- set_attribute # // # // # virtual function void set_attribute (integer txh, # string nm, # logic [1023:0] value, # uvm_radix_enum radix, # integer numbits=1024) # if (open_file()): # UVM_FILE file = m_text_db.m_file # $fdisplay(file, # " SET_ATTR @%0t {TXH:%0d NAME:%s VALUE:%s RADIX:%s BITS=%0d}", # $realtime, # txh, # nm, # uvm_bitstream_to_string(value, numbits, radix), # radix.name(), # numbits) # # end # endfunction # # # // Function- check_handle_kind # // # // # virtual function integer check_handle_kind (string htype, integer handle) # return ((uvm_recorder::get_recorder_from_handle(handle) != null) || # (uvm_tr_stream::get_stream_from_handle(handle) != null)) # endfunction # // Function- begin_tr # // # // # virtual function integer begin_tr(string txtype, # integer stream, # string nm, # string label="", # string desc="", # time begin_time=0) # if (open_file()): # uvm_tr_stream stream_obj = uvm_tr_stream::get_stream_from_handle(stream) # uvm_recorder recorder # # if (stream_obj is None) # return -1 # # recorder = stream_obj.open_recorder(nm, begin_time, txtype) # # return recorder.get_handle() # end # return -1 # endfunction # # # // Function- end_tr # // # // # virtual function void end_tr (integer handle, time end_time=0) # if (open_file()): # uvm_recorder record = uvm_recorder::get_recorder_from_handle(handle) # if (record != null): # record.close(end_time) # end # end # endfunction # # # // Function- link_tr # // # // # virtual function void link_tr(integer h1, # integer h2, # string relation="") # if (open_file()) # $fdisplay(self.m_text_db.m_file," LINK @%0t {TXH1:%0d TXH2:%0d RELATION=%0s}", $realtime,h1, # h2,relation) # endfunction # // Function- free_tr # // # // # virtual function void free_tr(integer handle) # if (open_file()): # uvm_recorder record = uvm_recorder::get_recorder_from_handle(handle) # if (record != null): # record.free() # end # end # endfunction // free_tr uvm_object_utils(UVMTextRecorder)