無償ツールで実践する「ハード・ソフト協調検証」(2) ―― テスト・プログラムはC言語で書く
リスト1(a)では,C言語コードのc_main関数を呼ぶためにimport 宣言を行っています.C言語コードのc_main関数内でSystemVerilogコード内のタスク(この場合はwrite_byte_busまたはread_byte_busを呼び出すコード)を実行するために,taskとしています.C言語コードからSystemVerilogコードのタスク(write_byte_bus,read_byte_bus)を呼び出すために,export宣言を行っています."DPI-C"とtaskの間にあるread_byte_bus = とwrite_byte_bus = の部分は,C言語コード内で使うときの関数名を指定しています.DPI-Cの宣言以外は,普通のSystemVerilog コードです.
リスト1(b)のc_main関数はSystemVerilogコード内のimport宣言でtaskとしたので,戻り値の型はint,戻り値は常に0としています.c_main関数内では,アドレス(0x2000)に対して0xdeをwrite_byte_bus関数でライト,read_byte_bus関数でリードした後に,ライトしたデータ(b_data)とリードしたデータ(b_exp)の比較を行っています.write_byte_bus関数は二つの引き数(addrとdata)を取り, 戻り値はvoidになります.また,read_byte_bus関数は二つの引き数(addrとdataへのポインタ)を取り,戻り値はvoidになります.
SystemVerilogコードのタスクにアクセスする場合は,C言語コードでは戻り値が必ずvoidになります.そのため,SystemVerilogコードからデータを返してもらいたいときは,read_byte_bus関数の第2 引き数のようにポインタ渡しとします.
リスト1(b)のread_byte_bus関数のように引き数のポインタを渡すのではなく,関数の戻り値とした方がコードとしてすっきりする場合が多々あります.そのようなときは,リスト2(a)のようにラッパ関数を定義します.ラッパ関数内で,ポインタへのアクセスに変換します(write_byte_bus関数ではラッパ関数は必要ないが,関数を同じような形にするために定義している).そして,リスト2(b)のようなラッパ関数のヘッダ・ファイルを作成し,このラッパ関数のヘッダ・ファイルをインクルードします.リスト2(c)のようにラッパ関数を呼び出すことで,関数の戻り値を使うことができます.こうすることで,すっきりしたコードになり,実機のテスト・プログラムと同じようなコードになります.
read_byte_bus( addr, &data );
リスト2 ラッパ関数
(a) ラッパ関数の定義ファイル(sv_wrapper.h)
void write_byte( unsigned int addr, unsigned int data )
{
write_byte_bus( addr, data );
}
unsigned int read_byte( unsigned int addr )
{
unsigned int data
return data;
}
(b) ラッパ関数のヘッダ・ファイル(sv_wrapper.c)
unsigned int read_byte( unsigned int addr );
(c) ラッパ関数を用いたC言語コード #include "sv_wrapper.h" int c_main( void ) write_byte( addr, b_data );
{
unsigned int addr;
unsigned char b_data, b_exp;
addr = 0x2000;
b_data = 0xde;
b_exp = read_byte( addr );
if( b_data != b_exp )
printf("compare error, BYTE : addr = 0x%08x, data = 0x%02x/0x%02x\n",
addr, b_data, b_exp );
return 0;
}
(第3回へ続く)
Verification Enginnerの戯言
http://blogs.yahoo.co.jp/verification_engineer