params: Fix floating point parameters
[gem5.git] / src / python / m5 / SimObject.py
index a0d66e6438eee0e6277e6478274a3d808fd3bd41..41ed3df9e9e190a83a13f9c958caf7f2f527c55c 100644 (file)
@@ -29,8 +29,9 @@
 
 import sys, types
 
+import proxy
+import m5
 from util import *
-from multidict import multidict
 
 # These utility functions have to come first because they're
 # referenced in params.py... otherwise they won't be defined when we
@@ -61,7 +62,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 +110,9 @@ except:
 #
 #####################################################################
 
+# list of all SimObject classes
+allClasses = {}
+
 # dict to look up SimObjects based on path
 instanceDict = {}
 
@@ -119,12 +123,15 @@ 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_objdecls' : 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,40 @@ 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:
+                    namespaces = namespace.split('::')
+                    namespaces.reverse()
+                    for namespace in namespaces:
+                        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']
+
+        if 'swig_objdecls' not in cls._value_dict:
+            cls._value_dict['swig_objdecls'] = []
+
         # 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 +255,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)' % \
@@ -309,19 +351,21 @@ class MetaSimObject(type):
     def __str__(cls):
         return cls.__name__
 
-    def cxx_decl(cls):
-        code = "#ifndef __PARAMS__%s\n#define __PARAMS__%s\n\n" % (cls, cls)
+    def get_base(cls):
+        if str(cls) == 'SimObject':
+            return None
 
-        if str(cls) != 'SimObject':
-            base = cls.__bases__[0].type
-        else:
-            base = None
+        return  cls.__bases__[0].type
+
+    def cxx_decl(cls):
+        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 +374,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:
@@ -342,20 +387,25 @@ class MetaSimObject(type):
         code += "\n".join(predecls2)
         code += "\n\n";
 
+        base = cls.get_base()
         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,24 +415,40 @@ class MetaSimObject(type):
         code += "\n#endif\n"
         return code
 
+    def cxx_type_decl(cls):
+        base = cls.get_base()
+        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):
+        base = cls.get_base()
 
-        code = '%%module %sParams\n' % cls
+        code = '%%module %s\n' % cls
 
-        if str(cls) != 'SimObject':
-            base = cls.__bases__[0].type
-        else:
-            base = None
+        code += '%{\n'
+        code += '#include "params/%s.hh"\n' % cls
+        code += '%}\n\n'
 
         # 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()
         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 +461,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,8 +481,10 @@ class SimObject(object):
     # get this metaclass.
     __metaclass__ = MetaSimObject
     type = 'SimObject'
+    abstract = True
 
     name = Param.String("Object name")
+    swig_objdecls = [ '%include "python/swig/sim_object.i"' ]
 
     # Initialize new instance.  For objects with SimObject-valued
     # children, we need to recursively clone the classes represented
@@ -440,6 +511,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 +649,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
 
@@ -648,59 +723,100 @@ class SimObject(object):
         for child in child_names:
             self._children[child].unproxy_all()
 
-    def print_ini(self):
-        print '[' + self.path() + ']'  # .ini section header
+    def print_ini(self, ini_file):
+        print >>ini_file, '[' + self.path() + ']'      # .ini section header
 
         instanceDict[self.path()] = self
 
-        if hasattr(self, 'type') and not isinstance(self, ParamContext):
-            print 'type=%s' % self.type
+        if hasattr(self, 'type'):
+            print >>ini_file, 'type=%s' % self.type
 
         child_names = self._children.keys()
         child_names.sort()
-        np_child_names = [c for c in child_names \
-                          if not isinstance(self._children[c], ParamContext)]
-        if len(np_child_names):
-            print 'children=%s' % ' '.join(np_child_names)
+        if len(child_names):
+            print >>ini_file, 'children=%s' % ' '.join(child_names)
 
         param_names = self._params.keys()
         param_names.sort()
         for param in param_names:
             value = self._values.get(param)
             if value != None:
-                print '%s=%s' % (param, self._values[param].ini_str())
+                print >>ini_file, '%s=%s' % (param,
+                                             self._values[param].ini_str())
 
         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:
-                print '%s=%s' % (port_name, port.ini_str())
+                print >>ini_file, '%s=%s' % (port_name, port.ini_str())
 
-        print  # blank line between objects
+        print >>ini_file       # blank line between objects
 
         for child in child_names:
-            self._children[child].print_ini()
+            self._children[child].print_ini(ini_file)
 
-    # 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 = getattr(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):
         if not self._ccObject:
-            self._ccObject = -1 # flag to catch cycles in recursion
-            self._ccObject = cc_main.createSimObject(self.path())
+            # Cycles in the configuration heirarchy are not supported. This
+            # will catch the resulting recursion and stop.
+            self._ccObject = -1
+            params = self.getCCParams()
+            self._ccObject = params.create()
         elif self._ccObject == -1:
-            raise RuntimeError, "%s: recursive call to getCCObject()" \
+            raise RuntimeError, "%s: Cycle found in configuration heirarchy." \
                   % 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):
@@ -711,8 +827,7 @@ class SimObject(object):
 
     def startDrain(self, drain_event, recursive):
         count = 0
-        # ParamContexts don't serialize
-        if isinstance(self, SimObject) and not isinstance(self, ParamContext):
+        if isinstance(self, SimObject):
             count += self._ccObject.drain(drain_event)
         if recursive:
             for child in self._children.itervalues():
@@ -720,20 +835,28 @@ class SimObject(object):
         return count
 
     def resume(self):
-        if isinstance(self, SimObject) and not isinstance(self, ParamContext):
+        if isinstance(self, SimObject):
             self._ccObject.resume()
         for child in self._children.itervalues():
             child.resume()
 
+    def getMemoryMode(self):
+        if not isinstance(self, m5.objects.System):
+            return None
+
+        return self._ccObject.getMemoryMode()
+
     def changeTiming(self, mode):
-        if isinstance(self, System):
+        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
+            # SimObject::setMemoryMode, not the System::setMemoryMode
             self._ccObject.setMemoryMode(mode)
         for child in self._children.itervalues():
             child.changeTiming(mode)
 
     def takeOverFrom(self, old_cpu):
-        cpu_ptr = cc_main.convertToBaseCPUPtr(old_cpu._ccObject)
-        self._ccObject.takeOverFrom(cpu_ptr)
+        self._ccObject.takeOverFrom(old_cpu._ccObject)
 
     # generate output file for 'dot' to display as a pretty graph.
     # this code is currently broken.
@@ -778,9 +901,6 @@ class SimObject(object):
         for c in self.children:
             c.outputDot(dot)
 
-class ParamContext(SimObject):
-    pass
-
 # Function to provide to C++ so it can look up instances based on paths
 def resolveSimObject(name):
     obj = instanceDict[name]
@@ -789,10 +909,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', 'ParamContext']
-
-
-# see comment on imports at end of __init__.py.
-import proxy
-import cc_main
-import m5
+__all__ = [ 'SimObject' ]