params.py revision 3102
15331Sgblack@eecs.umich.edu# Copyright (c) 2004-2006 The Regents of The University of Michigan
25331Sgblack@eecs.umich.edu# All rights reserved.
35331Sgblack@eecs.umich.edu#
45331Sgblack@eecs.umich.edu# Redistribution and use in source and binary forms, with or without
55331Sgblack@eecs.umich.edu# modification, are permitted provided that the following conditions are
65331Sgblack@eecs.umich.edu# met: redistributions of source code must retain the above copyright
75331Sgblack@eecs.umich.edu# notice, this list of conditions and the following disclaimer;
85331Sgblack@eecs.umich.edu# redistributions in binary form must reproduce the above copyright
95331Sgblack@eecs.umich.edu# notice, this list of conditions and the following disclaimer in the
105331Sgblack@eecs.umich.edu# documentation and/or other materials provided with the distribution;
115331Sgblack@eecs.umich.edu# neither the name of the copyright holders nor the names of its
125331Sgblack@eecs.umich.edu# contributors may be used to endorse or promote products derived from
135331Sgblack@eecs.umich.edu# this software without specific prior written permission.
145331Sgblack@eecs.umich.edu#
155331Sgblack@eecs.umich.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
165331Sgblack@eecs.umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
175331Sgblack@eecs.umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
185331Sgblack@eecs.umich.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
195331Sgblack@eecs.umich.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
205331Sgblack@eecs.umich.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
215331Sgblack@eecs.umich.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
225331Sgblack@eecs.umich.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
235331Sgblack@eecs.umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
245331Sgblack@eecs.umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
255331Sgblack@eecs.umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
265331Sgblack@eecs.umich.edu#
275331Sgblack@eecs.umich.edu# Authors: Steve Reinhardt
285331Sgblack@eecs.umich.edu#          Nathan Binkert
295331Sgblack@eecs.umich.edu
304276Sgblack@eecs.umich.edu#####################################################################
314276Sgblack@eecs.umich.edu#
324276Sgblack@eecs.umich.edu# Parameter description classes
334276Sgblack@eecs.umich.edu#
344276Sgblack@eecs.umich.edu# The _params dictionary in each class maps parameter names to either
354276Sgblack@eecs.umich.edu# a Param or a VectorParam object.  These objects contain the
364276Sgblack@eecs.umich.edu# parameter description string, the parameter type, and the default
374276Sgblack@eecs.umich.edu# value (if any).  The convert() method on these objects is used to
384276Sgblack@eecs.umich.edu# force whatever value is assigned to the parameter to the appropriate
394276Sgblack@eecs.umich.edu# type.
404276Sgblack@eecs.umich.edu#
414276Sgblack@eecs.umich.edu# Note that the default values are loaded into the class's attribute
424276Sgblack@eecs.umich.edu# space when the parameter dictionary is initialized (in
434276Sgblack@eecs.umich.edu# MetaSimObject._new_param()); after that point they aren't used.
444276Sgblack@eecs.umich.edu#
454276Sgblack@eecs.umich.edu#####################################################################
464276Sgblack@eecs.umich.edu
474276Sgblack@eecs.umich.eduimport sys, inspect, copy
484276Sgblack@eecs.umich.eduimport convert
494276Sgblack@eecs.umich.edufrom util import *
504276Sgblack@eecs.umich.edu
514276Sgblack@eecs.umich.edu# Dummy base class to identify types that are legitimate for SimObject
524276Sgblack@eecs.umich.edu# parameters.
534276Sgblack@eecs.umich.educlass ParamValue(object):
544276Sgblack@eecs.umich.edu
554276Sgblack@eecs.umich.edu    cxx_predecls = []
564276Sgblack@eecs.umich.edu    swig_predecls = []
574276Sgblack@eecs.umich.edu
584276Sgblack@eecs.umich.edu    # default for printing to .ini file is regular string conversion.
594276Sgblack@eecs.umich.edu    # will be overridden in some cases
604276Sgblack@eecs.umich.edu    def ini_str(self):
614276Sgblack@eecs.umich.edu        return str(self)
624276Sgblack@eecs.umich.edu
634276Sgblack@eecs.umich.edu    # allows us to blithely call unproxy() on things without checking
644276Sgblack@eecs.umich.edu    # if they're really proxies or not
654276Sgblack@eecs.umich.edu    def unproxy(self, base):
664276Sgblack@eecs.umich.edu        return self
674276Sgblack@eecs.umich.edu
684276Sgblack@eecs.umich.edu# Regular parameter description.
694276Sgblack@eecs.umich.educlass ParamDesc(object):
704276Sgblack@eecs.umich.edu    def __init__(self, ptype_str, ptype, *args, **kwargs):
714276Sgblack@eecs.umich.edu        self.ptype_str = ptype_str
724276Sgblack@eecs.umich.edu        # remember ptype only if it is provided
734276Sgblack@eecs.umich.edu        if ptype != None:
744276Sgblack@eecs.umich.edu            self.ptype = ptype
754276Sgblack@eecs.umich.edu
764276Sgblack@eecs.umich.edu        if args:
774276Sgblack@eecs.umich.edu            if len(args) == 1:
784276Sgblack@eecs.umich.edu                self.desc = args[0]
794276Sgblack@eecs.umich.edu            elif len(args) == 2:
804276Sgblack@eecs.umich.edu                self.default = args[0]
814276Sgblack@eecs.umich.edu                self.desc = args[1]
824276Sgblack@eecs.umich.edu            else:
834276Sgblack@eecs.umich.edu                raise TypeError, 'too many arguments'
844276Sgblack@eecs.umich.edu
854276Sgblack@eecs.umich.edu        if kwargs.has_key('desc'):
864276Sgblack@eecs.umich.edu            assert(not hasattr(self, 'desc'))
874276Sgblack@eecs.umich.edu            self.desc = kwargs['desc']
884276Sgblack@eecs.umich.edu            del kwargs['desc']
894711Sgblack@eecs.umich.edu
904276Sgblack@eecs.umich.edu        if kwargs.has_key('default'):
914276Sgblack@eecs.umich.edu            assert(not hasattr(self, 'default'))
925238Sgblack@eecs.umich.edu            self.default = kwargs['default']
935238Sgblack@eecs.umich.edu            del kwargs['default']
945238Sgblack@eecs.umich.edu
955238Sgblack@eecs.umich.edu        if kwargs:
965238Sgblack@eecs.umich.edu            raise TypeError, 'extra unknown kwargs %s' % kwargs
975238Sgblack@eecs.umich.edu
985238Sgblack@eecs.umich.edu        if not hasattr(self, 'desc'):
995238Sgblack@eecs.umich.edu            raise TypeError, 'desc attribute missing'
1005238Sgblack@eecs.umich.edu
1015238Sgblack@eecs.umich.edu    def __getattr__(self, attr):
1025238Sgblack@eecs.umich.edu        if attr == 'ptype':
1035238Sgblack@eecs.umich.edu            try:
1045238Sgblack@eecs.umich.edu                ptype = eval(self.ptype_str, objects.__dict__)
1055238Sgblack@eecs.umich.edu                if not isinstance(ptype, type):
1065238Sgblack@eecs.umich.edu                    raise NameError
1075238Sgblack@eecs.umich.edu                self.ptype = ptype
1085238Sgblack@eecs.umich.edu                return ptype
1095238Sgblack@eecs.umich.edu            except NameError:
1105238Sgblack@eecs.umich.edu                raise TypeError, \
1115238Sgblack@eecs.umich.edu                      "Param qualifier '%s' is not a type" % self.ptype_str
1125238Sgblack@eecs.umich.edu        raise AttributeError, "'%s' object has no attribute '%s'" % \
1135238Sgblack@eecs.umich.edu              (type(self).__name__, attr)
1145238Sgblack@eecs.umich.edu
1155238Sgblack@eecs.umich.edu    def convert(self, value):
1165238Sgblack@eecs.umich.edu        if isinstance(value, proxy.BaseProxy):
1175238Sgblack@eecs.umich.edu            value.set_param_desc(self)
1185238Sgblack@eecs.umich.edu            return value
1195238Sgblack@eecs.umich.edu        if not hasattr(self, 'ptype') and isNullPointer(value):
1205238Sgblack@eecs.umich.edu            # deferred evaluation of SimObject; continue to defer if
1215238Sgblack@eecs.umich.edu            # we're just assigning a null pointer
1225238Sgblack@eecs.umich.edu            return value
1235238Sgblack@eecs.umich.edu        if isinstance(value, self.ptype):
1245238Sgblack@eecs.umich.edu            return value
1255238Sgblack@eecs.umich.edu        if isNullPointer(value) and isSimObjectClass(self.ptype):
1265238Sgblack@eecs.umich.edu            return value
1275238Sgblack@eecs.umich.edu        return self.ptype(value)
1285238Sgblack@eecs.umich.edu
1295238Sgblack@eecs.umich.edu    def cxx_predecls(self):
1305238Sgblack@eecs.umich.edu        return self.ptype.cxx_predecls
1315683Sgblack@eecs.umich.edu
1325238Sgblack@eecs.umich.edu    def swig_predecls(self):
1335238Sgblack@eecs.umich.edu        return self.ptype.swig_predecls
1345238Sgblack@eecs.umich.edu
1355238Sgblack@eecs.umich.edu    def cxx_decl(self):
1365238Sgblack@eecs.umich.edu        return '%s %s;' % (self.ptype.cxx_type, self.name)
1375238Sgblack@eecs.umich.edu
1385238Sgblack@eecs.umich.edu# Vector-valued parameter description.  Just like ParamDesc, except
1395238Sgblack@eecs.umich.edu# that the value is a vector (list) of the specified type instead of a
1405291Sgblack@eecs.umich.edu# single value.
1415291Sgblack@eecs.umich.edu
1425291Sgblack@eecs.umich.educlass VectorParamValue(list):
1435291Sgblack@eecs.umich.edu    def ini_str(self):
1445291Sgblack@eecs.umich.edu        return ' '.join([v.ini_str() for v in self])
1455291Sgblack@eecs.umich.edu
1465291Sgblack@eecs.umich.edu    def unproxy(self, base):
1475291Sgblack@eecs.umich.edu        return [v.unproxy(base) for v in self]
1485291Sgblack@eecs.umich.edu
1495292Sgblack@eecs.umich.educlass SimObjVector(VectorParamValue):
1505292Sgblack@eecs.umich.edu    def print_ini(self):
1515292Sgblack@eecs.umich.edu        for v in self:
1525292Sgblack@eecs.umich.edu            v.print_ini()
1535292Sgblack@eecs.umich.edu
1545292Sgblack@eecs.umich.educlass VectorParamDesc(ParamDesc):
1555292Sgblack@eecs.umich.edu    # Convert assigned value to appropriate type.  If the RHS is not a
1565292Sgblack@eecs.umich.edu    # list or tuple, it generates a single-element list.
1575292Sgblack@eecs.umich.edu    def convert(self, value):
1585238Sgblack@eecs.umich.edu        if isinstance(value, (list, tuple)):
1595238Sgblack@eecs.umich.edu            # list: coerce each element into new list
1605359Sgblack@eecs.umich.edu            tmp_list = [ ParamDesc.convert(self, v) for v in value ]
1615238Sgblack@eecs.umich.edu            if isSimObjectSequence(tmp_list):
1625238Sgblack@eecs.umich.edu                return SimObjVector(tmp_list)
1635238Sgblack@eecs.umich.edu            else:
1644276Sgblack@eecs.umich.edu                return VectorParamValue(tmp_list)
1654276Sgblack@eecs.umich.edu        else:
1665789Sgblack@eecs.umich.edu            # singleton: leave it be (could coerce to a single-element
1675789Sgblack@eecs.umich.edu            # list here, but for some historical reason we don't...
1685789Sgblack@eecs.umich.edu            return ParamDesc.convert(self, value)
1695789Sgblack@eecs.umich.edu
1705789Sgblack@eecs.umich.edu    def cxx_predecls(self):
1715789Sgblack@eecs.umich.edu        return ['#include <vector>'] + self.ptype.cxx_predecls
1725789Sgblack@eecs.umich.edu
1735789Sgblack@eecs.umich.edu    def swig_predecls(self):
1745789Sgblack@eecs.umich.edu        return ['%include "std_vector.i"'] + self.ptype.swig_predecls
1755789Sgblack@eecs.umich.edu
1765789Sgblack@eecs.umich.edu    def cxx_decl(self):
1775789Sgblack@eecs.umich.edu        return 'std::vector< %s > %s;' % (self.ptype.cxx_type, self.name)
1785789Sgblack@eecs.umich.edu
1795789Sgblack@eecs.umich.educlass ParamFactory(object):
1805789Sgblack@eecs.umich.edu    def __init__(self, param_desc_class, ptype_str = None):
1815789Sgblack@eecs.umich.edu        self.param_desc_class = param_desc_class
1825789Sgblack@eecs.umich.edu        self.ptype_str = ptype_str
1835789Sgblack@eecs.umich.edu
1845789Sgblack@eecs.umich.edu    def __getattr__(self, attr):
1855789Sgblack@eecs.umich.edu        if self.ptype_str:
1865789Sgblack@eecs.umich.edu            attr = self.ptype_str + '.' + attr
1875789Sgblack@eecs.umich.edu        return ParamFactory(self.param_desc_class, attr)
1885789Sgblack@eecs.umich.edu
1895789Sgblack@eecs.umich.edu    # E.g., Param.Int(5, "number of widgets")
1905789Sgblack@eecs.umich.edu    def __call__(self, *args, **kwargs):
1915789Sgblack@eecs.umich.edu        caller_frame = inspect.currentframe().f_back
1925789Sgblack@eecs.umich.edu        ptype = None
1935789Sgblack@eecs.umich.edu        try:
1945789Sgblack@eecs.umich.edu            ptype = eval(self.ptype_str,
1955789Sgblack@eecs.umich.edu                         caller_frame.f_globals, caller_frame.f_locals)
1965789Sgblack@eecs.umich.edu            if not isinstance(ptype, type):
1975789Sgblack@eecs.umich.edu                raise TypeError, \
1985789Sgblack@eecs.umich.edu                      "Param qualifier is not a type: %s" % ptype
1995789Sgblack@eecs.umich.edu        except NameError:
2005789Sgblack@eecs.umich.edu            # if name isn't defined yet, assume it's a SimObject, and
2015789Sgblack@eecs.umich.edu            # try to resolve it later
2025789Sgblack@eecs.umich.edu            pass
2035789Sgblack@eecs.umich.edu        return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs)
2045789Sgblack@eecs.umich.edu
2055789Sgblack@eecs.umich.eduParam = ParamFactory(ParamDesc)
2065789Sgblack@eecs.umich.eduVectorParam = ParamFactory(VectorParamDesc)
2075789Sgblack@eecs.umich.edu
2085789Sgblack@eecs.umich.edu#####################################################################
2095789Sgblack@eecs.umich.edu#
2105789Sgblack@eecs.umich.edu# Parameter Types
2115789Sgblack@eecs.umich.edu#
2125789Sgblack@eecs.umich.edu# Though native Python types could be used to specify parameter types
2135789Sgblack@eecs.umich.edu# (the 'ptype' field of the Param and VectorParam classes), it's more
2145789Sgblack@eecs.umich.edu# flexible to define our own set of types.  This gives us more control
2155789Sgblack@eecs.umich.edu# over how Python expressions are converted to values (via the
2165789Sgblack@eecs.umich.edu# __init__() constructor) and how these values are printed out (via
2175789Sgblack@eecs.umich.edu# the __str__() conversion method).
2185789Sgblack@eecs.umich.edu#
2195789Sgblack@eecs.umich.edu#####################################################################
2205789Sgblack@eecs.umich.edu
2215789Sgblack@eecs.umich.edu# String-valued parameter.  Just mixin the ParamValue class with the
2225789Sgblack@eecs.umich.edu# built-in str class.
2235789Sgblack@eecs.umich.educlass String(ParamValue,str):
2245789Sgblack@eecs.umich.edu    cxx_type = 'std::string'
2255789Sgblack@eecs.umich.edu    cxx_predecls = ['#include <string>']
2265789Sgblack@eecs.umich.edu    swig_predecls = ['%include "std_string.i"\n' +
2275789Sgblack@eecs.umich.edu                     '%apply const std::string& {std::string *};']
2285789Sgblack@eecs.umich.edu    pass
2295789Sgblack@eecs.umich.edu
2305789Sgblack@eecs.umich.edu# superclass for "numeric" parameter values, to emulate math
2315789Sgblack@eecs.umich.edu# operations in a type-safe way.  e.g., a Latency times an int returns
2325789Sgblack@eecs.umich.edu# a new Latency object.
2335789Sgblack@eecs.umich.educlass NumericParamValue(ParamValue):
2345789Sgblack@eecs.umich.edu    def __str__(self):
2355789Sgblack@eecs.umich.edu        return str(self.value)
2365789Sgblack@eecs.umich.edu
2375789Sgblack@eecs.umich.edu    def __float__(self):
2385789Sgblack@eecs.umich.edu        return float(self.value)
2395789Sgblack@eecs.umich.edu
2405789Sgblack@eecs.umich.edu    # hook for bounds checking
2415789Sgblack@eecs.umich.edu    def _check(self):
2425789Sgblack@eecs.umich.edu        return
2435789Sgblack@eecs.umich.edu
2445789Sgblack@eecs.umich.edu    def __mul__(self, other):
2455789Sgblack@eecs.umich.edu        newobj = self.__class__(self)
2465789Sgblack@eecs.umich.edu        newobj.value *= other
2475789Sgblack@eecs.umich.edu        newobj._check()
2485789Sgblack@eecs.umich.edu        return newobj
2495789Sgblack@eecs.umich.edu
2505789Sgblack@eecs.umich.edu    __rmul__ = __mul__
2515789Sgblack@eecs.umich.edu
2525789Sgblack@eecs.umich.edu    def __div__(self, other):
2535789Sgblack@eecs.umich.edu        newobj = self.__class__(self)
2545789Sgblack@eecs.umich.edu        newobj.value /= other
2555789Sgblack@eecs.umich.edu        newobj._check()
2564712Sgblack@eecs.umich.edu        return newobj
2574711Sgblack@eecs.umich.edu
2584712Sgblack@eecs.umich.edu    def __sub__(self, other):
2595659Sgblack@eecs.umich.edu        newobj = self.__class__(self)
2604712Sgblack@eecs.umich.edu        newobj.value -= other
2614276Sgblack@eecs.umich.edu        newobj._check()
2624276Sgblack@eecs.umich.edu        return newobj
2634276Sgblack@eecs.umich.edu
2644276Sgblack@eecs.umich.edu# Metaclass for bounds-checked integer parameters.  See CheckedInt.
2654276Sgblack@eecs.umich.educlass CheckedIntType(type):
2664276Sgblack@eecs.umich.edu    def __init__(cls, name, bases, dict):
2674712Sgblack@eecs.umich.edu        super(CheckedIntType, cls).__init__(name, bases, dict)
2684712Sgblack@eecs.umich.edu
2694730Sgblack@eecs.umich.edu        # CheckedInt is an abstract base class, so we actually don't
2704760Sgblack@eecs.umich.edu        # want to do any processing on it... the rest of this code is
2714730Sgblack@eecs.umich.edu        # just for classes that derive from CheckedInt.
2725422Sgblack@eecs.umich.edu        if name == 'CheckedInt':
2735422Sgblack@eecs.umich.edu            return
2745422Sgblack@eecs.umich.edu
2754276Sgblack@eecs.umich.edu        if not cls.cxx_predecls:
2764760Sgblack@eecs.umich.edu            # most derived types require this, so we just do it here once
2774760Sgblack@eecs.umich.edu            cls.cxx_predecls = ['#include "sim/host.hh"']
2784760Sgblack@eecs.umich.edu
2795020Sgblack@eecs.umich.edu        if not cls.swig_predecls:
2805020Sgblack@eecs.umich.edu            # most derived types require this, so we just do it here once
2815020Sgblack@eecs.umich.edu            cls.swig_predecls = ['%import "python/m5/swig/stdint.i"\n' +
2825020Sgblack@eecs.umich.edu                                 '%import "sim/host.hh"']
2835020Sgblack@eecs.umich.edu
2845020Sgblack@eecs.umich.edu        if not (hasattr(cls, 'min') and hasattr(cls, 'max')):
2855020Sgblack@eecs.umich.edu            if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')):
2865020Sgblack@eecs.umich.edu                panic("CheckedInt subclass %s must define either\n" \
2875020Sgblack@eecs.umich.edu                      "    'min' and 'max' or 'size' and 'unsigned'\n" \
2885020Sgblack@eecs.umich.edu                      % name);
2895020Sgblack@eecs.umich.edu            if cls.unsigned:
2905020Sgblack@eecs.umich.edu                cls.min = 0
2915020Sgblack@eecs.umich.edu                cls.max = 2 ** cls.size - 1
2925020Sgblack@eecs.umich.edu            else:
2934760Sgblack@eecs.umich.edu                cls.min = -(2 ** (cls.size - 1))
2944760Sgblack@eecs.umich.edu                cls.max = (2 ** (cls.size - 1)) - 1
2954760Sgblack@eecs.umich.edu
2965020Sgblack@eecs.umich.edu# Abstract superclass for bounds-checked integer parameters.  This
2975020Sgblack@eecs.umich.edu# class is subclassed to generate parameter classes with specific
2985020Sgblack@eecs.umich.edu# bounds.  Initialization of the min and max bounds is done in the
2995020Sgblack@eecs.umich.edu# metaclass CheckedIntType.__init__.
3005020Sgblack@eecs.umich.educlass CheckedInt(NumericParamValue):
3014760Sgblack@eecs.umich.edu    __metaclass__ = CheckedIntType
3024760Sgblack@eecs.umich.edu
3034760Sgblack@eecs.umich.edu    def _check(self):
3045020Sgblack@eecs.umich.edu        if not self.min <= self.value <= self.max:
3055020Sgblack@eecs.umich.edu            raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
3065029Sgblack@eecs.umich.edu                  (self.min, self.value, self.max)
3075029Sgblack@eecs.umich.edu
3085020Sgblack@eecs.umich.edu    def __init__(self, value):
3095020Sgblack@eecs.umich.edu        if isinstance(value, str):
3105020Sgblack@eecs.umich.edu            self.value = convert.toInteger(value)
3115020Sgblack@eecs.umich.edu        elif isinstance(value, (int, long, float)):
3124760Sgblack@eecs.umich.edu            self.value = long(value)
3134760Sgblack@eecs.umich.edu        self._check()
3144760Sgblack@eecs.umich.edu
3155030Sgblack@eecs.umich.educlass Int(CheckedInt):      cxx_type = 'int';      size = 32; unsigned = False
3165030Sgblack@eecs.umich.educlass Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True
3175020Sgblack@eecs.umich.edu
3185020Sgblack@eecs.umich.educlass Int8(CheckedInt):     cxx_type =   'int8_t'; size =  8; unsigned = False
3194760Sgblack@eecs.umich.educlass UInt8(CheckedInt):    cxx_type =  'uint8_t'; size =  8; unsigned = True
3204760Sgblack@eecs.umich.educlass Int16(CheckedInt):    cxx_type =  'int16_t'; size = 16; unsigned = False
3214276Sgblack@eecs.umich.educlass UInt16(CheckedInt):   cxx_type = 'uint16_t'; size = 16; unsigned = True
3224276Sgblack@eecs.umich.educlass Int32(CheckedInt):    cxx_type =  'int32_t'; size = 32; unsigned = False
3235331Sgblack@eecs.umich.educlass UInt32(CheckedInt):   cxx_type = 'uint32_t'; size = 32; unsigned = True
3245331Sgblack@eecs.umich.educlass Int64(CheckedInt):    cxx_type =  'int64_t'; size = 64; unsigned = False
3255331Sgblack@eecs.umich.educlass UInt64(CheckedInt):   cxx_type = 'uint64_t'; size = 64; unsigned = True
3265331Sgblack@eecs.umich.edu
3275331Sgblack@eecs.umich.educlass Counter(CheckedInt):  cxx_type = 'Counter';  size = 64; unsigned = True
3285331Sgblack@eecs.umich.educlass Tick(CheckedInt):     cxx_type = 'Tick';     size = 64; unsigned = True
3295331Sgblack@eecs.umich.educlass TcpPort(CheckedInt):  cxx_type = 'uint16_t'; size = 16; unsigned = True
3305331Sgblack@eecs.umich.educlass UdpPort(CheckedInt):  cxx_type = 'uint16_t'; size = 16; unsigned = True
3315331Sgblack@eecs.umich.edu
3325331Sgblack@eecs.umich.educlass Percent(CheckedInt):  cxx_type = 'int'; min = 0; max = 100
3335331Sgblack@eecs.umich.edu
3345331Sgblack@eecs.umich.educlass Float(ParamValue, float):
3355331Sgblack@eecs.umich.edu    pass
3365331Sgblack@eecs.umich.edu
3375331Sgblack@eecs.umich.educlass MemorySize(CheckedInt):
3384276Sgblack@eecs.umich.edu    cxx_type = 'uint64_t'
3395020Sgblack@eecs.umich.edu    size = 64
3405020Sgblack@eecs.umich.edu    unsigned = True
3415020Sgblack@eecs.umich.edu    def __init__(self, value):
3425296Sgblack@eecs.umich.edu        if isinstance(value, MemorySize):
3435020Sgblack@eecs.umich.edu            self.value = value.value
3445241Sgblack@eecs.umich.edu        else:
3455020Sgblack@eecs.umich.edu            self.value = convert.toMemorySize(value)
3465020Sgblack@eecs.umich.edu        self._check()
3475020Sgblack@eecs.umich.edu
3485020Sgblack@eecs.umich.educlass MemorySize32(CheckedInt):
3495020Sgblack@eecs.umich.edu    size = 32
3505020Sgblack@eecs.umich.edu    unsigned = True
3515020Sgblack@eecs.umich.edu    def __init__(self, value):
3525020Sgblack@eecs.umich.edu        if isinstance(value, MemorySize):
3535020Sgblack@eecs.umich.edu            self.value = value.value
3545020Sgblack@eecs.umich.edu        else:
3555020Sgblack@eecs.umich.edu            self.value = convert.toMemorySize(value)
3564276Sgblack@eecs.umich.edu        self._check()
3575020Sgblack@eecs.umich.edu
3585020Sgblack@eecs.umich.educlass Addr(CheckedInt):
3595020Sgblack@eecs.umich.edu    cxx_type = 'Addr'
3605031Sgblack@eecs.umich.edu    cxx_predecls = ['#include "targetarch/isa_traits.hh"']
3615031Sgblack@eecs.umich.edu    size = 64
3625031Sgblack@eecs.umich.edu    unsigned = True
3635031Sgblack@eecs.umich.edu    def __init__(self, value):
3645020Sgblack@eecs.umich.edu        if isinstance(value, Addr):
3655020Sgblack@eecs.umich.edu            self.value = value.value
3665020Sgblack@eecs.umich.edu        else:
3675020Sgblack@eecs.umich.edu            try:
3685020Sgblack@eecs.umich.edu                self.value = convert.toMemorySize(value)
3695020Sgblack@eecs.umich.edu            except TypeError:
3705020Sgblack@eecs.umich.edu                self.value = long(value)
3715020Sgblack@eecs.umich.edu        self._check()
3725020Sgblack@eecs.umich.edu
3735020Sgblack@eecs.umich.edu
3745020Sgblack@eecs.umich.educlass MetaRange(type):
3755020Sgblack@eecs.umich.edu    def __init__(cls, name, bases, dict):
3765020Sgblack@eecs.umich.edu        super(MetaRange, cls).__init__(name, bases, dict)
3775020Sgblack@eecs.umich.edu        if name == 'Range':
3785020Sgblack@eecs.umich.edu            return
3795020Sgblack@eecs.umich.edu        cls.cxx_type = 'Range< %s >' % cls.type.cxx_type
3805020Sgblack@eecs.umich.edu        cls.cxx_predecls = \
3815020Sgblack@eecs.umich.edu                       ['#include "base/range.hh"'] + cls.type.cxx_predecls
3825020Sgblack@eecs.umich.edu
3835020Sgblack@eecs.umich.educlass Range(ParamValue):
3845020Sgblack@eecs.umich.edu    __metaclass__ = MetaRange
3855020Sgblack@eecs.umich.edu    type = Int # default; can be overridden in subclasses
3865020Sgblack@eecs.umich.edu    def __init__(self, *args, **kwargs):
3875020Sgblack@eecs.umich.edu        def handle_kwargs(self, kwargs):
3885020Sgblack@eecs.umich.edu            if 'end' in kwargs:
3895020Sgblack@eecs.umich.edu                self.second = self.type(kwargs.pop('end'))
3905020Sgblack@eecs.umich.edu            elif 'size' in kwargs:
3915020Sgblack@eecs.umich.edu                self.second = self.first + self.type(kwargs.pop('size')) - 1
3925058Sgblack@eecs.umich.edu            else:
3935020Sgblack@eecs.umich.edu                raise TypeError, "Either end or size must be specified"
3945020Sgblack@eecs.umich.edu
3955020Sgblack@eecs.umich.edu        if len(args) == 0:
3965020Sgblack@eecs.umich.edu            self.first = self.type(kwargs.pop('start'))
3975046Sgblack@eecs.umich.edu            handle_kwargs(self, kwargs)
3985046Sgblack@eecs.umich.edu
3995046Sgblack@eecs.umich.edu        elif len(args) == 1:
4005046Sgblack@eecs.umich.edu            if kwargs:
4015020Sgblack@eecs.umich.edu                self.first = self.type(args[0])
4025020Sgblack@eecs.umich.edu                handle_kwargs(self, kwargs)
4035020Sgblack@eecs.umich.edu            elif isinstance(args[0], Range):
4045020Sgblack@eecs.umich.edu                self.first = self.type(args[0].first)
4054276Sgblack@eecs.umich.edu                self.second = self.type(args[0].second)
4064276Sgblack@eecs.umich.edu            else:
4075149Sgblack@eecs.umich.edu                self.first = self.type(0)
4085409Sgblack@eecs.umich.edu                self.second = self.type(args[0]) - 1
4095149Sgblack@eecs.umich.edu
4104712Sgblack@eecs.umich.edu        elif len(args) == 2:
4114712Sgblack@eecs.umich.edu            self.first = self.type(args[0])
4124712Sgblack@eecs.umich.edu            self.second = self.type(args[1])
4134730Sgblack@eecs.umich.edu        else:
4144712Sgblack@eecs.umich.edu            raise TypeError, "Too many arguments specified"
4154276Sgblack@eecs.umich.edu
4164276Sgblack@eecs.umich.edu        if kwargs:
4174712Sgblack@eecs.umich.edu            raise TypeError, "too many keywords: %s" % kwargs.keys()
4184712Sgblack@eecs.umich.edu
4194712Sgblack@eecs.umich.edu    def __str__(self):
4204712Sgblack@eecs.umich.edu        return '%s:%s' % (self.first, self.second)
4214712Sgblack@eecs.umich.edu
4224712Sgblack@eecs.umich.educlass AddrRange(Range):
4234712Sgblack@eecs.umich.edu    type = Addr
4244712Sgblack@eecs.umich.edu
4254276Sgblack@eecs.umich.educlass TickRange(Range):
4264760Sgblack@eecs.umich.edu    type = Tick
4274760Sgblack@eecs.umich.edu
4284760Sgblack@eecs.umich.edu# Boolean parameter type.  Python doesn't let you subclass bool, since
4294760Sgblack@eecs.umich.edu# it doesn't want to let you create multiple instances of True and
4304760Sgblack@eecs.umich.edu# False.  Thus this is a little more complicated than String.
4314760Sgblack@eecs.umich.educlass Bool(ParamValue):
4324760Sgblack@eecs.umich.edu    cxx_type = 'bool'
4334760Sgblack@eecs.umich.edu    def __init__(self, value):
4344760Sgblack@eecs.umich.edu        try:
4354760Sgblack@eecs.umich.edu            self.value = convert.toBool(value)
4364760Sgblack@eecs.umich.edu        except TypeError:
4374760Sgblack@eecs.umich.edu            self.value = bool(value)
4384760Sgblack@eecs.umich.edu
4394760Sgblack@eecs.umich.edu    def __str__(self):
4404760Sgblack@eecs.umich.edu        return str(self.value)
4414760Sgblack@eecs.umich.edu
4424760Sgblack@eecs.umich.edu    def ini_str(self):
4434760Sgblack@eecs.umich.edu        if self.value:
4444760Sgblack@eecs.umich.edu            return 'true'
4454760Sgblack@eecs.umich.edu        return 'false'
4464760Sgblack@eecs.umich.edu
4474276Sgblack@eecs.umich.edudef IncEthernetAddr(addr, val = 1):
4485020Sgblack@eecs.umich.edu    bytes = map(lambda x: int(x, 16), addr.split(':'))
4495020Sgblack@eecs.umich.edu    bytes[5] += val
4505020Sgblack@eecs.umich.edu    for i in (5, 4, 3, 2, 1):
4515020Sgblack@eecs.umich.edu        val,rem = divmod(bytes[i], 256)
4525020Sgblack@eecs.umich.edu        bytes[i] = rem
4535020Sgblack@eecs.umich.edu        if val == 0:
4545020Sgblack@eecs.umich.edu            break
4555020Sgblack@eecs.umich.edu        bytes[i - 1] += val
4565020Sgblack@eecs.umich.edu    assert(bytes[0] <= 255)
4575020Sgblack@eecs.umich.edu    return ':'.join(map(lambda x: '%02x' % x, bytes))
4585020Sgblack@eecs.umich.edu
4595020Sgblack@eecs.umich.educlass NextEthernetAddr(object):
4605020Sgblack@eecs.umich.edu    addr = "00:90:00:00:00:01"
4615020Sgblack@eecs.umich.edu
4625020Sgblack@eecs.umich.edu    def __init__(self, inc = 1):
4635020Sgblack@eecs.umich.edu        self.value = NextEthernetAddr.addr
4645020Sgblack@eecs.umich.edu        NextEthernetAddr.addr = IncEthernetAddr(NextEthernetAddr.addr, inc)
4655020Sgblack@eecs.umich.edu
4665020Sgblack@eecs.umich.educlass EthernetAddr(ParamValue):
4675020Sgblack@eecs.umich.edu    cxx_type = 'Net::EthAddr'
4685020Sgblack@eecs.umich.edu    cxx_predecls = ['#include "base/inet.hh"']
4695020Sgblack@eecs.umich.edu    swig_predecls = ['class Net::EthAddr;']
4705020Sgblack@eecs.umich.edu    def __init__(self, value):
4715020Sgblack@eecs.umich.edu        if value == NextEthernetAddr:
4725020Sgblack@eecs.umich.edu            self.value = value
4735020Sgblack@eecs.umich.edu            return
4745052Sgblack@eecs.umich.edu
4755052Sgblack@eecs.umich.edu        if not isinstance(value, str):
4765052Sgblack@eecs.umich.edu            raise TypeError, "expected an ethernet address and didn't get one"
4775020Sgblack@eecs.umich.edu
4785020Sgblack@eecs.umich.edu        bytes = value.split(':')
4795059Sgblack@eecs.umich.edu        if len(bytes) != 6:
4805059Sgblack@eecs.umich.edu            raise TypeError, 'invalid ethernet address %s' % value
4815059Sgblack@eecs.umich.edu
4825059Sgblack@eecs.umich.edu        for byte in bytes:
4835059Sgblack@eecs.umich.edu            if not 0 <= int(byte) <= 256:
4845059Sgblack@eecs.umich.edu                raise TypeError, 'invalid ethernet address %s' % value
4855059Sgblack@eecs.umich.edu
4865020Sgblack@eecs.umich.edu        self.value = value
4874276Sgblack@eecs.umich.edu
4885020Sgblack@eecs.umich.edu    def unproxy(self, base):
4895020Sgblack@eecs.umich.edu        if self.value == NextEthernetAddr:
4905020Sgblack@eecs.umich.edu            self.addr = self.value().value
4915020Sgblack@eecs.umich.edu        return self
4925020Sgblack@eecs.umich.edu
4935020Sgblack@eecs.umich.edu    def __str__(self):
4945020Sgblack@eecs.umich.edu        if self.value == NextEthernetAddr:
4955020Sgblack@eecs.umich.edu            if hasattr(self, 'addr'):
4965020Sgblack@eecs.umich.edu                return self.addr
4975020Sgblack@eecs.umich.edu            else:
4985020Sgblack@eecs.umich.edu                return "NextEthernetAddr (unresolved)"
4995020Sgblack@eecs.umich.edu        else:
5005020Sgblack@eecs.umich.edu            return self.value
5015020Sgblack@eecs.umich.edu
5025020Sgblack@eecs.umich.edu# Enumerated types are a little more complex.  The user specifies the
5035020Sgblack@eecs.umich.edu# type as Enum(foo) where foo is either a list or dictionary of
5045020Sgblack@eecs.umich.edu# alternatives (typically strings, but not necessarily so).  (In the
5055020Sgblack@eecs.umich.edu# long run, the integer value of the parameter will be the list index
5065020Sgblack@eecs.umich.edu# or the corresponding dictionary value.  For now, since we only check
5075020Sgblack@eecs.umich.edu# that the alternative is valid and then spit it into a .ini file,
5085020Sgblack@eecs.umich.edu# there's not much point in using the dictionary.)
5095020Sgblack@eecs.umich.edu
5105020Sgblack@eecs.umich.edu# What Enum() must do is generate a new type encapsulating the
5115020Sgblack@eecs.umich.edu# provided list/dictionary so that specific values of the parameter
5125020Sgblack@eecs.umich.edu# can be instances of that type.  We define two hidden internal
5135020Sgblack@eecs.umich.edu# classes (_ListEnum and _DictEnum) to serve as base classes, then
5145020Sgblack@eecs.umich.edu# derive the new type from the appropriate base class on the fly.
5155020Sgblack@eecs.umich.edu
5165020Sgblack@eecs.umich.edu
5175020Sgblack@eecs.umich.edu# Metaclass for Enum types
5185020Sgblack@eecs.umich.educlass MetaEnum(type):
5195020Sgblack@eecs.umich.edu    def __init__(cls, name, bases, init_dict):
5205020Sgblack@eecs.umich.edu        if init_dict.has_key('map'):
5215020Sgblack@eecs.umich.edu            if not isinstance(cls.map, dict):
5225020Sgblack@eecs.umich.edu                raise TypeError, "Enum-derived class attribute 'map' " \
5235020Sgblack@eecs.umich.edu                      "must be of type dict"
5245047Sgblack@eecs.umich.edu            # build list of value strings from map
5255047Sgblack@eecs.umich.edu            cls.vals = cls.map.keys()
5265020Sgblack@eecs.umich.edu            cls.vals.sort()
5275047Sgblack@eecs.umich.edu        elif init_dict.has_key('vals'):
5285020Sgblack@eecs.umich.edu            if not isinstance(cls.vals, list):
5295047Sgblack@eecs.umich.edu                raise TypeError, "Enum-derived class attribute 'vals' " \
5305020Sgblack@eecs.umich.edu                      "must be of type list"
5315020Sgblack@eecs.umich.edu            # build string->value map from vals sequence
5325020Sgblack@eecs.umich.edu            cls.map = {}
5335020Sgblack@eecs.umich.edu            for idx,val in enumerate(cls.vals):
5344276Sgblack@eecs.umich.edu                cls.map[val] = idx
5355020Sgblack@eecs.umich.edu        else:
5365020Sgblack@eecs.umich.edu            raise TypeError, "Enum-derived class must define "\
5375020Sgblack@eecs.umich.edu                  "attribute 'map' or 'vals'"
5385020Sgblack@eecs.umich.edu
5395020Sgblack@eecs.umich.edu        cls.cxx_type = name + '::Enum'
5405020Sgblack@eecs.umich.edu
5415020Sgblack@eecs.umich.edu        super(MetaEnum, cls).__init__(name, bases, init_dict)
5425020Sgblack@eecs.umich.edu
5435020Sgblack@eecs.umich.edu    # Generate C++ class declaration for this enum type.
5445020Sgblack@eecs.umich.edu    # Note that we wrap the enum in a class/struct to act as a namespace,
5455020Sgblack@eecs.umich.edu    # so that the enum strings can be brief w/o worrying about collisions.
5465020Sgblack@eecs.umich.edu    def cxx_decl(cls):
5475020Sgblack@eecs.umich.edu        s = 'struct %s {\n  enum Enum {\n    ' % cls.__name__
5485020Sgblack@eecs.umich.edu        s += ',\n    '.join(['%s = %d' % (v,cls.map[v]) for v in cls.vals])
5495020Sgblack@eecs.umich.edu        s += '\n  };\n};\n'
5505020Sgblack@eecs.umich.edu        return s
5515020Sgblack@eecs.umich.edu
5525020Sgblack@eecs.umich.edu# Base class for enum types.
5535020Sgblack@eecs.umich.educlass Enum(ParamValue):
5545020Sgblack@eecs.umich.edu    __metaclass__ = MetaEnum
5555020Sgblack@eecs.umich.edu    vals = []
5565020Sgblack@eecs.umich.edu
5575020Sgblack@eecs.umich.edu    def __init__(self, value):
5585020Sgblack@eecs.umich.edu        if value not in self.map:
5594276Sgblack@eecs.umich.edu            raise TypeError, "Enum param got bad value '%s' (not in %s)" \
5605020Sgblack@eecs.umich.edu                  % (value, self.vals)
5615020Sgblack@eecs.umich.edu        self.value = value
5625020Sgblack@eecs.umich.edu
5635020Sgblack@eecs.umich.edu    def __str__(self):
5645020Sgblack@eecs.umich.edu        return self.value
5655020Sgblack@eecs.umich.edu
5665020Sgblack@eecs.umich.eduticks_per_sec = None
5675020Sgblack@eecs.umich.edu
5685020Sgblack@eecs.umich.edu# how big does a rounding error need to be before we warn about it?
5695020Sgblack@eecs.umich.edufrequency_tolerance = 0.001  # 0.1%
5705020Sgblack@eecs.umich.edu
5715020Sgblack@eecs.umich.edu# convert a floting-point # of ticks to integer, and warn if rounding
5725020Sgblack@eecs.umich.edu# discards too much precision
5735020Sgblack@eecs.umich.edudef tick_check(float_ticks):
5745020Sgblack@eecs.umich.edu    if float_ticks == 0:
5755020Sgblack@eecs.umich.edu        return 0
5765020Sgblack@eecs.umich.edu    int_ticks = int(round(float_ticks))
5775020Sgblack@eecs.umich.edu    err = (float_ticks - int_ticks) / float_ticks
5785020Sgblack@eecs.umich.edu    if err > frequency_tolerance:
5795020Sgblack@eecs.umich.edu        print >> sys.stderr, "Warning: rounding error > tolerance"
5805020Sgblack@eecs.umich.edu        print >> sys.stderr, "    %f rounded to %d" % (float_ticks, int_ticks)
5815020Sgblack@eecs.umich.edu        #raise ValueError
5825020Sgblack@eecs.umich.edu    return int_ticks
5835020Sgblack@eecs.umich.edu
5845020Sgblack@eecs.umich.edudef getLatency(value):
5855020Sgblack@eecs.umich.edu    if isinstance(value, Latency) or isinstance(value, Clock):
5865020Sgblack@eecs.umich.edu        return value.value
5875020Sgblack@eecs.umich.edu    elif isinstance(value, Frequency) or isinstance(value, RootClock):
5884276Sgblack@eecs.umich.edu        return 1 / value.value
5895020Sgblack@eecs.umich.edu    elif isinstance(value, str):
5905020Sgblack@eecs.umich.edu        try:
5915020Sgblack@eecs.umich.edu            return convert.toLatency(value)
5925020Sgblack@eecs.umich.edu        except ValueError:
5935238Sgblack@eecs.umich.edu            try:
5945238Sgblack@eecs.umich.edu                return 1 / convert.toFrequency(value)
5955238Sgblack@eecs.umich.edu            except ValueError:
5965238Sgblack@eecs.umich.edu                pass # fall through
5975238Sgblack@eecs.umich.edu    raise ValueError, "Invalid Frequency/Latency value '%s'" % value
5985238Sgblack@eecs.umich.edu
5995238Sgblack@eecs.umich.edu
6005238Sgblack@eecs.umich.educlass Latency(NumericParamValue):
6015238Sgblack@eecs.umich.edu    cxx_type = 'Tick'
6025238Sgblack@eecs.umich.edu    cxx_predecls = ['#include "sim/host.hh"']
6035238Sgblack@eecs.umich.edu    swig_predecls = ['%import "python/m5/swig/stdint.i"\n' +
6045238Sgblack@eecs.umich.edu                     '%import "sim/host.hh"']
6055238Sgblack@eecs.umich.edu    def __init__(self, value):
6065238Sgblack@eecs.umich.edu        self.value = getLatency(value)
6075238Sgblack@eecs.umich.edu
6085238Sgblack@eecs.umich.edu    def __getattr__(self, attr):
6095238Sgblack@eecs.umich.edu        if attr in ('latency', 'period'):
6105238Sgblack@eecs.umich.edu            return self
6115238Sgblack@eecs.umich.edu        if attr == 'frequency':
6125238Sgblack@eecs.umich.edu            return Frequency(self)
6135238Sgblack@eecs.umich.edu        raise AttributeError, "Latency object has no attribute '%s'" % attr
6145238Sgblack@eecs.umich.edu
6155238Sgblack@eecs.umich.edu    # convert latency to ticks
6165238Sgblack@eecs.umich.edu    def ini_str(self):
6175238Sgblack@eecs.umich.edu        return str(tick_check(self.value * ticks_per_sec))
6185238Sgblack@eecs.umich.edu
6195238Sgblack@eecs.umich.educlass Frequency(NumericParamValue):
6205238Sgblack@eecs.umich.edu    cxx_type = 'Tick'
6215238Sgblack@eecs.umich.edu    cxx_predecls = ['#include "sim/host.hh"']
6225238Sgblack@eecs.umich.edu    swig_predecls = ['%import "python/m5/swig/stdint.i"\n' +
6235238Sgblack@eecs.umich.edu                     '%import "sim/host.hh"']
6245238Sgblack@eecs.umich.edu    def __init__(self, value):
6255238Sgblack@eecs.umich.edu        self.value = 1 / getLatency(value)
6265238Sgblack@eecs.umich.edu
6275238Sgblack@eecs.umich.edu    def __getattr__(self, attr):
6285238Sgblack@eecs.umich.edu        if attr == 'frequency':
6295238Sgblack@eecs.umich.edu            return self
6305238Sgblack@eecs.umich.edu        if attr in ('latency', 'period'):
6315238Sgblack@eecs.umich.edu            return Latency(self)
6325238Sgblack@eecs.umich.edu        raise AttributeError, "Frequency object has no attribute '%s'" % attr
6335238Sgblack@eecs.umich.edu
6345238Sgblack@eecs.umich.edu    # convert frequency to ticks per period
6355238Sgblack@eecs.umich.edu    def ini_str(self):
6365238Sgblack@eecs.umich.edu        return self.period.ini_str()
6375238Sgblack@eecs.umich.edu
6385238Sgblack@eecs.umich.edu# Just like Frequency, except ini_str() is absolute # of ticks per sec (Hz).
6395238Sgblack@eecs.umich.edu# We can't inherit from Frequency because we don't want it to be directly
6405238Sgblack@eecs.umich.edu# assignable to a regular Frequency parameter.
6415238Sgblack@eecs.umich.educlass RootClock(ParamValue):
6425238Sgblack@eecs.umich.edu    cxx_type = 'Tick'
6435238Sgblack@eecs.umich.edu    cxx_predecls = ['#include "sim/host.hh"']
6445238Sgblack@eecs.umich.edu    swig_predecls = ['%import "python/m5/swig/stdint.i"\n' +
6455020Sgblack@eecs.umich.edu                     '%import "sim/host.hh"']
6465020Sgblack@eecs.umich.edu    def __init__(self, value):
6475020Sgblack@eecs.umich.edu        self.value = 1 / getLatency(value)
6485020Sgblack@eecs.umich.edu
6495020Sgblack@eecs.umich.edu    def __getattr__(self, attr):
6505020Sgblack@eecs.umich.edu        if attr == 'frequency':
6515020Sgblack@eecs.umich.edu            return Frequency(self)
6525020Sgblack@eecs.umich.edu        if attr in ('latency', 'period'):
6535020Sgblack@eecs.umich.edu            return Latency(self)
6545020Sgblack@eecs.umich.edu        raise AttributeError, "Frequency object has no attribute '%s'" % attr
6555020Sgblack@eecs.umich.edu
6565020Sgblack@eecs.umich.edu    def ini_str(self):
6575020Sgblack@eecs.umich.edu        return str(tick_check(self.value))
6585238Sgblack@eecs.umich.edu
6595238Sgblack@eecs.umich.edu# A generic frequency and/or Latency value.  Value is stored as a latency,
6605238Sgblack@eecs.umich.edu# but to avoid ambiguity this object does not support numeric ops (* or /).
6615238Sgblack@eecs.umich.edu# An explicit conversion to a Latency or Frequency must be made first.
6625238Sgblack@eecs.umich.educlass Clock(ParamValue):
6635238Sgblack@eecs.umich.edu    cxx_type = 'Tick'
6645238Sgblack@eecs.umich.edu    cxx_predecls = ['#include "sim/host.hh"']
6655238Sgblack@eecs.umich.edu    swig_predecls = ['%import "python/m5/swig/stdint.i"\n' +
6665238Sgblack@eecs.umich.edu                     '%import "sim/host.hh"']
6675238Sgblack@eecs.umich.edu    def __init__(self, value):
6685238Sgblack@eecs.umich.edu        self.value = getLatency(value)
6695238Sgblack@eecs.umich.edu
6705238Sgblack@eecs.umich.edu    def __getattr__(self, attr):
6715238Sgblack@eecs.umich.edu        if attr == 'frequency':
6725238Sgblack@eecs.umich.edu            return Frequency(self)
6735238Sgblack@eecs.umich.edu        if attr in ('latency', 'period'):
6745238Sgblack@eecs.umich.edu            return Latency(self)
6755238Sgblack@eecs.umich.edu        raise AttributeError, "Frequency object has no attribute '%s'" % attr
6765238Sgblack@eecs.umich.edu
6775238Sgblack@eecs.umich.edu    def ini_str(self):
6785238Sgblack@eecs.umich.edu        return self.period.ini_str()
6795238Sgblack@eecs.umich.edu
6805238Sgblack@eecs.umich.educlass NetworkBandwidth(float,ParamValue):
6815238Sgblack@eecs.umich.edu    cxx_type = 'float'
6825238Sgblack@eecs.umich.edu    def __new__(cls, value):
6835238Sgblack@eecs.umich.edu        val = convert.toNetworkBandwidth(value) / 8.0
6845238Sgblack@eecs.umich.edu        return super(cls, NetworkBandwidth).__new__(cls, val)
6855238Sgblack@eecs.umich.edu
6865238Sgblack@eecs.umich.edu    def __str__(self):
6875238Sgblack@eecs.umich.edu        return str(self.val)
6885238Sgblack@eecs.umich.edu
6895238Sgblack@eecs.umich.edu    def ini_str(self):
6905238Sgblack@eecs.umich.edu        return '%f' % (ticks_per_sec / float(self))
6915238Sgblack@eecs.umich.edu
6925238Sgblack@eecs.umich.educlass MemoryBandwidth(float,ParamValue):
6935238Sgblack@eecs.umich.edu    cxx_type = 'float'
6945238Sgblack@eecs.umich.edu    def __new__(self, value):
6955238Sgblack@eecs.umich.edu        val = convert.toMemoryBandwidth(value)
6965238Sgblack@eecs.umich.edu        return super(cls, MemoryBandwidth).__new__(cls, val)
6975238Sgblack@eecs.umich.edu
6985238Sgblack@eecs.umich.edu    def __str__(self):
6995238Sgblack@eecs.umich.edu        return str(self.val)
7005238Sgblack@eecs.umich.edu
7015238Sgblack@eecs.umich.edu    def ini_str(self):
7025238Sgblack@eecs.umich.edu        return '%f' % (ticks_per_sec / float(self))
7035238Sgblack@eecs.umich.edu
7045238Sgblack@eecs.umich.edu#
7055238Sgblack@eecs.umich.edu# "Constants"... handy aliases for various values.
7065238Sgblack@eecs.umich.edu#
7075238Sgblack@eecs.umich.edu
7085238Sgblack@eecs.umich.edu# Special class for NULL pointers.  Note the special check in
7095238Sgblack@eecs.umich.edu# make_param_value() above that lets these be assigned where a
7105020Sgblack@eecs.umich.edu# SimObject is required.
7115020Sgblack@eecs.umich.edu# only one copy of a particular node
7125020Sgblack@eecs.umich.educlass NullSimObject(object):
7135020Sgblack@eecs.umich.edu    __metaclass__ = Singleton
7145020Sgblack@eecs.umich.edu
7155020Sgblack@eecs.umich.edu    def __call__(cls):
7165020Sgblack@eecs.umich.edu        return cls
7175020Sgblack@eecs.umich.edu
7185020Sgblack@eecs.umich.edu    def _instantiate(self, parent = None, path = ''):
7195020Sgblack@eecs.umich.edu        pass
7205020Sgblack@eecs.umich.edu
7214276Sgblack@eecs.umich.edu    def ini_str(self):
7225020Sgblack@eecs.umich.edu        return 'Null'
7235020Sgblack@eecs.umich.edu
7245020Sgblack@eecs.umich.edu    def unproxy(self, base):
7255020Sgblack@eecs.umich.edu        return self
7265020Sgblack@eecs.umich.edu
7275020Sgblack@eecs.umich.edu    def set_path(self, parent, name):
7285020Sgblack@eecs.umich.edu        pass
7295020Sgblack@eecs.umich.edu    def __str__(self):
7305020Sgblack@eecs.umich.edu        return 'Null'
7315020Sgblack@eecs.umich.edu
7325020Sgblack@eecs.umich.edu# The only instance you'll ever need...
7335020Sgblack@eecs.umich.eduNULL = NullSimObject()
7345020Sgblack@eecs.umich.edu
7355020Sgblack@eecs.umich.edudef isNullPointer(value):
7365020Sgblack@eecs.umich.edu    return isinstance(value, NullSimObject)
7375020Sgblack@eecs.umich.edu
7385020Sgblack@eecs.umich.edu# Some memory range specifications use this as a default upper bound.
7395020Sgblack@eecs.umich.eduMaxAddr = Addr.max
7405020Sgblack@eecs.umich.eduMaxTick = Tick.max
7415020Sgblack@eecs.umich.eduAllMemory = AddrRange(0, MaxAddr)
7425020Sgblack@eecs.umich.edu
7435020Sgblack@eecs.umich.edu
7445020Sgblack@eecs.umich.edu#####################################################################
7455020Sgblack@eecs.umich.edu#
7465020Sgblack@eecs.umich.edu# Port objects
7475020Sgblack@eecs.umich.edu#
7485020Sgblack@eecs.umich.edu# Ports are used to interconnect objects in the memory system.
7495020Sgblack@eecs.umich.edu#
7505020Sgblack@eecs.umich.edu#####################################################################
7515020Sgblack@eecs.umich.edu
7524276Sgblack@eecs.umich.edu# Port reference: encapsulates a reference to a particular port on a
7534727Sgblack@eecs.umich.edu# particular SimObject.
7544727Sgblack@eecs.umich.educlass PortRef(object):
7554727Sgblack@eecs.umich.edu    def __init__(self, simobj, name, isVec):
7564727Sgblack@eecs.umich.edu        assert(isSimObject(simobj))
7574727Sgblack@eecs.umich.edu        self.simobj = simobj
7584727Sgblack@eecs.umich.edu        self.name = name
7594727Sgblack@eecs.umich.edu        self.index = -1
7604727Sgblack@eecs.umich.edu        self.isVec = isVec # is this a vector port?
7614727Sgblack@eecs.umich.edu        self.peer = None   # not associated with another port yet
7624727Sgblack@eecs.umich.edu        self.ccConnected = False # C++ port connection done?
7634727Sgblack@eecs.umich.edu
7644727Sgblack@eecs.umich.edu    # Set peer port reference.  Called via __setattr__ as a result of
7654727Sgblack@eecs.umich.edu    # a port assignment, e.g., "obj1.port1 = obj2.port2".
7664727Sgblack@eecs.umich.edu    def setPeer(self, other):
7674727Sgblack@eecs.umich.edu        if self.isVec:
7684727Sgblack@eecs.umich.edu            curMap = self.simobj._port_map.get(self.name, [])
7694727Sgblack@eecs.umich.edu            self.index = len(curMap)
7704727Sgblack@eecs.umich.edu            curMap.append(other)
7714727Sgblack@eecs.umich.edu        else:
7724727Sgblack@eecs.umich.edu            curMap = self.simobj._port_map.get(self.name)
7734727Sgblack@eecs.umich.edu            if curMap and not self.isVec:
7744760Sgblack@eecs.umich.edu                print "warning: overwriting port", self.simobj, self.name
7754760Sgblack@eecs.umich.edu            curMap = other
7764760Sgblack@eecs.umich.edu        self.simobj._port_map[self.name] = curMap
7774760Sgblack@eecs.umich.edu        self.peer = other
7784760Sgblack@eecs.umich.edu
7794760Sgblack@eecs.umich.edu    def clone(self, memo):
7804760Sgblack@eecs.umich.edu        newRef = copy.copy(self)
7814760Sgblack@eecs.umich.edu        assert(isSimObject(newRef.simobj))
7824760Sgblack@eecs.umich.edu        newRef.simobj = newRef.simobj(_memo=memo)
7834760Sgblack@eecs.umich.edu        # Tricky: if I'm the *second* PortRef in the pair to be
7844760Sgblack@eecs.umich.edu        # cloned, then my peer is still in the middle of its clone
7854760Sgblack@eecs.umich.edu        # method, and thus hasn't returned to its owner's
7864760Sgblack@eecs.umich.edu        # SimObject.__init__ to get installed in _port_map.  As a
7874760Sgblack@eecs.umich.edu        # result I have no way of finding the *new* peer object.  So I
7884760Sgblack@eecs.umich.edu        # mark myself as "waiting" for my peer, and I let the *first*
7894760Sgblack@eecs.umich.edu        # PortRef clone call set up both peer pointers after I return.
7904760Sgblack@eecs.umich.edu        newPeer = newRef.simobj._port_map.get(self.name)
7914760Sgblack@eecs.umich.edu        if newPeer:
7924760Sgblack@eecs.umich.edu            if self.isVec:
7934760Sgblack@eecs.umich.edu                assert(self.index != -1)
7944276Sgblack@eecs.umich.edu                newPeer = newPeer[self.index]
7954276Sgblack@eecs.umich.edu            # other guy is all set up except for his peer pointer
7964712Sgblack@eecs.umich.edu            assert(newPeer.peer == -1) # peer must be waiting for handshake
7974712Sgblack@eecs.umich.edu            newPeer.peer = newRef
7985659Sgblack@eecs.umich.edu            newRef.peer = newPeer
7995659Sgblack@eecs.umich.edu        else:
8005659Sgblack@eecs.umich.edu            # other guy is in clone; just wait for him to do the work
8015659Sgblack@eecs.umich.edu            newRef.peer = -1 # mark as waiting for handshake
8025659Sgblack@eecs.umich.edu        return newRef
8035659Sgblack@eecs.umich.edu
8045659Sgblack@eecs.umich.edu    # Call C++ to create corresponding port connection between C++ objects
8055659Sgblack@eecs.umich.edu    def ccConnect(self):
8065240Sgblack@eecs.umich.edu        if self.ccConnected: # already done this
8074712Sgblack@eecs.umich.edu            return
8084712Sgblack@eecs.umich.edu        peer = self.peer
8094712Sgblack@eecs.umich.edu        cc_main.connectPorts(self.simobj.getCCObject(), self.name, self.index,
8104712Sgblack@eecs.umich.edu                             peer.simobj.getCCObject(), peer.name, peer.index)
8114276Sgblack@eecs.umich.edu        self.ccConnected = True
8124276Sgblack@eecs.umich.edu        peer.ccConnected = True
8134712Sgblack@eecs.umich.edu
8144712Sgblack@eecs.umich.edu# Port description object.  Like a ParamDesc object, this represents a
8154712Sgblack@eecs.umich.edu# logical port in the SimObject class, not a particular port on a
8165240Sgblack@eecs.umich.edu# SimObject instance.  The latter are represented by PortRef objects.
8174712Sgblack@eecs.umich.educlass Port(object):
8184712Sgblack@eecs.umich.edu    def __init__(self, desc):
8195238Sgblack@eecs.umich.edu        self.desc = desc
8205238Sgblack@eecs.umich.edu        self.isVec = False
8215238Sgblack@eecs.umich.edu
8225238Sgblack@eecs.umich.edu    # Generate a PortRef for this port on the given SimObject with the
8235238Sgblack@eecs.umich.edu    # given name
8245238Sgblack@eecs.umich.edu    def makeRef(self, simobj, name):
8255238Sgblack@eecs.umich.edu        return PortRef(simobj, name, self.isVec)
8265238Sgblack@eecs.umich.edu
8275238Sgblack@eecs.umich.edu    # Connect an instance of this port (on the given SimObject with
8285238Sgblack@eecs.umich.edu    # the given name) with the port described by the supplied PortRef
8295238Sgblack@eecs.umich.edu    def connect(self, simobj, name, ref):
8305238Sgblack@eecs.umich.edu        if not isinstance(ref, PortRef):
8315238Sgblack@eecs.umich.edu            raise TypeError, \
8325238Sgblack@eecs.umich.edu                  "assigning non-port reference port '%s'" % name
8335238Sgblack@eecs.umich.edu        myRef = self.makeRef(simobj, name)
8344724Sgblack@eecs.umich.edu        myRef.setPeer(ref)
8354276Sgblack@eecs.umich.edu        ref.setPeer(myRef)
8364276Sgblack@eecs.umich.edu
8374864Sgblack@eecs.umich.edu# VectorPort description object.  Like Port, but represents a vector
8384864Sgblack@eecs.umich.edu# of connections (e.g., as on a Bus).
8394712Sgblack@eecs.umich.educlass VectorPort(Port):
8405240Sgblack@eecs.umich.edu    def __init__(self, desc):
8414712Sgblack@eecs.umich.edu        Port.__init__(self, desc)
8424712Sgblack@eecs.umich.edu        self.isVec = True
8434746Sgblack@eecs.umich.edu
8444746Sgblack@eecs.umich.edu
8454746Sgblack@eecs.umich.edu__all__ = ['Param', 'VectorParam',
8464746Sgblack@eecs.umich.edu           'Enum', 'Bool', 'String', 'Float',
8474746Sgblack@eecs.umich.edu           'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
8484276Sgblack@eecs.umich.edu           'Int32', 'UInt32', 'Int64', 'UInt64',
8494276Sgblack@eecs.umich.edu           'Counter', 'Addr', 'Tick', 'Percent',
8504712Sgblack@eecs.umich.edu           'TcpPort', 'UdpPort', 'EthernetAddr',
8515240Sgblack@eecs.umich.edu           'MemorySize', 'MemorySize32',
8525240Sgblack@eecs.umich.edu           'Latency', 'Frequency', 'RootClock', 'Clock',
8535240Sgblack@eecs.umich.edu           'NetworkBandwidth', 'MemoryBandwidth',
8545240Sgblack@eecs.umich.edu           'Range', 'AddrRange', 'TickRange',
8555240Sgblack@eecs.umich.edu           'MaxAddr', 'MaxTick', 'AllMemory',
8565240Sgblack@eecs.umich.edu           'NextEthernetAddr', 'NULL',
8575240Sgblack@eecs.umich.edu           'Port', 'VectorPort']
8585240Sgblack@eecs.umich.edu
8595240Sgblack@eecs.umich.edu# see comment on imports at end of __init__.py.
8605240Sgblack@eecs.umich.edufrom SimObject import isSimObject, isSimObjectSequence, isSimObjectClass
8615240Sgblack@eecs.umich.eduimport proxy
8625240Sgblack@eecs.umich.eduimport objects
8635238Sgblack@eecs.umich.eduimport cc_main
8645332Sgblack@eecs.umich.edu