proxy.py revision 13719
12137SN/A# Copyright (c) 2018 ARM Limited
25268Sksewell@umich.edu# All rights reserved.
35254Sksewell@umich.edu#
45254Sksewell@umich.edu# The license below extends only to copyright in the software and shall
52137SN/A# not be construed as granting a license to any other intellectual
65254Sksewell@umich.edu# property including but not limited to intellectual property relating
75254Sksewell@umich.edu# to a hardware implementation of the functionality of the software
85254Sksewell@umich.edu# licensed hereunder.  You may use the software subject to the license
95254Sksewell@umich.edu# terms below provided that you ensure that this notice is replicated
105254Sksewell@umich.edu# unmodified and in its entirety in all distributions of the software,
115254Sksewell@umich.edu# modified or unmodified, in source code or in binary form.
125254Sksewell@umich.edu#
135254Sksewell@umich.edu# Copyright (c) 2004-2006 The Regents of The University of Michigan
145254Sksewell@umich.edu# All rights reserved.
155254Sksewell@umich.edu#
162137SN/A# Redistribution and use in source and binary forms, with or without
175254Sksewell@umich.edu# modification, are permitted provided that the following conditions are
185254Sksewell@umich.edu# met: redistributions of source code must retain the above copyright
195254Sksewell@umich.edu# notice, this list of conditions and the following disclaimer;
205254Sksewell@umich.edu# redistributions in binary form must reproduce the above copyright
215254Sksewell@umich.edu# notice, this list of conditions and the following disclaimer in the
225254Sksewell@umich.edu# documentation and/or other materials provided with the distribution;
235254Sksewell@umich.edu# neither the name of the copyright holders nor the names of its
245254Sksewell@umich.edu# contributors may be used to endorse or promote products derived from
255254Sksewell@umich.edu# this software without specific prior written permission.
265254Sksewell@umich.edu#
275254Sksewell@umich.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
282665Ssaidi@eecs.umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
295268Sksewell@umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
305268Sksewell@umich.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
312137SN/A# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
322137SN/A# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3311793Sbrandon.potter@amd.com# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3411793Sbrandon.potter@amd.com# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3511793Sbrandon.potter@amd.com# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
362597SN/A# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3713985Sgabeblack@google.com# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
382137SN/A#
392680Sktlim@umich.edu# Authors: Steve Reinhardt
408232Snate@binkert.org#          Nathan Binkert
412137SN/A
428229Snate@binkert.org#####################################################################
432137SN/A#
4411794Sbrandon.potter@amd.com# Proxy object support.
458229Snate@binkert.org#
464661Sksewell@umich.edu#####################################################################
472137SN/A
482137SN/Afrom __future__ import print_function
492137SN/Afrom __future__ import absolute_import
502137SN/Aimport six
5113985Sgabeblack@google.comif six.PY3:
5213985Sgabeblack@google.com    long = int
5313985Sgabeblack@google.com
5413985Sgabeblack@google.comimport copy
5513985Sgabeblack@google.com
5613985Sgabeblack@google.com
5713985Sgabeblack@google.comclass BaseProxy(object):
5813985Sgabeblack@google.com    def __init__(self, search_self, search_up):
5913985Sgabeblack@google.com        self._search_self = search_self
6013985Sgabeblack@google.com        self._search_up = search_up
6113985Sgabeblack@google.com        self._multipliers = []
6213985Sgabeblack@google.com
6313985Sgabeblack@google.com    def __str__(self):
6413985Sgabeblack@google.com        if self._search_self and not self._search_up:
6513985Sgabeblack@google.com            s = 'Self'
6613985Sgabeblack@google.com        elif not self._search_self and self._search_up:
6713985Sgabeblack@google.com            s = 'Parent'
6813985Sgabeblack@google.com        else:
6913985Sgabeblack@google.com            s = 'ConfusedProxy'
7013985Sgabeblack@google.com        return s + '.' + self.path()
7113985Sgabeblack@google.com
7213985Sgabeblack@google.com    def __setattr__(self, attr, value):
7313985Sgabeblack@google.com        if not attr.startswith('_'):
7413985Sgabeblack@google.com            raise AttributeError(
7513985Sgabeblack@google.com                "cannot set attribute '%s' on proxy object" % attr)
7613985Sgabeblack@google.com        super(BaseProxy, self).__setattr__(attr, value)
7713985Sgabeblack@google.com
7813985Sgabeblack@google.com    # support for multiplying proxies by constants or other proxies to
7913985Sgabeblack@google.com    # other params
8013985Sgabeblack@google.com    def __mul__(self, other):
812137SN/A        if not (isinstance(other, (int, long, float)) or isproxy(other)):
822137SN/A            raise TypeError(
8313995Sbrandon.potter@amd.com                "Proxy multiplier must be a constant or a proxy to a param")
842137SN/A        self._multipliers.append(other)
856701Sgblack@eecs.umich.edu        return self
8613995Sbrandon.potter@amd.com
876701Sgblack@eecs.umich.edu    __rmul__ = __mul__
882137SN/A
892137SN/A    def _mulcheck(self, result, base):
909149SAli.Saidi@ARM.com        for multiplier in self._multipliers:
9114014Sciro.santilli@arm.com            if isproxy(multiplier):
922137SN/A                multiplier = multiplier.unproxy(base)
932137SN/A                # assert that we are multiplying with a compatible
942137SN/A                # param
9514024Sgabeblack@google.com                if not isinstance(multiplier, params.NumericParamValue):
962137SN/A                    raise TypeError(
972137SN/A                        "Proxy multiplier must be a numerical param")
982137SN/A                multiplier = multiplier.getValue()
992484SN/A            result *= multiplier
1002137SN/A        return result
1012137SN/A
1022137SN/A    def unproxy(self, base):
10313995Sbrandon.potter@amd.com        obj = base
1042137SN/A        done = False
1056701Sgblack@eecs.umich.edu
10613995Sbrandon.potter@amd.com        if self._search_self:
1076701Sgblack@eecs.umich.edu            result, done = self.find(obj)
1086701Sgblack@eecs.umich.edu
1096701Sgblack@eecs.umich.edu        if self._search_up:
1102137SN/A            # Search up the tree but mark ourself
1112137SN/A            # as visited to avoid a self-reference
1126378Sgblack@eecs.umich.edu            self._visited = True
11311320Ssteve.reinhardt@amd.com            obj._visited = True
1146378Sgblack@eecs.umich.edu            while not done:
1156701Sgblack@eecs.umich.edu                obj = obj._parent
1166378Sgblack@eecs.umich.edu                if not obj:
1176378Sgblack@eecs.umich.edu                    break
11814024Sgabeblack@google.com                result, done = self.find(obj)
1196378Sgblack@eecs.umich.edu
1206378Sgblack@eecs.umich.edu            self._visited = False
1212137SN/A            base._visited = False
1222484SN/A
1232137SN/A        if not done:
1242137SN/A            raise AttributeError(
1252137SN/A                "Can't resolve proxy '%s' of type '%s' from '%s'" % \
1262137SN/A                  (self.path(), self._pdesc.ptype_str, base.path()))
1272137SN/A
1282137SN/A        if isinstance(result, BaseProxy):
1292137SN/A            if result == self:
1302484SN/A                raise RuntimeError("Cycle in unproxy")
1312137SN/A            result = result.unproxy(obj)
13213995Sbrandon.potter@amd.com
1332137SN/A        return self._mulcheck(result, base)
1346701Sgblack@eecs.umich.edu
13513995Sbrandon.potter@amd.com    def getindex(obj, index):
1366701Sgblack@eecs.umich.edu        if index == None:
1376701Sgblack@eecs.umich.edu            return obj
1386701Sgblack@eecs.umich.edu        try:
1392137SN/A            obj = obj[index]
1402137SN/A        except TypeError:
1412137SN/A            if index != 0:
1426378Sgblack@eecs.umich.edu                raise
1436378Sgblack@eecs.umich.edu            # if index is 0 and item is not subscriptable, just
1446378Sgblack@eecs.umich.edu            # use item itself (so cpu[0] works on uniprocessors)
1456701Sgblack@eecs.umich.edu        return obj
1466378Sgblack@eecs.umich.edu    getindex = staticmethod(getindex)
14714024Sgabeblack@google.com
1486378Sgblack@eecs.umich.edu    # This method should be called once the proxy is assigned to a
1492137SN/A    # particular parameter or port to set the expected type of the
1506378Sgblack@eecs.umich.edu    # resolved proxy
1516378Sgblack@eecs.umich.edu    def set_param_desc(self, pdesc):
1522137SN/A        self._pdesc = pdesc
1532484SN/A
1542137SN/Aclass AttrProxy(BaseProxy):
1552137SN/A    def __init__(self, search_self, search_up, attr):
1562137SN/A        super(AttrProxy, self).__init__(search_self, search_up)
1572137SN/A        self._attr = attr
1582137SN/A        self._modifiers = []
1592137SN/A
1602137SN/A    def __getattr__(self, attr):
1616808Sgblack@eecs.umich.edu        # python uses __bases__ internally for inheritance
16213995Sbrandon.potter@amd.com        if attr.startswith('_'):
1636808Sgblack@eecs.umich.edu            return super(AttrProxy, self).__getattr__(self, attr)
1646808Sgblack@eecs.umich.edu        if hasattr(self, '_pdesc'):
16513995Sbrandon.potter@amd.com            raise AttributeError("Attribute reference on bound proxy")
1666808Sgblack@eecs.umich.edu        # Return a copy of self rather than modifying self in place
1676808Sgblack@eecs.umich.edu        # since self could be an indirect reference via a variable or
1686808Sgblack@eecs.umich.edu        # parameter
1696808Sgblack@eecs.umich.edu        new_self = copy.deepcopy(self)
1706808Sgblack@eecs.umich.edu        new_self._modifiers.append(attr)
1712137SN/A        return new_self
1722484SN/A
1732137SN/A    # support indexing on proxies (e.g., Self.cpu[0])
1742137SN/A    def __getitem__(self, key):
17513570Sbrandon.potter@amd.com        if not isinstance(key, int):
17613570Sbrandon.potter@amd.com            raise TypeError("Proxy object requires integer index")
1772553SN/A        if hasattr(self, '_pdesc'):
1782137SN/A            raise AttributeError("Index operation on bound proxy")
1792484SN/A        new_self = copy.deepcopy(self)
1802484SN/A        new_self._modifiers.append(key)
1812137SN/A        return new_self
1822137SN/A
1832484SN/A    def find(self, obj):
1842137SN/A        try:
1852484SN/A            val = getattr(obj, self._attr)
1862137SN/A            visited = False
1872553SN/A            if hasattr(val, '_visited'):
1882484SN/A                visited = getattr(val, '_visited')
1895748SSteve.Reinhardt@amd.com
1902484SN/A            if not visited:
1912137SN/A                # for any additional unproxying to be done, pass the
1922484SN/A                # current, rather than the original object so that proxy
1932484SN/A                # has the right context
1942137SN/A                obj = val
1952137SN/A            else:
1962484SN/A                return None, False
1972484SN/A        except:
1982484SN/A            return None, False
1992484SN/A        while isproxy(val):
2002484SN/A            val = val.unproxy(obj)
2012484SN/A        for m in self._modifiers:
2022484SN/A            if isinstance(m, str):
2032484SN/A                val = getattr(val, m)
2042484SN/A            elif isinstance(m, int):
2052137SN/A                val = val[m]
2062484SN/A            else:
2072484SN/A                assert("Item must be string or integer")
2082137SN/A            while isproxy(val):
2094661Sksewell@umich.edu                val = val.unproxy(obj)
2102484SN/A        return val, True
2115513SMichael.Adler@intel.com
2122484SN/A    def path(self):
2132137SN/A        p = self._attr
2144661Sksewell@umich.edu        for m in self._modifiers:
2152484SN/A            if isinstance(m, str):
2162484SN/A                p += '.%s' % m
2175748SSteve.Reinhardt@amd.com            elif isinstance(m, int):
2182491SN/A                p += '[%d]' % m
2192484SN/A            else:
2202484SN/A                assert("Item must be string or integer")
2212491SN/A        return p
2222491SN/A
2232137SN/Aclass AnyProxy(BaseProxy):
2242484SN/A    def find(self, obj):
2252484SN/A        return obj.find_any(self._pdesc.ptype)
2265867Sksewell@umich.edu
2272686Sksewell@umich.edu    def path(self):
2282484SN/A        return 'any'
2292484SN/A
2302484SN/A# The AllProxy traverses the entire sub-tree (not only the children)
2312484SN/A# and adds all objects of a specific type
2325513SMichael.Adler@intel.comclass AllProxy(BaseProxy):
2332137SN/A    def find(self, obj):
2342484SN/A        return obj.find_all(self._pdesc.ptype)
2352484SN/A
2362484SN/A    def path(self):
2372484SN/A        return 'all'
2382484SN/A
2392495SN/Adef isproxy(obj):
2402495SN/A    from . import params
2412484SN/A    if isinstance(obj, (BaseProxy, params.EthernetAddr)):
2422484SN/A        return True
2432495SN/A    elif isinstance(obj, (list, tuple)):
2442484SN/A        for v in obj:
2452495SN/A            if isproxy(v):
2462484SN/A                return True
2476378Sgblack@eecs.umich.edu    return False
2486378Sgblack@eecs.umich.edu
2494661Sksewell@umich.educlass ProxyFactory(object):
2502484SN/A    def __init__(self, search_self, search_up):
2512484SN/A        self.search_self = search_self
2522484SN/A        self.search_up = search_up
2532484SN/A
2542484SN/A    def __getattr__(self, attr):
2552484SN/A        if attr == 'any':
2562484SN/A            return AnyProxy(self.search_self, self.search_up)
2575513SMichael.Adler@intel.com        elif attr == 'all':
2582484SN/A            if self.search_up:
2592484SN/A                assert("Parant.all is not supported")
2602484SN/A            return AllProxy(self.search_self, self.search_up)
2612484SN/A        else:
2622553SN/A            return AttrProxy(self.search_self, self.search_up, attr)
2632495SN/A
2642686Sksewell@umich.edu# global objects for handling proxies
2652686Sksewell@umich.eduParent = ProxyFactory(search_self = False, search_up = True)
2664661Sksewell@umich.eduSelf = ProxyFactory(search_self = True, search_up = False)
2674661Sksewell@umich.edu
2682484SN/A# limit exports on 'from proxy import *'
2692484SN/A__all__ = ['Parent', 'Self']
2702484SN/A