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
47 from __future__
import absolute_import
50 from types
import FunctionType
, MethodType
, ModuleType
51 from functools
import wraps
56 from m5
.util
.pybind
import *
57 # Use the pyfdt and not the helper class, because the fdthelper
58 # relies on the SimObject definition
59 from m5
.ext
.pyfdt
import pyfdt
61 # Have to import params up top since Param is referenced on initial
62 # load (when SimObject class references Param to create a class
63 # variable, the 'name' param)...
64 from m5
.params
import *
65 # There are a few things we need that aren't in params.__all__ since
66 # normal users don't need them
67 from m5
.params
import ParamDesc
, VectorParamDesc
, \
68 isNullPointer
, SimObjectVector
, Port
70 from m5
.proxy
import *
71 from m5
.proxy
import isproxy
73 #####################################################################
75 # M5 Python Configuration Utility
77 # The basic idea is to write simple Python programs that build Python
78 # objects corresponding to M5 SimObjects for the desired simulation
79 # configuration. For now, the Python emits a .ini file that can be
80 # parsed by M5. In the future, some tighter integration between M5
81 # and the Python interpreter may allow bypassing the .ini file.
83 # Each SimObject class in M5 is represented by a Python class with the
84 # same name. The Python inheritance tree mirrors the M5 C++ tree
85 # (e.g., SimpleCPU derives from BaseCPU in both cases, and all
86 # SimObjects inherit from a single SimObject base class). To specify
87 # an instance of an M5 SimObject in a configuration, the user simply
88 # instantiates the corresponding Python object. The parameters for
89 # that SimObject are given by assigning to attributes of the Python
90 # object, either using keyword assignment in the constructor or in
91 # separate assignment statements. For example:
93 # cache = BaseCache(size='64KB')
94 # cache.hit_latency = 3
97 # The magic lies in the mapping of the Python attributes for SimObject
98 # classes to the actual SimObject parameter specifications. This
99 # allows parameter validity checking in the Python code. Continuing
100 # the example above, the statements "cache.blurfl=3" or
101 # "cache.assoc='hello'" would both result in runtime errors in Python,
102 # since the BaseCache object has no 'blurfl' parameter and the 'assoc'
103 # parameter requires an integer, respectively. This magic is done
104 # primarily by overriding the special __setattr__ method that controls
105 # assignment to object attributes.
107 # Once a set of Python objects have been instantiated in a hierarchy,
108 # calling 'instantiate(obj)' (where obj is the root of the hierarchy)
109 # will generate a .ini file.
111 #####################################################################
113 # list of all SimObject classes
116 # dict to look up SimObjects based on path
119 # Did any of the SimObjects lack a header file?
122 def public_value(key
, value
):
123 return key
.startswith('_') or \
124 isinstance(value
, (FunctionType
, MethodType
, ModuleType
,
127 def createCxxConfigDirectoryEntryFile(code
, name
, simobj
, is_header
):
128 entry_class
= 'CxxConfigDirectoryEntry_%s' % name
129 param_class
= '%sCxxConfigParams' % name
131 code('#include "params/%s.hh"' % name
)
134 for param
in simobj
._params
.values():
135 if isSimObjectClass(param
.ptype
):
136 code('#include "%s"' % param
.ptype
._value
_dict
['cxx_header'])
137 code('#include "params/%s.hh"' % param
.ptype
.__name
__)
139 param
.ptype
.cxx_ini_predecls(code
)
144 code('#include "sim/cxx_config.hh"')
146 code('class ${param_class} : public CxxConfigParams,'
147 ' public ${name}Params')
151 code('class DirectoryEntry : public CxxConfigDirectoryEntry')
155 code('DirectoryEntry();');
157 code('CxxConfigParams *makeParamsObject() const')
158 code('{ return new ${param_class}; }')
166 member_prefix
= '%s::' % param_class
168 code('#include "%s"' % simobj
._value
_dict
['cxx_header'])
169 code('#include "base/str.hh"')
170 code('#include "cxx_config/${name}.hh"')
173 code('#include "mem/mem_object.hh"')
174 code('#include "mem/port.hh"')
177 code('${member_prefix}DirectoryEntry::DirectoryEntry()');
181 return 'true' if b
else 'false'
184 for param
in simobj
._params
.values():
185 is_vector
= isinstance(param
, m5
.params
.VectorParamDesc
)
186 is_simobj
= issubclass(param
.ptype
, m5
.SimObject
.SimObject
)
188 code('parameters["%s"] = new ParamDesc("%s", %s, %s);' %
189 (param
.name
, param
.name
, cxx_bool(is_vector
),
190 cxx_bool(is_simobj
)));
192 for port
in simobj
._ports
.values():
193 is_vector
= isinstance(port
, m5
.params
.VectorPort
)
194 is_master
= port
.role
== 'MASTER'
196 code('ports["%s"] = new PortDesc("%s", %s, %s);' %
197 (port
.name
, port
.name
, cxx_bool(is_vector
),
198 cxx_bool(is_master
)))
204 code('bool ${member_prefix}setSimObject(const std::string &name,')
205 code(' SimObject *simObject)${end_of_decl}')
210 code('bool ret = true;')
213 for param
in simobj
._params
.values():
214 is_vector
= isinstance(param
, m5
.params
.VectorParamDesc
)
215 is_simobj
= issubclass(param
.ptype
, m5
.SimObject
.SimObject
)
217 if is_simobj
and not is_vector
:
218 code('} else if (name == "${{param.name}}") {')
220 code('this->${{param.name}} = '
221 'dynamic_cast<${{param.ptype.cxx_type}}>(simObject);')
222 code('if (simObject && !this->${{param.name}})')
223 code(' ret = false;')
226 code(' ret = false;')
234 code('bool ${member_prefix}setSimObjectVector('
235 'const std::string &name,')
236 code(' const std::vector<SimObject *> &simObjects)${end_of_decl}')
241 code('bool ret = true;')
244 for param
in simobj
._params
.values():
245 is_vector
= isinstance(param
, m5
.params
.VectorParamDesc
)
246 is_simobj
= issubclass(param
.ptype
, m5
.SimObject
.SimObject
)
248 if is_simobj
and is_vector
:
249 code('} else if (name == "${{param.name}}") {')
251 code('this->${{param.name}}.clear();')
252 code('for (auto i = simObjects.begin(); '
253 'ret && i != simObjects.end(); i ++)')
256 code('${{param.ptype.cxx_type}} object = '
257 'dynamic_cast<${{param.ptype.cxx_type}}>(*i);')
258 code('if (*i && !object)')
259 code(' ret = false;')
261 code(' this->${{param.name}}.push_back(object);')
266 code(' ret = false;')
274 code('void ${member_prefix}setName(const std::string &name_)'
280 code('this->name = name_;')
285 code('const std::string &${member_prefix}getName()')
286 code('{ return this->name; }')
289 code('bool ${member_prefix}setParam(const std::string &name,')
290 code(' const std::string &value, const Flags flags)${end_of_decl}')
295 code('bool ret = true;')
298 for param
in simobj
._params
.values():
299 is_vector
= isinstance(param
, m5
.params
.VectorParamDesc
)
300 is_simobj
= issubclass(param
.ptype
, m5
.SimObject
.SimObject
)
302 if not is_simobj
and not is_vector
:
303 code('} else if (name == "${{param.name}}") {')
305 param
.ptype
.cxx_ini_parse(code
,
306 'value', 'this->%s' % param
.name
, 'ret =')
309 code(' ret = false;')
317 code('bool ${member_prefix}setParamVector('
318 'const std::string &name,')
319 code(' const std::vector<std::string> &values,')
320 code(' const Flags flags)${end_of_decl}')
325 code('bool ret = true;')
328 for param
in simobj
._params
.values():
329 is_vector
= isinstance(param
, m5
.params
.VectorParamDesc
)
330 is_simobj
= issubclass(param
.ptype
, m5
.SimObject
.SimObject
)
332 if not is_simobj
and is_vector
:
333 code('} else if (name == "${{param.name}}") {')
335 code('${{param.name}}.clear();')
336 code('for (auto i = values.begin(); '
337 'ret && i != values.end(); i ++)')
340 code('${{param.ptype.cxx_type}} elem;')
341 param
.ptype
.cxx_ini_parse(code
,
342 '*i', 'elem', 'ret =')
344 code(' this->${{param.name}}.push_back(elem);')
349 code(' ret = false;')
357 code('bool ${member_prefix}setPortConnectionCount('
358 'const std::string &name,')
359 code(' unsigned int count)${end_of_decl}')
364 code('bool ret = true;')
368 for port
in simobj
._ports
.values():
369 code('else if (name == "${{port.name}}")')
370 code(' this->port_${{port.name}}_connection_count = count;')
372 code(' ret = false;')
379 code('SimObject *${member_prefix}simObjectCreate()${end_of_decl}')
383 if hasattr(simobj
, 'abstract') and simobj
.abstract
:
384 code(' return NULL;')
386 code(' return this->create();')
391 code('static CxxConfigDirectoryEntry'
392 ' *${member_prefix}makeDirectoryEntry()')
393 code('{ return new DirectoryEntry; }')
399 # The metaclass for SimObject. This class controls how new classes
400 # that derive from SimObject are instantiated, and provides inherited
401 # class behavior (just like a class controls how instances of that
402 # class are instantiated, and provides inherited instance behavior).
403 class MetaSimObject(type):
404 # Attributes that can be set only at initialization time
411 'cxx_base' : (str, type(None)),
412 'cxx_extra_bases' : list,
413 'cxx_exports' : list,
414 'cxx_param_exports' : list,
416 # Attributes that can be set any time
417 keywords
= { 'check' : FunctionType
}
419 # __new__ is called before __init__, and is where the statements
420 # in the body of the class definition get loaded into the class's
421 # __dict__. We intercept this to filter out parameter & port assignments
422 # and only allow "private" attributes to be passed to the base
423 # __new__ (starting with underscore).
424 def __new__(mcls
, name
, bases
, dict):
425 assert name
not in allClasses
, "SimObject %s already present" % name
427 # Copy "private" attributes, functions, and classes to the
428 # official dict. Everything else goes in _init_dict to be
429 # filtered in __init__.
433 for key
,val
in dict.items():
435 cxx_exports
.append(getattr(val
, "__pybind"))
436 except AttributeError:
439 if public_value(key
, val
):
442 # must be a param/port setting
443 value_dict
[key
] = val
444 if 'abstract' not in value_dict
:
445 value_dict
['abstract'] = False
446 if 'cxx_extra_bases' not in value_dict
:
447 value_dict
['cxx_extra_bases'] = []
448 if 'cxx_exports' not in value_dict
:
449 value_dict
['cxx_exports'] = cxx_exports
451 value_dict
['cxx_exports'] += cxx_exports
452 if 'cxx_param_exports' not in value_dict
:
453 value_dict
['cxx_param_exports'] = []
454 cls_dict
['_value_dict'] = value_dict
455 cls
= super(MetaSimObject
, mcls
).__new
__(mcls
, name
, bases
, cls_dict
)
456 if 'type' in value_dict
:
457 allClasses
[name
] = cls
460 # subclass initialization
461 def __init__(cls
, name
, bases
, dict):
462 # calls type.__init__()... I think that's a no-op, but leave
463 # it here just in case it's not.
464 super(MetaSimObject
, cls
).__init
__(name
, bases
, dict)
466 # initialize required attributes
468 # class-only attributes
469 cls
._params
= multidict() # param descriptions
470 cls
._ports
= multidict() # port descriptions
472 # class or instance attributes
473 cls
._values
= multidict() # param values
474 cls
._hr
_values
= multidict() # human readable param values
475 cls
._children
= multidict() # SimObject children
476 cls
._port
_refs
= multidict() # port ref objects
477 cls
._instantiated
= False # really instantiated, cloned, or subclassed
479 # We don't support multiple inheritance of sim objects. If you want
480 # to, you must fix multidict to deal with it properly. Non sim-objects
484 if isinstance(c
, MetaSimObject
):
488 "SimObjects do not support multiple inheritance")
492 # Set up general inheritance via multidicts. A subclass will
493 # inherit all its settings from the base class. The only time
494 # the following is not true is when we define the SimObject
495 # class itself (in which case the multidicts have no parent).
496 if isinstance(base
, MetaSimObject
):
498 cls
._params
.parent
= base
._params
499 cls
._ports
.parent
= base
._ports
500 cls
._values
.parent
= base
._values
501 cls
._hr
_values
.parent
= base
._hr
_values
502 cls
._children
.parent
= base
._children
503 cls
._port
_refs
.parent
= base
._port
_refs
504 # mark base as having been subclassed
505 base
._instantiated
= True
509 # default keyword values
510 if 'type' in cls
._value
_dict
:
511 if 'cxx_class' not in cls
._value
_dict
:
512 cls
._value
_dict
['cxx_class'] = cls
._value
_dict
['type']
514 cls
._value
_dict
['cxx_type'] = '%s *' % cls
._value
_dict
['cxx_class']
516 if 'cxx_header' not in cls
._value
_dict
:
519 warn("No header file specified for SimObject: %s", name
)
521 # Now process the _value_dict items. They could be defining
522 # new (or overriding existing) parameters or ports, setting
523 # class keywords (e.g., 'abstract'), or setting parameter
524 # values or port bindings. The first 3 can only be set when
525 # the class is defined, so we handle them here. The others
526 # can be set later too, so just emulate that by calling
528 for key
,val
in cls
._value
_dict
.items():
530 if isinstance(val
, ParamDesc
):
531 cls
._new
_param
(key
, val
)
534 elif isinstance(val
, Port
):
535 cls
._new
_port
(key
, val
)
537 # init-time-only keywords
538 elif key
in cls
.init_keywords
:
539 cls
._set
_keyword
(key
, val
, cls
.init_keywords
[key
])
541 # default: use normal path (ends up in __setattr__)
543 setattr(cls
, key
, val
)
545 def _set_keyword(cls
, keyword
, val
, kwtype
):
546 if not isinstance(val
, kwtype
):
547 raise TypeError('keyword %s has bad type %s (expecting %s)' % \
548 (keyword
, type(val
), kwtype
))
549 if isinstance(val
, FunctionType
):
550 val
= classmethod(val
)
551 type.__setattr
__(cls
, keyword
, val
)
553 def _new_param(cls
, name
, pdesc
):
554 # each param desc should be uniquely assigned to one variable
555 assert(not hasattr(pdesc
, 'name'))
557 cls
._params
[name
] = pdesc
558 if hasattr(pdesc
, 'default'):
559 cls
._set
_param
(name
, pdesc
.default
, pdesc
)
561 def _set_param(cls
, name
, value
, param
):
562 assert(param
.name
== name
)
565 value
= param
.convert(value
)
566 except Exception as e
:
567 msg
= "%s\nError setting param %s.%s to %s\n" % \
568 (e
, cls
.__name
__, name
, value
)
571 cls
._values
[name
] = value
572 # if param value is a SimObject, make it a child too, so that
573 # it gets cloned properly when the class is instantiated
574 if isSimObjectOrVector(value
) and not value
.has_parent():
575 cls
._add
_cls
_child
(name
, value
)
576 # update human-readable values of the param if it has a literal
577 # value and is not an object or proxy.
578 if not (isSimObjectOrVector(value
) or\
579 isinstance(value
, m5
.proxy
.BaseProxy
)):
580 cls
._hr
_values
[name
] = hr_value
582 def _add_cls_child(cls
, name
, child
):
583 # It's a little funky to have a class as a parent, but these
584 # objects should never be instantiated (only cloned, which
585 # clears the parent pointer), and this makes it clear that the
586 # object is not an orphan and can provide better error
588 child
.set_parent(cls
, name
)
589 if not isNullPointer(child
):
590 cls
._children
[name
] = child
592 def _new_port(cls
, name
, port
):
593 # each port should be uniquely assigned to one variable
594 assert(not hasattr(port
, 'name'))
596 cls
._ports
[name
] = port
598 # same as _get_port_ref, effectively, but for classes
599 def _cls_get_port_ref(cls
, attr
):
600 # Return reference that can be assigned to another port
601 # via __setattr__. There is only ever one reference
602 # object per port, but we create them lazily here.
603 ref
= cls
._port
_refs
.get(attr
)
605 ref
= cls
._ports
[attr
].makeRef(cls
)
606 cls
._port
_refs
[attr
] = ref
609 # Set attribute (called on foo.attr = value when foo is an
610 # instance of class cls).
611 def __setattr__(cls
, attr
, value
):
612 # normal processing for private attributes
613 if public_value(attr
, value
):
614 type.__setattr
__(cls
, attr
, value
)
617 if attr
in cls
.keywords
:
618 cls
._set
_keyword
(attr
, value
, cls
.keywords
[attr
])
621 if attr
in cls
._ports
:
622 cls
._cls
_get
_port
_ref
(attr
).connect(value
)
625 if isSimObjectOrSequence(value
) and cls
._instantiated
:
627 "cannot set SimObject parameter '%s' after\n" \
628 " class %s has been instantiated or subclassed" \
629 % (attr
, cls
.__name
__))
632 param
= cls
._params
.get(attr
)
634 cls
._set
_param
(attr
, value
, param
)
637 if isSimObjectOrSequence(value
):
638 # If RHS is a SimObject, it's an implicit child assignment.
639 cls
._add
_cls
_child
(attr
, coerceSimObjectOrVector(value
))
642 # no valid assignment... raise exception
643 raise AttributeError(
644 "Class %s has no parameter \'%s\'" % (cls
.__name
__, attr
))
646 def __getattr__(cls
, attr
):
647 if attr
== 'cxx_class_path':
648 return cls
.cxx_class
.split('::')
650 if attr
== 'cxx_class_name':
651 return cls
.cxx_class_path
[-1]
653 if attr
== 'cxx_namespaces':
654 return cls
.cxx_class_path
[:-1]
656 if attr
in cls
._values
:
657 return cls
._values
[attr
]
659 if attr
in cls
._children
:
660 return cls
._children
[attr
]
662 raise AttributeError(
663 "object '%s' has no attribute '%s'" % (cls
.__name
__, attr
))
668 # See ParamValue.cxx_predecls for description.
669 def cxx_predecls(cls
, code
):
670 code('#include "params/$cls.hh"')
672 def pybind_predecls(cls
, code
):
673 code('#include "${{cls.cxx_header}}"')
675 def pybind_decl(cls
, code
):
676 class_path
= cls
.cxx_class
.split('::')
677 namespaces
, classname
= class_path
[:-1], class_path
[-1]
678 py_class_name
= '_COLONS_'.join(class_path
) if namespaces
else \
681 # The 'local' attribute restricts us to the params declared in
682 # the object itself, not including inherited params (which
683 # will also be inherited from the base class's param struct
684 # here). Sort the params based on their key
685 params
= map(lambda k_v
: k_v
[1], sorted(cls
._params
.local
.items()))
686 ports
= cls
._ports
.local
688 code('''#include "pybind11/pybind11.h"
689 #include "pybind11/stl.h"
691 #include "params/$cls.hh"
692 #include "python/pybind11/core.hh"
693 #include "sim/init.hh"
694 #include "sim/sim_object.hh"
696 #include "${{cls.cxx_header}}"
701 param
.pybind_predecls(code
)
703 code('''namespace py = pybind11;
706 module_init(py::module &m_internal)
708 py::module m = m_internal.def_submodule("param_${cls}");
712 code('py::class_<${cls}Params, ${{cls._base.type}}Params, ' \
713 'std::unique_ptr<${{cls}}Params, py::nodelete>>(' \
714 'm, "${cls}Params")')
716 code('py::class_<${cls}Params, ' \
717 'std::unique_ptr<${cls}Params, py::nodelete>>(' \
718 'm, "${cls}Params")')
721 if not hasattr(cls
, 'abstract') or not cls
.abstract
:
722 code('.def(py::init<>())')
723 code('.def("create", &${cls}Params::create)')
725 param_exports
= cls
.cxx_param_exports
+ [
727 for k
, v
in sorted(cls
._params
.local
.items())
729 PyBindProperty("port_%s_connection_count" % port
.name
)
730 for port
in ports
.values()
732 for exp
in param_exports
:
733 exp
.export(code
, "%sParams" % cls
)
740 if 'cxx_base' in cls
._value
_dict
:
741 # If the c++ base class implied by python inheritance was
742 # overridden, use that value.
744 bases
.append(cls
.cxx_base
)
746 # If not and if there was a SimObject base, use its c++ class
747 # as this class' base.
748 bases
.append(cls
._base
.cxx_class
)
749 # Add in any extra bases that were requested.
750 bases
.extend(cls
.cxx_extra_bases
)
753 base_str
= ", ".join(bases
)
754 code('py::class_<${{cls.cxx_class}}, ${base_str}, ' \
755 'std::unique_ptr<${{cls.cxx_class}}, py::nodelete>>(' \
756 'm, "${py_class_name}")')
758 code('py::class_<${{cls.cxx_class}}, ' \
759 'std::unique_ptr<${{cls.cxx_class}}, py::nodelete>>(' \
760 'm, "${py_class_name}")')
762 for exp
in cls
.cxx_exports
:
763 exp
.export(code
, cls
.cxx_class
)
770 code('static EmbeddedPyBind embed_obj("${0}", module_init, "${1}");',
771 cls
, cls
._base
.type if cls
._base
else "")
774 # Generate the C++ declaration (.hh file) for this SimObject's
775 # param struct. Called from src/SConscript.
776 def cxx_param_decl(cls
, code
):
777 # The 'local' attribute restricts us to the params declared in
778 # the object itself, not including inherited params (which
779 # will also be inherited from the base class's param struct
780 # here). Sort the params based on their key
781 params
= map(lambda k_v
: k_v
[1], sorted(cls
._params
.local
.items()))
782 ports
= cls
._ports
.local
784 ptypes
= [p
.ptype
for p
in params
]
786 print(cls
, p
, p
.ptype_str
)
790 class_path
= cls
._value
_dict
['cxx_class'].split('::')
793 #ifndef __PARAMS__${cls}__
794 #define __PARAMS__${cls}__
799 # The base SimObject has a couple of params that get
800 # automatically set from Python without being declared through
801 # the normal Param mechanism; we slip them in here (needed
802 # predecls now, actual declarations below)
804 code('''#include <string>''')
806 # A forward class declaration is sufficient since we are just
807 # declaring a pointer.
808 for ns
in class_path
[:-1]:
809 code('namespace $ns {')
810 code('class $0;', class_path
[-1])
811 for ns
in reversed(class_path
[:-1]):
812 code('} // namespace $ns')
816 param
.cxx_predecls(code
)
817 for port
in ports
.values():
818 port
.cxx_predecls(code
)
822 code('#include "params/${{cls._base.type}}.hh"')
826 if issubclass(ptype
, Enum
):
827 code('#include "enums/${{ptype.__name__}}.hh"')
830 # now generate the actual param struct
831 code("struct ${cls}Params")
833 code(" : public ${{cls._base.type}}Params")
835 if not hasattr(cls
, 'abstract') or not cls
.abstract
:
836 if 'type' in cls
.__dict
__:
837 code(" ${{cls.cxx_type}} create();")
843 virtual ~SimObjectParams() {}
850 for port
in ports
.values():
857 code('#endif // __PARAMS__${cls}__')
860 # Generate the C++ declaration/definition files for this SimObject's
861 # param struct to allow C++ initialisation
862 def cxx_config_param_file(cls
, code
, is_header
):
863 createCxxConfigDirectoryEntryFile(code
, cls
.__name
__, cls
, is_header
)
866 # This *temporary* definition is required to support calls from the
867 # SimObject class definition to the MetaSimObject methods (in
868 # particular _set_param, which gets called for parameters with default
869 # values defined on the SimObject class itself). It will get
870 # overridden by the permanent definition (which requires that
871 # SimObject be defined) lower in this file.
872 def isSimObjectOrVector(value
):
875 def cxxMethod(*args
, **kwargs
):
876 """Decorator to export C++ functions to Python"""
880 override
= kwargs
.get("override", False)
881 cxx_name
= kwargs
.get("cxx_name", name
)
883 args
, varargs
, keywords
, defaults
= inspect
.getargspec(func
)
884 if varargs
or keywords
:
885 raise ValueError("Wrapped methods must not contain variable " \
888 # Create tuples of (argument, default)
890 args
= args
[:-len(defaults
)] + \
891 list(zip(args
[-len(defaults
):], defaults
))
892 # Don't include self in the argument list to PyBind
897 def cxx_call(self
, *args
, **kwargs
):
898 ccobj
= self
.getCCObject()
899 return getattr(ccobj
, name
)(*args
, **kwargs
)
902 def py_call(self
, *args
, **kwargs
):
903 return func(self
, *args
, **kwargs
)
905 f
= py_call
if override
else cxx_call
906 f
.__pybind
= PyBindMethod(name
, cxx_name
=cxx_name
, args
=args
)
912 elif len(args
) == 1 and len(kwargs
) == 0:
913 return decorate(*args
)
915 raise TypeError("One argument and no kwargs, or only kwargs expected")
917 # This class holds information about each simobject parameter
918 # that should be displayed on the command line for use in the
919 # configuration system.
920 class ParamInfo(object):
921 def __init__(self
, type, desc
, type_str
, example
, default_val
, access_str
):
924 self
.type_str
= type_str
925 self
.example_str
= example
926 self
.default_val
= default_val
927 # The string representation used to access this param through python.
928 # The method to access this parameter presented on the command line may
929 # be different, so this needs to be stored for later use.
930 self
.access_str
= access_str
933 # Make it so we can only set attributes at initialization time
934 # and effectively make this a const object.
935 def __setattr__(self
, name
, value
):
936 if not "created" in self
.__dict
__:
937 self
.__dict
__[name
] = value
939 class SimObjectCliWrapperException(Exception):
940 def __init__(self
, message
):
941 super(Exception, self
).__init
__(message
)
943 class SimObjectCliWrapper(object):
945 Wrapper class to restrict operations that may be done
946 from the command line on SimObjects.
948 Only parameters may be set, and only children may be accessed.
950 Slicing allows for multiple simultaneous assignment of items in
954 def __init__(self
, sim_objects
):
955 self
.__dict
__['_sim_objects'] = list(sim_objects
)
957 def __getattr__(self
, key
):
958 return SimObjectCliWrapper(sim_object
._children
[key
]
959 for sim_object
in self
._sim
_objects
)
961 def __setattr__(self
, key
, val
):
962 for sim_object
in self
._sim
_objects
:
963 if key
in sim_object
._params
:
964 if sim_object
._params
[key
].isCmdLineSettable():
965 setattr(sim_object
, key
, val
)
967 raise SimObjectCliWrapperException(
968 'tried to set or unsettable' \
969 'object parameter: ' + key
)
971 raise SimObjectCliWrapperException(
972 'tried to set or access non-existent' \
973 'object parameter: ' + key
)
975 def __getitem__(self
, idx
):
977 Extends the list() semantics to also allow tuples,
978 for example object[1, 3] selects items 1 and 3.
981 if isinstance(idx
, tuple):
983 out
.extend(self
[t
]._sim
_objects
)
985 if isinstance(idx
, int):
986 _range
= range(idx
, idx
+ 1)
987 elif not isinstance(idx
, slice):
988 raise SimObjectCliWrapperException( \
989 'invalid index type: ' + repr(idx
))
990 for sim_object
in self
._sim
_objects
:
991 if isinstance(idx
, slice):
992 _range
= range(*idx
.indices(len(sim_object
)))
993 out
.extend(sim_object
[i
] for i
in _range
)
994 return SimObjectCliWrapper(out
)
996 # The SimObject class is the root of the special hierarchy. Most of
997 # the code in this class deals with the configuration hierarchy itself
998 # (parent/child node relationships).
999 class SimObject(object):
1000 # Specify metaclass. Any class inheriting from SimObject will
1001 # get this metaclass.
1002 __metaclass__
= MetaSimObject
1006 cxx_header
= "sim/sim_object.hh"
1007 cxx_extra_bases
= [ "Drainable", "Serializable" ]
1008 eventq_index
= Param
.UInt32(Parent
.eventq_index
, "Event Queue Index")
1011 PyBindMethod("init"),
1012 PyBindMethod("initState"),
1013 PyBindMethod("memInvalidate"),
1014 PyBindMethod("memWriteback"),
1015 PyBindMethod("regStats"),
1016 PyBindMethod("resetStats"),
1017 PyBindMethod("regProbePoints"),
1018 PyBindMethod("regProbeListeners"),
1019 PyBindMethod("startup"),
1022 cxx_param_exports
= [
1023 PyBindProperty("name"),
1027 def loadState(self
, cp
):
1028 """Load SimObject state from a checkpoint"""
1031 # Returns a dict of all the option strings that can be
1032 # generated as command line options for this simobject instance
1033 # by tracing all reachable params in the top level instance and
1034 # any children it contains.
1035 def enumerateParams(self
, flags_dict
= {},
1036 cmd_line_str
= "", access_str
= ""):
1037 if hasattr(self
, "_paramEnumed"):
1038 print("Cycle detected enumerating params")
1040 self
._paramEnumed
= True
1041 # Scan the children first to pick up all the objects in this SimObj
1042 for keys
in self
._children
:
1043 child
= self
._children
[keys
]
1044 next_cmdline_str
= cmd_line_str
+ keys
1045 next_access_str
= access_str
+ keys
1046 if not isSimObjectVector(child
):
1047 next_cmdline_str
= next_cmdline_str
+ "."
1048 next_access_str
= next_access_str
+ "."
1049 flags_dict
= child
.enumerateParams(flags_dict
,
1053 # Go through the simple params in the simobject in this level
1054 # of the simobject hierarchy and save information about the
1055 # parameter to be used for generating and processing command line
1056 # options to the simulator to set these parameters.
1057 for keys
,values
in self
._params
.items():
1058 if values
.isCmdLineSettable():
1060 ex_str
= values
.example_str()
1062 if isinstance(values
, VectorParamDesc
):
1063 type_str
= 'Vector_%s' % values
.ptype_str
1066 type_str
= '%s' % values
.ptype_str
1067 ptype
= values
.ptype
1069 if keys
in self
._hr
_values\
1070 and keys
in self
._values\
1071 and not isinstance(self
._values
[keys
],
1072 m5
.proxy
.BaseProxy
):
1073 cmd_str
= cmd_line_str
+ keys
1074 acc_str
= access_str
+ keys
1075 flags_dict
[cmd_str
] = ParamInfo(ptype
,
1076 self
._params
[keys
].desc
, type_str
, ex_str
,
1077 values
.pretty_print(self
._hr
_values
[keys
]),
1079 elif not keys
in self
._hr
_values\
1080 and not keys
in self
._values
:
1082 cmd_str
= cmd_line_str
+ keys
1083 acc_str
= access_str
+ keys
1084 flags_dict
[cmd_str
] = ParamInfo(ptype
,
1085 self
._params
[keys
].desc
,
1086 type_str
, ex_str
, '', acc_str
)
1090 # Initialize new instance. For objects with SimObject-valued
1091 # children, we need to recursively clone the classes represented
1092 # by those param values as well in a consistent "deep copy"-style
1093 # fashion. That is, we want to make sure that each instance is
1094 # cloned only once, and that if there are multiple references to
1095 # the same original object, we end up with the corresponding
1096 # cloned references all pointing to the same cloned instance.
1097 def __init__(self
, **kwargs
):
1098 ancestor
= kwargs
.get('_ancestor')
1099 memo_dict
= kwargs
.get('_memo')
1100 if memo_dict
is None:
1101 # prepare to memoize any recursively instantiated objects
1104 # memoize me now to avoid problems with recursive calls
1105 memo_dict
[ancestor
] = self
1108 ancestor
= self
.__class
__
1109 ancestor
._instantiated
= True
1111 # initialize required attributes
1114 self
._ccObject
= None # pointer to C++ object
1115 self
._ccParams
= None
1116 self
._instantiated
= False # really "cloned"
1118 # Clone children specified at class level. No need for a
1119 # multidict here since we will be cloning everything.
1120 # Do children before parameter values so that children that
1121 # are also param values get cloned properly.
1123 for key
,val
in ancestor
._children
.items():
1124 self
.add_child(key
, val(_memo
=memo_dict
))
1126 # Inherit parameter values from class using multidict so
1127 # individual value settings can be overridden but we still
1128 # inherit late changes to non-overridden class values.
1129 self
._values
= multidict(ancestor
._values
)
1130 self
._hr
_values
= multidict(ancestor
._hr
_values
)
1131 # clone SimObject-valued parameters
1132 for key
,val
in ancestor
._values
.items():
1133 val
= tryAsSimObjectOrVector(val
)
1135 self
._values
[key
] = val(_memo
=memo_dict
)
1137 # clone port references. no need to use a multidict here
1138 # since we will be creating new references for all ports.
1139 self
._port
_refs
= {}
1140 for key
,val
in ancestor
._port
_refs
.items():
1141 self
._port
_refs
[key
] = val
.clone(self
, memo_dict
)
1142 # apply attribute assignments from keyword args, if any
1143 for key
,val
in kwargs
.items():
1144 setattr(self
, key
, val
)
1146 # "Clone" the current instance by creating another instance of
1147 # this instance's class, but that inherits its parameter values
1148 # and port mappings from the current instance. If we're in a
1149 # "deep copy" recursive clone, check the _memo dict to see if
1150 # we've already cloned this instance.
1151 def __call__(self
, **kwargs
):
1152 memo_dict
= kwargs
.get('_memo')
1153 if memo_dict
is None:
1154 # no memo_dict: must be top-level clone operation.
1155 # this is only allowed at the root of a hierarchy
1157 raise RuntimeError("attempt to clone object %s " \
1158 "not at the root of a tree (parent = %s)" \
1159 % (self
, self
._parent
))
1160 # create a new dict and use that.
1162 kwargs
['_memo'] = memo_dict
1163 elif self
in memo_dict
:
1164 # clone already done & memoized
1165 return memo_dict
[self
]
1166 return self
.__class
__(_ancestor
= self
, **kwargs
)
1168 def _get_port_ref(self
, attr
):
1169 # Return reference that can be assigned to another port
1170 # via __setattr__. There is only ever one reference
1171 # object per port, but we create them lazily here.
1172 ref
= self
._port
_refs
.get(attr
)
1174 ref
= self
._ports
[attr
].makeRef(self
)
1175 self
._port
_refs
[attr
] = ref
1178 def __getattr__(self
, attr
):
1179 if attr
in self
._ports
:
1180 return self
._get
_port
_ref
(attr
)
1182 if attr
in self
._values
:
1183 return self
._values
[attr
]
1185 if attr
in self
._children
:
1186 return self
._children
[attr
]
1188 # If the attribute exists on the C++ object, transparently
1189 # forward the reference there. This is typically used for
1190 # methods exported to Python (e.g., init(), and startup())
1191 if self
._ccObject
and hasattr(self
._ccObject
, attr
):
1192 return getattr(self
._ccObject
, attr
)
1194 err_string
= "object '%s' has no attribute '%s'" \
1195 % (self
.__class
__.__name
__, attr
)
1197 if not self
._ccObject
:
1198 err_string
+= "\n (C++ object is not yet constructed," \
1199 " so wrapped C++ methods are unavailable.)"
1201 raise AttributeError(err_string
)
1203 # Set attribute (called on foo.attr = value when foo is an
1204 # instance of class cls).
1205 def __setattr__(self
, attr
, value
):
1206 # normal processing for private attributes
1207 if attr
.startswith('_'):
1208 object.__setattr
__(self
, attr
, value
)
1211 if attr
in self
._ports
:
1212 # set up port connection
1213 self
._get
_port
_ref
(attr
).connect(value
)
1216 param
= self
._params
.get(attr
)
1220 value
= param
.convert(value
)
1221 except Exception as e
:
1222 msg
= "%s\nError setting param %s.%s to %s\n" % \
1223 (e
, self
.__class
__.__name
__, attr
, value
)
1226 self
._values
[attr
] = value
1227 # implicitly parent unparented objects assigned as params
1228 if isSimObjectOrVector(value
) and not value
.has_parent():
1229 self
.add_child(attr
, value
)
1230 # set the human-readable value dict if this is a param
1231 # with a literal value and is not being set as an object
1233 if not (isSimObjectOrVector(value
) or\
1234 isinstance(value
, m5
.proxy
.BaseProxy
)):
1235 self
._hr
_values
[attr
] = hr_value
1239 # if RHS is a SimObject, it's an implicit child assignment
1240 if isSimObjectOrSequence(value
):
1241 self
.add_child(attr
, value
)
1244 # no valid assignment... raise exception
1245 raise AttributeError("Class %s has no parameter %s" \
1246 % (self
.__class
__.__name
__, attr
))
1249 # this hack allows tacking a '[0]' onto parameters that may or may
1250 # not be vectors, and always getting the first element (e.g. cpus)
1251 def __getitem__(self
, key
):
1254 raise IndexError("Non-zero index '%s' to SimObject" % key
)
1256 # this hack allows us to iterate over a SimObject that may
1257 # not be a vector, so we can call a loop over it and get just one
1262 # Also implemented by SimObjectVector
1263 def clear_parent(self
, old_parent
):
1264 assert self
._parent
is old_parent
1267 # Also implemented by SimObjectVector
1268 def set_parent(self
, parent
, name
):
1269 self
._parent
= parent
1272 # Return parent object of this SimObject, not implemented by
1273 # SimObjectVector because the elements in a SimObjectVector may not share
1275 def get_parent(self
):
1278 # Also implemented by SimObjectVector
1282 # Also implemented by SimObjectVector
1283 def has_parent(self
):
1284 return self
._parent
is not None
1286 # clear out child with given name. This code is not likely to be exercised.
1287 # See comment in add_child.
1288 def clear_child(self
, name
):
1289 child
= self
._children
[name
]
1290 child
.clear_parent(self
)
1291 del self
._children
[name
]
1293 # Add a new child to this object.
1294 def add_child(self
, name
, child
):
1295 child
= coerceSimObjectOrVector(child
)
1296 if child
.has_parent():
1297 warn("add_child('%s'): child '%s' already has parent", name
,
1299 if name
in self
._children
:
1300 # This code path had an undiscovered bug that would make it fail
1301 # at runtime. It had been here for a long time and was only
1302 # exposed by a buggy script. Changes here will probably not be
1303 # exercised without specialized testing.
1304 self
.clear_child(name
)
1305 child
.set_parent(self
, name
)
1306 if not isNullPointer(child
):
1307 self
._children
[name
] = child
1309 # Take SimObject-valued parameters that haven't been explicitly
1310 # assigned as children and make them children of the object that
1311 # they were assigned to as a parameter value. This guarantees
1312 # that when we instantiate all the parameter objects we're still
1313 # inside the configuration hierarchy.
1314 def adoptOrphanParams(self
):
1315 for key
,val
in self
._values
.items():
1316 if not isSimObjectVector(val
) and isSimObjectSequence(val
):
1317 # need to convert raw SimObject sequences to
1318 # SimObjectVector class so we can call has_parent()
1319 val
= SimObjectVector(val
)
1320 self
._values
[key
] = val
1321 if isSimObjectOrVector(val
) and not val
.has_parent():
1322 warn("%s adopting orphan SimObject param '%s'", self
, key
)
1323 self
.add_child(key
, val
)
1326 if not self
._parent
:
1327 return '<orphan %s>' % self
.__class
__
1328 elif isinstance(self
._parent
, MetaSimObject
):
1329 return str(self
.__class
__)
1331 ppath
= self
._parent
.path()
1334 return ppath
+ "." + self
._name
1339 def config_value(self
):
1345 def find_any(self
, ptype
):
1346 if isinstance(self
, ptype
):
1350 for child
in self
._children
.values():
1352 if hasattr(child
, '_visited'):
1353 visited
= getattr(child
, '_visited')
1355 if isinstance(child
, ptype
) and not visited
:
1356 if found_obj
!= None and child
!= found_obj
:
1357 raise AttributeError(
1358 'parent.any matched more than one: %s %s' % \
1359 (found_obj
.path
, child
.path
))
1361 # search param space
1362 for pname
,pdesc
in self
._params
.items():
1363 if issubclass(pdesc
.ptype
, ptype
):
1364 match_obj
= self
._values
[pname
]
1365 if found_obj
!= None and found_obj
!= match_obj
:
1366 raise AttributeError(
1367 'parent.any matched more than one: %s and %s' % \
1368 (found_obj
.path
, match_obj
.path
))
1369 found_obj
= match_obj
1370 return found_obj
, found_obj
!= None
1372 def find_all(self
, ptype
):
1375 for child
in self
._children
.values():
1376 # a child could be a list, so ensure we visit each item
1377 if isinstance(child
, list):
1382 for child
in children
:
1383 if isinstance(child
, ptype
) and not isproxy(child
) and \
1384 not isNullPointer(child
):
1386 if isSimObject(child
):
1387 # also add results from the child itself
1388 child_all
, done
= child
.find_all(ptype
)
1389 all
.update(dict(zip(child_all
, [done
] * len(child_all
))))
1390 # search param space
1391 for pname
,pdesc
in self
._params
.items():
1392 if issubclass(pdesc
.ptype
, ptype
):
1393 match_obj
= self
._values
[pname
]
1394 if not isproxy(match_obj
) and not isNullPointer(match_obj
):
1395 all
[match_obj
] = True
1396 # Also make sure to sort the keys based on the objects' path to
1397 # ensure that the order is the same on all hosts
1398 return sorted(all
.keys(), key
= lambda o
: o
.path()), True
1400 def unproxy(self
, base
):
1403 def unproxyParams(self
):
1404 for param
in self
._params
.keys():
1405 value
= self
._values
.get(param
)
1406 if value
!= None and isproxy(value
):
1408 value
= value
.unproxy(self
)
1410 print("Error in unproxying param '%s' of %s" %
1411 (param
, self
.path()))
1413 setattr(self
, param
, value
)
1415 # Unproxy ports in sorted order so that 'append' operations on
1416 # vector ports are done in a deterministic fashion.
1417 port_names
= list(self
._ports
.keys())
1419 for port_name
in port_names
:
1420 port
= self
._port
_refs
.get(port_name
)
1424 def print_ini(self
, ini_file
):
1425 print('[' + self
.path() + ']', file=ini_file
) # .ini section header
1427 instanceDict
[self
.path()] = self
1429 if hasattr(self
, 'type'):
1430 print('type=%s' % self
.type, file=ini_file
)
1432 if len(self
._children
.keys()):
1433 print('children=%s' %
1434 ' '.join(self
._children
[n
].get_name()
1435 for n
in sorted(self
._children
.keys())),
1438 for param
in sorted(self
._params
.keys()):
1439 value
= self
._values
.get(param
)
1441 print('%s=%s' % (param
, self
._values
[param
].ini_str()),
1444 for port_name
in sorted(self
._ports
.keys()):
1445 port
= self
._port
_refs
.get(port_name
, None)
1447 print('%s=%s' % (port_name
, port
.ini_str()), file=ini_file
)
1449 print(file=ini_file
) # blank line between objects
1451 # generate a tree of dictionaries expressing all the parameters in the
1452 # instantiated system for use by scripts that want to do power, thermal
1453 # visualization, and other similar tasks
1454 def get_config_as_dict(self
):
1456 if hasattr(self
, 'type'):
1458 if hasattr(self
, 'cxx_class'):
1459 d
.cxx_class
= self
.cxx_class
1460 # Add the name and path of this object to be able to link to
1462 d
.name
= self
.get_name()
1463 d
.path
= self
.path()
1465 for param
in sorted(self
._params
.keys()):
1466 value
= self
._values
.get(param
)
1468 d
[param
] = value
.config_value()
1470 for n
in sorted(self
._children
.keys()):
1471 child
= self
._children
[n
]
1472 # Use the name of the attribute (and not get_name()) as
1473 # the key in the JSON dictionary to capture the hierarchy
1474 # in the Python code that assembled this system
1475 d
[n
] = child
.get_config_as_dict()
1477 for port_name
in sorted(self
._ports
.keys()):
1478 port
= self
._port
_refs
.get(port_name
, None)
1480 # Represent each port with a dictionary containing the
1481 # prominent attributes
1482 d
[port_name
] = port
.get_config_as_dict()
1486 def getCCParams(self
):
1488 return self
._ccParams
1490 cc_params_struct
= getattr(m5
.internal
.params
, '%sParams' % self
.type)
1491 cc_params
= cc_params_struct()
1492 cc_params
.name
= str(self
)
1494 param_names
= list(self
._params
.keys())
1496 for param
in param_names
:
1497 value
= self
._values
.get(param
)
1499 fatal("%s.%s without default or user set value",
1502 value
= value
.getValue()
1503 if isinstance(self
._params
[param
], VectorParamDesc
):
1504 assert isinstance(value
, list)
1505 vec
= getattr(cc_params
, param
)
1507 # Some types are exposed as opaque types. They support
1508 # the append operation unlike the automatically
1510 if isinstance(vec
, list):
1511 setattr(cc_params
, param
, list(value
))
1514 getattr(cc_params
, param
).append(v
)
1516 setattr(cc_params
, param
, value
)
1518 port_names
= list(self
._ports
.keys())
1520 for port_name
in port_names
:
1521 port
= self
._port
_refs
.get(port_name
, None)
1523 port_count
= len(port
)
1526 setattr(cc_params
, 'port_' + port_name
+ '_connection_count',
1528 self
._ccParams
= cc_params
1529 return self
._ccParams
1531 # Get C++ object corresponding to this object, calling C++ if
1532 # necessary to construct it. Does *not* recursively create
1534 def getCCObject(self
):
1535 if not self
._ccObject
:
1536 # Make sure this object is in the configuration hierarchy
1537 if not self
._parent
and not isRoot(self
):
1538 raise RuntimeError("Attempt to instantiate orphan node")
1539 # Cycles in the configuration hierarchy are not supported. This
1540 # will catch the resulting recursion and stop.
1542 if not self
.abstract
:
1543 params
= self
.getCCParams()
1544 self
._ccObject
= params
.create()
1545 elif self
._ccObject
== -1:
1546 raise RuntimeError("%s: Cycle found in configuration hierarchy." \
1548 return self
._ccObject
1550 def descendants(self
):
1552 # The order of the dict is implementation dependent, so sort
1553 # it based on the key (name) to ensure the order is the same
1555 for (name
, child
) in sorted(self
._children
.items()):
1556 for obj
in child
.descendants():
1559 # Call C++ to create C++ object corresponding to this object
1560 def createCCObject(self
):
1562 self
.getCCObject() # force creation
1565 return self
.getCCObject()
1567 # Create C++ port connections corresponding to the connections in
1569 def connectPorts(self
):
1570 # Sort the ports based on their attribute name to ensure the
1571 # order is the same on all hosts
1572 for (attr
, portRef
) in sorted(self
._port
_refs
.items()):
1575 # Default function for generating the device structure.
1576 # Can be overloaded by the inheriting class
1577 def generateDeviceTree(self
, state
):
1578 return # return without yielding anything
1579 yield # make this function a (null) generator
1581 def recurseDeviceTree(self
, state
):
1582 for child
in self
._children
.values():
1583 for item
in child
: # For looping over SimObjectVectors
1584 for dt
in item
.generateDeviceTree(state
):
1587 # On a separate method otherwise certain buggy Python versions
1588 # would fail with: SyntaxError: unqualified exec is not allowed
1589 # in function 'apply_config'
1590 def _apply_config_get_dict(self
):
1592 child_name
: SimObjectCliWrapper(
1593 iter(self
._children
[child_name
]))
1594 for child_name
in self
._children
1597 def apply_config(self
, params
):
1599 exec a list of Python code strings contained in params.
1601 The only exposed globals to those strings are the child
1602 SimObjects of this node.
1604 This function is intended to allow users to modify SimObject
1605 parameters from the command line with Python statements.
1607 d
= self
._apply
_config
_get
_dict
()
1608 for param
in params
:
1611 # Function to provide to C++ so it can look up instances based on paths
1612 def resolveSimObject(name
):
1613 obj
= instanceDict
[name
]
1614 return obj
.getCCObject()
1616 def isSimObject(value
):
1617 return isinstance(value
, SimObject
)
1619 def isSimObjectClass(value
):
1620 return issubclass(value
, SimObject
)
1622 def isSimObjectVector(value
):
1623 return isinstance(value
, SimObjectVector
)
1625 def isSimObjectSequence(value
):
1626 if not isinstance(value
, (list, tuple)) or len(value
) == 0:
1630 if not isNullPointer(val
) and not isSimObject(val
):
1635 def isSimObjectOrSequence(value
):
1636 return isSimObject(value
) or isSimObjectSequence(value
)
1639 from m5
.objects
import Root
1640 return obj
and obj
is Root
.getInstance()
1642 def isSimObjectOrVector(value
):
1643 return isSimObject(value
) or isSimObjectVector(value
)
1645 def tryAsSimObjectOrVector(value
):
1646 if isSimObjectOrVector(value
):
1648 if isSimObjectSequence(value
):
1649 return SimObjectVector(value
)
1652 def coerceSimObjectOrVector(value
):
1653 value
= tryAsSimObjectOrVector(value
)
1655 raise TypeError("SimObject or SimObjectVector expected")
1658 baseClasses
= allClasses
.copy()
1659 baseInstances
= instanceDict
.copy()
1662 global allClasses
, instanceDict
, noCxxHeader
1664 allClasses
= baseClasses
.copy()
1665 instanceDict
= baseInstances
.copy()
1668 # __all__ defines the list of symbols that get exported when
1669 # 'from config import *' is invoked. Try to keep this reasonably
1670 # short to avoid polluting other namespaces.