params.py revision 9941
13101Sstever@eecs.umich.edu# Copyright (c) 2012-2013 ARM Limited
23101Sstever@eecs.umich.edu# All rights reserved.
33101Sstever@eecs.umich.edu#
43101Sstever@eecs.umich.edu# The license below extends only to copyright in the software and shall
53101Sstever@eecs.umich.edu# not be construed as granting a license to any other intellectual
63101Sstever@eecs.umich.edu# property including but not limited to intellectual property relating
73101Sstever@eecs.umich.edu# to a hardware implementation of the functionality of the software
83101Sstever@eecs.umich.edu# licensed hereunder.  You may use the software subject to the license
93101Sstever@eecs.umich.edu# terms below provided that you ensure that this notice is replicated
103101Sstever@eecs.umich.edu# unmodified and in its entirety in all distributions of the software,
113101Sstever@eecs.umich.edu# modified or unmodified, in source code or in binary form.
123101Sstever@eecs.umich.edu#
133101Sstever@eecs.umich.edu# Copyright (c) 2004-2006 The Regents of The University of Michigan
143101Sstever@eecs.umich.edu# Copyright (c) 2010-2011 Advanced Micro Devices, Inc.
153101Sstever@eecs.umich.edu# All rights reserved.
163101Sstever@eecs.umich.edu#
173101Sstever@eecs.umich.edu# Redistribution and use in source and binary forms, with or without
183101Sstever@eecs.umich.edu# modification, are permitted provided that the following conditions are
193101Sstever@eecs.umich.edu# met: redistributions of source code must retain the above copyright
203101Sstever@eecs.umich.edu# notice, this list of conditions and the following disclaimer;
213101Sstever@eecs.umich.edu# redistributions in binary form must reproduce the above copyright
223101Sstever@eecs.umich.edu# notice, this list of conditions and the following disclaimer in the
233101Sstever@eecs.umich.edu# documentation and/or other materials provided with the distribution;
243101Sstever@eecs.umich.edu# neither the name of the copyright holders nor the names of its
253101Sstever@eecs.umich.edu# contributors may be used to endorse or promote products derived from
263101Sstever@eecs.umich.edu# this software without specific prior written permission.
273101Sstever@eecs.umich.edu#
283101Sstever@eecs.umich.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
293101Sstever@eecs.umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
303101Sstever@eecs.umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
313101Sstever@eecs.umich.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
323101Sstever@eecs.umich.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
333101Sstever@eecs.umich.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
343101Sstever@eecs.umich.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
353101Sstever@eecs.umich.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
363101Sstever@eecs.umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
373101Sstever@eecs.umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
383101Sstever@eecs.umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
393101Sstever@eecs.umich.edu#
403101Sstever@eecs.umich.edu# Authors: Steve Reinhardt
413101Sstever@eecs.umich.edu#          Nathan Binkert
423101Sstever@eecs.umich.edu#          Gabe Black
433101Sstever@eecs.umich.edu#          Andreas Hansson
443101Sstever@eecs.umich.edu
453101Sstever@eecs.umich.edu#####################################################################
463101Sstever@eecs.umich.edu#
473885Sbinkertn@umich.edu# Parameter description classes
483885Sbinkertn@umich.edu#
494762Snate@binkert.org# The _params dictionary in each class maps parameter names to either
503885Sbinkertn@umich.edu# a Param or a VectorParam object.  These objects contain the
513885Sbinkertn@umich.edu# parameter description string, the parameter type, and the default
523885Sbinkertn@umich.edu# value (if any).  The convert() method on these objects is used to
533101Sstever@eecs.umich.edu# force whatever value is assigned to the parameter to the appropriate
544380Sbinkertn@umich.edu# type.
554167Sbinkertn@umich.edu#
563102Sstever@eecs.umich.edu# Note that the default values are loaded into the class's attribute
573101Sstever@eecs.umich.edu# space when the parameter dictionary is initialized (in
584762Snate@binkert.org# MetaSimObject._new_param()); after that point they aren't used.
594762Snate@binkert.org#
604762Snate@binkert.org#####################################################################
614762Snate@binkert.org
624762Snate@binkert.orgimport copy
634762Snate@binkert.orgimport datetime
644762Snate@binkert.orgimport re
654762Snate@binkert.orgimport sys
664762Snate@binkert.orgimport time
674762Snate@binkert.orgimport math
684762Snate@binkert.org
695033Smilesck@eecs.umich.eduimport proxy
705033Smilesck@eecs.umich.eduimport ticks
715033Smilesck@eecs.umich.edufrom util import *
725033Smilesck@eecs.umich.edu
735033Smilesck@eecs.umich.edudef isSimObject(*args, **kwargs):
745033Smilesck@eecs.umich.edu    return SimObject.isSimObject(*args, **kwargs)
755033Smilesck@eecs.umich.edu
765033Smilesck@eecs.umich.edudef isSimObjectSequence(*args, **kwargs):
775033Smilesck@eecs.umich.edu    return SimObject.isSimObjectSequence(*args, **kwargs)
785033Smilesck@eecs.umich.edu
793101Sstever@eecs.umich.edudef isSimObjectClass(*args, **kwargs):
803101Sstever@eecs.umich.edu    return SimObject.isSimObjectClass(*args, **kwargs)
813101Sstever@eecs.umich.edu
825033Smilesck@eecs.umich.eduallParams = {}
833101Sstever@eecs.umich.edu
843101Sstever@eecs.umich.educlass MetaParamValue(type):
853101Sstever@eecs.umich.edu    def __new__(mcls, name, bases, dct):
863101Sstever@eecs.umich.edu        cls = super(MetaParamValue, mcls).__new__(mcls, name, bases, dct)
873101Sstever@eecs.umich.edu        assert name not in allParams
883101Sstever@eecs.umich.edu        allParams[name] = cls
893101Sstever@eecs.umich.edu        return cls
903101Sstever@eecs.umich.edu
913101Sstever@eecs.umich.edu
923101Sstever@eecs.umich.edu# Dummy base class to identify types that are legitimate for SimObject
933101Sstever@eecs.umich.edu# parameters.
943101Sstever@eecs.umich.educlass ParamValue(object):
953101Sstever@eecs.umich.edu    __metaclass__ = MetaParamValue
963101Sstever@eecs.umich.edu
973101Sstever@eecs.umich.edu
983101Sstever@eecs.umich.edu    # Generate the code needed as a prerequisite for declaring a C++
993101Sstever@eecs.umich.edu    # object of this type.  Typically generates one or more #include
1003101Sstever@eecs.umich.edu    # statements.  Used when declaring parameters of this type.
1013101Sstever@eecs.umich.edu    @classmethod
1023101Sstever@eecs.umich.edu    def cxx_predecls(cls, code):
1033101Sstever@eecs.umich.edu        pass
1043101Sstever@eecs.umich.edu
1053101Sstever@eecs.umich.edu    # Generate the code needed as a prerequisite for including a
1063101Sstever@eecs.umich.edu    # reference to a C++ object of this type in a SWIG .i file.
1073101Sstever@eecs.umich.edu    # Typically generates one or more %import or %include statements.
1083101Sstever@eecs.umich.edu    @classmethod
1093101Sstever@eecs.umich.edu    def swig_predecls(cls, code):
1103101Sstever@eecs.umich.edu        pass
1113101Sstever@eecs.umich.edu
1123101Sstever@eecs.umich.edu    # default for printing to .ini file is regular string conversion.
1133101Sstever@eecs.umich.edu    # will be overridden in some cases
1143101Sstever@eecs.umich.edu    def ini_str(self):
1153101Sstever@eecs.umich.edu        return str(self)
1163101Sstever@eecs.umich.edu
1173101Sstever@eecs.umich.edu    # allows us to blithely call unproxy() on things without checking
1183101Sstever@eecs.umich.edu    # if they're really proxies or not
1193101Sstever@eecs.umich.edu    def unproxy(self, base):
1203101Sstever@eecs.umich.edu        return self
1213101Sstever@eecs.umich.edu
1223101Sstever@eecs.umich.edu# Regular parameter description.
1233101Sstever@eecs.umich.educlass ParamDesc(object):
1243101Sstever@eecs.umich.edu    def __init__(self, ptype_str, ptype, *args, **kwargs):
1253101Sstever@eecs.umich.edu        self.ptype_str = ptype_str
1263101Sstever@eecs.umich.edu        # remember ptype only if it is provided
1273101Sstever@eecs.umich.edu        if ptype != None:
1283101Sstever@eecs.umich.edu            self.ptype = ptype
1293101Sstever@eecs.umich.edu
1303101Sstever@eecs.umich.edu        if args:
1313101Sstever@eecs.umich.edu            if len(args) == 1:
1325033Smilesck@eecs.umich.edu                self.desc = args[0]
1335033Smilesck@eecs.umich.edu            elif len(args) == 2:
1345033Smilesck@eecs.umich.edu                self.default = args[0]
1355033Smilesck@eecs.umich.edu                self.desc = args[1]
1365033Smilesck@eecs.umich.edu            else:
1373101Sstever@eecs.umich.edu                raise TypeError, 'too many arguments'
1383101Sstever@eecs.umich.edu
1393101Sstever@eecs.umich.edu        if kwargs.has_key('desc'):
1403101Sstever@eecs.umich.edu            assert(not hasattr(self, 'desc'))
1413101Sstever@eecs.umich.edu            self.desc = kwargs['desc']
1423101Sstever@eecs.umich.edu            del kwargs['desc']
1433101Sstever@eecs.umich.edu
1443101Sstever@eecs.umich.edu        if kwargs.has_key('default'):
1453101Sstever@eecs.umich.edu            assert(not hasattr(self, 'default'))
1463101Sstever@eecs.umich.edu            self.default = kwargs['default']
1473101Sstever@eecs.umich.edu            del kwargs['default']
1483101Sstever@eecs.umich.edu
1493101Sstever@eecs.umich.edu        if kwargs:
1503102Sstever@eecs.umich.edu            raise TypeError, 'extra unknown kwargs %s' % kwargs
1513101Sstever@eecs.umich.edu
1523101Sstever@eecs.umich.edu        if not hasattr(self, 'desc'):
1533101Sstever@eecs.umich.edu            raise TypeError, 'desc attribute missing'
1543101Sstever@eecs.umich.edu
1553101Sstever@eecs.umich.edu    def __getattr__(self, attr):
1563101Sstever@eecs.umich.edu        if attr == 'ptype':
1573101Sstever@eecs.umich.edu            ptype = SimObject.allClasses[self.ptype_str]
1583101Sstever@eecs.umich.edu            assert isSimObjectClass(ptype)
1593101Sstever@eecs.umich.edu            self.ptype = ptype
1603101Sstever@eecs.umich.edu            return ptype
1613101Sstever@eecs.umich.edu
1623101Sstever@eecs.umich.edu        raise AttributeError, "'%s' object has no attribute '%s'" % \
1633101Sstever@eecs.umich.edu              (type(self).__name__, attr)
1643101Sstever@eecs.umich.edu
1653101Sstever@eecs.umich.edu    def convert(self, value):
1663101Sstever@eecs.umich.edu        if isinstance(value, proxy.BaseProxy):
1673101Sstever@eecs.umich.edu            value.set_param_desc(self)
1685033Smilesck@eecs.umich.edu            return value
1693101Sstever@eecs.umich.edu        if not hasattr(self, 'ptype') and isNullPointer(value):
1703101Sstever@eecs.umich.edu            # deferred evaluation of SimObject; continue to defer if
1713101Sstever@eecs.umich.edu            # we're just assigning a null pointer
1724762Snate@binkert.org            return value
1734762Snate@binkert.org        if isinstance(value, self.ptype):
1744762Snate@binkert.org            return value
1753101Sstever@eecs.umich.edu        if isNullPointer(value) and isSimObjectClass(self.ptype):
1763101Sstever@eecs.umich.edu            return value
1773101Sstever@eecs.umich.edu        return self.ptype(value)
1783101Sstever@eecs.umich.edu
1795037Smilesck@eecs.umich.edu    def cxx_predecls(self, code):
1803101Sstever@eecs.umich.edu        code('#include <cstddef>')
1815037Smilesck@eecs.umich.edu        self.ptype.cxx_predecls(code)
1823101Sstever@eecs.umich.edu
1833101Sstever@eecs.umich.edu    def swig_predecls(self, code):
1843101Sstever@eecs.umich.edu        self.ptype.swig_predecls(code)
1853101Sstever@eecs.umich.edu
1863101Sstever@eecs.umich.edu    def cxx_decl(self, code):
1873101Sstever@eecs.umich.edu        code('${{self.ptype.cxx_type}} ${{self.name}};')
1883101Sstever@eecs.umich.edu
1893101Sstever@eecs.umich.edu# Vector-valued parameter description.  Just like ParamDesc, except
1903101Sstever@eecs.umich.edu# that the value is a vector (list) of the specified type instead of a
1914762Snate@binkert.org# single value.
1924762Snate@binkert.org
1934762Snate@binkert.orgclass VectorParamValue(list):
1944762Snate@binkert.org    __metaclass__ = MetaParamValue
1954762Snate@binkert.org    def __setattr__(self, attr, value):
1964762Snate@binkert.org        raise AttributeError, \
1974762Snate@binkert.org              "Not allowed to set %s on '%s'" % (attr, type(self).__name__)
1984762Snate@binkert.org
1994762Snate@binkert.org    def ini_str(self):
2004762Snate@binkert.org        return ' '.join([v.ini_str() for v in self])
2014762Snate@binkert.org
2024762Snate@binkert.org    def getValue(self):
2034762Snate@binkert.org        return [ v.getValue() for v in self ]
2044762Snate@binkert.org
2054762Snate@binkert.org    def unproxy(self, base):
2064762Snate@binkert.org        if len(self) == 1 and isinstance(self[0], proxy.AllProxy):
2073101Sstever@eecs.umich.edu            return self[0].unproxy(base)
2083101Sstever@eecs.umich.edu        else:
2093101Sstever@eecs.umich.edu             return [v.unproxy(base) for v in self]
2103101Sstever@eecs.umich.edu
2113101Sstever@eecs.umich.educlass SimObjectVector(VectorParamValue):
2123101Sstever@eecs.umich.edu    # support clone operation
2133101Sstever@eecs.umich.edu    def __call__(self, **kwargs):
2143101Sstever@eecs.umich.edu        return SimObjectVector([v(**kwargs) for v in self])
2153101Sstever@eecs.umich.edu
2163101Sstever@eecs.umich.edu    def clear_parent(self, old_parent):
2173101Sstever@eecs.umich.edu        for v in self:
2183101Sstever@eecs.umich.edu            v.clear_parent(old_parent)
2193101Sstever@eecs.umich.edu
2203101Sstever@eecs.umich.edu    def set_parent(self, parent, name):
2213101Sstever@eecs.umich.edu        if len(self) == 1:
2223101Sstever@eecs.umich.edu            self[0].set_parent(parent, name)
2233101Sstever@eecs.umich.edu        else:
2243101Sstever@eecs.umich.edu            width = int(math.ceil(math.log(len(self))/math.log(10)))
2253101Sstever@eecs.umich.edu            for i,v in enumerate(self):
2263101Sstever@eecs.umich.edu                v.set_parent(parent, "%s%0*d" % (name, width, i))
2273101Sstever@eecs.umich.edu
2285033Smilesck@eecs.umich.edu    def has_parent(self):
2295033Smilesck@eecs.umich.edu        return reduce(lambda x,y: x and y, [v.has_parent() for v in self])
2303101Sstever@eecs.umich.edu
2313101Sstever@eecs.umich.edu    # return 'cpu0 cpu1' etc. for print_ini()
2323101Sstever@eecs.umich.edu    def get_name(self):
2333101Sstever@eecs.umich.edu        return ' '.join([v._name for v in self])
2343101Sstever@eecs.umich.edu
2353101Sstever@eecs.umich.edu    # By iterating through the constituent members of the vector here
2363101Sstever@eecs.umich.edu    # we can nicely handle iterating over all a SimObject's children
2373101Sstever@eecs.umich.edu    # without having to provide lots of special functions on
2383101Sstever@eecs.umich.edu    # SimObjectVector directly.
2393101Sstever@eecs.umich.edu    def descendants(self):
2403101Sstever@eecs.umich.edu        for v in self:
2413101Sstever@eecs.umich.edu            for obj in v.descendants():
2423101Sstever@eecs.umich.edu                yield obj
2433101Sstever@eecs.umich.edu
2443101Sstever@eecs.umich.edu    def get_config_as_dict(self):
2453101Sstever@eecs.umich.edu        a = []
2463101Sstever@eecs.umich.edu        for v in self:
2473101Sstever@eecs.umich.edu            a.append(v.get_config_as_dict())
2483101Sstever@eecs.umich.edu        return a
2493101Sstever@eecs.umich.edu
2503101Sstever@eecs.umich.educlass VectorParamDesc(ParamDesc):
2513101Sstever@eecs.umich.edu    # Convert assigned value to appropriate type.  If the RHS is not a
2523101Sstever@eecs.umich.edu    # list or tuple, it generates a single-element list.
2533101Sstever@eecs.umich.edu    def convert(self, value):
2543101Sstever@eecs.umich.edu        if isinstance(value, (list, tuple)):
2553101Sstever@eecs.umich.edu            # list: coerce each element into new list
2563101Sstever@eecs.umich.edu            tmp_list = [ ParamDesc.convert(self, v) for v in value ]
2573101Sstever@eecs.umich.edu        else:
2584762Snate@binkert.org            # singleton: coerce to a single-element list
2594762Snate@binkert.org            tmp_list = [ ParamDesc.convert(self, value) ]
2604762Snate@binkert.org
2614762Snate@binkert.org        if isSimObjectSequence(tmp_list):
2623101Sstever@eecs.umich.edu            return SimObjectVector(tmp_list)
2633101Sstever@eecs.umich.edu        else:
2643101Sstever@eecs.umich.edu            return VectorParamValue(tmp_list)
2653101Sstever@eecs.umich.edu
2663101Sstever@eecs.umich.edu    def swig_module_name(self):
2673101Sstever@eecs.umich.edu        return "%s_vector" % self.ptype_str
2683101Sstever@eecs.umich.edu
2693101Sstever@eecs.umich.edu    def swig_predecls(self, code):
2703101Sstever@eecs.umich.edu        code('%import "${{self.swig_module_name()}}.i"')
2713101Sstever@eecs.umich.edu
2723101Sstever@eecs.umich.edu    def swig_decl(self, code):
2733714Sstever@eecs.umich.edu        code('%module(package="m5.internal") ${{self.swig_module_name()}}')
2743714Sstever@eecs.umich.edu        code('%{')
2753714Sstever@eecs.umich.edu        self.ptype.cxx_predecls(code)
2763714Sstever@eecs.umich.edu        code('%}')
2773714Sstever@eecs.umich.edu        code()
2783714Sstever@eecs.umich.edu        # Make sure the SWIGPY_SLICE_ARG is defined through this inclusion
2793101Sstever@eecs.umich.edu        code('%include "std_container.i"')
2803101Sstever@eecs.umich.edu        code()
2813101Sstever@eecs.umich.edu        self.ptype.swig_predecls(code)
2823101Sstever@eecs.umich.edu        code()
2833101Sstever@eecs.umich.edu        code('%include "std_vector.i"')
2843101Sstever@eecs.umich.edu        code()
2853101Sstever@eecs.umich.edu
2863101Sstever@eecs.umich.edu        ptype = self.ptype_str
2873101Sstever@eecs.umich.edu        cxx_type = self.ptype.cxx_type
2883101Sstever@eecs.umich.edu
2893101Sstever@eecs.umich.edu        code('''\
2903101Sstever@eecs.umich.edu%typemap(in) std::vector< $cxx_type >::value_type {
2913101Sstever@eecs.umich.edu    if (SWIG_ConvertPtr($$input, (void **)&$$1, $$1_descriptor, 0) == -1) {
2923101Sstever@eecs.umich.edu        if (SWIG_ConvertPtr($$input, (void **)&$$1,
2933101Sstever@eecs.umich.edu                            $$descriptor($cxx_type), 0) == -1) {
2943101Sstever@eecs.umich.edu            return NULL;
2953101Sstever@eecs.umich.edu        }
2963101Sstever@eecs.umich.edu    }
2973101Sstever@eecs.umich.edu}
2983101Sstever@eecs.umich.edu
2993101Sstever@eecs.umich.edu%typemap(in) std::vector< $cxx_type >::value_type * {
3003101Sstever@eecs.umich.edu    if (SWIG_ConvertPtr($$input, (void **)&$$1, $$1_descriptor, 0) == -1) {
3013101Sstever@eecs.umich.edu        if (SWIG_ConvertPtr($$input, (void **)&$$1,
3023101Sstever@eecs.umich.edu                            $$descriptor($cxx_type *), 0) == -1) {
3033101Sstever@eecs.umich.edu            return NULL;
3045033Smilesck@eecs.umich.edu        }
3053101Sstever@eecs.umich.edu    }
3063101Sstever@eecs.umich.edu}
3073101Sstever@eecs.umich.edu''')
3083101Sstever@eecs.umich.edu
3093101Sstever@eecs.umich.edu        code('%template(vector_$ptype) std::vector< $cxx_type >;')
3103101Sstever@eecs.umich.edu
3113101Sstever@eecs.umich.edu    def cxx_predecls(self, code):
3123101Sstever@eecs.umich.edu        code('#include <vector>')
3133101Sstever@eecs.umich.edu        self.ptype.cxx_predecls(code)
3143101Sstever@eecs.umich.edu
3153101Sstever@eecs.umich.edu    def cxx_decl(self, code):
3163101Sstever@eecs.umich.edu        code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};')
3173101Sstever@eecs.umich.edu
3183101Sstever@eecs.umich.educlass ParamFactory(object):
3193101Sstever@eecs.umich.edu    def __init__(self, param_desc_class, ptype_str = None):
3204762Snate@binkert.org        self.param_desc_class = param_desc_class
3213101Sstever@eecs.umich.edu        self.ptype_str = ptype_str
3223101Sstever@eecs.umich.edu
3233101Sstever@eecs.umich.edu    def __getattr__(self, attr):
3243101Sstever@eecs.umich.edu        if self.ptype_str:
3253101Sstever@eecs.umich.edu            attr = self.ptype_str + '.' + attr
3263101Sstever@eecs.umich.edu        return ParamFactory(self.param_desc_class, attr)
3273101Sstever@eecs.umich.edu
3283101Sstever@eecs.umich.edu    # E.g., Param.Int(5, "number of widgets")
3293101Sstever@eecs.umich.edu    def __call__(self, *args, **kwargs):
3303101Sstever@eecs.umich.edu        ptype = None
3313101Sstever@eecs.umich.edu        try:
3323101Sstever@eecs.umich.edu            ptype = allParams[self.ptype_str]
3333101Sstever@eecs.umich.edu        except KeyError:
3343101Sstever@eecs.umich.edu            # if name isn't defined yet, assume it's a SimObject, and
3353101Sstever@eecs.umich.edu            # try to resolve it later
3363101Sstever@eecs.umich.edu            pass
3373101Sstever@eecs.umich.edu        return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs)
3383101Sstever@eecs.umich.edu
3393101Sstever@eecs.umich.eduParam = ParamFactory(ParamDesc)
3403101Sstever@eecs.umich.eduVectorParam = ParamFactory(VectorParamDesc)
3413101Sstever@eecs.umich.edu
3423101Sstever@eecs.umich.edu#####################################################################
3433101Sstever@eecs.umich.edu#
3443101Sstever@eecs.umich.edu# Parameter Types
3453101Sstever@eecs.umich.edu#
3463101Sstever@eecs.umich.edu# Though native Python types could be used to specify parameter types
3473101Sstever@eecs.umich.edu# (the 'ptype' field of the Param and VectorParam classes), it's more
3483101Sstever@eecs.umich.edu# flexible to define our own set of types.  This gives us more control
3493102Sstever@eecs.umich.edu# over how Python expressions are converted to values (via the
3503714Sstever@eecs.umich.edu# __init__() constructor) and how these values are printed out (via
3513101Sstever@eecs.umich.edu# the __str__() conversion method).
3523714Sstever@eecs.umich.edu#
3533714Sstever@eecs.umich.edu#####################################################################
3543714Sstever@eecs.umich.edu
3553101Sstever@eecs.umich.edu# String-valued parameter.  Just mixin the ParamValue class with the
3563101Sstever@eecs.umich.edu# built-in str class.
3574762Snate@binkert.orgclass String(ParamValue,str):
3584762Snate@binkert.org    cxx_type = 'std::string'
3594762Snate@binkert.org
3603101Sstever@eecs.umich.edu    @classmethod
3613101Sstever@eecs.umich.edu    def cxx_predecls(self, code):
3623101Sstever@eecs.umich.edu        code('#include <string>')
3633101Sstever@eecs.umich.edu
3643101Sstever@eecs.umich.edu    @classmethod
3653101Sstever@eecs.umich.edu    def swig_predecls(cls, code):
3663101Sstever@eecs.umich.edu        code('%include "std_string.i"')
3673101Sstever@eecs.umich.edu
3683101Sstever@eecs.umich.edu    def getValue(self):
3693101Sstever@eecs.umich.edu        return self
3703101Sstever@eecs.umich.edu
3713101Sstever@eecs.umich.edu# superclass for "numeric" parameter values, to emulate math
3723101Sstever@eecs.umich.edu# operations in a type-safe way.  e.g., a Latency times an int returns
3733101Sstever@eecs.umich.edu# a new Latency object.
3743101Sstever@eecs.umich.educlass NumericParamValue(ParamValue):
3753101Sstever@eecs.umich.edu    def __str__(self):
3763101Sstever@eecs.umich.edu        return str(self.value)
3773101Sstever@eecs.umich.edu
3783101Sstever@eecs.umich.edu    def __float__(self):
3793101Sstever@eecs.umich.edu        return float(self.value)
3804446Sbinkertn@umich.edu
3813101Sstever@eecs.umich.edu    def __long__(self):
3824762Snate@binkert.org        return long(self.value)
3834762Snate@binkert.org
3844762Snate@binkert.org    def __int__(self):
3853101Sstever@eecs.umich.edu        return int(self.value)
3863101Sstever@eecs.umich.edu
3873101Sstever@eecs.umich.edu    # hook for bounds checking
3883101Sstever@eecs.umich.edu    def _check(self):
3893101Sstever@eecs.umich.edu        return
3903101Sstever@eecs.umich.edu
3913101Sstever@eecs.umich.edu    def __mul__(self, other):
3923101Sstever@eecs.umich.edu        newobj = self.__class__(self)
3933102Sstever@eecs.umich.edu        newobj.value *= other
3943101Sstever@eecs.umich.edu        newobj._check()
3953101Sstever@eecs.umich.edu        return newobj
3963101Sstever@eecs.umich.edu
3974168Sbinkertn@umich.edu    __rmul__ = __mul__
3983101Sstever@eecs.umich.edu
3993101Sstever@eecs.umich.edu    def __div__(self, other):
4003101Sstever@eecs.umich.edu        newobj = self.__class__(self)
4013101Sstever@eecs.umich.edu        newobj.value /= other
4023101Sstever@eecs.umich.edu        newobj._check()
4033101Sstever@eecs.umich.edu        return newobj
4043102Sstever@eecs.umich.edu
4053101Sstever@eecs.umich.edu    def __sub__(self, other):
4063101Sstever@eecs.umich.edu        newobj = self.__class__(self)
4073101Sstever@eecs.umich.edu        newobj.value -= other
4083101Sstever@eecs.umich.edu        newobj._check()
4094762Snate@binkert.org        return newobj
4103101Sstever@eecs.umich.edu
4113101Sstever@eecs.umich.edu# Metaclass for bounds-checked integer parameters.  See CheckedInt.
4123101Sstever@eecs.umich.educlass CheckedIntType(MetaParamValue):
4133101Sstever@eecs.umich.edu    def __init__(cls, name, bases, dict):
4143101Sstever@eecs.umich.edu        super(CheckedIntType, cls).__init__(name, bases, dict)
4153101Sstever@eecs.umich.edu
4163101Sstever@eecs.umich.edu        # CheckedInt is an abstract base class, so we actually don't
4173102Sstever@eecs.umich.edu        # want to do any processing on it... the rest of this code is
4183101Sstever@eecs.umich.edu        # just for classes that derive from CheckedInt.
4193101Sstever@eecs.umich.edu        if name == 'CheckedInt':
4203101Sstever@eecs.umich.edu            return
4213584Ssaidi@eecs.umich.edu
4223584Ssaidi@eecs.umich.edu        if not (hasattr(cls, 'min') and hasattr(cls, 'max')):
4233584Ssaidi@eecs.umich.edu            if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')):
4243584Ssaidi@eecs.umich.edu                panic("CheckedInt subclass %s must define either\n" \
4253584Ssaidi@eecs.umich.edu                      "    'min' and 'max' or 'size' and 'unsigned'\n",
4263101Sstever@eecs.umich.edu                      name);
4273101Sstever@eecs.umich.edu            if cls.unsigned:
4285033Smilesck@eecs.umich.edu                cls.min = 0
4293101Sstever@eecs.umich.edu                cls.max = 2 ** cls.size - 1
4303101Sstever@eecs.umich.edu            else:
4313101Sstever@eecs.umich.edu                cls.min = -(2 ** (cls.size - 1))
4323101Sstever@eecs.umich.edu                cls.max = (2 ** (cls.size - 1)) - 1
4333101Sstever@eecs.umich.edu
4343101Sstever@eecs.umich.edu# Abstract superclass for bounds-checked integer parameters.  This
4353101Sstever@eecs.umich.edu# class is subclassed to generate parameter classes with specific
4363101Sstever@eecs.umich.edu# bounds.  Initialization of the min and max bounds is done in the
4373101Sstever@eecs.umich.edu# metaclass CheckedIntType.__init__.
4383101Sstever@eecs.umich.educlass CheckedInt(NumericParamValue):
4393101Sstever@eecs.umich.edu    __metaclass__ = CheckedIntType
4403101Sstever@eecs.umich.edu
4413101Sstever@eecs.umich.edu    def _check(self):
4423101Sstever@eecs.umich.edu        if not self.min <= self.value <= self.max:
4433101Sstever@eecs.umich.edu            raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
4443101Sstever@eecs.umich.edu                  (self.min, self.value, self.max)
4453101Sstever@eecs.umich.edu
4463101Sstever@eecs.umich.edu    def __init__(self, value):
4473101Sstever@eecs.umich.edu        if isinstance(value, str):
4483101Sstever@eecs.umich.edu            self.value = convert.toInteger(value)
4493101Sstever@eecs.umich.edu        elif isinstance(value, (int, long, float, NumericParamValue)):
4503101Sstever@eecs.umich.edu            self.value = long(value)
4513101Sstever@eecs.umich.edu        else:
4523101Sstever@eecs.umich.edu            raise TypeError, "Can't convert object of type %s to CheckedInt" \
4533101Sstever@eecs.umich.edu                  % type(value).__name__
4543101Sstever@eecs.umich.edu        self._check()
4553101Sstever@eecs.umich.edu
4563101Sstever@eecs.umich.edu    @classmethod
4573101Sstever@eecs.umich.edu    def cxx_predecls(cls, code):
4583101Sstever@eecs.umich.edu        # most derived types require this, so we just do it here once
4593101Sstever@eecs.umich.edu        code('#include "base/types.hh"')
4603101Sstever@eecs.umich.edu
4613101Sstever@eecs.umich.edu    @classmethod
4623101Sstever@eecs.umich.edu    def swig_predecls(cls, code):
4633101Sstever@eecs.umich.edu        # most derived types require this, so we just do it here once
4643101Sstever@eecs.umich.edu        code('%import "stdint.i"')
4653101Sstever@eecs.umich.edu        code('%import "base/types.hh"')
4663101Sstever@eecs.umich.edu
4673101Sstever@eecs.umich.edu    def getValue(self):
4683101Sstever@eecs.umich.edu        return long(self.value)
4693101Sstever@eecs.umich.edu
4703101Sstever@eecs.umich.educlass Int(CheckedInt):      cxx_type = 'int';      size = 32; unsigned = False
4713101Sstever@eecs.umich.educlass Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True
4723101Sstever@eecs.umich.edu
4733101Sstever@eecs.umich.educlass Int8(CheckedInt):     cxx_type =   'int8_t'; size =  8; unsigned = False
4743101Sstever@eecs.umich.educlass UInt8(CheckedInt):    cxx_type =  'uint8_t'; size =  8; unsigned = True
4753101Sstever@eecs.umich.educlass Int16(CheckedInt):    cxx_type =  'int16_t'; size = 16; unsigned = False
4763101Sstever@eecs.umich.educlass UInt16(CheckedInt):   cxx_type = 'uint16_t'; size = 16; unsigned = True
4773101Sstever@eecs.umich.educlass Int32(CheckedInt):    cxx_type =  'int32_t'; size = 32; unsigned = False
4784762Snate@binkert.orgclass UInt32(CheckedInt):   cxx_type = 'uint32_t'; size = 32; unsigned = True
4794762Snate@binkert.orgclass Int64(CheckedInt):    cxx_type =  'int64_t'; size = 64; unsigned = False
4804762Snate@binkert.orgclass UInt64(CheckedInt):   cxx_type = 'uint64_t'; size = 64; unsigned = True
4814762Snate@binkert.org
4824762Snate@binkert.orgclass Counter(CheckedInt):  cxx_type = 'Counter';  size = 64; unsigned = True
4834762Snate@binkert.orgclass Tick(CheckedInt):     cxx_type = 'Tick';     size = 64; unsigned = True
4844762Snate@binkert.orgclass TcpPort(CheckedInt):  cxx_type = 'uint16_t'; size = 16; unsigned = True
4854762Snate@binkert.orgclass UdpPort(CheckedInt):  cxx_type = 'uint16_t'; size = 16; unsigned = True
4864762Snate@binkert.org
4873101Sstever@eecs.umich.educlass Percent(CheckedInt):  cxx_type = 'int'; min = 0; max = 100
4883101Sstever@eecs.umich.edu
4893101Sstever@eecs.umich.educlass Cycles(CheckedInt):
4904762Snate@binkert.org    cxx_type = 'Cycles'
4914762Snate@binkert.org    size = 64
4924762Snate@binkert.org    unsigned = True
4934762Snate@binkert.org
4944762Snate@binkert.org    def getValue(self):
4954762Snate@binkert.org        from m5.internal.core import Cycles
4964762Snate@binkert.org        return Cycles(self.value)
4974762Snate@binkert.org
4984762Snate@binkert.orgclass Float(ParamValue, float):
4993101Sstever@eecs.umich.edu    cxx_type = 'double'
5003101Sstever@eecs.umich.edu
5013101Sstever@eecs.umich.edu    def __init__(self, value):
5023101Sstever@eecs.umich.edu        if isinstance(value, (int, long, float, NumericParamValue, Float)):
5033101Sstever@eecs.umich.edu            self.value = float(value)
5043101Sstever@eecs.umich.edu        else:
5053101Sstever@eecs.umich.edu            raise TypeError, "Can't convert object of type %s to Float" \
5063101Sstever@eecs.umich.edu                  % type(value).__name__
5073102Sstever@eecs.umich.edu
5083101Sstever@eecs.umich.edu    def getValue(self):
5093101Sstever@eecs.umich.edu        return float(self.value)
5103101Sstever@eecs.umich.edu
5114762Snate@binkert.orgclass MemorySize(CheckedInt):
5124762Snate@binkert.org    cxx_type = 'uint64_t'
5134762Snate@binkert.org    size = 64
5143101Sstever@eecs.umich.edu    unsigned = True
5153101Sstever@eecs.umich.edu    def __init__(self, value):
5163101Sstever@eecs.umich.edu        if isinstance(value, MemorySize):
5173101Sstever@eecs.umich.edu            self.value = value.value
5183101Sstever@eecs.umich.edu        else:
5193101Sstever@eecs.umich.edu            self.value = convert.toMemorySize(value)
5203101Sstever@eecs.umich.edu        self._check()
5213101Sstever@eecs.umich.edu
5223101Sstever@eecs.umich.educlass MemorySize32(CheckedInt):
5233101Sstever@eecs.umich.edu    cxx_type = 'uint32_t'
5243101Sstever@eecs.umich.edu    size = 32
5253101Sstever@eecs.umich.edu    unsigned = True
5263101Sstever@eecs.umich.edu    def __init__(self, value):
5273101Sstever@eecs.umich.edu        if isinstance(value, MemorySize):
5283101Sstever@eecs.umich.edu            self.value = value.value
5293101Sstever@eecs.umich.edu        else:
5303101Sstever@eecs.umich.edu            self.value = convert.toMemorySize(value)
5313101Sstever@eecs.umich.edu        self._check()
5323101Sstever@eecs.umich.edu
5333101Sstever@eecs.umich.educlass Addr(CheckedInt):
5344380Sbinkertn@umich.edu    cxx_type = 'Addr'
5354380Sbinkertn@umich.edu    size = 64
5364380Sbinkertn@umich.edu    unsigned = True
5373101Sstever@eecs.umich.edu    def __init__(self, value):
5384380Sbinkertn@umich.edu        if isinstance(value, Addr):
5394380Sbinkertn@umich.edu            self.value = value.value
5404380Sbinkertn@umich.edu        else:
5413101Sstever@eecs.umich.edu            try:
5423101Sstever@eecs.umich.edu                self.value = convert.toMemorySize(value)
5433101Sstever@eecs.umich.edu            except TypeError:
5443101Sstever@eecs.umich.edu                self.value = long(value)
5454762Snate@binkert.org        self._check()
5463101Sstever@eecs.umich.edu    def __add__(self, other):
5473101Sstever@eecs.umich.edu        if isinstance(other, Addr):
5483101Sstever@eecs.umich.edu            return self.value + other.value
5493101Sstever@eecs.umich.edu        else:
5503101Sstever@eecs.umich.edu            return self.value + other
5513101Sstever@eecs.umich.edu
5523101Sstever@eecs.umich.educlass AddrRange(ParamValue):
5533101Sstever@eecs.umich.edu    cxx_type = 'AddrRange'
5543101Sstever@eecs.umich.edu
5553101Sstever@eecs.umich.edu    def __init__(self, *args, **kwargs):
5563101Sstever@eecs.umich.edu        # Disable interleaving by default
5573101Sstever@eecs.umich.edu        self.intlvHighBit = 0
5583101Sstever@eecs.umich.edu        self.intlvBits = 0
5593101Sstever@eecs.umich.edu        self.intlvMatch = 0
5603101Sstever@eecs.umich.edu
5613101Sstever@eecs.umich.edu        def handle_kwargs(self, kwargs):
5623101Sstever@eecs.umich.edu            # An address range needs to have an upper limit, specified
5633101Sstever@eecs.umich.edu            # either explicitly with an end, or as an offset using the
5643101Sstever@eecs.umich.edu            # size keyword.
5653101Sstever@eecs.umich.edu            if 'end' in kwargs:
5664380Sbinkertn@umich.edu                self.end = Addr(kwargs.pop('end'))
5673101Sstever@eecs.umich.edu            elif 'size' in kwargs:
5683101Sstever@eecs.umich.edu                self.end = self.start + Addr(kwargs.pop('size')) - 1
5694762Snate@binkert.org            else:
5704762Snate@binkert.org                raise TypeError, "Either end or size must be specified"
5714762Snate@binkert.org
5724762Snate@binkert.org            # Now on to the optional bit
5734380Sbinkertn@umich.edu            if 'intlvHighBit' in kwargs:
5744380Sbinkertn@umich.edu                self.intlvHighBit = int(kwargs.pop('intlvHighBit'))
5753101Sstever@eecs.umich.edu            if 'intlvBits' in kwargs:
5763932Sbinkertn@umich.edu                self.intlvBits = int(kwargs.pop('intlvBits'))
5773932Sbinkertn@umich.edu            if 'intlvMatch' in kwargs:
5783932Sbinkertn@umich.edu                self.intlvMatch = int(kwargs.pop('intlvMatch'))
5793932Sbinkertn@umich.edu
5803932Sbinkertn@umich.edu        if len(args) == 0:
5813932Sbinkertn@umich.edu            self.start = Addr(kwargs.pop('start'))
5823932Sbinkertn@umich.edu            handle_kwargs(self, kwargs)
5833932Sbinkertn@umich.edu
5843932Sbinkertn@umich.edu        elif len(args) == 1:
5853932Sbinkertn@umich.edu            if kwargs:
5863932Sbinkertn@umich.edu                self.start = Addr(args[0])
5873932Sbinkertn@umich.edu                handle_kwargs(self, kwargs)
5883932Sbinkertn@umich.edu            elif isinstance(args[0], (list, tuple)):
5893885Sbinkertn@umich.edu                self.start = Addr(args[0][0])
5903932Sbinkertn@umich.edu                self.end = Addr(args[0][1])
5913932Sbinkertn@umich.edu            else:
5923885Sbinkertn@umich.edu                self.start = Addr(0)
5933932Sbinkertn@umich.edu                self.end = Addr(args[0]) - 1
5943932Sbinkertn@umich.edu
5953932Sbinkertn@umich.edu        elif len(args) == 2:
5963932Sbinkertn@umich.edu            self.start = Addr(args[0])
5973932Sbinkertn@umich.edu            self.end = Addr(args[1])
5983932Sbinkertn@umich.edu        else:
5993932Sbinkertn@umich.edu            raise TypeError, "Too many arguments specified"
6003932Sbinkertn@umich.edu
6013932Sbinkertn@umich.edu        if kwargs:
6023932Sbinkertn@umich.edu            raise TypeError, "Too many keywords: %s" % kwargs.keys()
6033932Sbinkertn@umich.edu
6043932Sbinkertn@umich.edu    def __str__(self):
6053932Sbinkertn@umich.edu        return '%s:%s' % (self.start, self.end)
6063932Sbinkertn@umich.edu
6073932Sbinkertn@umich.edu    def size(self):
6083932Sbinkertn@umich.edu        # Divide the size by the size of the interleaving slice
6093932Sbinkertn@umich.edu        return (long(self.end) - long(self.start) + 1) >> self.intlvBits
6103932Sbinkertn@umich.edu
6113885Sbinkertn@umich.edu    @classmethod
6123885Sbinkertn@umich.edu    def cxx_predecls(cls, code):
6133885Sbinkertn@umich.edu        Addr.cxx_predecls(code)
6143885Sbinkertn@umich.edu        code('#include "base/addr_range.hh"')
6154762Snate@binkert.org
6164762Snate@binkert.org    @classmethod
6174762Snate@binkert.org    def swig_predecls(cls, code):
6183885Sbinkertn@umich.edu        Addr.swig_predecls(code)
6193932Sbinkertn@umich.edu
6203885Sbinkertn@umich.edu    def getValue(self):
6214762Snate@binkert.org        # Go from the Python class to the wrapped C++ class generated
6224762Snate@binkert.org        # by swig
6234762Snate@binkert.org        from m5.internal.range import AddrRange
6244762Snate@binkert.org
6254762Snate@binkert.org        return AddrRange(long(self.start), long(self.end),
6264762Snate@binkert.org                         int(self.intlvHighBit), int(self.intlvBits),
6274762Snate@binkert.org                         int(self.intlvMatch))
6284762Snate@binkert.org
6294762Snate@binkert.org# Boolean parameter type.  Python doesn't let you subclass bool, since
6304762Snate@binkert.org# it doesn't want to let you create multiple instances of True and
6314762Snate@binkert.org# False.  Thus this is a little more complicated than String.
6324762Snate@binkert.orgclass Bool(ParamValue):
6334762Snate@binkert.org    cxx_type = 'bool'
6344762Snate@binkert.org    def __init__(self, value):
6354762Snate@binkert.org        try:
6364762Snate@binkert.org            self.value = convert.toBool(value)
6374762Snate@binkert.org        except TypeError:
6384762Snate@binkert.org            self.value = bool(value)
6394762Snate@binkert.org
6404762Snate@binkert.org    def getValue(self):
6414762Snate@binkert.org        return bool(self.value)
6424762Snate@binkert.org
6434762Snate@binkert.org    def __str__(self):
6444762Snate@binkert.org        return str(self.value)
6454762Snate@binkert.org
6464762Snate@binkert.org    # implement truth value testing for Bool parameters so that these params
6473885Sbinkertn@umich.edu    # evaluate correctly during the python configuration phase
6484762Snate@binkert.org    def __nonzero__(self):
6493885Sbinkertn@umich.edu        return bool(self.value)
6503885Sbinkertn@umich.edu
6513932Sbinkertn@umich.edu    def ini_str(self):
6523885Sbinkertn@umich.edu        if self.value:
6533101Sstever@eecs.umich.edu            return 'true'
6543101Sstever@eecs.umich.edu        return 'false'
6553101Sstever@eecs.umich.edu
6563101Sstever@eecs.umich.edudef IncEthernetAddr(addr, val = 1):
6573101Sstever@eecs.umich.edu    bytes = map(lambda x: int(x, 16), addr.split(':'))
6583101Sstever@eecs.umich.edu    bytes[5] += val
6593101Sstever@eecs.umich.edu    for i in (5, 4, 3, 2, 1):
6603101Sstever@eecs.umich.edu        val,rem = divmod(bytes[i], 256)
6613101Sstever@eecs.umich.edu        bytes[i] = rem
6623101Sstever@eecs.umich.edu        if val == 0:
6633101Sstever@eecs.umich.edu            break
6643101Sstever@eecs.umich.edu        bytes[i - 1] += val
6653101Sstever@eecs.umich.edu    assert(bytes[0] <= 255)
6663101Sstever@eecs.umich.edu    return ':'.join(map(lambda x: '%02x' % x, bytes))
6674762Snate@binkert.org
6683101Sstever@eecs.umich.edu_NextEthernetAddr = "00:90:00:00:00:01"
6695033Smilesck@eecs.umich.edudef NextEthernetAddr():
6704762Snate@binkert.org    global _NextEthernetAddr
6714762Snate@binkert.org
6724762Snate@binkert.org    value = _NextEthernetAddr
6734762Snate@binkert.org    _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1)
6744762Snate@binkert.org    return value
6754762Snate@binkert.org
6764762Snate@binkert.orgclass EthernetAddr(ParamValue):
6773101Sstever@eecs.umich.edu    cxx_type = 'Net::EthAddr'
6783101Sstever@eecs.umich.edu
6793101Sstever@eecs.umich.edu    @classmethod
6803101Sstever@eecs.umich.edu    def cxx_predecls(cls, code):
6813101Sstever@eecs.umich.edu        code('#include "base/inet.hh"')
6823101Sstever@eecs.umich.edu
6833101Sstever@eecs.umich.edu    @classmethod
6843101Sstever@eecs.umich.edu    def swig_predecls(cls, code):
6853101Sstever@eecs.umich.edu        code('%include "python/swig/inet.i"')
6863101Sstever@eecs.umich.edu
6873101Sstever@eecs.umich.edu    def __init__(self, value):
6883101Sstever@eecs.umich.edu        if value == NextEthernetAddr:
6893101Sstever@eecs.umich.edu            self.value = value
6903101Sstever@eecs.umich.edu            return
6913101Sstever@eecs.umich.edu
6923101Sstever@eecs.umich.edu        if not isinstance(value, str):
6933101Sstever@eecs.umich.edu            raise TypeError, "expected an ethernet address and didn't get one"
6943101Sstever@eecs.umich.edu
6953101Sstever@eecs.umich.edu        bytes = value.split(':')
6963101Sstever@eecs.umich.edu        if len(bytes) != 6:
6974762Snate@binkert.org            raise TypeError, 'invalid ethernet address %s' % value
6983101Sstever@eecs.umich.edu
6993101Sstever@eecs.umich.edu        for byte in bytes:
7003101Sstever@eecs.umich.edu            if not 0 <= int(byte, base=16) <= 0xff:
7014762Snate@binkert.org                raise TypeError, 'invalid ethernet address %s' % value
7024762Snate@binkert.org
7034762Snate@binkert.org        self.value = value
7043101Sstever@eecs.umich.edu
7053101Sstever@eecs.umich.edu    def unproxy(self, base):
7063101Sstever@eecs.umich.edu        if self.value == NextEthernetAddr:
7073101Sstever@eecs.umich.edu            return EthernetAddr(self.value())
7084762Snate@binkert.org        return self
7094762Snate@binkert.org
7104762Snate@binkert.org    def getValue(self):
7114762Snate@binkert.org        from m5.internal.params import EthAddr
7124762Snate@binkert.org        return EthAddr(self.value)
7134762Snate@binkert.org
7144762Snate@binkert.org    def ini_str(self):
7154762Snate@binkert.org        return self.value
7164762Snate@binkert.org
7174762Snate@binkert.org# When initializing an IpAddress, pass in an existing IpAddress, a string of
7184762Snate@binkert.org# the form "a.b.c.d", or an integer representing an IP.
7194762Snate@binkert.orgclass IpAddress(ParamValue):
7204762Snate@binkert.org    cxx_type = 'Net::IpAddress'
7214762Snate@binkert.org
7224762Snate@binkert.org    @classmethod
7234762Snate@binkert.org    def cxx_predecls(cls, code):
7244762Snate@binkert.org        code('#include "base/inet.hh"')
7254762Snate@binkert.org
7264762Snate@binkert.org    @classmethod
7274762Snate@binkert.org    def swig_predecls(cls, code):
7284762Snate@binkert.org        code('%include "python/swig/inet.i"')
7294762Snate@binkert.org
7304762Snate@binkert.org    def __init__(self, value):
7314762Snate@binkert.org        if isinstance(value, IpAddress):
7324762Snate@binkert.org            self.ip = value.ip
7333101Sstever@eecs.umich.edu        else:
7343101Sstever@eecs.umich.edu            try:
7353101Sstever@eecs.umich.edu                self.ip = convert.toIpAddress(value)
7363101Sstever@eecs.umich.edu            except TypeError:
7373101Sstever@eecs.umich.edu                self.ip = long(value)
7383101Sstever@eecs.umich.edu        self.verifyIp()
7393101Sstever@eecs.umich.edu
7403101Sstever@eecs.umich.edu    def __str__(self):
7413101Sstever@eecs.umich.edu        tup = [(self.ip >> i)  & 0xff for i in (24, 16, 8, 0)]
7423101Sstever@eecs.umich.edu        return '%d.%d.%d.%d' % tuple(tup)
7433101Sstever@eecs.umich.edu
7443101Sstever@eecs.umich.edu    def __eq__(self, other):
7454762Snate@binkert.org        if isinstance(other, IpAddress):
7464762Snate@binkert.org            return self.ip == other.ip
7474762Snate@binkert.org        elif isinstance(other, str):
7483101Sstever@eecs.umich.edu            try:
7493101Sstever@eecs.umich.edu                return self.ip == convert.toIpAddress(other)
7503101Sstever@eecs.umich.edu            except:
7513101Sstever@eecs.umich.edu                return False
7523101Sstever@eecs.umich.edu        else:
7533101Sstever@eecs.umich.edu            return self.ip == other
7544167Sbinkertn@umich.edu
7553101Sstever@eecs.umich.edu    def __ne__(self, other):
7563101Sstever@eecs.umich.edu        return not (self == other)
7574762Snate@binkert.org
7583101Sstever@eecs.umich.edu    def verifyIp(self):
7594167Sbinkertn@umich.edu        if self.ip < 0 or self.ip >= (1 << 32):
7604762Snate@binkert.org            raise TypeError, "invalid ip address %#08x" % self.ip
7614762Snate@binkert.org
7624762Snate@binkert.org    def getValue(self):
7634167Sbinkertn@umich.edu        from m5.internal.params import IpAddress
7643101Sstever@eecs.umich.edu        return IpAddress(self.ip)
7654167Sbinkertn@umich.edu
7664167Sbinkertn@umich.edu# When initializing an IpNetmask, pass in an existing IpNetmask, a string of
7674167Sbinkertn@umich.edu# the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as
7684167Sbinkertn@umich.edu# positional or keyword arguments.
7694167Sbinkertn@umich.educlass IpNetmask(IpAddress):
7704167Sbinkertn@umich.edu    cxx_type = 'Net::IpNetmask'
7714167Sbinkertn@umich.edu
7724167Sbinkertn@umich.edu    @classmethod
7734167Sbinkertn@umich.edu    def cxx_predecls(cls, code):
7744167Sbinkertn@umich.edu        code('#include "base/inet.hh"')
7754167Sbinkertn@umich.edu
7764167Sbinkertn@umich.edu    @classmethod
7773101Sstever@eecs.umich.edu    def swig_predecls(cls, code):
7783101Sstever@eecs.umich.edu        code('%include "python/swig/inet.i"')
7793101Sstever@eecs.umich.edu
7803101Sstever@eecs.umich.edu    def __init__(self, *args, **kwargs):
7813101Sstever@eecs.umich.edu        def handle_kwarg(self, kwargs, key, elseVal = None):
7823101Sstever@eecs.umich.edu            if key in kwargs:
7833101Sstever@eecs.umich.edu                setattr(self, key, kwargs.pop(key))
7843101Sstever@eecs.umich.edu            elif elseVal:
7854762Snate@binkert.org                setattr(self, key, elseVal)
7864762Snate@binkert.org            else:
7874762Snate@binkert.org                raise TypeError, "No value set for %s" % key
7884762Snate@binkert.org
7894762Snate@binkert.org        if len(args) == 0:
7904762Snate@binkert.org            handle_kwarg(self, kwargs, 'ip')
7914762Snate@binkert.org            handle_kwarg(self, kwargs, 'netmask')
7923101Sstever@eecs.umich.edu
7933101Sstever@eecs.umich.edu        elif len(args) == 1:
7944762Snate@binkert.org            if kwargs:
7953101Sstever@eecs.umich.edu                if not 'ip' in kwargs and not 'netmask' in kwargs:
7964167Sbinkertn@umich.edu                    raise TypeError, "Invalid arguments"
7973101Sstever@eecs.umich.edu                handle_kwarg(self, kwargs, 'ip', args[0])
7984167Sbinkertn@umich.edu                handle_kwarg(self, kwargs, 'netmask', args[0])
7994167Sbinkertn@umich.edu            elif isinstance(args[0], IpNetmask):
8004167Sbinkertn@umich.edu                self.ip = args[0].ip
8014167Sbinkertn@umich.edu                self.netmask = args[0].netmask
8024167Sbinkertn@umich.edu            else:
8034167Sbinkertn@umich.edu                (self.ip, self.netmask) = convert.toIpNetmask(args[0])
8044167Sbinkertn@umich.edu
8054167Sbinkertn@umich.edu        elif len(args) == 2:
8064167Sbinkertn@umich.edu            self.ip = args[0]
8074167Sbinkertn@umich.edu            self.netmask = args[1]
8084167Sbinkertn@umich.edu        else:
8094167Sbinkertn@umich.edu            raise TypeError, "Too many arguments specified"
8103101Sstever@eecs.umich.edu
8113101Sstever@eecs.umich.edu        if kwargs:
8123101Sstever@eecs.umich.edu            raise TypeError, "Too many keywords: %s" % kwargs.keys()
8133101Sstever@eecs.umich.edu
8143101Sstever@eecs.umich.edu        self.verify()
8153101Sstever@eecs.umich.edu
8163101Sstever@eecs.umich.edu    def __str__(self):
8173101Sstever@eecs.umich.edu        return "%s/%d" % (super(IpNetmask, self).__str__(), self.netmask)
8184167Sbinkertn@umich.edu
8194762Snate@binkert.org    def __eq__(self, other):
8204762Snate@binkert.org        if isinstance(other, IpNetmask):
8214762Snate@binkert.org            return self.ip == other.ip and self.netmask == other.netmask
8224762Snate@binkert.org        elif isinstance(other, str):
8234762Snate@binkert.org            try:
8244762Snate@binkert.org                return (self.ip, self.netmask) == convert.toIpNetmask(other)
8254762Snate@binkert.org            except:
8263101Sstever@eecs.umich.edu                return False
8274762Snate@binkert.org        else:
8283101Sstever@eecs.umich.edu            return False
8293101Sstever@eecs.umich.edu
8303101Sstever@eecs.umich.edu    def verify(self):
8313101Sstever@eecs.umich.edu        self.verifyIp()
8323101Sstever@eecs.umich.edu        if self.netmask < 0 or self.netmask > 32:
8333101Sstever@eecs.umich.edu            raise TypeError, "invalid netmask %d" % netmask
8343101Sstever@eecs.umich.edu
8354762Snate@binkert.org    def getValue(self):
8363101Sstever@eecs.umich.edu        from m5.internal.params import IpNetmask
8373101Sstever@eecs.umich.edu        return IpNetmask(self.ip, self.netmask)
8384167Sbinkertn@umich.edu
8394167Sbinkertn@umich.edu# When initializing an IpWithPort, pass in an existing IpWithPort, a string of
8404167Sbinkertn@umich.edu# the form "a.b.c.d:p", or an ip and port as positional or keyword arguments.
8414167Sbinkertn@umich.educlass IpWithPort(IpAddress):
8424167Sbinkertn@umich.edu    cxx_type = 'Net::IpWithPort'
8434167Sbinkertn@umich.edu
8444167Sbinkertn@umich.edu    @classmethod
8454167Sbinkertn@umich.edu    def cxx_predecls(cls, code):
8464167Sbinkertn@umich.edu        code('#include "base/inet.hh"')
8474167Sbinkertn@umich.edu
8484167Sbinkertn@umich.edu    @classmethod
8494167Sbinkertn@umich.edu    def swig_predecls(cls, code):
8503101Sstever@eecs.umich.edu        code('%include "python/swig/inet.i"')
8513101Sstever@eecs.umich.edu
8523101Sstever@eecs.umich.edu    def __init__(self, *args, **kwargs):
8533101Sstever@eecs.umich.edu        def handle_kwarg(self, kwargs, key, elseVal = None):
8543101Sstever@eecs.umich.edu            if key in kwargs:
8553101Sstever@eecs.umich.edu                setattr(self, key, kwargs.pop(key))
8563101Sstever@eecs.umich.edu            elif elseVal:
8573101Sstever@eecs.umich.edu                setattr(self, key, elseVal)
8584762Snate@binkert.org            else:
8594762Snate@binkert.org                raise TypeError, "No value set for %s" % key
8604762Snate@binkert.org
8613101Sstever@eecs.umich.edu        if len(args) == 0:
8623101Sstever@eecs.umich.edu            handle_kwarg(self, kwargs, 'ip')
8633101Sstever@eecs.umich.edu            handle_kwarg(self, kwargs, 'port')
8643101Sstever@eecs.umich.edu
8653101Sstever@eecs.umich.edu        elif len(args) == 1:
8663101Sstever@eecs.umich.edu            if kwargs:
8674167Sbinkertn@umich.edu                if not 'ip' in kwargs and not 'port' in kwargs:
8684167Sbinkertn@umich.edu                    raise TypeError, "Invalid arguments"
8693101Sstever@eecs.umich.edu                handle_kwarg(self, kwargs, 'ip', args[0])
8703101Sstever@eecs.umich.edu                handle_kwarg(self, kwargs, 'port', args[0])
8713101Sstever@eecs.umich.edu            elif isinstance(args[0], IpWithPort):
8723101Sstever@eecs.umich.edu                self.ip = args[0].ip
8733101Sstever@eecs.umich.edu                self.port = args[0].port
8744762Snate@binkert.org            else:
8754167Sbinkertn@umich.edu                (self.ip, self.port) = convert.toIpWithPort(args[0])
8764167Sbinkertn@umich.edu
8774167Sbinkertn@umich.edu        elif len(args) == 2:
8784762Snate@binkert.org            self.ip = args[0]
8794762Snate@binkert.org            self.port = args[1]
8804762Snate@binkert.org        else:
8814762Snate@binkert.org            raise TypeError, "Too many arguments specified"
8824762Snate@binkert.org
8833101Sstever@eecs.umich.edu        if kwargs:
8843101Sstever@eecs.umich.edu            raise TypeError, "Too many keywords: %s" % kwargs.keys()
8853101Sstever@eecs.umich.edu
8863101Sstever@eecs.umich.edu        self.verify()
8874167Sbinkertn@umich.edu
8883102Sstever@eecs.umich.edu    def __str__(self):
8893101Sstever@eecs.umich.edu        return "%s:%d" % (super(IpWithPort, self).__str__(), self.port)
8903101Sstever@eecs.umich.edu
8913101Sstever@eecs.umich.edu    def __eq__(self, other):
8923101Sstever@eecs.umich.edu        if isinstance(other, IpWithPort):
8933101Sstever@eecs.umich.edu            return self.ip == other.ip and self.port == other.port
8944762Snate@binkert.org        elif isinstance(other, str):
8954167Sbinkertn@umich.edu            try:
8964167Sbinkertn@umich.edu                return (self.ip, self.port) == convert.toIpWithPort(other)
8974167Sbinkertn@umich.edu            except:
8984762Snate@binkert.org                return False
8994762Snate@binkert.org        else:
9004762Snate@binkert.org            return False
9014762Snate@binkert.org
9024762Snate@binkert.org    def verify(self):
9033101Sstever@eecs.umich.edu        self.verifyIp()
9043101Sstever@eecs.umich.edu        if self.port < 0 or self.port > 0xffff:
9053101Sstever@eecs.umich.edu            raise TypeError, "invalid port %d" % self.port
9063101Sstever@eecs.umich.edu
9073101Sstever@eecs.umich.edu    def getValue(self):
9083102Sstever@eecs.umich.edu        from m5.internal.params import IpWithPort
9093102Sstever@eecs.umich.edu        return IpWithPort(self.ip, self.port)
9103102Sstever@eecs.umich.edu
9113102Sstever@eecs.umich.edutime_formats = [ "%a %b %d %H:%M:%S %Z %Y",
9123102Sstever@eecs.umich.edu                 "%a %b %d %H:%M:%S %Z %Y",
9133102Sstever@eecs.umich.edu                 "%Y/%m/%d %H:%M:%S",
9143102Sstever@eecs.umich.edu                 "%Y/%m/%d %H:%M",
9153102Sstever@eecs.umich.edu                 "%Y/%m/%d",
9163102Sstever@eecs.umich.edu                 "%m/%d/%Y %H:%M:%S",
9173102Sstever@eecs.umich.edu                 "%m/%d/%Y %H:%M",
9183102Sstever@eecs.umich.edu                 "%m/%d/%Y",
9193102Sstever@eecs.umich.edu                 "%m/%d/%y %H:%M:%S",
9203102Sstever@eecs.umich.edu                 "%m/%d/%y %H:%M",
9213102Sstever@eecs.umich.edu                 "%m/%d/%y"]
9223102Sstever@eecs.umich.edu
9233102Sstever@eecs.umich.edu
9243102Sstever@eecs.umich.edudef parse_time(value):
9253102Sstever@eecs.umich.edu    from time import gmtime, strptime, struct_time, time
9263102Sstever@eecs.umich.edu    from datetime import datetime, date
9273102Sstever@eecs.umich.edu
9283102Sstever@eecs.umich.edu    if isinstance(value, struct_time):
9294762Snate@binkert.org        return value
9303102Sstever@eecs.umich.edu
9313102Sstever@eecs.umich.edu    if isinstance(value, (int, long)):
9323102Sstever@eecs.umich.edu        return gmtime(value)
9334762Snate@binkert.org
9344762Snate@binkert.org    if isinstance(value, (datetime, date)):
9354762Snate@binkert.org        return value.timetuple()
9363102Sstever@eecs.umich.edu
9373102Sstever@eecs.umich.edu    if isinstance(value, str):
9383102Sstever@eecs.umich.edu        if value in ('Now', 'Today'):
9393102Sstever@eecs.umich.edu            return time.gmtime(time.time())
9403102Sstever@eecs.umich.edu
9413102Sstever@eecs.umich.edu        for format in time_formats:
9423101Sstever@eecs.umich.edu            try:
9433101Sstever@eecs.umich.edu                return strptime(value, format)
9443101Sstever@eecs.umich.edu            except ValueError:
9453101Sstever@eecs.umich.edu                pass
9463101Sstever@eecs.umich.edu
9473101Sstever@eecs.umich.edu    raise ValueError, "Could not parse '%s' as a time" % value
9483101Sstever@eecs.umich.edu
9493101Sstever@eecs.umich.educlass Time(ParamValue):
9503101Sstever@eecs.umich.edu    cxx_type = 'tm'
9513101Sstever@eecs.umich.edu
9523101Sstever@eecs.umich.edu    @classmethod
9533101Sstever@eecs.umich.edu    def cxx_predecls(cls, code):
9543101Sstever@eecs.umich.edu        code('#include <time.h>')
9553101Sstever@eecs.umich.edu
9563101Sstever@eecs.umich.edu    @classmethod
9573101Sstever@eecs.umich.edu    def swig_predecls(cls, code):
9583101Sstever@eecs.umich.edu        code('%include "python/swig/time.i"')
9593105Sstever@eecs.umich.edu
9603105Sstever@eecs.umich.edu    def __init__(self, value):
9613101Sstever@eecs.umich.edu        self.value = parse_time(value)
9623101Sstever@eecs.umich.edu
9633101Sstever@eecs.umich.edu    def getValue(self):
9643101Sstever@eecs.umich.edu        from m5.internal.params import tm
9653105Sstever@eecs.umich.edu
9663101Sstever@eecs.umich.edu        c_time = tm()
9673103Sstever@eecs.umich.edu        py_time = self.value
9683105Sstever@eecs.umich.edu
9693103Sstever@eecs.umich.edu        # UNIX is years since 1900
9703105Sstever@eecs.umich.edu        c_time.tm_year = py_time.tm_year - 1900;
9713105Sstever@eecs.umich.edu
9723105Sstever@eecs.umich.edu        # Python starts at 1, UNIX starts at 0
9733105Sstever@eecs.umich.edu        c_time.tm_mon =  py_time.tm_mon - 1;
9743105Sstever@eecs.umich.edu        c_time.tm_mday = py_time.tm_mday;
9753105Sstever@eecs.umich.edu        c_time.tm_hour = py_time.tm_hour;
9763105Sstever@eecs.umich.edu        c_time.tm_min = py_time.tm_min;
9773105Sstever@eecs.umich.edu        c_time.tm_sec = py_time.tm_sec;
9783105Sstever@eecs.umich.edu
9793105Sstever@eecs.umich.edu        # Python has 0 as Monday, UNIX is 0 as sunday
9803105Sstever@eecs.umich.edu        c_time.tm_wday = py_time.tm_wday + 1
9813105Sstever@eecs.umich.edu        if c_time.tm_wday > 6:
9823105Sstever@eecs.umich.edu            c_time.tm_wday -= 7;
9833109Sstever@eecs.umich.edu
9843105Sstever@eecs.umich.edu        # Python starts at 1, Unix starts at 0
9853105Sstever@eecs.umich.edu        c_time.tm_yday = py_time.tm_yday - 1;
9863105Sstever@eecs.umich.edu
9873105Sstever@eecs.umich.edu        return c_time
9883105Sstever@eecs.umich.edu
9893105Sstever@eecs.umich.edu    def __str__(self):
9903105Sstever@eecs.umich.edu        return time.asctime(self.value)
9913105Sstever@eecs.umich.edu
9923101Sstever@eecs.umich.edu    def ini_str(self):
9933109Sstever@eecs.umich.edu        return str(self)
9943109Sstever@eecs.umich.edu
9953109Sstever@eecs.umich.edu    def get_config_as_dict(self):
9963109Sstever@eecs.umich.edu        return str(self)
9973109Sstever@eecs.umich.edu
9983109Sstever@eecs.umich.edu# Enumerated types are a little more complex.  The user specifies the
9993109Sstever@eecs.umich.edu# type as Enum(foo) where foo is either a list or dictionary of
10003109Sstever@eecs.umich.edu# alternatives (typically strings, but not necessarily so).  (In the
10013109Sstever@eecs.umich.edu# long run, the integer value of the parameter will be the list index
10023101Sstever@eecs.umich.edu# or the corresponding dictionary value.  For now, since we only check
10033105Sstever@eecs.umich.edu# that the alternative is valid and then spit it into a .ini file,
10043105Sstever@eecs.umich.edu# there's not much point in using the dictionary.)
10053105Sstever@eecs.umich.edu
10063101Sstever@eecs.umich.edu# What Enum() must do is generate a new type encapsulating the
10073105Sstever@eecs.umich.edu# provided list/dictionary so that specific values of the parameter
10083105Sstever@eecs.umich.edu# can be instances of that type.  We define two hidden internal
10093101Sstever@eecs.umich.edu# classes (_ListEnum and _DictEnum) to serve as base classes, then
10103105Sstever@eecs.umich.edu# derive the new type from the appropriate base class on the fly.
10113179Sstever@eecs.umich.edu
10123105Sstever@eecs.umich.eduallEnums = {}
10133105Sstever@eecs.umich.edu# Metaclass for Enum types
10143101Sstever@eecs.umich.educlass MetaEnum(MetaParamValue):
10153101Sstever@eecs.umich.edu    def __new__(mcls, name, bases, dict):
10163105Sstever@eecs.umich.edu        assert name not in allEnums
10173105Sstever@eecs.umich.edu
10183105Sstever@eecs.umich.edu        cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict)
10193105Sstever@eecs.umich.edu        allEnums[name] = cls
10203105Sstever@eecs.umich.edu        return cls
10213105Sstever@eecs.umich.edu
10223105Sstever@eecs.umich.edu    def __init__(cls, name, bases, init_dict):
10233105Sstever@eecs.umich.edu        if init_dict.has_key('map'):
10243105Sstever@eecs.umich.edu            if not isinstance(cls.map, dict):
10253105Sstever@eecs.umich.edu                raise TypeError, "Enum-derived class attribute 'map' " \
10263105Sstever@eecs.umich.edu                      "must be of type dict"
10273101Sstever@eecs.umich.edu            # build list of value strings from map
10283101Sstever@eecs.umich.edu            cls.vals = cls.map.keys()
10294859Snate@binkert.org            cls.vals.sort()
10304762Snate@binkert.org        elif init_dict.has_key('vals'):
10313101Sstever@eecs.umich.edu            if not isinstance(cls.vals, list):
10323101Sstever@eecs.umich.edu                raise TypeError, "Enum-derived class attribute 'vals' " \
10333101Sstever@eecs.umich.edu                      "must be of type list"
10344859Snate@binkert.org            # build string->value map from vals sequence
10354859Snate@binkert.org            cls.map = {}
10363101Sstever@eecs.umich.edu            for idx,val in enumerate(cls.vals):
10373101Sstever@eecs.umich.edu                cls.map[val] = idx
10383101Sstever@eecs.umich.edu        else:
10393105Sstever@eecs.umich.edu            raise TypeError, "Enum-derived class must define "\
10403105Sstever@eecs.umich.edu                  "attribute 'map' or 'vals'"
10413105Sstever@eecs.umich.edu
10423105Sstever@eecs.umich.edu        cls.cxx_type = 'Enums::%s' % name
10433105Sstever@eecs.umich.edu
10443105Sstever@eecs.umich.edu        super(MetaEnum, cls).__init__(name, bases, init_dict)
10453105Sstever@eecs.umich.edu
10463105Sstever@eecs.umich.edu    # Generate C++ class declaration for this enum type.
10473105Sstever@eecs.umich.edu    # Note that we wrap the enum in a class/struct to act as a namespace,
10483105Sstever@eecs.umich.edu    # so that the enum strings can be brief w/o worrying about collisions.
10493105Sstever@eecs.umich.edu    def cxx_decl(cls, code):
10503105Sstever@eecs.umich.edu        name = cls.__name__
10513105Sstever@eecs.umich.edu        code('''\
10523105Sstever@eecs.umich.edu#ifndef __ENUM__${name}__
10533105Sstever@eecs.umich.edu#define __ENUM__${name}__
10543105Sstever@eecs.umich.edu
10553105Sstever@eecs.umich.edunamespace Enums {
10563105Sstever@eecs.umich.edu    enum $name {
10573105Sstever@eecs.umich.edu''')
10583109Sstever@eecs.umich.edu        code.indent(2)
10593109Sstever@eecs.umich.edu        for val in cls.vals:
10603109Sstever@eecs.umich.edu            code('$val = ${{cls.map[val]}},')
10613105Sstever@eecs.umich.edu        code('Num_$name = ${{len(cls.vals)}}')
10623105Sstever@eecs.umich.edu        code.dedent(2)
10633105Sstever@eecs.umich.edu        code('''\
10643105Sstever@eecs.umich.edu    };
10653105Sstever@eecs.umich.eduextern const char *${name}Strings[Num_${name}];
10663105Sstever@eecs.umich.edu}
10673105Sstever@eecs.umich.edu
10683105Sstever@eecs.umich.edu#endif // __ENUM__${name}__
10693105Sstever@eecs.umich.edu''')
10703105Sstever@eecs.umich.edu
10713105Sstever@eecs.umich.edu    def cxx_def(cls, code):
10723105Sstever@eecs.umich.edu        name = cls.__name__
10733105Sstever@eecs.umich.edu        code('''\
10743105Sstever@eecs.umich.edu#include "enums/$name.hh"
10753105Sstever@eecs.umich.edunamespace Enums {
10763105Sstever@eecs.umich.edu    const char *${name}Strings[Num_${name}] =
10773105Sstever@eecs.umich.edu    {
10783105Sstever@eecs.umich.edu''')
10793105Sstever@eecs.umich.edu        code.indent(2)
10803105Sstever@eecs.umich.edu        for val in cls.vals:
10813105Sstever@eecs.umich.edu            code('"$val",')
10823105Sstever@eecs.umich.edu        code.dedent(2)
10833105Sstever@eecs.umich.edu        code('''
10843109Sstever@eecs.umich.edu    };
10853109Sstever@eecs.umich.edu} // namespace Enums
10863109Sstever@eecs.umich.edu''')
10873109Sstever@eecs.umich.edu
10883109Sstever@eecs.umich.edu    def swig_decl(cls, code):
10893109Sstever@eecs.umich.edu        name = cls.__name__
10903109Sstever@eecs.umich.edu        code('''\
10913109Sstever@eecs.umich.edu%module(package="m5.internal") enum_$name
10923109Sstever@eecs.umich.edu
10933109Sstever@eecs.umich.edu%{
10943109Sstever@eecs.umich.edu#include "enums/$name.hh"
10953109Sstever@eecs.umich.edu%}
10963109Sstever@eecs.umich.edu
10973109Sstever@eecs.umich.edu%include "enums/$name.hh"
10983109Sstever@eecs.umich.edu''')
10993109Sstever@eecs.umich.edu
11003109Sstever@eecs.umich.edu
11013109Sstever@eecs.umich.edu# Base class for enum types.
11023109Sstever@eecs.umich.educlass Enum(ParamValue):
11033105Sstever@eecs.umich.edu    __metaclass__ = MetaEnum
11043105Sstever@eecs.umich.edu    vals = []
11053105Sstever@eecs.umich.edu
11063105Sstever@eecs.umich.edu    def __init__(self, value):
11073105Sstever@eecs.umich.edu        if value not in self.map:
11083105Sstever@eecs.umich.edu            raise TypeError, "Enum param got bad value '%s' (not in %s)" \
11093105Sstever@eecs.umich.edu                  % (value, self.vals)
11103101Sstever@eecs.umich.edu        self.value = value
11113101Sstever@eecs.umich.edu
11123101Sstever@eecs.umich.edu    @classmethod
11133101Sstever@eecs.umich.edu    def cxx_predecls(cls, code):
11143105Sstever@eecs.umich.edu        code('#include "enums/$0.hh"', cls.__name__)
11153105Sstever@eecs.umich.edu
11163105Sstever@eecs.umich.edu    @classmethod
11173105Sstever@eecs.umich.edu    def swig_predecls(cls, code):
11183105Sstever@eecs.umich.edu        code('%import "python/m5/internal/enum_$0.i"', cls.__name__)
11193105Sstever@eecs.umich.edu
11203105Sstever@eecs.umich.edu    def getValue(self):
11213105Sstever@eecs.umich.edu        return int(self.map[self.value])
11223105Sstever@eecs.umich.edu
11233105Sstever@eecs.umich.edu    def __str__(self):
11243105Sstever@eecs.umich.edu        return self.value
11253101Sstever@eecs.umich.edu
11263101Sstever@eecs.umich.edu# how big does a rounding error need to be before we warn about it?
11273101Sstever@eecs.umich.edufrequency_tolerance = 0.001  # 0.1%
11283105Sstever@eecs.umich.edu
11293105Sstever@eecs.umich.educlass TickParamValue(NumericParamValue):
11303101Sstever@eecs.umich.edu    cxx_type = 'Tick'
11313101Sstever@eecs.umich.edu
11323101Sstever@eecs.umich.edu    @classmethod
11333105Sstever@eecs.umich.edu    def cxx_predecls(cls, code):
11343105Sstever@eecs.umich.edu        code('#include "base/types.hh"')
11353101Sstever@eecs.umich.edu
11363101Sstever@eecs.umich.edu    @classmethod
11373101Sstever@eecs.umich.edu    def swig_predecls(cls, code):
11383101Sstever@eecs.umich.edu        code('%import "stdint.i"')
11393105Sstever@eecs.umich.edu        code('%import "base/types.hh"')
11403105Sstever@eecs.umich.edu
11413101Sstever@eecs.umich.edu    def getValue(self):
11423101Sstever@eecs.umich.edu        return long(self.value)
11433105Sstever@eecs.umich.edu
11443105Sstever@eecs.umich.educlass Latency(TickParamValue):
11453105Sstever@eecs.umich.edu    def __init__(self, value):
11463109Sstever@eecs.umich.edu        if isinstance(value, (Latency, Clock)):
11473109Sstever@eecs.umich.edu            self.ticks = value.ticks
11483109Sstever@eecs.umich.edu            self.value = value.value
11493109Sstever@eecs.umich.edu        elif isinstance(value, Frequency):
11503109Sstever@eecs.umich.edu            self.ticks = value.ticks
11513109Sstever@eecs.umich.edu            self.value = 1.0 / value.value
11523109Sstever@eecs.umich.edu        elif value.endswith('t'):
11533109Sstever@eecs.umich.edu            self.ticks = True
11543105Sstever@eecs.umich.edu            self.value = int(value[:-1])
11553101Sstever@eecs.umich.edu        else:
11563101Sstever@eecs.umich.edu            self.ticks = False
11573101Sstever@eecs.umich.edu            self.value = convert.toLatency(value)
11583101Sstever@eecs.umich.edu
11593101Sstever@eecs.umich.edu    def __getattr__(self, attr):
11603101Sstever@eecs.umich.edu        if attr in ('latency', 'period'):
11613101Sstever@eecs.umich.edu            return self
11624167Sbinkertn@umich.edu        if attr == 'frequency':
11633101Sstever@eecs.umich.edu            return Frequency(self)
11643101Sstever@eecs.umich.edu        raise AttributeError, "Latency object has no attribute '%s'" % attr
11653101Sstever@eecs.umich.edu
11663885Sbinkertn@umich.edu    def getValue(self):
11673102Sstever@eecs.umich.edu        if self.ticks or self.value == 0:
11683101Sstever@eecs.umich.edu            value = self.value
1169        else:
1170            value = ticks.fromSeconds(self.value)
1171        return long(value)
1172
1173    # convert latency to ticks
1174    def ini_str(self):
1175        return '%d' % self.getValue()
1176
1177class Frequency(TickParamValue):
1178    def __init__(self, value):
1179        if isinstance(value, (Latency, Clock)):
1180            if value.value == 0:
1181                self.value = 0
1182            else:
1183                self.value = 1.0 / value.value
1184            self.ticks = value.ticks
1185        elif isinstance(value, Frequency):
1186            self.value = value.value
1187            self.ticks = value.ticks
1188        else:
1189            self.ticks = False
1190            self.value = convert.toFrequency(value)
1191
1192    def __getattr__(self, attr):
1193        if attr == 'frequency':
1194            return self
1195        if attr in ('latency', 'period'):
1196            return Latency(self)
1197        raise AttributeError, "Frequency object has no attribute '%s'" % attr
1198
1199    # convert latency to ticks
1200    def getValue(self):
1201        if self.ticks or self.value == 0:
1202            value = self.value
1203        else:
1204            value = ticks.fromSeconds(1.0 / self.value)
1205        return long(value)
1206
1207    def ini_str(self):
1208        return '%d' % self.getValue()
1209
1210# A generic frequency and/or Latency value. Value is stored as a
1211# latency, and any manipulation using a multiplier thus scales the
1212# clock period, i.e. a 2x multiplier doubles the clock period and thus
1213# halves the clock frequency.
1214class Clock(ParamValue):
1215    cxx_type = 'Tick'
1216
1217    @classmethod
1218    def cxx_predecls(cls, code):
1219        code('#include "base/types.hh"')
1220
1221    @classmethod
1222    def swig_predecls(cls, code):
1223        code('%import "stdint.i"')
1224        code('%import "base/types.hh"')
1225
1226    def __init__(self, value):
1227        if isinstance(value, (Latency, Clock)):
1228            self.ticks = value.ticks
1229            self.value = value.value
1230        elif isinstance(value, Frequency):
1231            self.ticks = value.ticks
1232            self.value = 1.0 / value.value
1233        elif value.endswith('t'):
1234            self.ticks = True
1235            self.value = int(value[:-1])
1236        else:
1237            self.ticks = False
1238            self.value = convert.anyToLatency(value)
1239
1240    def __getattr__(self, attr):
1241        if attr == 'frequency':
1242            return Frequency(self)
1243        if attr in ('latency', 'period'):
1244            return Latency(self)
1245        raise AttributeError, "Frequency object has no attribute '%s'" % attr
1246
1247    def getValue(self):
1248        return self.period.getValue()
1249
1250    def ini_str(self):
1251        return self.period.ini_str()
1252
1253class Voltage(float,ParamValue):
1254    cxx_type = 'double'
1255    def __new__(cls, value):
1256        # convert to voltage
1257        val = convert.toVoltage(value)
1258        return super(cls, Voltage).__new__(cls, val)
1259
1260    def __str__(self):
1261        return str(self.val)
1262
1263    def getValue(self):
1264        value = float(self)
1265        return value
1266
1267    def ini_str(self):
1268        return '%f' % self.getValue()
1269
1270class NetworkBandwidth(float,ParamValue):
1271    cxx_type = 'float'
1272    def __new__(cls, value):
1273        # convert to bits per second
1274        val = convert.toNetworkBandwidth(value)
1275        return super(cls, NetworkBandwidth).__new__(cls, val)
1276
1277    def __str__(self):
1278        return str(self.val)
1279
1280    def getValue(self):
1281        # convert to seconds per byte
1282        value = 8.0 / float(self)
1283        # convert to ticks per byte
1284        value = ticks.fromSeconds(value)
1285        return float(value)
1286
1287    def ini_str(self):
1288        return '%f' % self.getValue()
1289
1290class MemoryBandwidth(float,ParamValue):
1291    cxx_type = 'float'
1292    def __new__(cls, value):
1293        # convert to bytes per second
1294        val = convert.toMemoryBandwidth(value)
1295        return super(cls, MemoryBandwidth).__new__(cls, val)
1296
1297    def __str__(self):
1298        return str(self.val)
1299
1300    def getValue(self):
1301        # convert to seconds per byte
1302        value = float(self)
1303        if value:
1304            value = 1.0 / float(self)
1305        # convert to ticks per byte
1306        value = ticks.fromSeconds(value)
1307        return float(value)
1308
1309    def ini_str(self):
1310        return '%f' % self.getValue()
1311
1312#
1313# "Constants"... handy aliases for various values.
1314#
1315
1316# Special class for NULL pointers.  Note the special check in
1317# make_param_value() above that lets these be assigned where a
1318# SimObject is required.
1319# only one copy of a particular node
1320class NullSimObject(object):
1321    __metaclass__ = Singleton
1322
1323    def __call__(cls):
1324        return cls
1325
1326    def _instantiate(self, parent = None, path = ''):
1327        pass
1328
1329    def ini_str(self):
1330        return 'Null'
1331
1332    def unproxy(self, base):
1333        return self
1334
1335    def set_path(self, parent, name):
1336        pass
1337
1338    def __str__(self):
1339        return 'Null'
1340
1341    def getValue(self):
1342        return None
1343
1344# The only instance you'll ever need...
1345NULL = NullSimObject()
1346
1347def isNullPointer(value):
1348    return isinstance(value, NullSimObject)
1349
1350# Some memory range specifications use this as a default upper bound.
1351MaxAddr = Addr.max
1352MaxTick = Tick.max
1353AllMemory = AddrRange(0, MaxAddr)
1354
1355
1356#####################################################################
1357#
1358# Port objects
1359#
1360# Ports are used to interconnect objects in the memory system.
1361#
1362#####################################################################
1363
1364# Port reference: encapsulates a reference to a particular port on a
1365# particular SimObject.
1366class PortRef(object):
1367    def __init__(self, simobj, name, role):
1368        assert(isSimObject(simobj) or isSimObjectClass(simobj))
1369        self.simobj = simobj
1370        self.name = name
1371        self.role = role
1372        self.peer = None   # not associated with another port yet
1373        self.ccConnected = False # C++ port connection done?
1374        self.index = -1  # always -1 for non-vector ports
1375
1376    def __str__(self):
1377        return '%s.%s' % (self.simobj, self.name)
1378
1379    def __len__(self):
1380        # Return the number of connected ports, i.e. 0 is we have no
1381        # peer and 1 if we do.
1382        return int(self.peer != None)
1383
1384    # for config.ini, print peer's name (not ours)
1385    def ini_str(self):
1386        return str(self.peer)
1387
1388    # for config.json
1389    def get_config_as_dict(self):
1390        return {'role' : self.role, 'peer' : str(self.peer)}
1391
1392    def __getattr__(self, attr):
1393        if attr == 'peerObj':
1394            # shorthand for proxies
1395            return self.peer.simobj
1396        raise AttributeError, "'%s' object has no attribute '%s'" % \
1397              (self.__class__.__name__, attr)
1398
1399    # Full connection is symmetric (both ways).  Called via
1400    # SimObject.__setattr__ as a result of a port assignment, e.g.,
1401    # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
1402    # e.g., "obj1.portA[3] = obj2.portB".
1403    def connect(self, other):
1404        if isinstance(other, VectorPortRef):
1405            # reference to plain VectorPort is implicit append
1406            other = other._get_next()
1407        if self.peer and not proxy.isproxy(self.peer):
1408            fatal("Port %s is already connected to %s, cannot connect %s\n",
1409                  self, self.peer, other);
1410        self.peer = other
1411        if proxy.isproxy(other):
1412            other.set_param_desc(PortParamDesc())
1413        elif isinstance(other, PortRef):
1414            if other.peer is not self:
1415                other.connect(self)
1416        else:
1417            raise TypeError, \
1418                  "assigning non-port reference '%s' to port '%s'" \
1419                  % (other, self)
1420
1421    def clone(self, simobj, memo):
1422        if memo.has_key(self):
1423            return memo[self]
1424        newRef = copy.copy(self)
1425        memo[self] = newRef
1426        newRef.simobj = simobj
1427        assert(isSimObject(newRef.simobj))
1428        if self.peer and not proxy.isproxy(self.peer):
1429            peerObj = self.peer.simobj(_memo=memo)
1430            newRef.peer = self.peer.clone(peerObj, memo)
1431            assert(not isinstance(newRef.peer, VectorPortRef))
1432        return newRef
1433
1434    def unproxy(self, simobj):
1435        assert(simobj is self.simobj)
1436        if proxy.isproxy(self.peer):
1437            try:
1438                realPeer = self.peer.unproxy(self.simobj)
1439            except:
1440                print "Error in unproxying port '%s' of %s" % \
1441                      (self.name, self.simobj.path())
1442                raise
1443            self.connect(realPeer)
1444
1445    # Call C++ to create corresponding port connection between C++ objects
1446    def ccConnect(self):
1447        from m5.internal.pyobject import connectPorts
1448
1449        if self.role == 'SLAVE':
1450            # do nothing and let the master take care of it
1451            return
1452
1453        if self.ccConnected: # already done this
1454            return
1455        peer = self.peer
1456        if not self.peer: # nothing to connect to
1457            return
1458
1459        # check that we connect a master to a slave
1460        if self.role == peer.role:
1461            raise TypeError, \
1462                "cannot connect '%s' and '%s' due to identical role '%s'" \
1463                % (peer, self, self.role)
1464
1465        try:
1466            # self is always the master and peer the slave
1467            connectPorts(self.simobj.getCCObject(), self.name, self.index,
1468                         peer.simobj.getCCObject(), peer.name, peer.index)
1469        except:
1470            print "Error connecting port %s.%s to %s.%s" % \
1471                  (self.simobj.path(), self.name,
1472                   peer.simobj.path(), peer.name)
1473            raise
1474        self.ccConnected = True
1475        peer.ccConnected = True
1476
1477# A reference to an individual element of a VectorPort... much like a
1478# PortRef, but has an index.
1479class VectorPortElementRef(PortRef):
1480    def __init__(self, simobj, name, role, index):
1481        PortRef.__init__(self, simobj, name, role)
1482        self.index = index
1483
1484    def __str__(self):
1485        return '%s.%s[%d]' % (self.simobj, self.name, self.index)
1486
1487# A reference to a complete vector-valued port (not just a single element).
1488# Can be indexed to retrieve individual VectorPortElementRef instances.
1489class VectorPortRef(object):
1490    def __init__(self, simobj, name, role):
1491        assert(isSimObject(simobj) or isSimObjectClass(simobj))
1492        self.simobj = simobj
1493        self.name = name
1494        self.role = role
1495        self.elements = []
1496
1497    def __str__(self):
1498        return '%s.%s[:]' % (self.simobj, self.name)
1499
1500    def __len__(self):
1501        # Return the number of connected peers, corresponding the the
1502        # length of the elements.
1503        return len(self.elements)
1504
1505    # for config.ini, print peer's name (not ours)
1506    def ini_str(self):
1507        return ' '.join([el.ini_str() for el in self.elements])
1508
1509    # for config.json
1510    def get_config_as_dict(self):
1511        return {'role' : self.role,
1512                'peer' : [el.ini_str() for el in self.elements]}
1513
1514    def __getitem__(self, key):
1515        if not isinstance(key, int):
1516            raise TypeError, "VectorPort index must be integer"
1517        if key >= len(self.elements):
1518            # need to extend list
1519            ext = [VectorPortElementRef(self.simobj, self.name, self.role, i)
1520                   for i in range(len(self.elements), key+1)]
1521            self.elements.extend(ext)
1522        return self.elements[key]
1523
1524    def _get_next(self):
1525        return self[len(self.elements)]
1526
1527    def __setitem__(self, key, value):
1528        if not isinstance(key, int):
1529            raise TypeError, "VectorPort index must be integer"
1530        self[key].connect(value)
1531
1532    def connect(self, other):
1533        if isinstance(other, (list, tuple)):
1534            # Assign list of port refs to vector port.
1535            # For now, append them... not sure if that's the right semantics
1536            # or if it should replace the current vector.
1537            for ref in other:
1538                self._get_next().connect(ref)
1539        else:
1540            # scalar assignment to plain VectorPort is implicit append
1541            self._get_next().connect(other)
1542
1543    def clone(self, simobj, memo):
1544        if memo.has_key(self):
1545            return memo[self]
1546        newRef = copy.copy(self)
1547        memo[self] = newRef
1548        newRef.simobj = simobj
1549        assert(isSimObject(newRef.simobj))
1550        newRef.elements = [el.clone(simobj, memo) for el in self.elements]
1551        return newRef
1552
1553    def unproxy(self, simobj):
1554        [el.unproxy(simobj) for el in self.elements]
1555
1556    def ccConnect(self):
1557        [el.ccConnect() for el in self.elements]
1558
1559# Port description object.  Like a ParamDesc object, this represents a
1560# logical port in the SimObject class, not a particular port on a
1561# SimObject instance.  The latter are represented by PortRef objects.
1562class Port(object):
1563    # Generate a PortRef for this port on the given SimObject with the
1564    # given name
1565    def makeRef(self, simobj):
1566        return PortRef(simobj, self.name, self.role)
1567
1568    # Connect an instance of this port (on the given SimObject with
1569    # the given name) with the port described by the supplied PortRef
1570    def connect(self, simobj, ref):
1571        self.makeRef(simobj).connect(ref)
1572
1573    # No need for any pre-declarations at the moment as we merely rely
1574    # on an unsigned int.
1575    def cxx_predecls(self, code):
1576        pass
1577
1578    # Declare an unsigned int with the same name as the port, that
1579    # will eventually hold the number of connected ports (and thus the
1580    # number of elements for a VectorPort).
1581    def cxx_decl(self, code):
1582        code('unsigned int port_${{self.name}}_connection_count;')
1583
1584class MasterPort(Port):
1585    # MasterPort("description")
1586    def __init__(self, *args):
1587        if len(args) == 1:
1588            self.desc = args[0]
1589            self.role = 'MASTER'
1590        else:
1591            raise TypeError, 'wrong number of arguments'
1592
1593class SlavePort(Port):
1594    # SlavePort("description")
1595    def __init__(self, *args):
1596        if len(args) == 1:
1597            self.desc = args[0]
1598            self.role = 'SLAVE'
1599        else:
1600            raise TypeError, 'wrong number of arguments'
1601
1602# VectorPort description object.  Like Port, but represents a vector
1603# of connections (e.g., as on a Bus).
1604class VectorPort(Port):
1605    def __init__(self, *args):
1606        self.isVec = True
1607
1608    def makeRef(self, simobj):
1609        return VectorPortRef(simobj, self.name, self.role)
1610
1611class VectorMasterPort(VectorPort):
1612    # VectorMasterPort("description")
1613    def __init__(self, *args):
1614        if len(args) == 1:
1615            self.desc = args[0]
1616            self.role = 'MASTER'
1617            VectorPort.__init__(self, *args)
1618        else:
1619            raise TypeError, 'wrong number of arguments'
1620
1621class VectorSlavePort(VectorPort):
1622    # VectorSlavePort("description")
1623    def __init__(self, *args):
1624        if len(args) == 1:
1625            self.desc = args[0]
1626            self.role = 'SLAVE'
1627            VectorPort.__init__(self, *args)
1628        else:
1629            raise TypeError, 'wrong number of arguments'
1630
1631# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
1632# proxy objects (via set_param_desc()) so that proxy error messages
1633# make sense.
1634class PortParamDesc(object):
1635    __metaclass__ = Singleton
1636
1637    ptype_str = 'Port'
1638    ptype = Port
1639
1640baseEnums = allEnums.copy()
1641baseParams = allParams.copy()
1642
1643def clear():
1644    global allEnums, allParams
1645
1646    allEnums = baseEnums.copy()
1647    allParams = baseParams.copy()
1648
1649__all__ = ['Param', 'VectorParam',
1650           'Enum', 'Bool', 'String', 'Float',
1651           'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
1652           'Int32', 'UInt32', 'Int64', 'UInt64',
1653           'Counter', 'Addr', 'Tick', 'Percent',
1654           'TcpPort', 'UdpPort', 'EthernetAddr',
1655           'IpAddress', 'IpNetmask', 'IpWithPort',
1656           'MemorySize', 'MemorySize32',
1657           'Latency', 'Frequency', 'Clock', 'Voltage',
1658           'NetworkBandwidth', 'MemoryBandwidth',
1659           'AddrRange',
1660           'MaxAddr', 'MaxTick', 'AllMemory',
1661           'Time',
1662           'NextEthernetAddr', 'NULL',
1663           'MasterPort', 'SlavePort',
1664           'VectorMasterPort', 'VectorSlavePort']
1665
1666import SimObject
1667