SimObject.py revision 1605
112027Sjungma@eit.uni-kl.de# Copyright (c) 2004 The Regents of The University of Michigan
212027Sjungma@eit.uni-kl.de# All rights reserved.
312027Sjungma@eit.uni-kl.de#
412027Sjungma@eit.uni-kl.de# Redistribution and use in source and binary forms, with or without
512027Sjungma@eit.uni-kl.de# modification, are permitted provided that the following conditions are
612027Sjungma@eit.uni-kl.de# met: redistributions of source code must retain the above copyright
712027Sjungma@eit.uni-kl.de# notice, this list of conditions and the following disclaimer;
812027Sjungma@eit.uni-kl.de# redistributions in binary form must reproduce the above copyright
912027Sjungma@eit.uni-kl.de# notice, this list of conditions and the following disclaimer in the
1012027Sjungma@eit.uni-kl.de# documentation and/or other materials provided with the distribution;
1112027Sjungma@eit.uni-kl.de# neither the name of the copyright holders nor the names of its
1212027Sjungma@eit.uni-kl.de# contributors may be used to endorse or promote products derived from
1312027Sjungma@eit.uni-kl.de# this software without specific prior written permission.
1412027Sjungma@eit.uni-kl.de#
1512027Sjungma@eit.uni-kl.de# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1612027Sjungma@eit.uni-kl.de# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1712027Sjungma@eit.uni-kl.de# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1812027Sjungma@eit.uni-kl.de# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
1912027Sjungma@eit.uni-kl.de# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2012027Sjungma@eit.uni-kl.de# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2112027Sjungma@eit.uni-kl.de# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2212027Sjungma@eit.uni-kl.de# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2312027Sjungma@eit.uni-kl.de# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2412027Sjungma@eit.uni-kl.de# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2512027Sjungma@eit.uni-kl.de# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2612027Sjungma@eit.uni-kl.de
2712027Sjungma@eit.uni-kl.defrom __future__ import generators
2812027Sjungma@eit.uni-kl.deimport os, re, sys, types, inspect
2912027Sjungma@eit.uni-kl.de
3012027Sjungma@eit.uni-kl.defrom m5 import panic, env
3112027Sjungma@eit.uni-kl.defrom convert import *
3212027Sjungma@eit.uni-kl.defrom multidict import multidict
3312027Sjungma@eit.uni-kl.de
3412027Sjungma@eit.uni-kl.denoDot = False
3512027Sjungma@eit.uni-kl.detry:
3612027Sjungma@eit.uni-kl.de    import pydot
3712027Sjungma@eit.uni-kl.deexcept:
3812027Sjungma@eit.uni-kl.de    noDot = True
3912027Sjungma@eit.uni-kl.de
4012027Sjungma@eit.uni-kl.declass Singleton(type):
4112027Sjungma@eit.uni-kl.de    def __call__(cls, *args, **kwargs):
4212027Sjungma@eit.uni-kl.de        if hasattr(cls, '_instance'):
4312027Sjungma@eit.uni-kl.de            return cls._instance
4412027Sjungma@eit.uni-kl.de
4512027Sjungma@eit.uni-kl.de        cls._instance = super(Singleton, cls).__call__(*args, **kwargs)
4612027Sjungma@eit.uni-kl.de        return cls._instance
4712027Sjungma@eit.uni-kl.de
4812027Sjungma@eit.uni-kl.de#####################################################################
4912027Sjungma@eit.uni-kl.de#
5012027Sjungma@eit.uni-kl.de# M5 Python Configuration Utility
5112027Sjungma@eit.uni-kl.de#
5212027Sjungma@eit.uni-kl.de# The basic idea is to write simple Python programs that build Python
5312027Sjungma@eit.uni-kl.de# objects corresponding to M5 SimObjects for the deisred simulation
5412027Sjungma@eit.uni-kl.de# configuration.  For now, the Python emits a .ini file that can be
5512027Sjungma@eit.uni-kl.de# parsed by M5.  In the future, some tighter integration between M5
5612027Sjungma@eit.uni-kl.de# and the Python interpreter may allow bypassing the .ini file.
5712027Sjungma@eit.uni-kl.de#
5812027Sjungma@eit.uni-kl.de# Each SimObject class in M5 is represented by a Python class with the
5912027Sjungma@eit.uni-kl.de# same name.  The Python inheritance tree mirrors the M5 C++ tree
6012027Sjungma@eit.uni-kl.de# (e.g., SimpleCPU derives from BaseCPU in both cases, and all
6112027Sjungma@eit.uni-kl.de# SimObjects inherit from a single SimObject base class).  To specify
6212027Sjungma@eit.uni-kl.de# an instance of an M5 SimObject in a configuration, the user simply
6312027Sjungma@eit.uni-kl.de# instantiates the corresponding Python object.  The parameters for
6412027Sjungma@eit.uni-kl.de# that SimObject are given by assigning to attributes of the Python
6512027Sjungma@eit.uni-kl.de# object, either using keyword assignment in the constructor or in
6612027Sjungma@eit.uni-kl.de# separate assignment statements.  For example:
6712027Sjungma@eit.uni-kl.de#
6812027Sjungma@eit.uni-kl.de# cache = BaseCache('my_cache', root, size='64KB')
6912027Sjungma@eit.uni-kl.de# cache.hit_latency = 3
7012027Sjungma@eit.uni-kl.de# cache.assoc = 8
7112027Sjungma@eit.uni-kl.de#
7212027Sjungma@eit.uni-kl.de# (The first two constructor arguments specify the name of the created
7312027Sjungma@eit.uni-kl.de# cache and its parent node in the hierarchy.)
7412027Sjungma@eit.uni-kl.de#
7512027Sjungma@eit.uni-kl.de# The magic lies in the mapping of the Python attributes for SimObject
7612027Sjungma@eit.uni-kl.de# classes to the actual SimObject parameter specifications.  This
7712027Sjungma@eit.uni-kl.de# allows parameter validity checking in the Python code.  Continuing
7812027Sjungma@eit.uni-kl.de# the example above, the statements "cache.blurfl=3" or
7912027Sjungma@eit.uni-kl.de# "cache.assoc='hello'" would both result in runtime errors in Python,
8012027Sjungma@eit.uni-kl.de# since the BaseCache object has no 'blurfl' parameter and the 'assoc'
8112027Sjungma@eit.uni-kl.de# parameter requires an integer, respectively.  This magic is done
8212027Sjungma@eit.uni-kl.de# primarily by overriding the special __setattr__ method that controls
8312027Sjungma@eit.uni-kl.de# assignment to object attributes.
8412027Sjungma@eit.uni-kl.de#
8512027Sjungma@eit.uni-kl.de# The Python module provides another class, ConfigNode, which is a
8612027Sjungma@eit.uni-kl.de# superclass of SimObject.  ConfigNode implements the parent/child
8712027Sjungma@eit.uni-kl.de# relationship for building the configuration hierarchy tree.
8812027Sjungma@eit.uni-kl.de# Concrete instances of ConfigNode can be used to group objects in the
8912027Sjungma@eit.uni-kl.de# hierarchy, but do not correspond to SimObjects themselves (like a
9012027Sjungma@eit.uni-kl.de# .ini section with "children=" but no "type=".
9112027Sjungma@eit.uni-kl.de#
9212027Sjungma@eit.uni-kl.de# Once a set of Python objects have been instantiated in a hierarchy,
9312027Sjungma@eit.uni-kl.de# calling 'instantiate(obj)' (where obj is the root of the hierarchy)
9412027Sjungma@eit.uni-kl.de# will generate a .ini file.  See simple-4cpu.py for an example
9512027Sjungma@eit.uni-kl.de# (corresponding to m5-test/simple-4cpu.ini).
9612027Sjungma@eit.uni-kl.de#
9712027Sjungma@eit.uni-kl.de#####################################################################
9812027Sjungma@eit.uni-kl.de
9912027Sjungma@eit.uni-kl.de#####################################################################
10012027Sjungma@eit.uni-kl.de#
10112027Sjungma@eit.uni-kl.de# ConfigNode/SimObject classes
10212027Sjungma@eit.uni-kl.de#
10312027Sjungma@eit.uni-kl.de# The Python class hierarchy rooted by ConfigNode (which is the base
10412027Sjungma@eit.uni-kl.de# class of SimObject, which in turn is the base class of all other M5
10512027Sjungma@eit.uni-kl.de# SimObject classes) has special attribute behavior.  In general, an
10612027Sjungma@eit.uni-kl.de# object in this hierarchy has three categories of attribute-like
10712027Sjungma@eit.uni-kl.de# things:
10812027Sjungma@eit.uni-kl.de#
10912027Sjungma@eit.uni-kl.de# 1. Regular Python methods and variables.  These must start with an
11012027Sjungma@eit.uni-kl.de# underscore to be treated normally.
11112027Sjungma@eit.uni-kl.de#
11212027Sjungma@eit.uni-kl.de# 2. SimObject parameters.  These values are stored as normal Python
11312027Sjungma@eit.uni-kl.de# attributes, but all assignments to these attributes are checked
11412027Sjungma@eit.uni-kl.de# against the pre-defined set of parameters stored in the class's
11512027Sjungma@eit.uni-kl.de# _params dictionary.  Assignments to attributes that do not
11612027Sjungma@eit.uni-kl.de# correspond to predefined parameters, or that are not of the correct
11712027Sjungma@eit.uni-kl.de# type, incur runtime errors.
11812027Sjungma@eit.uni-kl.de#
11912027Sjungma@eit.uni-kl.de# 3. Hierarchy children.  The child nodes of a ConfigNode are stored
12012027Sjungma@eit.uni-kl.de# in the node's _children dictionary, but can be accessed using the
12112027Sjungma@eit.uni-kl.de# Python attribute dot-notation (just as they are printed out by the
12212027Sjungma@eit.uni-kl.de# simulator).  Children cannot be created using attribute assigment;
12312027Sjungma@eit.uni-kl.de# they must be added by specifying the parent node in the child's
12412027Sjungma@eit.uni-kl.de# constructor or using the '+=' operator.
12512027Sjungma@eit.uni-kl.de
12612027Sjungma@eit.uni-kl.de# The SimObject parameters are the most complex, for a few reasons.
12712027Sjungma@eit.uni-kl.de# First, both parameter descriptions and parameter values are
12812027Sjungma@eit.uni-kl.de# inherited.  Thus parameter description lookup must go up the
12912027Sjungma@eit.uni-kl.de# inheritance chain like normal attribute lookup, but this behavior
13012027Sjungma@eit.uni-kl.de# must be explicitly coded since the lookup occurs in each class's
13112027Sjungma@eit.uni-kl.de# _params attribute.  Second, because parameter values can be set
13212027Sjungma@eit.uni-kl.de# on SimObject classes (to implement default values), the parameter
13312027Sjungma@eit.uni-kl.de# checking behavior must be enforced on class attribute assignments as
13412027Sjungma@eit.uni-kl.de# well as instance attribute assignments.  Finally, because we allow
13512027Sjungma@eit.uni-kl.de# class specialization via inheritance (e.g., see the L1Cache class in
13612027Sjungma@eit.uni-kl.de# the simple-4cpu.py example), we must do parameter checking even on
13712027Sjungma@eit.uni-kl.de# class instantiation.  To provide all these features, we use a
13812027Sjungma@eit.uni-kl.de# metaclass to define most of the SimObject parameter behavior for
13912027Sjungma@eit.uni-kl.de# this class hierarchy.
14012027Sjungma@eit.uni-kl.de#
14112027Sjungma@eit.uni-kl.de#####################################################################
14212027Sjungma@eit.uni-kl.de
14312027Sjungma@eit.uni-kl.declass Proxy(object):
14412027Sjungma@eit.uni-kl.de    def __init__(self, path):
14512027Sjungma@eit.uni-kl.de        self._object = None
14612027Sjungma@eit.uni-kl.de        if path == 'any':
14712027Sjungma@eit.uni-kl.de            self._path = None
14812027Sjungma@eit.uni-kl.de        else:
14912027Sjungma@eit.uni-kl.de            # path is a list of (attr,index) tuples
15012027Sjungma@eit.uni-kl.de            self._path = [(path,None)]
15112027Sjungma@eit.uni-kl.de        self._index = None
15212027Sjungma@eit.uni-kl.de        self._multiplier = None
15312027Sjungma@eit.uni-kl.de
15412027Sjungma@eit.uni-kl.de    def __getattr__(self, attr):
15512027Sjungma@eit.uni-kl.de        # python uses __bases__ internally for inheritance
15612027Sjungma@eit.uni-kl.de        if attr == '__bases__':
15712027Sjungma@eit.uni-kl.de            return super(Proxy, self).__getattr__(self, attr)
15812027Sjungma@eit.uni-kl.de        if (self._path == None):
15912027Sjungma@eit.uni-kl.de            panic("Can't add attributes to 'any' proxy")
16012027Sjungma@eit.uni-kl.de        self._path.append((attr,None))
16112027Sjungma@eit.uni-kl.de        return self
16212027Sjungma@eit.uni-kl.de
16312027Sjungma@eit.uni-kl.de    def __setattr__(self, attr, value):
16412027Sjungma@eit.uni-kl.de        if not attr.startswith('_'):
16512027Sjungma@eit.uni-kl.de            raise AttributeError, 'cannot set attribute %s' % attr
16612027Sjungma@eit.uni-kl.de        super(Proxy, self).__setattr__(attr, value)
16712027Sjungma@eit.uni-kl.de
16812027Sjungma@eit.uni-kl.de    # support indexing on proxies (e.g., parent.cpu[0])
16912027Sjungma@eit.uni-kl.de    def __getitem__(self, key):
17012027Sjungma@eit.uni-kl.de        if not isinstance(key, int):
17112027Sjungma@eit.uni-kl.de            raise TypeError, "Proxy object requires integer index"
17212027Sjungma@eit.uni-kl.de        if self._path == None:
17312027Sjungma@eit.uni-kl.de            raise IndexError, "Index applied to 'any' proxy"
17412027Sjungma@eit.uni-kl.de        # replace index portion of last path element with new index
17512027Sjungma@eit.uni-kl.de        self._path[-1] = (self._path[-1][0], key)
17612027Sjungma@eit.uni-kl.de        return self
17712027Sjungma@eit.uni-kl.de
17812027Sjungma@eit.uni-kl.de    # support multiplying proxies by constants
17912027Sjungma@eit.uni-kl.de    def __mul__(self, other):
18012027Sjungma@eit.uni-kl.de        if not isinstance(other, int):
18112027Sjungma@eit.uni-kl.de            raise TypeError, "Proxy multiplier must be integer"
18212027Sjungma@eit.uni-kl.de        if self._multiplier == None:
18312027Sjungma@eit.uni-kl.de            self._multiplier = other
18412027Sjungma@eit.uni-kl.de        else:
18512027Sjungma@eit.uni-kl.de            # support chained multipliers
18612027Sjungma@eit.uni-kl.de            self._multiplier *= other
18712027Sjungma@eit.uni-kl.de        return self
18812027Sjungma@eit.uni-kl.de
18912027Sjungma@eit.uni-kl.de    def _mulcheck(self, result):
19012027Sjungma@eit.uni-kl.de        if self._multiplier == None:
19112027Sjungma@eit.uni-kl.de            return result
19212027Sjungma@eit.uni-kl.de        if not isinstance(result, int):
19312027Sjungma@eit.uni-kl.de            raise TypeError, "Proxy with multiplier resolves to " \
19412027Sjungma@eit.uni-kl.de                  "non-integer value"
19512027Sjungma@eit.uni-kl.de        return result * self._multiplier
19612027Sjungma@eit.uni-kl.de
19712027Sjungma@eit.uni-kl.de    def unproxy(self, base, ptype):
19812027Sjungma@eit.uni-kl.de        obj = base
19912027Sjungma@eit.uni-kl.de        done = False
20012027Sjungma@eit.uni-kl.de        while not done:
20112027Sjungma@eit.uni-kl.de            if obj is None:
20212027Sjungma@eit.uni-kl.de                raise AttributeError, \
20312027Sjungma@eit.uni-kl.de                      'Parent of %s type %s not found at path %s' \
20412027Sjungma@eit.uni-kl.de                      % (base.name, ptype, self._path)
20512027Sjungma@eit.uni-kl.de
20612027Sjungma@eit.uni-kl.de            result, done = obj.find(ptype, self._path)
20712027Sjungma@eit.uni-kl.de            obj = obj.parent
20812027Sjungma@eit.uni-kl.de
20912027Sjungma@eit.uni-kl.de        if isinstance(result, Proxy):
21012027Sjungma@eit.uni-kl.de            result = result.unproxy(obj, ptype)
21112027Sjungma@eit.uni-kl.de
21212027Sjungma@eit.uni-kl.de        return self._mulcheck(result)
21312027Sjungma@eit.uni-kl.de
21412027Sjungma@eit.uni-kl.de    def getindex(obj, index):
21512027Sjungma@eit.uni-kl.de        if index == None:
21612027Sjungma@eit.uni-kl.de            return obj
21712027Sjungma@eit.uni-kl.de        try:
21812027Sjungma@eit.uni-kl.de            obj = obj[index]
21912027Sjungma@eit.uni-kl.de        except TypeError:
22012027Sjungma@eit.uni-kl.de            if index != 0:
22112027Sjungma@eit.uni-kl.de                raise
22212027Sjungma@eit.uni-kl.de            # if index is 0 and item is not subscriptable, just
22312027Sjungma@eit.uni-kl.de            # use item itself (so cpu[0] works on uniprocessors)
22412027Sjungma@eit.uni-kl.de        return obj
22512027Sjungma@eit.uni-kl.de    getindex = staticmethod(getindex)
22612027Sjungma@eit.uni-kl.de
22712027Sjungma@eit.uni-kl.declass ProxyFactory(object):
22812027Sjungma@eit.uni-kl.de    def __getattr__(self, attr):
22912027Sjungma@eit.uni-kl.de        return Proxy(attr)
23012027Sjungma@eit.uni-kl.de
23112027Sjungma@eit.uni-kl.de# global object for handling parent.foo proxies
23212027Sjungma@eit.uni-kl.deparent = ProxyFactory()
23312027Sjungma@eit.uni-kl.de
23412027Sjungma@eit.uni-kl.dedef isSubClass(value, cls):
23512027Sjungma@eit.uni-kl.de    try:
23612027Sjungma@eit.uni-kl.de        return issubclass(value, cls)
23712027Sjungma@eit.uni-kl.de    except:
23812027Sjungma@eit.uni-kl.de        return False
23912027Sjungma@eit.uni-kl.de
24012027Sjungma@eit.uni-kl.dedef isConfigNode(value):
24112027Sjungma@eit.uni-kl.de    try:
24212027Sjungma@eit.uni-kl.de        return issubclass(value, ConfigNode)
24312027Sjungma@eit.uni-kl.de    except:
24412027Sjungma@eit.uni-kl.de        return False
24512027Sjungma@eit.uni-kl.de
24612027Sjungma@eit.uni-kl.dedef isSimObject(value):
24712027Sjungma@eit.uni-kl.de    try:
24812027Sjungma@eit.uni-kl.de        return issubclass(value, SimObject)
24912027Sjungma@eit.uni-kl.de    except:
25012027Sjungma@eit.uni-kl.de        return False
25112027Sjungma@eit.uni-kl.de
25212027Sjungma@eit.uni-kl.dedef isSimObjSequence(value):
25312027Sjungma@eit.uni-kl.de    if not isinstance(value, (list, tuple)):
25412027Sjungma@eit.uni-kl.de        return False
25512027Sjungma@eit.uni-kl.de
25612027Sjungma@eit.uni-kl.de    for val in value:
25712027Sjungma@eit.uni-kl.de        if not isNullPointer(val) and not isConfigNode(val):
25812027Sjungma@eit.uni-kl.de            return False
25912027Sjungma@eit.uni-kl.de
26012027Sjungma@eit.uni-kl.de    return True
26112027Sjungma@eit.uni-kl.de
26212027Sjungma@eit.uni-kl.dedef isParamContext(value):
26312027Sjungma@eit.uni-kl.de    try:
26412027Sjungma@eit.uni-kl.de        return issubclass(value, ParamContext)
26512027Sjungma@eit.uni-kl.de    except:
26612027Sjungma@eit.uni-kl.de        return False
26712027Sjungma@eit.uni-kl.de
26812027Sjungma@eit.uni-kl.de
26912027Sjungma@eit.uni-kl.declass_decorator = 'M5M5_SIMOBJECT_'
27012027Sjungma@eit.uni-kl.deexpr_decorator = 'M5M5_EXPRESSION_'
27112027Sjungma@eit.uni-kl.dedot_decorator = '_M5M5_DOT_'
27212027Sjungma@eit.uni-kl.de
27312027Sjungma@eit.uni-kl.de# 'Global' map of legitimate types for SimObject parameters.
27412027Sjungma@eit.uni-kl.deparam_types = {}
27512027Sjungma@eit.uni-kl.de
27612027Sjungma@eit.uni-kl.de# Dummy base class to identify types that are legitimate for SimObject
27712027Sjungma@eit.uni-kl.de# parameters.
27812027Sjungma@eit.uni-kl.declass ParamType(object):
27912027Sjungma@eit.uni-kl.de    pass
28012027Sjungma@eit.uni-kl.de
28112027Sjungma@eit.uni-kl.de# Add types defined in given context (dict or module) that are derived
28212027Sjungma@eit.uni-kl.de# from ParamType to param_types map.
28312027Sjungma@eit.uni-kl.dedef add_param_types(ctx):
28412027Sjungma@eit.uni-kl.de    if isinstance(ctx, types.DictType):
28512027Sjungma@eit.uni-kl.de        source_dict = ctx
28612027Sjungma@eit.uni-kl.de    elif isinstance(ctx, types.ModuleType):
28712027Sjungma@eit.uni-kl.de        source_dict = ctx.__dict__
28812027Sjungma@eit.uni-kl.de    else:
28912027Sjungma@eit.uni-kl.de        raise TypeError, \
29012027Sjungma@eit.uni-kl.de              "m5.config.add_param_types requires dict or module as arg"
29112027Sjungma@eit.uni-kl.de    for key,val in source_dict.iteritems():
29212027Sjungma@eit.uni-kl.de        if isinstance(val, type) and issubclass(val, ParamType):
29312027Sjungma@eit.uni-kl.de            param_types[key] = val
29412027Sjungma@eit.uni-kl.de
29512027Sjungma@eit.uni-kl.de# The metaclass for ConfigNode (and thus for everything that derives
29612027Sjungma@eit.uni-kl.de# from ConfigNode, including SimObject).  This class controls how new
29712027Sjungma@eit.uni-kl.de# classes that derive from ConfigNode are instantiated, and provides
29812027Sjungma@eit.uni-kl.de# inherited class behavior (just like a class controls how instances
29912027Sjungma@eit.uni-kl.de# of that class are instantiated, and provides inherited instance
30012027Sjungma@eit.uni-kl.de# behavior).
30112027Sjungma@eit.uni-kl.declass MetaConfigNode(type):
30212027Sjungma@eit.uni-kl.de    # Attributes that can be set only at initialization time
30312027Sjungma@eit.uni-kl.de    init_keywords = {}
30412027Sjungma@eit.uni-kl.de    # Attributes that can be set any time
30512027Sjungma@eit.uni-kl.de    keywords = { 'check' : types.FunctionType,
30612027Sjungma@eit.uni-kl.de                 'children' : types.ListType }
30712027Sjungma@eit.uni-kl.de
30812027Sjungma@eit.uni-kl.de    # __new__ is called before __init__, and is where the statements
30912027Sjungma@eit.uni-kl.de    # in the body of the class definition get loaded into the class's
31012027Sjungma@eit.uni-kl.de    # __dict__.  We intercept this to filter out parameter assignments
31112027Sjungma@eit.uni-kl.de    # and only allow "private" attributes to be passed to the base
31212027Sjungma@eit.uni-kl.de    # __new__ (starting with underscore).
31312027Sjungma@eit.uni-kl.de    def __new__(mcls, name, bases, dict):
31412027Sjungma@eit.uni-kl.de        # Copy "private" attributes (including special methods such as __new__)
31512027Sjungma@eit.uni-kl.de        # to the official dict.  Everything else goes in _init_dict to be
31612027Sjungma@eit.uni-kl.de        # filtered in __init__.
31712027Sjungma@eit.uni-kl.de        cls_dict = {}
31812027Sjungma@eit.uni-kl.de        for key,val in dict.items():
31912027Sjungma@eit.uni-kl.de            if key.startswith('_'):
32012027Sjungma@eit.uni-kl.de                cls_dict[key] = val
32112027Sjungma@eit.uni-kl.de                del dict[key]
32212027Sjungma@eit.uni-kl.de        cls_dict['_init_dict'] = dict
32312027Sjungma@eit.uni-kl.de        return super(MetaConfigNode, mcls).__new__(mcls, name, bases, cls_dict)
32412027Sjungma@eit.uni-kl.de
32512027Sjungma@eit.uni-kl.de    # initialization
32612027Sjungma@eit.uni-kl.de    def __init__(cls, name, bases, dict):
32712027Sjungma@eit.uni-kl.de        super(MetaConfigNode, cls).__init__(name, bases, dict)
32812027Sjungma@eit.uni-kl.de
32912027Sjungma@eit.uni-kl.de        # initialize required attributes
33012027Sjungma@eit.uni-kl.de        cls._params = multidict()
33112027Sjungma@eit.uni-kl.de        cls._values = multidict()
33212027Sjungma@eit.uni-kl.de        cls._param_types = {}
33312027Sjungma@eit.uni-kl.de        cls._bases = [c for c in cls.__mro__ if isConfigNode(c)]
33412027Sjungma@eit.uni-kl.de        cls._anon_subclass_counter = 0
33512027Sjungma@eit.uni-kl.de
33612027Sjungma@eit.uni-kl.de        # We don't support multiple inheritence.  If you want to, you
33712027Sjungma@eit.uni-kl.de        # must fix multidict to deal with it properly.
33812027Sjungma@eit.uni-kl.de        cnbase = [ base for base in bases if isConfigNode(base) ]
33912027Sjungma@eit.uni-kl.de        if len(cnbase) == 1:
34012027Sjungma@eit.uni-kl.de            # If your parent has a value in it that's a config node, clone
34112027Sjungma@eit.uni-kl.de            # it.  Do this now so if we update any of the values'
34212027Sjungma@eit.uni-kl.de            # attributes we are updating the clone and not the original.
34312027Sjungma@eit.uni-kl.de            for key,val in cnbase[0]._values.iteritems():
34412027Sjungma@eit.uni-kl.de
34512027Sjungma@eit.uni-kl.de                # don't clone if (1) we're about to overwrite it with
34612027Sjungma@eit.uni-kl.de                # a local setting or (2) we've already cloned a copy
34712027Sjungma@eit.uni-kl.de                # from an earlier (more derived) base
34812027Sjungma@eit.uni-kl.de                if cls._init_dict.has_key(key) or cls._values.has_key(key):
34912027Sjungma@eit.uni-kl.de                    continue
35012027Sjungma@eit.uni-kl.de
35112027Sjungma@eit.uni-kl.de                if isConfigNode(val):
35212027Sjungma@eit.uni-kl.de                    cls._values[key] = val()
35312027Sjungma@eit.uni-kl.de                elif isSimObjSequence(val) and len(val):
35412027Sjungma@eit.uni-kl.de                    cls._values[key] = [ v() for v in val ]
35512027Sjungma@eit.uni-kl.de
35612027Sjungma@eit.uni-kl.de            cls._params.parent = cnbase[0]._params
35712027Sjungma@eit.uni-kl.de            cls._values.parent = cnbase[0]._values
35812027Sjungma@eit.uni-kl.de
35912027Sjungma@eit.uni-kl.de        elif len(cnbase) > 1:
36012027Sjungma@eit.uni-kl.de            panic("""\
36112027Sjungma@eit.uni-kl.deThe config hierarchy only supports single inheritence of SimObject
36212027Sjungma@eit.uni-kl.declasses. You're trying to derive from:
36312027Sjungma@eit.uni-kl.de%s""" % str(cnbase))
36412027Sjungma@eit.uni-kl.de
36512027Sjungma@eit.uni-kl.de        # process param types from _init_dict, as these may be needed
36612027Sjungma@eit.uni-kl.de        # by param descriptions also in _init_dict
36712027Sjungma@eit.uni-kl.de        for key,val in cls._init_dict.items():
36812027Sjungma@eit.uni-kl.de            if isinstance(val, type) and issubclass(val, ParamType):
36912027Sjungma@eit.uni-kl.de                cls._param_types[key] = val
37012027Sjungma@eit.uni-kl.de                if not issubclass(val, ConfigNode):
37112027Sjungma@eit.uni-kl.de                    del cls._init_dict[key]
37212027Sjungma@eit.uni-kl.de
37312027Sjungma@eit.uni-kl.de        # now process remaining _init_dict items
37412027Sjungma@eit.uni-kl.de        for key,val in cls._init_dict.items():
37512027Sjungma@eit.uni-kl.de            # param descriptions
37612027Sjungma@eit.uni-kl.de            if isinstance(val, ParamBase):
37712027Sjungma@eit.uni-kl.de                cls._new_param(key, val)
37812027Sjungma@eit.uni-kl.de
37912027Sjungma@eit.uni-kl.de            # init-time-only keywords
38012027Sjungma@eit.uni-kl.de            elif cls.init_keywords.has_key(key):
38112027Sjungma@eit.uni-kl.de                cls._set_keyword(key, val, cls.init_keywords[key])
38212027Sjungma@eit.uni-kl.de
38312027Sjungma@eit.uni-kl.de            # See description of decorators in the importer.py file.
38412027Sjungma@eit.uni-kl.de            # We just strip off the expr_decorator now since we don't
38512027Sjungma@eit.uni-kl.de            # need from this point on.
38612027Sjungma@eit.uni-kl.de            elif key.startswith(expr_decorator):
38712027Sjungma@eit.uni-kl.de                key = key[len(expr_decorator):]
38812027Sjungma@eit.uni-kl.de                # because it had dots into a list so that we can find the
38912027Sjungma@eit.uni-kl.de                # proper variable to modify.
39012027Sjungma@eit.uni-kl.de                key = key.split(dot_decorator)
39112027Sjungma@eit.uni-kl.de                c = cls
39212027Sjungma@eit.uni-kl.de                for item in key[:-1]:
39312027Sjungma@eit.uni-kl.de                    c = getattr(c, item)
39412027Sjungma@eit.uni-kl.de                setattr(c, key[-1], val)
39512027Sjungma@eit.uni-kl.de
39612027Sjungma@eit.uni-kl.de            # default: use normal path (ends up in __setattr__)
39712027Sjungma@eit.uni-kl.de            else:
39812027Sjungma@eit.uni-kl.de                setattr(cls, key, val)
39912027Sjungma@eit.uni-kl.de
40012027Sjungma@eit.uni-kl.de    def _set_keyword(cls, keyword, val, kwtype):
40112027Sjungma@eit.uni-kl.de        if not isinstance(val, kwtype):
40212027Sjungma@eit.uni-kl.de            raise TypeError, 'keyword %s has bad type %s (expecting %s)' % \
40312027Sjungma@eit.uni-kl.de                  (keyword, type(val), kwtype)
40412027Sjungma@eit.uni-kl.de        if isinstance(val, types.FunctionType):
40512027Sjungma@eit.uni-kl.de            val = classmethod(val)
40612027Sjungma@eit.uni-kl.de        type.__setattr__(cls, keyword, val)
40712027Sjungma@eit.uni-kl.de
40812027Sjungma@eit.uni-kl.de    def _new_param(cls, name, value):
40912027Sjungma@eit.uni-kl.de        cls._params[name] = value
41012027Sjungma@eit.uni-kl.de        if hasattr(value, 'default'):
41112027Sjungma@eit.uni-kl.de            cls._values[name] = value.default
41212027Sjungma@eit.uni-kl.de        # try to resolve local param types in local param_types scope
41312027Sjungma@eit.uni-kl.de        value.maybe_resolve_type(cls._param_types)
41412027Sjungma@eit.uni-kl.de
41512027Sjungma@eit.uni-kl.de    # Set attribute (called on foo.attr = value when foo is an
41612027Sjungma@eit.uni-kl.de    # instance of class cls).
41712027Sjungma@eit.uni-kl.de    def __setattr__(cls, attr, value):
41812027Sjungma@eit.uni-kl.de        # normal processing for private attributes
41912027Sjungma@eit.uni-kl.de        if attr.startswith('_'):
42012027Sjungma@eit.uni-kl.de            type.__setattr__(cls, attr, value)
42112027Sjungma@eit.uni-kl.de            return
42212027Sjungma@eit.uni-kl.de
42312027Sjungma@eit.uni-kl.de        if cls.keywords.has_key(attr):
42412027Sjungma@eit.uni-kl.de            cls._set_keyword(attr, value, cls.keywords[attr])
42512027Sjungma@eit.uni-kl.de            return
42612027Sjungma@eit.uni-kl.de
42712027Sjungma@eit.uni-kl.de        # must be SimObject param
42812027Sjungma@eit.uni-kl.de        param = cls._params.get(attr, None)
42912027Sjungma@eit.uni-kl.de        if param:
43012027Sjungma@eit.uni-kl.de            # It's ok: set attribute by delegating to 'object' class.
43112027Sjungma@eit.uni-kl.de            # Note the use of param.make_value() to verify/canonicalize
43212027Sjungma@eit.uni-kl.de            # the assigned value
43312027Sjungma@eit.uni-kl.de            try:
43412027Sjungma@eit.uni-kl.de                param.valid(value)
43512027Sjungma@eit.uni-kl.de            except Exception, e:
43612027Sjungma@eit.uni-kl.de                msg = "%s\nError setting param %s.%s to %s\n" % \
43712027Sjungma@eit.uni-kl.de                      (e, cls.__name__, attr, value)
43812027Sjungma@eit.uni-kl.de                e.args = (msg, )
43912027Sjungma@eit.uni-kl.de                raise
44012027Sjungma@eit.uni-kl.de            cls._values[attr] = value
44112027Sjungma@eit.uni-kl.de        elif isConfigNode(value) or isSimObjSequence(value):
44212027Sjungma@eit.uni-kl.de            cls._values[attr] = value
44312027Sjungma@eit.uni-kl.de        else:
44412027Sjungma@eit.uni-kl.de            raise AttributeError, \
44512027Sjungma@eit.uni-kl.de                  "Class %s has no parameter %s" % (cls.__name__, attr)
44612027Sjungma@eit.uni-kl.de
44712027Sjungma@eit.uni-kl.de    def __getattr__(cls, attr):
44812027Sjungma@eit.uni-kl.de        if cls._params.has_key(attr) or cls._values.has_key(attr):
44912027Sjungma@eit.uni-kl.de            return Value(cls, attr)
45012027Sjungma@eit.uni-kl.de
45112027Sjungma@eit.uni-kl.de        if attr == '_cpp_param_decl' and hasattr(cls, 'type'):
45212027Sjungma@eit.uni-kl.de            return cls.type + '*'
45312027Sjungma@eit.uni-kl.de
45412027Sjungma@eit.uni-kl.de        raise AttributeError, \
45512027Sjungma@eit.uni-kl.de              "object '%s' has no attribute '%s'" % (cls.__name__, attr)
45612027Sjungma@eit.uni-kl.de
45712027Sjungma@eit.uni-kl.de    def add_child(cls, instance, name, child):
45812027Sjungma@eit.uni-kl.de        if isNullPointer(child) or instance.top_child_names.has_key(name):
45912027Sjungma@eit.uni-kl.de            return
46012027Sjungma@eit.uni-kl.de
46112027Sjungma@eit.uni-kl.de        if isinstance(child, (list, tuple)):
46212027Sjungma@eit.uni-kl.de            kid = []
46312027Sjungma@eit.uni-kl.de            for i,c in enumerate(child):
46412027Sjungma@eit.uni-kl.de                n = '%s%d' % (name, i)
46512027Sjungma@eit.uni-kl.de                k = c.instantiate(n, instance)
46612027Sjungma@eit.uni-kl.de
46712027Sjungma@eit.uni-kl.de                instance.children.append(k)
46812027Sjungma@eit.uni-kl.de                instance.child_names[n] = k
46912027Sjungma@eit.uni-kl.de                instance.child_objects[c] = k
47012027Sjungma@eit.uni-kl.de                kid.append(k)
47112027Sjungma@eit.uni-kl.de        else:
47212027Sjungma@eit.uni-kl.de            kid = child.instantiate(name, instance)
47312027Sjungma@eit.uni-kl.de            instance.children.append(kid)
47412027Sjungma@eit.uni-kl.de            instance.child_names[name] = kid
47512027Sjungma@eit.uni-kl.de            instance.child_objects[child] = kid
47612027Sjungma@eit.uni-kl.de
47712027Sjungma@eit.uni-kl.de        instance.top_child_names[name] = kid
47812027Sjungma@eit.uni-kl.de
47912027Sjungma@eit.uni-kl.de    # Print instance info to .ini file.
48012027Sjungma@eit.uni-kl.de    def instantiate(cls, name, parent = None):
48112027Sjungma@eit.uni-kl.de        instance = Node(name, cls, parent, isParamContext(cls))
48212027Sjungma@eit.uni-kl.de
48312027Sjungma@eit.uni-kl.de        if hasattr(cls, 'check'):
48412027Sjungma@eit.uni-kl.de            cls.check()
48512027Sjungma@eit.uni-kl.de
48612027Sjungma@eit.uni-kl.de        for key,value in cls._values.iteritems():
48712027Sjungma@eit.uni-kl.de            if isConfigNode(value):
48812027Sjungma@eit.uni-kl.de                cls.add_child(instance, key, value)
48912027Sjungma@eit.uni-kl.de            if isinstance(value, (list, tuple)):
49012027Sjungma@eit.uni-kl.de                vals = [ v for v in value if isConfigNode(v) ]
49112027Sjungma@eit.uni-kl.de                if len(vals):
49212027Sjungma@eit.uni-kl.de                    cls.add_child(instance, key, vals)
49312027Sjungma@eit.uni-kl.de
49412027Sjungma@eit.uni-kl.de        for pname,param in cls._params.iteritems():
49512027Sjungma@eit.uni-kl.de            value = cls._values.get(pname, None)
49612027Sjungma@eit.uni-kl.de            if value is None:
49712027Sjungma@eit.uni-kl.de                panic('Error getting %s from %s' % (pname, name))
49812027Sjungma@eit.uni-kl.de
49912027Sjungma@eit.uni-kl.de            try:
50012027Sjungma@eit.uni-kl.de                if isConfigNode(value):
50112027Sjungma@eit.uni-kl.de                    value = instance.child_objects[value]
50212027Sjungma@eit.uni-kl.de                elif isinstance(value, (list, tuple)):
50312027Sjungma@eit.uni-kl.de                    v = []
50412027Sjungma@eit.uni-kl.de                    for val in value:
50512027Sjungma@eit.uni-kl.de                        if isConfigNode(val):
50612027Sjungma@eit.uni-kl.de                            v.append(instance.child_objects[val])
50712027Sjungma@eit.uni-kl.de                        else:
50812027Sjungma@eit.uni-kl.de                            v.append(val)
50912027Sjungma@eit.uni-kl.de                    value = v
51012027Sjungma@eit.uni-kl.de
51112027Sjungma@eit.uni-kl.de                p = NodeParam(pname, param, value)
51212027Sjungma@eit.uni-kl.de                instance.params.append(p)
51312027Sjungma@eit.uni-kl.de                instance.param_names[pname] = p
51412027Sjungma@eit.uni-kl.de            except Exception, e:
51512027Sjungma@eit.uni-kl.de                msg = 'Exception while evaluating %s.%s\n%s' % \
51612027Sjungma@eit.uni-kl.de                      (instance.path, pname, e)
51712027Sjungma@eit.uni-kl.de                e.args = (msg, )
51812027Sjungma@eit.uni-kl.de                raise
51912027Sjungma@eit.uni-kl.de
52012027Sjungma@eit.uni-kl.de        return instance
52112027Sjungma@eit.uni-kl.de
52212027Sjungma@eit.uni-kl.de    def _convert(cls, value):
52312027Sjungma@eit.uni-kl.de        realvalue = value
52412027Sjungma@eit.uni-kl.de        if isinstance(value, Node):
52512027Sjungma@eit.uni-kl.de            realvalue = value.realtype
52612027Sjungma@eit.uni-kl.de
52712027Sjungma@eit.uni-kl.de        if isinstance(realvalue, Proxy):
52812027Sjungma@eit.uni-kl.de            return value
52912027Sjungma@eit.uni-kl.de
53012027Sjungma@eit.uni-kl.de        if realvalue == None or isNullPointer(realvalue):
53112027Sjungma@eit.uni-kl.de            return value
53212027Sjungma@eit.uni-kl.de
53312027Sjungma@eit.uni-kl.de        if isSubClass(realvalue, cls):
53412027Sjungma@eit.uni-kl.de            return value
53512027Sjungma@eit.uni-kl.de
53612027Sjungma@eit.uni-kl.de        raise TypeError, 'object %s type %s wrong type, should be %s' % \
53712027Sjungma@eit.uni-kl.de              (repr(realvalue), realvalue, cls)
53812027Sjungma@eit.uni-kl.de
53912027Sjungma@eit.uni-kl.de    def _string(cls, value):
54012027Sjungma@eit.uni-kl.de        if isNullPointer(value):
54112027Sjungma@eit.uni-kl.de            return 'Null'
54212027Sjungma@eit.uni-kl.de        return Node._string(value)
54312027Sjungma@eit.uni-kl.de
54412027Sjungma@eit.uni-kl.de# The ConfigNode class is the root of the special hierarchy.  Most of
54512027Sjungma@eit.uni-kl.de# the code in this class deals with the configuration hierarchy itself
54612027Sjungma@eit.uni-kl.de# (parent/child node relationships).
54712027Sjungma@eit.uni-kl.declass ConfigNode(object):
54812027Sjungma@eit.uni-kl.de    # Specify metaclass.  Any class inheriting from ConfigNode will
54912027Sjungma@eit.uni-kl.de    # get this metaclass.
55012027Sjungma@eit.uni-kl.de    __metaclass__ = MetaConfigNode
55112027Sjungma@eit.uni-kl.de
55212027Sjungma@eit.uni-kl.de    def __new__(cls, **kwargs):
55312027Sjungma@eit.uni-kl.de        name = cls.__name__ + ("_%d" % cls._anon_subclass_counter)
55412027Sjungma@eit.uni-kl.de        cls._anon_subclass_counter += 1
55512027Sjungma@eit.uni-kl.de        return cls.__metaclass__(name, (cls, ), kwargs)
55612027Sjungma@eit.uni-kl.de
55712027Sjungma@eit.uni-kl.declass ParamContext(ConfigNode,ParamType):
55812027Sjungma@eit.uni-kl.de    pass
55912027Sjungma@eit.uni-kl.de
56012027Sjungma@eit.uni-kl.declass MetaSimObject(MetaConfigNode):
56112027Sjungma@eit.uni-kl.de    # init_keywords and keywords are inherited from MetaConfigNode,
56212027Sjungma@eit.uni-kl.de    # with overrides/additions
56312027Sjungma@eit.uni-kl.de    init_keywords = MetaConfigNode.init_keywords
56412027Sjungma@eit.uni-kl.de    init_keywords.update({ 'abstract' : types.BooleanType,
56512027Sjungma@eit.uni-kl.de                           'type' : types.StringType })
56612027Sjungma@eit.uni-kl.de
56712027Sjungma@eit.uni-kl.de    keywords = MetaConfigNode.keywords
56812027Sjungma@eit.uni-kl.de    # no additional keywords
56912027Sjungma@eit.uni-kl.de
57012027Sjungma@eit.uni-kl.de    cpp_classes = []
57112027Sjungma@eit.uni-kl.de
57212027Sjungma@eit.uni-kl.de    # initialization
57312027Sjungma@eit.uni-kl.de    def __init__(cls, name, bases, dict):
57412027Sjungma@eit.uni-kl.de        super(MetaSimObject, cls).__init__(name, bases, dict)
57512027Sjungma@eit.uni-kl.de
57612027Sjungma@eit.uni-kl.de        if hasattr(cls, 'type'):
57712027Sjungma@eit.uni-kl.de            if name == 'SimObject':
57812027Sjungma@eit.uni-kl.de                cls._cpp_base = None
57912027Sjungma@eit.uni-kl.de            elif hasattr(cls._bases[1], 'type'):
58012027Sjungma@eit.uni-kl.de                cls._cpp_base = cls._bases[1].type
58112027Sjungma@eit.uni-kl.de            else:
58212027Sjungma@eit.uni-kl.de                panic("SimObject %s derives from a non-C++ SimObject %s "\
58312027Sjungma@eit.uni-kl.de                      "(no 'type')" % (cls, cls_bases[1].__name__))
58412027Sjungma@eit.uni-kl.de
58512027Sjungma@eit.uni-kl.de            # This class corresponds to a C++ class: put it on the global
58612027Sjungma@eit.uni-kl.de            # list of C++ objects to generate param structs, etc.
58712027Sjungma@eit.uni-kl.de            MetaSimObject.cpp_classes.append(cls)
58812027Sjungma@eit.uni-kl.de
58912027Sjungma@eit.uni-kl.de    def _cpp_decl(cls):
59012027Sjungma@eit.uni-kl.de        name = cls.__name__
59112027Sjungma@eit.uni-kl.de        code = ""
59212027Sjungma@eit.uni-kl.de        code += "\n".join([e.cpp_declare() for e in cls._param_types.values()])
59312027Sjungma@eit.uni-kl.de        code += "\n"
59412027Sjungma@eit.uni-kl.de        param_names = cls._params.keys()
59512027Sjungma@eit.uni-kl.de        param_names.sort()
59612027Sjungma@eit.uni-kl.de        code += "struct Params"
59712027Sjungma@eit.uni-kl.de        if cls._cpp_base:
59812027Sjungma@eit.uni-kl.de            code += " : public %s::Params" % cls._cpp_base
59912027Sjungma@eit.uni-kl.de        code += " {\n    "
60012027Sjungma@eit.uni-kl.de        code += "\n    ".join([cls._params[pname].cpp_decl(pname) \
60112027Sjungma@eit.uni-kl.de                               for pname in param_names])
60212027Sjungma@eit.uni-kl.de        code += "\n};\n"
60312027Sjungma@eit.uni-kl.de        return code
60412027Sjungma@eit.uni-kl.de
60512027Sjungma@eit.uni-kl.declass NodeParam(object):
60612027Sjungma@eit.uni-kl.de    def __init__(self, name, param, value):
60712027Sjungma@eit.uni-kl.de        self.name = name
60812027Sjungma@eit.uni-kl.de        self.param = param
60912027Sjungma@eit.uni-kl.de        self.ptype = param.ptype
61012027Sjungma@eit.uni-kl.de        self.convert = param.convert
61112027Sjungma@eit.uni-kl.de        self.string = param.string
61212027Sjungma@eit.uni-kl.de        self.value = value
61312027Sjungma@eit.uni-kl.de
61412027Sjungma@eit.uni-kl.declass Node(object):
61512027Sjungma@eit.uni-kl.de    all = {}
61612027Sjungma@eit.uni-kl.de    def __init__(self, name, realtype, parent, paramcontext):
61712027Sjungma@eit.uni-kl.de        self.name = name
61812027Sjungma@eit.uni-kl.de        self.realtype = realtype
61912027Sjungma@eit.uni-kl.de        if isSimObject(realtype):
62012027Sjungma@eit.uni-kl.de            self.type = realtype.type
62112027Sjungma@eit.uni-kl.de        else:
62212027Sjungma@eit.uni-kl.de            self.type = None
62312027Sjungma@eit.uni-kl.de        self.parent = parent
62412027Sjungma@eit.uni-kl.de        self.children = []
62512027Sjungma@eit.uni-kl.de        self.child_names = {}
62612027Sjungma@eit.uni-kl.de        self.child_objects = {}
62712027Sjungma@eit.uni-kl.de        self.top_child_names = {}
62812027Sjungma@eit.uni-kl.de        self.params = []
62912027Sjungma@eit.uni-kl.de        self.param_names = {}
63012027Sjungma@eit.uni-kl.de        self.paramcontext = paramcontext
63112027Sjungma@eit.uni-kl.de
63212027Sjungma@eit.uni-kl.de        path = [ self.name ]
63312027Sjungma@eit.uni-kl.de        node = self.parent
63412027Sjungma@eit.uni-kl.de        while node is not None:
63512027Sjungma@eit.uni-kl.de            if node.name != 'root':
63612027Sjungma@eit.uni-kl.de                path.insert(0, node.name)
63712027Sjungma@eit.uni-kl.de            else:
63812027Sjungma@eit.uni-kl.de                assert(node.parent is None)
63912027Sjungma@eit.uni-kl.de            node = node.parent
64012027Sjungma@eit.uni-kl.de        self.path = '.'.join(path)
64112027Sjungma@eit.uni-kl.de
64212027Sjungma@eit.uni-kl.de    def find(self, realtype, path):
64312027Sjungma@eit.uni-kl.de        if not path:
64412027Sjungma@eit.uni-kl.de            if issubclass(self.realtype, realtype):
64512027Sjungma@eit.uni-kl.de                return self, True
64612027Sjungma@eit.uni-kl.de
64712027Sjungma@eit.uni-kl.de            obj = None
64812027Sjungma@eit.uni-kl.de            for child in self.children:
64912027Sjungma@eit.uni-kl.de                if issubclass(child.realtype, realtype):
65012027Sjungma@eit.uni-kl.de                    if obj is not None:
65112027Sjungma@eit.uni-kl.de                        raise AttributeError, \
65212027Sjungma@eit.uni-kl.de                              'parent.any matched more than one: %s %s' % \
65312027Sjungma@eit.uni-kl.de                              (obj.path, child.path)
65412027Sjungma@eit.uni-kl.de                    obj = child
65512027Sjungma@eit.uni-kl.de            return obj, obj is not None
65612027Sjungma@eit.uni-kl.de
65712027Sjungma@eit.uni-kl.de        try:
65812027Sjungma@eit.uni-kl.de            obj = self
65912027Sjungma@eit.uni-kl.de            for (node,index) in path[:-1]:
66012027Sjungma@eit.uni-kl.de                if obj.child_names.has_key(node):
66112027Sjungma@eit.uni-kl.de                    obj = obj.child_names[node]
66212027Sjungma@eit.uni-kl.de                else:
66312027Sjungma@eit.uni-kl.de                    obj = obj.top_child_names[node]
66412027Sjungma@eit.uni-kl.de                obj = Proxy.getindex(obj, index)
66512027Sjungma@eit.uni-kl.de
66612027Sjungma@eit.uni-kl.de            (last,index) = path[-1]
66712027Sjungma@eit.uni-kl.de            if obj.child_names.has_key(last):
66812027Sjungma@eit.uni-kl.de                value = obj.child_names[last]
66912027Sjungma@eit.uni-kl.de                return Proxy.getindex(value, index), True
67012027Sjungma@eit.uni-kl.de            elif obj.top_child_names.has_key(last):
67112027Sjungma@eit.uni-kl.de                value = obj.top_child_names[last]
67212027Sjungma@eit.uni-kl.de                return Proxy.getindex(value, index), True
67312027Sjungma@eit.uni-kl.de            elif obj.param_names.has_key(last):
67412027Sjungma@eit.uni-kl.de                value = obj.param_names[last]
67512027Sjungma@eit.uni-kl.de                realtype._convert(value.value)
67612027Sjungma@eit.uni-kl.de                return Proxy.getindex(value.value, index), True
67712027Sjungma@eit.uni-kl.de        except KeyError:
67812027Sjungma@eit.uni-kl.de            pass
67912027Sjungma@eit.uni-kl.de
68012027Sjungma@eit.uni-kl.de        return None, False
68112027Sjungma@eit.uni-kl.de
68212027Sjungma@eit.uni-kl.de    def unproxy(self, param, ptype):
68312027Sjungma@eit.uni-kl.de        if not isinstance(param, Proxy):
68412027Sjungma@eit.uni-kl.de            return param
68512027Sjungma@eit.uni-kl.de        return param.unproxy(self, ptype)
68612027Sjungma@eit.uni-kl.de
68712027Sjungma@eit.uni-kl.de    def fixup(self):
68812027Sjungma@eit.uni-kl.de        self.all[self.path] = self
68912027Sjungma@eit.uni-kl.de
69012027Sjungma@eit.uni-kl.de        for param in self.params:
69112027Sjungma@eit.uni-kl.de            ptype = param.ptype
69212027Sjungma@eit.uni-kl.de            pval = param.value
69312027Sjungma@eit.uni-kl.de
69412027Sjungma@eit.uni-kl.de            try:
69512027Sjungma@eit.uni-kl.de                if isinstance(pval, (list, tuple)):
69612027Sjungma@eit.uni-kl.de                    param.value = [ self.unproxy(pv, ptype) for pv in pval ]
69712027Sjungma@eit.uni-kl.de                else:
69812027Sjungma@eit.uni-kl.de                    param.value = self.unproxy(pval, ptype)
69912027Sjungma@eit.uni-kl.de            except Exception, e:
70012027Sjungma@eit.uni-kl.de                msg = 'Error while fixing up %s:%s\n%s' % \
70112027Sjungma@eit.uni-kl.de                      (self.path, param.name, e)
70212027Sjungma@eit.uni-kl.de                e.args = (msg, )
70312027Sjungma@eit.uni-kl.de                raise
70412027Sjungma@eit.uni-kl.de
70512027Sjungma@eit.uni-kl.de        for child in self.children:
70612027Sjungma@eit.uni-kl.de            assert(child != self)
70712027Sjungma@eit.uni-kl.de            child.fixup()
70812027Sjungma@eit.uni-kl.de
70912027Sjungma@eit.uni-kl.de    # print type and parameter values to .ini file
71012027Sjungma@eit.uni-kl.de    def display(self):
71112027Sjungma@eit.uni-kl.de        print '[' + self.path + ']'	# .ini section header
71212027Sjungma@eit.uni-kl.de
71312027Sjungma@eit.uni-kl.de        if isSimObject(self.realtype):
71412027Sjungma@eit.uni-kl.de            print 'type = %s' % self.type
71512027Sjungma@eit.uni-kl.de
71612027Sjungma@eit.uni-kl.de        if self.children:
71712027Sjungma@eit.uni-kl.de            # instantiate children in same order they were added for
71812027Sjungma@eit.uni-kl.de            # backward compatibility (else we can end up with cpu1
71912027Sjungma@eit.uni-kl.de            # before cpu0).  Changing ordering can also influence timing
72012027Sjungma@eit.uni-kl.de            # in the current memory system, as caches get added to a bus
72112027Sjungma@eit.uni-kl.de            # in different orders which affects their priority in the
72212027Sjungma@eit.uni-kl.de            # case of simulataneous requests.
72312027Sjungma@eit.uni-kl.de            self.children.sort(lambda x,y: cmp(x.name, y.name))
72412027Sjungma@eit.uni-kl.de            children = [ c.name for c in self.children if not c.paramcontext]
72512027Sjungma@eit.uni-kl.de            print 'children =', ' '.join(children)
72612027Sjungma@eit.uni-kl.de
72712027Sjungma@eit.uni-kl.de        self.params.sort(lambda x,y: cmp(x.name, y.name))
72812027Sjungma@eit.uni-kl.de        for param in self.params:
72912027Sjungma@eit.uni-kl.de            try:
73012027Sjungma@eit.uni-kl.de                if param.value is None:
73112027Sjungma@eit.uni-kl.de                    raise AttributeError, 'Parameter with no value'
73212027Sjungma@eit.uni-kl.de
73312027Sjungma@eit.uni-kl.de                value = param.convert(param.value)
73412027Sjungma@eit.uni-kl.de                string = param.string(value)
73512027Sjungma@eit.uni-kl.de            except Exception, e:
73612027Sjungma@eit.uni-kl.de                msg = 'exception in %s:%s\n%s' % (self.path, param.name, e)
73712027Sjungma@eit.uni-kl.de                e.args = (msg, )
73812027Sjungma@eit.uni-kl.de                raise
73912027Sjungma@eit.uni-kl.de
74012027Sjungma@eit.uni-kl.de            print '%s = %s' % (param.name, string)
74112027Sjungma@eit.uni-kl.de
74212027Sjungma@eit.uni-kl.de        print
74312027Sjungma@eit.uni-kl.de
74412027Sjungma@eit.uni-kl.de        # recursively dump out children
74512027Sjungma@eit.uni-kl.de        for c in self.children:
74612027Sjungma@eit.uni-kl.de            c.display()
74712027Sjungma@eit.uni-kl.de
74812027Sjungma@eit.uni-kl.de    # print type and parameter values to .ini file
74912027Sjungma@eit.uni-kl.de    def outputDot(self, dot):
75012027Sjungma@eit.uni-kl.de        label = "{%s|" % self.path
75112027Sjungma@eit.uni-kl.de        if isSimObject(self.realtype):
75212027Sjungma@eit.uni-kl.de            label +=  '%s|' % self.type
75312027Sjungma@eit.uni-kl.de
75412027Sjungma@eit.uni-kl.de        if self.children:
75512027Sjungma@eit.uni-kl.de            # instantiate children in same order they were added for
75612027Sjungma@eit.uni-kl.de            # backward compatibility (else we can end up with cpu1
75712027Sjungma@eit.uni-kl.de            # before cpu0).
75812027Sjungma@eit.uni-kl.de            for c in self.children:
75912027Sjungma@eit.uni-kl.de                dot.add_edge(pydot.Edge(self.path,c.path, style="bold"))
76012027Sjungma@eit.uni-kl.de
76112027Sjungma@eit.uni-kl.de        simobjs = []
76212027Sjungma@eit.uni-kl.de        for param in self.params:
76312027Sjungma@eit.uni-kl.de            try:
76412027Sjungma@eit.uni-kl.de                if param.value is None:
76512027Sjungma@eit.uni-kl.de                    raise AttributeError, 'Parameter with no value'
76612027Sjungma@eit.uni-kl.de
76712027Sjungma@eit.uni-kl.de                value = param.convert(param.value)
76812027Sjungma@eit.uni-kl.de                string = param.string(value)
76912027Sjungma@eit.uni-kl.de            except Exception, e:
77012027Sjungma@eit.uni-kl.de                msg = 'exception in %s:%s\n%s' % (self.name, param.name, e)
77112027Sjungma@eit.uni-kl.de                e.args = (msg, )
77212027Sjungma@eit.uni-kl.de                raise
77312027Sjungma@eit.uni-kl.de
77412027Sjungma@eit.uni-kl.de            if isConfigNode(param.ptype) and string != "Null":
77512027Sjungma@eit.uni-kl.de                simobjs.append(string)
77612027Sjungma@eit.uni-kl.de            else:
77712027Sjungma@eit.uni-kl.de                label += '%s = %s\\n' % (param.name, string)
77812027Sjungma@eit.uni-kl.de
77912027Sjungma@eit.uni-kl.de        for so in simobjs:
78012027Sjungma@eit.uni-kl.de            label += "|<%s> %s" % (so, so)
78112027Sjungma@eit.uni-kl.de            dot.add_edge(pydot.Edge("%s:%s" % (self.path, so), so,
78212027Sjungma@eit.uni-kl.de                                    tailport="w"))
78312027Sjungma@eit.uni-kl.de        label += '}'
78412027Sjungma@eit.uni-kl.de        dot.add_node(pydot.Node(self.path,shape="Mrecord",label=label))
78512027Sjungma@eit.uni-kl.de
78612027Sjungma@eit.uni-kl.de        # recursively dump out children
78712027Sjungma@eit.uni-kl.de        for c in self.children:
78812027Sjungma@eit.uni-kl.de            c.outputDot(dot)
78912027Sjungma@eit.uni-kl.de
79012027Sjungma@eit.uni-kl.de    def _string(cls, value):
79112027Sjungma@eit.uni-kl.de        if not isinstance(value, Node):
79212027Sjungma@eit.uni-kl.de            raise AttributeError, 'expecting %s got %s' % (Node, value)
79312027Sjungma@eit.uni-kl.de        return value.path
79412027Sjungma@eit.uni-kl.de    _string = classmethod(_string)
79512027Sjungma@eit.uni-kl.de
79612027Sjungma@eit.uni-kl.de#####################################################################
79712027Sjungma@eit.uni-kl.de#
79812027Sjungma@eit.uni-kl.de# Parameter description classes
79912027Sjungma@eit.uni-kl.de#
80012027Sjungma@eit.uni-kl.de# The _params dictionary in each class maps parameter names to
80112027Sjungma@eit.uni-kl.de# either a Param or a VectorParam object.  These objects contain the
80212027Sjungma@eit.uni-kl.de# parameter description string, the parameter type, and the default
80312027Sjungma@eit.uni-kl.de# value (loaded from the PARAM section of the .odesc files).  The
80412027Sjungma@eit.uni-kl.de# _convert() method on these objects is used to force whatever value
80512027Sjungma@eit.uni-kl.de# is assigned to the parameter to the appropriate type.
80612027Sjungma@eit.uni-kl.de#
80712027Sjungma@eit.uni-kl.de# Note that the default values are loaded into the class's attribute
80812027Sjungma@eit.uni-kl.de# space when the parameter dictionary is initialized (in
80912027Sjungma@eit.uni-kl.de# MetaConfigNode._setparams()); after that point they aren't used.
81012027Sjungma@eit.uni-kl.de#
81112027Sjungma@eit.uni-kl.de#####################################################################
81212027Sjungma@eit.uni-kl.de
81312027Sjungma@eit.uni-kl.dedef isNullPointer(value):
81412027Sjungma@eit.uni-kl.de    return isinstance(value, NullSimObject)
81512027Sjungma@eit.uni-kl.de
81612027Sjungma@eit.uni-kl.declass Value(object):
81712027Sjungma@eit.uni-kl.de    def __init__(self, obj, attr):
81812027Sjungma@eit.uni-kl.de        super(Value, self).__setattr__('attr', attr)
81912027Sjungma@eit.uni-kl.de        super(Value, self).__setattr__('obj', obj)
82012027Sjungma@eit.uni-kl.de
82112027Sjungma@eit.uni-kl.de    def _getattr(self):
82212027Sjungma@eit.uni-kl.de        return self.obj._values.get(self.attr)
82312027Sjungma@eit.uni-kl.de
82412027Sjungma@eit.uni-kl.de    def __setattr__(self, attr, value):
82512027Sjungma@eit.uni-kl.de        setattr(self._getattr(), attr, value)
82612027Sjungma@eit.uni-kl.de
82712027Sjungma@eit.uni-kl.de    def __getattr__(self, attr):
82812027Sjungma@eit.uni-kl.de        return getattr(self._getattr(), attr)
82912027Sjungma@eit.uni-kl.de
83012027Sjungma@eit.uni-kl.de    def __getitem__(self, index):
83112027Sjungma@eit.uni-kl.de        return self._getattr().__getitem__(index)
83212027Sjungma@eit.uni-kl.de
83312027Sjungma@eit.uni-kl.de    def __call__(self, *args, **kwargs):
83412027Sjungma@eit.uni-kl.de        return self._getattr().__call__(*args, **kwargs)
83512027Sjungma@eit.uni-kl.de
83612027Sjungma@eit.uni-kl.de    def __nonzero__(self):
83712027Sjungma@eit.uni-kl.de        return bool(self._getattr())
83812027Sjungma@eit.uni-kl.de
83912027Sjungma@eit.uni-kl.de    def __str__(self):
84012027Sjungma@eit.uni-kl.de        return str(self._getattr())
84112027Sjungma@eit.uni-kl.de
84212027Sjungma@eit.uni-kl.de    def __len__(self):
84312027Sjungma@eit.uni-kl.de        return len(self._getattr())
84412027Sjungma@eit.uni-kl.de
84512027Sjungma@eit.uni-kl.de# Regular parameter.
84612027Sjungma@eit.uni-kl.declass ParamBase(object):
84712027Sjungma@eit.uni-kl.de    def __init__(self, ptype, *args, **kwargs):
84812027Sjungma@eit.uni-kl.de        if isinstance(ptype, types.StringType):
84912027Sjungma@eit.uni-kl.de            self.ptype_string = ptype
85012027Sjungma@eit.uni-kl.de        elif isinstance(ptype, type):
85112027Sjungma@eit.uni-kl.de            self.ptype = ptype
85212027Sjungma@eit.uni-kl.de        else:
85312027Sjungma@eit.uni-kl.de            raise TypeError, "Param type is not a type (%s)" % ptype
85412027Sjungma@eit.uni-kl.de
85512027Sjungma@eit.uni-kl.de        if args:
85612027Sjungma@eit.uni-kl.de            if len(args) == 1:
85712027Sjungma@eit.uni-kl.de                self.desc = args[0]
85812027Sjungma@eit.uni-kl.de            elif len(args) == 2:
85912027Sjungma@eit.uni-kl.de                self.default = args[0]
86012027Sjungma@eit.uni-kl.de                self.desc = args[1]
86112027Sjungma@eit.uni-kl.de            else:
86212027Sjungma@eit.uni-kl.de                raise TypeError, 'too many arguments'
86312027Sjungma@eit.uni-kl.de
86412027Sjungma@eit.uni-kl.de        if kwargs.has_key('desc'):
86512027Sjungma@eit.uni-kl.de            assert(not hasattr(self, 'desc'))
86612027Sjungma@eit.uni-kl.de            self.desc = kwargs['desc']
86712027Sjungma@eit.uni-kl.de            del kwargs['desc']
86812027Sjungma@eit.uni-kl.de
86912027Sjungma@eit.uni-kl.de        if kwargs.has_key('default'):
87012027Sjungma@eit.uni-kl.de            assert(not hasattr(self, 'default'))
87112027Sjungma@eit.uni-kl.de            self.default = kwargs['default']
87212027Sjungma@eit.uni-kl.de            del kwargs['default']
87312027Sjungma@eit.uni-kl.de
87412027Sjungma@eit.uni-kl.de        if kwargs:
87512027Sjungma@eit.uni-kl.de            raise TypeError, 'extra unknown kwargs %s' % kwargs
87612027Sjungma@eit.uni-kl.de
87712027Sjungma@eit.uni-kl.de        if not hasattr(self, 'desc'):
87812027Sjungma@eit.uni-kl.de            raise TypeError, 'desc attribute missing'
87912027Sjungma@eit.uni-kl.de
88012027Sjungma@eit.uni-kl.de    def maybe_resolve_type(self, context):
88112027Sjungma@eit.uni-kl.de        # check if already resolved... don't use hasattr(),
88212027Sjungma@eit.uni-kl.de        # as that calls __getattr__()
88312027Sjungma@eit.uni-kl.de        if self.__dict__.has_key('ptype'):
88412027Sjungma@eit.uni-kl.de            return
88512027Sjungma@eit.uni-kl.de        try:
88612027Sjungma@eit.uni-kl.de            self.ptype = context[self.ptype_string]
88712027Sjungma@eit.uni-kl.de        except KeyError:
88812027Sjungma@eit.uni-kl.de            # no harm in trying... we'll try again later using global scope
88912027Sjungma@eit.uni-kl.de            pass
89012027Sjungma@eit.uni-kl.de
89112027Sjungma@eit.uni-kl.de    def __getattr__(self, attr):
89212027Sjungma@eit.uni-kl.de        if attr == 'ptype':
89312027Sjungma@eit.uni-kl.de            try:
89412027Sjungma@eit.uni-kl.de                self.ptype = param_types[self.ptype_string]
89512027Sjungma@eit.uni-kl.de                return self.ptype
89612027Sjungma@eit.uni-kl.de            except:
89712027Sjungma@eit.uni-kl.de                panic("undefined Param type %s" % self.ptype_string)
89812027Sjungma@eit.uni-kl.de        else:
89912027Sjungma@eit.uni-kl.de            raise AttributeError, "'%s' object has no attribute '%s'" % \
90012027Sjungma@eit.uni-kl.de                  (type(self).__name__, attr)
90112027Sjungma@eit.uni-kl.de
90212027Sjungma@eit.uni-kl.de    def valid(self, value):
90312027Sjungma@eit.uni-kl.de        if not isinstance(value, Proxy):
90412027Sjungma@eit.uni-kl.de            self.ptype._convert(value)
90512027Sjungma@eit.uni-kl.de
90612027Sjungma@eit.uni-kl.de    def convert(self, value):
90712027Sjungma@eit.uni-kl.de        return self.ptype._convert(value)
90812027Sjungma@eit.uni-kl.de
90912027Sjungma@eit.uni-kl.de    def string(self, value):
91012027Sjungma@eit.uni-kl.de        return self.ptype._string(value)
91112027Sjungma@eit.uni-kl.de
91212027Sjungma@eit.uni-kl.de    def set(self, name, instance, value):
91312027Sjungma@eit.uni-kl.de        instance.__dict__[name] = value
91412027Sjungma@eit.uni-kl.de
91512027Sjungma@eit.uni-kl.de    def cpp_decl(self, name):
91612027Sjungma@eit.uni-kl.de        return '%s %s;' % (self.ptype._cpp_param_decl, name)
91712027Sjungma@eit.uni-kl.de
91812027Sjungma@eit.uni-kl.declass ParamFactory(object):
91912027Sjungma@eit.uni-kl.de    def __init__(self, type):
92012027Sjungma@eit.uni-kl.de        self.ptype = type
92112027Sjungma@eit.uni-kl.de
92212027Sjungma@eit.uni-kl.de    # E.g., Param.Int(5, "number of widgets")
92312027Sjungma@eit.uni-kl.de    def __call__(self, *args, **kwargs):
92412027Sjungma@eit.uni-kl.de        return ParamBase(self.ptype, *args, **kwargs)
92512027Sjungma@eit.uni-kl.de
92612027Sjungma@eit.uni-kl.de    # Strange magic to theoretically allow dotted names as Param classes,
92712027Sjungma@eit.uni-kl.de    # e.g., Param.Foo.Bar(...) to have a param of type Foo.Bar
92812027Sjungma@eit.uni-kl.de    def __getattr__(self, attr):
92912027Sjungma@eit.uni-kl.de        if attr == '__bases__':
93012027Sjungma@eit.uni-kl.de            raise AttributeError, ''
93112027Sjungma@eit.uni-kl.de        cls = type(self)
93212027Sjungma@eit.uni-kl.de        return cls(attr)
93312027Sjungma@eit.uni-kl.de
93412027Sjungma@eit.uni-kl.de    def __setattr__(self, attr, value):
93512027Sjungma@eit.uni-kl.de        if attr != 'ptype':
93612027Sjungma@eit.uni-kl.de            raise AttributeError, \
93712027Sjungma@eit.uni-kl.de                  'Attribute %s not available in %s' % (attr, self.__class__)
93812027Sjungma@eit.uni-kl.de        super(ParamFactory, self).__setattr__(attr, value)
93912027Sjungma@eit.uni-kl.de
94012027Sjungma@eit.uni-kl.deParam = ParamFactory(None)
94112027Sjungma@eit.uni-kl.de
94212027Sjungma@eit.uni-kl.de# Vector-valued parameter description.  Just like Param, except that
94312027Sjungma@eit.uni-kl.de# the value is a vector (list) of the specified type instead of a
94412027Sjungma@eit.uni-kl.de# single value.
94512027Sjungma@eit.uni-kl.declass VectorParamBase(ParamBase):
94612027Sjungma@eit.uni-kl.de    def __init__(self, type, *args, **kwargs):
94712027Sjungma@eit.uni-kl.de        ParamBase.__init__(self, type, *args, **kwargs)
94812027Sjungma@eit.uni-kl.de
94912027Sjungma@eit.uni-kl.de    def valid(self, value):
95012027Sjungma@eit.uni-kl.de        if value == None:
95112027Sjungma@eit.uni-kl.de            return True
95212027Sjungma@eit.uni-kl.de
95312027Sjungma@eit.uni-kl.de        if isinstance(value, (list, tuple)):
95412027Sjungma@eit.uni-kl.de            for val in value:
95512027Sjungma@eit.uni-kl.de                if not isinstance(val, Proxy):
95612027Sjungma@eit.uni-kl.de                    self.ptype._convert(val)
95712027Sjungma@eit.uni-kl.de        elif not isinstance(value, Proxy):
95812027Sjungma@eit.uni-kl.de            self.ptype._convert(value)
95912027Sjungma@eit.uni-kl.de
96012027Sjungma@eit.uni-kl.de    # Convert assigned value to appropriate type.  If the RHS is not a
96112027Sjungma@eit.uni-kl.de    # list or tuple, it generates a single-element list.
96212027Sjungma@eit.uni-kl.de    def convert(self, value):
96312027Sjungma@eit.uni-kl.de        if value == None:
96412027Sjungma@eit.uni-kl.de            return []
96512027Sjungma@eit.uni-kl.de
96612027Sjungma@eit.uni-kl.de        if isinstance(value, (list, tuple)):
96712027Sjungma@eit.uni-kl.de            # list: coerce each element into new list
96812027Sjungma@eit.uni-kl.de            return [ self.ptype._convert(v) for v in value ]
96912027Sjungma@eit.uni-kl.de        else:
97012027Sjungma@eit.uni-kl.de            # singleton: coerce & wrap in a list
97112027Sjungma@eit.uni-kl.de            return self.ptype._convert(value)
97212027Sjungma@eit.uni-kl.de
97312027Sjungma@eit.uni-kl.de    def string(self, value):
97412027Sjungma@eit.uni-kl.de        if isinstance(value, (list, tuple)):
97512027Sjungma@eit.uni-kl.de            return ' '.join([ self.ptype._string(v) for v in value])
97612027Sjungma@eit.uni-kl.de        else:
97712027Sjungma@eit.uni-kl.de            return self.ptype._string(value)
97812027Sjungma@eit.uni-kl.de
97912027Sjungma@eit.uni-kl.de    def cpp_decl(self, name):
98012027Sjungma@eit.uni-kl.de        return 'std::vector<%s> %s;' % (self.ptype._cpp_param_decl, name)
98112027Sjungma@eit.uni-kl.de
98212027Sjungma@eit.uni-kl.declass VectorParamFactory(ParamFactory):
98312027Sjungma@eit.uni-kl.de    # E.g., VectorParam.Int(5, "number of widgets")
98412027Sjungma@eit.uni-kl.de    def __call__(self, *args, **kwargs):
98512027Sjungma@eit.uni-kl.de        return VectorParamBase(self.ptype, *args, **kwargs)
98612027Sjungma@eit.uni-kl.de
98712027Sjungma@eit.uni-kl.deVectorParam = VectorParamFactory(None)
98812027Sjungma@eit.uni-kl.de
98912027Sjungma@eit.uni-kl.de#####################################################################
99012027Sjungma@eit.uni-kl.de#
99112027Sjungma@eit.uni-kl.de# Parameter Types
99212027Sjungma@eit.uni-kl.de#
99312027Sjungma@eit.uni-kl.de# Though native Python types could be used to specify parameter types
99412027Sjungma@eit.uni-kl.de# (the 'ptype' field of the Param and VectorParam classes), it's more
99512027Sjungma@eit.uni-kl.de# flexible to define our own set of types.  This gives us more control
99612027Sjungma@eit.uni-kl.de# over how Python expressions are converted to values (via the
99712027Sjungma@eit.uni-kl.de# __init__() constructor) and how these values are printed out (via
99812027Sjungma@eit.uni-kl.de# the __str__() conversion method).  Eventually we'll need these types
99912027Sjungma@eit.uni-kl.de# to correspond to distinct C++ types as well.
100012027Sjungma@eit.uni-kl.de#
100112027Sjungma@eit.uni-kl.de#####################################################################
100212027Sjungma@eit.uni-kl.de
100312027Sjungma@eit.uni-kl.declass MetaRange(type):
100412027Sjungma@eit.uni-kl.de    def __init__(cls, name, bases, dict):
100512027Sjungma@eit.uni-kl.de        super(MetaRange, cls).__init__(name, bases, dict)
100612027Sjungma@eit.uni-kl.de        if name == 'Range':
100712027Sjungma@eit.uni-kl.de            return
100812027Sjungma@eit.uni-kl.de        cls._cpp_param_decl = 'Range<%s>' % cls.type._cpp_param_decl
100912027Sjungma@eit.uni-kl.de
101012027Sjungma@eit.uni-kl.de    def _convert(cls, value):
101112027Sjungma@eit.uni-kl.de        if not isinstance(value, Range):
101212027Sjungma@eit.uni-kl.de            raise TypeError, 'value %s is not a Pair' % value
101312027Sjungma@eit.uni-kl.de        value = cls(value)
101412027Sjungma@eit.uni-kl.de        value.first = cls.type._convert(value.first)
101512027Sjungma@eit.uni-kl.de        value.second = cls.type._convert(value.second)
101612027Sjungma@eit.uni-kl.de        return value
101712027Sjungma@eit.uni-kl.de
101812027Sjungma@eit.uni-kl.de    def _string(cls, value):
101912027Sjungma@eit.uni-kl.de        first = int(value.first)
102012027Sjungma@eit.uni-kl.de        second = int(value.second)
102112027Sjungma@eit.uni-kl.de        if value.extend:
102212027Sjungma@eit.uni-kl.de            second += first
102312027Sjungma@eit.uni-kl.de        if not value.inclusive:
102412027Sjungma@eit.uni-kl.de            second -= 1
102512027Sjungma@eit.uni-kl.de        return '%s:%s' % (cls.type._string(first), cls.type._string(second))
102612027Sjungma@eit.uni-kl.de
102712027Sjungma@eit.uni-kl.declass Range(ParamType):
102812027Sjungma@eit.uni-kl.de    __metaclass__ = MetaRange
102912027Sjungma@eit.uni-kl.de    def __init__(self, *args, **kwargs):
103012027Sjungma@eit.uni-kl.de        if len(args) == 0:
103112027Sjungma@eit.uni-kl.de            self.first = kwargs.pop('start')
103212027Sjungma@eit.uni-kl.de
103312027Sjungma@eit.uni-kl.de            if 'end' in kwargs:
103412027Sjungma@eit.uni-kl.de                self.second = kwargs.pop('end')
103512027Sjungma@eit.uni-kl.de                self.inclusive = True
103612027Sjungma@eit.uni-kl.de                self.extend = False
103712027Sjungma@eit.uni-kl.de            elif 'size' in kwargs:
103812027Sjungma@eit.uni-kl.de                self.second = kwargs.pop('size')
103912027Sjungma@eit.uni-kl.de                self.inclusive = False
104012027Sjungma@eit.uni-kl.de                self.extend = True
104112027Sjungma@eit.uni-kl.de            else:
104212027Sjungma@eit.uni-kl.de                raise TypeError, "Either end or size must be specified"
104312027Sjungma@eit.uni-kl.de
104412027Sjungma@eit.uni-kl.de        elif len(args) == 1:
104512027Sjungma@eit.uni-kl.de            if kwargs:
104612027Sjungma@eit.uni-kl.de                self.first = args[0]
104712027Sjungma@eit.uni-kl.de                if 'end' in kwargs:
104812027Sjungma@eit.uni-kl.de                    self.second = kwargs.pop('end')
104912027Sjungma@eit.uni-kl.de                    self.inclusive = True
105012027Sjungma@eit.uni-kl.de                    self.extend = False
105112027Sjungma@eit.uni-kl.de                elif 'size' in kwargs:
105212027Sjungma@eit.uni-kl.de                    self.second = kwargs.pop('size')
105312027Sjungma@eit.uni-kl.de                    self.inclusive = False
105412027Sjungma@eit.uni-kl.de                    self.extend = True
105512027Sjungma@eit.uni-kl.de                else:
105612027Sjungma@eit.uni-kl.de                    raise TypeError, "Either end or size must be specified"
105712027Sjungma@eit.uni-kl.de            elif isinstance(args[0], Range):
105812027Sjungma@eit.uni-kl.de                self.first = args[0].first
105912027Sjungma@eit.uni-kl.de                self.second = args[0].second
106012027Sjungma@eit.uni-kl.de                self.inclusive = args[0].inclusive
106112027Sjungma@eit.uni-kl.de                self.extend = args[0].extend
106212027Sjungma@eit.uni-kl.de            else:
106312027Sjungma@eit.uni-kl.de                self.first = 0
106412027Sjungma@eit.uni-kl.de                self.second = args[0]
106512027Sjungma@eit.uni-kl.de                self.inclusive = False
106612027Sjungma@eit.uni-kl.de                self.extend = True
106712027Sjungma@eit.uni-kl.de
106812027Sjungma@eit.uni-kl.de        elif len(args) == 2:
106912027Sjungma@eit.uni-kl.de            self.first, self.second = args
107012027Sjungma@eit.uni-kl.de            self.inclusive = True
107112027Sjungma@eit.uni-kl.de            self.extend = False
107212027Sjungma@eit.uni-kl.de        else:
107312027Sjungma@eit.uni-kl.de            raise TypeError, "Too many arguments specified"
107412027Sjungma@eit.uni-kl.de
107512027Sjungma@eit.uni-kl.de        if kwargs:
107612027Sjungma@eit.uni-kl.de            raise TypeError, "too many keywords: %s" % kwargs.keys()
107712027Sjungma@eit.uni-kl.de
107812027Sjungma@eit.uni-kl.de# Metaclass for bounds-checked integer parameters.  See CheckedInt.
107912027Sjungma@eit.uni-kl.declass CheckedIntType(type):
108012027Sjungma@eit.uni-kl.de    def __init__(cls, name, bases, dict):
108112027Sjungma@eit.uni-kl.de        super(CheckedIntType, cls).__init__(name, bases, dict)
108212027Sjungma@eit.uni-kl.de
108312027Sjungma@eit.uni-kl.de        # CheckedInt is an abstract base class, so we actually don't
108412027Sjungma@eit.uni-kl.de        # want to do any processing on it... the rest of this code is
108512027Sjungma@eit.uni-kl.de        # just for classes that derive from CheckedInt.
108612027Sjungma@eit.uni-kl.de        if name == 'CheckedInt':
108712027Sjungma@eit.uni-kl.de            return
108812027Sjungma@eit.uni-kl.de
108912027Sjungma@eit.uni-kl.de        if not (hasattr(cls, 'min') and hasattr(cls, 'max')):
109012027Sjungma@eit.uni-kl.de            if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')):
109112027Sjungma@eit.uni-kl.de                panic("CheckedInt subclass %s must define either\n" \
109212027Sjungma@eit.uni-kl.de                      "    'min' and 'max' or 'size' and 'unsigned'\n" \
109312027Sjungma@eit.uni-kl.de                      % name);
109412027Sjungma@eit.uni-kl.de            if cls.unsigned:
109512027Sjungma@eit.uni-kl.de                cls.min = 0
109612027Sjungma@eit.uni-kl.de                cls.max = 2 ** cls.size - 1
109712027Sjungma@eit.uni-kl.de            else:
109812027Sjungma@eit.uni-kl.de                cls.min = -(2 ** (cls.size - 1))
109912027Sjungma@eit.uni-kl.de                cls.max = (2 ** (cls.size - 1)) - 1
110012027Sjungma@eit.uni-kl.de
110112027Sjungma@eit.uni-kl.de        cls._cpp_param_decl = cls.cppname
110212027Sjungma@eit.uni-kl.de
110312027Sjungma@eit.uni-kl.de    def _convert(cls, value):
110412027Sjungma@eit.uni-kl.de        if isinstance(value, bool):
110512027Sjungma@eit.uni-kl.de            return int(value)
110612027Sjungma@eit.uni-kl.de
110712027Sjungma@eit.uni-kl.de        if not isinstance(value, (int, long, float, str)):
110812027Sjungma@eit.uni-kl.de            raise TypeError, 'Integer param of invalid type %s' % type(value)
110912027Sjungma@eit.uni-kl.de
111012027Sjungma@eit.uni-kl.de        if isinstance(value, float):
111112027Sjungma@eit.uni-kl.de            value = long(value)
111212027Sjungma@eit.uni-kl.de        elif isinstance(value, str):
111312027Sjungma@eit.uni-kl.de            value = toInteger(value)
111412027Sjungma@eit.uni-kl.de
111512027Sjungma@eit.uni-kl.de        if not cls.min <= value <= cls.max:
111612027Sjungma@eit.uni-kl.de            raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
111712027Sjungma@eit.uni-kl.de                  (cls.min, value, cls.max)
111812027Sjungma@eit.uni-kl.de
111912027Sjungma@eit.uni-kl.de        return value
112012027Sjungma@eit.uni-kl.de
112112027Sjungma@eit.uni-kl.de    def _string(cls, value):
112212027Sjungma@eit.uni-kl.de        return str(value)
112312027Sjungma@eit.uni-kl.de
112412027Sjungma@eit.uni-kl.de# Abstract superclass for bounds-checked integer parameters.  This
112512027Sjungma@eit.uni-kl.de# class is subclassed to generate parameter classes with specific
112612027Sjungma@eit.uni-kl.de# bounds.  Initialization of the min and max bounds is done in the
112712027Sjungma@eit.uni-kl.de# metaclass CheckedIntType.__init__.
112812027Sjungma@eit.uni-kl.declass CheckedInt(long,ParamType):
112912027Sjungma@eit.uni-kl.de    __metaclass__ = CheckedIntType
113012027Sjungma@eit.uni-kl.de
113112027Sjungma@eit.uni-kl.declass Int(CheckedInt):      cppname = 'int';      size = 32; unsigned = False
113212027Sjungma@eit.uni-kl.declass Unsigned(CheckedInt): cppname = 'unsigned'; size = 32; unsigned = True
113312027Sjungma@eit.uni-kl.de
113412027Sjungma@eit.uni-kl.declass Int8(CheckedInt):     cppname =  'int8_t';  size =  8; unsigned = False
113512027Sjungma@eit.uni-kl.declass UInt8(CheckedInt):    cppname = 'uint8_t';  size =  8; unsigned = True
113612027Sjungma@eit.uni-kl.declass Int16(CheckedInt):    cppname =  'int16_t'; size = 16; unsigned = False
113712027Sjungma@eit.uni-kl.declass UInt16(CheckedInt):   cppname = 'uint16_t'; size = 16; unsigned = True
113812027Sjungma@eit.uni-kl.declass Int32(CheckedInt):    cppname =  'int32_t'; size = 32; unsigned = False
113912027Sjungma@eit.uni-kl.declass UInt32(CheckedInt):   cppname = 'uint32_t'; size = 32; unsigned = True
114012027Sjungma@eit.uni-kl.declass Int64(CheckedInt):    cppname =  'int64_t'; size = 64; unsigned = False
114112027Sjungma@eit.uni-kl.declass UInt64(CheckedInt):   cppname = 'uint64_t'; size = 64; unsigned = True
114212027Sjungma@eit.uni-kl.de
114312027Sjungma@eit.uni-kl.declass Counter(CheckedInt): cppname = 'Counter'; size = 64; unsigned = True
114412027Sjungma@eit.uni-kl.declass Tick(CheckedInt):    cppname = 'Tick';    size = 64; unsigned = True
114512027Sjungma@eit.uni-kl.de
114612027Sjungma@eit.uni-kl.declass Percent(CheckedInt): cppname = 'int'; min = 0; max = 100
114712027Sjungma@eit.uni-kl.de
114812027Sjungma@eit.uni-kl.declass MemorySize(CheckedInt):
114912027Sjungma@eit.uni-kl.de    cppname = 'uint64_t'
115012027Sjungma@eit.uni-kl.de    size = 64
115112027Sjungma@eit.uni-kl.de    unsigned = True
115212027Sjungma@eit.uni-kl.de    def __new__(cls, value):
115312027Sjungma@eit.uni-kl.de        return super(MemorySize, cls).__new__(cls, toMemorySize(value))
115412027Sjungma@eit.uni-kl.de
115512027Sjungma@eit.uni-kl.de    def _convert(cls, value):
115612027Sjungma@eit.uni-kl.de        return cls(value)
115712027Sjungma@eit.uni-kl.de    _convert = classmethod(_convert)
115812027Sjungma@eit.uni-kl.de
115912027Sjungma@eit.uni-kl.de    def _string(cls, value):
116012027Sjungma@eit.uni-kl.de        return '%d' % value
116112027Sjungma@eit.uni-kl.de    _string = classmethod(_string)
116212027Sjungma@eit.uni-kl.de
116312027Sjungma@eit.uni-kl.declass Addr(MemorySize):
116412027Sjungma@eit.uni-kl.de    pass
116512027Sjungma@eit.uni-kl.de
116612027Sjungma@eit.uni-kl.declass AddrRange(Range):
116712027Sjungma@eit.uni-kl.de    type = Addr
116812027Sjungma@eit.uni-kl.de
116912027Sjungma@eit.uni-kl.de# Boolean parameter type.
117012027Sjungma@eit.uni-kl.declass Bool(ParamType):
117112027Sjungma@eit.uni-kl.de    _cpp_param_decl = 'bool'
117212027Sjungma@eit.uni-kl.de    #def __new__(cls, value):
117312027Sjungma@eit.uni-kl.de    #    return super(MemorySize, cls).__new__(cls, toBool(value))
117412027Sjungma@eit.uni-kl.de
117512027Sjungma@eit.uni-kl.de    def _convert(cls, value):
117612027Sjungma@eit.uni-kl.de        return toBool(value)
117712027Sjungma@eit.uni-kl.de    _convert = classmethod(_convert)
117812027Sjungma@eit.uni-kl.de
117912027Sjungma@eit.uni-kl.de    def _string(cls, value):
118012027Sjungma@eit.uni-kl.de        if value:
118112027Sjungma@eit.uni-kl.de            return "true"
118212027Sjungma@eit.uni-kl.de        else:
118312027Sjungma@eit.uni-kl.de            return "false"
118412027Sjungma@eit.uni-kl.de    _string = classmethod(_string)
118512027Sjungma@eit.uni-kl.de
118612027Sjungma@eit.uni-kl.de# String-valued parameter.
118712027Sjungma@eit.uni-kl.declass String(ParamType):
118812027Sjungma@eit.uni-kl.de    _cpp_param_decl = 'string'
118912027Sjungma@eit.uni-kl.de
119012027Sjungma@eit.uni-kl.de    # Constructor.  Value must be Python string.
119112027Sjungma@eit.uni-kl.de    def _convert(cls,value):
119212027Sjungma@eit.uni-kl.de        if value is None:
119312027Sjungma@eit.uni-kl.de            return ''
119412027Sjungma@eit.uni-kl.de        if isinstance(value, str):
119512027Sjungma@eit.uni-kl.de            return value
119612027Sjungma@eit.uni-kl.de
119712027Sjungma@eit.uni-kl.de        raise TypeError, \
119812027Sjungma@eit.uni-kl.de              "String param got value %s %s" % (repr(value), type(value))
119912027Sjungma@eit.uni-kl.de    _convert = classmethod(_convert)
120012027Sjungma@eit.uni-kl.de
120112027Sjungma@eit.uni-kl.de    # Generate printable string version.  Not too tricky.
120212027Sjungma@eit.uni-kl.de    def _string(cls, value):
120312027Sjungma@eit.uni-kl.de        return value
120412027Sjungma@eit.uni-kl.de    _string = classmethod(_string)
120512027Sjungma@eit.uni-kl.de
120612027Sjungma@eit.uni-kl.dedef IncEthernetAddr(addr, val = 1):
120712027Sjungma@eit.uni-kl.de    bytes = map(lambda x: int(x, 16), addr.split(':'))
120812027Sjungma@eit.uni-kl.de    bytes[5] += val
120912027Sjungma@eit.uni-kl.de    for i in (5, 4, 3, 2, 1):
121012027Sjungma@eit.uni-kl.de        val,rem = divmod(bytes[i], 256)
121112027Sjungma@eit.uni-kl.de        bytes[i] = rem
121212027Sjungma@eit.uni-kl.de        if val == 0:
121312027Sjungma@eit.uni-kl.de            break
121412027Sjungma@eit.uni-kl.de        bytes[i - 1] += val
121512027Sjungma@eit.uni-kl.de    assert(bytes[0] <= 255)
121612027Sjungma@eit.uni-kl.de    return ':'.join(map(lambda x: '%02x' % x, bytes))
121712027Sjungma@eit.uni-kl.de
121812027Sjungma@eit.uni-kl.declass NextEthernetAddr(object):
121912027Sjungma@eit.uni-kl.de    __metaclass__ = Singleton
122012027Sjungma@eit.uni-kl.de    addr = "00:90:00:00:00:01"
122112027Sjungma@eit.uni-kl.de
122212027Sjungma@eit.uni-kl.de    def __init__(self, inc = 1):
122312027Sjungma@eit.uni-kl.de        self.value = self.addr
122412027Sjungma@eit.uni-kl.de        self.addr = IncEthernetAddr(self.addr, inc)
122512027Sjungma@eit.uni-kl.de
122612027Sjungma@eit.uni-kl.declass EthernetAddr(ParamType):
122712027Sjungma@eit.uni-kl.de    _cpp_param_decl = 'EthAddr'
122812027Sjungma@eit.uni-kl.de
122912027Sjungma@eit.uni-kl.de    def _convert(cls, value):
123012027Sjungma@eit.uni-kl.de        if value == NextEthernetAddr:
123112027Sjungma@eit.uni-kl.de            return value
123212027Sjungma@eit.uni-kl.de
123312027Sjungma@eit.uni-kl.de        if not isinstance(value, str):
123412027Sjungma@eit.uni-kl.de            raise TypeError, "expected an ethernet address and didn't get one"
123512027Sjungma@eit.uni-kl.de
123612027Sjungma@eit.uni-kl.de        bytes = value.split(':')
123712027Sjungma@eit.uni-kl.de        if len(bytes) != 6:
123812027Sjungma@eit.uni-kl.de            raise TypeError, 'invalid ethernet address %s' % value
123912027Sjungma@eit.uni-kl.de
124012027Sjungma@eit.uni-kl.de        for byte in bytes:
124112027Sjungma@eit.uni-kl.de            if not 0 <= int(byte) <= 256:
124212027Sjungma@eit.uni-kl.de                raise TypeError, 'invalid ethernet address %s' % value
124312027Sjungma@eit.uni-kl.de
124412027Sjungma@eit.uni-kl.de        return value
124512027Sjungma@eit.uni-kl.de    _convert = classmethod(_convert)
124612027Sjungma@eit.uni-kl.de
124712027Sjungma@eit.uni-kl.de    def _string(cls, value):
124812027Sjungma@eit.uni-kl.de        if value == NextEthernetAddr:
124912027Sjungma@eit.uni-kl.de            value = value().value
125012027Sjungma@eit.uni-kl.de        return value
125112027Sjungma@eit.uni-kl.de    _string = classmethod(_string)
125212027Sjungma@eit.uni-kl.de
125312027Sjungma@eit.uni-kl.de# Special class for NULL pointers.  Note the special check in
125412027Sjungma@eit.uni-kl.de# make_param_value() above that lets these be assigned where a
125512027Sjungma@eit.uni-kl.de# SimObject is required.
125612027Sjungma@eit.uni-kl.de# only one copy of a particular node
125712027Sjungma@eit.uni-kl.declass NullSimObject(object):
125812027Sjungma@eit.uni-kl.de    __metaclass__ = Singleton
125912027Sjungma@eit.uni-kl.de
126012027Sjungma@eit.uni-kl.de    def __call__(cls):
126112027Sjungma@eit.uni-kl.de        return cls
126212027Sjungma@eit.uni-kl.de
126312027Sjungma@eit.uni-kl.de    def _instantiate(self, parent = None, path = ''):
126412027Sjungma@eit.uni-kl.de        pass
126512027Sjungma@eit.uni-kl.de
126612027Sjungma@eit.uni-kl.de    def _convert(cls, value):
126712027Sjungma@eit.uni-kl.de        if value == Nxone:
126812027Sjungma@eit.uni-kl.de            return
126912027Sjungma@eit.uni-kl.de
127012027Sjungma@eit.uni-kl.de        if isinstance(value, cls):
127112027Sjungma@eit.uni-kl.de            return value
127212027Sjungma@eit.uni-kl.de
127312027Sjungma@eit.uni-kl.de        raise TypeError, 'object %s %s of the wrong type, should be %s' % \
127412027Sjungma@eit.uni-kl.de              (repr(value), type(value), cls)
127512027Sjungma@eit.uni-kl.de    _convert = classmethod(_convert)
127612027Sjungma@eit.uni-kl.de
127712027Sjungma@eit.uni-kl.de    def _string():
127812027Sjungma@eit.uni-kl.de        return 'NULL'
127912027Sjungma@eit.uni-kl.de    _string = staticmethod(_string)
128012027Sjungma@eit.uni-kl.de
128112027Sjungma@eit.uni-kl.de# The only instance you'll ever need...
128212027Sjungma@eit.uni-kl.deNull = NULL = NullSimObject()
128312027Sjungma@eit.uni-kl.de
128412027Sjungma@eit.uni-kl.de# Enumerated types are a little more complex.  The user specifies the
128512027Sjungma@eit.uni-kl.de# type as Enum(foo) where foo is either a list or dictionary of
128612027Sjungma@eit.uni-kl.de# alternatives (typically strings, but not necessarily so).  (In the
128712027Sjungma@eit.uni-kl.de# long run, the integer value of the parameter will be the list index
128812027Sjungma@eit.uni-kl.de# or the corresponding dictionary value.  For now, since we only check
128912027Sjungma@eit.uni-kl.de# that the alternative is valid and then spit it into a .ini file,
129012027Sjungma@eit.uni-kl.de# there's not much point in using the dictionary.)
129112027Sjungma@eit.uni-kl.de
129212027Sjungma@eit.uni-kl.de# What Enum() must do is generate a new type encapsulating the
129312027Sjungma@eit.uni-kl.de# provided list/dictionary so that specific values of the parameter
129412027Sjungma@eit.uni-kl.de# can be instances of that type.  We define two hidden internal
129512027Sjungma@eit.uni-kl.de# classes (_ListEnum and _DictEnum) to serve as base classes, then
129612027Sjungma@eit.uni-kl.de# derive the new type from the appropriate base class on the fly.
129712027Sjungma@eit.uni-kl.de
129812027Sjungma@eit.uni-kl.de
129912027Sjungma@eit.uni-kl.de# Metaclass for Enum types
130012027Sjungma@eit.uni-kl.declass MetaEnum(type):
130112027Sjungma@eit.uni-kl.de    def __init__(cls, name, bases, init_dict):
130212027Sjungma@eit.uni-kl.de        if init_dict.has_key('map'):
130312027Sjungma@eit.uni-kl.de            if not isinstance(cls.map, dict):
130412027Sjungma@eit.uni-kl.de                raise TypeError, "Enum-derived class attribute 'map' " \
130512027Sjungma@eit.uni-kl.de                      "must be of type dict"
130612027Sjungma@eit.uni-kl.de            # build list of value strings from map
130712027Sjungma@eit.uni-kl.de            cls.vals = cls.map.keys()
130812027Sjungma@eit.uni-kl.de            cls.vals.sort()
130912027Sjungma@eit.uni-kl.de        elif init_dict.has_key('vals'):
131012027Sjungma@eit.uni-kl.de            if not isinstance(cls.vals, list):
131112027Sjungma@eit.uni-kl.de                raise TypeError, "Enum-derived class attribute 'vals' " \
131212027Sjungma@eit.uni-kl.de                      "must be of type list"
131312027Sjungma@eit.uni-kl.de            # build string->value map from vals sequence
131412027Sjungma@eit.uni-kl.de            cls.map = {}
131512027Sjungma@eit.uni-kl.de            for idx,val in enumerate(cls.vals):
131612027Sjungma@eit.uni-kl.de                cls.map[val] = idx
131712027Sjungma@eit.uni-kl.de        else:
131812027Sjungma@eit.uni-kl.de            raise TypeError, "Enum-derived class must define "\
131912027Sjungma@eit.uni-kl.de                  "attribute 'map' or 'vals'"
132012027Sjungma@eit.uni-kl.de
132112027Sjungma@eit.uni-kl.de        cls._cpp_param_decl = name
132212027Sjungma@eit.uni-kl.de
132312027Sjungma@eit.uni-kl.de        super(MetaEnum, cls).__init__(name, bases, init_dict)
132412027Sjungma@eit.uni-kl.de
132512027Sjungma@eit.uni-kl.de    def cpp_declare(cls):
132612027Sjungma@eit.uni-kl.de        s = 'enum %s {\n    ' % cls.__name__
132712027Sjungma@eit.uni-kl.de        s += ',\n    '.join(['%s = %d' % (v,cls.map[v]) for v in cls.vals])
132812027Sjungma@eit.uni-kl.de        s += '\n};\n'
132912027Sjungma@eit.uni-kl.de        return s
133012027Sjungma@eit.uni-kl.de
133112027Sjungma@eit.uni-kl.de# Base class for enum types.
133212027Sjungma@eit.uni-kl.declass Enum(ParamType):
133312027Sjungma@eit.uni-kl.de    __metaclass__ = MetaEnum
133412027Sjungma@eit.uni-kl.de    vals = []
133512027Sjungma@eit.uni-kl.de
133612027Sjungma@eit.uni-kl.de    def _convert(self, value):
133712027Sjungma@eit.uni-kl.de        if value not in self.map:
133812027Sjungma@eit.uni-kl.de            raise TypeError, "Enum param got bad value '%s' (not in %s)" \
133912027Sjungma@eit.uni-kl.de                  % (value, self.vals)
134012027Sjungma@eit.uni-kl.de        return value
134112027Sjungma@eit.uni-kl.de    _convert = classmethod(_convert)
134212027Sjungma@eit.uni-kl.de
134312027Sjungma@eit.uni-kl.de    # Generate printable string version of value.
134412027Sjungma@eit.uni-kl.de    def _string(self, value):
134512027Sjungma@eit.uni-kl.de        return str(value)
134612027Sjungma@eit.uni-kl.de    _string = classmethod(_string)
134712027Sjungma@eit.uni-kl.de#
134812027Sjungma@eit.uni-kl.de# "Constants"... handy aliases for various values.
134912027Sjungma@eit.uni-kl.de#
135012027Sjungma@eit.uni-kl.de
135112027Sjungma@eit.uni-kl.declass Frequency(int,ParamType):
135212027Sjungma@eit.uni-kl.de    _cpp_param_decl = 'Tick'
135312027Sjungma@eit.uni-kl.de
135412027Sjungma@eit.uni-kl.de    def __new__(cls, value):
135512027Sjungma@eit.uni-kl.de        if isinstance(value, basestring):
135612027Sjungma@eit.uni-kl.de            val = int(env['FREQUENCY'] / toFrequency(value))
135712027Sjungma@eit.uni-kl.de        else:
135812027Sjungma@eit.uni-kl.de            val = toFrequency(value)
135912027Sjungma@eit.uni-kl.de        return super(cls, Frequency).__new__(cls, val)
136012027Sjungma@eit.uni-kl.de
136112027Sjungma@eit.uni-kl.de    def _convert(cls, value):
136212027Sjungma@eit.uni-kl.de        return cls(value)
136312027Sjungma@eit.uni-kl.de    _convert = classmethod(_convert)
136412027Sjungma@eit.uni-kl.de
136512027Sjungma@eit.uni-kl.de    def _string(cls, value):
136612027Sjungma@eit.uni-kl.de        return '%d' % value
136712027Sjungma@eit.uni-kl.de    _string = classmethod(_string)
136812027Sjungma@eit.uni-kl.de
136912027Sjungma@eit.uni-kl.declass Latency(int,ParamType):
137012027Sjungma@eit.uni-kl.de    _cpp_param_decl = 'Tick'
137112027Sjungma@eit.uni-kl.de    def __new__(cls, value):
137212027Sjungma@eit.uni-kl.de        if isinstance(value, basestring):
137312027Sjungma@eit.uni-kl.de            val = int(env['FREQUENCY'] * toLatency(value))
137412027Sjungma@eit.uni-kl.de        else:
137512027Sjungma@eit.uni-kl.de            val = toLatency(value)
137612027Sjungma@eit.uni-kl.de        return super(cls, Latency).__new__(cls, val)
137712027Sjungma@eit.uni-kl.de
137812027Sjungma@eit.uni-kl.de    def _convert(cls, value):
137912027Sjungma@eit.uni-kl.de        return cls(value)
138012027Sjungma@eit.uni-kl.de    _convert = classmethod(_convert)
138112027Sjungma@eit.uni-kl.de
138212027Sjungma@eit.uni-kl.de    def _string(cls, value):
138312027Sjungma@eit.uni-kl.de        return '%d' % value
138412027Sjungma@eit.uni-kl.de    _string = classmethod(_string)
138512027Sjungma@eit.uni-kl.de
138612027Sjungma@eit.uni-kl.de
138712027Sjungma@eit.uni-kl.de# Some memory range specifications use this as a default upper bound.
138812027Sjungma@eit.uni-kl.deMaxAddr = Addr.max
138912027Sjungma@eit.uni-kl.deMaxTick = Tick.max
139012027Sjungma@eit.uni-kl.deAllMemory = AddrRange(0, MaxAddr)
139112027Sjungma@eit.uni-kl.de
139212027Sjungma@eit.uni-kl.de#####################################################################
139312027Sjungma@eit.uni-kl.de
139412027Sjungma@eit.uni-kl.de# The final hook to generate .ini files.  Called from configuration
139512027Sjungma@eit.uni-kl.de# script once config is built.
139612027Sjungma@eit.uni-kl.dedef instantiate(root):
139712027Sjungma@eit.uni-kl.de    instance = root.instantiate('root')
139812027Sjungma@eit.uni-kl.de    instance.fixup()
139912027Sjungma@eit.uni-kl.de    instance.display()
140012027Sjungma@eit.uni-kl.de    if not noDot:
140112027Sjungma@eit.uni-kl.de       dot = pydot.Dot()
140212027Sjungma@eit.uni-kl.de       instance.outputDot(dot)
140312027Sjungma@eit.uni-kl.de       dot.orientation = "portrait"
140412027Sjungma@eit.uni-kl.de       dot.size = "8.5,11"
140512027Sjungma@eit.uni-kl.de       dot.ranksep="equally"
140612027Sjungma@eit.uni-kl.de       dot.rank="samerank"
140712027Sjungma@eit.uni-kl.de       dot.write("config.dot")
140812027Sjungma@eit.uni-kl.de       dot.write_ps("config.ps")
140912027Sjungma@eit.uni-kl.de
141012027Sjungma@eit.uni-kl.de# SimObject is a minimal extension of ConfigNode, implementing a
141112027Sjungma@eit.uni-kl.de# hierarchy node that corresponds to an M5 SimObject.  It prints out a
141212027Sjungma@eit.uni-kl.de# "type=" line to indicate its SimObject class, prints out the
141312027Sjungma@eit.uni-kl.de# assigned parameters corresponding to its class, and allows
141412027Sjungma@eit.uni-kl.de# parameters to be set by keyword in the constructor.  Note that most
141512027Sjungma@eit.uni-kl.de# of the heavy lifting for the SimObject param handling is done in the
141612027Sjungma@eit.uni-kl.de# MetaConfigNode metaclass.
141712027Sjungma@eit.uni-kl.declass SimObject(ConfigNode, ParamType):
141812027Sjungma@eit.uni-kl.de    __metaclass__ = MetaSimObject
141912027Sjungma@eit.uni-kl.de    type = 'SimObject'
142012027Sjungma@eit.uni-kl.de
142112027Sjungma@eit.uni-kl.de
142212027Sjungma@eit.uni-kl.de# __all__ defines the list of symbols that get exported when
142312027Sjungma@eit.uni-kl.de# 'from config import *' is invoked.  Try to keep this reasonably
142412027Sjungma@eit.uni-kl.de# short to avoid polluting other namespaces.
142512027Sjungma@eit.uni-kl.de__all__ = ['ConfigNode', 'SimObject', 'ParamContext', 'Param', 'VectorParam',
142612027Sjungma@eit.uni-kl.de           'parent', 'Enum',
142712027Sjungma@eit.uni-kl.de           'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
142812027Sjungma@eit.uni-kl.de           'Int32', 'UInt32', 'Int64', 'UInt64',
142912027Sjungma@eit.uni-kl.de           'Counter', 'Addr', 'Tick', 'Percent',
143012027Sjungma@eit.uni-kl.de           'MemorySize', 'Frequency', 'Latency',
143112027Sjungma@eit.uni-kl.de           'Range', 'AddrRange', 'MaxAddr', 'MaxTick', 'AllMemory', 'NULL',
143212027Sjungma@eit.uni-kl.de           'NextEthernetAddr', 'instantiate']
143312027Sjungma@eit.uni-kl.de