params.py revision 12200
13101Sstever@eecs.umich.edu# Copyright (c) 2012-2014, 2017 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#
493102Sstever@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    cmd_line_settable = False
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
1043102Sstever@eecs.umich.edu
1053101Sstever@eecs.umich.edu    @classmethod
1063102Sstever@eecs.umich.edu    def pybind_predecls(cls, code):
1073101Sstever@eecs.umich.edu        cls.cxx_predecls(code)
1083101Sstever@eecs.umich.edu
1093101Sstever@eecs.umich.edu    # default for printing to .ini file is regular string conversion.
1103102Sstever@eecs.umich.edu    # will be overridden in some cases
1113102Sstever@eecs.umich.edu    def ini_str(self):
1123101Sstever@eecs.umich.edu        return str(self)
1133101Sstever@eecs.umich.edu
1143101Sstever@eecs.umich.edu    # default for printing to .json file is regular string conversion.
1153101Sstever@eecs.umich.edu    # will be overridden in some cases, mostly to use native Python
1163101Sstever@eecs.umich.edu    # types where there are similar JSON types
1173101Sstever@eecs.umich.edu    def config_value(self):
1183101Sstever@eecs.umich.edu        return str(self)
1193101Sstever@eecs.umich.edu
1203101Sstever@eecs.umich.edu    # Prerequisites for .ini parsing with cxx_ini_parse
1213101Sstever@eecs.umich.edu    @classmethod
1223101Sstever@eecs.umich.edu    def cxx_ini_predecls(cls, code):
1233101Sstever@eecs.umich.edu        pass
1243101Sstever@eecs.umich.edu
1253102Sstever@eecs.umich.edu    # parse a .ini file entry for this param from string expression
1263101Sstever@eecs.umich.edu    # src into lvalue dest (of the param's C++ type)
1273101Sstever@eecs.umich.edu    @classmethod
1283101Sstever@eecs.umich.edu    def cxx_ini_parse(cls, code, src, dest, ret):
1293101Sstever@eecs.umich.edu        code('// Unhandled param type: %s' % cls.__name__)
1303101Sstever@eecs.umich.edu        code('%s false;' % ret)
1313101Sstever@eecs.umich.edu
1323101Sstever@eecs.umich.edu    # allows us to blithely call unproxy() on things without checking
1333101Sstever@eecs.umich.edu    # if they're really proxies or not
1343101Sstever@eecs.umich.edu    def unproxy(self, base):
1353101Sstever@eecs.umich.edu        return self
1363101Sstever@eecs.umich.edu
1373101Sstever@eecs.umich.edu    # Produce a human readable version of the stored value
1383101Sstever@eecs.umich.edu    def pretty_print(self, value):
1393101Sstever@eecs.umich.edu        return str(value)
1403101Sstever@eecs.umich.edu
1413101Sstever@eecs.umich.edu# Regular parameter description.
1423101Sstever@eecs.umich.educlass ParamDesc(object):
1433101Sstever@eecs.umich.edu    def __init__(self, ptype_str, ptype, *args, **kwargs):
1443101Sstever@eecs.umich.edu        self.ptype_str = ptype_str
1453101Sstever@eecs.umich.edu        # remember ptype only if it is provided
1463101Sstever@eecs.umich.edu        if ptype != None:
1473101Sstever@eecs.umich.edu            self.ptype = ptype
1483101Sstever@eecs.umich.edu
1493101Sstever@eecs.umich.edu        if args:
1503101Sstever@eecs.umich.edu            if len(args) == 1:
1513101Sstever@eecs.umich.edu                self.desc = args[0]
1523101Sstever@eecs.umich.edu            elif len(args) == 2:
1533101Sstever@eecs.umich.edu                self.default = args[0]
1543101Sstever@eecs.umich.edu                self.desc = args[1]
1553101Sstever@eecs.umich.edu            else:
1563101Sstever@eecs.umich.edu                raise TypeError, 'too many arguments'
1573101Sstever@eecs.umich.edu
1583101Sstever@eecs.umich.edu        if kwargs.has_key('desc'):
1593101Sstever@eecs.umich.edu            assert(not hasattr(self, 'desc'))
1603101Sstever@eecs.umich.edu            self.desc = kwargs['desc']
1613101Sstever@eecs.umich.edu            del kwargs['desc']
1623101Sstever@eecs.umich.edu
1633101Sstever@eecs.umich.edu        if kwargs.has_key('default'):
1643101Sstever@eecs.umich.edu            assert(not hasattr(self, 'default'))
1653101Sstever@eecs.umich.edu            self.default = kwargs['default']
1663101Sstever@eecs.umich.edu            del kwargs['default']
1673101Sstever@eecs.umich.edu
1683101Sstever@eecs.umich.edu        if kwargs:
1693101Sstever@eecs.umich.edu            raise TypeError, 'extra unknown kwargs %s' % kwargs
1703101Sstever@eecs.umich.edu
1713101Sstever@eecs.umich.edu        if not hasattr(self, 'desc'):
1723101Sstever@eecs.umich.edu            raise TypeError, 'desc attribute missing'
1733101Sstever@eecs.umich.edu
1743101Sstever@eecs.umich.edu    def __getattr__(self, attr):
1753101Sstever@eecs.umich.edu        if attr == 'ptype':
1763101Sstever@eecs.umich.edu            ptype = SimObject.allClasses[self.ptype_str]
1773101Sstever@eecs.umich.edu            assert isSimObjectClass(ptype)
1783101Sstever@eecs.umich.edu            self.ptype = ptype
1793101Sstever@eecs.umich.edu            return ptype
1803101Sstever@eecs.umich.edu
1813101Sstever@eecs.umich.edu        raise AttributeError, "'%s' object has no attribute '%s'" % \
1823101Sstever@eecs.umich.edu              (type(self).__name__, attr)
1833101Sstever@eecs.umich.edu
1843101Sstever@eecs.umich.edu    def example_str(self):
1853101Sstever@eecs.umich.edu        if hasattr(self.ptype, "ex_str"):
1863101Sstever@eecs.umich.edu            return self.ptype.ex_str
1873101Sstever@eecs.umich.edu        else:
1883101Sstever@eecs.umich.edu            return self.ptype_str
1893101Sstever@eecs.umich.edu
1903101Sstever@eecs.umich.edu    # Is the param available to be exposed on the command line
1913101Sstever@eecs.umich.edu    def isCmdLineSettable(self):
1923101Sstever@eecs.umich.edu        if hasattr(self.ptype, "cmd_line_settable"):
1933101Sstever@eecs.umich.edu            return self.ptype.cmd_line_settable
1943101Sstever@eecs.umich.edu        else:
1953101Sstever@eecs.umich.edu            return False
1963101Sstever@eecs.umich.edu
1973101Sstever@eecs.umich.edu    def convert(self, value):
1983101Sstever@eecs.umich.edu        if isinstance(value, proxy.BaseProxy):
1993101Sstever@eecs.umich.edu            value.set_param_desc(self)
2003101Sstever@eecs.umich.edu            return value
2013101Sstever@eecs.umich.edu        if not hasattr(self, 'ptype') and isNullPointer(value):
2023101Sstever@eecs.umich.edu            # deferred evaluation of SimObject; continue to defer if
2033101Sstever@eecs.umich.edu            # we're just assigning a null pointer
2043101Sstever@eecs.umich.edu            return value
2053101Sstever@eecs.umich.edu        if isinstance(value, self.ptype):
2063101Sstever@eecs.umich.edu            return value
2073101Sstever@eecs.umich.edu        if isNullPointer(value) and isSimObjectClass(self.ptype):
2083101Sstever@eecs.umich.edu            return value
2093101Sstever@eecs.umich.edu        return self.ptype(value)
2103101Sstever@eecs.umich.edu
2113101Sstever@eecs.umich.edu    def pretty_print(self, value):
2123101Sstever@eecs.umich.edu        if isinstance(value, proxy.BaseProxy):
2133101Sstever@eecs.umich.edu           return str(value)
2143101Sstever@eecs.umich.edu        if isNullPointer(value):
2153101Sstever@eecs.umich.edu           return NULL
2163101Sstever@eecs.umich.edu        return self.ptype(value).pretty_print(value)
2173101Sstever@eecs.umich.edu
2183101Sstever@eecs.umich.edu    def cxx_predecls(self, code):
2193101Sstever@eecs.umich.edu        code('#include <cstddef>')
2203101Sstever@eecs.umich.edu        self.ptype.cxx_predecls(code)
2213101Sstever@eecs.umich.edu
2223101Sstever@eecs.umich.edu    def pybind_predecls(self, code):
2233101Sstever@eecs.umich.edu        self.ptype.pybind_predecls(code)
2243101Sstever@eecs.umich.edu
2253101Sstever@eecs.umich.edu    def cxx_decl(self, code):
2263101Sstever@eecs.umich.edu        code('${{self.ptype.cxx_type}} ${{self.name}};')
2273101Sstever@eecs.umich.edu
2283101Sstever@eecs.umich.edu# Vector-valued parameter description.  Just like ParamDesc, except
2293101Sstever@eecs.umich.edu# that the value is a vector (list) of the specified type instead of a
2303101Sstever@eecs.umich.edu# single value.
2313101Sstever@eecs.umich.edu
2323101Sstever@eecs.umich.educlass VectorParamValue(list):
2333101Sstever@eecs.umich.edu    __metaclass__ = MetaParamValue
2343101Sstever@eecs.umich.edu    def __setattr__(self, attr, value):
2353101Sstever@eecs.umich.edu        raise AttributeError, \
2363101Sstever@eecs.umich.edu              "Not allowed to set %s on '%s'" % (attr, type(self).__name__)
2373101Sstever@eecs.umich.edu
2383101Sstever@eecs.umich.edu    def config_value(self):
2393101Sstever@eecs.umich.edu        return [v.config_value() for v in self]
2403101Sstever@eecs.umich.edu
2413101Sstever@eecs.umich.edu    def ini_str(self):
2423101Sstever@eecs.umich.edu        return ' '.join([v.ini_str() for v in self])
2433101Sstever@eecs.umich.edu
2443101Sstever@eecs.umich.edu    def getValue(self):
2453101Sstever@eecs.umich.edu        return [ v.getValue() for v in self ]
2463101Sstever@eecs.umich.edu
2473101Sstever@eecs.umich.edu    def unproxy(self, base):
2483101Sstever@eecs.umich.edu        if len(self) == 1 and isinstance(self[0], proxy.BaseProxy):
2493101Sstever@eecs.umich.edu            # The value is a proxy (e.g. Parent.any, Parent.all or
2503101Sstever@eecs.umich.edu            # Parent.x) therefore try resolve it
2513101Sstever@eecs.umich.edu            return self[0].unproxy(base)
2523101Sstever@eecs.umich.edu        else:
2533101Sstever@eecs.umich.edu            return [v.unproxy(base) for v in self]
2543101Sstever@eecs.umich.edu
2553101Sstever@eecs.umich.educlass SimObjectVector(VectorParamValue):
2563101Sstever@eecs.umich.edu    # support clone operation
2573101Sstever@eecs.umich.edu    def __call__(self, **kwargs):
2583101Sstever@eecs.umich.edu        return SimObjectVector([v(**kwargs) for v in self])
2593101Sstever@eecs.umich.edu
2603101Sstever@eecs.umich.edu    def clear_parent(self, old_parent):
2613101Sstever@eecs.umich.edu        for v in self:
2623101Sstever@eecs.umich.edu            v.clear_parent(old_parent)
2633101Sstever@eecs.umich.edu
2643101Sstever@eecs.umich.edu    def set_parent(self, parent, name):
2653101Sstever@eecs.umich.edu        if len(self) == 1:
2663101Sstever@eecs.umich.edu            self[0].set_parent(parent, name)
2673101Sstever@eecs.umich.edu        else:
2683101Sstever@eecs.umich.edu            width = int(math.ceil(math.log(len(self))/math.log(10)))
2693101Sstever@eecs.umich.edu            for i,v in enumerate(self):
2703101Sstever@eecs.umich.edu                v.set_parent(parent, "%s%0*d" % (name, width, i))
2713101Sstever@eecs.umich.edu
2723101Sstever@eecs.umich.edu    def has_parent(self):
2733101Sstever@eecs.umich.edu        return any([e.has_parent() for e in self if not isNullPointer(e)])
2743101Sstever@eecs.umich.edu
2753101Sstever@eecs.umich.edu    # return 'cpu0 cpu1' etc. for print_ini()
2763101Sstever@eecs.umich.edu    def get_name(self):
2773101Sstever@eecs.umich.edu        return ' '.join([v._name for v in self])
2783101Sstever@eecs.umich.edu
2793101Sstever@eecs.umich.edu    # By iterating through the constituent members of the vector here
2803101Sstever@eecs.umich.edu    # we can nicely handle iterating over all a SimObject's children
2813101Sstever@eecs.umich.edu    # without having to provide lots of special functions on
2823101Sstever@eecs.umich.edu    # SimObjectVector directly.
2833101Sstever@eecs.umich.edu    def descendants(self):
2843101Sstever@eecs.umich.edu        for v in self:
2853101Sstever@eecs.umich.edu            for obj in v.descendants():
2863101Sstever@eecs.umich.edu                yield obj
2873101Sstever@eecs.umich.edu
2883101Sstever@eecs.umich.edu    def get_config_as_dict(self):
2893101Sstever@eecs.umich.edu        a = []
2903101Sstever@eecs.umich.edu        for v in self:
2913101Sstever@eecs.umich.edu            a.append(v.get_config_as_dict())
2923101Sstever@eecs.umich.edu        return a
2933101Sstever@eecs.umich.edu
2943101Sstever@eecs.umich.edu    # If we are replacing an item in the vector, make sure to set the
2953101Sstever@eecs.umich.edu    # parent reference of the new SimObject to be the same as the parent
2963101Sstever@eecs.umich.edu    # of the SimObject being replaced. Useful to have if we created
2973101Sstever@eecs.umich.edu    # a SimObjectVector of temporary objects that will be modified later in
2983101Sstever@eecs.umich.edu    # configuration scripts.
2993101Sstever@eecs.umich.edu    def __setitem__(self, key, value):
3003101Sstever@eecs.umich.edu        val = self[key]
3013101Sstever@eecs.umich.edu        if value.has_parent():
3023101Sstever@eecs.umich.edu            warn("SimObject %s already has a parent" % value.get_name() +\
3033101Sstever@eecs.umich.edu                 " that is being overwritten by a SimObjectVector")
3043101Sstever@eecs.umich.edu        value.set_parent(val.get_parent(), val._name)
3053101Sstever@eecs.umich.edu        super(SimObjectVector, self).__setitem__(key, value)
3063101Sstever@eecs.umich.edu
3073101Sstever@eecs.umich.edu    # Enumerate the params of each member of the SimObject vector. Creates
3083101Sstever@eecs.umich.edu    # strings that will allow indexing into the vector by the python code and
3093101Sstever@eecs.umich.edu    # allow it to be specified on the command line.
3103102Sstever@eecs.umich.edu    def enumerateParams(self, flags_dict = {},
3113101Sstever@eecs.umich.edu                        cmd_line_str = "",
3123101Sstever@eecs.umich.edu                        access_str = ""):
3133101Sstever@eecs.umich.edu        if hasattr(self, "_paramEnumed"):
3143101Sstever@eecs.umich.edu            print "Cycle detected enumerating params at %s?!" % (cmd_line_str)
3153101Sstever@eecs.umich.edu        else:
3163101Sstever@eecs.umich.edu            x = 0
3173101Sstever@eecs.umich.edu            for vals in self:
3183101Sstever@eecs.umich.edu                # Each entry in the SimObjectVector should be an
3193101Sstever@eecs.umich.edu                # instance of a SimObject
3203101Sstever@eecs.umich.edu                flags_dict = vals.enumerateParams(flags_dict,
3213101Sstever@eecs.umich.edu                                                  cmd_line_str + "%d." % x,
3223101Sstever@eecs.umich.edu                                                  access_str + "[%d]." % x)
3233101Sstever@eecs.umich.edu                x = x + 1
3243101Sstever@eecs.umich.edu
3253101Sstever@eecs.umich.edu        return flags_dict
3263101Sstever@eecs.umich.edu
3273101Sstever@eecs.umich.educlass VectorParamDesc(ParamDesc):
3283101Sstever@eecs.umich.edu    # Convert assigned value to appropriate type.  If the RHS is not a
3293101Sstever@eecs.umich.edu    # list or tuple, it generates a single-element list.
3303101Sstever@eecs.umich.edu    def convert(self, value):
3313101Sstever@eecs.umich.edu        if isinstance(value, (list, tuple)):
3323101Sstever@eecs.umich.edu            # list: coerce each element into new list
3333101Sstever@eecs.umich.edu            tmp_list = [ ParamDesc.convert(self, v) for v in value ]
3343101Sstever@eecs.umich.edu        elif isinstance(value, str):
3353101Sstever@eecs.umich.edu            # If input is a csv string
3363101Sstever@eecs.umich.edu            tmp_list = [ ParamDesc.convert(self, v) \
3373101Sstever@eecs.umich.edu                         for v in value.strip('[').strip(']').split(',') ]
3383101Sstever@eecs.umich.edu        else:
3393101Sstever@eecs.umich.edu            # singleton: coerce to a single-element list
3403101Sstever@eecs.umich.edu            tmp_list = [ ParamDesc.convert(self, value) ]
3413101Sstever@eecs.umich.edu
3423101Sstever@eecs.umich.edu        if isSimObjectSequence(tmp_list):
3433101Sstever@eecs.umich.edu            return SimObjectVector(tmp_list)
3443101Sstever@eecs.umich.edu        else:
3453102Sstever@eecs.umich.edu            return VectorParamValue(tmp_list)
3463101Sstever@eecs.umich.edu
3473101Sstever@eecs.umich.edu    # Produce a human readable example string that describes
3483101Sstever@eecs.umich.edu    # how to set this vector parameter in the absence of a default
3493101Sstever@eecs.umich.edu    # value.
3503101Sstever@eecs.umich.edu    def example_str(self):
3513101Sstever@eecs.umich.edu        s = super(VectorParamDesc, self).example_str()
3523101Sstever@eecs.umich.edu        help_str = "[" + s + "," + s + ", ...]"
3533101Sstever@eecs.umich.edu        return help_str
3543101Sstever@eecs.umich.edu
3553102Sstever@eecs.umich.edu    # Produce a human readable representation of the value of this vector param.
3563101Sstever@eecs.umich.edu    def pretty_print(self, value):
3573101Sstever@eecs.umich.edu        if isinstance(value, (list, tuple)):
3583101Sstever@eecs.umich.edu            tmp_list = [ ParamDesc.pretty_print(self, v) for v in value ]
3593101Sstever@eecs.umich.edu        elif isinstance(value, str):
3603101Sstever@eecs.umich.edu            tmp_list = [ ParamDesc.pretty_print(self, v) for v in value.split(',') ]
3613101Sstever@eecs.umich.edu        else:
3623101Sstever@eecs.umich.edu            tmp_list = [ ParamDesc.pretty_print(self, value) ]
3633101Sstever@eecs.umich.edu
3643101Sstever@eecs.umich.edu        return tmp_list
3653101Sstever@eecs.umich.edu
3663101Sstever@eecs.umich.edu    # This is a helper function for the new config system
3673101Sstever@eecs.umich.edu    def __call__(self, value):
3683102Sstever@eecs.umich.edu        if isinstance(value, (list, tuple)):
3693101Sstever@eecs.umich.edu            # list: coerce each element into new list
3703101Sstever@eecs.umich.edu            tmp_list = [ ParamDesc.convert(self, v) for v in value ]
3713101Sstever@eecs.umich.edu        elif isinstance(value, str):
3723101Sstever@eecs.umich.edu            # If input is a csv string
3733101Sstever@eecs.umich.edu            tmp_list = [ ParamDesc.convert(self, v) \
3743101Sstever@eecs.umich.edu                         for v in value.strip('[').strip(']').split(',') ]
3753101Sstever@eecs.umich.edu        else:
3763101Sstever@eecs.umich.edu            # singleton: coerce to a single-element list
3773101Sstever@eecs.umich.edu            tmp_list = [ ParamDesc.convert(self, value) ]
3783101Sstever@eecs.umich.edu
3793101Sstever@eecs.umich.edu        return VectorParamValue(tmp_list)
3803101Sstever@eecs.umich.edu
3813101Sstever@eecs.umich.edu    def cxx_predecls(self, code):
3823101Sstever@eecs.umich.edu        code('#include <vector>')
3833101Sstever@eecs.umich.edu        self.ptype.cxx_predecls(code)
3843101Sstever@eecs.umich.edu
3853101Sstever@eecs.umich.edu    def pybind_predecls(self, code):
3863101Sstever@eecs.umich.edu        code('#include <vector>')
3873101Sstever@eecs.umich.edu        self.ptype.pybind_predecls(code)
3883101Sstever@eecs.umich.edu
3893101Sstever@eecs.umich.edu    def cxx_decl(self, code):
3903101Sstever@eecs.umich.edu        code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};')
3913101Sstever@eecs.umich.edu
3923101Sstever@eecs.umich.educlass ParamFactory(object):
3933101Sstever@eecs.umich.edu    def __init__(self, param_desc_class, ptype_str = None):
3943101Sstever@eecs.umich.edu        self.param_desc_class = param_desc_class
3953101Sstever@eecs.umich.edu        self.ptype_str = ptype_str
3963101Sstever@eecs.umich.edu
3973101Sstever@eecs.umich.edu    def __getattr__(self, attr):
3983101Sstever@eecs.umich.edu        if self.ptype_str:
3993101Sstever@eecs.umich.edu            attr = self.ptype_str + '.' + attr
4003101Sstever@eecs.umich.edu        return ParamFactory(self.param_desc_class, attr)
4013101Sstever@eecs.umich.edu
4023101Sstever@eecs.umich.edu    # E.g., Param.Int(5, "number of widgets")
4033101Sstever@eecs.umich.edu    def __call__(self, *args, **kwargs):
4043101Sstever@eecs.umich.edu        ptype = None
4053101Sstever@eecs.umich.edu        try:
4063101Sstever@eecs.umich.edu            ptype = allParams[self.ptype_str]
4073101Sstever@eecs.umich.edu        except KeyError:
4083101Sstever@eecs.umich.edu            # if name isn't defined yet, assume it's a SimObject, and
4093101Sstever@eecs.umich.edu            # try to resolve it later
4103101Sstever@eecs.umich.edu            pass
4113101Sstever@eecs.umich.edu        return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs)
4123101Sstever@eecs.umich.edu
4133101Sstever@eecs.umich.eduParam = ParamFactory(ParamDesc)
4143101Sstever@eecs.umich.eduVectorParam = ParamFactory(VectorParamDesc)
4153101Sstever@eecs.umich.edu
4163101Sstever@eecs.umich.edu#####################################################################
4173101Sstever@eecs.umich.edu#
4183101Sstever@eecs.umich.edu# Parameter Types
4193101Sstever@eecs.umich.edu#
4203101Sstever@eecs.umich.edu# Though native Python types could be used to specify parameter types
4213101Sstever@eecs.umich.edu# (the 'ptype' field of the Param and VectorParam classes), it's more
4223101Sstever@eecs.umich.edu# flexible to define our own set of types.  This gives us more control
4233101Sstever@eecs.umich.edu# over how Python expressions are converted to values (via the
4243101Sstever@eecs.umich.edu# __init__() constructor) and how these values are printed out (via
4253101Sstever@eecs.umich.edu# the __str__() conversion method).
4263101Sstever@eecs.umich.edu#
4273101Sstever@eecs.umich.edu#####################################################################
4283101Sstever@eecs.umich.edu
4293101Sstever@eecs.umich.edu# String-valued parameter.  Just mixin the ParamValue class with the
4303101Sstever@eecs.umich.edu# built-in str class.
4313101Sstever@eecs.umich.educlass String(ParamValue,str):
4323101Sstever@eecs.umich.edu    cxx_type = 'std::string'
4333101Sstever@eecs.umich.edu    cmd_line_settable = True
4343101Sstever@eecs.umich.edu
4353102Sstever@eecs.umich.edu    @classmethod
4363101Sstever@eecs.umich.edu    def cxx_predecls(self, code):
4373101Sstever@eecs.umich.edu        code('#include <string>')
4383101Sstever@eecs.umich.edu
4393101Sstever@eecs.umich.edu    def __call__(self, value):
4403101Sstever@eecs.umich.edu        self = value
4413101Sstever@eecs.umich.edu        return value
4423101Sstever@eecs.umich.edu
4433101Sstever@eecs.umich.edu    @classmethod
4443101Sstever@eecs.umich.edu    def cxx_ini_parse(self, code, src, dest, ret):
4453101Sstever@eecs.umich.edu        code('%s = %s;' % (dest, src))
4463101Sstever@eecs.umich.edu        code('%s true;' % ret)
4473101Sstever@eecs.umich.edu
4483101Sstever@eecs.umich.edu    def getValue(self):
4493101Sstever@eecs.umich.edu        return self
4503101Sstever@eecs.umich.edu
4513101Sstever@eecs.umich.edu# superclass for "numeric" parameter values, to emulate math
4523101Sstever@eecs.umich.edu# operations in a type-safe way.  e.g., a Latency times an int returns
4533101Sstever@eecs.umich.edu# a new Latency object.
4543101Sstever@eecs.umich.educlass NumericParamValue(ParamValue):
4553101Sstever@eecs.umich.edu    def __str__(self):
4563101Sstever@eecs.umich.edu        return str(self.value)
4573101Sstever@eecs.umich.edu
4583101Sstever@eecs.umich.edu    def __float__(self):
4593101Sstever@eecs.umich.edu        return float(self.value)
4603101Sstever@eecs.umich.edu
4613101Sstever@eecs.umich.edu    def __long__(self):
4623101Sstever@eecs.umich.edu        return long(self.value)
4633101Sstever@eecs.umich.edu
4643101Sstever@eecs.umich.edu    def __int__(self):
4653101Sstever@eecs.umich.edu        return int(self.value)
4663101Sstever@eecs.umich.edu
4673101Sstever@eecs.umich.edu    # hook for bounds checking
4683101Sstever@eecs.umich.edu    def _check(self):
4693101Sstever@eecs.umich.edu        return
4703101Sstever@eecs.umich.edu
4713101Sstever@eecs.umich.edu    def __mul__(self, other):
4723101Sstever@eecs.umich.edu        newobj = self.__class__(self)
4733101Sstever@eecs.umich.edu        newobj.value *= other
4743101Sstever@eecs.umich.edu        newobj._check()
4753101Sstever@eecs.umich.edu        return newobj
4763101Sstever@eecs.umich.edu
4773101Sstever@eecs.umich.edu    __rmul__ = __mul__
4783101Sstever@eecs.umich.edu
4793101Sstever@eecs.umich.edu    def __div__(self, other):
4803101Sstever@eecs.umich.edu        newobj = self.__class__(self)
4813101Sstever@eecs.umich.edu        newobj.value /= other
4823101Sstever@eecs.umich.edu        newobj._check()
4833101Sstever@eecs.umich.edu        return newobj
4843101Sstever@eecs.umich.edu
4853101Sstever@eecs.umich.edu    def __sub__(self, other):
4863101Sstever@eecs.umich.edu        newobj = self.__class__(self)
4873101Sstever@eecs.umich.edu        newobj.value -= other
4883101Sstever@eecs.umich.edu        newobj._check()
4893101Sstever@eecs.umich.edu        return newobj
4903101Sstever@eecs.umich.edu
4913101Sstever@eecs.umich.edu    def config_value(self):
4923101Sstever@eecs.umich.edu        return self.value
4933101Sstever@eecs.umich.edu
4943101Sstever@eecs.umich.edu    @classmethod
4953101Sstever@eecs.umich.edu    def cxx_ini_predecls(cls, code):
4963101Sstever@eecs.umich.edu        # Assume that base/str.hh will be included anyway
4973101Sstever@eecs.umich.edu        # code('#include "base/str.hh"')
4983101Sstever@eecs.umich.edu        pass
4993101Sstever@eecs.umich.edu
5003101Sstever@eecs.umich.edu    # The default for parsing PODs from an .ini entry is to extract from an
5013101Sstever@eecs.umich.edu    # istringstream and let overloading choose the right type according to
5023101Sstever@eecs.umich.edu    # the dest type.
5033101Sstever@eecs.umich.edu    @classmethod
5043101Sstever@eecs.umich.edu    def cxx_ini_parse(self, code, src, dest, ret):
5053101Sstever@eecs.umich.edu        code('%s to_number(%s, %s);' % (ret, src, dest))
5063101Sstever@eecs.umich.edu
5073101Sstever@eecs.umich.edu# Metaclass for bounds-checked integer parameters.  See CheckedInt.
5083101Sstever@eecs.umich.educlass CheckedIntType(MetaParamValue):
5093101Sstever@eecs.umich.edu    def __init__(cls, name, bases, dict):
5103101Sstever@eecs.umich.edu        super(CheckedIntType, cls).__init__(name, bases, dict)
5113101Sstever@eecs.umich.edu
5123101Sstever@eecs.umich.edu        # CheckedInt is an abstract base class, so we actually don't
5133101Sstever@eecs.umich.edu        # want to do any processing on it... the rest of this code is
5143101Sstever@eecs.umich.edu        # just for classes that derive from CheckedInt.
5153101Sstever@eecs.umich.edu        if name == 'CheckedInt':
5163101Sstever@eecs.umich.edu            return
5173101Sstever@eecs.umich.edu
5183101Sstever@eecs.umich.edu        if not (hasattr(cls, 'min') and hasattr(cls, 'max')):
5193101Sstever@eecs.umich.edu            if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')):
5203101Sstever@eecs.umich.edu                panic("CheckedInt subclass %s must define either\n" \
5213101Sstever@eecs.umich.edu                      "    'min' and 'max' or 'size' and 'unsigned'\n",
5223101Sstever@eecs.umich.edu                      name);
5233101Sstever@eecs.umich.edu            if cls.unsigned:
5243101Sstever@eecs.umich.edu                cls.min = 0
5253101Sstever@eecs.umich.edu                cls.max = 2 ** cls.size - 1
5263101Sstever@eecs.umich.edu            else:
5273101Sstever@eecs.umich.edu                cls.min = -(2 ** (cls.size - 1))
5283101Sstever@eecs.umich.edu                cls.max = (2 ** (cls.size - 1)) - 1
5293101Sstever@eecs.umich.edu
5303101Sstever@eecs.umich.edu# Abstract superclass for bounds-checked integer parameters.  This
5313101Sstever@eecs.umich.edu# class is subclassed to generate parameter classes with specific
5323101Sstever@eecs.umich.edu# bounds.  Initialization of the min and max bounds is done in the
5333101Sstever@eecs.umich.edu# metaclass CheckedIntType.__init__.
5343101Sstever@eecs.umich.educlass CheckedInt(NumericParamValue):
5353101Sstever@eecs.umich.edu    __metaclass__ = CheckedIntType
5363101Sstever@eecs.umich.edu    cmd_line_settable = True
5373101Sstever@eecs.umich.edu
5383101Sstever@eecs.umich.edu    def _check(self):
5393101Sstever@eecs.umich.edu        if not self.min <= self.value <= self.max:
5403101Sstever@eecs.umich.edu            raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
5413101Sstever@eecs.umich.edu                  (self.min, self.value, self.max)
5423101Sstever@eecs.umich.edu
5433101Sstever@eecs.umich.edu    def __init__(self, value):
5443101Sstever@eecs.umich.edu        if isinstance(value, str):
5453101Sstever@eecs.umich.edu            self.value = convert.toInteger(value)
5463101Sstever@eecs.umich.edu        elif isinstance(value, (int, long, float, NumericParamValue)):
5473101Sstever@eecs.umich.edu            self.value = long(value)
5483101Sstever@eecs.umich.edu        else:
5493101Sstever@eecs.umich.edu            raise TypeError, "Can't convert object of type %s to CheckedInt" \
5503101Sstever@eecs.umich.edu                  % type(value).__name__
5513101Sstever@eecs.umich.edu        self._check()
5523101Sstever@eecs.umich.edu
5533101Sstever@eecs.umich.edu    def __call__(self, value):
5543101Sstever@eecs.umich.edu        self.__init__(value)
5553101Sstever@eecs.umich.edu        return value
5563101Sstever@eecs.umich.edu
5573101Sstever@eecs.umich.edu    @classmethod
5583101Sstever@eecs.umich.edu    def cxx_predecls(cls, code):
5593101Sstever@eecs.umich.edu        # most derived types require this, so we just do it here once
5603101Sstever@eecs.umich.edu        code('#include "base/types.hh"')
5613101Sstever@eecs.umich.edu
5623101Sstever@eecs.umich.edu    def getValue(self):
5633101Sstever@eecs.umich.edu        return long(self.value)
5643101Sstever@eecs.umich.edu
5653101Sstever@eecs.umich.educlass Int(CheckedInt):      cxx_type = 'int';      size = 32; unsigned = False
5663101Sstever@eecs.umich.educlass Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True
5673101Sstever@eecs.umich.edu
5683101Sstever@eecs.umich.educlass Int8(CheckedInt):     cxx_type =   'int8_t'; size =  8; unsigned = False
5693101Sstever@eecs.umich.educlass UInt8(CheckedInt):    cxx_type =  'uint8_t'; size =  8; unsigned = True
5703101Sstever@eecs.umich.educlass Int16(CheckedInt):    cxx_type =  'int16_t'; size = 16; unsigned = False
5713101Sstever@eecs.umich.educlass UInt16(CheckedInt):   cxx_type = 'uint16_t'; size = 16; unsigned = True
5723101Sstever@eecs.umich.educlass Int32(CheckedInt):    cxx_type =  'int32_t'; size = 32; unsigned = False
5733101Sstever@eecs.umich.educlass UInt32(CheckedInt):   cxx_type = 'uint32_t'; size = 32; unsigned = True
5743101Sstever@eecs.umich.educlass Int64(CheckedInt):    cxx_type =  'int64_t'; size = 64; unsigned = False
5753101Sstever@eecs.umich.educlass UInt64(CheckedInt):   cxx_type = 'uint64_t'; size = 64; unsigned = True
5763101Sstever@eecs.umich.edu
5773101Sstever@eecs.umich.educlass Counter(CheckedInt):  cxx_type = 'Counter';  size = 64; unsigned = True
5783101Sstever@eecs.umich.educlass Tick(CheckedInt):     cxx_type = 'Tick';     size = 64; unsigned = True
5793101Sstever@eecs.umich.educlass TcpPort(CheckedInt):  cxx_type = 'uint16_t'; size = 16; unsigned = True
5803101Sstever@eecs.umich.educlass UdpPort(CheckedInt):  cxx_type = 'uint16_t'; size = 16; unsigned = True
5813101Sstever@eecs.umich.edu
5823101Sstever@eecs.umich.educlass Percent(CheckedInt):  cxx_type = 'int'; min = 0; max = 100
5833101Sstever@eecs.umich.edu
5843101Sstever@eecs.umich.educlass Cycles(CheckedInt):
5853101Sstever@eecs.umich.edu    cxx_type = 'Cycles'
5863101Sstever@eecs.umich.edu    size = 64
5873101Sstever@eecs.umich.edu    unsigned = True
5883101Sstever@eecs.umich.edu
5893101Sstever@eecs.umich.edu    def getValue(self):
5903101Sstever@eecs.umich.edu        from _m5.core import Cycles
5913102Sstever@eecs.umich.edu        return Cycles(self.value)
5923101Sstever@eecs.umich.edu
5933101Sstever@eecs.umich.edu    @classmethod
5943102Sstever@eecs.umich.edu    def cxx_ini_predecls(cls, code):
5953101Sstever@eecs.umich.edu        # Assume that base/str.hh will be included anyway
5963101Sstever@eecs.umich.edu        # code('#include "base/str.hh"')
5973101Sstever@eecs.umich.edu        pass
5983101Sstever@eecs.umich.edu
5993101Sstever@eecs.umich.edu    @classmethod
6003101Sstever@eecs.umich.edu    def cxx_ini_parse(cls, code, src, dest, ret):
6013101Sstever@eecs.umich.edu        code('uint64_t _temp;')
6023101Sstever@eecs.umich.edu        code('bool _ret = to_number(%s, _temp);' % src)
6033101Sstever@eecs.umich.edu        code('if (_ret)')
6043101Sstever@eecs.umich.edu        code('    %s = Cycles(_temp);' % dest)
6053101Sstever@eecs.umich.edu        code('%s _ret;' % ret)
6063101Sstever@eecs.umich.edu
6073101Sstever@eecs.umich.educlass Float(ParamValue, float):
6083101Sstever@eecs.umich.edu    cxx_type = 'double'
6093101Sstever@eecs.umich.edu    cmd_line_settable = True
6103101Sstever@eecs.umich.edu
6113101Sstever@eecs.umich.edu    def __init__(self, value):
6123101Sstever@eecs.umich.edu        if isinstance(value, (int, long, float, NumericParamValue, Float, str)):
6133101Sstever@eecs.umich.edu            self.value = float(value)
6143101Sstever@eecs.umich.edu        else:
6153101Sstever@eecs.umich.edu            raise TypeError, "Can't convert object of type %s to Float" \
6163101Sstever@eecs.umich.edu                  % type(value).__name__
6173101Sstever@eecs.umich.edu
6183101Sstever@eecs.umich.edu    def __call__(self, value):
6193101Sstever@eecs.umich.edu        self.__init__(value)
6203101Sstever@eecs.umich.edu        return value
6213101Sstever@eecs.umich.edu
6223101Sstever@eecs.umich.edu    def getValue(self):
6233101Sstever@eecs.umich.edu        return float(self.value)
6243101Sstever@eecs.umich.edu
6253101Sstever@eecs.umich.edu    def config_value(self):
6263101Sstever@eecs.umich.edu        return self
6273101Sstever@eecs.umich.edu
6283101Sstever@eecs.umich.edu    @classmethod
6293101Sstever@eecs.umich.edu    def cxx_ini_predecls(cls, code):
6303101Sstever@eecs.umich.edu        code('#include <sstream>')
6313101Sstever@eecs.umich.edu
6323101Sstever@eecs.umich.edu    @classmethod
6333101Sstever@eecs.umich.edu    def cxx_ini_parse(self, code, src, dest, ret):
6343101Sstever@eecs.umich.edu        code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
6353101Sstever@eecs.umich.edu
6363101Sstever@eecs.umich.educlass MemorySize(CheckedInt):
6373101Sstever@eecs.umich.edu    cxx_type = 'uint64_t'
6383101Sstever@eecs.umich.edu    ex_str = '512MB'
6393101Sstever@eecs.umich.edu    size = 64
6403101Sstever@eecs.umich.edu    unsigned = True
6413101Sstever@eecs.umich.edu    def __init__(self, value):
6423101Sstever@eecs.umich.edu        if isinstance(value, MemorySize):
6433101Sstever@eecs.umich.edu            self.value = value.value
6443101Sstever@eecs.umich.edu        else:
6453101Sstever@eecs.umich.edu            self.value = convert.toMemorySize(value)
6463101Sstever@eecs.umich.edu        self._check()
6473101Sstever@eecs.umich.edu
6483101Sstever@eecs.umich.educlass MemorySize32(CheckedInt):
6493101Sstever@eecs.umich.edu    cxx_type = 'uint32_t'
6503101Sstever@eecs.umich.edu    ex_str = '512MB'
6513101Sstever@eecs.umich.edu    size = 32
6523101Sstever@eecs.umich.edu    unsigned = True
6533101Sstever@eecs.umich.edu    def __init__(self, value):
6543101Sstever@eecs.umich.edu        if isinstance(value, MemorySize):
6553101Sstever@eecs.umich.edu            self.value = value.value
6563101Sstever@eecs.umich.edu        else:
6573101Sstever@eecs.umich.edu            self.value = convert.toMemorySize(value)
6583101Sstever@eecs.umich.edu        self._check()
6593101Sstever@eecs.umich.edu
6603101Sstever@eecs.umich.educlass Addr(CheckedInt):
6613101Sstever@eecs.umich.edu    cxx_type = 'Addr'
6623101Sstever@eecs.umich.edu    size = 64
6633101Sstever@eecs.umich.edu    unsigned = True
6643101Sstever@eecs.umich.edu    def __init__(self, value):
6653101Sstever@eecs.umich.edu        if isinstance(value, Addr):
6663101Sstever@eecs.umich.edu            self.value = value.value
6673101Sstever@eecs.umich.edu        else:
6683101Sstever@eecs.umich.edu            try:
6693101Sstever@eecs.umich.edu                # Often addresses are referred to with sizes. Ex: A device
6703101Sstever@eecs.umich.edu                # base address is at "512MB".  Use toMemorySize() to convert
6713101Sstever@eecs.umich.edu                # these into addresses. If the address is not specified with a
6723101Sstever@eecs.umich.edu                # "size", an exception will occur and numeric translation will
6733101Sstever@eecs.umich.edu                # proceed below.
6743101Sstever@eecs.umich.edu                self.value = convert.toMemorySize(value)
6753101Sstever@eecs.umich.edu            except (TypeError, ValueError):
6763101Sstever@eecs.umich.edu                # Convert number to string and use long() to do automatic
6773101Sstever@eecs.umich.edu                # base conversion (requires base=0 for auto-conversion)
6783101Sstever@eecs.umich.edu                self.value = long(str(value), base=0)
6793101Sstever@eecs.umich.edu
6803101Sstever@eecs.umich.edu        self._check()
6813101Sstever@eecs.umich.edu    def __add__(self, other):
6823101Sstever@eecs.umich.edu        if isinstance(other, Addr):
6833102Sstever@eecs.umich.edu            return self.value + other.value
6843101Sstever@eecs.umich.edu        else:
6853101Sstever@eecs.umich.edu            return self.value + other
6863101Sstever@eecs.umich.edu    def pretty_print(self, value):
6873101Sstever@eecs.umich.edu        try:
6883101Sstever@eecs.umich.edu            val = convert.toMemorySize(value)
6893101Sstever@eecs.umich.edu        except TypeError:
6903101Sstever@eecs.umich.edu            val = long(value)
6913101Sstever@eecs.umich.edu        return "0x%x" % long(val)
6923101Sstever@eecs.umich.edu
6933101Sstever@eecs.umich.educlass AddrRange(ParamValue):
6943101Sstever@eecs.umich.edu    cxx_type = 'AddrRange'
6953102Sstever@eecs.umich.edu
6963101Sstever@eecs.umich.edu    def __init__(self, *args, **kwargs):
6973101Sstever@eecs.umich.edu        # Disable interleaving and hashing by default
6983101Sstever@eecs.umich.edu        self.intlvHighBit = 0
6993101Sstever@eecs.umich.edu        self.xorHighBit = 0
7003101Sstever@eecs.umich.edu        self.intlvBits = 0
7013101Sstever@eecs.umich.edu        self.intlvMatch = 0
7023101Sstever@eecs.umich.edu
7033101Sstever@eecs.umich.edu        def handle_kwargs(self, kwargs):
7043101Sstever@eecs.umich.edu            # An address range needs to have an upper limit, specified
7053101Sstever@eecs.umich.edu            # either explicitly with an end, or as an offset using the
7063101Sstever@eecs.umich.edu            # size keyword.
7073101Sstever@eecs.umich.edu            if 'end' in kwargs:
7083102Sstever@eecs.umich.edu                self.end = Addr(kwargs.pop('end'))
7093102Sstever@eecs.umich.edu            elif 'size' in kwargs:
7103102Sstever@eecs.umich.edu                self.end = self.start + Addr(kwargs.pop('size')) - 1
7113102Sstever@eecs.umich.edu            else:
7123102Sstever@eecs.umich.edu                raise TypeError, "Either end or size must be specified"
7133102Sstever@eecs.umich.edu
7143102Sstever@eecs.umich.edu            # Now on to the optional bit
7153102Sstever@eecs.umich.edu            if 'intlvHighBit' in kwargs:
7163102Sstever@eecs.umich.edu                self.intlvHighBit = int(kwargs.pop('intlvHighBit'))
7173102Sstever@eecs.umich.edu            if 'xorHighBit' in kwargs:
7183102Sstever@eecs.umich.edu                self.xorHighBit = int(kwargs.pop('xorHighBit'))
7193102Sstever@eecs.umich.edu            if 'intlvBits' in kwargs:
7203102Sstever@eecs.umich.edu                self.intlvBits = int(kwargs.pop('intlvBits'))
7213102Sstever@eecs.umich.edu            if 'intlvMatch' in kwargs:
7223102Sstever@eecs.umich.edu                self.intlvMatch = int(kwargs.pop('intlvMatch'))
7233102Sstever@eecs.umich.edu
7243102Sstever@eecs.umich.edu        if len(args) == 0:
7253102Sstever@eecs.umich.edu            self.start = Addr(kwargs.pop('start'))
7263102Sstever@eecs.umich.edu            handle_kwargs(self, kwargs)
7273102Sstever@eecs.umich.edu
7283102Sstever@eecs.umich.edu        elif len(args) == 1:
7293102Sstever@eecs.umich.edu            if kwargs:
7303102Sstever@eecs.umich.edu                self.start = Addr(args[0])
7313102Sstever@eecs.umich.edu                handle_kwargs(self, kwargs)
7323102Sstever@eecs.umich.edu            elif isinstance(args[0], (list, tuple)):
7333102Sstever@eecs.umich.edu                self.start = Addr(args[0][0])
7343102Sstever@eecs.umich.edu                self.end = Addr(args[0][1])
7353102Sstever@eecs.umich.edu            else:
7363102Sstever@eecs.umich.edu                self.start = Addr(0)
7373102Sstever@eecs.umich.edu                self.end = Addr(args[0]) - 1
7383101Sstever@eecs.umich.edu
7393101Sstever@eecs.umich.edu        elif len(args) == 2:
7403101Sstever@eecs.umich.edu            self.start = Addr(args[0])
7413101Sstever@eecs.umich.edu            self.end = Addr(args[1])
7423101Sstever@eecs.umich.edu        else:
7433101Sstever@eecs.umich.edu            raise TypeError, "Too many arguments specified"
7443101Sstever@eecs.umich.edu
7453101Sstever@eecs.umich.edu        if kwargs:
7463101Sstever@eecs.umich.edu            raise TypeError, "Too many keywords: %s" % kwargs.keys()
7473101Sstever@eecs.umich.edu
7483101Sstever@eecs.umich.edu    def __str__(self):
7493101Sstever@eecs.umich.edu        return '%s:%s:%s:%s:%s:%s' \
7503101Sstever@eecs.umich.edu            % (self.start, self.end, self.intlvHighBit, self.xorHighBit,\
7513101Sstever@eecs.umich.edu               self.intlvBits, self.intlvMatch)
7523101Sstever@eecs.umich.edu
7533101Sstever@eecs.umich.edu    def size(self):
7543101Sstever@eecs.umich.edu        # Divide the size by the size of the interleaving slice
7553105Sstever@eecs.umich.edu        return (long(self.end) - long(self.start) + 1) >> self.intlvBits
7563105Sstever@eecs.umich.edu
7573101Sstever@eecs.umich.edu    @classmethod
7583101Sstever@eecs.umich.edu    def cxx_predecls(cls, code):
7593101Sstever@eecs.umich.edu        Addr.cxx_predecls(code)
7603101Sstever@eecs.umich.edu        code('#include "base/addr_range.hh"')
7613105Sstever@eecs.umich.edu
7623101Sstever@eecs.umich.edu    @classmethod
7633103Sstever@eecs.umich.edu    def pybind_predecls(cls, code):
7643105Sstever@eecs.umich.edu        Addr.pybind_predecls(code)
7653103Sstever@eecs.umich.edu        code('#include "base/addr_range.hh"')
7663105Sstever@eecs.umich.edu
7673105Sstever@eecs.umich.edu    @classmethod
7683105Sstever@eecs.umich.edu    def cxx_ini_predecls(cls, code):
7693105Sstever@eecs.umich.edu        code('#include <sstream>')
7703105Sstever@eecs.umich.edu
7713105Sstever@eecs.umich.edu    @classmethod
7723105Sstever@eecs.umich.edu    def cxx_ini_parse(cls, code, src, dest, ret):
7733105Sstever@eecs.umich.edu        code('uint64_t _start, _end, _intlvHighBit = 0, _xorHighBit = 0;')
7743105Sstever@eecs.umich.edu        code('uint64_t _intlvBits = 0, _intlvMatch = 0;')
7753105Sstever@eecs.umich.edu        code('char _sep;')
7763105Sstever@eecs.umich.edu        code('std::istringstream _stream(${src});')
7773105Sstever@eecs.umich.edu        code('_stream >> _start;')
7783105Sstever@eecs.umich.edu        code('_stream.get(_sep);')
7793105Sstever@eecs.umich.edu        code('_stream >> _end;')
7803105Sstever@eecs.umich.edu        code('if (!_stream.fail() && !_stream.eof()) {')
7813105Sstever@eecs.umich.edu        code('    _stream.get(_sep);')
7823105Sstever@eecs.umich.edu        code('    _stream >> _intlvHighBit;')
7833105Sstever@eecs.umich.edu        code('    _stream.get(_sep);')
7843105Sstever@eecs.umich.edu        code('    _stream >> _xorHighBit;')
7853105Sstever@eecs.umich.edu        code('    _stream.get(_sep);')
7863105Sstever@eecs.umich.edu        code('    _stream >> _intlvBits;')
7873105Sstever@eecs.umich.edu        code('    _stream.get(_sep);')
7883105Sstever@eecs.umich.edu        code('    _stream >> _intlvMatch;')
7893105Sstever@eecs.umich.edu        code('}')
7903105Sstever@eecs.umich.edu        code('bool _ret = !_stream.fail() &&'
7913105Sstever@eecs.umich.edu            '_stream.eof() && _sep == \':\';')
7923101Sstever@eecs.umich.edu        code('if (_ret)')
7933105Sstever@eecs.umich.edu        code('   ${dest} = AddrRange(_start, _end, _intlvHighBit, \
7943105Sstever@eecs.umich.edu                _xorHighBit, _intlvBits, _intlvMatch);')
7953105Sstever@eecs.umich.edu        code('${ret} _ret;')
7963101Sstever@eecs.umich.edu
7973105Sstever@eecs.umich.edu    def getValue(self):
7983105Sstever@eecs.umich.edu        # Go from the Python class to the wrapped C++ class
7993105Sstever@eecs.umich.edu        from _m5.range import AddrRange
8003101Sstever@eecs.umich.edu
8013105Sstever@eecs.umich.edu        return AddrRange(long(self.start), long(self.end),
8023105Sstever@eecs.umich.edu                         int(self.intlvHighBit), int(self.xorHighBit),
8033101Sstever@eecs.umich.edu                         int(self.intlvBits), int(self.intlvMatch))
8043105Sstever@eecs.umich.edu
8053105Sstever@eecs.umich.edu# Boolean parameter type.  Python doesn't let you subclass bool, since
8063105Sstever@eecs.umich.edu# it doesn't want to let you create multiple instances of True and
8073105Sstever@eecs.umich.edu# False.  Thus this is a little more complicated than String.
8083101Sstever@eecs.umich.educlass Bool(ParamValue):
8093101Sstever@eecs.umich.edu    cxx_type = 'bool'
8103105Sstever@eecs.umich.edu    cmd_line_settable = True
8113105Sstever@eecs.umich.edu
8123105Sstever@eecs.umich.edu    def __init__(self, value):
8133105Sstever@eecs.umich.edu        try:
8143105Sstever@eecs.umich.edu            self.value = convert.toBool(value)
8153105Sstever@eecs.umich.edu        except TypeError:
8163105Sstever@eecs.umich.edu            self.value = bool(value)
8173105Sstever@eecs.umich.edu
8183105Sstever@eecs.umich.edu    def __call__(self, value):
8193105Sstever@eecs.umich.edu        self.__init__(value)
8203105Sstever@eecs.umich.edu        return value
8213101Sstever@eecs.umich.edu
8223101Sstever@eecs.umich.edu    def getValue(self):
8233101Sstever@eecs.umich.edu        return bool(self.value)
8243101Sstever@eecs.umich.edu
8253101Sstever@eecs.umich.edu    def __str__(self):
8263101Sstever@eecs.umich.edu        return str(self.value)
8273101Sstever@eecs.umich.edu
8283101Sstever@eecs.umich.edu    # implement truth value testing for Bool parameters so that these params
8293101Sstever@eecs.umich.edu    # evaluate correctly during the python configuration phase
8303101Sstever@eecs.umich.edu    def __nonzero__(self):
8313105Sstever@eecs.umich.edu        return bool(self.value)
8323105Sstever@eecs.umich.edu
8333105Sstever@eecs.umich.edu    def ini_str(self):
8343105Sstever@eecs.umich.edu        if self.value:
8353105Sstever@eecs.umich.edu            return 'true'
8363105Sstever@eecs.umich.edu        return 'false'
8373105Sstever@eecs.umich.edu
8383105Sstever@eecs.umich.edu    def config_value(self):
8393105Sstever@eecs.umich.edu        return self.value
8403105Sstever@eecs.umich.edu
8413105Sstever@eecs.umich.edu    @classmethod
8423105Sstever@eecs.umich.edu    def cxx_ini_predecls(cls, code):
8433105Sstever@eecs.umich.edu        # Assume that base/str.hh will be included anyway
8443105Sstever@eecs.umich.edu        # code('#include "base/str.hh"')
8453105Sstever@eecs.umich.edu        pass
8463105Sstever@eecs.umich.edu
8473105Sstever@eecs.umich.edu    @classmethod
8483105Sstever@eecs.umich.edu    def cxx_ini_parse(cls, code, src, dest, ret):
8493105Sstever@eecs.umich.edu        code('%s to_bool(%s, %s);' % (ret, src, dest))
8503105Sstever@eecs.umich.edu
8513105Sstever@eecs.umich.edudef IncEthernetAddr(addr, val = 1):
8523105Sstever@eecs.umich.edu    bytes = map(lambda x: int(x, 16), addr.split(':'))
8533105Sstever@eecs.umich.edu    bytes[5] += val
8543105Sstever@eecs.umich.edu    for i in (5, 4, 3, 2, 1):
8553105Sstever@eecs.umich.edu        val,rem = divmod(bytes[i], 256)
8563105Sstever@eecs.umich.edu        bytes[i] = rem
8573105Sstever@eecs.umich.edu        if val == 0:
8583105Sstever@eecs.umich.edu            break
8593105Sstever@eecs.umich.edu        bytes[i - 1] += val
8603105Sstever@eecs.umich.edu    assert(bytes[0] <= 255)
8613105Sstever@eecs.umich.edu    return ':'.join(map(lambda x: '%02x' % x, bytes))
8623105Sstever@eecs.umich.edu
8633105Sstever@eecs.umich.edu_NextEthernetAddr = "00:90:00:00:00:01"
8643105Sstever@eecs.umich.edudef NextEthernetAddr():
8653105Sstever@eecs.umich.edu    global _NextEthernetAddr
8663105Sstever@eecs.umich.edu
8673105Sstever@eecs.umich.edu    value = _NextEthernetAddr
8683105Sstever@eecs.umich.edu    _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1)
8693105Sstever@eecs.umich.edu    return value
8703105Sstever@eecs.umich.edu
8713105Sstever@eecs.umich.educlass EthernetAddr(ParamValue):
8723105Sstever@eecs.umich.edu    cxx_type = 'Net::EthAddr'
8733105Sstever@eecs.umich.edu    ex_str = "00:90:00:00:00:01"
8743105Sstever@eecs.umich.edu    cmd_line_settable = True
8753105Sstever@eecs.umich.edu
8763105Sstever@eecs.umich.edu    @classmethod
8773105Sstever@eecs.umich.edu    def cxx_predecls(cls, code):
8783105Sstever@eecs.umich.edu        code('#include "base/inet.hh"')
8793105Sstever@eecs.umich.edu
8803105Sstever@eecs.umich.edu    def __init__(self, value):
8813105Sstever@eecs.umich.edu        if value == NextEthernetAddr:
8823101Sstever@eecs.umich.edu            self.value = value
8833101Sstever@eecs.umich.edu            return
8843101Sstever@eecs.umich.edu
8853101Sstever@eecs.umich.edu        if not isinstance(value, str):
8863105Sstever@eecs.umich.edu            raise TypeError, "expected an ethernet address and didn't get one"
8873105Sstever@eecs.umich.edu
8883105Sstever@eecs.umich.edu        bytes = value.split(':')
8893105Sstever@eecs.umich.edu        if len(bytes) != 6:
8903105Sstever@eecs.umich.edu            raise TypeError, 'invalid ethernet address %s' % value
8913105Sstever@eecs.umich.edu
8923105Sstever@eecs.umich.edu        for byte in bytes:
8933105Sstever@eecs.umich.edu            if not 0 <= int(byte, base=16) <= 0xff:
8943105Sstever@eecs.umich.edu                raise TypeError, 'invalid ethernet address %s' % value
8953105Sstever@eecs.umich.edu
8963105Sstever@eecs.umich.edu        self.value = value
8973101Sstever@eecs.umich.edu
8983101Sstever@eecs.umich.edu    def __call__(self, value):
8993101Sstever@eecs.umich.edu        self.__init__(value)
9003105Sstever@eecs.umich.edu        return value
9013105Sstever@eecs.umich.edu
9023101Sstever@eecs.umich.edu    def unproxy(self, base):
9033101Sstever@eecs.umich.edu        if self.value == NextEthernetAddr:
9043101Sstever@eecs.umich.edu            return EthernetAddr(self.value())
9053105Sstever@eecs.umich.edu        return self
9063105Sstever@eecs.umich.edu
9073101Sstever@eecs.umich.edu    def getValue(self):
9083101Sstever@eecs.umich.edu        from _m5.net import EthAddr
9093101Sstever@eecs.umich.edu        return EthAddr(self.value)
9103101Sstever@eecs.umich.edu
9113105Sstever@eecs.umich.edu    def __str__(self):
9123105Sstever@eecs.umich.edu        return self.value
9133101Sstever@eecs.umich.edu
9143101Sstever@eecs.umich.edu    def ini_str(self):
9153105Sstever@eecs.umich.edu        return self.value
9163105Sstever@eecs.umich.edu
9173105Sstever@eecs.umich.edu    @classmethod
9183105Sstever@eecs.umich.edu    def cxx_ini_parse(self, code, src, dest, ret):
9193101Sstever@eecs.umich.edu        code('%s = Net::EthAddr(%s);' % (dest, src))
9203101Sstever@eecs.umich.edu        code('%s true;' % ret)
9213101Sstever@eecs.umich.edu
9223101Sstever@eecs.umich.edu# When initializing an IpAddress, pass in an existing IpAddress, a string of
9233101Sstever@eecs.umich.edu# the form "a.b.c.d", or an integer representing an IP.
9243101Sstever@eecs.umich.educlass IpAddress(ParamValue):
9253101Sstever@eecs.umich.edu    cxx_type = 'Net::IpAddress'
9263101Sstever@eecs.umich.edu    ex_str = "127.0.0.1"
9273101Sstever@eecs.umich.edu    cmd_line_settable = True
9283101Sstever@eecs.umich.edu
9293101Sstever@eecs.umich.edu    @classmethod
9303101Sstever@eecs.umich.edu    def cxx_predecls(cls, code):
9313102Sstever@eecs.umich.edu        code('#include "base/inet.hh"')
9323101Sstever@eecs.umich.edu
9333101Sstever@eecs.umich.edu    def __init__(self, value):
9343101Sstever@eecs.umich.edu        if isinstance(value, IpAddress):
9353102Sstever@eecs.umich.edu            self.ip = value.ip
9363101Sstever@eecs.umich.edu        else:
9373102Sstever@eecs.umich.edu            try:
9383102Sstever@eecs.umich.edu                self.ip = convert.toIpAddress(value)
939            except TypeError:
940                self.ip = long(value)
941        self.verifyIp()
942
943    def __call__(self, value):
944        self.__init__(value)
945        return value
946
947    def __str__(self):
948        tup = [(self.ip >> i)  & 0xff for i in (24, 16, 8, 0)]
949        return '%d.%d.%d.%d' % tuple(tup)
950
951    def __eq__(self, other):
952        if isinstance(other, IpAddress):
953            return self.ip == other.ip
954        elif isinstance(other, str):
955            try:
956                return self.ip == convert.toIpAddress(other)
957            except:
958                return False
959        else:
960            return self.ip == other
961
962    def __ne__(self, other):
963        return not (self == other)
964
965    def verifyIp(self):
966        if self.ip < 0 or self.ip >= (1 << 32):
967            raise TypeError, "invalid ip address %#08x" % self.ip
968
969    def getValue(self):
970        from _m5.net import IpAddress
971        return IpAddress(self.ip)
972
973# When initializing an IpNetmask, pass in an existing IpNetmask, a string of
974# the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as
975# positional or keyword arguments.
976class IpNetmask(IpAddress):
977    cxx_type = 'Net::IpNetmask'
978    ex_str = "127.0.0.0/24"
979    cmd_line_settable = True
980
981    @classmethod
982    def cxx_predecls(cls, code):
983        code('#include "base/inet.hh"')
984
985    def __init__(self, *args, **kwargs):
986        def handle_kwarg(self, kwargs, key, elseVal = None):
987            if key in kwargs:
988                setattr(self, key, kwargs.pop(key))
989            elif elseVal:
990                setattr(self, key, elseVal)
991            else:
992                raise TypeError, "No value set for %s" % key
993
994        if len(args) == 0:
995            handle_kwarg(self, kwargs, 'ip')
996            handle_kwarg(self, kwargs, 'netmask')
997
998        elif len(args) == 1:
999            if kwargs:
1000                if not 'ip' in kwargs and not 'netmask' in kwargs:
1001                    raise TypeError, "Invalid arguments"
1002                handle_kwarg(self, kwargs, 'ip', args[0])
1003                handle_kwarg(self, kwargs, 'netmask', args[0])
1004            elif isinstance(args[0], IpNetmask):
1005                self.ip = args[0].ip
1006                self.netmask = args[0].netmask
1007            else:
1008                (self.ip, self.netmask) = convert.toIpNetmask(args[0])
1009
1010        elif len(args) == 2:
1011            self.ip = args[0]
1012            self.netmask = args[1]
1013        else:
1014            raise TypeError, "Too many arguments specified"
1015
1016        if kwargs:
1017            raise TypeError, "Too many keywords: %s" % kwargs.keys()
1018
1019        self.verify()
1020
1021    def __call__(self, value):
1022        self.__init__(value)
1023        return value
1024
1025    def __str__(self):
1026        return "%s/%d" % (super(IpNetmask, self).__str__(), self.netmask)
1027
1028    def __eq__(self, other):
1029        if isinstance(other, IpNetmask):
1030            return self.ip == other.ip and self.netmask == other.netmask
1031        elif isinstance(other, str):
1032            try:
1033                return (self.ip, self.netmask) == convert.toIpNetmask(other)
1034            except:
1035                return False
1036        else:
1037            return False
1038
1039    def verify(self):
1040        self.verifyIp()
1041        if self.netmask < 0 or self.netmask > 32:
1042            raise TypeError, "invalid netmask %d" % netmask
1043
1044    def getValue(self):
1045        from _m5.net import IpNetmask
1046        return IpNetmask(self.ip, self.netmask)
1047
1048# When initializing an IpWithPort, pass in an existing IpWithPort, a string of
1049# the form "a.b.c.d:p", or an ip and port as positional or keyword arguments.
1050class IpWithPort(IpAddress):
1051    cxx_type = 'Net::IpWithPort'
1052    ex_str = "127.0.0.1:80"
1053    cmd_line_settable = True
1054
1055    @classmethod
1056    def cxx_predecls(cls, code):
1057        code('#include "base/inet.hh"')
1058
1059    def __init__(self, *args, **kwargs):
1060        def handle_kwarg(self, kwargs, key, elseVal = None):
1061            if key in kwargs:
1062                setattr(self, key, kwargs.pop(key))
1063            elif elseVal:
1064                setattr(self, key, elseVal)
1065            else:
1066                raise TypeError, "No value set for %s" % key
1067
1068        if len(args) == 0:
1069            handle_kwarg(self, kwargs, 'ip')
1070            handle_kwarg(self, kwargs, 'port')
1071
1072        elif len(args) == 1:
1073            if kwargs:
1074                if not 'ip' in kwargs and not 'port' in kwargs:
1075                    raise TypeError, "Invalid arguments"
1076                handle_kwarg(self, kwargs, 'ip', args[0])
1077                handle_kwarg(self, kwargs, 'port', args[0])
1078            elif isinstance(args[0], IpWithPort):
1079                self.ip = args[0].ip
1080                self.port = args[0].port
1081            else:
1082                (self.ip, self.port) = convert.toIpWithPort(args[0])
1083
1084        elif len(args) == 2:
1085            self.ip = args[0]
1086            self.port = args[1]
1087        else:
1088            raise TypeError, "Too many arguments specified"
1089
1090        if kwargs:
1091            raise TypeError, "Too many keywords: %s" % kwargs.keys()
1092
1093        self.verify()
1094
1095    def __call__(self, value):
1096        self.__init__(value)
1097        return value
1098
1099    def __str__(self):
1100        return "%s:%d" % (super(IpWithPort, self).__str__(), self.port)
1101
1102    def __eq__(self, other):
1103        if isinstance(other, IpWithPort):
1104            return self.ip == other.ip and self.port == other.port
1105        elif isinstance(other, str):
1106            try:
1107                return (self.ip, self.port) == convert.toIpWithPort(other)
1108            except:
1109                return False
1110        else:
1111            return False
1112
1113    def verify(self):
1114        self.verifyIp()
1115        if self.port < 0 or self.port > 0xffff:
1116            raise TypeError, "invalid port %d" % self.port
1117
1118    def getValue(self):
1119        from _m5.net import IpWithPort
1120        return IpWithPort(self.ip, self.port)
1121
1122time_formats = [ "%a %b %d %H:%M:%S %Z %Y",
1123                 "%a %b %d %H:%M:%S %Y",
1124                 "%Y/%m/%d %H:%M:%S",
1125                 "%Y/%m/%d %H:%M",
1126                 "%Y/%m/%d",
1127                 "%m/%d/%Y %H:%M:%S",
1128                 "%m/%d/%Y %H:%M",
1129                 "%m/%d/%Y",
1130                 "%m/%d/%y %H:%M:%S",
1131                 "%m/%d/%y %H:%M",
1132                 "%m/%d/%y"]
1133
1134
1135def parse_time(value):
1136    from time import gmtime, strptime, struct_time, time
1137    from datetime import datetime, date
1138
1139    if isinstance(value, struct_time):
1140        return value
1141
1142    if isinstance(value, (int, long)):
1143        return gmtime(value)
1144
1145    if isinstance(value, (datetime, date)):
1146        return value.timetuple()
1147
1148    if isinstance(value, str):
1149        if value in ('Now', 'Today'):
1150            return time.gmtime(time.time())
1151
1152        for format in time_formats:
1153            try:
1154                return strptime(value, format)
1155            except ValueError:
1156                pass
1157
1158    raise ValueError, "Could not parse '%s' as a time" % value
1159
1160class Time(ParamValue):
1161    cxx_type = 'tm'
1162
1163    @classmethod
1164    def cxx_predecls(cls, code):
1165        code('#include <time.h>')
1166
1167    def __init__(self, value):
1168        self.value = parse_time(value)
1169
1170    def __call__(self, value):
1171        self.__init__(value)
1172        return value
1173
1174    def getValue(self):
1175        from _m5.core import tm
1176        import calendar
1177
1178        return tm.gmtime(calendar.timegm(self.value))
1179
1180    def __str__(self):
1181        return time.asctime(self.value)
1182
1183    def ini_str(self):
1184        return str(self)
1185
1186    def get_config_as_dict(self):
1187        assert false
1188        return str(self)
1189
1190    @classmethod
1191    def cxx_ini_predecls(cls, code):
1192        code('#include <time.h>')
1193
1194    @classmethod
1195    def cxx_ini_parse(cls, code, src, dest, ret):
1196        code('char *_parse_ret = strptime((${src}).c_str(),')
1197        code('    "%a %b %d %H:%M:%S %Y", &(${dest}));')
1198        code('${ret} _parse_ret && *_parse_ret == \'\\0\';');
1199
1200# Enumerated types are a little more complex.  The user specifies the
1201# type as Enum(foo) where foo is either a list or dictionary of
1202# alternatives (typically strings, but not necessarily so).  (In the
1203# long run, the integer value of the parameter will be the list index
1204# or the corresponding dictionary value.  For now, since we only check
1205# that the alternative is valid and then spit it into a .ini file,
1206# there's not much point in using the dictionary.)
1207
1208# What Enum() must do is generate a new type encapsulating the
1209# provided list/dictionary so that specific values of the parameter
1210# can be instances of that type.  We define two hidden internal
1211# classes (_ListEnum and _DictEnum) to serve as base classes, then
1212# derive the new type from the appropriate base class on the fly.
1213
1214allEnums = {}
1215# Metaclass for Enum types
1216class MetaEnum(MetaParamValue):
1217    def __new__(mcls, name, bases, dict):
1218        assert name not in allEnums
1219
1220        cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict)
1221        allEnums[name] = cls
1222        return cls
1223
1224    def __init__(cls, name, bases, init_dict):
1225        if init_dict.has_key('map'):
1226            if not isinstance(cls.map, dict):
1227                raise TypeError, "Enum-derived class attribute 'map' " \
1228                      "must be of type dict"
1229            # build list of value strings from map
1230            cls.vals = cls.map.keys()
1231            cls.vals.sort()
1232        elif init_dict.has_key('vals'):
1233            if not isinstance(cls.vals, list):
1234                raise TypeError, "Enum-derived class attribute 'vals' " \
1235                      "must be of type list"
1236            # build string->value map from vals sequence
1237            cls.map = {}
1238            for idx,val in enumerate(cls.vals):
1239                cls.map[val] = idx
1240        else:
1241            raise TypeError, "Enum-derived class must define "\
1242                  "attribute 'map' or 'vals'"
1243
1244        cls.cxx_type = 'Enums::%s' % name
1245
1246        super(MetaEnum, cls).__init__(name, bases, init_dict)
1247
1248    # Generate C++ class declaration for this enum type.
1249    # Note that we wrap the enum in a class/struct to act as a namespace,
1250    # so that the enum strings can be brief w/o worrying about collisions.
1251    def cxx_decl(cls, code):
1252        wrapper_name = cls.wrapper_name
1253        wrapper = 'struct' if cls.wrapper_is_struct else 'namespace'
1254        name = cls.__name__ if cls.enum_name is None else cls.enum_name
1255        idem_macro = '__ENUM__%s__%s__' % (wrapper_name, name)
1256
1257        code('''\
1258#ifndef $idem_macro
1259#define $idem_macro
1260
1261$wrapper $wrapper_name {
1262    enum $name {
1263''')
1264        code.indent(2)
1265        for val in cls.vals:
1266            code('$val = ${{cls.map[val]}},')
1267        code('Num_$name = ${{len(cls.vals)}}')
1268        code.dedent(2)
1269        code('    };')
1270
1271        if cls.wrapper_is_struct:
1272            code('    static const char *${name}Strings[Num_${name}];')
1273            code('};')
1274        else:
1275            code('extern const char *${name}Strings[Num_${name}];')
1276            code('}')
1277
1278        code()
1279        code('#endif // $idem_macro')
1280
1281    def cxx_def(cls, code):
1282        wrapper_name = cls.wrapper_name
1283        file_name = cls.__name__
1284        name = cls.__name__ if cls.enum_name is None else cls.enum_name
1285
1286        code('#include "enums/$file_name.hh"')
1287        if cls.wrapper_is_struct:
1288            code('const char *${wrapper_name}::${name}Strings'
1289                '[Num_${name}] =')
1290        else:
1291            code('namespace Enums {')
1292            code.indent(1)
1293            code(' const char *${name}Strings[Num_${name}] =')
1294
1295        code('{')
1296        code.indent(1)
1297        for val in cls.vals:
1298            code('"$val",')
1299        code.dedent(1)
1300        code('};')
1301
1302        if not cls.wrapper_is_struct:
1303            code('} // namespace $wrapper_name')
1304            code.dedent(1)
1305
1306    def pybind_def(cls, code):
1307        name = cls.__name__
1308        wrapper_name = cls.wrapper_name
1309        enum_name = cls.__name__ if cls.enum_name is None else cls.enum_name
1310
1311        code('''#include "pybind11/pybind11.h"
1312#include "pybind11/stl.h"
1313
1314#include <sim/init.hh>
1315
1316namespace py = pybind11;
1317
1318static void
1319module_init(py::module &m_internal)
1320{
1321    py::module m = m_internal.def_submodule("enum_${name}");
1322
1323    py::enum_<${wrapper_name}::${enum_name}>(m, "enum_${name}")
1324''')
1325
1326        code.indent()
1327        code.indent()
1328        for val in cls.vals:
1329            code('.value("${val}", ${wrapper_name}::${val})')
1330        code('.value("Num_${name}", ${wrapper_name}::Num_${enum_name})')
1331        code('.export_values()')
1332        code(';')
1333        code.dedent()
1334
1335        code('}')
1336        code.dedent()
1337        code()
1338        code('static EmbeddedPyBind embed_enum("enum_${name}", module_init);')
1339
1340
1341# Base class for enum types.
1342class Enum(ParamValue):
1343    __metaclass__ = MetaEnum
1344    vals = []
1345    cmd_line_settable = True
1346
1347    # The name of the wrapping namespace or struct
1348    wrapper_name = 'Enums'
1349
1350    # If true, the enum is wrapped in a struct rather than a namespace
1351    wrapper_is_struct = False
1352
1353    # If not None, use this as the enum name rather than this class name
1354    enum_name = None
1355
1356    def __init__(self, value):
1357        if value not in self.map:
1358            raise TypeError, "Enum param got bad value '%s' (not in %s)" \
1359                  % (value, self.vals)
1360        self.value = value
1361
1362    def __call__(self, value):
1363        self.__init__(value)
1364        return value
1365
1366    @classmethod
1367    def cxx_predecls(cls, code):
1368        code('#include "enums/$0.hh"', cls.__name__)
1369
1370    @classmethod
1371    def cxx_ini_parse(cls, code, src, dest, ret):
1372        code('if (false) {')
1373        for elem_name in cls.map.iterkeys():
1374            code('} else if (%s == "%s") {' % (src, elem_name))
1375            code.indent()
1376            code('%s = Enums::%s;' % (dest, elem_name))
1377            code('%s true;' % ret)
1378            code.dedent()
1379        code('} else {')
1380        code('    %s false;' % ret)
1381        code('}')
1382
1383    def getValue(self):
1384        import m5.internal.params
1385        e = getattr(m5.internal.params, "enum_%s" % self.__class__.__name__)
1386        return e(self.map[self.value])
1387
1388    def __str__(self):
1389        return self.value
1390
1391# how big does a rounding error need to be before we warn about it?
1392frequency_tolerance = 0.001  # 0.1%
1393
1394class TickParamValue(NumericParamValue):
1395    cxx_type = 'Tick'
1396    ex_str = "1MHz"
1397    cmd_line_settable = True
1398
1399    @classmethod
1400    def cxx_predecls(cls, code):
1401        code('#include "base/types.hh"')
1402
1403    def __call__(self, value):
1404        self.__init__(value)
1405        return value
1406
1407    def getValue(self):
1408        return long(self.value)
1409
1410    @classmethod
1411    def cxx_ini_predecls(cls, code):
1412        code('#include <sstream>')
1413
1414    # Ticks are expressed in seconds in JSON files and in plain
1415    # Ticks in .ini files.  Switch based on a config flag
1416    @classmethod
1417    def cxx_ini_parse(self, code, src, dest, ret):
1418        code('${ret} to_number(${src}, ${dest});')
1419
1420class Latency(TickParamValue):
1421    ex_str = "100ns"
1422
1423    def __init__(self, value):
1424        if isinstance(value, (Latency, Clock)):
1425            self.ticks = value.ticks
1426            self.value = value.value
1427        elif isinstance(value, Frequency):
1428            self.ticks = value.ticks
1429            self.value = 1.0 / value.value
1430        elif value.endswith('t'):
1431            self.ticks = True
1432            self.value = int(value[:-1])
1433        else:
1434            self.ticks = False
1435            self.value = convert.toLatency(value)
1436
1437    def __call__(self, value):
1438        self.__init__(value)
1439        return value
1440
1441    def __getattr__(self, attr):
1442        if attr in ('latency', 'period'):
1443            return self
1444        if attr == 'frequency':
1445            return Frequency(self)
1446        raise AttributeError, "Latency object has no attribute '%s'" % attr
1447
1448    def getValue(self):
1449        if self.ticks or self.value == 0:
1450            value = self.value
1451        else:
1452            value = ticks.fromSeconds(self.value)
1453        return long(value)
1454
1455    def config_value(self):
1456        return self.getValue()
1457
1458    # convert latency to ticks
1459    def ini_str(self):
1460        return '%d' % self.getValue()
1461
1462class Frequency(TickParamValue):
1463    ex_str = "1GHz"
1464
1465    def __init__(self, value):
1466        if isinstance(value, (Latency, Clock)):
1467            if value.value == 0:
1468                self.value = 0
1469            else:
1470                self.value = 1.0 / value.value
1471            self.ticks = value.ticks
1472        elif isinstance(value, Frequency):
1473            self.value = value.value
1474            self.ticks = value.ticks
1475        else:
1476            self.ticks = False
1477            self.value = convert.toFrequency(value)
1478
1479    def __call__(self, value):
1480        self.__init__(value)
1481        return value
1482
1483    def __getattr__(self, attr):
1484        if attr == 'frequency':
1485            return self
1486        if attr in ('latency', 'period'):
1487            return Latency(self)
1488        raise AttributeError, "Frequency object has no attribute '%s'" % attr
1489
1490    # convert latency to ticks
1491    def getValue(self):
1492        if self.ticks or self.value == 0:
1493            value = self.value
1494        else:
1495            value = ticks.fromSeconds(1.0 / self.value)
1496        return long(value)
1497
1498    def config_value(self):
1499        return self.getValue()
1500
1501    def ini_str(self):
1502        return '%d' % self.getValue()
1503
1504# A generic Frequency and/or Latency value. Value is stored as a
1505# latency, just like Latency and Frequency.
1506class Clock(TickParamValue):
1507    def __init__(self, value):
1508        if isinstance(value, (Latency, Clock)):
1509            self.ticks = value.ticks
1510            self.value = value.value
1511        elif isinstance(value, Frequency):
1512            self.ticks = value.ticks
1513            self.value = 1.0 / value.value
1514        elif value.endswith('t'):
1515            self.ticks = True
1516            self.value = int(value[:-1])
1517        else:
1518            self.ticks = False
1519            self.value = convert.anyToLatency(value)
1520
1521    def __call__(self, value):
1522        self.__init__(value)
1523        return value
1524
1525    def __str__(self):
1526        return "%s" % Latency(self)
1527
1528    def __getattr__(self, attr):
1529        if attr == 'frequency':
1530            return Frequency(self)
1531        if attr in ('latency', 'period'):
1532            return Latency(self)
1533        raise AttributeError, "Frequency object has no attribute '%s'" % attr
1534
1535    def getValue(self):
1536        return self.period.getValue()
1537
1538    def config_value(self):
1539        return self.period.config_value()
1540
1541    def ini_str(self):
1542        return self.period.ini_str()
1543
1544class Voltage(float,ParamValue):
1545    cxx_type = 'double'
1546    ex_str = "1V"
1547    cmd_line_settable = True
1548
1549    def __new__(cls, value):
1550        # convert to voltage
1551        val = convert.toVoltage(value)
1552        return super(cls, Voltage).__new__(cls, val)
1553
1554    def __call__(self, value):
1555        val = convert.toVoltage(value)
1556        self.__init__(val)
1557        return value
1558
1559    def __str__(self):
1560        return str(self.getValue())
1561
1562    def getValue(self):
1563        value = float(self)
1564        return value
1565
1566    def ini_str(self):
1567        return '%f' % self.getValue()
1568
1569    @classmethod
1570    def cxx_ini_predecls(cls, code):
1571        code('#include <sstream>')
1572
1573    @classmethod
1574    def cxx_ini_parse(self, code, src, dest, ret):
1575        code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
1576
1577class Current(float, ParamValue):
1578    cxx_type = 'double'
1579    ex_str = "1mA"
1580    cmd_line_settable = False
1581
1582    def __new__(cls, value):
1583        # convert to current
1584        val = convert.toCurrent(value)
1585        return super(cls, Current).__new__(cls, val)
1586
1587    def __call__(self, value):
1588        val = convert.toCurrent(value)
1589        self.__init__(val)
1590        return value
1591
1592    def __str__(self):
1593        return str(self.getValue())
1594
1595    def getValue(self):
1596        value = float(self)
1597        return value
1598
1599    def ini_str(self):
1600        return '%f' % self.getValue()
1601
1602    @classmethod
1603    def cxx_ini_predecls(cls, code):
1604        code('#include <sstream>')
1605
1606    @classmethod
1607    def cxx_ini_parse(self, code, src, dest, ret):
1608        code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
1609
1610class NetworkBandwidth(float,ParamValue):
1611    cxx_type = 'float'
1612    ex_str = "1Gbps"
1613    cmd_line_settable = True
1614
1615    def __new__(cls, value):
1616        # convert to bits per second
1617        val = convert.toNetworkBandwidth(value)
1618        return super(cls, NetworkBandwidth).__new__(cls, val)
1619
1620    def __str__(self):
1621        return str(self.val)
1622
1623    def __call__(self, value):
1624        val = convert.toNetworkBandwidth(value)
1625        self.__init__(val)
1626        return value
1627
1628    def getValue(self):
1629        # convert to seconds per byte
1630        value = 8.0 / float(self)
1631        # convert to ticks per byte
1632        value = ticks.fromSeconds(value)
1633        return float(value)
1634
1635    def ini_str(self):
1636        return '%f' % self.getValue()
1637
1638    def config_value(self):
1639        return '%f' % self.getValue()
1640
1641    @classmethod
1642    def cxx_ini_predecls(cls, code):
1643        code('#include <sstream>')
1644
1645    @classmethod
1646    def cxx_ini_parse(self, code, src, dest, ret):
1647        code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
1648
1649class MemoryBandwidth(float,ParamValue):
1650    cxx_type = 'float'
1651    ex_str = "1GB/s"
1652    cmd_line_settable = True
1653
1654    def __new__(cls, value):
1655        # convert to bytes per second
1656        val = convert.toMemoryBandwidth(value)
1657        return super(cls, MemoryBandwidth).__new__(cls, val)
1658
1659    def __call__(self, value):
1660        val = convert.toMemoryBandwidth(value)
1661        self.__init__(val)
1662        return value
1663
1664    def getValue(self):
1665        # convert to seconds per byte
1666        value = float(self)
1667        if value:
1668            value = 1.0 / float(self)
1669        # convert to ticks per byte
1670        value = ticks.fromSeconds(value)
1671        return float(value)
1672
1673    def ini_str(self):
1674        return '%f' % self.getValue()
1675
1676    def config_value(self):
1677        return '%f' % self.getValue()
1678
1679    @classmethod
1680    def cxx_ini_predecls(cls, code):
1681        code('#include <sstream>')
1682
1683    @classmethod
1684    def cxx_ini_parse(self, code, src, dest, ret):
1685        code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
1686
1687#
1688# "Constants"... handy aliases for various values.
1689#
1690
1691# Special class for NULL pointers.  Note the special check in
1692# make_param_value() above that lets these be assigned where a
1693# SimObject is required.
1694# only one copy of a particular node
1695class NullSimObject(object):
1696    __metaclass__ = Singleton
1697    _name = 'Null'
1698
1699    def __call__(cls):
1700        return cls
1701
1702    def _instantiate(self, parent = None, path = ''):
1703        pass
1704
1705    def ini_str(self):
1706        return 'Null'
1707
1708    def unproxy(self, base):
1709        return self
1710
1711    def set_path(self, parent, name):
1712        pass
1713
1714    def set_parent(self, parent, name):
1715        pass
1716
1717    def clear_parent(self, old_parent):
1718        pass
1719
1720    def descendants(self):
1721        return
1722        yield None
1723
1724    def get_config_as_dict(self):
1725        return {}
1726
1727    def __str__(self):
1728        return self._name
1729
1730    def config_value(self):
1731        return None
1732
1733    def getValue(self):
1734        return None
1735
1736# The only instance you'll ever need...
1737NULL = NullSimObject()
1738
1739def isNullPointer(value):
1740    return isinstance(value, NullSimObject)
1741
1742# Some memory range specifications use this as a default upper bound.
1743MaxAddr = Addr.max
1744MaxTick = Tick.max
1745AllMemory = AddrRange(0, MaxAddr)
1746
1747
1748#####################################################################
1749#
1750# Port objects
1751#
1752# Ports are used to interconnect objects in the memory system.
1753#
1754#####################################################################
1755
1756# Port reference: encapsulates a reference to a particular port on a
1757# particular SimObject.
1758class PortRef(object):
1759    def __init__(self, simobj, name, role):
1760        assert(isSimObject(simobj) or isSimObjectClass(simobj))
1761        self.simobj = simobj
1762        self.name = name
1763        self.role = role
1764        self.peer = None   # not associated with another port yet
1765        self.ccConnected = False # C++ port connection done?
1766        self.index = -1  # always -1 for non-vector ports
1767
1768    def __str__(self):
1769        return '%s.%s' % (self.simobj, self.name)
1770
1771    def __len__(self):
1772        # Return the number of connected ports, i.e. 0 is we have no
1773        # peer and 1 if we do.
1774        return int(self.peer != None)
1775
1776    # for config.ini, print peer's name (not ours)
1777    def ini_str(self):
1778        return str(self.peer)
1779
1780    # for config.json
1781    def get_config_as_dict(self):
1782        return {'role' : self.role, 'peer' : str(self.peer)}
1783
1784    def __getattr__(self, attr):
1785        if attr == 'peerObj':
1786            # shorthand for proxies
1787            return self.peer.simobj
1788        raise AttributeError, "'%s' object has no attribute '%s'" % \
1789              (self.__class__.__name__, attr)
1790
1791    # Full connection is symmetric (both ways).  Called via
1792    # SimObject.__setattr__ as a result of a port assignment, e.g.,
1793    # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
1794    # e.g., "obj1.portA[3] = obj2.portB".
1795    def connect(self, other):
1796        if isinstance(other, VectorPortRef):
1797            # reference to plain VectorPort is implicit append
1798            other = other._get_next()
1799        if self.peer and not proxy.isproxy(self.peer):
1800            fatal("Port %s is already connected to %s, cannot connect %s\n",
1801                  self, self.peer, other);
1802        self.peer = other
1803        if proxy.isproxy(other):
1804            other.set_param_desc(PortParamDesc())
1805        elif isinstance(other, PortRef):
1806            if other.peer is not self:
1807                other.connect(self)
1808        else:
1809            raise TypeError, \
1810                  "assigning non-port reference '%s' to port '%s'" \
1811                  % (other, self)
1812
1813    # Allow a master/slave port pair to be spliced between
1814    # a port and its connected peer. Useful operation for connecting
1815    # instrumentation structures into a system when it is necessary
1816    # to connect the instrumentation after the full system has been
1817    # constructed.
1818    def splice(self, new_master_peer, new_slave_peer):
1819        if self.peer and not proxy.isproxy(self.peer):
1820            if isinstance(new_master_peer, PortRef) and \
1821               isinstance(new_slave_peer, PortRef):
1822                 old_peer = self.peer
1823                 if self.role == 'SLAVE':
1824                     self.peer = new_master_peer
1825                     old_peer.peer = new_slave_peer
1826                     new_master_peer.connect(self)
1827                     new_slave_peer.connect(old_peer)
1828                 elif self.role == 'MASTER':
1829                     self.peer = new_slave_peer
1830                     old_peer.peer = new_master_peer
1831                     new_slave_peer.connect(self)
1832                     new_master_peer.connect(old_peer)
1833                 else:
1834                     panic("Port %s has unknown role, "+\
1835                           "cannot splice in new peers\n", self)
1836            else:
1837                raise TypeError, \
1838                      "Splicing non-port references '%s','%s' to port '%s'"\
1839                      % (new_peer, peers_new_peer, self)
1840        else:
1841            fatal("Port %s not connected, cannot splice in new peers\n", self)
1842
1843    def clone(self, simobj, memo):
1844        if memo.has_key(self):
1845            return memo[self]
1846        newRef = copy.copy(self)
1847        memo[self] = newRef
1848        newRef.simobj = simobj
1849        assert(isSimObject(newRef.simobj))
1850        if self.peer and not proxy.isproxy(self.peer):
1851            peerObj = self.peer.simobj(_memo=memo)
1852            newRef.peer = self.peer.clone(peerObj, memo)
1853            assert(not isinstance(newRef.peer, VectorPortRef))
1854        return newRef
1855
1856    def unproxy(self, simobj):
1857        assert(simobj is self.simobj)
1858        if proxy.isproxy(self.peer):
1859            try:
1860                realPeer = self.peer.unproxy(self.simobj)
1861            except:
1862                print "Error in unproxying port '%s' of %s" % \
1863                      (self.name, self.simobj.path())
1864                raise
1865            self.connect(realPeer)
1866
1867    # Call C++ to create corresponding port connection between C++ objects
1868    def ccConnect(self):
1869        from _m5.pyobject import connectPorts
1870
1871        if self.role == 'SLAVE':
1872            # do nothing and let the master take care of it
1873            return
1874
1875        if self.ccConnected: # already done this
1876            return
1877        peer = self.peer
1878        if not self.peer: # nothing to connect to
1879            return
1880
1881        # check that we connect a master to a slave
1882        if self.role == peer.role:
1883            raise TypeError, \
1884                "cannot connect '%s' and '%s' due to identical role '%s'" \
1885                % (peer, self, self.role)
1886
1887        try:
1888            # self is always the master and peer the slave
1889            connectPorts(self.simobj.getCCObject(), self.name, self.index,
1890                         peer.simobj.getCCObject(), peer.name, peer.index)
1891        except:
1892            print "Error connecting port %s.%s to %s.%s" % \
1893                  (self.simobj.path(), self.name,
1894                   peer.simobj.path(), peer.name)
1895            raise
1896        self.ccConnected = True
1897        peer.ccConnected = True
1898
1899# A reference to an individual element of a VectorPort... much like a
1900# PortRef, but has an index.
1901class VectorPortElementRef(PortRef):
1902    def __init__(self, simobj, name, role, index):
1903        PortRef.__init__(self, simobj, name, role)
1904        self.index = index
1905
1906    def __str__(self):
1907        return '%s.%s[%d]' % (self.simobj, self.name, self.index)
1908
1909# A reference to a complete vector-valued port (not just a single element).
1910# Can be indexed to retrieve individual VectorPortElementRef instances.
1911class VectorPortRef(object):
1912    def __init__(self, simobj, name, role):
1913        assert(isSimObject(simobj) or isSimObjectClass(simobj))
1914        self.simobj = simobj
1915        self.name = name
1916        self.role = role
1917        self.elements = []
1918
1919    def __str__(self):
1920        return '%s.%s[:]' % (self.simobj, self.name)
1921
1922    def __len__(self):
1923        # Return the number of connected peers, corresponding the the
1924        # length of the elements.
1925        return len(self.elements)
1926
1927    # for config.ini, print peer's name (not ours)
1928    def ini_str(self):
1929        return ' '.join([el.ini_str() for el in self.elements])
1930
1931    # for config.json
1932    def get_config_as_dict(self):
1933        return {'role' : self.role,
1934                'peer' : [el.ini_str() for el in self.elements]}
1935
1936    def __getitem__(self, key):
1937        if not isinstance(key, int):
1938            raise TypeError, "VectorPort index must be integer"
1939        if key >= len(self.elements):
1940            # need to extend list
1941            ext = [VectorPortElementRef(self.simobj, self.name, self.role, i)
1942                   for i in range(len(self.elements), key+1)]
1943            self.elements.extend(ext)
1944        return self.elements[key]
1945
1946    def _get_next(self):
1947        return self[len(self.elements)]
1948
1949    def __setitem__(self, key, value):
1950        if not isinstance(key, int):
1951            raise TypeError, "VectorPort index must be integer"
1952        self[key].connect(value)
1953
1954    def connect(self, other):
1955        if isinstance(other, (list, tuple)):
1956            # Assign list of port refs to vector port.
1957            # For now, append them... not sure if that's the right semantics
1958            # or if it should replace the current vector.
1959            for ref in other:
1960                self._get_next().connect(ref)
1961        else:
1962            # scalar assignment to plain VectorPort is implicit append
1963            self._get_next().connect(other)
1964
1965    def clone(self, simobj, memo):
1966        if memo.has_key(self):
1967            return memo[self]
1968        newRef = copy.copy(self)
1969        memo[self] = newRef
1970        newRef.simobj = simobj
1971        assert(isSimObject(newRef.simobj))
1972        newRef.elements = [el.clone(simobj, memo) for el in self.elements]
1973        return newRef
1974
1975    def unproxy(self, simobj):
1976        [el.unproxy(simobj) for el in self.elements]
1977
1978    def ccConnect(self):
1979        [el.ccConnect() for el in self.elements]
1980
1981# Port description object.  Like a ParamDesc object, this represents a
1982# logical port in the SimObject class, not a particular port on a
1983# SimObject instance.  The latter are represented by PortRef objects.
1984class Port(object):
1985    # Generate a PortRef for this port on the given SimObject with the
1986    # given name
1987    def makeRef(self, simobj):
1988        return PortRef(simobj, self.name, self.role)
1989
1990    # Connect an instance of this port (on the given SimObject with
1991    # the given name) with the port described by the supplied PortRef
1992    def connect(self, simobj, ref):
1993        self.makeRef(simobj).connect(ref)
1994
1995    # No need for any pre-declarations at the moment as we merely rely
1996    # on an unsigned int.
1997    def cxx_predecls(self, code):
1998        pass
1999
2000    def pybind_predecls(self, code):
2001        cls.cxx_predecls(self, code)
2002
2003    # Declare an unsigned int with the same name as the port, that
2004    # will eventually hold the number of connected ports (and thus the
2005    # number of elements for a VectorPort).
2006    def cxx_decl(self, code):
2007        code('unsigned int port_${{self.name}}_connection_count;')
2008
2009class MasterPort(Port):
2010    # MasterPort("description")
2011    def __init__(self, *args):
2012        if len(args) == 1:
2013            self.desc = args[0]
2014            self.role = 'MASTER'
2015        else:
2016            raise TypeError, 'wrong number of arguments'
2017
2018class SlavePort(Port):
2019    # SlavePort("description")
2020    def __init__(self, *args):
2021        if len(args) == 1:
2022            self.desc = args[0]
2023            self.role = 'SLAVE'
2024        else:
2025            raise TypeError, 'wrong number of arguments'
2026
2027# VectorPort description object.  Like Port, but represents a vector
2028# of connections (e.g., as on a XBar).
2029class VectorPort(Port):
2030    def __init__(self, *args):
2031        self.isVec = True
2032
2033    def makeRef(self, simobj):
2034        return VectorPortRef(simobj, self.name, self.role)
2035
2036class VectorMasterPort(VectorPort):
2037    # VectorMasterPort("description")
2038    def __init__(self, *args):
2039        if len(args) == 1:
2040            self.desc = args[0]
2041            self.role = 'MASTER'
2042            VectorPort.__init__(self, *args)
2043        else:
2044            raise TypeError, 'wrong number of arguments'
2045
2046class VectorSlavePort(VectorPort):
2047    # VectorSlavePort("description")
2048    def __init__(self, *args):
2049        if len(args) == 1:
2050            self.desc = args[0]
2051            self.role = 'SLAVE'
2052            VectorPort.__init__(self, *args)
2053        else:
2054            raise TypeError, 'wrong number of arguments'
2055
2056# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
2057# proxy objects (via set_param_desc()) so that proxy error messages
2058# make sense.
2059class PortParamDesc(object):
2060    __metaclass__ = Singleton
2061
2062    ptype_str = 'Port'
2063    ptype = Port
2064
2065baseEnums = allEnums.copy()
2066baseParams = allParams.copy()
2067
2068def clear():
2069    global allEnums, allParams
2070
2071    allEnums = baseEnums.copy()
2072    allParams = baseParams.copy()
2073
2074__all__ = ['Param', 'VectorParam',
2075           'Enum', 'Bool', 'String', 'Float',
2076           'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
2077           'Int32', 'UInt32', 'Int64', 'UInt64',
2078           'Counter', 'Addr', 'Tick', 'Percent',
2079           'TcpPort', 'UdpPort', 'EthernetAddr',
2080           'IpAddress', 'IpNetmask', 'IpWithPort',
2081           'MemorySize', 'MemorySize32',
2082           'Latency', 'Frequency', 'Clock', 'Voltage',
2083           'NetworkBandwidth', 'MemoryBandwidth',
2084           'AddrRange',
2085           'MaxAddr', 'MaxTick', 'AllMemory',
2086           'Time',
2087           'NextEthernetAddr', 'NULL',
2088           'MasterPort', 'SlavePort',
2089           'VectorMasterPort', 'VectorSlavePort']
2090
2091import SimObject
2092