params.py revision 11498
15331Sgblack@eecs.umich.edu# Copyright (c) 2012-2014 ARM Limited
25331Sgblack@eecs.umich.edu# All rights reserved.
35331Sgblack@eecs.umich.edu#
45331Sgblack@eecs.umich.edu# The license below extends only to copyright in the software and shall
55331Sgblack@eecs.umich.edu# not be construed as granting a license to any other intellectual
65331Sgblack@eecs.umich.edu# property including but not limited to intellectual property relating
75331Sgblack@eecs.umich.edu# to a hardware implementation of the functionality of the software
85331Sgblack@eecs.umich.edu# licensed hereunder.  You may use the software subject to the license
95331Sgblack@eecs.umich.edu# terms below provided that you ensure that this notice is replicated
105331Sgblack@eecs.umich.edu# unmodified and in its entirety in all distributions of the software,
115331Sgblack@eecs.umich.edu# modified or unmodified, in source code or in binary form.
125331Sgblack@eecs.umich.edu#
135331Sgblack@eecs.umich.edu# Copyright (c) 2004-2006 The Regents of The University of Michigan
145331Sgblack@eecs.umich.edu# Copyright (c) 2010-2011 Advanced Micro Devices, Inc.
155331Sgblack@eecs.umich.edu# All rights reserved.
165331Sgblack@eecs.umich.edu#
175331Sgblack@eecs.umich.edu# Redistribution and use in source and binary forms, with or without
185331Sgblack@eecs.umich.edu# modification, are permitted provided that the following conditions are
195331Sgblack@eecs.umich.edu# met: redistributions of source code must retain the above copyright
205331Sgblack@eecs.umich.edu# notice, this list of conditions and the following disclaimer;
215331Sgblack@eecs.umich.edu# redistributions in binary form must reproduce the above copyright
225331Sgblack@eecs.umich.edu# notice, this list of conditions and the following disclaimer in the
235331Sgblack@eecs.umich.edu# documentation and/or other materials provided with the distribution;
245331Sgblack@eecs.umich.edu# neither the name of the copyright holders nor the names of its
255331Sgblack@eecs.umich.edu# contributors may be used to endorse or promote products derived from
265331Sgblack@eecs.umich.edu# this software without specific prior written permission.
275331Sgblack@eecs.umich.edu#
285331Sgblack@eecs.umich.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
295331Sgblack@eecs.umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
304276Sgblack@eecs.umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
314276Sgblack@eecs.umich.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
324276Sgblack@eecs.umich.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
334276Sgblack@eecs.umich.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
344276Sgblack@eecs.umich.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
354276Sgblack@eecs.umich.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
364276Sgblack@eecs.umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
374276Sgblack@eecs.umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
384276Sgblack@eecs.umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
394276Sgblack@eecs.umich.edu#
404276Sgblack@eecs.umich.edu# Authors: Steve Reinhardt
414276Sgblack@eecs.umich.edu#          Nathan Binkert
424276Sgblack@eecs.umich.edu#          Gabe Black
434276Sgblack@eecs.umich.edu#          Andreas Hansson
444276Sgblack@eecs.umich.edu
454276Sgblack@eecs.umich.edu#####################################################################
464276Sgblack@eecs.umich.edu#
474276Sgblack@eecs.umich.edu# Parameter description classes
484276Sgblack@eecs.umich.edu#
494276Sgblack@eecs.umich.edu# The _params dictionary in each class maps parameter names to either
504276Sgblack@eecs.umich.edu# a Param or a VectorParam object.  These objects contain the
514276Sgblack@eecs.umich.edu# parameter description string, the parameter type, and the default
524276Sgblack@eecs.umich.edu# value (if any).  The convert() method on these objects is used to
534276Sgblack@eecs.umich.edu# force whatever value is assigned to the parameter to the appropriate
544276Sgblack@eecs.umich.edu# type.
554276Sgblack@eecs.umich.edu#
564276Sgblack@eecs.umich.edu# Note that the default values are loaded into the class's attribute
574276Sgblack@eecs.umich.edu# space when the parameter dictionary is initialized (in
584276Sgblack@eecs.umich.edu# MetaSimObject._new_param()); after that point they aren't used.
594276Sgblack@eecs.umich.edu#
604276Sgblack@eecs.umich.edu#####################################################################
614276Sgblack@eecs.umich.edu
624276Sgblack@eecs.umich.eduimport copy
634276Sgblack@eecs.umich.eduimport datetime
644276Sgblack@eecs.umich.eduimport re
654276Sgblack@eecs.umich.eduimport sys
664276Sgblack@eecs.umich.eduimport time
674276Sgblack@eecs.umich.eduimport math
684276Sgblack@eecs.umich.edu
694276Sgblack@eecs.umich.eduimport proxy
704276Sgblack@eecs.umich.eduimport ticks
714276Sgblack@eecs.umich.edufrom util import *
724276Sgblack@eecs.umich.edu
734276Sgblack@eecs.umich.edudef isSimObject(*args, **kwargs):
744276Sgblack@eecs.umich.edu    return SimObject.isSimObject(*args, **kwargs)
754276Sgblack@eecs.umich.edu
764276Sgblack@eecs.umich.edudef isSimObjectSequence(*args, **kwargs):
774276Sgblack@eecs.umich.edu    return SimObject.isSimObjectSequence(*args, **kwargs)
784276Sgblack@eecs.umich.edu
794276Sgblack@eecs.umich.edudef isSimObjectClass(*args, **kwargs):
804276Sgblack@eecs.umich.edu    return SimObject.isSimObjectClass(*args, **kwargs)
814276Sgblack@eecs.umich.edu
824276Sgblack@eecs.umich.eduallParams = {}
834276Sgblack@eecs.umich.edu
844276Sgblack@eecs.umich.educlass MetaParamValue(type):
854276Sgblack@eecs.umich.edu    def __new__(mcls, name, bases, dct):
864276Sgblack@eecs.umich.edu        cls = super(MetaParamValue, mcls).__new__(mcls, name, bases, dct)
874276Sgblack@eecs.umich.edu        assert name not in allParams
884276Sgblack@eecs.umich.edu        allParams[name] = cls
894711Sgblack@eecs.umich.edu        return cls
904276Sgblack@eecs.umich.edu
914276Sgblack@eecs.umich.edu
925238Sgblack@eecs.umich.edu# Dummy base class to identify types that are legitimate for SimObject
935238Sgblack@eecs.umich.edu# parameters.
945238Sgblack@eecs.umich.educlass ParamValue(object):
955238Sgblack@eecs.umich.edu    __metaclass__ = MetaParamValue
965937Sgblack@eecs.umich.edu    cmd_line_settable = False
975902Sgblack@eecs.umich.edu
985238Sgblack@eecs.umich.edu    # Generate the code needed as a prerequisite for declaring a C++
995238Sgblack@eecs.umich.edu    # object of this type.  Typically generates one or more #include
1005238Sgblack@eecs.umich.edu    # statements.  Used when declaring parameters of this type.
1015238Sgblack@eecs.umich.edu    @classmethod
1025238Sgblack@eecs.umich.edu    def cxx_predecls(cls, code):
1035238Sgblack@eecs.umich.edu        pass
1045238Sgblack@eecs.umich.edu
1055238Sgblack@eecs.umich.edu    # Generate the code needed as a prerequisite for including a
1065238Sgblack@eecs.umich.edu    # reference to a C++ object of this type in a SWIG .i file.
1075238Sgblack@eecs.umich.edu    # Typically generates one or more %import or %include statements.
1085238Sgblack@eecs.umich.edu    @classmethod
1095238Sgblack@eecs.umich.edu    def swig_predecls(cls, code):
1105238Sgblack@eecs.umich.edu        pass
1115238Sgblack@eecs.umich.edu
1125238Sgblack@eecs.umich.edu    # default for printing to .ini file is regular string conversion.
1135238Sgblack@eecs.umich.edu    # will be overridden in some cases
1145238Sgblack@eecs.umich.edu    def ini_str(self):
1155238Sgblack@eecs.umich.edu        return str(self)
1165238Sgblack@eecs.umich.edu
1175238Sgblack@eecs.umich.edu    # default for printing to .json file is regular string conversion.
1185238Sgblack@eecs.umich.edu    # will be overridden in some cases, mostly to use native Python
1195238Sgblack@eecs.umich.edu    # types where there are similar JSON types
1205238Sgblack@eecs.umich.edu    def config_value(self):
1215238Sgblack@eecs.umich.edu        return str(self)
1225238Sgblack@eecs.umich.edu
1235238Sgblack@eecs.umich.edu    # Prerequisites for .ini parsing with cxx_ini_parse
1245238Sgblack@eecs.umich.edu    @classmethod
1255238Sgblack@eecs.umich.edu    def cxx_ini_predecls(cls, code):
1265238Sgblack@eecs.umich.edu        pass
1275238Sgblack@eecs.umich.edu
1286055Sgblack@eecs.umich.edu    # parse a .ini file entry for this param from string expression
1296054Sgblack@eecs.umich.edu    # src into lvalue dest (of the param's C++ type)
1305238Sgblack@eecs.umich.edu    @classmethod
1315683Sgblack@eecs.umich.edu    def cxx_ini_parse(cls, code, src, dest, ret):
1325238Sgblack@eecs.umich.edu        code('// Unhandled param type: %s' % cls.__name__)
1335238Sgblack@eecs.umich.edu        code('%s false;' % ret)
1345238Sgblack@eecs.umich.edu
1355238Sgblack@eecs.umich.edu    # allows us to blithely call unproxy() on things without checking
1365238Sgblack@eecs.umich.edu    # if they're really proxies or not
1375238Sgblack@eecs.umich.edu    def unproxy(self, base):
1385238Sgblack@eecs.umich.edu        return self
1395238Sgblack@eecs.umich.edu
1405291Sgblack@eecs.umich.edu    # Produce a human readable version of the stored value
1415291Sgblack@eecs.umich.edu    def pretty_print(self, value):
1425291Sgblack@eecs.umich.edu        return str(value)
1435291Sgblack@eecs.umich.edu
1445291Sgblack@eecs.umich.edu# Regular parameter description.
1455291Sgblack@eecs.umich.educlass ParamDesc(object):
1465291Sgblack@eecs.umich.edu    def __init__(self, ptype_str, ptype, *args, **kwargs):
1475291Sgblack@eecs.umich.edu        self.ptype_str = ptype_str
1485291Sgblack@eecs.umich.edu        # remember ptype only if it is provided
1495292Sgblack@eecs.umich.edu        if ptype != None:
1505292Sgblack@eecs.umich.edu            self.ptype = ptype
1515292Sgblack@eecs.umich.edu
1525292Sgblack@eecs.umich.edu        if args:
1535292Sgblack@eecs.umich.edu            if len(args) == 1:
1545292Sgblack@eecs.umich.edu                self.desc = args[0]
1555292Sgblack@eecs.umich.edu            elif len(args) == 2:
1565292Sgblack@eecs.umich.edu                self.default = args[0]
1575292Sgblack@eecs.umich.edu                self.desc = args[1]
1586055Sgblack@eecs.umich.edu            else:
1596054Sgblack@eecs.umich.edu                raise TypeError, 'too many arguments'
1605359Sgblack@eecs.umich.edu
1615238Sgblack@eecs.umich.edu        if kwargs.has_key('desc'):
1625238Sgblack@eecs.umich.edu            assert(not hasattr(self, 'desc'))
1635238Sgblack@eecs.umich.edu            self.desc = kwargs['desc']
1644276Sgblack@eecs.umich.edu            del kwargs['desc']
1654276Sgblack@eecs.umich.edu
1665789Sgblack@eecs.umich.edu        if kwargs.has_key('default'):
1675789Sgblack@eecs.umich.edu            assert(not hasattr(self, 'default'))
1685789Sgblack@eecs.umich.edu            self.default = kwargs['default']
1695789Sgblack@eecs.umich.edu            del kwargs['default']
1705789Sgblack@eecs.umich.edu
1715789Sgblack@eecs.umich.edu        if kwargs:
1725789Sgblack@eecs.umich.edu            raise TypeError, 'extra unknown kwargs %s' % kwargs
1735789Sgblack@eecs.umich.edu
1745789Sgblack@eecs.umich.edu        if not hasattr(self, 'desc'):
1755789Sgblack@eecs.umich.edu            raise TypeError, 'desc attribute missing'
1765789Sgblack@eecs.umich.edu
1775789Sgblack@eecs.umich.edu    def __getattr__(self, attr):
1785789Sgblack@eecs.umich.edu        if attr == 'ptype':
1795789Sgblack@eecs.umich.edu            ptype = SimObject.allClasses[self.ptype_str]
1805789Sgblack@eecs.umich.edu            assert isSimObjectClass(ptype)
1815789Sgblack@eecs.umich.edu            self.ptype = ptype
1825789Sgblack@eecs.umich.edu            return ptype
1835789Sgblack@eecs.umich.edu
1845789Sgblack@eecs.umich.edu        raise AttributeError, "'%s' object has no attribute '%s'" % \
1855789Sgblack@eecs.umich.edu              (type(self).__name__, attr)
1865789Sgblack@eecs.umich.edu
1875789Sgblack@eecs.umich.edu    def example_str(self):
1885789Sgblack@eecs.umich.edu        if hasattr(self.ptype, "ex_str"):
1895789Sgblack@eecs.umich.edu            return self.ptype.ex_str
1905789Sgblack@eecs.umich.edu        else:
1915789Sgblack@eecs.umich.edu            return self.ptype_str
1925789Sgblack@eecs.umich.edu
1935789Sgblack@eecs.umich.edu    # Is the param available to be exposed on the command line
1945789Sgblack@eecs.umich.edu    def isCmdLineSettable(self):
1955789Sgblack@eecs.umich.edu        if hasattr(self.ptype, "cmd_line_settable"):
1965789Sgblack@eecs.umich.edu            return self.ptype.cmd_line_settable
1975789Sgblack@eecs.umich.edu        else:
1985789Sgblack@eecs.umich.edu            return False
1995789Sgblack@eecs.umich.edu
2005789Sgblack@eecs.umich.edu    def convert(self, value):
2015789Sgblack@eecs.umich.edu        if isinstance(value, proxy.BaseProxy):
2025789Sgblack@eecs.umich.edu            value.set_param_desc(self)
2035789Sgblack@eecs.umich.edu            return value
2045789Sgblack@eecs.umich.edu        if not hasattr(self, 'ptype') and isNullPointer(value):
2055789Sgblack@eecs.umich.edu            # deferred evaluation of SimObject; continue to defer if
2065789Sgblack@eecs.umich.edu            # we're just assigning a null pointer
2075789Sgblack@eecs.umich.edu            return value
2085789Sgblack@eecs.umich.edu        if isinstance(value, self.ptype):
2095789Sgblack@eecs.umich.edu            return value
2105789Sgblack@eecs.umich.edu        if isNullPointer(value) and isSimObjectClass(self.ptype):
2115789Sgblack@eecs.umich.edu            return value
2125789Sgblack@eecs.umich.edu        return self.ptype(value)
2135789Sgblack@eecs.umich.edu
2145789Sgblack@eecs.umich.edu    def pretty_print(self, value):
2155789Sgblack@eecs.umich.edu        if isinstance(value, proxy.BaseProxy):
2165789Sgblack@eecs.umich.edu           return str(value)
2175789Sgblack@eecs.umich.edu        if isNullPointer(value):
2185789Sgblack@eecs.umich.edu           return NULL
2195789Sgblack@eecs.umich.edu        return self.ptype(value).pretty_print(value)
2205789Sgblack@eecs.umich.edu
2215789Sgblack@eecs.umich.edu    def cxx_predecls(self, code):
2225789Sgblack@eecs.umich.edu        code('#include <cstddef>')
2235789Sgblack@eecs.umich.edu        self.ptype.cxx_predecls(code)
2245789Sgblack@eecs.umich.edu
2255789Sgblack@eecs.umich.edu    def swig_predecls(self, code):
2265789Sgblack@eecs.umich.edu        self.ptype.swig_predecls(code)
2275789Sgblack@eecs.umich.edu
2285789Sgblack@eecs.umich.edu    def cxx_decl(self, code):
2295789Sgblack@eecs.umich.edu        code('${{self.ptype.cxx_type}} ${{self.name}};')
2305789Sgblack@eecs.umich.edu
2315789Sgblack@eecs.umich.edu# Vector-valued parameter description.  Just like ParamDesc, except
2325789Sgblack@eecs.umich.edu# that the value is a vector (list) of the specified type instead of a
2335789Sgblack@eecs.umich.edu# single value.
2345789Sgblack@eecs.umich.edu
2355789Sgblack@eecs.umich.educlass VectorParamValue(list):
2365789Sgblack@eecs.umich.edu    __metaclass__ = MetaParamValue
2375789Sgblack@eecs.umich.edu    def __setattr__(self, attr, value):
2385789Sgblack@eecs.umich.edu        raise AttributeError, \
2395789Sgblack@eecs.umich.edu              "Not allowed to set %s on '%s'" % (attr, type(self).__name__)
2405789Sgblack@eecs.umich.edu
2415789Sgblack@eecs.umich.edu    def config_value(self):
2425789Sgblack@eecs.umich.edu        return [v.config_value() for v in self]
2435789Sgblack@eecs.umich.edu
2445789Sgblack@eecs.umich.edu    def ini_str(self):
2455789Sgblack@eecs.umich.edu        return ' '.join([v.ini_str() for v in self])
2465789Sgblack@eecs.umich.edu
2475789Sgblack@eecs.umich.edu    def getValue(self):
2485789Sgblack@eecs.umich.edu        return [ v.getValue() for v in self ]
2495789Sgblack@eecs.umich.edu
2505789Sgblack@eecs.umich.edu    def unproxy(self, base):
2515789Sgblack@eecs.umich.edu        if len(self) == 1 and isinstance(self[0], proxy.AllProxy):
2525789Sgblack@eecs.umich.edu            return self[0].unproxy(base)
2535789Sgblack@eecs.umich.edu        else:
2545789Sgblack@eecs.umich.edu             return [v.unproxy(base) for v in self]
2555789Sgblack@eecs.umich.edu
2564712Sgblack@eecs.umich.educlass SimObjectVector(VectorParamValue):
2575907Sgblack@eecs.umich.edu    # support clone operation
2585907Sgblack@eecs.umich.edu    def __call__(self, **kwargs):
2595907Sgblack@eecs.umich.edu        return SimObjectVector([v(**kwargs) for v in self])
2605907Sgblack@eecs.umich.edu
2615907Sgblack@eecs.umich.edu    def clear_parent(self, old_parent):
2625907Sgblack@eecs.umich.edu        for v in self:
2635907Sgblack@eecs.umich.edu            v.clear_parent(old_parent)
2644712Sgblack@eecs.umich.edu
2655659Sgblack@eecs.umich.edu    def set_parent(self, parent, name):
2664712Sgblack@eecs.umich.edu        if len(self) == 1:
2675933Sgblack@eecs.umich.edu            self[0].set_parent(parent, name)
2685908Sgblack@eecs.umich.edu        else:
2695908Sgblack@eecs.umich.edu            width = int(math.ceil(math.log(len(self))/math.log(10)))
2705908Sgblack@eecs.umich.edu            for i,v in enumerate(self):
2715908Sgblack@eecs.umich.edu                v.set_parent(parent, "%s%0*d" % (name, width, i))
2725908Sgblack@eecs.umich.edu
2735908Sgblack@eecs.umich.edu    def has_parent(self):
2745908Sgblack@eecs.umich.edu        return reduce(lambda x,y: x and y, [v.has_parent() for v in self])
2755908Sgblack@eecs.umich.edu
2765908Sgblack@eecs.umich.edu    # return 'cpu0 cpu1' etc. for print_ini()
2774276Sgblack@eecs.umich.edu    def get_name(self):
2784276Sgblack@eecs.umich.edu        return ' '.join([v._name for v in self])
2794712Sgblack@eecs.umich.edu
2804712Sgblack@eecs.umich.edu    # By iterating through the constituent members of the vector here
2814730Sgblack@eecs.umich.edu    # we can nicely handle iterating over all a SimObject's children
2824760Sgblack@eecs.umich.edu    # without having to provide lots of special functions on
2834730Sgblack@eecs.umich.edu    # SimObjectVector directly.
2845920Sgblack@eecs.umich.edu    def descendants(self):
2855422Sgblack@eecs.umich.edu        for v in self:
2865422Sgblack@eecs.umich.edu            for obj in v.descendants():
2874276Sgblack@eecs.umich.edu                yield obj
2886576Sgblack@eecs.umich.edu
2896576Sgblack@eecs.umich.edu    def get_config_as_dict(self):
2906576Sgblack@eecs.umich.edu        a = []
2916576Sgblack@eecs.umich.edu        for v in self:
2926576Sgblack@eecs.umich.edu            a.append(v.get_config_as_dict())
2936576Sgblack@eecs.umich.edu        return a
2946576Sgblack@eecs.umich.edu
2956576Sgblack@eecs.umich.edu    # If we are replacing an item in the vector, make sure to set the
2966576Sgblack@eecs.umich.edu    # parent reference of the new SimObject to be the same as the parent
2976576Sgblack@eecs.umich.edu    # of the SimObject being replaced. Useful to have if we created
2986576Sgblack@eecs.umich.edu    # a SimObjectVector of temporary objects that will be modified later in
2996576Sgblack@eecs.umich.edu    # configuration scripts.
3006576Sgblack@eecs.umich.edu    def __setitem__(self, key, value):
3016576Sgblack@eecs.umich.edu        val = self[key]
3026576Sgblack@eecs.umich.edu        if value.has_parent():
3036576Sgblack@eecs.umich.edu            warn("SimObject %s already has a parent" % value.get_name() +\
3046576Sgblack@eecs.umich.edu                 " that is being overwritten by a SimObjectVector")
3056576Sgblack@eecs.umich.edu        value.set_parent(val.get_parent(), val._name)
3065020Sgblack@eecs.umich.edu        super(SimObjectVector, self).__setitem__(key, value)
3076576Sgblack@eecs.umich.edu
3086576Sgblack@eecs.umich.edu    # Enumerate the params of each member of the SimObject vector. Creates
3096600Sgblack@eecs.umich.edu    # strings that will allow indexing into the vector by the python code and
3106600Sgblack@eecs.umich.edu    # allow it to be specified on the command line.
3116576Sgblack@eecs.umich.edu    def enumerateParams(self, flags_dict = {},
3126576Sgblack@eecs.umich.edu                        cmd_line_str = "",
3136576Sgblack@eecs.umich.edu                        access_str = ""):
3145020Sgblack@eecs.umich.edu        if hasattr(self, "_paramEnumed"):
3156576Sgblack@eecs.umich.edu            print "Cycle detected enumerating params at %s?!" % (cmd_line_str)
3166576Sgblack@eecs.umich.edu        else:
3176576Sgblack@eecs.umich.edu            x = 0
3186576Sgblack@eecs.umich.edu            for vals in self:
3196576Sgblack@eecs.umich.edu                # Each entry in the SimObjectVector should be an
3206576Sgblack@eecs.umich.edu                # instance of a SimObject
3216576Sgblack@eecs.umich.edu                flags_dict = vals.enumerateParams(flags_dict,
3226576Sgblack@eecs.umich.edu                                                  cmd_line_str + "%d." % x,
3236576Sgblack@eecs.umich.edu                                                  access_str + "[%d]." % x)
3246576Sgblack@eecs.umich.edu                x = x + 1
3256576Sgblack@eecs.umich.edu
3266576Sgblack@eecs.umich.edu        return flags_dict
3276576Sgblack@eecs.umich.edu
3286576Sgblack@eecs.umich.educlass VectorParamDesc(ParamDesc):
3296576Sgblack@eecs.umich.edu    # Convert assigned value to appropriate type.  If the RHS is not a
3306576Sgblack@eecs.umich.edu    # list or tuple, it generates a single-element list.
3316576Sgblack@eecs.umich.edu    def convert(self, value):
3326576Sgblack@eecs.umich.edu        if isinstance(value, (list, tuple)):
3336576Sgblack@eecs.umich.edu            # list: coerce each element into new list
3344760Sgblack@eecs.umich.edu            tmp_list = [ ParamDesc.convert(self, v) for v in value ]
3356576Sgblack@eecs.umich.edu        elif isinstance(value, str):
3366576Sgblack@eecs.umich.edu            # If input is a csv string
3376576Sgblack@eecs.umich.edu            tmp_list = [ ParamDesc.convert(self, v) \
3386576Sgblack@eecs.umich.edu                         for v in value.strip('[').strip(']').split(',') ]
3396576Sgblack@eecs.umich.edu        else:
3406576Sgblack@eecs.umich.edu            # singleton: coerce to a single-element list
3416576Sgblack@eecs.umich.edu            tmp_list = [ ParamDesc.convert(self, value) ]
3426576Sgblack@eecs.umich.edu
3436576Sgblack@eecs.umich.edu        if isSimObjectSequence(tmp_list):
3446576Sgblack@eecs.umich.edu            return SimObjectVector(tmp_list)
3456576Sgblack@eecs.umich.edu        else:
3466576Sgblack@eecs.umich.edu            return VectorParamValue(tmp_list)
3476576Sgblack@eecs.umich.edu
3486576Sgblack@eecs.umich.edu    # Produce a human readable example string that describes
3496576Sgblack@eecs.umich.edu    # how to set this vector parameter in the absence of a default
3506576Sgblack@eecs.umich.edu    # value.
3514760Sgblack@eecs.umich.edu    def example_str(self):
3526576Sgblack@eecs.umich.edu        s = super(VectorParamDesc, self).example_str()
3536576Sgblack@eecs.umich.edu        help_str = "[" + s + "," + s + ", ...]"
3546576Sgblack@eecs.umich.edu        return help_str
3556576Sgblack@eecs.umich.edu
3566576Sgblack@eecs.umich.edu    # Produce a human readable representation of the value of this vector param.
3576576Sgblack@eecs.umich.edu    def pretty_print(self, value):
3586576Sgblack@eecs.umich.edu        if isinstance(value, (list, tuple)):
3596576Sgblack@eecs.umich.edu            tmp_list = [ ParamDesc.pretty_print(self, v) for v in value ]
3606576Sgblack@eecs.umich.edu        elif isinstance(value, str):
3616576Sgblack@eecs.umich.edu            tmp_list = [ ParamDesc.pretty_print(self, v) for v in value.split(',') ]
3626576Sgblack@eecs.umich.edu        else:
3636576Sgblack@eecs.umich.edu            tmp_list = [ ParamDesc.pretty_print(self, value) ]
3646576Sgblack@eecs.umich.edu
3656576Sgblack@eecs.umich.edu        return tmp_list
3666576Sgblack@eecs.umich.edu
3676576Sgblack@eecs.umich.edu    # This is a helper function for the new config system
3686576Sgblack@eecs.umich.edu    def __call__(self, value):
3694760Sgblack@eecs.umich.edu        if isinstance(value, (list, tuple)):
3704276Sgblack@eecs.umich.edu            # list: coerce each element into new list
3715020Sgblack@eecs.umich.edu            tmp_list = [ ParamDesc.convert(self, v) for v in value ]
3725020Sgblack@eecs.umich.edu        elif isinstance(value, str):
3735020Sgblack@eecs.umich.edu            # If input is a csv string
3745031Sgblack@eecs.umich.edu            tmp_list = [ ParamDesc.convert(self, v) \
3755031Sgblack@eecs.umich.edu                         for v in value.strip('[').strip(']').split(',') ]
3765031Sgblack@eecs.umich.edu        else:
3775031Sgblack@eecs.umich.edu            # singleton: coerce to a single-element list
3786563Sgblack@eecs.umich.edu            tmp_list = [ ParamDesc.convert(self, value) ]
3795020Sgblack@eecs.umich.edu
3806606Sgblack@eecs.umich.edu        return VectorParamValue(tmp_list)
3816606Sgblack@eecs.umich.edu
3826602Sgblack@eecs.umich.edu    def swig_module_name(self):
3836602Sgblack@eecs.umich.edu        return "%s_vector" % self.ptype_str
3845020Sgblack@eecs.umich.edu
3855020Sgblack@eecs.umich.edu    def swig_predecls(self, code):
3865020Sgblack@eecs.umich.edu        code('%import "${{self.swig_module_name()}}.i"')
3876563Sgblack@eecs.umich.edu
3886606Sgblack@eecs.umich.edu    def swig_decl(self, code):
3896606Sgblack@eecs.umich.edu        code('%module(package="m5.internal") ${{self.swig_module_name()}}')
3905020Sgblack@eecs.umich.edu        code('%{')
3915020Sgblack@eecs.umich.edu        self.ptype.cxx_predecls(code)
3925020Sgblack@eecs.umich.edu        code('%}')
3935020Sgblack@eecs.umich.edu        code()
3946564Sgblack@eecs.umich.edu        # Make sure the SWIGPY_SLICE_ARG is defined through this inclusion
3956564Sgblack@eecs.umich.edu        code('%include "std_container.i"')
3966563Sgblack@eecs.umich.edu        code()
3975020Sgblack@eecs.umich.edu        self.ptype.swig_predecls(code)
3986606Sgblack@eecs.umich.edu        code()
3996606Sgblack@eecs.umich.edu        code('%include "std_vector.i"')
4005058Sgblack@eecs.umich.edu        code()
4016602Sgblack@eecs.umich.edu
4025020Sgblack@eecs.umich.edu        ptype = self.ptype_str
4035020Sgblack@eecs.umich.edu        cxx_type = self.ptype.cxx_type
4045020Sgblack@eecs.umich.edu
4055046Sgblack@eecs.umich.edu        code('%template(vector_$ptype) std::vector< $cxx_type >;')
4065046Sgblack@eecs.umich.edu
4075046Sgblack@eecs.umich.edu    def cxx_predecls(self, code):
4085046Sgblack@eecs.umich.edu        code('#include <vector>')
4096606Sgblack@eecs.umich.edu        self.ptype.cxx_predecls(code)
4105020Sgblack@eecs.umich.edu
4115020Sgblack@eecs.umich.edu    def cxx_decl(self, code):
4125020Sgblack@eecs.umich.edu        code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};')
4134276Sgblack@eecs.umich.edu
4144276Sgblack@eecs.umich.educlass ParamFactory(object):
4155149Sgblack@eecs.umich.edu    def __init__(self, param_desc_class, ptype_str = None):
4165409Sgblack@eecs.umich.edu        self.param_desc_class = param_desc_class
4175149Sgblack@eecs.umich.edu        self.ptype_str = ptype_str
4184712Sgblack@eecs.umich.edu
4195972Sgblack@eecs.umich.edu    def __getattr__(self, attr):
4204712Sgblack@eecs.umich.edu        if self.ptype_str:
4215972Sgblack@eecs.umich.edu            attr = self.ptype_str + '.' + attr
4225972Sgblack@eecs.umich.edu        return ParamFactory(self.param_desc_class, attr)
4235972Sgblack@eecs.umich.edu
4244712Sgblack@eecs.umich.edu    # E.g., Param.Int(5, "number of widgets")
4254730Sgblack@eecs.umich.edu    def __call__(self, *args, **kwargs):
4264712Sgblack@eecs.umich.edu        ptype = None
4274276Sgblack@eecs.umich.edu        try:
4284276Sgblack@eecs.umich.edu            ptype = allParams[self.ptype_str]
4294712Sgblack@eecs.umich.edu        except KeyError:
4304712Sgblack@eecs.umich.edu            # if name isn't defined yet, assume it's a SimObject, and
4314712Sgblack@eecs.umich.edu            # try to resolve it later
4324712Sgblack@eecs.umich.edu            pass
4334712Sgblack@eecs.umich.edu        return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs)
4344712Sgblack@eecs.umich.edu
4354712Sgblack@eecs.umich.eduParam = ParamFactory(ParamDesc)
4364712Sgblack@eecs.umich.eduVectorParam = ParamFactory(VectorParamDesc)
4374276Sgblack@eecs.umich.edu
4384760Sgblack@eecs.umich.edu#####################################################################
4394760Sgblack@eecs.umich.edu#
4404760Sgblack@eecs.umich.edu# Parameter Types
4414760Sgblack@eecs.umich.edu#
4424760Sgblack@eecs.umich.edu# Though native Python types could be used to specify parameter types
4434760Sgblack@eecs.umich.edu# (the 'ptype' field of the Param and VectorParam classes), it's more
4444760Sgblack@eecs.umich.edu# flexible to define our own set of types.  This gives us more control
4454760Sgblack@eecs.umich.edu# over how Python expressions are converted to values (via the
4464760Sgblack@eecs.umich.edu# __init__() constructor) and how these values are printed out (via
4474760Sgblack@eecs.umich.edu# the __str__() conversion method).
4484760Sgblack@eecs.umich.edu#
4494760Sgblack@eecs.umich.edu#####################################################################
4504760Sgblack@eecs.umich.edu
4514760Sgblack@eecs.umich.edu# String-valued parameter.  Just mixin the ParamValue class with the
4524760Sgblack@eecs.umich.edu# built-in str class.
4534760Sgblack@eecs.umich.educlass String(ParamValue,str):
4544760Sgblack@eecs.umich.edu    cxx_type = 'std::string'
4554760Sgblack@eecs.umich.edu    cmd_line_settable = True
4564760Sgblack@eecs.umich.edu
4574760Sgblack@eecs.umich.edu    @classmethod
4584760Sgblack@eecs.umich.edu    def cxx_predecls(self, code):
4596576Sgblack@eecs.umich.edu        code('#include <string>')
4606576Sgblack@eecs.umich.edu
4616576Sgblack@eecs.umich.edu    @classmethod
4626593Sgblack@eecs.umich.edu    def swig_predecls(cls, code):
4636576Sgblack@eecs.umich.edu        code('%include "std_string.i"')
4646576Sgblack@eecs.umich.edu
4656576Sgblack@eecs.umich.edu    def __call__(self, value):
4666576Sgblack@eecs.umich.edu        self = value
4676576Sgblack@eecs.umich.edu        return value
4686576Sgblack@eecs.umich.edu
4696576Sgblack@eecs.umich.edu    @classmethod
4706576Sgblack@eecs.umich.edu    def cxx_ini_parse(self, code, src, dest, ret):
4716576Sgblack@eecs.umich.edu        code('%s = %s;' % (dest, src))
4726576Sgblack@eecs.umich.edu        code('%s true;' % ret)
4736576Sgblack@eecs.umich.edu
4746576Sgblack@eecs.umich.edu    def getValue(self):
4756576Sgblack@eecs.umich.edu        return self
4766576Sgblack@eecs.umich.edu
4776576Sgblack@eecs.umich.edu# superclass for "numeric" parameter values, to emulate math
4786576Sgblack@eecs.umich.edu# operations in a type-safe way.  e.g., a Latency times an int returns
4796576Sgblack@eecs.umich.edu# a new Latency object.
4806593Sgblack@eecs.umich.educlass NumericParamValue(ParamValue):
4816576Sgblack@eecs.umich.edu    def __str__(self):
4826576Sgblack@eecs.umich.edu        return str(self.value)
4836576Sgblack@eecs.umich.edu
4846576Sgblack@eecs.umich.edu    def __float__(self):
4856576Sgblack@eecs.umich.edu        return float(self.value)
4866576Sgblack@eecs.umich.edu
4876576Sgblack@eecs.umich.edu    def __long__(self):
4886576Sgblack@eecs.umich.edu        return long(self.value)
4896576Sgblack@eecs.umich.edu
4905059Sgblack@eecs.umich.edu    def __int__(self):
4915059Sgblack@eecs.umich.edu        return int(self.value)
4926576Sgblack@eecs.umich.edu
4935059Sgblack@eecs.umich.edu    # hook for bounds checking
4945059Sgblack@eecs.umich.edu    def _check(self):
4955059Sgblack@eecs.umich.edu        return
4965020Sgblack@eecs.umich.edu
4976576Sgblack@eecs.umich.edu    def __mul__(self, other):
4986576Sgblack@eecs.umich.edu        newobj = self.__class__(self)
4996576Sgblack@eecs.umich.edu        newobj.value *= other
5006576Sgblack@eecs.umich.edu        newobj._check()
5016576Sgblack@eecs.umich.edu        return newobj
5026576Sgblack@eecs.umich.edu
5036576Sgblack@eecs.umich.edu    __rmul__ = __mul__
5046576Sgblack@eecs.umich.edu
5056576Sgblack@eecs.umich.edu    def __div__(self, other):
5066576Sgblack@eecs.umich.edu        newobj = self.__class__(self)
5076576Sgblack@eecs.umich.edu        newobj.value /= other
5086576Sgblack@eecs.umich.edu        newobj._check()
5096576Sgblack@eecs.umich.edu        return newobj
5106576Sgblack@eecs.umich.edu
5116576Sgblack@eecs.umich.edu    def __sub__(self, other):
5126576Sgblack@eecs.umich.edu        newobj = self.__class__(self)
5136576Sgblack@eecs.umich.edu        newobj.value -= other
5146606Sgblack@eecs.umich.edu        newobj._check()
5156576Sgblack@eecs.umich.edu        return newobj
5166576Sgblack@eecs.umich.edu
5176576Sgblack@eecs.umich.edu    def config_value(self):
5186576Sgblack@eecs.umich.edu        return self.value
5196576Sgblack@eecs.umich.edu
5206576Sgblack@eecs.umich.edu    @classmethod
5216576Sgblack@eecs.umich.edu    def cxx_ini_predecls(cls, code):
5226576Sgblack@eecs.umich.edu        # Assume that base/str.hh will be included anyway
5236576Sgblack@eecs.umich.edu        # code('#include "base/str.hh"')
5246576Sgblack@eecs.umich.edu        pass
5256606Sgblack@eecs.umich.edu
5266576Sgblack@eecs.umich.edu    # The default for parsing PODs from an .ini entry is to extract from an
5276576Sgblack@eecs.umich.edu    # istringstream and let overloading choose the right type according to
5286576Sgblack@eecs.umich.edu    # the dest type.
5296576Sgblack@eecs.umich.edu    @classmethod
5306576Sgblack@eecs.umich.edu    def cxx_ini_parse(self, code, src, dest, ret):
5316576Sgblack@eecs.umich.edu        code('%s to_number(%s, %s);' % (ret, src, dest))
5326576Sgblack@eecs.umich.edu
5336576Sgblack@eecs.umich.edu# Metaclass for bounds-checked integer parameters.  See CheckedInt.
5346576Sgblack@eecs.umich.educlass CheckedIntType(MetaParamValue):
5356576Sgblack@eecs.umich.edu    def __init__(cls, name, bases, dict):
5366576Sgblack@eecs.umich.edu        super(CheckedIntType, cls).__init__(name, bases, dict)
5376576Sgblack@eecs.umich.edu
5386576Sgblack@eecs.umich.edu        # CheckedInt is an abstract base class, so we actually don't
5396576Sgblack@eecs.umich.edu        # want to do any processing on it... the rest of this code is
5406576Sgblack@eecs.umich.edu        # just for classes that derive from CheckedInt.
5416576Sgblack@eecs.umich.edu        if name == 'CheckedInt':
5426576Sgblack@eecs.umich.edu            return
5435020Sgblack@eecs.umich.edu
5446576Sgblack@eecs.umich.edu        if not (hasattr(cls, 'min') and hasattr(cls, 'max')):
5456576Sgblack@eecs.umich.edu            if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')):
5466576Sgblack@eecs.umich.edu                panic("CheckedInt subclass %s must define either\n" \
5476576Sgblack@eecs.umich.edu                      "    'min' and 'max' or 'size' and 'unsigned'\n",
5486576Sgblack@eecs.umich.edu                      name);
5496576Sgblack@eecs.umich.edu            if cls.unsigned:
5506576Sgblack@eecs.umich.edu                cls.min = 0
5516576Sgblack@eecs.umich.edu                cls.max = 2 ** cls.size - 1
5526576Sgblack@eecs.umich.edu            else:
5536576Sgblack@eecs.umich.edu                cls.min = -(2 ** (cls.size - 1))
5546576Sgblack@eecs.umich.edu                cls.max = (2 ** (cls.size - 1)) - 1
5556576Sgblack@eecs.umich.edu
5566576Sgblack@eecs.umich.edu# Abstract superclass for bounds-checked integer parameters.  This
5576576Sgblack@eecs.umich.edu# class is subclassed to generate parameter classes with specific
5586576Sgblack@eecs.umich.edu# bounds.  Initialization of the min and max bounds is done in the
5596576Sgblack@eecs.umich.edu# metaclass CheckedIntType.__init__.
5606576Sgblack@eecs.umich.educlass CheckedInt(NumericParamValue):
5616576Sgblack@eecs.umich.edu    __metaclass__ = CheckedIntType
5626576Sgblack@eecs.umich.edu    cmd_line_settable = True
5636576Sgblack@eecs.umich.edu
5646576Sgblack@eecs.umich.edu    def _check(self):
5656576Sgblack@eecs.umich.edu        if not self.min <= self.value <= self.max:
5666576Sgblack@eecs.umich.edu            raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
5676576Sgblack@eecs.umich.edu                  (self.min, self.value, self.max)
5685020Sgblack@eecs.umich.edu
5696576Sgblack@eecs.umich.edu    def __init__(self, value):
5706576Sgblack@eecs.umich.edu        if isinstance(value, str):
5716576Sgblack@eecs.umich.edu            self.value = convert.toInteger(value)
5726576Sgblack@eecs.umich.edu        elif isinstance(value, (int, long, float, NumericParamValue)):
5736576Sgblack@eecs.umich.edu            self.value = long(value)
5746576Sgblack@eecs.umich.edu        else:
5756576Sgblack@eecs.umich.edu            raise TypeError, "Can't convert object of type %s to CheckedInt" \
5766576Sgblack@eecs.umich.edu                  % type(value).__name__
5776576Sgblack@eecs.umich.edu        self._check()
5786576Sgblack@eecs.umich.edu
5796576Sgblack@eecs.umich.edu    def __call__(self, value):
5806576Sgblack@eecs.umich.edu        self.__init__(value)
5816576Sgblack@eecs.umich.edu        return value
5826576Sgblack@eecs.umich.edu
5836576Sgblack@eecs.umich.edu    @classmethod
5846576Sgblack@eecs.umich.edu    def cxx_predecls(cls, code):
5856576Sgblack@eecs.umich.edu        # most derived types require this, so we just do it here once
5866576Sgblack@eecs.umich.edu        code('#include "base/types.hh"')
5876576Sgblack@eecs.umich.edu
5886576Sgblack@eecs.umich.edu    @classmethod
5896576Sgblack@eecs.umich.edu    def swig_predecls(cls, code):
5906576Sgblack@eecs.umich.edu        # most derived types require this, so we just do it here once
5916576Sgblack@eecs.umich.edu        code('%import "stdint.i"')
5926576Sgblack@eecs.umich.edu        code('%import "base/types.hh"')
5936576Sgblack@eecs.umich.edu
5946576Sgblack@eecs.umich.edu    def getValue(self):
5956576Sgblack@eecs.umich.edu        return long(self.value)
5966576Sgblack@eecs.umich.edu
5975020Sgblack@eecs.umich.educlass Int(CheckedInt):      cxx_type = 'int';      size = 32; unsigned = False
5986584Sgblack@eecs.umich.educlass Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True
5996584Sgblack@eecs.umich.edu
6006584Sgblack@eecs.umich.educlass Int8(CheckedInt):     cxx_type =   'int8_t'; size =  8; unsigned = False
6016597Sgblack@eecs.umich.educlass UInt8(CheckedInt):    cxx_type =  'uint8_t'; size =  8; unsigned = True
6026584Sgblack@eecs.umich.educlass Int16(CheckedInt):    cxx_type =  'int16_t'; size = 16; unsigned = False
6036584Sgblack@eecs.umich.educlass UInt16(CheckedInt):   cxx_type = 'uint16_t'; size = 16; unsigned = True
6046584Sgblack@eecs.umich.educlass Int32(CheckedInt):    cxx_type =  'int32_t'; size = 32; unsigned = False
6056584Sgblack@eecs.umich.educlass UInt32(CheckedInt):   cxx_type = 'uint32_t'; size = 32; unsigned = True
6066584Sgblack@eecs.umich.educlass Int64(CheckedInt):    cxx_type =  'int64_t'; size = 64; unsigned = False
6076584Sgblack@eecs.umich.educlass UInt64(CheckedInt):   cxx_type = 'uint64_t'; size = 64; unsigned = True
6086584Sgblack@eecs.umich.edu
6096584Sgblack@eecs.umich.educlass Counter(CheckedInt):  cxx_type = 'Counter';  size = 64; unsigned = True
6106584Sgblack@eecs.umich.educlass Tick(CheckedInt):     cxx_type = 'Tick';     size = 64; unsigned = True
6116584Sgblack@eecs.umich.educlass TcpPort(CheckedInt):  cxx_type = 'uint16_t'; size = 16; unsigned = True
6126584Sgblack@eecs.umich.educlass UdpPort(CheckedInt):  cxx_type = 'uint16_t'; size = 16; unsigned = True
6136584Sgblack@eecs.umich.edu
6146584Sgblack@eecs.umich.educlass Percent(CheckedInt):  cxx_type = 'int'; min = 0; max = 100
6156584Sgblack@eecs.umich.edu
6166584Sgblack@eecs.umich.educlass Cycles(CheckedInt):
6175238Sgblack@eecs.umich.edu    cxx_type = 'Cycles'
6186584Sgblack@eecs.umich.edu    size = 64
6196584Sgblack@eecs.umich.edu    unsigned = True
6206584Sgblack@eecs.umich.edu
6216584Sgblack@eecs.umich.edu    def getValue(self):
6226584Sgblack@eecs.umich.edu        from m5.internal.core import Cycles
6236584Sgblack@eecs.umich.edu        return Cycles(self.value)
6246584Sgblack@eecs.umich.edu
6256584Sgblack@eecs.umich.edu    @classmethod
6266584Sgblack@eecs.umich.edu    def cxx_ini_predecls(cls, code):
6276584Sgblack@eecs.umich.edu        # Assume that base/str.hh will be included anyway
6286584Sgblack@eecs.umich.edu        # code('#include "base/str.hh"')
6296584Sgblack@eecs.umich.edu        pass
6306584Sgblack@eecs.umich.edu
6316584Sgblack@eecs.umich.edu    @classmethod
6326584Sgblack@eecs.umich.edu    def cxx_ini_parse(cls, code, src, dest, ret):
6335238Sgblack@eecs.umich.edu        code('uint64_t _temp;')
6346584Sgblack@eecs.umich.edu        code('bool _ret = to_number(%s, _temp);' % src)
6356584Sgblack@eecs.umich.edu        code('if (_ret)')
6366584Sgblack@eecs.umich.edu        code('    %s = Cycles(_temp);' % dest)
6376584Sgblack@eecs.umich.edu        code('%s _ret;' % ret)
6386584Sgblack@eecs.umich.edu
6396584Sgblack@eecs.umich.educlass Float(ParamValue, float):
6406584Sgblack@eecs.umich.edu    cxx_type = 'double'
6416584Sgblack@eecs.umich.edu    cmd_line_settable = True
6426584Sgblack@eecs.umich.edu
6436584Sgblack@eecs.umich.edu    def __init__(self, value):
6446584Sgblack@eecs.umich.edu        if isinstance(value, (int, long, float, NumericParamValue, Float, str)):
6456584Sgblack@eecs.umich.edu            self.value = float(value)
6466584Sgblack@eecs.umich.edu        else:
6476584Sgblack@eecs.umich.edu            raise TypeError, "Can't convert object of type %s to Float" \
6486584Sgblack@eecs.umich.edu                  % type(value).__name__
6496584Sgblack@eecs.umich.edu
6506584Sgblack@eecs.umich.edu    def __call__(self, value):
6516584Sgblack@eecs.umich.edu        self.__init__(value)
6526584Sgblack@eecs.umich.edu        return value
6535238Sgblack@eecs.umich.edu
6546584Sgblack@eecs.umich.edu    def getValue(self):
6556584Sgblack@eecs.umich.edu        return float(self.value)
6566584Sgblack@eecs.umich.edu
6576584Sgblack@eecs.umich.edu    def config_value(self):
6585238Sgblack@eecs.umich.edu        return self
6596584Sgblack@eecs.umich.edu
6606584Sgblack@eecs.umich.edu    @classmethod
6616597Sgblack@eecs.umich.edu    def cxx_ini_predecls(cls, code):
6626584Sgblack@eecs.umich.edu        code('#include <sstream>')
6636584Sgblack@eecs.umich.edu
6646584Sgblack@eecs.umich.edu    @classmethod
6656584Sgblack@eecs.umich.edu    def cxx_ini_parse(self, code, src, dest, ret):
6666597Sgblack@eecs.umich.edu        code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
6676584Sgblack@eecs.umich.edu
6686584Sgblack@eecs.umich.educlass MemorySize(CheckedInt):
6696584Sgblack@eecs.umich.edu    cxx_type = 'uint64_t'
6706584Sgblack@eecs.umich.edu    ex_str = '512MB'
6716584Sgblack@eecs.umich.edu    size = 64
6726584Sgblack@eecs.umich.edu    unsigned = True
6736584Sgblack@eecs.umich.edu    def __init__(self, value):
6746584Sgblack@eecs.umich.edu        if isinstance(value, MemorySize):
6756584Sgblack@eecs.umich.edu            self.value = value.value
6766584Sgblack@eecs.umich.edu        else:
6776584Sgblack@eecs.umich.edu            self.value = convert.toMemorySize(value)
6786584Sgblack@eecs.umich.edu        self._check()
6796584Sgblack@eecs.umich.edu
6806584Sgblack@eecs.umich.educlass MemorySize32(CheckedInt):
6816584Sgblack@eecs.umich.edu    cxx_type = 'uint32_t'
6825238Sgblack@eecs.umich.edu    ex_str = '512MB'
6836584Sgblack@eecs.umich.edu    size = 32
6846584Sgblack@eecs.umich.edu    unsigned = True
6856584Sgblack@eecs.umich.edu    def __init__(self, value):
6866584Sgblack@eecs.umich.edu        if isinstance(value, MemorySize):
6876584Sgblack@eecs.umich.edu            self.value = value.value
6886584Sgblack@eecs.umich.edu        else:
6896584Sgblack@eecs.umich.edu            self.value = convert.toMemorySize(value)
6906584Sgblack@eecs.umich.edu        self._check()
6916584Sgblack@eecs.umich.edu
6926584Sgblack@eecs.umich.educlass Addr(CheckedInt):
6936584Sgblack@eecs.umich.edu    cxx_type = 'Addr'
6946584Sgblack@eecs.umich.edu    size = 64
6956584Sgblack@eecs.umich.edu    unsigned = True
6966584Sgblack@eecs.umich.edu    def __init__(self, value):
6976584Sgblack@eecs.umich.edu        if isinstance(value, Addr):
6985238Sgblack@eecs.umich.edu            self.value = value.value
6996584Sgblack@eecs.umich.edu        else:
7006584Sgblack@eecs.umich.edu            try:
7016584Sgblack@eecs.umich.edu                # Often addresses are referred to with sizes. Ex: A device
7026584Sgblack@eecs.umich.edu                # base address is at "512MB".  Use toMemorySize() to convert
7036584Sgblack@eecs.umich.edu                # these into addresses. If the address is not specified with a
7046584Sgblack@eecs.umich.edu                # "size", an exception will occur and numeric translation will
7056584Sgblack@eecs.umich.edu                # proceed below.
7066584Sgblack@eecs.umich.edu                self.value = convert.toMemorySize(value)
7076584Sgblack@eecs.umich.edu            except (TypeError, ValueError):
7086584Sgblack@eecs.umich.edu                # Convert number to string and use long() to do automatic
7096584Sgblack@eecs.umich.edu                # base conversion (requires base=0 for auto-conversion)
7106584Sgblack@eecs.umich.edu                self.value = long(str(value), base=0)
7116584Sgblack@eecs.umich.edu
7126584Sgblack@eecs.umich.edu        self._check()
7136584Sgblack@eecs.umich.edu    def __add__(self, other):
7146584Sgblack@eecs.umich.edu        if isinstance(other, Addr):
7156584Sgblack@eecs.umich.edu            return self.value + other.value
7166584Sgblack@eecs.umich.edu        else:
7176584Sgblack@eecs.umich.edu            return self.value + other
7185238Sgblack@eecs.umich.edu    def pretty_print(self, value):
7196584Sgblack@eecs.umich.edu        try:
7206584Sgblack@eecs.umich.edu            val = convert.toMemorySize(value)
7216584Sgblack@eecs.umich.edu        except TypeError:
7226584Sgblack@eecs.umich.edu            val = long(value)
7235238Sgblack@eecs.umich.edu        return "0x%x" % long(val)
7246584Sgblack@eecs.umich.edu
7256584Sgblack@eecs.umich.educlass AddrRange(ParamValue):
7266597Sgblack@eecs.umich.edu    cxx_type = 'AddrRange'
7276584Sgblack@eecs.umich.edu
7285238Sgblack@eecs.umich.edu    def __init__(self, *args, **kwargs):
7296584Sgblack@eecs.umich.edu        # Disable interleaving and hashing by default
7305020Sgblack@eecs.umich.edu        self.intlvHighBit = 0
7316584Sgblack@eecs.umich.edu        self.xorHighBit = 0
7326584Sgblack@eecs.umich.edu        self.intlvBits = 0
7336584Sgblack@eecs.umich.edu        self.intlvMatch = 0
7346584Sgblack@eecs.umich.edu
7356584Sgblack@eecs.umich.edu        def handle_kwargs(self, kwargs):
7366584Sgblack@eecs.umich.edu            # An address range needs to have an upper limit, specified
7376584Sgblack@eecs.umich.edu            # either explicitly with an end, or as an offset using the
7386584Sgblack@eecs.umich.edu            # size keyword.
7396584Sgblack@eecs.umich.edu            if 'end' in kwargs:
7406584Sgblack@eecs.umich.edu                self.end = Addr(kwargs.pop('end'))
7416584Sgblack@eecs.umich.edu            elif 'size' in kwargs:
7426584Sgblack@eecs.umich.edu                self.end = self.start + Addr(kwargs.pop('size')) - 1
7436584Sgblack@eecs.umich.edu            else:
7446584Sgblack@eecs.umich.edu                raise TypeError, "Either end or size must be specified"
7456584Sgblack@eecs.umich.edu
7466584Sgblack@eecs.umich.edu            # Now on to the optional bit
7476584Sgblack@eecs.umich.edu            if 'intlvHighBit' in kwargs:
7486584Sgblack@eecs.umich.edu                self.intlvHighBit = int(kwargs.pop('intlvHighBit'))
7496584Sgblack@eecs.umich.edu            if 'xorHighBit' in kwargs:
7506584Sgblack@eecs.umich.edu                self.xorHighBit = int(kwargs.pop('xorHighBit'))
7516584Sgblack@eecs.umich.edu            if 'intlvBits' in kwargs:
7526584Sgblack@eecs.umich.edu                self.intlvBits = int(kwargs.pop('intlvBits'))
7536584Sgblack@eecs.umich.edu            if 'intlvMatch' in kwargs:
7546584Sgblack@eecs.umich.edu                self.intlvMatch = int(kwargs.pop('intlvMatch'))
7556584Sgblack@eecs.umich.edu
7566584Sgblack@eecs.umich.edu        if len(args) == 0:
7576584Sgblack@eecs.umich.edu            self.start = Addr(kwargs.pop('start'))
7586584Sgblack@eecs.umich.edu            handle_kwargs(self, kwargs)
7596584Sgblack@eecs.umich.edu
7606584Sgblack@eecs.umich.edu        elif len(args) == 1:
7615020Sgblack@eecs.umich.edu            if kwargs:
7624727Sgblack@eecs.umich.edu                self.start = Addr(args[0])
7634727Sgblack@eecs.umich.edu                handle_kwargs(self, kwargs)
7644727Sgblack@eecs.umich.edu            elif isinstance(args[0], (list, tuple)):
7654727Sgblack@eecs.umich.edu                self.start = Addr(args[0][0])
7664727Sgblack@eecs.umich.edu                self.end = Addr(args[0][1])
7674727Sgblack@eecs.umich.edu            else:
7684727Sgblack@eecs.umich.edu                self.start = Addr(0)
7694727Sgblack@eecs.umich.edu                self.end = Addr(args[0]) - 1
7704727Sgblack@eecs.umich.edu
7714727Sgblack@eecs.umich.edu        elif len(args) == 2:
7724727Sgblack@eecs.umich.edu            self.start = Addr(args[0])
7734727Sgblack@eecs.umich.edu            self.end = Addr(args[1])
7744727Sgblack@eecs.umich.edu        else:
7754727Sgblack@eecs.umich.edu            raise TypeError, "Too many arguments specified"
7764727Sgblack@eecs.umich.edu
7774727Sgblack@eecs.umich.edu        if kwargs:
7784727Sgblack@eecs.umich.edu            raise TypeError, "Too many keywords: %s" % kwargs.keys()
7794727Sgblack@eecs.umich.edu
7804727Sgblack@eecs.umich.edu    def __str__(self):
7814727Sgblack@eecs.umich.edu        return '%s:%s' % (self.start, self.end)
7824760Sgblack@eecs.umich.edu
7834760Sgblack@eecs.umich.edu    def size(self):
7844760Sgblack@eecs.umich.edu        # Divide the size by the size of the interleaving slice
7854760Sgblack@eecs.umich.edu        return (long(self.end) - long(self.start) + 1) >> self.intlvBits
7864760Sgblack@eecs.umich.edu
7874760Sgblack@eecs.umich.edu    @classmethod
7884760Sgblack@eecs.umich.edu    def cxx_predecls(cls, code):
7894760Sgblack@eecs.umich.edu        Addr.cxx_predecls(code)
7904760Sgblack@eecs.umich.edu        code('#include "base/addr_range.hh"')
7914760Sgblack@eecs.umich.edu
7924760Sgblack@eecs.umich.edu    @classmethod
7934760Sgblack@eecs.umich.edu    def swig_predecls(cls, code):
7944760Sgblack@eecs.umich.edu        Addr.swig_predecls(code)
7954760Sgblack@eecs.umich.edu
7964760Sgblack@eecs.umich.edu    @classmethod
7974760Sgblack@eecs.umich.edu    def cxx_ini_predecls(cls, code):
7984760Sgblack@eecs.umich.edu        code('#include <sstream>')
7994760Sgblack@eecs.umich.edu
8004760Sgblack@eecs.umich.edu    @classmethod
8014760Sgblack@eecs.umich.edu    def cxx_ini_parse(cls, code, src, dest, ret):
8024276Sgblack@eecs.umich.edu        code('uint64_t _start, _end;')
8034276Sgblack@eecs.umich.edu        code('char _sep;')
8044712Sgblack@eecs.umich.edu        code('std::istringstream _stream(${src});')
8054712Sgblack@eecs.umich.edu        code('_stream >> _start;')
8065659Sgblack@eecs.umich.edu        code('_stream.get(_sep);')
8075659Sgblack@eecs.umich.edu        code('_stream >> _end;')
8086052Sgblack@eecs.umich.edu        code('bool _ret = !_stream.fail() &&'
8095659Sgblack@eecs.umich.edu            '_stream.eof() && _sep == \':\';')
8105659Sgblack@eecs.umich.edu        code('if (_ret)')
8115659Sgblack@eecs.umich.edu        code('   ${dest} = AddrRange(_start, _end);')
8125659Sgblack@eecs.umich.edu        code('${ret} _ret;')
8135659Sgblack@eecs.umich.edu
8145240Sgblack@eecs.umich.edu    def getValue(self):
8156480Sgblack@eecs.umich.edu        # Go from the Python class to the wrapped C++ class generated
8166480Sgblack@eecs.umich.edu        # by swig
8174712Sgblack@eecs.umich.edu        from m5.internal.range import AddrRange
8184712Sgblack@eecs.umich.edu
8194276Sgblack@eecs.umich.edu        return AddrRange(long(self.start), long(self.end),
8204276Sgblack@eecs.umich.edu                         int(self.intlvHighBit), int(self.xorHighBit),
8214712Sgblack@eecs.umich.edu                         int(self.intlvBits), int(self.intlvMatch))
8224712Sgblack@eecs.umich.edu
8234712Sgblack@eecs.umich.edu# Boolean parameter type.  Python doesn't let you subclass bool, since
8245240Sgblack@eecs.umich.edu# it doesn't want to let you create multiple instances of True and
8255977Sgblack@eecs.umich.edu# False.  Thus this is a little more complicated than String.
8266481Sgblack@eecs.umich.educlass Bool(ParamValue):
8275238Sgblack@eecs.umich.edu    cxx_type = 'bool'
8285967Sgblack@eecs.umich.edu    cmd_line_settable = True
8295967Sgblack@eecs.umich.edu
8305967Sgblack@eecs.umich.edu    def __init__(self, value):
8316599Sgblack@eecs.umich.edu        try:
8326598Sgblack@eecs.umich.edu            self.value = convert.toBool(value)
8335967Sgblack@eecs.umich.edu        except TypeError:
8345967Sgblack@eecs.umich.edu            self.value = bool(value)
8355967Sgblack@eecs.umich.edu
8365923Sgblack@eecs.umich.edu    def __call__(self, value):
8375238Sgblack@eecs.umich.edu        self.__init__(value)
8385238Sgblack@eecs.umich.edu        return value
8395967Sgblack@eecs.umich.edu
8405967Sgblack@eecs.umich.edu    def getValue(self):
8415967Sgblack@eecs.umich.edu        return bool(self.value)
8425967Sgblack@eecs.umich.edu
8435967Sgblack@eecs.umich.edu    def __str__(self):
8445967Sgblack@eecs.umich.edu        return str(self.value)
8455967Sgblack@eecs.umich.edu
8465967Sgblack@eecs.umich.edu    # implement truth value testing for Bool parameters so that these params
8475238Sgblack@eecs.umich.edu    # evaluate correctly during the python configuration phase
8485238Sgblack@eecs.umich.edu    def __nonzero__(self):
8495238Sgblack@eecs.umich.edu        return bool(self.value)
8504724Sgblack@eecs.umich.edu
8514276Sgblack@eecs.umich.edu    def ini_str(self):
8526593Sgblack@eecs.umich.edu        if self.value:
8536593Sgblack@eecs.umich.edu            return 'true'
8546593Sgblack@eecs.umich.edu        return 'false'
8556593Sgblack@eecs.umich.edu
8566593Sgblack@eecs.umich.edu    def config_value(self):
8576593Sgblack@eecs.umich.edu        return self.value
8586593Sgblack@eecs.umich.edu
8596593Sgblack@eecs.umich.edu    @classmethod
8606593Sgblack@eecs.umich.edu    def cxx_ini_predecls(cls, code):
8616593Sgblack@eecs.umich.edu        # Assume that base/str.hh will be included anyway
8626593Sgblack@eecs.umich.edu        # code('#include "base/str.hh"')
8636593Sgblack@eecs.umich.edu        pass
8646593Sgblack@eecs.umich.edu
8656593Sgblack@eecs.umich.edu    @classmethod
8666593Sgblack@eecs.umich.edu    def cxx_ini_parse(cls, code, src, dest, ret):
8676593Sgblack@eecs.umich.edu        code('%s to_bool(%s, %s);' % (ret, src, dest))
8686593Sgblack@eecs.umich.edu
8695240Sgblack@eecs.umich.edudef IncEthernetAddr(addr, val = 1):
8705240Sgblack@eecs.umich.edu    bytes = map(lambda x: int(x, 16), addr.split(':'))
8715240Sgblack@eecs.umich.edu    bytes[5] += val
8725240Sgblack@eecs.umich.edu    for i in (5, 4, 3, 2, 1):
8735240Sgblack@eecs.umich.edu        val,rem = divmod(bytes[i], 256)
8745240Sgblack@eecs.umich.edu        bytes[i] = rem
8755240Sgblack@eecs.umich.edu        if val == 0:
8765240Sgblack@eecs.umich.edu            break
8775240Sgblack@eecs.umich.edu        bytes[i - 1] += val
8785240Sgblack@eecs.umich.edu    assert(bytes[0] <= 255)
8795240Sgblack@eecs.umich.edu    return ':'.join(map(lambda x: '%02x' % x, bytes))
8806593Sgblack@eecs.umich.edu
8816593Sgblack@eecs.umich.edu_NextEthernetAddr = "00:90:00:00:00:01"
8826593Sgblack@eecs.umich.edudef NextEthernetAddr():
8836593Sgblack@eecs.umich.edu    global _NextEthernetAddr
8846593Sgblack@eecs.umich.edu
8856593Sgblack@eecs.umich.edu    value = _NextEthernetAddr
8866593Sgblack@eecs.umich.edu    _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1)
8876593Sgblack@eecs.umich.edu    return value
8885238Sgblack@eecs.umich.edu
8896576Sgblack@eecs.umich.educlass EthernetAddr(ParamValue):
8906576Sgblack@eecs.umich.edu    cxx_type = 'Net::EthAddr'
8916576Sgblack@eecs.umich.edu    ex_str = "00:90:00:00:00:01"
8926576Sgblack@eecs.umich.edu    cmd_line_settable = True
8936576Sgblack@eecs.umich.edu
8946576Sgblack@eecs.umich.edu    @classmethod
8956576Sgblack@eecs.umich.edu    def cxx_predecls(cls, code):
8966576Sgblack@eecs.umich.edu        code('#include "base/inet.hh"')
8976576Sgblack@eecs.umich.edu
8986576Sgblack@eecs.umich.edu    @classmethod
8996576Sgblack@eecs.umich.edu    def swig_predecls(cls, code):
9006576Sgblack@eecs.umich.edu        code('%include "python/swig/inet.i"')
9016576Sgblack@eecs.umich.edu
9025238Sgblack@eecs.umich.edu    def __init__(self, value):
9036576Sgblack@eecs.umich.edu        if value == NextEthernetAddr:
9046576Sgblack@eecs.umich.edu            self.value = value
9055238Sgblack@eecs.umich.edu            return
9066576Sgblack@eecs.umich.edu
9076576Sgblack@eecs.umich.edu        if not isinstance(value, str):
9086576Sgblack@eecs.umich.edu            raise TypeError, "expected an ethernet address and didn't get one"
9096604Sgblack@eecs.umich.edu
9106590Sgblack@eecs.umich.edu        bytes = value.split(':')
9116591Sgblack@eecs.umich.edu        if len(bytes) != 6:
9126591Sgblack@eecs.umich.edu            raise TypeError, 'invalid ethernet address %s' % value
9136597Sgblack@eecs.umich.edu
9146576Sgblack@eecs.umich.edu        for byte in bytes:
9156576Sgblack@eecs.umich.edu            if not 0 <= int(byte, base=16) <= 0xff:
9166576Sgblack@eecs.umich.edu                raise TypeError, 'invalid ethernet address %s' % value
9176604Sgblack@eecs.umich.edu
9186576Sgblack@eecs.umich.edu        self.value = value
9196576Sgblack@eecs.umich.edu
9206576Sgblack@eecs.umich.edu    def __call__(self, value):
9216576Sgblack@eecs.umich.edu        self.__init__(value)
9226604Sgblack@eecs.umich.edu        return value
9236591Sgblack@eecs.umich.edu
9246591Sgblack@eecs.umich.edu    def unproxy(self, base):
9256597Sgblack@eecs.umich.edu        if self.value == NextEthernetAddr:
9266576Sgblack@eecs.umich.edu            return EthernetAddr(self.value())
9276576Sgblack@eecs.umich.edu        return self
9286576Sgblack@eecs.umich.edu
9296576Sgblack@eecs.umich.edu    def getValue(self):
9306604Sgblack@eecs.umich.edu        from m5.internal.params import EthAddr
9316576Sgblack@eecs.umich.edu        return EthAddr(self.value)
9326576Sgblack@eecs.umich.edu
9336576Sgblack@eecs.umich.edu    def __str__(self):
9346576Sgblack@eecs.umich.edu        return self.value
9355238Sgblack@eecs.umich.edu
9366576Sgblack@eecs.umich.edu    def ini_str(self):
9376576Sgblack@eecs.umich.edu        return self.value
9386576Sgblack@eecs.umich.edu
9396576Sgblack@eecs.umich.edu    @classmethod
9405020Sgblack@eecs.umich.edu    def cxx_ini_parse(self, code, src, dest, ret):
9416593Sgblack@eecs.umich.edu        code('%s = Net::EthAddr(%s);' % (dest, src))
9426593Sgblack@eecs.umich.edu        code('%s true;' % ret)
9436593Sgblack@eecs.umich.edu
9446593Sgblack@eecs.umich.edu# When initializing an IpAddress, pass in an existing IpAddress, a string of
9456593Sgblack@eecs.umich.edu# the form "a.b.c.d", or an integer representing an IP.
9466593Sgblack@eecs.umich.educlass IpAddress(ParamValue):
9476593Sgblack@eecs.umich.edu    cxx_type = 'Net::IpAddress'
9486593Sgblack@eecs.umich.edu    ex_str = "127.0.0.1"
9496593Sgblack@eecs.umich.edu    cmd_line_settable = True
9506593Sgblack@eecs.umich.edu
9516593Sgblack@eecs.umich.edu    @classmethod
9526593Sgblack@eecs.umich.edu    def cxx_predecls(cls, code):
9536593Sgblack@eecs.umich.edu        code('#include "base/inet.hh"')
9546593Sgblack@eecs.umich.edu
9556593Sgblack@eecs.umich.edu    @classmethod
9566593Sgblack@eecs.umich.edu    def swig_predecls(cls, code):
9576593Sgblack@eecs.umich.edu        code('%include "python/swig/inet.i"')
9586593Sgblack@eecs.umich.edu
9596593Sgblack@eecs.umich.edu    def __init__(self, value):
9606593Sgblack@eecs.umich.edu        if isinstance(value, IpAddress):
9616593Sgblack@eecs.umich.edu            self.ip = value.ip
9626593Sgblack@eecs.umich.edu        else:
9636593Sgblack@eecs.umich.edu            try:
9646593Sgblack@eecs.umich.edu                self.ip = convert.toIpAddress(value)
9656593Sgblack@eecs.umich.edu            except TypeError:
9666593Sgblack@eecs.umich.edu                self.ip = long(value)
9676593Sgblack@eecs.umich.edu        self.verifyIp()
9686593Sgblack@eecs.umich.edu
9696593Sgblack@eecs.umich.edu    def __call__(self, value):
9706593Sgblack@eecs.umich.edu        self.__init__(value)
9716607Sgblack@eecs.umich.edu        return value
9726593Sgblack@eecs.umich.edu
9736593Sgblack@eecs.umich.edu    def __str__(self):
9746593Sgblack@eecs.umich.edu        tup = [(self.ip >> i)  & 0xff for i in (24, 16, 8, 0)]
9755020Sgblack@eecs.umich.edu        return '%d.%d.%d.%d' % tuple(tup)
9766576Sgblack@eecs.umich.edu
9776576Sgblack@eecs.umich.edu    def __eq__(self, other):
9786576Sgblack@eecs.umich.edu        if isinstance(other, IpAddress):
9796580Sgblack@eecs.umich.edu            return self.ip == other.ip
9806580Sgblack@eecs.umich.edu        elif isinstance(other, str):
9816576Sgblack@eecs.umich.edu            try:
9826576Sgblack@eecs.umich.edu                return self.ip == convert.toIpAddress(other)
9836576Sgblack@eecs.umich.edu            except:
9846576Sgblack@eecs.umich.edu                return False
9856576Sgblack@eecs.umich.edu        else:
9866576Sgblack@eecs.umich.edu            return self.ip == other
9876576Sgblack@eecs.umich.edu
9886576Sgblack@eecs.umich.edu    def __ne__(self, other):
9896576Sgblack@eecs.umich.edu        return not (self == other)
9906580Sgblack@eecs.umich.edu
9916580Sgblack@eecs.umich.edu    def verifyIp(self):
9926576Sgblack@eecs.umich.edu        if self.ip < 0 or self.ip >= (1 << 32):
9936576Sgblack@eecs.umich.edu            raise TypeError, "invalid ip address %#08x" % self.ip
9946576Sgblack@eecs.umich.edu
9956576Sgblack@eecs.umich.edu    def getValue(self):
9966576Sgblack@eecs.umich.edu        from m5.internal.params import IpAddress
9976576Sgblack@eecs.umich.edu        return IpAddress(self.ip)
9986576Sgblack@eecs.umich.edu
9996576Sgblack@eecs.umich.edu# When initializing an IpNetmask, pass in an existing IpNetmask, a string of
10005020Sgblack@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
10016588Sgblack@eecs.umich.edu# positional or keyword arguments.
10026588Sgblack@eecs.umich.educlass IpNetmask(IpAddress):
10036588Sgblack@eecs.umich.edu    cxx_type = 'Net::IpNetmask'
10046588Sgblack@eecs.umich.edu    ex_str = "127.0.0.0/24"
10056588Sgblack@eecs.umich.edu    cmd_line_settable = True
10066588Sgblack@eecs.umich.edu
10076588Sgblack@eecs.umich.edu    @classmethod
10086588Sgblack@eecs.umich.edu    def cxx_predecls(cls, code):
10096588Sgblack@eecs.umich.edu        code('#include "base/inet.hh"')
10106588Sgblack@eecs.umich.edu
10116588Sgblack@eecs.umich.edu    @classmethod
10126588Sgblack@eecs.umich.edu    def swig_predecls(cls, code):
10136588Sgblack@eecs.umich.edu        code('%include "python/swig/inet.i"')
10146588Sgblack@eecs.umich.edu
10156588Sgblack@eecs.umich.edu    def __init__(self, *args, **kwargs):
10166588Sgblack@eecs.umich.edu        def handle_kwarg(self, kwargs, key, elseVal = None):
10176588Sgblack@eecs.umich.edu            if key in kwargs:
10186588Sgblack@eecs.umich.edu                setattr(self, key, kwargs.pop(key))
10196588Sgblack@eecs.umich.edu            elif elseVal:
10206588Sgblack@eecs.umich.edu                setattr(self, key, elseVal)
10216588Sgblack@eecs.umich.edu            else:
10226588Sgblack@eecs.umich.edu                raise TypeError, "No value set for %s" % key
10236588Sgblack@eecs.umich.edu
10246588Sgblack@eecs.umich.edu        if len(args) == 0:
10256588Sgblack@eecs.umich.edu            handle_kwarg(self, kwargs, 'ip')
10266606Sgblack@eecs.umich.edu            handle_kwarg(self, kwargs, 'netmask')
10276588Sgblack@eecs.umich.edu
10286588Sgblack@eecs.umich.edu        elif len(args) == 1:
10296588Sgblack@eecs.umich.edu            if kwargs:
10306588Sgblack@eecs.umich.edu                if not 'ip' in kwargs and not 'netmask' in kwargs:
10316606Sgblack@eecs.umich.edu                    raise TypeError, "Invalid arguments"
10326588Sgblack@eecs.umich.edu                handle_kwarg(self, kwargs, 'ip', args[0])
10336588Sgblack@eecs.umich.edu                handle_kwarg(self, kwargs, 'netmask', args[0])
10346588Sgblack@eecs.umich.edu            elif isinstance(args[0], IpNetmask):
10355022Sgblack@eecs.umich.edu                self.ip = args[0].ip
10366576Sgblack@eecs.umich.edu                self.netmask = args[0].netmask
10376576Sgblack@eecs.umich.edu            else:
10386576Sgblack@eecs.umich.edu                (self.ip, self.netmask) = convert.toIpNetmask(args[0])
10396580Sgblack@eecs.umich.edu
10406580Sgblack@eecs.umich.edu        elif len(args) == 2:
10416576Sgblack@eecs.umich.edu            self.ip = args[0]
10426576Sgblack@eecs.umich.edu            self.netmask = args[1]
10436576Sgblack@eecs.umich.edu        else:
10446576Sgblack@eecs.umich.edu            raise TypeError, "Too many arguments specified"
10456576Sgblack@eecs.umich.edu
10466576Sgblack@eecs.umich.edu        if kwargs:
10476576Sgblack@eecs.umich.edu            raise TypeError, "Too many keywords: %s" % kwargs.keys()
10486576Sgblack@eecs.umich.edu
10496576Sgblack@eecs.umich.edu        self.verify()
10506580Sgblack@eecs.umich.edu
10516580Sgblack@eecs.umich.edu    def __call__(self, value):
10526576Sgblack@eecs.umich.edu        self.__init__(value)
10536576Sgblack@eecs.umich.edu        return value
10546576Sgblack@eecs.umich.edu
10556576Sgblack@eecs.umich.edu    def __str__(self):
10566576Sgblack@eecs.umich.edu        return "%s/%d" % (super(IpNetmask, self).__str__(), self.netmask)
10576576Sgblack@eecs.umich.edu
10586576Sgblack@eecs.umich.edu    def __eq__(self, other):
10596576Sgblack@eecs.umich.edu        if isinstance(other, IpNetmask):
10605020Sgblack@eecs.umich.edu            return self.ip == other.ip and self.netmask == other.netmask
10616586Sgblack@eecs.umich.edu        elif isinstance(other, str):
10626586Sgblack@eecs.umich.edu            try:
10636586Sgblack@eecs.umich.edu                return (self.ip, self.netmask) == convert.toIpNetmask(other)
10646586Sgblack@eecs.umich.edu            except:
10656586Sgblack@eecs.umich.edu                return False
10666586Sgblack@eecs.umich.edu        else:
10676586Sgblack@eecs.umich.edu            return False
10686586Sgblack@eecs.umich.edu
10696586Sgblack@eecs.umich.edu    def verify(self):
10706595Sgblack@eecs.umich.edu        self.verifyIp()
10716586Sgblack@eecs.umich.edu        if self.netmask < 0 or self.netmask > 32:
10726586Sgblack@eecs.umich.edu            raise TypeError, "invalid netmask %d" % netmask
10736586Sgblack@eecs.umich.edu
10746586Sgblack@eecs.umich.edu    def getValue(self):
10756586Sgblack@eecs.umich.edu        from m5.internal.params import IpNetmask
10766586Sgblack@eecs.umich.edu        return IpNetmask(self.ip, self.netmask)
10776586Sgblack@eecs.umich.edu
10786586Sgblack@eecs.umich.edu# When initializing an IpWithPort, pass in an existing IpWithPort, a string of
10796586Sgblack@eecs.umich.edu# the form "a.b.c.d:p", or an ip and port as positional or keyword arguments.
10806586Sgblack@eecs.umich.educlass IpWithPort(IpAddress):
10816595Sgblack@eecs.umich.edu    cxx_type = 'Net::IpWithPort'
10826586Sgblack@eecs.umich.edu    ex_str = "127.0.0.1:80"
10836586Sgblack@eecs.umich.edu    cmd_line_settable = True
10846586Sgblack@eecs.umich.edu
10856586Sgblack@eecs.umich.edu    @classmethod
10866586Sgblack@eecs.umich.edu    def cxx_predecls(cls, code):
10876586Sgblack@eecs.umich.edu        code('#include "base/inet.hh"')
10886586Sgblack@eecs.umich.edu
10896586Sgblack@eecs.umich.edu    @classmethod
10905022Sgblack@eecs.umich.edu    def swig_predecls(cls, code):
10916576Sgblack@eecs.umich.edu        code('%include "python/swig/inet.i"')
10926576Sgblack@eecs.umich.edu
10936576Sgblack@eecs.umich.edu    def __init__(self, *args, **kwargs):
10946580Sgblack@eecs.umich.edu        def handle_kwarg(self, kwargs, key, elseVal = None):
10956580Sgblack@eecs.umich.edu            if key in kwargs:
10966580Sgblack@eecs.umich.edu                setattr(self, key, kwargs.pop(key))
10976580Sgblack@eecs.umich.edu            elif elseVal:
10986576Sgblack@eecs.umich.edu                setattr(self, key, elseVal)
10996576Sgblack@eecs.umich.edu            else:
11006576Sgblack@eecs.umich.edu                raise TypeError, "No value set for %s" % key
11016576Sgblack@eecs.umich.edu
11026576Sgblack@eecs.umich.edu        if len(args) == 0:
11036576Sgblack@eecs.umich.edu            handle_kwarg(self, kwargs, 'ip')
11046576Sgblack@eecs.umich.edu            handle_kwarg(self, kwargs, 'port')
11056580Sgblack@eecs.umich.edu
11066580Sgblack@eecs.umich.edu        elif len(args) == 1:
11076580Sgblack@eecs.umich.edu            if kwargs:
11086580Sgblack@eecs.umich.edu                if not 'ip' in kwargs and not 'port' in kwargs:
11096576Sgblack@eecs.umich.edu                    raise TypeError, "Invalid arguments"
11106576Sgblack@eecs.umich.edu                handle_kwarg(self, kwargs, 'ip', args[0])
11116576Sgblack@eecs.umich.edu                handle_kwarg(self, kwargs, 'port', args[0])
11126576Sgblack@eecs.umich.edu            elif isinstance(args[0], IpWithPort):
11136576Sgblack@eecs.umich.edu                self.ip = args[0].ip
11146576Sgblack@eecs.umich.edu                self.port = args[0].port
11155020Sgblack@eecs.umich.edu            else:
11164276Sgblack@eecs.umich.edu                (self.ip, self.port) = convert.toIpWithPort(args[0])
11174276Sgblack@eecs.umich.edu
11184276Sgblack@eecs.umich.edu        elif len(args) == 2:
11194276Sgblack@eecs.umich.edu            self.ip = args[0]
11204276Sgblack@eecs.umich.edu            self.port = args[1]
11214276Sgblack@eecs.umich.edu        else:
11224276Sgblack@eecs.umich.edu            raise TypeError, "Too many arguments specified"
1123
1124        if kwargs:
1125            raise TypeError, "Too many keywords: %s" % kwargs.keys()
1126
1127        self.verify()
1128
1129    def __call__(self, value):
1130        self.__init__(value)
1131        return value
1132
1133    def __str__(self):
1134        return "%s:%d" % (super(IpWithPort, self).__str__(), self.port)
1135
1136    def __eq__(self, other):
1137        if isinstance(other, IpWithPort):
1138            return self.ip == other.ip and self.port == other.port
1139        elif isinstance(other, str):
1140            try:
1141                return (self.ip, self.port) == convert.toIpWithPort(other)
1142            except:
1143                return False
1144        else:
1145            return False
1146
1147    def verify(self):
1148        self.verifyIp()
1149        if self.port < 0 or self.port > 0xffff:
1150            raise TypeError, "invalid port %d" % self.port
1151
1152    def getValue(self):
1153        from m5.internal.params import IpWithPort
1154        return IpWithPort(self.ip, self.port)
1155
1156time_formats = [ "%a %b %d %H:%M:%S %Z %Y",
1157                 "%a %b %d %H:%M:%S %Y",
1158                 "%Y/%m/%d %H:%M:%S",
1159                 "%Y/%m/%d %H:%M",
1160                 "%Y/%m/%d",
1161                 "%m/%d/%Y %H:%M:%S",
1162                 "%m/%d/%Y %H:%M",
1163                 "%m/%d/%Y",
1164                 "%m/%d/%y %H:%M:%S",
1165                 "%m/%d/%y %H:%M",
1166                 "%m/%d/%y"]
1167
1168
1169def parse_time(value):
1170    from time import gmtime, strptime, struct_time, time
1171    from datetime import datetime, date
1172
1173    if isinstance(value, struct_time):
1174        return value
1175
1176    if isinstance(value, (int, long)):
1177        return gmtime(value)
1178
1179    if isinstance(value, (datetime, date)):
1180        return value.timetuple()
1181
1182    if isinstance(value, str):
1183        if value in ('Now', 'Today'):
1184            return time.gmtime(time.time())
1185
1186        for format in time_formats:
1187            try:
1188                return strptime(value, format)
1189            except ValueError:
1190                pass
1191
1192    raise ValueError, "Could not parse '%s' as a time" % value
1193
1194class Time(ParamValue):
1195    cxx_type = 'tm'
1196
1197    @classmethod
1198    def cxx_predecls(cls, code):
1199        code('#include <time.h>')
1200
1201    @classmethod
1202    def swig_predecls(cls, code):
1203        code('%include "python/swig/time.i"')
1204
1205    def __init__(self, value):
1206        self.value = parse_time(value)
1207
1208    def __call__(self, value):
1209        self.__init__(value)
1210        return value
1211
1212    def getValue(self):
1213        from m5.internal.params import tm
1214
1215        c_time = tm()
1216        py_time = self.value
1217
1218        # UNIX is years since 1900
1219        c_time.tm_year = py_time.tm_year - 1900;
1220
1221        # Python starts at 1, UNIX starts at 0
1222        c_time.tm_mon =  py_time.tm_mon - 1;
1223        c_time.tm_mday = py_time.tm_mday;
1224        c_time.tm_hour = py_time.tm_hour;
1225        c_time.tm_min = py_time.tm_min;
1226        c_time.tm_sec = py_time.tm_sec;
1227
1228        # Python has 0 as Monday, UNIX is 0 as sunday
1229        c_time.tm_wday = py_time.tm_wday + 1
1230        if c_time.tm_wday > 6:
1231            c_time.tm_wday -= 7;
1232
1233        # Python starts at 1, Unix starts at 0
1234        c_time.tm_yday = py_time.tm_yday - 1;
1235
1236        return c_time
1237
1238    def __str__(self):
1239        return time.asctime(self.value)
1240
1241    def ini_str(self):
1242        return str(self)
1243
1244    def get_config_as_dict(self):
1245        assert false
1246        return str(self)
1247
1248    @classmethod
1249    def cxx_ini_predecls(cls, code):
1250        code('#include <time.h>')
1251
1252    @classmethod
1253    def cxx_ini_parse(cls, code, src, dest, ret):
1254        code('char *_parse_ret = strptime((${src}).c_str(),')
1255        code('    "%a %b %d %H:%M:%S %Y", &(${dest}));')
1256        code('${ret} _parse_ret && *_parse_ret == \'\\0\';');
1257
1258# Enumerated types are a little more complex.  The user specifies the
1259# type as Enum(foo) where foo is either a list or dictionary of
1260# alternatives (typically strings, but not necessarily so).  (In the
1261# long run, the integer value of the parameter will be the list index
1262# or the corresponding dictionary value.  For now, since we only check
1263# that the alternative is valid and then spit it into a .ini file,
1264# there's not much point in using the dictionary.)
1265
1266# What Enum() must do is generate a new type encapsulating the
1267# provided list/dictionary so that specific values of the parameter
1268# can be instances of that type.  We define two hidden internal
1269# classes (_ListEnum and _DictEnum) to serve as base classes, then
1270# derive the new type from the appropriate base class on the fly.
1271
1272allEnums = {}
1273# Metaclass for Enum types
1274class MetaEnum(MetaParamValue):
1275    def __new__(mcls, name, bases, dict):
1276        assert name not in allEnums
1277
1278        cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict)
1279        allEnums[name] = cls
1280        return cls
1281
1282    def __init__(cls, name, bases, init_dict):
1283        if init_dict.has_key('map'):
1284            if not isinstance(cls.map, dict):
1285                raise TypeError, "Enum-derived class attribute 'map' " \
1286                      "must be of type dict"
1287            # build list of value strings from map
1288            cls.vals = cls.map.keys()
1289            cls.vals.sort()
1290        elif init_dict.has_key('vals'):
1291            if not isinstance(cls.vals, list):
1292                raise TypeError, "Enum-derived class attribute 'vals' " \
1293                      "must be of type list"
1294            # build string->value map from vals sequence
1295            cls.map = {}
1296            for idx,val in enumerate(cls.vals):
1297                cls.map[val] = idx
1298        else:
1299            raise TypeError, "Enum-derived class must define "\
1300                  "attribute 'map' or 'vals'"
1301
1302        cls.cxx_type = 'Enums::%s' % name
1303
1304        super(MetaEnum, cls).__init__(name, bases, init_dict)
1305
1306    # Generate C++ class declaration for this enum type.
1307    # Note that we wrap the enum in a class/struct to act as a namespace,
1308    # so that the enum strings can be brief w/o worrying about collisions.
1309    def cxx_decl(cls, code):
1310        wrapper_name = cls.wrapper_name
1311        wrapper = 'struct' if cls.wrapper_is_struct else 'namespace'
1312        name = cls.__name__ if cls.enum_name is None else cls.enum_name
1313        idem_macro = '__ENUM__%s__%s__' % (wrapper_name, name)
1314
1315        code('''\
1316#ifndef $idem_macro
1317#define $idem_macro
1318
1319$wrapper $wrapper_name {
1320    enum $name {
1321''')
1322        code.indent(2)
1323        for val in cls.vals:
1324            code('$val = ${{cls.map[val]}},')
1325        code('Num_$name = ${{len(cls.vals)}}')
1326        code.dedent(2)
1327        code('    };')
1328
1329        if cls.wrapper_is_struct:
1330            code('    static const char *${name}Strings[Num_${name}];')
1331            code('};')
1332        else:
1333            code('extern const char *${name}Strings[Num_${name}];')
1334            code('}')
1335
1336        code()
1337        code('#endif // $idem_macro')
1338
1339    def cxx_def(cls, code):
1340        wrapper_name = cls.wrapper_name
1341        file_name = cls.__name__
1342        name = cls.__name__ if cls.enum_name is None else cls.enum_name
1343
1344        code('#include "enums/$file_name.hh"')
1345        if cls.wrapper_is_struct:
1346            code('const char *${wrapper_name}::${name}Strings'
1347                '[Num_${name}] =')
1348        else:
1349            code('namespace Enums {')
1350            code.indent(1)
1351            code(' const char *${name}Strings[Num_${name}] =')
1352
1353        code('{')
1354        code.indent(1)
1355        for val in cls.vals:
1356            code('"$val",')
1357        code.dedent(1)
1358        code('};')
1359
1360        if not cls.wrapper_is_struct:
1361            code('} // namespace $wrapper_name')
1362            code.dedent(1)
1363
1364    def swig_decl(cls, code):
1365        name = cls.__name__
1366        code('''\
1367%module(package="m5.internal") enum_$name
1368
1369%{
1370#include "enums/$name.hh"
1371%}
1372
1373%include "enums/$name.hh"
1374''')
1375
1376
1377# Base class for enum types.
1378class Enum(ParamValue):
1379    __metaclass__ = MetaEnum
1380    vals = []
1381    cmd_line_settable = True
1382
1383    # The name of the wrapping namespace or struct
1384    wrapper_name = 'Enums'
1385
1386    # If true, the enum is wrapped in a struct rather than a namespace
1387    wrapper_is_struct = False
1388
1389    # If not None, use this as the enum name rather than this class name
1390    enum_name = None
1391
1392    def __init__(self, value):
1393        if value not in self.map:
1394            raise TypeError, "Enum param got bad value '%s' (not in %s)" \
1395                  % (value, self.vals)
1396        self.value = value
1397
1398    def __call__(self, value):
1399        self.__init__(value)
1400        return value
1401
1402    @classmethod
1403    def cxx_predecls(cls, code):
1404        code('#include "enums/$0.hh"', cls.__name__)
1405
1406    @classmethod
1407    def swig_predecls(cls, code):
1408        code('%import "python/m5/internal/enum_$0.i"', cls.__name__)
1409
1410    @classmethod
1411    def cxx_ini_parse(cls, code, src, dest, ret):
1412        code('if (false) {')
1413        for elem_name in cls.map.iterkeys():
1414            code('} else if (%s == "%s") {' % (src, elem_name))
1415            code.indent()
1416            code('%s = Enums::%s;' % (dest, elem_name))
1417            code('%s true;' % ret)
1418            code.dedent()
1419        code('} else {')
1420        code('    %s false;' % ret)
1421        code('}')
1422
1423    def getValue(self):
1424        return int(self.map[self.value])
1425
1426    def __str__(self):
1427        return self.value
1428
1429# how big does a rounding error need to be before we warn about it?
1430frequency_tolerance = 0.001  # 0.1%
1431
1432class TickParamValue(NumericParamValue):
1433    cxx_type = 'Tick'
1434    ex_str = "1MHz"
1435    cmd_line_settable = True
1436
1437    @classmethod
1438    def cxx_predecls(cls, code):
1439        code('#include "base/types.hh"')
1440
1441    @classmethod
1442    def swig_predecls(cls, code):
1443        code('%import "stdint.i"')
1444        code('%import "base/types.hh"')
1445
1446    def __call__(self, value):
1447        self.__init__(value)
1448        return value
1449
1450    def getValue(self):
1451        return long(self.value)
1452
1453    @classmethod
1454    def cxx_ini_predecls(cls, code):
1455        code('#include <sstream>')
1456
1457    # Ticks are expressed in seconds in JSON files and in plain
1458    # Ticks in .ini files.  Switch based on a config flag
1459    @classmethod
1460    def cxx_ini_parse(self, code, src, dest, ret):
1461        code('${ret} to_number(${src}, ${dest});')
1462
1463class Latency(TickParamValue):
1464    ex_str = "100ns"
1465
1466    def __init__(self, value):
1467        if isinstance(value, (Latency, Clock)):
1468            self.ticks = value.ticks
1469            self.value = value.value
1470        elif isinstance(value, Frequency):
1471            self.ticks = value.ticks
1472            self.value = 1.0 / value.value
1473        elif value.endswith('t'):
1474            self.ticks = True
1475            self.value = int(value[:-1])
1476        else:
1477            self.ticks = False
1478            self.value = convert.toLatency(value)
1479
1480    def __call__(self, value):
1481        self.__init__(value)
1482        return value
1483
1484    def __getattr__(self, attr):
1485        if attr in ('latency', 'period'):
1486            return self
1487        if attr == 'frequency':
1488            return Frequency(self)
1489        raise AttributeError, "Latency object has no attribute '%s'" % attr
1490
1491    def getValue(self):
1492        if self.ticks or self.value == 0:
1493            value = self.value
1494        else:
1495            value = ticks.fromSeconds(self.value)
1496        return long(value)
1497
1498    def config_value(self):
1499        return self.getValue()
1500
1501    # convert latency to ticks
1502    def ini_str(self):
1503        return '%d' % self.getValue()
1504
1505class Frequency(TickParamValue):
1506    ex_str = "1GHz"
1507
1508    def __init__(self, value):
1509        if isinstance(value, (Latency, Clock)):
1510            if value.value == 0:
1511                self.value = 0
1512            else:
1513                self.value = 1.0 / value.value
1514            self.ticks = value.ticks
1515        elif isinstance(value, Frequency):
1516            self.value = value.value
1517            self.ticks = value.ticks
1518        else:
1519            self.ticks = False
1520            self.value = convert.toFrequency(value)
1521
1522    def __call__(self, value):
1523        self.__init__(value)
1524        return value
1525
1526    def __getattr__(self, attr):
1527        if attr == 'frequency':
1528            return self
1529        if attr in ('latency', 'period'):
1530            return Latency(self)
1531        raise AttributeError, "Frequency object has no attribute '%s'" % attr
1532
1533    # convert latency to ticks
1534    def getValue(self):
1535        if self.ticks or self.value == 0:
1536            value = self.value
1537        else:
1538            value = ticks.fromSeconds(1.0 / self.value)
1539        return long(value)
1540
1541    def config_value(self):
1542        return self.getValue()
1543
1544    def ini_str(self):
1545        return '%d' % self.getValue()
1546
1547# A generic Frequency and/or Latency value. Value is stored as a
1548# latency, just like Latency and Frequency.
1549class Clock(TickParamValue):
1550    def __init__(self, value):
1551        if isinstance(value, (Latency, Clock)):
1552            self.ticks = value.ticks
1553            self.value = value.value
1554        elif isinstance(value, Frequency):
1555            self.ticks = value.ticks
1556            self.value = 1.0 / value.value
1557        elif value.endswith('t'):
1558            self.ticks = True
1559            self.value = int(value[:-1])
1560        else:
1561            self.ticks = False
1562            self.value = convert.anyToLatency(value)
1563
1564    def __call__(self, value):
1565        self.__init__(value)
1566        return value
1567
1568    def __str__(self):
1569        return "%s" % Latency(self)
1570
1571    def __getattr__(self, attr):
1572        if attr == 'frequency':
1573            return Frequency(self)
1574        if attr in ('latency', 'period'):
1575            return Latency(self)
1576        raise AttributeError, "Frequency object has no attribute '%s'" % attr
1577
1578    def getValue(self):
1579        return self.period.getValue()
1580
1581    def config_value(self):
1582        return self.period.config_value()
1583
1584    def ini_str(self):
1585        return self.period.ini_str()
1586
1587class Voltage(float,ParamValue):
1588    cxx_type = 'double'
1589    ex_str = "1V"
1590    cmd_line_settable = True
1591
1592    def __new__(cls, value):
1593        # convert to voltage
1594        val = convert.toVoltage(value)
1595        return super(cls, Voltage).__new__(cls, val)
1596
1597    def __call__(self, value):
1598        val = convert.toVoltage(value)
1599        self.__init__(val)
1600        return value
1601
1602    def __str__(self):
1603        return str(self.getValue())
1604
1605    def getValue(self):
1606        value = float(self)
1607        return value
1608
1609    def ini_str(self):
1610        return '%f' % self.getValue()
1611
1612    @classmethod
1613    def cxx_ini_predecls(cls, code):
1614        code('#include <sstream>')
1615
1616    @classmethod
1617    def cxx_ini_parse(self, code, src, dest, ret):
1618        code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
1619
1620class Current(float, ParamValue):
1621    cxx_type = 'double'
1622    ex_str = "1mA"
1623    cmd_line_settable = False
1624
1625    def __new__(cls, value):
1626        # convert to current
1627        val = convert.toCurrent(value)
1628        return super(cls, Current).__new__(cls, val)
1629
1630    def __call__(self, value):
1631        val = convert.toCurrent(value)
1632        self.__init__(val)
1633        return value
1634
1635    def __str__(self):
1636        return str(self.getValue())
1637
1638    def getValue(self):
1639        value = float(self)
1640        return value
1641
1642    def ini_str(self):
1643        return '%f' % self.getValue()
1644
1645    @classmethod
1646    def cxx_ini_predecls(cls, code):
1647        code('#include <sstream>')
1648
1649    @classmethod
1650    def cxx_ini_parse(self, code, src, dest, ret):
1651        code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
1652
1653class NetworkBandwidth(float,ParamValue):
1654    cxx_type = 'float'
1655    ex_str = "1Gbps"
1656    cmd_line_settable = True
1657
1658    def __new__(cls, value):
1659        # convert to bits per second
1660        val = convert.toNetworkBandwidth(value)
1661        return super(cls, NetworkBandwidth).__new__(cls, val)
1662
1663    def __str__(self):
1664        return str(self.val)
1665
1666    def __call__(self, value):
1667        val = convert.toNetworkBandwidth(value)
1668        self.__init__(val)
1669        return value
1670
1671    def getValue(self):
1672        # convert to seconds per byte
1673        value = 8.0 / float(self)
1674        # convert to ticks per byte
1675        value = ticks.fromSeconds(value)
1676        return float(value)
1677
1678    def ini_str(self):
1679        return '%f' % self.getValue()
1680
1681    def config_value(self):
1682        return '%f' % self.getValue()
1683
1684    @classmethod
1685    def cxx_ini_predecls(cls, code):
1686        code('#include <sstream>')
1687
1688    @classmethod
1689    def cxx_ini_parse(self, code, src, dest, ret):
1690        code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
1691
1692class MemoryBandwidth(float,ParamValue):
1693    cxx_type = 'float'
1694    ex_str = "1GB/s"
1695    cmd_line_settable = True
1696
1697    def __new__(cls, value):
1698        # convert to bytes per second
1699        val = convert.toMemoryBandwidth(value)
1700        return super(cls, MemoryBandwidth).__new__(cls, val)
1701
1702    def __call__(self, value):
1703        val = convert.toMemoryBandwidth(value)
1704        self.__init__(val)
1705        return value
1706
1707    def getValue(self):
1708        # convert to seconds per byte
1709        value = float(self)
1710        if value:
1711            value = 1.0 / float(self)
1712        # convert to ticks per byte
1713        value = ticks.fromSeconds(value)
1714        return float(value)
1715
1716    def ini_str(self):
1717        return '%f' % self.getValue()
1718
1719    def config_value(self):
1720        return '%f' % self.getValue()
1721
1722    @classmethod
1723    def cxx_ini_predecls(cls, code):
1724        code('#include <sstream>')
1725
1726    @classmethod
1727    def cxx_ini_parse(self, code, src, dest, ret):
1728        code('%s (std::istringstream(%s) >> %s).eof();' % (ret, src, dest))
1729
1730#
1731# "Constants"... handy aliases for various values.
1732#
1733
1734# Special class for NULL pointers.  Note the special check in
1735# make_param_value() above that lets these be assigned where a
1736# SimObject is required.
1737# only one copy of a particular node
1738class NullSimObject(object):
1739    __metaclass__ = Singleton
1740
1741    def __call__(cls):
1742        return cls
1743
1744    def _instantiate(self, parent = None, path = ''):
1745        pass
1746
1747    def ini_str(self):
1748        return 'Null'
1749
1750    def unproxy(self, base):
1751        return self
1752
1753    def set_path(self, parent, name):
1754        pass
1755
1756    def __str__(self):
1757        return 'Null'
1758
1759    def config_value(self):
1760        return None
1761
1762    def getValue(self):
1763        return None
1764
1765# The only instance you'll ever need...
1766NULL = NullSimObject()
1767
1768def isNullPointer(value):
1769    return isinstance(value, NullSimObject)
1770
1771# Some memory range specifications use this as a default upper bound.
1772MaxAddr = Addr.max
1773MaxTick = Tick.max
1774AllMemory = AddrRange(0, MaxAddr)
1775
1776
1777#####################################################################
1778#
1779# Port objects
1780#
1781# Ports are used to interconnect objects in the memory system.
1782#
1783#####################################################################
1784
1785# Port reference: encapsulates a reference to a particular port on a
1786# particular SimObject.
1787class PortRef(object):
1788    def __init__(self, simobj, name, role):
1789        assert(isSimObject(simobj) or isSimObjectClass(simobj))
1790        self.simobj = simobj
1791        self.name = name
1792        self.role = role
1793        self.peer = None   # not associated with another port yet
1794        self.ccConnected = False # C++ port connection done?
1795        self.index = -1  # always -1 for non-vector ports
1796
1797    def __str__(self):
1798        return '%s.%s' % (self.simobj, self.name)
1799
1800    def __len__(self):
1801        # Return the number of connected ports, i.e. 0 is we have no
1802        # peer and 1 if we do.
1803        return int(self.peer != None)
1804
1805    # for config.ini, print peer's name (not ours)
1806    def ini_str(self):
1807        return str(self.peer)
1808
1809    # for config.json
1810    def get_config_as_dict(self):
1811        return {'role' : self.role, 'peer' : str(self.peer)}
1812
1813    def __getattr__(self, attr):
1814        if attr == 'peerObj':
1815            # shorthand for proxies
1816            return self.peer.simobj
1817        raise AttributeError, "'%s' object has no attribute '%s'" % \
1818              (self.__class__.__name__, attr)
1819
1820    # Full connection is symmetric (both ways).  Called via
1821    # SimObject.__setattr__ as a result of a port assignment, e.g.,
1822    # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
1823    # e.g., "obj1.portA[3] = obj2.portB".
1824    def connect(self, other):
1825        if isinstance(other, VectorPortRef):
1826            # reference to plain VectorPort is implicit append
1827            other = other._get_next()
1828        if self.peer and not proxy.isproxy(self.peer):
1829            fatal("Port %s is already connected to %s, cannot connect %s\n",
1830                  self, self.peer, other);
1831        self.peer = other
1832        if proxy.isproxy(other):
1833            other.set_param_desc(PortParamDesc())
1834        elif isinstance(other, PortRef):
1835            if other.peer is not self:
1836                other.connect(self)
1837        else:
1838            raise TypeError, \
1839                  "assigning non-port reference '%s' to port '%s'" \
1840                  % (other, self)
1841
1842    # Allow a master/slave port pair to be spliced between
1843    # a port and its connected peer. Useful operation for connecting
1844    # instrumentation structures into a system when it is necessary
1845    # to connect the instrumentation after the full system has been
1846    # constructed.
1847    def splice(self, new_master_peer, new_slave_peer):
1848        if self.peer and not proxy.isproxy(self.peer):
1849            if isinstance(new_master_peer, PortRef) and \
1850               isinstance(new_slave_peer, PortRef):
1851                 old_peer = self.peer
1852                 if self.role == 'SLAVE':
1853                     self.peer = new_master_peer
1854                     old_peer.peer = new_slave_peer
1855                     new_master_peer.connect(self)
1856                     new_slave_peer.connect(old_peer)
1857                 elif self.role == 'MASTER':
1858                     self.peer = new_slave_peer
1859                     old_peer.peer = new_master_peer
1860                     new_slave_peer.connect(self)
1861                     new_master_peer.connect(old_peer)
1862                 else:
1863                     panic("Port %s has unknown role, "+\
1864                           "cannot splice in new peers\n", self)
1865            else:
1866                raise TypeError, \
1867                      "Splicing non-port references '%s','%s' to port '%s'"\
1868                      % (new_peer, peers_new_peer, self)
1869        else:
1870            fatal("Port %s not connected, cannot splice in new peers\n", self)
1871
1872    def clone(self, simobj, memo):
1873        if memo.has_key(self):
1874            return memo[self]
1875        newRef = copy.copy(self)
1876        memo[self] = newRef
1877        newRef.simobj = simobj
1878        assert(isSimObject(newRef.simobj))
1879        if self.peer and not proxy.isproxy(self.peer):
1880            peerObj = self.peer.simobj(_memo=memo)
1881            newRef.peer = self.peer.clone(peerObj, memo)
1882            assert(not isinstance(newRef.peer, VectorPortRef))
1883        return newRef
1884
1885    def unproxy(self, simobj):
1886        assert(simobj is self.simobj)
1887        if proxy.isproxy(self.peer):
1888            try:
1889                realPeer = self.peer.unproxy(self.simobj)
1890            except:
1891                print "Error in unproxying port '%s' of %s" % \
1892                      (self.name, self.simobj.path())
1893                raise
1894            self.connect(realPeer)
1895
1896    # Call C++ to create corresponding port connection between C++ objects
1897    def ccConnect(self):
1898        from m5.internal.pyobject import connectPorts
1899
1900        if self.role == 'SLAVE':
1901            # do nothing and let the master take care of it
1902            return
1903
1904        if self.ccConnected: # already done this
1905            return
1906        peer = self.peer
1907        if not self.peer: # nothing to connect to
1908            return
1909
1910        # check that we connect a master to a slave
1911        if self.role == peer.role:
1912            raise TypeError, \
1913                "cannot connect '%s' and '%s' due to identical role '%s'" \
1914                % (peer, self, self.role)
1915
1916        try:
1917            # self is always the master and peer the slave
1918            connectPorts(self.simobj.getCCObject(), self.name, self.index,
1919                         peer.simobj.getCCObject(), peer.name, peer.index)
1920        except:
1921            print "Error connecting port %s.%s to %s.%s" % \
1922                  (self.simobj.path(), self.name,
1923                   peer.simobj.path(), peer.name)
1924            raise
1925        self.ccConnected = True
1926        peer.ccConnected = True
1927
1928# A reference to an individual element of a VectorPort... much like a
1929# PortRef, but has an index.
1930class VectorPortElementRef(PortRef):
1931    def __init__(self, simobj, name, role, index):
1932        PortRef.__init__(self, simobj, name, role)
1933        self.index = index
1934
1935    def __str__(self):
1936        return '%s.%s[%d]' % (self.simobj, self.name, self.index)
1937
1938# A reference to a complete vector-valued port (not just a single element).
1939# Can be indexed to retrieve individual VectorPortElementRef instances.
1940class VectorPortRef(object):
1941    def __init__(self, simobj, name, role):
1942        assert(isSimObject(simobj) or isSimObjectClass(simobj))
1943        self.simobj = simobj
1944        self.name = name
1945        self.role = role
1946        self.elements = []
1947
1948    def __str__(self):
1949        return '%s.%s[:]' % (self.simobj, self.name)
1950
1951    def __len__(self):
1952        # Return the number of connected peers, corresponding the the
1953        # length of the elements.
1954        return len(self.elements)
1955
1956    # for config.ini, print peer's name (not ours)
1957    def ini_str(self):
1958        return ' '.join([el.ini_str() for el in self.elements])
1959
1960    # for config.json
1961    def get_config_as_dict(self):
1962        return {'role' : self.role,
1963                'peer' : [el.ini_str() for el in self.elements]}
1964
1965    def __getitem__(self, key):
1966        if not isinstance(key, int):
1967            raise TypeError, "VectorPort index must be integer"
1968        if key >= len(self.elements):
1969            # need to extend list
1970            ext = [VectorPortElementRef(self.simobj, self.name, self.role, i)
1971                   for i in range(len(self.elements), key+1)]
1972            self.elements.extend(ext)
1973        return self.elements[key]
1974
1975    def _get_next(self):
1976        return self[len(self.elements)]
1977
1978    def __setitem__(self, key, value):
1979        if not isinstance(key, int):
1980            raise TypeError, "VectorPort index must be integer"
1981        self[key].connect(value)
1982
1983    def connect(self, other):
1984        if isinstance(other, (list, tuple)):
1985            # Assign list of port refs to vector port.
1986            # For now, append them... not sure if that's the right semantics
1987            # or if it should replace the current vector.
1988            for ref in other:
1989                self._get_next().connect(ref)
1990        else:
1991            # scalar assignment to plain VectorPort is implicit append
1992            self._get_next().connect(other)
1993
1994    def clone(self, simobj, memo):
1995        if memo.has_key(self):
1996            return memo[self]
1997        newRef = copy.copy(self)
1998        memo[self] = newRef
1999        newRef.simobj = simobj
2000        assert(isSimObject(newRef.simobj))
2001        newRef.elements = [el.clone(simobj, memo) for el in self.elements]
2002        return newRef
2003
2004    def unproxy(self, simobj):
2005        [el.unproxy(simobj) for el in self.elements]
2006
2007    def ccConnect(self):
2008        [el.ccConnect() for el in self.elements]
2009
2010# Port description object.  Like a ParamDesc object, this represents a
2011# logical port in the SimObject class, not a particular port on a
2012# SimObject instance.  The latter are represented by PortRef objects.
2013class Port(object):
2014    # Generate a PortRef for this port on the given SimObject with the
2015    # given name
2016    def makeRef(self, simobj):
2017        return PortRef(simobj, self.name, self.role)
2018
2019    # Connect an instance of this port (on the given SimObject with
2020    # the given name) with the port described by the supplied PortRef
2021    def connect(self, simobj, ref):
2022        self.makeRef(simobj).connect(ref)
2023
2024    # No need for any pre-declarations at the moment as we merely rely
2025    # on an unsigned int.
2026    def cxx_predecls(self, code):
2027        pass
2028
2029    # Declare an unsigned int with the same name as the port, that
2030    # will eventually hold the number of connected ports (and thus the
2031    # number of elements for a VectorPort).
2032    def cxx_decl(self, code):
2033        code('unsigned int port_${{self.name}}_connection_count;')
2034
2035class MasterPort(Port):
2036    # MasterPort("description")
2037    def __init__(self, *args):
2038        if len(args) == 1:
2039            self.desc = args[0]
2040            self.role = 'MASTER'
2041        else:
2042            raise TypeError, 'wrong number of arguments'
2043
2044class SlavePort(Port):
2045    # SlavePort("description")
2046    def __init__(self, *args):
2047        if len(args) == 1:
2048            self.desc = args[0]
2049            self.role = 'SLAVE'
2050        else:
2051            raise TypeError, 'wrong number of arguments'
2052
2053# VectorPort description object.  Like Port, but represents a vector
2054# of connections (e.g., as on a XBar).
2055class VectorPort(Port):
2056    def __init__(self, *args):
2057        self.isVec = True
2058
2059    def makeRef(self, simobj):
2060        return VectorPortRef(simobj, self.name, self.role)
2061
2062class VectorMasterPort(VectorPort):
2063    # VectorMasterPort("description")
2064    def __init__(self, *args):
2065        if len(args) == 1:
2066            self.desc = args[0]
2067            self.role = 'MASTER'
2068            VectorPort.__init__(self, *args)
2069        else:
2070            raise TypeError, 'wrong number of arguments'
2071
2072class VectorSlavePort(VectorPort):
2073    # VectorSlavePort("description")
2074    def __init__(self, *args):
2075        if len(args) == 1:
2076            self.desc = args[0]
2077            self.role = 'SLAVE'
2078            VectorPort.__init__(self, *args)
2079        else:
2080            raise TypeError, 'wrong number of arguments'
2081
2082# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
2083# proxy objects (via set_param_desc()) so that proxy error messages
2084# make sense.
2085class PortParamDesc(object):
2086    __metaclass__ = Singleton
2087
2088    ptype_str = 'Port'
2089    ptype = Port
2090
2091baseEnums = allEnums.copy()
2092baseParams = allParams.copy()
2093
2094def clear():
2095    global allEnums, allParams
2096
2097    allEnums = baseEnums.copy()
2098    allParams = baseParams.copy()
2099
2100__all__ = ['Param', 'VectorParam',
2101           'Enum', 'Bool', 'String', 'Float',
2102           'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
2103           'Int32', 'UInt32', 'Int64', 'UInt64',
2104           'Counter', 'Addr', 'Tick', 'Percent',
2105           'TcpPort', 'UdpPort', 'EthernetAddr',
2106           'IpAddress', 'IpNetmask', 'IpWithPort',
2107           'MemorySize', 'MemorySize32',
2108           'Latency', 'Frequency', 'Clock', 'Voltage',
2109           'NetworkBandwidth', 'MemoryBandwidth',
2110           'AddrRange',
2111           'MaxAddr', 'MaxTick', 'AllMemory',
2112           'Time',
2113           'NextEthernetAddr', 'NULL',
2114           'MasterPort', 'SlavePort',
2115           'VectorMasterPort', 'VectorSlavePort']
2116
2117import SimObject
2118