Icarus VerilogとSystemCの連携(VPI)

機能検証

Verilog RTLのデザインをSystemCで検証する環境のサンプルです。

Kenji-Ishimaru/sysc_iv_sample
Co-simulation of SystemC and Icarus Verilog. Contribute to Kenji-Ishimaru/sysc_iv_sample development by creating an account on GitHub.

通常、Verilog RTLのデザインは、Verilogのテストベンチでテストデータ生成や出力データの検証を行いますが、VPI(Verilog Procedural Interface)という機能を使うとSystemCでテストデータ生成や出力データの検証が行えます。

VerilogシミュレータとSystemCの連携は、商用シミュレータを使うと簡単に行えますが、無償ツールのIcarus Verilogでも連携することができました。
VPIの連携には、以下の2つのサイトを参考にしました。ありがとうございます。
http://japanese.sugawara-systems.com/tutorial/tutorial/vpi/vpi.htm
http://www.asic-world.com/systemc/hdl.html

サンプルの動作環境

このサンプルは次の環境で動作を確認しました。

サンプルの概要

サンプルは、Verilogでインスタンス化したmod_aという簡単なRTLに対して、SystemCからランダムデータの入力を行い、SystemCでRTLの出力とリファレンスデータの一致確認を行っています。

サンプルの概要

DUTのmod_a.vは、8ビットの2入力を内部で加算して出力する単純な回路です。

サンプルの詳細

Verilog側でクロックとリセットの生成を行い、SystemC側でDUTへの入力データの生成と、DUTからの出力とリファレンスデータの一致確認を行っています。リファレンスデータの格納にはsc_fifoを利用しています。

サンプルの詳細

test_1.v

Verilog側のテストベンチは、DUTのインスタンス化とクロックとリセットの生成のみを行っています。SystemCとの連携は、$sc_stubという関数を呼び出すことで行っています。clkの生成は、初期値を0にしないと(初期値が1だと)、SystemC側のclk.pos()が逆になるようです。

vpi_stub.c

Verilog側で呼び出す$sc_stubは、vpi_register_systf()で登録しています。

$sc_stubが呼ばれると、sc_mod_a_tf()が呼ばれます。sc_mod_a_tf()では、Verilog側の信号との接続、clkに同期した信号が変化した時のコールバック関数 sc_clk_callback()、非同期リセットrst_xが変化した時のコールバック関数sc_async_callback()の登録を行っています。 init_sc()は、SystemC側の初期化を行っています。

コールバック関数sc_clk_callback()

clkに同期した信号をSystemCに取り込み、exec_sc()で時間を進めてSystemCで生成したデータをRTLに渡しています。done信号でexit_sc()を呼び出してシミュレーションを終了します。 

コールバック関数sc_async_callback()

非同期のリセット信号rst_xをSystemCに取り込んでいます。信号を取り込むだけで時間は進めていません。

mod_a_tb.cpp

SystemC側でmod_aモジュールのインスタンス化と信号接続、VPIから呼ばれる関数の実装を行っています。exec_sc()は、clkの立下りと立ち上がりの両エッジで呼ばれるので、RTL側の信号ドライブは立下り時だけ行うようにしています。立ち上がりでRTLの信号を変化させる場合は、Verilogテストベンチ側でレーシングの対策を行う必要があります。

mod_a.h

DUTへの入力データの生成、リファレンスデータの生成、信号モニター、テストシナリオのコントロールを行っています。テストシナリオのコントロール関数以外はSC_THREADです。

sc_fifoを読み書きする関数をSC_CTHREADとすると、シミュレーション時に次のようなワーニングが表示されます。

mod_a.cpp

入力データの生成とテストシナリオのコントロール

mod_a::stimulus()で行っています。リセット解除を待ってから、DUTに乱数を入力しています。

リファレンスデータの生成

mod_a::reference()で行っています。DUTが正しく動作した場合の期待値をsc_fifoに格納しています。 

信号モニター

mod_a::monitor()で信号のモニターと期待値の一致確認を行っています。DUTの出力と期待値が不一致の時はシミュレーションを終了しています。

コンパイルと実行のスクリプト

iverilogでRTLをコンパイルします。cとcppはiverilog-vpiでコンパイルします。LD_LIBRARY_PATHにSystemCのライブラリを指定しないと、実行時にエラーになります。コンパイル時に-rpathを指定することで不要にできるかもしれません。

実行結果

シミュレーションを実行すると、次のようなログが表示されます。SystemC側で生成された入力データでDUTが動作しているのが分かります。

結果の波形
タイトルとURLをコピーしました