SimObject.py revision 13764:1647bbdc9444
12623SN/A# Copyright (c) 2017-2018 ARM Limited 28926Sandreas.hansson@arm.com# All rights reserved. 38926Sandreas.hansson@arm.com# 48926Sandreas.hansson@arm.com# The license below extends only to copyright in the software and shall 58926Sandreas.hansson@arm.com# not be construed as granting a license to any other intellectual 68926Sandreas.hansson@arm.com# property including but not limited to intellectual property relating 78926Sandreas.hansson@arm.com# to a hardware implementation of the functionality of the software 88926Sandreas.hansson@arm.com# licensed hereunder. You may use the software subject to the license 98926Sandreas.hansson@arm.com# terms below provided that you ensure that this notice is replicated 108926Sandreas.hansson@arm.com# unmodified and in its entirety in all distributions of the software, 118926Sandreas.hansson@arm.com# modified or unmodified, in source code or in binary form. 128926Sandreas.hansson@arm.com# 138926Sandreas.hansson@arm.com# Copyright (c) 2004-2006 The Regents of The University of Michigan 142623SN/A# Copyright (c) 2010-20013 Advanced Micro Devices, Inc. 152623SN/A# Copyright (c) 2013 Mark D. Hill and David A. Wood 162623SN/A# All rights reserved. 172623SN/A# 182623SN/A# Redistribution and use in source and binary forms, with or without 192623SN/A# modification, are permitted provided that the following conditions are 202623SN/A# met: redistributions of source code must retain the above copyright 212623SN/A# notice, this list of conditions and the following disclaimer; 222623SN/A# redistributions in binary form must reproduce the above copyright 232623SN/A# notice, this list of conditions and the following disclaimer in the 242623SN/A# documentation and/or other materials provided with the distribution; 252623SN/A# neither the name of the copyright holders nor the names of its 262623SN/A# contributors may be used to endorse or promote products derived from 272623SN/A# this software without specific prior written permission. 282623SN/A# 292623SN/A# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 302623SN/A# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 312623SN/A# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 322623SN/A# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 332623SN/A# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 342623SN/A# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 352623SN/A# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 362623SN/A# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 372623SN/A# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 382623SN/A# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 392665Ssaidi@eecs.umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 402665Ssaidi@eecs.umich.edu# 412623SN/A# Authors: Steve Reinhardt 422623SN/A# Nathan Binkert 433170Sstever@eecs.umich.edu# Andreas Hansson 448105Sgblack@eecs.umich.edu# Andreas Sandberg 452623SN/A 464040Ssaidi@eecs.umich.edufrom __future__ import print_function 476658Snate@binkert.orgfrom __future__ import absolute_import 488229Snate@binkert.orgimport six 492623SN/Aif six.PY3: 509443SAndreas.Sandberg@ARM.com long = int 518232Snate@binkert.org 528232Snate@binkert.orgimport sys 533348Sbinkertn@umich.edufrom types import FunctionType, MethodType, ModuleType 543348Sbinkertn@umich.edufrom functools import wraps 558926Sandreas.hansson@arm.comimport inspect 564762Snate@binkert.org 577678Sgblack@eecs.umich.eduimport m5 582901Ssaidi@eecs.umich.edufrom m5.util import * 598779Sgblack@eecs.umich.edufrom m5.util.pybind import * 602623SN/A# Use the pyfdt and not the helper class, because the fdthelper 612623SN/A# relies on the SimObject definition 622623SN/Afrom m5.ext.pyfdt import pyfdt 632623SN/A 642623SN/A# Have to import params up top since Param is referenced on initial 655606Snate@binkert.org# load (when SimObject class references Param to create a class 662623SN/A# variable, the 'name' param)... 672623SN/Afrom m5.params import * 682623SN/A# There are a few things we need that aren't in params.__all__ since 692623SN/A# normal users don't need them 702623SN/Afrom m5.params import ParamDesc, VectorParamDesc, \ 712623SN/A isNullPointer, SimObjectVector, Port 722623SN/A 732623SN/Afrom m5.proxy import * 742623SN/Afrom m5.proxy import isproxy 752623SN/A 762623SN/A##################################################################### 775336Shines@cs.fsu.edu# 782623SN/A# M5 Python Configuration Utility 794873Sstever@eecs.umich.edu# 802623SN/A# The basic idea is to write simple Python programs that build Python 812623SN/A# objects corresponding to M5 SimObjects for the desired simulation 822623SN/A# configuration. For now, the Python emits a .ini file that can be 832623SN/A# parsed by M5. In the future, some tighter integration between M5 842623SN/A# and the Python interpreter may allow bypassing the .ini file. 852623SN/A# 868921Sandreas.hansson@arm.com# Each SimObject class in M5 is represented by a Python class with the 879433SAndreas.Sandberg@ARM.com# same name. The Python inheritance tree mirrors the M5 C++ tree 889424SAndreas.Sandberg@ARM.com# (e.g., SimpleCPU derives from BaseCPU in both cases, and all 899424SAndreas.Sandberg@ARM.com# SimObjects inherit from a single SimObject base class). To specify 909424SAndreas.Sandberg@ARM.com# an instance of an M5 SimObject in a configuration, the user simply 919424SAndreas.Sandberg@ARM.com# instantiates the corresponding Python object. The parameters for 929424SAndreas.Sandberg@ARM.com# that SimObject are given by assigning to attributes of the Python 938921Sandreas.hansson@arm.com# object, either using keyword assignment in the constructor or in 948921Sandreas.hansson@arm.com# separate assignment statements. For example: 958921Sandreas.hansson@arm.com# 969433SAndreas.Sandberg@ARM.com# cache = BaseCache(size='64KB') 978779Sgblack@eecs.umich.edu# cache.hit_latency = 3 988779Sgblack@eecs.umich.edu# cache.assoc = 8 998779Sgblack@eecs.umich.edu# 1008779Sgblack@eecs.umich.edu# The magic lies in the mapping of the Python attributes for SimObject 1018779Sgblack@eecs.umich.edu# classes to the actual SimObject parameter specifications. This 1028779Sgblack@eecs.umich.edu# allows parameter validity checking in the Python code. Continuing 1032623SN/A# the example above, the statements "cache.blurfl=3" or 1048706Sandreas.hansson@arm.com# "cache.assoc='hello'" would both result in runtime errors in Python, 1055714Shsul@eecs.umich.edu# since the BaseCache object has no 'blurfl' parameter and the 'assoc' 1065712Shsul@eecs.umich.edu# parameter requires an integer, respectively. This magic is done 1075712Shsul@eecs.umich.edu# primarily by overriding the special __setattr__ method that controls 1085712Shsul@eecs.umich.edu# assignment to object attributes. 1092623SN/A# 1102623SN/A# Once a set of Python objects have been instantiated in a hierarchy, 1115529Snate@binkert.org# calling 'instantiate(obj)' (where obj is the root of the hierarchy) 1126078Sgblack@eecs.umich.edu# will generate a .ini file. 1135487Snate@binkert.org# 1145487Snate@binkert.org##################################################################### 1159443SAndreas.Sandberg@ARM.com 1169095Sandreas.hansson@arm.com# list of all SimObject classes 1179095Sandreas.hansson@arm.comallClasses = {} 1188926Sandreas.hansson@arm.com 1192623SN/A# dict to look up SimObjects based on path 1202623SN/AinstanceDict = {} 1212623SN/A 1222623SN/A# Did any of the SimObjects lack a header file? 1232623SN/AnoCxxHeader = False 1242623SN/A 1252623SN/Adef public_value(key, value): 1266775SBrad.Beckmann@amd.com return key.startswith('_') or \ 1276775SBrad.Beckmann@amd.com isinstance(value, (FunctionType, MethodType, ModuleType, 1286775SBrad.Beckmann@amd.com classmethod, type)) 1292623SN/A 1302623SN/Adef createCxxConfigDirectoryEntryFile(code, name, simobj, is_header): 1319443SAndreas.Sandberg@ARM.com entry_class = 'CxxConfigDirectoryEntry_%s' % name 1329443SAndreas.Sandberg@ARM.com param_class = '%sCxxConfigParams' % name 1332623SN/A 1349443SAndreas.Sandberg@ARM.com code('#include "params/%s.hh"' % name) 1359443SAndreas.Sandberg@ARM.com 1369443SAndreas.Sandberg@ARM.com if not is_header: 1372623SN/A for param in simobj._params.values(): 1389443SAndreas.Sandberg@ARM.com if isSimObjectClass(param.ptype): 1399443SAndreas.Sandberg@ARM.com code('#include "%s"' % param.ptype._value_dict['cxx_header']) 1409443SAndreas.Sandberg@ARM.com code('#include "params/%s.hh"' % param.ptype.__name__) 1419443SAndreas.Sandberg@ARM.com else: 1429443SAndreas.Sandberg@ARM.com param.ptype.cxx_ini_predecls(code) 1439443SAndreas.Sandberg@ARM.com 1449443SAndreas.Sandberg@ARM.com if is_header: 1452915Sktlim@umich.edu member_prefix = '' 1469443SAndreas.Sandberg@ARM.com end_of_decl = ';' 1479443SAndreas.Sandberg@ARM.com code('#include "sim/cxx_config.hh"') 1489443SAndreas.Sandberg@ARM.com code() 1499342SAndreas.Sandberg@arm.com code('class ${param_class} : public CxxConfigParams,' 1509342SAndreas.Sandberg@arm.com ' public ${name}Params') 1512915Sktlim@umich.edu code('{') 1529342SAndreas.Sandberg@arm.com code(' private:') 1532915Sktlim@umich.edu code.indent() 1549443SAndreas.Sandberg@ARM.com code('class DirectoryEntry : public CxxConfigDirectoryEntry') 1555220Ssaidi@eecs.umich.edu code('{') 1565220Ssaidi@eecs.umich.edu code(' public:') 1575220Ssaidi@eecs.umich.edu code.indent() 1584940Snate@binkert.org code('DirectoryEntry();'); 1599424SAndreas.Sandberg@ARM.com code() 1609424SAndreas.Sandberg@ARM.com code('CxxConfigParams *makeParamsObject() const') 1619424SAndreas.Sandberg@ARM.com code('{ return new ${param_class}; }') 1629424SAndreas.Sandberg@ARM.com code.dedent() 1633324Shsul@eecs.umich.edu code('};') 1649443SAndreas.Sandberg@ARM.com code() 1659443SAndreas.Sandberg@ARM.com code.dedent() 1669443SAndreas.Sandberg@ARM.com code(' public:') 1679443SAndreas.Sandberg@ARM.com code.indent() 1687897Shestness@cs.utexas.edu else: 1692623SN/A member_prefix = '%s::' % param_class 1702623SN/A end_of_decl = '' 1719443SAndreas.Sandberg@ARM.com code('#include "%s"' % simobj._value_dict['cxx_header']) 1729443SAndreas.Sandberg@ARM.com code('#include "base/str.hh"') 1739443SAndreas.Sandberg@ARM.com code('#include "cxx_config/${name}.hh"') 1749443SAndreas.Sandberg@ARM.com 1759443SAndreas.Sandberg@ARM.com if simobj._ports: 1769443SAndreas.Sandberg@ARM.com code('#include "mem/mem_object.hh"') 1779443SAndreas.Sandberg@ARM.com code('#include "mem/port.hh"') 1789443SAndreas.Sandberg@ARM.com 1799443SAndreas.Sandberg@ARM.com code() 1809443SAndreas.Sandberg@ARM.com code('${member_prefix}DirectoryEntry::DirectoryEntry()'); 1819443SAndreas.Sandberg@ARM.com code('{') 1829443SAndreas.Sandberg@ARM.com 1839443SAndreas.Sandberg@ARM.com def cxx_bool(b): 1849443SAndreas.Sandberg@ARM.com return 'true' if b else 'false' 1859443SAndreas.Sandberg@ARM.com 1869443SAndreas.Sandberg@ARM.com code.indent() 1879443SAndreas.Sandberg@ARM.com for param in simobj._params.values(): 1889443SAndreas.Sandberg@ARM.com is_vector = isinstance(param, m5.params.VectorParamDesc) 1892623SN/A is_simobj = issubclass(param.ptype, m5.SimObject.SimObject) 1902798Sktlim@umich.edu 1912623SN/A code('parameters["%s"] = new ParamDesc("%s", %s, %s);' % 1929429SAndreas.Sandberg@ARM.com (param.name, param.name, cxx_bool(is_vector), 1939429SAndreas.Sandberg@ARM.com cxx_bool(is_simobj))); 1949443SAndreas.Sandberg@ARM.com 1959342SAndreas.Sandberg@arm.com for port in simobj._ports.values(): 1969443SAndreas.Sandberg@ARM.com is_vector = isinstance(port, m5.params.VectorPort) 1979443SAndreas.Sandberg@ARM.com is_master = port.role == 'MASTER' 1982798Sktlim@umich.edu 1992623SN/A code('ports["%s"] = new PortDesc("%s", %s, %s);' % 2002623SN/A (port.name, port.name, cxx_bool(is_vector), 2012623SN/A cxx_bool(is_master))) 2022623SN/A 2032623SN/A code.dedent() 2042623SN/A code('}') 2059429SAndreas.Sandberg@ARM.com code() 2062623SN/A 2079443SAndreas.Sandberg@ARM.com code('bool ${member_prefix}setSimObject(const std::string &name,') 2082623SN/A code(' SimObject *simObject)${end_of_decl}') 2092623SN/A 2109443SAndreas.Sandberg@ARM.com if not is_header: 2119443SAndreas.Sandberg@ARM.com code('{') 2129443SAndreas.Sandberg@ARM.com code.indent() 2139443SAndreas.Sandberg@ARM.com code('bool ret = true;') 2149443SAndreas.Sandberg@ARM.com code() 2159443SAndreas.Sandberg@ARM.com code('if (false) {') 2169443SAndreas.Sandberg@ARM.com for param in simobj._params.values(): 2179443SAndreas.Sandberg@ARM.com is_vector = isinstance(param, m5.params.VectorParamDesc) 2183512Sktlim@umich.edu is_simobj = issubclass(param.ptype, m5.SimObject.SimObject) 2199443SAndreas.Sandberg@ARM.com 2205712Shsul@eecs.umich.edu if is_simobj and not is_vector: 2215712Shsul@eecs.umich.edu code('} else if (name == "${{param.name}}") {') 2225712Shsul@eecs.umich.edu code.indent() 2232623SN/A code('this->${{param.name}} = ' 2242623SN/A 'dynamic_cast<${{param.ptype.cxx_type}}>(simObject);') 2252623SN/A code('if (simObject && !this->${{param.name}})') 2262623SN/A code(' ret = false;') 2279180Sandreas.hansson@arm.com code.dedent() 2282623SN/A code('} else {') 2294940Snate@binkert.org code(' ret = false;') 2304940Snate@binkert.org code('}') 2312623SN/A code() 2322683Sktlim@umich.edu code('return ret;') 2332623SN/A code.dedent() 2342623SN/A code('}') 2352623SN/A 2362623SN/A code() 2372623SN/A code('bool ${member_prefix}setSimObjectVector(' 2389180Sandreas.hansson@arm.com 'const std::string &name,') 2393686Sktlim@umich.edu code(' const std::vector<SimObject *> &simObjects)${end_of_decl}') 2403430Sgblack@eecs.umich.edu 2419179Sandreas.hansson@arm.com if not is_header: 2429342SAndreas.Sandberg@arm.com code('{') 2432623SN/A code.indent() 2442623SN/A code('bool ret = true;') 2452623SN/A code() 2462623SN/A code('if (false) {') 2478737Skoansin.tan@gmail.com for param in simobj._params.values(): 2482623SN/A is_vector = isinstance(param, m5.params.VectorParamDesc) 2494940Snate@binkert.org is_simobj = issubclass(param.ptype, m5.SimObject.SimObject) 2504940Snate@binkert.org 2512623SN/A if is_simobj and is_vector: 2522683Sktlim@umich.edu code('} else if (name == "${{param.name}}") {') 2532623SN/A code.indent() 2546043Sgblack@eecs.umich.edu code('this->${{param.name}}.clear();') 2556043Sgblack@eecs.umich.edu code('for (auto i = simObjects.begin(); ' 2566043Sgblack@eecs.umich.edu 'ret && i != simObjects.end(); i ++)') 2579342SAndreas.Sandberg@arm.com code('{') 2582626SN/A code.indent() 2592626SN/A code('${{param.ptype.cxx_type}} object = ' 2602626SN/A 'dynamic_cast<${{param.ptype.cxx_type}}>(*i);') 2612626SN/A code('if (*i && !object)') 2625606Snate@binkert.org code(' ret = false;') 2632623SN/A code('else') 2642623SN/A code(' this->${{param.name}}.push_back(object);') 2652623SN/A code.dedent() 2662623SN/A code('}') 2672623SN/A code.dedent() 2682623SN/A code('} else {') 2692623SN/A code(' ret = false;') 2708444Sgblack@eecs.umich.edu code('}') 2718444Sgblack@eecs.umich.edu code() 2722623SN/A code('return ret;') 2733169Sstever@eecs.umich.edu code.dedent() 2744870Sstever@eecs.umich.edu code('}') 2752623SN/A 2762623SN/A code() 2772623SN/A code('void ${member_prefix}setName(const std::string &name_)' 2782623SN/A '${end_of_decl}') 2792623SN/A 2804999Sgblack@eecs.umich.edu if not is_header: 2816227Snate@binkert.org code('{') 2824999Sgblack@eecs.umich.edu code.indent() 2837520Sgblack@eecs.umich.edu code('this->name = name_;') 2842623SN/A code.dedent() 2854999Sgblack@eecs.umich.edu code('}') 2864999Sgblack@eecs.umich.edu 2877520Sgblack@eecs.umich.edu if is_header: 2884999Sgblack@eecs.umich.edu code('const std::string &${member_prefix}getName()') 2897520Sgblack@eecs.umich.edu code('{ return this->name; }') 2907520Sgblack@eecs.umich.edu 2914999Sgblack@eecs.umich.edu code() 2924999Sgblack@eecs.umich.edu code('bool ${member_prefix}setParam(const std::string &name,') 2934999Sgblack@eecs.umich.edu code(' const std::string &value, const Flags flags)${end_of_decl}') 2947520Sgblack@eecs.umich.edu 2958832SAli.Saidi@ARM.com if not is_header: 2964999Sgblack@eecs.umich.edu code('{') 2974999Sgblack@eecs.umich.edu code.indent() 2986023Snate@binkert.org code('bool ret = true;') 2994999Sgblack@eecs.umich.edu code() 3004999Sgblack@eecs.umich.edu code('if (false) {') 3016623Sgblack@eecs.umich.edu for param in simobj._params.values(): 3024999Sgblack@eecs.umich.edu is_vector = isinstance(param, m5.params.VectorParamDesc) 3038949Sandreas.hansson@arm.com is_simobj = issubclass(param.ptype, m5.SimObject.SimObject) 3048949Sandreas.hansson@arm.com 3057520Sgblack@eecs.umich.edu if not is_simobj and not is_vector: 3064999Sgblack@eecs.umich.edu code('} else if (name == "${{param.name}}") {') 3078105Sgblack@eecs.umich.edu code.indent() 3084999Sgblack@eecs.umich.edu param.ptype.cxx_ini_parse(code, 3094999Sgblack@eecs.umich.edu 'value', 'this->%s' % param.name, 'ret =') 3108931Sandreas.hansson@arm.com code.dedent() 3118931Sandreas.hansson@arm.com code('} else {') 3124999Sgblack@eecs.umich.edu code(' ret = false;') 3134999Sgblack@eecs.umich.edu code('}') 3144999Sgblack@eecs.umich.edu code() 3154999Sgblack@eecs.umich.edu code('return ret;') 3165012Sgblack@eecs.umich.edu code.dedent() 3174999Sgblack@eecs.umich.edu code('}') 3184999Sgblack@eecs.umich.edu 3196102Sgblack@eecs.umich.edu code() 3204999Sgblack@eecs.umich.edu code('bool ${member_prefix}setParamVector(' 3214999Sgblack@eecs.umich.edu 'const std::string &name,') 3224968Sacolyte@umich.edu code(' const std::vector<std::string> &values,') 3234986Ssaidi@eecs.umich.edu code(' const Flags flags)${end_of_decl}') 3244999Sgblack@eecs.umich.edu 3256739Sgblack@eecs.umich.edu if not is_header: 3266739Sgblack@eecs.umich.edu code('{') 3276739Sgblack@eecs.umich.edu code.indent() 3286739Sgblack@eecs.umich.edu code('bool ret = true;') 3296739Sgblack@eecs.umich.edu code() 3306739Sgblack@eecs.umich.edu code('if (false) {') 3316739Sgblack@eecs.umich.edu for param in simobj._params.values(): 3326739Sgblack@eecs.umich.edu is_vector = isinstance(param, m5.params.VectorParamDesc) 3334999Sgblack@eecs.umich.edu is_simobj = issubclass(param.ptype, m5.SimObject.SimObject) 3344999Sgblack@eecs.umich.edu 3354999Sgblack@eecs.umich.edu if not is_simobj and is_vector: 3366078Sgblack@eecs.umich.edu code('} else if (name == "${{param.name}}") {') 3376078Sgblack@eecs.umich.edu code.indent() 3386078Sgblack@eecs.umich.edu code('${{param.name}}.clear();') 3396078Sgblack@eecs.umich.edu code('for (auto i = values.begin(); ' 3404999Sgblack@eecs.umich.edu 'ret && i != values.end(); i ++)') 3414968Sacolyte@umich.edu code('{') 3423170Sstever@eecs.umich.edu code.indent() 3434999Sgblack@eecs.umich.edu code('${{param.ptype.cxx_type}} elem;') 3444999Sgblack@eecs.umich.edu param.ptype.cxx_ini_parse(code, 3454999Sgblack@eecs.umich.edu '*i', 'elem', 'ret =') 3464999Sgblack@eecs.umich.edu code('if (ret)') 3474999Sgblack@eecs.umich.edu code(' this->${{param.name}}.push_back(elem);') 3487520Sgblack@eecs.umich.edu code.dedent() 3494999Sgblack@eecs.umich.edu code('}') 3507520Sgblack@eecs.umich.edu code.dedent() 3514999Sgblack@eecs.umich.edu code('} else {') 3524999Sgblack@eecs.umich.edu code(' ret = false;') 3532623SN/A code('}') 3542623SN/A code() 3552623SN/A code('return ret;') 3567520Sgblack@eecs.umich.edu code.dedent() 3572623SN/A code('}') 3588444Sgblack@eecs.umich.edu 3598444Sgblack@eecs.umich.edu code() 3602623SN/A code('bool ${member_prefix}setPortConnectionCount(' 3613169Sstever@eecs.umich.edu 'const std::string &name,') 3624870Sstever@eecs.umich.edu code(' unsigned int count)${end_of_decl}') 3632623SN/A 3642623SN/A if not is_header: 3652623SN/A code('{') 3662623SN/A code.indent() 3672623SN/A code('bool ret = true;') 3684999Sgblack@eecs.umich.edu code() 3696227Snate@binkert.org code('if (false)') 3704999Sgblack@eecs.umich.edu code(' ;') 3717520Sgblack@eecs.umich.edu for port in simobj._ports.values(): 3722623SN/A code('else if (name == "${{port.name}}")') 3734999Sgblack@eecs.umich.edu code(' this->port_${{port.name}}_connection_count = count;') 3744999Sgblack@eecs.umich.edu code('else') 3757520Sgblack@eecs.umich.edu code(' ret = false;') 3764999Sgblack@eecs.umich.edu code() 3774999Sgblack@eecs.umich.edu code('return ret;') 3787520Sgblack@eecs.umich.edu code.dedent() 3794999Sgblack@eecs.umich.edu code('}') 3804999Sgblack@eecs.umich.edu 3814999Sgblack@eecs.umich.edu code() 3824999Sgblack@eecs.umich.edu code('SimObject *${member_prefix}simObjectCreate()${end_of_decl}') 3838832SAli.Saidi@ARM.com 3844999Sgblack@eecs.umich.edu if not is_header: 3854999Sgblack@eecs.umich.edu code('{') 3866023Snate@binkert.org if hasattr(simobj, 'abstract') and simobj.abstract: 3874999Sgblack@eecs.umich.edu code(' return NULL;') 3884999Sgblack@eecs.umich.edu else: 3894999Sgblack@eecs.umich.edu code(' return this->create();') 3904999Sgblack@eecs.umich.edu code('}') 3914999Sgblack@eecs.umich.edu 3924999Sgblack@eecs.umich.edu if is_header: 3936102Sgblack@eecs.umich.edu code() 3944999Sgblack@eecs.umich.edu code('static CxxConfigDirectoryEntry' 3954999Sgblack@eecs.umich.edu ' *${member_prefix}makeDirectoryEntry()') 3964999Sgblack@eecs.umich.edu code('{ return new DirectoryEntry; }') 3974999Sgblack@eecs.umich.edu 3984999Sgblack@eecs.umich.edu if is_header: 3994999Sgblack@eecs.umich.edu code.dedent() 4004999Sgblack@eecs.umich.edu code('};') 4014999Sgblack@eecs.umich.edu 4024999Sgblack@eecs.umich.edu# The metaclass for SimObject. This class controls how new classes 4034999Sgblack@eecs.umich.edu# that derive from SimObject are instantiated, and provides inherited 4046623Sgblack@eecs.umich.edu# class behavior (just like a class controls how instances of that 4058949Sandreas.hansson@arm.com# class are instantiated, and provides inherited instance behavior). 4067520Sgblack@eecs.umich.educlass MetaSimObject(type): 4074999Sgblack@eecs.umich.edu # Attributes that can be set only at initialization time 4088105Sgblack@eecs.umich.edu init_keywords = { 4094999Sgblack@eecs.umich.edu 'abstract' : bool, 4104999Sgblack@eecs.umich.edu 'cxx_class' : str, 4114999Sgblack@eecs.umich.edu 'cxx_type' : str, 4128931Sandreas.hansson@arm.com 'cxx_header' : str, 4138931Sandreas.hansson@arm.com 'type' : str, 4144999Sgblack@eecs.umich.edu 'cxx_base' : (str, type(None)), 4154999Sgblack@eecs.umich.edu 'cxx_extra_bases' : list, 4164999Sgblack@eecs.umich.edu 'cxx_exports' : list, 4174999Sgblack@eecs.umich.edu 'cxx_param_exports' : list, 4184999Sgblack@eecs.umich.edu } 4194999Sgblack@eecs.umich.edu # Attributes that can be set any time 4204999Sgblack@eecs.umich.edu keywords = { 'check' : FunctionType } 4214999Sgblack@eecs.umich.edu 4227520Sgblack@eecs.umich.edu # __new__ is called before __init__, and is where the statements 4234999Sgblack@eecs.umich.edu # in the body of the class definition get loaded into the class's 4244999Sgblack@eecs.umich.edu # __dict__. We intercept this to filter out parameter & port assignments 4254999Sgblack@eecs.umich.edu # and only allow "private" attributes to be passed to the base 4264999Sgblack@eecs.umich.edu # __new__ (starting with underscore). 4274999Sgblack@eecs.umich.edu def __new__(mcls, name, bases, dict): 4284878Sstever@eecs.umich.edu assert name not in allClasses, "SimObject %s already present" % name 4294040Ssaidi@eecs.umich.edu 4304040Ssaidi@eecs.umich.edu # Copy "private" attributes, functions, and classes to the 4314999Sgblack@eecs.umich.edu # official dict. Everything else goes in _init_dict to be 4324999Sgblack@eecs.umich.edu # filtered in __init__. 4334999Sgblack@eecs.umich.edu cls_dict = {} 4344999Sgblack@eecs.umich.edu value_dict = {} 4356078Sgblack@eecs.umich.edu cxx_exports = [] 4366078Sgblack@eecs.umich.edu for key,val in dict.items(): 4376078Sgblack@eecs.umich.edu try: 4386078Sgblack@eecs.umich.edu cxx_exports.append(getattr(val, "__pybind")) 4396739Sgblack@eecs.umich.edu except AttributeError: 4406739Sgblack@eecs.umich.edu pass 4416739Sgblack@eecs.umich.edu 4426739Sgblack@eecs.umich.edu if public_value(key, val): 4436739Sgblack@eecs.umich.edu cls_dict[key] = val 4443170Sstever@eecs.umich.edu else: 4453170Sstever@eecs.umich.edu # must be a param/port setting 4464999Sgblack@eecs.umich.edu value_dict[key] = val 4474999Sgblack@eecs.umich.edu if 'abstract' not in value_dict: 4484999Sgblack@eecs.umich.edu value_dict['abstract'] = False 4494999Sgblack@eecs.umich.edu if 'cxx_extra_bases' not in value_dict: 4504999Sgblack@eecs.umich.edu value_dict['cxx_extra_bases'] = [] 4517520Sgblack@eecs.umich.edu if 'cxx_exports' not in value_dict: 4524999Sgblack@eecs.umich.edu value_dict['cxx_exports'] = cxx_exports 4537520Sgblack@eecs.umich.edu else: 4544999Sgblack@eecs.umich.edu value_dict['cxx_exports'] += cxx_exports 4554999Sgblack@eecs.umich.edu if 'cxx_param_exports' not in value_dict: 4562623SN/A value_dict['cxx_param_exports'] = [] 4572623SN/A cls_dict['_value_dict'] = value_dict 4582623SN/A cls = super(MetaSimObject, mcls).__new__(mcls, name, bases, cls_dict) 4592623SN/A if 'type' in value_dict: 4602623SN/A allClasses[name] = cls 4612623SN/A return cls 4622623SN/A 4634940Snate@binkert.org # subclass initialization 4644940Snate@binkert.org def __init__(cls, name, bases, dict): 4655487Snate@binkert.org # calls type.__init__()... I think that's a no-op, but leave 4662623SN/A # it here just in case it's not. 4676078Sgblack@eecs.umich.edu super(MetaSimObject, cls).__init__(name, bases, dict) 4682623SN/A 4692623SN/A # initialize required attributes 4703387Sgblack@eecs.umich.edu 4713387Sgblack@eecs.umich.edu # class-only attributes 4722626SN/A cls._params = multidict() # param descriptions 4735348Ssaidi@eecs.umich.edu cls._ports = multidict() # port descriptions 4748143SAli.Saidi@ARM.com 4759443SAndreas.Sandberg@ARM.com # class or instance attributes 4769443SAndreas.Sandberg@ARM.com cls._values = multidict() # param values 4778143SAli.Saidi@ARM.com cls._hr_values = multidict() # human readable param values 4789443SAndreas.Sandberg@ARM.com cls._children = multidict() # SimObject children 4795348Ssaidi@eecs.umich.edu cls._port_refs = multidict() # port ref objects 4805669Sgblack@eecs.umich.edu cls._instantiated = False # really instantiated, cloned, or subclassed 4815669Sgblack@eecs.umich.edu 4827720Sgblack@eecs.umich.edu # We don't support multiple inheritance of sim objects. If you want 4837720Sgblack@eecs.umich.edu # to, you must fix multidict to deal with it properly. Non sim-objects 4847720Sgblack@eecs.umich.edu # are ok, though 4857720Sgblack@eecs.umich.edu bTotal = 0 4867720Sgblack@eecs.umich.edu for c in bases: 4875894Sgblack@eecs.umich.edu if isinstance(c, MetaSimObject): 4886023Snate@binkert.org bTotal += 1 4896023Snate@binkert.org if bTotal > 1: 4905894Sgblack@eecs.umich.edu raise TypeError( 4912623SN/A "SimObjects do not support multiple inheritance") 4922623SN/A 4934182Sgblack@eecs.umich.edu base = bases[0] 4944182Sgblack@eecs.umich.edu 4954182Sgblack@eecs.umich.edu # Set up general inheritance via multidicts. A subclass will 4962662Sstever@eecs.umich.edu # inherit all its settings from the base class. The only time 4977720Sgblack@eecs.umich.edu # the following is not true is when we define the SimObject 4989023Sgblack@eecs.umich.edu # class itself (in which case the multidicts have no parent). 4995694Sgblack@eecs.umich.edu if isinstance(base, MetaSimObject): 5005694Sgblack@eecs.umich.edu cls._base = base 5015694Sgblack@eecs.umich.edu cls._params.parent = base._params 5025669Sgblack@eecs.umich.edu cls._ports.parent = base._ports 5039023Sgblack@eecs.umich.edu cls._values.parent = base._values 5045669Sgblack@eecs.umich.edu cls._hr_values.parent = base._hr_values 5055669Sgblack@eecs.umich.edu cls._children.parent = base._children 5068949Sandreas.hansson@arm.com cls._port_refs.parent = base._port_refs 5075669Sgblack@eecs.umich.edu # mark base as having been subclassed 5082623SN/A base._instantiated = True 5098931Sandreas.hansson@arm.com else: 5108931Sandreas.hansson@arm.com cls._base = None 5115669Sgblack@eecs.umich.edu 5125669Sgblack@eecs.umich.edu # default keyword values 5134968Sacolyte@umich.edu if 'type' in cls._value_dict: 5145669Sgblack@eecs.umich.edu if 'cxx_class' not in cls._value_dict: 5154968Sacolyte@umich.edu cls._value_dict['cxx_class'] = cls._value_dict['type'] 5165669Sgblack@eecs.umich.edu 5175669Sgblack@eecs.umich.edu cls._value_dict['cxx_type'] = '%s *' % cls._value_dict['cxx_class'] 5185669Sgblack@eecs.umich.edu 5195669Sgblack@eecs.umich.edu if 'cxx_header' not in cls._value_dict: 5204182Sgblack@eecs.umich.edu global noCxxHeader 5212623SN/A noCxxHeader = True 5223814Ssaidi@eecs.umich.edu warn("No header file specified for SimObject: %s", name) 5235001Sgblack@eecs.umich.edu 5244182Sgblack@eecs.umich.edu # Now process the _value_dict items. They could be defining 5254998Sgblack@eecs.umich.edu # new (or overriding existing) parameters or ports, setting 5264998Sgblack@eecs.umich.edu # class keywords (e.g., 'abstract'), or setting parameter 5274998Sgblack@eecs.umich.edu # values or port bindings. The first 3 can only be set when 5284998Sgblack@eecs.umich.edu # the class is defined, so we handle them here. The others 5297655Sali.saidi@arm.com # can be set later too, so just emulate that by calling 5305001Sgblack@eecs.umich.edu # setattr(). 5315001Sgblack@eecs.umich.edu for key,val in cls._value_dict.items(): 5325001Sgblack@eecs.umich.edu # param descriptions 5334998Sgblack@eecs.umich.edu if isinstance(val, ParamDesc): 5344182Sgblack@eecs.umich.edu cls._new_param(key, val) 5354182Sgblack@eecs.umich.edu 5362623SN/A # port objects 5373814Ssaidi@eecs.umich.edu elif isinstance(val, Port): 5384539Sgblack@eecs.umich.edu cls._new_port(key, val) 5394539Sgblack@eecs.umich.edu 5403814Ssaidi@eecs.umich.edu # init-time-only keywords 5413814Ssaidi@eecs.umich.edu elif key in cls.init_keywords: 5425487Snate@binkert.org cls._set_keyword(key, val, cls.init_keywords[key]) 5435487Snate@binkert.org 5445487Snate@binkert.org # default: use normal path (ends up in __setattr__) 5455487Snate@binkert.org else: 5465487Snate@binkert.org setattr(cls, key, val) 5475487Snate@binkert.org 5485487Snate@binkert.org def _set_keyword(cls, keyword, val, kwtype): 5495487Snate@binkert.org if not isinstance(val, kwtype): 5509180Sandreas.hansson@arm.com raise TypeError('keyword %s has bad type %s (expecting %s)' % \ 5519180Sandreas.hansson@arm.com (keyword, type(val), kwtype)) 5529180Sandreas.hansson@arm.com if isinstance(val, FunctionType): 5539180Sandreas.hansson@arm.com val = classmethod(val) 5549180Sandreas.hansson@arm.com type.__setattr__(cls, keyword, val) 5552623SN/A 5562623SN/A def _new_param(cls, name, pdesc): 5572623SN/A # each param desc should be uniquely assigned to one variable 5584377Sgblack@eecs.umich.edu assert(not hasattr(pdesc, 'name')) 5594182Sgblack@eecs.umich.edu pdesc.name = name 5602623SN/A cls._params[name] = pdesc 5612623SN/A if hasattr(pdesc, 'default'): 5629443SAndreas.Sandberg@ARM.com cls._set_param(name, pdesc.default, pdesc) 5639443SAndreas.Sandberg@ARM.com 5649443SAndreas.Sandberg@ARM.com def _set_param(cls, name, value, param): 5655487Snate@binkert.org assert(param.name == name) 5669179Sandreas.hansson@arm.com try: 5679179Sandreas.hansson@arm.com hr_value = value 5685487Snate@binkert.org value = param.convert(value) 5692626SN/A except Exception as e: 5707823Ssteve.reinhardt@amd.com msg = "%s\nError setting param %s.%s to %s\n" % \ 5712623SN/A (e, cls.__name__, name, value) 5722623SN/A e.args = (msg, ) 5732623SN/A raise 5745315Sstever@gmail.com cls._values[name] = value 5755315Sstever@gmail.com # if param value is a SimObject, make it a child too, so that 5765315Sstever@gmail.com # it gets cloned properly when the class is instantiated 5775315Sstever@gmail.com if isSimObjectOrVector(value) and not value.has_parent(): 5785315Sstever@gmail.com cls._add_cls_child(name, value) 5795315Sstever@gmail.com # update human-readable values of the param if it has a literal 5805315Sstever@gmail.com # value and is not an object or proxy. 5812623SN/A if not (isSimObjectOrVector(value) or\ 5822623SN/A isinstance(value, m5.proxy.BaseProxy)): 5832623SN/A cls._hr_values[name] = hr_value 5842623SN/A 5854762Snate@binkert.org def _add_cls_child(cls, name, child): 5864762Snate@binkert.org # It's a little funky to have a class as a parent, but these 5872623SN/A # objects should never be instantiated (only cloned, which 5885529Snate@binkert.org # clears the parent pointer), and this makes it clear that the 5898779Sgblack@eecs.umich.edu # object is not an orphan and can provide better error 5904762Snate@binkert.org # messages. 5915529Snate@binkert.org child.set_parent(cls, name) 5922623SN/A if not isNullPointer(child): 593 cls._children[name] = child 594 595 def _new_port(cls, name, port): 596 # each port should be uniquely assigned to one variable 597 assert(not hasattr(port, 'name')) 598 port.name = name 599 cls._ports[name] = port 600 601 # same as _get_port_ref, effectively, but for classes 602 def _cls_get_port_ref(cls, attr): 603 # Return reference that can be assigned to another port 604 # via __setattr__. There is only ever one reference 605 # object per port, but we create them lazily here. 606 ref = cls._port_refs.get(attr) 607 if not ref: 608 ref = cls._ports[attr].makeRef(cls) 609 cls._port_refs[attr] = ref 610 return ref 611 612 # Set attribute (called on foo.attr = value when foo is an 613 # instance of class cls). 614 def __setattr__(cls, attr, value): 615 # normal processing for private attributes 616 if public_value(attr, value): 617 type.__setattr__(cls, attr, value) 618 return 619 620 if attr in cls.keywords: 621 cls._set_keyword(attr, value, cls.keywords[attr]) 622 return 623 624 if attr in cls._ports: 625 cls._cls_get_port_ref(attr).connect(value) 626 return 627 628 if isSimObjectOrSequence(value) and cls._instantiated: 629 raise RuntimeError( 630 "cannot set SimObject parameter '%s' after\n" \ 631 " class %s has been instantiated or subclassed" \ 632 % (attr, cls.__name__)) 633 634 # check for param 635 param = cls._params.get(attr) 636 if param: 637 cls._set_param(attr, value, param) 638 return 639 640 if isSimObjectOrSequence(value): 641 # If RHS is a SimObject, it's an implicit child assignment. 642 cls._add_cls_child(attr, coerceSimObjectOrVector(value)) 643 return 644 645 # no valid assignment... raise exception 646 raise AttributeError( 647 "Class %s has no parameter \'%s\'" % (cls.__name__, attr)) 648 649 def __getattr__(cls, attr): 650 if attr == 'cxx_class_path': 651 return cls.cxx_class.split('::') 652 653 if attr == 'cxx_class_name': 654 return cls.cxx_class_path[-1] 655 656 if attr == 'cxx_namespaces': 657 return cls.cxx_class_path[:-1] 658 659 if attr in cls._values: 660 return cls._values[attr] 661 662 if attr in cls._children: 663 return cls._children[attr] 664 665 raise AttributeError( 666 "object '%s' has no attribute '%s'" % (cls.__name__, attr)) 667 668 def __str__(cls): 669 return cls.__name__ 670 671 # See ParamValue.cxx_predecls for description. 672 def cxx_predecls(cls, code): 673 code('#include "params/$cls.hh"') 674 675 def pybind_predecls(cls, code): 676 code('#include "${{cls.cxx_header}}"') 677 678 def pybind_decl(cls, code): 679 class_path = cls.cxx_class.split('::') 680 namespaces, classname = class_path[:-1], class_path[-1] 681 py_class_name = '_COLONS_'.join(class_path) if namespaces else \ 682 classname; 683 684 # The 'local' attribute restricts us to the params declared in 685 # the object itself, not including inherited params (which 686 # will also be inherited from the base class's param struct 687 # here). Sort the params based on their key 688 params = map(lambda k_v: k_v[1], sorted(cls._params.local.items())) 689 ports = cls._ports.local 690 691 code('''#include "pybind11/pybind11.h" 692#include "pybind11/stl.h" 693 694#include "params/$cls.hh" 695#include "python/pybind11/core.hh" 696#include "sim/init.hh" 697#include "sim/sim_object.hh" 698 699#include "${{cls.cxx_header}}" 700 701''') 702 703 for param in params: 704 param.pybind_predecls(code) 705 706 code('''namespace py = pybind11; 707 708static void 709module_init(py::module &m_internal) 710{ 711 py::module m = m_internal.def_submodule("param_${cls}"); 712''') 713 code.indent() 714 if cls._base: 715 code('py::class_<${cls}Params, ${{cls._base.type}}Params, ' \ 716 'std::unique_ptr<${{cls}}Params, py::nodelete>>(' \ 717 'm, "${cls}Params")') 718 else: 719 code('py::class_<${cls}Params, ' \ 720 'std::unique_ptr<${cls}Params, py::nodelete>>(' \ 721 'm, "${cls}Params")') 722 723 code.indent() 724 if not hasattr(cls, 'abstract') or not cls.abstract: 725 code('.def(py::init<>())') 726 code('.def("create", &${cls}Params::create)') 727 728 param_exports = cls.cxx_param_exports + [ 729 PyBindProperty(k) 730 for k, v in sorted(cls._params.local.items()) 731 ] + [ 732 PyBindProperty("port_%s_connection_count" % port.name) 733 for port in ports.values() 734 ] 735 for exp in param_exports: 736 exp.export(code, "%sParams" % cls) 737 738 code(';') 739 code() 740 code.dedent() 741 742 bases = [] 743 if 'cxx_base' in cls._value_dict: 744 # If the c++ base class implied by python inheritance was 745 # overridden, use that value. 746 if cls.cxx_base: 747 bases.append(cls.cxx_base) 748 elif cls._base: 749 # If not and if there was a SimObject base, use its c++ class 750 # as this class' base. 751 bases.append(cls._base.cxx_class) 752 # Add in any extra bases that were requested. 753 bases.extend(cls.cxx_extra_bases) 754 755 if bases: 756 base_str = ", ".join(bases) 757 code('py::class_<${{cls.cxx_class}}, ${base_str}, ' \ 758 'std::unique_ptr<${{cls.cxx_class}}, py::nodelete>>(' \ 759 'm, "${py_class_name}")') 760 else: 761 code('py::class_<${{cls.cxx_class}}, ' \ 762 'std::unique_ptr<${{cls.cxx_class}}, py::nodelete>>(' \ 763 'm, "${py_class_name}")') 764 code.indent() 765 for exp in cls.cxx_exports: 766 exp.export(code, cls.cxx_class) 767 code(';') 768 code.dedent() 769 code() 770 code.dedent() 771 code('}') 772 code() 773 code('static EmbeddedPyBind embed_obj("${0}", module_init, "${1}");', 774 cls, cls._base.type if cls._base else "") 775 776 777 # Generate the C++ declaration (.hh file) for this SimObject's 778 # param struct. Called from src/SConscript. 779 def cxx_param_decl(cls, code): 780 # The 'local' attribute restricts us to the params declared in 781 # the object itself, not including inherited params (which 782 # will also be inherited from the base class's param struct 783 # here). Sort the params based on their key 784 params = map(lambda k_v: k_v[1], sorted(cls._params.local.items())) 785 ports = cls._ports.local 786 try: 787 ptypes = [p.ptype for p in params] 788 except: 789 print(cls, p, p.ptype_str) 790 print(params) 791 raise 792 793 class_path = cls._value_dict['cxx_class'].split('::') 794 795 code('''\ 796#ifndef __PARAMS__${cls}__ 797#define __PARAMS__${cls}__ 798 799''') 800 801 802 # The base SimObject has a couple of params that get 803 # automatically set from Python without being declared through 804 # the normal Param mechanism; we slip them in here (needed 805 # predecls now, actual declarations below) 806 if cls == SimObject: 807 code('''#include <string>''') 808 809 # A forward class declaration is sufficient since we are just 810 # declaring a pointer. 811 for ns in class_path[:-1]: 812 code('namespace $ns {') 813 code('class $0;', class_path[-1]) 814 for ns in reversed(class_path[:-1]): 815 code('} // namespace $ns') 816 code() 817 818 for param in params: 819 param.cxx_predecls(code) 820 for port in ports.values(): 821 port.cxx_predecls(code) 822 code() 823 824 if cls._base: 825 code('#include "params/${{cls._base.type}}.hh"') 826 code() 827 828 for ptype in ptypes: 829 if issubclass(ptype, Enum): 830 code('#include "enums/${{ptype.__name__}}.hh"') 831 code() 832 833 # now generate the actual param struct 834 code("struct ${cls}Params") 835 if cls._base: 836 code(" : public ${{cls._base.type}}Params") 837 code("{") 838 if not hasattr(cls, 'abstract') or not cls.abstract: 839 if 'type' in cls.__dict__: 840 code(" ${{cls.cxx_type}} create();") 841 842 code.indent() 843 if cls == SimObject: 844 code(''' 845 SimObjectParams() {} 846 virtual ~SimObjectParams() {} 847 848 std::string name; 849 ''') 850 851 for param in params: 852 param.cxx_decl(code) 853 for port in ports.values(): 854 port.cxx_decl(code) 855 856 code.dedent() 857 code('};') 858 859 code() 860 code('#endif // __PARAMS__${cls}__') 861 return code 862 863 # Generate the C++ declaration/definition files for this SimObject's 864 # param struct to allow C++ initialisation 865 def cxx_config_param_file(cls, code, is_header): 866 createCxxConfigDirectoryEntryFile(code, cls.__name__, cls, is_header) 867 return code 868 869# This *temporary* definition is required to support calls from the 870# SimObject class definition to the MetaSimObject methods (in 871# particular _set_param, which gets called for parameters with default 872# values defined on the SimObject class itself). It will get 873# overridden by the permanent definition (which requires that 874# SimObject be defined) lower in this file. 875def isSimObjectOrVector(value): 876 return False 877 878def cxxMethod(*args, **kwargs): 879 """Decorator to export C++ functions to Python""" 880 881 def decorate(func): 882 name = func.__name__ 883 override = kwargs.get("override", False) 884 cxx_name = kwargs.get("cxx_name", name) 885 return_value_policy = kwargs.get("return_value_policy", None) 886 887 args, varargs, keywords, defaults = inspect.getargspec(func) 888 if varargs or keywords: 889 raise ValueError("Wrapped methods must not contain variable " \ 890 "arguments") 891 892 # Create tuples of (argument, default) 893 if defaults: 894 args = args[:-len(defaults)] + \ 895 list(zip(args[-len(defaults):], defaults)) 896 # Don't include self in the argument list to PyBind 897 args = args[1:] 898 899 900 @wraps(func) 901 def cxx_call(self, *args, **kwargs): 902 ccobj = self.getCCObject() 903 return getattr(ccobj, name)(*args, **kwargs) 904 905 @wraps(func) 906 def py_call(self, *args, **kwargs): 907 return func(self, *args, **kwargs) 908 909 f = py_call if override else cxx_call 910 f.__pybind = PyBindMethod(name, cxx_name=cxx_name, args=args, 911 return_value_policy=return_value_policy) 912 913 return f 914 915 if len(args) == 0: 916 return decorate 917 elif len(args) == 1 and len(kwargs) == 0: 918 return decorate(*args) 919 else: 920 raise TypeError("One argument and no kwargs, or only kwargs expected") 921 922# This class holds information about each simobject parameter 923# that should be displayed on the command line for use in the 924# configuration system. 925class ParamInfo(object): 926 def __init__(self, type, desc, type_str, example, default_val, access_str): 927 self.type = type 928 self.desc = desc 929 self.type_str = type_str 930 self.example_str = example 931 self.default_val = default_val 932 # The string representation used to access this param through python. 933 # The method to access this parameter presented on the command line may 934 # be different, so this needs to be stored for later use. 935 self.access_str = access_str 936 self.created = True 937 938 # Make it so we can only set attributes at initialization time 939 # and effectively make this a const object. 940 def __setattr__(self, name, value): 941 if not "created" in self.__dict__: 942 self.__dict__[name] = value 943 944class SimObjectCliWrapperException(Exception): 945 def __init__(self, message): 946 super(Exception, self).__init__(message) 947 948class SimObjectCliWrapper(object): 949 """ 950 Wrapper class to restrict operations that may be done 951 from the command line on SimObjects. 952 953 Only parameters may be set, and only children may be accessed. 954 955 Slicing allows for multiple simultaneous assignment of items in 956 one statement. 957 """ 958 959 def __init__(self, sim_objects): 960 self.__dict__['_sim_objects'] = list(sim_objects) 961 962 def __getattr__(self, key): 963 return SimObjectCliWrapper(sim_object._children[key] 964 for sim_object in self._sim_objects) 965 966 def __setattr__(self, key, val): 967 for sim_object in self._sim_objects: 968 if key in sim_object._params: 969 if sim_object._params[key].isCmdLineSettable(): 970 setattr(sim_object, key, val) 971 else: 972 raise SimObjectCliWrapperException( 973 'tried to set or unsettable' \ 974 'object parameter: ' + key) 975 else: 976 raise SimObjectCliWrapperException( 977 'tried to set or access non-existent' \ 978 'object parameter: ' + key) 979 980 def __getitem__(self, idx): 981 """ 982 Extends the list() semantics to also allow tuples, 983 for example object[1, 3] selects items 1 and 3. 984 """ 985 out = [] 986 if isinstance(idx, tuple): 987 for t in idx: 988 out.extend(self[t]._sim_objects) 989 else: 990 if isinstance(idx, int): 991 _range = range(idx, idx + 1) 992 elif not isinstance(idx, slice): 993 raise SimObjectCliWrapperException( \ 994 'invalid index type: ' + repr(idx)) 995 for sim_object in self._sim_objects: 996 if isinstance(idx, slice): 997 _range = range(*idx.indices(len(sim_object))) 998 out.extend(sim_object[i] for i in _range) 999 return SimObjectCliWrapper(out) 1000 1001# The SimObject class is the root of the special hierarchy. Most of 1002# the code in this class deals with the configuration hierarchy itself 1003# (parent/child node relationships). 1004class SimObject(object): 1005 # Specify metaclass. Any class inheriting from SimObject will 1006 # get this metaclass. 1007 __metaclass__ = MetaSimObject 1008 type = 'SimObject' 1009 abstract = True 1010 1011 cxx_header = "sim/sim_object.hh" 1012 cxx_extra_bases = [ "Drainable", "Serializable" ] 1013 eventq_index = Param.UInt32(Parent.eventq_index, "Event Queue Index") 1014 1015 cxx_exports = [ 1016 PyBindMethod("init"), 1017 PyBindMethod("initState"), 1018 PyBindMethod("memInvalidate"), 1019 PyBindMethod("memWriteback"), 1020 PyBindMethod("regStats"), 1021 PyBindMethod("resetStats"), 1022 PyBindMethod("regProbePoints"), 1023 PyBindMethod("regProbeListeners"), 1024 PyBindMethod("startup"), 1025 ] 1026 1027 cxx_param_exports = [ 1028 PyBindProperty("name"), 1029 ] 1030 1031 @cxxMethod 1032 def loadState(self, cp): 1033 """Load SimObject state from a checkpoint""" 1034 pass 1035 1036 # Returns a dict of all the option strings that can be 1037 # generated as command line options for this simobject instance 1038 # by tracing all reachable params in the top level instance and 1039 # any children it contains. 1040 def enumerateParams(self, flags_dict = {}, 1041 cmd_line_str = "", access_str = ""): 1042 if hasattr(self, "_paramEnumed"): 1043 print("Cycle detected enumerating params") 1044 else: 1045 self._paramEnumed = True 1046 # Scan the children first to pick up all the objects in this SimObj 1047 for keys in self._children: 1048 child = self._children[keys] 1049 next_cmdline_str = cmd_line_str + keys 1050 next_access_str = access_str + keys 1051 if not isSimObjectVector(child): 1052 next_cmdline_str = next_cmdline_str + "." 1053 next_access_str = next_access_str + "." 1054 flags_dict = child.enumerateParams(flags_dict, 1055 next_cmdline_str, 1056 next_access_str) 1057 1058 # Go through the simple params in the simobject in this level 1059 # of the simobject hierarchy and save information about the 1060 # parameter to be used for generating and processing command line 1061 # options to the simulator to set these parameters. 1062 for keys,values in self._params.items(): 1063 if values.isCmdLineSettable(): 1064 type_str = '' 1065 ex_str = values.example_str() 1066 ptype = None 1067 if isinstance(values, VectorParamDesc): 1068 type_str = 'Vector_%s' % values.ptype_str 1069 ptype = values 1070 else: 1071 type_str = '%s' % values.ptype_str 1072 ptype = values.ptype 1073 1074 if keys in self._hr_values\ 1075 and keys in self._values\ 1076 and not isinstance(self._values[keys], 1077 m5.proxy.BaseProxy): 1078 cmd_str = cmd_line_str + keys 1079 acc_str = access_str + keys 1080 flags_dict[cmd_str] = ParamInfo(ptype, 1081 self._params[keys].desc, type_str, ex_str, 1082 values.pretty_print(self._hr_values[keys]), 1083 acc_str) 1084 elif not keys in self._hr_values\ 1085 and not keys in self._values: 1086 # Empty param 1087 cmd_str = cmd_line_str + keys 1088 acc_str = access_str + keys 1089 flags_dict[cmd_str] = ParamInfo(ptype, 1090 self._params[keys].desc, 1091 type_str, ex_str, '', acc_str) 1092 1093 return flags_dict 1094 1095 # Initialize new instance. For objects with SimObject-valued 1096 # children, we need to recursively clone the classes represented 1097 # by those param values as well in a consistent "deep copy"-style 1098 # fashion. That is, we want to make sure that each instance is 1099 # cloned only once, and that if there are multiple references to 1100 # the same original object, we end up with the corresponding 1101 # cloned references all pointing to the same cloned instance. 1102 def __init__(self, **kwargs): 1103 ancestor = kwargs.get('_ancestor') 1104 memo_dict = kwargs.get('_memo') 1105 if memo_dict is None: 1106 # prepare to memoize any recursively instantiated objects 1107 memo_dict = {} 1108 elif ancestor: 1109 # memoize me now to avoid problems with recursive calls 1110 memo_dict[ancestor] = self 1111 1112 if not ancestor: 1113 ancestor = self.__class__ 1114 ancestor._instantiated = True 1115 1116 # initialize required attributes 1117 self._parent = None 1118 self._name = None 1119 self._ccObject = None # pointer to C++ object 1120 self._ccParams = None 1121 self._instantiated = False # really "cloned" 1122 1123 # Clone children specified at class level. No need for a 1124 # multidict here since we will be cloning everything. 1125 # Do children before parameter values so that children that 1126 # are also param values get cloned properly. 1127 self._children = {} 1128 for key,val in ancestor._children.items(): 1129 self.add_child(key, val(_memo=memo_dict)) 1130 1131 # Inherit parameter values from class using multidict so 1132 # individual value settings can be overridden but we still 1133 # inherit late changes to non-overridden class values. 1134 self._values = multidict(ancestor._values) 1135 self._hr_values = multidict(ancestor._hr_values) 1136 # clone SimObject-valued parameters 1137 for key,val in ancestor._values.items(): 1138 val = tryAsSimObjectOrVector(val) 1139 if val is not None: 1140 self._values[key] = val(_memo=memo_dict) 1141 1142 # clone port references. no need to use a multidict here 1143 # since we will be creating new references for all ports. 1144 self._port_refs = {} 1145 for key,val in ancestor._port_refs.items(): 1146 self._port_refs[key] = val.clone(self, memo_dict) 1147 # apply attribute assignments from keyword args, if any 1148 for key,val in kwargs.items(): 1149 setattr(self, key, val) 1150 1151 # "Clone" the current instance by creating another instance of 1152 # this instance's class, but that inherits its parameter values 1153 # and port mappings from the current instance. If we're in a 1154 # "deep copy" recursive clone, check the _memo dict to see if 1155 # we've already cloned this instance. 1156 def __call__(self, **kwargs): 1157 memo_dict = kwargs.get('_memo') 1158 if memo_dict is None: 1159 # no memo_dict: must be top-level clone operation. 1160 # this is only allowed at the root of a hierarchy 1161 if self._parent: 1162 raise RuntimeError("attempt to clone object %s " \ 1163 "not at the root of a tree (parent = %s)" \ 1164 % (self, self._parent)) 1165 # create a new dict and use that. 1166 memo_dict = {} 1167 kwargs['_memo'] = memo_dict 1168 elif self in memo_dict: 1169 # clone already done & memoized 1170 return memo_dict[self] 1171 return self.__class__(_ancestor = self, **kwargs) 1172 1173 def _get_port_ref(self, attr): 1174 # Return reference that can be assigned to another port 1175 # via __setattr__. There is only ever one reference 1176 # object per port, but we create them lazily here. 1177 ref = self._port_refs.get(attr) 1178 if ref == None: 1179 ref = self._ports[attr].makeRef(self) 1180 self._port_refs[attr] = ref 1181 return ref 1182 1183 def __getattr__(self, attr): 1184 if attr in self._ports: 1185 return self._get_port_ref(attr) 1186 1187 if attr in self._values: 1188 return self._values[attr] 1189 1190 if attr in self._children: 1191 return self._children[attr] 1192 1193 # If the attribute exists on the C++ object, transparently 1194 # forward the reference there. This is typically used for 1195 # methods exported to Python (e.g., init(), and startup()) 1196 if self._ccObject and hasattr(self._ccObject, attr): 1197 return getattr(self._ccObject, attr) 1198 1199 err_string = "object '%s' has no attribute '%s'" \ 1200 % (self.__class__.__name__, attr) 1201 1202 if not self._ccObject: 1203 err_string += "\n (C++ object is not yet constructed," \ 1204 " so wrapped C++ methods are unavailable.)" 1205 1206 raise AttributeError(err_string) 1207 1208 # Set attribute (called on foo.attr = value when foo is an 1209 # instance of class cls). 1210 def __setattr__(self, attr, value): 1211 # normal processing for private attributes 1212 if attr.startswith('_'): 1213 object.__setattr__(self, attr, value) 1214 return 1215 1216 if attr in self._ports: 1217 # set up port connection 1218 self._get_port_ref(attr).connect(value) 1219 return 1220 1221 param = self._params.get(attr) 1222 if param: 1223 try: 1224 hr_value = value 1225 value = param.convert(value) 1226 except Exception as e: 1227 msg = "%s\nError setting param %s.%s to %s\n" % \ 1228 (e, self.__class__.__name__, attr, value) 1229 e.args = (msg, ) 1230 raise 1231 self._values[attr] = value 1232 # implicitly parent unparented objects assigned as params 1233 if isSimObjectOrVector(value) and not value.has_parent(): 1234 self.add_child(attr, value) 1235 # set the human-readable value dict if this is a param 1236 # with a literal value and is not being set as an object 1237 # or proxy. 1238 if not (isSimObjectOrVector(value) or\ 1239 isinstance(value, m5.proxy.BaseProxy)): 1240 self._hr_values[attr] = hr_value 1241 1242 return 1243 1244 # if RHS is a SimObject, it's an implicit child assignment 1245 if isSimObjectOrSequence(value): 1246 self.add_child(attr, value) 1247 return 1248 1249 # no valid assignment... raise exception 1250 raise AttributeError("Class %s has no parameter %s" \ 1251 % (self.__class__.__name__, attr)) 1252 1253 1254 # this hack allows tacking a '[0]' onto parameters that may or may 1255 # not be vectors, and always getting the first element (e.g. cpus) 1256 def __getitem__(self, key): 1257 if key == 0: 1258 return self 1259 raise IndexError("Non-zero index '%s' to SimObject" % key) 1260 1261 # this hack allows us to iterate over a SimObject that may 1262 # not be a vector, so we can call a loop over it and get just one 1263 # element. 1264 def __len__(self): 1265 return 1 1266 1267 # Also implemented by SimObjectVector 1268 def clear_parent(self, old_parent): 1269 assert self._parent is old_parent 1270 self._parent = None 1271 1272 # Also implemented by SimObjectVector 1273 def set_parent(self, parent, name): 1274 self._parent = parent 1275 self._name = name 1276 1277 # Return parent object of this SimObject, not implemented by 1278 # SimObjectVector because the elements in a SimObjectVector may not share 1279 # the same parent 1280 def get_parent(self): 1281 return self._parent 1282 1283 # Also implemented by SimObjectVector 1284 def get_name(self): 1285 return self._name 1286 1287 # Also implemented by SimObjectVector 1288 def has_parent(self): 1289 return self._parent is not None 1290 1291 # clear out child with given name. This code is not likely to be exercised. 1292 # See comment in add_child. 1293 def clear_child(self, name): 1294 child = self._children[name] 1295 child.clear_parent(self) 1296 del self._children[name] 1297 1298 # Add a new child to this object. 1299 def add_child(self, name, child): 1300 child = coerceSimObjectOrVector(child) 1301 if child.has_parent(): 1302 warn("add_child('%s'): child '%s' already has parent", name, 1303 child.get_name()) 1304 if name in self._children: 1305 # This code path had an undiscovered bug that would make it fail 1306 # at runtime. It had been here for a long time and was only 1307 # exposed by a buggy script. Changes here will probably not be 1308 # exercised without specialized testing. 1309 self.clear_child(name) 1310 child.set_parent(self, name) 1311 if not isNullPointer(child): 1312 self._children[name] = child 1313 1314 # Take SimObject-valued parameters that haven't been explicitly 1315 # assigned as children and make them children of the object that 1316 # they were assigned to as a parameter value. This guarantees 1317 # that when we instantiate all the parameter objects we're still 1318 # inside the configuration hierarchy. 1319 def adoptOrphanParams(self): 1320 for key,val in self._values.items(): 1321 if not isSimObjectVector(val) and isSimObjectSequence(val): 1322 # need to convert raw SimObject sequences to 1323 # SimObjectVector class so we can call has_parent() 1324 val = SimObjectVector(val) 1325 self._values[key] = val 1326 if isSimObjectOrVector(val) and not val.has_parent(): 1327 warn("%s adopting orphan SimObject param '%s'", self, key) 1328 self.add_child(key, val) 1329 1330 def path(self): 1331 if not self._parent: 1332 return '<orphan %s>' % self.__class__ 1333 elif isinstance(self._parent, MetaSimObject): 1334 return str(self.__class__) 1335 1336 ppath = self._parent.path() 1337 if ppath == 'root': 1338 return self._name 1339 return ppath + "." + self._name 1340 1341 def __str__(self): 1342 return self.path() 1343 1344 def config_value(self): 1345 return self.path() 1346 1347 def ini_str(self): 1348 return self.path() 1349 1350 def find_any(self, ptype): 1351 if isinstance(self, ptype): 1352 return self, True 1353 1354 found_obj = None 1355 for child in self._children.values(): 1356 visited = False 1357 if hasattr(child, '_visited'): 1358 visited = getattr(child, '_visited') 1359 1360 if isinstance(child, ptype) and not visited: 1361 if found_obj != None and child != found_obj: 1362 raise AttributeError( 1363 'parent.any matched more than one: %s %s' % \ 1364 (found_obj.path, child.path)) 1365 found_obj = child 1366 # search param space 1367 for pname,pdesc in self._params.items(): 1368 if issubclass(pdesc.ptype, ptype): 1369 match_obj = self._values[pname] 1370 if found_obj != None and found_obj != match_obj: 1371 raise AttributeError( 1372 'parent.any matched more than one: %s and %s' % \ 1373 (found_obj.path, match_obj.path)) 1374 found_obj = match_obj 1375 return found_obj, found_obj != None 1376 1377 def find_all(self, ptype): 1378 all = {} 1379 # search children 1380 for child in self._children.values(): 1381 # a child could be a list, so ensure we visit each item 1382 if isinstance(child, list): 1383 children = child 1384 else: 1385 children = [child] 1386 1387 for child in children: 1388 if isinstance(child, ptype) and not isproxy(child) and \ 1389 not isNullPointer(child): 1390 all[child] = True 1391 if isSimObject(child): 1392 # also add results from the child itself 1393 child_all, done = child.find_all(ptype) 1394 all.update(dict(zip(child_all, [done] * len(child_all)))) 1395 # search param space 1396 for pname,pdesc in self._params.items(): 1397 if issubclass(pdesc.ptype, ptype): 1398 match_obj = self._values[pname] 1399 if not isproxy(match_obj) and not isNullPointer(match_obj): 1400 all[match_obj] = True 1401 # Also make sure to sort the keys based on the objects' path to 1402 # ensure that the order is the same on all hosts 1403 return sorted(all.keys(), key = lambda o: o.path()), True 1404 1405 def unproxy(self, base): 1406 return self 1407 1408 def unproxyParams(self): 1409 for param in self._params.keys(): 1410 value = self._values.get(param) 1411 if value != None and isproxy(value): 1412 try: 1413 value = value.unproxy(self) 1414 except: 1415 print("Error in unproxying param '%s' of %s" % 1416 (param, self.path())) 1417 raise 1418 setattr(self, param, value) 1419 1420 # Unproxy ports in sorted order so that 'append' operations on 1421 # vector ports are done in a deterministic fashion. 1422 port_names = list(self._ports.keys()) 1423 port_names.sort() 1424 for port_name in port_names: 1425 port = self._port_refs.get(port_name) 1426 if port != None: 1427 port.unproxy(self) 1428 1429 def print_ini(self, ini_file): 1430 print('[' + self.path() + ']', file=ini_file) # .ini section header 1431 1432 instanceDict[self.path()] = self 1433 1434 if hasattr(self, 'type'): 1435 print('type=%s' % self.type, file=ini_file) 1436 1437 if len(self._children.keys()): 1438 print('children=%s' % 1439 ' '.join(self._children[n].get_name() 1440 for n in sorted(self._children.keys())), 1441 file=ini_file) 1442 1443 for param in sorted(self._params.keys()): 1444 value = self._values.get(param) 1445 if value != None: 1446 print('%s=%s' % (param, self._values[param].ini_str()), 1447 file=ini_file) 1448 1449 for port_name in sorted(self._ports.keys()): 1450 port = self._port_refs.get(port_name, None) 1451 if port != None: 1452 print('%s=%s' % (port_name, port.ini_str()), file=ini_file) 1453 1454 print(file=ini_file) # blank line between objects 1455 1456 # generate a tree of dictionaries expressing all the parameters in the 1457 # instantiated system for use by scripts that want to do power, thermal 1458 # visualization, and other similar tasks 1459 def get_config_as_dict(self): 1460 d = attrdict() 1461 if hasattr(self, 'type'): 1462 d.type = self.type 1463 if hasattr(self, 'cxx_class'): 1464 d.cxx_class = self.cxx_class 1465 # Add the name and path of this object to be able to link to 1466 # the stats 1467 d.name = self.get_name() 1468 d.path = self.path() 1469 1470 for param in sorted(self._params.keys()): 1471 value = self._values.get(param) 1472 if value != None: 1473 d[param] = value.config_value() 1474 1475 for n in sorted(self._children.keys()): 1476 child = self._children[n] 1477 # Use the name of the attribute (and not get_name()) as 1478 # the key in the JSON dictionary to capture the hierarchy 1479 # in the Python code that assembled this system 1480 d[n] = child.get_config_as_dict() 1481 1482 for port_name in sorted(self._ports.keys()): 1483 port = self._port_refs.get(port_name, None) 1484 if port != None: 1485 # Represent each port with a dictionary containing the 1486 # prominent attributes 1487 d[port_name] = port.get_config_as_dict() 1488 1489 return d 1490 1491 def getCCParams(self): 1492 if self._ccParams: 1493 return self._ccParams 1494 1495 cc_params_struct = getattr(m5.internal.params, '%sParams' % self.type) 1496 cc_params = cc_params_struct() 1497 cc_params.name = str(self) 1498 1499 param_names = list(self._params.keys()) 1500 param_names.sort() 1501 for param in param_names: 1502 value = self._values.get(param) 1503 if value is None: 1504 fatal("%s.%s without default or user set value", 1505 self.path(), param) 1506 1507 value = value.getValue() 1508 if isinstance(self._params[param], VectorParamDesc): 1509 assert isinstance(value, list) 1510 vec = getattr(cc_params, param) 1511 assert not len(vec) 1512 # Some types are exposed as opaque types. They support 1513 # the append operation unlike the automatically 1514 # wrapped types. 1515 if isinstance(vec, list): 1516 setattr(cc_params, param, list(value)) 1517 else: 1518 for v in value: 1519 getattr(cc_params, param).append(v) 1520 else: 1521 setattr(cc_params, param, value) 1522 1523 port_names = list(self._ports.keys()) 1524 port_names.sort() 1525 for port_name in port_names: 1526 port = self._port_refs.get(port_name, None) 1527 if port != None: 1528 port_count = len(port) 1529 else: 1530 port_count = 0 1531 setattr(cc_params, 'port_' + port_name + '_connection_count', 1532 port_count) 1533 self._ccParams = cc_params 1534 return self._ccParams 1535 1536 # Get C++ object corresponding to this object, calling C++ if 1537 # necessary to construct it. Does *not* recursively create 1538 # children. 1539 def getCCObject(self): 1540 if not self._ccObject: 1541 # Make sure this object is in the configuration hierarchy 1542 if not self._parent and not isRoot(self): 1543 raise RuntimeError("Attempt to instantiate orphan node") 1544 # Cycles in the configuration hierarchy are not supported. This 1545 # will catch the resulting recursion and stop. 1546 self._ccObject = -1 1547 if not self.abstract: 1548 params = self.getCCParams() 1549 self._ccObject = params.create() 1550 elif self._ccObject == -1: 1551 raise RuntimeError("%s: Cycle found in configuration hierarchy." \ 1552 % self.path()) 1553 return self._ccObject 1554 1555 def descendants(self): 1556 yield self 1557 # The order of the dict is implementation dependent, so sort 1558 # it based on the key (name) to ensure the order is the same 1559 # on all hosts 1560 for (name, child) in sorted(self._children.items()): 1561 for obj in child.descendants(): 1562 yield obj 1563 1564 # Call C++ to create C++ object corresponding to this object 1565 def createCCObject(self): 1566 self.getCCParams() 1567 self.getCCObject() # force creation 1568 1569 def getValue(self): 1570 return self.getCCObject() 1571 1572 # Create C++ port connections corresponding to the connections in 1573 # _port_refs 1574 def connectPorts(self): 1575 # Sort the ports based on their attribute name to ensure the 1576 # order is the same on all hosts 1577 for (attr, portRef) in sorted(self._port_refs.items()): 1578 portRef.ccConnect() 1579 1580 # Default function for generating the device structure. 1581 # Can be overloaded by the inheriting class 1582 def generateDeviceTree(self, state): 1583 return # return without yielding anything 1584 yield # make this function a (null) generator 1585 1586 def recurseDeviceTree(self, state): 1587 for child in self._children.values(): 1588 for item in child: # For looping over SimObjectVectors 1589 for dt in item.generateDeviceTree(state): 1590 yield dt 1591 1592 # On a separate method otherwise certain buggy Python versions 1593 # would fail with: SyntaxError: unqualified exec is not allowed 1594 # in function 'apply_config' 1595 def _apply_config_get_dict(self): 1596 return { 1597 child_name: SimObjectCliWrapper( 1598 iter(self._children[child_name])) 1599 for child_name in self._children 1600 } 1601 1602 def apply_config(self, params): 1603 """ 1604 exec a list of Python code strings contained in params. 1605 1606 The only exposed globals to those strings are the child 1607 SimObjects of this node. 1608 1609 This function is intended to allow users to modify SimObject 1610 parameters from the command line with Python statements. 1611 """ 1612 d = self._apply_config_get_dict() 1613 for param in params: 1614 exec(param, d) 1615 1616# Function to provide to C++ so it can look up instances based on paths 1617def resolveSimObject(name): 1618 obj = instanceDict[name] 1619 return obj.getCCObject() 1620 1621def isSimObject(value): 1622 return isinstance(value, SimObject) 1623 1624def isSimObjectClass(value): 1625 return issubclass(value, SimObject) 1626 1627def isSimObjectVector(value): 1628 return isinstance(value, SimObjectVector) 1629 1630def isSimObjectSequence(value): 1631 if not isinstance(value, (list, tuple)) or len(value) == 0: 1632 return False 1633 1634 for val in value: 1635 if not isNullPointer(val) and not isSimObject(val): 1636 return False 1637 1638 return True 1639 1640def isSimObjectOrSequence(value): 1641 return isSimObject(value) or isSimObjectSequence(value) 1642 1643def isRoot(obj): 1644 from m5.objects import Root 1645 return obj and obj is Root.getInstance() 1646 1647def isSimObjectOrVector(value): 1648 return isSimObject(value) or isSimObjectVector(value) 1649 1650def tryAsSimObjectOrVector(value): 1651 if isSimObjectOrVector(value): 1652 return value 1653 if isSimObjectSequence(value): 1654 return SimObjectVector(value) 1655 return None 1656 1657def coerceSimObjectOrVector(value): 1658 value = tryAsSimObjectOrVector(value) 1659 if value is None: 1660 raise TypeError("SimObject or SimObjectVector expected") 1661 return value 1662 1663baseClasses = allClasses.copy() 1664baseInstances = instanceDict.copy() 1665 1666def clear(): 1667 global allClasses, instanceDict, noCxxHeader 1668 1669 allClasses = baseClasses.copy() 1670 instanceDict = baseInstances.copy() 1671 noCxxHeader = False 1672 1673# __all__ defines the list of symbols that get exported when 1674# 'from config import *' is invoked. Try to keep this reasonably 1675# short to avoid polluting other namespaces. 1676__all__ = [ 1677 'SimObject', 1678 'cxxMethod', 1679 'PyBindMethod', 1680 'PyBindProperty', 1681] 1682