Verilog-HDLを使った検証では、C/C++のモデルとVerilogのモデルを接続した協調検証が頻繁に行われる。Verilatorでも同様の機能が搭載されており、DPI-Cを使ったC/C++とVerilogとの通信が実現可能だ。
ここでは前回作成したcounter_4bit.sv
に対してDPI-Cを経由してCコードを接続してみる。例えば、カウンタがカウントアップするとC言語の関数を呼び出す。
- まず、接続するC言語の関数を
import
で宣言する。ここではdpi_c_func()
を宣言する。
// Function from C-code import "DPI-C" context task dpi_c_func(input int in, output int out);
dpi_c_func
は関数名、input int
はC言語実装側にとってのinputで、output int
はC言語実装側にとってのoutput(つまりポインタ)となる。
int return_value; always_ff @(posedge clk, negedge reset_n) begin if (!reset_n) begin cnt <= 4'h0; end else begin if (en) begin cnt <= cnt + 4'h1; /* verilator lint_off WIDTH */ dpi_c_func (cnt, return_value); $display("return_value = %d", return_value); end end end endmodule // counter_4bit
上記のように、Verilogの関数のように呼び出すことができる。
- C++の実装側。ここでは
dpi_counter_4bit.cpp
を用意する。
#include <verilated.h> #include "Vcounter_4bit.h" #include "stdio.h" extern "C" { int dpi_c_func (int i, int* o); } int dpi_c_func (int i, int* o) { printf("Hello from dpi_c_func(%d)\n", i); *o = 100 + i; return(0); }
実装についても特に言及すべきところは無いと思う。extern "C"
によってC++のデマングルを禁止している。入力側を値渡しの引数として、出力側はポインタ渡しで記述する。
ビルド時にdpi_counter.cpp
を追加すればよい。
$ verilator --cc --exe --trace-fst --trace-params --trace-structs --trace-underscore counter_4bit.v -exe tb_counter_4bit.cpp dpi_counter.cpp $ make -C obj_dir -f Vcounter_4bit.mk
実行してみよう。
$ ./obj_dir/Vcounter_4bit
Hello from c_task(0) return_value = 100 Hello from c_task(1) return_value = 101 Hello from c_task(2) return_value = 102 Hello from c_task(3) return_value = 103 Hello from c_task(4) return_value = 104 Hello from c_task(5) return_value = 105 Hello from c_task(6) return_value = 106 Hello from c_task(7) return_value = 107 Final Counter Value = 8
正しく動作していることが確認できた。