SimObject.py (11802:be62996c95d1) SimObject.py (11988:665cd5f8b52b)
1# Copyright (c) 2012 ARM Limited
1# Copyright (c) 2017 ARM Limited
2# All rights reserved.
3#
4# The license below extends only to copyright in the software and shall
5# not be construed as granting a license to any other intellectual
6# property including but not limited to intellectual property relating
7# to a hardware implementation of the functionality of the software
8# licensed hereunder. You may use the software subject to the license
9# terms below provided that you ensure that this notice is replicated
10# unmodified and in its entirety in all distributions of the software,
11# modified or unmodified, in source code or in binary form.
12#
13# Copyright (c) 2004-2006 The Regents of The University of Michigan
14# Copyright (c) 2010-20013 Advanced Micro Devices, Inc.
15# Copyright (c) 2013 Mark D. Hill and David A. Wood
16# All rights reserved.
17#
18# Redistribution and use in source and binary forms, with or without
19# modification, are permitted provided that the following conditions are
20# met: redistributions of source code must retain the above copyright
21# notice, this list of conditions and the following disclaimer;
22# redistributions in binary form must reproduce the above copyright
23# notice, this list of conditions and the following disclaimer in the
24# documentation and/or other materials provided with the distribution;
25# neither the name of the copyright holders nor the names of its
26# contributors may be used to endorse or promote products derived from
27# this software without specific prior written permission.
28#
29# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40#
41# Authors: Steve Reinhardt
42# Nathan Binkert
43# Andreas Hansson
2# All rights reserved.
3#
4# The license below extends only to copyright in the software and shall
5# not be construed as granting a license to any other intellectual
6# property including but not limited to intellectual property relating
7# to a hardware implementation of the functionality of the software
8# licensed hereunder. You may use the software subject to the license
9# terms below provided that you ensure that this notice is replicated
10# unmodified and in its entirety in all distributions of the software,
11# modified or unmodified, in source code or in binary form.
12#
13# Copyright (c) 2004-2006 The Regents of The University of Michigan
14# Copyright (c) 2010-20013 Advanced Micro Devices, Inc.
15# Copyright (c) 2013 Mark D. Hill and David A. Wood
16# All rights reserved.
17#
18# Redistribution and use in source and binary forms, with or without
19# modification, are permitted provided that the following conditions are
20# met: redistributions of source code must retain the above copyright
21# notice, this list of conditions and the following disclaimer;
22# redistributions in binary form must reproduce the above copyright
23# notice, this list of conditions and the following disclaimer in the
24# documentation and/or other materials provided with the distribution;
25# neither the name of the copyright holders nor the names of its
26# contributors may be used to endorse or promote products derived from
27# this software without specific prior written permission.
28#
29# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40#
41# Authors: Steve Reinhardt
42# Nathan Binkert
43# Andreas Hansson
44# Andreas Sandberg
44
45import sys
46from types import FunctionType, MethodType, ModuleType
45
46import sys
47from types import FunctionType, MethodType, ModuleType
48from functools import wraps
49import inspect
47
48import m5
49from m5.util import *
50
51import m5
52from m5.util import *
53from m5.util.pybind import *
50
51# Have to import params up top since Param is referenced on initial
52# load (when SimObject class references Param to create a class
53# variable, the 'name' param)...
54from m5.params import *
55# There are a few things we need that aren't in params.__all__ since
56# normal users don't need them
57from m5.params import ParamDesc, VectorParamDesc, \
58 isNullPointer, SimObjectVector, Port
59
60from m5.proxy import *
61from m5.proxy import isproxy
62
63#####################################################################
64#
65# M5 Python Configuration Utility
66#
67# The basic idea is to write simple Python programs that build Python
68# objects corresponding to M5 SimObjects for the desired simulation
69# configuration. For now, the Python emits a .ini file that can be
70# parsed by M5. In the future, some tighter integration between M5
71# and the Python interpreter may allow bypassing the .ini file.
72#
73# Each SimObject class in M5 is represented by a Python class with the
74# same name. The Python inheritance tree mirrors the M5 C++ tree
75# (e.g., SimpleCPU derives from BaseCPU in both cases, and all
76# SimObjects inherit from a single SimObject base class). To specify
77# an instance of an M5 SimObject in a configuration, the user simply
78# instantiates the corresponding Python object. The parameters for
79# that SimObject are given by assigning to attributes of the Python
80# object, either using keyword assignment in the constructor or in
81# separate assignment statements. For example:
82#
83# cache = BaseCache(size='64KB')
84# cache.hit_latency = 3
85# cache.assoc = 8
86#
87# The magic lies in the mapping of the Python attributes for SimObject
88# classes to the actual SimObject parameter specifications. This
89# allows parameter validity checking in the Python code. Continuing
90# the example above, the statements "cache.blurfl=3" or
91# "cache.assoc='hello'" would both result in runtime errors in Python,
92# since the BaseCache object has no 'blurfl' parameter and the 'assoc'
93# parameter requires an integer, respectively. This magic is done
94# primarily by overriding the special __setattr__ method that controls
95# assignment to object attributes.
96#
97# Once a set of Python objects have been instantiated in a hierarchy,
98# calling 'instantiate(obj)' (where obj is the root of the hierarchy)
99# will generate a .ini file.
100#
101#####################################################################
102
103# list of all SimObject classes
104allClasses = {}
105
106# dict to look up SimObjects based on path
107instanceDict = {}
108
109# Did any of the SimObjects lack a header file?
110noCxxHeader = False
111
112def public_value(key, value):
113 return key.startswith('_') or \
114 isinstance(value, (FunctionType, MethodType, ModuleType,
115 classmethod, type))
116
117def createCxxConfigDirectoryEntryFile(code, name, simobj, is_header):
118 entry_class = 'CxxConfigDirectoryEntry_%s' % name
119 param_class = '%sCxxConfigParams' % name
120
121 code('#include "params/%s.hh"' % name)
122
123 if not is_header:
124 for param in simobj._params.values():
125 if isSimObjectClass(param.ptype):
126 code('#include "%s"' % param.ptype._value_dict['cxx_header'])
127 code('#include "params/%s.hh"' % param.ptype.__name__)
128 else:
129 param.ptype.cxx_ini_predecls(code)
130
131 if is_header:
132 member_prefix = ''
133 end_of_decl = ';'
134 code('#include "sim/cxx_config.hh"')
135 code()
136 code('class ${param_class} : public CxxConfigParams,'
137 ' public ${name}Params')
138 code('{')
139 code(' private:')
140 code.indent()
141 code('class DirectoryEntry : public CxxConfigDirectoryEntry')
142 code('{')
143 code(' public:')
144 code.indent()
145 code('DirectoryEntry();');
146 code()
147 code('CxxConfigParams *makeParamsObject() const')
148 code('{ return new ${param_class}; }')
149 code.dedent()
150 code('};')
151 code()
152 code.dedent()
153 code(' public:')
154 code.indent()
155 else:
156 member_prefix = '%s::' % param_class
157 end_of_decl = ''
158 code('#include "%s"' % simobj._value_dict['cxx_header'])
159 code('#include "base/str.hh"')
160 code('#include "cxx_config/${name}.hh"')
161
162 if simobj._ports.values() != []:
163 code('#include "mem/mem_object.hh"')
164 code('#include "mem/port.hh"')
165
166 code()
167 code('${member_prefix}DirectoryEntry::DirectoryEntry()');
168 code('{')
169
170 def cxx_bool(b):
171 return 'true' if b else 'false'
172
173 code.indent()
174 for param in simobj._params.values():
175 is_vector = isinstance(param, m5.params.VectorParamDesc)
176 is_simobj = issubclass(param.ptype, m5.SimObject.SimObject)
177
178 code('parameters["%s"] = new ParamDesc("%s", %s, %s);' %
179 (param.name, param.name, cxx_bool(is_vector),
180 cxx_bool(is_simobj)));
181
182 for port in simobj._ports.values():
183 is_vector = isinstance(port, m5.params.VectorPort)
184 is_master = port.role == 'MASTER'
185
186 code('ports["%s"] = new PortDesc("%s", %s, %s);' %
187 (port.name, port.name, cxx_bool(is_vector),
188 cxx_bool(is_master)))
189
190 code.dedent()
191 code('}')
192 code()
193
194 code('bool ${member_prefix}setSimObject(const std::string &name,')
195 code(' SimObject *simObject)${end_of_decl}')
196
197 if not is_header:
198 code('{')
199 code.indent()
200 code('bool ret = true;')
201 code()
202 code('if (false) {')
203 for param in simobj._params.values():
204 is_vector = isinstance(param, m5.params.VectorParamDesc)
205 is_simobj = issubclass(param.ptype, m5.SimObject.SimObject)
206
207 if is_simobj and not is_vector:
208 code('} else if (name == "${{param.name}}") {')
209 code.indent()
210 code('this->${{param.name}} = '
211 'dynamic_cast<${{param.ptype.cxx_type}}>(simObject);')
212 code('if (simObject && !this->${{param.name}})')
213 code(' ret = false;')
214 code.dedent()
215 code('} else {')
216 code(' ret = false;')
217 code('}')
218 code()
219 code('return ret;')
220 code.dedent()
221 code('}')
222
223 code()
224 code('bool ${member_prefix}setSimObjectVector('
225 'const std::string &name,')
226 code(' const std::vector<SimObject *> &simObjects)${end_of_decl}')
227
228 if not is_header:
229 code('{')
230 code.indent()
231 code('bool ret = true;')
232 code()
233 code('if (false) {')
234 for param in simobj._params.values():
235 is_vector = isinstance(param, m5.params.VectorParamDesc)
236 is_simobj = issubclass(param.ptype, m5.SimObject.SimObject)
237
238 if is_simobj and is_vector:
239 code('} else if (name == "${{param.name}}") {')
240 code.indent()
241 code('this->${{param.name}}.clear();')
242 code('for (auto i = simObjects.begin(); '
243 'ret && i != simObjects.end(); i ++)')
244 code('{')
245 code.indent()
246 code('${{param.ptype.cxx_type}} object = '
247 'dynamic_cast<${{param.ptype.cxx_type}}>(*i);')
248 code('if (*i && !object)')
249 code(' ret = false;')
250 code('else')
251 code(' this->${{param.name}}.push_back(object);')
252 code.dedent()
253 code('}')
254 code.dedent()
255 code('} else {')
256 code(' ret = false;')
257 code('}')
258 code()
259 code('return ret;')
260 code.dedent()
261 code('}')
262
263 code()
264 code('void ${member_prefix}setName(const std::string &name_)'
265 '${end_of_decl}')
266
267 if not is_header:
268 code('{')
269 code.indent()
270 code('this->name = name_;')
54
55# Have to import params up top since Param is referenced on initial
56# load (when SimObject class references Param to create a class
57# variable, the 'name' param)...
58from m5.params import *
59# There are a few things we need that aren't in params.__all__ since
60# normal users don't need them
61from m5.params import ParamDesc, VectorParamDesc, \
62 isNullPointer, SimObjectVector, Port
63
64from m5.proxy import *
65from m5.proxy import isproxy
66
67#####################################################################
68#
69# M5 Python Configuration Utility
70#
71# The basic idea is to write simple Python programs that build Python
72# objects corresponding to M5 SimObjects for the desired simulation
73# configuration. For now, the Python emits a .ini file that can be
74# parsed by M5. In the future, some tighter integration between M5
75# and the Python interpreter may allow bypassing the .ini file.
76#
77# Each SimObject class in M5 is represented by a Python class with the
78# same name. The Python inheritance tree mirrors the M5 C++ tree
79# (e.g., SimpleCPU derives from BaseCPU in both cases, and all
80# SimObjects inherit from a single SimObject base class). To specify
81# an instance of an M5 SimObject in a configuration, the user simply
82# instantiates the corresponding Python object. The parameters for
83# that SimObject are given by assigning to attributes of the Python
84# object, either using keyword assignment in the constructor or in
85# separate assignment statements. For example:
86#
87# cache = BaseCache(size='64KB')
88# cache.hit_latency = 3
89# cache.assoc = 8
90#
91# The magic lies in the mapping of the Python attributes for SimObject
92# classes to the actual SimObject parameter specifications. This
93# allows parameter validity checking in the Python code. Continuing
94# the example above, the statements "cache.blurfl=3" or
95# "cache.assoc='hello'" would both result in runtime errors in Python,
96# since the BaseCache object has no 'blurfl' parameter and the 'assoc'
97# parameter requires an integer, respectively. This magic is done
98# primarily by overriding the special __setattr__ method that controls
99# assignment to object attributes.
100#
101# Once a set of Python objects have been instantiated in a hierarchy,
102# calling 'instantiate(obj)' (where obj is the root of the hierarchy)
103# will generate a .ini file.
104#
105#####################################################################
106
107# list of all SimObject classes
108allClasses = {}
109
110# dict to look up SimObjects based on path
111instanceDict = {}
112
113# Did any of the SimObjects lack a header file?
114noCxxHeader = False
115
116def public_value(key, value):
117 return key.startswith('_') or \
118 isinstance(value, (FunctionType, MethodType, ModuleType,
119 classmethod, type))
120
121def createCxxConfigDirectoryEntryFile(code, name, simobj, is_header):
122 entry_class = 'CxxConfigDirectoryEntry_%s' % name
123 param_class = '%sCxxConfigParams' % name
124
125 code('#include "params/%s.hh"' % name)
126
127 if not is_header:
128 for param in simobj._params.values():
129 if isSimObjectClass(param.ptype):
130 code('#include "%s"' % param.ptype._value_dict['cxx_header'])
131 code('#include "params/%s.hh"' % param.ptype.__name__)
132 else:
133 param.ptype.cxx_ini_predecls(code)
134
135 if is_header:
136 member_prefix = ''
137 end_of_decl = ';'
138 code('#include "sim/cxx_config.hh"')
139 code()
140 code('class ${param_class} : public CxxConfigParams,'
141 ' public ${name}Params')
142 code('{')
143 code(' private:')
144 code.indent()
145 code('class DirectoryEntry : public CxxConfigDirectoryEntry')
146 code('{')
147 code(' public:')
148 code.indent()
149 code('DirectoryEntry();');
150 code()
151 code('CxxConfigParams *makeParamsObject() const')
152 code('{ return new ${param_class}; }')
153 code.dedent()
154 code('};')
155 code()
156 code.dedent()
157 code(' public:')
158 code.indent()
159 else:
160 member_prefix = '%s::' % param_class
161 end_of_decl = ''
162 code('#include "%s"' % simobj._value_dict['cxx_header'])
163 code('#include "base/str.hh"')
164 code('#include "cxx_config/${name}.hh"')
165
166 if simobj._ports.values() != []:
167 code('#include "mem/mem_object.hh"')
168 code('#include "mem/port.hh"')
169
170 code()
171 code('${member_prefix}DirectoryEntry::DirectoryEntry()');
172 code('{')
173
174 def cxx_bool(b):
175 return 'true' if b else 'false'
176
177 code.indent()
178 for param in simobj._params.values():
179 is_vector = isinstance(param, m5.params.VectorParamDesc)
180 is_simobj = issubclass(param.ptype, m5.SimObject.SimObject)
181
182 code('parameters["%s"] = new ParamDesc("%s", %s, %s);' %
183 (param.name, param.name, cxx_bool(is_vector),
184 cxx_bool(is_simobj)));
185
186 for port in simobj._ports.values():
187 is_vector = isinstance(port, m5.params.VectorPort)
188 is_master = port.role == 'MASTER'
189
190 code('ports["%s"] = new PortDesc("%s", %s, %s);' %
191 (port.name, port.name, cxx_bool(is_vector),
192 cxx_bool(is_master)))
193
194 code.dedent()
195 code('}')
196 code()
197
198 code('bool ${member_prefix}setSimObject(const std::string &name,')
199 code(' SimObject *simObject)${end_of_decl}')
200
201 if not is_header:
202 code('{')
203 code.indent()
204 code('bool ret = true;')
205 code()
206 code('if (false) {')
207 for param in simobj._params.values():
208 is_vector = isinstance(param, m5.params.VectorParamDesc)
209 is_simobj = issubclass(param.ptype, m5.SimObject.SimObject)
210
211 if is_simobj and not is_vector:
212 code('} else if (name == "${{param.name}}") {')
213 code.indent()
214 code('this->${{param.name}} = '
215 'dynamic_cast<${{param.ptype.cxx_type}}>(simObject);')
216 code('if (simObject && !this->${{param.name}})')
217 code(' ret = false;')
218 code.dedent()
219 code('} else {')
220 code(' ret = false;')
221 code('}')
222 code()
223 code('return ret;')
224 code.dedent()
225 code('}')
226
227 code()
228 code('bool ${member_prefix}setSimObjectVector('
229 'const std::string &name,')
230 code(' const std::vector<SimObject *> &simObjects)${end_of_decl}')
231
232 if not is_header:
233 code('{')
234 code.indent()
235 code('bool ret = true;')
236 code()
237 code('if (false) {')
238 for param in simobj._params.values():
239 is_vector = isinstance(param, m5.params.VectorParamDesc)
240 is_simobj = issubclass(param.ptype, m5.SimObject.SimObject)
241
242 if is_simobj and is_vector:
243 code('} else if (name == "${{param.name}}") {')
244 code.indent()
245 code('this->${{param.name}}.clear();')
246 code('for (auto i = simObjects.begin(); '
247 'ret && i != simObjects.end(); i ++)')
248 code('{')
249 code.indent()
250 code('${{param.ptype.cxx_type}} object = '
251 'dynamic_cast<${{param.ptype.cxx_type}}>(*i);')
252 code('if (*i && !object)')
253 code(' ret = false;')
254 code('else')
255 code(' this->${{param.name}}.push_back(object);')
256 code.dedent()
257 code('}')
258 code.dedent()
259 code('} else {')
260 code(' ret = false;')
261 code('}')
262 code()
263 code('return ret;')
264 code.dedent()
265 code('}')
266
267 code()
268 code('void ${member_prefix}setName(const std::string &name_)'
269 '${end_of_decl}')
270
271 if not is_header:
272 code('{')
273 code.indent()
274 code('this->name = name_;')
271 code('this->pyobj = NULL;')
272 code.dedent()
273 code('}')
274
275 if is_header:
276 code('const std::string &${member_prefix}getName()')
277 code('{ return this->name; }')
278
279 code()
280 code('bool ${member_prefix}setParam(const std::string &name,')
281 code(' const std::string &value, const Flags flags)${end_of_decl}')
282
283 if not is_header:
284 code('{')
285 code.indent()
286 code('bool ret = true;')
287 code()
288 code('if (false) {')
289 for param in simobj._params.values():
290 is_vector = isinstance(param, m5.params.VectorParamDesc)
291 is_simobj = issubclass(param.ptype, m5.SimObject.SimObject)
292
293 if not is_simobj and not is_vector:
294 code('} else if (name == "${{param.name}}") {')
295 code.indent()
296 param.ptype.cxx_ini_parse(code,
297 'value', 'this->%s' % param.name, 'ret =')
298 code.dedent()
299 code('} else {')
300 code(' ret = false;')
301 code('}')
302 code()
303 code('return ret;')
304 code.dedent()
305 code('}')
306
307 code()
308 code('bool ${member_prefix}setParamVector('
309 'const std::string &name,')
310 code(' const std::vector<std::string> &values,')
311 code(' const Flags flags)${end_of_decl}')
312
313 if not is_header:
314 code('{')
315 code.indent()
316 code('bool ret = true;')
317 code()
318 code('if (false) {')
319 for param in simobj._params.values():
320 is_vector = isinstance(param, m5.params.VectorParamDesc)
321 is_simobj = issubclass(param.ptype, m5.SimObject.SimObject)
322
323 if not is_simobj and is_vector:
324 code('} else if (name == "${{param.name}}") {')
325 code.indent()
326 code('${{param.name}}.clear();')
327 code('for (auto i = values.begin(); '
328 'ret && i != values.end(); i ++)')
329 code('{')
330 code.indent()
331 code('${{param.ptype.cxx_type}} elem;')
332 param.ptype.cxx_ini_parse(code,
333 '*i', 'elem', 'ret =')
334 code('if (ret)')
335 code(' this->${{param.name}}.push_back(elem);')
336 code.dedent()
337 code('}')
338 code.dedent()
339 code('} else {')
340 code(' ret = false;')
341 code('}')
342 code()
343 code('return ret;')
344 code.dedent()
345 code('}')
346
347 code()
348 code('bool ${member_prefix}setPortConnectionCount('
349 'const std::string &name,')
350 code(' unsigned int count)${end_of_decl}')
351
352 if not is_header:
353 code('{')
354 code.indent()
355 code('bool ret = true;')
356 code()
357 code('if (false)')
358 code(' ;')
359 for port in simobj._ports.values():
360 code('else if (name == "${{port.name}}")')
361 code(' this->port_${{port.name}}_connection_count = count;')
362 code('else')
363 code(' ret = false;')
364 code()
365 code('return ret;')
366 code.dedent()
367 code('}')
368
369 code()
370 code('SimObject *${member_prefix}simObjectCreate()${end_of_decl}')
371
372 if not is_header:
373 code('{')
374 if hasattr(simobj, 'abstract') and simobj.abstract:
375 code(' return NULL;')
376 else:
377 code(' return this->create();')
378 code('}')
379
380 if is_header:
381 code()
382 code('static CxxConfigDirectoryEntry'
383 ' *${member_prefix}makeDirectoryEntry()')
384 code('{ return new DirectoryEntry; }')
385
386 if is_header:
387 code.dedent()
388 code('};')
389
390# The metaclass for SimObject. This class controls how new classes
391# that derive from SimObject are instantiated, and provides inherited
392# class behavior (just like a class controls how instances of that
393# class are instantiated, and provides inherited instance behavior).
394class MetaSimObject(type):
395 # Attributes that can be set only at initialization time
275 code.dedent()
276 code('}')
277
278 if is_header:
279 code('const std::string &${member_prefix}getName()')
280 code('{ return this->name; }')
281
282 code()
283 code('bool ${member_prefix}setParam(const std::string &name,')
284 code(' const std::string &value, const Flags flags)${end_of_decl}')
285
286 if not is_header:
287 code('{')
288 code.indent()
289 code('bool ret = true;')
290 code()
291 code('if (false) {')
292 for param in simobj._params.values():
293 is_vector = isinstance(param, m5.params.VectorParamDesc)
294 is_simobj = issubclass(param.ptype, m5.SimObject.SimObject)
295
296 if not is_simobj and not is_vector:
297 code('} else if (name == "${{param.name}}") {')
298 code.indent()
299 param.ptype.cxx_ini_parse(code,
300 'value', 'this->%s' % param.name, 'ret =')
301 code.dedent()
302 code('} else {')
303 code(' ret = false;')
304 code('}')
305 code()
306 code('return ret;')
307 code.dedent()
308 code('}')
309
310 code()
311 code('bool ${member_prefix}setParamVector('
312 'const std::string &name,')
313 code(' const std::vector<std::string> &values,')
314 code(' const Flags flags)${end_of_decl}')
315
316 if not is_header:
317 code('{')
318 code.indent()
319 code('bool ret = true;')
320 code()
321 code('if (false) {')
322 for param in simobj._params.values():
323 is_vector = isinstance(param, m5.params.VectorParamDesc)
324 is_simobj = issubclass(param.ptype, m5.SimObject.SimObject)
325
326 if not is_simobj and is_vector:
327 code('} else if (name == "${{param.name}}") {')
328 code.indent()
329 code('${{param.name}}.clear();')
330 code('for (auto i = values.begin(); '
331 'ret && i != values.end(); i ++)')
332 code('{')
333 code.indent()
334 code('${{param.ptype.cxx_type}} elem;')
335 param.ptype.cxx_ini_parse(code,
336 '*i', 'elem', 'ret =')
337 code('if (ret)')
338 code(' this->${{param.name}}.push_back(elem);')
339 code.dedent()
340 code('}')
341 code.dedent()
342 code('} else {')
343 code(' ret = false;')
344 code('}')
345 code()
346 code('return ret;')
347 code.dedent()
348 code('}')
349
350 code()
351 code('bool ${member_prefix}setPortConnectionCount('
352 'const std::string &name,')
353 code(' unsigned int count)${end_of_decl}')
354
355 if not is_header:
356 code('{')
357 code.indent()
358 code('bool ret = true;')
359 code()
360 code('if (false)')
361 code(' ;')
362 for port in simobj._ports.values():
363 code('else if (name == "${{port.name}}")')
364 code(' this->port_${{port.name}}_connection_count = count;')
365 code('else')
366 code(' ret = false;')
367 code()
368 code('return ret;')
369 code.dedent()
370 code('}')
371
372 code()
373 code('SimObject *${member_prefix}simObjectCreate()${end_of_decl}')
374
375 if not is_header:
376 code('{')
377 if hasattr(simobj, 'abstract') and simobj.abstract:
378 code(' return NULL;')
379 else:
380 code(' return this->create();')
381 code('}')
382
383 if is_header:
384 code()
385 code('static CxxConfigDirectoryEntry'
386 ' *${member_prefix}makeDirectoryEntry()')
387 code('{ return new DirectoryEntry; }')
388
389 if is_header:
390 code.dedent()
391 code('};')
392
393# The metaclass for SimObject. This class controls how new classes
394# that derive from SimObject are instantiated, and provides inherited
395# class behavior (just like a class controls how instances of that
396# class are instantiated, and provides inherited instance behavior).
397class MetaSimObject(type):
398 # Attributes that can be set only at initialization time
396 init_keywords = { 'abstract' : bool,
397 'cxx_class' : str,
398 'cxx_type' : str,
399 'cxx_header' : str,
400 'type' : str,
401 'cxx_bases' : list }
399 init_keywords = {
400 'abstract' : bool,
401 'cxx_class' : str,
402 'cxx_type' : str,
403 'cxx_header' : str,
404 'type' : str,
405 'cxx_bases' : list,
406 'cxx_exports' : list,
407 'cxx_param_exports' : list,
408 }
402 # Attributes that can be set any time
403 keywords = { 'check' : FunctionType }
404
405 # __new__ is called before __init__, and is where the statements
406 # in the body of the class definition get loaded into the class's
407 # __dict__. We intercept this to filter out parameter & port assignments
408 # and only allow "private" attributes to be passed to the base
409 # __new__ (starting with underscore).
410 def __new__(mcls, name, bases, dict):
411 assert name not in allClasses, "SimObject %s already present" % name
412
413 # Copy "private" attributes, functions, and classes to the
414 # official dict. Everything else goes in _init_dict to be
415 # filtered in __init__.
416 cls_dict = {}
417 value_dict = {}
409 # Attributes that can be set any time
410 keywords = { 'check' : FunctionType }
411
412 # __new__ is called before __init__, and is where the statements
413 # in the body of the class definition get loaded into the class's
414 # __dict__. We intercept this to filter out parameter & port assignments
415 # and only allow "private" attributes to be passed to the base
416 # __new__ (starting with underscore).
417 def __new__(mcls, name, bases, dict):
418 assert name not in allClasses, "SimObject %s already present" % name
419
420 # Copy "private" attributes, functions, and classes to the
421 # official dict. Everything else goes in _init_dict to be
422 # filtered in __init__.
423 cls_dict = {}
424 value_dict = {}
425 cxx_exports = []
418 for key,val in dict.items():
426 for key,val in dict.items():
427 try:
428 cxx_exports.append(getattr(val, "__pybind"))
429 except AttributeError:
430 pass
431
419 if public_value(key, val):
420 cls_dict[key] = val
421 else:
422 # must be a param/port setting
423 value_dict[key] = val
424 if 'abstract' not in value_dict:
425 value_dict['abstract'] = False
426 if 'cxx_bases' not in value_dict:
427 value_dict['cxx_bases'] = []
432 if public_value(key, val):
433 cls_dict[key] = val
434 else:
435 # must be a param/port setting
436 value_dict[key] = val
437 if 'abstract' not in value_dict:
438 value_dict['abstract'] = False
439 if 'cxx_bases' not in value_dict:
440 value_dict['cxx_bases'] = []
441 if 'cxx_exports' not in value_dict:
442 value_dict['cxx_exports'] = cxx_exports
443 else:
444 value_dict['cxx_exports'] += cxx_exports
445 if 'cxx_param_exports' not in value_dict:
446 value_dict['cxx_param_exports'] = []
428 cls_dict['_value_dict'] = value_dict
429 cls = super(MetaSimObject, mcls).__new__(mcls, name, bases, cls_dict)
430 if 'type' in value_dict:
431 allClasses[name] = cls
432 return cls
433
434 # subclass initialization
435 def __init__(cls, name, bases, dict):
436 # calls type.__init__()... I think that's a no-op, but leave
437 # it here just in case it's not.
438 super(MetaSimObject, cls).__init__(name, bases, dict)
439
440 # initialize required attributes
441
442 # class-only attributes
443 cls._params = multidict() # param descriptions
444 cls._ports = multidict() # port descriptions
445
446 # class or instance attributes
447 cls._values = multidict() # param values
448 cls._hr_values = multidict() # human readable param values
449 cls._children = multidict() # SimObject children
450 cls._port_refs = multidict() # port ref objects
451 cls._instantiated = False # really instantiated, cloned, or subclassed
452
453 # We don't support multiple inheritance of sim objects. If you want
454 # to, you must fix multidict to deal with it properly. Non sim-objects
455 # are ok, though
456 bTotal = 0
457 for c in bases:
458 if isinstance(c, MetaSimObject):
459 bTotal += 1
460 if bTotal > 1:
461 raise TypeError, "SimObjects do not support multiple inheritance"
462
463 base = bases[0]
464
465 # Set up general inheritance via multidicts. A subclass will
466 # inherit all its settings from the base class. The only time
467 # the following is not true is when we define the SimObject
468 # class itself (in which case the multidicts have no parent).
469 if isinstance(base, MetaSimObject):
470 cls._base = base
471 cls._params.parent = base._params
472 cls._ports.parent = base._ports
473 cls._values.parent = base._values
474 cls._hr_values.parent = base._hr_values
475 cls._children.parent = base._children
476 cls._port_refs.parent = base._port_refs
477 # mark base as having been subclassed
478 base._instantiated = True
479 else:
480 cls._base = None
481
482 # default keyword values
483 if 'type' in cls._value_dict:
484 if 'cxx_class' not in cls._value_dict:
485 cls._value_dict['cxx_class'] = cls._value_dict['type']
486
487 cls._value_dict['cxx_type'] = '%s *' % cls._value_dict['cxx_class']
488
489 if 'cxx_header' not in cls._value_dict:
490 global noCxxHeader
491 noCxxHeader = True
492 warn("No header file specified for SimObject: %s", name)
493
494 # Export methods are automatically inherited via C++, so we
495 # don't want the method declarations to get inherited on the
496 # python side (and thus end up getting repeated in the wrapped
497 # versions of derived classes). The code below basicallly
498 # suppresses inheritance by substituting in the base (null)
499 # versions of these methods unless a different version is
500 # explicitly supplied.
501 for method_name in ('export_methods', 'export_method_swig_predecls'):
502 if method_name not in cls.__dict__:
503 base_method = getattr(MetaSimObject, method_name)
504 m = MethodType(base_method, cls, MetaSimObject)
505 setattr(cls, method_name, m)
506
507 # Now process the _value_dict items. They could be defining
508 # new (or overriding existing) parameters or ports, setting
509 # class keywords (e.g., 'abstract'), or setting parameter
510 # values or port bindings. The first 3 can only be set when
511 # the class is defined, so we handle them here. The others
512 # can be set later too, so just emulate that by calling
513 # setattr().
514 for key,val in cls._value_dict.items():
515 # param descriptions
516 if isinstance(val, ParamDesc):
517 cls._new_param(key, val)
518
519 # port objects
520 elif isinstance(val, Port):
521 cls._new_port(key, val)
522
523 # init-time-only keywords
524 elif cls.init_keywords.has_key(key):
525 cls._set_keyword(key, val, cls.init_keywords[key])
526
527 # default: use normal path (ends up in __setattr__)
528 else:
529 setattr(cls, key, val)
530
531 def _set_keyword(cls, keyword, val, kwtype):
532 if not isinstance(val, kwtype):
533 raise TypeError, 'keyword %s has bad type %s (expecting %s)' % \
534 (keyword, type(val), kwtype)
535 if isinstance(val, FunctionType):
536 val = classmethod(val)
537 type.__setattr__(cls, keyword, val)
538
539 def _new_param(cls, name, pdesc):
540 # each param desc should be uniquely assigned to one variable
541 assert(not hasattr(pdesc, 'name'))
542 pdesc.name = name
543 cls._params[name] = pdesc
544 if hasattr(pdesc, 'default'):
545 cls._set_param(name, pdesc.default, pdesc)
546
547 def _set_param(cls, name, value, param):
548 assert(param.name == name)
549 try:
550 hr_value = value
551 value = param.convert(value)
552 except Exception, e:
553 msg = "%s\nError setting param %s.%s to %s\n" % \
554 (e, cls.__name__, name, value)
555 e.args = (msg, )
556 raise
557 cls._values[name] = value
558 # if param value is a SimObject, make it a child too, so that
559 # it gets cloned properly when the class is instantiated
560 if isSimObjectOrVector(value) and not value.has_parent():
561 cls._add_cls_child(name, value)
562 # update human-readable values of the param if it has a literal
563 # value and is not an object or proxy.
564 if not (isSimObjectOrVector(value) or\
565 isinstance(value, m5.proxy.BaseProxy)):
566 cls._hr_values[name] = hr_value
567
568 def _add_cls_child(cls, name, child):
569 # It's a little funky to have a class as a parent, but these
570 # objects should never be instantiated (only cloned, which
571 # clears the parent pointer), and this makes it clear that the
572 # object is not an orphan and can provide better error
573 # messages.
574 child.set_parent(cls, name)
575 cls._children[name] = child
576
577 def _new_port(cls, name, port):
578 # each port should be uniquely assigned to one variable
579 assert(not hasattr(port, 'name'))
580 port.name = name
581 cls._ports[name] = port
582
583 # same as _get_port_ref, effectively, but for classes
584 def _cls_get_port_ref(cls, attr):
585 # Return reference that can be assigned to another port
586 # via __setattr__. There is only ever one reference
587 # object per port, but we create them lazily here.
588 ref = cls._port_refs.get(attr)
589 if not ref:
590 ref = cls._ports[attr].makeRef(cls)
591 cls._port_refs[attr] = ref
592 return ref
593
594 # Set attribute (called on foo.attr = value when foo is an
595 # instance of class cls).
596 def __setattr__(cls, attr, value):
597 # normal processing for private attributes
598 if public_value(attr, value):
599 type.__setattr__(cls, attr, value)
600 return
601
602 if cls.keywords.has_key(attr):
603 cls._set_keyword(attr, value, cls.keywords[attr])
604 return
605
606 if cls._ports.has_key(attr):
607 cls._cls_get_port_ref(attr).connect(value)
608 return
609
610 if isSimObjectOrSequence(value) and cls._instantiated:
611 raise RuntimeError, \
612 "cannot set SimObject parameter '%s' after\n" \
613 " class %s has been instantiated or subclassed" \
614 % (attr, cls.__name__)
615
616 # check for param
617 param = cls._params.get(attr)
618 if param:
619 cls._set_param(attr, value, param)
620 return
621
622 if isSimObjectOrSequence(value):
623 # If RHS is a SimObject, it's an implicit child assignment.
624 cls._add_cls_child(attr, coerceSimObjectOrVector(value))
625 return
626
627 # no valid assignment... raise exception
628 raise AttributeError, \
629 "Class %s has no parameter \'%s\'" % (cls.__name__, attr)
630
631 def __getattr__(cls, attr):
632 if attr == 'cxx_class_path':
633 return cls.cxx_class.split('::')
634
635 if attr == 'cxx_class_name':
636 return cls.cxx_class_path[-1]
637
638 if attr == 'cxx_namespaces':
639 return cls.cxx_class_path[:-1]
640
641 if cls._values.has_key(attr):
642 return cls._values[attr]
643
644 if cls._children.has_key(attr):
645 return cls._children[attr]
646
647 raise AttributeError, \
648 "object '%s' has no attribute '%s'" % (cls.__name__, attr)
649
650 def __str__(cls):
651 return cls.__name__
652
653 # See ParamValue.cxx_predecls for description.
654 def cxx_predecls(cls, code):
655 code('#include "params/$cls.hh"')
656
447 cls_dict['_value_dict'] = value_dict
448 cls = super(MetaSimObject, mcls).__new__(mcls, name, bases, cls_dict)
449 if 'type' in value_dict:
450 allClasses[name] = cls
451 return cls
452
453 # subclass initialization
454 def __init__(cls, name, bases, dict):
455 # calls type.__init__()... I think that's a no-op, but leave
456 # it here just in case it's not.
457 super(MetaSimObject, cls).__init__(name, bases, dict)
458
459 # initialize required attributes
460
461 # class-only attributes
462 cls._params = multidict() # param descriptions
463 cls._ports = multidict() # port descriptions
464
465 # class or instance attributes
466 cls._values = multidict() # param values
467 cls._hr_values = multidict() # human readable param values
468 cls._children = multidict() # SimObject children
469 cls._port_refs = multidict() # port ref objects
470 cls._instantiated = False # really instantiated, cloned, or subclassed
471
472 # We don't support multiple inheritance of sim objects. If you want
473 # to, you must fix multidict to deal with it properly. Non sim-objects
474 # are ok, though
475 bTotal = 0
476 for c in bases:
477 if isinstance(c, MetaSimObject):
478 bTotal += 1
479 if bTotal > 1:
480 raise TypeError, "SimObjects do not support multiple inheritance"
481
482 base = bases[0]
483
484 # Set up general inheritance via multidicts. A subclass will
485 # inherit all its settings from the base class. The only time
486 # the following is not true is when we define the SimObject
487 # class itself (in which case the multidicts have no parent).
488 if isinstance(base, MetaSimObject):
489 cls._base = base
490 cls._params.parent = base._params
491 cls._ports.parent = base._ports
492 cls._values.parent = base._values
493 cls._hr_values.parent = base._hr_values
494 cls._children.parent = base._children
495 cls._port_refs.parent = base._port_refs
496 # mark base as having been subclassed
497 base._instantiated = True
498 else:
499 cls._base = None
500
501 # default keyword values
502 if 'type' in cls._value_dict:
503 if 'cxx_class' not in cls._value_dict:
504 cls._value_dict['cxx_class'] = cls._value_dict['type']
505
506 cls._value_dict['cxx_type'] = '%s *' % cls._value_dict['cxx_class']
507
508 if 'cxx_header' not in cls._value_dict:
509 global noCxxHeader
510 noCxxHeader = True
511 warn("No header file specified for SimObject: %s", name)
512
513 # Export methods are automatically inherited via C++, so we
514 # don't want the method declarations to get inherited on the
515 # python side (and thus end up getting repeated in the wrapped
516 # versions of derived classes). The code below basicallly
517 # suppresses inheritance by substituting in the base (null)
518 # versions of these methods unless a different version is
519 # explicitly supplied.
520 for method_name in ('export_methods', 'export_method_swig_predecls'):
521 if method_name not in cls.__dict__:
522 base_method = getattr(MetaSimObject, method_name)
523 m = MethodType(base_method, cls, MetaSimObject)
524 setattr(cls, method_name, m)
525
526 # Now process the _value_dict items. They could be defining
527 # new (or overriding existing) parameters or ports, setting
528 # class keywords (e.g., 'abstract'), or setting parameter
529 # values or port bindings. The first 3 can only be set when
530 # the class is defined, so we handle them here. The others
531 # can be set later too, so just emulate that by calling
532 # setattr().
533 for key,val in cls._value_dict.items():
534 # param descriptions
535 if isinstance(val, ParamDesc):
536 cls._new_param(key, val)
537
538 # port objects
539 elif isinstance(val, Port):
540 cls._new_port(key, val)
541
542 # init-time-only keywords
543 elif cls.init_keywords.has_key(key):
544 cls._set_keyword(key, val, cls.init_keywords[key])
545
546 # default: use normal path (ends up in __setattr__)
547 else:
548 setattr(cls, key, val)
549
550 def _set_keyword(cls, keyword, val, kwtype):
551 if not isinstance(val, kwtype):
552 raise TypeError, 'keyword %s has bad type %s (expecting %s)' % \
553 (keyword, type(val), kwtype)
554 if isinstance(val, FunctionType):
555 val = classmethod(val)
556 type.__setattr__(cls, keyword, val)
557
558 def _new_param(cls, name, pdesc):
559 # each param desc should be uniquely assigned to one variable
560 assert(not hasattr(pdesc, 'name'))
561 pdesc.name = name
562 cls._params[name] = pdesc
563 if hasattr(pdesc, 'default'):
564 cls._set_param(name, pdesc.default, pdesc)
565
566 def _set_param(cls, name, value, param):
567 assert(param.name == name)
568 try:
569 hr_value = value
570 value = param.convert(value)
571 except Exception, e:
572 msg = "%s\nError setting param %s.%s to %s\n" % \
573 (e, cls.__name__, name, value)
574 e.args = (msg, )
575 raise
576 cls._values[name] = value
577 # if param value is a SimObject, make it a child too, so that
578 # it gets cloned properly when the class is instantiated
579 if isSimObjectOrVector(value) and not value.has_parent():
580 cls._add_cls_child(name, value)
581 # update human-readable values of the param if it has a literal
582 # value and is not an object or proxy.
583 if not (isSimObjectOrVector(value) or\
584 isinstance(value, m5.proxy.BaseProxy)):
585 cls._hr_values[name] = hr_value
586
587 def _add_cls_child(cls, name, child):
588 # It's a little funky to have a class as a parent, but these
589 # objects should never be instantiated (only cloned, which
590 # clears the parent pointer), and this makes it clear that the
591 # object is not an orphan and can provide better error
592 # messages.
593 child.set_parent(cls, name)
594 cls._children[name] = child
595
596 def _new_port(cls, name, port):
597 # each port should be uniquely assigned to one variable
598 assert(not hasattr(port, 'name'))
599 port.name = name
600 cls._ports[name] = port
601
602 # same as _get_port_ref, effectively, but for classes
603 def _cls_get_port_ref(cls, attr):
604 # Return reference that can be assigned to another port
605 # via __setattr__. There is only ever one reference
606 # object per port, but we create them lazily here.
607 ref = cls._port_refs.get(attr)
608 if not ref:
609 ref = cls._ports[attr].makeRef(cls)
610 cls._port_refs[attr] = ref
611 return ref
612
613 # Set attribute (called on foo.attr = value when foo is an
614 # instance of class cls).
615 def __setattr__(cls, attr, value):
616 # normal processing for private attributes
617 if public_value(attr, value):
618 type.__setattr__(cls, attr, value)
619 return
620
621 if cls.keywords.has_key(attr):
622 cls._set_keyword(attr, value, cls.keywords[attr])
623 return
624
625 if cls._ports.has_key(attr):
626 cls._cls_get_port_ref(attr).connect(value)
627 return
628
629 if isSimObjectOrSequence(value) and cls._instantiated:
630 raise RuntimeError, \
631 "cannot set SimObject parameter '%s' after\n" \
632 " class %s has been instantiated or subclassed" \
633 % (attr, cls.__name__)
634
635 # check for param
636 param = cls._params.get(attr)
637 if param:
638 cls._set_param(attr, value, param)
639 return
640
641 if isSimObjectOrSequence(value):
642 # If RHS is a SimObject, it's an implicit child assignment.
643 cls._add_cls_child(attr, coerceSimObjectOrVector(value))
644 return
645
646 # no valid assignment... raise exception
647 raise AttributeError, \
648 "Class %s has no parameter \'%s\'" % (cls.__name__, attr)
649
650 def __getattr__(cls, attr):
651 if attr == 'cxx_class_path':
652 return cls.cxx_class.split('::')
653
654 if attr == 'cxx_class_name':
655 return cls.cxx_class_path[-1]
656
657 if attr == 'cxx_namespaces':
658 return cls.cxx_class_path[:-1]
659
660 if cls._values.has_key(attr):
661 return cls._values[attr]
662
663 if cls._children.has_key(attr):
664 return cls._children[attr]
665
666 raise AttributeError, \
667 "object '%s' has no attribute '%s'" % (cls.__name__, attr)
668
669 def __str__(cls):
670 return cls.__name__
671
672 # See ParamValue.cxx_predecls for description.
673 def cxx_predecls(cls, code):
674 code('#include "params/$cls.hh"')
675
676 def pybind_predecls(cls, code):
677 code('#include "${{cls.cxx_header}}"')
678
657 # See ParamValue.swig_predecls for description.
658 def swig_predecls(cls, code):
659 code('%import "python/_m5/param_$cls.i"')
660
661 # Hook for exporting additional C++ methods to Python via SWIG.
662 # Default is none, override using @classmethod in class definition.
663 def export_methods(cls, code):
664 pass
665
666 # Generate the code needed as a prerequisite for the C++ methods
667 # exported via export_methods() to be processed by SWIG.
668 # Typically generates one or more %include or %import statements.
669 # If any methods are exported, typically at least the C++ header
670 # declaring the relevant SimObject class must be included.
671 def export_method_swig_predecls(cls, code):
672 pass
673
674 # Generate the declaration for this object for wrapping with SWIG.
675 # Generates code that goes into a SWIG .i file. Called from
676 # src/SConscript.
677 def swig_decl(cls, code):
678 class_path = cls.cxx_class.split('::')
679 classname = class_path[-1]
680 namespaces = class_path[:-1]
681
682 # The 'local' attribute restricts us to the params declared in
683 # the object itself, not including inherited params (which
684 # will also be inherited from the base class's param struct
685 # here). Sort the params based on their key
686 params = map(lambda (k, v): v, sorted(cls._params.local.items()))
687 ports = cls._ports.local
688
689 code('%module(package="_m5") param_$cls')
690 code()
691 code('%{')
692 code('#include "sim/sim_object.hh"')
693 code('#include "params/$cls.hh"')
694 for param in params:
695 param.cxx_predecls(code)
696 code('#include "${{cls.cxx_header}}"')
697 code('''\
698/**
699 * This is a workaround for bug in swig. Prior to gcc 4.6.1 the STL
700 * headers like vector, string, etc. used to automatically pull in
701 * the cstddef header but starting with gcc 4.6.1 they no longer do.
702 * This leads to swig generated a file that does not compile so we
703 * explicitly include cstddef. Additionally, including version 2.0.4,
704 * swig uses ptrdiff_t without the std:: namespace prefix which is
705 * required with gcc 4.6.1. We explicitly provide access to it.
706 */
707#include <cstddef>
708using std::ptrdiff_t;
709''')
710 code('%}')
711 code()
712
713 for param in params:
714 param.swig_predecls(code)
715 cls.export_method_swig_predecls(code)
716
717 code()
718 if cls._base:
719 code('%import "python/_m5/param_${{cls._base}}.i"')
720 code()
721
722 for ns in namespaces:
723 code('namespace $ns {')
724
725 if namespaces:
726 code('// avoid name conflicts')
727 sep_string = '_COLONS_'
728 flat_name = sep_string.join(class_path)
729 code('%rename($flat_name) $classname;')
730
731 code()
732 code('// stop swig from creating/wrapping default ctor/dtor')
733 code('%nodefault $classname;')
734 code('class $classname')
735 if cls._base:
736 bases = [ cls._base.cxx_class ] + cls.cxx_bases
737 else:
738 bases = cls.cxx_bases
739 base_first = True
740 for base in bases:
741 if base_first:
742 code(' : public ${{base}}')
743 base_first = False
744 else:
745 code(' , public ${{base}}')
746
747 code('{')
748 code(' public:')
749 cls.export_methods(code)
750 code('};')
751
752 for ns in reversed(namespaces):
753 code('} // namespace $ns')
754
755 code()
756 code('%include "params/$cls.hh"')
757
679 # See ParamValue.swig_predecls for description.
680 def swig_predecls(cls, code):
681 code('%import "python/_m5/param_$cls.i"')
682
683 # Hook for exporting additional C++ methods to Python via SWIG.
684 # Default is none, override using @classmethod in class definition.
685 def export_methods(cls, code):
686 pass
687
688 # Generate the code needed as a prerequisite for the C++ methods
689 # exported via export_methods() to be processed by SWIG.
690 # Typically generates one or more %include or %import statements.
691 # If any methods are exported, typically at least the C++ header
692 # declaring the relevant SimObject class must be included.
693 def export_method_swig_predecls(cls, code):
694 pass
695
696 # Generate the declaration for this object for wrapping with SWIG.
697 # Generates code that goes into a SWIG .i file. Called from
698 # src/SConscript.
699 def swig_decl(cls, code):
700 class_path = cls.cxx_class.split('::')
701 classname = class_path[-1]
702 namespaces = class_path[:-1]
703
704 # The 'local' attribute restricts us to the params declared in
705 # the object itself, not including inherited params (which
706 # will also be inherited from the base class's param struct
707 # here). Sort the params based on their key
708 params = map(lambda (k, v): v, sorted(cls._params.local.items()))
709 ports = cls._ports.local
710
711 code('%module(package="_m5") param_$cls')
712 code()
713 code('%{')
714 code('#include "sim/sim_object.hh"')
715 code('#include "params/$cls.hh"')
716 for param in params:
717 param.cxx_predecls(code)
718 code('#include "${{cls.cxx_header}}"')
719 code('''\
720/**
721 * This is a workaround for bug in swig. Prior to gcc 4.6.1 the STL
722 * headers like vector, string, etc. used to automatically pull in
723 * the cstddef header but starting with gcc 4.6.1 they no longer do.
724 * This leads to swig generated a file that does not compile so we
725 * explicitly include cstddef. Additionally, including version 2.0.4,
726 * swig uses ptrdiff_t without the std:: namespace prefix which is
727 * required with gcc 4.6.1. We explicitly provide access to it.
728 */
729#include <cstddef>
730using std::ptrdiff_t;
731''')
732 code('%}')
733 code()
734
735 for param in params:
736 param.swig_predecls(code)
737 cls.export_method_swig_predecls(code)
738
739 code()
740 if cls._base:
741 code('%import "python/_m5/param_${{cls._base}}.i"')
742 code()
743
744 for ns in namespaces:
745 code('namespace $ns {')
746
747 if namespaces:
748 code('// avoid name conflicts')
749 sep_string = '_COLONS_'
750 flat_name = sep_string.join(class_path)
751 code('%rename($flat_name) $classname;')
752
753 code()
754 code('// stop swig from creating/wrapping default ctor/dtor')
755 code('%nodefault $classname;')
756 code('class $classname')
757 if cls._base:
758 bases = [ cls._base.cxx_class ] + cls.cxx_bases
759 else:
760 bases = cls.cxx_bases
761 base_first = True
762 for base in bases:
763 if base_first:
764 code(' : public ${{base}}')
765 base_first = False
766 else:
767 code(' , public ${{base}}')
768
769 code('{')
770 code(' public:')
771 cls.export_methods(code)
772 code('};')
773
774 for ns in reversed(namespaces):
775 code('} // namespace $ns')
776
777 code()
778 code('%include "params/$cls.hh"')
779
780 def pybind_decl(cls, code):
781 class_path = cls.cxx_class.split('::')
782 namespaces, classname = class_path[:-1], class_path[-1]
783 py_class_name = '_COLONS_'.join(class_path) if namespaces else \
784 classname;
758
785
786 # The 'local' attribute restricts us to the params declared in
787 # the object itself, not including inherited params (which
788 # will also be inherited from the base class's param struct
789 # here). Sort the params based on their key
790 params = map(lambda (k, v): v, sorted(cls._params.local.items()))
791 ports = cls._ports.local
792
793 code('''#include "pybind11/pybind11.h"
794#include "pybind11/stl.h"
795
796#include "sim/sim_object.hh"
797#include "params/$cls.hh"
798#include "sim/init.hh"
799#include "${{cls.cxx_header}}"
800
801''')
802
803 for param in params:
804 param.pybind_predecls(code)
805
806 code('''namespace py = pybind11;
807
808static void
809module_init(py::module &m_internal)
810{
811 py::module m = m_internal.def_submodule("param_${cls}");
812''')
813 code.indent()
814 if cls._base:
815 code('py::class_<${cls}Params, ${{cls._base.type}}Params>(m, ' \
816 '"${cls}Params")')
817 else:
818 code('py::class_<${cls}Params>(m, "${cls}Params")')
819
820 code.indent()
821 if not hasattr(cls, 'abstract') or not cls.abstract:
822 code('.def(py::init<>())')
823 code('.def("create", &${cls}Params::create)')
824
825 param_exports = cls.cxx_param_exports + [
826 PyBindProperty(k)
827 for k, v in sorted(cls._params.local.items())
828 ] + [
829 PyBindProperty("port_%s_connection_count" % port.name)
830 for port in ports.itervalues()
831 ]
832 for exp in param_exports:
833 exp.export(code, "%sParams" % cls)
834
835 code(';')
836 code()
837 code.dedent()
838
839 bases = [ cls._base.cxx_class ] + cls.cxx_bases if cls._base else \
840 cls.cxx_bases
841 if bases:
842 base_str = ", ".join(bases)
843 code('py::class_<${{cls.cxx_class}}, ${base_str}>(m, ' \
844 '"${py_class_name}")')
845 else:
846 code('py::class_<${{cls.cxx_class}}>(m, "${py_class_name}")')
847 code.indent()
848 for exp in cls.cxx_exports:
849 exp.export(code, cls.cxx_class)
850 code(';')
851 code.dedent()
852 code()
853 code.dedent()
854 code('}')
855 code()
856 code('static EmbeddedPyBind embed_obj("${0}", module_init, "${1}");',
857 cls, cls._base.type if cls._base else "")
858
859
759 # Generate the C++ declaration (.hh file) for this SimObject's
760 # param struct. Called from src/SConscript.
761 def cxx_param_decl(cls, code):
762 # The 'local' attribute restricts us to the params declared in
763 # the object itself, not including inherited params (which
764 # will also be inherited from the base class's param struct
765 # here). Sort the params based on their key
766 params = map(lambda (k, v): v, sorted(cls._params.local.items()))
767 ports = cls._ports.local
768 try:
769 ptypes = [p.ptype for p in params]
770 except:
771 print cls, p, p.ptype_str
772 print params
773 raise
774
775 class_path = cls._value_dict['cxx_class'].split('::')
776
777 code('''\
778#ifndef __PARAMS__${cls}__
779#define __PARAMS__${cls}__
780
781''')
782
860 # Generate the C++ declaration (.hh file) for this SimObject's
861 # param struct. Called from src/SConscript.
862 def cxx_param_decl(cls, code):
863 # The 'local' attribute restricts us to the params declared in
864 # the object itself, not including inherited params (which
865 # will also be inherited from the base class's param struct
866 # here). Sort the params based on their key
867 params = map(lambda (k, v): v, sorted(cls._params.local.items()))
868 ports = cls._ports.local
869 try:
870 ptypes = [p.ptype for p in params]
871 except:
872 print cls, p, p.ptype_str
873 print params
874 raise
875
876 class_path = cls._value_dict['cxx_class'].split('::')
877
878 code('''\
879#ifndef __PARAMS__${cls}__
880#define __PARAMS__${cls}__
881
882''')
883
884
885 # The base SimObject has a couple of params that get
886 # automatically set from Python without being declared through
887 # the normal Param mechanism; we slip them in here (needed
888 # predecls now, actual declarations below)
889 if cls == SimObject:
890 code('''#include <string>''')
891
783 # A forward class declaration is sufficient since we are just
784 # declaring a pointer.
785 for ns in class_path[:-1]:
786 code('namespace $ns {')
787 code('class $0;', class_path[-1])
788 for ns in reversed(class_path[:-1]):
789 code('} // namespace $ns')
790 code()
791
892 # A forward class declaration is sufficient since we are just
893 # declaring a pointer.
894 for ns in class_path[:-1]:
895 code('namespace $ns {')
896 code('class $0;', class_path[-1])
897 for ns in reversed(class_path[:-1]):
898 code('} // namespace $ns')
899 code()
900
792 # The base SimObject has a couple of params that get
793 # automatically set from Python without being declared through
794 # the normal Param mechanism; we slip them in here (needed
795 # predecls now, actual declarations below)
796 if cls == SimObject:
797 code('''
798#ifndef PY_VERSION
799struct PyObject;
800#endif
801
802#include <string>
803''')
804 for param in params:
805 param.cxx_predecls(code)
806 for port in ports.itervalues():
807 port.cxx_predecls(code)
808 code()
809
810 if cls._base:
811 code('#include "params/${{cls._base.type}}.hh"')
812 code()
813
814 for ptype in ptypes:
815 if issubclass(ptype, Enum):
816 code('#include "enums/${{ptype.__name__}}.hh"')
817 code()
818
819 # now generate the actual param struct
820 code("struct ${cls}Params")
821 if cls._base:
822 code(" : public ${{cls._base.type}}Params")
823 code("{")
824 if not hasattr(cls, 'abstract') or not cls.abstract:
825 if 'type' in cls.__dict__:
826 code(" ${{cls.cxx_type}} create();")
827
828 code.indent()
829 if cls == SimObject:
830 code('''
831 SimObjectParams() {}
832 virtual ~SimObjectParams() {}
833
834 std::string name;
901 for param in params:
902 param.cxx_predecls(code)
903 for port in ports.itervalues():
904 port.cxx_predecls(code)
905 code()
906
907 if cls._base:
908 code('#include "params/${{cls._base.type}}.hh"')
909 code()
910
911 for ptype in ptypes:
912 if issubclass(ptype, Enum):
913 code('#include "enums/${{ptype.__name__}}.hh"')
914 code()
915
916 # now generate the actual param struct
917 code("struct ${cls}Params")
918 if cls._base:
919 code(" : public ${{cls._base.type}}Params")
920 code("{")
921 if not hasattr(cls, 'abstract') or not cls.abstract:
922 if 'type' in cls.__dict__:
923 code(" ${{cls.cxx_type}} create();")
924
925 code.indent()
926 if cls == SimObject:
927 code('''
928 SimObjectParams() {}
929 virtual ~SimObjectParams() {}
930
931 std::string name;
835 PyObject *pyobj;
836 ''')
932 ''')
933
837 for param in params:
838 param.cxx_decl(code)
839 for port in ports.itervalues():
840 port.cxx_decl(code)
841
842 code.dedent()
843 code('};')
844
845 code()
846 code('#endif // __PARAMS__${cls}__')
847 return code
848
849 # Generate the C++ declaration/definition files for this SimObject's
850 # param struct to allow C++ initialisation
851 def cxx_config_param_file(cls, code, is_header):
852 createCxxConfigDirectoryEntryFile(code, cls.__name__, cls, is_header)
853 return code
854
855# This *temporary* definition is required to support calls from the
856# SimObject class definition to the MetaSimObject methods (in
857# particular _set_param, which gets called for parameters with default
858# values defined on the SimObject class itself). It will get
859# overridden by the permanent definition (which requires that
860# SimObject be defined) lower in this file.
861def isSimObjectOrVector(value):
862 return False
863
934 for param in params:
935 param.cxx_decl(code)
936 for port in ports.itervalues():
937 port.cxx_decl(code)
938
939 code.dedent()
940 code('};')
941
942 code()
943 code('#endif // __PARAMS__${cls}__')
944 return code
945
946 # Generate the C++ declaration/definition files for this SimObject's
947 # param struct to allow C++ initialisation
948 def cxx_config_param_file(cls, code, is_header):
949 createCxxConfigDirectoryEntryFile(code, cls.__name__, cls, is_header)
950 return code
951
952# This *temporary* definition is required to support calls from the
953# SimObject class definition to the MetaSimObject methods (in
954# particular _set_param, which gets called for parameters with default
955# values defined on the SimObject class itself). It will get
956# overridden by the permanent definition (which requires that
957# SimObject be defined) lower in this file.
958def isSimObjectOrVector(value):
959 return False
960
961def cxxMethod(*args, **kwargs):
962 """Decorator to export C++ functions to Python"""
963
964 def decorate(func):
965 name = func.func_name
966 override = kwargs.get("override", False)
967 cxx_name = kwargs.get("cxx_name", name)
968
969 args, varargs, keywords, defaults = inspect.getargspec(func)
970 if varargs or keywords:
971 raise ValueError("Wrapped methods must not contain variable " \
972 "arguments")
973
974 # Create tuples of (argument, default)
975 if defaults:
976 args = args[:-len(defaults)] + zip(args[-len(defaults):], defaults)
977 # Don't include self in the argument list to PyBind
978 args = args[1:]
979
980
981 @wraps(func)
982 def cxx_call(self, *args, **kwargs):
983 ccobj = self.getCCObject()
984 return getattr(ccobj, name)(*args, **kwargs)
985
986 @wraps(func)
987 def py_call(self, *args, **kwargs):
988 return self.func(*args, **kwargs)
989
990 f = py_call if override else cxx_call
991 f.__pybind = PyBindMethod(name, cxx_name=cxx_name, args=args)
992
993 return f
994
995 if len(args) == 0:
996 return decorate
997 elif len(args) == 1 and len(kwargs) == 0:
998 return decorate(*args)
999 else:
1000 raise TypeError("One argument and no kwargs, or only kwargs expected")
1001
864# This class holds information about each simobject parameter
865# that should be displayed on the command line for use in the
866# configuration system.
867class ParamInfo(object):
868 def __init__(self, type, desc, type_str, example, default_val, access_str):
869 self.type = type
870 self.desc = desc
871 self.type_str = type_str
872 self.example_str = example
873 self.default_val = default_val
874 # The string representation used to access this param through python.
875 # The method to access this parameter presented on the command line may
876 # be different, so this needs to be stored for later use.
877 self.access_str = access_str
878 self.created = True
879
880 # Make it so we can only set attributes at initialization time
881 # and effectively make this a const object.
882 def __setattr__(self, name, value):
883 if not "created" in self.__dict__:
884 self.__dict__[name] = value
885
886# The SimObject class is the root of the special hierarchy. Most of
887# the code in this class deals with the configuration hierarchy itself
888# (parent/child node relationships).
889class SimObject(object):
890 # Specify metaclass. Any class inheriting from SimObject will
891 # get this metaclass.
892 __metaclass__ = MetaSimObject
893 type = 'SimObject'
894 abstract = True
895
896 cxx_header = "sim/sim_object.hh"
897 cxx_bases = [ "Drainable", "Serializable" ]
898 eventq_index = Param.UInt32(Parent.eventq_index, "Event Queue Index")
899
900 @classmethod
901 def export_method_swig_predecls(cls, code):
902 code('''
903%include <std_string.i>
904
905%import "python/swig/drain.i"
906%import "python/swig/serialize.i"
907''')
908
909 @classmethod
910 def export_methods(cls, code):
911 code('''
912 void init();
913 void loadState(CheckpointIn &cp);
914 void initState();
915 void memInvalidate();
916 void memWriteback();
917 void regStats();
918 void resetStats();
919 void regProbePoints();
920 void regProbeListeners();
921 void startup();
922''')
923
1002# This class holds information about each simobject parameter
1003# that should be displayed on the command line for use in the
1004# configuration system.
1005class ParamInfo(object):
1006 def __init__(self, type, desc, type_str, example, default_val, access_str):
1007 self.type = type
1008 self.desc = desc
1009 self.type_str = type_str
1010 self.example_str = example
1011 self.default_val = default_val
1012 # The string representation used to access this param through python.
1013 # The method to access this parameter presented on the command line may
1014 # be different, so this needs to be stored for later use.
1015 self.access_str = access_str
1016 self.created = True
1017
1018 # Make it so we can only set attributes at initialization time
1019 # and effectively make this a const object.
1020 def __setattr__(self, name, value):
1021 if not "created" in self.__dict__:
1022 self.__dict__[name] = value
1023
1024# The SimObject class is the root of the special hierarchy. Most of
1025# the code in this class deals with the configuration hierarchy itself
1026# (parent/child node relationships).
1027class SimObject(object):
1028 # Specify metaclass. Any class inheriting from SimObject will
1029 # get this metaclass.
1030 __metaclass__ = MetaSimObject
1031 type = 'SimObject'
1032 abstract = True
1033
1034 cxx_header = "sim/sim_object.hh"
1035 cxx_bases = [ "Drainable", "Serializable" ]
1036 eventq_index = Param.UInt32(Parent.eventq_index, "Event Queue Index")
1037
1038 @classmethod
1039 def export_method_swig_predecls(cls, code):
1040 code('''
1041%include <std_string.i>
1042
1043%import "python/swig/drain.i"
1044%import "python/swig/serialize.i"
1045''')
1046
1047 @classmethod
1048 def export_methods(cls, code):
1049 code('''
1050 void init();
1051 void loadState(CheckpointIn &cp);
1052 void initState();
1053 void memInvalidate();
1054 void memWriteback();
1055 void regStats();
1056 void resetStats();
1057 void regProbePoints();
1058 void regProbeListeners();
1059 void startup();
1060''')
1061
1062 cxx_exports = [
1063 PyBindMethod("init"),
1064 PyBindMethod("initState"),
1065 PyBindMethod("memInvalidate"),
1066 PyBindMethod("memWriteback"),
1067 PyBindMethod("regStats"),
1068 PyBindMethod("resetStats"),
1069 PyBindMethod("regProbePoints"),
1070 PyBindMethod("regProbeListeners"),
1071 PyBindMethod("startup"),
1072 ]
1073
1074 cxx_param_exports = [
1075 PyBindProperty("name"),
1076 ]
1077
1078 @cxxMethod
1079 def loadState(self, cp):
1080 """Load SimObject state from a checkpoint"""
1081 pass
1082
924 # Returns a dict of all the option strings that can be
925 # generated as command line options for this simobject instance
926 # by tracing all reachable params in the top level instance and
927 # any children it contains.
928 def enumerateParams(self, flags_dict = {},
929 cmd_line_str = "", access_str = ""):
930 if hasattr(self, "_paramEnumed"):
931 print "Cycle detected enumerating params"
932 else:
933 self._paramEnumed = True
934 # Scan the children first to pick up all the objects in this SimObj
935 for keys in self._children:
936 child = self._children[keys]
937 next_cmdline_str = cmd_line_str + keys
938 next_access_str = access_str + keys
939 if not isSimObjectVector(child):
940 next_cmdline_str = next_cmdline_str + "."
941 next_access_str = next_access_str + "."
942 flags_dict = child.enumerateParams(flags_dict,
943 next_cmdline_str,
944 next_access_str)
945
946 # Go through the simple params in the simobject in this level
947 # of the simobject hierarchy and save information about the
948 # parameter to be used for generating and processing command line
949 # options to the simulator to set these parameters.
950 for keys,values in self._params.items():
951 if values.isCmdLineSettable():
952 type_str = ''
953 ex_str = values.example_str()
954 ptype = None
955 if isinstance(values, VectorParamDesc):
956 type_str = 'Vector_%s' % values.ptype_str
957 ptype = values
958 else:
959 type_str = '%s' % values.ptype_str
960 ptype = values.ptype
961
962 if keys in self._hr_values\
963 and keys in self._values\
964 and not isinstance(self._values[keys], m5.proxy.BaseProxy):
965 cmd_str = cmd_line_str + keys
966 acc_str = access_str + keys
967 flags_dict[cmd_str] = ParamInfo(ptype,
968 self._params[keys].desc, type_str, ex_str,
969 values.pretty_print(self._hr_values[keys]),
970 acc_str)
971 elif not keys in self._hr_values\
972 and not keys in self._values:
973 # Empty param
974 cmd_str = cmd_line_str + keys
975 acc_str = access_str + keys
976 flags_dict[cmd_str] = ParamInfo(ptype,
977 self._params[keys].desc,
978 type_str, ex_str, '', acc_str)
979
980 return flags_dict
981
982 # Initialize new instance. For objects with SimObject-valued
983 # children, we need to recursively clone the classes represented
984 # by those param values as well in a consistent "deep copy"-style
985 # fashion. That is, we want to make sure that each instance is
986 # cloned only once, and that if there are multiple references to
987 # the same original object, we end up with the corresponding
988 # cloned references all pointing to the same cloned instance.
989 def __init__(self, **kwargs):
990 ancestor = kwargs.get('_ancestor')
991 memo_dict = kwargs.get('_memo')
992 if memo_dict is None:
993 # prepare to memoize any recursively instantiated objects
994 memo_dict = {}
995 elif ancestor:
996 # memoize me now to avoid problems with recursive calls
997 memo_dict[ancestor] = self
998
999 if not ancestor:
1000 ancestor = self.__class__
1001 ancestor._instantiated = True
1002
1003 # initialize required attributes
1004 self._parent = None
1005 self._name = None
1006 self._ccObject = None # pointer to C++ object
1007 self._ccParams = None
1008 self._instantiated = False # really "cloned"
1009
1010 # Clone children specified at class level. No need for a
1011 # multidict here since we will be cloning everything.
1012 # Do children before parameter values so that children that
1013 # are also param values get cloned properly.
1014 self._children = {}
1015 for key,val in ancestor._children.iteritems():
1016 self.add_child(key, val(_memo=memo_dict))
1017
1018 # Inherit parameter values from class using multidict so
1019 # individual value settings can be overridden but we still
1020 # inherit late changes to non-overridden class values.
1021 self._values = multidict(ancestor._values)
1022 self._hr_values = multidict(ancestor._hr_values)
1023 # clone SimObject-valued parameters
1024 for key,val in ancestor._values.iteritems():
1025 val = tryAsSimObjectOrVector(val)
1026 if val is not None:
1027 self._values[key] = val(_memo=memo_dict)
1028
1029 # clone port references. no need to use a multidict here
1030 # since we will be creating new references for all ports.
1031 self._port_refs = {}
1032 for key,val in ancestor._port_refs.iteritems():
1033 self._port_refs[key] = val.clone(self, memo_dict)
1034 # apply attribute assignments from keyword args, if any
1035 for key,val in kwargs.iteritems():
1036 setattr(self, key, val)
1037
1038 # "Clone" the current instance by creating another instance of
1039 # this instance's class, but that inherits its parameter values
1040 # and port mappings from the current instance. If we're in a
1041 # "deep copy" recursive clone, check the _memo dict to see if
1042 # we've already cloned this instance.
1043 def __call__(self, **kwargs):
1044 memo_dict = kwargs.get('_memo')
1045 if memo_dict is None:
1046 # no memo_dict: must be top-level clone operation.
1047 # this is only allowed at the root of a hierarchy
1048 if self._parent:
1049 raise RuntimeError, "attempt to clone object %s " \
1050 "not at the root of a tree (parent = %s)" \
1051 % (self, self._parent)
1052 # create a new dict and use that.
1053 memo_dict = {}
1054 kwargs['_memo'] = memo_dict
1055 elif memo_dict.has_key(self):
1056 # clone already done & memoized
1057 return memo_dict[self]
1058 return self.__class__(_ancestor = self, **kwargs)
1059
1060 def _get_port_ref(self, attr):
1061 # Return reference that can be assigned to another port
1062 # via __setattr__. There is only ever one reference
1063 # object per port, but we create them lazily here.
1064 ref = self._port_refs.get(attr)
1065 if ref == None:
1066 ref = self._ports[attr].makeRef(self)
1067 self._port_refs[attr] = ref
1068 return ref
1069
1070 def __getattr__(self, attr):
1071 if self._ports.has_key(attr):
1072 return self._get_port_ref(attr)
1073
1074 if self._values.has_key(attr):
1075 return self._values[attr]
1076
1077 if self._children.has_key(attr):
1078 return self._children[attr]
1079
1080 # If the attribute exists on the C++ object, transparently
1081 # forward the reference there. This is typically used for
1082 # SWIG-wrapped methods such as init(), regStats(),
1083 # resetStats(), startup(), drain(), and
1084 # resume().
1085 if self._ccObject and hasattr(self._ccObject, attr):
1086 return getattr(self._ccObject, attr)
1087
1088 err_string = "object '%s' has no attribute '%s'" \
1089 % (self.__class__.__name__, attr)
1090
1091 if not self._ccObject:
1092 err_string += "\n (C++ object is not yet constructed," \
1093 " so wrapped C++ methods are unavailable.)"
1094
1095 raise AttributeError, err_string
1096
1097 # Set attribute (called on foo.attr = value when foo is an
1098 # instance of class cls).
1099 def __setattr__(self, attr, value):
1100 # normal processing for private attributes
1101 if attr.startswith('_'):
1102 object.__setattr__(self, attr, value)
1103 return
1104
1105 if self._ports.has_key(attr):
1106 # set up port connection
1107 self._get_port_ref(attr).connect(value)
1108 return
1109
1110 param = self._params.get(attr)
1111 if param:
1112 try:
1113 hr_value = value
1114 value = param.convert(value)
1115 except Exception, e:
1116 msg = "%s\nError setting param %s.%s to %s\n" % \
1117 (e, self.__class__.__name__, attr, value)
1118 e.args = (msg, )
1119 raise
1120 self._values[attr] = value
1121 # implicitly parent unparented objects assigned as params
1122 if isSimObjectOrVector(value) and not value.has_parent():
1123 self.add_child(attr, value)
1124 # set the human-readable value dict if this is a param
1125 # with a literal value and is not being set as an object
1126 # or proxy.
1127 if not (isSimObjectOrVector(value) or\
1128 isinstance(value, m5.proxy.BaseProxy)):
1129 self._hr_values[attr] = hr_value
1130
1131 return
1132
1133 # if RHS is a SimObject, it's an implicit child assignment
1134 if isSimObjectOrSequence(value):
1135 self.add_child(attr, value)
1136 return
1137
1138 # no valid assignment... raise exception
1139 raise AttributeError, "Class %s has no parameter %s" \
1140 % (self.__class__.__name__, attr)
1141
1142
1143 # this hack allows tacking a '[0]' onto parameters that may or may
1144 # not be vectors, and always getting the first element (e.g. cpus)
1145 def __getitem__(self, key):
1146 if key == 0:
1147 return self
1148 raise IndexError, "Non-zero index '%s' to SimObject" % key
1149
1150 # this hack allows us to iterate over a SimObject that may
1151 # not be a vector, so we can call a loop over it and get just one
1152 # element.
1153 def __len__(self):
1154 return 1
1155
1156 # Also implemented by SimObjectVector
1157 def clear_parent(self, old_parent):
1158 assert self._parent is old_parent
1159 self._parent = None
1160
1161 # Also implemented by SimObjectVector
1162 def set_parent(self, parent, name):
1163 self._parent = parent
1164 self._name = name
1165
1166 # Return parent object of this SimObject, not implemented by SimObjectVector
1167 # because the elements in a SimObjectVector may not share the same parent
1168 def get_parent(self):
1169 return self._parent
1170
1171 # Also implemented by SimObjectVector
1172 def get_name(self):
1173 return self._name
1174
1175 # Also implemented by SimObjectVector
1176 def has_parent(self):
1177 return self._parent is not None
1178
1179 # clear out child with given name. This code is not likely to be exercised.
1180 # See comment in add_child.
1181 def clear_child(self, name):
1182 child = self._children[name]
1183 child.clear_parent(self)
1184 del self._children[name]
1185
1186 # Add a new child to this object.
1187 def add_child(self, name, child):
1188 child = coerceSimObjectOrVector(child)
1189 if child.has_parent():
1190 warn("add_child('%s'): child '%s' already has parent", name,
1191 child.get_name())
1192 if self._children.has_key(name):
1193 # This code path had an undiscovered bug that would make it fail
1194 # at runtime. It had been here for a long time and was only
1195 # exposed by a buggy script. Changes here will probably not be
1196 # exercised without specialized testing.
1197 self.clear_child(name)
1198 child.set_parent(self, name)
1199 self._children[name] = child
1200
1201 # Take SimObject-valued parameters that haven't been explicitly
1202 # assigned as children and make them children of the object that
1203 # they were assigned to as a parameter value. This guarantees
1204 # that when we instantiate all the parameter objects we're still
1205 # inside the configuration hierarchy.
1206 def adoptOrphanParams(self):
1207 for key,val in self._values.iteritems():
1208 if not isSimObjectVector(val) and isSimObjectSequence(val):
1209 # need to convert raw SimObject sequences to
1210 # SimObjectVector class so we can call has_parent()
1211 val = SimObjectVector(val)
1212 self._values[key] = val
1213 if isSimObjectOrVector(val) and not val.has_parent():
1214 warn("%s adopting orphan SimObject param '%s'", self, key)
1215 self.add_child(key, val)
1216
1217 def path(self):
1218 if not self._parent:
1219 return '<orphan %s>' % self.__class__
1220 elif isinstance(self._parent, MetaSimObject):
1221 return str(self.__class__)
1222
1223 ppath = self._parent.path()
1224 if ppath == 'root':
1225 return self._name
1226 return ppath + "." + self._name
1227
1228 def __str__(self):
1229 return self.path()
1230
1231 def config_value(self):
1232 return self.path()
1233
1234 def ini_str(self):
1235 return self.path()
1236
1237 def find_any(self, ptype):
1238 if isinstance(self, ptype):
1239 return self, True
1240
1241 found_obj = None
1242 for child in self._children.itervalues():
1243 visited = False
1244 if hasattr(child, '_visited'):
1245 visited = getattr(child, '_visited')
1246
1247 if isinstance(child, ptype) and not visited:
1248 if found_obj != None and child != found_obj:
1249 raise AttributeError, \
1250 'parent.any matched more than one: %s %s' % \
1251 (found_obj.path, child.path)
1252 found_obj = child
1253 # search param space
1254 for pname,pdesc in self._params.iteritems():
1255 if issubclass(pdesc.ptype, ptype):
1256 match_obj = self._values[pname]
1257 if found_obj != None and found_obj != match_obj:
1258 raise AttributeError, \
1259 'parent.any matched more than one: %s and %s' % (found_obj.path, match_obj.path)
1260 found_obj = match_obj
1261 return found_obj, found_obj != None
1262
1263 def find_all(self, ptype):
1264 all = {}
1265 # search children
1266 for child in self._children.itervalues():
1267 # a child could be a list, so ensure we visit each item
1268 if isinstance(child, list):
1269 children = child
1270 else:
1271 children = [child]
1272
1273 for child in children:
1274 if isinstance(child, ptype) and not isproxy(child) and \
1275 not isNullPointer(child):
1276 all[child] = True
1277 if isSimObject(child):
1278 # also add results from the child itself
1279 child_all, done = child.find_all(ptype)
1280 all.update(dict(zip(child_all, [done] * len(child_all))))
1281 # search param space
1282 for pname,pdesc in self._params.iteritems():
1283 if issubclass(pdesc.ptype, ptype):
1284 match_obj = self._values[pname]
1285 if not isproxy(match_obj) and not isNullPointer(match_obj):
1286 all[match_obj] = True
1287 # Also make sure to sort the keys based on the objects' path to
1288 # ensure that the order is the same on all hosts
1289 return sorted(all.keys(), key = lambda o: o.path()), True
1290
1291 def unproxy(self, base):
1292 return self
1293
1294 def unproxyParams(self):
1295 for param in self._params.iterkeys():
1296 value = self._values.get(param)
1297 if value != None and isproxy(value):
1298 try:
1299 value = value.unproxy(self)
1300 except:
1301 print "Error in unproxying param '%s' of %s" % \
1302 (param, self.path())
1303 raise
1304 setattr(self, param, value)
1305
1306 # Unproxy ports in sorted order so that 'append' operations on
1307 # vector ports are done in a deterministic fashion.
1308 port_names = self._ports.keys()
1309 port_names.sort()
1310 for port_name in port_names:
1311 port = self._port_refs.get(port_name)
1312 if port != None:
1313 port.unproxy(self)
1314
1315 def print_ini(self, ini_file):
1316 print >>ini_file, '[' + self.path() + ']' # .ini section header
1317
1318 instanceDict[self.path()] = self
1319
1320 if hasattr(self, 'type'):
1321 print >>ini_file, 'type=%s' % self.type
1322
1323 if len(self._children.keys()):
1324 print >>ini_file, 'children=%s' % \
1325 ' '.join(self._children[n].get_name() \
1326 for n in sorted(self._children.keys()))
1327
1328 for param in sorted(self._params.keys()):
1329 value = self._values.get(param)
1330 if value != None:
1331 print >>ini_file, '%s=%s' % (param,
1332 self._values[param].ini_str())
1333
1334 for port_name in sorted(self._ports.keys()):
1335 port = self._port_refs.get(port_name, None)
1336 if port != None:
1337 print >>ini_file, '%s=%s' % (port_name, port.ini_str())
1338
1339 print >>ini_file # blank line between objects
1340
1341 # generate a tree of dictionaries expressing all the parameters in the
1342 # instantiated system for use by scripts that want to do power, thermal
1343 # visualization, and other similar tasks
1344 def get_config_as_dict(self):
1345 d = attrdict()
1346 if hasattr(self, 'type'):
1347 d.type = self.type
1348 if hasattr(self, 'cxx_class'):
1349 d.cxx_class = self.cxx_class
1350 # Add the name and path of this object to be able to link to
1351 # the stats
1352 d.name = self.get_name()
1353 d.path = self.path()
1354
1355 for param in sorted(self._params.keys()):
1356 value = self._values.get(param)
1357 if value != None:
1358 d[param] = value.config_value()
1359
1360 for n in sorted(self._children.keys()):
1361 child = self._children[n]
1362 # Use the name of the attribute (and not get_name()) as
1363 # the key in the JSON dictionary to capture the hierarchy
1364 # in the Python code that assembled this system
1365 d[n] = child.get_config_as_dict()
1366
1367 for port_name in sorted(self._ports.keys()):
1368 port = self._port_refs.get(port_name, None)
1369 if port != None:
1370 # Represent each port with a dictionary containing the
1371 # prominent attributes
1372 d[port_name] = port.get_config_as_dict()
1373
1374 return d
1375
1376 def getCCParams(self):
1377 if self._ccParams:
1378 return self._ccParams
1379
1380 cc_params_struct = getattr(m5.internal.params, '%sParams' % self.type)
1381 cc_params = cc_params_struct()
1083 # Returns a dict of all the option strings that can be
1084 # generated as command line options for this simobject instance
1085 # by tracing all reachable params in the top level instance and
1086 # any children it contains.
1087 def enumerateParams(self, flags_dict = {},
1088 cmd_line_str = "", access_str = ""):
1089 if hasattr(self, "_paramEnumed"):
1090 print "Cycle detected enumerating params"
1091 else:
1092 self._paramEnumed = True
1093 # Scan the children first to pick up all the objects in this SimObj
1094 for keys in self._children:
1095 child = self._children[keys]
1096 next_cmdline_str = cmd_line_str + keys
1097 next_access_str = access_str + keys
1098 if not isSimObjectVector(child):
1099 next_cmdline_str = next_cmdline_str + "."
1100 next_access_str = next_access_str + "."
1101 flags_dict = child.enumerateParams(flags_dict,
1102 next_cmdline_str,
1103 next_access_str)
1104
1105 # Go through the simple params in the simobject in this level
1106 # of the simobject hierarchy and save information about the
1107 # parameter to be used for generating and processing command line
1108 # options to the simulator to set these parameters.
1109 for keys,values in self._params.items():
1110 if values.isCmdLineSettable():
1111 type_str = ''
1112 ex_str = values.example_str()
1113 ptype = None
1114 if isinstance(values, VectorParamDesc):
1115 type_str = 'Vector_%s' % values.ptype_str
1116 ptype = values
1117 else:
1118 type_str = '%s' % values.ptype_str
1119 ptype = values.ptype
1120
1121 if keys in self._hr_values\
1122 and keys in self._values\
1123 and not isinstance(self._values[keys], m5.proxy.BaseProxy):
1124 cmd_str = cmd_line_str + keys
1125 acc_str = access_str + keys
1126 flags_dict[cmd_str] = ParamInfo(ptype,
1127 self._params[keys].desc, type_str, ex_str,
1128 values.pretty_print(self._hr_values[keys]),
1129 acc_str)
1130 elif not keys in self._hr_values\
1131 and not keys in self._values:
1132 # Empty param
1133 cmd_str = cmd_line_str + keys
1134 acc_str = access_str + keys
1135 flags_dict[cmd_str] = ParamInfo(ptype,
1136 self._params[keys].desc,
1137 type_str, ex_str, '', acc_str)
1138
1139 return flags_dict
1140
1141 # Initialize new instance. For objects with SimObject-valued
1142 # children, we need to recursively clone the classes represented
1143 # by those param values as well in a consistent "deep copy"-style
1144 # fashion. That is, we want to make sure that each instance is
1145 # cloned only once, and that if there are multiple references to
1146 # the same original object, we end up with the corresponding
1147 # cloned references all pointing to the same cloned instance.
1148 def __init__(self, **kwargs):
1149 ancestor = kwargs.get('_ancestor')
1150 memo_dict = kwargs.get('_memo')
1151 if memo_dict is None:
1152 # prepare to memoize any recursively instantiated objects
1153 memo_dict = {}
1154 elif ancestor:
1155 # memoize me now to avoid problems with recursive calls
1156 memo_dict[ancestor] = self
1157
1158 if not ancestor:
1159 ancestor = self.__class__
1160 ancestor._instantiated = True
1161
1162 # initialize required attributes
1163 self._parent = None
1164 self._name = None
1165 self._ccObject = None # pointer to C++ object
1166 self._ccParams = None
1167 self._instantiated = False # really "cloned"
1168
1169 # Clone children specified at class level. No need for a
1170 # multidict here since we will be cloning everything.
1171 # Do children before parameter values so that children that
1172 # are also param values get cloned properly.
1173 self._children = {}
1174 for key,val in ancestor._children.iteritems():
1175 self.add_child(key, val(_memo=memo_dict))
1176
1177 # Inherit parameter values from class using multidict so
1178 # individual value settings can be overridden but we still
1179 # inherit late changes to non-overridden class values.
1180 self._values = multidict(ancestor._values)
1181 self._hr_values = multidict(ancestor._hr_values)
1182 # clone SimObject-valued parameters
1183 for key,val in ancestor._values.iteritems():
1184 val = tryAsSimObjectOrVector(val)
1185 if val is not None:
1186 self._values[key] = val(_memo=memo_dict)
1187
1188 # clone port references. no need to use a multidict here
1189 # since we will be creating new references for all ports.
1190 self._port_refs = {}
1191 for key,val in ancestor._port_refs.iteritems():
1192 self._port_refs[key] = val.clone(self, memo_dict)
1193 # apply attribute assignments from keyword args, if any
1194 for key,val in kwargs.iteritems():
1195 setattr(self, key, val)
1196
1197 # "Clone" the current instance by creating another instance of
1198 # this instance's class, but that inherits its parameter values
1199 # and port mappings from the current instance. If we're in a
1200 # "deep copy" recursive clone, check the _memo dict to see if
1201 # we've already cloned this instance.
1202 def __call__(self, **kwargs):
1203 memo_dict = kwargs.get('_memo')
1204 if memo_dict is None:
1205 # no memo_dict: must be top-level clone operation.
1206 # this is only allowed at the root of a hierarchy
1207 if self._parent:
1208 raise RuntimeError, "attempt to clone object %s " \
1209 "not at the root of a tree (parent = %s)" \
1210 % (self, self._parent)
1211 # create a new dict and use that.
1212 memo_dict = {}
1213 kwargs['_memo'] = memo_dict
1214 elif memo_dict.has_key(self):
1215 # clone already done & memoized
1216 return memo_dict[self]
1217 return self.__class__(_ancestor = self, **kwargs)
1218
1219 def _get_port_ref(self, attr):
1220 # Return reference that can be assigned to another port
1221 # via __setattr__. There is only ever one reference
1222 # object per port, but we create them lazily here.
1223 ref = self._port_refs.get(attr)
1224 if ref == None:
1225 ref = self._ports[attr].makeRef(self)
1226 self._port_refs[attr] = ref
1227 return ref
1228
1229 def __getattr__(self, attr):
1230 if self._ports.has_key(attr):
1231 return self._get_port_ref(attr)
1232
1233 if self._values.has_key(attr):
1234 return self._values[attr]
1235
1236 if self._children.has_key(attr):
1237 return self._children[attr]
1238
1239 # If the attribute exists on the C++ object, transparently
1240 # forward the reference there. This is typically used for
1241 # SWIG-wrapped methods such as init(), regStats(),
1242 # resetStats(), startup(), drain(), and
1243 # resume().
1244 if self._ccObject and hasattr(self._ccObject, attr):
1245 return getattr(self._ccObject, attr)
1246
1247 err_string = "object '%s' has no attribute '%s'" \
1248 % (self.__class__.__name__, attr)
1249
1250 if not self._ccObject:
1251 err_string += "\n (C++ object is not yet constructed," \
1252 " so wrapped C++ methods are unavailable.)"
1253
1254 raise AttributeError, err_string
1255
1256 # Set attribute (called on foo.attr = value when foo is an
1257 # instance of class cls).
1258 def __setattr__(self, attr, value):
1259 # normal processing for private attributes
1260 if attr.startswith('_'):
1261 object.__setattr__(self, attr, value)
1262 return
1263
1264 if self._ports.has_key(attr):
1265 # set up port connection
1266 self._get_port_ref(attr).connect(value)
1267 return
1268
1269 param = self._params.get(attr)
1270 if param:
1271 try:
1272 hr_value = value
1273 value = param.convert(value)
1274 except Exception, e:
1275 msg = "%s\nError setting param %s.%s to %s\n" % \
1276 (e, self.__class__.__name__, attr, value)
1277 e.args = (msg, )
1278 raise
1279 self._values[attr] = value
1280 # implicitly parent unparented objects assigned as params
1281 if isSimObjectOrVector(value) and not value.has_parent():
1282 self.add_child(attr, value)
1283 # set the human-readable value dict if this is a param
1284 # with a literal value and is not being set as an object
1285 # or proxy.
1286 if not (isSimObjectOrVector(value) or\
1287 isinstance(value, m5.proxy.BaseProxy)):
1288 self._hr_values[attr] = hr_value
1289
1290 return
1291
1292 # if RHS is a SimObject, it's an implicit child assignment
1293 if isSimObjectOrSequence(value):
1294 self.add_child(attr, value)
1295 return
1296
1297 # no valid assignment... raise exception
1298 raise AttributeError, "Class %s has no parameter %s" \
1299 % (self.__class__.__name__, attr)
1300
1301
1302 # this hack allows tacking a '[0]' onto parameters that may or may
1303 # not be vectors, and always getting the first element (e.g. cpus)
1304 def __getitem__(self, key):
1305 if key == 0:
1306 return self
1307 raise IndexError, "Non-zero index '%s' to SimObject" % key
1308
1309 # this hack allows us to iterate over a SimObject that may
1310 # not be a vector, so we can call a loop over it and get just one
1311 # element.
1312 def __len__(self):
1313 return 1
1314
1315 # Also implemented by SimObjectVector
1316 def clear_parent(self, old_parent):
1317 assert self._parent is old_parent
1318 self._parent = None
1319
1320 # Also implemented by SimObjectVector
1321 def set_parent(self, parent, name):
1322 self._parent = parent
1323 self._name = name
1324
1325 # Return parent object of this SimObject, not implemented by SimObjectVector
1326 # because the elements in a SimObjectVector may not share the same parent
1327 def get_parent(self):
1328 return self._parent
1329
1330 # Also implemented by SimObjectVector
1331 def get_name(self):
1332 return self._name
1333
1334 # Also implemented by SimObjectVector
1335 def has_parent(self):
1336 return self._parent is not None
1337
1338 # clear out child with given name. This code is not likely to be exercised.
1339 # See comment in add_child.
1340 def clear_child(self, name):
1341 child = self._children[name]
1342 child.clear_parent(self)
1343 del self._children[name]
1344
1345 # Add a new child to this object.
1346 def add_child(self, name, child):
1347 child = coerceSimObjectOrVector(child)
1348 if child.has_parent():
1349 warn("add_child('%s'): child '%s' already has parent", name,
1350 child.get_name())
1351 if self._children.has_key(name):
1352 # This code path had an undiscovered bug that would make it fail
1353 # at runtime. It had been here for a long time and was only
1354 # exposed by a buggy script. Changes here will probably not be
1355 # exercised without specialized testing.
1356 self.clear_child(name)
1357 child.set_parent(self, name)
1358 self._children[name] = child
1359
1360 # Take SimObject-valued parameters that haven't been explicitly
1361 # assigned as children and make them children of the object that
1362 # they were assigned to as a parameter value. This guarantees
1363 # that when we instantiate all the parameter objects we're still
1364 # inside the configuration hierarchy.
1365 def adoptOrphanParams(self):
1366 for key,val in self._values.iteritems():
1367 if not isSimObjectVector(val) and isSimObjectSequence(val):
1368 # need to convert raw SimObject sequences to
1369 # SimObjectVector class so we can call has_parent()
1370 val = SimObjectVector(val)
1371 self._values[key] = val
1372 if isSimObjectOrVector(val) and not val.has_parent():
1373 warn("%s adopting orphan SimObject param '%s'", self, key)
1374 self.add_child(key, val)
1375
1376 def path(self):
1377 if not self._parent:
1378 return '<orphan %s>' % self.__class__
1379 elif isinstance(self._parent, MetaSimObject):
1380 return str(self.__class__)
1381
1382 ppath = self._parent.path()
1383 if ppath == 'root':
1384 return self._name
1385 return ppath + "." + self._name
1386
1387 def __str__(self):
1388 return self.path()
1389
1390 def config_value(self):
1391 return self.path()
1392
1393 def ini_str(self):
1394 return self.path()
1395
1396 def find_any(self, ptype):
1397 if isinstance(self, ptype):
1398 return self, True
1399
1400 found_obj = None
1401 for child in self._children.itervalues():
1402 visited = False
1403 if hasattr(child, '_visited'):
1404 visited = getattr(child, '_visited')
1405
1406 if isinstance(child, ptype) and not visited:
1407 if found_obj != None and child != found_obj:
1408 raise AttributeError, \
1409 'parent.any matched more than one: %s %s' % \
1410 (found_obj.path, child.path)
1411 found_obj = child
1412 # search param space
1413 for pname,pdesc in self._params.iteritems():
1414 if issubclass(pdesc.ptype, ptype):
1415 match_obj = self._values[pname]
1416 if found_obj != None and found_obj != match_obj:
1417 raise AttributeError, \
1418 'parent.any matched more than one: %s and %s' % (found_obj.path, match_obj.path)
1419 found_obj = match_obj
1420 return found_obj, found_obj != None
1421
1422 def find_all(self, ptype):
1423 all = {}
1424 # search children
1425 for child in self._children.itervalues():
1426 # a child could be a list, so ensure we visit each item
1427 if isinstance(child, list):
1428 children = child
1429 else:
1430 children = [child]
1431
1432 for child in children:
1433 if isinstance(child, ptype) and not isproxy(child) and \
1434 not isNullPointer(child):
1435 all[child] = True
1436 if isSimObject(child):
1437 # also add results from the child itself
1438 child_all, done = child.find_all(ptype)
1439 all.update(dict(zip(child_all, [done] * len(child_all))))
1440 # search param space
1441 for pname,pdesc in self._params.iteritems():
1442 if issubclass(pdesc.ptype, ptype):
1443 match_obj = self._values[pname]
1444 if not isproxy(match_obj) and not isNullPointer(match_obj):
1445 all[match_obj] = True
1446 # Also make sure to sort the keys based on the objects' path to
1447 # ensure that the order is the same on all hosts
1448 return sorted(all.keys(), key = lambda o: o.path()), True
1449
1450 def unproxy(self, base):
1451 return self
1452
1453 def unproxyParams(self):
1454 for param in self._params.iterkeys():
1455 value = self._values.get(param)
1456 if value != None and isproxy(value):
1457 try:
1458 value = value.unproxy(self)
1459 except:
1460 print "Error in unproxying param '%s' of %s" % \
1461 (param, self.path())
1462 raise
1463 setattr(self, param, value)
1464
1465 # Unproxy ports in sorted order so that 'append' operations on
1466 # vector ports are done in a deterministic fashion.
1467 port_names = self._ports.keys()
1468 port_names.sort()
1469 for port_name in port_names:
1470 port = self._port_refs.get(port_name)
1471 if port != None:
1472 port.unproxy(self)
1473
1474 def print_ini(self, ini_file):
1475 print >>ini_file, '[' + self.path() + ']' # .ini section header
1476
1477 instanceDict[self.path()] = self
1478
1479 if hasattr(self, 'type'):
1480 print >>ini_file, 'type=%s' % self.type
1481
1482 if len(self._children.keys()):
1483 print >>ini_file, 'children=%s' % \
1484 ' '.join(self._children[n].get_name() \
1485 for n in sorted(self._children.keys()))
1486
1487 for param in sorted(self._params.keys()):
1488 value = self._values.get(param)
1489 if value != None:
1490 print >>ini_file, '%s=%s' % (param,
1491 self._values[param].ini_str())
1492
1493 for port_name in sorted(self._ports.keys()):
1494 port = self._port_refs.get(port_name, None)
1495 if port != None:
1496 print >>ini_file, '%s=%s' % (port_name, port.ini_str())
1497
1498 print >>ini_file # blank line between objects
1499
1500 # generate a tree of dictionaries expressing all the parameters in the
1501 # instantiated system for use by scripts that want to do power, thermal
1502 # visualization, and other similar tasks
1503 def get_config_as_dict(self):
1504 d = attrdict()
1505 if hasattr(self, 'type'):
1506 d.type = self.type
1507 if hasattr(self, 'cxx_class'):
1508 d.cxx_class = self.cxx_class
1509 # Add the name and path of this object to be able to link to
1510 # the stats
1511 d.name = self.get_name()
1512 d.path = self.path()
1513
1514 for param in sorted(self._params.keys()):
1515 value = self._values.get(param)
1516 if value != None:
1517 d[param] = value.config_value()
1518
1519 for n in sorted(self._children.keys()):
1520 child = self._children[n]
1521 # Use the name of the attribute (and not get_name()) as
1522 # the key in the JSON dictionary to capture the hierarchy
1523 # in the Python code that assembled this system
1524 d[n] = child.get_config_as_dict()
1525
1526 for port_name in sorted(self._ports.keys()):
1527 port = self._port_refs.get(port_name, None)
1528 if port != None:
1529 # Represent each port with a dictionary containing the
1530 # prominent attributes
1531 d[port_name] = port.get_config_as_dict()
1532
1533 return d
1534
1535 def getCCParams(self):
1536 if self._ccParams:
1537 return self._ccParams
1538
1539 cc_params_struct = getattr(m5.internal.params, '%sParams' % self.type)
1540 cc_params = cc_params_struct()
1382 cc_params.pyobj = self
1383 cc_params.name = str(self)
1384
1385 param_names = self._params.keys()
1386 param_names.sort()
1387 for param in param_names:
1388 value = self._values.get(param)
1389 if value is None:
1390 fatal("%s.%s without default or user set value",
1391 self.path(), param)
1392
1393 value = value.getValue()
1394 if isinstance(self._params[param], VectorParamDesc):
1395 assert isinstance(value, list)
1396 vec = getattr(cc_params, param)
1397 assert not len(vec)
1541 cc_params.name = str(self)
1542
1543 param_names = self._params.keys()
1544 param_names.sort()
1545 for param in param_names:
1546 value = self._values.get(param)
1547 if value is None:
1548 fatal("%s.%s without default or user set value",
1549 self.path(), param)
1550
1551 value = value.getValue()
1552 if isinstance(self._params[param], VectorParamDesc):
1553 assert isinstance(value, list)
1554 vec = getattr(cc_params, param)
1555 assert not len(vec)
1398 for v in value:
1399 vec.append(v)
1556 setattr(cc_params, param, list(value))
1400 else:
1401 setattr(cc_params, param, value)
1402
1403 port_names = self._ports.keys()
1404 port_names.sort()
1405 for port_name in port_names:
1406 port = self._port_refs.get(port_name, None)
1407 if port != None:
1408 port_count = len(port)
1409 else:
1410 port_count = 0
1411 setattr(cc_params, 'port_' + port_name + '_connection_count',
1412 port_count)
1413 self._ccParams = cc_params
1414 return self._ccParams
1415
1416 # Get C++ object corresponding to this object, calling C++ if
1417 # necessary to construct it. Does *not* recursively create
1418 # children.
1419 def getCCObject(self):
1420 if not self._ccObject:
1421 # Make sure this object is in the configuration hierarchy
1422 if not self._parent and not isRoot(self):
1423 raise RuntimeError, "Attempt to instantiate orphan node"
1424 # Cycles in the configuration hierarchy are not supported. This
1425 # will catch the resulting recursion and stop.
1426 self._ccObject = -1
1427 if not self.abstract:
1428 params = self.getCCParams()
1429 self._ccObject = params.create()
1430 elif self._ccObject == -1:
1431 raise RuntimeError, "%s: Cycle found in configuration hierarchy." \
1432 % self.path()
1433 return self._ccObject
1434
1435 def descendants(self):
1436 yield self
1437 # The order of the dict is implementation dependent, so sort
1438 # it based on the key (name) to ensure the order is the same
1439 # on all hosts
1440 for (name, child) in sorted(self._children.iteritems()):
1441 for obj in child.descendants():
1442 yield obj
1443
1444 # Call C++ to create C++ object corresponding to this object
1445 def createCCObject(self):
1446 self.getCCParams()
1447 self.getCCObject() # force creation
1448
1449 def getValue(self):
1450 return self.getCCObject()
1451
1452 # Create C++ port connections corresponding to the connections in
1453 # _port_refs
1454 def connectPorts(self):
1455 # Sort the ports based on their attribute name to ensure the
1456 # order is the same on all hosts
1457 for (attr, portRef) in sorted(self._port_refs.iteritems()):
1458 portRef.ccConnect()
1459
1460# Function to provide to C++ so it can look up instances based on paths
1461def resolveSimObject(name):
1462 obj = instanceDict[name]
1463 return obj.getCCObject()
1464
1465def isSimObject(value):
1466 return isinstance(value, SimObject)
1467
1468def isSimObjectClass(value):
1469 return issubclass(value, SimObject)
1470
1471def isSimObjectVector(value):
1472 return isinstance(value, SimObjectVector)
1473
1474def isSimObjectSequence(value):
1475 if not isinstance(value, (list, tuple)) or len(value) == 0:
1476 return False
1477
1478 for val in value:
1479 if not isNullPointer(val) and not isSimObject(val):
1480 return False
1481
1482 return True
1483
1484def isSimObjectOrSequence(value):
1485 return isSimObject(value) or isSimObjectSequence(value)
1486
1487def isRoot(obj):
1488 from m5.objects import Root
1489 return obj and obj is Root.getInstance()
1490
1491def isSimObjectOrVector(value):
1492 return isSimObject(value) or isSimObjectVector(value)
1493
1494def tryAsSimObjectOrVector(value):
1495 if isSimObjectOrVector(value):
1496 return value
1497 if isSimObjectSequence(value):
1498 return SimObjectVector(value)
1499 return None
1500
1501def coerceSimObjectOrVector(value):
1502 value = tryAsSimObjectOrVector(value)
1503 if value is None:
1504 raise TypeError, "SimObject or SimObjectVector expected"
1505 return value
1506
1507baseClasses = allClasses.copy()
1508baseInstances = instanceDict.copy()
1509
1510def clear():
1511 global allClasses, instanceDict, noCxxHeader
1512
1513 allClasses = baseClasses.copy()
1514 instanceDict = baseInstances.copy()
1515 noCxxHeader = False
1516
1517# __all__ defines the list of symbols that get exported when
1518# 'from config import *' is invoked. Try to keep this reasonably
1519# short to avoid polluting other namespaces.
1557 else:
1558 setattr(cc_params, param, value)
1559
1560 port_names = self._ports.keys()
1561 port_names.sort()
1562 for port_name in port_names:
1563 port = self._port_refs.get(port_name, None)
1564 if port != None:
1565 port_count = len(port)
1566 else:
1567 port_count = 0
1568 setattr(cc_params, 'port_' + port_name + '_connection_count',
1569 port_count)
1570 self._ccParams = cc_params
1571 return self._ccParams
1572
1573 # Get C++ object corresponding to this object, calling C++ if
1574 # necessary to construct it. Does *not* recursively create
1575 # children.
1576 def getCCObject(self):
1577 if not self._ccObject:
1578 # Make sure this object is in the configuration hierarchy
1579 if not self._parent and not isRoot(self):
1580 raise RuntimeError, "Attempt to instantiate orphan node"
1581 # Cycles in the configuration hierarchy are not supported. This
1582 # will catch the resulting recursion and stop.
1583 self._ccObject = -1
1584 if not self.abstract:
1585 params = self.getCCParams()
1586 self._ccObject = params.create()
1587 elif self._ccObject == -1:
1588 raise RuntimeError, "%s: Cycle found in configuration hierarchy." \
1589 % self.path()
1590 return self._ccObject
1591
1592 def descendants(self):
1593 yield self
1594 # The order of the dict is implementation dependent, so sort
1595 # it based on the key (name) to ensure the order is the same
1596 # on all hosts
1597 for (name, child) in sorted(self._children.iteritems()):
1598 for obj in child.descendants():
1599 yield obj
1600
1601 # Call C++ to create C++ object corresponding to this object
1602 def createCCObject(self):
1603 self.getCCParams()
1604 self.getCCObject() # force creation
1605
1606 def getValue(self):
1607 return self.getCCObject()
1608
1609 # Create C++ port connections corresponding to the connections in
1610 # _port_refs
1611 def connectPorts(self):
1612 # Sort the ports based on their attribute name to ensure the
1613 # order is the same on all hosts
1614 for (attr, portRef) in sorted(self._port_refs.iteritems()):
1615 portRef.ccConnect()
1616
1617# Function to provide to C++ so it can look up instances based on paths
1618def resolveSimObject(name):
1619 obj = instanceDict[name]
1620 return obj.getCCObject()
1621
1622def isSimObject(value):
1623 return isinstance(value, SimObject)
1624
1625def isSimObjectClass(value):
1626 return issubclass(value, SimObject)
1627
1628def isSimObjectVector(value):
1629 return isinstance(value, SimObjectVector)
1630
1631def isSimObjectSequence(value):
1632 if not isinstance(value, (list, tuple)) or len(value) == 0:
1633 return False
1634
1635 for val in value:
1636 if not isNullPointer(val) and not isSimObject(val):
1637 return False
1638
1639 return True
1640
1641def isSimObjectOrSequence(value):
1642 return isSimObject(value) or isSimObjectSequence(value)
1643
1644def isRoot(obj):
1645 from m5.objects import Root
1646 return obj and obj is Root.getInstance()
1647
1648def isSimObjectOrVector(value):
1649 return isSimObject(value) or isSimObjectVector(value)
1650
1651def tryAsSimObjectOrVector(value):
1652 if isSimObjectOrVector(value):
1653 return value
1654 if isSimObjectSequence(value):
1655 return SimObjectVector(value)
1656 return None
1657
1658def coerceSimObjectOrVector(value):
1659 value = tryAsSimObjectOrVector(value)
1660 if value is None:
1661 raise TypeError, "SimObject or SimObjectVector expected"
1662 return value
1663
1664baseClasses = allClasses.copy()
1665baseInstances = instanceDict.copy()
1666
1667def clear():
1668 global allClasses, instanceDict, noCxxHeader
1669
1670 allClasses = baseClasses.copy()
1671 instanceDict = baseInstances.copy()
1672 noCxxHeader = False
1673
1674# __all__ defines the list of symbols that get exported when
1675# 'from config import *' is invoked. Try to keep this reasonably
1676# short to avoid polluting other namespaces.
1520__all__ = [ 'SimObject' ]
1677__all__ = [
1678 'SimObject',
1679 'cxxMethod',
1680 'PyBindMethod',
1681 'PyBindProperty',
1682]