1# Copyright (c) 2018 ARM Limited 2# All rights reserved. 3# 4# The license below extends only to copyright in the software and shall 5# not be construed as granting a license to any other intellectual 6# property including but not limited to intellectual property relating 7# to a hardware implementation of the functionality of the software 8# licensed hereunder. You may use the software subject to the license 9# terms below provided that you ensure that this notice is replicated 10# unmodified and in its entirety in all distributions of the software, 11# modified or unmodified, in source code or in binary form. 12# 13# Copyright (c) 2004-2006 The Regents of The University of Michigan 14# All rights reserved. 15# 16# Redistribution and use in source and binary forms, with or without 17# modification, are permitted provided that the following conditions are 18# met: redistributions of source code must retain the above copyright 19# notice, this list of conditions and the following disclaimer; 20# redistributions in binary form must reproduce the above copyright 21# notice, this list of conditions and the following disclaimer in the 22# documentation and/or other materials provided with the distribution; 23# neither the name of the copyright holders nor the names of its 24# contributors may be used to endorse or promote products derived from 25# this software without specific prior written permission. 26# 27# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 28# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 29# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 30# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 31# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 32# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 33# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 34# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 35# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 36# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 37# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 38# 39# Authors: Steve Reinhardt 40# Nathan Binkert 41 42##################################################################### 43# 44# Proxy object support. 45# 46##################################################################### 47 48from __future__ import print_function 49from __future__ import absolute_import
| 1# Copyright (c) 2018 ARM Limited 2# All rights reserved. 3# 4# The license below extends only to copyright in the software and shall 5# not be construed as granting a license to any other intellectual 6# property including but not limited to intellectual property relating 7# to a hardware implementation of the functionality of the software 8# licensed hereunder. You may use the software subject to the license 9# terms below provided that you ensure that this notice is replicated 10# unmodified and in its entirety in all distributions of the software, 11# modified or unmodified, in source code or in binary form. 12# 13# Copyright (c) 2004-2006 The Regents of The University of Michigan 14# All rights reserved. 15# 16# Redistribution and use in source and binary forms, with or without 17# modification, are permitted provided that the following conditions are 18# met: redistributions of source code must retain the above copyright 19# notice, this list of conditions and the following disclaimer; 20# redistributions in binary form must reproduce the above copyright 21# notice, this list of conditions and the following disclaimer in the 22# documentation and/or other materials provided with the distribution; 23# neither the name of the copyright holders nor the names of its 24# contributors may be used to endorse or promote products derived from 25# this software without specific prior written permission. 26# 27# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 28# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 29# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 30# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 31# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 32# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 33# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 34# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 35# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 36# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 37# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 38# 39# Authors: Steve Reinhardt 40# Nathan Binkert 41 42##################################################################### 43# 44# Proxy object support. 45# 46##################################################################### 47 48from __future__ import print_function 49from __future__ import absolute_import
|
50 51import copy 52 53 54class BaseProxy(object): 55 def __init__(self, search_self, search_up): 56 self._search_self = search_self 57 self._search_up = search_up 58 self._multipliers = [] 59 60 def __str__(self): 61 if self._search_self and not self._search_up: 62 s = 'Self' 63 elif not self._search_self and self._search_up: 64 s = 'Parent' 65 else: 66 s = 'ConfusedProxy' 67 return s + '.' + self.path() 68 69 def __setattr__(self, attr, value): 70 if not attr.startswith('_'): 71 raise AttributeError( 72 "cannot set attribute '%s' on proxy object" % attr) 73 super(BaseProxy, self).__setattr__(attr, value) 74 75 # support for multiplying proxies by constants or other proxies to 76 # other params 77 def __mul__(self, other): 78 if not (isinstance(other, (int, long, float)) or isproxy(other)): 79 raise TypeError( 80 "Proxy multiplier must be a constant or a proxy to a param") 81 self._multipliers.append(other) 82 return self 83 84 __rmul__ = __mul__ 85 86 def _mulcheck(self, result, base): 87 for multiplier in self._multipliers: 88 if isproxy(multiplier): 89 multiplier = multiplier.unproxy(base) 90 # assert that we are multiplying with a compatible 91 # param 92 if not isinstance(multiplier, params.NumericParamValue): 93 raise TypeError( 94 "Proxy multiplier must be a numerical param") 95 multiplier = multiplier.getValue() 96 result *= multiplier 97 return result 98 99 def unproxy(self, base): 100 obj = base 101 done = False 102 103 if self._search_self: 104 result, done = self.find(obj) 105 106 if self._search_up: 107 # Search up the tree but mark ourself 108 # as visited to avoid a self-reference 109 self._visited = True 110 obj._visited = True 111 while not done: 112 obj = obj._parent 113 if not obj: 114 break 115 result, done = self.find(obj) 116 117 self._visited = False 118 base._visited = False 119 120 if not done: 121 raise AttributeError( 122 "Can't resolve proxy '%s' of type '%s' from '%s'" % \ 123 (self.path(), self._pdesc.ptype_str, base.path())) 124 125 if isinstance(result, BaseProxy): 126 if result == self: 127 raise RuntimeError("Cycle in unproxy") 128 result = result.unproxy(obj) 129 130 return self._mulcheck(result, base) 131 132 def getindex(obj, index): 133 if index == None: 134 return obj 135 try: 136 obj = obj[index] 137 except TypeError: 138 if index != 0: 139 raise 140 # if index is 0 and item is not subscriptable, just 141 # use item itself (so cpu[0] works on uniprocessors) 142 return obj 143 getindex = staticmethod(getindex) 144 145 # This method should be called once the proxy is assigned to a 146 # particular parameter or port to set the expected type of the 147 # resolved proxy 148 def set_param_desc(self, pdesc): 149 self._pdesc = pdesc 150 151class AttrProxy(BaseProxy): 152 def __init__(self, search_self, search_up, attr): 153 super(AttrProxy, self).__init__(search_self, search_up) 154 self._attr = attr 155 self._modifiers = [] 156 157 def __getattr__(self, attr): 158 # python uses __bases__ internally for inheritance 159 if attr.startswith('_'): 160 return super(AttrProxy, self).__getattr__(self, attr) 161 if hasattr(self, '_pdesc'): 162 raise AttributeError("Attribute reference on bound proxy") 163 # Return a copy of self rather than modifying self in place 164 # since self could be an indirect reference via a variable or 165 # parameter 166 new_self = copy.deepcopy(self) 167 new_self._modifiers.append(attr) 168 return new_self 169 170 # support indexing on proxies (e.g., Self.cpu[0]) 171 def __getitem__(self, key): 172 if not isinstance(key, int): 173 raise TypeError("Proxy object requires integer index") 174 if hasattr(self, '_pdesc'): 175 raise AttributeError("Index operation on bound proxy") 176 new_self = copy.deepcopy(self) 177 new_self._modifiers.append(key) 178 return new_self 179 180 def find(self, obj): 181 try: 182 val = getattr(obj, self._attr) 183 visited = False 184 if hasattr(val, '_visited'): 185 visited = getattr(val, '_visited') 186 187 if not visited: 188 # for any additional unproxying to be done, pass the 189 # current, rather than the original object so that proxy 190 # has the right context 191 obj = val 192 else: 193 return None, False 194 except: 195 return None, False 196 while isproxy(val): 197 val = val.unproxy(obj) 198 for m in self._modifiers: 199 if isinstance(m, str): 200 val = getattr(val, m) 201 elif isinstance(m, int): 202 val = val[m] 203 else: 204 assert("Item must be string or integer") 205 while isproxy(val): 206 val = val.unproxy(obj) 207 return val, True 208 209 def path(self): 210 p = self._attr 211 for m in self._modifiers: 212 if isinstance(m, str): 213 p += '.%s' % m 214 elif isinstance(m, int): 215 p += '[%d]' % m 216 else: 217 assert("Item must be string or integer") 218 return p 219 220class AnyProxy(BaseProxy): 221 def find(self, obj): 222 return obj.find_any(self._pdesc.ptype) 223 224 def path(self): 225 return 'any' 226 227# The AllProxy traverses the entire sub-tree (not only the children) 228# and adds all objects of a specific type 229class AllProxy(BaseProxy): 230 def find(self, obj): 231 return obj.find_all(self._pdesc.ptype) 232 233 def path(self): 234 return 'all' 235 236def isproxy(obj): 237 from . import params 238 if isinstance(obj, (BaseProxy, params.EthernetAddr)): 239 return True 240 elif isinstance(obj, (list, tuple)): 241 for v in obj: 242 if isproxy(v): 243 return True 244 return False 245 246class ProxyFactory(object): 247 def __init__(self, search_self, search_up): 248 self.search_self = search_self 249 self.search_up = search_up 250 251 def __getattr__(self, attr): 252 if attr == 'any': 253 return AnyProxy(self.search_self, self.search_up) 254 elif attr == 'all': 255 if self.search_up: 256 assert("Parant.all is not supported") 257 return AllProxy(self.search_self, self.search_up) 258 else: 259 return AttrProxy(self.search_self, self.search_up, attr) 260 261# global objects for handling proxies 262Parent = ProxyFactory(search_self = False, search_up = True) 263Self = ProxyFactory(search_self = True, search_up = False) 264 265# limit exports on 'from proxy import *' 266__all__ = ['Parent', 'Self']
| 53 54import copy 55 56 57class BaseProxy(object): 58 def __init__(self, search_self, search_up): 59 self._search_self = search_self 60 self._search_up = search_up 61 self._multipliers = [] 62 63 def __str__(self): 64 if self._search_self and not self._search_up: 65 s = 'Self' 66 elif not self._search_self and self._search_up: 67 s = 'Parent' 68 else: 69 s = 'ConfusedProxy' 70 return s + '.' + self.path() 71 72 def __setattr__(self, attr, value): 73 if not attr.startswith('_'): 74 raise AttributeError( 75 "cannot set attribute '%s' on proxy object" % attr) 76 super(BaseProxy, self).__setattr__(attr, value) 77 78 # support for multiplying proxies by constants or other proxies to 79 # other params 80 def __mul__(self, other): 81 if not (isinstance(other, (int, long, float)) or isproxy(other)): 82 raise TypeError( 83 "Proxy multiplier must be a constant or a proxy to a param") 84 self._multipliers.append(other) 85 return self 86 87 __rmul__ = __mul__ 88 89 def _mulcheck(self, result, base): 90 for multiplier in self._multipliers: 91 if isproxy(multiplier): 92 multiplier = multiplier.unproxy(base) 93 # assert that we are multiplying with a compatible 94 # param 95 if not isinstance(multiplier, params.NumericParamValue): 96 raise TypeError( 97 "Proxy multiplier must be a numerical param") 98 multiplier = multiplier.getValue() 99 result *= multiplier 100 return result 101 102 def unproxy(self, base): 103 obj = base 104 done = False 105 106 if self._search_self: 107 result, done = self.find(obj) 108 109 if self._search_up: 110 # Search up the tree but mark ourself 111 # as visited to avoid a self-reference 112 self._visited = True 113 obj._visited = True 114 while not done: 115 obj = obj._parent 116 if not obj: 117 break 118 result, done = self.find(obj) 119 120 self._visited = False 121 base._visited = False 122 123 if not done: 124 raise AttributeError( 125 "Can't resolve proxy '%s' of type '%s' from '%s'" % \ 126 (self.path(), self._pdesc.ptype_str, base.path())) 127 128 if isinstance(result, BaseProxy): 129 if result == self: 130 raise RuntimeError("Cycle in unproxy") 131 result = result.unproxy(obj) 132 133 return self._mulcheck(result, base) 134 135 def getindex(obj, index): 136 if index == None: 137 return obj 138 try: 139 obj = obj[index] 140 except TypeError: 141 if index != 0: 142 raise 143 # if index is 0 and item is not subscriptable, just 144 # use item itself (so cpu[0] works on uniprocessors) 145 return obj 146 getindex = staticmethod(getindex) 147 148 # This method should be called once the proxy is assigned to a 149 # particular parameter or port to set the expected type of the 150 # resolved proxy 151 def set_param_desc(self, pdesc): 152 self._pdesc = pdesc 153 154class AttrProxy(BaseProxy): 155 def __init__(self, search_self, search_up, attr): 156 super(AttrProxy, self).__init__(search_self, search_up) 157 self._attr = attr 158 self._modifiers = [] 159 160 def __getattr__(self, attr): 161 # python uses __bases__ internally for inheritance 162 if attr.startswith('_'): 163 return super(AttrProxy, self).__getattr__(self, attr) 164 if hasattr(self, '_pdesc'): 165 raise AttributeError("Attribute reference on bound proxy") 166 # Return a copy of self rather than modifying self in place 167 # since self could be an indirect reference via a variable or 168 # parameter 169 new_self = copy.deepcopy(self) 170 new_self._modifiers.append(attr) 171 return new_self 172 173 # support indexing on proxies (e.g., Self.cpu[0]) 174 def __getitem__(self, key): 175 if not isinstance(key, int): 176 raise TypeError("Proxy object requires integer index") 177 if hasattr(self, '_pdesc'): 178 raise AttributeError("Index operation on bound proxy") 179 new_self = copy.deepcopy(self) 180 new_self._modifiers.append(key) 181 return new_self 182 183 def find(self, obj): 184 try: 185 val = getattr(obj, self._attr) 186 visited = False 187 if hasattr(val, '_visited'): 188 visited = getattr(val, '_visited') 189 190 if not visited: 191 # for any additional unproxying to be done, pass the 192 # current, rather than the original object so that proxy 193 # has the right context 194 obj = val 195 else: 196 return None, False 197 except: 198 return None, False 199 while isproxy(val): 200 val = val.unproxy(obj) 201 for m in self._modifiers: 202 if isinstance(m, str): 203 val = getattr(val, m) 204 elif isinstance(m, int): 205 val = val[m] 206 else: 207 assert("Item must be string or integer") 208 while isproxy(val): 209 val = val.unproxy(obj) 210 return val, True 211 212 def path(self): 213 p = self._attr 214 for m in self._modifiers: 215 if isinstance(m, str): 216 p += '.%s' % m 217 elif isinstance(m, int): 218 p += '[%d]' % m 219 else: 220 assert("Item must be string or integer") 221 return p 222 223class AnyProxy(BaseProxy): 224 def find(self, obj): 225 return obj.find_any(self._pdesc.ptype) 226 227 def path(self): 228 return 'any' 229 230# The AllProxy traverses the entire sub-tree (not only the children) 231# and adds all objects of a specific type 232class AllProxy(BaseProxy): 233 def find(self, obj): 234 return obj.find_all(self._pdesc.ptype) 235 236 def path(self): 237 return 'all' 238 239def isproxy(obj): 240 from . import params 241 if isinstance(obj, (BaseProxy, params.EthernetAddr)): 242 return True 243 elif isinstance(obj, (list, tuple)): 244 for v in obj: 245 if isproxy(v): 246 return True 247 return False 248 249class ProxyFactory(object): 250 def __init__(self, search_self, search_up): 251 self.search_self = search_self 252 self.search_up = search_up 253 254 def __getattr__(self, attr): 255 if attr == 'any': 256 return AnyProxy(self.search_self, self.search_up) 257 elif attr == 'all': 258 if self.search_up: 259 assert("Parant.all is not supported") 260 return AllProxy(self.search_self, self.search_up) 261 else: 262 return AttrProxy(self.search_self, self.search_up, attr) 263 264# global objects for handling proxies 265Parent = ProxyFactory(search_self = False, search_up = True) 266Self = ProxyFactory(search_self = True, search_up = False) 267 268# limit exports on 'from proxy import *' 269__all__ = ['Parent', 'Self']
|