├── MANIFEST.in
├── pysysc
├── __init__.py
├── sysc.py
├── structural.py
└── sccppyy.py
├── .project
├── .pydevproject
├── NOTES.md
├── .gitignore
├── PyScModule.h
├── setup.py
├── README.md
├── tests
└── test_pysysc.py
├── PyScModule.cpp
├── CONTRIBUTING.md
└── LICENSE
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | recursive-include projectname *.py
2 | include README.md
3 | include LICENSE
4 | include requirements.txt
5 |
--------------------------------------------------------------------------------
/pysysc/__init__.py:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (c) 2019 -2021 MINRES Technolgies GmbH
3 | #
4 | # SPDX-License-Identifier: Apache-2.0
5 | #
6 |
7 | from .sccppyy import *
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | PySysC
4 |
5 |
6 |
7 |
8 |
9 | org.python.pydev.PyDevBuilder
10 |
11 |
12 |
13 |
14 |
15 | org.python.pydev.pythonNature
16 |
17 |
18 |
--------------------------------------------------------------------------------
/pysysc/sysc.py:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (c) 2019 -2021 MINRES Technolgies GmbH
3 | #
4 | # SPDX-License-Identifier: Apache-2.0
5 | #
6 |
7 | '''
8 | Created on 30.08.2021
9 |
10 | @author: eyck
11 | '''
12 | from cppyy import gbl as cpp
13 |
14 | class ScModule(cpp.scc.PyScModule):
15 | '''
16 | classdocs
17 | '''
18 |
19 | def __init__(self, name):
20 | super().__init__(self, name)
21 |
22 | def __getattr__(self, attr):
23 | if self.instance is None:
24 | raise AttributeError
25 | return getattr(self.instance, attr)
26 |
27 | def ScMethod(self, func, sensitivity=[], initialize=False):
28 | pass
29 |
30 |
--------------------------------------------------------------------------------
/.pydevproject:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Default
8 |
9 |
10 |
11 |
12 | python interpreter
13 |
14 |
15 |
16 |
17 | 3.6
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | /${PROJECT_DIR_NAME}
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/NOTES.md:
--------------------------------------------------------------------------------
1 | # PySysC notes
2 |
3 | ## How to install pyenv
4 |
5 | ```
6 | apt-get install -y make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev xz-utils tk-dev libffi-dev liblzma-dev python-openssl
7 |
8 | git clone https://github.com/pyenv/pyenv.git ~/.pyenv
9 | echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc
10 | echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc
11 | echo 'eval "$(pyenv init -)"' >> ~/.bashrc
12 |
13 | git clone https://github.com/pyenv/pyenv-virtualenv.git $(pyenv root)/plugins/pyenv-virtualenv
14 | echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.bashrc
15 |
16 | git clone https://github.com/pyenv/pyenv-virtualenvwrapper.git $(pyenv root)/plugins/pyenv-virtualenvwrapper
17 | ```
18 |
19 | ## How to generate an AST dump
20 |
21 | ```
22 | clang++-6.0 -Xclang -ast-dump -fsyntax-only components.h -I/home/eyck/.conan/data/SystemC/2.3.3/minres/stable/package/639c4a2f24965e2a3603237a94eab6929f9d3993/include/ -std=c++11 -fno-color-diagnostics
23 | ```
24 |
25 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # ---> Python
2 | # Byte-compiled / optimized / DLL files
3 | __pycache__/
4 | *.py[cod]
5 | *$py.class
6 |
7 | # C extensions
8 | *.so
9 |
10 | # Distribution / packaging
11 | .Python
12 | env/
13 | build/
14 | develop-eggs/
15 | dist/
16 | downloads/
17 | eggs/
18 | .eggs/
19 | lib/
20 | lib64/
21 | parts/
22 | sdist/
23 | var/
24 | wheels/
25 | *.egg-info/
26 | .installed.cfg
27 | *.egg
28 |
29 | # PyInstaller
30 | # Usually these files are written by a python script from a template
31 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
32 | *.manifest
33 | *.spec
34 |
35 | # Installer logs
36 | pip-log.txt
37 | pip-delete-this-directory.txt
38 |
39 | # Unit test / coverage reports
40 | htmlcov/
41 | .tox/
42 | .coverage
43 | .coverage.*
44 | .cache
45 | nosetests.xml
46 | coverage.xml
47 | *,cover
48 | .hypothesis/
49 |
50 | # Translations
51 | *.mo
52 | *.pot
53 |
54 | # Django stuff:
55 | *.log
56 | local_settings.py
57 |
58 | # Flask stuff:
59 | instance/
60 | .webassets-cache
61 |
62 | # Scrapy stuff:
63 | .scrapy
64 |
65 | # Sphinx documentation
66 | docs/_build/
67 |
68 | # PyBuilder
69 | target/
70 |
71 | # Jupyter Notebook
72 | .ipynb_checkpoints
73 |
74 | # pyenv
75 | .python-version
76 |
77 | # celery beat schedule file
78 | celerybeat-schedule
79 |
80 | # SageMath parsed files
81 | *.sage.py
82 |
83 | # dotenv
84 | .env
85 |
86 | # virtualenv
87 | .venv
88 | venv/
89 | ENV/
90 |
91 | # Spyder project settings
92 | .spyderproject
93 |
94 | # Rope project settings
95 | .ropeproject
96 |
97 |
--------------------------------------------------------------------------------
/PyScModule.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019 -2021 MINRES Technolgies GmbH
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | #ifndef COMPONENTS_PYSCMODULE_H_
8 | #define COMPONENTS_PYSCMODULE_H_
9 | #include
10 | #include
11 | #include
12 | #define PY_SSIZE_T_CLEAN
13 | #include
14 |
15 |
16 | typedef struct _object PyObject;
17 |
18 | namespace scc {
19 |
20 | class PyScModule: public sc_core::sc_module {
21 | public:
22 | PyScModule(PyObject* self, const sc_core::sc_module_name& nm);
23 | virtual ~PyScModule();
24 |
25 | void ScThread(std::string fname);
26 | void ScWait();
27 | void ScWait( const sc_core::sc_event& e );
28 | void ScWait( const sc_core::sc_event_or_list& el );
29 | void ScWait( const sc_core::sc_event_and_list& el );
30 | void ScWait( const sc_core::sc_time& t );
31 | void ScWait( double v, sc_core::sc_time_unit tu );
32 | void ScWait( const sc_core::sc_time& t, const sc_core::sc_event& e );
33 | void ScWait( double v, sc_core::sc_time_unit tu, const sc_core::sc_event& e );
34 | void ScWait( const sc_core::sc_time& t, const sc_core::sc_event_or_list& el );
35 | void ScWait( double v, sc_core::sc_time_unit tu, const sc_core::sc_event_or_list& el );
36 | void ScWait( const sc_core::sc_time& t, const sc_core::sc_event_and_list& el );
37 | void ScWait( double v, sc_core::sc_time_unit tu, const sc_core::sc_event_and_list& el );
38 |
39 | protected:
40 | void before_end_of_elaboration() override;
41 | void end_of_elaboration() override;
42 | void start_of_simulation() override;
43 | void end_of_simulation() override;
44 | private:
45 | void invoke_callback(std::string const&);
46 | PyObject* self{nullptr};
47 | PyGILState_STATE gstate;
48 | };
49 |
50 | }
51 | #endif /* COMPONENTS_PYSCMODULE_H_ */
52 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (c) 2019 -2021 MINRES Technolgies GmbH
3 | #
4 | # SPDX-License-Identifier: Apache-2.0
5 | #
6 |
7 | from setuptools import setup, Extension
8 | import os
9 |
10 | def find(name, path):
11 | for root, dirs, files in os.walk(path):
12 | if name in files:
13 | return os.path.join(root, name)
14 |
15 | def readme():
16 | with open('README.md') as f:
17 | return f.read()
18 |
19 | sysc_home = os.environ['SYSTEMC_HOME']
20 | if os.environ.get('STDCXX') is not None:
21 | sysc_cxxstd = os.environ['STDCXX']
22 | else:
23 | sysc_cxxstd = '11'
24 | sysc_lib_dir = os.path.dirname(find('libsystemc.so', sysc_home))
25 |
26 | pysyscsc = Extension('pysyscsc',
27 | define_macros = [('MAJOR_VERSION', '1'), ('MINOR_VERSION', '0')],
28 | include_dirs = [sysc_home+'/include'],
29 | extra_compile_args = ['-std=c++%s'%sysc_cxxstd],
30 | extra_link_args = ['-Wl,-rpath,%s'%sysc_lib_dir],
31 | libraries = ['systemc'],
32 | library_dirs = [sysc_lib_dir],
33 | sources = ['PyScModule.cpp'],
34 | depends = ['PyScModule.h'])
35 |
36 |
37 | setup(name='PySysC',
38 | version='0.2',
39 | description='Python SystemC binding',
40 | long_description=readme(),
41 | ext_modules = [pysyscsc],
42 | classifiers=[
43 | 'Development Status :: 3 - Alpha',
44 | 'License :: OSI Approved :: Apache Software License',
45 | 'Programming Language :: Python :: 3.6',
46 | 'Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)'
47 | ],
48 | keywords='SystemC simulation',
49 | url='https://github.com/accellera-official/PySysC',
50 | author='MINRES Technologies GmbH',
51 | author_email='info@minres.com',
52 | license='Apache-2.0',
53 | packages=['pysysc'],
54 | package_data={
55 | 'pysyscsc': ['PyScModule.h'],
56 | },
57 | #data_files=[('include',['PyScModule.h'])],
58 | headers=['PyScModule.h'],
59 | include_package_data=True,
60 | install_requires=[
61 | 'cppyy',
62 | 'conan<2.0'
63 | ],
64 | test_suite='nose.collector',
65 | tests_require=['nose'],
66 | )
67 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PySysC
2 |
3 | A Python package to make SystemC usable from Python. It supports composition of a SystemC/TLM model as well as running the simulation. As of version 0.2 it also allows to run Python functions as part of an SC_THREAD.
4 |
5 | ## How to setup the environment
6 |
7 | The installation for PySysC is as follows (using bash shell). The process has
8 | been tested under CentOS7 and Ubuntu 20.04. Make sure a newer version of gcc
9 | is in your path (tested with gcc-6.3.0). Also the SystemC installation has to
10 | be reference with the environment variable SYSTEMC_HOME.
11 |
12 | If you get an error complaining about
13 | missing Python.h, you need to install Python development headers. See the
14 | articel under https://blog.ducthinh.net/gcc-no-such-file-python-h.
15 |
16 | ```
17 | # create virtual environment
18 | python3 -m venv pysysc-env
19 | # and avtivate it
20 | . pysysc-env/bin/activate
21 | # update pip to mekae sure we have the newest version
22 | python3 -m pip install --upgrade pip
23 | # install wheel package
24 | python3 -m pip install wheel
25 | # install cppyy, C++ std version needs to match the version used when building the SystemC library
26 | STDCXX=11 python3 -m pip install cppyy
27 | # clone of PySysC
28 | git clone https://git.minres.com/SystemC/PySysC.git
29 | # install PySysC, for development PySysC use 'python3 -m pip install -e`
30 | SYSTEMC_HOME= python3 -m pip install PySysC
31 | ```
32 |
33 | ## Running the example
34 |
35 | To run the example you need to clone and build the PySysC-SC repo. It contains the code and libraries being used in the example. This project uses [Conan.io](https://conan.io/) as package manager so it should be installed (see down below).
36 | To deactivate conan and use a SystemC installation just comment out the line `setup_conan()` in CMakeLists.txt and set the environment variable SYSTEMC_HOME.
37 |
38 | ### Run the router_eample.py
39 |
40 | ```
41 | # get the PySysC-SC repo
42 | git clone --recursive https://git.minres.com/SystemC/PySysC-SC.git
43 | # build the project libraries as shared libs
44 | cd PySysC-SC
45 | mkdir -p build/Debug
46 | cd build/Debug
47 | cmake -DCMAKE_BUILD_TYPE=Debug -DBUILD_SHARED_LIBS=ON ../..
48 | make -j components
49 | cd ../..
50 | # now we are ready to run the example
51 | python3 router_eample.py
52 |
53 | ```
54 |
55 | ### Installing conan separately
56 |
57 | To install conan being used during cmake and build the example project without
58 | PySysC you need to execute the following steps:
59 |
60 | ```
61 | # install conan into our virtual environment pysysc-env
62 | python3 -m pip install conan
63 | # create the default profile
64 | conan profile new default --detect
65 | # add the repo for SystemC packages used in the project
66 | conan remote add minres https://api.bintray.com/conan/minres/conan-repo
67 | ```
68 |
69 | ## TODO
70 |
71 | * pythonize `sc_module` with iteration protocol (`__next__` and `StopIteration` exception)
72 | * add support for SC_METHOD
73 |
--------------------------------------------------------------------------------
/tests/test_pysysc.py:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (c) 2019 -2021 MINRES Technolgies GmbH
3 | #
4 | # SPDX-License-Identifier: Apache-2.0
5 | #
6 |
7 | import unittest
8 | import json
9 | import cppyy
10 | import os.path
11 | import pysysc as scpy
12 | from cppyy import gbl as cpp
13 |
14 |
15 | class Test(unittest.TestCase):
16 |
17 | not_initialized=True
18 |
19 | def setUp(self):
20 | if Test.not_initialized:
21 | proj_home='../../PySysC-SC'
22 | conan_path=os.path.join(proj_home, 'conanfile.txt')
23 | conan_res = scpy.read_config_from_conan(conan_path)
24 | scpy.load_systemc()
25 | scpy.add_include_path(os.path.join(proj_home, 'sc-components/incl'))
26 | scpy.add_library('scc.h', os.path.join(proj_home, 'build/Debug/lib/libscc.so'))
27 | scpy.add_include_path(os.path.join(proj_home, 'components'))
28 | scpy.add_library('components.h', os.path.join(proj_home, 'build/Debug/lib/libcomponents.so'))
29 |
30 |
31 | ###############################################################################
32 | # instantiate
33 | ###############################################################################
34 | Test.clkgen = cpp.ClkGen(cpp.sc_core.sc_module_name("clk_gen"))
35 | Test.rstgen = cpp.ResetGen(cpp.sc_core.sc_module_name("rst_gen"))
36 | Test.initiator = cpp.Initiator(cpp.sc_core.sc_module_name("initiator"))
37 | Test.memories = [cpp.Memory(cpp.sc_core.sc_module_name(name)) for name in ["mem0", "mem1", "mem2", "mem3"]]
38 | Test.router = cpp.Router[4](cpp.sc_core.sc_module_name("router"))
39 | ###############################################################################
40 | # signals
41 | ###############################################################################
42 | Test.sig_clk = cpp.sc_core.sc_signal[cpp.sc_core.sc_time]("clk")
43 | Test.sig_rst = cpp.sc_core.sc_signal[cpp.sc_dt.sc_logic]("rst")
44 | ###############################################################################
45 | # connect it
46 | ###############################################################################
47 | Test.clkgen.clk_o(Test.sig_clk)
48 | Test.rstgen.reset_o(Test.sig_rst)
49 | Test.initiator.socket.bind(Test.router.target_socket)
50 | Test.initiator.clk_i(Test.sig_clk)
51 | Test.initiator.reset_i(Test.sig_rst)
52 | Test.router.clk_i(Test.sig_clk)
53 | Test.router.reset_i(Test.sig_rst)
54 | for idx,m in enumerate(Test.memories):
55 | Test.router.initiator_socket.at(idx).bind(m.socket)
56 | m.clk_i(Test.sig_clk)
57 | m.reset_i(Test.sig_rst)
58 |
59 | Test.not_initialized=False
60 |
61 | def tearDown(self):
62 | #cpp.sc_core.sc_stop()
63 | pass
64 |
65 |
66 | def testSCTimeRepr(self):
67 | cur_time=cpp.sc_core.sc_time_stamp()
68 | cur_time_str=cur_time.to_string()
69 | self.assertEqual(cur_time_str, '0 s')
70 |
71 | def testMembers(self):
72 | members = scpy.get_members(Test.initiator)
73 | print("members")
74 | methods = scpy.get_methods(Test.initiator)
75 | print("methods")
76 | ports = scpy.get_ports(Test.initiator)
77 | print("ports")
78 | intors = scpy.get_inititator_sockets(Test.initiator)
79 | print("intors")
80 | tgts = scpy.get_target_sockets(Test.initiator)
81 | print("tgts")
82 | childs = scpy.get_submodules(Test.initiator)
83 | print("childs")
84 | self.assertTrue(len(intors)==1, "Wrong numbers of initiator sockets")
85 |
86 | def testConnection(self):
87 | intors = scpy.get_inititator_sockets(Test.initiator)
88 | self.assertFalse(isinstance(intors[0][0], cpp.sc_core.sc_object), " intor[0] connects to sc_object", )
89 |
90 | # def testSim(self):
91 | # cpp.sc_core.sc_in_action=True
92 | # cpp.sc_core.sc_start()
93 |
94 | if __name__ == "__main__":
95 | #import sys;sys.argv = ['', 'Test.testName']
96 | unittest.main()
--------------------------------------------------------------------------------
/PyScModule.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019 -2021 MINRES Technolgies GmbH
3 | *
4 | * SPDX-License-Identifier: Apache-2.0
5 | */
6 |
7 | #define SC_INCLUDE_DYNAMIC_PROCESSES
8 | #include "PyScModule.h"
9 | #define PY_SSIZE_T_CLEAN
10 | #include
11 |
12 | class TPyScriptThreadLocker {
13 | PyGILState_STATE m_state;
14 | public:
15 | TPyScriptThreadLocker(): m_state(PyGILState_Ensure()) {}
16 | ~TPyScriptThreadLocker() { PyGILState_Release(m_state); }
17 | };
18 |
19 | scc::PyScModule::PyScModule(PyObject* self, const sc_core::sc_module_name& nm)
20 | : sc_core::sc_module(nm)
21 | , self(self)
22 | {
23 | if (! PyEval_ThreadsInitialized())
24 | PyEval_InitThreads();
25 | Py_INCREF(self);
26 | }
27 |
28 | scc::PyScModule::~PyScModule() {
29 | Py_DECREF(self);
30 | }
31 |
32 | void scc::PyScModule::before_end_of_elaboration(){
33 | invoke_callback("BeforeEndOfElaboration");
34 | }
35 |
36 | void scc::PyScModule::end_of_elaboration(){
37 | invoke_callback("EndOfElaboration");
38 | }
39 |
40 | void scc::PyScModule::start_of_simulation(){
41 | invoke_callback("StartOfSimulation");
42 | }
43 |
44 | void scc::PyScModule::end_of_simulation(){
45 | invoke_callback("EndOfSimulation");
46 | }
47 |
48 | void scc::PyScModule::ScThread(std::string fname) {
49 | sc_core::sc_spawn_options opts;
50 | auto run_handle = sc_core::sc_spawn([this, fname](){
51 | invoke_callback(fname);
52 | }, nullptr, &opts);
53 | this->sensitive << run_handle;
54 | this->sensitive_pos << run_handle;
55 | this->sensitive_neg << run_handle;
56 | }
57 | void scc::PyScModule::invoke_callback(std::string const& callback_name) {
58 | if(PyObject_HasAttrString(self, callback_name.c_str())){
59 | // acquiring the GIL
60 | gstate = PyGILState_Ensure();
61 | auto* func = PyObject_GetAttrString(self, callback_name.c_str());
62 | PyObject_CallFunctionObjArgs(func, nullptr);
63 | // Release the thread. No Python API allowed beyond this point.
64 | PyGILState_Release(gstate);
65 | }
66 | }
67 |
68 | void scc::PyScModule::ScWait() {
69 | PyGILState_Release(gstate);
70 | sc_core::sc_module::wait();
71 | gstate = PyGILState_Ensure();
72 | }
73 |
74 | void scc::PyScModule::ScWait(const sc_core::sc_event& e){
75 | PyGILState_Release(gstate);
76 | sc_core::sc_module::wait(e);
77 | gstate = PyGILState_Ensure();
78 | }
79 |
80 | void scc::PyScModule::ScWait(const sc_core::sc_event_or_list &el) {
81 | PyGILState_Release(gstate);
82 | sc_core::sc_module::wait(el);
83 | gstate = PyGILState_Ensure();
84 | }
85 |
86 | void scc::PyScModule::ScWait(const sc_core::sc_event_and_list &el) {
87 | PyGILState_Release(gstate);
88 | sc_core::sc_module::wait(el);
89 | gstate = PyGILState_Ensure();
90 | }
91 |
92 | void scc::PyScModule::ScWait(const sc_core::sc_time &t) {
93 | PyGILState_Release(gstate);
94 | sc_core::sc_module::wait(t);
95 | gstate = PyGILState_Ensure();
96 | }
97 |
98 | void scc::PyScModule::ScWait(double v, sc_core::sc_time_unit tu) {
99 | PyGILState_Release(gstate);
100 | sc_core::sc_module::wait(v, tu);
101 | gstate = PyGILState_Ensure();
102 | }
103 |
104 | void scc::PyScModule::ScWait(const sc_core::sc_time &t, const sc_core::sc_event &e) {
105 | PyGILState_Release(gstate);
106 | sc_core::sc_module::wait(t, e);
107 | gstate = PyGILState_Ensure();
108 | }
109 |
110 | void scc::PyScModule::ScWait(double v, sc_core::sc_time_unit tu, const sc_core::sc_event &e) {
111 | PyGILState_Release(gstate);
112 | sc_core::sc_module::wait(v, tu, e);
113 | gstate = PyGILState_Ensure();
114 | }
115 |
116 | void scc::PyScModule::ScWait(const sc_core::sc_time &t, const sc_core::sc_event_or_list &el) {
117 | PyGILState_Release(gstate);
118 | sc_core::sc_module::wait(t, el);
119 | gstate = PyGILState_Ensure();
120 | }
121 |
122 | void scc::PyScModule::ScWait(double v, sc_core::sc_time_unit tu, const sc_core::sc_event_or_list &el) {
123 | PyGILState_Release(gstate);
124 | sc_core::sc_module::wait(v, tu, el);
125 | gstate = PyGILState_Ensure();
126 | }
127 |
128 | void scc::PyScModule::ScWait(const sc_core::sc_time &t, const sc_core::sc_event_and_list &el) {
129 | PyGILState_Release(gstate);
130 | sc_core::sc_module::wait(t, el);
131 | gstate = PyGILState_Ensure();
132 | }
133 |
134 | void scc::PyScModule::ScWait(double v, sc_core::sc_time_unit tu, const sc_core::sc_event_and_list &el) {
135 | PyGILState_Release(gstate);
136 | sc_core::sc_module::wait(v, tu, el);
137 | gstate = PyGILState_Ensure();
138 | }
139 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | How to Contribute
2 | =================
3 |
4 | This repository is owned by the [Accellera Systems Initiative][1] and
5 | is maintained by the [SystemC Language Working Group][2] (LWG)
6 | according to the [Accellera Policies and Procedures][3].
7 |
8 | **Contributions to this reference implementation can only be
9 | accepted from Accellera members.**
10 |
11 | ### Join the Accellera SystemC Language Working Group
12 |
13 | If you would like to contribute to the development of SystemC and/or this
14 | reference implementation, have your company, organization, or university
15 | join Accellera and its working groups.
16 | Find out more information at http://www.accellera.org/about/join.
17 | If your company, organization or university is already an Accellera member,
18 | you can request to [join the SystemC Language Working Group here][4].
19 |
20 | ### Join the SystemC community
21 |
22 | If you are not an Accellera member, please join the **[SystemC community
23 | forum][5]** to provide feedback, report bugs and join the general
24 | discussion around the evolution of SystemC.
25 |
26 | [1]: https://www.accellera.org
27 | [2]: https://accellera.org/activities/working-groups/systemc-language
28 | [3]: https://accellera.org/about/policies-and-procedures
29 | [4]: https://workspace.accellera.org/apps/org/workgroup/lwg/
30 | [5]: https://forums.accellera.org/forum/9-systemc/
31 |
32 | ---------------------------------------------------------------------
33 | Issue reporting
34 | ---------------------------------------------------------------------
35 |
36 | You can post the bugs and suggestions of general interest to the
37 | [SystemC Community Forum][5]. When reporting bugs, please specify
38 | the following information (if applicable):
39 |
40 | 1. SystemC version
41 | 2. platform, compiler, flags
42 | 3. description of the problem
43 | 4. steps to reproduce the problem
44 | 5. compile/runtime warnings and errors
45 | 6. code sample, not more than 100 lines to demonstrate the problem
46 |
47 | > **Note**
48 | > All bugs will only be tested against the latest publicly available
49 | > version of the product.
50 |
51 | > **Note**
52 | > All C++ compilers that SystemC supports have bugs of different
53 | > degree of severity. We cannot fix those bugs.
54 | > Please report them to the compiler vendor.
55 |
56 | Accellera WG members have access to the WG-internal issue tracking
57 | at GitHub, as described [here][6].
58 |
59 | [6]: docs/DEVELOPMENT.md#issue-tracking
60 |
61 | ---------------------------------------------------------------------
62 | Patch submission
63 | ---------------------------------------------------------------------
64 |
65 | The following **sign-off procedure** is established to ensure that
66 | patches submitted for inclusion into this Accellera reference
67 | implementation are properly licensed under the
68 | [Apache License Version 2.0](LICENSE).
69 |
70 | The sign-off is a simple line at the end of the explanation for the
71 | patch (or commit message), which certifies that you wrote it yourself
72 | or otherwise have the right to pass it on as an open-source patch:
73 |
74 | ### Accellera Developer's Certificate of Origin
75 |
76 | By making a signed-off contribution to this Accellera project,
77 | I certify that:
78 |
79 | 1. The contribution was created in whole or in part by me and I have
80 | the right to submit it under the Apache License Version 2.0
81 | (see LICENSE).
82 |
83 | 2. The contribution was provided directly to me by some other person
84 | who certified (1) above, and I am forwarding it without
85 | modification.
86 |
87 | 3. I understand and agree that this Accellera project and the
88 | contribution are public and that a record of the contribution
89 | (including all personal information I submit with it, including
90 | my sign-off) is maintained indefinitely and may be redistributed
91 | in accordance with this project or the Apache License Version 2.0.
92 |
93 | If you can certify the above *Accellera Developer's Certificate of Origin*,
94 | please use `git commit --signoff` to add a line of the form:
95 | ```
96 | Signed-off-by: Ima Contributor
97 | ```
98 | using your real name (no pseudonyms or anonymous contributions).
99 |
100 | > **Note**
101 | > For Accellera members, contributions are already bound by the
102 | > [Accellera policies and procedures][3] and the sign-off is optional,
103 | > but recommended. For **non-Accellera** members, the sign-off is
104 | > **mandatory** for consideration by the Accellera WGs.
105 |
106 | When submitting a pull-request against the public repository, the
107 | contribution may be considered by the Accellera WGs for inclusion.
108 | An Accellera member may submit it to the private repository with their
109 | own `Signed-off-by` line appended. It stays under the sole governance
110 | of the corresponding WGs to decide whether the proposal will be included
111 | in the reference implementation (or future Accellera standards).
112 |
113 | ---------------------------------------------------------------------
114 | Repository organization
115 | ---------------------------------------------------------------------
116 |
117 | The central source code repository of the Accellera SystemC implementation
118 | is hosted in two repositories at [GitHub](http://github.com). The main
119 | repositories are **private** to the [`OSCI-WG` GitHub organization][7] and
120 | can be found at:
121 |
122 | * https://github.com/OSCI-WG/systemc (core SystemC library)
123 | * https://github.com/OSCI-WG/systemc-regressions (regression test suite)
124 |
125 | A read-only, **public** copy of these repositories can be found at
126 |
127 | * https://github.com/accellera-official/systemc (core SystemC library)
128 | * https://github.com/accellera-official/systemc-regressions (regression test suite)
129 |
130 | To obtain access to the repositories and the GitHub organization in general,
131 | LWG members can contact the LWG chairs at
132 | including their GitHub account name.
133 |
134 | [7]: https://github.com/osci-wg "Accellera WG GitHub organization"
135 |
--------------------------------------------------------------------------------
/pysysc/structural.py:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (c) 2019 -2021 MINRES Technolgies GmbH
3 | #
4 | # SPDX-License-Identifier: Apache-2.0
5 | #
6 |
7 | from cppyy import gbl as cpp
8 | from builtins import getattr
9 | import re
10 | from enum import Enum
11 | import logging
12 |
13 | class Mode(Enum):
14 | SIM = 1
15 | BUILD = 2
16 |
17 | mode=Mode.SIM
18 |
19 | module_list = list()
20 | connection_list = list()
21 |
22 | def dump_structure():
23 | mports=dict()
24 |
25 | def add_port(p, io):
26 | mod = p.get_parent_object()
27 | if mod not in mports:
28 | mports[mod]=dict()
29 | mports[mod]['in']=[]
30 | mports[mod]['out']=[]
31 | if not p in mports[mod][io]:
32 | mports[mod][io].append(p)
33 |
34 | for c in connection_list:
35 | add_port(c.source, 'out')
36 | for t in c.targets:
37 | add_port(t, 'in')
38 |
39 | with open("structure.dot", "w") as f:
40 | f.write("""digraph structs {
41 | rankdir=LR
42 | node [shape=record];\n""")
43 | for m in mports.keys():
44 | #struct3 [shape=record,label="hello\nworld |{ b |{c| d|e}| f}| g | h"];
45 | in_names=['<%s> %s'%(p.basename(), p.basename()) for p in mports[m]['in']]
46 | out_names=['<%s> %s'%(p.basename(), p.basename()) for p in mports[m]['out']]
47 | if len(in_names) == 0:
48 | f.write(' %s [shape=record,label="{%s|{%s}}"];\n' % (
49 | m.name(), m.basename(), '|'.join(out_names)))
50 | elif len(out_names) == 0:
51 | f.write(' %s [shape=record,label="{{%s}|%s}"];\n' % (
52 | m.name(), '|'.join(in_names), m.basename()))
53 | else:
54 | f.write(' %s [shape=record,label="{{%s}|%s|{%s}}"];\n' % (
55 | m.name(), '|'.join(in_names), m.basename(), '|'.join(out_names)))
56 | for c in connection_list:
57 | attr = 'dir=both arrowhead=box arrowtail=obox'
58 | if isinstance(c, Signal):
59 | attr = 'dir=none'
60 | src = '%s:%s' % (c.source.get_parent_object().name(), c.source.basename())
61 | for t in c.targets:
62 | tgt = '%s:%s' % (t.get_parent_object().name(), t.basename())
63 | f.write(" %s -> %s [%s];\n" % (src, tgt, attr))
64 | f.write("}\n")
65 |
66 | class Simulation(object):
67 |
68 | @staticmethod
69 | def run(duration = None):
70 | if duration:
71 | if isinstance(duration, str):
72 | f = cpp.sc_core.sc_time.from_string(duration)
73 | elif isinstance(duration, float):
74 | f=cpp.sc_core.sc_time.from_seconds(duration)
75 | elif isinstance(duration, cpp.sc_core.sc_time):
76 | f=duration
77 | else:
78 | raise ValueError(f'Illegal value for duration: {duration}.')
79 | logging.debug(f"Starting simulation for {f.to_string()}")
80 | cpp.sc_core.sc_start(f, cpp.sc_core.SC_RUN_TO_TIME)
81 | else:
82 | logging.debug("Starting simulation")
83 | cpp.sc_core.sc_start()
84 | if not cpp.sc_core.sc_end_of_simulation_invoked():
85 | cpp.sc_core.sc_stop()
86 |
87 |
88 | def __init__(self):
89 | pass
90 |
91 | class Module(object):
92 | '''
93 | classdocs
94 | '''
95 | def __init__(self, clazz):
96 | self.cppclazz=clazz
97 | self.instance=None
98 | module_list.append(self)
99 |
100 | def __getattr__(self, attr):
101 | if self.instance is None:
102 | raise AttributeError
103 | return getattr(self.instance, attr)
104 |
105 | def create(self, name, *args):
106 | sc_name = cpp.sc_core.sc_module_name(str(name))
107 | if args:
108 | self.instance = self.cppclazz(sc_name, *args)
109 | else:
110 | self.instance = self.cppclazz(sc_name)
111 | return self
112 |
113 | class Connection(object):
114 | '''
115 | classdocs
116 | '''
117 | def __init__(self):
118 | self.source=None
119 | self.targets=[]
120 | connection_list.append(self)
121 |
122 | def src(self, module_port):
123 | self.source=module_port
124 | return self
125 |
126 | def sink(self, module_port):
127 | self.targets.append(module_port)
128 | #TODO: add try block and print types of both ports in case of a missmatch
129 | self.source.bind(module_port)
130 | return self
131 |
132 | def cross(self, module_port_in, module_port_out):
133 | self.targets.append(module_port_in)
134 | self.source.bind(module_port_in)
135 | return Connection().src(module_port_out)
136 |
137 | class Signal(Connection):
138 | '''
139 | classdocs
140 | '''
141 |
142 | _sc_inout_re = re.compile(r'^sc_core::sc_(?:_in)?out<(.*)>$')
143 | _sc_in_re = re.compile(r'^sc_core::sc_in<(.*)>$')
144 | _sc_port_re = re.compile(r'^sc_core::sc_port<[^<]*<(.*)> ?>$')
145 |
146 | def __init__(self, name=None):
147 | Connection.__init__(self)
148 | self.name=name
149 | self.signal=None
150 | self.data_type=None
151 |
152 | def create_signal(self, module_port):
153 | if self.signal is None:
154 | port_class_name = type(module_port).__cpp_name__
155 | match = self._sc_inout_re.match(port_class_name)
156 | if match:
157 | self.data_type = match.group(1)
158 | else:
159 | match = self._sc_in_re.match(port_class_name)
160 | if match:
161 | self.data_type = match.group(1)
162 | else:
163 | match = self._sc_port_re.match(port_class_name)
164 | if match:
165 | self.data_type = match.group(1)
166 | if self.data_type is None:
167 | raise AttributeError
168 | py_dt_name = self.data_type.replace("::", ".").replace("<", "[").replace(">", "]")
169 | self.signal = eval("cpp.sc_core.sc_signal[cpp.%s](self.name)" % py_dt_name)
170 |
171 | def src(self, module_port):
172 | self.source=module_port
173 | self.create_signal(module_port)
174 | module_port.bind(self.signal)
175 | return self
176 |
177 | def sink(self, module_port):
178 | self.targets.append(module_port)
179 | self.create_signal(module_port)
180 | module_port.bind(self.signal)
181 | return self
182 |
183 | def cross(self, module_port_in, module_port_out):
184 | self.targets.append(module_port_in)
185 | self.source.bind(module_port_in)
186 | return Signal().src(module_port_out)
187 |
188 | class SignalVector(Connection):
189 | '''
190 | classdocs
191 | '''
192 |
193 | _sc_inout_re = re.compile(r'^sc_core::sc_vector ?>$')
194 | _sc_in_re = re.compile(r'^sc_core::sc_vector ?>$')
195 | _sc_port_re = re.compile(r'^sc_core::sc_vector ?> ?>$')
196 |
197 | def __init__(self, name=None):
198 | Connection.__init__(self)
199 | self.name=name
200 | self.signal=None
201 | self.data_type=None
202 |
203 | def create_signal(self, module_port):
204 | if self.signal is None:
205 | port_class_name = type(module_port).__cpp_name__
206 | match = self._sc_inout_re.match(port_class_name)
207 | if match:
208 | self.data_type = match.group(1)
209 | else:
210 | match = self._sc_in_re.match(port_class_name)
211 | if match:
212 | self.data_type = match.group(1)
213 | else:
214 | match = self._sc_port_re.match(port_class_name)
215 | if match:
216 | self.data_type = match.group(1)
217 | if self.data_type is None:
218 | raise AttributeError
219 | py_dt_name = self.data_type.replace("::", ".").replace("<", "[").replace(">", "]")
220 | self.signal = eval("cpp.sc_core.sc_signal[cpp.%s](self.name)" % py_dt_name)
221 |
222 | def src(self, module_port):
223 | self.source=module_port
224 | self.create_signal(module_port)
225 | module_port.bind(self.signal)
226 | return self
227 |
228 | def sink(self, module_port):
229 | self.targets.append(module_port)
230 | self.create_signal(module_port)
231 | module_port.bind(self.signal)
232 | return self
233 |
234 | class Clock(Connection):
235 | '''
236 | classdocs
237 | '''
238 | _sc_time_re = re.compile(r'^sc_core::sc_in')
239 |
240 | def __init__(
241 | self,
242 | name=None,
243 | period=1.0,
244 | time_unit='SC_NS',
245 | duty_cycle=0.5,
246 | start_time=0,
247 | posedge_first=True):
248 | Connection.__init__(self)
249 | self.name=name
250 | self.clk_tgl = cpp.sc_core.sc_clock(
251 | 'sc_clock_'+self.name,
252 | cpp.sc_core.sc_time(period, eval(f"cpp.sc_core.{time_unit}")),
253 | duty_cycle,
254 | cpp.sc_core.sc_time(start_time, eval(f"cpp.sc_core.{time_unit}")),
255 | posedge_first)
256 | self.clk_time = None
257 |
258 | def sink(self, module_port):
259 | self.targets.append(module_port)
260 | port_class_name = type(module_port).__cpp_name__
261 | match = self._sc_time_re.match(port_class_name)
262 | if match:
263 | if self.clk_time is None:
264 | self.clk_time = cpp.sc_core.sc_signal[cpp.sc_core.sc_time](self.name)
265 | self.clk_time.write(self.clk_tgl.period())
266 | module_port.bind(self.clk_time)
267 | else:
268 | module_port.bind(self.clk_tgl)
269 |
270 | return self
271 |
272 | class Event(object):
273 | '''
274 | classdocs
275 | '''
276 |
277 | def __init__(self, name='PySysCEvent'):
278 | self.name=name
279 | self.evt = cpp.sc_core.sc_event('sc_event_'+self.name)
280 |
281 | def notify(self, period=0.0, time_unit='SC_NS'):
282 | self.evt.notify(cpp.sc_core.sc_time(period, eval(f"cpp.sc_core.{time_unit}")))
283 |
284 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/pysysc/sccppyy.py:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (c) 2019 -2021 MINRES Technolgies GmbH
3 | #
4 | # SPDX-License-Identifier: Apache-2.0
5 | #
6 |
7 | import cppyy
8 | import os.path
9 | import site
10 | from sysconfig import get_paths
11 | import sys
12 | import re
13 | import logging
14 | from contextlib import (redirect_stdout, redirect_stderr)
15 | import io
16 |
17 | lang_symbols = {
18 | 3: '199711L',
19 | 11:'201103L',
20 | 14:'201402L',
21 | 17:'201703L'}
22 | sysIncludeDirs = set()
23 |
24 | includeDirs = set()
25 |
26 | interactive = False
27 |
28 | def find_file(name, paths):
29 | for path in paths:
30 | for root, dirs, files in os.walk(path):
31 | if name in files:
32 | return os.path.join(root, name)
33 |
34 | def read_config_from_conan(build_dir, build_type='Release'):
35 | data={}
36 | with io.open(os.path.join(build_dir, 'conanbuildinfo.txt'), encoding='utf-8') as conan_file:
37 | sl = conan_file.readlines()
38 | key=''
39 | for item in sl:
40 | stripped_item = item.rstrip()
41 | match = re.search(r'\[(\S+)\]', stripped_item)
42 | if match:
43 | key=match.group(1)
44 | data[key]=[]
45 | elif len(stripped_item):
46 | data[key].append(stripped_item)
47 | # set include pathes and load libraries
48 | for p in data['includedirs']:
49 | add_sys_include_path(p)
50 | for l in data['libdirs']:
51 | if os.path.exists(l+'/'+'libsystemc.so'):
52 | cppyy.load_library(l+'/'+'libsystemc.so')
53 | for b in data['builddirs']:
54 | if '/systemc/' in b:
55 | os.environ['SYSTEMC_HOME'] =b
56 | elif '/systemc-cci/' in b:
57 | os.environ['CCI_HOME'] = b
58 | elif '/systemc-scv/' in b:
59 | os.environ['SCV_HOME'] = b
60 |
61 | systemc_loaded=False
62 | cci_loaded=False
63 |
64 | def load_systemc(cxxstd=11):
65 | if 'SYSTEMC_HOME' in os.environ:
66 | add_sys_include_path(os.path.join(os.environ['SYSTEMC_HOME'], 'include'))
67 | systemc_loaded = False
68 | for l in ['lib', 'lib64', 'lib-linux', 'lib-linux64']:
69 | for f in ['libsystemc.so']:
70 | full_file=os.path.join(os.environ['SYSTEMC_HOME'], l, f)
71 | if os.path.isfile(full_file):
72 | cppyy.load_library(full_file)
73 | cppyy.cppdef("""
74 | #define SC_CPLUSPLUS %s
75 | #include "systemc"
76 | #include "tlm"
77 | namespace sc_core { extern void pln(); }
78 | """ % lang_symbols[cxxstd])
79 | systemc_loaded=True
80 | _load_systemc_cci()
81 | break
82 | if systemc_loaded: break;
83 | if not interactive: cppyy.gbl.sc_core.pln()
84 | cppyy.gbl.sc_core.sc_in_action=True
85 | _load_pythonization_lib()
86 | return True
87 | return False
88 |
89 | def _load_systemc_scv():
90 | if 'SCV_HOME' in os.environ:
91 | add_sys_include_path(os.path.join(os.environ['SCV_HOME'], 'include'))
92 | for l in ['lib', 'lib64', 'lib-linux', 'lib-linux64']:
93 | for f in ['libscv.so']:
94 | full_file = os.path.join(os.environ['SCV_HOME'], l, f)
95 | if os.path.isfile(full_file):
96 | cppyy.load_library(full_file)
97 | cppyy.include("cci_configuration")
98 | cci_loaded=True
99 | return True
100 | return False
101 |
102 | def _load_systemc_cci():
103 | for home_dir in ['CCI_HOME', 'SYSTEMC_HOME']:
104 | if home_dir in os.environ:
105 | if os.path.exists(os.path.join(os.environ[home_dir], 'include', 'cci_configuration')):
106 | add_sys_include_path(os.path.join(os.environ[home_dir], 'include'))
107 | for l in ['lib', 'lib64', 'lib-linux', 'lib-linux64']:
108 | for f in ['libcciapi.so']:
109 | full_file = os.path.join(os.environ[home_dir], l, f)
110 | if os.path.isfile(full_file):
111 | cppyy.load_library(full_file)
112 | cppyy.include("cci_configuration")
113 | cci_loaded=True
114 | return True
115 | return False
116 |
117 | def _load_pythonization_lib(debug = False):
118 | plat_info = get_paths()
119 | # check for standard search path
120 | for key in plat_info:
121 | plat_dir =plat_info[key]
122 | if os.path.isdir(plat_dir):
123 | if debug: logging.debug("Checking for pythonization lib in platform dir %s"%plat_dir)
124 | for file in os.listdir(plat_dir):
125 | if re.match(r'pysyscsc.*\.so', file):
126 | cppyy.load_library(os.path.join(plat_dir, file))
127 | full_path = os.path.join(plat_dir, '../../../include/site/python%d.%d/PySysC/PyScModule.h' % sys.version_info[:2])
128 | if debug: logging.debug('found %s, looking for %s'%(file, full_path))
129 | if full_path and os.path.isfile(full_path):
130 | cppyy.include(full_path)
131 | return
132 | # check site packages first to check for venv
133 | for site_dir in site.getsitepackages():
134 | if os.path.isdir(site_dir):
135 | if debug: logging.debug("Checking for pythonization lib in site package dir %s"%site_dir)
136 | for file in os.listdir(site_dir):
137 | if re.match(r'pysyscsc.*\.so', file):
138 | cppyy.load_library(os.path.join(site_dir, file))
139 | full_path = find_file('PyScModule.h', site.PREFIXES)
140 | if debug: logging.debug('found %s, looking at %s for %s'%(file, site.PREFIXES, full_path))
141 | if full_path and os.path.isfile(full_path):
142 | cppyy.include(full_path)
143 | return
144 | if site.ENABLE_USER_SITE:
145 | #check user site packages (re.g. ~/.local)
146 | user_site_dir = site.getusersitepackages()
147 | if os.path.isdir(user_site_dir):
148 | if debug: logging.debug("Checking for pythonization lib in user site dir %s"%user_site_dir)
149 | for file in os.listdir(user_site_dir):
150 | if re.match(r'pysyscsc.*\.so', file):
151 | cppyy.load_library(os.path.join(user_site_dir, file))
152 | user_base = site.USER_BASE
153 | full_path = user_base + '/include/python%d.%d/PySysC/PyScModule.h' % sys.version_info[:2]
154 | if debug: logging.debug('found %s, looking at %s for %s'%(file, user_base, full_path))
155 | if os.path.isfile(full_path):
156 | cppyy.include(full_path)
157 | return
158 | # could not be found in install, maybe development environment
159 | pkgDir = os.path.join(os.path.dirname( os.path.realpath(__file__)), '..')
160 | if os.path.isdir(pkgDir):
161 | if debug: logging.debug("Checking for pythonization lib in source dir %s"%pkgDir)
162 | for file in os.listdir(pkgDir):
163 | if re.match(r'pysyscsc.*\.so', file):
164 | cppyy.load_library(os.path.join(pkgDir, file))
165 | full_path = os.path.join(pkgDir, 'PyScModule.h')
166 | if full_path and os.path.isfile(full_path):
167 | cppyy.include(full_path)
168 | return
169 | sys.exit("No Pythonization found")
170 |
171 | def add_library(header, lib, project_dir=None):
172 | lib_path = lib
173 | if(project_dir is not None):
174 | for root, dirs, files in os.walk(project_dir):
175 | if lib in files:
176 | lib_path = os.path.join(root, lib)
177 | break
178 | buf = io.StringIO()
179 | with redirect_stdout(buf), redirect_stderr(buf):
180 | cppyy.load_library(lib_path)
181 | cppyy.include(header)
182 | return buf.getvalue()
183 |
184 | def add_include_path(incl):
185 | includeDirs.add(incl)
186 | cppyy.add_include_path(incl)
187 |
188 | def add_sys_include_path(incl):
189 | sysIncludeDirs.add(incl)
190 | cppyy.add_include_path(incl)
191 |
192 | # prepare a pythonizor
193 | def _pythonizor(clazz, name):
194 | # A pythonizor receives the freshly prepared bound C++ class, and a name stripped down to
195 | # the namespace the pythonizor is applied. Also accessible are clazz.__name__ (for the
196 | # Python name) and clazz.__cpp_name__ (for the C++ name)
197 | if name == 'sc_time':
198 | clazz.__repr__ = lambda self: repr(self.to_string())
199 | clazz.__str__ = lambda self: self.to_string()
200 | elif name in ['sc_object', 'sc_module']:
201 | clazz.__repr__ = lambda self: repr(self.name())
202 | elif len(name) > 8 and name[:7] == 'sc_port<':
203 | clazz.__repr__ = lambda self: repr(self.name())
204 | elif len(name) > 10 and name[:9] == 'sc_export<':
205 | clazz.__repr__ = lambda self: repr(self.name())
206 |
207 | # install the pythonizor as a callback on namespace 'sc_core' (default is the global namespace)
208 | cppyy.py.add_pythonization(_pythonizor, 'sc_core')
209 |
210 | # reflection methods
211 | def get_members(sc_object):
212 | def is_cpp_data_type(name, module):
213 | matches = [x for x in ['int', 'char', 'float', 'double'] if name == x]
214 | if len(matches) > 0 or module[:10] == "cppyy.gbl.":
215 | return True
216 | else:
217 | return False
218 |
219 | members = [(e, getattr(sc_object, e)) for e in dir(sc_object)]
220 | return [(k,v) for k,v in members if is_cpp_data_type(type(v).__name__, type(v).__module__)]
221 |
222 | def get_methods(sc_object):
223 | members = [(e, getattr(sc_object, e)) for e in dir(sc_object)]
224 | return [(k,v) for k,v in members if type(v).__name__=='CPPOverload']
225 |
226 | def get_ports(module):
227 | res = []
228 | for elem in dir(module):
229 | attr=getattr(module, elem)
230 | if isinstance(attr, cppyy.gbl.sc_core.sc_port_base) and not isinstance(attr, cppyy.gbl.tlm.tlm_base_socket_if):
231 | res.append(attr)
232 | return res
233 |
234 | def get_exports(module):
235 | res = []
236 | for elem in dir(module):
237 | attr=getattr(module, elem)
238 | if isinstance(attr, cppyy.gbl.sc_core.sc_export_base) and not isinstance(attr, cppyy.gbl.tlm.tlm_base_socket_if):
239 | res.append(attr)
240 | return res
241 |
242 | def get_initiator_sockets(module):
243 | res = []
244 | for elem in dir(module):
245 | attr=getattr(module, elem)
246 | if isinstance(attr, cppyy.gbl.sc_core.sc_port_base) and isinstance(attr, cppyy.gbl.tlm.tlm_base_socket_if):
247 | res.append(attr)
248 | return res
249 |
250 | def get_target_sockets(module):
251 | res = []
252 | for elem in dir(module):
253 | attr=getattr(module, elem)
254 | if isinstance(attr, cppyy.gbl.sc_core.sc_export_base) and isinstance(attr, cppyy.gbl.tlm.tlm_base_socket_if):
255 | res.append(attr)
256 | return res
257 |
258 | def get_submodules(module):
259 | res = []
260 | for elem in dir(module):
261 | attr=getattr(module, elem)
262 | if isinstance(attr, cppyy.gbl.sc_core.sc_module):
263 | res.append(attr)
264 | return res
265 |
266 | import time
267 |
268 | class timewith():
269 | def __init__(self, name=''):
270 | self.name = name
271 | self.start = time.time()
272 |
273 | @property
274 | def elapsed(self):
275 | return time.time() - self.start
276 |
277 | def checkpoint(self, name=''):
278 | return '{timer} {checkpoint} took {elapsed} seconds'.format(timer=self.name, checkpoint=name, elapsed=self.elapsed).strip()
279 |
280 | def __enter__(self):
281 | return self
282 |
283 | def __exit__(self, mytype, value, traceback):
284 | print(self.checkpoint('finished'))
285 | pass
286 |
--------------------------------------------------------------------------------