config.py (2738:5d7a31c7fa29) | config.py (2740:1c2058745499) |
---|---|
1# Copyright (c) 2004-2005 The Regents of The University of Michigan | 1# Copyright (c) 2004-2006 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 9# notice, this list of conditions and the following disclaimer in the --- 12 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 | 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 9# notice, this list of conditions and the following disclaimer in the --- 12 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 | 30import os, re, sys, types, inspect, copy |
31 32import m5 33from m5 import panic 34from convert import * 35from multidict import multidict 36 37noDot = False 38try: --- 40 unchanged lines hidden (view full) --- 79# "cache.assoc='hello'" would both result in runtime errors in Python, 80# since the BaseCache object has no 'blurfl' parameter and the 'assoc' 81# parameter requires an integer, respectively. This magic is done 82# primarily by overriding the special __setattr__ method that controls 83# assignment to object attributes. 84# 85# Once a set of Python objects have been instantiated in a hierarchy, 86# calling 'instantiate(obj)' (where obj is the root of the hierarchy) | 31 32import m5 33from m5 import panic 34from convert import * 35from multidict import multidict 36 37noDot = False 38try: --- 40 unchanged lines hidden (view full) --- 79# "cache.assoc='hello'" would both result in runtime errors in Python, 80# since the BaseCache object has no 'blurfl' parameter and the 'assoc' 81# parameter requires an integer, respectively. This magic is done 82# primarily by overriding the special __setattr__ method that controls 83# assignment to object attributes. 84# 85# Once a set of Python objects have been instantiated in a hierarchy, 86# calling 'instantiate(obj)' (where obj is the root of the hierarchy) |
87# will generate a .ini file. See simple-4cpu.py for an example 88# (corresponding to m5-test/simple-4cpu.ini). | 87# will generate a .ini file. |
89# 90##################################################################### 91 | 88# 89##################################################################### 90 |
92##################################################################### 93# 94# ConfigNode/SimObject classes 95# 96# The Python class hierarchy rooted by ConfigNode (which is the base 97# class of SimObject, which in turn is the base class of all other M5 98# SimObject classes) has special attribute behavior. In general, an 99# object in this hierarchy has three categories of attribute-like 100# things: 101# 102# 1. Regular Python methods and variables. These must start with an 103# underscore to be treated normally. 104# 105# 2. SimObject parameters. These values are stored as normal Python 106# attributes, but all assignments to these attributes are checked 107# against the pre-defined set of parameters stored in the class's 108# _params dictionary. Assignments to attributes that do not 109# correspond to predefined parameters, or that are not of the correct 110# type, incur runtime errors. 111# 112# 3. Hierarchy children. The child nodes of a ConfigNode are stored 113# in the node's _children dictionary, but can be accessed using the 114# Python attribute dot-notation (just as they are printed out by the 115# simulator). Children cannot be created using attribute assigment; 116# they must be added by specifying the parent node in the child's 117# constructor or using the '+=' operator. 118 119# The SimObject parameters are the most complex, for a few reasons. 120# First, both parameter descriptions and parameter values are 121# inherited. Thus parameter description lookup must go up the 122# inheritance chain like normal attribute lookup, but this behavior 123# must be explicitly coded since the lookup occurs in each class's 124# _params attribute. Second, because parameter values can be set 125# on SimObject classes (to implement default values), the parameter 126# checking behavior must be enforced on class attribute assignments as 127# well as instance attribute assignments. Finally, because we allow 128# class specialization via inheritance (e.g., see the L1Cache class in 129# the simple-4cpu.py example), we must do parameter checking even on 130# class instantiation. To provide all these features, we use a 131# metaclass to define most of the SimObject parameter behavior for 132# this class hierarchy. 133# 134##################################################################### 135 136 | |
137# dict to look up SimObjects based on path 138instanceDict = {} 139 | 91# dict to look up SimObjects based on path 92instanceDict = {} 93 |
94############################# 95# 96# Utility methods 97# 98############################# 99 |
|
140def isSimObject(value): 141 return isinstance(value, SimObject) 142 | 100def isSimObject(value): 101 return isinstance(value, SimObject) 102 |
143def isSimObjectClass(value): 144 try: 145 return issubclass(value, SimObject) 146 except TypeError: 147 # happens if value is not a class at all 148 return False 149 | |
150def isSimObjectSequence(value): 151 if not isinstance(value, (list, tuple)) or len(value) == 0: 152 return False 153 154 for val in value: 155 if not isNullPointer(val) and not isSimObject(val): 156 return False 157 158 return True 159 | 103def isSimObjectSequence(value): 104 if not isinstance(value, (list, tuple)) or len(value) == 0: 105 return False 106 107 for val in value: 108 if not isNullPointer(val) and not isSimObject(val): 109 return False 110 111 return True 112 |
160def isSimObjectClassSequence(value): 161 if not isinstance(value, (list, tuple)) or len(value) == 0: 162 return False 163 164 for val in value: 165 if not isNullPointer(val) and not isSimObjectClass(val): 166 return False 167 168 return True 169 | |
170def isSimObjectOrSequence(value): 171 return isSimObject(value) or isSimObjectSequence(value) 172 | 113def isSimObjectOrSequence(value): 114 return isSimObject(value) or isSimObjectSequence(value) 115 |
173def isSimObjectClassOrSequence(value): 174 return isSimObjectClass(value) or isSimObjectClassSequence(value) 175 | |
176def isNullPointer(value): 177 return isinstance(value, NullSimObject) 178 179# Apply method to object. 180# applyMethod(obj, 'meth', <args>) is equivalent to obj.meth(<args>) 181def applyMethod(obj, meth, *args, **kwargs): 182 return getattr(obj, meth)(*args, **kwargs) 183 184# If the first argument is an (non-sequence) object, apply the named 185# method with the given arguments. If the first argument is a 186# sequence, apply the method to each element of the sequence (a la 187# 'map'). 188def applyOrMap(objOrSeq, meth, *args, **kwargs): 189 if not isinstance(objOrSeq, (list, tuple)): 190 return applyMethod(objOrSeq, meth, *args, **kwargs) 191 else: 192 return [applyMethod(o, meth, *args, **kwargs) for o in objOrSeq] 193 194 | 116def isNullPointer(value): 117 return isinstance(value, NullSimObject) 118 119# Apply method to object. 120# applyMethod(obj, 'meth', <args>) is equivalent to obj.meth(<args>) 121def applyMethod(obj, meth, *args, **kwargs): 122 return getattr(obj, meth)(*args, **kwargs) 123 124# If the first argument is an (non-sequence) object, apply the named 125# method with the given arguments. If the first argument is a 126# sequence, apply the method to each element of the sequence (a la 127# 'map'). 128def applyOrMap(objOrSeq, meth, *args, **kwargs): 129 if not isinstance(objOrSeq, (list, tuple)): 130 return applyMethod(objOrSeq, meth, *args, **kwargs) 131 else: 132 return [applyMethod(o, meth, *args, **kwargs) for o in objOrSeq] 133 134 |
195# The metaclass for ConfigNode (and thus for everything that derives 196# from ConfigNode, including SimObject). This class controls how new 197# classes that derive from ConfigNode are instantiated, and provides 198# inherited class behavior (just like a class controls how instances 199# of that class are instantiated, and provides inherited instance 200# behavior). | 135# The metaclass for SimObject. This class controls how new classes 136# that derive from SimObject are instantiated, and provides inherited 137# class behavior (just like a class controls how instances of that 138# class are instantiated, and provides inherited instance behavior). |
201class MetaSimObject(type): 202 # Attributes that can be set only at initialization time 203 init_keywords = { 'abstract' : types.BooleanType, 204 'type' : types.StringType } 205 # Attributes that can be set any time | 139class MetaSimObject(type): 140 # Attributes that can be set only at initialization time 141 init_keywords = { 'abstract' : types.BooleanType, 142 'type' : types.StringType } 143 # Attributes that can be set any time |
206 keywords = { 'check' : types.FunctionType, 207 'children' : types.ListType, 208 'ccObject' : types.ObjectType } | 144 keywords = { 'check' : types.FunctionType } |
209 210 # __new__ is called before __init__, and is where the statements 211 # in the body of the class definition get loaded into the class's | 145 146 # __new__ is called before __init__, and is where the statements 147 # in the body of the class definition get loaded into the class's |
212 # __dict__. We intercept this to filter out parameter assignments | 148 # __dict__. We intercept this to filter out parameter & port assignments |
213 # and only allow "private" attributes to be passed to the base 214 # __new__ (starting with underscore). 215 def __new__(mcls, name, bases, dict): | 149 # and only allow "private" attributes to be passed to the base 150 # __new__ (starting with underscore). 151 def __new__(mcls, name, bases, dict): |
216 if dict.has_key('_init_dict'): 217 # must have been called from makeSubclass() rather than 218 # via Python class declaration; bypass filtering process. 219 cls_dict = dict 220 else: 221 # Copy "private" attributes (including special methods 222 # such as __new__) to the official dict. Everything else 223 # goes in _init_dict to be filtered in __init__. 224 cls_dict = {} 225 for key,val in dict.items(): 226 if key.startswith('_'): 227 cls_dict[key] = val 228 del dict[key] 229 cls_dict['_init_dict'] = dict | 152 # Copy "private" attributes, functions, and classes to the 153 # official dict. Everything else goes in _init_dict to be 154 # filtered in __init__. 155 cls_dict = {} 156 value_dict = {} 157 for key,val in dict.items(): 158 if key.startswith('_') or isinstance(val, (types.FunctionType, 159 types.TypeType)): 160 cls_dict[key] = val 161 else: 162 # must be a param/port setting 163 value_dict[key] = val 164 cls_dict['_value_dict'] = value_dict |
230 return super(MetaSimObject, mcls).__new__(mcls, name, bases, cls_dict) 231 232 # subclass initialization 233 def __init__(cls, name, bases, dict): 234 # calls type.__init__()... I think that's a no-op, but leave 235 # it here just in case it's not. 236 super(MetaSimObject, cls).__init__(name, bases, dict) 237 238 # initialize required attributes | 165 return super(MetaSimObject, mcls).__new__(mcls, name, bases, cls_dict) 166 167 # subclass initialization 168 def __init__(cls, name, bases, dict): 169 # calls type.__init__()... I think that's a no-op, but leave 170 # it here just in case it's not. 171 super(MetaSimObject, cls).__init__(name, bases, dict) 172 173 # initialize required attributes |
239 cls._params = multidict() 240 cls._values = multidict() 241 cls._ports = multidict() 242 cls._instantiated = False # really instantiated or subclassed 243 cls._anon_subclass_counter = 0 | |
244 | 174 |
175 # class-only attributes 176 cls._params = multidict() # param descriptions 177 cls._ports = multidict() # port descriptions 178 179 # class or instance attributes 180 cls._values = multidict() # param values 181 cls._port_map = multidict() # port bindings 182 cls._instantiated = False # really instantiated, cloned, or subclassed 183 |
|
245 # We don't support multiple inheritance. If you want to, you 246 # must fix multidict to deal with it properly. 247 if len(bases) > 1: 248 raise TypeError, "SimObjects do not support multiple inheritance" 249 250 base = bases[0] 251 | 184 # We don't support multiple inheritance. If you want to, you 185 # must fix multidict to deal with it properly. 186 if len(bases) > 1: 187 raise TypeError, "SimObjects do not support multiple inheritance" 188 189 base = bases[0] 190 |
252 # the only time the following is not true is when we define 253 # the SimObject class itself | 191 # Set up general inheritance via multidicts. A subclass will 192 # inherit all its settings from the base class. The only time 193 # the following is not true is when we define the SimObject 194 # class itself (in which case the multidicts have no parent). |
254 if isinstance(base, MetaSimObject): 255 cls._params.parent = base._params | 195 if isinstance(base, MetaSimObject): 196 cls._params.parent = base._params |
256 cls._values.parent = base._values | |
257 cls._ports.parent = base._ports | 197 cls._ports.parent = base._ports |
198 cls._values.parent = base._values 199 cls._port_map.parent = base._port_map 200 # mark base as having been subclassed |
|
258 base._instantiated = True 259 | 201 base._instantiated = True 202 |
260 # now process the _init_dict items 261 for key,val in cls._init_dict.items(): 262 if isinstance(val, (types.FunctionType, types.TypeType)): 263 type.__setattr__(cls, key, val) 264 | 203 # Now process the _value_dict items. They could be defining 204 # new (or overriding existing) parameters or ports, setting 205 # class keywords (e.g., 'abstract'), or setting parameter 206 # values or port bindings. The first 3 can only be set when 207 # the class is defined, so we handle them here. The others 208 # can be set later too, so just emulate that by calling 209 # setattr(). 210 for key,val in cls._value_dict.items(): |
265 # param descriptions | 211 # param descriptions |
266 elif isinstance(val, ParamDesc): | 212 if isinstance(val, ParamDesc): |
267 cls._new_param(key, val) 268 269 # port objects 270 elif isinstance(val, Port): 271 cls._ports[key] = val 272 273 # init-time-only keywords 274 elif cls.init_keywords.has_key(key): 275 cls._set_keyword(key, val, cls.init_keywords[key]) 276 277 # default: use normal path (ends up in __setattr__) 278 else: 279 setattr(cls, key, val) 280 | 213 cls._new_param(key, val) 214 215 # port objects 216 elif isinstance(val, Port): 217 cls._ports[key] = val 218 219 # init-time-only keywords 220 elif cls.init_keywords.has_key(key): 221 cls._set_keyword(key, val, cls.init_keywords[key]) 222 223 # default: use normal path (ends up in __setattr__) 224 else: 225 setattr(cls, key, val) 226 |
281 # Pull the deep-copy memoization dict out of the class dict if 282 # it's there... 283 memo = cls.__dict__.get('_memo', {}) 284 285 # Handle SimObject values 286 for key,val in cls._values.iteritems(): 287 # SimObject instances need to be promoted to classes. 288 # Existing classes should not have any instance values, so 289 # these can only occur at the lowest level dict (the 290 # parameters just being set in this class definition). 291 if isSimObjectOrSequence(val): 292 assert(val == cls._values.local[key]) 293 cls._values[key] = applyOrMap(val, 'makeClass', memo) 294 # SimObject classes need to be subclassed so that 295 # parameters that get set at this level only affect this 296 # level and derivatives. 297 elif isSimObjectClassOrSequence(val): 298 assert(not cls._values.local.has_key(key)) 299 cls._values[key] = applyOrMap(val, 'makeSubclass', {}, memo) 300 301 | |
302 def _set_keyword(cls, keyword, val, kwtype): 303 if not isinstance(val, kwtype): 304 raise TypeError, 'keyword %s has bad type %s (expecting %s)' % \ 305 (keyword, type(val), kwtype) 306 if isinstance(val, types.FunctionType): 307 val = classmethod(val) 308 type.__setattr__(cls, keyword, val) 309 --- 13 unchanged lines hidden (view full) --- 323 if cls.keywords.has_key(attr): 324 cls._set_keyword(attr, value, cls.keywords[attr]) 325 return 326 327 if cls._ports.has_key(attr): 328 self._ports[attr].connect(self, attr, value) 329 return 330 | 227 def _set_keyword(cls, keyword, val, kwtype): 228 if not isinstance(val, kwtype): 229 raise TypeError, 'keyword %s has bad type %s (expecting %s)' % \ 230 (keyword, type(val), kwtype) 231 if isinstance(val, types.FunctionType): 232 val = classmethod(val) 233 type.__setattr__(cls, keyword, val) 234 --- 13 unchanged lines hidden (view full) --- 248 if cls.keywords.has_key(attr): 249 cls._set_keyword(attr, value, cls.keywords[attr]) 250 return 251 252 if cls._ports.has_key(attr): 253 self._ports[attr].connect(self, attr, value) 254 return 255 |
331 # must be SimObject param 332 param = cls._params.get(attr, None) 333 if param: 334 # It's ok: set attribute by delegating to 'object' class. 335 if isSimObjectOrSequence(value) and cls._instantiated: 336 raise AttributeError, \ 337 "Cannot set SimObject parameter '%s' after\n" \ | 256 if isSimObjectOrSequence(value) and cls._instantiated: 257 raise RuntimeError, \ 258 "cannot set SimObject parameter '%s' after\n" \ |
338 " class %s has been instantiated or subclassed" \ 339 % (attr, cls.__name__) | 259 " class %s has been instantiated or subclassed" \ 260 % (attr, cls.__name__) |
261 262 # check for param 263 param = cls._params.get(attr, None) 264 if param: |
|
340 try: 341 cls._values[attr] = param.convert(value) 342 except Exception, e: 343 msg = "%s\nError setting param %s.%s to %s\n" % \ 344 (e, cls.__name__, attr, value) 345 e.args = (msg, ) 346 raise | 265 try: 266 cls._values[attr] = param.convert(value) 267 except Exception, e: 268 msg = "%s\nError setting param %s.%s to %s\n" % \ 269 (e, cls.__name__, attr, value) 270 e.args = (msg, ) 271 raise |
347 # I would love to get rid of this | |
348 elif isSimObjectOrSequence(value): | 272 elif isSimObjectOrSequence(value): |
349 cls._values[attr] = value | 273 # if RHS is a SimObject, it's an implicit child assignment 274 cls._values[attr] = value |
350 else: 351 raise AttributeError, \ 352 "Class %s has no parameter %s" % (cls.__name__, attr) 353 354 def __getattr__(cls, attr): 355 if cls._values.has_key(attr): 356 return cls._values[attr] 357 358 raise AttributeError, \ 359 "object '%s' has no attribute '%s'" % (cls.__name__, attr) 360 | 275 else: 276 raise AttributeError, \ 277 "Class %s has no parameter %s" % (cls.__name__, attr) 278 279 def __getattr__(cls, attr): 280 if cls._values.has_key(attr): 281 return cls._values[attr] 282 283 raise AttributeError, \ 284 "object '%s' has no attribute '%s'" % (cls.__name__, attr) 285 |
361 # Create a subclass of this class. Basically a function interface 362 # to the standard Python class definition mechanism, primarily for 363 # internal use. 'memo' dict param supports "deep copy" (really 364 # "deep subclass") operations... within a given operation, 365 # multiple references to a class should result in a single 366 # subclass object with multiple references to it (as opposed to 367 # mutiple unique subclasses). 368 def makeSubclass(cls, init_dict, memo = {}): 369 subcls = memo.get(cls) 370 if not subcls: 371 name = cls.__name__ + '_' + str(cls._anon_subclass_counter) 372 cls._anon_subclass_counter += 1 373 subcls = MetaSimObject(name, (cls,), 374 { '_init_dict': init_dict, '_memo': memo }) 375 return subcls 376 377# The ConfigNode class is the root of the special hierarchy. Most of | 286# The SimObject class is the root of the special hierarchy. Most of |
378# the code in this class deals with the configuration hierarchy itself 379# (parent/child node relationships). 380class SimObject(object): 381 # Specify metaclass. Any class inheriting from SimObject will 382 # get this metaclass. 383 __metaclass__ = MetaSimObject 384 | 287# the code in this class deals with the configuration hierarchy itself 288# (parent/child node relationships). 289class SimObject(object): 290 # Specify metaclass. Any class inheriting from SimObject will 291 # get this metaclass. 292 __metaclass__ = MetaSimObject 293 |
385 # __new__ operator allocates new instances of the class. We 386 # override it here just to support "deep instantiation" operation 387 # via the _memo dict. When recursively instantiating an object 388 # hierarchy we want to make sure that each class is instantiated 389 # only once, and that if there are multiple references to the same 390 # original class, we end up with the corresponding instantiated 391 # references all pointing to the same instance. 392 def __new__(cls, _memo = None, **kwargs): 393 if _memo is not None and _memo.has_key(cls): 394 # return previously instantiated object 395 assert(len(kwargs) == 0) 396 return _memo[cls] 397 else: 398 # Need a new one... if it needs to be memoized, this will 399 # happen in __init__. We defer the insertion until then 400 # so __init__ can use the memo dict to tell whether or not 401 # to perform the initialization. 402 return super(SimObject, cls).__new__(cls, **kwargs) | 294 # Initialize new instance. For objects with SimObject-valued 295 # children, we need to recursively clone the classes represented 296 # by those param values as well in a consistent "deep copy"-style 297 # fashion. That is, we want to make sure that each instance is 298 # cloned only once, and that if there are multiple references to 299 # the same original object, we end up with the corresponding 300 # cloned references all pointing to the same cloned instance. 301 def __init__(self, **kwargs): 302 ancestor = kwargs.get('_ancestor') 303 memo_dict = kwargs.get('_memo') 304 if memo_dict is None: 305 # prepare to memoize any recursively instantiated objects 306 memo_dict = {} 307 elif ancestor: 308 # memoize me now to avoid problems with recursive calls 309 memo_dict[ancestor] = self |
403 | 310 |
404 # Initialize new instance previously allocated by __new__. For 405 # objects with SimObject-valued params, we need to recursively 406 # instantiate the classes represented by those param values as 407 # well (in a consistent "deep copy"-style fashion; see comment 408 # above). 409 def __init__(self, _memo = None, **kwargs): 410 if _memo is not None: 411 # We're inside a "deep instantiation" 412 assert(isinstance(_memo, dict)) 413 assert(len(kwargs) == 0) 414 if _memo.has_key(self.__class__): 415 # __new__ returned an existing, already initialized 416 # instance, so there's nothing to do here 417 assert(_memo[self.__class__] == self) 418 return 419 # no pre-existing object, so remember this one here 420 _memo[self.__class__] = self 421 else: 422 # This is a new top-level instantiation... don't memoize 423 # this objcet, but prepare to memoize any recursively 424 # instantiated objects. 425 _memo = {} | 311 if not ancestor: 312 ancestor = self.__class__ 313 ancestor._instantiated = True |
426 | 314 |
427 self.__class__._instantiated = True 428 | 315 # initialize required attributes 316 self._parent = None |
429 self._children = {} | 317 self._children = {} |
318 self._ccObject = None # pointer to C++ object 319 self._instantiated = False # really "cloned" 320 |
|
430 # Inherit parameter values from class using multidict so 431 # individual value settings can be overridden. | 321 # Inherit parameter values from class using multidict so 322 # individual value settings can be overridden. |
432 self._values = multidict(self.__class__._values) 433 # For SimObject-valued parameters, the class should have 434 # classes (not instances) for the values. We need to 435 # instantiate these classes rather than just inheriting the 436 # class object. 437 for key,val in self.__class__._values.iteritems(): 438 if isSimObjectClass(val): 439 setattr(self, key, val(_memo)) 440 elif isSimObjectClassSequence(val) and len(val): 441 setattr(self, key, [ v(_memo) for v in val ]) | 323 self._values = multidict(ancestor._values) 324 # clone SimObject-valued parameters 325 for key,val in ancestor._values.iteritems(): 326 if isSimObject(val): 327 setattr(self, key, val(_memo=memo_dict)) 328 elif isSimObjectSequence(val) and len(val): 329 setattr(self, key, [ v(_memo=memo_dict) for v in val ]) 330 # clone port references. no need to use a multidict here 331 # since we will be creating new references for all ports. 332 self._port_map = {} 333 for key,val in ancestor._port_map.iteritems(): 334 self._port_map[key] = applyOrMap(val, 'clone', memo_dict) |
442 # apply attribute assignments from keyword args, if any 443 for key,val in kwargs.iteritems(): 444 setattr(self, key, val) 445 | 335 # apply attribute assignments from keyword args, if any 336 for key,val in kwargs.iteritems(): 337 setattr(self, key, val) 338 |
446 self._ccObject = None # pointer to C++ object 447 self._port_map = {} # map of port connections 448 449 # Use this instance as a template to create a new class. 450 def makeClass(self, memo = {}): 451 cls = memo.get(self) 452 if not cls: 453 cls = self.__class__.makeSubclass(self._values.local) 454 memo[self] = cls 455 return cls 456 457 # Direct instantiation of instances (cloning) is no longer 458 # allowed; must generate class from instance first. | 339 # "Clone" the current instance by creating another instance of 340 # this instance's class, but that inherits its parameter values 341 # and port mappings from the current instance. If we're in a 342 # "deep copy" recursive clone, check the _memo dict to see if 343 # we've already cloned this instance. |
459 def __call__(self, **kwargs): | 344 def __call__(self, **kwargs): |
460 raise TypeError, "cannot instantiate SimObject; "\ 461 "use makeClass() to make class first" | 345 memo_dict = kwargs.get('_memo') 346 if memo_dict is None: 347 # no memo_dict: must be top-level clone operation. 348 # this is only allowed at the root of a hierarchy 349 if self._parent: 350 raise RuntimeError, "attempt to clone object %s " \ 351 "not at the root of a tree (parent = %s)" \ 352 % (self, self._parent) 353 # create a new dict and use that. 354 memo_dict = {} 355 kwargs['_memo'] = memo_dict 356 elif memo_dict.has_key(self): 357 # clone already done & memoized 358 return memo_dict[self] 359 return self.__class__(_ancestor = self, **kwargs) |
462 463 def __getattr__(self, attr): 464 if self._ports.has_key(attr): 465 # return reference that can be assigned to another port 466 # via __setattr__ 467 return self._ports[attr].makeRef(self, attr) 468 469 if self._values.has_key(attr): --- 10 unchanged lines hidden (view full) --- 480 object.__setattr__(self, attr, value) 481 return 482 483 if self._ports.has_key(attr): 484 # set up port connection 485 self._ports[attr].connect(self, attr, value) 486 return 487 | 360 361 def __getattr__(self, attr): 362 if self._ports.has_key(attr): 363 # return reference that can be assigned to another port 364 # via __setattr__ 365 return self._ports[attr].makeRef(self, attr) 366 367 if self._values.has_key(attr): --- 10 unchanged lines hidden (view full) --- 378 object.__setattr__(self, attr, value) 379 return 380 381 if self._ports.has_key(attr): 382 # set up port connection 383 self._ports[attr].connect(self, attr, value) 384 return 385 |
386 if isSimObjectOrSequence(value) and self._instantiated: 387 raise RuntimeError, \ 388 "cannot set SimObject parameter '%s' after\n" \ 389 " instance been cloned %s" % (attr, `self`) 390 |
|
488 # must be SimObject param 489 param = self._params.get(attr, None) 490 if param: | 391 # must be SimObject param 392 param = self._params.get(attr, None) 393 if param: |
491 # It's ok: set attribute by delegating to 'object' class. | |
492 try: 493 value = param.convert(value) 494 except Exception, e: 495 msg = "%s\nError setting param %s.%s to %s\n" % \ 496 (e, self.__class__.__name__, attr, value) 497 e.args = (msg, ) 498 raise | 394 try: 395 value = param.convert(value) 396 except Exception, e: 397 msg = "%s\nError setting param %s.%s to %s\n" % \ 398 (e, self.__class__.__name__, attr, value) 399 e.args = (msg, ) 400 raise |
499 # I would love to get rid of this | |
500 elif isSimObjectOrSequence(value): 501 pass 502 else: 503 raise AttributeError, "Class %s has no parameter %s" \ 504 % (self.__class__.__name__, attr) 505 506 # clear out old child with this name, if any 507 self.clear_child(attr) --- 22 unchanged lines hidden (view full) --- 530 for i in xrange(len(child)): 531 del self._children["s%d" % (name, i)] 532 del self._children[name] 533 534 def add_child(self, name, value): 535 self._children[name] = value 536 537 def set_path(self, parent, name): | 401 elif isSimObjectOrSequence(value): 402 pass 403 else: 404 raise AttributeError, "Class %s has no parameter %s" \ 405 % (self.__class__.__name__, attr) 406 407 # clear out old child with this name, if any 408 self.clear_child(attr) --- 22 unchanged lines hidden (view full) --- 431 for i in xrange(len(child)): 432 del self._children["s%d" % (name, i)] 433 del self._children[name] 434 435 def add_child(self, name, value): 436 self._children[name] = value 437 438 def set_path(self, parent, name): |
538 if not hasattr(self, '_parent'): | 439 if not self._parent: |
539 self._parent = parent 540 self._name = name 541 parent.add_child(name, self) 542 543 def path(self): | 440 self._parent = parent 441 self._name = name 442 parent.add_child(name, self) 443 444 def path(self): |
544 if not hasattr(self, '_parent'): | 445 if not self._parent: |
545 return 'root' 546 ppath = self._parent.path() 547 if ppath == 'root': 548 return self._name 549 return ppath + "." + self._name 550 551 def __str__(self): 552 return self.path() --- 60 unchanged lines hidden (view full) --- 613 print # blank line between objects 614 615 for child in child_names: 616 self._children[child].print_ini() 617 618 # Call C++ to create C++ object corresponding to this object and 619 # (recursively) all its children 620 def createCCObject(self): | 446 return 'root' 447 ppath = self._parent.path() 448 if ppath == 'root': 449 return self._name 450 return ppath + "." + self._name 451 452 def __str__(self): 453 return self.path() --- 60 unchanged lines hidden (view full) --- 514 print # blank line between objects 515 516 for child in child_names: 517 self._children[child].print_ini() 518 519 # Call C++ to create C++ object corresponding to this object and 520 # (recursively) all its children 521 def createCCObject(self): |
621 if self._ccObject: 622 return 623 self._ccObject = -1 624 self._ccObject = m5.main.createSimObject(self.path()) | 522 self.getCCObject() # force creation |
625 for child in self._children.itervalues(): 626 child.createCCObject() 627 | 523 for child in self._children.itervalues(): 524 child.createCCObject() 525 |
526 # Get C++ object corresponding to this object, calling C++ if 527 # necessary to construct it. Does *not* recursively create 528 # children. 529 def getCCObject(self): 530 if not self._ccObject: 531 self._ccObject = -1 # flag to catch cycles in recursion 532 self._ccObject = m5.main.createSimObject(self.path()) 533 elif self._ccObject == -1: 534 raise RuntimeError, "%s: recursive call to getCCObject()" \ 535 % self.path() 536 return self._ccObject 537 |
|
628 # Create C++ port connections corresponding to the connections in 629 # _port_map (& recursively for all children) 630 def connectPorts(self): 631 for portRef in self._port_map.itervalues(): 632 applyOrMap(portRef, 'ccConnect') 633 for child in self._children.itervalues(): 634 child.connectPorts() 635 --- 82 unchanged lines hidden (view full) --- 718 obj = base 719 done = False 720 721 if self._search_self: 722 result, done = self.find(obj) 723 724 if self._search_up: 725 while not done: | 538 # Create C++ port connections corresponding to the connections in 539 # _port_map (& recursively for all children) 540 def connectPorts(self): 541 for portRef in self._port_map.itervalues(): 542 applyOrMap(portRef, 'ccConnect') 543 for child in self._children.itervalues(): 544 child.connectPorts() 545 --- 82 unchanged lines hidden (view full) --- 628 obj = base 629 done = False 630 631 if self._search_self: 632 result, done = self.find(obj) 633 634 if self._search_up: 635 while not done: |
726 try: obj = obj._parent 727 except: break 728 | 636 obj = obj._parent 637 if not obj: 638 break |
729 result, done = self.find(obj) 730 731 if not done: 732 raise AttributeError, "Can't resolve proxy '%s' from '%s'" % \ 733 (self.path(), base.path()) 734 735 if isinstance(result, BaseProxy): 736 if result == self: --- 99 unchanged lines hidden (view full) --- 836# global objects for handling proxies 837Parent = ProxyFactory(search_self = False, search_up = True) 838Self = ProxyFactory(search_self = True, search_up = False) 839 840##################################################################### 841# 842# Parameter description classes 843# | 639 result, done = self.find(obj) 640 641 if not done: 642 raise AttributeError, "Can't resolve proxy '%s' from '%s'" % \ 643 (self.path(), base.path()) 644 645 if isinstance(result, BaseProxy): 646 if result == self: --- 99 unchanged lines hidden (view full) --- 746# global objects for handling proxies 747Parent = ProxyFactory(search_self = False, search_up = True) 748Self = ProxyFactory(search_self = True, search_up = False) 749 750##################################################################### 751# 752# Parameter description classes 753# |
844# The _params dictionary in each class maps parameter names to 845# either a Param or a VectorParam object. These objects contain the | 754# The _params dictionary in each class maps parameter names to either 755# a Param or a VectorParam object. These objects contain the |
846# parameter description string, the parameter type, and the default | 756# parameter description string, the parameter type, and the default |
847# value (loaded from the PARAM section of the .odesc files). The 848# _convert() method on these objects is used to force whatever value 849# is assigned to the parameter to the appropriate type. | 757# value (if any). The convert() method on these objects is used to 758# force whatever value is assigned to the parameter to the appropriate 759# type. |
850# 851# Note that the default values are loaded into the class's attribute 852# space when the parameter dictionary is initialized (in | 760# 761# Note that the default values are loaded into the class's attribute 762# space when the parameter dictionary is initialized (in |
853# MetaConfigNode._setparams()); after that point they aren't used. | 763# MetaSimObject._new_param()); after that point they aren't used. |
854# 855##################################################################### 856 857# Dummy base class to identify types that are legitimate for SimObject 858# parameters. 859class ParamValue(object): 860 861 # default for printing to .ini file is regular string conversion. --- 613 unchanged lines hidden (view full) --- 1475# Ports are used to interconnect objects in the memory system. 1476# 1477##################################################################### 1478 1479# Port reference: encapsulates a reference to a particular port on a 1480# particular SimObject. 1481class PortRef(object): 1482 def __init__(self, simobj, name, isVec): | 764# 765##################################################################### 766 767# Dummy base class to identify types that are legitimate for SimObject 768# parameters. 769class ParamValue(object): 770 771 # default for printing to .ini file is regular string conversion. --- 613 unchanged lines hidden (view full) --- 1385# Ports are used to interconnect objects in the memory system. 1386# 1387##################################################################### 1388 1389# Port reference: encapsulates a reference to a particular port on a 1390# particular SimObject. 1391class PortRef(object): 1392 def __init__(self, simobj, name, isVec): |
1393 assert(isSimObject(simobj)) |
|
1483 self.simobj = simobj 1484 self.name = name 1485 self.index = -1 1486 self.isVec = isVec # is this a vector port? 1487 self.peer = None # not associated with another port yet 1488 self.ccConnected = False # C++ port connection done? 1489 1490 # Set peer port reference. Called via __setattr__ as a result of --- 6 unchanged lines hidden (view full) --- 1497 else: 1498 curMap = self.simobj._port_map.get(self.name) 1499 if curMap and not self.isVec: 1500 print "warning: overwriting port", self.simobj, self.name 1501 curMap = other 1502 self.simobj._port_map[self.name] = curMap 1503 self.peer = other 1504 | 1394 self.simobj = simobj 1395 self.name = name 1396 self.index = -1 1397 self.isVec = isVec # is this a vector port? 1398 self.peer = None # not associated with another port yet 1399 self.ccConnected = False # C++ port connection done? 1400 1401 # Set peer port reference. Called via __setattr__ as a result of --- 6 unchanged lines hidden (view full) --- 1408 else: 1409 curMap = self.simobj._port_map.get(self.name) 1410 if curMap and not self.isVec: 1411 print "warning: overwriting port", self.simobj, self.name 1412 curMap = other 1413 self.simobj._port_map[self.name] = curMap 1414 self.peer = other 1415 |
1416 def clone(self, memo): 1417 newRef = copy.copy(self) 1418 assert(isSimObject(newRef.simobj)) 1419 newRef.simobj = newRef.simobj(_memo=memo) 1420 # Tricky: if I'm the *second* PortRef in the pair to be 1421 # cloned, then my peer is still in the middle of its clone 1422 # method, and thus hasn't returned to its owner's 1423 # SimObject.__init__ to get installed in _port_map. As a 1424 # result I have no way of finding the *new* peer object. So I 1425 # mark myself as "waiting" for my peer, and I let the *first* 1426 # PortRef clone call set up both peer pointers after I return. 1427 newPeer = newRef.simobj._port_map.get(self.name) 1428 if newPeer: 1429 if self.isVec: 1430 assert(self.index != -1) 1431 newPeer = newPeer[self.index] 1432 # other guy is all set up except for his peer pointer 1433 assert(newPeer.peer == -1) # peer must be waiting for handshake 1434 newPeer.peer = newRef 1435 newRef.peer = newPeer 1436 else: 1437 # other guy is in clone; just wait for him to do the work 1438 newRef.peer = -1 # mark as waiting for handshake 1439 return newRef 1440 |
|
1505 # Call C++ to create corresponding port connection between C++ objects 1506 def ccConnect(self): 1507 if self.ccConnected: # already done this 1508 return 1509 peer = self.peer | 1441 # Call C++ to create corresponding port connection between C++ objects 1442 def ccConnect(self): 1443 if self.ccConnected: # already done this 1444 return 1445 peer = self.peer |
1510 m5.main.connectPorts(self.simobj._ccObject, self.name, self.index, 1511 peer.simobj._ccObject, peer.name, peer.index) | 1446 m5.main.connectPorts(self.simobj.getCCObject(), self.name, self.index, 1447 peer.simobj.getCCObject(), peer.name, peer.index) |
1512 self.ccConnected = True 1513 peer.ccConnected = True 1514 1515# Port description object. Like a ParamDesc object, this represents a 1516# logical port in the SimObject class, not a particular port on a 1517# SimObject instance. The latter are represented by PortRef objects. 1518class Port(object): 1519 def __init__(self, desc): 1520 self.desc = desc 1521 self.isVec = False 1522 1523 # Generate a PortRef for this port on the given SimObject with the 1524 # given name 1525 def makeRef(self, simobj, name): 1526 return PortRef(simobj, name, self.isVec) 1527 1528 # Connect an instance of this port (on the given SimObject with 1529 # the given name) with the port described by the supplied PortRef 1530 def connect(self, simobj, name, ref): | 1448 self.ccConnected = True 1449 peer.ccConnected = True 1450 1451# Port description object. Like a ParamDesc object, this represents a 1452# logical port in the SimObject class, not a particular port on a 1453# SimObject instance. The latter are represented by PortRef objects. 1454class Port(object): 1455 def __init__(self, desc): 1456 self.desc = desc 1457 self.isVec = False 1458 1459 # Generate a PortRef for this port on the given SimObject with the 1460 # given name 1461 def makeRef(self, simobj, name): 1462 return PortRef(simobj, name, self.isVec) 1463 1464 # Connect an instance of this port (on the given SimObject with 1465 # the given name) with the port described by the supplied PortRef 1466 def connect(self, simobj, name, ref): |
1467 if not isinstance(ref, PortRef): 1468 raise TypeError, \ 1469 "assigning non-port reference port '%s'" % name |
|
1531 myRef = self.makeRef(simobj, name) 1532 myRef.setPeer(ref) 1533 ref.setPeer(myRef) 1534 1535# VectorPort description object. Like Port, but represents a vector 1536# of connections (e.g., as on a Bus). 1537class VectorPort(Port): 1538 def __init__(self, desc): --- 23 unchanged lines hidden --- | 1470 myRef = self.makeRef(simobj, name) 1471 myRef.setPeer(ref) 1472 ref.setPeer(myRef) 1473 1474# VectorPort description object. Like Port, but represents a vector 1475# of connections (e.g., as on a Bus). 1476class VectorPort(Port): 1477 def __init__(self, desc): --- 23 unchanged lines hidden --- |