params.py revision 10181:6270235e0585
16167SN/A# Copyright (c) 2012-2013 ARM Limited
26167SN/A# All rights reserved.
36167SN/A#
410036SAli.Saidi@ARM.com# The license below extends only to copyright in the software and shall
58835SAli.Saidi@ARM.com# not be construed as granting a license to any other intellectual
610036SAli.Saidi@ARM.com# property including but not limited to intellectual property relating
77935SN/A# to a hardware implementation of the functionality of the software
87935SN/A# licensed hereunder.  You may use the software subject to the license
97935SN/A# terms below provided that you ensure that this notice is replicated
106167SN/A# unmodified and in its entirety in all distributions of the software,
116167SN/A# modified or unmodified, in source code or in binary form.
126167SN/A#
1310526Snilay@cs.wisc.edu# Copyright (c) 2004-2006 The Regents of The University of Michigan
148835SAli.Saidi@ARM.com# Copyright (c) 2010-2011 Advanced Micro Devices, Inc.
159864Snilay@cs.wisc.edu# All rights reserved.
169864Snilay@cs.wisc.edu#
1710036SAli.Saidi@ARM.com# Redistribution and use in source and binary forms, with or without
188835SAli.Saidi@ARM.com# modification, are permitted provided that the following conditions are
198835SAli.Saidi@ARM.com# met: redistributions of source code must retain the above copyright
2010315Snilay@cs.wisc.edu# notice, this list of conditions and the following disclaimer;
218835SAli.Saidi@ARM.com# redistributions in binary form must reproduce the above copyright
2210093Snilay@cs.wisc.edu# notice, this list of conditions and the following disclaimer in the
237935SN/A# documentation and/or other materials provided with the distribution;
249864Snilay@cs.wisc.edu# neither the name of the copyright holders nor the names of its
2510526Snilay@cs.wisc.edu# contributors may be used to endorse or promote products derived from
2610736Snilay@cs.wisc.edu# this software without specific prior written permission.
278721SN/A#
288835SAli.Saidi@ARM.com# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
298835SAli.Saidi@ARM.com# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
307935SN/A# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
317935SN/A# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
327935SN/A# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
337935SN/A# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
347935SN/A# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
357935SN/A# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
367935SN/A# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
378983Snate@binkert.org# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
386167SN/A# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
399864Snilay@cs.wisc.edu#
409864Snilay@cs.wisc.edu# Authors: Steve Reinhardt
419864Snilay@cs.wisc.edu#          Nathan Binkert
4210315Snilay@cs.wisc.edu#          Gabe Black
4310036SAli.Saidi@ARM.com#          Andreas Hansson
4410315Snilay@cs.wisc.edu
459864Snilay@cs.wisc.edu#####################################################################
469864Snilay@cs.wisc.edu#
476167SN/A# Parameter description classes
486167SN/A#
499864Snilay@cs.wisc.edu# The _params dictionary in each class maps parameter names to either
5010093Snilay@cs.wisc.edu# a Param or a VectorParam object.  These objects contain the
516167SN/A# parameter description string, the parameter type, and the default
529864Snilay@cs.wisc.edu# value (if any).  The convert() method on these objects is used to
536167SN/A# force whatever value is assigned to the parameter to the appropriate
546167SN/A# type.
558835SAli.Saidi@ARM.com#
566167SN/A# Note that the default values are loaded into the class's attribute
576167SN/A# space when the parameter dictionary is initialized (in
5810036SAli.Saidi@ARM.com# MetaSimObject._new_param()); after that point they aren't used.
596167SN/A#
606167SN/A#####################################################################
618835SAli.Saidi@ARM.com
629469Snilay@cs.wisc.eduimport copy
636167SN/Aimport datetime
646167SN/Aimport re
656167SN/Aimport sys
666167SN/Aimport time
676167SN/Aimport math
686167SN/A
698835SAli.Saidi@ARM.comimport proxy
706167SN/Aimport ticks
719864Snilay@cs.wisc.edufrom util import *
7210229Snilay@cs.wisc.edu
739469Snilay@cs.wisc.edudef isSimObject(*args, **kwargs):
746167SN/A    return SimObject.isSimObject(*args, **kwargs)
756167SN/A
766167SN/Adef isSimObjectSequence(*args, **kwargs):
779469Snilay@cs.wisc.edu    return SimObject.isSimObjectSequence(*args, **kwargs)
789469Snilay@cs.wisc.edu
796167SN/Adef isSimObjectClass(*args, **kwargs):
809864Snilay@cs.wisc.edu    return SimObject.isSimObjectClass(*args, **kwargs)
819864Snilay@cs.wisc.edu
829864Snilay@cs.wisc.eduallParams = {}
8310315Snilay@cs.wisc.edu
8410036SAli.Saidi@ARM.comclass MetaParamValue(type):
8510315Snilay@cs.wisc.edu    def __new__(mcls, name, bases, dct):
869864Snilay@cs.wisc.edu        cls = super(MetaParamValue, mcls).__new__(mcls, name, bases, dct)
879864Snilay@cs.wisc.edu        assert name not in allParams
886167SN/A        allParams[name] = cls
896167SN/A        return cls
9010036SAli.Saidi@ARM.com
916167SN/A
926167SN/A# Dummy base class to identify types that are legitimate for SimObject
938835SAli.Saidi@ARM.com# parameters.
948835SAli.Saidi@ARM.comclass ParamValue(object):
9510036SAli.Saidi@ARM.com    __metaclass__ = MetaParamValue
968835SAli.Saidi@ARM.com
979469Snilay@cs.wisc.edu
989469Snilay@cs.wisc.edu    # Generate the code needed as a prerequisite for declaring a C++
9910036SAli.Saidi@ARM.com    # object of this type.  Typically generates one or more #include
1009469Snilay@cs.wisc.edu    # statements.  Used when declaring parameters of this type.
1019469Snilay@cs.wisc.edu    @classmethod
10210036SAli.Saidi@ARM.com    def cxx_predecls(cls, code):
1039469Snilay@cs.wisc.edu        pass
1046167SN/A
1056167SN/A    # Generate the code needed as a prerequisite for including a
10610036SAli.Saidi@ARM.com    # reference to a C++ object of this type in a SWIG .i file.
1076167SN/A    # Typically generates one or more %import or %include statements.
1086167SN/A    @classmethod
1096167SN/A    def swig_predecls(cls, code):
1106167SN/A        pass
11110036SAli.Saidi@ARM.com
1126167SN/A    # default for printing to .ini file is regular string conversion.
1136167SN/A    # will be overridden in some cases
1146167SN/A    def ini_str(self):
1156167SN/A        return str(self)
1166167SN/A
11710736Snilay@cs.wisc.edu    # allows us to blithely call unproxy() on things without checking
1186167SN/A    # if they're really proxies or not
1196167SN/A    def unproxy(self, base):
1206167SN/A        return self
1216167SN/A
12210036SAli.Saidi@ARM.com# Regular parameter description.
12311066Snilay@cs.wisc.educlass ParamDesc(object):
1246167SN/A    def __init__(self, ptype_str, ptype, *args, **kwargs):
1256167SN/A        self.ptype_str = ptype_str
12610736Snilay@cs.wisc.edu        # remember ptype only if it is provided
1276167SN/A        if ptype != None:
1286167SN/A            self.ptype = ptype
1296167SN/A
1306167SN/A        if args:
1316167SN/A            if len(args) == 1:
1326167SN/A                self.desc = args[0]
1336167SN/A            elif len(args) == 2:
13410451Snilay@cs.wisc.edu                self.default = args[0]
1356167SN/A                self.desc = args[1]
13610315Snilay@cs.wisc.edu            else:
13710315Snilay@cs.wisc.edu                raise TypeError, 'too many arguments'
13810315Snilay@cs.wisc.edu
13910315Snilay@cs.wisc.edu        if kwargs.has_key('desc'):
14010315Snilay@cs.wisc.edu            assert(not hasattr(self, 'desc'))
14110315Snilay@cs.wisc.edu            self.desc = kwargs['desc']
14210315Snilay@cs.wisc.edu            del kwargs['desc']
14310315Snilay@cs.wisc.edu
14410526Snilay@cs.wisc.edu        if kwargs.has_key('default'):
14510526Snilay@cs.wisc.edu            assert(not hasattr(self, 'default'))
14610526Snilay@cs.wisc.edu            self.default = kwargs['default']
14710526Snilay@cs.wisc.edu            del kwargs['default']
14810526Snilay@cs.wisc.edu
14910526Snilay@cs.wisc.edu        if kwargs:
15010526Snilay@cs.wisc.edu            raise TypeError, 'extra unknown kwargs %s' % kwargs
15110526Snilay@cs.wisc.edu
15210526Snilay@cs.wisc.edu        if not hasattr(self, 'desc'):
15310526Snilay@cs.wisc.edu            raise TypeError, 'desc attribute missing'
15410526Snilay@cs.wisc.edu
15510526Snilay@cs.wisc.edu    def __getattr__(self, attr):
15610526Snilay@cs.wisc.edu        if attr == 'ptype':
15710526Snilay@cs.wisc.edu            ptype = SimObject.allClasses[self.ptype_str]
15810526Snilay@cs.wisc.edu            assert isSimObjectClass(ptype)
15910526Snilay@cs.wisc.edu            self.ptype = ptype
16010526Snilay@cs.wisc.edu            return ptype
16110526Snilay@cs.wisc.edu
16210526Snilay@cs.wisc.edu        raise AttributeError, "'%s' object has no attribute '%s'" % \
16310526Snilay@cs.wisc.edu              (type(self).__name__, attr)
16410526Snilay@cs.wisc.edu
16510526Snilay@cs.wisc.edu    def convert(self, value):
16610526Snilay@cs.wisc.edu        if isinstance(value, proxy.BaseProxy):
16710526Snilay@cs.wisc.edu            value.set_param_desc(self)
16810526Snilay@cs.wisc.edu            return value
16910526Snilay@cs.wisc.edu        if not hasattr(self, 'ptype') and isNullPointer(value):
17010526Snilay@cs.wisc.edu            # deferred evaluation of SimObject; continue to defer if
17110736Snilay@cs.wisc.edu            # we're just assigning a null pointer
17210526Snilay@cs.wisc.edu            return value
17310526Snilay@cs.wisc.edu        if isinstance(value, self.ptype):
17410526Snilay@cs.wisc.edu            return value
17510526Snilay@cs.wisc.edu        if isNullPointer(value) and isSimObjectClass(self.ptype):
1769864Snilay@cs.wisc.edu            return value
1779864Snilay@cs.wisc.edu        return self.ptype(value)
17810526Snilay@cs.wisc.edu
17910526Snilay@cs.wisc.edu    def cxx_predecls(self, code):
18010526Snilay@cs.wisc.edu        code('#include <cstddef>')
18110526Snilay@cs.wisc.edu        self.ptype.cxx_predecls(code)
18210526Snilay@cs.wisc.edu
18310036SAli.Saidi@ARM.com    def swig_predecls(self, code):
1849469Snilay@cs.wisc.edu        self.ptype.swig_predecls(code)
18510526Snilay@cs.wisc.edu
18610526Snilay@cs.wisc.edu    def cxx_decl(self, code):
18710526Snilay@cs.wisc.edu        code('${{self.ptype.cxx_type}} ${{self.name}};')
18810526Snilay@cs.wisc.edu
18910526Snilay@cs.wisc.edu# Vector-valued parameter description.  Just like ParamDesc, except
19010526Snilay@cs.wisc.edu# that the value is a vector (list) of the specified type instead of a
19110526Snilay@cs.wisc.edu# single value.
19210526Snilay@cs.wisc.edu
19310526Snilay@cs.wisc.educlass VectorParamValue(list):
19410526Snilay@cs.wisc.edu    __metaclass__ = MetaParamValue
19510526Snilay@cs.wisc.edu    def __setattr__(self, attr, value):
19610526Snilay@cs.wisc.edu        raise AttributeError, \
19710526Snilay@cs.wisc.edu              "Not allowed to set %s on '%s'" % (attr, type(self).__name__)
19810526Snilay@cs.wisc.edu
19910526Snilay@cs.wisc.edu    def ini_str(self):
20010526Snilay@cs.wisc.edu        return ' '.join([v.ini_str() for v in self])
20110526Snilay@cs.wisc.edu
20210526Snilay@cs.wisc.edu    def getValue(self):
20310526Snilay@cs.wisc.edu        return [ v.getValue() for v in self ]
20410526Snilay@cs.wisc.edu
20510526Snilay@cs.wisc.edu    def unproxy(self, base):
20610526Snilay@cs.wisc.edu        if len(self) == 1 and isinstance(self[0], proxy.AllProxy):
20710526Snilay@cs.wisc.edu            return self[0].unproxy(base)
20810526Snilay@cs.wisc.edu        else:
20910526Snilay@cs.wisc.edu             return [v.unproxy(base) for v in self]
21010526Snilay@cs.wisc.edu
21110526Snilay@cs.wisc.educlass SimObjectVector(VectorParamValue):
21210526Snilay@cs.wisc.edu    # support clone operation
21310526Snilay@cs.wisc.edu    def __call__(self, **kwargs):
21410526Snilay@cs.wisc.edu        return SimObjectVector([v(**kwargs) for v in self])
21510526Snilay@cs.wisc.edu
21610526Snilay@cs.wisc.edu    def clear_parent(self, old_parent):
21710526Snilay@cs.wisc.edu        for v in self:
21810526Snilay@cs.wisc.edu            v.clear_parent(old_parent)
21910526Snilay@cs.wisc.edu
2209469Snilay@cs.wisc.edu    def set_parent(self, parent, name):
2219469Snilay@cs.wisc.edu        if len(self) == 1:
2229469Snilay@cs.wisc.edu            self[0].set_parent(parent, name)
22310036SAli.Saidi@ARM.com        else:
22410736Snilay@cs.wisc.edu            width = int(math.ceil(math.log(len(self))/math.log(10)))
22510036SAli.Saidi@ARM.com            for i,v in enumerate(self):
2269469Snilay@cs.wisc.edu                v.set_parent(parent, "%s%0*d" % (name, width, i))
2279864Snilay@cs.wisc.edu
22810036SAli.Saidi@ARM.com    def has_parent(self):
22910036SAli.Saidi@ARM.com        return reduce(lambda x,y: x and y, [v.has_parent() for v in self])
23010526Snilay@cs.wisc.edu
23110036SAli.Saidi@ARM.com    # return 'cpu0 cpu1' etc. for print_ini()
23210526Snilay@cs.wisc.edu    def get_name(self):
2339469Snilay@cs.wisc.edu        return ' '.join([v._name for v in self])
2349469Snilay@cs.wisc.edu
2359469Snilay@cs.wisc.edu    # By iterating through the constituent members of the vector here
2369864Snilay@cs.wisc.edu    # we can nicely handle iterating over all a SimObject's children
2379864Snilay@cs.wisc.edu    # without having to provide lots of special functions on
2389864Snilay@cs.wisc.edu    # SimObjectVector directly.
23910315Snilay@cs.wisc.edu    def descendants(self):
24010036SAli.Saidi@ARM.com        for v in self:
24110315Snilay@cs.wisc.edu            for obj in v.descendants():
2429864Snilay@cs.wisc.edu                yield obj
2439864Snilay@cs.wisc.edu
2449469Snilay@cs.wisc.edu    def get_config_as_dict(self):
2456928SN/A        a = []
24611023Sjthestness@gmail.com        for v in self:
2476928SN/A            a.append(v.get_config_as_dict())
2489864Snilay@cs.wisc.edu        return a
24910036SAli.Saidi@ARM.com
2509469Snilay@cs.wisc.edu    # If we are replacing an item in the vector, make sure to set the
2516928SN/A    # parent reference of the new SimObject to be the same as the parent
25211023Sjthestness@gmail.com    # of the SimObject being replaced. Useful to have if we created
25311023Sjthestness@gmail.com    # a SimObjectVector of temporary objects that will be modified later in
25410036SAli.Saidi@ARM.com    # configuration scripts.
25511023Sjthestness@gmail.com    def __setitem__(self, key, value):
2566928SN/A        val = self[key]
2576928SN/A        if value.has_parent():
25811023Sjthestness@gmail.com            warn("SimObject %s already has a parent" % value.get_name() +\
25911023Sjthestness@gmail.com                 " that is being overwritten by a SimObjectVector")
26011023Sjthestness@gmail.com        value.set_parent(val.get_parent(), val._name)
2618540SN/A        super(SimObjectVector, self).__setitem__(key, value)
26210526Snilay@cs.wisc.edu
26310526Snilay@cs.wisc.educlass VectorParamDesc(ParamDesc):
2649864Snilay@cs.wisc.edu    # Convert assigned value to appropriate type.  If the RHS is not a
2656928SN/A    # list or tuple, it generates a single-element list.
26610526Snilay@cs.wisc.edu    def convert(self, value):
2676928SN/A        if isinstance(value, (list, tuple)):
2689469Snilay@cs.wisc.edu            # list: coerce each element into new list
2696928SN/A            tmp_list = [ ParamDesc.convert(self, v) for v in value ]
27010036SAli.Saidi@ARM.com        else:
2719469Snilay@cs.wisc.edu            # singleton: coerce to a single-element list
2729864Snilay@cs.wisc.edu            tmp_list = [ ParamDesc.convert(self, value) ]
2736928SN/A
2746928SN/A        if isSimObjectSequence(tmp_list):
27511023Sjthestness@gmail.com            return SimObjectVector(tmp_list)
27611023Sjthestness@gmail.com        else:
27711023Sjthestness@gmail.com            return VectorParamValue(tmp_list)
27811023Sjthestness@gmail.com
27911023Sjthestness@gmail.com    def swig_module_name(self):
28011023Sjthestness@gmail.com        return "%s_vector" % self.ptype_str
28111023Sjthestness@gmail.com
28211023Sjthestness@gmail.com    def swig_predecls(self, code):
28311023Sjthestness@gmail.com        code('%import "${{self.swig_module_name()}}.i"')
28411023Sjthestness@gmail.com
28511023Sjthestness@gmail.com    def swig_decl(self, code):
28611023Sjthestness@gmail.com        code('%module(package="m5.internal") ${{self.swig_module_name()}}')
28711023Sjthestness@gmail.com        code('%{')
28811023Sjthestness@gmail.com        self.ptype.cxx_predecls(code)
28911023Sjthestness@gmail.com        code('%}')
29011023Sjthestness@gmail.com        code()
29111023Sjthestness@gmail.com        # Make sure the SWIGPY_SLICE_ARG is defined through this inclusion
29211023Sjthestness@gmail.com        code('%include "std_container.i"')
29311023Sjthestness@gmail.com        code()
29411023Sjthestness@gmail.com        self.ptype.swig_predecls(code)
29511023Sjthestness@gmail.com        code()
29611023Sjthestness@gmail.com        code('%include "std_vector.i"')
29711023Sjthestness@gmail.com        code()
29811023Sjthestness@gmail.com
29911023Sjthestness@gmail.com        ptype = self.ptype_str
30011023Sjthestness@gmail.com        cxx_type = self.ptype.cxx_type
30111023Sjthestness@gmail.com
30211023Sjthestness@gmail.com        code('%template(vector_$ptype) std::vector< $cxx_type >;')
30311023Sjthestness@gmail.com
30411023Sjthestness@gmail.com    def cxx_predecls(self, code):
30511023Sjthestness@gmail.com        code('#include <vector>')
30611023Sjthestness@gmail.com        self.ptype.cxx_predecls(code)
30711023Sjthestness@gmail.com
30811023Sjthestness@gmail.com    def cxx_decl(self, code):
30911023Sjthestness@gmail.com        code('std::vector< ${{self.ptype.cxx_type}} > ${{self.name}};')
31011023Sjthestness@gmail.com
31111023Sjthestness@gmail.comclass ParamFactory(object):
31211023Sjthestness@gmail.com    def __init__(self, param_desc_class, ptype_str = None):
31311023Sjthestness@gmail.com        self.param_desc_class = param_desc_class
31411023Sjthestness@gmail.com        self.ptype_str = ptype_str
31511023Sjthestness@gmail.com
31611023Sjthestness@gmail.com    def __getattr__(self, attr):
31711023Sjthestness@gmail.com        if self.ptype_str:
31811023Sjthestness@gmail.com            attr = self.ptype_str + '.' + attr
31911023Sjthestness@gmail.com        return ParamFactory(self.param_desc_class, attr)
32011023Sjthestness@gmail.com
32111023Sjthestness@gmail.com    # E.g., Param.Int(5, "number of widgets")
32211023Sjthestness@gmail.com    def __call__(self, *args, **kwargs):
32311023Sjthestness@gmail.com        ptype = None
32411023Sjthestness@gmail.com        try:
32511023Sjthestness@gmail.com            ptype = allParams[self.ptype_str]
32611023Sjthestness@gmail.com        except KeyError:
32711023Sjthestness@gmail.com            # if name isn't defined yet, assume it's a SimObject, and
3289469Snilay@cs.wisc.edu            # try to resolve it later
3297935SN/A            pass
33011023Sjthestness@gmail.com        return self.param_desc_class(self.ptype_str, ptype, *args, **kwargs)
3317935SN/A
3329469Snilay@cs.wisc.eduParam = ParamFactory(ParamDesc)
3337935SN/AVectorParam = ParamFactory(VectorParamDesc)
33410315Snilay@cs.wisc.edu
33510036SAli.Saidi@ARM.com#####################################################################
33610036SAli.Saidi@ARM.com#
33711023Sjthestness@gmail.com# Parameter Types
3387935SN/A#
33911023Sjthestness@gmail.com# Though native Python types could be used to specify parameter types
3407935SN/A# (the 'ptype' field of the Param and VectorParam classes), it's more
3417935SN/A# flexible to define our own set of types.  This gives us more control
34211023Sjthestness@gmail.com# over how Python expressions are converted to values (via the
34311023Sjthestness@gmail.com# __init__() constructor) and how these values are printed out (via
34411023Sjthestness@gmail.com# the __str__() conversion method).
3458540SN/A#
3468835SAli.Saidi@ARM.com#####################################################################
3479469Snilay@cs.wisc.edu
34810526Snilay@cs.wisc.edu# String-valued parameter.  Just mixin the ParamValue class with the
3499864Snilay@cs.wisc.edu# built-in str class.
3507935SN/Aclass String(ParamValue,str):
3517935SN/A    cxx_type = 'std::string'
3529469Snilay@cs.wisc.edu
3538540SN/A    @classmethod
35411023Sjthestness@gmail.com    def cxx_predecls(self, code):
3558540SN/A        code('#include <string>')
3569113SBrad.Beckmann@amd.com
3579113SBrad.Beckmann@amd.com    @classmethod
35810036SAli.Saidi@ARM.com    def swig_predecls(cls, code):
3598721SN/A        code('%include "std_string.i"')
36011023Sjthestness@gmail.com
3619113SBrad.Beckmann@amd.com    def getValue(self):
36211023Sjthestness@gmail.com        return self
3638540SN/A
3648540SN/A# superclass for "numeric" parameter values, to emulate math
3659113SBrad.Beckmann@amd.com# operations in a type-safe way.  e.g., a Latency times an int returns
3669113SBrad.Beckmann@amd.com# a new Latency object.
3678540SN/Aclass NumericParamValue(ParamValue):
36811023Sjthestness@gmail.com    def __str__(self):
36911023Sjthestness@gmail.com        return str(self.value)
37011023Sjthestness@gmail.com
37111023Sjthestness@gmail.com    def __float__(self):
37211023Sjthestness@gmail.com        return float(self.value)
37311023Sjthestness@gmail.com
37411023Sjthestness@gmail.com    def __long__(self):
37511023Sjthestness@gmail.com        return long(self.value)
37611023Sjthestness@gmail.com
37711023Sjthestness@gmail.com    def __int__(self):
37811023Sjthestness@gmail.com        return int(self.value)
37911023Sjthestness@gmail.com
38011023Sjthestness@gmail.com    # hook for bounds checking
38111023Sjthestness@gmail.com    def _check(self):
38211023Sjthestness@gmail.com        return
38311023Sjthestness@gmail.com
38411023Sjthestness@gmail.com    def __mul__(self, other):
38511023Sjthestness@gmail.com        newobj = self.__class__(self)
38611023Sjthestness@gmail.com        newobj.value *= other
38711023Sjthestness@gmail.com        newobj._check()
38811023Sjthestness@gmail.com        return newobj
38911023Sjthestness@gmail.com
39011023Sjthestness@gmail.com    __rmul__ = __mul__
39111023Sjthestness@gmail.com
39211023Sjthestness@gmail.com    def __div__(self, other):
39311023Sjthestness@gmail.com        newobj = self.__class__(self)
39411023Sjthestness@gmail.com        newobj.value /= other
39511023Sjthestness@gmail.com        newobj._check()
39611023Sjthestness@gmail.com        return newobj
39711023Sjthestness@gmail.com
39811023Sjthestness@gmail.com    def __sub__(self, other):
39911023Sjthestness@gmail.com        newobj = self.__class__(self)
40011023Sjthestness@gmail.com        newobj.value -= other
40111023Sjthestness@gmail.com        newobj._check()
40211023Sjthestness@gmail.com        return newobj
40311023Sjthestness@gmail.com
40411023Sjthestness@gmail.com# Metaclass for bounds-checked integer parameters.  See CheckedInt.
40511023Sjthestness@gmail.comclass CheckedIntType(MetaParamValue):
40611023Sjthestness@gmail.com    def __init__(cls, name, bases, dict):
40711023Sjthestness@gmail.com        super(CheckedIntType, cls).__init__(name, bases, dict)
40811023Sjthestness@gmail.com
40911023Sjthestness@gmail.com        # CheckedInt is an abstract base class, so we actually don't
41011023Sjthestness@gmail.com        # want to do any processing on it... the rest of this code is
41111023Sjthestness@gmail.com        # just for classes that derive from CheckedInt.
41211023Sjthestness@gmail.com        if name == 'CheckedInt':
41311023Sjthestness@gmail.com            return
41411023Sjthestness@gmail.com
41511023Sjthestness@gmail.com        if not (hasattr(cls, 'min') and hasattr(cls, 'max')):
41611023Sjthestness@gmail.com            if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')):
41711023Sjthestness@gmail.com                panic("CheckedInt subclass %s must define either\n" \
41811023Sjthestness@gmail.com                      "    'min' and 'max' or 'size' and 'unsigned'\n",
4199469Snilay@cs.wisc.edu                      name);
4208540SN/A            if cls.unsigned:
42110315Snilay@cs.wisc.edu                cls.min = 0
4229469Snilay@cs.wisc.edu                cls.max = 2 ** cls.size - 1
42311023Sjthestness@gmail.com            else:
4248540SN/A                cls.min = -(2 ** (cls.size - 1))
42510036SAli.Saidi@ARM.com                cls.max = (2 ** (cls.size - 1)) - 1
4269469Snilay@cs.wisc.edu
42711023Sjthestness@gmail.com# Abstract superclass for bounds-checked integer parameters.  This
4288540SN/A# class is subclassed to generate parameter classes with specific
4298540SN/A# bounds.  Initialization of the min and max bounds is done in the
4308983Snate@binkert.org# metaclass CheckedIntType.__init__.
4318983Snate@binkert.orgclass CheckedInt(NumericParamValue):
4328983Snate@binkert.org    __metaclass__ = CheckedIntType
4338540SN/A
4348540SN/A    def _check(self):
4358540SN/A        if not self.min <= self.value <= self.max:
4368983Snate@binkert.org            raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
4378540SN/A                  (self.min, self.value, self.max)
4389864Snilay@cs.wisc.edu
4399864Snilay@cs.wisc.edu    def __init__(self, value):
4409864Snilay@cs.wisc.edu        if isinstance(value, str):
4419864Snilay@cs.wisc.edu            self.value = convert.toInteger(value)
44210036SAli.Saidi@ARM.com        elif isinstance(value, (int, long, float, NumericParamValue)):
4439864Snilay@cs.wisc.edu            self.value = long(value)
4447935SN/A        else:
4457935SN/A            raise TypeError, "Can't convert object of type %s to CheckedInt" \
44611066Snilay@cs.wisc.edu                  % type(value).__name__
4477935SN/A        self._check()
4487935SN/A
4499864Snilay@cs.wisc.edu    @classmethod
4507935SN/A    def cxx_predecls(cls, code):
4518540SN/A        # most derived types require this, so we just do it here once
45210036SAli.Saidi@ARM.com        code('#include "base/types.hh"')
4539605Snilay@cs.wisc.edu
45411066Snilay@cs.wisc.edu    @classmethod
4559605Snilay@cs.wisc.edu    def swig_predecls(cls, code):
45610229Snilay@cs.wisc.edu        # most derived types require this, so we just do it here once
45711066Snilay@cs.wisc.edu        code('%import "stdint.i"')
45811023Sjthestness@gmail.com        code('%import "base/types.hh"')
4599864Snilay@cs.wisc.edu
4608540SN/A    def getValue(self):
4619605Snilay@cs.wisc.edu        return long(self.value)
46211023Sjthestness@gmail.com
46311023Sjthestness@gmail.comclass Int(CheckedInt):      cxx_type = 'int';      size = 32; unsigned = False
4647935SN/Aclass Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True
4659605Snilay@cs.wisc.edu
4668540SN/Aclass Int8(CheckedInt):     cxx_type =   'int8_t'; size =  8; unsigned = False
4678540SN/Aclass UInt8(CheckedInt):    cxx_type =  'uint8_t'; size =  8; unsigned = True
46810036SAli.Saidi@ARM.comclass Int16(CheckedInt):    cxx_type =  'int16_t'; size = 16; unsigned = False
4699469Snilay@cs.wisc.educlass UInt16(CheckedInt):   cxx_type = 'uint16_t'; size = 16; unsigned = True
4709864Snilay@cs.wisc.educlass Int32(CheckedInt):    cxx_type =  'int32_t'; size = 32; unsigned = False
4717935SN/Aclass UInt32(CheckedInt):   cxx_type = 'uint32_t'; size = 32; unsigned = True
4728540SN/Aclass Int64(CheckedInt):    cxx_type =  'int64_t'; size = 64; unsigned = False
4737935SN/Aclass UInt64(CheckedInt):   cxx_type = 'uint64_t'; size = 64; unsigned = True
4747935SN/A
4759605Snilay@cs.wisc.educlass Counter(CheckedInt):  cxx_type = 'Counter';  size = 64; unsigned = True
4768540SN/Aclass Tick(CheckedInt):     cxx_type = 'Tick';     size = 64; unsigned = True
4778540SN/Aclass TcpPort(CheckedInt):  cxx_type = 'uint16_t'; size = 16; unsigned = True
47810036SAli.Saidi@ARM.comclass UdpPort(CheckedInt):  cxx_type = 'uint16_t'; size = 16; unsigned = True
4799469Snilay@cs.wisc.edu
4809864Snilay@cs.wisc.educlass Percent(CheckedInt):  cxx_type = 'int'; min = 0; max = 100
4817935SN/A
4828540SN/Aclass Cycles(CheckedInt):
4837935SN/A    cxx_type = 'Cycles'
4847935SN/A    size = 64
48511023Sjthestness@gmail.com    unsigned = True
48611023Sjthestness@gmail.com
48711023Sjthestness@gmail.com    def getValue(self):
48811023Sjthestness@gmail.com        from m5.internal.core import Cycles
48911023Sjthestness@gmail.com        return Cycles(self.value)
49011023Sjthestness@gmail.com
49111023Sjthestness@gmail.comclass Float(ParamValue, float):
49211023Sjthestness@gmail.com    cxx_type = 'double'
49311023Sjthestness@gmail.com
49411023Sjthestness@gmail.com    def __init__(self, value):
49511023Sjthestness@gmail.com        if isinstance(value, (int, long, float, NumericParamValue, Float)):
49611023Sjthestness@gmail.com            self.value = float(value)
49711023Sjthestness@gmail.com        else:
49811023Sjthestness@gmail.com            raise TypeError, "Can't convert object of type %s to Float" \
49911023Sjthestness@gmail.com                  % type(value).__name__
50011023Sjthestness@gmail.com
50111023Sjthestness@gmail.com    def getValue(self):
50211023Sjthestness@gmail.com        return float(self.value)
50311023Sjthestness@gmail.com
50411023Sjthestness@gmail.comclass MemorySize(CheckedInt):
50511023Sjthestness@gmail.com    cxx_type = 'uint64_t'
50611023Sjthestness@gmail.com    size = 64
50711023Sjthestness@gmail.com    unsigned = True
50811023Sjthestness@gmail.com    def __init__(self, value):
50911023Sjthestness@gmail.com        if isinstance(value, MemorySize):
51011023Sjthestness@gmail.com            self.value = value.value
51111023Sjthestness@gmail.com        else:
51211023Sjthestness@gmail.com            self.value = convert.toMemorySize(value)
51311023Sjthestness@gmail.com        self._check()
51411023Sjthestness@gmail.com
51511023Sjthestness@gmail.comclass MemorySize32(CheckedInt):
51611023Sjthestness@gmail.com    cxx_type = 'uint32_t'
51711023Sjthestness@gmail.com    size = 32
51811023Sjthestness@gmail.com    unsigned = True
51911023Sjthestness@gmail.com    def __init__(self, value):
52011023Sjthestness@gmail.com        if isinstance(value, MemorySize):
52111023Sjthestness@gmail.com            self.value = value.value
52211023Sjthestness@gmail.com        else:
52311023Sjthestness@gmail.com            self.value = convert.toMemorySize(value)
52411023Sjthestness@gmail.com        self._check()
52511023Sjthestness@gmail.com
52611023Sjthestness@gmail.comclass Addr(CheckedInt):
52711023Sjthestness@gmail.com    cxx_type = 'Addr'
52811023Sjthestness@gmail.com    size = 64
52911023Sjthestness@gmail.com    unsigned = True
53011023Sjthestness@gmail.com    def __init__(self, value):
53111023Sjthestness@gmail.com        if isinstance(value, Addr):
53211023Sjthestness@gmail.com            self.value = value.value
53311023Sjthestness@gmail.com        else:
53411023Sjthestness@gmail.com            try:
53511023Sjthestness@gmail.com                self.value = convert.toMemorySize(value)
53611023Sjthestness@gmail.com            except TypeError:
53711023Sjthestness@gmail.com                self.value = long(value)
53811023Sjthestness@gmail.com        self._check()
53911023Sjthestness@gmail.com    def __add__(self, other):
54011023Sjthestness@gmail.com        if isinstance(other, Addr):
54111023Sjthestness@gmail.com            return self.value + other.value
54211023Sjthestness@gmail.com        else:
54311023Sjthestness@gmail.com            return self.value + other
54411023Sjthestness@gmail.com
54511023Sjthestness@gmail.comclass AddrRange(ParamValue):
54611023Sjthestness@gmail.com    cxx_type = 'AddrRange'
54711023Sjthestness@gmail.com
54811023Sjthestness@gmail.com    def __init__(self, *args, **kwargs):
54911023Sjthestness@gmail.com        # Disable interleaving by default
55011023Sjthestness@gmail.com        self.intlvHighBit = 0
55111023Sjthestness@gmail.com        self.intlvBits = 0
55211023Sjthestness@gmail.com        self.intlvMatch = 0
55311023Sjthestness@gmail.com
55411023Sjthestness@gmail.com        def handle_kwargs(self, kwargs):
55511023Sjthestness@gmail.com            # An address range needs to have an upper limit, specified
55611023Sjthestness@gmail.com            # either explicitly with an end, or as an offset using the
55711023Sjthestness@gmail.com            # size keyword.
55811023Sjthestness@gmail.com            if 'end' in kwargs:
55911023Sjthestness@gmail.com                self.end = Addr(kwargs.pop('end'))
56011023Sjthestness@gmail.com            elif 'size' in kwargs:
56111023Sjthestness@gmail.com                self.end = self.start + Addr(kwargs.pop('size')) - 1
56211023Sjthestness@gmail.com            else:
56311023Sjthestness@gmail.com                raise TypeError, "Either end or size must be specified"
56411023Sjthestness@gmail.com
56511023Sjthestness@gmail.com            # Now on to the optional bit
56611023Sjthestness@gmail.com            if 'intlvHighBit' in kwargs:
56711023Sjthestness@gmail.com                self.intlvHighBit = int(kwargs.pop('intlvHighBit'))
56811023Sjthestness@gmail.com            if 'intlvBits' in kwargs:
56911023Sjthestness@gmail.com                self.intlvBits = int(kwargs.pop('intlvBits'))
57011023Sjthestness@gmail.com            if 'intlvMatch' in kwargs:
57111023Sjthestness@gmail.com                self.intlvMatch = int(kwargs.pop('intlvMatch'))
57211023Sjthestness@gmail.com
57311023Sjthestness@gmail.com        if len(args) == 0:
57411023Sjthestness@gmail.com            self.start = Addr(kwargs.pop('start'))
57511023Sjthestness@gmail.com            handle_kwargs(self, kwargs)
57611023Sjthestness@gmail.com
57711023Sjthestness@gmail.com        elif len(args) == 1:
57811023Sjthestness@gmail.com            if kwargs:
57911023Sjthestness@gmail.com                self.start = Addr(args[0])
58011023Sjthestness@gmail.com                handle_kwargs(self, kwargs)
58111023Sjthestness@gmail.com            elif isinstance(args[0], (list, tuple)):
58211023Sjthestness@gmail.com                self.start = Addr(args[0][0])
58311023Sjthestness@gmail.com                self.end = Addr(args[0][1])
58411023Sjthestness@gmail.com            else:
58511023Sjthestness@gmail.com                self.start = Addr(0)
58611023Sjthestness@gmail.com                self.end = Addr(args[0]) - 1
58711023Sjthestness@gmail.com
58811023Sjthestness@gmail.com        elif len(args) == 2:
58911023Sjthestness@gmail.com            self.start = Addr(args[0])
59011023Sjthestness@gmail.com            self.end = Addr(args[1])
59111023Sjthestness@gmail.com        else:
59211023Sjthestness@gmail.com            raise TypeError, "Too many arguments specified"
59311023Sjthestness@gmail.com
59411023Sjthestness@gmail.com        if kwargs:
59511023Sjthestness@gmail.com            raise TypeError, "Too many keywords: %s" % kwargs.keys()
59611023Sjthestness@gmail.com
59711023Sjthestness@gmail.com    def __str__(self):
59811023Sjthestness@gmail.com        return '%s:%s' % (self.start, self.end)
59911023Sjthestness@gmail.com
60011023Sjthestness@gmail.com    def size(self):
60111023Sjthestness@gmail.com        # Divide the size by the size of the interleaving slice
60211023Sjthestness@gmail.com        return (long(self.end) - long(self.start) + 1) >> self.intlvBits
60311023Sjthestness@gmail.com
60411023Sjthestness@gmail.com    @classmethod
60511023Sjthestness@gmail.com    def cxx_predecls(cls, code):
60611023Sjthestness@gmail.com        Addr.cxx_predecls(code)
60711023Sjthestness@gmail.com        code('#include "base/addr_range.hh"')
60811023Sjthestness@gmail.com
60911023Sjthestness@gmail.com    @classmethod
61011023Sjthestness@gmail.com    def swig_predecls(cls, code):
61111023Sjthestness@gmail.com        Addr.swig_predecls(code)
61211023Sjthestness@gmail.com
61311023Sjthestness@gmail.com    def getValue(self):
61411023Sjthestness@gmail.com        # Go from the Python class to the wrapped C++ class generated
61511023Sjthestness@gmail.com        # by swig
61611023Sjthestness@gmail.com        from m5.internal.range import AddrRange
61711023Sjthestness@gmail.com
61811023Sjthestness@gmail.com        return AddrRange(long(self.start), long(self.end),
61911023Sjthestness@gmail.com                         int(self.intlvHighBit), int(self.intlvBits),
62011023Sjthestness@gmail.com                         int(self.intlvMatch))
62111023Sjthestness@gmail.com
62211023Sjthestness@gmail.com# Boolean parameter type.  Python doesn't let you subclass bool, since
62311023Sjthestness@gmail.com# it doesn't want to let you create multiple instances of True and
62411023Sjthestness@gmail.com# False.  Thus this is a little more complicated than String.
62511023Sjthestness@gmail.comclass Bool(ParamValue):
62611023Sjthestness@gmail.com    cxx_type = 'bool'
62711023Sjthestness@gmail.com    def __init__(self, value):
62811023Sjthestness@gmail.com        try:
62911023Sjthestness@gmail.com            self.value = convert.toBool(value)
63011023Sjthestness@gmail.com        except TypeError:
63111023Sjthestness@gmail.com            self.value = bool(value)
63211023Sjthestness@gmail.com
63311023Sjthestness@gmail.com    def getValue(self):
63411023Sjthestness@gmail.com        return bool(self.value)
63511023Sjthestness@gmail.com
63611023Sjthestness@gmail.com    def __str__(self):
63711023Sjthestness@gmail.com        return str(self.value)
63811023Sjthestness@gmail.com
63911023Sjthestness@gmail.com    # implement truth value testing for Bool parameters so that these params
64011023Sjthestness@gmail.com    # evaluate correctly during the python configuration phase
64111023Sjthestness@gmail.com    def __nonzero__(self):
64211023Sjthestness@gmail.com        return bool(self.value)
64311023Sjthestness@gmail.com
64411023Sjthestness@gmail.com    def ini_str(self):
6459605Snilay@cs.wisc.edu        if self.value:
6468540SN/A            return 'true'
6478540SN/A        return 'false'
64810036SAli.Saidi@ARM.com
6496928SN/Adef IncEthernetAddr(addr, val = 1):
6508540SN/A    bytes = map(lambda x: int(x, 16), addr.split(':'))
6519864Snilay@cs.wisc.edu    bytes[5] += val
6529864Snilay@cs.wisc.edu    for i in (5, 4, 3, 2, 1):
6536928SN/A        val,rem = divmod(bytes[i], 256)
6546928SN/A        bytes[i] = rem
6559605Snilay@cs.wisc.edu        if val == 0:
6568540SN/A            break
6578540SN/A        bytes[i - 1] += val
65810036SAli.Saidi@ARM.com    assert(bytes[0] <= 255)
6596928SN/A    return ':'.join(map(lambda x: '%02x' % x, bytes))
6608540SN/A
6619864Snilay@cs.wisc.edu_NextEthernetAddr = "00:90:00:00:00:01"
6629864Snilay@cs.wisc.edudef NextEthernetAddr():
6636928SN/A    global _NextEthernetAddr
6646928SN/A
6659864Snilay@cs.wisc.edu    value = _NextEthernetAddr
6669864Snilay@cs.wisc.edu    _NextEthernetAddr = IncEthernetAddr(_NextEthernetAddr, 1)
66711066Snilay@cs.wisc.edu    return value
6689864Snilay@cs.wisc.edu
66910036SAli.Saidi@ARM.comclass EthernetAddr(ParamValue):
67011066Snilay@cs.wisc.edu    cxx_type = 'Net::EthAddr'
67111023Sjthestness@gmail.com
6729864Snilay@cs.wisc.edu    @classmethod
67311066Snilay@cs.wisc.edu    def cxx_predecls(cls, code):
6749864Snilay@cs.wisc.edu        code('#include "base/inet.hh"')
67511023Sjthestness@gmail.com
67611023Sjthestness@gmail.com    @classmethod
67711023Sjthestness@gmail.com    def swig_predecls(cls, code):
67811023Sjthestness@gmail.com        code('%include "python/swig/inet.i"')
67911023Sjthestness@gmail.com
68011023Sjthestness@gmail.com    def __init__(self, value):
68111023Sjthestness@gmail.com        if value == NextEthernetAddr:
68211023Sjthestness@gmail.com            self.value = value
68311023Sjthestness@gmail.com            return
68411023Sjthestness@gmail.com
68511023Sjthestness@gmail.com        if not isinstance(value, str):
68611023Sjthestness@gmail.com            raise TypeError, "expected an ethernet address and didn't get one"
68711023Sjthestness@gmail.com
68811023Sjthestness@gmail.com        bytes = value.split(':')
68911023Sjthestness@gmail.com        if len(bytes) != 6:
69011023Sjthestness@gmail.com            raise TypeError, 'invalid ethernet address %s' % value
69111023Sjthestness@gmail.com
69211023Sjthestness@gmail.com        for byte in bytes:
69311023Sjthestness@gmail.com            if not 0 <= int(byte, base=16) <= 0xff:
69411023Sjthestness@gmail.com                raise TypeError, 'invalid ethernet address %s' % value
69511023Sjthestness@gmail.com
69611023Sjthestness@gmail.com        self.value = value
69711023Sjthestness@gmail.com
69811023Sjthestness@gmail.com    def unproxy(self, base):
69911023Sjthestness@gmail.com        if self.value == NextEthernetAddr:
70011023Sjthestness@gmail.com            return EthernetAddr(self.value())
70111023Sjthestness@gmail.com        return self
70211023Sjthestness@gmail.com
70311023Sjthestness@gmail.com    def getValue(self):
70411023Sjthestness@gmail.com        from m5.internal.params import EthAddr
70511023Sjthestness@gmail.com        return EthAddr(self.value)
70611023Sjthestness@gmail.com
70711023Sjthestness@gmail.com    def ini_str(self):
70811023Sjthestness@gmail.com        return self.value
70911023Sjthestness@gmail.com
71011023Sjthestness@gmail.com# When initializing an IpAddress, pass in an existing IpAddress, a string of
71111023Sjthestness@gmail.com# the form "a.b.c.d", or an integer representing an IP.
71211023Sjthestness@gmail.comclass IpAddress(ParamValue):
71311023Sjthestness@gmail.com    cxx_type = 'Net::IpAddress'
71411023Sjthestness@gmail.com
71511023Sjthestness@gmail.com    @classmethod
71611023Sjthestness@gmail.com    def cxx_predecls(cls, code):
71711023Sjthestness@gmail.com        code('#include "base/inet.hh"')
71811023Sjthestness@gmail.com
71911023Sjthestness@gmail.com    @classmethod
72011023Sjthestness@gmail.com    def swig_predecls(cls, code):
72111023Sjthestness@gmail.com        code('%include "python/swig/inet.i"')
72211023Sjthestness@gmail.com
72311023Sjthestness@gmail.com    def __init__(self, value):
72411023Sjthestness@gmail.com        if isinstance(value, IpAddress):
72511023Sjthestness@gmail.com            self.ip = value.ip
72611023Sjthestness@gmail.com        else:
72711023Sjthestness@gmail.com            try:
72811023Sjthestness@gmail.com                self.ip = convert.toIpAddress(value)
72911023Sjthestness@gmail.com            except TypeError:
73011023Sjthestness@gmail.com                self.ip = long(value)
73111023Sjthestness@gmail.com        self.verifyIp()
73211023Sjthestness@gmail.com
73311023Sjthestness@gmail.com    def __str__(self):
73411023Sjthestness@gmail.com        tup = [(self.ip >> i)  & 0xff for i in (24, 16, 8, 0)]
73511023Sjthestness@gmail.com        return '%d.%d.%d.%d' % tuple(tup)
73611023Sjthestness@gmail.com
73711023Sjthestness@gmail.com    def __eq__(self, other):
73811023Sjthestness@gmail.com        if isinstance(other, IpAddress):
73911023Sjthestness@gmail.com            return self.ip == other.ip
74011023Sjthestness@gmail.com        elif isinstance(other, str):
74111023Sjthestness@gmail.com            try:
74211023Sjthestness@gmail.com                return self.ip == convert.toIpAddress(other)
74311023Sjthestness@gmail.com            except:
74411023Sjthestness@gmail.com                return False
74511023Sjthestness@gmail.com        else:
74611023Sjthestness@gmail.com            return self.ip == other
74711023Sjthestness@gmail.com
74811023Sjthestness@gmail.com    def __ne__(self, other):
74911023Sjthestness@gmail.com        return not (self == other)
75011023Sjthestness@gmail.com
75111023Sjthestness@gmail.com    def verifyIp(self):
75211023Sjthestness@gmail.com        if self.ip < 0 or self.ip >= (1 << 32):
75311023Sjthestness@gmail.com            raise TypeError, "invalid ip address %#08x" % self.ip
75411023Sjthestness@gmail.com
75511023Sjthestness@gmail.com    def getValue(self):
75611023Sjthestness@gmail.com        from m5.internal.params import IpAddress
75711023Sjthestness@gmail.com        return IpAddress(self.ip)
75811023Sjthestness@gmail.com
75911023Sjthestness@gmail.com# When initializing an IpNetmask, pass in an existing IpNetmask, a string of
76011023Sjthestness@gmail.com# the form "a.b.c.d/n" or "a.b.c.d/e.f.g.h", or an ip and netmask as
76111023Sjthestness@gmail.com# positional or keyword arguments.
76211023Sjthestness@gmail.comclass IpNetmask(IpAddress):
76311023Sjthestness@gmail.com    cxx_type = 'Net::IpNetmask'
76411023Sjthestness@gmail.com
76511023Sjthestness@gmail.com    @classmethod
76611023Sjthestness@gmail.com    def cxx_predecls(cls, code):
76711023Sjthestness@gmail.com        code('#include "base/inet.hh"')
76811023Sjthestness@gmail.com
76911023Sjthestness@gmail.com    @classmethod
77011023Sjthestness@gmail.com    def swig_predecls(cls, code):
77111023Sjthestness@gmail.com        code('%include "python/swig/inet.i"')
77211023Sjthestness@gmail.com
77311023Sjthestness@gmail.com    def __init__(self, *args, **kwargs):
77411023Sjthestness@gmail.com        def handle_kwarg(self, kwargs, key, elseVal = None):
77511023Sjthestness@gmail.com            if key in kwargs:
77611023Sjthestness@gmail.com                setattr(self, key, kwargs.pop(key))
77711023Sjthestness@gmail.com            elif elseVal:
77811023Sjthestness@gmail.com                setattr(self, key, elseVal)
77911023Sjthestness@gmail.com            else:
78011023Sjthestness@gmail.com                raise TypeError, "No value set for %s" % key
78111023Sjthestness@gmail.com
78211023Sjthestness@gmail.com        if len(args) == 0:
78311023Sjthestness@gmail.com            handle_kwarg(self, kwargs, 'ip')
78411023Sjthestness@gmail.com            handle_kwarg(self, kwargs, 'netmask')
78511023Sjthestness@gmail.com
78611023Sjthestness@gmail.com        elif len(args) == 1:
78711023Sjthestness@gmail.com            if kwargs:
78811023Sjthestness@gmail.com                if not 'ip' in kwargs and not 'netmask' in kwargs:
78911023Sjthestness@gmail.com                    raise TypeError, "Invalid arguments"
79011023Sjthestness@gmail.com                handle_kwarg(self, kwargs, 'ip', args[0])
79111023Sjthestness@gmail.com                handle_kwarg(self, kwargs, 'netmask', args[0])
79211023Sjthestness@gmail.com            elif isinstance(args[0], IpNetmask):
79311023Sjthestness@gmail.com                self.ip = args[0].ip
79411023Sjthestness@gmail.com                self.netmask = args[0].netmask
7959864Snilay@cs.wisc.edu            else:
7969864Snilay@cs.wisc.edu                (self.ip, self.netmask) = convert.toIpNetmask(args[0])
79711066Snilay@cs.wisc.edu
7989864Snilay@cs.wisc.edu        elif len(args) == 2:
79910036SAli.Saidi@ARM.com            self.ip = args[0]
80011066Snilay@cs.wisc.edu            self.netmask = args[1]
80111023Sjthestness@gmail.com        else:
8029864Snilay@cs.wisc.edu            raise TypeError, "Too many arguments specified"
80311066Snilay@cs.wisc.edu
8049864Snilay@cs.wisc.edu        if kwargs:
80511023Sjthestness@gmail.com            raise TypeError, "Too many keywords: %s" % kwargs.keys()
80611023Sjthestness@gmail.com
80711023Sjthestness@gmail.com        self.verify()
80811023Sjthestness@gmail.com
80911023Sjthestness@gmail.com    def __str__(self):
81011023Sjthestness@gmail.com        return "%s/%d" % (super(IpNetmask, self).__str__(), self.netmask)
81111023Sjthestness@gmail.com
81211023Sjthestness@gmail.com    def __eq__(self, other):
81311023Sjthestness@gmail.com        if isinstance(other, IpNetmask):
81411023Sjthestness@gmail.com            return self.ip == other.ip and self.netmask == other.netmask
81511023Sjthestness@gmail.com        elif isinstance(other, str):
81611023Sjthestness@gmail.com            try:
81711023Sjthestness@gmail.com                return (self.ip, self.netmask) == convert.toIpNetmask(other)
81811023Sjthestness@gmail.com            except:
81911023Sjthestness@gmail.com                return False
82011023Sjthestness@gmail.com        else:
82111023Sjthestness@gmail.com            return False
82211023Sjthestness@gmail.com
82311023Sjthestness@gmail.com    def verify(self):
82411023Sjthestness@gmail.com        self.verifyIp()
82511023Sjthestness@gmail.com        if self.netmask < 0 or self.netmask > 32:
82611023Sjthestness@gmail.com            raise TypeError, "invalid netmask %d" % netmask
82711023Sjthestness@gmail.com
82811023Sjthestness@gmail.com    def getValue(self):
82911023Sjthestness@gmail.com        from m5.internal.params import IpNetmask
83011023Sjthestness@gmail.com        return IpNetmask(self.ip, self.netmask)
83111023Sjthestness@gmail.com
83211023Sjthestness@gmail.com# When initializing an IpWithPort, pass in an existing IpWithPort, a string of
83311023Sjthestness@gmail.com# the form "a.b.c.d:p", or an ip and port as positional or keyword arguments.
83411023Sjthestness@gmail.comclass IpWithPort(IpAddress):
83511023Sjthestness@gmail.com    cxx_type = 'Net::IpWithPort'
83611023Sjthestness@gmail.com
83711023Sjthestness@gmail.com    @classmethod
83811023Sjthestness@gmail.com    def cxx_predecls(cls, code):
83911023Sjthestness@gmail.com        code('#include "base/inet.hh"')
84011023Sjthestness@gmail.com
84111023Sjthestness@gmail.com    @classmethod
84211023Sjthestness@gmail.com    def swig_predecls(cls, code):
84311023Sjthestness@gmail.com        code('%include "python/swig/inet.i"')
84411023Sjthestness@gmail.com
84511023Sjthestness@gmail.com    def __init__(self, *args, **kwargs):
84611023Sjthestness@gmail.com        def handle_kwarg(self, kwargs, key, elseVal = None):
84711023Sjthestness@gmail.com            if key in kwargs:
84811023Sjthestness@gmail.com                setattr(self, key, kwargs.pop(key))
84911023Sjthestness@gmail.com            elif elseVal:
85011023Sjthestness@gmail.com                setattr(self, key, elseVal)
85111023Sjthestness@gmail.com            else:
85211023Sjthestness@gmail.com                raise TypeError, "No value set for %s" % key
85311023Sjthestness@gmail.com
85411023Sjthestness@gmail.com        if len(args) == 0:
85511023Sjthestness@gmail.com            handle_kwarg(self, kwargs, 'ip')
85611023Sjthestness@gmail.com            handle_kwarg(self, kwargs, 'port')
85711023Sjthestness@gmail.com
85811023Sjthestness@gmail.com        elif len(args) == 1:
85911023Sjthestness@gmail.com            if kwargs:
86011023Sjthestness@gmail.com                if not 'ip' in kwargs and not 'port' in kwargs:
86111023Sjthestness@gmail.com                    raise TypeError, "Invalid arguments"
86211023Sjthestness@gmail.com                handle_kwarg(self, kwargs, 'ip', args[0])
86311023Sjthestness@gmail.com                handle_kwarg(self, kwargs, 'port', args[0])
86411023Sjthestness@gmail.com            elif isinstance(args[0], IpWithPort):
86511023Sjthestness@gmail.com                self.ip = args[0].ip
86611023Sjthestness@gmail.com                self.port = args[0].port
86711023Sjthestness@gmail.com            else:
86811023Sjthestness@gmail.com                (self.ip, self.port) = convert.toIpWithPort(args[0])
86911023Sjthestness@gmail.com
87011023Sjthestness@gmail.com        elif len(args) == 2:
87111023Sjthestness@gmail.com            self.ip = args[0]
87211023Sjthestness@gmail.com            self.port = args[1]
87311023Sjthestness@gmail.com        else:
87411023Sjthestness@gmail.com            raise TypeError, "Too many arguments specified"
87511023Sjthestness@gmail.com
87611023Sjthestness@gmail.com        if kwargs:
87711023Sjthestness@gmail.com            raise TypeError, "Too many keywords: %s" % kwargs.keys()
87811023Sjthestness@gmail.com
87911023Sjthestness@gmail.com        self.verify()
88011023Sjthestness@gmail.com
88111023Sjthestness@gmail.com    def __str__(self):
88211023Sjthestness@gmail.com        return "%s:%d" % (super(IpWithPort, self).__str__(), self.port)
88311023Sjthestness@gmail.com
88411023Sjthestness@gmail.com    def __eq__(self, other):
88511023Sjthestness@gmail.com        if isinstance(other, IpWithPort):
88611023Sjthestness@gmail.com            return self.ip == other.ip and self.port == other.port
88711023Sjthestness@gmail.com        elif isinstance(other, str):
88811023Sjthestness@gmail.com            try:
88911023Sjthestness@gmail.com                return (self.ip, self.port) == convert.toIpWithPort(other)
89011023Sjthestness@gmail.com            except:
89111023Sjthestness@gmail.com                return False
89211023Sjthestness@gmail.com        else:
89311023Sjthestness@gmail.com            return False
89411023Sjthestness@gmail.com
89511023Sjthestness@gmail.com    def verify(self):
89611023Sjthestness@gmail.com        self.verifyIp()
89711023Sjthestness@gmail.com        if self.port < 0 or self.port > 0xffff:
89811023Sjthestness@gmail.com            raise TypeError, "invalid port %d" % self.port
89911023Sjthestness@gmail.com
90011023Sjthestness@gmail.com    def getValue(self):
90111023Sjthestness@gmail.com        from m5.internal.params import IpWithPort
90211023Sjthestness@gmail.com        return IpWithPort(self.ip, self.port)
90311023Sjthestness@gmail.com
90411023Sjthestness@gmail.comtime_formats = [ "%a %b %d %H:%M:%S %Z %Y",
90511023Sjthestness@gmail.com                 "%a %b %d %H:%M:%S %Z %Y",
90611023Sjthestness@gmail.com                 "%Y/%m/%d %H:%M:%S",
90711023Sjthestness@gmail.com                 "%Y/%m/%d %H:%M",
90811023Sjthestness@gmail.com                 "%Y/%m/%d",
90911023Sjthestness@gmail.com                 "%m/%d/%Y %H:%M:%S",
91011023Sjthestness@gmail.com                 "%m/%d/%Y %H:%M",
91111023Sjthestness@gmail.com                 "%m/%d/%Y",
91211023Sjthestness@gmail.com                 "%m/%d/%y %H:%M:%S",
91311023Sjthestness@gmail.com                 "%m/%d/%y %H:%M",
91411023Sjthestness@gmail.com                 "%m/%d/%y"]
91511023Sjthestness@gmail.com
91611023Sjthestness@gmail.com
91711023Sjthestness@gmail.comdef parse_time(value):
91811023Sjthestness@gmail.com    from time import gmtime, strptime, struct_time, time
91911023Sjthestness@gmail.com    from datetime import datetime, date
92011023Sjthestness@gmail.com
92111023Sjthestness@gmail.com    if isinstance(value, struct_time):
92211023Sjthestness@gmail.com        return value
92311023Sjthestness@gmail.com
92411023Sjthestness@gmail.com    if isinstance(value, (int, long)):
9259864Snilay@cs.wisc.edu        return gmtime(value)
9269864Snilay@cs.wisc.edu
92711066Snilay@cs.wisc.edu    if isinstance(value, (datetime, date)):
9289864Snilay@cs.wisc.edu        return value.timetuple()
92910036SAli.Saidi@ARM.com
93011066Snilay@cs.wisc.edu    if isinstance(value, str):
93111023Sjthestness@gmail.com        if value in ('Now', 'Today'):
9329864Snilay@cs.wisc.edu            return time.gmtime(time.time())
93311066Snilay@cs.wisc.edu
9349864Snilay@cs.wisc.edu        for format in time_formats:
93511023Sjthestness@gmail.com            try:
93611023Sjthestness@gmail.com                return strptime(value, format)
93711023Sjthestness@gmail.com            except ValueError:
93811023Sjthestness@gmail.com                pass
93911023Sjthestness@gmail.com
94011023Sjthestness@gmail.com    raise ValueError, "Could not parse '%s' as a time" % value
94111023Sjthestness@gmail.com
94211023Sjthestness@gmail.comclass Time(ParamValue):
94311023Sjthestness@gmail.com    cxx_type = 'tm'
94411023Sjthestness@gmail.com
94511023Sjthestness@gmail.com    @classmethod
94611023Sjthestness@gmail.com    def cxx_predecls(cls, code):
94711023Sjthestness@gmail.com        code('#include <time.h>')
94811023Sjthestness@gmail.com
94911023Sjthestness@gmail.com    @classmethod
95011023Sjthestness@gmail.com    def swig_predecls(cls, code):
95111023Sjthestness@gmail.com        code('%include "python/swig/time.i"')
95211023Sjthestness@gmail.com
95311023Sjthestness@gmail.com    def __init__(self, value):
95411023Sjthestness@gmail.com        self.value = parse_time(value)
95511023Sjthestness@gmail.com
95611023Sjthestness@gmail.com    def getValue(self):
95711023Sjthestness@gmail.com        from m5.internal.params import tm
95811023Sjthestness@gmail.com
95911023Sjthestness@gmail.com        c_time = tm()
96011023Sjthestness@gmail.com        py_time = self.value
96111023Sjthestness@gmail.com
96211023Sjthestness@gmail.com        # UNIX is years since 1900
96311023Sjthestness@gmail.com        c_time.tm_year = py_time.tm_year - 1900;
96411023Sjthestness@gmail.com
96511023Sjthestness@gmail.com        # Python starts at 1, UNIX starts at 0
96611023Sjthestness@gmail.com        c_time.tm_mon =  py_time.tm_mon - 1;
96711023Sjthestness@gmail.com        c_time.tm_mday = py_time.tm_mday;
96811023Sjthestness@gmail.com        c_time.tm_hour = py_time.tm_hour;
96911023Sjthestness@gmail.com        c_time.tm_min = py_time.tm_min;
97011023Sjthestness@gmail.com        c_time.tm_sec = py_time.tm_sec;
97111023Sjthestness@gmail.com
97211023Sjthestness@gmail.com        # Python has 0 as Monday, UNIX is 0 as sunday
97311023Sjthestness@gmail.com        c_time.tm_wday = py_time.tm_wday + 1
97411023Sjthestness@gmail.com        if c_time.tm_wday > 6:
97511023Sjthestness@gmail.com            c_time.tm_wday -= 7;
97611023Sjthestness@gmail.com
97711023Sjthestness@gmail.com        # Python starts at 1, Unix starts at 0
97811023Sjthestness@gmail.com        c_time.tm_yday = py_time.tm_yday - 1;
97911023Sjthestness@gmail.com
98011023Sjthestness@gmail.com        return c_time
98111023Sjthestness@gmail.com
98211023Sjthestness@gmail.com    def __str__(self):
98311023Sjthestness@gmail.com        return time.asctime(self.value)
98411023Sjthestness@gmail.com
98511023Sjthestness@gmail.com    def ini_str(self):
98611023Sjthestness@gmail.com        return str(self)
98711023Sjthestness@gmail.com
98811023Sjthestness@gmail.com    def get_config_as_dict(self):
98911023Sjthestness@gmail.com        return str(self)
99011023Sjthestness@gmail.com
99111023Sjthestness@gmail.com# Enumerated types are a little more complex.  The user specifies the
99211023Sjthestness@gmail.com# type as Enum(foo) where foo is either a list or dictionary of
99311023Sjthestness@gmail.com# alternatives (typically strings, but not necessarily so).  (In the
99411023Sjthestness@gmail.com# long run, the integer value of the parameter will be the list index
99511023Sjthestness@gmail.com# or the corresponding dictionary value.  For now, since we only check
99611023Sjthestness@gmail.com# that the alternative is valid and then spit it into a .ini file,
99711023Sjthestness@gmail.com# there's not much point in using the dictionary.)
99811023Sjthestness@gmail.com
99911023Sjthestness@gmail.com# What Enum() must do is generate a new type encapsulating the
100011023Sjthestness@gmail.com# provided list/dictionary so that specific values of the parameter
100111023Sjthestness@gmail.com# can be instances of that type.  We define two hidden internal
100211023Sjthestness@gmail.com# classes (_ListEnum and _DictEnum) to serve as base classes, then
100311023Sjthestness@gmail.com# derive the new type from the appropriate base class on the fly.
100411023Sjthestness@gmail.com
100511023Sjthestness@gmail.comallEnums = {}
100611023Sjthestness@gmail.com# Metaclass for Enum types
100711023Sjthestness@gmail.comclass MetaEnum(MetaParamValue):
100811023Sjthestness@gmail.com    def __new__(mcls, name, bases, dict):
100911023Sjthestness@gmail.com        assert name not in allEnums
101011023Sjthestness@gmail.com
101111023Sjthestness@gmail.com        cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict)
101211023Sjthestness@gmail.com        allEnums[name] = cls
101311023Sjthestness@gmail.com        return cls
101411023Sjthestness@gmail.com
101511023Sjthestness@gmail.com    def __init__(cls, name, bases, init_dict):
101611023Sjthestness@gmail.com        if init_dict.has_key('map'):
101711023Sjthestness@gmail.com            if not isinstance(cls.map, dict):
101811023Sjthestness@gmail.com                raise TypeError, "Enum-derived class attribute 'map' " \
101911023Sjthestness@gmail.com                      "must be of type dict"
102011023Sjthestness@gmail.com            # build list of value strings from map
102111023Sjthestness@gmail.com            cls.vals = cls.map.keys()
102211023Sjthestness@gmail.com            cls.vals.sort()
102311023Sjthestness@gmail.com        elif init_dict.has_key('vals'):
102411023Sjthestness@gmail.com            if not isinstance(cls.vals, list):
102511023Sjthestness@gmail.com                raise TypeError, "Enum-derived class attribute 'vals' " \
102611023Sjthestness@gmail.com                      "must be of type list"
102711023Sjthestness@gmail.com            # build string->value map from vals sequence
102811023Sjthestness@gmail.com            cls.map = {}
102911023Sjthestness@gmail.com            for idx,val in enumerate(cls.vals):
103011023Sjthestness@gmail.com                cls.map[val] = idx
103111023Sjthestness@gmail.com        else:
103211023Sjthestness@gmail.com            raise TypeError, "Enum-derived class must define "\
103311023Sjthestness@gmail.com                  "attribute 'map' or 'vals'"
103411023Sjthestness@gmail.com
103511023Sjthestness@gmail.com        cls.cxx_type = 'Enums::%s' % name
103611023Sjthestness@gmail.com
103711023Sjthestness@gmail.com        super(MetaEnum, cls).__init__(name, bases, init_dict)
103811023Sjthestness@gmail.com
103911023Sjthestness@gmail.com    # Generate C++ class declaration for this enum type.
104011023Sjthestness@gmail.com    # Note that we wrap the enum in a class/struct to act as a namespace,
104111023Sjthestness@gmail.com    # so that the enum strings can be brief w/o worrying about collisions.
104211023Sjthestness@gmail.com    def cxx_decl(cls, code):
104311023Sjthestness@gmail.com        name = cls.__name__
104411023Sjthestness@gmail.com        code('''\
104511023Sjthestness@gmail.com#ifndef __ENUM__${name}__
104611023Sjthestness@gmail.com#define __ENUM__${name}__
104711023Sjthestness@gmail.com
104811023Sjthestness@gmail.comnamespace Enums {
104911023Sjthestness@gmail.com    enum $name {
105011023Sjthestness@gmail.com''')
105111023Sjthestness@gmail.com        code.indent(2)
105211023Sjthestness@gmail.com        for val in cls.vals:
105311023Sjthestness@gmail.com            code('$val = ${{cls.map[val]}},')
105411023Sjthestness@gmail.com        code('Num_$name = ${{len(cls.vals)}}')
105511023Sjthestness@gmail.com        code.dedent(2)
105611023Sjthestness@gmail.com        code('''\
105711023Sjthestness@gmail.com    };
105811023Sjthestness@gmail.comextern const char *${name}Strings[Num_${name}];
105911023Sjthestness@gmail.com}
106011023Sjthestness@gmail.com
106111023Sjthestness@gmail.com#endif // __ENUM__${name}__
106211023Sjthestness@gmail.com''')
106311023Sjthestness@gmail.com
106411023Sjthestness@gmail.com    def cxx_def(cls, code):
106511023Sjthestness@gmail.com        name = cls.__name__
106611023Sjthestness@gmail.com        code('''\
106711023Sjthestness@gmail.com#include "enums/$name.hh"
106811023Sjthestness@gmail.comnamespace Enums {
106911023Sjthestness@gmail.com    const char *${name}Strings[Num_${name}] =
107011023Sjthestness@gmail.com    {
107111023Sjthestness@gmail.com''')
107211023Sjthestness@gmail.com        code.indent(2)
107311023Sjthestness@gmail.com        for val in cls.vals:
107411023Sjthestness@gmail.com            code('"$val",')
107511023Sjthestness@gmail.com        code.dedent(2)
107611023Sjthestness@gmail.com        code('''
107711023Sjthestness@gmail.com    };
107811023Sjthestness@gmail.com} // namespace Enums
107911023Sjthestness@gmail.com''')
108011023Sjthestness@gmail.com
108111023Sjthestness@gmail.com    def swig_decl(cls, code):
108211023Sjthestness@gmail.com        name = cls.__name__
108311023Sjthestness@gmail.com        code('''\
108411023Sjthestness@gmail.com%module(package="m5.internal") enum_$name
108511023Sjthestness@gmail.com
108611023Sjthestness@gmail.com%{
108711023Sjthestness@gmail.com#include "enums/$name.hh"
108811023Sjthestness@gmail.com%}
108911023Sjthestness@gmail.com
109011023Sjthestness@gmail.com%include "enums/$name.hh"
109111023Sjthestness@gmail.com''')
109211023Sjthestness@gmail.com
109311023Sjthestness@gmail.com
109411023Sjthestness@gmail.com# Base class for enum types.
10958721SN/Aclass Enum(ParamValue):
10968721SN/A    __metaclass__ = MetaEnum
10979864Snilay@cs.wisc.edu    vals = []
109810036SAli.Saidi@ARM.com
10998540SN/A    def __init__(self, value):
11008983Snate@binkert.org        if value not in self.map:
11018983Snate@binkert.org            raise TypeError, "Enum param got bad value '%s' (not in %s)" \
11028983Snate@binkert.org                  % (value, self.vals)
11038721SN/A        self.value = value
11048721SN/A
11058983Snate@binkert.org    @classmethod
11066928SN/A    def cxx_predecls(cls, code):
11079864Snilay@cs.wisc.edu        code('#include "enums/$0.hh"', cls.__name__)
11089864Snilay@cs.wisc.edu
110910036SAli.Saidi@ARM.com    @classmethod
11109864Snilay@cs.wisc.edu    def swig_predecls(cls, code):
11119864Snilay@cs.wisc.edu        code('%import "python/m5/internal/enum_$0.i"', cls.__name__)
1112
1113    def getValue(self):
1114        return int(self.map[self.value])
1115
1116    def __str__(self):
1117        return self.value
1118
1119# how big does a rounding error need to be before we warn about it?
1120frequency_tolerance = 0.001  # 0.1%
1121
1122class TickParamValue(NumericParamValue):
1123    cxx_type = 'Tick'
1124
1125    @classmethod
1126    def cxx_predecls(cls, code):
1127        code('#include "base/types.hh"')
1128
1129    @classmethod
1130    def swig_predecls(cls, code):
1131        code('%import "stdint.i"')
1132        code('%import "base/types.hh"')
1133
1134    def getValue(self):
1135        return long(self.value)
1136
1137class Latency(TickParamValue):
1138    def __init__(self, value):
1139        if isinstance(value, (Latency, Clock)):
1140            self.ticks = value.ticks
1141            self.value = value.value
1142        elif isinstance(value, Frequency):
1143            self.ticks = value.ticks
1144            self.value = 1.0 / value.value
1145        elif value.endswith('t'):
1146            self.ticks = True
1147            self.value = int(value[:-1])
1148        else:
1149            self.ticks = False
1150            self.value = convert.toLatency(value)
1151
1152    def __getattr__(self, attr):
1153        if attr in ('latency', 'period'):
1154            return self
1155        if attr == 'frequency':
1156            return Frequency(self)
1157        raise AttributeError, "Latency object has no attribute '%s'" % attr
1158
1159    def getValue(self):
1160        if self.ticks or self.value == 0:
1161            value = self.value
1162        else:
1163            value = ticks.fromSeconds(self.value)
1164        return long(value)
1165
1166    # convert latency to ticks
1167    def ini_str(self):
1168        return '%d' % self.getValue()
1169
1170class Frequency(TickParamValue):
1171    def __init__(self, value):
1172        if isinstance(value, (Latency, Clock)):
1173            if value.value == 0:
1174                self.value = 0
1175            else:
1176                self.value = 1.0 / value.value
1177            self.ticks = value.ticks
1178        elif isinstance(value, Frequency):
1179            self.value = value.value
1180            self.ticks = value.ticks
1181        else:
1182            self.ticks = False
1183            self.value = convert.toFrequency(value)
1184
1185    def __getattr__(self, attr):
1186        if attr == 'frequency':
1187            return self
1188        if attr in ('latency', 'period'):
1189            return Latency(self)
1190        raise AttributeError, "Frequency object has no attribute '%s'" % attr
1191
1192    # convert latency to ticks
1193    def getValue(self):
1194        if self.ticks or self.value == 0:
1195            value = self.value
1196        else:
1197            value = ticks.fromSeconds(1.0 / self.value)
1198        return long(value)
1199
1200    def ini_str(self):
1201        return '%d' % self.getValue()
1202
1203# A generic Frequency and/or Latency value. Value is stored as a
1204# latency, just like Latency and Frequency.
1205class Clock(TickParamValue):
1206    def __init__(self, value):
1207        if isinstance(value, (Latency, Clock)):
1208            self.ticks = value.ticks
1209            self.value = value.value
1210        elif isinstance(value, Frequency):
1211            self.ticks = value.ticks
1212            self.value = 1.0 / value.value
1213        elif value.endswith('t'):
1214            self.ticks = True
1215            self.value = int(value[:-1])
1216        else:
1217            self.ticks = False
1218            self.value = convert.anyToLatency(value)
1219
1220    def __getattr__(self, attr):
1221        if attr == 'frequency':
1222            return Frequency(self)
1223        if attr in ('latency', 'period'):
1224            return Latency(self)
1225        raise AttributeError, "Frequency object has no attribute '%s'" % attr
1226
1227    def getValue(self):
1228        return self.period.getValue()
1229
1230    def ini_str(self):
1231        return self.period.ini_str()
1232
1233class Voltage(float,ParamValue):
1234    cxx_type = 'double'
1235    def __new__(cls, value):
1236        # convert to voltage
1237        val = convert.toVoltage(value)
1238        return super(cls, Voltage).__new__(cls, val)
1239
1240    def __str__(self):
1241        return str(self.val)
1242
1243    def getValue(self):
1244        value = float(self)
1245        return value
1246
1247    def ini_str(self):
1248        return '%f' % self.getValue()
1249
1250class NetworkBandwidth(float,ParamValue):
1251    cxx_type = 'float'
1252    def __new__(cls, value):
1253        # convert to bits per second
1254        val = convert.toNetworkBandwidth(value)
1255        return super(cls, NetworkBandwidth).__new__(cls, val)
1256
1257    def __str__(self):
1258        return str(self.val)
1259
1260    def getValue(self):
1261        # convert to seconds per byte
1262        value = 8.0 / float(self)
1263        # convert to ticks per byte
1264        value = ticks.fromSeconds(value)
1265        return float(value)
1266
1267    def ini_str(self):
1268        return '%f' % self.getValue()
1269
1270class MemoryBandwidth(float,ParamValue):
1271    cxx_type = 'float'
1272    def __new__(cls, value):
1273        # convert to bytes per second
1274        val = convert.toMemoryBandwidth(value)
1275        return super(cls, MemoryBandwidth).__new__(cls, val)
1276
1277    def __str__(self):
1278        return str(self.val)
1279
1280    def getValue(self):
1281        # convert to seconds per byte
1282        value = float(self)
1283        if value:
1284            value = 1.0 / float(self)
1285        # convert to ticks per byte
1286        value = ticks.fromSeconds(value)
1287        return float(value)
1288
1289    def ini_str(self):
1290        return '%f' % self.getValue()
1291
1292#
1293# "Constants"... handy aliases for various values.
1294#
1295
1296# Special class for NULL pointers.  Note the special check in
1297# make_param_value() above that lets these be assigned where a
1298# SimObject is required.
1299# only one copy of a particular node
1300class NullSimObject(object):
1301    __metaclass__ = Singleton
1302
1303    def __call__(cls):
1304        return cls
1305
1306    def _instantiate(self, parent = None, path = ''):
1307        pass
1308
1309    def ini_str(self):
1310        return 'Null'
1311
1312    def unproxy(self, base):
1313        return self
1314
1315    def set_path(self, parent, name):
1316        pass
1317
1318    def __str__(self):
1319        return 'Null'
1320
1321    def getValue(self):
1322        return None
1323
1324# The only instance you'll ever need...
1325NULL = NullSimObject()
1326
1327def isNullPointer(value):
1328    return isinstance(value, NullSimObject)
1329
1330# Some memory range specifications use this as a default upper bound.
1331MaxAddr = Addr.max
1332MaxTick = Tick.max
1333AllMemory = AddrRange(0, MaxAddr)
1334
1335
1336#####################################################################
1337#
1338# Port objects
1339#
1340# Ports are used to interconnect objects in the memory system.
1341#
1342#####################################################################
1343
1344# Port reference: encapsulates a reference to a particular port on a
1345# particular SimObject.
1346class PortRef(object):
1347    def __init__(self, simobj, name, role):
1348        assert(isSimObject(simobj) or isSimObjectClass(simobj))
1349        self.simobj = simobj
1350        self.name = name
1351        self.role = role
1352        self.peer = None   # not associated with another port yet
1353        self.ccConnected = False # C++ port connection done?
1354        self.index = -1  # always -1 for non-vector ports
1355
1356    def __str__(self):
1357        return '%s.%s' % (self.simobj, self.name)
1358
1359    def __len__(self):
1360        # Return the number of connected ports, i.e. 0 is we have no
1361        # peer and 1 if we do.
1362        return int(self.peer != None)
1363
1364    # for config.ini, print peer's name (not ours)
1365    def ini_str(self):
1366        return str(self.peer)
1367
1368    # for config.json
1369    def get_config_as_dict(self):
1370        return {'role' : self.role, 'peer' : str(self.peer)}
1371
1372    def __getattr__(self, attr):
1373        if attr == 'peerObj':
1374            # shorthand for proxies
1375            return self.peer.simobj
1376        raise AttributeError, "'%s' object has no attribute '%s'" % \
1377              (self.__class__.__name__, attr)
1378
1379    # Full connection is symmetric (both ways).  Called via
1380    # SimObject.__setattr__ as a result of a port assignment, e.g.,
1381    # "obj1.portA = obj2.portB", or via VectorPortElementRef.__setitem__,
1382    # e.g., "obj1.portA[3] = obj2.portB".
1383    def connect(self, other):
1384        if isinstance(other, VectorPortRef):
1385            # reference to plain VectorPort is implicit append
1386            other = other._get_next()
1387        if self.peer and not proxy.isproxy(self.peer):
1388            fatal("Port %s is already connected to %s, cannot connect %s\n",
1389                  self, self.peer, other);
1390        self.peer = other
1391        if proxy.isproxy(other):
1392            other.set_param_desc(PortParamDesc())
1393        elif isinstance(other, PortRef):
1394            if other.peer is not self:
1395                other.connect(self)
1396        else:
1397            raise TypeError, \
1398                  "assigning non-port reference '%s' to port '%s'" \
1399                  % (other, self)
1400
1401    def clone(self, simobj, memo):
1402        if memo.has_key(self):
1403            return memo[self]
1404        newRef = copy.copy(self)
1405        memo[self] = newRef
1406        newRef.simobj = simobj
1407        assert(isSimObject(newRef.simobj))
1408        if self.peer and not proxy.isproxy(self.peer):
1409            peerObj = self.peer.simobj(_memo=memo)
1410            newRef.peer = self.peer.clone(peerObj, memo)
1411            assert(not isinstance(newRef.peer, VectorPortRef))
1412        return newRef
1413
1414    def unproxy(self, simobj):
1415        assert(simobj is self.simobj)
1416        if proxy.isproxy(self.peer):
1417            try:
1418                realPeer = self.peer.unproxy(self.simobj)
1419            except:
1420                print "Error in unproxying port '%s' of %s" % \
1421                      (self.name, self.simobj.path())
1422                raise
1423            self.connect(realPeer)
1424
1425    # Call C++ to create corresponding port connection between C++ objects
1426    def ccConnect(self):
1427        from m5.internal.pyobject import connectPorts
1428
1429        if self.role == 'SLAVE':
1430            # do nothing and let the master take care of it
1431            return
1432
1433        if self.ccConnected: # already done this
1434            return
1435        peer = self.peer
1436        if not self.peer: # nothing to connect to
1437            return
1438
1439        # check that we connect a master to a slave
1440        if self.role == peer.role:
1441            raise TypeError, \
1442                "cannot connect '%s' and '%s' due to identical role '%s'" \
1443                % (peer, self, self.role)
1444
1445        try:
1446            # self is always the master and peer the slave
1447            connectPorts(self.simobj.getCCObject(), self.name, self.index,
1448                         peer.simobj.getCCObject(), peer.name, peer.index)
1449        except:
1450            print "Error connecting port %s.%s to %s.%s" % \
1451                  (self.simobj.path(), self.name,
1452                   peer.simobj.path(), peer.name)
1453            raise
1454        self.ccConnected = True
1455        peer.ccConnected = True
1456
1457# A reference to an individual element of a VectorPort... much like a
1458# PortRef, but has an index.
1459class VectorPortElementRef(PortRef):
1460    def __init__(self, simobj, name, role, index):
1461        PortRef.__init__(self, simobj, name, role)
1462        self.index = index
1463
1464    def __str__(self):
1465        return '%s.%s[%d]' % (self.simobj, self.name, self.index)
1466
1467# A reference to a complete vector-valued port (not just a single element).
1468# Can be indexed to retrieve individual VectorPortElementRef instances.
1469class VectorPortRef(object):
1470    def __init__(self, simobj, name, role):
1471        assert(isSimObject(simobj) or isSimObjectClass(simobj))
1472        self.simobj = simobj
1473        self.name = name
1474        self.role = role
1475        self.elements = []
1476
1477    def __str__(self):
1478        return '%s.%s[:]' % (self.simobj, self.name)
1479
1480    def __len__(self):
1481        # Return the number of connected peers, corresponding the the
1482        # length of the elements.
1483        return len(self.elements)
1484
1485    # for config.ini, print peer's name (not ours)
1486    def ini_str(self):
1487        return ' '.join([el.ini_str() for el in self.elements])
1488
1489    # for config.json
1490    def get_config_as_dict(self):
1491        return {'role' : self.role,
1492                'peer' : [el.ini_str() for el in self.elements]}
1493
1494    def __getitem__(self, key):
1495        if not isinstance(key, int):
1496            raise TypeError, "VectorPort index must be integer"
1497        if key >= len(self.elements):
1498            # need to extend list
1499            ext = [VectorPortElementRef(self.simobj, self.name, self.role, i)
1500                   for i in range(len(self.elements), key+1)]
1501            self.elements.extend(ext)
1502        return self.elements[key]
1503
1504    def _get_next(self):
1505        return self[len(self.elements)]
1506
1507    def __setitem__(self, key, value):
1508        if not isinstance(key, int):
1509            raise TypeError, "VectorPort index must be integer"
1510        self[key].connect(value)
1511
1512    def connect(self, other):
1513        if isinstance(other, (list, tuple)):
1514            # Assign list of port refs to vector port.
1515            # For now, append them... not sure if that's the right semantics
1516            # or if it should replace the current vector.
1517            for ref in other:
1518                self._get_next().connect(ref)
1519        else:
1520            # scalar assignment to plain VectorPort is implicit append
1521            self._get_next().connect(other)
1522
1523    def clone(self, simobj, memo):
1524        if memo.has_key(self):
1525            return memo[self]
1526        newRef = copy.copy(self)
1527        memo[self] = newRef
1528        newRef.simobj = simobj
1529        assert(isSimObject(newRef.simobj))
1530        newRef.elements = [el.clone(simobj, memo) for el in self.elements]
1531        return newRef
1532
1533    def unproxy(self, simobj):
1534        [el.unproxy(simobj) for el in self.elements]
1535
1536    def ccConnect(self):
1537        [el.ccConnect() for el in self.elements]
1538
1539# Port description object.  Like a ParamDesc object, this represents a
1540# logical port in the SimObject class, not a particular port on a
1541# SimObject instance.  The latter are represented by PortRef objects.
1542class Port(object):
1543    # Generate a PortRef for this port on the given SimObject with the
1544    # given name
1545    def makeRef(self, simobj):
1546        return PortRef(simobj, self.name, self.role)
1547
1548    # Connect an instance of this port (on the given SimObject with
1549    # the given name) with the port described by the supplied PortRef
1550    def connect(self, simobj, ref):
1551        self.makeRef(simobj).connect(ref)
1552
1553    # No need for any pre-declarations at the moment as we merely rely
1554    # on an unsigned int.
1555    def cxx_predecls(self, code):
1556        pass
1557
1558    # Declare an unsigned int with the same name as the port, that
1559    # will eventually hold the number of connected ports (and thus the
1560    # number of elements for a VectorPort).
1561    def cxx_decl(self, code):
1562        code('unsigned int port_${{self.name}}_connection_count;')
1563
1564class MasterPort(Port):
1565    # MasterPort("description")
1566    def __init__(self, *args):
1567        if len(args) == 1:
1568            self.desc = args[0]
1569            self.role = 'MASTER'
1570        else:
1571            raise TypeError, 'wrong number of arguments'
1572
1573class SlavePort(Port):
1574    # SlavePort("description")
1575    def __init__(self, *args):
1576        if len(args) == 1:
1577            self.desc = args[0]
1578            self.role = 'SLAVE'
1579        else:
1580            raise TypeError, 'wrong number of arguments'
1581
1582# VectorPort description object.  Like Port, but represents a vector
1583# of connections (e.g., as on a Bus).
1584class VectorPort(Port):
1585    def __init__(self, *args):
1586        self.isVec = True
1587
1588    def makeRef(self, simobj):
1589        return VectorPortRef(simobj, self.name, self.role)
1590
1591class VectorMasterPort(VectorPort):
1592    # VectorMasterPort("description")
1593    def __init__(self, *args):
1594        if len(args) == 1:
1595            self.desc = args[0]
1596            self.role = 'MASTER'
1597            VectorPort.__init__(self, *args)
1598        else:
1599            raise TypeError, 'wrong number of arguments'
1600
1601class VectorSlavePort(VectorPort):
1602    # VectorSlavePort("description")
1603    def __init__(self, *args):
1604        if len(args) == 1:
1605            self.desc = args[0]
1606            self.role = 'SLAVE'
1607            VectorPort.__init__(self, *args)
1608        else:
1609            raise TypeError, 'wrong number of arguments'
1610
1611# 'Fake' ParamDesc for Port references to assign to the _pdesc slot of
1612# proxy objects (via set_param_desc()) so that proxy error messages
1613# make sense.
1614class PortParamDesc(object):
1615    __metaclass__ = Singleton
1616
1617    ptype_str = 'Port'
1618    ptype = Port
1619
1620baseEnums = allEnums.copy()
1621baseParams = allParams.copy()
1622
1623def clear():
1624    global allEnums, allParams
1625
1626    allEnums = baseEnums.copy()
1627    allParams = baseParams.copy()
1628
1629__all__ = ['Param', 'VectorParam',
1630           'Enum', 'Bool', 'String', 'Float',
1631           'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
1632           'Int32', 'UInt32', 'Int64', 'UInt64',
1633           'Counter', 'Addr', 'Tick', 'Percent',
1634           'TcpPort', 'UdpPort', 'EthernetAddr',
1635           'IpAddress', 'IpNetmask', 'IpWithPort',
1636           'MemorySize', 'MemorySize32',
1637           'Latency', 'Frequency', 'Clock', 'Voltage',
1638           'NetworkBandwidth', 'MemoryBandwidth',
1639           'AddrRange',
1640           'MaxAddr', 'MaxTick', 'AllMemory',
1641           'Time',
1642           'NextEthernetAddr', 'NULL',
1643           'MasterPort', 'SlavePort',
1644           'VectorMasterPort', 'VectorSlavePort']
1645
1646import SimObject
1647