f553fd664bf196c22a645b9ef209866211f6374c
1 # Copyright (c) 2017-2018 ARM Limited
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.
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.
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.
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.
41 # Authors: Steve Reinhardt
46 from __future__
import print_function
49 from types
import FunctionType
, MethodType
, ModuleType
50 from functools
import wraps
55 from m5
.util
.pybind
import *
56 # Use the pyfdt and not the helper class, because the fdthelper
57 # relies on the SimObject definition
58 from m5
.ext
.pyfdt
import pyfdt
60 # Have to import params up top since Param is referenced on initial
61 # load (when SimObject class references Param to create a class
62 # variable, the 'name' param)...
63 from m5
.params
import *
64 # There are a few things we need that aren't in params.__all__ since
65 # normal users don't need them
66 from m5
.params
import ParamDesc
, VectorParamDesc
, \
67 isNullPointer
, SimObjectVector
, Port
69 from m5
.proxy
import *
70 from m5
.proxy
import isproxy
72 #####################################################################
74 # M5 Python Configuration Utility
76 # The basic idea is to write simple Python programs that build Python
77 # objects corresponding to M5 SimObjects for the desired simulation
78 # configuration. For now, the Python emits a .ini file that can be
79 # parsed by M5. In the future, some tighter integration between M5
80 # and the Python interpreter may allow bypassing the .ini file.
82 # Each SimObject class in M5 is represented by a Python class with the
83 # same name. The Python inheritance tree mirrors the M5 C++ tree
84 # (e.g., SimpleCPU derives from BaseCPU in both cases, and all
85 # SimObjects inherit from a single SimObject base class). To specify
86 # an instance of an M5 SimObject in a configuration, the user simply
87 # instantiates the corresponding Python object. The parameters for
88 # that SimObject are given by assigning to attributes of the Python
89 # object, either using keyword assignment in the constructor or in
90 # separate assignment statements. For example:
92 # cache = BaseCache(size='64KB')
93 # cache.hit_latency = 3
96 # The magic lies in the mapping of the Python attributes for SimObject
97 # classes to the actual SimObject parameter specifications. This
98 # allows parameter validity checking in the Python code. Continuing
99 # the example above, the statements "cache.blurfl=3" or
100 # "cache.assoc='hello'" would both result in runtime errors in Python,
101 # since the BaseCache object has no 'blurfl' parameter and the 'assoc'
102 # parameter requires an integer, respectively. This magic is done
103 # primarily by overriding the special __setattr__ method that controls
104 # assignment to object attributes.
106 # Once a set of Python objects have been instantiated in a hierarchy,
107 # calling 'instantiate(obj)' (where obj is the root of the hierarchy)
108 # will generate a .ini file.
110 #####################################################################
112 # list of all SimObject classes
115 # dict to look up SimObjects based on path
118 # Did any of the SimObjects lack a header file?
121 def public_value(key
, value
):
122 return key
.startswith('_') or \
123 isinstance(value
, (FunctionType
, MethodType
, ModuleType
,
126 def createCxxConfigDirectoryEntryFile(code
, name
, simobj
, is_header
):
127 entry_class
= 'CxxConfigDirectoryEntry_%s' % name
128 param_class
= '%sCxxConfigParams' % name
130 code('#include "params/%s.hh"' % name
)
133 for param
in simobj
._params
.values():
134 if isSimObjectClass(param
.ptype
):
135 code('#include "%s"' % param
.ptype
._value
_dict
['cxx_header'])
136 code('#include "params/%s.hh"' % param
.ptype
.__name
__)
138 param
.ptype
.cxx_ini_predecls(code
)
143 code('#include "sim/cxx_config.hh"')
145 code('class ${param_class} : public CxxConfigParams,'
146 ' public ${name}Params')
150 code('class DirectoryEntry : public CxxConfigDirectoryEntry')
154 code('DirectoryEntry();');
156 code('CxxConfigParams *makeParamsObject() const')
157 code('{ return new ${param_class}; }')
165 member_prefix
= '%s::' % param_class
167 code('#include "%s"' % simobj
._value
_dict
['cxx_header'])
168 code('#include "base/str.hh"')
169 code('#include "cxx_config/${name}.hh"')
171 if simobj
._ports
.values() != []:
172 code('#include "mem/mem_object.hh"')
173 code('#include "mem/port.hh"')
176 code('${member_prefix}DirectoryEntry::DirectoryEntry()');
180 return 'true' if b
else 'false'
183 for param
in simobj
._params
.values():
184 is_vector
= isinstance(param
, m5
.params
.VectorParamDesc
)
185 is_simobj
= issubclass(param
.ptype
, m5
.SimObject
.SimObject
)
187 code('parameters["%s"] = new ParamDesc("%s", %s, %s);' %
188 (param
.name
, param
.name
, cxx_bool(is_vector
),
189 cxx_bool(is_simobj
)));
191 for port
in simobj
._ports
.values():
192 is_vector
= isinstance(port
, m5
.params
.VectorPort
)
193 is_master
= port
.role
== 'MASTER'
195 code('ports["%s"] = new PortDesc("%s", %s, %s);' %
196 (port
.name
, port
.name
, cxx_bool(is_vector
),
197 cxx_bool(is_master
)))
203 code('bool ${member_prefix}setSimObject(const std::string &name,')
204 code(' SimObject *simObject)${end_of_decl}')
209 code('bool ret = true;')
212 for param
in simobj
._params
.values():
213 is_vector
= isinstance(param
, m5
.params
.VectorParamDesc
)
214 is_simobj
= issubclass(param
.ptype
, m5
.SimObject
.SimObject
)
216 if is_simobj
and not is_vector
:
217 code('} else if (name == "${{param.name}}") {')
219 code('this->${{param.name}} = '
220 'dynamic_cast<${{param.ptype.cxx_type}}>(simObject);')
221 code('if (simObject && !this->${{param.name}})')
222 code(' ret = false;')
225 code(' ret = false;')
233 code('bool ${member_prefix}setSimObjectVector('
234 'const std::string &name,')
235 code(' const std::vector<SimObject *> &simObjects)${end_of_decl}')
240 code('bool ret = true;')
243 for param
in simobj
._params
.values():
244 is_vector
= isinstance(param
, m5
.params
.VectorParamDesc
)
245 is_simobj
= issubclass(param
.ptype
, m5
.SimObject
.SimObject
)
247 if is_simobj
and is_vector
:
248 code('} else if (name == "${{param.name}}") {')
250 code('this->${{param.name}}.clear();')
251 code('for (auto i = simObjects.begin(); '
252 'ret && i != simObjects.end(); i ++)')
255 code('${{param.ptype.cxx_type}} object = '
256 'dynamic_cast<${{param.ptype.cxx_type}}>(*i);')
257 code('if (*i && !object)')
258 code(' ret = false;')
260 code(' this->${{param.name}}.push_back(object);')
265 code(' ret = false;')
273 code('void ${member_prefix}setName(const std::string &name_)'
279 code('this->name = name_;')
284 code('const std::string &${member_prefix}getName()')
285 code('{ return this->name; }')
288 code('bool ${member_prefix}setParam(const std::string &name,')
289 code(' const std::string &value, const Flags flags)${end_of_decl}')
294 code('bool ret = true;')
297 for param
in simobj
._params
.values():
298 is_vector
= isinstance(param
, m5
.params
.VectorParamDesc
)
299 is_simobj
= issubclass(param
.ptype
, m5
.SimObject
.SimObject
)
301 if not is_simobj
and not is_vector
:
302 code('} else if (name == "${{param.name}}") {')
304 param
.ptype
.cxx_ini_parse(code
,
305 'value', 'this->%s' % param
.name
, 'ret =')
308 code(' ret = false;')
316 code('bool ${member_prefix}setParamVector('
317 'const std::string &name,')
318 code(' const std::vector<std::string> &values,')
319 code(' const Flags flags)${end_of_decl}')
324 code('bool ret = true;')
327 for param
in simobj
._params
.values():
328 is_vector
= isinstance(param
, m5
.params
.VectorParamDesc
)
329 is_simobj
= issubclass(param
.ptype
, m5
.SimObject
.SimObject
)
331 if not is_simobj
and is_vector
:
332 code('} else if (name == "${{param.name}}") {')
334 code('${{param.name}}.clear();')
335 code('for (auto i = values.begin(); '
336 'ret && i != values.end(); i ++)')
339 code('${{param.ptype.cxx_type}} elem;')
340 param
.ptype
.cxx_ini_parse(code
,
341 '*i', 'elem', 'ret =')
343 code(' this->${{param.name}}.push_back(elem);')
348 code(' ret = false;')
356 code('bool ${member_prefix}setPortConnectionCount('
357 'const std::string &name,')
358 code(' unsigned int count)${end_of_decl}')
363 code('bool ret = true;')
367 for port
in simobj
._ports
.values():
368 code('else if (name == "${{port.name}}")')
369 code(' this->port_${{port.name}}_connection_count = count;')
371 code(' ret = false;')
378 code('SimObject *${member_prefix}simObjectCreate()${end_of_decl}')
382 if hasattr(simobj
, 'abstract') and simobj
.abstract
:
383 code(' return NULL;')
385 code(' return this->create();')
390 code('static CxxConfigDirectoryEntry'
391 ' *${member_prefix}makeDirectoryEntry()')
392 code('{ return new DirectoryEntry; }')
398 # The metaclass for SimObject. This class controls how new classes
399 # that derive from SimObject are instantiated, and provides inherited
400 # class behavior (just like a class controls how instances of that
401 # class are instantiated, and provides inherited instance behavior).
402 class MetaSimObject(type):
403 # Attributes that can be set only at initialization time
410 'cxx_base' : (str, type(None)),
411 'cxx_extra_bases' : list,
412 'cxx_exports' : list,
413 'cxx_param_exports' : list,
415 # Attributes that can be set any time
416 keywords
= { 'check' : FunctionType
}
418 # __new__ is called before __init__, and is where the statements
419 # in the body of the class definition get loaded into the class's
420 # __dict__. We intercept this to filter out parameter & port assignments
421 # and only allow "private" attributes to be passed to the base
422 # __new__ (starting with underscore).
423 def __new__(mcls
, name
, bases
, dict):
424 assert name
not in allClasses
, "SimObject %s already present" % name
426 # Copy "private" attributes, functions, and classes to the
427 # official dict. Everything else goes in _init_dict to be
428 # filtered in __init__.
432 for key
,val
in dict.items():
434 cxx_exports
.append(getattr(val
, "__pybind"))
435 except AttributeError:
438 if public_value(key
, val
):
441 # must be a param/port setting
442 value_dict
[key
] = val
443 if 'abstract' not in value_dict
:
444 value_dict
['abstract'] = False
445 if 'cxx_extra_bases' not in value_dict
:
446 value_dict
['cxx_extra_bases'] = []
447 if 'cxx_exports' not in value_dict
:
448 value_dict
['cxx_exports'] = cxx_exports
450 value_dict
['cxx_exports'] += cxx_exports
451 if 'cxx_param_exports' not in value_dict
:
452 value_dict
['cxx_param_exports'] = []
453 cls_dict
['_value_dict'] = value_dict
454 cls
= super(MetaSimObject
, mcls
).__new
__(mcls
, name
, bases
, cls_dict
)
455 if 'type' in value_dict
:
456 allClasses
[name
] = cls
459 # subclass initialization
460 def __init__(cls
, name
, bases
, dict):
461 # calls type.__init__()... I think that's a no-op, but leave
462 # it here just in case it's not.
463 super(MetaSimObject
, cls
).__init
__(name
, bases
, dict)
465 # initialize required attributes
467 # class-only attributes
468 cls
._params
= multidict() # param descriptions
469 cls
._ports
= multidict() # port descriptions
471 # class or instance attributes
472 cls
._values
= multidict() # param values
473 cls
._hr
_values
= multidict() # human readable param values
474 cls
._children
= multidict() # SimObject children
475 cls
._port
_refs
= multidict() # port ref objects
476 cls
._instantiated
= False # really instantiated, cloned, or subclassed
478 # We don't support multiple inheritance of sim objects. If you want
479 # to, you must fix multidict to deal with it properly. Non sim-objects
483 if isinstance(c
, MetaSimObject
):
487 "SimObjects do not support multiple inheritance")
491 # Set up general inheritance via multidicts. A subclass will
492 # inherit all its settings from the base class. The only time
493 # the following is not true is when we define the SimObject
494 # class itself (in which case the multidicts have no parent).
495 if isinstance(base
, MetaSimObject
):
497 cls
._params
.parent
= base
._params
498 cls
._ports
.parent
= base
._ports
499 cls
._values
.parent
= base
._values
500 cls
._hr
_values
.parent
= base
._hr
_values
501 cls
._children
.parent
= base
._children
502 cls
._port
_refs
.parent
= base
._port
_refs
503 # mark base as having been subclassed
504 base
._instantiated
= True
508 # default keyword values
509 if 'type' in cls
._value
_dict
:
510 if 'cxx_class' not in cls
._value
_dict
:
511 cls
._value
_dict
['cxx_class'] = cls
._value
_dict
['type']
513 cls
._value
_dict
['cxx_type'] = '%s *' % cls
._value
_dict
['cxx_class']
515 if 'cxx_header' not in cls
._value
_dict
:
518 warn("No header file specified for SimObject: %s", name
)
520 # Now process the _value_dict items. They could be defining
521 # new (or overriding existing) parameters or ports, setting
522 # class keywords (e.g., 'abstract'), or setting parameter
523 # values or port bindings. The first 3 can only be set when
524 # the class is defined, so we handle them here. The others
525 # can be set later too, so just emulate that by calling
527 for key
,val
in cls
._value
_dict
.items():
529 if isinstance(val
, ParamDesc
):
530 cls
._new
_param
(key
, val
)
533 elif isinstance(val
, Port
):
534 cls
._new
_port
(key
, val
)
536 # init-time-only keywords
537 elif key
in cls
.init_keywords
:
538 cls
._set
_keyword
(key
, val
, cls
.init_keywords
[key
])
540 # default: use normal path (ends up in __setattr__)
542 setattr(cls
, key
, val
)
544 def _set_keyword(cls
, keyword
, val
, kwtype
):
545 if not isinstance(val
, kwtype
):
546 raise TypeError('keyword %s has bad type %s (expecting %s)' % \
547 (keyword
, type(val
), kwtype
))
548 if isinstance(val
, FunctionType
):
549 val
= classmethod(val
)
550 type.__setattr
__(cls
, keyword
, val
)
552 def _new_param(cls
, name
, pdesc
):
553 # each param desc should be uniquely assigned to one variable
554 assert(not hasattr(pdesc
, 'name'))
556 cls
._params
[name
] = pdesc
557 if hasattr(pdesc
, 'default'):
558 cls
._set
_param
(name
, pdesc
.default
, pdesc
)
560 def _set_param(cls
, name
, value
, param
):
561 assert(param
.name
== name
)
564 value
= param
.convert(value
)
565 except Exception as e
:
566 msg
= "%s\nError setting param %s.%s to %s\n" % \
567 (e
, cls
.__name
__, name
, value
)
570 cls
._values
[name
] = value
571 # if param value is a SimObject, make it a child too, so that
572 # it gets cloned properly when the class is instantiated
573 if isSimObjectOrVector(value
) and not value
.has_parent():
574 cls
._add
_cls
_child
(name
, value
)
575 # update human-readable values of the param if it has a literal
576 # value and is not an object or proxy.
577 if not (isSimObjectOrVector(value
) or\
578 isinstance(value
, m5
.proxy
.BaseProxy
)):
579 cls
._hr
_values
[name
] = hr_value
581 def _add_cls_child(cls
, name
, child
):
582 # It's a little funky to have a class as a parent, but these
583 # objects should never be instantiated (only cloned, which
584 # clears the parent pointer), and this makes it clear that the
585 # object is not an orphan and can provide better error
587 child
.set_parent(cls
, name
)
588 if not isNullPointer(child
):
589 cls
._children
[name
] = child
591 def _new_port(cls
, name
, port
):
592 # each port should be uniquely assigned to one variable
593 assert(not hasattr(port
, 'name'))
595 cls
._ports
[name
] = port
597 # same as _get_port_ref, effectively, but for classes
598 def _cls_get_port_ref(cls
, attr
):
599 # Return reference that can be assigned to another port
600 # via __setattr__. There is only ever one reference
601 # object per port, but we create them lazily here.
602 ref
= cls
._port
_refs
.get(attr
)
604 ref
= cls
._ports
[attr
].makeRef(cls
)
605 cls
._port
_refs
[attr
] = ref
608 # Set attribute (called on foo.attr = value when foo is an
609 # instance of class cls).
610 def __setattr__(cls
, attr
, value
):
611 # normal processing for private attributes
612 if public_value(attr
, value
):
613 type.__setattr
__(cls
, attr
, value
)
616 if attr
in cls
.keywords
:
617 cls
._set
_keyword
(attr
, value
, cls
.keywords
[attr
])
620 if attr
in cls
._ports
:
621 cls
._cls
_get
_port
_ref
(attr
).connect(value
)
624 if isSimObjectOrSequence(value
) and cls
._instantiated
:
626 "cannot set SimObject parameter '%s' after\n" \
627 " class %s has been instantiated or subclassed" \
628 % (attr
, cls
.__name
__))
631 param
= cls
._params
.get(attr
)
633 cls
._set
_param
(attr
, value
, param
)
636 if isSimObjectOrSequence(value
):
637 # If RHS is a SimObject, it's an implicit child assignment.
638 cls
._add
_cls
_child
(attr
, coerceSimObjectOrVector(value
))
641 # no valid assignment... raise exception
642 raise AttributeError(
643 "Class %s has no parameter \'%s\'" % (cls
.__name
__, attr
))
645 def __getattr__(cls
, attr
):
646 if attr
== 'cxx_class_path':
647 return cls
.cxx_class
.split('::')
649 if attr
== 'cxx_class_name':
650 return cls
.cxx_class_path
[-1]
652 if attr
== 'cxx_namespaces':
653 return cls
.cxx_class_path
[:-1]
655 if attr
in cls
._values
:
656 return cls
._values
[attr
]
658 if attr
in cls
._children
:
659 return cls
._children
[attr
]
661 raise AttributeError(
662 "object '%s' has no attribute '%s'" % (cls
.__name
__, attr
))
667 # See ParamValue.cxx_predecls for description.
668 def cxx_predecls(cls
, code
):
669 code('#include "params/$cls.hh"')
671 def pybind_predecls(cls
, code
):
672 code('#include "${{cls.cxx_header}}"')
674 def pybind_decl(cls
, code
):
675 class_path
= cls
.cxx_class
.split('::')
676 namespaces
, classname
= class_path
[:-1], class_path
[-1]
677 py_class_name
= '_COLONS_'.join(class_path
) if namespaces
else \
680 # The 'local' attribute restricts us to the params declared in
681 # the object itself, not including inherited params (which
682 # will also be inherited from the base class's param struct
683 # here). Sort the params based on their key
684 params
= map(lambda (k
, v
): v
, sorted(cls
._params
.local
.items()))
685 ports
= cls
._ports
.local
687 code('''#include "pybind11/pybind11.h"
688 #include "pybind11/stl.h"
690 #include "params/$cls.hh"
691 #include "python/pybind11/core.hh"
692 #include "sim/init.hh"
693 #include "sim/sim_object.hh"
695 #include "${{cls.cxx_header}}"
700 param
.pybind_predecls(code
)
702 code('''namespace py = pybind11;
705 module_init(py::module &m_internal)
707 py::module m = m_internal.def_submodule("param_${cls}");
711 code('py::class_<${cls}Params, ${{cls._base.type}}Params, ' \
712 'std::unique_ptr<${{cls}}Params, py::nodelete>>(' \
713 'm, "${cls}Params")')
715 code('py::class_<${cls}Params, ' \
716 'std::unique_ptr<${cls}Params, py::nodelete>>(' \
717 'm, "${cls}Params")')
720 if not hasattr(cls
, 'abstract') or not cls
.abstract
:
721 code('.def(py::init<>())')
722 code('.def("create", &${cls}Params::create)')
724 param_exports
= cls
.cxx_param_exports
+ [
726 for k
, v
in sorted(cls
._params
.local
.items())
728 PyBindProperty("port_%s_connection_count" % port
.name
)
729 for port
in ports
.itervalues()
731 for exp
in param_exports
:
732 exp
.export(code
, "%sParams" % cls
)
739 if 'cxx_base' in cls
._value
_dict
:
740 # If the c++ base class implied by python inheritance was
741 # overridden, use that value.
743 bases
.append(cls
.cxx_base
)
745 # If not and if there was a SimObject base, use its c++ class
746 # as this class' base.
747 bases
.append(cls
._base
.cxx_class
)
748 # Add in any extra bases that were requested.
749 bases
.extend(cls
.cxx_extra_bases
)
752 base_str
= ", ".join(bases
)
753 code('py::class_<${{cls.cxx_class}}, ${base_str}, ' \
754 'std::unique_ptr<${{cls.cxx_class}}, py::nodelete>>(' \
755 'm, "${py_class_name}")')
757 code('py::class_<${{cls.cxx_class}}, ' \
758 'std::unique_ptr<${{cls.cxx_class}}, py::nodelete>>(' \
759 'm, "${py_class_name}")')
761 for exp
in cls
.cxx_exports
:
762 exp
.export(code
, cls
.cxx_class
)
769 code('static EmbeddedPyBind embed_obj("${0}", module_init, "${1}");',
770 cls
, cls
._base
.type if cls
._base
else "")
773 # Generate the C++ declaration (.hh file) for this SimObject's
774 # param struct. Called from src/SConscript.
775 def cxx_param_decl(cls
, code
):
776 # The 'local' attribute restricts us to the params declared in
777 # the object itself, not including inherited params (which
778 # will also be inherited from the base class's param struct
779 # here). Sort the params based on their key
780 params
= map(lambda (k
, v
): v
, sorted(cls
._params
.local
.items()))
781 ports
= cls
._ports
.local
783 ptypes
= [p
.ptype
for p
in params
]
785 print(cls
, p
, p
.ptype_str
)
789 class_path
= cls
._value
_dict
['cxx_class'].split('::')
792 #ifndef __PARAMS__${cls}__
793 #define __PARAMS__${cls}__
798 # The base SimObject has a couple of params that get
799 # automatically set from Python without being declared through
800 # the normal Param mechanism; we slip them in here (needed
801 # predecls now, actual declarations below)
803 code('''#include <string>''')
805 # A forward class declaration is sufficient since we are just
806 # declaring a pointer.
807 for ns
in class_path
[:-1]:
808 code('namespace $ns {')
809 code('class $0;', class_path
[-1])
810 for ns
in reversed(class_path
[:-1]):
811 code('} // namespace $ns')
815 param
.cxx_predecls(code
)
816 for port
in ports
.itervalues():
817 port
.cxx_predecls(code
)
821 code('#include "params/${{cls._base.type}}.hh"')
825 if issubclass(ptype
, Enum
):
826 code('#include "enums/${{ptype.__name__}}.hh"')
829 # now generate the actual param struct
830 code("struct ${cls}Params")
832 code(" : public ${{cls._base.type}}Params")
834 if not hasattr(cls
, 'abstract') or not cls
.abstract
:
835 if 'type' in cls
.__dict
__:
836 code(" ${{cls.cxx_type}} create();")
842 virtual ~SimObjectParams() {}
849 for port
in ports
.itervalues():
856 code('#endif // __PARAMS__${cls}__')
859 # Generate the C++ declaration/definition files for this SimObject's
860 # param struct to allow C++ initialisation
861 def cxx_config_param_file(cls
, code
, is_header
):
862 createCxxConfigDirectoryEntryFile(code
, cls
.__name
__, cls
, is_header
)
865 # This *temporary* definition is required to support calls from the
866 # SimObject class definition to the MetaSimObject methods (in
867 # particular _set_param, which gets called for parameters with default
868 # values defined on the SimObject class itself). It will get
869 # overridden by the permanent definition (which requires that
870 # SimObject be defined) lower in this file.
871 def isSimObjectOrVector(value
):
874 def cxxMethod(*args
, **kwargs
):
875 """Decorator to export C++ functions to Python"""
878 name
= func
.func_name
879 override
= kwargs
.get("override", False)
880 cxx_name
= kwargs
.get("cxx_name", name
)
882 args
, varargs
, keywords
, defaults
= inspect
.getargspec(func
)
883 if varargs
or keywords
:
884 raise ValueError("Wrapped methods must not contain variable " \
887 # Create tuples of (argument, default)
889 args
= args
[:-len(defaults
)] + zip(args
[-len(defaults
):], defaults
)
890 # Don't include self in the argument list to PyBind
895 def cxx_call(self
, *args
, **kwargs
):
896 ccobj
= self
.getCCObject()
897 return getattr(ccobj
, name
)(*args
, **kwargs
)
900 def py_call(self
, *args
, **kwargs
):
901 return func(self
, *args
, **kwargs
)
903 f
= py_call
if override
else cxx_call
904 f
.__pybind
= PyBindMethod(name
, cxx_name
=cxx_name
, args
=args
)
910 elif len(args
) == 1 and len(kwargs
) == 0:
911 return decorate(*args
)
913 raise TypeError("One argument and no kwargs, or only kwargs expected")
915 # This class holds information about each simobject parameter
916 # that should be displayed on the command line for use in the
917 # configuration system.
918 class ParamInfo(object):
919 def __init__(self
, type, desc
, type_str
, example
, default_val
, access_str
):
922 self
.type_str
= type_str
923 self
.example_str
= example
924 self
.default_val
= default_val
925 # The string representation used to access this param through python.
926 # The method to access this parameter presented on the command line may
927 # be different, so this needs to be stored for later use.
928 self
.access_str
= access_str
931 # Make it so we can only set attributes at initialization time
932 # and effectively make this a const object.
933 def __setattr__(self
, name
, value
):
934 if not "created" in self
.__dict
__:
935 self
.__dict
__[name
] = value
937 class SimObjectCliWrapperException(Exception):
938 def __init__(self
, message
):
939 super(Exception, self
).__init
__(message
)
941 class SimObjectCliWrapper(object):
943 Wrapper class to restrict operations that may be done
944 from the command line on SimObjects.
946 Only parameters may be set, and only children may be accessed.
948 Slicing allows for multiple simultaneous assignment of items in
952 def __init__(self
, sim_objects
):
953 self
.__dict
__['_sim_objects'] = list(sim_objects
)
955 def __getattr__(self
, key
):
956 return SimObjectCliWrapper(sim_object
._children
[key
]
957 for sim_object
in self
._sim
_objects
)
959 def __setattr__(self
, key
, val
):
960 for sim_object
in self
._sim
_objects
:
961 if key
in sim_object
._params
:
962 if sim_object
._params
[key
].isCmdLineSettable():
963 setattr(sim_object
, key
, val
)
965 raise SimObjectCliWrapperException(
966 'tried to set or unsettable' \
967 'object parameter: ' + key
)
969 raise SimObjectCliWrapperException(
970 'tried to set or access non-existent' \
971 'object parameter: ' + key
)
973 def __getitem__(self
, idx
):
975 Extends the list() semantics to also allow tuples,
976 for example object[1, 3] selects items 1 and 3.
979 if isinstance(idx
, tuple):
981 out
.extend(self
[t
]._sim
_objects
)
983 if isinstance(idx
, int):
984 _range
= range(idx
, idx
+ 1)
985 elif not isinstance(idx
, slice):
986 raise SimObjectCliWrapperException( \
987 'invalid index type: ' + repr(idx
))
988 for sim_object
in self
._sim
_objects
:
989 if isinstance(idx
, slice):
990 _range
= range(*idx
.indices(len(sim_object
)))
991 out
.extend(sim_object
[i
] for i
in _range
)
992 return SimObjectCliWrapper(out
)
994 # The SimObject class is the root of the special hierarchy. Most of
995 # the code in this class deals with the configuration hierarchy itself
996 # (parent/child node relationships).
997 class SimObject(object):
998 # Specify metaclass. Any class inheriting from SimObject will
999 # get this metaclass.
1000 __metaclass__
= MetaSimObject
1004 cxx_header
= "sim/sim_object.hh"
1005 cxx_extra_bases
= [ "Drainable", "Serializable" ]
1006 eventq_index
= Param
.UInt32(Parent
.eventq_index
, "Event Queue Index")
1009 PyBindMethod("init"),
1010 PyBindMethod("initState"),
1011 PyBindMethod("memInvalidate"),
1012 PyBindMethod("memWriteback"),
1013 PyBindMethod("regStats"),
1014 PyBindMethod("resetStats"),
1015 PyBindMethod("regProbePoints"),
1016 PyBindMethod("regProbeListeners"),
1017 PyBindMethod("startup"),
1020 cxx_param_exports
= [
1021 PyBindProperty("name"),
1025 def loadState(self
, cp
):
1026 """Load SimObject state from a checkpoint"""
1029 # Returns a dict of all the option strings that can be
1030 # generated as command line options for this simobject instance
1031 # by tracing all reachable params in the top level instance and
1032 # any children it contains.
1033 def enumerateParams(self
, flags_dict
= {},
1034 cmd_line_str
= "", access_str
= ""):
1035 if hasattr(self
, "_paramEnumed"):
1036 print("Cycle detected enumerating params")
1038 self
._paramEnumed
= True
1039 # Scan the children first to pick up all the objects in this SimObj
1040 for keys
in self
._children
:
1041 child
= self
._children
[keys
]
1042 next_cmdline_str
= cmd_line_str
+ keys
1043 next_access_str
= access_str
+ keys
1044 if not isSimObjectVector(child
):
1045 next_cmdline_str
= next_cmdline_str
+ "."
1046 next_access_str
= next_access_str
+ "."
1047 flags_dict
= child
.enumerateParams(flags_dict
,
1051 # Go through the simple params in the simobject in this level
1052 # of the simobject hierarchy and save information about the
1053 # parameter to be used for generating and processing command line
1054 # options to the simulator to set these parameters.
1055 for keys
,values
in self
._params
.items():
1056 if values
.isCmdLineSettable():
1058 ex_str
= values
.example_str()
1060 if isinstance(values
, VectorParamDesc
):
1061 type_str
= 'Vector_%s' % values
.ptype_str
1064 type_str
= '%s' % values
.ptype_str
1065 ptype
= values
.ptype
1067 if keys
in self
._hr
_values\
1068 and keys
in self
._values\
1069 and not isinstance(self
._values
[keys
],
1070 m5
.proxy
.BaseProxy
):
1071 cmd_str
= cmd_line_str
+ keys
1072 acc_str
= access_str
+ keys
1073 flags_dict
[cmd_str
] = ParamInfo(ptype
,
1074 self
._params
[keys
].desc
, type_str
, ex_str
,
1075 values
.pretty_print(self
._hr
_values
[keys
]),
1077 elif not keys
in self
._hr
_values\
1078 and not keys
in self
._values
:
1080 cmd_str
= cmd_line_str
+ keys
1081 acc_str
= access_str
+ keys
1082 flags_dict
[cmd_str
] = ParamInfo(ptype
,
1083 self
._params
[keys
].desc
,
1084 type_str
, ex_str
, '', acc_str
)
1088 # Initialize new instance. For objects with SimObject-valued
1089 # children, we need to recursively clone the classes represented
1090 # by those param values as well in a consistent "deep copy"-style
1091 # fashion. That is, we want to make sure that each instance is
1092 # cloned only once, and that if there are multiple references to
1093 # the same original object, we end up with the corresponding
1094 # cloned references all pointing to the same cloned instance.
1095 def __init__(self
, **kwargs
):
1096 ancestor
= kwargs
.get('_ancestor')
1097 memo_dict
= kwargs
.get('_memo')
1098 if memo_dict
is None:
1099 # prepare to memoize any recursively instantiated objects
1102 # memoize me now to avoid problems with recursive calls
1103 memo_dict
[ancestor
] = self
1106 ancestor
= self
.__class
__
1107 ancestor
._instantiated
= True
1109 # initialize required attributes
1112 self
._ccObject
= None # pointer to C++ object
1113 self
._ccParams
= None
1114 self
._instantiated
= False # really "cloned"
1116 # Clone children specified at class level. No need for a
1117 # multidict here since we will be cloning everything.
1118 # Do children before parameter values so that children that
1119 # are also param values get cloned properly.
1121 for key
,val
in ancestor
._children
.iteritems():
1122 self
.add_child(key
, val(_memo
=memo_dict
))
1124 # Inherit parameter values from class using multidict so
1125 # individual value settings can be overridden but we still
1126 # inherit late changes to non-overridden class values.
1127 self
._values
= multidict(ancestor
._values
)
1128 self
._hr
_values
= multidict(ancestor
._hr
_values
)
1129 # clone SimObject-valued parameters
1130 for key
,val
in ancestor
._values
.iteritems():
1131 val
= tryAsSimObjectOrVector(val
)
1133 self
._values
[key
] = val(_memo
=memo_dict
)
1135 # clone port references. no need to use a multidict here
1136 # since we will be creating new references for all ports.
1137 self
._port
_refs
= {}
1138 for key
,val
in ancestor
._port
_refs
.iteritems():
1139 self
._port
_refs
[key
] = val
.clone(self
, memo_dict
)
1140 # apply attribute assignments from keyword args, if any
1141 for key
,val
in kwargs
.iteritems():
1142 setattr(self
, key
, val
)
1144 # "Clone" the current instance by creating another instance of
1145 # this instance's class, but that inherits its parameter values
1146 # and port mappings from the current instance. If we're in a
1147 # "deep copy" recursive clone, check the _memo dict to see if
1148 # we've already cloned this instance.
1149 def __call__(self
, **kwargs
):
1150 memo_dict
= kwargs
.get('_memo')
1151 if memo_dict
is None:
1152 # no memo_dict: must be top-level clone operation.
1153 # this is only allowed at the root of a hierarchy
1155 raise RuntimeError("attempt to clone object %s " \
1156 "not at the root of a tree (parent = %s)" \
1157 % (self
, self
._parent
))
1158 # create a new dict and use that.
1160 kwargs
['_memo'] = memo_dict
1161 elif self
in memo_dict
:
1162 # clone already done & memoized
1163 return memo_dict
[self
]
1164 return self
.__class
__(_ancestor
= self
, **kwargs
)
1166 def _get_port_ref(self
, attr
):
1167 # Return reference that can be assigned to another port
1168 # via __setattr__. There is only ever one reference
1169 # object per port, but we create them lazily here.
1170 ref
= self
._port
_refs
.get(attr
)
1172 ref
= self
._ports
[attr
].makeRef(self
)
1173 self
._port
_refs
[attr
] = ref
1176 def __getattr__(self
, attr
):
1177 if attr
in self
._ports
:
1178 return self
._get
_port
_ref
(attr
)
1180 if attr
in self
._values
:
1181 return self
._values
[attr
]
1183 if attr
in self
._children
:
1184 return self
._children
[attr
]
1186 # If the attribute exists on the C++ object, transparently
1187 # forward the reference there. This is typically used for
1188 # methods exported to Python (e.g., init(), and startup())
1189 if self
._ccObject
and hasattr(self
._ccObject
, attr
):
1190 return getattr(self
._ccObject
, attr
)
1192 err_string
= "object '%s' has no attribute '%s'" \
1193 % (self
.__class
__.__name
__, attr
)
1195 if not self
._ccObject
:
1196 err_string
+= "\n (C++ object is not yet constructed," \
1197 " so wrapped C++ methods are unavailable.)"
1199 raise AttributeError(err_string
)
1201 # Set attribute (called on foo.attr = value when foo is an
1202 # instance of class cls).
1203 def __setattr__(self
, attr
, value
):
1204 # normal processing for private attributes
1205 if attr
.startswith('_'):
1206 object.__setattr
__(self
, attr
, value
)
1209 if attr
in self
._ports
:
1210 # set up port connection
1211 self
._get
_port
_ref
(attr
).connect(value
)
1214 param
= self
._params
.get(attr
)
1218 value
= param
.convert(value
)
1219 except Exception as e
:
1220 msg
= "%s\nError setting param %s.%s to %s\n" % \
1221 (e
, self
.__class
__.__name
__, attr
, value
)
1224 self
._values
[attr
] = value
1225 # implicitly parent unparented objects assigned as params
1226 if isSimObjectOrVector(value
) and not value
.has_parent():
1227 self
.add_child(attr
, value
)
1228 # set the human-readable value dict if this is a param
1229 # with a literal value and is not being set as an object
1231 if not (isSimObjectOrVector(value
) or\
1232 isinstance(value
, m5
.proxy
.BaseProxy
)):
1233 self
._hr
_values
[attr
] = hr_value
1237 # if RHS is a SimObject, it's an implicit child assignment
1238 if isSimObjectOrSequence(value
):
1239 self
.add_child(attr
, value
)
1242 # no valid assignment... raise exception
1243 raise AttributeError("Class %s has no parameter %s" \
1244 % (self
.__class
__.__name
__, attr
))
1247 # this hack allows tacking a '[0]' onto parameters that may or may
1248 # not be vectors, and always getting the first element (e.g. cpus)
1249 def __getitem__(self
, key
):
1252 raise IndexError("Non-zero index '%s' to SimObject" % key
)
1254 # this hack allows us to iterate over a SimObject that may
1255 # not be a vector, so we can call a loop over it and get just one
1260 # Also implemented by SimObjectVector
1261 def clear_parent(self
, old_parent
):
1262 assert self
._parent
is old_parent
1265 # Also implemented by SimObjectVector
1266 def set_parent(self
, parent
, name
):
1267 self
._parent
= parent
1270 # Return parent object of this SimObject, not implemented by
1271 # SimObjectVector because the elements in a SimObjectVector may not share
1273 def get_parent(self
):
1276 # Also implemented by SimObjectVector
1280 # Also implemented by SimObjectVector
1281 def has_parent(self
):
1282 return self
._parent
is not None
1284 # clear out child with given name. This code is not likely to be exercised.
1285 # See comment in add_child.
1286 def clear_child(self
, name
):
1287 child
= self
._children
[name
]
1288 child
.clear_parent(self
)
1289 del self
._children
[name
]
1291 # Add a new child to this object.
1292 def add_child(self
, name
, child
):
1293 child
= coerceSimObjectOrVector(child
)
1294 if child
.has_parent():
1295 warn("add_child('%s'): child '%s' already has parent", name
,
1297 if name
in self
._children
:
1298 # This code path had an undiscovered bug that would make it fail
1299 # at runtime. It had been here for a long time and was only
1300 # exposed by a buggy script. Changes here will probably not be
1301 # exercised without specialized testing.
1302 self
.clear_child(name
)
1303 child
.set_parent(self
, name
)
1304 if not isNullPointer(child
):
1305 self
._children
[name
] = child
1307 # Take SimObject-valued parameters that haven't been explicitly
1308 # assigned as children and make them children of the object that
1309 # they were assigned to as a parameter value. This guarantees
1310 # that when we instantiate all the parameter objects we're still
1311 # inside the configuration hierarchy.
1312 def adoptOrphanParams(self
):
1313 for key
,val
in self
._values
.iteritems():
1314 if not isSimObjectVector(val
) and isSimObjectSequence(val
):
1315 # need to convert raw SimObject sequences to
1316 # SimObjectVector class so we can call has_parent()
1317 val
= SimObjectVector(val
)
1318 self
._values
[key
] = val
1319 if isSimObjectOrVector(val
) and not val
.has_parent():
1320 warn("%s adopting orphan SimObject param '%s'", self
, key
)
1321 self
.add_child(key
, val
)
1324 if not self
._parent
:
1325 return '<orphan %s>' % self
.__class
__
1326 elif isinstance(self
._parent
, MetaSimObject
):
1327 return str(self
.__class
__)
1329 ppath
= self
._parent
.path()
1332 return ppath
+ "." + self
._name
1337 def config_value(self
):
1343 def find_any(self
, ptype
):
1344 if isinstance(self
, ptype
):
1348 for child
in self
._children
.itervalues():
1350 if hasattr(child
, '_visited'):
1351 visited
= getattr(child
, '_visited')
1353 if isinstance(child
, ptype
) and not visited
:
1354 if found_obj
!= None and child
!= found_obj
:
1355 raise AttributeError(
1356 'parent.any matched more than one: %s %s' % \
1357 (found_obj
.path
, child
.path
))
1359 # search param space
1360 for pname
,pdesc
in self
._params
.iteritems():
1361 if issubclass(pdesc
.ptype
, ptype
):
1362 match_obj
= self
._values
[pname
]
1363 if found_obj
!= None and found_obj
!= match_obj
:
1364 raise AttributeError(
1365 'parent.any matched more than one: %s and %s' % \
1366 (found_obj
.path
, match_obj
.path
))
1367 found_obj
= match_obj
1368 return found_obj
, found_obj
!= None
1370 def find_all(self
, ptype
):
1373 for child
in self
._children
.itervalues():
1374 # a child could be a list, so ensure we visit each item
1375 if isinstance(child
, list):
1380 for child
in children
:
1381 if isinstance(child
, ptype
) and not isproxy(child
) and \
1382 not isNullPointer(child
):
1384 if isSimObject(child
):
1385 # also add results from the child itself
1386 child_all
, done
= child
.find_all(ptype
)
1387 all
.update(dict(zip(child_all
, [done
] * len(child_all
))))
1388 # search param space
1389 for pname
,pdesc
in self
._params
.iteritems():
1390 if issubclass(pdesc
.ptype
, ptype
):
1391 match_obj
= self
._values
[pname
]
1392 if not isproxy(match_obj
) and not isNullPointer(match_obj
):
1393 all
[match_obj
] = True
1394 # Also make sure to sort the keys based on the objects' path to
1395 # ensure that the order is the same on all hosts
1396 return sorted(all
.keys(), key
= lambda o
: o
.path()), True
1398 def unproxy(self
, base
):
1401 def unproxyParams(self
):
1402 for param
in self
._params
.iterkeys():
1403 value
= self
._values
.get(param
)
1404 if value
!= None and isproxy(value
):
1406 value
= value
.unproxy(self
)
1408 print("Error in unproxying param '%s' of %s" %
1409 (param
, self
.path()))
1411 setattr(self
, param
, value
)
1413 # Unproxy ports in sorted order so that 'append' operations on
1414 # vector ports are done in a deterministic fashion.
1415 port_names
= self
._ports
.keys()
1417 for port_name
in port_names
:
1418 port
= self
._port
_refs
.get(port_name
)
1422 def print_ini(self
, ini_file
):
1423 print('[' + self
.path() + ']', file=ini_file
) # .ini section header
1425 instanceDict
[self
.path()] = self
1427 if hasattr(self
, 'type'):
1428 print('type=%s' % self
.type, file=ini_file
)
1430 if len(self
._children
.keys()):
1431 print('children=%s' %
1432 ' '.join(self
._children
[n
].get_name()
1433 for n
in sorted(self
._children
.keys())),
1436 for param
in sorted(self
._params
.keys()):
1437 value
= self
._values
.get(param
)
1439 print('%s=%s' % (param
, self
._values
[param
].ini_str()),
1442 for port_name
in sorted(self
._ports
.keys()):
1443 port
= self
._port
_refs
.get(port_name
, None)
1445 print('%s=%s' % (port_name
, port
.ini_str()), file=ini_file
)
1447 print(file=ini_file
) # blank line between objects
1449 # generate a tree of dictionaries expressing all the parameters in the
1450 # instantiated system for use by scripts that want to do power, thermal
1451 # visualization, and other similar tasks
1452 def get_config_as_dict(self
):
1454 if hasattr(self
, 'type'):
1456 if hasattr(self
, 'cxx_class'):
1457 d
.cxx_class
= self
.cxx_class
1458 # Add the name and path of this object to be able to link to
1460 d
.name
= self
.get_name()
1461 d
.path
= self
.path()
1463 for param
in sorted(self
._params
.keys()):
1464 value
= self
._values
.get(param
)
1466 d
[param
] = value
.config_value()
1468 for n
in sorted(self
._children
.keys()):
1469 child
= self
._children
[n
]
1470 # Use the name of the attribute (and not get_name()) as
1471 # the key in the JSON dictionary to capture the hierarchy
1472 # in the Python code that assembled this system
1473 d
[n
] = child
.get_config_as_dict()
1475 for port_name
in sorted(self
._ports
.keys()):
1476 port
= self
._port
_refs
.get(port_name
, None)
1478 # Represent each port with a dictionary containing the
1479 # prominent attributes
1480 d
[port_name
] = port
.get_config_as_dict()
1484 def getCCParams(self
):
1486 return self
._ccParams
1488 cc_params_struct
= getattr(m5
.internal
.params
, '%sParams' % self
.type)
1489 cc_params
= cc_params_struct()
1490 cc_params
.name
= str(self
)
1492 param_names
= self
._params
.keys()
1494 for param
in param_names
:
1495 value
= self
._values
.get(param
)
1497 fatal("%s.%s without default or user set value",
1500 value
= value
.getValue()
1501 if isinstance(self
._params
[param
], VectorParamDesc
):
1502 assert isinstance(value
, list)
1503 vec
= getattr(cc_params
, param
)
1505 # Some types are exposed as opaque types. They support
1506 # the append operation unlike the automatically
1508 if isinstance(vec
, list):
1509 setattr(cc_params
, param
, list(value
))
1512 getattr(cc_params
, param
).append(v
)
1514 setattr(cc_params
, param
, value
)
1516 port_names
= self
._ports
.keys()
1518 for port_name
in port_names
:
1519 port
= self
._port
_refs
.get(port_name
, None)
1521 port_count
= len(port
)
1524 setattr(cc_params
, 'port_' + port_name
+ '_connection_count',
1526 self
._ccParams
= cc_params
1527 return self
._ccParams
1529 # Get C++ object corresponding to this object, calling C++ if
1530 # necessary to construct it. Does *not* recursively create
1532 def getCCObject(self
):
1533 if not self
._ccObject
:
1534 # Make sure this object is in the configuration hierarchy
1535 if not self
._parent
and not isRoot(self
):
1536 raise RuntimeError("Attempt to instantiate orphan node")
1537 # Cycles in the configuration hierarchy are not supported. This
1538 # will catch the resulting recursion and stop.
1540 if not self
.abstract
:
1541 params
= self
.getCCParams()
1542 self
._ccObject
= params
.create()
1543 elif self
._ccObject
== -1:
1544 raise RuntimeError("%s: Cycle found in configuration hierarchy." \
1546 return self
._ccObject
1548 def descendants(self
):
1550 # The order of the dict is implementation dependent, so sort
1551 # it based on the key (name) to ensure the order is the same
1553 for (name
, child
) in sorted(self
._children
.iteritems()):
1554 for obj
in child
.descendants():
1557 # Call C++ to create C++ object corresponding to this object
1558 def createCCObject(self
):
1560 self
.getCCObject() # force creation
1563 return self
.getCCObject()
1565 # Create C++ port connections corresponding to the connections in
1567 def connectPorts(self
):
1568 # Sort the ports based on their attribute name to ensure the
1569 # order is the same on all hosts
1570 for (attr
, portRef
) in sorted(self
._port
_refs
.iteritems()):
1573 # Default function for generating the device structure.
1574 # Can be overloaded by the inheriting class
1575 def generateDeviceTree(self
, state
):
1576 return # return without yielding anything
1577 yield # make this function a (null) generator
1579 def recurseDeviceTree(self
, state
):
1580 for child
in self
._children
.itervalues():
1581 for item
in child
: # For looping over SimObjectVectors
1582 for dt
in item
.generateDeviceTree(state
):
1585 # On a separate method otherwise certain buggy Python versions
1586 # would fail with: SyntaxError: unqualified exec is not allowed
1587 # in function 'apply_config'
1588 def _apply_config_get_dict(self
):
1590 child_name
: SimObjectCliWrapper(
1591 iter(self
._children
[child_name
]))
1592 for child_name
in self
._children
1595 def apply_config(self
, params
):
1597 exec a list of Python code strings contained in params.
1599 The only exposed globals to those strings are the child
1600 SimObjects of this node.
1602 This function is intended to allow users to modify SimObject
1603 parameters from the command line with Python statements.
1605 d
= self
._apply
_config
_get
_dict
()
1606 for param
in params
:
1609 # Function to provide to C++ so it can look up instances based on paths
1610 def resolveSimObject(name
):
1611 obj
= instanceDict
[name
]
1612 return obj
.getCCObject()
1614 def isSimObject(value
):
1615 return isinstance(value
, SimObject
)
1617 def isSimObjectClass(value
):
1618 return issubclass(value
, SimObject
)
1620 def isSimObjectVector(value
):
1621 return isinstance(value
, SimObjectVector
)
1623 def isSimObjectSequence(value
):
1624 if not isinstance(value
, (list, tuple)) or len(value
) == 0:
1628 if not isNullPointer(val
) and not isSimObject(val
):
1633 def isSimObjectOrSequence(value
):
1634 return isSimObject(value
) or isSimObjectSequence(value
)
1637 from m5
.objects
import Root
1638 return obj
and obj
is Root
.getInstance()
1640 def isSimObjectOrVector(value
):
1641 return isSimObject(value
) or isSimObjectVector(value
)
1643 def tryAsSimObjectOrVector(value
):
1644 if isSimObjectOrVector(value
):
1646 if isSimObjectSequence(value
):
1647 return SimObjectVector(value
)
1650 def coerceSimObjectOrVector(value
):
1651 value
= tryAsSimObjectOrVector(value
)
1653 raise TypeError("SimObject or SimObjectVector expected")
1656 baseClasses
= allClasses
.copy()
1657 baseInstances
= instanceDict
.copy()
1660 global allClasses
, instanceDict
, noCxxHeader
1662 allClasses
= baseClasses
.copy()
1663 instanceDict
= baseInstances
.copy()
1666 # __all__ defines the list of symbols that get exported when
1667 # 'from config import *' is invoked. Try to keep this reasonably
1668 # short to avoid polluting other namespaces.