Major changes to how SimObjects are created and initialized. Almost all
[gem5.git] / src / python / m5 / SimObject.py
index f87e13732eb2d5f5ce23a7272ea3d25ca9c79ca5..1e7d289e2d5e02f179b25a2aa01c6d5dbc0aa76f 100644 (file)
@@ -29,6 +29,8 @@
 
 import sys, types
 
+import proxy
+import m5
 from util import *
 from multidict import multidict
 
@@ -61,7 +63,7 @@ def isSimObjectOrSequence(value):
 from params import *
 # There are a few things we need that aren't in params.__all__ since
 # normal users don't need them
-from params import ParamDesc, isNullPointer, SimObjVector
+from params import ParamDesc, VectorParamDesc, isNullPointer, SimObjVector
 
 noDot = False
 try:
@@ -109,6 +111,9 @@ except:
 #
 #####################################################################
 
+# list of all SimObject classes
+allClasses = {}
+
 # dict to look up SimObjects based on path
 instanceDict = {}
 
@@ -119,12 +124,14 @@ instanceDict = {}
 class MetaSimObject(type):
     # Attributes that can be set only at initialization time
     init_keywords = { 'abstract' : types.BooleanType,
+                      'cxx_namespace' : types.StringType,
+                      'cxx_class' : types.StringType,
+                      'cxx_type' : types.StringType,
+                      'cxx_predecls' : types.ListType,
+                      'swig_predecls' : types.ListType,
                       'type' : types.StringType }
     # Attributes that can be set any time
-    keywords = { 'check' : types.FunctionType,
-                 'cxx_type' : types.StringType,
-                 'cxx_predecls' : types.ListType,
-                 'swig_predecls' : types.ListType }
+    keywords = { 'check' : types.FunctionType }
 
     # __new__ is called before __init__, and is where the statements
     # in the body of the class definition get loaded into the class's
@@ -132,6 +139,8 @@ class MetaSimObject(type):
     # and only allow "private" attributes to be passed to the base
     # __new__ (starting with underscore).
     def __new__(mcls, name, bases, dict):
+        assert name not in allClasses
+
         # Copy "private" attributes, functions, and classes to the
         # official dict.  Everything else goes in _init_dict to be
         # filtered in __init__.
@@ -144,8 +153,13 @@ class MetaSimObject(type):
             else:
                 # must be a param/port setting
                 value_dict[key] = val
+        if 'abstract' not in value_dict:
+            value_dict['abstract'] = False
         cls_dict['_value_dict'] = value_dict
-        return super(MetaSimObject, mcls).__new__(mcls, name, bases, cls_dict)
+        cls = super(MetaSimObject, mcls).__new__(mcls, name, bases, cls_dict)
+        if 'type' in value_dict:
+            allClasses[name] = cls
+        return cls
 
     # subclass initialization
     def __init__(cls, name, bases, dict):
@@ -183,6 +197,34 @@ class MetaSimObject(type):
             # mark base as having been subclassed
             base._instantiated = True
 
+        # default keyword values
+        if 'type' in cls._value_dict:
+            _type = cls._value_dict['type']
+            if 'cxx_class' not in cls._value_dict:
+                cls._value_dict['cxx_class'] = _type
+
+            namespace = cls._value_dict.get('cxx_namespace', None)
+
+            _cxx_class = cls._value_dict['cxx_class']
+            if 'cxx_type' not in cls._value_dict:
+                t = _cxx_class + '*'
+                if namespace:
+                    t = '%s::%s' % (namespace, t)
+                cls._value_dict['cxx_type'] = t
+            if 'cxx_predecls' not in cls._value_dict:
+                # A forward class declaration is sufficient since we are
+                # just declaring a pointer.
+                decl = 'class %s;' % _cxx_class
+                if namespace:
+                    decl = 'namespace %s { %s }' % (namespace, decl)
+                cls._value_dict['cxx_predecls'] = [decl]
+
+            if 'swig_predecls' not in cls._value_dict:
+                # A forward class declaration is sufficient since we are
+                # just declaring a pointer.
+                cls._value_dict['swig_predecls'] = \
+                    cls._value_dict['cxx_predecls']
+
         # Now process the _value_dict items.  They could be defining
         # new (or overriding existing) parameters or ports, setting
         # class keywords (e.g., 'abstract'), or setting parameter
@@ -207,12 +249,6 @@ class MetaSimObject(type):
             else:
                 setattr(cls, key, val)
 
-        cls.cxx_type = cls.type + '*'
-        # A forward class declaration is sufficient since we are just
-        # declaring a pointer.
-        cls.cxx_predecls = ['class %s;' % cls.type]
-        cls.swig_predecls = cls.cxx_predecls
-
     def _set_keyword(cls, keyword, val, kwtype):
         if not isinstance(val, kwtype):
             raise TypeError, 'keyword %s has bad type %s (expecting %s)' % \
