There is a circular dependency between params and proxy at import time. This causes issues for Python 3. Add the imports to the specific methods with the dependencies to make the import happen when the method is executed instead. Change-Id: I770112fd3c07c395459e204976942bda3dc7236f Signed-off-by: Andreas Sandberg <andreas.sandberg@arm.com> Reviewed-on: https://gem5-review.googlesource.com/c/15993 Reviewed-by: Giacomo Travaglini <giacomo.travaglini@arm.com> Reviewed-by: Juha Jäykkä <juha.jaykka@arm.com>
267 lines
9.3 KiB
Python
267 lines
9.3 KiB
Python
# Copyright (c) 2018 ARM Limited
|
|
# All rights reserved.
|
|
#
|
|
# The license below extends only to copyright in the software and shall
|
|
# not be construed as granting a license to any other intellectual
|
|
# property including but not limited to intellectual property relating
|
|
# to a hardware implementation of the functionality of the software
|
|
# licensed hereunder. You may use the software subject to the license
|
|
# terms below provided that you ensure that this notice is replicated
|
|
# unmodified and in its entirety in all distributions of the software,
|
|
# modified or unmodified, in source code or in binary form.
|
|
#
|
|
# Copyright (c) 2004-2006 The Regents of The University of Michigan
|
|
# All rights reserved.
|
|
#
|
|
# Redistribution and use in source and binary forms, with or without
|
|
# modification, are permitted provided that the following conditions are
|
|
# met: redistributions of source code must retain the above copyright
|
|
# notice, this list of conditions and the following disclaimer;
|
|
# redistributions in binary form must reproduce the above copyright
|
|
# notice, this list of conditions and the following disclaimer in the
|
|
# documentation and/or other materials provided with the distribution;
|
|
# neither the name of the copyright holders nor the names of its
|
|
# contributors may be used to endorse or promote products derived from
|
|
# this software without specific prior written permission.
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
#
|
|
# Authors: Steve Reinhardt
|
|
# Nathan Binkert
|
|
|
|
#####################################################################
|
|
#
|
|
# Proxy object support.
|
|
#
|
|
#####################################################################
|
|
|
|
from __future__ import print_function
|
|
from __future__ import absolute_import
|
|
|
|
import copy
|
|
|
|
|
|
class BaseProxy(object):
|
|
def __init__(self, search_self, search_up):
|
|
self._search_self = search_self
|
|
self._search_up = search_up
|
|
self._multipliers = []
|
|
|
|
def __str__(self):
|
|
if self._search_self and not self._search_up:
|
|
s = 'Self'
|
|
elif not self._search_self and self._search_up:
|
|
s = 'Parent'
|
|
else:
|
|
s = 'ConfusedProxy'
|
|
return s + '.' + self.path()
|
|
|
|
def __setattr__(self, attr, value):
|
|
if not attr.startswith('_'):
|
|
raise AttributeError(
|
|
"cannot set attribute '%s' on proxy object" % attr)
|
|
super(BaseProxy, self).__setattr__(attr, value)
|
|
|
|
# support for multiplying proxies by constants or other proxies to
|
|
# other params
|
|
def __mul__(self, other):
|
|
if not (isinstance(other, (int, long, float)) or isproxy(other)):
|
|
raise TypeError(
|
|
"Proxy multiplier must be a constant or a proxy to a param")
|
|
self._multipliers.append(other)
|
|
return self
|
|
|
|
__rmul__ = __mul__
|
|
|
|
def _mulcheck(self, result, base):
|
|
for multiplier in self._multipliers:
|
|
if isproxy(multiplier):
|
|
multiplier = multiplier.unproxy(base)
|
|
# assert that we are multiplying with a compatible
|
|
# param
|
|
if not isinstance(multiplier, params.NumericParamValue):
|
|
raise TypeError(
|
|
"Proxy multiplier must be a numerical param")
|
|
multiplier = multiplier.getValue()
|
|
result *= multiplier
|
|
return result
|
|
|
|
def unproxy(self, base):
|
|
obj = base
|
|
done = False
|
|
|
|
if self._search_self:
|
|
result, done = self.find(obj)
|
|
|
|
if self._search_up:
|
|
# Search up the tree but mark ourself
|
|
# as visited to avoid a self-reference
|
|
self._visited = True
|
|
obj._visited = True
|
|
while not done:
|
|
obj = obj._parent
|
|
if not obj:
|
|
break
|
|
result, done = self.find(obj)
|
|
|
|
self._visited = False
|
|
base._visited = False
|
|
|
|
if not done:
|
|
raise AttributeError(
|
|
"Can't resolve proxy '%s' of type '%s' from '%s'" % \
|
|
(self.path(), self._pdesc.ptype_str, base.path()))
|
|
|
|
if isinstance(result, BaseProxy):
|
|
if result == self:
|
|
raise RuntimeError("Cycle in unproxy")
|
|
result = result.unproxy(obj)
|
|
|
|
return self._mulcheck(result, base)
|
|
|
|
def getindex(obj, index):
|
|
if index == None:
|
|
return obj
|
|
try:
|
|
obj = obj[index]
|
|
except TypeError:
|
|
if index != 0:
|
|
raise
|
|
# if index is 0 and item is not subscriptable, just
|
|
# use item itself (so cpu[0] works on uniprocessors)
|
|
return obj
|
|
getindex = staticmethod(getindex)
|
|
|
|
# This method should be called once the proxy is assigned to a
|
|
# particular parameter or port to set the expected type of the
|
|
# resolved proxy
|
|
def set_param_desc(self, pdesc):
|
|
self._pdesc = pdesc
|
|
|
|
class AttrProxy(BaseProxy):
|
|
def __init__(self, search_self, search_up, attr):
|
|
super(AttrProxy, self).__init__(search_self, search_up)
|
|
self._attr = attr
|
|
self._modifiers = []
|
|
|
|
def __getattr__(self, attr):
|
|
# python uses __bases__ internally for inheritance
|
|
if attr.startswith('_'):
|
|
return super(AttrProxy, self).__getattr__(self, attr)
|
|
if hasattr(self, '_pdesc'):
|
|
raise AttributeError("Attribute reference on bound proxy")
|
|
# Return a copy of self rather than modifying self in place
|
|
# since self could be an indirect reference via a variable or
|
|
# parameter
|
|
new_self = copy.deepcopy(self)
|
|
new_self._modifiers.append(attr)
|
|
return new_self
|
|
|
|
# support indexing on proxies (e.g., Self.cpu[0])
|
|
def __getitem__(self, key):
|
|
if not isinstance(key, int):
|
|
raise TypeError("Proxy object requires integer index")
|
|
if hasattr(self, '_pdesc'):
|
|
raise AttributeError("Index operation on bound proxy")
|
|
new_self = copy.deepcopy(self)
|
|
new_self._modifiers.append(key)
|
|
return new_self
|
|
|
|
def find(self, obj):
|
|
try:
|
|
val = getattr(obj, self._attr)
|
|
visited = False
|
|
if hasattr(val, '_visited'):
|
|
visited = getattr(val, '_visited')
|
|
|
|
if not visited:
|
|
# for any additional unproxying to be done, pass the
|
|
# current, rather than the original object so that proxy
|
|
# has the right context
|
|
obj = val
|
|
else:
|
|
return None, False
|
|
except:
|
|
return None, False
|
|
while isproxy(val):
|
|
val = val.unproxy(obj)
|
|
for m in self._modifiers:
|
|
if isinstance(m, str):
|
|
val = getattr(val, m)
|
|
elif isinstance(m, int):
|
|
val = val[m]
|
|
else:
|
|
assert("Item must be string or integer")
|
|
while isproxy(val):
|
|
val = val.unproxy(obj)
|
|
return val, True
|
|
|
|
def path(self):
|
|
p = self._attr
|
|
for m in self._modifiers:
|
|
if isinstance(m, str):
|
|
p += '.%s' % m
|
|
elif isinstance(m, int):
|
|
p += '[%d]' % m
|
|
else:
|
|
assert("Item must be string or integer")
|
|
return p
|
|
|
|
class AnyProxy(BaseProxy):
|
|
def find(self, obj):
|
|
return obj.find_any(self._pdesc.ptype)
|
|
|
|
def path(self):
|
|
return 'any'
|
|
|
|
# The AllProxy traverses the entire sub-tree (not only the children)
|
|
# and adds all objects of a specific type
|
|
class AllProxy(BaseProxy):
|
|
def find(self, obj):
|
|
return obj.find_all(self._pdesc.ptype)
|
|
|
|
def path(self):
|
|
return 'all'
|
|
|
|
def isproxy(obj):
|
|
from . import params
|
|
if isinstance(obj, (BaseProxy, params.EthernetAddr)):
|
|
return True
|
|
elif isinstance(obj, (list, tuple)):
|
|
for v in obj:
|
|
if isproxy(v):
|
|
return True
|
|
return False
|
|
|
|
class ProxyFactory(object):
|
|
def __init__(self, search_self, search_up):
|
|
self.search_self = search_self
|
|
self.search_up = search_up
|
|
|
|
def __getattr__(self, attr):
|
|
if attr == 'any':
|
|
return AnyProxy(self.search_self, self.search_up)
|
|
elif attr == 'all':
|
|
if self.search_up:
|
|
assert("Parant.all is not supported")
|
|
return AllProxy(self.search_self, self.search_up)
|
|
else:
|
|
return AttrProxy(self.search_self, self.search_up, attr)
|
|
|
|
# global objects for handling proxies
|
|
Parent = ProxyFactory(search_self = False, search_up = True)
|
|
Self = ProxyFactory(search_self = True, search_up = False)
|
|
|
|
# limit exports on 'from proxy import *'
|
|
__all__ = ['Parent', 'Self']
|