python: Add binding for the new AddrRange c++ constructor
[gem5.git] / src / python / m5 / params.py
index 981bb0d37a9486a647546f705c833dea1f9af495..c1c6ca94717cbd9659b4347fd384207f032a5652 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (c) 2012-2013 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 = {}
@@ -93,7 +101,7 @@ class MetaParamValue(type):
 # parameters.
 class ParamValue(object):
     __metaclass__ = MetaParamValue
-
+    cmd_line_settable = False
 
     # Generate the code needed as a prerequisite for declaring a C++
     # object of this type.  Typically generates one or more #include
@@ -102,23 +110,42 @@ class ParamValue(object):
     def cxx_predecls(cls, code):
         pass
 
-    # Generate the code needed as a prerequisite for including a
-    # reference to a C++ object of this type in a SWIG .i file.
-    # Typically generates one or more %import or %include statements.
     @classmethod
-    def swig_predecls(cls, code):
-        pass
+    def pybind_predecls(cls, code):
+        cls.cxx_predecls(code)
 
     # default for printing to .ini file is regular string conversion.
     # will be overridden in some cases
     def ini_str(self):
         return str(self)
 
+    # default for printing to .json file is regular string conversion.
+    # will be overridden in some cases, mostly to use native Python
+    # types where there are similar JSON types
+    def config_value(self):
+        return str(self)
+
+    # Prerequisites for .ini parsing with cxx_ini_parse
+    @classmethod
+    def cxx_ini_predecls(cls, code):
+        pass
+
+    # parse a .ini file entry for this param from string expression
+    # src into lvalue dest (of the param's C++ type)
+    @classmethod
+    def cxx_ini_parse(cls, code, src, dest, ret):
+        code('// Unhandled param type: %s' % cls.__name__)
+        code('%s false;' % ret)
+
     # allows us to blithely call unproxy() on things without checking
     # if they're really proxies or not
     def unproxy(self, base):
         return self
 
+    # Produce a human readable version of the stored value
+    def pretty_print(self, value):
+        return str(value)
+
 # Regular parameter description.
 class ParamDesc(object):
     def __init__(self, ptype_str, ptype, *args, **kwargs):
@@ -134,39 +161,53 @@ 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"):
+            return self.ptype.ex_str
+        else:
+            return self.ptype_str
+
+    # Is the param available to be exposed on the command line
+    def isCmdLineSettable(self):
+        if hasattr(self.ptype, "cmd_line_settable"):
+            return self.ptype.cmd_line_settable
+        else:
+            return False
 
     def convert(self, value):
         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
@@ -176,12 +217,19 @@ class ParamDesc(object):
             return value
         return self.ptype(value)
 
+    def pretty_print(self, value):
+        if isinstance(value, proxy.BaseProxy):
+           return str(value)
+        if isNullPointer(value):
+           return NULL
+        return self.ptype(value).pretty_print(value)
+
     def cxx_predecls(self, code):
         code('#include <cstddef>')
         self.ptype.cxx_predecls(code)
 
-    def swig_predecls(self, code):
-        self.ptype.swig_predecls(code)
+    def pybind_predecls(self, code):
+        self.ptype.pybind_predecls(code)
 
     def cxx_decl(self, code):
         code('${{self.ptype.cxx_type}} ${{self.name}};')
@@ -193,8 +241,11 @@ 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]
 
     def ini_str(self):
         return ' '.join([v.ini_str() for v in self])
@@ -203,10 +254,12 @@ class VectorParamValue(list):
         return [ v.getValue() for v in self ]
 
     def unproxy(self, base):
-        if len(self) == 1 and isinstance(self[0], proxy.AllProxy):
+        if len(self) == 1 and isinstance(self[0], proxy.BaseProxy):
+            # The value is a proxy (e.g. Parent.any, Parent.all or
+            # Parent.x) therefore try resolve it
             return self[0].unproxy(base)
         else:
-             return [v.unproxy(base) for v in self]
+            return [v.unproxy(base) for v in self]
 
 class SimObjectVector(VectorParamValue):
     # support clone operation
@@ -226,7 +279,7 @@ class SimObjectVector(VectorParamValue):
                 v.set_parent(parent, "%s%0*d" % (name, width, i))
 
     def has_parent(self):
-        return reduce(lambda x,y: x and y, [v.has_parent() for v in self])
+        return any([e.has_parent() for e in self if not isNullPointer(e)])
 
     # return 'cpu0 cpu1' etc. for print_ini()
     def get_name(self):
@@ -247,6 +300,39 @@ class SimObjectVector(VectorParamValue):
             a.append(v.get_config_as_dict())
         return a
 
