params.py revision 3885
13101Sstever@eecs.umich.edu# Copyright (c) 2004-2006 The Regents of The University of Michigan
23101Sstever@eecs.umich.edu# All rights reserved.
33101Sstever@eecs.umich.edu#
43101Sstever@eecs.umich.edu# Redistribution and use in source and binary forms, with or without
53101Sstever@eecs.umich.edu# modification, are permitted provided that the following conditions are
63101Sstever@eecs.umich.edu# met: redistributions of source code must retain the above copyright
73101Sstever@eecs.umich.edu# notice, this list of conditions and the following disclaimer;
83101Sstever@eecs.umich.edu# redistributions in binary form must reproduce the above copyright
93101Sstever@eecs.umich.edu# notice, this list of conditions and the following disclaimer in the
103101Sstever@eecs.umich.edu# documentation and/or other materials provided with the distribution;
113101Sstever@eecs.umich.edu# neither the name of the copyright holders nor the names of its
123101Sstever@eecs.umich.edu# contributors may be used to endorse or promote products derived from
133101Sstever@eecs.umich.edu# this software without specific prior written permission.
143101Sstever@eecs.umich.edu#
153101Sstever@eecs.umich.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
163101Sstever@eecs.umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
173101Sstever@eecs.umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
183101Sstever@eecs.umich.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
193101Sstever@eecs.umich.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
203101Sstever@eecs.umich.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
213101Sstever@eecs.umich.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
223101Sstever@eecs.umich.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
233101Sstever@eecs.umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
243101Sstever@eecs.umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
253101Sstever@eecs.umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
263101Sstever@eecs.umich.edu#
273101Sstever@eecs.umich.edu# Authors: Steve Reinhardt
283101Sstever@eecs.umich.edu#          Nathan Binkert
293101Sstever@eecs.umich.edu
303101Sstever@eecs.umich.edu#####################################################################
313101Sstever@eecs.umich.edu#
323101Sstever@eecs.umich.edu# Parameter description classes
333101Sstever@eecs.umich.edu#
343101Sstever@eecs.umich.edu# The _params dictionary in each class maps parameter names to either
353101Sstever@eecs.umich.edu# a Param or a VectorParam object.  These objects contain the
363101Sstever@eecs.umich.edu# parameter description string, the parameter type, and the default
373101Sstever@eecs.umich.edu# value (if any).  The convert() method on these objects is used to
383101Sstever@eecs.umich.edu# force whatever value is assigned to the parameter to the appropriate
393101Sstever@eecs.umich.edu# type.
403101Sstever@eecs.umich.edu#
413101Sstever@eecs.umich.edu# Note that the default values are loaded into the class's attribute
423101Sstever@eecs.umich.edu# space when the parameter dictionary is initialized (in
433101Sstever@eecs.umich.edu# MetaSimObject._new_param()); after that point they aren't used.
443101Sstever@eecs.umich.edu#
453101Sstever@eecs.umich.edu#####################################################################
463101Sstever@eecs.umich.edu
473885Sbinkertn@umich.eduimport copy
483885Sbinkertn@umich.eduimport datetime
493885Sbinkertn@umich.eduimport inspect
503885Sbinkertn@umich.eduimport sys
513885Sbinkertn@umich.eduimport time
523885Sbinkertn@umich.edu
533101Sstever@eecs.umich.eduimport convert
543102Sstever@eecs.umich.edufrom util import *
553101Sstever@eecs.umich.edu
563101Sstever@eecs.umich.edu# Dummy base class to identify types that are legitimate for SimObject
573101Sstever@eecs.umich.edu# parameters.
583101Sstever@eecs.umich.educlass ParamValue(object):
593101Sstever@eecs.umich.edu
603101Sstever@eecs.umich.edu    cxx_predecls = []
613101Sstever@eecs.umich.edu    swig_predecls = []
623101Sstever@eecs.umich.edu
633101Sstever@eecs.umich.edu    # default for printing to .ini file is regular string conversion.
643101Sstever@eecs.umich.edu    # will be overridden in some cases
653101Sstever@eecs.umich.edu    def ini_str(self):
663101Sstever@eecs.umich.edu        return str(self)
673101Sstever@eecs.umich.edu
683101Sstever@eecs.umich.edu    # allows us to blithely call unproxy() on things without checking
693101Sstever@eecs.umich.edu    # if they're really proxies or not
703101Sstever@eecs.umich.edu    def unproxy(self, base):
713101Sstever@eecs.umich.edu        return self
723101Sstever@eecs.umich.edu
733101Sstever@eecs.umich.edu# Regular parameter description.
743101Sstever@eecs.umich.educlass ParamDesc(object):
753101Sstever@eecs.umich.edu    def __init__(self, ptype_str, ptype, *args, **kwargs):
763101Sstever@eecs.umich.edu        self.ptype_str = ptype_str
773101Sstever@eecs.umich.edu        # remember ptype only if it is provided
783101Sstever@eecs.umich.edu        if ptype != None:
793101Sstever@eecs.umich.edu            self.ptype = ptype
803101Sstever@eecs.umich.edu
813101Sstever@eecs.umich.edu        if args:
823101Sstever@eecs.umich.edu            if len(args) == 1:
833101Sstever@eecs.umich.edu                self.desc = args[0]
843101Sstever@eecs.umich.edu            elif len(args) == 2:
853101Sstever@eecs.umich.edu                self.default = args[0]
863101Sstever@eecs.umich.edu                self.desc = args[1]
873101Sstever@eecs.umich.edu            else:
883101Sstever@eecs.umich.edu                raise TypeError, 'too many arguments'
893101Sstever@eecs.umich.edu
903101Sstever@eecs.umich.edu        if kwargs.has_key('desc'):
913101Sstever@eecs.umich.edu            assert(not hasattr(self, 'desc'))
923101Sstever@eecs.umich.edu            self.desc = kwargs['desc']
933101Sstever@eecs.umich.edu            del kwargs['desc']
943101Sstever@eecs.umich.edu
953101Sstever@eecs.umich.edu        if kwargs.has_key('default'):
963101Sstever@eecs.umich.edu            assert(not hasattr(self, 'default'))
973101Sstever@eecs.umich.edu            self.default = kwargs['default']
983101Sstever@eecs.umich.edu            del kwargs['default']
993101Sstever@eecs.umich.edu
1003101Sstever@eecs.umich.edu        if kwargs:
1013101Sstever@eecs.umich.edu            raise TypeError, 'extra unknown kwargs %s' % kwargs
1023101Sstever@eecs.umich.edu
1033101Sstever@eecs.umich.edu        if not hasattr(self, 'desc'):
1043101Sstever@eecs.umich.edu            raise TypeError, 'desc attribute missing'
1053101Sstever@eecs.umich.edu
1063101Sstever@eecs.umich.edu    def __getattr__(self, attr):
1073101Sstever@eecs.umich.edu        if attr == 'ptype':
1083101Sstever@eecs.umich.edu            try:
1093102Sstever@eecs.umich.edu                ptype = eval(self.ptype_str, objects.__dict__)
1103101Sstever@eecs.umich.edu                if not isinstance(ptype, type):
1113102Sstever@eecs.umich.edu                    raise NameError
1123101Sstever@eecs.umich.edu                self.ptype = ptype
1133101Sstever@eecs.umich.edu                return ptype
1143101Sstever@eecs.umich.edu            except NameError:
1153102Sstever@eecs.umich.edu                raise TypeError, \
1163102Sstever@eecs.umich.edu                      "Param qualifier '%s' is not a type" % self.ptype_str
1173101Sstever@eecs.umich.edu        raise AttributeError, "'%s' object has no attribute '%s'" % \
1183101Sstever@eecs.umich.edu              (type(self).__name__, attr)
1193101Sstever@eecs.umich.edu
1203101Sstever@eecs.umich.edu    def convert(self, value):
1213101Sstever@eecs.umich.edu        if isinstance(value, proxy.BaseProxy):
1223101Sstever@eecs.umich.edu            value.set_param_desc(self)
1233101Sstever@eecs.umich.edu            return value
1243101Sstever@eecs.umich.edu        if not hasattr(self, 'ptype') and isNullPointer(value):
1253101Sstever@eecs.umich.edu            # deferred evaluation of SimObject; continue to defer if
1263101Sstever@eecs.umich.edu            # we're just assigning a null pointer
1273101Sstever@eecs.umich.edu            return value
1283101Sstever@eecs.umich.edu        if isinstance(value, self.ptype):
1293101Sstever@eecs.umich.edu            return value
1303102Sstever@eecs.umich.edu        if isNullPointer(value) and isSimObjectClass(self.ptype):
1313101Sstever@eecs.umich.edu            return value
1323101Sstever@eecs.umich.edu        return self.ptype(value)
1333101Sstever@eecs.umich.edu
1343101Sstever@eecs.umich.edu    def cxx_predecls(self):
1353101Sstever@eecs.umich.edu        return self.ptype.cxx_predecls
1363101Sstever@eecs.umich.edu
1373101Sstever@eecs.umich.edu    def swig_predecls(self):
1383101Sstever@eecs.umich.edu        return self.ptype.swig_predecls
1393101Sstever@eecs.umich.edu
1403101Sstever@eecs.umich.edu    def cxx_decl(self):
1413101Sstever@eecs.umich.edu        return '%s %s;' % (self.ptype.cxx_type, self.name)
1423101Sstever@eecs.umich.edu
1433101Sstever@eecs.umich.edu# Vector-valued parameter description.  Just like ParamDesc, except
1443101Sstever@eecs.umich.edu# that the value is a vector (list) of the specified type instead of a
1453101Sstever@eecs.umich.edu# single value.
1463101Sstever@eecs.umich.edu
1473101Sstever@eecs.umich.educlass VectorParamValue(list):
1483101Sstever@eecs.umich.edu    def ini_str(self):
1493101Sstever@eecs.umich.edu        return ' '.join([v.ini_str() for v in self])
1503101Sstever@eecs.umich.edu
1513101Sstever@eecs.umich.edu    def unproxy(self, base):
1523101Sstever@eecs.umich.edu        return [v.unproxy(base) for v in self]
1533101Sstever@eecs.umich.edu
1543101Sstever@eecs.umich.educlass SimObjVector(VectorParamValue):
1553101Sstever@eecs.umich.edu    def print_ini(self):
1563101Sstever@eecs.umich.edu        for v in self:
1573101Sstever@eecs.umich.edu            v.print_ini()
1583101Sstever@eecs.umich.edu
1593101Sstever@eecs.umich.educlass VectorParamDesc(ParamDesc):
1603101Sstever@eecs.umich.edu    # Convert assigned value to appropriate type.  If the RHS is not a
1613101Sstever@eecs.umich.edu    # list or tuple, it generates a single-element list.
1623101Sstever@eecs.umich.edu    def convert(self, value):
1633101Sstever@eecs.umich.edu        if isinstance(value, (list, tuple)):
1643101Sstever@eecs.umich.edu            # list: coerce each element into new list
1653101Sstever@eecs.umich.edu            tmp_list = [ ParamDesc.convert(self, v) for v in value ]
1663101Sstever@eecs.umich.edu            if isSimObjectSequence(tmp_list):
1673101Sstever@eecs.umich.edu                return SimObjVector(tmp_list)
1683101Sstever@eecs.umich.edu            else:
1693101Sstever@eecs.umich.edu                return VectorParamValue(tmp_list)
1703101Sstever@eecs.umich.edu        else:
1713101Sstever@eecs.umich.edu            # singleton: leave it be (could coerce to a single-element
1723101Sstever@eecs.umich.edu            # list here, but for some historical reason we don't...
1733101Sstever@eecs.umich.edu            return ParamDesc.convert(self, value)
1743101Sstever@eecs.umich.edu
1753101Sstever@eecs.umich.edu    def cxx_predecls(self):
1763101Sstever@eecs.umich.edu        return ['#include <vector>'] + self.ptype.cxx_predecls
1773101Sstever@eecs.umich.edu
1783101Sstever@eecs.umich.edu    def swig_predecls(self):
1793101Sstever@eecs.umich.edu        return ['%include "std_vector.i"'] + self.ptype.swig_predecls
1803101Sstever@eecs.umich.edu
1813101Sstever@eecs.umich.edu    def cxx_decl(self):
1823101Sstever@eecs.umich.edu        return 'std::vector< %s > %s;' % (self.ptype.cxx_type, self.name)
1833101Sstever@eecs.umich.edu
1843101Sstever@eecs.umich.educlass ParamFactory(object):
1853101Sstever@eecs.umich.edu    def __init__(self, param_desc_class, ptype_str = None):
1863101Sstever@eecs.umich.edu        self.param_desc_class = param_desc_class
1873101Sstever@eecs.umich.edu        self.ptype_str = ptype_str
1883101Sstever@eecs.umich.edu
1893101Sstever@eecs.umich.edu    def __getattr__(self, attr):
1903101Sstever@eecs.umich.edu        if self.ptype_str:
1913101Sstever@eecs.umich.edu            attr = self.ptype_str + '.' + attr
1923101Sstever@eecs.umich.edu        return ParamFactory(self.param_desc_class, attr)
1933101Sstever@eecs.umich.edu
1943101Sstever@eecs.umich.edu    # E.g., Param.Int(5, "number of widgets")
1953101Sstever@eecs.umich.edu    def __call__(self, *args, **kwargs):
1963101Sstever@eecs.umich.edu        caller_frame = inspect.currentframe().f_back
1973101Sstever@eecs.umich.edu        ptype = None
1983101Sstever@eecs.umich.edu        try:
1993101Sstever@eecs.umich.edu            ptype = eval(self.ptype_str,
2003101Sstever@eecs.umich.edu                         caller_frame.f_globals, caller_frame.f_locals)
2013101Sstever@eecs.umich.edu            if not isinstance(ptype, type):
2023101Sstever@eecs.umich.edu                raise TypeError, \
2033101Sstever@eecs.umich.edu                      "Param qualifier is not a type: %s" % ptype
2043101Sstever@eecs.umich.edu        except NameError:
2053101Sstever@eecs.umich.edu            # if name isn't defined yet, assume it's a SimObject, and
2063101Sstever@eecs.umich.edu            # try to resolve it later
2073101Sstever@eecs.umich.edu            pass
2083101Sstever@eecs.umich.edu        return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs)
2093101Sstever@eecs.umich.edu
2103101Sstever@eecs.umich.eduParam = ParamFactory(ParamDesc)
2113101Sstever@eecs.umich.eduVectorParam = ParamFactory(VectorParamDesc)
2123101Sstever@eecs.umich.edu
2133101Sstever@eecs.umich.edu#####################################################################
2143101Sstever@eecs.umich.edu#
2153101Sstever@eecs.umich.edu# Parameter Types
2163101Sstever@eecs.umich.edu#
2173101Sstever@eecs.umich.edu# Though native Python types could be used to specify parameter types
2183101Sstever@eecs.umich.edu# (the 'ptype' field of the Param and VectorParam classes), it's more
2193101Sstever@eecs.umich.edu# flexible to define our own set of types.  This gives us more control
2203101Sstever@eecs.umich.edu# over how Python expressions are converted to values (via the
2213101Sstever@eecs.umich.edu# __init__() constructor) and how these values are printed out (via
2223101Sstever@eecs.umich.edu# the __str__() conversion method).
2233101Sstever@eecs.umich.edu#
2243101Sstever@eecs.umich.edu#####################################################################
2253101Sstever@eecs.umich.edu
2263101Sstever@eecs.umich.edu# String-valued parameter.  Just mixin the ParamValue class with the
2273101Sstever@eecs.umich.edu# built-in str class.
2283101Sstever@eecs.umich.educlass String(ParamValue,str):
2293101Sstever@eecs.umich.edu    cxx_type = 'std::string'
2303101Sstever@eecs.umich.edu    cxx_predecls = ['#include <string>']
2313101Sstever@eecs.umich.edu    swig_predecls = ['%include "std_string.i"\n' +
2323101Sstever@eecs.umich.edu                     '%apply const std::string& {std::string *};']
2333101Sstever@eecs.umich.edu    pass
2343101Sstever@eecs.umich.edu
2353101Sstever@eecs.umich.edu# superclass for "numeric" parameter values, to emulate math
2363101Sstever@eecs.umich.edu# operations in a type-safe way.  e.g., a Latency times an int returns
2373101Sstever@eecs.umich.edu# a new Latency object.
2383101Sstever@eecs.umich.educlass NumericParamValue(ParamValue):
2393101Sstever@eecs.umich.edu    def __str__(self):
2403101Sstever@eecs.umich.edu        return str(self.value)
2413101Sstever@eecs.umich.edu
2423101Sstever@eecs.umich.edu    def __float__(self):
2433101Sstever@eecs.umich.edu        return float(self.value)
2443101Sstever@eecs.umich.edu
2453714Sstever@eecs.umich.edu    def __long__(self):
2463714Sstever@eecs.umich.edu        return long(self.value)
2473714Sstever@eecs.umich.edu
2483714Sstever@eecs.umich.edu    def __int__(self):
2493714Sstever@eecs.umich.edu        return int(self.value)
2503714Sstever@eecs.umich.edu
2513101Sstever@eecs.umich.edu    # hook for bounds checking
2523101Sstever@eecs.umich.edu    def _check(self):
2533101Sstever@eecs.umich.edu        return
2543101Sstever@eecs.umich.edu
2553101Sstever@eecs.umich.edu    def __mul__(self, other):
2563101Sstever@eecs.umich.edu        newobj = self.__class__(self)
2573101Sstever@eecs.umich.edu        newobj.value *= other
2583101Sstever@eecs.umich.edu        newobj._check()
2593101Sstever@eecs.umich.edu        return newobj
2603101Sstever@eecs.umich.edu
2613101Sstever@eecs.umich.edu    __rmul__ = __mul__
2623101Sstever@eecs.umich.edu
2633101Sstever@eecs.umich.edu    def __div__(self, other):
2643101Sstever@eecs.umich.edu        newobj = self.__class__(self)
2653101Sstever@eecs.umich.edu        newobj.value /= other
2663101Sstever@eecs.umich.edu        newobj._check()
2673101Sstever@eecs.umich.edu        return newobj
2683101Sstever@eecs.umich.edu
2693101Sstever@eecs.umich.edu    def __sub__(self, other):
2703101Sstever@eecs.umich.edu        newobj = self.__class__(self)
2713101Sstever@eecs.umich.edu        newobj.value -= other
2723101Sstever@eecs.umich.edu        newobj._check()
2733101Sstever@eecs.umich.edu        return newobj
2743101Sstever@eecs.umich.edu
2753101Sstever@eecs.umich.edu# Metaclass for bounds-checked integer parameters.  See CheckedInt.
2763101Sstever@eecs.umich.educlass CheckedIntType(type):
2773101Sstever@eecs.umich.edu    def __init__(cls, name, bases, dict):
2783101Sstever@eecs.umich.edu        super(CheckedIntType, cls).__init__(name, bases, dict)
2793101Sstever@eecs.umich.edu
2803101Sstever@eecs.umich.edu        # CheckedInt is an abstract base class, so we actually don't
2813101Sstever@eecs.umich.edu        # want to do any processing on it... the rest of this code is
2823101Sstever@eecs.umich.edu        # just for classes that derive from CheckedInt.
2833101Sstever@eecs.umich.edu        if name == 'CheckedInt':
2843101Sstever@eecs.umich.edu            return
2853101Sstever@eecs.umich.edu
2863101Sstever@eecs.umich.edu        if not cls.cxx_predecls:
2873101Sstever@eecs.umich.edu            # most derived types require this, so we just do it here once
2883101Sstever@eecs.umich.edu            cls.cxx_predecls = ['#include "sim/host.hh"']
2893101Sstever@eecs.umich.edu
2903101Sstever@eecs.umich.edu        if not cls.swig_predecls:
2913101Sstever@eecs.umich.edu            # most derived types require this, so we just do it here once
2923101Sstever@eecs.umich.edu            cls.swig_predecls = ['%import "python/m5/swig/stdint.i"\n' +
2933101Sstever@eecs.umich.edu                                 '%import "sim/host.hh"']
2943101Sstever@eecs.umich.edu
2953101Sstever@eecs.umich.edu        if not (hasattr(cls, 'min') and hasattr(cls, 'max')):
2963101Sstever@eecs.umich.edu            if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')):
2973101Sstever@eecs.umich.edu                panic("CheckedInt subclass %s must define either\n" \
2983101Sstever@eecs.umich.edu                      "    'min' and 'max' or 'size' and 'unsigned'\n" \
2993101Sstever@eecs.umich.edu                      % name);
3003101Sstever@eecs.umich.edu            if cls.unsigned:
3013101Sstever@eecs.umich.edu                cls.min = 0
3023101Sstever@eecs.umich.edu                cls.max = 2 ** cls.size - 1
3033101Sstever@eecs.umich.edu            else:
3043101Sstever@eecs.umich.edu                cls.min = -(2 ** (cls.size - 1))
3053101Sstever@eecs.umich.edu                cls.max = (2 ** (cls.size - 1)) - 1
3063101Sstever@eecs.umich.edu
3073101Sstever@eecs.umich.edu# Abstract superclass for bounds-checked integer parameters.  This
3083101Sstever@eecs.umich.edu# class is subclassed to generate parameter classes with specific
3093101Sstever@eecs.umich.edu# bounds.  Initialization of the min and max bounds is done in the
3103101Sstever@eecs.umich.edu# metaclass CheckedIntType.__init__.
3113101Sstever@eecs.umich.educlass CheckedInt(NumericParamValue):
3123101Sstever@eecs.umich.edu    __metaclass__ = CheckedIntType
3133101Sstever@eecs.umich.edu
3143101Sstever@eecs.umich.edu    def _check(self):
3153101Sstever@eecs.umich.edu        if not self.min <= self.value <= self.max:
3163101Sstever@eecs.umich.edu            raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
3173101Sstever@eecs.umich.edu                  (self.min, self.value, self.max)
3183101Sstever@eecs.umich.edu
3193101Sstever@eecs.umich.edu    def __init__(self, value):
3203101Sstever@eecs.umich.edu        if isinstance(value, str):
3213102Sstever@eecs.umich.edu            self.value = convert.toInteger(value)
3223714Sstever@eecs.umich.edu        elif isinstance(value, (int, long, float, NumericParamValue)):
3233101Sstever@eecs.umich.edu            self.value = long(value)
3243714Sstever@eecs.umich.edu        else:
3253714Sstever@eecs.umich.edu            raise TypeError, "Can't convert object of type %s to CheckedInt" \
3263714Sstever@eecs.umich.edu                  % type(value).__name__
3273101Sstever@eecs.umich.edu        self._check()
3283101Sstever@eecs.umich.edu
3293101Sstever@eecs.umich.educlass Int(CheckedInt):      cxx_type = 'int';      size = 32; unsigned = False
3303101Sstever@eecs.umich.educlass Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True
3313101Sstever@eecs.umich.edu
3323101Sstever@eecs.umich.educlass Int8(CheckedInt):     cxx_type =   'int8_t'; size =  8; unsigned = False
3333101Sstever@eecs.umich.educlass UInt8(CheckedInt):    cxx_type =  'uint8_t'; size =  8; unsigned = True
3343101Sstever@eecs.umich.educlass Int16(CheckedInt):    cxx_type =  'int16_t'; size = 16; unsigned = False
3353101Sstever@eecs.umich.educlass UInt16(CheckedInt):   cxx_type = 'uint16_t'; size = 16; unsigned = True
3363101Sstever@eecs.umich.educlass Int32(CheckedInt):    cxx_type =  'int32_t'; size = 32; unsigned = False
3373101Sstever@eecs.umich.educlass UInt32(CheckedInt):   cxx_type = 'uint32_t'; size = 32; unsigned = True
3383101Sstever@eecs.umich.educlass Int64(CheckedInt):    cxx_type =  'int64_t'; size = 64; unsigned = False
3393101Sstever@eecs.umich.educlass UInt64(CheckedInt):   cxx_type = 'uint64_t'; size = 64; unsigned = True
3403101Sstever@eecs.umich.edu
3413101Sstever@eecs.umich.educlass Counter(CheckedInt):  cxx_type = 'Counter';  size = 64; unsigned = True
3423101Sstever@eecs.umich.educlass Tick(CheckedInt):     cxx_type = 'Tick';     size = 64; unsigned = True
3433101Sstever@eecs.umich.educlass TcpPort(CheckedInt):  cxx_type = 'uint16_t'; size = 16; unsigned = True
3443101Sstever@eecs.umich.educlass UdpPort(CheckedInt):  cxx_type = 'uint16_t'; size = 16; unsigned = True
3453101Sstever@eecs.umich.edu
3463101Sstever@eecs.umich.educlass Percent(CheckedInt):  cxx_type = 'int'; min = 0; max = 100
3473101Sstever@eecs.umich.edu
3483101Sstever@eecs.umich.educlass Float(ParamValue, float):
3493101Sstever@eecs.umich.edu    pass
3503101Sstever@eecs.umich.edu
3513101Sstever@eecs.umich.educlass MemorySize(CheckedInt):
3523101Sstever@eecs.umich.edu    cxx_type = 'uint64_t'
3533101Sstever@eecs.umich.edu    size = 64
3543101Sstever@eecs.umich.edu    unsigned = True
3553101Sstever@eecs.umich.edu    def __init__(self, value):
3563101Sstever@eecs.umich.edu        if isinstance(value, MemorySize):
3573101Sstever@eecs.umich.edu            self.value = value.value
3583101Sstever@eecs.umich.edu        else:
3593102Sstever@eecs.umich.edu            self.value = convert.toMemorySize(value)
3603101Sstever@eecs.umich.edu        self._check()
3613101Sstever@eecs.umich.edu
3623101Sstever@eecs.umich.educlass MemorySize32(CheckedInt):
3633101Sstever@eecs.umich.edu    size = 32
3643101Sstever@eecs.umich.edu    unsigned = True
3653101Sstever@eecs.umich.edu    def __init__(self, value):
3663101Sstever@eecs.umich.edu        if isinstance(value, MemorySize):
3673101Sstever@eecs.umich.edu            self.value = value.value
3683101Sstever@eecs.umich.edu        else:
3693102Sstever@eecs.umich.edu            self.value = convert.toMemorySize(value)
3703101Sstever@eecs.umich.edu        self._check()
3713101Sstever@eecs.umich.edu
3723101Sstever@eecs.umich.educlass Addr(CheckedInt):
3733101Sstever@eecs.umich.edu    cxx_type = 'Addr'
3743101Sstever@eecs.umich.edu    cxx_predecls = ['#include "targetarch/isa_traits.hh"']
3753101Sstever@eecs.umich.edu    size = 64
3763101Sstever@eecs.umich.edu    unsigned = True
3773101Sstever@eecs.umich.edu    def __init__(self, value):
3783101Sstever@eecs.umich.edu        if isinstance(value, Addr):
3793101Sstever@eecs.umich.edu            self.value = value.value
3803101Sstever@eecs.umich.edu        else:
3813101Sstever@eecs.umich.edu            try:
3823102Sstever@eecs.umich.edu                self.value = convert.toMemorySize(value)
3833101Sstever@eecs.umich.edu            except TypeError:
3843101Sstever@eecs.umich.edu                self.value = long(value)
3853101Sstever@eecs.umich.edu        self._check()
3863584Ssaidi@eecs.umich.edu    def __add__(self, other):
3873584Ssaidi@eecs.umich.edu        if isinstance(other, Addr):
3883584Ssaidi@eecs.umich.edu            return self.value + other.value
3893584Ssaidi@eecs.umich.edu        else:
3903584Ssaidi@eecs.umich.edu            return self.value + other
3913101Sstever@eecs.umich.edu
3923101Sstever@eecs.umich.edu
3933101Sstever@eecs.umich.educlass MetaRange(type):
3943101Sstever@eecs.umich.edu    def __init__(cls, name, bases, dict):
3953101Sstever@eecs.umich.edu        super(MetaRange, cls).__init__(name, bases, dict)
3963101Sstever@eecs.umich.edu        if name == 'Range':
3973101Sstever@eecs.umich.edu            return
3983101Sstever@eecs.umich.edu        cls.cxx_type = 'Range< %s >' % cls.type.cxx_type
3993101Sstever@eecs.umich.edu        cls.cxx_predecls = \
4003101Sstever@eecs.umich.edu                       ['#include "base/range.hh"'] + cls.type.cxx_predecls
4013101Sstever@eecs.umich.edu
4023101Sstever@eecs.umich.educlass Range(ParamValue):
4033101Sstever@eecs.umich.edu    __metaclass__ = MetaRange
4043101Sstever@eecs.umich.edu    type = Int # default; can be overridden in subclasses
4053101Sstever@eecs.umich.edu    def __init__(self, *args, **kwargs):
4063101Sstever@eecs.umich.edu        def handle_kwargs(self, kwargs):
4073101Sstever@eecs.umich.edu            if 'end' in kwargs:
4083101Sstever@eecs.umich.edu                self.second = self.type(kwargs.pop('end'))
4093101Sstever@eecs.umich.edu            elif 'size' in kwargs:
4103101Sstever@eecs.umich.edu                self.second = self.first + self.type(kwargs.pop('size')) - 1
4113101Sstever@eecs.umich.edu            else:
4123101Sstever@eecs.umich.edu                raise TypeError, "Either end or size must be specified"
4133101Sstever@eecs.umich.edu
4143101Sstever@eecs.umich.edu        if len(args) == 0:
4153101Sstever@eecs.umich.edu            self.first = self.type(kwargs.pop('start'))
4163101Sstever@eecs.umich.edu            handle_kwargs(self, kwargs)
4173101Sstever@eecs.umich.edu
4183101Sstever@eecs.umich.edu        elif len(args) == 1:
4193101Sstever@eecs.umich.edu            if kwargs:
4203101Sstever@eecs.umich.edu                self.first = self.type(args[0])
4213101Sstever@eecs.umich.edu                handle_kwargs(self, kwargs)
4223101Sstever@eecs.umich.edu            elif isinstance(args[0], Range):
4233101Sstever@eecs.umich.edu                self.first = self.type(args[0].first)
4243101Sstever@eecs.umich.edu                self.second = self.type(args[0].second)
4253101Sstever@eecs.umich.edu            else:
4263101Sstever@eecs.umich.edu                self.first = self.type(0)
4273101Sstever@eecs.umich.edu                self.second = self.type(args[0]) - 1
4283101Sstever@eecs.umich.edu
4293101Sstever@eecs.umich.edu        elif len(args) == 2:
4303101Sstever@eecs.umich.edu            self.first = self.type(args[0])
4313101Sstever@eecs.umich.edu            self.second = self.type(args[1])
4323101Sstever@eecs.umich.edu        else:
4333101Sstever@eecs.umich.edu            raise TypeError, "Too many arguments specified"
4343101Sstever@eecs.umich.edu
4353101Sstever@eecs.umich.edu        if kwargs:
4363101Sstever@eecs.umich.edu            raise TypeError, "too many keywords: %s" % kwargs.keys()
4373101Sstever@eecs.umich.edu
4383101Sstever@eecs.umich.edu    def __str__(self):
4393101Sstever@eecs.umich.edu        return '%s:%s' % (self.first, self.second)
4403101Sstever@eecs.umich.edu
4413101Sstever@eecs.umich.educlass AddrRange(Range):
4423101Sstever@eecs.umich.edu    type = Addr
4433101Sstever@eecs.umich.edu
4443101Sstever@eecs.umich.educlass TickRange(Range):
4453101Sstever@eecs.umich.edu    type = Tick
4463101Sstever@eecs.umich.edu
4473101Sstever@eecs.umich.edu# Boolean parameter type.  Python doesn't let you subclass bool, since
4483101Sstever@eecs.umich.edu# it doesn't want to let you create multiple instances of True and
4493101Sstever@eecs.umich.edu# False.  Thus this is a little more complicated than String.
4503101Sstever@eecs.umich.educlass Bool(ParamValue):
4513101Sstever@eecs.umich.edu    cxx_type = 'bool'
4523101Sstever@eecs.umich.edu    def __init__(self, value):
4533101Sstever@eecs.umich.edu        try:
4543102Sstever@eecs.umich.edu            self.value = convert.toBool(value)
4553101Sstever@eecs.umich.edu        except TypeError:
4563101Sstever@eecs.umich.edu            self.value = bool(value)
4573101Sstever@eecs.umich.edu
4583101Sstever@eecs.umich.edu    def __str__(self):
4593101Sstever@eecs.umich.edu        return str(self.value)
4603101Sstever@eecs.umich.edu
4613101Sstever@eecs.umich.edu    def ini_str(self):
4623101Sstever@eecs.umich.edu        if self.value:
4633101Sstever@eecs.umich.edu            return 'true'
4643101Sstever@eecs.umich.edu        return 'false'
4653101Sstever@eecs.umich.edu
4663101Sstever@eecs.umich.edudef IncEthernetAddr(addr, val = 1):
4673101Sstever@eecs.umich.edu    bytes = map(lambda x: int(x, 16), addr.split(':'))
4683101Sstever@eecs.umich.edu    bytes[5] += val
4693101Sstever@eecs.umich.edu    for i in (5, 4, 3, 2, 1):
4703101Sstever@eecs.umich.edu        val,rem = divmod(bytes[i], 256)
4713101Sstever@eecs.umich.edu        bytes[i] = rem
4723101Sstever@eecs.umich.edu        if val == 0:
4733101Sstever@eecs.umich.edu            break
4743101Sstever@eecs.umich.edu        bytes[i - 1] += val
4753101Sstever@eecs.umich.edu    assert(bytes[0] <= 255)
4763101Sstever@eecs.umich.edu    return ':'.join(map(lambda x: '%02x' % x, bytes))
4773101Sstever@eecs.umich.edu
4783101Sstever@eecs.umich.educlass NextEthernetAddr(object):
4793101Sstever@eecs.umich.edu    addr = "00:90:00:00:00:01"
4803101Sstever@eecs.umich.edu
4813101Sstever@eecs.umich.edu    def __init__(self, inc = 1):
4823101Sstever@eecs.umich.edu        self.value = NextEthernetAddr.addr
4833101Sstever@eecs.umich.edu        NextEthernetAddr.addr = IncEthernetAddr(NextEthernetAddr.addr, inc)
4843101Sstever@eecs.umich.edu
4853101Sstever@eecs.umich.educlass EthernetAddr(ParamValue):
4863101Sstever@eecs.umich.edu    cxx_type = 'Net::EthAddr'
4873101Sstever@eecs.umich.edu    cxx_predecls = ['#include "base/inet.hh"']
4883101Sstever@eecs.umich.edu    swig_predecls = ['class Net::EthAddr;']
4893101Sstever@eecs.umich.edu    def __init__(self, value):
4903101Sstever@eecs.umich.edu        if value == NextEthernetAddr:
4913101Sstever@eecs.umich.edu            self.value = value
4923101Sstever@eecs.umich.edu            return
4933101Sstever@eecs.umich.edu
4943101Sstever@eecs.umich.edu        if not isinstance(value, str):
4953101Sstever@eecs.umich.edu            raise TypeError, "expected an ethernet address and didn't get one"
4963101Sstever@eecs.umich.edu
4973101Sstever@eecs.umich.edu        bytes = value.split(':')
4983101Sstever@eecs.umich.edu        if len(bytes) != 6:
4993101Sstever@eecs.umich.edu            raise TypeError, 'invalid ethernet address %s' % value
5003101Sstever@eecs.umich.edu
5013101Sstever@eecs.umich.edu        for byte in bytes:
5023101Sstever@eecs.umich.edu            if not 0 <= int(byte) <= 256:
5033101Sstever@eecs.umich.edu                raise TypeError, 'invalid ethernet address %s' % value
5043101Sstever@eecs.umich.edu
5053101Sstever@eecs.umich.edu        self.value = value
5063101Sstever@eecs.umich.edu
5073101Sstever@eecs.umich.edu    def unproxy(self, base):
5083101Sstever@eecs.umich.edu        if self.value == NextEthernetAddr:
5093101Sstever@eecs.umich.edu            self.addr = self.value().value
5103101Sstever@eecs.umich.edu        return self
5113101Sstever@eecs.umich.edu
5123101Sstever@eecs.umich.edu    def __str__(self):
5133101Sstever@eecs.umich.edu        if self.value == NextEthernetAddr:
5143101Sstever@eecs.umich.edu            if hasattr(self, 'addr'):
5153101Sstever@eecs.umich.edu                return self.addr
5163101Sstever@eecs.umich.edu            else:
5173101Sstever@eecs.umich.edu                return "NextEthernetAddr (unresolved)"
5183101Sstever@eecs.umich.edu        else:
5193101Sstever@eecs.umich.edu            return self.value
5203101Sstever@eecs.umich.edu
5213885Sbinkertn@umich.edudef parse_time(value):
5223885Sbinkertn@umich.edu    strings = [ "%a %b %d %H:%M:%S %Z %Y",
5233885Sbinkertn@umich.edu                "%a %b %d %H:%M:%S %Z %Y",
5243885Sbinkertn@umich.edu                "%Y/%m/%d %H:%M:%S",
5253885Sbinkertn@umich.edu                "%Y/%m/%d %H:%M",
5263885Sbinkertn@umich.edu                "%Y/%m/%d",
5273885Sbinkertn@umich.edu                "%m/%d/%Y %H:%M:%S",
5283885Sbinkertn@umich.edu                "%m/%d/%Y %H:%M",
5293885Sbinkertn@umich.edu                "%m/%d/%Y",
5303885Sbinkertn@umich.edu                "%m/%d/%y %H:%M:%S",
5313885Sbinkertn@umich.edu                "%m/%d/%y %H:%M",
5323885Sbinkertn@umich.edu                "%m/%d/%y"]
5333885Sbinkertn@umich.edu
5343885Sbinkertn@umich.edu    for string in strings:
5353885Sbinkertn@umich.edu        try:
5363885Sbinkertn@umich.edu            return time.strptime(value, string)
5373885Sbinkertn@umich.edu        except ValueError:
5383885Sbinkertn@umich.edu            pass
5393885Sbinkertn@umich.edu
5403885Sbinkertn@umich.edu    raise ValueError, "Could not parse '%s' as a time" % value
5413885Sbinkertn@umich.edu
5423885Sbinkertn@umich.educlass Time(ParamValue):
5433885Sbinkertn@umich.edu    cxx_type = 'time_t'
5443885Sbinkertn@umich.edu    def __init__(self, value):
5453885Sbinkertn@umich.edu        if isinstance(value, time.struct_time):
5463885Sbinkertn@umich.edu            self.value = time.mktime(value)
5473885Sbinkertn@umich.edu        elif isinstance(value, int):
5483885Sbinkertn@umich.edu            self.value = value
5493885Sbinkertn@umich.edu        elif isinstance(value, str):
5503885Sbinkertn@umich.edu            if value in ('Now', 'Today'):
5513885Sbinkertn@umich.edu                self.value = time.time()
5523885Sbinkertn@umich.edu            else:
5533885Sbinkertn@umich.edu                self.value = time.mktime(parse_time(value))
5543885Sbinkertn@umich.edu        elif isinstance(value, (datetime.datetime, datetime.date)):
5553885Sbinkertn@umich.edu            self.value = time.mktime(value.timetuple())
5563885Sbinkertn@umich.edu        else:
5573885Sbinkertn@umich.edu            raise ValueError, "Could not parse '%s' as a time" % value
5583885Sbinkertn@umich.edu
5593885Sbinkertn@umich.edu    def __str__(self):
5603885Sbinkertn@umich.edu        return str(int(self.value))
5613885Sbinkertn@umich.edu
5623885Sbinkertn@umich.edu    def ini_str(self):
5633885Sbinkertn@umich.edu        return str(int(self.value))
5643885Sbinkertn@umich.edu
5653101Sstever@eecs.umich.edu# Enumerated types are a little more complex.  The user specifies the
5663101Sstever@eecs.umich.edu# type as Enum(foo) where foo is either a list or dictionary of
5673101Sstever@eecs.umich.edu# alternatives (typically strings, but not necessarily so).  (In the
5683101Sstever@eecs.umich.edu# long run, the integer value of the parameter will be the list index
5693101Sstever@eecs.umich.edu# or the corresponding dictionary value.  For now, since we only check
5703101Sstever@eecs.umich.edu# that the alternative is valid and then spit it into a .ini file,
5713101Sstever@eecs.umich.edu# there's not much point in using the dictionary.)
5723101Sstever@eecs.umich.edu
5733101Sstever@eecs.umich.edu# What Enum() must do is generate a new type encapsulating the
5743101Sstever@eecs.umich.edu# provided list/dictionary so that specific values of the parameter
5753101Sstever@eecs.umich.edu# can be instances of that type.  We define two hidden internal
5763101Sstever@eecs.umich.edu# classes (_ListEnum and _DictEnum) to serve as base classes, then
5773101Sstever@eecs.umich.edu# derive the new type from the appropriate base class on the fly.
5783101Sstever@eecs.umich.edu
5793101Sstever@eecs.umich.edu
5803101Sstever@eecs.umich.edu# Metaclass for Enum types
5813101Sstever@eecs.umich.educlass MetaEnum(type):
5823101Sstever@eecs.umich.edu    def __init__(cls, name, bases, init_dict):
5833101Sstever@eecs.umich.edu        if init_dict.has_key('map'):
5843101Sstever@eecs.umich.edu            if not isinstance(cls.map, dict):
5853101Sstever@eecs.umich.edu                raise TypeError, "Enum-derived class attribute 'map' " \
5863101Sstever@eecs.umich.edu                      "must be of type dict"
5873101Sstever@eecs.umich.edu            # build list of value strings from map
5883101Sstever@eecs.umich.edu            cls.vals = cls.map.keys()
5893101Sstever@eecs.umich.edu            cls.vals.sort()
5903101Sstever@eecs.umich.edu        elif init_dict.has_key('vals'):
5913101Sstever@eecs.umich.edu            if not isinstance(cls.vals, list):
5923101Sstever@eecs.umich.edu                raise TypeError, "Enum-derived class attribute 'vals' " \
5933101Sstever@eecs.umich.edu                      "must be of type list"
5943101Sstever@eecs.umich.edu            # build string->value map from vals sequence
5953101Sstever@eecs.umich.edu            cls.map = {}
5963101Sstever@eecs.umich.edu            for idx,val in enumerate(cls.vals):
5973101Sstever@eecs.umich.edu                cls.map[val] = idx
5983101Sstever@eecs.umich.edu        else:
5993101Sstever@eecs.umich.edu            raise TypeError, "Enum-derived class must define "\
6003101Sstever@eecs.umich.edu                  "attribute 'map' or 'vals'"
6013101Sstever@eecs.umich.edu
6023101Sstever@eecs.umich.edu        cls.cxx_type = name + '::Enum'
6033101Sstever@eecs.umich.edu
6043101Sstever@eecs.umich.edu        super(MetaEnum, cls).__init__(name, bases, init_dict)
6053101Sstever@eecs.umich.edu
6063101Sstever@eecs.umich.edu    # Generate C++ class declaration for this enum type.
6073101Sstever@eecs.umich.edu    # Note that we wrap the enum in a class/struct to act as a namespace,
6083101Sstever@eecs.umich.edu    # so that the enum strings can be brief w/o worrying about collisions.
6093101Sstever@eecs.umich.edu    def cxx_decl(cls):
6103101Sstever@eecs.umich.edu        s = 'struct %s {\n  enum Enum {\n    ' % cls.__name__
6113101Sstever@eecs.umich.edu        s += ',\n    '.join(['%s = %d' % (v,cls.map[v]) for v in cls.vals])
6123101Sstever@eecs.umich.edu        s += '\n  };\n};\n'
6133101Sstever@eecs.umich.edu        return s
6143101Sstever@eecs.umich.edu
6153101Sstever@eecs.umich.edu# Base class for enum types.
6163101Sstever@eecs.umich.educlass Enum(ParamValue):
6173101Sstever@eecs.umich.edu    __metaclass__ = MetaEnum
6183101Sstever@eecs.umich.edu    vals = []
6193101Sstever@eecs.umich.edu
6203101Sstever@eecs.umich.edu    def __init__(self, value):
6213101Sstever@eecs.umich.edu        if value not in self.map:
6223101Sstever@eecs.umich.edu            raise TypeError, "Enum param got bad value '%s' (not in %s)" \
6233101Sstever@eecs.umich.edu                  % (value, self.vals)
6243101Sstever@eecs.umich.edu        self.value = value
6253101Sstever@eecs.umich.edu
6263101Sstever@eecs.umich.edu    def __str__(self):
6273101Sstever@eecs.umich.edu        return self.value
6283101Sstever@eecs.umich.edu
6293101Sstever@eecs.umich.eduticks_per_sec = None
6303101Sstever@eecs.umich.edu
6313101Sstever@eecs.umich.edu# how big does a rounding error need to be before we warn about it?
6323101Sstever@eecs.umich.edufrequency_tolerance = 0.001  # 0.1%
6333101Sstever@eecs.umich.edu
6343101Sstever@eecs.umich.edu# convert a floting-point # of ticks to integer, and warn if rounding
6353101Sstever@eecs.umich.edu# discards too much precision
6363101Sstever@eecs.umich.edudef tick_check(float_ticks):
6373101Sstever@eecs.umich.edu    if float_ticks == 0:
6383101Sstever@eecs.umich.edu        return 0
6393101Sstever@eecs.umich.edu    int_ticks = int(round(float_ticks))
6403101Sstever@eecs.umich.edu    err = (float_ticks - int_ticks) / float_ticks
6413101Sstever@eecs.umich.edu    if err > frequency_tolerance:
6423101Sstever@eecs.umich.edu        print >> sys.stderr, "Warning: rounding error > tolerance"
6433101Sstever@eecs.umich.edu        print >> sys.stderr, "    %f rounded to %d" % (float_ticks, int_ticks)
6443101Sstever@eecs.umich.edu        #raise ValueError
6453101Sstever@eecs.umich.edu    return int_ticks
6463101Sstever@eecs.umich.edu
6473101Sstever@eecs.umich.edudef getLatency(value):
6483101Sstever@eecs.umich.edu    if isinstance(value, Latency) or isinstance(value, Clock):
6493101Sstever@eecs.umich.edu        return value.value
6503101Sstever@eecs.umich.edu    elif isinstance(value, Frequency) or isinstance(value, RootClock):
6513101Sstever@eecs.umich.edu        return 1 / value.value
6523101Sstever@eecs.umich.edu    elif isinstance(value, str):
6533101Sstever@eecs.umich.edu        try:
6543102Sstever@eecs.umich.edu            return convert.toLatency(value)
6553101Sstever@eecs.umich.edu        except ValueError:
6563101Sstever@eecs.umich.edu            try:
6573102Sstever@eecs.umich.edu                return 1 / convert.toFrequency(value)
6583101Sstever@eecs.umich.edu            except ValueError:
6593101Sstever@eecs.umich.edu                pass # fall through
6603101Sstever@eecs.umich.edu    raise ValueError, "Invalid Frequency/Latency value '%s'" % value
6613101Sstever@eecs.umich.edu
6623101Sstever@eecs.umich.edu
6633101Sstever@eecs.umich.educlass Latency(NumericParamValue):
6643101Sstever@eecs.umich.edu    cxx_type = 'Tick'
6653101Sstever@eecs.umich.edu    cxx_predecls = ['#include "sim/host.hh"']
6663101Sstever@eecs.umich.edu    swig_predecls = ['%import "python/m5/swig/stdint.i"\n' +
6673101Sstever@eecs.umich.edu                     '%import "sim/host.hh"']
6683101Sstever@eecs.umich.edu    def __init__(self, value):
6693101Sstever@eecs.umich.edu        self.value = getLatency(value)
6703101Sstever@eecs.umich.edu
6713101Sstever@eecs.umich.edu    def __getattr__(self, attr):
6723101Sstever@eecs.umich.edu        if attr in ('latency', 'period'):
6733101Sstever@eecs.umich.edu            return self
6743101Sstever@eecs.umich.edu        if attr == 'frequency':
6753101Sstever@eecs.umich.edu            return Frequency(self)
6763101Sstever@eecs.umich.edu        raise AttributeError, "Latency object has no attribute '%s'" % attr
6773101Sstever@eecs.umich.edu
6783101Sstever@eecs.umich.edu    # convert latency to ticks
6793101Sstever@eecs.umich.edu    def ini_str(self):
6803101Sstever@eecs.umich.edu        return str(tick_check(self.value * ticks_per_sec))
6813101Sstever@eecs.umich.edu
6823101Sstever@eecs.umich.educlass Frequency(NumericParamValue):
6833101Sstever@eecs.umich.edu    cxx_type = 'Tick'
6843101Sstever@eecs.umich.edu    cxx_predecls = ['#include "sim/host.hh"']
6853101Sstever@eecs.umich.edu    swig_predecls = ['%import "python/m5/swig/stdint.i"\n' +
6863101Sstever@eecs.umich.edu                     '%import "sim/host.hh"']
6873101Sstever@eecs.umich.edu    def __init__(self, value):
6883101Sstever@eecs.umich.edu        self.value = 1 / getLatency(value)
6893101Sstever@eecs.umich.edu
6903101Sstever@eecs.umich.edu    def __getattr__(self, attr):
6913101Sstever@eecs.umich.edu        if attr == 'frequency':
6923101Sstever@eecs.umich.edu            return self
6933101Sstever@eecs.umich.edu        if attr in ('latency', 'period'):
6943101Sstever@eecs.umich.edu            return Latency(self)
6953101Sstever@eecs.umich.edu        raise AttributeError, "Frequency object has no attribute '%s'" % attr
6963101Sstever@eecs.umich.edu
6973101Sstever@eecs.umich.edu    # convert frequency to ticks per period
6983101Sstever@eecs.umich.edu    def ini_str(self):
6993101Sstever@eecs.umich.edu        return self.period.ini_str()
7003101Sstever@eecs.umich.edu
7013101Sstever@eecs.umich.edu# Just like Frequency, except ini_str() is absolute # of ticks per sec (Hz).
7023101Sstever@eecs.umich.edu# We can't inherit from Frequency because we don't want it to be directly
7033101Sstever@eecs.umich.edu# assignable to a regular Frequency parameter.
7043101Sstever@eecs.umich.educlass RootClock(ParamValue):
7053101Sstever@eecs.umich.edu    cxx_type = 'Tick'
7063101Sstever@eecs.umich.edu    cxx_predecls = ['#include "sim/host.hh"']
7073101Sstever@eecs.umich.edu    swig_predecls = ['%import "python/m5/swig/stdint.i"\n' +
7083101Sstever@eecs.umich.edu                     '%import "sim/host.hh"']
7093101Sstever@eecs.umich.edu    def __init__(self, value):
7103101Sstever@eecs.umich.edu        self.value = 1 / getLatency(value)
7113101Sstever@eecs.umich.edu
7123101Sstever@eecs.umich.edu    def __getattr__(self, attr):
7133101Sstever@eecs.umich.edu        if attr == 'frequency':
7143101Sstever@eecs.umich.edu            return Frequency(self)
7153101Sstever@eecs.umich.edu        if attr in ('latency', 'period'):
7163101Sstever@eecs.umich.edu            return Latency(self)
7173101Sstever@eecs.umich.edu        raise AttributeError, "Frequency object has no attribute '%s'" % attr
7183101Sstever@eecs.umich.edu
7193101Sstever@eecs.umich.edu    def ini_str(self):
7203101Sstever@eecs.umich.edu        return str(tick_check(self.value))
7213101Sstever@eecs.umich.edu
7223101Sstever@eecs.umich.edu# A generic frequency and/or Latency value.  Value is stored as a latency,
7233101Sstever@eecs.umich.edu# but to avoid ambiguity this object does not support numeric ops (* or /).
7243101Sstever@eecs.umich.edu# An explicit conversion to a Latency or Frequency must be made first.
7253101Sstever@eecs.umich.educlass Clock(ParamValue):
7263101Sstever@eecs.umich.edu    cxx_type = 'Tick'
7273101Sstever@eecs.umich.edu    cxx_predecls = ['#include "sim/host.hh"']
7283101Sstever@eecs.umich.edu    swig_predecls = ['%import "python/m5/swig/stdint.i"\n' +
7293101Sstever@eecs.umich.edu                     '%import "sim/host.hh"']
7303101Sstever@eecs.umich.edu    def __init__(self, value):
7313101Sstever@eecs.umich.edu        self.value = getLatency(value)
7323101Sstever@eecs.umich.edu
7333101Sstever@eecs.umich.edu    def __getattr__(self, attr):
7343101Sstever@eecs.umich.edu        if attr == 'frequency':
7353101Sstever@eecs.umich.edu            return Frequency(self)
7363101Sstever@eecs.umich.edu        if attr in ('latency', 'period'):
7373101Sstever@eecs.umich.edu            return Latency(self)
7383101Sstever@eecs.umich.edu        raise AttributeError, "Frequency object has no attribute '%s'" % attr
7393101Sstever@eecs.umich.edu
7403101Sstever@eecs.umich.edu    def ini_str(self):
7413101Sstever@eecs.umich.edu        return self.period.ini_str()
7423101Sstever@eecs.umich.edu
7433101Sstever@eecs.umich.educlass NetworkBandwidth(float,ParamValue):
7443101Sstever@eecs.umich.edu    cxx_type = 'float'
7453101Sstever@eecs.umich.edu    def __new__(cls, value):
7463102Sstever@eecs.umich.edu        val = convert.toNetworkBandwidth(value) / 8.0
7473101Sstever@eecs.umich.edu        return super(cls, NetworkBandwidth).__new__(cls, val)
7483101Sstever@eecs.umich.edu
7493101Sstever@eecs.umich.edu    def __str__(self):
7503101Sstever@eecs.umich.edu        return str(self.val)
7513101Sstever@eecs.umich.edu
7523101Sstever@eecs.umich.edu    def ini_str(self):
7533101Sstever@eecs.umich.edu        return '%f' % (ticks_per_sec / float(self))
7543101Sstever@eecs.umich.edu
7553101Sstever@eecs.umich.educlass MemoryBandwidth(float,ParamValue):
7563101Sstever@eecs.umich.edu    cxx_type = 'float'
7573101Sstever@eecs.umich.edu    def __new__(self, value):
7583102Sstever@eecs.umich.edu        val = convert.toMemoryBandwidth(value)
7593101Sstever@eecs.umich.edu        return super(cls, MemoryBandwidth).__new__(cls, val)
7603101Sstever@eecs.umich.edu
7613101Sstever@eecs.umich.edu    def __str__(self):
7623101Sstever@eecs.umich.edu        return str(self.val)
7633101Sstever@eecs.umich.edu
7643101Sstever@eecs.umich.edu    def ini_str(self):
7653101Sstever@eecs.umich.edu        return '%f' % (ticks_per_sec / float(self))
7663101Sstever@eecs.umich.edu
7673101Sstever@eecs.umich.edu#
7683101Sstever@eecs.umich.edu# "Constants"... handy aliases for various values.
7693101Sstever@eecs.umich.edu#
7703101Sstever@eecs.umich.edu
7713102Sstever@eecs.umich.edu# Special class for NULL pointers.  Note the special check in
7723102Sstever@eecs.umich.edu# make_param_value() above that lets these be assigned where a
7733102Sstever@eecs.umich.edu# SimObject is required.
7743102Sstever@eecs.umich.edu# only one copy of a particular node
7753102Sstever@eecs.umich.educlass NullSimObject(object):
7763102Sstever@eecs.umich.edu    __metaclass__ = Singleton
7773102Sstever@eecs.umich.edu
7783102Sstever@eecs.umich.edu    def __call__(cls):
7793102Sstever@eecs.umich.edu        return cls
7803102Sstever@eecs.umich.edu
7813102Sstever@eecs.umich.edu    def _instantiate(self, parent = None, path = ''):
7823102Sstever@eecs.umich.edu        pass
7833102Sstever@eecs.umich.edu
7843102Sstever@eecs.umich.edu    def ini_str(self):
7853102Sstever@eecs.umich.edu        return 'Null'
7863102Sstever@eecs.umich.edu
7873102Sstever@eecs.umich.edu    def unproxy(self, base):
7883102Sstever@eecs.umich.edu        return self
7893102Sstever@eecs.umich.edu
7903102Sstever@eecs.umich.edu    def set_path(self, parent, name):
7913102Sstever@eecs.umich.edu        pass
7923102Sstever@eecs.umich.edu    def __str__(self):
7933102Sstever@eecs.umich.edu        return 'Null'
7943102Sstever@eecs.umich.edu
7953102Sstever@eecs.umich.edu# The only instance you'll ever need...
7963102Sstever@eecs.umich.eduNULL = NullSimObject()
7973102Sstever@eecs.umich.edu
7983102Sstever@eecs.umich.edudef isNullPointer(value):
7993102Sstever@eecs.umich.edu    return isinstance(value, NullSimObject)
8003102Sstever@eecs.umich.edu
8013101Sstever@eecs.umich.edu# Some memory range specifications use this as a default upper bound.
8023101Sstever@eecs.umich.eduMaxAddr = Addr.max
8033101Sstever@eecs.umich.eduMaxTick = Tick.max
8043101Sstever@eecs.umich.eduAllMemory = AddrRange(0, MaxAddr)
8053101Sstever@eecs.umich.edu
8063101Sstever@eecs.umich.edu
8073101Sstever@eecs.umich.edu#####################################################################
8083101Sstever@eecs.umich.edu#
8093101Sstever@eecs.umich.edu# Port objects
8103101Sstever@eecs.umich.edu#
8113101Sstever@eecs.umich.edu# Ports are used to interconnect objects in the memory system.
8123101Sstever@eecs.umich.edu#
8133101Sstever@eecs.umich.edu#####################################################################
8143101Sstever@eecs.umich.edu
8153101Sstever@eecs.umich.edu# Port reference: encapsulates a reference to a particular port on a
8163101Sstever@eecs.umich.edu# particular SimObject.
8173101Sstever@eecs.umich.educlass PortRef(object):
8183105Sstever@eecs.umich.edu    def __init__(self, simobj, name):
8193105Sstever@eecs.umich.edu        assert(isSimObject(simobj) or isSimObjectClass(simobj))
8203101Sstever@eecs.umich.edu        self.simobj = simobj
8213101Sstever@eecs.umich.edu        self.name = name
8223101Sstever@eecs.umich.edu        self.peer = None   # not associated with another port yet
8233101Sstever@eecs.umich.edu        self.ccConnected = False # C++ port connection done?
8243105Sstever@eecs.umich.edu        self.index = -1  # always -1 for non-vector ports
8253101Sstever@eecs.umich.edu
8263103Sstever@eecs.umich.edu    def __str__(self):
8273105Sstever@eecs.umich.edu        return '%s.%s' % (self.simobj, self.name)
8283103Sstever@eecs.umich.edu
8293105Sstever@eecs.umich.edu    # for config.ini, print peer's name (not ours)
8303105Sstever@eecs.umich.edu    def ini_str(self):
8313105Sstever@eecs.umich.edu        return str(self.peer)
8323105Sstever@eecs.umich.edu
8333105Sstever@eecs.umich.edu    def __getattr__(self, attr):
8343105Sstever@eecs.umich.edu        if attr == 'peerObj':
8353105Sstever@eecs.umich.edu            # shorthand for proxies
8363105Sstever@eecs.umich.edu            return self.peer.simobj
8373105Sstever@eecs.umich.edu        raise AttributeError, "'%s' object has no attribute '%s'" % \
8383105Sstever@eecs.umich.edu              (self.__class__.__name__, attr)
8393105Sstever@eecs.umich.edu
8403105Sstever@eecs.umich.edu    # Full connection is symmetric (both ways).  Called via
8413105Sstever@eecs.umich.edu    # SimObject.__setattr__ as a result of a port assignment, e.g.,
8423109Sstever@eecs.umich.edu    # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
8433105Sstever@eecs.umich.edu    # e.g., "obj1.portA[3] = obj2.portB".
8443105Sstever@eecs.umich.edu    def connect(self, other):
8453105Sstever@eecs.umich.edu        if isinstance(other, VectorPortRef):
8463105Sstever@eecs.umich.edu            # reference to plain VectorPort is implicit append
8473105Sstever@eecs.umich.edu            other = other._get_next()
8483105Sstever@eecs.umich.edu        if self.peer and not proxy.isproxy(self.peer):
8493105Sstever@eecs.umich.edu            print "warning: overwriting port", self, \
8503105Sstever@eecs.umich.edu                  "value", self.peer, "with", other
8513101Sstever@eecs.umich.edu        self.peer = other
8523109Sstever@eecs.umich.edu        if proxy.isproxy(other):
8533109Sstever@eecs.umich.edu            other.set_param_desc(PortParamDesc())
8543109Sstever@eecs.umich.edu        elif isinstance(other, PortRef):
8553109Sstever@eecs.umich.edu            if other.peer is not self:
8563109Sstever@eecs.umich.edu                other.connect(self)
8573109Sstever@eecs.umich.edu        else:
8583109Sstever@eecs.umich.edu            raise TypeError, \
8593109Sstever@eecs.umich.edu                  "assigning non-port reference '%s' to port '%s'" \
8603109Sstever@eecs.umich.edu                  % (other, self)
8613101Sstever@eecs.umich.edu
8623105Sstever@eecs.umich.edu    def clone(self, simobj, memo):
8633105Sstever@eecs.umich.edu        if memo.has_key(self):
8643105Sstever@eecs.umich.edu            return memo[self]
8653101Sstever@eecs.umich.edu        newRef = copy.copy(self)
8663105Sstever@eecs.umich.edu        memo[self] = newRef
8673105Sstever@eecs.umich.edu        newRef.simobj = simobj
8683101Sstever@eecs.umich.edu        assert(isSimObject(newRef.simobj))
8693105Sstever@eecs.umich.edu        if self.peer and not proxy.isproxy(self.peer):
8703179Sstever@eecs.umich.edu            peerObj = self.peer.simobj(_memo=memo)
8713105Sstever@eecs.umich.edu            newRef.peer = self.peer.clone(peerObj, memo)
8723105Sstever@eecs.umich.edu            assert(not isinstance(newRef.peer, VectorPortRef))
8733101Sstever@eecs.umich.edu        return newRef
8743101Sstever@eecs.umich.edu
8753105Sstever@eecs.umich.edu    def unproxy(self, simobj):
8763105Sstever@eecs.umich.edu        assert(simobj is self.simobj)
8773105Sstever@eecs.umich.edu        if proxy.isproxy(self.peer):
8783105Sstever@eecs.umich.edu            try:
8793105Sstever@eecs.umich.edu                realPeer = self.peer.unproxy(self.simobj)
8803105Sstever@eecs.umich.edu            except:
8813105Sstever@eecs.umich.edu                print "Error in unproxying port '%s' of %s" % \
8823105Sstever@eecs.umich.edu                      (self.name, self.simobj.path())
8833105Sstever@eecs.umich.edu                raise
8843105Sstever@eecs.umich.edu            self.connect(realPeer)
8853105Sstever@eecs.umich.edu
8863101Sstever@eecs.umich.edu    # Call C++ to create corresponding port connection between C++ objects
8873101Sstever@eecs.umich.edu    def ccConnect(self):
8883101Sstever@eecs.umich.edu        if self.ccConnected: # already done this
8893101Sstever@eecs.umich.edu            return
8903101Sstever@eecs.umich.edu        peer = self.peer
8913624Sbinkertn@umich.edu        internal.main.connectPorts(self.simobj.getCCObject(), self.name,
8923624Sbinkertn@umich.edu                                   self.index, peer.simobj.getCCObject(),
8933624Sbinkertn@umich.edu                                   peer.name, peer.index)
8943101Sstever@eecs.umich.edu        self.ccConnected = True
8953101Sstever@eecs.umich.edu        peer.ccConnected = True
8963101Sstever@eecs.umich.edu
8973105Sstever@eecs.umich.edu# A reference to an individual element of a VectorPort... much like a
8983105Sstever@eecs.umich.edu# PortRef, but has an index.
8993105Sstever@eecs.umich.educlass VectorPortElementRef(PortRef):
9003105Sstever@eecs.umich.edu    def __init__(self, simobj, name, index):
9013105Sstever@eecs.umich.edu        PortRef.__init__(self, simobj, name)
9023105Sstever@eecs.umich.edu        self.index = index
9033105Sstever@eecs.umich.edu
9043105Sstever@eecs.umich.edu    def __str__(self):
9053105Sstever@eecs.umich.edu        return '%s.%s[%d]' % (self.simobj, self.name, self.index)
9063105Sstever@eecs.umich.edu
9073105Sstever@eecs.umich.edu# A reference to a complete vector-valued port (not just a single element).
9083105Sstever@eecs.umich.edu# Can be indexed to retrieve individual VectorPortElementRef instances.
9093105Sstever@eecs.umich.educlass VectorPortRef(object):
9103105Sstever@eecs.umich.edu    def __init__(self, simobj, name):
9113105Sstever@eecs.umich.edu        assert(isSimObject(simobj) or isSimObjectClass(simobj))
9123105Sstever@eecs.umich.edu        self.simobj = simobj
9133105Sstever@eecs.umich.edu        self.name = name
9143105Sstever@eecs.umich.edu        self.elements = []
9153105Sstever@eecs.umich.edu
9163109Sstever@eecs.umich.edu    def __str__(self):
9173109Sstever@eecs.umich.edu        return '%s.%s[:]' % (self.simobj, self.name)
9183109Sstever@eecs.umich.edu
9193105Sstever@eecs.umich.edu    # for config.ini, print peer's name (not ours)
9203105Sstever@eecs.umich.edu    def ini_str(self):
9213105Sstever@eecs.umich.edu        return ' '.join([el.ini_str() for el in self.elements])
9223105Sstever@eecs.umich.edu
9233105Sstever@eecs.umich.edu    def __getitem__(self, key):
9243105Sstever@eecs.umich.edu        if not isinstance(key, int):
9253105Sstever@eecs.umich.edu            raise TypeError, "VectorPort index must be integer"
9263105Sstever@eecs.umich.edu        if key >= len(self.elements):
9273105Sstever@eecs.umich.edu            # need to extend list
9283105Sstever@eecs.umich.edu            ext = [VectorPortElementRef(self.simobj, self.name, i)
9293105Sstever@eecs.umich.edu                   for i in range(len(self.elements), key+1)]
9303105Sstever@eecs.umich.edu            self.elements.extend(ext)
9313105Sstever@eecs.umich.edu        return self.elements[key]
9323105Sstever@eecs.umich.edu
9333105Sstever@eecs.umich.edu    def _get_next(self):
9343105Sstever@eecs.umich.edu        return self[len(self.elements)]
9353105Sstever@eecs.umich.edu
9363105Sstever@eecs.umich.edu    def __setitem__(self, key, value):
9373105Sstever@eecs.umich.edu        if not isinstance(key, int):
9383105Sstever@eecs.umich.edu            raise TypeError, "VectorPort index must be integer"
9393105Sstever@eecs.umich.edu        self[key].connect(value)
9403105Sstever@eecs.umich.edu
9413105Sstever@eecs.umich.edu    def connect(self, other):
9423109Sstever@eecs.umich.edu        if isinstance(other, (list, tuple)):
9433109Sstever@eecs.umich.edu            # Assign list of port refs to vector port.
9443109Sstever@eecs.umich.edu            # For now, append them... not sure if that's the right semantics
9453109Sstever@eecs.umich.edu            # or if it should replace the current vector.
9463109Sstever@eecs.umich.edu            for ref in other:
9473109Sstever@eecs.umich.edu                self._get_next().connect(ref)
9483109Sstever@eecs.umich.edu        else:
9493109Sstever@eecs.umich.edu            # scalar assignment to plain VectorPort is implicit append
9503109Sstever@eecs.umich.edu            self._get_next().connect(other)
9513109Sstever@eecs.umich.edu
9523109Sstever@eecs.umich.edu    def clone(self, simobj, memo):
9533109Sstever@eecs.umich.edu        if memo.has_key(self):
9543109Sstever@eecs.umich.edu            return memo[self]
9553109Sstever@eecs.umich.edu        newRef = copy.copy(self)
9563109Sstever@eecs.umich.edu        memo[self] = newRef
9573109Sstever@eecs.umich.edu        newRef.simobj = simobj
9583109Sstever@eecs.umich.edu        assert(isSimObject(newRef.simobj))
9593109Sstever@eecs.umich.edu        newRef.elements = [el.clone(simobj, memo) for el in self.elements]
9603109Sstever@eecs.umich.edu        return newRef
9613105Sstever@eecs.umich.edu
9623105Sstever@eecs.umich.edu    def unproxy(self, simobj):
9633105Sstever@eecs.umich.edu        [el.unproxy(simobj) for el in self.elements]
9643105Sstever@eecs.umich.edu
9653105Sstever@eecs.umich.edu    def ccConnect(self):
9663105Sstever@eecs.umich.edu        [el.ccConnect() for el in self.elements]
9673105Sstever@eecs.umich.edu
9683101Sstever@eecs.umich.edu# Port description object.  Like a ParamDesc object, this represents a
9693101Sstever@eecs.umich.edu# logical port in the SimObject class, not a particular port on a
9703101Sstever@eecs.umich.edu# SimObject instance.  The latter are represented by PortRef objects.
9713101Sstever@eecs.umich.educlass Port(object):
9723105Sstever@eecs.umich.edu    # Port("description") or Port(default, "description")
9733105Sstever@eecs.umich.edu    def __init__(self, *args):
9743105Sstever@eecs.umich.edu        if len(args) == 1:
9753105Sstever@eecs.umich.edu            self.desc = args[0]
9763105Sstever@eecs.umich.edu        elif len(args) == 2:
9773105Sstever@eecs.umich.edu            self.default = args[0]
9783105Sstever@eecs.umich.edu            self.desc = args[1]
9793105Sstever@eecs.umich.edu        else:
9803105Sstever@eecs.umich.edu            raise TypeError, 'wrong number of arguments'
9813105Sstever@eecs.umich.edu        # self.name is set by SimObject class on assignment
9823105Sstever@eecs.umich.edu        # e.g., pio_port = Port("blah") sets self.name to 'pio_port'
9833101Sstever@eecs.umich.edu
9843101Sstever@eecs.umich.edu    # Generate a PortRef for this port on the given SimObject with the
9853101Sstever@eecs.umich.edu    # given name
9863105Sstever@eecs.umich.edu    def makeRef(self, simobj):
9873105Sstever@eecs.umich.edu        return PortRef(simobj, self.name)
9883101Sstever@eecs.umich.edu
9893101Sstever@eecs.umich.edu    # Connect an instance of this port (on the given SimObject with
9903101Sstever@eecs.umich.edu    # the given name) with the port described by the supplied PortRef
9913105Sstever@eecs.umich.edu    def connect(self, simobj, ref):
9923105Sstever@eecs.umich.edu        self.makeRef(simobj).connect(ref)
9933101Sstever@eecs.umich.edu
9943101Sstever@eecs.umich.edu# VectorPort description object.  Like Port, but represents a vector
9953101Sstever@eecs.umich.edu# of connections (e.g., as on a Bus).
9963101Sstever@eecs.umich.educlass VectorPort(Port):
9973105Sstever@eecs.umich.edu    def __init__(self, *args):
9983105Sstever@eecs.umich.edu        Port.__init__(self, *args)
9993101Sstever@eecs.umich.edu        self.isVec = True
10003101Sstever@eecs.umich.edu
10013105Sstever@eecs.umich.edu    def makeRef(self, simobj):
10023105Sstever@eecs.umich.edu        return VectorPortRef(simobj, self.name)
10033105Sstever@eecs.umich.edu
10043109Sstever@eecs.umich.edu# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
10053109Sstever@eecs.umich.edu# proxy objects (via set_param_desc()) so that proxy error messages
10063109Sstever@eecs.umich.edu# make sense.
10073109Sstever@eecs.umich.educlass PortParamDesc(object):
10083109Sstever@eecs.umich.edu    __metaclass__ = Singleton
10093109Sstever@eecs.umich.edu
10103109Sstever@eecs.umich.edu    ptype_str = 'Port'
10113109Sstever@eecs.umich.edu    ptype = Port
10123105Sstever@eecs.umich.edu
10133101Sstever@eecs.umich.edu
10143101Sstever@eecs.umich.edu__all__ = ['Param', 'VectorParam',
10153101Sstever@eecs.umich.edu           'Enum', 'Bool', 'String', 'Float',
10163101Sstever@eecs.umich.edu           'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
10173101Sstever@eecs.umich.edu           'Int32', 'UInt32', 'Int64', 'UInt64',
10183101Sstever@eecs.umich.edu           'Counter', 'Addr', 'Tick', 'Percent',
10193101Sstever@eecs.umich.edu           'TcpPort', 'UdpPort', 'EthernetAddr',
10203101Sstever@eecs.umich.edu           'MemorySize', 'MemorySize32',
10213101Sstever@eecs.umich.edu           'Latency', 'Frequency', 'RootClock', 'Clock',
10223101Sstever@eecs.umich.edu           'NetworkBandwidth', 'MemoryBandwidth',
10233101Sstever@eecs.umich.edu           'Range', 'AddrRange', 'TickRange',
10243101Sstever@eecs.umich.edu           'MaxAddr', 'MaxTick', 'AllMemory',
10253885Sbinkertn@umich.edu           'Time',
10263102Sstever@eecs.umich.edu           'NextEthernetAddr', 'NULL',
10273101Sstever@eecs.umich.edu           'Port', 'VectorPort']
10283101Sstever@eecs.umich.edu
10293101Sstever@eecs.umich.edu# see comment on imports at end of __init__.py.
10303102Sstever@eecs.umich.edufrom SimObject import isSimObject, isSimObjectSequence, isSimObjectClass
10313101Sstever@eecs.umich.eduimport proxy
10323102Sstever@eecs.umich.eduimport objects
10333624Sbinkertn@umich.eduimport internal
1034