SimObject.py (11802:be62996c95d1) SimObject.py (11988:665cd5f8b52b)
1# Copyright (c) 2012 ARM Limited
1# Copyright (c) 2017 ARM Limited
2# All rights reserved.
3#
4# The license below extends only to copyright in the software and shall
5# not be construed as granting a license to any other intellectual
6# property including but not limited to intellectual property relating
7# to a hardware implementation of the functionality of the software
8# licensed hereunder. You may use the software subject to the license
9# terms below provided that you ensure that this notice is replicated

--- 26 unchanged lines hidden (view full) ---

36# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40#
41# Authors: Steve Reinhardt
42# Nathan Binkert
43# Andreas Hansson
2# All rights reserved.
3#
4# The license below extends only to copyright in the software and shall
5# not be construed as granting a license to any other intellectual
6# property including but not limited to intellectual property relating
7# to a hardware implementation of the functionality of the software
8# licensed hereunder. You may use the software subject to the license
9# terms below provided that you ensure that this notice is replicated

--- 26 unchanged lines hidden (view full) ---

36# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40#
41# Authors: Steve Reinhardt
42# Nathan Binkert
43# Andreas Hansson
44# Andreas Sandberg
44
45import sys
46from types import FunctionType, MethodType, ModuleType
45
46import sys
47from types import FunctionType, MethodType, ModuleType
48from functools import wraps
49import inspect
47
48import m5
49from m5.util import *
50
51import m5
52from m5.util import *
53from m5.util.pybind import *
50
51# Have to import params up top since Param is referenced on initial
52# load (when SimObject class references Param to create a class
53# variable, the 'name' param)...
54from m5.params import *
55# There are a few things we need that aren't in params.__all__ since
56# normal users don't need them
57from m5.params import ParamDesc, VectorParamDesc, \

--- 205 unchanged lines hidden (view full) ---

263 code()
264 code('void ${member_prefix}setName(const std::string &name_)'
265 '${end_of_decl}')
266
267 if not is_header:
268 code('{')
269 code.indent()
270 code('this->name = name_;')
54
55# Have to import params up top since Param is referenced on initial
56# load (when SimObject class references Param to create a class
57# variable, the 'name' param)...
58from m5.params import *
59# There are a few things we need that aren't in params.__all__ since
60# normal users don't need them
61from m5.params import ParamDesc, VectorParamDesc, \

--- 205 unchanged lines hidden (view full) ---

267 code()
268 code('void ${member_prefix}setName(const std::string &name_)'
269 '${end_of_decl}')
270
271 if not is_header:
272 code('{')
273 code.indent()
274 code('this->name = name_;')
271 code('this->pyobj = NULL;')
272 code.dedent()
273 code('}')
274
275 if is_header:
276 code('const std::string &${member_prefix}getName()')
277 code('{ return this->name; }')
278
279 code()

--- 108 unchanged lines hidden (view full) ---

388 code('};')
389
390# The metaclass for SimObject. This class controls how new classes
391# that derive from SimObject are instantiated, and provides inherited
392# class behavior (just like a class controls how instances of that
393# class are instantiated, and provides inherited instance behavior).
394class MetaSimObject(type):
395 # Attributes that can be set only at initialization time
275 code.dedent()
276 code('}')
277
278 if is_header:
279 code('const std::string &${member_prefix}getName()')
280 code('{ return this->name; }')
281
282 code()

--- 108 unchanged lines hidden (view full) ---

391 code('};')
392
393# The metaclass for SimObject. This class controls how new classes
394# that derive from SimObject are instantiated, and provides inherited
395# class behavior (just like a class controls how instances of that
396# class are instantiated, and provides inherited instance behavior).
397class MetaSimObject(type):
398 # Attributes that can be set only at initialization time
396 init_keywords = { 'abstract' : bool,
397 'cxx_class' : str,
398 'cxx_type' : str,
399 'cxx_header' : str,
400 'type' : str,
401 'cxx_bases' : list }
399 init_keywords = {
400 'abstract' : bool,
401 'cxx_class' : str,
402 'cxx_type' : str,
403 'cxx_header' : str,
404 'type' : str,
405 'cxx_bases' : list,
406 'cxx_exports' : list,
407 'cxx_param_exports' : list,
408 }
402 # Attributes that can be set any time
403 keywords = { 'check' : FunctionType }
404
405 # __new__ is called before __init__, and is where the statements
406 # in the body of the class definition get loaded into the class's
407 # __dict__. We intercept this to filter out parameter & port assignments
408 # and only allow "private" attributes to be passed to the base
409 # __new__ (starting with underscore).
410 def __new__(mcls, name, bases, dict):
411 assert name not in allClasses, "SimObject %s already present" % name
412
413 # Copy "private" attributes, functions, and classes to the
414 # official dict. Everything else goes in _init_dict to be
415 # filtered in __init__.
416 cls_dict = {}
417 value_dict = {}
409 # Attributes that can be set any time
410 keywords = { 'check' : FunctionType }
411
412 # __new__ is called before __init__, and is where the statements
413 # in the body of the class definition get loaded into the class's
414 # __dict__. We intercept this to filter out parameter & port assignments
415 # and only allow "private" attributes to be passed to the base
416 # __new__ (starting with underscore).
417 def __new__(mcls, name, bases, dict):
418 assert name not in allClasses, "SimObject %s already present" % name
419
420 # Copy "private" attributes, functions, and classes to the
421 # official dict. Everything else goes in _init_dict to be
422 # filtered in __init__.
423 cls_dict = {}
424 value_dict = {}
425 cxx_exports = []
418 for key,val in dict.items():
426 for key,val in dict.items():
427 try:
428 cxx_exports.append(getattr(val, "__pybind"))
429 except AttributeError:
430 pass
431
419 if public_value(key, val):
420 cls_dict[key] = val
421 else:
422 # must be a param/port setting
423 value_dict[key] = val
424 if 'abstract' not in value_dict:
425 value_dict['abstract'] = False
426 if 'cxx_bases' not in value_dict:
427 value_dict['cxx_bases'] = []
432 if public_value(key, val):
433 cls_dict[key] = val
434 else:
435 # must be a param/port setting
436 value_dict[key] = val
437 if 'abstract' not in value_dict:
438 value_dict['abstract'] = False
439 if 'cxx_bases' not in value_dict:
440 value_dict['cxx_bases'] = []
441 if 'cxx_exports' not in value_dict:
442 value_dict['cxx_exports'] = cxx_exports
443 else:
444 value_dict['cxx_exports'] += cxx_exports
445 if 'cxx_param_exports' not in value_dict:
446 value_dict['cxx_param_exports'] = []
428 cls_dict['_value_dict'] = value_dict
429 cls = super(MetaSimObject, mcls).__new__(mcls, name, bases, cls_dict)
430 if 'type' in value_dict:
431 allClasses[name] = cls
432 return cls
433
434 # subclass initialization
435 def __init__(cls, name, bases, dict):

--- 213 unchanged lines hidden (view full) ---

649
650 def __str__(cls):
651 return cls.__name__
652
653 # See ParamValue.cxx_predecls for description.
654 def cxx_predecls(cls, code):
655 code('#include "params/$cls.hh"')
656
447 cls_dict['_value_dict'] = value_dict
448 cls = super(MetaSimObject, mcls).__new__(mcls, name, bases, cls_dict)
449 if 'type' in value_dict:
450 allClasses[name] = cls
451 return cls
452
453 # subclass initialization
454 def __init__(cls, name, bases, dict):

--- 213 unchanged lines hidden (view full) ---

668
669 def __str__(cls):
670 return cls.__name__
671
672 # See ParamValue.cxx_predecls for description.
673 def cxx_predecls(cls, code):
674 code('#include "params/$cls.hh"')
675
676 def pybind_predecls(cls, code):
677 code('#include "${{cls.cxx_header}}"')
678
657 # See ParamValue.swig_predecls for description.
658 def swig_predecls(cls, code):
659 code('%import "python/_m5/param_$cls.i"')
660
661 # Hook for exporting additional C++ methods to Python via SWIG.
662 # Default is none, override using @classmethod in class definition.
663 def export_methods(cls, code):
664 pass

--- 85 unchanged lines hidden (view full) ---

750 code('};')
751
752 for ns in reversed(namespaces):
753 code('} // namespace $ns')
754
755 code()
756 code('%include "params/$cls.hh"')
757
679 # See ParamValue.swig_predecls for description.
680 def swig_predecls(cls, code):
681 code('%import "python/_m5/param_$cls.i"')
682
683 # Hook for exporting additional C++ methods to Python via SWIG.
684 # Default is none, override using @classmethod in class definition.
685 def export_methods(cls, code):
686 pass

--- 85 unchanged lines hidden (view full) ---

772 code('};')
773
774 for ns in reversed(namespaces):
775 code('} // namespace $ns')
776
777 code()
778 code('%include "params/$cls.hh"')
779
780 def pybind_decl(cls, code):
781 class_path = cls.cxx_class.split('::')
782 namespaces, classname = class_path[:-1], class_path[-1]
783 py_class_name = '_COLONS_'.join(class_path) if namespaces else \
784 classname;
758
785
786 # The 'local' attribute restricts us to the params declared in
787 # the object itself, not including inherited params (which
788 # will also be inherited from the base class's param struct
789 # here). Sort the params based on their key
790 params = map(lambda (k, v): v, sorted(cls._params.local.items()))
791 ports = cls._ports.local
792
793 code('''#include "pybind11/pybind11.h"
794#include "pybind11/stl.h"
795
796#include "sim/sim_object.hh"
797#include "params/$cls.hh"
798#include "sim/init.hh"
799#include "${{cls.cxx_header}}"
800
801''')
802
803 for param in params:
804 param.pybind_predecls(code)
805
806 code('''namespace py = pybind11;
807
808static void
809module_init(py::module &m_internal)
810{
811 py::module m = m_internal.def_submodule("param_${cls}");
812''')
813 code.indent()
814 if cls._base:
815 code('py::class_<${cls}Params, ${{cls._base.type}}Params>(m, ' \
816 '"${cls}Params")')
817 else:
818 code('py::class_<${cls}Params>(m, "${cls}Params")')
819
820 code.indent()
821 if not hasattr(cls, 'abstract') or not cls.abstract:
822 code('.def(py::init<>())')
823 code('.def("create", &${cls}Params::create)')
824
825 param_exports = cls.cxx_param_exports + [
826 PyBindProperty(k)
827 for k, v in sorted(cls._params.local.items())
828 ] + [
829 PyBindProperty("port_%s_connection_count" % port.name)
830 for port in ports.itervalues()
831 ]
832 for exp in param_exports:
833 exp.export(code, "%sParams" % cls)
834
835 code(';')
836 code()
837 code.dedent()
838
839 bases = [ cls._base.cxx_class ] + cls.cxx_bases if cls._base else \
840 cls.cxx_bases
841 if bases:
842 base_str = ", ".join(bases)
843 code('py::class_<${{cls.cxx_class}}, ${base_str}>(m, ' \
844 '"${py_class_name}")')
845 else:
846 code('py::class_<${{cls.cxx_class}}>(m, "${py_class_name}")')
847 code.indent()
848 for exp in cls.cxx_exports:
849 exp.export(code, cls.cxx_class)
850 code(';')
851 code.dedent()
852 code()
853 code.dedent()
854 code('}')
855 code()
856 code('static EmbeddedPyBind embed_obj("${0}", module_init, "${1}");',
857 cls, cls._base.type if cls._base else "")
858
859
759 # Generate the C++ declaration (.hh file) for this SimObject's
760 # param struct. Called from src/SConscript.
761 def cxx_param_decl(cls, code):
762 # The 'local' attribute restricts us to the params declared in
763 # the object itself, not including inherited params (which
764 # will also be inherited from the base class's param struct
765 # here). Sort the params based on their key
766 params = map(lambda (k, v): v, sorted(cls._params.local.items()))

--- 8 unchanged lines hidden (view full) ---

775 class_path = cls._value_dict['cxx_class'].split('::')
776
777 code('''\
778#ifndef __PARAMS__${cls}__
779#define __PARAMS__${cls}__
780
781''')
782
860 # Generate the C++ declaration (.hh file) for this SimObject's
861 # param struct. Called from src/SConscript.
862 def cxx_param_decl(cls, code):
863 # The 'local' attribute restricts us to the params declared in
864 # the object itself, not including inherited params (which
865 # will also be inherited from the base class's param struct
866 # here). Sort the params based on their key
867 params = map(lambda (k, v): v, sorted(cls._params.local.items()))

--- 8 unchanged lines hidden (view full) ---

876 class_path = cls._value_dict['cxx_class'].split('::')
877
878 code('''\
879#ifndef __PARAMS__${cls}__
880#define __PARAMS__${cls}__
881
882''')
883
884
885 # The base SimObject has a couple of params that get
886 # automatically set from Python without being declared through
887 # the normal Param mechanism; we slip them in here (needed
888 # predecls now, actual declarations below)
889 if cls == SimObject:
890 code('''#include <string>''')
891
783 # A forward class declaration is sufficient since we are just
784 # declaring a pointer.
785 for ns in class_path[:-1]:
786 code('namespace $ns {')
787 code('class $0;', class_path[-1])
788 for ns in reversed(class_path[:-1]):
789 code('} // namespace $ns')
790 code()
791
892 # A forward class declaration is sufficient since we are just
893 # declaring a pointer.
894 for ns in class_path[:-1]:
895 code('namespace $ns {')
896 code('class $0;', class_path[-1])
897 for ns in reversed(class_path[:-1]):
898 code('} // namespace $ns')
899 code()
900
792 # The base SimObject has a couple of params that get
793 # automatically set from Python without being declared through
794 # the normal Param mechanism; we slip them in here (needed
795 # predecls now, actual declarations below)
796 if cls == SimObject:
797 code('''
798#ifndef PY_VERSION
799struct PyObject;
800#endif
801
802#include <string>
803''')
804 for param in params:
805 param.cxx_predecls(code)
806 for port in ports.itervalues():
807 port.cxx_predecls(code)
808 code()
809
810 if cls._base:
811 code('#include "params/${{cls._base.type}}.hh"')

--- 15 unchanged lines hidden (view full) ---

827
828 code.indent()
829 if cls == SimObject:
830 code('''
831 SimObjectParams() {}
832 virtual ~SimObjectParams() {}
833
834 std::string name;
901 for param in params:
902 param.cxx_predecls(code)
903 for port in ports.itervalues():
904 port.cxx_predecls(code)
905 code()
906
907 if cls._base:
908 code('#include "params/${{cls._base.type}}.hh"')

--- 15 unchanged lines hidden (view full) ---

924
925 code.indent()
926 if cls == SimObject:
927 code('''
928 SimObjectParams() {}
929 virtual ~SimObjectParams() {}
930
931 std::string name;
835 PyObject *pyobj;
836 ''')
932 ''')
933
837 for param in params:
838 param.cxx_decl(code)
839 for port in ports.itervalues():
840 port.cxx_decl(code)
841
842 code.dedent()
843 code('};')
844

--- 11 unchanged lines hidden (view full) ---

856# SimObject class definition to the MetaSimObject methods (in
857# particular _set_param, which gets called for parameters with default
858# values defined on the SimObject class itself). It will get
859# overridden by the permanent definition (which requires that
860# SimObject be defined) lower in this file.
861def isSimObjectOrVector(value):
862 return False
863
934 for param in params:
935 param.cxx_decl(code)
936 for port in ports.itervalues():
937 port.cxx_decl(code)
938
939 code.dedent()
940 code('};')
941

--- 11 unchanged lines hidden (view full) ---

953# SimObject class definition to the MetaSimObject methods (in
954# particular _set_param, which gets called for parameters with default
955# values defined on the SimObject class itself). It will get
956# overridden by the permanent definition (which requires that
957# SimObject be defined) lower in this file.
958def isSimObjectOrVector(value):
959 return False
960
961def cxxMethod(*args, **kwargs):
962 """Decorator to export C++ functions to Python"""
963
964 def decorate(func):
965 name = func.func_name
966 override = kwargs.get("override", False)
967 cxx_name = kwargs.get("cxx_name", name)
968
969 args, varargs, keywords, defaults = inspect.getargspec(func)
970 if varargs or keywords:
971 raise ValueError("Wrapped methods must not contain variable " \
972 "arguments")
973
974 # Create tuples of (argument, default)
975 if defaults:
976 args = args[:-len(defaults)] + zip(args[-len(defaults):], defaults)
977 # Don't include self in the argument list to PyBind
978 args = args[1:]
979
980
981 @wraps(func)
982 def cxx_call(self, *args, **kwargs):
983 ccobj = self.getCCObject()
984 return getattr(ccobj, name)(*args, **kwargs)
985
986 @wraps(func)
987 def py_call(self, *args, **kwargs):
988 return self.func(*args, **kwargs)
989
990 f = py_call if override else cxx_call
991 f.__pybind = PyBindMethod(name, cxx_name=cxx_name, args=args)
992
993 return f
994
995 if len(args) == 0:
996 return decorate
997 elif len(args) == 1 and len(kwargs) == 0:
998 return decorate(*args)
999 else:
1000 raise TypeError("One argument and no kwargs, or only kwargs expected")
1001
864# This class holds information about each simobject parameter
865# that should be displayed on the command line for use in the
866# configuration system.
867class ParamInfo(object):
868 def __init__(self, type, desc, type_str, example, default_val, access_str):
869 self.type = type
870 self.desc = desc
871 self.type_str = type_str

--- 44 unchanged lines hidden (view full) ---

916 void memWriteback();
917 void regStats();
918 void resetStats();
919 void regProbePoints();
920 void regProbeListeners();
921 void startup();
922''')
923
1002# This class holds information about each simobject parameter
1003# that should be displayed on the command line for use in the
1004# configuration system.
1005class ParamInfo(object):
1006 def __init__(self, type, desc, type_str, example, default_val, access_str):
1007 self.type = type
1008 self.desc = desc
1009 self.type_str = type_str

--- 44 unchanged lines hidden (view full) ---

1054 void memWriteback();
1055 void regStats();
1056 void resetStats();
1057 void regProbePoints();
1058 void regProbeListeners();
1059 void startup();
1060''')
1061
1062 cxx_exports = [
1063 PyBindMethod("init"),
1064 PyBindMethod("initState"),
1065 PyBindMethod("memInvalidate"),
1066 PyBindMethod("memWriteback"),
1067 PyBindMethod("regStats"),
1068 PyBindMethod("resetStats"),
1069 PyBindMethod("regProbePoints"),
1070 PyBindMethod("regProbeListeners"),
1071 PyBindMethod("startup"),
1072 ]
1073
1074 cxx_param_exports = [
1075 PyBindProperty("name"),
1076 ]
1077
1078 @cxxMethod
1079 def loadState(self, cp):
1080 """Load SimObject state from a checkpoint"""
1081 pass
1082
924 # Returns a dict of all the option strings that can be
925 # generated as command line options for this simobject instance
926 # by tracing all reachable params in the top level instance and
927 # any children it contains.
928 def enumerateParams(self, flags_dict = {},
929 cmd_line_str = "", access_str = ""):
930 if hasattr(self, "_paramEnumed"):
931 print "Cycle detected enumerating params"

--- 442 unchanged lines hidden (view full) ---

1374 return d
1375
1376 def getCCParams(self):
1377 if self._ccParams:
1378 return self._ccParams
1379
1380 cc_params_struct = getattr(m5.internal.params, '%sParams' % self.type)
1381 cc_params = cc_params_struct()
1083 # Returns a dict of all the option strings that can be
1084 # generated as command line options for this simobject instance
1085 # by tracing all reachable params in the top level instance and
1086 # any children it contains.
1087 def enumerateParams(self, flags_dict = {},
1088 cmd_line_str = "", access_str = ""):
1089 if hasattr(self, "_paramEnumed"):
1090 print "Cycle detected enumerating params"

--- 442 unchanged lines hidden (view full) ---

1533 return d
1534
1535 def getCCParams(self):
1536 if self._ccParams:
1537 return self._ccParams
1538
1539 cc_params_struct = getattr(m5.internal.params, '%sParams' % self.type)
1540 cc_params = cc_params_struct()
1382 cc_params.pyobj = self
1383 cc_params.name = str(self)
1384
1385 param_names = self._params.keys()
1386 param_names.sort()
1387 for param in param_names:
1388 value = self._values.get(param)
1389 if value is None:
1390 fatal("%s.%s without default or user set value",
1391 self.path(), param)
1392
1393 value = value.getValue()
1394 if isinstance(self._params[param], VectorParamDesc):
1395 assert isinstance(value, list)
1396 vec = getattr(cc_params, param)
1397 assert not len(vec)
1541 cc_params.name = str(self)
1542
1543 param_names = self._params.keys()
1544 param_names.sort()
1545 for param in param_names:
1546 value = self._values.get(param)
1547 if value is None:
1548 fatal("%s.%s without default or user set value",
1549 self.path(), param)
1550
1551 value = value.getValue()
1552 if isinstance(self._params[param], VectorParamDesc):
1553 assert isinstance(value, list)
1554 vec = getattr(cc_params, param)
1555 assert not len(vec)
1398 for v in value:
1399 vec.append(v)
1556 setattr(cc_params, param, list(value))
1400 else:
1401 setattr(cc_params, param, value)
1402
1403 port_names = self._ports.keys()
1404 port_names.sort()
1405 for port_name in port_names:
1406 port = self._port_refs.get(port_name, None)
1407 if port != None:

--- 104 unchanged lines hidden (view full) ---

1512
1513 allClasses = baseClasses.copy()
1514 instanceDict = baseInstances.copy()
1515 noCxxHeader = False
1516
1517# __all__ defines the list of symbols that get exported when
1518# 'from config import *' is invoked. Try to keep this reasonably
1519# short to avoid polluting other namespaces.
1557 else:
1558 setattr(cc_params, param, value)
1559
1560 port_names = self._ports.keys()
1561 port_names.sort()
1562 for port_name in port_names:
1563 port = self._port_refs.get(port_name, None)
1564 if port != None:

--- 104 unchanged lines hidden (view full) ---

1669
1670 allClasses = baseClasses.copy()
1671 instanceDict = baseInstances.copy()
1672 noCxxHeader = False
1673
1674# __all__ defines the list of symbols that get exported when
1675# 'from config import *' is invoked. Try to keep this reasonably
1676# short to avoid polluting other namespaces.
1520__all__ = [ 'SimObject' ]
1677__all__ = [
1678 'SimObject',
1679 'cxxMethod',
1680 'PyBindMethod',
1681 'PyBindProperty',
1682]