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