stats: Add support for listing available formats
[gem5.git] / src / python / m5 / params.py
index 0f7d6e091f730f21c4d04fe3fc22448c82fce474..b9afff2a1dccf4e1e1904949a298472ad7b74e95 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (c) 2012-2014, 2017 ARM Limited
+# Copyright (c) 2012-2014, 2017-2019 ARM Limited
 # All rights reserved.
 #
 # The license below extends only to copyright in the software and shall
 #
 #####################################################################
 
+from __future__ import print_function
+import six
+if six.PY3:
+    long = int
+
 import copy
 import datetime
 import re
@@ -66,17 +71,20 @@ import sys
 import time
 import math
 
-import proxy
-import ticks
-from util import *
+from . import proxy
+from . import ticks
+from .util import *
 
 def isSimObject(*args, **kwargs):
+    from . import SimObject
     return SimObject.isSimObject(*args, **kwargs)
 
 def isSimObjectSequence(*args, **kwargs):
+    from . import SimObject
     return SimObject.isSimObjectSequence(*args, **kwargs)
 
 def isSimObjectClass(*args, **kwargs):
+    from . import SimObject
     return SimObject.isSimObjectClass(*args, **kwargs)
 
 allParams = {}
@@ -153,33 +161,34 @@ class ParamDesc(object):
                 self.default = args[0]
                 self.desc = args[1]
             else:
-                raise TypeError, 'too many arguments'
+                raise TypeError('too many arguments')
 
-        if kwargs.has_key('desc'):
+        if 'desc' in kwargs:
             assert(not hasattr(self, 'desc'))
             self.desc = kwargs['desc']
             del kwargs['desc']
 
-        if kwargs.has_key('default'):
+        if 'default' in kwargs:
             assert(not hasattr(self, 'default'))
             self.default = kwargs['default']
             del kwargs['default']
 
         if kwargs:
-            raise TypeError, 'extra unknown kwargs %s' % kwargs
+            raise TypeError('extra unknown kwargs %s' % kwargs)
 
         if not hasattr(self, 'desc'):
-            raise TypeError, 'desc attribute missing'
+            raise TypeError('desc attribute missing')
 
     def __getattr__(self, attr):
         if attr == 'ptype':
+            from . import SimObject
             ptype = SimObject.allClasses[self.ptype_str]
             assert isSimObjectClass(ptype)
             self.ptype = ptype
             return ptype
 
-        raise AttributeError"'%s' object has no attribute '%s'" % \
-              (type(self).__name__, attr)
+        raise AttributeError("'%s' object has no attribute '%s'" % \
+              (type(self).__name__, attr))
 
     def example_str(self):
         if hasattr(self.ptype, "ex_str"):
@@ -198,7 +207,7 @@ class ParamDesc(object):
         if isinstance(value, proxy.BaseProxy):
             value.set_param_desc(self)
             return value
-        if not hasattr(self, 'ptype') and isNullPointer(value):
+        if 'ptype' not in self.__dict__ and isNullPointer(value):
             # deferred evaluation of SimObject; continue to defer if
             # we're just assigning a null pointer
             return value
@@ -232,8 +241,8 @@ class ParamDesc(object):
 class VectorParamValue(list):
     __metaclass__ = MetaParamValue
     def __setattr__(self, attr, value):
-        raise AttributeError, \
-              "Not allowed to set %s on '%s'" % (attr, type(self).__name__)
+        raise AttributeError("Not allowed to set %s on '%s'" % \
+                             (attr, type(self).__name__))
 
     def config_value(self):
         return [v.config_value() for v in self]
@@ -311,7 +320,7 @@ class SimObjectVector(VectorParamValue):
                         cmd_line_str = "",
                         access_str = ""):
         if hasattr(self, "_paramEnumed"):
-            print "Cycle detected enumerating params at %s?!" % (cmd_line_str)
+            print("Cycle detected enumerating params at %s?!" % (cmd_line_str))
         else:
             x = 0
             for vals in self:
@@ -452,6 +461,10 @@ class String(ParamValue,str):
 # operations in a type-safe way.  e.g., a Latency times an int returns
 # a new Latency object.
 class NumericParamValue(ParamValue):
+    @staticmethod
+    def unwrap(v):
+        return v.value if isinstance(v, NumericParamValue) else v
+
     def __str__(self):
         return str(self.value)
 
@@ -470,24 +483,70 @@ class NumericParamValue(ParamValue):
 
     def __mul__(self, other):
         newobj = self.__class__(self)
-        newobj.value *= other
+        newobj.value *= NumericParamValue.unwrap(other)
         newobj._check()
         return newobj
 
     __rmul__ = __mul__
 
-    def __div__(self, other):
+    def __truediv__(self, other):
+        newobj = self.__class__(self)
+        newobj.value /= NumericParamValue.unwrap(other)
+        newobj._check()
+        return newobj
+
+    def __floordiv__(self, other):
+        newobj = self.__class__(self)
+        newobj.value //= NumericParamValue.unwrap(other)
+        newobj._check()
+        return newobj
+
+
+    def __add__(self, other):
         newobj = self.__class__(self)
-        newobj.value /= other
+        newobj.value += NumericParamValue.unwrap(other)
         newobj._check()
         return newobj
 
     def __sub__(self, other):
         newobj = self.__class__(self)
-        newobj.value -= other
+        newobj.value -= NumericParamValue.unwrap(other)
         newobj._check()
         return newobj
 