+    # If we are replacing an item in the vector, make sure to set the
+    # parent reference of the new SimObject to be the same as the parent
+    # of the SimObject being replaced. Useful to have if we created
+    # a SimObjectVector of temporary objects that will be modified later in
+    # configuration scripts.
+    def __setitem__(self, key, value):
+        val = self[key]
+        if value.has_parent():
+            warn("SimObject %s already has a parent" % value.get_name() +\
+                 " that is being overwritten by a SimObjectVector")
+        value.set_parent(val.get_parent(), val._name)
+        super(SimObjectVector, self).__setitem__(key, value)
+
+    # Enumerate the params of each member of the SimObject vector. Creates
+    # strings that will allow indexing into the vector by the python code and
+    # allow it to be specified on the command line.
+    def enumerateParams(self, flags_dict = {},
+                        cmd_line_str = "",
+                        access_str = ""):
+        if hasattr(self, "_paramEnumed"):
+            print("Cycle detected enumerating params at %s?!" % (cmd_line_str))
+        else:
+            x = 0
+            for vals in self:
+                # Each entry in the SimObjectVector should be an
+                # instance of a SimObject
+                flags_dict = vals.enumerateParams(flags_dict,
+                                                  cmd_line_str + "%d." % x,
+                                                  access_str + "[%d]." % x)
+                x = x + 1
+
+        return flags_dict
+
 class VectorParamDesc(ParamDesc):
     # Convert assigned value to appropriate type.  If the RHS is not a
     # list or tuple, it generates a single-element list.
@@ -254,6 +340,10 @@ class VectorParamDesc(ParamDesc):
         if isinstance(value, (list, tuple)):
             # list: coerce each element into new list
             tmp_list = [ ParamDesc.convert(self, v) for v in value ]
+        elif isinstance(value, str):
+            # If input is a csv string
+            tmp_list = [ ParamDesc.convert(self, v) \
+                         for v in value.strip('[').strip(']').split(',') ]
         else:
             # singleton: coerce to a single-element list
             tmp_list = [ ParamDesc.convert(self, value) ]
@@ -263,55 +353,48 @@ class VectorParamDesc(ParamDesc):
         else:
             return VectorParamValue(tmp_list)
 
-    def swig_module_name(self):
-        return "%s_vector" % self.ptype_str
-
-    def swig_predecls(self, code):
-        code('%import "${{self.swig_module_name()}}.i"')
+    # Produce a human readable example string that describes
+    # how to set this vector parameter in the absence of a default
+    # value.
+    def example_str(self):
+        s = super(VectorParamDesc, self).example_str()
+        help_str = "[" + s + "," + s + ", ...]"
+        return help_str
 
-    def swig_decl(self, code):
-        code('%module(package="m5.internal") ${{self.swig_module_name()}}')
-        code('%{')
-        self.ptype.cxx_predecls(code)
-        code('%}')
-        code()
-        # Make sure the SWIGPY_SLICE_ARG is defined through this inclusion
-        code('%include "std_container.i"')
-        code()
-        self.ptype.swig_predecls(code)
-        code()
-        code('%include "std_vector.i"')
-        code()
+    # Produce a human readable representation of the value of this vector param.
+    def pretty_print(self, value):
+        if isinstance(value, (list, tuple)):
+            tmp_list = [ ParamDesc.pretty_print(self, v) for v in value ]
+        elif isinstance(value, str):
+            tmp_list = [ ParamDesc.pretty_print(self, v) for v in value.split(',') ]
+        else:
+            tmp_list = [ ParamDesc.pretty_print(self, value) ]
 
-        ptype = self.ptype_str
-        cxx_type = self.ptype.cxx_type
+        return tmp_list
 
-        code('''\
-%typemap(in) std::vector< $cxx_type >::value_type {
-    if (SWIG_ConvertPtr($$input, (void **)&$$1, $$1_descriptor, 0) == -1) {
-        if (SWIG_ConvertPtr($$input, (void **)&$$1,
-                            $$descriptor($cxx_type), 0) == -1) {
-            return NULL;
-        }
-    }
-}
-
-%typemap(in) std::vector< $cxx_type >::value_type * {
-    if (SWIG_ConvertPtr($$input, (void **)&$$1, $$1_descriptor, 0) == -1) {
-        if (SWIG_ConvertPtr($$input, (void **)&$$1,
-                            $$descriptor($cxx_type *), 0) == -1) {
-            return NULL;
-        }
-    }
-}
-''')
+    # This is a helper function for the new config system
+    def __call__(self, value):
+        if isinstance(value, (list, tuple)):
+            # list: coerce each element into new list
+            tmp_list = [ ParamDesc.convert(self, v) for v in value ]
+        elif isinstance(value, str):
+            # If input is a csv string
+            tmp_list = [ ParamDesc.convert(self, v) \
+                         for v in value.strip('[').strip(']').split(',') ]
+        else:
+            # singleton: coerce to a single-element list
+            tmp_list = [ ParamDesc.convert(self, value) ]
 
