#// -----------------------------------------------------------------------
#// Copyright 2007-2011 Mentor Graphics Corporation
#// Copyright 2007-2011 Cadence Design Systems, Inc.
#// Copyright 2010-2011 Synopsys, Inc.
#// Copyright 2013 NVIDIA Corporation
#// Copyright 2019-2020 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 typing import List, Dict
import cocotb
from cocotb.triggers import Timer
from .uvm_report_object import UVMReportObject
from .uvm_object_globals import (UVM_NONE, UVM_MEDIUM, UVM_PHASE_DONE, UVM_INFO,
UVM_CHECK_FIELDS, UVM_PHASE_SCHEDULE, UVM_WARNING, UVM_ERROR, UVM_FATAL)
from .uvm_common_phases import UVMBuildPhase
from .uvm_domain import UVMDomain
from .uvm_debug import uvm_debug
from .uvm_object import UVMObject
from .uvm_queue import UVMQueue
from .uvm_pool import UVMEventPool
from .sv import sv, uvm_split_string
from ..macros import uvm_info, uvm_fatal, uvm_warning, uvm_error
from .uvm_recorder import UVMRecorder
from .uvm_globals import (uvm_is_match, uvm_string_to_action,
uvm_string_to_severity, uvm_zero_delay)
from .uvm_factory import UVMObjectWrapper
from .uvm_links import (UVMRelatedLink, UVMParentChildLink)
INV_WARN1 = ("+uvm_set_action requires 4 arguments, but %0d given for command "
+ "+uvm_set_action=%s, Usage: +uvm_set_action=<comp>,<id>,<severity>,<action[|action]>")
INV_WARN2 = ("Bad severity argument \"%s\" given to command +uvm_set_action=%s,"
+ "Usage: +uvm_set_action=<comp>,<id>,<severity>,<action[|action]>")
INV_WARN3 = ("Bad action argument \"%s\" given to command +uvm_set_action=%s, "
+ "Usage: +uvm_set_action=<comp>,<id>,<severity>,<action[|action]>")
INV_WARN4 = ("+uvm_set_severity requires 4 arguments, but %0d given for command "
+ "+uvm_set_severity=%s, Usage: +uvm_set_severity=<comp>,<id>,<orig_severity>,<new_severity>")
INV_WARN5 = ("Bad severity argument \"%s\" given to command +uvm_set_severity=%s,"
+ " Usage: +uvm_set_severity=<comp>,<id>,<orig_severity>,<new_severity>")
INV_WARN6 = ("Bad severity argument \"%s\" given to command +uvm_set_severity=%s, "
+ "Usage: +uvm_set_severity=<comp>,<id>,<orig_severity>,<new_severity>")
[docs]class VerbositySetting():
"""
The verbosity settings may have a specific phase to start at.
We will do this work in the `UVMComponent.phase_started` callback.
:ivar UVMComponent comp: Component related to the settings
:ivar UVMPhase phase: Phase in which settings apply.
:ivar int id: ID for verbosity setting
:ivar int offset: Time offset for verbosity setting
:ivar int verbosity: Verbosity level of the setting.
"""
def __init__(self):
self.comp = ""
self.phase = ""
self.id = ""
self.offset = 0
self.verbosity = UVM_MEDIUM
[docs] def convert2string(self):
return "Comp: {}, phase: {}, ID: {}, offset: {}, verb: {}".format(
self.comp, self.phase, self.id, self.offset, self.verbosity)
CLONE_ERR = ("Attempting to clone '%s'. Clone cannot be called on a uvm_component. "
+ " The clone target variable will be set to None.")
[docs]class uvm_cmdline_parsed_arg_t:
"""
Class used to return arguments and associated data parsed from cmd line
arguments. These are usually plusargs given with +ARG_NAME=ARG_VALUE
:ivar str arg: Argument name
:ivar list args: Values of given argument.
:ivar int used: Logs how many times arg is used.
"""
def __init__(self):
self.arg = ""
self.args = []
self.used = 0
[docs]class UVMComponent(UVMReportObject):
"""
Base class for defining UVM components
The uvm_component class is the root base class for UVM components. In
addition to the features inherited from `UVMObject` and `UVMReportObject`,
uvm_component provides the following interfaces:
Hierarchy:
provides methods for searching and traversing the component hierarchy.
Phasing
defines a phased test flow that all components follow, with a
group of standard phase methods and an API for custom phases and
multiple independent phasing domains to mirror DUT behavior e.g. power
Reporting
provides a convenience interface to the `UVMReportHandler`. All
messages, warnings, and errors are processed through this interface.
Transaction recording
provides methods for recording the transactions
produced or consumed by the component to a transaction database (vendor
specific).
Factory
provides a convenience interface to the `UVMFactory`. The factory
is used to create new components and other objects based on type-wide and
instance-specific configuration.
The `UVMComponent` is automatically seeded during construction using UVM
seeding, if enabled. All other objects must be manually reseeded, if
appropriate. See `UVMObject.reseed` for more information.
Most local methods within the class are prefixed with m_, indicating they are
not user-level methods.
:cvar bool print_config_matches: Setting this static variable causes
`UVMConfigDb.get` to print info about
matching configuration settings as they are being applied.
:ivar UVMTrDatabase tr_database: Specifies the `UVMTrDatabase` object to use
for `begin_tr` and other methods in the <Recording Interface>.
Default is `UVMCoreService.get_default_tr_database`.
:ivar bool print_enabled: This bit determines if this component should automatically be printed as a
child of its parent object. By default, all children are printed. However, this bit allows a parent
component to disable the printing of specific children.
"""
print_config_matches = False
m_time_settings: List[VerbositySetting] = []
def __init__(self, name, parent):
"""
Creates a new component with the given leaf instance `name` and handle
to its `parent`. If the component is a top-level component (i.e. it is
created in a static module or interface), `parent` should be `None`.
The component will be inserted as a child of the `parent` object, if any.
If `parent` already has a child by the given `name`, an error is produced.
If `parent` is `None`, then the component will become a child of the
implicit top-level component, `uvm_top`.
All classes derived from uvm_component must call super.new(name,parent).
Args:
name (str): Name of the component.
parent (UVMComponent): Parent component.
"""
super().__init__(name)
self.m_children: Dict[str, 'UVMComponent'] = {} # uvm_component[string]
self.print_enabled = True
self.m_current_phase = None # the most recently executed phase
self.m_parent = None
self.m_children_by_handle: Dict['UVMComponent', 'UVMComponent'] = {}
self.m_children_ordered: List['UVMComponent'] = []
self.m_build_done = False
self.m_phasing_active = 0
self.recording_detail = UVM_NONE
self.m_name = ""
self.m_verbosity_settings = []
self.m_main_stream = None
# functors to override uvm_root defaults
self.m_phase_imps = {} # uvm_phase[uvm_phase]
self.child_ptr = -1
self.m_tr_h = {} # uvm_recorder m_tr_h[uvm_transaction]
self.m_run_process = None
self.tr_database = None # uvm_tr_database
self.m_domain = None
self.m_phase_process = None # process
self.event_pool: UVMEventPool = UVMEventPool("evt_pool")
self.m_streams = {} # uvm_tr_stream [string][string]
# If uvm_top, reset name to "" so it doesn't show in full paths then return
if parent is None and name == "__top__":
self.set_name("")
#UVMReportObject.set_name(self, name)
#self.m_name = self.get_name()
return
from .uvm_coreservice import UVMCoreService
cs = UVMCoreService.get()
top = cs.get_root()
# Check that we're not in or past end_of_elaboration
common = UVMDomain.get_common_domain()
bld = common.find(UVMBuildPhase.get())
if bld is None:
uvm_fatal("COMP/INTERNAL", "attempt to find build phase object failed")
if bld.get_state() == UVM_PHASE_DONE:
parent_name = top.get_full_name()
if parent is not None:
parent_name = parent.get_full_name()
uvm_fatal("ILLCRT", ("It is illegal to create a component ('" +
name + "' under '" + parent_name + "') after the build phase has ended."))
if name == "":
name = "COMP_" + str(UVMObject.m_inst_count)
if parent == self:
uvm_fatal("THISPARENT",
"cannot set the parent of a component to itself")
if parent is None:
parent = top
if self.uvm_report_enabled(UVM_MEDIUM+1, UVM_INFO, "NEWCOMP"):
nname = parent.get_full_name()
if parent == top:
nname = "uvm_top"
uvm_info("NEWCOMP", "Creating " + nname + "." + name, UVM_MEDIUM+1)
if parent.has_child(name) and self != parent.get_child(name):
if parent == top:
error_str = ("Name '" + name + "' is not unique to other top-level "
+ "instances. If parent is a module, build a unique name by combining the "
+ "the module name and component name: $sformatf('%m.%s','"
+ name + "').")
uvm_fatal("CLDEXT", error_str)
else:
uvm_fatal("CLDEXT",
sv.sformatf("Cannot set '%s' as a child of '%s', %s",
name, parent.get_full_name(), "which already has a child by that name."))
return
self.m_parent = parent
self.set_name(name)
if self.m_parent.m_add_child(self) is False:
self.m_parent = None
self.m_domain = parent.m_domain # by default, inherit domains from parents
# Now that inst name is established, reseed (if use_uvm_seeding is set)
self.reseed()
# Do local configuration settings
arr = []
from .uvm_config_db import UVMConfigDb
if UVMConfigDb.get(self, "", "recording_detail", arr):
self.recording_detail = arr[0]
self.m_rh.set_name(self.get_full_name())
self.set_report_verbosity_level(parent.get_report_verbosity_level())
self.m_set_cl_msg_args()
"""
Group: Hierarchy Interface
These methods provide user access to information about the component
hierarchy, i.e., topology.
"""
[docs] def get_parent(self):
"""
Function: get_parent
Returns a handle to this component's parent, or `None` if it has no parent.
Returns:
UVMComponent: Parent of this component.
"""
return self.m_parent
[docs] def get_full_name(self) -> str:
"""
Returns the full hierarchical name of this object. The default
implementation concatenates the hierarchical name of the parent, if any,
with the leaf name of this object, as given by `UVMObject.get_name`.
Returns:
str: Full hierarchical name of this component.
"""
if self.m_name == "":
return self.get_name()
else:
return self.m_name
[docs] def get_children(self, children):
"""
This function populates the end of the `children` array with the
list of this component's children.
.. code-block:: python
array = []
my_comp.get_children(array)
for comp in array:
do_something(comp)
Args:
children (list): List into which child components are appended
"""
for name in self.m_children:
children.append(self.m_children[name])
[docs] def get_child(self, name):
"""
Args:
name (str): Name of desired child
Returns:
UVMComponent: Child component matching name.
"""
if name in self.m_children:
return self.m_children[name]
[docs] def get_next_child(self):
"""
Returns:
UVMComponent: Next child component.
"""
self.child_ptr += 1
if (self.child_ptr < len(self.m_children_ordered)):
return self.m_children_ordered[self.child_ptr]
return None
[docs] def get_first_child(self):
"""
These methods are used to iterate through this component's children, if
any. For example, given a component with an object handle, `comp`, the
following code calls `UVMObject.print` for each child:
.. code-block:: python
name = ""
child = comp.get_first_child()
while child is not None:
child.print()
child = comp.get_next_child()
Returns:
UVMComponent: First child component.
"""
self.child_ptr = 0
if len(self.m_children_ordered) > 0:
return self.m_children_ordered[0]
return None
[docs] def get_num_children(self):
"""
Returns:
int: The number of this component's children.
"""
return len(self.m_children_ordered)
[docs] def has_child(self, name):
"""
Args:
name (str): Desired child component name.
Returns:
bool: True if this component has a child with the given `name`,
False otherwise.
"""
return name in self.m_children
[docs] def set_name(self, name):
"""
Renames this component to `name` and recalculates all descendants'
full names. This is an internal function for now.
Args:
name (str): New name
"""
if self.m_name != "":
uvm_error("INVSTNM", ("It is illegal to change the name of a component."
+ "The component name will not be changed to \"{}\"".format(name)))
return
super().set_name(name)
self.m_set_full_name()
[docs] def lookup(self, name):
"""
Looks for a component with the given hierarchical `name` relative to this
component. If the given `name` is preceded with a '.' (dot), then the search
begins relative to the top level (absolute lookup). The handle of the
matching component is returned, else `None`. The name must not contain
wildcards.
Args:
name:
Returns:
UVMComponent: Matching component, or None is no match is found.
"""
leaf = ""
remainder = ""
comp = None
from .uvm_coreservice import UVMCoreService
cs = UVMCoreService.get()
top = cs.get_root()
comp = self
[leaf, remainder] = self.m_extract_name(name, leaf, remainder)
if leaf == "":
comp = top # absolute lookup
[leaf, remainder] = self.m_extract_name(remainder, leaf, remainder)
if comp.has_child(leaf) is False:
uvm_warning("Lookup Error",
sv.sformatf("Cannot find child %0s from comp %s",leaf,
comp.get_name()))
return None
if remainder != "":
return comp.m_children[leaf].lookup(remainder)
return comp.m_children[leaf]
[docs] def get_depth(self) -> int:
"""
Returns the component's depth from the root level. uvm_top has a
depth of 0. The test and any other top level components have a depth
of 1, and so on.
Returns:
int: The component's depth from the root level
"""
if self.m_name == "":
return 0
get_depth = 1
for i in range(len(self.m_name)):
if (self.m_name[i] == "."):
get_depth += 1
return get_depth
# Group: Phasing Interface
#
# These methods implement an interface which allows all components to step
# through a standard schedule of phases, or a customized schedule, and
# also an API to allow independent phase domains which can jump like state
# machines to reflect behavior e.g. power domains on the DUT in different
# portions of the testbench. The phase tasks and functions are the phase
# name with the _phase suffix. For example, the build phase function is
# <build_phase>.
#
# All processes associated with a task-based phase are killed when the phase
# ends. See <uvm_task_phase> for more details.
[docs] def build_phase(self, phase):
"""
The `UVMBuildPhase` phase implementation method.
Any override should call super().build_phase(phase) to execute the automatic
configuration of fields registered in the component by calling
`apply_config_settings`.
To turn off automatic configuration for a component,
do not call super().build_phase(phase).
This method should never be called directly.
Args:
phase (UVMPhase):
"""
self.m_build_done = True
self.build()
[docs] def build(self):
"""
For backward compatibility the base `build_phase` method calls `build`.
"""
self.m_build_done = True
self.apply_config_settings(UVMComponent.print_config_matches)
if self.m_phasing_active == 0:
uvm_warning("UVM_DEPRECATED",
"build()/build_phase() has been called explicitly")
[docs] def connect_phase(self, phase):
"""
The `UVMConnectPhase` phase implementation method.
This method should never be called directly.
Args:
phase (UVMPhase):
"""
pass
# For backward compatibility the base connect_phase method calls connect.
# extern virtual function void connect()
[docs] def end_of_elaboration_phase(self, phase):
"""
The `UVMEndOfElaborationPhase` phase implementation method.
This method should never be called directly.
Args:
phase (UVMPhase):
"""
pass
# For backward compatibility the base <end_of_elaboration_phase> method calls <end_of_elaboration>.
# extern virtual function void end_of_elaboration()
[docs] def start_of_simulation_phase(self, phase):
"""
The `UVMStartOfSimulationPhase` phase implementation method.
This method should never be called directly.
Args:
phase (UVMPhase):
"""
self.start_of_simulation()
return
[docs] def start_of_simulation(self):
"""
For backward compatibility the base `start_of_simulation_phase` method calls `start_of_simulation`.
extern virtual function void start_of_simulation()
"""
return
[docs] async def run_phase(self, phase):
"""
Task: run_phase
The `UVMRunPhase` phase implementation method.
This task returning or not does not indicate the end
or persistence of this phase.
Thus the phase will automatically
end once all objections are dropped using ~phase.drop_objection()~.
Any processes forked by this task continue to run
after the task returns,
but they will be killed once the phase ends.
The run_phase task should never be called directly.
"""
uvm_debug(self, 'run_phase', self.get_name() + ' yielding self.run()')
# self.m_run_process = cocotb.start_soon(self.run())
# yield self.m_run_process
await self.run()
# For backward compatibility the base <run_phase> method calls <run>.
# extern virtual task run()
[docs] async def run(self):
uvm_debug(self, 'run', self.get_name() + ' yield Timer(0) in self.run()')
await uvm_zero_delay()
[docs] async def pre_reset_phase(self, phase):
"""
Task: pre_reset_phase
The `uvm_pre_reset_phase` phase implementation method.
This task returning or not does not indicate the end
or persistence of this phase.
It is necessary to raise an objection
using ~phase.raise_objection()~ to cause the phase to persist.
Once all components have dropped their respective objection
using ~phase.drop_objection()~, or if no components raises an
objection, the phase is ended.
Any processes forked by this task continue to run
after the task returns,
but they will be killed once the phase ends.
This method should not be called directly.
Args:
phase:
"""
await uvm_zero_delay()
[docs] async def reset_phase(self, phase):
"""
Task: reset_phase
The `uvm_reset_phase` phase implementation method.
This task returning or not does not indicate the end
or persistence of this phase.
It is necessary to raise an objection
using ~phase.raise_objection()~ to cause the phase to persist.
Once all components have dropped their respective objection
using ~phase.drop_objection()~, or if no components raises an
objection, the phase is ended.
Any processes forked by this task continue to run
after the task returns,
but they will be killed once the phase ends.
This method should not be called directly.
Args:
phase:
"""
await uvm_zero_delay()
[docs] async def post_reset_phase(self, phase):
"""
Task: post_reset_phase
The `uvm_post_reset_phase` phase implementation method.
This task returning or not does not indicate the end
or persistence of this phase.
It is necessary to raise an objection
using ~phase.raise_objection()~ to cause the phase to persist.
Once all components have dropped their respective objection
using ~phase.drop_objection()~, or if no components raises an
objection, the phase is ended.
Any processes forked by this task continue to run
after the task returns,
but they will be killed once the phase ends.
This method should not be called directly.
Args:
phase:
"""
await uvm_zero_delay()
[docs] async def post_configure_phase(self, phase):
"""
Task: post_configure_phase
The `uvm_post_configure_phase` phase implementation method.
This task returning or not does not indicate the end
or persistence of this phase.
It is necessary to raise an objection
using ~phase.raise_objection()~ to cause the phase to persist.
Once all components have dropped their respective objection
using ~phase.drop_objection()~, or if no components raises an
objection, the phase is ended.
Any processes forked by this task continue to run
after the task returns,
but they will be killed once the phase ends.
This method should not be called directly.
Args:
phase:
"""
await uvm_zero_delay()
[docs] async def pre_main_phase(self, phase):
"""
Task: pre_main_phase
The `uvm_pre_main_phase` phase implementation method.
This task returning or not does not indicate the end
or persistence of this phase.
It is necessary to raise an objection
using ~phase.raise_objection()~ to cause the phase to persist.
Once all components have dropped their respective objection
using ~phase.drop_objection()~, or if no components raises an
objection, the phase is ended.
Any processes forked by this task continue to run
after the task returns,
but they will be killed once the phase ends.
This method should not be called directly.
Args:
phase:
"""
await uvm_zero_delay()
[docs] async def main_phase(self, phase):
"""
Task: main_phase
The `uvm_main_phase` phase implementation method.
This task returning or not does not indicate the end
or persistence of this phase.
It is necessary to raise an objection
using ~phase.raise_objection()~ to cause the phase to persist.
Once all components have dropped their respective objection
using ~phase.drop_objection()~, or if no components raises an
objection, the phase is ended.
Any processes forked by this task continue to run
after the task returns,
but they will be killed once the phase ends.
This method should not be called directly.
Args:
phase:
"""
await uvm_zero_delay()
[docs] async def post_main_phase(self, phase):
"""
Task: post_main_phase
The `uvm_post_main_phase` phase implementation method.
This task returning or not does not indicate the end
or persistence of this phase.
It is necessary to raise an objection
using ~phase.raise_objection()~ to cause the phase to persist.
Once all components have dropped their respective objection
using ~phase.drop_objection()~, or if no components raises an
objection, the phase is ended.
Any processes forked by this task continue to run
after the task returns,
but they will be killed once the phase ends.
This method should not be called directly.
Args:
phase:
"""
await uvm_zero_delay()
[docs] async def pre_shutdown_phase(self, phase):
"""
Task: pre_shutdown_phase
The `uvm_pre_shutdown_phase` phase implementation method.
This task returning or not does not indicate the end
or persistence of this phase.
It is necessary to raise an objection
using ~phase.raise_objection()~ to cause the phase to persist.
Once all components have dropped their respective objection
using ~phase.drop_objection()~, or if no components raises an
objection, the phase is ended.
Any processes forked by this task continue to run
after the task returns,
but they will be killed once the phase ends.
This method should not be called directly.
Args:
phase:
"""
await uvm_zero_delay()
[docs] async def shutdown_phase(self, phase):
"""
Task: shutdown_phase
The `uvm_shutdown_phase` phase implementation method.
This task returning or not does not indicate the end
or persistence of this phase.
It is necessary to raise an objection
using ~phase.raise_objection()~ to cause the phase to persist.
Once all components have dropped their respective objection
using ~phase.drop_objection()~, or if no components raises an
objection, the phase is ended.
Any processes forked by this task continue to run
after the task returns,
but they will be killed once the phase ends.
This method should not be called directly.
Args:
phase:
"""
await uvm_zero_delay()
[docs] async def post_shutdown_phase(self, phase):
"""
Task: post_shutdown_phase
The `uvm_post_shutdown_phase` phase implementation method.
This task returning or not does not indicate the end
or persistence of this phase.
It is necessary to raise an objection
using ~phase.raise_objection()~ to cause the phase to persist.
Once all components have dropped their respective objection
using ~phase.drop_objection()~, or if no components raises an
objection, the phase is ended.
Any processes forked by this task continue to run
after the task returns,
but they will be killed once the phase ends.
This method should not be called directly.
Args:
phase:
"""
await uvm_zero_delay()
#// For backward compatibility the base extract_phase method calls extract.
#extern virtual function void extract()
[docs] def check_phase(self, phase):
"""
The `UVMCheckPhase` phase implementation method.
This method should never be called directly.
Args:
phase:
"""
pass
#// For backward compatibility the base check_phase method calls check.
#extern virtual function void check()
[docs] def report_phase(self, phase):
"""
The `UVMReportPhase` phase implementation method.
This method should never be called directly.
Args:
phase:
"""
pass
[docs] def final_phase(self, phase):
"""
The `UVMFinalPhase` phase implementation method.
This method should never be called directly.
Args:
phase:
"""
# self.m_rh._close_files()
pass
[docs] def phase_started(self, phase):
"""
Invoked at the start of each phase. The `phase` argument specifies
the phase being started. Any threads spawned in this callback are
not affected when the phase ends.
Args:
phase:
"""
pass
[docs] def phase_ended(self, phase):
"""
Invoked at the end of each phase. The `phase` argument specifies
the phase that is ending. Any threads spawned in this callback are
not affected when the phase ends.
Args:
phase:
"""
pass
[docs] def phase_ready_to_end(self, phase):
"""
Function: phase_ready_to_end
Invoked when all objections to ending the given `phase` and all
sibling phases have been dropped, thus indicating that `phase` is
ready to begin a clean exit. Sibling phases are any phases that
have a common successor phase in the schedule plus any phases that
sync'd to the current phase. Components needing to consume delta
cycles or advance time to perform a clean exit from the phase
may raise the phase's objection.
.. code-block:: python
phase.raise_objection(self, "Reason")
It is the responsibility of this component to drop the objection
once it is ready for this phase to end (and processes killed).
If no objection to the given `phase` or sibling phases are raised,
then phase_ended() is called after a delta cycle. If any objection
is raised, then when all objections to ending the given `phase`
and siblings are dropped, another iteration of phase_ready_to_end
is called. To prevent endless iterations due to coding error,
after 20 iterations, phase_ended() is called regardless of whether
previous iteration had any objections raised.
"""
pass
#// phase / schedule / domain API
[docs] def set_domain(self, domain, hier=True):
"""
Apply a phase domain to this component and, if `hier` is set,
recursively to all its children.
Calls the virtual `define_domain` method, which derived components can
override to augment or replace the domain definition of its base class.
Assigns this component [tree] to a domain. adds required schedules into graph
If called from build, `hier` won't recurse into all chilren (which don't exist yet)
If we have components inherit their parent's domain by default, then `hier`
isn't needed and we need a way to prevent children from inheriting this component's domain
Args:
domain:
hier:
"""
# build and store the custom domain
self.m_domain = domain
self.define_domain(domain)
if hier is True:
for c in self.m_children:
self.m_children[c].set_domain(domain)
[docs] def get_domain(self):
"""
Return handle to the phase domain set on this component
Returns:
"""
return self.m_domain
[docs] def define_domain(self, domain):
"""
Builds custom phase schedules into the provided `domain` handle.
This method is called by `set_domain`, which integrators use to specify
this component belongs in a domain apart from the default 'uvm' domain.
Custom component base classes requiring a custom phasing schedule can
augment or replace the domain definition they inherit by overriding
their `defined_domain`. To augment, overrides would call super.define_domain().
To replace, overrides would not call super.define_domain().
The default implementation adds a copy of the `uvm` phasing schedule to
the given `domain`, if one doesn't already exist, and only if the domain
is currently empty.
Calling `set_domain`
with the default `uvm` domain (i.e. <uvm_domain::get_uvm_domain> ) on
a component with no `define_domain` override effectively reverts the
that component to using the default `uvm` domain. This may be useful
if a branch of the testbench hierarchy defines a custom domain, but
some child sub-branch should remain in the default `uvm` domain,
call `set_domain` with a new domain instance handle with `hier` set.
Then, in the sub-branch, call `set_domain` with the default `uvm` domain handle,
obtained via <uvm_domain::get_uvm_domain>.
Alternatively, the integrator may define the graph in a new domain externally,
then call `set_domain` to apply it to a component.
Args:
domain:
"""
from .uvm_phase import UVMPhase
from .uvm_common_phases import UVMRunPhase
schedule = None # uvm_phase
# //schedule = domain.find(uvm_domain::get_uvm_schedule())
schedule = domain.find_by_name("uvm_sched")
if schedule is None:
# uvm_domain common
schedule = UVMPhase("uvm_sched", UVM_PHASE_SCHEDULE)
UVMDomain.add_uvm_phases(schedule)
domain.add(schedule)
common = UVMDomain.get_common_domain()
if common.find(domain,0) is None:
common.add(domain, with_phase=UVMRunPhase.get())
[docs] def set_phase_imp(self, phase, imp, hier=1):
"""
Override the default implementation for a phase on this component (tree) with a
custom one, which must be created as a singleton object extending the default
one and implementing required behavior in exec and traverse methods
The `hier` specifies whether to apply the custom functor to the whole tree or
just this component.
Args:
phase:
imp:
hier:
"""
self.m_phase_imps[phase] = imp
if hier:
for c in self.m_children:
self.m_children[c].set_phase_imp(phase,imp,hier)
[docs] async def suspend(self):
"""
Suspend this component.
This method must be implemented by the user to suspend the
component according to the protocol and functionality it implements.
A suspended component can be subsequently resumed using <resume()>.
"""
uvm_warning("COMP/SPND/UNIMP", "suspend() not implemented")
[docs] async def resume(self):
"""
Resume this component.
This method must be implemented by the user to resume a component
that was previously suspended using <suspend()>.
Some component may start in the suspended state and
may need to be explicitly resumed.
"""
uvm_warning("COMP/RSUM/UNIMP", "resume() not implemented")
[docs] def resolve_bindings(self) -> None:
"""
Processes all port, export, and imp connections. Checks whether each port's
min and max connection requirements are met.
It is called just before the end_of_elaboration phase.
Users should not call directly.
"""
return
[docs] def massage_scope(self, scope: str) -> str:
if scope == "":
return "^$"
if scope == "*":
return self.get_full_name() + ".*"
# absolute path to the top-level test
if scope == "uvm_test_top":
return "uvm_test_top"
# absolute path to uvm_root
if scope[0] == ".":
return self.get_full_name() + scope
return self.get_full_name() + "." + scope
#// Group: Configuration Interface
#//
#// Components can be designed to be user-configurable in terms of its
#// topology (the type and number of children it has), mode of operation, and
#// run-time parameters (knobs). The configuration interface accommodates
#// this common need, allowing component composition and state to be modified
#// without having to derive new classes or new class hierarchies for
#// every configuration scenario.
#//
[docs] def check_config_usage(self, recurse=1) -> None:
"""
Check all configuration settings in a components configuration table
to determine if the setting has been used, overridden or not used.
When `recurse` is 1 (default), configuration for this and all child
components are recursively checked. This function is automatically
called in the check phase, but can be manually called at any time.
To get all configuration information prior to the run phase, do something
like this in your top object:
.. code-block:: python
def start_of_simulation_phase(self, phase):
self.check_config_usage()
Args:
recurse:
"""
from .uvm_resource import UVMResourcePool
rp = UVMResourcePool.get()
rq = rp.find_unused_resources()
if len(rq) == 0:
return
uvm_info("CFGNRD"," ::: The following resources have at least one write and no reads :::",UVM_INFO)
rp.print_resources(rq, 1)
[docs] def apply_config_settings(self, verbose=0):
"""
Searches for all config settings matching this component's instance path.
For each match, the appropriate set_*_local method is called using the
matching config setting's field_name and value. Provided the set_*_local
method is implemented, the component property associated with the
field_name is assigned the given value.
This function is called by <uvm_component::build_phase>.
The apply_config_settings method determines all the configuration
settings targeting this component and calls the appropriate set_*_local
method to set each one. To work, you must override one or more set_*_local
methods to accommodate setting of your component's specific properties.
Any properties registered with the optional `uvm_*_field macros do not
require special handling by the set_*_local methods; the macros provide
the set_*_local functionality for you.
If you do not want apply_config_settings to be called for a component,
then the build_phase() method should be overloaded and you should not call
super.build_phase(phase). Likewise, apply_config_settings can be overloaded to
customize automated configuration.
When the `verbose` bit is set, all overrides are printed as they are
applied. If the component's `print_config_matches` property is set, then
apply_config_settings is automatically called with `verbose` = 1.
Args:
verbose (bool): If true, prints more verbose information
"""
from .uvm_resource import UVMResourcePool
rp = UVMResourcePool.get() # uvm_resource_pool
rq = UVMQueue() # uvm_queue#(uvm_resource_base) rq
r = None # uvm_resource_base r
name = ""
search_name = ""
i = 0
j = 0
# populate an internal 'field_array' with list of
# fields declared with `uvm_field macros (checking
# that there aren't any duplicates along the way)
self._m_uvm_field_automation(None, UVM_CHECK_FIELDS, "")
T_cont = UVMObject._m_uvm_status_container
# if no declared fields, nothing to do.
if len(T_cont.field_array) == 0:
return
if verbose:
uvm_info("CFGAPL","applying configuration settings", UVM_NONE)
# // The following is VERY expensive. Needs refactoring. Should
# // get config only for the specific field names in 'field_array'.
# // That's because the resource pool is organized first by field name.
# // Can further optimize by encoding the value for each 'field_array'
# // entry to indicate string, uvm_bitstream_t, or object. That way,
# // we call 'get' for specific fields of specific types rather than
# // the search-and-cast approach here.
rq = rp.lookup_scope(self.get_full_name())
rq = UVMResourcePool.sort_by_precedence(rq)
# // rq is in precedence order now, so we have to go through in reverse
# // order to do the settings.
# for(int i=rq.size()-1; i>=0; --i):
for i in range(len(rq)):
r = rq[i]
name = r.get_name()
# // does name have brackets [] in it?
while j < len(name):
if (name[j] == "[" or name[j] == "."):
break
j += 1
# // If it does have brackets then we'll use the name
# // up to the brackets to search __m_uvm_status_container.field_array
if j < len(name):
search_name = name[0:j]
else:
search_name = name
if search_name not in T_cont.field_array and search_name != "recording_detail":
continue
if verbose:
uvm_info("CFGAPL",sv.sformatf("applying configuration to field %s", name),UVM_NONE)
val = r.read(self)
if isinstance(val, int):
self.set_int_local(name, val)
elif isinstance(val, UVMObject):
self.set_object_local(name, val, 0)
elif isinstance(val, UVMObjectWrapper):
self.set_object_local(name, val.obj, val.clone)
elif isinstance(val, str):
self.set_string_local(name, val)
elif verbose:
uvm_info("CFGAPL", sv.sformatf("field %s has an unsupported type", name), UVM_NONE)
T_cont.field_array.clear()
[docs] def print_config_settings(self, field="", comp=None, recurse=False) -> None:
"""
Function: print_config_settings
Called without arguments, print_config_settings prints all configuration
information for this component, as set by previous calls to <uvm_config_db::set()>.
The settings are printing in the order of their precedence.
If `field` is specified and non-empty, then only configuration settings
matching that field, if any, are printed. The field may not contain
wildcards.
If `comp` is specified and non-`None`, then the configuration for that
component is printed.
If `recurse` is set, then configuration information for all `comp`'s
children and below are printed as well.
This function has been deprecated. Use print_config instead.
Args:
field (str): Print all config related to given field,
comp (UVMComponent): If given, print config only for that component.
recurse (bool): If true, recurse to all children
"""
UVMComponent.have_been_warned = False
if not UVMComponent.have_been_warned:
uvm_warning("deprecated",
"uvm_component::print_config_settings has been deprecated. Use print_config() instead")
UVMComponent.have_been_warned = True
self.print_config(recurse, 1)
[docs] def print_config(self, recurse=False, audit=False) -> None:
"""
Function: print_config
Print_config prints all configuration information for this
component, as set by previous calls to `UVMConfigDb.set` and exports to
the resources pool. The settings are printing in the order of
their precedence.
If `recurse` is set, then configuration information for all
children and below are printed as well.
if `audit` is set then the audit trail for each resource is printed
along with the resource name and value
Args:
recurse (bool): If true, recurse to child components
audit (bool): If true, print audit trail for each resource.
"""
from .uvm_resource import UVMResourcePool
rp = UVMResourcePool.get()
uvm_info("CFGPRT","visible resources:", UVM_INFO)
rp.print_resources(rp.lookup_scope(self.get_full_name()), audit)
if recurse:
for key in self.m_children:
c = self.m_children[key]
c.print_config(recurse, audit)
[docs] def print_config_with_audit(self, recurse=0) -> None:
"""
Function: print_config_with_audit
Operates the same as print_config except that the audit bit is
forced to 1. This interface makes user code a bit more readable as
it avoids multiple arbitrary bit settings in the argument list.
If `recurse` is set, then configuration information for all
children and below are printed as well.
"""
self.print_config(recurse, 1)
"""
Group: Objection Interface
These methods provide object level hooks into the `UVMObjection`
mechanism.
"""
[docs] def raised(self, objection, source_obj, description, count):
"""
Function: raised
The `raised` callback is called when this or a descendant of this component
instance raises the specified `objection`. The `source_obj` is the object
that originally raised the objection.
The `description` is optionally provided by the `source_obj` to give a
reason for raising the objection. The `count` indicates the number of
objections raised by the `source_obj`.
"""
pass
[docs] def dropped(self, objection, source_obj, description, count):
"""
The `dropped` callback is called when this or a descendant of this component
instance drops the specified `objection`. The `source_obj` is the object
that originally dropped the objection.
The `description` is optionally provided by the `source_obj` to give a
reason for dropping the objection. The `count` indicates the number of
objections dropped by the `source_obj`.
Args:
objection (UVMObjection):
source_obj (UVMObject):
description (str):
count (int):
"""
pass
[docs] async def all_dropped(self, objection, source_obj, description, count):
"""
The `all_droppped` callback is called when all objections have been
dropped by this component and all its descendants. The `source_obj` is the
object that dropped the last objection.
The `description` is optionally provided by the `source_obj` to give a
reason for raising the objection. The `count` indicates the number of
objections dropped by the `source_obj`.
Args:
objection:
source_obj:
description:
count:
"""
pass
#// Group: Factory Interface
#//
#// The factory interface provides convenient access to a portion of UVM's
#// <uvm_factory> interface. For creating new objects and components, the
#// preferred method of accessing the factory is via the object or component
#// wrapper (see <uvm_component_registry #(T,Tname)> and
#// <uvm_object_registry #(T,Tname)>). The wrapper also provides functions
#// for setting type and instance overrides.
#//
[docs] def create_component(self, requested_type_name, name):
"""
Function: create_component
A convenience function for <uvm_factory::create_component_by_name>,
this method calls upon the factory to create a new child component
whose type corresponds to the preregistered type name, `requested_type_name`,
and instance name, `name`. This method is equivalent to::
factory.create_component_by_name(requested_type_name,
get_full_name(), name, this)
If the factory determines that a type or instance override exists, the type
of the component created may be different than the requested type. See
<set_type_override> and <set_inst_override>. See also <uvm_factory> for
details on factory operation.
"""
factory = _get_factory()
return factory.create_component_by_name(requested_type_name,
self.get_full_name(), name, self)
[docs] def create_object(self, requested_type_name, name=""):
"""
A convenience function for `UVMFactory.create_object_by_name`,
this method calls upon the factory to create a new object
whose type corresponds to the preregistered type name,
`requested_type_name`, and instance name, `name`. This method is
equivalent to::
factory.create_object_by_name(requested_type_name,
get_full_name(), name)
If the factory determines that a type or instance override exists, the
type of the object created may be different than the requested type. See
`UVMFactory` for details on factory operation.
"""
factory = _get_factory()
return factory.create_object_by_name(requested_type_name,
self.get_full_name(), name)
[docs] @classmethod
def set_type_override_by_type(cls, original_type, override_type, replace=1):
"""
A convenience function for `UVMFactory.set_type_override_by_type`, this
method registers a factory override for components and objects created at
this level of hierarchy or below. This method is equivalent to::
factory.set_type_override_by_type(original_type, override_type,replace)
The `relative_inst_path` is relative to this component and may include
wildcards. The `original_type` represents the type that is being overridden.
In subsequent calls to `UVMFactory.create_object_by_type` or
`UVMFactory.create_component_by_type`, if the requested_type matches the
`original_type` and the instance paths match, the factory will produce
the `override_type`.
The original and override type arguments are lightweight proxies to the
types they represent. See <set_inst_override_by_type> for information
on usage.
"""
factory = _get_factory()
factory.set_type_override_by_type(original_type, override_type, replace)
#// Function: set_inst_override_by_type
#//
#// A convenience function for <uvm_factory::set_inst_override_by_type>, this
#// method registers a factory override for components and objects created at
#// this level of hierarchy or below. In typical usage, this method is
#// equivalent to:
#//
#//| factory.set_inst_override_by_type( original_type,
#//| override_type,
#//| {get_full_name(),".",
#//| relative_inst_path})
#//
#// The `relative_inst_path` is relative to this component and may include
#// wildcards. The `original_type` represents the type that is being overridden.
#// In subsequent calls to `UVMFactory.create_object_by_type` or
#// `UVMFactory.create_component_by_type`, if the requested_type matches the
#// `original_type` and the instance paths match, the factory will produce the
#// `override_type`.
#//
#// The original and override types are lightweight proxies to the types they
#// represent. They can be obtained by calling ~type::get_type()~, if
#// implemented by `type`, or by directly calling ~type::type_id::get()~, where
#// `type` is the user type and `type_id` is the name of the typedef to
#// <uvm_object_registry #(T,Tname)> or <uvm_component_registry #(T,Tname)>.
#//
#// If you are employing the `uvm_*_utils macros, the typedef and the get_type
#// method will be implemented for you. For details on the utils macros
#// refer to <Utility and Field Macros for Components and Objects>.
#//
#// The following example shows `uvm_*_utils usage:
#//
#//| class comp extends uvm_component
#//| `uvm_component_utils(comp)
#//| ...
#//| endclass
#//|
#//| class mycomp extends uvm_component
#//| `uvm_component_utils(mycomp)
#//| ...
#//| endclass
#//|
#//| class block extends uvm_component
#//| `uvm_component_utils(block)
#//| comp c_inst
#//| virtual function void build_phase(uvm_phase phase)
#//| set_inst_override_by_type("c_inst",comp::get_type(),
#//| mycomp::get_type())
#//| endfunction
#//| ...
#//| endclass
#extern function void set_inst_override_by_type(string relative_inst_path,
# uvm_object_wrapper original_type,
# uvm_object_wrapper override_type)
#function void uvm_component::set_inst_override_by_type (string relative_inst_path,
# uvm_object_wrapper original_type,
# uvm_object_wrapper override_type)
# string full_inst_path
# uvm_coreservice_t cs = uvm_coreservice_t::get()
# uvm_factory factory=cs.get_factory()
#
# if (relative_inst_path == "")
# full_inst_path = get_full_name()
# else
# full_inst_path = {get_full_name(), ".", relative_inst_path}
#
# factory.set_inst_override_by_type(original_type, override_type, full_inst_path)
#
#endfunction
[docs] @classmethod
def set_type_override(cls, original_type_name, override_type_name,
replace=1):
"""
Function: set_type_override
A convenience function for `UVMFactory.set_type_override_by_name`,
this method configures the factory to create an object of type
`override_type_name` whenever the factory is asked to produce a type
represented by `original_type_name`. This method is equivalent to::
factory.set_type_override_by_name(original_type_name,
override_type_name, replace)
The `original_type_name` typically refers to a preregistered type in the
factory. It may, however, be any arbitrary string. Subsequent calls to
create_component or create_object with the same string and matching
instance path will produce the type represented by override_type_name.
The `override_type_name` must refer to a preregistered type in the factory.
"""
factory = _get_factory()
factory.set_type_override_by_name(original_type_name,override_type_name, replace)
#// Function: set_inst_override
#//
#// A convenience function for <uvm_factory::set_inst_override_by_name>, this
#// method registers a factory override for components created at this level
#// of hierarchy or below. In typical usage, this method is equivalent to:
#//
#//| factory.set_inst_override_by_name(original_type_name,
#//| override_type_name,
#//| {get_full_name(),".",
#//| relative_inst_path}
#//| )
#//
#// The `relative_inst_path` is relative to this component and may include
#// wildcards. The `original_type_name` typically refers to a preregistered type
#// in the factory. It may, however, be any arbitrary string. Subsequent calls
#// to create_component or create_object with the same string and matching
#// instance path will produce the type represented by `override_type_name`.
#// The `override_type_name` must refer to a preregistered type in the factory.
#extern function void set_inst_override(string relative_inst_path,
# string original_type_name,
# string override_type_name)
[docs] def print_override_info(self, requested_type_name, name=""):
"""
This factory debug method performs the same lookup process as create_object
and create_component, but instead of creating an object, it prints
information about what type of object would be created given the
provided arguments.
"""
factory = _get_factory()
factory.debug_create_by_name(requested_type_name, self.get_full_name(), name)
#// Group: Hierarchical Reporting Interface
#//
#// This interface provides versions of the set_report_* methods in the
#// <uvm_report_object> base class that are applied recursively to this
#// component and all its children.
#//
#// When a report is issued and its associated action has the LOG bit set, the
#// report will be sent to its associated FILE descriptor.
#// Function: set_report_id_verbosity_hier
[docs] def set_report_id_verbosity_hier(self, id, verbosity):
self.set_report_id_verbosity(id, verbosity)
for c in self.m_children:
self.m_children[c].set_report_id_verbosity_hier(id, verbosity)
#// Function: set_report_severity_id_verbosity_hier
#//
#// These methods recursively associate the specified verbosity with reports of
#// the given `severity`, `id`, or ~severity-id~ pair. A verbosity associated
#// with a particular severity-id pair takes precedence over a verbosity
#// associated with id, which takes precedence over a verbosity associated
#// with a severity.
#//
#// For a list of severities and their default verbosities, refer to
#// `UVMReportHandler`.
[docs] def set_report_severity_id_verbosity_hier(self, severity, id, verbosity):
self.set_report_severity_id_verbosity(severity, id, verbosity)
for c in self.m_children:
self.m_children[c].set_report_severity_id_verbosity_hier(severity, id, verbosity)
[docs] def set_report_severity_action_hier(self, severity, action):
"""
Args:
severity:
action:
"""
self.set_report_severity_action(severity, action)
for c in self.m_children:
self.m_children[c].set_report_severity_action_hier(severity, action)
[docs] def set_report_severity_id_action_hier(self, severity, id, action):
self.set_report_severity_id_action(severity, id, action)
for c in self.m_children:
self.m_children[c].set_report_severity_id_action_hier(severity, id, action)
[docs] def set_report_id_action_hier(self, id, action):
"""
These methods recursively associate the specified action with reports of
the given `severity`, `id`, or ~severity-id~ pair. An action associated
with a particular severity-id pair takes precedence over an action
associated with id, which takes precedence over an action associated
with a severity.
For a list of severities and their default actions, refer to
`UVMReportHandler`.
Args:
id (str): Message ID to use ('' = all)
action:
"""
self.set_report_id_action(id, action)
for c in self.m_children:
self.m_children[c].set_report_id_action_hier(id, action)
[docs] def set_report_default_file_hier(self, file):
"""
Sets default report file hierarchically. All `UVM_LOG` actions are
written into this file, unless more specific file is set.
Args:
file:
"""
self.set_report_default_file(file)
for c in self.m_children:
self.m_children[c].set_report_default_file_hier(file)
#// Function: set_report_severity_file_hier
[docs] def set_report_severity_file_hier(self, severity, file):
self.set_report_severity_file(severity, file)
for c in self.m_children:
self.m_children[c].set_report_severity_file_hier(severity, file)
#// Function: set_report_id_file_hier
[docs] def set_report_id_file_hier(self, id, file):
self.set_report_id_file(id, file)
for c in self.m_children:
self.m_children[c].set_report_id_file_hier(id, file)
#// Function: set_report_severity_id_file_hier
#//
#// These methods recursively associate the specified FILE descriptor with
#// reports of the given `severity`, `id`, or ~severity-id~ pair. A FILE
#// associated with a particular severity-id pair takes precedence over a FILE
#// associated with id, which take precedence over an a FILE associated with a
#// severity, which takes precedence over the default FILE descriptor.
#//
#// For a list of severities and other information related to the report
#// mechanism, refer to `UVMReportHandler`.
[docs] def set_report_severity_id_file_hier(self, severity, id, file):
self.set_report_severity_id_file(severity, id, file)
for c in self.m_children:
self.m_children[c].set_report_severity_id_file_hier(severity, id, file)
[docs] def set_report_verbosity_level_hier(self, verbosity):
"""
This method recursively sets the maximum verbosity level for reports for
this component and all those below it. Any report from this component
subtree whose verbosity exceeds this maximum will be ignored.
See `UVMReportHandler` for a list of predefined message verbosity levels
and their meaning.
Args:
verbosity:
"""
self.set_report_verbosity_level(verbosity)
for c in self.m_children:
self.m_children[c].set_report_verbosity_level_hier(verbosity)
[docs] def pre_abort(self):
"""
This callback is executed when the message system is executing a
`UVM_EXIT` action. The exit action causes an immediate termination of
the simulation, but the pre_abort callback hook gives components an
opportunity to provide additional information to the user before
the termination happens. For example, a test may want to executed
the report function of a particular component even when an error
condition has happened to force a premature termination you would
write a function like:
.. code-block:: python
def pre_abort(self):
self.report()
The pre_abort() callback hooks are called in a bottom-up fashion.
"""
pass
[docs] def m_do_pre_abort(self):
for child in self.m_children:
self.m_children[child].m_do_pre_abort()
self.pre_abort()
#// Group: Recording Interface
#// These methods comprise the component-based transaction recording
#// interface. The methods can be used to record the transactions that
#// this component "sees", i.e. produces or consumes.
#//
#// The API and implementation are subject to change once a vendor-independent
#// use-model is determined.
[docs] def accept_tr(self, tr, accept_time=0):
"""
This function marks the acceptance of a transaction, `tr`, by this
component. Specifically, it performs the following actions:
- Calls the `tr`'s <uvm_transaction::accept_tr> method, passing to it the
`accept_time` argument.
- Calls this component's <do_accept_tr> method to allow for any post-begin
action in derived classes.
- Triggers the component's internal accept_tr event. Any processes waiting
on this event will resume in the next delta cycle.
Args:
tr:
accept_time:
"""
e = None
tr.accept_tr(accept_time)
self.do_accept_tr(tr)
e = self.event_pool.get("accept_tr")
if e is not None:
e.trigger()
[docs] def do_accept_tr(self, tr):
"""
The `accept_tr` method calls this function to accommodate any user-defined
post-accept action. Implementations should call super.do_accept_tr to
ensure correct operation.
Args:
tr:
"""
return
[docs] def begin_tr(self, tr, stream_name="main", label="", desc="", begin_time=0,
parent_handle=0):
"""
This function marks the start of a transaction, `tr`, by this component.
Specifically, it performs the following actions:
- Calls `tr`'s <uvm_transaction::begin_tr> method, passing to it the
`begin_time` argument. The `begin_time` should be greater than or equal
to the accept time. By default, when `begin_time` = 0, the current
simulation time is used.
If recording is enabled (recording_detail != UVM_OFF), then a new
database-transaction is started on the component's transaction stream
given by the stream argument. No transaction properties are recorded at
this time.
- Calls the component's <do_begin_tr> method to allow for any post-begin
action in derived classes.
- Triggers the component's internal begin_tr event. Any processes waiting
on this event will resume in the next delta cycle.
A handle to the transaction is returned. The meaning of this handle, as
well as the interpretation of the arguments `stream_name`, `label`, and
`desc` are vendor specific.
Args:
tr:
stream_name:
label:
desc:
begin_time:
parent_handle:
Returns:
"""
return self.m_begin_tr(tr, parent_handle, stream_name, label, desc, begin_time)
[docs] def begin_child_tr(self, tr, parent_handle=0, stream_name="main", label="", desc="",
begin_time=0):
"""
This function marks the start of a child transaction, `tr`, by this
component. Its operation is identical to that of <begin_tr>, except that
an association is made between this transaction and the provided parent
transaction. This association is vendor-specific.
Args:
tr:
parent_handle:
stream_name:
label:
desc:
begin_time:
Returns:
"""
return self.m_begin_tr(tr, parent_handle, stream_name, label, desc, begin_time)
[docs] def do_begin_tr(self, tr, stream_name, tr_handle):
"""
The <begin_tr> and <begin_child_tr> methods call this function to
accommodate any user-defined post-begin action. Implementations should call
super.do_begin_tr to ensure correct operation.
Args:
tr:
stream_name:
tr_handle:
"""
return
[docs] def end_tr(self, tr, end_time=0, free_handle=1):
"""
Function: end_tr
This function marks the end of a transaction, `tr`, by this component.
Specifically, it performs the following actions:
- Calls `tr`'s <uvm_transaction::end_tr> method, passing to it the
`end_time` argument. The `end_time` must at least be greater than the
begin time. By default, when `end_time` = 0, the current simulation time
is used.
The transaction's properties are recorded to the database-transaction on
which it was started, and then the transaction is ended. Only those
properties handled by the transaction's do_record method (and optional
`uvm_*_field macros) are recorded.
- Calls the component's <do_end_tr> method to accommodate any post-end
action in derived classes.
- Triggers the component's internal end_tr event. Any processes waiting on
this event will resume in the next delta cycle.
The `free_handle` bit indicates that this transaction is no longer needed.
The implementation of free_handle is vendor-specific.
Args:
tr:
end_time:
free_handle:
"""
e = None # uvm_event#(uvm_object) e
recorder = None # uvm_recorder recorder
# db: uvm_tr_database = self.m_get_tr_database()
if tr is None:
return
tr.end_tr(end_time, free_handle)
if self.recording_detail != UVM_NONE:
if tr in self.m_tr_h:
recorder = self.m_tr_h[tr]
self.do_end_tr(tr, recorder.get_handle()) # callback
del self.m_tr_h[tr]
tr.record(recorder)
recorder.close(end_time)
if free_handle:
recorder.free()
else:
self.do_end_tr(tr, 0) # callback
e = self.event_pool.get("end_tr")
if e is not None:
e.trigger()
[docs] def do_end_tr(self, tr, tr_handle):
"""
The <end_tr> method calls this function to accommodate any user-defined
post-end action. Implementations should call super.do_end_tr to ensure
correct operation.
Args:
tr:
tr_handle:
"""
return
#// Function: record_error_tr
#//
#// This function marks an error transaction by a component. Properties of the
#// given uvm_object, `info`, as implemented in its <uvm_object::do_record> method,
#// are recorded to the transaction database.
#//
#// An `error_time` of 0 indicates to use the current simulation time. The
#// `keep_active` bit determines if the handle should remain active. If 0,
#// then a zero-length error transaction is recorded. A handle to the
#// database-transaction is returned.
#//
#// Interpretation of this handle, as well as the strings `stream_name`,
#// `label`, and `desc`, are vendor-specific.
#extern function integer record_error_tr (string stream_name="main",
# uvm_object info=None,
# string label="error_tr",
# string desc="",
# time error_time=0,
# bit keep_active=0)
[docs] def record_error_tr(self, stream_name="main", info=None, label="error_tr", desc="",
error_time=0, keep_active=0):
recorder = None # uvm_recorder
etype = ""
handle = 0
stream = None # uvm_tr_stream
db = self.m_get_tr_database() # uvm_tr_database
if keep_active:
etype = "Event, Link"
else:
etype = "Event"
if error_time == 0:
error_time = sv.realtime()
if (stream_name == "" or stream_name == "main"):
if self.m_main_stream is None:
self.m_main_stream = self.tr_database.open_stream("main", self.get_full_name(), "TVM")
stream = self.m_main_stream
else:
stream = self.get_tr_stream(stream_name)
handle = 0
if stream is not None:
recorder = stream.open_recorder(label, error_time, etype)
if recorder is not None:
if label != "":
recorder.record_string("label", label)
if desc != "":
recorder.record_string("desc", desc)
if info is not None:
info.record(recorder)
recorder.close(error_time)
if keep_active == 0:
recorder.free()
else:
handle = recorder.get_handle()
return handle
#// Function: record_event_tr
#//
#// This function marks an event transaction by a component.
#//
#// An `event_time` of 0 indicates to use the current simulation time.
#//
#// A handle to the transaction is returned. The `keep_active` bit determines
#// if the handle may be used for other vendor-specific purposes.
#//
#// The strings for `stream_name`, `label`, and `desc` are vendor-specific
#// identifiers for the transaction.
#extern function integer record_event_tr (string stream_name="main",
# uvm_object info=None,
# string label="event_tr",
# string desc="",
# time event_time=0,
# bit keep_active=0)
[docs] def record_event_tr(self, stream_name="main", info=None, label="event_tr",
desc="", event_time=0,keep_active=0):
recorder = None # uvm_recorder
etype = ""
handle = 0
stream = None # uvm_tr_stream
db = self.m_get_tr_database() # uvm_tr_database
if keep_active:
etype = "Event, Link"
else:
etype = "Event"
if event_time == 0:
event_time = sv.realtime()
if (stream_name == "" or stream_name=="main"):
if self.m_main_stream is None:
self.m_main_stream = self.tr_database.open_stream("main", self.get_full_name(), "TVM")
stream = self.m_main_stream
else:
stream = self.get_tr_stream(stream_name)
handle = 0
if stream is not None:
recorder = stream.open_recorder(label, event_time, etype)
if recorder is not None:
if label != "":
recorder.record_string("label", label)
if desc != "":
recorder.record_string("desc", desc)
if info is not None:
info.record(recorder)
recorder.close(event_time)
if keep_active == 0:
recorder.free()
else:
handle = recorder.get_handle()
return handle
[docs] def get_tr_stream(self, name, stream_type_name=""):
"""
Streams which are retrieved via this method will be stored internally,
such that later calls to `get_tr_stream` will return the same stream
reference.
The stream can be removed from the internal storage via a call
to `free_tr_stream`.
Args:
name (str):Name for the stream
stream_type_name: Type name for the stream (Default = "")
Returns:
UVMTrStream: Stream with this component's full name as scope.
"""
db = self.m_get_tr_database() # uvm_tr_database
if name not in self.m_streams:
self.m_streams[name] = {}
if stream_type_name not in self.m_streams[name]:
self.m_streams[name][stream_type_name] = db.open_stream(name,
self.get_full_name(), stream_type_name)
return self.m_streams[name][stream_type_name]
#// Function: free_tr_stream
#// Frees the internal references associated with `stream`.
#//
#// The next call to <get_tr_stream> will result in a newly created
#// <uvm_tr_stream>. If the current stream is open (or closed),
#// then it will be freed.
#extern virtual function void free_tr_stream(uvm_tr_stream stream)
[docs] def free_tr_stream(self, stream):
# Check the None case...
if stream is None:
return
str_name = stream.get_name()
str_type_name = stream.get_stream_type_name()
# Then make sure this name/type_name combo exists
if (str_name not in self.m_streams or str_type_name not in
self.m_streams[str_name]):
return
# Then make sure this name/type_name combo is THIS stream
if self.m_streams[str_name][str_type_name] != stream:
return
# Then delete it from the arrays
del self.m_streams[str_name][str_type_name]
if len(self.m_streams[str_name]) == 0:
del self.m_streams[str_name]
# Finally, free the stream if necessary
if stream.is_open() or stream.is_closed():
stream.free()
[docs] def m_get_tr_database(self):
"""
Returns:
"""
if self.tr_database is None:
from .uvm_coreservice import UVMCoreService
cs = UVMCoreService.get()
self.tr_database = cs.get_default_tr_database()
return self.tr_database
[docs] def set_int_local(self, field_name, value, recurse=1):
"""
Args:
field_name:
value:
recurse:
"""
# call the super function to get child recursion and any registered fields
super().set_int_local(field_name, value, recurse)
# set the local properties
if uvm_is_match(field_name, "recording_detail"):
self.recording_detail = value
[docs] def m_set_full_name(self):
"""
m_set_full_name
"""
#if self.m_parent is None:
# uvm_fatal("Should not be called with uvm_root")
from .uvm_root import UVMRoot
#top = UVMRoot.get()
# top = None
top = []
if sv.cast(top, self.m_parent, UVMRoot) or self.m_parent is None:
self.m_name = self.get_name()
else:
self.m_name = self.m_parent.get_full_name() + "." + self.get_name()
for c in self.m_children:
tmp = self.m_children[c]
tmp.m_set_full_name()
[docs] def do_resolve_bindings(self):
"""
do_resolve_bindings
"""
for s in self.m_children:
self.m_children[s].do_resolve_bindings()
self.resolve_bindings()
#extern function void do_flush()
[docs] def do_flush(self):
for c in self.m_children:
self.m_children[c].do_flush()
self.flush()
#extern virtual function void flush ()
#endfunction
[docs] def create(self, name=""):
"""
Overridden to disable component creation using this method.
Args:
name (str): Name of the component.
Returns:
None - Create cannot be called on `UVMComponent`
"""
uvm_error("ILLCRT",
"create cannot be called on a uvm_component. Use create_component instead.")
return None
[docs] def clone(self):
"""
Components cannot be cloned. Added this to show `uvm_error` whenever a
cloning is attempted.
Returns:
None - Components cannot be cloned.
"""
uvm_error("ILLCLN", sv.sformatf(CLONE_ERR, self.get_full_name()))
return None
[docs] def m_begin_tr(self, tr, parent_handle=0, stream_name="main", label="",
desc="", begin_time=0):
"""
Args:
tr (UVMTransaction):
parent_handle:
stream_name (str):
label (str):
desc (str):
begin_time (int):
Returns:
"""
e = None # uvm_event#(uvm_object) e
name = ""
kind = ""
db = None # uvm_tr_database db
handle = 0
link_handle = 0
stream = None # uvm_tr_stream
# uvm_recorder
recorder = None
parent_recorder = None
link_recorder = None
if tr is None:
return 0
db = self.m_get_tr_database()
if parent_handle != 0:
parent_recorder = UVMRecorder.get_recorder_from_handle(parent_handle)
if parent_recorder is None:
seq = [] # uvm_sequence_item
from ..seq.uvm_sequence_item import UVMSequenceItem
if (sv.cast(seq,tr, UVMSequenceItem)):
seq = seq[0]
parent_seq = seq.get_parent_sequence()
if (parent_seq is not None):
parent_recorder = parent_seq.m_tr_recorder
if parent_recorder is not None:
link_handle = tr.begin_child_tr(begin_time, parent_recorder.get_handle())
else:
link_handle = tr.begin_tr(begin_time)
if link_handle != 0:
link_recorder = UVMRecorder.get_recorder_from_handle(link_handle)
if tr.get_name() != "":
name = tr.get_name()
else:
name = tr.get_type_name()
# TODO needed for recording only
if self.recording_detail != UVM_NONE:
if (stream_name == "") or (stream_name == "main"):
if self.m_main_stream is None:
self.m_main_stream = db.open_stream("main", self.get_full_name(), "TVM")
stream = self.m_main_stream
else:
stream = self.get_tr_stream(stream_name)
if stream is not None:
kind = "Begin_End, Link"
if parent_recorder is None:
kind = "Begin_No_Parent, Link"
recorder = stream.open_recorder(name, begin_time, kind)
if recorder is not None:
if label != "":
recorder.record_string("label", label)
if desc != "":
recorder.record_string("desc", desc)
if parent_recorder is not None:
self.tr_database.establish_link(UVMParentChildLink.get_link(parent_recorder,
recorder))
if link_recorder is not None:
self.tr_database.establish_link(UVMRelatedLink.get_link(recorder,
link_recorder))
self.m_tr_h[tr] = recorder
handle = 0
if recorder is not None:
handle = recorder.get_handle()
self.do_begin_tr(tr, stream_name, handle)
e = self.event_pool.get("begin_tr")
if e is not None:
e.trigger(tr)
return handle
#type_name = "uvm_component"
#def get_type_name(self):
# return UVMComponent.type_name
#extern function void do_print(uvm_printer printer)
[docs] def m_set_cl_msg_args(self):
"""
Internal methods for setting up command line messaging stuff
#extern function void m_set_cl_msg_args
"""
self.m_set_cl_verb()
self.m_set_cl_action()
self.m_set_cl_sev()
first_m_set_cl_verb = 1
[docs] def m_set_cl_verb(self):
"""
#extern function void m_set_cl_verb
"""
# // _ALL_ can be used for ids
# // +uvm_set_verbosity=<comp>,<id>,<verbosity>,<phase|time>,<offset>
# // +uvm_set_verbosity=uvm_test_top.env0.agent1.*,_ALL_,UVM_FULL,time,800
from .uvm_coreservice import UVMCoreService
cs = UVMCoreService.get()
from .uvm_cmdline_processor import UVMCmdlineProcessor
values = [] # static string values[$]
args = [] # string args[$]
clp = UVMCmdlineProcessor.get_inst()
cs = UVMCoreService.get()
top = cs.get_root()
if len(values) == 0:
clp.get_arg_values("+uvm_set_verbosity=", values)
for i in range(len(values)):
setting = VerbositySetting()
args.clear()
uvm_split_string(values[i], ",", args)
# Warning is already issued in uvm_root, so just don't keep it
len_match = len(args) not in [4, 5]
setting.verbosity = clp.m_convert_verb(args[2])
if UVMComponent.first_m_set_cl_verb and (len_match or setting.verbosity == -1):
del values[i]
else:
setting.comp = args[0]
setting.id = args[1]
setting.verbosity = clp.m_convert_verb(args[2])
setting.phase = args[3]
setting.offset = 0
if len(args) == 5:
setting.offset = int(args[4])
if ((setting.phase == "time") and (self == top)):
UVMComponent.m_time_settings.append(setting)
if uvm_is_match(setting.comp, self.get_full_name()):
if((setting.phase == "" or setting.phase == "build" or
setting.phase == "time") and setting.offset == 0):
if setting.id == "_ALL_":
self.set_report_verbosity_level(setting.verbosity)
else:
self.set_report_id_verbosity(setting.id, setting.verbosity)
else:
if setting.phase != "time":
self.m_verbosity_settings.append(setting)
if self == top:
cocotb.start_soon(self.m_fork_time_settings(top))
UVMComponent.first_m_set_cl_verb = 0
[docs] async def m_fork_time_settings(self, top):
m_time_settings = UVMComponent.m_time_settings
#fork begin
last_time = 0
if len(m_time_settings) > 0:
m_time_settings.sort(key=lambda item: item.offset)
for i in range(len(m_time_settings)):
comps = []
top.find_all(m_time_settings[i].comp, comps)
duration = m_time_settings[i].offset - last_time
last_time = m_time_settings[i].offset
cocotb.start_soon(self.m_set_comp_settings(i, comps.copy(), duration))
#end join_none // fork begin
[docs] async def m_set_comp_settings(self, i, comps, dur):
m_time_settings = UVMComponent.m_time_settings
await Timer(dur)
if m_time_settings[i].id == "_ALL_":
for comp in comps:
comp.set_report_verbosity_level(m_time_settings[i].verbosity)
else:
for comp in comps:
comp.set_report_id_verbosity(m_time_settings[i].id, m_time_settings[i].verbosity)
initialized_m_set_cl_action = 0
#extern function void m_set_cl_action
[docs] def m_set_cl_action(self):
# _ALL_ can be used for ids or severities
# +uvm_set_action=<comp>,<id>,<severity>,<action[|action]>
# +uvm_set_action=uvm_test_top.env0.*,_ALL_,UVM_ERROR,UVM_NO_ACTION
sev = 0
action = 0
if not UVMComponent.initialized_m_set_cl_action:
from .uvm_cmdline_processor import UVMCmdlineProcessor
values = []
UVMCmdlineProcessor.uvm_cmdline_proc.get_arg_values("+uvm_set_action=", values)
for idx in range(len(values)):
t = uvm_cmdline_parsed_arg_t()
args = []
uvm_split_string(values[idx], ",", args)
if len(args) != 4:
uvm_warning("INVLCMDARGS", sv.sformatf(INV_WARN1, len(args), values[idx]))
if((args[2] != "_ALL_") and not uvm_string_to_severity(args[2], sev)):
uvm_warning("INVLCMDARGS", sv.sformatf(INV_WARN2, args[2], values[idx]))
continue
if not uvm_string_to_action(args[3], action):
uvm_warning("INVLCMDARGS", sv.sformatf(INV_WARN3, args[3], values[idx]))
continue
t.args = args
t.arg = values[idx]
UVMComponent.m_uvm_applied_cl_action.append(t)
UVMComponent.initialized_m_set_cl_action = 1
for i in range(len(UVMComponent.m_uvm_applied_cl_action)):
args = UVMComponent.m_uvm_applied_cl_action[i].args
if not uvm_is_match(args[0], self.get_full_name()):
continue
sev = uvm_string_to_severity(args[2], sev)
action = uvm_string_to_action(args[3], action)
UVMComponent.m_uvm_applied_cl_action[i].used += 1
if args[1] == "_ALL_":
if args[2] == "_ALL_":
self.set_report_severity_action(UVM_INFO, action)
self.set_report_severity_action(UVM_WARNING, action)
self.set_report_severity_action(UVM_ERROR, action)
self.set_report_severity_action(UVM_FATAL, action)
else:
self.set_report_severity_action(sev, action)
else:
if args[2] == "_ALL_":
self.set_report_id_action(args[1], action)
else:
self.set_report_severity_id_action(sev, args[1], action)
initialized_m_set_cl_sev = 0
#extern function void m_set_cl_sev
[docs] def m_set_cl_sev(self):
# // _ALL_ can be used for ids or severities
# // +uvm_set_severity=<comp>,<id>,<orig_severity>,<new_severity>
# // +uvm_set_severity=uvm_test_top.env0.*,BAD_CRC,UVM_ERROR,UVM_WARNING
orig_sev = 0
sev = 0
if not UVMComponent.initialized_m_set_cl_sev:
values = []
from .uvm_cmdline_processor import UVMCmdlineProcessor
UVMCmdlineProcessor.uvm_cmdline_proc.get_arg_values("+uvm_set_severity=",values)
for idx in range(len(values)):
t = uvm_cmdline_parsed_arg_t()
args = [] # string[$]
uvm_split_string(values[idx], ",", args)
if len(args) != 4:
uvm_warning("INVLCMDARGS", sv.sformatf(INV_WARN4, len(args), values[idx]))
continue
if args[2] != "_ALL_" and not uvm_string_to_severity(args[2], orig_sev):
uvm_warning("INVLCMDARGS", sv.sformatf(INV_WARN5, args[2], values[idx]))
continue
if uvm_string_to_severity(args[3], sev) == -1:
uvm_warning("INVLCMDARGS", sv.sformatf(INV_WARN6, args[3], values[idx]))
continue
t.args = args
t.arg = values[idx]
UVMComponent.m_uvm_applied_cl_sev.append(t)
UVMComponent.initialized_m_set_cl_sev = 1
m_uvm_applied_cl_sev = UVMComponent.m_uvm_applied_cl_sev
for i in range(len(m_uvm_applied_cl_sev)):
args = m_uvm_applied_cl_sev[i].args
if not uvm_is_match(args[0], self.get_full_name()):
continue
orig_sev = uvm_string_to_severity(args[2], orig_sev)
sev = uvm_string_to_severity(args[3], sev)
m_uvm_applied_cl_sev[i].used += 1
if (args[1] == "_ALL_" and args[2] == "_ALL_"):
self.set_report_severity_override(UVM_INFO,sev)
self.set_report_severity_override(UVM_WARNING,sev)
self.set_report_severity_override(UVM_ERROR,sev)
self.set_report_severity_override(UVM_FATAL,sev)
elif (args[1] == "_ALL_"):
self.set_report_severity_override(orig_sev,sev)
elif (args[2] == "_ALL_"):
self.set_report_severity_id_override(UVM_INFO,args[1],sev)
self.set_report_severity_id_override(UVM_WARNING,args[1],sev)
self.set_report_severity_id_override(UVM_ERROR,args[1],sev)
self.set_report_severity_id_override(UVM_FATAL,args[1],sev)
else:
self.set_report_severity_id_override(orig_sev,args[1],sev)
m_uvm_applied_cl_action: List[uvm_cmdline_parsed_arg_t] = []
m_uvm_applied_cl_sev: List[uvm_cmdline_parsed_arg_t] = []
[docs] def m_add_child(self, child):
if child.get_name() in self.m_children:
old_child = self.m_children[child.get_name()]
uvm_warning("BDCLD",
"A child with name {} (type={}) exists"
.format(child.get_name(), old_child.get_type_name()))
return False
self.m_children[child.get_name()] = child
self.m_children_ordered.append(child)
self.m_children_by_handle[child] = child
return True
[docs] def has_first_child(self):
return len(self.m_children_ordered) > 0
[docs] def has_next_child(self):
return len(self.m_children_ordered) > (self.child_ptr + 1)
[docs] def m_apply_verbosity_settings(self, phase):
"""
#extern function void m_apply_verbosity_settings(uvm_phase phase)
Args:
phase:
"""
pass
for i in self.m_verbosity_settings:
if phase.get_name() == self.m_verbosity_settings[i].phase:
if self.m_verbosity_settings[i].offset == 0:
if self.m_verbosity_settings[i].id == "_ALL_":
self.set_report_verbosity_level(self.m_verbosity_settings[i].verbosity)
else:
self.set_report_id_verbosity(self.m_verbosity_settings[i].id,
self.m_verbosity_settings[i].verbosity)
else:
#process p = process::self()
#string p_rand = p.get_randstate()
#fork begin
setting = self.m_verbosity_settings[i]
#setting.offset
if setting.id == "_ALL_":
self.set_report_verbosity_level(setting.verbosity)
else:
self.set_report_id_verbosity(setting.id, setting.verbosity)
#end join_none
#p.set_randstate(p_rand)
# Remove after use
del self.m_verbosity_settings[i]
[docs] def kill(self):
"""
Kill internal run process of this component.
"""
if self.m_run_process is not None:
if hasattr(self.m_run_process, 'kill'):
self.m_run_process.kill()
else:
print("No kill() available")
#//
#// Factory Methods
#// set_inst_override
#
#function void uvm_component::set_inst_override (string relative_inst_path,
# string original_type_name,
# string override_type_name)
# full_inst_path = ""
# factory= _get_factory()
#
# if (relative_inst_path == "")
# full_inst_path = get_full_name()
# else
# full_inst_path = {get_full_name(), ".", relative_inst_path}
#
# factory.set_inst_override_by_name(
# original_type_name,
# override_type_name,
# full_inst_path)
#endfunction
#
#
#//
#// Configuration interface
#//
#
#
#// Undocumented struct for storing clone bit along w/
#// object on set_config_object(...) calls
#class uvm_config_object_wrapper
# uvm_object obj
# bit clone
#endclass : uvm_config_object_wrapper
#
#
#// do_print (override)
#// --------
#
#function void uvm_component::do_print(uvm_printer printer)
# string v
# super.do_print(printer)
#
# // It is printed only if its value is other than the default (UVM_NONE)
# if(uvm_verbosity'(recording_detail) != UVM_NONE)
# case (recording_detail)
# UVM_LOW : printer.print_generic("recording_detail", "uvm_verbosity",
# $bits(recording_detail), "UVM_LOW")
# UVM_MEDIUM : printer.print_generic("recording_detail", "uvm_verbosity",
# $bits(recording_detail), "UVM_MEDIUM")
# UVM_HIGH : printer.print_generic("recording_detail", "uvm_verbosity",
# $bits(recording_detail), "UVM_HIGH")
# UVM_FULL : printer.print_generic("recording_detail", "uvm_verbosity",
# $bits(recording_detail), "UVM_FULL")
# default : printer.print_field_int("recording_detail", recording_detail,
# $bits(recording_detail), UVM_DEC, , "integral")
# endcase
#
#endfunction
def _get_factory():
from .uvm_coreservice import UVMCoreService
cs = UVMCoreService.get()
factory = cs.get_factory()
return factory