DPI-CではVerilogのデータ構造をC言語などのソフトウェア言語に取り込むことが出来るようになった。
だいたいの場合は32ビット~64ビットの渡すことになるので、C言語側のuint32_t
やuint64_t
に単純にマップすれば良いのだが、
これ以上のデータを扱うためにはどうすれば良いのか調べてみることにした。
いろんな資料を見てみるに、バイト単位の配列に変換してC言語側に渡すことにより、64ビットよりも大きなデータを扱うことができるような、気がしている。
ここでやりたいのは、例えばL1Dキャッシュの1ライン(512ビットとか)をC言語側に渡したい場合。 この場合は、手順的にはいったんC言語で収まる型の配列に値を変換するらしい。なるほど。
int unsigned l1d_array[msrh_lsu_pkg::DCACHE_DATA_W/32]; generate for (genvar idx = 0; idx < msrh_lsu_pkg::DCACHE_DATA_W/32; idx++) begin : array_loop assign l1d_array[idx] = l1d_wr_if.data[idx*32+:32]; end endgenerate
そして、DPI-C関数の宣言は以下のようにする。
import "DPI-C" function void record_stq_store ( input longint rtl_time, input longint paddr, input int ram_addr, input int unsigned array[msrh_lsu_pkg::DCACHE_DATA_W/32], input longint be, input int size );
input int unsigned array
として、32ビットの配列としているのがミソ。この状態でVerilatorでコンパイルすると、生成されるC言語側のテンプレートは以下のようになった。
Vmsrh_tb__Dpi.h
// DPI import at ../src/../src/msrh_stq.sv:488:30 extern void record_stq_store(long long rtl_time, long long paddr, int ram_addr, const unsigned int* array, long long be, int size);
なるほど。const int*
の配列で受け取れるらしい。ではC言語側の実装を書いていく。
void record_stq_store(long long rtl_time, long long paddr, int ram_addr, const int* l1d_data, long long be, int size) {
これでOK。引数の型は上記のテンプレートからそのまま引っ張ってきた。これで上手く通信ができるようになった。
ちなみにこれは8ビットの配列としてもOK。例えばバイトイネーブルが付いていて8ビットの方が扱いやすければそうすればよろしい。
import "DPI-C" function void record_stq_store ( input longint rtl_time, input longint paddr, input int ram_addr, input byte array[msrh_lsu_pkg::DCACHE_DATA_B_W], input longint be, input int size ); byte l1d_array[msrh_lsu_pkg::DCACHE_DATA_B_W]; generate for (genvar idx = 0; idx < msrh_lsu_pkg::DCACHE_DATA_B_W; idx++) begin : array_loop assign l1d_array[idx] = l1d_wr_if.data[idx*8+:8]; end endgenerate