proxy.py revision 13714
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
5013714Sandreas.sandberg@arm.com
513179Sstever@eecs.umich.eduimport copy
523179Sstever@eecs.umich.edu
5313714Sandreas.sandberg@arm.comfrom . import params
5412798Snikos.nikoleris@arm.com
553101Sstever@eecs.umich.educlass BaseProxy(object):
563101Sstever@eecs.umich.edu    def __init__(self, search_self, search_up):
573101Sstever@eecs.umich.edu        self._search_self = search_self
583101Sstever@eecs.umich.edu        self._search_up = search_up
5912798Snikos.nikoleris@arm.com        self._multipliers = []
603101Sstever@eecs.umich.edu
613109Sstever@eecs.umich.edu    def __str__(self):
623109Sstever@eecs.umich.edu        if self._search_self and not self._search_up:
633109Sstever@eecs.umich.edu            s = 'Self'
643109Sstever@eecs.umich.edu        elif not self._search_self and self._search_up:
653109Sstever@eecs.umich.edu            s = 'Parent'
663109Sstever@eecs.umich.edu        else:
673109Sstever@eecs.umich.edu            s = 'ConfusedProxy'
683109Sstever@eecs.umich.edu        return s + '.' + self.path()
693109Sstever@eecs.umich.edu
703101Sstever@eecs.umich.edu    def __setattr__(self, attr, value):
713101Sstever@eecs.umich.edu        if not attr.startswith('_'):
7213663Sandreas.sandberg@arm.com            raise AttributeError(
7313663Sandreas.sandberg@arm.com                "cannot set attribute '%s' on proxy object" % attr)
743101Sstever@eecs.umich.edu        super(BaseProxy, self).__setattr__(attr, value)
753101Sstever@eecs.umich.edu
7612798Snikos.nikoleris@arm.com    # support for multiplying proxies by constants or other proxies to
7712798Snikos.nikoleris@arm.com    # other params
783101Sstever@eecs.umich.edu    def __mul__(self, other):
7912798Snikos.nikoleris@arm.com        if not (isinstance(other, (int, long, float)) or isproxy(other)):
8013663Sandreas.sandberg@arm.com            raise TypeError(
8113663Sandreas.sandberg@arm.com                "Proxy multiplier must be a constant or a proxy to a param")
8212798Snikos.nikoleris@arm.com        self._multipliers.append(other)
833101Sstever@eecs.umich.edu        return self
843101Sstever@eecs.umich.edu
853101Sstever@eecs.umich.edu    __rmul__ = __mul__
863101Sstever@eecs.umich.edu
8712798Snikos.nikoleris@arm.com    def _mulcheck(self, result, base):
8812798Snikos.nikoleris@arm.com        for multiplier in self._multipliers:
8912798Snikos.nikoleris@arm.com            if isproxy(multiplier):
9012798Snikos.nikoleris@arm.com                multiplier = multiplier.unproxy(base)
9112798Snikos.nikoleris@arm.com                # assert that we are multiplying with a compatible
9212798Snikos.nikoleris@arm.com                # param
9312798Snikos.nikoleris@arm.com                if not isinstance(multiplier, params.NumericParamValue):
9413663Sandreas.sandberg@arm.com                    raise TypeError(
9513663Sandreas.sandberg@arm.com                        "Proxy multiplier must be a numerical param")
9612798Snikos.nikoleris@arm.com                multiplier = multiplier.getValue()
9712798Snikos.nikoleris@arm.com            result *= multiplier
9812798Snikos.nikoleris@arm.com        return result
993101Sstever@eecs.umich.edu
1003101Sstever@eecs.umich.edu    def unproxy(self, base):
1013101Sstever@eecs.umich.edu        obj = base
1023101Sstever@eecs.umich.edu        done = False
1033101Sstever@eecs.umich.edu
1043101Sstever@eecs.umich.edu        if self._search_self:
1053101Sstever@eecs.umich.edu            result, done = self.find(obj)
1063101Sstever@eecs.umich.edu
1073101Sstever@eecs.umich.edu        if self._search_up:
10810195SGeoffrey.Blake@arm.com            # Search up the tree but mark ourself
10910195SGeoffrey.Blake@arm.com            # as visited to avoid a self-reference
11010195SGeoffrey.Blake@arm.com            self._visited = True
11110195SGeoffrey.Blake@arm.com            obj._visited = True
1123101Sstever@eecs.umich.edu            while not done:
1133101Sstever@eecs.umich.edu                obj = obj._parent
1143101Sstever@eecs.umich.edu                if not obj:
1153101Sstever@eecs.umich.edu                    break
1163101Sstever@eecs.umich.edu                result, done = self.find(obj)
1173101Sstever@eecs.umich.edu
11810195SGeoffrey.Blake@arm.com            self._visited = False
11910195SGeoffrey.Blake@arm.com            base._visited = False
12010195SGeoffrey.Blake@arm.com
1213101Sstever@eecs.umich.edu        if not done:
12213663Sandreas.sandberg@arm.com            raise AttributeError(
12313663Sandreas.sandberg@arm.com                "Can't resolve proxy '%s' of type '%s' from '%s'" % \
12413663Sandreas.sandberg@arm.com                  (self.path(), self._pdesc.ptype_str, base.path()))
1253101Sstever@eecs.umich.edu
1263101Sstever@eecs.umich.edu        if isinstance(result, BaseProxy):
1273101Sstever@eecs.umich.edu            if result == self:
12813663Sandreas.sandberg@arm.com                raise RuntimeError("Cycle in unproxy")
1293101Sstever@eecs.umich.edu            result = result.unproxy(obj)
1303101Sstever@eecs.umich.edu
13112798Snikos.nikoleris@arm.com        return self._mulcheck(result, base)
1323101Sstever@eecs.umich.edu
1333101Sstever@eecs.umich.edu    def getindex(obj, index):
1343101Sstever@eecs.umich.edu        if index == None:
1353101Sstever@eecs.umich.edu            return obj
1363101Sstever@eecs.umich.edu        try:
1373101Sstever@eecs.umich.edu            obj = obj[index]
1383101Sstever@eecs.umich.edu        except TypeError:
1393101Sstever@eecs.umich.edu            if index != 0:
1403101Sstever@eecs.umich.edu                raise
1413101Sstever@eecs.umich.edu            # if index is 0 and item is not subscriptable, just
1423101Sstever@eecs.umich.edu            # use item itself (so cpu[0] works on uniprocessors)
1433101Sstever@eecs.umich.edu        return obj
1443101Sstever@eecs.umich.edu    getindex = staticmethod(getindex)
1453101Sstever@eecs.umich.edu
1463109Sstever@eecs.umich.edu    # This method should be called once the proxy is assigned to a
1473109Sstever@eecs.umich.edu    # particular parameter or port to set the expected type of the
1483109Sstever@eecs.umich.edu    # resolved proxy
1493101Sstever@eecs.umich.edu    def set_param_desc(self, pdesc):
1503101Sstever@eecs.umich.edu        self._pdesc = pdesc
1513101Sstever@eecs.umich.edu
1523101Sstever@eecs.umich.educlass AttrProxy(BaseProxy):
1533101Sstever@eecs.umich.edu    def __init__(self, search_self, search_up, attr):
1543101Sstever@eecs.umich.edu        super(AttrProxy, self).__init__(search_self, search_up)
1553101Sstever@eecs.umich.edu        self._attr = attr
1563101Sstever@eecs.umich.edu        self._modifiers = []
1573101Sstever@eecs.umich.edu
1583101Sstever@eecs.umich.edu    def __getattr__(self, attr):
1593101Sstever@eecs.umich.edu        # python uses __bases__ internally for inheritance
1603101Sstever@eecs.umich.edu        if attr.startswith('_'):
1613101Sstever@eecs.umich.edu            return super(AttrProxy, self).__getattr__(self, attr)
1623101Sstever@eecs.umich.edu        if hasattr(self, '_pdesc'):
16313663Sandreas.sandberg@arm.com            raise AttributeError("Attribute reference on bound proxy")
1643179Sstever@eecs.umich.edu        # Return a copy of self rather than modifying self in place
1653179Sstever@eecs.umich.edu        # since self could be an indirect reference via a variable or
1663179Sstever@eecs.umich.edu        # parameter
1673179Sstever@eecs.umich.edu        new_self = copy.deepcopy(self)
1683179Sstever@eecs.umich.edu        new_self._modifiers.append(attr)
1693179Sstever@eecs.umich.edu        return new_self
1703101Sstever@eecs.umich.edu
1713101Sstever@eecs.umich.edu    # support indexing on proxies (e.g., Self.cpu[0])
1723101Sstever@eecs.umich.edu    def __getitem__(self, key):
1733101Sstever@eecs.umich.edu        if not isinstance(key, int):
17413663Sandreas.sandberg@arm.com            raise TypeError("Proxy object requires integer index")
1753179Sstever@eecs.umich.edu        if hasattr(self, '_pdesc'):
17613663Sandreas.sandberg@arm.com            raise AttributeError("Index operation on bound proxy")
1773179Sstever@eecs.umich.edu        new_self = copy.deepcopy(self)
1783179Sstever@eecs.umich.edu        new_self._modifiers.append(key)
1793179Sstever@eecs.umich.edu        return new_self
1803101Sstever@eecs.umich.edu
1813101Sstever@eecs.umich.edu    def find(self, obj):
1823101Sstever@eecs.umich.edu        try:
1833101Sstever@eecs.umich.edu            val = getattr(obj, self._attr)
18410195SGeoffrey.Blake@arm.com            visited = False
18510195SGeoffrey.Blake@arm.com            if hasattr(val, '_visited'):
18610195SGeoffrey.Blake@arm.com                visited = getattr(val, '_visited')
18710195SGeoffrey.Blake@arm.com
18810195SGeoffrey.Blake@arm.com            if not visited:
18910195SGeoffrey.Blake@arm.com                # for any additional unproxying to be done, pass the
19010195SGeoffrey.Blake@arm.com                # current, rather than the original object so that proxy
19110195SGeoffrey.Blake@arm.com                # has the right context
19210195SGeoffrey.Blake@arm.com                obj = val
19310195SGeoffrey.Blake@arm.com            else:
19410195SGeoffrey.Blake@arm.com                return None, False
1953101Sstever@eecs.umich.edu        except:
1963101Sstever@eecs.umich.edu            return None, False
1973101Sstever@eecs.umich.edu        while isproxy(val):
1983101Sstever@eecs.umich.edu            val = val.unproxy(obj)
1993101Sstever@eecs.umich.edu        for m in self._modifiers:
2003101Sstever@eecs.umich.edu            if isinstance(m, str):
2013101Sstever@eecs.umich.edu                val = getattr(val, m)
2023101Sstever@eecs.umich.edu            elif isinstance(m, int):
2033101Sstever@eecs.umich.edu                val = val[m]
2043101Sstever@eecs.umich.edu            else:
2053101Sstever@eecs.umich.edu                assert("Item must be string or integer")
2063101Sstever@eecs.umich.edu            while isproxy(val):
2073101Sstever@eecs.umich.edu                val = val.unproxy(obj)
2083101Sstever@eecs.umich.edu        return val, True
2093101Sstever@eecs.umich.edu
2103101Sstever@eecs.umich.edu    def path(self):
2113101Sstever@eecs.umich.edu        p = self._attr
2123101Sstever@eecs.umich.edu        for m in self._modifiers:
2133101Sstever@eecs.umich.edu            if isinstance(m, str):
2143101Sstever@eecs.umich.edu                p += '.%s' % m
2153101Sstever@eecs.umich.edu            elif isinstance(m, int):
2163101Sstever@eecs.umich.edu                p += '[%d]' % m
2173101Sstever@eecs.umich.edu            else:
2183101Sstever@eecs.umich.edu                assert("Item must be string or integer")
2193101Sstever@eecs.umich.edu        return p
2203101Sstever@eecs.umich.edu
2213101Sstever@eecs.umich.educlass AnyProxy(BaseProxy):
2223101Sstever@eecs.umich.edu    def find(self, obj):
2233101Sstever@eecs.umich.edu        return obj.find_any(self._pdesc.ptype)
2243101Sstever@eecs.umich.edu
2253101Sstever@eecs.umich.edu    def path(self):
2263101Sstever@eecs.umich.edu        return 'any'
2273101Sstever@eecs.umich.edu
2288927Sandreas.hansson@arm.com# The AllProxy traverses the entire sub-tree (not only the children)
2298927Sandreas.hansson@arm.com# and adds all objects of a specific type
2308459SAli.Saidi@ARM.comclass AllProxy(BaseProxy):
2318459SAli.Saidi@ARM.com    def find(self, obj):
2328459SAli.Saidi@ARM.com        return obj.find_all(self._pdesc.ptype)
2338459SAli.Saidi@ARM.com
2348459SAli.Saidi@ARM.com    def path(self):
2358459SAli.Saidi@ARM.com        return 'all'
2368459SAli.Saidi@ARM.com
2373101Sstever@eecs.umich.edudef isproxy(obj):
2383101Sstever@eecs.umich.edu    if isinstance(obj, (BaseProxy, params.EthernetAddr)):
2393101Sstever@eecs.umich.edu        return True
2403101Sstever@eecs.umich.edu    elif isinstance(obj, (list, tuple)):
2413101Sstever@eecs.umich.edu        for v in obj:
2423101Sstever@eecs.umich.edu            if isproxy(v):
2433101Sstever@eecs.umich.edu                return True
2443101Sstever@eecs.umich.edu    return False
2453101Sstever@eecs.umich.edu
2463101Sstever@eecs.umich.educlass ProxyFactory(object):
2473101Sstever@eecs.umich.edu    def __init__(self, search_self, search_up):
2483101Sstever@eecs.umich.edu        self.search_self = search_self
2493101Sstever@eecs.umich.edu        self.search_up = search_up
2503101Sstever@eecs.umich.edu
2513101Sstever@eecs.umich.edu    def __getattr__(self, attr):
2523101Sstever@eecs.umich.edu        if attr == 'any':
2533101Sstever@eecs.umich.edu            return AnyProxy(self.search_self, self.search_up)
2548459SAli.Saidi@ARM.com        elif attr == 'all':
2558459SAli.Saidi@ARM.com            if self.search_up:
2568459SAli.Saidi@ARM.com                assert("Parant.all is not supported")
2578459SAli.Saidi@ARM.com            return AllProxy(self.search_self, self.search_up)
2583101Sstever@eecs.umich.edu        else:
2593101Sstever@eecs.umich.edu            return AttrProxy(self.search_self, self.search_up, attr)
2603101Sstever@eecs.umich.edu
2613101Sstever@eecs.umich.edu# global objects for handling proxies
2623101Sstever@eecs.umich.eduParent = ProxyFactory(search_self = False, search_up = True)
2633101Sstever@eecs.umich.eduSelf = ProxyFactory(search_self = True, search_up = False)
2643101Sstever@eecs.umich.edu
2653101Sstever@eecs.umich.edu# limit exports on 'from proxy import *'
2663101Sstever@eecs.umich.edu__all__ = ['Parent', 'Self']
2673101Sstever@eecs.umich.edu
2683101Sstever@eecs.umich.edu# see comment on imports at end of __init__.py.
2693101Sstever@eecs.umich.eduimport params # for EthernetAddr
270