Source code for uvm.base.uvm_misc

#
#------------------------------------------------------------------------------
#   Copyright 2007-2011 Mentor Graphics Corporation
#   Copyright 2007-2011 Cadence Design Systems, Inc.
#   Copyright 2010 Synopsys, Inc.
#   Copyright 2014 NVIDIA Corporation
#   Copyright 2023 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 typing import Dict, Optional

import re
from ..macros.uvm_message_defines import uvm_error, uvm_warning
from .uvm_object_globals import (UVM_BIN, UVM_COMPARE, UVM_COPY, UVM_DEC, UVM_FLAGS,
                                 UVM_NORADIX, UVM_OCT, UVM_PACK, UVM_PRINT, UVM_RECORD, UVM_SETINT,
                                 UVM_SETOBJ, UVM_SETSTR, UVM_STRING, UVM_TIME, UVM_UNPACK,
                                 UVM_UNSIGNED, UVM_HEX)
from .uvm_scope_stack import UVMScopeStack
from .sv import sv

UVM_APPEND = 0
UVM_PREPEND = 1

UVM_ENABLE_FIELD_CHECKS = 0


[docs]def isunknown(value): return False
[docs]def uvm_get_array_index_string(arg: str, is_wildcard: int) -> str: """ Function- uvm_get_array_index_string Args: Returns: """ i = 0 res = "" is_wildcard = 1 i = len(arg) - 1 if arg[i] == "]": while (i > 0 and (arg[i] != "[")): if ((arg[i] == "*") or (arg[i] == "?")): i = 0 i -= 1 if i > 0: res = arg[i+1: len(arg)-1] is_wildcard = 0 return res
[docs]def uvm_bitstream_to_string(value, size, radix=UVM_NORADIX, radix_str="") -> str: """ Function- uvm_bitstream_to_string Args: value (int): size: radix: radix_str: Returns: str: Given number as string. """ # sign extend & don't show radix for negative values if radix == UVM_DEC and (value >> (size-1)): return "{}".format(value) # TODO $countbits(value,'z) would be even better if isunknown(value): _t = 0 for idx in range(0, size): _t[idx] = value[idx] value = _t else: value &= (1 << size) - 1 return num_with_radix(radix, radix_str, value)
[docs]def uvm_integral_to_string(value, size, radix=UVM_NORADIX, radix_str="") -> str: """ Function- uvm_integral_to_string Args: value (int): size (int): radix: radix_str (str): Returns: str: """ # sign extend & don't show radix for negative values if radix == UVM_DEC and (value >> (size-1)) == 1: return "{}".format(value) # TODO $countbits(value,'z) would be even better if isunknown(value) is True: _t = 0 for idx in range(0, size): _t[idx] = value[idx] value = _t else: value &= (1 << size) - 1 return num_with_radix(radix, radix_str, value)
[docs]def uvm_object_value_str(v) -> str: """ Function- uvm_object_value_str Args: v (object): Object to convert to string. Returns: str: Inst ID for `UVMObject`, otherwise uses str() """ if v is None: return "<null>" res = "" if hasattr(v, 'get_inst_id'): res = "{}".format(v.get_inst_id()) res = "@" + res else: res = str(v) return res
[docs]def uvm_leaf_scope(full_name: str, scope_separator=".") -> str: """ Function- uvm_leaf_scope Args: full_name (str): scope_separator (str): Returns: str: Leaf scope name without any brackets/indexing. """ bmatches = 0 bracket_match = get_bracket_match(scope_separator) # Only use bracket matching if the input string has the end match if bracket_match != "" and bracket_match != full_name[-1]: bracket_match = "" if bracket_match == "": regex = re.compile(scope_separator) if scope_separator == ".": regex = re.compile(r"\.") if not regex.search(full_name): return full_name pos = 0 for pos in range(len(full_name) - 1, 0, -1): if full_name[pos] == bracket_match: bmatches += 1 elif full_name[pos] == scope_separator: bmatches -= 1 if bmatches == 0 or bracket_match == "": break res = "" if pos > 0: max_pos = len(full_name) if scope_separator != ".": pos -= 1 max_pos -= 1 if full_name[pos+1] == scope_separator: pos += 1 res = full_name[pos+1:max_pos] else: res = full_name return res
[docs]def get_bracket_match(scope_separator: str) -> str: bracket_match = "" if scope_separator == "[": bracket_match = "]" elif scope_separator == "(": bracket_match = ")" elif scope_separator == "<": bracket_match = ">" elif scope_separator == "{": bracket_match = "}" return bracket_match
[docs]def num_with_radix(radix, radix_str: str, value) -> str: if radix == UVM_BIN: return "{}{:b}".format(radix_str, value) if radix == UVM_OCT: return "{}{}".format(radix_str, value) if radix == UVM_UNSIGNED: return "{}{}".format(radix_str, value) if radix == UVM_STRING: return "{}{}".format(radix_str, value) if radix == UVM_TIME: return "{}{}".format(radix_str, value) if radix == UVM_DEC: return "{}{}".format(radix_str, value) if radix == UVM_HEX: return "{}{:X}".format(radix_str, value) return "{}{}".format(radix_str, value)
[docs]class ProcessContainerC: def __init__(self, p_): self.p = p_
[docs]class UVMStatusContainer: """ Internal class to contain status information for automation methods. """ # static bit field_array[string]; field_array: Dict[str, bool] = {} # static bit print_matches; print_matches = False def __init__(self): """ The clone setting is used by the set/get config to know if cloning is on. """ self.clone = True # Information variables used by the macro functions for storage. self.warning = False self.status = False self.bitstream = 0 self.intv = 0 self.element = 0 self.stringv = "" self.scratch1 = "" self.scratch2 = "" self.key = "" self.object = None self.array_warning_done = False # The scope stack is used for messages that are emitted by policy classes. self.scope = UVMScopeStack() self.m_uvm_cycle_scopes = [] # uvm_object [$]; # //Used for checking cycles. When a data function is entered, if the depth is # //non-zero, then then the existeance of the object in the map means that a # //cycle has occured and the function should immediately exit. When the # //function exits, it should reset the cycle map so that there is no memory # //leak. self.cycle_check = {} # bit cycle_check[uvm_object]; # //These are the policy objects currently in use. The policy object gets set # //when a function starts up. The macros use this. # self.comparer = None # UVMComparer # self.packer = None # UVMPacker # self.recorder = None # UVMRecorder # self.printer = None # UVMPrinter
[docs] def do_field_check(self, field, obj): if UVM_ENABLE_FIELD_CHECKS: if field in self.field_array: uvm_error("MLTFLD", "Field {} is defined multiple times in type '{}'". format(field, obj.get_type_name())) UVMStatusContainer.field_array[field] = 1
[docs] def get_function_type(self, what: int) -> str: if what == UVM_COPY: return "copy" elif what == UVM_COMPARE: return "compare" elif what == UVM_PRINT: return "print" elif what == UVM_RECORD: return "record" elif what == UVM_PACK: return "pack" elif what == UVM_UNPACK: return "unpack" elif what == UVM_FLAGS: return "get_flags" elif what == UVM_SETINT: return "set" elif what == UVM_SETOBJ: return "set_object" elif what == UVM_SETSTR: return "set_string" else: return "unknown"
[docs] def get_full_scope_arg(self): """ Returns: """ return self.scope.get()
# // utility function used to perform a cycle check when config setting are pushed # // to uvm_objects. the function has to look at the current object stack representing # // the call stack of all __m_uvm_field_automation() invocations. # // it is a only a cycle if the previous __m_uvm_field_automation call scope # // is not identical with the current scope AND the scope is already present in the # // object stack
[docs] def m_do_cycle_check(self, scope): ll = None if len(self.m_uvm_cycle_scopes) > 0: ll = self.m_uvm_cycle_scopes # we have been in this scope before (but actually right before so assuming a super/derived # context of the same object) if ll == scope: self.m_uvm_cycle_scopes.append(scope) return 0 else: # now check if we have already been in this scope before idx = -1 #uvm_object m[$] = m_uvm_cycle_scopes.find_first(item) with (item == scope); for i in range(len(self.m_uvm_cycle_scopes)): if self.m_uvm_cycle_scopes[i] == scope: idx = i break if idx != -1: return 1 # detected a cycle else: self.m_uvm_cycle_scopes.append(scope) return 0
[docs]def m_uvm_string_queue_join(i: int) -> str: res = "" for idx in range(len(i)): res = res + i[idx] return res
#//------------------------------------------------------------------------------ #// CLASS: uvm_utils #(TYPE,FIELD) #// #// This class contains useful template functions. #// #//------------------------------------------------------------------------------
[docs]class UVMUtils(): # (type TYPE=int, string FIELD="config")
[docs] @classmethod def find_all(cls, start, TYPE): """ Function: find_all Recursively finds all component instances of the parameter type `TYPE`, starting with the component given by `start`. Uses <uvm_root::find_all>. Args: start: TYPE: Returns: """ from .uvm_coreservice import UVMCoreService comp_list = [] types = [] cs = UVMCoreService.get() top = cs.get_root() top.find_all("*", comp_list, start) for comp in comp_list: typ = [] if sv.cast(typ, comp, TYPE): types.append(typ[0]) if len(types) == 0: uvm_warning("find_type-no match", "Instance of type '" + TYPE.type_name + " not found in component hierarchy beginning at " + start.get_full_name()) return types
# static def find(self,uvm_component start): # types_t types = find_all(start) # if (types.size() == 0) # return None # if (types.size() > 1): # uvm_warning("find_type-multi match",{"More than one instance of type '",TYPE::type_name, # " found in component hierarchy beginning at ",start.get_full_name()}) # return None # end # return types[0] # endfunction #
[docs] @classmethod def create_type_by_name(cls, type_name, contxt): from .uvm_coreservice import UVMCoreService obj = None typ = None # TYPE cs = UVMCoreService.get() factory = cs.get_factory() obj = factory.create_object_by_name(type_name,contxt,type_name) typ = obj # TODO cast # if (!sv.cast(typ,obj)) # uvm_error("WRONG_TYPE",{"The type_name given '",type_name, # "' with context '",contxt,"' did not produce the expected type."}) return typ
[docs] @classmethod def get_config(cls, comp, is_fatal): """ This method gets the object config of type `TYPE` associated with component `comp`. We check for the two kinds of error which may occur with this kind of operation. Args: cls: comp: is_fatal: Returns: """ obj = None cfg = None # TODO # # if (!m_uvm_config_obj_misc::get(comp,"",FIELD, obj)): # if (is_fatal) # comp.uvm_report_fatal("NO_SET_CFG", {"no set_config to field '", FIELD, # "' for component '",comp.get_full_name(),"'"}, # UVM_MEDIUM, `uvm_file , `uvm_line ) # else # comp.uvm_report_warning("NO_SET_CFG", {"no set_config to field '", FIELD, # "' for component '",comp.get_full_name(),"'"}, # UVM_MEDIUM, `uvm_file , `uvm_line ) # return None # end # # if (!sv.cast(cfg, obj)): # if (is_fatal) # comp.uvm_report_fatal( "GET_CFG_TYPE_FAIL", # {"set_config_object with field name ",FIELD, # " is not of type '",TYPE::type_name,"'"}, # UVM_NONE , `uvm_file , `uvm_line ) # else # comp.uvm_report_warning( "GET_CFG_TYPE_FAIL", # {"set_config_object with field name ",FIELD, # " is not of type '",TYPE::type_name,"'"}, # UVM_NONE , `uvm_file , `uvm_line ) # end # return cfg