params.py revision 5468:786868ff3058
111988Sandreas.sandberg@arm.com# Copyright (c) 2004-2006 The Regents of The University of Michigan
28839Sandreas.hansson@arm.com# All rights reserved.
38839Sandreas.hansson@arm.com#
48839Sandreas.hansson@arm.com# Redistribution and use in source and binary forms, with or without
58839Sandreas.hansson@arm.com# modification, are permitted provided that the following conditions are
68839Sandreas.hansson@arm.com# met: redistributions of source code must retain the above copyright
78839Sandreas.hansson@arm.com# notice, this list of conditions and the following disclaimer;
88839Sandreas.hansson@arm.com# redistributions in binary form must reproduce the above copyright
98839Sandreas.hansson@arm.com# notice, this list of conditions and the following disclaimer in the
108839Sandreas.hansson@arm.com# documentation and/or other materials provided with the distribution;
118839Sandreas.hansson@arm.com# neither the name of the copyright holders nor the names of its
128839Sandreas.hansson@arm.com# contributors may be used to endorse or promote products derived from
133101Sstever@eecs.umich.edu# this software without specific prior written permission.
148579Ssteve.reinhardt@amd.com#
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
427778Sgblack@eecs.umich.edu# space when the parameter dictionary is initialized (in
438839Sandreas.hansson@arm.com# MetaSimObject._new_param()); after that point they aren't used.
443101Sstever@eecs.umich.edu#
453101Sstever@eecs.umich.edu#####################################################################
463101Sstever@eecs.umich.edu
473101Sstever@eecs.umich.eduimport copy
483101Sstever@eecs.umich.eduimport datetime
493101Sstever@eecs.umich.eduimport re
503101Sstever@eecs.umich.eduimport sys
513101Sstever@eecs.umich.eduimport time
523101Sstever@eecs.umich.edu
533101Sstever@eecs.umich.eduimport convert
543101Sstever@eecs.umich.eduimport proxy
553101Sstever@eecs.umich.eduimport ticks
563101Sstever@eecs.umich.edufrom util import *
573101Sstever@eecs.umich.edu
583101Sstever@eecs.umich.eduimport SimObject
593101Sstever@eecs.umich.edu
603101Sstever@eecs.umich.edudef isSimObject(*args, **kwargs):
613101Sstever@eecs.umich.edu    return SimObject.isSimObject(*args, **kwargs)
623885Sbinkertn@umich.edu
633885Sbinkertn@umich.edudef isSimObjectSequence(*args, **kwargs):
644762Snate@binkert.org    return SimObject.isSimObjectSequence(*args, **kwargs)
653885Sbinkertn@umich.edu
663885Sbinkertn@umich.edudef isSimObjectClass(*args, **kwargs):
677528Ssteve.reinhardt@amd.com    return SimObject.isSimObjectClass(*args, **kwargs)
683885Sbinkertn@umich.edu
694380Sbinkertn@umich.eduallParams = {}
704167Sbinkertn@umich.edu
713102Sstever@eecs.umich.educlass MetaParamValue(type):
723101Sstever@eecs.umich.edu    def __new__(mcls, name, bases, dct):
734762Snate@binkert.org        cls = super(MetaParamValue, mcls).__new__(mcls, name, bases, dct)
744762Snate@binkert.org        assert name not in allParams
754762Snate@binkert.org        allParams[name] = cls
764762Snate@binkert.org        return cls
774762Snate@binkert.org
784762Snate@binkert.org
794762Snate@binkert.org# Dummy base class to identify types that are legitimate for SimObject
804762Snate@binkert.org# parameters.
814762Snate@binkert.orgclass ParamValue(object):
825033Smilesck@eecs.umich.edu    __metaclass__ = MetaParamValue
835033Smilesck@eecs.umich.edu
845033Smilesck@eecs.umich.edu    cxx_predecls = []
855033Smilesck@eecs.umich.edu    swig_predecls = []
865033Smilesck@eecs.umich.edu
875033Smilesck@eecs.umich.edu    # default for printing to .ini file is regular string conversion.
885033Smilesck@eecs.umich.edu    # will be overridden in some cases
895033Smilesck@eecs.umich.edu    def ini_str(self):
905033Smilesck@eecs.umich.edu        return str(self)
915033Smilesck@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):
955033Smilesck@eecs.umich.edu        return self
9610267SGeoffrey.Blake@arm.com
978596Ssteve.reinhardt@amd.com# Regular parameter description.
988596Ssteve.reinhardt@amd.comclass ParamDesc(object):
998596Ssteve.reinhardt@amd.com    def __init__(self, ptype_str, ptype, *args, **kwargs):
1008596Ssteve.reinhardt@amd.com        self.ptype_str = ptype_str
1017673Snate@binkert.org        # remember ptype only if it is provided
1027673Snate@binkert.org        if ptype != None:
1037673Snate@binkert.org            self.ptype = ptype
1047673Snate@binkert.org
10511988Sandreas.sandberg@arm.com        if args:
10611988Sandreas.sandberg@arm.com            if len(args) == 1:
10711988Sandreas.sandberg@arm.com                self.desc = args[0]
10811988Sandreas.sandberg@arm.com            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
11410380SAndrew.Bardsley@arm.com        if kwargs.has_key('desc'):
11510380SAndrew.Bardsley@arm.com            assert(not hasattr(self, 'desc'))
11610380SAndrew.Bardsley@arm.com            self.desc = kwargs['desc']
11710380SAndrew.Bardsley@arm.com            del kwargs['desc']
11810380SAndrew.Bardsley@arm.com
11910380SAndrew.Bardsley@arm.com        if kwargs.has_key('default'):
12010458Sandreas.hansson@arm.com            assert(not hasattr(self, 'default'))
12110458Sandreas.hansson@arm.com            self.default = kwargs['default']
12210458Sandreas.hansson@arm.com            del kwargs['default']
12310458Sandreas.hansson@arm.com
12410458Sandreas.hansson@arm.com        if kwargs:
12510458Sandreas.hansson@arm.com            raise TypeError, 'extra unknown kwargs %s' % kwargs
12610458Sandreas.hansson@arm.com
12710458Sandreas.hansson@arm.com        if not hasattr(self, 'desc'):
12810458Sandreas.hansson@arm.com            raise TypeError, 'desc attribute missing'
12910458Sandreas.hansson@arm.com
13010458Sandreas.hansson@arm.com    def __getattr__(self, attr):
13110458Sandreas.hansson@arm.com        if attr == 'ptype':
1323101Sstever@eecs.umich.edu            ptype = SimObject.allClasses[self.ptype_str]
1333101Sstever@eecs.umich.edu            assert issubclass(ptype, SimObject.SimObject)
1343101Sstever@eecs.umich.edu            self.ptype = ptype
1353101Sstever@eecs.umich.edu            return ptype
1363101Sstever@eecs.umich.edu
13710267SGeoffrey.Blake@arm.com        raise AttributeError, "'%s' object has no attribute '%s'" % \
13810267SGeoffrey.Blake@arm.com              (type(self).__name__, attr)
13910267SGeoffrey.Blake@arm.com
14010267SGeoffrey.Blake@arm.com    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
1503101Sstever@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):
1683101Sstever@eecs.umich.edu    __metaclass__ = MetaParamValue
1693101Sstever@eecs.umich.edu    def ini_str(self):
1703101Sstever@eecs.umich.edu        return ' '.join([v.ini_str() for v in self])
1713101Sstever@eecs.umich.edu
1723101Sstever@eecs.umich.edu    def getValue(self):
1733101Sstever@eecs.umich.edu        return [ v.getValue() for v in self ]
1743101Sstever@eecs.umich.edu
1753101Sstever@eecs.umich.edu    def unproxy(self, base):
1765033Smilesck@eecs.umich.edu        return [v.unproxy(base) for v in self]
1776656Snate@binkert.org
1785033Smilesck@eecs.umich.educlass SimObjVector(VectorParamValue):
1795033Smilesck@eecs.umich.edu    def print_ini(self, ini_file):
1805033Smilesck@eecs.umich.edu        for v in self:
1813101Sstever@eecs.umich.edu            v.print_ini(ini_file)
1823101Sstever@eecs.umich.edu
1833101Sstever@eecs.umich.educlass VectorParamDesc(ParamDesc):
18410267SGeoffrey.Blake@arm.com    # Convert assigned value to appropriate type.  If the RHS is not a
18510267SGeoffrey.Blake@arm.com    # list or tuple, it generates a single-element list.
18610267SGeoffrey.Blake@arm.com    def convert(self, value):
18710267SGeoffrey.Blake@arm.com        if isinstance(value, (list, tuple)):
18810267SGeoffrey.Blake@arm.com            # list: coerce each element into new list
18910267SGeoffrey.Blake@arm.com            tmp_list = [ ParamDesc.convert(self, v) for v in value ]
19010267SGeoffrey.Blake@arm.com        else:
19110267SGeoffrey.Blake@arm.com            # singleton: coerce to a single-element list
19210267SGeoffrey.Blake@arm.com            tmp_list = [ ParamDesc.convert(self, value) ]
19310267SGeoffrey.Blake@arm.com
19410267SGeoffrey.Blake@arm.com        if isSimObjectSequence(tmp_list):
19510267SGeoffrey.Blake@arm.com            return SimObjVector(tmp_list)
19610267SGeoffrey.Blake@arm.com        else:
1973101Sstever@eecs.umich.edu            return VectorParamValue(tmp_list)
1983101Sstever@eecs.umich.edu
1993101Sstever@eecs.umich.edu    def swig_predecls(self):
2003101Sstever@eecs.umich.edu        return ['%%include "%s_vptype.i"' % self.ptype_str]
2013101Sstever@eecs.umich.edu
2023101Sstever@eecs.umich.edu    def swig_decl(self):
2033101Sstever@eecs.umich.edu        cxx_type = re.sub('std::', '', self.ptype.cxx_type)
2043101Sstever@eecs.umich.edu        vdecl = 'namespace std { %%template(vector_%s) vector< %s >; }' % \
2053101Sstever@eecs.umich.edu                (self.ptype_str, cxx_type)
2063101Sstever@eecs.umich.edu        return ['%include "std_vector.i"'] + self.ptype.swig_predecls + [vdecl]
2073102Sstever@eecs.umich.edu
2083101Sstever@eecs.umich.edu    def cxx_predecls(self):
2093101Sstever@eecs.umich.edu        return ['#include <vector>'] + self.ptype.cxx_predecls
2103101Sstever@eecs.umich.edu
21110267SGeoffrey.Blake@arm.com    def cxx_decl(self):
21210267SGeoffrey.Blake@arm.com        return 'std::vector< %s > %s;' % (self.ptype.cxx_type, self.name)
21310267SGeoffrey.Blake@arm.com
21410267SGeoffrey.Blake@arm.comclass ParamFactory(object):
21510267SGeoffrey.Blake@arm.com    def __init__(self, param_desc_class, ptype_str = None):
21610267SGeoffrey.Blake@arm.com        self.param_desc_class = param_desc_class
21710267SGeoffrey.Blake@arm.com        self.ptype_str = ptype_str
2187673Snate@binkert.org
2198607Sgblack@eecs.umich.edu    def __getattr__(self, attr):
2207673Snate@binkert.org        if self.ptype_str:
2213101Sstever@eecs.umich.edu            attr = self.ptype_str + '.' + attr
22211988Sandreas.sandberg@arm.com        return ParamFactory(self.param_desc_class, attr)
22311988Sandreas.sandberg@arm.com
22411988Sandreas.sandberg@arm.com    # E.g., Param.Int(5, "number of widgets")
2257673Snate@binkert.org    def __call__(self, *args, **kwargs):
2267673Snate@binkert.org        ptype = None
2273101Sstever@eecs.umich.edu        try:
2283101Sstever@eecs.umich.edu            ptype = allParams[self.ptype_str]
2293101Sstever@eecs.umich.edu        except KeyError:
2303101Sstever@eecs.umich.edu            # if name isn't defined yet, assume it's a SimObject, and
2313101Sstever@eecs.umich.edu            # try to resolve it later
2323101Sstever@eecs.umich.edu            pass
2335033Smilesck@eecs.umich.edu        return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs)
2345475Snate@binkert.org
2355475Snate@binkert.orgParam = ParamFactory(ParamDesc)
2365475Snate@binkert.orgVectorParam = ParamFactory(VectorParamDesc)
2375475Snate@binkert.org
23810380SAndrew.Bardsley@arm.com#####################################################################
23910380SAndrew.Bardsley@arm.com#
24010380SAndrew.Bardsley@arm.com# Parameter Types
2413101Sstever@eecs.umich.edu#
2423101Sstever@eecs.umich.edu# Though native Python types could be used to specify parameter types
2433101Sstever@eecs.umich.edu# (the 'ptype' field of the Param and VectorParam classes), it's more
2444762Snate@binkert.org# flexible to define our own set of types.  This gives us more control
2454762Snate@binkert.org# over how Python expressions are converted to values (via the
2464762Snate@binkert.org# __init__() constructor) and how these values are printed out (via
2473101Sstever@eecs.umich.edu# the __str__() conversion method).
2488460SAli.Saidi@ARM.com#
2498459SAli.Saidi@ARM.com#####################################################################
2508459SAli.Saidi@ARM.com
2518459SAli.Saidi@ARM.com# String-valued parameter.  Just mixin the ParamValue class with the
2523101Sstever@eecs.umich.edu# built-in str class.
2537528Ssteve.reinhardt@amd.comclass String(ParamValue,str):
2547528Ssteve.reinhardt@amd.com    cxx_type = 'std::string'
2557528Ssteve.reinhardt@amd.com    cxx_predecls = ['#include <string>']
2567528Ssteve.reinhardt@amd.com    swig_predecls = ['%include "std_string.i"\n' +
2577528Ssteve.reinhardt@amd.com                     '%apply const std::string& {std::string *};']
2587528Ssteve.reinhardt@amd.com    swig_predecls = ['%include "std_string.i"' ]
2593101Sstever@eecs.umich.edu
2607528Ssteve.reinhardt@amd.com    def getValue(self):
2617528Ssteve.reinhardt@amd.com        return self
2627528Ssteve.reinhardt@amd.com
2637528Ssteve.reinhardt@amd.com# superclass for "numeric" parameter values, to emulate math
2647528Ssteve.reinhardt@amd.com# operations in a type-safe way.  e.g., a Latency times an int returns
2657528Ssteve.reinhardt@amd.com# a new Latency object.
2667528Ssteve.reinhardt@amd.comclass NumericParamValue(ParamValue):
2677528Ssteve.reinhardt@amd.com    def __str__(self):
2687528Ssteve.reinhardt@amd.com        return str(self.value)
2697528Ssteve.reinhardt@amd.com
2708321Ssteve.reinhardt@amd.com    def __float__(self):
2718321Ssteve.reinhardt@amd.com        return float(self.value)
2727528Ssteve.reinhardt@amd.com
2737528Ssteve.reinhardt@amd.com    def __long__(self):
2747528Ssteve.reinhardt@amd.com        return long(self.value)
2757528Ssteve.reinhardt@amd.com
2767528Ssteve.reinhardt@amd.com    def __int__(self):
2777528Ssteve.reinhardt@amd.com        return int(self.value)
2787528Ssteve.reinhardt@amd.com
2797528Ssteve.reinhardt@amd.com    # hook for bounds checking
2807528Ssteve.reinhardt@amd.com    def _check(self):
2817528Ssteve.reinhardt@amd.com        return
2827528Ssteve.reinhardt@amd.com
2837528Ssteve.reinhardt@amd.com    def __mul__(self, other):
2847528Ssteve.reinhardt@amd.com        newobj = self.__class__(self)
2853101Sstever@eecs.umich.edu        newobj.value *= other
2868664SAli.Saidi@ARM.com        newobj._check()
2878664SAli.Saidi@ARM.com        return newobj
2888664SAli.Saidi@ARM.com
2898664SAli.Saidi@ARM.com    __rmul__ = __mul__
2908664SAli.Saidi@ARM.com
2918664SAli.Saidi@ARM.com    def __div__(self, other):
2929953Sgeoffrey.blake@arm.com        newobj = self.__class__(self)
2939953Sgeoffrey.blake@arm.com        newobj.value /= other
2949953Sgeoffrey.blake@arm.com        newobj._check()
2959953Sgeoffrey.blake@arm.com        return newobj
2969953Sgeoffrey.blake@arm.com
2979953Sgeoffrey.blake@arm.com    def __sub__(self, other):
2989953Sgeoffrey.blake@arm.com        newobj = self.__class__(self)
2999953Sgeoffrey.blake@arm.com        newobj.value -= other
3009953Sgeoffrey.blake@arm.com        newobj._check()
3019953Sgeoffrey.blake@arm.com        return newobj
3029953Sgeoffrey.blake@arm.com
3039953Sgeoffrey.blake@arm.com# Metaclass for bounds-checked integer parameters.  See CheckedInt.
3049953Sgeoffrey.blake@arm.comclass CheckedIntType(MetaParamValue):
30510267SGeoffrey.Blake@arm.com    def __init__(cls, name, bases, dict):
30610267SGeoffrey.Blake@arm.com        super(CheckedIntType, cls).__init__(name, bases, dict)
30710267SGeoffrey.Blake@arm.com
30810267SGeoffrey.Blake@arm.com        # CheckedInt is an abstract base class, so we actually don't
30910267SGeoffrey.Blake@arm.com        # want to do any processing on it... the rest of this code is
31010267SGeoffrey.Blake@arm.com        # just for classes that derive from CheckedInt.
31110267SGeoffrey.Blake@arm.com        if name == 'CheckedInt':
31210267SGeoffrey.Blake@arm.com            return
31310267SGeoffrey.Blake@arm.com
31410267SGeoffrey.Blake@arm.com        if not cls.cxx_predecls:
31510267SGeoffrey.Blake@arm.com            # most derived types require this, so we just do it here once
31610267SGeoffrey.Blake@arm.com            cls.cxx_predecls = ['#include "sim/host.hh"']
31710267SGeoffrey.Blake@arm.com
31810267SGeoffrey.Blake@arm.com        if not cls.swig_predecls:
31910267SGeoffrey.Blake@arm.com            # most derived types require this, so we just do it here once
32010267SGeoffrey.Blake@arm.com            cls.swig_predecls = ['%import "stdint.i"\n' +
32110267SGeoffrey.Blake@arm.com                                 '%import "sim/host.hh"']
32210267SGeoffrey.Blake@arm.com
32310267SGeoffrey.Blake@arm.com        if not (hasattr(cls, 'min') and hasattr(cls, 'max')):
32410267SGeoffrey.Blake@arm.com            if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')):
3253101Sstever@eecs.umich.edu                panic("CheckedInt subclass %s must define either\n" \
3263101Sstever@eecs.umich.edu                      "    'min' and 'max' or 'size' and 'unsigned'\n" \
3273101Sstever@eecs.umich.edu                      % name);
3283101Sstever@eecs.umich.edu            if cls.unsigned:
3293101Sstever@eecs.umich.edu                cls.min = 0
3303101Sstever@eecs.umich.edu                cls.max = 2 ** cls.size - 1
3313101Sstever@eecs.umich.edu            else:
33210364SGeoffrey.Blake@arm.com                cls.min = -(2 ** (cls.size - 1))
33310364SGeoffrey.Blake@arm.com                cls.max = (2 ** (cls.size - 1)) - 1
33410364SGeoffrey.Blake@arm.com
33510364SGeoffrey.Blake@arm.com# Abstract superclass for bounds-checked integer parameters.  This
3363101Sstever@eecs.umich.edu# class is subclassed to generate parameter classes with specific
3374762Snate@binkert.org# bounds.  Initialization of the min and max bounds is done in the
3384762Snate@binkert.org# metaclass CheckedIntType.__init__.
3394762Snate@binkert.orgclass CheckedInt(NumericParamValue):
3404762Snate@binkert.org    __metaclass__ = CheckedIntType
3417528Ssteve.reinhardt@amd.com
3424762Snate@binkert.org    def _check(self):
3434762Snate@binkert.org        if not self.min <= self.value <= self.max:
3444762Snate@binkert.org            raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
34510267SGeoffrey.Blake@arm.com                  (self.min, self.value, self.max)
34610267SGeoffrey.Blake@arm.com
34710267SGeoffrey.Blake@arm.com    def __init__(self, value):
34810267SGeoffrey.Blake@arm.com        if isinstance(value, str):
34910267SGeoffrey.Blake@arm.com            self.value = convert.toInteger(value)
35010267SGeoffrey.Blake@arm.com        elif isinstance(value, (int, long, float, NumericParamValue)):
35110267SGeoffrey.Blake@arm.com            self.value = long(value)
35210267SGeoffrey.Blake@arm.com        else:
35310267SGeoffrey.Blake@arm.com            raise TypeError, "Can't convert object of type %s to CheckedInt" \
35410267SGeoffrey.Blake@arm.com                  % type(value).__name__
35510267SGeoffrey.Blake@arm.com        self._check()
35610267SGeoffrey.Blake@arm.com
35710267SGeoffrey.Blake@arm.com    def getValue(self):
35810267SGeoffrey.Blake@arm.com        return long(self.value)
35910267SGeoffrey.Blake@arm.com
36010267SGeoffrey.Blake@arm.comclass Int(CheckedInt):      cxx_type = 'int';      size = 32; unsigned = False
36110267SGeoffrey.Blake@arm.comclass Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True
36210267SGeoffrey.Blake@arm.com
36310267SGeoffrey.Blake@arm.comclass Int8(CheckedInt):     cxx_type =   'int8_t'; size =  8; unsigned = False
36410267SGeoffrey.Blake@arm.comclass UInt8(CheckedInt):    cxx_type =  'uint8_t'; size =  8; unsigned = True
36510267SGeoffrey.Blake@arm.comclass Int16(CheckedInt):    cxx_type =  'int16_t'; size = 16; unsigned = False
36610267SGeoffrey.Blake@arm.comclass UInt16(CheckedInt):   cxx_type = 'uint16_t'; size = 16; unsigned = True
36710267SGeoffrey.Blake@arm.comclass Int32(CheckedInt):    cxx_type =  'int32_t'; size = 32; unsigned = False
36810267SGeoffrey.Blake@arm.comclass UInt32(CheckedInt):   cxx_type = 'uint32_t'; size = 32; unsigned = True
36910267SGeoffrey.Blake@arm.comclass Int64(CheckedInt):    cxx_type =  'int64_t'; size = 64; unsigned = False
37010267SGeoffrey.Blake@arm.comclass UInt64(CheckedInt):   cxx_type = 'uint64_t'; size = 64; unsigned = True
37110364SGeoffrey.Blake@arm.com
37210364SGeoffrey.Blake@arm.comclass Counter(CheckedInt):  cxx_type = 'Counter';  size = 64; unsigned = True
37310267SGeoffrey.Blake@arm.comclass Tick(CheckedInt):     cxx_type = 'Tick';     size = 64; unsigned = True
37410267SGeoffrey.Blake@arm.comclass TcpPort(CheckedInt):  cxx_type = 'uint16_t'; size = 16; unsigned = True
37510267SGeoffrey.Blake@arm.comclass UdpPort(CheckedInt):  cxx_type = 'uint16_t'; size = 16; unsigned = True
37610267SGeoffrey.Blake@arm.com
37710267SGeoffrey.Blake@arm.comclass Percent(CheckedInt):  cxx_type = 'int'; min = 0; max = 100
37810267SGeoffrey.Blake@arm.com
3797673Snate@binkert.orgclass Float(ParamValue, float):
3807673Snate@binkert.org    cxx_type = 'double'
3817673Snate@binkert.org
3823101Sstever@eecs.umich.edu    def __init__(self, value):
38311988Sandreas.sandberg@arm.com        if isinstance(value, (int, long, float, NumericParamValue, Float)):
38411988Sandreas.sandberg@arm.com            self.value = float(value)
38511988Sandreas.sandberg@arm.com        else:
38611988Sandreas.sandberg@arm.com            raise TypeError, "Can't convert object of type %s to Float" \
3877673Snate@binkert.org                  % type(value).__name__
3887673Snate@binkert.org
3893101Sstever@eecs.umich.edu    def getValue(self):
3903101Sstever@eecs.umich.edu        return float(self.value)
3913101Sstever@eecs.umich.edu
3923101Sstever@eecs.umich.educlass MemorySize(CheckedInt):
3933101Sstever@eecs.umich.edu    cxx_type = 'uint64_t'
3943101Sstever@eecs.umich.edu    size = 64
3953101Sstever@eecs.umich.edu    unsigned = True
3963101Sstever@eecs.umich.edu    def __init__(self, value):
3973101Sstever@eecs.umich.edu        if isinstance(value, MemorySize):
3983101Sstever@eecs.umich.edu            self.value = value.value
3993101Sstever@eecs.umich.edu        else:
4003101Sstever@eecs.umich.edu            self.value = convert.toMemorySize(value)
4013101Sstever@eecs.umich.edu        self._check()
4023101Sstever@eecs.umich.edu
4033101Sstever@eecs.umich.educlass MemorySize32(CheckedInt):
4045033Smilesck@eecs.umich.edu    cxx_type = 'uint32_t'
4055033Smilesck@eecs.umich.edu    size = 32
4063101Sstever@eecs.umich.edu    unsigned = True
4073101Sstever@eecs.umich.edu    def __init__(self, value):
4083101Sstever@eecs.umich.edu        if isinstance(value, MemorySize):
4093101Sstever@eecs.umich.edu            self.value = value.value
4103101Sstever@eecs.umich.edu        else:
4113101Sstever@eecs.umich.edu            self.value = convert.toMemorySize(value)
4123101Sstever@eecs.umich.edu        self._check()
4133101Sstever@eecs.umich.edu
4143101Sstever@eecs.umich.educlass Addr(CheckedInt):
4153101Sstever@eecs.umich.edu    cxx_type = 'Addr'
4163101Sstever@eecs.umich.edu    size = 64
4173101Sstever@eecs.umich.edu    unsigned = True
4183101Sstever@eecs.umich.edu    def __init__(self, value):
4193101Sstever@eecs.umich.edu        if isinstance(value, Addr):
4203101Sstever@eecs.umich.edu            self.value = value.value
4213101Sstever@eecs.umich.edu        else:
4223101Sstever@eecs.umich.edu            try:
4233101Sstever@eecs.umich.edu                self.value = convert.toMemorySize(value)
4243101Sstever@eecs.umich.edu            except TypeError:
4253101Sstever@eecs.umich.edu                self.value = long(value)
4263101Sstever@eecs.umich.edu        self._check()
4273101Sstever@eecs.umich.edu    def __add__(self, other):
4283101Sstever@eecs.umich.edu        if isinstance(other, Addr):
4293101Sstever@eecs.umich.edu            return self.value + other.value
4303101Sstever@eecs.umich.edu        else:
43110267SGeoffrey.Blake@arm.com            return self.value + other
4327673Snate@binkert.org
4337673Snate@binkert.org
4347673Snate@binkert.orgclass MetaRange(MetaParamValue):
4357673Snate@binkert.org    def __init__(cls, name, bases, dict):
4367673Snate@binkert.org        super(MetaRange, cls).__init__(name, bases, dict)
43710267SGeoffrey.Blake@arm.com        if name == 'Range':
43810267SGeoffrey.Blake@arm.com            return
43910267SGeoffrey.Blake@arm.com        cls.cxx_type = 'Range< %s >' % cls.type.cxx_type
44010267SGeoffrey.Blake@arm.com        cls.cxx_predecls = \
44110458Sandreas.hansson@arm.com                       ['#include "base/range.hh"'] + cls.type.cxx_predecls
44210458Sandreas.hansson@arm.com
44310458Sandreas.hansson@arm.comclass Range(ParamValue):
44410458Sandreas.hansson@arm.com    __metaclass__ = MetaRange
44510458Sandreas.hansson@arm.com    type = Int # default; can be overridden in subclasses
4464762Snate@binkert.org    def __init__(self, *args, **kwargs):
4474762Snate@binkert.org        def handle_kwargs(self, kwargs):
4483101Sstever@eecs.umich.edu            if 'end' in kwargs:
4493101Sstever@eecs.umich.edu                self.second = self.type(kwargs.pop('end'))
4503101Sstever@eecs.umich.edu            elif 'size' in kwargs:
4513101Sstever@eecs.umich.edu                self.second = self.first + self.type(kwargs.pop('size')) - 1
4523101Sstever@eecs.umich.edu            else:
4533101Sstever@eecs.umich.edu                raise TypeError, "Either end or size must be specified"
4543101Sstever@eecs.umich.edu
4553101Sstever@eecs.umich.edu        if len(args) == 0:
4563101Sstever@eecs.umich.edu            self.first = self.type(kwargs.pop('start'))
4573101Sstever@eecs.umich.edu            handle_kwargs(self, kwargs)
4583101Sstever@eecs.umich.edu
4593714Sstever@eecs.umich.edu        elif len(args) == 1:
4603714Sstever@eecs.umich.edu            if kwargs:
4613714Sstever@eecs.umich.edu                self.first = self.type(args[0])
4623714Sstever@eecs.umich.edu                handle_kwargs(self, kwargs)
4633714Sstever@eecs.umich.edu            elif isinstance(args[0], Range):
4643714Sstever@eecs.umich.edu                self.first = self.type(args[0].first)
4653101Sstever@eecs.umich.edu                self.second = self.type(args[0].second)
4663101Sstever@eecs.umich.edu            elif isinstance(args[0], (list, tuple)):
4673101Sstever@eecs.umich.edu                self.first = self.type(args[0][0])
4683101Sstever@eecs.umich.edu                self.second = self.type(args[0][1])
4693101Sstever@eecs.umich.edu            else:
4703101Sstever@eecs.umich.edu                self.first = self.type(0)
4713101Sstever@eecs.umich.edu                self.second = self.type(args[0]) - 1
4723101Sstever@eecs.umich.edu
4733101Sstever@eecs.umich.edu        elif len(args) == 2:
4743101Sstever@eecs.umich.edu            self.first = self.type(args[0])
4753101Sstever@eecs.umich.edu            self.second = self.type(args[1])
4763101Sstever@eecs.umich.edu        else:
4773101Sstever@eecs.umich.edu            raise TypeError, "Too many arguments specified"
4783101Sstever@eecs.umich.edu
4793101Sstever@eecs.umich.edu        if kwargs:
4803101Sstever@eecs.umich.edu            raise TypeError, "too many keywords: %s" % kwargs.keys()
4813101Sstever@eecs.umich.edu
4823101Sstever@eecs.umich.edu    def __str__(self):
4833101Sstever@eecs.umich.edu        return '%s:%s' % (self.first, self.second)
4843101Sstever@eecs.umich.edu
4853101Sstever@eecs.umich.educlass AddrRange(Range):
4863101Sstever@eecs.umich.edu    type = Addr
4873101Sstever@eecs.umich.edu    swig_predecls = ['%include "python/swig/range.i"']
4883101Sstever@eecs.umich.edu
48910380SAndrew.Bardsley@arm.com    def getValue(self):
49010380SAndrew.Bardsley@arm.com        from m5.objects.params import AddrRange
49110380SAndrew.Bardsley@arm.com
49210458Sandreas.hansson@arm.com        value = AddrRange()
49310458Sandreas.hansson@arm.com        value.start = long(self.first)
49410458Sandreas.hansson@arm.com        value.end = long(self.second)
49510458Sandreas.hansson@arm.com        return value
49610458Sandreas.hansson@arm.com
49710458Sandreas.hansson@arm.comclass TickRange(Range):
49810458Sandreas.hansson@arm.com    type = Tick
49910458Sandreas.hansson@arm.com    swig_predecls = ['%include "python/swig/range.i"']
50010458Sandreas.hansson@arm.com
50110458Sandreas.hansson@arm.com    def getValue(self):
50210458Sandreas.hansson@arm.com        from m5.objects.params import TickRange
50310458Sandreas.hansson@arm.com
50410458Sandreas.hansson@arm.com        value = TickRange()
5053101Sstever@eecs.umich.edu        value.start = long(self.first)
5065033Smilesck@eecs.umich.edu        value.end = long(self.second)
5073101Sstever@eecs.umich.edu        return value
5083101Sstever@eecs.umich.edu
5093101Sstever@eecs.umich.edu# Boolean parameter type.  Python doesn't let you subclass bool, since
5103101Sstever@eecs.umich.edu# it doesn't want to let you create multiple instances of True and
5113101Sstever@eecs.umich.edu# False.  Thus this is a little more complicated than String.
5123101Sstever@eecs.umich.educlass Bool(ParamValue):
5133101Sstever@eecs.umich.edu    cxx_type = 'bool'
5143101Sstever@eecs.umich.edu    def __init__(self, value):
5153101Sstever@eecs.umich.edu        try:
5163101Sstever@eecs.umich.edu            self.value = convert.toBool(value)
5173101Sstever@eecs.umich.edu        except TypeError:
5183101Sstever@eecs.umich.edu            self.value = bool(value)
5195822Ssaidi@eecs.umich.edu
5205822Ssaidi@eecs.umich.edu    def getValue(self):
5213101Sstever@eecs.umich.edu        return bool(self.value)
5223101Sstever@eecs.umich.edu
5233101Sstever@eecs.umich.edu    def __str__(self):
5243101Sstever@eecs.umich.edu        return str(self.value)
5253101Sstever@eecs.umich.edu
5263101Sstever@eecs.umich.edu    def ini_str(self):
5273101Sstever@eecs.umich.edu        if self.value:
5283101Sstever@eecs.umich.edu            return 'true'
5293101Sstever@eecs.umich.edu        return 'false'
5303101Sstever@eecs.umich.edu
5313101Sstever@eecs.umich.edudef IncEthernetAddr(addr, val = 1):
5323101Sstever@eecs.umich.edu    bytes = map(lambda x: int(x, 16), addr.split(':'))
5333101Sstever@eecs.umich.edu    bytes[5] += val
53410267SGeoffrey.Blake@arm.com    for i in (5, 4, 3, 2, 1):
5353101Sstever@eecs.umich.edu        val,rem = divmod(bytes[i], 256)
5363101Sstever@eecs.umich.edu        bytes[i] = rem
5373101Sstever@eecs.umich.edu        if val == 0:
5383101Sstever@eecs.umich.edu            break
5393101Sstever@eecs.umich.edu        bytes[i - 1] += val
5403101Sstever@eecs.umich.edu    assert(bytes[0] <= 255)
5413101Sstever@eecs.umich.edu    return ':'.join(map(lambda x: '%02x' % x, bytes))
5423101Sstever@eecs.umich.edu
5433102Sstever@eecs.umich.edu_NextEthernetAddr = "00:90:00:00:00:01"
5443714Sstever@eecs.umich.edudef NextEthernetAddr():
5453101Sstever@eecs.umich.edu    global _NextEthernetAddr
5463714Sstever@eecs.umich.edu
5473714Sstever@eecs.umich.edu    value = _NextEthernetAddr
5483714Sstever@eecs.umich.edu    _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1)
5493101Sstever@eecs.umich.edu    return value
5503101Sstever@eecs.umich.edu
55110267SGeoffrey.Blake@arm.comclass EthernetAddr(ParamValue):
55210267SGeoffrey.Blake@arm.com    cxx_type = 'Net::EthAddr'
55310267SGeoffrey.Blake@arm.com    cxx_predecls = ['#include "base/inet.hh"']
55410267SGeoffrey.Blake@arm.com    swig_predecls = ['%include "python/swig/inet.i"']
5557673Snate@binkert.org    def __init__(self, value):
5567673Snate@binkert.org        if value == NextEthernetAddr:
5577673Snate@binkert.org            self.value = value
5587673Snate@binkert.org            return
5597673Snate@binkert.org
5604762Snate@binkert.org        if not isinstance(value, str):
5614762Snate@binkert.org            raise TypeError, "expected an ethernet address and didn't get one"
5624762Snate@binkert.org
5633101Sstever@eecs.umich.edu        bytes = value.split(':')
5643101Sstever@eecs.umich.edu        if len(bytes) != 6:
5653101Sstever@eecs.umich.edu            raise TypeError, 'invalid ethernet address %s' % value
5663101Sstever@eecs.umich.edu
5673101Sstever@eecs.umich.edu        for byte in bytes:
5683101Sstever@eecs.umich.edu            if not 0 <= int(byte) <= 256:
5693101Sstever@eecs.umich.edu                raise TypeError, 'invalid ethernet address %s' % value
5703101Sstever@eecs.umich.edu
5713101Sstever@eecs.umich.edu        self.value = value
5723101Sstever@eecs.umich.edu
5733101Sstever@eecs.umich.edu    def unproxy(self, base):
5743101Sstever@eecs.umich.edu        if self.value == NextEthernetAddr:
5753101Sstever@eecs.umich.edu            return EthernetAddr(self.value())
5763101Sstever@eecs.umich.edu        return self
5773101Sstever@eecs.umich.edu
5783101Sstever@eecs.umich.edu    def getValue(self):
5793101Sstever@eecs.umich.edu        from m5.objects.params import EthAddr
5803101Sstever@eecs.umich.edu        return EthAddr(self.value)
5813101Sstever@eecs.umich.edu
5829184Sandreas.hansson@arm.com    def ini_str(self):
5839184Sandreas.hansson@arm.com        return self.value
5849184Sandreas.hansson@arm.com
5859184Sandreas.hansson@arm.comtime_formats = [ "%a %b %d %H:%M:%S %Z %Y",
5869184Sandreas.hansson@arm.com                 "%a %b %d %H:%M:%S %Z %Y",
5879184Sandreas.hansson@arm.com                 "%Y/%m/%d %H:%M:%S",
58811802Sandreas.sandberg@arm.com                 "%Y/%m/%d %H:%M",
5899184Sandreas.hansson@arm.com                 "%Y/%m/%d",
5909184Sandreas.hansson@arm.com                 "%m/%d/%Y %H:%M:%S",
59110458Sandreas.hansson@arm.com                 "%m/%d/%Y %H:%M",
59210458Sandreas.hansson@arm.com                 "%m/%d/%Y",
59310458Sandreas.hansson@arm.com                 "%m/%d/%y %H:%M:%S",
59410458Sandreas.hansson@arm.com                 "%m/%d/%y %H:%M",
59510458Sandreas.hansson@arm.com                 "%m/%d/%y"]
59610458Sandreas.hansson@arm.com
59710458Sandreas.hansson@arm.com
59810458Sandreas.hansson@arm.comdef parse_time(value):
59910458Sandreas.hansson@arm.com    from time import gmtime, strptime, struct_time, time
60010458Sandreas.hansson@arm.com    from datetime import datetime, date
60110458Sandreas.hansson@arm.com
60210458Sandreas.hansson@arm.com    if isinstance(value, struct_time):
60310458Sandreas.hansson@arm.com        return value
60410458Sandreas.hansson@arm.com
6053101Sstever@eecs.umich.edu    if isinstance(value, (int, long)):
6064446Sbinkertn@umich.edu        return gmtime(value)
60710668SGeoffrey.Blake@arm.com
6083101Sstever@eecs.umich.edu    if isinstance(value, (datetime, date)):
6095468Snate@binkert.org        return value.timetuple()
61010267SGeoffrey.Blake@arm.com
6115468Snate@binkert.org    if isinstance(value, str):
6125468Snate@binkert.org        if value in ('Now', 'Today'):
6135468Snate@binkert.org            return time.gmtime(time.time())
6145468Snate@binkert.org
6155468Snate@binkert.org        for format in time_formats:
61610267SGeoffrey.Blake@arm.com            try:
61710267SGeoffrey.Blake@arm.com                return strptime(value, format)
61810267SGeoffrey.Blake@arm.com            except ValueError:
61910267SGeoffrey.Blake@arm.com                pass
6204762Snate@binkert.org
6214762Snate@binkert.org    raise ValueError, "Could not parse '%s' as a time" % value
6224762Snate@binkert.org
62310380SAndrew.Bardsley@arm.comclass Time(ParamValue):
62410380SAndrew.Bardsley@arm.com    cxx_type = 'tm'
62510380SAndrew.Bardsley@arm.com    cxx_predecls = [ '#include <time.h>' ]
62610458Sandreas.hansson@arm.com    swig_predecls = [ '%include "python/swig/time.i"' ]
62710458Sandreas.hansson@arm.com    def __init__(self, value):
62810458Sandreas.hansson@arm.com        self.value = parse_time(value)
62910458Sandreas.hansson@arm.com
63010458Sandreas.hansson@arm.com    def getValue(self):
63110458Sandreas.hansson@arm.com        from m5.objects.params import tm
63210458Sandreas.hansson@arm.com
63310458Sandreas.hansson@arm.com        c_time = tm()
6343101Sstever@eecs.umich.edu        py_time = self.value
6353101Sstever@eecs.umich.edu
63610267SGeoffrey.Blake@arm.com        # UNIX is years since 1900
6373101Sstever@eecs.umich.edu        c_time.tm_year = py_time.tm_year - 1900;
6383101Sstever@eecs.umich.edu
6393101Sstever@eecs.umich.edu        # Python starts at 1, UNIX starts at 0
6403101Sstever@eecs.umich.edu        c_time.tm_mon =  py_time.tm_mon - 1;
6413101Sstever@eecs.umich.edu        c_time.tm_mday = py_time.tm_mday;
6423101Sstever@eecs.umich.edu        c_time.tm_hour = py_time.tm_hour;
6433102Sstever@eecs.umich.edu        c_time.tm_min = py_time.tm_min;
6443101Sstever@eecs.umich.edu        c_time.tm_sec = py_time.tm_sec;
6453101Sstever@eecs.umich.edu
6463101Sstever@eecs.umich.edu        # Python has 0 as Monday, UNIX is 0 as sunday
6474168Sbinkertn@umich.edu        c_time.tm_wday = py_time.tm_wday + 1
64810267SGeoffrey.Blake@arm.com        if c_time.tm_wday > 6:
6493101Sstever@eecs.umich.edu            c_time.tm_wday -= 7;
6503101Sstever@eecs.umich.edu
6513101Sstever@eecs.umich.edu        # Python starts at 1, Unix starts at 0
6523101Sstever@eecs.umich.edu        c_time.tm_yday = py_time.tm_yday - 1;
6533101Sstever@eecs.umich.edu
6543101Sstever@eecs.umich.edu        return c_time
6553102Sstever@eecs.umich.edu
6563101Sstever@eecs.umich.edu    def __str__(self):
6573101Sstever@eecs.umich.edu        return time.asctime(self.value)
6583101Sstever@eecs.umich.edu
6593101Sstever@eecs.umich.edu    def ini_str(self):
6603101Sstever@eecs.umich.edu        return str(self)
6613101Sstever@eecs.umich.edu
6623101Sstever@eecs.umich.edu# Enumerated types are a little more complex.  The user specifies the
6633101Sstever@eecs.umich.edu# type as Enum(foo) where foo is either a list or dictionary of
6643101Sstever@eecs.umich.edu# alternatives (typically strings, but not necessarily so).  (In the
6653101Sstever@eecs.umich.edu# long run, the integer value of the parameter will be the list index
6663101Sstever@eecs.umich.edu# or the corresponding dictionary value.  For now, since we only check
66710317Smitch.hayenga@arm.com# that the alternative is valid and then spit it into a .ini file,
66810317Smitch.hayenga@arm.com# there's not much point in using the dictionary.)
66910317Smitch.hayenga@arm.com
67010317Smitch.hayenga@arm.com# What Enum() must do is generate a new type encapsulating the
67110317Smitch.hayenga@arm.com# provided list/dictionary so that specific values of the parameter
6723102Sstever@eecs.umich.edu# can be instances of that type.  We define two hidden internal
67310317Smitch.hayenga@arm.com# classes (_ListEnum and _DictEnum) to serve as base classes, then
67410317Smitch.hayenga@arm.com# derive the new type from the appropriate base class on the fly.
67510317Smitch.hayenga@arm.com
67610317Smitch.hayenga@arm.comallEnums = {}
67710317Smitch.hayenga@arm.com# Metaclass for Enum types
6783101Sstever@eecs.umich.educlass MetaEnum(MetaParamValue):
6793584Ssaidi@eecs.umich.edu    def __new__(mcls, name, bases, dict):
6803584Ssaidi@eecs.umich.edu        assert name not in allEnums
6813584Ssaidi@eecs.umich.edu
6823584Ssaidi@eecs.umich.edu        cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict)
6833584Ssaidi@eecs.umich.edu        allEnums[name] = cls
68410267SGeoffrey.Blake@arm.com        return cls
68510267SGeoffrey.Blake@arm.com
68610267SGeoffrey.Blake@arm.com    def __init__(cls, name, bases, init_dict):
68710267SGeoffrey.Blake@arm.com        if init_dict.has_key('map'):
68810267SGeoffrey.Blake@arm.com            if not isinstance(cls.map, dict):
68910267SGeoffrey.Blake@arm.com                raise TypeError, "Enum-derived class attribute 'map' " \
6903101Sstever@eecs.umich.edu                      "must be of type dict"
6919232Sandreas.hansson@arm.com            # build list of value strings from map
6929235Sandreas.hansson@arm.com            cls.vals = cls.map.keys()
6933101Sstever@eecs.umich.edu            cls.vals.sort()
6943101Sstever@eecs.umich.edu        elif init_dict.has_key('vals'):
69510676Sandreas.hansson@arm.com            if not isinstance(cls.vals, list):
6969411Sandreas.hansson@arm.com                raise TypeError, "Enum-derived class attribute 'vals' " \
69710676Sandreas.hansson@arm.com                      "must be of type list"
6989411Sandreas.hansson@arm.com            # build string->value map from vals sequence
6999411Sandreas.hansson@arm.com            cls.map = {}
7009411Sandreas.hansson@arm.com            for idx,val in enumerate(cls.vals):
7013101Sstever@eecs.umich.edu                cls.map[val] = idx
7029411Sandreas.hansson@arm.com        else:
7039411Sandreas.hansson@arm.com            raise TypeError, "Enum-derived class must define "\
7049411Sandreas.hansson@arm.com                  "attribute 'map' or 'vals'"
7053101Sstever@eecs.umich.edu
7069232Sandreas.hansson@arm.com        cls.cxx_type = 'Enums::%s' % name
7073101Sstever@eecs.umich.edu
7089232Sandreas.hansson@arm.com        super(MetaEnum, cls).__init__(name, bases, init_dict)
7093101Sstever@eecs.umich.edu
7103101Sstever@eecs.umich.edu    def __str__(cls):
7113101Sstever@eecs.umich.edu        return cls.__name__
7129411Sandreas.hansson@arm.com
7139411Sandreas.hansson@arm.com    # Generate C++ class declaration for this enum type.
7149411Sandreas.hansson@arm.com    # Note that we wrap the enum in a class/struct to act as a namespace,
71510676Sandreas.hansson@arm.com    # so that the enum strings can be brief w/o worrying about collisions.
71610676Sandreas.hansson@arm.com    def cxx_decl(cls):
7179411Sandreas.hansson@arm.com        code = "#ifndef __ENUM__%s\n" % cls
7189411Sandreas.hansson@arm.com        code += '#define __ENUM__%s\n' % cls
7199411Sandreas.hansson@arm.com        code += '\n'
7209411Sandreas.hansson@arm.com        code += 'namespace Enums {\n'
7219411Sandreas.hansson@arm.com        code += '    enum %s {\n' % cls
7223101Sstever@eecs.umich.edu        for val in cls.vals:
7239232Sandreas.hansson@arm.com            code += '        %s = %d,\n' % (val, cls.map[val])
7243101Sstever@eecs.umich.edu        code += '        Num_%s = %d,\n' % (cls, len(cls.vals))
7253101Sstever@eecs.umich.edu        code += '    };\n'
7263101Sstever@eecs.umich.edu        code += '    extern const char *%sStrings[Num_%s];\n' % (cls, cls)
7273101Sstever@eecs.umich.edu        code += '}\n'
7289232Sandreas.hansson@arm.com        code += '\n'
7293101Sstever@eecs.umich.edu        code += '#endif\n'
7305219Ssaidi@eecs.umich.edu        return code
7319232Sandreas.hansson@arm.com
7329232Sandreas.hansson@arm.com    def cxx_def(cls):
7333101Sstever@eecs.umich.edu        code = '#include "enums/%s.hh"\n' % cls
7349232Sandreas.hansson@arm.com        code += 'namespace Enums {\n'
7359232Sandreas.hansson@arm.com        code += '    const char *%sStrings[Num_%s] =\n' % (cls, cls)
7363101Sstever@eecs.umich.edu        code += '    {\n'
7373101Sstever@eecs.umich.edu        for val in cls.vals:
7389232Sandreas.hansson@arm.com            code += '        "%s",\n' % val
7399232Sandreas.hansson@arm.com        code += '    };\n'
7403101Sstever@eecs.umich.edu        code += '}\n'
7413101Sstever@eecs.umich.edu        return code
7423101Sstever@eecs.umich.edu
7433101Sstever@eecs.umich.edu# Base class for enum types.
7449232Sandreas.hansson@arm.comclass Enum(ParamValue):
7453101Sstever@eecs.umich.edu    __metaclass__ = MetaEnum
7463101Sstever@eecs.umich.edu    vals = []
74711620SMatthew.Poremba@amd.com
74811620SMatthew.Poremba@amd.com    def __init__(self, value):
74911620SMatthew.Poremba@amd.com        if value not in self.map:
7509232Sandreas.hansson@arm.com            raise TypeError, "Enum param got bad value '%s' (not in %s)" \
7519232Sandreas.hansson@arm.com                  % (value, self.vals)
7529411Sandreas.hansson@arm.com        self.value = value
7539411Sandreas.hansson@arm.com
7543101Sstever@eecs.umich.edu    def getValue(self):
7557673Snate@binkert.org        return int(self.map[self.value])
7567673Snate@binkert.org
7579232Sandreas.hansson@arm.com    def __str__(self):
7589235Sandreas.hansson@arm.com        return self.value
7597675Snate@binkert.org
7607675Snate@binkert.org# how big does a rounding error need to be before we warn about it?
76111988Sandreas.sandberg@arm.comfrequency_tolerance = 0.001  # 0.1%
76211988Sandreas.sandberg@arm.com
76311988Sandreas.sandberg@arm.comclass TickParamValue(NumericParamValue):
76411988Sandreas.sandberg@arm.com    cxx_type = 'Tick'
76511988Sandreas.sandberg@arm.com    cxx_predecls = ['#include "sim/host.hh"']
76610458Sandreas.hansson@arm.com    swig_predecls = ['%import "stdint.i"\n' +
76710458Sandreas.hansson@arm.com                     '%import "sim/host.hh"']
76810458Sandreas.hansson@arm.com
76910458Sandreas.hansson@arm.com    def getValue(self):
77010458Sandreas.hansson@arm.com        return long(self.value)
77111620SMatthew.Poremba@amd.com
77211620SMatthew.Poremba@amd.comclass Latency(TickParamValue):
77310458Sandreas.hansson@arm.com    def __init__(self, value):
77410458Sandreas.hansson@arm.com        if isinstance(value, (Latency, Clock)):
77510458Sandreas.hansson@arm.com            self.ticks = value.ticks
77610458Sandreas.hansson@arm.com            self.value = value.value
77710458Sandreas.hansson@arm.com        elif isinstance(value, Frequency):
77811620SMatthew.Poremba@amd.com            self.ticks = value.ticks
77911620SMatthew.Poremba@amd.com            self.value = 1.0 / value.value
78011620SMatthew.Poremba@amd.com        elif value.endswith('t'):
78111620SMatthew.Poremba@amd.com            self.ticks = True
78211620SMatthew.Poremba@amd.com            self.value = int(value[:-1])
78311620SMatthew.Poremba@amd.com        else:
78411620SMatthew.Poremba@amd.com            self.ticks = False
78511620SMatthew.Poremba@amd.com            self.value = convert.toLatency(value)
78611620SMatthew.Poremba@amd.com
78711620SMatthew.Poremba@amd.com    def __getattr__(self, attr):
78810458Sandreas.hansson@arm.com        if attr in ('latency', 'period'):
78910458Sandreas.hansson@arm.com            return self
79010458Sandreas.hansson@arm.com        if attr == 'frequency':
79111620SMatthew.Poremba@amd.com            return Frequency(self)
79211620SMatthew.Poremba@amd.com        raise AttributeError, "Latency object has no attribute '%s'" % attr
79310458Sandreas.hansson@arm.com
79410458Sandreas.hansson@arm.com    def getValue(self):
7954762Snate@binkert.org        if self.ticks or self.value == 0:
79611991Sandreas.sandberg@arm.com            value = self.value
79711802Sandreas.sandberg@arm.com        else:
7984762Snate@binkert.org            value = ticks.fromSeconds(self.value)
7999411Sandreas.hansson@arm.com        return long(value)
80010676Sandreas.hansson@arm.com
80110676Sandreas.hansson@arm.com    # convert latency to ticks
8023101Sstever@eecs.umich.edu    def ini_str(self):
8033101Sstever@eecs.umich.edu        return '%d' % self.getValue()
8043101Sstever@eecs.umich.edu
8053101Sstever@eecs.umich.educlass Frequency(TickParamValue):
8063101Sstever@eecs.umich.edu    def __init__(self, value):
8073101Sstever@eecs.umich.edu        if isinstance(value, (Latency, Clock)):
80810267SGeoffrey.Blake@arm.com            if value.value == 0:
80910267SGeoffrey.Blake@arm.com                self.value = 0
8103101Sstever@eecs.umich.edu            else:
8113101Sstever@eecs.umich.edu                self.value = 1.0 / value.value
8123102Sstever@eecs.umich.edu            self.ticks = value.ticks
8133101Sstever@eecs.umich.edu        elif isinstance(value, Frequency):
8143101Sstever@eecs.umich.edu            self.value = value.value
8153101Sstever@eecs.umich.edu            self.ticks = value.ticks
81610267SGeoffrey.Blake@arm.com        else:
81710267SGeoffrey.Blake@arm.com            self.ticks = False
81810267SGeoffrey.Blake@arm.com            self.value = convert.toFrequency(value)
81910267SGeoffrey.Blake@arm.com
8204762Snate@binkert.org    def __getattr__(self, attr):
8214762Snate@binkert.org        if attr == 'frequency':
8224762Snate@binkert.org            return self
8233101Sstever@eecs.umich.edu        if attr in ('latency', 'period'):
8243101Sstever@eecs.umich.edu            return Latency(self)
8253101Sstever@eecs.umich.edu        raise AttributeError, "Frequency object has no attribute '%s'" % attr
8268934SBrad.Beckmann@amd.com
8278934SBrad.Beckmann@amd.com    # convert latency to ticks
8288934SBrad.Beckmann@amd.com    def getValue(self):
8298934SBrad.Beckmann@amd.com        if self.ticks or self.value == 0:
8308934SBrad.Beckmann@amd.com            value = self.value
8313101Sstever@eecs.umich.edu        else:
8323101Sstever@eecs.umich.edu            value = ticks.fromSeconds(1.0 / self.value)
8333101Sstever@eecs.umich.edu        return long(value)
8343101Sstever@eecs.umich.edu
8353101Sstever@eecs.umich.edu    def ini_str(self):
83610380SAndrew.Bardsley@arm.com        return '%d' % self.getValue()
83710380SAndrew.Bardsley@arm.com
83810380SAndrew.Bardsley@arm.com# A generic frequency and/or Latency value.  Value is stored as a latency,
83910458Sandreas.hansson@arm.com# but to avoid ambiguity this object does not support numeric ops (* or /).
84010458Sandreas.hansson@arm.com# An explicit conversion to a Latency or Frequency must be made first.
84110458Sandreas.hansson@arm.comclass Clock(ParamValue):
84210458Sandreas.hansson@arm.com    cxx_type = 'Tick'
84310458Sandreas.hansson@arm.com    cxx_predecls = ['#include "sim/host.hh"']
84410458Sandreas.hansson@arm.com    swig_predecls = ['%import "stdint.i"\n' +
84510458Sandreas.hansson@arm.com                     '%import "sim/host.hh"']
84610458Sandreas.hansson@arm.com    def __init__(self, value):
84710458Sandreas.hansson@arm.com        if isinstance(value, (Latency, Clock)):
84810458Sandreas.hansson@arm.com            self.ticks = value.ticks
8493101Sstever@eecs.umich.edu            self.value = value.value
8503101Sstever@eecs.umich.edu        elif isinstance(value, Frequency):
8513101Sstever@eecs.umich.edu            self.ticks = value.ticks
8523101Sstever@eecs.umich.edu            self.value = 1.0 / value.value
8533101Sstever@eecs.umich.edu        elif value.endswith('t'):
8543101Sstever@eecs.umich.edu            self.ticks = True
8553101Sstever@eecs.umich.edu            self.value = int(value[:-1])
8563101Sstever@eecs.umich.edu        else:
8573101Sstever@eecs.umich.edu            self.ticks = False
8583101Sstever@eecs.umich.edu            self.value = convert.anyToLatency(value)
8593101Sstever@eecs.umich.edu
8603101Sstever@eecs.umich.edu    def __getattr__(self, attr):
8614380Sbinkertn@umich.edu        if attr == 'frequency':
8624380Sbinkertn@umich.edu            return Frequency(self)
8634380Sbinkertn@umich.edu        if attr in ('latency', 'period'):
8643101Sstever@eecs.umich.edu            return Latency(self)
8654380Sbinkertn@umich.edu        raise AttributeError, "Frequency object has no attribute '%s'" % attr
8664380Sbinkertn@umich.edu
8674380Sbinkertn@umich.edu    def getValue(self):
8683101Sstever@eecs.umich.edu        return self.period.getValue()
8693101Sstever@eecs.umich.edu
8703101Sstever@eecs.umich.edu    def ini_str(self):
87110267SGeoffrey.Blake@arm.com        return self.period.ini_str()
87210267SGeoffrey.Blake@arm.com
8737673Snate@binkert.orgclass NetworkBandwidth(float,ParamValue):
8747673Snate@binkert.org    cxx_type = 'float'
8757673Snate@binkert.org    def __new__(cls, value):
8767673Snate@binkert.org        # convert to bits per second
8777673Snate@binkert.org        val = convert.toNetworkBandwidth(value)
8783101Sstever@eecs.umich.edu        return super(cls, NetworkBandwidth).__new__(cls, val)
8793101Sstever@eecs.umich.edu
8803101Sstever@eecs.umich.edu    def __str__(self):
8813101Sstever@eecs.umich.edu        return str(self.val)
8823101Sstever@eecs.umich.edu
8833101Sstever@eecs.umich.edu    def getValue(self):
8843101Sstever@eecs.umich.edu        # convert to seconds per byte
8853101Sstever@eecs.umich.edu        value = 8.0 / float(self)
8863101Sstever@eecs.umich.edu        # convert to ticks per byte
8873101Sstever@eecs.umich.edu        value = ticks.fromSeconds(value)
8883101Sstever@eecs.umich.edu        return float(value)
8893101Sstever@eecs.umich.edu
8903101Sstever@eecs.umich.edu    def ini_str(self):
8919941SGeoffrey.Blake@arm.com        return '%f' % self.getValue()
8923101Sstever@eecs.umich.edu
8933101Sstever@eecs.umich.educlass MemoryBandwidth(float,ParamValue):
8943101Sstever@eecs.umich.edu    cxx_type = 'float'
8953101Sstever@eecs.umich.edu    def __new__(self, value):
89610267SGeoffrey.Blake@arm.com        # we want the number of ticks per byte of data
89710267SGeoffrey.Blake@arm.com        val = convert.toMemoryBandwidth(value)
89810267SGeoffrey.Blake@arm.com        return super(cls, MemoryBandwidth).__new__(cls, val)
89910267SGeoffrey.Blake@arm.com
9003101Sstever@eecs.umich.edu    def __str__(self):
9013101Sstever@eecs.umich.edu        return str(self.val)
9024380Sbinkertn@umich.edu
9033101Sstever@eecs.umich.edu    def getValue(self):
9043101Sstever@eecs.umich.edu        # convert to seconds per byte
9054762Snate@binkert.org        value = float(self)
90611988Sandreas.sandberg@arm.com        if value:
9074762Snate@binkert.org            value = 1.0 / float(self)
9084762Snate@binkert.org        # convert to ticks per byte
90911228SAndrew.Bardsley@arm.com        value = ticks.fromSeconds(value)
91011228SAndrew.Bardsley@arm.com        return float(value)
91111228SAndrew.Bardsley@arm.com
9124380Sbinkertn@umich.edu    def ini_str(self):
9134380Sbinkertn@umich.edu        return '%f' % self.getValue()
9143101Sstever@eecs.umich.edu
91510458Sandreas.hansson@arm.com#
91610458Sandreas.hansson@arm.com# "Constants"... handy aliases for various values.
91710458Sandreas.hansson@arm.com#
91810458Sandreas.hansson@arm.com
91910458Sandreas.hansson@arm.com# Special class for NULL pointers.  Note the special check in
9207777Sgblack@eecs.umich.edu# make_param_value() above that lets these be assigned where a
9217777Sgblack@eecs.umich.edu# SimObject is required.
9227777Sgblack@eecs.umich.edu# only one copy of a particular node
9237777Sgblack@eecs.umich.educlass NullSimObject(object):
92410267SGeoffrey.Blake@arm.com    __metaclass__ = Singleton
92510267SGeoffrey.Blake@arm.com
9267777Sgblack@eecs.umich.edu    def __call__(cls):
9277777Sgblack@eecs.umich.edu        return cls
9287777Sgblack@eecs.umich.edu
9297777Sgblack@eecs.umich.edu    def _instantiate(self, parent = None, path = ''):
9307777Sgblack@eecs.umich.edu        pass
9317777Sgblack@eecs.umich.edu
9327777Sgblack@eecs.umich.edu    def ini_str(self):
9337777Sgblack@eecs.umich.edu        return 'Null'
9347777Sgblack@eecs.umich.edu
9357777Sgblack@eecs.umich.edu    def unproxy(self, base):
9367777Sgblack@eecs.umich.edu        return self
9377777Sgblack@eecs.umich.edu
9387777Sgblack@eecs.umich.edu    def set_path(self, parent, name):
9397777Sgblack@eecs.umich.edu        pass
9407777Sgblack@eecs.umich.edu
94110267SGeoffrey.Blake@arm.com    def __str__(self):
94210267SGeoffrey.Blake@arm.com        return 'Null'
94310267SGeoffrey.Blake@arm.com
94410267SGeoffrey.Blake@arm.com    def getValue(self):
9458579Ssteve.reinhardt@amd.com        return None
9468579Ssteve.reinhardt@amd.com
9478579Ssteve.reinhardt@amd.com# The only instance you'll ever need...
9488579Ssteve.reinhardt@amd.comNULL = NullSimObject()
9498579Ssteve.reinhardt@amd.com
9508579Ssteve.reinhardt@amd.comdef isNullPointer(value):
9518579Ssteve.reinhardt@amd.com    return isinstance(value, NullSimObject)
9528579Ssteve.reinhardt@amd.com
9538579Ssteve.reinhardt@amd.com# Some memory range specifications use this as a default upper bound.
9548579Ssteve.reinhardt@amd.comMaxAddr = Addr.max
9558579Ssteve.reinhardt@amd.comMaxTick = Tick.max
9568579Ssteve.reinhardt@amd.comAllMemory = AddrRange(0, MaxAddr)
9578579Ssteve.reinhardt@amd.com
9588579Ssteve.reinhardt@amd.com
9598579Ssteve.reinhardt@amd.com#####################################################################
9608579Ssteve.reinhardt@amd.com#
9618579Ssteve.reinhardt@amd.com# Port objects
9628579Ssteve.reinhardt@amd.com#
9637777Sgblack@eecs.umich.edu# Ports are used to interconnect objects in the memory system.
9647777Sgblack@eecs.umich.edu#
9657798Sgblack@eecs.umich.edu#####################################################################
9667777Sgblack@eecs.umich.edu
9677777Sgblack@eecs.umich.edu# Port reference: encapsulates a reference to a particular port on a
96811988Sandreas.sandberg@arm.com# particular SimObject.
9697777Sgblack@eecs.umich.educlass PortRef(object):
9707777Sgblack@eecs.umich.edu    def __init__(self, simobj, name):
9717777Sgblack@eecs.umich.edu        assert(isSimObject(simobj) or isSimObjectClass(simobj))
9727777Sgblack@eecs.umich.edu        self.simobj = simobj
9737777Sgblack@eecs.umich.edu        self.name = name
9747777Sgblack@eecs.umich.edu        self.peer = None   # not associated with another port yet
9757777Sgblack@eecs.umich.edu        self.ccConnected = False # C++ port connection done?
97610267SGeoffrey.Blake@arm.com        self.index = -1  # always -1 for non-vector ports
97710267SGeoffrey.Blake@arm.com
9787777Sgblack@eecs.umich.edu    def __str__(self):
9797777Sgblack@eecs.umich.edu        return '%s.%s' % (self.simobj, self.name)
9807777Sgblack@eecs.umich.edu
9817777Sgblack@eecs.umich.edu    # for config.ini, print peer's name (not ours)
9827777Sgblack@eecs.umich.edu    def ini_str(self):
9837777Sgblack@eecs.umich.edu        return str(self.peer)
9847777Sgblack@eecs.umich.edu
9857777Sgblack@eecs.umich.edu    def __getattr__(self, attr):
9867777Sgblack@eecs.umich.edu        if attr == 'peerObj':
9877777Sgblack@eecs.umich.edu            # shorthand for proxies
9887777Sgblack@eecs.umich.edu            return self.peer.simobj
9897777Sgblack@eecs.umich.edu        raise AttributeError, "'%s' object has no attribute '%s'" % \
9907777Sgblack@eecs.umich.edu              (self.__class__.__name__, attr)
9917777Sgblack@eecs.umich.edu
9927777Sgblack@eecs.umich.edu    # Full connection is symmetric (both ways).  Called via
9937777Sgblack@eecs.umich.edu    # SimObject.__setattr__ as a result of a port assignment, e.g.,
9947777Sgblack@eecs.umich.edu    # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
9957777Sgblack@eecs.umich.edu    # e.g., "obj1.portA[3] = obj2.portB".
9967777Sgblack@eecs.umich.edu    def connect(self, other):
9977777Sgblack@eecs.umich.edu        if isinstance(other, VectorPortRef):
9987777Sgblack@eecs.umich.edu            # reference to plain VectorPort is implicit append
9997777Sgblack@eecs.umich.edu            other = other._get_next()
10007777Sgblack@eecs.umich.edu        if self.peer and not proxy.isproxy(self.peer):
10017777Sgblack@eecs.umich.edu            print "warning: overwriting port", self, \
10027777Sgblack@eecs.umich.edu                  "value", self.peer, "with", other
10037777Sgblack@eecs.umich.edu        self.peer = other
10047777Sgblack@eecs.umich.edu        if proxy.isproxy(other):
10057777Sgblack@eecs.umich.edu            other.set_param_desc(PortParamDesc())
10067777Sgblack@eecs.umich.edu        elif isinstance(other, PortRef):
10077777Sgblack@eecs.umich.edu            if other.peer is not self:
10087777Sgblack@eecs.umich.edu                other.connect(self)
10097777Sgblack@eecs.umich.edu        else:
10107777Sgblack@eecs.umich.edu            raise TypeError, \
10117777Sgblack@eecs.umich.edu                  "assigning non-port reference '%s' to port '%s'" \
10127777Sgblack@eecs.umich.edu                  % (other, self)
10137777Sgblack@eecs.umich.edu
10147777Sgblack@eecs.umich.edu    def clone(self, simobj, memo):
10157777Sgblack@eecs.umich.edu        if memo.has_key(self):
10167777Sgblack@eecs.umich.edu            return memo[self]
10177777Sgblack@eecs.umich.edu        newRef = copy.copy(self)
10187777Sgblack@eecs.umich.edu        memo[self] = newRef
101910267SGeoffrey.Blake@arm.com        newRef.simobj = simobj
102010267SGeoffrey.Blake@arm.com        assert(isSimObject(newRef.simobj))
102110267SGeoffrey.Blake@arm.com        if self.peer and not proxy.isproxy(self.peer):
102210267SGeoffrey.Blake@arm.com            peerObj = self.peer.simobj(_memo=memo)
10238579Ssteve.reinhardt@amd.com            newRef.peer = self.peer.clone(peerObj, memo)
10248579Ssteve.reinhardt@amd.com            assert(not isinstance(newRef.peer, VectorPortRef))
10258579Ssteve.reinhardt@amd.com        return newRef
10268579Ssteve.reinhardt@amd.com
10278579Ssteve.reinhardt@amd.com    def unproxy(self, simobj):
10288579Ssteve.reinhardt@amd.com        assert(simobj is self.simobj)
10298579Ssteve.reinhardt@amd.com        if proxy.isproxy(self.peer):
10308579Ssteve.reinhardt@amd.com            try:
10318579Ssteve.reinhardt@amd.com                realPeer = self.peer.unproxy(self.simobj)
10328579Ssteve.reinhardt@amd.com            except:
10338579Ssteve.reinhardt@amd.com                print "Error in unproxying port '%s' of %s" % \
10348579Ssteve.reinhardt@amd.com                      (self.name, self.simobj.path())
10358579Ssteve.reinhardt@amd.com                raise
10368579Ssteve.reinhardt@amd.com            self.connect(realPeer)
10377777Sgblack@eecs.umich.edu
10387777Sgblack@eecs.umich.edu    # Call C++ to create corresponding port connection between C++ objects
10397777Sgblack@eecs.umich.edu    def ccConnect(self):
10407777Sgblack@eecs.umich.edu        from m5.objects.params import connectPorts
10417777Sgblack@eecs.umich.edu
10427777Sgblack@eecs.umich.edu        if self.ccConnected: # already done this
104311988Sandreas.sandberg@arm.com            return
10447777Sgblack@eecs.umich.edu        peer = self.peer
10457777Sgblack@eecs.umich.edu        connectPorts(self.simobj.getCCObject(), self.name, self.index,
10467777Sgblack@eecs.umich.edu                     peer.simobj.getCCObject(), peer.name, peer.index)
10477777Sgblack@eecs.umich.edu        self.ccConnected = True
10487777Sgblack@eecs.umich.edu        peer.ccConnected = True
10497777Sgblack@eecs.umich.edu
105010267SGeoffrey.Blake@arm.com# A reference to an individual element of a VectorPort... much like a
105110267SGeoffrey.Blake@arm.com# PortRef, but has an index.
10527777Sgblack@eecs.umich.educlass VectorPortElementRef(PortRef):
10537777Sgblack@eecs.umich.edu    def __init__(self, simobj, name, index):
10547777Sgblack@eecs.umich.edu        PortRef.__init__(self, simobj, name)
10557777Sgblack@eecs.umich.edu        self.index = index
10567777Sgblack@eecs.umich.edu
10577777Sgblack@eecs.umich.edu    def __str__(self):
10587777Sgblack@eecs.umich.edu        return '%s.%s[%d]' % (self.simobj, self.name, self.index)
10597777Sgblack@eecs.umich.edu
10607777Sgblack@eecs.umich.edu# A reference to a complete vector-valued port (not just a single element).
10617777Sgblack@eecs.umich.edu# Can be indexed to retrieve individual VectorPortElementRef instances.
10627777Sgblack@eecs.umich.educlass VectorPortRef(object):
10637777Sgblack@eecs.umich.edu    def __init__(self, simobj, name):
10647777Sgblack@eecs.umich.edu        assert(isSimObject(simobj) or isSimObjectClass(simobj))
10657777Sgblack@eecs.umich.edu        self.simobj = simobj
10667777Sgblack@eecs.umich.edu        self.name = name
10677777Sgblack@eecs.umich.edu        self.elements = []
10687777Sgblack@eecs.umich.edu
10697777Sgblack@eecs.umich.edu    def __str__(self):
10707777Sgblack@eecs.umich.edu        return '%s.%s[:]' % (self.simobj, self.name)
10717777Sgblack@eecs.umich.edu
10727777Sgblack@eecs.umich.edu    # for config.ini, print peer's name (not ours)
10737777Sgblack@eecs.umich.edu    def ini_str(self):
10747777Sgblack@eecs.umich.edu        return ' '.join([el.ini_str() for el in self.elements])
10757777Sgblack@eecs.umich.edu
10767777Sgblack@eecs.umich.edu    def __getitem__(self, key):
10777777Sgblack@eecs.umich.edu        if not isinstance(key, int):
10787777Sgblack@eecs.umich.edu            raise TypeError, "VectorPort index must be integer"
10797777Sgblack@eecs.umich.edu        if key >= len(self.elements):
10807777Sgblack@eecs.umich.edu            # need to extend list
10817777Sgblack@eecs.umich.edu            ext = [VectorPortElementRef(self.simobj, self.name, i)
10827777Sgblack@eecs.umich.edu                   for i in range(len(self.elements), key+1)]
10837777Sgblack@eecs.umich.edu            self.elements.extend(ext)
10847777Sgblack@eecs.umich.edu        return self.elements[key]
10857777Sgblack@eecs.umich.edu
10867777Sgblack@eecs.umich.edu    def _get_next(self):
10877777Sgblack@eecs.umich.edu        return self[len(self.elements)]
10887777Sgblack@eecs.umich.edu
10897777Sgblack@eecs.umich.edu    def __setitem__(self, key, value):
10907777Sgblack@eecs.umich.edu        if not isinstance(key, int):
10917777Sgblack@eecs.umich.edu            raise TypeError, "VectorPort index must be integer"
10927777Sgblack@eecs.umich.edu        self[key].connect(value)
109310267SGeoffrey.Blake@arm.com
109410267SGeoffrey.Blake@arm.com    def connect(self, other):
109510267SGeoffrey.Blake@arm.com        if isinstance(other, (list, tuple)):
109610267SGeoffrey.Blake@arm.com            # Assign list of port refs to vector port.
10978579Ssteve.reinhardt@amd.com            # For now, append them... not sure if that's the right semantics
10988579Ssteve.reinhardt@amd.com            # or if it should replace the current vector.
10998579Ssteve.reinhardt@amd.com            for ref in other:
11008579Ssteve.reinhardt@amd.com                self._get_next().connect(ref)
11018579Ssteve.reinhardt@amd.com        else:
11028579Ssteve.reinhardt@amd.com            # scalar assignment to plain VectorPort is implicit append
11038579Ssteve.reinhardt@amd.com            self._get_next().connect(other)
11048579Ssteve.reinhardt@amd.com
11058579Ssteve.reinhardt@amd.com    def clone(self, simobj, memo):
11068579Ssteve.reinhardt@amd.com        if memo.has_key(self):
11078579Ssteve.reinhardt@amd.com            return memo[self]
11088579Ssteve.reinhardt@amd.com        newRef = copy.copy(self)
11098579Ssteve.reinhardt@amd.com        memo[self] = newRef
11108579Ssteve.reinhardt@amd.com        newRef.simobj = simobj
11117777Sgblack@eecs.umich.edu        assert(isSimObject(newRef.simobj))
11127777Sgblack@eecs.umich.edu        newRef.elements = [el.clone(simobj, memo) for el in self.elements]
11137777Sgblack@eecs.umich.edu        return newRef
11147777Sgblack@eecs.umich.edu
11157777Sgblack@eecs.umich.edu    def unproxy(self, simobj):
11167777Sgblack@eecs.umich.edu        [el.unproxy(simobj) for el in self.elements]
111711988Sandreas.sandberg@arm.com
11187777Sgblack@eecs.umich.edu    def ccConnect(self):
11197777Sgblack@eecs.umich.edu        [el.ccConnect() for el in self.elements]
11203932Sbinkertn@umich.edu
112110380SAndrew.Bardsley@arm.com# Port description object.  Like a ParamDesc object, this represents a
11223932Sbinkertn@umich.edu# logical port in the SimObject class, not a particular port on a
11233932Sbinkertn@umich.edu# SimObject instance.  The latter are represented by PortRef objects.
11243932Sbinkertn@umich.educlass Port(object):
11253932Sbinkertn@umich.edu    # Port("description") or Port(default, "description")
11263932Sbinkertn@umich.edu    def __init__(self, *args):
11273932Sbinkertn@umich.edu        if len(args) == 1:
11283932Sbinkertn@umich.edu            self.desc = args[0]
11293932Sbinkertn@umich.edu        elif len(args) == 2:
11303932Sbinkertn@umich.edu            self.default = args[0]
11313932Sbinkertn@umich.edu            self.desc = args[1]
11323932Sbinkertn@umich.edu        else:
11333885Sbinkertn@umich.edu            raise TypeError, 'wrong number of arguments'
11343932Sbinkertn@umich.edu        # self.name is set by SimObject class on assignment
11353932Sbinkertn@umich.edu        # e.g., pio_port = Port("blah") sets self.name to 'pio_port'
11363885Sbinkertn@umich.edu
11373932Sbinkertn@umich.edu    # Generate a PortRef for this port on the given SimObject with the
11383932Sbinkertn@umich.edu    # given name
11393932Sbinkertn@umich.edu    def makeRef(self, simobj):
11403932Sbinkertn@umich.edu        return PortRef(simobj, self.name)
11413932Sbinkertn@umich.edu
11423932Sbinkertn@umich.edu    # Connect an instance of this port (on the given SimObject with
11433932Sbinkertn@umich.edu    # the given name) with the port described by the supplied PortRef
11443932Sbinkertn@umich.edu    def connect(self, simobj, ref):
11453932Sbinkertn@umich.edu        self.makeRef(simobj).connect(ref)
11463932Sbinkertn@umich.edu
11473932Sbinkertn@umich.edu# VectorPort description object.  Like Port, but represents a vector
11483932Sbinkertn@umich.edu# of connections (e.g., as on a Bus).
11493932Sbinkertn@umich.educlass VectorPort(Port):
11503932Sbinkertn@umich.edu    def __init__(self, *args):
11513932Sbinkertn@umich.edu        Port.__init__(self, *args)
11523932Sbinkertn@umich.edu        self.isVec = True
11533932Sbinkertn@umich.edu
11543932Sbinkertn@umich.edu    def makeRef(self, simobj):
11553885Sbinkertn@umich.edu        return VectorPortRef(simobj, self.name)
11563885Sbinkertn@umich.edu
11573885Sbinkertn@umich.edu# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
11583885Sbinkertn@umich.edu# proxy objects (via set_param_desc()) so that proxy error messages
11594762Snate@binkert.org# make sense.
11607673Snate@binkert.orgclass PortParamDesc(object):
11617673Snate@binkert.org    __metaclass__ = Singleton
11627673Snate@binkert.org
11637673Snate@binkert.org    ptype_str = 'Port'
11647673Snate@binkert.org    ptype = Port
11653885Sbinkertn@umich.edu
11663932Sbinkertn@umich.edu__all__ = ['Param', 'VectorParam',
11673885Sbinkertn@umich.edu           'Enum', 'Bool', 'String', 'Float',
116810267SGeoffrey.Blake@arm.com           'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
116910267SGeoffrey.Blake@arm.com           'Int32', 'UInt32', 'Int64', 'UInt64',
117010267SGeoffrey.Blake@arm.com           'Counter', 'Addr', 'Tick', 'Percent',
117110267SGeoffrey.Blake@arm.com           'TcpPort', 'UdpPort', 'EthernetAddr',
11724762Snate@binkert.org           'MemorySize', 'MemorySize32',
117311988Sandreas.sandberg@arm.com           'Latency', 'Frequency', 'Clock',
117411988Sandreas.sandberg@arm.com           'NetworkBandwidth', 'MemoryBandwidth',
11754762Snate@binkert.org           'Range', 'AddrRange', 'TickRange',
117611988Sandreas.sandberg@arm.com           'MaxAddr', 'MaxTick', 'AllMemory',
11774762Snate@binkert.org           'Time',
11783885Sbinkertn@umich.edu           'NextEthernetAddr', 'NULL',
11794762Snate@binkert.org           'Port', 'VectorPort']
11803885Sbinkertn@umich.edu