-        code('%template(vector_$ptype) std::vector< $cxx_type >;')
+        return VectorParamValue(tmp_list)
 
     def cxx_predecls(self, code):
         code('#include <vector>')
         self.ptype.cxx_predecls(code)
 
+    def pybind_predecls(self, code):
+        code('#include <vector>')
+        self.ptype.pybind_predecls(code)
+
     def cxx_decl(self, code):
         code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};')
 
@@ -356,14 +439,20 @@ VectorParam = ParamFactory(VectorParamDesc)
 # built-in str class.
 class String(ParamValue,str):
     cxx_type = 'std::string'
+    cmd_line_settable = True
 
     @classmethod
     def cxx_predecls(self, code):
         code('#include <string>')
 
+    def __call__(self, value):
+        self = value
+        return value
+
     @classmethod
-    def swig_predecls(cls, code):
-        code('%include "std_string.i"')
+    def cxx_ini_parse(self, code, src, dest, ret):
+        code('%s = %s;' % (dest, src))
+        code('%s true;' % ret)
 
     def getValue(self):
         return self
@@ -372,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)
 
@@ -390,24 +483,86 @@ 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 /= other
+        newobj.value //= NumericParamValue.unwrap(other)
+        newobj._check()
+        return newobj
+
+
+    def __add__(self, other):
+        newobj = self.__class__(self)
+        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
+
+    @classmethod
+    def cxx_ini_predecls(cls, code):
+        # Assume that base/str.hh will be included anyway
+        # code('#include "base/str.hh"')
+        pass
+
+    # The default for parsing PODs from an .ini entry is to extract from an
+    # istringstream and let overloading choose the right type according to
+    # the dest type.
+    @classmethod
+    def cxx_ini_parse(self, code, src, dest, ret):
+        code('%s to_number(%s, %s);' % (ret, src, dest))
+
 # Metaclass for bounds-checked integer parameters.  See CheckedInt.
 class CheckedIntType(MetaParamValue):
     def __init__(cls, name, bases, dict):
@@ -437,11 +592,12 @@ class CheckedIntType(MetaParamValue):
 # metaclass CheckedIntType.__init__.
 class CheckedInt(NumericParamValue):
     __metaclass__ = CheckedIntType
+    cmd_line_settable = True
 
     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):
@@ -449,21 +605,22 @@ 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
         code('#include "base/types.hh"')
 
-    @classmethod
-    def swig_predecls(cls, code):
-        # most derived types require this, so we just do it here once
-        code('%import "stdint.i"')
-        code('%import "base/types.hh"')
-
     def getValue(self):
         return long(self.value)
 
@@ -492,24 +649,55 @@ class Cycles(CheckedInt):
     unsigned = True
 
     def getValue(self):
-        from m5.internal.core import Cycles
+        from _m5.core import Cycles
         return Cycles(self.value)
 
+    @classmethod
+    def cxx_ini_predecls(cls, code):
+        # Assume that base/str.hh will be included anyway
+        # code('#include "base/str.hh"')
+        pass
+
+    @classmethod
+    def cxx_ini_parse(cls, code, src, dest, ret):
+        code('uint64_t _temp;')
+        code('bool _ret = to_number(%s, _temp);' % src)
+        code('if (_ret)')
+        code('    %s = Cycles(_temp);' % dest)
+        code('%s _ret;' % ret)
+
 class Float(ParamValue, float):
     cxx_type = 'double'
+    cmd_line_settable = True
 
     def __init__(self, value):
