SimObject.py revision 13698:bc371875a67c
15409Sgblack@eecs.umich.edu# Copyright (c) 2017-2018 ARM Limited
24519Sgblack@eecs.umich.edu# All rights reserved.
34519Sgblack@eecs.umich.edu#
47087Snate@binkert.org# The license below extends only to copyright in the software and shall
57087Snate@binkert.org# not be construed as granting a license to any other intellectual
67087Snate@binkert.org# property including but not limited to intellectual property relating
77087Snate@binkert.org# to a hardware implementation of the functionality of the software
87087Snate@binkert.org# licensed hereunder.  You may use the software subject to the license
97087Snate@binkert.org# terms below provided that you ensure that this notice is replicated
107087Snate@binkert.org# unmodified and in its entirety in all distributions of the software,
117087Snate@binkert.org# modified or unmodified, in source code or in binary form.
124519Sgblack@eecs.umich.edu#
137087Snate@binkert.org# Copyright (c) 2004-2006 The Regents of The University of Michigan
147087Snate@binkert.org# Copyright (c) 2010-20013 Advanced Micro Devices, Inc.
157087Snate@binkert.org# Copyright (c) 2013 Mark D. Hill and David A. Wood
167087Snate@binkert.org# All rights reserved.
177087Snate@binkert.org#
187087Snate@binkert.org# Redistribution and use in source and binary forms, with or without
197087Snate@binkert.org# modification, are permitted provided that the following conditions are
207087Snate@binkert.org# met: redistributions of source code must retain the above copyright
214519Sgblack@eecs.umich.edu# notice, this list of conditions and the following disclaimer;
227087Snate@binkert.org# redistributions in binary form must reproduce the above copyright
234519Sgblack@eecs.umich.edu# notice, this list of conditions and the following disclaimer in the
244519Sgblack@eecs.umich.edu# documentation and/or other materials provided with the distribution;
254519Sgblack@eecs.umich.edu# neither the name of the copyright holders nor the names of its
264519Sgblack@eecs.umich.edu# contributors may be used to endorse or promote products derived from
274519Sgblack@eecs.umich.edu# this software without specific prior written permission.
284519Sgblack@eecs.umich.edu#
294519Sgblack@eecs.umich.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
304519Sgblack@eecs.umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
314519Sgblack@eecs.umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
324519Sgblack@eecs.umich.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
334519Sgblack@eecs.umich.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
344519Sgblack@eecs.umich.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
354519Sgblack@eecs.umich.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
364519Sgblack@eecs.umich.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
374519Sgblack@eecs.umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
384519Sgblack@eecs.umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
394519Sgblack@eecs.umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
404519Sgblack@eecs.umich.edu#
414519Sgblack@eecs.umich.edu# Authors: Steve Reinhardt
424519Sgblack@eecs.umich.edu#          Nathan Binkert
434519Sgblack@eecs.umich.edu#          Andreas Hansson
444519Sgblack@eecs.umich.edu#          Andreas Sandberg
4512234Sgabeblack@google.com
464519Sgblack@eecs.umich.edufrom __future__ import print_function
474519Sgblack@eecs.umich.edu
484519Sgblack@eecs.umich.eduimport sys
494519Sgblack@eecs.umich.edufrom types import FunctionType, MethodType, ModuleType
504809Sgblack@eecs.umich.edufrom functools import wraps
514519Sgblack@eecs.umich.eduimport inspect
524519Sgblack@eecs.umich.edu
534688Sgblack@eecs.umich.eduimport m5
547969Sgblack@eecs.umich.edufrom m5.util import *
557969Sgblack@eecs.umich.edufrom m5.util.pybind import *
564688Sgblack@eecs.umich.edu# Use the pyfdt and not the helper class, because the fdthelper
574688Sgblack@eecs.umich.edu# relies on the SimObject definition
584688Sgblack@eecs.umich.edufrom m5.ext.pyfdt import pyfdt
594688Sgblack@eecs.umich.edu
604688Sgblack@eecs.umich.edu# Have to import params up top since Param is referenced on initial
614708Sgblack@eecs.umich.edu# load (when SimObject class references Param to create a class
624708Sgblack@eecs.umich.edu# variable, the 'name' param)...
634708Sgblack@eecs.umich.edufrom m5.params import *
644708Sgblack@eecs.umich.edu# There are a few things we need that aren't in params.__all__ since
654519Sgblack@eecs.umich.edu# normal users don't need them
664519Sgblack@eecs.umich.edufrom m5.params import ParamDesc, VectorParamDesc, \
674519Sgblack@eecs.umich.edu     isNullPointer, SimObjectVector, Port
684519Sgblack@eecs.umich.edu
694519Sgblack@eecs.umich.edufrom m5.proxy import *
704519Sgblack@eecs.umich.edufrom m5.proxy import isproxy
714519Sgblack@eecs.umich.edu
724519Sgblack@eecs.umich.edu#####################################################################
734519Sgblack@eecs.umich.edu#
744519Sgblack@eecs.umich.edu# M5 Python Configuration Utility
754519Sgblack@eecs.umich.edu#
7612234Sgabeblack@google.com# The basic idea is to write simple Python programs that build Python
774519Sgblack@eecs.umich.edu# objects corresponding to M5 SimObjects for the desired simulation
784519Sgblack@eecs.umich.edu# configuration.  For now, the Python emits a .ini file that can be
794519Sgblack@eecs.umich.edu# parsed by M5.  In the future, some tighter integration between M5
804519Sgblack@eecs.umich.edu# and the Python interpreter may allow bypassing the .ini file.
814519Sgblack@eecs.umich.edu#
824519Sgblack@eecs.umich.edu# Each SimObject class in M5 is represented by a Python class with the
834688Sgblack@eecs.umich.edu# same name.  The Python inheritance tree mirrors the M5 C++ tree
847969Sgblack@eecs.umich.edu# (e.g., SimpleCPU derives from BaseCPU in both cases, and all
857969Sgblack@eecs.umich.edu# SimObjects inherit from a single SimObject base class).  To specify
864688Sgblack@eecs.umich.edu# an instance of an M5 SimObject in a configuration, the user simply
874688Sgblack@eecs.umich.edu# instantiates the corresponding Python object.  The parameters for
884688Sgblack@eecs.umich.edu# that SimObject are given by assigning to attributes of the Python
894688Sgblack@eecs.umich.edu# object, either using keyword assignment in the constructor or in
904688Sgblack@eecs.umich.edu# separate assignment statements.  For example:
914708Sgblack@eecs.umich.edu#
924708Sgblack@eecs.umich.edu# cache = BaseCache(size='64KB')
934708Sgblack@eecs.umich.edu# cache.hit_latency = 3
944708Sgblack@eecs.umich.edu# cache.assoc = 8
954519Sgblack@eecs.umich.edu#
964519Sgblack@eecs.umich.edu# The magic lies in the mapping of the Python attributes for SimObject
974519Sgblack@eecs.umich.edu# classes to the actual SimObject parameter specifications.  This
984519Sgblack@eecs.umich.edu# allows parameter validity checking in the Python code.  Continuing
994519Sgblack@eecs.umich.edu# the example above, the statements "cache.blurfl=3" or
1004519Sgblack@eecs.umich.edu# "cache.assoc='hello'" would both result in runtime errors in Python,
1014519Sgblack@eecs.umich.edu# since the BaseCache object has no 'blurfl' parameter and the 'assoc'
1024519Sgblack@eecs.umich.edu# parameter requires an integer, respectively.  This magic is done
1034519Sgblack@eecs.umich.edu# primarily by overriding the special __setattr__ method that controls
1044519Sgblack@eecs.umich.edu# assignment to object attributes.
1054519Sgblack@eecs.umich.edu#
1064519Sgblack@eecs.umich.edu# Once a set of Python objects have been instantiated in a hierarchy,
1074519Sgblack@eecs.umich.edu# calling 'instantiate(obj)' (where obj is the root of the hierarchy)
1084519Sgblack@eecs.umich.edu# will generate a .ini file.
1094519Sgblack@eecs.umich.edu#
1107620Sgblack@eecs.umich.edu#####################################################################
1116345Sgblack@eecs.umich.edu
1124712Sgblack@eecs.umich.edu# list of all SimObject classes
1134519Sgblack@eecs.umich.eduallClasses = {}
1144519Sgblack@eecs.umich.edu
1154519Sgblack@eecs.umich.edu# dict to look up SimObjects based on path
1164519Sgblack@eecs.umich.eduinstanceDict = {}
1174519Sgblack@eecs.umich.edu
1184519Sgblack@eecs.umich.edu# Did any of the SimObjects lack a header file?
1194519Sgblack@eecs.umich.edunoCxxHeader = False
1204951Sgblack@eecs.umich.edu
1214519Sgblack@eecs.umich.edudef public_value(key, value):
1224519Sgblack@eecs.umich.edu    return key.startswith('_') or \
1234951Sgblack@eecs.umich.edu               isinstance(value, (FunctionType, MethodType, ModuleType,
1247620Sgblack@eecs.umich.edu                                  classmethod, type))
1256646Sgblack@eecs.umich.edu
1264712Sgblack@eecs.umich.edudef createCxxConfigDirectoryEntryFile(code, name, simobj, is_header):
1274519Sgblack@eecs.umich.edu    entry_class = 'CxxConfigDirectoryEntry_%s' % name
1284519Sgblack@eecs.umich.edu    param_class = '%sCxxConfigParams' % name
1294519Sgblack@eecs.umich.edu
1304519Sgblack@eecs.umich.edu    code('#include "params/%s.hh"' % name)
1314519Sgblack@eecs.umich.edu
1324519Sgblack@eecs.umich.edu    if not is_header:
13310184SCurtis.Dunham@arm.com        for param in simobj._params.values():
1347620Sgblack@eecs.umich.edu            if isSimObjectClass(param.ptype):
1356345Sgblack@eecs.umich.edu                code('#include "%s"' % param.ptype._value_dict['cxx_header'])
1364712Sgblack@eecs.umich.edu                code('#include "params/%s.hh"' % param.ptype.__name__)
1377620Sgblack@eecs.umich.edu            else:
1384688Sgblack@eecs.umich.edu                param.ptype.cxx_ini_predecls(code)
1394581Sgblack@eecs.umich.edu
1404519Sgblack@eecs.umich.edu    if is_header:
1417626Sgblack@eecs.umich.edu        member_prefix = ''
1427894SBrad.Beckmann@amd.com        end_of_decl = ';'
1434519Sgblack@eecs.umich.edu        code('#include "sim/cxx_config.hh"')
1444519Sgblack@eecs.umich.edu        code()
1454519Sgblack@eecs.umich.edu        code('class ${param_class} : public CxxConfigParams,'
1464519Sgblack@eecs.umich.edu            ' public ${name}Params')
14710184SCurtis.Dunham@arm.com        code('{')
1487620Sgblack@eecs.umich.edu        code('  private:')
1496646Sgblack@eecs.umich.edu        code.indent()
1504712Sgblack@eecs.umich.edu        code('class DirectoryEntry : public CxxConfigDirectoryEntry')
1517620Sgblack@eecs.umich.edu        code('{')
1524688Sgblack@eecs.umich.edu        code('  public:')
1534581Sgblack@eecs.umich.edu        code.indent()
1544519Sgblack@eecs.umich.edu        code('DirectoryEntry();');
1557626Sgblack@eecs.umich.edu        code()
1567894SBrad.Beckmann@amd.com        code('CxxConfigParams *makeParamsObject() const')
1574519Sgblack@eecs.umich.edu        code('{ return new ${param_class}; }')
1584519Sgblack@eecs.umich.edu        code.dedent()
1594519Sgblack@eecs.umich.edu        code('};')
1605075Sgblack@eecs.umich.edu        code()
1615075Sgblack@eecs.umich.edu        code.dedent()
1625075Sgblack@eecs.umich.edu        code('  public:')
1635075Sgblack@eecs.umich.edu        code.indent()
1645428Sgblack@eecs.umich.edu    else:
1655428Sgblack@eecs.umich.edu        member_prefix = '%s::' % param_class
1665674Sgblack@eecs.umich.edu        end_of_decl = ''
1675899Sgblack@eecs.umich.edu        code('#include "%s"' % simobj._value_dict['cxx_header'])
1685936Sgblack@eecs.umich.edu        code('#include "base/str.hh"')
1695428Sgblack@eecs.umich.edu        code('#include "cxx_config/${name}.hh"')
1705678Sgblack@eecs.umich.edu
1715678Sgblack@eecs.umich.edu        if simobj._ports.values() != []:
1725678Sgblack@eecs.umich.edu            code('#include "mem/mem_object.hh"')
1735678Sgblack@eecs.umich.edu            code('#include "mem/port.hh"')
1745678Sgblack@eecs.umich.edu
1755678Sgblack@eecs.umich.edu        code()
1765678Sgblack@eecs.umich.edu        code('${member_prefix}DirectoryEntry::DirectoryEntry()');
1775678Sgblack@eecs.umich.edu        code('{')
1785678Sgblack@eecs.umich.edu
1795075Sgblack@eecs.umich.edu        def cxx_bool(b):
1805075Sgblack@eecs.umich.edu            return 'true' if b else 'false'
1815075Sgblack@eecs.umich.edu
1825075Sgblack@eecs.umich.edu        code.indent()
1835075Sgblack@eecs.umich.edu        for param in simobj._params.values():
1845075Sgblack@eecs.umich.edu            is_vector = isinstance(param, m5.params.VectorParamDesc)
1855075Sgblack@eecs.umich.edu            is_simobj = issubclass(param.ptype, m5.SimObject.SimObject)
1865075Sgblack@eecs.umich.edu
1877719Sgblack@eecs.umich.edu            code('parameters["%s"] = new ParamDesc("%s", %s, %s);' %
1885075Sgblack@eecs.umich.edu                (param.name, param.name, cxx_bool(is_vector),
1895075Sgblack@eecs.umich.edu                cxx_bool(is_simobj)));
1905075Sgblack@eecs.umich.edu
1915075Sgblack@eecs.umich.edu        for port in simobj._ports.values():
1925075Sgblack@eecs.umich.edu            is_vector = isinstance(port, m5.params.VectorPort)
1935075Sgblack@eecs.umich.edu            is_master = port.role == 'MASTER'
1945075Sgblack@eecs.umich.edu
1955075Sgblack@eecs.umich.edu            code('ports["%s"] = new PortDesc("%s", %s, %s);' %
1965075Sgblack@eecs.umich.edu                (port.name, port.name, cxx_bool(is_vector),
1975075Sgblack@eecs.umich.edu                cxx_bool(is_master)))
1985075Sgblack@eecs.umich.edu
1995075Sgblack@eecs.umich.edu        code.dedent()
2005075Sgblack@eecs.umich.edu        code('}')
2015075Sgblack@eecs.umich.edu        code()
2025075Sgblack@eecs.umich.edu
2035075Sgblack@eecs.umich.edu    code('bool ${member_prefix}setSimObject(const std::string &name,')
2045075Sgblack@eecs.umich.edu    code('    SimObject *simObject)${end_of_decl}')
2055075Sgblack@eecs.umich.edu
2065075Sgblack@eecs.umich.edu    if not is_header:
2075075Sgblack@eecs.umich.edu        code('{')
2085075Sgblack@eecs.umich.edu        code.indent()
2095075Sgblack@eecs.umich.edu        code('bool ret = true;')
2105075Sgblack@eecs.umich.edu        code()
2115075Sgblack@eecs.umich.edu        code('if (false) {')
2125075Sgblack@eecs.umich.edu        for param in simobj._params.values():
2134519Sgblack@eecs.umich.edu            is_vector = isinstance(param, m5.params.VectorParamDesc)
2145040Sgblack@eecs.umich.edu            is_simobj = issubclass(param.ptype, m5.SimObject.SimObject)
2155040Sgblack@eecs.umich.edu
2165040Sgblack@eecs.umich.edu            if is_simobj and not is_vector:
2175040Sgblack@eecs.umich.edu                code('} else if (name == "${{param.name}}") {')
2185040Sgblack@eecs.umich.edu                code.indent()
2195040Sgblack@eecs.umich.edu                code('this->${{param.name}} = '
2205040Sgblack@eecs.umich.edu                    'dynamic_cast<${{param.ptype.cxx_type}}>(simObject);')
2215040Sgblack@eecs.umich.edu                code('if (simObject && !this->${{param.name}})')
2225040Sgblack@eecs.umich.edu                code('   ret = false;')
2235040Sgblack@eecs.umich.edu                code.dedent()
2245040Sgblack@eecs.umich.edu        code('} else {')
2255040Sgblack@eecs.umich.edu        code('    ret = false;')
2265040Sgblack@eecs.umich.edu        code('}')
2275040Sgblack@eecs.umich.edu        code()
2285040Sgblack@eecs.umich.edu        code('return ret;')
2295040Sgblack@eecs.umich.edu        code.dedent()
2305040Sgblack@eecs.umich.edu        code('}')
2317967Sgblack@eecs.umich.edu
2329699Snilay@cs.wisc.edu    code()
2339699Snilay@cs.wisc.edu    code('bool ${member_prefix}setSimObjectVector('
2345040Sgblack@eecs.umich.edu        'const std::string &name,')
2355040Sgblack@eecs.umich.edu    code('    const std::vector<SimObject *> &simObjects)${end_of_decl}')
2365040Sgblack@eecs.umich.edu
2375040Sgblack@eecs.umich.edu    if not is_header:
2385040Sgblack@eecs.umich.edu        code('{')
2395040Sgblack@eecs.umich.edu        code.indent()
2405040Sgblack@eecs.umich.edu        code('bool ret = true;')
24111320Ssteve.reinhardt@amd.com        code()
2427894SBrad.Beckmann@amd.com        code('if (false) {')
2437967Sgblack@eecs.umich.edu        for param in simobj._params.values():
2447967Sgblack@eecs.umich.edu            is_vector = isinstance(param, m5.params.VectorParamDesc)
2455040Sgblack@eecs.umich.edu            is_simobj = issubclass(param.ptype, m5.SimObject.SimObject)
2465040Sgblack@eecs.umich.edu
2475040Sgblack@eecs.umich.edu            if is_simobj and is_vector:
2488588Sgblack@eecs.umich.edu                code('} else if (name == "${{param.name}}") {')
2497967Sgblack@eecs.umich.edu                code.indent()
2505062Sgblack@eecs.umich.edu                code('this->${{param.name}}.clear();')
2515062Sgblack@eecs.umich.edu                code('for (auto i = simObjects.begin(); '
2525062Sgblack@eecs.umich.edu                    'ret && i != simObjects.end(); i ++)')
2535062Sgblack@eecs.umich.edu                code('{')
2545062Sgblack@eecs.umich.edu                code.indent()
2555040Sgblack@eecs.umich.edu                code('${{param.ptype.cxx_type}} object = '
2565062Sgblack@eecs.umich.edu                    'dynamic_cast<${{param.ptype.cxx_type}}>(*i);')
2577967Sgblack@eecs.umich.edu                code('if (*i && !object)')
2585062Sgblack@eecs.umich.edu                code('    ret = false;')
2595062Sgblack@eecs.umich.edu                code('else')
2607894SBrad.Beckmann@amd.com                code('    this->${{param.name}}.push_back(object);')
2619699Snilay@cs.wisc.edu                code.dedent()
2629699Snilay@cs.wisc.edu                code('}')
2636647Sgblack@eecs.umich.edu                code.dedent()
2645040Sgblack@eecs.umich.edu        code('} else {')
2656647Sgblack@eecs.umich.edu        code('    ret = false;')
2667967Sgblack@eecs.umich.edu        code('}')
2676647Sgblack@eecs.umich.edu        code()
2686647Sgblack@eecs.umich.edu        code('return ret;')
2697894SBrad.Beckmann@amd.com        code.dedent()
2709699Snilay@cs.wisc.edu        code('}')
2719699Snilay@cs.wisc.edu
2725040Sgblack@eecs.umich.edu    code()
2735040Sgblack@eecs.umich.edu    code('void ${member_prefix}setName(const std::string &name_)'
2745040Sgblack@eecs.umich.edu        '${end_of_decl}')
2755040Sgblack@eecs.umich.edu
2765239Sgblack@eecs.umich.edu    if not is_header:
2775040Sgblack@eecs.umich.edu        code('{')
2789699Snilay@cs.wisc.edu        code.indent()
2795040Sgblack@eecs.umich.edu        code('this->name = name_;')
2805040Sgblack@eecs.umich.edu        code.dedent()
2815040Sgblack@eecs.umich.edu        code('}')
2825040Sgblack@eecs.umich.edu
2837967Sgblack@eecs.umich.edu    if is_header:
2847967Sgblack@eecs.umich.edu        code('const std::string &${member_prefix}getName()')
2857967Sgblack@eecs.umich.edu        code('{ return this->name; }')
2867967Sgblack@eecs.umich.edu
2877967Sgblack@eecs.umich.edu    code()
2887967Sgblack@eecs.umich.edu    code('bool ${member_prefix}setParam(const std::string &name,')
2897967Sgblack@eecs.umich.edu    code('    const std::string &value, const Flags flags)${end_of_decl}')
2907967Sgblack@eecs.umich.edu
2917967Sgblack@eecs.umich.edu    if not is_header:
2927967Sgblack@eecs.umich.edu        code('{')
2937967Sgblack@eecs.umich.edu        code.indent()
2947967Sgblack@eecs.umich.edu        code('bool ret = true;')
2957967Sgblack@eecs.umich.edu        code()
2967967Sgblack@eecs.umich.edu        code('if (false) {')
2977967Sgblack@eecs.umich.edu        for param in simobj._params.values():
2987967Sgblack@eecs.umich.edu            is_vector = isinstance(param, m5.params.VectorParamDesc)
2997967Sgblack@eecs.umich.edu            is_simobj = issubclass(param.ptype, m5.SimObject.SimObject)
3007967Sgblack@eecs.umich.edu
3017967Sgblack@eecs.umich.edu            if not is_simobj and not is_vector:
3027967Sgblack@eecs.umich.edu                code('} else if (name == "${{param.name}}") {')
3037967Sgblack@eecs.umich.edu                code.indent()
3045040Sgblack@eecs.umich.edu                param.ptype.cxx_ini_parse(code,
3055040Sgblack@eecs.umich.edu                    'value', 'this->%s' % param.name, 'ret =')
3065040Sgblack@eecs.umich.edu                code.dedent()
3075040Sgblack@eecs.umich.edu        code('} else {')
3085040Sgblack@eecs.umich.edu        code('    ret = false;')
3095040Sgblack@eecs.umich.edu        code('}')
3106647Sgblack@eecs.umich.edu        code()
3115040Sgblack@eecs.umich.edu        code('return ret;')
3125040Sgblack@eecs.umich.edu        code.dedent()
3135040Sgblack@eecs.umich.edu        code('}')
3145040Sgblack@eecs.umich.edu
3155040Sgblack@eecs.umich.edu    code()
3167967Sgblack@eecs.umich.edu    code('bool ${member_prefix}setParamVector('
3175040Sgblack@eecs.umich.edu        'const std::string &name,')
3185040Sgblack@eecs.umich.edu    code('    const std::vector<std::string> &values,')
3195040Sgblack@eecs.umich.edu    code('    const Flags flags)${end_of_decl}')
3207894SBrad.Beckmann@amd.com
3219699Snilay@cs.wisc.edu    if not is_header:
3229699Snilay@cs.wisc.edu        code('{')
3237967Sgblack@eecs.umich.edu        code.indent()
3247967Sgblack@eecs.umich.edu        code('bool ret = true;')
3257967Sgblack@eecs.umich.edu        code()
3267967Sgblack@eecs.umich.edu        code('if (false) {')
3277967Sgblack@eecs.umich.edu        for param in simobj._params.values():
3287967Sgblack@eecs.umich.edu            is_vector = isinstance(param, m5.params.VectorParamDesc)
3299699Snilay@cs.wisc.edu            is_simobj = issubclass(param.ptype, m5.SimObject.SimObject)
3309699Snilay@cs.wisc.edu
3315040Sgblack@eecs.umich.edu            if not is_simobj and is_vector:
3325040Sgblack@eecs.umich.edu                code('} else if (name == "${{param.name}}") {')
3337967Sgblack@eecs.umich.edu                code.indent()
3347967Sgblack@eecs.umich.edu                code('${{param.name}}.clear();')
3357967Sgblack@eecs.umich.edu                code('for (auto i = values.begin(); '
3367967Sgblack@eecs.umich.edu                    'ret && i != values.end(); i ++)')
3375040Sgblack@eecs.umich.edu                code('{')
3385040Sgblack@eecs.umich.edu                code.indent()
3395040Sgblack@eecs.umich.edu                code('${{param.ptype.cxx_type}} elem;')
3404688Sgblack@eecs.umich.edu                param.ptype.cxx_ini_parse(code,
3415040Sgblack@eecs.umich.edu                    '*i', 'elem', 'ret =')
3424688Sgblack@eecs.umich.edu                code('if (ret)')
3434688Sgblack@eecs.umich.edu                code('    this->${{param.name}}.push_back(elem);')
3444688Sgblack@eecs.umich.edu                code.dedent()
3454688Sgblack@eecs.umich.edu                code('}')
3465040Sgblack@eecs.umich.edu                code.dedent()
3474688Sgblack@eecs.umich.edu        code('} else {')
3485040Sgblack@eecs.umich.edu        code('    ret = false;')
3495040Sgblack@eecs.umich.edu        code('}')
3505040Sgblack@eecs.umich.edu        code()
3517967Sgblack@eecs.umich.edu        code('return ret;')
3525040Sgblack@eecs.umich.edu        code.dedent()
3535040Sgblack@eecs.umich.edu        code('}')
3545040Sgblack@eecs.umich.edu
3557894SBrad.Beckmann@amd.com    code()
3569699Snilay@cs.wisc.edu    code('bool ${member_prefix}setPortConnectionCount('
3575040Sgblack@eecs.umich.edu        'const std::string &name,')
3585040Sgblack@eecs.umich.edu    code('    unsigned int count)${end_of_decl}')
3597967Sgblack@eecs.umich.edu
3607967Sgblack@eecs.umich.edu    if not is_header:
3619699Snilay@cs.wisc.edu        code('{')
3625040Sgblack@eecs.umich.edu        code.indent()
3635040Sgblack@eecs.umich.edu        code('bool ret = true;')
3645040Sgblack@eecs.umich.edu        code()
3655040Sgblack@eecs.umich.edu        code('if (false)')
3665040Sgblack@eecs.umich.edu        code('    ;')
3677894SBrad.Beckmann@amd.com        for port in simobj._ports.values():
3687894SBrad.Beckmann@amd.com            code('else if (name == "${{port.name}}")')
3695040Sgblack@eecs.umich.edu            code('    this->port_${{port.name}}_connection_count = count;')
3705040Sgblack@eecs.umich.edu        code('else')
3715040Sgblack@eecs.umich.edu        code('    ret = false;')
3728588Sgblack@eecs.umich.edu        code()
3735040Sgblack@eecs.umich.edu        code('return ret;')
3745040Sgblack@eecs.umich.edu        code.dedent()
3754688Sgblack@eecs.umich.edu        code('}')
3764688Sgblack@eecs.umich.edu
3775040Sgblack@eecs.umich.edu    code()
3785040Sgblack@eecs.umich.edu    code('SimObject *${member_prefix}simObjectCreate()${end_of_decl}')
3795040Sgblack@eecs.umich.edu
3805040Sgblack@eecs.umich.edu    if not is_header:
3814688Sgblack@eecs.umich.edu        code('{')
3824688Sgblack@eecs.umich.edu        if hasattr(simobj, 'abstract') and simobj.abstract:
3835040Sgblack@eecs.umich.edu            code('    return NULL;')
3847967Sgblack@eecs.umich.edu        else:
3855040Sgblack@eecs.umich.edu            code('    return this->create();')
3865040Sgblack@eecs.umich.edu        code('}')
3875040Sgblack@eecs.umich.edu
3887894SBrad.Beckmann@amd.com    if is_header:
3899699Snilay@cs.wisc.edu        code()
3905040Sgblack@eecs.umich.edu        code('static CxxConfigDirectoryEntry'
3915040Sgblack@eecs.umich.edu            ' *${member_prefix}makeDirectoryEntry()')
3924519Sgblack@eecs.umich.edu        code('{ return new DirectoryEntry; }')
3934519Sgblack@eecs.umich.edu
3945040Sgblack@eecs.umich.edu    if is_header:
3954688Sgblack@eecs.umich.edu        code.dedent()
3964701Sgblack@eecs.umich.edu        code('};')
3974688Sgblack@eecs.umich.edu
3984688Sgblack@eecs.umich.edu# The metaclass for SimObject.  This class controls how new classes
3994688Sgblack@eecs.umich.edu# that derive from SimObject are instantiated, and provides inherited
4004688Sgblack@eecs.umich.edu# class behavior (just like a class controls how instances of that
4014688Sgblack@eecs.umich.edu# class are instantiated, and provides inherited instance behavior).
4024688Sgblack@eecs.umich.educlass MetaSimObject(type):
4034688Sgblack@eecs.umich.edu    # Attributes that can be set only at initialization time
4044519Sgblack@eecs.umich.edu    init_keywords = {
4057620Sgblack@eecs.umich.edu        'abstract' : bool,
4067967Sgblack@eecs.umich.edu        'cxx_class' : str,
4077967Sgblack@eecs.umich.edu        'cxx_type' : str,
4087967Sgblack@eecs.umich.edu        'cxx_header' : str,
4097967Sgblack@eecs.umich.edu        'type' : str,
4107967Sgblack@eecs.umich.edu        'cxx_base' : (str, type(None)),
4117967Sgblack@eecs.umich.edu        'cxx_extra_bases' : list,
4127967Sgblack@eecs.umich.edu        'cxx_exports' : list,
4137967Sgblack@eecs.umich.edu        'cxx_param_exports' : list,
4147967Sgblack@eecs.umich.edu    }
4157967Sgblack@eecs.umich.edu    # Attributes that can be set any time
4167967Sgblack@eecs.umich.edu    keywords = { 'check' : FunctionType }
4177967Sgblack@eecs.umich.edu
4187967Sgblack@eecs.umich.edu    # __new__ is called before __init__, and is where the statements
4197967Sgblack@eecs.umich.edu    # in the body of the class definition get loaded into the class's
4207967Sgblack@eecs.umich.edu    # __dict__.  We intercept this to filter out parameter & port assignments
4217967Sgblack@eecs.umich.edu    # and only allow "private" attributes to be passed to the base
4227967Sgblack@eecs.umich.edu    # __new__ (starting with underscore).
4237967Sgblack@eecs.umich.edu    def __new__(mcls, name, bases, dict):
4247967Sgblack@eecs.umich.edu        assert name not in allClasses, "SimObject %s already present" % name
4257967Sgblack@eecs.umich.edu
4267967Sgblack@eecs.umich.edu        # Copy "private" attributes, functions, and classes to the
4277967Sgblack@eecs.umich.edu        # official dict.  Everything else goes in _init_dict to be
4287967Sgblack@eecs.umich.edu        # filtered in __init__.
4297967Sgblack@eecs.umich.edu        cls_dict = {}
4307967Sgblack@eecs.umich.edu        value_dict = {}
4317967Sgblack@eecs.umich.edu        cxx_exports = []
4327967Sgblack@eecs.umich.edu        for key,val in dict.items():
4337967Sgblack@eecs.umich.edu            try:
4347967Sgblack@eecs.umich.edu                cxx_exports.append(getattr(val, "__pybind"))
4357967Sgblack@eecs.umich.edu            except AttributeError:
4367967Sgblack@eecs.umich.edu                pass
4377967Sgblack@eecs.umich.edu
4387967Sgblack@eecs.umich.edu            if public_value(key, val):
4397967Sgblack@eecs.umich.edu                cls_dict[key] = val
4407967Sgblack@eecs.umich.edu            else:
4414519Sgblack@eecs.umich.edu                # must be a param/port setting
4425040Sgblack@eecs.umich.edu                value_dict[key] = val
4434688Sgblack@eecs.umich.edu        if 'abstract' not in value_dict:
4445040Sgblack@eecs.umich.edu            value_dict['abstract'] = False
4455040Sgblack@eecs.umich.edu        if 'cxx_extra_bases' not in value_dict:
4465115Sgblack@eecs.umich.edu            value_dict['cxx_extra_bases'] = []
4479212Snilay@cs.wisc.edu        if 'cxx_exports' not in value_dict:
4489212Snilay@cs.wisc.edu            value_dict['cxx_exports'] = cxx_exports
4499212Snilay@cs.wisc.edu        else:
4509212Snilay@cs.wisc.edu            value_dict['cxx_exports'] += cxx_exports
4519212Snilay@cs.wisc.edu        if 'cxx_param_exports' not in value_dict:
4529010Snilay@cs.wisc.edu            value_dict['cxx_param_exports'] = []
4535040Sgblack@eecs.umich.edu        cls_dict['_value_dict'] = value_dict
4549212Snilay@cs.wisc.edu        cls = super(MetaSimObject, mcls).__new__(mcls, name, bases, cls_dict)
4559212Snilay@cs.wisc.edu        if 'type' in value_dict:
4565040Sgblack@eecs.umich.edu            allClasses[name] = cls
4574519Sgblack@eecs.umich.edu        return cls
4585040Sgblack@eecs.umich.edu
4595040Sgblack@eecs.umich.edu    # subclass initialization
4609010Snilay@cs.wisc.edu    def __init__(cls, name, bases, dict):
4619212Snilay@cs.wisc.edu        # calls type.__init__()... I think that's a no-op, but leave
4629212Snilay@cs.wisc.edu        # it here just in case it's not.
4639212Snilay@cs.wisc.edu        super(MetaSimObject, cls).__init__(name, bases, dict)
4649212Snilay@cs.wisc.edu
4659212Snilay@cs.wisc.edu        # initialize required attributes
4669212Snilay@cs.wisc.edu
4679212Snilay@cs.wisc.edu        # class-only attributes
4689212Snilay@cs.wisc.edu        cls._params = multidict() # param descriptions
4699212Snilay@cs.wisc.edu        cls._ports = multidict()  # port descriptions
4709010Snilay@cs.wisc.edu
4714519Sgblack@eecs.umich.edu        # class or instance attributes
4725040Sgblack@eecs.umich.edu        cls._values = multidict()   # param values
4735040Sgblack@eecs.umich.edu        cls._hr_values = multidict() # human readable param values
4749010Snilay@cs.wisc.edu        cls._children = multidict() # SimObject children
4759212Snilay@cs.wisc.edu        cls._port_refs = multidict() # port ref objects
4769212Snilay@cs.wisc.edu        cls._instantiated = False # really instantiated, cloned, or subclassed
4779212Snilay@cs.wisc.edu
4789212Snilay@cs.wisc.edu        # We don't support multiple inheritance of sim objects.  If you want
4799212Snilay@cs.wisc.edu        # to, you must fix multidict to deal with it properly. Non sim-objects
4809212Snilay@cs.wisc.edu        # are ok, though
4819212Snilay@cs.wisc.edu        bTotal = 0
4829212Snilay@cs.wisc.edu        for c in bases:
4839212Snilay@cs.wisc.edu            if isinstance(c, MetaSimObject):
4849010Snilay@cs.wisc.edu                bTotal += 1
4854519Sgblack@eecs.umich.edu            if bTotal > 1:
4865040Sgblack@eecs.umich.edu                raise TypeError(
4875040Sgblack@eecs.umich.edu                      "SimObjects do not support multiple inheritance")
4889211Snilay@cs.wisc.edu
4899211Snilay@cs.wisc.edu        base = bases[0]
4907894SBrad.Beckmann@amd.com
4914519Sgblack@eecs.umich.edu        # Set up general inheritance via multidicts.  A subclass will
4925063Sgblack@eecs.umich.edu        # inherit all its settings from the base class.  The only time
4935063Sgblack@eecs.umich.edu        # the following is not true is when we define the SimObject
4945063Sgblack@eecs.umich.edu        # class itself (in which case the multidicts have no parent).
4955063Sgblack@eecs.umich.edu        if isinstance(base, MetaSimObject):
4965063Sgblack@eecs.umich.edu            cls._base = base
4976345Sgblack@eecs.umich.edu            cls._params.parent = base._params
4986345Sgblack@eecs.umich.edu            cls._ports.parent = base._ports
4995063Sgblack@eecs.umich.edu            cls._values.parent = base._values
5005063Sgblack@eecs.umich.edu            cls._hr_values.parent = base._hr_values
5015063Sgblack@eecs.umich.edu            cls._children.parent = base._children
5025063Sgblack@eecs.umich.edu            cls._port_refs.parent = base._port_refs
5036345Sgblack@eecs.umich.edu            # mark base as having been subclassed
5046345Sgblack@eecs.umich.edu            base._instantiated = True
5055063Sgblack@eecs.umich.edu        else:
5065040Sgblack@eecs.umich.edu            cls._base = None
5077969Sgblack@eecs.umich.edu
5087969Sgblack@eecs.umich.edu        # default keyword values
5094595Sgblack@eecs.umich.edu        if 'type' in cls._value_dict:
5105040Sgblack@eecs.umich.edu            if 'cxx_class' not in cls._value_dict:
5117969Sgblack@eecs.umich.edu                cls._value_dict['cxx_class'] = cls._value_dict['type']
5127969Sgblack@eecs.umich.edu
5134595Sgblack@eecs.umich.edu            cls._value_dict['cxx_type'] = '%s *' % cls._value_dict['cxx_class']
5145040Sgblack@eecs.umich.edu
5155040Sgblack@eecs.umich.edu            if 'cxx_header' not in cls._value_dict:
5169010Snilay@cs.wisc.edu                global noCxxHeader
5177969Sgblack@eecs.umich.edu                noCxxHeader = True
5185040Sgblack@eecs.umich.edu                warn("No header file specified for SimObject: %s", name)
5197967Sgblack@eecs.umich.edu
5209010Snilay@cs.wisc.edu        # Now process the _value_dict items.  They could be defining
5217969Sgblack@eecs.umich.edu        # new (or overriding existing) parameters or ports, setting
5227967Sgblack@eecs.umich.edu        # class keywords (e.g., 'abstract'), or setting parameter
5235040Sgblack@eecs.umich.edu        # values or port bindings.  The first 3 can only be set when
5245040Sgblack@eecs.umich.edu        # the class is defined, so we handle them here.  The others
5255040Sgblack@eecs.umich.edu        # can be set later too, so just emulate that by calling
5269010Snilay@cs.wisc.edu        # setattr().
5277969Sgblack@eecs.umich.edu        for key,val in cls._value_dict.items():
5285040Sgblack@eecs.umich.edu            # param descriptions
5297967Sgblack@eecs.umich.edu            if isinstance(val, ParamDesc):
5309010Snilay@cs.wisc.edu                cls._new_param(key, val)
5317969Sgblack@eecs.umich.edu
5327967Sgblack@eecs.umich.edu            # port objects
5335040Sgblack@eecs.umich.edu            elif isinstance(val, Port):
5345040Sgblack@eecs.umich.edu                cls._new_port(key, val)
5357969Sgblack@eecs.umich.edu
5367969Sgblack@eecs.umich.edu            # init-time-only keywords
5375040Sgblack@eecs.umich.edu            elif key in cls.init_keywords:
5385040Sgblack@eecs.umich.edu                cls._set_keyword(key, val, cls.init_keywords[key])
5397969Sgblack@eecs.umich.edu
5407969Sgblack@eecs.umich.edu            # default: use normal path (ends up in __setattr__)
5415040Sgblack@eecs.umich.edu            else:
5425040Sgblack@eecs.umich.edu                setattr(cls, key, val)
5437969Sgblack@eecs.umich.edu
5447969Sgblack@eecs.umich.edu    def _set_keyword(cls, keyword, val, kwtype):
5455040Sgblack@eecs.umich.edu        if not isinstance(val, kwtype):
5465063Sgblack@eecs.umich.edu            raise TypeError('keyword %s has bad type %s (expecting %s)' % \
5479699Snilay@cs.wisc.edu                  (keyword, type(val), kwtype))
5489699Snilay@cs.wisc.edu        if isinstance(val, FunctionType):
54912025Sgabeblack@google.com            val = classmethod(val)
55012025Sgabeblack@google.com        type.__setattr__(cls, keyword, val)
55112025Sgabeblack@google.com
55212025Sgabeblack@google.com    def _new_param(cls, name, pdesc):
55312025Sgabeblack@google.com        # each param desc should be uniquely assigned to one variable
5545040Sgblack@eecs.umich.edu        assert(not hasattr(pdesc, 'name'))
5555063Sgblack@eecs.umich.edu        pdesc.name = name
55612025Sgabeblack@google.com        cls._params[name] = pdesc
55712025Sgabeblack@google.com        if hasattr(pdesc, 'default'):
55812025Sgabeblack@google.com            cls._set_param(name, pdesc.default, pdesc)
55912025Sgabeblack@google.com
56012025Sgabeblack@google.com    def _set_param(cls, name, value, param):
56112025Sgabeblack@google.com        assert(param.name == name)
56212025Sgabeblack@google.com        try:
56312025Sgabeblack@google.com            hr_value = value
56412025Sgabeblack@google.com            value = param.convert(value)
56512025Sgabeblack@google.com        except Exception as e:
56612025Sgabeblack@google.com            msg = "%s\nError setting param %s.%s to %s\n" % \
56712025Sgabeblack@google.com                  (e, cls.__name__, name, value)
56812025Sgabeblack@google.com            e.args = (msg, )
56912025Sgabeblack@google.com            raise
57012025Sgabeblack@google.com        cls._values[name] = value
57112025Sgabeblack@google.com        # if param value is a SimObject, make it a child too, so that
57212025Sgabeblack@google.com        # it gets cloned properly when the class is instantiated
57312025Sgabeblack@google.com        if isSimObjectOrVector(value) and not value.has_parent():
57412025Sgabeblack@google.com            cls._add_cls_child(name, value)
57512025Sgabeblack@google.com        # update human-readable values of the param if it has a literal
57612025Sgabeblack@google.com        # value and is not an object or proxy.
57712025Sgabeblack@google.com        if not (isSimObjectOrVector(value) or\
57812025Sgabeblack@google.com                isinstance(value, m5.proxy.BaseProxy)):
5796462Sgblack@eecs.umich.edu            cls._hr_values[name] = hr_value
58012025Sgabeblack@google.com
5816462Sgblack@eecs.umich.edu    def _add_cls_child(cls, name, child):
58212025Sgabeblack@google.com        # It's a little funky to have a class as a parent, but these
58312025Sgabeblack@google.com        # objects should never be instantiated (only cloned, which
58412025Sgabeblack@google.com        # clears the parent pointer), and this makes it clear that the
5855040Sgblack@eecs.umich.edu        # object is not an orphan and can provide better error
5866463Sgblack@eecs.umich.edu        # messages.
5876463Sgblack@eecs.umich.edu        child.set_parent(cls, name)
5886463Sgblack@eecs.umich.edu        if not isNullPointer(child):
5899212Snilay@cs.wisc.edu            cls._children[name] = child
5909212Snilay@cs.wisc.edu
5916463Sgblack@eecs.umich.edu    def _new_port(cls, name, port):
5929212Snilay@cs.wisc.edu        # each port should be uniquely assigned to one variable
5939212Snilay@cs.wisc.edu        assert(not hasattr(port, 'name'))
5946463Sgblack@eecs.umich.edu        port.name = name
5956463Sgblack@eecs.umich.edu        cls._ports[name] = port
5965040Sgblack@eecs.umich.edu
5975063Sgblack@eecs.umich.edu    # same as _get_port_ref, effectively, but for classes
5989699Snilay@cs.wisc.edu    def _cls_get_port_ref(cls, attr):
5999699Snilay@cs.wisc.edu        # Return reference that can be assigned to another port
60012025Sgabeblack@google.com        # via __setattr__.  There is only ever one reference
60112025Sgabeblack@google.com        # object per port, but we create them lazily here.
60212025Sgabeblack@google.com        ref = cls._port_refs.get(attr)
60312025Sgabeblack@google.com        if not ref:
6045040Sgblack@eecs.umich.edu            ref = cls._ports[attr].makeRef(cls)
6055063Sgblack@eecs.umich.edu            cls._port_refs[attr] = ref
60612025Sgabeblack@google.com        return ref
60712025Sgabeblack@google.com
60812025Sgabeblack@google.com    # Set attribute (called on foo.attr = value when foo is an
60912025Sgabeblack@google.com    # instance of class cls).
61012025Sgabeblack@google.com    def __setattr__(cls, attr, value):
61112025Sgabeblack@google.com        # normal processing for private attributes
61212025Sgabeblack@google.com        if public_value(attr, value):
61312025Sgabeblack@google.com            type.__setattr__(cls, attr, value)
61412025Sgabeblack@google.com            return
61512025Sgabeblack@google.com
61612025Sgabeblack@google.com        if attr in cls.keywords:
61712025Sgabeblack@google.com            cls._set_keyword(attr, value, cls.keywords[attr])
61812025Sgabeblack@google.com            return
61912025Sgabeblack@google.com
62012025Sgabeblack@google.com        if attr in cls._ports:
62112025Sgabeblack@google.com            cls._cls_get_port_ref(attr).connect(value)
62212025Sgabeblack@google.com            return
62312025Sgabeblack@google.com
62412025Sgabeblack@google.com        if isSimObjectOrSequence(value) and cls._instantiated:
62512025Sgabeblack@google.com            raise RuntimeError(
62612025Sgabeblack@google.com                  "cannot set SimObject parameter '%s' after\n" \
62712025Sgabeblack@google.com                  "    class %s has been instantiated or subclassed" \
6285040Sgblack@eecs.umich.edu                  % (attr, cls.__name__))
6296463Sgblack@eecs.umich.edu
6306463Sgblack@eecs.umich.edu        # check for param
6319212Snilay@cs.wisc.edu        param = cls._params.get(attr)
6329212Snilay@cs.wisc.edu        if param:
6336463Sgblack@eecs.umich.edu            cls._set_param(attr, value, param)
6349212Snilay@cs.wisc.edu            return
6359212Snilay@cs.wisc.edu
6366463Sgblack@eecs.umich.edu        if isSimObjectOrSequence(value):
6376463Sgblack@eecs.umich.edu            # If RHS is a SimObject, it's an implicit child assignment.
6385040Sgblack@eecs.umich.edu            cls._add_cls_child(attr, coerceSimObjectOrVector(value))
6395063Sgblack@eecs.umich.edu            return
6405063Sgblack@eecs.umich.edu
6417967Sgblack@eecs.umich.edu        # no valid assignment... raise exception
6425040Sgblack@eecs.umich.edu        raise AttributeError(
6435063Sgblack@eecs.umich.edu              "Class %s has no parameter \'%s\'" % (cls.__name__, attr))
6445063Sgblack@eecs.umich.edu
6455063Sgblack@eecs.umich.edu    def __getattr__(cls, attr):
6465063Sgblack@eecs.umich.edu        if attr == 'cxx_class_path':
6476345Sgblack@eecs.umich.edu            return cls.cxx_class.split('::')
6486345Sgblack@eecs.umich.edu
6495063Sgblack@eecs.umich.edu        if attr == 'cxx_class_name':
6507967Sgblack@eecs.umich.edu            return cls.cxx_class_path[-1]
6515062Sgblack@eecs.umich.edu
6525075Sgblack@eecs.umich.edu        if attr == 'cxx_namespaces':
6535075Sgblack@eecs.umich.edu            return cls.cxx_class_path[:-1]
6549699Snilay@cs.wisc.edu
6559699Snilay@cs.wisc.edu        if attr in cls._values:
6565040Sgblack@eecs.umich.edu            return cls._values[attr]
6575075Sgblack@eecs.umich.edu
6585075Sgblack@eecs.umich.edu        if attr in cls._children:
6595075Sgblack@eecs.umich.edu            return cls._children[attr]
6605075Sgblack@eecs.umich.edu
6615075Sgblack@eecs.umich.edu        raise AttributeError(
6625075Sgblack@eecs.umich.edu              "object '%s' has no attribute '%s'" % (cls.__name__, attr))
6635075Sgblack@eecs.umich.edu
6645075Sgblack@eecs.umich.edu    def __str__(cls):
6655075Sgblack@eecs.umich.edu        return cls.__name__
6665075Sgblack@eecs.umich.edu
6677719Sgblack@eecs.umich.edu    # See ParamValue.cxx_predecls for description.
66810805Snilay@cs.wisc.edu    def cxx_predecls(cls, code):
6697719Sgblack@eecs.umich.edu        code('#include "params/$cls.hh"')
6707719Sgblack@eecs.umich.edu
6717719Sgblack@eecs.umich.edu    def pybind_predecls(cls, code):
6727719Sgblack@eecs.umich.edu        code('#include "${{cls.cxx_header}}"')
6737719Sgblack@eecs.umich.edu
6747719Sgblack@eecs.umich.edu    def pybind_decl(cls, code):
6757719Sgblack@eecs.umich.edu        class_path = cls.cxx_class.split('::')
6765040Sgblack@eecs.umich.edu        namespaces, classname = class_path[:-1], class_path[-1]
6774823Sgblack@eecs.umich.edu        py_class_name = '_COLONS_'.join(class_path) if namespaces else \
6785075Sgblack@eecs.umich.edu                        classname;
6795075Sgblack@eecs.umich.edu
6809699Snilay@cs.wisc.edu        # The 'local' attribute restricts us to the params declared in
6819699Snilay@cs.wisc.edu        # the object itself, not including inherited params (which
6827967Sgblack@eecs.umich.edu        # will also be inherited from the base class's param struct
6835075Sgblack@eecs.umich.edu        # here). Sort the params based on their key
6845075Sgblack@eecs.umich.edu        params = map(lambda k_v: k_v[1], sorted(cls._params.local.items()))
6855075Sgblack@eecs.umich.edu        ports = cls._ports.local
6865075Sgblack@eecs.umich.edu
6875075Sgblack@eecs.umich.edu        code('''#include "pybind11/pybind11.h"
6885075Sgblack@eecs.umich.edu#include "pybind11/stl.h"
6895075Sgblack@eecs.umich.edu
6907719Sgblack@eecs.umich.edu#include "params/$cls.hh"
69110805Snilay@cs.wisc.edu#include "python/pybind11/core.hh"
6927719Sgblack@eecs.umich.edu#include "sim/init.hh"
6937070Sgblack@eecs.umich.edu#include "sim/sim_object.hh"
6947070Sgblack@eecs.umich.edu
6957070Sgblack@eecs.umich.edu#include "${{cls.cxx_header}}"
6967070Sgblack@eecs.umich.edu
6977070Sgblack@eecs.umich.edu''')
6987070Sgblack@eecs.umich.edu
6997070Sgblack@eecs.umich.edu        for param in params:
7007070Sgblack@eecs.umich.edu            param.pybind_predecls(code)
7017080Sgblack@eecs.umich.edu
7027070Sgblack@eecs.umich.edu        code('''namespace py = pybind11;
7037080Sgblack@eecs.umich.edu
7047070Sgblack@eecs.umich.edustatic void
7057070Sgblack@eecs.umich.edumodule_init(py::module &m_internal)
7067070Sgblack@eecs.umich.edu{
7077070Sgblack@eecs.umich.edu    py::module m = m_internal.def_submodule("param_${cls}");
7087070Sgblack@eecs.umich.edu''')
7097080Sgblack@eecs.umich.edu        code.indent()
7107080Sgblack@eecs.umich.edu        if cls._base:
7117080Sgblack@eecs.umich.edu            code('py::class_<${cls}Params, ${{cls._base.type}}Params, ' \
7127080Sgblack@eecs.umich.edu                 'std::unique_ptr<${{cls}}Params, py::nodelete>>(' \
7137070Sgblack@eecs.umich.edu                 'm, "${cls}Params")')
7147070Sgblack@eecs.umich.edu        else:
7157070Sgblack@eecs.umich.edu            code('py::class_<${cls}Params, ' \
7167070Sgblack@eecs.umich.edu                 'std::unique_ptr<${cls}Params, py::nodelete>>(' \
7177070Sgblack@eecs.umich.edu                 'm, "${cls}Params")')
7187070Sgblack@eecs.umich.edu
7197070Sgblack@eecs.umich.edu        code.indent()
7207070Sgblack@eecs.umich.edu        if not hasattr(cls, 'abstract') or not cls.abstract:
7217070Sgblack@eecs.umich.edu            code('.def(py::init<>())')
7227070Sgblack@eecs.umich.edu            code('.def("create", &${cls}Params::create)')
7237070Sgblack@eecs.umich.edu
7247070Sgblack@eecs.umich.edu        param_exports = cls.cxx_param_exports + [
7257070Sgblack@eecs.umich.edu            PyBindProperty(k)
7265075Sgblack@eecs.umich.edu            for k, v in sorted(cls._params.local.items())
7275075Sgblack@eecs.umich.edu        ] + [
7285075Sgblack@eecs.umich.edu            PyBindProperty("port_%s_connection_count" % port.name)
7297967Sgblack@eecs.umich.edu            for port in ports.itervalues()
7305075Sgblack@eecs.umich.edu        ]
7315075Sgblack@eecs.umich.edu        for exp in param_exports:
7325075Sgblack@eecs.umich.edu            exp.export(code, "%sParams" % cls)
7335075Sgblack@eecs.umich.edu
7347967Sgblack@eecs.umich.edu        code(';')
7357967Sgblack@eecs.umich.edu        code()
7365075Sgblack@eecs.umich.edu        code.dedent()
7377480Sgblack@eecs.umich.edu
7389212Snilay@cs.wisc.edu        bases = []
7395075Sgblack@eecs.umich.edu        if 'cxx_base' in cls._value_dict:
7409212Snilay@cs.wisc.edu            # If the c++ base class implied by python inheritance was
7415075Sgblack@eecs.umich.edu            # overridden, use that value.
7424732Sgblack@eecs.umich.edu            if cls.cxx_base:
7435075Sgblack@eecs.umich.edu                bases.append(cls.cxx_base)
7445075Sgblack@eecs.umich.edu        elif cls._base:
7457967Sgblack@eecs.umich.edu            # If not and if there was a SimObject base, use its c++ class
7465075Sgblack@eecs.umich.edu            # as this class' base.
7475075Sgblack@eecs.umich.edu            bases.append(cls._base.cxx_class)
7485075Sgblack@eecs.umich.edu        # Add in any extra bases that were requested.
7497967Sgblack@eecs.umich.edu        bases.extend(cls.cxx_extra_bases)
7505040Sgblack@eecs.umich.edu
7515040Sgblack@eecs.umich.edu        if bases:
7525040Sgblack@eecs.umich.edu            base_str = ", ".join(bases)
7536482Sgblack@eecs.umich.edu            code('py::class_<${{cls.cxx_class}}, ${base_str}, ' \
7545040Sgblack@eecs.umich.edu                 'std::unique_ptr<${{cls.cxx_class}}, py::nodelete>>(' \
7554732Sgblack@eecs.umich.edu                 'm, "${py_class_name}")')
7565040Sgblack@eecs.umich.edu        else:
7575076Sgblack@eecs.umich.edu            code('py::class_<${{cls.cxx_class}}, ' \
7585040Sgblack@eecs.umich.edu                 'std::unique_ptr<${{cls.cxx_class}}, py::nodelete>>(' \
7594756Sgblack@eecs.umich.edu                 'm, "${py_class_name}")')
7604823Sgblack@eecs.umich.edu        code.indent()
7615040Sgblack@eecs.umich.edu        for exp in cls.cxx_exports:
7627967Sgblack@eecs.umich.edu            exp.export(code, cls.cxx_class)
7637967Sgblack@eecs.umich.edu        code(';')
7647967Sgblack@eecs.umich.edu        code.dedent()
7657967Sgblack@eecs.umich.edu        code()
7665076Sgblack@eecs.umich.edu        code.dedent()
7675076Sgblack@eecs.umich.edu        code('}')
7685076Sgblack@eecs.umich.edu        code()
7695076Sgblack@eecs.umich.edu        code('static EmbeddedPyBind embed_obj("${0}", module_init, "${1}");',
7705076Sgblack@eecs.umich.edu             cls, cls._base.type if cls._base else "")
7719212Snilay@cs.wisc.edu
7729212Snilay@cs.wisc.edu
7739010Snilay@cs.wisc.edu    # Generate the C++ declaration (.hh file) for this SimObject's
7745076Sgblack@eecs.umich.edu    # param struct.  Called from src/SConscript.
7755076Sgblack@eecs.umich.edu    def cxx_param_decl(cls, code):
7766441Sgblack@eecs.umich.edu        # The 'local' attribute restricts us to the params declared in
7776441Sgblack@eecs.umich.edu        # the object itself, not including inherited params (which
7785076Sgblack@eecs.umich.edu        # will also be inherited from the base class's param struct
7796441Sgblack@eecs.umich.edu        # here). Sort the params based on their key
7809010Snilay@cs.wisc.edu        params = map(lambda k_v: k_v[1], sorted(cls._params.local.items()))
7815076Sgblack@eecs.umich.edu        ports = cls._ports.local
7829010Snilay@cs.wisc.edu        try:
7839212Snilay@cs.wisc.edu            ptypes = [p.ptype for p in params]
7849212Snilay@cs.wisc.edu        except:
7859010Snilay@cs.wisc.edu            print(cls, p, p.ptype_str)
7869010Snilay@cs.wisc.edu            print(params)
7875076Sgblack@eecs.umich.edu            raise
7885076Sgblack@eecs.umich.edu
7899212Snilay@cs.wisc.edu        class_path = cls._value_dict['cxx_class'].split('::')
7909010Snilay@cs.wisc.edu
7915076Sgblack@eecs.umich.edu        code('''\
7929212Snilay@cs.wisc.edu#ifndef __PARAMS__${cls}__
7939212Snilay@cs.wisc.edu#define __PARAMS__${cls}__
7949212Snilay@cs.wisc.edu
7959212Snilay@cs.wisc.edu''')
7969212Snilay@cs.wisc.edu
7979212Snilay@cs.wisc.edu
7989212Snilay@cs.wisc.edu        # The base SimObject has a couple of params that get
7995076Sgblack@eecs.umich.edu        # automatically set from Python without being declared through
8005076Sgblack@eecs.umich.edu        # the normal Param mechanism; we slip them in here (needed
8015040Sgblack@eecs.umich.edu        # predecls now, actual declarations below)
8025076Sgblack@eecs.umich.edu        if cls == SimObject:
8037967Sgblack@eecs.umich.edu            code('''#include <string>''')
8047967Sgblack@eecs.umich.edu
8057967Sgblack@eecs.umich.edu        # A forward class declaration is sufficient since we are just
8065040Sgblack@eecs.umich.edu        # declaring a pointer.
8074756Sgblack@eecs.umich.edu        for ns in class_path[:-1]:
8084732Sgblack@eecs.umich.edu            code('namespace $ns {')
8094823Sgblack@eecs.umich.edu        code('class $0;', class_path[-1])
8105040Sgblack@eecs.umich.edu        for ns in reversed(class_path[:-1]):
8117967Sgblack@eecs.umich.edu            code('} // namespace $ns')
8127967Sgblack@eecs.umich.edu        code()
8137967Sgblack@eecs.umich.edu
8147967Sgblack@eecs.umich.edu        for param in params:
8157967Sgblack@eecs.umich.edu            param.cxx_predecls(code)
8165076Sgblack@eecs.umich.edu        for port in ports.itervalues():
8175076Sgblack@eecs.umich.edu            port.cxx_predecls(code)
8185076Sgblack@eecs.umich.edu        code()
8195076Sgblack@eecs.umich.edu
8205076Sgblack@eecs.umich.edu        if cls._base:
8219212Snilay@cs.wisc.edu            code('#include "params/${{cls._base.type}}.hh"')
8229212Snilay@cs.wisc.edu            code()
8239010Snilay@cs.wisc.edu
8245076Sgblack@eecs.umich.edu        for ptype in ptypes:
82511320Ssteve.reinhardt@amd.com            if issubclass(ptype, Enum):
8266442Sgblack@eecs.umich.edu                code('#include "enums/${{ptype.__name__}}.hh"')
8276442Sgblack@eecs.umich.edu                code()
8289212Snilay@cs.wisc.edu
8299212Snilay@cs.wisc.edu        # now generate the actual param struct
8306442Sgblack@eecs.umich.edu        code("struct ${cls}Params")
8319010Snilay@cs.wisc.edu        if cls._base:
8325076Sgblack@eecs.umich.edu            code("    : public ${{cls._base.type}}Params")
8335076Sgblack@eecs.umich.edu        code("{")
8349212Snilay@cs.wisc.edu        if not hasattr(cls, 'abstract') or not cls.abstract:
8359010Snilay@cs.wisc.edu            if 'type' in cls.__dict__:
8365076Sgblack@eecs.umich.edu                code("    ${{cls.cxx_type}} create();")
8379212Snilay@cs.wisc.edu
8389212Snilay@cs.wisc.edu        code.indent()
8399212Snilay@cs.wisc.edu        if cls == SimObject:
8409212Snilay@cs.wisc.edu            code('''
8419212Snilay@cs.wisc.edu    SimObjectParams() {}
8429212Snilay@cs.wisc.edu    virtual ~SimObjectParams() {}
8439212Snilay@cs.wisc.edu
8445076Sgblack@eecs.umich.edu    std::string name;
8455076Sgblack@eecs.umich.edu            ''')
8465040Sgblack@eecs.umich.edu
8475076Sgblack@eecs.umich.edu        for param in params:
8487967Sgblack@eecs.umich.edu            param.cxx_decl(code)
8497967Sgblack@eecs.umich.edu        for port in ports.itervalues():
8507967Sgblack@eecs.umich.edu            port.cxx_decl(code)
8515040Sgblack@eecs.umich.edu
8524756Sgblack@eecs.umich.edu        code.dedent()
8536443Sgblack@eecs.umich.edu        code('};')
8545032Sgblack@eecs.umich.edu
8554823Sgblack@eecs.umich.edu        code()
8565040Sgblack@eecs.umich.edu        code('#endif // __PARAMS__${cls}__')
8577967Sgblack@eecs.umich.edu        return code
8587967Sgblack@eecs.umich.edu
8597967Sgblack@eecs.umich.edu    # Generate the C++ declaration/definition files for this SimObject's
8607967Sgblack@eecs.umich.edu    # param struct to allow C++ initialisation
8617967Sgblack@eecs.umich.edu    def cxx_config_param_file(cls, code, is_header):
8627967Sgblack@eecs.umich.edu        createCxxConfigDirectoryEntryFile(code, cls.__name__, cls, is_header)
8635076Sgblack@eecs.umich.edu        return code
8645076Sgblack@eecs.umich.edu
8655076Sgblack@eecs.umich.edu# This *temporary* definition is required to support calls from the
8665076Sgblack@eecs.umich.edu# SimObject class definition to the MetaSimObject methods (in
8675076Sgblack@eecs.umich.edu# particular _set_param, which gets called for parameters with default
8689212Snilay@cs.wisc.edu# values defined on the SimObject class itself).  It will get
8699212Snilay@cs.wisc.edu# overridden by the permanent definition (which requires that
8709010Snilay@cs.wisc.edu# SimObject be defined) lower in this file.
8715076Sgblack@eecs.umich.edudef isSimObjectOrVector(value):
8726444Sgblack@eecs.umich.edu    return False
8736444Sgblack@eecs.umich.edu
8746444Sgblack@eecs.umich.edudef cxxMethod(*args, **kwargs):
8756444Sgblack@eecs.umich.edu    """Decorator to export C++ functions to Python"""
8769212Snilay@cs.wisc.edu
8779212Snilay@cs.wisc.edu    def decorate(func):
8786444Sgblack@eecs.umich.edu        name = func.__name__
8799010Snilay@cs.wisc.edu        override = kwargs.get("override", False)
8805076Sgblack@eecs.umich.edu        cxx_name = kwargs.get("cxx_name", name)
8819212Snilay@cs.wisc.edu
8829212Snilay@cs.wisc.edu        args, varargs, keywords, defaults = inspect.getargspec(func)
8839212Snilay@cs.wisc.edu        if varargs or keywords:
8849212Snilay@cs.wisc.edu            raise ValueError("Wrapped methods must not contain variable " \
8859212Snilay@cs.wisc.edu                             "arguments")
8869212Snilay@cs.wisc.edu
8879212Snilay@cs.wisc.edu        # Create tuples of (argument, default)
8885076Sgblack@eecs.umich.edu        if defaults:
8895076Sgblack@eecs.umich.edu            args = args[:-len(defaults)] + zip(args[-len(defaults):], defaults)
8905040Sgblack@eecs.umich.edu        # Don't include self in the argument list to PyBind
8915076Sgblack@eecs.umich.edu        args = args[1:]
8925040Sgblack@eecs.umich.edu
8934732Sgblack@eecs.umich.edu
8944756Sgblack@eecs.umich.edu        @wraps(func)
8956449Sgblack@eecs.umich.edu        def cxx_call(self, *args, **kwargs):
8967967Sgblack@eecs.umich.edu            ccobj = self.getCCObject()
8976449Sgblack@eecs.umich.edu            return getattr(ccobj, name)(*args, **kwargs)
8986449Sgblack@eecs.umich.edu
8994732Sgblack@eecs.umich.edu        @wraps(func)
9007967Sgblack@eecs.umich.edu        def py_call(self, *args, **kwargs):
9016447Sgblack@eecs.umich.edu            return func(self, *args, **kwargs)
9025040Sgblack@eecs.umich.edu
9035076Sgblack@eecs.umich.edu        f = py_call if override else cxx_call
9045076Sgblack@eecs.umich.edu        f.__pybind = PyBindMethod(name, cxx_name=cxx_name, args=args)
9055076Sgblack@eecs.umich.edu
9065076Sgblack@eecs.umich.edu        return f
9075076Sgblack@eecs.umich.edu
9089212Snilay@cs.wisc.edu    if len(args) == 0:
9099212Snilay@cs.wisc.edu        return decorate
9109010Snilay@cs.wisc.edu    elif len(args) == 1 and len(kwargs) == 0:
9115076Sgblack@eecs.umich.edu        return decorate(*args)
9125076Sgblack@eecs.umich.edu    else:
9135076Sgblack@eecs.umich.edu        raise TypeError("One argument and no kwargs, or only kwargs expected")
9145076Sgblack@eecs.umich.edu
9159010Snilay@cs.wisc.edu# This class holds information about each simobject parameter
9169212Snilay@cs.wisc.edu# that should be displayed on the command line for use in the
9179212Snilay@cs.wisc.edu# configuration system.
9189010Snilay@cs.wisc.educlass ParamInfo(object):
9199010Snilay@cs.wisc.edu  def __init__(self, type, desc, type_str, example, default_val, access_str):
9205076Sgblack@eecs.umich.edu    self.type = type
9215076Sgblack@eecs.umich.edu    self.desc = desc
9229212Snilay@cs.wisc.edu    self.type_str = type_str
9239010Snilay@cs.wisc.edu    self.example_str = example
9245076Sgblack@eecs.umich.edu    self.default_val = default_val
9259212Snilay@cs.wisc.edu    # The string representation used to access this param through python.
9269212Snilay@cs.wisc.edu    # The method to access this parameter presented on the command line may
9279212Snilay@cs.wisc.edu    # be different, so this needs to be stored for later use.
9289212Snilay@cs.wisc.edu    self.access_str = access_str
9299212Snilay@cs.wisc.edu    self.created = True
9309212Snilay@cs.wisc.edu
9319212Snilay@cs.wisc.edu  # Make it so we can only set attributes at initialization time
9325076Sgblack@eecs.umich.edu  # and effectively make this a const object.
9335076Sgblack@eecs.umich.edu  def __setattr__(self, name, value):
9345040Sgblack@eecs.umich.edu    if not "created" in self.__dict__:
9355076Sgblack@eecs.umich.edu      self.__dict__[name] = value
9365040Sgblack@eecs.umich.edu
9374733Sgblack@eecs.umich.educlass SimObjectCliWrapperException(Exception):
9384756Sgblack@eecs.umich.edu    def __init__(self, message):
9396454Sgblack@eecs.umich.edu        super(Exception, self).__init__(message)
9407967Sgblack@eecs.umich.edu
9419010Snilay@cs.wisc.educlass SimObjectCliWrapper(object):
9426454Sgblack@eecs.umich.edu    """
9436454Sgblack@eecs.umich.edu    Wrapper class to restrict operations that may be done
9446454Sgblack@eecs.umich.edu    from the command line on SimObjects.
9456454Sgblack@eecs.umich.edu
9464733Sgblack@eecs.umich.edu    Only parameters may be set, and only children may be accessed.
9477967Sgblack@eecs.umich.edu
9486447Sgblack@eecs.umich.edu    Slicing allows for multiple simultaneous assignment of items in
9495040Sgblack@eecs.umich.edu    one statement.
9505076Sgblack@eecs.umich.edu    """
9515076Sgblack@eecs.umich.edu
9525076Sgblack@eecs.umich.edu    def __init__(self, sim_objects):
9539010Snilay@cs.wisc.edu        self.__dict__['_sim_objects'] = list(sim_objects)
9545076Sgblack@eecs.umich.edu
9555076Sgblack@eecs.umich.edu    def __getattr__(self, key):
9569212Snilay@cs.wisc.edu        return SimObjectCliWrapper(sim_object._children[key]
9579212Snilay@cs.wisc.edu                for sim_object in self._sim_objects)
9589010Snilay@cs.wisc.edu
9595076Sgblack@eecs.umich.edu    def __setattr__(self, key, val):
9606453Sgblack@eecs.umich.edu        for sim_object in self._sim_objects:
9616453Sgblack@eecs.umich.edu            if key in sim_object._params:
9629212Snilay@cs.wisc.edu                if sim_object._params[key].isCmdLineSettable():
9636453Sgblack@eecs.umich.edu                    setattr(sim_object, key, val)
9645076Sgblack@eecs.umich.edu                else:
9656454Sgblack@eecs.umich.edu                    raise SimObjectCliWrapperException(
9666454Sgblack@eecs.umich.edu                            'tried to set or unsettable' \
9676454Sgblack@eecs.umich.edu                            'object parameter: ' + key)
9689212Snilay@cs.wisc.edu            else:
9699212Snilay@cs.wisc.edu                raise SimObjectCliWrapperException(
9706454Sgblack@eecs.umich.edu                            'tried to set or access non-existent' \
9719010Snilay@cs.wisc.edu                            'object parameter: ' + key)
9725076Sgblack@eecs.umich.edu
9739212Snilay@cs.wisc.edu    def __getitem__(self, idx):
9749212Snilay@cs.wisc.edu        """
9759212Snilay@cs.wisc.edu        Extends the list() semantics to also allow tuples,
9769212Snilay@cs.wisc.edu        for example object[1, 3] selects items 1 and 3.
9779212Snilay@cs.wisc.edu        """
9789212Snilay@cs.wisc.edu        out = []
9799212Snilay@cs.wisc.edu        if isinstance(idx, tuple):
9805076Sgblack@eecs.umich.edu            for t in idx:
9815076Sgblack@eecs.umich.edu                out.extend(self[t]._sim_objects)
9825040Sgblack@eecs.umich.edu        else:
9835076Sgblack@eecs.umich.edu            if isinstance(idx, int):
9845040Sgblack@eecs.umich.edu                _range = range(idx, idx + 1)
9854732Sgblack@eecs.umich.edu            elif not isinstance(idx, slice):
9864756Sgblack@eecs.umich.edu                raise SimObjectCliWrapperException( \
9876446Sgblack@eecs.umich.edu                        'invalid index type: ' + repr(idx))
9887967Sgblack@eecs.umich.edu            for sim_object in self._sim_objects:
9896446Sgblack@eecs.umich.edu                if isinstance(idx, slice):
9904732Sgblack@eecs.umich.edu                    _range = range(*idx.indices(len(sim_object)))
9916446Sgblack@eecs.umich.edu                out.extend(sim_object[i] for i in _range)
9924732Sgblack@eecs.umich.edu        return SimObjectCliWrapper(out)
9937967Sgblack@eecs.umich.edu
9946447Sgblack@eecs.umich.edu# The SimObject class is the root of the special hierarchy.  Most of
9955040Sgblack@eecs.umich.edu# the code in this class deals with the configuration hierarchy itself
9965076Sgblack@eecs.umich.edu# (parent/child node relationships).
9975076Sgblack@eecs.umich.educlass SimObject(object):
9985076Sgblack@eecs.umich.edu    # Specify metaclass.  Any class inheriting from SimObject will
9995076Sgblack@eecs.umich.edu    # get this metaclass.
10005076Sgblack@eecs.umich.edu    __metaclass__ = MetaSimObject
10019212Snilay@cs.wisc.edu    type = 'SimObject'
10029212Snilay@cs.wisc.edu    abstract = True
10039010Snilay@cs.wisc.edu
10045076Sgblack@eecs.umich.edu    cxx_header = "sim/sim_object.hh"
10055076Sgblack@eecs.umich.edu    cxx_extra_bases = [ "Drainable", "Serializable" ]
10065076Sgblack@eecs.umich.edu    eventq_index = Param.UInt32(Parent.eventq_index, "Event Queue Index")
10075076Sgblack@eecs.umich.edu
10089010Snilay@cs.wisc.edu    cxx_exports = [
10099212Snilay@cs.wisc.edu        PyBindMethod("init"),
10109212Snilay@cs.wisc.edu        PyBindMethod("initState"),
10119010Snilay@cs.wisc.edu        PyBindMethod("memInvalidate"),
10129010Snilay@cs.wisc.edu        PyBindMethod("memWriteback"),
10135076Sgblack@eecs.umich.edu        PyBindMethod("regStats"),
10145076Sgblack@eecs.umich.edu        PyBindMethod("resetStats"),
10159212Snilay@cs.wisc.edu        PyBindMethod("regProbePoints"),
10169010Snilay@cs.wisc.edu        PyBindMethod("regProbeListeners"),
10175076Sgblack@eecs.umich.edu        PyBindMethod("startup"),
10189212Snilay@cs.wisc.edu    ]
10199212Snilay@cs.wisc.edu
10209212Snilay@cs.wisc.edu    cxx_param_exports = [
10219212Snilay@cs.wisc.edu        PyBindProperty("name"),
10229212Snilay@cs.wisc.edu    ]
10239212Snilay@cs.wisc.edu
10249212Snilay@cs.wisc.edu    @cxxMethod
10255076Sgblack@eecs.umich.edu    def loadState(self, cp):
10265076Sgblack@eecs.umich.edu        """Load SimObject state from a checkpoint"""
10275040Sgblack@eecs.umich.edu        pass
10285076Sgblack@eecs.umich.edu
10295040Sgblack@eecs.umich.edu    # Returns a dict of all the option strings that can be
10304733Sgblack@eecs.umich.edu    # generated as command line options for this simobject instance
10314756Sgblack@eecs.umich.edu    # by tracing all reachable params in the top level instance and
10326456Sgblack@eecs.umich.edu    # any children it contains.
10337967Sgblack@eecs.umich.edu    def enumerateParams(self, flags_dict = {},
10349010Snilay@cs.wisc.edu                        cmd_line_str = "", access_str = ""):
10356456Sgblack@eecs.umich.edu        if hasattr(self, "_paramEnumed"):
10366456Sgblack@eecs.umich.edu            print("Cycle detected enumerating params")
10374733Sgblack@eecs.umich.edu        else:
10384733Sgblack@eecs.umich.edu            self._paramEnumed = True
10394823Sgblack@eecs.umich.edu            # Scan the children first to pick up all the objects in this SimObj
10406456Sgblack@eecs.umich.edu            for keys in self._children:
10414733Sgblack@eecs.umich.edu                child = self._children[keys]
10427967Sgblack@eecs.umich.edu                next_cmdline_str = cmd_line_str + keys
10436447Sgblack@eecs.umich.edu                next_access_str = access_str + keys
10445040Sgblack@eecs.umich.edu                if not isSimObjectVector(child):
10455076Sgblack@eecs.umich.edu                    next_cmdline_str = next_cmdline_str + "."
10465076Sgblack@eecs.umich.edu                    next_access_str = next_access_str + "."
10475076Sgblack@eecs.umich.edu                flags_dict = child.enumerateParams(flags_dict,
10489010Snilay@cs.wisc.edu                                                   next_cmdline_str,
10495076Sgblack@eecs.umich.edu                                                   next_access_str)
10505076Sgblack@eecs.umich.edu
10519212Snilay@cs.wisc.edu            # Go through the simple params in the simobject in this level
10529212Snilay@cs.wisc.edu            # of the simobject hierarchy and save information about the
10539010Snilay@cs.wisc.edu            # parameter to be used for generating and processing command line
10545076Sgblack@eecs.umich.edu            # options to the simulator to set these parameters.
10556456Sgblack@eecs.umich.edu            for keys,values in self._params.items():
10565076Sgblack@eecs.umich.edu                if values.isCmdLineSettable():
105711320Ssteve.reinhardt@amd.com                    type_str = ''
10589010Snilay@cs.wisc.edu                    ex_str = values.example_str()
10599212Snilay@cs.wisc.edu                    ptype = None
10609212Snilay@cs.wisc.edu                    if isinstance(values, VectorParamDesc):
10619010Snilay@cs.wisc.edu                        type_str = 'Vector_%s' % values.ptype_str
10629010Snilay@cs.wisc.edu                        ptype = values
10635076Sgblack@eecs.umich.edu                    else:
10645076Sgblack@eecs.umich.edu                        type_str = '%s' % values.ptype_str
10659212Snilay@cs.wisc.edu                        ptype = values.ptype
10669010Snilay@cs.wisc.edu
10675076Sgblack@eecs.umich.edu                    if keys in self._hr_values\
10689212Snilay@cs.wisc.edu                       and keys in self._values\
10699212Snilay@cs.wisc.edu                       and not isinstance(self._values[keys],
10709212Snilay@cs.wisc.edu                                          m5.proxy.BaseProxy):
10719212Snilay@cs.wisc.edu                        cmd_str = cmd_line_str + keys
10729212Snilay@cs.wisc.edu                        acc_str = access_str + keys
10739212Snilay@cs.wisc.edu                        flags_dict[cmd_str] = ParamInfo(ptype,
10749212Snilay@cs.wisc.edu                                    self._params[keys].desc, type_str, ex_str,
10755076Sgblack@eecs.umich.edu                                    values.pretty_print(self._hr_values[keys]),
10765076Sgblack@eecs.umich.edu                                    acc_str)
10774732Sgblack@eecs.umich.edu                    elif not keys in self._hr_values\
10786479Sgblack@eecs.umich.edu                         and not keys in self._values:
10797967Sgblack@eecs.umich.edu                        # Empty param
10806479Sgblack@eecs.umich.edu                        cmd_str = cmd_line_str + keys
10816479Sgblack@eecs.umich.edu                        acc_str = access_str + keys
10827967Sgblack@eecs.umich.edu                        flags_dict[cmd_str] = ParamInfo(ptype,
10836479Sgblack@eecs.umich.edu                                    self._params[keys].desc,
10846479Sgblack@eecs.umich.edu                                    type_str, ex_str, '', acc_str)
10856479Sgblack@eecs.umich.edu
10866479Sgblack@eecs.umich.edu        return flags_dict
10876479Sgblack@eecs.umich.edu
10886479Sgblack@eecs.umich.edu    # Initialize new instance.  For objects with SimObject-valued
10896479Sgblack@eecs.umich.edu    # children, we need to recursively clone the classes represented
10906479Sgblack@eecs.umich.edu    # by those param values as well in a consistent "deep copy"-style
10916479Sgblack@eecs.umich.edu    # fashion.  That is, we want to make sure that each instance is
10926479Sgblack@eecs.umich.edu    # cloned only once, and that if there are multiple references to
10937967Sgblack@eecs.umich.edu    # the same original object, we end up with the corresponding
10946479Sgblack@eecs.umich.edu    # cloned references all pointing to the same cloned instance.
10957967Sgblack@eecs.umich.edu    def __init__(self, **kwargs):
10967967Sgblack@eecs.umich.edu        ancestor = kwargs.get('_ancestor')
10976479Sgblack@eecs.umich.edu        memo_dict = kwargs.get('_memo')
10986479Sgblack@eecs.umich.edu        if memo_dict is None:
10996479Sgblack@eecs.umich.edu            # prepare to memoize any recursively instantiated objects
11006479Sgblack@eecs.umich.edu            memo_dict = {}
11016479Sgblack@eecs.umich.edu        elif ancestor:
11029212Snilay@cs.wisc.edu            # memoize me now to avoid problems with recursive calls
11039212Snilay@cs.wisc.edu            memo_dict[ancestor] = self
11046479Sgblack@eecs.umich.edu
11059010Snilay@cs.wisc.edu        if not ancestor:
11066479Sgblack@eecs.umich.edu            ancestor = self.__class__
11076479Sgblack@eecs.umich.edu        ancestor._instantiated = True
11086479Sgblack@eecs.umich.edu
11096479Sgblack@eecs.umich.edu        # initialize required attributes
11106479Sgblack@eecs.umich.edu        self._parent = None
11116479Sgblack@eecs.umich.edu        self._name = None
11126479Sgblack@eecs.umich.edu        self._ccObject = None  # pointer to C++ object
11136479Sgblack@eecs.umich.edu        self._ccParams = None
11146479Sgblack@eecs.umich.edu        self._instantiated = False # really "cloned"
11159010Snilay@cs.wisc.edu
11166479Sgblack@eecs.umich.edu        # Clone children specified at class level.  No need for a
11179010Snilay@cs.wisc.edu        # multidict here since we will be cloning everything.
11189212Snilay@cs.wisc.edu        # Do children before parameter values so that children that
11199212Snilay@cs.wisc.edu        # are also param values get cloned properly.
11209010Snilay@cs.wisc.edu        self._children = {}
11219010Snilay@cs.wisc.edu        for key,val in ancestor._children.iteritems():
11226479Sgblack@eecs.umich.edu            self.add_child(key, val(_memo=memo_dict))
11236479Sgblack@eecs.umich.edu
11246479Sgblack@eecs.umich.edu        # Inherit parameter values from class using multidict so
11259212Snilay@cs.wisc.edu        # individual value settings can be overridden but we still
11269010Snilay@cs.wisc.edu        # inherit late changes to non-overridden class values.
11276479Sgblack@eecs.umich.edu        self._values = multidict(ancestor._values)
11289212Snilay@cs.wisc.edu        self._hr_values = multidict(ancestor._hr_values)
11299212Snilay@cs.wisc.edu        # clone SimObject-valued parameters
11309212Snilay@cs.wisc.edu        for key,val in ancestor._values.iteritems():
11319212Snilay@cs.wisc.edu            val = tryAsSimObjectOrVector(val)
11329212Snilay@cs.wisc.edu            if val is not None:
11339212Snilay@cs.wisc.edu                self._values[key] = val(_memo=memo_dict)
11349212Snilay@cs.wisc.edu
11356479Sgblack@eecs.umich.edu        # clone port references.  no need to use a multidict here
11366479Sgblack@eecs.umich.edu        # since we will be creating new references for all ports.
11376479Sgblack@eecs.umich.edu        self._port_refs = {}
11386479Sgblack@eecs.umich.edu        for key,val in ancestor._port_refs.iteritems():
11397967Sgblack@eecs.umich.edu            self._port_refs[key] = val.clone(self, memo_dict)
11406479Sgblack@eecs.umich.edu        # apply attribute assignments from keyword args, if any
11416479Sgblack@eecs.umich.edu        for key,val in kwargs.iteritems():
11427967Sgblack@eecs.umich.edu            setattr(self, key, val)
11436479Sgblack@eecs.umich.edu
11446479Sgblack@eecs.umich.edu    # "Clone" the current instance by creating another instance of
11456479Sgblack@eecs.umich.edu    # this instance's class, but that inherits its parameter values
11466479Sgblack@eecs.umich.edu    # and port mappings from the current instance.  If we're in a
11476479Sgblack@eecs.umich.edu    # "deep copy" recursive clone, check the _memo dict to see if
11486479Sgblack@eecs.umich.edu    # we've already cloned this instance.
11496479Sgblack@eecs.umich.edu    def __call__(self, **kwargs):
11506479Sgblack@eecs.umich.edu        memo_dict = kwargs.get('_memo')
11516479Sgblack@eecs.umich.edu        if memo_dict is None:
11526479Sgblack@eecs.umich.edu            # no memo_dict: must be top-level clone operation.
11536479Sgblack@eecs.umich.edu            # this is only allowed at the root of a hierarchy
11546479Sgblack@eecs.umich.edu            if self._parent:
11556479Sgblack@eecs.umich.edu                raise RuntimeError("attempt to clone object %s " \
11566479Sgblack@eecs.umich.edu                      "not at the root of a tree (parent = %s)" \
11576479Sgblack@eecs.umich.edu                      % (self, self._parent))
11586479Sgblack@eecs.umich.edu            # create a new dict and use that.
11597967Sgblack@eecs.umich.edu            memo_dict = {}
11606479Sgblack@eecs.umich.edu            kwargs['_memo'] = memo_dict
11617967Sgblack@eecs.umich.edu        elif self in memo_dict:
11627967Sgblack@eecs.umich.edu            # clone already done & memoized
11636479Sgblack@eecs.umich.edu            return memo_dict[self]
11646479Sgblack@eecs.umich.edu        return self.__class__(_ancestor = self, **kwargs)
11656479Sgblack@eecs.umich.edu
11666479Sgblack@eecs.umich.edu    def _get_port_ref(self, attr):
11676479Sgblack@eecs.umich.edu        # Return reference that can be assigned to another port
11689212Snilay@cs.wisc.edu        # via __setattr__.  There is only ever one reference
11699212Snilay@cs.wisc.edu        # object per port, but we create them lazily here.
11706479Sgblack@eecs.umich.edu        ref = self._port_refs.get(attr)
11719010Snilay@cs.wisc.edu        if ref == None:
11726479Sgblack@eecs.umich.edu            ref = self._ports[attr].makeRef(self)
11736479Sgblack@eecs.umich.edu            self._port_refs[attr] = ref
11746479Sgblack@eecs.umich.edu        return ref
11756479Sgblack@eecs.umich.edu
11766479Sgblack@eecs.umich.edu    def __getattr__(self, attr):
11776479Sgblack@eecs.umich.edu        if attr in self._ports:
11786479Sgblack@eecs.umich.edu            return self._get_port_ref(attr)
11796479Sgblack@eecs.umich.edu
11806479Sgblack@eecs.umich.edu        if attr in self._values:
11819010Snilay@cs.wisc.edu            return self._values[attr]
11826479Sgblack@eecs.umich.edu
11839010Snilay@cs.wisc.edu        if attr in self._children:
11849212Snilay@cs.wisc.edu            return self._children[attr]
11859212Snilay@cs.wisc.edu
11869010Snilay@cs.wisc.edu        # If the attribute exists on the C++ object, transparently
11879010Snilay@cs.wisc.edu        # forward the reference there.  This is typically used for
11886479Sgblack@eecs.umich.edu        # methods exported to Python (e.g., init(), and startup())
11896479Sgblack@eecs.umich.edu        if self._ccObject and hasattr(self._ccObject, attr):
11906479Sgblack@eecs.umich.edu            return getattr(self._ccObject, attr)
11919212Snilay@cs.wisc.edu
11929010Snilay@cs.wisc.edu        err_string = "object '%s' has no attribute '%s'" \
11936479Sgblack@eecs.umich.edu              % (self.__class__.__name__, attr)
11949212Snilay@cs.wisc.edu
11959212Snilay@cs.wisc.edu        if not self._ccObject:
11969212Snilay@cs.wisc.edu            err_string += "\n  (C++ object is not yet constructed," \
11979212Snilay@cs.wisc.edu                          " so wrapped C++ methods are unavailable.)"
11989212Snilay@cs.wisc.edu
11999212Snilay@cs.wisc.edu        raise AttributeError(err_string)
12009212Snilay@cs.wisc.edu
12016479Sgblack@eecs.umich.edu    # Set attribute (called on foo.attr = value when foo is an
12026479Sgblack@eecs.umich.edu    # instance of class cls).
12036479Sgblack@eecs.umich.edu    def __setattr__(self, attr, value):
12046479Sgblack@eecs.umich.edu        # normal processing for private attributes
12056479Sgblack@eecs.umich.edu        if attr.startswith('_'):
12066479Sgblack@eecs.umich.edu            object.__setattr__(self, attr, value)
12075040Sgblack@eecs.umich.edu            return
12087789Sgblack@eecs.umich.edu
12097789Sgblack@eecs.umich.edu        if attr in self._ports:
12105040Sgblack@eecs.umich.edu            # set up port connection
12115040Sgblack@eecs.umich.edu            self._get_port_ref(attr).connect(value)
12129010Snilay@cs.wisc.edu            return
12139010Snilay@cs.wisc.edu
12149010Snilay@cs.wisc.edu        param = self._params.get(attr)
12159010Snilay@cs.wisc.edu        if param:
12169010Snilay@cs.wisc.edu            try:
12179211Snilay@cs.wisc.edu                hr_value = value
12189010Snilay@cs.wisc.edu                value = param.convert(value)
12199010Snilay@cs.wisc.edu            except Exception as e:
12205040Sgblack@eecs.umich.edu                msg = "%s\nError setting param %s.%s to %s\n" % \
12215426Sgblack@eecs.umich.edu                      (e, self.__class__.__name__, attr, value)
12225426Sgblack@eecs.umich.edu                e.args = (msg, )
12235426Sgblack@eecs.umich.edu                raise
12245426Sgblack@eecs.umich.edu            self._values[attr] = value
12259010Snilay@cs.wisc.edu            # implicitly parent unparented objects assigned as params
12265426Sgblack@eecs.umich.edu            if isSimObjectOrVector(value) and not value.has_parent():
12279010Snilay@cs.wisc.edu                self.add_child(attr, value)
12289211Snilay@cs.wisc.edu            # set the human-readable value dict if this is a param
12299010Snilay@cs.wisc.edu            # with a literal value and is not being set as an object
12309010Snilay@cs.wisc.edu            # or proxy.
12319010Snilay@cs.wisc.edu            if not (isSimObjectOrVector(value) or\
12329010Snilay@cs.wisc.edu                    isinstance(value, m5.proxy.BaseProxy)):
12335426Sgblack@eecs.umich.edu                self._hr_values[attr] = hr_value
12345426Sgblack@eecs.umich.edu
12355426Sgblack@eecs.umich.edu            return
12365426Sgblack@eecs.umich.edu
12375040Sgblack@eecs.umich.edu        # if RHS is a SimObject, it's an implicit child assignment
12387789Sgblack@eecs.umich.edu        if isSimObjectOrSequence(value):
12395040Sgblack@eecs.umich.edu            self.add_child(attr, value)
12405040Sgblack@eecs.umich.edu            return
12419211Snilay@cs.wisc.edu
12425040Sgblack@eecs.umich.edu        # no valid assignment... raise exception
12435426Sgblack@eecs.umich.edu        raise AttributeError("Class %s has no parameter %s" \
12449010Snilay@cs.wisc.edu              % (self.__class__.__name__, attr))
12459211Snilay@cs.wisc.edu
12469211Snilay@cs.wisc.edu
12479010Snilay@cs.wisc.edu    # this hack allows tacking a '[0]' onto parameters that may or may
12485426Sgblack@eecs.umich.edu    # not be vectors, and always getting the first element (e.g. cpus)
12495040Sgblack@eecs.umich.edu    def __getitem__(self, key):
12505040Sgblack@eecs.umich.edu        if key == 0:
12519211Snilay@cs.wisc.edu            return self
12529211Snilay@cs.wisc.edu        raise IndexError("Non-zero index '%s' to SimObject" % key)
12534951Sgblack@eecs.umich.edu
12549010Snilay@cs.wisc.edu    # this hack allows us to iterate over a SimObject that may
12555040Sgblack@eecs.umich.edu    # not be a vector, so we can call a loop over it and get just one
12569010Snilay@cs.wisc.edu    # element.
12577967Sgblack@eecs.umich.edu    def __len__(self):
12589211Snilay@cs.wisc.edu        return 1
12599211Snilay@cs.wisc.edu
12607967Sgblack@eecs.umich.edu    # Also implemented by SimObjectVector
12619010Snilay@cs.wisc.edu    def clear_parent(self, old_parent):
12627967Sgblack@eecs.umich.edu        assert self._parent is old_parent
12639010Snilay@cs.wisc.edu        self._parent = None
12645040Sgblack@eecs.umich.edu
12655040Sgblack@eecs.umich.edu    # Also implemented by SimObjectVector
12665040Sgblack@eecs.umich.edu    def set_parent(self, parent, name):
12676345Sgblack@eecs.umich.edu        self._parent = parent
12684732Sgblack@eecs.umich.edu        self._name = name
12695426Sgblack@eecs.umich.edu
12705426Sgblack@eecs.umich.edu    # Return parent object of this SimObject, not implemented by
12715426Sgblack@eecs.umich.edu    # SimObjectVector because the elements in a SimObjectVector may not share
12729211Snilay@cs.wisc.edu    # the same parent
12739010Snilay@cs.wisc.edu    def get_parent(self):
12749010Snilay@cs.wisc.edu        return self._parent
12755426Sgblack@eecs.umich.edu
12765426Sgblack@eecs.umich.edu    # Also implemented by SimObjectVector
12779010Snilay@cs.wisc.edu    def get_name(self):
12785426Sgblack@eecs.umich.edu        return self._name
12799010Snilay@cs.wisc.edu
12807967Sgblack@eecs.umich.edu    # Also implemented by SimObjectVector
12817967Sgblack@eecs.umich.edu    def has_parent(self):
12829211Snilay@cs.wisc.edu        return self._parent is not None
12839010Snilay@cs.wisc.edu
12849010Snilay@cs.wisc.edu    # clear out child with given name. This code is not likely to be exercised.
12857967Sgblack@eecs.umich.edu    # See comment in add_child.
12867967Sgblack@eecs.umich.edu    def clear_child(self, name):
12879010Snilay@cs.wisc.edu        child = self._children[name]
12887967Sgblack@eecs.umich.edu        child.clear_parent(self)
12899010Snilay@cs.wisc.edu        del self._children[name]
12905426Sgblack@eecs.umich.edu
12915426Sgblack@eecs.umich.edu    # Add a new child to this object.
12925426Sgblack@eecs.umich.edu    def add_child(self, name, child):
12936345Sgblack@eecs.umich.edu        child = coerceSimObjectOrVector(child)
12945426Sgblack@eecs.umich.edu        if child.has_parent():
12955040Sgblack@eecs.umich.edu            warn("add_child('%s'): child '%s' already has parent", name,
12965040Sgblack@eecs.umich.edu                child.get_name())
12974823Sgblack@eecs.umich.edu        if name in self._children:
12985239Sgblack@eecs.umich.edu            # This code path had an undiscovered bug that would make it fail
12995239Sgblack@eecs.umich.edu            # at runtime. It had been here for a long time and was only
13005239Sgblack@eecs.umich.edu            # exposed by a buggy script. Changes here will probably not be
13015239Sgblack@eecs.umich.edu            # exercised without specialized testing.
13025007Sgblack@eecs.umich.edu            self.clear_child(name)
13035007Sgblack@eecs.umich.edu        child.set_parent(self, name)
13045040Sgblack@eecs.umich.edu        if not isNullPointer(child):
13059010Snilay@cs.wisc.edu            self._children[name] = child
13067967Sgblack@eecs.umich.edu
13077967Sgblack@eecs.umich.edu    # Take SimObject-valued parameters that haven't been explicitly
13087967Sgblack@eecs.umich.edu    # assigned as children and make them children of the object that
13097967Sgblack@eecs.umich.edu    # they were assigned to as a parameter value.  This guarantees
13107967Sgblack@eecs.umich.edu    # that when we instantiate all the parameter objects we're still
13117967Sgblack@eecs.umich.edu    # inside the configuration hierarchy.
13127967Sgblack@eecs.umich.edu    def adoptOrphanParams(self):
13137967Sgblack@eecs.umich.edu        for key,val in self._values.iteritems():
13147967Sgblack@eecs.umich.edu            if not isSimObjectVector(val) and isSimObjectSequence(val):
13159010Snilay@cs.wisc.edu                # need to convert raw SimObject sequences to
13165239Sgblack@eecs.umich.edu                # SimObjectVector class so we can call has_parent()
13179010Snilay@cs.wisc.edu                val = SimObjectVector(val)
13189212Snilay@cs.wisc.edu                self._values[key] = val
13199212Snilay@cs.wisc.edu            if isSimObjectOrVector(val) and not val.has_parent():
13209212Snilay@cs.wisc.edu                warn("%s adopting orphan SimObject param '%s'", self, key)
13219212Snilay@cs.wisc.edu                self.add_child(key, val)
13229010Snilay@cs.wisc.edu
13239212Snilay@cs.wisc.edu    def path(self):
13249212Snilay@cs.wisc.edu        if not self._parent:
13259212Snilay@cs.wisc.edu            return '<orphan %s>' % self.__class__
13269212Snilay@cs.wisc.edu        elif isinstance(self._parent, MetaSimObject):
13279010Snilay@cs.wisc.edu            return str(self.__class__)
13285239Sgblack@eecs.umich.edu
13294714Sgblack@eecs.umich.edu        ppath = self._parent.path()
13305040Sgblack@eecs.umich.edu        if ppath == 'root':
13315927Sgblack@eecs.umich.edu            return self._name
13327967Sgblack@eecs.umich.edu        return ppath + "." + self._name
13335241Sgblack@eecs.umich.edu
13345926Sgblack@eecs.umich.edu    def __str__(self):
13355926Sgblack@eecs.umich.edu        return self.path()
13365926Sgblack@eecs.umich.edu
13376345Sgblack@eecs.umich.edu    def config_value(self):
13387967Sgblack@eecs.umich.edu        return self.path()
13395926Sgblack@eecs.umich.edu
13405926Sgblack@eecs.umich.edu    def ini_str(self):
13415926Sgblack@eecs.umich.edu        return self.path()
134210474Sandreas.hansson@arm.com
13435926Sgblack@eecs.umich.edu    def find_any(self, ptype):
134410474Sandreas.hansson@arm.com        if isinstance(self, ptype):
13455926Sgblack@eecs.umich.edu            return self, True
13467967Sgblack@eecs.umich.edu
13475926Sgblack@eecs.umich.edu        found_obj = None
13485926Sgblack@eecs.umich.edu        for child in self._children.itervalues():
13497967Sgblack@eecs.umich.edu            visited = False
13507967Sgblack@eecs.umich.edu            if hasattr(child, '_visited'):
13515926Sgblack@eecs.umich.edu              visited = getattr(child, '_visited')
13525926Sgblack@eecs.umich.edu
13535926Sgblack@eecs.umich.edu            if isinstance(child, ptype) and not visited:
13545926Sgblack@eecs.umich.edu                if found_obj != None and child != found_obj:
13556345Sgblack@eecs.umich.edu                    raise AttributeError(
13565926Sgblack@eecs.umich.edu                          'parent.any matched more than one: %s %s' % \
13575926Sgblack@eecs.umich.edu                          (found_obj.path, child.path))
13585926Sgblack@eecs.umich.edu                found_obj = child
13595926Sgblack@eecs.umich.edu        # search param space
136010474Sandreas.hansson@arm.com        for pname,pdesc in self._params.iteritems():
13616345Sgblack@eecs.umich.edu            if issubclass(pdesc.ptype, ptype):
13625926Sgblack@eecs.umich.edu                match_obj = self._values[pname]
136310474Sandreas.hansson@arm.com                if found_obj != None and found_obj != match_obj:
13645926Sgblack@eecs.umich.edu                    raise AttributeError(
136510474Sandreas.hansson@arm.com                          'parent.any matched more than one: %s and %s' % \
13665926Sgblack@eecs.umich.edu                          (found_obj.path, match_obj.path))
13675926Sgblack@eecs.umich.edu                found_obj = match_obj
13685926Sgblack@eecs.umich.edu        return found_obj, found_obj != None
13695926Sgblack@eecs.umich.edu
13705926Sgblack@eecs.umich.edu    def find_all(self, ptype):
13715296Sgblack@eecs.umich.edu        all = {}
13725296Sgblack@eecs.umich.edu        # search children
13735296Sgblack@eecs.umich.edu        for child in self._children.itervalues():
13746345Sgblack@eecs.umich.edu            # a child could be a list, so ensure we visit each item
13757967Sgblack@eecs.umich.edu            if isinstance(child, list):
13765924Sgblack@eecs.umich.edu                children = child
137710474Sandreas.hansson@arm.com            else:
13785296Sgblack@eecs.umich.edu                children = [child]
13797967Sgblack@eecs.umich.edu
13805296Sgblack@eecs.umich.edu            for child in children:
13815296Sgblack@eecs.umich.edu                if isinstance(child, ptype) and not isproxy(child) and \
13827967Sgblack@eecs.umich.edu                        not isNullPointer(child):
13837967Sgblack@eecs.umich.edu                    all[child] = True
13845296Sgblack@eecs.umich.edu                if isSimObject(child):
13855241Sgblack@eecs.umich.edu                    # also add results from the child itself
13865241Sgblack@eecs.umich.edu                    child_all, done = child.find_all(ptype)
13875241Sgblack@eecs.umich.edu                    all.update(dict(zip(child_all, [done] * len(child_all))))
13886345Sgblack@eecs.umich.edu        # search param space
13895241Sgblack@eecs.umich.edu        for pname,pdesc in self._params.iteritems():
13905241Sgblack@eecs.umich.edu            if issubclass(pdesc.ptype, ptype):
139110474Sandreas.hansson@arm.com                match_obj = self._values[pname]
13925241Sgblack@eecs.umich.edu                if not isproxy(match_obj) and not isNullPointer(match_obj):
13935241Sgblack@eecs.umich.edu                    all[match_obj] = True
13945241Sgblack@eecs.umich.edu        # Also make sure to sort the keys based on the objects' path to
13955241Sgblack@eecs.umich.edu        # ensure that the order is the same on all hosts
13965241Sgblack@eecs.umich.edu        return sorted(all.keys(), key = lambda o: o.path()), True
13975241Sgblack@eecs.umich.edu
13985241Sgblack@eecs.umich.edu    def unproxy(self, base):
13995241Sgblack@eecs.umich.edu        return self
14005241Sgblack@eecs.umich.edu
14015241Sgblack@eecs.umich.edu    def unproxyParams(self):
14025241Sgblack@eecs.umich.edu        for param in self._params.iterkeys():
14035241Sgblack@eecs.umich.edu            value = self._values.get(param)
14045241Sgblack@eecs.umich.edu            if value != None and isproxy(value):
14055241Sgblack@eecs.umich.edu                try:
14065241Sgblack@eecs.umich.edu                    value = value.unproxy(self)
14075241Sgblack@eecs.umich.edu                except:
14085241Sgblack@eecs.umich.edu                    print("Error in unproxying param '%s' of %s" %
140910474Sandreas.hansson@arm.com                          (param, self.path()))
14105241Sgblack@eecs.umich.edu                    raise
14115241Sgblack@eecs.umich.edu                setattr(self, param, value)
14125241Sgblack@eecs.umich.edu
14135241Sgblack@eecs.umich.edu        # Unproxy ports in sorted order so that 'append' operations on
14145241Sgblack@eecs.umich.edu        # vector ports are done in a deterministic fashion.
14155241Sgblack@eecs.umich.edu        port_names = self._ports.keys()
14165241Sgblack@eecs.umich.edu        port_names.sort()
14175241Sgblack@eecs.umich.edu        for port_name in port_names:
14185241Sgblack@eecs.umich.edu            port = self._port_refs.get(port_name)
14195241Sgblack@eecs.umich.edu            if port != None:
14205241Sgblack@eecs.umich.edu                port.unproxy(self)
14215241Sgblack@eecs.umich.edu
142210474Sandreas.hansson@arm.com    def print_ini(self, ini_file):
14235241Sgblack@eecs.umich.edu        print('[' + self.path() + ']', file=ini_file)    # .ini section header
14245241Sgblack@eecs.umich.edu
14255241Sgblack@eecs.umich.edu        instanceDict[self.path()] = self
14265241Sgblack@eecs.umich.edu
14275241Sgblack@eecs.umich.edu        if hasattr(self, 'type'):
142810474Sandreas.hansson@arm.com            print('type=%s' % self.type, file=ini_file)
14295241Sgblack@eecs.umich.edu
14305241Sgblack@eecs.umich.edu        if len(self._children.keys()):
143110474Sandreas.hansson@arm.com            print('children=%s' %
14328857Sgblack@eecs.umich.edu                  ' '.join(self._children[n].get_name()
14335241Sgblack@eecs.umich.edu                           for n in sorted(self._children.keys())),
14345241Sgblack@eecs.umich.edu                  file=ini_file)
14355241Sgblack@eecs.umich.edu
14365241Sgblack@eecs.umich.edu        for param in sorted(self._params.keys()):
14375290Sgblack@eecs.umich.edu            value = self._values.get(param)
14385294Sgblack@eecs.umich.edu            if value != None:
14395672Sgblack@eecs.umich.edu                print('%s=%s' % (param, self._values[param].ini_str()),
14405294Sgblack@eecs.umich.edu                      file=ini_file)
14415290Sgblack@eecs.umich.edu
14425294Sgblack@eecs.umich.edu        for port_name in sorted(self._ports.keys()):
14436345Sgblack@eecs.umich.edu            port = self._port_refs.get(port_name, None)
14445294Sgblack@eecs.umich.edu            if port != None:
14455294Sgblack@eecs.umich.edu                print('%s=%s' % (port_name, port.ini_str()), file=ini_file)
14465290Sgblack@eecs.umich.edu
14475294Sgblack@eecs.umich.edu        print(file=ini_file)        # blank line between objects
14485290Sgblack@eecs.umich.edu
14495290Sgblack@eecs.umich.edu    # generate a tree of dictionaries expressing all the parameters in the
14505294Sgblack@eecs.umich.edu    # instantiated system for use by scripts that want to do power, thermal
14515290Sgblack@eecs.umich.edu    # visualization, and other similar tasks
14525294Sgblack@eecs.umich.edu    def get_config_as_dict(self):
14535294Sgblack@eecs.umich.edu        d = attrdict()
14545294Sgblack@eecs.umich.edu        if hasattr(self, 'type'):
14555294Sgblack@eecs.umich.edu            d.type = self.type
14565294Sgblack@eecs.umich.edu        if hasattr(self, 'cxx_class'):
14575294Sgblack@eecs.umich.edu            d.cxx_class = self.cxx_class
14585294Sgblack@eecs.umich.edu        # Add the name and path of this object to be able to link to
14595294Sgblack@eecs.umich.edu        # the stats
14605905Sgblack@eecs.umich.edu        d.name = self.get_name()
14615905Sgblack@eecs.umich.edu        d.path = self.path()
14625905Sgblack@eecs.umich.edu
14635905Sgblack@eecs.umich.edu        for param in sorted(self._params.keys()):
14645905Sgblack@eecs.umich.edu            value = self._values.get(param)
14655294Sgblack@eecs.umich.edu            if value != None:
14667967Sgblack@eecs.umich.edu                d[param] = value.config_value()
14677967Sgblack@eecs.umich.edu
14685294Sgblack@eecs.umich.edu        for n in sorted(self._children.keys()):
14695294Sgblack@eecs.umich.edu            child = self._children[n]
14707967Sgblack@eecs.umich.edu            # Use the name of the attribute (and not get_name()) as
14717967Sgblack@eecs.umich.edu            # the key in the JSON dictionary to capture the hierarchy
14725294Sgblack@eecs.umich.edu            # in the Python code that assembled this system
14735427Sgblack@eecs.umich.edu            d[n] = child.get_config_as_dict()
14747967Sgblack@eecs.umich.edu
14757967Sgblack@eecs.umich.edu        for port_name in sorted(self._ports.keys()):
14765427Sgblack@eecs.umich.edu            port = self._port_refs.get(port_name, None)
14775294Sgblack@eecs.umich.edu            if port != None:
14787967Sgblack@eecs.umich.edu                # Represent each port with a dictionary containing the
14797967Sgblack@eecs.umich.edu                # prominent attributes
14805294Sgblack@eecs.umich.edu                d[port_name] = port.get_config_as_dict()
14815682Sgblack@eecs.umich.edu
14825682Sgblack@eecs.umich.edu        return d
14836345Sgblack@eecs.umich.edu
14846345Sgblack@eecs.umich.edu    def getCCParams(self):
14855682Sgblack@eecs.umich.edu        if self._ccParams:
14865682Sgblack@eecs.umich.edu            return self._ccParams
14875682Sgblack@eecs.umich.edu
14885682Sgblack@eecs.umich.edu        cc_params_struct = getattr(m5.internal.params, '%sParams' % self.type)
14895682Sgblack@eecs.umich.edu        cc_params = cc_params_struct()
14905682Sgblack@eecs.umich.edu        cc_params.name = str(self)
14916345Sgblack@eecs.umich.edu
14926345Sgblack@eecs.umich.edu        param_names = self._params.keys()
14935682Sgblack@eecs.umich.edu        param_names.sort()
14945682Sgblack@eecs.umich.edu        for param in param_names:
14955682Sgblack@eecs.umich.edu            value = self._values.get(param)
14965682Sgblack@eecs.umich.edu            if value is None:
14975428Sgblack@eecs.umich.edu                fatal("%s.%s without default or user set value",
14985428Sgblack@eecs.umich.edu                      self.path(), param)
14995428Sgblack@eecs.umich.edu
15005428Sgblack@eecs.umich.edu            value = value.getValue()
15015428Sgblack@eecs.umich.edu            if isinstance(self._params[param], VectorParamDesc):
15025294Sgblack@eecs.umich.edu                assert isinstance(value, list)
15035424Sgblack@eecs.umich.edu                vec = getattr(cc_params, param)
15045433Sgblack@eecs.umich.edu                assert not len(vec)
15055433Sgblack@eecs.umich.edu                # Some types are exposed as opaque types. They support
15065433Sgblack@eecs.umich.edu                # the append operation unlike the automatically
15075294Sgblack@eecs.umich.edu                # wrapped types.
15085428Sgblack@eecs.umich.edu                if isinstance(vec, list):
15095428Sgblack@eecs.umich.edu                    setattr(cc_params, param, list(value))
15105428Sgblack@eecs.umich.edu                else:
15115428Sgblack@eecs.umich.edu                    for v in value:
15125428Sgblack@eecs.umich.edu                        getattr(cc_params, param).append(v)
15136060Sgblack@eecs.umich.edu            else:
15146060Sgblack@eecs.umich.edu                setattr(cc_params, param, value)
151510474Sandreas.hansson@arm.com
15166060Sgblack@eecs.umich.edu        port_names = self._ports.keys()
151710474Sandreas.hansson@arm.com        port_names.sort()
15186060Sgblack@eecs.umich.edu        for port_name in port_names:
15195428Sgblack@eecs.umich.edu            port = self._port_refs.get(port_name, None)
15205428Sgblack@eecs.umich.edu            if port != None:
152110474Sandreas.hansson@arm.com                port_count = len(port)
152210474Sandreas.hansson@arm.com            else:
15238857Sgblack@eecs.umich.edu                port_count = 0
15245428Sgblack@eecs.umich.edu            setattr(cc_params, 'port_' + port_name + '_connection_count',
15255855Sgblack@eecs.umich.edu                    port_count)
15265853Sgblack@eecs.umich.edu        self._ccParams = cc_params
15275674Sgblack@eecs.umich.edu        return self._ccParams
152810474Sandreas.hansson@arm.com
15296058Sgblack@eecs.umich.edu    # Get C++ object corresponding to this object, calling C++ if
15305674Sgblack@eecs.umich.edu    # necessary to construct it.  Does *not* recursively create
15315855Sgblack@eecs.umich.edu    # children.
15325855Sgblack@eecs.umich.edu    def getCCObject(self):
15335853Sgblack@eecs.umich.edu        if not self._ccObject:
15345861Snate@binkert.org            # Make sure this object is in the configuration hierarchy
15355853Sgblack@eecs.umich.edu            if not self._parent and not isRoot(self):
153610474Sandreas.hansson@arm.com                raise RuntimeError("Attempt to instantiate orphan node")
15375853Sgblack@eecs.umich.edu            # Cycles in the configuration hierarchy are not supported. This
15385674Sgblack@eecs.umich.edu            # will catch the resulting recursion and stop.
15395428Sgblack@eecs.umich.edu            self._ccObject = -1
15405433Sgblack@eecs.umich.edu            if not self.abstract:
15415433Sgblack@eecs.umich.edu                params = self.getCCParams()
154210474Sandreas.hansson@arm.com                self._ccObject = params.create()
15438626Sgblack@eecs.umich.edu        elif self._ccObject == -1:
15448626Sgblack@eecs.umich.edu            raise RuntimeError("%s: Cycle found in configuration hierarchy." \
15455433Sgblack@eecs.umich.edu                  % self.path())
15465433Sgblack@eecs.umich.edu        return self._ccObject
154710474Sandreas.hansson@arm.com
15485433Sgblack@eecs.umich.edu    def descendants(self):
15498626Sgblack@eecs.umich.edu        yield self
15508626Sgblack@eecs.umich.edu        # The order of the dict is implementation dependent, so sort
155110474Sandreas.hansson@arm.com        # it based on the key (name) to ensure the order is the same
15525433Sgblack@eecs.umich.edu        # on all hosts
15535428Sgblack@eecs.umich.edu        for (name, child) in sorted(self._children.iteritems()):
15545428Sgblack@eecs.umich.edu            for obj in child.descendants():
15555428Sgblack@eecs.umich.edu                yield obj
15565433Sgblack@eecs.umich.edu
15575433Sgblack@eecs.umich.edu    # Call C++ to create C++ object corresponding to this object
15585433Sgblack@eecs.umich.edu    def createCCObject(self):
15595433Sgblack@eecs.umich.edu        self.getCCParams()
15605679Sgblack@eecs.umich.edu        self.getCCObject() # force creation
156110474Sandreas.hansson@arm.com
15625679Sgblack@eecs.umich.edu    def getValue(self):
156310474Sandreas.hansson@arm.com        return self.getCCObject()
15645679Sgblack@eecs.umich.edu
15655428Sgblack@eecs.umich.edu    # Create C++ port connections corresponding to the connections in
15665428Sgblack@eecs.umich.edu    # _port_refs
15675428Sgblack@eecs.umich.edu    def connectPorts(self):
15685675Sgblack@eecs.umich.edu        # Sort the ports based on their attribute name to ensure the
15695675Sgblack@eecs.umich.edu        # order is the same on all hosts
157010474Sandreas.hansson@arm.com        for (attr, portRef) in sorted(self._port_refs.iteritems()):
15715675Sgblack@eecs.umich.edu            portRef.ccConnect()
15725675Sgblack@eecs.umich.edu
157310474Sandreas.hansson@arm.com    # Default function for generating the device structure.
157410474Sandreas.hansson@arm.com    # Can be overloaded by the inheriting class
15758857Sgblack@eecs.umich.edu    def generateDeviceTree(self, state):
15765675Sgblack@eecs.umich.edu        return # return without yielding anything
15775428Sgblack@eecs.umich.edu        yield  # make this function a (null) generator
15785899Sgblack@eecs.umich.edu
15795899Sgblack@eecs.umich.edu    def recurseDeviceTree(self, state):
158010474Sandreas.hansson@arm.com        for child in self._children.itervalues():
15815899Sgblack@eecs.umich.edu            for item in child: # For looping over SimObjectVectors
15825899Sgblack@eecs.umich.edu                for dt in item.generateDeviceTree(state):
15835900Sgblack@eecs.umich.edu                    yield dt
15845900Sgblack@eecs.umich.edu
158510474Sandreas.hansson@arm.com    # On a separate method otherwise certain buggy Python versions
15865900Sgblack@eecs.umich.edu    # would fail with: SyntaxError: unqualified exec is not allowed
15875900Sgblack@eecs.umich.edu    # in function 'apply_config'
15885900Sgblack@eecs.umich.edu    def _apply_config_get_dict(self):
158910474Sandreas.hansson@arm.com        return {
15905900Sgblack@eecs.umich.edu            child_name: SimObjectCliWrapper(
15915900Sgblack@eecs.umich.edu                iter(self._children[child_name]))
15925936Sgblack@eecs.umich.edu            for child_name in self._children
15935936Sgblack@eecs.umich.edu        }
159410474Sandreas.hansson@arm.com
15955936Sgblack@eecs.umich.edu    def apply_config(self, params):
15965936Sgblack@eecs.umich.edu        """
15975936Sgblack@eecs.umich.edu        exec a list of Python code strings contained in params.
15985936Sgblack@eecs.umich.edu
159910474Sandreas.hansson@arm.com        The only exposed globals to those strings are the child
16005936Sgblack@eecs.umich.edu        SimObjects of this node.
160110474Sandreas.hansson@arm.com
16025936Sgblack@eecs.umich.edu        This function is intended to allow users to modify SimObject
16035936Sgblack@eecs.umich.edu        parameters from the command line with Python statements.
16045428Sgblack@eecs.umich.edu        """
160510474Sandreas.hansson@arm.com        d = self._apply_config_get_dict()
16068857Sgblack@eecs.umich.edu        for param in params:
16075428Sgblack@eecs.umich.edu            exec(param, d)
16085294Sgblack@eecs.umich.edu
16095294Sgblack@eecs.umich.edu# Function to provide to C++ so it can look up instances based on paths
16105294Sgblack@eecs.umich.edudef resolveSimObject(name):
16119212Snilay@cs.wisc.edu    obj = instanceDict[name]
16129212Snilay@cs.wisc.edu    return obj.getCCObject()
16139010Snilay@cs.wisc.edu
16149010Snilay@cs.wisc.edudef isSimObject(value):
16159212Snilay@cs.wisc.edu    return isinstance(value, SimObject)
16169212Snilay@cs.wisc.edu
16179010Snilay@cs.wisc.edudef isSimObjectClass(value):
16185294Sgblack@eecs.umich.edu    return issubclass(value, SimObject)
16195294Sgblack@eecs.umich.edu
16205294Sgblack@eecs.umich.edudef isSimObjectVector(value):
16215294Sgblack@eecs.umich.edu    return isinstance(value, SimObjectVector)
16225678Sgblack@eecs.umich.edu
16235294Sgblack@eecs.umich.edudef isSimObjectSequence(value):
16245678Sgblack@eecs.umich.edu    if not isinstance(value, (list, tuple)) or len(value) == 0:
16255678Sgblack@eecs.umich.edu        return False
16265678Sgblack@eecs.umich.edu
16275678Sgblack@eecs.umich.edu    for val in value:
16285678Sgblack@eecs.umich.edu        if not isNullPointer(val) and not isSimObject(val):
16295678Sgblack@eecs.umich.edu            return False
16305678Sgblack@eecs.umich.edu
16315678Sgblack@eecs.umich.edu    return True
16325678Sgblack@eecs.umich.edu
16335678Sgblack@eecs.umich.edudef isSimObjectOrSequence(value):
16345678Sgblack@eecs.umich.edu    return isSimObject(value) or isSimObjectSequence(value)
16355678Sgblack@eecs.umich.edu
16365678Sgblack@eecs.umich.edudef isRoot(obj):
16375678Sgblack@eecs.umich.edu    from m5.objects import Root
16385678Sgblack@eecs.umich.edu    return obj and obj is Root.getInstance()
163910474Sandreas.hansson@arm.com
16408857Sgblack@eecs.umich.edudef isSimObjectOrVector(value):
16415678Sgblack@eecs.umich.edu    return isSimObject(value) or isSimObjectVector(value)
16425678Sgblack@eecs.umich.edu
16435294Sgblack@eecs.umich.edudef tryAsSimObjectOrVector(value):
16445294Sgblack@eecs.umich.edu    if isSimObjectOrVector(value):
16455409Sgblack@eecs.umich.edu        return value
16465409Sgblack@eecs.umich.edu    if isSimObjectSequence(value):
16475409Sgblack@eecs.umich.edu        return SimObjectVector(value)
16485409Sgblack@eecs.umich.edu    return None
16495409Sgblack@eecs.umich.edu
16505409Sgblack@eecs.umich.edudef coerceSimObjectOrVector(value):
16515409Sgblack@eecs.umich.edu    value = tryAsSimObjectOrVector(value)
16525409Sgblack@eecs.umich.edu    if value is None:
16535409Sgblack@eecs.umich.edu        raise TypeError("SimObject or SimObjectVector expected")
16545409Sgblack@eecs.umich.edu    return value
16555429Sgblack@eecs.umich.edu
16565429Sgblack@eecs.umich.edubaseClasses = allClasses.copy()
16575429Sgblack@eecs.umich.edubaseInstances = instanceDict.copy()
16585429Sgblack@eecs.umich.edu
16595429Sgblack@eecs.umich.edudef clear():
16605294Sgblack@eecs.umich.edu    global allClasses, instanceDict, noCxxHeader
16615294Sgblack@eecs.umich.edu
16625294Sgblack@eecs.umich.edu    allClasses = baseClasses.copy()
16635433Sgblack@eecs.umich.edu    instanceDict = baseInstances.copy()
16648857Sgblack@eecs.umich.edu    noCxxHeader = False
16658857Sgblack@eecs.umich.edu
16668857Sgblack@eecs.umich.edu# __all__ defines the list of symbols that get exported when
16678857Sgblack@eecs.umich.edu# 'from config import *' is invoked.  Try to keep this reasonably
16688857Sgblack@eecs.umich.edu# short to avoid polluting other namespaces.
16698857Sgblack@eecs.umich.edu__all__ = [
167010474Sandreas.hansson@arm.com    'SimObject',
16718857Sgblack@eecs.umich.edu    'cxxMethod',
16728857Sgblack@eecs.umich.edu    'PyBindMethod',
16735901Sgblack@eecs.umich.edu    'PyBindProperty',
16748857Sgblack@eecs.umich.edu]
16758857Sgblack@eecs.umich.edu