params.py revision 7673
13101Sstever@eecs.umich.edu# Copyright (c) 2004-2006 The Regents of The University of Michigan
27534Ssteve.reinhardt@amd.com# Copyright (c) 2010 Advanced Micro Devices, Inc.
33101Sstever@eecs.umich.edu# All rights reserved.
43101Sstever@eecs.umich.edu#
53101Sstever@eecs.umich.edu# Redistribution and use in source and binary forms, with or without
63101Sstever@eecs.umich.edu# modification, are permitted provided that the following conditions are
73101Sstever@eecs.umich.edu# met: redistributions of source code must retain the above copyright
83101Sstever@eecs.umich.edu# notice, this list of conditions and the following disclaimer;
93101Sstever@eecs.umich.edu# redistributions in binary form must reproduce the above copyright
103101Sstever@eecs.umich.edu# notice, this list of conditions and the following disclaimer in the
113101Sstever@eecs.umich.edu# documentation and/or other materials provided with the distribution;
123101Sstever@eecs.umich.edu# neither the name of the copyright holders nor the names of its
133101Sstever@eecs.umich.edu# contributors may be used to endorse or promote products derived from
143101Sstever@eecs.umich.edu# this software without specific prior written permission.
153101Sstever@eecs.umich.edu#
163101Sstever@eecs.umich.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
173101Sstever@eecs.umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
183101Sstever@eecs.umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
193101Sstever@eecs.umich.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
203101Sstever@eecs.umich.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
213101Sstever@eecs.umich.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
223101Sstever@eecs.umich.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
233101Sstever@eecs.umich.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
243101Sstever@eecs.umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
253101Sstever@eecs.umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
263101Sstever@eecs.umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
273101Sstever@eecs.umich.edu#
283101Sstever@eecs.umich.edu# Authors: Steve Reinhardt
293101Sstever@eecs.umich.edu#          Nathan Binkert
303101Sstever@eecs.umich.edu
313101Sstever@eecs.umich.edu#####################################################################
323101Sstever@eecs.umich.edu#
333101Sstever@eecs.umich.edu# Parameter description classes
343101Sstever@eecs.umich.edu#
353101Sstever@eecs.umich.edu# The _params dictionary in each class maps parameter names to either
363101Sstever@eecs.umich.edu# a Param or a VectorParam object.  These objects contain the
373101Sstever@eecs.umich.edu# parameter description string, the parameter type, and the default
383101Sstever@eecs.umich.edu# value (if any).  The convert() method on these objects is used to
393101Sstever@eecs.umich.edu# force whatever value is assigned to the parameter to the appropriate
403101Sstever@eecs.umich.edu# type.
413101Sstever@eecs.umich.edu#
423101Sstever@eecs.umich.edu# Note that the default values are loaded into the class's attribute
433101Sstever@eecs.umich.edu# space when the parameter dictionary is initialized (in
443101Sstever@eecs.umich.edu# MetaSimObject._new_param()); after that point they aren't used.
453101Sstever@eecs.umich.edu#
463101Sstever@eecs.umich.edu#####################################################################
473101Sstever@eecs.umich.edu
483885Sbinkertn@umich.eduimport copy
493885Sbinkertn@umich.eduimport datetime
504762Snate@binkert.orgimport re
513885Sbinkertn@umich.eduimport sys
523885Sbinkertn@umich.eduimport time
537528Ssteve.reinhardt@amd.comimport math
543885Sbinkertn@umich.edu
554380Sbinkertn@umich.eduimport proxy
564167Sbinkertn@umich.eduimport ticks
573102Sstever@eecs.umich.edufrom util import *
583101Sstever@eecs.umich.edu
594762Snate@binkert.orgdef isSimObject(*args, **kwargs):
604762Snate@binkert.org    return SimObject.isSimObject(*args, **kwargs)
614762Snate@binkert.org
624762Snate@binkert.orgdef isSimObjectSequence(*args, **kwargs):
634762Snate@binkert.org    return SimObject.isSimObjectSequence(*args, **kwargs)
644762Snate@binkert.org
654762Snate@binkert.orgdef isSimObjectClass(*args, **kwargs):
664762Snate@binkert.org    return SimObject.isSimObjectClass(*args, **kwargs)
674762Snate@binkert.org
685033Smilesck@eecs.umich.eduallParams = {}
695033Smilesck@eecs.umich.edu
705033Smilesck@eecs.umich.educlass MetaParamValue(type):
715033Smilesck@eecs.umich.edu    def __new__(mcls, name, bases, dct):
725033Smilesck@eecs.umich.edu        cls = super(MetaParamValue, mcls).__new__(mcls, name, bases, dct)
735033Smilesck@eecs.umich.edu        assert name not in allParams
745033Smilesck@eecs.umich.edu        allParams[name] = cls
755033Smilesck@eecs.umich.edu        return cls
765033Smilesck@eecs.umich.edu
775033Smilesck@eecs.umich.edu
783101Sstever@eecs.umich.edu# Dummy base class to identify types that are legitimate for SimObject
793101Sstever@eecs.umich.edu# parameters.
803101Sstever@eecs.umich.educlass ParamValue(object):
815033Smilesck@eecs.umich.edu    __metaclass__ = MetaParamValue
823101Sstever@eecs.umich.edu
837673Snate@binkert.org    @classmethod
847673Snate@binkert.org    def cxx_predecls(cls, code):
857673Snate@binkert.org        pass
867673Snate@binkert.org
877673Snate@binkert.org    @classmethod
887673Snate@binkert.org    def swig_predecls(cls, code):
897673Snate@binkert.org        pass
903101Sstever@eecs.umich.edu
913101Sstever@eecs.umich.edu    # default for printing to .ini file is regular string conversion.
923101Sstever@eecs.umich.edu    # will be overridden in some cases
933101Sstever@eecs.umich.edu    def ini_str(self):
943101Sstever@eecs.umich.edu        return str(self)
953101Sstever@eecs.umich.edu
963101Sstever@eecs.umich.edu    # allows us to blithely call unproxy() on things without checking
973101Sstever@eecs.umich.edu    # if they're really proxies or not
983101Sstever@eecs.umich.edu    def unproxy(self, base):
993101Sstever@eecs.umich.edu        return self
1003101Sstever@eecs.umich.edu
1013101Sstever@eecs.umich.edu# Regular parameter description.
1023101Sstever@eecs.umich.educlass ParamDesc(object):
1036656Snate@binkert.org    file_ext = 'ptype'
1046656Snate@binkert.org
1053101Sstever@eecs.umich.edu    def __init__(self, ptype_str, ptype, *args, **kwargs):
1063101Sstever@eecs.umich.edu        self.ptype_str = ptype_str
1073101Sstever@eecs.umich.edu        # remember ptype only if it is provided
1083101Sstever@eecs.umich.edu        if ptype != None:
1093101Sstever@eecs.umich.edu            self.ptype = ptype
1103101Sstever@eecs.umich.edu
1113101Sstever@eecs.umich.edu        if args:
1123101Sstever@eecs.umich.edu            if len(args) == 1:
1133101Sstever@eecs.umich.edu                self.desc = args[0]
1143101Sstever@eecs.umich.edu            elif len(args) == 2:
1153101Sstever@eecs.umich.edu                self.default = args[0]
1163101Sstever@eecs.umich.edu                self.desc = args[1]
1173101Sstever@eecs.umich.edu            else:
1183101Sstever@eecs.umich.edu                raise TypeError, 'too many arguments'
1193101Sstever@eecs.umich.edu
1203101Sstever@eecs.umich.edu        if kwargs.has_key('desc'):
1213101Sstever@eecs.umich.edu            assert(not hasattr(self, 'desc'))
1223101Sstever@eecs.umich.edu            self.desc = kwargs['desc']
1233101Sstever@eecs.umich.edu            del kwargs['desc']
1243101Sstever@eecs.umich.edu
1253101Sstever@eecs.umich.edu        if kwargs.has_key('default'):
1263101Sstever@eecs.umich.edu            assert(not hasattr(self, 'default'))
1273101Sstever@eecs.umich.edu            self.default = kwargs['default']
1283101Sstever@eecs.umich.edu            del kwargs['default']
1293101Sstever@eecs.umich.edu
1303101Sstever@eecs.umich.edu        if kwargs:
1313101Sstever@eecs.umich.edu            raise TypeError, 'extra unknown kwargs %s' % kwargs
1323101Sstever@eecs.umich.edu
1333101Sstever@eecs.umich.edu        if not hasattr(self, 'desc'):
1343101Sstever@eecs.umich.edu            raise TypeError, 'desc attribute missing'
1353101Sstever@eecs.umich.edu
1363101Sstever@eecs.umich.edu    def __getattr__(self, attr):
1373101Sstever@eecs.umich.edu        if attr == 'ptype':
1385033Smilesck@eecs.umich.edu            ptype = SimObject.allClasses[self.ptype_str]
1396656Snate@binkert.org            assert isSimObjectClass(ptype)
1405033Smilesck@eecs.umich.edu            self.ptype = ptype
1415033Smilesck@eecs.umich.edu            return ptype
1425033Smilesck@eecs.umich.edu
1433101Sstever@eecs.umich.edu        raise AttributeError, "'%s' object has no attribute '%s'" % \
1443101Sstever@eecs.umich.edu              (type(self).__name__, attr)
1453101Sstever@eecs.umich.edu
1463101Sstever@eecs.umich.edu    def convert(self, value):
1473101Sstever@eecs.umich.edu        if isinstance(value, proxy.BaseProxy):
1483101Sstever@eecs.umich.edu            value.set_param_desc(self)
1493101Sstever@eecs.umich.edu            return value
1503101Sstever@eecs.umich.edu        if not hasattr(self, 'ptype') and isNullPointer(value):
1513101Sstever@eecs.umich.edu            # deferred evaluation of SimObject; continue to defer if
1523101Sstever@eecs.umich.edu            # we're just assigning a null pointer
1533101Sstever@eecs.umich.edu            return value
1543101Sstever@eecs.umich.edu        if isinstance(value, self.ptype):
1553101Sstever@eecs.umich.edu            return value
1563102Sstever@eecs.umich.edu        if isNullPointer(value) and isSimObjectClass(self.ptype):
1573101Sstever@eecs.umich.edu            return value
1583101Sstever@eecs.umich.edu        return self.ptype(value)
1593101Sstever@eecs.umich.edu
1607673Snate@binkert.org    def cxx_predecls(self, code):
1617673Snate@binkert.org        self.ptype.cxx_predecls(code)
1623101Sstever@eecs.umich.edu
1637673Snate@binkert.org    def swig_predecls(self, code):
1647673Snate@binkert.org        self.ptype.swig_predecls(code)
1653101Sstever@eecs.umich.edu
1667673Snate@binkert.org    def cxx_decl(self, code):
1677673Snate@binkert.org        code('${{self.ptype.cxx_type}} ${{self.name}};')
1683101Sstever@eecs.umich.edu
1693101Sstever@eecs.umich.edu# Vector-valued parameter description.  Just like ParamDesc, except
1703101Sstever@eecs.umich.edu# that the value is a vector (list) of the specified type instead of a
1713101Sstever@eecs.umich.edu# single value.
1723101Sstever@eecs.umich.edu
1733101Sstever@eecs.umich.educlass VectorParamValue(list):
1745033Smilesck@eecs.umich.edu    __metaclass__ = MetaParamValue
1755475Snate@binkert.org    def __setattr__(self, attr, value):
1765475Snate@binkert.org        raise AttributeError, \
1775475Snate@binkert.org              "Not allowed to set %s on '%s'" % (attr, type(self).__name__)
1785475Snate@binkert.org
1793101Sstever@eecs.umich.edu    def ini_str(self):
1803101Sstever@eecs.umich.edu        return ' '.join([v.ini_str() for v in self])
1813101Sstever@eecs.umich.edu
1824762Snate@binkert.org    def getValue(self):
1834762Snate@binkert.org        return [ v.getValue() for v in self ]
1844762Snate@binkert.org
1853101Sstever@eecs.umich.edu    def unproxy(self, base):
1863101Sstever@eecs.umich.edu        return [v.unproxy(base) for v in self]
1873101Sstever@eecs.umich.edu
1887528Ssteve.reinhardt@amd.comclass SimObjectVector(VectorParamValue):
1897528Ssteve.reinhardt@amd.com    # support clone operation
1907528Ssteve.reinhardt@amd.com    def __call__(self, **kwargs):
1917528Ssteve.reinhardt@amd.com        return SimObjectVector([v(**kwargs) for v in self])
1927528Ssteve.reinhardt@amd.com
1937528Ssteve.reinhardt@amd.com    def clear_parent(self, old_parent):
1943101Sstever@eecs.umich.edu        for v in self:
1957528Ssteve.reinhardt@amd.com            v.clear_parent(old_parent)
1967528Ssteve.reinhardt@amd.com
1977528Ssteve.reinhardt@amd.com    def set_parent(self, parent, name):
1987528Ssteve.reinhardt@amd.com        if len(self) == 1:
1997528Ssteve.reinhardt@amd.com            self[0].set_parent(parent, name)
2007528Ssteve.reinhardt@amd.com        else:
2017528Ssteve.reinhardt@amd.com            width = int(math.ceil(math.log(len(self))/math.log(10)))
2027528Ssteve.reinhardt@amd.com            for i,v in enumerate(self):
2037528Ssteve.reinhardt@amd.com                v.set_parent(parent, "%s%0*d" % (name, width, i))
2047528Ssteve.reinhardt@amd.com
2057528Ssteve.reinhardt@amd.com    def get_parent(self):
2067528Ssteve.reinhardt@amd.com        parent_set = set(v._parent for v in self)
2077528Ssteve.reinhardt@amd.com        if len(parent_set) != 1:
2087528Ssteve.reinhardt@amd.com            raise RuntimeError, \
2097528Ssteve.reinhardt@amd.com                  "SimObjectVector elements have inconsistent parent value."
2107528Ssteve.reinhardt@amd.com        return parent_set.pop()
2117528Ssteve.reinhardt@amd.com
2127528Ssteve.reinhardt@amd.com    # return 'cpu0 cpu1' etc. for print_ini()
2137528Ssteve.reinhardt@amd.com    def get_name(self):
2147528Ssteve.reinhardt@amd.com        return ' '.join([v._name for v in self])
2157528Ssteve.reinhardt@amd.com
2167528Ssteve.reinhardt@amd.com    # By iterating through the constituent members of the vector here
2177528Ssteve.reinhardt@amd.com    # we can nicely handle iterating over all a SimObject's children
2187528Ssteve.reinhardt@amd.com    # without having to provide lots of special functions on
2197528Ssteve.reinhardt@amd.com    # SimObjectVector directly.
2207528Ssteve.reinhardt@amd.com    def descendants(self):
2217528Ssteve.reinhardt@amd.com        for v in self:
2227528Ssteve.reinhardt@amd.com            for obj in v.descendants():
2237528Ssteve.reinhardt@amd.com                yield obj
2243101Sstever@eecs.umich.edu
2253101Sstever@eecs.umich.educlass VectorParamDesc(ParamDesc):
2266656Snate@binkert.org    file_ext = 'vptype'
2276656Snate@binkert.org
2283101Sstever@eecs.umich.edu    # Convert assigned value to appropriate type.  If the RHS is not a
2293101Sstever@eecs.umich.edu    # list or tuple, it generates a single-element list.
2303101Sstever@eecs.umich.edu    def convert(self, value):
2313101Sstever@eecs.umich.edu        if isinstance(value, (list, tuple)):
2323101Sstever@eecs.umich.edu            # list: coerce each element into new list
2333101Sstever@eecs.umich.edu            tmp_list = [ ParamDesc.convert(self, v) for v in value ]
2343101Sstever@eecs.umich.edu        else:
2354762Snate@binkert.org            # singleton: coerce to a single-element list
2364762Snate@binkert.org            tmp_list = [ ParamDesc.convert(self, value) ]
2374762Snate@binkert.org
2384762Snate@binkert.org        if isSimObjectSequence(tmp_list):
2397528Ssteve.reinhardt@amd.com            return SimObjectVector(tmp_list)
2404762Snate@binkert.org        else:
2414762Snate@binkert.org            return VectorParamValue(tmp_list)
2424762Snate@binkert.org
2437673Snate@binkert.org    def swig_predecls(self, code):
2447673Snate@binkert.org        code('%include "${{self.ptype_str}}_vptype.i"')
2454762Snate@binkert.org
2467673Snate@binkert.org    def swig_decl(self, code):
2474762Snate@binkert.org        cxx_type = re.sub('std::', '', self.ptype.cxx_type)
2487673Snate@binkert.org        code('%include "std_vector.i"')
2497673Snate@binkert.org        self.ptype.swig_predecls(code)
2507673Snate@binkert.org        code('''\
2517673Snate@binkert.orgnamespace std {
2527673Snate@binkert.org%template(vector_${{self.ptype_str}}) vector< $cxx_type >;
2537673Snate@binkert.org}
2547673Snate@binkert.org''')
2553101Sstever@eecs.umich.edu
2567673Snate@binkert.org    def cxx_predecls(self, code):
2577673Snate@binkert.org        code('#include <vector>')
2587673Snate@binkert.org        self.ptype.cxx_predecls(code)
2593101Sstever@eecs.umich.edu
2607673Snate@binkert.org    def cxx_decl(self, code):
2617673Snate@binkert.org        code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};')
2623101Sstever@eecs.umich.edu
2633101Sstever@eecs.umich.educlass ParamFactory(object):
2643101Sstever@eecs.umich.edu    def __init__(self, param_desc_class, ptype_str = None):
2653101Sstever@eecs.umich.edu        self.param_desc_class = param_desc_class
2663101Sstever@eecs.umich.edu        self.ptype_str = ptype_str
2673101Sstever@eecs.umich.edu
2683101Sstever@eecs.umich.edu    def __getattr__(self, attr):
2693101Sstever@eecs.umich.edu        if self.ptype_str:
2703101Sstever@eecs.umich.edu            attr = self.ptype_str + '.' + attr
2713101Sstever@eecs.umich.edu        return ParamFactory(self.param_desc_class, attr)
2723101Sstever@eecs.umich.edu
2733101Sstever@eecs.umich.edu    # E.g., Param.Int(5, "number of widgets")
2743101Sstever@eecs.umich.edu    def __call__(self, *args, **kwargs):
2753101Sstever@eecs.umich.edu        ptype = None
2763101Sstever@eecs.umich.edu        try:
2775033Smilesck@eecs.umich.edu            ptype = allParams[self.ptype_str]
2785033Smilesck@eecs.umich.edu        except KeyError:
2793101Sstever@eecs.umich.edu            # if name isn't defined yet, assume it's a SimObject, and
2803101Sstever@eecs.umich.edu            # try to resolve it later
2813101Sstever@eecs.umich.edu            pass
2823101Sstever@eecs.umich.edu        return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs)
2833101Sstever@eecs.umich.edu
2843101Sstever@eecs.umich.eduParam = ParamFactory(ParamDesc)
2853101Sstever@eecs.umich.eduVectorParam = ParamFactory(VectorParamDesc)
2863101Sstever@eecs.umich.edu
2873101Sstever@eecs.umich.edu#####################################################################
2883101Sstever@eecs.umich.edu#
2893101Sstever@eecs.umich.edu# Parameter Types
2903101Sstever@eecs.umich.edu#
2913101Sstever@eecs.umich.edu# Though native Python types could be used to specify parameter types
2923101Sstever@eecs.umich.edu# (the 'ptype' field of the Param and VectorParam classes), it's more
2933101Sstever@eecs.umich.edu# flexible to define our own set of types.  This gives us more control
2943101Sstever@eecs.umich.edu# over how Python expressions are converted to values (via the
2953101Sstever@eecs.umich.edu# __init__() constructor) and how these values are printed out (via
2963101Sstever@eecs.umich.edu# the __str__() conversion method).
2973101Sstever@eecs.umich.edu#
2983101Sstever@eecs.umich.edu#####################################################################
2993101Sstever@eecs.umich.edu
3003101Sstever@eecs.umich.edu# String-valued parameter.  Just mixin the ParamValue class with the
3013101Sstever@eecs.umich.edu# built-in str class.
3023101Sstever@eecs.umich.educlass String(ParamValue,str):
3033101Sstever@eecs.umich.edu    cxx_type = 'std::string'
3047673Snate@binkert.org
3057673Snate@binkert.org    @classmethod
3067673Snate@binkert.org    def cxx_predecls(self, code):
3077673Snate@binkert.org        code('#include <string>')
3087673Snate@binkert.org
3097673Snate@binkert.org    @classmethod
3107673Snate@binkert.org    def swig_predecls(cls, code):
3117673Snate@binkert.org        code('%include "std_string.i"')
3124762Snate@binkert.org
3134762Snate@binkert.org    def getValue(self):
3144762Snate@binkert.org        return self
3153101Sstever@eecs.umich.edu
3163101Sstever@eecs.umich.edu# superclass for "numeric" parameter values, to emulate math
3173101Sstever@eecs.umich.edu# operations in a type-safe way.  e.g., a Latency times an int returns
3183101Sstever@eecs.umich.edu# a new Latency object.
3193101Sstever@eecs.umich.educlass NumericParamValue(ParamValue):
3203101Sstever@eecs.umich.edu    def __str__(self):
3213101Sstever@eecs.umich.edu        return str(self.value)
3223101Sstever@eecs.umich.edu
3233101Sstever@eecs.umich.edu    def __float__(self):
3243101Sstever@eecs.umich.edu        return float(self.value)
3253101Sstever@eecs.umich.edu
3263714Sstever@eecs.umich.edu    def __long__(self):
3273714Sstever@eecs.umich.edu        return long(self.value)
3283714Sstever@eecs.umich.edu
3293714Sstever@eecs.umich.edu    def __int__(self):
3303714Sstever@eecs.umich.edu        return int(self.value)
3313714Sstever@eecs.umich.edu
3323101Sstever@eecs.umich.edu    # hook for bounds checking
3333101Sstever@eecs.umich.edu    def _check(self):
3343101Sstever@eecs.umich.edu        return
3353101Sstever@eecs.umich.edu
3363101Sstever@eecs.umich.edu    def __mul__(self, other):
3373101Sstever@eecs.umich.edu        newobj = self.__class__(self)
3383101Sstever@eecs.umich.edu        newobj.value *= other
3393101Sstever@eecs.umich.edu        newobj._check()
3403101Sstever@eecs.umich.edu        return newobj
3413101Sstever@eecs.umich.edu
3423101Sstever@eecs.umich.edu    __rmul__ = __mul__
3433101Sstever@eecs.umich.edu
3443101Sstever@eecs.umich.edu    def __div__(self, other):
3453101Sstever@eecs.umich.edu        newobj = self.__class__(self)
3463101Sstever@eecs.umich.edu        newobj.value /= other
3473101Sstever@eecs.umich.edu        newobj._check()
3483101Sstever@eecs.umich.edu        return newobj
3493101Sstever@eecs.umich.edu
3503101Sstever@eecs.umich.edu    def __sub__(self, other):
3513101Sstever@eecs.umich.edu        newobj = self.__class__(self)
3523101Sstever@eecs.umich.edu        newobj.value -= other
3533101Sstever@eecs.umich.edu        newobj._check()
3543101Sstever@eecs.umich.edu        return newobj
3553101Sstever@eecs.umich.edu
3563101Sstever@eecs.umich.edu# Metaclass for bounds-checked integer parameters.  See CheckedInt.
3575033Smilesck@eecs.umich.educlass CheckedIntType(MetaParamValue):
3583101Sstever@eecs.umich.edu    def __init__(cls, name, bases, dict):
3593101Sstever@eecs.umich.edu        super(CheckedIntType, cls).__init__(name, bases, dict)
3603101Sstever@eecs.umich.edu
3613101Sstever@eecs.umich.edu        # CheckedInt is an abstract base class, so we actually don't
3623101Sstever@eecs.umich.edu        # want to do any processing on it... the rest of this code is
3633101Sstever@eecs.umich.edu        # just for classes that derive from CheckedInt.
3643101Sstever@eecs.umich.edu        if name == 'CheckedInt':
3653101Sstever@eecs.umich.edu            return
3663101Sstever@eecs.umich.edu
3673101Sstever@eecs.umich.edu        if not (hasattr(cls, 'min') and hasattr(cls, 'max')):
3683101Sstever@eecs.umich.edu            if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')):
3693101Sstever@eecs.umich.edu                panic("CheckedInt subclass %s must define either\n" \
3705822Ssaidi@eecs.umich.edu                      "    'min' and 'max' or 'size' and 'unsigned'\n",
3715822Ssaidi@eecs.umich.edu                      name);
3723101Sstever@eecs.umich.edu            if cls.unsigned:
3733101Sstever@eecs.umich.edu                cls.min = 0
3743101Sstever@eecs.umich.edu                cls.max = 2 ** cls.size - 1
3753101Sstever@eecs.umich.edu            else:
3763101Sstever@eecs.umich.edu                cls.min = -(2 ** (cls.size - 1))
3773101Sstever@eecs.umich.edu                cls.max = (2 ** (cls.size - 1)) - 1
3783101Sstever@eecs.umich.edu
3793101Sstever@eecs.umich.edu# Abstract superclass for bounds-checked integer parameters.  This
3803101Sstever@eecs.umich.edu# class is subclassed to generate parameter classes with specific
3813101Sstever@eecs.umich.edu# bounds.  Initialization of the min and max bounds is done in the
3823101Sstever@eecs.umich.edu# metaclass CheckedIntType.__init__.
3833101Sstever@eecs.umich.educlass CheckedInt(NumericParamValue):
3843101Sstever@eecs.umich.edu    __metaclass__ = CheckedIntType
3853101Sstever@eecs.umich.edu
3863101Sstever@eecs.umich.edu    def _check(self):
3873101Sstever@eecs.umich.edu        if not self.min <= self.value <= self.max:
3883101Sstever@eecs.umich.edu            raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
3893101Sstever@eecs.umich.edu                  (self.min, self.value, self.max)
3903101Sstever@eecs.umich.edu
3913101Sstever@eecs.umich.edu    def __init__(self, value):
3923101Sstever@eecs.umich.edu        if isinstance(value, str):
3933102Sstever@eecs.umich.edu            self.value = convert.toInteger(value)
3943714Sstever@eecs.umich.edu        elif isinstance(value, (int, long, float, NumericParamValue)):
3953101Sstever@eecs.umich.edu            self.value = long(value)
3963714Sstever@eecs.umich.edu        else:
3973714Sstever@eecs.umich.edu            raise TypeError, "Can't convert object of type %s to CheckedInt" \
3983714Sstever@eecs.umich.edu                  % type(value).__name__
3993101Sstever@eecs.umich.edu        self._check()
4003101Sstever@eecs.umich.edu
4017673Snate@binkert.org    @classmethod
4027673Snate@binkert.org    def cxx_predecls(cls, code):
4037673Snate@binkert.org        # most derived types require this, so we just do it here once
4047673Snate@binkert.org        code('#include "base/types.hh"')
4057673Snate@binkert.org
4067673Snate@binkert.org    @classmethod
4077673Snate@binkert.org    def swig_predecls(cls, code):
4087673Snate@binkert.org        # most derived types require this, so we just do it here once
4097673Snate@binkert.org        code('%import "stdint.i"')
4107673Snate@binkert.org        code('%import "base/types.hh"')
4117673Snate@binkert.org
4124762Snate@binkert.org    def getValue(self):
4134762Snate@binkert.org        return long(self.value)
4144762Snate@binkert.org
4153101Sstever@eecs.umich.educlass Int(CheckedInt):      cxx_type = 'int';      size = 32; unsigned = False
4163101Sstever@eecs.umich.educlass Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True
4173101Sstever@eecs.umich.edu
4183101Sstever@eecs.umich.educlass Int8(CheckedInt):     cxx_type =   'int8_t'; size =  8; unsigned = False
4193101Sstever@eecs.umich.educlass UInt8(CheckedInt):    cxx_type =  'uint8_t'; size =  8; unsigned = True
4203101Sstever@eecs.umich.educlass Int16(CheckedInt):    cxx_type =  'int16_t'; size = 16; unsigned = False
4213101Sstever@eecs.umich.educlass UInt16(CheckedInt):   cxx_type = 'uint16_t'; size = 16; unsigned = True
4223101Sstever@eecs.umich.educlass Int32(CheckedInt):    cxx_type =  'int32_t'; size = 32; unsigned = False
4233101Sstever@eecs.umich.educlass UInt32(CheckedInt):   cxx_type = 'uint32_t'; size = 32; unsigned = True
4243101Sstever@eecs.umich.educlass Int64(CheckedInt):    cxx_type =  'int64_t'; size = 64; unsigned = False
4253101Sstever@eecs.umich.educlass UInt64(CheckedInt):   cxx_type = 'uint64_t'; size = 64; unsigned = True
4263101Sstever@eecs.umich.edu
4273101Sstever@eecs.umich.educlass Counter(CheckedInt):  cxx_type = 'Counter';  size = 64; unsigned = True
4283101Sstever@eecs.umich.educlass Tick(CheckedInt):     cxx_type = 'Tick';     size = 64; unsigned = True
4293101Sstever@eecs.umich.educlass TcpPort(CheckedInt):  cxx_type = 'uint16_t'; size = 16; unsigned = True
4303101Sstever@eecs.umich.educlass UdpPort(CheckedInt):  cxx_type = 'uint16_t'; size = 16; unsigned = True
4313101Sstever@eecs.umich.edu
4323101Sstever@eecs.umich.educlass Percent(CheckedInt):  cxx_type = 'int'; min = 0; max = 100
4333101Sstever@eecs.umich.edu
4343101Sstever@eecs.umich.educlass Float(ParamValue, float):
4354446Sbinkertn@umich.edu    cxx_type = 'double'
4363101Sstever@eecs.umich.edu
4375468Snate@binkert.org    def __init__(self, value):
4385468Snate@binkert.org        if isinstance(value, (int, long, float, NumericParamValue, Float)):
4395468Snate@binkert.org            self.value = float(value)
4405468Snate@binkert.org        else:
4415468Snate@binkert.org            raise TypeError, "Can't convert object of type %s to Float" \
4425468Snate@binkert.org                  % type(value).__name__
4435468Snate@binkert.org
4444762Snate@binkert.org    def getValue(self):
4454762Snate@binkert.org        return float(self.value)
4464762Snate@binkert.org
4473101Sstever@eecs.umich.educlass MemorySize(CheckedInt):
4483101Sstever@eecs.umich.edu    cxx_type = 'uint64_t'
4493101Sstever@eecs.umich.edu    size = 64
4503101Sstever@eecs.umich.edu    unsigned = True
4513101Sstever@eecs.umich.edu    def __init__(self, value):
4523101Sstever@eecs.umich.edu        if isinstance(value, MemorySize):
4533101Sstever@eecs.umich.edu            self.value = value.value
4543101Sstever@eecs.umich.edu        else:
4553102Sstever@eecs.umich.edu            self.value = convert.toMemorySize(value)
4563101Sstever@eecs.umich.edu        self._check()
4573101Sstever@eecs.umich.edu
4583101Sstever@eecs.umich.educlass MemorySize32(CheckedInt):
4594168Sbinkertn@umich.edu    cxx_type = 'uint32_t'
4603101Sstever@eecs.umich.edu    size = 32
4613101Sstever@eecs.umich.edu    unsigned = True
4623101Sstever@eecs.umich.edu    def __init__(self, value):
4633101Sstever@eecs.umich.edu        if isinstance(value, MemorySize):
4643101Sstever@eecs.umich.edu            self.value = value.value
4653101Sstever@eecs.umich.edu        else:
4663102Sstever@eecs.umich.edu            self.value = convert.toMemorySize(value)
4673101Sstever@eecs.umich.edu        self._check()
4683101Sstever@eecs.umich.edu
4693101Sstever@eecs.umich.educlass Addr(CheckedInt):
4703101Sstever@eecs.umich.edu    cxx_type = 'Addr'
4713101Sstever@eecs.umich.edu    size = 64
4723101Sstever@eecs.umich.edu    unsigned = True
4733101Sstever@eecs.umich.edu    def __init__(self, value):
4743101Sstever@eecs.umich.edu        if isinstance(value, Addr):
4753101Sstever@eecs.umich.edu            self.value = value.value
4763101Sstever@eecs.umich.edu        else:
4773101Sstever@eecs.umich.edu            try:
4783102Sstever@eecs.umich.edu                self.value = convert.toMemorySize(value)
4793101Sstever@eecs.umich.edu            except TypeError:
4803101Sstever@eecs.umich.edu                self.value = long(value)
4813101Sstever@eecs.umich.edu        self._check()
4823584Ssaidi@eecs.umich.edu    def __add__(self, other):
4833584Ssaidi@eecs.umich.edu        if isinstance(other, Addr):
4843584Ssaidi@eecs.umich.edu            return self.value + other.value
4853584Ssaidi@eecs.umich.edu        else:
4863584Ssaidi@eecs.umich.edu            return self.value + other
4873101Sstever@eecs.umich.edu
4883101Sstever@eecs.umich.edu
4895033Smilesck@eecs.umich.educlass MetaRange(MetaParamValue):
4903101Sstever@eecs.umich.edu    def __init__(cls, name, bases, dict):
4913101Sstever@eecs.umich.edu        super(MetaRange, cls).__init__(name, bases, dict)
4923101Sstever@eecs.umich.edu        if name == 'Range':
4933101Sstever@eecs.umich.edu            return
4943101Sstever@eecs.umich.edu        cls.cxx_type = 'Range< %s >' % cls.type.cxx_type
4953101Sstever@eecs.umich.edu
4963101Sstever@eecs.umich.educlass Range(ParamValue):
4973101Sstever@eecs.umich.edu    __metaclass__ = MetaRange
4983101Sstever@eecs.umich.edu    type = Int # default; can be overridden in subclasses
4993101Sstever@eecs.umich.edu    def __init__(self, *args, **kwargs):
5003101Sstever@eecs.umich.edu        def handle_kwargs(self, kwargs):
5013101Sstever@eecs.umich.edu            if 'end' in kwargs:
5023101Sstever@eecs.umich.edu                self.second = self.type(kwargs.pop('end'))
5033101Sstever@eecs.umich.edu            elif 'size' in kwargs:
5043101Sstever@eecs.umich.edu                self.second = self.first + self.type(kwargs.pop('size')) - 1
5053101Sstever@eecs.umich.edu            else:
5063101Sstever@eecs.umich.edu                raise TypeError, "Either end or size must be specified"
5073101Sstever@eecs.umich.edu
5083101Sstever@eecs.umich.edu        if len(args) == 0:
5093101Sstever@eecs.umich.edu            self.first = self.type(kwargs.pop('start'))
5103101Sstever@eecs.umich.edu            handle_kwargs(self, kwargs)
5113101Sstever@eecs.umich.edu
5123101Sstever@eecs.umich.edu        elif len(args) == 1:
5133101Sstever@eecs.umich.edu            if kwargs:
5143101Sstever@eecs.umich.edu                self.first = self.type(args[0])
5153101Sstever@eecs.umich.edu                handle_kwargs(self, kwargs)
5163101Sstever@eecs.umich.edu            elif isinstance(args[0], Range):
5173101Sstever@eecs.umich.edu                self.first = self.type(args[0].first)
5183101Sstever@eecs.umich.edu                self.second = self.type(args[0].second)
5195219Ssaidi@eecs.umich.edu            elif isinstance(args[0], (list, tuple)):
5205219Ssaidi@eecs.umich.edu                self.first = self.type(args[0][0])
5215219Ssaidi@eecs.umich.edu                self.second = self.type(args[0][1])
5223101Sstever@eecs.umich.edu            else:
5233101Sstever@eecs.umich.edu                self.first = self.type(0)
5243101Sstever@eecs.umich.edu                self.second = self.type(args[0]) - 1
5253101Sstever@eecs.umich.edu
5263101Sstever@eecs.umich.edu        elif len(args) == 2:
5273101Sstever@eecs.umich.edu            self.first = self.type(args[0])
5283101Sstever@eecs.umich.edu            self.second = self.type(args[1])
5293101Sstever@eecs.umich.edu        else:
5303101Sstever@eecs.umich.edu            raise TypeError, "Too many arguments specified"
5313101Sstever@eecs.umich.edu
5323101Sstever@eecs.umich.edu        if kwargs:
5333101Sstever@eecs.umich.edu            raise TypeError, "too many keywords: %s" % kwargs.keys()
5343101Sstever@eecs.umich.edu
5353101Sstever@eecs.umich.edu    def __str__(self):
5363101Sstever@eecs.umich.edu        return '%s:%s' % (self.first, self.second)
5373101Sstever@eecs.umich.edu
5387673Snate@binkert.org    @classmethod
5397673Snate@binkert.org    def cxx_predecls(cls, code):
5407673Snate@binkert.org        code('#include "base/range.hh"')
5417673Snate@binkert.org        cls.type.cxx_predecls(code)
5427673Snate@binkert.org
5433101Sstever@eecs.umich.educlass AddrRange(Range):
5443101Sstever@eecs.umich.edu    type = Addr
5457673Snate@binkert.org
5467673Snate@binkert.org    @classmethod
5477673Snate@binkert.org    def swig_predecls(cls, code):
5487673Snate@binkert.org        code('%include "python/swig/range.i"')
5494762Snate@binkert.org
5504762Snate@binkert.org    def getValue(self):
5514762Snate@binkert.org        from m5.objects.params import AddrRange
5524762Snate@binkert.org
5534762Snate@binkert.org        value = AddrRange()
5544762Snate@binkert.org        value.start = long(self.first)
5554762Snate@binkert.org        value.end = long(self.second)
5564762Snate@binkert.org        return value
5573101Sstever@eecs.umich.edu
5583101Sstever@eecs.umich.educlass TickRange(Range):
5593101Sstever@eecs.umich.edu    type = Tick
5607673Snate@binkert.org
5617673Snate@binkert.org    @classmethod
5627673Snate@binkert.org    def swig_predecls(cls, code):
5637673Snate@binkert.org        code('%include "python/swig/range.i"')
5644762Snate@binkert.org
5654762Snate@binkert.org    def getValue(self):
5664762Snate@binkert.org        from m5.objects.params import TickRange
5674762Snate@binkert.org
5684762Snate@binkert.org        value = TickRange()
5694762Snate@binkert.org        value.start = long(self.first)
5704762Snate@binkert.org        value.end = long(self.second)
5714762Snate@binkert.org        return value
5723101Sstever@eecs.umich.edu
5733101Sstever@eecs.umich.edu# Boolean parameter type.  Python doesn't let you subclass bool, since
5743101Sstever@eecs.umich.edu# it doesn't want to let you create multiple instances of True and
5753101Sstever@eecs.umich.edu# False.  Thus this is a little more complicated than String.
5763101Sstever@eecs.umich.educlass Bool(ParamValue):
5773101Sstever@eecs.umich.edu    cxx_type = 'bool'
5783101Sstever@eecs.umich.edu    def __init__(self, value):
5793101Sstever@eecs.umich.edu        try:
5803102Sstever@eecs.umich.edu            self.value = convert.toBool(value)
5813101Sstever@eecs.umich.edu        except TypeError:
5823101Sstever@eecs.umich.edu            self.value = bool(value)
5833101Sstever@eecs.umich.edu
5844762Snate@binkert.org    def getValue(self):
5854762Snate@binkert.org        return bool(self.value)
5864762Snate@binkert.org
5873101Sstever@eecs.umich.edu    def __str__(self):
5883101Sstever@eecs.umich.edu        return str(self.value)
5893101Sstever@eecs.umich.edu
5903101Sstever@eecs.umich.edu    def ini_str(self):
5913101Sstever@eecs.umich.edu        if self.value:
5923101Sstever@eecs.umich.edu            return 'true'
5933101Sstever@eecs.umich.edu        return 'false'
5943101Sstever@eecs.umich.edu
5953101Sstever@eecs.umich.edudef IncEthernetAddr(addr, val = 1):
5963101Sstever@eecs.umich.edu    bytes = map(lambda x: int(x, 16), addr.split(':'))
5973101Sstever@eecs.umich.edu    bytes[5] += val
5983101Sstever@eecs.umich.edu    for i in (5, 4, 3, 2, 1):
5993101Sstever@eecs.umich.edu        val,rem = divmod(bytes[i], 256)
6003101Sstever@eecs.umich.edu        bytes[i] = rem
6013101Sstever@eecs.umich.edu        if val == 0:
6023101Sstever@eecs.umich.edu            break
6033101Sstever@eecs.umich.edu        bytes[i - 1] += val
6043101Sstever@eecs.umich.edu    assert(bytes[0] <= 255)
6053101Sstever@eecs.umich.edu    return ':'.join(map(lambda x: '%02x' % x, bytes))
6063101Sstever@eecs.umich.edu
6074380Sbinkertn@umich.edu_NextEthernetAddr = "00:90:00:00:00:01"
6084380Sbinkertn@umich.edudef NextEthernetAddr():
6094380Sbinkertn@umich.edu    global _NextEthernetAddr
6103101Sstever@eecs.umich.edu
6114380Sbinkertn@umich.edu    value = _NextEthernetAddr
6124380Sbinkertn@umich.edu    _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1)
6134380Sbinkertn@umich.edu    return value
6143101Sstever@eecs.umich.edu
6153101Sstever@eecs.umich.educlass EthernetAddr(ParamValue):
6163101Sstever@eecs.umich.edu    cxx_type = 'Net::EthAddr'
6177673Snate@binkert.org
6187673Snate@binkert.org    @classmethod
6197673Snate@binkert.org    def cxx_predecls(cls, code):
6207673Snate@binkert.org        code('#include "base/inet.hh"')
6217673Snate@binkert.org
6227673Snate@binkert.org    @classmethod
6237673Snate@binkert.org    def swig_predecls(cls, code):
6247673Snate@binkert.org        code('%include "python/swig/inet.i"')
6257673Snate@binkert.org
6263101Sstever@eecs.umich.edu    def __init__(self, value):
6273101Sstever@eecs.umich.edu        if value == NextEthernetAddr:
6283101Sstever@eecs.umich.edu            self.value = value
6293101Sstever@eecs.umich.edu            return
6303101Sstever@eecs.umich.edu
6313101Sstever@eecs.umich.edu        if not isinstance(value, str):
6323101Sstever@eecs.umich.edu            raise TypeError, "expected an ethernet address and didn't get one"
6333101Sstever@eecs.umich.edu
6343101Sstever@eecs.umich.edu        bytes = value.split(':')
6353101Sstever@eecs.umich.edu        if len(bytes) != 6:
6363101Sstever@eecs.umich.edu            raise TypeError, 'invalid ethernet address %s' % value
6373101Sstever@eecs.umich.edu
6383101Sstever@eecs.umich.edu        for byte in bytes:
6393101Sstever@eecs.umich.edu            if not 0 <= int(byte) <= 256:
6403101Sstever@eecs.umich.edu                raise TypeError, 'invalid ethernet address %s' % value
6413101Sstever@eecs.umich.edu
6423101Sstever@eecs.umich.edu        self.value = value
6433101Sstever@eecs.umich.edu
6443101Sstever@eecs.umich.edu    def unproxy(self, base):
6453101Sstever@eecs.umich.edu        if self.value == NextEthernetAddr:
6464380Sbinkertn@umich.edu            return EthernetAddr(self.value())
6473101Sstever@eecs.umich.edu        return self
6483101Sstever@eecs.umich.edu
6494762Snate@binkert.org    def getValue(self):
6504762Snate@binkert.org        from m5.objects.params import EthAddr
6514762Snate@binkert.org        return EthAddr(self.value)
6524762Snate@binkert.org
6534380Sbinkertn@umich.edu    def ini_str(self):
6544380Sbinkertn@umich.edu        return self.value
6553101Sstever@eecs.umich.edu
6563932Sbinkertn@umich.edutime_formats = [ "%a %b %d %H:%M:%S %Z %Y",
6573932Sbinkertn@umich.edu                 "%a %b %d %H:%M:%S %Z %Y",
6583932Sbinkertn@umich.edu                 "%Y/%m/%d %H:%M:%S",
6593932Sbinkertn@umich.edu                 "%Y/%m/%d %H:%M",
6603932Sbinkertn@umich.edu                 "%Y/%m/%d",
6613932Sbinkertn@umich.edu                 "%m/%d/%Y %H:%M:%S",
6623932Sbinkertn@umich.edu                 "%m/%d/%Y %H:%M",
6633932Sbinkertn@umich.edu                 "%m/%d/%Y",
6643932Sbinkertn@umich.edu                 "%m/%d/%y %H:%M:%S",
6653932Sbinkertn@umich.edu                 "%m/%d/%y %H:%M",
6663932Sbinkertn@umich.edu                 "%m/%d/%y"]
6673932Sbinkertn@umich.edu
6683932Sbinkertn@umich.edu
6693885Sbinkertn@umich.edudef parse_time(value):
6703932Sbinkertn@umich.edu    from time import gmtime, strptime, struct_time, time
6713932Sbinkertn@umich.edu    from datetime import datetime, date
6723885Sbinkertn@umich.edu
6733932Sbinkertn@umich.edu    if isinstance(value, struct_time):
6743932Sbinkertn@umich.edu        return value
6753932Sbinkertn@umich.edu
6763932Sbinkertn@umich.edu    if isinstance(value, (int, long)):
6773932Sbinkertn@umich.edu        return gmtime(value)
6783932Sbinkertn@umich.edu
6793932Sbinkertn@umich.edu    if isinstance(value, (datetime, date)):
6803932Sbinkertn@umich.edu        return value.timetuple()
6813932Sbinkertn@umich.edu
6823932Sbinkertn@umich.edu    if isinstance(value, str):
6833932Sbinkertn@umich.edu        if value in ('Now', 'Today'):
6843932Sbinkertn@umich.edu            return time.gmtime(time.time())
6853932Sbinkertn@umich.edu
6863932Sbinkertn@umich.edu        for format in time_formats:
6873932Sbinkertn@umich.edu            try:
6883932Sbinkertn@umich.edu                return strptime(value, format)
6893932Sbinkertn@umich.edu            except ValueError:
6903932Sbinkertn@umich.edu                pass
6913885Sbinkertn@umich.edu
6923885Sbinkertn@umich.edu    raise ValueError, "Could not parse '%s' as a time" % value
6933885Sbinkertn@umich.edu
6943885Sbinkertn@umich.educlass Time(ParamValue):
6954762Snate@binkert.org    cxx_type = 'tm'
6967673Snate@binkert.org
6977673Snate@binkert.org    @classmethod
6987673Snate@binkert.org    def cxx_predecls(cls, code):
6997673Snate@binkert.org        code('#include <time.h>')
7007673Snate@binkert.org
7017673Snate@binkert.org    @classmethod
7027673Snate@binkert.org    def swig_predecls(cls, code):
7037673Snate@binkert.org        code('%include "python/swig/time.i"')
7047673Snate@binkert.org
7053885Sbinkertn@umich.edu    def __init__(self, value):
7063932Sbinkertn@umich.edu        self.value = parse_time(value)
7073885Sbinkertn@umich.edu
7084762Snate@binkert.org    def getValue(self):
7094762Snate@binkert.org        from m5.objects.params import tm
7104762Snate@binkert.org
7114762Snate@binkert.org        c_time = tm()
7124762Snate@binkert.org        py_time = self.value
7134762Snate@binkert.org
7144762Snate@binkert.org        # UNIX is years since 1900
7154762Snate@binkert.org        c_time.tm_year = py_time.tm_year - 1900;
7164762Snate@binkert.org
7174762Snate@binkert.org        # Python starts at 1, UNIX starts at 0
7184762Snate@binkert.org        c_time.tm_mon =  py_time.tm_mon - 1;
7194762Snate@binkert.org        c_time.tm_mday = py_time.tm_mday;
7204762Snate@binkert.org        c_time.tm_hour = py_time.tm_hour;
7214762Snate@binkert.org        c_time.tm_min = py_time.tm_min;
7224762Snate@binkert.org        c_time.tm_sec = py_time.tm_sec;
7234762Snate@binkert.org
7244762Snate@binkert.org        # Python has 0 as Monday, UNIX is 0 as sunday
7254762Snate@binkert.org        c_time.tm_wday = py_time.tm_wday + 1
7264762Snate@binkert.org        if c_time.tm_wday > 6:
7274762Snate@binkert.org            c_time.tm_wday -= 7;
7284762Snate@binkert.org
7294762Snate@binkert.org        # Python starts at 1, Unix starts at 0
7304762Snate@binkert.org        c_time.tm_yday = py_time.tm_yday - 1;
7314762Snate@binkert.org
7324762Snate@binkert.org        return c_time
7334762Snate@binkert.org
7343885Sbinkertn@umich.edu    def __str__(self):
7354762Snate@binkert.org        return time.asctime(self.value)
7363885Sbinkertn@umich.edu
7373885Sbinkertn@umich.edu    def ini_str(self):
7383932Sbinkertn@umich.edu        return str(self)
7393885Sbinkertn@umich.edu
7403101Sstever@eecs.umich.edu# Enumerated types are a little more complex.  The user specifies the
7413101Sstever@eecs.umich.edu# type as Enum(foo) where foo is either a list or dictionary of
7423101Sstever@eecs.umich.edu# alternatives (typically strings, but not necessarily so).  (In the
7433101Sstever@eecs.umich.edu# long run, the integer value of the parameter will be the list index
7443101Sstever@eecs.umich.edu# or the corresponding dictionary value.  For now, since we only check
7453101Sstever@eecs.umich.edu# that the alternative is valid and then spit it into a .ini file,
7463101Sstever@eecs.umich.edu# there's not much point in using the dictionary.)
7473101Sstever@eecs.umich.edu
7483101Sstever@eecs.umich.edu# What Enum() must do is generate a new type encapsulating the
7493101Sstever@eecs.umich.edu# provided list/dictionary so that specific values of the parameter
7503101Sstever@eecs.umich.edu# can be instances of that type.  We define two hidden internal
7513101Sstever@eecs.umich.edu# classes (_ListEnum and _DictEnum) to serve as base classes, then
7523101Sstever@eecs.umich.edu# derive the new type from the appropriate base class on the fly.
7533101Sstever@eecs.umich.edu
7544762Snate@binkert.orgallEnums = {}
7553101Sstever@eecs.umich.edu# Metaclass for Enum types
7565033Smilesck@eecs.umich.educlass MetaEnum(MetaParamValue):
7574762Snate@binkert.org    def __new__(mcls, name, bases, dict):
7584762Snate@binkert.org        assert name not in allEnums
7594762Snate@binkert.org
7604762Snate@binkert.org        cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict)
7614762Snate@binkert.org        allEnums[name] = cls
7624762Snate@binkert.org        return cls
7634762Snate@binkert.org
7643101Sstever@eecs.umich.edu    def __init__(cls, name, bases, init_dict):
7653101Sstever@eecs.umich.edu        if init_dict.has_key('map'):
7663101Sstever@eecs.umich.edu            if not isinstance(cls.map, dict):
7673101Sstever@eecs.umich.edu                raise TypeError, "Enum-derived class attribute 'map' " \
7683101Sstever@eecs.umich.edu                      "must be of type dict"
7693101Sstever@eecs.umich.edu            # build list of value strings from map
7703101Sstever@eecs.umich.edu            cls.vals = cls.map.keys()
7713101Sstever@eecs.umich.edu            cls.vals.sort()
7723101Sstever@eecs.umich.edu        elif init_dict.has_key('vals'):
7733101Sstever@eecs.umich.edu            if not isinstance(cls.vals, list):
7743101Sstever@eecs.umich.edu                raise TypeError, "Enum-derived class attribute 'vals' " \
7753101Sstever@eecs.umich.edu                      "must be of type list"
7763101Sstever@eecs.umich.edu            # build string->value map from vals sequence
7773101Sstever@eecs.umich.edu            cls.map = {}
7783101Sstever@eecs.umich.edu            for idx,val in enumerate(cls.vals):
7793101Sstever@eecs.umich.edu                cls.map[val] = idx
7803101Sstever@eecs.umich.edu        else:
7813101Sstever@eecs.umich.edu            raise TypeError, "Enum-derived class must define "\
7823101Sstever@eecs.umich.edu                  "attribute 'map' or 'vals'"
7833101Sstever@eecs.umich.edu
7844762Snate@binkert.org        cls.cxx_type = 'Enums::%s' % name
7853101Sstever@eecs.umich.edu
7863101Sstever@eecs.umich.edu        super(MetaEnum, cls).__init__(name, bases, init_dict)
7873101Sstever@eecs.umich.edu
7883101Sstever@eecs.umich.edu    # Generate C++ class declaration for this enum type.
7893101Sstever@eecs.umich.edu    # Note that we wrap the enum in a class/struct to act as a namespace,
7903101Sstever@eecs.umich.edu    # so that the enum strings can be brief w/o worrying about collisions.
7917673Snate@binkert.org    def cxx_decl(cls, code):
7926654Snate@binkert.org        name = cls.__name__
7937673Snate@binkert.org        code('''\
7947673Snate@binkert.org#ifndef __ENUM__${name}__
7957673Snate@binkert.org#define __ENUM__${name}__
7967673Snate@binkert.org
7977673Snate@binkert.orgnamespace Enums {
7987673Snate@binkert.org    enum $name {
7997673Snate@binkert.org''')
8007673Snate@binkert.org        code.indent(2)
8014762Snate@binkert.org        for val in cls.vals:
8027673Snate@binkert.org            code('$val = ${{cls.map[val]}},')
8037673Snate@binkert.org        code('Num_$name = ${{len(cls.vals)}},')
8047673Snate@binkert.org        code.dedent(2)
8057673Snate@binkert.org        code('''\
8067673Snate@binkert.org    };
8077673Snate@binkert.orgextern const char *${name}Strings[Num_${name}];
8087673Snate@binkert.org}
8094762Snate@binkert.org
8107673Snate@binkert.org#endif // __ENUM__${name}__
8117673Snate@binkert.org''')
8127673Snate@binkert.org
8137673Snate@binkert.org    def cxx_def(cls, code):
8146654Snate@binkert.org        name = cls.__name__
8157673Snate@binkert.org        code('''\
8167673Snate@binkert.org#include "enums/${name}.hh"
8177673Snate@binkert.orgnamespace Enums {
8187673Snate@binkert.org    const char *${name}Strings[Num_${name}] =
8197673Snate@binkert.org    {
8207673Snate@binkert.org''')
8217673Snate@binkert.org        code.indent(2)
8224762Snate@binkert.org        for val in cls.vals:
8237673Snate@binkert.org            code('"$val",')
8247673Snate@binkert.org        code.dedent(2)
8257673Snate@binkert.org        code('''
8267673Snate@binkert.org    };
8277673Snate@binkert.org/* namespace Enums */ }
8287673Snate@binkert.org''')
8293101Sstever@eecs.umich.edu
8303101Sstever@eecs.umich.edu# Base class for enum types.
8313101Sstever@eecs.umich.educlass Enum(ParamValue):
8323101Sstever@eecs.umich.edu    __metaclass__ = MetaEnum
8333101Sstever@eecs.umich.edu    vals = []
8343101Sstever@eecs.umich.edu
8353101Sstever@eecs.umich.edu    def __init__(self, value):
8363101Sstever@eecs.umich.edu        if value not in self.map:
8373101Sstever@eecs.umich.edu            raise TypeError, "Enum param got bad value '%s' (not in %s)" \
8383101Sstever@eecs.umich.edu                  % (value, self.vals)
8393101Sstever@eecs.umich.edu        self.value = value
8403101Sstever@eecs.umich.edu
8414762Snate@binkert.org    def getValue(self):
8424762Snate@binkert.org        return int(self.map[self.value])
8434762Snate@binkert.org
8443101Sstever@eecs.umich.edu    def __str__(self):
8453101Sstever@eecs.umich.edu        return self.value
8463101Sstever@eecs.umich.edu
8473101Sstever@eecs.umich.edu# how big does a rounding error need to be before we warn about it?
8483101Sstever@eecs.umich.edufrequency_tolerance = 0.001  # 0.1%
8493101Sstever@eecs.umich.edu
8504167Sbinkertn@umich.educlass TickParamValue(NumericParamValue):
8513101Sstever@eecs.umich.edu    cxx_type = 'Tick'
8527673Snate@binkert.org
8537673Snate@binkert.org    @classmethod
8547673Snate@binkert.org    def cxx_predecls(cls, code):
8557673Snate@binkert.org        code('#include "base/types.hh"')
8567673Snate@binkert.org
8577673Snate@binkert.org    @classmethod
8587673Snate@binkert.org    def swig_predecls(cls, code):
8597673Snate@binkert.org        code('%import "stdint.i"')
8607673Snate@binkert.org        code('%import "base/types.hh"')
8614167Sbinkertn@umich.edu
8624762Snate@binkert.org    def getValue(self):
8634762Snate@binkert.org        return long(self.value)
8644762Snate@binkert.org
8654167Sbinkertn@umich.educlass Latency(TickParamValue):
8663101Sstever@eecs.umich.edu    def __init__(self, value):
8674167Sbinkertn@umich.edu        if isinstance(value, (Latency, Clock)):
8684167Sbinkertn@umich.edu            self.ticks = value.ticks
8694167Sbinkertn@umich.edu            self.value = value.value
8704167Sbinkertn@umich.edu        elif isinstance(value, Frequency):
8714167Sbinkertn@umich.edu            self.ticks = value.ticks
8724167Sbinkertn@umich.edu            self.value = 1.0 / value.value
8734167Sbinkertn@umich.edu        elif value.endswith('t'):
8744167Sbinkertn@umich.edu            self.ticks = True
8754167Sbinkertn@umich.edu            self.value = int(value[:-1])
8764167Sbinkertn@umich.edu        else:
8774167Sbinkertn@umich.edu            self.ticks = False
8784167Sbinkertn@umich.edu            self.value = convert.toLatency(value)
8793101Sstever@eecs.umich.edu
8803101Sstever@eecs.umich.edu    def __getattr__(self, attr):
8813101Sstever@eecs.umich.edu        if attr in ('latency', 'period'):
8823101Sstever@eecs.umich.edu            return self
8833101Sstever@eecs.umich.edu        if attr == 'frequency':
8843101Sstever@eecs.umich.edu            return Frequency(self)
8853101Sstever@eecs.umich.edu        raise AttributeError, "Latency object has no attribute '%s'" % attr
8863101Sstever@eecs.umich.edu
8874762Snate@binkert.org    def getValue(self):
8884762Snate@binkert.org        if self.ticks or self.value == 0:
8894762Snate@binkert.org            value = self.value
8904762Snate@binkert.org        else:
8914762Snate@binkert.org            value = ticks.fromSeconds(self.value)
8924762Snate@binkert.org        return long(value)
8934762Snate@binkert.org
8943101Sstever@eecs.umich.edu    # convert latency to ticks
8953101Sstever@eecs.umich.edu    def ini_str(self):
8964762Snate@binkert.org        return '%d' % self.getValue()
8973101Sstever@eecs.umich.edu
8984167Sbinkertn@umich.educlass Frequency(TickParamValue):
8993101Sstever@eecs.umich.edu    def __init__(self, value):
9004167Sbinkertn@umich.edu        if isinstance(value, (Latency, Clock)):
9014167Sbinkertn@umich.edu            if value.value == 0:
9024167Sbinkertn@umich.edu                self.value = 0
9034167Sbinkertn@umich.edu            else:
9044167Sbinkertn@umich.edu                self.value = 1.0 / value.value
9054167Sbinkertn@umich.edu            self.ticks = value.ticks
9064167Sbinkertn@umich.edu        elif isinstance(value, Frequency):
9074167Sbinkertn@umich.edu            self.value = value.value
9084167Sbinkertn@umich.edu            self.ticks = value.ticks
9094167Sbinkertn@umich.edu        else:
9104167Sbinkertn@umich.edu            self.ticks = False
9114167Sbinkertn@umich.edu            self.value = convert.toFrequency(value)
9123101Sstever@eecs.umich.edu
9133101Sstever@eecs.umich.edu    def __getattr__(self, attr):
9143101Sstever@eecs.umich.edu        if attr == 'frequency':
9153101Sstever@eecs.umich.edu            return self
9163101Sstever@eecs.umich.edu        if attr in ('latency', 'period'):
9173101Sstever@eecs.umich.edu            return Latency(self)
9183101Sstever@eecs.umich.edu        raise AttributeError, "Frequency object has no attribute '%s'" % attr
9193101Sstever@eecs.umich.edu
9204167Sbinkertn@umich.edu    # convert latency to ticks
9214762Snate@binkert.org    def getValue(self):
9224762Snate@binkert.org        if self.ticks or self.value == 0:
9234762Snate@binkert.org            value = self.value
9244762Snate@binkert.org        else:
9254762Snate@binkert.org            value = ticks.fromSeconds(1.0 / self.value)
9264762Snate@binkert.org        return long(value)
9274762Snate@binkert.org
9283101Sstever@eecs.umich.edu    def ini_str(self):
9294762Snate@binkert.org        return '%d' % self.getValue()
9303101Sstever@eecs.umich.edu
9313101Sstever@eecs.umich.edu# A generic frequency and/or Latency value.  Value is stored as a latency,
9323101Sstever@eecs.umich.edu# but to avoid ambiguity this object does not support numeric ops (* or /).
9333101Sstever@eecs.umich.edu# An explicit conversion to a Latency or Frequency must be made first.
9343101Sstever@eecs.umich.educlass Clock(ParamValue):
9353101Sstever@eecs.umich.edu    cxx_type = 'Tick'
9367673Snate@binkert.org
9377673Snate@binkert.org    @classmethod
9387673Snate@binkert.org    def cxx_predecls(cls, code):
9397673Snate@binkert.org        code('#include "base/types.hh"')
9407673Snate@binkert.org
9417673Snate@binkert.org    @classmethod
9427673Snate@binkert.org    def swig_predecls(cls, code):
9437673Snate@binkert.org        code('%import "stdint.i"')
9447673Snate@binkert.org        code('%import "base/types.hh"')
9457673Snate@binkert.org
9463101Sstever@eecs.umich.edu    def __init__(self, value):
9474167Sbinkertn@umich.edu        if isinstance(value, (Latency, Clock)):
9484167Sbinkertn@umich.edu            self.ticks = value.ticks
9494167Sbinkertn@umich.edu            self.value = value.value
9504167Sbinkertn@umich.edu        elif isinstance(value, Frequency):
9514167Sbinkertn@umich.edu            self.ticks = value.ticks
9524167Sbinkertn@umich.edu            self.value = 1.0 / value.value
9534167Sbinkertn@umich.edu        elif value.endswith('t'):
9544167Sbinkertn@umich.edu            self.ticks = True
9554167Sbinkertn@umich.edu            self.value = int(value[:-1])
9564167Sbinkertn@umich.edu        else:
9574167Sbinkertn@umich.edu            self.ticks = False
9584167Sbinkertn@umich.edu            self.value = convert.anyToLatency(value)
9593101Sstever@eecs.umich.edu
9603101Sstever@eecs.umich.edu    def __getattr__(self, attr):
9613101Sstever@eecs.umich.edu        if attr == 'frequency':
9623101Sstever@eecs.umich.edu            return Frequency(self)
9633101Sstever@eecs.umich.edu        if attr in ('latency', 'period'):
9643101Sstever@eecs.umich.edu            return Latency(self)
9653101Sstever@eecs.umich.edu        raise AttributeError, "Frequency object has no attribute '%s'" % attr
9663101Sstever@eecs.umich.edu
9674762Snate@binkert.org    def getValue(self):
9684762Snate@binkert.org        return self.period.getValue()
9694762Snate@binkert.org
9703101Sstever@eecs.umich.edu    def ini_str(self):
9713101Sstever@eecs.umich.edu        return self.period.ini_str()
9723101Sstever@eecs.umich.edu
9733101Sstever@eecs.umich.educlass NetworkBandwidth(float,ParamValue):
9743101Sstever@eecs.umich.edu    cxx_type = 'float'
9753101Sstever@eecs.umich.edu    def __new__(cls, value):
9764167Sbinkertn@umich.edu        # convert to bits per second
9774167Sbinkertn@umich.edu        val = convert.toNetworkBandwidth(value)
9783101Sstever@eecs.umich.edu        return super(cls, NetworkBandwidth).__new__(cls, val)
9793101Sstever@eecs.umich.edu
9803101Sstever@eecs.umich.edu    def __str__(self):
9813101Sstever@eecs.umich.edu        return str(self.val)
9823101Sstever@eecs.umich.edu
9834762Snate@binkert.org    def getValue(self):
9844167Sbinkertn@umich.edu        # convert to seconds per byte
9854167Sbinkertn@umich.edu        value = 8.0 / float(self)
9864167Sbinkertn@umich.edu        # convert to ticks per byte
9874762Snate@binkert.org        value = ticks.fromSeconds(value)
9884762Snate@binkert.org        return float(value)
9894762Snate@binkert.org
9904762Snate@binkert.org    def ini_str(self):
9914762Snate@binkert.org        return '%f' % self.getValue()
9923101Sstever@eecs.umich.edu
9933101Sstever@eecs.umich.educlass MemoryBandwidth(float,ParamValue):
9943101Sstever@eecs.umich.edu    cxx_type = 'float'
9955469Snate@binkert.org    def __new__(cls, value):
9964167Sbinkertn@umich.edu        # we want the number of ticks per byte of data
9973102Sstever@eecs.umich.edu        val = convert.toMemoryBandwidth(value)
9983101Sstever@eecs.umich.edu        return super(cls, MemoryBandwidth).__new__(cls, val)
9993101Sstever@eecs.umich.edu
10003101Sstever@eecs.umich.edu    def __str__(self):
10013101Sstever@eecs.umich.edu        return str(self.val)
10023101Sstever@eecs.umich.edu
10034762Snate@binkert.org    def getValue(self):
10044167Sbinkertn@umich.edu        # convert to seconds per byte
10055468Snate@binkert.org        value = float(self)
10065468Snate@binkert.org        if value:
10075468Snate@binkert.org            value = 1.0 / float(self)
10084167Sbinkertn@umich.edu        # convert to ticks per byte
10094762Snate@binkert.org        value = ticks.fromSeconds(value)
10104762Snate@binkert.org        return float(value)
10114762Snate@binkert.org
10124762Snate@binkert.org    def ini_str(self):
10134762Snate@binkert.org        return '%f' % self.getValue()
10143101Sstever@eecs.umich.edu
10153101Sstever@eecs.umich.edu#
10163101Sstever@eecs.umich.edu# "Constants"... handy aliases for various values.
10173101Sstever@eecs.umich.edu#
10183101Sstever@eecs.umich.edu
10193102Sstever@eecs.umich.edu# Special class for NULL pointers.  Note the special check in
10203102Sstever@eecs.umich.edu# make_param_value() above that lets these be assigned where a
10213102Sstever@eecs.umich.edu# SimObject is required.
10223102Sstever@eecs.umich.edu# only one copy of a particular node
10233102Sstever@eecs.umich.educlass NullSimObject(object):
10243102Sstever@eecs.umich.edu    __metaclass__ = Singleton
10253102Sstever@eecs.umich.edu
10263102Sstever@eecs.umich.edu    def __call__(cls):
10273102Sstever@eecs.umich.edu        return cls
10283102Sstever@eecs.umich.edu
10293102Sstever@eecs.umich.edu    def _instantiate(self, parent = None, path = ''):
10303102Sstever@eecs.umich.edu        pass
10313102Sstever@eecs.umich.edu
10323102Sstever@eecs.umich.edu    def ini_str(self):
10333102Sstever@eecs.umich.edu        return 'Null'
10343102Sstever@eecs.umich.edu
10353102Sstever@eecs.umich.edu    def unproxy(self, base):
10363102Sstever@eecs.umich.edu        return self
10373102Sstever@eecs.umich.edu
10383102Sstever@eecs.umich.edu    def set_path(self, parent, name):
10393102Sstever@eecs.umich.edu        pass
10404762Snate@binkert.org
10413102Sstever@eecs.umich.edu    def __str__(self):
10423102Sstever@eecs.umich.edu        return 'Null'
10433102Sstever@eecs.umich.edu
10444762Snate@binkert.org    def getValue(self):
10454762Snate@binkert.org        return None
10464762Snate@binkert.org
10473102Sstever@eecs.umich.edu# The only instance you'll ever need...
10483102Sstever@eecs.umich.eduNULL = NullSimObject()
10493102Sstever@eecs.umich.edu
10503102Sstever@eecs.umich.edudef isNullPointer(value):
10513102Sstever@eecs.umich.edu    return isinstance(value, NullSimObject)
10523102Sstever@eecs.umich.edu
10533101Sstever@eecs.umich.edu# Some memory range specifications use this as a default upper bound.
10543101Sstever@eecs.umich.eduMaxAddr = Addr.max
10553101Sstever@eecs.umich.eduMaxTick = Tick.max
10563101Sstever@eecs.umich.eduAllMemory = AddrRange(0, MaxAddr)
10573101Sstever@eecs.umich.edu
10583101Sstever@eecs.umich.edu
10593101Sstever@eecs.umich.edu#####################################################################
10603101Sstever@eecs.umich.edu#
10613101Sstever@eecs.umich.edu# Port objects
10623101Sstever@eecs.umich.edu#
10633101Sstever@eecs.umich.edu# Ports are used to interconnect objects in the memory system.
10643101Sstever@eecs.umich.edu#
10653101Sstever@eecs.umich.edu#####################################################################
10663101Sstever@eecs.umich.edu
10673101Sstever@eecs.umich.edu# Port reference: encapsulates a reference to a particular port on a
10683101Sstever@eecs.umich.edu# particular SimObject.
10693101Sstever@eecs.umich.educlass PortRef(object):
10703105Sstever@eecs.umich.edu    def __init__(self, simobj, name):
10713105Sstever@eecs.umich.edu        assert(isSimObject(simobj) or isSimObjectClass(simobj))
10723101Sstever@eecs.umich.edu        self.simobj = simobj
10733101Sstever@eecs.umich.edu        self.name = name
10743101Sstever@eecs.umich.edu        self.peer = None   # not associated with another port yet
10753101Sstever@eecs.umich.edu        self.ccConnected = False # C++ port connection done?
10763105Sstever@eecs.umich.edu        self.index = -1  # always -1 for non-vector ports
10773101Sstever@eecs.umich.edu
10783103Sstever@eecs.umich.edu    def __str__(self):
10793105Sstever@eecs.umich.edu        return '%s.%s' % (self.simobj, self.name)
10803103Sstever@eecs.umich.edu
10813105Sstever@eecs.umich.edu    # for config.ini, print peer's name (not ours)
10823105Sstever@eecs.umich.edu    def ini_str(self):
10833105Sstever@eecs.umich.edu        return str(self.peer)
10843105Sstever@eecs.umich.edu
10853105Sstever@eecs.umich.edu    def __getattr__(self, attr):
10863105Sstever@eecs.umich.edu        if attr == 'peerObj':
10873105Sstever@eecs.umich.edu            # shorthand for proxies
10883105Sstever@eecs.umich.edu            return self.peer.simobj
10893105Sstever@eecs.umich.edu        raise AttributeError, "'%s' object has no attribute '%s'" % \
10903105Sstever@eecs.umich.edu              (self.__class__.__name__, attr)
10913105Sstever@eecs.umich.edu
10923105Sstever@eecs.umich.edu    # Full connection is symmetric (both ways).  Called via
10933105Sstever@eecs.umich.edu    # SimObject.__setattr__ as a result of a port assignment, e.g.,
10943109Sstever@eecs.umich.edu    # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
10953105Sstever@eecs.umich.edu    # e.g., "obj1.portA[3] = obj2.portB".
10963105Sstever@eecs.umich.edu    def connect(self, other):
10973105Sstever@eecs.umich.edu        if isinstance(other, VectorPortRef):
10983105Sstever@eecs.umich.edu            # reference to plain VectorPort is implicit append
10993105Sstever@eecs.umich.edu            other = other._get_next()
11003105Sstever@eecs.umich.edu        if self.peer and not proxy.isproxy(self.peer):
11013105Sstever@eecs.umich.edu            print "warning: overwriting port", self, \
11023105Sstever@eecs.umich.edu                  "value", self.peer, "with", other
11035578SSteve.Reinhardt@amd.com            self.peer.peer = None
11043101Sstever@eecs.umich.edu        self.peer = other
11053109Sstever@eecs.umich.edu        if proxy.isproxy(other):
11063109Sstever@eecs.umich.edu            other.set_param_desc(PortParamDesc())
11073109Sstever@eecs.umich.edu        elif isinstance(other, PortRef):
11083109Sstever@eecs.umich.edu            if other.peer is not self:
11093109Sstever@eecs.umich.edu                other.connect(self)
11103109Sstever@eecs.umich.edu        else:
11113109Sstever@eecs.umich.edu            raise TypeError, \
11123109Sstever@eecs.umich.edu                  "assigning non-port reference '%s' to port '%s'" \
11133109Sstever@eecs.umich.edu                  % (other, self)
11143101Sstever@eecs.umich.edu
11153105Sstever@eecs.umich.edu    def clone(self, simobj, memo):
11163105Sstever@eecs.umich.edu        if memo.has_key(self):
11173105Sstever@eecs.umich.edu            return memo[self]
11183101Sstever@eecs.umich.edu        newRef = copy.copy(self)
11193105Sstever@eecs.umich.edu        memo[self] = newRef
11203105Sstever@eecs.umich.edu        newRef.simobj = simobj
11213101Sstever@eecs.umich.edu        assert(isSimObject(newRef.simobj))
11223105Sstever@eecs.umich.edu        if self.peer and not proxy.isproxy(self.peer):
11233179Sstever@eecs.umich.edu            peerObj = self.peer.simobj(_memo=memo)
11243105Sstever@eecs.umich.edu            newRef.peer = self.peer.clone(peerObj, memo)
11253105Sstever@eecs.umich.edu            assert(not isinstance(newRef.peer, VectorPortRef))
11263101Sstever@eecs.umich.edu        return newRef
11273101Sstever@eecs.umich.edu
11283105Sstever@eecs.umich.edu    def unproxy(self, simobj):
11293105Sstever@eecs.umich.edu        assert(simobj is self.simobj)
11303105Sstever@eecs.umich.edu        if proxy.isproxy(self.peer):
11313105Sstever@eecs.umich.edu            try:
11323105Sstever@eecs.umich.edu                realPeer = self.peer.unproxy(self.simobj)
11333105Sstever@eecs.umich.edu            except:
11343105Sstever@eecs.umich.edu                print "Error in unproxying port '%s' of %s" % \
11353105Sstever@eecs.umich.edu                      (self.name, self.simobj.path())
11363105Sstever@eecs.umich.edu                raise
11373105Sstever@eecs.umich.edu            self.connect(realPeer)
11383105Sstever@eecs.umich.edu
11393101Sstever@eecs.umich.edu    # Call C++ to create corresponding port connection between C++ objects
11403101Sstever@eecs.umich.edu    def ccConnect(self):
11414859Snate@binkert.org        from m5.objects.params import connectPorts
11424762Snate@binkert.org
11433101Sstever@eecs.umich.edu        if self.ccConnected: # already done this
11443101Sstever@eecs.umich.edu            return
11453101Sstever@eecs.umich.edu        peer = self.peer
11465578SSteve.Reinhardt@amd.com        if not self.peer: # nothing to connect to
11475578SSteve.Reinhardt@amd.com            return
11487526Ssteve.reinhardt@amd.com        try:
11497526Ssteve.reinhardt@amd.com            connectPorts(self.simobj.getCCObject(), self.name, self.index,
11507526Ssteve.reinhardt@amd.com                         peer.simobj.getCCObject(), peer.name, peer.index)
11517526Ssteve.reinhardt@amd.com        except:
11527526Ssteve.reinhardt@amd.com            print "Error connecting port %s.%s to %s.%s" % \
11537526Ssteve.reinhardt@amd.com                  (self.simobj.path(), self.name,
11547526Ssteve.reinhardt@amd.com                   peer.simobj.path(), peer.name)
11557526Ssteve.reinhardt@amd.com            raise
11563101Sstever@eecs.umich.edu        self.ccConnected = True
11573101Sstever@eecs.umich.edu        peer.ccConnected = True
11583101Sstever@eecs.umich.edu
11593105Sstever@eecs.umich.edu# A reference to an individual element of a VectorPort... much like a
11603105Sstever@eecs.umich.edu# PortRef, but has an index.
11613105Sstever@eecs.umich.educlass VectorPortElementRef(PortRef):
11623105Sstever@eecs.umich.edu    def __init__(self, simobj, name, index):
11633105Sstever@eecs.umich.edu        PortRef.__init__(self, simobj, name)
11643105Sstever@eecs.umich.edu        self.index = index
11653105Sstever@eecs.umich.edu
11663105Sstever@eecs.umich.edu    def __str__(self):
11673105Sstever@eecs.umich.edu        return '%s.%s[%d]' % (self.simobj, self.name, self.index)
11683105Sstever@eecs.umich.edu
11693105Sstever@eecs.umich.edu# A reference to a complete vector-valued port (not just a single element).
11703105Sstever@eecs.umich.edu# Can be indexed to retrieve individual VectorPortElementRef instances.
11713105Sstever@eecs.umich.educlass VectorPortRef(object):
11723105Sstever@eecs.umich.edu    def __init__(self, simobj, name):
11733105Sstever@eecs.umich.edu        assert(isSimObject(simobj) or isSimObjectClass(simobj))
11743105Sstever@eecs.umich.edu        self.simobj = simobj
11753105Sstever@eecs.umich.edu        self.name = name
11763105Sstever@eecs.umich.edu        self.elements = []
11773105Sstever@eecs.umich.edu
11783109Sstever@eecs.umich.edu    def __str__(self):
11793109Sstever@eecs.umich.edu        return '%s.%s[:]' % (self.simobj, self.name)
11803109Sstever@eecs.umich.edu
11813105Sstever@eecs.umich.edu    # for config.ini, print peer's name (not ours)
11823105Sstever@eecs.umich.edu    def ini_str(self):
11833105Sstever@eecs.umich.edu        return ' '.join([el.ini_str() for el in self.elements])
11843105Sstever@eecs.umich.edu
11853105Sstever@eecs.umich.edu    def __getitem__(self, key):
11863105Sstever@eecs.umich.edu        if not isinstance(key, int):
11873105Sstever@eecs.umich.edu            raise TypeError, "VectorPort index must be integer"
11883105Sstever@eecs.umich.edu        if key >= len(self.elements):
11893105Sstever@eecs.umich.edu            # need to extend list
11903105Sstever@eecs.umich.edu            ext = [VectorPortElementRef(self.simobj, self.name, i)
11913105Sstever@eecs.umich.edu                   for i in range(len(self.elements), key+1)]
11923105Sstever@eecs.umich.edu            self.elements.extend(ext)
11933105Sstever@eecs.umich.edu        return self.elements[key]
11943105Sstever@eecs.umich.edu
11953105Sstever@eecs.umich.edu    def _get_next(self):
11963105Sstever@eecs.umich.edu        return self[len(self.elements)]
11973105Sstever@eecs.umich.edu
11983105Sstever@eecs.umich.edu    def __setitem__(self, key, value):
11993105Sstever@eecs.umich.edu        if not isinstance(key, int):
12003105Sstever@eecs.umich.edu            raise TypeError, "VectorPort index must be integer"
12013105Sstever@eecs.umich.edu        self[key].connect(value)
12023105Sstever@eecs.umich.edu
12033105Sstever@eecs.umich.edu    def connect(self, other):
12043109Sstever@eecs.umich.edu        if isinstance(other, (list, tuple)):
12053109Sstever@eecs.umich.edu            # Assign list of port refs to vector port.
12063109Sstever@eecs.umich.edu            # For now, append them... not sure if that's the right semantics
12073109Sstever@eecs.umich.edu            # or if it should replace the current vector.
12083109Sstever@eecs.umich.edu            for ref in other:
12093109Sstever@eecs.umich.edu                self._get_next().connect(ref)
12103109Sstever@eecs.umich.edu        else:
12113109Sstever@eecs.umich.edu            # scalar assignment to plain VectorPort is implicit append
12123109Sstever@eecs.umich.edu            self._get_next().connect(other)
12133109Sstever@eecs.umich.edu
12143109Sstever@eecs.umich.edu    def clone(self, simobj, memo):
12153109Sstever@eecs.umich.edu        if memo.has_key(self):
12163109Sstever@eecs.umich.edu            return memo[self]
12173109Sstever@eecs.umich.edu        newRef = copy.copy(self)
12183109Sstever@eecs.umich.edu        memo[self] = newRef
12193109Sstever@eecs.umich.edu        newRef.simobj = simobj
12203109Sstever@eecs.umich.edu        assert(isSimObject(newRef.simobj))
12213109Sstever@eecs.umich.edu        newRef.elements = [el.clone(simobj, memo) for el in self.elements]
12223109Sstever@eecs.umich.edu        return newRef
12233105Sstever@eecs.umich.edu
12243105Sstever@eecs.umich.edu    def unproxy(self, simobj):
12253105Sstever@eecs.umich.edu        [el.unproxy(simobj) for el in self.elements]
12263105Sstever@eecs.umich.edu
12273105Sstever@eecs.umich.edu    def ccConnect(self):
12283105Sstever@eecs.umich.edu        [el.ccConnect() for el in self.elements]
12293105Sstever@eecs.umich.edu
12303101Sstever@eecs.umich.edu# Port description object.  Like a ParamDesc object, this represents a
12313101Sstever@eecs.umich.edu# logical port in the SimObject class, not a particular port on a
12323101Sstever@eecs.umich.edu# SimObject instance.  The latter are represented by PortRef objects.
12333101Sstever@eecs.umich.educlass Port(object):
12343105Sstever@eecs.umich.edu    # Port("description") or Port(default, "description")
12353105Sstever@eecs.umich.edu    def __init__(self, *args):
12363105Sstever@eecs.umich.edu        if len(args) == 1:
12373105Sstever@eecs.umich.edu            self.desc = args[0]
12383105Sstever@eecs.umich.edu        elif len(args) == 2:
12393105Sstever@eecs.umich.edu            self.default = args[0]
12403105Sstever@eecs.umich.edu            self.desc = args[1]
12413105Sstever@eecs.umich.edu        else:
12423105Sstever@eecs.umich.edu            raise TypeError, 'wrong number of arguments'
12433105Sstever@eecs.umich.edu        # self.name is set by SimObject class on assignment
12443105Sstever@eecs.umich.edu        # e.g., pio_port = Port("blah") sets self.name to 'pio_port'
12453101Sstever@eecs.umich.edu
12463101Sstever@eecs.umich.edu    # Generate a PortRef for this port on the given SimObject with the
12473101Sstever@eecs.umich.edu    # given name
12483105Sstever@eecs.umich.edu    def makeRef(self, simobj):
12493105Sstever@eecs.umich.edu        return PortRef(simobj, self.name)
12503101Sstever@eecs.umich.edu
12513101Sstever@eecs.umich.edu    # Connect an instance of this port (on the given SimObject with
12523101Sstever@eecs.umich.edu    # the given name) with the port described by the supplied PortRef
12533105Sstever@eecs.umich.edu    def connect(self, simobj, ref):
12543105Sstever@eecs.umich.edu        self.makeRef(simobj).connect(ref)
12553101Sstever@eecs.umich.edu
12563101Sstever@eecs.umich.edu# VectorPort description object.  Like Port, but represents a vector
12573101Sstever@eecs.umich.edu# of connections (e.g., as on a Bus).
12583101Sstever@eecs.umich.educlass VectorPort(Port):
12593105Sstever@eecs.umich.edu    def __init__(self, *args):
12603105Sstever@eecs.umich.edu        Port.__init__(self, *args)
12613101Sstever@eecs.umich.edu        self.isVec = True
12623101Sstever@eecs.umich.edu
12633105Sstever@eecs.umich.edu    def makeRef(self, simobj):
12643105Sstever@eecs.umich.edu        return VectorPortRef(simobj, self.name)
12653105Sstever@eecs.umich.edu
12663109Sstever@eecs.umich.edu# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
12673109Sstever@eecs.umich.edu# proxy objects (via set_param_desc()) so that proxy error messages
12683109Sstever@eecs.umich.edu# make sense.
12693109Sstever@eecs.umich.educlass PortParamDesc(object):
12703109Sstever@eecs.umich.edu    __metaclass__ = Singleton
12713109Sstever@eecs.umich.edu
12723109Sstever@eecs.umich.edu    ptype_str = 'Port'
12733109Sstever@eecs.umich.edu    ptype = Port
12743105Sstever@eecs.umich.edu
12756654Snate@binkert.orgbaseEnums = allEnums.copy()
12766654Snate@binkert.orgbaseParams = allParams.copy()
12776654Snate@binkert.org
12786654Snate@binkert.orgdef clear():
12796654Snate@binkert.org    global allEnums, allParams
12806654Snate@binkert.org
12816654Snate@binkert.org    allEnums = baseEnums.copy()
12826654Snate@binkert.org    allParams = baseParams.copy()
12836654Snate@binkert.org
12843101Sstever@eecs.umich.edu__all__ = ['Param', 'VectorParam',
12853101Sstever@eecs.umich.edu           'Enum', 'Bool', 'String', 'Float',
12863101Sstever@eecs.umich.edu           'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
12873101Sstever@eecs.umich.edu           'Int32', 'UInt32', 'Int64', 'UInt64',
12883101Sstever@eecs.umich.edu           'Counter', 'Addr', 'Tick', 'Percent',
12893101Sstever@eecs.umich.edu           'TcpPort', 'UdpPort', 'EthernetAddr',
12903101Sstever@eecs.umich.edu           'MemorySize', 'MemorySize32',
12914167Sbinkertn@umich.edu           'Latency', 'Frequency', 'Clock',
12923101Sstever@eecs.umich.edu           'NetworkBandwidth', 'MemoryBandwidth',
12933101Sstever@eecs.umich.edu           'Range', 'AddrRange', 'TickRange',
12943101Sstever@eecs.umich.edu           'MaxAddr', 'MaxTick', 'AllMemory',
12953885Sbinkertn@umich.edu           'Time',
12963102Sstever@eecs.umich.edu           'NextEthernetAddr', 'NULL',
12973101Sstever@eecs.umich.edu           'Port', 'VectorPort']
12986654Snate@binkert.org
12996654Snate@binkert.orgimport SimObject
1300