-        if isinstance(value, (int, long, float, NumericParamValue, 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)
+        return value
 
     def getValue(self):
         return float(self.value)
 
+    def config_value(self):
+        return self
+
+    @classmethod
+    def cxx_ini_predecls(cls, code):
+        code('#include <sstream>')
+
+    @classmethod
+    def cxx_ini_parse(self, code, src, dest, ret):
+        code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
+
 class MemorySize(CheckedInt):
     cxx_type = 'uint64_t'
+    ex_str = '512MB'
     size = 64
     unsigned = True
     def __init__(self, value):
@@ -521,6 +709,7 @@ class MemorySize(CheckedInt):
 
 class MemorySize32(CheckedInt):
     cxx_type = 'uint32_t'
+    ex_str = '512MB'
     size = 32
     unsigned = True
     def __init__(self, value):
@@ -539,24 +728,40 @@ class Addr(CheckedInt):
             self.value = value.value
         else:
             try:
+                # Often addresses are referred to with sizes. Ex: A device
+                # base address is at "512MB".  Use toMemorySize() to convert
+                # these into addresses. If the address is not specified with a
+                # "size", an exception will occur and numeric translation will
+                # proceed below.
                 self.value = convert.toMemorySize(value)
-            except TypeError:
-                self.value = long(value)
+            except (TypeError, ValueError):
+                # Convert number to string and use long() to do automatic
+                # base conversion (requires base=0 for auto-conversion)
+                self.value = long(str(value), base=0)
+
         self._check()
     def __add__(self, other):
         if isinstance(other, Addr):
             return self.value + other.value
         else:
             return self.value + other
+    def pretty_print(self, value):
+        try:
+            val = convert.toMemorySize(value)
+        except TypeError:
+            val = long(value)
+        return "0x%x" % long(val)
 
 class AddrRange(ParamValue):
     cxx_type = 'AddrRange'
 
     def __init__(self, *args, **kwargs):
-        # Disable interleaving by default
+        # 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
@@ -567,16 +772,31 @@ 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 '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 'intlvHighBit' in kwargs:
+                    intlv_high_bit = int(kwargs.pop('intlvHighBit'))
+                if 'xorHighBit' in kwargs:
+                    xor_high_bit = int(kwargs.pop('xorHighBit'))
+                if 'intlvBits' in kwargs:
+                    self.intlvBits = int(kwargs.pop('intlvBits'))
+                    self.masks = [0] * self.intlvBits
+                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)
@@ -596,13 +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' % (self.start, self.end)
+        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
@@ -614,29 +838,68 @@ class AddrRange(ParamValue):
         code('#include "base/addr_range.hh"')
 
     @classmethod
-    def swig_predecls(cls, code):
-        Addr.swig_predecls(code)
+    def pybind_predecls(cls, code):
+        Addr.pybind_predecls(code)
+        code('#include "base/addr_range.hh"')
+
+    @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('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('    _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('_ret = _ret && !_stream.fail() && _stream.eof();')
+        code('if (_ret)')
+        code('   ${dest} = AddrRange(_start, _end, _masks, _intlvMatch);')
+        code('${ret} _ret;')
 
     def getValue(self):
-        # Go from the Python class to the wrapped C++ class generated
-        # by swig
-        from m5.internal.range import AddrRange
+        # Go from the Python class to the wrapped C++ class
+        from _m5.range import AddrRange
 
         return AddrRange(long(self.start), long(self.end),
-                         int(self.intlvHighBit), 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
 # False.  Thus this is a little more complicated than String.
 class Bool(ParamValue):
     cxx_type = 'bool'
+    cmd_line_settable = True
+
     def __init__(self, value):
         try:
             self.value = convert.toBool(value)
         except TypeError:
             self.value = bool(value)
 
+    def __call__(self, value):
+        self.__init__(value)
+        return value
+
     def getValue(self):
         return bool(self.value)
 
@@ -645,16 +908,32 @@ 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'
         return 'false'
 
+    def config_value(self):
+        return self.value
+
+    @classmethod
+    def cxx_ini_predecls(cls, code):
+        # Assume that base/str.hh will be included anyway
+        # code('#include "base/str.hh"')
+        pass
+
+    @classmethod
+    def cxx_ini_parse(cls, code, src, dest, ret):
+        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)
@@ -675,58 +954,66 @@ def NextEthernetAddr():
 
 class EthernetAddr(ParamValue):
     cxx_type = 'Net::EthAddr'
+    ex_str = "00:90:00:00:00:01"
+    cmd_line_settable = True
 
     @classmethod
     def cxx_predecls(cls, code):
         code('#include "base/inet.hh"')
 
-    @classmethod
-    def swig_predecls(cls, code):
-        code('%include "python/swig/inet.i"')
-
     def __init__(self, value):
         if value == NextEthernetAddr:
             self.value = value
             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
 
+    def __call__(self, value):
+        self.__init__(value)
+        return value
+
     def unproxy(self, base):
         if self.value == NextEthernetAddr:
             return EthernetAddr(self.value())
         return self
 
     def getValue(self):
-        from m5.internal.params import EthAddr
+        from _m5.net import EthAddr
         return EthAddr(self.value)
 
+    def __str__(self):
+        return self.value
+
     def ini_str(self):
         return self.value
 
+    @classmethod
+    def cxx_ini_parse(self, code, src, dest, ret):
+        code('%s = Net::EthAddr(%s);' % (dest, src))
+        code('%s true;' % ret)
+
 # When initializing an IpAddress, pass in an existing IpAddress, a string of
 # the form "a.b.c.d", or an integer representing an IP.
 class IpAddress(ParamValue):
     cxx_type = 'Net::IpAddress'
+    ex_str = "127.0.0.1"
+    cmd_line_settable = True
 
     @classmethod
     def cxx_predecls(cls, code):
         code('#include "base/inet.hh"')
 
-    @classmethod
-    def swig_predecls(cls, code):
-        code('%include "python/swig/inet.i"')
-
     def __init__(self, value):
         if isinstance(value, IpAddress):
             self.ip = value.ip
@@ -737,6 +1024,10 @@ class IpAddress(ParamValue):
                 self.ip = long(value)
         self.verifyIp()
 
+    def __call__(self, value):
+        self.__init__(value)
+        return value
+
     def __str__(self):
         tup = [(self.ip >> i)  & 0xff for i in (24, 16, 8, 0)]
         return '%d.%d.%d.%d' % tuple(tup)
@@ -757,10 +1048,10 @@ 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.internal.params import IpAddress
+        from _m5.net import IpAddress
         return IpAddress(self.ip)
 
 # When initializing an IpNetmask, pass in an existing IpNetmask, a string of
@@ -768,15 +1059,13 @@ class IpAddress(ParamValue):
 # positional or keyword arguments.
 class IpNetmask(IpAddress):
     cxx_type = 'Net::IpNetmask'
+    ex_str = "127.0.0.0/24"
+    cmd_line_settable = True
 
     @classmethod
     def cxx_predecls(cls, code):
         code('#include "base/inet.hh"')
 
-    @classmethod
-    def swig_predecls(cls, code):
-        code('%include "python/swig/inet.i"')
-
     def __init__(self, *args, **kwargs):
         def handle_kwarg(self, kwargs, key, elseVal = None):
             if key in kwargs:
@@ -784,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')
@@ -793,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):
@@ -806,13 +1095,17 @@ 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()
 
