Deleted Added
sdiff udiff text old ( 2738:5d7a31c7fa29 ) new ( 2740:1c2058745499 )
full compact
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
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
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).
89#
90#####################################################################
91
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
140def isSimObject(value):
141 return isinstance(value, SimObject)
142
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
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
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
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).
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
206 keywords = { 'check' : types.FunctionType,
207 'children' : types.ListType,
208 'ccObject' : types.ObjectType }
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
212 # __dict__. We intercept this to filter out parameter 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):
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
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
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
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
252 # the only time the following is not true is when we define
253 # the SimObject class itself
254 if isinstance(base, MetaSimObject):
255 cls._params.parent = base._params
256 cls._values.parent = base._values
257 cls._ports.parent = base._ports
258 base._instantiated = True
259
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
265 # param descriptions
266 elif 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
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
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" \
338 " class %s has been instantiated or subclassed" \
339 % (attr, cls.__name__)
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
347 # I would love to get rid of this
348 elif isSimObjectOrSequence(value):
349 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
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
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
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)
403
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 = {}
426
427 self.__class__._instantiated = True
428
429 self._children = {}
430 # Inherit parameter values from class using multidict so
431 # 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 ])
442 # apply attribute assignments from keyword args, if any
443 for key,val in kwargs.iteritems():
444 setattr(self, key, val)
445
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.
459 def __call__(self, **kwargs):
460 raise TypeError, "cannot instantiate SimObject; "\
461 "use makeClass() to make class first"
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
488 # must be SimObject param
489 param = self._params.get(attr, None)
490 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
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):
538 if not hasattr(self, '_parent'):
539 self._parent = parent
540 self._name = name
541 parent.add_child(name, self)
542
543 def path(self):
544 if not hasattr(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):
621 if self._ccObject:
622 return
623 self._ccObject = -1
624 self._ccObject = m5.main.createSimObject(self.path())
625 for child in self._children.itervalues():
626 child.createCCObject()
627
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:
726 try: obj = obj._parent
727 except: break
728
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#
844# The _params dictionary in each class maps parameter names to
845# either a Param or a VectorParam object. These objects contain the
846# 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.
850#
851# Note that the default values are loaded into the class's attribute
852# space when the parameter dictionary is initialized (in
853# MetaConfigNode._setparams()); 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):
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
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
1510 m5.main.connectPorts(self.simobj._ccObject, self.name, self.index,
1511 peer.simobj._ccObject, 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):
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 ---