+    def __iadd__(self, other):
+        self.value += NumericParamValue.unwrap(other)
+        self._check()
+        return self
+
+    def __isub__(self, other):
+        self.value -= NumericParamValue.unwrap(other)
+        self._check()
+        return self
+
+    def __imul__(self, other):
+        self.value *= NumericParamValue.unwrap(other)
+        self._check()
+        return self
+
+    def __itruediv__(self, other):
+        self.value /= NumericParamValue.unwrap(other)
+        self._check()
+        return self
+
+    def __ifloordiv__(self, other):
+        self.value //= NumericParamValue.unwrap(other)
+        self._check()
+        return self
+
+    def __lt__(self, other):
+        return self.value < NumericParamValue.unwrap(other)
+
+    # Python 2.7 pre __future__.division operators
+    # TODO: Remove these when after "import division from __future__"
+    __div__ =  __truediv__
+    __idiv__ = __itruediv__
+
     def config_value(self):
         return self.value
 
@@ -537,8 +596,8 @@ class CheckedInt(NumericParamValue):
 
     def _check(self):
         if not self.min <= self.value <= self.max:
-            raise TypeError'Integer param out of bounds %d < %d < %d' % \
-                  (self.min, self.value, self.max)
+            raise TypeError('Integer param out of bounds %d < %d < %d' % \
+                  (self.min, self.value, self.max))
 
     def __init__(self, value):
         if isinstance(value, str):
@@ -546,14 +605,17 @@ class CheckedInt(NumericParamValue):
         elif isinstance(value, (int, long, float, NumericParamValue)):
             self.value = long(value)
         else:
-            raise TypeError"Can't convert object of type %s to CheckedInt" \
-                  % type(value).__name__
+            raise TypeError("Can't convert object of type %s to CheckedInt" \
+                  % type(value).__name__)
         self._check()
 
     def __call__(self, value):
         self.__init__(value)
         return value
 
+    def __index__(self):
+        return int(self.value)
+
     @classmethod
     def cxx_predecls(cls, code):
         # most derived types require this, so we just do it here once
@@ -612,8 +674,8 @@ class Float(ParamValue, float):
         if isinstance(value, (int, long, float, NumericParamValue, Float, str)):
             self.value = float(value)
         else:
-            raise TypeError"Can't convert object of type %s to Float" \
-                  % type(value).__name__
+            raise TypeError("Can't convert object of type %s to Float" \
+                  % type(value).__name__)
 
     def __call__(self, value):
         self.__init__(value)
@@ -695,10 +757,9 @@ class AddrRange(ParamValue):
 
     def __init__(self, *args, **kwargs):
         # Disable interleaving and hashing by default
-        self.intlvHighBit = 0
-        self.xorHighBit = 0
         self.intlvBits = 0
         self.intlvMatch = 0
+        self.masks = []
 
         def handle_kwargs(self, kwargs):
             # An address range needs to have an upper limit, specified
@@ -709,18 +770,33 @@ class AddrRange(ParamValue):
             elif 'size' in kwargs:
                 self.end = self.start + Addr(kwargs.pop('size')) - 1
             else:
-                raise TypeError, "Either end or size must be specified"
+                raise TypeError("Either end or size must be specified")
 
             # Now on to the optional bit
-            if 'intlvHighBit' in kwargs:
-                self.intlvHighBit = int(kwargs.pop('intlvHighBit'))
-            if 'xorHighBit' in kwargs:
-                self.xorHighBit = int(kwargs.pop('xorHighBit'))
-            if 'intlvBits' in kwargs:
-                self.intlvBits = int(kwargs.pop('intlvBits'))
             if 'intlvMatch' in kwargs:
                 self.intlvMatch = int(kwargs.pop('intlvMatch'))
 
+            if 'masks' in kwargs:
+                self.masks = [ long(x) for x in list(kwargs.pop('masks')) ]
+                self.intlvBits = len(self.masks)
+            else:
+                if 'intlvBits' in kwargs:
+                    self.intlvBits = int(kwargs.pop('intlvBits'))
+                    self.masks = [0] * self.intlvBits
+                    if 'intlvHighBit' not in kwargs:
+                        raise TypeError("No interleave bits specified")
+                    intlv_high_bit = int(kwargs.pop('intlvHighBit'))
+                    xor_high_bit = 0
+                    if 'xorHighBit' in kwargs:
+                        xor_high_bit = int(kwargs.pop('xorHighBit'))
+                    for i in range(0, self.intlvBits):
+                        bit1 = intlv_high_bit - i
+                        mask = 1 << bit1
+                        if xor_high_bit != 0:
+                            bit2 = xor_high_bit - i
+                            mask |= 1 << bit2
+                        self.masks[self.intlvBits - i - 1] = mask
+
         if len(args) == 0:
             self.start = Addr(kwargs.pop('start'))
             handle_kwargs(self, kwargs)
@@ -740,15 +816,17 @@ class AddrRange(ParamValue):
             self.start = Addr(args[0])
             self.end = Addr(args[1])
         else:
-            raise TypeError, "Too many arguments specified"
+            raise TypeError("Too many arguments specified")
 
         if kwargs:
-            raise TypeError, "Too many keywords: %s" % kwargs.keys()
+            raise TypeError("Too many keywords: %s" % list(kwargs.keys()))
 
     def __str__(self):
-        return '%s:%s:%s:%s:%s:%s' \
-            % (self.start, self.end, self.intlvHighBit, self.xorHighBit,\
-               self.intlvBits, self.intlvMatch)
+        if len(self.masks) == 0:
+            return '%s:%s' % (self.start, self.end)
+        else:
+            return '%s:%s:%s:%s' % (self.start, self.end, self.intlvMatch,
+                                    ':'.join(str(m) for m in self.masks))
 
     def size(self):
         # Divide the size by the size of the interleaving slice
