params.py revision 5475
13101Sstever@eecs.umich.edu# Copyright (c) 2004-2006 The Regents of The University of Michigan
23101Sstever@eecs.umich.edu# All rights reserved.
33101Sstever@eecs.umich.edu#
43101Sstever@eecs.umich.edu# Redistribution and use in source and binary forms, with or without
53101Sstever@eecs.umich.edu# modification, are permitted provided that the following conditions are
63101Sstever@eecs.umich.edu# met: redistributions of source code must retain the above copyright
73101Sstever@eecs.umich.edu# notice, this list of conditions and the following disclaimer;
83101Sstever@eecs.umich.edu# redistributions in binary form must reproduce the above copyright
93101Sstever@eecs.umich.edu# notice, this list of conditions and the following disclaimer in the
103101Sstever@eecs.umich.edu# documentation and/or other materials provided with the distribution;
113101Sstever@eecs.umich.edu# neither the name of the copyright holders nor the names of its
123101Sstever@eecs.umich.edu# contributors may be used to endorse or promote products derived from
133101Sstever@eecs.umich.edu# this software without specific prior written permission.
143101Sstever@eecs.umich.edu#
153101Sstever@eecs.umich.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
163101Sstever@eecs.umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
173101Sstever@eecs.umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
183101Sstever@eecs.umich.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
193101Sstever@eecs.umich.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
203101Sstever@eecs.umich.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
213101Sstever@eecs.umich.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
223101Sstever@eecs.umich.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
233101Sstever@eecs.umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
243101Sstever@eecs.umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
253101Sstever@eecs.umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
263101Sstever@eecs.umich.edu#
273101Sstever@eecs.umich.edu# Authors: Steve Reinhardt
283101Sstever@eecs.umich.edu#          Nathan Binkert
293101Sstever@eecs.umich.edu
303101Sstever@eecs.umich.edu#####################################################################
313101Sstever@eecs.umich.edu#
323101Sstever@eecs.umich.edu# Parameter description classes
333101Sstever@eecs.umich.edu#
343101Sstever@eecs.umich.edu# The _params dictionary in each class maps parameter names to either
353101Sstever@eecs.umich.edu# a Param or a VectorParam object.  These objects contain the
363101Sstever@eecs.umich.edu# parameter description string, the parameter type, and the default
373101Sstever@eecs.umich.edu# value (if any).  The convert() method on these objects is used to
383101Sstever@eecs.umich.edu# force whatever value is assigned to the parameter to the appropriate
393101Sstever@eecs.umich.edu# type.
403101Sstever@eecs.umich.edu#
413101Sstever@eecs.umich.edu# Note that the default values are loaded into the class's attribute
423101Sstever@eecs.umich.edu# space when the parameter dictionary is initialized (in
433101Sstever@eecs.umich.edu# MetaSimObject._new_param()); after that point they aren't used.
443101Sstever@eecs.umich.edu#
453101Sstever@eecs.umich.edu#####################################################################
463101Sstever@eecs.umich.edu
473885Sbinkertn@umich.eduimport copy
483885Sbinkertn@umich.eduimport datetime
494762Snate@binkert.orgimport re
503885Sbinkertn@umich.eduimport sys
513885Sbinkertn@umich.eduimport time
523885Sbinkertn@umich.edu
533101Sstever@eecs.umich.eduimport convert
544380Sbinkertn@umich.eduimport proxy
554167Sbinkertn@umich.eduimport ticks
563102Sstever@eecs.umich.edufrom util import *
573101Sstever@eecs.umich.edu
584762Snate@binkert.orgimport SimObject
594762Snate@binkert.org
604762Snate@binkert.orgdef isSimObject(*args, **kwargs):
614762Snate@binkert.org    return SimObject.isSimObject(*args, **kwargs)
624762Snate@binkert.org
634762Snate@binkert.orgdef isSimObjectSequence(*args, **kwargs):
644762Snate@binkert.org    return SimObject.isSimObjectSequence(*args, **kwargs)
654762Snate@binkert.org
664762Snate@binkert.orgdef isSimObjectClass(*args, **kwargs):
674762Snate@binkert.org    return SimObject.isSimObjectClass(*args, **kwargs)
684762Snate@binkert.org
695033Smilesck@eecs.umich.eduallParams = {}
705033Smilesck@eecs.umich.edu
715033Smilesck@eecs.umich.educlass MetaParamValue(type):
725033Smilesck@eecs.umich.edu    def __new__(mcls, name, bases, dct):
735033Smilesck@eecs.umich.edu        cls = super(MetaParamValue, mcls).__new__(mcls, name, bases, dct)
745033Smilesck@eecs.umich.edu        assert name not in allParams
755033Smilesck@eecs.umich.edu        allParams[name] = cls
765033Smilesck@eecs.umich.edu        return cls
775033Smilesck@eecs.umich.edu
785033Smilesck@eecs.umich.edu
793101Sstever@eecs.umich.edu# Dummy base class to identify types that are legitimate for SimObject
803101Sstever@eecs.umich.edu# parameters.
813101Sstever@eecs.umich.educlass ParamValue(object):
825033Smilesck@eecs.umich.edu    __metaclass__ = MetaParamValue
833101Sstever@eecs.umich.edu
843101Sstever@eecs.umich.edu    cxx_predecls = []
853101Sstever@eecs.umich.edu    swig_predecls = []
863101Sstever@eecs.umich.edu
873101Sstever@eecs.umich.edu    # default for printing to .ini file is regular string conversion.
883101Sstever@eecs.umich.edu    # will be overridden in some cases
893101Sstever@eecs.umich.edu    def ini_str(self):
903101Sstever@eecs.umich.edu        return str(self)
913101Sstever@eecs.umich.edu
923101Sstever@eecs.umich.edu    # allows us to blithely call unproxy() on things without checking
933101Sstever@eecs.umich.edu    # if they're really proxies or not
943101Sstever@eecs.umich.edu    def unproxy(self, base):
953101Sstever@eecs.umich.edu        return self
963101Sstever@eecs.umich.edu
973101Sstever@eecs.umich.edu# Regular parameter description.
983101Sstever@eecs.umich.educlass ParamDesc(object):
993101Sstever@eecs.umich.edu    def __init__(self, ptype_str, ptype, *args, **kwargs):
1003101Sstever@eecs.umich.edu        self.ptype_str = ptype_str
1013101Sstever@eecs.umich.edu        # remember ptype only if it is provided
1023101Sstever@eecs.umich.edu        if ptype != None:
1033101Sstever@eecs.umich.edu            self.ptype = ptype
1043101Sstever@eecs.umich.edu
1053101Sstever@eecs.umich.edu        if args:
1063101Sstever@eecs.umich.edu            if len(args) == 1:
1073101Sstever@eecs.umich.edu                self.desc = args[0]
1083101Sstever@eecs.umich.edu            elif len(args) == 2:
1093101Sstever@eecs.umich.edu                self.default = args[0]
1103101Sstever@eecs.umich.edu                self.desc = args[1]
1113101Sstever@eecs.umich.edu            else:
1123101Sstever@eecs.umich.edu                raise TypeError, 'too many arguments'
1133101Sstever@eecs.umich.edu
1143101Sstever@eecs.umich.edu        if kwargs.has_key('desc'):
1153101Sstever@eecs.umich.edu            assert(not hasattr(self, 'desc'))
1163101Sstever@eecs.umich.edu            self.desc = kwargs['desc']
1173101Sstever@eecs.umich.edu            del kwargs['desc']
1183101Sstever@eecs.umich.edu
1193101Sstever@eecs.umich.edu        if kwargs.has_key('default'):
1203101Sstever@eecs.umich.edu            assert(not hasattr(self, 'default'))
1213101Sstever@eecs.umich.edu            self.default = kwargs['default']
1223101Sstever@eecs.umich.edu            del kwargs['default']
1233101Sstever@eecs.umich.edu
1243101Sstever@eecs.umich.edu        if kwargs:
1253101Sstever@eecs.umich.edu            raise TypeError, 'extra unknown kwargs %s' % kwargs
1263101Sstever@eecs.umich.edu
1273101Sstever@eecs.umich.edu        if not hasattr(self, 'desc'):
1283101Sstever@eecs.umich.edu            raise TypeError, 'desc attribute missing'
1293101Sstever@eecs.umich.edu
1303101Sstever@eecs.umich.edu    def __getattr__(self, attr):
1313101Sstever@eecs.umich.edu        if attr == 'ptype':
1325033Smilesck@eecs.umich.edu            ptype = SimObject.allClasses[self.ptype_str]
1335033Smilesck@eecs.umich.edu            assert issubclass(ptype, SimObject.SimObject)
1345033Smilesck@eecs.umich.edu            self.ptype = ptype
1355033Smilesck@eecs.umich.edu            return ptype
1365033Smilesck@eecs.umich.edu
1373101Sstever@eecs.umich.edu        raise AttributeError, "'%s' object has no attribute '%s'" % \
1383101Sstever@eecs.umich.edu              (type(self).__name__, attr)
1393101Sstever@eecs.umich.edu
1403101Sstever@eecs.umich.edu    def convert(self, value):
1413101Sstever@eecs.umich.edu        if isinstance(value, proxy.BaseProxy):
1423101Sstever@eecs.umich.edu            value.set_param_desc(self)
1433101Sstever@eecs.umich.edu            return value
1443101Sstever@eecs.umich.edu        if not hasattr(self, 'ptype') and isNullPointer(value):
1453101Sstever@eecs.umich.edu            # deferred evaluation of SimObject; continue to defer if
1463101Sstever@eecs.umich.edu            # we're just assigning a null pointer
1473101Sstever@eecs.umich.edu            return value
1483101Sstever@eecs.umich.edu        if isinstance(value, self.ptype):
1493101Sstever@eecs.umich.edu            return value
1503102Sstever@eecs.umich.edu        if isNullPointer(value) and isSimObjectClass(self.ptype):
1513101Sstever@eecs.umich.edu            return value
1523101Sstever@eecs.umich.edu        return self.ptype(value)
1533101Sstever@eecs.umich.edu
1543101Sstever@eecs.umich.edu    def cxx_predecls(self):
1553101Sstever@eecs.umich.edu        return self.ptype.cxx_predecls
1563101Sstever@eecs.umich.edu
1573101Sstever@eecs.umich.edu    def swig_predecls(self):
1583101Sstever@eecs.umich.edu        return self.ptype.swig_predecls
1593101Sstever@eecs.umich.edu
1603101Sstever@eecs.umich.edu    def cxx_decl(self):
1613101Sstever@eecs.umich.edu        return '%s %s;' % (self.ptype.cxx_type, self.name)
1623101Sstever@eecs.umich.edu
1633101Sstever@eecs.umich.edu# Vector-valued parameter description.  Just like ParamDesc, except
1643101Sstever@eecs.umich.edu# that the value is a vector (list) of the specified type instead of a
1653101Sstever@eecs.umich.edu# single value.
1663101Sstever@eecs.umich.edu
1673101Sstever@eecs.umich.educlass VectorParamValue(list):
1685033Smilesck@eecs.umich.edu    __metaclass__ = MetaParamValue
1695475Snate@binkert.org    def __setattr__(self, attr, value):
1705475Snate@binkert.org        raise AttributeError, \
1715475Snate@binkert.org              "Not allowed to set %s on '%s'" % (attr, type(self).__name__)
1725475Snate@binkert.org
1733101Sstever@eecs.umich.edu    def ini_str(self):
1743101Sstever@eecs.umich.edu        return ' '.join([v.ini_str() for v in self])
1753101Sstever@eecs.umich.edu
1764762Snate@binkert.org    def getValue(self):
1774762Snate@binkert.org        return [ v.getValue() for v in self ]
1784762Snate@binkert.org
1793101Sstever@eecs.umich.edu    def unproxy(self, base):
1803101Sstever@eecs.umich.edu        return [v.unproxy(base) for v in self]
1813101Sstever@eecs.umich.edu
1823101Sstever@eecs.umich.educlass SimObjVector(VectorParamValue):
1835037Smilesck@eecs.umich.edu    def print_ini(self, ini_file):
1843101Sstever@eecs.umich.edu        for v in self:
1855037Smilesck@eecs.umich.edu            v.print_ini(ini_file)
1863101Sstever@eecs.umich.edu
1873101Sstever@eecs.umich.educlass VectorParamDesc(ParamDesc):
1883101Sstever@eecs.umich.edu    # Convert assigned value to appropriate type.  If the RHS is not a
1893101Sstever@eecs.umich.edu    # list or tuple, it generates a single-element list.
1903101Sstever@eecs.umich.edu    def convert(self, value):
1913101Sstever@eecs.umich.edu        if isinstance(value, (list, tuple)):
1923101Sstever@eecs.umich.edu            # list: coerce each element into new list
1933101Sstever@eecs.umich.edu            tmp_list = [ ParamDesc.convert(self, v) for v in value ]
1943101Sstever@eecs.umich.edu        else:
1954762Snate@binkert.org            # singleton: coerce to a single-element list
1964762Snate@binkert.org            tmp_list = [ ParamDesc.convert(self, value) ]
1974762Snate@binkert.org
1984762Snate@binkert.org        if isSimObjectSequence(tmp_list):
1994762Snate@binkert.org            return SimObjVector(tmp_list)
2004762Snate@binkert.org        else:
2014762Snate@binkert.org            return VectorParamValue(tmp_list)
2024762Snate@binkert.org
2034762Snate@binkert.org    def swig_predecls(self):
2044762Snate@binkert.org        return ['%%include "%s_vptype.i"' % self.ptype_str]
2054762Snate@binkert.org
2064762Snate@binkert.org    def swig_decl(self):
2074762Snate@binkert.org        cxx_type = re.sub('std::', '', self.ptype.cxx_type)
2084762Snate@binkert.org        vdecl = 'namespace std { %%template(vector_%s) vector< %s >; }' % \
2094762Snate@binkert.org                (self.ptype_str, cxx_type)
2104762Snate@binkert.org        return ['%include "std_vector.i"'] + self.ptype.swig_predecls + [vdecl]
2113101Sstever@eecs.umich.edu
2123101Sstever@eecs.umich.edu    def cxx_predecls(self):
2133101Sstever@eecs.umich.edu        return ['#include <vector>'] + self.ptype.cxx_predecls
2143101Sstever@eecs.umich.edu
2153101Sstever@eecs.umich.edu    def cxx_decl(self):
2163101Sstever@eecs.umich.edu        return 'std::vector< %s > %s;' % (self.ptype.cxx_type, self.name)
2173101Sstever@eecs.umich.edu
2183101Sstever@eecs.umich.educlass ParamFactory(object):
2193101Sstever@eecs.umich.edu    def __init__(self, param_desc_class, ptype_str = None):
2203101Sstever@eecs.umich.edu        self.param_desc_class = param_desc_class
2213101Sstever@eecs.umich.edu        self.ptype_str = ptype_str
2223101Sstever@eecs.umich.edu
2233101Sstever@eecs.umich.edu    def __getattr__(self, attr):
2243101Sstever@eecs.umich.edu        if self.ptype_str:
2253101Sstever@eecs.umich.edu            attr = self.ptype_str + '.' + attr
2263101Sstever@eecs.umich.edu        return ParamFactory(self.param_desc_class, attr)
2273101Sstever@eecs.umich.edu
2283101Sstever@eecs.umich.edu    # E.g., Param.Int(5, "number of widgets")
2293101Sstever@eecs.umich.edu    def __call__(self, *args, **kwargs):
2303101Sstever@eecs.umich.edu        ptype = None
2313101Sstever@eecs.umich.edu        try:
2325033Smilesck@eecs.umich.edu            ptype = allParams[self.ptype_str]
2335033Smilesck@eecs.umich.edu        except KeyError:
2343101Sstever@eecs.umich.edu            # if name isn't defined yet, assume it's a SimObject, and
2353101Sstever@eecs.umich.edu            # try to resolve it later
2363101Sstever@eecs.umich.edu            pass
2373101Sstever@eecs.umich.edu        return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs)
2383101Sstever@eecs.umich.edu
2393101Sstever@eecs.umich.eduParam = ParamFactory(ParamDesc)
2403101Sstever@eecs.umich.eduVectorParam = ParamFactory(VectorParamDesc)
2413101Sstever@eecs.umich.edu
2423101Sstever@eecs.umich.edu#####################################################################
2433101Sstever@eecs.umich.edu#
2443101Sstever@eecs.umich.edu# Parameter Types
2453101Sstever@eecs.umich.edu#
2463101Sstever@eecs.umich.edu# Though native Python types could be used to specify parameter types
2473101Sstever@eecs.umich.edu# (the 'ptype' field of the Param and VectorParam classes), it's more
2483101Sstever@eecs.umich.edu# flexible to define our own set of types.  This gives us more control
2493101Sstever@eecs.umich.edu# over how Python expressions are converted to values (via the
2503101Sstever@eecs.umich.edu# __init__() constructor) and how these values are printed out (via
2513101Sstever@eecs.umich.edu# the __str__() conversion method).
2523101Sstever@eecs.umich.edu#
2533101Sstever@eecs.umich.edu#####################################################################
2543101Sstever@eecs.umich.edu
2553101Sstever@eecs.umich.edu# String-valued parameter.  Just mixin the ParamValue class with the
2563101Sstever@eecs.umich.edu# built-in str class.
2573101Sstever@eecs.umich.educlass String(ParamValue,str):
2583101Sstever@eecs.umich.edu    cxx_type = 'std::string'
2593101Sstever@eecs.umich.edu    cxx_predecls = ['#include <string>']
2603101Sstever@eecs.umich.edu    swig_predecls = ['%include "std_string.i"\n' +
2613101Sstever@eecs.umich.edu                     '%apply const std::string& {std::string *};']
2624762Snate@binkert.org    swig_predecls = ['%include "std_string.i"' ]
2634762Snate@binkert.org
2644762Snate@binkert.org    def getValue(self):
2654762Snate@binkert.org        return self
2663101Sstever@eecs.umich.edu
2673101Sstever@eecs.umich.edu# superclass for "numeric" parameter values, to emulate math
2683101Sstever@eecs.umich.edu# operations in a type-safe way.  e.g., a Latency times an int returns
2693101Sstever@eecs.umich.edu# a new Latency object.
2703101Sstever@eecs.umich.educlass NumericParamValue(ParamValue):
2713101Sstever@eecs.umich.edu    def __str__(self):
2723101Sstever@eecs.umich.edu        return str(self.value)
2733101Sstever@eecs.umich.edu
2743101Sstever@eecs.umich.edu    def __float__(self):
2753101Sstever@eecs.umich.edu        return float(self.value)
2763101Sstever@eecs.umich.edu
2773714Sstever@eecs.umich.edu    def __long__(self):
2783714Sstever@eecs.umich.edu        return long(self.value)
2793714Sstever@eecs.umich.edu
2803714Sstever@eecs.umich.edu    def __int__(self):
2813714Sstever@eecs.umich.edu        return int(self.value)
2823714Sstever@eecs.umich.edu
2833101Sstever@eecs.umich.edu    # hook for bounds checking
2843101Sstever@eecs.umich.edu    def _check(self):
2853101Sstever@eecs.umich.edu        return
2863101Sstever@eecs.umich.edu
2873101Sstever@eecs.umich.edu    def __mul__(self, other):
2883101Sstever@eecs.umich.edu        newobj = self.__class__(self)
2893101Sstever@eecs.umich.edu        newobj.value *= other
2903101Sstever@eecs.umich.edu        newobj._check()
2913101Sstever@eecs.umich.edu        return newobj
2923101Sstever@eecs.umich.edu
2933101Sstever@eecs.umich.edu    __rmul__ = __mul__
2943101Sstever@eecs.umich.edu
2953101Sstever@eecs.umich.edu    def __div__(self, other):
2963101Sstever@eecs.umich.edu        newobj = self.__class__(self)
2973101Sstever@eecs.umich.edu        newobj.value /= other
2983101Sstever@eecs.umich.edu        newobj._check()
2993101Sstever@eecs.umich.edu        return newobj
3003101Sstever@eecs.umich.edu
3013101Sstever@eecs.umich.edu    def __sub__(self, other):
3023101Sstever@eecs.umich.edu        newobj = self.__class__(self)
3033101Sstever@eecs.umich.edu        newobj.value -= other
3043101Sstever@eecs.umich.edu        newobj._check()
3053101Sstever@eecs.umich.edu        return newobj
3063101Sstever@eecs.umich.edu
3073101Sstever@eecs.umich.edu# Metaclass for bounds-checked integer parameters.  See CheckedInt.
3085033Smilesck@eecs.umich.educlass CheckedIntType(MetaParamValue):
3093101Sstever@eecs.umich.edu    def __init__(cls, name, bases, dict):
3103101Sstever@eecs.umich.edu        super(CheckedIntType, cls).__init__(name, bases, dict)
3113101Sstever@eecs.umich.edu
3123101Sstever@eecs.umich.edu        # CheckedInt is an abstract base class, so we actually don't
3133101Sstever@eecs.umich.edu        # want to do any processing on it... the rest of this code is
3143101Sstever@eecs.umich.edu        # just for classes that derive from CheckedInt.
3153101Sstever@eecs.umich.edu        if name == 'CheckedInt':
3163101Sstever@eecs.umich.edu            return
3173101Sstever@eecs.umich.edu
3183101Sstever@eecs.umich.edu        if not cls.cxx_predecls:
3193101Sstever@eecs.umich.edu            # most derived types require this, so we just do it here once
3203101Sstever@eecs.umich.edu            cls.cxx_predecls = ['#include "sim/host.hh"']
3213101Sstever@eecs.umich.edu
3223101Sstever@eecs.umich.edu        if not cls.swig_predecls:
3233101Sstever@eecs.umich.edu            # most derived types require this, so we just do it here once
3244762Snate@binkert.org            cls.swig_predecls = ['%import "stdint.i"\n' +
3253101Sstever@eecs.umich.edu                                 '%import "sim/host.hh"']
3263101Sstever@eecs.umich.edu
3273101Sstever@eecs.umich.edu        if not (hasattr(cls, 'min') and hasattr(cls, 'max')):
3283101Sstever@eecs.umich.edu            if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')):
3293101Sstever@eecs.umich.edu                panic("CheckedInt subclass %s must define either\n" \
3303101Sstever@eecs.umich.edu                      "    'min' and 'max' or 'size' and 'unsigned'\n" \
3313101Sstever@eecs.umich.edu                      % name);
3323101Sstever@eecs.umich.edu            if cls.unsigned:
3333101Sstever@eecs.umich.edu                cls.min = 0
3343101Sstever@eecs.umich.edu                cls.max = 2 ** cls.size - 1
3353101Sstever@eecs.umich.edu            else:
3363101Sstever@eecs.umich.edu                cls.min = -(2 ** (cls.size - 1))
3373101Sstever@eecs.umich.edu                cls.max = (2 ** (cls.size - 1)) - 1
3383101Sstever@eecs.umich.edu
3393101Sstever@eecs.umich.edu# Abstract superclass for bounds-checked integer parameters.  This
3403101Sstever@eecs.umich.edu# class is subclassed to generate parameter classes with specific
3413101Sstever@eecs.umich.edu# bounds.  Initialization of the min and max bounds is done in the
3423101Sstever@eecs.umich.edu# metaclass CheckedIntType.__init__.
3433101Sstever@eecs.umich.educlass CheckedInt(NumericParamValue):
3443101Sstever@eecs.umich.edu    __metaclass__ = CheckedIntType
3453101Sstever@eecs.umich.edu
3463101Sstever@eecs.umich.edu    def _check(self):
3473101Sstever@eecs.umich.edu        if not self.min <= self.value <= self.max:
3483101Sstever@eecs.umich.edu            raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
3493101Sstever@eecs.umich.edu                  (self.min, self.value, self.max)
3503101Sstever@eecs.umich.edu
3513101Sstever@eecs.umich.edu    def __init__(self, value):
3523101Sstever@eecs.umich.edu        if isinstance(value, str):
3533102Sstever@eecs.umich.edu            self.value = convert.toInteger(value)
3543714Sstever@eecs.umich.edu        elif isinstance(value, (int, long, float, NumericParamValue)):
3553101Sstever@eecs.umich.edu            self.value = long(value)
3563714Sstever@eecs.umich.edu        else:
3573714Sstever@eecs.umich.edu            raise TypeError, "Can't convert object of type %s to CheckedInt" \
3583714Sstever@eecs.umich.edu                  % type(value).__name__
3593101Sstever@eecs.umich.edu        self._check()
3603101Sstever@eecs.umich.edu
3614762Snate@binkert.org    def getValue(self):
3624762Snate@binkert.org        return long(self.value)
3634762Snate@binkert.org
3643101Sstever@eecs.umich.educlass Int(CheckedInt):      cxx_type = 'int';      size = 32; unsigned = False
3653101Sstever@eecs.umich.educlass Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True
3663101Sstever@eecs.umich.edu
3673101Sstever@eecs.umich.educlass Int8(CheckedInt):     cxx_type =   'int8_t'; size =  8; unsigned = False
3683101Sstever@eecs.umich.educlass UInt8(CheckedInt):    cxx_type =  'uint8_t'; size =  8; unsigned = True
3693101Sstever@eecs.umich.educlass Int16(CheckedInt):    cxx_type =  'int16_t'; size = 16; unsigned = False
3703101Sstever@eecs.umich.educlass UInt16(CheckedInt):   cxx_type = 'uint16_t'; size = 16; unsigned = True
3713101Sstever@eecs.umich.educlass Int32(CheckedInt):    cxx_type =  'int32_t'; size = 32; unsigned = False
3723101Sstever@eecs.umich.educlass UInt32(CheckedInt):   cxx_type = 'uint32_t'; size = 32; unsigned = True
3733101Sstever@eecs.umich.educlass Int64(CheckedInt):    cxx_type =  'int64_t'; size = 64; unsigned = False
3743101Sstever@eecs.umich.educlass UInt64(CheckedInt):   cxx_type = 'uint64_t'; size = 64; unsigned = True
3753101Sstever@eecs.umich.edu
3763101Sstever@eecs.umich.educlass Counter(CheckedInt):  cxx_type = 'Counter';  size = 64; unsigned = True
3773101Sstever@eecs.umich.educlass Tick(CheckedInt):     cxx_type = 'Tick';     size = 64; unsigned = True
3783101Sstever@eecs.umich.educlass TcpPort(CheckedInt):  cxx_type = 'uint16_t'; size = 16; unsigned = True
3793101Sstever@eecs.umich.educlass UdpPort(CheckedInt):  cxx_type = 'uint16_t'; size = 16; unsigned = True
3803101Sstever@eecs.umich.edu
3813101Sstever@eecs.umich.educlass Percent(CheckedInt):  cxx_type = 'int'; min = 0; max = 100
3823101Sstever@eecs.umich.edu
3833101Sstever@eecs.umich.educlass Float(ParamValue, float):
3844446Sbinkertn@umich.edu    cxx_type = 'double'
3853101Sstever@eecs.umich.edu
3865468Snate@binkert.org    def __init__(self, value):
3875468Snate@binkert.org        if isinstance(value, (int, long, float, NumericParamValue, Float)):
3885468Snate@binkert.org            self.value = float(value)
3895468Snate@binkert.org        else:
3905468Snate@binkert.org            raise TypeError, "Can't convert object of type %s to Float" \
3915468Snate@binkert.org                  % type(value).__name__
3925468Snate@binkert.org
3934762Snate@binkert.org    def getValue(self):
3944762Snate@binkert.org        return float(self.value)
3954762Snate@binkert.org
3963101Sstever@eecs.umich.educlass MemorySize(CheckedInt):
3973101Sstever@eecs.umich.edu    cxx_type = 'uint64_t'
3983101Sstever@eecs.umich.edu    size = 64
3993101Sstever@eecs.umich.edu    unsigned = True
4003101Sstever@eecs.umich.edu    def __init__(self, value):
4013101Sstever@eecs.umich.edu        if isinstance(value, MemorySize):
4023101Sstever@eecs.umich.edu            self.value = value.value
4033101Sstever@eecs.umich.edu        else:
4043102Sstever@eecs.umich.edu            self.value = convert.toMemorySize(value)
4053101Sstever@eecs.umich.edu        self._check()
4063101Sstever@eecs.umich.edu
4073101Sstever@eecs.umich.educlass MemorySize32(CheckedInt):
4084168Sbinkertn@umich.edu    cxx_type = 'uint32_t'
4093101Sstever@eecs.umich.edu    size = 32
4103101Sstever@eecs.umich.edu    unsigned = True
4113101Sstever@eecs.umich.edu    def __init__(self, value):
4123101Sstever@eecs.umich.edu        if isinstance(value, MemorySize):
4133101Sstever@eecs.umich.edu            self.value = value.value
4143101Sstever@eecs.umich.edu        else:
4153102Sstever@eecs.umich.edu            self.value = convert.toMemorySize(value)
4163101Sstever@eecs.umich.edu        self._check()
4173101Sstever@eecs.umich.edu
4183101Sstever@eecs.umich.educlass Addr(CheckedInt):
4193101Sstever@eecs.umich.edu    cxx_type = 'Addr'
4203101Sstever@eecs.umich.edu    size = 64
4213101Sstever@eecs.umich.edu    unsigned = True
4223101Sstever@eecs.umich.edu    def __init__(self, value):
4233101Sstever@eecs.umich.edu        if isinstance(value, Addr):
4243101Sstever@eecs.umich.edu            self.value = value.value
4253101Sstever@eecs.umich.edu        else:
4263101Sstever@eecs.umich.edu            try:
4273102Sstever@eecs.umich.edu                self.value = convert.toMemorySize(value)
4283101Sstever@eecs.umich.edu            except TypeError:
4293101Sstever@eecs.umich.edu                self.value = long(value)
4303101Sstever@eecs.umich.edu        self._check()
4313584Ssaidi@eecs.umich.edu    def __add__(self, other):
4323584Ssaidi@eecs.umich.edu        if isinstance(other, Addr):
4333584Ssaidi@eecs.umich.edu            return self.value + other.value
4343584Ssaidi@eecs.umich.edu        else:
4353584Ssaidi@eecs.umich.edu            return self.value + other
4363101Sstever@eecs.umich.edu
4373101Sstever@eecs.umich.edu
4385033Smilesck@eecs.umich.educlass MetaRange(MetaParamValue):
4393101Sstever@eecs.umich.edu    def __init__(cls, name, bases, dict):
4403101Sstever@eecs.umich.edu        super(MetaRange, cls).__init__(name, bases, dict)
4413101Sstever@eecs.umich.edu        if name == 'Range':
4423101Sstever@eecs.umich.edu            return
4433101Sstever@eecs.umich.edu        cls.cxx_type = 'Range< %s >' % cls.type.cxx_type
4443101Sstever@eecs.umich.edu        cls.cxx_predecls = \
4453101Sstever@eecs.umich.edu                       ['#include "base/range.hh"'] + cls.type.cxx_predecls
4463101Sstever@eecs.umich.edu
4473101Sstever@eecs.umich.educlass Range(ParamValue):
4483101Sstever@eecs.umich.edu    __metaclass__ = MetaRange
4493101Sstever@eecs.umich.edu    type = Int # default; can be overridden in subclasses
4503101Sstever@eecs.umich.edu    def __init__(self, *args, **kwargs):
4513101Sstever@eecs.umich.edu        def handle_kwargs(self, kwargs):
4523101Sstever@eecs.umich.edu            if 'end' in kwargs:
4533101Sstever@eecs.umich.edu                self.second = self.type(kwargs.pop('end'))
4543101Sstever@eecs.umich.edu            elif 'size' in kwargs:
4553101Sstever@eecs.umich.edu                self.second = self.first + self.type(kwargs.pop('size')) - 1
4563101Sstever@eecs.umich.edu            else:
4573101Sstever@eecs.umich.edu                raise TypeError, "Either end or size must be specified"
4583101Sstever@eecs.umich.edu
4593101Sstever@eecs.umich.edu        if len(args) == 0:
4603101Sstever@eecs.umich.edu            self.first = self.type(kwargs.pop('start'))
4613101Sstever@eecs.umich.edu            handle_kwargs(self, kwargs)
4623101Sstever@eecs.umich.edu
4633101Sstever@eecs.umich.edu        elif len(args) == 1:
4643101Sstever@eecs.umich.edu            if kwargs:
4653101Sstever@eecs.umich.edu                self.first = self.type(args[0])
4663101Sstever@eecs.umich.edu                handle_kwargs(self, kwargs)
4673101Sstever@eecs.umich.edu            elif isinstance(args[0], Range):
4683101Sstever@eecs.umich.edu                self.first = self.type(args[0].first)
4693101Sstever@eecs.umich.edu                self.second = self.type(args[0].second)
4705219Ssaidi@eecs.umich.edu            elif isinstance(args[0], (list, tuple)):
4715219Ssaidi@eecs.umich.edu                self.first = self.type(args[0][0])
4725219Ssaidi@eecs.umich.edu                self.second = self.type(args[0][1])
4733101Sstever@eecs.umich.edu            else:
4743101Sstever@eecs.umich.edu                self.first = self.type(0)
4753101Sstever@eecs.umich.edu                self.second = self.type(args[0]) - 1
4763101Sstever@eecs.umich.edu
4773101Sstever@eecs.umich.edu        elif len(args) == 2:
4783101Sstever@eecs.umich.edu            self.first = self.type(args[0])
4793101Sstever@eecs.umich.edu            self.second = self.type(args[1])
4803101Sstever@eecs.umich.edu        else:
4813101Sstever@eecs.umich.edu            raise TypeError, "Too many arguments specified"
4823101Sstever@eecs.umich.edu
4833101Sstever@eecs.umich.edu        if kwargs:
4843101Sstever@eecs.umich.edu            raise TypeError, "too many keywords: %s" % kwargs.keys()
4853101Sstever@eecs.umich.edu
4863101Sstever@eecs.umich.edu    def __str__(self):
4873101Sstever@eecs.umich.edu        return '%s:%s' % (self.first, self.second)
4883101Sstever@eecs.umich.edu
4893101Sstever@eecs.umich.educlass AddrRange(Range):
4903101Sstever@eecs.umich.edu    type = Addr
4914762Snate@binkert.org    swig_predecls = ['%include "python/swig/range.i"']
4924762Snate@binkert.org
4934762Snate@binkert.org    def getValue(self):
4944762Snate@binkert.org        from m5.objects.params import AddrRange
4954762Snate@binkert.org
4964762Snate@binkert.org        value = AddrRange()
4974762Snate@binkert.org        value.start = long(self.first)
4984762Snate@binkert.org        value.end = long(self.second)
4994762Snate@binkert.org        return value
5003101Sstever@eecs.umich.edu
5013101Sstever@eecs.umich.educlass TickRange(Range):
5023101Sstever@eecs.umich.edu    type = Tick
5034762Snate@binkert.org    swig_predecls = ['%include "python/swig/range.i"']
5044762Snate@binkert.org
5054762Snate@binkert.org    def getValue(self):
5064762Snate@binkert.org        from m5.objects.params import TickRange
5074762Snate@binkert.org
5084762Snate@binkert.org        value = TickRange()
5094762Snate@binkert.org        value.start = long(self.first)
5104762Snate@binkert.org        value.end = long(self.second)
5114762Snate@binkert.org        return value
5123101Sstever@eecs.umich.edu
5133101Sstever@eecs.umich.edu# Boolean parameter type.  Python doesn't let you subclass bool, since
5143101Sstever@eecs.umich.edu# it doesn't want to let you create multiple instances of True and
5153101Sstever@eecs.umich.edu# False.  Thus this is a little more complicated than String.
5163101Sstever@eecs.umich.educlass Bool(ParamValue):
5173101Sstever@eecs.umich.edu    cxx_type = 'bool'
5183101Sstever@eecs.umich.edu    def __init__(self, value):
5193101Sstever@eecs.umich.edu        try:
5203102Sstever@eecs.umich.edu            self.value = convert.toBool(value)
5213101Sstever@eecs.umich.edu        except TypeError:
5223101Sstever@eecs.umich.edu            self.value = bool(value)
5233101Sstever@eecs.umich.edu
5244762Snate@binkert.org    def getValue(self):
5254762Snate@binkert.org        return bool(self.value)
5264762Snate@binkert.org
5273101Sstever@eecs.umich.edu    def __str__(self):
5283101Sstever@eecs.umich.edu        return str(self.value)
5293101Sstever@eecs.umich.edu
5303101Sstever@eecs.umich.edu    def ini_str(self):
5313101Sstever@eecs.umich.edu        if self.value:
5323101Sstever@eecs.umich.edu            return 'true'
5333101Sstever@eecs.umich.edu        return 'false'
5343101Sstever@eecs.umich.edu
5353101Sstever@eecs.umich.edudef IncEthernetAddr(addr, val = 1):
5363101Sstever@eecs.umich.edu    bytes = map(lambda x: int(x, 16), addr.split(':'))
5373101Sstever@eecs.umich.edu    bytes[5] += val
5383101Sstever@eecs.umich.edu    for i in (5, 4, 3, 2, 1):
5393101Sstever@eecs.umich.edu        val,rem = divmod(bytes[i], 256)
5403101Sstever@eecs.umich.edu        bytes[i] = rem
5413101Sstever@eecs.umich.edu        if val == 0:
5423101Sstever@eecs.umich.edu            break
5433101Sstever@eecs.umich.edu        bytes[i - 1] += val
5443101Sstever@eecs.umich.edu    assert(bytes[0] <= 255)
5453101Sstever@eecs.umich.edu    return ':'.join(map(lambda x: '%02x' % x, bytes))
5463101Sstever@eecs.umich.edu
5474380Sbinkertn@umich.edu_NextEthernetAddr = "00:90:00:00:00:01"
5484380Sbinkertn@umich.edudef NextEthernetAddr():
5494380Sbinkertn@umich.edu    global _NextEthernetAddr
5503101Sstever@eecs.umich.edu
5514380Sbinkertn@umich.edu    value = _NextEthernetAddr
5524380Sbinkertn@umich.edu    _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1)
5534380Sbinkertn@umich.edu    return value
5543101Sstever@eecs.umich.edu
5553101Sstever@eecs.umich.educlass EthernetAddr(ParamValue):
5563101Sstever@eecs.umich.edu    cxx_type = 'Net::EthAddr'
5573101Sstever@eecs.umich.edu    cxx_predecls = ['#include "base/inet.hh"']
5584762Snate@binkert.org    swig_predecls = ['%include "python/swig/inet.i"']
5593101Sstever@eecs.umich.edu    def __init__(self, value):
5603101Sstever@eecs.umich.edu        if value == NextEthernetAddr:
5613101Sstever@eecs.umich.edu            self.value = value
5623101Sstever@eecs.umich.edu            return
5633101Sstever@eecs.umich.edu
5643101Sstever@eecs.umich.edu        if not isinstance(value, str):
5653101Sstever@eecs.umich.edu            raise TypeError, "expected an ethernet address and didn't get one"
5663101Sstever@eecs.umich.edu
5673101Sstever@eecs.umich.edu        bytes = value.split(':')
5683101Sstever@eecs.umich.edu        if len(bytes) != 6:
5693101Sstever@eecs.umich.edu            raise TypeError, 'invalid ethernet address %s' % value
5703101Sstever@eecs.umich.edu
5713101Sstever@eecs.umich.edu        for byte in bytes:
5723101Sstever@eecs.umich.edu            if not 0 <= int(byte) <= 256:
5733101Sstever@eecs.umich.edu                raise TypeError, 'invalid ethernet address %s' % value
5743101Sstever@eecs.umich.edu
5753101Sstever@eecs.umich.edu        self.value = value
5763101Sstever@eecs.umich.edu
5773101Sstever@eecs.umich.edu    def unproxy(self, base):
5783101Sstever@eecs.umich.edu        if self.value == NextEthernetAddr:
5794380Sbinkertn@umich.edu            return EthernetAddr(self.value())
5803101Sstever@eecs.umich.edu        return self
5813101Sstever@eecs.umich.edu
5824762Snate@binkert.org    def getValue(self):
5834762Snate@binkert.org        from m5.objects.params import EthAddr
5844762Snate@binkert.org        return EthAddr(self.value)
5854762Snate@binkert.org
5864380Sbinkertn@umich.edu    def ini_str(self):
5874380Sbinkertn@umich.edu        return self.value
5883101Sstever@eecs.umich.edu
5893932Sbinkertn@umich.edutime_formats = [ "%a %b %d %H:%M:%S %Z %Y",
5903932Sbinkertn@umich.edu                 "%a %b %d %H:%M:%S %Z %Y",
5913932Sbinkertn@umich.edu                 "%Y/%m/%d %H:%M:%S",
5923932Sbinkertn@umich.edu                 "%Y/%m/%d %H:%M",
5933932Sbinkertn@umich.edu                 "%Y/%m/%d",
5943932Sbinkertn@umich.edu                 "%m/%d/%Y %H:%M:%S",
5953932Sbinkertn@umich.edu                 "%m/%d/%Y %H:%M",
5963932Sbinkertn@umich.edu                 "%m/%d/%Y",
5973932Sbinkertn@umich.edu                 "%m/%d/%y %H:%M:%S",
5983932Sbinkertn@umich.edu                 "%m/%d/%y %H:%M",
5993932Sbinkertn@umich.edu                 "%m/%d/%y"]
6003932Sbinkertn@umich.edu
6013932Sbinkertn@umich.edu
6023885Sbinkertn@umich.edudef parse_time(value):
6033932Sbinkertn@umich.edu    from time import gmtime, strptime, struct_time, time
6043932Sbinkertn@umich.edu    from datetime import datetime, date
6053885Sbinkertn@umich.edu
6063932Sbinkertn@umich.edu    if isinstance(value, struct_time):
6073932Sbinkertn@umich.edu        return value
6083932Sbinkertn@umich.edu
6093932Sbinkertn@umich.edu    if isinstance(value, (int, long)):
6103932Sbinkertn@umich.edu        return gmtime(value)
6113932Sbinkertn@umich.edu
6123932Sbinkertn@umich.edu    if isinstance(value, (datetime, date)):
6133932Sbinkertn@umich.edu        return value.timetuple()
6143932Sbinkertn@umich.edu
6153932Sbinkertn@umich.edu    if isinstance(value, str):
6163932Sbinkertn@umich.edu        if value in ('Now', 'Today'):
6173932Sbinkertn@umich.edu            return time.gmtime(time.time())
6183932Sbinkertn@umich.edu
6193932Sbinkertn@umich.edu        for format in time_formats:
6203932Sbinkertn@umich.edu            try:
6213932Sbinkertn@umich.edu                return strptime(value, format)
6223932Sbinkertn@umich.edu            except ValueError:
6233932Sbinkertn@umich.edu                pass
6243885Sbinkertn@umich.edu
6253885Sbinkertn@umich.edu    raise ValueError, "Could not parse '%s' as a time" % value
6263885Sbinkertn@umich.edu
6273885Sbinkertn@umich.educlass Time(ParamValue):
6284762Snate@binkert.org    cxx_type = 'tm'
6294762Snate@binkert.org    cxx_predecls = [ '#include <time.h>' ]
6304762Snate@binkert.org    swig_predecls = [ '%include "python/swig/time.i"' ]
6313885Sbinkertn@umich.edu    def __init__(self, value):
6323932Sbinkertn@umich.edu        self.value = parse_time(value)
6333885Sbinkertn@umich.edu
6344762Snate@binkert.org    def getValue(self):
6354762Snate@binkert.org        from m5.objects.params import tm
6364762Snate@binkert.org
6374762Snate@binkert.org        c_time = tm()
6384762Snate@binkert.org        py_time = self.value
6394762Snate@binkert.org
6404762Snate@binkert.org        # UNIX is years since 1900
6414762Snate@binkert.org        c_time.tm_year = py_time.tm_year - 1900;
6424762Snate@binkert.org
6434762Snate@binkert.org        # Python starts at 1, UNIX starts at 0
6444762Snate@binkert.org        c_time.tm_mon =  py_time.tm_mon - 1;
6454762Snate@binkert.org        c_time.tm_mday = py_time.tm_mday;
6464762Snate@binkert.org        c_time.tm_hour = py_time.tm_hour;
6474762Snate@binkert.org        c_time.tm_min = py_time.tm_min;
6484762Snate@binkert.org        c_time.tm_sec = py_time.tm_sec;
6494762Snate@binkert.org
6504762Snate@binkert.org        # Python has 0 as Monday, UNIX is 0 as sunday
6514762Snate@binkert.org        c_time.tm_wday = py_time.tm_wday + 1
6524762Snate@binkert.org        if c_time.tm_wday > 6:
6534762Snate@binkert.org            c_time.tm_wday -= 7;
6544762Snate@binkert.org
6554762Snate@binkert.org        # Python starts at 1, Unix starts at 0
6564762Snate@binkert.org        c_time.tm_yday = py_time.tm_yday - 1;
6574762Snate@binkert.org
6584762Snate@binkert.org        return c_time
6594762Snate@binkert.org
6603885Sbinkertn@umich.edu    def __str__(self):
6614762Snate@binkert.org        return time.asctime(self.value)
6623885Sbinkertn@umich.edu
6633885Sbinkertn@umich.edu    def ini_str(self):
6643932Sbinkertn@umich.edu        return str(self)
6653885Sbinkertn@umich.edu
6663101Sstever@eecs.umich.edu# Enumerated types are a little more complex.  The user specifies the
6673101Sstever@eecs.umich.edu# type as Enum(foo) where foo is either a list or dictionary of
6683101Sstever@eecs.umich.edu# alternatives (typically strings, but not necessarily so).  (In the
6693101Sstever@eecs.umich.edu# long run, the integer value of the parameter will be the list index
6703101Sstever@eecs.umich.edu# or the corresponding dictionary value.  For now, since we only check
6713101Sstever@eecs.umich.edu# that the alternative is valid and then spit it into a .ini file,
6723101Sstever@eecs.umich.edu# there's not much point in using the dictionary.)
6733101Sstever@eecs.umich.edu
6743101Sstever@eecs.umich.edu# What Enum() must do is generate a new type encapsulating the
6753101Sstever@eecs.umich.edu# provided list/dictionary so that specific values of the parameter
6763101Sstever@eecs.umich.edu# can be instances of that type.  We define two hidden internal
6773101Sstever@eecs.umich.edu# classes (_ListEnum and _DictEnum) to serve as base classes, then
6783101Sstever@eecs.umich.edu# derive the new type from the appropriate base class on the fly.
6793101Sstever@eecs.umich.edu
6804762Snate@binkert.orgallEnums = {}
6813101Sstever@eecs.umich.edu# Metaclass for Enum types
6825033Smilesck@eecs.umich.educlass MetaEnum(MetaParamValue):
6834762Snate@binkert.org    def __new__(mcls, name, bases, dict):
6844762Snate@binkert.org        assert name not in allEnums
6854762Snate@binkert.org
6864762Snate@binkert.org        cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict)
6874762Snate@binkert.org        allEnums[name] = cls
6884762Snate@binkert.org        return cls
6894762Snate@binkert.org
6903101Sstever@eecs.umich.edu    def __init__(cls, name, bases, init_dict):
6913101Sstever@eecs.umich.edu        if init_dict.has_key('map'):
6923101Sstever@eecs.umich.edu            if not isinstance(cls.map, dict):
6933101Sstever@eecs.umich.edu                raise TypeError, "Enum-derived class attribute 'map' " \
6943101Sstever@eecs.umich.edu                      "must be of type dict"
6953101Sstever@eecs.umich.edu            # build list of value strings from map
6963101Sstever@eecs.umich.edu            cls.vals = cls.map.keys()
6973101Sstever@eecs.umich.edu            cls.vals.sort()
6983101Sstever@eecs.umich.edu        elif init_dict.has_key('vals'):
6993101Sstever@eecs.umich.edu            if not isinstance(cls.vals, list):
7003101Sstever@eecs.umich.edu                raise TypeError, "Enum-derived class attribute 'vals' " \
7013101Sstever@eecs.umich.edu                      "must be of type list"
7023101Sstever@eecs.umich.edu            # build string->value map from vals sequence
7033101Sstever@eecs.umich.edu            cls.map = {}
7043101Sstever@eecs.umich.edu            for idx,val in enumerate(cls.vals):
7053101Sstever@eecs.umich.edu                cls.map[val] = idx
7063101Sstever@eecs.umich.edu        else:
7073101Sstever@eecs.umich.edu            raise TypeError, "Enum-derived class must define "\
7083101Sstever@eecs.umich.edu                  "attribute 'map' or 'vals'"
7093101Sstever@eecs.umich.edu
7104762Snate@binkert.org        cls.cxx_type = 'Enums::%s' % name
7113101Sstever@eecs.umich.edu
7123101Sstever@eecs.umich.edu        super(MetaEnum, cls).__init__(name, bases, init_dict)
7133101Sstever@eecs.umich.edu
7144762Snate@binkert.org    def __str__(cls):
7154762Snate@binkert.org        return cls.__name__
7164762Snate@binkert.org
7173101Sstever@eecs.umich.edu    # Generate C++ class declaration for this enum type.
7183101Sstever@eecs.umich.edu    # Note that we wrap the enum in a class/struct to act as a namespace,
7193101Sstever@eecs.umich.edu    # so that the enum strings can be brief w/o worrying about collisions.
7203101Sstever@eecs.umich.edu    def cxx_decl(cls):
7214762Snate@binkert.org        code = "#ifndef __ENUM__%s\n" % cls
7224762Snate@binkert.org        code += '#define __ENUM__%s\n' % cls
7234762Snate@binkert.org        code += '\n'
7244762Snate@binkert.org        code += 'namespace Enums {\n'
7254762Snate@binkert.org        code += '    enum %s {\n' % cls
7264762Snate@binkert.org        for val in cls.vals:
7274762Snate@binkert.org            code += '        %s = %d,\n' % (val, cls.map[val])
7284762Snate@binkert.org        code += '        Num_%s = %d,\n' % (cls, len(cls.vals))
7294762Snate@binkert.org        code += '    };\n'
7304762Snate@binkert.org        code += '    extern const char *%sStrings[Num_%s];\n' % (cls, cls)
7314762Snate@binkert.org        code += '}\n'
7324762Snate@binkert.org        code += '\n'
7334762Snate@binkert.org        code += '#endif\n'
7344762Snate@binkert.org        return code
7354762Snate@binkert.org
7364762Snate@binkert.org    def cxx_def(cls):
7374762Snate@binkert.org        code = '#include "enums/%s.hh"\n' % cls
7384762Snate@binkert.org        code += 'namespace Enums {\n'
7394762Snate@binkert.org        code += '    const char *%sStrings[Num_%s] =\n' % (cls, cls)
7404762Snate@binkert.org        code += '    {\n'
7414762Snate@binkert.org        for val in cls.vals:
7424762Snate@binkert.org            code += '        "%s",\n' % val
7434762Snate@binkert.org        code += '    };\n'
7444762Snate@binkert.org        code += '}\n'
7454762Snate@binkert.org        return code
7463101Sstever@eecs.umich.edu
7473101Sstever@eecs.umich.edu# Base class for enum types.
7483101Sstever@eecs.umich.educlass Enum(ParamValue):
7493101Sstever@eecs.umich.edu    __metaclass__ = MetaEnum
7503101Sstever@eecs.umich.edu    vals = []
7513101Sstever@eecs.umich.edu
7523101Sstever@eecs.umich.edu    def __init__(self, value):
7533101Sstever@eecs.umich.edu        if value not in self.map:
7543101Sstever@eecs.umich.edu            raise TypeError, "Enum param got bad value '%s' (not in %s)" \
7553101Sstever@eecs.umich.edu                  % (value, self.vals)
7563101Sstever@eecs.umich.edu        self.value = value
7573101Sstever@eecs.umich.edu
7584762Snate@binkert.org    def getValue(self):
7594762Snate@binkert.org        return int(self.map[self.value])
7604762Snate@binkert.org
7613101Sstever@eecs.umich.edu    def __str__(self):
7623101Sstever@eecs.umich.edu        return self.value
7633101Sstever@eecs.umich.edu
7643101Sstever@eecs.umich.edu# how big does a rounding error need to be before we warn about it?
7653101Sstever@eecs.umich.edufrequency_tolerance = 0.001  # 0.1%
7663101Sstever@eecs.umich.edu
7674167Sbinkertn@umich.educlass TickParamValue(NumericParamValue):
7683101Sstever@eecs.umich.edu    cxx_type = 'Tick'
7693101Sstever@eecs.umich.edu    cxx_predecls = ['#include "sim/host.hh"']
7704762Snate@binkert.org    swig_predecls = ['%import "stdint.i"\n' +
7713101Sstever@eecs.umich.edu                     '%import "sim/host.hh"']
7724167Sbinkertn@umich.edu
7734762Snate@binkert.org    def getValue(self):
7744762Snate@binkert.org        return long(self.value)
7754762Snate@binkert.org
7764167Sbinkertn@umich.educlass Latency(TickParamValue):
7773101Sstever@eecs.umich.edu    def __init__(self, value):
7784167Sbinkertn@umich.edu        if isinstance(value, (Latency, Clock)):
7794167Sbinkertn@umich.edu            self.ticks = value.ticks
7804167Sbinkertn@umich.edu            self.value = value.value
7814167Sbinkertn@umich.edu        elif isinstance(value, Frequency):
7824167Sbinkertn@umich.edu            self.ticks = value.ticks
7834167Sbinkertn@umich.edu            self.value = 1.0 / value.value
7844167Sbinkertn@umich.edu        elif value.endswith('t'):
7854167Sbinkertn@umich.edu            self.ticks = True
7864167Sbinkertn@umich.edu            self.value = int(value[:-1])
7874167Sbinkertn@umich.edu        else:
7884167Sbinkertn@umich.edu            self.ticks = False
7894167Sbinkertn@umich.edu            self.value = convert.toLatency(value)
7903101Sstever@eecs.umich.edu
7913101Sstever@eecs.umich.edu    def __getattr__(self, attr):
7923101Sstever@eecs.umich.edu        if attr in ('latency', 'period'):
7933101Sstever@eecs.umich.edu            return self
7943101Sstever@eecs.umich.edu        if attr == 'frequency':
7953101Sstever@eecs.umich.edu            return Frequency(self)
7963101Sstever@eecs.umich.edu        raise AttributeError, "Latency object has no attribute '%s'" % attr
7973101Sstever@eecs.umich.edu
7984762Snate@binkert.org    def getValue(self):
7994762Snate@binkert.org        if self.ticks or self.value == 0:
8004762Snate@binkert.org            value = self.value
8014762Snate@binkert.org        else:
8024762Snate@binkert.org            value = ticks.fromSeconds(self.value)
8034762Snate@binkert.org        return long(value)
8044762Snate@binkert.org
8053101Sstever@eecs.umich.edu    # convert latency to ticks
8063101Sstever@eecs.umich.edu    def ini_str(self):
8074762Snate@binkert.org        return '%d' % self.getValue()
8083101Sstever@eecs.umich.edu
8094167Sbinkertn@umich.educlass Frequency(TickParamValue):
8103101Sstever@eecs.umich.edu    def __init__(self, value):
8114167Sbinkertn@umich.edu        if isinstance(value, (Latency, Clock)):
8124167Sbinkertn@umich.edu            if value.value == 0:
8134167Sbinkertn@umich.edu                self.value = 0
8144167Sbinkertn@umich.edu            else:
8154167Sbinkertn@umich.edu                self.value = 1.0 / value.value
8164167Sbinkertn@umich.edu            self.ticks = value.ticks
8174167Sbinkertn@umich.edu        elif isinstance(value, Frequency):
8184167Sbinkertn@umich.edu            self.value = value.value
8194167Sbinkertn@umich.edu            self.ticks = value.ticks
8204167Sbinkertn@umich.edu        else:
8214167Sbinkertn@umich.edu            self.ticks = False
8224167Sbinkertn@umich.edu            self.value = convert.toFrequency(value)
8233101Sstever@eecs.umich.edu
8243101Sstever@eecs.umich.edu    def __getattr__(self, attr):
8253101Sstever@eecs.umich.edu        if attr == 'frequency':
8263101Sstever@eecs.umich.edu            return self
8273101Sstever@eecs.umich.edu        if attr in ('latency', 'period'):
8283101Sstever@eecs.umich.edu            return Latency(self)
8293101Sstever@eecs.umich.edu        raise AttributeError, "Frequency object has no attribute '%s'" % attr
8303101Sstever@eecs.umich.edu
8314167Sbinkertn@umich.edu    # convert latency to ticks
8324762Snate@binkert.org    def getValue(self):
8334762Snate@binkert.org        if self.ticks or self.value == 0:
8344762Snate@binkert.org            value = self.value
8354762Snate@binkert.org        else:
8364762Snate@binkert.org            value = ticks.fromSeconds(1.0 / self.value)
8374762Snate@binkert.org        return long(value)
8384762Snate@binkert.org
8393101Sstever@eecs.umich.edu    def ini_str(self):
8404762Snate@binkert.org        return '%d' % self.getValue()
8413101Sstever@eecs.umich.edu
8423101Sstever@eecs.umich.edu# A generic frequency and/or Latency value.  Value is stored as a latency,
8433101Sstever@eecs.umich.edu# but to avoid ambiguity this object does not support numeric ops (* or /).
8443101Sstever@eecs.umich.edu# An explicit conversion to a Latency or Frequency must be made first.
8453101Sstever@eecs.umich.educlass Clock(ParamValue):
8463101Sstever@eecs.umich.edu    cxx_type = 'Tick'
8473101Sstever@eecs.umich.edu    cxx_predecls = ['#include "sim/host.hh"']
8484762Snate@binkert.org    swig_predecls = ['%import "stdint.i"\n' +
8493101Sstever@eecs.umich.edu                     '%import "sim/host.hh"']
8503101Sstever@eecs.umich.edu    def __init__(self, value):
8514167Sbinkertn@umich.edu        if isinstance(value, (Latency, Clock)):
8524167Sbinkertn@umich.edu            self.ticks = value.ticks
8534167Sbinkertn@umich.edu            self.value = value.value
8544167Sbinkertn@umich.edu        elif isinstance(value, Frequency):
8554167Sbinkertn@umich.edu            self.ticks = value.ticks
8564167Sbinkertn@umich.edu            self.value = 1.0 / value.value
8574167Sbinkertn@umich.edu        elif value.endswith('t'):
8584167Sbinkertn@umich.edu            self.ticks = True
8594167Sbinkertn@umich.edu            self.value = int(value[:-1])
8604167Sbinkertn@umich.edu        else:
8614167Sbinkertn@umich.edu            self.ticks = False
8624167Sbinkertn@umich.edu            self.value = convert.anyToLatency(value)
8633101Sstever@eecs.umich.edu
8643101Sstever@eecs.umich.edu    def __getattr__(self, attr):
8653101Sstever@eecs.umich.edu        if attr == 'frequency':
8663101Sstever@eecs.umich.edu            return Frequency(self)
8673101Sstever@eecs.umich.edu        if attr in ('latency', 'period'):
8683101Sstever@eecs.umich.edu            return Latency(self)
8693101Sstever@eecs.umich.edu        raise AttributeError, "Frequency object has no attribute '%s'" % attr
8703101Sstever@eecs.umich.edu
8714762Snate@binkert.org    def getValue(self):
8724762Snate@binkert.org        return self.period.getValue()
8734762Snate@binkert.org
8743101Sstever@eecs.umich.edu    def ini_str(self):
8753101Sstever@eecs.umich.edu        return self.period.ini_str()
8763101Sstever@eecs.umich.edu
8773101Sstever@eecs.umich.educlass NetworkBandwidth(float,ParamValue):
8783101Sstever@eecs.umich.edu    cxx_type = 'float'
8793101Sstever@eecs.umich.edu    def __new__(cls, value):
8804167Sbinkertn@umich.edu        # convert to bits per second
8814167Sbinkertn@umich.edu        val = convert.toNetworkBandwidth(value)
8823101Sstever@eecs.umich.edu        return super(cls, NetworkBandwidth).__new__(cls, val)
8833101Sstever@eecs.umich.edu
8843101Sstever@eecs.umich.edu    def __str__(self):
8853101Sstever@eecs.umich.edu        return str(self.val)
8863101Sstever@eecs.umich.edu
8874762Snate@binkert.org    def getValue(self):
8884167Sbinkertn@umich.edu        # convert to seconds per byte
8894167Sbinkertn@umich.edu        value = 8.0 / float(self)
8904167Sbinkertn@umich.edu        # convert to ticks per byte
8914762Snate@binkert.org        value = ticks.fromSeconds(value)
8924762Snate@binkert.org        return float(value)
8934762Snate@binkert.org
8944762Snate@binkert.org    def ini_str(self):
8954762Snate@binkert.org        return '%f' % self.getValue()
8963101Sstever@eecs.umich.edu
8973101Sstever@eecs.umich.educlass MemoryBandwidth(float,ParamValue):
8983101Sstever@eecs.umich.edu    cxx_type = 'float'
8995469Snate@binkert.org    def __new__(cls, value):
9004167Sbinkertn@umich.edu        # we want the number of ticks per byte of data
9013102Sstever@eecs.umich.edu        val = convert.toMemoryBandwidth(value)
9023101Sstever@eecs.umich.edu        return super(cls, MemoryBandwidth).__new__(cls, val)
9033101Sstever@eecs.umich.edu
9043101Sstever@eecs.umich.edu    def __str__(self):
9053101Sstever@eecs.umich.edu        return str(self.val)
9063101Sstever@eecs.umich.edu
9074762Snate@binkert.org    def getValue(self):
9084167Sbinkertn@umich.edu        # convert to seconds per byte
9095468Snate@binkert.org        value = float(self)
9105468Snate@binkert.org        if value:
9115468Snate@binkert.org            value = 1.0 / float(self)
9124167Sbinkertn@umich.edu        # convert to ticks per byte
9134762Snate@binkert.org        value = ticks.fromSeconds(value)
9144762Snate@binkert.org        return float(value)
9154762Snate@binkert.org
9164762Snate@binkert.org    def ini_str(self):
9174762Snate@binkert.org        return '%f' % self.getValue()
9183101Sstever@eecs.umich.edu
9193101Sstever@eecs.umich.edu#
9203101Sstever@eecs.umich.edu# "Constants"... handy aliases for various values.
9213101Sstever@eecs.umich.edu#
9223101Sstever@eecs.umich.edu
9233102Sstever@eecs.umich.edu# Special class for NULL pointers.  Note the special check in
9243102Sstever@eecs.umich.edu# make_param_value() above that lets these be assigned where a
9253102Sstever@eecs.umich.edu# SimObject is required.
9263102Sstever@eecs.umich.edu# only one copy of a particular node
9273102Sstever@eecs.umich.educlass NullSimObject(object):
9283102Sstever@eecs.umich.edu    __metaclass__ = Singleton
9293102Sstever@eecs.umich.edu
9303102Sstever@eecs.umich.edu    def __call__(cls):
9313102Sstever@eecs.umich.edu        return cls
9323102Sstever@eecs.umich.edu
9333102Sstever@eecs.umich.edu    def _instantiate(self, parent = None, path = ''):
9343102Sstever@eecs.umich.edu        pass
9353102Sstever@eecs.umich.edu
9363102Sstever@eecs.umich.edu    def ini_str(self):
9373102Sstever@eecs.umich.edu        return 'Null'
9383102Sstever@eecs.umich.edu
9393102Sstever@eecs.umich.edu    def unproxy(self, base):
9403102Sstever@eecs.umich.edu        return self
9413102Sstever@eecs.umich.edu
9423102Sstever@eecs.umich.edu    def set_path(self, parent, name):
9433102Sstever@eecs.umich.edu        pass
9444762Snate@binkert.org
9453102Sstever@eecs.umich.edu    def __str__(self):
9463102Sstever@eecs.umich.edu        return 'Null'
9473102Sstever@eecs.umich.edu
9484762Snate@binkert.org    def getValue(self):
9494762Snate@binkert.org        return None
9504762Snate@binkert.org
9513102Sstever@eecs.umich.edu# The only instance you'll ever need...
9523102Sstever@eecs.umich.eduNULL = NullSimObject()
9533102Sstever@eecs.umich.edu
9543102Sstever@eecs.umich.edudef isNullPointer(value):
9553102Sstever@eecs.umich.edu    return isinstance(value, NullSimObject)
9563102Sstever@eecs.umich.edu
9573101Sstever@eecs.umich.edu# Some memory range specifications use this as a default upper bound.
9583101Sstever@eecs.umich.eduMaxAddr = Addr.max
9593101Sstever@eecs.umich.eduMaxTick = Tick.max
9603101Sstever@eecs.umich.eduAllMemory = AddrRange(0, MaxAddr)
9613101Sstever@eecs.umich.edu
9623101Sstever@eecs.umich.edu
9633101Sstever@eecs.umich.edu#####################################################################
9643101Sstever@eecs.umich.edu#
9653101Sstever@eecs.umich.edu# Port objects
9663101Sstever@eecs.umich.edu#
9673101Sstever@eecs.umich.edu# Ports are used to interconnect objects in the memory system.
9683101Sstever@eecs.umich.edu#
9693101Sstever@eecs.umich.edu#####################################################################
9703101Sstever@eecs.umich.edu
9713101Sstever@eecs.umich.edu# Port reference: encapsulates a reference to a particular port on a
9723101Sstever@eecs.umich.edu# particular SimObject.
9733101Sstever@eecs.umich.educlass PortRef(object):
9743105Sstever@eecs.umich.edu    def __init__(self, simobj, name):
9753105Sstever@eecs.umich.edu        assert(isSimObject(simobj) or isSimObjectClass(simobj))
9763101Sstever@eecs.umich.edu        self.simobj = simobj
9773101Sstever@eecs.umich.edu        self.name = name
9783101Sstever@eecs.umich.edu        self.peer = None   # not associated with another port yet
9793101Sstever@eecs.umich.edu        self.ccConnected = False # C++ port connection done?
9803105Sstever@eecs.umich.edu        self.index = -1  # always -1 for non-vector ports
9813101Sstever@eecs.umich.edu
9823103Sstever@eecs.umich.edu    def __str__(self):
9833105Sstever@eecs.umich.edu        return '%s.%s' % (self.simobj, self.name)
9843103Sstever@eecs.umich.edu
9853105Sstever@eecs.umich.edu    # for config.ini, print peer's name (not ours)
9863105Sstever@eecs.umich.edu    def ini_str(self):
9873105Sstever@eecs.umich.edu        return str(self.peer)
9883105Sstever@eecs.umich.edu
9893105Sstever@eecs.umich.edu    def __getattr__(self, attr):
9903105Sstever@eecs.umich.edu        if attr == 'peerObj':
9913105Sstever@eecs.umich.edu            # shorthand for proxies
9923105Sstever@eecs.umich.edu            return self.peer.simobj
9933105Sstever@eecs.umich.edu        raise AttributeError, "'%s' object has no attribute '%s'" % \
9943105Sstever@eecs.umich.edu              (self.__class__.__name__, attr)
9953105Sstever@eecs.umich.edu
9963105Sstever@eecs.umich.edu    # Full connection is symmetric (both ways).  Called via
9973105Sstever@eecs.umich.edu    # SimObject.__setattr__ as a result of a port assignment, e.g.,
9983109Sstever@eecs.umich.edu    # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
9993105Sstever@eecs.umich.edu    # e.g., "obj1.portA[3] = obj2.portB".
10003105Sstever@eecs.umich.edu    def connect(self, other):
10013105Sstever@eecs.umich.edu        if isinstance(other, VectorPortRef):
10023105Sstever@eecs.umich.edu            # reference to plain VectorPort is implicit append
10033105Sstever@eecs.umich.edu            other = other._get_next()
10043105Sstever@eecs.umich.edu        if self.peer and not proxy.isproxy(self.peer):
10053105Sstever@eecs.umich.edu            print "warning: overwriting port", self, \
10063105Sstever@eecs.umich.edu                  "value", self.peer, "with", other
10073101Sstever@eecs.umich.edu        self.peer = other
10083109Sstever@eecs.umich.edu        if proxy.isproxy(other):
10093109Sstever@eecs.umich.edu            other.set_param_desc(PortParamDesc())
10103109Sstever@eecs.umich.edu        elif isinstance(other, PortRef):
10113109Sstever@eecs.umich.edu            if other.peer is not self:
10123109Sstever@eecs.umich.edu                other.connect(self)
10133109Sstever@eecs.umich.edu        else:
10143109Sstever@eecs.umich.edu            raise TypeError, \
10153109Sstever@eecs.umich.edu                  "assigning non-port reference '%s' to port '%s'" \
10163109Sstever@eecs.umich.edu                  % (other, self)
10173101Sstever@eecs.umich.edu
10183105Sstever@eecs.umich.edu    def clone(self, simobj, memo):
10193105Sstever@eecs.umich.edu        if memo.has_key(self):
10203105Sstever@eecs.umich.edu            return memo[self]
10213101Sstever@eecs.umich.edu        newRef = copy.copy(self)
10223105Sstever@eecs.umich.edu        memo[self] = newRef
10233105Sstever@eecs.umich.edu        newRef.simobj = simobj
10243101Sstever@eecs.umich.edu        assert(isSimObject(newRef.simobj))
10253105Sstever@eecs.umich.edu        if self.peer and not proxy.isproxy(self.peer):
10263179Sstever@eecs.umich.edu            peerObj = self.peer.simobj(_memo=memo)
10273105Sstever@eecs.umich.edu            newRef.peer = self.peer.clone(peerObj, memo)
10283105Sstever@eecs.umich.edu            assert(not isinstance(newRef.peer, VectorPortRef))
10293101Sstever@eecs.umich.edu        return newRef
10303101Sstever@eecs.umich.edu
10313105Sstever@eecs.umich.edu    def unproxy(self, simobj):
10323105Sstever@eecs.umich.edu        assert(simobj is self.simobj)
10333105Sstever@eecs.umich.edu        if proxy.isproxy(self.peer):
10343105Sstever@eecs.umich.edu            try:
10353105Sstever@eecs.umich.edu                realPeer = self.peer.unproxy(self.simobj)
10363105Sstever@eecs.umich.edu            except:
10373105Sstever@eecs.umich.edu                print "Error in unproxying port '%s' of %s" % \
10383105Sstever@eecs.umich.edu                      (self.name, self.simobj.path())
10393105Sstever@eecs.umich.edu                raise
10403105Sstever@eecs.umich.edu            self.connect(realPeer)
10413105Sstever@eecs.umich.edu
10423101Sstever@eecs.umich.edu    # Call C++ to create corresponding port connection between C++ objects
10433101Sstever@eecs.umich.edu    def ccConnect(self):
10444859Snate@binkert.org        from m5.objects.params import connectPorts
10454762Snate@binkert.org
10463101Sstever@eecs.umich.edu        if self.ccConnected: # already done this
10473101Sstever@eecs.umich.edu            return
10483101Sstever@eecs.umich.edu        peer = self.peer
10494859Snate@binkert.org        connectPorts(self.simobj.getCCObject(), self.name, self.index,
10504859Snate@binkert.org                     peer.simobj.getCCObject(), peer.name, peer.index)
10513101Sstever@eecs.umich.edu        self.ccConnected = True
10523101Sstever@eecs.umich.edu        peer.ccConnected = True
10533101Sstever@eecs.umich.edu
10543105Sstever@eecs.umich.edu# A reference to an individual element of a VectorPort... much like a
10553105Sstever@eecs.umich.edu# PortRef, but has an index.
10563105Sstever@eecs.umich.educlass VectorPortElementRef(PortRef):
10573105Sstever@eecs.umich.edu    def __init__(self, simobj, name, index):
10583105Sstever@eecs.umich.edu        PortRef.__init__(self, simobj, name)
10593105Sstever@eecs.umich.edu        self.index = index
10603105Sstever@eecs.umich.edu
10613105Sstever@eecs.umich.edu    def __str__(self):
10623105Sstever@eecs.umich.edu        return '%s.%s[%d]' % (self.simobj, self.name, self.index)
10633105Sstever@eecs.umich.edu
10643105Sstever@eecs.umich.edu# A reference to a complete vector-valued port (not just a single element).
10653105Sstever@eecs.umich.edu# Can be indexed to retrieve individual VectorPortElementRef instances.
10663105Sstever@eecs.umich.educlass VectorPortRef(object):
10673105Sstever@eecs.umich.edu    def __init__(self, simobj, name):
10683105Sstever@eecs.umich.edu        assert(isSimObject(simobj) or isSimObjectClass(simobj))
10693105Sstever@eecs.umich.edu        self.simobj = simobj
10703105Sstever@eecs.umich.edu        self.name = name
10713105Sstever@eecs.umich.edu        self.elements = []
10723105Sstever@eecs.umich.edu
10733109Sstever@eecs.umich.edu    def __str__(self):
10743109Sstever@eecs.umich.edu        return '%s.%s[:]' % (self.simobj, self.name)
10753109Sstever@eecs.umich.edu
10763105Sstever@eecs.umich.edu    # for config.ini, print peer's name (not ours)
10773105Sstever@eecs.umich.edu    def ini_str(self):
10783105Sstever@eecs.umich.edu        return ' '.join([el.ini_str() for el in self.elements])
10793105Sstever@eecs.umich.edu
10803105Sstever@eecs.umich.edu    def __getitem__(self, key):
10813105Sstever@eecs.umich.edu        if not isinstance(key, int):
10823105Sstever@eecs.umich.edu            raise TypeError, "VectorPort index must be integer"
10833105Sstever@eecs.umich.edu        if key >= len(self.elements):
10843105Sstever@eecs.umich.edu            # need to extend list
10853105Sstever@eecs.umich.edu            ext = [VectorPortElementRef(self.simobj, self.name, i)
10863105Sstever@eecs.umich.edu                   for i in range(len(self.elements), key+1)]
10873105Sstever@eecs.umich.edu            self.elements.extend(ext)
10883105Sstever@eecs.umich.edu        return self.elements[key]
10893105Sstever@eecs.umich.edu
10903105Sstever@eecs.umich.edu    def _get_next(self):
10913105Sstever@eecs.umich.edu        return self[len(self.elements)]
10923105Sstever@eecs.umich.edu
10933105Sstever@eecs.umich.edu    def __setitem__(self, key, value):
10943105Sstever@eecs.umich.edu        if not isinstance(key, int):
10953105Sstever@eecs.umich.edu            raise TypeError, "VectorPort index must be integer"
10963105Sstever@eecs.umich.edu        self[key].connect(value)
10973105Sstever@eecs.umich.edu
10983105Sstever@eecs.umich.edu    def connect(self, other):
10993109Sstever@eecs.umich.edu        if isinstance(other, (list, tuple)):
11003109Sstever@eecs.umich.edu            # Assign list of port refs to vector port.
11013109Sstever@eecs.umich.edu            # For now, append them... not sure if that's the right semantics
11023109Sstever@eecs.umich.edu            # or if it should replace the current vector.
11033109Sstever@eecs.umich.edu            for ref in other:
11043109Sstever@eecs.umich.edu                self._get_next().connect(ref)
11053109Sstever@eecs.umich.edu        else:
11063109Sstever@eecs.umich.edu            # scalar assignment to plain VectorPort is implicit append
11073109Sstever@eecs.umich.edu            self._get_next().connect(other)
11083109Sstever@eecs.umich.edu
11093109Sstever@eecs.umich.edu    def clone(self, simobj, memo):
11103109Sstever@eecs.umich.edu        if memo.has_key(self):
11113109Sstever@eecs.umich.edu            return memo[self]
11123109Sstever@eecs.umich.edu        newRef = copy.copy(self)
11133109Sstever@eecs.umich.edu        memo[self] = newRef
11143109Sstever@eecs.umich.edu        newRef.simobj = simobj
11153109Sstever@eecs.umich.edu        assert(isSimObject(newRef.simobj))
11163109Sstever@eecs.umich.edu        newRef.elements = [el.clone(simobj, memo) for el in self.elements]
11173109Sstever@eecs.umich.edu        return newRef
11183105Sstever@eecs.umich.edu
11193105Sstever@eecs.umich.edu    def unproxy(self, simobj):
11203105Sstever@eecs.umich.edu        [el.unproxy(simobj) for el in self.elements]
11213105Sstever@eecs.umich.edu
11223105Sstever@eecs.umich.edu    def ccConnect(self):
11233105Sstever@eecs.umich.edu        [el.ccConnect() for el in self.elements]
11243105Sstever@eecs.umich.edu
11253101Sstever@eecs.umich.edu# Port description object.  Like a ParamDesc object, this represents a
11263101Sstever@eecs.umich.edu# logical port in the SimObject class, not a particular port on a
11273101Sstever@eecs.umich.edu# SimObject instance.  The latter are represented by PortRef objects.
11283101Sstever@eecs.umich.educlass Port(object):
11293105Sstever@eecs.umich.edu    # Port("description") or Port(default, "description")
11303105Sstever@eecs.umich.edu    def __init__(self, *args):
11313105Sstever@eecs.umich.edu        if len(args) == 1:
11323105Sstever@eecs.umich.edu            self.desc = args[0]
11333105Sstever@eecs.umich.edu        elif len(args) == 2:
11343105Sstever@eecs.umich.edu            self.default = args[0]
11353105Sstever@eecs.umich.edu            self.desc = args[1]
11363105Sstever@eecs.umich.edu        else:
11373105Sstever@eecs.umich.edu            raise TypeError, 'wrong number of arguments'
11383105Sstever@eecs.umich.edu        # self.name is set by SimObject class on assignment
11393105Sstever@eecs.umich.edu        # e.g., pio_port = Port("blah") sets self.name to 'pio_port'
11403101Sstever@eecs.umich.edu
11413101Sstever@eecs.umich.edu    # Generate a PortRef for this port on the given SimObject with the
11423101Sstever@eecs.umich.edu    # given name
11433105Sstever@eecs.umich.edu    def makeRef(self, simobj):
11443105Sstever@eecs.umich.edu        return PortRef(simobj, self.name)
11453101Sstever@eecs.umich.edu
11463101Sstever@eecs.umich.edu    # Connect an instance of this port (on the given SimObject with
11473101Sstever@eecs.umich.edu    # the given name) with the port described by the supplied PortRef
11483105Sstever@eecs.umich.edu    def connect(self, simobj, ref):
11493105Sstever@eecs.umich.edu        self.makeRef(simobj).connect(ref)
11503101Sstever@eecs.umich.edu
11513101Sstever@eecs.umich.edu# VectorPort description object.  Like Port, but represents a vector
11523101Sstever@eecs.umich.edu# of connections (e.g., as on a Bus).
11533101Sstever@eecs.umich.educlass VectorPort(Port):
11543105Sstever@eecs.umich.edu    def __init__(self, *args):
11553105Sstever@eecs.umich.edu        Port.__init__(self, *args)
11563101Sstever@eecs.umich.edu        self.isVec = True
11573101Sstever@eecs.umich.edu
11583105Sstever@eecs.umich.edu    def makeRef(self, simobj):
11593105Sstever@eecs.umich.edu        return VectorPortRef(simobj, self.name)
11603105Sstever@eecs.umich.edu
11613109Sstever@eecs.umich.edu# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
11623109Sstever@eecs.umich.edu# proxy objects (via set_param_desc()) so that proxy error messages
11633109Sstever@eecs.umich.edu# make sense.
11643109Sstever@eecs.umich.educlass PortParamDesc(object):
11653109Sstever@eecs.umich.edu    __metaclass__ = Singleton
11663109Sstever@eecs.umich.edu
11673109Sstever@eecs.umich.edu    ptype_str = 'Port'
11683109Sstever@eecs.umich.edu    ptype = Port
11693105Sstever@eecs.umich.edu
11703101Sstever@eecs.umich.edu__all__ = ['Param', 'VectorParam',
11713101Sstever@eecs.umich.edu           'Enum', 'Bool', 'String', 'Float',
11723101Sstever@eecs.umich.edu           'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
11733101Sstever@eecs.umich.edu           'Int32', 'UInt32', 'Int64', 'UInt64',
11743101Sstever@eecs.umich.edu           'Counter', 'Addr', 'Tick', 'Percent',
11753101Sstever@eecs.umich.edu           'TcpPort', 'UdpPort', 'EthernetAddr',
11763101Sstever@eecs.umich.edu           'MemorySize', 'MemorySize32',
11774167Sbinkertn@umich.edu           'Latency', 'Frequency', 'Clock',
11783101Sstever@eecs.umich.edu           'NetworkBandwidth', 'MemoryBandwidth',
11793101Sstever@eecs.umich.edu           'Range', 'AddrRange', 'TickRange',
11803101Sstever@eecs.umich.edu           'MaxAddr', 'MaxTick', 'AllMemory',
11813885Sbinkertn@umich.edu           'Time',
11823102Sstever@eecs.umich.edu           'NextEthernetAddr', 'NULL',
11833101Sstever@eecs.umich.edu           'Port', 'VectorPort']
1184