params.py revision 13699
13101Sstever@eecs.umich.edu# Copyright (c) 2012-2014, 2017, 2018 ARM Limited
23101Sstever@eecs.umich.edu# All rights reserved.
33101Sstever@eecs.umich.edu#
43101Sstever@eecs.umich.edu# The license below extends only to copyright in the software and shall
53101Sstever@eecs.umich.edu# not be construed as granting a license to any other intellectual
63101Sstever@eecs.umich.edu# property including but not limited to intellectual property relating
73101Sstever@eecs.umich.edu# to a hardware implementation of the functionality of the software
83101Sstever@eecs.umich.edu# licensed hereunder.  You may use the software subject to the license
93101Sstever@eecs.umich.edu# terms below provided that you ensure that this notice is replicated
103101Sstever@eecs.umich.edu# unmodified and in its entirety in all distributions of the software,
113101Sstever@eecs.umich.edu# modified or unmodified, in source code or in binary form.
123101Sstever@eecs.umich.edu#
133101Sstever@eecs.umich.edu# Copyright (c) 2004-2006 The Regents of The University of Michigan
143101Sstever@eecs.umich.edu# Copyright (c) 2010-2011 Advanced Micro Devices, Inc.
153101Sstever@eecs.umich.edu# All rights reserved.
163101Sstever@eecs.umich.edu#
173101Sstever@eecs.umich.edu# Redistribution and use in source and binary forms, with or without
183101Sstever@eecs.umich.edu# modification, are permitted provided that the following conditions are
193101Sstever@eecs.umich.edu# met: redistributions of source code must retain the above copyright
203101Sstever@eecs.umich.edu# notice, this list of conditions and the following disclaimer;
213101Sstever@eecs.umich.edu# redistributions in binary form must reproduce the above copyright
223101Sstever@eecs.umich.edu# notice, this list of conditions and the following disclaimer in the
233101Sstever@eecs.umich.edu# documentation and/or other materials provided with the distribution;
243101Sstever@eecs.umich.edu# neither the name of the copyright holders nor the names of its
253101Sstever@eecs.umich.edu# contributors may be used to endorse or promote products derived from
263101Sstever@eecs.umich.edu# this software without specific prior written permission.
273101Sstever@eecs.umich.edu#
283101Sstever@eecs.umich.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
293101Sstever@eecs.umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
303101Sstever@eecs.umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
313101Sstever@eecs.umich.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
323101Sstever@eecs.umich.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
333101Sstever@eecs.umich.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
343101Sstever@eecs.umich.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
353101Sstever@eecs.umich.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
363101Sstever@eecs.umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
373101Sstever@eecs.umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
383101Sstever@eecs.umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
393101Sstever@eecs.umich.edu#
403101Sstever@eecs.umich.edu# Authors: Steve Reinhardt
413101Sstever@eecs.umich.edu#          Nathan Binkert
423101Sstever@eecs.umich.edu#          Gabe Black
433101Sstever@eecs.umich.edu#          Andreas Hansson
443101Sstever@eecs.umich.edu
453101Sstever@eecs.umich.edu#####################################################################
463101Sstever@eecs.umich.edu#
473885Sbinkertn@umich.edu# Parameter description classes
483885Sbinkertn@umich.edu#
493885Sbinkertn@umich.edu# The _params dictionary in each class maps parameter names to either
503885Sbinkertn@umich.edu# a Param or a VectorParam object.  These objects contain the
513885Sbinkertn@umich.edu# parameter description string, the parameter type, and the default
523885Sbinkertn@umich.edu# value (if any).  The convert() method on these objects is used to
533101Sstever@eecs.umich.edu# force whatever value is assigned to the parameter to the appropriate
544380Sbinkertn@umich.edu# type.
554167Sbinkertn@umich.edu#
563102Sstever@eecs.umich.edu# Note that the default values are loaded into the class's attribute
573101Sstever@eecs.umich.edu# space when the parameter dictionary is initialized (in
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.edufrom __future__ import print_function
633101Sstever@eecs.umich.edu
643101Sstever@eecs.umich.eduimport copy
653101Sstever@eecs.umich.eduimport datetime
663101Sstever@eecs.umich.eduimport re
673101Sstever@eecs.umich.eduimport sys
683101Sstever@eecs.umich.eduimport time
693101Sstever@eecs.umich.eduimport math
703101Sstever@eecs.umich.edu
713101Sstever@eecs.umich.eduimport proxy
723101Sstever@eecs.umich.eduimport ticks
733101Sstever@eecs.umich.edufrom util import *
743101Sstever@eecs.umich.edu
753101Sstever@eecs.umich.edudef isSimObject(*args, **kwargs):
763101Sstever@eecs.umich.edu    return SimObject.isSimObject(*args, **kwargs)
773101Sstever@eecs.umich.edu
783101Sstever@eecs.umich.edudef isSimObjectSequence(*args, **kwargs):
793101Sstever@eecs.umich.edu    return SimObject.isSimObjectSequence(*args, **kwargs)
803101Sstever@eecs.umich.edu
813101Sstever@eecs.umich.edudef isSimObjectClass(*args, **kwargs):
823101Sstever@eecs.umich.edu    return SimObject.isSimObjectClass(*args, **kwargs)
833101Sstever@eecs.umich.edu
843101Sstever@eecs.umich.eduallParams = {}
853101Sstever@eecs.umich.edu
863101Sstever@eecs.umich.educlass MetaParamValue(type):
873101Sstever@eecs.umich.edu    def __new__(mcls, name, bases, dct):
883101Sstever@eecs.umich.edu        cls = super(MetaParamValue, mcls).__new__(mcls, name, bases, dct)
893101Sstever@eecs.umich.edu        assert name not in allParams
903101Sstever@eecs.umich.edu        allParams[name] = cls
913101Sstever@eecs.umich.edu        return cls
923101Sstever@eecs.umich.edu
933101Sstever@eecs.umich.edu
943101Sstever@eecs.umich.edu# Dummy base class to identify types that are legitimate for SimObject
953101Sstever@eecs.umich.edu# parameters.
963101Sstever@eecs.umich.educlass ParamValue(object):
973101Sstever@eecs.umich.edu    __metaclass__ = MetaParamValue
983101Sstever@eecs.umich.edu    cmd_line_settable = False
993101Sstever@eecs.umich.edu
1003101Sstever@eecs.umich.edu    # Generate the code needed as a prerequisite for declaring a C++
1013101Sstever@eecs.umich.edu    # object of this type.  Typically generates one or more #include
1023101Sstever@eecs.umich.edu    # statements.  Used when declaring parameters of this type.
1033101Sstever@eecs.umich.edu    @classmethod
1043101Sstever@eecs.umich.edu    def cxx_predecls(cls, code):
1053101Sstever@eecs.umich.edu        pass
1063101Sstever@eecs.umich.edu
1073101Sstever@eecs.umich.edu    @classmethod
1083101Sstever@eecs.umich.edu    def pybind_predecls(cls, code):
1093101Sstever@eecs.umich.edu        cls.cxx_predecls(code)
1103101Sstever@eecs.umich.edu
1113102Sstever@eecs.umich.edu    # default for printing to .ini file is regular string conversion.
1123101Sstever@eecs.umich.edu    # will be overridden in some cases
1133102Sstever@eecs.umich.edu    def ini_str(self):
1143101Sstever@eecs.umich.edu        return str(self)
1153101Sstever@eecs.umich.edu
1163101Sstever@eecs.umich.edu    # default for printing to .json file is regular string conversion.
1173102Sstever@eecs.umich.edu    # will be overridden in some cases, mostly to use native Python
1183102Sstever@eecs.umich.edu    # types where there are similar JSON types
1193101Sstever@eecs.umich.edu    def config_value(self):
1203101Sstever@eecs.umich.edu        return str(self)
1213101Sstever@eecs.umich.edu
1223101Sstever@eecs.umich.edu    # Prerequisites for .ini parsing with cxx_ini_parse
1233101Sstever@eecs.umich.edu    @classmethod
1243101Sstever@eecs.umich.edu    def cxx_ini_predecls(cls, code):
1253101Sstever@eecs.umich.edu        pass
1263101Sstever@eecs.umich.edu
1273101Sstever@eecs.umich.edu    # parse a .ini file entry for this param from string expression
1283101Sstever@eecs.umich.edu    # src into lvalue dest (of the param's C++ type)
1293101Sstever@eecs.umich.edu    @classmethod
1303101Sstever@eecs.umich.edu    def cxx_ini_parse(cls, code, src, dest, ret):
1313101Sstever@eecs.umich.edu        code('// Unhandled param type: %s' % cls.__name__)
1323102Sstever@eecs.umich.edu        code('%s false;' % ret)
1333101Sstever@eecs.umich.edu
1343101Sstever@eecs.umich.edu    # allows us to blithely call unproxy() on things without checking
1353101Sstever@eecs.umich.edu    # if they're really proxies or not
1363101Sstever@eecs.umich.edu    def unproxy(self, base):
1373101Sstever@eecs.umich.edu        return self
1383101Sstever@eecs.umich.edu
1393101Sstever@eecs.umich.edu    # Produce a human readable version of the stored value
1403101Sstever@eecs.umich.edu    def pretty_print(self, value):
1413101Sstever@eecs.umich.edu        return str(value)
1423101Sstever@eecs.umich.edu
1433101Sstever@eecs.umich.edu# Regular parameter description.
1443101Sstever@eecs.umich.educlass ParamDesc(object):
1453101Sstever@eecs.umich.edu    def __init__(self, ptype_str, ptype, *args, **kwargs):
1463101Sstever@eecs.umich.edu        self.ptype_str = ptype_str
1473101Sstever@eecs.umich.edu        # remember ptype only if it is provided
1483101Sstever@eecs.umich.edu        if ptype != None:
1493101Sstever@eecs.umich.edu            self.ptype = ptype
1503101Sstever@eecs.umich.edu
1513101Sstever@eecs.umich.edu        if args:
1523101Sstever@eecs.umich.edu            if len(args) == 1:
1533101Sstever@eecs.umich.edu                self.desc = args[0]
1543101Sstever@eecs.umich.edu            elif len(args) == 2:
1553101Sstever@eecs.umich.edu                self.default = args[0]
1563101Sstever@eecs.umich.edu                self.desc = args[1]
1573101Sstever@eecs.umich.edu            else:
1583101Sstever@eecs.umich.edu                raise TypeError('too many arguments')
1593101Sstever@eecs.umich.edu
1603101Sstever@eecs.umich.edu        if 'desc' in kwargs:
1613101Sstever@eecs.umich.edu            assert(not hasattr(self, 'desc'))
1623101Sstever@eecs.umich.edu            self.desc = kwargs['desc']
1633101Sstever@eecs.umich.edu            del kwargs['desc']
1643101Sstever@eecs.umich.edu
1653101Sstever@eecs.umich.edu        if 'default' in kwargs:
1663101Sstever@eecs.umich.edu            assert(not hasattr(self, 'default'))
1673101Sstever@eecs.umich.edu            self.default = kwargs['default']
1683101Sstever@eecs.umich.edu            del kwargs['default']
1693101Sstever@eecs.umich.edu
1703101Sstever@eecs.umich.edu        if kwargs:
1713101Sstever@eecs.umich.edu            raise TypeError('extra unknown kwargs %s' % kwargs)
1723101Sstever@eecs.umich.edu
1733101Sstever@eecs.umich.edu        if not hasattr(self, 'desc'):
1743101Sstever@eecs.umich.edu            raise TypeError('desc attribute missing')
1753101Sstever@eecs.umich.edu
1763101Sstever@eecs.umich.edu    def __getattr__(self, attr):
1773101Sstever@eecs.umich.edu        if attr == 'ptype':
1783101Sstever@eecs.umich.edu            ptype = SimObject.allClasses[self.ptype_str]
1793101Sstever@eecs.umich.edu            assert isSimObjectClass(ptype)
1803101Sstever@eecs.umich.edu            self.ptype = ptype
1813101Sstever@eecs.umich.edu            return ptype
1823101Sstever@eecs.umich.edu
1833101Sstever@eecs.umich.edu        raise AttributeError("'%s' object has no attribute '%s'" % \
1843101Sstever@eecs.umich.edu              (type(self).__name__, attr))
1853101Sstever@eecs.umich.edu
1863101Sstever@eecs.umich.edu    def example_str(self):
1873101Sstever@eecs.umich.edu        if hasattr(self.ptype, "ex_str"):
1883101Sstever@eecs.umich.edu            return self.ptype.ex_str
1893101Sstever@eecs.umich.edu        else:
1903101Sstever@eecs.umich.edu            return self.ptype_str
1913101Sstever@eecs.umich.edu
1923101Sstever@eecs.umich.edu    # Is the param available to be exposed on the command line
1933101Sstever@eecs.umich.edu    def isCmdLineSettable(self):
1943101Sstever@eecs.umich.edu        if hasattr(self.ptype, "cmd_line_settable"):
1953101Sstever@eecs.umich.edu            return self.ptype.cmd_line_settable
1963101Sstever@eecs.umich.edu        else:
1973101Sstever@eecs.umich.edu            return False
1983101Sstever@eecs.umich.edu
1993101Sstever@eecs.umich.edu    def convert(self, value):
2003101Sstever@eecs.umich.edu        if isinstance(value, proxy.BaseProxy):
2013101Sstever@eecs.umich.edu            value.set_param_desc(self)
2023101Sstever@eecs.umich.edu            return value
2033101Sstever@eecs.umich.edu        if 'ptype' not in self.__dict__ and isNullPointer(value):
2043101Sstever@eecs.umich.edu            # deferred evaluation of SimObject; continue to defer if
2053101Sstever@eecs.umich.edu            # we're just assigning a null pointer
2063101Sstever@eecs.umich.edu            return value
2073101Sstever@eecs.umich.edu        if isinstance(value, self.ptype):
2083101Sstever@eecs.umich.edu            return value
2093101Sstever@eecs.umich.edu        if isNullPointer(value) and isSimObjectClass(self.ptype):
2103101Sstever@eecs.umich.edu            return value
2113101Sstever@eecs.umich.edu        return self.ptype(value)
2123101Sstever@eecs.umich.edu
2133101Sstever@eecs.umich.edu    def pretty_print(self, value):
2143101Sstever@eecs.umich.edu        if isinstance(value, proxy.BaseProxy):
2153101Sstever@eecs.umich.edu           return str(value)
2163101Sstever@eecs.umich.edu        if isNullPointer(value):
2173101Sstever@eecs.umich.edu           return NULL
2183101Sstever@eecs.umich.edu        return self.ptype(value).pretty_print(value)
2193101Sstever@eecs.umich.edu
2203101Sstever@eecs.umich.edu    def cxx_predecls(self, code):
2213101Sstever@eecs.umich.edu        code('#include <cstddef>')
2223101Sstever@eecs.umich.edu        self.ptype.cxx_predecls(code)
2233101Sstever@eecs.umich.edu
2243101Sstever@eecs.umich.edu    def pybind_predecls(self, code):
2253101Sstever@eecs.umich.edu        self.ptype.pybind_predecls(code)
2263101Sstever@eecs.umich.edu
2273101Sstever@eecs.umich.edu    def cxx_decl(self, code):
2283101Sstever@eecs.umich.edu        code('${{self.ptype.cxx_type}} ${{self.name}};')
2293101Sstever@eecs.umich.edu
2303101Sstever@eecs.umich.edu# Vector-valued parameter description.  Just like ParamDesc, except
2313101Sstever@eecs.umich.edu# that the value is a vector (list) of the specified type instead of a
2323101Sstever@eecs.umich.edu# single value.
2333101Sstever@eecs.umich.edu
2343101Sstever@eecs.umich.educlass VectorParamValue(list):
2353101Sstever@eecs.umich.edu    __metaclass__ = MetaParamValue
2363101Sstever@eecs.umich.edu    def __setattr__(self, attr, value):
2373101Sstever@eecs.umich.edu        raise AttributeError("Not allowed to set %s on '%s'" % \
2383101Sstever@eecs.umich.edu                             (attr, type(self).__name__))
2393101Sstever@eecs.umich.edu
2403101Sstever@eecs.umich.edu    def config_value(self):
2413101Sstever@eecs.umich.edu        return [v.config_value() for v in self]
2423101Sstever@eecs.umich.edu
2433101Sstever@eecs.umich.edu    def ini_str(self):
2443101Sstever@eecs.umich.edu        return ' '.join([v.ini_str() for v in self])
2453101Sstever@eecs.umich.edu
2463101Sstever@eecs.umich.edu    def getValue(self):
2473714Sstever@eecs.umich.edu        return [ v.getValue() for v in self ]
2483714Sstever@eecs.umich.edu
2493714Sstever@eecs.umich.edu    def unproxy(self, base):
2503714Sstever@eecs.umich.edu        if len(self) == 1 and isinstance(self[0], proxy.BaseProxy):
2513714Sstever@eecs.umich.edu            # The value is a proxy (e.g. Parent.any, Parent.all or
2523714Sstever@eecs.umich.edu            # Parent.x) therefore try resolve it
2533101Sstever@eecs.umich.edu            return self[0].unproxy(base)
2543101Sstever@eecs.umich.edu        else:
2553101Sstever@eecs.umich.edu            return [v.unproxy(base) for v in self]
2563101Sstever@eecs.umich.edu
2573101Sstever@eecs.umich.educlass SimObjectVector(VectorParamValue):
2583101Sstever@eecs.umich.edu    # support clone operation
2593101Sstever@eecs.umich.edu    def __call__(self, **kwargs):
2603101Sstever@eecs.umich.edu        return SimObjectVector([v(**kwargs) for v in self])
2613101Sstever@eecs.umich.edu
2623101Sstever@eecs.umich.edu    def clear_parent(self, old_parent):
2633101Sstever@eecs.umich.edu        for v in self:
2643101Sstever@eecs.umich.edu            v.clear_parent(old_parent)
2653101Sstever@eecs.umich.edu
2663101Sstever@eecs.umich.edu    def set_parent(self, parent, name):
2673101Sstever@eecs.umich.edu        if len(self) == 1:
2683101Sstever@eecs.umich.edu            self[0].set_parent(parent, name)
2693101Sstever@eecs.umich.edu        else:
2703101Sstever@eecs.umich.edu            width = int(math.ceil(math.log(len(self))/math.log(10)))
2713101Sstever@eecs.umich.edu            for i,v in enumerate(self):
2723101Sstever@eecs.umich.edu                v.set_parent(parent, "%s%0*d" % (name, width, i))
2733101Sstever@eecs.umich.edu
2743101Sstever@eecs.umich.edu    def has_parent(self):
2753101Sstever@eecs.umich.edu        return any([e.has_parent() for e in self if not isNullPointer(e)])
2763101Sstever@eecs.umich.edu
2773101Sstever@eecs.umich.edu    # return 'cpu0 cpu1' etc. for print_ini()
2783101Sstever@eecs.umich.edu    def get_name(self):
2793101Sstever@eecs.umich.edu        return ' '.join([v._name for v in self])
2803101Sstever@eecs.umich.edu
2813101Sstever@eecs.umich.edu    # By iterating through the constituent members of the vector here
2823101Sstever@eecs.umich.edu    # we can nicely handle iterating over all a SimObject's children
2833101Sstever@eecs.umich.edu    # without having to provide lots of special functions on
2843101Sstever@eecs.umich.edu    # SimObjectVector directly.
2853101Sstever@eecs.umich.edu    def descendants(self):
2863101Sstever@eecs.umich.edu        for v in self:
2873101Sstever@eecs.umich.edu            for obj in v.descendants():
2883101Sstever@eecs.umich.edu                yield obj
2893101Sstever@eecs.umich.edu
2903101Sstever@eecs.umich.edu    def get_config_as_dict(self):
2913101Sstever@eecs.umich.edu        a = []
2923101Sstever@eecs.umich.edu        for v in self:
2933101Sstever@eecs.umich.edu            a.append(v.get_config_as_dict())
2943101Sstever@eecs.umich.edu        return a
2953101Sstever@eecs.umich.edu
2963101Sstever@eecs.umich.edu    # If we are replacing an item in the vector, make sure to set the
2973101Sstever@eecs.umich.edu    # parent reference of the new SimObject to be the same as the parent
2983101Sstever@eecs.umich.edu    # of the SimObject being replaced. Useful to have if we created
2993101Sstever@eecs.umich.edu    # a SimObjectVector of temporary objects that will be modified later in
3003101Sstever@eecs.umich.edu    # configuration scripts.
3013101Sstever@eecs.umich.edu    def __setitem__(self, key, value):
3023101Sstever@eecs.umich.edu        val = self[key]
3033101Sstever@eecs.umich.edu        if value.has_parent():
3043101Sstever@eecs.umich.edu            warn("SimObject %s already has a parent" % value.get_name() +\
3053101Sstever@eecs.umich.edu                 " that is being overwritten by a SimObjectVector")
3063101Sstever@eecs.umich.edu        value.set_parent(val.get_parent(), val._name)
3073101Sstever@eecs.umich.edu        super(SimObjectVector, self).__setitem__(key, value)
3083101Sstever@eecs.umich.edu
3093101Sstever@eecs.umich.edu    # Enumerate the params of each member of the SimObject vector. Creates
3103101Sstever@eecs.umich.edu    # strings that will allow indexing into the vector by the python code and
3113101Sstever@eecs.umich.edu    # allow it to be specified on the command line.
3123101Sstever@eecs.umich.edu    def enumerateParams(self, flags_dict = {},
3133101Sstever@eecs.umich.edu                        cmd_line_str = "",
3143101Sstever@eecs.umich.edu                        access_str = ""):
3153101Sstever@eecs.umich.edu        if hasattr(self, "_paramEnumed"):
3163101Sstever@eecs.umich.edu            print("Cycle detected enumerating params at %s?!" % (cmd_line_str))
3173101Sstever@eecs.umich.edu        else:
3183101Sstever@eecs.umich.edu            x = 0
3193101Sstever@eecs.umich.edu            for vals in self:
3203101Sstever@eecs.umich.edu                # Each entry in the SimObjectVector should be an
3213101Sstever@eecs.umich.edu                # instance of a SimObject
3223101Sstever@eecs.umich.edu                flags_dict = vals.enumerateParams(flags_dict,
3233102Sstever@eecs.umich.edu                                                  cmd_line_str + "%d." % x,
3243714Sstever@eecs.umich.edu                                                  access_str + "[%d]." % x)
3253101Sstever@eecs.umich.edu                x = x + 1
3263714Sstever@eecs.umich.edu
3273714Sstever@eecs.umich.edu        return flags_dict
3283714Sstever@eecs.umich.edu
3293101Sstever@eecs.umich.educlass VectorParamDesc(ParamDesc):
3303101Sstever@eecs.umich.edu    # Convert assigned value to appropriate type.  If the RHS is not a
3313101Sstever@eecs.umich.edu    # list or tuple, it generates a single-element list.
3323101Sstever@eecs.umich.edu    def convert(self, value):
3333101Sstever@eecs.umich.edu        if isinstance(value, (list, tuple)):
3343101Sstever@eecs.umich.edu            # list: coerce each element into new list
3353101Sstever@eecs.umich.edu            tmp_list = [ ParamDesc.convert(self, v) for v in value ]
3363101Sstever@eecs.umich.edu        elif isinstance(value, str):
3373101Sstever@eecs.umich.edu            # If input is a csv string
3383101Sstever@eecs.umich.edu            tmp_list = [ ParamDesc.convert(self, v) \
3393101Sstever@eecs.umich.edu                         for v in value.strip('[').strip(']').split(',') ]
3403101Sstever@eecs.umich.edu        else:
3413101Sstever@eecs.umich.edu            # singleton: coerce to a single-element list
3423101Sstever@eecs.umich.edu            tmp_list = [ ParamDesc.convert(self, value) ]
3433101Sstever@eecs.umich.edu
3443101Sstever@eecs.umich.edu        if isSimObjectSequence(tmp_list):
3453101Sstever@eecs.umich.edu            return SimObjectVector(tmp_list)
3463101Sstever@eecs.umich.edu        else:
3473101Sstever@eecs.umich.edu            return VectorParamValue(tmp_list)
3483101Sstever@eecs.umich.edu
3493101Sstever@eecs.umich.edu    # Produce a human readable example string that describes
3503101Sstever@eecs.umich.edu    # how to set this vector parameter in the absence of a default
3513101Sstever@eecs.umich.edu    # value.
3523101Sstever@eecs.umich.edu    def example_str(self):
3533101Sstever@eecs.umich.edu        s = super(VectorParamDesc, self).example_str()
3543101Sstever@eecs.umich.edu        help_str = "[" + s + "," + s + ", ...]"
3553101Sstever@eecs.umich.edu        return help_str
3563101Sstever@eecs.umich.edu
3573101Sstever@eecs.umich.edu    # Produce a human readable representation of the value of this vector param.
3583101Sstever@eecs.umich.edu    def pretty_print(self, value):
3593101Sstever@eecs.umich.edu        if isinstance(value, (list, tuple)):
3603101Sstever@eecs.umich.edu            tmp_list = [ ParamDesc.pretty_print(self, v) for v in value ]
3613102Sstever@eecs.umich.edu        elif isinstance(value, str):
3623101Sstever@eecs.umich.edu            tmp_list = [ ParamDesc.pretty_print(self, v) for v in value.split(',') ]
3633101Sstever@eecs.umich.edu        else:
3643101Sstever@eecs.umich.edu            tmp_list = [ ParamDesc.pretty_print(self, value) ]
3654168Sbinkertn@umich.edu
3663101Sstever@eecs.umich.edu        return tmp_list
3673101Sstever@eecs.umich.edu
3683101Sstever@eecs.umich.edu    # This is a helper function for the new config system
3693101Sstever@eecs.umich.edu    def __call__(self, value):
3703101Sstever@eecs.umich.edu        if isinstance(value, (list, tuple)):
3713101Sstever@eecs.umich.edu            # list: coerce each element into new list
3723102Sstever@eecs.umich.edu            tmp_list = [ ParamDesc.convert(self, v) for v in value ]
3733101Sstever@eecs.umich.edu        elif isinstance(value, str):
3743101Sstever@eecs.umich.edu            # If input is a csv string
3753101Sstever@eecs.umich.edu            tmp_list = [ ParamDesc.convert(self, v) \
3763101Sstever@eecs.umich.edu                         for v in value.strip('[').strip(']').split(',') ]
3773101Sstever@eecs.umich.edu        else:
3783101Sstever@eecs.umich.edu            # singleton: coerce to a single-element list
3793101Sstever@eecs.umich.edu            tmp_list = [ ParamDesc.convert(self, value) ]
3803101Sstever@eecs.umich.edu
3813101Sstever@eecs.umich.edu        return VectorParamValue(tmp_list)
3823101Sstever@eecs.umich.edu
3833101Sstever@eecs.umich.edu    def cxx_predecls(self, code):
3843101Sstever@eecs.umich.edu        code('#include <vector>')
3853102Sstever@eecs.umich.edu        self.ptype.cxx_predecls(code)
3863101Sstever@eecs.umich.edu
3873101Sstever@eecs.umich.edu    def pybind_predecls(self, code):
3883101Sstever@eecs.umich.edu        code('#include <vector>')
3893584Ssaidi@eecs.umich.edu        self.ptype.pybind_predecls(code)
3903584Ssaidi@eecs.umich.edu
3913584Ssaidi@eecs.umich.edu    def cxx_decl(self, code):
3923584Ssaidi@eecs.umich.edu        code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};')
3933584Ssaidi@eecs.umich.edu
3943101Sstever@eecs.umich.educlass ParamFactory(object):
3953101Sstever@eecs.umich.edu    def __init__(self, param_desc_class, ptype_str = None):
3963101Sstever@eecs.umich.edu        self.param_desc_class = param_desc_class
3973101Sstever@eecs.umich.edu        self.ptype_str = ptype_str
3983101Sstever@eecs.umich.edu
3993101Sstever@eecs.umich.edu    def __getattr__(self, attr):
4003101Sstever@eecs.umich.edu        if self.ptype_str:
4013101Sstever@eecs.umich.edu            attr = self.ptype_str + '.' + attr
4023101Sstever@eecs.umich.edu        return ParamFactory(self.param_desc_class, attr)
4033101Sstever@eecs.umich.edu
4043101Sstever@eecs.umich.edu    # E.g., Param.Int(5, "number of widgets")
4053101Sstever@eecs.umich.edu    def __call__(self, *args, **kwargs):
4063101Sstever@eecs.umich.edu        ptype = None
4073101Sstever@eecs.umich.edu        try:
4083101Sstever@eecs.umich.edu            ptype = allParams[self.ptype_str]
4093101Sstever@eecs.umich.edu        except KeyError:
4103101Sstever@eecs.umich.edu            # if name isn't defined yet, assume it's a SimObject, and
4113101Sstever@eecs.umich.edu            # try to resolve it later
4123101Sstever@eecs.umich.edu            pass
4133101Sstever@eecs.umich.edu        return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs)
4143101Sstever@eecs.umich.edu
4153101Sstever@eecs.umich.eduParam = ParamFactory(ParamDesc)
4163101Sstever@eecs.umich.eduVectorParam = ParamFactory(VectorParamDesc)
4173101Sstever@eecs.umich.edu
4183101Sstever@eecs.umich.edu#####################################################################
4193101Sstever@eecs.umich.edu#
4203101Sstever@eecs.umich.edu# Parameter Types
4213101Sstever@eecs.umich.edu#
4223101Sstever@eecs.umich.edu# Though native Python types could be used to specify parameter types
4233101Sstever@eecs.umich.edu# (the 'ptype' field of the Param and VectorParam classes), it's more
4243101Sstever@eecs.umich.edu# flexible to define our own set of types.  This gives us more control
4253101Sstever@eecs.umich.edu# over how Python expressions are converted to values (via the
4263101Sstever@eecs.umich.edu# __init__() constructor) and how these values are printed out (via
4273101Sstever@eecs.umich.edu# the __str__() conversion method).
4283101Sstever@eecs.umich.edu#
4293101Sstever@eecs.umich.edu#####################################################################
4303101Sstever@eecs.umich.edu
4313101Sstever@eecs.umich.edu# String-valued parameter.  Just mixin the ParamValue class with the
4323101Sstever@eecs.umich.edu# built-in str class.
4333101Sstever@eecs.umich.educlass String(ParamValue,str):
4343101Sstever@eecs.umich.edu    cxx_type = 'std::string'
4353101Sstever@eecs.umich.edu    cmd_line_settable = True
4363101Sstever@eecs.umich.edu
4373101Sstever@eecs.umich.edu    @classmethod
4383101Sstever@eecs.umich.edu    def cxx_predecls(self, code):
4393101Sstever@eecs.umich.edu        code('#include <string>')
4403101Sstever@eecs.umich.edu
4413101Sstever@eecs.umich.edu    def __call__(self, value):
4423101Sstever@eecs.umich.edu        self = value
4433101Sstever@eecs.umich.edu        return value
4443101Sstever@eecs.umich.edu
4453101Sstever@eecs.umich.edu    @classmethod
4463101Sstever@eecs.umich.edu    def cxx_ini_parse(self, code, src, dest, ret):
4473101Sstever@eecs.umich.edu        code('%s = %s;' % (dest, src))
4483101Sstever@eecs.umich.edu        code('%s true;' % ret)
4493101Sstever@eecs.umich.edu
4503101Sstever@eecs.umich.edu    def getValue(self):
4513101Sstever@eecs.umich.edu        return self
4523101Sstever@eecs.umich.edu
4533101Sstever@eecs.umich.edu# superclass for "numeric" parameter values, to emulate math
4543101Sstever@eecs.umich.edu# operations in a type-safe way.  e.g., a Latency times an int returns
4553101Sstever@eecs.umich.edu# a new Latency object.
4563101Sstever@eecs.umich.educlass NumericParamValue(ParamValue):
4573102Sstever@eecs.umich.edu    def __str__(self):
4583101Sstever@eecs.umich.edu        return str(self.value)
4593101Sstever@eecs.umich.edu
4603101Sstever@eecs.umich.edu    def __float__(self):
4613101Sstever@eecs.umich.edu        return float(self.value)
4623101Sstever@eecs.umich.edu
4633101Sstever@eecs.umich.edu    def __long__(self):
4643101Sstever@eecs.umich.edu        return long(self.value)
4653101Sstever@eecs.umich.edu
4663101Sstever@eecs.umich.edu    def __int__(self):
4673101Sstever@eecs.umich.edu        return int(self.value)
4683101Sstever@eecs.umich.edu
4693101Sstever@eecs.umich.edu    # hook for bounds checking
4703101Sstever@eecs.umich.edu    def _check(self):
4713101Sstever@eecs.umich.edu        return
4723101Sstever@eecs.umich.edu
4733101Sstever@eecs.umich.edu    def __mul__(self, other):
4743101Sstever@eecs.umich.edu        newobj = self.__class__(self)
4753101Sstever@eecs.umich.edu        newobj.value *= other
4763101Sstever@eecs.umich.edu        newobj._check()
4773101Sstever@eecs.umich.edu        return newobj
4783101Sstever@eecs.umich.edu
4793101Sstever@eecs.umich.edu    __rmul__ = __mul__
4803101Sstever@eecs.umich.edu
4814380Sbinkertn@umich.edu    def __div__(self, other):
4824380Sbinkertn@umich.edu        newobj = self.__class__(self)
4834380Sbinkertn@umich.edu        newobj.value /= other
4843101Sstever@eecs.umich.edu        newobj._check()
4854380Sbinkertn@umich.edu        return newobj
4864380Sbinkertn@umich.edu
4874380Sbinkertn@umich.edu    def __sub__(self, other):
4883101Sstever@eecs.umich.edu        newobj = self.__class__(self)
4893101Sstever@eecs.umich.edu        newobj.value -= other
4903101Sstever@eecs.umich.edu        newobj._check()
4913101Sstever@eecs.umich.edu        return newobj
4923101Sstever@eecs.umich.edu
4933101Sstever@eecs.umich.edu    def config_value(self):
4943101Sstever@eecs.umich.edu        return self.value
4953101Sstever@eecs.umich.edu
4963101Sstever@eecs.umich.edu    @classmethod
4973101Sstever@eecs.umich.edu    def cxx_ini_predecls(cls, code):
4983101Sstever@eecs.umich.edu        # Assume that base/str.hh will be included anyway
4993101Sstever@eecs.umich.edu        # code('#include "base/str.hh"')
5003101Sstever@eecs.umich.edu        pass
5013101Sstever@eecs.umich.edu
5023101Sstever@eecs.umich.edu    # The default for parsing PODs from an .ini entry is to extract from an
5033101Sstever@eecs.umich.edu    # istringstream and let overloading choose the right type according to
5043101Sstever@eecs.umich.edu    # the dest type.
5053101Sstever@eecs.umich.edu    @classmethod
5063101Sstever@eecs.umich.edu    def cxx_ini_parse(self, code, src, dest, ret):
5073101Sstever@eecs.umich.edu        code('%s to_number(%s, %s);' % (ret, src, dest))
5083101Sstever@eecs.umich.edu
5093101Sstever@eecs.umich.edu# Metaclass for bounds-checked integer parameters.  See CheckedInt.
5103101Sstever@eecs.umich.educlass CheckedIntType(MetaParamValue):
5113101Sstever@eecs.umich.edu    def __init__(cls, name, bases, dict):
5123101Sstever@eecs.umich.edu        super(CheckedIntType, cls).__init__(name, bases, dict)
5134380Sbinkertn@umich.edu
5143101Sstever@eecs.umich.edu        # CheckedInt is an abstract base class, so we actually don't
5153101Sstever@eecs.umich.edu        # want to do any processing on it... the rest of this code is
5164380Sbinkertn@umich.edu        # just for classes that derive from CheckedInt.
5174380Sbinkertn@umich.edu        if name == 'CheckedInt':
5183101Sstever@eecs.umich.edu            return
5193932Sbinkertn@umich.edu
5203932Sbinkertn@umich.edu        if not (hasattr(cls, 'min') and hasattr(cls, 'max')):
5213932Sbinkertn@umich.edu            if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')):
5223932Sbinkertn@umich.edu                panic("CheckedInt subclass %s must define either\n" \
5233932Sbinkertn@umich.edu                      "    'min' and 'max' or 'size' and 'unsigned'\n",
5243932Sbinkertn@umich.edu                      name);
5253932Sbinkertn@umich.edu            if cls.unsigned:
5263932Sbinkertn@umich.edu                cls.min = 0
5273932Sbinkertn@umich.edu                cls.max = 2 ** cls.size - 1
5283932Sbinkertn@umich.edu            else:
5293932Sbinkertn@umich.edu                cls.min = -(2 ** (cls.size - 1))
5303932Sbinkertn@umich.edu                cls.max = (2 ** (cls.size - 1)) - 1
5313932Sbinkertn@umich.edu
5323885Sbinkertn@umich.edu# Abstract superclass for bounds-checked integer parameters.  This
5333932Sbinkertn@umich.edu# class is subclassed to generate parameter classes with specific
5343932Sbinkertn@umich.edu# bounds.  Initialization of the min and max bounds is done in the
5353885Sbinkertn@umich.edu# metaclass CheckedIntType.__init__.
5363932Sbinkertn@umich.educlass CheckedInt(NumericParamValue):
5373932Sbinkertn@umich.edu    __metaclass__ = CheckedIntType
5383932Sbinkertn@umich.edu    cmd_line_settable = True
5393932Sbinkertn@umich.edu
5403932Sbinkertn@umich.edu    def _check(self):
5413932Sbinkertn@umich.edu        if not self.min <= self.value <= self.max:
5423932Sbinkertn@umich.edu            raise TypeError('Integer param out of bounds %d < %d < %d' % \
5433932Sbinkertn@umich.edu                  (self.min, self.value, self.max))
5443932Sbinkertn@umich.edu
5453932Sbinkertn@umich.edu    def __init__(self, value):
5463932Sbinkertn@umich.edu        if isinstance(value, str):
5473932Sbinkertn@umich.edu            self.value = convert.toInteger(value)
5483932Sbinkertn@umich.edu        elif isinstance(value, (int, long, float, NumericParamValue)):
5493932Sbinkertn@umich.edu            self.value = long(value)
5503932Sbinkertn@umich.edu        else:
5513932Sbinkertn@umich.edu            raise TypeError("Can't convert object of type %s to CheckedInt" \
5523932Sbinkertn@umich.edu                  % type(value).__name__)
5533932Sbinkertn@umich.edu        self._check()
5543885Sbinkertn@umich.edu
5553885Sbinkertn@umich.edu    def __call__(self, value):
5563885Sbinkertn@umich.edu        self.__init__(value)
5573885Sbinkertn@umich.edu        return value
5583885Sbinkertn@umich.edu
5593885Sbinkertn@umich.edu    @classmethod
5603932Sbinkertn@umich.edu    def cxx_predecls(cls, code):
5613885Sbinkertn@umich.edu        # most derived types require this, so we just do it here once
5623885Sbinkertn@umich.edu        code('#include "base/types.hh"')
5633932Sbinkertn@umich.edu
5643932Sbinkertn@umich.edu    def getValue(self):
5653885Sbinkertn@umich.edu        return long(self.value)
5663885Sbinkertn@umich.edu
5673932Sbinkertn@umich.educlass Int(CheckedInt):      cxx_type = 'int';      size = 32; unsigned = False
5683885Sbinkertn@umich.educlass Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True
5693101Sstever@eecs.umich.edu
5703101Sstever@eecs.umich.educlass Int8(CheckedInt):     cxx_type =   'int8_t'; size =  8; unsigned = False
5713101Sstever@eecs.umich.educlass UInt8(CheckedInt):    cxx_type =  'uint8_t'; size =  8; unsigned = True
5723101Sstever@eecs.umich.educlass Int16(CheckedInt):    cxx_type =  'int16_t'; size = 16; unsigned = False
5733101Sstever@eecs.umich.educlass UInt16(CheckedInt):   cxx_type = 'uint16_t'; size = 16; unsigned = True
5743101Sstever@eecs.umich.educlass Int32(CheckedInt):    cxx_type =  'int32_t'; size = 32; unsigned = False
5753101Sstever@eecs.umich.educlass UInt32(CheckedInt):   cxx_type = 'uint32_t'; size = 32; unsigned = True
5763101Sstever@eecs.umich.educlass Int64(CheckedInt):    cxx_type =  'int64_t'; size = 64; unsigned = False
5773101Sstever@eecs.umich.educlass UInt64(CheckedInt):   cxx_type = 'uint64_t'; size = 64; unsigned = True
5783101Sstever@eecs.umich.edu
5793101Sstever@eecs.umich.educlass Counter(CheckedInt):  cxx_type = 'Counter';  size = 64; unsigned = True
5803101Sstever@eecs.umich.educlass Tick(CheckedInt):     cxx_type = 'Tick';     size = 64; unsigned = True
5813101Sstever@eecs.umich.educlass TcpPort(CheckedInt):  cxx_type = 'uint16_t'; size = 16; unsigned = True
5823101Sstever@eecs.umich.educlass UdpPort(CheckedInt):  cxx_type = 'uint16_t'; size = 16; unsigned = True
5833101Sstever@eecs.umich.edu
5843101Sstever@eecs.umich.educlass Percent(CheckedInt):  cxx_type = 'int'; min = 0; max = 100
5853101Sstever@eecs.umich.edu
5863101Sstever@eecs.umich.educlass Cycles(CheckedInt):
5873101Sstever@eecs.umich.edu    cxx_type = 'Cycles'
5883101Sstever@eecs.umich.edu    size = 64
5893101Sstever@eecs.umich.edu    unsigned = True
5903101Sstever@eecs.umich.edu
5913101Sstever@eecs.umich.edu    def getValue(self):
5923101Sstever@eecs.umich.edu        from _m5.core import Cycles
5933101Sstever@eecs.umich.edu        return Cycles(self.value)
5943101Sstever@eecs.umich.edu
5953101Sstever@eecs.umich.edu    @classmethod
5963101Sstever@eecs.umich.edu    def cxx_ini_predecls(cls, code):
5973101Sstever@eecs.umich.edu        # Assume that base/str.hh will be included anyway
5983101Sstever@eecs.umich.edu        # code('#include "base/str.hh"')
5993101Sstever@eecs.umich.edu        pass
6003101Sstever@eecs.umich.edu
6013101Sstever@eecs.umich.edu    @classmethod
6023101Sstever@eecs.umich.edu    def cxx_ini_parse(cls, code, src, dest, ret):
6033101Sstever@eecs.umich.edu        code('uint64_t _temp;')
6043101Sstever@eecs.umich.edu        code('bool _ret = to_number(%s, _temp);' % src)
6053101Sstever@eecs.umich.edu        code('if (_ret)')
6063101Sstever@eecs.umich.edu        code('    %s = Cycles(_temp);' % dest)
6073101Sstever@eecs.umich.edu        code('%s _ret;' % ret)
6083101Sstever@eecs.umich.edu
6093101Sstever@eecs.umich.educlass Float(ParamValue, float):
6103101Sstever@eecs.umich.edu    cxx_type = 'double'
6113101Sstever@eecs.umich.edu    cmd_line_settable = True
6123101Sstever@eecs.umich.edu
6133101Sstever@eecs.umich.edu    def __init__(self, value):
6143101Sstever@eecs.umich.edu        if isinstance(value, (int, long, float, NumericParamValue, Float, str)):
6153101Sstever@eecs.umich.edu            self.value = float(value)
6163101Sstever@eecs.umich.edu        else:
6173101Sstever@eecs.umich.edu            raise TypeError("Can't convert object of type %s to Float" \
6183101Sstever@eecs.umich.edu                  % type(value).__name__)
6193101Sstever@eecs.umich.edu
6203101Sstever@eecs.umich.edu    def __call__(self, value):
6213101Sstever@eecs.umich.edu        self.__init__(value)
6223101Sstever@eecs.umich.edu        return value
6233101Sstever@eecs.umich.edu
6243101Sstever@eecs.umich.edu    def getValue(self):
6253101Sstever@eecs.umich.edu        return float(self.value)
6263101Sstever@eecs.umich.edu
6273101Sstever@eecs.umich.edu    def config_value(self):
6283101Sstever@eecs.umich.edu        return self
6293101Sstever@eecs.umich.edu
6303101Sstever@eecs.umich.edu    @classmethod
6313101Sstever@eecs.umich.edu    def cxx_ini_predecls(cls, code):
6323101Sstever@eecs.umich.edu        code('#include <sstream>')
6333101Sstever@eecs.umich.edu
6343101Sstever@eecs.umich.edu    @classmethod
6353101Sstever@eecs.umich.edu    def cxx_ini_parse(self, code, src, dest, ret):
6364167Sbinkertn@umich.edu        code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
6373101Sstever@eecs.umich.edu
6383101Sstever@eecs.umich.educlass MemorySize(CheckedInt):
6393101Sstever@eecs.umich.edu    cxx_type = 'uint64_t'
6403101Sstever@eecs.umich.edu    ex_str = '512MB'
6414167Sbinkertn@umich.edu    size = 64
6424167Sbinkertn@umich.edu    unsigned = True
6433101Sstever@eecs.umich.edu    def __init__(self, value):
6444167Sbinkertn@umich.edu        if isinstance(value, MemorySize):
6454167Sbinkertn@umich.edu            self.value = value.value
6464167Sbinkertn@umich.edu        else:
6474167Sbinkertn@umich.edu            self.value = convert.toMemorySize(value)
6484167Sbinkertn@umich.edu        self._check()
6494167Sbinkertn@umich.edu
6504167Sbinkertn@umich.educlass MemorySize32(CheckedInt):
6514167Sbinkertn@umich.edu    cxx_type = 'uint32_t'
6524167Sbinkertn@umich.edu    ex_str = '512MB'
6534167Sbinkertn@umich.edu    size = 32
6544167Sbinkertn@umich.edu    unsigned = True
6554167Sbinkertn@umich.edu    def __init__(self, value):
6563101Sstever@eecs.umich.edu        if isinstance(value, MemorySize):
6573101Sstever@eecs.umich.edu            self.value = value.value
6583101Sstever@eecs.umich.edu        else:
6593101Sstever@eecs.umich.edu            self.value = convert.toMemorySize(value)
6603101Sstever@eecs.umich.edu        self._check()
6613101Sstever@eecs.umich.edu
6623101Sstever@eecs.umich.educlass Addr(CheckedInt):
6633101Sstever@eecs.umich.edu    cxx_type = 'Addr'
6643101Sstever@eecs.umich.edu    size = 64
6653101Sstever@eecs.umich.edu    unsigned = True
6664167Sbinkertn@umich.edu    def __init__(self, value):
6674167Sbinkertn@umich.edu        if isinstance(value, Addr):
6684167Sbinkertn@umich.edu            self.value = value.value
6694167Sbinkertn@umich.edu        else:
6703101Sstever@eecs.umich.edu            try:
6714167Sbinkertn@umich.edu                # Often addresses are referred to with sizes. Ex: A device
6723101Sstever@eecs.umich.edu                # base address is at "512MB".  Use toMemorySize() to convert
6734167Sbinkertn@umich.edu                # these into addresses. If the address is not specified with a
6744167Sbinkertn@umich.edu                # "size", an exception will occur and numeric translation will
6754167Sbinkertn@umich.edu                # proceed below.
6764167Sbinkertn@umich.edu                self.value = convert.toMemorySize(value)
6774167Sbinkertn@umich.edu            except (TypeError, ValueError):
6784167Sbinkertn@umich.edu                # Convert number to string and use long() to do automatic
6794167Sbinkertn@umich.edu                # base conversion (requires base=0 for auto-conversion)
6804167Sbinkertn@umich.edu                self.value = long(str(value), base=0)
6814167Sbinkertn@umich.edu
6824167Sbinkertn@umich.edu        self._check()
6834167Sbinkertn@umich.edu    def __add__(self, other):
6844167Sbinkertn@umich.edu        if isinstance(other, Addr):
6853101Sstever@eecs.umich.edu            return self.value + other.value
6863101Sstever@eecs.umich.edu        else:
6873101Sstever@eecs.umich.edu            return self.value + other
6883101Sstever@eecs.umich.edu    def pretty_print(self, value):
6893101Sstever@eecs.umich.edu        try:
6903101Sstever@eecs.umich.edu            val = convert.toMemorySize(value)
6913101Sstever@eecs.umich.edu        except TypeError:
6923101Sstever@eecs.umich.edu            val = long(value)
6934167Sbinkertn@umich.edu        return "0x%x" % long(val)
6943101Sstever@eecs.umich.edu
6954167Sbinkertn@umich.educlass AddrRange(ParamValue):
6964167Sbinkertn@umich.edu    cxx_type = 'AddrRange'
6974167Sbinkertn@umich.edu
6984167Sbinkertn@umich.edu    def __init__(self, *args, **kwargs):
6993101Sstever@eecs.umich.edu        # Disable interleaving and hashing by default
7003101Sstever@eecs.umich.edu        self.intlvHighBit = 0
7013101Sstever@eecs.umich.edu        self.xorHighBit = 0
7023101Sstever@eecs.umich.edu        self.intlvBits = 0
7033101Sstever@eecs.umich.edu        self.intlvMatch = 0
7043101Sstever@eecs.umich.edu
7053101Sstever@eecs.umich.edu        def handle_kwargs(self, kwargs):
7063101Sstever@eecs.umich.edu            # An address range needs to have an upper limit, specified
7073101Sstever@eecs.umich.edu            # either explicitly with an end, or as an offset using the
7083101Sstever@eecs.umich.edu            # size keyword.
7094167Sbinkertn@umich.edu            if 'end' in kwargs:
7104167Sbinkertn@umich.edu                self.end = Addr(kwargs.pop('end'))
7114167Sbinkertn@umich.edu            elif 'size' in kwargs:
7124167Sbinkertn@umich.edu                self.end = self.start + Addr(kwargs.pop('size')) - 1
7134167Sbinkertn@umich.edu            else:
7144167Sbinkertn@umich.edu                raise TypeError("Either end or size must be specified")
7154167Sbinkertn@umich.edu
7164167Sbinkertn@umich.edu            # Now on to the optional bit
7174167Sbinkertn@umich.edu            if 'intlvHighBit' in kwargs:
7184167Sbinkertn@umich.edu                self.intlvHighBit = int(kwargs.pop('intlvHighBit'))
7194167Sbinkertn@umich.edu            if 'xorHighBit' in kwargs:
7204167Sbinkertn@umich.edu                self.xorHighBit = int(kwargs.pop('xorHighBit'))
7213101Sstever@eecs.umich.edu            if 'intlvBits' in kwargs:
7223101Sstever@eecs.umich.edu                self.intlvBits = int(kwargs.pop('intlvBits'))
7233101Sstever@eecs.umich.edu            if 'intlvMatch' in kwargs:
7243101Sstever@eecs.umich.edu                self.intlvMatch = int(kwargs.pop('intlvMatch'))
7253101Sstever@eecs.umich.edu
7263101Sstever@eecs.umich.edu        if len(args) == 0:
7273101Sstever@eecs.umich.edu            self.start = Addr(kwargs.pop('start'))
7283101Sstever@eecs.umich.edu            handle_kwargs(self, kwargs)
7293101Sstever@eecs.umich.edu
7303101Sstever@eecs.umich.edu        elif len(args) == 1:
7313101Sstever@eecs.umich.edu            if kwargs:
7323101Sstever@eecs.umich.edu                self.start = Addr(args[0])
7333101Sstever@eecs.umich.edu                handle_kwargs(self, kwargs)
7343101Sstever@eecs.umich.edu            elif isinstance(args[0], (list, tuple)):
7354167Sbinkertn@umich.edu                self.start = Addr(args[0][0])
7364167Sbinkertn@umich.edu                self.end = Addr(args[0][1])
7373101Sstever@eecs.umich.edu            else:
7383101Sstever@eecs.umich.edu                self.start = Addr(0)
7393101Sstever@eecs.umich.edu                self.end = Addr(args[0]) - 1
7403101Sstever@eecs.umich.edu
7413101Sstever@eecs.umich.edu        elif len(args) == 2:
7423101Sstever@eecs.umich.edu            self.start = Addr(args[0])
7434167Sbinkertn@umich.edu            self.end = Addr(args[1])
7444167Sbinkertn@umich.edu        else:
7454167Sbinkertn@umich.edu            raise TypeError("Too many arguments specified")
7464167Sbinkertn@umich.edu
7473101Sstever@eecs.umich.edu        if kwargs:
7483101Sstever@eecs.umich.edu            raise TypeError("Too many keywords: %s" % list(kwargs.keys()))
7493101Sstever@eecs.umich.edu
7503101Sstever@eecs.umich.edu    def __str__(self):
7514167Sbinkertn@umich.edu        return '%s:%s:%s:%s:%s:%s' \
7523102Sstever@eecs.umich.edu            % (self.start, self.end, self.intlvHighBit, self.xorHighBit,\
7533101Sstever@eecs.umich.edu               self.intlvBits, self.intlvMatch)
7543101Sstever@eecs.umich.edu
7553101Sstever@eecs.umich.edu    def size(self):
7563101Sstever@eecs.umich.edu        # Divide the size by the size of the interleaving slice
7573101Sstever@eecs.umich.edu        return (long(self.end) - long(self.start) + 1) >> self.intlvBits
7583101Sstever@eecs.umich.edu
7594167Sbinkertn@umich.edu    @classmethod
7604167Sbinkertn@umich.edu    def cxx_predecls(cls, code):
7614167Sbinkertn@umich.edu        Addr.cxx_predecls(code)
7624167Sbinkertn@umich.edu        code('#include "base/addr_range.hh"')
7633101Sstever@eecs.umich.edu
7643101Sstever@eecs.umich.edu    @classmethod
7653101Sstever@eecs.umich.edu    def pybind_predecls(cls, code):
7663101Sstever@eecs.umich.edu        Addr.pybind_predecls(code)
7673101Sstever@eecs.umich.edu        code('#include "base/addr_range.hh"')
7683102Sstever@eecs.umich.edu
7693102Sstever@eecs.umich.edu    @classmethod
7703102Sstever@eecs.umich.edu    def cxx_ini_predecls(cls, code):
7713102Sstever@eecs.umich.edu        code('#include <sstream>')
7723102Sstever@eecs.umich.edu
7733102Sstever@eecs.umich.edu    @classmethod
7743102Sstever@eecs.umich.edu    def cxx_ini_parse(cls, code, src, dest, ret):
7753102Sstever@eecs.umich.edu        code('uint64_t _start, _end, _intlvHighBit = 0, _xorHighBit = 0;')
7763102Sstever@eecs.umich.edu        code('uint64_t _intlvBits = 0, _intlvMatch = 0;')
7773102Sstever@eecs.umich.edu        code('char _sep;')
7783102Sstever@eecs.umich.edu        code('std::istringstream _stream(${src});')
7793102Sstever@eecs.umich.edu        code('_stream >> _start;')
7803102Sstever@eecs.umich.edu        code('_stream.get(_sep);')
7813102Sstever@eecs.umich.edu        code('_stream >> _end;')
7823102Sstever@eecs.umich.edu        code('if (!_stream.fail() && !_stream.eof()) {')
7833102Sstever@eecs.umich.edu        code('    _stream.get(_sep);')
7843102Sstever@eecs.umich.edu        code('    _stream >> _intlvHighBit;')
7853102Sstever@eecs.umich.edu        code('    _stream.get(_sep);')
7863102Sstever@eecs.umich.edu        code('    _stream >> _xorHighBit;')
7873102Sstever@eecs.umich.edu        code('    _stream.get(_sep);')
7883102Sstever@eecs.umich.edu        code('    _stream >> _intlvBits;')
7893102Sstever@eecs.umich.edu        code('    _stream.get(_sep);')
7903102Sstever@eecs.umich.edu        code('    _stream >> _intlvMatch;')
7913102Sstever@eecs.umich.edu        code('}')
7923102Sstever@eecs.umich.edu        code('bool _ret = !_stream.fail() &&'
7933102Sstever@eecs.umich.edu            '_stream.eof() && _sep == \':\';')
7943102Sstever@eecs.umich.edu        code('if (_ret)')
7953102Sstever@eecs.umich.edu        code('   ${dest} = AddrRange(_start, _end, _intlvHighBit, \
7963102Sstever@eecs.umich.edu                _xorHighBit, _intlvBits, _intlvMatch);')
7973102Sstever@eecs.umich.edu        code('${ret} _ret;')
7983101Sstever@eecs.umich.edu
7993101Sstever@eecs.umich.edu    def getValue(self):
8003101Sstever@eecs.umich.edu        # Go from the Python class to the wrapped C++ class
8013101Sstever@eecs.umich.edu        from _m5.range import AddrRange
8023101Sstever@eecs.umich.edu
8033101Sstever@eecs.umich.edu        return AddrRange(long(self.start), long(self.end),
8043101Sstever@eecs.umich.edu                         int(self.intlvHighBit), int(self.xorHighBit),
8053101Sstever@eecs.umich.edu                         int(self.intlvBits), int(self.intlvMatch))
8063101Sstever@eecs.umich.edu
8073101Sstever@eecs.umich.edu# Boolean parameter type.  Python doesn't let you subclass bool, since
8083101Sstever@eecs.umich.edu# it doesn't want to let you create multiple instances of True and
8093101Sstever@eecs.umich.edu# False.  Thus this is a little more complicated than String.
8103101Sstever@eecs.umich.educlass Bool(ParamValue):
8113101Sstever@eecs.umich.edu    cxx_type = 'bool'
8123101Sstever@eecs.umich.edu    cmd_line_settable = True
8133101Sstever@eecs.umich.edu
8143101Sstever@eecs.umich.edu    def __init__(self, value):
8153105Sstever@eecs.umich.edu        try:
8163105Sstever@eecs.umich.edu            self.value = convert.toBool(value)
8173101Sstever@eecs.umich.edu        except TypeError:
8183101Sstever@eecs.umich.edu            self.value = bool(value)
8193101Sstever@eecs.umich.edu
8203101Sstever@eecs.umich.edu    def __call__(self, value):
8213105Sstever@eecs.umich.edu        self.__init__(value)
8223101Sstever@eecs.umich.edu        return value
8233103Sstever@eecs.umich.edu
8243105Sstever@eecs.umich.edu    def getValue(self):
8253103Sstever@eecs.umich.edu        return bool(self.value)
8263105Sstever@eecs.umich.edu
8273105Sstever@eecs.umich.edu    def __str__(self):
8283105Sstever@eecs.umich.edu        return str(self.value)
8293105Sstever@eecs.umich.edu
8303105Sstever@eecs.umich.edu    # implement truth value testing for Bool parameters so that these params
8313105Sstever@eecs.umich.edu    # evaluate correctly during the python configuration phase
8323105Sstever@eecs.umich.edu    def __bool__(self):
8333105Sstever@eecs.umich.edu        return bool(self.value)
8343105Sstever@eecs.umich.edu
8353105Sstever@eecs.umich.edu    # Python 2.7 uses __nonzero__ instead of __bool__
8363105Sstever@eecs.umich.edu    __nonzero__ = __bool__
8373105Sstever@eecs.umich.edu
8383105Sstever@eecs.umich.edu    def ini_str(self):
8393109Sstever@eecs.umich.edu        if self.value:
8403105Sstever@eecs.umich.edu            return 'true'
8413105Sstever@eecs.umich.edu        return 'false'
8423105Sstever@eecs.umich.edu
8433105Sstever@eecs.umich.edu    def config_value(self):
8443105Sstever@eecs.umich.edu        return self.value
8453105Sstever@eecs.umich.edu
8463105Sstever@eecs.umich.edu    @classmethod
8473105Sstever@eecs.umich.edu    def cxx_ini_predecls(cls, code):
8483101Sstever@eecs.umich.edu        # Assume that base/str.hh will be included anyway
8493109Sstever@eecs.umich.edu        # code('#include "base/str.hh"')
8503109Sstever@eecs.umich.edu        pass
8513109Sstever@eecs.umich.edu
8523109Sstever@eecs.umich.edu    @classmethod
8533109Sstever@eecs.umich.edu    def cxx_ini_parse(cls, code, src, dest, ret):
8543109Sstever@eecs.umich.edu        code('%s to_bool(%s, %s);' % (ret, src, dest))
8553109Sstever@eecs.umich.edu
8563109Sstever@eecs.umich.edudef IncEthernetAddr(addr, val = 1):
8573109Sstever@eecs.umich.edu    bytes = map(lambda x: int(x, 16), addr.split(':'))
8583101Sstever@eecs.umich.edu    bytes[5] += val
8593105Sstever@eecs.umich.edu    for i in (5, 4, 3, 2, 1):
8603105Sstever@eecs.umich.edu        val,rem = divmod(bytes[i], 256)
8613105Sstever@eecs.umich.edu        bytes[i] = rem
8623101Sstever@eecs.umich.edu        if val == 0:
8633105Sstever@eecs.umich.edu            break
8643105Sstever@eecs.umich.edu        bytes[i - 1] += val
8653101Sstever@eecs.umich.edu    assert(bytes[0] <= 255)
8663105Sstever@eecs.umich.edu    return ':'.join(map(lambda x: '%02x' % x, bytes))
8673179Sstever@eecs.umich.edu
8683105Sstever@eecs.umich.edu_NextEthernetAddr = "00:90:00:00:00:01"
8693105Sstever@eecs.umich.edudef NextEthernetAddr():
8703101Sstever@eecs.umich.edu    global _NextEthernetAddr
8713101Sstever@eecs.umich.edu
8723105Sstever@eecs.umich.edu    value = _NextEthernetAddr
8733105Sstever@eecs.umich.edu    _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1)
8743105Sstever@eecs.umich.edu    return value
8753105Sstever@eecs.umich.edu
8763105Sstever@eecs.umich.educlass EthernetAddr(ParamValue):
8773105Sstever@eecs.umich.edu    cxx_type = 'Net::EthAddr'
8783105Sstever@eecs.umich.edu    ex_str = "00:90:00:00:00:01"
8793105Sstever@eecs.umich.edu    cmd_line_settable = True
8803105Sstever@eecs.umich.edu
8813105Sstever@eecs.umich.edu    @classmethod
8823105Sstever@eecs.umich.edu    def cxx_predecls(cls, code):
8833101Sstever@eecs.umich.edu        code('#include "base/inet.hh"')
8843101Sstever@eecs.umich.edu
8853101Sstever@eecs.umich.edu    def __init__(self, value):
8863101Sstever@eecs.umich.edu        if value == NextEthernetAddr:
8873101Sstever@eecs.umich.edu            self.value = value
8884123Sbinkertn@umich.edu            return
8894123Sbinkertn@umich.edu
8903101Sstever@eecs.umich.edu        if not isinstance(value, str):
8913101Sstever@eecs.umich.edu            raise TypeError("expected an ethernet address and didn't get one")
8923101Sstever@eecs.umich.edu
8933105Sstever@eecs.umich.edu        bytes = value.split(':')
8943105Sstever@eecs.umich.edu        if len(bytes) != 6:
8953105Sstever@eecs.umich.edu            raise TypeError('invalid ethernet address %s' % value)
8963105Sstever@eecs.umich.edu
8973105Sstever@eecs.umich.edu        for byte in bytes:
8983105Sstever@eecs.umich.edu            if not 0 <= int(byte, base=16) <= 0xff:
8993105Sstever@eecs.umich.edu                raise TypeError('invalid ethernet address %s' % value)
9003105Sstever@eecs.umich.edu
9013105Sstever@eecs.umich.edu        self.value = value
9023105Sstever@eecs.umich.edu
9033105Sstever@eecs.umich.edu    def __call__(self, value):
9043105Sstever@eecs.umich.edu        self.__init__(value)
9053105Sstever@eecs.umich.edu        return value
9063105Sstever@eecs.umich.edu
9073105Sstever@eecs.umich.edu    def unproxy(self, base):
9083105Sstever@eecs.umich.edu        if self.value == NextEthernetAddr:
9093105Sstever@eecs.umich.edu            return EthernetAddr(self.value())
9103105Sstever@eecs.umich.edu        return self
9113105Sstever@eecs.umich.edu
9123109Sstever@eecs.umich.edu    def getValue(self):
9133109Sstever@eecs.umich.edu        from _m5.net import EthAddr
9143109Sstever@eecs.umich.edu        return EthAddr(self.value)
9153105Sstever@eecs.umich.edu
9163105Sstever@eecs.umich.edu    def __str__(self):
9173105Sstever@eecs.umich.edu        return self.value
9183105Sstever@eecs.umich.edu
9193105Sstever@eecs.umich.edu    def ini_str(self):
9203105Sstever@eecs.umich.edu        return self.value
9213105Sstever@eecs.umich.edu
9223105Sstever@eecs.umich.edu    @classmethod
9233105Sstever@eecs.umich.edu    def cxx_ini_parse(self, code, src, dest, ret):
9243105Sstever@eecs.umich.edu        code('%s = Net::EthAddr(%s);' % (dest, src))
9253105Sstever@eecs.umich.edu        code('%s true;' % ret)
9263105Sstever@eecs.umich.edu
9273105Sstever@eecs.umich.edu# When initializing an IpAddress, pass in an existing IpAddress, a string of
9283105Sstever@eecs.umich.edu# the form "a.b.c.d", or an integer representing an IP.
9293105Sstever@eecs.umich.educlass IpAddress(ParamValue):
9303105Sstever@eecs.umich.edu    cxx_type = 'Net::IpAddress'
9313105Sstever@eecs.umich.edu    ex_str = "127.0.0.1"
9323105Sstever@eecs.umich.edu    cmd_line_settable = True
9333105Sstever@eecs.umich.edu
9343105Sstever@eecs.umich.edu    @classmethod
9353105Sstever@eecs.umich.edu    def cxx_predecls(cls, code):
9363105Sstever@eecs.umich.edu        code('#include "base/inet.hh"')
9373105Sstever@eecs.umich.edu
9383109Sstever@eecs.umich.edu    def __init__(self, value):
9393109Sstever@eecs.umich.edu        if isinstance(value, IpAddress):
9403109Sstever@eecs.umich.edu            self.ip = value.ip
9413109Sstever@eecs.umich.edu        else:
9423109Sstever@eecs.umich.edu            try:
9433109Sstever@eecs.umich.edu                self.ip = convert.toIpAddress(value)
9443109Sstever@eecs.umich.edu            except TypeError:
9453109Sstever@eecs.umich.edu                self.ip = long(value)
9463109Sstever@eecs.umich.edu        self.verifyIp()
9473109Sstever@eecs.umich.edu
9483109Sstever@eecs.umich.edu    def __call__(self, value):
9493109Sstever@eecs.umich.edu        self.__init__(value)
9503109Sstever@eecs.umich.edu        return value
9513109Sstever@eecs.umich.edu
9523109Sstever@eecs.umich.edu    def __str__(self):
9533109Sstever@eecs.umich.edu        tup = [(self.ip >> i)  & 0xff for i in (24, 16, 8, 0)]
9543109Sstever@eecs.umich.edu        return '%d.%d.%d.%d' % tuple(tup)
9553109Sstever@eecs.umich.edu
9563109Sstever@eecs.umich.edu    def __eq__(self, other):
9573105Sstever@eecs.umich.edu        if isinstance(other, IpAddress):
9583105Sstever@eecs.umich.edu            return self.ip == other.ip
9593105Sstever@eecs.umich.edu        elif isinstance(other, str):
9603105Sstever@eecs.umich.edu            try:
9613105Sstever@eecs.umich.edu                return self.ip == convert.toIpAddress(other)
9623105Sstever@eecs.umich.edu            except:
9633105Sstever@eecs.umich.edu                return False
9643101Sstever@eecs.umich.edu        else:
9653101Sstever@eecs.umich.edu            return self.ip == other
9663101Sstever@eecs.umich.edu
9673101Sstever@eecs.umich.edu    def __ne__(self, other):
9683105Sstever@eecs.umich.edu        return not (self == other)
9693105Sstever@eecs.umich.edu
9703105Sstever@eecs.umich.edu    def verifyIp(self):
9713105Sstever@eecs.umich.edu        if self.ip < 0 or self.ip >= (1 << 32):
9723105Sstever@eecs.umich.edu            raise TypeError("invalid ip address %#08x" % self.ip)
9733105Sstever@eecs.umich.edu
9743105Sstever@eecs.umich.edu    def getValue(self):
9753105Sstever@eecs.umich.edu        from _m5.net import IpAddress
9763105Sstever@eecs.umich.edu        return IpAddress(self.ip)
9773105Sstever@eecs.umich.edu
9783105Sstever@eecs.umich.edu# When initializing an IpNetmask, pass in an existing IpNetmask, a string of
9793101Sstever@eecs.umich.edu# the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as
9803101Sstever@eecs.umich.edu# positional or keyword arguments.
9813101Sstever@eecs.umich.educlass IpNetmask(IpAddress):
9823105Sstever@eecs.umich.edu    cxx_type = 'Net::IpNetmask'
9833105Sstever@eecs.umich.edu    ex_str = "127.0.0.0/24"
9843101Sstever@eecs.umich.edu    cmd_line_settable = True
9853101Sstever@eecs.umich.edu
9863101Sstever@eecs.umich.edu    @classmethod
9873105Sstever@eecs.umich.edu    def cxx_predecls(cls, code):
9883105Sstever@eecs.umich.edu        code('#include "base/inet.hh"')
9893101Sstever@eecs.umich.edu
9903101Sstever@eecs.umich.edu    def __init__(self, *args, **kwargs):
9913101Sstever@eecs.umich.edu        def handle_kwarg(self, kwargs, key, elseVal = None):
9923101Sstever@eecs.umich.edu            if key in kwargs:
9933105Sstever@eecs.umich.edu                setattr(self, key, kwargs.pop(key))
9943105Sstever@eecs.umich.edu            elif elseVal:
9953101Sstever@eecs.umich.edu                setattr(self, key, elseVal)
9963101Sstever@eecs.umich.edu            else:
9973105Sstever@eecs.umich.edu                raise TypeError("No value set for %s" % key)
9983105Sstever@eecs.umich.edu
9993105Sstever@eecs.umich.edu        if len(args) == 0:
10003109Sstever@eecs.umich.edu            handle_kwarg(self, kwargs, 'ip')
10013109Sstever@eecs.umich.edu            handle_kwarg(self, kwargs, 'netmask')
10023109Sstever@eecs.umich.edu
10033109Sstever@eecs.umich.edu        elif len(args) == 1:
10043109Sstever@eecs.umich.edu            if kwargs:
10053109Sstever@eecs.umich.edu                if not 'ip' in kwargs and not 'netmask' in kwargs:
10063109Sstever@eecs.umich.edu                    raise TypeError("Invalid arguments")
10073109Sstever@eecs.umich.edu                handle_kwarg(self, kwargs, 'ip', args[0])
10083105Sstever@eecs.umich.edu                handle_kwarg(self, kwargs, 'netmask', args[0])
10093101Sstever@eecs.umich.edu            elif isinstance(args[0], IpNetmask):
10103101Sstever@eecs.umich.edu                self.ip = args[0].ip
10113101Sstever@eecs.umich.edu                self.netmask = args[0].netmask
10123101Sstever@eecs.umich.edu            else:
10133101Sstever@eecs.umich.edu                (self.ip, self.netmask) = convert.toIpNetmask(args[0])
10143101Sstever@eecs.umich.edu
10153101Sstever@eecs.umich.edu        elif len(args) == 2:
10163101Sstever@eecs.umich.edu            self.ip = args[0]
10174167Sbinkertn@umich.edu            self.netmask = args[1]
10183101Sstever@eecs.umich.edu        else:
10193101Sstever@eecs.umich.edu            raise TypeError("Too many arguments specified")
10203101Sstever@eecs.umich.edu
10213885Sbinkertn@umich.edu        if kwargs:
10223102Sstever@eecs.umich.edu            raise TypeError("Too many keywords: %s" % list(kwargs.keys()))
10233101Sstever@eecs.umich.edu
10243101Sstever@eecs.umich.edu        self.verify()
10253101Sstever@eecs.umich.edu
10263102Sstever@eecs.umich.edu    def __call__(self, value):
10273102Sstever@eecs.umich.edu        self.__init__(value)
10283624Sbinkertn@umich.edu        return value
1029
1030    def __str__(self):
1031        return "%s/%d" % (super(IpNetmask, self).__str__(), self.netmask)
1032
1033    def __eq__(self, other):
1034        if isinstance(other, IpNetmask):
1035            return self.ip == other.ip and self.netmask == other.netmask
1036        elif isinstance(other, str):
1037            try:
1038                return (self.ip, self.netmask) == convert.toIpNetmask(other)
1039            except:
1040                return False
1041        else:
1042            return False
1043
1044    def verify(self):
1045        self.verifyIp()
1046        if self.netmask < 0 or self.netmask > 32:
1047            raise TypeError("invalid netmask %d" % netmask)
1048
1049    def getValue(self):
1050        from _m5.net import IpNetmask
1051        return IpNetmask(self.ip, self.netmask)
1052
1053# When initializing an IpWithPort, pass in an existing IpWithPort, a string of
1054# the form "a.b.c.d:p", or an ip and port as positional or keyword arguments.
1055class IpWithPort(IpAddress):
1056    cxx_type = 'Net::IpWithPort'
1057    ex_str = "127.0.0.1:80"
1058    cmd_line_settable = True
1059
1060    @classmethod
1061    def cxx_predecls(cls, code):
1062        code('#include "base/inet.hh"')
1063
1064    def __init__(self, *args, **kwargs):
1065        def handle_kwarg(self, kwargs, key, elseVal = None):
1066            if key in kwargs:
1067                setattr(self, key, kwargs.pop(key))
1068            elif elseVal:
1069                setattr(self, key, elseVal)
1070            else:
1071                raise TypeError("No value set for %s" % key)
1072
1073        if len(args) == 0:
1074            handle_kwarg(self, kwargs, 'ip')
1075            handle_kwarg(self, kwargs, 'port')
1076
1077        elif len(args) == 1:
1078            if kwargs:
1079                if not 'ip' in kwargs and not 'port' in kwargs:
1080                    raise TypeError("Invalid arguments")
1081                handle_kwarg(self, kwargs, 'ip', args[0])
1082                handle_kwarg(self, kwargs, 'port', args[0])
1083            elif isinstance(args[0], IpWithPort):
1084                self.ip = args[0].ip
1085                self.port = args[0].port
1086            else:
1087                (self.ip, self.port) = convert.toIpWithPort(args[0])
1088
1089        elif len(args) == 2:
1090            self.ip = args[0]
1091            self.port = args[1]
1092        else:
1093            raise TypeError("Too many arguments specified")
1094
1095        if kwargs:
1096            raise TypeError("Too many keywords: %s" % list(kwargs.keys()))
1097
1098        self.verify()
1099
1100    def __call__(self, value):
1101        self.__init__(value)
1102        return value
1103
1104    def __str__(self):
1105        return "%s:%d" % (super(IpWithPort, self).__str__(), self.port)
1106
1107    def __eq__(self, other):
1108        if isinstance(other, IpWithPort):
1109            return self.ip == other.ip and self.port == other.port
1110        elif isinstance(other, str):
1111            try:
1112                return (self.ip, self.port) == convert.toIpWithPort(other)
1113            except:
1114                return False
1115        else:
1116            return False
1117
1118    def verify(self):
1119        self.verifyIp()
1120        if self.port < 0 or self.port > 0xffff:
1121            raise TypeError("invalid port %d" % self.port)
1122
1123    def getValue(self):
1124        from _m5.net import IpWithPort
1125        return IpWithPort(self.ip, self.port)
1126
1127time_formats = [ "%a %b %d %H:%M:%S %Z %Y",
1128                 "%a %b %d %H:%M:%S %Y",
1129                 "%Y/%m/%d %H:%M:%S",
1130                 "%Y/%m/%d %H:%M",
1131                 "%Y/%m/%d",
1132                 "%m/%d/%Y %H:%M:%S",
1133                 "%m/%d/%Y %H:%M",
1134                 "%m/%d/%Y",
1135                 "%m/%d/%y %H:%M:%S",
1136                 "%m/%d/%y %H:%M",
1137                 "%m/%d/%y"]
1138
1139
1140def parse_time(value):
1141    from time import gmtime, strptime, struct_time, time
1142    from datetime import datetime, date
1143
1144    if isinstance(value, struct_time):
1145        return value
1146
1147    if isinstance(value, (int, long)):
1148        return gmtime(value)
1149
1150    if isinstance(value, (datetime, date)):
1151        return value.timetuple()
1152
1153    if isinstance(value, str):
1154        if value in ('Now', 'Today'):
1155            return time.gmtime(time.time())
1156
1157        for format in time_formats:
1158            try:
1159                return strptime(value, format)
1160            except ValueError:
1161                pass
1162
1163    raise ValueError("Could not parse '%s' as a time" % value)
1164
1165class Time(ParamValue):
1166    cxx_type = 'tm'
1167
1168    @classmethod
1169    def cxx_predecls(cls, code):
1170        code('#include <time.h>')
1171
1172    def __init__(self, value):
1173        self.value = parse_time(value)
1174
1175    def __call__(self, value):
1176        self.__init__(value)
1177        return value
1178
1179    def getValue(self):
1180        from _m5.core import tm
1181        import calendar
1182
1183        return tm.gmtime(calendar.timegm(self.value))
1184
1185    def __str__(self):
1186        return time.asctime(self.value)
1187
1188    def ini_str(self):
1189        return str(self)
1190
1191    def get_config_as_dict(self):
1192        assert false
1193        return str(self)
1194
1195    @classmethod
1196    def cxx_ini_predecls(cls, code):
1197        code('#include <time.h>')
1198
1199    @classmethod
1200    def cxx_ini_parse(cls, code, src, dest, ret):
1201        code('char *_parse_ret = strptime((${src}).c_str(),')
1202        code('    "%a %b %d %H:%M:%S %Y", &(${dest}));')
1203        code('${ret} _parse_ret && *_parse_ret == \'\\0\';');
1204
1205# Enumerated types are a little more complex.  The user specifies the
1206# type as Enum(foo) where foo is either a list or dictionary of
1207# alternatives (typically strings, but not necessarily so).  (In the
1208# long run, the integer value of the parameter will be the list index
1209# or the corresponding dictionary value.  For now, since we only check
1210# that the alternative is valid and then spit it into a .ini file,
1211# there's not much point in using the dictionary.)
1212
1213# What Enum() must do is generate a new type encapsulating the
1214# provided list/dictionary so that specific values of the parameter
1215# can be instances of that type.  We define two hidden internal
1216# classes (_ListEnum and _DictEnum) to serve as base classes, then
1217# derive the new type from the appropriate base class on the fly.
1218
1219allEnums = {}
1220# Metaclass for Enum types
1221class MetaEnum(MetaParamValue):
1222    def __new__(mcls, name, bases, dict):
1223        assert name not in allEnums
1224
1225        cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict)
1226        allEnums[name] = cls
1227        return cls
1228
1229    def __init__(cls, name, bases, init_dict):
1230        if 'map' in init_dict:
1231            if not isinstance(cls.map, dict):
1232                raise TypeError("Enum-derived class attribute 'map' " \
1233                      "must be of type dict")
1234            # build list of value strings from map
1235            cls.vals = cls.map.keys()
1236            cls.vals.sort()
1237        elif 'vals' in init_dict:
1238            if not isinstance(cls.vals, list):
1239                raise TypeError("Enum-derived class attribute 'vals' " \
1240                      "must be of type list")
1241            # build string->value map from vals sequence
1242            cls.map = {}
1243            for idx,val in enumerate(cls.vals):
1244                cls.map[val] = idx
1245        else:
1246            raise TypeError("Enum-derived class must define "\
1247                  "attribute 'map' or 'vals'")
1248
1249        if cls.is_class:
1250            cls.cxx_type = '%s' % name
1251        else:
1252            cls.cxx_type = 'Enums::%s' % name
1253
1254        super(MetaEnum, cls).__init__(name, bases, init_dict)
1255
1256    # Generate C++ class declaration for this enum type.
1257    # Note that we wrap the enum in a class/struct to act as a namespace,
1258    # so that the enum strings can be brief w/o worrying about collisions.
1259    def cxx_decl(cls, code):
1260        wrapper_name = cls.wrapper_name
1261        wrapper = 'struct' if cls.wrapper_is_struct else 'namespace'
1262        name = cls.__name__ if cls.enum_name is None else cls.enum_name
1263        idem_macro = '__ENUM__%s__%s__' % (wrapper_name, name)
1264
1265        code('''\
1266#ifndef $idem_macro
1267#define $idem_macro
1268
1269''')
1270        if cls.is_class:
1271            code('''\
1272enum class $name {
1273''')
1274        else:
1275            code('''\
1276$wrapper $wrapper_name {
1277    enum $name {
1278''')
1279            code.indent(1)
1280        code.indent(1)
1281        for val in cls.vals:
1282            code('$val = ${{cls.map[val]}},')
1283        code('Num_$name = ${{len(cls.vals)}}')
1284        code.dedent(1)
1285        code('};')
1286
1287        if cls.is_class:
1288            code('''\
1289extern const char *${name}Strings[static_cast<int>(${name}::Num_${name})];
1290''')
1291        elif cls.wrapper_is_struct:
1292            code('static const char *${name}Strings[Num_${name}];')
1293        else:
1294            code('extern const char *${name}Strings[Num_${name}];')
1295
1296        if not cls.is_class:
1297            code.dedent(1)
1298            code('};')
1299
1300        code()
1301        code('#endif // $idem_macro')
1302
1303    def cxx_def(cls, code):
1304        wrapper_name = cls.wrapper_name
1305        file_name = cls.__name__
1306        name = cls.__name__ if cls.enum_name is None else cls.enum_name
1307
1308        code('#include "enums/$file_name.hh"')
1309        if cls.wrapper_is_struct:
1310            code('const char *${wrapper_name}::${name}Strings'
1311                '[Num_${name}] =')
1312        else:
1313            if cls.is_class:
1314                code('''\
1315const char *${name}Strings[static_cast<int>(${name}::Num_${name})] =
1316''')
1317            else:
1318                code('namespace Enums {')
1319                code.indent(1)
1320                code('const char *${name}Strings[Num_${name}] =')
1321
1322        code('{')
1323        code.indent(1)
1324        for val in cls.vals:
1325            code('"$val",')
1326        code.dedent(1)
1327        code('};')
1328
1329        if not cls.wrapper_is_struct and not cls.is_class:
1330            code.dedent(1)
1331            code('} // namespace $wrapper_name')
1332
1333
1334    def pybind_def(cls, code):
1335        name = cls.__name__
1336        enum_name = cls.__name__ if cls.enum_name is None else cls.enum_name
1337        wrapper_name = enum_name if cls.is_class else cls.wrapper_name
1338
1339        code('''#include "pybind11/pybind11.h"
1340#include "pybind11/stl.h"
1341
1342#include <sim/init.hh>
1343
1344namespace py = pybind11;
1345
1346static void
1347module_init(py::module &m_internal)
1348{
1349    py::module m = m_internal.def_submodule("enum_${name}");
1350
1351''')
1352        if cls.is_class:
1353            code('py::enum_<${enum_name}>(m, "enum_${name}")')
1354        else:
1355            code('py::enum_<${wrapper_name}::${enum_name}>(m, "enum_${name}")')
1356
1357        code.indent()
1358        code.indent()
1359        for val in cls.vals:
1360            code('.value("${val}", ${wrapper_name}::${val})')
1361        code('.value("Num_${name}", ${wrapper_name}::Num_${enum_name})')
1362        code('.export_values()')
1363        code(';')
1364        code.dedent()
1365
1366        code('}')
1367        code.dedent()
1368        code()
1369        code('static EmbeddedPyBind embed_enum("enum_${name}", module_init);')
1370
1371
1372# Base class for enum types.
1373class Enum(ParamValue):
1374    __metaclass__ = MetaEnum
1375    vals = []
1376    cmd_line_settable = True
1377
1378    # The name of the wrapping namespace or struct
1379    wrapper_name = 'Enums'
1380
1381    # If true, the enum is wrapped in a struct rather than a namespace
1382    wrapper_is_struct = False
1383
1384    is_class = False
1385
1386    # If not None, use this as the enum name rather than this class name
1387    enum_name = None
1388
1389    def __init__(self, value):
1390        if value not in self.map:
1391            raise TypeError("Enum param got bad value '%s' (not in %s)" \
1392                  % (value, self.vals))
1393        self.value = value
1394
1395    def __call__(self, value):
1396        self.__init__(value)
1397        return value
1398
1399    @classmethod
1400    def cxx_predecls(cls, code):
1401        code('#include "enums/$0.hh"', cls.__name__)
1402
1403    @classmethod
1404    def cxx_ini_parse(cls, code, src, dest, ret):
1405        code('if (false) {')
1406        for elem_name in cls.map.iterkeys():
1407            code('} else if (%s == "%s") {' % (src, elem_name))
1408            code.indent()
1409            code('%s = Enums::%s;' % (dest, elem_name))
1410            code('%s true;' % ret)
1411            code.dedent()
1412        code('} else {')
1413        code('    %s false;' % ret)
1414        code('}')
1415
1416    def getValue(self):
1417        import m5.internal.params
1418        e = getattr(m5.internal.params, "enum_%s" % self.__class__.__name__)
1419        return e(self.map[self.value])
1420
1421    def __str__(self):
1422        return self.value
1423
1424# This param will generate a scoped c++ enum and its python bindings.
1425class ScopedEnum(Enum):
1426    __metaclass__ = MetaEnum
1427    vals = []
1428    cmd_line_settable = True
1429
1430    # The name of the wrapping namespace or struct
1431    wrapper_name = None
1432
1433    # If true, the enum is wrapped in a struct rather than a namespace
1434    wrapper_is_struct = False
1435
1436    # If true, the generated enum is a scoped enum
1437    is_class = True
1438
1439    # If not None, use this as the enum name rather than this class name
1440    enum_name = None
1441
1442# how big does a rounding error need to be before we warn about it?
1443frequency_tolerance = 0.001  # 0.1%
1444
1445class TickParamValue(NumericParamValue):
1446    cxx_type = 'Tick'
1447    ex_str = "1MHz"
1448    cmd_line_settable = True
1449
1450    @classmethod
1451    def cxx_predecls(cls, code):
1452        code('#include "base/types.hh"')
1453
1454    def __call__(self, value):
1455        self.__init__(value)
1456        return value
1457
1458    def getValue(self):
1459        return long(self.value)
1460
1461    @classmethod
1462    def cxx_ini_predecls(cls, code):
1463        code('#include <sstream>')
1464
1465    # Ticks are expressed in seconds in JSON files and in plain
1466    # Ticks in .ini files.  Switch based on a config flag
1467    @classmethod
1468    def cxx_ini_parse(self, code, src, dest, ret):
1469        code('${ret} to_number(${src}, ${dest});')
1470
1471class Latency(TickParamValue):
1472    ex_str = "100ns"
1473
1474    def __init__(self, value):
1475        if isinstance(value, (Latency, Clock)):
1476            self.ticks = value.ticks
1477            self.value = value.value
1478        elif isinstance(value, Frequency):
1479            self.ticks = value.ticks
1480            self.value = 1.0 / value.value
1481        elif value.endswith('t'):
1482            self.ticks = True
1483            self.value = int(value[:-1])
1484        else:
1485            self.ticks = False
1486            self.value = convert.toLatency(value)
1487
1488    def __call__(self, value):
1489        self.__init__(value)
1490        return value
1491
1492    def __getattr__(self, attr):
1493        if attr in ('latency', 'period'):
1494            return self
1495        if attr == 'frequency':
1496            return Frequency(self)
1497        raise AttributeError("Latency object has no attribute '%s'" % attr)
1498
1499    def getValue(self):
1500        if self.ticks or self.value == 0:
1501            value = self.value
1502        else:
1503            value = ticks.fromSeconds(self.value)
1504        return long(value)
1505
1506    def config_value(self):
1507        return self.getValue()
1508
1509    # convert latency to ticks
1510    def ini_str(self):
1511        return '%d' % self.getValue()
1512
1513class Frequency(TickParamValue):
1514    ex_str = "1GHz"
1515
1516    def __init__(self, value):
1517        if isinstance(value, (Latency, Clock)):
1518            if value.value == 0:
1519                self.value = 0
1520            else:
1521                self.value = 1.0 / value.value
1522            self.ticks = value.ticks
1523        elif isinstance(value, Frequency):
1524            self.value = value.value
1525            self.ticks = value.ticks
1526        else:
1527            self.ticks = False
1528            self.value = convert.toFrequency(value)
1529
1530    def __call__(self, value):
1531        self.__init__(value)
1532        return value
1533
1534    def __getattr__(self, attr):
1535        if attr == 'frequency':
1536            return self
1537        if attr in ('latency', 'period'):
1538            return Latency(self)
1539        raise AttributeError("Frequency object has no attribute '%s'" % attr)
1540
1541    # convert latency to ticks
1542    def getValue(self):
1543        if self.ticks or self.value == 0:
1544            value = self.value
1545        else:
1546            value = ticks.fromSeconds(1.0 / self.value)
1547        return long(value)
1548
1549    def config_value(self):
1550        return self.getValue()
1551
1552    def ini_str(self):
1553        return '%d' % self.getValue()
1554
1555# A generic Frequency and/or Latency value. Value is stored as a
1556# latency, just like Latency and Frequency.
1557class Clock(TickParamValue):
1558    def __init__(self, value):
1559        if isinstance(value, (Latency, Clock)):
1560            self.ticks = value.ticks
1561            self.value = value.value
1562        elif isinstance(value, Frequency):
1563            self.ticks = value.ticks
1564            self.value = 1.0 / value.value
1565        elif value.endswith('t'):
1566            self.ticks = True
1567            self.value = int(value[:-1])
1568        else:
1569            self.ticks = False
1570            self.value = convert.anyToLatency(value)
1571
1572    def __call__(self, value):
1573        self.__init__(value)
1574        return value
1575
1576    def __str__(self):
1577        return "%s" % Latency(self)
1578
1579    def __getattr__(self, attr):
1580        if attr == 'frequency':
1581            return Frequency(self)
1582        if attr in ('latency', 'period'):
1583            return Latency(self)
1584        raise AttributeError("Frequency object has no attribute '%s'" % attr)
1585
1586    def getValue(self):
1587        return self.period.getValue()
1588
1589    def config_value(self):
1590        return self.period.config_value()
1591
1592    def ini_str(self):
1593        return self.period.ini_str()
1594
1595class Voltage(Float):
1596    ex_str = "1V"
1597
1598    def __new__(cls, value):
1599        value = convert.toVoltage(value)
1600        return super(cls, Voltage).__new__(cls, value)
1601
1602    def __init__(self, value):
1603        value = convert.toVoltage(value)
1604        super(Voltage, self).__init__(value)
1605
1606class Current(Float):
1607    ex_str = "1mA"
1608
1609    def __new__(cls, value):
1610        value = convert.toCurrent(value)
1611        return super(cls, Current).__new__(cls, value)
1612
1613    def __init__(self, value):
1614        value = convert.toCurrent(value)
1615        super(Current, self).__init__(value)
1616
1617class Energy(Float):
1618    ex_str = "1pJ"
1619
1620    def __new__(cls, value):
1621        value = convert.toEnergy(value)
1622        return super(cls, Energy).__new__(cls, value)
1623
1624    def __init__(self, value):
1625        value = convert.toEnergy(value)
1626        super(Energy, self).__init__(value)
1627
1628class NetworkBandwidth(float,ParamValue):
1629    cxx_type = 'float'
1630    ex_str = "1Gbps"
1631    cmd_line_settable = True
1632
1633    def __new__(cls, value):
1634        # convert to bits per second
1635        val = convert.toNetworkBandwidth(value)
1636        return super(cls, NetworkBandwidth).__new__(cls, val)
1637
1638    def __str__(self):
1639        return str(self.val)
1640
1641    def __call__(self, value):
1642        val = convert.toNetworkBandwidth(value)
1643        self.__init__(val)
1644        return value
1645
1646    def getValue(self):
1647        # convert to seconds per byte
1648        value = 8.0 / float(self)
1649        # convert to ticks per byte
1650        value = ticks.fromSeconds(value)
1651        return float(value)
1652
1653    def ini_str(self):
1654        return '%f' % self.getValue()
1655
1656    def config_value(self):
1657        return '%f' % self.getValue()
1658
1659    @classmethod
1660    def cxx_ini_predecls(cls, code):
1661        code('#include <sstream>')
1662
1663    @classmethod
1664    def cxx_ini_parse(self, code, src, dest, ret):
1665        code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
1666
1667class MemoryBandwidth(float,ParamValue):
1668    cxx_type = 'float'
1669    ex_str = "1GB/s"
1670    cmd_line_settable = True
1671
1672    def __new__(cls, value):
1673        # convert to bytes per second
1674        val = convert.toMemoryBandwidth(value)
1675        return super(cls, MemoryBandwidth).__new__(cls, val)
1676
1677    def __call__(self, value):
1678        val = convert.toMemoryBandwidth(value)
1679        self.__init__(val)
1680        return value
1681
1682    def getValue(self):
1683        # convert to seconds per byte
1684        value = float(self)
1685        if value:
1686            value = 1.0 / float(self)
1687        # convert to ticks per byte
1688        value = ticks.fromSeconds(value)
1689        return float(value)
1690
1691    def ini_str(self):
1692        return '%f' % self.getValue()
1693
1694    def config_value(self):
1695        return '%f' % self.getValue()
1696
1697    @classmethod
1698    def cxx_ini_predecls(cls, code):
1699        code('#include <sstream>')
1700
1701    @classmethod
1702    def cxx_ini_parse(self, code, src, dest, ret):
1703        code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
1704
1705#
1706# "Constants"... handy aliases for various values.
1707#
1708
1709# Special class for NULL pointers.  Note the special check in
1710# make_param_value() above that lets these be assigned where a
1711# SimObject is required.
1712# only one copy of a particular node
1713class NullSimObject(object):
1714    __metaclass__ = Singleton
1715    _name = 'Null'
1716
1717    def __call__(cls):
1718        return cls
1719
1720    def _instantiate(self, parent = None, path = ''):
1721        pass
1722
1723    def ini_str(self):
1724        return 'Null'
1725
1726    def unproxy(self, base):
1727        return self
1728
1729    def set_path(self, parent, name):
1730        pass
1731
1732    def set_parent(self, parent, name):
1733        pass
1734
1735    def clear_parent(self, old_parent):
1736        pass
1737
1738    def descendants(self):
1739        return
1740        yield None
1741
1742    def get_config_as_dict(self):
1743        return {}
1744
1745    def __str__(self):
1746        return self._name
1747
1748    def config_value(self):
1749        return None
1750
1751    def getValue(self):
1752        return None
1753
1754# The only instance you'll ever need...
1755NULL = NullSimObject()
1756
1757def isNullPointer(value):
1758    return isinstance(value, NullSimObject)
1759
1760# Some memory range specifications use this as a default upper bound.
1761MaxAddr = Addr.max
1762MaxTick = Tick.max
1763AllMemory = AddrRange(0, MaxAddr)
1764
1765
1766#####################################################################
1767#
1768# Port objects
1769#
1770# Ports are used to interconnect objects in the memory system.
1771#
1772#####################################################################
1773
1774# Port reference: encapsulates a reference to a particular port on a
1775# particular SimObject.
1776class PortRef(object):
1777    def __init__(self, simobj, name, role):
1778        assert(isSimObject(simobj) or isSimObjectClass(simobj))
1779        self.simobj = simobj
1780        self.name = name
1781        self.role = role
1782        self.peer = None   # not associated with another port yet
1783        self.ccConnected = False # C++ port connection done?
1784        self.index = -1  # always -1 for non-vector ports
1785
1786    def __str__(self):
1787        return '%s.%s' % (self.simobj, self.name)
1788
1789    def __len__(self):
1790        # Return the number of connected ports, i.e. 0 is we have no
1791        # peer and 1 if we do.
1792        return int(self.peer != None)
1793
1794    # for config.ini, print peer's name (not ours)
1795    def ini_str(self):
1796        return str(self.peer)
1797
1798    # for config.json
1799    def get_config_as_dict(self):
1800        return {'role' : self.role, 'peer' : str(self.peer)}
1801
1802    def __getattr__(self, attr):
1803        if attr == 'peerObj':
1804            # shorthand for proxies
1805            return self.peer.simobj
1806        raise AttributeError("'%s' object has no attribute '%s'" % \
1807              (self.__class__.__name__, attr))
1808
1809    # Full connection is symmetric (both ways).  Called via
1810    # SimObject.__setattr__ as a result of a port assignment, e.g.,
1811    # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
1812    # e.g., "obj1.portA[3] = obj2.portB".
1813    def connect(self, other):
1814        if isinstance(other, VectorPortRef):
1815            # reference to plain VectorPort is implicit append
1816            other = other._get_next()
1817        if self.peer and not proxy.isproxy(self.peer):
1818            fatal("Port %s is already connected to %s, cannot connect %s\n",
1819                  self, self.peer, other);
1820        self.peer = other
1821        if proxy.isproxy(other):
1822            other.set_param_desc(PortParamDesc())
1823        elif isinstance(other, PortRef):
1824            if other.peer is not self:
1825                other.connect(self)
1826        else:
1827            raise TypeError("assigning non-port reference '%s' to port '%s'" \
1828                  % (other, self))
1829
1830    # Allow a master/slave port pair to be spliced between
1831    # a port and its connected peer. Useful operation for connecting
1832    # instrumentation structures into a system when it is necessary
1833    # to connect the instrumentation after the full system has been
1834    # constructed.
1835    def splice(self, new_master_peer, new_slave_peer):
1836        if not self.peer or proxy.isproxy(self.peer):
1837            fatal("Port %s not connected, cannot splice in new peers\n", self)
1838
1839        if not isinstance(new_master_peer, PortRef) or \
1840           not isinstance(new_slave_peer, PortRef):
1841            raise TypeError(
1842                  "Splicing non-port references '%s','%s' to port '%s'" % \
1843                  (new_master_peer, new_slave_peer, self))
1844
1845        old_peer = self.peer
1846        if self.role == 'SLAVE':
1847            self.peer = new_master_peer
1848            old_peer.peer = new_slave_peer
1849            new_master_peer.connect(self)
1850            new_slave_peer.connect(old_peer)
1851        elif self.role == 'MASTER':
1852            self.peer = new_slave_peer
1853            old_peer.peer = new_master_peer
1854            new_slave_peer.connect(self)
1855            new_master_peer.connect(old_peer)
1856        else:
1857            panic("Port %s has unknown role, "+\
1858                  "cannot splice in new peers\n", self)
1859
1860    def clone(self, simobj, memo):
1861        if self in memo:
1862            return memo[self]
1863        newRef = copy.copy(self)
1864        memo[self] = newRef
1865        newRef.simobj = simobj
1866        assert(isSimObject(newRef.simobj))
1867        if self.peer and not proxy.isproxy(self.peer):
1868            peerObj = self.peer.simobj(_memo=memo)
1869            newRef.peer = self.peer.clone(peerObj, memo)
1870            assert(not isinstance(newRef.peer, VectorPortRef))
1871        return newRef
1872
1873    def unproxy(self, simobj):
1874        assert(simobj is self.simobj)
1875        if proxy.isproxy(self.peer):
1876            try:
1877                realPeer = self.peer.unproxy(self.simobj)
1878            except:
1879                print("Error in unproxying port '%s' of %s" %
1880                      (self.name, self.simobj.path()))
1881                raise
1882            self.connect(realPeer)
1883
1884    # Call C++ to create corresponding port connection between C++ objects
1885    def ccConnect(self):
1886        from _m5.pyobject import connectPorts
1887
1888        if self.ccConnected: # already done this
1889            return
1890
1891        peer = self.peer
1892        if not self.peer: # nothing to connect to
1893            return
1894
1895        # check that we connect a master to a slave
1896        if self.role == peer.role:
1897            raise TypeError(
1898                "cannot connect '%s' and '%s' due to identical role '%s'" % \
1899                (peer, self, self.role))
1900
1901        if self.role == 'SLAVE':
1902            # do nothing and let the master take care of it
1903            return
1904
1905        try:
1906            # self is always the master and peer the slave
1907            connectPorts(self.simobj.getCCObject(), self.name, self.index,
1908                         peer.simobj.getCCObject(), peer.name, peer.index)
1909        except:
1910            print("Error connecting port %s.%s to %s.%s" %
1911                  (self.simobj.path(), self.name,
1912                   peer.simobj.path(), peer.name))
1913            raise
1914        self.ccConnected = True
1915        peer.ccConnected = True
1916
1917# A reference to an individual element of a VectorPort... much like a
1918# PortRef, but has an index.
1919class VectorPortElementRef(PortRef):
1920    def __init__(self, simobj, name, role, index):
1921        PortRef.__init__(self, simobj, name, role)
1922        self.index = index
1923
1924    def __str__(self):
1925        return '%s.%s[%d]' % (self.simobj, self.name, self.index)
1926
1927# A reference to a complete vector-valued port (not just a single element).
1928# Can be indexed to retrieve individual VectorPortElementRef instances.
1929class VectorPortRef(object):
1930    def __init__(self, simobj, name, role):
1931        assert(isSimObject(simobj) or isSimObjectClass(simobj))
1932        self.simobj = simobj
1933        self.name = name
1934        self.role = role
1935        self.elements = []
1936
1937    def __str__(self):
1938        return '%s.%s[:]' % (self.simobj, self.name)
1939
1940    def __len__(self):
1941        # Return the number of connected peers, corresponding the the
1942        # length of the elements.
1943        return len(self.elements)
1944
1945    # for config.ini, print peer's name (not ours)
1946    def ini_str(self):
1947        return ' '.join([el.ini_str() for el in self.elements])
1948
1949    # for config.json
1950    def get_config_as_dict(self):
1951        return {'role' : self.role,
1952                'peer' : [el.ini_str() for el in self.elements]}
1953
1954    def __getitem__(self, key):
1955        if not isinstance(key, int):
1956            raise TypeError("VectorPort index must be integer")
1957        if key >= len(self.elements):
1958            # need to extend list
1959            ext = [VectorPortElementRef(self.simobj, self.name, self.role, i)
1960                   for i in range(len(self.elements), key+1)]
1961            self.elements.extend(ext)
1962        return self.elements[key]
1963
1964    def _get_next(self):
1965        return self[len(self.elements)]
1966
1967    def __setitem__(self, key, value):
1968        if not isinstance(key, int):
1969            raise TypeError("VectorPort index must be integer")
1970        self[key].connect(value)
1971
1972    def connect(self, other):
1973        if isinstance(other, (list, tuple)):
1974            # Assign list of port refs to vector port.
1975            # For now, append them... not sure if that's the right semantics
1976            # or if it should replace the current vector.
1977            for ref in other:
1978                self._get_next().connect(ref)
1979        else:
1980            # scalar assignment to plain VectorPort is implicit append
1981            self._get_next().connect(other)
1982
1983    def clone(self, simobj, memo):
1984        if self in memo:
1985            return memo[self]
1986        newRef = copy.copy(self)
1987        memo[self] = newRef
1988        newRef.simobj = simobj
1989        assert(isSimObject(newRef.simobj))
1990        newRef.elements = [el.clone(simobj, memo) for el in self.elements]
1991        return newRef
1992
1993    def unproxy(self, simobj):
1994        [el.unproxy(simobj) for el in self.elements]
1995
1996    def ccConnect(self):
1997        [el.ccConnect() for el in self.elements]
1998
1999# Port description object.  Like a ParamDesc object, this represents a
2000# logical port in the SimObject class, not a particular port on a
2001# SimObject instance.  The latter are represented by PortRef objects.
2002class Port(object):
2003    # Generate a PortRef for this port on the given SimObject with the
2004    # given name
2005    def makeRef(self, simobj):
2006        return PortRef(simobj, self.name, self.role)
2007
2008    # Connect an instance of this port (on the given SimObject with
2009    # the given name) with the port described by the supplied PortRef
2010    def connect(self, simobj, ref):
2011        self.makeRef(simobj).connect(ref)
2012
2013    # No need for any pre-declarations at the moment as we merely rely
2014    # on an unsigned int.
2015    def cxx_predecls(self, code):
2016        pass
2017
2018    def pybind_predecls(self, code):
2019        cls.cxx_predecls(self, code)
2020
2021    # Declare an unsigned int with the same name as the port, that
2022    # will eventually hold the number of connected ports (and thus the
2023    # number of elements for a VectorPort).
2024    def cxx_decl(self, code):
2025        code('unsigned int port_${{self.name}}_connection_count;')
2026
2027class MasterPort(Port):
2028    # MasterPort("description")
2029    def __init__(self, *args):
2030        if len(args) == 1:
2031            self.desc = args[0]
2032            self.role = 'MASTER'
2033        else:
2034            raise TypeError('wrong number of arguments')
2035
2036class SlavePort(Port):
2037    # SlavePort("description")
2038    def __init__(self, *args):
2039        if len(args) == 1:
2040            self.desc = args[0]
2041            self.role = 'SLAVE'
2042        else:
2043            raise TypeError('wrong number of arguments')
2044
2045# VectorPort description object.  Like Port, but represents a vector
2046# of connections (e.g., as on a XBar).
2047class VectorPort(Port):
2048    def __init__(self, *args):
2049        self.isVec = True
2050
2051    def makeRef(self, simobj):
2052        return VectorPortRef(simobj, self.name, self.role)
2053
2054class VectorMasterPort(VectorPort):
2055    # VectorMasterPort("description")
2056    def __init__(self, *args):
2057        if len(args) == 1:
2058            self.desc = args[0]
2059            self.role = 'MASTER'
2060            VectorPort.__init__(self, *args)
2061        else:
2062            raise TypeError('wrong number of arguments')
2063
2064class VectorSlavePort(VectorPort):
2065    # VectorSlavePort("description")
2066    def __init__(self, *args):
2067        if len(args) == 1:
2068            self.desc = args[0]
2069            self.role = 'SLAVE'
2070            VectorPort.__init__(self, *args)
2071        else:
2072            raise TypeError('wrong number of arguments')
2073
2074# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
2075# proxy objects (via set_param_desc()) so that proxy error messages
2076# make sense.
2077class PortParamDesc(object):
2078    __metaclass__ = Singleton
2079
2080    ptype_str = 'Port'
2081    ptype = Port
2082
2083baseEnums = allEnums.copy()
2084baseParams = allParams.copy()
2085
2086def clear():
2087    global allEnums, allParams
2088
2089    allEnums = baseEnums.copy()
2090    allParams = baseParams.copy()
2091
2092__all__ = ['Param', 'VectorParam',
2093           'Enum', 'ScopedEnum', 'Bool', 'String', 'Float',
2094           'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
2095           'Int32', 'UInt32', 'Int64', 'UInt64',
2096           'Counter', 'Addr', 'Tick', 'Percent',
2097           'TcpPort', 'UdpPort', 'EthernetAddr',
2098           'IpAddress', 'IpNetmask', 'IpWithPort',
2099           'MemorySize', 'MemorySize32',
2100           'Latency', 'Frequency', 'Clock', 'Voltage', 'Current', 'Energy',
2101           'NetworkBandwidth', 'MemoryBandwidth',
2102           'AddrRange',
2103           'MaxAddr', 'MaxTick', 'AllMemory',
2104           'Time',
2105           'NextEthernetAddr', 'NULL',
2106           'MasterPort', 'SlavePort',
2107           'VectorMasterPort', 'VectorSlavePort']
2108
2109import SimObject
2110