FPGA開発日記

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

VHDL/Verilogのテスティングフレームワーク"VUnit"

ソフトウェア環境下においてテスティングフレームワークは、例えばJUnit, GoogleTest など。 しかしハードウェア言語向けのテスティングフレームワークというのは少ない。

以前に少し紹介したのは、cocotbというテスティングフレームワーク、こちらはPythonを使用するフレームワークだ。ブログでも少し紹介した。

github.com

msyksphinz.hatenablog.com

それ以外にもう少し発見した。VUnitというVHDL/SystemVerilog用のテスティングフレームワークだ。

VUnit — VUnit documentation

f:id:msyksphinz:20171005010245p:plain

ここでは、Verilogをベースにして調査してみよう。まずはインストールから。

cd vunit
sudo python ./setup.py install

これでVUnitのバイナリがインストールされる。

次にサンプルを眺めてみよう。サンプルコードは、 examples/verilog/uart/に置いてある。

cd vunit/example/verilog/uart
python ./run.py
Compiling ../../../../../../../usr/local/lib/python2.7/dist-packages/vunit_hdl-2.2.1rc0-py2.7.egg/vunit/verilog/vunit_pkg.sv into vunit_lib ...
Compiling src/uart_tx.sv into uart_lib ...
Compiling src/uart_rx.sv into uart_lib ...
Compiling src/test/tb_uart_tx.sv into tb_uart_lib ...
Compiling src/test/tb_uart_rx.sv into tb_uart_lib ...
Starting tb_uart_lib.tb_uart_rx.test_tvalid_low_at_start
pass (P=1 S=0 F=0 T=5) tb_uart_lib.tb_uart_rx.test_tvalid_low_at_start (1.6 seconds)

Starting tb_uart_lib.tb_uart_rx.test_receives_one_byte
pass (P=2 S=0 F=0 T=5) tb_uart_lib.tb_uart_rx.test_receives_one_byte (0.1 seconds)

Starting tb_uart_lib.tb_uart_rx.test_two_bytes_cause_overflow
pass (P=3 S=0 F=0 T=5) tb_uart_lib.tb_uart_rx.test_two_bytes_cause_overflow (0.2 seconds)

Starting tb_uart_lib.tb_uart_tx.test_send_one_byte
pass (P=4 S=0 F=0 T=5) tb_uart_lib.tb_uart_tx.test_send_one_byte (0.2 seconds)

Starting tb_uart_lib.tb_uart_tx.test_send_many_bytes
pass (P=5 S=0 F=0 T=5) tb_uart_lib.tb_uart_tx.test_send_many_bytes (0.2 seconds)

==== Summary ================================================================
pass tb_uart_lib.tb_uart_rx.test_tvalid_low_at_start      (1.6 seconds)
pass tb_uart_lib.tb_uart_rx.test_receives_one_byte        (0.1 seconds)
pass tb_uart_lib.tb_uart_rx.test_two_bytes_cause_overflow (0.2 seconds)
pass tb_uart_lib.tb_uart_tx.test_send_one_byte            (0.2 seconds)
pass tb_uart_lib.tb_uart_tx.test_send_many_bytes          (0.2 seconds)
=============================================================================
pass 5 of 5
=============================================================================
Total time was 2.4 seconds
Elapsed time was 2.7 seconds
=============================================================================
All passed!

こんな調子で実行される。この指定されたrun.pyは何をしているのかということだが、ソースコードに脚注を付けていくと、

from os.path import join, dirname
from vunit.verilog import VUnit

ui = VUnit.from_argv()

src_path = join(dirname(__file__), "src")    # ソースファイルの場所を指定できるようにする。

uart_lib = ui.add_library("uart_lib")              # UART本体を格納するためのライブラリを定義する
uart_lib.add_source_files(join(src_path, "*.sv"))  # ライブラリにソースコードを挿入する

tb_uart_lib = ui.add_library("tb_uart_lib")                   # UARTのテストパタンを格納するためのライブラリを定義する
tb_uart_lib.add_source_files(join(src_path, "test", "*.sv"))  # UARTのライブラリにソースコードを挿入する。

ui.main()  # テスト実行

テストパタンの中身

テストパタンの中身をチェックしてみる。例えば、 examples/verilog/uart/src/test/tb_uart_tx.sv を見てみよう。いくつかのtaskが定義されていることが分かる。

テストケースとテストスイート

TEST_SUITEはテストスイートを定義する。TEST_SUITEの中には、テストケースを定義している。テストケースは、テストスイート内に複数定義することが出来る。

テストケースはそのままテストを記述している。

   `TEST_SUITE begin
      `TEST_CASE("test_send_one_byte") begin
         send();
         check_all_was_received();
      end
      `TEST_CASE("test_send_many_bytes") begin
         for (int i=0; i<7; i++) begin
            send();
         end
         check_all_was_received();
      end
   end

テストケースでは、いくつかのdefineが使用できる。

  • TEST_SUITE_SETUP : 全てのテストスイート共通のセットアップを行う。
  • TEST_CASE_SETUP : 全てのテストケースの共通のセットアップを行う。
  • CHECK_EQUAL : アサーションを記述する。
  • TEST_CASE_CLEANUP : 全てのテストケース共通で、テスト終了後の処理を行う。
  • TEST_SUITE_CLEANUP : 全てのテストスイート共通で、テスト終了後の処理を行う。
  • WATCHDOG : タイムアウト設定

これでいくつかサンプル作って試してみたいな。