#
#------------------------------------------------------------------------------
# Copyright 2007-2010 Mentor Graphics Corporation
# Copyright 2007-2010 Cadence Design Systems, Inc.
# Copyright 2010 Synopsys, Inc.
# Copyright 2019 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.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# Title: Factory Component and Object Wrappers
#
# Topic: Intro
#
# This section defines the proxy component and object classes used by the
# factory. To avoid the overhead of creating an instance of every component
# and object that get registered, the factory holds lightweight wrappers,
# or proxies. When a request for a new object is made, the factory calls upon
# the proxy to create the object it represents.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
#
# CLASS: uvm_component_registry #(T,Tname)
#
# The uvm_component_registry serves as a lightweight proxy for a component of
# type ~T~ and type name ~Tname~, a string. The proxy enables efficient
# registration with the <uvm_factory>. Without it, registration would
# require an instance of the component itself.
#
# See <Usage> section below for information on using uvm_component_registry.
#
#------------------------------------------------------------------------------
from .uvm_factory import UVMObjectWrapper
from .uvm_globals import uvm_report_warning, uvm_report_fatal
from .uvm_object_globals import UVM_NONE
[docs]def get_factory():
from .uvm_coreservice import UVMCoreService
cs = UVMCoreService.get()
return cs.get_factory()
[docs]class UVMComponentRegistry(UVMObjectWrapper):
# dict of UVMComponentRegistry
registry_db = {} # tname -> UVMComponentRegistry
registered = {} # tname -> bool
# Stores the actual constructors
comps = {}
def __init__(self, Constr, tname):
self.Constr = Constr
self.tname = tname
self.type_name = tname
if tname in UVMComponentRegistry.registry_db:
uvm_report_warning("COMP_REGD", (tname + ' has already been'
+ ' added into the UVMComponentRegistry'))
UVMComponentRegistry.comps[tname] = Constr
UVMComponentRegistry.registered[tname] = False
UVMComponentRegistry.registry_db[tname] = self.get()
[docs] @classmethod
def reset(cls):
"""Resets the state of the component registry. Used for unit testing"""
UVMComponentRegistry.registry_db.clear()
UVMComponentRegistry.registered.clear()
UVMComponentRegistry.comps.clear()
[docs] def create_component(self, name, parent):
"""
Function: create_component
Creates a component of type T having the provided `name` and `parent`.
This is an override of the method in `uvm_object_wrapper`. It is
called by the factory after determining the type of object to create.
You should not call this method directly. Call `create` instead.
Args:
name:
parent:
Returns:
"""
return UVMComponentRegistry.comps[self.tname](name, parent)
[docs] def get_type_name(self):
"""
Function: get_type_name
Returns the value given by the string parameter, `Tname`. This method
overrides the method in `uvm_object_wrapper`.
Returns:
"""
return self.tname
[docs] def get(self):
"""
Function: get
Returns the singleton instance of this type. Type-based factory operation
depends on there being a single proxy instance for each registered type.
Returns:
"""
if UVMComponentRegistry.registered[self.tname] is False:
factory = get_factory()
factory.register(self)
UVMComponentRegistry.registered[self.tname] = True
return self
[docs] def create(self, name, parent, contxt=""):
"""
Function: create
Returns an instance of the component type, `T`, represented by this proxy,
subject to any factory overrides based on the context provided by the
`parent`'s full name. The `contxt` argument, if supplied, supersedes the
`parent`'s context. The new instance will have the given leaf `name`
and `parent`.
Args:
name:
parent:
contxt:
Returns:
Raises:
"""
factory = get_factory()
if contxt == "" and parent is not None:
contxt = parent.get_full_name()
obj = factory.create_component_by_type(self.get(),contxt,name,parent)
if obj is not None:
return obj
# cast check removed, TSP
msg = ("Factory did not return a component of type '" + self.type_name
+ "'. A component of type '")
if obj is None:
msg += "null"
else:
get_type_name_func = getattr(obj, "get_type_name", None)
if callable(get_type_name_func):
msg += obj.get_type_name()
else:
klass_name = obj.__class__
raise Exception('No get_type_name in {}. Did you use uvm_componen_utils({})'.format(
klass_name, klass_name))
msg += "' was returned instead. Name=" + name + " Parent="
if parent is None:
msg += 'null'
else:
msg += parent.get_type_name()
msg += " contxt=" + contxt
uvm_report_fatal("FCTTYP", msg, UVM_NONE)
[docs] def set_type_override(self, override_type, replace=True):
"""
Function: set_type_override
Configures the factory to create an object of the type represented by
`override_type` whenever a request is made to create an object of the type,
`T`, represented by this proxy, provided no instance override applies. The
original type, `T`, is typically a super class of the override type.
Args:
override_type:
replace:
"""
factory = get_factory()
factory.set_type_override_by_type(self.get(),override_type,replace)
[docs] def set_inst_override(self, override_type, inst_path, parent=None):
"""
Function: set_inst_override
Configures the factory to create a component of the type represented by
`override_type` whenever a request is made to create an object of the type,
`T`, represented by this proxy, with matching instance paths. The original
type, `T`, is typically a super class of the override type.
If `parent` is not specified, `inst_path` is interpreted as an absolute
instance path, which enables instance overrides to be set from outside
component classes. If `parent` is specified, `inst_path` is interpreted
as being relative to the `parent`'s hierarchical instance path, i.e.
~{parent.get_full_name(),".",inst_path}~ is the instance path that is
registered with the override. The `inst_path` may contain wildcards for
matching against multiple contexts.
Args:
override_type:
inst_path:
parent:
"""
if parent is not None:
if inst_path == "":
inst_path = parent.get_full_name()
else:
inst_path = parent.get_full_name() + "." + inst_path
factory = get_factory()
factory.set_inst_override_by_type(self.get(),override_type,inst_path)
[docs]class UVMObjectRegistry(UVMObjectWrapper):
# dict of UVMObjectRegistry
registry_db = {} # tname -> UVMObjectRegistry
registered = {} # tname -> bool
# Stores the actual constructors
objs = {}
def __init__(self, Constr, tname):
self.Constr = Constr
self.tname = tname
self.type_name = tname
if tname in UVMObjectRegistry.registry_db:
uvm_report_warning("COMP_REGD", (tname + ' has already been'
+ ' added into the UVMObjectRegistry'))
UVMObjectRegistry.objs[tname] = Constr
UVMObjectRegistry.registered[tname] = False
UVMObjectRegistry.registry_db[tname] = self.get()
[docs] @staticmethod
def reset():
"""Resets the state of the object registry. Used for unit testing"""
UVMObjectRegistry.registry_db.clear()
UVMObjectRegistry.registered.clear()
UVMObjectRegistry.objs.clear()
# Function: create_object
#
# Creates an object of type ~T~ and returns it as a handle to a
# <uvm_object>. This is an override of the method in <uvm_object_wrapper>.
# It is called by the factory after determining the type of object to create.
# You should not call this method directly. Call <create> instead.
[docs] def create_object(self, name=""):
return UVMObjectRegistry.objs[self.tname](name)
[docs] def get_type_name(self):
"""
Function: get_type_name
Returns the value given by the string parameter, `Tname`. This method
overrides the method in `uvm_object_wrapper`.
Returns:
"""
return self.type_name
[docs] def get(self):
"""
Function: get
Returns the singleton instance of this type. Type-based factory operation
depends on there being a single proxy instance for each registered type.
Returns:
"""
if UVMObjectRegistry.registered[self.tname] is False:
factory = get_factory()
factory.register(self)
UVMObjectRegistry.registered[self.tname] = True
return self
[docs] def create(self, name, parent=None, contxt=""):
"""
Function: create
Returns an instance of the object type, `T`, represented by this proxy,
subject to any factory overrides based on the context provided by the
`parent`'s full name. The `contxt` argument, if supplied, supersedes the
`parent`'s context. The new instance will have the given leaf `name`,
if provided.
Args:
name:
parent:
contxt:
Returns:
"""
factory = get_factory()
if contxt == "" and parent is not None:
contxt = parent.get_full_name()
obj = factory.create_object_by_type(self.get(),contxt,name)
if obj is not None:
return obj
create = obj
# tpoikela: TODO could check the type for extra safety
#if (!$cast(create, obj)) begin
# string msg
# msg = {"Factory did not return an object of type '",type_name,
# "'. A component of type '",obj == null ? "null" : obj.get_type_name(),
# "' was returned instead. Name=",name," Parent=",
# parent==null?"null":parent.get_type_name()," contxt=",contxt}
# uvm_report_fatal("FCTTYP", msg, UVM_NONE)
return create
[docs] def set_type_override(self, override_type, replace=True):
"""
Function: set_type_override
Configures the factory to create an object of the type represented by
`override_type` whenever a request is made to create an object of the type
represented by this proxy, provided no instance override applies. The
original type, `T`, is typically a super class of the override type.
Args:
override_type:
replace:
"""
factory = get_factory()
factory.set_type_override_by_type(self.get(), override_type, replace)
[docs] def set_inst_override(self, override_type, inst_path, parent=None):
"""
Function: set_inst_override
Configures the factory to create an object of the type represented by
`override_type` whenever a request is made to create an object of the type
represented by this proxy, with matching instance paths. The original
type, `T`, is typically a super class of the override type.
If `parent` is not specified, `inst_path` is interpreted as an absolute
instance path, which enables instance overrides to be set from outside
component classes. If `parent` is specified, `inst_path` is interpreted
as being relative to the `parent`'s hierarchical instance path, i.e.
~{parent.get_full_name(),".",inst_path}~ is the instance path that is
registered with the override. The `inst_path` may contain wildcards for
matching against multiple contexts.
Args:
override_type:
inst_path:
parent:
"""
factory = get_factory()
if parent is not None:
if inst_path == "":
inst_path = parent.get_full_name()
else:
inst_path = parent.get_full_name() + "." + inst_path
factory.set_inst_override_by_type(self.get(), override_type, inst_path)