proxy.py revision 13742
110816SN/A# Copyright (c) 2018 ARM Limited 29288SN/A# All rights reserved. 39288SN/A# 49288SN/A# The license below extends only to copyright in the software and shall 59288SN/A# not be construed as granting a license to any other intellectual 69288SN/A# property including but not limited to intellectual property relating 79288SN/A# to a hardware implementation of the functionality of the software 89288SN/A# licensed hereunder. You may use the software subject to the license 99288SN/A# terms below provided that you ensure that this notice is replicated 109288SN/A# unmodified and in its entirety in all distributions of the software, 119288SN/A# modified or unmodified, in source code or in binary form. 129288SN/A# 134486SN/A# Copyright (c) 2004-2006 The Regents of The University of Michigan 144486SN/A# All rights reserved. 154486SN/A# 164486SN/A# Redistribution and use in source and binary forms, with or without 174486SN/A# modification, are permitted provided that the following conditions are 184486SN/A# met: redistributions of source code must retain the above copyright 194486SN/A# notice, this list of conditions and the following disclaimer; 204486SN/A# redistributions in binary form must reproduce the above copyright 214486SN/A# notice, this list of conditions and the following disclaimer in the 224486SN/A# documentation and/or other materials provided with the distribution; 234486SN/A# neither the name of the copyright holders nor the names of its 244486SN/A# contributors may be used to endorse or promote products derived from 254486SN/A# this software without specific prior written permission. 264486SN/A# 274486SN/A# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 284486SN/A# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 294486SN/A# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 304486SN/A# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 314486SN/A# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 324486SN/A# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 334486SN/A# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 344486SN/A# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 354486SN/A# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 364486SN/A# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 374486SN/A# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 384486SN/A# 394486SN/A# Authors: Steve Reinhardt 4011053Sandreas.hansson@arm.com# Nathan Binkert 414486SN/A 423102SN/A##################################################################### 438833SN/A# 442826SN/A# Proxy object support. 458831SN/A# 469796SN/A##################################################################### 471615SN/A 482826SN/Afrom __future__ import print_function 491366SN/Afrom __future__ import absolute_import 5011053Sandreas.hansson@arm.comimport six 519338SN/Aif six.PY3: 5210816SN/A long = int 5310816SN/A 5410816SN/Aimport copy 5510816SN/A 5611722Ssophiane.senni@gmail.com 5711722Ssophiane.senni@gmail.comclass BaseProxy(object): 5810816SN/A def __init__(self, search_self, search_up): 5910816SN/A self._search_self = search_self 6012513Sodanrc@yahoo.com.br self._search_up = search_up 6112513Sodanrc@yahoo.com.br self._multipliers = [] 6212513Sodanrc@yahoo.com.br 631310SN/A def __str__(self): 6410816SN/A if self._search_self and not self._search_up: 6510816SN/A s = 'Self' 6610816SN/A elif not self._search_self and self._search_up: 6710816SN/A s = 'Parent' 6810816SN/A else: 6910816SN/A s = 'ConfusedProxy' 7010816SN/A return s + '.' + self.path() 7110884SN/A 7210816SN/A def __setattr__(self, attr, value): 7310816SN/A if not attr.startswith('_'): 745875SN/A raise AttributeError( 7510816SN/A "cannot set attribute '%s' on proxy object" % attr) 7610816SN/A super(BaseProxy, self).__setattr__(attr, value) 7710816SN/A 7810025SN/A # support for multiplying proxies by constants or other proxies to 7910025SN/A # other params 8010816SN/A def __mul__(self, other): 8110816SN/A if not (isinstance(other, (int, long, float)) or isproxy(other)): 8210816SN/A raise TypeError( 8310816SN/A "Proxy multiplier must be a constant or a proxy to a param") 8410816SN/A self._multipliers.append(other) 8510816SN/A return self 8610816SN/A 8710816SN/A __rmul__ = __mul__ 8811053Sandreas.hansson@arm.com 8911197Sandreas.hansson@arm.com def _mulcheck(self, result, base): 9011197Sandreas.hansson@arm.com for multiplier in self._multipliers: 9111197Sandreas.hansson@arm.com if isproxy(multiplier): 9211197Sandreas.hansson@arm.com multiplier = multiplier.unproxy(base) 9311053Sandreas.hansson@arm.com # assert that we are multiplying with a compatible 9411053Sandreas.hansson@arm.com # param 9511053Sandreas.hansson@arm.com if not isinstance(multiplier, params.NumericParamValue): 9611197Sandreas.hansson@arm.com raise TypeError( 9711197Sandreas.hansson@arm.com "Proxy multiplier must be a numerical param") 9811197Sandreas.hansson@arm.com multiplier = multiplier.getValue() 9911197Sandreas.hansson@arm.com result *= multiplier 10011197Sandreas.hansson@arm.com return result 10111197Sandreas.hansson@arm.com 10211197Sandreas.hansson@arm.com def unproxy(self, base): 10311197Sandreas.hansson@arm.com obj = base 10411197Sandreas.hansson@arm.com done = False 10511197Sandreas.hansson@arm.com 10611197Sandreas.hansson@arm.com if self._search_self: 10711197Sandreas.hansson@arm.com result, done = self.find(obj) 10811199Sandreas.hansson@arm.com 10911199Sandreas.hansson@arm.com if self._search_up: 11011199Sandreas.hansson@arm.com # Search up the tree but mark ourself 11111199Sandreas.hansson@arm.com # as visited to avoid a self-reference 11211199Sandreas.hansson@arm.com self._visited = True 11311199Sandreas.hansson@arm.com obj._visited = True 11411199Sandreas.hansson@arm.com while not done: 11511199Sandreas.hansson@arm.com 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 visited: 191 return None, False 192 193 if not isproxy(val): 194 # for any additional unproxying to be done, pass the 195 # current, rather than the original object so that proxy 196 # has the right context 197 obj = val 198 199 except: 200 return None, False 201 while isproxy(val): 202 val = val.unproxy(obj) 203 for m in self._modifiers: 204 if isinstance(m, str): 205 val = getattr(val, m) 206 elif isinstance(m, int): 207 val = val[m] 208 else: 209 assert("Item must be string or integer") 210 while isproxy(val): 211 val = val.unproxy(obj) 212 return val, True 213 214 def path(self): 215 p = self._attr 216 for m in self._modifiers: 217 if isinstance(m, str): 218 p += '.%s' % m 219 elif isinstance(m, int): 220 p += '[%d]' % m 221 else: 222 assert("Item must be string or integer") 223 return p 224 225class AnyProxy(BaseProxy): 226 def find(self, obj): 227 return obj.find_any(self._pdesc.ptype) 228 229 def path(self): 230 return 'any' 231 232# The AllProxy traverses the entire sub-tree (not only the children) 233# and adds all objects of a specific type 234class AllProxy(BaseProxy): 235 def find(self, obj): 236 return obj.find_all(self._pdesc.ptype) 237 238 def path(self): 239 return 'all' 240 241def isproxy(obj): 242 from . import params 243 if isinstance(obj, (BaseProxy, params.EthernetAddr)): 244 return True 245 elif isinstance(obj, (list, tuple)): 246 for v in obj: 247 if isproxy(v): 248 return True 249 return False 250 251class ProxyFactory(object): 252 def __init__(self, search_self, search_up): 253 self.search_self = search_self 254 self.search_up = search_up 255 256 def __getattr__(self, attr): 257 if attr == 'any': 258 return AnyProxy(self.search_self, self.search_up) 259 elif attr == 'all': 260 if self.search_up: 261 assert("Parant.all is not supported") 262 return AllProxy(self.search_self, self.search_up) 263 else: 264 return AttrProxy(self.search_self, self.search_up, attr) 265 266# global objects for handling proxies 267Parent = ProxyFactory(search_self = False, search_up = True) 268Self = ProxyFactory(search_self = True, search_up = False) 269 270# limit exports on 'from proxy import *' 271__all__ = ['Parent', 'Self'] 272