params.py revision 13542:5e914b841659
18839Sandreas.hansson@arm.com# Copyright (c) 2012-2014, 2017 ARM Limited
28839Sandreas.hansson@arm.com# All rights reserved.
38839Sandreas.hansson@arm.com#
48839Sandreas.hansson@arm.com# The license below extends only to copyright in the software and shall
58839Sandreas.hansson@arm.com# not be construed as granting a license to any other intellectual
68839Sandreas.hansson@arm.com# property including but not limited to intellectual property relating
78839Sandreas.hansson@arm.com# to a hardware implementation of the functionality of the software
88839Sandreas.hansson@arm.com# licensed hereunder.  You may use the software subject to the license
98839Sandreas.hansson@arm.com# terms below provided that you ensure that this notice is replicated
108839Sandreas.hansson@arm.com# unmodified and in its entirety in all distributions of the software,
118839Sandreas.hansson@arm.com# modified or unmodified, in source code or in binary form.
128839Sandreas.hansson@arm.com#
133101Sstever@eecs.umich.edu# Copyright (c) 2004-2006 The Regents of The University of Michigan
148579Ssteve.reinhardt@amd.com# Copyright (c) 2010-2011 Advanced Micro Devices, Inc.
153101Sstever@eecs.umich.edu# All rights reserved.
163101Sstever@eecs.umich.edu#
173101Sstever@eecs.umich.edu# Redistribution and use in source and binary forms, with or without
183101Sstever@eecs.umich.edu# modification, are permitted provided that the following conditions are
193101Sstever@eecs.umich.edu# met: redistributions of source code must retain the above copyright
203101Sstever@eecs.umich.edu# notice, this list of conditions and the following disclaimer;
213101Sstever@eecs.umich.edu# redistributions in binary form must reproduce the above copyright
223101Sstever@eecs.umich.edu# notice, this list of conditions and the following disclaimer in the
233101Sstever@eecs.umich.edu# documentation and/or other materials provided with the distribution;
243101Sstever@eecs.umich.edu# neither the name of the copyright holders nor the names of its
253101Sstever@eecs.umich.edu# contributors may be used to endorse or promote products derived from
263101Sstever@eecs.umich.edu# this software without specific prior written permission.
273101Sstever@eecs.umich.edu#
283101Sstever@eecs.umich.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
293101Sstever@eecs.umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
303101Sstever@eecs.umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
313101Sstever@eecs.umich.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
323101Sstever@eecs.umich.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
333101Sstever@eecs.umich.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
343101Sstever@eecs.umich.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
353101Sstever@eecs.umich.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
363101Sstever@eecs.umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
373101Sstever@eecs.umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
383101Sstever@eecs.umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
393101Sstever@eecs.umich.edu#
403101Sstever@eecs.umich.edu# Authors: Steve Reinhardt
413101Sstever@eecs.umich.edu#          Nathan Binkert
427778Sgblack@eecs.umich.edu#          Gabe Black
438839Sandreas.hansson@arm.com#          Andreas Hansson
443101Sstever@eecs.umich.edu
453101Sstever@eecs.umich.edu#####################################################################
463101Sstever@eecs.umich.edu#
473101Sstever@eecs.umich.edu# Parameter description classes
483101Sstever@eecs.umich.edu#
493101Sstever@eecs.umich.edu# The _params dictionary in each class maps parameter names to either
503101Sstever@eecs.umich.edu# a Param or a VectorParam object.  These objects contain the
513101Sstever@eecs.umich.edu# parameter description string, the parameter type, and the default
523101Sstever@eecs.umich.edu# value (if any).  The convert() method on these objects is used to
533101Sstever@eecs.umich.edu# force whatever value is assigned to the parameter to the appropriate
543101Sstever@eecs.umich.edu# type.
553101Sstever@eecs.umich.edu#
563101Sstever@eecs.umich.edu# Note that the default values are loaded into the class's attribute
573101Sstever@eecs.umich.edu# space when the parameter dictionary is initialized (in
583101Sstever@eecs.umich.edu# MetaSimObject._new_param()); after that point they aren't used.
593101Sstever@eecs.umich.edu#
603101Sstever@eecs.umich.edu#####################################################################
613101Sstever@eecs.umich.edu
623885Sbinkertn@umich.edufrom __future__ import print_function
633885Sbinkertn@umich.edu
644762Snate@binkert.orgimport copy
653885Sbinkertn@umich.eduimport datetime
663885Sbinkertn@umich.eduimport re
677528Ssteve.reinhardt@amd.comimport sys
683885Sbinkertn@umich.eduimport time
694380Sbinkertn@umich.eduimport math
704167Sbinkertn@umich.edu
713102Sstever@eecs.umich.eduimport proxy
723101Sstever@eecs.umich.eduimport ticks
734762Snate@binkert.orgfrom util import *
744762Snate@binkert.org
754762Snate@binkert.orgdef isSimObject(*args, **kwargs):
764762Snate@binkert.org    return SimObject.isSimObject(*args, **kwargs)
774762Snate@binkert.org
784762Snate@binkert.orgdef isSimObjectSequence(*args, **kwargs):
794762Snate@binkert.org    return SimObject.isSimObjectSequence(*args, **kwargs)
804762Snate@binkert.org
814762Snate@binkert.orgdef isSimObjectClass(*args, **kwargs):
825033Smilesck@eecs.umich.edu    return SimObject.isSimObjectClass(*args, **kwargs)
835033Smilesck@eecs.umich.edu
845033Smilesck@eecs.umich.eduallParams = {}
855033Smilesck@eecs.umich.edu
865033Smilesck@eecs.umich.educlass MetaParamValue(type):
875033Smilesck@eecs.umich.edu    def __new__(mcls, name, bases, dct):
885033Smilesck@eecs.umich.edu        cls = super(MetaParamValue, mcls).__new__(mcls, name, bases, dct)
895033Smilesck@eecs.umich.edu        assert name not in allParams
905033Smilesck@eecs.umich.edu        allParams[name] = cls
915033Smilesck@eecs.umich.edu        return cls
923101Sstever@eecs.umich.edu
933101Sstever@eecs.umich.edu
943101Sstever@eecs.umich.edu# Dummy base class to identify types that are legitimate for SimObject
955033Smilesck@eecs.umich.edu# parameters.
963101Sstever@eecs.umich.educlass ParamValue(object):
978596Ssteve.reinhardt@amd.com    __metaclass__ = MetaParamValue
988596Ssteve.reinhardt@amd.com    cmd_line_settable = False
998596Ssteve.reinhardt@amd.com
1008596Ssteve.reinhardt@amd.com    # Generate the code needed as a prerequisite for declaring a C++
1017673Snate@binkert.org    # object of this type.  Typically generates one or more #include
1027673Snate@binkert.org    # statements.  Used when declaring parameters of this type.
1037673Snate@binkert.org    @classmethod
1047673Snate@binkert.org    def cxx_predecls(cls, code):
1058596Ssteve.reinhardt@amd.com        pass
1068596Ssteve.reinhardt@amd.com
1078596Ssteve.reinhardt@amd.com    @classmethod
1087673Snate@binkert.org    def pybind_predecls(cls, code):
1097673Snate@binkert.org        cls.cxx_predecls(code)
1107673Snate@binkert.org
1113101Sstever@eecs.umich.edu    # default for printing to .ini file is regular string conversion.
1123101Sstever@eecs.umich.edu    # will be overridden in some cases
1133101Sstever@eecs.umich.edu    def ini_str(self):
1143101Sstever@eecs.umich.edu        return str(self)
1153101Sstever@eecs.umich.edu
1163101Sstever@eecs.umich.edu    # default for printing to .json file is regular string conversion.
1173101Sstever@eecs.umich.edu    # will be overridden in some cases, mostly to use native Python
1183101Sstever@eecs.umich.edu    # types where there are similar JSON types
1193101Sstever@eecs.umich.edu    def config_value(self):
1203101Sstever@eecs.umich.edu        return str(self)
1213101Sstever@eecs.umich.edu
1223101Sstever@eecs.umich.edu    # Prerequisites for .ini parsing with cxx_ini_parse
1233101Sstever@eecs.umich.edu    @classmethod
1243101Sstever@eecs.umich.edu    def cxx_ini_predecls(cls, code):
1253101Sstever@eecs.umich.edu        pass
1263101Sstever@eecs.umich.edu
1273101Sstever@eecs.umich.edu    # parse a .ini file entry for this param from string expression
1283101Sstever@eecs.umich.edu    # src into lvalue dest (of the param's C++ type)
1293101Sstever@eecs.umich.edu    @classmethod
1303101Sstever@eecs.umich.edu    def cxx_ini_parse(cls, code, src, dest, ret):
1313101Sstever@eecs.umich.edu        code('// Unhandled param type: %s' % cls.__name__)
1323101Sstever@eecs.umich.edu        code('%s false;' % ret)
1333101Sstever@eecs.umich.edu
1343101Sstever@eecs.umich.edu    # allows us to blithely call unproxy() on things without checking
1353101Sstever@eecs.umich.edu    # if they're really proxies or not
1363101Sstever@eecs.umich.edu    def unproxy(self, base):
1373101Sstever@eecs.umich.edu        return self
1383101Sstever@eecs.umich.edu
1393101Sstever@eecs.umich.edu    # Produce a human readable version of the stored value
1403101Sstever@eecs.umich.edu    def pretty_print(self, value):
1413101Sstever@eecs.umich.edu        return str(value)
1423101Sstever@eecs.umich.edu
1433101Sstever@eecs.umich.edu# Regular parameter description.
1443101Sstever@eecs.umich.educlass ParamDesc(object):
1453101Sstever@eecs.umich.edu    def __init__(self, ptype_str, ptype, *args, **kwargs):
1463101Sstever@eecs.umich.edu        self.ptype_str = ptype_str
1473101Sstever@eecs.umich.edu        # remember ptype only if it is provided
1483101Sstever@eecs.umich.edu        if ptype != None:
1493101Sstever@eecs.umich.edu            self.ptype = ptype
1503101Sstever@eecs.umich.edu
1513101Sstever@eecs.umich.edu        if args:
1523101Sstever@eecs.umich.edu            if len(args) == 1:
1533101Sstever@eecs.umich.edu                self.desc = args[0]
1543101Sstever@eecs.umich.edu            elif len(args) == 2:
1553101Sstever@eecs.umich.edu                self.default = args[0]
1563101Sstever@eecs.umich.edu                self.desc = args[1]
1575033Smilesck@eecs.umich.edu            else:
1586656Snate@binkert.org                raise TypeError, 'too many arguments'
1595033Smilesck@eecs.umich.edu
1605033Smilesck@eecs.umich.edu        if kwargs.has_key('desc'):
1615033Smilesck@eecs.umich.edu            assert(not hasattr(self, 'desc'))
1623101Sstever@eecs.umich.edu            self.desc = kwargs['desc']
1633101Sstever@eecs.umich.edu            del kwargs['desc']
1643101Sstever@eecs.umich.edu
1653101Sstever@eecs.umich.edu        if kwargs.has_key('default'):
1663101Sstever@eecs.umich.edu            assert(not hasattr(self, 'default'))
1673101Sstever@eecs.umich.edu            self.default = kwargs['default']
1683101Sstever@eecs.umich.edu            del kwargs['default']
1693101Sstever@eecs.umich.edu
1703101Sstever@eecs.umich.edu        if kwargs:
1713101Sstever@eecs.umich.edu            raise TypeError, 'extra unknown kwargs %s' % kwargs
1723101Sstever@eecs.umich.edu
1733101Sstever@eecs.umich.edu        if not hasattr(self, 'desc'):
1743101Sstever@eecs.umich.edu            raise TypeError, 'desc attribute missing'
1753102Sstever@eecs.umich.edu
1763101Sstever@eecs.umich.edu    def __getattr__(self, attr):
1773101Sstever@eecs.umich.edu        if attr == 'ptype':
1783101Sstever@eecs.umich.edu            ptype = SimObject.allClasses[self.ptype_str]
1797673Snate@binkert.org            assert isSimObjectClass(ptype)
1808607Sgblack@eecs.umich.edu            self.ptype = ptype
1817673Snate@binkert.org            return ptype
1823101Sstever@eecs.umich.edu
1837673Snate@binkert.org        raise AttributeError, "'%s' object has no attribute '%s'" % \
1847673Snate@binkert.org              (type(self).__name__, attr)
1853101Sstever@eecs.umich.edu
1867673Snate@binkert.org    def example_str(self):
1877673Snate@binkert.org        if hasattr(self.ptype, "ex_str"):
1883101Sstever@eecs.umich.edu            return self.ptype.ex_str
1893101Sstever@eecs.umich.edu        else:
1903101Sstever@eecs.umich.edu            return self.ptype_str
1913101Sstever@eecs.umich.edu
1923101Sstever@eecs.umich.edu    # Is the param available to be exposed on the command line
1933101Sstever@eecs.umich.edu    def isCmdLineSettable(self):
1945033Smilesck@eecs.umich.edu        if hasattr(self.ptype, "cmd_line_settable"):
1955475Snate@binkert.org            return self.ptype.cmd_line_settable
1965475Snate@binkert.org        else:
1975475Snate@binkert.org            return False
1985475Snate@binkert.org
1993101Sstever@eecs.umich.edu    def convert(self, value):
2003101Sstever@eecs.umich.edu        if isinstance(value, proxy.BaseProxy):
2013101Sstever@eecs.umich.edu            value.set_param_desc(self)
2024762Snate@binkert.org            return value
2034762Snate@binkert.org        if not hasattr(self, 'ptype') and isNullPointer(value):
2044762Snate@binkert.org            # deferred evaluation of SimObject; continue to defer if
2053101Sstever@eecs.umich.edu            # we're just assigning a null pointer
2068460SAli.Saidi@ARM.com            return value
2078459SAli.Saidi@ARM.com        if isinstance(value, self.ptype):
2088459SAli.Saidi@ARM.com            return value
2098459SAli.Saidi@ARM.com        if isNullPointer(value) and isSimObjectClass(self.ptype):
2103101Sstever@eecs.umich.edu            return value
2117528Ssteve.reinhardt@amd.com        return self.ptype(value)
2127528Ssteve.reinhardt@amd.com
2137528Ssteve.reinhardt@amd.com    def pretty_print(self, value):
2147528Ssteve.reinhardt@amd.com        if isinstance(value, proxy.BaseProxy):
2157528Ssteve.reinhardt@amd.com           return str(value)
2167528Ssteve.reinhardt@amd.com        if isNullPointer(value):
2173101Sstever@eecs.umich.edu           return NULL
2187528Ssteve.reinhardt@amd.com        return self.ptype(value).pretty_print(value)
2197528Ssteve.reinhardt@amd.com
2207528Ssteve.reinhardt@amd.com    def cxx_predecls(self, code):
2217528Ssteve.reinhardt@amd.com        code('#include <cstddef>')
2227528Ssteve.reinhardt@amd.com        self.ptype.cxx_predecls(code)
2237528Ssteve.reinhardt@amd.com
2247528Ssteve.reinhardt@amd.com    def pybind_predecls(self, code):
2257528Ssteve.reinhardt@amd.com        self.ptype.pybind_predecls(code)
2267528Ssteve.reinhardt@amd.com
2277528Ssteve.reinhardt@amd.com    def cxx_decl(self, code):
2288321Ssteve.reinhardt@amd.com        code('${{self.ptype.cxx_type}} ${{self.name}};')
2298321Ssteve.reinhardt@amd.com
2307528Ssteve.reinhardt@amd.com# Vector-valued parameter description.  Just like ParamDesc, except
2317528Ssteve.reinhardt@amd.com# that the value is a vector (list) of the specified type instead of a
2327528Ssteve.reinhardt@amd.com# single value.
2337528Ssteve.reinhardt@amd.com
2347528Ssteve.reinhardt@amd.comclass VectorParamValue(list):
2357528Ssteve.reinhardt@amd.com    __metaclass__ = MetaParamValue
2367528Ssteve.reinhardt@amd.com    def __setattr__(self, attr, value):
2377528Ssteve.reinhardt@amd.com        raise AttributeError, \
2387528Ssteve.reinhardt@amd.com              "Not allowed to set %s on '%s'" % (attr, type(self).__name__)
2397528Ssteve.reinhardt@amd.com
2407528Ssteve.reinhardt@amd.com    def config_value(self):
2417528Ssteve.reinhardt@amd.com        return [v.config_value() for v in self]
2427528Ssteve.reinhardt@amd.com
2433101Sstever@eecs.umich.edu    def ini_str(self):
2448664SAli.Saidi@ARM.com        return ' '.join([v.ini_str() for v in self])
2458664SAli.Saidi@ARM.com
2468664SAli.Saidi@ARM.com    def getValue(self):
2478664SAli.Saidi@ARM.com        return [ v.getValue() for v in self ]
2488664SAli.Saidi@ARM.com
2498664SAli.Saidi@ARM.com    def unproxy(self, base):
2503101Sstever@eecs.umich.edu        if len(self) == 1 and isinstance(self[0], proxy.BaseProxy):
2513101Sstever@eecs.umich.edu            # The value is a proxy (e.g. Parent.any, Parent.all or
2523101Sstever@eecs.umich.edu            # Parent.x) therefore try resolve it
2533101Sstever@eecs.umich.edu            return self[0].unproxy(base)
2543101Sstever@eecs.umich.edu        else:
2553101Sstever@eecs.umich.edu            return [v.unproxy(base) for v in self]
2563101Sstever@eecs.umich.edu
2573101Sstever@eecs.umich.educlass SimObjectVector(VectorParamValue):
2584762Snate@binkert.org    # support clone operation
2594762Snate@binkert.org    def __call__(self, **kwargs):
2604762Snate@binkert.org        return SimObjectVector([v(**kwargs) for v in self])
2614762Snate@binkert.org
2627528Ssteve.reinhardt@amd.com    def clear_parent(self, old_parent):
2634762Snate@binkert.org        for v in self:
2644762Snate@binkert.org            v.clear_parent(old_parent)
2654762Snate@binkert.org
2668596Ssteve.reinhardt@amd.com    def set_parent(self, parent, name):
2678596Ssteve.reinhardt@amd.com        if len(self) == 1:
2688596Ssteve.reinhardt@amd.com            self[0].set_parent(parent, name)
2697673Snate@binkert.org        else:
2708596Ssteve.reinhardt@amd.com            width = int(math.ceil(math.log(len(self))/math.log(10)))
2714762Snate@binkert.org            for i,v in enumerate(self):
2727673Snate@binkert.org                v.set_parent(parent, "%s%0*d" % (name, width, i))
2738596Ssteve.reinhardt@amd.com
2747675Snate@binkert.org    def has_parent(self):
2757675Snate@binkert.org        return any([e.has_parent() for e in self if not isNullPointer(e)])
2767675Snate@binkert.org
2777675Snate@binkert.org    # return 'cpu0 cpu1' etc. for print_ini()
2788656Sandreas.hansson@arm.com    def get_name(self):
2798656Sandreas.hansson@arm.com        return ' '.join([v._name for v in self])
2808656Sandreas.hansson@arm.com
2817675Snate@binkert.org    # By iterating through the constituent members of the vector here
2827675Snate@binkert.org    # we can nicely handle iterating over all a SimObject's children
2837673Snate@binkert.org    # without having to provide lots of special functions on
2847675Snate@binkert.org    # SimObjectVector directly.
2857675Snate@binkert.org    def descendants(self):
2867675Snate@binkert.org        for v in self:
2877675Snate@binkert.org            for obj in v.descendants():
2887675Snate@binkert.org                yield obj
2897673Snate@binkert.org
2907675Snate@binkert.org    def get_config_as_dict(self):
2917675Snate@binkert.org        a = []
2927675Snate@binkert.org        for v in self:
2937675Snate@binkert.org            a.append(v.get_config_as_dict())
2947675Snate@binkert.org        return a
2957675Snate@binkert.org
2967675Snate@binkert.org    # If we are replacing an item in the vector, make sure to set the
2977675Snate@binkert.org    # parent reference of the new SimObject to be the same as the parent
2987675Snate@binkert.org    # of the SimObject being replaced. Useful to have if we created
2997675Snate@binkert.org    # a SimObjectVector of temporary objects that will be modified later in
3007675Snate@binkert.org    # configuration scripts.
3017675Snate@binkert.org    def __setitem__(self, key, value):
3027675Snate@binkert.org        val = self[key]
3037675Snate@binkert.org        if value.has_parent():
3047675Snate@binkert.org            warn("SimObject %s already has a parent" % value.get_name() +\
3057675Snate@binkert.org                 " that is being overwritten by a SimObjectVector")
3067673Snate@binkert.org        value.set_parent(val.get_parent(), val._name)
3077673Snate@binkert.org        super(SimObjectVector, self).__setitem__(key, value)
3083101Sstever@eecs.umich.edu
3097675Snate@binkert.org    # Enumerate the params of each member of the SimObject vector. Creates
3107675Snate@binkert.org    # strings that will allow indexing into the vector by the python code and
3117673Snate@binkert.org    # allow it to be specified on the command line.
3127673Snate@binkert.org    def enumerateParams(self, flags_dict = {},
3137673Snate@binkert.org                        cmd_line_str = "",
3143101Sstever@eecs.umich.edu                        access_str = ""):
3157673Snate@binkert.org        if hasattr(self, "_paramEnumed"):
3167673Snate@binkert.org            print("Cycle detected enumerating params at %s?!" % (cmd_line_str))
3173101Sstever@eecs.umich.edu        else:
3183101Sstever@eecs.umich.edu            x = 0
3193101Sstever@eecs.umich.edu            for vals in self:
3203101Sstever@eecs.umich.edu                # Each entry in the SimObjectVector should be an
3213101Sstever@eecs.umich.edu                # instance of a SimObject
3223101Sstever@eecs.umich.edu                flags_dict = vals.enumerateParams(flags_dict,
3233101Sstever@eecs.umich.edu                                                  cmd_line_str + "%d." % x,
3243101Sstever@eecs.umich.edu                                                  access_str + "[%d]." % x)
3253101Sstever@eecs.umich.edu                x = x + 1
3263101Sstever@eecs.umich.edu
3273101Sstever@eecs.umich.edu        return flags_dict
3283101Sstever@eecs.umich.edu
3293101Sstever@eecs.umich.educlass VectorParamDesc(ParamDesc):
3303101Sstever@eecs.umich.edu    # Convert assigned value to appropriate type.  If the RHS is not a
3313101Sstever@eecs.umich.edu    # list or tuple, it generates a single-element list.
3325033Smilesck@eecs.umich.edu    def convert(self, value):
3335033Smilesck@eecs.umich.edu        if isinstance(value, (list, tuple)):
3343101Sstever@eecs.umich.edu            # list: coerce each element into new list
3353101Sstever@eecs.umich.edu            tmp_list = [ ParamDesc.convert(self, v) for v in value ]
3363101Sstever@eecs.umich.edu        elif isinstance(value, str):
3373101Sstever@eecs.umich.edu            # If input is a csv string
3383101Sstever@eecs.umich.edu            tmp_list = [ ParamDesc.convert(self, v) \
3393101Sstever@eecs.umich.edu                         for v in value.strip('[').strip(']').split(',') ]
3403101Sstever@eecs.umich.edu        else:
3413101Sstever@eecs.umich.edu            # singleton: coerce to a single-element list
3423101Sstever@eecs.umich.edu            tmp_list = [ ParamDesc.convert(self, value) ]
3433101Sstever@eecs.umich.edu
3443101Sstever@eecs.umich.edu        if isSimObjectSequence(tmp_list):
3453101Sstever@eecs.umich.edu            return SimObjectVector(tmp_list)
3463101Sstever@eecs.umich.edu        else:
3473101Sstever@eecs.umich.edu            return VectorParamValue(tmp_list)
3483101Sstever@eecs.umich.edu
3493101Sstever@eecs.umich.edu    # Produce a human readable example string that describes
3503101Sstever@eecs.umich.edu    # how to set this vector parameter in the absence of a default
3513101Sstever@eecs.umich.edu    # value.
3523101Sstever@eecs.umich.edu    def example_str(self):
3533101Sstever@eecs.umich.edu        s = super(VectorParamDesc, self).example_str()
3543101Sstever@eecs.umich.edu        help_str = "[" + s + "," + s + ", ...]"
3553101Sstever@eecs.umich.edu        return help_str
3563101Sstever@eecs.umich.edu
3573101Sstever@eecs.umich.edu    # Produce a human readable representation of the value of this vector param.
3583101Sstever@eecs.umich.edu    def pretty_print(self, value):
3597673Snate@binkert.org        if isinstance(value, (list, tuple)):
3607673Snate@binkert.org            tmp_list = [ ParamDesc.pretty_print(self, v) for v in value ]
3617673Snate@binkert.org        elif isinstance(value, str):
3627673Snate@binkert.org            tmp_list = [ ParamDesc.pretty_print(self, v) for v in value.split(',') ]
3637673Snate@binkert.org        else:
3647673Snate@binkert.org            tmp_list = [ ParamDesc.pretty_print(self, value) ]
3657673Snate@binkert.org
3667673Snate@binkert.org        return tmp_list
3674762Snate@binkert.org
3684762Snate@binkert.org    # This is a helper function for the new config system
3694762Snate@binkert.org    def __call__(self, value):
3703101Sstever@eecs.umich.edu        if isinstance(value, (list, tuple)):
3713101Sstever@eecs.umich.edu            # list: coerce each element into new list
3723101Sstever@eecs.umich.edu            tmp_list = [ ParamDesc.convert(self, v) for v in value ]
3733101Sstever@eecs.umich.edu        elif isinstance(value, str):
3743101Sstever@eecs.umich.edu            # If input is a csv string
3753101Sstever@eecs.umich.edu            tmp_list = [ ParamDesc.convert(self, v) \
3763101Sstever@eecs.umich.edu                         for v in value.strip('[').strip(']').split(',') ]
3773101Sstever@eecs.umich.edu        else:
3783101Sstever@eecs.umich.edu            # singleton: coerce to a single-element list
3793101Sstever@eecs.umich.edu            tmp_list = [ ParamDesc.convert(self, value) ]
3803101Sstever@eecs.umich.edu
3813714Sstever@eecs.umich.edu        return VectorParamValue(tmp_list)
3823714Sstever@eecs.umich.edu
3833714Sstever@eecs.umich.edu    def cxx_predecls(self, code):
3843714Sstever@eecs.umich.edu        code('#include <vector>')
3853714Sstever@eecs.umich.edu        self.ptype.cxx_predecls(code)
3863714Sstever@eecs.umich.edu
3873101Sstever@eecs.umich.edu    def pybind_predecls(self, code):
3883101Sstever@eecs.umich.edu        code('#include <vector>')
3893101Sstever@eecs.umich.edu        self.ptype.pybind_predecls(code)
3903101Sstever@eecs.umich.edu
3913101Sstever@eecs.umich.edu    def cxx_decl(self, code):
3923101Sstever@eecs.umich.edu        code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};')
3933101Sstever@eecs.umich.edu
3943101Sstever@eecs.umich.educlass ParamFactory(object):
3953101Sstever@eecs.umich.edu    def __init__(self, param_desc_class, ptype_str = None):
3963101Sstever@eecs.umich.edu        self.param_desc_class = param_desc_class
3973101Sstever@eecs.umich.edu        self.ptype_str = ptype_str
3983101Sstever@eecs.umich.edu
3993101Sstever@eecs.umich.edu    def __getattr__(self, attr):
4003101Sstever@eecs.umich.edu        if self.ptype_str:
4013101Sstever@eecs.umich.edu            attr = self.ptype_str + '.' + attr
4023101Sstever@eecs.umich.edu        return ParamFactory(self.param_desc_class, attr)
4033101Sstever@eecs.umich.edu
4043101Sstever@eecs.umich.edu    # E.g., Param.Int(5, "number of widgets")
4053101Sstever@eecs.umich.edu    def __call__(self, *args, **kwargs):
4063101Sstever@eecs.umich.edu        ptype = None
4073101Sstever@eecs.umich.edu        try:
4083101Sstever@eecs.umich.edu            ptype = allParams[self.ptype_str]
4093101Sstever@eecs.umich.edu        except KeyError:
4103101Sstever@eecs.umich.edu            # if name isn't defined yet, assume it's a SimObject, and
4113101Sstever@eecs.umich.edu            # try to resolve it later
4125033Smilesck@eecs.umich.edu            pass
4133101Sstever@eecs.umich.edu        return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs)
4143101Sstever@eecs.umich.edu
4153101Sstever@eecs.umich.eduParam = ParamFactory(ParamDesc)
4163101Sstever@eecs.umich.eduVectorParam = ParamFactory(VectorParamDesc)
4173101Sstever@eecs.umich.edu
4183101Sstever@eecs.umich.edu#####################################################################
4193101Sstever@eecs.umich.edu#
4203101Sstever@eecs.umich.edu# Parameter Types
4213101Sstever@eecs.umich.edu#
4223101Sstever@eecs.umich.edu# Though native Python types could be used to specify parameter types
4233101Sstever@eecs.umich.edu# (the 'ptype' field of the Param and VectorParam classes), it's more
4243101Sstever@eecs.umich.edu# flexible to define our own set of types.  This gives us more control
4255822Ssaidi@eecs.umich.edu# over how Python expressions are converted to values (via the
4265822Ssaidi@eecs.umich.edu# __init__() constructor) and how these values are printed out (via
4273101Sstever@eecs.umich.edu# the __str__() conversion method).
4283101Sstever@eecs.umich.edu#
4293101Sstever@eecs.umich.edu#####################################################################
4303101Sstever@eecs.umich.edu
4313101Sstever@eecs.umich.edu# String-valued parameter.  Just mixin the ParamValue class with the
4323101Sstever@eecs.umich.edu# built-in str class.
4333101Sstever@eecs.umich.educlass String(ParamValue,str):
4343101Sstever@eecs.umich.edu    cxx_type = 'std::string'
4353101Sstever@eecs.umich.edu    cmd_line_settable = True
4363101Sstever@eecs.umich.edu
4373101Sstever@eecs.umich.edu    @classmethod
4383101Sstever@eecs.umich.edu    def cxx_predecls(self, code):
4393101Sstever@eecs.umich.edu        code('#include <string>')
4403101Sstever@eecs.umich.edu
4413101Sstever@eecs.umich.edu    def __call__(self, value):
4423101Sstever@eecs.umich.edu        self = value
4433101Sstever@eecs.umich.edu        return value
4443101Sstever@eecs.umich.edu
4453101Sstever@eecs.umich.edu    @classmethod
4463101Sstever@eecs.umich.edu    def cxx_ini_parse(self, code, src, dest, ret):
4473101Sstever@eecs.umich.edu        code('%s = %s;' % (dest, src))
4483102Sstever@eecs.umich.edu        code('%s true;' % ret)
4493714Sstever@eecs.umich.edu
4503101Sstever@eecs.umich.edu    def getValue(self):
4513714Sstever@eecs.umich.edu        return self
4523714Sstever@eecs.umich.edu
4533714Sstever@eecs.umich.edu# superclass for "numeric" parameter values, to emulate math
4543101Sstever@eecs.umich.edu# operations in a type-safe way.  e.g., a Latency times an int returns
4553101Sstever@eecs.umich.edu# a new Latency object.
4567673Snate@binkert.orgclass NumericParamValue(ParamValue):
4577673Snate@binkert.org    def __str__(self):
4587673Snate@binkert.org        return str(self.value)
4597673Snate@binkert.org
4607673Snate@binkert.org    def __float__(self):
4617673Snate@binkert.org        return float(self.value)
4627673Snate@binkert.org
4637673Snate@binkert.org    def __long__(self):
4647673Snate@binkert.org        return long(self.value)
4657673Snate@binkert.org
4667673Snate@binkert.org    def __int__(self):
4674762Snate@binkert.org        return int(self.value)
4684762Snate@binkert.org
4694762Snate@binkert.org    # hook for bounds checking
4703101Sstever@eecs.umich.edu    def _check(self):
4713101Sstever@eecs.umich.edu        return
4723101Sstever@eecs.umich.edu
4733101Sstever@eecs.umich.edu    def __mul__(self, other):
4743101Sstever@eecs.umich.edu        newobj = self.__class__(self)
4753101Sstever@eecs.umich.edu        newobj.value *= other
4763101Sstever@eecs.umich.edu        newobj._check()
4773101Sstever@eecs.umich.edu        return newobj
4783101Sstever@eecs.umich.edu
4793101Sstever@eecs.umich.edu    __rmul__ = __mul__
4803101Sstever@eecs.umich.edu
4813101Sstever@eecs.umich.edu    def __div__(self, other):
4823101Sstever@eecs.umich.edu        newobj = self.__class__(self)
4833101Sstever@eecs.umich.edu        newobj.value /= other
4843101Sstever@eecs.umich.edu        newobj._check()
4853101Sstever@eecs.umich.edu        return newobj
4863101Sstever@eecs.umich.edu
4873101Sstever@eecs.umich.edu    def __sub__(self, other):
4883101Sstever@eecs.umich.edu        newobj = self.__class__(self)
4893101Sstever@eecs.umich.edu        newobj.value -= other
4904446Sbinkertn@umich.edu        newobj._check()
4913101Sstever@eecs.umich.edu        return newobj
4925468Snate@binkert.org
4935468Snate@binkert.org    def config_value(self):
4945468Snate@binkert.org        return self.value
4955468Snate@binkert.org
4965468Snate@binkert.org    @classmethod
4975468Snate@binkert.org    def cxx_ini_predecls(cls, code):
4985468Snate@binkert.org        # Assume that base/str.hh will be included anyway
4994762Snate@binkert.org        # code('#include "base/str.hh"')
5004762Snate@binkert.org        pass
5014762Snate@binkert.org
5023101Sstever@eecs.umich.edu    # The default for parsing PODs from an .ini entry is to extract from an
5033101Sstever@eecs.umich.edu    # istringstream and let overloading choose the right type according to
5043101Sstever@eecs.umich.edu    # the dest type.
5053101Sstever@eecs.umich.edu    @classmethod
5063101Sstever@eecs.umich.edu    def cxx_ini_parse(self, code, src, dest, ret):
5073101Sstever@eecs.umich.edu        code('%s to_number(%s, %s);' % (ret, src, dest))
5083101Sstever@eecs.umich.edu
5093101Sstever@eecs.umich.edu# Metaclass for bounds-checked integer parameters.  See CheckedInt.
5103102Sstever@eecs.umich.educlass CheckedIntType(MetaParamValue):
5113101Sstever@eecs.umich.edu    def __init__(cls, name, bases, dict):
5123101Sstever@eecs.umich.edu        super(CheckedIntType, cls).__init__(name, bases, dict)
5133101Sstever@eecs.umich.edu
5144168Sbinkertn@umich.edu        # CheckedInt is an abstract base class, so we actually don't
5153101Sstever@eecs.umich.edu        # want to do any processing on it... the rest of this code is
5163101Sstever@eecs.umich.edu        # just for classes that derive from CheckedInt.
5173101Sstever@eecs.umich.edu        if name == 'CheckedInt':
5183101Sstever@eecs.umich.edu            return
5193101Sstever@eecs.umich.edu
5203101Sstever@eecs.umich.edu        if not (hasattr(cls, 'min') and hasattr(cls, 'max')):
5213102Sstever@eecs.umich.edu            if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')):
5223101Sstever@eecs.umich.edu                panic("CheckedInt subclass %s must define either\n" \
5233101Sstever@eecs.umich.edu                      "    'min' and 'max' or 'size' and 'unsigned'\n",
5243101Sstever@eecs.umich.edu                      name);
5253101Sstever@eecs.umich.edu            if cls.unsigned:
5263101Sstever@eecs.umich.edu                cls.min = 0
5273101Sstever@eecs.umich.edu                cls.max = 2 ** cls.size - 1
5283101Sstever@eecs.umich.edu            else:
5293101Sstever@eecs.umich.edu                cls.min = -(2 ** (cls.size - 1))
5303101Sstever@eecs.umich.edu                cls.max = (2 ** (cls.size - 1)) - 1
5313101Sstever@eecs.umich.edu
5323101Sstever@eecs.umich.edu# Abstract superclass for bounds-checked integer parameters.  This
5333102Sstever@eecs.umich.edu# class is subclassed to generate parameter classes with specific
5343101Sstever@eecs.umich.edu# bounds.  Initialization of the min and max bounds is done in the
5353101Sstever@eecs.umich.edu# metaclass CheckedIntType.__init__.
5363101Sstever@eecs.umich.educlass CheckedInt(NumericParamValue):
5373584Ssaidi@eecs.umich.edu    __metaclass__ = CheckedIntType
5383584Ssaidi@eecs.umich.edu    cmd_line_settable = True
5393584Ssaidi@eecs.umich.edu
5403584Ssaidi@eecs.umich.edu    def _check(self):
5413584Ssaidi@eecs.umich.edu        if not self.min <= self.value <= self.max:
5423101Sstever@eecs.umich.edu            raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
5433101Sstever@eecs.umich.edu                  (self.min, self.value, self.max)
5445033Smilesck@eecs.umich.edu
5453101Sstever@eecs.umich.edu    def __init__(self, value):
5463101Sstever@eecs.umich.edu        if isinstance(value, str):
5473101Sstever@eecs.umich.edu            self.value = convert.toInteger(value)
5483101Sstever@eecs.umich.edu        elif isinstance(value, (int, long, float, NumericParamValue)):
5493101Sstever@eecs.umich.edu            self.value = long(value)
5503101Sstever@eecs.umich.edu        else:
5513101Sstever@eecs.umich.edu            raise TypeError, "Can't convert object of type %s to CheckedInt" \
5523101Sstever@eecs.umich.edu                  % type(value).__name__
5533101Sstever@eecs.umich.edu        self._check()
5543101Sstever@eecs.umich.edu
5553101Sstever@eecs.umich.edu    def __call__(self, value):
5563101Sstever@eecs.umich.edu        self.__init__(value)
5573101Sstever@eecs.umich.edu        return value
5583101Sstever@eecs.umich.edu
5593101Sstever@eecs.umich.edu    @classmethod
5603101Sstever@eecs.umich.edu    def cxx_predecls(cls, code):
5613101Sstever@eecs.umich.edu        # most derived types require this, so we just do it here once
5623101Sstever@eecs.umich.edu        code('#include "base/types.hh"')
5633101Sstever@eecs.umich.edu
5643101Sstever@eecs.umich.edu    def getValue(self):
5653101Sstever@eecs.umich.edu        return long(self.value)
5663101Sstever@eecs.umich.edu
5673101Sstever@eecs.umich.educlass Int(CheckedInt):      cxx_type = 'int';      size = 32; unsigned = False
5683101Sstever@eecs.umich.educlass Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True
5693101Sstever@eecs.umich.edu
5703101Sstever@eecs.umich.educlass Int8(CheckedInt):     cxx_type =   'int8_t'; size =  8; unsigned = False
5713101Sstever@eecs.umich.educlass UInt8(CheckedInt):    cxx_type =  'uint8_t'; size =  8; unsigned = True
5723101Sstever@eecs.umich.educlass Int16(CheckedInt):    cxx_type =  'int16_t'; size = 16; unsigned = False
5733101Sstever@eecs.umich.educlass UInt16(CheckedInt):   cxx_type = 'uint16_t'; size = 16; unsigned = True
5745219Ssaidi@eecs.umich.educlass Int32(CheckedInt):    cxx_type =  'int32_t'; size = 32; unsigned = False
5755219Ssaidi@eecs.umich.educlass UInt32(CheckedInt):   cxx_type = 'uint32_t'; size = 32; unsigned = True
5765219Ssaidi@eecs.umich.educlass Int64(CheckedInt):    cxx_type =  'int64_t'; size = 64; unsigned = False
5773101Sstever@eecs.umich.educlass UInt64(CheckedInt):   cxx_type = 'uint64_t'; size = 64; unsigned = True
5783101Sstever@eecs.umich.edu
5793101Sstever@eecs.umich.educlass Counter(CheckedInt):  cxx_type = 'Counter';  size = 64; unsigned = True
5803101Sstever@eecs.umich.educlass Tick(CheckedInt):     cxx_type = 'Tick';     size = 64; unsigned = True
5813101Sstever@eecs.umich.educlass TcpPort(CheckedInt):  cxx_type = 'uint16_t'; size = 16; unsigned = True
5823101Sstever@eecs.umich.educlass UdpPort(CheckedInt):  cxx_type = 'uint16_t'; size = 16; unsigned = True
5833101Sstever@eecs.umich.edu
5843101Sstever@eecs.umich.educlass Percent(CheckedInt):  cxx_type = 'int'; min = 0; max = 100
5853101Sstever@eecs.umich.edu
5863101Sstever@eecs.umich.educlass Cycles(CheckedInt):
5873101Sstever@eecs.umich.edu    cxx_type = 'Cycles'
5883101Sstever@eecs.umich.edu    size = 64
5893101Sstever@eecs.umich.edu    unsigned = True
5903101Sstever@eecs.umich.edu
5913101Sstever@eecs.umich.edu    def getValue(self):
5923101Sstever@eecs.umich.edu        from _m5.core import Cycles
5937673Snate@binkert.org        return Cycles(self.value)
5947673Snate@binkert.org
5957675Snate@binkert.org    @classmethod
5967673Snate@binkert.org    def cxx_ini_predecls(cls, code):
5977675Snate@binkert.org        # Assume that base/str.hh will be included anyway
5987675Snate@binkert.org        # code('#include "base/str.hh"')
5997675Snate@binkert.org        pass
6007675Snate@binkert.org
6017675Snate@binkert.org    @classmethod
6027673Snate@binkert.org    def cxx_ini_parse(cls, code, src, dest, ret):
6033101Sstever@eecs.umich.edu        code('uint64_t _temp;')
6043101Sstever@eecs.umich.edu        code('bool _ret = to_number(%s, _temp);' % src)
6057673Snate@binkert.org        code('if (_ret)')
6064762Snate@binkert.org        code('    %s = Cycles(_temp);' % dest)
6077675Snate@binkert.org        code('%s _ret;' % ret)
6084762Snate@binkert.org
6094762Snate@binkert.orgclass Float(ParamValue, float):
6104762Snate@binkert.org    cxx_type = 'double'
6114762Snate@binkert.org    cmd_line_settable = True
6124762Snate@binkert.org
6133101Sstever@eecs.umich.edu    def __init__(self, value):
6143101Sstever@eecs.umich.edu        if isinstance(value, (int, long, float, NumericParamValue, Float, str)):
6153101Sstever@eecs.umich.edu            self.value = float(value)
6167673Snate@binkert.org        else:
6174762Snate@binkert.org            raise TypeError, "Can't convert object of type %s to Float" \
6187675Snate@binkert.org                  % type(value).__name__
6194762Snate@binkert.org
6204762Snate@binkert.org    def __call__(self, value):
6214762Snate@binkert.org        self.__init__(value)
6224762Snate@binkert.org        return value
6234762Snate@binkert.org
6243101Sstever@eecs.umich.edu    def getValue(self):
6253101Sstever@eecs.umich.edu        return float(self.value)
6263101Sstever@eecs.umich.edu
6273101Sstever@eecs.umich.edu    def config_value(self):
6283101Sstever@eecs.umich.edu        return self
6293101Sstever@eecs.umich.edu
6303101Sstever@eecs.umich.edu    @classmethod
6313101Sstever@eecs.umich.edu    def cxx_ini_predecls(cls, code):
6323102Sstever@eecs.umich.edu        code('#include <sstream>')
6333101Sstever@eecs.umich.edu
6343101Sstever@eecs.umich.edu    @classmethod
6353101Sstever@eecs.umich.edu    def cxx_ini_parse(self, code, src, dest, ret):
6364762Snate@binkert.org        code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
6374762Snate@binkert.org
6384762Snate@binkert.orgclass MemorySize(CheckedInt):
6393101Sstever@eecs.umich.edu    cxx_type = 'uint64_t'
6403101Sstever@eecs.umich.edu    ex_str = '512MB'
6413101Sstever@eecs.umich.edu    size = 64
6423101Sstever@eecs.umich.edu    unsigned = True
6433101Sstever@eecs.umich.edu    def __init__(self, value):
6443101Sstever@eecs.umich.edu        if isinstance(value, MemorySize):
6453101Sstever@eecs.umich.edu            self.value = value.value
6463101Sstever@eecs.umich.edu        else:
6473101Sstever@eecs.umich.edu            self.value = convert.toMemorySize(value)
6483101Sstever@eecs.umich.edu        self._check()
6493101Sstever@eecs.umich.edu
6503101Sstever@eecs.umich.educlass MemorySize32(CheckedInt):
6513101Sstever@eecs.umich.edu    cxx_type = 'uint32_t'
6523101Sstever@eecs.umich.edu    ex_str = '512MB'
6533101Sstever@eecs.umich.edu    size = 32
6543101Sstever@eecs.umich.edu    unsigned = True
6553101Sstever@eecs.umich.edu    def __init__(self, value):
6563101Sstever@eecs.umich.edu        if isinstance(value, MemorySize):
6573101Sstever@eecs.umich.edu            self.value = value.value
6583101Sstever@eecs.umich.edu        else:
6594380Sbinkertn@umich.edu            self.value = convert.toMemorySize(value)
6604380Sbinkertn@umich.edu        self._check()
6614380Sbinkertn@umich.edu
6623101Sstever@eecs.umich.educlass Addr(CheckedInt):
6634380Sbinkertn@umich.edu    cxx_type = 'Addr'
6644380Sbinkertn@umich.edu    size = 64
6654380Sbinkertn@umich.edu    unsigned = True
6663101Sstever@eecs.umich.edu    def __init__(self, value):
6673101Sstever@eecs.umich.edu        if isinstance(value, Addr):
6683101Sstever@eecs.umich.edu            self.value = value.value
6697673Snate@binkert.org        else:
6707673Snate@binkert.org            try:
6717673Snate@binkert.org                # Often addresses are referred to with sizes. Ex: A device
6727673Snate@binkert.org                # base address is at "512MB".  Use toMemorySize() to convert
6737673Snate@binkert.org                # these into addresses. If the address is not specified with a
6747673Snate@binkert.org                # "size", an exception will occur and numeric translation will
6757673Snate@binkert.org                # proceed below.
6767673Snate@binkert.org                self.value = convert.toMemorySize(value)
6777673Snate@binkert.org            except (TypeError, ValueError):
6783101Sstever@eecs.umich.edu                # Convert number to string and use long() to do automatic
6793101Sstever@eecs.umich.edu                # base conversion (requires base=0 for auto-conversion)
6803101Sstever@eecs.umich.edu                self.value = long(str(value), base=0)
6813101Sstever@eecs.umich.edu
6823101Sstever@eecs.umich.edu        self._check()
6833101Sstever@eecs.umich.edu    def __add__(self, other):
6843101Sstever@eecs.umich.edu        if isinstance(other, Addr):
6853101Sstever@eecs.umich.edu            return self.value + other.value
6863101Sstever@eecs.umich.edu        else:
6873101Sstever@eecs.umich.edu            return self.value + other
6883101Sstever@eecs.umich.edu    def pretty_print(self, value):
6893101Sstever@eecs.umich.edu        try:
6903101Sstever@eecs.umich.edu            val = convert.toMemorySize(value)
6917743Sgblack@eecs.umich.edu        except TypeError:
6923101Sstever@eecs.umich.edu            val = long(value)
6933101Sstever@eecs.umich.edu        return "0x%x" % long(val)
6943101Sstever@eecs.umich.edu
6953101Sstever@eecs.umich.educlass AddrRange(ParamValue):
6963101Sstever@eecs.umich.edu    cxx_type = 'AddrRange'
6973101Sstever@eecs.umich.edu
6984380Sbinkertn@umich.edu    def __init__(self, *args, **kwargs):
6993101Sstever@eecs.umich.edu        # Disable interleaving and hashing by default
7003101Sstever@eecs.umich.edu        self.intlvHighBit = 0
7014762Snate@binkert.org        self.xorHighBit = 0
7027677Snate@binkert.org        self.intlvBits = 0
7034762Snate@binkert.org        self.intlvMatch = 0
7044762Snate@binkert.org
7054380Sbinkertn@umich.edu        def handle_kwargs(self, kwargs):
7064380Sbinkertn@umich.edu            # An address range needs to have an upper limit, specified
7073101Sstever@eecs.umich.edu            # either explicitly with an end, or as an offset using the
7087777Sgblack@eecs.umich.edu            # size keyword.
7097777Sgblack@eecs.umich.edu            if 'end' in kwargs:
7107777Sgblack@eecs.umich.edu                self.end = Addr(kwargs.pop('end'))
7117777Sgblack@eecs.umich.edu            elif 'size' in kwargs:
7127777Sgblack@eecs.umich.edu                self.end = self.start + Addr(kwargs.pop('size')) - 1
7137777Sgblack@eecs.umich.edu            else:
7147777Sgblack@eecs.umich.edu                raise TypeError, "Either end or size must be specified"
7157777Sgblack@eecs.umich.edu
7167777Sgblack@eecs.umich.edu            # Now on to the optional bit
7177777Sgblack@eecs.umich.edu            if 'intlvHighBit' in kwargs:
7187777Sgblack@eecs.umich.edu                self.intlvHighBit = int(kwargs.pop('intlvHighBit'))
7197777Sgblack@eecs.umich.edu            if 'xorHighBit' in kwargs:
7207777Sgblack@eecs.umich.edu                self.xorHighBit = int(kwargs.pop('xorHighBit'))
7217777Sgblack@eecs.umich.edu            if 'intlvBits' in kwargs:
7227777Sgblack@eecs.umich.edu                self.intlvBits = int(kwargs.pop('intlvBits'))
7237777Sgblack@eecs.umich.edu            if 'intlvMatch' in kwargs:
7247777Sgblack@eecs.umich.edu                self.intlvMatch = int(kwargs.pop('intlvMatch'))
7257777Sgblack@eecs.umich.edu
7267777Sgblack@eecs.umich.edu        if len(args) == 0:
7277777Sgblack@eecs.umich.edu            self.start = Addr(kwargs.pop('start'))
7287777Sgblack@eecs.umich.edu            handle_kwargs(self, kwargs)
7297777Sgblack@eecs.umich.edu
7307777Sgblack@eecs.umich.edu        elif len(args) == 1:
7318579Ssteve.reinhardt@amd.com            if kwargs:
7328579Ssteve.reinhardt@amd.com                self.start = Addr(args[0])
7338579Ssteve.reinhardt@amd.com                handle_kwargs(self, kwargs)
7348579Ssteve.reinhardt@amd.com            elif isinstance(args[0], (list, tuple)):
7358579Ssteve.reinhardt@amd.com                self.start = Addr(args[0][0])
7368579Ssteve.reinhardt@amd.com                self.end = Addr(args[0][1])
7378579Ssteve.reinhardt@amd.com            else:
7388579Ssteve.reinhardt@amd.com                self.start = Addr(0)
7398579Ssteve.reinhardt@amd.com                self.end = Addr(args[0]) - 1
7408579Ssteve.reinhardt@amd.com
7418579Ssteve.reinhardt@amd.com        elif len(args) == 2:
7428579Ssteve.reinhardt@amd.com            self.start = Addr(args[0])
7438579Ssteve.reinhardt@amd.com            self.end = Addr(args[1])
7448579Ssteve.reinhardt@amd.com        else:
7458579Ssteve.reinhardt@amd.com            raise TypeError, "Too many arguments specified"
7468579Ssteve.reinhardt@amd.com
7478579Ssteve.reinhardt@amd.com        if kwargs:
7488579Ssteve.reinhardt@amd.com            raise TypeError, "Too many keywords: %s" % kwargs.keys()
7497777Sgblack@eecs.umich.edu
7507777Sgblack@eecs.umich.edu    def __str__(self):
7517798Sgblack@eecs.umich.edu        return '%s:%s:%s:%s:%s:%s' \
7527777Sgblack@eecs.umich.edu            % (self.start, self.end, self.intlvHighBit, self.xorHighBit,\
7537777Sgblack@eecs.umich.edu               self.intlvBits, self.intlvMatch)
7547777Sgblack@eecs.umich.edu
7557777Sgblack@eecs.umich.edu    def size(self):
7567777Sgblack@eecs.umich.edu        # Divide the size by the size of the interleaving slice
7577777Sgblack@eecs.umich.edu        return (long(self.end) - long(self.start) + 1) >> self.intlvBits
7587777Sgblack@eecs.umich.edu
7597777Sgblack@eecs.umich.edu    @classmethod
7607777Sgblack@eecs.umich.edu    def cxx_predecls(cls, code):
7617777Sgblack@eecs.umich.edu        Addr.cxx_predecls(code)
7627777Sgblack@eecs.umich.edu        code('#include "base/addr_range.hh"')
7637777Sgblack@eecs.umich.edu
7647777Sgblack@eecs.umich.edu    @classmethod
7657777Sgblack@eecs.umich.edu    def pybind_predecls(cls, code):
7667777Sgblack@eecs.umich.edu        Addr.pybind_predecls(code)
7677777Sgblack@eecs.umich.edu        code('#include "base/addr_range.hh"')
7687777Sgblack@eecs.umich.edu
7697777Sgblack@eecs.umich.edu    @classmethod
7707777Sgblack@eecs.umich.edu    def cxx_ini_predecls(cls, code):
7717777Sgblack@eecs.umich.edu        code('#include <sstream>')
7727777Sgblack@eecs.umich.edu
7737777Sgblack@eecs.umich.edu    @classmethod
7747777Sgblack@eecs.umich.edu    def cxx_ini_parse(cls, code, src, dest, ret):
7757777Sgblack@eecs.umich.edu        code('uint64_t _start, _end, _intlvHighBit = 0, _xorHighBit = 0;')
7767777Sgblack@eecs.umich.edu        code('uint64_t _intlvBits = 0, _intlvMatch = 0;')
7777777Sgblack@eecs.umich.edu        code('char _sep;')
7787777Sgblack@eecs.umich.edu        code('std::istringstream _stream(${src});')
7797777Sgblack@eecs.umich.edu        code('_stream >> _start;')
7807777Sgblack@eecs.umich.edu        code('_stream.get(_sep);')
7817777Sgblack@eecs.umich.edu        code('_stream >> _end;')
7827777Sgblack@eecs.umich.edu        code('if (!_stream.fail() && !_stream.eof()) {')
7837777Sgblack@eecs.umich.edu        code('    _stream.get(_sep);')
7847777Sgblack@eecs.umich.edu        code('    _stream >> _intlvHighBit;')
7857777Sgblack@eecs.umich.edu        code('    _stream.get(_sep);')
7867777Sgblack@eecs.umich.edu        code('    _stream >> _xorHighBit;')
7877777Sgblack@eecs.umich.edu        code('    _stream.get(_sep);')
7887777Sgblack@eecs.umich.edu        code('    _stream >> _intlvBits;')
7897777Sgblack@eecs.umich.edu        code('    _stream.get(_sep);')
7907777Sgblack@eecs.umich.edu        code('    _stream >> _intlvMatch;')
7917777Sgblack@eecs.umich.edu        code('}')
7927777Sgblack@eecs.umich.edu        code('bool _ret = !_stream.fail() &&'
7937777Sgblack@eecs.umich.edu            '_stream.eof() && _sep == \':\';')
7947777Sgblack@eecs.umich.edu        code('if (_ret)')
7957777Sgblack@eecs.umich.edu        code('   ${dest} = AddrRange(_start, _end, _intlvHighBit, \
7967777Sgblack@eecs.umich.edu                _xorHighBit, _intlvBits, _intlvMatch);')
7977777Sgblack@eecs.umich.edu        code('${ret} _ret;')
7987777Sgblack@eecs.umich.edu
7997777Sgblack@eecs.umich.edu    def getValue(self):
8007777Sgblack@eecs.umich.edu        # Go from the Python class to the wrapped C++ class
8017777Sgblack@eecs.umich.edu        from _m5.range import AddrRange
8027777Sgblack@eecs.umich.edu
8037777Sgblack@eecs.umich.edu        return AddrRange(long(self.start), long(self.end),
8047777Sgblack@eecs.umich.edu                         int(self.intlvHighBit), int(self.xorHighBit),
8057777Sgblack@eecs.umich.edu                         int(self.intlvBits), int(self.intlvMatch))
8067777Sgblack@eecs.umich.edu
8078579Ssteve.reinhardt@amd.com# Boolean parameter type.  Python doesn't let you subclass bool, since
8088579Ssteve.reinhardt@amd.com# it doesn't want to let you create multiple instances of True and
8098579Ssteve.reinhardt@amd.com# False.  Thus this is a little more complicated than String.
8108579Ssteve.reinhardt@amd.comclass Bool(ParamValue):
8118579Ssteve.reinhardt@amd.com    cxx_type = 'bool'
8128579Ssteve.reinhardt@amd.com    cmd_line_settable = True
8138579Ssteve.reinhardt@amd.com
8148579Ssteve.reinhardt@amd.com    def __init__(self, value):
8158579Ssteve.reinhardt@amd.com        try:
8168579Ssteve.reinhardt@amd.com            self.value = convert.toBool(value)
8178579Ssteve.reinhardt@amd.com        except TypeError:
8188579Ssteve.reinhardt@amd.com            self.value = bool(value)
8198579Ssteve.reinhardt@amd.com
8208579Ssteve.reinhardt@amd.com    def __call__(self, value):
8217777Sgblack@eecs.umich.edu        self.__init__(value)
8227777Sgblack@eecs.umich.edu        return value
8237777Sgblack@eecs.umich.edu
8247777Sgblack@eecs.umich.edu    def getValue(self):
8257777Sgblack@eecs.umich.edu        return bool(self.value)
8267777Sgblack@eecs.umich.edu
8277777Sgblack@eecs.umich.edu    def __str__(self):
8287777Sgblack@eecs.umich.edu        return str(self.value)
8297777Sgblack@eecs.umich.edu
8307777Sgblack@eecs.umich.edu    # implement truth value testing for Bool parameters so that these params
8317777Sgblack@eecs.umich.edu    # evaluate correctly during the python configuration phase
8327777Sgblack@eecs.umich.edu    def __nonzero__(self):
8337777Sgblack@eecs.umich.edu        return bool(self.value)
8347777Sgblack@eecs.umich.edu
8357777Sgblack@eecs.umich.edu    def ini_str(self):
8367777Sgblack@eecs.umich.edu        if self.value:
8377777Sgblack@eecs.umich.edu            return 'true'
8387777Sgblack@eecs.umich.edu        return 'false'
8397777Sgblack@eecs.umich.edu
8407777Sgblack@eecs.umich.edu    def config_value(self):
8417777Sgblack@eecs.umich.edu        return self.value
8427777Sgblack@eecs.umich.edu
8437777Sgblack@eecs.umich.edu    @classmethod
8447777Sgblack@eecs.umich.edu    def cxx_ini_predecls(cls, code):
8457777Sgblack@eecs.umich.edu        # Assume that base/str.hh will be included anyway
8467777Sgblack@eecs.umich.edu        # code('#include "base/str.hh"')
8477777Sgblack@eecs.umich.edu        pass
8487777Sgblack@eecs.umich.edu
8497777Sgblack@eecs.umich.edu    @classmethod
8507777Sgblack@eecs.umich.edu    def cxx_ini_parse(cls, code, src, dest, ret):
8517777Sgblack@eecs.umich.edu        code('%s to_bool(%s, %s);' % (ret, src, dest))
8527777Sgblack@eecs.umich.edu
8537777Sgblack@eecs.umich.edudef IncEthernetAddr(addr, val = 1):
8547777Sgblack@eecs.umich.edu    bytes = map(lambda x: int(x, 16), addr.split(':'))
8557777Sgblack@eecs.umich.edu    bytes[5] += val
8567777Sgblack@eecs.umich.edu    for i in (5, 4, 3, 2, 1):
8577777Sgblack@eecs.umich.edu        val,rem = divmod(bytes[i], 256)
8587777Sgblack@eecs.umich.edu        bytes[i] = rem
8597777Sgblack@eecs.umich.edu        if val == 0:
8607777Sgblack@eecs.umich.edu            break
8617777Sgblack@eecs.umich.edu        bytes[i - 1] += val
8627777Sgblack@eecs.umich.edu    assert(bytes[0] <= 255)
8637777Sgblack@eecs.umich.edu    return ':'.join(map(lambda x: '%02x' % x, bytes))
8647777Sgblack@eecs.umich.edu
8657777Sgblack@eecs.umich.edu_NextEthernetAddr = "00:90:00:00:00:01"
8667777Sgblack@eecs.umich.edudef NextEthernetAddr():
8677777Sgblack@eecs.umich.edu    global _NextEthernetAddr
8687777Sgblack@eecs.umich.edu
8697777Sgblack@eecs.umich.edu    value = _NextEthernetAddr
8707777Sgblack@eecs.umich.edu    _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1)
8717777Sgblack@eecs.umich.edu    return value
8727777Sgblack@eecs.umich.edu
8737777Sgblack@eecs.umich.educlass EthernetAddr(ParamValue):
8747777Sgblack@eecs.umich.edu    cxx_type = 'Net::EthAddr'
8757777Sgblack@eecs.umich.edu    ex_str = "00:90:00:00:00:01"
8767777Sgblack@eecs.umich.edu    cmd_line_settable = True
8777777Sgblack@eecs.umich.edu
8787777Sgblack@eecs.umich.edu    @classmethod
8798579Ssteve.reinhardt@amd.com    def cxx_predecls(cls, code):
8808579Ssteve.reinhardt@amd.com        code('#include "base/inet.hh"')
8818579Ssteve.reinhardt@amd.com
8828579Ssteve.reinhardt@amd.com    def __init__(self, value):
8838579Ssteve.reinhardt@amd.com        if value == NextEthernetAddr:
8848579Ssteve.reinhardt@amd.com            self.value = value
8858579Ssteve.reinhardt@amd.com            return
8868579Ssteve.reinhardt@amd.com
8878579Ssteve.reinhardt@amd.com        if not isinstance(value, str):
8888579Ssteve.reinhardt@amd.com            raise TypeError, "expected an ethernet address and didn't get one"
8898579Ssteve.reinhardt@amd.com
8908579Ssteve.reinhardt@amd.com        bytes = value.split(':')
8918579Ssteve.reinhardt@amd.com        if len(bytes) != 6:
8928579Ssteve.reinhardt@amd.com            raise TypeError, 'invalid ethernet address %s' % value
8937777Sgblack@eecs.umich.edu
8947777Sgblack@eecs.umich.edu        for byte in bytes:
8957777Sgblack@eecs.umich.edu            if not 0 <= int(byte, base=16) <= 0xff:
8967777Sgblack@eecs.umich.edu                raise TypeError, 'invalid ethernet address %s' % value
8977777Sgblack@eecs.umich.edu
8987777Sgblack@eecs.umich.edu        self.value = value
8997777Sgblack@eecs.umich.edu
9007777Sgblack@eecs.umich.edu    def __call__(self, value):
9017777Sgblack@eecs.umich.edu        self.__init__(value)
9023932Sbinkertn@umich.edu        return value
9033932Sbinkertn@umich.edu
9043932Sbinkertn@umich.edu    def unproxy(self, base):
9053932Sbinkertn@umich.edu        if self.value == NextEthernetAddr:
9063932Sbinkertn@umich.edu            return EthernetAddr(self.value())
9073932Sbinkertn@umich.edu        return self
9083932Sbinkertn@umich.edu
9093932Sbinkertn@umich.edu    def getValue(self):
9103932Sbinkertn@umich.edu        from _m5.net import EthAddr
9113932Sbinkertn@umich.edu        return EthAddr(self.value)
9123932Sbinkertn@umich.edu
9133932Sbinkertn@umich.edu    def __str__(self):
9143932Sbinkertn@umich.edu        return self.value
9153885Sbinkertn@umich.edu
9163932Sbinkertn@umich.edu    def ini_str(self):
9173932Sbinkertn@umich.edu        return self.value
9183885Sbinkertn@umich.edu
9193932Sbinkertn@umich.edu    @classmethod
9203932Sbinkertn@umich.edu    def cxx_ini_parse(self, code, src, dest, ret):
9213932Sbinkertn@umich.edu        code('%s = Net::EthAddr(%s);' % (dest, src))
9223932Sbinkertn@umich.edu        code('%s true;' % ret)
9233932Sbinkertn@umich.edu
9243932Sbinkertn@umich.edu# When initializing an IpAddress, pass in an existing IpAddress, a string of
9253932Sbinkertn@umich.edu# the form "a.b.c.d", or an integer representing an IP.
9263932Sbinkertn@umich.educlass IpAddress(ParamValue):
9273932Sbinkertn@umich.edu    cxx_type = 'Net::IpAddress'
9283932Sbinkertn@umich.edu    ex_str = "127.0.0.1"
9293932Sbinkertn@umich.edu    cmd_line_settable = True
9303932Sbinkertn@umich.edu
9313932Sbinkertn@umich.edu    @classmethod
9323932Sbinkertn@umich.edu    def cxx_predecls(cls, code):
9333932Sbinkertn@umich.edu        code('#include "base/inet.hh"')
9343932Sbinkertn@umich.edu
9353932Sbinkertn@umich.edu    def __init__(self, value):
9363932Sbinkertn@umich.edu        if isinstance(value, IpAddress):
9373885Sbinkertn@umich.edu            self.ip = value.ip
9383885Sbinkertn@umich.edu        else:
9393885Sbinkertn@umich.edu            try:
9403885Sbinkertn@umich.edu                self.ip = convert.toIpAddress(value)
9414762Snate@binkert.org            except TypeError:
9427673Snate@binkert.org                self.ip = long(value)
9437673Snate@binkert.org        self.verifyIp()
9447673Snate@binkert.org
9457673Snate@binkert.org    def __call__(self, value):
9467673Snate@binkert.org        self.__init__(value)
9477673Snate@binkert.org        return value
9487673Snate@binkert.org
9497673Snate@binkert.org    def __str__(self):
9507673Snate@binkert.org        tup = [(self.ip >> i)  & 0xff for i in (24, 16, 8, 0)]
9513885Sbinkertn@umich.edu        return '%d.%d.%d.%d' % tuple(tup)
9523932Sbinkertn@umich.edu
9533885Sbinkertn@umich.edu    def __eq__(self, other):
9544762Snate@binkert.org        if isinstance(other, IpAddress):
9557677Snate@binkert.org            return self.ip == other.ip
9564762Snate@binkert.org        elif isinstance(other, str):
9574762Snate@binkert.org            try:
9584762Snate@binkert.org                return self.ip == convert.toIpAddress(other)
9594762Snate@binkert.org            except:
9604762Snate@binkert.org                return False
9614762Snate@binkert.org        else:
9624762Snate@binkert.org            return self.ip == other
9634762Snate@binkert.org
9644762Snate@binkert.org    def __ne__(self, other):
9654762Snate@binkert.org        return not (self == other)
9664762Snate@binkert.org
9674762Snate@binkert.org    def verifyIp(self):
9684762Snate@binkert.org        if self.ip < 0 or self.ip >= (1 << 32):
9694762Snate@binkert.org            raise TypeError, "invalid ip address %#08x" % self.ip
9704762Snate@binkert.org
9714762Snate@binkert.org    def getValue(self):
9724762Snate@binkert.org        from _m5.net import IpAddress
9734762Snate@binkert.org        return IpAddress(self.ip)
9744762Snate@binkert.org
9754762Snate@binkert.org# When initializing an IpNetmask, pass in an existing IpNetmask, a string of
9764762Snate@binkert.org# the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as
9774762Snate@binkert.org# positional or keyword arguments.
9784762Snate@binkert.orgclass IpNetmask(IpAddress):
9794762Snate@binkert.org    cxx_type = 'Net::IpNetmask'
9803885Sbinkertn@umich.edu    ex_str = "127.0.0.0/24"
9814762Snate@binkert.org    cmd_line_settable = True
9823885Sbinkertn@umich.edu
9833885Sbinkertn@umich.edu    @classmethod
9843932Sbinkertn@umich.edu    def cxx_predecls(cls, code):
9853885Sbinkertn@umich.edu        code('#include "base/inet.hh"')
9868664SAli.Saidi@ARM.com
9878664SAli.Saidi@ARM.com    def __init__(self, *args, **kwargs):
9888664SAli.Saidi@ARM.com        def handle_kwarg(self, kwargs, key, elseVal = None):
9893101Sstever@eecs.umich.edu            if key in kwargs:
9903101Sstever@eecs.umich.edu                setattr(self, key, kwargs.pop(key))
9913101Sstever@eecs.umich.edu            elif elseVal:
9923101Sstever@eecs.umich.edu                setattr(self, key, elseVal)
9933101Sstever@eecs.umich.edu            else:
9943101Sstever@eecs.umich.edu                raise TypeError, "No value set for %s" % key
9953101Sstever@eecs.umich.edu
9963101Sstever@eecs.umich.edu        if len(args) == 0:
9973101Sstever@eecs.umich.edu            handle_kwarg(self, kwargs, 'ip')
9983101Sstever@eecs.umich.edu            handle_kwarg(self, kwargs, 'netmask')
9993101Sstever@eecs.umich.edu
10003101Sstever@eecs.umich.edu        elif len(args) == 1:
10013101Sstever@eecs.umich.edu            if kwargs:
10023101Sstever@eecs.umich.edu                if not 'ip' in kwargs and not 'netmask' in kwargs:
10034762Snate@binkert.org                    raise TypeError, "Invalid arguments"
10043101Sstever@eecs.umich.edu                handle_kwarg(self, kwargs, 'ip', args[0])
10055033Smilesck@eecs.umich.edu                handle_kwarg(self, kwargs, 'netmask', args[0])
10064762Snate@binkert.org            elif isinstance(args[0], IpNetmask):
10074762Snate@binkert.org                self.ip = args[0].ip
10084762Snate@binkert.org                self.netmask = args[0].netmask
10094762Snate@binkert.org            else:
10104762Snate@binkert.org                (self.ip, self.netmask) = convert.toIpNetmask(args[0])
10114762Snate@binkert.org
10124762Snate@binkert.org        elif len(args) == 2:
10133101Sstever@eecs.umich.edu            self.ip = args[0]
10143101Sstever@eecs.umich.edu            self.netmask = args[1]
10153101Sstever@eecs.umich.edu        else:
10163101Sstever@eecs.umich.edu            raise TypeError, "Too many arguments specified"
10173101Sstever@eecs.umich.edu
10183101Sstever@eecs.umich.edu        if kwargs:
10193101Sstever@eecs.umich.edu            raise TypeError, "Too many keywords: %s" % kwargs.keys()
10203101Sstever@eecs.umich.edu
10213101Sstever@eecs.umich.edu        self.verify()
10223101Sstever@eecs.umich.edu
10233101Sstever@eecs.umich.edu    def __call__(self, value):
10243101Sstever@eecs.umich.edu        self.__init__(value)
10253101Sstever@eecs.umich.edu        return value
10263101Sstever@eecs.umich.edu
10273101Sstever@eecs.umich.edu    def __str__(self):
10283101Sstever@eecs.umich.edu        return "%s/%d" % (super(IpNetmask, self).__str__(), self.netmask)
10293101Sstever@eecs.umich.edu
10303101Sstever@eecs.umich.edu    def __eq__(self, other):
10313101Sstever@eecs.umich.edu        if isinstance(other, IpNetmask):
10323101Sstever@eecs.umich.edu            return self.ip == other.ip and self.netmask == other.netmask
10334762Snate@binkert.org        elif isinstance(other, str):
10343101Sstever@eecs.umich.edu            try:
10353101Sstever@eecs.umich.edu                return (self.ip, self.netmask) == convert.toIpNetmask(other)
10363101Sstever@eecs.umich.edu            except:
10373101Sstever@eecs.umich.edu                return False
10383101Sstever@eecs.umich.edu        else:
10393101Sstever@eecs.umich.edu            return False
10407673Snate@binkert.org
10416654Snate@binkert.org    def verify(self):
10427673Snate@binkert.org        self.verifyIp()
10437673Snate@binkert.org        if self.netmask < 0 or self.netmask > 32:
10447673Snate@binkert.org            raise TypeError, "invalid netmask %d" % netmask
10457673Snate@binkert.org
10467673Snate@binkert.org    def getValue(self):
10477673Snate@binkert.org        from _m5.net import IpNetmask
10487673Snate@binkert.org        return IpNetmask(self.ip, self.netmask)
10497673Snate@binkert.org
10504762Snate@binkert.org# When initializing an IpWithPort, pass in an existing IpWithPort, a string of
10517673Snate@binkert.org# the form "a.b.c.d:p", or an ip and port as positional or keyword arguments.
10527673Snate@binkert.orgclass IpWithPort(IpAddress):
10537673Snate@binkert.org    cxx_type = 'Net::IpWithPort'
10547673Snate@binkert.org    ex_str = "127.0.0.1:80"
10557673Snate@binkert.org    cmd_line_settable = True
10567673Snate@binkert.org
10577673Snate@binkert.org    @classmethod
10584762Snate@binkert.org    def cxx_predecls(cls, code):
10597673Snate@binkert.org        code('#include "base/inet.hh"')
10607673Snate@binkert.org
10617673Snate@binkert.org    def __init__(self, *args, **kwargs):
10627673Snate@binkert.org        def handle_kwarg(self, kwargs, key, elseVal = None):
10636654Snate@binkert.org            if key in kwargs:
10647673Snate@binkert.org                setattr(self, key, kwargs.pop(key))
10657677Snate@binkert.org            elif elseVal:
10667673Snate@binkert.org                setattr(self, key, elseVal)
10677673Snate@binkert.org            else:
10687673Snate@binkert.org                raise TypeError, "No value set for %s" % key
10697673Snate@binkert.org
10707673Snate@binkert.org        if len(args) == 0:
10714762Snate@binkert.org            handle_kwarg(self, kwargs, 'ip')
10727673Snate@binkert.org            handle_kwarg(self, kwargs, 'port')
10737673Snate@binkert.org
10747673Snate@binkert.org        elif len(args) == 1:
10757673Snate@binkert.org            if kwargs:
10767811Ssteve.reinhardt@amd.com                if not 'ip' in kwargs and not 'port' in kwargs:
10777673Snate@binkert.org                    raise TypeError, "Invalid arguments"
10783101Sstever@eecs.umich.edu                handle_kwarg(self, kwargs, 'ip', args[0])
10798596Ssteve.reinhardt@amd.com                handle_kwarg(self, kwargs, 'port', args[0])
10808596Ssteve.reinhardt@amd.com            elif isinstance(args[0], IpWithPort):
10818596Ssteve.reinhardt@amd.com                self.ip = args[0].ip
10828596Ssteve.reinhardt@amd.com                self.port = args[0].port
10838596Ssteve.reinhardt@amd.com            else:
10848596Ssteve.reinhardt@amd.com                (self.ip, self.port) = convert.toIpWithPort(args[0])
10858596Ssteve.reinhardt@amd.com
10868596Ssteve.reinhardt@amd.com        elif len(args) == 2:
10878596Ssteve.reinhardt@amd.com            self.ip = args[0]
10888596Ssteve.reinhardt@amd.com            self.port = args[1]
10898596Ssteve.reinhardt@amd.com        else:
10908596Ssteve.reinhardt@amd.com            raise TypeError, "Too many arguments specified"
10918596Ssteve.reinhardt@amd.com
10923101Sstever@eecs.umich.edu        if kwargs:
10933101Sstever@eecs.umich.edu            raise TypeError, "Too many keywords: %s" % kwargs.keys()
10943101Sstever@eecs.umich.edu
10953101Sstever@eecs.umich.edu        self.verify()
10963101Sstever@eecs.umich.edu
10973101Sstever@eecs.umich.edu    def __call__(self, value):
10983101Sstever@eecs.umich.edu        self.__init__(value)
10993101Sstever@eecs.umich.edu        return value
11003101Sstever@eecs.umich.edu
11013101Sstever@eecs.umich.edu    def __str__(self):
11023101Sstever@eecs.umich.edu        return "%s:%d" % (super(IpWithPort, self).__str__(), self.port)
11037675Snate@binkert.org
11047675Snate@binkert.org    def __eq__(self, other):
11057675Snate@binkert.org        if isinstance(other, IpWithPort):
11067675Snate@binkert.org            return self.ip == other.ip and self.port == other.port
11077675Snate@binkert.org        elif isinstance(other, str):
11087675Snate@binkert.org            try:
11097677Snate@binkert.org                return (self.ip, self.port) == convert.toIpWithPort(other)
11107675Snate@binkert.org            except:
11114762Snate@binkert.org                return False
11124762Snate@binkert.org        else:
11134762Snate@binkert.org            return False
11143101Sstever@eecs.umich.edu
11153101Sstever@eecs.umich.edu    def verify(self):
11163101Sstever@eecs.umich.edu        self.verifyIp()
11173101Sstever@eecs.umich.edu        if self.port < 0 or self.port > 0xffff:
11183101Sstever@eecs.umich.edu            raise TypeError, "invalid port %d" % self.port
11193101Sstever@eecs.umich.edu
11204167Sbinkertn@umich.edu    def getValue(self):
11213101Sstever@eecs.umich.edu        from _m5.net import IpWithPort
11227673Snate@binkert.org        return IpWithPort(self.ip, self.port)
11237673Snate@binkert.org
11247673Snate@binkert.orgtime_formats = [ "%a %b %d %H:%M:%S %Z %Y",
11257673Snate@binkert.org                 "%a %b %d %H:%M:%S %Y",
11267673Snate@binkert.org                 "%Y/%m/%d %H:%M:%S",
11277673Snate@binkert.org                 "%Y/%m/%d %H:%M",
11287673Snate@binkert.org                 "%Y/%m/%d",
11297673Snate@binkert.org                 "%m/%d/%Y %H:%M:%S",
11307673Snate@binkert.org                 "%m/%d/%Y %H:%M",
11314167Sbinkertn@umich.edu                 "%m/%d/%Y",
11324762Snate@binkert.org                 "%m/%d/%y %H:%M:%S",
11334762Snate@binkert.org                 "%m/%d/%y %H:%M",
11344762Snate@binkert.org                 "%m/%d/%y"]
11354167Sbinkertn@umich.edu
11363101Sstever@eecs.umich.edu
11374167Sbinkertn@umich.edudef parse_time(value):
11384167Sbinkertn@umich.edu    from time import gmtime, strptime, struct_time, time
11394167Sbinkertn@umich.edu    from datetime import datetime, date
11404167Sbinkertn@umich.edu
11414167Sbinkertn@umich.edu    if isinstance(value, struct_time):
11424167Sbinkertn@umich.edu        return value
11434167Sbinkertn@umich.edu
11444167Sbinkertn@umich.edu    if isinstance(value, (int, long)):
11454167Sbinkertn@umich.edu        return gmtime(value)
11464167Sbinkertn@umich.edu
11474167Sbinkertn@umich.edu    if isinstance(value, (datetime, date)):
11484167Sbinkertn@umich.edu        return value.timetuple()
11493101Sstever@eecs.umich.edu
11503101Sstever@eecs.umich.edu    if isinstance(value, str):
11513101Sstever@eecs.umich.edu        if value in ('Now', 'Today'):
11523101Sstever@eecs.umich.edu            return time.gmtime(time.time())
11533101Sstever@eecs.umich.edu
11543101Sstever@eecs.umich.edu        for format in time_formats:
11553101Sstever@eecs.umich.edu            try:
11563101Sstever@eecs.umich.edu                return strptime(value, format)
11574762Snate@binkert.org            except ValueError:
11584762Snate@binkert.org                pass
11594762Snate@binkert.org
11604762Snate@binkert.org    raise ValueError, "Could not parse '%s' as a time" % value
11614762Snate@binkert.org
11624762Snate@binkert.orgclass Time(ParamValue):
11634762Snate@binkert.org    cxx_type = 'tm'
11643101Sstever@eecs.umich.edu
11653101Sstever@eecs.umich.edu    @classmethod
11664762Snate@binkert.org    def cxx_predecls(cls, code):
11673101Sstever@eecs.umich.edu        code('#include <time.h>')
11684167Sbinkertn@umich.edu
11693101Sstever@eecs.umich.edu    def __init__(self, value):
11704167Sbinkertn@umich.edu        self.value = parse_time(value)
11714167Sbinkertn@umich.edu
11724167Sbinkertn@umich.edu    def __call__(self, value):
11734167Sbinkertn@umich.edu        self.__init__(value)
11744167Sbinkertn@umich.edu        return value
11754167Sbinkertn@umich.edu
11764167Sbinkertn@umich.edu    def getValue(self):
11774167Sbinkertn@umich.edu        from _m5.core import tm
11784167Sbinkertn@umich.edu        import calendar
11794167Sbinkertn@umich.edu
11804167Sbinkertn@umich.edu        return tm.gmtime(calendar.timegm(self.value))
11814167Sbinkertn@umich.edu
11823101Sstever@eecs.umich.edu    def __str__(self):
11833101Sstever@eecs.umich.edu        return time.asctime(self.value)
11843101Sstever@eecs.umich.edu
11853101Sstever@eecs.umich.edu    def ini_str(self):
11863101Sstever@eecs.umich.edu        return str(self)
11873101Sstever@eecs.umich.edu
11883101Sstever@eecs.umich.edu    def get_config_as_dict(self):
11893101Sstever@eecs.umich.edu        assert false
11904167Sbinkertn@umich.edu        return str(self)
11914762Snate@binkert.org
11924762Snate@binkert.org    @classmethod
11934762Snate@binkert.org    def cxx_ini_predecls(cls, code):
11944762Snate@binkert.org        code('#include <time.h>')
11954762Snate@binkert.org
11964762Snate@binkert.org    @classmethod
11974762Snate@binkert.org    def cxx_ini_parse(cls, code, src, dest, ret):
11983101Sstever@eecs.umich.edu        code('char *_parse_ret = strptime((${src}).c_str(),')
11994762Snate@binkert.org        code('    "%a %b %d %H:%M:%S %Y", &(${dest}));')
12003101Sstever@eecs.umich.edu        code('${ret} _parse_ret && *_parse_ret == \'\\0\';');
12013101Sstever@eecs.umich.edu
12023101Sstever@eecs.umich.edu# Enumerated types are a little more complex.  The user specifies the
12033101Sstever@eecs.umich.edu# type as Enum(foo) where foo is either a list or dictionary of
12043101Sstever@eecs.umich.edu# alternatives (typically strings, but not necessarily so).  (In the
12053101Sstever@eecs.umich.edu# long run, the integer value of the parameter will be the list index
12067673Snate@binkert.org# or the corresponding dictionary value.  For now, since we only check
12077673Snate@binkert.org# that the alternative is valid and then spit it into a .ini file,
12087673Snate@binkert.org# there's not much point in using the dictionary.)
12097673Snate@binkert.org
12107673Snate@binkert.org# What Enum() must do is generate a new type encapsulating the
12117673Snate@binkert.org# provided list/dictionary so that specific values of the parameter
12127673Snate@binkert.org# can be instances of that type.  We define two hidden internal
12137673Snate@binkert.org# classes (_ListEnum and _DictEnum) to serve as base classes, then
12147673Snate@binkert.org# derive the new type from the appropriate base class on the fly.
12157673Snate@binkert.org
12163101Sstever@eecs.umich.eduallEnums = {}
12174167Sbinkertn@umich.edu# Metaclass for Enum types
12184167Sbinkertn@umich.educlass MetaEnum(MetaParamValue):
12194167Sbinkertn@umich.edu    def __new__(mcls, name, bases, dict):
12204167Sbinkertn@umich.edu        assert name not in allEnums
12214167Sbinkertn@umich.edu
12224167Sbinkertn@umich.edu        cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict)
12234167Sbinkertn@umich.edu        allEnums[name] = cls
12244167Sbinkertn@umich.edu        return cls
12254167Sbinkertn@umich.edu
12264167Sbinkertn@umich.edu    def __init__(cls, name, bases, init_dict):
12274167Sbinkertn@umich.edu        if init_dict.has_key('map'):
12284167Sbinkertn@umich.edu            if not isinstance(cls.map, dict):
12293101Sstever@eecs.umich.edu                raise TypeError, "Enum-derived class attribute 'map' " \
12303101Sstever@eecs.umich.edu                      "must be of type dict"
12313101Sstever@eecs.umich.edu            # build list of value strings from map
12323101Sstever@eecs.umich.edu            cls.vals = cls.map.keys()
12333101Sstever@eecs.umich.edu            cls.vals.sort()
12343101Sstever@eecs.umich.edu        elif init_dict.has_key('vals'):
12353101Sstever@eecs.umich.edu            if not isinstance(cls.vals, list):
12363101Sstever@eecs.umich.edu                raise TypeError, "Enum-derived class attribute 'vals' " \
12374762Snate@binkert.org                      "must be of type list"
12384762Snate@binkert.org            # build string->value map from vals sequence
12394762Snate@binkert.org            cls.map = {}
12403101Sstever@eecs.umich.edu            for idx,val in enumerate(cls.vals):
12413101Sstever@eecs.umich.edu                cls.map[val] = idx
12423101Sstever@eecs.umich.edu        else:
12433101Sstever@eecs.umich.edu            raise TypeError, "Enum-derived class must define "\
12443101Sstever@eecs.umich.edu                  "attribute 'map' or 'vals'"
12453101Sstever@eecs.umich.edu
12464167Sbinkertn@umich.edu        cls.cxx_type = 'Enums::%s' % name
12474167Sbinkertn@umich.edu
12483101Sstever@eecs.umich.edu        super(MetaEnum, cls).__init__(name, bases, init_dict)
12493101Sstever@eecs.umich.edu
12503101Sstever@eecs.umich.edu    # Generate C++ class declaration for this enum type.
12513101Sstever@eecs.umich.edu    # Note that we wrap the enum in a class/struct to act as a namespace,
12523101Sstever@eecs.umich.edu    # so that the enum strings can be brief w/o worrying about collisions.
12534762Snate@binkert.org    def cxx_decl(cls, code):
12544167Sbinkertn@umich.edu        wrapper_name = cls.wrapper_name
12554167Sbinkertn@umich.edu        wrapper = 'struct' if cls.wrapper_is_struct else 'namespace'
12564167Sbinkertn@umich.edu        name = cls.__name__ if cls.enum_name is None else cls.enum_name
12574762Snate@binkert.org        idem_macro = '__ENUM__%s__%s__' % (wrapper_name, name)
12584762Snate@binkert.org
12594762Snate@binkert.org        code('''\
12604762Snate@binkert.org#ifndef $idem_macro
12614762Snate@binkert.org#define $idem_macro
12623101Sstever@eecs.umich.edu
12633101Sstever@eecs.umich.edu$wrapper $wrapper_name {
12643101Sstever@eecs.umich.edu    enum $name {
12655469Snate@binkert.org''')
12667743Sgblack@eecs.umich.edu        code.indent(2)
12673102Sstever@eecs.umich.edu        for val in cls.vals:
12683101Sstever@eecs.umich.edu            code('$val = ${{cls.map[val]}},')
12693101Sstever@eecs.umich.edu        code('Num_$name = ${{len(cls.vals)}}')
12703101Sstever@eecs.umich.edu        code.dedent(2)
12713101Sstever@eecs.umich.edu        code('    };')
12723101Sstever@eecs.umich.edu
12734762Snate@binkert.org        if cls.wrapper_is_struct:
12744167Sbinkertn@umich.edu            code('    static const char *${name}Strings[Num_${name}];')
12755468Snate@binkert.org            code('};')
12765468Snate@binkert.org        else:
12775468Snate@binkert.org            code('extern const char *${name}Strings[Num_${name}];')
12784167Sbinkertn@umich.edu            code('}')
12794762Snate@binkert.org
12804762Snate@binkert.org        code()
12814762Snate@binkert.org        code('#endif // $idem_macro')
12824762Snate@binkert.org
12834762Snate@binkert.org    def cxx_def(cls, code):
12843101Sstever@eecs.umich.edu        wrapper_name = cls.wrapper_name
12853101Sstever@eecs.umich.edu        file_name = cls.__name__
12863101Sstever@eecs.umich.edu        name = cls.__name__ if cls.enum_name is None else cls.enum_name
12873101Sstever@eecs.umich.edu
12883101Sstever@eecs.umich.edu        code('#include "enums/$file_name.hh"')
12893102Sstever@eecs.umich.edu        if cls.wrapper_is_struct:
12903102Sstever@eecs.umich.edu            code('const char *${wrapper_name}::${name}Strings'
12913102Sstever@eecs.umich.edu                '[Num_${name}] =')
12923102Sstever@eecs.umich.edu        else:
12933102Sstever@eecs.umich.edu            code('namespace Enums {')
12943102Sstever@eecs.umich.edu            code.indent(1)
12953102Sstever@eecs.umich.edu            code(' const char *${name}Strings[Num_${name}] =')
12963102Sstever@eecs.umich.edu
12973102Sstever@eecs.umich.edu        code('{')
12983102Sstever@eecs.umich.edu        code.indent(1)
12993102Sstever@eecs.umich.edu        for val in cls.vals:
13003102Sstever@eecs.umich.edu            code('"$val",')
13013102Sstever@eecs.umich.edu        code.dedent(1)
13023102Sstever@eecs.umich.edu        code('};')
13033102Sstever@eecs.umich.edu
13043102Sstever@eecs.umich.edu        if not cls.wrapper_is_struct:
13053102Sstever@eecs.umich.edu            code('} // namespace $wrapper_name')
13063102Sstever@eecs.umich.edu            code.dedent(1)
13073102Sstever@eecs.umich.edu
13083102Sstever@eecs.umich.edu    def pybind_def(cls, code):
13093102Sstever@eecs.umich.edu        name = cls.__name__
13104762Snate@binkert.org        wrapper_name = cls.wrapper_name
13113102Sstever@eecs.umich.edu        enum_name = cls.__name__ if cls.enum_name is None else cls.enum_name
13123102Sstever@eecs.umich.edu
13133102Sstever@eecs.umich.edu        code('''#include "pybind11/pybind11.h"
13144762Snate@binkert.org#include "pybind11/stl.h"
13154762Snate@binkert.org
13164762Snate@binkert.org#include <sim/init.hh>
13173102Sstever@eecs.umich.edu
13183102Sstever@eecs.umich.edunamespace py = pybind11;
13193102Sstever@eecs.umich.edu
13203102Sstever@eecs.umich.edustatic void
13213102Sstever@eecs.umich.edumodule_init(py::module &m_internal)
13223102Sstever@eecs.umich.edu{
13233101Sstever@eecs.umich.edu    py::module m = m_internal.def_submodule("enum_${name}");
13243101Sstever@eecs.umich.edu
13253101Sstever@eecs.umich.edu    py::enum_<${wrapper_name}::${enum_name}>(m, "enum_${name}")
13263101Sstever@eecs.umich.edu''')
13273101Sstever@eecs.umich.edu
13283101Sstever@eecs.umich.edu        code.indent()
13293101Sstever@eecs.umich.edu        code.indent()
13303101Sstever@eecs.umich.edu        for val in cls.vals:
13313101Sstever@eecs.umich.edu            code('.value("${val}", ${wrapper_name}::${val})')
13323101Sstever@eecs.umich.edu        code('.value("Num_${name}", ${wrapper_name}::Num_${enum_name})')
13333101Sstever@eecs.umich.edu        code('.export_values()')
13343101Sstever@eecs.umich.edu        code(';')
13353101Sstever@eecs.umich.edu        code.dedent()
13363101Sstever@eecs.umich.edu
13373101Sstever@eecs.umich.edu        code('}')
13383101Sstever@eecs.umich.edu        code.dedent()
13393101Sstever@eecs.umich.edu        code()
13408839Sandreas.hansson@arm.com        code('static EmbeddedPyBind embed_enum("enum_${name}", module_init);')
13413105Sstever@eecs.umich.edu
13423101Sstever@eecs.umich.edu
13433101Sstever@eecs.umich.edu# Base class for enum types.
13448839Sandreas.hansson@arm.comclass Enum(ParamValue):
13453101Sstever@eecs.umich.edu    __metaclass__ = MetaEnum
13463101Sstever@eecs.umich.edu    vals = []
13473105Sstever@eecs.umich.edu    cmd_line_settable = True
13483101Sstever@eecs.umich.edu
13493103Sstever@eecs.umich.edu    # The name of the wrapping namespace or struct
13503105Sstever@eecs.umich.edu    wrapper_name = 'Enums'
13513103Sstever@eecs.umich.edu
13528840Sandreas.hansson@arm.com    # If true, the enum is wrapped in a struct rather than a namespace
13538840Sandreas.hansson@arm.com    wrapper_is_struct = False
13548840Sandreas.hansson@arm.com
13558840Sandreas.hansson@arm.com    # If not None, use this as the enum name rather than this class name
13568840Sandreas.hansson@arm.com    enum_name = None
13573105Sstever@eecs.umich.edu
13583105Sstever@eecs.umich.edu    def __init__(self, value):
13593105Sstever@eecs.umich.edu        if value not in self.map:
13603105Sstever@eecs.umich.edu            raise TypeError, "Enum param got bad value '%s' (not in %s)" \
13613105Sstever@eecs.umich.edu                  % (value, self.vals)
13623105Sstever@eecs.umich.edu        self.value = value
13633105Sstever@eecs.umich.edu
13643105Sstever@eecs.umich.edu    def __call__(self, value):
13653105Sstever@eecs.umich.edu        self.__init__(value)
13663105Sstever@eecs.umich.edu        return value
13673105Sstever@eecs.umich.edu
13683105Sstever@eecs.umich.edu    @classmethod
13693105Sstever@eecs.umich.edu    def cxx_predecls(cls, code):
13703109Sstever@eecs.umich.edu        code('#include "enums/$0.hh"', cls.__name__)
13713105Sstever@eecs.umich.edu
13723105Sstever@eecs.umich.edu    @classmethod
13733105Sstever@eecs.umich.edu    def cxx_ini_parse(cls, code, src, dest, ret):
13743105Sstever@eecs.umich.edu        code('if (false) {')
13753105Sstever@eecs.umich.edu        for elem_name in cls.map.iterkeys():
13763105Sstever@eecs.umich.edu            code('} else if (%s == "%s") {' % (src, elem_name))
13773105Sstever@eecs.umich.edu            code.indent()
13783105Sstever@eecs.umich.edu            code('%s = Enums::%s;' % (dest, elem_name))
13795578SSteve.Reinhardt@amd.com            code('%s true;' % ret)
13803101Sstever@eecs.umich.edu            code.dedent()
13813109Sstever@eecs.umich.edu        code('} else {')
13823109Sstever@eecs.umich.edu        code('    %s false;' % ret)
13833109Sstever@eecs.umich.edu        code('}')
13843109Sstever@eecs.umich.edu
13853109Sstever@eecs.umich.edu    def getValue(self):
13863109Sstever@eecs.umich.edu        import m5.internal.params
13873109Sstever@eecs.umich.edu        e = getattr(m5.internal.params, "enum_%s" % self.__class__.__name__)
13883109Sstever@eecs.umich.edu        return e(self.map[self.value])
13893109Sstever@eecs.umich.edu
13903101Sstever@eecs.umich.edu    def __str__(self):
13913105Sstever@eecs.umich.edu        return self.value
13923105Sstever@eecs.umich.edu
13933105Sstever@eecs.umich.edu# how big does a rounding error need to be before we warn about it?
13943101Sstever@eecs.umich.edufrequency_tolerance = 0.001  # 0.1%
13953105Sstever@eecs.umich.edu
13963105Sstever@eecs.umich.educlass TickParamValue(NumericParamValue):
13973101Sstever@eecs.umich.edu    cxx_type = 'Tick'
13983105Sstever@eecs.umich.edu    ex_str = "1MHz"
13993179Sstever@eecs.umich.edu    cmd_line_settable = True
14003105Sstever@eecs.umich.edu
14013105Sstever@eecs.umich.edu    @classmethod
14023101Sstever@eecs.umich.edu    def cxx_predecls(cls, code):
14033101Sstever@eecs.umich.edu        code('#include "base/types.hh"')
14043105Sstever@eecs.umich.edu
14053105Sstever@eecs.umich.edu    def __call__(self, value):
14063105Sstever@eecs.umich.edu        self.__init__(value)
14073105Sstever@eecs.umich.edu        return value
14083105Sstever@eecs.umich.edu
14093105Sstever@eecs.umich.edu    def getValue(self):
14103105Sstever@eecs.umich.edu        return long(self.value)
14113105Sstever@eecs.umich.edu
14123105Sstever@eecs.umich.edu    @classmethod
14133105Sstever@eecs.umich.edu    def cxx_ini_predecls(cls, code):
14143105Sstever@eecs.umich.edu        code('#include <sstream>')
14153101Sstever@eecs.umich.edu
14163101Sstever@eecs.umich.edu    # Ticks are expressed in seconds in JSON files and in plain
14178597Ssteve.reinhardt@amd.com    # Ticks in .ini files.  Switch based on a config flag
14184762Snate@binkert.org    @classmethod
14198839Sandreas.hansson@arm.com    def cxx_ini_parse(self, code, src, dest, ret):
14208839Sandreas.hansson@arm.com        code('${ret} to_number(${src}, ${dest});')
14218839Sandreas.hansson@arm.com
14228839Sandreas.hansson@arm.comclass Latency(TickParamValue):
14233101Sstever@eecs.umich.edu    ex_str = "100ns"
14243101Sstever@eecs.umich.edu
14253101Sstever@eecs.umich.edu    def __init__(self, value):
14265578SSteve.Reinhardt@amd.com        if isinstance(value, (Latency, Clock)):
14275578SSteve.Reinhardt@amd.com            self.ticks = value.ticks
14288839Sandreas.hansson@arm.com            self.value = value.value
14298839Sandreas.hansson@arm.com        elif isinstance(value, Frequency):
14308839Sandreas.hansson@arm.com            self.ticks = value.ticks
14318839Sandreas.hansson@arm.com            self.value = 1.0 / value.value
14328839Sandreas.hansson@arm.com        elif value.endswith('t'):
14338839Sandreas.hansson@arm.com            self.ticks = True
14348839Sandreas.hansson@arm.com            self.value = int(value[:-1])
14357526Ssteve.reinhardt@amd.com        else:
14368839Sandreas.hansson@arm.com            self.ticks = False
14377526Ssteve.reinhardt@amd.com            self.value = convert.toLatency(value)
14387526Ssteve.reinhardt@amd.com
14397526Ssteve.reinhardt@amd.com    def __call__(self, value):
14407526Ssteve.reinhardt@amd.com        self.__init__(value)
14417526Ssteve.reinhardt@amd.com        return value
14427526Ssteve.reinhardt@amd.com
14437526Ssteve.reinhardt@amd.com    def __getattr__(self, attr):
14443101Sstever@eecs.umich.edu        if attr in ('latency', 'period'):
14453101Sstever@eecs.umich.edu            return self
14463101Sstever@eecs.umich.edu        if attr == 'frequency':
14473105Sstever@eecs.umich.edu            return Frequency(self)
14483105Sstever@eecs.umich.edu        raise AttributeError, "Latency object has no attribute '%s'" % attr
14493105Sstever@eecs.umich.edu
14508839Sandreas.hansson@arm.com    def getValue(self):
14518839Sandreas.hansson@arm.com        if self.ticks or self.value == 0:
14523105Sstever@eecs.umich.edu            value = self.value
14533105Sstever@eecs.umich.edu        else:
14543105Sstever@eecs.umich.edu            value = ticks.fromSeconds(self.value)
14553105Sstever@eecs.umich.edu        return long(value)
14563105Sstever@eecs.umich.edu
14573105Sstever@eecs.umich.edu    def config_value(self):
14583105Sstever@eecs.umich.edu        return self.getValue()
14593105Sstever@eecs.umich.edu
14608839Sandreas.hansson@arm.com    # convert latency to ticks
14613105Sstever@eecs.umich.edu    def ini_str(self):
14623105Sstever@eecs.umich.edu        return '%d' % self.getValue()
14633105Sstever@eecs.umich.edu
14648839Sandreas.hansson@arm.comclass Frequency(TickParamValue):
14653105Sstever@eecs.umich.edu    ex_str = "1GHz"
14663105Sstever@eecs.umich.edu
14673109Sstever@eecs.umich.edu    def __init__(self, value):
14683109Sstever@eecs.umich.edu        if isinstance(value, (Latency, Clock)):
14693109Sstever@eecs.umich.edu            if value.value == 0:
14708840Sandreas.hansson@arm.com                self.value = 0
14718840Sandreas.hansson@arm.com            else:
14728840Sandreas.hansson@arm.com                self.value = 1.0 / value.value
14738840Sandreas.hansson@arm.com            self.ticks = value.ticks
14748840Sandreas.hansson@arm.com        elif isinstance(value, Frequency):
14753105Sstever@eecs.umich.edu            self.value = value.value
14763105Sstever@eecs.umich.edu            self.ticks = value.ticks
14773105Sstever@eecs.umich.edu        else:
14783105Sstever@eecs.umich.edu            self.ticks = False
14793105Sstever@eecs.umich.edu            self.value = convert.toFrequency(value)
14803105Sstever@eecs.umich.edu
14813105Sstever@eecs.umich.edu    def __call__(self, value):
14823105Sstever@eecs.umich.edu        self.__init__(value)
14833105Sstever@eecs.umich.edu        return value
14848839Sandreas.hansson@arm.com
14853105Sstever@eecs.umich.edu    def __getattr__(self, attr):
14863105Sstever@eecs.umich.edu        if attr == 'frequency':
14873105Sstever@eecs.umich.edu            return self
14883105Sstever@eecs.umich.edu        if attr in ('latency', 'period'):
14893105Sstever@eecs.umich.edu            return Latency(self)
14903105Sstever@eecs.umich.edu        raise AttributeError, "Frequency object has no attribute '%s'" % attr
14913105Sstever@eecs.umich.edu
14923105Sstever@eecs.umich.edu    # convert latency to ticks
14933105Sstever@eecs.umich.edu    def getValue(self):
14943105Sstever@eecs.umich.edu        if self.ticks or self.value == 0:
14953105Sstever@eecs.umich.edu            value = self.value
14963105Sstever@eecs.umich.edu        else:
14973105Sstever@eecs.umich.edu            value = ticks.fromSeconds(1.0 / self.value)
14983109Sstever@eecs.umich.edu        return long(value)
14993109Sstever@eecs.umich.edu
15003109Sstever@eecs.umich.edu    def config_value(self):
15013109Sstever@eecs.umich.edu        return self.getValue()
15023109Sstever@eecs.umich.edu
15033109Sstever@eecs.umich.edu    def ini_str(self):
15043109Sstever@eecs.umich.edu        return '%d' % self.getValue()
15053109Sstever@eecs.umich.edu
15063109Sstever@eecs.umich.edu# A generic Frequency and/or Latency value. Value is stored as a
15073109Sstever@eecs.umich.edu# latency, just like Latency and Frequency.
15083109Sstever@eecs.umich.educlass Clock(TickParamValue):
15093109Sstever@eecs.umich.edu    def __init__(self, value):
15103109Sstever@eecs.umich.edu        if isinstance(value, (Latency, Clock)):
15113109Sstever@eecs.umich.edu            self.ticks = value.ticks
15123109Sstever@eecs.umich.edu            self.value = value.value
15133109Sstever@eecs.umich.edu        elif isinstance(value, Frequency):
15143109Sstever@eecs.umich.edu            self.ticks = value.ticks
15153109Sstever@eecs.umich.edu            self.value = 1.0 / value.value
15163109Sstever@eecs.umich.edu        elif value.endswith('t'):
15173105Sstever@eecs.umich.edu            self.ticks = True
15183105Sstever@eecs.umich.edu            self.value = int(value[:-1])
15193105Sstever@eecs.umich.edu        else:
15203105Sstever@eecs.umich.edu            self.ticks = False
15213105Sstever@eecs.umich.edu            self.value = convert.anyToLatency(value)
15223105Sstever@eecs.umich.edu
15233105Sstever@eecs.umich.edu    def __call__(self, value):
15243101Sstever@eecs.umich.edu        self.__init__(value)
15253101Sstever@eecs.umich.edu        return value
15263101Sstever@eecs.umich.edu
15273101Sstever@eecs.umich.edu    def __str__(self):
15283101Sstever@eecs.umich.edu        return "%s" % Latency(self)
15293101Sstever@eecs.umich.edu
15303105Sstever@eecs.umich.edu    def __getattr__(self, attr):
15318839Sandreas.hansson@arm.com        if attr == 'frequency':
15323101Sstever@eecs.umich.edu            return Frequency(self)
15333101Sstever@eecs.umich.edu        if attr in ('latency', 'period'):
15343101Sstever@eecs.umich.edu            return Latency(self)
15353105Sstever@eecs.umich.edu        raise AttributeError, "Frequency object has no attribute '%s'" % attr
15363105Sstever@eecs.umich.edu
15373101Sstever@eecs.umich.edu    def getValue(self):
15388840Sandreas.hansson@arm.com        return self.period.getValue()
15398840Sandreas.hansson@arm.com
15408840Sandreas.hansson@arm.com    def config_value(self):
15418840Sandreas.hansson@arm.com        return self.period.config_value()
15428840Sandreas.hansson@arm.com
15438840Sandreas.hansson@arm.com    def ini_str(self):
15448840Sandreas.hansson@arm.com        return self.period.ini_str()
15458840Sandreas.hansson@arm.com
15468840Sandreas.hansson@arm.comclass Voltage(Float):
15478840Sandreas.hansson@arm.com    ex_str = "1V"
15488840Sandreas.hansson@arm.com
15498839Sandreas.hansson@arm.com    def __new__(cls, value):
15508839Sandreas.hansson@arm.com        value = convert.toVoltage(value)
15518839Sandreas.hansson@arm.com        return super(cls, Voltage).__new__(cls, value)
15528839Sandreas.hansson@arm.com
15538839Sandreas.hansson@arm.com    def __init__(self, value):
15548839Sandreas.hansson@arm.com        value = convert.toVoltage(value)
15558839Sandreas.hansson@arm.com        super(Voltage, self).__init__(value)
15568839Sandreas.hansson@arm.com
15578839Sandreas.hansson@arm.comclass Current(Float):
15588839Sandreas.hansson@arm.com    ex_str = "1mA"
15598839Sandreas.hansson@arm.com
15608839Sandreas.hansson@arm.com    def __new__(cls, value):
15618839Sandreas.hansson@arm.com        value = convert.toCurrent(value)
15628839Sandreas.hansson@arm.com        return super(cls, Current).__new__(cls, value)
15638839Sandreas.hansson@arm.com
15648839Sandreas.hansson@arm.com    def __init__(self, value):
15658839Sandreas.hansson@arm.com        value = convert.toCurrent(value)
15668839Sandreas.hansson@arm.com        super(Current, self).__init__(value)
15673101Sstever@eecs.umich.edu
15683101Sstever@eecs.umich.educlass Energy(Float):
15693101Sstever@eecs.umich.edu    ex_str = "1pJ"
15703105Sstever@eecs.umich.edu
15713101Sstever@eecs.umich.edu    def __new__(cls, value):
15723101Sstever@eecs.umich.edu        value = convert.toEnergy(value)
15733105Sstever@eecs.umich.edu        return super(cls, Energy).__new__(cls, value)
15748839Sandreas.hansson@arm.com
15758839Sandreas.hansson@arm.com    def __init__(self, value):
15768839Sandreas.hansson@arm.com        value = convert.toEnergy(value)
15778839Sandreas.hansson@arm.com        super(Energy, self).__init__(value)
15788839Sandreas.hansson@arm.com
15798839Sandreas.hansson@arm.comclass NetworkBandwidth(float,ParamValue):
15808839Sandreas.hansson@arm.com    cxx_type = 'float'
15818839Sandreas.hansson@arm.com    ex_str = "1Gbps"
15828839Sandreas.hansson@arm.com    cmd_line_settable = True
15838839Sandreas.hansson@arm.com
15848839Sandreas.hansson@arm.com    def __new__(cls, value):
15858839Sandreas.hansson@arm.com        # convert to bits per second
15868839Sandreas.hansson@arm.com        val = convert.toNetworkBandwidth(value)
15878839Sandreas.hansson@arm.com        return super(cls, NetworkBandwidth).__new__(cls, val)
15888839Sandreas.hansson@arm.com
15898839Sandreas.hansson@arm.com    def __str__(self):
15908839Sandreas.hansson@arm.com        return str(self.val)
15918839Sandreas.hansson@arm.com
15928839Sandreas.hansson@arm.com    def __call__(self, value):
15938839Sandreas.hansson@arm.com        val = convert.toNetworkBandwidth(value)
15948839Sandreas.hansson@arm.com        self.__init__(val)
15953105Sstever@eecs.umich.edu        return value
15963109Sstever@eecs.umich.edu
15973109Sstever@eecs.umich.edu    def getValue(self):
15983109Sstever@eecs.umich.edu        # convert to seconds per byte
15993109Sstever@eecs.umich.edu        value = 8.0 / float(self)
16003109Sstever@eecs.umich.edu        # convert to ticks per byte
16013109Sstever@eecs.umich.edu        value = ticks.fromSeconds(value)
16023109Sstever@eecs.umich.edu        return float(value)
16033109Sstever@eecs.umich.edu
16043105Sstever@eecs.umich.edu    def ini_str(self):
16056654Snate@binkert.org        return '%f' % self.getValue()
16066654Snate@binkert.org
16076654Snate@binkert.org    def config_value(self):
16086654Snate@binkert.org        return '%f' % self.getValue()
16096654Snate@binkert.org
16106654Snate@binkert.org    @classmethod
16116654Snate@binkert.org    def cxx_ini_predecls(cls, code):
16126654Snate@binkert.org        code('#include <sstream>')
16136654Snate@binkert.org
16143101Sstever@eecs.umich.edu    @classmethod
16153101Sstever@eecs.umich.edu    def cxx_ini_parse(self, code, src, dest, ret):
16163101Sstever@eecs.umich.edu        code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
16173101Sstever@eecs.umich.edu
16183101Sstever@eecs.umich.educlass MemoryBandwidth(float,ParamValue):
16193101Sstever@eecs.umich.edu    cxx_type = 'float'
16207777Sgblack@eecs.umich.edu    ex_str = "1GB/s"
16213101Sstever@eecs.umich.edu    cmd_line_settable = True
16224167Sbinkertn@umich.edu
16233101Sstever@eecs.umich.edu    def __new__(cls, value):
16243101Sstever@eecs.umich.edu        # convert to bytes per second
16253101Sstever@eecs.umich.edu        val = convert.toMemoryBandwidth(value)
16263885Sbinkertn@umich.edu        return super(cls, MemoryBandwidth).__new__(cls, val)
16273102Sstever@eecs.umich.edu
16288839Sandreas.hansson@arm.com    def __call__(self, value):
16298839Sandreas.hansson@arm.com        val = convert.toMemoryBandwidth(value)
16306654Snate@binkert.org        self.__init__(val)
16316654Snate@binkert.org        return value
1632
1633    def getValue(self):
1634        # convert to seconds per byte
1635        value = float(self)
1636        if value:
1637            value = 1.0 / float(self)
1638        # convert to ticks per byte
1639        value = ticks.fromSeconds(value)
1640        return float(value)
1641
1642    def ini_str(self):
1643        return '%f' % self.getValue()
1644
1645    def config_value(self):
1646        return '%f' % self.getValue()
1647
1648    @classmethod
1649    def cxx_ini_predecls(cls, code):
1650        code('#include <sstream>')
1651
1652    @classmethod
1653    def cxx_ini_parse(self, code, src, dest, ret):
1654        code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
1655
1656#
1657# "Constants"... handy aliases for various values.
1658#
1659
1660# Special class for NULL pointers.  Note the special check in
1661# make_param_value() above that lets these be assigned where a
1662# SimObject is required.
1663# only one copy of a particular node
1664class NullSimObject(object):
1665    __metaclass__ = Singleton
1666    _name = 'Null'
1667
1668    def __call__(cls):
1669        return cls
1670
1671    def _instantiate(self, parent = None, path = ''):
1672        pass
1673
1674    def ini_str(self):
1675        return 'Null'
1676
1677    def unproxy(self, base):
1678        return self
1679
1680    def set_path(self, parent, name):
1681        pass
1682
1683    def set_parent(self, parent, name):
1684        pass
1685
1686    def clear_parent(self, old_parent):
1687        pass
1688
1689    def descendants(self):
1690        return
1691        yield None
1692
1693    def get_config_as_dict(self):
1694        return {}
1695
1696    def __str__(self):
1697        return self._name
1698
1699    def config_value(self):
1700        return None
1701
1702    def getValue(self):
1703        return None
1704
1705# The only instance you'll ever need...
1706NULL = NullSimObject()
1707
1708def isNullPointer(value):
1709    return isinstance(value, NullSimObject)
1710
1711# Some memory range specifications use this as a default upper bound.
1712MaxAddr = Addr.max
1713MaxTick = Tick.max
1714AllMemory = AddrRange(0, MaxAddr)
1715
1716
1717#####################################################################
1718#
1719# Port objects
1720#
1721# Ports are used to interconnect objects in the memory system.
1722#
1723#####################################################################
1724
1725# Port reference: encapsulates a reference to a particular port on a
1726# particular SimObject.
1727class PortRef(object):
1728    def __init__(self, simobj, name, role):
1729        assert(isSimObject(simobj) or isSimObjectClass(simobj))
1730        self.simobj = simobj
1731        self.name = name
1732        self.role = role
1733        self.peer = None   # not associated with another port yet
1734        self.ccConnected = False # C++ port connection done?
1735        self.index = -1  # always -1 for non-vector ports
1736
1737    def __str__(self):
1738        return '%s.%s' % (self.simobj, self.name)
1739
1740    def __len__(self):
1741        # Return the number of connected ports, i.e. 0 is we have no
1742        # peer and 1 if we do.
1743        return int(self.peer != None)
1744
1745    # for config.ini, print peer's name (not ours)
1746    def ini_str(self):
1747        return str(self.peer)
1748
1749    # for config.json
1750    def get_config_as_dict(self):
1751        return {'role' : self.role, 'peer' : str(self.peer)}
1752
1753    def __getattr__(self, attr):
1754        if attr == 'peerObj':
1755            # shorthand for proxies
1756            return self.peer.simobj
1757        raise AttributeError, "'%s' object has no attribute '%s'" % \
1758              (self.__class__.__name__, attr)
1759
1760    # Full connection is symmetric (both ways).  Called via
1761    # SimObject.__setattr__ as a result of a port assignment, e.g.,
1762    # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
1763    # e.g., "obj1.portA[3] = obj2.portB".
1764    def connect(self, other):
1765        if isinstance(other, VectorPortRef):
1766            # reference to plain VectorPort is implicit append
1767            other = other._get_next()
1768        if self.peer and not proxy.isproxy(self.peer):
1769            fatal("Port %s is already connected to %s, cannot connect %s\n",
1770                  self, self.peer, other);
1771        self.peer = other
1772        if proxy.isproxy(other):
1773            other.set_param_desc(PortParamDesc())
1774        elif isinstance(other, PortRef):
1775            if other.peer is not self:
1776                other.connect(self)
1777        else:
1778            raise TypeError, \
1779                  "assigning non-port reference '%s' to port '%s'" \
1780                  % (other, self)
1781
1782    # Allow a master/slave port pair to be spliced between
1783    # a port and its connected peer. Useful operation for connecting
1784    # instrumentation structures into a system when it is necessary
1785    # to connect the instrumentation after the full system has been
1786    # constructed.
1787    def splice(self, new_master_peer, new_slave_peer):
1788        if self.peer and not proxy.isproxy(self.peer):
1789            if isinstance(new_master_peer, PortRef) and \
1790               isinstance(new_slave_peer, PortRef):
1791                 old_peer = self.peer
1792                 if self.role == 'SLAVE':
1793                     self.peer = new_master_peer
1794                     old_peer.peer = new_slave_peer
1795                     new_master_peer.connect(self)
1796                     new_slave_peer.connect(old_peer)
1797                 elif self.role == 'MASTER':
1798                     self.peer = new_slave_peer
1799                     old_peer.peer = new_master_peer
1800                     new_slave_peer.connect(self)
1801                     new_master_peer.connect(old_peer)
1802                 else:
1803                     panic("Port %s has unknown role, "+\
1804                           "cannot splice in new peers\n", self)
1805            else:
1806                raise TypeError, \
1807                      "Splicing non-port references '%s','%s' to port '%s'"\
1808                      % (new_master_peer, new_slave_peer, self)
1809        else:
1810            fatal("Port %s not connected, cannot splice in new peers\n", self)
1811
1812    def clone(self, simobj, memo):
1813        if memo.has_key(self):
1814            return memo[self]
1815        newRef = copy.copy(self)
1816        memo[self] = newRef
1817        newRef.simobj = simobj
1818        assert(isSimObject(newRef.simobj))
1819        if self.peer and not proxy.isproxy(self.peer):
1820            peerObj = self.peer.simobj(_memo=memo)
1821            newRef.peer = self.peer.clone(peerObj, memo)
1822            assert(not isinstance(newRef.peer, VectorPortRef))
1823        return newRef
1824
1825    def unproxy(self, simobj):
1826        assert(simobj is self.simobj)
1827        if proxy.isproxy(self.peer):
1828            try:
1829                realPeer = self.peer.unproxy(self.simobj)
1830            except:
1831                print("Error in unproxying port '%s' of %s" %
1832                      (self.name, self.simobj.path()))
1833                raise
1834            self.connect(realPeer)
1835
1836    # Call C++ to create corresponding port connection between C++ objects
1837    def ccConnect(self):
1838        from _m5.pyobject import connectPorts
1839
1840        if self.role == 'SLAVE':
1841            # do nothing and let the master take care of it
1842            return
1843
1844        if self.ccConnected: # already done this
1845            return
1846        peer = self.peer
1847        if not self.peer: # nothing to connect to
1848            return
1849
1850        # check that we connect a master to a slave
1851        if self.role == peer.role:
1852            raise TypeError, \
1853                "cannot connect '%s' and '%s' due to identical role '%s'" \
1854                % (peer, self, self.role)
1855
1856        try:
1857            # self is always the master and peer the slave
1858            connectPorts(self.simobj.getCCObject(), self.name, self.index,
1859                         peer.simobj.getCCObject(), peer.name, peer.index)
1860        except:
1861            print("Error connecting port %s.%s to %s.%s" %
1862                  (self.simobj.path(), self.name,
1863                   peer.simobj.path(), peer.name))
1864            raise
1865        self.ccConnected = True
1866        peer.ccConnected = True
1867
1868# A reference to an individual element of a VectorPort... much like a
1869# PortRef, but has an index.
1870class VectorPortElementRef(PortRef):
1871    def __init__(self, simobj, name, role, index):
1872        PortRef.__init__(self, simobj, name, role)
1873        self.index = index
1874
1875    def __str__(self):
1876        return '%s.%s[%d]' % (self.simobj, self.name, self.index)
1877
1878# A reference to a complete vector-valued port (not just a single element).
1879# Can be indexed to retrieve individual VectorPortElementRef instances.
1880class VectorPortRef(object):
1881    def __init__(self, simobj, name, role):
1882        assert(isSimObject(simobj) or isSimObjectClass(simobj))
1883        self.simobj = simobj
1884        self.name = name
1885        self.role = role
1886        self.elements = []
1887
1888    def __str__(self):
1889        return '%s.%s[:]' % (self.simobj, self.name)
1890
1891    def __len__(self):
1892        # Return the number of connected peers, corresponding the the
1893        # length of the elements.
1894        return len(self.elements)
1895
1896    # for config.ini, print peer's name (not ours)
1897    def ini_str(self):
1898        return ' '.join([el.ini_str() for el in self.elements])
1899
1900    # for config.json
1901    def get_config_as_dict(self):
1902        return {'role' : self.role,
1903                'peer' : [el.ini_str() for el in self.elements]}
1904
1905    def __getitem__(self, key):
1906        if not isinstance(key, int):
1907            raise TypeError, "VectorPort index must be integer"
1908        if key >= len(self.elements):
1909            # need to extend list
1910            ext = [VectorPortElementRef(self.simobj, self.name, self.role, i)
1911                   for i in range(len(self.elements), key+1)]
1912            self.elements.extend(ext)
1913        return self.elements[key]
1914
1915    def _get_next(self):
1916        return self[len(self.elements)]
1917
1918    def __setitem__(self, key, value):
1919        if not isinstance(key, int):
1920            raise TypeError, "VectorPort index must be integer"
1921        self[key].connect(value)
1922
1923    def connect(self, other):
1924        if isinstance(other, (list, tuple)):
1925            # Assign list of port refs to vector port.
1926            # For now, append them... not sure if that's the right semantics
1927            # or if it should replace the current vector.
1928            for ref in other:
1929                self._get_next().connect(ref)
1930        else:
1931            # scalar assignment to plain VectorPort is implicit append
1932            self._get_next().connect(other)
1933
1934    def clone(self, simobj, memo):
1935        if memo.has_key(self):
1936            return memo[self]
1937        newRef = copy.copy(self)
1938        memo[self] = newRef
1939        newRef.simobj = simobj
1940        assert(isSimObject(newRef.simobj))
1941        newRef.elements = [el.clone(simobj, memo) for el in self.elements]
1942        return newRef
1943
1944    def unproxy(self, simobj):
1945        [el.unproxy(simobj) for el in self.elements]
1946
1947    def ccConnect(self):
1948        [el.ccConnect() for el in self.elements]
1949
1950# Port description object.  Like a ParamDesc object, this represents a
1951# logical port in the SimObject class, not a particular port on a
1952# SimObject instance.  The latter are represented by PortRef objects.
1953class Port(object):
1954    # Generate a PortRef for this port on the given SimObject with the
1955    # given name
1956    def makeRef(self, simobj):
1957        return PortRef(simobj, self.name, self.role)
1958
1959    # Connect an instance of this port (on the given SimObject with
1960    # the given name) with the port described by the supplied PortRef
1961    def connect(self, simobj, ref):
1962        self.makeRef(simobj).connect(ref)
1963
1964    # No need for any pre-declarations at the moment as we merely rely
1965    # on an unsigned int.
1966    def cxx_predecls(self, code):
1967        pass
1968
1969    def pybind_predecls(self, code):
1970        cls.cxx_predecls(self, code)
1971
1972    # Declare an unsigned int with the same name as the port, that
1973    # will eventually hold the number of connected ports (and thus the
1974    # number of elements for a VectorPort).
1975    def cxx_decl(self, code):
1976        code('unsigned int port_${{self.name}}_connection_count;')
1977
1978class MasterPort(Port):
1979    # MasterPort("description")
1980    def __init__(self, *args):
1981        if len(args) == 1:
1982            self.desc = args[0]
1983            self.role = 'MASTER'
1984        else:
1985            raise TypeError, 'wrong number of arguments'
1986
1987class SlavePort(Port):
1988    # SlavePort("description")
1989    def __init__(self, *args):
1990        if len(args) == 1:
1991            self.desc = args[0]
1992            self.role = 'SLAVE'
1993        else:
1994            raise TypeError, 'wrong number of arguments'
1995
1996# VectorPort description object.  Like Port, but represents a vector
1997# of connections (e.g., as on a XBar).
1998class VectorPort(Port):
1999    def __init__(self, *args):
2000        self.isVec = True
2001
2002    def makeRef(self, simobj):
2003        return VectorPortRef(simobj, self.name, self.role)
2004
2005class VectorMasterPort(VectorPort):
2006    # VectorMasterPort("description")
2007    def __init__(self, *args):
2008        if len(args) == 1:
2009            self.desc = args[0]
2010            self.role = 'MASTER'
2011            VectorPort.__init__(self, *args)
2012        else:
2013            raise TypeError, 'wrong number of arguments'
2014
2015class VectorSlavePort(VectorPort):
2016    # VectorSlavePort("description")
2017    def __init__(self, *args):
2018        if len(args) == 1:
2019            self.desc = args[0]
2020            self.role = 'SLAVE'
2021            VectorPort.__init__(self, *args)
2022        else:
2023            raise TypeError, 'wrong number of arguments'
2024
2025# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
2026# proxy objects (via set_param_desc()) so that proxy error messages
2027# make sense.
2028class PortParamDesc(object):
2029    __metaclass__ = Singleton
2030
2031    ptype_str = 'Port'
2032    ptype = Port
2033
2034baseEnums = allEnums.copy()
2035baseParams = allParams.copy()
2036
2037def clear():
2038    global allEnums, allParams
2039
2040    allEnums = baseEnums.copy()
2041    allParams = baseParams.copy()
2042
2043__all__ = ['Param', 'VectorParam',
2044           'Enum', 'Bool', 'String', 'Float',
2045           'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
2046           'Int32', 'UInt32', 'Int64', 'UInt64',
2047           'Counter', 'Addr', 'Tick', 'Percent',
2048           'TcpPort', 'UdpPort', 'EthernetAddr',
2049           'IpAddress', 'IpNetmask', 'IpWithPort',
2050           'MemorySize', 'MemorySize32',
2051           'Latency', 'Frequency', 'Clock', 'Voltage', 'Current', 'Energy',
2052           'NetworkBandwidth', 'MemoryBandwidth',
2053           'AddrRange',
2054           'MaxAddr', 'MaxTick', 'AllMemory',
2055           'Time',
2056           'NextEthernetAddr', 'NULL',
2057           'MasterPort', 'SlavePort',
2058           'VectorMasterPort', 'VectorSlavePort']
2059
2060import SimObject
2061