params.py revision 13543
111988Sandreas.sandberg@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
6212563Sgabeblack@google.comfrom __future__ import print_function
6312563Sgabeblack@google.com
643885Sbinkertn@umich.eduimport copy
653885Sbinkertn@umich.eduimport datetime
664762Snate@binkert.orgimport re
673885Sbinkertn@umich.eduimport sys
683885Sbinkertn@umich.eduimport time
697528Ssteve.reinhardt@amd.comimport math
703885Sbinkertn@umich.edu
714380Sbinkertn@umich.eduimport proxy
724167Sbinkertn@umich.eduimport ticks
733102Sstever@eecs.umich.edufrom util import *
743101Sstever@eecs.umich.edu
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):
824762Snate@binkert.org    return SimObject.isSimObjectClass(*args, **kwargs)
834762Snate@binkert.org
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
925033Smilesck@eecs.umich.edu
935033Smilesck@eecs.umich.edu
943101Sstever@eecs.umich.edu# Dummy base class to identify types that are legitimate for SimObject
953101Sstever@eecs.umich.edu# parameters.
963101Sstever@eecs.umich.educlass ParamValue(object):
975033Smilesck@eecs.umich.edu    __metaclass__ = MetaParamValue
9810267SGeoffrey.Blake@arm.com    cmd_line_settable = False
998596Ssteve.reinhardt@amd.com
1008596Ssteve.reinhardt@amd.com    # Generate the code needed as a prerequisite for declaring a C++
1018596Ssteve.reinhardt@amd.com    # object of this type.  Typically generates one or more #include
1028596Ssteve.reinhardt@amd.com    # statements.  Used when declaring parameters of this type.
1037673Snate@binkert.org    @classmethod
1047673Snate@binkert.org    def cxx_predecls(cls, code):
1057673Snate@binkert.org        pass
1067673Snate@binkert.org
10711988Sandreas.sandberg@arm.com    @classmethod
10811988Sandreas.sandberg@arm.com    def pybind_predecls(cls, code):
10911988Sandreas.sandberg@arm.com        cls.cxx_predecls(code)
11011988Sandreas.sandberg@arm.com
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
11610380SAndrew.Bardsley@arm.com    # default for printing to .json file is regular string conversion.
11710380SAndrew.Bardsley@arm.com    # will be overridden in some cases, mostly to use native Python
11810380SAndrew.Bardsley@arm.com    # types where there are similar JSON types
11910380SAndrew.Bardsley@arm.com    def config_value(self):
12010380SAndrew.Bardsley@arm.com        return str(self)
12110380SAndrew.Bardsley@arm.com
12210458Sandreas.hansson@arm.com    # Prerequisites for .ini parsing with cxx_ini_parse
12310458Sandreas.hansson@arm.com    @classmethod
12410458Sandreas.hansson@arm.com    def cxx_ini_predecls(cls, code):
12510458Sandreas.hansson@arm.com        pass
12610458Sandreas.hansson@arm.com
12710458Sandreas.hansson@arm.com    # parse a .ini file entry for this param from string expression
12810458Sandreas.hansson@arm.com    # src into lvalue dest (of the param's C++ type)
12910458Sandreas.hansson@arm.com    @classmethod
13010458Sandreas.hansson@arm.com    def cxx_ini_parse(cls, code, src, dest, ret):
13110458Sandreas.hansson@arm.com        code('// Unhandled param type: %s' % cls.__name__)
13210458Sandreas.hansson@arm.com        code('%s false;' % ret)
13310458Sandreas.hansson@arm.com
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
13910267SGeoffrey.Blake@arm.com    # Produce a human readable version of the stored value
14010267SGeoffrey.Blake@arm.com    def pretty_print(self, value):
14110267SGeoffrey.Blake@arm.com        return str(value)
14210267SGeoffrey.Blake@arm.com
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]
1573101Sstever@eecs.umich.edu            else:
1583101Sstever@eecs.umich.edu                raise TypeError, 'too many arguments'
1593101Sstever@eecs.umich.edu
1603101Sstever@eecs.umich.edu        if kwargs.has_key('desc'):
1613101Sstever@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'
1753101Sstever@eecs.umich.edu
1763101Sstever@eecs.umich.edu    def __getattr__(self, attr):
1773101Sstever@eecs.umich.edu        if attr == 'ptype':
1785033Smilesck@eecs.umich.edu            ptype = SimObject.allClasses[self.ptype_str]
1796656Snate@binkert.org            assert isSimObjectClass(ptype)
1805033Smilesck@eecs.umich.edu            self.ptype = ptype
1815033Smilesck@eecs.umich.edu            return ptype
1825033Smilesck@eecs.umich.edu
1833101Sstever@eecs.umich.edu        raise AttributeError, "'%s' object has no attribute '%s'" % \
1843101Sstever@eecs.umich.edu              (type(self).__name__, attr)
1853101Sstever@eecs.umich.edu
18610267SGeoffrey.Blake@arm.com    def example_str(self):
18710267SGeoffrey.Blake@arm.com        if hasattr(self.ptype, "ex_str"):
18810267SGeoffrey.Blake@arm.com            return self.ptype.ex_str
18910267SGeoffrey.Blake@arm.com        else:
19010267SGeoffrey.Blake@arm.com            return self.ptype_str
19110267SGeoffrey.Blake@arm.com
19210267SGeoffrey.Blake@arm.com    # Is the param available to be exposed on the command line
19310267SGeoffrey.Blake@arm.com    def isCmdLineSettable(self):
19410267SGeoffrey.Blake@arm.com        if hasattr(self.ptype, "cmd_line_settable"):
19510267SGeoffrey.Blake@arm.com            return self.ptype.cmd_line_settable
19610267SGeoffrey.Blake@arm.com        else:
19710267SGeoffrey.Blake@arm.com            return False
19810267SGeoffrey.Blake@arm.com
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)
2023101Sstever@eecs.umich.edu            return value
2033101Sstever@eecs.umich.edu        if not hasattr(self, 'ptype') and isNullPointer(value):
2043101Sstever@eecs.umich.edu            # deferred evaluation of SimObject; continue to defer if
2053101Sstever@eecs.umich.edu            # we're just assigning a null pointer
2063101Sstever@eecs.umich.edu            return value
2073101Sstever@eecs.umich.edu        if isinstance(value, self.ptype):
2083101Sstever@eecs.umich.edu            return value
2093102Sstever@eecs.umich.edu        if isNullPointer(value) and isSimObjectClass(self.ptype):
2103101Sstever@eecs.umich.edu            return value
2113101Sstever@eecs.umich.edu        return self.ptype(value)
2123101Sstever@eecs.umich.edu
21310267SGeoffrey.Blake@arm.com    def pretty_print(self, value):
21410267SGeoffrey.Blake@arm.com        if isinstance(value, proxy.BaseProxy):
21510267SGeoffrey.Blake@arm.com           return str(value)
21610267SGeoffrey.Blake@arm.com        if isNullPointer(value):
21710267SGeoffrey.Blake@arm.com           return NULL
21810267SGeoffrey.Blake@arm.com        return self.ptype(value).pretty_print(value)
21910267SGeoffrey.Blake@arm.com
2207673Snate@binkert.org    def cxx_predecls(self, code):
2218607Sgblack@eecs.umich.edu        code('#include <cstddef>')
2227673Snate@binkert.org        self.ptype.cxx_predecls(code)
2233101Sstever@eecs.umich.edu
22411988Sandreas.sandberg@arm.com    def pybind_predecls(self, code):
22511988Sandreas.sandberg@arm.com        self.ptype.pybind_predecls(code)
22611988Sandreas.sandberg@arm.com
2277673Snate@binkert.org    def cxx_decl(self, code):
2287673Snate@binkert.org        code('${{self.ptype.cxx_type}} ${{self.name}};')
2293101Sstever@eecs.umich.edu
2303101Sstever@eecs.umich.edu# Vector-valued parameter description.  Just like ParamDesc, except
2313101Sstever@eecs.umich.edu# that the value is a vector (list) of the specified type instead of a
2323101Sstever@eecs.umich.edu# single value.
2333101Sstever@eecs.umich.edu
2343101Sstever@eecs.umich.educlass VectorParamValue(list):
2355033Smilesck@eecs.umich.edu    __metaclass__ = MetaParamValue
2365475Snate@binkert.org    def __setattr__(self, attr, value):
2375475Snate@binkert.org        raise AttributeError, \
2385475Snate@binkert.org              "Not allowed to set %s on '%s'" % (attr, type(self).__name__)
2395475Snate@binkert.org
24010380SAndrew.Bardsley@arm.com    def config_value(self):
24110380SAndrew.Bardsley@arm.com        return [v.config_value() for v in self]
24210380SAndrew.Bardsley@arm.com
2433101Sstever@eecs.umich.edu    def ini_str(self):
2443101Sstever@eecs.umich.edu        return ' '.join([v.ini_str() for v in self])
2453101Sstever@eecs.umich.edu
2464762Snate@binkert.org    def getValue(self):
2474762Snate@binkert.org        return [ v.getValue() for v in self ]
2484762Snate@binkert.org
2493101Sstever@eecs.umich.edu    def unproxy(self, base):
25012050Snikos.nikoleris@arm.com        if len(self) == 1 and isinstance(self[0], proxy.BaseProxy):
25112050Snikos.nikoleris@arm.com            # The value is a proxy (e.g. Parent.any, Parent.all or
25212050Snikos.nikoleris@arm.com            # Parent.x) therefore try resolve it
2538459SAli.Saidi@ARM.com            return self[0].unproxy(base)
2548459SAli.Saidi@ARM.com        else:
25512050Snikos.nikoleris@arm.com            return [v.unproxy(base) for v in self]
2563101Sstever@eecs.umich.edu
2577528Ssteve.reinhardt@amd.comclass SimObjectVector(VectorParamValue):
2587528Ssteve.reinhardt@amd.com    # support clone operation
2597528Ssteve.reinhardt@amd.com    def __call__(self, **kwargs):
2607528Ssteve.reinhardt@amd.com        return SimObjectVector([v(**kwargs) for v in self])
2617528Ssteve.reinhardt@amd.com
2627528Ssteve.reinhardt@amd.com    def clear_parent(self, old_parent):
2633101Sstever@eecs.umich.edu        for v in self:
2647528Ssteve.reinhardt@amd.com            v.clear_parent(old_parent)
2657528Ssteve.reinhardt@amd.com
2667528Ssteve.reinhardt@amd.com    def set_parent(self, parent, name):
2677528Ssteve.reinhardt@amd.com        if len(self) == 1:
2687528Ssteve.reinhardt@amd.com            self[0].set_parent(parent, name)
2697528Ssteve.reinhardt@amd.com        else:
2707528Ssteve.reinhardt@amd.com            width = int(math.ceil(math.log(len(self))/math.log(10)))
2717528Ssteve.reinhardt@amd.com            for i,v in enumerate(self):
2727528Ssteve.reinhardt@amd.com                v.set_parent(parent, "%s%0*d" % (name, width, i))
2737528Ssteve.reinhardt@amd.com
2748321Ssteve.reinhardt@amd.com    def has_parent(self):
27512194Sgabeblack@google.com        return any([e.has_parent() for e in self if not isNullPointer(e)])
2767528Ssteve.reinhardt@amd.com
2777528Ssteve.reinhardt@amd.com    # return 'cpu0 cpu1' etc. for print_ini()
2787528Ssteve.reinhardt@amd.com    def get_name(self):
2797528Ssteve.reinhardt@amd.com        return ' '.join([v._name for v in self])
2807528Ssteve.reinhardt@amd.com
2817528Ssteve.reinhardt@amd.com    # By iterating through the constituent members of the vector here
2827528Ssteve.reinhardt@amd.com    # we can nicely handle iterating over all a SimObject's children
2837528Ssteve.reinhardt@amd.com    # without having to provide lots of special functions on
2847528Ssteve.reinhardt@amd.com    # SimObjectVector directly.
2857528Ssteve.reinhardt@amd.com    def descendants(self):
2867528Ssteve.reinhardt@amd.com        for v in self:
2877528Ssteve.reinhardt@amd.com            for obj in v.descendants():
2887528Ssteve.reinhardt@amd.com                yield obj
2893101Sstever@eecs.umich.edu
2908664SAli.Saidi@ARM.com    def get_config_as_dict(self):
2918664SAli.Saidi@ARM.com        a = []
2928664SAli.Saidi@ARM.com        for v in self:
2938664SAli.Saidi@ARM.com            a.append(v.get_config_as_dict())
2948664SAli.Saidi@ARM.com        return a
2958664SAli.Saidi@ARM.com
2969953Sgeoffrey.blake@arm.com    # If we are replacing an item in the vector, make sure to set the
2979953Sgeoffrey.blake@arm.com    # parent reference of the new SimObject to be the same as the parent
2989953Sgeoffrey.blake@arm.com    # of the SimObject being replaced. Useful to have if we created
2999953Sgeoffrey.blake@arm.com    # a SimObjectVector of temporary objects that will be modified later in
3009953Sgeoffrey.blake@arm.com    # configuration scripts.
3019953Sgeoffrey.blake@arm.com    def __setitem__(self, key, value):
3029953Sgeoffrey.blake@arm.com        val = self[key]
3039953Sgeoffrey.blake@arm.com        if value.has_parent():
3049953Sgeoffrey.blake@arm.com            warn("SimObject %s already has a parent" % value.get_name() +\
3059953Sgeoffrey.blake@arm.com                 " that is being overwritten by a SimObjectVector")
3069953Sgeoffrey.blake@arm.com        value.set_parent(val.get_parent(), val._name)
3079953Sgeoffrey.blake@arm.com        super(SimObjectVector, self).__setitem__(key, value)
3089953Sgeoffrey.blake@arm.com
30910267SGeoffrey.Blake@arm.com    # Enumerate the params of each member of the SimObject vector. Creates
31010267SGeoffrey.Blake@arm.com    # strings that will allow indexing into the vector by the python code and
31110267SGeoffrey.Blake@arm.com    # allow it to be specified on the command line.
31210267SGeoffrey.Blake@arm.com    def enumerateParams(self, flags_dict = {},
31310267SGeoffrey.Blake@arm.com                        cmd_line_str = "",
31410267SGeoffrey.Blake@arm.com                        access_str = ""):
31510267SGeoffrey.Blake@arm.com        if hasattr(self, "_paramEnumed"):
31612563Sgabeblack@google.com            print("Cycle detected enumerating params at %s?!" % (cmd_line_str))
31710267SGeoffrey.Blake@arm.com        else:
31810267SGeoffrey.Blake@arm.com            x = 0
31910267SGeoffrey.Blake@arm.com            for vals in self:
32010267SGeoffrey.Blake@arm.com                # Each entry in the SimObjectVector should be an
32110267SGeoffrey.Blake@arm.com                # instance of a SimObject
32210267SGeoffrey.Blake@arm.com                flags_dict = vals.enumerateParams(flags_dict,
32310267SGeoffrey.Blake@arm.com                                                  cmd_line_str + "%d." % x,
32410267SGeoffrey.Blake@arm.com                                                  access_str + "[%d]." % x)
32510267SGeoffrey.Blake@arm.com                x = x + 1
32610267SGeoffrey.Blake@arm.com
32710267SGeoffrey.Blake@arm.com        return flags_dict
32810267SGeoffrey.Blake@arm.com
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.
3323101Sstever@eecs.umich.edu    def convert(self, value):
3333101Sstever@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 ]
33610364SGeoffrey.Blake@arm.com        elif isinstance(value, str):
33710364SGeoffrey.Blake@arm.com            # If input is a csv string
33810364SGeoffrey.Blake@arm.com            tmp_list = [ ParamDesc.convert(self, v) \
33910364SGeoffrey.Blake@arm.com                         for v in value.strip('[').strip(']').split(',') ]
3403101Sstever@eecs.umich.edu        else:
3414762Snate@binkert.org            # singleton: coerce to a single-element list
3424762Snate@binkert.org            tmp_list = [ ParamDesc.convert(self, value) ]
3434762Snate@binkert.org
3444762Snate@binkert.org        if isSimObjectSequence(tmp_list):
3457528Ssteve.reinhardt@amd.com            return SimObjectVector(tmp_list)
3464762Snate@binkert.org        else:
3474762Snate@binkert.org            return VectorParamValue(tmp_list)
3484762Snate@binkert.org
34910267SGeoffrey.Blake@arm.com    # Produce a human readable example string that describes
35010267SGeoffrey.Blake@arm.com    # how to set this vector parameter in the absence of a default
35110267SGeoffrey.Blake@arm.com    # value.
35210267SGeoffrey.Blake@arm.com    def example_str(self):
35310267SGeoffrey.Blake@arm.com        s = super(VectorParamDesc, self).example_str()
35410267SGeoffrey.Blake@arm.com        help_str = "[" + s + "," + s + ", ...]"
35510267SGeoffrey.Blake@arm.com        return help_str
35610267SGeoffrey.Blake@arm.com
35710267SGeoffrey.Blake@arm.com    # Produce a human readable representation of the value of this vector param.
35810267SGeoffrey.Blake@arm.com    def pretty_print(self, value):
35910267SGeoffrey.Blake@arm.com        if isinstance(value, (list, tuple)):
36010267SGeoffrey.Blake@arm.com            tmp_list = [ ParamDesc.pretty_print(self, v) for v in value ]
36110267SGeoffrey.Blake@arm.com        elif isinstance(value, str):
36210267SGeoffrey.Blake@arm.com            tmp_list = [ ParamDesc.pretty_print(self, v) for v in value.split(',') ]
36310267SGeoffrey.Blake@arm.com        else:
36410267SGeoffrey.Blake@arm.com            tmp_list = [ ParamDesc.pretty_print(self, value) ]
36510267SGeoffrey.Blake@arm.com
36610267SGeoffrey.Blake@arm.com        return tmp_list
36710267SGeoffrey.Blake@arm.com
36810267SGeoffrey.Blake@arm.com    # This is a helper function for the new config system
36910267SGeoffrey.Blake@arm.com    def __call__(self, value):
37010267SGeoffrey.Blake@arm.com        if isinstance(value, (list, tuple)):
37110267SGeoffrey.Blake@arm.com            # list: coerce each element into new list
37210267SGeoffrey.Blake@arm.com            tmp_list = [ ParamDesc.convert(self, v) for v in value ]
37310267SGeoffrey.Blake@arm.com        elif isinstance(value, str):
37410267SGeoffrey.Blake@arm.com            # If input is a csv string
37510364SGeoffrey.Blake@arm.com            tmp_list = [ ParamDesc.convert(self, v) \
37610364SGeoffrey.Blake@arm.com                         for v in value.strip('[').strip(']').split(',') ]
37710267SGeoffrey.Blake@arm.com        else:
37810267SGeoffrey.Blake@arm.com            # singleton: coerce to a single-element list
37910267SGeoffrey.Blake@arm.com            tmp_list = [ ParamDesc.convert(self, value) ]
38010267SGeoffrey.Blake@arm.com
38110267SGeoffrey.Blake@arm.com        return VectorParamValue(tmp_list)
38210267SGeoffrey.Blake@arm.com
3837673Snate@binkert.org    def cxx_predecls(self, code):
3847673Snate@binkert.org        code('#include <vector>')
3857673Snate@binkert.org        self.ptype.cxx_predecls(code)
3863101Sstever@eecs.umich.edu
38711988Sandreas.sandberg@arm.com    def pybind_predecls(self, code):
38811988Sandreas.sandberg@arm.com        code('#include <vector>')
38911988Sandreas.sandberg@arm.com        self.ptype.pybind_predecls(code)
39011988Sandreas.sandberg@arm.com
3917673Snate@binkert.org    def cxx_decl(self, code):
3927673Snate@binkert.org        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:
4085033Smilesck@eecs.umich.edu            ptype = allParams[self.ptype_str]
4095033Smilesck@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
4123101Sstever@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
4253101Sstever@eecs.umich.edu# over how Python expressions are converted to values (via the
4263101Sstever@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'
43510267SGeoffrey.Blake@arm.com    cmd_line_settable = True
4367673Snate@binkert.org
4377673Snate@binkert.org    @classmethod
4387673Snate@binkert.org    def cxx_predecls(self, code):
4397673Snate@binkert.org        code('#include <string>')
4407673Snate@binkert.org
44110267SGeoffrey.Blake@arm.com    def __call__(self, value):
44210267SGeoffrey.Blake@arm.com        self = value
44310267SGeoffrey.Blake@arm.com        return value
44410267SGeoffrey.Blake@arm.com
44510458Sandreas.hansson@arm.com    @classmethod
44610458Sandreas.hansson@arm.com    def cxx_ini_parse(self, code, src, dest, ret):
44710458Sandreas.hansson@arm.com        code('%s = %s;' % (dest, src))
44810458Sandreas.hansson@arm.com        code('%s true;' % ret)
44910458Sandreas.hansson@arm.com
4504762Snate@binkert.org    def getValue(self):
4514762Snate@binkert.org        return self
4523101Sstever@eecs.umich.edu
4533101Sstever@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.
4563101Sstever@eecs.umich.educlass NumericParamValue(ParamValue):
4573101Sstever@eecs.umich.edu    def __str__(self):
4583101Sstever@eecs.umich.edu        return str(self.value)
4593101Sstever@eecs.umich.edu
4603101Sstever@eecs.umich.edu    def __float__(self):
4613101Sstever@eecs.umich.edu        return float(self.value)
4623101Sstever@eecs.umich.edu
4633714Sstever@eecs.umich.edu    def __long__(self):
4643714Sstever@eecs.umich.edu        return long(self.value)
4653714Sstever@eecs.umich.edu
4663714Sstever@eecs.umich.edu    def __int__(self):
4673714Sstever@eecs.umich.edu        return int(self.value)
4683714Sstever@eecs.umich.edu
4693101Sstever@eecs.umich.edu    # 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
4903101Sstever@eecs.umich.edu        newobj._check()
4913101Sstever@eecs.umich.edu        return newobj
4923101Sstever@eecs.umich.edu
49310380SAndrew.Bardsley@arm.com    def config_value(self):
49410380SAndrew.Bardsley@arm.com        return self.value
49510380SAndrew.Bardsley@arm.com
49610458Sandreas.hansson@arm.com    @classmethod
49710458Sandreas.hansson@arm.com    def cxx_ini_predecls(cls, code):
49810458Sandreas.hansson@arm.com        # Assume that base/str.hh will be included anyway
49910458Sandreas.hansson@arm.com        # code('#include "base/str.hh"')
50010458Sandreas.hansson@arm.com        pass
50110458Sandreas.hansson@arm.com
50210458Sandreas.hansson@arm.com    # The default for parsing PODs from an .ini entry is to extract from an
50310458Sandreas.hansson@arm.com    # istringstream and let overloading choose the right type according to
50410458Sandreas.hansson@arm.com    # the dest type.
50510458Sandreas.hansson@arm.com    @classmethod
50610458Sandreas.hansson@arm.com    def cxx_ini_parse(self, code, src, dest, ret):
50710458Sandreas.hansson@arm.com        code('%s to_number(%s, %s);' % (ret, src, dest))
50810458Sandreas.hansson@arm.com
5093101Sstever@eecs.umich.edu# Metaclass for bounds-checked integer parameters.  See CheckedInt.
5105033Smilesck@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
5143101Sstever@eecs.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')):
5213101Sstever@eecs.umich.edu            if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')):
5223101Sstever@eecs.umich.edu                panic("CheckedInt subclass %s must define either\n" \
5235822Ssaidi@eecs.umich.edu                      "    'min' and 'max' or 'size' and 'unsigned'\n",
5245822Ssaidi@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
5333101Sstever@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):
5373101Sstever@eecs.umich.edu    __metaclass__ = CheckedIntType
53810267SGeoffrey.Blake@arm.com    cmd_line_settable = True
5393101Sstever@eecs.umich.edu
5403101Sstever@eecs.umich.edu    def _check(self):
5413101Sstever@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)
5443101Sstever@eecs.umich.edu
5453101Sstever@eecs.umich.edu    def __init__(self, value):
5463101Sstever@eecs.umich.edu        if isinstance(value, str):
5473102Sstever@eecs.umich.edu            self.value = convert.toInteger(value)
5483714Sstever@eecs.umich.edu        elif isinstance(value, (int, long, float, NumericParamValue)):
5493101Sstever@eecs.umich.edu            self.value = long(value)
5503714Sstever@eecs.umich.edu        else:
5513714Sstever@eecs.umich.edu            raise TypeError, "Can't convert object of type %s to CheckedInt" \
5523714Sstever@eecs.umich.edu                  % type(value).__name__
5533101Sstever@eecs.umich.edu        self._check()
5543101Sstever@eecs.umich.edu
55510267SGeoffrey.Blake@arm.com    def __call__(self, value):
55610267SGeoffrey.Blake@arm.com        self.__init__(value)
55710267SGeoffrey.Blake@arm.com        return value
55810267SGeoffrey.Blake@arm.com
5597673Snate@binkert.org    @classmethod
5607673Snate@binkert.org    def cxx_predecls(cls, code):
5617673Snate@binkert.org        # most derived types require this, so we just do it here once
5627673Snate@binkert.org        code('#include "base/types.hh"')
5637673Snate@binkert.org
5644762Snate@binkert.org    def getValue(self):
5654762Snate@binkert.org        return long(self.value)
5664762Snate@binkert.org
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
5743101Sstever@eecs.umich.educlass Int32(CheckedInt):    cxx_type =  'int32_t'; size = 32; unsigned = False
5753101Sstever@eecs.umich.educlass UInt32(CheckedInt):   cxx_type = 'uint32_t'; size = 32; unsigned = True
5763101Sstever@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
5869184Sandreas.hansson@arm.comclass Cycles(CheckedInt):
5879184Sandreas.hansson@arm.com    cxx_type = 'Cycles'
5889184Sandreas.hansson@arm.com    size = 64
5899184Sandreas.hansson@arm.com    unsigned = True
5909184Sandreas.hansson@arm.com
5919184Sandreas.hansson@arm.com    def getValue(self):
59211802Sandreas.sandberg@arm.com        from _m5.core import Cycles
5939184Sandreas.hansson@arm.com        return Cycles(self.value)
5949184Sandreas.hansson@arm.com
59510458Sandreas.hansson@arm.com    @classmethod
59610458Sandreas.hansson@arm.com    def cxx_ini_predecls(cls, code):
59710458Sandreas.hansson@arm.com        # Assume that base/str.hh will be included anyway
59810458Sandreas.hansson@arm.com        # code('#include "base/str.hh"')
59910458Sandreas.hansson@arm.com        pass
60010458Sandreas.hansson@arm.com
60110458Sandreas.hansson@arm.com    @classmethod
60210458Sandreas.hansson@arm.com    def cxx_ini_parse(cls, code, src, dest, ret):
60310458Sandreas.hansson@arm.com        code('uint64_t _temp;')
60410458Sandreas.hansson@arm.com        code('bool _ret = to_number(%s, _temp);' % src)
60510458Sandreas.hansson@arm.com        code('if (_ret)')
60610458Sandreas.hansson@arm.com        code('    %s = Cycles(_temp);' % dest)
60710458Sandreas.hansson@arm.com        code('%s _ret;' % ret)
60810458Sandreas.hansson@arm.com
6093101Sstever@eecs.umich.educlass Float(ParamValue, float):
6104446Sbinkertn@umich.edu    cxx_type = 'double'
61110668SGeoffrey.Blake@arm.com    cmd_line_settable = True
6123101Sstever@eecs.umich.edu
6135468Snate@binkert.org    def __init__(self, value):
61410267SGeoffrey.Blake@arm.com        if isinstance(value, (int, long, float, NumericParamValue, Float, str)):
6155468Snate@binkert.org            self.value = float(value)
6165468Snate@binkert.org        else:
6175468Snate@binkert.org            raise TypeError, "Can't convert object of type %s to Float" \
6185468Snate@binkert.org                  % type(value).__name__
6195468Snate@binkert.org
62010267SGeoffrey.Blake@arm.com    def __call__(self, value):
62110267SGeoffrey.Blake@arm.com        self.__init__(value)
62210267SGeoffrey.Blake@arm.com        return value
62310267SGeoffrey.Blake@arm.com
6244762Snate@binkert.org    def getValue(self):
6254762Snate@binkert.org        return float(self.value)
6264762Snate@binkert.org
62710380SAndrew.Bardsley@arm.com    def config_value(self):
62810380SAndrew.Bardsley@arm.com        return self
62910380SAndrew.Bardsley@arm.com
63010458Sandreas.hansson@arm.com    @classmethod
63110458Sandreas.hansson@arm.com    def cxx_ini_predecls(cls, code):
63210458Sandreas.hansson@arm.com        code('#include <sstream>')
63310458Sandreas.hansson@arm.com
63410458Sandreas.hansson@arm.com    @classmethod
63510458Sandreas.hansson@arm.com    def cxx_ini_parse(self, code, src, dest, ret):
63610458Sandreas.hansson@arm.com        code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
63710458Sandreas.hansson@arm.com
6383101Sstever@eecs.umich.educlass MemorySize(CheckedInt):
6393101Sstever@eecs.umich.edu    cxx_type = 'uint64_t'
64010267SGeoffrey.Blake@arm.com    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:
6473102Sstever@eecs.umich.edu            self.value = convert.toMemorySize(value)
6483101Sstever@eecs.umich.edu        self._check()
6493101Sstever@eecs.umich.edu
6503101Sstever@eecs.umich.educlass MemorySize32(CheckedInt):
6514168Sbinkertn@umich.edu    cxx_type = 'uint32_t'
65210267SGeoffrey.Blake@arm.com    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:
6593102Sstever@eecs.umich.edu            self.value = convert.toMemorySize(value)
6603101Sstever@eecs.umich.edu        self._check()
6613101Sstever@eecs.umich.edu
6623101Sstever@eecs.umich.educlass Addr(CheckedInt):
6633101Sstever@eecs.umich.edu    cxx_type = 'Addr'
6643101Sstever@eecs.umich.edu    size = 64
6653101Sstever@eecs.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
6693101Sstever@eecs.umich.edu        else:
6703101Sstever@eecs.umich.edu            try:
67110317Smitch.hayenga@arm.com                # Often addresses are referred to with sizes. Ex: A device
67210317Smitch.hayenga@arm.com                # base address is at "512MB".  Use toMemorySize() to convert
67310317Smitch.hayenga@arm.com                # these into addresses. If the address is not specified with a
67410317Smitch.hayenga@arm.com                # "size", an exception will occur and numeric translation will
67510317Smitch.hayenga@arm.com                # proceed below.
6763102Sstever@eecs.umich.edu                self.value = convert.toMemorySize(value)
67710317Smitch.hayenga@arm.com            except (TypeError, ValueError):
67810317Smitch.hayenga@arm.com                # Convert number to string and use long() to do automatic
67910317Smitch.hayenga@arm.com                # base conversion (requires base=0 for auto-conversion)
68010317Smitch.hayenga@arm.com                self.value = long(str(value), base=0)
68110317Smitch.hayenga@arm.com
6823101Sstever@eecs.umich.edu        self._check()
6833584Ssaidi@eecs.umich.edu    def __add__(self, other):
6843584Ssaidi@eecs.umich.edu        if isinstance(other, Addr):
6853584Ssaidi@eecs.umich.edu            return self.value + other.value
6863584Ssaidi@eecs.umich.edu        else:
6873584Ssaidi@eecs.umich.edu            return self.value + other
68810267SGeoffrey.Blake@arm.com    def pretty_print(self, value):
68910267SGeoffrey.Blake@arm.com        try:
69010267SGeoffrey.Blake@arm.com            val = convert.toMemorySize(value)
69110267SGeoffrey.Blake@arm.com        except TypeError:
69210267SGeoffrey.Blake@arm.com            val = long(value)
69310267SGeoffrey.Blake@arm.com        return "0x%x" % long(val)
6943101Sstever@eecs.umich.edu
6959232Sandreas.hansson@arm.comclass AddrRange(ParamValue):
6969235Sandreas.hansson@arm.com    cxx_type = 'AddrRange'
6973101Sstever@eecs.umich.edu
6983101Sstever@eecs.umich.edu    def __init__(self, *args, **kwargs):
69910676Sandreas.hansson@arm.com        # Disable interleaving and hashing by default
7009411Sandreas.hansson@arm.com        self.intlvHighBit = 0
70110676Sandreas.hansson@arm.com        self.xorHighBit = 0
7029411Sandreas.hansson@arm.com        self.intlvBits = 0
7039411Sandreas.hansson@arm.com        self.intlvMatch = 0
7049411Sandreas.hansson@arm.com
7053101Sstever@eecs.umich.edu        def handle_kwargs(self, kwargs):
7069411Sandreas.hansson@arm.com            # An address range needs to have an upper limit, specified
7079411Sandreas.hansson@arm.com            # either explicitly with an end, or as an offset using the
7089411Sandreas.hansson@arm.com            # size keyword.
7093101Sstever@eecs.umich.edu            if 'end' in kwargs:
7109232Sandreas.hansson@arm.com                self.end = Addr(kwargs.pop('end'))
7113101Sstever@eecs.umich.edu            elif 'size' in kwargs:
7129232Sandreas.hansson@arm.com                self.end = self.start + Addr(kwargs.pop('size')) - 1
7133101Sstever@eecs.umich.edu            else:
7143101Sstever@eecs.umich.edu                raise TypeError, "Either end or size must be specified"
7153101Sstever@eecs.umich.edu
7169411Sandreas.hansson@arm.com            # Now on to the optional bit
7179411Sandreas.hansson@arm.com            if 'intlvHighBit' in kwargs:
7189411Sandreas.hansson@arm.com                self.intlvHighBit = int(kwargs.pop('intlvHighBit'))
71910676Sandreas.hansson@arm.com            if 'xorHighBit' in kwargs:
72010676Sandreas.hansson@arm.com                self.xorHighBit = int(kwargs.pop('xorHighBit'))
7219411Sandreas.hansson@arm.com            if 'intlvBits' in kwargs:
7229411Sandreas.hansson@arm.com                self.intlvBits = int(kwargs.pop('intlvBits'))
7239411Sandreas.hansson@arm.com            if 'intlvMatch' in kwargs:
7249411Sandreas.hansson@arm.com                self.intlvMatch = int(kwargs.pop('intlvMatch'))
7259411Sandreas.hansson@arm.com
7263101Sstever@eecs.umich.edu        if len(args) == 0:
7279232Sandreas.hansson@arm.com            self.start = Addr(kwargs.pop('start'))
7283101Sstever@eecs.umich.edu            handle_kwargs(self, kwargs)
7293101Sstever@eecs.umich.edu
7303101Sstever@eecs.umich.edu        elif len(args) == 1:
7313101Sstever@eecs.umich.edu            if kwargs:
7329232Sandreas.hansson@arm.com                self.start = Addr(args[0])
7333101Sstever@eecs.umich.edu                handle_kwargs(self, kwargs)
7345219Ssaidi@eecs.umich.edu            elif isinstance(args[0], (list, tuple)):
7359232Sandreas.hansson@arm.com                self.start = Addr(args[0][0])
7369232Sandreas.hansson@arm.com                self.end = Addr(args[0][1])
7373101Sstever@eecs.umich.edu            else:
7389232Sandreas.hansson@arm.com                self.start = Addr(0)
7399232Sandreas.hansson@arm.com                self.end = Addr(args[0]) - 1
7403101Sstever@eecs.umich.edu
7413101Sstever@eecs.umich.edu        elif len(args) == 2:
7429232Sandreas.hansson@arm.com            self.start = Addr(args[0])
7439232Sandreas.hansson@arm.com            self.end = Addr(args[1])
7443101Sstever@eecs.umich.edu        else:
7453101Sstever@eecs.umich.edu            raise TypeError, "Too many arguments specified"
7463101Sstever@eecs.umich.edu
7473101Sstever@eecs.umich.edu        if kwargs:
7489232Sandreas.hansson@arm.com            raise TypeError, "Too many keywords: %s" % kwargs.keys()
7493101Sstever@eecs.umich.edu
7503101Sstever@eecs.umich.edu    def __str__(self):
75111620SMatthew.Poremba@amd.com        return '%s:%s:%s:%s:%s:%s' \
75211620SMatthew.Poremba@amd.com            % (self.start, self.end, self.intlvHighBit, self.xorHighBit,\
75311620SMatthew.Poremba@amd.com               self.intlvBits, self.intlvMatch)
7549232Sandreas.hansson@arm.com
7559232Sandreas.hansson@arm.com    def size(self):
7569411Sandreas.hansson@arm.com        # Divide the size by the size of the interleaving slice
7579411Sandreas.hansson@arm.com        return (long(self.end) - long(self.start) + 1) >> self.intlvBits
7583101Sstever@eecs.umich.edu
7597673Snate@binkert.org    @classmethod
7607673Snate@binkert.org    def cxx_predecls(cls, code):
7619232Sandreas.hansson@arm.com        Addr.cxx_predecls(code)
7629235Sandreas.hansson@arm.com        code('#include "base/addr_range.hh"')
7637675Snate@binkert.org
7647675Snate@binkert.org    @classmethod
76511988Sandreas.sandberg@arm.com    def pybind_predecls(cls, code):
76611988Sandreas.sandberg@arm.com        Addr.pybind_predecls(code)
76711988Sandreas.sandberg@arm.com        code('#include "base/addr_range.hh"')
76811988Sandreas.sandberg@arm.com
76911988Sandreas.sandberg@arm.com    @classmethod
77010458Sandreas.hansson@arm.com    def cxx_ini_predecls(cls, code):
77110458Sandreas.hansson@arm.com        code('#include <sstream>')
77210458Sandreas.hansson@arm.com
77310458Sandreas.hansson@arm.com    @classmethod
77410458Sandreas.hansson@arm.com    def cxx_ini_parse(cls, code, src, dest, ret):
77511620SMatthew.Poremba@amd.com        code('uint64_t _start, _end, _intlvHighBit = 0, _xorHighBit = 0;')
77611620SMatthew.Poremba@amd.com        code('uint64_t _intlvBits = 0, _intlvMatch = 0;')
77710458Sandreas.hansson@arm.com        code('char _sep;')
77810458Sandreas.hansson@arm.com        code('std::istringstream _stream(${src});')
77910458Sandreas.hansson@arm.com        code('_stream >> _start;')
78010458Sandreas.hansson@arm.com        code('_stream.get(_sep);')
78110458Sandreas.hansson@arm.com        code('_stream >> _end;')
78211620SMatthew.Poremba@amd.com        code('if (!_stream.fail() && !_stream.eof()) {')
78311620SMatthew.Poremba@amd.com        code('    _stream.get(_sep);')
78411620SMatthew.Poremba@amd.com        code('    _stream >> _intlvHighBit;')
78511620SMatthew.Poremba@amd.com        code('    _stream.get(_sep);')
78611620SMatthew.Poremba@amd.com        code('    _stream >> _xorHighBit;')
78711620SMatthew.Poremba@amd.com        code('    _stream.get(_sep);')
78811620SMatthew.Poremba@amd.com        code('    _stream >> _intlvBits;')
78911620SMatthew.Poremba@amd.com        code('    _stream.get(_sep);')
79011620SMatthew.Poremba@amd.com        code('    _stream >> _intlvMatch;')
79111620SMatthew.Poremba@amd.com        code('}')
79210458Sandreas.hansson@arm.com        code('bool _ret = !_stream.fail() &&'
79310458Sandreas.hansson@arm.com            '_stream.eof() && _sep == \':\';')
79410458Sandreas.hansson@arm.com        code('if (_ret)')
79511620SMatthew.Poremba@amd.com        code('   ${dest} = AddrRange(_start, _end, _intlvHighBit, \
79611620SMatthew.Poremba@amd.com                _xorHighBit, _intlvBits, _intlvMatch);')
79710458Sandreas.hansson@arm.com        code('${ret} _ret;')
79810458Sandreas.hansson@arm.com
7994762Snate@binkert.org    def getValue(self):
80011991Sandreas.sandberg@arm.com        # Go from the Python class to the wrapped C++ class
80111802Sandreas.sandberg@arm.com        from _m5.range import AddrRange
8024762Snate@binkert.org
8039411Sandreas.hansson@arm.com        return AddrRange(long(self.start), long(self.end),
80410676Sandreas.hansson@arm.com                         int(self.intlvHighBit), int(self.xorHighBit),
80510676Sandreas.hansson@arm.com                         int(self.intlvBits), int(self.intlvMatch))
8063101Sstever@eecs.umich.edu
8073101Sstever@eecs.umich.edu# Boolean parameter type.  Python doesn't let you subclass bool, since
8083101Sstever@eecs.umich.edu# it doesn't want to let you create multiple instances of True and
8093101Sstever@eecs.umich.edu# False.  Thus this is a little more complicated than String.
8103101Sstever@eecs.umich.educlass Bool(ParamValue):
8113101Sstever@eecs.umich.edu    cxx_type = 'bool'
81210267SGeoffrey.Blake@arm.com    cmd_line_settable = True
81310267SGeoffrey.Blake@arm.com
8143101Sstever@eecs.umich.edu    def __init__(self, value):
8153101Sstever@eecs.umich.edu        try:
8163102Sstever@eecs.umich.edu            self.value = convert.toBool(value)
8173101Sstever@eecs.umich.edu        except TypeError:
8183101Sstever@eecs.umich.edu            self.value = bool(value)
8193101Sstever@eecs.umich.edu
82010267SGeoffrey.Blake@arm.com    def __call__(self, value):
82110267SGeoffrey.Blake@arm.com        self.__init__(value)
82210267SGeoffrey.Blake@arm.com        return value
82310267SGeoffrey.Blake@arm.com
8244762Snate@binkert.org    def getValue(self):
8254762Snate@binkert.org        return bool(self.value)
8264762Snate@binkert.org
8273101Sstever@eecs.umich.edu    def __str__(self):
8283101Sstever@eecs.umich.edu        return str(self.value)
8293101Sstever@eecs.umich.edu
8308934SBrad.Beckmann@amd.com    # implement truth value testing for Bool parameters so that these params
8318934SBrad.Beckmann@amd.com    # evaluate correctly during the python configuration phase
8328934SBrad.Beckmann@amd.com    def __nonzero__(self):
8338934SBrad.Beckmann@amd.com        return bool(self.value)
8348934SBrad.Beckmann@amd.com
8353101Sstever@eecs.umich.edu    def ini_str(self):
8363101Sstever@eecs.umich.edu        if self.value:
8373101Sstever@eecs.umich.edu            return 'true'
8383101Sstever@eecs.umich.edu        return 'false'
8393101Sstever@eecs.umich.edu
84010380SAndrew.Bardsley@arm.com    def config_value(self):
84110380SAndrew.Bardsley@arm.com        return self.value
84210380SAndrew.Bardsley@arm.com
84310458Sandreas.hansson@arm.com    @classmethod
84410458Sandreas.hansson@arm.com    def cxx_ini_predecls(cls, code):
84510458Sandreas.hansson@arm.com        # Assume that base/str.hh will be included anyway
84610458Sandreas.hansson@arm.com        # code('#include "base/str.hh"')
84710458Sandreas.hansson@arm.com        pass
84810458Sandreas.hansson@arm.com
84910458Sandreas.hansson@arm.com    @classmethod
85010458Sandreas.hansson@arm.com    def cxx_ini_parse(cls, code, src, dest, ret):
85110458Sandreas.hansson@arm.com        code('%s to_bool(%s, %s);' % (ret, src, dest))
85210458Sandreas.hansson@arm.com
8533101Sstever@eecs.umich.edudef IncEthernetAddr(addr, val = 1):
8543101Sstever@eecs.umich.edu    bytes = map(lambda x: int(x, 16), addr.split(':'))
8553101Sstever@eecs.umich.edu    bytes[5] += val
8563101Sstever@eecs.umich.edu    for i in (5, 4, 3, 2, 1):
8573101Sstever@eecs.umich.edu        val,rem = divmod(bytes[i], 256)
8583101Sstever@eecs.umich.edu        bytes[i] = rem
8593101Sstever@eecs.umich.edu        if val == 0:
8603101Sstever@eecs.umich.edu            break
8613101Sstever@eecs.umich.edu        bytes[i - 1] += val
8623101Sstever@eecs.umich.edu    assert(bytes[0] <= 255)
8633101Sstever@eecs.umich.edu    return ':'.join(map(lambda x: '%02x' % x, bytes))
8643101Sstever@eecs.umich.edu
8654380Sbinkertn@umich.edu_NextEthernetAddr = "00:90:00:00:00:01"
8664380Sbinkertn@umich.edudef NextEthernetAddr():
8674380Sbinkertn@umich.edu    global _NextEthernetAddr
8683101Sstever@eecs.umich.edu
8694380Sbinkertn@umich.edu    value = _NextEthernetAddr
8704380Sbinkertn@umich.edu    _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1)
8714380Sbinkertn@umich.edu    return value
8723101Sstever@eecs.umich.edu
8733101Sstever@eecs.umich.educlass EthernetAddr(ParamValue):
8743101Sstever@eecs.umich.edu    cxx_type = 'Net::EthAddr'
87510267SGeoffrey.Blake@arm.com    ex_str = "00:90:00:00:00:01"
87610267SGeoffrey.Blake@arm.com    cmd_line_settable = True
8777673Snate@binkert.org
8787673Snate@binkert.org    @classmethod
8797673Snate@binkert.org    def cxx_predecls(cls, code):
8807673Snate@binkert.org        code('#include "base/inet.hh"')
8817673Snate@binkert.org
8823101Sstever@eecs.umich.edu    def __init__(self, value):
8833101Sstever@eecs.umich.edu        if value == NextEthernetAddr:
8843101Sstever@eecs.umich.edu            self.value = value
8853101Sstever@eecs.umich.edu            return
8863101Sstever@eecs.umich.edu
8873101Sstever@eecs.umich.edu        if not isinstance(value, str):
8883101Sstever@eecs.umich.edu            raise TypeError, "expected an ethernet address and didn't get one"
8893101Sstever@eecs.umich.edu
8903101Sstever@eecs.umich.edu        bytes = value.split(':')
8913101Sstever@eecs.umich.edu        if len(bytes) != 6:
8923101Sstever@eecs.umich.edu            raise TypeError, 'invalid ethernet address %s' % value
8933101Sstever@eecs.umich.edu
8943101Sstever@eecs.umich.edu        for byte in bytes:
8959941SGeoffrey.Blake@arm.com            if not 0 <= int(byte, base=16) <= 0xff:
8963101Sstever@eecs.umich.edu                raise TypeError, 'invalid ethernet address %s' % value
8973101Sstever@eecs.umich.edu
8983101Sstever@eecs.umich.edu        self.value = value
8993101Sstever@eecs.umich.edu
90010267SGeoffrey.Blake@arm.com    def __call__(self, value):
90110267SGeoffrey.Blake@arm.com        self.__init__(value)
90210267SGeoffrey.Blake@arm.com        return value
90310267SGeoffrey.Blake@arm.com
9043101Sstever@eecs.umich.edu    def unproxy(self, base):
9053101Sstever@eecs.umich.edu        if self.value == NextEthernetAddr:
9064380Sbinkertn@umich.edu            return EthernetAddr(self.value())
9073101Sstever@eecs.umich.edu        return self
9083101Sstever@eecs.umich.edu
9094762Snate@binkert.org    def getValue(self):
91011988Sandreas.sandberg@arm.com        from _m5.net import EthAddr
9114762Snate@binkert.org        return EthAddr(self.value)
9124762Snate@binkert.org
91311228SAndrew.Bardsley@arm.com    def __str__(self):
91411228SAndrew.Bardsley@arm.com        return self.value
91511228SAndrew.Bardsley@arm.com
9164380Sbinkertn@umich.edu    def ini_str(self):
9174380Sbinkertn@umich.edu        return self.value
9183101Sstever@eecs.umich.edu
91910458Sandreas.hansson@arm.com    @classmethod
92010458Sandreas.hansson@arm.com    def cxx_ini_parse(self, code, src, dest, ret):
92110458Sandreas.hansson@arm.com        code('%s = Net::EthAddr(%s);' % (dest, src))
92210458Sandreas.hansson@arm.com        code('%s true;' % ret)
92310458Sandreas.hansson@arm.com
9247777Sgblack@eecs.umich.edu# When initializing an IpAddress, pass in an existing IpAddress, a string of
9257777Sgblack@eecs.umich.edu# the form "a.b.c.d", or an integer representing an IP.
9267777Sgblack@eecs.umich.educlass IpAddress(ParamValue):
9277777Sgblack@eecs.umich.edu    cxx_type = 'Net::IpAddress'
92810267SGeoffrey.Blake@arm.com    ex_str = "127.0.0.1"
92910267SGeoffrey.Blake@arm.com    cmd_line_settable = True
9307777Sgblack@eecs.umich.edu
9317777Sgblack@eecs.umich.edu    @classmethod
9327777Sgblack@eecs.umich.edu    def cxx_predecls(cls, code):
9337777Sgblack@eecs.umich.edu        code('#include "base/inet.hh"')
9347777Sgblack@eecs.umich.edu
9357777Sgblack@eecs.umich.edu    def __init__(self, value):
9367777Sgblack@eecs.umich.edu        if isinstance(value, IpAddress):
9377777Sgblack@eecs.umich.edu            self.ip = value.ip
9387777Sgblack@eecs.umich.edu        else:
9397777Sgblack@eecs.umich.edu            try:
9407777Sgblack@eecs.umich.edu                self.ip = convert.toIpAddress(value)
9417777Sgblack@eecs.umich.edu            except TypeError:
9427777Sgblack@eecs.umich.edu                self.ip = long(value)
9437777Sgblack@eecs.umich.edu        self.verifyIp()
9447777Sgblack@eecs.umich.edu
94510267SGeoffrey.Blake@arm.com    def __call__(self, value):
94610267SGeoffrey.Blake@arm.com        self.__init__(value)
94710267SGeoffrey.Blake@arm.com        return value
94810267SGeoffrey.Blake@arm.com
9498579Ssteve.reinhardt@amd.com    def __str__(self):
9508579Ssteve.reinhardt@amd.com        tup = [(self.ip >> i)  & 0xff for i in (24, 16, 8, 0)]
9518579Ssteve.reinhardt@amd.com        return '%d.%d.%d.%d' % tuple(tup)
9528579Ssteve.reinhardt@amd.com
9538579Ssteve.reinhardt@amd.com    def __eq__(self, other):
9548579Ssteve.reinhardt@amd.com        if isinstance(other, IpAddress):
9558579Ssteve.reinhardt@amd.com            return self.ip == other.ip
9568579Ssteve.reinhardt@amd.com        elif isinstance(other, str):
9578579Ssteve.reinhardt@amd.com            try:
9588579Ssteve.reinhardt@amd.com                return self.ip == convert.toIpAddress(other)
9598579Ssteve.reinhardt@amd.com            except:
9608579Ssteve.reinhardt@amd.com                return False
9618579Ssteve.reinhardt@amd.com        else:
9628579Ssteve.reinhardt@amd.com            return self.ip == other
9638579Ssteve.reinhardt@amd.com
9648579Ssteve.reinhardt@amd.com    def __ne__(self, other):
9658579Ssteve.reinhardt@amd.com        return not (self == other)
9668579Ssteve.reinhardt@amd.com
9677777Sgblack@eecs.umich.edu    def verifyIp(self):
9687777Sgblack@eecs.umich.edu        if self.ip < 0 or self.ip >= (1 << 32):
9697798Sgblack@eecs.umich.edu            raise TypeError, "invalid ip address %#08x" % self.ip
9707777Sgblack@eecs.umich.edu
9717777Sgblack@eecs.umich.edu    def getValue(self):
97211988Sandreas.sandberg@arm.com        from _m5.net import IpAddress
9737777Sgblack@eecs.umich.edu        return IpAddress(self.ip)
9747777Sgblack@eecs.umich.edu
9757777Sgblack@eecs.umich.edu# When initializing an IpNetmask, pass in an existing IpNetmask, a string of
9767777Sgblack@eecs.umich.edu# the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as
9777777Sgblack@eecs.umich.edu# positional or keyword arguments.
9787777Sgblack@eecs.umich.educlass IpNetmask(IpAddress):
9797777Sgblack@eecs.umich.edu    cxx_type = 'Net::IpNetmask'
98010267SGeoffrey.Blake@arm.com    ex_str = "127.0.0.0/24"
98110267SGeoffrey.Blake@arm.com    cmd_line_settable = True
9827777Sgblack@eecs.umich.edu
9837777Sgblack@eecs.umich.edu    @classmethod
9847777Sgblack@eecs.umich.edu    def cxx_predecls(cls, code):
9857777Sgblack@eecs.umich.edu        code('#include "base/inet.hh"')
9867777Sgblack@eecs.umich.edu
9877777Sgblack@eecs.umich.edu    def __init__(self, *args, **kwargs):
9887777Sgblack@eecs.umich.edu        def handle_kwarg(self, kwargs, key, elseVal = None):
9897777Sgblack@eecs.umich.edu            if key in kwargs:
9907777Sgblack@eecs.umich.edu                setattr(self, key, kwargs.pop(key))
9917777Sgblack@eecs.umich.edu            elif elseVal:
9927777Sgblack@eecs.umich.edu                setattr(self, key, elseVal)
9937777Sgblack@eecs.umich.edu            else:
9947777Sgblack@eecs.umich.edu                raise TypeError, "No value set for %s" % key
9957777Sgblack@eecs.umich.edu
9967777Sgblack@eecs.umich.edu        if len(args) == 0:
9977777Sgblack@eecs.umich.edu            handle_kwarg(self, kwargs, 'ip')
9987777Sgblack@eecs.umich.edu            handle_kwarg(self, kwargs, 'netmask')
9997777Sgblack@eecs.umich.edu
10007777Sgblack@eecs.umich.edu        elif len(args) == 1:
10017777Sgblack@eecs.umich.edu            if kwargs:
10027777Sgblack@eecs.umich.edu                if not 'ip' in kwargs and not 'netmask' in kwargs:
10037777Sgblack@eecs.umich.edu                    raise TypeError, "Invalid arguments"
10047777Sgblack@eecs.umich.edu                handle_kwarg(self, kwargs, 'ip', args[0])
10057777Sgblack@eecs.umich.edu                handle_kwarg(self, kwargs, 'netmask', args[0])
10067777Sgblack@eecs.umich.edu            elif isinstance(args[0], IpNetmask):
10077777Sgblack@eecs.umich.edu                self.ip = args[0].ip
10087777Sgblack@eecs.umich.edu                self.netmask = args[0].netmask
10097777Sgblack@eecs.umich.edu            else:
10107777Sgblack@eecs.umich.edu                (self.ip, self.netmask) = convert.toIpNetmask(args[0])
10117777Sgblack@eecs.umich.edu
10127777Sgblack@eecs.umich.edu        elif len(args) == 2:
10137777Sgblack@eecs.umich.edu            self.ip = args[0]
10147777Sgblack@eecs.umich.edu            self.netmask = args[1]
10157777Sgblack@eecs.umich.edu        else:
10167777Sgblack@eecs.umich.edu            raise TypeError, "Too many arguments specified"
10177777Sgblack@eecs.umich.edu
10187777Sgblack@eecs.umich.edu        if kwargs:
10197777Sgblack@eecs.umich.edu            raise TypeError, "Too many keywords: %s" % kwargs.keys()
10207777Sgblack@eecs.umich.edu
10217777Sgblack@eecs.umich.edu        self.verify()
10227777Sgblack@eecs.umich.edu
102310267SGeoffrey.Blake@arm.com    def __call__(self, value):
102410267SGeoffrey.Blake@arm.com        self.__init__(value)
102510267SGeoffrey.Blake@arm.com        return value
102610267SGeoffrey.Blake@arm.com
10278579Ssteve.reinhardt@amd.com    def __str__(self):
10288579Ssteve.reinhardt@amd.com        return "%s/%d" % (super(IpNetmask, self).__str__(), self.netmask)
10298579Ssteve.reinhardt@amd.com
10308579Ssteve.reinhardt@amd.com    def __eq__(self, other):
10318579Ssteve.reinhardt@amd.com        if isinstance(other, IpNetmask):
10328579Ssteve.reinhardt@amd.com            return self.ip == other.ip and self.netmask == other.netmask
10338579Ssteve.reinhardt@amd.com        elif isinstance(other, str):
10348579Ssteve.reinhardt@amd.com            try:
10358579Ssteve.reinhardt@amd.com                return (self.ip, self.netmask) == convert.toIpNetmask(other)
10368579Ssteve.reinhardt@amd.com            except:
10378579Ssteve.reinhardt@amd.com                return False
10388579Ssteve.reinhardt@amd.com        else:
10398579Ssteve.reinhardt@amd.com            return False
10408579Ssteve.reinhardt@amd.com
10417777Sgblack@eecs.umich.edu    def verify(self):
10427777Sgblack@eecs.umich.edu        self.verifyIp()
10437777Sgblack@eecs.umich.edu        if self.netmask < 0 or self.netmask > 32:
10447777Sgblack@eecs.umich.edu            raise TypeError, "invalid netmask %d" % netmask
10457777Sgblack@eecs.umich.edu
10467777Sgblack@eecs.umich.edu    def getValue(self):
104711988Sandreas.sandberg@arm.com        from _m5.net import IpNetmask
10487777Sgblack@eecs.umich.edu        return IpNetmask(self.ip, self.netmask)
10497777Sgblack@eecs.umich.edu
10507777Sgblack@eecs.umich.edu# When initializing an IpWithPort, pass in an existing IpWithPort, a string of
10517777Sgblack@eecs.umich.edu# the form "a.b.c.d:p", or an ip and port as positional or keyword arguments.
10527777Sgblack@eecs.umich.educlass IpWithPort(IpAddress):
10537777Sgblack@eecs.umich.edu    cxx_type = 'Net::IpWithPort'
105410267SGeoffrey.Blake@arm.com    ex_str = "127.0.0.1:80"
105510267SGeoffrey.Blake@arm.com    cmd_line_settable = True
10567777Sgblack@eecs.umich.edu
10577777Sgblack@eecs.umich.edu    @classmethod
10587777Sgblack@eecs.umich.edu    def cxx_predecls(cls, code):
10597777Sgblack@eecs.umich.edu        code('#include "base/inet.hh"')
10607777Sgblack@eecs.umich.edu
10617777Sgblack@eecs.umich.edu    def __init__(self, *args, **kwargs):
10627777Sgblack@eecs.umich.edu        def handle_kwarg(self, kwargs, key, elseVal = None):
10637777Sgblack@eecs.umich.edu            if key in kwargs:
10647777Sgblack@eecs.umich.edu                setattr(self, key, kwargs.pop(key))
10657777Sgblack@eecs.umich.edu            elif elseVal:
10667777Sgblack@eecs.umich.edu                setattr(self, key, elseVal)
10677777Sgblack@eecs.umich.edu            else:
10687777Sgblack@eecs.umich.edu                raise TypeError, "No value set for %s" % key
10697777Sgblack@eecs.umich.edu
10707777Sgblack@eecs.umich.edu        if len(args) == 0:
10717777Sgblack@eecs.umich.edu            handle_kwarg(self, kwargs, 'ip')
10727777Sgblack@eecs.umich.edu            handle_kwarg(self, kwargs, 'port')
10737777Sgblack@eecs.umich.edu
10747777Sgblack@eecs.umich.edu        elif len(args) == 1:
10757777Sgblack@eecs.umich.edu            if kwargs:
10767777Sgblack@eecs.umich.edu                if not 'ip' in kwargs and not 'port' in kwargs:
10777777Sgblack@eecs.umich.edu                    raise TypeError, "Invalid arguments"
10787777Sgblack@eecs.umich.edu                handle_kwarg(self, kwargs, 'ip', args[0])
10797777Sgblack@eecs.umich.edu                handle_kwarg(self, kwargs, 'port', args[0])
10807777Sgblack@eecs.umich.edu            elif isinstance(args[0], IpWithPort):
10817777Sgblack@eecs.umich.edu                self.ip = args[0].ip
10827777Sgblack@eecs.umich.edu                self.port = args[0].port
10837777Sgblack@eecs.umich.edu            else:
10847777Sgblack@eecs.umich.edu                (self.ip, self.port) = convert.toIpWithPort(args[0])
10857777Sgblack@eecs.umich.edu
10867777Sgblack@eecs.umich.edu        elif len(args) == 2:
10877777Sgblack@eecs.umich.edu            self.ip = args[0]
10887777Sgblack@eecs.umich.edu            self.port = args[1]
10897777Sgblack@eecs.umich.edu        else:
10907777Sgblack@eecs.umich.edu            raise TypeError, "Too many arguments specified"
10917777Sgblack@eecs.umich.edu
10927777Sgblack@eecs.umich.edu        if kwargs:
10937777Sgblack@eecs.umich.edu            raise TypeError, "Too many keywords: %s" % kwargs.keys()
10947777Sgblack@eecs.umich.edu
10957777Sgblack@eecs.umich.edu        self.verify()
10967777Sgblack@eecs.umich.edu
109710267SGeoffrey.Blake@arm.com    def __call__(self, value):
109810267SGeoffrey.Blake@arm.com        self.__init__(value)
109910267SGeoffrey.Blake@arm.com        return value
110010267SGeoffrey.Blake@arm.com
11018579Ssteve.reinhardt@amd.com    def __str__(self):
11028579Ssteve.reinhardt@amd.com        return "%s:%d" % (super(IpWithPort, self).__str__(), self.port)
11038579Ssteve.reinhardt@amd.com
11048579Ssteve.reinhardt@amd.com    def __eq__(self, other):
11058579Ssteve.reinhardt@amd.com        if isinstance(other, IpWithPort):
11068579Ssteve.reinhardt@amd.com            return self.ip == other.ip and self.port == other.port
11078579Ssteve.reinhardt@amd.com        elif isinstance(other, str):
11088579Ssteve.reinhardt@amd.com            try:
11098579Ssteve.reinhardt@amd.com                return (self.ip, self.port) == convert.toIpWithPort(other)
11108579Ssteve.reinhardt@amd.com            except:
11118579Ssteve.reinhardt@amd.com                return False
11128579Ssteve.reinhardt@amd.com        else:
11138579Ssteve.reinhardt@amd.com            return False
11148579Ssteve.reinhardt@amd.com
11157777Sgblack@eecs.umich.edu    def verify(self):
11167777Sgblack@eecs.umich.edu        self.verifyIp()
11177777Sgblack@eecs.umich.edu        if self.port < 0 or self.port > 0xffff:
11187777Sgblack@eecs.umich.edu            raise TypeError, "invalid port %d" % self.port
11197777Sgblack@eecs.umich.edu
11207777Sgblack@eecs.umich.edu    def getValue(self):
112111988Sandreas.sandberg@arm.com        from _m5.net import IpWithPort
11227777Sgblack@eecs.umich.edu        return IpWithPort(self.ip, self.port)
11237777Sgblack@eecs.umich.edu
11243932Sbinkertn@umich.edutime_formats = [ "%a %b %d %H:%M:%S %Z %Y",
112510380SAndrew.Bardsley@arm.com                 "%a %b %d %H:%M:%S %Y",
11263932Sbinkertn@umich.edu                 "%Y/%m/%d %H:%M:%S",
11273932Sbinkertn@umich.edu                 "%Y/%m/%d %H:%M",
11283932Sbinkertn@umich.edu                 "%Y/%m/%d",
11293932Sbinkertn@umich.edu                 "%m/%d/%Y %H:%M:%S",
11303932Sbinkertn@umich.edu                 "%m/%d/%Y %H:%M",
11313932Sbinkertn@umich.edu                 "%m/%d/%Y",
11323932Sbinkertn@umich.edu                 "%m/%d/%y %H:%M:%S",
11333932Sbinkertn@umich.edu                 "%m/%d/%y %H:%M",
11343932Sbinkertn@umich.edu                 "%m/%d/%y"]
11353932Sbinkertn@umich.edu
11363932Sbinkertn@umich.edu
11373885Sbinkertn@umich.edudef parse_time(value):
11383932Sbinkertn@umich.edu    from time import gmtime, strptime, struct_time, time
11393932Sbinkertn@umich.edu    from datetime import datetime, date
11403885Sbinkertn@umich.edu
11413932Sbinkertn@umich.edu    if isinstance(value, struct_time):
11423932Sbinkertn@umich.edu        return value
11433932Sbinkertn@umich.edu
11443932Sbinkertn@umich.edu    if isinstance(value, (int, long)):
11453932Sbinkertn@umich.edu        return gmtime(value)
11463932Sbinkertn@umich.edu
11473932Sbinkertn@umich.edu    if isinstance(value, (datetime, date)):
11483932Sbinkertn@umich.edu        return value.timetuple()
11493932Sbinkertn@umich.edu
11503932Sbinkertn@umich.edu    if isinstance(value, str):
11513932Sbinkertn@umich.edu        if value in ('Now', 'Today'):
11523932Sbinkertn@umich.edu            return time.gmtime(time.time())
11533932Sbinkertn@umich.edu
11543932Sbinkertn@umich.edu        for format in time_formats:
11553932Sbinkertn@umich.edu            try:
11563932Sbinkertn@umich.edu                return strptime(value, format)
11573932Sbinkertn@umich.edu            except ValueError:
11583932Sbinkertn@umich.edu                pass
11593885Sbinkertn@umich.edu
11603885Sbinkertn@umich.edu    raise ValueError, "Could not parse '%s' as a time" % value
11613885Sbinkertn@umich.edu
11623885Sbinkertn@umich.educlass Time(ParamValue):
11634762Snate@binkert.org    cxx_type = 'tm'
11647673Snate@binkert.org
11657673Snate@binkert.org    @classmethod
11667673Snate@binkert.org    def cxx_predecls(cls, code):
11677673Snate@binkert.org        code('#include <time.h>')
11687673Snate@binkert.org
11693885Sbinkertn@umich.edu    def __init__(self, value):
11703932Sbinkertn@umich.edu        self.value = parse_time(value)
11713885Sbinkertn@umich.edu
117210267SGeoffrey.Blake@arm.com    def __call__(self, value):
117310267SGeoffrey.Blake@arm.com        self.__init__(value)
117410267SGeoffrey.Blake@arm.com        return value
117510267SGeoffrey.Blake@arm.com
11764762Snate@binkert.org    def getValue(self):
117711988Sandreas.sandberg@arm.com        from _m5.core import tm
117811988Sandreas.sandberg@arm.com        import calendar
11794762Snate@binkert.org
118011988Sandreas.sandberg@arm.com        return tm.gmtime(calendar.timegm(self.value))
11814762Snate@binkert.org
11823885Sbinkertn@umich.edu    def __str__(self):
11834762Snate@binkert.org        return time.asctime(self.value)
11843885Sbinkertn@umich.edu
11853885Sbinkertn@umich.edu    def ini_str(self):
11863932Sbinkertn@umich.edu        return str(self)
11873885Sbinkertn@umich.edu
11888664SAli.Saidi@ARM.com    def get_config_as_dict(self):
118910380SAndrew.Bardsley@arm.com        assert false
11908664SAli.Saidi@ARM.com        return str(self)
11918664SAli.Saidi@ARM.com
119210458Sandreas.hansson@arm.com    @classmethod
119310458Sandreas.hansson@arm.com    def cxx_ini_predecls(cls, code):
119410458Sandreas.hansson@arm.com        code('#include <time.h>')
119510458Sandreas.hansson@arm.com
119610458Sandreas.hansson@arm.com    @classmethod
119710458Sandreas.hansson@arm.com    def cxx_ini_parse(cls, code, src, dest, ret):
119810458Sandreas.hansson@arm.com        code('char *_parse_ret = strptime((${src}).c_str(),')
119910458Sandreas.hansson@arm.com        code('    "%a %b %d %H:%M:%S %Y", &(${dest}));')
120010458Sandreas.hansson@arm.com        code('${ret} _parse_ret && *_parse_ret == \'\\0\';');
120110458Sandreas.hansson@arm.com
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
12063101Sstever@eecs.umich.edu# or the corresponding dictionary value.  For now, since we only check
12073101Sstever@eecs.umich.edu# that the alternative is valid and then spit it into a .ini file,
12083101Sstever@eecs.umich.edu# there's not much point in using the dictionary.)
12093101Sstever@eecs.umich.edu
12103101Sstever@eecs.umich.edu# What Enum() must do is generate a new type encapsulating the
12113101Sstever@eecs.umich.edu# provided list/dictionary so that specific values of the parameter
12123101Sstever@eecs.umich.edu# can be instances of that type.  We define two hidden internal
12133101Sstever@eecs.umich.edu# classes (_ListEnum and _DictEnum) to serve as base classes, then
12143101Sstever@eecs.umich.edu# derive the new type from the appropriate base class on the fly.
12153101Sstever@eecs.umich.edu
12164762Snate@binkert.orgallEnums = {}
12173101Sstever@eecs.umich.edu# Metaclass for Enum types
12185033Smilesck@eecs.umich.educlass MetaEnum(MetaParamValue):
12194762Snate@binkert.org    def __new__(mcls, name, bases, dict):
12204762Snate@binkert.org        assert name not in allEnums
12214762Snate@binkert.org
12224762Snate@binkert.org        cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict)
12234762Snate@binkert.org        allEnums[name] = cls
12244762Snate@binkert.org        return cls
12254762Snate@binkert.org
12263101Sstever@eecs.umich.edu    def __init__(cls, name, bases, init_dict):
12273101Sstever@eecs.umich.edu        if init_dict.has_key('map'):
12283101Sstever@eecs.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' " \
12373101Sstever@eecs.umich.edu                      "must be of type list"
12383101Sstever@eecs.umich.edu            # build string->value map from vals sequence
12393101Sstever@eecs.umich.edu            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
12464762Snate@binkert.org        cls.cxx_type = 'Enums::%s' % name
12473101Sstever@eecs.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.
12537673Snate@binkert.org    def cxx_decl(cls, code):
125410201SAndrew.Bardsley@arm.com        wrapper_name = cls.wrapper_name
125510201SAndrew.Bardsley@arm.com        wrapper = 'struct' if cls.wrapper_is_struct else 'namespace'
125610201SAndrew.Bardsley@arm.com        name = cls.__name__ if cls.enum_name is None else cls.enum_name
125710201SAndrew.Bardsley@arm.com        idem_macro = '__ENUM__%s__%s__' % (wrapper_name, name)
125810201SAndrew.Bardsley@arm.com
12597673Snate@binkert.org        code('''\
126010201SAndrew.Bardsley@arm.com#ifndef $idem_macro
126110201SAndrew.Bardsley@arm.com#define $idem_macro
12627673Snate@binkert.org
126310201SAndrew.Bardsley@arm.com$wrapper $wrapper_name {
12647673Snate@binkert.org    enum $name {
12657673Snate@binkert.org''')
12667673Snate@binkert.org        code.indent(2)
12674762Snate@binkert.org        for val in cls.vals:
12687673Snate@binkert.org            code('$val = ${{cls.map[val]}},')
12698902Sandreas.hansson@arm.com        code('Num_$name = ${{len(cls.vals)}}')
12707673Snate@binkert.org        code.dedent(2)
127110201SAndrew.Bardsley@arm.com        code('    };')
12724762Snate@binkert.org
127310201SAndrew.Bardsley@arm.com        if cls.wrapper_is_struct:
127410201SAndrew.Bardsley@arm.com            code('    static const char *${name}Strings[Num_${name}];')
127510201SAndrew.Bardsley@arm.com            code('};')
127610201SAndrew.Bardsley@arm.com        else:
127710201SAndrew.Bardsley@arm.com            code('extern const char *${name}Strings[Num_${name}];')
127810201SAndrew.Bardsley@arm.com            code('}')
127910201SAndrew.Bardsley@arm.com
128010201SAndrew.Bardsley@arm.com        code()
128110201SAndrew.Bardsley@arm.com        code('#endif // $idem_macro')
12827673Snate@binkert.org
12837673Snate@binkert.org    def cxx_def(cls, code):
128410201SAndrew.Bardsley@arm.com        wrapper_name = cls.wrapper_name
128510201SAndrew.Bardsley@arm.com        file_name = cls.__name__
128610201SAndrew.Bardsley@arm.com        name = cls.__name__ if cls.enum_name is None else cls.enum_name
128710201SAndrew.Bardsley@arm.com
128810201SAndrew.Bardsley@arm.com        code('#include "enums/$file_name.hh"')
128910201SAndrew.Bardsley@arm.com        if cls.wrapper_is_struct:
129010201SAndrew.Bardsley@arm.com            code('const char *${wrapper_name}::${name}Strings'
129110201SAndrew.Bardsley@arm.com                '[Num_${name}] =')
129210201SAndrew.Bardsley@arm.com        else:
129310201SAndrew.Bardsley@arm.com            code('namespace Enums {')
129410201SAndrew.Bardsley@arm.com            code.indent(1)
129510201SAndrew.Bardsley@arm.com            code(' const char *${name}Strings[Num_${name}] =')
129610201SAndrew.Bardsley@arm.com
129710201SAndrew.Bardsley@arm.com        code('{')
129810201SAndrew.Bardsley@arm.com        code.indent(1)
12994762Snate@binkert.org        for val in cls.vals:
13007673Snate@binkert.org            code('"$val",')
130110201SAndrew.Bardsley@arm.com        code.dedent(1)
130210201SAndrew.Bardsley@arm.com        code('};')
130310201SAndrew.Bardsley@arm.com
130410201SAndrew.Bardsley@arm.com        if not cls.wrapper_is_struct:
130510201SAndrew.Bardsley@arm.com            code('} // namespace $wrapper_name')
130610201SAndrew.Bardsley@arm.com            code.dedent(1)
13073101Sstever@eecs.umich.edu
130811988Sandreas.sandberg@arm.com    def pybind_def(cls, code):
130911988Sandreas.sandberg@arm.com        name = cls.__name__
131011988Sandreas.sandberg@arm.com        wrapper_name = cls.wrapper_name
131111988Sandreas.sandberg@arm.com        enum_name = cls.__name__ if cls.enum_name is None else cls.enum_name
131211988Sandreas.sandberg@arm.com
131311988Sandreas.sandberg@arm.com        code('''#include "pybind11/pybind11.h"
131411988Sandreas.sandberg@arm.com#include "pybind11/stl.h"
131511988Sandreas.sandberg@arm.com
131611988Sandreas.sandberg@arm.com#include <sim/init.hh>
131711988Sandreas.sandberg@arm.com
131811988Sandreas.sandberg@arm.comnamespace py = pybind11;
131911988Sandreas.sandberg@arm.com
132011988Sandreas.sandberg@arm.comstatic void
132111988Sandreas.sandberg@arm.commodule_init(py::module &m_internal)
132211988Sandreas.sandberg@arm.com{
132311988Sandreas.sandberg@arm.com    py::module m = m_internal.def_submodule("enum_${name}");
132411988Sandreas.sandberg@arm.com
132511988Sandreas.sandberg@arm.com    py::enum_<${wrapper_name}::${enum_name}>(m, "enum_${name}")
132611988Sandreas.sandberg@arm.com''')
132711988Sandreas.sandberg@arm.com
132811988Sandreas.sandberg@arm.com        code.indent()
132911988Sandreas.sandberg@arm.com        code.indent()
133011988Sandreas.sandberg@arm.com        for val in cls.vals:
133111988Sandreas.sandberg@arm.com            code('.value("${val}", ${wrapper_name}::${val})')
133211988Sandreas.sandberg@arm.com        code('.value("Num_${name}", ${wrapper_name}::Num_${enum_name})')
133311988Sandreas.sandberg@arm.com        code('.export_values()')
133411988Sandreas.sandberg@arm.com        code(';')
133511988Sandreas.sandberg@arm.com        code.dedent()
133611988Sandreas.sandberg@arm.com
133711988Sandreas.sandberg@arm.com        code('}')
133811988Sandreas.sandberg@arm.com        code.dedent()
133911988Sandreas.sandberg@arm.com        code()
134011988Sandreas.sandberg@arm.com        code('static EmbeddedPyBind embed_enum("enum_${name}", module_init);')
134111988Sandreas.sandberg@arm.com
13428596Ssteve.reinhardt@amd.com
13433101Sstever@eecs.umich.edu# Base class for enum types.
13443101Sstever@eecs.umich.educlass Enum(ParamValue):
13453101Sstever@eecs.umich.edu    __metaclass__ = MetaEnum
13463101Sstever@eecs.umich.edu    vals = []
134710267SGeoffrey.Blake@arm.com    cmd_line_settable = True
13483101Sstever@eecs.umich.edu
134910201SAndrew.Bardsley@arm.com    # The name of the wrapping namespace or struct
135010201SAndrew.Bardsley@arm.com    wrapper_name = 'Enums'
135110201SAndrew.Bardsley@arm.com
135210201SAndrew.Bardsley@arm.com    # If true, the enum is wrapped in a struct rather than a namespace
135310201SAndrew.Bardsley@arm.com    wrapper_is_struct = False
135410201SAndrew.Bardsley@arm.com
135510201SAndrew.Bardsley@arm.com    # If not None, use this as the enum name rather than this class name
135610201SAndrew.Bardsley@arm.com    enum_name = None
135710201SAndrew.Bardsley@arm.com
13583101Sstever@eecs.umich.edu    def __init__(self, value):
13593101Sstever@eecs.umich.edu        if value not in self.map:
13603101Sstever@eecs.umich.edu            raise TypeError, "Enum param got bad value '%s' (not in %s)" \
13613101Sstever@eecs.umich.edu                  % (value, self.vals)
13623101Sstever@eecs.umich.edu        self.value = value
13633101Sstever@eecs.umich.edu
136410267SGeoffrey.Blake@arm.com    def __call__(self, value):
136510267SGeoffrey.Blake@arm.com        self.__init__(value)
136610267SGeoffrey.Blake@arm.com        return value
136710267SGeoffrey.Blake@arm.com
13687675Snate@binkert.org    @classmethod
13697675Snate@binkert.org    def cxx_predecls(cls, code):
13707675Snate@binkert.org        code('#include "enums/$0.hh"', cls.__name__)
13717675Snate@binkert.org
13727675Snate@binkert.org    @classmethod
137310458Sandreas.hansson@arm.com    def cxx_ini_parse(cls, code, src, dest, ret):
137410458Sandreas.hansson@arm.com        code('if (false) {')
137510458Sandreas.hansson@arm.com        for elem_name in cls.map.iterkeys():
137610458Sandreas.hansson@arm.com            code('} else if (%s == "%s") {' % (src, elem_name))
137710458Sandreas.hansson@arm.com            code.indent()
137810458Sandreas.hansson@arm.com            code('%s = Enums::%s;' % (dest, elem_name))
137910458Sandreas.hansson@arm.com            code('%s true;' % ret)
138010458Sandreas.hansson@arm.com            code.dedent()
138110458Sandreas.hansson@arm.com        code('} else {')
138210458Sandreas.hansson@arm.com        code('    %s false;' % ret)
138310458Sandreas.hansson@arm.com        code('}')
138410458Sandreas.hansson@arm.com
13854762Snate@binkert.org    def getValue(self):
138611988Sandreas.sandberg@arm.com        import m5.internal.params
138711988Sandreas.sandberg@arm.com        e = getattr(m5.internal.params, "enum_%s" % self.__class__.__name__)
138811988Sandreas.sandberg@arm.com        return e(self.map[self.value])
13894762Snate@binkert.org
13903101Sstever@eecs.umich.edu    def __str__(self):
13913101Sstever@eecs.umich.edu        return self.value
13923101Sstever@eecs.umich.edu
13933101Sstever@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%
13953101Sstever@eecs.umich.edu
13964167Sbinkertn@umich.educlass TickParamValue(NumericParamValue):
13973101Sstever@eecs.umich.edu    cxx_type = 'Tick'
139810267SGeoffrey.Blake@arm.com    ex_str = "1MHz"
139910267SGeoffrey.Blake@arm.com    cmd_line_settable = True
14007673Snate@binkert.org
14017673Snate@binkert.org    @classmethod
14027673Snate@binkert.org    def cxx_predecls(cls, code):
14037673Snate@binkert.org        code('#include "base/types.hh"')
14047673Snate@binkert.org
140510267SGeoffrey.Blake@arm.com    def __call__(self, value):
140610267SGeoffrey.Blake@arm.com        self.__init__(value)
140710267SGeoffrey.Blake@arm.com        return value
140810267SGeoffrey.Blake@arm.com
14094762Snate@binkert.org    def getValue(self):
14104762Snate@binkert.org        return long(self.value)
14114762Snate@binkert.org
141210458Sandreas.hansson@arm.com    @classmethod
141310458Sandreas.hansson@arm.com    def cxx_ini_predecls(cls, code):
141410458Sandreas.hansson@arm.com        code('#include <sstream>')
141510458Sandreas.hansson@arm.com
141610458Sandreas.hansson@arm.com    # Ticks are expressed in seconds in JSON files and in plain
141710458Sandreas.hansson@arm.com    # Ticks in .ini files.  Switch based on a config flag
141810458Sandreas.hansson@arm.com    @classmethod
141910458Sandreas.hansson@arm.com    def cxx_ini_parse(self, code, src, dest, ret):
142010458Sandreas.hansson@arm.com        code('${ret} to_number(${src}, ${dest});')
142110458Sandreas.hansson@arm.com
14224167Sbinkertn@umich.educlass Latency(TickParamValue):
142310267SGeoffrey.Blake@arm.com    ex_str = "100ns"
142410267SGeoffrey.Blake@arm.com
14253101Sstever@eecs.umich.edu    def __init__(self, value):
14264167Sbinkertn@umich.edu        if isinstance(value, (Latency, Clock)):
14274167Sbinkertn@umich.edu            self.ticks = value.ticks
14284167Sbinkertn@umich.edu            self.value = value.value
14294167Sbinkertn@umich.edu        elif isinstance(value, Frequency):
14304167Sbinkertn@umich.edu            self.ticks = value.ticks
14314167Sbinkertn@umich.edu            self.value = 1.0 / value.value
14324167Sbinkertn@umich.edu        elif value.endswith('t'):
14334167Sbinkertn@umich.edu            self.ticks = True
14344167Sbinkertn@umich.edu            self.value = int(value[:-1])
14354167Sbinkertn@umich.edu        else:
14364167Sbinkertn@umich.edu            self.ticks = False
14374167Sbinkertn@umich.edu            self.value = convert.toLatency(value)
14383101Sstever@eecs.umich.edu
143910267SGeoffrey.Blake@arm.com    def __call__(self, value):
144010267SGeoffrey.Blake@arm.com        self.__init__(value)
144110267SGeoffrey.Blake@arm.com        return value
144210267SGeoffrey.Blake@arm.com
14433101Sstever@eecs.umich.edu    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':
14473101Sstever@eecs.umich.edu            return Frequency(self)
14483101Sstever@eecs.umich.edu        raise AttributeError, "Latency object has no attribute '%s'" % attr
14493101Sstever@eecs.umich.edu
14504762Snate@binkert.org    def getValue(self):
14514762Snate@binkert.org        if self.ticks or self.value == 0:
14524762Snate@binkert.org            value = self.value
14534762Snate@binkert.org        else:
14544762Snate@binkert.org            value = ticks.fromSeconds(self.value)
14554762Snate@binkert.org        return long(value)
14564762Snate@binkert.org
145710380SAndrew.Bardsley@arm.com    def config_value(self):
145810380SAndrew.Bardsley@arm.com        return self.getValue()
145910380SAndrew.Bardsley@arm.com
14603101Sstever@eecs.umich.edu    # convert latency to ticks
14613101Sstever@eecs.umich.edu    def ini_str(self):
14624762Snate@binkert.org        return '%d' % self.getValue()
14633101Sstever@eecs.umich.edu
14644167Sbinkertn@umich.educlass Frequency(TickParamValue):
146510267SGeoffrey.Blake@arm.com    ex_str = "1GHz"
146610267SGeoffrey.Blake@arm.com
14673101Sstever@eecs.umich.edu    def __init__(self, value):
14684167Sbinkertn@umich.edu        if isinstance(value, (Latency, Clock)):
14694167Sbinkertn@umich.edu            if value.value == 0:
14704167Sbinkertn@umich.edu                self.value = 0
14714167Sbinkertn@umich.edu            else:
14724167Sbinkertn@umich.edu                self.value = 1.0 / value.value
14734167Sbinkertn@umich.edu            self.ticks = value.ticks
14744167Sbinkertn@umich.edu        elif isinstance(value, Frequency):
14754167Sbinkertn@umich.edu            self.value = value.value
14764167Sbinkertn@umich.edu            self.ticks = value.ticks
14774167Sbinkertn@umich.edu        else:
14784167Sbinkertn@umich.edu            self.ticks = False
14794167Sbinkertn@umich.edu            self.value = convert.toFrequency(value)
14803101Sstever@eecs.umich.edu
148110267SGeoffrey.Blake@arm.com    def __call__(self, value):
148210267SGeoffrey.Blake@arm.com        self.__init__(value)
148310267SGeoffrey.Blake@arm.com        return value
148410267SGeoffrey.Blake@arm.com
14853101Sstever@eecs.umich.edu    def __getattr__(self, attr):
14863101Sstever@eecs.umich.edu        if attr == 'frequency':
14873101Sstever@eecs.umich.edu            return self
14883101Sstever@eecs.umich.edu        if attr in ('latency', 'period'):
14893101Sstever@eecs.umich.edu            return Latency(self)
14903101Sstever@eecs.umich.edu        raise AttributeError, "Frequency object has no attribute '%s'" % attr
14913101Sstever@eecs.umich.edu
14924167Sbinkertn@umich.edu    # convert latency to ticks
14934762Snate@binkert.org    def getValue(self):
14944762Snate@binkert.org        if self.ticks or self.value == 0:
14954762Snate@binkert.org            value = self.value
14964762Snate@binkert.org        else:
14974762Snate@binkert.org            value = ticks.fromSeconds(1.0 / self.value)
14984762Snate@binkert.org        return long(value)
14994762Snate@binkert.org
150010380SAndrew.Bardsley@arm.com    def config_value(self):
150110380SAndrew.Bardsley@arm.com        return self.getValue()
150210380SAndrew.Bardsley@arm.com
15033101Sstever@eecs.umich.edu    def ini_str(self):
15044762Snate@binkert.org        return '%d' % self.getValue()
15053101Sstever@eecs.umich.edu
150610019Sandreas.hansson@arm.com# A generic Frequency and/or Latency value. Value is stored as a
150710019Sandreas.hansson@arm.com# latency, just like Latency and Frequency.
150810019Sandreas.hansson@arm.comclass Clock(TickParamValue):
15093101Sstever@eecs.umich.edu    def __init__(self, value):
15104167Sbinkertn@umich.edu        if isinstance(value, (Latency, Clock)):
15114167Sbinkertn@umich.edu            self.ticks = value.ticks
15124167Sbinkertn@umich.edu            self.value = value.value
15134167Sbinkertn@umich.edu        elif isinstance(value, Frequency):
15144167Sbinkertn@umich.edu            self.ticks = value.ticks
15154167Sbinkertn@umich.edu            self.value = 1.0 / value.value
15164167Sbinkertn@umich.edu        elif value.endswith('t'):
15174167Sbinkertn@umich.edu            self.ticks = True
15184167Sbinkertn@umich.edu            self.value = int(value[:-1])
15194167Sbinkertn@umich.edu        else:
15204167Sbinkertn@umich.edu            self.ticks = False
15214167Sbinkertn@umich.edu            self.value = convert.anyToLatency(value)
15223101Sstever@eecs.umich.edu
152310267SGeoffrey.Blake@arm.com    def __call__(self, value):
152410267SGeoffrey.Blake@arm.com        self.__init__(value)
152510267SGeoffrey.Blake@arm.com        return value
152610267SGeoffrey.Blake@arm.com
152710267SGeoffrey.Blake@arm.com    def __str__(self):
152810267SGeoffrey.Blake@arm.com        return "%s" % Latency(self)
152910267SGeoffrey.Blake@arm.com
15303101Sstever@eecs.umich.edu    def __getattr__(self, attr):
15313101Sstever@eecs.umich.edu        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)
15353101Sstever@eecs.umich.edu        raise AttributeError, "Frequency object has no attribute '%s'" % attr
15363101Sstever@eecs.umich.edu
15374762Snate@binkert.org    def getValue(self):
15384762Snate@binkert.org        return self.period.getValue()
15394762Snate@binkert.org
154010380SAndrew.Bardsley@arm.com    def config_value(self):
154110380SAndrew.Bardsley@arm.com        return self.period.config_value()
154210380SAndrew.Bardsley@arm.com
15433101Sstever@eecs.umich.edu    def ini_str(self):
15443101Sstever@eecs.umich.edu        return self.period.ini_str()
15453101Sstever@eecs.umich.edu
154612250Sgabeblack@google.comclass Voltage(Float):
154710267SGeoffrey.Blake@arm.com    ex_str = "1V"
154810267SGeoffrey.Blake@arm.com
15499827Sakash.bagdia@arm.com    def __new__(cls, value):
155012250Sgabeblack@google.com        value = convert.toVoltage(value)
155112250Sgabeblack@google.com        return super(cls, Voltage).__new__(cls, value)
15529827Sakash.bagdia@arm.com
155312250Sgabeblack@google.com    def __init__(self, value):
155412250Sgabeblack@google.com        value = convert.toVoltage(value)
155512250Sgabeblack@google.com        super(Voltage, self).__init__(value)
155610267SGeoffrey.Blake@arm.com
155712250Sgabeblack@google.comclass Current(Float):
155810427Sandreas.hansson@arm.com    ex_str = "1mA"
155910427Sandreas.hansson@arm.com
156010427Sandreas.hansson@arm.com    def __new__(cls, value):
156112250Sgabeblack@google.com        value = convert.toCurrent(value)
156212250Sgabeblack@google.com        return super(cls, Current).__new__(cls, value)
156310427Sandreas.hansson@arm.com
156412250Sgabeblack@google.com    def __init__(self, value):
156512250Sgabeblack@google.com        value = convert.toCurrent(value)
156612250Sgabeblack@google.com        super(Current, self).__init__(value)
156710458Sandreas.hansson@arm.com
156812253Sgabeblack@google.comclass Energy(Float):
156912253Sgabeblack@google.com    ex_str = "1pJ"
157012253Sgabeblack@google.com
157112253Sgabeblack@google.com    def __new__(cls, value):
157212253Sgabeblack@google.com        value = convert.toEnergy(value)
157312253Sgabeblack@google.com        return super(cls, Energy).__new__(cls, value)
157412253Sgabeblack@google.com
157512253Sgabeblack@google.com    def __init__(self, value):
157612253Sgabeblack@google.com        value = convert.toEnergy(value)
157712253Sgabeblack@google.com        super(Energy, self).__init__(value)
157812253Sgabeblack@google.com
15793101Sstever@eecs.umich.educlass NetworkBandwidth(float,ParamValue):
15803101Sstever@eecs.umich.edu    cxx_type = 'float'
158110267SGeoffrey.Blake@arm.com    ex_str = "1Gbps"
158210267SGeoffrey.Blake@arm.com    cmd_line_settable = True
158310267SGeoffrey.Blake@arm.com
15843101Sstever@eecs.umich.edu    def __new__(cls, value):
15854167Sbinkertn@umich.edu        # convert to bits per second
15864167Sbinkertn@umich.edu        val = convert.toNetworkBandwidth(value)
15873101Sstever@eecs.umich.edu        return super(cls, NetworkBandwidth).__new__(cls, val)
15883101Sstever@eecs.umich.edu
15893101Sstever@eecs.umich.edu    def __str__(self):
15903101Sstever@eecs.umich.edu        return str(self.val)
15913101Sstever@eecs.umich.edu
159210267SGeoffrey.Blake@arm.com    def __call__(self, value):
159310267SGeoffrey.Blake@arm.com        val = convert.toNetworkBandwidth(value)
159410267SGeoffrey.Blake@arm.com        self.__init__(val)
159510267SGeoffrey.Blake@arm.com        return value
159610267SGeoffrey.Blake@arm.com
15974762Snate@binkert.org    def getValue(self):
15984167Sbinkertn@umich.edu        # convert to seconds per byte
15994167Sbinkertn@umich.edu        value = 8.0 / float(self)
16004167Sbinkertn@umich.edu        # convert to ticks per byte
16014762Snate@binkert.org        value = ticks.fromSeconds(value)
16024762Snate@binkert.org        return float(value)
16034762Snate@binkert.org
16044762Snate@binkert.org    def ini_str(self):
16054762Snate@binkert.org        return '%f' % self.getValue()
16063101Sstever@eecs.umich.edu
160710380SAndrew.Bardsley@arm.com    def config_value(self):
160810380SAndrew.Bardsley@arm.com        return '%f' % self.getValue()
160910380SAndrew.Bardsley@arm.com
161010458Sandreas.hansson@arm.com    @classmethod
161110458Sandreas.hansson@arm.com    def cxx_ini_predecls(cls, code):
161210458Sandreas.hansson@arm.com        code('#include <sstream>')
161310458Sandreas.hansson@arm.com
161410458Sandreas.hansson@arm.com    @classmethod
161510458Sandreas.hansson@arm.com    def cxx_ini_parse(self, code, src, dest, ret):
161610458Sandreas.hansson@arm.com        code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
161710458Sandreas.hansson@arm.com
16183101Sstever@eecs.umich.educlass MemoryBandwidth(float,ParamValue):
16193101Sstever@eecs.umich.edu    cxx_type = 'float'
162010267SGeoffrey.Blake@arm.com    ex_str = "1GB/s"
162110267SGeoffrey.Blake@arm.com    cmd_line_settable = True
162210267SGeoffrey.Blake@arm.com
16235469Snate@binkert.org    def __new__(cls, value):
16247743Sgblack@eecs.umich.edu        # convert to bytes per second
16253102Sstever@eecs.umich.edu        val = convert.toMemoryBandwidth(value)
16263101Sstever@eecs.umich.edu        return super(cls, MemoryBandwidth).__new__(cls, val)
16273101Sstever@eecs.umich.edu
162810267SGeoffrey.Blake@arm.com    def __call__(self, value):
162910267SGeoffrey.Blake@arm.com        val = convert.toMemoryBandwidth(value)
163010267SGeoffrey.Blake@arm.com        self.__init__(val)
163110267SGeoffrey.Blake@arm.com        return value
16323101Sstever@eecs.umich.edu
16334762Snate@binkert.org    def getValue(self):
16344167Sbinkertn@umich.edu        # convert to seconds per byte
16355468Snate@binkert.org        value = float(self)
16365468Snate@binkert.org        if value:
16375468Snate@binkert.org            value = 1.0 / float(self)
16384167Sbinkertn@umich.edu        # convert to ticks per byte
16394762Snate@binkert.org        value = ticks.fromSeconds(value)
16404762Snate@binkert.org        return float(value)
16414762Snate@binkert.org
16424762Snate@binkert.org    def ini_str(self):
16434762Snate@binkert.org        return '%f' % self.getValue()
16443101Sstever@eecs.umich.edu
164510380SAndrew.Bardsley@arm.com    def config_value(self):
164610380SAndrew.Bardsley@arm.com        return '%f' % self.getValue()
164710380SAndrew.Bardsley@arm.com
164810458Sandreas.hansson@arm.com    @classmethod
164910458Sandreas.hansson@arm.com    def cxx_ini_predecls(cls, code):
165010458Sandreas.hansson@arm.com        code('#include <sstream>')
165110458Sandreas.hansson@arm.com
165210458Sandreas.hansson@arm.com    @classmethod
165310458Sandreas.hansson@arm.com    def cxx_ini_parse(self, code, src, dest, ret):
165410458Sandreas.hansson@arm.com        code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
165510458Sandreas.hansson@arm.com
16563101Sstever@eecs.umich.edu#
16573101Sstever@eecs.umich.edu# "Constants"... handy aliases for various values.
16583101Sstever@eecs.umich.edu#
16593101Sstever@eecs.umich.edu
16603102Sstever@eecs.umich.edu# Special class for NULL pointers.  Note the special check in
16613102Sstever@eecs.umich.edu# make_param_value() above that lets these be assigned where a
16623102Sstever@eecs.umich.edu# SimObject is required.
16633102Sstever@eecs.umich.edu# only one copy of a particular node
16643102Sstever@eecs.umich.educlass NullSimObject(object):
16653102Sstever@eecs.umich.edu    __metaclass__ = Singleton
166612197Sgabeblack@google.com    _name = 'Null'
16673102Sstever@eecs.umich.edu
16683102Sstever@eecs.umich.edu    def __call__(cls):
16693102Sstever@eecs.umich.edu        return cls
16703102Sstever@eecs.umich.edu
16713102Sstever@eecs.umich.edu    def _instantiate(self, parent = None, path = ''):
16723102Sstever@eecs.umich.edu        pass
16733102Sstever@eecs.umich.edu
16743102Sstever@eecs.umich.edu    def ini_str(self):
16753102Sstever@eecs.umich.edu        return 'Null'
16763102Sstever@eecs.umich.edu
16773102Sstever@eecs.umich.edu    def unproxy(self, base):
16783102Sstever@eecs.umich.edu        return self
16793102Sstever@eecs.umich.edu
16803102Sstever@eecs.umich.edu    def set_path(self, parent, name):
16813102Sstever@eecs.umich.edu        pass
16824762Snate@binkert.org
168312192Sgabeblack@google.com    def set_parent(self, parent, name):
168412192Sgabeblack@google.com        pass
168512192Sgabeblack@google.com
168612195Sgabeblack@google.com    def clear_parent(self, old_parent):
168712195Sgabeblack@google.com        pass
168812195Sgabeblack@google.com
168912196Sgabeblack@google.com    def descendants(self):
169012196Sgabeblack@google.com        return
169112196Sgabeblack@google.com        yield None
169212196Sgabeblack@google.com
169312200Sgabeblack@google.com    def get_config_as_dict(self):
169412200Sgabeblack@google.com        return {}
169512200Sgabeblack@google.com
16963102Sstever@eecs.umich.edu    def __str__(self):
169712197Sgabeblack@google.com        return self._name
16983102Sstever@eecs.umich.edu
169910380SAndrew.Bardsley@arm.com    def config_value(self):
170010380SAndrew.Bardsley@arm.com        return None
170110380SAndrew.Bardsley@arm.com
17024762Snate@binkert.org    def getValue(self):
17034762Snate@binkert.org        return None
17044762Snate@binkert.org
17053102Sstever@eecs.umich.edu# The only instance you'll ever need...
17063102Sstever@eecs.umich.eduNULL = NullSimObject()
17073102Sstever@eecs.umich.edu
17083102Sstever@eecs.umich.edudef isNullPointer(value):
17093102Sstever@eecs.umich.edu    return isinstance(value, NullSimObject)
17103102Sstever@eecs.umich.edu
17113101Sstever@eecs.umich.edu# Some memory range specifications use this as a default upper bound.
17123101Sstever@eecs.umich.eduMaxAddr = Addr.max
17133101Sstever@eecs.umich.eduMaxTick = Tick.max
17143101Sstever@eecs.umich.eduAllMemory = AddrRange(0, MaxAddr)
17153101Sstever@eecs.umich.edu
17163101Sstever@eecs.umich.edu
17173101Sstever@eecs.umich.edu#####################################################################
17183101Sstever@eecs.umich.edu#
17193101Sstever@eecs.umich.edu# Port objects
17203101Sstever@eecs.umich.edu#
17213101Sstever@eecs.umich.edu# Ports are used to interconnect objects in the memory system.
17223101Sstever@eecs.umich.edu#
17233101Sstever@eecs.umich.edu#####################################################################
17243101Sstever@eecs.umich.edu
17253101Sstever@eecs.umich.edu# Port reference: encapsulates a reference to a particular port on a
17263101Sstever@eecs.umich.edu# particular SimObject.
17273101Sstever@eecs.umich.educlass PortRef(object):
17288839Sandreas.hansson@arm.com    def __init__(self, simobj, name, role):
17293105Sstever@eecs.umich.edu        assert(isSimObject(simobj) or isSimObjectClass(simobj))
17303101Sstever@eecs.umich.edu        self.simobj = simobj
17313101Sstever@eecs.umich.edu        self.name = name
17328839Sandreas.hansson@arm.com        self.role = role
17333101Sstever@eecs.umich.edu        self.peer = None   # not associated with another port yet
17343101Sstever@eecs.umich.edu        self.ccConnected = False # C++ port connection done?
17353105Sstever@eecs.umich.edu        self.index = -1  # always -1 for non-vector ports
17363101Sstever@eecs.umich.edu
17373103Sstever@eecs.umich.edu    def __str__(self):
17383105Sstever@eecs.umich.edu        return '%s.%s' % (self.simobj, self.name)
17393103Sstever@eecs.umich.edu
17408840Sandreas.hansson@arm.com    def __len__(self):
17418840Sandreas.hansson@arm.com        # Return the number of connected ports, i.e. 0 is we have no
17428840Sandreas.hansson@arm.com        # peer and 1 if we do.
17438840Sandreas.hansson@arm.com        return int(self.peer != None)
17448840Sandreas.hansson@arm.com
17453105Sstever@eecs.umich.edu    # for config.ini, print peer's name (not ours)
17463105Sstever@eecs.umich.edu    def ini_str(self):
17473105Sstever@eecs.umich.edu        return str(self.peer)
17483105Sstever@eecs.umich.edu
17499017Sandreas.hansson@arm.com    # for config.json
17509017Sandreas.hansson@arm.com    def get_config_as_dict(self):
17519017Sandreas.hansson@arm.com        return {'role' : self.role, 'peer' : str(self.peer)}
17529017Sandreas.hansson@arm.com
17533105Sstever@eecs.umich.edu    def __getattr__(self, attr):
17543105Sstever@eecs.umich.edu        if attr == 'peerObj':
17553105Sstever@eecs.umich.edu            # shorthand for proxies
17563105Sstever@eecs.umich.edu            return self.peer.simobj
17573105Sstever@eecs.umich.edu        raise AttributeError, "'%s' object has no attribute '%s'" % \
17583105Sstever@eecs.umich.edu              (self.__class__.__name__, attr)
17593105Sstever@eecs.umich.edu
17603105Sstever@eecs.umich.edu    # Full connection is symmetric (both ways).  Called via
17613105Sstever@eecs.umich.edu    # SimObject.__setattr__ as a result of a port assignment, e.g.,
17623109Sstever@eecs.umich.edu    # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
17633105Sstever@eecs.umich.edu    # e.g., "obj1.portA[3] = obj2.portB".
17643105Sstever@eecs.umich.edu    def connect(self, other):
17653105Sstever@eecs.umich.edu        if isinstance(other, VectorPortRef):
17663105Sstever@eecs.umich.edu            # reference to plain VectorPort is implicit append
17673105Sstever@eecs.umich.edu            other = other._get_next()
17683105Sstever@eecs.umich.edu        if self.peer and not proxy.isproxy(self.peer):
17699014Sandreas.hansson@arm.com            fatal("Port %s is already connected to %s, cannot connect %s\n",
17709014Sandreas.hansson@arm.com                  self, self.peer, other);
17713101Sstever@eecs.umich.edu        self.peer = other
17723109Sstever@eecs.umich.edu        if proxy.isproxy(other):
17733109Sstever@eecs.umich.edu            other.set_param_desc(PortParamDesc())
17743109Sstever@eecs.umich.edu        elif isinstance(other, PortRef):
17753109Sstever@eecs.umich.edu            if other.peer is not self:
17763109Sstever@eecs.umich.edu                other.connect(self)
17773109Sstever@eecs.umich.edu        else:
17783109Sstever@eecs.umich.edu            raise TypeError, \
17793109Sstever@eecs.umich.edu                  "assigning non-port reference '%s' to port '%s'" \
17803109Sstever@eecs.umich.edu                  % (other, self)
17813101Sstever@eecs.umich.edu
178210355SGeoffrey.Blake@arm.com    # Allow a master/slave port pair to be spliced between
178310355SGeoffrey.Blake@arm.com    # a port and its connected peer. Useful operation for connecting
178410355SGeoffrey.Blake@arm.com    # instrumentation structures into a system when it is necessary
178510355SGeoffrey.Blake@arm.com    # to connect the instrumentation after the full system has been
178610355SGeoffrey.Blake@arm.com    # constructed.
178710355SGeoffrey.Blake@arm.com    def splice(self, new_master_peer, new_slave_peer):
178813543Sgabeblack@google.com        if not self.peer or proxy.isproxy(self.peer):
178913543Sgabeblack@google.com            fatal("Port %s not connected, cannot splice in new peers\n", self)
179013543Sgabeblack@google.com
179113543Sgabeblack@google.com        if not isinstance(new_master_peer, PortRef) or \
179213543Sgabeblack@google.com           not isinstance(new_slave_peer, PortRef):
179313543Sgabeblack@google.com            raise TypeError, \
179413543Sgabeblack@google.com                  "Splicing non-port references '%s','%s' to port '%s'" % \
179513543Sgabeblack@google.com                  (new_master_peer, new_slave_peer, self)
179613543Sgabeblack@google.com
179713543Sgabeblack@google.com        old_peer = self.peer
179813543Sgabeblack@google.com        if self.role == 'SLAVE':
179913543Sgabeblack@google.com            self.peer = new_master_peer
180013543Sgabeblack@google.com            old_peer.peer = new_slave_peer
180113543Sgabeblack@google.com            new_master_peer.connect(self)
180213543Sgabeblack@google.com            new_slave_peer.connect(old_peer)
180313543Sgabeblack@google.com        elif self.role == 'MASTER':
180413543Sgabeblack@google.com            self.peer = new_slave_peer
180513543Sgabeblack@google.com            old_peer.peer = new_master_peer
180613543Sgabeblack@google.com            new_slave_peer.connect(self)
180713543Sgabeblack@google.com            new_master_peer.connect(old_peer)
180810355SGeoffrey.Blake@arm.com        else:
180913543Sgabeblack@google.com            panic("Port %s has unknown role, "+\
181013543Sgabeblack@google.com                  "cannot splice in new peers\n", self)
181110355SGeoffrey.Blake@arm.com
18123105Sstever@eecs.umich.edu    def clone(self, simobj, memo):
18133105Sstever@eecs.umich.edu        if memo.has_key(self):
18143105Sstever@eecs.umich.edu            return memo[self]
18153101Sstever@eecs.umich.edu        newRef = copy.copy(self)
18163105Sstever@eecs.umich.edu        memo[self] = newRef
18173105Sstever@eecs.umich.edu        newRef.simobj = simobj
18183101Sstever@eecs.umich.edu        assert(isSimObject(newRef.simobj))
18193105Sstever@eecs.umich.edu        if self.peer and not proxy.isproxy(self.peer):
18203179Sstever@eecs.umich.edu            peerObj = self.peer.simobj(_memo=memo)
18213105Sstever@eecs.umich.edu            newRef.peer = self.peer.clone(peerObj, memo)
18223105Sstever@eecs.umich.edu            assert(not isinstance(newRef.peer, VectorPortRef))
18233101Sstever@eecs.umich.edu        return newRef
18243101Sstever@eecs.umich.edu
18253105Sstever@eecs.umich.edu    def unproxy(self, simobj):
18263105Sstever@eecs.umich.edu        assert(simobj is self.simobj)
18273105Sstever@eecs.umich.edu        if proxy.isproxy(self.peer):
18283105Sstever@eecs.umich.edu            try:
18293105Sstever@eecs.umich.edu                realPeer = self.peer.unproxy(self.simobj)
18303105Sstever@eecs.umich.edu            except:
183112563Sgabeblack@google.com                print("Error in unproxying port '%s' of %s" %
183212563Sgabeblack@google.com                      (self.name, self.simobj.path()))
18333105Sstever@eecs.umich.edu                raise
18343105Sstever@eecs.umich.edu            self.connect(realPeer)
18353105Sstever@eecs.umich.edu
18363101Sstever@eecs.umich.edu    # Call C++ to create corresponding port connection between C++ objects
18373101Sstever@eecs.umich.edu    def ccConnect(self):
183811802Sandreas.sandberg@arm.com        from _m5.pyobject import connectPorts
18394762Snate@binkert.org
18408839Sandreas.hansson@arm.com        if self.role == 'SLAVE':
18418839Sandreas.hansson@arm.com            # do nothing and let the master take care of it
18428839Sandreas.hansson@arm.com            return
18438839Sandreas.hansson@arm.com
18443101Sstever@eecs.umich.edu        if self.ccConnected: # already done this
18453101Sstever@eecs.umich.edu            return
18463101Sstever@eecs.umich.edu        peer = self.peer
18475578SSteve.Reinhardt@amd.com        if not self.peer: # nothing to connect to
18485578SSteve.Reinhardt@amd.com            return
18498839Sandreas.hansson@arm.com
18508839Sandreas.hansson@arm.com        # check that we connect a master to a slave
18518839Sandreas.hansson@arm.com        if self.role == peer.role:
18528839Sandreas.hansson@arm.com            raise TypeError, \
18538839Sandreas.hansson@arm.com                "cannot connect '%s' and '%s' due to identical role '%s'" \
18548839Sandreas.hansson@arm.com                % (peer, self, self.role)
18558839Sandreas.hansson@arm.com
18567526Ssteve.reinhardt@amd.com        try:
18578839Sandreas.hansson@arm.com            # self is always the master and peer the slave
18587526Ssteve.reinhardt@amd.com            connectPorts(self.simobj.getCCObject(), self.name, self.index,
18597526Ssteve.reinhardt@amd.com                         peer.simobj.getCCObject(), peer.name, peer.index)
18607526Ssteve.reinhardt@amd.com        except:
186112563Sgabeblack@google.com            print("Error connecting port %s.%s to %s.%s" %
18627526Ssteve.reinhardt@amd.com                  (self.simobj.path(), self.name,
186312563Sgabeblack@google.com                   peer.simobj.path(), peer.name))
18647526Ssteve.reinhardt@amd.com            raise
18653101Sstever@eecs.umich.edu        self.ccConnected = True
18663101Sstever@eecs.umich.edu        peer.ccConnected = True
18673101Sstever@eecs.umich.edu
18683105Sstever@eecs.umich.edu# A reference to an individual element of a VectorPort... much like a
18693105Sstever@eecs.umich.edu# PortRef, but has an index.
18703105Sstever@eecs.umich.educlass VectorPortElementRef(PortRef):
18718839Sandreas.hansson@arm.com    def __init__(self, simobj, name, role, index):
18728839Sandreas.hansson@arm.com        PortRef.__init__(self, simobj, name, role)
18733105Sstever@eecs.umich.edu        self.index = index
18743105Sstever@eecs.umich.edu
18753105Sstever@eecs.umich.edu    def __str__(self):
18763105Sstever@eecs.umich.edu        return '%s.%s[%d]' % (self.simobj, self.name, self.index)
18773105Sstever@eecs.umich.edu
18783105Sstever@eecs.umich.edu# A reference to a complete vector-valued port (not just a single element).
18793105Sstever@eecs.umich.edu# Can be indexed to retrieve individual VectorPortElementRef instances.
18803105Sstever@eecs.umich.educlass VectorPortRef(object):
18818839Sandreas.hansson@arm.com    def __init__(self, simobj, name, role):
18823105Sstever@eecs.umich.edu        assert(isSimObject(simobj) or isSimObjectClass(simobj))
18833105Sstever@eecs.umich.edu        self.simobj = simobj
18843105Sstever@eecs.umich.edu        self.name = name
18858839Sandreas.hansson@arm.com        self.role = role
18863105Sstever@eecs.umich.edu        self.elements = []
18873105Sstever@eecs.umich.edu
18883109Sstever@eecs.umich.edu    def __str__(self):
18893109Sstever@eecs.umich.edu        return '%s.%s[:]' % (self.simobj, self.name)
18903109Sstever@eecs.umich.edu
18918840Sandreas.hansson@arm.com    def __len__(self):
18928840Sandreas.hansson@arm.com        # Return the number of connected peers, corresponding the the
18938840Sandreas.hansson@arm.com        # length of the elements.
18948840Sandreas.hansson@arm.com        return len(self.elements)
18958840Sandreas.hansson@arm.com
18963105Sstever@eecs.umich.edu    # for config.ini, print peer's name (not ours)
18973105Sstever@eecs.umich.edu    def ini_str(self):
18983105Sstever@eecs.umich.edu        return ' '.join([el.ini_str() for el in self.elements])
18993105Sstever@eecs.umich.edu
19009017Sandreas.hansson@arm.com    # for config.json
19019017Sandreas.hansson@arm.com    def get_config_as_dict(self):
19029017Sandreas.hansson@arm.com        return {'role' : self.role,
19039017Sandreas.hansson@arm.com                'peer' : [el.ini_str() for el in self.elements]}
19049017Sandreas.hansson@arm.com
19053105Sstever@eecs.umich.edu    def __getitem__(self, key):
19063105Sstever@eecs.umich.edu        if not isinstance(key, int):
19073105Sstever@eecs.umich.edu            raise TypeError, "VectorPort index must be integer"
19083105Sstever@eecs.umich.edu        if key >= len(self.elements):
19093105Sstever@eecs.umich.edu            # need to extend list
19108839Sandreas.hansson@arm.com            ext = [VectorPortElementRef(self.simobj, self.name, self.role, i)
19113105Sstever@eecs.umich.edu                   for i in range(len(self.elements), key+1)]
19123105Sstever@eecs.umich.edu            self.elements.extend(ext)
19133105Sstever@eecs.umich.edu        return self.elements[key]
19143105Sstever@eecs.umich.edu
19153105Sstever@eecs.umich.edu    def _get_next(self):
19163105Sstever@eecs.umich.edu        return self[len(self.elements)]
19173105Sstever@eecs.umich.edu
19183105Sstever@eecs.umich.edu    def __setitem__(self, key, value):
19193105Sstever@eecs.umich.edu        if not isinstance(key, int):
19203105Sstever@eecs.umich.edu            raise TypeError, "VectorPort index must be integer"
19213105Sstever@eecs.umich.edu        self[key].connect(value)
19223105Sstever@eecs.umich.edu
19233105Sstever@eecs.umich.edu    def connect(self, other):
19243109Sstever@eecs.umich.edu        if isinstance(other, (list, tuple)):
19253109Sstever@eecs.umich.edu            # Assign list of port refs to vector port.
19263109Sstever@eecs.umich.edu            # For now, append them... not sure if that's the right semantics
19273109Sstever@eecs.umich.edu            # or if it should replace the current vector.
19283109Sstever@eecs.umich.edu            for ref in other:
19293109Sstever@eecs.umich.edu                self._get_next().connect(ref)
19303109Sstever@eecs.umich.edu        else:
19313109Sstever@eecs.umich.edu            # scalar assignment to plain VectorPort is implicit append
19323109Sstever@eecs.umich.edu            self._get_next().connect(other)
19333109Sstever@eecs.umich.edu
19343109Sstever@eecs.umich.edu    def clone(self, simobj, memo):
19353109Sstever@eecs.umich.edu        if memo.has_key(self):
19363109Sstever@eecs.umich.edu            return memo[self]
19373109Sstever@eecs.umich.edu        newRef = copy.copy(self)
19383109Sstever@eecs.umich.edu        memo[self] = newRef
19393109Sstever@eecs.umich.edu        newRef.simobj = simobj
19403109Sstever@eecs.umich.edu        assert(isSimObject(newRef.simobj))
19413109Sstever@eecs.umich.edu        newRef.elements = [el.clone(simobj, memo) for el in self.elements]
19423109Sstever@eecs.umich.edu        return newRef
19433105Sstever@eecs.umich.edu
19443105Sstever@eecs.umich.edu    def unproxy(self, simobj):
19453105Sstever@eecs.umich.edu        [el.unproxy(simobj) for el in self.elements]
19463105Sstever@eecs.umich.edu
19473105Sstever@eecs.umich.edu    def ccConnect(self):
19483105Sstever@eecs.umich.edu        [el.ccConnect() for el in self.elements]
19493105Sstever@eecs.umich.edu
19503101Sstever@eecs.umich.edu# Port description object.  Like a ParamDesc object, this represents a
19513101Sstever@eecs.umich.edu# logical port in the SimObject class, not a particular port on a
19523101Sstever@eecs.umich.edu# SimObject instance.  The latter are represented by PortRef objects.
19533101Sstever@eecs.umich.educlass Port(object):
19543101Sstever@eecs.umich.edu    # Generate a PortRef for this port on the given SimObject with the
19553101Sstever@eecs.umich.edu    # given name
19563105Sstever@eecs.umich.edu    def makeRef(self, simobj):
19578839Sandreas.hansson@arm.com        return PortRef(simobj, self.name, self.role)
19583101Sstever@eecs.umich.edu
19593101Sstever@eecs.umich.edu    # Connect an instance of this port (on the given SimObject with
19603101Sstever@eecs.umich.edu    # the given name) with the port described by the supplied PortRef
19613105Sstever@eecs.umich.edu    def connect(self, simobj, ref):
19623105Sstever@eecs.umich.edu        self.makeRef(simobj).connect(ref)
19633101Sstever@eecs.umich.edu
19648840Sandreas.hansson@arm.com    # No need for any pre-declarations at the moment as we merely rely
19658840Sandreas.hansson@arm.com    # on an unsigned int.
19668840Sandreas.hansson@arm.com    def cxx_predecls(self, code):
19678840Sandreas.hansson@arm.com        pass
19688840Sandreas.hansson@arm.com
196911988Sandreas.sandberg@arm.com    def pybind_predecls(self, code):
197011988Sandreas.sandberg@arm.com        cls.cxx_predecls(self, code)
197111988Sandreas.sandberg@arm.com
19728840Sandreas.hansson@arm.com    # Declare an unsigned int with the same name as the port, that
19738840Sandreas.hansson@arm.com    # will eventually hold the number of connected ports (and thus the
19748840Sandreas.hansson@arm.com    # number of elements for a VectorPort).
19758840Sandreas.hansson@arm.com    def cxx_decl(self, code):
19768840Sandreas.hansson@arm.com        code('unsigned int port_${{self.name}}_connection_count;')
19778840Sandreas.hansson@arm.com
19788839Sandreas.hansson@arm.comclass MasterPort(Port):
19798839Sandreas.hansson@arm.com    # MasterPort("description")
19808839Sandreas.hansson@arm.com    def __init__(self, *args):
19818839Sandreas.hansson@arm.com        if len(args) == 1:
19828839Sandreas.hansson@arm.com            self.desc = args[0]
19838839Sandreas.hansson@arm.com            self.role = 'MASTER'
19848839Sandreas.hansson@arm.com        else:
19858839Sandreas.hansson@arm.com            raise TypeError, 'wrong number of arguments'
19868839Sandreas.hansson@arm.com
19878839Sandreas.hansson@arm.comclass SlavePort(Port):
19888839Sandreas.hansson@arm.com    # SlavePort("description")
19898839Sandreas.hansson@arm.com    def __init__(self, *args):
19908839Sandreas.hansson@arm.com        if len(args) == 1:
19918839Sandreas.hansson@arm.com            self.desc = args[0]
19928839Sandreas.hansson@arm.com            self.role = 'SLAVE'
19938839Sandreas.hansson@arm.com        else:
19948839Sandreas.hansson@arm.com            raise TypeError, 'wrong number of arguments'
19958839Sandreas.hansson@arm.com
19963101Sstever@eecs.umich.edu# VectorPort description object.  Like Port, but represents a vector
199710405Sandreas.hansson@arm.com# of connections (e.g., as on a XBar).
19983101Sstever@eecs.umich.educlass VectorPort(Port):
19993105Sstever@eecs.umich.edu    def __init__(self, *args):
20003101Sstever@eecs.umich.edu        self.isVec = True
20013101Sstever@eecs.umich.edu
20023105Sstever@eecs.umich.edu    def makeRef(self, simobj):
20038839Sandreas.hansson@arm.com        return VectorPortRef(simobj, self.name, self.role)
20048839Sandreas.hansson@arm.com
20058839Sandreas.hansson@arm.comclass VectorMasterPort(VectorPort):
20068839Sandreas.hansson@arm.com    # VectorMasterPort("description")
20078839Sandreas.hansson@arm.com    def __init__(self, *args):
20088839Sandreas.hansson@arm.com        if len(args) == 1:
20098839Sandreas.hansson@arm.com            self.desc = args[0]
20108839Sandreas.hansson@arm.com            self.role = 'MASTER'
20118839Sandreas.hansson@arm.com            VectorPort.__init__(self, *args)
20128839Sandreas.hansson@arm.com        else:
20138839Sandreas.hansson@arm.com            raise TypeError, 'wrong number of arguments'
20148839Sandreas.hansson@arm.com
20158839Sandreas.hansson@arm.comclass VectorSlavePort(VectorPort):
20168839Sandreas.hansson@arm.com    # VectorSlavePort("description")
20178839Sandreas.hansson@arm.com    def __init__(self, *args):
20188839Sandreas.hansson@arm.com        if len(args) == 1:
20198839Sandreas.hansson@arm.com            self.desc = args[0]
20208839Sandreas.hansson@arm.com            self.role = 'SLAVE'
20218839Sandreas.hansson@arm.com            VectorPort.__init__(self, *args)
20228839Sandreas.hansson@arm.com        else:
20238839Sandreas.hansson@arm.com            raise TypeError, 'wrong number of arguments'
20243105Sstever@eecs.umich.edu
20253109Sstever@eecs.umich.edu# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
20263109Sstever@eecs.umich.edu# proxy objects (via set_param_desc()) so that proxy error messages
20273109Sstever@eecs.umich.edu# make sense.
20283109Sstever@eecs.umich.educlass PortParamDesc(object):
20293109Sstever@eecs.umich.edu    __metaclass__ = Singleton
20303109Sstever@eecs.umich.edu
20313109Sstever@eecs.umich.edu    ptype_str = 'Port'
20323109Sstever@eecs.umich.edu    ptype = Port
20333105Sstever@eecs.umich.edu
20346654Snate@binkert.orgbaseEnums = allEnums.copy()
20356654Snate@binkert.orgbaseParams = allParams.copy()
20366654Snate@binkert.org
20376654Snate@binkert.orgdef clear():
20386654Snate@binkert.org    global allEnums, allParams
20396654Snate@binkert.org
20406654Snate@binkert.org    allEnums = baseEnums.copy()
20416654Snate@binkert.org    allParams = baseParams.copy()
20426654Snate@binkert.org
20433101Sstever@eecs.umich.edu__all__ = ['Param', 'VectorParam',
20443101Sstever@eecs.umich.edu           'Enum', 'Bool', 'String', 'Float',
20453101Sstever@eecs.umich.edu           'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
20463101Sstever@eecs.umich.edu           'Int32', 'UInt32', 'Int64', 'UInt64',
20473101Sstever@eecs.umich.edu           'Counter', 'Addr', 'Tick', 'Percent',
20483101Sstever@eecs.umich.edu           'TcpPort', 'UdpPort', 'EthernetAddr',
20497777Sgblack@eecs.umich.edu           'IpAddress', 'IpNetmask', 'IpWithPort',
20503101Sstever@eecs.umich.edu           'MemorySize', 'MemorySize32',
205112253Sgabeblack@google.com           'Latency', 'Frequency', 'Clock', 'Voltage', 'Current', 'Energy',
20523101Sstever@eecs.umich.edu           'NetworkBandwidth', 'MemoryBandwidth',
20539232Sandreas.hansson@arm.com           'AddrRange',
20543101Sstever@eecs.umich.edu           'MaxAddr', 'MaxTick', 'AllMemory',
20553885Sbinkertn@umich.edu           'Time',
20563102Sstever@eecs.umich.edu           'NextEthernetAddr', 'NULL',
20578839Sandreas.hansson@arm.com           'MasterPort', 'SlavePort',
20588839Sandreas.hansson@arm.com           'VectorMasterPort', 'VectorSlavePort']
20596654Snate@binkert.org
20606654Snate@binkert.orgimport SimObject
2061