params.py revision 13716
111988Sandreas.sandberg@arm.com# Copyright (c) 2012-2014, 2017, 2018 ARM Limited
28839Sandreas.hansson@arm.com# All rights reserved.
38839Sandreas.hansson@arm.com#
48839Sandreas.hansson@arm.com# The license below extends only to copyright in the software and shall
58839Sandreas.hansson@arm.com# not be construed as granting a license to any other intellectual
68839Sandreas.hansson@arm.com# property including but not limited to intellectual property relating
78839Sandreas.hansson@arm.com# to a hardware implementation of the functionality of the software
88839Sandreas.hansson@arm.com# licensed hereunder.  You may use the software subject to the license
98839Sandreas.hansson@arm.com# terms below provided that you ensure that this notice is replicated
108839Sandreas.hansson@arm.com# unmodified and in its entirety in all distributions of the software,
118839Sandreas.hansson@arm.com# modified or unmodified, in source code or in binary form.
128839Sandreas.hansson@arm.com#
133101Sstever@eecs.umich.edu# Copyright (c) 2004-2006 The Regents of The University of Michigan
148579Ssteve.reinhardt@amd.com# Copyright (c) 2010-2011 Advanced Micro Devices, Inc.
153101Sstever@eecs.umich.edu# All rights reserved.
163101Sstever@eecs.umich.edu#
173101Sstever@eecs.umich.edu# Redistribution and use in source and binary forms, with or without
183101Sstever@eecs.umich.edu# modification, are permitted provided that the following conditions are
193101Sstever@eecs.umich.edu# met: redistributions of source code must retain the above copyright
203101Sstever@eecs.umich.edu# notice, this list of conditions and the following disclaimer;
213101Sstever@eecs.umich.edu# redistributions in binary form must reproduce the above copyright
223101Sstever@eecs.umich.edu# notice, this list of conditions and the following disclaimer in the
233101Sstever@eecs.umich.edu# documentation and/or other materials provided with the distribution;
243101Sstever@eecs.umich.edu# neither the name of the copyright holders nor the names of its
253101Sstever@eecs.umich.edu# contributors may be used to endorse or promote products derived from
263101Sstever@eecs.umich.edu# this software without specific prior written permission.
273101Sstever@eecs.umich.edu#
283101Sstever@eecs.umich.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
293101Sstever@eecs.umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
303101Sstever@eecs.umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
313101Sstever@eecs.umich.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
323101Sstever@eecs.umich.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
333101Sstever@eecs.umich.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
343101Sstever@eecs.umich.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
353101Sstever@eecs.umich.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
363101Sstever@eecs.umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
373101Sstever@eecs.umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
383101Sstever@eecs.umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
393101Sstever@eecs.umich.edu#
403101Sstever@eecs.umich.edu# Authors: Steve Reinhardt
413101Sstever@eecs.umich.edu#          Nathan Binkert
427778Sgblack@eecs.umich.edu#          Gabe Black
438839Sandreas.hansson@arm.com#          Andreas Hansson
443101Sstever@eecs.umich.edu
453101Sstever@eecs.umich.edu#####################################################################
463101Sstever@eecs.umich.edu#
473101Sstever@eecs.umich.edu# Parameter description classes
483101Sstever@eecs.umich.edu#
493101Sstever@eecs.umich.edu# The _params dictionary in each class maps parameter names to either
503101Sstever@eecs.umich.edu# a Param or a VectorParam object.  These objects contain the
513101Sstever@eecs.umich.edu# parameter description string, the parameter type, and the default
523101Sstever@eecs.umich.edu# value (if any).  The convert() method on these objects is used to
533101Sstever@eecs.umich.edu# force whatever value is assigned to the parameter to the appropriate
543101Sstever@eecs.umich.edu# type.
553101Sstever@eecs.umich.edu#
563101Sstever@eecs.umich.edu# Note that the default values are loaded into the class's attribute
573101Sstever@eecs.umich.edu# space when the parameter dictionary is initialized (in
583101Sstever@eecs.umich.edu# MetaSimObject._new_param()); after that point they aren't used.
593101Sstever@eecs.umich.edu#
603101Sstever@eecs.umich.edu#####################################################################
613101Sstever@eecs.umich.edu
623885Sbinkertn@umich.edufrom __future__ import print_function
633885Sbinkertn@umich.edu
644762Snate@binkert.orgimport copy
653885Sbinkertn@umich.eduimport datetime
663885Sbinkertn@umich.eduimport re
677528Ssteve.reinhardt@amd.comimport sys
683885Sbinkertn@umich.eduimport time
694380Sbinkertn@umich.eduimport math
704167Sbinkertn@umich.edu
713102Sstever@eecs.umich.edufrom . import proxy
723101Sstever@eecs.umich.edufrom . import ticks
734762Snate@binkert.orgfrom .util import *
744762Snate@binkert.org
754762Snate@binkert.orgdef isSimObject(*args, **kwargs):
764762Snate@binkert.org    from . import SimObject
774762Snate@binkert.org    return SimObject.isSimObject(*args, **kwargs)
784762Snate@binkert.org
794762Snate@binkert.orgdef isSimObjectSequence(*args, **kwargs):
804762Snate@binkert.org    from . import SimObject
814762Snate@binkert.org    return SimObject.isSimObjectSequence(*args, **kwargs)
825033Smilesck@eecs.umich.edu
835033Smilesck@eecs.umich.edudef isSimObjectClass(*args, **kwargs):
845033Smilesck@eecs.umich.edu    from . import SimObject
855033Smilesck@eecs.umich.edu    return SimObject.isSimObjectClass(*args, **kwargs)
865033Smilesck@eecs.umich.edu
875033Smilesck@eecs.umich.eduallParams = {}
885033Smilesck@eecs.umich.edu
895033Smilesck@eecs.umich.educlass MetaParamValue(type):
905033Smilesck@eecs.umich.edu    def __new__(mcls, name, bases, dct):
915033Smilesck@eecs.umich.edu        cls = super(MetaParamValue, mcls).__new__(mcls, name, bases, dct)
923101Sstever@eecs.umich.edu        assert name not in allParams
933101Sstever@eecs.umich.edu        allParams[name] = cls
943101Sstever@eecs.umich.edu        return cls
955033Smilesck@eecs.umich.edu
9610267SGeoffrey.Blake@arm.com
978596Ssteve.reinhardt@amd.com# Dummy base class to identify types that are legitimate for SimObject
988596Ssteve.reinhardt@amd.com# parameters.
998596Ssteve.reinhardt@amd.comclass ParamValue(object):
1008596Ssteve.reinhardt@amd.com    __metaclass__ = MetaParamValue
1017673Snate@binkert.org    cmd_line_settable = False
1027673Snate@binkert.org
1037673Snate@binkert.org    # Generate the code needed as a prerequisite for declaring a C++
1047673Snate@binkert.org    # object of this type.  Typically generates one or more #include
10511988Sandreas.sandberg@arm.com    # statements.  Used when declaring parameters of this type.
10611988Sandreas.sandberg@arm.com    @classmethod
10711988Sandreas.sandberg@arm.com    def cxx_predecls(cls, code):
10811988Sandreas.sandberg@arm.com        pass
1093101Sstever@eecs.umich.edu
1103101Sstever@eecs.umich.edu    @classmethod
1113101Sstever@eecs.umich.edu    def pybind_predecls(cls, code):
1123101Sstever@eecs.umich.edu        cls.cxx_predecls(code)
1133101Sstever@eecs.umich.edu
11410380SAndrew.Bardsley@arm.com    # default for printing to .ini file is regular string conversion.
11510380SAndrew.Bardsley@arm.com    # will be overridden in some cases
11610380SAndrew.Bardsley@arm.com    def ini_str(self):
11710380SAndrew.Bardsley@arm.com        return str(self)
11810380SAndrew.Bardsley@arm.com
11910380SAndrew.Bardsley@arm.com    # default for printing to .json file is regular string conversion.
12010458Sandreas.hansson@arm.com    # will be overridden in some cases, mostly to use native Python
12110458Sandreas.hansson@arm.com    # types where there are similar JSON types
12210458Sandreas.hansson@arm.com    def config_value(self):
12310458Sandreas.hansson@arm.com        return str(self)
12410458Sandreas.hansson@arm.com
12510458Sandreas.hansson@arm.com    # Prerequisites for .ini parsing with cxx_ini_parse
12610458Sandreas.hansson@arm.com    @classmethod
12710458Sandreas.hansson@arm.com    def cxx_ini_predecls(cls, code):
12810458Sandreas.hansson@arm.com        pass
12910458Sandreas.hansson@arm.com
13010458Sandreas.hansson@arm.com    # parse a .ini file entry for this param from string expression
13110458Sandreas.hansson@arm.com    # src into lvalue dest (of the param's C++ type)
1323101Sstever@eecs.umich.edu    @classmethod
1333101Sstever@eecs.umich.edu    def cxx_ini_parse(cls, code, src, dest, ret):
1343101Sstever@eecs.umich.edu        code('// Unhandled param type: %s' % cls.__name__)
1353101Sstever@eecs.umich.edu        code('%s false;' % ret)
1363101Sstever@eecs.umich.edu
13710267SGeoffrey.Blake@arm.com    # allows us to blithely call unproxy() on things without checking
13810267SGeoffrey.Blake@arm.com    # if they're really proxies or not
13910267SGeoffrey.Blake@arm.com    def unproxy(self, base):
14010267SGeoffrey.Blake@arm.com        return self
1413101Sstever@eecs.umich.edu
1423101Sstever@eecs.umich.edu    # Produce a human readable version of the stored value
1433101Sstever@eecs.umich.edu    def pretty_print(self, value):
1443101Sstever@eecs.umich.edu        return str(value)
1453101Sstever@eecs.umich.edu
1463101Sstever@eecs.umich.edu# Regular parameter description.
1473101Sstever@eecs.umich.educlass ParamDesc(object):
1483101Sstever@eecs.umich.edu    def __init__(self, ptype_str, ptype, *args, **kwargs):
1493101Sstever@eecs.umich.edu        self.ptype_str = ptype_str
1503101Sstever@eecs.umich.edu        # remember ptype only if it is provided
1513101Sstever@eecs.umich.edu        if ptype != None:
1523101Sstever@eecs.umich.edu            self.ptype = ptype
1533101Sstever@eecs.umich.edu
1543101Sstever@eecs.umich.edu        if args:
1553101Sstever@eecs.umich.edu            if len(args) == 1:
1563101Sstever@eecs.umich.edu                self.desc = args[0]
1573101Sstever@eecs.umich.edu            elif len(args) == 2:
1583101Sstever@eecs.umich.edu                self.default = args[0]
1593101Sstever@eecs.umich.edu                self.desc = args[1]
1603101Sstever@eecs.umich.edu            else:
1613101Sstever@eecs.umich.edu                raise TypeError('too many arguments')
1623101Sstever@eecs.umich.edu
1633101Sstever@eecs.umich.edu        if 'desc' in kwargs:
1643101Sstever@eecs.umich.edu            assert(not hasattr(self, 'desc'))
1653101Sstever@eecs.umich.edu            self.desc = kwargs['desc']
1663101Sstever@eecs.umich.edu            del kwargs['desc']
1673101Sstever@eecs.umich.edu
1683101Sstever@eecs.umich.edu        if 'default' in kwargs:
1693101Sstever@eecs.umich.edu            assert(not hasattr(self, 'default'))
1703101Sstever@eecs.umich.edu            self.default = kwargs['default']
1713101Sstever@eecs.umich.edu            del kwargs['default']
1723101Sstever@eecs.umich.edu
1733101Sstever@eecs.umich.edu        if kwargs:
1743101Sstever@eecs.umich.edu            raise TypeError('extra unknown kwargs %s' % kwargs)
1753101Sstever@eecs.umich.edu
1765033Smilesck@eecs.umich.edu        if not hasattr(self, 'desc'):
1776656Snate@binkert.org            raise TypeError('desc attribute missing')
1785033Smilesck@eecs.umich.edu
1795033Smilesck@eecs.umich.edu    def __getattr__(self, attr):
1805033Smilesck@eecs.umich.edu        if attr == 'ptype':
1813101Sstever@eecs.umich.edu            from . import SimObject
1823101Sstever@eecs.umich.edu            ptype = SimObject.allClasses[self.ptype_str]
1833101Sstever@eecs.umich.edu            assert isSimObjectClass(ptype)
18410267SGeoffrey.Blake@arm.com            self.ptype = ptype
18510267SGeoffrey.Blake@arm.com            return ptype
18610267SGeoffrey.Blake@arm.com
18710267SGeoffrey.Blake@arm.com        raise AttributeError("'%s' object has no attribute '%s'" % \
18810267SGeoffrey.Blake@arm.com              (type(self).__name__, attr))
18910267SGeoffrey.Blake@arm.com
19010267SGeoffrey.Blake@arm.com    def example_str(self):
19110267SGeoffrey.Blake@arm.com        if hasattr(self.ptype, "ex_str"):
19210267SGeoffrey.Blake@arm.com            return self.ptype.ex_str
19310267SGeoffrey.Blake@arm.com        else:
19410267SGeoffrey.Blake@arm.com            return self.ptype_str
19510267SGeoffrey.Blake@arm.com
19610267SGeoffrey.Blake@arm.com    # Is the param available to be exposed on the command line
1973101Sstever@eecs.umich.edu    def isCmdLineSettable(self):
1983101Sstever@eecs.umich.edu        if hasattr(self.ptype, "cmd_line_settable"):
1993101Sstever@eecs.umich.edu            return self.ptype.cmd_line_settable
2003101Sstever@eecs.umich.edu        else:
2013101Sstever@eecs.umich.edu            return False
2023101Sstever@eecs.umich.edu
2033101Sstever@eecs.umich.edu    def convert(self, value):
2043101Sstever@eecs.umich.edu        if isinstance(value, proxy.BaseProxy):
2053101Sstever@eecs.umich.edu            value.set_param_desc(self)
2063101Sstever@eecs.umich.edu            return value
2073102Sstever@eecs.umich.edu        if 'ptype' not in self.__dict__ and isNullPointer(value):
2083101Sstever@eecs.umich.edu            # deferred evaluation of SimObject; continue to defer if
2093101Sstever@eecs.umich.edu            # we're just assigning a null pointer
2103101Sstever@eecs.umich.edu            return value
21110267SGeoffrey.Blake@arm.com        if isinstance(value, self.ptype):
21210267SGeoffrey.Blake@arm.com            return value
21310267SGeoffrey.Blake@arm.com        if isNullPointer(value) and isSimObjectClass(self.ptype):
21410267SGeoffrey.Blake@arm.com            return value
21510267SGeoffrey.Blake@arm.com        return self.ptype(value)
21610267SGeoffrey.Blake@arm.com
21710267SGeoffrey.Blake@arm.com    def pretty_print(self, value):
2187673Snate@binkert.org        if isinstance(value, proxy.BaseProxy):
2198607Sgblack@eecs.umich.edu           return str(value)
2207673Snate@binkert.org        if isNullPointer(value):
2213101Sstever@eecs.umich.edu           return NULL
22211988Sandreas.sandberg@arm.com        return self.ptype(value).pretty_print(value)
22311988Sandreas.sandberg@arm.com
22411988Sandreas.sandberg@arm.com    def cxx_predecls(self, code):
2257673Snate@binkert.org        code('#include <cstddef>')
2267673Snate@binkert.org        self.ptype.cxx_predecls(code)
2273101Sstever@eecs.umich.edu
2283101Sstever@eecs.umich.edu    def pybind_predecls(self, code):
2293101Sstever@eecs.umich.edu        self.ptype.pybind_predecls(code)
2303101Sstever@eecs.umich.edu
2313101Sstever@eecs.umich.edu    def cxx_decl(self, code):
2323101Sstever@eecs.umich.edu        code('${{self.ptype.cxx_type}} ${{self.name}};')
2335033Smilesck@eecs.umich.edu
2345475Snate@binkert.org# Vector-valued parameter description.  Just like ParamDesc, except
2355475Snate@binkert.org# that the value is a vector (list) of the specified type instead of a
2365475Snate@binkert.org# single value.
2375475Snate@binkert.org
23810380SAndrew.Bardsley@arm.comclass VectorParamValue(list):
23910380SAndrew.Bardsley@arm.com    __metaclass__ = MetaParamValue
24010380SAndrew.Bardsley@arm.com    def __setattr__(self, attr, value):
2413101Sstever@eecs.umich.edu        raise AttributeError("Not allowed to set %s on '%s'" % \
2423101Sstever@eecs.umich.edu                             (attr, type(self).__name__))
2433101Sstever@eecs.umich.edu
2444762Snate@binkert.org    def config_value(self):
2454762Snate@binkert.org        return [v.config_value() for v in self]
2464762Snate@binkert.org
2473101Sstever@eecs.umich.edu    def ini_str(self):
24812050Snikos.nikoleris@arm.com        return ' '.join([v.ini_str() for v in self])
24912050Snikos.nikoleris@arm.com
25012050Snikos.nikoleris@arm.com    def getValue(self):
2518459SAli.Saidi@ARM.com        return [ v.getValue() for v in self ]
2528459SAli.Saidi@ARM.com
25312050Snikos.nikoleris@arm.com    def unproxy(self, base):
2543101Sstever@eecs.umich.edu        if len(self) == 1 and isinstance(self[0], proxy.BaseProxy):
2557528Ssteve.reinhardt@amd.com            # The value is a proxy (e.g. Parent.any, Parent.all or
2567528Ssteve.reinhardt@amd.com            # Parent.x) therefore try resolve it
2577528Ssteve.reinhardt@amd.com            return self[0].unproxy(base)
2587528Ssteve.reinhardt@amd.com        else:
2597528Ssteve.reinhardt@amd.com            return [v.unproxy(base) for v in self]
2607528Ssteve.reinhardt@amd.com
2613101Sstever@eecs.umich.educlass SimObjectVector(VectorParamValue):
2627528Ssteve.reinhardt@amd.com    # support clone operation
2637528Ssteve.reinhardt@amd.com    def __call__(self, **kwargs):
2647528Ssteve.reinhardt@amd.com        return SimObjectVector([v(**kwargs) for v in self])
2657528Ssteve.reinhardt@amd.com
2667528Ssteve.reinhardt@amd.com    def clear_parent(self, old_parent):
2677528Ssteve.reinhardt@amd.com        for v in self:
2687528Ssteve.reinhardt@amd.com            v.clear_parent(old_parent)
2697528Ssteve.reinhardt@amd.com
2707528Ssteve.reinhardt@amd.com    def set_parent(self, parent, name):
2717528Ssteve.reinhardt@amd.com        if len(self) == 1:
2728321Ssteve.reinhardt@amd.com            self[0].set_parent(parent, name)
27312194Sgabeblack@google.com        else:
2747528Ssteve.reinhardt@amd.com            width = int(math.ceil(math.log(len(self))/math.log(10)))
2757528Ssteve.reinhardt@amd.com            for i,v in enumerate(self):
2767528Ssteve.reinhardt@amd.com                v.set_parent(parent, "%s%0*d" % (name, width, i))
2777528Ssteve.reinhardt@amd.com
2787528Ssteve.reinhardt@amd.com    def has_parent(self):
2797528Ssteve.reinhardt@amd.com        return any([e.has_parent() for e in self if not isNullPointer(e)])
2807528Ssteve.reinhardt@amd.com
2817528Ssteve.reinhardt@amd.com    # return 'cpu0 cpu1' etc. for print_ini()
2827528Ssteve.reinhardt@amd.com    def get_name(self):
2837528Ssteve.reinhardt@amd.com        return ' '.join([v._name for v in self])
2847528Ssteve.reinhardt@amd.com
2857528Ssteve.reinhardt@amd.com    # By iterating through the constituent members of the vector here
2867528Ssteve.reinhardt@amd.com    # we can nicely handle iterating over all a SimObject's children
2873101Sstever@eecs.umich.edu    # without having to provide lots of special functions on
2888664SAli.Saidi@ARM.com    # SimObjectVector directly.
2898664SAli.Saidi@ARM.com    def descendants(self):
2908664SAli.Saidi@ARM.com        for v in self:
2918664SAli.Saidi@ARM.com            for obj in v.descendants():
2928664SAli.Saidi@ARM.com                yield obj
2938664SAli.Saidi@ARM.com
2949953Sgeoffrey.blake@arm.com    def get_config_as_dict(self):
2959953Sgeoffrey.blake@arm.com        a = []
2969953Sgeoffrey.blake@arm.com        for v in self:
2979953Sgeoffrey.blake@arm.com            a.append(v.get_config_as_dict())
2989953Sgeoffrey.blake@arm.com        return a
2999953Sgeoffrey.blake@arm.com
3009953Sgeoffrey.blake@arm.com    # If we are replacing an item in the vector, make sure to set the
3019953Sgeoffrey.blake@arm.com    # parent reference of the new SimObject to be the same as the parent
3029953Sgeoffrey.blake@arm.com    # of the SimObject being replaced. Useful to have if we created
3039953Sgeoffrey.blake@arm.com    # a SimObjectVector of temporary objects that will be modified later in
3049953Sgeoffrey.blake@arm.com    # configuration scripts.
3059953Sgeoffrey.blake@arm.com    def __setitem__(self, key, value):
3069953Sgeoffrey.blake@arm.com        val = self[key]
30710267SGeoffrey.Blake@arm.com        if value.has_parent():
30810267SGeoffrey.Blake@arm.com            warn("SimObject %s already has a parent" % value.get_name() +\
30910267SGeoffrey.Blake@arm.com                 " that is being overwritten by a SimObjectVector")
31010267SGeoffrey.Blake@arm.com        value.set_parent(val.get_parent(), val._name)
31110267SGeoffrey.Blake@arm.com        super(SimObjectVector, self).__setitem__(key, value)
31210267SGeoffrey.Blake@arm.com
31310267SGeoffrey.Blake@arm.com    # Enumerate the params of each member of the SimObject vector. Creates
31410267SGeoffrey.Blake@arm.com    # strings that will allow indexing into the vector by the python code and
31510267SGeoffrey.Blake@arm.com    # allow it to be specified on the command line.
31610267SGeoffrey.Blake@arm.com    def enumerateParams(self, flags_dict = {},
31710267SGeoffrey.Blake@arm.com                        cmd_line_str = "",
31810267SGeoffrey.Blake@arm.com                        access_str = ""):
31910267SGeoffrey.Blake@arm.com        if hasattr(self, "_paramEnumed"):
32010267SGeoffrey.Blake@arm.com            print("Cycle detected enumerating params at %s?!" % (cmd_line_str))
32110267SGeoffrey.Blake@arm.com        else:
32210267SGeoffrey.Blake@arm.com            x = 0
32310267SGeoffrey.Blake@arm.com            for vals in self:
32410267SGeoffrey.Blake@arm.com                # Each entry in the SimObjectVector should be an
32510267SGeoffrey.Blake@arm.com                # instance of a SimObject
32610267SGeoffrey.Blake@arm.com                flags_dict = vals.enumerateParams(flags_dict,
3273101Sstever@eecs.umich.edu                                                  cmd_line_str + "%d." % x,
3283101Sstever@eecs.umich.edu                                                  access_str + "[%d]." % x)
3293101Sstever@eecs.umich.edu                x = x + 1
3303101Sstever@eecs.umich.edu
3313101Sstever@eecs.umich.edu        return flags_dict
3323101Sstever@eecs.umich.edu
3333101Sstever@eecs.umich.educlass VectorParamDesc(ParamDesc):
33410364SGeoffrey.Blake@arm.com    # Convert assigned value to appropriate type.  If the RHS is not a
33510364SGeoffrey.Blake@arm.com    # list or tuple, it generates a single-element list.
33610364SGeoffrey.Blake@arm.com    def convert(self, value):
33710364SGeoffrey.Blake@arm.com        if isinstance(value, (list, tuple)):
3383101Sstever@eecs.umich.edu            # list: coerce each element into new list
3394762Snate@binkert.org            tmp_list = [ ParamDesc.convert(self, v) for v in value ]
3404762Snate@binkert.org        elif isinstance(value, str):
3414762Snate@binkert.org            # If input is a csv string
3424762Snate@binkert.org            tmp_list = [ ParamDesc.convert(self, v) \
3437528Ssteve.reinhardt@amd.com                         for v in value.strip('[').strip(']').split(',') ]
3444762Snate@binkert.org        else:
3454762Snate@binkert.org            # singleton: coerce to a single-element list
3464762Snate@binkert.org            tmp_list = [ ParamDesc.convert(self, value) ]
34710267SGeoffrey.Blake@arm.com
34810267SGeoffrey.Blake@arm.com        if isSimObjectSequence(tmp_list):
34910267SGeoffrey.Blake@arm.com            return SimObjectVector(tmp_list)
35010267SGeoffrey.Blake@arm.com        else:
35110267SGeoffrey.Blake@arm.com            return VectorParamValue(tmp_list)
35210267SGeoffrey.Blake@arm.com
35310267SGeoffrey.Blake@arm.com    # Produce a human readable example string that describes
35410267SGeoffrey.Blake@arm.com    # how to set this vector parameter in the absence of a default
35510267SGeoffrey.Blake@arm.com    # value.
35610267SGeoffrey.Blake@arm.com    def example_str(self):
35710267SGeoffrey.Blake@arm.com        s = super(VectorParamDesc, self).example_str()
35810267SGeoffrey.Blake@arm.com        help_str = "[" + s + "," + s + ", ...]"
35910267SGeoffrey.Blake@arm.com        return help_str
36010267SGeoffrey.Blake@arm.com
36110267SGeoffrey.Blake@arm.com    # Produce a human readable representation of the value of this vector param.
36210267SGeoffrey.Blake@arm.com    def pretty_print(self, value):
36310267SGeoffrey.Blake@arm.com        if isinstance(value, (list, tuple)):
36410267SGeoffrey.Blake@arm.com            tmp_list = [ ParamDesc.pretty_print(self, v) for v in value ]
36510267SGeoffrey.Blake@arm.com        elif isinstance(value, str):
36610267SGeoffrey.Blake@arm.com            tmp_list = [ ParamDesc.pretty_print(self, v) for v in value.split(',') ]
36710267SGeoffrey.Blake@arm.com        else:
36810267SGeoffrey.Blake@arm.com            tmp_list = [ ParamDesc.pretty_print(self, value) ]
36910267SGeoffrey.Blake@arm.com
37010267SGeoffrey.Blake@arm.com        return tmp_list
37110267SGeoffrey.Blake@arm.com
37210267SGeoffrey.Blake@arm.com    # This is a helper function for the new config system
37310364SGeoffrey.Blake@arm.com    def __call__(self, value):
37410364SGeoffrey.Blake@arm.com        if isinstance(value, (list, tuple)):
37510267SGeoffrey.Blake@arm.com            # list: coerce each element into new list
37610267SGeoffrey.Blake@arm.com            tmp_list = [ ParamDesc.convert(self, v) for v in value ]
37710267SGeoffrey.Blake@arm.com        elif isinstance(value, str):
37810267SGeoffrey.Blake@arm.com            # If input is a csv string
37910267SGeoffrey.Blake@arm.com            tmp_list = [ ParamDesc.convert(self, v) \
38010267SGeoffrey.Blake@arm.com                         for v in value.strip('[').strip(']').split(',') ]
3817673Snate@binkert.org        else:
3827673Snate@binkert.org            # singleton: coerce to a single-element list
3837673Snate@binkert.org            tmp_list = [ ParamDesc.convert(self, value) ]
3843101Sstever@eecs.umich.edu
38511988Sandreas.sandberg@arm.com        return VectorParamValue(tmp_list)
38611988Sandreas.sandberg@arm.com
38711988Sandreas.sandberg@arm.com    def cxx_predecls(self, code):
38811988Sandreas.sandberg@arm.com        code('#include <vector>')
3897673Snate@binkert.org        self.ptype.cxx_predecls(code)
3907673Snate@binkert.org
3913101Sstever@eecs.umich.edu    def pybind_predecls(self, code):
3923101Sstever@eecs.umich.edu        code('#include <vector>')
3933101Sstever@eecs.umich.edu        self.ptype.pybind_predecls(code)
3943101Sstever@eecs.umich.edu
3953101Sstever@eecs.umich.edu    def cxx_decl(self, code):
3963101Sstever@eecs.umich.edu        code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};')
3973101Sstever@eecs.umich.edu
3983101Sstever@eecs.umich.educlass ParamFactory(object):
3993101Sstever@eecs.umich.edu    def __init__(self, param_desc_class, ptype_str = None):
4003101Sstever@eecs.umich.edu        self.param_desc_class = param_desc_class
4013101Sstever@eecs.umich.edu        self.ptype_str = ptype_str
4023101Sstever@eecs.umich.edu
4033101Sstever@eecs.umich.edu    def __getattr__(self, attr):
4043101Sstever@eecs.umich.edu        if self.ptype_str:
4053101Sstever@eecs.umich.edu            attr = self.ptype_str + '.' + attr
4065033Smilesck@eecs.umich.edu        return ParamFactory(self.param_desc_class, attr)
4075033Smilesck@eecs.umich.edu
4083101Sstever@eecs.umich.edu    # E.g., Param.Int(5, "number of widgets")
4093101Sstever@eecs.umich.edu    def __call__(self, *args, **kwargs):
4103101Sstever@eecs.umich.edu        ptype = None
4113101Sstever@eecs.umich.edu        try:
4123101Sstever@eecs.umich.edu            ptype = allParams[self.ptype_str]
4133101Sstever@eecs.umich.edu        except KeyError:
4143101Sstever@eecs.umich.edu            # if name isn't defined yet, assume it's a SimObject, and
4153101Sstever@eecs.umich.edu            # try to resolve it later
4163101Sstever@eecs.umich.edu            pass
4173101Sstever@eecs.umich.edu        return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs)
4183101Sstever@eecs.umich.edu
4193101Sstever@eecs.umich.eduParam = ParamFactory(ParamDesc)
4203101Sstever@eecs.umich.eduVectorParam = ParamFactory(VectorParamDesc)
4213101Sstever@eecs.umich.edu
4223101Sstever@eecs.umich.edu#####################################################################
4233101Sstever@eecs.umich.edu#
4243101Sstever@eecs.umich.edu# Parameter Types
4253101Sstever@eecs.umich.edu#
4263101Sstever@eecs.umich.edu# Though native Python types could be used to specify parameter types
4273101Sstever@eecs.umich.edu# (the 'ptype' field of the Param and VectorParam classes), it's more
4283101Sstever@eecs.umich.edu# flexible to define our own set of types.  This gives us more control
4293101Sstever@eecs.umich.edu# over how Python expressions are converted to values (via the
4303101Sstever@eecs.umich.edu# __init__() constructor) and how these values are printed out (via
4313101Sstever@eecs.umich.edu# the __str__() conversion method).
4323101Sstever@eecs.umich.edu#
43310267SGeoffrey.Blake@arm.com#####################################################################
4347673Snate@binkert.org
4357673Snate@binkert.org# String-valued parameter.  Just mixin the ParamValue class with the
4367673Snate@binkert.org# built-in str class.
4377673Snate@binkert.orgclass String(ParamValue,str):
4387673Snate@binkert.org    cxx_type = 'std::string'
43910267SGeoffrey.Blake@arm.com    cmd_line_settable = True
44010267SGeoffrey.Blake@arm.com
44110267SGeoffrey.Blake@arm.com    @classmethod
44210267SGeoffrey.Blake@arm.com    def cxx_predecls(self, code):
44310458Sandreas.hansson@arm.com        code('#include <string>')
44410458Sandreas.hansson@arm.com
44510458Sandreas.hansson@arm.com    def __call__(self, value):
44610458Sandreas.hansson@arm.com        self = value
44710458Sandreas.hansson@arm.com        return value
4484762Snate@binkert.org
4494762Snate@binkert.org    @classmethod
4503101Sstever@eecs.umich.edu    def cxx_ini_parse(self, code, src, dest, ret):
4513101Sstever@eecs.umich.edu        code('%s = %s;' % (dest, src))
4523101Sstever@eecs.umich.edu        code('%s true;' % ret)
4533101Sstever@eecs.umich.edu
4543101Sstever@eecs.umich.edu    def getValue(self):
4553101Sstever@eecs.umich.edu        return self
4563101Sstever@eecs.umich.edu
4573101Sstever@eecs.umich.edu# superclass for "numeric" parameter values, to emulate math
4583101Sstever@eecs.umich.edu# operations in a type-safe way.  e.g., a Latency times an int returns
4593101Sstever@eecs.umich.edu# a new Latency object.
4603101Sstever@eecs.umich.educlass NumericParamValue(ParamValue):
4613714Sstever@eecs.umich.edu    @staticmethod
4623714Sstever@eecs.umich.edu    def unwrap(v):
4633714Sstever@eecs.umich.edu        return v.value if isinstance(v, NumericParamValue) else v
4643714Sstever@eecs.umich.edu
4653714Sstever@eecs.umich.edu    def __str__(self):
4663714Sstever@eecs.umich.edu        return str(self.value)
4673101Sstever@eecs.umich.edu
4683101Sstever@eecs.umich.edu    def __float__(self):
4693101Sstever@eecs.umich.edu        return float(self.value)
4703101Sstever@eecs.umich.edu
4713101Sstever@eecs.umich.edu    def __long__(self):
4723101Sstever@eecs.umich.edu        return long(self.value)
4733101Sstever@eecs.umich.edu
4743101Sstever@eecs.umich.edu    def __int__(self):
4753101Sstever@eecs.umich.edu        return int(self.value)
4763101Sstever@eecs.umich.edu
4773101Sstever@eecs.umich.edu    # hook for bounds checking
4783101Sstever@eecs.umich.edu    def _check(self):
4793101Sstever@eecs.umich.edu        return
4803101Sstever@eecs.umich.edu
4813101Sstever@eecs.umich.edu    def __mul__(self, other):
4823101Sstever@eecs.umich.edu        newobj = self.__class__(self)
4833101Sstever@eecs.umich.edu        newobj.value *= NumericParamValue.unwrap(other)
4843101Sstever@eecs.umich.edu        newobj._check()
4853101Sstever@eecs.umich.edu        return newobj
4863101Sstever@eecs.umich.edu
4873101Sstever@eecs.umich.edu    __rmul__ = __mul__
4883101Sstever@eecs.umich.edu
4893101Sstever@eecs.umich.edu    def __truediv__(self, other):
4903101Sstever@eecs.umich.edu        newobj = self.__class__(self)
49110380SAndrew.Bardsley@arm.com        newobj.value /= NumericParamValue.unwrap(other)
49210380SAndrew.Bardsley@arm.com        newobj._check()
49310380SAndrew.Bardsley@arm.com        return newobj
49410458Sandreas.hansson@arm.com
49510458Sandreas.hansson@arm.com    def __floordiv__(self, other):
49610458Sandreas.hansson@arm.com        newobj = self.__class__(self)
49710458Sandreas.hansson@arm.com        newobj.value //= NumericParamValue.unwrap(other)
49810458Sandreas.hansson@arm.com        newobj._check()
49910458Sandreas.hansson@arm.com        return newobj
50010458Sandreas.hansson@arm.com
50110458Sandreas.hansson@arm.com
50210458Sandreas.hansson@arm.com    def __add__(self, other):
50310458Sandreas.hansson@arm.com        newobj = self.__class__(self)
50410458Sandreas.hansson@arm.com        newobj.value += NumericParamValue.unwrap(other)
50510458Sandreas.hansson@arm.com        newobj._check()
50610458Sandreas.hansson@arm.com        return newobj
5073101Sstever@eecs.umich.edu
5085033Smilesck@eecs.umich.edu    def __sub__(self, other):
5093101Sstever@eecs.umich.edu        newobj = self.__class__(self)
5103101Sstever@eecs.umich.edu        newobj.value -= NumericParamValue.unwrap(other)
5113101Sstever@eecs.umich.edu        newobj._check()
5123101Sstever@eecs.umich.edu        return newobj
5133101Sstever@eecs.umich.edu
5143101Sstever@eecs.umich.edu    def __iadd__(self, other):
5153101Sstever@eecs.umich.edu        self.value += NumericParamValue.unwrap(other)
5163101Sstever@eecs.umich.edu        self._check()
5173101Sstever@eecs.umich.edu        return self
5183101Sstever@eecs.umich.edu
5193101Sstever@eecs.umich.edu    def __isub__(self, other):
5203101Sstever@eecs.umich.edu        self.value -= NumericParamValue.unwrap(other)
5215822Ssaidi@eecs.umich.edu        self._check()
5225822Ssaidi@eecs.umich.edu        return self
5233101Sstever@eecs.umich.edu
5243101Sstever@eecs.umich.edu    def __imul__(self, other):
5253101Sstever@eecs.umich.edu        self.value *= NumericParamValue.unwrap(other)
5263101Sstever@eecs.umich.edu        self._check()
5273101Sstever@eecs.umich.edu        return self
5283101Sstever@eecs.umich.edu
5293101Sstever@eecs.umich.edu    def __itruediv__(self, other):
5303101Sstever@eecs.umich.edu        self.value /= NumericParamValue.unwrap(other)
5313101Sstever@eecs.umich.edu        self._check()
5323101Sstever@eecs.umich.edu        return self
5333101Sstever@eecs.umich.edu
5343101Sstever@eecs.umich.edu    def __ifloordiv__(self, other):
5353101Sstever@eecs.umich.edu        self.value //= NumericParamValue.unwrap(other)
53610267SGeoffrey.Blake@arm.com        self._check()
5373101Sstever@eecs.umich.edu        return self
5383101Sstever@eecs.umich.edu
5393101Sstever@eecs.umich.edu    def __lt__(self, other):
5403101Sstever@eecs.umich.edu        return self.value < NumericParamValue.unwrap(other)
5413101Sstever@eecs.umich.edu
5423101Sstever@eecs.umich.edu    # Python 2.7 pre __future__.division operators
5433101Sstever@eecs.umich.edu    # TODO: Remove these when after "import division from __future__"
5443101Sstever@eecs.umich.edu    __div__ =  __truediv__
5453102Sstever@eecs.umich.edu    __idiv__ = __itruediv__
5463714Sstever@eecs.umich.edu
5473101Sstever@eecs.umich.edu    def config_value(self):
5483714Sstever@eecs.umich.edu        return self.value
5493714Sstever@eecs.umich.edu
5503714Sstever@eecs.umich.edu    @classmethod
5513101Sstever@eecs.umich.edu    def cxx_ini_predecls(cls, code):
5523101Sstever@eecs.umich.edu        # Assume that base/str.hh will be included anyway
55310267SGeoffrey.Blake@arm.com        # code('#include "base/str.hh"')
55410267SGeoffrey.Blake@arm.com        pass
55510267SGeoffrey.Blake@arm.com
55610267SGeoffrey.Blake@arm.com    # The default for parsing PODs from an .ini entry is to extract from an
5577673Snate@binkert.org    # istringstream and let overloading choose the right type according to
5587673Snate@binkert.org    # the dest type.
5597673Snate@binkert.org    @classmethod
5607673Snate@binkert.org    def cxx_ini_parse(self, code, src, dest, ret):
5617673Snate@binkert.org        code('%s to_number(%s, %s);' % (ret, src, dest))
5624762Snate@binkert.org
5634762Snate@binkert.org# Metaclass for bounds-checked integer parameters.  See CheckedInt.
5644762Snate@binkert.orgclass CheckedIntType(MetaParamValue):
5653101Sstever@eecs.umich.edu    def __init__(cls, name, bases, dict):
5663101Sstever@eecs.umich.edu        super(CheckedIntType, cls).__init__(name, bases, dict)
5673101Sstever@eecs.umich.edu
5683101Sstever@eecs.umich.edu        # CheckedInt is an abstract base class, so we actually don't
5693101Sstever@eecs.umich.edu        # want to do any processing on it... the rest of this code is
5703101Sstever@eecs.umich.edu        # just for classes that derive from CheckedInt.
5713101Sstever@eecs.umich.edu        if name == 'CheckedInt':
5723101Sstever@eecs.umich.edu            return
5733101Sstever@eecs.umich.edu
5743101Sstever@eecs.umich.edu        if not (hasattr(cls, 'min') and hasattr(cls, 'max')):
5753101Sstever@eecs.umich.edu            if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')):
5763101Sstever@eecs.umich.edu                panic("CheckedInt subclass %s must define either\n" \
5773101Sstever@eecs.umich.edu                      "    'min' and 'max' or 'size' and 'unsigned'\n",
5783101Sstever@eecs.umich.edu                      name);
5793101Sstever@eecs.umich.edu            if cls.unsigned:
5803101Sstever@eecs.umich.edu                cls.min = 0
5813101Sstever@eecs.umich.edu                cls.max = 2 ** cls.size - 1
5823101Sstever@eecs.umich.edu            else:
5833101Sstever@eecs.umich.edu                cls.min = -(2 ** (cls.size - 1))
5849184Sandreas.hansson@arm.com                cls.max = (2 ** (cls.size - 1)) - 1
5859184Sandreas.hansson@arm.com
5869184Sandreas.hansson@arm.com# Abstract superclass for bounds-checked integer parameters.  This
5879184Sandreas.hansson@arm.com# class is subclassed to generate parameter classes with specific
5889184Sandreas.hansson@arm.com# bounds.  Initialization of the min and max bounds is done in the
5899184Sandreas.hansson@arm.com# metaclass CheckedIntType.__init__.
59011802Sandreas.sandberg@arm.comclass CheckedInt(NumericParamValue):
5919184Sandreas.hansson@arm.com    __metaclass__ = CheckedIntType
5929184Sandreas.hansson@arm.com    cmd_line_settable = True
59310458Sandreas.hansson@arm.com
59410458Sandreas.hansson@arm.com    def _check(self):
59510458Sandreas.hansson@arm.com        if not self.min <= self.value <= self.max:
59610458Sandreas.hansson@arm.com            raise TypeError('Integer param out of bounds %d < %d < %d' % \
59710458Sandreas.hansson@arm.com                  (self.min, self.value, self.max))
59810458Sandreas.hansson@arm.com
59910458Sandreas.hansson@arm.com    def __init__(self, value):
60010458Sandreas.hansson@arm.com        if isinstance(value, str):
60110458Sandreas.hansson@arm.com            self.value = convert.toInteger(value)
60210458Sandreas.hansson@arm.com        elif isinstance(value, (int, long, float, NumericParamValue)):
60310458Sandreas.hansson@arm.com            self.value = long(value)
60410458Sandreas.hansson@arm.com        else:
60510458Sandreas.hansson@arm.com            raise TypeError("Can't convert object of type %s to CheckedInt" \
60610458Sandreas.hansson@arm.com                  % type(value).__name__)
6073101Sstever@eecs.umich.edu        self._check()
6084446Sbinkertn@umich.edu
60910668SGeoffrey.Blake@arm.com    def __call__(self, value):
6103101Sstever@eecs.umich.edu        self.__init__(value)
6115468Snate@binkert.org        return value
61210267SGeoffrey.Blake@arm.com
6135468Snate@binkert.org    def __index__(self):
6145468Snate@binkert.org        return int(self.value)
6155468Snate@binkert.org
6165468Snate@binkert.org    @classmethod
6175468Snate@binkert.org    def cxx_predecls(cls, code):
61810267SGeoffrey.Blake@arm.com        # most derived types require this, so we just do it here once
61910267SGeoffrey.Blake@arm.com        code('#include "base/types.hh"')
62010267SGeoffrey.Blake@arm.com
62110267SGeoffrey.Blake@arm.com    def getValue(self):
6224762Snate@binkert.org        return long(self.value)
6234762Snate@binkert.org
6244762Snate@binkert.orgclass Int(CheckedInt):      cxx_type = 'int';      size = 32; unsigned = False
62510380SAndrew.Bardsley@arm.comclass Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True
62610380SAndrew.Bardsley@arm.com
62710380SAndrew.Bardsley@arm.comclass Int8(CheckedInt):     cxx_type =   'int8_t'; size =  8; unsigned = False
62810458Sandreas.hansson@arm.comclass UInt8(CheckedInt):    cxx_type =  'uint8_t'; size =  8; unsigned = True
62910458Sandreas.hansson@arm.comclass Int16(CheckedInt):    cxx_type =  'int16_t'; size = 16; unsigned = False
63010458Sandreas.hansson@arm.comclass UInt16(CheckedInt):   cxx_type = 'uint16_t'; size = 16; unsigned = True
63110458Sandreas.hansson@arm.comclass Int32(CheckedInt):    cxx_type =  'int32_t'; size = 32; unsigned = False
63210458Sandreas.hansson@arm.comclass UInt32(CheckedInt):   cxx_type = 'uint32_t'; size = 32; unsigned = True
63310458Sandreas.hansson@arm.comclass Int64(CheckedInt):    cxx_type =  'int64_t'; size = 64; unsigned = False
63410458Sandreas.hansson@arm.comclass UInt64(CheckedInt):   cxx_type = 'uint64_t'; size = 64; unsigned = True
63510458Sandreas.hansson@arm.com
6363101Sstever@eecs.umich.educlass Counter(CheckedInt):  cxx_type = 'Counter';  size = 64; unsigned = True
6373101Sstever@eecs.umich.educlass Tick(CheckedInt):     cxx_type = 'Tick';     size = 64; unsigned = True
63810267SGeoffrey.Blake@arm.comclass TcpPort(CheckedInt):  cxx_type = 'uint16_t'; size = 16; unsigned = True
6393101Sstever@eecs.umich.educlass UdpPort(CheckedInt):  cxx_type = 'uint16_t'; size = 16; unsigned = True
6403101Sstever@eecs.umich.edu
6413101Sstever@eecs.umich.educlass Percent(CheckedInt):  cxx_type = 'int'; min = 0; max = 100
6423101Sstever@eecs.umich.edu
6433101Sstever@eecs.umich.educlass Cycles(CheckedInt):
6443101Sstever@eecs.umich.edu    cxx_type = 'Cycles'
6453102Sstever@eecs.umich.edu    size = 64
6463101Sstever@eecs.umich.edu    unsigned = True
6473101Sstever@eecs.umich.edu
6483101Sstever@eecs.umich.edu    def getValue(self):
6494168Sbinkertn@umich.edu        from _m5.core import Cycles
65010267SGeoffrey.Blake@arm.com        return Cycles(self.value)
6513101Sstever@eecs.umich.edu
6523101Sstever@eecs.umich.edu    @classmethod
6533101Sstever@eecs.umich.edu    def cxx_ini_predecls(cls, code):
6543101Sstever@eecs.umich.edu        # Assume that base/str.hh will be included anyway
6553101Sstever@eecs.umich.edu        # code('#include "base/str.hh"')
6563101Sstever@eecs.umich.edu        pass
6573102Sstever@eecs.umich.edu
6583101Sstever@eecs.umich.edu    @classmethod
6593101Sstever@eecs.umich.edu    def cxx_ini_parse(cls, code, src, dest, ret):
6603101Sstever@eecs.umich.edu        code('uint64_t _temp;')
6613101Sstever@eecs.umich.edu        code('bool _ret = to_number(%s, _temp);' % src)
6623101Sstever@eecs.umich.edu        code('if (_ret)')
6633101Sstever@eecs.umich.edu        code('    %s = Cycles(_temp);' % dest)
6643101Sstever@eecs.umich.edu        code('%s _ret;' % ret)
6653101Sstever@eecs.umich.edu
6663101Sstever@eecs.umich.educlass Float(ParamValue, float):
6673101Sstever@eecs.umich.edu    cxx_type = 'double'
6683101Sstever@eecs.umich.edu    cmd_line_settable = True
66910317Smitch.hayenga@arm.com
67010317Smitch.hayenga@arm.com    def __init__(self, value):
67110317Smitch.hayenga@arm.com        if isinstance(value, (int, long, float, NumericParamValue, Float, str)):
67210317Smitch.hayenga@arm.com            self.value = float(value)
67310317Smitch.hayenga@arm.com        else:
6743102Sstever@eecs.umich.edu            raise TypeError("Can't convert object of type %s to Float" \
67510317Smitch.hayenga@arm.com                  % type(value).__name__)
67610317Smitch.hayenga@arm.com
67710317Smitch.hayenga@arm.com    def __call__(self, value):
67810317Smitch.hayenga@arm.com        self.__init__(value)
67910317Smitch.hayenga@arm.com        return value
6803101Sstever@eecs.umich.edu
6813584Ssaidi@eecs.umich.edu    def getValue(self):
6823584Ssaidi@eecs.umich.edu        return float(self.value)
6833584Ssaidi@eecs.umich.edu
6843584Ssaidi@eecs.umich.edu    def config_value(self):
6853584Ssaidi@eecs.umich.edu        return self
68610267SGeoffrey.Blake@arm.com
68710267SGeoffrey.Blake@arm.com    @classmethod
68810267SGeoffrey.Blake@arm.com    def cxx_ini_predecls(cls, code):
68910267SGeoffrey.Blake@arm.com        code('#include <sstream>')
69010267SGeoffrey.Blake@arm.com
69110267SGeoffrey.Blake@arm.com    @classmethod
6923101Sstever@eecs.umich.edu    def cxx_ini_parse(self, code, src, dest, ret):
6939232Sandreas.hansson@arm.com        code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
6949235Sandreas.hansson@arm.com
6953101Sstever@eecs.umich.educlass MemorySize(CheckedInt):
6963101Sstever@eecs.umich.edu    cxx_type = 'uint64_t'
69710676Sandreas.hansson@arm.com    ex_str = '512MB'
6989411Sandreas.hansson@arm.com    size = 64
69910676Sandreas.hansson@arm.com    unsigned = True
7009411Sandreas.hansson@arm.com    def __init__(self, value):
7019411Sandreas.hansson@arm.com        if isinstance(value, MemorySize):
7029411Sandreas.hansson@arm.com            self.value = value.value
7033101Sstever@eecs.umich.edu        else:
7049411Sandreas.hansson@arm.com            self.value = convert.toMemorySize(value)
7059411Sandreas.hansson@arm.com        self._check()
7069411Sandreas.hansson@arm.com
7073101Sstever@eecs.umich.educlass MemorySize32(CheckedInt):
7089232Sandreas.hansson@arm.com    cxx_type = 'uint32_t'
7093101Sstever@eecs.umich.edu    ex_str = '512MB'
7109232Sandreas.hansson@arm.com    size = 32
7113101Sstever@eecs.umich.edu    unsigned = True
7123101Sstever@eecs.umich.edu    def __init__(self, value):
7133101Sstever@eecs.umich.edu        if isinstance(value, MemorySize):
7149411Sandreas.hansson@arm.com            self.value = value.value
7159411Sandreas.hansson@arm.com        else:
7169411Sandreas.hansson@arm.com            self.value = convert.toMemorySize(value)
71710676Sandreas.hansson@arm.com        self._check()
71810676Sandreas.hansson@arm.com
7199411Sandreas.hansson@arm.comclass Addr(CheckedInt):
7209411Sandreas.hansson@arm.com    cxx_type = 'Addr'
7219411Sandreas.hansson@arm.com    size = 64
7229411Sandreas.hansson@arm.com    unsigned = True
7239411Sandreas.hansson@arm.com    def __init__(self, value):
7243101Sstever@eecs.umich.edu        if isinstance(value, Addr):
7259232Sandreas.hansson@arm.com            self.value = value.value
7263101Sstever@eecs.umich.edu        else:
7273101Sstever@eecs.umich.edu            try:
7283101Sstever@eecs.umich.edu                # Often addresses are referred to with sizes. Ex: A device
7293101Sstever@eecs.umich.edu                # base address is at "512MB".  Use toMemorySize() to convert
7309232Sandreas.hansson@arm.com                # these into addresses. If the address is not specified with a
7313101Sstever@eecs.umich.edu                # "size", an exception will occur and numeric translation will
7325219Ssaidi@eecs.umich.edu                # proceed below.
7339232Sandreas.hansson@arm.com                self.value = convert.toMemorySize(value)
7349232Sandreas.hansson@arm.com            except (TypeError, ValueError):
7353101Sstever@eecs.umich.edu                # Convert number to string and use long() to do automatic
7369232Sandreas.hansson@arm.com                # base conversion (requires base=0 for auto-conversion)
7379232Sandreas.hansson@arm.com                self.value = long(str(value), base=0)
7383101Sstever@eecs.umich.edu
7393101Sstever@eecs.umich.edu        self._check()
7409232Sandreas.hansson@arm.com    def __add__(self, other):
7419232Sandreas.hansson@arm.com        if isinstance(other, Addr):
7423101Sstever@eecs.umich.edu            return self.value + other.value
7433101Sstever@eecs.umich.edu        else:
7443101Sstever@eecs.umich.edu            return self.value + other
7453101Sstever@eecs.umich.edu    def pretty_print(self, value):
7469232Sandreas.hansson@arm.com        try:
7473101Sstever@eecs.umich.edu            val = convert.toMemorySize(value)
7483101Sstever@eecs.umich.edu        except TypeError:
74911620SMatthew.Poremba@amd.com            val = long(value)
75011620SMatthew.Poremba@amd.com        return "0x%x" % long(val)
75111620SMatthew.Poremba@amd.com
7529232Sandreas.hansson@arm.comclass AddrRange(ParamValue):
7539232Sandreas.hansson@arm.com    cxx_type = 'AddrRange'
7549411Sandreas.hansson@arm.com
7559411Sandreas.hansson@arm.com    def __init__(self, *args, **kwargs):
7563101Sstever@eecs.umich.edu        # Disable interleaving and hashing by default
7577673Snate@binkert.org        self.intlvHighBit = 0
7587673Snate@binkert.org        self.xorHighBit = 0
7599232Sandreas.hansson@arm.com        self.intlvBits = 0
7609235Sandreas.hansson@arm.com        self.intlvMatch = 0
7617675Snate@binkert.org
7627675Snate@binkert.org        def handle_kwargs(self, kwargs):
76311988Sandreas.sandberg@arm.com            # An address range needs to have an upper limit, specified
76411988Sandreas.sandberg@arm.com            # either explicitly with an end, or as an offset using the
76511988Sandreas.sandberg@arm.com            # size keyword.
76611988Sandreas.sandberg@arm.com            if 'end' in kwargs:
76711988Sandreas.sandberg@arm.com                self.end = Addr(kwargs.pop('end'))
76810458Sandreas.hansson@arm.com            elif 'size' in kwargs:
76910458Sandreas.hansson@arm.com                self.end = self.start + Addr(kwargs.pop('size')) - 1
77010458Sandreas.hansson@arm.com            else:
77110458Sandreas.hansson@arm.com                raise TypeError("Either end or size must be specified")
77210458Sandreas.hansson@arm.com
77311620SMatthew.Poremba@amd.com            # Now on to the optional bit
77411620SMatthew.Poremba@amd.com            if 'intlvHighBit' in kwargs:
77510458Sandreas.hansson@arm.com                self.intlvHighBit = int(kwargs.pop('intlvHighBit'))
77610458Sandreas.hansson@arm.com            if 'xorHighBit' in kwargs:
77710458Sandreas.hansson@arm.com                self.xorHighBit = int(kwargs.pop('xorHighBit'))
77810458Sandreas.hansson@arm.com            if 'intlvBits' in kwargs:
77910458Sandreas.hansson@arm.com                self.intlvBits = int(kwargs.pop('intlvBits'))
78011620SMatthew.Poremba@amd.com            if 'intlvMatch' in kwargs:
78111620SMatthew.Poremba@amd.com                self.intlvMatch = int(kwargs.pop('intlvMatch'))
78211620SMatthew.Poremba@amd.com
78311620SMatthew.Poremba@amd.com        if len(args) == 0:
78411620SMatthew.Poremba@amd.com            self.start = Addr(kwargs.pop('start'))
78511620SMatthew.Poremba@amd.com            handle_kwargs(self, kwargs)
78611620SMatthew.Poremba@amd.com
78711620SMatthew.Poremba@amd.com        elif len(args) == 1:
78811620SMatthew.Poremba@amd.com            if kwargs:
78911620SMatthew.Poremba@amd.com                self.start = Addr(args[0])
79010458Sandreas.hansson@arm.com                handle_kwargs(self, kwargs)
79110458Sandreas.hansson@arm.com            elif isinstance(args[0], (list, tuple)):
79210458Sandreas.hansson@arm.com                self.start = Addr(args[0][0])
79311620SMatthew.Poremba@amd.com                self.end = Addr(args[0][1])
79411620SMatthew.Poremba@amd.com            else:
79510458Sandreas.hansson@arm.com                self.start = Addr(0)
79610458Sandreas.hansson@arm.com                self.end = Addr(args[0]) - 1
7974762Snate@binkert.org
79811991Sandreas.sandberg@arm.com        elif len(args) == 2:
79911802Sandreas.sandberg@arm.com            self.start = Addr(args[0])
8004762Snate@binkert.org            self.end = Addr(args[1])
8019411Sandreas.hansson@arm.com        else:
80210676Sandreas.hansson@arm.com            raise TypeError("Too many arguments specified")
80310676Sandreas.hansson@arm.com
8043101Sstever@eecs.umich.edu        if kwargs:
8053101Sstever@eecs.umich.edu            raise TypeError("Too many keywords: %s" % list(kwargs.keys()))
8063101Sstever@eecs.umich.edu
8073101Sstever@eecs.umich.edu    def __str__(self):
8083101Sstever@eecs.umich.edu        return '%s:%s:%s:%s:%s:%s' \
8093101Sstever@eecs.umich.edu            % (self.start, self.end, self.intlvHighBit, self.xorHighBit,\
81010267SGeoffrey.Blake@arm.com               self.intlvBits, self.intlvMatch)
81110267SGeoffrey.Blake@arm.com
8123101Sstever@eecs.umich.edu    def size(self):
8133101Sstever@eecs.umich.edu        # Divide the size by the size of the interleaving slice
8143102Sstever@eecs.umich.edu        return (long(self.end) - long(self.start) + 1) >> self.intlvBits
8153101Sstever@eecs.umich.edu
8163101Sstever@eecs.umich.edu    @classmethod
8173101Sstever@eecs.umich.edu    def cxx_predecls(cls, code):
81810267SGeoffrey.Blake@arm.com        Addr.cxx_predecls(code)
81910267SGeoffrey.Blake@arm.com        code('#include "base/addr_range.hh"')
82010267SGeoffrey.Blake@arm.com
82110267SGeoffrey.Blake@arm.com    @classmethod
8224762Snate@binkert.org    def pybind_predecls(cls, code):
8234762Snate@binkert.org        Addr.pybind_predecls(code)
8244762Snate@binkert.org        code('#include "base/addr_range.hh"')
8253101Sstever@eecs.umich.edu
8263101Sstever@eecs.umich.edu    @classmethod
8273101Sstever@eecs.umich.edu    def cxx_ini_predecls(cls, code):
8288934SBrad.Beckmann@amd.com        code('#include <sstream>')
8298934SBrad.Beckmann@amd.com
8308934SBrad.Beckmann@amd.com    @classmethod
8318934SBrad.Beckmann@amd.com    def cxx_ini_parse(cls, code, src, dest, ret):
8328934SBrad.Beckmann@amd.com        code('uint64_t _start, _end, _intlvHighBit = 0, _xorHighBit = 0;')
8333101Sstever@eecs.umich.edu        code('uint64_t _intlvBits = 0, _intlvMatch = 0;')
8343101Sstever@eecs.umich.edu        code('char _sep;')
8353101Sstever@eecs.umich.edu        code('std::istringstream _stream(${src});')
8363101Sstever@eecs.umich.edu        code('_stream >> _start;')
8373101Sstever@eecs.umich.edu        code('_stream.get(_sep);')
83810380SAndrew.Bardsley@arm.com        code('_stream >> _end;')
83910380SAndrew.Bardsley@arm.com        code('if (!_stream.fail() && !_stream.eof()) {')
84010380SAndrew.Bardsley@arm.com        code('    _stream.get(_sep);')
84110458Sandreas.hansson@arm.com        code('    _stream >> _intlvHighBit;')
84210458Sandreas.hansson@arm.com        code('    _stream.get(_sep);')
84310458Sandreas.hansson@arm.com        code('    _stream >> _xorHighBit;')
84410458Sandreas.hansson@arm.com        code('    _stream.get(_sep);')
84510458Sandreas.hansson@arm.com        code('    _stream >> _intlvBits;')
84610458Sandreas.hansson@arm.com        code('    _stream.get(_sep);')
84710458Sandreas.hansson@arm.com        code('    _stream >> _intlvMatch;')
84810458Sandreas.hansson@arm.com        code('}')
84910458Sandreas.hansson@arm.com        code('bool _ret = !_stream.fail() &&'
85010458Sandreas.hansson@arm.com            '_stream.eof() && _sep == \':\';')
8513101Sstever@eecs.umich.edu        code('if (_ret)')
8523101Sstever@eecs.umich.edu        code('   ${dest} = AddrRange(_start, _end, _intlvHighBit, \
8533101Sstever@eecs.umich.edu                _xorHighBit, _intlvBits, _intlvMatch);')
8543101Sstever@eecs.umich.edu        code('${ret} _ret;')
8553101Sstever@eecs.umich.edu
8563101Sstever@eecs.umich.edu    def getValue(self):
8573101Sstever@eecs.umich.edu        # Go from the Python class to the wrapped C++ class
8583101Sstever@eecs.umich.edu        from _m5.range import AddrRange
8593101Sstever@eecs.umich.edu
8603101Sstever@eecs.umich.edu        return AddrRange(long(self.start), long(self.end),
8613101Sstever@eecs.umich.edu                         int(self.intlvHighBit), int(self.xorHighBit),
8623101Sstever@eecs.umich.edu                         int(self.intlvBits), int(self.intlvMatch))
8634380Sbinkertn@umich.edu
8644380Sbinkertn@umich.edu# Boolean parameter type.  Python doesn't let you subclass bool, since
8654380Sbinkertn@umich.edu# it doesn't want to let you create multiple instances of True and
8663101Sstever@eecs.umich.edu# False.  Thus this is a little more complicated than String.
8674380Sbinkertn@umich.educlass Bool(ParamValue):
8684380Sbinkertn@umich.edu    cxx_type = 'bool'
8694380Sbinkertn@umich.edu    cmd_line_settable = True
8703101Sstever@eecs.umich.edu
8713101Sstever@eecs.umich.edu    def __init__(self, value):
8723101Sstever@eecs.umich.edu        try:
87310267SGeoffrey.Blake@arm.com            self.value = convert.toBool(value)
87410267SGeoffrey.Blake@arm.com        except TypeError:
8757673Snate@binkert.org            self.value = bool(value)
8767673Snate@binkert.org
8777673Snate@binkert.org    def __call__(self, value):
8787673Snate@binkert.org        self.__init__(value)
8797673Snate@binkert.org        return value
8803101Sstever@eecs.umich.edu
8813101Sstever@eecs.umich.edu    def getValue(self):
8823101Sstever@eecs.umich.edu        return bool(self.value)
8833101Sstever@eecs.umich.edu
8843101Sstever@eecs.umich.edu    def __str__(self):
8853101Sstever@eecs.umich.edu        return str(self.value)
8863101Sstever@eecs.umich.edu
8873101Sstever@eecs.umich.edu    # implement truth value testing for Bool parameters so that these params
8883101Sstever@eecs.umich.edu    # evaluate correctly during the python configuration phase
8893101Sstever@eecs.umich.edu    def __bool__(self):
8903101Sstever@eecs.umich.edu        return bool(self.value)
8913101Sstever@eecs.umich.edu
8923101Sstever@eecs.umich.edu    # Python 2.7 uses __nonzero__ instead of __bool__
8939941SGeoffrey.Blake@arm.com    __nonzero__ = __bool__
8943101Sstever@eecs.umich.edu
8953101Sstever@eecs.umich.edu    def ini_str(self):
8963101Sstever@eecs.umich.edu        if self.value:
8973101Sstever@eecs.umich.edu            return 'true'
89810267SGeoffrey.Blake@arm.com        return 'false'
89910267SGeoffrey.Blake@arm.com
90010267SGeoffrey.Blake@arm.com    def config_value(self):
90110267SGeoffrey.Blake@arm.com        return self.value
9023101Sstever@eecs.umich.edu
9033101Sstever@eecs.umich.edu    @classmethod
9044380Sbinkertn@umich.edu    def cxx_ini_predecls(cls, code):
9053101Sstever@eecs.umich.edu        # Assume that base/str.hh will be included anyway
9063101Sstever@eecs.umich.edu        # code('#include "base/str.hh"')
9074762Snate@binkert.org        pass
90811988Sandreas.sandberg@arm.com
9094762Snate@binkert.org    @classmethod
9104762Snate@binkert.org    def cxx_ini_parse(cls, code, src, dest, ret):
91111228SAndrew.Bardsley@arm.com        code('%s to_bool(%s, %s);' % (ret, src, dest))
91211228SAndrew.Bardsley@arm.com
91311228SAndrew.Bardsley@arm.comdef IncEthernetAddr(addr, val = 1):
9144380Sbinkertn@umich.edu    bytes = [ int(x, 16) for x in addr.split(':') ]
9154380Sbinkertn@umich.edu    bytes[5] += val
9163101Sstever@eecs.umich.edu    for i in (5, 4, 3, 2, 1):
91710458Sandreas.hansson@arm.com        val,rem = divmod(bytes[i], 256)
91810458Sandreas.hansson@arm.com        bytes[i] = rem
91910458Sandreas.hansson@arm.com        if val == 0:
92010458Sandreas.hansson@arm.com            break
92110458Sandreas.hansson@arm.com        bytes[i - 1] += val
9227777Sgblack@eecs.umich.edu    assert(bytes[0] <= 255)
9237777Sgblack@eecs.umich.edu    return ':'.join(map(lambda x: '%02x' % x, bytes))
9247777Sgblack@eecs.umich.edu
9257777Sgblack@eecs.umich.edu_NextEthernetAddr = "00:90:00:00:00:01"
92610267SGeoffrey.Blake@arm.comdef NextEthernetAddr():
92710267SGeoffrey.Blake@arm.com    global _NextEthernetAddr
9287777Sgblack@eecs.umich.edu
9297777Sgblack@eecs.umich.edu    value = _NextEthernetAddr
9307777Sgblack@eecs.umich.edu    _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1)
9317777Sgblack@eecs.umich.edu    return value
9327777Sgblack@eecs.umich.edu
9337777Sgblack@eecs.umich.educlass EthernetAddr(ParamValue):
9347777Sgblack@eecs.umich.edu    cxx_type = 'Net::EthAddr'
9357777Sgblack@eecs.umich.edu    ex_str = "00:90:00:00:00:01"
9367777Sgblack@eecs.umich.edu    cmd_line_settable = True
9377777Sgblack@eecs.umich.edu
9387777Sgblack@eecs.umich.edu    @classmethod
9397777Sgblack@eecs.umich.edu    def cxx_predecls(cls, code):
9407777Sgblack@eecs.umich.edu        code('#include "base/inet.hh"')
9417777Sgblack@eecs.umich.edu
9427777Sgblack@eecs.umich.edu    def __init__(self, value):
94310267SGeoffrey.Blake@arm.com        if value == NextEthernetAddr:
94410267SGeoffrey.Blake@arm.com            self.value = value
94510267SGeoffrey.Blake@arm.com            return
94610267SGeoffrey.Blake@arm.com
9478579Ssteve.reinhardt@amd.com        if not isinstance(value, str):
9488579Ssteve.reinhardt@amd.com            raise TypeError("expected an ethernet address and didn't get one")
9498579Ssteve.reinhardt@amd.com
9508579Ssteve.reinhardt@amd.com        bytes = value.split(':')
9518579Ssteve.reinhardt@amd.com        if len(bytes) != 6:
9528579Ssteve.reinhardt@amd.com            raise TypeError('invalid ethernet address %s' % value)
9538579Ssteve.reinhardt@amd.com
9548579Ssteve.reinhardt@amd.com        for byte in bytes:
9558579Ssteve.reinhardt@amd.com            if not 0 <= int(byte, base=16) <= 0xff:
9568579Ssteve.reinhardt@amd.com                raise TypeError('invalid ethernet address %s' % value)
9578579Ssteve.reinhardt@amd.com
9588579Ssteve.reinhardt@amd.com        self.value = value
9598579Ssteve.reinhardt@amd.com
9608579Ssteve.reinhardt@amd.com    def __call__(self, value):
9618579Ssteve.reinhardt@amd.com        self.__init__(value)
9628579Ssteve.reinhardt@amd.com        return value
9638579Ssteve.reinhardt@amd.com
9648579Ssteve.reinhardt@amd.com    def unproxy(self, base):
9657777Sgblack@eecs.umich.edu        if self.value == NextEthernetAddr:
9667777Sgblack@eecs.umich.edu            return EthernetAddr(self.value())
9677798Sgblack@eecs.umich.edu        return self
9687777Sgblack@eecs.umich.edu
9697777Sgblack@eecs.umich.edu    def getValue(self):
97011988Sandreas.sandberg@arm.com        from _m5.net import EthAddr
9717777Sgblack@eecs.umich.edu        return EthAddr(self.value)
9727777Sgblack@eecs.umich.edu
9737777Sgblack@eecs.umich.edu    def __str__(self):
9747777Sgblack@eecs.umich.edu        return self.value
9757777Sgblack@eecs.umich.edu
9767777Sgblack@eecs.umich.edu    def ini_str(self):
9777777Sgblack@eecs.umich.edu        return self.value
97810267SGeoffrey.Blake@arm.com
97910267SGeoffrey.Blake@arm.com    @classmethod
9807777Sgblack@eecs.umich.edu    def cxx_ini_parse(self, code, src, dest, ret):
9817777Sgblack@eecs.umich.edu        code('%s = Net::EthAddr(%s);' % (dest, src))
9827777Sgblack@eecs.umich.edu        code('%s true;' % ret)
9837777Sgblack@eecs.umich.edu
9847777Sgblack@eecs.umich.edu# When initializing an IpAddress, pass in an existing IpAddress, a string of
9857777Sgblack@eecs.umich.edu# the form "a.b.c.d", or an integer representing an IP.
9867777Sgblack@eecs.umich.educlass IpAddress(ParamValue):
9877777Sgblack@eecs.umich.edu    cxx_type = 'Net::IpAddress'
9887777Sgblack@eecs.umich.edu    ex_str = "127.0.0.1"
9897777Sgblack@eecs.umich.edu    cmd_line_settable = True
9907777Sgblack@eecs.umich.edu
9917777Sgblack@eecs.umich.edu    @classmethod
9927777Sgblack@eecs.umich.edu    def cxx_predecls(cls, code):
9937777Sgblack@eecs.umich.edu        code('#include "base/inet.hh"')
9947777Sgblack@eecs.umich.edu
9957777Sgblack@eecs.umich.edu    def __init__(self, value):
9967777Sgblack@eecs.umich.edu        if isinstance(value, IpAddress):
9977777Sgblack@eecs.umich.edu            self.ip = value.ip
9987777Sgblack@eecs.umich.edu        else:
9997777Sgblack@eecs.umich.edu            try:
10007777Sgblack@eecs.umich.edu                self.ip = convert.toIpAddress(value)
10017777Sgblack@eecs.umich.edu            except TypeError:
10027777Sgblack@eecs.umich.edu                self.ip = long(value)
10037777Sgblack@eecs.umich.edu        self.verifyIp()
10047777Sgblack@eecs.umich.edu
10057777Sgblack@eecs.umich.edu    def __call__(self, value):
10067777Sgblack@eecs.umich.edu        self.__init__(value)
10077777Sgblack@eecs.umich.edu        return value
10087777Sgblack@eecs.umich.edu
10097777Sgblack@eecs.umich.edu    def __str__(self):
10107777Sgblack@eecs.umich.edu        tup = [(self.ip >> i)  & 0xff for i in (24, 16, 8, 0)]
10117777Sgblack@eecs.umich.edu        return '%d.%d.%d.%d' % tuple(tup)
10127777Sgblack@eecs.umich.edu
10137777Sgblack@eecs.umich.edu    def __eq__(self, other):
10147777Sgblack@eecs.umich.edu        if isinstance(other, IpAddress):
10157777Sgblack@eecs.umich.edu            return self.ip == other.ip
10167777Sgblack@eecs.umich.edu        elif isinstance(other, str):
10177777Sgblack@eecs.umich.edu            try:
10187777Sgblack@eecs.umich.edu                return self.ip == convert.toIpAddress(other)
10197777Sgblack@eecs.umich.edu            except:
10207777Sgblack@eecs.umich.edu                return False
102110267SGeoffrey.Blake@arm.com        else:
102210267SGeoffrey.Blake@arm.com            return self.ip == other
102310267SGeoffrey.Blake@arm.com
102410267SGeoffrey.Blake@arm.com    def __ne__(self, other):
10258579Ssteve.reinhardt@amd.com        return not (self == other)
10268579Ssteve.reinhardt@amd.com
10278579Ssteve.reinhardt@amd.com    def verifyIp(self):
10288579Ssteve.reinhardt@amd.com        if self.ip < 0 or self.ip >= (1 << 32):
10298579Ssteve.reinhardt@amd.com            raise TypeError("invalid ip address %#08x" % self.ip)
10308579Ssteve.reinhardt@amd.com
10318579Ssteve.reinhardt@amd.com    def getValue(self):
10328579Ssteve.reinhardt@amd.com        from _m5.net import IpAddress
10338579Ssteve.reinhardt@amd.com        return IpAddress(self.ip)
10348579Ssteve.reinhardt@amd.com
10358579Ssteve.reinhardt@amd.com# When initializing an IpNetmask, pass in an existing IpNetmask, a string of
10368579Ssteve.reinhardt@amd.com# the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as
10378579Ssteve.reinhardt@amd.com# positional or keyword arguments.
10388579Ssteve.reinhardt@amd.comclass IpNetmask(IpAddress):
10397777Sgblack@eecs.umich.edu    cxx_type = 'Net::IpNetmask'
10407777Sgblack@eecs.umich.edu    ex_str = "127.0.0.0/24"
10417777Sgblack@eecs.umich.edu    cmd_line_settable = True
10427777Sgblack@eecs.umich.edu
10437777Sgblack@eecs.umich.edu    @classmethod
10447777Sgblack@eecs.umich.edu    def cxx_predecls(cls, code):
104511988Sandreas.sandberg@arm.com        code('#include "base/inet.hh"')
10467777Sgblack@eecs.umich.edu
10477777Sgblack@eecs.umich.edu    def __init__(self, *args, **kwargs):
10487777Sgblack@eecs.umich.edu        def handle_kwarg(self, kwargs, key, elseVal = None):
10497777Sgblack@eecs.umich.edu            if key in kwargs:
10507777Sgblack@eecs.umich.edu                setattr(self, key, kwargs.pop(key))
10517777Sgblack@eecs.umich.edu            elif elseVal:
105210267SGeoffrey.Blake@arm.com                setattr(self, key, elseVal)
105310267SGeoffrey.Blake@arm.com            else:
10547777Sgblack@eecs.umich.edu                raise TypeError("No value set for %s" % key)
10557777Sgblack@eecs.umich.edu
10567777Sgblack@eecs.umich.edu        if len(args) == 0:
10577777Sgblack@eecs.umich.edu            handle_kwarg(self, kwargs, 'ip')
10587777Sgblack@eecs.umich.edu            handle_kwarg(self, kwargs, 'netmask')
10597777Sgblack@eecs.umich.edu
10607777Sgblack@eecs.umich.edu        elif len(args) == 1:
10617777Sgblack@eecs.umich.edu            if kwargs:
10627777Sgblack@eecs.umich.edu                if not 'ip' in kwargs and not 'netmask' in kwargs:
10637777Sgblack@eecs.umich.edu                    raise TypeError("Invalid arguments")
10647777Sgblack@eecs.umich.edu                handle_kwarg(self, kwargs, 'ip', args[0])
10657777Sgblack@eecs.umich.edu                handle_kwarg(self, kwargs, 'netmask', args[0])
10667777Sgblack@eecs.umich.edu            elif isinstance(args[0], IpNetmask):
10677777Sgblack@eecs.umich.edu                self.ip = args[0].ip
10687777Sgblack@eecs.umich.edu                self.netmask = args[0].netmask
10697777Sgblack@eecs.umich.edu            else:
10707777Sgblack@eecs.umich.edu                (self.ip, self.netmask) = convert.toIpNetmask(args[0])
10717777Sgblack@eecs.umich.edu
10727777Sgblack@eecs.umich.edu        elif len(args) == 2:
10737777Sgblack@eecs.umich.edu            self.ip = args[0]
10747777Sgblack@eecs.umich.edu            self.netmask = args[1]
10757777Sgblack@eecs.umich.edu        else:
10767777Sgblack@eecs.umich.edu            raise TypeError("Too many arguments specified")
10777777Sgblack@eecs.umich.edu
10787777Sgblack@eecs.umich.edu        if kwargs:
10797777Sgblack@eecs.umich.edu            raise TypeError("Too many keywords: %s" % list(kwargs.keys()))
10807777Sgblack@eecs.umich.edu
10817777Sgblack@eecs.umich.edu        self.verify()
10827777Sgblack@eecs.umich.edu
10837777Sgblack@eecs.umich.edu    def __call__(self, value):
10847777Sgblack@eecs.umich.edu        self.__init__(value)
10857777Sgblack@eecs.umich.edu        return value
10867777Sgblack@eecs.umich.edu
10877777Sgblack@eecs.umich.edu    def __str__(self):
10887777Sgblack@eecs.umich.edu        return "%s/%d" % (super(IpNetmask, self).__str__(), self.netmask)
10897777Sgblack@eecs.umich.edu
10907777Sgblack@eecs.umich.edu    def __eq__(self, other):
10917777Sgblack@eecs.umich.edu        if isinstance(other, IpNetmask):
10927777Sgblack@eecs.umich.edu            return self.ip == other.ip and self.netmask == other.netmask
10937777Sgblack@eecs.umich.edu        elif isinstance(other, str):
10947777Sgblack@eecs.umich.edu            try:
109510267SGeoffrey.Blake@arm.com                return (self.ip, self.netmask) == convert.toIpNetmask(other)
109610267SGeoffrey.Blake@arm.com            except:
109710267SGeoffrey.Blake@arm.com                return False
109810267SGeoffrey.Blake@arm.com        else:
10998579Ssteve.reinhardt@amd.com            return False
11008579Ssteve.reinhardt@amd.com
11018579Ssteve.reinhardt@amd.com    def verify(self):
11028579Ssteve.reinhardt@amd.com        self.verifyIp()
11038579Ssteve.reinhardt@amd.com        if self.netmask < 0 or self.netmask > 32:
11048579Ssteve.reinhardt@amd.com            raise TypeError("invalid netmask %d" % netmask)
11058579Ssteve.reinhardt@amd.com
11068579Ssteve.reinhardt@amd.com    def getValue(self):
11078579Ssteve.reinhardt@amd.com        from _m5.net import IpNetmask
11088579Ssteve.reinhardt@amd.com        return IpNetmask(self.ip, self.netmask)
11098579Ssteve.reinhardt@amd.com
11108579Ssteve.reinhardt@amd.com# When initializing an IpWithPort, pass in an existing IpWithPort, a string of
11118579Ssteve.reinhardt@amd.com# the form "a.b.c.d:p", or an ip and port as positional or keyword arguments.
11128579Ssteve.reinhardt@amd.comclass IpWithPort(IpAddress):
11137777Sgblack@eecs.umich.edu    cxx_type = 'Net::IpWithPort'
11147777Sgblack@eecs.umich.edu    ex_str = "127.0.0.1:80"
11157777Sgblack@eecs.umich.edu    cmd_line_settable = True
11167777Sgblack@eecs.umich.edu
11177777Sgblack@eecs.umich.edu    @classmethod
11187777Sgblack@eecs.umich.edu    def cxx_predecls(cls, code):
111911988Sandreas.sandberg@arm.com        code('#include "base/inet.hh"')
11207777Sgblack@eecs.umich.edu
11217777Sgblack@eecs.umich.edu    def __init__(self, *args, **kwargs):
11223932Sbinkertn@umich.edu        def handle_kwarg(self, kwargs, key, elseVal = None):
112310380SAndrew.Bardsley@arm.com            if key in kwargs:
11243932Sbinkertn@umich.edu                setattr(self, key, kwargs.pop(key))
11253932Sbinkertn@umich.edu            elif elseVal:
11263932Sbinkertn@umich.edu                setattr(self, key, elseVal)
11273932Sbinkertn@umich.edu            else:
11283932Sbinkertn@umich.edu                raise TypeError("No value set for %s" % key)
11293932Sbinkertn@umich.edu
11303932Sbinkertn@umich.edu        if len(args) == 0:
11313932Sbinkertn@umich.edu            handle_kwarg(self, kwargs, 'ip')
11323932Sbinkertn@umich.edu            handle_kwarg(self, kwargs, 'port')
11333932Sbinkertn@umich.edu
11343932Sbinkertn@umich.edu        elif len(args) == 1:
11353885Sbinkertn@umich.edu            if kwargs:
11363932Sbinkertn@umich.edu                if not 'ip' in kwargs and not 'port' in kwargs:
11373932Sbinkertn@umich.edu                    raise TypeError("Invalid arguments")
11383885Sbinkertn@umich.edu                handle_kwarg(self, kwargs, 'ip', args[0])
11393932Sbinkertn@umich.edu                handle_kwarg(self, kwargs, 'port', args[0])
11403932Sbinkertn@umich.edu            elif isinstance(args[0], IpWithPort):
11413932Sbinkertn@umich.edu                self.ip = args[0].ip
11423932Sbinkertn@umich.edu                self.port = args[0].port
11433932Sbinkertn@umich.edu            else:
11443932Sbinkertn@umich.edu                (self.ip, self.port) = convert.toIpWithPort(args[0])
11453932Sbinkertn@umich.edu
11463932Sbinkertn@umich.edu        elif len(args) == 2:
11473932Sbinkertn@umich.edu            self.ip = args[0]
11483932Sbinkertn@umich.edu            self.port = args[1]
11493932Sbinkertn@umich.edu        else:
11503932Sbinkertn@umich.edu            raise TypeError("Too many arguments specified")
11513932Sbinkertn@umich.edu
11523932Sbinkertn@umich.edu        if kwargs:
11533932Sbinkertn@umich.edu            raise TypeError("Too many keywords: %s" % list(kwargs.keys()))
11543932Sbinkertn@umich.edu
11553932Sbinkertn@umich.edu        self.verify()
11563932Sbinkertn@umich.edu
11573885Sbinkertn@umich.edu    def __call__(self, value):
11583885Sbinkertn@umich.edu        self.__init__(value)
11593885Sbinkertn@umich.edu        return value
11603885Sbinkertn@umich.edu
11614762Snate@binkert.org    def __str__(self):
11627673Snate@binkert.org        return "%s:%d" % (super(IpWithPort, self).__str__(), self.port)
11637673Snate@binkert.org
11647673Snate@binkert.org    def __eq__(self, other):
11657673Snate@binkert.org        if isinstance(other, IpWithPort):
11667673Snate@binkert.org            return self.ip == other.ip and self.port == other.port
11673885Sbinkertn@umich.edu        elif isinstance(other, str):
11683932Sbinkertn@umich.edu            try:
11693885Sbinkertn@umich.edu                return (self.ip, self.port) == convert.toIpWithPort(other)
117010267SGeoffrey.Blake@arm.com            except:
117110267SGeoffrey.Blake@arm.com                return False
117210267SGeoffrey.Blake@arm.com        else:
117310267SGeoffrey.Blake@arm.com            return False
11744762Snate@binkert.org
117511988Sandreas.sandberg@arm.com    def verify(self):
117611988Sandreas.sandberg@arm.com        self.verifyIp()
11774762Snate@binkert.org        if self.port < 0 or self.port > 0xffff:
117811988Sandreas.sandberg@arm.com            raise TypeError("invalid port %d" % self.port)
11794762Snate@binkert.org
11803885Sbinkertn@umich.edu    def getValue(self):
11814762Snate@binkert.org        from _m5.net import IpWithPort
11823885Sbinkertn@umich.edu        return IpWithPort(self.ip, self.port)
11833885Sbinkertn@umich.edu
11843932Sbinkertn@umich.edutime_formats = [ "%a %b %d %H:%M:%S %Z %Y",
11853885Sbinkertn@umich.edu                 "%a %b %d %H:%M:%S %Y",
11868664SAli.Saidi@ARM.com                 "%Y/%m/%d %H:%M:%S",
118710380SAndrew.Bardsley@arm.com                 "%Y/%m/%d %H:%M",
11888664SAli.Saidi@ARM.com                 "%Y/%m/%d",
11898664SAli.Saidi@ARM.com                 "%m/%d/%Y %H:%M:%S",
119010458Sandreas.hansson@arm.com                 "%m/%d/%Y %H:%M",
119110458Sandreas.hansson@arm.com                 "%m/%d/%Y",
119210458Sandreas.hansson@arm.com                 "%m/%d/%y %H:%M:%S",
119310458Sandreas.hansson@arm.com                 "%m/%d/%y %H:%M",
119410458Sandreas.hansson@arm.com                 "%m/%d/%y"]
119510458Sandreas.hansson@arm.com
119610458Sandreas.hansson@arm.com
119710458Sandreas.hansson@arm.comdef parse_time(value):
119810458Sandreas.hansson@arm.com    from time import gmtime, strptime, struct_time, time
119910458Sandreas.hansson@arm.com    from datetime import datetime, date
12003101Sstever@eecs.umich.edu
12013101Sstever@eecs.umich.edu    if isinstance(value, struct_time):
12023101Sstever@eecs.umich.edu        return value
12033101Sstever@eecs.umich.edu
12043101Sstever@eecs.umich.edu    if isinstance(value, (int, long)):
12053101Sstever@eecs.umich.edu        return gmtime(value)
12063101Sstever@eecs.umich.edu
12073101Sstever@eecs.umich.edu    if isinstance(value, (datetime, date)):
12083101Sstever@eecs.umich.edu        return value.timetuple()
12093101Sstever@eecs.umich.edu
12103101Sstever@eecs.umich.edu    if isinstance(value, str):
12113101Sstever@eecs.umich.edu        if value in ('Now', 'Today'):
12123101Sstever@eecs.umich.edu            return time.gmtime(time.time())
12133101Sstever@eecs.umich.edu
12144762Snate@binkert.org        for format in time_formats:
12153101Sstever@eecs.umich.edu            try:
12165033Smilesck@eecs.umich.edu                return strptime(value, format)
12174762Snate@binkert.org            except ValueError:
12184762Snate@binkert.org                pass
12194762Snate@binkert.org
12204762Snate@binkert.org    raise ValueError("Could not parse '%s' as a time" % value)
12214762Snate@binkert.org
12224762Snate@binkert.orgclass Time(ParamValue):
12234762Snate@binkert.org    cxx_type = 'tm'
12243101Sstever@eecs.umich.edu
12253101Sstever@eecs.umich.edu    @classmethod
12263101Sstever@eecs.umich.edu    def cxx_predecls(cls, code):
12273101Sstever@eecs.umich.edu        code('#include <time.h>')
12283101Sstever@eecs.umich.edu
12293101Sstever@eecs.umich.edu    def __init__(self, value):
12303101Sstever@eecs.umich.edu        self.value = parse_time(value)
12313101Sstever@eecs.umich.edu
12323101Sstever@eecs.umich.edu    def __call__(self, value):
12333101Sstever@eecs.umich.edu        self.__init__(value)
12343101Sstever@eecs.umich.edu        return value
12353101Sstever@eecs.umich.edu
12363101Sstever@eecs.umich.edu    def getValue(self):
12373101Sstever@eecs.umich.edu        from _m5.core import tm
12383101Sstever@eecs.umich.edu        import calendar
12393101Sstever@eecs.umich.edu
12403101Sstever@eecs.umich.edu        return tm.gmtime(calendar.timegm(self.value))
12413101Sstever@eecs.umich.edu
12423101Sstever@eecs.umich.edu    def __str__(self):
12433101Sstever@eecs.umich.edu        return time.asctime(self.value)
12444762Snate@binkert.org
12453101Sstever@eecs.umich.edu    def ini_str(self):
12463101Sstever@eecs.umich.edu        return str(self)
12473101Sstever@eecs.umich.edu
12483101Sstever@eecs.umich.edu    def get_config_as_dict(self):
12493101Sstever@eecs.umich.edu        assert false
12503101Sstever@eecs.umich.edu        return str(self)
12517673Snate@binkert.org
125210201SAndrew.Bardsley@arm.com    @classmethod
125310201SAndrew.Bardsley@arm.com    def cxx_ini_predecls(cls, code):
125410201SAndrew.Bardsley@arm.com        code('#include <time.h>')
125510201SAndrew.Bardsley@arm.com
125610201SAndrew.Bardsley@arm.com    @classmethod
12577673Snate@binkert.org    def cxx_ini_parse(cls, code, src, dest, ret):
125810201SAndrew.Bardsley@arm.com        code('char *_parse_ret = strptime((${src}).c_str(),')
125910201SAndrew.Bardsley@arm.com        code('    "%a %b %d %H:%M:%S %Y", &(${dest}));')
12607673Snate@binkert.org        code('${ret} _parse_ret && *_parse_ret == \'\\0\';');
126110201SAndrew.Bardsley@arm.com
12627673Snate@binkert.org# Enumerated types are a little more complex.  The user specifies the
12637673Snate@binkert.org# type as Enum(foo) where foo is either a list or dictionary of
12647673Snate@binkert.org# alternatives (typically strings, but not necessarily so).  (In the
12654762Snate@binkert.org# long run, the integer value of the parameter will be the list index
12667673Snate@binkert.org# or the corresponding dictionary value.  For now, since we only check
12678902Sandreas.hansson@arm.com# that the alternative is valid and then spit it into a .ini file,
12687673Snate@binkert.org# there's not much point in using the dictionary.)
126910201SAndrew.Bardsley@arm.com
12704762Snate@binkert.org# What Enum() must do is generate a new type encapsulating the
127110201SAndrew.Bardsley@arm.com# provided list/dictionary so that specific values of the parameter
127210201SAndrew.Bardsley@arm.com# can be instances of that type.  We define two hidden internal
127310201SAndrew.Bardsley@arm.com# classes (_ListEnum and _DictEnum) to serve as base classes, then
127410201SAndrew.Bardsley@arm.com# derive the new type from the appropriate base class on the fly.
127510201SAndrew.Bardsley@arm.com
127610201SAndrew.Bardsley@arm.comallEnums = {}
127710201SAndrew.Bardsley@arm.com# Metaclass for Enum types
127810201SAndrew.Bardsley@arm.comclass MetaEnum(MetaParamValue):
127910201SAndrew.Bardsley@arm.com    def __new__(mcls, name, bases, dict):
12807673Snate@binkert.org        assert name not in allEnums
12817673Snate@binkert.org
128210201SAndrew.Bardsley@arm.com        cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict)
128310201SAndrew.Bardsley@arm.com        allEnums[name] = cls
128410201SAndrew.Bardsley@arm.com        return cls
128510201SAndrew.Bardsley@arm.com
128610201SAndrew.Bardsley@arm.com    def __init__(cls, name, bases, init_dict):
128710201SAndrew.Bardsley@arm.com        if 'map' in init_dict:
128810201SAndrew.Bardsley@arm.com            if not isinstance(cls.map, dict):
128910201SAndrew.Bardsley@arm.com                raise TypeError("Enum-derived class attribute 'map' " \
129010201SAndrew.Bardsley@arm.com                      "must be of type dict")
129110201SAndrew.Bardsley@arm.com            # build list of value strings from map
129210201SAndrew.Bardsley@arm.com            cls.vals = list(cls.map.keys())
129310201SAndrew.Bardsley@arm.com            cls.vals.sort()
129410201SAndrew.Bardsley@arm.com        elif 'vals' in init_dict:
129510201SAndrew.Bardsley@arm.com            if not isinstance(cls.vals, list):
129610201SAndrew.Bardsley@arm.com                raise TypeError("Enum-derived class attribute 'vals' " \
12974762Snate@binkert.org                      "must be of type list")
12987673Snate@binkert.org            # build string->value map from vals sequence
129910201SAndrew.Bardsley@arm.com            cls.map = {}
130010201SAndrew.Bardsley@arm.com            for idx,val in enumerate(cls.vals):
130110201SAndrew.Bardsley@arm.com                cls.map[val] = idx
130210201SAndrew.Bardsley@arm.com        else:
130310201SAndrew.Bardsley@arm.com            raise TypeError("Enum-derived class must define "\
130410201SAndrew.Bardsley@arm.com                  "attribute 'map' or 'vals'")
13053101Sstever@eecs.umich.edu
130611988Sandreas.sandberg@arm.com        if cls.is_class:
130711988Sandreas.sandberg@arm.com            cls.cxx_type = '%s' % name
130811988Sandreas.sandberg@arm.com        else:
130911988Sandreas.sandberg@arm.com            cls.cxx_type = 'Enums::%s' % name
131011988Sandreas.sandberg@arm.com
131111988Sandreas.sandberg@arm.com        super(MetaEnum, cls).__init__(name, bases, init_dict)
131211988Sandreas.sandberg@arm.com
131311988Sandreas.sandberg@arm.com    # Generate C++ class declaration for this enum type.
131411988Sandreas.sandberg@arm.com    # Note that we wrap the enum in a class/struct to act as a namespace,
131511988Sandreas.sandberg@arm.com    # so that the enum strings can be brief w/o worrying about collisions.
131611988Sandreas.sandberg@arm.com    def cxx_decl(cls, code):
131711988Sandreas.sandberg@arm.com        wrapper_name = cls.wrapper_name
131811988Sandreas.sandberg@arm.com        wrapper = 'struct' if cls.wrapper_is_struct else 'namespace'
131911988Sandreas.sandberg@arm.com        name = cls.__name__ if cls.enum_name is None else cls.enum_name
132011988Sandreas.sandberg@arm.com        idem_macro = '__ENUM__%s__%s__' % (wrapper_name, name)
132111988Sandreas.sandberg@arm.com
132211988Sandreas.sandberg@arm.com        code('''\
132311988Sandreas.sandberg@arm.com#ifndef $idem_macro
132411988Sandreas.sandberg@arm.com#define $idem_macro
132511988Sandreas.sandberg@arm.com
132611988Sandreas.sandberg@arm.com''')
132711988Sandreas.sandberg@arm.com        if cls.is_class:
132811988Sandreas.sandberg@arm.com            code('''\
132911988Sandreas.sandberg@arm.comenum class $name {
133011988Sandreas.sandberg@arm.com''')
133111988Sandreas.sandberg@arm.com        else:
133211988Sandreas.sandberg@arm.com            code('''\
133311988Sandreas.sandberg@arm.com$wrapper $wrapper_name {
133411988Sandreas.sandberg@arm.com    enum $name {
133511988Sandreas.sandberg@arm.com''')
133611988Sandreas.sandberg@arm.com            code.indent(1)
133711988Sandreas.sandberg@arm.com        code.indent(1)
133811988Sandreas.sandberg@arm.com        for val in cls.vals:
133911988Sandreas.sandberg@arm.com            code('$val = ${{cls.map[val]}},')
13408596Ssteve.reinhardt@amd.com        code('Num_$name = ${{len(cls.vals)}}')
13413101Sstever@eecs.umich.edu        code.dedent(1)
13423101Sstever@eecs.umich.edu        code('};')
13433101Sstever@eecs.umich.edu
13443101Sstever@eecs.umich.edu        if cls.is_class:
134510267SGeoffrey.Blake@arm.com            code('''\
13463101Sstever@eecs.umich.eduextern const char *${name}Strings[static_cast<int>(${name}::Num_${name})];
134710201SAndrew.Bardsley@arm.com''')
134810201SAndrew.Bardsley@arm.com        elif cls.wrapper_is_struct:
134910201SAndrew.Bardsley@arm.com            code('static const char *${name}Strings[Num_${name}];')
135010201SAndrew.Bardsley@arm.com        else:
135110201SAndrew.Bardsley@arm.com            code('extern const char *${name}Strings[Num_${name}];')
135210201SAndrew.Bardsley@arm.com
135310201SAndrew.Bardsley@arm.com        if not cls.is_class:
135410201SAndrew.Bardsley@arm.com            code.dedent(1)
135510201SAndrew.Bardsley@arm.com            code('};')
13563101Sstever@eecs.umich.edu
13573101Sstever@eecs.umich.edu        code()
13583101Sstever@eecs.umich.edu        code('#endif // $idem_macro')
13593101Sstever@eecs.umich.edu
13603101Sstever@eecs.umich.edu    def cxx_def(cls, code):
13613101Sstever@eecs.umich.edu        wrapper_name = cls.wrapper_name
136210267SGeoffrey.Blake@arm.com        file_name = cls.__name__
136310267SGeoffrey.Blake@arm.com        name = cls.__name__ if cls.enum_name is None else cls.enum_name
136410267SGeoffrey.Blake@arm.com
136510267SGeoffrey.Blake@arm.com        code('#include "enums/$file_name.hh"')
13667675Snate@binkert.org        if cls.wrapper_is_struct:
13677675Snate@binkert.org            code('const char *${wrapper_name}::${name}Strings'
13687675Snate@binkert.org                '[Num_${name}] =')
13697675Snate@binkert.org        else:
13707675Snate@binkert.org            if cls.is_class:
137110458Sandreas.hansson@arm.com                code('''\
137210458Sandreas.hansson@arm.comconst char *${name}Strings[static_cast<int>(${name}::Num_${name})] =
137310458Sandreas.hansson@arm.com''')
137410458Sandreas.hansson@arm.com            else:
137510458Sandreas.hansson@arm.com                code('namespace Enums {')
137610458Sandreas.hansson@arm.com                code.indent(1)
137710458Sandreas.hansson@arm.com                code('const char *${name}Strings[Num_${name}] =')
137810458Sandreas.hansson@arm.com
137910458Sandreas.hansson@arm.com        code('{')
138010458Sandreas.hansson@arm.com        code.indent(1)
138110458Sandreas.hansson@arm.com        for val in cls.vals:
138210458Sandreas.hansson@arm.com            code('"$val",')
13834762Snate@binkert.org        code.dedent(1)
138411988Sandreas.sandberg@arm.com        code('};')
138511988Sandreas.sandberg@arm.com
138611988Sandreas.sandberg@arm.com        if not cls.wrapper_is_struct and not cls.is_class:
13874762Snate@binkert.org            code.dedent(1)
13883101Sstever@eecs.umich.edu            code('} // namespace $wrapper_name')
13893101Sstever@eecs.umich.edu
13903101Sstever@eecs.umich.edu
13913101Sstever@eecs.umich.edu    def pybind_def(cls, code):
13923101Sstever@eecs.umich.edu        name = cls.__name__
13933101Sstever@eecs.umich.edu        enum_name = cls.__name__ if cls.enum_name is None else cls.enum_name
13944167Sbinkertn@umich.edu        wrapper_name = enum_name if cls.is_class else cls.wrapper_name
13953101Sstever@eecs.umich.edu
139610267SGeoffrey.Blake@arm.com        code('''#include "pybind11/pybind11.h"
139710267SGeoffrey.Blake@arm.com#include "pybind11/stl.h"
13987673Snate@binkert.org
13997673Snate@binkert.org#include <sim/init.hh>
14007673Snate@binkert.org
14017673Snate@binkert.orgnamespace py = pybind11;
14027673Snate@binkert.org
140310267SGeoffrey.Blake@arm.comstatic void
140410267SGeoffrey.Blake@arm.commodule_init(py::module &m_internal)
140510267SGeoffrey.Blake@arm.com{
140610267SGeoffrey.Blake@arm.com    py::module m = m_internal.def_submodule("enum_${name}");
14074762Snate@binkert.org
14084762Snate@binkert.org''')
14094762Snate@binkert.org        if cls.is_class:
141010458Sandreas.hansson@arm.com            code('py::enum_<${enum_name}>(m, "enum_${name}")')
141110458Sandreas.hansson@arm.com        else:
141210458Sandreas.hansson@arm.com            code('py::enum_<${wrapper_name}::${enum_name}>(m, "enum_${name}")')
141310458Sandreas.hansson@arm.com
141410458Sandreas.hansson@arm.com        code.indent()
141510458Sandreas.hansson@arm.com        code.indent()
141610458Sandreas.hansson@arm.com        for val in cls.vals:
141710458Sandreas.hansson@arm.com            code('.value("${val}", ${wrapper_name}::${val})')
141810458Sandreas.hansson@arm.com        code('.value("Num_${name}", ${wrapper_name}::Num_${enum_name})')
141910458Sandreas.hansson@arm.com        code('.export_values()')
14204167Sbinkertn@umich.edu        code(';')
142110267SGeoffrey.Blake@arm.com        code.dedent()
142210267SGeoffrey.Blake@arm.com
14233101Sstever@eecs.umich.edu        code('}')
14244167Sbinkertn@umich.edu        code.dedent()
14254167Sbinkertn@umich.edu        code()
14264167Sbinkertn@umich.edu        code('static EmbeddedPyBind embed_enum("enum_${name}", module_init);')
14274167Sbinkertn@umich.edu
14284167Sbinkertn@umich.edu
14294167Sbinkertn@umich.edu# Base class for enum types.
14304167Sbinkertn@umich.educlass Enum(ParamValue):
14314167Sbinkertn@umich.edu    __metaclass__ = MetaEnum
14324167Sbinkertn@umich.edu    vals = []
14334167Sbinkertn@umich.edu    cmd_line_settable = True
14344167Sbinkertn@umich.edu
14354167Sbinkertn@umich.edu    # The name of the wrapping namespace or struct
14363101Sstever@eecs.umich.edu    wrapper_name = 'Enums'
143710267SGeoffrey.Blake@arm.com
143810267SGeoffrey.Blake@arm.com    # If true, the enum is wrapped in a struct rather than a namespace
143910267SGeoffrey.Blake@arm.com    wrapper_is_struct = False
144010267SGeoffrey.Blake@arm.com
14413101Sstever@eecs.umich.edu    is_class = False
14423101Sstever@eecs.umich.edu
14433101Sstever@eecs.umich.edu    # If not None, use this as the enum name rather than this class name
14443101Sstever@eecs.umich.edu    enum_name = None
14453101Sstever@eecs.umich.edu
14463101Sstever@eecs.umich.edu    def __init__(self, value):
14473101Sstever@eecs.umich.edu        if value not in self.map:
14484762Snate@binkert.org            raise TypeError("Enum param got bad value '%s' (not in %s)" \
14494762Snate@binkert.org                  % (value, self.vals))
14504762Snate@binkert.org        self.value = value
14514762Snate@binkert.org
14524762Snate@binkert.org    def __call__(self, value):
14534762Snate@binkert.org        self.__init__(value)
14544762Snate@binkert.org        return value
145510380SAndrew.Bardsley@arm.com
145610380SAndrew.Bardsley@arm.com    @classmethod
145710380SAndrew.Bardsley@arm.com    def cxx_predecls(cls, code):
14583101Sstever@eecs.umich.edu        code('#include "enums/$0.hh"', cls.__name__)
14593101Sstever@eecs.umich.edu
14604762Snate@binkert.org    @classmethod
14613101Sstever@eecs.umich.edu    def cxx_ini_parse(cls, code, src, dest, ret):
14624167Sbinkertn@umich.edu        code('if (false) {')
146310267SGeoffrey.Blake@arm.com        for elem_name in cls.map.keys():
146410267SGeoffrey.Blake@arm.com            code('} else if (%s == "%s") {' % (src, elem_name))
14653101Sstever@eecs.umich.edu            code.indent()
14664167Sbinkertn@umich.edu            code('%s = Enums::%s;' % (dest, elem_name))
14674167Sbinkertn@umich.edu            code('%s true;' % ret)
14684167Sbinkertn@umich.edu            code.dedent()
14694167Sbinkertn@umich.edu        code('} else {')
14704167Sbinkertn@umich.edu        code('    %s false;' % ret)
14714167Sbinkertn@umich.edu        code('}')
14724167Sbinkertn@umich.edu
14734167Sbinkertn@umich.edu    def getValue(self):
14744167Sbinkertn@umich.edu        import m5.internal.params
14754167Sbinkertn@umich.edu        e = getattr(m5.internal.params, "enum_%s" % self.__class__.__name__)
14764167Sbinkertn@umich.edu        return e(self.map[self.value])
14774167Sbinkertn@umich.edu
14783101Sstever@eecs.umich.edu    def __str__(self):
147910267SGeoffrey.Blake@arm.com        return self.value
148010267SGeoffrey.Blake@arm.com
148110267SGeoffrey.Blake@arm.com# This param will generate a scoped c++ enum and its python bindings.
148210267SGeoffrey.Blake@arm.comclass ScopedEnum(Enum):
14833101Sstever@eecs.umich.edu    __metaclass__ = MetaEnum
14843101Sstever@eecs.umich.edu    vals = []
14853101Sstever@eecs.umich.edu    cmd_line_settable = True
14863101Sstever@eecs.umich.edu
14873101Sstever@eecs.umich.edu    # The name of the wrapping namespace or struct
14883101Sstever@eecs.umich.edu    wrapper_name = None
14893101Sstever@eecs.umich.edu
14904167Sbinkertn@umich.edu    # If true, the enum is wrapped in a struct rather than a namespace
14914762Snate@binkert.org    wrapper_is_struct = False
14924762Snate@binkert.org
14934762Snate@binkert.org    # If true, the generated enum is a scoped enum
14944762Snate@binkert.org    is_class = True
14954762Snate@binkert.org
14964762Snate@binkert.org    # If not None, use this as the enum name rather than this class name
14974762Snate@binkert.org    enum_name = None
149810380SAndrew.Bardsley@arm.com
149910380SAndrew.Bardsley@arm.com# how big does a rounding error need to be before we warn about it?
150010380SAndrew.Bardsley@arm.comfrequency_tolerance = 0.001  # 0.1%
15013101Sstever@eecs.umich.edu
15024762Snate@binkert.orgclass TickParamValue(NumericParamValue):
15033101Sstever@eecs.umich.edu    cxx_type = 'Tick'
150410019Sandreas.hansson@arm.com    ex_str = "1MHz"
150510019Sandreas.hansson@arm.com    cmd_line_settable = True
150610019Sandreas.hansson@arm.com
15073101Sstever@eecs.umich.edu    @classmethod
15084167Sbinkertn@umich.edu    def cxx_predecls(cls, code):
15094167Sbinkertn@umich.edu        code('#include "base/types.hh"')
15104167Sbinkertn@umich.edu
15114167Sbinkertn@umich.edu    def __call__(self, value):
15124167Sbinkertn@umich.edu        self.__init__(value)
15134167Sbinkertn@umich.edu        return value
15144167Sbinkertn@umich.edu
15154167Sbinkertn@umich.edu    def getValue(self):
15164167Sbinkertn@umich.edu        return long(self.value)
15174167Sbinkertn@umich.edu
15184167Sbinkertn@umich.edu    @classmethod
15194167Sbinkertn@umich.edu    def cxx_ini_predecls(cls, code):
15203101Sstever@eecs.umich.edu        code('#include <sstream>')
152110267SGeoffrey.Blake@arm.com
152210267SGeoffrey.Blake@arm.com    # Ticks are expressed in seconds in JSON files and in plain
152310267SGeoffrey.Blake@arm.com    # Ticks in .ini files.  Switch based on a config flag
152410267SGeoffrey.Blake@arm.com    @classmethod
152510267SGeoffrey.Blake@arm.com    def cxx_ini_parse(self, code, src, dest, ret):
152610267SGeoffrey.Blake@arm.com        code('${ret} to_number(${src}, ${dest});')
152710267SGeoffrey.Blake@arm.com
15283101Sstever@eecs.umich.educlass Latency(TickParamValue):
15293101Sstever@eecs.umich.edu    ex_str = "100ns"
15303101Sstever@eecs.umich.edu
15313101Sstever@eecs.umich.edu    def __init__(self, value):
15323101Sstever@eecs.umich.edu        if isinstance(value, (Latency, Clock)):
15333101Sstever@eecs.umich.edu            self.ticks = value.ticks
15343101Sstever@eecs.umich.edu            self.value = value.value
15354762Snate@binkert.org        elif isinstance(value, Frequency):
15364762Snate@binkert.org            self.ticks = value.ticks
15374762Snate@binkert.org            self.value = 1.0 / value.value
153810380SAndrew.Bardsley@arm.com        elif value.endswith('t'):
153910380SAndrew.Bardsley@arm.com            self.ticks = True
154010380SAndrew.Bardsley@arm.com            self.value = int(value[:-1])
15413101Sstever@eecs.umich.edu        else:
15423101Sstever@eecs.umich.edu            self.ticks = False
15433101Sstever@eecs.umich.edu            self.value = convert.toLatency(value)
154412250Sgabeblack@google.com
154510267SGeoffrey.Blake@arm.com    def __call__(self, value):
154610267SGeoffrey.Blake@arm.com        self.__init__(value)
15479827Sakash.bagdia@arm.com        return value
154812250Sgabeblack@google.com
154912250Sgabeblack@google.com    def __getattr__(self, attr):
15509827Sakash.bagdia@arm.com        if attr in ('latency', 'period'):
155112250Sgabeblack@google.com            return self
155212250Sgabeblack@google.com        if attr == 'frequency':
155312250Sgabeblack@google.com            return Frequency(self)
155410267SGeoffrey.Blake@arm.com        raise AttributeError("Latency object has no attribute '%s'" % attr)
155512250Sgabeblack@google.com
155610427Sandreas.hansson@arm.com    def getValue(self):
155710427Sandreas.hansson@arm.com        if self.ticks or self.value == 0:
155810427Sandreas.hansson@arm.com            value = self.value
155912250Sgabeblack@google.com        else:
156012250Sgabeblack@google.com            value = ticks.fromSeconds(self.value)
156110427Sandreas.hansson@arm.com        return long(value)
156212250Sgabeblack@google.com
156312250Sgabeblack@google.com    def config_value(self):
156412250Sgabeblack@google.com        return self.getValue()
156510458Sandreas.hansson@arm.com
15663101Sstever@eecs.umich.edu    # convert latency to ticks
15673101Sstever@eecs.umich.edu    def ini_str(self):
156810267SGeoffrey.Blake@arm.com        return '%d' % self.getValue()
156910267SGeoffrey.Blake@arm.com
157010267SGeoffrey.Blake@arm.comclass Frequency(TickParamValue):
15713101Sstever@eecs.umich.edu    ex_str = "1GHz"
15724167Sbinkertn@umich.edu
15734167Sbinkertn@umich.edu    def __init__(self, value):
15743101Sstever@eecs.umich.edu        if isinstance(value, (Latency, Clock)):
15753101Sstever@eecs.umich.edu            if value.value == 0:
15763101Sstever@eecs.umich.edu                self.value = 0
15773101Sstever@eecs.umich.edu            else:
15783101Sstever@eecs.umich.edu                self.value = 1.0 / value.value
157910267SGeoffrey.Blake@arm.com            self.ticks = value.ticks
158010267SGeoffrey.Blake@arm.com        elif isinstance(value, Frequency):
158110267SGeoffrey.Blake@arm.com            self.value = value.value
158210267SGeoffrey.Blake@arm.com            self.ticks = value.ticks
158310267SGeoffrey.Blake@arm.com        else:
15844762Snate@binkert.org            self.ticks = False
15854167Sbinkertn@umich.edu            self.value = convert.toFrequency(value)
15864167Sbinkertn@umich.edu
15874167Sbinkertn@umich.edu    def __call__(self, value):
15884762Snate@binkert.org        self.__init__(value)
15894762Snate@binkert.org        return value
15904762Snate@binkert.org
15914762Snate@binkert.org    def __getattr__(self, attr):
15924762Snate@binkert.org        if attr == 'frequency':
15933101Sstever@eecs.umich.edu            return self
159410380SAndrew.Bardsley@arm.com        if attr in ('latency', 'period'):
159510380SAndrew.Bardsley@arm.com            return Latency(self)
159610380SAndrew.Bardsley@arm.com        raise AttributeError("Frequency object has no attribute '%s'" % attr)
159710458Sandreas.hansson@arm.com
159810458Sandreas.hansson@arm.com    # convert latency to ticks
159910458Sandreas.hansson@arm.com    def getValue(self):
160010458Sandreas.hansson@arm.com        if self.ticks or self.value == 0:
160110458Sandreas.hansson@arm.com            value = self.value
160210458Sandreas.hansson@arm.com        else:
160310458Sandreas.hansson@arm.com            value = ticks.fromSeconds(1.0 / self.value)
160410458Sandreas.hansson@arm.com        return long(value)
16053101Sstever@eecs.umich.edu
16063101Sstever@eecs.umich.edu    def config_value(self):
160710267SGeoffrey.Blake@arm.com        return self.getValue()
160810267SGeoffrey.Blake@arm.com
160910267SGeoffrey.Blake@arm.com    def ini_str(self):
16105469Snate@binkert.org        return '%d' % self.getValue()
16117743Sgblack@eecs.umich.edu
16123102Sstever@eecs.umich.edu# A generic Frequency and/or Latency value. Value is stored as a
16133101Sstever@eecs.umich.edu# latency, just like Latency and Frequency.
16143101Sstever@eecs.umich.educlass Clock(TickParamValue):
161510267SGeoffrey.Blake@arm.com    def __init__(self, value):
161610267SGeoffrey.Blake@arm.com        if isinstance(value, (Latency, Clock)):
161710267SGeoffrey.Blake@arm.com            self.ticks = value.ticks
161810267SGeoffrey.Blake@arm.com            self.value = value.value
16193101Sstever@eecs.umich.edu        elif isinstance(value, Frequency):
16204762Snate@binkert.org            self.ticks = value.ticks
16214167Sbinkertn@umich.edu            self.value = 1.0 / value.value
16225468Snate@binkert.org        elif value.endswith('t'):
16235468Snate@binkert.org            self.ticks = True
16245468Snate@binkert.org            self.value = int(value[:-1])
16254167Sbinkertn@umich.edu        else:
16264762Snate@binkert.org            self.ticks = False
16274762Snate@binkert.org            self.value = convert.anyToLatency(value)
16284762Snate@binkert.org
16294762Snate@binkert.org    def __call__(self, value):
16304762Snate@binkert.org        self.__init__(value)
16313101Sstever@eecs.umich.edu        return value
163210380SAndrew.Bardsley@arm.com
163310380SAndrew.Bardsley@arm.com    def __str__(self):
163410380SAndrew.Bardsley@arm.com        return "%s" % Latency(self)
163510458Sandreas.hansson@arm.com
163610458Sandreas.hansson@arm.com    def __getattr__(self, attr):
163710458Sandreas.hansson@arm.com        if attr == 'frequency':
163810458Sandreas.hansson@arm.com            return Frequency(self)
163910458Sandreas.hansson@arm.com        if attr in ('latency', 'period'):
164010458Sandreas.hansson@arm.com            return Latency(self)
164110458Sandreas.hansson@arm.com        raise AttributeError("Frequency object has no attribute '%s'" % attr)
164210458Sandreas.hansson@arm.com
16433101Sstever@eecs.umich.edu    def getValue(self):
16443101Sstever@eecs.umich.edu        return self.period.getValue()
16453101Sstever@eecs.umich.edu
16463101Sstever@eecs.umich.edu    def config_value(self):
16473102Sstever@eecs.umich.edu        return self.period.config_value()
16483102Sstever@eecs.umich.edu
16493102Sstever@eecs.umich.edu    def ini_str(self):
16503102Sstever@eecs.umich.edu        return self.period.ini_str()
16513102Sstever@eecs.umich.edu
16523102Sstever@eecs.umich.educlass Voltage(Float):
165312197Sgabeblack@google.com    ex_str = "1V"
16543102Sstever@eecs.umich.edu
16553102Sstever@eecs.umich.edu    def __new__(cls, value):
16563102Sstever@eecs.umich.edu        value = convert.toVoltage(value)
16573102Sstever@eecs.umich.edu        return super(cls, Voltage).__new__(cls, value)
16583102Sstever@eecs.umich.edu
16593102Sstever@eecs.umich.edu    def __init__(self, value):
16603102Sstever@eecs.umich.edu        value = convert.toVoltage(value)
16613102Sstever@eecs.umich.edu        super(Voltage, self).__init__(value)
16623102Sstever@eecs.umich.edu
16633102Sstever@eecs.umich.educlass Current(Float):
16643102Sstever@eecs.umich.edu    ex_str = "1mA"
16653102Sstever@eecs.umich.edu
16663102Sstever@eecs.umich.edu    def __new__(cls, value):
16673102Sstever@eecs.umich.edu        value = convert.toCurrent(value)
16683102Sstever@eecs.umich.edu        return super(cls, Current).__new__(cls, value)
16694762Snate@binkert.org
167012192Sgabeblack@google.com    def __init__(self, value):
167112192Sgabeblack@google.com        value = convert.toCurrent(value)
167212192Sgabeblack@google.com        super(Current, self).__init__(value)
167312195Sgabeblack@google.com
167412195Sgabeblack@google.comclass Energy(Float):
167512195Sgabeblack@google.com    ex_str = "1pJ"
167612196Sgabeblack@google.com
167712196Sgabeblack@google.com    def __new__(cls, value):
167812196Sgabeblack@google.com        value = convert.toEnergy(value)
167912196Sgabeblack@google.com        return super(cls, Energy).__new__(cls, value)
168012200Sgabeblack@google.com
168112200Sgabeblack@google.com    def __init__(self, value):
168212200Sgabeblack@google.com        value = convert.toEnergy(value)
16833102Sstever@eecs.umich.edu        super(Energy, self).__init__(value)
168412197Sgabeblack@google.com
16853102Sstever@eecs.umich.educlass NetworkBandwidth(float,ParamValue):
168610380SAndrew.Bardsley@arm.com    cxx_type = 'float'
168710380SAndrew.Bardsley@arm.com    ex_str = "1Gbps"
168810380SAndrew.Bardsley@arm.com    cmd_line_settable = True
16894762Snate@binkert.org
16904762Snate@binkert.org    def __new__(cls, value):
16914762Snate@binkert.org        # convert to bits per second
16923102Sstever@eecs.umich.edu        val = convert.toNetworkBandwidth(value)
16933102Sstever@eecs.umich.edu        return super(cls, NetworkBandwidth).__new__(cls, val)
16943102Sstever@eecs.umich.edu
16953102Sstever@eecs.umich.edu    def __str__(self):
16963102Sstever@eecs.umich.edu        return str(self.val)
16973102Sstever@eecs.umich.edu
16983101Sstever@eecs.umich.edu    def __call__(self, value):
16993101Sstever@eecs.umich.edu        val = convert.toNetworkBandwidth(value)
17003101Sstever@eecs.umich.edu        self.__init__(val)
17013101Sstever@eecs.umich.edu        return value
17023101Sstever@eecs.umich.edu
17033101Sstever@eecs.umich.edu    def getValue(self):
17043101Sstever@eecs.umich.edu        # convert to seconds per byte
17053101Sstever@eecs.umich.edu        value = 8.0 / float(self)
17063101Sstever@eecs.umich.edu        # convert to ticks per byte
17073101Sstever@eecs.umich.edu        value = ticks.fromSeconds(value)
17083101Sstever@eecs.umich.edu        return float(value)
17093101Sstever@eecs.umich.edu
17103101Sstever@eecs.umich.edu    def ini_str(self):
17113101Sstever@eecs.umich.edu        return '%f' % self.getValue()
17123101Sstever@eecs.umich.edu
17133101Sstever@eecs.umich.edu    def config_value(self):
17143101Sstever@eecs.umich.edu        return '%f' % self.getValue()
17158839Sandreas.hansson@arm.com
17163105Sstever@eecs.umich.edu    @classmethod
17173101Sstever@eecs.umich.edu    def cxx_ini_predecls(cls, code):
17183101Sstever@eecs.umich.edu        code('#include <sstream>')
17198839Sandreas.hansson@arm.com
17203101Sstever@eecs.umich.edu    @classmethod
17213101Sstever@eecs.umich.edu    def cxx_ini_parse(self, code, src, dest, ret):
17223105Sstever@eecs.umich.edu        code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
17233101Sstever@eecs.umich.edu
17243103Sstever@eecs.umich.educlass MemoryBandwidth(float,ParamValue):
17253105Sstever@eecs.umich.edu    cxx_type = 'float'
17263103Sstever@eecs.umich.edu    ex_str = "1GB/s"
17278840Sandreas.hansson@arm.com    cmd_line_settable = True
17288840Sandreas.hansson@arm.com
17298840Sandreas.hansson@arm.com    def __new__(cls, value):
17308840Sandreas.hansson@arm.com        # convert to bytes per second
17318840Sandreas.hansson@arm.com        val = convert.toMemoryBandwidth(value)
17323105Sstever@eecs.umich.edu        return super(cls, MemoryBandwidth).__new__(cls, val)
17333105Sstever@eecs.umich.edu
17343105Sstever@eecs.umich.edu    def __call__(self, value):
17353105Sstever@eecs.umich.edu        val = convert.toMemoryBandwidth(value)
17369017Sandreas.hansson@arm.com        self.__init__(val)
17379017Sandreas.hansson@arm.com        return value
17389017Sandreas.hansson@arm.com
17399017Sandreas.hansson@arm.com    def getValue(self):
17403105Sstever@eecs.umich.edu        # convert to seconds per byte
17413105Sstever@eecs.umich.edu        value = float(self)
17423105Sstever@eecs.umich.edu        if value:
17433105Sstever@eecs.umich.edu            value = 1.0 / float(self)
17443105Sstever@eecs.umich.edu        # convert to ticks per byte
17453105Sstever@eecs.umich.edu        value = ticks.fromSeconds(value)
17463105Sstever@eecs.umich.edu        return float(value)
17473105Sstever@eecs.umich.edu
17483105Sstever@eecs.umich.edu    def ini_str(self):
17493109Sstever@eecs.umich.edu        return '%f' % self.getValue()
17503105Sstever@eecs.umich.edu
17513105Sstever@eecs.umich.edu    def config_value(self):
17523105Sstever@eecs.umich.edu        return '%f' % self.getValue()
17533105Sstever@eecs.umich.edu
17543105Sstever@eecs.umich.edu    @classmethod
17553105Sstever@eecs.umich.edu    def cxx_ini_predecls(cls, code):
17569014Sandreas.hansson@arm.com        code('#include <sstream>')
17579014Sandreas.hansson@arm.com
17583101Sstever@eecs.umich.edu    @classmethod
17593109Sstever@eecs.umich.edu    def cxx_ini_parse(self, code, src, dest, ret):
17603109Sstever@eecs.umich.edu        code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
17613109Sstever@eecs.umich.edu
17623109Sstever@eecs.umich.edu#
17633109Sstever@eecs.umich.edu# "Constants"... handy aliases for various values.
17643109Sstever@eecs.umich.edu#
17653109Sstever@eecs.umich.edu
17663109Sstever@eecs.umich.edu# Special class for NULL pointers.  Note the special check in
17673109Sstever@eecs.umich.edu# make_param_value() above that lets these be assigned where a
17683101Sstever@eecs.umich.edu# SimObject is required.
176910355SGeoffrey.Blake@arm.com# only one copy of a particular node
177010355SGeoffrey.Blake@arm.comclass NullSimObject(object):
177110355SGeoffrey.Blake@arm.com    __metaclass__ = Singleton
177210355SGeoffrey.Blake@arm.com    _name = 'Null'
177310355SGeoffrey.Blake@arm.com
177410355SGeoffrey.Blake@arm.com    def __call__(cls):
177510355SGeoffrey.Blake@arm.com        return cls
177610355SGeoffrey.Blake@arm.com
177710355SGeoffrey.Blake@arm.com    def _instantiate(self, parent = None, path = ''):
177810355SGeoffrey.Blake@arm.com        pass
177910355SGeoffrey.Blake@arm.com
178010355SGeoffrey.Blake@arm.com    def ini_str(self):
178110355SGeoffrey.Blake@arm.com        return 'Null'
178210355SGeoffrey.Blake@arm.com
178310355SGeoffrey.Blake@arm.com    def unproxy(self, base):
178410355SGeoffrey.Blake@arm.com        return self
178510355SGeoffrey.Blake@arm.com
178610355SGeoffrey.Blake@arm.com    def set_path(self, parent, name):
178710355SGeoffrey.Blake@arm.com        pass
178810355SGeoffrey.Blake@arm.com
178910355SGeoffrey.Blake@arm.com    def set_parent(self, parent, name):
179010355SGeoffrey.Blake@arm.com        pass
179110355SGeoffrey.Blake@arm.com
179210355SGeoffrey.Blake@arm.com    def clear_parent(self, old_parent):
179310355SGeoffrey.Blake@arm.com        pass
179410355SGeoffrey.Blake@arm.com
179510355SGeoffrey.Blake@arm.com    def descendants(self):
179610355SGeoffrey.Blake@arm.com        return
179710355SGeoffrey.Blake@arm.com        yield None
179810355SGeoffrey.Blake@arm.com
17993105Sstever@eecs.umich.edu    def get_config_as_dict(self):
18003105Sstever@eecs.umich.edu        return {}
18013105Sstever@eecs.umich.edu
18023101Sstever@eecs.umich.edu    def __str__(self):
18033105Sstever@eecs.umich.edu        return self._name
18043105Sstever@eecs.umich.edu
18053101Sstever@eecs.umich.edu    def config_value(self):
18063105Sstever@eecs.umich.edu        return None
18073179Sstever@eecs.umich.edu
18083105Sstever@eecs.umich.edu    def getValue(self):
18093105Sstever@eecs.umich.edu        return None
18103101Sstever@eecs.umich.edu
18113101Sstever@eecs.umich.edu# The only instance you'll ever need...
18123105Sstever@eecs.umich.eduNULL = NullSimObject()
18133105Sstever@eecs.umich.edu
18143105Sstever@eecs.umich.edudef isNullPointer(value):
18153105Sstever@eecs.umich.edu    return isinstance(value, NullSimObject)
18163105Sstever@eecs.umich.edu
18173105Sstever@eecs.umich.edu# Some memory range specifications use this as a default upper bound.
18183105Sstever@eecs.umich.eduMaxAddr = Addr.max
18193105Sstever@eecs.umich.eduMaxTick = Tick.max
18203105Sstever@eecs.umich.eduAllMemory = AddrRange(0, MaxAddr)
18213105Sstever@eecs.umich.edu
18223105Sstever@eecs.umich.edu
18233101Sstever@eecs.umich.edu#####################################################################
18243101Sstever@eecs.umich.edu#
182511802Sandreas.sandberg@arm.com# Port objects
18264762Snate@binkert.org#
18278839Sandreas.hansson@arm.com# Ports are used to interconnect objects in the memory system.
18288839Sandreas.hansson@arm.com#
18298839Sandreas.hansson@arm.com#####################################################################
18308839Sandreas.hansson@arm.com
18313101Sstever@eecs.umich.edu# Port reference: encapsulates a reference to a particular port on a
18323101Sstever@eecs.umich.edu# particular SimObject.
18333101Sstever@eecs.umich.educlass PortRef(object):
18345578SSteve.Reinhardt@amd.com    def __init__(self, simobj, name, role):
18355578SSteve.Reinhardt@amd.com        assert(isSimObject(simobj) or isSimObjectClass(simobj))
18368839Sandreas.hansson@arm.com        self.simobj = simobj
18378839Sandreas.hansson@arm.com        self.name = name
18388839Sandreas.hansson@arm.com        self.role = role
18398839Sandreas.hansson@arm.com        self.peer = None   # not associated with another port yet
18408839Sandreas.hansson@arm.com        self.ccConnected = False # C++ port connection done?
18418839Sandreas.hansson@arm.com        self.index = -1  # always -1 for non-vector ports
18428839Sandreas.hansson@arm.com
18437526Ssteve.reinhardt@amd.com    def __str__(self):
18448839Sandreas.hansson@arm.com        return '%s.%s' % (self.simobj, self.name)
18457526Ssteve.reinhardt@amd.com
18467526Ssteve.reinhardt@amd.com    def __len__(self):
18477526Ssteve.reinhardt@amd.com        # Return the number of connected ports, i.e. 0 is we have no
18487526Ssteve.reinhardt@amd.com        # peer and 1 if we do.
18497526Ssteve.reinhardt@amd.com        return int(self.peer != None)
18507526Ssteve.reinhardt@amd.com
18517526Ssteve.reinhardt@amd.com    # for config.ini, print peer's name (not ours)
18523101Sstever@eecs.umich.edu    def ini_str(self):
18533101Sstever@eecs.umich.edu        return str(self.peer)
18543101Sstever@eecs.umich.edu
18553105Sstever@eecs.umich.edu    # for config.json
18563105Sstever@eecs.umich.edu    def get_config_as_dict(self):
18573105Sstever@eecs.umich.edu        return {'role' : self.role, 'peer' : str(self.peer)}
18588839Sandreas.hansson@arm.com
18598839Sandreas.hansson@arm.com    def __getattr__(self, attr):
18603105Sstever@eecs.umich.edu        if attr == 'peerObj':
18613105Sstever@eecs.umich.edu            # shorthand for proxies
18623105Sstever@eecs.umich.edu            return self.peer.simobj
18633105Sstever@eecs.umich.edu        raise AttributeError("'%s' object has no attribute '%s'" % \
18643105Sstever@eecs.umich.edu              (self.__class__.__name__, attr))
18653105Sstever@eecs.umich.edu
18663105Sstever@eecs.umich.edu    # Full connection is symmetric (both ways).  Called via
18673105Sstever@eecs.umich.edu    # SimObject.__setattr__ as a result of a port assignment, e.g.,
18688839Sandreas.hansson@arm.com    # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
18693105Sstever@eecs.umich.edu    # e.g., "obj1.portA[3] = obj2.portB".
18703105Sstever@eecs.umich.edu    def connect(self, other):
18713105Sstever@eecs.umich.edu        if isinstance(other, VectorPortRef):
18728839Sandreas.hansson@arm.com            # reference to plain VectorPort is implicit append
18733105Sstever@eecs.umich.edu            other = other._get_next()
18743105Sstever@eecs.umich.edu        if self.peer and not proxy.isproxy(self.peer):
18753109Sstever@eecs.umich.edu            fatal("Port %s is already connected to %s, cannot connect %s\n",
18763109Sstever@eecs.umich.edu                  self, self.peer, other);
18773109Sstever@eecs.umich.edu        self.peer = other
18788840Sandreas.hansson@arm.com        if proxy.isproxy(other):
18798840Sandreas.hansson@arm.com            other.set_param_desc(PortParamDesc())
18808840Sandreas.hansson@arm.com        elif isinstance(other, PortRef):
18818840Sandreas.hansson@arm.com            if other.peer is not self:
18828840Sandreas.hansson@arm.com                other.connect(self)
18833105Sstever@eecs.umich.edu        else:
18843105Sstever@eecs.umich.edu            raise TypeError("assigning non-port reference '%s' to port '%s'" \
18853105Sstever@eecs.umich.edu                  % (other, self))
18863105Sstever@eecs.umich.edu
18879017Sandreas.hansson@arm.com    # Allow a master/slave port pair to be spliced between
18889017Sandreas.hansson@arm.com    # a port and its connected peer. Useful operation for connecting
18899017Sandreas.hansson@arm.com    # instrumentation structures into a system when it is necessary
18909017Sandreas.hansson@arm.com    # to connect the instrumentation after the full system has been
18919017Sandreas.hansson@arm.com    # constructed.
18923105Sstever@eecs.umich.edu    def splice(self, new_master_peer, new_slave_peer):
18933105Sstever@eecs.umich.edu        if not self.peer or proxy.isproxy(self.peer):
18943105Sstever@eecs.umich.edu            fatal("Port %s not connected, cannot splice in new peers\n", self)
18953105Sstever@eecs.umich.edu
18963105Sstever@eecs.umich.edu        if not isinstance(new_master_peer, PortRef) or \
18978839Sandreas.hansson@arm.com           not isinstance(new_slave_peer, PortRef):
18983105Sstever@eecs.umich.edu            raise TypeError(
18993105Sstever@eecs.umich.edu                  "Splicing non-port references '%s','%s' to port '%s'" % \
19003105Sstever@eecs.umich.edu                  (new_master_peer, new_slave_peer, self))
19013105Sstever@eecs.umich.edu
19023105Sstever@eecs.umich.edu        old_peer = self.peer
19033105Sstever@eecs.umich.edu        if self.role == 'SLAVE':
19043105Sstever@eecs.umich.edu            self.peer = new_master_peer
19053105Sstever@eecs.umich.edu            old_peer.peer = new_slave_peer
19063105Sstever@eecs.umich.edu            new_master_peer.connect(self)
19073105Sstever@eecs.umich.edu            new_slave_peer.connect(old_peer)
19083105Sstever@eecs.umich.edu        elif self.role == 'MASTER':
19093105Sstever@eecs.umich.edu            self.peer = new_slave_peer
19103105Sstever@eecs.umich.edu            old_peer.peer = new_master_peer
19113109Sstever@eecs.umich.edu            new_slave_peer.connect(self)
19123109Sstever@eecs.umich.edu            new_master_peer.connect(old_peer)
19133109Sstever@eecs.umich.edu        else:
19143109Sstever@eecs.umich.edu            panic("Port %s has unknown role, "+\
19153109Sstever@eecs.umich.edu                  "cannot splice in new peers\n", self)
19163109Sstever@eecs.umich.edu
19173109Sstever@eecs.umich.edu    def clone(self, simobj, memo):
19183109Sstever@eecs.umich.edu        if self in memo:
19193109Sstever@eecs.umich.edu            return memo[self]
19203109Sstever@eecs.umich.edu        newRef = copy.copy(self)
19213109Sstever@eecs.umich.edu        memo[self] = newRef
19223109Sstever@eecs.umich.edu        newRef.simobj = simobj
19233109Sstever@eecs.umich.edu        assert(isSimObject(newRef.simobj))
19243109Sstever@eecs.umich.edu        if self.peer and not proxy.isproxy(self.peer):
19253109Sstever@eecs.umich.edu            peerObj = self.peer.simobj(_memo=memo)
19263109Sstever@eecs.umich.edu            newRef.peer = self.peer.clone(peerObj, memo)
19273109Sstever@eecs.umich.edu            assert(not isinstance(newRef.peer, VectorPortRef))
19283109Sstever@eecs.umich.edu        return newRef
19293109Sstever@eecs.umich.edu
19303105Sstever@eecs.umich.edu    def unproxy(self, simobj):
19313105Sstever@eecs.umich.edu        assert(simobj is self.simobj)
19323105Sstever@eecs.umich.edu        if proxy.isproxy(self.peer):
19333105Sstever@eecs.umich.edu            try:
19343105Sstever@eecs.umich.edu                realPeer = self.peer.unproxy(self.simobj)
19353105Sstever@eecs.umich.edu            except:
19363105Sstever@eecs.umich.edu                print("Error in unproxying port '%s' of %s" %
19373101Sstever@eecs.umich.edu                      (self.name, self.simobj.path()))
19383101Sstever@eecs.umich.edu                raise
19393101Sstever@eecs.umich.edu            self.connect(realPeer)
19403101Sstever@eecs.umich.edu
19413101Sstever@eecs.umich.edu    # Call C++ to create corresponding port connection between C++ objects
19423101Sstever@eecs.umich.edu    def ccConnect(self):
19433105Sstever@eecs.umich.edu        from _m5.pyobject import connectPorts
19448839Sandreas.hansson@arm.com
19453101Sstever@eecs.umich.edu        if self.ccConnected: # already done this
19463101Sstever@eecs.umich.edu            return
19473101Sstever@eecs.umich.edu
19483105Sstever@eecs.umich.edu        peer = self.peer
19493105Sstever@eecs.umich.edu        if not self.peer: # nothing to connect to
19503101Sstever@eecs.umich.edu            return
19518840Sandreas.hansson@arm.com
19528840Sandreas.hansson@arm.com        # check that we connect a master to a slave
19538840Sandreas.hansson@arm.com        if self.role == peer.role:
19548840Sandreas.hansson@arm.com            raise TypeError(
19558840Sandreas.hansson@arm.com                "cannot connect '%s' and '%s' due to identical role '%s'" % \
195611988Sandreas.sandberg@arm.com                (peer, self, self.role))
195711988Sandreas.sandberg@arm.com
195811988Sandreas.sandberg@arm.com        if self.role == 'SLAVE':
19598840Sandreas.hansson@arm.com            # do nothing and let the master take care of it
19608840Sandreas.hansson@arm.com            return
19618840Sandreas.hansson@arm.com
19628840Sandreas.hansson@arm.com        try:
19638840Sandreas.hansson@arm.com            # self is always the master and peer the slave
19648840Sandreas.hansson@arm.com            connectPorts(self.simobj.getCCObject(), self.name, self.index,
19658839Sandreas.hansson@arm.com                         peer.simobj.getCCObject(), peer.name, peer.index)
19668839Sandreas.hansson@arm.com        except:
19678839Sandreas.hansson@arm.com            print("Error connecting port %s.%s to %s.%s" %
19688839Sandreas.hansson@arm.com                  (self.simobj.path(), self.name,
19698839Sandreas.hansson@arm.com                   peer.simobj.path(), peer.name))
19708839Sandreas.hansson@arm.com            raise
19718839Sandreas.hansson@arm.com        self.ccConnected = True
19728839Sandreas.hansson@arm.com        peer.ccConnected = True
19738839Sandreas.hansson@arm.com
19748839Sandreas.hansson@arm.com# A reference to an individual element of a VectorPort... much like a
19758839Sandreas.hansson@arm.com# PortRef, but has an index.
19768839Sandreas.hansson@arm.comclass VectorPortElementRef(PortRef):
19778839Sandreas.hansson@arm.com    def __init__(self, simobj, name, role, index):
19788839Sandreas.hansson@arm.com        PortRef.__init__(self, simobj, name, role)
19798839Sandreas.hansson@arm.com        self.index = index
19808839Sandreas.hansson@arm.com
19818839Sandreas.hansson@arm.com    def __str__(self):
19828839Sandreas.hansson@arm.com        return '%s.%s[%d]' % (self.simobj, self.name, self.index)
19833101Sstever@eecs.umich.edu
198410405Sandreas.hansson@arm.com# A reference to a complete vector-valued port (not just a single element).
19853101Sstever@eecs.umich.edu# Can be indexed to retrieve individual VectorPortElementRef instances.
19863105Sstever@eecs.umich.educlass VectorPortRef(object):
19873101Sstever@eecs.umich.edu    def __init__(self, simobj, name, role):
19883101Sstever@eecs.umich.edu        assert(isSimObject(simobj) or isSimObjectClass(simobj))
19893105Sstever@eecs.umich.edu        self.simobj = simobj
19908839Sandreas.hansson@arm.com        self.name = name
19918839Sandreas.hansson@arm.com        self.role = role
19928839Sandreas.hansson@arm.com        self.elements = []
19938839Sandreas.hansson@arm.com
19948839Sandreas.hansson@arm.com    def __str__(self):
19958839Sandreas.hansson@arm.com        return '%s.%s[:]' % (self.simobj, self.name)
19968839Sandreas.hansson@arm.com
19978839Sandreas.hansson@arm.com    def __len__(self):
19988839Sandreas.hansson@arm.com        # Return the number of connected peers, corresponding the the
19998839Sandreas.hansson@arm.com        # length of the elements.
20008839Sandreas.hansson@arm.com        return len(self.elements)
20018839Sandreas.hansson@arm.com
20028839Sandreas.hansson@arm.com    # for config.ini, print peer's name (not ours)
20038839Sandreas.hansson@arm.com    def ini_str(self):
20048839Sandreas.hansson@arm.com        return ' '.join([el.ini_str() for el in self.elements])
20058839Sandreas.hansson@arm.com
20068839Sandreas.hansson@arm.com    # for config.json
20078839Sandreas.hansson@arm.com    def get_config_as_dict(self):
20088839Sandreas.hansson@arm.com        return {'role' : self.role,
20098839Sandreas.hansson@arm.com                'peer' : [el.ini_str() for el in self.elements]}
20108839Sandreas.hansson@arm.com
20113105Sstever@eecs.umich.edu    def __getitem__(self, key):
20123109Sstever@eecs.umich.edu        if not isinstance(key, int):
20133109Sstever@eecs.umich.edu            raise TypeError("VectorPort index must be integer")
20143109Sstever@eecs.umich.edu        if key >= len(self.elements):
20153109Sstever@eecs.umich.edu            # need to extend list
20163109Sstever@eecs.umich.edu            ext = [VectorPortElementRef(self.simobj, self.name, self.role, i)
20173109Sstever@eecs.umich.edu                   for i in range(len(self.elements), key+1)]
20183109Sstever@eecs.umich.edu            self.elements.extend(ext)
20193109Sstever@eecs.umich.edu        return self.elements[key]
20203105Sstever@eecs.umich.edu
20216654Snate@binkert.org    def _get_next(self):
20226654Snate@binkert.org        return self[len(self.elements)]
20236654Snate@binkert.org
20246654Snate@binkert.org    def __setitem__(self, key, value):
20256654Snate@binkert.org        if not isinstance(key, int):
20266654Snate@binkert.org            raise TypeError("VectorPort index must be integer")
20276654Snate@binkert.org        self[key].connect(value)
20286654Snate@binkert.org
20296654Snate@binkert.org    def connect(self, other):
20303101Sstever@eecs.umich.edu        if isinstance(other, (list, tuple)):
20313101Sstever@eecs.umich.edu            # Assign list of port refs to vector port.
20323101Sstever@eecs.umich.edu            # For now, append them... not sure if that's the right semantics
20333101Sstever@eecs.umich.edu            # or if it should replace the current vector.
20343101Sstever@eecs.umich.edu            for ref in other:
20353101Sstever@eecs.umich.edu                self._get_next().connect(ref)
20367777Sgblack@eecs.umich.edu        else:
20373101Sstever@eecs.umich.edu            # scalar assignment to plain VectorPort is implicit append
20389827Sakash.bagdia@arm.com            self._get_next().connect(other)
20393101Sstever@eecs.umich.edu
20409232Sandreas.hansson@arm.com    def clone(self, simobj, memo):
20413101Sstever@eecs.umich.edu        if self in memo:
20423885Sbinkertn@umich.edu            return memo[self]
20433102Sstever@eecs.umich.edu        newRef = copy.copy(self)
20448839Sandreas.hansson@arm.com        memo[self] = newRef
20458839Sandreas.hansson@arm.com        newRef.simobj = simobj
20466654Snate@binkert.org        assert(isSimObject(newRef.simobj))
20476654Snate@binkert.org        newRef.elements = [el.clone(simobj, memo) for el in self.elements]
2048        return newRef
2049
2050    def unproxy(self, simobj):
2051        [el.unproxy(simobj) for el in self.elements]
2052
2053    def ccConnect(self):
2054        [el.ccConnect() for el in self.elements]
2055
2056# Port description object.  Like a ParamDesc object, this represents a
2057# logical port in the SimObject class, not a particular port on a
2058# SimObject instance.  The latter are represented by PortRef objects.
2059class Port(object):
2060    # Generate a PortRef for this port on the given SimObject with the
2061    # given name
2062    def makeRef(self, simobj):
2063        return PortRef(simobj, self.name, self.role)
2064
2065    # Connect an instance of this port (on the given SimObject with
2066    # the given name) with the port described by the supplied PortRef
2067    def connect(self, simobj, ref):
2068        self.makeRef(simobj).connect(ref)
2069
2070    # No need for any pre-declarations at the moment as we merely rely
2071    # on an unsigned int.
2072    def cxx_predecls(self, code):
2073        pass
2074
2075    def pybind_predecls(self, code):
2076        cls.cxx_predecls(self, code)
2077
2078    # Declare an unsigned int with the same name as the port, that
2079    # will eventually hold the number of connected ports (and thus the
2080    # number of elements for a VectorPort).
2081    def cxx_decl(self, code):
2082        code('unsigned int port_${{self.name}}_connection_count;')
2083
2084class MasterPort(Port):
2085    # MasterPort("description")
2086    def __init__(self, *args):
2087        if len(args) == 1:
2088            self.desc = args[0]
2089            self.role = 'MASTER'
2090        else:
2091            raise TypeError('wrong number of arguments')
2092
2093class SlavePort(Port):
2094    # SlavePort("description")
2095    def __init__(self, *args):
2096        if len(args) == 1:
2097            self.desc = args[0]
2098            self.role = 'SLAVE'
2099        else:
2100            raise TypeError('wrong number of arguments')
2101
2102# VectorPort description object.  Like Port, but represents a vector
2103# of connections (e.g., as on a XBar).
2104class VectorPort(Port):
2105    def __init__(self, *args):
2106        self.isVec = True
2107
2108    def makeRef(self, simobj):
2109        return VectorPortRef(simobj, self.name, self.role)
2110
2111class VectorMasterPort(VectorPort):
2112    # VectorMasterPort("description")
2113    def __init__(self, *args):
2114        if len(args) == 1:
2115            self.desc = args[0]
2116            self.role = 'MASTER'
2117            VectorPort.__init__(self, *args)
2118        else:
2119            raise TypeError('wrong number of arguments')
2120
2121class VectorSlavePort(VectorPort):
2122    # VectorSlavePort("description")
2123    def __init__(self, *args):
2124        if len(args) == 1:
2125            self.desc = args[0]
2126            self.role = 'SLAVE'
2127            VectorPort.__init__(self, *args)
2128        else:
2129            raise TypeError('wrong number of arguments')
2130
2131# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
2132# proxy objects (via set_param_desc()) so that proxy error messages
2133# make sense.
2134class PortParamDesc(object):
2135    __metaclass__ = Singleton
2136
2137    ptype_str = 'Port'
2138    ptype = Port
2139
2140baseEnums = allEnums.copy()
2141baseParams = allParams.copy()
2142
2143def clear():
2144    global allEnums, allParams
2145
2146    allEnums = baseEnums.copy()
2147    allParams = baseParams.copy()
2148
2149__all__ = ['Param', 'VectorParam',
2150           'Enum', 'ScopedEnum', 'Bool', 'String', 'Float',
2151           'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
2152           'Int32', 'UInt32', 'Int64', 'UInt64',
2153           'Counter', 'Addr', 'Tick', 'Percent',
2154           'TcpPort', 'UdpPort', 'EthernetAddr',
2155           'IpAddress', 'IpNetmask', 'IpWithPort',
2156           'MemorySize', 'MemorySize32',
2157           'Latency', 'Frequency', 'Clock', 'Voltage', 'Current', 'Energy',
2158           'NetworkBandwidth', 'MemoryBandwidth',
2159           'AddrRange',
2160           'MaxAddr', 'MaxTick', 'AllMemory',
2161           'Time',
2162           'NextEthernetAddr', 'NULL',
2163           'MasterPort', 'SlavePort',
2164           'VectorMasterPort', 'VectorSlavePort']
2165