proxy.py revision 13716
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
5312798Snikos.nikoleris@arm.com
543101Sstever@eecs.umich.educlass BaseProxy(object):
553101Sstever@eecs.umich.edu    def __init__(self, search_self, search_up):
563101Sstever@eecs.umich.edu        self._search_self = search_self
573101Sstever@eecs.umich.edu        self._search_up = search_up
5812798Snikos.nikoleris@arm.com        self._multipliers = []
593101Sstever@eecs.umich.edu
603109Sstever@eecs.umich.edu    def __str__(self):
613109Sstever@eecs.umich.edu        if self._search_self and not self._search_up:
623109Sstever@eecs.umich.edu            s = 'Self'
633109Sstever@eecs.umich.edu        elif not self._search_self and self._search_up:
643109Sstever@eecs.umich.edu            s = 'Parent'
653109Sstever@eecs.umich.edu        else:
663109Sstever@eecs.umich.edu            s = 'ConfusedProxy'
673109Sstever@eecs.umich.edu        return s + '.' + self.path()
683109Sstever@eecs.umich.edu
693101Sstever@eecs.umich.edu    def __setattr__(self, attr, value):
703101Sstever@eecs.umich.edu        if not attr.startswith('_'):
7113663Sandreas.sandberg@arm.com            raise AttributeError(
7213663Sandreas.sandberg@arm.com                "cannot set attribute '%s' on proxy object" % attr)
733101Sstever@eecs.umich.edu        super(BaseProxy, self).__setattr__(attr, value)
743101Sstever@eecs.umich.edu
7512798Snikos.nikoleris@arm.com    # support for multiplying proxies by constants or other proxies to
7612798Snikos.nikoleris@arm.com    # other params
773101Sstever@eecs.umich.edu    def __mul__(self, other):
7812798Snikos.nikoleris@arm.com        if not (isinstance(other, (int, long, float)) or isproxy(other)):
7913663Sandreas.sandberg@arm.com            raise TypeError(
8013663Sandreas.sandberg@arm.com                "Proxy multiplier must be a constant or a proxy to a param")
8112798Snikos.nikoleris@arm.com        self._multipliers.append(other)
823101Sstever@eecs.umich.edu        return self
833101Sstever@eecs.umich.edu
843101Sstever@eecs.umich.edu    __rmul__ = __mul__
853101Sstever@eecs.umich.edu
8612798Snikos.nikoleris@arm.com    def _mulcheck(self, result, base):
8712798Snikos.nikoleris@arm.com        for multiplier in self._multipliers:
8812798Snikos.nikoleris@arm.com            if isproxy(multiplier):
8912798Snikos.nikoleris@arm.com                multiplier = multiplier.unproxy(base)
9012798Snikos.nikoleris@arm.com                # assert that we are multiplying with a compatible
9112798Snikos.nikoleris@arm.com                # param
9212798Snikos.nikoleris@arm.com                if not isinstance(multiplier, params.NumericParamValue):
9313663Sandreas.sandberg@arm.com                    raise TypeError(
9413663Sandreas.sandberg@arm.com                        "Proxy multiplier must be a numerical param")
9512798Snikos.nikoleris@arm.com                multiplier = multiplier.getValue()
9612798Snikos.nikoleris@arm.com            result *= multiplier
9712798Snikos.nikoleris@arm.com        return result
983101Sstever@eecs.umich.edu
993101Sstever@eecs.umich.edu    def unproxy(self, base):
1003101Sstever@eecs.umich.edu        obj = base
1013101Sstever@eecs.umich.edu        done = False
1023101Sstever@eecs.umich.edu
1033101Sstever@eecs.umich.edu        if self._search_self:
1043101Sstever@eecs.umich.edu            result, done = self.find(obj)
1053101Sstever@eecs.umich.edu
1063101Sstever@eecs.umich.edu        if self._search_up:
10710195SGeoffrey.Blake@arm.com            # Search up the tree but mark ourself
10810195SGeoffrey.Blake@arm.com            # as visited to avoid a self-reference
10910195SGeoffrey.Blake@arm.com            self._visited = True
11010195SGeoffrey.Blake@arm.com            obj._visited = True
1113101Sstever@eecs.umich.edu            while not done:
1123101Sstever@eecs.umich.edu                obj = obj._parent
1133101Sstever@eecs.umich.edu                if not obj:
1143101Sstever@eecs.umich.edu                    break
1153101Sstever@eecs.umich.edu                result, done = self.find(obj)
1163101Sstever@eecs.umich.edu
11710195SGeoffrey.Blake@arm.com            self._visited = False
11810195SGeoffrey.Blake@arm.com            base._visited = False
11910195SGeoffrey.Blake@arm.com
1203101Sstever@eecs.umich.edu        if not done:
12113663Sandreas.sandberg@arm.com            raise AttributeError(
12213663Sandreas.sandberg@arm.com                "Can't resolve proxy '%s' of type '%s' from '%s'" % \
12313663Sandreas.sandberg@arm.com                  (self.path(), self._pdesc.ptype_str, base.path()))
1243101Sstever@eecs.umich.edu
1253101Sstever@eecs.umich.edu        if isinstance(result, BaseProxy):
1263101Sstever@eecs.umich.edu            if result == self:
12713663Sandreas.sandberg@arm.com                raise RuntimeError("Cycle in unproxy")
1283101Sstever@eecs.umich.edu            result = result.unproxy(obj)
1293101Sstever@eecs.umich.edu
13012798Snikos.nikoleris@arm.com        return self._mulcheck(result, base)
1313101Sstever@eecs.umich.edu
1323101Sstever@eecs.umich.edu    def getindex(obj, index):
1333101Sstever@eecs.umich.edu        if index == None:
1343101Sstever@eecs.umich.edu            return obj
1353101Sstever@eecs.umich.edu        try:
1363101Sstever@eecs.umich.edu            obj = obj[index]
1373101Sstever@eecs.umich.edu        except TypeError:
1383101Sstever@eecs.umich.edu            if index != 0:
1393101Sstever@eecs.umich.edu                raise
1403101Sstever@eecs.umich.edu            # if index is 0 and item is not subscriptable, just
1413101Sstever@eecs.umich.edu            # use item itself (so cpu[0] works on uniprocessors)
1423101Sstever@eecs.umich.edu        return obj
1433101Sstever@eecs.umich.edu    getindex = staticmethod(getindex)
1443101Sstever@eecs.umich.edu
1453109Sstever@eecs.umich.edu    # This method should be called once the proxy is assigned to a
1463109Sstever@eecs.umich.edu    # particular parameter or port to set the expected type of the
1473109Sstever@eecs.umich.edu    # resolved proxy
1483101Sstever@eecs.umich.edu    def set_param_desc(self, pdesc):
1493101Sstever@eecs.umich.edu        self._pdesc = pdesc
1503101Sstever@eecs.umich.edu
1513101Sstever@eecs.umich.educlass AttrProxy(BaseProxy):
1523101Sstever@eecs.umich.edu    def __init__(self, search_self, search_up, attr):
1533101Sstever@eecs.umich.edu        super(AttrProxy, self).__init__(search_self, search_up)
1543101Sstever@eecs.umich.edu        self._attr = attr
1553101Sstever@eecs.umich.edu        self._modifiers = []
1563101Sstever@eecs.umich.edu
1573101Sstever@eecs.umich.edu    def __getattr__(self, attr):
1583101Sstever@eecs.umich.edu        # python uses __bases__ internally for inheritance
1593101Sstever@eecs.umich.edu        if attr.startswith('_'):
1603101Sstever@eecs.umich.edu            return super(AttrProxy, self).__getattr__(self, attr)
1613101Sstever@eecs.umich.edu        if hasattr(self, '_pdesc'):
16213663Sandreas.sandberg@arm.com            raise AttributeError("Attribute reference on bound proxy")
1633179Sstever@eecs.umich.edu        # Return a copy of self rather than modifying self in place
1643179Sstever@eecs.umich.edu        # since self could be an indirect reference via a variable or
1653179Sstever@eecs.umich.edu        # parameter
1663179Sstever@eecs.umich.edu        new_self = copy.deepcopy(self)
1673179Sstever@eecs.umich.edu        new_self._modifiers.append(attr)
1683179Sstever@eecs.umich.edu        return new_self
1693101Sstever@eecs.umich.edu
1703101Sstever@eecs.umich.edu    # support indexing on proxies (e.g., Self.cpu[0])
1713101Sstever@eecs.umich.edu    def __getitem__(self, key):
1723101Sstever@eecs.umich.edu        if not isinstance(key, int):
17313663Sandreas.sandberg@arm.com            raise TypeError("Proxy object requires integer index")
1743179Sstever@eecs.umich.edu        if hasattr(self, '_pdesc'):
17513663Sandreas.sandberg@arm.com            raise AttributeError("Index operation on bound proxy")
1763179Sstever@eecs.umich.edu        new_self = copy.deepcopy(self)
1773179Sstever@eecs.umich.edu        new_self._modifiers.append(key)
1783179Sstever@eecs.umich.edu        return new_self
1793101Sstever@eecs.umich.edu
1803101Sstever@eecs.umich.edu    def find(self, obj):
1813101Sstever@eecs.umich.edu        try:
1823101Sstever@eecs.umich.edu            val = getattr(obj, self._attr)
18310195SGeoffrey.Blake@arm.com            visited = False
18410195SGeoffrey.Blake@arm.com            if hasattr(val, '_visited'):
18510195SGeoffrey.Blake@arm.com                visited = getattr(val, '_visited')
18610195SGeoffrey.Blake@arm.com
18710195SGeoffrey.Blake@arm.com            if not visited:
18810195SGeoffrey.Blake@arm.com                # for any additional unproxying to be done, pass the
18910195SGeoffrey.Blake@arm.com                # current, rather than the original object so that proxy
19010195SGeoffrey.Blake@arm.com                # has the right context
19110195SGeoffrey.Blake@arm.com                obj = val
19210195SGeoffrey.Blake@arm.com            else:
19310195SGeoffrey.Blake@arm.com                return None, False
1943101Sstever@eecs.umich.edu        except:
1953101Sstever@eecs.umich.edu            return None, False
1963101Sstever@eecs.umich.edu        while isproxy(val):
1973101Sstever@eecs.umich.edu            val = val.unproxy(obj)
1983101Sstever@eecs.umich.edu        for m in self._modifiers:
1993101Sstever@eecs.umich.edu            if isinstance(m, str):
2003101Sstever@eecs.umich.edu                val = getattr(val, m)
2013101Sstever@eecs.umich.edu            elif isinstance(m, int):
2023101Sstever@eecs.umich.edu                val = val[m]
2033101Sstever@eecs.umich.edu            else:
2043101Sstever@eecs.umich.edu                assert("Item must be string or integer")
2053101Sstever@eecs.umich.edu            while isproxy(val):
2063101Sstever@eecs.umich.edu                val = val.unproxy(obj)
2073101Sstever@eecs.umich.edu        return val, True
2083101Sstever@eecs.umich.edu
2093101Sstever@eecs.umich.edu    def path(self):
2103101Sstever@eecs.umich.edu        p = self._attr
2113101Sstever@eecs.umich.edu        for m in self._modifiers:
2123101Sstever@eecs.umich.edu            if isinstance(m, str):
2133101Sstever@eecs.umich.edu                p += '.%s' % m
2143101Sstever@eecs.umich.edu            elif isinstance(m, int):
2153101Sstever@eecs.umich.edu                p += '[%d]' % m
2163101Sstever@eecs.umich.edu            else:
2173101Sstever@eecs.umich.edu                assert("Item must be string or integer")
2183101Sstever@eecs.umich.edu        return p
2193101Sstever@eecs.umich.edu
2203101Sstever@eecs.umich.educlass AnyProxy(BaseProxy):
2213101Sstever@eecs.umich.edu    def find(self, obj):
2223101Sstever@eecs.umich.edu        return obj.find_any(self._pdesc.ptype)
2233101Sstever@eecs.umich.edu
2243101Sstever@eecs.umich.edu    def path(self):
2253101Sstever@eecs.umich.edu        return 'any'
2263101Sstever@eecs.umich.edu
2278927Sandreas.hansson@arm.com# The AllProxy traverses the entire sub-tree (not only the children)
2288927Sandreas.hansson@arm.com# and adds all objects of a specific type
2298459SAli.Saidi@ARM.comclass AllProxy(BaseProxy):
2308459SAli.Saidi@ARM.com    def find(self, obj):
2318459SAli.Saidi@ARM.com        return obj.find_all(self._pdesc.ptype)
2328459SAli.Saidi@ARM.com
2338459SAli.Saidi@ARM.com    def path(self):
2348459SAli.Saidi@ARM.com        return 'all'
2358459SAli.Saidi@ARM.com
2363101Sstever@eecs.umich.edudef isproxy(obj):
23713716Sandreas.sandberg@arm.com    from . import params
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']
267