SimObject.py revision 10458
112853Sgabeblack@google.com# Copyright (c) 2012 ARM Limited 212853Sgabeblack@google.com# All rights reserved. 312853Sgabeblack@google.com# 412853Sgabeblack@google.com# The license below extends only to copyright in the software and shall 512853Sgabeblack@google.com# not be construed as granting a license to any other intellectual 612853Sgabeblack@google.com# property including but not limited to intellectual property relating 712853Sgabeblack@google.com# to a hardware implementation of the functionality of the software 812853Sgabeblack@google.com# licensed hereunder. You may use the software subject to the license 912853Sgabeblack@google.com# terms below provided that you ensure that this notice is replicated 1012853Sgabeblack@google.com# unmodified and in its entirety in all distributions of the software, 1112853Sgabeblack@google.com# modified or unmodified, in source code or in binary form. 1212853Sgabeblack@google.com# 1312853Sgabeblack@google.com# Copyright (c) 2004-2006 The Regents of The University of Michigan 1412853Sgabeblack@google.com# Copyright (c) 2010-20013 Advanced Micro Devices, Inc. 1512853Sgabeblack@google.com# Copyright (c) 2013 Mark D. Hill and David A. Wood 1612853Sgabeblack@google.com# All rights reserved. 1712853Sgabeblack@google.com# 1812853Sgabeblack@google.com# Redistribution and use in source and binary forms, with or without 1912853Sgabeblack@google.com# modification, are permitted provided that the following conditions are 2012853Sgabeblack@google.com# met: redistributions of source code must retain the above copyright 2112853Sgabeblack@google.com# notice, this list of conditions and the following disclaimer; 2212853Sgabeblack@google.com# redistributions in binary form must reproduce the above copyright 2312853Sgabeblack@google.com# notice, this list of conditions and the following disclaimer in the 2412853Sgabeblack@google.com# documentation and/or other materials provided with the distribution; 2512853Sgabeblack@google.com# neither the name of the copyright holders nor the names of its 2612853Sgabeblack@google.com# contributors may be used to endorse or promote products derived from 2712853Sgabeblack@google.com# this software without specific prior written permission. 2812853Sgabeblack@google.com# 2912853Sgabeblack@google.com# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 3012853Sgabeblack@google.com# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3112853Sgabeblack@google.com# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 3212853Sgabeblack@google.com# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 3312853Sgabeblack@google.com# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3412853Sgabeblack@google.com# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3512853Sgabeblack@google.com# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3612853Sgabeblack@google.com# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3712853Sgabeblack@google.com# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3812853Sgabeblack@google.com# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3912853Sgabeblack@google.com# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 4012853Sgabeblack@google.com# 4112853Sgabeblack@google.com# Authors: Steve Reinhardt 4212853Sgabeblack@google.com# Nathan Binkert 4312853Sgabeblack@google.com# Andreas Hansson 4412853Sgabeblack@google.com 4512853Sgabeblack@google.comimport sys 4612853Sgabeblack@google.comfrom types import FunctionType, MethodType, ModuleType 4712853Sgabeblack@google.com 4812853Sgabeblack@google.comimport m5 4912853Sgabeblack@google.comfrom m5.util import * 5012853Sgabeblack@google.com 5112853Sgabeblack@google.com# Have to import params up top since Param is referenced on initial 5212853Sgabeblack@google.com# load (when SimObject class references Param to create a class 5312853Sgabeblack@google.com# variable, the 'name' param)... 5412853Sgabeblack@google.comfrom m5.params import * 5512853Sgabeblack@google.com# There are a few things we need that aren't in params.__all__ since 5612853Sgabeblack@google.com# normal users don't need them 5712853Sgabeblack@google.comfrom m5.params import ParamDesc, VectorParamDesc, \ 5812853Sgabeblack@google.com isNullPointer, SimObjectVector, Port 5912853Sgabeblack@google.com 6012853Sgabeblack@google.comfrom m5.proxy import * 6112853Sgabeblack@google.comfrom m5.proxy import isproxy 6212853Sgabeblack@google.com 6312853Sgabeblack@google.com##################################################################### 6412853Sgabeblack@google.com# 6512853Sgabeblack@google.com# M5 Python Configuration Utility 6612853Sgabeblack@google.com# 6712853Sgabeblack@google.com# The basic idea is to write simple Python programs that build Python 6812853Sgabeblack@google.com# objects corresponding to M5 SimObjects for the desired simulation 6912853Sgabeblack@google.com# configuration. For now, the Python emits a .ini file that can be 7012853Sgabeblack@google.com# parsed by M5. In the future, some tighter integration between M5 7112853Sgabeblack@google.com# and the Python interpreter may allow bypassing the .ini file. 7212853Sgabeblack@google.com# 7312853Sgabeblack@google.com# Each SimObject class in M5 is represented by a Python class with the 7412853Sgabeblack@google.com# same name. The Python inheritance tree mirrors the M5 C++ tree 7512853Sgabeblack@google.com# (e.g., SimpleCPU derives from BaseCPU in both cases, and all 7612853Sgabeblack@google.com# SimObjects inherit from a single SimObject base class). To specify 7712853Sgabeblack@google.com# an instance of an M5 SimObject in a configuration, the user simply 7812853Sgabeblack@google.com# instantiates the corresponding Python object. The parameters for 7912853Sgabeblack@google.com# that SimObject are given by assigning to attributes of the Python 8012853Sgabeblack@google.com# object, either using keyword assignment in the constructor or in 8112853Sgabeblack@google.com# separate assignment statements. For example: 8212853Sgabeblack@google.com# 8312853Sgabeblack@google.com# cache = BaseCache(size='64KB') 8412853Sgabeblack@google.com# cache.hit_latency = 3 8512853Sgabeblack@google.com# cache.assoc = 8 8612853Sgabeblack@google.com# 8712853Sgabeblack@google.com# The magic lies in the mapping of the Python attributes for SimObject 8812853Sgabeblack@google.com# classes to the actual SimObject parameter specifications. This 8912853Sgabeblack@google.com# allows parameter validity checking in the Python code. Continuing 9012853Sgabeblack@google.com# the example above, the statements "cache.blurfl=3" or 9112853Sgabeblack@google.com# "cache.assoc='hello'" would both result in runtime errors in Python, 9212853Sgabeblack@google.com# since the BaseCache object has no 'blurfl' parameter and the 'assoc' 9312853Sgabeblack@google.com# parameter requires an integer, respectively. This magic is done 9412853Sgabeblack@google.com# primarily by overriding the special __setattr__ method that controls 9512853Sgabeblack@google.com# assignment to object attributes. 9612853Sgabeblack@google.com# 9712853Sgabeblack@google.com# Once a set of Python objects have been instantiated in a hierarchy, 9812853Sgabeblack@google.com# calling 'instantiate(obj)' (where obj is the root of the hierarchy) 9912853Sgabeblack@google.com# will generate a .ini file. 10012853Sgabeblack@google.com# 10112853Sgabeblack@google.com##################################################################### 10212853Sgabeblack@google.com 10312853Sgabeblack@google.com# list of all SimObject classes 10412853Sgabeblack@google.comallClasses = {} 10512853Sgabeblack@google.com 10612853Sgabeblack@google.com# dict to look up SimObjects based on path 10712853Sgabeblack@google.cominstanceDict = {} 10812853Sgabeblack@google.com 10912853Sgabeblack@google.com# Did any of the SimObjects lack a header file? 11012853Sgabeblack@google.comnoCxxHeader = False 11112853Sgabeblack@google.com 11212853Sgabeblack@google.comdef public_value(key, value): 11312853Sgabeblack@google.com return key.startswith('_') or \ 11412853Sgabeblack@google.com isinstance(value, (FunctionType, MethodType, ModuleType, 11512853Sgabeblack@google.com classmethod, type)) 11612853Sgabeblack@google.com 11712853Sgabeblack@google.comdef createCxxConfigDirectoryEntryFile(code, name, simobj, is_header): 11812853Sgabeblack@google.com entry_class = 'CxxConfigDirectoryEntry_%s' % name 11912853Sgabeblack@google.com param_class = '%sCxxConfigParams' % name 12012853Sgabeblack@google.com 12112853Sgabeblack@google.com code('#include "params/%s.hh"' % name) 12212853Sgabeblack@google.com 12312853Sgabeblack@google.com if not is_header: 12412853Sgabeblack@google.com for param in simobj._params.values(): 12512853Sgabeblack@google.com if isSimObjectClass(param.ptype): 12612853Sgabeblack@google.com code('#include "%s"' % param.ptype._value_dict['cxx_header']) 12712853Sgabeblack@google.com code('#include "params/%s.hh"' % param.ptype.__name__) 12812853Sgabeblack@google.com else: 12912853Sgabeblack@google.com param.ptype.cxx_ini_predecls(code) 13012853Sgabeblack@google.com 13112853Sgabeblack@google.com if is_header: 13212853Sgabeblack@google.com member_prefix = '' 13312853Sgabeblack@google.com end_of_decl = ';' 13412853Sgabeblack@google.com code('#include "sim/cxx_config.hh"') 13512853Sgabeblack@google.com code() 13612853Sgabeblack@google.com code('class ${param_class} : public CxxConfigParams,' 13712853Sgabeblack@google.com ' public ${name}Params') 13812853Sgabeblack@google.com code('{') 13912853Sgabeblack@google.com code(' private:') 14012853Sgabeblack@google.com code.indent() 14112853Sgabeblack@google.com code('class DirectoryEntry : public CxxConfigDirectoryEntry') 14212853Sgabeblack@google.com code('{') 14312853Sgabeblack@google.com code(' public:') 14412853Sgabeblack@google.com code.indent() 14512853Sgabeblack@google.com code('DirectoryEntry();'); 14612853Sgabeblack@google.com code() 14712853Sgabeblack@google.com code('CxxConfigParams *makeParamsObject() const') 14812853Sgabeblack@google.com code('{ return new ${param_class}; }') 14912853Sgabeblack@google.com code.dedent() 15012853Sgabeblack@google.com code('};') 15112853Sgabeblack@google.com code() 15212853Sgabeblack@google.com code.dedent() 15312853Sgabeblack@google.com code(' public:') 15412853Sgabeblack@google.com code.indent() 15512853Sgabeblack@google.com else: 15612853Sgabeblack@google.com member_prefix = '%s::' % param_class 15712853Sgabeblack@google.com end_of_decl = '' 15812853Sgabeblack@google.com code('#include "%s"' % simobj._value_dict['cxx_header']) 15912853Sgabeblack@google.com code('#include "base/str.hh"') 16012853Sgabeblack@google.com code('#include "cxx_config/${name}.hh"') 16112853Sgabeblack@google.com 16212853Sgabeblack@google.com if simobj._ports.values() != []: 16312853Sgabeblack@google.com code('#include "mem/mem_object.hh"') 16412853Sgabeblack@google.com code('#include "mem/port.hh"') 16512853Sgabeblack@google.com 16612853Sgabeblack@google.com code() 16712853Sgabeblack@google.com code('${member_prefix}DirectoryEntry::DirectoryEntry()'); 16812853Sgabeblack@google.com code('{') 16912853Sgabeblack@google.com 17012853Sgabeblack@google.com def cxx_bool(b): 17112853Sgabeblack@google.com return 'true' if b else 'false' 17212853Sgabeblack@google.com 17312853Sgabeblack@google.com code.indent() 17412853Sgabeblack@google.com for param in simobj._params.values(): 17512853Sgabeblack@google.com is_vector = isinstance(param, m5.params.VectorParamDesc) 17612853Sgabeblack@google.com is_simobj = issubclass(param.ptype, m5.SimObject.SimObject) 17712853Sgabeblack@google.com 17812853Sgabeblack@google.com code('parameters["%s"] = new ParamDesc("%s", %s, %s);' % 17912853Sgabeblack@google.com (param.name, param.name, cxx_bool(is_vector), 18012853Sgabeblack@google.com cxx_bool(is_simobj))); 18112853Sgabeblack@google.com 18212853Sgabeblack@google.com for port in simobj._ports.values(): 18312853Sgabeblack@google.com is_vector = isinstance(port, m5.params.VectorPort) 18412853Sgabeblack@google.com is_master = port.role == 'MASTER' 18512853Sgabeblack@google.com 18612853Sgabeblack@google.com code('ports["%s"] = new PortDesc("%s", %s, %s);' % 18712853Sgabeblack@google.com (port.name, port.name, cxx_bool(is_vector), 18812853Sgabeblack@google.com cxx_bool(is_master))) 18912853Sgabeblack@google.com 19012853Sgabeblack@google.com code.dedent() 19112853Sgabeblack@google.com code('}') 19212853Sgabeblack@google.com code() 19312853Sgabeblack@google.com 19412853Sgabeblack@google.com code('bool ${member_prefix}setSimObject(const std::string &name,') 19512853Sgabeblack@google.com code(' SimObject *simObject)${end_of_decl}') 19612853Sgabeblack@google.com 19712853Sgabeblack@google.com if not is_header: 19812853Sgabeblack@google.com code('{') 19912853Sgabeblack@google.com code.indent() 20012853Sgabeblack@google.com code('bool ret = true;') 20112853Sgabeblack@google.com code() 20212853Sgabeblack@google.com code('if (false) {') 20312853Sgabeblack@google.com for param in simobj._params.values(): 20412853Sgabeblack@google.com is_vector = isinstance(param, m5.params.VectorParamDesc) 20512853Sgabeblack@google.com is_simobj = issubclass(param.ptype, m5.SimObject.SimObject) 20612853Sgabeblack@google.com 20712853Sgabeblack@google.com if is_simobj and not is_vector: 20812853Sgabeblack@google.com code('} else if (name == "${{param.name}}") {') 20912853Sgabeblack@google.com code.indent() 21012853Sgabeblack@google.com code('this->${{param.name}} = ' 21112853Sgabeblack@google.com 'dynamic_cast<${{param.ptype.cxx_type}}>(simObject);') 21212853Sgabeblack@google.com code('if (simObject && !this->${{param.name}})') 21312853Sgabeblack@google.com code(' ret = false;') 21412853Sgabeblack@google.com code.dedent() 21512853Sgabeblack@google.com code('} else {') 21612853Sgabeblack@google.com code(' ret = false;') 21712853Sgabeblack@google.com code('}') 21812853Sgabeblack@google.com code() 21912853Sgabeblack@google.com code('return ret;') 22012853Sgabeblack@google.com code.dedent() 22112853Sgabeblack@google.com code('}') 22212853Sgabeblack@google.com 22312853Sgabeblack@google.com code() 22412853Sgabeblack@google.com code('bool ${member_prefix}setSimObjectVector(' 22512853Sgabeblack@google.com 'const std::string &name,') 22612853Sgabeblack@google.com code(' const std::vector<SimObject *> &simObjects)${end_of_decl}') 22712853Sgabeblack@google.com 22812853Sgabeblack@google.com if not is_header: 22912853Sgabeblack@google.com code('{') 23012853Sgabeblack@google.com code.indent() 23112853Sgabeblack@google.com code('bool ret = true;') 23212853Sgabeblack@google.com code() 23312853Sgabeblack@google.com code('if (false) {') 23412853Sgabeblack@google.com for param in simobj._params.values(): 23512853Sgabeblack@google.com is_vector = isinstance(param, m5.params.VectorParamDesc) 23612853Sgabeblack@google.com is_simobj = issubclass(param.ptype, m5.SimObject.SimObject) 23712853Sgabeblack@google.com 23812853Sgabeblack@google.com if is_simobj and is_vector: 23912853Sgabeblack@google.com code('} else if (name == "${{param.name}}") {') 24012853Sgabeblack@google.com code.indent() 24112853Sgabeblack@google.com code('this->${{param.name}}.clear();') 24212853Sgabeblack@google.com code('for (auto i = simObjects.begin(); ' 24312853Sgabeblack@google.com 'ret && i != simObjects.end(); i ++)') 24412853Sgabeblack@google.com code('{') 24512853Sgabeblack@google.com code.indent() 24612853Sgabeblack@google.com code('${{param.ptype.cxx_type}} object = ' 24712853Sgabeblack@google.com 'dynamic_cast<${{param.ptype.cxx_type}}>(*i);') 24812853Sgabeblack@google.com code('if (*i && !object)') 24912853Sgabeblack@google.com code(' ret = false;') 25012853Sgabeblack@google.com code('else') 25112853Sgabeblack@google.com code(' this->${{param.name}}.push_back(object);') 25212853Sgabeblack@google.com code.dedent() 25312853Sgabeblack@google.com code('}') 25412853Sgabeblack@google.com code.dedent() 25512853Sgabeblack@google.com code('} else {') 25612853Sgabeblack@google.com code(' ret = false;') 25712853Sgabeblack@google.com code('}') 25812853Sgabeblack@google.com code() 25912853Sgabeblack@google.com code('return ret;') 26012853Sgabeblack@google.com code.dedent() 26112853Sgabeblack@google.com code('}') 26212853Sgabeblack@google.com 26312853Sgabeblack@google.com code() 26412853Sgabeblack@google.com code('void ${member_prefix}setName(const std::string &name_)' 26512853Sgabeblack@google.com '${end_of_decl}') 26612853Sgabeblack@google.com 26712853Sgabeblack@google.com if not is_header: 26812853Sgabeblack@google.com code('{') 26912853Sgabeblack@google.com code.indent() 27012853Sgabeblack@google.com code('this->name = name_;') 27112853Sgabeblack@google.com code('this->pyobj = NULL;') 27212853Sgabeblack@google.com code.dedent() 27312853Sgabeblack@google.com code('}') 27412853Sgabeblack@google.com 27512853Sgabeblack@google.com if is_header: 27612853Sgabeblack@google.com code('const std::string &${member_prefix}getName()') 27712853Sgabeblack@google.com code('{ return this->name; }') 27812853Sgabeblack@google.com 27912853Sgabeblack@google.com code() 28012853Sgabeblack@google.com code('bool ${member_prefix}setParam(const std::string &name,') 28112853Sgabeblack@google.com code(' const std::string &value, const Flags flags)${end_of_decl}') 28212853Sgabeblack@google.com 28312853Sgabeblack@google.com if not is_header: 28412853Sgabeblack@google.com code('{') 28512853Sgabeblack@google.com code.indent() 28612853Sgabeblack@google.com code('bool ret = true;') 28712853Sgabeblack@google.com code() 28812853Sgabeblack@google.com code('if (false) {') 28912853Sgabeblack@google.com for param in simobj._params.values(): 29012853Sgabeblack@google.com is_vector = isinstance(param, m5.params.VectorParamDesc) 29112853Sgabeblack@google.com is_simobj = issubclass(param.ptype, m5.SimObject.SimObject) 29212853Sgabeblack@google.com 29312853Sgabeblack@google.com if not is_simobj and not is_vector: 29412853Sgabeblack@google.com code('} else if (name == "${{param.name}}") {') 29512853Sgabeblack@google.com code.indent() 29612853Sgabeblack@google.com param.ptype.cxx_ini_parse(code, 29712853Sgabeblack@google.com 'value', 'this->%s' % param.name, 'ret =') 29812853Sgabeblack@google.com code.dedent() 29912853Sgabeblack@google.com code('} else {') 30012853Sgabeblack@google.com code(' ret = false;') 30112853Sgabeblack@google.com code('}') 30212853Sgabeblack@google.com code() 30312853Sgabeblack@google.com code('return ret;') 30412853Sgabeblack@google.com code.dedent() 30512853Sgabeblack@google.com code('}') 30612853Sgabeblack@google.com 30712853Sgabeblack@google.com code() 30812853Sgabeblack@google.com code('bool ${member_prefix}setParamVector(' 30912853Sgabeblack@google.com 'const std::string &name,') 31012853Sgabeblack@google.com code(' const std::vector<std::string> &values,') 31112853Sgabeblack@google.com code(' const Flags flags)${end_of_decl}') 31212853Sgabeblack@google.com 31312853Sgabeblack@google.com if not is_header: 31412853Sgabeblack@google.com code('{') 31512853Sgabeblack@google.com code.indent() 31612853Sgabeblack@google.com code('bool ret = true;') 31712853Sgabeblack@google.com code() 31812853Sgabeblack@google.com code('if (false) {') 31912853Sgabeblack@google.com for param in simobj._params.values(): 32012853Sgabeblack@google.com is_vector = isinstance(param, m5.params.VectorParamDesc) 32112853Sgabeblack@google.com is_simobj = issubclass(param.ptype, m5.SimObject.SimObject) 32212853Sgabeblack@google.com 32312853Sgabeblack@google.com if not is_simobj and is_vector: 32412853Sgabeblack@google.com code('} else if (name == "${{param.name}}") {') 32512853Sgabeblack@google.com code.indent() 32612853Sgabeblack@google.com code('${{param.name}}.clear();') 32712853Sgabeblack@google.com code('for (auto i = values.begin(); ' 32812853Sgabeblack@google.com 'ret && i != values.end(); i ++)') 32912853Sgabeblack@google.com code('{') 33012853Sgabeblack@google.com code.indent() 33112853Sgabeblack@google.com code('${{param.ptype.cxx_type}} elem;') 33212853Sgabeblack@google.com param.ptype.cxx_ini_parse(code, 33312853Sgabeblack@google.com '*i', 'elem', 'ret =') 33412853Sgabeblack@google.com code('if (ret)') 33512853Sgabeblack@google.com code(' this->${{param.name}}.push_back(elem);') 33612853Sgabeblack@google.com code.dedent() 33712853Sgabeblack@google.com code('}') 33812853Sgabeblack@google.com code.dedent() 33912853Sgabeblack@google.com code('} else {') 34012853Sgabeblack@google.com code(' ret = false;') 34112853Sgabeblack@google.com code('}') 34212853Sgabeblack@google.com code() 34312853Sgabeblack@google.com code('return ret;') 34412853Sgabeblack@google.com code.dedent() 34512853Sgabeblack@google.com code('}') 34612853Sgabeblack@google.com 34712853Sgabeblack@google.com code() 34812853Sgabeblack@google.com code('bool ${member_prefix}setPortConnectionCount(' 34912853Sgabeblack@google.com 'const std::string &name,') 35012853Sgabeblack@google.com code(' unsigned int count)${end_of_decl}') 35112853Sgabeblack@google.com 35212853Sgabeblack@google.com if not is_header: 35312853Sgabeblack@google.com code('{') 35412853Sgabeblack@google.com code.indent() 35512853Sgabeblack@google.com code('bool ret = true;') 35612853Sgabeblack@google.com code() 35712853Sgabeblack@google.com code('if (false)') 35812853Sgabeblack@google.com code(' ;') 35912853Sgabeblack@google.com for port in simobj._ports.values(): 36012853Sgabeblack@google.com code('else if (name == "${{port.name}}")') 36112853Sgabeblack@google.com code(' this->port_${{port.name}}_connection_count = count;') 36212853Sgabeblack@google.com code('else') 36312853Sgabeblack@google.com code(' ret = false;') 36412853Sgabeblack@google.com code() 36512853Sgabeblack@google.com code('return ret;') 36612853Sgabeblack@google.com code.dedent() 36712853Sgabeblack@google.com code('}') 36812853Sgabeblack@google.com 36912853Sgabeblack@google.com code() 37012853Sgabeblack@google.com code('SimObject *${member_prefix}simObjectCreate()${end_of_decl}') 37112853Sgabeblack@google.com 37212853Sgabeblack@google.com if not is_header: 37312853Sgabeblack@google.com code('{') 37412853Sgabeblack@google.com if hasattr(simobj, 'abstract') and simobj.abstract: 37512853Sgabeblack@google.com code(' return NULL;') 37612853Sgabeblack@google.com else: 37712853Sgabeblack@google.com code(' return this->create();') 37812853Sgabeblack@google.com code('}') 37912853Sgabeblack@google.com 38012853Sgabeblack@google.com if is_header: 38112853Sgabeblack@google.com code() 38212853Sgabeblack@google.com code('static CxxConfigDirectoryEntry' 38312853Sgabeblack@google.com ' *${member_prefix}makeDirectoryEntry()') 38412853Sgabeblack@google.com code('{ return new DirectoryEntry; }') 38512853Sgabeblack@google.com 38612853Sgabeblack@google.com if is_header: 38712853Sgabeblack@google.com code.dedent() 38812853Sgabeblack@google.com code('};') 38912853Sgabeblack@google.com 39012853Sgabeblack@google.com# The metaclass for SimObject. This class controls how new classes 39112853Sgabeblack@google.com# that derive from SimObject are instantiated, and provides inherited 39212853Sgabeblack@google.com# class behavior (just like a class controls how instances of that 39312853Sgabeblack@google.com# class are instantiated, and provides inherited instance behavior). 39412853Sgabeblack@google.comclass MetaSimObject(type): 39512853Sgabeblack@google.com # Attributes that can be set only at initialization time 39612853Sgabeblack@google.com init_keywords = { 'abstract' : bool, 39712853Sgabeblack@google.com 'cxx_class' : str, 39812853Sgabeblack@google.com 'cxx_type' : str, 39912853Sgabeblack@google.com 'cxx_header' : str, 40012853Sgabeblack@google.com 'type' : str, 40112853Sgabeblack@google.com 'cxx_bases' : list } 40212853Sgabeblack@google.com # Attributes that can be set any time 40312853Sgabeblack@google.com keywords = { 'check' : FunctionType } 40412853Sgabeblack@google.com 40512853Sgabeblack@google.com # __new__ is called before __init__, and is where the statements 40612853Sgabeblack@google.com # in the body of the class definition get loaded into the class's 40712853Sgabeblack@google.com # __dict__. We intercept this to filter out parameter & port assignments 40812853Sgabeblack@google.com # and only allow "private" attributes to be passed to the base 40912853Sgabeblack@google.com # __new__ (starting with underscore). 41012853Sgabeblack@google.com def __new__(mcls, name, bases, dict): 41112853Sgabeblack@google.com assert name not in allClasses, "SimObject %s already present" % name 41212853Sgabeblack@google.com 41312853Sgabeblack@google.com # Copy "private" attributes, functions, and classes to the 41412853Sgabeblack@google.com # official dict. Everything else goes in _init_dict to be 41512853Sgabeblack@google.com # filtered in __init__. 41612853Sgabeblack@google.com cls_dict = {} 41712853Sgabeblack@google.com value_dict = {} 41812853Sgabeblack@google.com for key,val in dict.items(): 41912853Sgabeblack@google.com if public_value(key, val): 42012853Sgabeblack@google.com cls_dict[key] = val 42112853Sgabeblack@google.com else: 42212853Sgabeblack@google.com # must be a param/port setting 42312853Sgabeblack@google.com value_dict[key] = val 42412853Sgabeblack@google.com if 'abstract' not in value_dict: 42512853Sgabeblack@google.com value_dict['abstract'] = False 42612853Sgabeblack@google.com if 'cxx_bases' not in value_dict: 42712853Sgabeblack@google.com value_dict['cxx_bases'] = [] 42812853Sgabeblack@google.com cls_dict['_value_dict'] = value_dict 42912853Sgabeblack@google.com cls = super(MetaSimObject, mcls).__new__(mcls, name, bases, cls_dict) 43012853Sgabeblack@google.com if 'type' in value_dict: 43112853Sgabeblack@google.com allClasses[name] = cls 43212853Sgabeblack@google.com return cls 43312853Sgabeblack@google.com 43412853Sgabeblack@google.com # subclass initialization 43512853Sgabeblack@google.com def __init__(cls, name, bases, dict): 43612853Sgabeblack@google.com # calls type.__init__()... I think that's a no-op, but leave 43712853Sgabeblack@google.com # it here just in case it's not. 43812853Sgabeblack@google.com super(MetaSimObject, cls).__init__(name, bases, dict) 43912853Sgabeblack@google.com 44012853Sgabeblack@google.com # initialize required attributes 44112853Sgabeblack@google.com 44212853Sgabeblack@google.com # class-only attributes 44312853Sgabeblack@google.com cls._params = multidict() # param descriptions 44412853Sgabeblack@google.com cls._ports = multidict() # port descriptions 44512853Sgabeblack@google.com 44612853Sgabeblack@google.com # class or instance attributes 44712853Sgabeblack@google.com cls._values = multidict() # param values 44812853Sgabeblack@google.com cls._hr_values = multidict() # human readable param values 44912853Sgabeblack@google.com cls._children = multidict() # SimObject children 45012853Sgabeblack@google.com cls._port_refs = multidict() # port ref objects 45112853Sgabeblack@google.com cls._instantiated = False # really instantiated, cloned, or subclassed 45212853Sgabeblack@google.com 45312853Sgabeblack@google.com # We don't support multiple inheritance of sim objects. If you want 45412853Sgabeblack@google.com # to, you must fix multidict to deal with it properly. Non sim-objects 45512853Sgabeblack@google.com # are ok, though 45612853Sgabeblack@google.com bTotal = 0 45712853Sgabeblack@google.com for c in bases: 45812853Sgabeblack@google.com if isinstance(c, MetaSimObject): 45912853Sgabeblack@google.com bTotal += 1 46012853Sgabeblack@google.com if bTotal > 1: 46112853Sgabeblack@google.com raise TypeError, "SimObjects do not support multiple inheritance" 46212853Sgabeblack@google.com 46312853Sgabeblack@google.com base = bases[0] 46412853Sgabeblack@google.com 46512853Sgabeblack@google.com # Set up general inheritance via multidicts. A subclass will 46612853Sgabeblack@google.com # inherit all its settings from the base class. The only time 46712853Sgabeblack@google.com # the following is not true is when we define the SimObject 46812853Sgabeblack@google.com # class itself (in which case the multidicts have no parent). 46912853Sgabeblack@google.com if isinstance(base, MetaSimObject): 47012853Sgabeblack@google.com cls._base = base 47112853Sgabeblack@google.com cls._params.parent = base._params 47212853Sgabeblack@google.com cls._ports.parent = base._ports 47312853Sgabeblack@google.com cls._values.parent = base._values 47412853Sgabeblack@google.com cls._hr_values.parent = base._hr_values 47512853Sgabeblack@google.com cls._children.parent = base._children 47612853Sgabeblack@google.com cls._port_refs.parent = base._port_refs 47712853Sgabeblack@google.com # mark base as having been subclassed 47812853Sgabeblack@google.com base._instantiated = True 47912853Sgabeblack@google.com else: 48012853Sgabeblack@google.com cls._base = None 48112853Sgabeblack@google.com 48212853Sgabeblack@google.com # default keyword values 48312853Sgabeblack@google.com if 'type' in cls._value_dict: 48412853Sgabeblack@google.com if 'cxx_class' not in cls._value_dict: 48512853Sgabeblack@google.com cls._value_dict['cxx_class'] = cls._value_dict['type'] 48612853Sgabeblack@google.com 48712853Sgabeblack@google.com cls._value_dict['cxx_type'] = '%s *' % cls._value_dict['cxx_class'] 48812853Sgabeblack@google.com 48912853Sgabeblack@google.com if 'cxx_header' not in cls._value_dict: 49012853Sgabeblack@google.com global noCxxHeader 49112853Sgabeblack@google.com noCxxHeader = True 49212853Sgabeblack@google.com warn("No header file specified for SimObject: %s", name) 49312853Sgabeblack@google.com 49412853Sgabeblack@google.com # Export methods are automatically inherited via C++, so we 49512853Sgabeblack@google.com # don't want the method declarations to get inherited on the 49612853Sgabeblack@google.com # python side (and thus end up getting repeated in the wrapped 49712853Sgabeblack@google.com # versions of derived classes). The code below basicallly 49812853Sgabeblack@google.com # suppresses inheritance by substituting in the base (null) 49912853Sgabeblack@google.com # versions of these methods unless a different version is 50012853Sgabeblack@google.com # explicitly supplied. 50112853Sgabeblack@google.com for method_name in ('export_methods', 'export_method_cxx_predecls', 50212853Sgabeblack@google.com 'export_method_swig_predecls'): 50312853Sgabeblack@google.com if method_name not in cls.__dict__: 50412853Sgabeblack@google.com base_method = getattr(MetaSimObject, method_name) 50512853Sgabeblack@google.com m = MethodType(base_method, cls, MetaSimObject) 50612853Sgabeblack@google.com setattr(cls, method_name, m) 50712853Sgabeblack@google.com 50812853Sgabeblack@google.com # Now process the _value_dict items. They could be defining 50912853Sgabeblack@google.com # new (or overriding existing) parameters or ports, setting 51012853Sgabeblack@google.com # class keywords (e.g., 'abstract'), or setting parameter 51112853Sgabeblack@google.com # values or port bindings. The first 3 can only be set when 51212853Sgabeblack@google.com # the class is defined, so we handle them here. The others 51312853Sgabeblack@google.com # can be set later too, so just emulate that by calling 51412853Sgabeblack@google.com # setattr(). 51512853Sgabeblack@google.com for key,val in cls._value_dict.items(): 51612853Sgabeblack@google.com # param descriptions 51712853Sgabeblack@google.com if isinstance(val, ParamDesc): 51812853Sgabeblack@google.com cls._new_param(key, val) 51912853Sgabeblack@google.com 52012853Sgabeblack@google.com # port objects 52112853Sgabeblack@google.com elif isinstance(val, Port): 52212853Sgabeblack@google.com cls._new_port(key, val) 52312853Sgabeblack@google.com 52412853Sgabeblack@google.com # init-time-only keywords 52512853Sgabeblack@google.com elif cls.init_keywords.has_key(key): 52612853Sgabeblack@google.com cls._set_keyword(key, val, cls.init_keywords[key]) 52712853Sgabeblack@google.com 52812853Sgabeblack@google.com # default: use normal path (ends up in __setattr__) 52912853Sgabeblack@google.com else: 53012853Sgabeblack@google.com setattr(cls, key, val) 53112853Sgabeblack@google.com 53212853Sgabeblack@google.com def _set_keyword(cls, keyword, val, kwtype): 53312853Sgabeblack@google.com if not isinstance(val, kwtype): 53412853Sgabeblack@google.com raise TypeError, 'keyword %s has bad type %s (expecting %s)' % \ 53512853Sgabeblack@google.com (keyword, type(val), kwtype) 53612853Sgabeblack@google.com if isinstance(val, FunctionType): 53712853Sgabeblack@google.com val = classmethod(val) 53812853Sgabeblack@google.com type.__setattr__(cls, keyword, val) 53912853Sgabeblack@google.com 54012853Sgabeblack@google.com def _new_param(cls, name, pdesc): 54112853Sgabeblack@google.com # each param desc should be uniquely assigned to one variable 54212853Sgabeblack@google.com assert(not hasattr(pdesc, 'name')) 54312853Sgabeblack@google.com pdesc.name = name 54412853Sgabeblack@google.com cls._params[name] = pdesc 54512853Sgabeblack@google.com if hasattr(pdesc, 'default'): 54612853Sgabeblack@google.com cls._set_param(name, pdesc.default, pdesc) 54712853Sgabeblack@google.com 54812853Sgabeblack@google.com def _set_param(cls, name, value, param): 54912853Sgabeblack@google.com assert(param.name == name) 55012853Sgabeblack@google.com try: 55112853Sgabeblack@google.com hr_value = value 55212853Sgabeblack@google.com value = param.convert(value) 55312853Sgabeblack@google.com except Exception, e: 55412853Sgabeblack@google.com msg = "%s\nError setting param %s.%s to %s\n" % \ 55512853Sgabeblack@google.com (e, cls.__name__, name, value) 55612853Sgabeblack@google.com e.args = (msg, ) 55712853Sgabeblack@google.com raise 55812853Sgabeblack@google.com cls._values[name] = value 55912853Sgabeblack@google.com # if param value is a SimObject, make it a child too, so that 56012853Sgabeblack@google.com # it gets cloned properly when the class is instantiated 56112853Sgabeblack@google.com if isSimObjectOrVector(value) and not value.has_parent(): 56212853Sgabeblack@google.com cls._add_cls_child(name, value) 56312853Sgabeblack@google.com # update human-readable values of the param if it has a literal 56412853Sgabeblack@google.com # value and is not an object or proxy. 56512853Sgabeblack@google.com if not (isSimObjectOrVector(value) or\ 56612853Sgabeblack@google.com isinstance(value, m5.proxy.BaseProxy)): 56712853Sgabeblack@google.com cls._hr_values[name] = hr_value 56812853Sgabeblack@google.com 56912853Sgabeblack@google.com def _add_cls_child(cls, name, child): 57012853Sgabeblack@google.com # It's a little funky to have a class as a parent, but these 57112853Sgabeblack@google.com # objects should never be instantiated (only cloned, which 57212853Sgabeblack@google.com # clears the parent pointer), and this makes it clear that the 57312853Sgabeblack@google.com # object is not an orphan and can provide better error 57412853Sgabeblack@google.com # messages. 57512853Sgabeblack@google.com child.set_parent(cls, name) 57612853Sgabeblack@google.com cls._children[name] = child 57712853Sgabeblack@google.com 57812853Sgabeblack@google.com def _new_port(cls, name, port): 57912853Sgabeblack@google.com # each port should be uniquely assigned to one variable 58012853Sgabeblack@google.com assert(not hasattr(port, 'name')) 58112853Sgabeblack@google.com port.name = name 58212853Sgabeblack@google.com cls._ports[name] = port 58312853Sgabeblack@google.com 58412853Sgabeblack@google.com # same as _get_port_ref, effectively, but for classes 58512853Sgabeblack@google.com def _cls_get_port_ref(cls, attr): 58612853Sgabeblack@google.com # Return reference that can be assigned to another port 58712853Sgabeblack@google.com # via __setattr__. There is only ever one reference 58812853Sgabeblack@google.com # object per port, but we create them lazily here. 58912853Sgabeblack@google.com ref = cls._port_refs.get(attr) 59012853Sgabeblack@google.com if not ref: 59112853Sgabeblack@google.com ref = cls._ports[attr].makeRef(cls) 59212853Sgabeblack@google.com cls._port_refs[attr] = ref 59312853Sgabeblack@google.com return ref 59412853Sgabeblack@google.com 59512853Sgabeblack@google.com # Set attribute (called on foo.attr = value when foo is an 59612853Sgabeblack@google.com # instance of class cls). 59712853Sgabeblack@google.com def __setattr__(cls, attr, value): 59812853Sgabeblack@google.com # normal processing for private attributes 59912853Sgabeblack@google.com if public_value(attr, value): 60012853Sgabeblack@google.com type.__setattr__(cls, attr, value) 60112853Sgabeblack@google.com return 60212853Sgabeblack@google.com 60312853Sgabeblack@google.com if cls.keywords.has_key(attr): 60412853Sgabeblack@google.com cls._set_keyword(attr, value, cls.keywords[attr]) 60512853Sgabeblack@google.com return 60612853Sgabeblack@google.com 60712853Sgabeblack@google.com if cls._ports.has_key(attr): 60812853Sgabeblack@google.com cls._cls_get_port_ref(attr).connect(value) 60912853Sgabeblack@google.com return 61012853Sgabeblack@google.com 61112853Sgabeblack@google.com if isSimObjectOrSequence(value) and cls._instantiated: 61212853Sgabeblack@google.com raise RuntimeError, \ 61312853Sgabeblack@google.com "cannot set SimObject parameter '%s' after\n" \ 61412853Sgabeblack@google.com " class %s has been instantiated or subclassed" \ 61512853Sgabeblack@google.com % (attr, cls.__name__) 61612853Sgabeblack@google.com 61712853Sgabeblack@google.com # check for param 61812853Sgabeblack@google.com param = cls._params.get(attr) 61912853Sgabeblack@google.com if param: 62012853Sgabeblack@google.com cls._set_param(attr, value, param) 62112853Sgabeblack@google.com return 62212853Sgabeblack@google.com 62312853Sgabeblack@google.com if isSimObjectOrSequence(value): 62412853Sgabeblack@google.com # If RHS is a SimObject, it's an implicit child assignment. 62512853Sgabeblack@google.com cls._add_cls_child(attr, coerceSimObjectOrVector(value)) 62612853Sgabeblack@google.com return 62712853Sgabeblack@google.com 62812853Sgabeblack@google.com # no valid assignment... raise exception 62912853Sgabeblack@google.com raise AttributeError, \ 63012853Sgabeblack@google.com "Class %s has no parameter \'%s\'" % (cls.__name__, attr) 63112853Sgabeblack@google.com 63212853Sgabeblack@google.com def __getattr__(cls, attr): 63312853Sgabeblack@google.com if attr == 'cxx_class_path': 63412853Sgabeblack@google.com return cls.cxx_class.split('::') 63512853Sgabeblack@google.com 63612853Sgabeblack@google.com if attr == 'cxx_class_name': 63712853Sgabeblack@google.com return cls.cxx_class_path[-1] 63812853Sgabeblack@google.com 63912853Sgabeblack@google.com if attr == 'cxx_namespaces': 64012853Sgabeblack@google.com return cls.cxx_class_path[:-1] 64112853Sgabeblack@google.com 64212853Sgabeblack@google.com if cls._values.has_key(attr): 64312853Sgabeblack@google.com return cls._values[attr] 64412853Sgabeblack@google.com 64512853Sgabeblack@google.com if cls._children.has_key(attr): 64612853Sgabeblack@google.com return cls._children[attr] 64712853Sgabeblack@google.com 64812853Sgabeblack@google.com raise AttributeError, \ 64912853Sgabeblack@google.com "object '%s' has no attribute '%s'" % (cls.__name__, attr) 65012853Sgabeblack@google.com 65112853Sgabeblack@google.com def __str__(cls): 65212853Sgabeblack@google.com return cls.__name__ 65312853Sgabeblack@google.com 65412853Sgabeblack@google.com # See ParamValue.cxx_predecls for description. 65512853Sgabeblack@google.com def cxx_predecls(cls, code): 65612853Sgabeblack@google.com code('#include "params/$cls.hh"') 65712853Sgabeblack@google.com 65812853Sgabeblack@google.com # See ParamValue.swig_predecls for description. 65912853Sgabeblack@google.com def swig_predecls(cls, code): 66012853Sgabeblack@google.com code('%import "python/m5/internal/param_$cls.i"') 66112853Sgabeblack@google.com 66212853Sgabeblack@google.com # Hook for exporting additional C++ methods to Python via SWIG. 66312853Sgabeblack@google.com # Default is none, override using @classmethod in class definition. 66412853Sgabeblack@google.com def export_methods(cls, code): 66512853Sgabeblack@google.com pass 66612853Sgabeblack@google.com 66712853Sgabeblack@google.com # Generate the code needed as a prerequisite for the C++ methods 66812853Sgabeblack@google.com # exported via export_methods() to be compiled in the _wrap.cc 66912853Sgabeblack@google.com # file. Typically generates one or more #include statements. If 67012853Sgabeblack@google.com # any methods are exported, typically at least the C++ header 67112853Sgabeblack@google.com # declaring the relevant SimObject class must be included. 67212853Sgabeblack@google.com def export_method_cxx_predecls(cls, code): 67312853Sgabeblack@google.com pass 67412853Sgabeblack@google.com 67512853Sgabeblack@google.com # Generate the code needed as a prerequisite for the C++ methods 67612853Sgabeblack@google.com # exported via export_methods() to be processed by SWIG. 67712853Sgabeblack@google.com # Typically generates one or more %include or %import statements. 67812853Sgabeblack@google.com # If any methods are exported, typically at least the C++ header 67912853Sgabeblack@google.com # declaring the relevant SimObject class must be included. 68012853Sgabeblack@google.com def export_method_swig_predecls(cls, code): 68112853Sgabeblack@google.com pass 68212853Sgabeblack@google.com 68312853Sgabeblack@google.com # Generate the declaration for this object for wrapping with SWIG. 68412853Sgabeblack@google.com # Generates code that goes into a SWIG .i file. Called from 68512853Sgabeblack@google.com # src/SConscript. 68612853Sgabeblack@google.com def swig_decl(cls, code): 68712853Sgabeblack@google.com class_path = cls.cxx_class.split('::') 68812853Sgabeblack@google.com classname = class_path[-1] 68912853Sgabeblack@google.com namespaces = class_path[:-1] 69012853Sgabeblack@google.com 69112853Sgabeblack@google.com # The 'local' attribute restricts us to the params declared in 69212853Sgabeblack@google.com # the object itself, not including inherited params (which 69312853Sgabeblack@google.com # will also be inherited from the base class's param struct 69412853Sgabeblack@google.com # here). 69512853Sgabeblack@google.com params = cls._params.local.values() 69612853Sgabeblack@google.com ports = cls._ports.local 69712853Sgabeblack@google.com 69812853Sgabeblack@google.com code('%module(package="m5.internal") param_$cls') 69912853Sgabeblack@google.com code() 70012853Sgabeblack@google.com code('%{') 70112853Sgabeblack@google.com code('#include "sim/sim_object.hh"') 70212853Sgabeblack@google.com code('#include "params/$cls.hh"') 70312853Sgabeblack@google.com for param in params: 70412853Sgabeblack@google.com param.cxx_predecls(code) 70512853Sgabeblack@google.com code('#include "${{cls.cxx_header}}"') 70612853Sgabeblack@google.com cls.export_method_cxx_predecls(code) 70712853Sgabeblack@google.com code('''\ 70812853Sgabeblack@google.com/** 70912853Sgabeblack@google.com * This is a workaround for bug in swig. Prior to gcc 4.6.1 the STL 71012853Sgabeblack@google.com * headers like vector, string, etc. used to automatically pull in 71112853Sgabeblack@google.com * the cstddef header but starting with gcc 4.6.1 they no longer do. 71212853Sgabeblack@google.com * This leads to swig generated a file that does not compile so we 71312853Sgabeblack@google.com * explicitly include cstddef. Additionally, including version 2.0.4, 71412853Sgabeblack@google.com * swig uses ptrdiff_t without the std:: namespace prefix which is 71512853Sgabeblack@google.com * required with gcc 4.6.1. We explicitly provide access to it. 71612853Sgabeblack@google.com */ 71712853Sgabeblack@google.com#include <cstddef> 71812853Sgabeblack@google.comusing std::ptrdiff_t; 71912853Sgabeblack@google.com''') 72012853Sgabeblack@google.com code('%}') 72112853Sgabeblack@google.com code() 72212853Sgabeblack@google.com 72312853Sgabeblack@google.com for param in params: 72412853Sgabeblack@google.com param.swig_predecls(code) 72512853Sgabeblack@google.com cls.export_method_swig_predecls(code) 72612853Sgabeblack@google.com 72712853Sgabeblack@google.com code() 72812853Sgabeblack@google.com if cls._base: 72912853Sgabeblack@google.com code('%import "python/m5/internal/param_${{cls._base}}.i"') 73012853Sgabeblack@google.com code() 73112853Sgabeblack@google.com 73212853Sgabeblack@google.com for ns in namespaces: 73312853Sgabeblack@google.com code('namespace $ns {') 73412853Sgabeblack@google.com 73512853Sgabeblack@google.com if namespaces: 73612853Sgabeblack@google.com code('// avoid name conflicts') 73712853Sgabeblack@google.com sep_string = '_COLONS_' 73812853Sgabeblack@google.com flat_name = sep_string.join(class_path) 73912853Sgabeblack@google.com code('%rename($flat_name) $classname;') 74012853Sgabeblack@google.com 74112853Sgabeblack@google.com code() 74212853Sgabeblack@google.com code('// stop swig from creating/wrapping default ctor/dtor') 74312853Sgabeblack@google.com code('%nodefault $classname;') 74412853Sgabeblack@google.com code('class $classname') 74512853Sgabeblack@google.com if cls._base: 74612853Sgabeblack@google.com bases = [ cls._base.cxx_class ] + cls.cxx_bases 74712853Sgabeblack@google.com else: 74812853Sgabeblack@google.com bases = cls.cxx_bases 74912853Sgabeblack@google.com base_first = True 75012853Sgabeblack@google.com for base in bases: 75112853Sgabeblack@google.com if base_first: 75212853Sgabeblack@google.com code(' : public ${{base}}') 75312853Sgabeblack@google.com base_first = False 75412853Sgabeblack@google.com else: 75512853Sgabeblack@google.com code(' , public ${{base}}') 75612853Sgabeblack@google.com 75712853Sgabeblack@google.com code('{') 75812853Sgabeblack@google.com code(' public:') 75912853Sgabeblack@google.com cls.export_methods(code) 76012853Sgabeblack@google.com code('};') 76112853Sgabeblack@google.com 76212853Sgabeblack@google.com for ns in reversed(namespaces): 76312853Sgabeblack@google.com code('} // namespace $ns') 76412853Sgabeblack@google.com 76512853Sgabeblack@google.com code() 76612853Sgabeblack@google.com code('%include "params/$cls.hh"') 76712853Sgabeblack@google.com 76812853Sgabeblack@google.com 76912853Sgabeblack@google.com # Generate the C++ declaration (.hh file) for this SimObject's 77012853Sgabeblack@google.com # param struct. Called from src/SConscript. 77112853Sgabeblack@google.com def cxx_param_decl(cls, code): 77212853Sgabeblack@google.com # The 'local' attribute restricts us to the params declared in 77312853Sgabeblack@google.com # the object itself, not including inherited params (which 77412853Sgabeblack@google.com # will also be inherited from the base class's param struct 77512853Sgabeblack@google.com # here). 77612853Sgabeblack@google.com params = cls._params.local.values() 77712853Sgabeblack@google.com ports = cls._ports.local 77812853Sgabeblack@google.com try: 77912853Sgabeblack@google.com ptypes = [p.ptype for p in params] 78012853Sgabeblack@google.com except: 78112853Sgabeblack@google.com print cls, p, p.ptype_str 78212853Sgabeblack@google.com print params 78312853Sgabeblack@google.com raise 78412853Sgabeblack@google.com 78512853Sgabeblack@google.com class_path = cls._value_dict['cxx_class'].split('::') 78612853Sgabeblack@google.com 78712853Sgabeblack@google.com code('''\ 78812853Sgabeblack@google.com#ifndef __PARAMS__${cls}__ 78912853Sgabeblack@google.com#define __PARAMS__${cls}__ 79012853Sgabeblack@google.com 79112853Sgabeblack@google.com''') 79212853Sgabeblack@google.com 79312853Sgabeblack@google.com # A forward class declaration is sufficient since we are just 79412853Sgabeblack@google.com # declaring a pointer. 79512853Sgabeblack@google.com for ns in class_path[:-1]: 79612853Sgabeblack@google.com code('namespace $ns {') 79712853Sgabeblack@google.com code('class $0;', class_path[-1]) 79812853Sgabeblack@google.com for ns in reversed(class_path[:-1]): 79912853Sgabeblack@google.com code('} // namespace $ns') 80012853Sgabeblack@google.com code() 80112853Sgabeblack@google.com 80212853Sgabeblack@google.com # The base SimObject has a couple of params that get 80312853Sgabeblack@google.com # automatically set from Python without being declared through 80412853Sgabeblack@google.com # the normal Param mechanism; we slip them in here (needed 80512853Sgabeblack@google.com # predecls now, actual declarations below) 80612853Sgabeblack@google.com if cls == SimObject: 80712853Sgabeblack@google.com code(''' 80812853Sgabeblack@google.com#ifndef PY_VERSION 80912853Sgabeblack@google.comstruct PyObject; 81012853Sgabeblack@google.com#endif 81112853Sgabeblack@google.com 81212853Sgabeblack@google.com#include <string> 81312853Sgabeblack@google.com''') 81412853Sgabeblack@google.com for param in params: 81512853Sgabeblack@google.com param.cxx_predecls(code) 81612853Sgabeblack@google.com for port in ports.itervalues(): 81712853Sgabeblack@google.com port.cxx_predecls(code) 81812853Sgabeblack@google.com code() 81912853Sgabeblack@google.com 82012853Sgabeblack@google.com if cls._base: 82112853Sgabeblack@google.com code('#include "params/${{cls._base.type}}.hh"') 82212853Sgabeblack@google.com code() 82312853Sgabeblack@google.com 82412853Sgabeblack@google.com for ptype in ptypes: 82512853Sgabeblack@google.com if issubclass(ptype, Enum): 82612853Sgabeblack@google.com code('#include "enums/${{ptype.__name__}}.hh"') 82712853Sgabeblack@google.com code() 82812853Sgabeblack@google.com 82912853Sgabeblack@google.com # now generate the actual param struct 83012853Sgabeblack@google.com code("struct ${cls}Params") 83112853Sgabeblack@google.com if cls._base: 83212853Sgabeblack@google.com code(" : public ${{cls._base.type}}Params") 83312853Sgabeblack@google.com code("{") 83412853Sgabeblack@google.com if not hasattr(cls, 'abstract') or not cls.abstract: 83512853Sgabeblack@google.com if 'type' in cls.__dict__: 83612853Sgabeblack@google.com code(" ${{cls.cxx_type}} create();") 83712853Sgabeblack@google.com 83812853Sgabeblack@google.com code.indent() 83912853Sgabeblack@google.com if cls == SimObject: 84012853Sgabeblack@google.com code(''' 84112853Sgabeblack@google.com SimObjectParams() {} 84212853Sgabeblack@google.com virtual ~SimObjectParams() {} 84312853Sgabeblack@google.com 84412853Sgabeblack@google.com std::string name; 84512853Sgabeblack@google.com PyObject *pyobj; 84612853Sgabeblack@google.com ''') 84712853Sgabeblack@google.com for param in params: 84812853Sgabeblack@google.com param.cxx_decl(code) 84912853Sgabeblack@google.com for port in ports.itervalues(): 85012853Sgabeblack@google.com port.cxx_decl(code) 85112853Sgabeblack@google.com 85212853Sgabeblack@google.com code.dedent() 85312853Sgabeblack@google.com code('};') 85412853Sgabeblack@google.com 85512853Sgabeblack@google.com code() 85612853Sgabeblack@google.com code('#endif // __PARAMS__${cls}__') 85712853Sgabeblack@google.com return code 85812853Sgabeblack@google.com 85912853Sgabeblack@google.com # Generate the C++ declaration/definition files for this SimObject's 86012853Sgabeblack@google.com # param struct to allow C++ initialisation 86112853Sgabeblack@google.com def cxx_config_param_file(cls, code, is_header): 86212853Sgabeblack@google.com createCxxConfigDirectoryEntryFile(code, cls.__name__, cls, is_header) 86312853Sgabeblack@google.com return code 86412853Sgabeblack@google.com 86512853Sgabeblack@google.com# This *temporary* definition is required to support calls from the 86612853Sgabeblack@google.com# SimObject class definition to the MetaSimObject methods (in 86712853Sgabeblack@google.com# particular _set_param, which gets called for parameters with default 86812853Sgabeblack@google.com# values defined on the SimObject class itself). It will get 86912853Sgabeblack@google.com# overridden by the permanent definition (which requires that 87012853Sgabeblack@google.com# SimObject be defined) lower in this file. 87112853Sgabeblack@google.comdef isSimObjectOrVector(value): 87212853Sgabeblack@google.com return False 87312853Sgabeblack@google.com 87412853Sgabeblack@google.com# This class holds information about each simobject parameter 87512853Sgabeblack@google.com# that should be displayed on the command line for use in the 87612853Sgabeblack@google.com# configuration system. 87712853Sgabeblack@google.comclass ParamInfo(object): 87812853Sgabeblack@google.com def __init__(self, type, desc, type_str, example, default_val, access_str): 87912853Sgabeblack@google.com self.type = type 88012853Sgabeblack@google.com self.desc = desc 88112853Sgabeblack@google.com self.type_str = type_str 88212853Sgabeblack@google.com self.example_str = example 88312853Sgabeblack@google.com self.default_val = default_val 88412853Sgabeblack@google.com # The string representation used to access this param through python. 88512853Sgabeblack@google.com # The method to access this parameter presented on the command line may 88612853Sgabeblack@google.com # be different, so this needs to be stored for later use. 88712853Sgabeblack@google.com self.access_str = access_str 88812853Sgabeblack@google.com self.created = True 88912853Sgabeblack@google.com 89012853Sgabeblack@google.com # Make it so we can only set attributes at initialization time 89112853Sgabeblack@google.com # and effectively make this a const object. 89212853Sgabeblack@google.com def __setattr__(self, name, value): 89312853Sgabeblack@google.com if not "created" in self.__dict__: 89412853Sgabeblack@google.com self.__dict__[name] = value 89512853Sgabeblack@google.com 89612853Sgabeblack@google.com# The SimObject class is the root of the special hierarchy. Most of 89712853Sgabeblack@google.com# the code in this class deals with the configuration hierarchy itself 89812853Sgabeblack@google.com# (parent/child node relationships). 89912853Sgabeblack@google.comclass SimObject(object): 90012853Sgabeblack@google.com # Specify metaclass. Any class inheriting from SimObject will 90112853Sgabeblack@google.com # get this metaclass. 90212853Sgabeblack@google.com __metaclass__ = MetaSimObject 90312853Sgabeblack@google.com type = 'SimObject' 90412853Sgabeblack@google.com abstract = True 90512853Sgabeblack@google.com 90612853Sgabeblack@google.com cxx_header = "sim/sim_object.hh" 90712853Sgabeblack@google.com cxx_bases = [ "Drainable", "Serializable" ] 90812853Sgabeblack@google.com eventq_index = Param.UInt32(Parent.eventq_index, "Event Queue Index") 90912853Sgabeblack@google.com 91012853Sgabeblack@google.com @classmethod 91112853Sgabeblack@google.com def export_method_swig_predecls(cls, code): 91212853Sgabeblack@google.com code(''' 91312853Sgabeblack@google.com%include <std_string.i> 91412853Sgabeblack@google.com 91512853Sgabeblack@google.com%import "python/swig/drain.i" 91612853Sgabeblack@google.com%import "python/swig/serialize.i" 91712853Sgabeblack@google.com''') 91812853Sgabeblack@google.com 91912853Sgabeblack@google.com @classmethod 92012853Sgabeblack@google.com def export_methods(cls, code): 92112853Sgabeblack@google.com code(''' 92212853Sgabeblack@google.com void init(); 92312853Sgabeblack@google.com void loadState(Checkpoint *cp); 92412853Sgabeblack@google.com void initState(); 92512853Sgabeblack@google.com void regStats(); 92612853Sgabeblack@google.com void resetStats(); 92712853Sgabeblack@google.com void regProbePoints(); 92812853Sgabeblack@google.com void regProbeListeners(); 92912853Sgabeblack@google.com void startup(); 93012853Sgabeblack@google.com''') 93112853Sgabeblack@google.com 93212853Sgabeblack@google.com # Returns a dict of all the option strings that can be 93312853Sgabeblack@google.com # generated as command line options for this simobject instance 93412853Sgabeblack@google.com # by tracing all reachable params in the top level instance and 93512853Sgabeblack@google.com # any children it contains. 93612853Sgabeblack@google.com def enumerateParams(self, flags_dict = {}, 93712853Sgabeblack@google.com cmd_line_str = "", access_str = ""): 93812853Sgabeblack@google.com if hasattr(self, "_paramEnumed"): 93912853Sgabeblack@google.com print "Cycle detected enumerating params" 94012853Sgabeblack@google.com else: 94112853Sgabeblack@google.com self._paramEnumed = True 94212853Sgabeblack@google.com # Scan the children first to pick up all the objects in this SimObj 94312853Sgabeblack@google.com for keys in self._children: 94412853Sgabeblack@google.com child = self._children[keys] 94512853Sgabeblack@google.com next_cmdline_str = cmd_line_str + keys 94612853Sgabeblack@google.com next_access_str = access_str + keys 94712853Sgabeblack@google.com if not isSimObjectVector(child): 94812853Sgabeblack@google.com next_cmdline_str = next_cmdline_str + "." 94912853Sgabeblack@google.com next_access_str = next_access_str + "." 95012853Sgabeblack@google.com flags_dict = child.enumerateParams(flags_dict, 95112853Sgabeblack@google.com next_cmdline_str, 95212853Sgabeblack@google.com next_access_str) 95312853Sgabeblack@google.com 95412853Sgabeblack@google.com # Go through the simple params in the simobject in this level 95512853Sgabeblack@google.com # of the simobject hierarchy and save information about the 95612853Sgabeblack@google.com # parameter to be used for generating and processing command line 95712853Sgabeblack@google.com # options to the simulator to set these parameters. 95812853Sgabeblack@google.com for keys,values in self._params.items(): 95912853Sgabeblack@google.com if values.isCmdLineSettable(): 96012853Sgabeblack@google.com type_str = '' 96112853Sgabeblack@google.com ex_str = values.example_str() 96212853Sgabeblack@google.com ptype = None 96312853Sgabeblack@google.com if isinstance(values, VectorParamDesc): 96412853Sgabeblack@google.com type_str = 'Vector_%s' % values.ptype_str 96512853Sgabeblack@google.com ptype = values 96612853Sgabeblack@google.com else: 96712853Sgabeblack@google.com type_str = '%s' % values.ptype_str 96812853Sgabeblack@google.com ptype = values.ptype 96912853Sgabeblack@google.com 97012853Sgabeblack@google.com if keys in self._hr_values\ 97112853Sgabeblack@google.com and keys in self._values\ 97212853Sgabeblack@google.com and not isinstance(self._values[keys], m5.proxy.BaseProxy): 97312853Sgabeblack@google.com cmd_str = cmd_line_str + keys 97412853Sgabeblack@google.com acc_str = access_str + keys 97512853Sgabeblack@google.com flags_dict[cmd_str] = ParamInfo(ptype, 97612853Sgabeblack@google.com self._params[keys].desc, type_str, ex_str, 97712853Sgabeblack@google.com values.pretty_print(self._hr_values[keys]), 97812853Sgabeblack@google.com acc_str) 97912853Sgabeblack@google.com elif not keys in self._hr_values\ 98012853Sgabeblack@google.com and not keys in self._values: 98112853Sgabeblack@google.com # Empty param 98212853Sgabeblack@google.com cmd_str = cmd_line_str + keys 98312853Sgabeblack@google.com acc_str = access_str + keys 98412853Sgabeblack@google.com flags_dict[cmd_str] = ParamInfo(ptype, 98512853Sgabeblack@google.com self._params[keys].desc, 98612853Sgabeblack@google.com type_str, ex_str, '', acc_str) 98712853Sgabeblack@google.com 98812853Sgabeblack@google.com return flags_dict 98912853Sgabeblack@google.com 99012853Sgabeblack@google.com # Initialize new instance. For objects with SimObject-valued 99112853Sgabeblack@google.com # children, we need to recursively clone the classes represented 99212853Sgabeblack@google.com # by those param values as well in a consistent "deep copy"-style 99312853Sgabeblack@google.com # fashion. That is, we want to make sure that each instance is 99412853Sgabeblack@google.com # cloned only once, and that if there are multiple references to 99512853Sgabeblack@google.com # the same original object, we end up with the corresponding 99612853Sgabeblack@google.com # cloned references all pointing to the same cloned instance. 99712853Sgabeblack@google.com def __init__(self, **kwargs): 99812853Sgabeblack@google.com ancestor = kwargs.get('_ancestor') 99912853Sgabeblack@google.com memo_dict = kwargs.get('_memo') 100012853Sgabeblack@google.com if memo_dict is None: 100112853Sgabeblack@google.com # prepare to memoize any recursively instantiated objects 100212853Sgabeblack@google.com memo_dict = {} 100312853Sgabeblack@google.com elif ancestor: 100412853Sgabeblack@google.com # memoize me now to avoid problems with recursive calls 100512853Sgabeblack@google.com memo_dict[ancestor] = self 100612853Sgabeblack@google.com 100712853Sgabeblack@google.com if not ancestor: 100812853Sgabeblack@google.com ancestor = self.__class__ 100912853Sgabeblack@google.com ancestor._instantiated = True 101012853Sgabeblack@google.com 101112853Sgabeblack@google.com # initialize required attributes 101212853Sgabeblack@google.com self._parent = None 101312853Sgabeblack@google.com self._name = None 101412853Sgabeblack@google.com self._ccObject = None # pointer to C++ object 101512853Sgabeblack@google.com self._ccParams = None 101612853Sgabeblack@google.com self._instantiated = False # really "cloned" 101712853Sgabeblack@google.com 101812853Sgabeblack@google.com # Clone children specified at class level. No need for a 101912853Sgabeblack@google.com # multidict here since we will be cloning everything. 102012853Sgabeblack@google.com # Do children before parameter values so that children that 102112853Sgabeblack@google.com # are also param values get cloned properly. 102212853Sgabeblack@google.com self._children = {} 102312853Sgabeblack@google.com for key,val in ancestor._children.iteritems(): 102412853Sgabeblack@google.com self.add_child(key, val(_memo=memo_dict)) 102512853Sgabeblack@google.com 102612853Sgabeblack@google.com # Inherit parameter values from class using multidict so 102712853Sgabeblack@google.com # individual value settings can be overridden but we still 102812853Sgabeblack@google.com # inherit late changes to non-overridden class values. 102912853Sgabeblack@google.com self._values = multidict(ancestor._values) 103012853Sgabeblack@google.com self._hr_values = multidict(ancestor._hr_values) 103112853Sgabeblack@google.com # clone SimObject-valued parameters 103212853Sgabeblack@google.com for key,val in ancestor._values.iteritems(): 103312853Sgabeblack@google.com val = tryAsSimObjectOrVector(val) 103412853Sgabeblack@google.com if val is not None: 103512853Sgabeblack@google.com self._values[key] = val(_memo=memo_dict) 103612853Sgabeblack@google.com 103712853Sgabeblack@google.com # clone port references. no need to use a multidict here 103812853Sgabeblack@google.com # since we will be creating new references for all ports. 103912853Sgabeblack@google.com self._port_refs = {} 104012853Sgabeblack@google.com for key,val in ancestor._port_refs.iteritems(): 104112853Sgabeblack@google.com self._port_refs[key] = val.clone(self, memo_dict) 104212853Sgabeblack@google.com # apply attribute assignments from keyword args, if any 104312853Sgabeblack@google.com for key,val in kwargs.iteritems(): 104412853Sgabeblack@google.com setattr(self, key, val) 104512853Sgabeblack@google.com 104612853Sgabeblack@google.com # "Clone" the current instance by creating another instance of 104712853Sgabeblack@google.com # this instance's class, but that inherits its parameter values 104812853Sgabeblack@google.com # and port mappings from the current instance. If we're in a 104912853Sgabeblack@google.com # "deep copy" recursive clone, check the _memo dict to see if 105012853Sgabeblack@google.com # we've already cloned this instance. 105112853Sgabeblack@google.com def __call__(self, **kwargs): 105212853Sgabeblack@google.com memo_dict = kwargs.get('_memo') 105312853Sgabeblack@google.com if memo_dict is None: 105412853Sgabeblack@google.com # no memo_dict: must be top-level clone operation. 105512853Sgabeblack@google.com # this is only allowed at the root of a hierarchy 105612853Sgabeblack@google.com if self._parent: 105712853Sgabeblack@google.com raise RuntimeError, "attempt to clone object %s " \ 105812853Sgabeblack@google.com "not at the root of a tree (parent = %s)" \ 105912853Sgabeblack@google.com % (self, self._parent) 106012853Sgabeblack@google.com # create a new dict and use that. 106112853Sgabeblack@google.com memo_dict = {} 106212853Sgabeblack@google.com kwargs['_memo'] = memo_dict 106312853Sgabeblack@google.com elif memo_dict.has_key(self): 106412853Sgabeblack@google.com # clone already done & memoized 106512853Sgabeblack@google.com return memo_dict[self] 106612853Sgabeblack@google.com return self.__class__(_ancestor = self, **kwargs) 106712853Sgabeblack@google.com 106812853Sgabeblack@google.com def _get_port_ref(self, attr): 106912853Sgabeblack@google.com # Return reference that can be assigned to another port 107012853Sgabeblack@google.com # via __setattr__. There is only ever one reference 107112853Sgabeblack@google.com # object per port, but we create them lazily here. 107212853Sgabeblack@google.com ref = self._port_refs.get(attr) 107312853Sgabeblack@google.com if ref == None: 107412853Sgabeblack@google.com ref = self._ports[attr].makeRef(self) 107512853Sgabeblack@google.com self._port_refs[attr] = ref 107612853Sgabeblack@google.com return ref 107712853Sgabeblack@google.com 107812853Sgabeblack@google.com def __getattr__(self, attr): 107912853Sgabeblack@google.com if self._ports.has_key(attr): 108012853Sgabeblack@google.com return self._get_port_ref(attr) 108112853Sgabeblack@google.com 108212853Sgabeblack@google.com if self._values.has_key(attr): 108312853Sgabeblack@google.com return self._values[attr] 108412853Sgabeblack@google.com 108512853Sgabeblack@google.com if self._children.has_key(attr): 108612853Sgabeblack@google.com return self._children[attr] 108712853Sgabeblack@google.com 108812853Sgabeblack@google.com # If the attribute exists on the C++ object, transparently 108912853Sgabeblack@google.com # forward the reference there. This is typically used for 109012853Sgabeblack@google.com # SWIG-wrapped methods such as init(), regStats(), 109112853Sgabeblack@google.com # resetStats(), startup(), drain(), and 109212853Sgabeblack@google.com # resume(). 109312853Sgabeblack@google.com if self._ccObject and hasattr(self._ccObject, attr): 109412853Sgabeblack@google.com return getattr(self._ccObject, attr) 109512853Sgabeblack@google.com 109612853Sgabeblack@google.com err_string = "object '%s' has no attribute '%s'" \ 109712853Sgabeblack@google.com % (self.__class__.__name__, attr) 109812853Sgabeblack@google.com 109912853Sgabeblack@google.com if not self._ccObject: 110012853Sgabeblack@google.com err_string += "\n (C++ object is not yet constructed," \ 110112853Sgabeblack@google.com " so wrapped C++ methods are unavailable.)" 110212853Sgabeblack@google.com 110312853Sgabeblack@google.com raise AttributeError, err_string 110412853Sgabeblack@google.com 110512853Sgabeblack@google.com # Set attribute (called on foo.attr = value when foo is an 110612853Sgabeblack@google.com # instance of class cls). 110712853Sgabeblack@google.com def __setattr__(self, attr, value): 110812853Sgabeblack@google.com # normal processing for private attributes 110912853Sgabeblack@google.com if attr.startswith('_'): 111012853Sgabeblack@google.com object.__setattr__(self, attr, value) 111112853Sgabeblack@google.com return 111212853Sgabeblack@google.com 111312853Sgabeblack@google.com if self._ports.has_key(attr): 111412853Sgabeblack@google.com # set up port connection 111512853Sgabeblack@google.com self._get_port_ref(attr).connect(value) 111612853Sgabeblack@google.com return 111712853Sgabeblack@google.com 111812853Sgabeblack@google.com param = self._params.get(attr) 111912853Sgabeblack@google.com if param: 112012853Sgabeblack@google.com try: 112112853Sgabeblack@google.com hr_value = value 112212853Sgabeblack@google.com value = param.convert(value) 112312853Sgabeblack@google.com except Exception, e: 112412853Sgabeblack@google.com msg = "%s\nError setting param %s.%s to %s\n" % \ 112512853Sgabeblack@google.com (e, self.__class__.__name__, attr, value) 112612853Sgabeblack@google.com e.args = (msg, ) 112712853Sgabeblack@google.com raise 112812853Sgabeblack@google.com self._values[attr] = value 112912853Sgabeblack@google.com # implicitly parent unparented objects assigned as params 113012853Sgabeblack@google.com if isSimObjectOrVector(value) and not value.has_parent(): 113112853Sgabeblack@google.com self.add_child(attr, value) 113212853Sgabeblack@google.com # set the human-readable value dict if this is a param 113312853Sgabeblack@google.com # with a literal value and is not being set as an object 113412853Sgabeblack@google.com # or proxy. 113512853Sgabeblack@google.com if not (isSimObjectOrVector(value) or\ 113612853Sgabeblack@google.com isinstance(value, m5.proxy.BaseProxy)): 113712853Sgabeblack@google.com self._hr_values[attr] = hr_value 113812853Sgabeblack@google.com 113912853Sgabeblack@google.com return 114012853Sgabeblack@google.com 114112853Sgabeblack@google.com # if RHS is a SimObject, it's an implicit child assignment 114212853Sgabeblack@google.com if isSimObjectOrSequence(value): 114312853Sgabeblack@google.com self.add_child(attr, value) 114412853Sgabeblack@google.com return 114512853Sgabeblack@google.com 114612853Sgabeblack@google.com # no valid assignment... raise exception 114712853Sgabeblack@google.com raise AttributeError, "Class %s has no parameter %s" \ 114812853Sgabeblack@google.com % (self.__class__.__name__, attr) 114912853Sgabeblack@google.com 115012853Sgabeblack@google.com 115112853Sgabeblack@google.com # this hack allows tacking a '[0]' onto parameters that may or may 115212853Sgabeblack@google.com # not be vectors, and always getting the first element (e.g. cpus) 115312853Sgabeblack@google.com def __getitem__(self, key): 115412853Sgabeblack@google.com if key == 0: 115512853Sgabeblack@google.com return self 115612853Sgabeblack@google.com raise IndexError, "Non-zero index '%s' to SimObject" % key 115712853Sgabeblack@google.com 115812853Sgabeblack@google.com # this hack allows us to iterate over a SimObject that may 115912853Sgabeblack@google.com # not be a vector, so we can call a loop over it and get just one 116012853Sgabeblack@google.com # element. 116112853Sgabeblack@google.com def __len__(self): 116212853Sgabeblack@google.com return 1 116312853Sgabeblack@google.com 116412853Sgabeblack@google.com # Also implemented by SimObjectVector 116512853Sgabeblack@google.com def clear_parent(self, old_parent): 116612853Sgabeblack@google.com assert self._parent is old_parent 116712853Sgabeblack@google.com self._parent = None 116812853Sgabeblack@google.com 116912853Sgabeblack@google.com # Also implemented by SimObjectVector 117012853Sgabeblack@google.com def set_parent(self, parent, name): 117112853Sgabeblack@google.com self._parent = parent 117212853Sgabeblack@google.com self._name = name 117312853Sgabeblack@google.com 117412853Sgabeblack@google.com # Return parent object of this SimObject, not implemented by SimObjectVector 117512853Sgabeblack@google.com # because the elements in a SimObjectVector may not share the same parent 117612853Sgabeblack@google.com def get_parent(self): 117712853Sgabeblack@google.com return self._parent 117812853Sgabeblack@google.com 117912853Sgabeblack@google.com # Also implemented by SimObjectVector 118012853Sgabeblack@google.com def get_name(self): 118112853Sgabeblack@google.com return self._name 118212853Sgabeblack@google.com 118312853Sgabeblack@google.com # Also implemented by SimObjectVector 118412853Sgabeblack@google.com def has_parent(self): 118512853Sgabeblack@google.com return self._parent is not None 118612853Sgabeblack@google.com 118712853Sgabeblack@google.com # clear out child with given name. This code is not likely to be exercised. 118812853Sgabeblack@google.com # See comment in add_child. 118912853Sgabeblack@google.com def clear_child(self, name): 119012853Sgabeblack@google.com child = self._children[name] 119112853Sgabeblack@google.com child.clear_parent(self) 119212853Sgabeblack@google.com del self._children[name] 119312853Sgabeblack@google.com 119412853Sgabeblack@google.com # Add a new child to this object. 119512853Sgabeblack@google.com def add_child(self, name, child): 119612853Sgabeblack@google.com child = coerceSimObjectOrVector(child) 119712853Sgabeblack@google.com if child.has_parent(): 119812853Sgabeblack@google.com warn("add_child('%s'): child '%s' already has parent", name, 119912853Sgabeblack@google.com child.get_name()) 120012853Sgabeblack@google.com if self._children.has_key(name): 120112853Sgabeblack@google.com # This code path had an undiscovered bug that would make it fail 120212853Sgabeblack@google.com # at runtime. It had been here for a long time and was only 120312853Sgabeblack@google.com # exposed by a buggy script. Changes here will probably not be 120412853Sgabeblack@google.com # exercised without specialized testing. 120512853Sgabeblack@google.com self.clear_child(name) 120612853Sgabeblack@google.com child.set_parent(self, name) 120712853Sgabeblack@google.com self._children[name] = child 120812853Sgabeblack@google.com 120912853Sgabeblack@google.com # Take SimObject-valued parameters that haven't been explicitly 121012853Sgabeblack@google.com # assigned as children and make them children of the object that 121112853Sgabeblack@google.com # they were assigned to as a parameter value. This guarantees 121212853Sgabeblack@google.com # that when we instantiate all the parameter objects we're still 121312853Sgabeblack@google.com # inside the configuration hierarchy. 121412853Sgabeblack@google.com def adoptOrphanParams(self): 121512853Sgabeblack@google.com for key,val in self._values.iteritems(): 121612853Sgabeblack@google.com if not isSimObjectVector(val) and isSimObjectSequence(val): 121712853Sgabeblack@google.com # need to convert raw SimObject sequences to 121812853Sgabeblack@google.com # SimObjectVector class so we can call has_parent() 121912853Sgabeblack@google.com val = SimObjectVector(val) 122012853Sgabeblack@google.com self._values[key] = val 122112853Sgabeblack@google.com if isSimObjectOrVector(val) and not val.has_parent(): 122212853Sgabeblack@google.com warn("%s adopting orphan SimObject param '%s'", self, key) 122312853Sgabeblack@google.com self.add_child(key, val) 122412853Sgabeblack@google.com 122512853Sgabeblack@google.com def path(self): 122612853Sgabeblack@google.com if not self._parent: 122712853Sgabeblack@google.com return '<orphan %s>' % self.__class__ 122812853Sgabeblack@google.com ppath = self._parent.path() 122912853Sgabeblack@google.com if ppath == 'root': 123012853Sgabeblack@google.com return self._name 123112853Sgabeblack@google.com return ppath + "." + self._name 123212853Sgabeblack@google.com 123312853Sgabeblack@google.com def __str__(self): 123412853Sgabeblack@google.com return self.path() 123512853Sgabeblack@google.com 123612853Sgabeblack@google.com def config_value(self): 123712853Sgabeblack@google.com return self.path() 123812853Sgabeblack@google.com 123912853Sgabeblack@google.com def ini_str(self): 124012853Sgabeblack@google.com return self.path() 124112853Sgabeblack@google.com 124212853Sgabeblack@google.com def find_any(self, ptype): 124312853Sgabeblack@google.com if isinstance(self, ptype): 124412853Sgabeblack@google.com return self, True 124512853Sgabeblack@google.com 124612853Sgabeblack@google.com found_obj = None 124712853Sgabeblack@google.com for child in self._children.itervalues(): 124812853Sgabeblack@google.com visited = False 124912853Sgabeblack@google.com if hasattr(child, '_visited'): 125012853Sgabeblack@google.com visited = getattr(child, '_visited') 125112853Sgabeblack@google.com 125212853Sgabeblack@google.com if isinstance(child, ptype) and not visited: 125312853Sgabeblack@google.com if found_obj != None and child != found_obj: 125412853Sgabeblack@google.com raise AttributeError, \ 125512853Sgabeblack@google.com 'parent.any matched more than one: %s %s' % \ 125612853Sgabeblack@google.com (found_obj.path, child.path) 125712853Sgabeblack@google.com found_obj = child 125812853Sgabeblack@google.com # search param space 125912853Sgabeblack@google.com for pname,pdesc in self._params.iteritems(): 126012853Sgabeblack@google.com if issubclass(pdesc.ptype, ptype): 126112853Sgabeblack@google.com match_obj = self._values[pname] 126212853Sgabeblack@google.com if found_obj != None and found_obj != match_obj: 126312853Sgabeblack@google.com raise AttributeError, \ 126412853Sgabeblack@google.com 'parent.any matched more than one: %s and %s' % (found_obj.path, match_obj.path) 126512853Sgabeblack@google.com found_obj = match_obj 126612853Sgabeblack@google.com return found_obj, found_obj != None 126712853Sgabeblack@google.com 126812853Sgabeblack@google.com def find_all(self, ptype): 126912853Sgabeblack@google.com all = {} 127012853Sgabeblack@google.com # search children 127112853Sgabeblack@google.com for child in self._children.itervalues(): 127212853Sgabeblack@google.com # a child could be a list, so ensure we visit each item 127312853Sgabeblack@google.com if isinstance(child, list): 127412853Sgabeblack@google.com children = child 127512853Sgabeblack@google.com else: 127612853Sgabeblack@google.com children = [child] 127712853Sgabeblack@google.com 127812853Sgabeblack@google.com for child in children: 127912853Sgabeblack@google.com if isinstance(child, ptype) and not isproxy(child) and \ 128012853Sgabeblack@google.com not isNullPointer(child): 128112853Sgabeblack@google.com all[child] = True 128212853Sgabeblack@google.com if isSimObject(child): 128312853Sgabeblack@google.com # also add results from the child itself 128412853Sgabeblack@google.com child_all, done = child.find_all(ptype) 128512853Sgabeblack@google.com all.update(dict(zip(child_all, [done] * len(child_all)))) 128612853Sgabeblack@google.com # search param space 128712853Sgabeblack@google.com for pname,pdesc in self._params.iteritems(): 128812853Sgabeblack@google.com if issubclass(pdesc.ptype, ptype): 128912853Sgabeblack@google.com match_obj = self._values[pname] 129012853Sgabeblack@google.com if not isproxy(match_obj) and not isNullPointer(match_obj): 129112853Sgabeblack@google.com all[match_obj] = True 129212853Sgabeblack@google.com return all.keys(), True 129312853Sgabeblack@google.com 129412853Sgabeblack@google.com def unproxy(self, base): 129512853Sgabeblack@google.com return self 129612853Sgabeblack@google.com 129712853Sgabeblack@google.com def unproxyParams(self): 129812853Sgabeblack@google.com for param in self._params.iterkeys(): 129912853Sgabeblack@google.com value = self._values.get(param) 130012853Sgabeblack@google.com if value != None and isproxy(value): 130112853Sgabeblack@google.com try: 130212853Sgabeblack@google.com value = value.unproxy(self) 130312853Sgabeblack@google.com except: 130412853Sgabeblack@google.com print "Error in unproxying param '%s' of %s" % \ 130512853Sgabeblack@google.com (param, self.path()) 130612853Sgabeblack@google.com raise 130712853Sgabeblack@google.com setattr(self, param, value) 130812853Sgabeblack@google.com 130912853Sgabeblack@google.com # Unproxy ports in sorted order so that 'append' operations on 131012853Sgabeblack@google.com # vector ports are done in a deterministic fashion. 131112853Sgabeblack@google.com port_names = self._ports.keys() 131212853Sgabeblack@google.com port_names.sort() 131312853Sgabeblack@google.com for port_name in port_names: 131412853Sgabeblack@google.com port = self._port_refs.get(port_name) 131512853Sgabeblack@google.com if port != None: 131612853Sgabeblack@google.com port.unproxy(self) 131712853Sgabeblack@google.com 131812853Sgabeblack@google.com def print_ini(self, ini_file): 131912853Sgabeblack@google.com print >>ini_file, '[' + self.path() + ']' # .ini section header 132012853Sgabeblack@google.com 132112853Sgabeblack@google.com instanceDict[self.path()] = self 132212853Sgabeblack@google.com 132312853Sgabeblack@google.com if hasattr(self, 'type'): 132412853Sgabeblack@google.com print >>ini_file, 'type=%s' % self.type 132512853Sgabeblack@google.com 132612853Sgabeblack@google.com if len(self._children.keys()): 132712853Sgabeblack@google.com print >>ini_file, 'children=%s' % \ 132812853Sgabeblack@google.com ' '.join(self._children[n].get_name() \ 132912853Sgabeblack@google.com for n in sorted(self._children.keys())) 133012853Sgabeblack@google.com 133112853Sgabeblack@google.com for param in sorted(self._params.keys()): 133212853Sgabeblack@google.com value = self._values.get(param) 133312853Sgabeblack@google.com if value != None: 133412853Sgabeblack@google.com print >>ini_file, '%s=%s' % (param, 133512853Sgabeblack@google.com self._values[param].ini_str()) 133612853Sgabeblack@google.com 133712853Sgabeblack@google.com for port_name in sorted(self._ports.keys()): 133812853Sgabeblack@google.com port = self._port_refs.get(port_name, None) 133912853Sgabeblack@google.com if port != None: 134012853Sgabeblack@google.com print >>ini_file, '%s=%s' % (port_name, port.ini_str()) 134112853Sgabeblack@google.com 134212853Sgabeblack@google.com print >>ini_file # blank line between objects 134312853Sgabeblack@google.com 134412853Sgabeblack@google.com # generate a tree of dictionaries expressing all the parameters in the 134512853Sgabeblack@google.com # instantiated system for use by scripts that want to do power, thermal 134612853Sgabeblack@google.com # visualization, and other similar tasks 134712853Sgabeblack@google.com def get_config_as_dict(self): 134812853Sgabeblack@google.com d = attrdict() 134912853Sgabeblack@google.com if hasattr(self, 'type'): 135012853Sgabeblack@google.com d.type = self.type 135112853Sgabeblack@google.com if hasattr(self, 'cxx_class'): 135212853Sgabeblack@google.com d.cxx_class = self.cxx_class 135312853Sgabeblack@google.com # Add the name and path of this object to be able to link to 135412853Sgabeblack@google.com # the stats 135512853Sgabeblack@google.com d.name = self.get_name() 135612853Sgabeblack@google.com d.path = self.path() 135712853Sgabeblack@google.com 135812853Sgabeblack@google.com for param in sorted(self._params.keys()): 135912853Sgabeblack@google.com value = self._values.get(param) 136012853Sgabeblack@google.com if value != None: 136112853Sgabeblack@google.com d[param] = value.config_value() 136212853Sgabeblack@google.com 136312853Sgabeblack@google.com for n in sorted(self._children.keys()): 136412853Sgabeblack@google.com child = self._children[n] 136512853Sgabeblack@google.com # Use the name of the attribute (and not get_name()) as 136612853Sgabeblack@google.com # the key in the JSON dictionary to capture the hierarchy 136712853Sgabeblack@google.com # in the Python code that assembled this system 136812853Sgabeblack@google.com d[n] = child.get_config_as_dict() 136912853Sgabeblack@google.com 137012853Sgabeblack@google.com for port_name in sorted(self._ports.keys()): 137112853Sgabeblack@google.com port = self._port_refs.get(port_name, None) 137212853Sgabeblack@google.com if port != None: 137312853Sgabeblack@google.com # Represent each port with a dictionary containing the 137412853Sgabeblack@google.com # prominent attributes 137512853Sgabeblack@google.com d[port_name] = port.get_config_as_dict() 137612853Sgabeblack@google.com 137712853Sgabeblack@google.com return d 137812853Sgabeblack@google.com 137912853Sgabeblack@google.com def getCCParams(self): 138012853Sgabeblack@google.com if self._ccParams: 138112853Sgabeblack@google.com return self._ccParams 138212853Sgabeblack@google.com 138312853Sgabeblack@google.com cc_params_struct = getattr(m5.internal.params, '%sParams' % self.type) 138412853Sgabeblack@google.com cc_params = cc_params_struct() 138512853Sgabeblack@google.com cc_params.pyobj = self 138612853Sgabeblack@google.com cc_params.name = str(self) 138712853Sgabeblack@google.com 138812853Sgabeblack@google.com param_names = self._params.keys() 138912853Sgabeblack@google.com param_names.sort() 139012853Sgabeblack@google.com for param in param_names: 139112853Sgabeblack@google.com value = self._values.get(param) 139212853Sgabeblack@google.com if value is None: 139312853Sgabeblack@google.com fatal("%s.%s without default or user set value", 139412853Sgabeblack@google.com self.path(), param) 139512853Sgabeblack@google.com 139612853Sgabeblack@google.com value = value.getValue() 139712853Sgabeblack@google.com if isinstance(self._params[param], VectorParamDesc): 139812853Sgabeblack@google.com assert isinstance(value, list) 139912853Sgabeblack@google.com vec = getattr(cc_params, param) 140012853Sgabeblack@google.com assert not len(vec) 140112853Sgabeblack@google.com for v in value: 140212853Sgabeblack@google.com vec.append(v) 140312853Sgabeblack@google.com else: 140412853Sgabeblack@google.com setattr(cc_params, param, value) 140512853Sgabeblack@google.com 140612853Sgabeblack@google.com port_names = self._ports.keys() 140712853Sgabeblack@google.com port_names.sort() 140812853Sgabeblack@google.com for port_name in port_names: 140912853Sgabeblack@google.com port = self._port_refs.get(port_name, None) 141012853Sgabeblack@google.com if port != None: 141112853Sgabeblack@google.com port_count = len(port) 141212853Sgabeblack@google.com else: 141312853Sgabeblack@google.com port_count = 0 141412853Sgabeblack@google.com setattr(cc_params, 'port_' + port_name + '_connection_count', 141512853Sgabeblack@google.com port_count) 141612853Sgabeblack@google.com self._ccParams = cc_params 141712853Sgabeblack@google.com return self._ccParams 141812853Sgabeblack@google.com 141912853Sgabeblack@google.com # Get C++ object corresponding to this object, calling C++ if 142012853Sgabeblack@google.com # necessary to construct it. Does *not* recursively create 142112853Sgabeblack@google.com # children. 142212853Sgabeblack@google.com def getCCObject(self): 142312853Sgabeblack@google.com if not self._ccObject: 142412853Sgabeblack@google.com # Make sure this object is in the configuration hierarchy 142512853Sgabeblack@google.com if not self._parent and not isRoot(self): 142612853Sgabeblack@google.com raise RuntimeError, "Attempt to instantiate orphan node" 142712853Sgabeblack@google.com # Cycles in the configuration hierarchy are not supported. This 142812853Sgabeblack@google.com # will catch the resulting recursion and stop. 142912853Sgabeblack@google.com self._ccObject = -1 143012853Sgabeblack@google.com if not self.abstract: 143112853Sgabeblack@google.com params = self.getCCParams() 143212853Sgabeblack@google.com self._ccObject = params.create() 143312853Sgabeblack@google.com elif self._ccObject == -1: 143412853Sgabeblack@google.com raise RuntimeError, "%s: Cycle found in configuration hierarchy." \ 143512853Sgabeblack@google.com % self.path() 143612853Sgabeblack@google.com return self._ccObject 143712853Sgabeblack@google.com 143812853Sgabeblack@google.com def descendants(self): 143912853Sgabeblack@google.com yield self 144012853Sgabeblack@google.com for child in self._children.itervalues(): 144112853Sgabeblack@google.com for obj in child.descendants(): 144212853Sgabeblack@google.com yield obj 144312853Sgabeblack@google.com 144412853Sgabeblack@google.com # Call C++ to create C++ object corresponding to this object 144512853Sgabeblack@google.com def createCCObject(self): 144612853Sgabeblack@google.com self.getCCParams() 144712853Sgabeblack@google.com self.getCCObject() # force creation 144812853Sgabeblack@google.com 144912853Sgabeblack@google.com def getValue(self): 145012853Sgabeblack@google.com return self.getCCObject() 145112853Sgabeblack@google.com 145212853Sgabeblack@google.com # Create C++ port connections corresponding to the connections in 145312853Sgabeblack@google.com # _port_refs 145412853Sgabeblack@google.com def connectPorts(self): 145512853Sgabeblack@google.com for portRef in self._port_refs.itervalues(): 145612853Sgabeblack@google.com portRef.ccConnect() 145712853Sgabeblack@google.com 145812853Sgabeblack@google.com# Function to provide to C++ so it can look up instances based on paths 145912853Sgabeblack@google.comdef resolveSimObject(name): 146012853Sgabeblack@google.com obj = instanceDict[name] 146112853Sgabeblack@google.com return obj.getCCObject() 146212853Sgabeblack@google.com 146312853Sgabeblack@google.comdef isSimObject(value): 146412853Sgabeblack@google.com return isinstance(value, SimObject) 146512853Sgabeblack@google.com 146612853Sgabeblack@google.comdef isSimObjectClass(value): 146712853Sgabeblack@google.com return issubclass(value, SimObject) 146812853Sgabeblack@google.com 146912853Sgabeblack@google.comdef isSimObjectVector(value): 147012853Sgabeblack@google.com return isinstance(value, SimObjectVector) 147112853Sgabeblack@google.com 147212853Sgabeblack@google.comdef isSimObjectSequence(value): 147312853Sgabeblack@google.com if not isinstance(value, (list, tuple)) or len(value) == 0: 147412853Sgabeblack@google.com return False 147512853Sgabeblack@google.com 147612853Sgabeblack@google.com for val in value: 147712853Sgabeblack@google.com if not isNullPointer(val) and not isSimObject(val): 147812853Sgabeblack@google.com return False 147912853Sgabeblack@google.com 148012853Sgabeblack@google.com return True 148112853Sgabeblack@google.com 148212853Sgabeblack@google.comdef isSimObjectOrSequence(value): 148312853Sgabeblack@google.com return isSimObject(value) or isSimObjectSequence(value) 148412853Sgabeblack@google.com 148512853Sgabeblack@google.comdef isRoot(obj): 148612853Sgabeblack@google.com from m5.objects import Root 148712853Sgabeblack@google.com return obj and obj is Root.getInstance() 148812853Sgabeblack@google.com 148912853Sgabeblack@google.comdef isSimObjectOrVector(value): 149012853Sgabeblack@google.com return isSimObject(value) or isSimObjectVector(value) 149112853Sgabeblack@google.com 149212853Sgabeblack@google.comdef tryAsSimObjectOrVector(value): 149312853Sgabeblack@google.com if isSimObjectOrVector(value): 149412853Sgabeblack@google.com return value 149512853Sgabeblack@google.com if isSimObjectSequence(value): 149612853Sgabeblack@google.com return SimObjectVector(value) 149712853Sgabeblack@google.com return None 149812853Sgabeblack@google.com 149912853Sgabeblack@google.comdef coerceSimObjectOrVector(value): 150012853Sgabeblack@google.com value = tryAsSimObjectOrVector(value) 150112853Sgabeblack@google.com if value is None: 150212853Sgabeblack@google.com raise TypeError, "SimObject or SimObjectVector expected" 150312853Sgabeblack@google.com return value 150412853Sgabeblack@google.com 150512853Sgabeblack@google.combaseClasses = allClasses.copy() 150612853Sgabeblack@google.combaseInstances = instanceDict.copy() 150712853Sgabeblack@google.com 150812853Sgabeblack@google.comdef clear(): 150912853Sgabeblack@google.com global allClasses, instanceDict, noCxxHeader 151012853Sgabeblack@google.com 151112853Sgabeblack@google.com allClasses = baseClasses.copy() 151212853Sgabeblack@google.com instanceDict = baseInstances.copy() 151312853Sgabeblack@google.com noCxxHeader = False 151412853Sgabeblack@google.com 151512853Sgabeblack@google.com# __all__ defines the list of symbols that get exported when 151612853Sgabeblack@google.com# 'from config import *' is invoked. Try to keep this reasonably 151712853Sgabeblack@google.com# short to avoid polluting other namespaces. 151812853Sgabeblack@google.com__all__ = [ 'SimObject' ] 151912853Sgabeblack@google.com