Verification Engineerの戯言
今回は、前回(http://blogs.yahoo.co.jp/verification_engineer/12162656.html)に続いて、
DPI-CとBFMについてです。
2つのポイント、
A)、SystemVerilog側からC言語側を呼び出すとき、
B)、C言語の関数からBFMの外部バスにアクセスするとき、
のB)について、本日は説明します。
C言語の関数からBFMの外部バスにアクセスするには、SystemVerilog側のtaskにて行います。
外部バスへのアクセスをSystemVerilogのtaskは次のようになっているとします。
task bus_read( input int unsigned addr, output int unsigned data );
bus.read( addr, data );
endtask : bus_read
task bus_write( input int unsigned addr, input int unsigned data );
bus.write( addr, data );
endtask : bus_write
bus_readタスクは外部バスへのリードアクセス、bus_writeタスクは外部バスへのライトアクセスに
なります。実際の外部バスのアクセスは、busインターフェース内のbus_read/bus_writeタスクに
任せます。
この2つのタスク(bus_read/bus_write)をC言語側から使えるように次のようにします。
export "DPI-C" task bus_read;
export "DPI-C" task bus_write;
importのときと違って、タスクに対する引数の宣言は必要ありません。
ただし、C言語側での関数のプロトタイプでは、次のように引数の型は必要です。
int bus_read( unsigned int addr, unsigned int *data );
int bus_write( unsigned int addr, unsigned int data );
SystemVerilog側のtaskの引数がinputの場合は値渡しで、outputの場合はポインタ渡しになります。
また、SystemVerilogのタスクをC言語側で使うときは、戻り値は必ずint型になります。
通常の戻り値は"0"です。SystemVerilog側のtaskがdisableされたときは戻り値が"1"です。
(disableは、Verilog HDLからあるもので、disable bus_read; のように使います)。
これでC言語側からSystemVerilog側のtaskが使えるようになりました。
c_main関数内では、つぎのようになります。
int c_main( void )
{
unsigned int addr, data, exp;
addr = 0x00004000;
data = 0xabcdef01;
bus_write( addr, data );
bus_read( addr, &exp );
if( data != exp )
printf("<<ERR>> : mismatch data(0x%x) != exp(0x%x)\n",
data, exp );
return 0;
}
アドレス(0x000040000)にデータ(0xabcdef01)をライト、リードし、
ライトした値とリードした値を比較します。
c_main関数の戻り値は、bus_read/bus_writeと同じようにdisableされたときは"1"になります。
通常の戻り値は"0"です。
c_main関数を実行すると、シミュレーション時間が進むのは、bus_read/bus_writeを実行した部分です。
それ以外の部分ではシミュレーション時間は進みません。
でも、外部バスへのアクセスすること無しにシミュレーション時間を進めたい場合は、
SystemVerilog側で時間を進めるタスクを呼び出せばいいのです。そのためのタスクは
次のようなものでいいでしょう!
export "DPI-C" task bus_nop;
task bus_nop( input int n );
for( int i=0 ; i<n ; i++ )
@(posedge CLK);
endtask : bus_nop
このタスクでは、指定したクロック数だけシミュレーション時間を進めます。
このタスクを使って、C言語側からアクセスします。
int bus_nop( int n );
int c_main( void )
{
unsigned int addr, data, exp;
addr = 0x00004000;
data = 0xabcdef01;
bus_write( addr, data );
bus_nop( 10 );
bus_read( addr, &exp );
if( data != exp )
printf("<<ERR>> : mismatch data(0x%x) != exp(0x%x)\n",
data, exp );
return 0;
}
bus_writeとbus_readの間に10クロック分、シミュレーション時間を進めます。
ここまで説明した内容でとりあえず、BFMでDPI-Cを利用できるようになります。