@@ -767,31 +845,35 @@ class AddrRange(ParamValue):
     @classmethod
     def cxx_ini_predecls(cls, code):
         code('#include <sstream>')
+        code('#include <vector>')
+        code('#include "base/types.hh"')
 
     @classmethod
     def cxx_ini_parse(cls, code, src, dest, ret):
-        code('uint64_t _start, _end, _intlvHighBit = 0, _xorHighBit = 0;')
-        code('uint64_t _intlvBits = 0, _intlvMatch = 0;')
+        code('bool _ret = true;')
+        code('uint64_t _start, _end, _intlvMatch = 0;')
+        code('std::vector<Addr> _masks;')
         code('char _sep;')
         code('std::istringstream _stream(${src});')
         code('_stream >> _start;')
         code('_stream.get(_sep);')
+        code('_ret = _sep == \':\';')
         code('_stream >> _end;')
         code('if (!_stream.fail() && !_stream.eof()) {')
         code('    _stream.get(_sep);')
-        code('    _stream >> _intlvHighBit;')
-        code('    _stream.get(_sep);')
-        code('    _stream >> _xorHighBit;')
-        code('    _stream.get(_sep);')
-        code('    _stream >> _intlvBits;')
-        code('    _stream.get(_sep);')
+        code('    _ret = ret && _sep == \':\';')
         code('    _stream >> _intlvMatch;')
+        code('    while (!_stream.fail() && !_stream.eof()) {')
+        code('        _stream.get(_sep);')
+        code('        _ret = ret && _sep == \':\';')
+        code('        Addr mask;')
+        code('        _stream >> mask;')
+        code('        _masks.push_back(mask);')
+        code('    }')
         code('}')
-        code('bool _ret = !_stream.fail() &&'
-            '_stream.eof() && _sep == \':\';')
+        code('_ret = _ret && !_stream.fail() && _stream.eof();')
         code('if (_ret)')
-        code('   ${dest} = AddrRange(_start, _end, _intlvHighBit, \
-                _xorHighBit, _intlvBits, _intlvMatch);')
+        code('   ${dest} = AddrRange(_start, _end, _masks, _intlvMatch);')
         code('${ret} _ret;')
 
     def getValue(self):
@@ -799,8 +881,7 @@ class AddrRange(ParamValue):
         from _m5.range import AddrRange
 
         return AddrRange(long(self.start), long(self.end),
-                         int(self.intlvHighBit), int(self.xorHighBit),
-                         int(self.intlvBits), int(self.intlvMatch))
+                         self.masks, int(self.intlvMatch))
 
 # Boolean parameter type.  Python doesn't let you subclass bool, since
 # it doesn't want to let you create multiple instances of True and
@@ -827,9 +908,12 @@ class Bool(ParamValue):
 
     # implement truth value testing for Bool parameters so that these params
     # evaluate correctly during the python configuration phase
-    def __nonzero__(self):
+    def __bool__(self):
         return bool(self.value)
 
+    # Python 2.7 uses __nonzero__ instead of __bool__
+    __nonzero__ = __bool__
+
     def ini_str(self):
         if self.value:
             return 'true'
@@ -849,7 +933,7 @@ class Bool(ParamValue):
         code('%s to_bool(%s, %s);' % (ret, src, dest))
 
 def IncEthernetAddr(addr, val = 1):
-    bytes = map(lambda x: int(x, 16), addr.split(':'))
+    bytes = [ int(x, 16) for x in addr.split(':') ]
     bytes[5] += val
     for i in (5, 4, 3, 2, 1):
         val,rem = divmod(bytes[i], 256)
@@ -883,15 +967,15 @@ class EthernetAddr(ParamValue):
             return
 
         if not isinstance(value, str):
-            raise TypeError, "expected an ethernet address and didn't get one"
+            raise TypeError("expected an ethernet address and didn't get one")
 
         bytes = value.split(':')
         if len(bytes) != 6:
-            raise TypeError, 'invalid ethernet address %s' % value
+            raise TypeError('invalid ethernet address %s' % value)
 
         for byte in bytes:
             if not 0 <= int(byte, base=16) <= 0xff:
-                raise TypeError, 'invalid ethernet address %s' % value
+                raise TypeError('invalid ethernet address %s' % value)
 
         self.value = value
 
@@ -964,7 +1048,7 @@ class IpAddress(ParamValue):
 
     def verifyIp(self):
         if self.ip < 0 or self.ip >= (1 << 32):
-            raise TypeError, "invalid ip address %#08x" % self.ip
+            raise TypeError("invalid ip address %#08x" % self.ip)
 
     def getValue(self):
         from _m5.net import IpAddress
@@ -989,7 +1073,7 @@ class IpNetmask(IpAddress):
             elif elseVal:
                 setattr(self, key, elseVal)
             else:
-                raise TypeError, "No value set for %s" % key
+                raise TypeError("No value set for %s" % key)
 
         if len(args) == 0:
             handle_kwarg(self, kwargs, 'ip')
@@ -998,7 +1082,7 @@ class IpNetmask(IpAddress):
         elif len(args) == 1:
             if kwargs:
                 if not 'ip' in kwargs and not 'netmask' in kwargs:
-                    raise TypeError, "Invalid arguments"
+                    raise TypeError("Invalid arguments")
                 handle_kwarg(self, kwargs, 'ip', args[0])
                 handle_kwarg(self, kwargs, 'netmask', args[0])
             elif isinstance(args[0], IpNetmask):