@@ -310,18 +346,19 @@ class MetaSimObject(type):
         return cls.__name__
 
     def cxx_decl(cls):
-        code = "#ifndef __PARAMS__%s\n#define __PARAMS__%s\n\n" % (cls, cls)
-
         if str(cls) != 'SimObject':
             base = cls.__bases__[0].type
         else:
             base = None
 
+        code = "#ifndef __PARAMS__%s\n" % cls
+        code += "#define __PARAMS__%s\n\n" % cls
+
         # The 'dict' attribute restricts us to the params declared in
         # the object itself, not including inherited params (which
         # will also be inherited from the base class's param struct
         # here).
-        params = cls._params.dict.values()
+        params = cls._params.local.values()
         try:
             ptypes = [p.ptype for p in params]
         except:
@@ -330,9 +367,10 @@ class MetaSimObject(type):
             raise
 
         # get a list of lists of predeclaration lines
-        predecls = [p.cxx_predecls() for p in params]
-        # flatten
-        predecls = reduce(lambda x,y:x+y, predecls, [])
+        predecls = []
+        predecls.extend(cls.cxx_predecls)
+        for p in params:
+            predecls.extend(p.cxx_predecls())
         # remove redundant lines
         predecls2 = []
         for pd in predecls:
@@ -345,17 +383,21 @@ class MetaSimObject(type):
         if base:
             code += '#include "params/%s.hh"\n\n' % base
 
-        # Generate declarations for locally defined enumerations.
-        enum_ptypes = [t for t in ptypes if issubclass(t, Enum)]
-        if enum_ptypes:
-            code += "\n".join([t.cxx_decl() for t in enum_ptypes])
-            code += "\n\n"
+        for ptype in ptypes:
+            if issubclass(ptype, Enum):
+                code += '#include "enums/%s.hh"\n' % ptype.__name__
+                code += "\n\n"
 
         # now generate the actual param struct
         code += "struct %sParams" % cls
         if base:
             code += " : public %sParams" % base
-        code += " {\n"
+        code += "\n{\n"
+        if cls == SimObject:
+            code += "    virtual ~%sParams() {}\n" % cls
+        if not hasattr(cls, 'abstract') or not cls.abstract:
+            if 'type' in cls.__dict__:
+                code += "    %s create();\n" % cls.cxx_type
         decls = [p.cxx_decl() for p in params]
         decls.sort()
         code += "".join(["    %s\n" % d for d in decls])
@@ -365,12 +407,34 @@ class MetaSimObject(type):
         code += "\n#endif\n"
         return code
 
+    def cxx_type_decl(cls):
+        if str(cls) != 'SimObject':
+            base = cls.__bases__[0]
+        else:
+            base = None
+
+        code = ''
+
+        if base:
+            code += '#include "%s_type.h"\n' % base
+
+        # now generate dummy code for inheritance
+        code += "struct %s" % cls.cxx_class
+        if base:
+            code += " : public %s" % base.cxx_class
+        code += "\n{};\n"
+
+        return code
+
     def swig_decl(cls):
+        code = '%%module %s\n' % cls
 
-        code = '%%module %sParams\n' % cls
+        code += '%{\n'
+        code += '#include "params/%s.hh"\n' % cls
+        code += '%}\n\n'
 
         if str(cls) != 'SimObject':
-            base = cls.__bases__[0].type
+            base = cls.__bases__[0]
         else:
             base = None
 
@@ -378,11 +442,12 @@ class MetaSimObject(type):
         # the object itself, not including inherited params (which
         # will also be inherited from the base class's param struct
         # here).
-        params = cls._params.dict.values()
+        params = cls._params.local.values()
         ptypes = [p.ptype for p in params]
 
         # get a list of lists of predeclaration lines
-        predecls = [p.swig_predecls() for p in params]
+        predecls = []
+        predecls.extend([ p.swig_predecls() for p in params ])
         # flatten
         predecls = reduce(lambda x,y:x+y, predecls, [])
         # remove redundant lines
@@ -395,11 +460,14 @@ class MetaSimObject(type):
         code += "\n\n";
 
         if base:
-            code += '%%import "python/m5/swig/%sParams.i"\n\n' % base
+            code += '%%import "params/%s.i"\n\n' % base
 
