diff --git a/PyScModule.cpp b/PyScModule.cpp new file mode 100644 index 0000000..ada025b --- /dev/null +++ b/PyScModule.cpp @@ -0,0 +1,57 @@ +/* + * PyScModule.cpp + * + * Created on: 08.06.2019 + * Author: eyck + */ + +#include "PyScModule.h" +#define PY_SSIZE_T_CLEAN +#include + +class TPyScriptThreadLocker { + PyGILState_STATE m_state; +public: + TPyScriptThreadLocker(): m_state(PyGILState_Ensure()) {} + ~TPyScriptThreadLocker() { PyGILState_Release(m_state); } +}; + +scc::PyScModule::PyScModule(PyObject* self, const sc_core::sc_module_name& nm) +: sc_core::sc_module(nm) +, self(self) +{ + if (! PyEval_ThreadsInitialized()) + PyEval_InitThreads(); + Py_INCREF(self); +} + +scc::PyScModule::~PyScModule() { + Py_DECREF(self); +} + +void scc::PyScModule::before_end_of_elaboration(){ + invoke_callback("BeforeEndOfElaboration"); +} + +void scc::PyScModule::end_of_elaboration(){ + invoke_callback("EndOfElaboration"); +} +void scc::PyScModule::start_of_simulation(){ + invoke_callback("StartOfSimulation"); +} + +void scc::PyScModule::end_of_simulation(){ + invoke_callback("EndOfSimulation"); +} + +void scc::PyScModule::invoke_callback(const char* callback_name) { + // acquiring the GIL + PyGILState_STATE gstate; + gstate = PyGILState_Ensure(); + if(PyObject_HasAttrString(self, callback_name)){ + auto* func = PyObject_GetAttrString(self, callback_name); + PyObject_CallFunctionObjArgs(func, nullptr); + } + // Release the thread. No Python API allowed beyond this point. + PyGILState_Release(gstate); +} diff --git a/PyScModule.h b/PyScModule.h new file mode 100644 index 0000000..25ab3c3 --- /dev/null +++ b/PyScModule.h @@ -0,0 +1,33 @@ +/* + * PyScModule.h + * + * Created on: 08.06.2019 + * Author: eyck + */ + +#ifndef COMPONENTS_PYSCMODULE_H_ +#define COMPONENTS_PYSCMODULE_H_ +#include +#include +#include + +typedef struct _object PyObject; + +namespace scc { + +class PyScModule: public sc_core::sc_module { +public: + PyScModule(PyObject* self, const sc_core::sc_module_name& nm); + virtual ~PyScModule(); +protected: + void before_end_of_elaboration() override; + void end_of_elaboration() override; + void start_of_simulation() override; + void end_of_simulation() override; +private: + void invoke_callback(const char*); + PyObject* self{nullptr}; +}; + +} +#endif /* COMPONENTS_PYSCMODULE_H_ */ diff --git a/pysysc/sccppyy.py b/pysysc/sccppyy.py index 514e373..b9b6160 100644 --- a/pysysc/sccppyy.py +++ b/pysysc/sccppyy.py @@ -1,6 +1,7 @@ import json import cppyy import os.path +from pathlib import Path import sys import tempfile import conans.client.conan_api as conan @@ -13,8 +14,6 @@ lang_symbols = { 14:'201402L', 17:'201703L'} lang_level=11 -''' -''' sysIncludeDirs = set() @@ -92,6 +91,7 @@ namespace sc_core { extern void pln(); } if systemc_loaded: break; if not interactive: cppyy.gbl.sc_core.pln() cppyy.gbl.sc_core.sc_in_action=True + _load_pythonization_lib() return True return False @@ -120,7 +120,17 @@ def _load_systemc_cci(): cci_loaded=True return True return False - + +def _load_pythonization_lib(): + import pysysc + path = os.path.dirname(os.path.dirname(pysysc.__file__)) + for file in os.listdir(path): + if file.endswith(".so"): + cppyy.load_library(os.path.join(path, file)) + cppyy.include(os.path.join(path, "PyScModule.h")) + return + + def add_library(file, lib): buf = io.StringIO() with redirect_stdout(buf), redirect_stderr(buf): @@ -150,8 +160,6 @@ def _pythonizor(clazz, name): clazz.__repr__ = lambda self: repr(self.name()) elif len(name) > 10 and name[:9] == 'sc_export<': clazz.__repr__ = lambda self: repr(self.name()) -# else: -# print('not pythonizing', name) # install the pythonizor as a callback on namespace 'Math' (default is the global namespace) cppyy.py.add_pythonization(_pythonizor, 'sc_core') diff --git a/pysysc/structural.py b/pysysc/structural.py index 1b7f57b..e83a2cb 100644 --- a/pysysc/structural.py +++ b/pysysc/structural.py @@ -8,7 +8,6 @@ from builtins import getattr import re from enum import Enum import logging -import pysysc class Mode(Enum): SIM = 1 @@ -21,6 +20,8 @@ class Simulation(object): @staticmethod def run(): cpp.sc_core.sc_start() + if not cpp.sc_core.sc_end_of_simulation_invoked(): + cpp.sc_core.sc_stop() @staticmethod def setup(log_level = logging.WARNING): diff --git a/setup.py b/setup.py index 196431f..ec3c5df 100644 --- a/setup.py +++ b/setup.py @@ -1,15 +1,26 @@ -from setuptools import setup - +from setuptools import setup, Extension +import os def readme(): with open('README.md') as f: return f.read() +sysc_home = os.environ['SYSTEMC_HOME'] + +pysyscsc = Extension('pysyscsc', + define_macros = [('MAJOR_VERSION', '1'), ('MINOR_VERSION', '0')], + extra_compile_args = ['-std=c++11'], + include_dirs = [sysc_home+'/include'], + libraries = ['systemc'], + library_dirs = [sysc_home+'/lib'], + sources = ['PyScModule.cpp']) + setup(name='PySysC', version='0.1', description='Python SystemC binding', long_description=readme(), + ext_modules = [pysyscsc], classifiers=[ 'Development Status :: 3 - Alpha', 'License :: OSI Approved :: Apache Software License', @@ -22,11 +33,12 @@ setup(name='PySysC', author_email='info@minres.com', license='Apache-2.0', packages=['pysysc'], + data_files=[('.',['PyScModule.h'])], + include_package_data=True, install_requires=[ 'cppyy', 'conan' ], - include_package_data=True, test_suite='nose.collector', tests_require=['nose'], )