1# Copyright (c) 2004-2005 The Regents of The University of Michigan 2# All rights reserved. 3# 4# Redistribution and use in source and binary forms, with or without 5# modification, are permitted provided that the following conditions are 6# met: redistributions of source code must retain the above copyright 7# notice, this list of conditions and the following disclaimer; 8# redistributions in binary form must reproduce the above copyright --- 13 unchanged lines hidden (view full) --- 22# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26# 27# Authors: Steve Reinhardt 28# Nathan Binkert 29 |
30import os, re, sys, types, inspect 31 32import m5 |
33from m5 import panic |
34from convert import * 35from multidict import multidict 36 37noDot = False 38try: 39 import pydot 40except: 41 noDot = True --- 89 unchanged lines hidden (view full) --- 131# metaclass to define most of the SimObject parameter behavior for 132# this class hierarchy. 133# 134##################################################################### 135 136def isSimObject(value): 137 return isinstance(value, SimObject) 138 |
139def isSimObjectClass(value): 140 try: 141 return issubclass(value, SimObject) 142 except TypeError: 143 # happens if value is not a class at all 144 return False 145 |
146def isSimObjSequence(value): 147 if not isinstance(value, (list, tuple)): 148 return False 149 150 for val in value: 151 if not isNullPointer(val) and not isSimObject(val): 152 return False 153 154 return True 155 |
156def isSimObjClassSequence(value): 157 if not isinstance(value, (list, tuple)): 158 return False 159 160 for val in value: 161 if not isNullPointer(val) and not isSimObjectClass(val): 162 return False 163 164 return True 165 |
166def isNullPointer(value): 167 return isinstance(value, NullSimObject) 168 169# The metaclass for ConfigNode (and thus for everything that derives 170# from ConfigNode, including SimObject). This class controls how new 171# classes that derive from ConfigNode are instantiated, and provides 172# inherited class behavior (just like a class controls how instances 173# of that class are instantiated, and provides inherited instance --- 7 unchanged lines hidden (view full) --- 181 'children' : types.ListType } 182 183 # __new__ is called before __init__, and is where the statements 184 # in the body of the class definition get loaded into the class's 185 # __dict__. We intercept this to filter out parameter assignments 186 # and only allow "private" attributes to be passed to the base 187 # __new__ (starting with underscore). 188 def __new__(mcls, name, bases, dict): |
189 if dict.has_key('_init_dict'): 190 # must have been called from makeSubclass() rather than 191 # via Python class declaration; bypass filtering process. 192 cls_dict = dict 193 else: 194 # Copy "private" attributes (including special methods 195 # such as __new__) to the official dict. Everything else 196 # goes in _init_dict to be filtered in __init__. 197 cls_dict = {} 198 for key,val in dict.items(): 199 if key.startswith('_'): 200 cls_dict[key] = val 201 del dict[key] 202 cls_dict['_init_dict'] = dict |
203 return super(MetaSimObject, mcls).__new__(mcls, name, bases, cls_dict) 204 |
205 # subclass initialization |
206 def __init__(cls, name, bases, dict): |
207 # calls type.__init__()... I think that's a no-op, but leave 208 # it here just in case it's not. |
209 super(MetaSimObject, cls).__init__(name, bases, dict) 210 211 # initialize required attributes 212 cls._params = multidict() 213 cls._values = multidict() 214 cls._anon_subclass_counter = 0 215 216 # We don't support multiple inheritance. If you want to, you 217 # must fix multidict to deal with it properly. 218 if len(bases) > 1: 219 raise TypeError, "SimObjects do not support multiple inheritance" 220 221 base = bases[0] 222 |
223 # the only time the following is not true is when we define 224 # the SimObject class itself |
225 if isinstance(base, MetaSimObject): 226 cls._params.parent = base._params 227 cls._values.parent = base._values 228 |
229 # now process the _init_dict items |
230 for key,val in cls._init_dict.items(): 231 if isinstance(val, (types.FunctionType, types.TypeType)): 232 type.__setattr__(cls, key, val) 233 234 # param descriptions 235 elif isinstance(val, ParamDesc): 236 cls._new_param(key, val) 237 238 # init-time-only keywords 239 elif cls.init_keywords.has_key(key): 240 cls._set_keyword(key, val, cls.init_keywords[key]) 241 242 # default: use normal path (ends up in __setattr__) 243 else: 244 setattr(cls, key, val) 245 |
246 # Pull the deep-copy memoization dict out of the class dict if 247 # it's there... 248 memo = cls.__dict__.get('_memo', {}) 249 250 # Handle SimObject values 251 for key,val in cls._values.iteritems(): 252 # SimObject instances need to be promoted to classes. 253 # Existing classes should not have any instance values, so 254 # these can only occur at the lowest level dict (the 255 # parameters just being set in this class definition). 256 if isSimObject(val): 257 assert(val == cls._values.local[key]) 258 cls._values[key] = val.makeClass(memo) 259 elif isSimObjSequence(val) and len(val): 260 assert(val == cls._values.local[key]) 261 cls._values[key] = [ v.makeClass(memo) for v in val ] 262 # SimObject classes need to be subclassed so that 263 # parameters that get set at this level only affect this 264 # level and derivatives. 265 elif isSimObjectClass(val): 266 assert(not cls._values.local.has_key(key)) 267 cls._values[key] = val.makeSubclass({}, memo) 268 elif isSimObjClassSequence(val) and len(val): 269 assert(not cls._values.local.has_key(key)) 270 cls._values[key] = [ v.makeSubclass({}, memo) for v in val ] 271 272 |
273 def _set_keyword(cls, keyword, val, kwtype): 274 if not isinstance(val, kwtype): 275 raise TypeError, 'keyword %s has bad type %s (expecting %s)' % \ 276 (keyword, type(val), kwtype) 277 if isinstance(val, types.FunctionType): 278 val = classmethod(val) 279 type.__setattr__(cls, keyword, val) 280 --- 34 unchanged lines hidden (view full) --- 315 316 def __getattr__(cls, attr): 317 if cls._values.has_key(attr): 318 return cls._values[attr] 319 320 raise AttributeError, \ 321 "object '%s' has no attribute '%s'" % (cls.__name__, attr) 322 |
323 # Create a subclass of this class. Basically a function interface 324 # to the standard Python class definition mechanism, primarily for 325 # internal use. 'memo' dict param supports "deep copy" (really 326 # "deep subclass") operations... within a given operation, 327 # multiple references to a class should result in a single 328 # subclass object with multiple references to it (as opposed to 329 # mutiple unique subclasses). 330 def makeSubclass(cls, init_dict, memo = {}): 331 subcls = memo.get(cls) 332 if not subcls: 333 name = cls.__name__ + '_' + str(cls._anon_subclass_counter) 334 cls._anon_subclass_counter += 1 335 subcls = MetaSimObject(name, (cls,), 336 { '_init_dict': init_dict, '_memo': memo }) 337 return subcls 338 |
339# The ConfigNode class is the root of the special hierarchy. Most of 340# the code in this class deals with the configuration hierarchy itself 341# (parent/child node relationships). 342class SimObject(object): 343 # Specify metaclass. Any class inheriting from SimObject will 344 # get this metaclass. 345 __metaclass__ = MetaSimObject 346 |
347 # __new__ operator allocates new instances of the class. We 348 # override it here just to support "deep instantiation" operation 349 # via the _memo dict. When recursively instantiating an object 350 # hierarchy we want to make sure that each class is instantiated 351 # only once, and that if there are multiple references to the same 352 # original class, we end up with the corresponding instantiated 353 # references all pointing to the same instance. 354 def __new__(cls, _memo = None, **kwargs): 355 if _memo is not None and _memo.has_key(cls): 356 # return previously instantiated object 357 assert(len(kwargs) == 0) 358 return _memo[cls] 359 else: 360 # Need a new one... if it needs to be memoized, this will 361 # happen in __init__. We defer the insertion until then 362 # so __init__ can use the memo dict to tell whether or not 363 # to perform the initialization. 364 return super(SimObject, cls).__new__(cls, **kwargs) 365 366 # Initialize new instance previously allocated by __new__. For 367 # objects with SimObject-valued params, we need to recursively 368 # instantiate the classes represented by those param values as 369 # well (in a consistent "deep copy"-style fashion; see comment 370 # above). 371 def __init__(self, _memo = None, **kwargs): 372 if _memo is not None: 373 # We're inside a "deep instantiation" 374 assert(isinstance(_memo, dict)) 375 assert(len(kwargs) == 0) 376 if _memo.has_key(self.__class__): 377 # __new__ returned an existing, already initialized 378 # instance, so there's nothing to do here 379 assert(_memo[self.__class__] == self) 380 return 381 # no pre-existing object, so remember this one here 382 _memo[self.__class__] = self 383 else: 384 # This is a new top-level instantiation... don't memoize 385 # this objcet, but prepare to memoize any recursively 386 # instantiated objects. 387 _memo = {} 388 |
389 self._children = {} |
390 # Inherit parameter values from class using multidict so 391 # individual value settings can be overridden. 392 self._values = multidict(self.__class__._values) 393 # For SimObject-valued parameters, the class should have 394 # classes (not instances) for the values. We need to 395 # instantiate these classes rather than just inheriting the 396 # class object. 397 for key,val in self.__class__._values.iteritems(): 398 if isSimObjectClass(val): 399 setattr(self, key, val(_memo)) 400 elif isSimObjClassSequence(val) and len(val): 401 setattr(self, key, [ v(_memo) for v in val ]) |
402 # apply attribute assignments from keyword args, if any 403 for key,val in kwargs.iteritems(): 404 setattr(self, key, val) 405 |
406 # Use this instance as a template to create a new class. 407 def makeClass(self, memo = {}): 408 cls = memo.get(self) 409 if not cls: 410 cls = self.__class__.makeSubclass(self._values.local) 411 memo[self] = cls 412 return cls 413 414 # Direct instantiation of instances (cloning) is no longer 415 # allowed; must generate class from instance first. |
416 def __call__(self, **kwargs): |
417 raise TypeError, "cannot instantiate SimObject; "\ 418 "use makeClass() to make class first" |
419 420 def __getattr__(self, attr): 421 if self._values.has_key(attr): 422 return self._values[attr] 423 424 raise AttributeError, "object '%s' has no attribute '%s'" \ 425 % (self.__class__.__name__, attr) 426 --- 740 unchanged lines hidden (view full) --- 1167 1168 def unproxy(self, base): 1169 if self.value == NextEthernetAddr: 1170 self.addr = self.value().value 1171 return self 1172 1173 def __str__(self): 1174 if self.value == NextEthernetAddr: |
1175 if hasattr(self, 'addr'): 1176 return self.addr 1177 else: 1178 return "NextEthernetAddr (unresolved)" |
1179 else: 1180 return self.value 1181 1182# Special class for NULL pointers. Note the special check in 1183# make_param_value() above that lets these be assigned where a 1184# SimObject is required. 1185# only one copy of a particular node 1186class NullSimObject(object): --- 229 unchanged lines hidden --- |