+    def __call__(self, value):
+        self.__init__(value)
+        return value
+
     def __str__(self):
         return "%s/%d" % (super(IpNetmask, self).__str__(), self.netmask)
 
@@ -830,25 +1123,23 @@ 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.internal.params import IpNetmask
+        from _m5.net import IpNetmask
         return IpNetmask(self.ip, self.netmask)
 
 # When initializing an IpWithPort, pass in an existing IpWithPort, a string of
 # the form "a.b.c.d:p", or an ip and port as positional or keyword arguments.
 class IpWithPort(IpAddress):
     cxx_type = 'Net::IpWithPort'
+    ex_str = "127.0.0.1:80"
+    cmd_line_settable = True
 
     @classmethod
     def cxx_predecls(cls, code):
         code('#include "base/inet.hh"')
 
-    @classmethod
-    def swig_predecls(cls, code):
-        code('%include "python/swig/inet.i"')
-
     def __init__(self, *args, **kwargs):
         def handle_kwarg(self, kwargs, key, elseVal = None):
             if key in kwargs:
@@ -856,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')
@@ -865,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):
@@ -878,13 +1169,17 @@ 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()
 
+    def __call__(self, value):
+        self.__init__(value)
+        return value
+
     def __str__(self):
         return "%s:%d" % (super(IpWithPort, self).__str__(), self.port)
 
@@ -902,14 +1197,14 @@ 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.internal.params import IpWithPort
+        from _m5.net import IpWithPort
         return IpWithPort(self.ip, self.port)
 
 time_formats = [ "%a %b %d %H:%M:%S %Z %Y",
-                 "%a %b %d %H:%M:%S %Z %Y",
+                 "%a %b %d %H:%M:%S %Y",
                  "%Y/%m/%d %H:%M:%S",
                  "%Y/%m/%d %H:%M",
                  "%Y/%m/%d",
@@ -944,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'
@@ -953,38 +1248,18 @@ class Time(ParamValue):
     def cxx_predecls(cls, code):
         code('#include <time.h>')
 
-    @classmethod
-    def swig_predecls(cls, code):
-        code('%include "python/swig/time.i"')
-
     def __init__(self, value):
         self.value = parse_time(value)
 
-    def getValue(self):
-        from m5.internal.params import tm
-
-        c_time = tm()
-        py_time = self.value
-
-        # UNIX is years since 1900
-        c_time.tm_year = py_time.tm_year - 1900;
-
-        # Python starts at 1, UNIX starts at 0
-        c_time.tm_mon =  py_time.tm_mon - 1;
-        c_time.tm_mday = py_time.tm_mday;
-        c_time.tm_hour = py_time.tm_hour;
-        c_time.tm_min = py_time.tm_min;
-        c_time.tm_sec = py_time.tm_sec;
-
-        # Python has 0 as Monday, UNIX is 0 as sunday
-        c_time.tm_wday = py_time.tm_wday + 1
-        if c_time.tm_wday > 6:
-            c_time.tm_wday -= 7;
+    def __call__(self, value):
+        self.__init__(value)
+        return value
 
-        # Python starts at 1, Unix starts at 0
-        c_time.tm_yday = py_time.tm_yday - 1;
+    def getValue(self):
+        from _m5.core import tm
+        import calendar
 
-        return c_time
+        return tm.gmtime(calendar.timegm(self.value))
 
     def __str__(self):
         return time.asctime(self.value)
@@ -993,8 +1268,19 @@ class Time(ParamValue):
         return str(self)
 
     def get_config_as_dict(self):
+        assert false
         return str(self)
 
+    @classmethod
+    def cxx_ini_predecls(cls, code):
+        code('#include <time.h>')
+
+    @classmethod
+    def cxx_ini_parse(cls, code, src, dest, ret):
+        code('char *_parse_ret = strptime((${src}).c_str(),')
+        code('    "%a %b %d %H:%M:%S %Y", &(${dest}));')
+        code('${ret} _parse_ret && *_parse_ret == \'\\0\';');
+
 # Enumerated types are a little more complex.  The user specifies the
 # type as Enum(foo) where foo is either a list or dictionary of
 # alternatives (typically strings, but not necessarily so).  (In the
@@ -1020,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)
 
