params.py revision 7673:b28bd1fa9a35
12623SN/A# Copyright (c) 2004-2006 The Regents of The University of Michigan
22623SN/A# Copyright (c) 2010 Advanced Micro Devices, Inc.
32623SN/A# All rights reserved.
42623SN/A#
52623SN/A# Redistribution and use in source and binary forms, with or without
62623SN/A# modification, are permitted provided that the following conditions are
72623SN/A# met: redistributions of source code must retain the above copyright
82623SN/A# notice, this list of conditions and the following disclaimer;
92623SN/A# redistributions in binary form must reproduce the above copyright
102623SN/A# notice, this list of conditions and the following disclaimer in the
112623SN/A# documentation and/or other materials provided with the distribution;
122623SN/A# neither the name of the copyright holders nor the names of its
132623SN/A# contributors may be used to endorse or promote products derived from
142623SN/A# this software without specific prior written permission.
152623SN/A#
162623SN/A# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172623SN/A# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182623SN/A# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192623SN/A# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202623SN/A# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212623SN/A# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222623SN/A# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232623SN/A# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242623SN/A# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252623SN/A# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262623SN/A# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272665Ssaidi@eecs.umich.edu#
282665Ssaidi@eecs.umich.edu# Authors: Steve Reinhardt
292623SN/A#          Nathan Binkert
302623SN/A
312623SN/A#####################################################################
322623SN/A#
332623SN/A# Parameter description classes
342623SN/A#
352623SN/A# The _params dictionary in each class maps parameter names to either
362623SN/A# a Param or a VectorParam object.  These objects contain the
372623SN/A# parameter description string, the parameter type, and the default
382623SN/A# value (if any).  The convert() method on these objects is used to
392623SN/A# force whatever value is assigned to the parameter to the appropriate
402623SN/A# type.
412623SN/A#
422623SN/A# Note that the default values are loaded into the class's attribute
432623SN/A# space when the parameter dictionary is initialized (in
442623SN/A# MetaSimObject._new_param()); after that point they aren't used.
452623SN/A#
462623SN/A#####################################################################
472623SN/A
482623SN/Aimport copy
492623SN/Aimport datetime
502623SN/Aimport re
512623SN/Aimport sys
522623SN/Aimport time
532623SN/Aimport math
542623SN/A
552623SN/Aimport proxy
562623SN/Aimport ticks
572623SN/Afrom util import *
582856Srdreslin@umich.edu
592856Srdreslin@umich.edudef isSimObject(*args, **kwargs):
602856Srdreslin@umich.edu    return SimObject.isSimObject(*args, **kwargs)
612856Srdreslin@umich.edu
622856Srdreslin@umich.edudef isSimObjectSequence(*args, **kwargs):
632856Srdreslin@umich.edu    return SimObject.isSimObjectSequence(*args, **kwargs)
642856Srdreslin@umich.edu
652856Srdreslin@umich.edudef isSimObjectClass(*args, **kwargs):
662856Srdreslin@umich.edu    return SimObject.isSimObjectClass(*args, **kwargs)
672856Srdreslin@umich.edu
682623SN/AallParams = {}
692623SN/A
702623SN/Aclass MetaParamValue(type):
712623SN/A    def __new__(mcls, name, bases, dct):
722623SN/A        cls = super(MetaParamValue, mcls).__new__(mcls, name, bases, dct)
732856Srdreslin@umich.edu        assert name not in allParams
742856Srdreslin@umich.edu        allParams[name] = cls
752856Srdreslin@umich.edu        return cls
762623SN/A
772856Srdreslin@umich.edu
782856Srdreslin@umich.edu# Dummy base class to identify types that are legitimate for SimObject
792856Srdreslin@umich.edu# parameters.
802623SN/Aclass ParamValue(object):
812623SN/A    __metaclass__ = MetaParamValue
822623SN/A
832680Sktlim@umich.edu    @classmethod
842680Sktlim@umich.edu    def cxx_predecls(cls, code):
852623SN/A        pass
862623SN/A
872680Sktlim@umich.edu    @classmethod
882623SN/A    def swig_predecls(cls, code):
892623SN/A        pass
902623SN/A
912623SN/A    # default for printing to .ini file is regular string conversion.
922623SN/A    # will be overridden in some cases
932630SN/A    def ini_str(self):
942623SN/A        return str(self)
952623SN/A
962623SN/A    # allows us to blithely call unproxy() on things without checking
972623SN/A    # if they're really proxies or not
982623SN/A    def unproxy(self, base):
992623SN/A        return self
1002630SN/A
1012623SN/A# Regular parameter description.
1022623SN/Aclass ParamDesc(object):
1032623SN/A    file_ext = 'ptype'
1042623SN/A
1052623SN/A    def __init__(self, ptype_str, ptype, *args, **kwargs):
1062623SN/A        self.ptype_str = ptype_str
1072630SN/A        # remember ptype only if it is provided
1082623SN/A        if ptype != None:
1092623SN/A            self.ptype = ptype
1102623SN/A
1112623SN/A        if args:
1122623SN/A            if len(args) == 1:
1132623SN/A                self.desc = args[0]
1142623SN/A            elif len(args) == 2:
1152626SN/A                self.default = args[0]
1162626SN/A                self.desc = args[1]
1172626SN/A            else:
1182623SN/A                raise TypeError, 'too many arguments'
1192623SN/A
1202623SN/A        if kwargs.has_key('desc'):
1212657Ssaidi@eecs.umich.edu            assert(not hasattr(self, 'desc'))
1222623SN/A            self.desc = kwargs['desc']
1232623SN/A            del kwargs['desc']
1242623SN/A
1252623SN/A        if kwargs.has_key('default'):
1262623SN/A            assert(not hasattr(self, 'default'))
1272623SN/A            self.default = kwargs['default']
1282623SN/A            del kwargs['default']
1292623SN/A
1302623SN/A        if kwargs:
1312640Sstever@eecs.umich.edu            raise TypeError, 'extra unknown kwargs %s' % kwargs
1322623SN/A
1332623SN/A        if not hasattr(self, 'desc'):
1342623SN/A            raise TypeError, 'desc attribute missing'
1352663Sstever@eecs.umich.edu
1362663Sstever@eecs.umich.edu    def __getattr__(self, attr):
1372827Srdreslin@umich.edu        if attr == 'ptype':
1382641Sstever@eecs.umich.edu            ptype = SimObject.allClasses[self.ptype_str]
1392623SN/A            assert isSimObjectClass(ptype)
1402623SN/A            self.ptype = ptype
1412663Sstever@eecs.umich.edu            return ptype
1422827Srdreslin@umich.edu
1432641Sstever@eecs.umich.edu        raise AttributeError, "'%s' object has no attribute '%s'" % \
1442641Sstever@eecs.umich.edu              (type(self).__name__, attr)
1452623SN/A
1462623SN/A    def convert(self, value):
1472663Sstever@eecs.umich.edu        if isinstance(value, proxy.BaseProxy):
1482827Srdreslin@umich.edu            value.set_param_desc(self)
1492641Sstever@eecs.umich.edu            return value
1502641Sstever@eecs.umich.edu        if not hasattr(self, 'ptype') and isNullPointer(value):
1512623SN/A            # deferred evaluation of SimObject; continue to defer if
1522623SN/A            # we're just assigning a null pointer
1532623SN/A            return value
1542623SN/A        if isinstance(value, self.ptype):
1552623SN/A            return value
1562623SN/A        if isNullPointer(value) and isSimObjectClass(self.ptype):
1572623SN/A            return value
1582623SN/A        return self.ptype(value)
1592623SN/A
1602623SN/A    def cxx_predecls(self, code):
1612915Sktlim@umich.edu        self.ptype.cxx_predecls(code)
1622915Sktlim@umich.edu
1632623SN/A    def swig_predecls(self, code):
1642623SN/A        self.ptype.swig_predecls(code)
1652915Sktlim@umich.edu
1662623SN/A    def cxx_decl(self, code):
1672623SN/A        code('${{self.ptype.cxx_type}} ${{self.name}};')
1682623SN/A
1692623SN/A# Vector-valued parameter description.  Just like ParamDesc, except
1702623SN/A# that the value is a vector (list) of the specified type instead of a
1712915Sktlim@umich.edu# single value.
1722915Sktlim@umich.edu
1732915Sktlim@umich.educlass VectorParamValue(list):
1742623SN/A    __metaclass__ = MetaParamValue
1752915Sktlim@umich.edu    def __setattr__(self, attr, value):
1762915Sktlim@umich.edu        raise AttributeError, \
1772915Sktlim@umich.edu              "Not allowed to set %s on '%s'" % (attr, type(self).__name__)
1782915Sktlim@umich.edu
1792915Sktlim@umich.edu    def ini_str(self):
1802915Sktlim@umich.edu        return ' '.join([v.ini_str() for v in self])
1812915Sktlim@umich.edu
1822915Sktlim@umich.edu    def getValue(self):
1832915Sktlim@umich.edu        return [ v.getValue() for v in self ]
1842623SN/A
1852623SN/A    def unproxy(self, base):
1862623SN/A        return [v.unproxy(base) for v in self]
1872798Sktlim@umich.edu
1882623SN/Aclass SimObjectVector(VectorParamValue):
1892798Sktlim@umich.edu    # support clone operation
1902798Sktlim@umich.edu    def __call__(self, **kwargs):
1912623SN/A        return SimObjectVector([v(**kwargs) for v in self])
1922798Sktlim@umich.edu
1932623SN/A    def clear_parent(self, old_parent):
1942623SN/A        for v in self:
1952623SN/A            v.clear_parent(old_parent)
1962623SN/A
1972623SN/A    def set_parent(self, parent, name):
1982623SN/A        if len(self) == 1:
1992623SN/A            self[0].set_parent(parent, name)
2002623SN/A        else:
2012623SN/A            width = int(math.ceil(math.log(len(self))/math.log(10)))
2022623SN/A            for i,v in enumerate(self):
2032680Sktlim@umich.edu                v.set_parent(parent, "%s%0*d" % (name, width, i))
2042623SN/A
2052680Sktlim@umich.edu    def get_parent(self):
2062680Sktlim@umich.edu        parent_set = set(v._parent for v in self)
2072680Sktlim@umich.edu        if len(parent_set) != 1:
2082623SN/A            raise RuntimeError, \
2092623SN/A                  "SimObjectVector elements have inconsistent parent value."
2102623SN/A        return parent_set.pop()
2112623SN/A
2122623SN/A    # return 'cpu0 cpu1' etc. for print_ini()
2132623SN/A    def get_name(self):
2142623SN/A        return ' '.join([v._name for v in self])
2152623SN/A
2162623SN/A    # By iterating through the constituent members of the vector here
2172623SN/A    # we can nicely handle iterating over all a SimObject's children
2182623SN/A    # without having to provide lots of special functions on
2192623SN/A    # SimObjectVector directly.
2202683Sktlim@umich.edu    def descendants(self):
2212623SN/A        for v in self:
2222623SN/A            for obj in v.descendants():
2232623SN/A                yield obj
2242623SN/A
2252623SN/Aclass VectorParamDesc(ParamDesc):
2262623SN/A    file_ext = 'vptype'
2272623SN/A
2282623SN/A    # Convert assigned value to appropriate type.  If the RHS is not a
2292623SN/A    # list or tuple, it generates a single-element list.
2302623SN/A    def convert(self, value):
2312623SN/A        if isinstance(value, (list, tuple)):
2322623SN/A            # list: coerce each element into new list
2332623SN/A            tmp_list = [ ParamDesc.convert(self, v) for v in value ]
2342623SN/A        else:
2352683Sktlim@umich.edu            # singleton: coerce to a single-element list
2362623SN/A            tmp_list = [ ParamDesc.convert(self, value) ]
2372623SN/A
2382626SN/A        if isSimObjectSequence(tmp_list):
2392626SN/A            return SimObjectVector(tmp_list)
2402626SN/A        else:
2412626SN/A            return VectorParamValue(tmp_list)
2422626SN/A
2432623SN/A    def swig_predecls(self, code):
2442623SN/A        code('%include "${{self.ptype_str}}_vptype.i"')
2452623SN/A
2462623SN/A    def swig_decl(self, code):
2472623SN/A        cxx_type = re.sub('std::', '', self.ptype.cxx_type)
2482623SN/A        code('%include "std_vector.i"')
2492623SN/A        self.ptype.swig_predecls(code)
2502623SN/A        code('''\
2512623SN/Anamespace std {
2522623SN/A%template(vector_${{self.ptype_str}}) vector< $cxx_type >;
2532683Sktlim@umich.edu}
2542623SN/A''')
2552623SN/A
2562623SN/A    def cxx_predecls(self, code):
2572623SN/A        code('#include <vector>')
2582623SN/A        self.ptype.cxx_predecls(code)
2592623SN/A
2602683Sktlim@umich.edu    def cxx_decl(self, code):
2612623SN/A        code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};')
2622623SN/A
2632623SN/Aclass ParamFactory(object):
2642641Sstever@eecs.umich.edu    def __init__(self, param_desc_class, ptype_str = None):
2652623SN/A        self.param_desc_class = param_desc_class
2662662Sstever@eecs.umich.edu        self.ptype_str = ptype_str
2672623SN/A
2682623SN/A    def __getattr__(self, attr):
2692641Sstever@eecs.umich.edu        if self.ptype_str:
2702623SN/A            attr = self.ptype_str + '.' + attr
2712623SN/A        return ParamFactory(self.param_desc_class, attr)
2722623SN/A
2732623SN/A    # E.g., Param.Int(5, "number of widgets")
2742623SN/A    def __call__(self, *args, **kwargs):
2752623SN/A        ptype = None
2762623SN/A        try:
2772623SN/A            ptype = allParams[self.ptype_str]
2782623SN/A        except KeyError:
2792623SN/A            # if name isn't defined yet, assume it's a SimObject, and
2802623SN/A            # try to resolve it later
2812623SN/A            pass
2822623SN/A        return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs)
2832623SN/A
2842623SN/AParam = ParamFactory(ParamDesc)
2852623SN/AVectorParam = ParamFactory(VectorParamDesc)
2862623SN/A
2872623SN/A#####################################################################
2882623SN/A#
2892623SN/A# Parameter Types
2902623SN/A#
2912623SN/A# Though native Python types could be used to specify parameter types
2922623SN/A# (the 'ptype' field of the Param and VectorParam classes), it's more
2932623SN/A# flexible to define our own set of types.  This gives us more control
2942623SN/A# over how Python expressions are converted to values (via the
2952623SN/A# __init__() constructor) and how these values are printed out (via
2962623SN/A# the __str__() conversion method).
2972623SN/A#
2982623SN/A#####################################################################
2992623SN/A
3002623SN/A# String-valued parameter.  Just mixin the ParamValue class with the
3012623SN/A# built-in str class.
3022623SN/Aclass String(ParamValue,str):
3032623SN/A    cxx_type = 'std::string'
3042623SN/A
3052623SN/A    @classmethod
3062623SN/A    def cxx_predecls(self, code):
3072623SN/A        code('#include <string>')
3082623SN/A
3092623SN/A    @classmethod
3102623SN/A    def swig_predecls(cls, code):
3112623SN/A        code('%include "std_string.i"')
3122623SN/A
3132623SN/A    def getValue(self):
3142623SN/A        return self
3152623SN/A
3162623SN/A# superclass for "numeric" parameter values, to emulate math
3172623SN/A# operations in a type-safe way.  e.g., a Latency times an int returns
3182623SN/A# a new Latency object.
3192623SN/Aclass NumericParamValue(ParamValue):
3202623SN/A    def __str__(self):
3212623SN/A        return str(self.value)
3222623SN/A
3232623SN/A    def __float__(self):
3242623SN/A        return float(self.value)
3252623SN/A
3262623SN/A    def __long__(self):
3272623SN/A        return long(self.value)
3282683Sktlim@umich.edu
3292623SN/A    def __int__(self):
3302623SN/A        return int(self.value)
3312623SN/A
3322623SN/A    # hook for bounds checking
3332623SN/A    def _check(self):
3342623SN/A        return
3352683Sktlim@umich.edu
3362623SN/A    def __mul__(self, other):
3372623SN/A        newobj = self.__class__(self)
3382623SN/A        newobj.value *= other
3392623SN/A        newobj._check()
3402662Sstever@eecs.umich.edu        return newobj
3412623SN/A
3422623SN/A    __rmul__ = __mul__
3432662Sstever@eecs.umich.edu
3442623SN/A    def __div__(self, other):
3452623SN/A        newobj = self.__class__(self)
3462641Sstever@eecs.umich.edu        newobj.value /= other
3472631SN/A        newobj._check()
3482631SN/A        return newobj
3492631SN/A
3502631SN/A    def __sub__(self, other):
3512623SN/A        newobj = self.__class__(self)
3522623SN/A        newobj.value -= other
3532623SN/A        newobj._check()
3542623SN/A        return newobj
3552623SN/A
3562623SN/A# Metaclass for bounds-checked integer parameters.  See CheckedInt.
3572623SN/Aclass CheckedIntType(MetaParamValue):
3582623SN/A    def __init__(cls, name, bases, dict):
3592623SN/A        super(CheckedIntType, cls).__init__(name, bases, dict)
3602623SN/A
3612623SN/A        # CheckedInt is an abstract base class, so we actually don't
3622623SN/A        # want to do any processing on it... the rest of this code is
3632623SN/A        # just for classes that derive from CheckedInt.
3642623SN/A        if name == 'CheckedInt':
3652623SN/A            return
3662623SN/A
3672623SN/A        if not (hasattr(cls, 'min') and hasattr(cls, 'max')):
3682623SN/A            if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')):
3692623SN/A                panic("CheckedInt subclass %s must define either\n" \
3702623SN/A                      "    'min' and 'max' or 'size' and 'unsigned'\n",
3712623SN/A                      name);
3722623SN/A            if cls.unsigned:
3732623SN/A                cls.min = 0
3742623SN/A                cls.max = 2 ** cls.size - 1
3752623SN/A            else:
3762623SN/A                cls.min = -(2 ** (cls.size - 1))
3772623SN/A                cls.max = (2 ** (cls.size - 1)) - 1
3782623SN/A
3792623SN/A# Abstract superclass for bounds-checked integer parameters.  This
3802623SN/A# class is subclassed to generate parameter classes with specific
3812623SN/A# bounds.  Initialization of the min and max bounds is done in the
3822623SN/A# metaclass CheckedIntType.__init__.
3832623SN/Aclass CheckedInt(NumericParamValue):
3842623SN/A    __metaclass__ = CheckedIntType
3852623SN/A
3862623SN/A    def _check(self):
3872623SN/A        if not self.min <= self.value <= self.max:
3882623SN/A            raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
3892623SN/A                  (self.min, self.value, self.max)
3902623SN/A
3912623SN/A    def __init__(self, value):
3922623SN/A        if isinstance(value, str):
3932623SN/A            self.value = convert.toInteger(value)
3942623SN/A        elif isinstance(value, (int, long, float, NumericParamValue)):
3952623SN/A            self.value = long(value)
3962623SN/A        else:
3972623SN/A            raise TypeError, "Can't convert object of type %s to CheckedInt" \
3982623SN/A                  % type(value).__name__
3992623SN/A        self._check()
4002623SN/A
4012623SN/A    @classmethod
4022623SN/A    def cxx_predecls(cls, code):
4032623SN/A        # most derived types require this, so we just do it here once
4042623SN/A        code('#include "base/types.hh"')
4052623SN/A
4062623SN/A    @classmethod
4072623SN/A    def swig_predecls(cls, code):
4082623SN/A        # most derived types require this, so we just do it here once
4092623SN/A        code('%import "stdint.i"')
4102623SN/A        code('%import "base/types.hh"')
4112623SN/A
4122623SN/A    def getValue(self):
4132623SN/A        return long(self.value)
4142623SN/A
4152623SN/Aclass Int(CheckedInt):      cxx_type = 'int';      size = 32; unsigned = False
4162623SN/Aclass Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True
4172626SN/A
4182626SN/Aclass Int8(CheckedInt):     cxx_type =   'int8_t'; size =  8; unsigned = False
4192662Sstever@eecs.umich.educlass UInt8(CheckedInt):    cxx_type =  'uint8_t'; size =  8; unsigned = True
4202623SN/Aclass Int16(CheckedInt):    cxx_type =  'int16_t'; size = 16; unsigned = False
4212623SN/Aclass UInt16(CheckedInt):   cxx_type = 'uint16_t'; size = 16; unsigned = True
4222662Sstever@eecs.umich.educlass Int32(CheckedInt):    cxx_type =  'int32_t'; size = 32; unsigned = False
4232662Sstever@eecs.umich.educlass UInt32(CheckedInt):   cxx_type = 'uint32_t'; size = 32; unsigned = True
4242662Sstever@eecs.umich.educlass Int64(CheckedInt):    cxx_type =  'int64_t'; size = 64; unsigned = False
4252623SN/Aclass UInt64(CheckedInt):   cxx_type = 'uint64_t'; size = 64; unsigned = True
4262623SN/A
4272623SN/Aclass Counter(CheckedInt):  cxx_type = 'Counter';  size = 64; unsigned = True
4282623SN/Aclass Tick(CheckedInt):     cxx_type = 'Tick';     size = 64; unsigned = True
4292623SN/Aclass TcpPort(CheckedInt):  cxx_type = 'uint16_t'; size = 16; unsigned = True
4302623SN/Aclass UdpPort(CheckedInt):  cxx_type = 'uint16_t'; size = 16; unsigned = True
4312623SN/A
4322623SN/Aclass Percent(CheckedInt):  cxx_type = 'int'; min = 0; max = 100
4332623SN/A
4342662Sstever@eecs.umich.educlass Float(ParamValue, float):
4352623SN/A    cxx_type = 'double'
4362662Sstever@eecs.umich.edu
4372803Ssaidi@eecs.umich.edu    def __init__(self, value):
4382803Ssaidi@eecs.umich.edu        if isinstance(value, (int, long, float, NumericParamValue, Float)):
4392803Ssaidi@eecs.umich.edu            self.value = float(value)
4402803Ssaidi@eecs.umich.edu        else:
4412803Ssaidi@eecs.umich.edu            raise TypeError, "Can't convert object of type %s to Float" \
4422623SN/A                  % type(value).__name__
4432623SN/A
4442623SN/A    def getValue(self):
4452623SN/A        return float(self.value)
4462623SN/A
4472623SN/Aclass MemorySize(CheckedInt):
4482623SN/A    cxx_type = 'uint64_t'
4492626SN/A    size = 64
4502626SN/A    unsigned = True
4512623SN/A    def __init__(self, value):
4522623SN/A        if isinstance(value, MemorySize):
4532623SN/A            self.value = value.value
4542623SN/A        else:
4552623SN/A            self.value = convert.toMemorySize(value)
4562623SN/A        self._check()
4572623SN/A
4582623SN/Aclass MemorySize32(CheckedInt):
4592623SN/A    cxx_type = 'uint32_t'
4602623SN/A    size = 32
4612623SN/A    unsigned = True
4622623SN/A    def __init__(self, value):
4632623SN/A        if isinstance(value, MemorySize):
4642623SN/A            self.value = value.value
4652623SN/A        else:
4662623SN/A            self.value = convert.toMemorySize(value)
4672623SN/A        self._check()
4682623SN/A
4692623SN/Aclass Addr(CheckedInt):
4702623SN/A    cxx_type = 'Addr'
4712623SN/A    size = 64
4722623SN/A    unsigned = True
4732623SN/A    def __init__(self, value):
4742623SN/A        if isinstance(value, Addr):
4752623SN/A            self.value = value.value
4762623SN/A        else:
4772623SN/A            try:
4782623SN/A                self.value = convert.toMemorySize(value)
4792623SN/A            except TypeError:
4802623SN/A                self.value = long(value)
4812623SN/A        self._check()
4822623SN/A    def __add__(self, other):
4832623SN/A        if isinstance(other, Addr):
4842623SN/A            return self.value + other.value
4852623SN/A        else:
4862623SN/A            return self.value + other
4872623SN/A
4882623SN/A
4892623SN/Aclass MetaRange(MetaParamValue):
4902623SN/A    def __init__(cls, name, bases, dict):
4912623SN/A        super(MetaRange, cls).__init__(name, bases, dict)
4922623SN/A        if name == 'Range':
4932623SN/A            return
4942623SN/A        cls.cxx_type = 'Range< %s >' % cls.type.cxx_type
4952623SN/A
4962623SN/Aclass Range(ParamValue):
4972623SN/A    __metaclass__ = MetaRange
4982623SN/A    type = Int # default; can be overridden in subclasses
4992623SN/A    def __init__(self, *args, **kwargs):
5002623SN/A        def handle_kwargs(self, kwargs):
5012623SN/A            if 'end' in kwargs:
5022623SN/A                self.second = self.type(kwargs.pop('end'))
5032623SN/A            elif 'size' in kwargs:
5042623SN/A                self.second = self.first + self.type(kwargs.pop('size')) - 1
5052623SN/A            else:
5062623SN/A                raise TypeError, "Either end or size must be specified"
5072623SN/A
5082623SN/A        if len(args) == 0:
5092623SN/A            self.first = self.type(kwargs.pop('start'))
5102623SN/A            handle_kwargs(self, kwargs)
5112623SN/A
5122623SN/A        elif len(args) == 1:
5132623SN/A            if kwargs:
5142623SN/A                self.first = self.type(args[0])
5152623SN/A                handle_kwargs(self, kwargs)
5162623SN/A            elif isinstance(args[0], Range):
5172623SN/A                self.first = self.type(args[0].first)
5182623SN/A                self.second = self.type(args[0].second)
5192623SN/A            elif isinstance(args[0], (list, tuple)):
5202623SN/A                self.first = self.type(args[0][0])
5212623SN/A                self.second = self.type(args[0][1])
5222623SN/A            else:
5232623SN/A                self.first = self.type(0)
5242623SN/A                self.second = self.type(args[0]) - 1
5252623SN/A
5262623SN/A        elif len(args) == 2:
5272623SN/A            self.first = self.type(args[0])
5282623SN/A            self.second = self.type(args[1])
5292623SN/A        else:
5302623SN/A            raise TypeError, "Too many arguments specified"
5312623SN/A
5322623SN/A        if kwargs:
5332623SN/A            raise TypeError, "too many keywords: %s" % kwargs.keys()
5342623SN/A
5352623SN/A    def __str__(self):
5362623SN/A        return '%s:%s' % (self.first, self.second)
5372623SN/A
5382623SN/A    @classmethod
5392623SN/A    def cxx_predecls(cls, code):
5402623SN/A        code('#include "base/range.hh"')
5412623SN/A        cls.type.cxx_predecls(code)
5422623SN/A
5432623SN/Aclass AddrRange(Range):
5442623SN/A    type = Addr
5452623SN/A
5462623SN/A    @classmethod
5472623SN/A    def swig_predecls(cls, code):
5482623SN/A        code('%include "python/swig/range.i"')
5492623SN/A
5502623SN/A    def getValue(self):
551        from m5.objects.params import AddrRange
552
553        value = AddrRange()
554        value.start = long(self.first)
555        value.end = long(self.second)
556        return value
557
558class TickRange(Range):
559    type = Tick
560
561    @classmethod
562    def swig_predecls(cls, code):
563        code('%include "python/swig/range.i"')
564
565    def getValue(self):
566        from m5.objects.params import TickRange
567
568        value = TickRange()
569        value.start = long(self.first)
570        value.end = long(self.second)
571        return value
572
573# Boolean parameter type.  Python doesn't let you subclass bool, since
574# it doesn't want to let you create multiple instances of True and
575# False.  Thus this is a little more complicated than String.
576class Bool(ParamValue):
577    cxx_type = 'bool'
578    def __init__(self, value):
579        try:
580            self.value = convert.toBool(value)
581        except TypeError:
582            self.value = bool(value)
583
584    def getValue(self):
585        return bool(self.value)
586
587    def __str__(self):
588        return str(self.value)
589
590    def ini_str(self):
591        if self.value:
592            return 'true'
593        return 'false'
594
595def IncEthernetAddr(addr, val = 1):
596    bytes = map(lambda x: int(x, 16), addr.split(':'))
597    bytes[5] += val
598    for i in (5, 4, 3, 2, 1):
599        val,rem = divmod(bytes[i], 256)
600        bytes[i] = rem
601        if val == 0:
602            break
603        bytes[i - 1] += val
604    assert(bytes[0] <= 255)
605    return ':'.join(map(lambda x: '%02x' % x, bytes))
606
607_NextEthernetAddr = "00:90:00:00:00:01"
608def NextEthernetAddr():
609    global _NextEthernetAddr
610
611    value = _NextEthernetAddr
612    _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1)
613    return value
614
615class EthernetAddr(ParamValue):
616    cxx_type = 'Net::EthAddr'
617
618    @classmethod
619    def cxx_predecls(cls, code):
620        code('#include "base/inet.hh"')
621
622    @classmethod
623    def swig_predecls(cls, code):
624        code('%include "python/swig/inet.i"')
625
626    def __init__(self, value):
627        if value == NextEthernetAddr:
628            self.value = value
629            return
630
631        if not isinstance(value, str):
632            raise TypeError, "expected an ethernet address and didn't get one"
633
634        bytes = value.split(':')
635        if len(bytes) != 6:
636            raise TypeError, 'invalid ethernet address %s' % value
637
638        for byte in bytes:
639            if not 0 <= int(byte) <= 256:
640                raise TypeError, 'invalid ethernet address %s' % value
641
642        self.value = value
643
644    def unproxy(self, base):
645        if self.value == NextEthernetAddr:
646            return EthernetAddr(self.value())
647        return self
648
649    def getValue(self):
650        from m5.objects.params import EthAddr
651        return EthAddr(self.value)
652
653    def ini_str(self):
654        return self.value
655
656time_formats = [ "%a %b %d %H:%M:%S %Z %Y",
657                 "%a %b %d %H:%M:%S %Z %Y",
658                 "%Y/%m/%d %H:%M:%S",
659                 "%Y/%m/%d %H:%M",
660                 "%Y/%m/%d",
661                 "%m/%d/%Y %H:%M:%S",
662                 "%m/%d/%Y %H:%M",
663                 "%m/%d/%Y",
664                 "%m/%d/%y %H:%M:%S",
665                 "%m/%d/%y %H:%M",
666                 "%m/%d/%y"]
667
668
669def parse_time(value):
670    from time import gmtime, strptime, struct_time, time
671    from datetime import datetime, date
672
673    if isinstance(value, struct_time):
674        return value
675
676    if isinstance(value, (int, long)):
677        return gmtime(value)
678
679    if isinstance(value, (datetime, date)):
680        return value.timetuple()
681
682    if isinstance(value, str):
683        if value in ('Now', 'Today'):
684            return time.gmtime(time.time())
685
686        for format in time_formats:
687            try:
688                return strptime(value, format)
689            except ValueError:
690                pass
691
692    raise ValueError, "Could not parse '%s' as a time" % value
693
694class Time(ParamValue):
695    cxx_type = 'tm'
696
697    @classmethod
698    def cxx_predecls(cls, code):
699        code('#include <time.h>')
700
701    @classmethod
702    def swig_predecls(cls, code):
703        code('%include "python/swig/time.i"')
704
705    def __init__(self, value):
706        self.value = parse_time(value)
707
708    def getValue(self):
709        from m5.objects.params import tm
710
711        c_time = tm()
712        py_time = self.value
713
714        # UNIX is years since 1900
715        c_time.tm_year = py_time.tm_year - 1900;
716
717        # Python starts at 1, UNIX starts at 0
718        c_time.tm_mon =  py_time.tm_mon - 1;
719        c_time.tm_mday = py_time.tm_mday;
720        c_time.tm_hour = py_time.tm_hour;
721        c_time.tm_min = py_time.tm_min;
722        c_time.tm_sec = py_time.tm_sec;
723
724        # Python has 0 as Monday, UNIX is 0 as sunday
725        c_time.tm_wday = py_time.tm_wday + 1
726        if c_time.tm_wday > 6:
727            c_time.tm_wday -= 7;
728
729        # Python starts at 1, Unix starts at 0
730        c_time.tm_yday = py_time.tm_yday - 1;
731
732        return c_time
733
734    def __str__(self):
735        return time.asctime(self.value)
736
737    def ini_str(self):
738        return str(self)
739
740# Enumerated types are a little more complex.  The user specifies the
741# type as Enum(foo) where foo is either a list or dictionary of
742# alternatives (typically strings, but not necessarily so).  (In the
743# long run, the integer value of the parameter will be the list index
744# or the corresponding dictionary value.  For now, since we only check
745# that the alternative is valid and then spit it into a .ini file,
746# there's not much point in using the dictionary.)
747
748# What Enum() must do is generate a new type encapsulating the
749# provided list/dictionary so that specific values of the parameter
750# can be instances of that type.  We define two hidden internal
751# classes (_ListEnum and _DictEnum) to serve as base classes, then
752# derive the new type from the appropriate base class on the fly.
753
754allEnums = {}
755# Metaclass for Enum types
756class MetaEnum(MetaParamValue):
757    def __new__(mcls, name, bases, dict):
758        assert name not in allEnums
759
760        cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict)
761        allEnums[name] = cls
762        return cls
763
764    def __init__(cls, name, bases, init_dict):
765        if init_dict.has_key('map'):
766            if not isinstance(cls.map, dict):
767                raise TypeError, "Enum-derived class attribute 'map' " \
768                      "must be of type dict"
769            # build list of value strings from map
770            cls.vals = cls.map.keys()
771            cls.vals.sort()
772        elif init_dict.has_key('vals'):
773            if not isinstance(cls.vals, list):
774                raise TypeError, "Enum-derived class attribute 'vals' " \
775                      "must be of type list"
776            # build string->value map from vals sequence
777            cls.map = {}
778            for idx,val in enumerate(cls.vals):
779                cls.map[val] = idx
780        else:
781            raise TypeError, "Enum-derived class must define "\
782                  "attribute 'map' or 'vals'"
783
784        cls.cxx_type = 'Enums::%s' % name
785
786        super(MetaEnum, cls).__init__(name, bases, init_dict)
787
788    # Generate C++ class declaration for this enum type.
789    # Note that we wrap the enum in a class/struct to act as a namespace,
790    # so that the enum strings can be brief w/o worrying about collisions.
791    def cxx_decl(cls, code):
792        name = cls.__name__
793        code('''\
794#ifndef __ENUM__${name}__
795#define __ENUM__${name}__
796
797namespace Enums {
798    enum $name {
799''')
800        code.indent(2)
801        for val in cls.vals:
802            code('$val = ${{cls.map[val]}},')
803        code('Num_$name = ${{len(cls.vals)}},')
804        code.dedent(2)
805        code('''\
806    };
807extern const char *${name}Strings[Num_${name}];
808}
809
810#endif // __ENUM__${name}__
811''')
812
813    def cxx_def(cls, code):
814        name = cls.__name__
815        code('''\
816#include "enums/${name}.hh"
817namespace Enums {
818    const char *${name}Strings[Num_${name}] =
819    {
820''')
821        code.indent(2)
822        for val in cls.vals:
823            code('"$val",')
824        code.dedent(2)
825        code('''
826    };
827/* namespace Enums */ }
828''')
829
830# Base class for enum types.
831class Enum(ParamValue):
832    __metaclass__ = MetaEnum
833    vals = []
834
835    def __init__(self, value):
836        if value not in self.map:
837            raise TypeError, "Enum param got bad value '%s' (not in %s)" \
838                  % (value, self.vals)
839        self.value = value
840
841    def getValue(self):
842        return int(self.map[self.value])
843
844    def __str__(self):
845        return self.value
846
847# how big does a rounding error need to be before we warn about it?
848frequency_tolerance = 0.001  # 0.1%
849
850class TickParamValue(NumericParamValue):
851    cxx_type = 'Tick'
852
853    @classmethod
854    def cxx_predecls(cls, code):
855        code('#include "base/types.hh"')
856
857    @classmethod
858    def swig_predecls(cls, code):
859        code('%import "stdint.i"')
860        code('%import "base/types.hh"')
861
862    def getValue(self):
863        return long(self.value)
864
865class Latency(TickParamValue):
866    def __init__(self, value):
867        if isinstance(value, (Latency, Clock)):
868            self.ticks = value.ticks
869            self.value = value.value
870        elif isinstance(value, Frequency):
871            self.ticks = value.ticks
872            self.value = 1.0 / value.value
873        elif value.endswith('t'):
874            self.ticks = True
875            self.value = int(value[:-1])
876        else:
877            self.ticks = False
878            self.value = convert.toLatency(value)
879
880    def __getattr__(self, attr):
881        if attr in ('latency', 'period'):
882            return self
883        if attr == 'frequency':
884            return Frequency(self)
885        raise AttributeError, "Latency object has no attribute '%s'" % attr
886
887    def getValue(self):
888        if self.ticks or self.value == 0:
889            value = self.value
890        else:
891            value = ticks.fromSeconds(self.value)
892        return long(value)
893
894    # convert latency to ticks
895    def ini_str(self):
896        return '%d' % self.getValue()
897
898class Frequency(TickParamValue):
899    def __init__(self, value):
900        if isinstance(value, (Latency, Clock)):
901            if value.value == 0:
902                self.value = 0
903            else:
904                self.value = 1.0 / value.value
905            self.ticks = value.ticks
906        elif isinstance(value, Frequency):
907            self.value = value.value
908            self.ticks = value.ticks
909        else:
910            self.ticks = False
911            self.value = convert.toFrequency(value)
912
913    def __getattr__(self, attr):
914        if attr == 'frequency':
915            return self
916        if attr in ('latency', 'period'):
917            return Latency(self)
918        raise AttributeError, "Frequency object has no attribute '%s'" % attr
919
920    # convert latency to ticks
921    def getValue(self):
922        if self.ticks or self.value == 0:
923            value = self.value
924        else:
925            value = ticks.fromSeconds(1.0 / self.value)
926        return long(value)
927
928    def ini_str(self):
929        return '%d' % self.getValue()
930
931# A generic frequency and/or Latency value.  Value is stored as a latency,
932# but to avoid ambiguity this object does not support numeric ops (* or /).
933# An explicit conversion to a Latency or Frequency must be made first.
934class Clock(ParamValue):
935    cxx_type = 'Tick'
936
937    @classmethod
938    def cxx_predecls(cls, code):
939        code('#include "base/types.hh"')
940
941    @classmethod
942    def swig_predecls(cls, code):
943        code('%import "stdint.i"')
944        code('%import "base/types.hh"')
945
946    def __init__(self, value):
947        if isinstance(value, (Latency, Clock)):
948            self.ticks = value.ticks
949            self.value = value.value
950        elif isinstance(value, Frequency):
951            self.ticks = value.ticks
952            self.value = 1.0 / value.value
953        elif value.endswith('t'):
954            self.ticks = True
955            self.value = int(value[:-1])
956        else:
957            self.ticks = False
958            self.value = convert.anyToLatency(value)
959
960    def __getattr__(self, attr):
961        if attr == 'frequency':
962            return Frequency(self)
963        if attr in ('latency', 'period'):
964            return Latency(self)
965        raise AttributeError, "Frequency object has no attribute '%s'" % attr
966
967    def getValue(self):
968        return self.period.getValue()
969
970    def ini_str(self):
971        return self.period.ini_str()
972
973class NetworkBandwidth(float,ParamValue):
974    cxx_type = 'float'
975    def __new__(cls, value):
976        # convert to bits per second
977        val = convert.toNetworkBandwidth(value)
978        return super(cls, NetworkBandwidth).__new__(cls, val)
979
980    def __str__(self):
981        return str(self.val)
982
983    def getValue(self):
984        # convert to seconds per byte
985        value = 8.0 / float(self)
986        # convert to ticks per byte
987        value = ticks.fromSeconds(value)
988        return float(value)
989
990    def ini_str(self):
991        return '%f' % self.getValue()
992
993class MemoryBandwidth(float,ParamValue):
994    cxx_type = 'float'
995    def __new__(cls, value):
996        # we want the number of ticks per byte of data
997        val = convert.toMemoryBandwidth(value)
998        return super(cls, MemoryBandwidth).__new__(cls, val)
999
1000    def __str__(self):
1001        return str(self.val)
1002
1003    def getValue(self):
1004        # convert to seconds per byte
1005        value = float(self)
1006        if value:
1007            value = 1.0 / float(self)
1008        # convert to ticks per byte
1009        value = ticks.fromSeconds(value)
1010        return float(value)
1011
1012    def ini_str(self):
1013        return '%f' % self.getValue()
1014
1015#
1016# "Constants"... handy aliases for various values.
1017#
1018
1019# Special class for NULL pointers.  Note the special check in
1020# make_param_value() above that lets these be assigned where a
1021# SimObject is required.
1022# only one copy of a particular node
1023class NullSimObject(object):
1024    __metaclass__ = Singleton
1025
1026    def __call__(cls):
1027        return cls
1028
1029    def _instantiate(self, parent = None, path = ''):
1030        pass
1031
1032    def ini_str(self):
1033        return 'Null'
1034
1035    def unproxy(self, base):
1036        return self
1037
1038    def set_path(self, parent, name):
1039        pass
1040
1041    def __str__(self):
1042        return 'Null'
1043
1044    def getValue(self):
1045        return None
1046
1047# The only instance you'll ever need...
1048NULL = NullSimObject()
1049
1050def isNullPointer(value):
1051    return isinstance(value, NullSimObject)
1052
1053# Some memory range specifications use this as a default upper bound.
1054MaxAddr = Addr.max
1055MaxTick = Tick.max
1056AllMemory = AddrRange(0, MaxAddr)
1057
1058
1059#####################################################################
1060#
1061# Port objects
1062#
1063# Ports are used to interconnect objects in the memory system.
1064#
1065#####################################################################
1066
1067# Port reference: encapsulates a reference to a particular port on a
1068# particular SimObject.
1069class PortRef(object):
1070    def __init__(self, simobj, name):
1071        assert(isSimObject(simobj) or isSimObjectClass(simobj))
1072        self.simobj = simobj
1073        self.name = name
1074        self.peer = None   # not associated with another port yet
1075        self.ccConnected = False # C++ port connection done?
1076        self.index = -1  # always -1 for non-vector ports
1077
1078    def __str__(self):
1079        return '%s.%s' % (self.simobj, self.name)
1080
1081    # for config.ini, print peer's name (not ours)
1082    def ini_str(self):
1083        return str(self.peer)
1084
1085    def __getattr__(self, attr):
1086        if attr == 'peerObj':
1087            # shorthand for proxies
1088            return self.peer.simobj
1089        raise AttributeError, "'%s' object has no attribute '%s'" % \
1090              (self.__class__.__name__, attr)
1091
1092    # Full connection is symmetric (both ways).  Called via
1093    # SimObject.__setattr__ as a result of a port assignment, e.g.,
1094    # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
1095    # e.g., "obj1.portA[3] = obj2.portB".
1096    def connect(self, other):
1097        if isinstance(other, VectorPortRef):
1098            # reference to plain VectorPort is implicit append
1099            other = other._get_next()
1100        if self.peer and not proxy.isproxy(self.peer):
1101            print "warning: overwriting port", self, \
1102                  "value", self.peer, "with", other
1103            self.peer.peer = None
1104        self.peer = other
1105        if proxy.isproxy(other):
1106            other.set_param_desc(PortParamDesc())
1107        elif isinstance(other, PortRef):
1108            if other.peer is not self:
1109                other.connect(self)
1110        else:
1111            raise TypeError, \
1112                  "assigning non-port reference '%s' to port '%s'" \
1113                  % (other, self)
1114
1115    def clone(self, simobj, memo):
1116        if memo.has_key(self):
1117            return memo[self]
1118        newRef = copy.copy(self)
1119        memo[self] = newRef
1120        newRef.simobj = simobj
1121        assert(isSimObject(newRef.simobj))
1122        if self.peer and not proxy.isproxy(self.peer):
1123            peerObj = self.peer.simobj(_memo=memo)
1124            newRef.peer = self.peer.clone(peerObj, memo)
1125            assert(not isinstance(newRef.peer, VectorPortRef))
1126        return newRef
1127
1128    def unproxy(self, simobj):
1129        assert(simobj is self.simobj)
1130        if proxy.isproxy(self.peer):
1131            try:
1132                realPeer = self.peer.unproxy(self.simobj)
1133            except:
1134                print "Error in unproxying port '%s' of %s" % \
1135                      (self.name, self.simobj.path())
1136                raise
1137            self.connect(realPeer)
1138
1139    # Call C++ to create corresponding port connection between C++ objects
1140    def ccConnect(self):
1141        from m5.objects.params import connectPorts
1142
1143        if self.ccConnected: # already done this
1144            return
1145        peer = self.peer
1146        if not self.peer: # nothing to connect to
1147            return
1148        try:
1149            connectPorts(self.simobj.getCCObject(), self.name, self.index,
1150                         peer.simobj.getCCObject(), peer.name, peer.index)
1151        except:
1152            print "Error connecting port %s.%s to %s.%s" % \
1153                  (self.simobj.path(), self.name,
1154                   peer.simobj.path(), peer.name)
1155            raise
1156        self.ccConnected = True
1157        peer.ccConnected = True
1158
1159# A reference to an individual element of a VectorPort... much like a
1160# PortRef, but has an index.
1161class VectorPortElementRef(PortRef):
1162    def __init__(self, simobj, name, index):
1163        PortRef.__init__(self, simobj, name)
1164        self.index = index
1165
1166    def __str__(self):
1167        return '%s.%s[%d]' % (self.simobj, self.name, self.index)
1168
1169# A reference to a complete vector-valued port (not just a single element).
1170# Can be indexed to retrieve individual VectorPortElementRef instances.
1171class VectorPortRef(object):
1172    def __init__(self, simobj, name):
1173        assert(isSimObject(simobj) or isSimObjectClass(simobj))
1174        self.simobj = simobj
1175        self.name = name
1176        self.elements = []
1177
1178    def __str__(self):
1179        return '%s.%s[:]' % (self.simobj, self.name)
1180
1181    # for config.ini, print peer's name (not ours)
1182    def ini_str(self):
1183        return ' '.join([el.ini_str() for el in self.elements])
1184
1185    def __getitem__(self, key):
1186        if not isinstance(key, int):
1187            raise TypeError, "VectorPort index must be integer"
1188        if key >= len(self.elements):
1189            # need to extend list
1190            ext = [VectorPortElementRef(self.simobj, self.name, i)
1191                   for i in range(len(self.elements), key+1)]
1192            self.elements.extend(ext)
1193        return self.elements[key]
1194
1195    def _get_next(self):
1196        return self[len(self.elements)]
1197
1198    def __setitem__(self, key, value):
1199        if not isinstance(key, int):
1200            raise TypeError, "VectorPort index must be integer"
1201        self[key].connect(value)
1202
1203    def connect(self, other):
1204        if isinstance(other, (list, tuple)):
1205            # Assign list of port refs to vector port.
1206            # For now, append them... not sure if that's the right semantics
1207            # or if it should replace the current vector.
1208            for ref in other:
1209                self._get_next().connect(ref)
1210        else:
1211            # scalar assignment to plain VectorPort is implicit append
1212            self._get_next().connect(other)
1213
1214    def clone(self, simobj, memo):
1215        if memo.has_key(self):
1216            return memo[self]
1217        newRef = copy.copy(self)
1218        memo[self] = newRef
1219        newRef.simobj = simobj
1220        assert(isSimObject(newRef.simobj))
1221        newRef.elements = [el.clone(simobj, memo) for el in self.elements]
1222        return newRef
1223
1224    def unproxy(self, simobj):
1225        [el.unproxy(simobj) for el in self.elements]
1226
1227    def ccConnect(self):
1228        [el.ccConnect() for el in self.elements]
1229
1230# Port description object.  Like a ParamDesc object, this represents a
1231# logical port in the SimObject class, not a particular port on a
1232# SimObject instance.  The latter are represented by PortRef objects.
1233class Port(object):
1234    # Port("description") or Port(default, "description")
1235    def __init__(self, *args):
1236        if len(args) == 1:
1237            self.desc = args[0]
1238        elif len(args) == 2:
1239            self.default = args[0]
1240            self.desc = args[1]
1241        else:
1242            raise TypeError, 'wrong number of arguments'
1243        # self.name is set by SimObject class on assignment
1244        # e.g., pio_port = Port("blah") sets self.name to 'pio_port'
1245
1246    # Generate a PortRef for this port on the given SimObject with the
1247    # given name
1248    def makeRef(self, simobj):
1249        return PortRef(simobj, self.name)
1250
1251    # Connect an instance of this port (on the given SimObject with
1252    # the given name) with the port described by the supplied PortRef
1253    def connect(self, simobj, ref):
1254        self.makeRef(simobj).connect(ref)
1255
1256# VectorPort description object.  Like Port, but represents a vector
1257# of connections (e.g., as on a Bus).
1258class VectorPort(Port):
1259    def __init__(self, *args):
1260        Port.__init__(self, *args)
1261        self.isVec = True
1262
1263    def makeRef(self, simobj):
1264        return VectorPortRef(simobj, self.name)
1265
1266# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
1267# proxy objects (via set_param_desc()) so that proxy error messages
1268# make sense.
1269class PortParamDesc(object):
1270    __metaclass__ = Singleton
1271
1272    ptype_str = 'Port'
1273    ptype = Port
1274
1275baseEnums = allEnums.copy()
1276baseParams = allParams.copy()
1277
1278def clear():
1279    global allEnums, allParams
1280
1281    allEnums = baseEnums.copy()
1282    allParams = baseParams.copy()
1283
1284__all__ = ['Param', 'VectorParam',
1285           'Enum', 'Bool', 'String', 'Float',
1286           'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
1287           'Int32', 'UInt32', 'Int64', 'UInt64',
1288           'Counter', 'Addr', 'Tick', 'Percent',
1289           'TcpPort', 'UdpPort', 'EthernetAddr',
1290           'MemorySize', 'MemorySize32',
1291           'Latency', 'Frequency', 'Clock',
1292           'NetworkBandwidth', 'MemoryBandwidth',
1293           'Range', 'AddrRange', 'TickRange',
1294           'MaxAddr', 'MaxTick', 'AllMemory',
1295           'Time',
1296           'NextEthernetAddr', 'NULL',
1297           'Port', 'VectorPort']
1298
1299import SimObject
1300