#
#------------------------------------------------------------------------------
# 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.
#------------------------------------------------------------------------------
"""
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.
"""
from .uvm_factory import UVMObjectWrapper
from .uvm_globals import uvm_report_warning, uvm_report_fatal
from .uvm_object_globals import UVM_NONE
# from .uvm_component import UVMComponent
from .uvm_object import UVMObject
from typing import Dict
[docs]def get_factory():
from .uvm_coreservice import UVMCoreService
cs = UVMCoreService.get()
return cs.get_factory()
[docs]class UVMComponentRegistry(UVMObjectWrapper):
"""
CLASS: UVMComponentRegistry #(T,Tname)
The UVMComponentRegistry 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 UVMComponentRegistry.
"""
# dict of UVMComponentRegistry
registry_db: Dict[str, 'UVMComponentRegistry'] = {}
registered: Dict[str, bool] = {}
# Stores the actual constructors
comps: Dict[str, type] = {}
def __init__(self, Constr: type, tname: str):
if type(Constr) is not type:
raise TypeError("Constr must be a type")
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) -> None:
"""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: str, parent):
"""
Function: create_component
Creates a component of type T having the provided `name` and `parent`.
This is an override of the method in `UVMObjectWrapper`. 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) -> str:
"""
Function: get_type_name
Returns the value given by the string parameter, `Tname`. This method
overrides the method in `UVMObjectWrapper`.
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: str, 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:
UVMComponent: The created component
Raises:
AttributeError: If get_type_name is not defined in the object.
"""
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
# Rest of the code is for error reporting. Normally, we should've
# returned already
# tpoikela: cast check removed
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 AttributeError(
'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) -> None:
"""
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) -> 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: [str, 'UVMObjectRegistry'] = {}
registered: [str, bool] = {}
# Stores the actual constructors
objs: [str, type] = {}
def __init__(self, Constr: type, tname: str):
if type(Constr) is not type:
raise TypeError("Constr must be a type")
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() -> None:
"""Resets the state of the object registry. Used for unit testing"""
UVMObjectRegistry.registry_db.clear()
UVMObjectRegistry.registered.clear()
UVMObjectRegistry.objs.clear()
[docs] def create_object(self, name="") -> UVMObject:
"""
Function: create_object
Creates an object of type ~T~ and returns it as a handle to a
`UVMObject`. This is an override of the method in `UVMObjectWrapper`.
It is called by the factory after determining the type of object to create.
You should not call this method directly. Call <create> instead.
"""
return UVMObjectRegistry.objs[self.tname](name)
[docs] def get_type_name(self) -> str:
"""
Function: get_type_name
Returns the value given by the string parameter, `Tname`. This method
overrides the method in `UVMObjectWrapper`.
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) -> None:
"""
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: str, 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)