FPGA開発日記

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

ソフトウェアとVerilogを連携させたいならば、DPI-Cがオススメ

Verilog-HDLの環境に、プログラムのhexファイルだとか、ソフトウェアで生成したデータであるとか、あるいはVerilogのシミュレーション自身をソフトウェアにより制御したいときには、DPI-Cがオススメだ。

www.kumikomi.net

DPI-Cを使うことにより、VerilogのタスクをC/C++から呼び出すことができたり、C/C++の関数をVerilog-HDLからタスクとして呼び出すことができるようになる。 大概のシミュレータ(VCS/Modelsim/NCVerilog)でもサポートされており、基本的なC++との通信ツールとして確立されている。 もう一つ、VPIという規格があるのだが、こちらは、VerilogからC/C++を呼び出すのみであり、C/C++からVerilogを読み出すことはできない。この分、DPI-Cの方が便利であると言える。 VPIはVerilog-HDLシミュレータとしてはVeritakがサポートされている。こちらも、便利なので時々利用している。シミュレータによって使い分ける感じかな。

Verilog Procedural Interface - Wikipedia, the free encyclopedia

この機能を使って、バイナリファイルをVerilog-HDLのブロックRAMにロードする機能を実装した。 バイナリファイルといっても、hexが記述してあるテキストファイルなのだが、これをC/C++で読み込む。この読み込み関数がVerilog-HDLのブロックRAMを書き換える機能を呼び出し、hexをロードするという訳だ。

Verilog-HDL : hexファイルを読み出すC/C++の関数を呼び出し
C/C++ : hexファイルをオープン、ロードし、整形しVerilog-HDLのタスクを呼び出し
Verilog-HDL : 関数からデータを受け取って、BlockRAMへ書き出し

とりあえず、8ビットずつしかBlockRAMへ書き込む関数が用意できなかったため、いちいちシフトしてBlockRAMへ書き込むようにしている。

task DPI_task_writeByte;
    input [31: 0] addr;
    input [ 7: 0] data;
...
        if ($unsigned(addr[31: 0]) >= 32'hbfc0_0000 && $unsigned(addr[31: 0]) <= 32'hbfc0_0fff) begin
            // Startup ROM
            addr_offset = addr - 32'hbfc0_0000;
            addr4 = (addr_offset[31: 4]);
            addr4_index = (addr_offset[ 3: 2]);
            inst = DUT.ram_START.bram_0.regs[addr4];
            DUT.ram_START.bram_0.regs[addr4] = (inst[127:0] & (~(8'hff << {addr_offset[ 3: 0], 3'b000}))) |
                                               (data[ 7: 0] << {addr_offset[ 3: 0], 3'b000});

この関数DPI_task_writeByteはC/C++から呼び出されるタスクであり、引数としてアドレス、バイトデータを渡される。 アドレス範囲によって書き込まれるBlockRAMが違うので最初にアドレス判定を行い、オフセットを抜く (addr_offset)。 次に、対象となるBlockRAMのラインをとりあえず読み出し、そのラインに対して対象のバイト列をマージする。 そして最後に、再度ラインに書き込みを行い、BlockRAMを更新する。

とまあ、上記の解説はDPI-Cとは関係無いけれども、Verilog-HDLだけでは面倒な、複雑な処理でもDPI-Cを混ぜればうまくこなすことができる。オススメ!

github.com