VUnit の概要
VUnit は、現在利用可能な最も人気のあるオープンソース VHDL 検証フレームワークの 1 つです。 Python テスト スイート ランナーと専用の VHDL ライブラリを組み合わせて、テストベンチを自動化します。
この無料の VUnit チュートリアルを提供するために、VHDLwhiz は Ahmadmunthar Zaklouta の協力を得て、この記事の残りの部分の背後にいます。これには、コンピューターにダウンロードして実行できる単純な VUnit サンプル プロジェクトが含まれます。
アフマドに言葉を贈りましょう!
このチュートリアルは、設計の検証プロセスで VUnit フレームワークを使用する方法を示すことを目的としています。 VUnit のセットアップ、VUnit テストベンチの作成、VUnit チェック ライブラリの使用、および ModelSim での VUnit テストの実行のプロセスについて説明します。また、いくつかの検証テクニックも示します。
概要
この記事には複数のスクリーンショットが含まれています。 画像をクリックすると大きくなります!
サイドバーを使用して概要をナビゲートします をクリックするか、モバイル デバイスを使用している場合は、下にスクロールして右上隅にあるポップアップ ナビゲーション ボタンをクリックします。
要件
このチュートリアルでは、このソフトウェアが Windows マシンにインストールされていることを前提としています:
- Intel ModelSim
- ModelSim を無料でインストールする方法については、この記事を参照してください。
- ModelSim が PATH にあるはずです。
- Python 3.6 以上。
- Python をダウンロード
- Python が PATH にある必要があります。
- GIT (オプション).
- GIT をダウンロード
- Windows ターミナル (オプション)
- Windows ターミナルをダウンロード
また、基本的な VHDL の知識と ModelSim のスキルがあることも前提としています。
インストール中
- VUnit の取得:
- GIT がある場合は、GitHub から C ドライブにクローンできます:
git clone --recurse-submodules https://github.com/VUnit/vunit.git
- それ以外の場合は、GitHub から Zip としてダウンロードして、C ドライブに展開できます:
- VUnit をダウンロードします。
- それ以外の場合は、GitHub から Zip としてダウンロードして、C ドライブに展開できます:
- VUnit のインストール:
- ターミナルを開き、
02
に移動します 次のコマンドを入力してください:
- ターミナルを開き、
python setup.py install
- VUnit の構成:
- 以下のようにシステムに環境変数を追加してください。
17
:マシンの ModelSim へのパス20
:モデルシム
サンプル プロジェクトをダウンロード
以下のフォームを使用して、サンプル プロジェクトと VHDL コードをダウンロードできます。
Zip を C:\vunit_tutorial に解凍します .
はじめに
VUnit は HDL 用のテスト フレームワークであり、「早期かつ頻繁にテストする」テスト主導のワークフローと、テスト実行の自動化と管理のためのツールボックスを提供することで、検証プロセスを容易にします。これは、広範な豊富な機能を備えた高度なフレームワークですが、使いやすく、適応も簡単です。これは完全にオープンソースであり、従来のテスト方法論に簡単に組み込むことができます。
VUnit は 2 つの主要コンポーネントで構成されています:
- Python ライブラリ: テストの自動化、管理、構成に役立つツールを提供する
- VHDL ライブラリ: 一般的な検証タスクに役立つ一連のライブラリ
VHDL 部分は、下図に示すように 6 つのライブラリで構成されています。このチュートリアルでは、ロギング ライブラリとチェック ライブラリを使用します。
テスト中の設計
38
という名前の、このチュートリアルで使用されるデザイン 、特定のモーターの始動手順を実装し、モーターの状態を表す 3 つの LED を駆動します。
インターフェイスは入力レコード 45
で構成されます 3 つの要素 (入力として 3 つのスイッチ) と出力レコード 52
を使用 3 つの要素 (出力として赤、黄、緑の 3 つの LED)。
一部のモーターは、使用を開始する前に最初に初期化する必要があります。モーターの起動手順には 3 つのステップがあります:
<オール>起動シーケンス
ここでは、モーターの起動シーケンスと LED インジケーターの意味について説明します。
- RED_LED 読み込み設定を表します .
- YELLOW_LED ローディング キャリブレーションを表します .
- これで、switch_2 をオンにできます。
- switch_2 をオンにすると、YELLOW_LED が 5 クロック サイクル後に点灯し始め、10 クロック サイクル続きます。その後、YELLOW_LED と RED_LED が消灯します。
- GREEN_LED モーターが回転していることを示します。
- これで、モーターを使用する準備が整いました。 switch_3 がオンになるたびに、スイッチ_3 がオフになるまで GREEN_LED が点灯し始めます。
- このシーケンスに違反すると、すべてのスイッチがオフになるまで 3 つの LED がすべて点灯し続け、シーケンスを再開できます。>
テストベンチ開発
チュートリアルのこのパートは、次のサブセクションで構成されています:
<オール>Python 実行スクリプト run.py のセットアップ
各 VUnit プロジェクトには、最上位の Python スクリプト 62
が必要です プロジェクトへのエントリ ポイントとして機能し、すべての VHDL デザイン、テストベンチ、およびライブラリ ソースを指定します。
このファイルは通常、プロジェクト ディレクトリに存在します。このチュートリアルで使用するディレクトリ ツリーは次のとおりです。
76
で ファイルでは、次の 3 つのことを行う必要があります:
1 – このファイルが存在するパスを取得し、設計およびテストベンチ ファイルのパスを指定します。
# ROOT ROOT = Path(__file__).resolve().parent # Sources path for DUT DUT_PATH = ROOT / "design" # Sources path for TB TEST_PATH = ROOT / "testbench"
2 – VUnit インスタンスを作成します。
これにより、VUnit インスタンスが作成され、82
という名前の変数に割り当てられます .次に 93
を使用できます ライブラリとさまざまなタスクを作成します。
# create VUnit instance VU = VUnit.from_argv() VU.enable_location_preprocessing()
3 – ライブラリを作成し、VHDL ソースをライブラリに追加します。
私は、設計部分をテストベンチ部分から分離するのが好きです。したがって、2 つのライブラリを作成します:105
と 117
.
# create design library design_lib = VU.add_library("design_lib") # add design source files to design_lib design_lib.add_source_files([DUT_PATH / "*.vhdl"]) # create testbench library tb_lib = VU.add_library("tb_lib") # add testbench source files to tb_lib tb_lib.add_source_files([TEST_PATH / "*.vhdl"])
ファイルの残りの部分は、ModelSim が 121
を使用するための構成です。 ファイルが存在する場合。
注: ここでは、134
を使用します 拡大。 142
を使用している場合は、変更が必要になる場合があります .
この作業構造が気に入った場合は、このファイルをまったく変更する必要はありません。新しいプロジェクトを開始するときはいつでも、それをプロジェクト ディレクトリにコピーするだけです。ただし、別のディレクトリ構造を希望する場合は、作業構造に準拠するようにパスを変更する必要があります。
これで、このファイルを使用するたびに、VUnit はプロジェクト内の VUnit テストベンチを自動的にスキャンし、コンパイル順序を決定し、ライブラリを作成してソースをコンパイルし、オプションで、すべてまたは特定のテスト ケースでシミュレーターを実行します。
それは素晴らしいことではありませんか? 😀
VUnit スケルトンのセットアップ
VUnit テストベンチを作成するには、テストベンチ ファイル 159
に特定のコードを追加する必要があります。
1 – 次のようにライブラリを追加します。
まず、VUnit ライブラリ 164
を追加する必要があります およびそのコンテキスト:178
、次のように VUnit 機能にアクセスできるようにします:
LIBRARY VUNIT_LIB; CONTEXT VUNIT_LIB.VUNIT_CONTEXT;
次に、デザイン ライブラリとテストベンチ ライブラリ 188
を追加する必要があります。 と 194
次のように DUT とパッケージにアクセスできるようにします:
LIBRARY DESIGN_LIB; USE DESIGN_LIB.MOTOR_PKG.ALL; LIBRARY TB_LIB; USE TB_LIB.MOTOR_TB_PKG.ALL;
DUT には 2 つのパッケージがあります。設計用:200
もう 1 つはテストベンチ要素 213
用 .これは通常、大きなプロジェクトがどのように構成されているかという理由で、私が作成した単純なパッケージです。 VUnit がそれをどのように処理するかを示したいと思います。
221
と231
246
にコンパイルされます .251
と264
272
にコンパイルされます .
2 – 次のようにランナー構成をエンティティに追加します:
ENTITY motor_start_tb IS GENERIC(runner_cfg : string := runner_cfg_default); END ENTITY motor_start_tb;
286
Python テスト ランナーがテストベンチを制御できるようにする一般的な定数です。つまり、python 環境からテストを実行できます。このジェネリックは必須であり、変更されません。
3 – 次のように、VUnit テストベンチ スケルトンをテストベンチに追加します。
ARCHITECTURE tb OF motor_start_tb IS test_runner : PROCESS BEGIN -- setup VUnit test_runner_setup(runner, runner_cfg); test_cases_loop : WHILE test_suite LOOP -- your testbench test cases here END LOOP test_cases_loop; test_runner_cleanup(runner); -- end of simulation END PROCESS test_runner; END ARCHITECTURE tb;
295
テストベンチの主要な制御プロセスです。常にプロシージャ 300
で始まります 手順 314
で終了します .シミュレーションは、これら 2 つの手順の間に存在します。 329
すべてのテスト ケースが行われるテスト スーツです。
テスト ケースを作成するには、VUnit の 337
を使用します。 次のように If ステートメント内で機能します:
IF run("test_case_name") THEN -- test case code here ELSIF run("test_case_name") THEN -- test case code here END IF;
次に、346
の呼び出しで指定した名前で呼び出すだけで、Python 環境からすべてまたは特定のテスト ケースを実行できます。 .
テストベンチのセットアップ
ここでは、以下に示すように、DUT と通信するために必要な信号を追加することから始めます。
-------------------------------------------------------------------------- -- TYPES, RECORDS, INTERNAL SIGNALS, FSM, CONSTANTS DECLARATION. -------------------------------------------------------------------------- -- CONSTANTS DECLARATION -- -- simulation constants CONSTANT C_CLK_PERIOD : time := 10 ns; -- INTERNAL SIGNALS DECLARATION -- -- DUT interface SIGNAL clk : STD_LOGIC := '0'; SIGNAL reset : STD_LOGIC := '1'; SIGNAL motor_start_in : MOTOR_START_IN_RECORD_TYPE := (switch_1 => '0', switch_2 => '0', switch_3 => '0'); SIGNAL motor_start_out : MOTOR_START_OUT_RECORD_TYPE; -- simulation signals SIGNAL led_out : STD_LOGIC_VECTOR(2 DOWNTO 0) := (OTHERS => '0');
注: シグナルを初期値で初期化することをお勧めします。
次に、DUT を次のようにインスタンス化します。
-------------------------------------------------------------------------- -- DUT INSTANTIATION. -------------------------------------------------------------------------- motor_start_tb_inst : ENTITY DESIGN_LIB.motor_start(rtl) PORT MAP( clk => clk, reset => reset, motor_start_in => motor_start_in, motor_start_out => motor_start_out );
注: 入力ポートと出力ポートをレコードにグループ化しました。エンティティとインスタンス化がすっきりするので、これは大規模なプロジェクトでは有益だと思います。
そして最後に 359
を運転します 、 362
、および 375
ここに示すように:
-------------------------------------------------------------------------- -- SIGNAL DEFINITION OF UNUSED OUTPUT PORTS AND FIXED SIGNALS. -------------------------------------------------------------------------- led_out(0) <= motor_start_out.red_led; led_out(1) <= motor_start_out.yellow_led; led_out(2) <= motor_start_out.green_led; -------------------------------------------------------------------------- -- CLOCK AND RESET. -------------------------------------------------------------------------- clk <= NOT clk after C_CLK_PERIOD / 2; reset <= '0' after 5 * (C_CLK_PERIOD / 2);
テスト ケースの開発
それでは、DUT に戻り、いくつかのテスト ケースを作成して実際の作業を開始しましょう。 2 つのシナリオを紹介します:
設計エンジニアのシナリオ: デザイナーの立場から、デザイナー自身が検証を行います。通常、開発段階で発生するこのシナリオでは、デザイナーはコードにアクセスできます。このシナリオでは、VUnit が「早期かつ頻繁にテストする」のにどのように役立つかを示します。
検証エンジニアのシナリオ :設計 (DUT) はブラック ボックスとして扱われます。外部インターフェースとテスト要件しか知りません。
また、次の 3 つの検証手法についても説明します。
- テスト ケース内のドライバーとチェッカー
- テスト ケース内のドライバーおよび制御されたチェッカー
- テスト ケース内のドライバーとセルフチェック チェッカー
最初の手法から始めて、この記事の後半で最後の 2 つの手法に戻りましょう。
テスト ケース内のドライバーとチェッカー
これは最も簡単な方法です。ドライバーとチェッカーはテスト ケース自体の内部にあり、テスト ケース コード内に駆動とチェック操作を実装します。
以下のように RED_LED 機能を開発したと仮定しましょう:
WHEN SWITCH_1_ON => IF (motor_start_in.switch_1 = '0' OR motor_start_in.switch_2 = '1' OR motor_start_in.switch_3 = '1') THEN state = WAIT_FOR_SWITCHES_OFF; ELSIF (counter = 0) THEN led_s.red_led <= '1'; state <= WAIT_FOR_SWITCH_2; ELSE led_s.red_led <= NOT led_s.red_led; END IF;
そして今、残りの機能の開発に進む前に、設計を検証したいと考えています.
そのために、VUnit の 389
を使用します 397
内の関数 次に示すように、switch_1 をオンにしたときの出力を検証するためのテスト ケースを作成します。
IF run("switch_1_on_output_check") THEN info("------------------------------------------------------------------"); info("TEST CASE: switches_off_output_check"); info("------------------------------------------------------------------"); -- code for your test case here.
これにより、「switch_1_on_output_check」という名前のテスト ケースが作成されます
注: 408
トランスクリプト画面とターミナルに出力するログ ライブラリからの VUnit プロシージャです。テスト結果を表示するために使用します。
ここで、このテスト ケースのコードを記述します。そのために、VUnit のチェック サブプログラムを使用します。
switch_1 がオンになった後、RED_LED が 5 回点滅することがわかっているので、VHDL For ループを作成し、その中でチェックを実行します。
413
プロシージャは、提供された特定のパラメータのチェックを実行します。これには多くのバリエーションがあり、ここではデモンストレーション目的でそれらのいくつかを使用しました.
check(expr => motor_start_out.red_led = '1', msg => "Expect red_led to be ON '1'");
ここでは、シミュレーション時間のこの時点で RED_LED が「1」であるかどうかをテストし、コンソールにメッセージを出力します:
# 35001 ps - check - PASS - red_led when switch_1 on (motor_start_tb.vhdl:192)
注意 PASS か ERROR か、このチェックが行われたときのタイムスタンプ、およびこのチェックが行われたファイル名と行番号がわかります。
もう 1 つの方法は、422
を使用することです。 手順。ここでは、YELLOW_LED が「0」であることを確認するために使用します:
check_false(expr => ??motor_start_out.yellow_led, msg => result("for yellow_led when switch_1 on"));
ここでは、VUnit の 438
を使用します メッセージを改善する機能。プリントアウトは次のようになります:
# 35001 ps - check - PASS - False check passed for yellow_led when switch_1 on # (motor_start_tb.vhdl:193)
注意 チェック タイプに関する追加情報を出力すること:「False check passed」.
さらに別の方法は、 448
を使用することです .ここでは、GREEN_LED が「0」であることをテストするために使用します:
check_equal(got => motor_start_out.green_led, expected => '0', msg => result("for green_led when switch_1 on"));
ここでは、比較のために追加のパラメーター「0」を指定しました。結果のプリントアウトは次のとおりです:
# 35001 ps - check - PASS - Equality check passed for green_led when switch_1 on - # Got 0. (motor_start_tb.vhdl:194)
これで、1 クロック サイクル後に RED_LED がオフになり、他の LED もオフのままになることがわかります。 454
を使用できます 以下に示すように、それらすべてを同時にチェックするには:
check_equal(led_out, STD_LOGIC_VECTOR'("000"), result("for led_out when switch_1 on"), warning);
注意 修飾子 468
の使用 であるため、プロシージャの値があいまいではありません。また、このチェックのレベルを WARNING に指定しました。これは、このチェックが失敗した場合、エラーをスローする代わりに警告を発行することを意味します。出力は次のようになります:
# 45001 ps - check - PASS - Equality check passed for led_out when switch_1 on - # Got 000 (0). (motor_start_tb.vhdl:197)
これは完全なテスト ケースのコードです:
WAIT UNTIL reset <= '0'; WAIT UNTIL falling_edge(clk); motor_start_in.switch_1 <= '1'; -- turn on switch_1 FOR i IN 0 TO 4 LOOP WAIT UNTIL rising_edge(clk); WAIT FOR 1 ps; check(expr => motor_start_out.red_led = '1', msg => "Expect red_led to be ON '1'"); check_false(expr => ??motor_start_out.yellow_led, msg => result("for yellow_led when switch_1 on")); check_equal(got => motor_start_out.green_led, expected => '0', msg => result("for green_led when switch_1 on")); WAIT UNTIL rising_edge(clk); WAIT FOR 1 ps; check_equal(led_out, STD_LOGIC_VECTOR'("000"), result("for led_out when switch_1 on"), warning); END LOOP; info("===== TEST CASE FINISHED =====");
実行中のテスト ケース
ここで、テスト ケースを実行します。ターミナルまたはシミュレータ GUI でテストを実行できます。
ターミナルでテストを実行する
これを行うには、まず新しいターミナル (CMD、PowerShell、Windows ターミナル) を開き、vunit_tutorial に移動します。 479
があるディレクトリ ファイルが見つかりました。
テスト ケースを実行するには、次のように入力します。
python .\run.py *switch_1_on_output_check
VUnit はすべての VHDL ファイルを正しい順序でコンパイルして解析し、VUnit テストベンチを探します。次に、VUnit はこれらのファイル内を調べて、481
を検索します。 "switch_1_on_output_check" テスト ケース名を使用して実行します。
注: テスト ケースの前に * ワイルドカード記号を付けて、フル ネームと一致させます。
tb_lib.motor_start_tb.switch_1_on_output_check
VUnit コマンドライン インターフェイスはワイルドカードを受け入れるため、これが可能です。
シミュレート後の出力結果は次のとおりです:
Starting tb_lib.motor_start_tb.switch_1_on_output_check Output file: C:\vunit_tutorial\vunit_out\test_output\tb_lib.motor_start_tb. switch_1_on_output_check_6df3cd7bf77a9a304e02d3e25d028a92fc541cf5\output.txt pass (P=1 S=0 F=0 T=1) tb_lib.motor_start_tb.switch_1_on_output_check (1.1 seconds) ==== Summary ========================================================== pass tb_lib.motor_start_tb.switch_1_on_output_check (1.1 seconds) ======================================================================= pass 1 of 1 ======================================================================= Total time was 1.1 seconds Elapsed time was 1.1 seconds ======================================================================= All passed!
1 つのテストが実行され、PASS であることがわかります。
注意 その VUnit は vunit_out を作成しました プロジェクトディレクトリのフォルダー。このフォルダー内に、test_output という名前のフォルダーがあります。 テストに関するレポートがあります。
上記では、各チェックの詳細を含まない最終的なテスト結果のみを取得しましたが、VUnit コマンドライン ツールには、テストを実行するためのいくつかのスイッチが用意されています。シミュレーション中に何が起こっているかについてより多くの情報を取得するには、冗長スイッチ 499
を使用できます。 :
python .\run.py *switch_1_on_output_check -v
詳細な出力は次のようになります:
その他の便利なスイッチは次のとおりです:
505
:すべてのテスト ケースを一覧表示します。
516
:最初に出力フォルダーを削除してから、テストを実行します。
527
:このスイッチは、エラーをチェックするテストを実行せずにコンパイルする場合などに便利です。
シミュレータ GUI でのテストの実行
多くの場合、波の目視検査が必要です。 VUnit は、GUI スイッチ 536
を使用して、シミュレーターでテストを実行する自動化された方法を提供します。 . 547
ファイルが利用可能です。
python .\run.py *switch_1_on_output_check -g
ここで、VUnit はこの特定のテスト ケースの ModelSim を起動し、波形ウィンドウを開き、信号を追加します。 波の中
注: 必要に応じて波形をカスタマイズできますが、waves 内に波形フォーマット ファイルを保存する必要があります。 この命名規則 563
のフォルダー VUnit が ModelSim を起動するときにロードできるようにします。
エラーを発見した後にコードを変更し、このテスト ケースを再実行するとします。その場合、ModelSim のトランスクリプト ウィンドウに次のように入力できます:574
、これにより、VUnit が再コンパイル、再起動、およびシミュレーションを再実行します。
テスト ケース内のドライバーと制御されたチェッカー
これまで、VUnit テストベンチをセットアップし、テスト ケースを開発して実行する方法を学びました。このセクションでは、別の検証アプローチと VUnit チェッカー ライブラリを使用して、検証エンジニアの観点からさらに多くのテスト ケースを作成します。
前のテスト ケースとは異なり、このアプローチではドライバーがテスト ケースの内側にあり、チェッカーが外側にありますが、テスト ケースは引き続きそれを制御します。
この検証要件があると仮定しましょう:
- switch_1 がオンで、RED_LED が点灯している間に、switch_2 をオンにした後、出力を確認します。
DUT セクションから、次のことがわかります。
- switch_2 を ON にすると、YELLOW_LED が 5 クロック サイクル後に 10 クロック サイクルの間、常時点灯し始め、その後、YELLOW_LED と RED_LED がオフになります。
VUnit の 580
を使用します 以下を確認する手順:
- 最初から switch_2 がオンになるまで、YELLOW_LED は「0」です。
- YELLOW_LED は 10 クロック サイクルの間「1」です。
VUnit の 593
を使用します 以下を確認する手順:
- switch_2 をオンにしてから 5 クロック サイクル後に、YELLOW_LED が「1」になります。
check_stable :603
で始まるウィンドウ内で信号が安定していることを確認します 信号パルスと 616
で終了 信号パルス。
check_next :626
の後のいくつかのクロック サイクル後に信号 =「1」であることを確認します。 信号パルス。
637
と 645
信号はテスト ケースから制御されます。
650
に必要なシグナルを追加することから始めます。 と 663
手順は次のとおりです:
-- VUnit signals SIGNAL enable : STD_LOGIC := '0'; -- for yellow_led SIGNAL yellow_next_start_event : STD_LOGIC := '0'; SIGNAL yellow_low_start_event : STD_LOGIC := '0'; SIGNAL yellow_low_end_event : STD_LOGIC := '0'; SIGNAL yellow_high_start_event : STD_LOGIC := '0'; SIGNAL yellow_high_end_event : STD_LOGIC := '0';
次に、672
内に新しいテスト ケースを作成します。 VUnit の 689
を使用 次のように機能します:
ELSIF run("switch_2_on_output_check") THEN info("------------------------------------------------------------------"); info("TEST CASE: switch_2_on_output_check"); info("------------------------------------------------------------------");
695
を作成します 706
で使用するための YELLOW_LED の低状態 手順は次のとおりです:
WAIT UNTIL reset <= '0'; -- out of reset enable <= '1'; pulse_high(clk, yellow_low_start_event); WAIT FOR C_CLK_PERIOD * 3;
719
信号は 725
をアクティブにします と 736
最初から有効にしたいと考えています。
749
758
からの簡単な手順です 次の立ち上がりクロック エッジを待機し、1 クロック サイクルの間信号をパルスします。この場合、765
です。 .
ここで、switch_1 をオンにして、RED_LED が点灯し続けるまで待ってから、switch_2 をオンにします:
-- turn ON switch_1 motor_start_in.switch_1 <= '1'; -- wait until RED_LED finished WAIT FOR C_CLK_PERIOD * 12; -- turn ON switch_2 motor_start_in.switch_2 <= '1';
これで、5 クロック サイクル後、YELLOW_LED が「1」になることがわかりました。したがって、777
を作成します。 782
で使用する YELLOW_LED 用 手順:
-- after 5 clk cycles YELLOW_LED will light -- next_start_event for YELLOW_LED high pulse_high(clk, yellow_next_start_event); -- 1st clk cycle
同様に、 792
を作成します 807
で使用する YELLOW_LED の低状態 手順:
WAIT FOR C_CLK_PERIOD * 3; -- end event for YELLOW_LED low pulse_high(clk, yellow_low_end_event); -- 5th clk cycle
これで、YELLOW_LED が 10 クロック サイクルの間ハイになります。したがって、819
を作成します。 821
の YELLOW_LED のハイ状態 手順:
-- YELLOW_LED is high for 10 clk cycles -- start event for YELLOW_LED high yellow_high_start_event <= '1'; WAIT UNTIL rising_edge(clk); -- 1st clk cycle yellow_high_start_event <= '0';
ここでは 837
を使用しませんでした 次の立ち下がりエッジではなく、今パルスを発生させたいからです。
841
を作成します 857
の YELLOW_LED のハイ状態 次のように 8 クロック サイクル後:
WAIT FOR C_CLK_PERIOD * 8; -- end event for YELLOW_LED pulse_high(clk, yellow_high_end_event); -- 10th clk cycle
以上で、テストケースは終了です。次のようなプロセスの後に、チェッカー プロシージャへの呼び出しを追加するだけです。
---------------------------------------------------------------------- -- Related YELLOW_LED check ---------------------------------------------------------------------- -- check that YELLOW_LED is low from start until switch_2 is ON check_stable(clock => clk, en => enable, start_event => yellow_low_start_event, end_event => yellow_low_end_event, expr => motor_start_out.yellow_led, msg => result("YELLOW_LED Low before switch_2"), active_clock_edge => rising_edge, allow_restart => false); -- check that YELLOW_LED is high after switch_2 is ON check_next(clock => clk, en => enable, start_event => yellow_next_start_event, expr => motor_start_out.yellow_led, msg => result("for yellow_led is high after 5 clk"), num_cks => 5, allow_overlapping => false, allow_missing_start => true); -- check that YELLOW_LED is high after for 10 clk cycle check_stable(clk, enable, yellow_high_start_event, yellow_high_end_event, motor_start_out.yellow_led, result("for YELLOW_LED High after switch_2"));
注: 861
875
のパラメータ 新しい 880
の場合、新しいウィンドウを開始する手順 895
の前に発生 .
注: 907
に 5 を入れます 916
の 5 クロック サイクル後に YELLOW_LED がハイになるため、この手順を実行します。 .
注: 929
の最後の 2 つのパラメーター
936
:2 番目の940
を許可します 最初の expr が「1」になる前。957
:expr が969
なしで「1」になることを許可します .
これで、次のようにコマンド ラインからテスト ケースを実行できます。
python .\run.py *switch_2_on_output_check -v
結果は次のようになります:
次のように、シミュレータ GUI でテスト ケースを実行できます。
python .\run.py *switch_2_on_output_check -g
この波形の結果:
注:970
そして 980
992
のシグナル 1005
の場合、監視対象の信号が参照されます。 .
このテスト ケースでは、テスト ケースからチェック操作を取り出しましたが、テスト ケースからそれらを制御しました。また、RED_LED 機能をチェックしていないことに注意してください。
テスト ケース内のドライバーとセルフチェック チェッカー
前のアプローチの欠点の 1 つは、読みにくいことです。テスト ケースに、1018
など、興味のない、またはテストや機能に関連しない情報が含まれている および 1029
信号。これらすべての詳細を非表示にし、テスト ケースにドライバーのみを含め、セルフチェック チェッカーを作成します。
ドライバーの設計から始めましょう。
VHDL のプロシージャは、その良い候補です。 VHDL プロシージャの使用方法がわからない場合は、このチュートリアルを確認してください。
以下は手順 1030
です 1042
から .
PROCEDURE switch_driver( SIGNAL switches : OUT MOTOR_START_IN_RECORD_TYPE; CONSTANT clk_period : IN TIME; CONSTANT sw1_delay : IN INTEGER; CONSTANT sw2_delay : IN INTEGER; CONSTANT sw3_delay : IN INTEGER) IS BEGIN IF (sw1_delay = 0) THEN WAIT FOR clk_period * sw1_delay; switches.switch_1 <= '1'; ELSIF (sw1_delay = -1) THEN switches.switch_1 <= '0'; END IF; IF (sw2_delay = 0) THEN WAIT FOR clk_period * sw2_delay; switches.switch_2 <= '1'; ELSIF (sw2_delay = -1) THEN switches.switch_2 <= '0'; END IF; IF (sw3_delay = 0) THEN WAIT FOR clk_period * sw3_delay; switches.switch_3 <= '1'; ELSIF (sw3_delay = -1) THEN switches.switch_3 <= '0'; END IF; END PROCEDURE switch_driver;
遅延を計算するためのクロック周期と、各スイッチの望ましい遅延をクロック周期で指定する整数を提供します。
- 自然値 (>=0) の意味:(
1056
の後にスイッチをオンにする *1065
). - 値 -1 は、スイッチをオフにすることを意味します。
- その他の負の値はすべて、何もしないことを意味します。
これで、この手順をテスト ケース内で次のように使用できます。
switch_driver(motor_start_in,C_CLK_PERIOD,3,12,20);
これにより、3 クロック サイクル後に switch_1 がオンになり、12 クロック サイクル後に switch_2 がオンになり、最後に 20 クロック サイクル後に switch_3 がオンになります。
これまで、VUnit のデフォルト チェッカーを使用してきました。 VUnit は、カスタム チェッカーを持つ可能性を提供します。これは、多数のチェックを伴う大きなテスト ケースがあり、チェックに関する統計が必要な場合、またはチェックを残りのテストベンチと混同したくない場合に役立ちます。
RED_LED のカスタム チェッカーを作成し、失敗のログ レベルを WARNING に設定します。
CONSTANT RED_CHECKER : checker_t := new_checker("red_led_checker", WARNING);
そして、Setup VUnit セクションで RED_CHECKER のロギング パス チェックを有効にします。
show(get_logger(RED_CHECKER), display_handler, pass);
次に、セルフチェック チェッカー (またはモニター) に移りましょう。最初に RED_LED のセルフチェック チェッカーを設計し、次のようなプロセスを使用します。
- switch_1 がオンになるのを待ち、
1071
を追加します すべての LED が低い場合:
red_monitor_process : PROCESS BEGIN WAIT UNTIL reset = '0'; pulse_high(clk, led_low_start_event); WAIT UNTIL motor_start_in.switch_1 = '1';
- 最初のテスト ケースと同じ FOR LOOP を使用して RED_LED を点滅させ、
1081
を追加します。 RED_LED ハイ:
-- RED_LED is blinking FOR i IN 0 TO 4 LOOP IF (motor_start_in.switch_1 = '1' AND motor_start_in.switch_2 = '0' AND motor_start_in.switch_3 = '0') THEN WAIT UNTIL rising_edge(clk); WAIT FOR 1 ps; check(RED_CHECKER, motor_start_out.red_led = '1', result("for red_led blink high")); WAIT UNTIL rising_edge(clk); WAIT FOR 1 ps; check(RED_CHECKER, motor_start_out.red_led = '0', result("for red_led blink low")); -- RED_LED is constantly lighting start event IF (i = 4) THEN -- finish blinking WAIT UNTIL rising_edge(clk); WAIT FOR 1 ps; check(RED_CHECKER, motor_start_out.red_led = '1', result("for red_led blink low")); pulse_high(clk, red_high_start_event); END IF; ELSE -- perform check for error (All led high until all switches are off) END IF; END LOOP;
- switch_2 がオンになるのを待ってから、
1097
を追加します。 RED_LED ハイ:
IF (motor_start_in.switch_2 /= '1') THEN WAIT UNTIL motor_start_in.switch_2 = '1'; END IF; WAIT UNTIL rising_edge(clk); WAIT FOR C_CLK_PERIOD * 14; -- RED_LED is constantly lighting end event pulse_high(clk, red_high_end_event); END PROCESS red_monitor_process;
1109
を追加します RED_LED の高低の手順:
-- check that RED_LED is low from start until switch_1 is ON -- Note the use of motor_start_in.switch_1 as end_event check_stable(RED_CHECKER, clk, enable, led_low_start_event, motor_start_in.switch_1, motor_start_out.red_led, result("RED_LED low before switch_1")); -- check that RED_LED is low after switch_2 is ON check_stable(RED_CHECKER, clk, enable, red_high_start_event, red_high_end_event, motor_start_out.red_led, result("RED_LED high after switch_1"));
次のテストケースでこれをテストしましょう:
ELSIF run("red_led_output_self-check") THEN info("---------------------------------------------------------------"); info("TEST CASE: red_led_output_self-check"); info("---------------------------------------------------------------"); WAIT UNTIL reset = '0'; -- turn switch_1 on after 3 clk cycles and switch_2 after 13 clk cycles switch_driver(motor_start_in,C_CLK_PERIOD,3,13,-1); WAIT FOR C_CLK_PERIOD * 3; -- dummy wait info("===== TEST CASE FINISHED =====");
次のようにシミュレーションを実行します:
python .\run.py *red_led* -v
結果は次のようになります:
注意 チェッカーが 1112
であること .
同じアプローチに従って YELLOW_LED のセルフチェック チェッカーを設計できますが、これは読者の演習として残します。ただし、1124
を使用して GREEN_LED 機能を検証する次のさまざまな方法を示します。 、 1132
、 1148
、および 1157
GREEN_LED が最初から switch_3 が初めてオンになるまでオフであることを確認するには、単純に 1167
を使用します。 手順:
-- check that GREEN_LED is low from start until switch_3 is ON. check_stable(clk, enable, led_low_start_event, motor_start_in.switch_3, motor_start_out.green_led, result("GREEN_LED low before switch_3"));
switch_3 がオンになったときに GREEN_LED がオンになっていることを確認する 1 つの方法は、1177
を使用することです。 手順。 1188
として switch_3 を使用して呼び出します 、1 クロック サイクルを 1195
に割り当てます 、重複を許可:
-- check that GREEN_LED is high using check_next check_next(clock => clk, en => green_next_en, start_event => motor_start_in.switch_3, expr => motor_start_out.green_led, msg => result("for green_led high using check_next"), num_cks => 1, allow_overlapping => true, allow_missing_start => false);
オーバーラップを許可したため、switch_3 が「1」の場合、この手順はクロックの立ち上がりエッジごとにトリガーされます。1 クロック サイクル後に GREEN_LED が「1」であると予想されます。これが目的です。
GREEN_LED 機能をテストする別の方法は、1206
のクロック バージョンを使用することです。 この手順の有効化として switch_3 の遅延バージョンを使用する手順:
switch_3_delayed <= motor_start_in.switch_3'delayed(C_CLK_PERIOD + 1 ps) AND NOT enable; check(clock => clk, en => switch_3_delayed, expr => motor_start_out.green_led, msg => result("for green_led high using delayed"));
1218
switch_3 の 1 クロック サイクル遅延信号です。したがって、この手順は、switch_3 が「1」になってから 1 クロック サイクル後に常に有効になり、この手順は、有効になっているときに GREEN_LED が「1」であることを確認します。
1221
信号は、1 クロック サイクル遅延したバージョンの switch_3 です。したがって、この手順は、switch_3 が「1」になった 1 クロック サイクル後に常に有効になります。有効にすると、プロシージャは GREEN_LED が「1」であることを確認します。
注: 1236
で AND NOT を有効にする プロセス アプローチを使用していないときに、このシグナルをマスクするだけです。
最後に、VHDL While ループで専用プロセスを使用して、GREEN_LED のチェックを実行できます。
green_monitor_process : PROCESS BEGIN WAIT UNTIL enable = '1' AND motor_start_in.switch_1 = '1' AND motor_start_in.switch_2 = '1' AND motor_start_in.switch_3 = '1'; WHILE motor_start_in.switch_3 = '1' LOOP WAIT UNTIL rising_edge(clk); WAIT FOR 1 ps; check_equal(led_out, STD_LOGIC_VECTOR'("100"), result("for led_out when switch_3 on")); END LOOP; END PROCESS green_monitor_process;
次に、GREEN_LED のテスト ケースを次のように作成します。
ELSIF run("switch_3_on_output_check") THEN info("-------------------------------------------------------------"); info("TEST CASE: switch_3_on_output_check"); info("-------------------------------------------------------------"); info("check using a clocked check PROCEDURES"); WAIT UNTIL reset = '0'; switch_driver(motor_start_in,C_CLK_PERIOD,3,12,20); WAIT FOR C_CLK_PERIOD * 5; switch_driver(motor_start_in,C_CLK_PERIOD,-2,-2,-1); WAIT FOR C_CLK_PERIOD * 3; -- dummy wait info("-------------------------------------------------------------"); info("check using check_next PROCEDURES"); green_next_en <= '1'; switch_driver(motor_start_in,C_CLK_PERIOD,-2,-2,10); WAIT FOR C_CLK_PERIOD * 5; switch_driver(motor_start_in,C_CLK_PERIOD,-2,-2,-1); WAIT FOR C_CLK_PERIOD * 3; -- dummy wait green_next_en <= '0'; info("-------------------------------------------------------------"); info("check using check_equal process"); enable <= '1'; switch_driver(motor_start_in,C_CLK_PERIOD,-2,-2,10); WAIT FOR C_CLK_PERIOD * 5; switch_driver(motor_start_in,C_CLK_PERIOD,-2,-2,-1); WAIT FOR C_CLK_PERIOD * 10; -- dummy wait info("===== TEST CASE FINISHED =====");
テスト ケースを作成したら、それを実行してさまざまな結果を確認できます。
セルフチェック アプローチのテスト ケースは、VHDL の知識がないエンジニアにとっても、はるかに読みやすいことがわかります。
テストベンチ ファイルには他のテスト ケースがあります。このコマンドを使用してそれらを開始できます:
python .\run.py *motor_start_tb* --list
そして、これはコンソールに出力された出力です:
tb_lib.motor_start_tb.switches_off_output_check tb_lib.motor_start_tb.switch_1_on_output_check tb_lib.motor_start_tb.switch_2_on_output_check tb_lib.motor_start_tb.red_led_output_self-check tb_lib.motor_start_tb.switch_3_on_output_check tb_lib.motor_start_tb.switch_2_error_output_check Listed 6 tests
次のように入力して、すべてのテスト ケースを実行できます。
python .\run.py
結果は次のとおりです。
==== Summary ============================================================= pass tb_lib.motor_start_tb.switch_1_on_output_check (0.4 seconds) pass tb_lib.motor_start_tb.switch_2_on_output_check (0.4 seconds) pass tb_lib.motor_start_tb.red_led_output_self-check (0.4 seconds) pass tb_lib.motor_start_tb.switch_3_on_output_check (0.4 seconds) fail tb_lib.motor_start_tb.switches_off_output_check (0.9 seconds) fail tb_lib.motor_start_tb.switch_2_error_output_check (0.4 seconds) ========================================================================== pass 4 of 6 fail 2 of 6 ========================================================================== Total time was 2.9 seconds Elapsed time was 2.9 seconds ========================================================================== Some failed!
まとめ
VUnit フレームワークは、テスト実行の自動化のための高度な機能と、テストベンチ開発のための豊富なライブラリを提供します。さらに、設計エンジニアは設計を早い段階で頻繁にテストできます。
VUnit は、検証エンジニアがテストベンチをより迅速かつ簡単に開発および実行するのにも役立ちます。最も重要なことは、学習曲線が速くて軽いことです。
ここからどこへ行く
- VUnit ドキュメント
- VUnit ブログ
- VUnit ジッター
以下のフォームを使用してサンプル プロジェクトをダウンロードしてください!
VHDL