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 ---