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