params.py revision 10267
110037SARM gem5 Developers# Copyright (c) 2012-2013 ARM Limited
210037SARM gem5 Developers# All rights reserved.
312359Snikos.nikoleris@arm.com#
410037SARM gem5 Developers# The license below extends only to copyright in the software and shall
510037SARM gem5 Developers# not be construed as granting a license to any other intellectual
610037SARM gem5 Developers# property including but not limited to intellectual property relating
710037SARM gem5 Developers# to a hardware implementation of the functionality of the software
810037SARM gem5 Developers# licensed hereunder.  You may use the software subject to the license
910037SARM gem5 Developers# terms below provided that you ensure that this notice is replicated
1010037SARM gem5 Developers# unmodified and in its entirety in all distributions of the software,
1110037SARM gem5 Developers# modified or unmodified, in source code or in binary form.
1210037SARM gem5 Developers#
1310037SARM gem5 Developers# Copyright (c) 2004-2006 The Regents of The University of Michigan
1410037SARM gem5 Developers# Copyright (c) 2010-2011 Advanced Micro Devices, Inc.
1510037SARM gem5 Developers# All rights reserved.
1610037SARM gem5 Developers#
1710037SARM gem5 Developers# Redistribution and use in source and binary forms, with or without
1810037SARM gem5 Developers# modification, are permitted provided that the following conditions are
1910037SARM gem5 Developers# met: redistributions of source code must retain the above copyright
2010037SARM gem5 Developers# notice, this list of conditions and the following disclaimer;
2110037SARM gem5 Developers# redistributions in binary form must reproduce the above copyright
2210037SARM gem5 Developers# notice, this list of conditions and the following disclaimer in the
2310037SARM gem5 Developers# documentation and/or other materials provided with the distribution;
2410037SARM gem5 Developers# neither the name of the copyright holders nor the names of its
2510037SARM gem5 Developers# contributors may be used to endorse or promote products derived from
2610037SARM gem5 Developers# this software without specific prior written permission.
2710037SARM gem5 Developers#
2810037SARM gem5 Developers# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2910037SARM gem5 Developers# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3010037SARM gem5 Developers# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
3110037SARM gem5 Developers# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3210037SARM gem5 Developers# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3310037SARM gem5 Developers# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3410037SARM gem5 Developers# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3510037SARM gem5 Developers# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3610037SARM gem5 Developers# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3710037SARM gem5 Developers# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3810037SARM gem5 Developers# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3910037SARM gem5 Developers#
4010037SARM gem5 Developers# Authors: Steve Reinhardt
4110037SARM gem5 Developers#          Nathan Binkert
4210037SARM gem5 Developers#          Gabe Black
4310037SARM gem5 Developers#          Andreas Hansson
4410037SARM gem5 Developers
4510037SARM gem5 Developers#####################################################################
4610037SARM gem5 Developers#
4710037SARM gem5 Developers# Parameter description classes
4810037SARM gem5 Developers#
4910037SARM gem5 Developers# The _params dictionary in each class maps parameter names to either
5010037SARM gem5 Developers# a Param or a VectorParam object.  These objects contain the
5110037SARM gem5 Developers# parameter description string, the parameter type, and the default
5210037SARM gem5 Developers# value (if any).  The convert() method on these objects is used to
5311862Snikos.nikoleris@arm.com# force whatever value is assigned to the parameter to the appropriate
5410037SARM gem5 Developers# type.
5510037SARM gem5 Developers#
5610037SARM gem5 Developers# Note that the default values are loaded into the class's attribute
5710037SARM gem5 Developers# space when the parameter dictionary is initialized (in
5810037SARM gem5 Developers# MetaSimObject._new_param()); after that point they aren't used.
5910037SARM gem5 Developers#
6010037SARM gem5 Developers#####################################################################
6110037SARM gem5 Developers
6210037SARM gem5 Developersimport copy
6310037SARM gem5 Developersimport datetime
6410037SARM gem5 Developersimport re
6510037SARM gem5 Developersimport sys
6610037SARM gem5 Developersimport time
6710037SARM gem5 Developersimport math
6810037SARM gem5 Developers
6910037SARM gem5 Developersimport proxy
7010037SARM gem5 Developersimport ticks
7110037SARM gem5 Developersfrom util import *
7210037SARM gem5 Developers
7310037SARM gem5 Developersdef isSimObject(*args, **kwargs):
7410037SARM gem5 Developers    return SimObject.isSimObject(*args, **kwargs)
7510037SARM gem5 Developers
7610037SARM gem5 Developersdef isSimObjectSequence(*args, **kwargs):
7710037SARM gem5 Developers    return SimObject.isSimObjectSequence(*args, **kwargs)
7810037SARM gem5 Developers
7910037SARM gem5 Developersdef isSimObjectClass(*args, **kwargs):
8010037SARM gem5 Developers    return SimObject.isSimObjectClass(*args, **kwargs)
8110037SARM gem5 Developers
8210037SARM gem5 DevelopersallParams = {}
8310037SARM gem5 Developers
8410037SARM gem5 Developersclass MetaParamValue(type):
8510037SARM gem5 Developers    def __new__(mcls, name, bases, dct):
8610037SARM gem5 Developers        cls = super(MetaParamValue, mcls).__new__(mcls, name, bases, dct)
8710037SARM gem5 Developers        assert name not in allParams
8810037SARM gem5 Developers        allParams[name] = cls
8910037SARM gem5 Developers        return cls
9010037SARM gem5 Developers
9110037SARM gem5 Developers
9210037SARM gem5 Developers# Dummy base class to identify types that are legitimate for SimObject
9310037SARM gem5 Developers# parameters.
9410037SARM gem5 Developersclass ParamValue(object):
9510037SARM gem5 Developers    __metaclass__ = MetaParamValue
9610037SARM gem5 Developers    cmd_line_settable = False
9710037SARM gem5 Developers
9810037SARM gem5 Developers    # Generate the code needed as a prerequisite for declaring a C++
9910037SARM gem5 Developers    # object of this type.  Typically generates one or more #include
10010037SARM gem5 Developers    # statements.  Used when declaring parameters of this type.
10110037SARM gem5 Developers    @classmethod
10210037SARM gem5 Developers    def cxx_predecls(cls, code):
10310037SARM gem5 Developers        pass
10410037SARM gem5 Developers
10510037SARM gem5 Developers    # Generate the code needed as a prerequisite for including a
10610037SARM gem5 Developers    # reference to a C++ object of this type in a SWIG .i file.
10710037SARM gem5 Developers    # Typically generates one or more %import or %include statements.
10810037SARM gem5 Developers    @classmethod
10910037SARM gem5 Developers    def swig_predecls(cls, code):
11010037SARM gem5 Developers        pass
11110037SARM gem5 Developers
11210037SARM gem5 Developers    # default for printing to .ini file is regular string conversion.
11310037SARM gem5 Developers    # will be overridden in some cases
11410037SARM gem5 Developers    def ini_str(self):
11510037SARM gem5 Developers        return str(self)
11610037SARM gem5 Developers
11710037SARM gem5 Developers    # allows us to blithely call unproxy() on things without checking
11810037SARM gem5 Developers    # if they're really proxies or not
11910037SARM gem5 Developers    def unproxy(self, base):
12010037SARM gem5 Developers        return self
12110037SARM gem5 Developers
12210037SARM gem5 Developers    # Produce a human readable version of the stored value
12310037SARM gem5 Developers    def pretty_print(self, value):
12410037SARM gem5 Developers        return str(value)
12510037SARM gem5 Developers
12610037SARM gem5 Developers# Regular parameter description.
12710037SARM gem5 Developersclass ParamDesc(object):
12810037SARM gem5 Developers    def __init__(self, ptype_str, ptype, *args, **kwargs):
12910037SARM gem5 Developers        self.ptype_str = ptype_str
13010037SARM gem5 Developers        # remember ptype only if it is provided
13110037SARM gem5 Developers        if ptype != None:
13210037SARM gem5 Developers            self.ptype = ptype
13310037SARM gem5 Developers
13410037SARM gem5 Developers        if args:
13510037SARM gem5 Developers            if len(args) == 1:
13610037SARM gem5 Developers                self.desc = args[0]
13710037SARM gem5 Developers            elif len(args) == 2:
13810037SARM gem5 Developers                self.default = args[0]
13910037SARM gem5 Developers                self.desc = args[1]
14010037SARM gem5 Developers            else:
14110037SARM gem5 Developers                raise TypeError, 'too many arguments'
14210037SARM gem5 Developers
14310037SARM gem5 Developers        if kwargs.has_key('desc'):
14410037SARM gem5 Developers            assert(not hasattr(self, 'desc'))
14510037SARM gem5 Developers            self.desc = kwargs['desc']
14610037SARM gem5 Developers            del kwargs['desc']
14710037SARM gem5 Developers
14810037SARM gem5 Developers        if kwargs.has_key('default'):
14910037SARM gem5 Developers            assert(not hasattr(self, 'default'))
15010037SARM gem5 Developers            self.default = kwargs['default']
15110037SARM gem5 Developers            del kwargs['default']
15210037SARM gem5 Developers
15310037SARM gem5 Developers        if kwargs:
15410037SARM gem5 Developers            raise TypeError, 'extra unknown kwargs %s' % kwargs
15510037SARM gem5 Developers
15610037SARM gem5 Developers        if not hasattr(self, 'desc'):
15710037SARM gem5 Developers            raise TypeError, 'desc attribute missing'
15810037SARM gem5 Developers
15910037SARM gem5 Developers    def __getattr__(self, attr):
16010037SARM gem5 Developers        if attr == 'ptype':
16110037SARM gem5 Developers            ptype = SimObject.allClasses[self.ptype_str]
16210037SARM gem5 Developers            assert isSimObjectClass(ptype)
16310037SARM gem5 Developers            self.ptype = ptype
16410037SARM gem5 Developers            return ptype
16510037SARM gem5 Developers
16610037SARM gem5 Developers        raise AttributeError, "'%s' object has no attribute '%s'" % \
16710037SARM gem5 Developers              (type(self).__name__, attr)
16810037SARM gem5 Developers
16910037SARM gem5 Developers    def example_str(self):
17010037SARM gem5 Developers        if hasattr(self.ptype, "ex_str"):
17110037SARM gem5 Developers            return self.ptype.ex_str
17210037SARM gem5 Developers        else:
17310037SARM gem5 Developers            return self.ptype_str
17410037SARM gem5 Developers
17510037SARM gem5 Developers    # Is the param available to be exposed on the command line
17610037SARM gem5 Developers    def isCmdLineSettable(self):
17710037SARM gem5 Developers        if hasattr(self.ptype, "cmd_line_settable"):
17810037SARM gem5 Developers            return self.ptype.cmd_line_settable
17910037SARM gem5 Developers        else:
18010037SARM gem5 Developers            return False
18110037SARM gem5 Developers
18210037SARM gem5 Developers    def convert(self, value):
18310037SARM gem5 Developers        if isinstance(value, proxy.BaseProxy):
18410037SARM gem5 Developers            value.set_param_desc(self)
18510037SARM gem5 Developers            return value
18610037SARM gem5 Developers        if not hasattr(self, 'ptype') and isNullPointer(value):
18710037SARM gem5 Developers            # deferred evaluation of SimObject; continue to defer if
18810037SARM gem5 Developers            # we're just assigning a null pointer
18910037SARM gem5 Developers            return value
19010037SARM gem5 Developers        if isinstance(value, self.ptype):
19110037SARM gem5 Developers            return value
19210037SARM gem5 Developers        if isNullPointer(value) and isSimObjectClass(self.ptype):
19310037SARM gem5 Developers            return value
19410037SARM gem5 Developers        return self.ptype(value)
19510037SARM gem5 Developers
19610037SARM gem5 Developers    def pretty_print(self, value):
19710037SARM gem5 Developers        if isinstance(value, proxy.BaseProxy):
19810037SARM gem5 Developers           return str(value)
19910037SARM gem5 Developers        if isNullPointer(value):
20010037SARM gem5 Developers           return NULL
20110037SARM gem5 Developers        return self.ptype(value).pretty_print(value)
20210037SARM gem5 Developers
20310037SARM gem5 Developers    def cxx_predecls(self, code):
20410037SARM gem5 Developers        code('#include <cstddef>')
20510037SARM gem5 Developers        self.ptype.cxx_predecls(code)
20610037SARM gem5 Developers
20710037SARM gem5 Developers    def swig_predecls(self, code):
20810037SARM gem5 Developers        self.ptype.swig_predecls(code)
20910037SARM gem5 Developers
21010037SARM gem5 Developers    def cxx_decl(self, code):
21110037SARM gem5 Developers        code('${{self.ptype.cxx_type}} ${{self.name}};')
21210037SARM gem5 Developers
21310037SARM gem5 Developers# Vector-valued parameter description.  Just like ParamDesc, except
21410037SARM gem5 Developers# that the value is a vector (list) of the specified type instead of a
21510037SARM gem5 Developers# single value.
21610037SARM gem5 Developers
21710037SARM gem5 Developersclass VectorParamValue(list):
21810037SARM gem5 Developers    __metaclass__ = MetaParamValue
21910037SARM gem5 Developers    def __setattr__(self, attr, value):
22010037SARM gem5 Developers        raise AttributeError, \
22110037SARM gem5 Developers              "Not allowed to set %s on '%s'" % (attr, type(self).__name__)
22210037SARM gem5 Developers
22310037SARM gem5 Developers    def ini_str(self):
22410037SARM gem5 Developers        return ' '.join([v.ini_str() for v in self])
22510037SARM gem5 Developers
22610037SARM gem5 Developers    def getValue(self):
22710037SARM gem5 Developers        return [ v.getValue() for v in self ]
22810037SARM gem5 Developers
22912258Sgiacomo.travaglini@arm.com    def unproxy(self, base):
23012258Sgiacomo.travaglini@arm.com        if len(self) == 1 and isinstance(self[0], proxy.AllProxy):
23112258Sgiacomo.travaglini@arm.com            return self[0].unproxy(base)
23212258Sgiacomo.travaglini@arm.com        else:
23312258Sgiacomo.travaglini@arm.com             return [v.unproxy(base) for v in self]
23412258Sgiacomo.travaglini@arm.com
23512258Sgiacomo.travaglini@arm.comclass SimObjectVector(VectorParamValue):
23612258Sgiacomo.travaglini@arm.com    # support clone operation
23712258Sgiacomo.travaglini@arm.com    def __call__(self, **kwargs):
23812258Sgiacomo.travaglini@arm.com        return SimObjectVector([v(**kwargs) for v in self])
23912258Sgiacomo.travaglini@arm.com
24012258Sgiacomo.travaglini@arm.com    def clear_parent(self, old_parent):
24112258Sgiacomo.travaglini@arm.com        for v in self:
24212258Sgiacomo.travaglini@arm.com            v.clear_parent(old_parent)
24312258Sgiacomo.travaglini@arm.com
24412258Sgiacomo.travaglini@arm.com    def set_parent(self, parent, name):
24512258Sgiacomo.travaglini@arm.com        if len(self) == 1:
24612258Sgiacomo.travaglini@arm.com            self[0].set_parent(parent, name)
24712258Sgiacomo.travaglini@arm.com        else:
24812258Sgiacomo.travaglini@arm.com            width = int(math.ceil(math.log(len(self))/math.log(10)))
24912258Sgiacomo.travaglini@arm.com            for i,v in enumerate(self):
25012258Sgiacomo.travaglini@arm.com                v.set_parent(parent, "%s%0*d" % (name, width, i))
25112258Sgiacomo.travaglini@arm.com
25212258Sgiacomo.travaglini@arm.com    def has_parent(self):
25312258Sgiacomo.travaglini@arm.com        return reduce(lambda x,y: x and y, [v.has_parent() for v in self])
25412258Sgiacomo.travaglini@arm.com
25512258Sgiacomo.travaglini@arm.com    # return 'cpu0 cpu1' etc. for print_ini()
25612258Sgiacomo.travaglini@arm.com    def get_name(self):
25712258Sgiacomo.travaglini@arm.com        return ' '.join([v._name for v in self])
25812258Sgiacomo.travaglini@arm.com
25912258Sgiacomo.travaglini@arm.com    # By iterating through the constituent members of the vector here
26012258Sgiacomo.travaglini@arm.com    # we can nicely handle iterating over all a SimObject's children
26112258Sgiacomo.travaglini@arm.com    # without having to provide lots of special functions on
26212258Sgiacomo.travaglini@arm.com    # SimObjectVector directly.
26312258Sgiacomo.travaglini@arm.com    def descendants(self):
26412258Sgiacomo.travaglini@arm.com        for v in self:
26510037SARM gem5 Developers            for obj in v.descendants():
26610037SARM gem5 Developers                yield obj
26710037SARM gem5 Developers
26810037SARM gem5 Developers    def get_config_as_dict(self):
26910037SARM gem5 Developers        a = []
27010037SARM gem5 Developers        for v in self:
27110037SARM gem5 Developers            a.append(v.get_config_as_dict())
27210037SARM gem5 Developers        return a
27310037SARM gem5 Developers
27410037SARM gem5 Developers    # If we are replacing an item in the vector, make sure to set the
27510037SARM gem5 Developers    # parent reference of the new SimObject to be the same as the parent
27610037SARM gem5 Developers    # of the SimObject being replaced. Useful to have if we created
27710037SARM gem5 Developers    # a SimObjectVector of temporary objects that will be modified later in
27810037SARM gem5 Developers    # configuration scripts.
27910037SARM gem5 Developers    def __setitem__(self, key, value):
28010037SARM gem5 Developers        val = self[key]
28110037SARM gem5 Developers        if value.has_parent():
28210037SARM gem5 Developers            warn("SimObject %s already has a parent" % value.get_name() +\
28310037SARM gem5 Developers                 " that is being overwritten by a SimObjectVector")
28410037SARM gem5 Developers        value.set_parent(val.get_parent(), val._name)
28510037SARM gem5 Developers        super(SimObjectVector, self).__setitem__(key, value)
28610037SARM gem5 Developers
28712227Sgiacomo.travaglini@arm.com    # Enumerate the params of each member of the SimObject vector. Creates
28810037SARM gem5 Developers    # strings that will allow indexing into the vector by the python code and
28910037SARM gem5 Developers    # allow it to be specified on the command line.
29010037SARM gem5 Developers    def enumerateParams(self, flags_dict = {},
29110037SARM gem5 Developers                        cmd_line_str = "",
29210037SARM gem5 Developers                        access_str = ""):
29310037SARM gem5 Developers        if hasattr(self, "_paramEnumed"):
29410037SARM gem5 Developers            print "Cycle detected enumerating params at %s?!" % (cmd_line_str)
29510037SARM gem5 Developers        else:
29610037SARM gem5 Developers            x = 0
29710037SARM gem5 Developers            for vals in self:
29810037SARM gem5 Developers                # Each entry in the SimObjectVector should be an
29910037SARM gem5 Developers                # instance of a SimObject
30010037SARM gem5 Developers                flags_dict = vals.enumerateParams(flags_dict,
30110037SARM gem5 Developers                                                  cmd_line_str + "%d." % x,
30210037SARM gem5 Developers                                                  access_str + "[%d]." % x)
30310037SARM gem5 Developers                x = x + 1
30410037SARM gem5 Developers
30510037SARM gem5 Developers        return flags_dict
30610037SARM gem5 Developers
30710037SARM gem5 Developersclass VectorParamDesc(ParamDesc):
30810037SARM gem5 Developers    # Convert assigned value to appropriate type.  If the RHS is not a
30910037SARM gem5 Developers    # list or tuple, it generates a single-element list.
31010037SARM gem5 Developers    def convert(self, value):
31110037SARM gem5 Developers        if isinstance(value, (list, tuple)):
31210037SARM gem5 Developers            # list: coerce each element into new list
31310037SARM gem5 Developers            tmp_list = [ ParamDesc.convert(self, v) for v in value ]
31410037SARM gem5 Developers        else:
31510037SARM gem5 Developers            # singleton: coerce to a single-element list
31610037SARM gem5 Developers            tmp_list = [ ParamDesc.convert(self, value) ]
31710037SARM gem5 Developers
31810037SARM gem5 Developers        if isSimObjectSequence(tmp_list):
31910037SARM gem5 Developers            return SimObjectVector(tmp_list)
32012359Snikos.nikoleris@arm.com        else:
32112359Snikos.nikoleris@arm.com            return VectorParamValue(tmp_list)
32210037SARM gem5 Developers
32310474Sandreas.hansson@arm.com    # Produce a human readable example string that describes
32410474Sandreas.hansson@arm.com    # how to set this vector parameter in the absence of a default
32510205SAli.Saidi@ARM.com    # value.
32610474Sandreas.hansson@arm.com    def example_str(self):
32710474Sandreas.hansson@arm.com        s = super(VectorParamDesc, self).example_str()
32810037SARM gem5 Developers        help_str = "[" + s + "," + s + ", ...]"
32910037SARM gem5 Developers        return help_str
33010037SARM gem5 Developers
33110037SARM gem5 Developers    # Produce a human readable representation of the value of this vector param.
33210474Sandreas.hansson@arm.com    def pretty_print(self, value):
33310474Sandreas.hansson@arm.com        if isinstance(value, (list, tuple)):
33410037SARM gem5 Developers            tmp_list = [ ParamDesc.pretty_print(self, v) for v in value ]
33510037SARM gem5 Developers        elif isinstance(value, str):
33610037SARM gem5 Developers            tmp_list = [ ParamDesc.pretty_print(self, v) for v in value.split(',') ]
33710037SARM gem5 Developers        else:
33810037SARM gem5 Developers            tmp_list = [ ParamDesc.pretty_print(self, value) ]
33911582SDylan.Johnson@ARM.com
34010474Sandreas.hansson@arm.com        return tmp_list
34110474Sandreas.hansson@arm.com
34210037SARM gem5 Developers    # This is a helper function for the new config system
34310037SARM gem5 Developers    def __call__(self, value):
34410037SARM gem5 Developers        if isinstance(value, (list, tuple)):
34510037SARM gem5 Developers            # list: coerce each element into new list
34610037SARM gem5 Developers            tmp_list = [ ParamDesc.convert(self, v) for v in value ]
34710037SARM gem5 Developers        elif isinstance(value, str):
34810474Sandreas.hansson@arm.com            # If input is a csv string
34910474Sandreas.hansson@arm.com            tmp_list = [ ParamDesc.convert(self, v) for v in value.split(',') ]
35010037SARM gem5 Developers        else:
35110037SARM gem5 Developers            # singleton: coerce to a single-element list
35210037SARM gem5 Developers            tmp_list = [ ParamDesc.convert(self, value) ]
35310037SARM gem5 Developers
35410037SARM gem5 Developers        return VectorParamValue(tmp_list)
35512280Sgiacomo.travaglini@arm.com
35610037SARM gem5 Developers    def swig_module_name(self):
35712106SRekai.GonzalezAlberquilla@arm.com        return "%s_vector" % self.ptype_str
35810037SARM gem5 Developers
35910037SARM gem5 Developers    def swig_predecls(self, code):
36010037SARM gem5 Developers        code('%import "${{self.swig_module_name()}}.i"')
36110037SARM gem5 Developers
36212280Sgiacomo.travaglini@arm.com    def swig_decl(self, code):
36312280Sgiacomo.travaglini@arm.com        code('%module(package="m5.internal") ${{self.swig_module_name()}}')
36412280Sgiacomo.travaglini@arm.com        code('%{')
36512280Sgiacomo.travaglini@arm.com        self.ptype.cxx_predecls(code)
36612280Sgiacomo.travaglini@arm.com        code('%}')
36712280Sgiacomo.travaglini@arm.com        code()
36812280Sgiacomo.travaglini@arm.com        # Make sure the SWIGPY_SLICE_ARG is defined through this inclusion
36912280Sgiacomo.travaglini@arm.com        code('%include "std_container.i"')
37010037SARM gem5 Developers        code()
37110037SARM gem5 Developers        self.ptype.swig_predecls(code)
37210037SARM gem5 Developers        code()
37310037SARM gem5 Developers        code('%include "std_vector.i"')
37410037SARM gem5 Developers        code()
37510037SARM gem5 Developers
37610037SARM gem5 Developers        ptype = self.ptype_str
37710037SARM gem5 Developers        cxx_type = self.ptype.cxx_type
37810037SARM gem5 Developers
37912280Sgiacomo.travaglini@arm.com        code('%template(vector_$ptype) std::vector< $cxx_type >;')
38010037SARM gem5 Developers
38112106SRekai.GonzalezAlberquilla@arm.com    def cxx_predecls(self, code):
38210037SARM gem5 Developers        code('#include <vector>')
38310037SARM gem5 Developers        self.ptype.cxx_predecls(code)
38410037SARM gem5 Developers
38510037SARM gem5 Developers    def cxx_decl(self, code):
38612280Sgiacomo.travaglini@arm.com        code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};')
38712280Sgiacomo.travaglini@arm.com
38812280Sgiacomo.travaglini@arm.comclass ParamFactory(object):
38912280Sgiacomo.travaglini@arm.com    def __init__(self, param_desc_class, ptype_str = None):
39012280Sgiacomo.travaglini@arm.com        self.param_desc_class = param_desc_class
39112280Sgiacomo.travaglini@arm.com        self.ptype_str = ptype_str
39212280Sgiacomo.travaglini@arm.com
39312280Sgiacomo.travaglini@arm.com    def __getattr__(self, attr):
39412280Sgiacomo.travaglini@arm.com        if self.ptype_str:
39510037SARM gem5 Developers            attr = self.ptype_str + '.' + attr
39610037SARM gem5 Developers        return ParamFactory(self.param_desc_class, attr)
39710037SARM gem5 Developers
39810037SARM gem5 Developers    # E.g., Param.Int(5, "number of widgets")
39910037SARM gem5 Developers    def __call__(self, *args, **kwargs):
40010037SARM gem5 Developers        ptype = None
40110037SARM gem5 Developers        try:
40210037SARM gem5 Developers            ptype = allParams[self.ptype_str]
40310037SARM gem5 Developers        except KeyError:
40412106SRekai.GonzalezAlberquilla@arm.com            # if name isn't defined yet, assume it's a SimObject, and
40512106SRekai.GonzalezAlberquilla@arm.com            # try to resolve it later
40610037SARM gem5 Developers            pass
40710037SARM gem5 Developers        return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs)
40810037SARM gem5 Developers
40910037SARM gem5 DevelopersParam = ParamFactory(ParamDesc)
41010037SARM gem5 DevelopersVectorParam = ParamFactory(VectorParamDesc)
41110037SARM gem5 Developers
41210037SARM gem5 Developers#####################################################################
41310037SARM gem5 Developers#
41410037SARM gem5 Developers# Parameter Types
41510037SARM gem5 Developers#
41610037SARM gem5 Developers# Though native Python types could be used to specify parameter types
41710037SARM gem5 Developers# (the 'ptype' field of the Param and VectorParam classes), it's more
41810037SARM gem5 Developers# flexible to define our own set of types.  This gives us more control
41910037SARM gem5 Developers# over how Python expressions are converted to values (via the
42012504Snikos.nikoleris@arm.com# __init__() constructor) and how these values are printed out (via
42110037SARM gem5 Developers# the __str__() conversion method).
42210037SARM gem5 Developers#
42310037SARM gem5 Developers#####################################################################
42410037SARM gem5 Developers
42510037SARM gem5 Developers# String-valued parameter.  Just mixin the ParamValue class with the
42610037SARM gem5 Developers# built-in str class.
42710037SARM gem5 Developersclass String(ParamValue,str):
42810037SARM gem5 Developers    cxx_type = 'std::string'
42910037SARM gem5 Developers    cmd_line_settable = True
43010037SARM gem5 Developers
43112359Snikos.nikoleris@arm.com    @classmethod
43212359Snikos.nikoleris@arm.com    def cxx_predecls(self, code):
43312359Snikos.nikoleris@arm.com        code('#include <string>')
43412359Snikos.nikoleris@arm.com
43512359Snikos.nikoleris@arm.com    @classmethod
43612359Snikos.nikoleris@arm.com    def swig_predecls(cls, code):
43712359Snikos.nikoleris@arm.com        code('%include "std_string.i"')
43812359Snikos.nikoleris@arm.com
43912359Snikos.nikoleris@arm.com    def __call__(self, value):
44012359Snikos.nikoleris@arm.com        self = value
44112359Snikos.nikoleris@arm.com        return value
44212359Snikos.nikoleris@arm.com
44312359Snikos.nikoleris@arm.com    def getValue(self):
44412359Snikos.nikoleris@arm.com        return self
44512359Snikos.nikoleris@arm.com
44612359Snikos.nikoleris@arm.com# superclass for "numeric" parameter values, to emulate math
44712359Snikos.nikoleris@arm.com# operations in a type-safe way.  e.g., a Latency times an int returns
44812359Snikos.nikoleris@arm.com# a new Latency object.
44912359Snikos.nikoleris@arm.comclass NumericParamValue(ParamValue):
45012359Snikos.nikoleris@arm.com    def __str__(self):
45112359Snikos.nikoleris@arm.com        return str(self.value)
45212359Snikos.nikoleris@arm.com
45312359Snikos.nikoleris@arm.com    def __float__(self):
45412359Snikos.nikoleris@arm.com        return float(self.value)
45512359Snikos.nikoleris@arm.com
45612359Snikos.nikoleris@arm.com    def __long__(self):
45712359Snikos.nikoleris@arm.com        return long(self.value)
45812359Snikos.nikoleris@arm.com
45912359Snikos.nikoleris@arm.com    def __int__(self):
46012359Snikos.nikoleris@arm.com        return int(self.value)
46112359Snikos.nikoleris@arm.com
46212359Snikos.nikoleris@arm.com    # hook for bounds checking
46312359Snikos.nikoleris@arm.com    def _check(self):
46412359Snikos.nikoleris@arm.com        return
46512359Snikos.nikoleris@arm.com
46612359Snikos.nikoleris@arm.com    def __mul__(self, other):
46712359Snikos.nikoleris@arm.com        newobj = self.__class__(self)
46812359Snikos.nikoleris@arm.com        newobj.value *= other
46912359Snikos.nikoleris@arm.com        newobj._check()
47012359Snikos.nikoleris@arm.com        return newobj
47112359Snikos.nikoleris@arm.com
47212359Snikos.nikoleris@arm.com    __rmul__ = __mul__
47312359Snikos.nikoleris@arm.com
47412359Snikos.nikoleris@arm.com    def __div__(self, other):
47512359Snikos.nikoleris@arm.com        newobj = self.__class__(self)
47612359Snikos.nikoleris@arm.com        newobj.value /= other
47712359Snikos.nikoleris@arm.com        newobj._check()
47812359Snikos.nikoleris@arm.com        return newobj
47912359Snikos.nikoleris@arm.com
48012359Snikos.nikoleris@arm.com    def __sub__(self, other):
48112359Snikos.nikoleris@arm.com        newobj = self.__class__(self)
48212359Snikos.nikoleris@arm.com        newobj.value -= other
48312359Snikos.nikoleris@arm.com        newobj._check()
48412359Snikos.nikoleris@arm.com        return newobj
48512359Snikos.nikoleris@arm.com
48612359Snikos.nikoleris@arm.com# Metaclass for bounds-checked integer parameters.  See CheckedInt.
48712359Snikos.nikoleris@arm.comclass CheckedIntType(MetaParamValue):
48812359Snikos.nikoleris@arm.com    def __init__(cls, name, bases, dict):
48912359Snikos.nikoleris@arm.com        super(CheckedIntType, cls).__init__(name, bases, dict)
49012359Snikos.nikoleris@arm.com
49112359Snikos.nikoleris@arm.com        # CheckedInt is an abstract base class, so we actually don't
49212359Snikos.nikoleris@arm.com        # want to do any processing on it... the rest of this code is
49312359Snikos.nikoleris@arm.com        # just for classes that derive from CheckedInt.
49412359Snikos.nikoleris@arm.com        if name == 'CheckedInt':
49512359Snikos.nikoleris@arm.com            return
49612359Snikos.nikoleris@arm.com
49712359Snikos.nikoleris@arm.com        if not (hasattr(cls, 'min') and hasattr(cls, 'max')):
49812359Snikos.nikoleris@arm.com            if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')):
49912359Snikos.nikoleris@arm.com                panic("CheckedInt subclass %s must define either\n" \
50012359Snikos.nikoleris@arm.com                      "    'min' and 'max' or 'size' and 'unsigned'\n",
50112359Snikos.nikoleris@arm.com                      name);
50212359Snikos.nikoleris@arm.com            if cls.unsigned:
50312359Snikos.nikoleris@arm.com                cls.min = 0
50412359Snikos.nikoleris@arm.com                cls.max = 2 ** cls.size - 1
50512359Snikos.nikoleris@arm.com            else:
50612359Snikos.nikoleris@arm.com                cls.min = -(2 ** (cls.size - 1))
50712359Snikos.nikoleris@arm.com                cls.max = (2 ** (cls.size - 1)) - 1
50812359Snikos.nikoleris@arm.com
50912359Snikos.nikoleris@arm.com# Abstract superclass for bounds-checked integer parameters.  This
51012359Snikos.nikoleris@arm.com# class is subclassed to generate parameter classes with specific
51112359Snikos.nikoleris@arm.com# bounds.  Initialization of the min and max bounds is done in the
51212359Snikos.nikoleris@arm.com# metaclass CheckedIntType.__init__.
51312359Snikos.nikoleris@arm.comclass CheckedInt(NumericParamValue):
51412359Snikos.nikoleris@arm.com    __metaclass__ = CheckedIntType
51512359Snikos.nikoleris@arm.com    cmd_line_settable = True
51612359Snikos.nikoleris@arm.com
51712359Snikos.nikoleris@arm.com    def _check(self):
51812359Snikos.nikoleris@arm.com        if not self.min <= self.value <= self.max:
51912359Snikos.nikoleris@arm.com            raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
52012359Snikos.nikoleris@arm.com                  (self.min, self.value, self.max)
52112359Snikos.nikoleris@arm.com
52212359Snikos.nikoleris@arm.com    def __init__(self, value):
52312359Snikos.nikoleris@arm.com        if isinstance(value, str):
52412359Snikos.nikoleris@arm.com            self.value = convert.toInteger(value)
52512359Snikos.nikoleris@arm.com        elif isinstance(value, (int, long, float, NumericParamValue)):
52612359Snikos.nikoleris@arm.com            self.value = long(value)
52712359Snikos.nikoleris@arm.com        else:
52812359Snikos.nikoleris@arm.com            raise TypeError, "Can't convert object of type %s to CheckedInt" \
52912359Snikos.nikoleris@arm.com                  % type(value).__name__
53012359Snikos.nikoleris@arm.com        self._check()
53112359Snikos.nikoleris@arm.com
53212359Snikos.nikoleris@arm.com    def __call__(self, value):
53312359Snikos.nikoleris@arm.com        self.__init__(value)
53412359Snikos.nikoleris@arm.com        return value
53512359Snikos.nikoleris@arm.com
53612359Snikos.nikoleris@arm.com    @classmethod
53712359Snikos.nikoleris@arm.com    def cxx_predecls(cls, code):
53812359Snikos.nikoleris@arm.com        # most derived types require this, so we just do it here once
53912359Snikos.nikoleris@arm.com        code('#include "base/types.hh"')
54012359Snikos.nikoleris@arm.com
54112359Snikos.nikoleris@arm.com    @classmethod
54210037SARM gem5 Developers    def swig_predecls(cls, code):
54310037SARM gem5 Developers        # most derived types require this, so we just do it here once
54410037SARM gem5 Developers        code('%import "stdint.i"')
54512106SRekai.GonzalezAlberquilla@arm.com        code('%import "base/types.hh"')
54612106SRekai.GonzalezAlberquilla@arm.com
54710037SARM gem5 Developers    def getValue(self):
54810474Sandreas.hansson@arm.com        return long(self.value)
54910474Sandreas.hansson@arm.com
55010037SARM gem5 Developersclass Int(CheckedInt):      cxx_type = 'int';      size = 32; unsigned = False
55110037SARM gem5 Developersclass Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True
55210037SARM gem5 Developers
55310037SARM gem5 Developersclass Int8(CheckedInt):     cxx_type =   'int8_t'; size =  8; unsigned = False
55410037SARM gem5 Developersclass UInt8(CheckedInt):    cxx_type =  'uint8_t'; size =  8; unsigned = True
55510037SARM gem5 Developersclass Int16(CheckedInt):    cxx_type =  'int16_t'; size = 16; unsigned = False
55612106SRekai.GonzalezAlberquilla@arm.comclass UInt16(CheckedInt):   cxx_type = 'uint16_t'; size = 16; unsigned = True
55712106SRekai.GonzalezAlberquilla@arm.comclass Int32(CheckedInt):    cxx_type =  'int32_t'; size = 32; unsigned = False
55810037SARM gem5 Developersclass UInt32(CheckedInt):   cxx_type = 'uint32_t'; size = 32; unsigned = True
55910474Sandreas.hansson@arm.comclass Int64(CheckedInt):    cxx_type =  'int64_t'; size = 64; unsigned = False
56010474Sandreas.hansson@arm.comclass UInt64(CheckedInt):   cxx_type = 'uint64_t'; size = 64; unsigned = True
56110205SAli.Saidi@ARM.com
56210037SARM gem5 Developersclass Counter(CheckedInt):  cxx_type = 'Counter';  size = 64; unsigned = True
56310037SARM gem5 Developersclass Tick(CheckedInt):     cxx_type = 'Tick';     size = 64; unsigned = True
56410037SARM gem5 Developersclass TcpPort(CheckedInt):  cxx_type = 'uint16_t'; size = 16; unsigned = True
56510037SARM gem5 Developersclass UdpPort(CheckedInt):  cxx_type = 'uint16_t'; size = 16; unsigned = True
56610037SARM gem5 Developers
56710037SARM gem5 Developersclass Percent(CheckedInt):  cxx_type = 'int'; min = 0; max = 100
56810037SARM gem5 Developers
56910037SARM gem5 Developersclass Cycles(CheckedInt):
57012106SRekai.GonzalezAlberquilla@arm.com    cxx_type = 'Cycles'
57112106SRekai.GonzalezAlberquilla@arm.com    size = 64
57210037SARM gem5 Developers    unsigned = True
57310474Sandreas.hansson@arm.com
57410474Sandreas.hansson@arm.com    def getValue(self):
57510205SAli.Saidi@ARM.com        from m5.internal.core import Cycles
57610037SARM gem5 Developers        return Cycles(self.value)
57710037SARM gem5 Developers
57810037SARM gem5 Developersclass Float(ParamValue, float):
57910037SARM gem5 Developers    cxx_type = 'double'
58010037SARM gem5 Developers    cmdLineSettable = True
58110037SARM gem5 Developers
58210037SARM gem5 Developers    def __init__(self, value):
58310037SARM gem5 Developers        if isinstance(value, (int, long, float, NumericParamValue, Float, str)):
58410037SARM gem5 Developers            self.value = float(value)
58510037SARM gem5 Developers        else:
58610037SARM gem5 Developers            raise TypeError, "Can't convert object of type %s to Float" \
58710037SARM gem5 Developers                  % type(value).__name__
58810037SARM gem5 Developers
58910037SARM gem5 Developers    def __call__(self, value):
59010037SARM gem5 Developers        self.__init__(value)
59110037SARM gem5 Developers        return value
59210037SARM gem5 Developers
59310037SARM gem5 Developers    def getValue(self):
59410037SARM gem5 Developers        return float(self.value)
59510037SARM gem5 Developers
59610037SARM gem5 Developersclass MemorySize(CheckedInt):
59710037SARM gem5 Developers    cxx_type = 'uint64_t'
59810037SARM gem5 Developers    ex_str = '512MB'
59910037SARM gem5 Developers    size = 64
60010037SARM gem5 Developers    unsigned = True
60110037SARM gem5 Developers    def __init__(self, value):
60210037SARM gem5 Developers        if isinstance(value, MemorySize):
60310037SARM gem5 Developers            self.value = value.value
60410037SARM gem5 Developers        else:
60510037SARM gem5 Developers            self.value = convert.toMemorySize(value)
60610037SARM gem5 Developers        self._check()
60710037SARM gem5 Developers
60810037SARM gem5 Developersclass MemorySize32(CheckedInt):
60910037SARM gem5 Developers    cxx_type = 'uint32_t'
61010037SARM gem5 Developers    ex_str = '512MB'
61110037SARM gem5 Developers    size = 32
61210037SARM gem5 Developers    unsigned = True
61310037SARM gem5 Developers    def __init__(self, value):
61410037SARM gem5 Developers        if isinstance(value, MemorySize):
61510037SARM gem5 Developers            self.value = value.value
61610037SARM gem5 Developers        else:
61710037SARM gem5 Developers            self.value = convert.toMemorySize(value)
61810037SARM gem5 Developers        self._check()
61910037SARM gem5 Developers
62010037SARM gem5 Developersclass Addr(CheckedInt):
62110037SARM gem5 Developers    cxx_type = 'Addr'
62210037SARM gem5 Developers    size = 64
62310037SARM gem5 Developers    unsigned = True
62410037SARM gem5 Developers    def __init__(self, value):
62510037SARM gem5 Developers        if isinstance(value, Addr):
62610037SARM gem5 Developers            self.value = value.value
62710037SARM gem5 Developers        else:
62810037SARM gem5 Developers            try:
62910037SARM gem5 Developers                self.value = convert.toMemorySize(value)
63010037SARM gem5 Developers            except TypeError:
631                self.value = long(value)
632        self._check()
633    def __add__(self, other):
634        if isinstance(other, Addr):
635            return self.value + other.value
636        else:
637            return self.value + other
638    def pretty_print(self, value):
639        try:
640            val = convert.toMemorySize(value)
641        except TypeError:
642            val = long(value)
643        return "0x%x" % long(val)
644
645class AddrRange(ParamValue):
646    cxx_type = 'AddrRange'
647
648    def __init__(self, *args, **kwargs):
649        # Disable interleaving by default
650        self.intlvHighBit = 0
651        self.intlvBits = 0
652        self.intlvMatch = 0
653
654        def handle_kwargs(self, kwargs):
655            # An address range needs to have an upper limit, specified
656            # either explicitly with an end, or as an offset using the
657            # size keyword.
658            if 'end' in kwargs:
659                self.end = Addr(kwargs.pop('end'))
660            elif 'size' in kwargs:
661                self.end = self.start + Addr(kwargs.pop('size')) - 1
662            else:
663                raise TypeError, "Either end or size must be specified"
664
665            # Now on to the optional bit
666            if 'intlvHighBit' in kwargs:
667                self.intlvHighBit = int(kwargs.pop('intlvHighBit'))
668            if 'intlvBits' in kwargs:
669                self.intlvBits = int(kwargs.pop('intlvBits'))
670            if 'intlvMatch' in kwargs:
671                self.intlvMatch = int(kwargs.pop('intlvMatch'))
672
673        if len(args) == 0:
674            self.start = Addr(kwargs.pop('start'))
675            handle_kwargs(self, kwargs)
676
677        elif len(args) == 1:
678            if kwargs:
679                self.start = Addr(args[0])
680                handle_kwargs(self, kwargs)
681            elif isinstance(args[0], (list, tuple)):
682                self.start = Addr(args[0][0])
683                self.end = Addr(args[0][1])
684            else:
685                self.start = Addr(0)
686                self.end = Addr(args[0]) - 1
687
688        elif len(args) == 2:
689            self.start = Addr(args[0])
690            self.end = Addr(args[1])
691        else:
692            raise TypeError, "Too many arguments specified"
693
694        if kwargs:
695            raise TypeError, "Too many keywords: %s" % kwargs.keys()
696
697    def __str__(self):
698        return '%s:%s' % (self.start, self.end)
699
700    def size(self):
701        # Divide the size by the size of the interleaving slice
702        return (long(self.end) - long(self.start) + 1) >> self.intlvBits
703
704    @classmethod
705    def cxx_predecls(cls, code):
706        Addr.cxx_predecls(code)
707        code('#include "base/addr_range.hh"')
708
709    @classmethod
710    def swig_predecls(cls, code):
711        Addr.swig_predecls(code)
712
713    def getValue(self):
714        # Go from the Python class to the wrapped C++ class generated
715        # by swig
716        from m5.internal.range import AddrRange
717
718        return AddrRange(long(self.start), long(self.end),
719                         int(self.intlvHighBit), int(self.intlvBits),
720                         int(self.intlvMatch))
721
722# Boolean parameter type.  Python doesn't let you subclass bool, since
723# it doesn't want to let you create multiple instances of True and
724# False.  Thus this is a little more complicated than String.
725class Bool(ParamValue):
726    cxx_type = 'bool'
727    cmd_line_settable = True
728
729    def __init__(self, value):
730        try:
731            self.value = convert.toBool(value)
732        except TypeError:
733            self.value = bool(value)
734
735    def __call__(self, value):
736        self.__init__(value)
737        return value
738
739    def getValue(self):
740        return bool(self.value)
741
742    def __str__(self):
743        return str(self.value)
744
745    # implement truth value testing for Bool parameters so that these params
746    # evaluate correctly during the python configuration phase
747    def __nonzero__(self):
748        return bool(self.value)
749
750    def ini_str(self):
751        if self.value:
752            return 'true'
753        return 'false'
754
755def IncEthernetAddr(addr, val = 1):
756    bytes = map(lambda x: int(x, 16), addr.split(':'))
757    bytes[5] += val
758    for i in (5, 4, 3, 2, 1):
759        val,rem = divmod(bytes[i], 256)
760        bytes[i] = rem
761        if val == 0:
762            break
763        bytes[i - 1] += val
764    assert(bytes[0] <= 255)
765    return ':'.join(map(lambda x: '%02x' % x, bytes))
766
767_NextEthernetAddr = "00:90:00:00:00:01"
768def NextEthernetAddr():
769    global _NextEthernetAddr
770
771    value = _NextEthernetAddr
772    _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1)
773    return value
774
775class EthernetAddr(ParamValue):
776    cxx_type = 'Net::EthAddr'
777    ex_str = "00:90:00:00:00:01"
778    cmd_line_settable = True
779
780    @classmethod
781    def cxx_predecls(cls, code):
782        code('#include "base/inet.hh"')
783
784    @classmethod
785    def swig_predecls(cls, code):
786        code('%include "python/swig/inet.i"')
787
788    def __init__(self, value):
789        if value == NextEthernetAddr:
790            self.value = value
791            return
792
793        if not isinstance(value, str):
794            raise TypeError, "expected an ethernet address and didn't get one"
795
796        bytes = value.split(':')
797        if len(bytes) != 6:
798            raise TypeError, 'invalid ethernet address %s' % value
799
800        for byte in bytes:
801            if not 0 <= int(byte, base=16) <= 0xff:
802                raise TypeError, 'invalid ethernet address %s' % value
803
804        self.value = value
805
806    def __call__(self, value):
807        self.__init__(value)
808        return value
809
810    def unproxy(self, base):
811        if self.value == NextEthernetAddr:
812            return EthernetAddr(self.value())
813        return self
814
815    def getValue(self):
816        from m5.internal.params import EthAddr
817        return EthAddr(self.value)
818
819    def ini_str(self):
820        return self.value
821
822# When initializing an IpAddress, pass in an existing IpAddress, a string of
823# the form "a.b.c.d", or an integer representing an IP.
824class IpAddress(ParamValue):
825    cxx_type = 'Net::IpAddress'
826    ex_str = "127.0.0.1"
827    cmd_line_settable = True
828
829    @classmethod
830    def cxx_predecls(cls, code):
831        code('#include "base/inet.hh"')
832
833    @classmethod
834    def swig_predecls(cls, code):
835        code('%include "python/swig/inet.i"')
836
837    def __init__(self, value):
838        if isinstance(value, IpAddress):
839            self.ip = value.ip
840        else:
841            try:
842                self.ip = convert.toIpAddress(value)
843            except TypeError:
844                self.ip = long(value)
845        self.verifyIp()
846
847    def __call__(self, value):
848        self.__init__(value)
849        return value
850
851    def __str__(self):
852        tup = [(self.ip >> i)  & 0xff for i in (24, 16, 8, 0)]
853        return '%d.%d.%d.%d' % tuple(tup)
854
855    def __eq__(self, other):
856        if isinstance(other, IpAddress):
857            return self.ip == other.ip
858        elif isinstance(other, str):
859            try:
860                return self.ip == convert.toIpAddress(other)
861            except:
862                return False
863        else:
864            return self.ip == other
865
866    def __ne__(self, other):
867        return not (self == other)
868
869    def verifyIp(self):
870        if self.ip < 0 or self.ip >= (1 << 32):
871            raise TypeError, "invalid ip address %#08x" % self.ip
872
873    def getValue(self):
874        from m5.internal.params import IpAddress
875        return IpAddress(self.ip)
876
877# When initializing an IpNetmask, pass in an existing IpNetmask, a string of
878# the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as
879# positional or keyword arguments.
880class IpNetmask(IpAddress):
881    cxx_type = 'Net::IpNetmask'
882    ex_str = "127.0.0.0/24"
883    cmd_line_settable = True
884
885    @classmethod
886    def cxx_predecls(cls, code):
887        code('#include "base/inet.hh"')
888
889    @classmethod
890    def swig_predecls(cls, code):
891        code('%include "python/swig/inet.i"')
892
893    def __init__(self, *args, **kwargs):
894        def handle_kwarg(self, kwargs, key, elseVal = None):
895            if key in kwargs:
896                setattr(self, key, kwargs.pop(key))
897            elif elseVal:
898                setattr(self, key, elseVal)
899            else:
900                raise TypeError, "No value set for %s" % key
901
902        if len(args) == 0:
903            handle_kwarg(self, kwargs, 'ip')
904            handle_kwarg(self, kwargs, 'netmask')
905
906        elif len(args) == 1:
907            if kwargs:
908                if not 'ip' in kwargs and not 'netmask' in kwargs:
909                    raise TypeError, "Invalid arguments"
910                handle_kwarg(self, kwargs, 'ip', args[0])
911                handle_kwarg(self, kwargs, 'netmask', args[0])
912            elif isinstance(args[0], IpNetmask):
913                self.ip = args[0].ip
914                self.netmask = args[0].netmask
915            else:
916                (self.ip, self.netmask) = convert.toIpNetmask(args[0])
917
918        elif len(args) == 2:
919            self.ip = args[0]
920            self.netmask = args[1]
921        else:
922            raise TypeError, "Too many arguments specified"
923
924        if kwargs:
925            raise TypeError, "Too many keywords: %s" % kwargs.keys()
926
927        self.verify()
928
929    def __call__(self, value):
930        self.__init__(value)
931        return value
932
933    def __str__(self):
934        return "%s/%d" % (super(IpNetmask, self).__str__(), self.netmask)
935
936    def __eq__(self, other):
937        if isinstance(other, IpNetmask):
938            return self.ip == other.ip and self.netmask == other.netmask
939        elif isinstance(other, str):
940            try:
941                return (self.ip, self.netmask) == convert.toIpNetmask(other)
942            except:
943                return False
944        else:
945            return False
946
947    def verify(self):
948        self.verifyIp()
949        if self.netmask < 0 or self.netmask > 32:
950            raise TypeError, "invalid netmask %d" % netmask
951
952    def getValue(self):
953        from m5.internal.params import IpNetmask
954        return IpNetmask(self.ip, self.netmask)
955
956# When initializing an IpWithPort, pass in an existing IpWithPort, a string of
957# the form "a.b.c.d:p", or an ip and port as positional or keyword arguments.
958class IpWithPort(IpAddress):
959    cxx_type = 'Net::IpWithPort'
960    ex_str = "127.0.0.1:80"
961    cmd_line_settable = True
962
963    @classmethod
964    def cxx_predecls(cls, code):
965        code('#include "base/inet.hh"')
966
967    @classmethod
968    def swig_predecls(cls, code):
969        code('%include "python/swig/inet.i"')
970
971    def __init__(self, *args, **kwargs):
972        def handle_kwarg(self, kwargs, key, elseVal = None):
973            if key in kwargs:
974                setattr(self, key, kwargs.pop(key))
975            elif elseVal:
976                setattr(self, key, elseVal)
977            else:
978                raise TypeError, "No value set for %s" % key
979
980        if len(args) == 0:
981            handle_kwarg(self, kwargs, 'ip')
982            handle_kwarg(self, kwargs, 'port')
983
984        elif len(args) == 1:
985            if kwargs:
986                if not 'ip' in kwargs and not 'port' in kwargs:
987                    raise TypeError, "Invalid arguments"
988                handle_kwarg(self, kwargs, 'ip', args[0])
989                handle_kwarg(self, kwargs, 'port', args[0])
990            elif isinstance(args[0], IpWithPort):
991                self.ip = args[0].ip
992                self.port = args[0].port
993            else:
994                (self.ip, self.port) = convert.toIpWithPort(args[0])
995
996        elif len(args) == 2:
997            self.ip = args[0]
998            self.port = args[1]
999        else:
1000            raise TypeError, "Too many arguments specified"
1001
1002        if kwargs:
1003            raise TypeError, "Too many keywords: %s" % kwargs.keys()
1004
1005        self.verify()
1006
1007    def __call__(self, value):
1008        self.__init__(value)
1009        return value
1010
1011    def __str__(self):
1012        return "%s:%d" % (super(IpWithPort, self).__str__(), self.port)
1013
1014    def __eq__(self, other):
1015        if isinstance(other, IpWithPort):
1016            return self.ip == other.ip and self.port == other.port
1017        elif isinstance(other, str):
1018            try:
1019                return (self.ip, self.port) == convert.toIpWithPort(other)
1020            except:
1021                return False
1022        else:
1023            return False
1024
1025    def verify(self):
1026        self.verifyIp()
1027        if self.port < 0 or self.port > 0xffff:
1028            raise TypeError, "invalid port %d" % self.port
1029
1030    def getValue(self):
1031        from m5.internal.params import IpWithPort
1032        return IpWithPort(self.ip, self.port)
1033
1034time_formats = [ "%a %b %d %H:%M:%S %Z %Y",
1035                 "%a %b %d %H:%M:%S %Z %Y",
1036                 "%Y/%m/%d %H:%M:%S",
1037                 "%Y/%m/%d %H:%M",
1038                 "%Y/%m/%d",
1039                 "%m/%d/%Y %H:%M:%S",
1040                 "%m/%d/%Y %H:%M",
1041                 "%m/%d/%Y",
1042                 "%m/%d/%y %H:%M:%S",
1043                 "%m/%d/%y %H:%M",
1044                 "%m/%d/%y"]
1045
1046
1047def parse_time(value):
1048    from time import gmtime, strptime, struct_time, time
1049    from datetime import datetime, date
1050
1051    if isinstance(value, struct_time):
1052        return value
1053
1054    if isinstance(value, (int, long)):
1055        return gmtime(value)
1056
1057    if isinstance(value, (datetime, date)):
1058        return value.timetuple()
1059
1060    if isinstance(value, str):
1061        if value in ('Now', 'Today'):
1062            return time.gmtime(time.time())
1063
1064        for format in time_formats:
1065            try:
1066                return strptime(value, format)
1067            except ValueError:
1068                pass
1069
1070    raise ValueError, "Could not parse '%s' as a time" % value
1071
1072class Time(ParamValue):
1073    cxx_type = 'tm'
1074
1075    @classmethod
1076    def cxx_predecls(cls, code):
1077        code('#include <time.h>')
1078
1079    @classmethod
1080    def swig_predecls(cls, code):
1081        code('%include "python/swig/time.i"')
1082
1083    def __init__(self, value):
1084        self.value = parse_time(value)
1085
1086    def __call__(self, value):
1087        self.__init__(value)
1088        return value
1089
1090    def getValue(self):
1091        from m5.internal.params import tm
1092
1093        c_time = tm()
1094        py_time = self.value
1095
1096        # UNIX is years since 1900
1097        c_time.tm_year = py_time.tm_year - 1900;
1098
1099        # Python starts at 1, UNIX starts at 0
1100        c_time.tm_mon =  py_time.tm_mon - 1;
1101        c_time.tm_mday = py_time.tm_mday;
1102        c_time.tm_hour = py_time.tm_hour;
1103        c_time.tm_min = py_time.tm_min;
1104        c_time.tm_sec = py_time.tm_sec;
1105
1106        # Python has 0 as Monday, UNIX is 0 as sunday
1107        c_time.tm_wday = py_time.tm_wday + 1
1108        if c_time.tm_wday > 6:
1109            c_time.tm_wday -= 7;
1110
1111        # Python starts at 1, Unix starts at 0
1112        c_time.tm_yday = py_time.tm_yday - 1;
1113
1114        return c_time
1115
1116    def __str__(self):
1117        return time.asctime(self.value)
1118
1119    def ini_str(self):
1120        return str(self)
1121
1122    def get_config_as_dict(self):
1123        return str(self)
1124
1125# Enumerated types are a little more complex.  The user specifies the
1126# type as Enum(foo) where foo is either a list or dictionary of
1127# alternatives (typically strings, but not necessarily so).  (In the
1128# long run, the integer value of the parameter will be the list index
1129# or the corresponding dictionary value.  For now, since we only check
1130# that the alternative is valid and then spit it into a .ini file,
1131# there's not much point in using the dictionary.)
1132
1133# What Enum() must do is generate a new type encapsulating the
1134# provided list/dictionary so that specific values of the parameter
1135# can be instances of that type.  We define two hidden internal
1136# classes (_ListEnum and _DictEnum) to serve as base classes, then
1137# derive the new type from the appropriate base class on the fly.
1138
1139allEnums = {}
1140# Metaclass for Enum types
1141class MetaEnum(MetaParamValue):
1142    def __new__(mcls, name, bases, dict):
1143        assert name not in allEnums
1144
1145        cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict)
1146        allEnums[name] = cls
1147        return cls
1148
1149    def __init__(cls, name, bases, init_dict):
1150        if init_dict.has_key('map'):
1151            if not isinstance(cls.map, dict):
1152                raise TypeError, "Enum-derived class attribute 'map' " \
1153                      "must be of type dict"
1154            # build list of value strings from map
1155            cls.vals = cls.map.keys()
1156            cls.vals.sort()
1157        elif init_dict.has_key('vals'):
1158            if not isinstance(cls.vals, list):
1159                raise TypeError, "Enum-derived class attribute 'vals' " \
1160                      "must be of type list"
1161            # build string->value map from vals sequence
1162            cls.map = {}
1163            for idx,val in enumerate(cls.vals):
1164                cls.map[val] = idx
1165        else:
1166            raise TypeError, "Enum-derived class must define "\
1167                  "attribute 'map' or 'vals'"
1168
1169        cls.cxx_type = 'Enums::%s' % name
1170
1171        super(MetaEnum, cls).__init__(name, bases, init_dict)
1172
1173    # Generate C++ class declaration for this enum type.
1174    # Note that we wrap the enum in a class/struct to act as a namespace,
1175    # so that the enum strings can be brief w/o worrying about collisions.
1176    def cxx_decl(cls, code):
1177        wrapper_name = cls.wrapper_name
1178        wrapper = 'struct' if cls.wrapper_is_struct else 'namespace'
1179        name = cls.__name__ if cls.enum_name is None else cls.enum_name
1180        idem_macro = '__ENUM__%s__%s__' % (wrapper_name, name)
1181
1182        code('''\
1183#ifndef $idem_macro
1184#define $idem_macro
1185
1186$wrapper $wrapper_name {
1187    enum $name {
1188''')
1189        code.indent(2)
1190        for val in cls.vals:
1191            code('$val = ${{cls.map[val]}},')
1192        code('Num_$name = ${{len(cls.vals)}}')
1193        code.dedent(2)
1194        code('    };')
1195
1196        if cls.wrapper_is_struct:
1197            code('    static const char *${name}Strings[Num_${name}];')
1198            code('};')
1199        else:
1200            code('extern const char *${name}Strings[Num_${name}];')
1201            code('}')
1202
1203        code()
1204        code('#endif // $idem_macro')
1205
1206    def cxx_def(cls, code):
1207        wrapper_name = cls.wrapper_name
1208        file_name = cls.__name__
1209        name = cls.__name__ if cls.enum_name is None else cls.enum_name
1210
1211        code('#include "enums/$file_name.hh"')
1212        if cls.wrapper_is_struct:
1213            code('const char *${wrapper_name}::${name}Strings'
1214                '[Num_${name}] =')
1215        else:
1216            code('namespace Enums {')
1217            code.indent(1)
1218            code(' const char *${name}Strings[Num_${name}] =')
1219
1220        code('{')
1221        code.indent(1)
1222        for val in cls.vals:
1223            code('"$val",')
1224        code.dedent(1)
1225        code('};')
1226
1227        if not cls.wrapper_is_struct:
1228            code('} // namespace $wrapper_name')
1229            code.dedent(1)
1230
1231    def swig_decl(cls, code):
1232        name = cls.__name__
1233        code('''\
1234%module(package="m5.internal") enum_$name
1235
1236%{
1237#include "enums/$name.hh"
1238%}
1239
1240%include "enums/$name.hh"
1241''')
1242
1243
1244# Base class for enum types.
1245class Enum(ParamValue):
1246    __metaclass__ = MetaEnum
1247    vals = []
1248    cmd_line_settable = True
1249
1250    # The name of the wrapping namespace or struct
1251    wrapper_name = 'Enums'
1252
1253    # If true, the enum is wrapped in a struct rather than a namespace
1254    wrapper_is_struct = False
1255
1256    # If not None, use this as the enum name rather than this class name
1257    enum_name = None
1258
1259    def __init__(self, value):
1260        if value not in self.map:
1261            raise TypeError, "Enum param got bad value '%s' (not in %s)" \
1262                  % (value, self.vals)
1263        self.value = value
1264
1265    def __call__(self, value):
1266        self.__init__(value)
1267        return value
1268
1269    @classmethod
1270    def cxx_predecls(cls, code):
1271        code('#include "enums/$0.hh"', cls.__name__)
1272
1273    @classmethod
1274    def swig_predecls(cls, code):
1275        code('%import "python/m5/internal/enum_$0.i"', cls.__name__)
1276
1277    def getValue(self):
1278        return int(self.map[self.value])
1279
1280    def __str__(self):
1281        return self.value
1282
1283# how big does a rounding error need to be before we warn about it?
1284frequency_tolerance = 0.001  # 0.1%
1285
1286class TickParamValue(NumericParamValue):
1287    cxx_type = 'Tick'
1288    ex_str = "1MHz"
1289    cmd_line_settable = True
1290
1291    @classmethod
1292    def cxx_predecls(cls, code):
1293        code('#include "base/types.hh"')
1294
1295    @classmethod
1296    def swig_predecls(cls, code):
1297        code('%import "stdint.i"')
1298        code('%import "base/types.hh"')
1299
1300    def __call__(self, value):
1301        self.__init__(value)
1302        return value
1303
1304    def getValue(self):
1305        return long(self.value)
1306
1307class Latency(TickParamValue):
1308    ex_str = "100ns"
1309
1310    def __init__(self, value):
1311        if isinstance(value, (Latency, Clock)):
1312            self.ticks = value.ticks
1313            self.value = value.value
1314        elif isinstance(value, Frequency):
1315            self.ticks = value.ticks
1316            self.value = 1.0 / value.value
1317        elif value.endswith('t'):
1318            self.ticks = True
1319            self.value = int(value[:-1])
1320        else:
1321            self.ticks = False
1322            self.value = convert.toLatency(value)
1323
1324    def __call__(self, value):
1325        self.__init__(value)
1326        return value
1327
1328    def __getattr__(self, attr):
1329        if attr in ('latency', 'period'):
1330            return self
1331        if attr == 'frequency':
1332            return Frequency(self)
1333        raise AttributeError, "Latency object has no attribute '%s'" % attr
1334
1335    def getValue(self):
1336        if self.ticks or self.value == 0:
1337            value = self.value
1338        else:
1339            value = ticks.fromSeconds(self.value)
1340        return long(value)
1341
1342    # convert latency to ticks
1343    def ini_str(self):
1344        return '%d' % self.getValue()
1345
1346class Frequency(TickParamValue):
1347    ex_str = "1GHz"
1348
1349    def __init__(self, value):
1350        if isinstance(value, (Latency, Clock)):
1351            if value.value == 0:
1352                self.value = 0
1353            else:
1354                self.value = 1.0 / value.value
1355            self.ticks = value.ticks
1356        elif isinstance(value, Frequency):
1357            self.value = value.value
1358            self.ticks = value.ticks
1359        else:
1360            self.ticks = False
1361            self.value = convert.toFrequency(value)
1362
1363    def __call__(self, value):
1364        self.__init__(value)
1365        return value
1366
1367    def __getattr__(self, attr):
1368        if attr == 'frequency':
1369            return self
1370        if attr in ('latency', 'period'):
1371            return Latency(self)
1372        raise AttributeError, "Frequency object has no attribute '%s'" % attr
1373
1374    # convert latency to ticks
1375    def getValue(self):
1376        if self.ticks or self.value == 0:
1377            value = self.value
1378        else:
1379            value = ticks.fromSeconds(1.0 / self.value)
1380        return long(value)
1381
1382    def ini_str(self):
1383        return '%d' % self.getValue()
1384
1385# A generic Frequency and/or Latency value. Value is stored as a
1386# latency, just like Latency and Frequency.
1387class Clock(TickParamValue):
1388    def __init__(self, value):
1389        if isinstance(value, (Latency, Clock)):
1390            self.ticks = value.ticks
1391            self.value = value.value
1392        elif isinstance(value, Frequency):
1393            self.ticks = value.ticks
1394            self.value = 1.0 / value.value
1395        elif value.endswith('t'):
1396            self.ticks = True
1397            self.value = int(value[:-1])
1398        else:
1399            self.ticks = False
1400            self.value = convert.anyToLatency(value)
1401
1402    def __call__(self, value):
1403        self.__init__(value)
1404        return value
1405
1406    def __str__(self):
1407        return "%s" % Latency(self)
1408
1409    def __getattr__(self, attr):
1410        if attr == 'frequency':
1411            return Frequency(self)
1412        if attr in ('latency', 'period'):
1413            return Latency(self)
1414        raise AttributeError, "Frequency object has no attribute '%s'" % attr
1415
1416    def getValue(self):
1417        return self.period.getValue()
1418
1419    def ini_str(self):
1420        return self.period.ini_str()
1421
1422class Voltage(float,ParamValue):
1423    cxx_type = 'double'
1424    ex_str = "1V"
1425    cmd_line_settable = False
1426
1427    def __new__(cls, value):
1428        # convert to voltage
1429        val = convert.toVoltage(value)
1430        return super(cls, Voltage).__new__(cls, val)
1431
1432    def __call__(self, value):
1433        val = convert.toVoltage(value)
1434        self.__init__(val)
1435        return value
1436
1437    def __str__(self):
1438        return str(self.getValue())
1439
1440    def getValue(self):
1441        value = float(self)
1442        return value
1443
1444    def ini_str(self):
1445        return '%f' % self.getValue()
1446
1447class NetworkBandwidth(float,ParamValue):
1448    cxx_type = 'float'
1449    ex_str = "1Gbps"
1450    cmd_line_settable = True
1451
1452    def __new__(cls, value):
1453        # convert to bits per second
1454        val = convert.toNetworkBandwidth(value)
1455        return super(cls, NetworkBandwidth).__new__(cls, val)
1456
1457    def __str__(self):
1458        return str(self.val)
1459
1460    def __call__(self, value):
1461        val = convert.toNetworkBandwidth(value)
1462        self.__init__(val)
1463        return value
1464
1465    def getValue(self):
1466        # convert to seconds per byte
1467        value = 8.0 / float(self)
1468        # convert to ticks per byte
1469        value = ticks.fromSeconds(value)
1470        return float(value)
1471
1472    def ini_str(self):
1473        return '%f' % self.getValue()
1474
1475class MemoryBandwidth(float,ParamValue):
1476    cxx_type = 'float'
1477    ex_str = "1GB/s"
1478    cmd_line_settable = True
1479
1480    def __new__(cls, value):
1481        # convert to bytes per second
1482        val = convert.toMemoryBandwidth(value)
1483        return super(cls, MemoryBandwidth).__new__(cls, val)
1484
1485    def __call__(self, value):
1486        val = convert.toMemoryBandwidth(value)
1487        self.__init__(val)
1488        return value
1489
1490    def getValue(self):
1491        # convert to seconds per byte
1492        value = float(self)
1493        if value:
1494            value = 1.0 / float(self)
1495        # convert to ticks per byte
1496        value = ticks.fromSeconds(value)
1497        return float(value)
1498
1499    def ini_str(self):
1500        return '%f' % self.getValue()
1501
1502#
1503# "Constants"... handy aliases for various values.
1504#
1505
1506# Special class for NULL pointers.  Note the special check in
1507# make_param_value() above that lets these be assigned where a
1508# SimObject is required.
1509# only one copy of a particular node
1510class NullSimObject(object):
1511    __metaclass__ = Singleton
1512
1513    def __call__(cls):
1514        return cls
1515
1516    def _instantiate(self, parent = None, path = ''):
1517        pass
1518
1519    def ini_str(self):
1520        return 'Null'
1521
1522    def unproxy(self, base):
1523        return self
1524
1525    def set_path(self, parent, name):
1526        pass
1527
1528    def __str__(self):
1529        return 'Null'
1530
1531    def getValue(self):
1532        return None
1533
1534# The only instance you'll ever need...
1535NULL = NullSimObject()
1536
1537def isNullPointer(value):
1538    return isinstance(value, NullSimObject)
1539
1540# Some memory range specifications use this as a default upper bound.
1541MaxAddr = Addr.max
1542MaxTick = Tick.max
1543AllMemory = AddrRange(0, MaxAddr)
1544
1545
1546#####################################################################
1547#
1548# Port objects
1549#
1550# Ports are used to interconnect objects in the memory system.
1551#
1552#####################################################################
1553
1554# Port reference: encapsulates a reference to a particular port on a
1555# particular SimObject.
1556class PortRef(object):
1557    def __init__(self, simobj, name, role):
1558        assert(isSimObject(simobj) or isSimObjectClass(simobj))
1559        self.simobj = simobj
1560        self.name = name
1561        self.role = role
1562        self.peer = None   # not associated with another port yet
1563        self.ccConnected = False # C++ port connection done?
1564        self.index = -1  # always -1 for non-vector ports
1565
1566    def __str__(self):
1567        return '%s.%s' % (self.simobj, self.name)
1568
1569    def __len__(self):
1570        # Return the number of connected ports, i.e. 0 is we have no
1571        # peer and 1 if we do.
1572        return int(self.peer != None)
1573
1574    # for config.ini, print peer's name (not ours)
1575    def ini_str(self):
1576        return str(self.peer)
1577
1578    # for config.json
1579    def get_config_as_dict(self):
1580        return {'role' : self.role, 'peer' : str(self.peer)}
1581
1582    def __getattr__(self, attr):
1583        if attr == 'peerObj':
1584            # shorthand for proxies
1585            return self.peer.simobj
1586        raise AttributeError, "'%s' object has no attribute '%s'" % \
1587              (self.__class__.__name__, attr)
1588
1589    # Full connection is symmetric (both ways).  Called via
1590    # SimObject.__setattr__ as a result of a port assignment, e.g.,
1591    # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
1592    # e.g., "obj1.portA[3] = obj2.portB".
1593    def connect(self, other):
1594        if isinstance(other, VectorPortRef):
1595            # reference to plain VectorPort is implicit append
1596            other = other._get_next()
1597        if self.peer and not proxy.isproxy(self.peer):
1598            fatal("Port %s is already connected to %s, cannot connect %s\n",
1599                  self, self.peer, other);
1600        self.peer = other
1601        if proxy.isproxy(other):
1602            other.set_param_desc(PortParamDesc())
1603        elif isinstance(other, PortRef):
1604            if other.peer is not self:
1605                other.connect(self)
1606        else:
1607            raise TypeError, \
1608                  "assigning non-port reference '%s' to port '%s'" \
1609                  % (other, self)
1610
1611    def clone(self, simobj, memo):
1612        if memo.has_key(self):
1613            return memo[self]
1614        newRef = copy.copy(self)
1615        memo[self] = newRef
1616        newRef.simobj = simobj
1617        assert(isSimObject(newRef.simobj))
1618        if self.peer and not proxy.isproxy(self.peer):
1619            peerObj = self.peer.simobj(_memo=memo)
1620            newRef.peer = self.peer.clone(peerObj, memo)
1621            assert(not isinstance(newRef.peer, VectorPortRef))
1622        return newRef
1623
1624    def unproxy(self, simobj):
1625        assert(simobj is self.simobj)
1626        if proxy.isproxy(self.peer):
1627            try:
1628                realPeer = self.peer.unproxy(self.simobj)
1629            except:
1630                print "Error in unproxying port '%s' of %s" % \
1631                      (self.name, self.simobj.path())
1632                raise
1633            self.connect(realPeer)
1634
1635    # Call C++ to create corresponding port connection between C++ objects
1636    def ccConnect(self):
1637        from m5.internal.pyobject import connectPorts
1638
1639        if self.role == 'SLAVE':
1640            # do nothing and let the master take care of it
1641            return
1642
1643        if self.ccConnected: # already done this
1644            return
1645        peer = self.peer
1646        if not self.peer: # nothing to connect to
1647            return
1648
1649        # check that we connect a master to a slave
1650        if self.role == peer.role:
1651            raise TypeError, \
1652                "cannot connect '%s' and '%s' due to identical role '%s'" \
1653                % (peer, self, self.role)
1654
1655        try:
1656            # self is always the master and peer the slave
1657            connectPorts(self.simobj.getCCObject(), self.name, self.index,
1658                         peer.simobj.getCCObject(), peer.name, peer.index)
1659        except:
1660            print "Error connecting port %s.%s to %s.%s" % \
1661                  (self.simobj.path(), self.name,
1662                   peer.simobj.path(), peer.name)
1663            raise
1664        self.ccConnected = True
1665        peer.ccConnected = True
1666
1667# A reference to an individual element of a VectorPort... much like a
1668# PortRef, but has an index.
1669class VectorPortElementRef(PortRef):
1670    def __init__(self, simobj, name, role, index):
1671        PortRef.__init__(self, simobj, name, role)
1672        self.index = index
1673
1674    def __str__(self):
1675        return '%s.%s[%d]' % (self.simobj, self.name, self.index)
1676
1677# A reference to a complete vector-valued port (not just a single element).
1678# Can be indexed to retrieve individual VectorPortElementRef instances.
1679class VectorPortRef(object):
1680    def __init__(self, simobj, name, role):
1681        assert(isSimObject(simobj) or isSimObjectClass(simobj))
1682        self.simobj = simobj
1683        self.name = name
1684        self.role = role
1685        self.elements = []
1686
1687    def __str__(self):
1688        return '%s.%s[:]' % (self.simobj, self.name)
1689
1690    def __len__(self):
1691        # Return the number of connected peers, corresponding the the
1692        # length of the elements.
1693        return len(self.elements)
1694
1695    # for config.ini, print peer's name (not ours)
1696    def ini_str(self):
1697        return ' '.join([el.ini_str() for el in self.elements])
1698
1699    # for config.json
1700    def get_config_as_dict(self):
1701        return {'role' : self.role,
1702                'peer' : [el.ini_str() for el in self.elements]}
1703
1704    def __getitem__(self, key):
1705        if not isinstance(key, int):
1706            raise TypeError, "VectorPort index must be integer"
1707        if key >= len(self.elements):
1708            # need to extend list
1709            ext = [VectorPortElementRef(self.simobj, self.name, self.role, i)
1710                   for i in range(len(self.elements), key+1)]
1711            self.elements.extend(ext)
1712        return self.elements[key]
1713
1714    def _get_next(self):
1715        return self[len(self.elements)]
1716
1717    def __setitem__(self, key, value):
1718        if not isinstance(key, int):
1719            raise TypeError, "VectorPort index must be integer"
1720        self[key].connect(value)
1721
1722    def connect(self, other):
1723        if isinstance(other, (list, tuple)):
1724            # Assign list of port refs to vector port.
1725            # For now, append them... not sure if that's the right semantics
1726            # or if it should replace the current vector.
1727            for ref in other:
1728                self._get_next().connect(ref)
1729        else:
1730            # scalar assignment to plain VectorPort is implicit append
1731            self._get_next().connect(other)
1732
1733    def clone(self, simobj, memo):
1734        if memo.has_key(self):
1735            return memo[self]
1736        newRef = copy.copy(self)
1737        memo[self] = newRef
1738        newRef.simobj = simobj
1739        assert(isSimObject(newRef.simobj))
1740        newRef.elements = [el.clone(simobj, memo) for el in self.elements]
1741        return newRef
1742
1743    def unproxy(self, simobj):
1744        [el.unproxy(simobj) for el in self.elements]
1745
1746    def ccConnect(self):
1747        [el.ccConnect() for el in self.elements]
1748
1749# Port description object.  Like a ParamDesc object, this represents a
1750# logical port in the SimObject class, not a particular port on a
1751# SimObject instance.  The latter are represented by PortRef objects.
1752class Port(object):
1753    # Generate a PortRef for this port on the given SimObject with the
1754    # given name
1755    def makeRef(self, simobj):
1756        return PortRef(simobj, self.name, self.role)
1757
1758    # Connect an instance of this port (on the given SimObject with
1759    # the given name) with the port described by the supplied PortRef
1760    def connect(self, simobj, ref):
1761        self.makeRef(simobj).connect(ref)
1762
1763    # No need for any pre-declarations at the moment as we merely rely
1764    # on an unsigned int.
1765    def cxx_predecls(self, code):
1766        pass
1767
1768    # Declare an unsigned int with the same name as the port, that
1769    # will eventually hold the number of connected ports (and thus the
1770    # number of elements for a VectorPort).
1771    def cxx_decl(self, code):
1772        code('unsigned int port_${{self.name}}_connection_count;')
1773
1774class MasterPort(Port):
1775    # MasterPort("description")
1776    def __init__(self, *args):
1777        if len(args) == 1:
1778            self.desc = args[0]
1779            self.role = 'MASTER'
1780        else:
1781            raise TypeError, 'wrong number of arguments'
1782
1783class SlavePort(Port):
1784    # SlavePort("description")
1785    def __init__(self, *args):
1786        if len(args) == 1:
1787            self.desc = args[0]
1788            self.role = 'SLAVE'
1789        else:
1790            raise TypeError, 'wrong number of arguments'
1791
1792# VectorPort description object.  Like Port, but represents a vector
1793# of connections (e.g., as on a Bus).
1794class VectorPort(Port):
1795    def __init__(self, *args):
1796        self.isVec = True
1797
1798    def makeRef(self, simobj):
1799        return VectorPortRef(simobj, self.name, self.role)
1800
1801class VectorMasterPort(VectorPort):
1802    # VectorMasterPort("description")
1803    def __init__(self, *args):
1804        if len(args) == 1:
1805            self.desc = args[0]
1806            self.role = 'MASTER'
1807            VectorPort.__init__(self, *args)
1808        else:
1809            raise TypeError, 'wrong number of arguments'
1810
1811class VectorSlavePort(VectorPort):
1812    # VectorSlavePort("description")
1813    def __init__(self, *args):
1814        if len(args) == 1:
1815            self.desc = args[0]
1816            self.role = 'SLAVE'
1817            VectorPort.__init__(self, *args)
1818        else:
1819            raise TypeError, 'wrong number of arguments'
1820
1821# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
1822# proxy objects (via set_param_desc()) so that proxy error messages
1823# make sense.
1824class PortParamDesc(object):
1825    __metaclass__ = Singleton
1826
1827    ptype_str = 'Port'
1828    ptype = Port
1829
1830baseEnums = allEnums.copy()
1831baseParams = allParams.copy()
1832
1833def clear():
1834    global allEnums, allParams
1835
1836    allEnums = baseEnums.copy()
1837    allParams = baseParams.copy()
1838
1839__all__ = ['Param', 'VectorParam',
1840           'Enum', 'Bool', 'String', 'Float',
1841           'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
1842           'Int32', 'UInt32', 'Int64', 'UInt64',
1843           'Counter', 'Addr', 'Tick', 'Percent',
1844           'TcpPort', 'UdpPort', 'EthernetAddr',
1845           'IpAddress', 'IpNetmask', 'IpWithPort',
1846           'MemorySize', 'MemorySize32',
1847           'Latency', 'Frequency', 'Clock', 'Voltage',
1848           'NetworkBandwidth', 'MemoryBandwidth',
1849           'AddrRange',
1850           'MaxAddr', 'MaxTick', 'AllMemory',
1851           'Time',
1852           'NextEthernetAddr', 'NULL',
1853           'MasterPort', 'SlavePort',
1854           'VectorMasterPort', 'VectorSlavePort']
1855
1856import SimObject
1857