-        code += '%{\n'
-        code += '#include "params/%s.hh"\n' % cls
-        code += '%}\n\n'
+        for ptype in ptypes:
+            if issubclass(ptype, Enum):
+                code += '%%import "enums/%s.hh"\n' % ptype.__name__
+                code += "\n\n"
+
+        code += '%%import "params/%s_type.hh"\n\n' % cls
         code += '%%include "params/%s.hh"\n\n' % cls
 
         return code
@@ -412,6 +480,7 @@ class SimObject(object):
     # get this metaclass.
     __metaclass__ = MetaSimObject
     type = 'SimObject'
+    abstract = True
 
     name = Param.String("Object name")
 
@@ -440,6 +509,7 @@ class SimObject(object):
         self._parent = None
         self._children = {}
         self._ccObject = None  # pointer to C++ object
+        self._ccParams = None
         self._instantiated = False # really "cloned"
 
         # Inherit parameter values from class using multidict so
@@ -577,8 +647,11 @@ class SimObject(object):
             value._maybe_set_parent(self, attr)
         elif isSimObjectSequence(value):
             value = SimObjVector(value)
-            [v._maybe_set_parent(self, "%s%d" % (attr, i))
-             for i,v in enumerate(value)]
+            if len(value) == 1:
+                value[0]._maybe_set_parent(self, attr)
+            else:
+                for i,v in enumerate(value):
+                    v._maybe_set_parent(self, "%s%d" % (attr, i))
 
         self._values[attr] = value
 
@@ -680,25 +753,66 @@ class SimObject(object):
         for child in child_names:
             self._children[child].print_ini()
 
-    # Call C++ to create C++ object corresponding to this object and
-    # (recursively) all its children
-    def createCCObject(self):
-        self.getCCObject() # force creation
-        for child in self._children.itervalues():
-            child.createCCObject()
+    def getCCParams(self):
+        if self._ccParams:
+            return self._ccParams
+
+        cc_params_struct = eval('m5.objects.params.%sParams' % self.type)
+        cc_params = cc_params_struct()
+        cc_params.object = self
+        cc_params.name = str(self)
+
+        param_names = self._params.keys()
+        param_names.sort()
+        for param in param_names:
+            value = self._values.get(param)
+            if value is None:
+                continue
+
+            value = value.getValue()
+            if isinstance(self._params[param], VectorParamDesc):
+                assert isinstance(value, list)
+                vec = getattr(cc_params, param)
+                assert not len(vec)
+                for v in value:
+                    vec.append(v)
+            else:
+                setattr(cc_params, param, value)
+
+        port_names = self._ports.keys()
+        port_names.sort()
+        for port_name in port_names:
+            port = self._port_refs.get(port_name, None)
+            if port != None:
+                setattr(cc_params, port_name, port)
+        self._ccParams = cc_params
+        return self._ccParams
 
     # Get C++ object corresponding to this object, calling C++ if
     # necessary to construct it.  Does *not* recursively create
     # children.
     def getCCObject(self):
+        import internal
+        params = self.getCCParams()
         if not self._ccObject:
             self._ccObject = -1 # flag to catch cycles in recursion
-            self._ccObject = internal.sim_object.createSimObject(self.path())
+            self._ccObject = params.create()
         elif self._ccObject == -1:
             raise RuntimeError, "%s: recursive call to getCCObject()" \
                   % self.path()
         return self._ccObject
 
+    # Call C++ to create C++ object corresponding to this object and
+    # (recursively) all its children
+    def createCCObject(self):
+        self.getCCParams()
+        self.getCCObject() # force creation
+        for child in self._children.itervalues():
+            child.createCCObject()
+
+    def getValue(self):
+        return self.getCCObject()
+
     # Create C++ port connections corresponding to the connections in
     # _port_refs (& recursively for all children)
     def connectPorts(self):
@@ -730,6 +844,7 @@ class SimObject(object):
         return system_ptr.getMemoryMode()
 
     def changeTiming(self, mode):
+        import internal
         if isinstance(self, m5.objects.System):
             # i don't know if there's a better way to do this - calling
             # setMemoryMode directly from self._ccObject results in calling
@@ -740,6 +855,7 @@ class SimObject(object):
             child.changeTiming(mode)
 
     def takeOverFrom(self, old_cpu):
+        import internal
         cpu_ptr = internal.sim_object.convertToBaseCPUPtr(old_cpu._ccObject)
         self._ccObject.takeOverFrom(cpu_ptr)
 
@@ -794,9 +910,4 @@ def resolveSimObject(name):
 # __all__ defines the list of symbols that get exported when
 # 'from config import *' is invoked.  Try to keep this reasonably
 # short to avoid polluting other namespaces.
-__all__ = ['SimObject']
-
-# see comment on imports at end of __init__.py.
-import proxy
-import internal
-import m5
+__all__ = [ 'SimObject' ]