FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

DPI-Cで64ビット以上のデータを扱うための試行

DPI-CではVerilogのデータ構造をC言語などのソフトウェア言語に取り込むことが出来るようになった。 だいたいの場合は32ビット~64ビットの渡すことになるので、C言語側のuint32_tuint64_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