params.py revision 9941
12740SN/A# Copyright (c) 2012-2013 ARM Limited
21046SN/A# All rights reserved.
31046SN/A#
41046SN/A# The license below extends only to copyright in the software and shall
51046SN/A# not be construed as granting a license to any other intellectual
61046SN/A# property including but not limited to intellectual property relating
71046SN/A# to a hardware implementation of the functionality of the software
81046SN/A# licensed hereunder.  You may use the software subject to the license
91046SN/A# terms below provided that you ensure that this notice is replicated
101046SN/A# unmodified and in its entirety in all distributions of the software,
111046SN/A# modified or unmodified, in source code or in binary form.
121046SN/A#
131046SN/A# Copyright (c) 2004-2006 The Regents of The University of Michigan
141046SN/A# Copyright (c) 2010-2011 Advanced Micro Devices, Inc.
151046SN/A# All rights reserved.
161046SN/A#
171046SN/A# Redistribution and use in source and binary forms, with or without
181046SN/A# modification, are permitted provided that the following conditions are
191046SN/A# met: redistributions of source code must retain the above copyright
201046SN/A# notice, this list of conditions and the following disclaimer;
211046SN/A# redistributions in binary form must reproduce the above copyright
221046SN/A# notice, this list of conditions and the following disclaimer in the
231046SN/A# documentation and/or other materials provided with the distribution;
241046SN/A# neither the name of the copyright holders nor the names of its
251046SN/A# contributors may be used to endorse or promote products derived from
262665SN/A# this software without specific prior written permission.
272665SN/A#
282665SN/A# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
291046SN/A# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
305766Snate@binkert.org# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
315766Snate@binkert.org# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
325766Snate@binkert.org# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
331438SN/A# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
344762Snate@binkert.org# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
354762Snate@binkert.org# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
363102Sstever@eecs.umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
371438SN/A# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
383102Sstever@eecs.umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
393102Sstever@eecs.umich.edu#
403102Sstever@eecs.umich.edu# Authors: Steve Reinhardt
413102Sstever@eecs.umich.edu#          Nathan Binkert
423102Sstever@eecs.umich.edu#          Gabe Black
433102Sstever@eecs.umich.edu#          Andreas Hansson
443102Sstever@eecs.umich.edu
453102Sstever@eecs.umich.edu#####################################################################
463102Sstever@eecs.umich.edu#
473102Sstever@eecs.umich.edu# Parameter description classes
483102Sstever@eecs.umich.edu#
493102Sstever@eecs.umich.edu# The _params dictionary in each class maps parameter names to either
503102Sstever@eecs.umich.edu# a Param or a VectorParam object.  These objects contain the
513102Sstever@eecs.umich.edu# parameter description string, the parameter type, and the default
523102Sstever@eecs.umich.edu# value (if any).  The convert() method on these objects is used to
533102Sstever@eecs.umich.edu# force whatever value is assigned to the parameter to the appropriate
543102Sstever@eecs.umich.edu# type.
553102Sstever@eecs.umich.edu#
563102Sstever@eecs.umich.edu# Note that the default values are loaded into the class's attribute
573102Sstever@eecs.umich.edu# space when the parameter dictionary is initialized (in
583102Sstever@eecs.umich.edu# MetaSimObject._new_param()); after that point they aren't used.
593102Sstever@eecs.umich.edu#
603102Sstever@eecs.umich.edu#####################################################################
613102Sstever@eecs.umich.edu
623102Sstever@eecs.umich.eduimport copy
633102Sstever@eecs.umich.eduimport datetime
643102Sstever@eecs.umich.eduimport re
653102Sstever@eecs.umich.eduimport sys
663102Sstever@eecs.umich.eduimport time
674762Snate@binkert.orgimport math
683102Sstever@eecs.umich.edu
691342SN/Aimport proxy
701342SN/Aimport ticks
711378SN/Afrom util import *
721342SN/A
731378SN/Adef isSimObject(*args, **kwargs):
74679SN/A    return SimObject.isSimObject(*args, **kwargs)
75679SN/A
76679SN/Adef isSimObjectSequence(*args, **kwargs):
77679SN/A    return SimObject.isSimObjectSequence(*args, **kwargs)
78679SN/A
79679SN/Adef isSimObjectClass(*args, **kwargs):
801692SN/A    return SimObject.isSimObjectClass(*args, **kwargs)
81679SN/A
82679SN/AallParams = {}
83679SN/A
84679SN/Aclass MetaParamValue(type):
85679SN/A    def __new__(mcls, name, bases, dct):
86679SN/A        cls = super(MetaParamValue, mcls).__new__(mcls, name, bases, dct)
87679SN/A        assert name not in allParams
88679SN/A        allParams[name] = cls
89679SN/A        return cls
90679SN/A
91679SN/A
92679SN/A# Dummy base class to identify types that are legitimate for SimObject
93679SN/A# parameters.
94679SN/Aclass ParamValue(object):
951692SN/A    __metaclass__ = MetaParamValue
96679SN/A
97679SN/A
98679SN/A    # Generate the code needed as a prerequisite for declaring a C++
99679SN/A    # object of this type.  Typically generates one or more #include
100679SN/A    # statements.  Used when declaring parameters of this type.
101679SN/A    @classmethod
102679SN/A    def cxx_predecls(cls, code):
103679SN/A        pass
104679SN/A
105679SN/A    # Generate the code needed as a prerequisite for including a
106679SN/A    # reference to a C++ object of this type in a SWIG .i file.
107679SN/A    # Typically generates one or more %import or %include statements.
108679SN/A    @classmethod
109679SN/A    def swig_predecls(cls, code):
110679SN/A        pass
1112740SN/A
112679SN/A    # default for printing to .ini file is regular string conversion.
113679SN/A    # will be overridden in some cases
114679SN/A    def ini_str(self):
1154762Snate@binkert.org        return str(self)
1164762Snate@binkert.org
1174762Snate@binkert.org    # allows us to blithely call unproxy() on things without checking
1182738SN/A    # if they're really proxies or not
1192738SN/A    def unproxy(self, base):
1202738SN/A        return self
1212740SN/A
1222740SN/A# Regular parameter description.
1232740SN/Aclass ParamDesc(object):
1242740SN/A    def __init__(self, ptype_str, ptype, *args, **kwargs):
1251692SN/A        self.ptype_str = ptype_str
1261427SN/A        # remember ptype only if it is provided
1271692SN/A        if ptype != None:
1284762Snate@binkert.org            self.ptype = ptype
1294762Snate@binkert.org
1304762Snate@binkert.org        if args:
1314859Snate@binkert.org            if len(args) == 1:
1324762Snate@binkert.org                self.desc = args[0]
1331692SN/A            elif len(args) == 2:
1341427SN/A                self.default = args[0]
1354762Snate@binkert.org                self.desc = args[1]
136679SN/A            else:
137679SN/A                raise TypeError, 'too many arguments'
138679SN/A
1392740SN/A        if kwargs.has_key('desc'):
140679SN/A            assert(not hasattr(self, 'desc'))
141679SN/A            self.desc = kwargs['desc']
1421310SN/A            del kwargs['desc']
1434762Snate@binkert.org
1444762Snate@binkert.org        if kwargs.has_key('default'):
1452740SN/A            assert(not hasattr(self, 'default'))
1462740SN/A            self.default = kwargs['default']
1472740SN/A            del kwargs['default']
1482740SN/A
1492740SN/A        if kwargs:
1502740SN/A            raise TypeError, 'extra unknown kwargs %s' % kwargs
1512740SN/A
1522740SN/A        if not hasattr(self, 'desc'):
1532740SN/A            raise TypeError, 'desc attribute missing'
1542740SN/A
1552740SN/A    def __getattr__(self, attr):
1562740SN/A        if attr == 'ptype':
1574762Snate@binkert.org            ptype = SimObject.allClasses[self.ptype_str]
1584762Snate@binkert.org            assert isSimObjectClass(ptype)
1592740SN/A            self.ptype = ptype
1604762Snate@binkert.org            return ptype
1614762Snate@binkert.org
1624762Snate@binkert.org        raise AttributeError, "'%s' object has no attribute '%s'" % \
1634762Snate@binkert.org              (type(self).__name__, attr)
164679SN/A
1652711SN/A    def convert(self, value):
166679SN/A        if isinstance(value, proxy.BaseProxy):
1672711SN/A            value.set_param_desc(self)
1682711SN/A            return value
1691692SN/A        if not hasattr(self, 'ptype') and isNullPointer(value):
1701310SN/A            # deferred evaluation of SimObject; continue to defer if
1711427SN/A            # we're just assigning a null pointer
1722740SN/A            return value
1732740SN/A        if isinstance(value, self.ptype):
1742740SN/A            return value
1752740SN/A        if isNullPointer(value) and isSimObjectClass(self.ptype):
1762740SN/A            return value
1772740SN/A        return self.ptype(value)
1782740SN/A
1793105Sstever@eecs.umich.edu    def cxx_predecls(self, code):
1802740SN/A        code('#include <cstddef>')
1811310SN/A        self.ptype.cxx_predecls(code)
1821692SN/A
1831585SN/A    def swig_predecls(self, code):
1841692SN/A        self.ptype.swig_predecls(code)
1851692SN/A
1861692SN/A    def cxx_decl(self, code):
1871692SN/A        code('${{self.ptype.cxx_type}} ${{self.name}};')
1881692SN/A
1892740SN/A# Vector-valued parameter description.  Just like ParamDesc, except
1902740SN/A# that the value is a vector (list) of the specified type instead of a
1912740SN/A# single value.
1922740SN/A
1931692SN/Aclass VectorParamValue(list):
1945610Snate@binkert.org    __metaclass__ = MetaParamValue
1951692SN/A    def __setattr__(self, attr, value):
1962740SN/A        raise AttributeError, \
1971692SN/A              "Not allowed to set %s on '%s'" % (attr, type(self).__name__)
1983105Sstever@eecs.umich.edu
1992740SN/A    def ini_str(self):
2002712SN/A        return ' '.join([v.ini_str() for v in self])
2015610Snate@binkert.org
2025610Snate@binkert.org    def getValue(self):
2031692SN/A        return [ v.getValue() for v in self ]
2044762Snate@binkert.org
2054762Snate@binkert.org    def unproxy(self, base):
2064762Snate@binkert.org        if len(self) == 1 and isinstance(self[0], proxy.AllProxy):
2075610Snate@binkert.org            return self[0].unproxy(base)
2084762Snate@binkert.org        else:
2095610Snate@binkert.org             return [v.unproxy(base) for v in self]
2105610Snate@binkert.org
2114762Snate@binkert.orgclass SimObjectVector(VectorParamValue):
2124762Snate@binkert.org    # support clone operation
2134762Snate@binkert.org    def __call__(self, **kwargs):
2145610Snate@binkert.org        return SimObjectVector([v(**kwargs) for v in self])
2155610Snate@binkert.org
2165610Snate@binkert.org    def clear_parent(self, old_parent):
2175610Snate@binkert.org        for v in self:
2185610Snate@binkert.org            v.clear_parent(old_parent)
2194762Snate@binkert.org
2204762Snate@binkert.org    def set_parent(self, parent, name):
2214762Snate@binkert.org        if len(self) == 1:
2224762Snate@binkert.org            self[0].set_parent(parent, name)
2234762Snate@binkert.org        else:
2244762Snate@binkert.org            width = int(math.ceil(math.log(len(self))/math.log(10)))
2254762Snate@binkert.org            for i,v in enumerate(self):
2264762Snate@binkert.org                v.set_parent(parent, "%s%0*d" % (name, width, i))
2274859Snate@binkert.org
2284859Snate@binkert.org    def has_parent(self):
2294859Snate@binkert.org        return reduce(lambda x,y: x and y, [v.has_parent() for v in self])
2302740SN/A
2312740SN/A    # return 'cpu0 cpu1' etc. for print_ini()
2322740SN/A    def get_name(self):
2332740SN/A        return ' '.join([v._name for v in self])
2342740SN/A
2352740SN/A    # By iterating through the constituent members of the vector here
2362740SN/A    # we can nicely handle iterating over all a SimObject's children
2372740SN/A    # without having to provide lots of special functions on
2381527SN/A    # SimObjectVector directly.
2392740SN/A    def descendants(self):
2401585SN/A        for v in self:
2411427SN/A            for obj in v.descendants():
2422738SN/A                yield obj
2432738SN/A
2443105Sstever@eecs.umich.edu    def get_config_as_dict(self):
2452738SN/A        a = []
2461427SN/A        for v in self:
2471427SN/A            a.append(v.get_config_as_dict())
2481427SN/A        return a
2491427SN/A
2501427SN/Aclass VectorParamDesc(ParamDesc):
2511427SN/A    # Convert assigned value to appropriate type.  If the RHS is not a
2521427SN/A    # list or tuple, it generates a single-element list.
2531427SN/A    def convert(self, value):
2541427SN/A        if isinstance(value, (list, tuple)):
2551427SN/A            # list: coerce each element into new list
2561427SN/A            tmp_list = [ ParamDesc.convert(self, v) for v in value ]
2571427SN/A        else:
2581427SN/A            # singleton: coerce to a single-element list
2591427SN/A            tmp_list = [ ParamDesc.convert(self, value) ]
2601427SN/A
2611427SN/A        if isSimObjectSequence(tmp_list):
2623100SN/A            return SimObjectVector(tmp_list)
2633100SN/A        else:
2643100SN/A            return VectorParamValue(tmp_list)
2653100SN/A
2663100SN/A    def swig_module_name(self):
2673100SN/A        return "%s_vector" % self.ptype_str
2683105Sstever@eecs.umich.edu
2693105Sstever@eecs.umich.edu    def swig_predecls(self, code):
2703105Sstever@eecs.umich.edu        code('%import "${{self.swig_module_name()}}.i"')
2713105Sstever@eecs.umich.edu
2723105Sstever@eecs.umich.edu    def swig_decl(self, code):
2733105Sstever@eecs.umich.edu        code('%module(package="m5.internal") ${{self.swig_module_name()}}')
2743105Sstever@eecs.umich.edu        code('%{')
2753105Sstever@eecs.umich.edu        self.ptype.cxx_predecls(code)
2763105Sstever@eecs.umich.edu        code('%}')
2773105Sstever@eecs.umich.edu        code()
2783105Sstever@eecs.umich.edu        # Make sure the SWIGPY_SLICE_ARG is defined through this inclusion
2793105Sstever@eecs.umich.edu        code('%include "std_container.i"')
2803105Sstever@eecs.umich.edu        code()
2813105Sstever@eecs.umich.edu        self.ptype.swig_predecls(code)
2823105Sstever@eecs.umich.edu        code()
2833105Sstever@eecs.umich.edu        code('%include "std_vector.i"')
2843105Sstever@eecs.umich.edu        code()
2853105Sstever@eecs.umich.edu
2863105Sstever@eecs.umich.edu        ptype = self.ptype_str
2873105Sstever@eecs.umich.edu        cxx_type = self.ptype.cxx_type
2883105Sstever@eecs.umich.edu
2893105Sstever@eecs.umich.edu        code('''\
2903105Sstever@eecs.umich.edu%typemap(in) std::vector< $cxx_type >::value_type {
2913105Sstever@eecs.umich.edu    if (SWIG_ConvertPtr($$input, (void **)&$$1, $$1_descriptor, 0) == -1) {
2923105Sstever@eecs.umich.edu        if (SWIG_ConvertPtr($$input, (void **)&$$1,
2933105Sstever@eecs.umich.edu                            $$descriptor($cxx_type), 0) == -1) {
2943105Sstever@eecs.umich.edu            return NULL;
2953105Sstever@eecs.umich.edu        }
2963105Sstever@eecs.umich.edu    }
2973105Sstever@eecs.umich.edu}
2981585SN/A
2991310SN/A%typemap(in) std::vector< $cxx_type >::value_type * {
3001310SN/A    if (SWIG_ConvertPtr($$input, (void **)&$$1, $$1_descriptor, 0) == -1) {
3011310SN/A        if (SWIG_ConvertPtr($$input, (void **)&$$1,
3021310SN/A                            $$descriptor($cxx_type *), 0) == -1) {
3031310SN/A            return NULL;
3041310SN/A        }
3051310SN/A    }
3061310SN/A}
3071310SN/A''')
3081427SN/A
3091310SN/A        code('%template(vector_$ptype) std::vector< $cxx_type >;')
3101310SN/A
3112738SN/A    def cxx_predecls(self, code):
3123105Sstever@eecs.umich.edu        code('#include <vector>')
3132738SN/A        self.ptype.cxx_predecls(code)
3142738SN/A
3152740SN/A    def cxx_decl(self, code):
3162740SN/A        code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};')
3172740SN/A
3182740SN/Aclass ParamFactory(object):
3192740SN/A    def __init__(self, param_desc_class, ptype_str = None):
3202740SN/A        self.param_desc_class = param_desc_class
3212740SN/A        self.ptype_str = ptype_str
3223105Sstever@eecs.umich.edu
3231310SN/A    def __getattr__(self, attr):
3243105Sstever@eecs.umich.edu        if self.ptype_str:
3253105Sstever@eecs.umich.edu            attr = self.ptype_str + '.' + attr
3263105Sstever@eecs.umich.edu        return ParamFactory(self.param_desc_class, attr)
3273105Sstever@eecs.umich.edu
3283105Sstever@eecs.umich.edu    # E.g., Param.Int(5, "number of widgets")
3293105Sstever@eecs.umich.edu    def __call__(self, *args, **kwargs):
3303105Sstever@eecs.umich.edu        ptype = None
3313105Sstever@eecs.umich.edu        try:
3323105Sstever@eecs.umich.edu            ptype = allParams[self.ptype_str]
3332740SN/A        except KeyError:
3343105Sstever@eecs.umich.edu            # if name isn't defined yet, assume it's a SimObject, and
3353105Sstever@eecs.umich.edu            # try to resolve it later
3363105Sstever@eecs.umich.edu            pass
3373105Sstever@eecs.umich.edu        return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs)
3383105Sstever@eecs.umich.edu
3391310SN/AParam = ParamFactory(ParamDesc)
3401585SN/AVectorParam = ParamFactory(VectorParamDesc)
3411692SN/A
3421692SN/A#####################################################################
3431585SN/A#
3441585SN/A# Parameter Types
3451585SN/A#
3461585SN/A# Though native Python types could be used to specify parameter types
3473100SN/A# (the 'ptype' field of the Param and VectorParam classes), it's more
3483100SN/A# flexible to define our own set of types.  This gives us more control
3493100SN/A# over how Python expressions are converted to values (via the
3503100SN/A# __init__() constructor) and how these values are printed out (via
3514762Snate@binkert.org# the __str__() conversion method).
3524762Snate@binkert.org#
3534762Snate@binkert.org#####################################################################
3543100SN/A
3553100SN/A# String-valued parameter.  Just mixin the ParamValue class with the
3563100SN/A# built-in str class.
3573100SN/Aclass String(ParamValue,str):
3584762Snate@binkert.org    cxx_type = 'std::string'
3593100SN/A
3603100SN/A    @classmethod
3613100SN/A    def cxx_predecls(self, code):
3623100SN/A        code('#include <string>')
3633100SN/A
3643100SN/A    @classmethod
3653100SN/A    def swig_predecls(cls, code):
3663100SN/A        code('%include "std_string.i"')
3674762Snate@binkert.org
3684762Snate@binkert.org    def getValue(self):
3694762Snate@binkert.org        return self
3704762Snate@binkert.org
3714762Snate@binkert.org# superclass for "numeric" parameter values, to emulate math
3724762Snate@binkert.org# operations in a type-safe way.  e.g., a Latency times an int returns
3734762Snate@binkert.org# a new Latency object.
3744762Snate@binkert.orgclass NumericParamValue(ParamValue):
3754762Snate@binkert.org    def __str__(self):
3764762Snate@binkert.org        return str(self.value)
3774762Snate@binkert.org
3784762Snate@binkert.org    def __float__(self):
3794762Snate@binkert.org        return float(self.value)
3805610Snate@binkert.org
3815610Snate@binkert.org    def __long__(self):
3824762Snate@binkert.org        return long(self.value)
3834762Snate@binkert.org
3844762Snate@binkert.org    def __int__(self):
3854762Snate@binkert.org        return int(self.value)
3864762Snate@binkert.org
3874762Snate@binkert.org    # hook for bounds checking
3885610Snate@binkert.org    def _check(self):
3895488Snate@binkert.org        return
3905488Snate@binkert.org
3915488Snate@binkert.org    def __mul__(self, other):
3925488Snate@binkert.org        newobj = self.__class__(self)
3935488Snate@binkert.org        newobj.value *= other
3945488Snate@binkert.org        newobj._check()
3955488Snate@binkert.org        return newobj
3965488Snate@binkert.org
3975488Snate@binkert.org    __rmul__ = __mul__
3984762Snate@binkert.org
3995488Snate@binkert.org    def __div__(self, other):
4004762Snate@binkert.org        newobj = self.__class__(self)
4015610Snate@binkert.org        newobj.value /= other
4024762Snate@binkert.org        newobj._check()
4034762Snate@binkert.org        return newobj
4044762Snate@binkert.org
4054762Snate@binkert.org    def __sub__(self, other):
4064762Snate@binkert.org        newobj = self.__class__(self)
4074762Snate@binkert.org        newobj.value -= other
4084762Snate@binkert.org        newobj._check()
4094762Snate@binkert.org        return newobj
4104762Snate@binkert.org
4114762Snate@binkert.org# Metaclass for bounds-checked integer parameters.  See CheckedInt.
4124762Snate@binkert.orgclass CheckedIntType(MetaParamValue):
4134762Snate@binkert.org    def __init__(cls, name, bases, dict):
4144762Snate@binkert.org        super(CheckedIntType, cls).__init__(name, bases, dict)
4154762Snate@binkert.org
4164762Snate@binkert.org        # CheckedInt is an abstract base class, so we actually don't
4174762Snate@binkert.org        # want to do any processing on it... the rest of this code is
4184762Snate@binkert.org        # just for classes that derive from CheckedInt.
4194762Snate@binkert.org        if name == 'CheckedInt':
4204762Snate@binkert.org            return
4214762Snate@binkert.org
4224762Snate@binkert.org        if not (hasattr(cls, 'min') and hasattr(cls, 'max')):
4234762Snate@binkert.org            if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')):
4244762Snate@binkert.org                panic("CheckedInt subclass %s must define either\n" \
4254762Snate@binkert.org                      "    'min' and 'max' or 'size' and 'unsigned'\n",
4264762Snate@binkert.org                      name);
4274762Snate@binkert.org            if cls.unsigned:
4284762Snate@binkert.org                cls.min = 0
4294762Snate@binkert.org                cls.max = 2 ** cls.size - 1
4303100SN/A            else:
4313100SN/A                cls.min = -(2 ** (cls.size - 1))
4323100SN/A                cls.max = (2 ** (cls.size - 1)) - 1
4333100SN/A
4343100SN/A# Abstract superclass for bounds-checked integer parameters.  This
4353100SN/A# class is subclassed to generate parameter classes with specific
4363100SN/A# bounds.  Initialization of the min and max bounds is done in the
4373100SN/A# metaclass CheckedIntType.__init__.
4383100SN/Aclass CheckedInt(NumericParamValue):
4393100SN/A    __metaclass__ = CheckedIntType
4403100SN/A
4415610Snate@binkert.org    def _check(self):
4425610Snate@binkert.org        if not self.min <= self.value <= self.max:
4433100SN/A            raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
4444762Snate@binkert.org                  (self.min, self.value, self.max)
4454762Snate@binkert.org
4464762Snate@binkert.org    def __init__(self, value):
4474762Snate@binkert.org        if isinstance(value, str):
4483100SN/A            self.value = convert.toInteger(value)
4494762Snate@binkert.org        elif isinstance(value, (int, long, float, NumericParamValue)):
4503100SN/A            self.value = long(value)
4513100SN/A        else:
4523100SN/A            raise TypeError, "Can't convert object of type %s to CheckedInt" \
4533100SN/A                  % type(value).__name__
4542740SN/A        self._check()
455679SN/A
456679SN/A    @classmethod
4571692SN/A    def cxx_predecls(cls, code):
4581692SN/A        # most derived types require this, so we just do it here once
459679SN/A        code('#include "base/types.hh"')
4601692SN/A
4613100SN/A    @classmethod
4624762Snate@binkert.org    def swig_predecls(cls, code):
4633100SN/A        # most derived types require this, so we just do it here once
4644859Snate@binkert.org        code('%import "stdint.i"')
465679SN/A        code('%import "base/types.hh"')
4662740SN/A
4672740SN/A    def getValue(self):
4682740SN/A        return long(self.value)
4692740SN/A
4702740SN/Aclass Int(CheckedInt):      cxx_type = 'int';      size = 32; unsigned = False
4712740SN/Aclass Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True
4722740SN/A
4732740SN/Aclass Int8(CheckedInt):     cxx_type =   'int8_t'; size =  8; unsigned = False
4742740SN/Aclass UInt8(CheckedInt):    cxx_type =  'uint8_t'; size =  8; unsigned = True
4752740SN/Aclass Int16(CheckedInt):    cxx_type =  'int16_t'; size = 16; unsigned = False
4762740SN/Aclass UInt16(CheckedInt):   cxx_type = 'uint16_t'; size = 16; unsigned = True
4772740SN/Aclass Int32(CheckedInt):    cxx_type =  'int32_t'; size = 32; unsigned = False
4782740SN/Aclass UInt32(CheckedInt):   cxx_type = 'uint32_t'; size = 32; unsigned = True
4792740SN/Aclass Int64(CheckedInt):    cxx_type =  'int64_t'; size = 64; unsigned = False
4802740SN/Aclass UInt64(CheckedInt):   cxx_type = 'uint64_t'; size = 64; unsigned = True
4812740SN/A
4822711SN/Aclass Counter(CheckedInt):  cxx_type = 'Counter';  size = 64; unsigned = True
4832740SN/Aclass Tick(CheckedInt):     cxx_type = 'Tick';     size = 64; unsigned = True
4842740SN/Aclass TcpPort(CheckedInt):  cxx_type = 'uint16_t'; size = 16; unsigned = True
4852740SN/Aclass UdpPort(CheckedInt):  cxx_type = 'uint16_t'; size = 16; unsigned = True
4862711SN/A
4872740SN/Aclass Percent(CheckedInt):  cxx_type = 'int'; min = 0; max = 100
4882740SN/A
4892740SN/Aclass Cycles(CheckedInt):
4902740SN/A    cxx_type = 'Cycles'
4914762Snate@binkert.org    size = 64
4922740SN/A    unsigned = True
4932712SN/A
4942711SN/A    def getValue(self):
4952711SN/A        from m5.internal.core import Cycles
4962740SN/A        return Cycles(self.value)
4972740SN/A
4982740SN/Aclass Float(ParamValue, float):
4992740SN/A    cxx_type = 'double'
5002740SN/A
5012740SN/A    def __init__(self, value):
5022740SN/A        if isinstance(value, (int, long, float, NumericParamValue, Float)):
5032740SN/A            self.value = float(value)
5042740SN/A        else:
5053105Sstever@eecs.umich.edu            raise TypeError, "Can't convert object of type %s to Float" \
5063105Sstever@eecs.umich.edu                  % type(value).__name__
5073105Sstever@eecs.umich.edu
5081692SN/A    def getValue(self):
5091692SN/A        return float(self.value)
5101692SN/A
511679SN/Aclass MemorySize(CheckedInt):
5122740SN/A    cxx_type = 'uint64_t'
5132740SN/A    size = 64
5142740SN/A    unsigned = True
5152740SN/A    def __init__(self, value):
5162740SN/A        if isinstance(value, MemorySize):
5171692SN/A            self.value = value.value
5182740SN/A        else:
5192740SN/A            self.value = convert.toMemorySize(value)
5202740SN/A        self._check()
5212740SN/A
5222740SN/Aclass MemorySize32(CheckedInt):
5232740SN/A    cxx_type = 'uint32_t'
5242740SN/A    size = 32
5252740SN/A    unsigned = True
5262740SN/A    def __init__(self, value):
5272740SN/A        if isinstance(value, MemorySize):
5282740SN/A            self.value = value.value
5292740SN/A        else:
5302740SN/A            self.value = convert.toMemorySize(value)
5312740SN/A        self._check()
5322740SN/A
5331343SN/Aclass Addr(CheckedInt):
5343105Sstever@eecs.umich.edu    cxx_type = 'Addr'
5353105Sstever@eecs.umich.edu    size = 64
5363105Sstever@eecs.umich.edu    unsigned = True
5373105Sstever@eecs.umich.edu    def __init__(self, value):
5383105Sstever@eecs.umich.edu        if isinstance(value, Addr):
5393105Sstever@eecs.umich.edu            self.value = value.value
5403105Sstever@eecs.umich.edu        else:
5413105Sstever@eecs.umich.edu            try:
5423105Sstever@eecs.umich.edu                self.value = convert.toMemorySize(value)
5433105Sstever@eecs.umich.edu            except TypeError:
5441692SN/A                self.value = long(value)
5452738SN/A        self._check()
5463105Sstever@eecs.umich.edu    def __add__(self, other):
5472738SN/A        if isinstance(other, Addr):
5481692SN/A            return self.value + other.value
5491692SN/A        else:
5501427SN/A            return self.value + other
5511692SN/A
5521692SN/Aclass AddrRange(ParamValue):
5531427SN/A    cxx_type = 'AddrRange'
5541692SN/A
5551692SN/A    def __init__(self, *args, **kwargs):
5561692SN/A        # Disable interleaving by default
5571692SN/A        self.intlvHighBit = 0
5581692SN/A        self.intlvBits = 0
5591692SN/A        self.intlvMatch = 0
5601692SN/A
5611427SN/A        def handle_kwargs(self, kwargs):
5622738SN/A            # An address range needs to have an upper limit, specified
5632738SN/A            # either explicitly with an end, or as an offset using the
5643105Sstever@eecs.umich.edu            # size keyword.
5652738SN/A            if 'end' in kwargs:
5662738SN/A                self.end = Addr(kwargs.pop('end'))
5672740SN/A            elif 'size' in kwargs:
5682740SN/A                self.end = self.start + Addr(kwargs.pop('size')) - 1
5692740SN/A            else:
5702740SN/A                raise TypeError, "Either end or size must be specified"
5712740SN/A
5721692SN/A            # Now on to the optional bit
5733105Sstever@eecs.umich.edu            if 'intlvHighBit' in kwargs:
5741692SN/A                self.intlvHighBit = int(kwargs.pop('intlvHighBit'))
5751310SN/A            if 'intlvBits' in kwargs:
5761692SN/A                self.intlvBits = int(kwargs.pop('intlvBits'))
5771587SN/A            if 'intlvMatch' in kwargs:
5781692SN/A                self.intlvMatch = int(kwargs.pop('intlvMatch'))
5791692SN/A
5801605SN/A        if len(args) == 0:
5811605SN/A            self.start = Addr(kwargs.pop('start'))
5823105Sstever@eecs.umich.edu            handle_kwargs(self, kwargs)
5833105Sstever@eecs.umich.edu
5841310SN/A        elif len(args) == 1:
5853105Sstever@eecs.umich.edu            if kwargs:
5863105Sstever@eecs.umich.edu                self.start = Addr(args[0])
5873105Sstever@eecs.umich.edu                handle_kwargs(self, kwargs)
5881693SN/A            elif isinstance(args[0], (list, tuple)):
5893105Sstever@eecs.umich.edu                self.start = Addr(args[0][0])
5903105Sstever@eecs.umich.edu                self.end = Addr(args[0][1])
5913105Sstever@eecs.umich.edu            else:
5921310SN/A                self.start = Addr(0)
5931310SN/A                self.end = Addr(args[0]) - 1
5941692SN/A
5951692SN/A        elif len(args) == 2:
5961692SN/A            self.start = Addr(args[0])
5971692SN/A            self.end = Addr(args[1])
5981692SN/A        else:
5991692SN/A            raise TypeError, "Too many arguments specified"
6001310SN/A
6011693SN/A        if kwargs:
6021693SN/A            raise TypeError, "Too many keywords: %s" % kwargs.keys()
6031693SN/A
6041693SN/A    def __str__(self):
6051693SN/A        return '%s:%s' % (self.start, self.end)
6061693SN/A
6071693SN/A    def size(self):
6081693SN/A        # Divide the size by the size of the interleaving slice
6091693SN/A        return (long(self.end) - long(self.start) + 1) >> self.intlvBits
6101693SN/A
6111692SN/A    @classmethod
6121692SN/A    def cxx_predecls(cls, code):
6131310SN/A        Addr.cxx_predecls(code)
6143105Sstever@eecs.umich.edu        code('#include "base/addr_range.hh"')
6152740SN/A
6161692SN/A    @classmethod
6171692SN/A    def swig_predecls(cls, code):
6181692SN/A        Addr.swig_predecls(code)
6191310SN/A
6203105Sstever@eecs.umich.edu    def getValue(self):
6213105Sstever@eecs.umich.edu        # Go from the Python class to the wrapped C++ class generated
6223105Sstever@eecs.umich.edu        # by swig
6233105Sstever@eecs.umich.edu        from m5.internal.range import AddrRange
6243105Sstever@eecs.umich.edu
6253105Sstever@eecs.umich.edu        return AddrRange(long(self.start), long(self.end),
6263105Sstever@eecs.umich.edu                         int(self.intlvHighBit), int(self.intlvBits),
6273105Sstever@eecs.umich.edu                         int(self.intlvMatch))
6283105Sstever@eecs.umich.edu
6294762Snate@binkert.org# Boolean parameter type.  Python doesn't let you subclass bool, since
6304762Snate@binkert.org# it doesn't want to let you create multiple instances of True and
6314762Snate@binkert.org# False.  Thus this is a little more complicated than String.
6325766Snate@binkert.orgclass Bool(ParamValue):
6334762Snate@binkert.org    cxx_type = 'bool'
6345766Snate@binkert.org    def __init__(self, value):
6353105Sstever@eecs.umich.edu        try:
6363105Sstever@eecs.umich.edu            self.value = convert.toBool(value)
6373105Sstever@eecs.umich.edu        except TypeError:
6381692SN/A            self.value = bool(value)
6392740SN/A
6401692SN/A    def getValue(self):
6411692SN/A        return bool(self.value)
6421692SN/A
6431692SN/A    def __str__(self):
6441692SN/A        return str(self.value)
6451310SN/A
6461692SN/A    # implement truth value testing for Bool parameters so that these params
6471692SN/A    # evaluate correctly during the python configuration phase
6481310SN/A    def __nonzero__(self):
6491692SN/A        return bool(self.value)
6501692SN/A
6511310SN/A    def ini_str(self):
6521692SN/A        if self.value:
6531692SN/A            return 'true'
6541692SN/A        return 'false'
6551310SN/A
6561692SN/Adef IncEthernetAddr(addr, val = 1):
6571692SN/A    bytes = map(lambda x: int(x, 16), addr.split(':'))
6581692SN/A    bytes[5] += val
6591692SN/A    for i in (5, 4, 3, 2, 1):
6601692SN/A        val,rem = divmod(bytes[i], 256)
6611692SN/A        bytes[i] = rem
6621814SN/A        if val == 0:
6631692SN/A            break
6641692SN/A        bytes[i - 1] += val
6651692SN/A    assert(bytes[0] <= 255)
6661692SN/A    return ':'.join(map(lambda x: '%02x' % x, bytes))
6671692SN/A
6681692SN/A_NextEthernetAddr = "00:90:00:00:00:01"
6691692SN/Adef NextEthernetAddr():
6701692SN/A    global _NextEthernetAddr
6711692SN/A
6721692SN/A    value = _NextEthernetAddr
6731692SN/A    _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1)
6741815SN/A    return value
6751815SN/A
6761815SN/Aclass EthernetAddr(ParamValue):
6773105Sstever@eecs.umich.edu    cxx_type = 'Net::EthAddr'
6783105Sstever@eecs.umich.edu
6793105Sstever@eecs.umich.edu    @classmethod
6803105Sstever@eecs.umich.edu    def cxx_predecls(cls, code):
6813105Sstever@eecs.umich.edu        code('#include "base/inet.hh"')
6823105Sstever@eecs.umich.edu
6833105Sstever@eecs.umich.edu    @classmethod
6843105Sstever@eecs.umich.edu    def swig_predecls(cls, code):
6853105Sstever@eecs.umich.edu        code('%include "python/swig/inet.i"')
6863105Sstever@eecs.umich.edu
6873105Sstever@eecs.umich.edu    def __init__(self, value):
6883105Sstever@eecs.umich.edu        if value == NextEthernetAddr:
6893107Sstever@eecs.umich.edu            self.value = value
6903107Sstever@eecs.umich.edu            return
6913107Sstever@eecs.umich.edu
6923107Sstever@eecs.umich.edu        if not isinstance(value, str):
6933107Sstever@eecs.umich.edu            raise TypeError, "expected an ethernet address and didn't get one"
6943105Sstever@eecs.umich.edu
6953105Sstever@eecs.umich.edu        bytes = value.split(':')
6963105Sstever@eecs.umich.edu        if len(bytes) != 6:
6973105Sstever@eecs.umich.edu            raise TypeError, 'invalid ethernet address %s' % value
6983107Sstever@eecs.umich.edu
6993107Sstever@eecs.umich.edu        for byte in bytes:
7003107Sstever@eecs.umich.edu            if not 0 <= int(byte, base=16) <= 0xff:
7013107Sstever@eecs.umich.edu                raise TypeError, 'invalid ethernet address %s' % value
7023107Sstever@eecs.umich.edu
7033105Sstever@eecs.umich.edu        self.value = value
7045037Smilesck@eecs.umich.edu
7055543Ssaidi@eecs.umich.edu    def unproxy(self, base):
7061692SN/A        if self.value == NextEthernetAddr:
7072738SN/A            return EthernetAddr(self.value())
7082738SN/A        return self
7094081Sbinkertn@umich.edu
7105037Smilesck@eecs.umich.edu    def getValue(self):
7111692SN/A        from m5.internal.params import EthAddr
7121692SN/A        return EthAddr(self.value)
7131692SN/A
7144081Sbinkertn@umich.edu    def ini_str(self):
7155037Smilesck@eecs.umich.edu        return self.value
7161692SN/A
7171692SN/A# When initializing an IpAddress, pass in an existing IpAddress, a string of
7181692SN/A# the form "a.b.c.d", or an integer representing an IP.
7191692SN/Aclass IpAddress(ParamValue):
7203105Sstever@eecs.umich.edu    cxx_type = 'Net::IpAddress'
7211692SN/A
7225037Smilesck@eecs.umich.edu    @classmethod
7235037Smilesck@eecs.umich.edu    def cxx_predecls(cls, code):
7241692SN/A        code('#include "base/inet.hh"')
7253103Sstever@eecs.umich.edu
7263103Sstever@eecs.umich.edu    @classmethod
7273103Sstever@eecs.umich.edu    def swig_predecls(cls, code):
7283105Sstever@eecs.umich.edu        code('%include "python/swig/inet.i"')
7293105Sstever@eecs.umich.edu
7305037Smilesck@eecs.umich.edu    def __init__(self, value):
7313103Sstever@eecs.umich.edu        if isinstance(value, IpAddress):
7325543Ssaidi@eecs.umich.edu            self.ip = value.ip
7331692SN/A        else:
7341692SN/A            try:
7355037Smilesck@eecs.umich.edu                self.ip = convert.toIpAddress(value)
7361692SN/A            except TypeError:
7374762Snate@binkert.org                self.ip = long(value)
7384762Snate@binkert.org        self.verifyIp()
7394762Snate@binkert.org
7404762Snate@binkert.org    def __str__(self):
7415033Smilesck@eecs.umich.edu        tup = [(self.ip >> i)  & 0xff for i in (24, 16, 8, 0)]
7424762Snate@binkert.org        return '%d.%d.%d.%d' % tuple(tup)
7435488Snate@binkert.org
7444762Snate@binkert.org    def __eq__(self, other):
7454762Snate@binkert.org        if isinstance(other, IpAddress):
7464762Snate@binkert.org            return self.ip == other.ip
7474762Snate@binkert.org        elif isinstance(other, str):
7484762Snate@binkert.org            try:
7494762Snate@binkert.org                return self.ip == convert.toIpAddress(other)
7504762Snate@binkert.org            except:
7514762Snate@binkert.org                return False
7524762Snate@binkert.org        else:
7534762Snate@binkert.org            return self.ip == other
7544762Snate@binkert.org
7554762Snate@binkert.org    def __ne__(self, other):
7564762Snate@binkert.org        return not (self == other)
7574762Snate@binkert.org
7584762Snate@binkert.org    def verifyIp(self):
7594762Snate@binkert.org        if self.ip < 0 or self.ip >= (1 << 32):
7604762Snate@binkert.org            raise TypeError, "invalid ip address %#08x" % self.ip
7614762Snate@binkert.org
7624762Snate@binkert.org    def getValue(self):
7634762Snate@binkert.org        from m5.internal.params import IpAddress
7644762Snate@binkert.org        return IpAddress(self.ip)
7654762Snate@binkert.org
7664762Snate@binkert.org# When initializing an IpNetmask, pass in an existing IpNetmask, a string of
7674762Snate@binkert.org# the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as
7684762Snate@binkert.org# positional or keyword arguments.
7694762Snate@binkert.orgclass IpNetmask(IpAddress):
7704762Snate@binkert.org    cxx_type = 'Net::IpNetmask'
7712738SN/A
7722740SN/A    @classmethod
7732740SN/A    def cxx_predecls(cls, code):
7742740SN/A        code('#include "base/inet.hh"')
7752740SN/A
7762740SN/A    @classmethod
7775244Sgblack@eecs.umich.edu    def swig_predecls(cls, code):
7785244Sgblack@eecs.umich.edu        code('%include "python/swig/inet.i"')
7795244Sgblack@eecs.umich.edu
7805244Sgblack@eecs.umich.edu    def __init__(self, *args, **kwargs):
7814762Snate@binkert.org        def handle_kwarg(self, kwargs, key, elseVal = None):
7822740SN/A            if key in kwargs:
7835244Sgblack@eecs.umich.edu                setattr(self, key, kwargs.pop(key))
7842740SN/A            elif elseVal:
7852740SN/A                setattr(self, key, elseVal)
7862740SN/A            else:
7874762Snate@binkert.org                raise TypeError, "No value set for %s" % key
7884762Snate@binkert.org
7894762Snate@binkert.org        if len(args) == 0:
7904762Snate@binkert.org            handle_kwarg(self, kwargs, 'ip')
7914762Snate@binkert.org            handle_kwarg(self, kwargs, 'netmask')
7924762Snate@binkert.org
7934762Snate@binkert.org        elif len(args) == 1:
7944762Snate@binkert.org            if kwargs:
7954762Snate@binkert.org                if not 'ip' in kwargs and not 'netmask' in kwargs:
7964762Snate@binkert.org                    raise TypeError, "Invalid arguments"
7974762Snate@binkert.org                handle_kwarg(self, kwargs, 'ip', args[0])
7982738SN/A                handle_kwarg(self, kwargs, 'netmask', args[0])
7993105Sstever@eecs.umich.edu            elif isinstance(args[0], IpNetmask):
8002738SN/A                self.ip = args[0].ip
8013105Sstever@eecs.umich.edu                self.netmask = args[0].netmask
8023105Sstever@eecs.umich.edu            else:
8032738SN/A                (self.ip, self.netmask) = convert.toIpNetmask(args[0])
8042738SN/A
8052738SN/A        elif len(args) == 2:
8062839SN/A            self.ip = args[0]
8072797SN/A            self.netmask = args[1]
8084081Sbinkertn@umich.edu        else:
8092901SN/A            raise TypeError, "Too many arguments specified"
8102797SN/A
8112797SN/A        if kwargs:
8122839SN/A            raise TypeError, "Too many keywords: %s" % kwargs.keys()
8132797SN/A
8142797SN/A        self.verify()
8152797SN/A
8164081Sbinkertn@umich.edu    def __str__(self):
8172797SN/A        return "%s/%d" % (super(IpNetmask, self).__str__(), self.netmask)
8182797SN/A
8192797SN/A    def __eq__(self, other):
8202797SN/A        if isinstance(other, IpNetmask):
8214553Sbinkertn@umich.edu            return self.ip == other.ip and self.netmask == other.netmask
8224553Sbinkertn@umich.edu        elif isinstance(other, str):
8234553Sbinkertn@umich.edu            try:
8244553Sbinkertn@umich.edu                return (self.ip, self.netmask) == convert.toIpNetmask(other)
8254859Snate@binkert.org            except:
8264553Sbinkertn@umich.edu                return False
8272797SN/A        else:
8283202Shsul@eecs.umich.edu            return False
8293202Shsul@eecs.umich.edu
8303202Shsul@eecs.umich.edu    def verify(self):
8313202Shsul@eecs.umich.edu        self.verifyIp()
8324859Snate@binkert.org        if self.netmask < 0 or self.netmask > 32:
8332797SN/A            raise TypeError, "invalid netmask %d" % netmask
8342797SN/A
8352797SN/A    def getValue(self):
8362797SN/A        from m5.internal.params import IpNetmask
8374859Snate@binkert.org        return IpNetmask(self.ip, self.netmask)
8382797SN/A
8391692SN/A# When initializing an IpWithPort, pass in an existing IpWithPort, a string of
8401692SN/A# the form "a.b.c.d:p", or an ip and port as positional or keyword arguments.
8411342SN/Aclass IpWithPort(IpAddress):
8421342SN/A    cxx_type = 'Net::IpWithPort'
8431342SN/A
8441342SN/A    @classmethod
8451342SN/A    def cxx_predecls(cls, code):
8461342SN/A        code('#include "base/inet.hh"')
8471342SN/A
8481342SN/A    @classmethod
8491342SN/A    def swig_predecls(cls, code):
8501342SN/A        code('%include "python/swig/inet.i"')
8511342SN/A
8521342SN/A    def __init__(self, *args, **kwargs):
8531342SN/A        def handle_kwarg(self, kwargs, key, elseVal = None):
8541342SN/A            if key in kwargs:
8551342SN/A                setattr(self, key, kwargs.pop(key))
8561342SN/A            elif elseVal:
8571342SN/A                setattr(self, key, elseVal)
8581342SN/A            else:
8591692SN/A                raise TypeError, "No value set for %s" % key
8601342SN/A
8611587SN/A        if len(args) == 0:
8621605SN/A            handle_kwarg(self, kwargs, 'ip')
8631605SN/A            handle_kwarg(self, kwargs, 'port')
8641342SN/A
8651605SN/A        elif len(args) == 1:
8661692SN/A            if kwargs:
8671342SN/A                if not 'ip' in kwargs and not 'port' in kwargs:
8681342SN/A                    raise TypeError, "Invalid arguments"
8691342SN/A                handle_kwarg(self, kwargs, 'ip', args[0])
8701342SN/A                handle_kwarg(self, kwargs, 'port', args[0])
8711342SN/A            elif isinstance(args[0], IpWithPort):
8721342SN/A                self.ip = args[0].ip
8731587SN/A                self.port = args[0].port
8741587SN/A            else:
8751342SN/A                (self.ip, self.port) = convert.toIpWithPort(args[0])
8761342SN/A
8771342SN/A        elif len(args) == 2:
8781342SN/A            self.ip = args[0]
8791342SN/A            self.port = args[1]
8801342SN/A        else:
8811342SN/A            raise TypeError, "Too many arguments specified"
8823101Sstever@eecs.umich.edu
8833101Sstever@eecs.umich.edu        if kwargs:
8843101Sstever@eecs.umich.edu            raise TypeError, "Too many keywords: %s" % kwargs.keys()
8853101Sstever@eecs.umich.edu
886679SN/A        self.verify()
8871528SN/A
8881528SN/A    def __str__(self):
8891528SN/A        return "%s:%d" % (super(IpWithPort, self).__str__(), self.port)
8904762Snate@binkert.org
891    def __eq__(self, other):
892        if isinstance(other, IpWithPort):
893            return self.ip == other.ip and self.port == other.port
894        elif isinstance(other, str):
895            try:
896                return (self.ip, self.port) == convert.toIpWithPort(other)
897            except:
898                return False
899        else:
900            return False
901
902    def verify(self):
903        self.verifyIp()
904        if self.port < 0 or self.port > 0xffff:
905            raise TypeError, "invalid port %d" % self.port
906
907    def getValue(self):
908        from m5.internal.params import IpWithPort
909        return IpWithPort(self.ip, self.port)
910
911time_formats = [ "%a %b %d %H:%M:%S %Z %Y",
912                 "%a %b %d %H:%M:%S %Z %Y",
913                 "%Y/%m/%d %H:%M:%S",
914                 "%Y/%m/%d %H:%M",
915                 "%Y/%m/%d",
916                 "%m/%d/%Y %H:%M:%S",
917                 "%m/%d/%Y %H:%M",
918                 "%m/%d/%Y",
919                 "%m/%d/%y %H:%M:%S",
920                 "%m/%d/%y %H:%M",
921                 "%m/%d/%y"]
922
923
924def parse_time(value):
925    from time import gmtime, strptime, struct_time, time
926    from datetime import datetime, date
927
928    if isinstance(value, struct_time):
929        return value
930
931    if isinstance(value, (int, long)):
932        return gmtime(value)
933
934    if isinstance(value, (datetime, date)):
935        return value.timetuple()
936
937    if isinstance(value, str):
938        if value in ('Now', 'Today'):
939            return time.gmtime(time.time())
940
941        for format in time_formats:
942            try:
943                return strptime(value, format)
944            except ValueError:
945                pass
946
947    raise ValueError, "Could not parse '%s' as a time" % value
948
949class Time(ParamValue):
950    cxx_type = 'tm'
951
952    @classmethod
953    def cxx_predecls(cls, code):
954        code('#include <time.h>')
955
956    @classmethod
957    def swig_predecls(cls, code):
958        code('%include "python/swig/time.i"')
959
960    def __init__(self, value):
961        self.value = parse_time(value)
962
963    def getValue(self):
964        from m5.internal.params import tm
965
966        c_time = tm()
967        py_time = self.value
968
969        # UNIX is years since 1900
970        c_time.tm_year = py_time.tm_year - 1900;
971
972        # Python starts at 1, UNIX starts at 0
973        c_time.tm_mon =  py_time.tm_mon - 1;
974        c_time.tm_mday = py_time.tm_mday;
975        c_time.tm_hour = py_time.tm_hour;
976        c_time.tm_min = py_time.tm_min;
977        c_time.tm_sec = py_time.tm_sec;
978
979        # Python has 0 as Monday, UNIX is 0 as sunday
980        c_time.tm_wday = py_time.tm_wday + 1
981        if c_time.tm_wday > 6:
982            c_time.tm_wday -= 7;
983
984        # Python starts at 1, Unix starts at 0
985        c_time.tm_yday = py_time.tm_yday - 1;
986
987        return c_time
988
989    def __str__(self):
990        return time.asctime(self.value)
991
992    def ini_str(self):
993        return str(self)
994
995    def get_config_as_dict(self):
996        return str(self)
997
998# Enumerated types are a little more complex.  The user specifies the
999# type as Enum(foo) where foo is either a list or dictionary of
1000# alternatives (typically strings, but not necessarily so).  (In the
1001# long run, the integer value of the parameter will be the list index
1002# or the corresponding dictionary value.  For now, since we only check
1003# that the alternative is valid and then spit it into a .ini file,
1004# there's not much point in using the dictionary.)
1005
1006# What Enum() must do is generate a new type encapsulating the
1007# provided list/dictionary so that specific values of the parameter
1008# can be instances of that type.  We define two hidden internal
1009# classes (_ListEnum and _DictEnum) to serve as base classes, then
1010# derive the new type from the appropriate base class on the fly.
1011
1012allEnums = {}
1013# Metaclass for Enum types
1014class MetaEnum(MetaParamValue):
1015    def __new__(mcls, name, bases, dict):
1016        assert name not in allEnums
1017
1018        cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict)
1019        allEnums[name] = cls
1020        return cls
1021
1022    def __init__(cls, name, bases, init_dict):
1023        if init_dict.has_key('map'):
1024            if not isinstance(cls.map, dict):
1025                raise TypeError, "Enum-derived class attribute 'map' " \
1026                      "must be of type dict"
1027            # build list of value strings from map
1028            cls.vals = cls.map.keys()
1029            cls.vals.sort()
1030        elif init_dict.has_key('vals'):
1031            if not isinstance(cls.vals, list):
1032                raise TypeError, "Enum-derived class attribute 'vals' " \
1033                      "must be of type list"
1034            # build string->value map from vals sequence
1035            cls.map = {}
1036            for idx,val in enumerate(cls.vals):
1037                cls.map[val] = idx
1038        else:
1039            raise TypeError, "Enum-derived class must define "\
1040                  "attribute 'map' or 'vals'"
1041
1042        cls.cxx_type = 'Enums::%s' % name
1043
1044        super(MetaEnum, cls).__init__(name, bases, init_dict)
1045
1046    # Generate C++ class declaration for this enum type.
1047    # Note that we wrap the enum in a class/struct to act as a namespace,
1048    # so that the enum strings can be brief w/o worrying about collisions.
1049    def cxx_decl(cls, code):
1050        name = cls.__name__
1051        code('''\
1052#ifndef __ENUM__${name}__
1053#define __ENUM__${name}__
1054
1055namespace Enums {
1056    enum $name {
1057''')
1058        code.indent(2)
1059        for val in cls.vals:
1060            code('$val = ${{cls.map[val]}},')
1061        code('Num_$name = ${{len(cls.vals)}}')
1062        code.dedent(2)
1063        code('''\
1064    };
1065extern const char *${name}Strings[Num_${name}];
1066}
1067
1068#endif // __ENUM__${name}__
1069''')
1070
1071    def cxx_def(cls, code):
1072        name = cls.__name__
1073        code('''\
1074#include "enums/$name.hh"
1075namespace Enums {
1076    const char *${name}Strings[Num_${name}] =
1077    {
1078''')
1079        code.indent(2)
1080        for val in cls.vals:
1081            code('"$val",')
1082        code.dedent(2)
1083        code('''
1084    };
1085} // namespace Enums
1086''')
1087
1088    def swig_decl(cls, code):
1089        name = cls.__name__
1090        code('''\
1091%module(package="m5.internal") enum_$name
1092
1093%{
1094#include "enums/$name.hh"
1095%}
1096
1097%include "enums/$name.hh"
1098''')
1099
1100
1101# Base class for enum types.
1102class Enum(ParamValue):
1103    __metaclass__ = MetaEnum
1104    vals = []
1105
1106    def __init__(self, value):
1107        if value not in self.map:
1108            raise TypeError, "Enum param got bad value '%s' (not in %s)" \
1109                  % (value, self.vals)
1110        self.value = value
1111
1112    @classmethod
1113    def cxx_predecls(cls, code):
1114        code('#include "enums/$0.hh"', cls.__name__)
1115
1116    @classmethod
1117    def swig_predecls(cls, code):
1118        code('%import "python/m5/internal/enum_$0.i"', cls.__name__)
1119
1120    def getValue(self):
1121        return int(self.map[self.value])
1122
1123    def __str__(self):
1124        return self.value
1125
1126# how big does a rounding error need to be before we warn about it?
1127frequency_tolerance = 0.001  # 0.1%
1128
1129class TickParamValue(NumericParamValue):
1130    cxx_type = 'Tick'
1131
1132    @classmethod
1133    def cxx_predecls(cls, code):
1134        code('#include "base/types.hh"')
1135
1136    @classmethod
1137    def swig_predecls(cls, code):
1138        code('%import "stdint.i"')
1139        code('%import "base/types.hh"')
1140
1141    def getValue(self):
1142        return long(self.value)
1143
1144class Latency(TickParamValue):
1145    def __init__(self, value):
1146        if isinstance(value, (Latency, Clock)):
1147            self.ticks = value.ticks
1148            self.value = value.value
1149        elif isinstance(value, Frequency):
1150            self.ticks = value.ticks
1151            self.value = 1.0 / value.value
1152        elif value.endswith('t'):
1153            self.ticks = True
1154            self.value = int(value[:-1])
1155        else:
1156            self.ticks = False
1157            self.value = convert.toLatency(value)
1158
1159    def __getattr__(self, attr):
1160        if attr in ('latency', 'period'):
1161            return self
1162        if attr == 'frequency':
1163            return Frequency(self)
1164        raise AttributeError, "Latency object has no attribute '%s'" % attr
1165
1166    def getValue(self):
1167        if self.ticks or self.value == 0:
1168            value = self.value
1169        else:
1170            value = ticks.fromSeconds(self.value)
1171        return long(value)
1172
1173    # convert latency to ticks
1174    def ini_str(self):
1175        return '%d' % self.getValue()
1176
1177class Frequency(TickParamValue):
1178    def __init__(self, value):
1179        if isinstance(value, (Latency, Clock)):
1180            if value.value == 0:
1181                self.value = 0
1182            else:
1183                self.value = 1.0 / value.value
1184            self.ticks = value.ticks
1185        elif isinstance(value, Frequency):
1186            self.value = value.value
1187            self.ticks = value.ticks
1188        else:
1189            self.ticks = False
1190            self.value = convert.toFrequency(value)
1191
1192    def __getattr__(self, attr):
1193        if attr == 'frequency':
1194            return self
1195        if attr in ('latency', 'period'):
1196            return Latency(self)
1197        raise AttributeError, "Frequency object has no attribute '%s'" % attr
1198
1199    # convert latency to ticks
1200    def getValue(self):
1201        if self.ticks or self.value == 0:
1202            value = self.value
1203        else:
1204            value = ticks.fromSeconds(1.0 / self.value)
1205        return long(value)
1206
1207    def ini_str(self):
1208        return '%d' % self.getValue()
1209
1210# A generic frequency and/or Latency value. Value is stored as a
1211# latency, and any manipulation using a multiplier thus scales the
1212# clock period, i.e. a 2x multiplier doubles the clock period and thus
1213# halves the clock frequency.
1214class Clock(ParamValue):
1215    cxx_type = 'Tick'
1216
1217    @classmethod
1218    def cxx_predecls(cls, code):
1219        code('#include "base/types.hh"')
1220
1221    @classmethod
1222    def swig_predecls(cls, code):
1223        code('%import "stdint.i"')
1224        code('%import "base/types.hh"')
1225
1226    def __init__(self, value):
1227        if isinstance(value, (Latency, Clock)):
1228            self.ticks = value.ticks
1229            self.value = value.value
1230        elif isinstance(value, Frequency):
1231            self.ticks = value.ticks
1232            self.value = 1.0 / value.value
1233        elif value.endswith('t'):
1234            self.ticks = True
1235            self.value = int(value[:-1])
1236        else:
1237            self.ticks = False
1238            self.value = convert.anyToLatency(value)
1239
1240    def __getattr__(self, attr):
1241        if attr == 'frequency':
1242            return Frequency(self)
1243        if attr in ('latency', 'period'):
1244            return Latency(self)
1245        raise AttributeError, "Frequency object has no attribute '%s'" % attr
1246
1247    def getValue(self):
1248        return self.period.getValue()
1249
1250    def ini_str(self):
1251        return self.period.ini_str()
1252
1253class Voltage(float,ParamValue):
1254    cxx_type = 'double'
1255    def __new__(cls, value):
1256        # convert to voltage
1257        val = convert.toVoltage(value)
1258        return super(cls, Voltage).__new__(cls, val)
1259
1260    def __str__(self):
1261        return str(self.val)
1262
1263    def getValue(self):
1264        value = float(self)
1265        return value
1266
1267    def ini_str(self):
1268        return '%f' % self.getValue()
1269
1270class NetworkBandwidth(float,ParamValue):
1271    cxx_type = 'float'
1272    def __new__(cls, value):
1273        # convert to bits per second
1274        val = convert.toNetworkBandwidth(value)
1275        return super(cls, NetworkBandwidth).__new__(cls, val)
1276
1277    def __str__(self):
1278        return str(self.val)
1279
1280    def getValue(self):
1281        # convert to seconds per byte
1282        value = 8.0 / float(self)
1283        # convert to ticks per byte
1284        value = ticks.fromSeconds(value)
1285        return float(value)
1286
1287    def ini_str(self):
1288        return '%f' % self.getValue()
1289
1290class MemoryBandwidth(float,ParamValue):
1291    cxx_type = 'float'
1292    def __new__(cls, value):
1293        # convert to bytes per second
1294        val = convert.toMemoryBandwidth(value)
1295        return super(cls, MemoryBandwidth).__new__(cls, val)
1296
1297    def __str__(self):
1298        return str(self.val)
1299
1300    def getValue(self):
1301        # convert to seconds per byte
1302        value = float(self)
1303        if value:
1304            value = 1.0 / float(self)
1305        # convert to ticks per byte
1306        value = ticks.fromSeconds(value)
1307        return float(value)
1308
1309    def ini_str(self):
1310        return '%f' % self.getValue()
1311
1312#
1313# "Constants"... handy aliases for various values.
1314#
1315
1316# Special class for NULL pointers.  Note the special check in
1317# make_param_value() above that lets these be assigned where a
1318# SimObject is required.
1319# only one copy of a particular node
1320class NullSimObject(object):
1321    __metaclass__ = Singleton
1322
1323    def __call__(cls):
1324        return cls
1325
1326    def _instantiate(self, parent = None, path = ''):
1327        pass
1328
1329    def ini_str(self):
1330        return 'Null'
1331
1332    def unproxy(self, base):
1333        return self
1334
1335    def set_path(self, parent, name):
1336        pass
1337
1338    def __str__(self):
1339        return 'Null'
1340
1341    def getValue(self):
1342        return None
1343
1344# The only instance you'll ever need...
1345NULL = NullSimObject()
1346
1347def isNullPointer(value):
1348    return isinstance(value, NullSimObject)
1349
1350# Some memory range specifications use this as a default upper bound.
1351MaxAddr = Addr.max
1352MaxTick = Tick.max
1353AllMemory = AddrRange(0, MaxAddr)
1354
1355
1356#####################################################################
1357#
1358# Port objects
1359#
1360# Ports are used to interconnect objects in the memory system.
1361#
1362#####################################################################
1363
1364# Port reference: encapsulates a reference to a particular port on a
1365# particular SimObject.
1366class PortRef(object):
1367    def __init__(self, simobj, name, role):
1368        assert(isSimObject(simobj) or isSimObjectClass(simobj))
1369        self.simobj = simobj
1370        self.name = name
1371        self.role = role
1372        self.peer = None   # not associated with another port yet
1373        self.ccConnected = False # C++ port connection done?
1374        self.index = -1  # always -1 for non-vector ports
1375
1376    def __str__(self):
1377        return '%s.%s' % (self.simobj, self.name)
1378
1379    def __len__(self):
1380        # Return the number of connected ports, i.e. 0 is we have no
1381        # peer and 1 if we do.
1382        return int(self.peer != None)
1383
1384    # for config.ini, print peer's name (not ours)
1385    def ini_str(self):
1386        return str(self.peer)
1387
1388    # for config.json
1389    def get_config_as_dict(self):
1390        return {'role' : self.role, 'peer' : str(self.peer)}
1391
1392    def __getattr__(self, attr):
1393        if attr == 'peerObj':
1394            # shorthand for proxies
1395            return self.peer.simobj
1396        raise AttributeError, "'%s' object has no attribute '%s'" % \
1397              (self.__class__.__name__, attr)
1398
1399    # Full connection is symmetric (both ways).  Called via
1400    # SimObject.__setattr__ as a result of a port assignment, e.g.,
1401    # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
1402    # e.g., "obj1.portA[3] = obj2.portB".
1403    def connect(self, other):
1404        if isinstance(other, VectorPortRef):
1405            # reference to plain VectorPort is implicit append
1406            other = other._get_next()
1407        if self.peer and not proxy.isproxy(self.peer):
1408            fatal("Port %s is already connected to %s, cannot connect %s\n",
1409                  self, self.peer, other);
1410        self.peer = other
1411        if proxy.isproxy(other):
1412            other.set_param_desc(PortParamDesc())
1413        elif isinstance(other, PortRef):
1414            if other.peer is not self:
1415                other.connect(self)
1416        else:
1417            raise TypeError, \
1418                  "assigning non-port reference '%s' to port '%s'" \
1419                  % (other, self)
1420
1421    def clone(self, simobj, memo):
1422        if memo.has_key(self):
1423            return memo[self]
1424        newRef = copy.copy(self)
1425        memo[self] = newRef
1426        newRef.simobj = simobj
1427        assert(isSimObject(newRef.simobj))
1428        if self.peer and not proxy.isproxy(self.peer):
1429            peerObj = self.peer.simobj(_memo=memo)
1430            newRef.peer = self.peer.clone(peerObj, memo)
1431            assert(not isinstance(newRef.peer, VectorPortRef))
1432        return newRef
1433
1434    def unproxy(self, simobj):
1435        assert(simobj is self.simobj)
1436        if proxy.isproxy(self.peer):
1437            try:
1438                realPeer = self.peer.unproxy(self.simobj)
1439            except:
1440                print "Error in unproxying port '%s' of %s" % \
1441                      (self.name, self.simobj.path())
1442                raise
1443            self.connect(realPeer)
1444
1445    # Call C++ to create corresponding port connection between C++ objects
1446    def ccConnect(self):
1447        from m5.internal.pyobject import connectPorts
1448
1449        if self.role == 'SLAVE':
1450            # do nothing and let the master take care of it
1451            return
1452
1453        if self.ccConnected: # already done this
1454            return
1455        peer = self.peer
1456        if not self.peer: # nothing to connect to
1457            return
1458
1459        # check that we connect a master to a slave
1460        if self.role == peer.role:
1461            raise TypeError, \
1462                "cannot connect '%s' and '%s' due to identical role '%s'" \
1463                % (peer, self, self.role)
1464
1465        try:
1466            # self is always the master and peer the slave
1467            connectPorts(self.simobj.getCCObject(), self.name, self.index,
1468                         peer.simobj.getCCObject(), peer.name, peer.index)
1469        except:
1470            print "Error connecting port %s.%s to %s.%s" % \
1471                  (self.simobj.path(), self.name,
1472                   peer.simobj.path(), peer.name)
1473            raise
1474        self.ccConnected = True
1475        peer.ccConnected = True
1476
1477# A reference to an individual element of a VectorPort... much like a
1478# PortRef, but has an index.
1479class VectorPortElementRef(PortRef):
1480    def __init__(self, simobj, name, role, index):
1481        PortRef.__init__(self, simobj, name, role)
1482        self.index = index
1483
1484    def __str__(self):
1485        return '%s.%s[%d]' % (self.simobj, self.name, self.index)
1486
1487# A reference to a complete vector-valued port (not just a single element).
1488# Can be indexed to retrieve individual VectorPortElementRef instances.
1489class VectorPortRef(object):
1490    def __init__(self, simobj, name, role):
1491        assert(isSimObject(simobj) or isSimObjectClass(simobj))
1492        self.simobj = simobj
1493        self.name = name
1494        self.role = role
1495        self.elements = []
1496
1497    def __str__(self):
1498        return '%s.%s[:]' % (self.simobj, self.name)
1499
1500    def __len__(self):
1501        # Return the number of connected peers, corresponding the the
1502        # length of the elements.
1503        return len(self.elements)
1504
1505    # for config.ini, print peer's name (not ours)
1506    def ini_str(self):
1507        return ' '.join([el.ini_str() for el in self.elements])
1508
1509    # for config.json
1510    def get_config_as_dict(self):
1511        return {'role' : self.role,
1512                'peer' : [el.ini_str() for el in self.elements]}
1513
1514    def __getitem__(self, key):
1515        if not isinstance(key, int):
1516            raise TypeError, "VectorPort index must be integer"
1517        if key >= len(self.elements):
1518            # need to extend list
1519            ext = [VectorPortElementRef(self.simobj, self.name, self.role, i)
1520                   for i in range(len(self.elements), key+1)]
1521            self.elements.extend(ext)
1522        return self.elements[key]
1523
1524    def _get_next(self):
1525        return self[len(self.elements)]
1526
1527    def __setitem__(self, key, value):
1528        if not isinstance(key, int):
1529            raise TypeError, "VectorPort index must be integer"
1530        self[key].connect(value)
1531
1532    def connect(self, other):
1533        if isinstance(other, (list, tuple)):
1534            # Assign list of port refs to vector port.
1535            # For now, append them... not sure if that's the right semantics
1536            # or if it should replace the current vector.
1537            for ref in other:
1538                self._get_next().connect(ref)
1539        else:
1540            # scalar assignment to plain VectorPort is implicit append
1541            self._get_next().connect(other)
1542
1543    def clone(self, simobj, memo):
1544        if memo.has_key(self):
1545            return memo[self]
1546        newRef = copy.copy(self)
1547        memo[self] = newRef
1548        newRef.simobj = simobj
1549        assert(isSimObject(newRef.simobj))
1550        newRef.elements = [el.clone(simobj, memo) for el in self.elements]
1551        return newRef
1552
1553    def unproxy(self, simobj):
1554        [el.unproxy(simobj) for el in self.elements]
1555
1556    def ccConnect(self):
1557        [el.ccConnect() for el in self.elements]
1558
1559# Port description object.  Like a ParamDesc object, this represents a
1560# logical port in the SimObject class, not a particular port on a
1561# SimObject instance.  The latter are represented by PortRef objects.
1562class Port(object):
1563    # Generate a PortRef for this port on the given SimObject with the
1564    # given name
1565    def makeRef(self, simobj):
1566        return PortRef(simobj, self.name, self.role)
1567
1568    # Connect an instance of this port (on the given SimObject with
1569    # the given name) with the port described by the supplied PortRef
1570    def connect(self, simobj, ref):
1571        self.makeRef(simobj).connect(ref)
1572
1573    # No need for any pre-declarations at the moment as we merely rely
1574    # on an unsigned int.
1575    def cxx_predecls(self, code):
1576        pass
1577
1578    # Declare an unsigned int with the same name as the port, that
1579    # will eventually hold the number of connected ports (and thus the
1580    # number of elements for a VectorPort).
1581    def cxx_decl(self, code):
1582        code('unsigned int port_${{self.name}}_connection_count;')
1583
1584class MasterPort(Port):
1585    # MasterPort("description")
1586    def __init__(self, *args):
1587        if len(args) == 1:
1588            self.desc = args[0]
1589            self.role = 'MASTER'
1590        else:
1591            raise TypeError, 'wrong number of arguments'
1592
1593class SlavePort(Port):
1594    # SlavePort("description")
1595    def __init__(self, *args):
1596        if len(args) == 1:
1597            self.desc = args[0]
1598            self.role = 'SLAVE'
1599        else:
1600            raise TypeError, 'wrong number of arguments'
1601
1602# VectorPort description object.  Like Port, but represents a vector
1603# of connections (e.g., as on a Bus).
1604class VectorPort(Port):
1605    def __init__(self, *args):
1606        self.isVec = True
1607
1608    def makeRef(self, simobj):
1609        return VectorPortRef(simobj, self.name, self.role)
1610
1611class VectorMasterPort(VectorPort):
1612    # VectorMasterPort("description")
1613    def __init__(self, *args):
1614        if len(args) == 1:
1615            self.desc = args[0]
1616            self.role = 'MASTER'
1617            VectorPort.__init__(self, *args)
1618        else:
1619            raise TypeError, 'wrong number of arguments'
1620
1621class VectorSlavePort(VectorPort):
1622    # VectorSlavePort("description")
1623    def __init__(self, *args):
1624        if len(args) == 1:
1625            self.desc = args[0]
1626            self.role = 'SLAVE'
1627            VectorPort.__init__(self, *args)
1628        else:
1629            raise TypeError, 'wrong number of arguments'
1630
1631# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
1632# proxy objects (via set_param_desc()) so that proxy error messages
1633# make sense.
1634class PortParamDesc(object):
1635    __metaclass__ = Singleton
1636
1637    ptype_str = 'Port'
1638    ptype = Port
1639
1640baseEnums = allEnums.copy()
1641baseParams = allParams.copy()
1642
1643def clear():
1644    global allEnums, allParams
1645
1646    allEnums = baseEnums.copy()
1647    allParams = baseParams.copy()
1648
1649__all__ = ['Param', 'VectorParam',
1650           'Enum', 'Bool', 'String', 'Float',
1651           'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
1652           'Int32', 'UInt32', 'Int64', 'UInt64',
1653           'Counter', 'Addr', 'Tick', 'Percent',
1654           'TcpPort', 'UdpPort', 'EthernetAddr',
1655           'IpAddress', 'IpNetmask', 'IpWithPort',
1656           'MemorySize', 'MemorySize32',
1657           'Latency', 'Frequency', 'Clock', 'Voltage',
1658           'NetworkBandwidth', 'MemoryBandwidth',
1659           'AddrRange',
1660           'MaxAddr', 'MaxTick', 'AllMemory',
1661           'Time',
1662           'NextEthernetAddr', 'NULL',
1663           'MasterPort', 'SlavePort',
1664           'VectorMasterPort', 'VectorSlavePort']
1665
1666import SimObject
1667