proxy.py revision 13761
112798Snikos.nikoleris@arm.com# Copyright (c) 2018 ARM Limited 212798Snikos.nikoleris@arm.com# All rights reserved. 312798Snikos.nikoleris@arm.com# 412798Snikos.nikoleris@arm.com# The license below extends only to copyright in the software and shall 512798Snikos.nikoleris@arm.com# not be construed as granting a license to any other intellectual 612798Snikos.nikoleris@arm.com# property including but not limited to intellectual property relating 712798Snikos.nikoleris@arm.com# to a hardware implementation of the functionality of the software 812798Snikos.nikoleris@arm.com# licensed hereunder. You may use the software subject to the license 912798Snikos.nikoleris@arm.com# terms below provided that you ensure that this notice is replicated 1012798Snikos.nikoleris@arm.com# unmodified and in its entirety in all distributions of the software, 1112798Snikos.nikoleris@arm.com# modified or unmodified, in source code or in binary form. 1212798Snikos.nikoleris@arm.com# 133101Sstever@eecs.umich.edu# Copyright (c) 2004-2006 The Regents of The University of Michigan 143101Sstever@eecs.umich.edu# All rights reserved. 153101Sstever@eecs.umich.edu# 163101Sstever@eecs.umich.edu# Redistribution and use in source and binary forms, with or without 173101Sstever@eecs.umich.edu# modification, are permitted provided that the following conditions are 183101Sstever@eecs.umich.edu# met: redistributions of source code must retain the above copyright 193101Sstever@eecs.umich.edu# notice, this list of conditions and the following disclaimer; 203101Sstever@eecs.umich.edu# redistributions in binary form must reproduce the above copyright 213101Sstever@eecs.umich.edu# notice, this list of conditions and the following disclaimer in the 223101Sstever@eecs.umich.edu# documentation and/or other materials provided with the distribution; 233101Sstever@eecs.umich.edu# neither the name of the copyright holders nor the names of its 243101Sstever@eecs.umich.edu# contributors may be used to endorse or promote products derived from 253101Sstever@eecs.umich.edu# this software without specific prior written permission. 263101Sstever@eecs.umich.edu# 273101Sstever@eecs.umich.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 283101Sstever@eecs.umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 293101Sstever@eecs.umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 303101Sstever@eecs.umich.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 313101Sstever@eecs.umich.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 323101Sstever@eecs.umich.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 333101Sstever@eecs.umich.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 343101Sstever@eecs.umich.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 353101Sstever@eecs.umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 363101Sstever@eecs.umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 373101Sstever@eecs.umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 383101Sstever@eecs.umich.edu# 393101Sstever@eecs.umich.edu# Authors: Steve Reinhardt 403101Sstever@eecs.umich.edu# Nathan Binkert 413101Sstever@eecs.umich.edu 423101Sstever@eecs.umich.edu##################################################################### 433101Sstever@eecs.umich.edu# 443101Sstever@eecs.umich.edu# Proxy object support. 453101Sstever@eecs.umich.edu# 463101Sstever@eecs.umich.edu##################################################################### 473101Sstever@eecs.umich.edu 4813714Sandreas.sandberg@arm.comfrom __future__ import print_function 4913714Sandreas.sandberg@arm.comfrom __future__ import absolute_import 5013719Sandreas.sandberg@arm.comimport six 5113719Sandreas.sandberg@arm.comif six.PY3: 5213719Sandreas.sandberg@arm.com long = int 5313714Sandreas.sandberg@arm.com 543179Sstever@eecs.umich.eduimport copy 553179Sstever@eecs.umich.edu 5612798Snikos.nikoleris@arm.com 573101Sstever@eecs.umich.educlass BaseProxy(object): 583101Sstever@eecs.umich.edu def __init__(self, search_self, search_up): 593101Sstever@eecs.umich.edu self._search_self = search_self 603101Sstever@eecs.umich.edu self._search_up = search_up 6112798Snikos.nikoleris@arm.com self._multipliers = [] 623101Sstever@eecs.umich.edu 633109Sstever@eecs.umich.edu def __str__(self): 643109Sstever@eecs.umich.edu if self._search_self and not self._search_up: 653109Sstever@eecs.umich.edu s = 'Self' 663109Sstever@eecs.umich.edu elif not self._search_self and self._search_up: 673109Sstever@eecs.umich.edu s = 'Parent' 683109Sstever@eecs.umich.edu else: 693109Sstever@eecs.umich.edu s = 'ConfusedProxy' 703109Sstever@eecs.umich.edu return s + '.' + self.path() 713109Sstever@eecs.umich.edu 723101Sstever@eecs.umich.edu def __setattr__(self, attr, value): 733101Sstever@eecs.umich.edu if not attr.startswith('_'): 7413663Sandreas.sandberg@arm.com raise AttributeError( 7513663Sandreas.sandberg@arm.com "cannot set attribute '%s' on proxy object" % attr) 763101Sstever@eecs.umich.edu super(BaseProxy, self).__setattr__(attr, value) 773101Sstever@eecs.umich.edu 7812798Snikos.nikoleris@arm.com # support for multiplying proxies by constants or other proxies to 7912798Snikos.nikoleris@arm.com # other params 803101Sstever@eecs.umich.edu def __mul__(self, other): 8112798Snikos.nikoleris@arm.com if not (isinstance(other, (int, long, float)) or isproxy(other)): 8213663Sandreas.sandberg@arm.com raise TypeError( 8313663Sandreas.sandberg@arm.com "Proxy multiplier must be a constant or a proxy to a param") 8412798Snikos.nikoleris@arm.com self._multipliers.append(other) 853101Sstever@eecs.umich.edu return self 863101Sstever@eecs.umich.edu 873101Sstever@eecs.umich.edu __rmul__ = __mul__ 883101Sstever@eecs.umich.edu 8912798Snikos.nikoleris@arm.com def _mulcheck(self, result, base): 9013761Sodanrc@yahoo.com.br from . import params 9112798Snikos.nikoleris@arm.com for multiplier in self._multipliers: 9212798Snikos.nikoleris@arm.com if isproxy(multiplier): 9312798Snikos.nikoleris@arm.com multiplier = multiplier.unproxy(base) 9412798Snikos.nikoleris@arm.com # assert that we are multiplying with a compatible 9512798Snikos.nikoleris@arm.com # param 9612798Snikos.nikoleris@arm.com if not isinstance(multiplier, params.NumericParamValue): 9713663Sandreas.sandberg@arm.com raise TypeError( 9813663Sandreas.sandberg@arm.com "Proxy multiplier must be a numerical param") 9912798Snikos.nikoleris@arm.com multiplier = multiplier.getValue() 10013761Sodanrc@yahoo.com.br result = result * multiplier 10112798Snikos.nikoleris@arm.com return result 1023101Sstever@eecs.umich.edu 1033101Sstever@eecs.umich.edu def unproxy(self, base): 1043101Sstever@eecs.umich.edu obj = base 1053101Sstever@eecs.umich.edu done = False 1063101Sstever@eecs.umich.edu 1073101Sstever@eecs.umich.edu if self._search_self: 1083101Sstever@eecs.umich.edu result, done = self.find(obj) 1093101Sstever@eecs.umich.edu 1103101Sstever@eecs.umich.edu if self._search_up: 11110195SGeoffrey.Blake@arm.com # Search up the tree but mark ourself 11210195SGeoffrey.Blake@arm.com # as visited to avoid a self-reference 11310195SGeoffrey.Blake@arm.com self._visited = True 11410195SGeoffrey.Blake@arm.com obj._visited = True 1153101Sstever@eecs.umich.edu while not done: 1163101Sstever@eecs.umich.edu obj = obj._parent 1173101Sstever@eecs.umich.edu if not obj: 1183101Sstever@eecs.umich.edu break 1193101Sstever@eecs.umich.edu result, done = self.find(obj) 1203101Sstever@eecs.umich.edu 12110195SGeoffrey.Blake@arm.com self._visited = False 12210195SGeoffrey.Blake@arm.com base._visited = False 12310195SGeoffrey.Blake@arm.com 1243101Sstever@eecs.umich.edu if not done: 12513663Sandreas.sandberg@arm.com raise AttributeError( 12613663Sandreas.sandberg@arm.com "Can't resolve proxy '%s' of type '%s' from '%s'" % \ 12713663Sandreas.sandberg@arm.com (self.path(), self._pdesc.ptype_str, base.path())) 1283101Sstever@eecs.umich.edu 1293101Sstever@eecs.umich.edu if isinstance(result, BaseProxy): 1303101Sstever@eecs.umich.edu if result == self: 13113663Sandreas.sandberg@arm.com raise RuntimeError("Cycle in unproxy") 1323101Sstever@eecs.umich.edu result = result.unproxy(obj) 1333101Sstever@eecs.umich.edu 13412798Snikos.nikoleris@arm.com return self._mulcheck(result, base) 1353101Sstever@eecs.umich.edu 1363101Sstever@eecs.umich.edu def getindex(obj, index): 1373101Sstever@eecs.umich.edu if index == None: 1383101Sstever@eecs.umich.edu return obj 1393101Sstever@eecs.umich.edu try: 1403101Sstever@eecs.umich.edu obj = obj[index] 1413101Sstever@eecs.umich.edu except TypeError: 1423101Sstever@eecs.umich.edu if index != 0: 1433101Sstever@eecs.umich.edu raise 1443101Sstever@eecs.umich.edu # if index is 0 and item is not subscriptable, just 1453101Sstever@eecs.umich.edu # use item itself (so cpu[0] works on uniprocessors) 1463101Sstever@eecs.umich.edu return obj 1473101Sstever@eecs.umich.edu getindex = staticmethod(getindex) 1483101Sstever@eecs.umich.edu 1493109Sstever@eecs.umich.edu # This method should be called once the proxy is assigned to a 1503109Sstever@eecs.umich.edu # particular parameter or port to set the expected type of the 1513109Sstever@eecs.umich.edu # resolved proxy 1523101Sstever@eecs.umich.edu def set_param_desc(self, pdesc): 1533101Sstever@eecs.umich.edu self._pdesc = pdesc 1543101Sstever@eecs.umich.edu 1553101Sstever@eecs.umich.educlass AttrProxy(BaseProxy): 1563101Sstever@eecs.umich.edu def __init__(self, search_self, search_up, attr): 1573101Sstever@eecs.umich.edu super(AttrProxy, self).__init__(search_self, search_up) 1583101Sstever@eecs.umich.edu self._attr = attr 1593101Sstever@eecs.umich.edu self._modifiers = [] 1603101Sstever@eecs.umich.edu 1613101Sstever@eecs.umich.edu def __getattr__(self, attr): 1623101Sstever@eecs.umich.edu # python uses __bases__ internally for inheritance 1633101Sstever@eecs.umich.edu if attr.startswith('_'): 1643101Sstever@eecs.umich.edu return super(AttrProxy, self).__getattr__(self, attr) 1653101Sstever@eecs.umich.edu if hasattr(self, '_pdesc'): 16613663Sandreas.sandberg@arm.com raise AttributeError("Attribute reference on bound proxy") 1673179Sstever@eecs.umich.edu # Return a copy of self rather than modifying self in place 1683179Sstever@eecs.umich.edu # since self could be an indirect reference via a variable or 1693179Sstever@eecs.umich.edu # parameter 1703179Sstever@eecs.umich.edu new_self = copy.deepcopy(self) 1713179Sstever@eecs.umich.edu new_self._modifiers.append(attr) 1723179Sstever@eecs.umich.edu return new_self 1733101Sstever@eecs.umich.edu 1743101Sstever@eecs.umich.edu # support indexing on proxies (e.g., Self.cpu[0]) 1753101Sstever@eecs.umich.edu def __getitem__(self, key): 1763101Sstever@eecs.umich.edu if not isinstance(key, int): 17713663Sandreas.sandberg@arm.com raise TypeError("Proxy object requires integer index") 1783179Sstever@eecs.umich.edu if hasattr(self, '_pdesc'): 17913663Sandreas.sandberg@arm.com raise AttributeError("Index operation on bound proxy") 1803179Sstever@eecs.umich.edu new_self = copy.deepcopy(self) 1813179Sstever@eecs.umich.edu new_self._modifiers.append(key) 1823179Sstever@eecs.umich.edu return new_self 1833101Sstever@eecs.umich.edu 1843101Sstever@eecs.umich.edu def find(self, obj): 1853101Sstever@eecs.umich.edu try: 1863101Sstever@eecs.umich.edu val = getattr(obj, self._attr) 18710195SGeoffrey.Blake@arm.com visited = False 18810195SGeoffrey.Blake@arm.com if hasattr(val, '_visited'): 18910195SGeoffrey.Blake@arm.com visited = getattr(val, '_visited') 19010195SGeoffrey.Blake@arm.com 19113742Sandreas.sandberg@arm.com if visited: 19213742Sandreas.sandberg@arm.com return None, False 19313742Sandreas.sandberg@arm.com 19413742Sandreas.sandberg@arm.com if not isproxy(val): 19510195SGeoffrey.Blake@arm.com # for any additional unproxying to be done, pass the 19610195SGeoffrey.Blake@arm.com # current, rather than the original object so that proxy 19710195SGeoffrey.Blake@arm.com # has the right context 19810195SGeoffrey.Blake@arm.com obj = val 19913742Sandreas.sandberg@arm.com 2003101Sstever@eecs.umich.edu except: 2013101Sstever@eecs.umich.edu return None, False 2023101Sstever@eecs.umich.edu while isproxy(val): 2033101Sstever@eecs.umich.edu val = val.unproxy(obj) 2043101Sstever@eecs.umich.edu for m in self._modifiers: 2053101Sstever@eecs.umich.edu if isinstance(m, str): 2063101Sstever@eecs.umich.edu val = getattr(val, m) 2073101Sstever@eecs.umich.edu elif isinstance(m, int): 2083101Sstever@eecs.umich.edu val = val[m] 2093101Sstever@eecs.umich.edu else: 2103101Sstever@eecs.umich.edu assert("Item must be string or integer") 2113101Sstever@eecs.umich.edu while isproxy(val): 2123101Sstever@eecs.umich.edu val = val.unproxy(obj) 2133101Sstever@eecs.umich.edu return val, True 2143101Sstever@eecs.umich.edu 2153101Sstever@eecs.umich.edu def path(self): 2163101Sstever@eecs.umich.edu p = self._attr 2173101Sstever@eecs.umich.edu for m in self._modifiers: 2183101Sstever@eecs.umich.edu if isinstance(m, str): 2193101Sstever@eecs.umich.edu p += '.%s' % m 2203101Sstever@eecs.umich.edu elif isinstance(m, int): 2213101Sstever@eecs.umich.edu p += '[%d]' % m 2223101Sstever@eecs.umich.edu else: 2233101Sstever@eecs.umich.edu assert("Item must be string or integer") 2243101Sstever@eecs.umich.edu return p 2253101Sstever@eecs.umich.edu 2263101Sstever@eecs.umich.educlass AnyProxy(BaseProxy): 2273101Sstever@eecs.umich.edu def find(self, obj): 2283101Sstever@eecs.umich.edu return obj.find_any(self._pdesc.ptype) 2293101Sstever@eecs.umich.edu 2303101Sstever@eecs.umich.edu def path(self): 2313101Sstever@eecs.umich.edu return 'any' 2323101Sstever@eecs.umich.edu 2338927Sandreas.hansson@arm.com# The AllProxy traverses the entire sub-tree (not only the children) 2348927Sandreas.hansson@arm.com# and adds all objects of a specific type 2358459SAli.Saidi@ARM.comclass AllProxy(BaseProxy): 2368459SAli.Saidi@ARM.com def find(self, obj): 2378459SAli.Saidi@ARM.com return obj.find_all(self._pdesc.ptype) 2388459SAli.Saidi@ARM.com 2398459SAli.Saidi@ARM.com def path(self): 2408459SAli.Saidi@ARM.com return 'all' 2418459SAli.Saidi@ARM.com 2423101Sstever@eecs.umich.edudef isproxy(obj): 24313716Sandreas.sandberg@arm.com from . import params 2443101Sstever@eecs.umich.edu if isinstance(obj, (BaseProxy, params.EthernetAddr)): 2453101Sstever@eecs.umich.edu return True 2463101Sstever@eecs.umich.edu elif isinstance(obj, (list, tuple)): 2473101Sstever@eecs.umich.edu for v in obj: 2483101Sstever@eecs.umich.edu if isproxy(v): 2493101Sstever@eecs.umich.edu return True 2503101Sstever@eecs.umich.edu return False 2513101Sstever@eecs.umich.edu 2523101Sstever@eecs.umich.educlass ProxyFactory(object): 2533101Sstever@eecs.umich.edu def __init__(self, search_self, search_up): 2543101Sstever@eecs.umich.edu self.search_self = search_self 2553101Sstever@eecs.umich.edu self.search_up = search_up 2563101Sstever@eecs.umich.edu 2573101Sstever@eecs.umich.edu def __getattr__(self, attr): 2583101Sstever@eecs.umich.edu if attr == 'any': 2593101Sstever@eecs.umich.edu return AnyProxy(self.search_self, self.search_up) 2608459SAli.Saidi@ARM.com elif attr == 'all': 2618459SAli.Saidi@ARM.com if self.search_up: 2628459SAli.Saidi@ARM.com assert("Parant.all is not supported") 2638459SAli.Saidi@ARM.com return AllProxy(self.search_self, self.search_up) 2643101Sstever@eecs.umich.edu else: 2653101Sstever@eecs.umich.edu return AttrProxy(self.search_self, self.search_up, attr) 2663101Sstever@eecs.umich.edu 2673101Sstever@eecs.umich.edu# global objects for handling proxies 2683101Sstever@eecs.umich.eduParent = ProxyFactory(search_self = False, search_up = True) 2693101Sstever@eecs.umich.eduSelf = ProxyFactory(search_self = True, search_up = False) 2703101Sstever@eecs.umich.edu 2713101Sstever@eecs.umich.edu# limit exports on 'from proxy import *' 2723101Sstever@eecs.umich.edu__all__ = ['Parent', 'Self'] 273