@@ -1011,10 +1095,10 @@ class IpNetmask(IpAddress):
             self.ip = args[0]
             self.netmask = args[1]
         else:
-            raise TypeError, "Too many arguments specified"
+            raise TypeError("Too many arguments specified")
 
         if kwargs:
-            raise TypeError, "Too many keywords: %s" % kwargs.keys()
+            raise TypeError("Too many keywords: %s" % list(kwargs.keys()))
 
         self.verify()
 
@@ -1039,7 +1123,7 @@ class IpNetmask(IpAddress):
     def verify(self):
         self.verifyIp()
         if self.netmask < 0 or self.netmask > 32:
-            raise TypeError, "invalid netmask %d" % netmask
+            raise TypeError("invalid netmask %d" % netmask)
 
     def getValue(self):
         from _m5.net import IpNetmask
@@ -1063,7 +1147,7 @@ class IpWithPort(IpAddress):
             elif elseVal:
                 setattr(self, key, elseVal)
             else:
-                raise TypeError, "No value set for %s" % key
+                raise TypeError("No value set for %s" % key)
 
         if len(args) == 0:
             handle_kwarg(self, kwargs, 'ip')
@@ -1072,7 +1156,7 @@ class IpWithPort(IpAddress):
         elif len(args) == 1:
             if kwargs:
                 if not 'ip' in kwargs and not 'port' in kwargs:
-                    raise TypeError, "Invalid arguments"
+                    raise TypeError("Invalid arguments")
                 handle_kwarg(self, kwargs, 'ip', args[0])
                 handle_kwarg(self, kwargs, 'port', args[0])
             elif isinstance(args[0], IpWithPort):
@@ -1085,10 +1169,10 @@ class IpWithPort(IpAddress):
             self.ip = args[0]
             self.port = args[1]
         else:
-            raise TypeError, "Too many arguments specified"
+            raise TypeError("Too many arguments specified")
 
         if kwargs:
-            raise TypeError, "Too many keywords: %s" % kwargs.keys()
+            raise TypeError("Too many keywords: %s" % list(kwargs.keys()))
 
         self.verify()
 
@@ -1113,7 +1197,7 @@ class IpWithPort(IpAddress):
     def verify(self):
         self.verifyIp()
         if self.port < 0 or self.port > 0xffff:
-            raise TypeError, "invalid port %d" % self.port
+            raise TypeError("invalid port %d" % self.port)
 
     def getValue(self):
         from _m5.net import IpWithPort
@@ -1155,7 +1239,7 @@ def parse_time(value):
             except ValueError:
                 pass
 
-    raise ValueError, "Could not parse '%s' as a time" % value
+    raise ValueError("Could not parse '%s' as a time" % value)
 
 class Time(ParamValue):
     cxx_type = 'tm'
@@ -1222,26 +1306,29 @@ class MetaEnum(MetaParamValue):
         return cls
 
     def __init__(cls, name, bases, init_dict):
-        if init_dict.has_key('map'):
+        if 'map' in init_dict:
             if not isinstance(cls.map, dict):
-                raise TypeError"Enum-derived class attribute 'map' " \
-                      "must be of type dict"
+                raise TypeError("Enum-derived class attribute 'map' " \
+                      "must be of type dict")
             # build list of value strings from map
-            cls.vals = cls.map.keys()
+            cls.vals = list(cls.map.keys())
             cls.vals.sort()
-        elif init_dict.has_key('vals'):
+        elif 'vals' in init_dict:
             if not isinstance(cls.vals, list):
-                raise TypeError"Enum-derived class attribute 'vals' " \
-                      "must be of type list"
+                raise TypeError("Enum-derived class attribute 'vals' " \
+                      "must be of type list")
             # build string->value map from vals sequence
             cls.map = {}
             for idx,val in enumerate(cls.vals):
                 cls.map[val] = idx
         else:
-            raise TypeError"Enum-derived class must define "\
-                  "attribute 'map' or 'vals'"
+            raise TypeError("Enum-derived class must define "\
+                  "attribute 'map' or 'vals'")
 
-        cls.cxx_type = 'Enums::%s' % name
+        if cls.is_class:
+            cls.cxx_type = '%s' % name
+        else:
+            cls.cxx_type = 'Enums::%s' % name
 
         super(MetaEnum, cls).__init__(name, bases, init_dict)
 
@@ -1258,22 +1345,36 @@ class MetaEnum(MetaParamValue):
 #ifndef $idem_macro
 #define $idem_macro
 
