params.py revision 14052:8e23338327aa
13101Sstever@eecs.umich.edu# Copyright (c) 2012-2014, 2017-2019 ARM Limited
27534Ssteve.reinhardt@amd.com# All rights reserved.
33101Sstever@eecs.umich.edu#
43101Sstever@eecs.umich.edu# The license below extends only to copyright in the software and shall
53101Sstever@eecs.umich.edu# not be construed as granting a license to any other intellectual
63101Sstever@eecs.umich.edu# property including but not limited to intellectual property relating
73101Sstever@eecs.umich.edu# to a hardware implementation of the functionality of the software
83101Sstever@eecs.umich.edu# licensed hereunder.  You may use the software subject to the license
93101Sstever@eecs.umich.edu# terms below provided that you ensure that this notice is replicated
103101Sstever@eecs.umich.edu# unmodified and in its entirety in all distributions of the software,
113101Sstever@eecs.umich.edu# modified or unmodified, in source code or in binary form.
123101Sstever@eecs.umich.edu#
133101Sstever@eecs.umich.edu# Copyright (c) 2004-2006 The Regents of The University of Michigan
143101Sstever@eecs.umich.edu# Copyright (c) 2010-2011 Advanced Micro Devices, Inc.
153101Sstever@eecs.umich.edu# All rights reserved.
163101Sstever@eecs.umich.edu#
173101Sstever@eecs.umich.edu# Redistribution and use in source and binary forms, with or without
183101Sstever@eecs.umich.edu# modification, are permitted provided that the following conditions are
193101Sstever@eecs.umich.edu# met: redistributions of source code must retain the above copyright
203101Sstever@eecs.umich.edu# notice, this list of conditions and the following disclaimer;
213101Sstever@eecs.umich.edu# redistributions in binary form must reproduce the above copyright
223101Sstever@eecs.umich.edu# notice, this list of conditions and the following disclaimer in the
233101Sstever@eecs.umich.edu# documentation and/or other materials provided with the distribution;
243101Sstever@eecs.umich.edu# neither the name of the copyright holders nor the names of its
253101Sstever@eecs.umich.edu# contributors may be used to endorse or promote products derived from
263101Sstever@eecs.umich.edu# this software without specific prior written permission.
273101Sstever@eecs.umich.edu#
283101Sstever@eecs.umich.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
293101Sstever@eecs.umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
307778Sgblack@eecs.umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
313101Sstever@eecs.umich.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
323101Sstever@eecs.umich.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
333101Sstever@eecs.umich.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
343101Sstever@eecs.umich.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
353101Sstever@eecs.umich.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
363101Sstever@eecs.umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
373101Sstever@eecs.umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
383101Sstever@eecs.umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
393101Sstever@eecs.umich.edu#
403101Sstever@eecs.umich.edu# Authors: Steve Reinhardt
413101Sstever@eecs.umich.edu#          Nathan Binkert
423101Sstever@eecs.umich.edu#          Gabe Black
433101Sstever@eecs.umich.edu#          Andreas Hansson
443101Sstever@eecs.umich.edu
453101Sstever@eecs.umich.edu#####################################################################
463101Sstever@eecs.umich.edu#
473101Sstever@eecs.umich.edu# Parameter description classes
483101Sstever@eecs.umich.edu#
493885Sbinkertn@umich.edu# The _params dictionary in each class maps parameter names to either
503885Sbinkertn@umich.edu# a Param or a VectorParam object.  These objects contain the
514762Snate@binkert.org# parameter description string, the parameter type, and the default
523885Sbinkertn@umich.edu# value (if any).  The convert() method on these objects is used to
533885Sbinkertn@umich.edu# force whatever value is assigned to the parameter to the appropriate
547528Ssteve.reinhardt@amd.com# type.
553885Sbinkertn@umich.edu#
564380Sbinkertn@umich.edu# Note that the default values are loaded into the class's attribute
574167Sbinkertn@umich.edu# space when the parameter dictionary is initialized (in
583102Sstever@eecs.umich.edu# MetaSimObject._new_param()); after that point they aren't used.
593101Sstever@eecs.umich.edu#
604762Snate@binkert.org#####################################################################
614762Snate@binkert.org
624762Snate@binkert.orgfrom __future__ import print_function
634762Snate@binkert.orgimport six
644762Snate@binkert.orgif six.PY3:
654762Snate@binkert.org    long = int
664762Snate@binkert.org
674762Snate@binkert.orgimport copy
684762Snate@binkert.orgimport datetime
695033Smilesck@eecs.umich.eduimport re
705033Smilesck@eecs.umich.eduimport sys
715033Smilesck@eecs.umich.eduimport time
725033Smilesck@eecs.umich.eduimport math
735033Smilesck@eecs.umich.edu
745033Smilesck@eecs.umich.edufrom . import proxy
755033Smilesck@eecs.umich.edufrom . import ticks
765033Smilesck@eecs.umich.edufrom .util import *
775033Smilesck@eecs.umich.edu
785033Smilesck@eecs.umich.edudef isSimObject(*args, **kwargs):
793101Sstever@eecs.umich.edu    from . import SimObject
803101Sstever@eecs.umich.edu    return SimObject.isSimObject(*args, **kwargs)
813101Sstever@eecs.umich.edu
825033Smilesck@eecs.umich.edudef isSimObjectSequence(*args, **kwargs):
833101Sstever@eecs.umich.edu    from . import SimObject
847673Snate@binkert.org    return SimObject.isSimObjectSequence(*args, **kwargs)
857673Snate@binkert.org
867673Snate@binkert.orgdef isSimObjectClass(*args, **kwargs):
877673Snate@binkert.org    from . import SimObject
887673Snate@binkert.org    return SimObject.isSimObjectClass(*args, **kwargs)
897673Snate@binkert.org
907673Snate@binkert.orgallParams = {}
913101Sstever@eecs.umich.edu
923101Sstever@eecs.umich.educlass MetaParamValue(type):
933101Sstever@eecs.umich.edu    def __new__(mcls, name, bases, dct):
943101Sstever@eecs.umich.edu        cls = super(MetaParamValue, mcls).__new__(mcls, name, bases, dct)
953101Sstever@eecs.umich.edu        assert name not in allParams
963101Sstever@eecs.umich.edu        allParams[name] = cls
973101Sstever@eecs.umich.edu        return cls
983101Sstever@eecs.umich.edu
993101Sstever@eecs.umich.edu
1003101Sstever@eecs.umich.edu# Dummy base class to identify types that are legitimate for SimObject
1013101Sstever@eecs.umich.edu# parameters.
1023101Sstever@eecs.umich.educlass ParamValue(object):
1033101Sstever@eecs.umich.edu    __metaclass__ = MetaParamValue
1046656Snate@binkert.org    cmd_line_settable = False
1056656Snate@binkert.org
1063101Sstever@eecs.umich.edu    # Generate the code needed as a prerequisite for declaring a C++
1073101Sstever@eecs.umich.edu    # object of this type.  Typically generates one or more #include
1083101Sstever@eecs.umich.edu    # statements.  Used when declaring parameters of this type.
1093101Sstever@eecs.umich.edu    @classmethod
1103101Sstever@eecs.umich.edu    def cxx_predecls(cls, code):
1113101Sstever@eecs.umich.edu        pass
1123101Sstever@eecs.umich.edu
1133101Sstever@eecs.umich.edu    @classmethod
1143101Sstever@eecs.umich.edu    def pybind_predecls(cls, code):
1153101Sstever@eecs.umich.edu        cls.cxx_predecls(code)
1163101Sstever@eecs.umich.edu
1173101Sstever@eecs.umich.edu    # default for printing to .ini file is regular string conversion.
1183101Sstever@eecs.umich.edu    # will be overridden in some cases
1193101Sstever@eecs.umich.edu    def ini_str(self):
1203101Sstever@eecs.umich.edu        return str(self)
1213101Sstever@eecs.umich.edu
1223101Sstever@eecs.umich.edu    # default for printing to .json file is regular string conversion.
1233101Sstever@eecs.umich.edu    # will be overridden in some cases, mostly to use native Python
1243101Sstever@eecs.umich.edu    # types where there are similar JSON types
1253101Sstever@eecs.umich.edu    def config_value(self):
1263101Sstever@eecs.umich.edu        return str(self)
1273101Sstever@eecs.umich.edu
1283101Sstever@eecs.umich.edu    # Prerequisites for .ini parsing with cxx_ini_parse
1293101Sstever@eecs.umich.edu    @classmethod
1303101Sstever@eecs.umich.edu    def cxx_ini_predecls(cls, code):
1313101Sstever@eecs.umich.edu        pass
1323101Sstever@eecs.umich.edu
1333101Sstever@eecs.umich.edu    # parse a .ini file entry for this param from string expression
1343101Sstever@eecs.umich.edu    # src into lvalue dest (of the param's C++ type)
1353101Sstever@eecs.umich.edu    @classmethod
1363101Sstever@eecs.umich.edu    def cxx_ini_parse(cls, code, src, dest, ret):
1373101Sstever@eecs.umich.edu        code('// Unhandled param type: %s' % cls.__name__)
1383101Sstever@eecs.umich.edu        code('%s false;' % ret)
1395033Smilesck@eecs.umich.edu
1406656Snate@binkert.org    # allows us to blithely call unproxy() on things without checking
1415033Smilesck@eecs.umich.edu    # if they're really proxies or not
1425033Smilesck@eecs.umich.edu    def unproxy(self, base):
1435033Smilesck@eecs.umich.edu        return self
1443101Sstever@eecs.umich.edu
1453101Sstever@eecs.umich.edu    # Produce a human readable version of the stored value
1463101Sstever@eecs.umich.edu    def pretty_print(self, value):
1473101Sstever@eecs.umich.edu        return str(value)
1483101Sstever@eecs.umich.edu
1493101Sstever@eecs.umich.edu# Regular parameter description.
1503101Sstever@eecs.umich.educlass ParamDesc(object):
1513101Sstever@eecs.umich.edu    def __init__(self, ptype_str, ptype, *args, **kwargs):
1523101Sstever@eecs.umich.edu        self.ptype_str = ptype_str
1533101Sstever@eecs.umich.edu        # remember ptype only if it is provided
1543101Sstever@eecs.umich.edu        if ptype != None:
1553101Sstever@eecs.umich.edu            self.ptype = ptype
1563101Sstever@eecs.umich.edu
1573102Sstever@eecs.umich.edu        if args:
1583101Sstever@eecs.umich.edu            if len(args) == 1:
1593101Sstever@eecs.umich.edu                self.desc = args[0]
1603101Sstever@eecs.umich.edu            elif len(args) == 2:
1617673Snate@binkert.org                self.default = args[0]
1627673Snate@binkert.org                self.desc = args[1]
1633101Sstever@eecs.umich.edu            else:
1647673Snate@binkert.org                raise TypeError('too many arguments')
1657673Snate@binkert.org
1663101Sstever@eecs.umich.edu        if 'desc' in kwargs:
1677673Snate@binkert.org            assert(not hasattr(self, 'desc'))
1687673Snate@binkert.org            self.desc = kwargs['desc']
1693101Sstever@eecs.umich.edu            del kwargs['desc']
1703101Sstever@eecs.umich.edu
1713101Sstever@eecs.umich.edu        if 'default' in kwargs:
1723101Sstever@eecs.umich.edu            assert(not hasattr(self, 'default'))
1733101Sstever@eecs.umich.edu            self.default = kwargs['default']
1743101Sstever@eecs.umich.edu            del kwargs['default']
1755033Smilesck@eecs.umich.edu
1765475Snate@binkert.org        if kwargs:
1775475Snate@binkert.org            raise TypeError('extra unknown kwargs %s' % kwargs)
1785475Snate@binkert.org
1795475Snate@binkert.org        if not hasattr(self, 'desc'):
1803101Sstever@eecs.umich.edu            raise TypeError('desc attribute missing')
1813101Sstever@eecs.umich.edu
1823101Sstever@eecs.umich.edu    def __getattr__(self, attr):
1834762Snate@binkert.org        if attr == 'ptype':
1844762Snate@binkert.org            from . import SimObject
1854762Snate@binkert.org            ptype = SimObject.allClasses[self.ptype_str]
1863101Sstever@eecs.umich.edu            assert isSimObjectClass(ptype)
1873101Sstever@eecs.umich.edu            self.ptype = ptype
1883101Sstever@eecs.umich.edu            return ptype
1897528Ssteve.reinhardt@amd.com
1907528Ssteve.reinhardt@amd.com        raise AttributeError("'%s' object has no attribute '%s'" % \
1917528Ssteve.reinhardt@amd.com              (type(self).__name__, attr))
1927528Ssteve.reinhardt@amd.com
1937528Ssteve.reinhardt@amd.com    def example_str(self):
1947528Ssteve.reinhardt@amd.com        if hasattr(self.ptype, "ex_str"):
1953101Sstever@eecs.umich.edu            return self.ptype.ex_str
1967528Ssteve.reinhardt@amd.com        else:
1977528Ssteve.reinhardt@amd.com            return self.ptype_str
1987528Ssteve.reinhardt@amd.com
1997528Ssteve.reinhardt@amd.com    # Is the param available to be exposed on the command line
2007528Ssteve.reinhardt@amd.com    def isCmdLineSettable(self):
2017528Ssteve.reinhardt@amd.com        if hasattr(self.ptype, "cmd_line_settable"):
2027528Ssteve.reinhardt@amd.com            return self.ptype.cmd_line_settable
2037528Ssteve.reinhardt@amd.com        else:
2047528Ssteve.reinhardt@amd.com            return False
2057528Ssteve.reinhardt@amd.com
2067528Ssteve.reinhardt@amd.com    def convert(self, value):
2077528Ssteve.reinhardt@amd.com        if isinstance(value, proxy.BaseProxy):
2087528Ssteve.reinhardt@amd.com            value.set_param_desc(self)
2097528Ssteve.reinhardt@amd.com            return value
2107528Ssteve.reinhardt@amd.com        if 'ptype' not in self.__dict__ and isNullPointer(value):
2117528Ssteve.reinhardt@amd.com            # deferred evaluation of SimObject; continue to defer if
2127528Ssteve.reinhardt@amd.com            # we're just assigning a null pointer
2137528Ssteve.reinhardt@amd.com            return value
2147528Ssteve.reinhardt@amd.com        if isinstance(value, self.ptype):
2157528Ssteve.reinhardt@amd.com            return value
2167528Ssteve.reinhardt@amd.com        if isNullPointer(value) and isSimObjectClass(self.ptype):
2177528Ssteve.reinhardt@amd.com            return value
2187528Ssteve.reinhardt@amd.com        return self.ptype(value)
2197528Ssteve.reinhardt@amd.com
2207528Ssteve.reinhardt@amd.com    def pretty_print(self, value):
2217528Ssteve.reinhardt@amd.com        if isinstance(value, proxy.BaseProxy):
2227528Ssteve.reinhardt@amd.com           return str(value)
2237528Ssteve.reinhardt@amd.com        if isNullPointer(value):
2247528Ssteve.reinhardt@amd.com           return NULL
2253101Sstever@eecs.umich.edu        return self.ptype(value).pretty_print(value)
2263101Sstever@eecs.umich.edu
2276656Snate@binkert.org    def cxx_predecls(self, code):
2286656Snate@binkert.org        code('#include <cstddef>')
2293101Sstever@eecs.umich.edu        self.ptype.cxx_predecls(code)
2303101Sstever@eecs.umich.edu
2313101Sstever@eecs.umich.edu    def pybind_predecls(self, code):
2323101Sstever@eecs.umich.edu        self.ptype.pybind_predecls(code)
2333101Sstever@eecs.umich.edu
2343101Sstever@eecs.umich.edu    def cxx_decl(self, code):
2353101Sstever@eecs.umich.edu        code('${{self.ptype.cxx_type}} ${{self.name}};')
2364762Snate@binkert.org
2374762Snate@binkert.org# Vector-valued parameter description.  Just like ParamDesc, except
2384762Snate@binkert.org# that the value is a vector (list) of the specified type instead of a
2394762Snate@binkert.org# single value.
2407528Ssteve.reinhardt@amd.com
2414762Snate@binkert.orgclass VectorParamValue(list):
2424762Snate@binkert.org    __metaclass__ = MetaParamValue
2434762Snate@binkert.org    def __setattr__(self, attr, value):
2447673Snate@binkert.org        raise AttributeError("Not allowed to set %s on '%s'" % \
2457677Snate@binkert.org                             (attr, type(self).__name__))
2464762Snate@binkert.org
2477673Snate@binkert.org    def config_value(self):
2487675Snate@binkert.org        return [v.config_value() for v in self]
2497675Snate@binkert.org
2507675Snate@binkert.org    def ini_str(self):
2517675Snate@binkert.org        return ' '.join([v.ini_str() for v in self])
2527675Snate@binkert.org
2537675Snate@binkert.org    def getValue(self):
2547673Snate@binkert.org        return [ v.getValue() for v in self ]
2557675Snate@binkert.org
2567675Snate@binkert.org    def unproxy(self, base):
2577675Snate@binkert.org        if len(self) == 1 and isinstance(self[0], proxy.BaseProxy):
2587675Snate@binkert.org            # The value is a proxy (e.g. Parent.any, Parent.all or
2597675Snate@binkert.org            # Parent.x) therefore try resolve it
2607673Snate@binkert.org            return self[0].unproxy(base)
2617675Snate@binkert.org        else:
2627675Snate@binkert.org            return [v.unproxy(base) for v in self]
2637675Snate@binkert.org
2647675Snate@binkert.orgclass SimObjectVector(VectorParamValue):
2657675Snate@binkert.org    # support clone operation
2667675Snate@binkert.org    def __call__(self, **kwargs):
2677675Snate@binkert.org        return SimObjectVector([v(**kwargs) for v in self])
2687675Snate@binkert.org
2697675Snate@binkert.org    def clear_parent(self, old_parent):
2707675Snate@binkert.org        for v in self:
2717675Snate@binkert.org            v.clear_parent(old_parent)
2727675Snate@binkert.org
2737675Snate@binkert.org    def set_parent(self, parent, name):
2747675Snate@binkert.org        if len(self) == 1:
2757675Snate@binkert.org            self[0].set_parent(parent, name)
2767675Snate@binkert.org        else:
2777673Snate@binkert.org            width = int(math.ceil(math.log(len(self))/math.log(10)))
2787673Snate@binkert.org            for i,v in enumerate(self):
2793101Sstever@eecs.umich.edu                v.set_parent(parent, "%s%0*d" % (name, width, i))
2807675Snate@binkert.org
2817675Snate@binkert.org    def has_parent(self):
2827673Snate@binkert.org        return any([e.has_parent() for e in self if not isNullPointer(e)])
2837673Snate@binkert.org
2847673Snate@binkert.org    # return 'cpu0 cpu1' etc. for print_ini()
2853101Sstever@eecs.umich.edu    def get_name(self):
2867673Snate@binkert.org        return ' '.join([v._name for v in self])
2877673Snate@binkert.org
2883101Sstever@eecs.umich.edu    # By iterating through the constituent members of the vector here
2893101Sstever@eecs.umich.edu    # we can nicely handle iterating over all a SimObject's children
2903101Sstever@eecs.umich.edu    # without having to provide lots of special functions on
2913101Sstever@eecs.umich.edu    # SimObjectVector directly.
2923101Sstever@eecs.umich.edu    def descendants(self):
2933101Sstever@eecs.umich.edu        for v in self:
2943101Sstever@eecs.umich.edu            for obj in v.descendants():
2953101Sstever@eecs.umich.edu                yield obj
2963101Sstever@eecs.umich.edu
2973101Sstever@eecs.umich.edu    def get_config_as_dict(self):
2983101Sstever@eecs.umich.edu        a = []
2993101Sstever@eecs.umich.edu        for v in self:
3003101Sstever@eecs.umich.edu            a.append(v.get_config_as_dict())
3013101Sstever@eecs.umich.edu        return a
3023101Sstever@eecs.umich.edu
3035033Smilesck@eecs.umich.edu    # If we are replacing an item in the vector, make sure to set the
3045033Smilesck@eecs.umich.edu    # parent reference of the new SimObject to be the same as the parent
3053101Sstever@eecs.umich.edu    # of the SimObject being replaced. Useful to have if we created
3063101Sstever@eecs.umich.edu    # a SimObjectVector of temporary objects that will be modified later in
3073101Sstever@eecs.umich.edu    # configuration scripts.
3083101Sstever@eecs.umich.edu    def __setitem__(self, key, value):
3093101Sstever@eecs.umich.edu        val = self[key]
3103101Sstever@eecs.umich.edu        if value.has_parent():
3113101Sstever@eecs.umich.edu            warn("SimObject %s already has a parent" % value.get_name() +\
3123101Sstever@eecs.umich.edu                 " that is being overwritten by a SimObjectVector")
3133101Sstever@eecs.umich.edu        value.set_parent(val.get_parent(), val._name)
3143101Sstever@eecs.umich.edu        super(SimObjectVector, self).__setitem__(key, value)
3153101Sstever@eecs.umich.edu
3163101Sstever@eecs.umich.edu    # Enumerate the params of each member of the SimObject vector. Creates
3173101Sstever@eecs.umich.edu    # strings that will allow indexing into the vector by the python code and
3183101Sstever@eecs.umich.edu    # allow it to be specified on the command line.
3193101Sstever@eecs.umich.edu    def enumerateParams(self, flags_dict = {},
3203101Sstever@eecs.umich.edu                        cmd_line_str = "",
3213101Sstever@eecs.umich.edu                        access_str = ""):
3223101Sstever@eecs.umich.edu        if hasattr(self, "_paramEnumed"):
3233101Sstever@eecs.umich.edu            print("Cycle detected enumerating params at %s?!" % (cmd_line_str))
3243101Sstever@eecs.umich.edu        else:
3253101Sstever@eecs.umich.edu            x = 0
3263101Sstever@eecs.umich.edu            for vals in self:
3273101Sstever@eecs.umich.edu                # Each entry in the SimObjectVector should be an
3283101Sstever@eecs.umich.edu                # instance of a SimObject
3293101Sstever@eecs.umich.edu                flags_dict = vals.enumerateParams(flags_dict,
3307673Snate@binkert.org                                                  cmd_line_str + "%d." % x,
3317673Snate@binkert.org                                                  access_str + "[%d]." % x)
3327673Snate@binkert.org                x = x + 1
3337673Snate@binkert.org
3347673Snate@binkert.org        return flags_dict
3357673Snate@binkert.org
3367673Snate@binkert.orgclass VectorParamDesc(ParamDesc):
3377673Snate@binkert.org    # Convert assigned value to appropriate type.  If the RHS is not a
3384762Snate@binkert.org    # list or tuple, it generates a single-element list.
3394762Snate@binkert.org    def convert(self, value):
3404762Snate@binkert.org        if isinstance(value, (list, tuple)):
3413101Sstever@eecs.umich.edu            # list: coerce each element into new list
3423101Sstever@eecs.umich.edu            tmp_list = [ ParamDesc.convert(self, v) for v in value ]
3433101Sstever@eecs.umich.edu        elif isinstance(value, str):
3443101Sstever@eecs.umich.edu            # If input is a csv string
3453101Sstever@eecs.umich.edu            tmp_list = [ ParamDesc.convert(self, v) \
3463101Sstever@eecs.umich.edu                         for v in value.strip('[').strip(']').split(',') ]
3473101Sstever@eecs.umich.edu        else:
3483101Sstever@eecs.umich.edu            # singleton: coerce to a single-element list
3493101Sstever@eecs.umich.edu            tmp_list = [ ParamDesc.convert(self, value) ]
3503101Sstever@eecs.umich.edu
3513101Sstever@eecs.umich.edu        if isSimObjectSequence(tmp_list):
3523714Sstever@eecs.umich.edu            return SimObjectVector(tmp_list)
3533714Sstever@eecs.umich.edu        else:
3543714Sstever@eecs.umich.edu            return VectorParamValue(tmp_list)
3553714Sstever@eecs.umich.edu
3563714Sstever@eecs.umich.edu    # Produce a human readable example string that describes
3573714Sstever@eecs.umich.edu    # how to set this vector parameter in the absence of a default
3583101Sstever@eecs.umich.edu    # value.
3593101Sstever@eecs.umich.edu    def example_str(self):
3603101Sstever@eecs.umich.edu        s = super(VectorParamDesc, self).example_str()
3613101Sstever@eecs.umich.edu        help_str = "[" + s + "," + s + ", ...]"
3623101Sstever@eecs.umich.edu        return help_str
3633101Sstever@eecs.umich.edu
3643101Sstever@eecs.umich.edu    # Produce a human readable representation of the value of this vector param.
3653101Sstever@eecs.umich.edu    def pretty_print(self, value):
3663101Sstever@eecs.umich.edu        if isinstance(value, (list, tuple)):
3673101Sstever@eecs.umich.edu            tmp_list = [ ParamDesc.pretty_print(self, v) for v in value ]
3683101Sstever@eecs.umich.edu        elif isinstance(value, str):
3693101Sstever@eecs.umich.edu            tmp_list = [ ParamDesc.pretty_print(self, v) for v in value.split(',') ]
3703101Sstever@eecs.umich.edu        else:
3713101Sstever@eecs.umich.edu            tmp_list = [ ParamDesc.pretty_print(self, value) ]
3723101Sstever@eecs.umich.edu
3733101Sstever@eecs.umich.edu        return tmp_list
3743101Sstever@eecs.umich.edu
3753101Sstever@eecs.umich.edu    # This is a helper function for the new config system
3763101Sstever@eecs.umich.edu    def __call__(self, value):
3773101Sstever@eecs.umich.edu        if isinstance(value, (list, tuple)):
3783101Sstever@eecs.umich.edu            # list: coerce each element into new list
3793101Sstever@eecs.umich.edu            tmp_list = [ ParamDesc.convert(self, v) for v in value ]
3803101Sstever@eecs.umich.edu        elif isinstance(value, str):
3813101Sstever@eecs.umich.edu            # If input is a csv string
3823101Sstever@eecs.umich.edu            tmp_list = [ ParamDesc.convert(self, v) \
3835033Smilesck@eecs.umich.edu                         for v in value.strip('[').strip(']').split(',') ]
3843101Sstever@eecs.umich.edu        else:
3853101Sstever@eecs.umich.edu            # singleton: coerce to a single-element list
3863101Sstever@eecs.umich.edu            tmp_list = [ ParamDesc.convert(self, value) ]
3873101Sstever@eecs.umich.edu
3883101Sstever@eecs.umich.edu        return VectorParamValue(tmp_list)
3893101Sstever@eecs.umich.edu
3903101Sstever@eecs.umich.edu    def cxx_predecls(self, code):
3913101Sstever@eecs.umich.edu        code('#include <vector>')
3923101Sstever@eecs.umich.edu        self.ptype.cxx_predecls(code)
3933101Sstever@eecs.umich.edu
3943101Sstever@eecs.umich.edu    def pybind_predecls(self, code):
3953101Sstever@eecs.umich.edu        code('#include <vector>')
3965822Ssaidi@eecs.umich.edu        self.ptype.pybind_predecls(code)
3975822Ssaidi@eecs.umich.edu
3983101Sstever@eecs.umich.edu    def cxx_decl(self, code):
3993101Sstever@eecs.umich.edu        code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};')
4003101Sstever@eecs.umich.edu
4013101Sstever@eecs.umich.educlass ParamFactory(object):
4023101Sstever@eecs.umich.edu    def __init__(self, param_desc_class, ptype_str = None):
4033101Sstever@eecs.umich.edu        self.param_desc_class = param_desc_class
4043101Sstever@eecs.umich.edu        self.ptype_str = ptype_str
4053101Sstever@eecs.umich.edu
4063101Sstever@eecs.umich.edu    def __getattr__(self, attr):
4073101Sstever@eecs.umich.edu        if self.ptype_str:
4083101Sstever@eecs.umich.edu            attr = self.ptype_str + '.' + attr
4093101Sstever@eecs.umich.edu        return ParamFactory(self.param_desc_class, attr)
4103101Sstever@eecs.umich.edu
4113101Sstever@eecs.umich.edu    # E.g., Param.Int(5, "number of widgets")
4123101Sstever@eecs.umich.edu    def __call__(self, *args, **kwargs):
4133101Sstever@eecs.umich.edu        ptype = None
4143101Sstever@eecs.umich.edu        try:
4153101Sstever@eecs.umich.edu            ptype = allParams[self.ptype_str]
4163101Sstever@eecs.umich.edu        except KeyError:
4173101Sstever@eecs.umich.edu            # if name isn't defined yet, assume it's a SimObject, and
4183101Sstever@eecs.umich.edu            # try to resolve it later
4193102Sstever@eecs.umich.edu            pass
4203714Sstever@eecs.umich.edu        return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs)
4213101Sstever@eecs.umich.edu
4223714Sstever@eecs.umich.eduParam = ParamFactory(ParamDesc)
4233714Sstever@eecs.umich.eduVectorParam = ParamFactory(VectorParamDesc)
4243714Sstever@eecs.umich.edu
4253101Sstever@eecs.umich.edu#####################################################################
4263101Sstever@eecs.umich.edu#
4277673Snate@binkert.org# Parameter Types
4287673Snate@binkert.org#
4297673Snate@binkert.org# Though native Python types could be used to specify parameter types
4307673Snate@binkert.org# (the 'ptype' field of the Param and VectorParam classes), it's more
4317673Snate@binkert.org# flexible to define our own set of types.  This gives us more control
4327673Snate@binkert.org# over how Python expressions are converted to values (via the
4337673Snate@binkert.org# __init__() constructor) and how these values are printed out (via
4347673Snate@binkert.org# the __str__() conversion method).
4357673Snate@binkert.org#
4367673Snate@binkert.org#####################################################################
4377673Snate@binkert.org
4384762Snate@binkert.org# String-valued parameter.  Just mixin the ParamValue class with the
4394762Snate@binkert.org# built-in str class.
4404762Snate@binkert.orgclass String(ParamValue,str):
4413101Sstever@eecs.umich.edu    cxx_type = 'std::string'
4423101Sstever@eecs.umich.edu    cmd_line_settable = True
4433101Sstever@eecs.umich.edu
4443101Sstever@eecs.umich.edu    @classmethod
4453101Sstever@eecs.umich.edu    def cxx_predecls(self, code):
4463101Sstever@eecs.umich.edu        code('#include <string>')
4473101Sstever@eecs.umich.edu
4483101Sstever@eecs.umich.edu    def __call__(self, value):
4493101Sstever@eecs.umich.edu        self = value
4503101Sstever@eecs.umich.edu        return value
4513101Sstever@eecs.umich.edu
4523101Sstever@eecs.umich.edu    @classmethod
4533101Sstever@eecs.umich.edu    def cxx_ini_parse(self, code, src, dest, ret):
4543101Sstever@eecs.umich.edu        code('%s = %s;' % (dest, src))
4553101Sstever@eecs.umich.edu        code('%s true;' % ret)
4563101Sstever@eecs.umich.edu
4573101Sstever@eecs.umich.edu    def getValue(self):
4583101Sstever@eecs.umich.edu        return self
4593101Sstever@eecs.umich.edu
4603101Sstever@eecs.umich.edu# superclass for "numeric" parameter values, to emulate math
4614446Sbinkertn@umich.edu# operations in a type-safe way.  e.g., a Latency times an int returns
4623101Sstever@eecs.umich.edu# a new Latency object.
4635468Snate@binkert.orgclass NumericParamValue(ParamValue):
4645468Snate@binkert.org    @staticmethod
4655468Snate@binkert.org    def unwrap(v):
4665468Snate@binkert.org        return v.value if isinstance(v, NumericParamValue) else v
4675468Snate@binkert.org
4685468Snate@binkert.org    def __str__(self):
4695468Snate@binkert.org        return str(self.value)
4704762Snate@binkert.org
4714762Snate@binkert.org    def __float__(self):
4724762Snate@binkert.org        return float(self.value)
4733101Sstever@eecs.umich.edu
4743101Sstever@eecs.umich.edu    def __long__(self):
4753101Sstever@eecs.umich.edu        return long(self.value)
4763101Sstever@eecs.umich.edu
4773101Sstever@eecs.umich.edu    def __int__(self):
4783101Sstever@eecs.umich.edu        return int(self.value)
4793101Sstever@eecs.umich.edu
4803101Sstever@eecs.umich.edu    # hook for bounds checking
4813102Sstever@eecs.umich.edu    def _check(self):
4823101Sstever@eecs.umich.edu        return
4833101Sstever@eecs.umich.edu
4843101Sstever@eecs.umich.edu    def __mul__(self, other):
4854168Sbinkertn@umich.edu        newobj = self.__class__(self)
4863101Sstever@eecs.umich.edu        newobj.value *= NumericParamValue.unwrap(other)
4873101Sstever@eecs.umich.edu        newobj._check()
4883101Sstever@eecs.umich.edu        return newobj
4893101Sstever@eecs.umich.edu
4903101Sstever@eecs.umich.edu    __rmul__ = __mul__
4913101Sstever@eecs.umich.edu
4923102Sstever@eecs.umich.edu    def __truediv__(self, other):
4933101Sstever@eecs.umich.edu        newobj = self.__class__(self)
4943101Sstever@eecs.umich.edu        newobj.value /= NumericParamValue.unwrap(other)
4953101Sstever@eecs.umich.edu        newobj._check()
4963101Sstever@eecs.umich.edu        return newobj
4973101Sstever@eecs.umich.edu
4983101Sstever@eecs.umich.edu    def __floordiv__(self, other):
4993101Sstever@eecs.umich.edu        newobj = self.__class__(self)
5003101Sstever@eecs.umich.edu        newobj.value //= NumericParamValue.unwrap(other)
5013101Sstever@eecs.umich.edu        newobj._check()
5023101Sstever@eecs.umich.edu        return newobj
5033101Sstever@eecs.umich.edu
5043102Sstever@eecs.umich.edu
5053101Sstever@eecs.umich.edu    def __add__(self, other):
5063101Sstever@eecs.umich.edu        newobj = self.__class__(self)
5073101Sstever@eecs.umich.edu        newobj.value += NumericParamValue.unwrap(other)
5083584Ssaidi@eecs.umich.edu        newobj._check()
5093584Ssaidi@eecs.umich.edu        return newobj
5103584Ssaidi@eecs.umich.edu
5113584Ssaidi@eecs.umich.edu    def __sub__(self, other):
5123584Ssaidi@eecs.umich.edu        newobj = self.__class__(self)
5133101Sstever@eecs.umich.edu        newobj.value -= NumericParamValue.unwrap(other)
5143101Sstever@eecs.umich.edu        newobj._check()
5155033Smilesck@eecs.umich.edu        return newobj
5163101Sstever@eecs.umich.edu
5173101Sstever@eecs.umich.edu    def __iadd__(self, other):
5183101Sstever@eecs.umich.edu        self.value += NumericParamValue.unwrap(other)
5193101Sstever@eecs.umich.edu        self._check()
5203101Sstever@eecs.umich.edu        return self
5213101Sstever@eecs.umich.edu
5223101Sstever@eecs.umich.edu    def __isub__(self, other):
5233101Sstever@eecs.umich.edu        self.value -= NumericParamValue.unwrap(other)
5243101Sstever@eecs.umich.edu        self._check()
5253101Sstever@eecs.umich.edu        return self
5263101Sstever@eecs.umich.edu
5273101Sstever@eecs.umich.edu    def __imul__(self, other):
5283101Sstever@eecs.umich.edu        self.value *= NumericParamValue.unwrap(other)
5293101Sstever@eecs.umich.edu        self._check()
5303101Sstever@eecs.umich.edu        return self
5313101Sstever@eecs.umich.edu
5323101Sstever@eecs.umich.edu    def __itruediv__(self, other):
5333101Sstever@eecs.umich.edu        self.value /= NumericParamValue.unwrap(other)
5343101Sstever@eecs.umich.edu        self._check()
5353101Sstever@eecs.umich.edu        return self
5363101Sstever@eecs.umich.edu
5373101Sstever@eecs.umich.edu    def __ifloordiv__(self, other):
5383101Sstever@eecs.umich.edu        self.value //= NumericParamValue.unwrap(other)
5393101Sstever@eecs.umich.edu        self._check()
5403101Sstever@eecs.umich.edu        return self
5413101Sstever@eecs.umich.edu
5423101Sstever@eecs.umich.edu    def __lt__(self, other):
5433101Sstever@eecs.umich.edu        return self.value < NumericParamValue.unwrap(other)
5443101Sstever@eecs.umich.edu
5455219Ssaidi@eecs.umich.edu    # Python 2.7 pre __future__.division operators
5465219Ssaidi@eecs.umich.edu    # TODO: Remove these when after "import division from __future__"
5475219Ssaidi@eecs.umich.edu    __div__ =  __truediv__
5483101Sstever@eecs.umich.edu    __idiv__ = __itruediv__
5493101Sstever@eecs.umich.edu
5503101Sstever@eecs.umich.edu    def config_value(self):
5513101Sstever@eecs.umich.edu        return self.value
5523101Sstever@eecs.umich.edu
5533101Sstever@eecs.umich.edu    @classmethod
5543101Sstever@eecs.umich.edu    def cxx_ini_predecls(cls, code):
5553101Sstever@eecs.umich.edu        # Assume that base/str.hh will be included anyway
5563101Sstever@eecs.umich.edu        # code('#include "base/str.hh"')
5573101Sstever@eecs.umich.edu        pass
5583101Sstever@eecs.umich.edu
5593101Sstever@eecs.umich.edu    # The default for parsing PODs from an .ini entry is to extract from an
5603101Sstever@eecs.umich.edu    # istringstream and let overloading choose the right type according to
5613101Sstever@eecs.umich.edu    # the dest type.
5623101Sstever@eecs.umich.edu    @classmethod
5633101Sstever@eecs.umich.edu    def cxx_ini_parse(self, code, src, dest, ret):
5647673Snate@binkert.org        code('%s to_number(%s, %s);' % (ret, src, dest))
5657673Snate@binkert.org
5667675Snate@binkert.org# Metaclass for bounds-checked integer parameters.  See CheckedInt.
5677673Snate@binkert.orgclass CheckedIntType(MetaParamValue):
5687675Snate@binkert.org    def __init__(cls, name, bases, dict):
5697675Snate@binkert.org        super(CheckedIntType, cls).__init__(name, bases, dict)
5707675Snate@binkert.org
5717675Snate@binkert.org        # CheckedInt is an abstract base class, so we actually don't
5727675Snate@binkert.org        # want to do any processing on it... the rest of this code is
5737673Snate@binkert.org        # just for classes that derive from CheckedInt.
5743101Sstever@eecs.umich.edu        if name == 'CheckedInt':
5753101Sstever@eecs.umich.edu            return
5767673Snate@binkert.org
5774762Snate@binkert.org        if not (hasattr(cls, 'min') and hasattr(cls, 'max')):
5787675Snate@binkert.org            if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')):
5794762Snate@binkert.org                panic("CheckedInt subclass %s must define either\n" \
5804762Snate@binkert.org                      "    'min' and 'max' or 'size' and 'unsigned'\n",
5814762Snate@binkert.org                      name);
5824762Snate@binkert.org            if cls.unsigned:
5834762Snate@binkert.org                cls.min = 0
5843101Sstever@eecs.umich.edu                cls.max = 2 ** cls.size - 1
5853101Sstever@eecs.umich.edu            else:
5863101Sstever@eecs.umich.edu                cls.min = -(2 ** (cls.size - 1))
5877673Snate@binkert.org                cls.max = (2 ** (cls.size - 1)) - 1
5884762Snate@binkert.org
5897675Snate@binkert.org# Abstract superclass for bounds-checked integer parameters.  This
5904762Snate@binkert.org# class is subclassed to generate parameter classes with specific
5914762Snate@binkert.org# bounds.  Initialization of the min and max bounds is done in the
5924762Snate@binkert.org# metaclass CheckedIntType.__init__.
5934762Snate@binkert.orgclass CheckedInt(NumericParamValue):
5944762Snate@binkert.org    __metaclass__ = CheckedIntType
5953101Sstever@eecs.umich.edu    cmd_line_settable = True
5963101Sstever@eecs.umich.edu
5973101Sstever@eecs.umich.edu    def _check(self):
5983101Sstever@eecs.umich.edu        if not self.min <= self.value <= self.max:
5993101Sstever@eecs.umich.edu            raise TypeError('Integer param out of bounds %d < %d < %d' % \
6003101Sstever@eecs.umich.edu                  (self.min, self.value, self.max))
6013101Sstever@eecs.umich.edu
6023101Sstever@eecs.umich.edu    def __init__(self, value):
6033102Sstever@eecs.umich.edu        if isinstance(value, str):
6043101Sstever@eecs.umich.edu            self.value = convert.toInteger(value)
6053101Sstever@eecs.umich.edu        elif isinstance(value, (int, long, float, NumericParamValue)):
6063101Sstever@eecs.umich.edu            self.value = long(value)
6074762Snate@binkert.org        else:
6084762Snate@binkert.org            raise TypeError("Can't convert object of type %s to CheckedInt" \
6094762Snate@binkert.org                  % type(value).__name__)
6103101Sstever@eecs.umich.edu        self._check()
6113101Sstever@eecs.umich.edu
6123101Sstever@eecs.umich.edu    def __call__(self, value):
6133101Sstever@eecs.umich.edu        self.__init__(value)
6143101Sstever@eecs.umich.edu        return value
6153101Sstever@eecs.umich.edu
6163101Sstever@eecs.umich.edu    def __index__(self):
6173101Sstever@eecs.umich.edu        return int(self.value)
6183101Sstever@eecs.umich.edu
6193101Sstever@eecs.umich.edu    @classmethod
6203101Sstever@eecs.umich.edu    def cxx_predecls(cls, code):
6213101Sstever@eecs.umich.edu        # most derived types require this, so we just do it here once
6223101Sstever@eecs.umich.edu        code('#include "base/types.hh"')
6233101Sstever@eecs.umich.edu
6243101Sstever@eecs.umich.edu    def getValue(self):
6253101Sstever@eecs.umich.edu        return long(self.value)
6263101Sstever@eecs.umich.edu
6273101Sstever@eecs.umich.educlass Int(CheckedInt):      cxx_type = 'int';      size = 32; unsigned = False
6283101Sstever@eecs.umich.educlass Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True
6293101Sstever@eecs.umich.edu
6304380Sbinkertn@umich.educlass Int8(CheckedInt):     cxx_type =   'int8_t'; size =  8; unsigned = False
6314380Sbinkertn@umich.educlass UInt8(CheckedInt):    cxx_type =  'uint8_t'; size =  8; unsigned = True
6324380Sbinkertn@umich.educlass Int16(CheckedInt):    cxx_type =  'int16_t'; size = 16; unsigned = False
6333101Sstever@eecs.umich.educlass UInt16(CheckedInt):   cxx_type = 'uint16_t'; size = 16; unsigned = True
6344380Sbinkertn@umich.educlass Int32(CheckedInt):    cxx_type =  'int32_t'; size = 32; unsigned = False
6354380Sbinkertn@umich.educlass UInt32(CheckedInt):   cxx_type = 'uint32_t'; size = 32; unsigned = True
6364380Sbinkertn@umich.educlass Int64(CheckedInt):    cxx_type =  'int64_t'; size = 64; unsigned = False
6373101Sstever@eecs.umich.educlass UInt64(CheckedInt):   cxx_type = 'uint64_t'; size = 64; unsigned = True
6383101Sstever@eecs.umich.edu
6393101Sstever@eecs.umich.educlass Counter(CheckedInt):  cxx_type = 'Counter';  size = 64; unsigned = True
6407673Snate@binkert.orgclass Tick(CheckedInt):     cxx_type = 'Tick';     size = 64; unsigned = True
6417673Snate@binkert.orgclass TcpPort(CheckedInt):  cxx_type = 'uint16_t'; size = 16; unsigned = True
6427673Snate@binkert.orgclass UdpPort(CheckedInt):  cxx_type = 'uint16_t'; size = 16; unsigned = True
6437673Snate@binkert.org
6447673Snate@binkert.orgclass Percent(CheckedInt):  cxx_type = 'int'; min = 0; max = 100
6457673Snate@binkert.org
6467673Snate@binkert.orgclass Cycles(CheckedInt):
6477673Snate@binkert.org    cxx_type = 'Cycles'
6487673Snate@binkert.org    size = 64
6493101Sstever@eecs.umich.edu    unsigned = True
6503101Sstever@eecs.umich.edu
6513101Sstever@eecs.umich.edu    def getValue(self):
6523101Sstever@eecs.umich.edu        from _m5.core import Cycles
6533101Sstever@eecs.umich.edu        return Cycles(self.value)
6543101Sstever@eecs.umich.edu
6553101Sstever@eecs.umich.edu    @classmethod
6563101Sstever@eecs.umich.edu    def cxx_ini_predecls(cls, code):
6573101Sstever@eecs.umich.edu        # Assume that base/str.hh will be included anyway
6583101Sstever@eecs.umich.edu        # code('#include "base/str.hh"')
6593101Sstever@eecs.umich.edu        pass
6603101Sstever@eecs.umich.edu
6613101Sstever@eecs.umich.edu    @classmethod
6627743Sgblack@eecs.umich.edu    def cxx_ini_parse(cls, code, src, dest, ret):
6633101Sstever@eecs.umich.edu        code('uint64_t _temp;')
6643101Sstever@eecs.umich.edu        code('bool _ret = to_number(%s, _temp);' % src)
6653101Sstever@eecs.umich.edu        code('if (_ret)')
6663101Sstever@eecs.umich.edu        code('    %s = Cycles(_temp);' % dest)
6673101Sstever@eecs.umich.edu        code('%s _ret;' % ret)
6683101Sstever@eecs.umich.edu
6694380Sbinkertn@umich.educlass Float(ParamValue, float):
6703101Sstever@eecs.umich.edu    cxx_type = 'double'
6713101Sstever@eecs.umich.edu    cmd_line_settable = True
6724762Snate@binkert.org
6737677Snate@binkert.org    def __init__(self, value):
6744762Snate@binkert.org        if isinstance(value, (int, long, float, NumericParamValue, Float, str)):
6754762Snate@binkert.org            self.value = float(value)
6764380Sbinkertn@umich.edu        else:
6774380Sbinkertn@umich.edu            raise TypeError("Can't convert object of type %s to Float" \
6783101Sstever@eecs.umich.edu                  % type(value).__name__)
6797777Sgblack@eecs.umich.edu
6807777Sgblack@eecs.umich.edu    def __call__(self, value):
6817777Sgblack@eecs.umich.edu        self.__init__(value)
6827777Sgblack@eecs.umich.edu        return value
6837777Sgblack@eecs.umich.edu
6847777Sgblack@eecs.umich.edu    def getValue(self):
6857777Sgblack@eecs.umich.edu        return float(self.value)
6867777Sgblack@eecs.umich.edu
6877777Sgblack@eecs.umich.edu    def config_value(self):
6887777Sgblack@eecs.umich.edu        return self
6897777Sgblack@eecs.umich.edu
6907777Sgblack@eecs.umich.edu    @classmethod
6917777Sgblack@eecs.umich.edu    def cxx_ini_predecls(cls, code):
6927777Sgblack@eecs.umich.edu        code('#include <sstream>')
6937777Sgblack@eecs.umich.edu
6947777Sgblack@eecs.umich.edu    @classmethod
6957777Sgblack@eecs.umich.edu    def cxx_ini_parse(self, code, src, dest, ret):
6967777Sgblack@eecs.umich.edu        code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
6977777Sgblack@eecs.umich.edu
6987777Sgblack@eecs.umich.educlass MemorySize(CheckedInt):
6997777Sgblack@eecs.umich.edu    cxx_type = 'uint64_t'
7007777Sgblack@eecs.umich.edu    ex_str = '512MB'
7017777Sgblack@eecs.umich.edu    size = 64
7027777Sgblack@eecs.umich.edu    unsigned = True
7037777Sgblack@eecs.umich.edu    def __init__(self, value):
7047777Sgblack@eecs.umich.edu        if isinstance(value, MemorySize):
7057777Sgblack@eecs.umich.edu            self.value = value.value
7067777Sgblack@eecs.umich.edu        else:
7077777Sgblack@eecs.umich.edu            self.value = convert.toMemorySize(value)
7087777Sgblack@eecs.umich.edu        self._check()
7097777Sgblack@eecs.umich.edu
7107777Sgblack@eecs.umich.educlass MemorySize32(CheckedInt):
7117777Sgblack@eecs.umich.edu    cxx_type = 'uint32_t'
7127777Sgblack@eecs.umich.edu    ex_str = '512MB'
7137777Sgblack@eecs.umich.edu    size = 32
7147777Sgblack@eecs.umich.edu    unsigned = True
7157777Sgblack@eecs.umich.edu    def __init__(self, value):
7167777Sgblack@eecs.umich.edu        if isinstance(value, MemorySize):
7177777Sgblack@eecs.umich.edu            self.value = value.value
7187777Sgblack@eecs.umich.edu        else:
7197777Sgblack@eecs.umich.edu            self.value = convert.toMemorySize(value)
7207777Sgblack@eecs.umich.edu        self._check()
7217777Sgblack@eecs.umich.edu
7227777Sgblack@eecs.umich.educlass Addr(CheckedInt):
7237777Sgblack@eecs.umich.edu    cxx_type = 'Addr'
7247777Sgblack@eecs.umich.edu    size = 64
7257777Sgblack@eecs.umich.edu    unsigned = True
7267777Sgblack@eecs.umich.edu    def __init__(self, value):
7277777Sgblack@eecs.umich.edu        if isinstance(value, Addr):
7287777Sgblack@eecs.umich.edu            self.value = value.value
7297777Sgblack@eecs.umich.edu        else:
7307777Sgblack@eecs.umich.edu            try:
7317777Sgblack@eecs.umich.edu                # Often addresses are referred to with sizes. Ex: A device
7327777Sgblack@eecs.umich.edu                # base address is at "512MB".  Use toMemorySize() to convert
7337777Sgblack@eecs.umich.edu                # these into addresses. If the address is not specified with a
7347777Sgblack@eecs.umich.edu                # "size", an exception will occur and numeric translation will
7357777Sgblack@eecs.umich.edu                # proceed below.
7367777Sgblack@eecs.umich.edu                self.value = convert.toMemorySize(value)
7377777Sgblack@eecs.umich.edu            except (TypeError, ValueError):
7387777Sgblack@eecs.umich.edu                # Convert number to string and use long() to do automatic
7397777Sgblack@eecs.umich.edu                # base conversion (requires base=0 for auto-conversion)
7407777Sgblack@eecs.umich.edu                self.value = long(str(value), base=0)
7417777Sgblack@eecs.umich.edu
7427777Sgblack@eecs.umich.edu        self._check()
7437777Sgblack@eecs.umich.edu    def __add__(self, other):
7447777Sgblack@eecs.umich.edu        if isinstance(other, Addr):
7457777Sgblack@eecs.umich.edu            return self.value + other.value
7467777Sgblack@eecs.umich.edu        else:
7477777Sgblack@eecs.umich.edu            return self.value + other
7487777Sgblack@eecs.umich.edu    def pretty_print(self, value):
7497777Sgblack@eecs.umich.edu        try:
7507777Sgblack@eecs.umich.edu            val = convert.toMemorySize(value)
7517777Sgblack@eecs.umich.edu        except TypeError:
7527777Sgblack@eecs.umich.edu            val = long(value)
7537777Sgblack@eecs.umich.edu        return "0x%x" % long(val)
7547777Sgblack@eecs.umich.edu
7557777Sgblack@eecs.umich.educlass AddrRange(ParamValue):
7567777Sgblack@eecs.umich.edu    cxx_type = 'AddrRange'
7577777Sgblack@eecs.umich.edu
7587777Sgblack@eecs.umich.edu    def __init__(self, *args, **kwargs):
7597777Sgblack@eecs.umich.edu        # Disable interleaving and hashing by default
7607777Sgblack@eecs.umich.edu        self.intlvHighBit = 0
7617777Sgblack@eecs.umich.edu        self.xorHighBit = 0
7627777Sgblack@eecs.umich.edu        self.intlvBits = 0
7637777Sgblack@eecs.umich.edu        self.intlvMatch = 0
7647777Sgblack@eecs.umich.edu        self.masks = []
7657777Sgblack@eecs.umich.edu
7667777Sgblack@eecs.umich.edu        def handle_kwargs(self, kwargs):
7677777Sgblack@eecs.umich.edu            # An address range needs to have an upper limit, specified
7687777Sgblack@eecs.umich.edu            # either explicitly with an end, or as an offset using the
7697777Sgblack@eecs.umich.edu            # size keyword.
7707777Sgblack@eecs.umich.edu            if 'end' in kwargs:
7717777Sgblack@eecs.umich.edu                self.end = Addr(kwargs.pop('end'))
7727777Sgblack@eecs.umich.edu            elif 'size' in kwargs:
7737777Sgblack@eecs.umich.edu                self.end = self.start + Addr(kwargs.pop('size')) - 1
7747777Sgblack@eecs.umich.edu            else:
7757777Sgblack@eecs.umich.edu                raise TypeError("Either end or size must be specified")
7767777Sgblack@eecs.umich.edu
7777777Sgblack@eecs.umich.edu            # Now on to the optional bit
7787777Sgblack@eecs.umich.edu            if 'intlvMatch' in kwargs:
7797777Sgblack@eecs.umich.edu                self.intlvMatch = int(kwargs.pop('intlvMatch'))
7807777Sgblack@eecs.umich.edu
7817777Sgblack@eecs.umich.edu            if 'masks' in kwargs:
7827777Sgblack@eecs.umich.edu                self.masks = [ long(x) for x in list(kwargs.pop('masks')) ]
7837777Sgblack@eecs.umich.edu                self.intlvBits = len(self.masks)
7847777Sgblack@eecs.umich.edu            else:
7857777Sgblack@eecs.umich.edu                if 'intlvHighBit' in kwargs:
7867777Sgblack@eecs.umich.edu                    intlv_high_bit = int(kwargs.pop('intlvHighBit'))
7877777Sgblack@eecs.umich.edu                if 'xorHighBit' in kwargs:
7887777Sgblack@eecs.umich.edu                    xor_high_bit = int(kwargs.pop('xorHighBit'))
7897777Sgblack@eecs.umich.edu                if 'intlvBits' in kwargs:
7907777Sgblack@eecs.umich.edu                    self.intlvBits = int(kwargs.pop('intlvBits'))
7917777Sgblack@eecs.umich.edu                    self.masks = [0] * self.intlvBits
7927777Sgblack@eecs.umich.edu                for i in range(0, self.intlvBits):
7937777Sgblack@eecs.umich.edu                    bit1 = intlv_high_bit - i
7947777Sgblack@eecs.umich.edu                    mask = 1 << bit1
7957777Sgblack@eecs.umich.edu                    if xor_high_bit != 0:
7967777Sgblack@eecs.umich.edu                        bit2 = xor_high_bit - i
7977777Sgblack@eecs.umich.edu                        mask |= 1 << bit2
7987777Sgblack@eecs.umich.edu                    self.masks[self.intlvBits - i - 1] = mask
7997777Sgblack@eecs.umich.edu
8007777Sgblack@eecs.umich.edu        if len(args) == 0:
8017777Sgblack@eecs.umich.edu            self.start = Addr(kwargs.pop('start'))
8027777Sgblack@eecs.umich.edu            handle_kwargs(self, kwargs)
8037777Sgblack@eecs.umich.edu
8047777Sgblack@eecs.umich.edu        elif len(args) == 1:
8057777Sgblack@eecs.umich.edu            if kwargs:
8067777Sgblack@eecs.umich.edu                self.start = Addr(args[0])
8077777Sgblack@eecs.umich.edu                handle_kwargs(self, kwargs)
8087777Sgblack@eecs.umich.edu            elif isinstance(args[0], (list, tuple)):
8097777Sgblack@eecs.umich.edu                self.start = Addr(args[0][0])
8107777Sgblack@eecs.umich.edu                self.end = Addr(args[0][1])
8117777Sgblack@eecs.umich.edu            else:
8127777Sgblack@eecs.umich.edu                self.start = Addr(0)
8137777Sgblack@eecs.umich.edu                self.end = Addr(args[0]) - 1
8147777Sgblack@eecs.umich.edu
8157777Sgblack@eecs.umich.edu        elif len(args) == 2:
8167777Sgblack@eecs.umich.edu            self.start = Addr(args[0])
8177777Sgblack@eecs.umich.edu            self.end = Addr(args[1])
8187777Sgblack@eecs.umich.edu        else:
8197777Sgblack@eecs.umich.edu            raise TypeError("Too many arguments specified")
8207777Sgblack@eecs.umich.edu
8217777Sgblack@eecs.umich.edu        if kwargs:
8227777Sgblack@eecs.umich.edu            raise TypeError("Too many keywords: %s" % list(kwargs.keys()))
8237777Sgblack@eecs.umich.edu
8247777Sgblack@eecs.umich.edu    def __str__(self):
8257777Sgblack@eecs.umich.edu        if len(self.masks) == 0:
8267777Sgblack@eecs.umich.edu            return '%s:%s' % (self.start, self.end)
8277777Sgblack@eecs.umich.edu        else:
8287777Sgblack@eecs.umich.edu            return '%s:%s:%s:%s' % (self.start, self.end, self.intlvMatch,
8297777Sgblack@eecs.umich.edu                                    ':'.join(str(m) for m in self.masks))
8307777Sgblack@eecs.umich.edu
8317777Sgblack@eecs.umich.edu    def size(self):
8327777Sgblack@eecs.umich.edu        # Divide the size by the size of the interleaving slice
8337777Sgblack@eecs.umich.edu        return (long(self.end) - long(self.start) + 1) >> self.intlvBits
8347777Sgblack@eecs.umich.edu
8357777Sgblack@eecs.umich.edu    @classmethod
8363932Sbinkertn@umich.edu    def cxx_predecls(cls, code):
8373932Sbinkertn@umich.edu        Addr.cxx_predecls(code)
8383932Sbinkertn@umich.edu        code('#include "base/addr_range.hh"')
8393932Sbinkertn@umich.edu
8403932Sbinkertn@umich.edu    @classmethod
8413932Sbinkertn@umich.edu    def pybind_predecls(cls, code):
8423932Sbinkertn@umich.edu        Addr.pybind_predecls(code)
8433932Sbinkertn@umich.edu        code('#include "base/addr_range.hh"')
8443932Sbinkertn@umich.edu
8453932Sbinkertn@umich.edu    @classmethod
8463932Sbinkertn@umich.edu    def cxx_ini_predecls(cls, code):
8473932Sbinkertn@umich.edu        code('#include <sstream>')
8483932Sbinkertn@umich.edu        code('#include <vector>')
8493885Sbinkertn@umich.edu        code('#include "base/types.hh"')
8503932Sbinkertn@umich.edu
8513932Sbinkertn@umich.edu    @classmethod
8523885Sbinkertn@umich.edu    def cxx_ini_parse(cls, code, src, dest, ret):
8533932Sbinkertn@umich.edu        code('bool _ret = true;')
8543932Sbinkertn@umich.edu        code('uint64_t _start, _end, _intlvMatch = 0;')
8553932Sbinkertn@umich.edu        code('std::vector<Addr> _masks;')
8563932Sbinkertn@umich.edu        code('char _sep;')
8573932Sbinkertn@umich.edu        code('std::istringstream _stream(${src});')
8583932Sbinkertn@umich.edu        code('_stream >> _start;')
8593932Sbinkertn@umich.edu        code('_stream.get(_sep);')
8603932Sbinkertn@umich.edu        code('_ret = _sep == \':\';')
8613932Sbinkertn@umich.edu        code('_stream >> _end;')
8623932Sbinkertn@umich.edu        code('if (!_stream.fail() && !_stream.eof()) {')
8633932Sbinkertn@umich.edu        code('    _stream.get(_sep);')
8643932Sbinkertn@umich.edu        code('    _ret = ret && _sep == \':\';')
8653932Sbinkertn@umich.edu        code('    _stream >> _intlvMatch;')
8663932Sbinkertn@umich.edu        code('    while (!_stream.fail() && !_stream.eof()) {')
8673932Sbinkertn@umich.edu        code('        _stream.get(_sep);')
8683932Sbinkertn@umich.edu        code('        _ret = ret && _sep == \':\';')
8693932Sbinkertn@umich.edu        code('        Addr mask;')
8703932Sbinkertn@umich.edu        code('        _stream >> mask;')
8713885Sbinkertn@umich.edu        code('        _masks.push_back(mask);')
8723885Sbinkertn@umich.edu        code('    }')
8733885Sbinkertn@umich.edu        code('}')
8743885Sbinkertn@umich.edu        code('_ret = _ret && !_stream.fail() && _stream.eof();')
8754762Snate@binkert.org        code('if (_ret)')
8767673Snate@binkert.org        code('   ${dest} = AddrRange(_start, _end, _masks, _intlvMatch);')
8777673Snate@binkert.org        code('${ret} _ret;')
8787673Snate@binkert.org
8797673Snate@binkert.org    def getValue(self):
8807673Snate@binkert.org        # Go from the Python class to the wrapped C++ class
8817673Snate@binkert.org        from _m5.range import AddrRange
8827673Snate@binkert.org
8837673Snate@binkert.org        return AddrRange(long(self.start), long(self.end),
8847673Snate@binkert.org                         self.masks, int(self.intlvMatch))
8853885Sbinkertn@umich.edu
8863932Sbinkertn@umich.edu# Boolean parameter type.  Python doesn't let you subclass bool, since
8873885Sbinkertn@umich.edu# it doesn't want to let you create multiple instances of True and
8884762Snate@binkert.org# False.  Thus this is a little more complicated than String.
8897677Snate@binkert.orgclass Bool(ParamValue):
8904762Snate@binkert.org    cxx_type = 'bool'
8914762Snate@binkert.org    cmd_line_settable = True
8924762Snate@binkert.org
8934762Snate@binkert.org    def __init__(self, value):
8944762Snate@binkert.org        try:
8954762Snate@binkert.org            self.value = convert.toBool(value)
8964762Snate@binkert.org        except TypeError:
8974762Snate@binkert.org            self.value = bool(value)
8984762Snate@binkert.org
8994762Snate@binkert.org    def __call__(self, value):
9004762Snate@binkert.org        self.__init__(value)
9014762Snate@binkert.org        return value
9024762Snate@binkert.org
9034762Snate@binkert.org    def getValue(self):
9044762Snate@binkert.org        return bool(self.value)
9054762Snate@binkert.org
9064762Snate@binkert.org    def __str__(self):
9074762Snate@binkert.org        return str(self.value)
9084762Snate@binkert.org
9094762Snate@binkert.org    # implement truth value testing for Bool parameters so that these params
9104762Snate@binkert.org    # evaluate correctly during the python configuration phase
9114762Snate@binkert.org    def __bool__(self):
9124762Snate@binkert.org        return bool(self.value)
9134762Snate@binkert.org
9143885Sbinkertn@umich.edu    # Python 2.7 uses __nonzero__ instead of __bool__
9154762Snate@binkert.org    __nonzero__ = __bool__
9163885Sbinkertn@umich.edu
9173885Sbinkertn@umich.edu    def ini_str(self):
9183932Sbinkertn@umich.edu        if self.value:
9193885Sbinkertn@umich.edu            return 'true'
9203101Sstever@eecs.umich.edu        return 'false'
9213101Sstever@eecs.umich.edu
9223101Sstever@eecs.umich.edu    def config_value(self):
9233101Sstever@eecs.umich.edu        return self.value
9243101Sstever@eecs.umich.edu
9253101Sstever@eecs.umich.edu    @classmethod
9263101Sstever@eecs.umich.edu    def cxx_ini_predecls(cls, code):
9273101Sstever@eecs.umich.edu        # Assume that base/str.hh will be included anyway
9283101Sstever@eecs.umich.edu        # code('#include "base/str.hh"')
9293101Sstever@eecs.umich.edu        pass
9303101Sstever@eecs.umich.edu
9313101Sstever@eecs.umich.edu    @classmethod
9323101Sstever@eecs.umich.edu    def cxx_ini_parse(cls, code, src, dest, ret):
9333101Sstever@eecs.umich.edu        code('%s to_bool(%s, %s);' % (ret, src, dest))
9344762Snate@binkert.org
9353101Sstever@eecs.umich.edudef IncEthernetAddr(addr, val = 1):
9365033Smilesck@eecs.umich.edu    bytes = [ int(x, 16) for x in addr.split(':') ]
9374762Snate@binkert.org    bytes[5] += val
9384762Snate@binkert.org    for i in (5, 4, 3, 2, 1):
9394762Snate@binkert.org        val,rem = divmod(bytes[i], 256)
9404762Snate@binkert.org        bytes[i] = rem
9414762Snate@binkert.org        if val == 0:
9424762Snate@binkert.org            break
9434762Snate@binkert.org        bytes[i - 1] += val
9443101Sstever@eecs.umich.edu    assert(bytes[0] <= 255)
9453101Sstever@eecs.umich.edu    return ':'.join(map(lambda x: '%02x' % x, bytes))
9463101Sstever@eecs.umich.edu
9473101Sstever@eecs.umich.edu_NextEthernetAddr = "00:90:00:00:00:01"
9483101Sstever@eecs.umich.edudef NextEthernetAddr():
9493101Sstever@eecs.umich.edu    global _NextEthernetAddr
9503101Sstever@eecs.umich.edu
9513101Sstever@eecs.umich.edu    value = _NextEthernetAddr
9523101Sstever@eecs.umich.edu    _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1)
9533101Sstever@eecs.umich.edu    return value
9543101Sstever@eecs.umich.edu
9553101Sstever@eecs.umich.educlass EthernetAddr(ParamValue):
9563101Sstever@eecs.umich.edu    cxx_type = 'Net::EthAddr'
9573101Sstever@eecs.umich.edu    ex_str = "00:90:00:00:00:01"
9583101Sstever@eecs.umich.edu    cmd_line_settable = True
9593101Sstever@eecs.umich.edu
9603101Sstever@eecs.umich.edu    @classmethod
9613101Sstever@eecs.umich.edu    def cxx_predecls(cls, code):
9623101Sstever@eecs.umich.edu        code('#include "base/inet.hh"')
9633101Sstever@eecs.umich.edu
9644762Snate@binkert.org    def __init__(self, value):
9653101Sstever@eecs.umich.edu        if value == NextEthernetAddr:
9663101Sstever@eecs.umich.edu            self.value = value
9673101Sstever@eecs.umich.edu            return
9683101Sstever@eecs.umich.edu
9693101Sstever@eecs.umich.edu        if not isinstance(value, str):
9703101Sstever@eecs.umich.edu            raise TypeError("expected an ethernet address and didn't get one")
9717673Snate@binkert.org
9726654Snate@binkert.org        bytes = value.split(':')
9737673Snate@binkert.org        if len(bytes) != 6:
9747673Snate@binkert.org            raise TypeError('invalid ethernet address %s' % value)
9757673Snate@binkert.org
9767673Snate@binkert.org        for byte in bytes:
9777673Snate@binkert.org            if not 0 <= int(byte, base=16) <= 0xff:
9787673Snate@binkert.org                raise TypeError('invalid ethernet address %s' % value)
9797673Snate@binkert.org
9807673Snate@binkert.org        self.value = value
9814762Snate@binkert.org
9827673Snate@binkert.org    def __call__(self, value):
9837673Snate@binkert.org        self.__init__(value)
9847673Snate@binkert.org        return value
9857673Snate@binkert.org
9867673Snate@binkert.org    def unproxy(self, base):
9877673Snate@binkert.org        if self.value == NextEthernetAddr:
9887673Snate@binkert.org            return EthernetAddr(self.value())
9894762Snate@binkert.org        return self
9907673Snate@binkert.org
9917673Snate@binkert.org    def getValue(self):
9927673Snate@binkert.org        from _m5.net import EthAddr
9937673Snate@binkert.org        return EthAddr(self.value)
9946654Snate@binkert.org
9957673Snate@binkert.org    def __str__(self):
9967677Snate@binkert.org        return self.value
9977673Snate@binkert.org
9987673Snate@binkert.org    def ini_str(self):
9997673Snate@binkert.org        return self.value
10007673Snate@binkert.org
10017673Snate@binkert.org    @classmethod
10024762Snate@binkert.org    def cxx_ini_parse(self, code, src, dest, ret):
10037673Snate@binkert.org        code('%s = Net::EthAddr(%s);' % (dest, src))
10047673Snate@binkert.org        code('%s true;' % ret)
10057673Snate@binkert.org
10067673Snate@binkert.org# When initializing an IpAddress, pass in an existing IpAddress, a string of
10077673Snate@binkert.org# the form "a.b.c.d", or an integer representing an IP.
10087673Snate@binkert.orgclass IpAddress(ParamValue):
10093101Sstever@eecs.umich.edu    cxx_type = 'Net::IpAddress'
10103101Sstever@eecs.umich.edu    ex_str = "127.0.0.1"
10113101Sstever@eecs.umich.edu    cmd_line_settable = True
10123101Sstever@eecs.umich.edu
10133101Sstever@eecs.umich.edu    @classmethod
10143101Sstever@eecs.umich.edu    def cxx_predecls(cls, code):
10153101Sstever@eecs.umich.edu        code('#include "base/inet.hh"')
10163101Sstever@eecs.umich.edu
10173101Sstever@eecs.umich.edu    def __init__(self, value):
10183101Sstever@eecs.umich.edu        if isinstance(value, IpAddress):
10193101Sstever@eecs.umich.edu            self.ip = value.ip
10203101Sstever@eecs.umich.edu        else:
10217675Snate@binkert.org            try:
10227675Snate@binkert.org                self.ip = convert.toIpAddress(value)
10237675Snate@binkert.org            except TypeError:
10247675Snate@binkert.org                self.ip = long(value)
10257675Snate@binkert.org        self.verifyIp()
10267675Snate@binkert.org
10277677Snate@binkert.org    def __call__(self, value):
10287675Snate@binkert.org        self.__init__(value)
10294762Snate@binkert.org        return value
10304762Snate@binkert.org
10314762Snate@binkert.org    def __str__(self):
10323101Sstever@eecs.umich.edu        tup = [(self.ip >> i)  & 0xff for i in (24, 16, 8, 0)]
10333101Sstever@eecs.umich.edu        return '%d.%d.%d.%d' % tuple(tup)
10343101Sstever@eecs.umich.edu
10353101Sstever@eecs.umich.edu    def __eq__(self, other):
10363101Sstever@eecs.umich.edu        if isinstance(other, IpAddress):
10373101Sstever@eecs.umich.edu            return self.ip == other.ip
10384167Sbinkertn@umich.edu        elif isinstance(other, str):
10393101Sstever@eecs.umich.edu            try:
10407673Snate@binkert.org                return self.ip == convert.toIpAddress(other)
10417673Snate@binkert.org            except:
10427673Snate@binkert.org                return False
10437673Snate@binkert.org        else:
10447673Snate@binkert.org            return self.ip == other
10457673Snate@binkert.org
10467673Snate@binkert.org    def __ne__(self, other):
10477673Snate@binkert.org        return not (self == other)
10487673Snate@binkert.org
10494167Sbinkertn@umich.edu    def verifyIp(self):
10504762Snate@binkert.org        if self.ip < 0 or self.ip >= (1 << 32):
10514762Snate@binkert.org            raise TypeError("invalid ip address %#08x" % self.ip)
10524762Snate@binkert.org
10534167Sbinkertn@umich.edu    def getValue(self):
10543101Sstever@eecs.umich.edu        from _m5.net import IpAddress
10554167Sbinkertn@umich.edu        return IpAddress(self.ip)
10564167Sbinkertn@umich.edu
10574167Sbinkertn@umich.edu# When initializing an IpNetmask, pass in an existing IpNetmask, a string of
10584167Sbinkertn@umich.edu# the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as
10594167Sbinkertn@umich.edu# positional or keyword arguments.
10604167Sbinkertn@umich.educlass IpNetmask(IpAddress):
10614167Sbinkertn@umich.edu    cxx_type = 'Net::IpNetmask'
10624167Sbinkertn@umich.edu    ex_str = "127.0.0.0/24"
10634167Sbinkertn@umich.edu    cmd_line_settable = True
10644167Sbinkertn@umich.edu
10654167Sbinkertn@umich.edu    @classmethod
10664167Sbinkertn@umich.edu    def cxx_predecls(cls, code):
10673101Sstever@eecs.umich.edu        code('#include "base/inet.hh"')
10683101Sstever@eecs.umich.edu
10693101Sstever@eecs.umich.edu    def __init__(self, *args, **kwargs):
10703101Sstever@eecs.umich.edu        def handle_kwarg(self, kwargs, key, elseVal = None):
10713101Sstever@eecs.umich.edu            if key in kwargs:
10723101Sstever@eecs.umich.edu                setattr(self, key, kwargs.pop(key))
10733101Sstever@eecs.umich.edu            elif elseVal:
10743101Sstever@eecs.umich.edu                setattr(self, key, elseVal)
10754762Snate@binkert.org            else:
10764762Snate@binkert.org                raise TypeError("No value set for %s" % key)
10774762Snate@binkert.org
10784762Snate@binkert.org        if len(args) == 0:
10794762Snate@binkert.org            handle_kwarg(self, kwargs, 'ip')
10804762Snate@binkert.org            handle_kwarg(self, kwargs, 'netmask')
10814762Snate@binkert.org
10823101Sstever@eecs.umich.edu        elif len(args) == 1:
10833101Sstever@eecs.umich.edu            if kwargs:
10844762Snate@binkert.org                if not 'ip' in kwargs and not 'netmask' in kwargs:
10853101Sstever@eecs.umich.edu                    raise TypeError("Invalid arguments")
10864167Sbinkertn@umich.edu                handle_kwarg(self, kwargs, 'ip', args[0])
10873101Sstever@eecs.umich.edu                handle_kwarg(self, kwargs, 'netmask', args[0])
10884167Sbinkertn@umich.edu            elif isinstance(args[0], IpNetmask):
10894167Sbinkertn@umich.edu                self.ip = args[0].ip
10904167Sbinkertn@umich.edu                self.netmask = args[0].netmask
10914167Sbinkertn@umich.edu            else:
10924167Sbinkertn@umich.edu                (self.ip, self.netmask) = convert.toIpNetmask(args[0])
10934167Sbinkertn@umich.edu
10944167Sbinkertn@umich.edu        elif len(args) == 2:
10954167Sbinkertn@umich.edu            self.ip = args[0]
10964167Sbinkertn@umich.edu            self.netmask = args[1]
10974167Sbinkertn@umich.edu        else:
10984167Sbinkertn@umich.edu            raise TypeError("Too many arguments specified")
10994167Sbinkertn@umich.edu
11003101Sstever@eecs.umich.edu        if kwargs:
11013101Sstever@eecs.umich.edu            raise TypeError("Too many keywords: %s" % list(kwargs.keys()))
11023101Sstever@eecs.umich.edu
11033101Sstever@eecs.umich.edu        self.verify()
11043101Sstever@eecs.umich.edu
11053101Sstever@eecs.umich.edu    def __call__(self, value):
11063101Sstever@eecs.umich.edu        self.__init__(value)
11073101Sstever@eecs.umich.edu        return value
11084167Sbinkertn@umich.edu
11094762Snate@binkert.org    def __str__(self):
11104762Snate@binkert.org        return "%s/%d" % (super(IpNetmask, self).__str__(), self.netmask)
11114762Snate@binkert.org
11124762Snate@binkert.org    def __eq__(self, other):
11134762Snate@binkert.org        if isinstance(other, IpNetmask):
11144762Snate@binkert.org            return self.ip == other.ip and self.netmask == other.netmask
11154762Snate@binkert.org        elif isinstance(other, str):
11163101Sstever@eecs.umich.edu            try:
11174762Snate@binkert.org                return (self.ip, self.netmask) == convert.toIpNetmask(other)
11183101Sstever@eecs.umich.edu            except:
11193101Sstever@eecs.umich.edu                return False
11203101Sstever@eecs.umich.edu        else:
11213101Sstever@eecs.umich.edu            return False
11223101Sstever@eecs.umich.edu
11233101Sstever@eecs.umich.edu    def verify(self):
11247673Snate@binkert.org        self.verifyIp()
11257673Snate@binkert.org        if self.netmask < 0 or self.netmask > 32:
11267673Snate@binkert.org            raise TypeError("invalid netmask %d" % netmask)
11277673Snate@binkert.org
11287673Snate@binkert.org    def getValue(self):
11297673Snate@binkert.org        from _m5.net import IpNetmask
11307673Snate@binkert.org        return IpNetmask(self.ip, self.netmask)
11317673Snate@binkert.org
11327673Snate@binkert.org# When initializing an IpWithPort, pass in an existing IpWithPort, a string of
11337673Snate@binkert.org# the form "a.b.c.d:p", or an ip and port as positional or keyword arguments.
11343101Sstever@eecs.umich.educlass IpWithPort(IpAddress):
11354167Sbinkertn@umich.edu    cxx_type = 'Net::IpWithPort'
11364167Sbinkertn@umich.edu    ex_str = "127.0.0.1:80"
11374167Sbinkertn@umich.edu    cmd_line_settable = True
11384167Sbinkertn@umich.edu
11394167Sbinkertn@umich.edu    @classmethod
11404167Sbinkertn@umich.edu    def cxx_predecls(cls, code):
11414167Sbinkertn@umich.edu        code('#include "base/inet.hh"')
11424167Sbinkertn@umich.edu
11434167Sbinkertn@umich.edu    def __init__(self, *args, **kwargs):
11444167Sbinkertn@umich.edu        def handle_kwarg(self, kwargs, key, elseVal = None):
11454167Sbinkertn@umich.edu            if key in kwargs:
11464167Sbinkertn@umich.edu                setattr(self, key, kwargs.pop(key))
11473101Sstever@eecs.umich.edu            elif elseVal:
11483101Sstever@eecs.umich.edu                setattr(self, key, elseVal)
11493101Sstever@eecs.umich.edu            else:
11503101Sstever@eecs.umich.edu                raise TypeError("No value set for %s" % key)
11513101Sstever@eecs.umich.edu
11523101Sstever@eecs.umich.edu        if len(args) == 0:
11533101Sstever@eecs.umich.edu            handle_kwarg(self, kwargs, 'ip')
11543101Sstever@eecs.umich.edu            handle_kwarg(self, kwargs, 'port')
11554762Snate@binkert.org
11564762Snate@binkert.org        elif len(args) == 1:
11574762Snate@binkert.org            if kwargs:
11583101Sstever@eecs.umich.edu                if not 'ip' in kwargs and not 'port' in kwargs:
11593101Sstever@eecs.umich.edu                    raise TypeError("Invalid arguments")
11603101Sstever@eecs.umich.edu                handle_kwarg(self, kwargs, 'ip', args[0])
11613101Sstever@eecs.umich.edu                handle_kwarg(self, kwargs, 'port', args[0])
11623101Sstever@eecs.umich.edu            elif isinstance(args[0], IpWithPort):
11633101Sstever@eecs.umich.edu                self.ip = args[0].ip
11644167Sbinkertn@umich.edu                self.port = args[0].port
11654167Sbinkertn@umich.edu            else:
11663101Sstever@eecs.umich.edu                (self.ip, self.port) = convert.toIpWithPort(args[0])
11673101Sstever@eecs.umich.edu
11683101Sstever@eecs.umich.edu        elif len(args) == 2:
11693101Sstever@eecs.umich.edu            self.ip = args[0]
11703101Sstever@eecs.umich.edu            self.port = args[1]
11714762Snate@binkert.org        else:
11724167Sbinkertn@umich.edu            raise TypeError("Too many arguments specified")
11734167Sbinkertn@umich.edu
11744167Sbinkertn@umich.edu        if kwargs:
11754762Snate@binkert.org            raise TypeError("Too many keywords: %s" % list(kwargs.keys()))
11764762Snate@binkert.org
11774762Snate@binkert.org        self.verify()
11784762Snate@binkert.org
11794762Snate@binkert.org    def __call__(self, value):
11803101Sstever@eecs.umich.edu        self.__init__(value)
11813101Sstever@eecs.umich.edu        return value
11823101Sstever@eecs.umich.edu
11835469Snate@binkert.org    def __str__(self):
11847743Sgblack@eecs.umich.edu        return "%s:%d" % (super(IpWithPort, self).__str__(), self.port)
11853102Sstever@eecs.umich.edu
11863101Sstever@eecs.umich.edu    def __eq__(self, other):
11873101Sstever@eecs.umich.edu        if isinstance(other, IpWithPort):
11883101Sstever@eecs.umich.edu            return self.ip == other.ip and self.port == other.port
11893101Sstever@eecs.umich.edu        elif isinstance(other, str):
11903101Sstever@eecs.umich.edu            try:
11914762Snate@binkert.org                return (self.ip, self.port) == convert.toIpWithPort(other)
11924167Sbinkertn@umich.edu            except:
11935468Snate@binkert.org                return False
11945468Snate@binkert.org        else:
11955468Snate@binkert.org            return False
11964167Sbinkertn@umich.edu
11974762Snate@binkert.org    def verify(self):
11984762Snate@binkert.org        self.verifyIp()
11994762Snate@binkert.org        if self.port < 0 or self.port > 0xffff:
12004762Snate@binkert.org            raise TypeError("invalid port %d" % self.port)
12014762Snate@binkert.org
12023101Sstever@eecs.umich.edu    def getValue(self):
12033101Sstever@eecs.umich.edu        from _m5.net import IpWithPort
12043101Sstever@eecs.umich.edu        return IpWithPort(self.ip, self.port)
12053101Sstever@eecs.umich.edu
12063101Sstever@eecs.umich.edutime_formats = [ "%a %b %d %H:%M:%S %Z %Y",
12073102Sstever@eecs.umich.edu                 "%a %b %d %H:%M:%S %Y",
12083102Sstever@eecs.umich.edu                 "%Y/%m/%d %H:%M:%S",
12093102Sstever@eecs.umich.edu                 "%Y/%m/%d %H:%M",
12103102Sstever@eecs.umich.edu                 "%Y/%m/%d",
12113102Sstever@eecs.umich.edu                 "%m/%d/%Y %H:%M:%S",
12123102Sstever@eecs.umich.edu                 "%m/%d/%Y %H:%M",
12133102Sstever@eecs.umich.edu                 "%m/%d/%Y",
12143102Sstever@eecs.umich.edu                 "%m/%d/%y %H:%M:%S",
12153102Sstever@eecs.umich.edu                 "%m/%d/%y %H:%M",
12163102Sstever@eecs.umich.edu                 "%m/%d/%y"]
12173102Sstever@eecs.umich.edu
12183102Sstever@eecs.umich.edu
12193102Sstever@eecs.umich.edudef parse_time(value):
12203102Sstever@eecs.umich.edu    from time import gmtime, strptime, struct_time, time
12213102Sstever@eecs.umich.edu    from datetime import datetime, date
12223102Sstever@eecs.umich.edu
12233102Sstever@eecs.umich.edu    if isinstance(value, struct_time):
12243102Sstever@eecs.umich.edu        return value
12253102Sstever@eecs.umich.edu
12263102Sstever@eecs.umich.edu    if isinstance(value, (int, long)):
12273102Sstever@eecs.umich.edu        return gmtime(value)
12284762Snate@binkert.org
12293102Sstever@eecs.umich.edu    if isinstance(value, (datetime, date)):
12303102Sstever@eecs.umich.edu        return value.timetuple()
12313102Sstever@eecs.umich.edu
12324762Snate@binkert.org    if isinstance(value, str):
12334762Snate@binkert.org        if value in ('Now', 'Today'):
12344762Snate@binkert.org            return time.gmtime(time.time())
12353102Sstever@eecs.umich.edu
12363102Sstever@eecs.umich.edu        for format in time_formats:
12373102Sstever@eecs.umich.edu            try:
12383102Sstever@eecs.umich.edu                return strptime(value, format)
12393102Sstever@eecs.umich.edu            except ValueError:
12403102Sstever@eecs.umich.edu                pass
12413101Sstever@eecs.umich.edu
12423101Sstever@eecs.umich.edu    raise ValueError("Could not parse '%s' as a time" % value)
12433101Sstever@eecs.umich.edu
12443101Sstever@eecs.umich.educlass Time(ParamValue):
12453101Sstever@eecs.umich.edu    cxx_type = 'tm'
12463101Sstever@eecs.umich.edu
12473101Sstever@eecs.umich.edu    @classmethod
12483101Sstever@eecs.umich.edu    def cxx_predecls(cls, code):
12493101Sstever@eecs.umich.edu        code('#include <time.h>')
12503101Sstever@eecs.umich.edu
12513101Sstever@eecs.umich.edu    def __init__(self, value):
12523101Sstever@eecs.umich.edu        self.value = parse_time(value)
12533101Sstever@eecs.umich.edu
12543101Sstever@eecs.umich.edu    def __call__(self, value):
12553101Sstever@eecs.umich.edu        self.__init__(value)
12563101Sstever@eecs.umich.edu        return value
12573101Sstever@eecs.umich.edu
12583105Sstever@eecs.umich.edu    def getValue(self):
12593105Sstever@eecs.umich.edu        from _m5.core import tm
12603101Sstever@eecs.umich.edu        import calendar
12613101Sstever@eecs.umich.edu
12623101Sstever@eecs.umich.edu        return tm.gmtime(calendar.timegm(self.value))
12633101Sstever@eecs.umich.edu
12643105Sstever@eecs.umich.edu    def __str__(self):
12653101Sstever@eecs.umich.edu        return time.asctime(self.value)
12663103Sstever@eecs.umich.edu
12673105Sstever@eecs.umich.edu    def ini_str(self):
12683103Sstever@eecs.umich.edu        return str(self)
12693105Sstever@eecs.umich.edu
12703105Sstever@eecs.umich.edu    def get_config_as_dict(self):
12713105Sstever@eecs.umich.edu        assert false
12723105Sstever@eecs.umich.edu        return str(self)
12733105Sstever@eecs.umich.edu
12743105Sstever@eecs.umich.edu    @classmethod
12753105Sstever@eecs.umich.edu    def cxx_ini_predecls(cls, code):
12763105Sstever@eecs.umich.edu        code('#include <time.h>')
12773105Sstever@eecs.umich.edu
12783105Sstever@eecs.umich.edu    @classmethod
12793105Sstever@eecs.umich.edu    def cxx_ini_parse(cls, code, src, dest, ret):
12803105Sstever@eecs.umich.edu        code('char *_parse_ret = strptime((${src}).c_str(),')
12813105Sstever@eecs.umich.edu        code('    "%a %b %d %H:%M:%S %Y", &(${dest}));')
12823109Sstever@eecs.umich.edu        code('${ret} _parse_ret && *_parse_ret == \'\\0\';');
12833105Sstever@eecs.umich.edu
12843105Sstever@eecs.umich.edu# Enumerated types are a little more complex.  The user specifies the
12853105Sstever@eecs.umich.edu# type as Enum(foo) where foo is either a list or dictionary of
12863105Sstever@eecs.umich.edu# alternatives (typically strings, but not necessarily so).  (In the
12873105Sstever@eecs.umich.edu# long run, the integer value of the parameter will be the list index
12883105Sstever@eecs.umich.edu# or the corresponding dictionary value.  For now, since we only check
12893105Sstever@eecs.umich.edu# that the alternative is valid and then spit it into a .ini file,
12903105Sstever@eecs.umich.edu# there's not much point in using the dictionary.)
12915578SSteve.Reinhardt@amd.com
12923101Sstever@eecs.umich.edu# What Enum() must do is generate a new type encapsulating the
12933109Sstever@eecs.umich.edu# provided list/dictionary so that specific values of the parameter
12943109Sstever@eecs.umich.edu# can be instances of that type.  We define two hidden internal
12953109Sstever@eecs.umich.edu# classes (_ListEnum and _DictEnum) to serve as base classes, then
12963109Sstever@eecs.umich.edu# derive the new type from the appropriate base class on the fly.
12973109Sstever@eecs.umich.edu
12983109Sstever@eecs.umich.eduallEnums = {}
12993109Sstever@eecs.umich.edu# Metaclass for Enum types
13003109Sstever@eecs.umich.educlass MetaEnum(MetaParamValue):
13013109Sstever@eecs.umich.edu    def __new__(mcls, name, bases, dict):
13023101Sstever@eecs.umich.edu        assert name not in allEnums
13033105Sstever@eecs.umich.edu
13043105Sstever@eecs.umich.edu        cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict)
13053105Sstever@eecs.umich.edu        allEnums[name] = cls
13063101Sstever@eecs.umich.edu        return cls
13073105Sstever@eecs.umich.edu
13083105Sstever@eecs.umich.edu    def __init__(cls, name, bases, init_dict):
13093101Sstever@eecs.umich.edu        if 'map' in init_dict:
13103105Sstever@eecs.umich.edu            if not isinstance(cls.map, dict):
13113179Sstever@eecs.umich.edu                raise TypeError("Enum-derived class attribute 'map' " \
13123105Sstever@eecs.umich.edu                      "must be of type dict")
13133105Sstever@eecs.umich.edu            # build list of value strings from map
13143101Sstever@eecs.umich.edu            cls.vals = list(cls.map.keys())
13153101Sstever@eecs.umich.edu            cls.vals.sort()
13163105Sstever@eecs.umich.edu        elif 'vals' in init_dict:
13173105Sstever@eecs.umich.edu            if not isinstance(cls.vals, list):
13183105Sstever@eecs.umich.edu                raise TypeError("Enum-derived class attribute 'vals' " \
13193105Sstever@eecs.umich.edu                      "must be of type list")
13203105Sstever@eecs.umich.edu            # build string->value map from vals sequence
13213105Sstever@eecs.umich.edu            cls.map = {}
13223105Sstever@eecs.umich.edu            for idx,val in enumerate(cls.vals):
13233105Sstever@eecs.umich.edu                cls.map[val] = idx
13243105Sstever@eecs.umich.edu        else:
13253105Sstever@eecs.umich.edu            raise TypeError("Enum-derived class must define "\
13263105Sstever@eecs.umich.edu                  "attribute 'map' or 'vals'")
13273101Sstever@eecs.umich.edu
13283101Sstever@eecs.umich.edu        if cls.is_class:
13297677Snate@binkert.org            cls.cxx_type = '%s' % name
13304762Snate@binkert.org        else:
13313101Sstever@eecs.umich.edu            cls.cxx_type = 'Enums::%s' % name
13323101Sstever@eecs.umich.edu
13333101Sstever@eecs.umich.edu        super(MetaEnum, cls).__init__(name, bases, init_dict)
13345578SSteve.Reinhardt@amd.com
13355578SSteve.Reinhardt@amd.com    # Generate C++ class declaration for this enum type.
13367526Ssteve.reinhardt@amd.com    # Note that we wrap the enum in a class/struct to act as a namespace,
13377526Ssteve.reinhardt@amd.com    # so that the enum strings can be brief w/o worrying about collisions.
13387526Ssteve.reinhardt@amd.com    def cxx_decl(cls, code):
13397526Ssteve.reinhardt@amd.com        wrapper_name = cls.wrapper_name
13407526Ssteve.reinhardt@amd.com        wrapper = 'struct' if cls.wrapper_is_struct else 'namespace'
13417526Ssteve.reinhardt@amd.com        name = cls.__name__ if cls.enum_name is None else cls.enum_name
13427526Ssteve.reinhardt@amd.com        idem_macro = '__ENUM__%s__%s__' % (wrapper_name, name)
13437526Ssteve.reinhardt@amd.com
13443101Sstever@eecs.umich.edu        code('''\
13453101Sstever@eecs.umich.edu#ifndef $idem_macro
13463101Sstever@eecs.umich.edu#define $idem_macro
13473105Sstever@eecs.umich.edu
13483105Sstever@eecs.umich.edu''')
13493105Sstever@eecs.umich.edu        if cls.is_class:
13503105Sstever@eecs.umich.edu            code('''\
13513105Sstever@eecs.umich.eduenum class $name {
13523105Sstever@eecs.umich.edu''')
13533105Sstever@eecs.umich.edu        else:
13543105Sstever@eecs.umich.edu            code('''\
13553105Sstever@eecs.umich.edu$wrapper $wrapper_name {
13563105Sstever@eecs.umich.edu    enum $name {
13573105Sstever@eecs.umich.edu''')
13583105Sstever@eecs.umich.edu            code.indent(1)
13593105Sstever@eecs.umich.edu        code.indent(1)
13603105Sstever@eecs.umich.edu        for val in cls.vals:
13613105Sstever@eecs.umich.edu            code('$val = ${{cls.map[val]}},')
13623105Sstever@eecs.umich.edu        code('Num_$name = ${{len(cls.vals)}}')
13633105Sstever@eecs.umich.edu        code.dedent(1)
13643105Sstever@eecs.umich.edu        code('};')
13653105Sstever@eecs.umich.edu
13663109Sstever@eecs.umich.edu        if cls.is_class:
13673109Sstever@eecs.umich.edu            code('''\
13683109Sstever@eecs.umich.eduextern const char *${name}Strings[static_cast<int>(${name}::Num_${name})];
13693105Sstever@eecs.umich.edu''')
13703105Sstever@eecs.umich.edu        elif cls.wrapper_is_struct:
13713105Sstever@eecs.umich.edu            code('static const char *${name}Strings[Num_${name}];')
13723105Sstever@eecs.umich.edu        else:
13733105Sstever@eecs.umich.edu            code('extern const char *${name}Strings[Num_${name}];')
13743105Sstever@eecs.umich.edu
13753105Sstever@eecs.umich.edu        if not cls.is_class:
13763105Sstever@eecs.umich.edu            code.dedent(1)
13773105Sstever@eecs.umich.edu            code('};')
13783105Sstever@eecs.umich.edu
13793105Sstever@eecs.umich.edu        code()
13803105Sstever@eecs.umich.edu        code('#endif // $idem_macro')
13813105Sstever@eecs.umich.edu
13823105Sstever@eecs.umich.edu    def cxx_def(cls, code):
13833105Sstever@eecs.umich.edu        wrapper_name = cls.wrapper_name
13843105Sstever@eecs.umich.edu        file_name = cls.__name__
13853105Sstever@eecs.umich.edu        name = cls.__name__ if cls.enum_name is None else cls.enum_name
13863105Sstever@eecs.umich.edu
13873105Sstever@eecs.umich.edu        code('#include "enums/$file_name.hh"')
13883105Sstever@eecs.umich.edu        if cls.wrapper_is_struct:
13893105Sstever@eecs.umich.edu            code('const char *${wrapper_name}::${name}Strings'
13903105Sstever@eecs.umich.edu                '[Num_${name}] =')
13913105Sstever@eecs.umich.edu        else:
13923109Sstever@eecs.umich.edu            if cls.is_class:
13933109Sstever@eecs.umich.edu                code('''\
13943109Sstever@eecs.umich.educonst char *${name}Strings[static_cast<int>(${name}::Num_${name})] =
13953109Sstever@eecs.umich.edu''')
13963109Sstever@eecs.umich.edu            else:
13973109Sstever@eecs.umich.edu                code('namespace Enums {')
13983109Sstever@eecs.umich.edu                code.indent(1)
13993109Sstever@eecs.umich.edu                code('const char *${name}Strings[Num_${name}] =')
14003109Sstever@eecs.umich.edu
14013109Sstever@eecs.umich.edu        code('{')
14023109Sstever@eecs.umich.edu        code.indent(1)
14033109Sstever@eecs.umich.edu        for val in cls.vals:
14043109Sstever@eecs.umich.edu            code('"$val",')
14053109Sstever@eecs.umich.edu        code.dedent(1)
14063109Sstever@eecs.umich.edu        code('};')
14073109Sstever@eecs.umich.edu
14083109Sstever@eecs.umich.edu        if not cls.wrapper_is_struct and not cls.is_class:
14093109Sstever@eecs.umich.edu            code.dedent(1)
14103109Sstever@eecs.umich.edu            code('} // namespace $wrapper_name')
14113105Sstever@eecs.umich.edu
14123105Sstever@eecs.umich.edu
14133105Sstever@eecs.umich.edu    def pybind_def(cls, code):
14143105Sstever@eecs.umich.edu        name = cls.__name__
14153105Sstever@eecs.umich.edu        enum_name = cls.__name__ if cls.enum_name is None else cls.enum_name
14163105Sstever@eecs.umich.edu        wrapper_name = enum_name if cls.is_class else cls.wrapper_name
14173105Sstever@eecs.umich.edu
14183101Sstever@eecs.umich.edu        code('''#include "pybind11/pybind11.h"
14193101Sstever@eecs.umich.edu#include "pybind11/stl.h"
14203101Sstever@eecs.umich.edu
14213101Sstever@eecs.umich.edu#include <sim/init.hh>
14223105Sstever@eecs.umich.edu
14233105Sstever@eecs.umich.edunamespace py = pybind11;
14243105Sstever@eecs.umich.edu
14253105Sstever@eecs.umich.edustatic void
14263105Sstever@eecs.umich.edumodule_init(py::module &m_internal)
14273105Sstever@eecs.umich.edu{
14283105Sstever@eecs.umich.edu    py::module m = m_internal.def_submodule("enum_${name}");
14293105Sstever@eecs.umich.edu
14303105Sstever@eecs.umich.edu''')
14313105Sstever@eecs.umich.edu        if cls.is_class:
14323105Sstever@eecs.umich.edu            code('py::enum_<${enum_name}>(m, "enum_${name}")')
14333101Sstever@eecs.umich.edu        else:
14343101Sstever@eecs.umich.edu            code('py::enum_<${wrapper_name}::${enum_name}>(m, "enum_${name}")')
14353101Sstever@eecs.umich.edu
14363105Sstever@eecs.umich.edu        code.indent()
14373105Sstever@eecs.umich.edu        code.indent()
14383101Sstever@eecs.umich.edu        for val in cls.vals:
14393101Sstever@eecs.umich.edu            code('.value("${val}", ${wrapper_name}::${val})')
14403101Sstever@eecs.umich.edu        code('.value("Num_${name}", ${wrapper_name}::Num_${enum_name})')
14413105Sstever@eecs.umich.edu        code('.export_values()')
14423105Sstever@eecs.umich.edu        code(';')
14433101Sstever@eecs.umich.edu        code.dedent()
14443101Sstever@eecs.umich.edu
14453101Sstever@eecs.umich.edu        code('}')
14463101Sstever@eecs.umich.edu        code.dedent()
14473105Sstever@eecs.umich.edu        code()
14483105Sstever@eecs.umich.edu        code('static EmbeddedPyBind embed_enum("enum_${name}", module_init);')
14493101Sstever@eecs.umich.edu
14503101Sstever@eecs.umich.edu
14513105Sstever@eecs.umich.edu# Base class for enum types.
14523105Sstever@eecs.umich.educlass Enum(ParamValue):
14533105Sstever@eecs.umich.edu    __metaclass__ = MetaEnum
14543109Sstever@eecs.umich.edu    vals = []
14553109Sstever@eecs.umich.edu    cmd_line_settable = True
14563109Sstever@eecs.umich.edu
14573109Sstever@eecs.umich.edu    # The name of the wrapping namespace or struct
14583109Sstever@eecs.umich.edu    wrapper_name = 'Enums'
14593109Sstever@eecs.umich.edu
14603109Sstever@eecs.umich.edu    # If true, the enum is wrapped in a struct rather than a namespace
14613109Sstever@eecs.umich.edu    wrapper_is_struct = False
14623105Sstever@eecs.umich.edu
14636654Snate@binkert.org    is_class = False
14646654Snate@binkert.org
14656654Snate@binkert.org    # If not None, use this as the enum name rather than this class name
14666654Snate@binkert.org    enum_name = None
14676654Snate@binkert.org
14686654Snate@binkert.org    def __init__(self, value):
14696654Snate@binkert.org        if value not in self.map:
14706654Snate@binkert.org            raise TypeError("Enum param got bad value '%s' (not in %s)" \
14716654Snate@binkert.org                  % (value, self.vals))
14723101Sstever@eecs.umich.edu        self.value = value
14733101Sstever@eecs.umich.edu
14743101Sstever@eecs.umich.edu    def __call__(self, value):
14753101Sstever@eecs.umich.edu        self.__init__(value)
14763101Sstever@eecs.umich.edu        return value
14773101Sstever@eecs.umich.edu
14787777Sgblack@eecs.umich.edu    @classmethod
14793101Sstever@eecs.umich.edu    def cxx_predecls(cls, code):
14804167Sbinkertn@umich.edu        code('#include "enums/$0.hh"', cls.__name__)
14813101Sstever@eecs.umich.edu
14823101Sstever@eecs.umich.edu    @classmethod
14833101Sstever@eecs.umich.edu    def cxx_ini_parse(cls, code, src, dest, ret):
14843885Sbinkertn@umich.edu        code('if (false) {')
14853102Sstever@eecs.umich.edu        for elem_name in cls.map.keys():
14863101Sstever@eecs.umich.edu            code('} else if (%s == "%s") {' % (src, elem_name))
14876654Snate@binkert.org            code.indent()
14886654Snate@binkert.org            name = cls.__name__ if cls.enum_name is None else cls.enum_name
1489            code('%s = %s::%s;' % (dest, name if cls.is_class else 'Enums',
1490                                   elem_name))
1491            code('%s true;' % ret)
1492            code.dedent()
1493        code('} else {')
1494        code('    %s false;' % ret)
1495        code('}')
1496
1497    def getValue(self):
1498        import m5.internal.params
1499        e = getattr(m5.internal.params, "enum_%s" % self.__class__.__name__)
1500        return e(self.map[self.value])
1501
1502    def __str__(self):
1503        return self.value
1504
1505# This param will generate a scoped c++ enum and its python bindings.
1506class ScopedEnum(Enum):
1507    __metaclass__ = MetaEnum
1508    vals = []
1509    cmd_line_settable = True
1510
1511    # The name of the wrapping namespace or struct
1512    wrapper_name = None
1513
1514    # If true, the enum is wrapped in a struct rather than a namespace
1515    wrapper_is_struct = False
1516
1517    # If true, the generated enum is a scoped enum
1518    is_class = True
1519
1520    # If not None, use this as the enum name rather than this class name
1521    enum_name = None
1522
1523# how big does a rounding error need to be before we warn about it?
1524frequency_tolerance = 0.001  # 0.1%
1525
1526class TickParamValue(NumericParamValue):
1527    cxx_type = 'Tick'
1528    ex_str = "1MHz"
1529    cmd_line_settable = True
1530
1531    @classmethod
1532    def cxx_predecls(cls, code):
1533        code('#include "base/types.hh"')
1534
1535    def __call__(self, value):
1536        self.__init__(value)
1537        return value
1538
1539    def getValue(self):
1540        return long(self.value)
1541
1542    @classmethod
1543    def cxx_ini_predecls(cls, code):
1544        code('#include <sstream>')
1545
1546    # Ticks are expressed in seconds in JSON files and in plain
1547    # Ticks in .ini files.  Switch based on a config flag
1548    @classmethod
1549    def cxx_ini_parse(self, code, src, dest, ret):
1550        code('${ret} to_number(${src}, ${dest});')
1551
1552class Latency(TickParamValue):
1553    ex_str = "100ns"
1554
1555    def __init__(self, value):
1556        if isinstance(value, (Latency, Clock)):
1557            self.ticks = value.ticks
1558            self.value = value.value
1559        elif isinstance(value, Frequency):
1560            self.ticks = value.ticks
1561            self.value = 1.0 / value.value
1562        elif value.endswith('t'):
1563            self.ticks = True
1564            self.value = int(value[:-1])
1565        else:
1566            self.ticks = False
1567            self.value = convert.toLatency(value)
1568
1569    def __call__(self, value):
1570        self.__init__(value)
1571        return value
1572
1573    def __getattr__(self, attr):
1574        if attr in ('latency', 'period'):
1575            return self
1576        if attr == 'frequency':
1577            return Frequency(self)
1578        raise AttributeError("Latency object has no attribute '%s'" % attr)
1579
1580    def getValue(self):
1581        if self.ticks or self.value == 0:
1582            value = self.value
1583        else:
1584            value = ticks.fromSeconds(self.value)
1585        return long(value)
1586
1587    def config_value(self):
1588        return self.getValue()
1589
1590    # convert latency to ticks
1591    def ini_str(self):
1592        return '%d' % self.getValue()
1593
1594class Frequency(TickParamValue):
1595    ex_str = "1GHz"
1596
1597    def __init__(self, value):
1598        if isinstance(value, (Latency, Clock)):
1599            if value.value == 0:
1600                self.value = 0
1601            else:
1602                self.value = 1.0 / value.value
1603            self.ticks = value.ticks
1604        elif isinstance(value, Frequency):
1605            self.value = value.value
1606            self.ticks = value.ticks
1607        else:
1608            self.ticks = False
1609            self.value = convert.toFrequency(value)
1610
1611    def __call__(self, value):
1612        self.__init__(value)
1613        return value
1614
1615    def __getattr__(self, attr):
1616        if attr == 'frequency':
1617            return self
1618        if attr in ('latency', 'period'):
1619            return Latency(self)
1620        raise AttributeError("Frequency object has no attribute '%s'" % attr)
1621
1622    # convert latency to ticks
1623    def getValue(self):
1624        if self.ticks or self.value == 0:
1625            value = self.value
1626        else:
1627            value = ticks.fromSeconds(1.0 / self.value)
1628        return long(value)
1629
1630    def config_value(self):
1631        return self.getValue()
1632
1633    def ini_str(self):
1634        return '%d' % self.getValue()
1635
1636# A generic Frequency and/or Latency value. Value is stored as a
1637# latency, just like Latency and Frequency.
1638class Clock(TickParamValue):
1639    def __init__(self, value):
1640        if isinstance(value, (Latency, Clock)):
1641            self.ticks = value.ticks
1642            self.value = value.value
1643        elif isinstance(value, Frequency):
1644            self.ticks = value.ticks
1645            self.value = 1.0 / value.value
1646        elif value.endswith('t'):
1647            self.ticks = True
1648            self.value = int(value[:-1])
1649        else:
1650            self.ticks = False
1651            self.value = convert.anyToLatency(value)
1652
1653    def __call__(self, value):
1654        self.__init__(value)
1655        return value
1656
1657    def __str__(self):
1658        return "%s" % Latency(self)
1659
1660    def __getattr__(self, attr):
1661        if attr == 'frequency':
1662            return Frequency(self)
1663        if attr in ('latency', 'period'):
1664            return Latency(self)
1665        raise AttributeError("Frequency object has no attribute '%s'" % attr)
1666
1667    def getValue(self):
1668        return self.period.getValue()
1669
1670    def config_value(self):
1671        return self.period.config_value()
1672
1673    def ini_str(self):
1674        return self.period.ini_str()
1675
1676class Voltage(Float):
1677    ex_str = "1V"
1678
1679    def __new__(cls, value):
1680        value = convert.toVoltage(value)
1681        return super(cls, Voltage).__new__(cls, value)
1682
1683    def __init__(self, value):
1684        value = convert.toVoltage(value)
1685        super(Voltage, self).__init__(value)
1686
1687class Current(Float):
1688    ex_str = "1mA"
1689
1690    def __new__(cls, value):
1691        value = convert.toCurrent(value)
1692        return super(cls, Current).__new__(cls, value)
1693
1694    def __init__(self, value):
1695        value = convert.toCurrent(value)
1696        super(Current, self).__init__(value)
1697
1698class Energy(Float):
1699    ex_str = "1pJ"
1700
1701    def __new__(cls, value):
1702        value = convert.toEnergy(value)
1703        return super(cls, Energy).__new__(cls, value)
1704
1705    def __init__(self, value):
1706        value = convert.toEnergy(value)
1707        super(Energy, self).__init__(value)
1708
1709class NetworkBandwidth(float,ParamValue):
1710    cxx_type = 'float'
1711    ex_str = "1Gbps"
1712    cmd_line_settable = True
1713
1714    def __new__(cls, value):
1715        # convert to bits per second
1716        val = convert.toNetworkBandwidth(value)
1717        return super(cls, NetworkBandwidth).__new__(cls, val)
1718
1719    def __str__(self):
1720        return str(self.val)
1721
1722    def __call__(self, value):
1723        val = convert.toNetworkBandwidth(value)
1724        self.__init__(val)
1725        return value
1726
1727    def getValue(self):
1728        # convert to seconds per byte
1729        value = 8.0 / float(self)
1730        # convert to ticks per byte
1731        value = ticks.fromSeconds(value)
1732        return float(value)
1733
1734    def ini_str(self):
1735        return '%f' % self.getValue()
1736
1737    def config_value(self):
1738        return '%f' % self.getValue()
1739
1740    @classmethod
1741    def cxx_ini_predecls(cls, code):
1742        code('#include <sstream>')
1743
1744    @classmethod
1745    def cxx_ini_parse(self, code, src, dest, ret):
1746        code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
1747
1748class MemoryBandwidth(float,ParamValue):
1749    cxx_type = 'float'
1750    ex_str = "1GB/s"
1751    cmd_line_settable = True
1752
1753    def __new__(cls, value):
1754        # convert to bytes per second
1755        val = convert.toMemoryBandwidth(value)
1756        return super(cls, MemoryBandwidth).__new__(cls, val)
1757
1758    def __call__(self, value):
1759        val = convert.toMemoryBandwidth(value)
1760        self.__init__(val)
1761        return value
1762
1763    def getValue(self):
1764        # convert to seconds per byte
1765        value = float(self)
1766        if value:
1767            value = 1.0 / float(self)
1768        # convert to ticks per byte
1769        value = ticks.fromSeconds(value)
1770        return float(value)
1771
1772    def ini_str(self):
1773        return '%f' % self.getValue()
1774
1775    def config_value(self):
1776        return '%f' % self.getValue()
1777
1778    @classmethod
1779    def cxx_ini_predecls(cls, code):
1780        code('#include <sstream>')
1781
1782    @classmethod
1783    def cxx_ini_parse(self, code, src, dest, ret):
1784        code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
1785
1786#
1787# "Constants"... handy aliases for various values.
1788#
1789
1790# Special class for NULL pointers.  Note the special check in
1791# make_param_value() above that lets these be assigned where a
1792# SimObject is required.
1793# only one copy of a particular node
1794class NullSimObject(object):
1795    __metaclass__ = Singleton
1796    _name = 'Null'
1797
1798    def __call__(cls):
1799        return cls
1800
1801    def _instantiate(self, parent = None, path = ''):
1802        pass
1803
1804    def ini_str(self):
1805        return 'Null'
1806
1807    def unproxy(self, base):
1808        return self
1809
1810    def set_path(self, parent, name):
1811        pass
1812
1813    def set_parent(self, parent, name):
1814        pass
1815
1816    def clear_parent(self, old_parent):
1817        pass
1818
1819    def descendants(self):
1820        return
1821        yield None
1822
1823    def get_config_as_dict(self):
1824        return {}
1825
1826    def __str__(self):
1827        return self._name
1828
1829    def config_value(self):
1830        return None
1831
1832    def getValue(self):
1833        return None
1834
1835# The only instance you'll ever need...
1836NULL = NullSimObject()
1837
1838def isNullPointer(value):
1839    return isinstance(value, NullSimObject)
1840
1841# Some memory range specifications use this as a default upper bound.
1842MaxAddr = Addr.max
1843MaxTick = Tick.max
1844AllMemory = AddrRange(0, MaxAddr)
1845
1846
1847#####################################################################
1848#
1849# Port objects
1850#
1851# Ports are used to interconnect objects in the memory system.
1852#
1853#####################################################################
1854
1855# Port reference: encapsulates a reference to a particular port on a
1856# particular SimObject.
1857class PortRef(object):
1858    def __init__(self, simobj, name, role, is_source):
1859        assert(isSimObject(simobj) or isSimObjectClass(simobj))
1860        self.simobj = simobj
1861        self.name = name
1862        self.role = role
1863        self.is_source = is_source
1864        self.peer = None   # not associated with another port yet
1865        self.ccConnected = False # C++ port connection done?
1866        self.index = -1  # always -1 for non-vector ports
1867
1868    def __str__(self):
1869        return '%s.%s' % (self.simobj, self.name)
1870
1871    def __len__(self):
1872        # Return the number of connected ports, i.e. 0 is we have no
1873        # peer and 1 if we do.
1874        return int(self.peer != None)
1875
1876    # for config.ini, print peer's name (not ours)
1877    def ini_str(self):
1878        return str(self.peer)
1879
1880    # for config.json
1881    def get_config_as_dict(self):
1882        return {'role' : self.role, 'peer' : str(self.peer),
1883                'is_source' : str(self.is_source)}
1884
1885    def __getattr__(self, attr):
1886        if attr == 'peerObj':
1887            # shorthand for proxies
1888            return self.peer.simobj
1889        raise AttributeError("'%s' object has no attribute '%s'" % \
1890              (self.__class__.__name__, attr))
1891
1892    # Full connection is symmetric (both ways).  Called via
1893    # SimObject.__setattr__ as a result of a port assignment, e.g.,
1894    # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
1895    # e.g., "obj1.portA[3] = obj2.portB".
1896    def connect(self, other):
1897        if isinstance(other, VectorPortRef):
1898            # reference to plain VectorPort is implicit append
1899            other = other._get_next()
1900        if self.peer and not proxy.isproxy(self.peer):
1901            fatal("Port %s is already connected to %s, cannot connect %s\n",
1902                  self, self.peer, other);
1903        self.peer = other
1904
1905        if proxy.isproxy(other):
1906            other.set_param_desc(PortParamDesc())
1907            return
1908        elif not isinstance(other, PortRef):
1909            raise TypeError("assigning non-port reference '%s' to port '%s'" \
1910                  % (other, self))
1911
1912        if not Port.is_compat(self, other):
1913            fatal("Ports %s and %s with roles '%s' and '%s' "
1914                    "are not compatible", self, other, self.role, other.role)
1915
1916        if other.peer is not self:
1917            other.connect(self)
1918
1919    # Allow a compatible port pair to be spliced between a port and its
1920    # connected peer. Useful operation for connecting instrumentation
1921    # structures into a system when it is necessary to connect the
1922    # instrumentation after the full system has been constructed.
1923    def splice(self, new_1, new_2):
1924        if not self.peer or proxy.isproxy(self.peer):
1925            fatal("Port %s not connected, cannot splice in new peers\n", self)
1926
1927        if not isinstance(new_1, PortRef) or not isinstance(new_2, PortRef):
1928            raise TypeError(
1929                  "Splicing non-port references '%s','%s' to port '%s'" % \
1930                  (new_1, new_2, self))
1931
1932        old_peer = self.peer
1933
1934        if Port.is_compat(old_peer, new_1) and Port.is_compat(self, new_2):
1935            old_peer.peer = new_1
1936            new_1.peer = old_peer
1937            self.peer = new_2
1938            new_2.peer = self
1939        elif Port.is_compat(old_peer, new_2) and Port.is_compat(self, new_1):
1940            old_peer.peer = new_2
1941            new_2.peer = old_peer
1942            self.peer = new_1
1943            new_1.peer = self
1944        else:
1945            fatal("Ports %s(%s) and %s(%s) can't be compatibly spliced with "
1946                    "%s(%s) and %s(%s)", self, self.role,
1947                    old_peer, old_peer.role, new_1, new_1.role,
1948                    new_2, new_2.role)
1949
1950    def clone(self, simobj, memo):
1951        if self in memo:
1952            return memo[self]
1953        newRef = copy.copy(self)
1954        memo[self] = newRef
1955        newRef.simobj = simobj
1956        assert(isSimObject(newRef.simobj))
1957        if self.peer and not proxy.isproxy(self.peer):
1958            peerObj = self.peer.simobj(_memo=memo)
1959            newRef.peer = self.peer.clone(peerObj, memo)
1960            assert(not isinstance(newRef.peer, VectorPortRef))
1961        return newRef
1962
1963    def unproxy(self, simobj):
1964        assert(simobj is self.simobj)
1965        if proxy.isproxy(self.peer):
1966            try:
1967                realPeer = self.peer.unproxy(self.simobj)
1968            except:
1969                print("Error in unproxying port '%s' of %s" %
1970                      (self.name, self.simobj.path()))
1971                raise
1972            self.connect(realPeer)
1973
1974    # Call C++ to create corresponding port connection between C++ objects
1975    def ccConnect(self):
1976        if self.ccConnected: # already done this
1977            return
1978
1979        peer = self.peer
1980        if not self.peer: # nothing to connect to
1981            return
1982
1983        port = self.simobj.getPort(self.name, self.index)
1984        peer_port = peer.simobj.getPort(peer.name, peer.index)
1985        port.bind(peer_port)
1986
1987        self.ccConnected = True
1988
1989# A reference to an individual element of a VectorPort... much like a
1990# PortRef, but has an index.
1991class VectorPortElementRef(PortRef):
1992    def __init__(self, simobj, name, role, is_source, index):
1993        PortRef.__init__(self, simobj, name, role, is_source)
1994        self.index = index
1995
1996    def __str__(self):
1997        return '%s.%s[%d]' % (self.simobj, self.name, self.index)
1998
1999# A reference to a complete vector-valued port (not just a single element).
2000# Can be indexed to retrieve individual VectorPortElementRef instances.
2001class VectorPortRef(object):
2002    def __init__(self, simobj, name, role, is_source):
2003        assert(isSimObject(simobj) or isSimObjectClass(simobj))
2004        self.simobj = simobj
2005        self.name = name
2006        self.role = role
2007        self.is_source = is_source
2008        self.elements = []
2009
2010    def __str__(self):
2011        return '%s.%s[:]' % (self.simobj, self.name)
2012
2013    def __len__(self):
2014        # Return the number of connected peers, corresponding the the
2015        # length of the elements.
2016        return len(self.elements)
2017
2018    # for config.ini, print peer's name (not ours)
2019    def ini_str(self):
2020        return ' '.join([el.ini_str() for el in self.elements])
2021
2022    # for config.json
2023    def get_config_as_dict(self):
2024        return {'role' : self.role,
2025                'peer' : [el.ini_str() for el in self.elements],
2026                'is_source' : str(self.is_source)}
2027
2028    def __getitem__(self, key):
2029        if not isinstance(key, int):
2030            raise TypeError("VectorPort index must be integer")
2031        if key >= len(self.elements):
2032            # need to extend list
2033            ext = [VectorPortElementRef(
2034                    self.simobj, self.name, self.role, self.is_source, i)
2035                   for i in range(len(self.elements), key+1)]
2036            self.elements.extend(ext)
2037        return self.elements[key]
2038
2039    def _get_next(self):
2040        return self[len(self.elements)]
2041
2042    def __setitem__(self, key, value):
2043        if not isinstance(key, int):
2044            raise TypeError("VectorPort index must be integer")
2045        self[key].connect(value)
2046
2047    def connect(self, other):
2048        if isinstance(other, (list, tuple)):
2049            # Assign list of port refs to vector port.
2050            # For now, append them... not sure if that's the right semantics
2051            # or if it should replace the current vector.
2052            for ref in other:
2053                self._get_next().connect(ref)
2054        else:
2055            # scalar assignment to plain VectorPort is implicit append
2056            self._get_next().connect(other)
2057
2058    def clone(self, simobj, memo):
2059        if self in memo:
2060            return memo[self]
2061        newRef = copy.copy(self)
2062        memo[self] = newRef
2063        newRef.simobj = simobj
2064        assert(isSimObject(newRef.simobj))
2065        newRef.elements = [el.clone(simobj, memo) for el in self.elements]
2066        return newRef
2067
2068    def unproxy(self, simobj):
2069        [el.unproxy(simobj) for el in self.elements]
2070
2071    def ccConnect(self):
2072        [el.ccConnect() for el in self.elements]
2073
2074# Port description object.  Like a ParamDesc object, this represents a
2075# logical port in the SimObject class, not a particular port on a
2076# SimObject instance.  The latter are represented by PortRef objects.
2077class Port(object):
2078    # Port("role", "description")
2079
2080    _compat_dict = { }
2081
2082    @classmethod
2083    def compat(cls, role, peer):
2084        cls._compat_dict.setdefault(role, set()).add(peer)
2085        cls._compat_dict.setdefault(peer, set()).add(role)
2086
2087    @classmethod
2088    def is_compat(cls, one, two):
2089        for port in one, two:
2090            if not port.role in Port._compat_dict:
2091                fatal("Unrecognized role '%s' for port %s\n", port.role, port)
2092        return one.role in Port._compat_dict[two.role]
2093
2094    def __init__(self, role, desc, is_source=False):
2095        self.desc = desc
2096        self.role = role
2097        self.is_source = is_source
2098
2099    # Generate a PortRef for this port on the given SimObject with the
2100    # given name
2101    def makeRef(self, simobj):
2102        return PortRef(simobj, self.name, self.role, self.is_source)
2103
2104    # Connect an instance of this port (on the given SimObject with
2105    # the given name) with the port described by the supplied PortRef
2106    def connect(self, simobj, ref):
2107        self.makeRef(simobj).connect(ref)
2108
2109    # No need for any pre-declarations at the moment as we merely rely
2110    # on an unsigned int.
2111    def cxx_predecls(self, code):
2112        pass
2113
2114    def pybind_predecls(self, code):
2115        cls.cxx_predecls(self, code)
2116
2117    # Declare an unsigned int with the same name as the port, that
2118    # will eventually hold the number of connected ports (and thus the
2119    # number of elements for a VectorPort).
2120    def cxx_decl(self, code):
2121        code('unsigned int port_${{self.name}}_connection_count;')
2122
2123Port.compat('GEM5 REQUESTER', 'GEM5 RESPONDER')
2124
2125class RequestPort(Port):
2126    # RequestPort("description")
2127    def __init__(self, desc):
2128        super(RequestPort, self).__init__(
2129                'GEM5 REQUESTER', desc, is_source=True)
2130
2131class ResponsePort(Port):
2132    # ResponsePort("description")
2133    def __init__(self, desc):
2134        super(ResponsePort, self).__init__('GEM5 RESPONDER', desc)
2135
2136# VectorPort description object.  Like Port, but represents a vector
2137# of connections (e.g., as on a XBar).
2138class VectorPort(Port):
2139    def makeRef(self, simobj):
2140        return VectorPortRef(simobj, self.name, self.role, self.is_source)
2141
2142class VectorRequestPort(VectorPort):
2143    # VectorRequestPort("description")
2144    def __init__(self, desc):
2145        super(VectorRequestPort, self).__init__(
2146                'GEM5 REQUESTER', desc, is_source=True)
2147
2148class VectorResponsePort(VectorPort):
2149    # VectorResponsePort("description")
2150    def __init__(self, desc):
2151        super(VectorResponsePort, self).__init__('GEM5 RESPONDER', desc)
2152
2153# Old names, maintained for compatibility.
2154MasterPort = RequestPort
2155SlavePort = ResponsePort
2156VectorMasterPort = VectorRequestPort
2157VectorSlavePort = VectorResponsePort
2158
2159# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
2160# proxy objects (via set_param_desc()) so that proxy error messages
2161# make sense.
2162class PortParamDesc(object):
2163    __metaclass__ = Singleton
2164
2165    ptype_str = 'Port'
2166    ptype = Port
2167
2168baseEnums = allEnums.copy()
2169baseParams = allParams.copy()
2170
2171def clear():
2172    global allEnums, allParams
2173
2174    allEnums = baseEnums.copy()
2175    allParams = baseParams.copy()
2176
2177__all__ = ['Param', 'VectorParam',
2178           'Enum', 'ScopedEnum', 'Bool', 'String', 'Float',
2179           'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
2180           'Int32', 'UInt32', 'Int64', 'UInt64',
2181           'Counter', 'Addr', 'Tick', 'Percent',
2182           'TcpPort', 'UdpPort', 'EthernetAddr',
2183           'IpAddress', 'IpNetmask', 'IpWithPort',
2184           'MemorySize', 'MemorySize32',
2185           'Latency', 'Frequency', 'Clock', 'Voltage', 'Current', 'Energy',
2186           'NetworkBandwidth', 'MemoryBandwidth',
2187           'AddrRange',
2188           'MaxAddr', 'MaxTick', 'AllMemory',
2189           'Time',
2190           'NextEthernetAddr', 'NULL',
2191           'Port', 'RequestPort', 'ResponsePort', 'MasterPort', 'SlavePort',
2192           'VectorPort', 'VectorRequestPort', 'VectorResponsePort',
2193           'VectorMasterPort', 'VectorSlavePort']
2194