Merge zizzer:/bk/m5 into zed.eecs.umich.edu:/z/hsul/work/m5/pact05
[gem5.git] / python / m5 / config.py
index 74022059f1e94ea6630f26edb6d3a4a63499d866..64ec994906ee3a5b12062017e18695aac078a55c 100644 (file)
@@ -27,7 +27,7 @@
 from __future__ import generators
 import os, re, sys, types, inspect
 
-from smartdict import SmartDict
+from m5 import panic
 from convert import *
 
 noDot = False
@@ -36,16 +36,6 @@ try:
 except:
     noDot = True
 
-env = SmartDict()
-env.update(os.environ)
-
-def panic(string):
-    print >>sys.stderr, 'panic:', string
-    sys.exit(1)
-
-def issequence(value):
-    return isinstance(value, tuple) or isinstance(value, list)
-
 class Singleton(type):
     def __call__(cls, *args, **kwargs):
         if hasattr(cls, '_instance'):
@@ -150,25 +140,91 @@ class Singleton(type):
 #####################################################################
 
 class Proxy(object):
-    def __init__(self, path = ()):
+    def __init__(self, path):
         self._object = None
-        self._path = path
+        if path == 'any':
+            self._path = None
+        else:
+            # path is a list of (attr,index) tuples
+            self._path = [(path,None)]
+        self._index = None
+        self._multiplier = None
 
     def __getattr__(self, attr):
-        return Proxy(self._path + (attr, ))
+        if attr == '__bases__':
+            return super(Proxy, self).__getattr__(self, attr)
+        self._path.append((attr,None))
+        return self
 
     def __setattr__(self, attr, value):
         if not attr.startswith('_'):
             raise AttributeError, 'cannot set attribute %s' % attr
         super(Proxy, self).__setattr__(attr, value)
 
-    def _convert(self):
-        obj = self._object
-        for attr in self._path:
-            obj = obj.__getattribute__(attr)
+    # support indexing on proxies (e.g., parent.cpu[0])
+    def __getitem__(self, key):
+        if not isinstance(key, int):
+            raise TypeError, "Proxy object requires integer index"
+        if self._path == None:
+            raise IndexError, "Index applied to 'any' proxy"
+        # replace index portion of last path element with new index
+        self._path[-1] = (self._path[-1][0], key)
+        return self
+
+    # support multiplying proxies by constants
+    def __mul__(self, other):
+        if not isinstance(other, int):
+            raise TypeError, "Proxy multiplier must be integer"
+        if self._multiplier == None:
+            self._multiplier = other
+        else:
+            # support chained multipliers
+            self._multiplier *= other
+        return self
+
+    def _mulcheck(self, result):
+        if self._multiplier == None:
+            return result
+        if not isinstance(result, int):
+            raise TypeError, "Proxy with multiplier resolves to " \
+                  "non-integer value"
+        return result * self._multiplier
+
+    def unproxy(self, base, ptype):
+        obj = base
+        done = False
+        while not done:
+            if obj is None:
+                raise AttributeError, \
+                      'Parent of %s type %s not found at path %s' \
+                      % (base.name, ptype, self._path)
+            result, done = obj.find(ptype, self._path)
+            obj = obj.parent
+
+        if isinstance(result, Proxy):
+            result = result.unproxy(obj, ptype)
+
+        return self._mulcheck(result)
+
+    def getindex(obj, index):
+        if index == None:
+            return obj
+        try:
+            obj = obj[index]
+        except TypeError:
+            if index != 0:
+                raise
+            # if index is 0 and item is not subscriptable, just
+            # use item itself (so cpu[0] works on uniprocessors)
         return obj
+    getindex = staticmethod(getindex)
 
-Super = Proxy()
+class ProxyFactory(object):
+    def __getattr__(self, attr):
+        return Proxy(attr)
+
+# global object for handling parent.foo proxies
+parent = ProxyFactory()
 
 def isSubClass(value, cls):
     try:
@@ -189,7 +245,7 @@ def isSimObject(value):
         return False
 
 def isSimObjSequence(value):
-    if not issequence(value):
+    if not isinstance(value, (list, tuple)):
         return False
 
     for val in value:
@@ -463,7 +519,7 @@ class MetaConfigNode(type):
         if isNullPointer(child) or instance.top_child_names.has_key(name):
             return
 
-        if issequence(child):
+        if isinstance(child, (list, tuple)):
             kid = []
             for i,c in enumerate(child):
                 n = '%s%d' % (name, i)
@@ -491,10 +547,10 @@ class MetaConfigNode(type):
         for key,value in cls._getvalues().iteritems():
             if isConfigNode(value):
                 cls.add_child(instance, key, value)