@@ -1047,101 +1336,220 @@ class MetaEnum(MetaParamValue):
     # Note that we wrap the enum in a class/struct to act as a namespace,
     # so that the enum strings can be brief w/o worrying about collisions.
     def cxx_decl(cls, code):
-        name = cls.__name__
+        wrapper_name = cls.wrapper_name
+        wrapper = 'struct' if cls.wrapper_is_struct else 'namespace'
+        name = cls.__name__ if cls.enum_name is None else cls.enum_name
+        idem_macro = '__ENUM__%s__%s__' % (wrapper_name, name)
+
         code('''\
-#ifndef __ENUM__${name}__
-#define __ENUM__${name}__
+#ifndef $idem_macro
+#define $idem_macro
 
-namespace Enums {
+''')
+        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('''\
-    };
-extern const char *${name}Strings[Num_${name}];
-}
+        code.dedent(1)
+        code('};')
 
-#endif // __ENUM__${name}__
+        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}];')
+
+        if not cls.is_class:
+            code.dedent(1)
+            code('};')
+
+        code()
+        code('#endif // $idem_macro')
 
     def cxx_def(cls, code):
-        name = cls.__name__
-        code('''\
-#include "enums/$name.hh"
-namespace Enums {
-    const char *${name}Strings[Num_${name}] =
-    {
+        wrapper_name = cls.wrapper_name
+        file_name = cls.__name__
+        name = cls.__name__ if cls.enum_name is None else cls.enum_name
+
+        code('#include "enums/$file_name.hh"')
+        if cls.wrapper_is_struct:
+            code('const char *${wrapper_name}::${name}Strings'
+                '[Num_${name}] =')
+        else:
+            if cls.is_class:
+                code('''\
+const char *${name}Strings[static_cast<int>(${name}::Num_${name})] =
 ''')
-        code.indent(2)
+            else:
+                code('namespace Enums {')
+                code.indent(1)
+                code('const char *${name}Strings[Num_${name}] =')
+
+        code('{')
+        code.indent(1)
         for val in cls.vals:
             code('"$val",')
-        code.dedent(2)
-        code('''
-    };
-} // namespace Enums
-''')
+        code.dedent(1)
+        code('};')
+
+        if not cls.wrapper_is_struct and not cls.is_class:
+            code.dedent(1)
+            code('} // namespace $wrapper_name')
 
-    def swig_decl(cls, code):
+
+    def pybind_def(cls, code):
         name = cls.__name__
-        code('''\
-%module(package="m5.internal") enum_$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"
+
+#include <sim/init.hh>
+
+namespace py = pybind11;
 
-%{
-#include "enums/$name.hh"
-%}
+static void
+module_init(py::module &m_internal)
+{
+    py::module m = m_internal.def_submodule("enum_${name}");
 
-%include "enums/$name.hh"
 ''')
+        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()
+        for val in cls.vals:
+            code('.value("${val}", ${wrapper_name}::${val})')
+        code('.value("Num_${name}", ${wrapper_name}::Num_${enum_name})')
+        code('.export_values()')
+        code(';')
+        code.dedent()
+
+        code('}')
+        code.dedent()
+        code()
+        code('static EmbeddedPyBind embed_enum("enum_${name}", module_init);')
 
 
 # Base class for enum types.
 class Enum(ParamValue):
     __metaclass__ = MetaEnum
     vals = []
+    cmd_line_settable = True
+
+    # The name of the wrapping namespace or struct
+    wrapper_name = 'Enums'
+
+    # 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):
+        self.__init__(value)
+        return value
+
     @classmethod
     def cxx_predecls(cls, code):
         code('#include "enums/$0.hh"', cls.__name__)
 
     @classmethod
-    def swig_predecls(cls, code):
-        code('%import "python/m5/internal/enum_$0.i"', cls.__name__)
+    def cxx_ini_parse(cls, code, src, dest, ret):
+        code('if (false) {')
+        for elem_name in cls.map.keys():
+            code('} else if (%s == "%s") {' % (src, elem_name))
+            code.indent()
+            code('%s = Enums::%s;' % (dest, elem_name))
+            code('%s true;' % ret)
+            code.dedent()
+        code('} else {')
+        code('    %s false;' % ret)
+        code('}')
 
     def getValue(self):
-        return int(self.map[self.value])
+        import m5.internal.params
+        e = getattr(m5.internal.params, "enum_%s" % self.__class__.__name__)
+        return e(self.map[self.value])
 
     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%
 
 class TickParamValue(NumericParamValue):
     cxx_type = 'Tick'
+    ex_str = "1MHz"
+    cmd_line_settable = True
 
     @classmethod
     def cxx_predecls(cls, code):
         code('#include "base/types.hh"')
 
-    @classmethod
-    def swig_predecls(cls, code):
-        code('%import "stdint.i"')
-        code('%import "base/types.hh"')
+    def __call__(self, value):
+        self.__init__(value)
+        return value
 
     def getValue(self):
         return long(self.value)
 
+    @classmethod
+    def cxx_ini_predecls(cls, code):
+        code('#include <sstream>')
+
+    # Ticks are expressed in seconds in JSON files and in plain
+    # Ticks in .ini files.  Switch based on a config flag
+    @classmethod
+    def cxx_ini_parse(self, code, src, dest, ret):
+        code('${ret} to_number(${src}, ${dest});')
+
 class Latency(TickParamValue):
+    ex_str = "100ns"
+
     def __init__(self, value):
         if isinstance(value, (Latency, Clock)):
             self.ticks = value.ticks
@@ -1156,12 +1564,16 @@ class Latency(TickParamValue):
             self.ticks = False
             self.value = convert.toLatency(value)
 
+    def __call__(self, value):
+        self.__init__(value)
+        return value
+
     def __getattr__(self, attr):
         if attr in ('latency', 'period'):
             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:
@@ -1170,11 +1582,16 @@ class Latency(TickParamValue):
             value = ticks.fromSeconds(self.value)
         return long(value)
 
+    def config_value(self):
+        return self.getValue()
+
     # convert latency to ticks
     def ini_str(self):
         return '%d' % self.getValue()
 
 class Frequency(TickParamValue):
+    ex_str = "1GHz"
+
     def __init__(self, value):
         if isinstance(value, (Latency, Clock)):
             if value.value == 0:
@@ -1189,12 +1606,16 @@ class Frequency(TickParamValue):
             self.ticks = False
             self.value = convert.toFrequency(value)
 
+    def __call__(self, value):
+        self.__init__(value)
+        return value
+
     def __getattr__(self, attr):
         if attr == 'frequency':
             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):
@@ -1204,25 +1625,15 @@ class Frequency(TickParamValue):
             value = ticks.fromSeconds(1.0 / self.value)
         return long(value)
 
+    def config_value(self):
+        return self.getValue()
+
     def ini_str(self):
         return '%d' % self.getValue()
 
-# A generic frequency and/or Latency value. Value is stored as a
-# latency, and any manipulation using a multiplier thus scales the
-# clock period, i.e. a 2x multiplier doubles the clock period and thus
-# halves the clock frequency.
-class Clock(ParamValue):
-    cxx_type = 'Tick'
-
-    @classmethod
-    def cxx_predecls(cls, code):
-        code('#include "base/types.hh"')
-
-    @classmethod
-    def swig_predecls(cls, code):
-        code('%import "stdint.i"')
-        code('%import "base/types.hh"')
-
+# A generic Frequency and/or Latency value. Value is stored as a
+# latency, just like Latency and Frequency.
+class Clock(TickParamValue):
     def __init__(self, value):
         if isinstance(value, (Latency, Clock)):
             self.ticks = value.ticks
@@ -1237,38 +1648,67 @@ class Clock(ParamValue):
             self.ticks = False
             self.value = convert.anyToLatency(value)
 
+    def __call__(self, value):
+        self.__init__(value)
+        return value
+
+    def __str__(self):
+        return "%s" % Latency(self)
+
     def __getattr__(self, attr):
         if attr == 'frequency':
             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()
 
+    def config_value(self):
+        return self.period.config_value()
+
     def ini_str(self):
         return self.period.ini_str()
 
-class Voltage(float,ParamValue):
-    cxx_type = 'double'
+class Voltage(Float):
+    ex_str = "1V"
+
     def __new__(cls, value):
-        # convert to voltage
-        val = convert.toVoltage(value)
-        return super(cls, Voltage).__new__(cls, val)
+        value = convert.toVoltage(value)
+        return super(cls, Voltage).__new__(cls, value)
 
-    def __str__(self):
-        return str(self.val)
+    def __init__(self, value):
+        value = convert.toVoltage(value)
+        super(Voltage, self).__init__(value)
 
-    def getValue(self):
-        value = float(self)
-        return value
+class Current(Float):
+    ex_str = "1mA"
 
-    def ini_str(self):
-        return '%f' % self.getValue()
+    def __new__(cls, value):
+        value = convert.toCurrent(value)
+        return super(cls, Current).__new__(cls, value)
+
+    def __init__(self, value):
+        value = convert.toCurrent(value)
+        super(Current, self).__init__(value)
+
+class Energy(Float):
+    ex_str = "1pJ"
+
+    def __new__(cls, value):
+        value = convert.toEnergy(value)
+        return super(cls, Energy).__new__(cls, value)
+
+    def __init__(self, value):
+        value = convert.toEnergy(value)
+        super(Energy, self).__init__(value)
 
 class NetworkBandwidth(float,ParamValue):
     cxx_type = 'float'
+    ex_str = "1Gbps"
+    cmd_line_settable = True
+
     def __new__(cls, value):
         # convert to bits per second
         val = convert.toNetworkBandwidth(value)
@@ -1277,6 +1717,11 @@ class NetworkBandwidth(float,ParamValue):
     def __str__(self):
         return str(self.val)
 
+    def __call__(self, value):
+        val = convert.toNetworkBandwidth(value)
+        self.__init__(val)
+        return value
+
     def getValue(self):
         # convert to seconds per byte
         value = 8.0 / float(self)
@@ -1287,15 +1732,31 @@ class NetworkBandwidth(float,ParamValue):
     def ini_str(self):
         return '%f' % self.getValue()
 
+    def config_value(self):
+        return '%f' % self.getValue()
+
+    @classmethod
+    def cxx_ini_predecls(cls, code):
+        code('#include <sstream>')
+
+    @classmethod
+    def cxx_ini_parse(self, code, src, dest, ret):
+        code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
+
 class MemoryBandwidth(float,ParamValue):
     cxx_type = 'float'
+    ex_str = "1GB/s"
+    cmd_line_settable = True
+
     def __new__(cls, value):
         # convert to bytes per second
         val = convert.toMemoryBandwidth(value)
         return super(cls, MemoryBandwidth).__new__(cls, val)
 
-    def __str__(self):
-        return str(self.val)
+    def __call__(self, value):
+        val = convert.toMemoryBandwidth(value)
+        self.__init__(val)
+        return value
 
     def getValue(self):
         # convert to seconds per byte
@@ -1309,6 +1770,17 @@ class MemoryBandwidth(float,ParamValue):
     def ini_str(self):
         return '%f' % self.getValue()
 
+    def config_value(self):
+        return '%f' % self.getValue()
+
+    @classmethod
+    def cxx_ini_predecls(cls, code):
+        code('#include <sstream>')
+
+    @classmethod
+    def cxx_ini_parse(self, code, src, dest, ret):
+        code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
+
 #
 # "Constants"... handy aliases for various values.
 #
@@ -1319,6 +1791,7 @@ class MemoryBandwidth(float,ParamValue):
 # only one copy of a particular node
 class NullSimObject(object):
     __metaclass__ = Singleton
+    _name = 'Null'
 
     def __call__(cls):
         return cls
@@ -1335,8 +1808,24 @@ class NullSimObject(object):
     def set_path(self, parent, name):
         pass
 
+    def set_parent(self, parent, name):
+        pass
+
+    def clear_parent(self, old_parent):
+        pass
+
+    def descendants(self):
+        return
+        yield None
+
+    def get_config_as_dict(self):
+        return {}
+
     def __str__(self):
-        return 'Null'
+        return self._name
+
+    def config_value(self):
+        return None
 
     def getValue(self):
         return None
@@ -1364,11 +1853,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
@@ -1387,14 +1877,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.,
@@ -1408,18 +1899,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)
+            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:
-            raise TypeError, \
-                  "assigning non-port reference '%s' to port '%s'" \
-                  % (other, self)
+            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
@@ -1437,48 +1964,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.internal.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):
@@ -1487,11 +1997,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):
@@ -1509,14 +2020,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]
@@ -1526,7 +2039,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):
@@ -1541,7 +2054,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
@@ -1560,10 +2073,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
@@ -1575,58 +2109,50 @@ class Port(object):
     def cxx_predecls(self, code):
         pass
 
+    def pybind_predecls(self, code):
+        cls.cxx_predecls(self, code)
+
     # Declare an unsigned int with the same name as the port, that
     # will eventually hold the number of connected ports (and thus the
     # number of elements for a VectorPort).
     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 Bus).
+# 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
@@ -1647,20 +2173,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