www.learnsystemc.com
を試していく。まずはHello Worldから。
Hello World
https://www.learnsystemc.com/basic/hello_world
このページのサンプルコードをhello.ccとして保存する。Makefileを用意する。
include Makefile.config PROJECT = hello OBJS = $(PROJECT).o include Makefile.rules
Makefile.config, Makefile.rules は systemc インストールディレクトリの examplesの下にあるものを使う。
これで make を実行し、 ./hello.x を実行すると、以下のように正しく動作しているようだ。
$ ./hello.x SystemC 3.0.0_pub_rev_20231124-Accellera --- Feb 18 2024 18:43:12 Copyright (c) 1996-2023 by all Contributors, ALL RIGHTS RESERVED Hello world using approach 1 Hello world using approach 2
ソースコードを見ていく。
hello1() については完全なC++標準なので特に特筆すべき点はない。
C++のエントリーポイントはmain関数だが、SystemCのエントリーポイントはsc_main関数である。
SystemCのモジュールはsc_moduleベースクラスを継承したものである。
骨組みのみを抜き出すと以下の通り。
#include <systemc> using namespace sc_core; struct HelloWorld : sc_module {}; int sc_main(int, char*[]) { HelloWorld helloworld("helloworld"); sc_start(); return 0; }
中身については次のチャプターで議論する。
SystemC Module
https://www.learnsystemc.com/basic/module
SystemCのモジュールはsc_moduleクラスを継承するクラスであり、Verilogのモジュールと同様の機能を持つ。
SystemCモジュールの定義は以下の3通りがある。
- SC_MODULE(module_name) {}: マクロによる定義。2.のシンタックスシュガー
- struct module_name: public sc_module {}: C++文法に基づく定義であり、1よりreadableである。
- class module_name : public sc_module { public: }: コンストラクタをpublicにしなければならないときはこうする。
SystemCモジュールは以下の注意点がある。
Constructor: SC_CTOR
https://www.learnsystemc.com/basic/sc_ctor
SC_CTORマクロはコンストラクタ定義のシンタックスシュガーであり、
SC_CTOR(MODULE_A) {}
のような使い方をする。
sc_module_nameパラメータ以外のパラメータをコンストラクタに渡したい場合はSC_CTORマクロは使えず、
MODULE_C(sc_module_name name, int i) : sc_module(name), i(i) {}
のような書き方をする。
補注:最新のIEEE 1666-2023規格ではSC_CTORにsc_module_name以外の追加のパラメータを入れることができるようになった。
https://systemc.org/events/scef202309/ の SystemC IEEE 1666 update のプレゼンテーション p.18 を参照。
実際に Systemc-3.0 で動くか試してみる。サンプルコード中、
SC_CTOR(MODULE_C); MODULE_C(sc_module_name name, int i) : sc_module(name), i(i) {
を以下のように書き換えてコンパイルする。
SC_CTOR(MODULE_C, int i) : i(i) {
make して実行すると、正しく動くことが確認できた。
$ ./hello.x SystemC 3.0.0_pub_rev_20231124-Accellera --- Feb 18 2024 18:43:12 Copyright (c) 1996-2023 by all Contributors, ALL RIGHTS RESERVED module_a module_b module_c, i = 1
SC_HAS_PROCESS
https://www.learnsystemc.com/basic/sc_has_process
SC_HAS_PROCESSはsc_module_name以外のパラメータをとるコンストラクタのためのマクロのようだ。
SC_HAS_PROCESSはSystemC v2.0で導入された。SC_CTORと比較してみよう。
#define SC_CTOR(user_module_name) typedef user_module_name SC_CURRENT_USER_MODULE; user_module_name( ::sc_core::sc_module_name ) #define SC_HAS_PROCESS(user_module_name) typedef user_module_name SC_CURRENT_USER_MODULE
これらの違いは、SC_CTORはコンストラクタ定義に関する記述が末尾にあるのに対して、SC_HAS_PROCESSにはそれがない点である。
SC_CTORとSC_HAS_PROCESSのどちらも現モジュール名をSC_CURRENT_USER_MODULEとして定義しており、SC_METHOD/SC_THREAD/SC_CTHREADを通じてシミュレーションカーネルにメンバー関数を登録する用途で使用される。
推奨される記述スタイルは以下の通り。
- シミュレーションプロセスでないモジュールはSC_CTORやSC_HAS_PROCESSを使用しない。
- コンストラクタに追加のパラメータが必要ない場合はSC_CTORを使用する。
- コンストラクタに追加のパラメータが必要な場合は SC_HAS_PROCESSを使用する。
補注:前チャプターとも関連するが、SC_HAS_PROCESSは最新のIEEE1666-2023ではdeprecatedとなった。
サンプルコードをコンパイルすると以下のようなエラーが出る。
systemc-3.0.0_pub_rev_20231129/include/sysc/kernel/sc_module.h:423:32: error: ‘sc_core::sc_has_process_used’ is deprecated: SC_HAS_PROCESS(user_module_name) is obsolete in IEEE 1666-2023, define SC_ALLOW_DEPRECATED_IEEE_API to suppress. [-Werror=deprecated-declarations] 423 | static_assert(sc_core::sc_has_process_used, "no-op to avoid stray ';'") | ^~~~~~~~~~~~~~~~~~~
Makefile.configを以下のように修正するとビルドが通る。
#FLAGS_COMMON = -g -Wall -std=c++17 FLAGS_COMMON = -g -Wall -std=c++17 -DSC_ALLOW_DEPRECATED_IEEE_API
この修正なしにビルドが通るようにサンプルコードを書き換えてみると以下のようになる。
#include <systemc> using namespace sc_core; SC_MODULE(MODULE_A) { MODULE_A(sc_module_name name) { std::cout << this->name() << ", no SC_CTOR or SC_HAS_PROCESS" << std::endl; } }; SC_MODULE(MODULE_B1) { SC_CTOR(MODULE_B1) { SC_METHOD(func_b); } void func_b() { std::cout << name() << ", SC_CTOR" << std::endl; } }; SC_MODULE(MODULE_C) { const int i; SC_CTOR(MODULE_C, int i) : i(i) { SC_METHOD(func_c); } void func_c() { std::cout << name() << ", additional input argument" << std::endl; } }; SC_MODULE(MODULE_D1) { SC_CTOR(MODULE_D1); void func_d() { std::cout << this->name() << ", SC_CTOR inside header, constructor defined outside header" << std::endl; } }; MODULE_D1::MODULE_D1(sc_module_name name) : sc_module(name) { SC_METHOD(func_d); } SC_MODULE(MODULE_E) { MODULE_E(sc_module_name name); void func_e() { std::cout << this->name() << ", SC_HAS_PROCESS outside header, CANNOT use SC_CTOR" << std::endl; } }; MODULE_E::MODULE_E(sc_module_name name) { SC_METHOD(func_e); } int sc_main(int, char*[]) { MODULE_A module_a("module_a"); MODULE_B1 module_b1("module_b1"); MODULE_C module_c("module_c", 1); MODULE_D1 module_d1("module_d1"); MODULE_E module_e("module_e"); sc_start(); return 0; }