SystemC は,ハードウェア表現に特化した言語ではなく,C++ +ライブラリで実現されているため,記述容易性において様々な問題があります.
scpp は,そのような SystemC の記述性改善を目的としたプリプロセッサです.以下の機能を持っています.
-
モジュール接続の自動化: モジュール間の信号接続を,ルールに従って自動的に結線します.Emacs の Verilog モードの
AutoConnect
と同等の機能です. また必要な中間信号を自動的に生成します. -
SC_METHOD()
,SC_THREAD()
,SC_CTHREAD()
記述分離の抑制: SystemC では,これらの記述はSC_CTOR()
に記述しなければならず,関数本体から分離して記述しなければなりませんが,scpp では,関数本体の直前に記述することができます. -
sc_trace()
記述の自動生成: 有償ツールなどを使わない限り,SystemC で信号ダンプしたい場合は,ダンプしたい信号は階層名を含めて手動で指定する必要がありますが,それを自動化します. -
メンバイニシャライザによる信号名設定の自動生成:
sc_trace()
で,波形ダンプに正確な信号名を表示するためには,ポート・信号に信号名を設定しなければなりませんが,これを自動化します. -
SC_METHOD()
のセンシティビティリスト自動生成: Verilog-HDL ではalways@( * )
表記でセンシティビティリストを省略できますが,scpp でこれを実現します. -
テストベンチ記述の省力化:DUT をインスタンス化するスタブ記述作成を省力化します.
C++ ソースコードに埋め込まれたディレクティブ ($ScppInstance
等) を置換することで,上記のことを実現します.それ以外の記述は一切変更しません.
git clone https://github.com/yoshinrt/scpp.git
cd sample
make SYSTEMC=path_to_systemc_root
で,サンプルの SystemC モジュールの sim を行うことができます.また,*.scpp.cpp / *.scpp.h を元に,*.cpp / *.h が生成されます.
scpp による変更前後のファイルを比較 (コミット e2de8eb,もしくは diff sample/SimpleDma.scpp.h sample/SimpleDma.h
) することで,どのような記述が自動生成されたかを確認できます.
scpp.pl [-I<include path>] [-D<name>[=<definition>]] [-o <output file>]
[-v] [--clean] <input file>
-I<include path>
: インクルードファイルのサーチパスの末尾に<include path>
を追加します.-D<name>[=<definition>]
:<name>
をマクロとして<definition>
に定義します.<definition>
が省略された場合,1 に定義されます.-o <output file>
: 出力ファイル名を指定します.省略時は<input file>
が<input file>.bak
にリネームされた後,<input file>
に上書きされます.-v
: 自動認識したポートやシグナル等の情報を<src_file>.list
に出力します.--clean
: scpp.pl が自動生成した記述を削除します.<input file>
: 入力ファイル名を指定します.
C++ ソースコードにディレクティブを記述するには,以下のいずれかの形式を使用します.$ScppSomeDirective
は,具体的には $ScppInstance
等を記述します.使用できるディレクティブについては scpp ディレクティブ 一覧 を参照してください.
- 1 行,Begin ~ End なし
// $ScppSomeDirective( <ディレクティブ引数> ... )
- 1 行,Begin ~ End あり
// $ScppSomeDirective( <ディレクティブ引数> ... ) Begin
<C++ code> ...
// $ScppEnd
- 複数行,Begin ~ End なし
/* $ScppSomeDirective(
<ディレクティブ引数> ...
) */
- 複数行,Begin ~ End あり
/* $ScppSomeDirective(
<ディレクティブ引数> ...
) Begin */
<C++ code> ...
// $ScppEnd
ディレクティブは,C++ コメントとして記述します.
ディレクティブ引数がない,または省略する場合は,( ) ごと省略することができます.
ディレクティブ引数等を複数行に分けて記述する場合は,/* ... */
形式のコメントを使用する必要があります.//
形式のコメントで複数行に分けることはできません.
scpp は,ディレクティブにより自動生成した C++ コードを Begin ... $ScppEnd
の間に出力します.scpp 処理前に Begin ... $ScppEnd
間に記述されていたコードは一旦削除されます.また Begin ... $ScppEnd
が記述されていない場合,scpp により自動的に追加されます.
scpp は C プリプロセッサ (cpp) を内蔵しており,scpp は C++ ソースコードを解析時 (例えば,モジュールのポート解析) は,内蔵 cpp を通してから処理されます.したがって以下の制限があります.
systemc.h
をインクルード時は<...>
を使用して#include <systemc.h>
と記述してください.scpp は,<...>
を使用したinclude
は無視することで,SC_MODULE
等のマクロが展開されることを抑制しています.- 同様に,システムインクルードヘッダ (
stdio.h
等) は<...>
で記述してください. #ifdef
等でソースコードが切り替えられている場合,scpp 実行時の define 状況で処理されます.scpp 処理後に define 状態が変更された場合,scpp により自動生成されたコードと一致しない場合があります.- 上記のような制限があるため,パラメタライズ設計を行うときは,極力 define による定義ではなく,C++ テンプレート等の cpp マクロ展開されない手法で実施することを推奨します.
既知の課題については こちら を参照してください.
まともな C++ パーザは実装してませんので,ちょっと凝った記述をするだけでまともに動作しません.
- $ScppAutoMember
- $ScppAutoMemberSim
- $ScppCthread
- $ScppFunction
- $ScppInitializer
- $ScppInstance
- $ScppMethod
- $ScppSensitive
- $ScppSigTrace
- $ScppThread
必要な信号,モジュールへのポインタ変数,プロトタイプ宣言を出力します.
$ScppAutoMember
引数はありません.
$ScppInstance で自動生成された信号 及び SC_MODULE
へのポインタ変数,
$ScppMethod,
$ScppThread,
$ScppCthread,
$ScppFunction
が記述されたメンバ関数のプロトタイプ宣言を出力します.
詳細はそれぞれの解説を参照してください.
// $ScppAutoMember
出力結果
// $ScppAutoMember Begin
sc_signal<sc_uint<32> > SrcAddr;
sc_signal<sc_uint<32> > DstAddr;
sc_signal<sc_uint<32> > XferCnt;
sc_signal<bool> Run;
sc_signal<bool> Done;
sc_signal<bool> NceCh[CH_NUM];
sc_signal<sc_uint<32> > RegRDataCh[CH_NUM];
sc_signal<sc_uint<32> > SrcAddrCh[CH_NUM];
sc_signal<sc_uint<32> > DstAddrCh[CH_NUM];
sc_signal<sc_uint<32> > XferCntCh[CH_NUM];
sc_signal<bool> RunCh[CH_NUM];
sc_signal<bool> DoneCh[CH_NUM];
SimpleDmaCore *u_SimpleDmaCore;
SimpleDmaReg *u_SimpleDmaReg[CH_NUM];
void AddrDecorder( void );
void ArbiterSelector( void );
void RDataSelector( void );
// $ScppEnd
シミュレーションテストベンチ用に,必要な信号,モジュールへのポインタ変数,プロトタイプ宣言を出力します.
$ScppAutoMemberSim
引数はありません.
$ScppAutoMember と下記を除き同一の機能です.詳細については $ScppAutoMember を参照してください.
$ScppAutoMember との違いは,以下のとおりです.
sc_in / sc_out / sc_inout
の代わりにsc_signal
が生成されます.sc_fifo_in / sc_fifo_out / sc_fifo_inout
の代わりにsc_fifo
が生成されます.
$ScppAutoMemberSim
はテストベンチ記述において,DUT のポートと接続するための sc_signal
記述を自動的に生成することを意図しています.
// $ScppAutoMemberSim
出力結果
// $ScppAutoMemberSim Begin
sc_signal<bool> nrst;
sc_signal<sc_uint<32> > RegAddr;
sc_signal<sc_uint<32> > RegWData;
sc_signal<bool> RegNce;
sc_signal<bool> RegWrite;
sc_signal<sc_uint<32> > RegRData;
sc_signal<sc_uint<32> > SramAddr;
sc_signal<sc_uint<32> > SramWData;
sc_signal<bool> SramNce;
sc_signal<bool> SramWrite;
sc_signal<sc_uint<32> > SramRData;
SimpleDma<8> *SimpleDma0;
// $ScppEnd
信号の name を設定するメンバイニシャライザ記述を出力します.
$ScppInitializer[( <char> )]
char
: 出力する区切り文字等を文字列で指定します.- 文字列に
:
が含まれる場合,初期化リストの先頭に:
を出力します.ただし,初期化リストが何もないときは,何も出力されません. - 文字列に
,
が含まれる場合,初期化リストの最後に,
を出力します.ただし,初期化リストが何もないときは,何も出力されません. ":,"
のように,両方指定することが可能です.
- 文字列に
コンストラクタに指定する,信号の name 初期化のためのメンバイニシャライザ記述を生成します.
SystemC で信号をダンプ (sc_trace()
) し,ダンプファイルで信号名を正しく表示するためには,メンバイニシャライザで信号名を指定する必要がありますが,$ScppInitializer
はそれを自動化します.
認識したすべての sc_in_clk / sc_in / sc_out / sc_inout / sc_signal
のメンバイニシャライザ記述を生成します.
ただし,それらの信号が配列の場合,メンバイニシャライザ記述は生成されません (C++ 仕様による制限).
SC_CTOR( SimpleDma ) :
// $ScppInitializer( ":" )
{
出力結果
SC_CTOR( SimpleDma )
// $ScppInitializer Begin
: clk( "clk" ),
nrst( "nrst" ),
RegAddr( "RegAddr" ),
RegWData( "RegWData" ),
RegNce( "RegNce" ),
RegWrite( "RegWrite" ),
RegRData( "RegRData" ),
SramAddr( "SramAddr" ),
SramWData( "SramWData" ),
SramNce( "SramNce" ),
SramWrite( "SramWrite" ),
SramRData( "SramRData" ),
SrcAddr( "SrcAddr" ),
DstAddr( "DstAddr" ),
XferCnt( "XferCnt" ),
Run( "Run" ),
Done( "Done" )
// $ScppEnd
{
SC_CTHREAD()
記述を,関数本体の直前に記述することを可能にします.
$ScppCthread( <clock>[, <reset>, <attr>])
clock
: クロックイベントを指定しますreset
: リセット信号を指定しますattr
: リセットの属性を,以下の組み合わせで文字列で指定します"a"
:async_reset_signal_is()
を生成します"s"
:reset_signal_is()
を生成します"p"
: リセット極性を true に設定します"n"
: リセット極性を false に設定します
reset
, attr
を省略時は,async_reset_signal_is()
,reset_signal_is()
記述は生成されません.
SC_CTHREAD()
記述を,関数本体の直前に記述することを可能にします.
SC_CTHREAD()
は SC_CTOR()
内に記述しなければならず,通常は動作を記述した関数本体から離れていますが,これは可読性に問題があります.
$ScppCthread
を関数本体の直前に記述することで,$ScppSensitive
の位置に SC_CTHREAD()
記述を生成します.
また,$ScppAutoMember
の位置に,その関数のプロトタイプ宣言記述を生成します.
// $ScppCthread( clk.pos(), nrst, "an" )
void SimpleDmaReg::RegWriteThread( void ){
出力結果 ($ScppSensitive
)
// $ScppSensitive( "SimpleDmaReg.cpp" ) Begin
SC_CTHREAD( RegWriteThread, clk.pos() );
async_reset_signal_is( nrst, false );
// $ScppEnd
出力結果 ($ScppAutoMember
)
// $ScppAutoMember Begin
void RegWriteThread( void );
// $ScppEnd
メンバ関数のプロトタイプ宣言をヘッダファイルに生成します.
$ScppFunction
引数はありません.
$ScppFunction
を関数本体の直前に記述することで,$ScppAutoMember
の位置に,その関数のプロトタイプ宣言記述を生成します.
このディレクティブは直接 SystemC とは関係ありませんが,$ScppMethod や $ScppCthread 等と同じような感覚で,ヘッダファイルにプロトタイプ宣言記述を生成することができます.
// $ScppFunction
sc_uint<32> Decoder::GaloaLog( sc_uint<32> idx ){
...
}
// $ScppFunction
void Decoder::Compute(
sc_uint<32> *DataBuf,
sc_uint<32>& DataSize
){
...
}
出力結果 ($ScppAutoMember
)
// $ScppAutoMember Begin
sc_uint<32> GaloaLog( sc_uint<32> idx );
void Compute(
sc_uint<32> *DataBuf,
sc_uint<32>& DataSize
);
// $ScppEnd
SystemC モジュールをインスタンスし,自動的に結線します.また必要な信号を自動生成します.
$ScppInstance( <submodule>, <instance>, <file> [, <regexp> ...])
submodule
: インスタンス化するサブモジュール名を指定します.instance
: インスタンス化するサブモジュールのインスタンス名を指定します.file
: サブモジュール名が記述されたファイルを指定します.ファイル名に "." を指定すると,$ScppInstance
が記述されたファイル自身を指定します.regexp
: ポート⇔信号 結線ルールを指定します.
SystemC モジュールをインスタンスし,自動的に結線します.また必要な信号を自動生成します.
現在のところ,自動接続可能なポートは sc_(in|out|inout)
sc_(in|out|inout)_clk
sc_fifo_(in|out|inout)
に限られます.
regexp
に指定されたルールに従い,サブモジュールのポートをモジュールの信号名に変換します.regexp
の書式は以下のとおりです.
"/port/signal/option"
port
には perl 正規表現を使用できます.regexp
が複数記述されている場合,ルールの一番目から順番に port
にマッチするかどうかが照合され,最初にマッチしたルールが採用されます.記述容易性のため,port
には先頭に '^',末尾に '$' が自動的に付加されます.
- 例:
clka
clkb
もマッチさせるためには,clk.*
と記述する必要があります.
signal
は,そのポートに接続する信号名を指定します.port
でグルーピング (...)
を使用した場合,$1
等の後方参照が使用できます.
- 例:
"/clk(.*)/CLK$1/"
…clka
ポートがCLKa
信号に接続されます.
すべてのルールにマッチしなかった場合,ポート名と同名の信号に接続されます.
option
には次の文字列をいくつか指定します.option
は省略可能です.
I
: 接続された信号を強制的にsc_in
にしますO
: 接続された信号を強制的にsc_out
にしますIO
: 接続された信号を強制的にsc_inout
にしますW
: 接続された信号を強制的にsc_signal
にしますNC
: この出力ポートが浮きポートであることを宣言します.実際にはダミーの sc_signal が生成され,それに接続されます.d
: このルールにマッチしたポートは,自動結線の対象から外されます.
port
は省略可能です.省略された場合,^(.*)$
と記述したとみなされます.
signal
は省略可能です.省略された場合,port
と同名の信号に接続されます.
正規表現の区切り記号である /
は別の記号でも記述可能であり,regexp
の先頭の文字を区切り文字と認識します.例えば,"/hoge.*/fuga/" と記述した場合,*/
の部分で複数行コメントの終わりと認識されてしまうため,正常にパースできません.この場合,"@hoge.*@fuga@"
等,別の記号を使用する必要があります.
$ScppInstance
が記述されたモジュールのすべての $ScppInstance
を処理し終えた後,次のルールに従って信号が生成され,$ScppAutoMember
の場所に出力します.
- モジュール内に既に
sc_in
等の信号の宣言が存在する場合: 信号は生成されません option
でI
,O
等の指定がある場合: その指定に従って信号が生成されますsc_in
,sc_out
両方に接続されている場合 (例えば,submodule_a の sc_in と submodule_b の sc_out に接続されている場合):sc_signal
が生成されますsc_in
のみに接続されている場合:sc_in
が生成されますsc_out
のみに接続されている場合:sc_out
が生成されます
サブモジュールのポートが多次元配列の場合,同次元・同サイズの信号に接続されます.つまり,u_Inst.port[ n ] -> signal[ n ]
のように接続されます.
instance
には配列添字を指定することができ,この場合,インスタンス配列を生成します.下記の例では,8 個の Module モジュールがインスタンス化されます.
例: $ScppInstance( Module, u_Inst[8], ... )
またこのとき,結線ルールの signal
の末尾に []
を指定することが出来ます.この場合,信号の配列が生成され,u_Inst[ n ].port -> signal[ n ]
に接続されます.さらに port が多次元配列の場合,u_Inst[ n ].port[ m ] -> signal[ n ][ m ]
のように接続されます.
/* $ScppInstance(
SimpleDmaReg, u_SimpleDmaReg[ CH_NUM ], "SimpleDmaReg.h",
"/clk|nrst//",
"/(Addr|WData|Write)/Reg$1/",
"/(RData)/Reg$1Ch[]/W",
"//$1Ch[]/W",
) */
出力結果 ($ScppInstance
)
/* $ScppInstance(
SimpleDmaReg, u_SimpleDmaReg[ CH_NUM ], "SimpleDmaReg.h",
"/clk|nrst//",
"/(Addr|WData|Write)/Reg$1/",
"/(RData)/Reg$1Ch[]/W",
"//$1Ch[]/W",
) Begin */
for( int _i_0 = 0; _i_0 < CH_NUM; ++_i_0 ){
u_SimpleDmaReg[_i_0] = new SimpleDmaReg(( std::string( "u_SimpleDmaReg(" ) + std::to_string(_i_0) + ")" ).c_str());
u_SimpleDmaReg[_i_0]->clk( clk );
u_SimpleDmaReg[_i_0]->nrst( nrst );
u_SimpleDmaReg[_i_0]->Addr( RegAddr );
u_SimpleDmaReg[_i_0]->WData( RegWData );
u_SimpleDmaReg[_i_0]->Nce( NceCh[_i_0] );
u_SimpleDmaReg[_i_0]->Write( RegWrite );
u_SimpleDmaReg[_i_0]->RData( RegRDataCh[_i_0] );
u_SimpleDmaReg[_i_0]->SrcAddr( SrcAddrCh[_i_0] );
u_SimpleDmaReg[_i_0]->DstAddr( DstAddrCh[_i_0] );
u_SimpleDmaReg[_i_0]->XferCnt( XferCntCh[_i_0] );
u_SimpleDmaReg[_i_0]->Run( RunCh[_i_0] );
u_SimpleDmaReg[_i_0]->Done( DoneCh[_i_0] );
}
// $ScppEnd
出力結果 ($ScppAutoMember
)
// $ScppAutoMember Begin
SimpleDmaReg *u_SimpleDmaReg[CH_NUM];
// $ScppEnd
SC_METHOD()
記述を,関数本体の直前に記述することを可能にします.
$ScppMethod[( code )]
code
: センシティビティリストを表現する C++ コードを記述します
SC_METHOD()
記述を,関数本体の直前に記述することを可能にします.
SC_METHOD()
は SC_CTOR()
内に記述しなければならず,通常は動作を記述した関数本体から離れていますが,これは可読性に問題があります.
$ScppMethod
を関数本体の直前に記述することで,$ScppSensitive
の位置に SC_METHOD()
記述を生成します.
また,$ScppAutoMember
の位置に,その関数のプロトタイプ宣言記述を生成します.
引数省略時は,その関数内で .read()
されている信号をすべて使用して,センシティビティリストを自動的に生成します.
// $ScppMethod
void SimpleDma::AddrDecorder( void ){
// (...省略...)
/* $ScppMethod(
for( int i = 0; i < CH_NUM; ++i ){
sensitive << DstAddrCh[i] << RunCh[i] << SrcAddrCh[i] << XferCntCh[i];
}
sensitive << Done;
)*/
void SimpleDma::ArbiterSelector( void ){
出力結果 ($ScppSensitive
)
// $ScppSensitive( "." ) Begin
SC_METHOD( AddrDecorder );
sensitive << RegAddr << RegNce;
SC_METHOD( ArbiterSelector );
for( int i = 0; i < CH_NUM; ++i ){
sensitive << DstAddrCh[i] << RunCh[i] << SrcAddrCh[i] << XferCntCh[i];
}
sensitive << Done;
// $ScppEnd
出力結果 ($ScppAutoMember
)
// $ScppAutoMember Begin
void AddrDecorder( void );
void ArbiterSelector( void );
// $ScppEnd
$ScppMethod,$ScppThread,$ScppCthread で記述されたセンシティビティリストを出力します.
$ScppSensitive( <file> [, <file> ...])
file
:$ScppMethod, $ScppThread, $ScppCthread
が記述されたファイルを指定します.ファイル名に "." を指定すると,$ScppSensitive
が記述されたファイル自身を指定します.
$ScppMethod,$ScppThread,$ScppCthread で記述されたセンシティビティリストを出力します.
SC_METHOD() SC_TREAD() SC_CTHREAD()
は SC_CTOR()
内に記述しなければならず,通常は動作を記述した関数本体から離れていますが,これは可読性に問題があります.
$ScppSensitive
を SC_CTOR()
内に記述することで,指定された file から $ScppMethod,$ScppThread,$ScppCthread を検索し,センシティビティリスト記述を $ScppSensitive
の位置に生成します.
// $ScppSensitive( "." )
出力結果
// $ScppSensitive( "." ) Begin
SC_METHOD( AddrDecorder );
sensitive << RegAddr << RegNce;
SC_METHOD( ArbiterSelector );
for( int i = 0; i < CH_NUM; ++i ){
sensitive << DstAddrCh[i] << RunCh[i] << SrcAddrCh[i] << XferCntCh[i];
}
sensitive << Done;
SC_METHOD( RDataSelector );
for( int i = 0; i < CH_NUM; ++i ) sensitive << RegRDataCh[i];
// $ScppEnd
SC_THREAD()
記述を,関数本体の直前に記述することを可能にします.
$ScppThread( code )
code
: センシティビティリストを表現する C++ コードを記述します
SC_THREAD()
記述を,関数本体の直前に記述することを可能にします.
SC_THREAD()
は SC_CTOR()
内に記述しなければならず,通常は動作を記述した関数本体から離れていますが,これは可読性に問題があります.
$ScppThread
を関数本体の直前に記述することで,$ScppSensitive
の位置に SC_THREAD()
記述を生成します.
また,$ScppAutoMember
の位置に,その関数のプロトタイプ宣言記述を生成します.
// $ScppThread( sensitive << clk.pos())
void SimpleDma::ArbiterSelector( void ){
出力結果 ($ScppSensitive
)
// $ScppSensitive( "." ) Begin
SC_THREAD( ArbiterSelector );
sensitive << clk.pos();
// $ScppEnd
出力結果 ($ScppAutoMember
)
// $ScppAutoMember Begin
void ArbiterSelector( void );
// $ScppEnd
そのモジュール内の信号の sc_trace()
記述を生成します.
$ScppSigTrace[( <regexp> ... )]
regexp
: トレース対象,または除外する信号のルール (正規表現) を指定します.引数が省略された場合,モジュール内のすべての信号がトレースされます.
そのモジュール内の信号の sc_trace()
記述を生成します.ただし SystemC の制限により,sc_fifo
はトレースできません.
グローバル変数として sc_trace_file *ScppTraceFile
が定義されていることを前提としています.またこのモジュールがインスタンス化される前に ScppTraceFile
は sc_create_vcd_trace_file()
されていなければなりません.
#ifdef VCD_WAVE
していますので,VCD 出力するためには VCD_WAVE
が define されている必要があります.
regexp
に指定されたルールに従い,トレース対象または除外する信号が決定されます.regexp
の書式は以下のとおりです.
"/signal/option"
signal
には perl 正規表現を使用できます.regexp
が複数記述されている場合,ルールの一番目から順番に signal
にマッチするかどうかが照合され,最初にマッチしたルールが採用されます.記述容易性のため,signal
には先頭に '^',末尾に '$' が自動的に付加されます.
- 例:
clka
clkb
もマッチさせるためには,clk.*
と記述する必要があります.
すべてのルールにマッチしなかった信号は,トレース対象と判定されます.
option
には次の文字列をいくつか指定します.option
は省略可能です.
S
: このルールは,スカラ型の信号にのみ適用されます.A
: このルールは,配列型の信号にのみ適用されます.N
: このルールにマッチした信号は,トレース対象から除外されます.このオプションが指定されなかったルールにマッチした信号は,トレース対象になります.
signal
は省略可能です.省略された場合,.*
と記述したとみなされます.
正規表現の区切り記号である /
は別の記号でも記述可能であり,regexp
の先頭の文字を区切り文字と認識します.例えば,"/hoge.*/" と記述した場合,*/
の部分で複数行コメントの終わりと認識されてしまうため,正常にパースできません.この場合,"@hoge.*@"
等,別の記号を使用する必要があります.
sc_main()
の記述
#ifdef VCD_WAVE
sc_trace_file *ScppTraceFile;
#endif
int sc_main( int argc, char **argv ){
#ifdef VCD_WAVE
ScppTraceFile = sc_create_vcd_trace_file( "simple_dma" );
ScppTraceFile->set_time_unit( 1.0, SC_NS );
#endif
SimpleDma *u_SimpleDma = new SimpleDma( "u_SimpleDma" );
個々のモジュールの記述
#ifdef VCD_WAVE
extern sc_trace_file *ScppTraceFile;
#endif
SC_MODULE( SimpleDma ){
// ...(省略)...
/* $ScppSigTrace(
"/DataBuf/N"
) */
出力結果
// $ScppSigTrace Begin
#ifdef VCD_WAVE
sc_trace( ScppTraceFile, clk, std::string( this->name()) + ".clk" );
sc_trace( ScppTraceFile, nrst, std::string( this->name()) + ".nrst" );
sc_trace( ScppTraceFile, RegAddr, std::string( this->name()) + ".RegAddr" );
sc_trace( ScppTraceFile, RegWData, std::string( this->name()) + ".RegWData" );
sc_trace( ScppTraceFile, RegNce, std::string( this->name()) + ".RegNce" );
sc_trace( ScppTraceFile, RegWrite, std::string( this->name()) + ".RegWrite" );
sc_trace( ScppTraceFile, RegRData, std::string( this->name()) + ".RegRData" );
sc_trace( ScppTraceFile, SramAddr, std::string( this->name()) + ".SramAddr" );
sc_trace( ScppTraceFile, SramWData, std::string( this->name()) + ".SramWData" );
sc_trace( ScppTraceFile, SramNce, std::string( this->name()) + ".SramNce" );
sc_trace( ScppTraceFile, SramWrite, std::string( this->name()) + ".SramWrite" );
sc_trace( ScppTraceFile, SramRData, std::string( this->name()) + ".SramRData" );
sc_trace( ScppTraceFile, SrcAddr, std::string( this->name()) + ".SrcAddr" );
sc_trace( ScppTraceFile, DstAddr, std::string( this->name()) + ".DstAddr" );
sc_trace( ScppTraceFile, XferCnt, std::string( this->name()) + ".XferCnt" );
sc_trace( ScppTraceFile, Run, std::string( this->name()) + ".Run" );
sc_trace( ScppTraceFile, Done, std::string( this->name()) + ".Done" );
#endif // VCD_WAVE
// $ScppEnd