-            if issequence(value):
-                list = [ v for v in value if isConfigNode(v) ]
-                if len(list):
-                    cls.add_child(instance, key, list)
+            if isinstance(value, (list, tuple)):
+                vals = [ v for v in value if isConfigNode(v) ]
+                if len(vals):
+                    cls.add_child(instance, key, vals)
 
         for pname,param in cls._getparams().iteritems():
             try:
@@ -505,7 +561,7 @@ class MetaConfigNode(type):
             try:
                 if isConfigNode(value):
                     value = instance.child_objects[value]
-                elif issequence(value):
+                elif isinstance(value, (list, tuple)):
                     v = []
                     for val in value:
                         if isConfigNode(val):
@@ -654,50 +710,40 @@ class Node(object):
                 if issubclass(child.realtype, realtype):
                     if obj is not None:
                         raise AttributeError, \
-                              'Super matched more than one: %s %s' % \
+                              'parent.any matched more than one: %s %s' % \
                               (obj.path, child.path)
                     obj = child
             return obj, obj is not None
 
         try:
             obj = self
-            for node in path[:-1]:
-                obj = obj.child_names[node]
+            for (node,index) in path[:-1]:
+                if obj.child_names.has_key(node):
+                    obj = obj.child_names[node]
+                else:
+                    obj = obj.top_child_names[node]
+                obj = Proxy.getindex(obj, index)
 
-            last = path[-1]
+            (last,index) = path[-1]
             if obj.child_names.has_key(last):
                 value = obj.child_names[last]
-                if issubclass(value.realtype, realtype):
-                    return value, True
+                return Proxy.getindex(value, index), True
+            elif obj.top_child_names.has_key(last):
+                value = obj.top_child_names[last]
+                return Proxy.getindex(value, index), True
             elif obj.param_names.has_key(last):
                 value = obj.param_names[last]
                 realtype._convert(value.value)
-                return value.value, True
+                return Proxy.getindex(value.value, index), True
         except KeyError:
             pass
 
         return None, False
 
-    def unproxy(self, ptype, value):
-        if not isinstance(value, Proxy):
-            return value
-
-        if value is None:
-            raise AttributeError, 'Error while fixing up %s' % self.path
-
-        obj = self
-        done = False
-        while not done:
-            if obj is None:
-                raise AttributeError, \
-                      'Parent of %s type %s not found at path %s' \
-                      % (self.name, ptype, value._path)
-            found, done = obj.find(ptype, value._path)
-            if isinstance(found, Proxy):
-                done = False
-            obj = obj.parent
-
-        return found
+    def unproxy(self, param, ptype):
+        if not isinstance(param, Proxy):
+            return param
+        return param.unproxy(self, ptype)
 
     def fixup(self):
         self.all[self.path] = self
@@ -707,10 +753,10 @@ class Node(object):
             pval = param.value
 
             try:
-                if issequence(pval):
-                    param.value = [ self.unproxy(ptype, pv) for pv in pval ]
+                if isinstance(pval, (list, tuple)):
+                    param.value = [ self.unproxy(pv, ptype) for pv in pval ]
                 else:
-                    param.value = self.unproxy(ptype, pval)
+                    param.value = self.unproxy(pval, ptype)
             except:
                 print 'Error while fixing up %s:%s' % (self.path, param.name)
                 raise
@@ -851,6 +897,9 @@ class Value(object):
     def __str__(self):
         return str(self._getattr())
 
+    def __len__(self):
+        return len(self._getattr())
+
 # Regular parameter.
 class _Param(object):
     def __init__(self, ptype, *args, **kwargs):
@@ -960,7 +1009,7 @@ class _VectorParam(_Param):
         if value == None:
             return True
 
-        if issequence(value):
+        if isinstance(value, (list, tuple)):
             for val in value:
                 if not isinstance(val, Proxy):
                     self.ptype._convert(val)
@@ -973,7 +1022,7 @@ class _VectorParam(_Param):
         if value == None:
             return []
 
-        if issequence(value):
+        if isinstance(value, (list, tuple)):
             # list: coerce each element into new list
             return [ self.ptype._convert(v) for v in value ]
         else:
@@ -981,7 +1030,7 @@ class _VectorParam(_Param):
             return self.ptype._convert(value)
 
     def string(self, value):
-        if issequence(value):
+        if isinstance(value, (list, tuple)):
             return ' '.join([ self.ptype._string(v) for v in value])
         else:
             return self.ptype._string(value)
@@ -1347,9 +1396,8 @@ class SimObject(ConfigNode, ParamType):
 # __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__ = ['env', 'issequence',
-           'ConfigNode', 'SimObject', 'ParamContext', 'Param', 'VectorParam',
-           'Super', 'Enum',
+__all__ = ['ConfigNode', 'SimObject', 'ParamContext', 'Param', 'VectorParam',
+           'parent', 'Enum',
            'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
            'Int32', 'UInt32', 'Int64', 'UInt64',
            'Counter', 'Addr', 'Tick', 'Percent',