工業製造
産業用モノのインターネット | 工業材料 | 機器のメンテナンスと修理 | 産業プログラミング |
home  MfgRobots >> 工業製造 >  >> Industrial programming >> VHDL

VUnit の概要

VUnit は、現在利用可能な最も人気のあるオープンソース VHDL 検証フレームワークの 1 つです。 Python テスト スイート ランナーと専用の VHDL ライブラリを組み合わせて、テストベンチを自動化します。

この無料の VUnit チュートリアルを提供するために、VHDLwhiz は Ahmadmunthar Zaklouta の協力を得て、この記事の残りの部分の背後にいます。これには、コンピューターにダウンロードして実行できる単純な VUnit サンプル プロジェクトが含まれます。

アフマドに言葉を贈りましょう!

このチュートリアルは、設計の検証プロセスで VUnit フレームワークを使用する方法を示すことを目的としています。 VUnit のセットアップ、VUnit テストベンチの作成、VUnit チェック ライブラリの使用、および ModelSim での VUnit テストの実行のプロセスについて説明します。また、いくつかの検証テクニックも示します。

概要

この記事には複数のスクリーンショットが含まれています。 画像をクリックすると大きくなります!

サイドバーを使用して概要をナビゲートします をクリックするか、モバイル デバイスを使用している場合は、下にスクロールして右上隅にあるポップアップ ナビゲーション ボタンをクリックします。

要件

このチュートリアルでは、このソフトウェアが Windows マシンにインストールされていることを前提としています:

また、基本的な VHDL の知識と ModelSim のスキルがあることも前提としています。

インストール中

git clone --recurse-submodules https://github.com/VUnit/vunit.git
 
python setup.py install

サンプル プロジェクトをダウンロード

以下のフォームを使用して、サンプル プロジェクトと VHDL コードをダウンロードできます。

Zip を C:\vunit_tutorial に解凍します .

はじめに

VUnit は HDL 用のテスト フレームワークであり、「早期かつ頻繁にテストする」テスト主導のワークフローと、テスト実行の自動化と管理のためのツールボックスを提供することで、検証プロセスを容易にします。これは、広範な豊富な機能を備えた高度なフレームワークですが、使いやすく、適応も簡単です。これは完全にオープンソースであり、従来のテスト方法論に簡単に組み込むことができます。

VUnit は 2 つの主要コンポーネントで構成されています:

VHDL 部分は、下図に示すように 6 つのライブラリで構成されています。このチュートリアルでは、ロギング ライブラリとチェック ライブラリを使用します。

テスト中の設計

38 という名前の、このチュートリアルで使用されるデザイン 、特定のモーターの始動手順を実装し、モーターの状態を表す 3 つの LED を駆動します。

インターフェイスは入力レコード 45 で構成されます 3 つの要素 (入力として 3 つのスイッチ) と出力レコード 52 を使用 3 つの要素 (出力として赤、黄、緑の 3 つの LED)。

一部のモーターは、使用を開始する前に最初に初期化する必要があります。モーターの起動手順には 3 つのステップがあります:

<オール>
  • 設定を読み込んでいます
  • 調整
  • 回転
  • 起動シーケンス

    ここでは、モーターの起動シーケンスと LED インジケーターの意味について説明します。

    <オール>
  • switch_1 をオンにします。
  • RED_LED が 5 回点滅し始めます。
  • RED_LED の点滅が止まり、点灯し続けるまで待ちます。
    1. これで、switch_2 をオンにできます。
    2. switch_2 をオンにすると、YELLOW_LED が 5 クロック サイクル後に点灯し始め、10 クロック サイクル続きます。その後、YELLOW_LED と RED_LED が消灯します。
    1. これで、モーターを使用する準備が整いました。 switch_3 がオンになるたびに、スイッチ_3 がオフになるまで GREEN_LED が点灯し始めます。
    2. このシーケンスに違反すると、すべてのスイッチがオフになるまで 3 つの LED がすべて点灯し続け、シーケンスを再開できます。

    テストベンチ開発

    チュートリアルのこのパートは、次のサブセクションで構成されています:

    <オール>
  • Python 実行スクリプトの設定
  • VUnit スケルトンのセットアップ
  • テストベンチのセットアップ
  • 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 つのライブラリを作成します:105117 .

    # 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 がそれをどのように処理するかを示したいと思います。

    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 チェッカー ライブラリを使用して、検証エンジニアの観点からさらに多くのテスト ケースを作成します。

    前のテスト ケースとは異なり、このアプローチではドライバーがテスト ケースの内側にあり、チェッカーが外側にありますが、テスト ケースは引き続きそれを制御します。

    この検証要件があると仮定しましょう:

    DUT セクションから、次のことがわかります。

    VUnit の 580 を使用します 以下を確認する手順:

    VUnit の 593 を使用します 以下を確認する手順:

    check_stable :603 で始まるウィンドウ内で信号が安定していることを確認します 信号パルスと 616 で終了 信号パルス。

    check_next :626 の後のいくつかのクロック サイクル後に信号 =「1」であることを確認します。 信号パルス。

    637645 信号はテスト ケースから制御されます。

    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 つのパラメーター

    これで、次のようにコマンド ラインからテスト ケースを実行できます。

    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;
    

    遅延を計算するためのクロック周期と、各スイッチの望ましい遅延をクロック周期で指定する整数を提供します。

    これで、この手順をテスト ケース内で次のように使用できます。

    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 のセルフチェック チェッカーを設計し、次のようなプロセスを使用します。

    red_monitor_process : PROCESS
    BEGIN
      WAIT UNTIL reset = '0';
      pulse_high(clk, led_low_start_event);
      WAIT UNTIL motor_start_in.switch_1 = '1';
    
    -- 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;
    
      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;
    
    -- 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 機能を検証する次のさまざまな方法を示します。 、 11321148 、および 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 は、検証エンジニアがテストベンチをより迅速かつ簡単に開発および実行するのにも役立ちます。最も重要なことは、学習曲線が速くて軽いことです。

    ここからどこへ行く

    以下のフォームを使用してサンプル プロジェクトをダウンロードしてください!


    VHDL

    1. Code Ready Containers:クラウドでのプロセス自動化ツール入門
    2. セラミック3D印刷の開始
    3. 基本的な染料に精通する!
    4. TJBot入門
    5. RAK 831 LoraGatewayおよびRPi3の使用を開始する
    6. RAK831LoRaゲートウェイとRPi3の使用を開始する
    7. IoTとのビジネスに取り掛かる
    8. 保険におけるAI入門:入門ガイド
    9. Arduinoチュートリアル01:はじめに
    10. My.Cat.com を開始する
    11. Node-RED と Docker の使用開始