summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/python/m5/SimObject.py144
-rw-r--r--src/python/m5/params.py41
-rw-r--r--src/python/m5/simulate.py4
3 files changed, 136 insertions, 53 deletions
diff --git a/src/python/m5/SimObject.py b/src/python/m5/SimObject.py
index a3905949a..d95fb987e 100644
--- a/src/python/m5/SimObject.py
+++ b/src/python/m5/SimObject.py
@@ -27,7 +27,6 @@
# Authors: Steve Reinhardt
# Nathan Binkert
-import math
import sys
from types import FunctionType
@@ -45,7 +44,8 @@ from m5.util import *
from m5.params import *
# There are a few things we need that aren't in params.__all__ since
# normal users don't need them
-from m5.params import ParamDesc, VectorParamDesc, isNullPointer, SimObjVector
+from m5.params import ParamDesc, VectorParamDesc, \
+ isNullPointer, SimObjectVector
from m5.proxy import *
from m5.proxy import isproxy
@@ -155,6 +155,7 @@ class MetaSimObject(type):
# class or instance attributes
cls._values = multidict() # param values
+ cls._children = multidict() # SimObject children
cls._port_refs = multidict() # port ref objects
cls._instantiated = False # really instantiated, cloned, or subclassed
@@ -174,6 +175,7 @@ class MetaSimObject(type):
cls._params.parent = base._params
cls._ports.parent = base._ports
cls._values.parent = base._values
+ cls._children.parent = base._children
cls._port_refs.parent = base._port_refs
# mark base as having been subclassed
base._instantiated = True
@@ -305,11 +307,7 @@ class MetaSimObject(type):
if isSimObjectOrSequence(value):
# If RHS is a SimObject, it's an implicit child assignment.
- # Classes don't have children, so we just put this object
- # in _values; later, each instance will do a 'setattr(self,
- # attr, _values[attr])' in SimObject.__init__ which will
- # add this object as a child.
- cls._values[attr] = value
+ cls._children[attr] = coerceSimObjectOrVector(value)
return
# no valid assignment... raise exception
@@ -320,6 +318,9 @@ class MetaSimObject(type):
if cls._values.has_key(attr):
return cls._values[attr]
+ if cls._children.has_key(attr):
+ return cls._children[attr]
+
raise AttributeError, \
"object '%s' has no attribute '%s'" % (cls.__name__, attr)
@@ -465,20 +466,27 @@ class SimObject(object):
# initialize required attributes
self._parent = None
- self._children = {}
+ self._name = None
self._ccObject = None # pointer to C++ object
self._ccParams = None
self._instantiated = False # really "cloned"
# Inherit parameter values from class using multidict so
- # individual value settings can be overridden.
+ # individual value settings can be overridden but we still
+ # inherit late changes to non-overridden class values.
self._values = multidict(ancestor._values)
# clone SimObject-valued parameters
for key,val in ancestor._values.iteritems():
- if isSimObject(val):
- setattr(self, key, val(_memo=memo_dict))
- elif isSimObjectSequence(val) and len(val):
- setattr(self, key, [ v(_memo=memo_dict) for v in val ])
+ val = tryAsSimObjectOrVector(val)
+ if val is not None:
+ self._values[key] = val(_memo=memo_dict)
+
+ # Clone children specified at class level. No need for a
+ # multidict here since we will be cloning everything.
+ self._children = {}
+ for key,val in ancestor._children.iteritems():
+ self.add_child(key, val(_memo=memo_dict))
+
# clone port references. no need to use a multidict here
# since we will be creating new references for all ports.
self._port_refs = {}
@@ -527,6 +535,9 @@ class SimObject(object):
if self._values.has_key(attr):
return self._values[attr]
+ if self._children.has_key(attr):
+ return self._children[attr]
+
# If the attribute exists on the C++ object, transparently
# forward the reference there. This is typically used for
# SWIG-wrapped methods such as init(), regStats(),
@@ -556,7 +567,6 @@ class SimObject(object):
"cannot set SimObject parameter '%s' after\n" \
" instance been cloned %s" % (attr, `self`)
- # must be SimObject param
param = self._params.get(attr)
if param:
try:
@@ -566,11 +576,12 @@ class SimObject(object):
(e, self.__class__.__name__, attr, value)
e.args = (msg, )
raise
- self._set_child(attr, value)
+ self._values[attr] = value
return
+ # if RHS is a SimObject, it's an implicit child assignment
if isSimObjectOrSequence(value):
- self._set_child(attr, value)
+ self.add_child(attr, value)
return
# no valid assignment... raise exception
@@ -585,42 +596,57 @@ class SimObject(object):
return self
raise TypeError, "Non-zero index '%s' to SimObject" % key
- # clear out children with given name, even if it's a vector
- def clear_child(self, name):
- if not self._children.has_key(name):
- return
- child = self._children[name]
- if isinstance(child, SimObjVector):
- for i in xrange(len(child)):
- del self._children["s%d" % (name, i)]
- del self._children[name]
+ # Also implemented by SimObjectVector
+ def clear_parent(self, old_parent):
+ assert self._parent is old_parent
+ self._parent = None
- def add_child(self, name, value):
- self._children[name] = value
+ # Also implemented by SimObjectVector
+ def set_parent(self, parent, name):
+ self._parent = parent
+ self._name = name
- def _maybe_set_parent(self, parent, name):
- if not self._parent:
- self._parent = parent
- self._name = name
- parent.add_child(name, self)
+ # Also implemented by SimObjectVector
+ def get_name(self):
+ return self._name
- def _set_child(self, attr, value):
- # if RHS is a SimObject, it's an implicit child assignment
- # clear out old child with this name, if any
- self.clear_child(attr)
-
- if isSimObject(value):
- value._maybe_set_parent(self, attr)
- elif isSimObjectSequence(value):
- value = SimObjVector(value)
- if len(value) == 1:
- value[0]._maybe_set_parent(self, attr)
- else:
- width = int(math.ceil(math.log(len(value))/math.log(10)))
- for i,v in enumerate(value):
- v._maybe_set_parent(self, "%s%0*d" % (attr, width, i))
+ # use this rather than directly accessing _parent for symmetry
+ # with SimObjectVector
+ def get_parent(self):
+ return self._parent
- self._values[attr] = value
+ # clear out child with given name
+ def clear_child(self, name):
+ child = self._children[name]
+ child.clear_parent(self)
+ del self._children[name]
+
+ # Add a new child to this object.
+ def add_child(self, name, child):
+ child = coerceSimObjectOrVector(child)
+ if child.get_parent():
+ raise RuntimeError, \
+ "add_child('%s'): child '%s' already has parent '%s'" % \
+ (name, child._name, child._parent)
+ if self._children.has_key(name):
+ clear_child(name)
+ child.set_parent(self, name)
+ self._children[name] = child
+
+ # Take SimObject-valued parameters that haven't been explicitly
+ # assigned as children and make them children of the object that
+ # they were assigned to as a parameter value. This guarantees
+ # that when we instantiate all the parameter objects we're still
+ # inside the configuration hierarchy.
+ def adoptOrphanParams(self):
+ for key,val in self._values.iteritems():
+ if not isSimObjectVector(val) and isSimObjectSequence(val):
+ # need to convert raw SimObject sequences to
+ # SimObjectVector class so we can call get_parent()
+ val = SimObjectVector(val)
+ self._values[key] = val
+ if isSimObjectOrVector(val) and not val.get_parent():
+ self.add_child(key, val)
def path(self):
if not self._parent:
@@ -693,7 +719,8 @@ class SimObject(object):
child_names = self._children.keys()
child_names.sort()
if len(child_names):
- print >>ini_file, 'children=%s' % ' '.join(child_names)
+ print >>ini_file, 'children=%s' % \
+ ' '.join(self._children[n].get_name() for n in child_names)
param_names = self._params.keys()
param_names.sort()
@@ -856,6 +883,9 @@ def isSimObject(value):
def isSimObjectClass(value):
return issubclass(value, SimObject)
+def isSimObjectVector(value):
+ return isinstance(value, SimObjectVector)
+
def isSimObjectSequence(value):
if not isinstance(value, (list, tuple)) or len(value) == 0:
return False
@@ -873,6 +903,22 @@ def isRoot(obj):
from m5.objects import Root
return obj and obj is Root.getInstance()
+def isSimObjectOrVector(value):
+ return isSimObject(value) or isSimObjectVector(value)
+
+def tryAsSimObjectOrVector(value):
+ if isSimObjectOrVector(value):
+ return value
+ if isSimObjectSequence(value):
+ return SimObjectVector(value)
+ return None
+
+def coerceSimObjectOrVector(value):
+ value = tryAsSimObjectOrVector(value)
+ if value is None:
+ raise TypeError, "SimObject or SimObjectVector expected"
+ return value
+
baseClasses = allClasses.copy()
baseInstances = instanceDict.copy()
diff --git a/src/python/m5/params.py b/src/python/m5/params.py
index d9578e157..75dcf094a 100644
--- a/src/python/m5/params.py
+++ b/src/python/m5/params.py
@@ -49,6 +49,7 @@ import datetime
import re
import sys
import time
+import math
import proxy
import ticks
@@ -178,10 +179,42 @@ class VectorParamValue(list):
def unproxy(self, base):
return [v.unproxy(base) for v in self]
-class SimObjVector(VectorParamValue):
- def print_ini(self, ini_file):
+class SimObjectVector(VectorParamValue):
+ # support clone operation
+ def __call__(self, **kwargs):
+ return SimObjectVector([v(**kwargs) for v in self])
+
+ def clear_parent(self, old_parent):
+ for v in self:
+ v.clear_parent(old_parent)
+
+ def set_parent(self, parent, name):
+ if len(self) == 1:
+ self[0].set_parent(parent, name)
+ else:
+ width = int(math.ceil(math.log(len(self))/math.log(10)))
+ for i,v in enumerate(self):
+ v.set_parent(parent, "%s%0*d" % (name, width, i))
+
+ def get_parent(self):
+ parent_set = set(v._parent for v in self)
+ if len(parent_set) != 1:
+ raise RuntimeError, \
+ "SimObjectVector elements have inconsistent parent value."
+ return parent_set.pop()
+
+ # return 'cpu0 cpu1' etc. for print_ini()
+ def get_name(self):
+ return ' '.join([v._name for v in self])
+
+ # By iterating through the constituent members of the vector here
+ # we can nicely handle iterating over all a SimObject's children
+ # without having to provide lots of special functions on
+ # SimObjectVector directly.
+ def descendants(self):
for v in self:
- v.print_ini(ini_file)
+ for obj in v.descendants():
+ yield obj
class VectorParamDesc(ParamDesc):
file_ext = 'vptype'
@@ -197,7 +230,7 @@ class VectorParamDesc(ParamDesc):
tmp_list = [ ParamDesc.convert(self, value) ]
if isSimObjectSequence(tmp_list):
- return SimObjVector(tmp_list)
+ return SimObjectVector(tmp_list)
else:
return VectorParamValue(tmp_list)
diff --git a/src/python/m5/simulate.py b/src/python/m5/simulate.py
index 54c6a0a2d..28ba10c0d 100644
--- a/src/python/m5/simulate.py
+++ b/src/python/m5/simulate.py
@@ -55,6 +55,10 @@ def instantiate():
# we need to fix the global frequency
ticks.fixGlobalFrequency()
+ # Make sure SimObject-valued params are in the configuration
+ # hierarchy so we catch them with future descendants() walks
+ for obj in root.descendants(): obj.adoptOrphanParams()
+
# Unproxy in sorted order for determinism
for obj in root.descendants(): obj.unproxyParams()