+''')
+        if cls.is_class:
+            code('''\
+enum class $name {
+''')
+        else:
+            code('''\
 $wrapper $wrapper_name {
     enum $name {
 ''')
-        code.indent(2)
+            code.indent(1)
+        code.indent(1)
         for val in cls.vals:
             code('$val = ${{cls.map[val]}},')
         code('Num_$name = ${{len(cls.vals)}}')
-        code.dedent(2)
-        code('    };')
+        code.dedent(1)
+        code('};')
 
-        if cls.wrapper_is_struct:
-            code('    static const char *${name}Strings[Num_${name}];')
-            code('};')
+        if cls.is_class:
+            code('''\
+extern const char *${name}Strings[static_cast<int>(${name}::Num_${name})];
+''')
+        elif cls.wrapper_is_struct:
+            code('static const char *${name}Strings[Num_${name}];')
         else:
             code('extern const char *${name}Strings[Num_${name}];')
-            code('}')
+
+        if not cls.is_class:
+            code.dedent(1)
+            code('};')
 
         code()
         code('#endif // $idem_macro')
@@ -1288,9 +1389,14 @@ $wrapper $wrapper_name {
             code('const char *${wrapper_name}::${name}Strings'
                 '[Num_${name}] =')
         else:
-            code('namespace Enums {')
-            code.indent(1)
-            code(' const char *${name}Strings[Num_${name}] =')
+            if cls.is_class:
+                code('''\
+const char *${name}Strings[static_cast<int>(${name}::Num_${name})] =
+''')
+            else:
+                code('namespace Enums {')
+                code.indent(1)
+                code('const char *${name}Strings[Num_${name}] =')
 
         code('{')
         code.indent(1)
@@ -1299,14 +1405,15 @@ $wrapper $wrapper_name {
         code.dedent(1)
         code('};')
 
-        if not cls.wrapper_is_struct:
-            code('} // namespace $wrapper_name')
+        if not cls.wrapper_is_struct and not cls.is_class:
             code.dedent(1)
+            code('} // namespace $wrapper_name')
+
 
     def pybind_def(cls, code):
         name = cls.__name__
-        wrapper_name = cls.wrapper_name
         enum_name = cls.__name__ if cls.enum_name is None else cls.enum_name
+        wrapper_name = enum_name if cls.is_class else cls.wrapper_name
 
         code('''#include "pybind11/pybind11.h"
 #include "pybind11/stl.h"
@@ -1320,8 +1427,11 @@ module_init(py::module &m_internal)
 {
     py::module m = m_internal.def_submodule("enum_${name}");
 
-    py::enum_<${wrapper_name}::${enum_name}>(m, "enum_${name}")
 ''')
+        if cls.is_class:
+            code('py::enum_<${enum_name}>(m, "enum_${name}")')
+        else:
+            code('py::enum_<${wrapper_name}::${enum_name}>(m, "enum_${name}")')
 
         code.indent()
         code.indent()
@@ -1350,13 +1460,15 @@ class Enum(ParamValue):
     # If true, the enum is wrapped in a struct rather than a namespace
     wrapper_is_struct = False
 
+    is_class = False
+
     # If not None, use this as the enum name rather than this class name
     enum_name = None
 
     def __init__(self, value):
         if value not in self.map:
-            raise TypeError"Enum param got bad value '%s' (not in %s)" \
-                  % (value, self.vals)
+            raise TypeError("Enum param got bad value '%s' (not in %s)" \
+                  % (value, self.vals))
         self.value = value
 
     def __call__(self, value):
@@ -1370,10 +1482,12 @@ class Enum(ParamValue):
     @classmethod
     def cxx_ini_parse(cls, code, src, dest, ret):
         code('if (false) {')
-        for elem_name in cls.map.iterkeys():
+        for elem_name in cls.map.keys():
             code('} else if (%s == "%s") {' % (src, elem_name))
             code.indent()
-            code('%s = Enums::%s;' % (dest, elem_name))
+            name = cls.__name__ if cls.enum_name is None else cls.enum_name
+            code('%s = %s::%s;' % (dest, name if cls.is_class else 'Enums',
+                                   elem_name))
             code('%s true;' % ret)
             code.dedent()
         code('} else {')
@@ -1388,6 +1502,24 @@ class Enum(ParamValue):
     def __str__(self):
         return self.value
 
+# This param will generate a scoped c++ enum and its python bindings.
+class ScopedEnum(Enum):
+    __metaclass__ = MetaEnum
+    vals = []
+    cmd_line_settable = True
+
+    # The name of the wrapping namespace or struct
+    wrapper_name = None
+
+    # If true, the enum is wrapped in a struct rather than a namespace
+    wrapper_is_struct = False
+
+    # If true, the generated enum is a scoped enum
+    is_class = True
+
+    # If not None, use this as the enum name rather than this class name
+    enum_name = None
+
 # how big does a rounding error need to be before we warn about it?
 frequency_tolerance = 0.001  # 0.1%
 
@@ -1443,7 +1575,7 @@ class Latency(TickParamValue):
             return self
         if attr == 'frequency':
             return Frequency(self)
-        raise AttributeError, "Latency object has no attribute '%s'" % attr
+        raise AttributeError("Latency object has no attribute '%s'" % attr)
 
     def getValue(self):
         if self.ticks or self.value == 0:
@@ -1485,7 +1617,7 @@ class Frequency(TickParamValue):
             return self
         if attr in ('latency', 'period'):
             return Latency(self)
-        raise AttributeError, "Frequency object has no attribute '%s'" % attr
+        raise AttributeError("Frequency object has no attribute '%s'" % attr)
 
     # convert latency to ticks
     def getValue(self):
@@ -1530,7 +1662,7 @@ class Clock(TickParamValue):
             return Frequency(self)
         if attr in ('latency', 'period'):
             return Latency(self)
-        raise AttributeError, "Frequency object has no attribute '%s'" % attr
+        raise AttributeError("Frequency object has no attribute '%s'" % attr)
 
     def getValue(self):
         return self.period.getValue()
@@ -1541,71 +1673,38 @@ class Clock(TickParamValue):
     def ini_str(self):
         return self.period.ini_str()
 
-class Voltage(float,ParamValue):
-    cxx_type = 'double'
+class Voltage(Float):
     ex_str = "1V"
-    cmd_line_settable = True
 
     def __new__(cls, value):
-        # convert to voltage
-        val = convert.toVoltage(value)
-        return super(cls, Voltage).__new__(cls, val)
-
-    def __call__(self, value):
-        val = convert.toVoltage(value)
-        self.__init__(val)
-        return value
-
-    def __str__(self):
-        return str(self.getValue())
-
-    def getValue(self):
-        value = float(self)
-        return value
-
-    def ini_str(self):
-        return '%f' % self.getValue()
-
-    @classmethod
-    def cxx_ini_predecls(cls, code):
-        code('#include <sstream>')
+        value = convert.toVoltage(value)
+        return super(cls, Voltage).__new__(cls, value)
 
-    @classmethod
-    def cxx_ini_parse(self, code, src, dest, ret):
-        code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
+    def __init__(self, value):
+        value = convert.toVoltage(value)
+        super(Voltage, self).__init__(value)
 
-class Current(float, ParamValue):
-    cxx_type = 'double'
+class Current(Float):
     ex_str = "1mA"
-    cmd_line_settable = False
 
     def __new__(cls, value):
-        # convert to current
-        val = convert.toCurrent(value)
-        return super(cls, Current).__new__(cls, val)
-
-    def __call__(self, value):
-        val = convert.toCurrent(value)
-        self.__init__(val)
-        return value
-
-    def __str__(self):
-        return str(self.getValue())
+        value = convert.toCurrent(value)
+        return super(cls, Current).__new__(cls, value)
 
-    def getValue(self):
-        value = float(self)
-        return value
+    def __init__(self, value):
+        value = convert.toCurrent(value)
+        super(Current, self).__init__(value)
 
-    def ini_str(self):
-        return '%f' % self.getValue()
+class Energy(Float):
+    ex_str = "1pJ"
 
-    @classmethod
-    def cxx_ini_predecls(cls, code):
-        code('#include <sstream>')
+    def __new__(cls, value):
+        value = convert.toEnergy(value)
+        return super(cls, Energy).__new__(cls, value)
 
-    @classmethod
-    def cxx_ini_parse(self, code, src, dest, ret):
-        code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
+    def __init__(self, value):
+        value = convert.toEnergy(value)
+        super(Energy, self).__init__(value)
 
 class NetworkBandwidth(float,ParamValue):
     cxx_type = 'float'
@@ -1721,6 +1820,9 @@ class NullSimObject(object):
         return
         yield None
 
+    def get_config_as_dict(self):
+        return {}
+
     def __str__(self):
         return self._name
 
@@ -1753,11 +1855,12 @@ AllMemory = AddrRange(0, MaxAddr)
 # Port reference: encapsulates a reference to a particular port on a
 # particular SimObject.
 class PortRef(object):
-    def __init__(self, simobj, name, role):
+    def __init__(self, simobj, name, role, is_source):
         assert(isSimObject(simobj) or isSimObjectClass(simobj))
         self.simobj = simobj
         self.name = name
         self.role = role
+        self.is_source = is_source
         self.peer = None   # not associated with another port yet
         self.ccConnected = False # C++ port connection done?
         self.index = -1  # always -1 for non-vector ports
@@ -1776,14 +1879,15 @@ class PortRef(object):
 
     # for config.json
     def get_config_as_dict(self):
-        return {'role' : self.role, 'peer' : str(self.peer)}
+        return {'role' : self.role, 'peer' : str(self.peer),
+                'is_source' : str(self.is_source)}
 
     def __getattr__(self, attr):
         if attr == 'peerObj':
             # shorthand for proxies
             return self.peer.simobj
-        raise AttributeError"'%s' object has no attribute '%s'" % \
-              (self.__class__.__name__, attr)
+        raise AttributeError("'%s' object has no attribute '%s'" % \
+              (self.__class__.__name__, attr))
 
     # Full connection is symmetric (both ways).  Called via
     # SimObject.__setattr__ as a result of a port assignment, e.g.,
@@ -1797,48 +1901,54 @@ class PortRef(object):
             fatal("Port %s is already connected to %s, cannot connect %s\n",
                   self, self.peer, other);
         self.peer = other
+
         if proxy.isproxy(other):
             other.set_param_desc(PortParamDesc())
-        elif isinstance(other, PortRef):
-            if other.peer is not self:
-                other.connect(self)
-        else:
-            raise TypeError, \
-                  "assigning non-port reference '%s' to port '%s'" \
-                  % (other, self)
-
-    # Allow a master/slave port pair to be spliced between
-    # a port and its connected peer. Useful operation for connecting
-    # instrumentation structures into a system when it is necessary
-    # to connect the instrumentation after the full system has been
-    # constructed.
-    def splice(self, new_master_peer, new_slave_peer):
-        if self.peer and not proxy.isproxy(self.peer):
-            if isinstance(new_master_peer, PortRef) and \
-               isinstance(new_slave_peer, PortRef):
-                 old_peer = self.peer
-                 if self.role == 'SLAVE':
-                     self.peer = new_master_peer
-                     old_peer.peer = new_slave_peer
-                     new_master_peer.connect(self)
-                     new_slave_peer.connect(old_peer)
-                 elif self.role == 'MASTER':
-                     self.peer = new_slave_peer
-                     old_peer.peer = new_master_peer
-                     new_slave_peer.connect(self)
-                     new_master_peer.connect(old_peer)
-                 else:
-                     panic("Port %s has unknown role, "+\
-                           "cannot splice in new peers\n", self)
-            else:
-                raise TypeError, \
-                      "Splicing non-port references '%s','%s' to port '%s'"\
-                      % (new_peer, peers_new_peer, self)
-        else:
+            return
+        elif not isinstance(other, PortRef):
+            raise TypeError("assigning non-port reference '%s' to port '%s'" \
+                  % (other, self))
+
+        if not Port.is_compat(self, other):
+            fatal("Ports %s and %s with roles '%s' and '%s' "
+                    "are not compatible", self, other, self.role, other.role)
+
+        if other.peer is not self:
+            other.connect(self)
+
+    # Allow a compatible port pair to be spliced between a port and its
+    # connected peer. Useful operation for connecting instrumentation
+    # structures into a system when it is necessary to connect the
+    # instrumentation after the full system has been constructed.
+    def splice(self, new_1, new_2):
+        if not self.peer or proxy.isproxy(self.peer):
             fatal("Port %s not connected, cannot splice in new peers\n", self)
 
+        if not isinstance(new_1, PortRef) or not isinstance(new_2, PortRef):
+            raise TypeError(
+                  "Splicing non-port references '%s','%s' to port '%s'" % \
+                  (new_1, new_2, self))
+
+        old_peer = self.peer
+
+        if Port.is_compat(old_peer, new_1) and Port.is_compat(self, new_2):
+            old_peer.peer = new_1
+            new_1.peer = old_peer
+            self.peer = new_2
+            new_2.peer = self
+        elif Port.is_compat(old_peer, new_2) and Port.is_compat(self, new_1):
+            old_peer.peer = new_2
+            new_2.peer = old_peer
+            self.peer = new_1
+            new_1.peer = self
+        else:
+            fatal("Ports %s(%s) and %s(%s) can't be compatibly spliced with "
+                    "%s(%s) and %s(%s)", self, self.role,
+                    old_peer, old_peer.role, new_1, new_1.role,
+                    new_2, new_2.role)
+
     def clone(self, simobj, memo):
-        if memo.has_key(self):
+        if self in memo:
             return memo[self]
         newRef = copy.copy(self)
         memo[self] = newRef
@@ -1856,48 +1966,31 @@ class PortRef(object):
             try:
                 realPeer = self.peer.unproxy(self.simobj)
             except:
-                print "Error in unproxying port '%s' of %s" % \
-                      (self.name, self.simobj.path())
+                print("Error in unproxying port '%s' of %s" %
+                      (self.name, self.simobj.path()))
                 raise
             self.connect(realPeer)
 
     # Call C++ to create corresponding port connection between C++ objects
     def ccConnect(self):
-        from _m5.pyobject import connectPorts
-
-        if self.role == 'SLAVE':
-            # do nothing and let the master take care of it
-            return
-
         if self.ccConnected: # already done this
             return
+
         peer = self.peer
         if not self.peer: # nothing to connect to
             return
 
-        # check that we connect a master to a slave
-        if self.role == peer.role:
-            raise TypeError, \
-                "cannot connect '%s' and '%s' due to identical role '%s'" \
-                % (peer, self, self.role)
+        port = self.simobj.getPort(self.name, self.index)
+        peer_port = peer.simobj.getPort(peer.name, peer.index)
+        port.bind(peer_port)
 
-        try:
-            # self is always the master and peer the slave
-            connectPorts(self.simobj.getCCObject(), self.name, self.index,
-                         peer.simobj.getCCObject(), peer.name, peer.index)
-        except:
-            print "Error connecting port %s.%s to %s.%s" % \
-                  (self.simobj.path(), self.name,
-                   peer.simobj.path(), peer.name)
-            raise
         self.ccConnected = True
-        peer.ccConnected = True
 
 # A reference to an individual element of a VectorPort... much like a
 # PortRef, but has an index.
 class VectorPortElementRef(PortRef):
-    def __init__(self, simobj, name, role, index):
-        PortRef.__init__(self, simobj, name, role)
+    def __init__(self, simobj, name, role, is_source, index):
+        PortRef.__init__(self, simobj, name, role, is_source)
         self.index = index
 
     def __str__(self):
@@ -1906,11 +1999,12 @@ class VectorPortElementRef(PortRef):
 # A reference to a complete vector-valued port (not just a single element).
 # Can be indexed to retrieve individual VectorPortElementRef instances.
 class VectorPortRef(object):
-    def __init__(self, simobj, name, role):
+    def __init__(self, simobj, name, role, is_source):
         assert(isSimObject(simobj) or isSimObjectClass(simobj))
         self.simobj = simobj
         self.name = name
         self.role = role
+        self.is_source = is_source
         self.elements = []
 
     def __str__(self):
@@ -1928,14 +2022,16 @@ class VectorPortRef(object):
     # for config.json
     def get_config_as_dict(self):
         return {'role' : self.role,
-                'peer' : [el.ini_str() for el in self.elements]}
+                'peer' : [el.ini_str() for el in self.elements],
+                'is_source' : str(self.is_source)}
 
     def __getitem__(self, key):
         if not isinstance(key, int):
-            raise TypeError, "VectorPort index must be integer"
+            raise TypeError("VectorPort index must be integer")
         if key >= len(self.elements):
             # need to extend list
-            ext = [VectorPortElementRef(self.simobj, self.name, self.role, i)
+            ext = [VectorPortElementRef(
+                    self.simobj, self.name, self.role, self.is_source, i)
                    for i in range(len(self.elements), key+1)]
             self.elements.extend(ext)
         return self.elements[key]
@@ -1945,7 +2041,7 @@ class VectorPortRef(object):
 
     def __setitem__(self, key, value):
         if not isinstance(key, int):
-            raise TypeError, "VectorPort index must be integer"
+            raise TypeError("VectorPort index must be integer")
         self[key].connect(value)
 
     def connect(self, other):
@@ -1960,7 +2056,7 @@ class VectorPortRef(object):
             self._get_next().connect(other)
 
     def clone(self, simobj, memo):
-        if memo.has_key(self):
+        if self in memo:
             return memo[self]
         newRef = copy.copy(self)
         memo[self] = newRef
@@ -1979,10 +2075,31 @@ class VectorPortRef(object):
 # logical port in the SimObject class, not a particular port on a
 # SimObject instance.  The latter are represented by PortRef objects.
 class Port(object):
+    # Port("role", "description")
+
+    _compat_dict = { }
+
+    @classmethod
+    def compat(cls, role, peer):
+        cls._compat_dict.setdefault(role, set()).add(peer)
+        cls._compat_dict.setdefault(peer, set()).add(role)
+
+    @classmethod
+    def is_compat(cls, one, two):
+        for port in one, two:
+            if not port.role in Port._compat_dict:
+                fatal("Unrecognized role '%s' for port %s\n", port.role, port)
+        return one.role in Port._compat_dict[two.role]
+
+    def __init__(self, role, desc, is_source=False):
+        self.desc = desc
+        self.role = role
+        self.is_source = is_source
+
     # Generate a PortRef for this port on the given SimObject with the
     # given name
     def makeRef(self, simobj):
-        return PortRef(simobj, self.name, self.role)
+        return PortRef(simobj, self.name, self.role, self.is_source)
 
     # Connect an instance of this port (on the given SimObject with
     # the given name) with the port described by the supplied PortRef
@@ -2003,52 +2120,41 @@ class Port(object):
     def cxx_decl(self, code):
         code('unsigned int port_${{self.name}}_connection_count;')
 
-class MasterPort(Port):
-    # MasterPort("description")
-    def __init__(self, *args):
-        if len(args) == 1:
-            self.desc = args[0]
-            self.role = 'MASTER'
-        else:
-            raise TypeError, 'wrong number of arguments'
-
-class SlavePort(Port):
-    # SlavePort("description")
-    def __init__(self, *args):
-        if len(args) == 1:
-            self.desc = args[0]
-            self.role = 'SLAVE'
-        else:
-            raise TypeError, 'wrong number of arguments'
+Port.compat('GEM5 REQUESTER', 'GEM5 RESPONDER')
+
+class RequestPort(Port):
+    # RequestPort("description")
+    def __init__(self, desc):
+        super(RequestPort, self).__init__(
+                'GEM5 REQUESTER', desc, is_source=True)
+
+class ResponsePort(Port):
+    # ResponsePort("description")
+    def __init__(self, desc):
+        super(ResponsePort, self).__init__('GEM5 RESPONDER', desc)
 
 # VectorPort description object.  Like Port, but represents a vector
 # of connections (e.g., as on a XBar).
 class VectorPort(Port):
-    def __init__(self, *args):
-        self.isVec = True
-
     def makeRef(self, simobj):
-        return VectorPortRef(simobj, self.name, self.role)
-
-class VectorMasterPort(VectorPort):
-    # VectorMasterPort("description")
-    def __init__(self, *args):
-        if len(args) == 1:
-            self.desc = args[0]
-            self.role = 'MASTER'
-            VectorPort.__init__(self, *args)
-        else:
-            raise TypeError, 'wrong number of arguments'
-
-class VectorSlavePort(VectorPort):
-    # VectorSlavePort("description")
-    def __init__(self, *args):
-        if len(args) == 1:
-            self.desc = args[0]
-            self.role = 'SLAVE'
-            VectorPort.__init__(self, *args)
-        else:
-            raise TypeError, 'wrong number of arguments'
+        return VectorPortRef(simobj, self.name, self.role, self.is_source)
+
+class VectorRequestPort(VectorPort):
+    # VectorRequestPort("description")
+    def __init__(self, desc):
+        super(VectorRequestPort, self).__init__(
+                'GEM5 REQUESTER', desc, is_source=True)
+
+class VectorResponsePort(VectorPort):
+    # VectorResponsePort("description")
+    def __init__(self, desc):
+        super(VectorResponsePort, self).__init__('GEM5 RESPONDER', desc)
+
+# Old names, maintained for compatibility.
+MasterPort = RequestPort
+SlavePort = ResponsePort
+VectorMasterPort = VectorRequestPort
+VectorSlavePort = VectorResponsePort
 
 # 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
 # proxy objects (via set_param_desc()) so that proxy error messages
@@ -2069,20 +2175,19 @@ def clear():
     allParams = baseParams.copy()
 
 __all__ = ['Param', 'VectorParam',
-           'Enum', 'Bool', 'String', 'Float',
+           'Enum', 'ScopedEnum', 'Bool', 'String', 'Float',
            'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
            'Int32', 'UInt32', 'Int64', 'UInt64',
            'Counter', 'Addr', 'Tick', 'Percent',
            'TcpPort', 'UdpPort', 'EthernetAddr',
            'IpAddress', 'IpNetmask', 'IpWithPort',
            'MemorySize', 'MemorySize32',
-           'Latency', 'Frequency', 'Clock', 'Voltage',
+           'Latency', 'Frequency', 'Clock', 'Voltage', 'Current', 'Energy',
            'NetworkBandwidth', 'MemoryBandwidth',
            'AddrRange',
            'MaxAddr', 'MaxTick', 'AllMemory',
            'Time',
            'NextEthernetAddr', 'NULL',
-           'MasterPort', 'SlavePort',
+           'Port', 'RequestPort', 'ResponsePort', 'MasterPort', 'SlavePort',
+           'VectorPort', 'VectorRequestPort', 'VectorResponsePort',
            'VectorMasterPort', 'VectorSlavePort']
-
-import SimObject