params.py revision 9544:1a075d9bc1bc
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#
473101Sstever@eecs.umich.edu# Parameter description classes
483101Sstever@eecs.umich.edu#
493101Sstever@eecs.umich.edu# The _params dictionary in each class maps parameter names to either
503101Sstever@eecs.umich.edu# a Param or a VectorParam object.  These objects contain the
513101Sstever@eecs.umich.edu# parameter description string, the parameter type, and the default
523101Sstever@eecs.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
543101Sstever@eecs.umich.edu# type.
553101Sstever@eecs.umich.edu#
563101Sstever@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
583101Sstever@eecs.umich.edu# MetaSimObject._new_param()); after that point they aren't used.
593101Sstever@eecs.umich.edu#
603101Sstever@eecs.umich.edu#####################################################################
613101Sstever@eecs.umich.edu
623101Sstever@eecs.umich.eduimport copy
633101Sstever@eecs.umich.eduimport datetime
643101Sstever@eecs.umich.eduimport re
653101Sstever@eecs.umich.eduimport sys
663101Sstever@eecs.umich.eduimport time
673101Sstever@eecs.umich.eduimport math
683101Sstever@eecs.umich.edu
693101Sstever@eecs.umich.eduimport proxy
703101Sstever@eecs.umich.eduimport ticks
713101Sstever@eecs.umich.edufrom util import *
723101Sstever@eecs.umich.edu
733101Sstever@eecs.umich.edudef isSimObject(*args, **kwargs):
743101Sstever@eecs.umich.edu    return SimObject.isSimObject(*args, **kwargs)
753101Sstever@eecs.umich.edu
763101Sstever@eecs.umich.edudef isSimObjectSequence(*args, **kwargs):
773101Sstever@eecs.umich.edu    return SimObject.isSimObjectSequence(*args, **kwargs)
783101Sstever@eecs.umich.edu
793101Sstever@eecs.umich.edudef isSimObjectClass(*args, **kwargs):
803101Sstever@eecs.umich.edu    return SimObject.isSimObjectClass(*args, **kwargs)
813101Sstever@eecs.umich.edu
823101Sstever@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:
1323101Sstever@eecs.umich.edu                self.desc = args[0]
1333101Sstever@eecs.umich.edu            elif len(args) == 2:
1343101Sstever@eecs.umich.edu                self.default = args[0]
1353101Sstever@eecs.umich.edu                self.desc = args[1]
1363101Sstever@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:
1503101Sstever@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)
1683101Sstever@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
1723101Sstever@eecs.umich.edu            return value
1733101Sstever@eecs.umich.edu        if isinstance(value, self.ptype):
1743101Sstever@eecs.umich.edu            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
1793101Sstever@eecs.umich.edu    def cxx_predecls(self, code):
1803101Sstever@eecs.umich.edu        code('#include <cstddef>')
1813101Sstever@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
1913101Sstever@eecs.umich.edu# single value.
1923101Sstever@eecs.umich.edu
1933101Sstever@eecs.umich.educlass VectorParamValue(list):
1943101Sstever@eecs.umich.edu    __metaclass__ = MetaParamValue
1953101Sstever@eecs.umich.edu    def __setattr__(self, attr, value):
1963101Sstever@eecs.umich.edu        raise AttributeError, \
1973101Sstever@eecs.umich.edu              "Not allowed to set %s on '%s'" % (attr, type(self).__name__)
1983101Sstever@eecs.umich.edu
1993101Sstever@eecs.umich.edu    def ini_str(self):
2003101Sstever@eecs.umich.edu        return ' '.join([v.ini_str() for v in self])
2013101Sstever@eecs.umich.edu
2023101Sstever@eecs.umich.edu    def getValue(self):
2033101Sstever@eecs.umich.edu        return [ v.getValue() for v in self ]
2043101Sstever@eecs.umich.edu
2053101Sstever@eecs.umich.edu    def unproxy(self, base):
2063101Sstever@eecs.umich.edu        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
2283101Sstever@eecs.umich.edu    def has_parent(self):
2293101Sstever@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:
2583101Sstever@eecs.umich.edu            # singleton: coerce to a single-element list
2593101Sstever@eecs.umich.edu            tmp_list = [ ParamDesc.convert(self, value) ]
2603101Sstever@eecs.umich.edu
2613101Sstever@eecs.umich.edu        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):
2733101Sstever@eecs.umich.edu        code('%module(package="m5.internal") ${{self.swig_module_name()}}')
2743101Sstever@eecs.umich.edu        code('%{')
2753101Sstever@eecs.umich.edu        self.ptype.cxx_predecls(code)
2763101Sstever@eecs.umich.edu        code('%}')
2773101Sstever@eecs.umich.edu        code()
2783101Sstever@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;
3043101Sstever@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):
3203101Sstever@eecs.umich.edu        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
3493101Sstever@eecs.umich.edu# over how Python expressions are converted to values (via the
3503101Sstever@eecs.umich.edu# __init__() constructor) and how these values are printed out (via
3513101Sstever@eecs.umich.edu# the __str__() conversion method).
3523101Sstever@eecs.umich.edu#
3533101Sstever@eecs.umich.edu#####################################################################
3543101Sstever@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.
3573101Sstever@eecs.umich.educlass String(ParamValue,str):
3583101Sstever@eecs.umich.edu    cxx_type = 'std::string'
3593101Sstever@eecs.umich.edu
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)
3803101Sstever@eecs.umich.edu
3813101Sstever@eecs.umich.edu    def __long__(self):
3823101Sstever@eecs.umich.edu        return long(self.value)
3833101Sstever@eecs.umich.edu
3843101Sstever@eecs.umich.edu    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)
3933101Sstever@eecs.umich.edu        newobj.value *= other
3943101Sstever@eecs.umich.edu        newobj._check()
3953101Sstever@eecs.umich.edu        return newobj
3963101Sstever@eecs.umich.edu
3973101Sstever@eecs.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
4043101Sstever@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()
4093101Sstever@eecs.umich.edu        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
4173101Sstever@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
4213101Sstever@eecs.umich.edu
4223101Sstever@eecs.umich.edu        if not (hasattr(cls, 'min') and hasattr(cls, 'max')):
4233101Sstever@eecs.umich.edu            if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')):
4243101Sstever@eecs.umich.edu                panic("CheckedInt subclass %s must define either\n" \
4253101Sstever@eecs.umich.edu                      "    'min' and 'max' or 'size' and 'unsigned'\n",
4263101Sstever@eecs.umich.edu                      name);
4273101Sstever@eecs.umich.edu            if cls.unsigned:
4283101Sstever@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
4783101Sstever@eecs.umich.educlass UInt32(CheckedInt):   cxx_type = 'uint32_t'; size = 32; unsigned = True
4793101Sstever@eecs.umich.educlass Int64(CheckedInt):    cxx_type =  'int64_t'; size = 64; unsigned = False
4803101Sstever@eecs.umich.educlass UInt64(CheckedInt):   cxx_type = 'uint64_t'; size = 64; unsigned = True
4813101Sstever@eecs.umich.edu
4823101Sstever@eecs.umich.educlass Counter(CheckedInt):  cxx_type = 'Counter';  size = 64; unsigned = True
4833101Sstever@eecs.umich.educlass Tick(CheckedInt):     cxx_type = 'Tick';     size = 64; unsigned = True
4843101Sstever@eecs.umich.educlass TcpPort(CheckedInt):  cxx_type = 'uint16_t'; size = 16; unsigned = True
4853101Sstever@eecs.umich.educlass UdpPort(CheckedInt):  cxx_type = 'uint16_t'; size = 16; unsigned = True
4863101Sstever@eecs.umich.edu
4873101Sstever@eecs.umich.educlass Percent(CheckedInt):  cxx_type = 'int'; min = 0; max = 100
4883101Sstever@eecs.umich.edu
4893101Sstever@eecs.umich.educlass Cycles(CheckedInt):
4903101Sstever@eecs.umich.edu    cxx_type = 'Cycles'
4913101Sstever@eecs.umich.edu    size = 64
4923101Sstever@eecs.umich.edu    unsigned = True
4933101Sstever@eecs.umich.edu
4943101Sstever@eecs.umich.edu    def getValue(self):
4953101Sstever@eecs.umich.edu        from m5.internal.core import Cycles
4963101Sstever@eecs.umich.edu        return Cycles(self.value)
4973101Sstever@eecs.umich.edu
4983101Sstever@eecs.umich.educlass 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__
5073101Sstever@eecs.umich.edu
5083101Sstever@eecs.umich.edu    def getValue(self):
5093101Sstever@eecs.umich.edu        return float(self.value)
5103101Sstever@eecs.umich.edu
5113101Sstever@eecs.umich.educlass MemorySize(CheckedInt):
5123101Sstever@eecs.umich.edu    cxx_type = 'uint64_t'
5133101Sstever@eecs.umich.edu    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):
5343101Sstever@eecs.umich.edu    cxx_type = 'Addr'
5353101Sstever@eecs.umich.edu    size = 64
5363101Sstever@eecs.umich.edu    unsigned = True
5373101Sstever@eecs.umich.edu    def __init__(self, value):
5383101Sstever@eecs.umich.edu        if isinstance(value, Addr):
5393101Sstever@eecs.umich.edu            self.value = value.value
5403101Sstever@eecs.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)
5453101Sstever@eecs.umich.edu        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:
5663101Sstever@eecs.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
5693101Sstever@eecs.umich.edu            else:
5703101Sstever@eecs.umich.edu                raise TypeError, "Either end or size must be specified"
5713101Sstever@eecs.umich.edu
5723101Sstever@eecs.umich.edu            # Now on to the optional bit
5733101Sstever@eecs.umich.edu            if 'intlvHighBit' in kwargs:
5743101Sstever@eecs.umich.edu                self.intlvHighBit = int(kwargs.pop('intlvHighBit'))
5753101Sstever@eecs.umich.edu            if 'intlvBits' in kwargs:
5763101Sstever@eecs.umich.edu                self.intlvBits = int(kwargs.pop('intlvBits'))
5773101Sstever@eecs.umich.edu            if 'intlvMatch' in kwargs:
5783101Sstever@eecs.umich.edu                self.intlvMatch = int(kwargs.pop('intlvMatch'))
5793101Sstever@eecs.umich.edu
5803101Sstever@eecs.umich.edu        if len(args) == 0:
5813101Sstever@eecs.umich.edu            self.start = Addr(kwargs.pop('start'))
5823101Sstever@eecs.umich.edu            handle_kwargs(self, kwargs)
5833101Sstever@eecs.umich.edu
5843101Sstever@eecs.umich.edu        elif len(args) == 1:
5853101Sstever@eecs.umich.edu            if kwargs:
5863101Sstever@eecs.umich.edu                self.start = Addr(args[0])
5873101Sstever@eecs.umich.edu                handle_kwargs(self, kwargs)
5883101Sstever@eecs.umich.edu            elif isinstance(args[0], (list, tuple)):
5893101Sstever@eecs.umich.edu                self.start = Addr(args[0][0])
5903101Sstever@eecs.umich.edu                self.end = Addr(args[0][1])
5913101Sstever@eecs.umich.edu            else:
5923101Sstever@eecs.umich.edu                self.start = Addr(0)
5933101Sstever@eecs.umich.edu                self.end = Addr(args[0]) - 1
5943101Sstever@eecs.umich.edu
5953101Sstever@eecs.umich.edu        elif len(args) == 2:
5963101Sstever@eecs.umich.edu            self.start = Addr(args[0])
5973101Sstever@eecs.umich.edu            self.end = Addr(args[1])
5983101Sstever@eecs.umich.edu        else:
5993101Sstever@eecs.umich.edu            raise TypeError, "Too many arguments specified"
6003101Sstever@eecs.umich.edu
6013101Sstever@eecs.umich.edu        if kwargs:
6023101Sstever@eecs.umich.edu            raise TypeError, "Too many keywords: %s" % kwargs.keys()
6033101Sstever@eecs.umich.edu
6043101Sstever@eecs.umich.edu    def __str__(self):
6053101Sstever@eecs.umich.edu        return '%s:%s' % (self.start, self.end)
6063101Sstever@eecs.umich.edu
6073101Sstever@eecs.umich.edu    def size(self):
6083101Sstever@eecs.umich.edu        # Divide the size by the size of the interleaving slice
6093101Sstever@eecs.umich.edu        return (long(self.end) - long(self.start) + 1) >> self.intlvBits
6103101Sstever@eecs.umich.edu
6113101Sstever@eecs.umich.edu    @classmethod
6123101Sstever@eecs.umich.edu    def cxx_predecls(cls, code):
6133101Sstever@eecs.umich.edu        Addr.cxx_predecls(code)
6143101Sstever@eecs.umich.edu        code('#include "base/addr_range.hh"')
6153101Sstever@eecs.umich.edu
6163101Sstever@eecs.umich.edu    @classmethod
6173101Sstever@eecs.umich.edu    def swig_predecls(cls, code):
6183101Sstever@eecs.umich.edu        Addr.swig_predecls(code)
6193101Sstever@eecs.umich.edu
6203101Sstever@eecs.umich.edu    def getValue(self):
6213101Sstever@eecs.umich.edu        # Go from the Python class to the wrapped C++ class generated
6223101Sstever@eecs.umich.edu        # by swig
6233101Sstever@eecs.umich.edu        from m5.internal.range import AddrRange
6243101Sstever@eecs.umich.edu
6253101Sstever@eecs.umich.edu        return AddrRange(long(self.start), long(self.end),
6263101Sstever@eecs.umich.edu                         int(self.intlvHighBit), int(self.intlvBits),
6273101Sstever@eecs.umich.edu                         int(self.intlvMatch))
6283101Sstever@eecs.umich.edu
6293101Sstever@eecs.umich.edu# Boolean parameter type.  Python doesn't let you subclass bool, since
6303101Sstever@eecs.umich.edu# it doesn't want to let you create multiple instances of True and
6313101Sstever@eecs.umich.edu# False.  Thus this is a little more complicated than String.
6323101Sstever@eecs.umich.educlass Bool(ParamValue):
6333101Sstever@eecs.umich.edu    cxx_type = 'bool'
6343101Sstever@eecs.umich.edu    def __init__(self, value):
6353101Sstever@eecs.umich.edu        try:
6363101Sstever@eecs.umich.edu            self.value = convert.toBool(value)
6373101Sstever@eecs.umich.edu        except TypeError:
6383101Sstever@eecs.umich.edu            self.value = bool(value)
6393101Sstever@eecs.umich.edu
6403101Sstever@eecs.umich.edu    def getValue(self):
6413101Sstever@eecs.umich.edu        return bool(self.value)
6423101Sstever@eecs.umich.edu
6433101Sstever@eecs.umich.edu    def __str__(self):
6443101Sstever@eecs.umich.edu        return str(self.value)
6453101Sstever@eecs.umich.edu
6463101Sstever@eecs.umich.edu    # implement truth value testing for Bool parameters so that these params
6473101Sstever@eecs.umich.edu    # evaluate correctly during the python configuration phase
6483101Sstever@eecs.umich.edu    def __nonzero__(self):
6493101Sstever@eecs.umich.edu        return bool(self.value)
6503101Sstever@eecs.umich.edu
6513101Sstever@eecs.umich.edu    def ini_str(self):
6523101Sstever@eecs.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))
6673101Sstever@eecs.umich.edu
6683101Sstever@eecs.umich.edu_NextEthernetAddr = "00:90:00:00:00:01"
6693101Sstever@eecs.umich.edudef NextEthernetAddr():
6703101Sstever@eecs.umich.edu    global _NextEthernetAddr
6713101Sstever@eecs.umich.edu
6723101Sstever@eecs.umich.edu    value = _NextEthernetAddr
6733101Sstever@eecs.umich.edu    _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1)
6743101Sstever@eecs.umich.edu    return value
6753101Sstever@eecs.umich.edu
6763101Sstever@eecs.umich.educlass 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:
6973101Sstever@eecs.umich.edu            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) <= 0xff:
7013101Sstever@eecs.umich.edu                raise TypeError, 'invalid ethernet address %s' % value
7023101Sstever@eecs.umich.edu
7033101Sstever@eecs.umich.edu        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())
7083101Sstever@eecs.umich.edu        return self
7093101Sstever@eecs.umich.edu
7103101Sstever@eecs.umich.edu    def getValue(self):
7113101Sstever@eecs.umich.edu        from m5.internal.params import EthAddr
7123101Sstever@eecs.umich.edu        return EthAddr(self.value)
7133101Sstever@eecs.umich.edu
7143101Sstever@eecs.umich.edu    def ini_str(self):
7153101Sstever@eecs.umich.edu        return self.value
7163101Sstever@eecs.umich.edu
7173101Sstever@eecs.umich.edu# When initializing an IpAddress, pass in an existing IpAddress, a string of
7183101Sstever@eecs.umich.edu# the form "a.b.c.d", or an integer representing an IP.
7193101Sstever@eecs.umich.educlass IpAddress(ParamValue):
7203101Sstever@eecs.umich.edu    cxx_type = 'Net::IpAddress'
7213101Sstever@eecs.umich.edu
7223101Sstever@eecs.umich.edu    @classmethod
7233101Sstever@eecs.umich.edu    def cxx_predecls(cls, code):
7243101Sstever@eecs.umich.edu        code('#include "base/inet.hh"')
7253101Sstever@eecs.umich.edu
7263101Sstever@eecs.umich.edu    @classmethod
7273101Sstever@eecs.umich.edu    def swig_predecls(cls, code):
7283101Sstever@eecs.umich.edu        code('%include "python/swig/inet.i"')
7293101Sstever@eecs.umich.edu
7303101Sstever@eecs.umich.edu    def __init__(self, value):
7313101Sstever@eecs.umich.edu        if isinstance(value, IpAddress):
7323101Sstever@eecs.umich.edu            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):
7453101Sstever@eecs.umich.edu        if isinstance(other, IpAddress):
7463101Sstever@eecs.umich.edu            return self.ip == other.ip
7473101Sstever@eecs.umich.edu        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
7543101Sstever@eecs.umich.edu
7553101Sstever@eecs.umich.edu    def __ne__(self, other):
7563101Sstever@eecs.umich.edu        return not (self == other)
7573101Sstever@eecs.umich.edu
7583101Sstever@eecs.umich.edu    def verifyIp(self):
7593101Sstever@eecs.umich.edu        if self.ip < 0 or self.ip >= (1 << 32):
7603101Sstever@eecs.umich.edu            raise TypeError, "invalid ip address %#08x" % self.ip
7613101Sstever@eecs.umich.edu
7623101Sstever@eecs.umich.edu    def getValue(self):
7633101Sstever@eecs.umich.edu        from m5.internal.params import IpAddress
7643101Sstever@eecs.umich.edu        return IpAddress(self.ip)
7653101Sstever@eecs.umich.edu
7663101Sstever@eecs.umich.edu# When initializing an IpNetmask, pass in an existing IpNetmask, a string of
7673101Sstever@eecs.umich.edu# the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as
7683101Sstever@eecs.umich.edu# positional or keyword arguments.
7693101Sstever@eecs.umich.educlass IpNetmask(IpAddress):
7703101Sstever@eecs.umich.edu    cxx_type = 'Net::IpNetmask'
7713101Sstever@eecs.umich.edu
7723101Sstever@eecs.umich.edu    @classmethod
7733101Sstever@eecs.umich.edu    def cxx_predecls(cls, code):
7743101Sstever@eecs.umich.edu        code('#include "base/inet.hh"')
7753101Sstever@eecs.umich.edu
7763101Sstever@eecs.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:
7853101Sstever@eecs.umich.edu                setattr(self, key, elseVal)
7863101Sstever@eecs.umich.edu            else:
7873101Sstever@eecs.umich.edu                raise TypeError, "No value set for %s" % key
7883101Sstever@eecs.umich.edu
7893101Sstever@eecs.umich.edu        if len(args) == 0:
7903101Sstever@eecs.umich.edu            handle_kwarg(self, kwargs, 'ip')
7913101Sstever@eecs.umich.edu            handle_kwarg(self, kwargs, 'netmask')
7923101Sstever@eecs.umich.edu
7933101Sstever@eecs.umich.edu        elif len(args) == 1:
7943101Sstever@eecs.umich.edu            if kwargs:
7953101Sstever@eecs.umich.edu                if not 'ip' in kwargs and not 'netmask' in kwargs:
7963101Sstever@eecs.umich.edu                    raise TypeError, "Invalid arguments"
7973101Sstever@eecs.umich.edu                handle_kwarg(self, kwargs, 'ip', args[0])
7983101Sstever@eecs.umich.edu                handle_kwarg(self, kwargs, 'netmask', args[0])
7993101Sstever@eecs.umich.edu            elif isinstance(args[0], IpNetmask):
8003101Sstever@eecs.umich.edu                self.ip = args[0].ip
8013101Sstever@eecs.umich.edu                self.netmask = args[0].netmask
8023101Sstever@eecs.umich.edu            else:
8033101Sstever@eecs.umich.edu                (self.ip, self.netmask) = convert.toIpNetmask(args[0])
8043101Sstever@eecs.umich.edu
8053101Sstever@eecs.umich.edu        elif len(args) == 2:
8063101Sstever@eecs.umich.edu            self.ip = args[0]
8073101Sstever@eecs.umich.edu            self.netmask = args[1]
8083101Sstever@eecs.umich.edu        else:
8093101Sstever@eecs.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)
8183101Sstever@eecs.umich.edu
8193101Sstever@eecs.umich.edu    def __eq__(self, other):
8203101Sstever@eecs.umich.edu        if isinstance(other, IpNetmask):
8213101Sstever@eecs.umich.edu            return self.ip == other.ip and self.netmask == other.netmask
8223101Sstever@eecs.umich.edu        elif isinstance(other, str):
8233101Sstever@eecs.umich.edu            try:
8243101Sstever@eecs.umich.edu                return (self.ip, self.netmask) == convert.toIpNetmask(other)
8253101Sstever@eecs.umich.edu            except:
8263101Sstever@eecs.umich.edu                return False
8273101Sstever@eecs.umich.edu        else:
8283101Sstever@eecs.umich.edu            return False
8293101Sstever@eecs.umich.edu
8303101Sstever@eecs.umich.edu    def verify(self):
8313101Sstever@eecs.umich.edu        self.verifyIp()
832        if self.netmask < 0 or self.netmask > 32:
833            raise TypeError, "invalid netmask %d" % netmask
834
835    def getValue(self):
836        from m5.internal.params import IpNetmask
837        return IpNetmask(self.ip, self.netmask)
838
839# When initializing an IpWithPort, pass in an existing IpWithPort, a string of
840# the form "a.b.c.d:p", or an ip and port as positional or keyword arguments.
841class IpWithPort(IpAddress):
842    cxx_type = 'Net::IpWithPort'
843
844    @classmethod
845    def cxx_predecls(cls, code):
846        code('#include "base/inet.hh"')
847
848    @classmethod
849    def swig_predecls(cls, code):
850        code('%include "python/swig/inet.i"')
851
852    def __init__(self, *args, **kwargs):
853        def handle_kwarg(self, kwargs, key, elseVal = None):
854            if key in kwargs:
855                setattr(self, key, kwargs.pop(key))
856            elif elseVal:
857                setattr(self, key, elseVal)
858            else:
859                raise TypeError, "No value set for %s" % key
860
861        if len(args) == 0:
862            handle_kwarg(self, kwargs, 'ip')
863            handle_kwarg(self, kwargs, 'port')
864
865        elif len(args) == 1:
866            if kwargs:
867                if not 'ip' in kwargs and not 'port' in kwargs:
868                    raise TypeError, "Invalid arguments"
869                handle_kwarg(self, kwargs, 'ip', args[0])
870                handle_kwarg(self, kwargs, 'port', args[0])
871            elif isinstance(args[0], IpWithPort):
872                self.ip = args[0].ip
873                self.port = args[0].port
874            else:
875                (self.ip, self.port) = convert.toIpWithPort(args[0])
876
877        elif len(args) == 2:
878            self.ip = args[0]
879            self.port = args[1]
880        else:
881            raise TypeError, "Too many arguments specified"
882
883        if kwargs:
884            raise TypeError, "Too many keywords: %s" % kwargs.keys()
885
886        self.verify()
887
888    def __str__(self):
889        return "%s:%d" % (super(IpWithPort, self).__str__(), self.port)
890
891    def __eq__(self, other):
892        if isinstance(other, IpWithPort):
893            return self.ip == other.ip and self.port == other.port
894        elif isinstance(other, str):
895            try:
896                return (self.ip, self.port) == convert.toIpWithPort(other)
897            except:
898                return False
899        else:
900            return False
901
902    def verify(self):
903        self.verifyIp()
904        if self.port < 0 or self.port > 0xffff:
905            raise TypeError, "invalid port %d" % self.port
906
907    def getValue(self):
908        from m5.internal.params import IpWithPort
909        return IpWithPort(self.ip, self.port)
910
911time_formats = [ "%a %b %d %H:%M:%S %Z %Y",
912                 "%a %b %d %H:%M:%S %Z %Y",
913                 "%Y/%m/%d %H:%M:%S",
914                 "%Y/%m/%d %H:%M",
915                 "%Y/%m/%d",
916                 "%m/%d/%Y %H:%M:%S",
917                 "%m/%d/%Y %H:%M",
918                 "%m/%d/%Y",
919                 "%m/%d/%y %H:%M:%S",
920                 "%m/%d/%y %H:%M",
921                 "%m/%d/%y"]
922
923
924def parse_time(value):
925    from time import gmtime, strptime, struct_time, time
926    from datetime import datetime, date
927
928    if isinstance(value, struct_time):
929        return value
930
931    if isinstance(value, (int, long)):
932        return gmtime(value)
933
934    if isinstance(value, (datetime, date)):
935        return value.timetuple()
936
937    if isinstance(value, str):
938        if value in ('Now', 'Today'):
939            return time.gmtime(time.time())
940
941        for format in time_formats:
942            try:
943                return strptime(value, format)
944            except ValueError:
945                pass
946
947    raise ValueError, "Could not parse '%s' as a time" % value
948
949class Time(ParamValue):
950    cxx_type = 'tm'
951
952    @classmethod
953    def cxx_predecls(cls, code):
954        code('#include <time.h>')
955
956    @classmethod
957    def swig_predecls(cls, code):
958        code('%include "python/swig/time.i"')
959
960    def __init__(self, value):
961        self.value = parse_time(value)
962
963    def getValue(self):
964        from m5.internal.params import tm
965
966        c_time = tm()
967        py_time = self.value
968
969        # UNIX is years since 1900
970        c_time.tm_year = py_time.tm_year - 1900;
971
972        # Python starts at 1, UNIX starts at 0
973        c_time.tm_mon =  py_time.tm_mon - 1;
974        c_time.tm_mday = py_time.tm_mday;
975        c_time.tm_hour = py_time.tm_hour;
976        c_time.tm_min = py_time.tm_min;
977        c_time.tm_sec = py_time.tm_sec;
978
979        # Python has 0 as Monday, UNIX is 0 as sunday
980        c_time.tm_wday = py_time.tm_wday + 1
981        if c_time.tm_wday > 6:
982            c_time.tm_wday -= 7;
983
984        # Python starts at 1, Unix starts at 0
985        c_time.tm_yday = py_time.tm_yday - 1;
986
987        return c_time
988
989    def __str__(self):
990        return time.asctime(self.value)
991
992    def ini_str(self):
993        return str(self)
994
995    def get_config_as_dict(self):
996        return str(self)
997
998# Enumerated types are a little more complex.  The user specifies the
999# type as Enum(foo) where foo is either a list or dictionary of
1000# alternatives (typically strings, but not necessarily so).  (In the
1001# long run, the integer value of the parameter will be the list index
1002# or the corresponding dictionary value.  For now, since we only check
1003# that the alternative is valid and then spit it into a .ini file,
1004# there's not much point in using the dictionary.)
1005
1006# What Enum() must do is generate a new type encapsulating the
1007# provided list/dictionary so that specific values of the parameter
1008# can be instances of that type.  We define two hidden internal
1009# classes (_ListEnum and _DictEnum) to serve as base classes, then
1010# derive the new type from the appropriate base class on the fly.
1011
1012allEnums = {}
1013# Metaclass for Enum types
1014class MetaEnum(MetaParamValue):
1015    def __new__(mcls, name, bases, dict):
1016        assert name not in allEnums
1017
1018        cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict)
1019        allEnums[name] = cls
1020        return cls
1021
1022    def __init__(cls, name, bases, init_dict):
1023        if init_dict.has_key('map'):
1024            if not isinstance(cls.map, dict):
1025                raise TypeError, "Enum-derived class attribute 'map' " \
1026                      "must be of type dict"
1027            # build list of value strings from map
1028            cls.vals = cls.map.keys()
1029            cls.vals.sort()
1030        elif init_dict.has_key('vals'):
1031            if not isinstance(cls.vals, list):
1032                raise TypeError, "Enum-derived class attribute 'vals' " \
1033                      "must be of type list"
1034            # build string->value map from vals sequence
1035            cls.map = {}
1036            for idx,val in enumerate(cls.vals):
1037                cls.map[val] = idx
1038        else:
1039            raise TypeError, "Enum-derived class must define "\
1040                  "attribute 'map' or 'vals'"
1041
1042        cls.cxx_type = 'Enums::%s' % name
1043
1044        super(MetaEnum, cls).__init__(name, bases, init_dict)
1045
1046    # Generate C++ class declaration for this enum type.
1047    # Note that we wrap the enum in a class/struct to act as a namespace,
1048    # so that the enum strings can be brief w/o worrying about collisions.
1049    def cxx_decl(cls, code):
1050        name = cls.__name__
1051        code('''\
1052#ifndef __ENUM__${name}__
1053#define __ENUM__${name}__
1054
1055namespace Enums {
1056    enum $name {
1057''')
1058        code.indent(2)
1059        for val in cls.vals:
1060            code('$val = ${{cls.map[val]}},')
1061        code('Num_$name = ${{len(cls.vals)}}')
1062        code.dedent(2)
1063        code('''\
1064    };
1065extern const char *${name}Strings[Num_${name}];
1066}
1067
1068#endif // __ENUM__${name}__
1069''')
1070
1071    def cxx_def(cls, code):
1072        name = cls.__name__
1073        code('''\
1074#include "enums/$name.hh"
1075namespace Enums {
1076    const char *${name}Strings[Num_${name}] =
1077    {
1078''')
1079        code.indent(2)
1080        for val in cls.vals:
1081            code('"$val",')
1082        code.dedent(2)
1083        code('''
1084    };
1085} // namespace Enums
1086''')
1087
1088    def swig_decl(cls, code):
1089        name = cls.__name__
1090        code('''\
1091%module(package="m5.internal") enum_$name
1092
1093%{
1094#include "enums/$name.hh"
1095%}
1096
1097%include "enums/$name.hh"
1098''')
1099
1100
1101# Base class for enum types.
1102class Enum(ParamValue):
1103    __metaclass__ = MetaEnum
1104    vals = []
1105
1106    def __init__(self, value):
1107        if value not in self.map:
1108            raise TypeError, "Enum param got bad value '%s' (not in %s)" \
1109                  % (value, self.vals)
1110        self.value = value
1111
1112    @classmethod
1113    def cxx_predecls(cls, code):
1114        code('#include "enums/$0.hh"', cls.__name__)
1115
1116    @classmethod
1117    def swig_predecls(cls, code):
1118        code('%import "python/m5/internal/enum_$0.i"', cls.__name__)
1119
1120    def getValue(self):
1121        return int(self.map[self.value])
1122
1123    def __str__(self):
1124        return self.value
1125
1126# how big does a rounding error need to be before we warn about it?
1127frequency_tolerance = 0.001  # 0.1%
1128
1129class TickParamValue(NumericParamValue):
1130    cxx_type = 'Tick'
1131
1132    @classmethod
1133    def cxx_predecls(cls, code):
1134        code('#include "base/types.hh"')
1135
1136    @classmethod
1137    def swig_predecls(cls, code):
1138        code('%import "stdint.i"')
1139        code('%import "base/types.hh"')
1140
1141    def getValue(self):
1142        return long(self.value)
1143
1144class Latency(TickParamValue):
1145    def __init__(self, value):
1146        if isinstance(value, (Latency, Clock)):
1147            self.ticks = value.ticks
1148            self.value = value.value
1149        elif isinstance(value, Frequency):
1150            self.ticks = value.ticks
1151            self.value = 1.0 / value.value
1152        elif value.endswith('t'):
1153            self.ticks = True
1154            self.value = int(value[:-1])
1155        else:
1156            self.ticks = False
1157            self.value = convert.toLatency(value)
1158
1159    def __getattr__(self, attr):
1160        if attr in ('latency', 'period'):
1161            return self
1162        if attr == 'frequency':
1163            return Frequency(self)
1164        raise AttributeError, "Latency object has no attribute '%s'" % attr
1165
1166    def getValue(self):
1167        if self.ticks or self.value == 0:
1168            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 __mul__(self, other):
1248        # Always treat the clock as a period when scaling
1249        newobj = self.__class__(self)
1250        newobj.value *= other
1251        return newobj
1252
1253    __rmul__ = __mul__
1254
1255    def getValue(self):
1256        return self.period.getValue()
1257
1258    def ini_str(self):
1259        return self.period.ini_str()
1260
1261class NetworkBandwidth(float,ParamValue):
1262    cxx_type = 'float'
1263    def __new__(cls, value):
1264        # convert to bits per second
1265        val = convert.toNetworkBandwidth(value)
1266        return super(cls, NetworkBandwidth).__new__(cls, val)
1267
1268    def __str__(self):
1269        return str(self.val)
1270
1271    def getValue(self):
1272        # convert to seconds per byte
1273        value = 8.0 / float(self)
1274        # convert to ticks per byte
1275        value = ticks.fromSeconds(value)
1276        return float(value)
1277
1278    def ini_str(self):
1279        return '%f' % self.getValue()
1280
1281class MemoryBandwidth(float,ParamValue):
1282    cxx_type = 'float'
1283    def __new__(cls, value):
1284        # convert to bytes per second
1285        val = convert.toMemoryBandwidth(value)
1286        return super(cls, MemoryBandwidth).__new__(cls, val)
1287
1288    def __str__(self):
1289        return str(self.val)
1290
1291    def getValue(self):
1292        # convert to seconds per byte
1293        value = float(self)
1294        if value:
1295            value = 1.0 / float(self)
1296        # convert to ticks per byte
1297        value = ticks.fromSeconds(value)
1298        return float(value)
1299
1300    def ini_str(self):
1301        return '%f' % self.getValue()
1302
1303#
1304# "Constants"... handy aliases for various values.
1305#
1306
1307# Special class for NULL pointers.  Note the special check in
1308# make_param_value() above that lets these be assigned where a
1309# SimObject is required.
1310# only one copy of a particular node
1311class NullSimObject(object):
1312    __metaclass__ = Singleton
1313
1314    def __call__(cls):
1315        return cls
1316
1317    def _instantiate(self, parent = None, path = ''):
1318        pass
1319
1320    def ini_str(self):
1321        return 'Null'
1322
1323    def unproxy(self, base):
1324        return self
1325
1326    def set_path(self, parent, name):
1327        pass
1328
1329    def __str__(self):
1330        return 'Null'
1331
1332    def getValue(self):
1333        return None
1334
1335# The only instance you'll ever need...
1336NULL = NullSimObject()
1337
1338def isNullPointer(value):
1339    return isinstance(value, NullSimObject)
1340
1341# Some memory range specifications use this as a default upper bound.
1342MaxAddr = Addr.max
1343MaxTick = Tick.max
1344AllMemory = AddrRange(0, MaxAddr)
1345
1346
1347#####################################################################
1348#
1349# Port objects
1350#
1351# Ports are used to interconnect objects in the memory system.
1352#
1353#####################################################################
1354
1355# Port reference: encapsulates a reference to a particular port on a
1356# particular SimObject.
1357class PortRef(object):
1358    def __init__(self, simobj, name, role):
1359        assert(isSimObject(simobj) or isSimObjectClass(simobj))
1360        self.simobj = simobj
1361        self.name = name
1362        self.role = role
1363        self.peer = None   # not associated with another port yet
1364        self.ccConnected = False # C++ port connection done?
1365        self.index = -1  # always -1 for non-vector ports
1366
1367    def __str__(self):
1368        return '%s.%s' % (self.simobj, self.name)
1369
1370    def __len__(self):
1371        # Return the number of connected ports, i.e. 0 is we have no
1372        # peer and 1 if we do.
1373        return int(self.peer != None)
1374
1375    # for config.ini, print peer's name (not ours)
1376    def ini_str(self):
1377        return str(self.peer)
1378
1379    # for config.json
1380    def get_config_as_dict(self):
1381        return {'role' : self.role, 'peer' : str(self.peer)}
1382
1383    def __getattr__(self, attr):
1384        if attr == 'peerObj':
1385            # shorthand for proxies
1386            return self.peer.simobj
1387        raise AttributeError, "'%s' object has no attribute '%s'" % \
1388              (self.__class__.__name__, attr)
1389
1390    # Full connection is symmetric (both ways).  Called via
1391    # SimObject.__setattr__ as a result of a port assignment, e.g.,
1392    # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
1393    # e.g., "obj1.portA[3] = obj2.portB".
1394    def connect(self, other):
1395        if isinstance(other, VectorPortRef):
1396            # reference to plain VectorPort is implicit append
1397            other = other._get_next()
1398        if self.peer and not proxy.isproxy(self.peer):
1399            fatal("Port %s is already connected to %s, cannot connect %s\n",
1400                  self, self.peer, other);
1401        self.peer = other
1402        if proxy.isproxy(other):
1403            other.set_param_desc(PortParamDesc())
1404        elif isinstance(other, PortRef):
1405            if other.peer is not self:
1406                other.connect(self)
1407        else:
1408            raise TypeError, \
1409                  "assigning non-port reference '%s' to port '%s'" \
1410                  % (other, self)
1411
1412    def clone(self, simobj, memo):
1413        if memo.has_key(self):
1414            return memo[self]
1415        newRef = copy.copy(self)
1416        memo[self] = newRef
1417        newRef.simobj = simobj
1418        assert(isSimObject(newRef.simobj))
1419        if self.peer and not proxy.isproxy(self.peer):
1420            peerObj = self.peer.simobj(_memo=memo)
1421            newRef.peer = self.peer.clone(peerObj, memo)
1422            assert(not isinstance(newRef.peer, VectorPortRef))
1423        return newRef
1424
1425    def unproxy(self, simobj):
1426        assert(simobj is self.simobj)
1427        if proxy.isproxy(self.peer):
1428            try:
1429                realPeer = self.peer.unproxy(self.simobj)
1430            except:
1431                print "Error in unproxying port '%s' of %s" % \
1432                      (self.name, self.simobj.path())
1433                raise
1434            self.connect(realPeer)
1435
1436    # Call C++ to create corresponding port connection between C++ objects
1437    def ccConnect(self):
1438        from m5.internal.pyobject import connectPorts
1439
1440        if self.role == 'SLAVE':
1441            # do nothing and let the master take care of it
1442            return
1443
1444        if self.ccConnected: # already done this
1445            return
1446        peer = self.peer
1447        if not self.peer: # nothing to connect to
1448            return
1449
1450        # check that we connect a master to a slave
1451        if self.role == peer.role:
1452            raise TypeError, \
1453                "cannot connect '%s' and '%s' due to identical role '%s'" \
1454                % (peer, self, self.role)
1455
1456        try:
1457            # self is always the master and peer the slave
1458            connectPorts(self.simobj.getCCObject(), self.name, self.index,
1459                         peer.simobj.getCCObject(), peer.name, peer.index)
1460        except:
1461            print "Error connecting port %s.%s to %s.%s" % \
1462                  (self.simobj.path(), self.name,
1463                   peer.simobj.path(), peer.name)
1464            raise
1465        self.ccConnected = True
1466        peer.ccConnected = True
1467
1468# A reference to an individual element of a VectorPort... much like a
1469# PortRef, but has an index.
1470class VectorPortElementRef(PortRef):
1471    def __init__(self, simobj, name, role, index):
1472        PortRef.__init__(self, simobj, name, role)
1473        self.index = index
1474
1475    def __str__(self):
1476        return '%s.%s[%d]' % (self.simobj, self.name, self.index)
1477
1478# A reference to a complete vector-valued port (not just a single element).
1479# Can be indexed to retrieve individual VectorPortElementRef instances.
1480class VectorPortRef(object):
1481    def __init__(self, simobj, name, role):
1482        assert(isSimObject(simobj) or isSimObjectClass(simobj))
1483        self.simobj = simobj
1484        self.name = name
1485        self.role = role
1486        self.elements = []
1487
1488    def __str__(self):
1489        return '%s.%s[:]' % (self.simobj, self.name)
1490
1491    def __len__(self):
1492        # Return the number of connected peers, corresponding the the
1493        # length of the elements.
1494        return len(self.elements)
1495
1496    # for config.ini, print peer's name (not ours)
1497    def ini_str(self):
1498        return ' '.join([el.ini_str() for el in self.elements])
1499
1500    # for config.json
1501    def get_config_as_dict(self):
1502        return {'role' : self.role,
1503                'peer' : [el.ini_str() for el in self.elements]}
1504
1505    def __getitem__(self, key):
1506        if not isinstance(key, int):
1507            raise TypeError, "VectorPort index must be integer"
1508        if key >= len(self.elements):
1509            # need to extend list
1510            ext = [VectorPortElementRef(self.simobj, self.name, self.role, i)
1511                   for i in range(len(self.elements), key+1)]
1512            self.elements.extend(ext)
1513        return self.elements[key]
1514
1515    def _get_next(self):
1516        return self[len(self.elements)]
1517
1518    def __setitem__(self, key, value):
1519        if not isinstance(key, int):
1520            raise TypeError, "VectorPort index must be integer"
1521        self[key].connect(value)
1522
1523    def connect(self, other):
1524        if isinstance(other, (list, tuple)):
1525            # Assign list of port refs to vector port.
1526            # For now, append them... not sure if that's the right semantics
1527            # or if it should replace the current vector.
1528            for ref in other:
1529                self._get_next().connect(ref)
1530        else:
1531            # scalar assignment to plain VectorPort is implicit append
1532            self._get_next().connect(other)
1533
1534    def clone(self, simobj, memo):
1535        if memo.has_key(self):
1536            return memo[self]
1537        newRef = copy.copy(self)
1538        memo[self] = newRef
1539        newRef.simobj = simobj
1540        assert(isSimObject(newRef.simobj))
1541        newRef.elements = [el.clone(simobj, memo) for el in self.elements]
1542        return newRef
1543
1544    def unproxy(self, simobj):
1545        [el.unproxy(simobj) for el in self.elements]
1546
1547    def ccConnect(self):
1548        [el.ccConnect() for el in self.elements]
1549
1550# Port description object.  Like a ParamDesc object, this represents a
1551# logical port in the SimObject class, not a particular port on a
1552# SimObject instance.  The latter are represented by PortRef objects.
1553class Port(object):
1554    # Generate a PortRef for this port on the given SimObject with the
1555    # given name
1556    def makeRef(self, simobj):
1557        return PortRef(simobj, self.name, self.role)
1558
1559    # Connect an instance of this port (on the given SimObject with
1560    # the given name) with the port described by the supplied PortRef
1561    def connect(self, simobj, ref):
1562        self.makeRef(simobj).connect(ref)
1563
1564    # No need for any pre-declarations at the moment as we merely rely
1565    # on an unsigned int.
1566    def cxx_predecls(self, code):
1567        pass
1568
1569    # Declare an unsigned int with the same name as the port, that
1570    # will eventually hold the number of connected ports (and thus the
1571    # number of elements for a VectorPort).
1572    def cxx_decl(self, code):
1573        code('unsigned int port_${{self.name}}_connection_count;')
1574
1575class MasterPort(Port):
1576    # MasterPort("description")
1577    def __init__(self, *args):
1578        if len(args) == 1:
1579            self.desc = args[0]
1580            self.role = 'MASTER'
1581        else:
1582            raise TypeError, 'wrong number of arguments'
1583
1584class SlavePort(Port):
1585    # SlavePort("description")
1586    def __init__(self, *args):
1587        if len(args) == 1:
1588            self.desc = args[0]
1589            self.role = 'SLAVE'
1590        else:
1591            raise TypeError, 'wrong number of arguments'
1592
1593# VectorPort description object.  Like Port, but represents a vector
1594# of connections (e.g., as on a Bus).
1595class VectorPort(Port):
1596    def __init__(self, *args):
1597        self.isVec = True
1598
1599    def makeRef(self, simobj):
1600        return VectorPortRef(simobj, self.name, self.role)
1601
1602class VectorMasterPort(VectorPort):
1603    # VectorMasterPort("description")
1604    def __init__(self, *args):
1605        if len(args) == 1:
1606            self.desc = args[0]
1607            self.role = 'MASTER'
1608            VectorPort.__init__(self, *args)
1609        else:
1610            raise TypeError, 'wrong number of arguments'
1611
1612class VectorSlavePort(VectorPort):
1613    # VectorSlavePort("description")
1614    def __init__(self, *args):
1615        if len(args) == 1:
1616            self.desc = args[0]
1617            self.role = 'SLAVE'
1618            VectorPort.__init__(self, *args)
1619        else:
1620            raise TypeError, 'wrong number of arguments'
1621
1622# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
1623# proxy objects (via set_param_desc()) so that proxy error messages
1624# make sense.
1625class PortParamDesc(object):
1626    __metaclass__ = Singleton
1627
1628    ptype_str = 'Port'
1629    ptype = Port
1630
1631baseEnums = allEnums.copy()
1632baseParams = allParams.copy()
1633
1634def clear():
1635    global allEnums, allParams
1636
1637    allEnums = baseEnums.copy()
1638    allParams = baseParams.copy()
1639
1640__all__ = ['Param', 'VectorParam',
1641           'Enum', 'Bool', 'String', 'Float',
1642           'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
1643           'Int32', 'UInt32', 'Int64', 'UInt64',
1644           'Counter', 'Addr', 'Tick', 'Percent',
1645           'TcpPort', 'UdpPort', 'EthernetAddr',
1646           'IpAddress', 'IpNetmask', 'IpWithPort',
1647           'MemorySize', 'MemorySize32',
1648           'Latency', 'Frequency', 'Clock',
1649           'NetworkBandwidth', 'MemoryBandwidth',
1650           'AddrRange',
1651           'MaxAddr', 'MaxTick', 'AllMemory',
1652           'Time',
1653           'NextEthernetAddr', 'NULL',
1654           'MasterPort', 'SlavePort',
1655           'VectorMasterPort', 'VectorSlavePort']
1656
1657import SimObject
1658