params.py revision 10405
19537Satgutier@umich.edu# Copyright (c) 2012-2014 ARM Limited
29537Satgutier@umich.edu# All rights reserved.
39537Satgutier@umich.edu#
49537Satgutier@umich.edu# The license below extends only to copyright in the software and shall
59537Satgutier@umich.edu# not be construed as granting a license to any other intellectual
69537Satgutier@umich.edu# property including but not limited to intellectual property relating
79537Satgutier@umich.edu# to a hardware implementation of the functionality of the software
89537Satgutier@umich.edu# licensed hereunder.  You may use the software subject to the license
99537Satgutier@umich.edu# terms below provided that you ensure that this notice is replicated
109537Satgutier@umich.edu# unmodified and in its entirety in all distributions of the software,
119537Satgutier@umich.edu# modified or unmodified, in source code or in binary form.
129537Satgutier@umich.edu#
139537Satgutier@umich.edu# Copyright (c) 2004-2006 The Regents of The University of Michigan
149537Satgutier@umich.edu# Copyright (c) 2010-2011 Advanced Micro Devices, Inc.
159537Satgutier@umich.edu# All rights reserved.
169537Satgutier@umich.edu#
179537Satgutier@umich.edu# Redistribution and use in source and binary forms, with or without
189537Satgutier@umich.edu# modification, are permitted provided that the following conditions are
199537Satgutier@umich.edu# met: redistributions of source code must retain the above copyright
209537Satgutier@umich.edu# notice, this list of conditions and the following disclaimer;
219537Satgutier@umich.edu# redistributions in binary form must reproduce the above copyright
229537Satgutier@umich.edu# notice, this list of conditions and the following disclaimer in the
239537Satgutier@umich.edu# documentation and/or other materials provided with the distribution;
249537Satgutier@umich.edu# neither the name of the copyright holders nor the names of its
259537Satgutier@umich.edu# contributors may be used to endorse or promote products derived from
269537Satgutier@umich.edu# this software without specific prior written permission.
279537Satgutier@umich.edu#
289537Satgutier@umich.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
299537Satgutier@umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
309537Satgutier@umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
319537Satgutier@umich.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
329537Satgutier@umich.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
339537Satgutier@umich.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
349537Satgutier@umich.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
359537Satgutier@umich.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
369537Satgutier@umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
379537Satgutier@umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
389537Satgutier@umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
399537Satgutier@umich.edu#
409537Satgutier@umich.edu# Authors: Steve Reinhardt
419537Satgutier@umich.edu#          Nathan Binkert
429537Satgutier@umich.edu#          Gabe Black
439537Satgutier@umich.edu#          Andreas Hansson
449537Satgutier@umich.edu
459537Satgutier@umich.edu#####################################################################
469537Satgutier@umich.edu#
479537Satgutier@umich.edu# Parameter description classes
489537Satgutier@umich.edu#
499537Satgutier@umich.edu# The _params dictionary in each class maps parameter names to either
509537Satgutier@umich.edu# a Param or a VectorParam object.  These objects contain the
519537Satgutier@umich.edu# parameter description string, the parameter type, and the default
529537Satgutier@umich.edu# value (if any).  The convert() method on these objects is used to
539537Satgutier@umich.edu# force whatever value is assigned to the parameter to the appropriate
549537Satgutier@umich.edu# type.
559537Satgutier@umich.edu#
569537Satgutier@umich.edu# Note that the default values are loaded into the class's attribute
579537Satgutier@umich.edu# space when the parameter dictionary is initialized (in
589537Satgutier@umich.edu# MetaSimObject._new_param()); after that point they aren't used.
599537Satgutier@umich.edu#
609537Satgutier@umich.edu#####################################################################
619537Satgutier@umich.edu
629537Satgutier@umich.eduimport copy
639537Satgutier@umich.eduimport datetime
649537Satgutier@umich.eduimport re
659537Satgutier@umich.eduimport sys
669537Satgutier@umich.eduimport time
679537Satgutier@umich.eduimport math
689537Satgutier@umich.edu
699537Satgutier@umich.eduimport proxy
709537Satgutier@umich.eduimport ticks
719537Satgutier@umich.edufrom util import *
729537Satgutier@umich.edu
739537Satgutier@umich.edudef isSimObject(*args, **kwargs):
749537Satgutier@umich.edu    return SimObject.isSimObject(*args, **kwargs)
759537Satgutier@umich.edu
769537Satgutier@umich.edudef isSimObjectSequence(*args, **kwargs):
779537Satgutier@umich.edu    return SimObject.isSimObjectSequence(*args, **kwargs)
789537Satgutier@umich.edu
799537Satgutier@umich.edudef isSimObjectClass(*args, **kwargs):
809537Satgutier@umich.edu    return SimObject.isSimObjectClass(*args, **kwargs)
819537Satgutier@umich.edu
829537Satgutier@umich.eduallParams = {}
839537Satgutier@umich.edu
849537Satgutier@umich.educlass MetaParamValue(type):
859537Satgutier@umich.edu    def __new__(mcls, name, bases, dct):
869537Satgutier@umich.edu        cls = super(MetaParamValue, mcls).__new__(mcls, name, bases, dct)
879537Satgutier@umich.edu        assert name not in allParams
889537Satgutier@umich.edu        allParams[name] = cls
899537Satgutier@umich.edu        return cls
909537Satgutier@umich.edu
919537Satgutier@umich.edu
929537Satgutier@umich.edu# Dummy base class to identify types that are legitimate for SimObject
939537Satgutier@umich.edu# parameters.
949537Satgutier@umich.educlass ParamValue(object):
959537Satgutier@umich.edu    __metaclass__ = MetaParamValue
969537Satgutier@umich.edu    cmd_line_settable = False
979537Satgutier@umich.edu
989537Satgutier@umich.edu    # Generate the code needed as a prerequisite for declaring a C++
999537Satgutier@umich.edu    # object of this type.  Typically generates one or more #include
1009537Satgutier@umich.edu    # statements.  Used when declaring parameters of this type.
1019537Satgutier@umich.edu    @classmethod
1029537Satgutier@umich.edu    def cxx_predecls(cls, code):
1039537Satgutier@umich.edu        pass
1049537Satgutier@umich.edu
1059537Satgutier@umich.edu    # Generate the code needed as a prerequisite for including a
1069537Satgutier@umich.edu    # reference to a C++ object of this type in a SWIG .i file.
1079537Satgutier@umich.edu    # Typically generates one or more %import or %include statements.
1089537Satgutier@umich.edu    @classmethod
1099537Satgutier@umich.edu    def swig_predecls(cls, code):
1109537Satgutier@umich.edu        pass
1119537Satgutier@umich.edu
1129537Satgutier@umich.edu    # default for printing to .ini file is regular string conversion.
1139537Satgutier@umich.edu    # will be overridden in some cases
1149537Satgutier@umich.edu    def ini_str(self):
1159537Satgutier@umich.edu        return str(self)
1169537Satgutier@umich.edu
1179537Satgutier@umich.edu    # default for printing to .json file is regular string conversion.
1189537Satgutier@umich.edu    # will be overridden in some cases, mostly to use native Python
1199537Satgutier@umich.edu    # types where there are similar JSON types
1209537Satgutier@umich.edu    def config_value(self):
1219537Satgutier@umich.edu        return str(self)
1229537Satgutier@umich.edu
1239537Satgutier@umich.edu    # allows us to blithely call unproxy() on things without checking
1249537Satgutier@umich.edu    # if they're really proxies or not
1259537Satgutier@umich.edu    def unproxy(self, base):
1269537Satgutier@umich.edu        return self
1279537Satgutier@umich.edu
1289537Satgutier@umich.edu    # Produce a human readable version of the stored value
1299537Satgutier@umich.edu    def pretty_print(self, value):
1309537Satgutier@umich.edu        return str(value)
1319537Satgutier@umich.edu
1329537Satgutier@umich.edu# Regular parameter description.
1339537Satgutier@umich.educlass ParamDesc(object):
1349537Satgutier@umich.edu    def __init__(self, ptype_str, ptype, *args, **kwargs):
1359537Satgutier@umich.edu        self.ptype_str = ptype_str
1369537Satgutier@umich.edu        # remember ptype only if it is provided
1379537Satgutier@umich.edu        if ptype != None:
1389537Satgutier@umich.edu            self.ptype = ptype
1399537Satgutier@umich.edu
1409537Satgutier@umich.edu        if args:
1419537Satgutier@umich.edu            if len(args) == 1:
1429537Satgutier@umich.edu                self.desc = args[0]
1439537Satgutier@umich.edu            elif len(args) == 2:
1449537Satgutier@umich.edu                self.default = args[0]
1459537Satgutier@umich.edu                self.desc = args[1]
1469537Satgutier@umich.edu            else:
1479537Satgutier@umich.edu                raise TypeError, 'too many arguments'
1489537Satgutier@umich.edu
1499537Satgutier@umich.edu        if kwargs.has_key('desc'):
1509537Satgutier@umich.edu            assert(not hasattr(self, 'desc'))
1519537Satgutier@umich.edu            self.desc = kwargs['desc']
1529537Satgutier@umich.edu            del kwargs['desc']
1539537Satgutier@umich.edu
1549537Satgutier@umich.edu        if kwargs.has_key('default'):
1559537Satgutier@umich.edu            assert(not hasattr(self, 'default'))
1569537Satgutier@umich.edu            self.default = kwargs['default']
1579537Satgutier@umich.edu            del kwargs['default']
1589537Satgutier@umich.edu
1599537Satgutier@umich.edu        if kwargs:
1609537Satgutier@umich.edu            raise TypeError, 'extra unknown kwargs %s' % kwargs
1619537Satgutier@umich.edu
1629537Satgutier@umich.edu        if not hasattr(self, 'desc'):
1639537Satgutier@umich.edu            raise TypeError, 'desc attribute missing'
1649537Satgutier@umich.edu
1659537Satgutier@umich.edu    def __getattr__(self, attr):
1669537Satgutier@umich.edu        if attr == 'ptype':
1679537Satgutier@umich.edu            ptype = SimObject.allClasses[self.ptype_str]
1689537Satgutier@umich.edu            assert isSimObjectClass(ptype)
1699537Satgutier@umich.edu            self.ptype = ptype
1709537Satgutier@umich.edu            return ptype
1719537Satgutier@umich.edu
1729537Satgutier@umich.edu        raise AttributeError, "'%s' object has no attribute '%s'" % \
1739537Satgutier@umich.edu              (type(self).__name__, attr)
1749537Satgutier@umich.edu
1759537Satgutier@umich.edu    def example_str(self):
1769537Satgutier@umich.edu        if hasattr(self.ptype, "ex_str"):
1779537Satgutier@umich.edu            return self.ptype.ex_str
1789537Satgutier@umich.edu        else:
1799537Satgutier@umich.edu            return self.ptype_str
1809537Satgutier@umich.edu
1819537Satgutier@umich.edu    # Is the param available to be exposed on the command line
1829537Satgutier@umich.edu    def isCmdLineSettable(self):
1839537Satgutier@umich.edu        if hasattr(self.ptype, "cmd_line_settable"):
1849537Satgutier@umich.edu            return self.ptype.cmd_line_settable
1859537Satgutier@umich.edu        else:
1869537Satgutier@umich.edu            return False
1879537Satgutier@umich.edu
1889537Satgutier@umich.edu    def convert(self, value):
1899537Satgutier@umich.edu        if isinstance(value, proxy.BaseProxy):
1909537Satgutier@umich.edu            value.set_param_desc(self)
1919537Satgutier@umich.edu            return value
1929537Satgutier@umich.edu        if not hasattr(self, 'ptype') and isNullPointer(value):
1939537Satgutier@umich.edu            # deferred evaluation of SimObject; continue to defer if
1949537Satgutier@umich.edu            # we're just assigning a null pointer
1959537Satgutier@umich.edu            return value
1969537Satgutier@umich.edu        if isinstance(value, self.ptype):
1979537Satgutier@umich.edu            return value
1989537Satgutier@umich.edu        if isNullPointer(value) and isSimObjectClass(self.ptype):
1999537Satgutier@umich.edu            return value
2009537Satgutier@umich.edu        return self.ptype(value)
2019537Satgutier@umich.edu
2029537Satgutier@umich.edu    def pretty_print(self, value):
2039537Satgutier@umich.edu        if isinstance(value, proxy.BaseProxy):
2049537Satgutier@umich.edu           return str(value)
2059537Satgutier@umich.edu        if isNullPointer(value):
2069537Satgutier@umich.edu           return NULL
2079537Satgutier@umich.edu        return self.ptype(value).pretty_print(value)
2089537Satgutier@umich.edu
2099537Satgutier@umich.edu    def cxx_predecls(self, code):
2109537Satgutier@umich.edu        code('#include <cstddef>')
2119537Satgutier@umich.edu        self.ptype.cxx_predecls(code)
2129537Satgutier@umich.edu
2139537Satgutier@umich.edu    def swig_predecls(self, code):
2149537Satgutier@umich.edu        self.ptype.swig_predecls(code)
2159537Satgutier@umich.edu
2169537Satgutier@umich.edu    def cxx_decl(self, code):
2179537Satgutier@umich.edu        code('${{self.ptype.cxx_type}} ${{self.name}};')
2189537Satgutier@umich.edu
2199537Satgutier@umich.edu# Vector-valued parameter description.  Just like ParamDesc, except
2209537Satgutier@umich.edu# that the value is a vector (list) of the specified type instead of a
2219537Satgutier@umich.edu# single value.
2229537Satgutier@umich.edu
2239537Satgutier@umich.educlass VectorParamValue(list):
2249537Satgutier@umich.edu    __metaclass__ = MetaParamValue
2259537Satgutier@umich.edu    def __setattr__(self, attr, value):
2269537Satgutier@umich.edu        raise AttributeError, \
2279537Satgutier@umich.edu              "Not allowed to set %s on '%s'" % (attr, type(self).__name__)
2289537Satgutier@umich.edu
2299537Satgutier@umich.edu    def config_value(self):
2309537Satgutier@umich.edu        return [v.config_value() for v in self]
2319537Satgutier@umich.edu
2329537Satgutier@umich.edu    def ini_str(self):
2339537Satgutier@umich.edu        return ' '.join([v.ini_str() for v in self])
2349537Satgutier@umich.edu
2359537Satgutier@umich.edu    def getValue(self):
2369537Satgutier@umich.edu        return [ v.getValue() for v in self ]
2379537Satgutier@umich.edu
2389537Satgutier@umich.edu    def unproxy(self, base):
2399537Satgutier@umich.edu        if len(self) == 1 and isinstance(self[0], proxy.AllProxy):
2409537Satgutier@umich.edu            return self[0].unproxy(base)
2419537Satgutier@umich.edu        else:
2429537Satgutier@umich.edu             return [v.unproxy(base) for v in self]
2439537Satgutier@umich.edu
2449537Satgutier@umich.educlass SimObjectVector(VectorParamValue):
2459537Satgutier@umich.edu    # support clone operation
2469537Satgutier@umich.edu    def __call__(self, **kwargs):
2479537Satgutier@umich.edu        return SimObjectVector([v(**kwargs) for v in self])
2489537Satgutier@umich.edu
2499537Satgutier@umich.edu    def clear_parent(self, old_parent):
2509537Satgutier@umich.edu        for v in self:
2519537Satgutier@umich.edu            v.clear_parent(old_parent)
2529537Satgutier@umich.edu
2539537Satgutier@umich.edu    def set_parent(self, parent, name):
2549537Satgutier@umich.edu        if len(self) == 1:
2559537Satgutier@umich.edu            self[0].set_parent(parent, name)
2569537Satgutier@umich.edu        else:
2579537Satgutier@umich.edu            width = int(math.ceil(math.log(len(self))/math.log(10)))
2589537Satgutier@umich.edu            for i,v in enumerate(self):
2599537Satgutier@umich.edu                v.set_parent(parent, "%s%0*d" % (name, width, i))
2609537Satgutier@umich.edu
2619537Satgutier@umich.edu    def has_parent(self):
2629537Satgutier@umich.edu        return reduce(lambda x,y: x and y, [v.has_parent() for v in self])
2639537Satgutier@umich.edu
2649537Satgutier@umich.edu    # return 'cpu0 cpu1' etc. for print_ini()
2659537Satgutier@umich.edu    def get_name(self):
2669537Satgutier@umich.edu        return ' '.join([v._name for v in self])
2679537Satgutier@umich.edu
2689537Satgutier@umich.edu    # By iterating through the constituent members of the vector here
2699537Satgutier@umich.edu    # we can nicely handle iterating over all a SimObject's children
2709537Satgutier@umich.edu    # without having to provide lots of special functions on
2719537Satgutier@umich.edu    # SimObjectVector directly.
2729537Satgutier@umich.edu    def descendants(self):
2739537Satgutier@umich.edu        for v in self:
2749537Satgutier@umich.edu            for obj in v.descendants():
2759537Satgutier@umich.edu                yield obj
2769537Satgutier@umich.edu
2779537Satgutier@umich.edu    def get_config_as_dict(self):
2789537Satgutier@umich.edu        a = []
2799537Satgutier@umich.edu        for v in self:
2809537Satgutier@umich.edu            a.append(v.get_config_as_dict())
2819537Satgutier@umich.edu        return a
2829537Satgutier@umich.edu
2839537Satgutier@umich.edu    # If we are replacing an item in the vector, make sure to set the
2849537Satgutier@umich.edu    # parent reference of the new SimObject to be the same as the parent
2859537Satgutier@umich.edu    # of the SimObject being replaced. Useful to have if we created
2869537Satgutier@umich.edu    # a SimObjectVector of temporary objects that will be modified later in
2879537Satgutier@umich.edu    # configuration scripts.
2889537Satgutier@umich.edu    def __setitem__(self, key, value):
2899537Satgutier@umich.edu        val = self[key]
2909537Satgutier@umich.edu        if value.has_parent():
2919537Satgutier@umich.edu            warn("SimObject %s already has a parent" % value.get_name() +\
2929537Satgutier@umich.edu                 " that is being overwritten by a SimObjectVector")
2939537Satgutier@umich.edu        value.set_parent(val.get_parent(), val._name)
2949537Satgutier@umich.edu        super(SimObjectVector, self).__setitem__(key, value)
2959537Satgutier@umich.edu
2969537Satgutier@umich.edu    # Enumerate the params of each member of the SimObject vector. Creates
2979537Satgutier@umich.edu    # strings that will allow indexing into the vector by the python code and
2989537Satgutier@umich.edu    # allow it to be specified on the command line.
2999537Satgutier@umich.edu    def enumerateParams(self, flags_dict = {},
3009537Satgutier@umich.edu                        cmd_line_str = "",
3019537Satgutier@umich.edu                        access_str = ""):
3029537Satgutier@umich.edu        if hasattr(self, "_paramEnumed"):
3039537Satgutier@umich.edu            print "Cycle detected enumerating params at %s?!" % (cmd_line_str)
3049537Satgutier@umich.edu        else:
3059537Satgutier@umich.edu            x = 0
3069537Satgutier@umich.edu            for vals in self:
3079537Satgutier@umich.edu                # Each entry in the SimObjectVector should be an
3089537Satgutier@umich.edu                # instance of a SimObject
3099537Satgutier@umich.edu                flags_dict = vals.enumerateParams(flags_dict,
3109537Satgutier@umich.edu                                                  cmd_line_str + "%d." % x,
3119537Satgutier@umich.edu                                                  access_str + "[%d]." % x)
3129537Satgutier@umich.edu                x = x + 1
3139537Satgutier@umich.edu
3149537Satgutier@umich.edu        return flags_dict
3159537Satgutier@umich.edu
3169537Satgutier@umich.educlass VectorParamDesc(ParamDesc):
3179537Satgutier@umich.edu    # Convert assigned value to appropriate type.  If the RHS is not a
3189537Satgutier@umich.edu    # list or tuple, it generates a single-element list.
3199537Satgutier@umich.edu    def convert(self, value):
3209537Satgutier@umich.edu        if isinstance(value, (list, tuple)):
3219537Satgutier@umich.edu            # list: coerce each element into new list
3229537Satgutier@umich.edu            tmp_list = [ ParamDesc.convert(self, v) for v in value ]
3239537Satgutier@umich.edu        elif isinstance(value, str):
3249537Satgutier@umich.edu            # If input is a csv string
3259537Satgutier@umich.edu            tmp_list = [ ParamDesc.convert(self, v) \
3269537Satgutier@umich.edu                         for v in value.strip('[').strip(']').split(',') ]
3279537Satgutier@umich.edu        else:
3289537Satgutier@umich.edu            # singleton: coerce to a single-element list
3299537Satgutier@umich.edu            tmp_list = [ ParamDesc.convert(self, value) ]
3309537Satgutier@umich.edu
3319537Satgutier@umich.edu        if isSimObjectSequence(tmp_list):
3329537Satgutier@umich.edu            return SimObjectVector(tmp_list)
3339537Satgutier@umich.edu        else:
3349537Satgutier@umich.edu            return VectorParamValue(tmp_list)
3359537Satgutier@umich.edu
3369537Satgutier@umich.edu    # Produce a human readable example string that describes
3379537Satgutier@umich.edu    # how to set this vector parameter in the absence of a default
3389537Satgutier@umich.edu    # value.
3399537Satgutier@umich.edu    def example_str(self):
3409537Satgutier@umich.edu        s = super(VectorParamDesc, self).example_str()
3419537Satgutier@umich.edu        help_str = "[" + s + "," + s + ", ...]"
3429537Satgutier@umich.edu        return help_str
3439537Satgutier@umich.edu
3449537Satgutier@umich.edu    # Produce a human readable representation of the value of this vector param.
3459537Satgutier@umich.edu    def pretty_print(self, value):
3469537Satgutier@umich.edu        if isinstance(value, (list, tuple)):
3479537Satgutier@umich.edu            tmp_list = [ ParamDesc.pretty_print(self, v) for v in value ]
3489537Satgutier@umich.edu        elif isinstance(value, str):
3499537Satgutier@umich.edu            tmp_list = [ ParamDesc.pretty_print(self, v) for v in value.split(',') ]
3509537Satgutier@umich.edu        else:
3519537Satgutier@umich.edu            tmp_list = [ ParamDesc.pretty_print(self, value) ]
3529537Satgutier@umich.edu
3539537Satgutier@umich.edu        return tmp_list
3549537Satgutier@umich.edu
3559537Satgutier@umich.edu    # This is a helper function for the new config system
3569537Satgutier@umich.edu    def __call__(self, value):
3579537Satgutier@umich.edu        if isinstance(value, (list, tuple)):
3589537Satgutier@umich.edu            # list: coerce each element into new list
3599537Satgutier@umich.edu            tmp_list = [ ParamDesc.convert(self, v) for v in value ]
3609537Satgutier@umich.edu        elif isinstance(value, str):
3619537Satgutier@umich.edu            # If input is a csv string
3629537Satgutier@umich.edu            tmp_list = [ ParamDesc.convert(self, v) \
3639537Satgutier@umich.edu                         for v in value.strip('[').strip(']').split(',') ]
3649537Satgutier@umich.edu        else:
3659537Satgutier@umich.edu            # singleton: coerce to a single-element list
3669537Satgutier@umich.edu            tmp_list = [ ParamDesc.convert(self, value) ]
3679537Satgutier@umich.edu
3689537Satgutier@umich.edu        return VectorParamValue(tmp_list)
3699537Satgutier@umich.edu
3709537Satgutier@umich.edu    def swig_module_name(self):
3719537Satgutier@umich.edu        return "%s_vector" % self.ptype_str
3729537Satgutier@umich.edu
3739537Satgutier@umich.edu    def swig_predecls(self, code):
3749537Satgutier@umich.edu        code('%import "${{self.swig_module_name()}}.i"')
3759537Satgutier@umich.edu
3769537Satgutier@umich.edu    def swig_decl(self, code):
3779537Satgutier@umich.edu        code('%module(package="m5.internal") ${{self.swig_module_name()}}')
3789537Satgutier@umich.edu        code('%{')
3799537Satgutier@umich.edu        self.ptype.cxx_predecls(code)
3809537Satgutier@umich.edu        code('%}')
3819537Satgutier@umich.edu        code()
3829537Satgutier@umich.edu        # Make sure the SWIGPY_SLICE_ARG is defined through this inclusion
3839537Satgutier@umich.edu        code('%include "std_container.i"')
3849537Satgutier@umich.edu        code()
3859537Satgutier@umich.edu        self.ptype.swig_predecls(code)
3869537Satgutier@umich.edu        code()
3879537Satgutier@umich.edu        code('%include "std_vector.i"')
3889537Satgutier@umich.edu        code()
3899537Satgutier@umich.edu
3909537Satgutier@umich.edu        ptype = self.ptype_str
3919537Satgutier@umich.edu        cxx_type = self.ptype.cxx_type
3929537Satgutier@umich.edu
3939537Satgutier@umich.edu        code('%template(vector_$ptype) std::vector< $cxx_type >;')
3949537Satgutier@umich.edu
3959537Satgutier@umich.edu    def cxx_predecls(self, code):
3969537Satgutier@umich.edu        code('#include <vector>')
3979537Satgutier@umich.edu        self.ptype.cxx_predecls(code)
3989537Satgutier@umich.edu
3999537Satgutier@umich.edu    def cxx_decl(self, code):
4009537Satgutier@umich.edu        code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};')
4019537Satgutier@umich.edu
4029537Satgutier@umich.educlass ParamFactory(object):
4039537Satgutier@umich.edu    def __init__(self, param_desc_class, ptype_str = None):
4049537Satgutier@umich.edu        self.param_desc_class = param_desc_class
4059537Satgutier@umich.edu        self.ptype_str = ptype_str
4069537Satgutier@umich.edu
4079537Satgutier@umich.edu    def __getattr__(self, attr):
4089537Satgutier@umich.edu        if self.ptype_str:
4099537Satgutier@umich.edu            attr = self.ptype_str + '.' + attr
4109537Satgutier@umich.edu        return ParamFactory(self.param_desc_class, attr)
4119537Satgutier@umich.edu
4129537Satgutier@umich.edu    # E.g., Param.Int(5, "number of widgets")
4139537Satgutier@umich.edu    def __call__(self, *args, **kwargs):
4149537Satgutier@umich.edu        ptype = None
4159537Satgutier@umich.edu        try:
4169537Satgutier@umich.edu            ptype = allParams[self.ptype_str]
4179537Satgutier@umich.edu        except KeyError:
4189537Satgutier@umich.edu            # if name isn't defined yet, assume it's a SimObject, and
4199537Satgutier@umich.edu            # try to resolve it later
4209537Satgutier@umich.edu            pass
4219537Satgutier@umich.edu        return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs)
4229537Satgutier@umich.edu
4239537Satgutier@umich.eduParam = ParamFactory(ParamDesc)
4249537Satgutier@umich.eduVectorParam = ParamFactory(VectorParamDesc)
4259537Satgutier@umich.edu
4269537Satgutier@umich.edu#####################################################################
4279537Satgutier@umich.edu#
4289537Satgutier@umich.edu# Parameter Types
4299537Satgutier@umich.edu#
4309537Satgutier@umich.edu# Though native Python types could be used to specify parameter types
4319537Satgutier@umich.edu# (the 'ptype' field of the Param and VectorParam classes), it's more
4329537Satgutier@umich.edu# flexible to define our own set of types.  This gives us more control
4339537Satgutier@umich.edu# over how Python expressions are converted to values (via the
4349537Satgutier@umich.edu# __init__() constructor) and how these values are printed out (via
4359537Satgutier@umich.edu# the __str__() conversion method).
4369537Satgutier@umich.edu#
4379537Satgutier@umich.edu#####################################################################
4389537Satgutier@umich.edu
4399537Satgutier@umich.edu# String-valued parameter.  Just mixin the ParamValue class with the
4409537Satgutier@umich.edu# built-in str class.
4419537Satgutier@umich.educlass String(ParamValue,str):
4429537Satgutier@umich.edu    cxx_type = 'std::string'
4439537Satgutier@umich.edu    cmd_line_settable = True
4449537Satgutier@umich.edu
4459537Satgutier@umich.edu    @classmethod
4469537Satgutier@umich.edu    def cxx_predecls(self, code):
4479537Satgutier@umich.edu        code('#include <string>')
4489537Satgutier@umich.edu
4499537Satgutier@umich.edu    @classmethod
4509537Satgutier@umich.edu    def swig_predecls(cls, code):
4519537Satgutier@umich.edu        code('%include "std_string.i"')
4529537Satgutier@umich.edu
4539537Satgutier@umich.edu    def __call__(self, value):
4549537Satgutier@umich.edu        self = value
4559537Satgutier@umich.edu        return value
4569537Satgutier@umich.edu
4579537Satgutier@umich.edu    def getValue(self):
4589537Satgutier@umich.edu        return self
4599537Satgutier@umich.edu
4609537Satgutier@umich.edu# superclass for "numeric" parameter values, to emulate math
4619537Satgutier@umich.edu# operations in a type-safe way.  e.g., a Latency times an int returns
4629537Satgutier@umich.edu# a new Latency object.
4639537Satgutier@umich.educlass NumericParamValue(ParamValue):
4649537Satgutier@umich.edu    def __str__(self):
4659537Satgutier@umich.edu        return str(self.value)
4669537Satgutier@umich.edu
4679537Satgutier@umich.edu    def __float__(self):
4689537Satgutier@umich.edu        return float(self.value)
4699537Satgutier@umich.edu
4709537Satgutier@umich.edu    def __long__(self):
4719537Satgutier@umich.edu        return long(self.value)
4729537Satgutier@umich.edu
4739537Satgutier@umich.edu    def __int__(self):
4749537Satgutier@umich.edu        return int(self.value)
4759537Satgutier@umich.edu
4769537Satgutier@umich.edu    # hook for bounds checking
4779537Satgutier@umich.edu    def _check(self):
4789537Satgutier@umich.edu        return
4799537Satgutier@umich.edu
4809537Satgutier@umich.edu    def __mul__(self, other):
4819537Satgutier@umich.edu        newobj = self.__class__(self)
4829537Satgutier@umich.edu        newobj.value *= other
4839537Satgutier@umich.edu        newobj._check()
4849537Satgutier@umich.edu        return newobj
4859537Satgutier@umich.edu
4869537Satgutier@umich.edu    __rmul__ = __mul__
4879537Satgutier@umich.edu
4889537Satgutier@umich.edu    def __div__(self, other):
4899537Satgutier@umich.edu        newobj = self.__class__(self)
4909537Satgutier@umich.edu        newobj.value /= other
4919537Satgutier@umich.edu        newobj._check()
4929537Satgutier@umich.edu        return newobj
4939537Satgutier@umich.edu
4949537Satgutier@umich.edu    def __sub__(self, other):
4959537Satgutier@umich.edu        newobj = self.__class__(self)
4969537Satgutier@umich.edu        newobj.value -= other
4979537Satgutier@umich.edu        newobj._check()
4989537Satgutier@umich.edu        return newobj
4999537Satgutier@umich.edu
5009537Satgutier@umich.edu    def config_value(self):
5019537Satgutier@umich.edu        return self.value
5029537Satgutier@umich.edu
5039537Satgutier@umich.edu# Metaclass for bounds-checked integer parameters.  See CheckedInt.
5049537Satgutier@umich.educlass CheckedIntType(MetaParamValue):
5059537Satgutier@umich.edu    def __init__(cls, name, bases, dict):
5069537Satgutier@umich.edu        super(CheckedIntType, cls).__init__(name, bases, dict)
5079537Satgutier@umich.edu
5089537Satgutier@umich.edu        # CheckedInt is an abstract base class, so we actually don't
5099537Satgutier@umich.edu        # want to do any processing on it... the rest of this code is
5109537Satgutier@umich.edu        # just for classes that derive from CheckedInt.
5119537Satgutier@umich.edu        if name == 'CheckedInt':
5129537Satgutier@umich.edu            return
5139537Satgutier@umich.edu
5149537Satgutier@umich.edu        if not (hasattr(cls, 'min') and hasattr(cls, 'max')):
5159537Satgutier@umich.edu            if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')):
5169537Satgutier@umich.edu                panic("CheckedInt subclass %s must define either\n" \
5179537Satgutier@umich.edu                      "    'min' and 'max' or 'size' and 'unsigned'\n",
5189537Satgutier@umich.edu                      name);
5199537Satgutier@umich.edu            if cls.unsigned:
5209537Satgutier@umich.edu                cls.min = 0
5219537Satgutier@umich.edu                cls.max = 2 ** cls.size - 1
5229537Satgutier@umich.edu            else:
5239537Satgutier@umich.edu                cls.min = -(2 ** (cls.size - 1))
5249537Satgutier@umich.edu                cls.max = (2 ** (cls.size - 1)) - 1
5259537Satgutier@umich.edu
5269537Satgutier@umich.edu# Abstract superclass for bounds-checked integer parameters.  This
5279537Satgutier@umich.edu# class is subclassed to generate parameter classes with specific
5289537Satgutier@umich.edu# bounds.  Initialization of the min and max bounds is done in the
5299537Satgutier@umich.edu# metaclass CheckedIntType.__init__.
5309537Satgutier@umich.educlass CheckedInt(NumericParamValue):
5319537Satgutier@umich.edu    __metaclass__ = CheckedIntType
5329537Satgutier@umich.edu    cmd_line_settable = True
5339537Satgutier@umich.edu
5349537Satgutier@umich.edu    def _check(self):
5359537Satgutier@umich.edu        if not self.min <= self.value <= self.max:
5369537Satgutier@umich.edu            raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
5379537Satgutier@umich.edu                  (self.min, self.value, self.max)
5389537Satgutier@umich.edu
5399537Satgutier@umich.edu    def __init__(self, value):
5409537Satgutier@umich.edu        if isinstance(value, str):
5419537Satgutier@umich.edu            self.value = convert.toInteger(value)
5429537Satgutier@umich.edu        elif isinstance(value, (int, long, float, NumericParamValue)):
5439537Satgutier@umich.edu            self.value = long(value)
5449537Satgutier@umich.edu        else:
5459537Satgutier@umich.edu            raise TypeError, "Can't convert object of type %s to CheckedInt" \
5469537Satgutier@umich.edu                  % type(value).__name__
5479537Satgutier@umich.edu        self._check()
5489537Satgutier@umich.edu
5499537Satgutier@umich.edu    def __call__(self, value):
5509537Satgutier@umich.edu        self.__init__(value)
5519537Satgutier@umich.edu        return value
5529537Satgutier@umich.edu
5539537Satgutier@umich.edu    @classmethod
5549537Satgutier@umich.edu    def cxx_predecls(cls, code):
5559537Satgutier@umich.edu        # most derived types require this, so we just do it here once
5569537Satgutier@umich.edu        code('#include "base/types.hh"')
5579537Satgutier@umich.edu
5589537Satgutier@umich.edu    @classmethod
5599537Satgutier@umich.edu    def swig_predecls(cls, code):
5609537Satgutier@umich.edu        # most derived types require this, so we just do it here once
5619537Satgutier@umich.edu        code('%import "stdint.i"')
5629537Satgutier@umich.edu        code('%import "base/types.hh"')
5639537Satgutier@umich.edu
5649537Satgutier@umich.edu    def getValue(self):
5659537Satgutier@umich.edu        return long(self.value)
5669537Satgutier@umich.edu
5679537Satgutier@umich.educlass Int(CheckedInt):      cxx_type = 'int';      size = 32; unsigned = False
5689537Satgutier@umich.educlass Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True
5699537Satgutier@umich.edu
5709537Satgutier@umich.educlass Int8(CheckedInt):     cxx_type =   'int8_t'; size =  8; unsigned = False
5719537Satgutier@umich.educlass UInt8(CheckedInt):    cxx_type =  'uint8_t'; size =  8; unsigned = True
5729537Satgutier@umich.educlass Int16(CheckedInt):    cxx_type =  'int16_t'; size = 16; unsigned = False
5739537Satgutier@umich.educlass UInt16(CheckedInt):   cxx_type = 'uint16_t'; size = 16; unsigned = True
5749537Satgutier@umich.educlass Int32(CheckedInt):    cxx_type =  'int32_t'; size = 32; unsigned = False
5759537Satgutier@umich.educlass UInt32(CheckedInt):   cxx_type = 'uint32_t'; size = 32; unsigned = True
5769537Satgutier@umich.educlass Int64(CheckedInt):    cxx_type =  'int64_t'; size = 64; unsigned = False
5779537Satgutier@umich.educlass UInt64(CheckedInt):   cxx_type = 'uint64_t'; size = 64; unsigned = True
5789537Satgutier@umich.edu
5799537Satgutier@umich.educlass Counter(CheckedInt):  cxx_type = 'Counter';  size = 64; unsigned = True
5809537Satgutier@umich.educlass Tick(CheckedInt):     cxx_type = 'Tick';     size = 64; unsigned = True
5819537Satgutier@umich.educlass TcpPort(CheckedInt):  cxx_type = 'uint16_t'; size = 16; unsigned = True
5829537Satgutier@umich.educlass UdpPort(CheckedInt):  cxx_type = 'uint16_t'; size = 16; unsigned = True
5839537Satgutier@umich.edu
5849537Satgutier@umich.educlass Percent(CheckedInt):  cxx_type = 'int'; min = 0; max = 100
5859537Satgutier@umich.edu
5869537Satgutier@umich.educlass Cycles(CheckedInt):
5879537Satgutier@umich.edu    cxx_type = 'Cycles'
5889537Satgutier@umich.edu    size = 64
5899537Satgutier@umich.edu    unsigned = True
5909537Satgutier@umich.edu
5919537Satgutier@umich.edu    def getValue(self):
5929537Satgutier@umich.edu        from m5.internal.core import Cycles
5939537Satgutier@umich.edu        return Cycles(self.value)
5949537Satgutier@umich.edu
5959537Satgutier@umich.educlass Float(ParamValue, float):
5969537Satgutier@umich.edu    cxx_type = 'double'
5979537Satgutier@umich.edu    cmdLineSettable = True
5989537Satgutier@umich.edu
5999537Satgutier@umich.edu    def __init__(self, value):
6009537Satgutier@umich.edu        if isinstance(value, (int, long, float, NumericParamValue, Float, str)):
6019537Satgutier@umich.edu            self.value = float(value)
6029537Satgutier@umich.edu        else:
6039537Satgutier@umich.edu            raise TypeError, "Can't convert object of type %s to Float" \
6049537Satgutier@umich.edu                  % type(value).__name__
6059537Satgutier@umich.edu
6069537Satgutier@umich.edu    def __call__(self, value):
6079537Satgutier@umich.edu        self.__init__(value)
6089537Satgutier@umich.edu        return value
6099537Satgutier@umich.edu
6109537Satgutier@umich.edu    def getValue(self):
6119537Satgutier@umich.edu        return float(self.value)
6129537Satgutier@umich.edu
6139537Satgutier@umich.edu    def config_value(self):
6149537Satgutier@umich.edu        return self
6159537Satgutier@umich.edu
6169537Satgutier@umich.educlass MemorySize(CheckedInt):
6179537Satgutier@umich.edu    cxx_type = 'uint64_t'
6189537Satgutier@umich.edu    ex_str = '512MB'
6199537Satgutier@umich.edu    size = 64
6209537Satgutier@umich.edu    unsigned = True
6219537Satgutier@umich.edu    def __init__(self, value):
6229537Satgutier@umich.edu        if isinstance(value, MemorySize):
6239537Satgutier@umich.edu            self.value = value.value
6249537Satgutier@umich.edu        else:
6259537Satgutier@umich.edu            self.value = convert.toMemorySize(value)
6269537Satgutier@umich.edu        self._check()
6279537Satgutier@umich.edu
6289537Satgutier@umich.educlass MemorySize32(CheckedInt):
6299537Satgutier@umich.edu    cxx_type = 'uint32_t'
6309537Satgutier@umich.edu    ex_str = '512MB'
6319537Satgutier@umich.edu    size = 32
6329537Satgutier@umich.edu    unsigned = True
6339537Satgutier@umich.edu    def __init__(self, value):
6349537Satgutier@umich.edu        if isinstance(value, MemorySize):
6359537Satgutier@umich.edu            self.value = value.value
6369537Satgutier@umich.edu        else:
6379537Satgutier@umich.edu            self.value = convert.toMemorySize(value)
6389537Satgutier@umich.edu        self._check()
6399537Satgutier@umich.edu
6409537Satgutier@umich.educlass Addr(CheckedInt):
6419537Satgutier@umich.edu    cxx_type = 'Addr'
6429537Satgutier@umich.edu    size = 64
6439537Satgutier@umich.edu    unsigned = True
6449537Satgutier@umich.edu    def __init__(self, value):
6459537Satgutier@umich.edu        if isinstance(value, Addr):
6469537Satgutier@umich.edu            self.value = value.value
6479537Satgutier@umich.edu        else:
6489537Satgutier@umich.edu            try:
6499537Satgutier@umich.edu                # Often addresses are referred to with sizes. Ex: A device
6509537Satgutier@umich.edu                # base address is at "512MB".  Use toMemorySize() to convert
6519537Satgutier@umich.edu                # these into addresses. If the address is not specified with a
6529537Satgutier@umich.edu                # "size", an exception will occur and numeric translation will
6539537Satgutier@umich.edu                # proceed below.
6549537Satgutier@umich.edu                self.value = convert.toMemorySize(value)
6559537Satgutier@umich.edu            except (TypeError, ValueError):
6569537Satgutier@umich.edu                # Convert number to string and use long() to do automatic
6579537Satgutier@umich.edu                # base conversion (requires base=0 for auto-conversion)
6589537Satgutier@umich.edu                self.value = long(str(value), base=0)
6599537Satgutier@umich.edu
6609537Satgutier@umich.edu        self._check()
6619537Satgutier@umich.edu    def __add__(self, other):
6629537Satgutier@umich.edu        if isinstance(other, Addr):
6639537Satgutier@umich.edu            return self.value + other.value
6649537Satgutier@umich.edu        else:
6659537Satgutier@umich.edu            return self.value + other
6669537Satgutier@umich.edu    def pretty_print(self, value):
6679537Satgutier@umich.edu        try:
6689537Satgutier@umich.edu            val = convert.toMemorySize(value)
6699537Satgutier@umich.edu        except TypeError:
6709537Satgutier@umich.edu            val = long(value)
6719537Satgutier@umich.edu        return "0x%x" % long(val)
6729537Satgutier@umich.edu
6739537Satgutier@umich.educlass AddrRange(ParamValue):
6749537Satgutier@umich.edu    cxx_type = 'AddrRange'
6759537Satgutier@umich.edu
6769537Satgutier@umich.edu    def __init__(self, *args, **kwargs):
6779537Satgutier@umich.edu        # Disable interleaving by default
6789537Satgutier@umich.edu        self.intlvHighBit = 0
6799537Satgutier@umich.edu        self.intlvBits = 0
6809537Satgutier@umich.edu        self.intlvMatch = 0
6819537Satgutier@umich.edu
6829537Satgutier@umich.edu        def handle_kwargs(self, kwargs):
6839537Satgutier@umich.edu            # An address range needs to have an upper limit, specified
6849537Satgutier@umich.edu            # either explicitly with an end, or as an offset using the
6859537Satgutier@umich.edu            # size keyword.
6869537Satgutier@umich.edu            if 'end' in kwargs:
6879537Satgutier@umich.edu                self.end = Addr(kwargs.pop('end'))
6889537Satgutier@umich.edu            elif 'size' in kwargs:
6899537Satgutier@umich.edu                self.end = self.start + Addr(kwargs.pop('size')) - 1
6909537Satgutier@umich.edu            else:
6919537Satgutier@umich.edu                raise TypeError, "Either end or size must be specified"
6929537Satgutier@umich.edu
6939537Satgutier@umich.edu            # Now on to the optional bit
6949537Satgutier@umich.edu            if 'intlvHighBit' in kwargs:
6959537Satgutier@umich.edu                self.intlvHighBit = int(kwargs.pop('intlvHighBit'))
6969537Satgutier@umich.edu            if 'intlvBits' in kwargs:
6979537Satgutier@umich.edu                self.intlvBits = int(kwargs.pop('intlvBits'))
6989537Satgutier@umich.edu            if 'intlvMatch' in kwargs:
6999537Satgutier@umich.edu                self.intlvMatch = int(kwargs.pop('intlvMatch'))
7009537Satgutier@umich.edu
7019537Satgutier@umich.edu        if len(args) == 0:
7029537Satgutier@umich.edu            self.start = Addr(kwargs.pop('start'))
7039537Satgutier@umich.edu            handle_kwargs(self, kwargs)
7049537Satgutier@umich.edu
7059537Satgutier@umich.edu        elif len(args) == 1:
7069537Satgutier@umich.edu            if kwargs:
7079537Satgutier@umich.edu                self.start = Addr(args[0])
7089537Satgutier@umich.edu                handle_kwargs(self, kwargs)
7099537Satgutier@umich.edu            elif isinstance(args[0], (list, tuple)):
7109537Satgutier@umich.edu                self.start = Addr(args[0][0])
7119537Satgutier@umich.edu                self.end = Addr(args[0][1])
7129537Satgutier@umich.edu            else:
7139537Satgutier@umich.edu                self.start = Addr(0)
7149537Satgutier@umich.edu                self.end = Addr(args[0]) - 1
7159537Satgutier@umich.edu
7169537Satgutier@umich.edu        elif len(args) == 2:
7179537Satgutier@umich.edu            self.start = Addr(args[0])
7189537Satgutier@umich.edu            self.end = Addr(args[1])
7199537Satgutier@umich.edu        else:
7209537Satgutier@umich.edu            raise TypeError, "Too many arguments specified"
7219537Satgutier@umich.edu
7229537Satgutier@umich.edu        if kwargs:
7239537Satgutier@umich.edu            raise TypeError, "Too many keywords: %s" % kwargs.keys()
7249537Satgutier@umich.edu
7259537Satgutier@umich.edu    def __str__(self):
7269537Satgutier@umich.edu        return '%s:%s' % (self.start, self.end)
7279537Satgutier@umich.edu
7289537Satgutier@umich.edu    def size(self):
7299537Satgutier@umich.edu        # Divide the size by the size of the interleaving slice
7309537Satgutier@umich.edu        return (long(self.end) - long(self.start) + 1) >> self.intlvBits
7319537Satgutier@umich.edu
7329537Satgutier@umich.edu    @classmethod
7339537Satgutier@umich.edu    def cxx_predecls(cls, code):
7349537Satgutier@umich.edu        Addr.cxx_predecls(code)
7359537Satgutier@umich.edu        code('#include "base/addr_range.hh"')
7369537Satgutier@umich.edu
7379537Satgutier@umich.edu    @classmethod
7389537Satgutier@umich.edu    def swig_predecls(cls, code):
7399537Satgutier@umich.edu        Addr.swig_predecls(code)
7409537Satgutier@umich.edu
7419537Satgutier@umich.edu    def getValue(self):
7429537Satgutier@umich.edu        # Go from the Python class to the wrapped C++ class generated
7439537Satgutier@umich.edu        # by swig
7449537Satgutier@umich.edu        from m5.internal.range import AddrRange
7459537Satgutier@umich.edu
7469537Satgutier@umich.edu        return AddrRange(long(self.start), long(self.end),
7479537Satgutier@umich.edu                         int(self.intlvHighBit), int(self.intlvBits),
7489537Satgutier@umich.edu                         int(self.intlvMatch))
7499537Satgutier@umich.edu
7509537Satgutier@umich.edu# Boolean parameter type.  Python doesn't let you subclass bool, since
7519537Satgutier@umich.edu# it doesn't want to let you create multiple instances of True and
7529537Satgutier@umich.edu# False.  Thus this is a little more complicated than String.
7539537Satgutier@umich.educlass Bool(ParamValue):
7549537Satgutier@umich.edu    cxx_type = 'bool'
7559537Satgutier@umich.edu    cmd_line_settable = True
7569537Satgutier@umich.edu
7579537Satgutier@umich.edu    def __init__(self, value):
7589537Satgutier@umich.edu        try:
7599537Satgutier@umich.edu            self.value = convert.toBool(value)
7609537Satgutier@umich.edu        except TypeError:
7619537Satgutier@umich.edu            self.value = bool(value)
7629537Satgutier@umich.edu
7639537Satgutier@umich.edu    def __call__(self, value):
7649537Satgutier@umich.edu        self.__init__(value)
7659537Satgutier@umich.edu        return value
7669537Satgutier@umich.edu
7679537Satgutier@umich.edu    def getValue(self):
7689537Satgutier@umich.edu        return bool(self.value)
7699537Satgutier@umich.edu
7709537Satgutier@umich.edu    def __str__(self):
7719537Satgutier@umich.edu        return str(self.value)
7729537Satgutier@umich.edu
7739537Satgutier@umich.edu    # implement truth value testing for Bool parameters so that these params
7749537Satgutier@umich.edu    # evaluate correctly during the python configuration phase
7759537Satgutier@umich.edu    def __nonzero__(self):
7769537Satgutier@umich.edu        return bool(self.value)
7779537Satgutier@umich.edu
7789537Satgutier@umich.edu    def ini_str(self):
7799537Satgutier@umich.edu        if self.value:
7809537Satgutier@umich.edu            return 'true'
7819537Satgutier@umich.edu        return 'false'
7829537Satgutier@umich.edu
7839537Satgutier@umich.edu    def config_value(self):
7849537Satgutier@umich.edu        return self.value
7859537Satgutier@umich.edu
7869537Satgutier@umich.edudef IncEthernetAddr(addr, val = 1):
7879537Satgutier@umich.edu    bytes = map(lambda x: int(x, 16), addr.split(':'))
7889537Satgutier@umich.edu    bytes[5] += val
7899537Satgutier@umich.edu    for i in (5, 4, 3, 2, 1):
7909537Satgutier@umich.edu        val,rem = divmod(bytes[i], 256)
7919537Satgutier@umich.edu        bytes[i] = rem
7929537Satgutier@umich.edu        if val == 0:
7939537Satgutier@umich.edu            break
7949537Satgutier@umich.edu        bytes[i - 1] += val
7959537Satgutier@umich.edu    assert(bytes[0] <= 255)
7969537Satgutier@umich.edu    return ':'.join(map(lambda x: '%02x' % x, bytes))
7979537Satgutier@umich.edu
7989537Satgutier@umich.edu_NextEthernetAddr = "00:90:00:00:00:01"
7999537Satgutier@umich.edudef NextEthernetAddr():
8009537Satgutier@umich.edu    global _NextEthernetAddr
8019537Satgutier@umich.edu
8029537Satgutier@umich.edu    value = _NextEthernetAddr
8039537Satgutier@umich.edu    _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1)
8049537Satgutier@umich.edu    return value
8059537Satgutier@umich.edu
8069537Satgutier@umich.educlass EthernetAddr(ParamValue):
8079537Satgutier@umich.edu    cxx_type = 'Net::EthAddr'
8089537Satgutier@umich.edu    ex_str = "00:90:00:00:00:01"
8099537Satgutier@umich.edu    cmd_line_settable = True
8109537Satgutier@umich.edu
8119537Satgutier@umich.edu    @classmethod
8129537Satgutier@umich.edu    def cxx_predecls(cls, code):
8139537Satgutier@umich.edu        code('#include "base/inet.hh"')
8149537Satgutier@umich.edu
8159537Satgutier@umich.edu    @classmethod
8169537Satgutier@umich.edu    def swig_predecls(cls, code):
8179537Satgutier@umich.edu        code('%include "python/swig/inet.i"')
8189537Satgutier@umich.edu
8199537Satgutier@umich.edu    def __init__(self, value):
8209537Satgutier@umich.edu        if value == NextEthernetAddr:
8219537Satgutier@umich.edu            self.value = value
8229537Satgutier@umich.edu            return
8239537Satgutier@umich.edu
8249537Satgutier@umich.edu        if not isinstance(value, str):
8259537Satgutier@umich.edu            raise TypeError, "expected an ethernet address and didn't get one"
8269537Satgutier@umich.edu
8279537Satgutier@umich.edu        bytes = value.split(':')
8289537Satgutier@umich.edu        if len(bytes) != 6:
8299537Satgutier@umich.edu            raise TypeError, 'invalid ethernet address %s' % value
8309537Satgutier@umich.edu
8319537Satgutier@umich.edu        for byte in bytes:
8329537Satgutier@umich.edu            if not 0 <= int(byte, base=16) <= 0xff:
8339537Satgutier@umich.edu                raise TypeError, 'invalid ethernet address %s' % value
8349537Satgutier@umich.edu
8359537Satgutier@umich.edu        self.value = value
8369537Satgutier@umich.edu
8379537Satgutier@umich.edu    def __call__(self, value):
8389537Satgutier@umich.edu        self.__init__(value)
8399537Satgutier@umich.edu        return value
8409537Satgutier@umich.edu
8419537Satgutier@umich.edu    def unproxy(self, base):
8429537Satgutier@umich.edu        if self.value == NextEthernetAddr:
8439537Satgutier@umich.edu            return EthernetAddr(self.value())
8449537Satgutier@umich.edu        return self
8459537Satgutier@umich.edu
8469537Satgutier@umich.edu    def getValue(self):
8479537Satgutier@umich.edu        from m5.internal.params import EthAddr
8489537Satgutier@umich.edu        return EthAddr(self.value)
8499537Satgutier@umich.edu
8509537Satgutier@umich.edu    def ini_str(self):
8519537Satgutier@umich.edu        return self.value
8529537Satgutier@umich.edu
8539537Satgutier@umich.edu# When initializing an IpAddress, pass in an existing IpAddress, a string of
8549537Satgutier@umich.edu# the form "a.b.c.d", or an integer representing an IP.
8559537Satgutier@umich.educlass IpAddress(ParamValue):
8569537Satgutier@umich.edu    cxx_type = 'Net::IpAddress'
8579537Satgutier@umich.edu    ex_str = "127.0.0.1"
8589537Satgutier@umich.edu    cmd_line_settable = True
8599537Satgutier@umich.edu
8609537Satgutier@umich.edu    @classmethod
8619537Satgutier@umich.edu    def cxx_predecls(cls, code):
8629537Satgutier@umich.edu        code('#include "base/inet.hh"')
8639537Satgutier@umich.edu
8649537Satgutier@umich.edu    @classmethod
8659537Satgutier@umich.edu    def swig_predecls(cls, code):
8669537Satgutier@umich.edu        code('%include "python/swig/inet.i"')
8679537Satgutier@umich.edu
8689537Satgutier@umich.edu    def __init__(self, value):
8699537Satgutier@umich.edu        if isinstance(value, IpAddress):
8709537Satgutier@umich.edu            self.ip = value.ip
8719537Satgutier@umich.edu        else:
8729537Satgutier@umich.edu            try:
8739537Satgutier@umich.edu                self.ip = convert.toIpAddress(value)
8749537Satgutier@umich.edu            except TypeError:
8759537Satgutier@umich.edu                self.ip = long(value)
8769537Satgutier@umich.edu        self.verifyIp()
8779537Satgutier@umich.edu
8789537Satgutier@umich.edu    def __call__(self, value):
8799537Satgutier@umich.edu        self.__init__(value)
8809537Satgutier@umich.edu        return value
8819537Satgutier@umich.edu
8829537Satgutier@umich.edu    def __str__(self):
8839537Satgutier@umich.edu        tup = [(self.ip >> i)  & 0xff for i in (24, 16, 8, 0)]
8849537Satgutier@umich.edu        return '%d.%d.%d.%d' % tuple(tup)
8859537Satgutier@umich.edu
8869537Satgutier@umich.edu    def __eq__(self, other):
8879537Satgutier@umich.edu        if isinstance(other, IpAddress):
8889537Satgutier@umich.edu            return self.ip == other.ip
8899537Satgutier@umich.edu        elif isinstance(other, str):
8909537Satgutier@umich.edu            try:
8919537Satgutier@umich.edu                return self.ip == convert.toIpAddress(other)
8929537Satgutier@umich.edu            except:
8939537Satgutier@umich.edu                return False
8949537Satgutier@umich.edu        else:
8959537Satgutier@umich.edu            return self.ip == other
8969537Satgutier@umich.edu
8979537Satgutier@umich.edu    def __ne__(self, other):
8989537Satgutier@umich.edu        return not (self == other)
8999537Satgutier@umich.edu
9009537Satgutier@umich.edu    def verifyIp(self):
9019537Satgutier@umich.edu        if self.ip < 0 or self.ip >= (1 << 32):
9029537Satgutier@umich.edu            raise TypeError, "invalid ip address %#08x" % self.ip
9039537Satgutier@umich.edu
9049537Satgutier@umich.edu    def getValue(self):
9059537Satgutier@umich.edu        from m5.internal.params import IpAddress
9069537Satgutier@umich.edu        return IpAddress(self.ip)
9079537Satgutier@umich.edu
9089537Satgutier@umich.edu# When initializing an IpNetmask, pass in an existing IpNetmask, a string of
9099537Satgutier@umich.edu# the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as
9109537Satgutier@umich.edu# positional or keyword arguments.
9119537Satgutier@umich.educlass IpNetmask(IpAddress):
9129537Satgutier@umich.edu    cxx_type = 'Net::IpNetmask'
9139537Satgutier@umich.edu    ex_str = "127.0.0.0/24"
9149537Satgutier@umich.edu    cmd_line_settable = True
9159537Satgutier@umich.edu
9169537Satgutier@umich.edu    @classmethod
9179537Satgutier@umich.edu    def cxx_predecls(cls, code):
9189537Satgutier@umich.edu        code('#include "base/inet.hh"')
9199537Satgutier@umich.edu
9209537Satgutier@umich.edu    @classmethod
9219537Satgutier@umich.edu    def swig_predecls(cls, code):
9229537Satgutier@umich.edu        code('%include "python/swig/inet.i"')
9239537Satgutier@umich.edu
9249537Satgutier@umich.edu    def __init__(self, *args, **kwargs):
9259537Satgutier@umich.edu        def handle_kwarg(self, kwargs, key, elseVal = None):
9269537Satgutier@umich.edu            if key in kwargs:
9279537Satgutier@umich.edu                setattr(self, key, kwargs.pop(key))
9289537Satgutier@umich.edu            elif elseVal:
9299537Satgutier@umich.edu                setattr(self, key, elseVal)
9309537Satgutier@umich.edu            else:
9319537Satgutier@umich.edu                raise TypeError, "No value set for %s" % key
9329537Satgutier@umich.edu
9339537Satgutier@umich.edu        if len(args) == 0:
9349537Satgutier@umich.edu            handle_kwarg(self, kwargs, 'ip')
9359537Satgutier@umich.edu            handle_kwarg(self, kwargs, 'netmask')
9369537Satgutier@umich.edu
9379537Satgutier@umich.edu        elif len(args) == 1:
9389537Satgutier@umich.edu            if kwargs:
9399537Satgutier@umich.edu                if not 'ip' in kwargs and not 'netmask' in kwargs:
9409537Satgutier@umich.edu                    raise TypeError, "Invalid arguments"
9419537Satgutier@umich.edu                handle_kwarg(self, kwargs, 'ip', args[0])
9429537Satgutier@umich.edu                handle_kwarg(self, kwargs, 'netmask', args[0])
9439537Satgutier@umich.edu            elif isinstance(args[0], IpNetmask):
9449537Satgutier@umich.edu                self.ip = args[0].ip
9459537Satgutier@umich.edu                self.netmask = args[0].netmask
9469537Satgutier@umich.edu            else:
9479537Satgutier@umich.edu                (self.ip, self.netmask) = convert.toIpNetmask(args[0])
9489537Satgutier@umich.edu
9499537Satgutier@umich.edu        elif len(args) == 2:
9509537Satgutier@umich.edu            self.ip = args[0]
9519537Satgutier@umich.edu            self.netmask = args[1]
9529537Satgutier@umich.edu        else:
9539537Satgutier@umich.edu            raise TypeError, "Too many arguments specified"
9549537Satgutier@umich.edu
9559537Satgutier@umich.edu        if kwargs:
9569537Satgutier@umich.edu            raise TypeError, "Too many keywords: %s" % kwargs.keys()
9579537Satgutier@umich.edu
9589537Satgutier@umich.edu        self.verify()
9599537Satgutier@umich.edu
9609537Satgutier@umich.edu    def __call__(self, value):
9619537Satgutier@umich.edu        self.__init__(value)
9629537Satgutier@umich.edu        return value
9639537Satgutier@umich.edu
9649537Satgutier@umich.edu    def __str__(self):
9659537Satgutier@umich.edu        return "%s/%d" % (super(IpNetmask, self).__str__(), self.netmask)
9669537Satgutier@umich.edu
9679537Satgutier@umich.edu    def __eq__(self, other):
9689537Satgutier@umich.edu        if isinstance(other, IpNetmask):
9699537Satgutier@umich.edu            return self.ip == other.ip and self.netmask == other.netmask
9709537Satgutier@umich.edu        elif isinstance(other, str):
9719537Satgutier@umich.edu            try:
9729537Satgutier@umich.edu                return (self.ip, self.netmask) == convert.toIpNetmask(other)
9739537Satgutier@umich.edu            except:
9749537Satgutier@umich.edu                return False
9759537Satgutier@umich.edu        else:
9769537Satgutier@umich.edu            return False
9779537Satgutier@umich.edu
9789537Satgutier@umich.edu    def verify(self):
9799537Satgutier@umich.edu        self.verifyIp()
9809537Satgutier@umich.edu        if self.netmask < 0 or self.netmask > 32:
9819537Satgutier@umich.edu            raise TypeError, "invalid netmask %d" % netmask
9829537Satgutier@umich.edu
9839537Satgutier@umich.edu    def getValue(self):
9849537Satgutier@umich.edu        from m5.internal.params import IpNetmask
9859537Satgutier@umich.edu        return IpNetmask(self.ip, self.netmask)
9869537Satgutier@umich.edu
9879537Satgutier@umich.edu# When initializing an IpWithPort, pass in an existing IpWithPort, a string of
9889537Satgutier@umich.edu# the form "a.b.c.d:p", or an ip and port as positional or keyword arguments.
9899537Satgutier@umich.educlass IpWithPort(IpAddress):
9909537Satgutier@umich.edu    cxx_type = 'Net::IpWithPort'
9919537Satgutier@umich.edu    ex_str = "127.0.0.1:80"
9929537Satgutier@umich.edu    cmd_line_settable = True
9939537Satgutier@umich.edu
9949537Satgutier@umich.edu    @classmethod
9959537Satgutier@umich.edu    def cxx_predecls(cls, code):
9969537Satgutier@umich.edu        code('#include "base/inet.hh"')
9979537Satgutier@umich.edu
9989537Satgutier@umich.edu    @classmethod
9999537Satgutier@umich.edu    def swig_predecls(cls, code):
10009537Satgutier@umich.edu        code('%include "python/swig/inet.i"')
10019537Satgutier@umich.edu
10029537Satgutier@umich.edu    def __init__(self, *args, **kwargs):
10039537Satgutier@umich.edu        def handle_kwarg(self, kwargs, key, elseVal = None):
10049537Satgutier@umich.edu            if key in kwargs:
10059537Satgutier@umich.edu                setattr(self, key, kwargs.pop(key))
10069537Satgutier@umich.edu            elif elseVal:
10079537Satgutier@umich.edu                setattr(self, key, elseVal)
10089537Satgutier@umich.edu            else:
10099537Satgutier@umich.edu                raise TypeError, "No value set for %s" % key
10109537Satgutier@umich.edu
10119537Satgutier@umich.edu        if len(args) == 0:
10129537Satgutier@umich.edu            handle_kwarg(self, kwargs, 'ip')
10139537Satgutier@umich.edu            handle_kwarg(self, kwargs, 'port')
10149537Satgutier@umich.edu
10159537Satgutier@umich.edu        elif len(args) == 1:
10169537Satgutier@umich.edu            if kwargs:
10179537Satgutier@umich.edu                if not 'ip' in kwargs and not 'port' in kwargs:
10189537Satgutier@umich.edu                    raise TypeError, "Invalid arguments"
10199537Satgutier@umich.edu                handle_kwarg(self, kwargs, 'ip', args[0])
10209537Satgutier@umich.edu                handle_kwarg(self, kwargs, 'port', args[0])
10219537Satgutier@umich.edu            elif isinstance(args[0], IpWithPort):
10229537Satgutier@umich.edu                self.ip = args[0].ip
10239537Satgutier@umich.edu                self.port = args[0].port
10249537Satgutier@umich.edu            else:
10259537Satgutier@umich.edu                (self.ip, self.port) = convert.toIpWithPort(args[0])
10269537Satgutier@umich.edu
10279537Satgutier@umich.edu        elif len(args) == 2:
10289537Satgutier@umich.edu            self.ip = args[0]
10299537Satgutier@umich.edu            self.port = args[1]
10309537Satgutier@umich.edu        else:
10319537Satgutier@umich.edu            raise TypeError, "Too many arguments specified"
10329537Satgutier@umich.edu
10339537Satgutier@umich.edu        if kwargs:
10349537Satgutier@umich.edu            raise TypeError, "Too many keywords: %s" % kwargs.keys()
10359537Satgutier@umich.edu
10369537Satgutier@umich.edu        self.verify()
10379537Satgutier@umich.edu
10389537Satgutier@umich.edu    def __call__(self, value):
10399537Satgutier@umich.edu        self.__init__(value)
10409537Satgutier@umich.edu        return value
10419537Satgutier@umich.edu
10429537Satgutier@umich.edu    def __str__(self):
10439537Satgutier@umich.edu        return "%s:%d" % (super(IpWithPort, self).__str__(), self.port)
10449537Satgutier@umich.edu
10459537Satgutier@umich.edu    def __eq__(self, other):
10469537Satgutier@umich.edu        if isinstance(other, IpWithPort):
10479537Satgutier@umich.edu            return self.ip == other.ip and self.port == other.port
10489537Satgutier@umich.edu        elif isinstance(other, str):
10499537Satgutier@umich.edu            try:
10509537Satgutier@umich.edu                return (self.ip, self.port) == convert.toIpWithPort(other)
10519537Satgutier@umich.edu            except:
10529537Satgutier@umich.edu                return False
10539537Satgutier@umich.edu        else:
10549537Satgutier@umich.edu            return False
10559537Satgutier@umich.edu
10569537Satgutier@umich.edu    def verify(self):
10579537Satgutier@umich.edu        self.verifyIp()
10589537Satgutier@umich.edu        if self.port < 0 or self.port > 0xffff:
10599537Satgutier@umich.edu            raise TypeError, "invalid port %d" % self.port
10609537Satgutier@umich.edu
10619537Satgutier@umich.edu    def getValue(self):
10629537Satgutier@umich.edu        from m5.internal.params import IpWithPort
10639537Satgutier@umich.edu        return IpWithPort(self.ip, self.port)
10649537Satgutier@umich.edu
10659537Satgutier@umich.edutime_formats = [ "%a %b %d %H:%M:%S %Z %Y",
10669537Satgutier@umich.edu                 "%a %b %d %H:%M:%S %Y",
10679537Satgutier@umich.edu                 "%Y/%m/%d %H:%M:%S",
10689537Satgutier@umich.edu                 "%Y/%m/%d %H:%M",
10699537Satgutier@umich.edu                 "%Y/%m/%d",
10709537Satgutier@umich.edu                 "%m/%d/%Y %H:%M:%S",
10719537Satgutier@umich.edu                 "%m/%d/%Y %H:%M",
10729537Satgutier@umich.edu                 "%m/%d/%Y",
10739537Satgutier@umich.edu                 "%m/%d/%y %H:%M:%S",
10749537Satgutier@umich.edu                 "%m/%d/%y %H:%M",
10759537Satgutier@umich.edu                 "%m/%d/%y"]
10769537Satgutier@umich.edu
10779537Satgutier@umich.edu
10789537Satgutier@umich.edudef parse_time(value):
10799537Satgutier@umich.edu    from time import gmtime, strptime, struct_time, time
10809537Satgutier@umich.edu    from datetime import datetime, date
10819537Satgutier@umich.edu
10829537Satgutier@umich.edu    if isinstance(value, struct_time):
10839537Satgutier@umich.edu        return value
10849537Satgutier@umich.edu
10859537Satgutier@umich.edu    if isinstance(value, (int, long)):
10869537Satgutier@umich.edu        return gmtime(value)
10879537Satgutier@umich.edu
10889537Satgutier@umich.edu    if isinstance(value, (datetime, date)):
10899537Satgutier@umich.edu        return value.timetuple()
10909537Satgutier@umich.edu
10919537Satgutier@umich.edu    if isinstance(value, str):
10929537Satgutier@umich.edu        if value in ('Now', 'Today'):
10939537Satgutier@umich.edu            return time.gmtime(time.time())
10949537Satgutier@umich.edu
10959537Satgutier@umich.edu        for format in time_formats:
10969537Satgutier@umich.edu            try:
10979537Satgutier@umich.edu                return strptime(value, format)
10989537Satgutier@umich.edu            except ValueError:
10999537Satgutier@umich.edu                pass
11009537Satgutier@umich.edu
11019537Satgutier@umich.edu    raise ValueError, "Could not parse '%s' as a time" % value
11029537Satgutier@umich.edu
11039537Satgutier@umich.educlass Time(ParamValue):
11049537Satgutier@umich.edu    cxx_type = 'tm'
11059537Satgutier@umich.edu
11069537Satgutier@umich.edu    @classmethod
11079537Satgutier@umich.edu    def cxx_predecls(cls, code):
11089537Satgutier@umich.edu        code('#include <time.h>')
11099537Satgutier@umich.edu
11109537Satgutier@umich.edu    @classmethod
11119537Satgutier@umich.edu    def swig_predecls(cls, code):
11129537Satgutier@umich.edu        code('%include "python/swig/time.i"')
11139537Satgutier@umich.edu
11149537Satgutier@umich.edu    def __init__(self, value):
11159537Satgutier@umich.edu        self.value = parse_time(value)
11169537Satgutier@umich.edu
11179537Satgutier@umich.edu    def __call__(self, value):
11189537Satgutier@umich.edu        self.__init__(value)
11199537Satgutier@umich.edu        return value
11209537Satgutier@umich.edu
11219537Satgutier@umich.edu    def getValue(self):
11229537Satgutier@umich.edu        from m5.internal.params import tm
11239537Satgutier@umich.edu
11249537Satgutier@umich.edu        c_time = tm()
11259537Satgutier@umich.edu        py_time = self.value
11269537Satgutier@umich.edu
11279537Satgutier@umich.edu        # UNIX is years since 1900
11289537Satgutier@umich.edu        c_time.tm_year = py_time.tm_year - 1900;
11299537Satgutier@umich.edu
11309537Satgutier@umich.edu        # Python starts at 1, UNIX starts at 0
11319537Satgutier@umich.edu        c_time.tm_mon =  py_time.tm_mon - 1;
11329537Satgutier@umich.edu        c_time.tm_mday = py_time.tm_mday;
11339537Satgutier@umich.edu        c_time.tm_hour = py_time.tm_hour;
11349537Satgutier@umich.edu        c_time.tm_min = py_time.tm_min;
11359537Satgutier@umich.edu        c_time.tm_sec = py_time.tm_sec;
11369537Satgutier@umich.edu
11379537Satgutier@umich.edu        # Python has 0 as Monday, UNIX is 0 as sunday
11389537Satgutier@umich.edu        c_time.tm_wday = py_time.tm_wday + 1
11399537Satgutier@umich.edu        if c_time.tm_wday > 6:
11409537Satgutier@umich.edu            c_time.tm_wday -= 7;
11419537Satgutier@umich.edu
11429537Satgutier@umich.edu        # Python starts at 1, Unix starts at 0
11439537Satgutier@umich.edu        c_time.tm_yday = py_time.tm_yday - 1;
11449537Satgutier@umich.edu
11459537Satgutier@umich.edu        return c_time
11469537Satgutier@umich.edu
11479537Satgutier@umich.edu    def __str__(self):
11489537Satgutier@umich.edu        return time.asctime(self.value)
11499537Satgutier@umich.edu
11509537Satgutier@umich.edu    def ini_str(self):
11519537Satgutier@umich.edu        return str(self)
11529537Satgutier@umich.edu
11539537Satgutier@umich.edu    def get_config_as_dict(self):
11549537Satgutier@umich.edu        assert false
11559537Satgutier@umich.edu        return str(self)
11569537Satgutier@umich.edu
11579537Satgutier@umich.edu# Enumerated types are a little more complex.  The user specifies the
11589537Satgutier@umich.edu# type as Enum(foo) where foo is either a list or dictionary of
11599537Satgutier@umich.edu# alternatives (typically strings, but not necessarily so).  (In the
11609537Satgutier@umich.edu# long run, the integer value of the parameter will be the list index
11619537Satgutier@umich.edu# or the corresponding dictionary value.  For now, since we only check
11629537Satgutier@umich.edu# that the alternative is valid and then spit it into a .ini file,
11639537Satgutier@umich.edu# there's not much point in using the dictionary.)
11649537Satgutier@umich.edu
11659537Satgutier@umich.edu# What Enum() must do is generate a new type encapsulating the
11669537Satgutier@umich.edu# provided list/dictionary so that specific values of the parameter
11679537Satgutier@umich.edu# can be instances of that type.  We define two hidden internal
11689537Satgutier@umich.edu# classes (_ListEnum and _DictEnum) to serve as base classes, then
11699537Satgutier@umich.edu# derive the new type from the appropriate base class on the fly.
11709537Satgutier@umich.edu
11719537Satgutier@umich.eduallEnums = {}
11729537Satgutier@umich.edu# Metaclass for Enum types
11739537Satgutier@umich.educlass MetaEnum(MetaParamValue):
11749537Satgutier@umich.edu    def __new__(mcls, name, bases, dict):
11759537Satgutier@umich.edu        assert name not in allEnums
11769537Satgutier@umich.edu
11779537Satgutier@umich.edu        cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict)
11789537Satgutier@umich.edu        allEnums[name] = cls
11799537Satgutier@umich.edu        return cls
11809537Satgutier@umich.edu
11819537Satgutier@umich.edu    def __init__(cls, name, bases, init_dict):
11829537Satgutier@umich.edu        if init_dict.has_key('map'):
11839537Satgutier@umich.edu            if not isinstance(cls.map, dict):
11849537Satgutier@umich.edu                raise TypeError, "Enum-derived class attribute 'map' " \
11859537Satgutier@umich.edu                      "must be of type dict"
11869537Satgutier@umich.edu            # build list of value strings from map
11879537Satgutier@umich.edu            cls.vals = cls.map.keys()
11889537Satgutier@umich.edu            cls.vals.sort()
11899537Satgutier@umich.edu        elif init_dict.has_key('vals'):
11909537Satgutier@umich.edu            if not isinstance(cls.vals, list):
11919537Satgutier@umich.edu                raise TypeError, "Enum-derived class attribute 'vals' " \
11929537Satgutier@umich.edu                      "must be of type list"
11939537Satgutier@umich.edu            # build string->value map from vals sequence
11949537Satgutier@umich.edu            cls.map = {}
11959537Satgutier@umich.edu            for idx,val in enumerate(cls.vals):
11969537Satgutier@umich.edu                cls.map[val] = idx
11979537Satgutier@umich.edu        else:
11989537Satgutier@umich.edu            raise TypeError, "Enum-derived class must define "\
11999537Satgutier@umich.edu                  "attribute 'map' or 'vals'"
12009537Satgutier@umich.edu
12019537Satgutier@umich.edu        cls.cxx_type = 'Enums::%s' % name
12029537Satgutier@umich.edu
12039537Satgutier@umich.edu        super(MetaEnum, cls).__init__(name, bases, init_dict)
12049537Satgutier@umich.edu
12059537Satgutier@umich.edu    # Generate C++ class declaration for this enum type.
12069537Satgutier@umich.edu    # Note that we wrap the enum in a class/struct to act as a namespace,
12079537Satgutier@umich.edu    # so that the enum strings can be brief w/o worrying about collisions.
12089537Satgutier@umich.edu    def cxx_decl(cls, code):
12099537Satgutier@umich.edu        wrapper_name = cls.wrapper_name
12109537Satgutier@umich.edu        wrapper = 'struct' if cls.wrapper_is_struct else 'namespace'
12119537Satgutier@umich.edu        name = cls.__name__ if cls.enum_name is None else cls.enum_name
12129537Satgutier@umich.edu        idem_macro = '__ENUM__%s__%s__' % (wrapper_name, name)
12139537Satgutier@umich.edu
12149537Satgutier@umich.edu        code('''\
12159537Satgutier@umich.edu#ifndef $idem_macro
12169537Satgutier@umich.edu#define $idem_macro
12179537Satgutier@umich.edu
12189537Satgutier@umich.edu$wrapper $wrapper_name {
12199537Satgutier@umich.edu    enum $name {
12209537Satgutier@umich.edu''')
12219537Satgutier@umich.edu        code.indent(2)
12229537Satgutier@umich.edu        for val in cls.vals:
12239537Satgutier@umich.edu            code('$val = ${{cls.map[val]}},')
12249537Satgutier@umich.edu        code('Num_$name = ${{len(cls.vals)}}')
12259537Satgutier@umich.edu        code.dedent(2)
12269537Satgutier@umich.edu        code('    };')
12279537Satgutier@umich.edu
12289537Satgutier@umich.edu        if cls.wrapper_is_struct:
12299537Satgutier@umich.edu            code('    static const char *${name}Strings[Num_${name}];')
12309537Satgutier@umich.edu            code('};')
12319537Satgutier@umich.edu        else:
12329537Satgutier@umich.edu            code('extern const char *${name}Strings[Num_${name}];')
12339537Satgutier@umich.edu            code('}')
12349537Satgutier@umich.edu
12359537Satgutier@umich.edu        code()
12369537Satgutier@umich.edu        code('#endif // $idem_macro')
12379537Satgutier@umich.edu
12389537Satgutier@umich.edu    def cxx_def(cls, code):
12399537Satgutier@umich.edu        wrapper_name = cls.wrapper_name
12409537Satgutier@umich.edu        file_name = cls.__name__
12419537Satgutier@umich.edu        name = cls.__name__ if cls.enum_name is None else cls.enum_name
12429537Satgutier@umich.edu
12439537Satgutier@umich.edu        code('#include "enums/$file_name.hh"')
12449537Satgutier@umich.edu        if cls.wrapper_is_struct:
12459537Satgutier@umich.edu            code('const char *${wrapper_name}::${name}Strings'
12469537Satgutier@umich.edu                '[Num_${name}] =')
12479537Satgutier@umich.edu        else:
12489537Satgutier@umich.edu            code('namespace Enums {')
12499537Satgutier@umich.edu            code.indent(1)
12509537Satgutier@umich.edu            code(' const char *${name}Strings[Num_${name}] =')
12519537Satgutier@umich.edu
12529537Satgutier@umich.edu        code('{')
12539537Satgutier@umich.edu        code.indent(1)
12549537Satgutier@umich.edu        for val in cls.vals:
12559537Satgutier@umich.edu            code('"$val",')
12569537Satgutier@umich.edu        code.dedent(1)
12579537Satgutier@umich.edu        code('};')
12589537Satgutier@umich.edu
12599537Satgutier@umich.edu        if not cls.wrapper_is_struct:
12609537Satgutier@umich.edu            code('} // namespace $wrapper_name')
12619537Satgutier@umich.edu            code.dedent(1)
12629537Satgutier@umich.edu
12639537Satgutier@umich.edu    def swig_decl(cls, code):
12649537Satgutier@umich.edu        name = cls.__name__
12659537Satgutier@umich.edu        code('''\
12669537Satgutier@umich.edu%module(package="m5.internal") enum_$name
12679537Satgutier@umich.edu
12689537Satgutier@umich.edu%{
12699537Satgutier@umich.edu#include "enums/$name.hh"
12709537Satgutier@umich.edu%}
12719537Satgutier@umich.edu
12729537Satgutier@umich.edu%include "enums/$name.hh"
12739537Satgutier@umich.edu''')
12749537Satgutier@umich.edu
12759537Satgutier@umich.edu
12769537Satgutier@umich.edu# Base class for enum types.
12779537Satgutier@umich.educlass Enum(ParamValue):
12789537Satgutier@umich.edu    __metaclass__ = MetaEnum
12799537Satgutier@umich.edu    vals = []
12809537Satgutier@umich.edu    cmd_line_settable = True
12819537Satgutier@umich.edu
12829537Satgutier@umich.edu    # The name of the wrapping namespace or struct
12839537Satgutier@umich.edu    wrapper_name = 'Enums'
12849537Satgutier@umich.edu
12859537Satgutier@umich.edu    # If true, the enum is wrapped in a struct rather than a namespace
12869537Satgutier@umich.edu    wrapper_is_struct = False
12879537Satgutier@umich.edu
12889537Satgutier@umich.edu    # If not None, use this as the enum name rather than this class name
12899537Satgutier@umich.edu    enum_name = None
12909537Satgutier@umich.edu
12919537Satgutier@umich.edu    def __init__(self, value):
12929537Satgutier@umich.edu        if value not in self.map:
12939537Satgutier@umich.edu            raise TypeError, "Enum param got bad value '%s' (not in %s)" \
12949537Satgutier@umich.edu                  % (value, self.vals)
12959537Satgutier@umich.edu        self.value = value
12969537Satgutier@umich.edu
12979537Satgutier@umich.edu    def __call__(self, value):
12989537Satgutier@umich.edu        self.__init__(value)
12999537Satgutier@umich.edu        return value
13009537Satgutier@umich.edu
13019537Satgutier@umich.edu    @classmethod
13029537Satgutier@umich.edu    def cxx_predecls(cls, code):
13039537Satgutier@umich.edu        code('#include "enums/$0.hh"', cls.__name__)
13049537Satgutier@umich.edu
13059537Satgutier@umich.edu    @classmethod
13069537Satgutier@umich.edu    def swig_predecls(cls, code):
13079537Satgutier@umich.edu        code('%import "python/m5/internal/enum_$0.i"', cls.__name__)
13089537Satgutier@umich.edu
13099537Satgutier@umich.edu    def getValue(self):
13109537Satgutier@umich.edu        return int(self.map[self.value])
13119537Satgutier@umich.edu
13129537Satgutier@umich.edu    def __str__(self):
13139537Satgutier@umich.edu        return self.value
13149537Satgutier@umich.edu
13159537Satgutier@umich.edu# how big does a rounding error need to be before we warn about it?
13169537Satgutier@umich.edufrequency_tolerance = 0.001  # 0.1%
13179537Satgutier@umich.edu
13189537Satgutier@umich.educlass TickParamValue(NumericParamValue):
13199537Satgutier@umich.edu    cxx_type = 'Tick'
13209537Satgutier@umich.edu    ex_str = "1MHz"
13219537Satgutier@umich.edu    cmd_line_settable = True
13229537Satgutier@umich.edu
13239537Satgutier@umich.edu    @classmethod
13249537Satgutier@umich.edu    def cxx_predecls(cls, code):
13259537Satgutier@umich.edu        code('#include "base/types.hh"')
13269537Satgutier@umich.edu
13279537Satgutier@umich.edu    @classmethod
13289537Satgutier@umich.edu    def swig_predecls(cls, code):
13299537Satgutier@umich.edu        code('%import "stdint.i"')
13309537Satgutier@umich.edu        code('%import "base/types.hh"')
13319537Satgutier@umich.edu
13329537Satgutier@umich.edu    def __call__(self, value):
13339537Satgutier@umich.edu        self.__init__(value)
13349537Satgutier@umich.edu        return value
13359537Satgutier@umich.edu
13369537Satgutier@umich.edu    def getValue(self):
13379537Satgutier@umich.edu        return long(self.value)
13389537Satgutier@umich.edu
13399537Satgutier@umich.educlass Latency(TickParamValue):
13409537Satgutier@umich.edu    ex_str = "100ns"
13419537Satgutier@umich.edu
13429537Satgutier@umich.edu    def __init__(self, value):
13439537Satgutier@umich.edu        if isinstance(value, (Latency, Clock)):
13449537Satgutier@umich.edu            self.ticks = value.ticks
13459537Satgutier@umich.edu            self.value = value.value
13469537Satgutier@umich.edu        elif isinstance(value, Frequency):
13479537Satgutier@umich.edu            self.ticks = value.ticks
13489537Satgutier@umich.edu            self.value = 1.0 / value.value
13499537Satgutier@umich.edu        elif value.endswith('t'):
13509537Satgutier@umich.edu            self.ticks = True
13519537Satgutier@umich.edu            self.value = int(value[:-1])
13529537Satgutier@umich.edu        else:
13539537Satgutier@umich.edu            self.ticks = False
13549537Satgutier@umich.edu            self.value = convert.toLatency(value)
13559537Satgutier@umich.edu
13569537Satgutier@umich.edu    def __call__(self, value):
13579537Satgutier@umich.edu        self.__init__(value)
13589537Satgutier@umich.edu        return value
13599537Satgutier@umich.edu
13609537Satgutier@umich.edu    def __getattr__(self, attr):
13619537Satgutier@umich.edu        if attr in ('latency', 'period'):
13629537Satgutier@umich.edu            return self
13639537Satgutier@umich.edu        if attr == 'frequency':
13649537Satgutier@umich.edu            return Frequency(self)
13659537Satgutier@umich.edu        raise AttributeError, "Latency object has no attribute '%s'" % attr
13669537Satgutier@umich.edu
13679537Satgutier@umich.edu    def getValue(self):
13689537Satgutier@umich.edu        if self.ticks or self.value == 0:
13699537Satgutier@umich.edu            value = self.value
13709537Satgutier@umich.edu        else:
13719537Satgutier@umich.edu            value = ticks.fromSeconds(self.value)
13729537Satgutier@umich.edu        return long(value)
13739537Satgutier@umich.edu
13749537Satgutier@umich.edu    def config_value(self):
13759537Satgutier@umich.edu        return self.getValue()
13769537Satgutier@umich.edu
13779537Satgutier@umich.edu    # convert latency to ticks
13789537Satgutier@umich.edu    def ini_str(self):
13799537Satgutier@umich.edu        return '%d' % self.getValue()
13809537Satgutier@umich.edu
13819537Satgutier@umich.educlass Frequency(TickParamValue):
13829537Satgutier@umich.edu    ex_str = "1GHz"
13839537Satgutier@umich.edu
13849537Satgutier@umich.edu    def __init__(self, value):
13859537Satgutier@umich.edu        if isinstance(value, (Latency, Clock)):
13869537Satgutier@umich.edu            if value.value == 0:
13879537Satgutier@umich.edu                self.value = 0
13889537Satgutier@umich.edu            else:
13899537Satgutier@umich.edu                self.value = 1.0 / value.value
13909537Satgutier@umich.edu            self.ticks = value.ticks
13919537Satgutier@umich.edu        elif isinstance(value, Frequency):
13929537Satgutier@umich.edu            self.value = value.value
13939537Satgutier@umich.edu            self.ticks = value.ticks
13949537Satgutier@umich.edu        else:
13959537Satgutier@umich.edu            self.ticks = False
13969537Satgutier@umich.edu            self.value = convert.toFrequency(value)
13979537Satgutier@umich.edu
13989537Satgutier@umich.edu    def __call__(self, value):
13999537Satgutier@umich.edu        self.__init__(value)
14009537Satgutier@umich.edu        return value
14019537Satgutier@umich.edu
14029537Satgutier@umich.edu    def __getattr__(self, attr):
14039537Satgutier@umich.edu        if attr == 'frequency':
14049537Satgutier@umich.edu            return self
14059537Satgutier@umich.edu        if attr in ('latency', 'period'):
14069537Satgutier@umich.edu            return Latency(self)
14079537Satgutier@umich.edu        raise AttributeError, "Frequency object has no attribute '%s'" % attr
14089537Satgutier@umich.edu
14099537Satgutier@umich.edu    # convert latency to ticks
14109537Satgutier@umich.edu    def getValue(self):
14119537Satgutier@umich.edu        if self.ticks or self.value == 0:
14129537Satgutier@umich.edu            value = self.value
14139537Satgutier@umich.edu        else:
14149537Satgutier@umich.edu            value = ticks.fromSeconds(1.0 / self.value)
14159537Satgutier@umich.edu        return long(value)
14169537Satgutier@umich.edu
14179537Satgutier@umich.edu    def config_value(self):
14189537Satgutier@umich.edu        return self.getValue()
14199537Satgutier@umich.edu
14209537Satgutier@umich.edu    def ini_str(self):
14219537Satgutier@umich.edu        return '%d' % self.getValue()
14229537Satgutier@umich.edu
14239537Satgutier@umich.edu# A generic Frequency and/or Latency value. Value is stored as a
14249537Satgutier@umich.edu# latency, just like Latency and Frequency.
14259537Satgutier@umich.educlass Clock(TickParamValue):
14269537Satgutier@umich.edu    def __init__(self, value):
14279537Satgutier@umich.edu        if isinstance(value, (Latency, Clock)):
14289537Satgutier@umich.edu            self.ticks = value.ticks
14299537Satgutier@umich.edu            self.value = value.value
14309537Satgutier@umich.edu        elif isinstance(value, Frequency):
14319537Satgutier@umich.edu            self.ticks = value.ticks
14329537Satgutier@umich.edu            self.value = 1.0 / value.value
14339537Satgutier@umich.edu        elif value.endswith('t'):
14349537Satgutier@umich.edu            self.ticks = True
14359537Satgutier@umich.edu            self.value = int(value[:-1])
14369537Satgutier@umich.edu        else:
14379537Satgutier@umich.edu            self.ticks = False
14389537Satgutier@umich.edu            self.value = convert.anyToLatency(value)
14399537Satgutier@umich.edu
14409537Satgutier@umich.edu    def __call__(self, value):
14419537Satgutier@umich.edu        self.__init__(value)
14429537Satgutier@umich.edu        return value
14439537Satgutier@umich.edu
14449537Satgutier@umich.edu    def __str__(self):
14459537Satgutier@umich.edu        return "%s" % Latency(self)
14469537Satgutier@umich.edu
14479537Satgutier@umich.edu    def __getattr__(self, attr):
14489537Satgutier@umich.edu        if attr == 'frequency':
14499537Satgutier@umich.edu            return Frequency(self)
14509537Satgutier@umich.edu        if attr in ('latency', 'period'):
14519537Satgutier@umich.edu            return Latency(self)
14529537Satgutier@umich.edu        raise AttributeError, "Frequency object has no attribute '%s'" % attr
14539537Satgutier@umich.edu
14549537Satgutier@umich.edu    def getValue(self):
14559537Satgutier@umich.edu        return self.period.getValue()
14569537Satgutier@umich.edu
14579537Satgutier@umich.edu    def config_value(self):
14589537Satgutier@umich.edu        return self.period.config_value()
14599537Satgutier@umich.edu
14609537Satgutier@umich.edu    def ini_str(self):
14619537Satgutier@umich.edu        return self.period.ini_str()
14629537Satgutier@umich.edu
14639537Satgutier@umich.educlass Voltage(float,ParamValue):
14649537Satgutier@umich.edu    cxx_type = 'double'
14659537Satgutier@umich.edu    ex_str = "1V"
14669537Satgutier@umich.edu    cmd_line_settable = False
1467
1468    def __new__(cls, value):
1469        # convert to voltage
1470        val = convert.toVoltage(value)
1471        return super(cls, Voltage).__new__(cls, val)
1472
1473    def __call__(self, value):
1474        val = convert.toVoltage(value)
1475        self.__init__(val)
1476        return value
1477
1478    def __str__(self):
1479        return str(self.getValue())
1480
1481    def getValue(self):
1482        value = float(self)
1483        return value
1484
1485    def ini_str(self):
1486        return '%f' % self.getValue()
1487
1488class NetworkBandwidth(float,ParamValue):
1489    cxx_type = 'float'
1490    ex_str = "1Gbps"
1491    cmd_line_settable = True
1492
1493    def __new__(cls, value):
1494        # convert to bits per second
1495        val = convert.toNetworkBandwidth(value)
1496        return super(cls, NetworkBandwidth).__new__(cls, val)
1497
1498    def __str__(self):
1499        return str(self.val)
1500
1501    def __call__(self, value):
1502        val = convert.toNetworkBandwidth(value)
1503        self.__init__(val)
1504        return value
1505
1506    def getValue(self):
1507        # convert to seconds per byte
1508        value = 8.0 / float(self)
1509        # convert to ticks per byte
1510        value = ticks.fromSeconds(value)
1511        return float(value)
1512
1513    def ini_str(self):
1514        return '%f' % self.getValue()
1515
1516    def config_value(self):
1517        return '%f' % self.getValue()
1518
1519class MemoryBandwidth(float,ParamValue):
1520    cxx_type = 'float'
1521    ex_str = "1GB/s"
1522    cmd_line_settable = True
1523
1524    def __new__(cls, value):
1525        # convert to bytes per second
1526        val = convert.toMemoryBandwidth(value)
1527        return super(cls, MemoryBandwidth).__new__(cls, val)
1528
1529    def __call__(self, value):
1530        val = convert.toMemoryBandwidth(value)
1531        self.__init__(val)
1532        return value
1533
1534    def getValue(self):
1535        # convert to seconds per byte
1536        value = float(self)
1537        if value:
1538            value = 1.0 / float(self)
1539        # convert to ticks per byte
1540        value = ticks.fromSeconds(value)
1541        return float(value)
1542
1543    def ini_str(self):
1544        return '%f' % self.getValue()
1545
1546    def config_value(self):
1547        return '%f' % self.getValue()
1548
1549#
1550# "Constants"... handy aliases for various values.
1551#
1552
1553# Special class for NULL pointers.  Note the special check in
1554# make_param_value() above that lets these be assigned where a
1555# SimObject is required.
1556# only one copy of a particular node
1557class NullSimObject(object):
1558    __metaclass__ = Singleton
1559
1560    def __call__(cls):
1561        return cls
1562
1563    def _instantiate(self, parent = None, path = ''):
1564        pass
1565
1566    def ini_str(self):
1567        return 'Null'
1568
1569    def unproxy(self, base):
1570        return self
1571
1572    def set_path(self, parent, name):
1573        pass
1574
1575    def __str__(self):
1576        return 'Null'
1577
1578    def config_value(self):
1579        return None
1580
1581    def getValue(self):
1582        return None
1583
1584# The only instance you'll ever need...
1585NULL = NullSimObject()
1586
1587def isNullPointer(value):
1588    return isinstance(value, NullSimObject)
1589
1590# Some memory range specifications use this as a default upper bound.
1591MaxAddr = Addr.max
1592MaxTick = Tick.max
1593AllMemory = AddrRange(0, MaxAddr)
1594
1595
1596#####################################################################
1597#
1598# Port objects
1599#
1600# Ports are used to interconnect objects in the memory system.
1601#
1602#####################################################################
1603
1604# Port reference: encapsulates a reference to a particular port on a
1605# particular SimObject.
1606class PortRef(object):
1607    def __init__(self, simobj, name, role):
1608        assert(isSimObject(simobj) or isSimObjectClass(simobj))
1609        self.simobj = simobj
1610        self.name = name
1611        self.role = role
1612        self.peer = None   # not associated with another port yet
1613        self.ccConnected = False # C++ port connection done?
1614        self.index = -1  # always -1 for non-vector ports
1615
1616    def __str__(self):
1617        return '%s.%s' % (self.simobj, self.name)
1618
1619    def __len__(self):
1620        # Return the number of connected ports, i.e. 0 is we have no
1621        # peer and 1 if we do.
1622        return int(self.peer != None)
1623
1624    # for config.ini, print peer's name (not ours)
1625    def ini_str(self):
1626        return str(self.peer)
1627
1628    # for config.json
1629    def get_config_as_dict(self):
1630        return {'role' : self.role, 'peer' : str(self.peer)}
1631
1632    def __getattr__(self, attr):
1633        if attr == 'peerObj':
1634            # shorthand for proxies
1635            return self.peer.simobj
1636        raise AttributeError, "'%s' object has no attribute '%s'" % \
1637              (self.__class__.__name__, attr)
1638
1639    # Full connection is symmetric (both ways).  Called via
1640    # SimObject.__setattr__ as a result of a port assignment, e.g.,
1641    # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
1642    # e.g., "obj1.portA[3] = obj2.portB".
1643    def connect(self, other):
1644        if isinstance(other, VectorPortRef):
1645            # reference to plain VectorPort is implicit append
1646            other = other._get_next()
1647        if self.peer and not proxy.isproxy(self.peer):
1648            fatal("Port %s is already connected to %s, cannot connect %s\n",
1649                  self, self.peer, other);
1650        self.peer = other
1651        if proxy.isproxy(other):
1652            other.set_param_desc(PortParamDesc())
1653        elif isinstance(other, PortRef):
1654            if other.peer is not self:
1655                other.connect(self)
1656        else:
1657            raise TypeError, \
1658                  "assigning non-port reference '%s' to port '%s'" \
1659                  % (other, self)
1660
1661    # Allow a master/slave port pair to be spliced between
1662    # a port and its connected peer. Useful operation for connecting
1663    # instrumentation structures into a system when it is necessary
1664    # to connect the instrumentation after the full system has been
1665    # constructed.
1666    def splice(self, new_master_peer, new_slave_peer):
1667        if self.peer and not proxy.isproxy(self.peer):
1668            if isinstance(new_master_peer, PortRef) and \
1669               isinstance(new_slave_peer, PortRef):
1670                 old_peer = self.peer
1671                 if self.role == 'SLAVE':
1672                     self.peer = new_master_peer
1673                     old_peer.peer = new_slave_peer
1674                     new_master_peer.connect(self)
1675                     new_slave_peer.connect(old_peer)
1676                 elif self.role == 'MASTER':
1677                     self.peer = new_slave_peer
1678                     old_peer.peer = new_master_peer
1679                     new_slave_peer.connect(self)
1680                     new_master_peer.connect(old_peer)
1681                 else:
1682                     panic("Port %s has unknown role, "+\
1683                           "cannot splice in new peers\n", self)
1684            else:
1685                raise TypeError, \
1686                      "Splicing non-port references '%s','%s' to port '%s'"\
1687                      % (new_peer, peers_new_peer, self)
1688        else:
1689            fatal("Port %s not connected, cannot splice in new peers\n", self)
1690
1691    def clone(self, simobj, memo):
1692        if memo.has_key(self):
1693            return memo[self]
1694        newRef = copy.copy(self)
1695        memo[self] = newRef
1696        newRef.simobj = simobj
1697        assert(isSimObject(newRef.simobj))
1698        if self.peer and not proxy.isproxy(self.peer):
1699            peerObj = self.peer.simobj(_memo=memo)
1700            newRef.peer = self.peer.clone(peerObj, memo)
1701            assert(not isinstance(newRef.peer, VectorPortRef))
1702        return newRef
1703
1704    def unproxy(self, simobj):
1705        assert(simobj is self.simobj)
1706        if proxy.isproxy(self.peer):
1707            try:
1708                realPeer = self.peer.unproxy(self.simobj)
1709            except:
1710                print "Error in unproxying port '%s' of %s" % \
1711                      (self.name, self.simobj.path())
1712                raise
1713            self.connect(realPeer)
1714
1715    # Call C++ to create corresponding port connection between C++ objects
1716    def ccConnect(self):
1717        from m5.internal.pyobject import connectPorts
1718
1719        if self.role == 'SLAVE':
1720            # do nothing and let the master take care of it
1721            return
1722
1723        if self.ccConnected: # already done this
1724            return
1725        peer = self.peer
1726        if not self.peer: # nothing to connect to
1727            return
1728
1729        # check that we connect a master to a slave
1730        if self.role == peer.role:
1731            raise TypeError, \
1732                "cannot connect '%s' and '%s' due to identical role '%s'" \
1733                % (peer, self, self.role)
1734
1735        try:
1736            # self is always the master and peer the slave
1737            connectPorts(self.simobj.getCCObject(), self.name, self.index,
1738                         peer.simobj.getCCObject(), peer.name, peer.index)
1739        except:
1740            print "Error connecting port %s.%s to %s.%s" % \
1741                  (self.simobj.path(), self.name,
1742                   peer.simobj.path(), peer.name)
1743            raise
1744        self.ccConnected = True
1745        peer.ccConnected = True
1746
1747# A reference to an individual element of a VectorPort... much like a
1748# PortRef, but has an index.
1749class VectorPortElementRef(PortRef):
1750    def __init__(self, simobj, name, role, index):
1751        PortRef.__init__(self, simobj, name, role)
1752        self.index = index
1753
1754    def __str__(self):
1755        return '%s.%s[%d]' % (self.simobj, self.name, self.index)
1756
1757# A reference to a complete vector-valued port (not just a single element).
1758# Can be indexed to retrieve individual VectorPortElementRef instances.
1759class VectorPortRef(object):
1760    def __init__(self, simobj, name, role):
1761        assert(isSimObject(simobj) or isSimObjectClass(simobj))
1762        self.simobj = simobj
1763        self.name = name
1764        self.role = role
1765        self.elements = []
1766
1767    def __str__(self):
1768        return '%s.%s[:]' % (self.simobj, self.name)
1769
1770    def __len__(self):
1771        # Return the number of connected peers, corresponding the the
1772        # length of the elements.
1773        return len(self.elements)
1774
1775    # for config.ini, print peer's name (not ours)
1776    def ini_str(self):
1777        return ' '.join([el.ini_str() for el in self.elements])
1778
1779    # for config.json
1780    def get_config_as_dict(self):
1781        return {'role' : self.role,
1782                'peer' : [el.ini_str() for el in self.elements]}
1783
1784    def __getitem__(self, key):
1785        if not isinstance(key, int):
1786            raise TypeError, "VectorPort index must be integer"
1787        if key >= len(self.elements):
1788            # need to extend list
1789            ext = [VectorPortElementRef(self.simobj, self.name, self.role, i)
1790                   for i in range(len(self.elements), key+1)]
1791            self.elements.extend(ext)
1792        return self.elements[key]
1793
1794    def _get_next(self):
1795        return self[len(self.elements)]
1796
1797    def __setitem__(self, key, value):
1798        if not isinstance(key, int):
1799            raise TypeError, "VectorPort index must be integer"
1800        self[key].connect(value)
1801
1802    def connect(self, other):
1803        if isinstance(other, (list, tuple)):
1804            # Assign list of port refs to vector port.
1805            # For now, append them... not sure if that's the right semantics
1806            # or if it should replace the current vector.
1807            for ref in other:
1808                self._get_next().connect(ref)
1809        else:
1810            # scalar assignment to plain VectorPort is implicit append
1811            self._get_next().connect(other)
1812
1813    def clone(self, simobj, memo):
1814        if memo.has_key(self):
1815            return memo[self]
1816        newRef = copy.copy(self)
1817        memo[self] = newRef
1818        newRef.simobj = simobj
1819        assert(isSimObject(newRef.simobj))
1820        newRef.elements = [el.clone(simobj, memo) for el in self.elements]
1821        return newRef
1822
1823    def unproxy(self, simobj):
1824        [el.unproxy(simobj) for el in self.elements]
1825
1826    def ccConnect(self):
1827        [el.ccConnect() for el in self.elements]
1828
1829# Port description object.  Like a ParamDesc object, this represents a
1830# logical port in the SimObject class, not a particular port on a
1831# SimObject instance.  The latter are represented by PortRef objects.
1832class Port(object):
1833    # Generate a PortRef for this port on the given SimObject with the
1834    # given name
1835    def makeRef(self, simobj):
1836        return PortRef(simobj, self.name, self.role)
1837
1838    # Connect an instance of this port (on the given SimObject with
1839    # the given name) with the port described by the supplied PortRef
1840    def connect(self, simobj, ref):
1841        self.makeRef(simobj).connect(ref)
1842
1843    # No need for any pre-declarations at the moment as we merely rely
1844    # on an unsigned int.
1845    def cxx_predecls(self, code):
1846        pass
1847
1848    # Declare an unsigned int with the same name as the port, that
1849    # will eventually hold the number of connected ports (and thus the
1850    # number of elements for a VectorPort).
1851    def cxx_decl(self, code):
1852        code('unsigned int port_${{self.name}}_connection_count;')
1853
1854class MasterPort(Port):
1855    # MasterPort("description")
1856    def __init__(self, *args):
1857        if len(args) == 1:
1858            self.desc = args[0]
1859            self.role = 'MASTER'
1860        else:
1861            raise TypeError, 'wrong number of arguments'
1862
1863class SlavePort(Port):
1864    # SlavePort("description")
1865    def __init__(self, *args):
1866        if len(args) == 1:
1867            self.desc = args[0]
1868            self.role = 'SLAVE'
1869        else:
1870            raise TypeError, 'wrong number of arguments'
1871
1872# VectorPort description object.  Like Port, but represents a vector
1873# of connections (e.g., as on a XBar).
1874class VectorPort(Port):
1875    def __init__(self, *args):
1876        self.isVec = True
1877
1878    def makeRef(self, simobj):
1879        return VectorPortRef(simobj, self.name, self.role)
1880
1881class VectorMasterPort(VectorPort):
1882    # VectorMasterPort("description")
1883    def __init__(self, *args):
1884        if len(args) == 1:
1885            self.desc = args[0]
1886            self.role = 'MASTER'
1887            VectorPort.__init__(self, *args)
1888        else:
1889            raise TypeError, 'wrong number of arguments'
1890
1891class VectorSlavePort(VectorPort):
1892    # VectorSlavePort("description")
1893    def __init__(self, *args):
1894        if len(args) == 1:
1895            self.desc = args[0]
1896            self.role = 'SLAVE'
1897            VectorPort.__init__(self, *args)
1898        else:
1899            raise TypeError, 'wrong number of arguments'
1900
1901# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
1902# proxy objects (via set_param_desc()) so that proxy error messages
1903# make sense.
1904class PortParamDesc(object):
1905    __metaclass__ = Singleton
1906
1907    ptype_str = 'Port'
1908    ptype = Port
1909
1910baseEnums = allEnums.copy()
1911baseParams = allParams.copy()
1912
1913def clear():
1914    global allEnums, allParams
1915
1916    allEnums = baseEnums.copy()
1917    allParams = baseParams.copy()
1918
1919__all__ = ['Param', 'VectorParam',
1920           'Enum', 'Bool', 'String', 'Float',
1921           'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
1922           'Int32', 'UInt32', 'Int64', 'UInt64',
1923           'Counter', 'Addr', 'Tick', 'Percent',
1924           'TcpPort', 'UdpPort', 'EthernetAddr',
1925           'IpAddress', 'IpNetmask', 'IpWithPort',
1926           'MemorySize', 'MemorySize32',
1927           'Latency', 'Frequency', 'Clock', 'Voltage',
1928           'NetworkBandwidth', 'MemoryBandwidth',
1929           'AddrRange',
1930           'MaxAddr', 'MaxTick', 'AllMemory',
1931           'Time',
1932           'NextEthernetAddr', 'NULL',
1933           'MasterPort', 'SlavePort',
1934           'VectorMasterPort', 'VectorSlavePort']
1935
1936import SimObject
1937