For Good FPGA Design

UVMの環境構築!(10) Test (テストコンポーネント)

UVMの環境構築第9回では、テストの定義(作成)方法について解説していきます。

なお、ソースコードはGitHubに公開しています。

目次

シリーズ目次

UVMの環境構築!シリーズの目次は、第1回 解説編の一番下をご覧ください。

テストの概要

テスト(テストコンポーネント)はuvm_testまたはそのサブクラスを継承して定義します。

テストコンポーネントの目的は、テスト項目を指定することです。主に次のことを行います。

  • エンバイロンメントをインスタンスします。
  • エンバイロンメントのコンフィグレーション(設定変更)を行います。UVMの環境構築第8回 Environment で説明したように、エンバイロンメントはコンフィグレーションパラメータを持つことができます。テストでは、uvm_config_db#(T)::set()により、コンフィグレーションパラメータを設定します。
  • テストすべきシーケンスを指定します。
図1 UVMにおけるテスト

テストの定義方法

通常は複数のテストケースがあり、その中で共通する項目があります。したがって、共通する項目をベースクラスとして定義し、そのベースクラスを継承して各テストケースを定義します。

my_test_base

それでは、ソースコードを見ながら、テストの定義方法について説明します。

my_test_base.sv

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class my_test_base extends uvm_test;
 
    my_env  env0;
 
    string result;
 
    `uvm_component_utils(my_test_base)
 
    /* Constructor */
    function new(string name = "my_test_base", uvm_component parent = null);
        super.new(name, parent);
    endfunction
 
    /* Build phase */
    function void build_phase(uvm_phase phase);
        super.build_phase(phase);
 
        env0 = my_env::type_id::create("env0", this);
    endfunction
 
    /* Extract phase */
    function void extract_phase(uvm_phase phase);
        if (env0.scoreboard0.n_error > 0)
            result = "FAIL";
        else
            result = "PASS";
    endfunction
 
    /* Report phase */
    function void report_phase(uvm_phase phase);
        `uvm_info(get_type_name(),
            $sformatf("[%s] Trial = %d, Error = %d",
            result, env0.scoreboard0.n_trial, env0.scoreboard0.n_error), UVM_NONE)
    endfunction
 
endclass
  • 1行目:uvm_testを継承して、my_test_baseを定義します。
  • 3行目:エンバイロンメントを定義します。
  • 7行目:UVMマクロを書きます。
  • 9~12行目:コンストラクタを定義します。
  • 14~19行目:Build phaseを定義します。この中で、エンバイロンメントのインスタンスを作成します。もし、エンバイロンメントのコンフィグレーションを行う場合は、エンバイロンメントのインスタンスを作成する前にuvm_config_db#(T)::set()を行います。
    /* Build phase */
    function void build_phase(uvm_phase phase);
        super.build_phase(phase);
 
        uvm_config_db#(T)::set(this, "env0", "config_pram1", value1);
        uvm_config_db#(T)::set(this, "env0", "config_pram2", value2);
 
        env0 = my_env::type_id::create("env0", this);
    endfunction
  • 21~27行目:シミュレーションが終了すると、Extract phseに移ります。ここでは、シミュレーション結果を抽出するための処理を定義できます。今回は、スコアボードでカウントしたエラー数を抽出し、PASS / FAILの判定を行いました。
  • 29~34行目:Report phaseでは、結果を出力する処理を記述できます。今回は、結果、試行回数、エラー数を出力するようにしました。

my_test1

通常は複数のテストケースがありますが、今回は1つだけテストケースを定義しました。

my_test1.sv

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class my_test1 extends my_test_base;
 
    `uvm_component_utils(my_test1)
 
    /* Constructor */
    function new(string name = "my_test1", uvm_component parent = null);
        super.new(name, parent);
    endfunction
 
    /* Build phase */
    function void build_phase(uvm_phase phase);
        uvm_config_db #(uvm_object_wrapper)::set(
            this,
            "env0.agent0.sequencer.run_phase",
            "default_sequence",
            my_sequence1::type_id::get()
        );
 
        super.build_phase(phase);
    endfunction
 
endclass
  • 1行目:my_test_baseを継承して、my_test1を定義します。
  • 3行目:UVMマクロを書きます。
  • 5~8行目:コンストラクタを定義します。
  • 10行目:Build phaseを定義します。ここでは、シーケンサーのdefault_sequenceに、シーケンスを割り当てます。シーケンサーはRun phaseでこのシーケンスを使い、スティミュラス生成を行います。

今回はenv0とagent0しかないので、テストの役割が分かりにくいかもしれません。例えば、agent0とagent1があった場合、次のようにテストケースを作成できます。各コンポーネントとシーケンスを個別に作った後に複数のテストパターンを作成できるため、検証環境構築が効率的になります。

agent0 に割り当てるシーケンスagent1 に割り当てるシーケンス
テストケース1シーケンスA_0シーケンスB_0
テストケース2シーケンスA_0シーケンスB_1
テストケース3シーケンスA_1シーケンスB_0
テストケース4シーケンスA_1シーケンスB_1
表1 テストケースの作成例

まとめ

今回は、テスト(テストコンポーネント)の定義方法について解説しました。シリーズを通してご覧いただけると、UVM検証環境が構築できるようになりますので、ぜひ他のコンポーネントの解説もご覧ください。

シリーズ目次はこちら

アバター画像
この記事を書いた人
ジーノ。大手電機メーカーで、基板設計の全般と、FPGAの設計に従事した経験を活かし、FPGAについて情報発信中。
RTL設計、シミュレーション、タイミング・クロージャ、FPGAまわりのハードウェア開発まで、幅広く取り扱っております。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA