1c1
< # Copyright (c) 2012 ARM Limited
---
> # Copyright (c) 2017 ARM Limited
43a44
> # Andreas Sandberg
46a48,49
> from functools import wraps
> import inspect
49a53
> from m5.util.pybind import *
271d274
< code('this->pyobj = NULL;')
396,401c399,408
< init_keywords = { 'abstract' : bool,
< 'cxx_class' : str,
< 'cxx_type' : str,
< 'cxx_header' : str,
< 'type' : str,
< 'cxx_bases' : list }
---
> init_keywords = {
> 'abstract' : bool,
> 'cxx_class' : str,
> 'cxx_type' : str,
> 'cxx_header' : str,
> 'type' : str,
> 'cxx_bases' : list,
> 'cxx_exports' : list,
> 'cxx_param_exports' : list,
> }
417a425
> cxx_exports = []
418a427,431
> try:
> cxx_exports.append(getattr(val, "__pybind"))
> except AttributeError:
> pass
>
427a441,446
> if 'cxx_exports' not in value_dict:
> value_dict['cxx_exports'] = cxx_exports
> else:
> value_dict['cxx_exports'] += cxx_exports
> if 'cxx_param_exports' not in value_dict:
> value_dict['cxx_param_exports'] = []
656a676,678
> def pybind_predecls(cls, code):
> code('#include "${{cls.cxx_header}}"')
>
757a780,784
> def pybind_decl(cls, code):
> class_path = cls.cxx_class.split('::')
> namespaces, classname = class_path[:-1], class_path[-1]
> py_class_name = '_COLONS_'.join(class_path) if namespaces else \
> classname;
758a786,859
> # The 'local' attribute restricts us to the params declared in
> # the object itself, not including inherited params (which
> # will also be inherited from the base class's param struct
> # here). Sort the params based on their key
> params = map(lambda (k, v): v, sorted(cls._params.local.items()))
> ports = cls._ports.local
>
> code('''#include "pybind11/pybind11.h"
> #include "pybind11/stl.h"
>
> #include "sim/sim_object.hh"
> #include "params/$cls.hh"
> #include "sim/init.hh"
> #include "${{cls.cxx_header}}"
>
> ''')
>
> for param in params:
> param.pybind_predecls(code)
>
> code('''namespace py = pybind11;
>
> static void
> module_init(py::module &m_internal)
> {
> py::module m = m_internal.def_submodule("param_${cls}");
> ''')
> code.indent()
> if cls._base:
> code('py::class_<${cls}Params, ${{cls._base.type}}Params>(m, ' \
> '"${cls}Params")')
> else:
> code('py::class_<${cls}Params>(m, "${cls}Params")')
>
> code.indent()
> if not hasattr(cls, 'abstract') or not cls.abstract:
> code('.def(py::init<>())')
> code('.def("create", &${cls}Params::create)')
>
> param_exports = cls.cxx_param_exports + [
> PyBindProperty(k)
> for k, v in sorted(cls._params.local.items())
> ] + [
> PyBindProperty("port_%s_connection_count" % port.name)
> for port in ports.itervalues()
> ]
> for exp in param_exports:
> exp.export(code, "%sParams" % cls)
>
> code(';')
> code()
> code.dedent()
>
> bases = [ cls._base.cxx_class ] + cls.cxx_bases if cls._base else \
> cls.cxx_bases
> if bases:
> base_str = ", ".join(bases)
> code('py::class_<${{cls.cxx_class}}, ${base_str}>(m, ' \
> '"${py_class_name}")')
> else:
> code('py::class_<${{cls.cxx_class}}>(m, "${py_class_name}")')
> code.indent()
> for exp in cls.cxx_exports:
> exp.export(code, cls.cxx_class)
> code(';')
> code.dedent()
> code()
> code.dedent()
> code('}')
> code()
> code('static EmbeddedPyBind embed_obj("${0}", module_init, "${1}");',
> cls, cls._base.type if cls._base else "")
>
>
782a884,891
>
> # The base SimObject has a couple of params that get
> # automatically set from Python without being declared through
> # the normal Param mechanism; we slip them in here (needed
> # predecls now, actual declarations below)
> if cls == SimObject:
> code('''#include <string>''')
>
792,803d900
< # The base SimObject has a couple of params that get
< # automatically set from Python without being declared through
< # the normal Param mechanism; we slip them in here (needed
< # predecls now, actual declarations below)
< if cls == SimObject:
< code('''
< #ifndef PY_VERSION
< struct PyObject;
< #endif
<
< #include <string>
< ''')
835d931
< PyObject *pyobj;
836a933
>
863a961,1001
> def cxxMethod(*args, **kwargs):
> """Decorator to export C++ functions to Python"""
>
> def decorate(func):
> name = func.func_name
> override = kwargs.get("override", False)
> cxx_name = kwargs.get("cxx_name", name)
>
> args, varargs, keywords, defaults = inspect.getargspec(func)
> if varargs or keywords:
> raise ValueError("Wrapped methods must not contain variable " \
> "arguments")
>
> # Create tuples of (argument, default)
> if defaults:
> args = args[:-len(defaults)] + zip(args[-len(defaults):], defaults)
> # Don't include self in the argument list to PyBind
> args = args[1:]
>
>
> @wraps(func)
> def cxx_call(self, *args, **kwargs):
> ccobj = self.getCCObject()
> return getattr(ccobj, name)(*args, **kwargs)
>
> @wraps(func)
> def py_call(self, *args, **kwargs):
> return self.func(*args, **kwargs)
>
> f = py_call if override else cxx_call
> f.__pybind = PyBindMethod(name, cxx_name=cxx_name, args=args)
>
> return f
>
> if len(args) == 0:
> return decorate
> elif len(args) == 1 and len(kwargs) == 0:
> return decorate(*args)
> else:
> raise TypeError("One argument and no kwargs, or only kwargs expected")
>
923a1062,1082
> cxx_exports = [
> PyBindMethod("init"),
> PyBindMethod("initState"),
> PyBindMethod("memInvalidate"),
> PyBindMethod("memWriteback"),
> PyBindMethod("regStats"),
> PyBindMethod("resetStats"),
> PyBindMethod("regProbePoints"),
> PyBindMethod("regProbeListeners"),
> PyBindMethod("startup"),
> ]
>
> cxx_param_exports = [
> PyBindProperty("name"),
> ]
>
> @cxxMethod
> def loadState(self, cp):
> """Load SimObject state from a checkpoint"""
> pass
>
1382d1540
< cc_params.pyobj = self
1398,1399c1556
< for v in value:
< vec.append(v)
---
> setattr(cc_params, param, list(value))
1520c1677,1682
< __all__ = [ 'SimObject' ]
---
> __all__ = [
> 'SimObject',
> 'cxxMethod',
> 'PyBindMethod',
> 'PyBindProperty',
> ]