Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

コンポーネントを使う

組み込みの $tb コンポーネントに加えて、Rust で書いた検証コンポーネントをネイティブテストで使えます。コンポーネントは、バスファンクショナルモデル(BFM)・プロトコルチェッカー・ゴールデンモデルなどとして振る舞う Rust の型で、Veryl の組み込みシミュレータが駆動します。

コンポーネントは always_ff プロセスのように振る舞います。クロックエッジで更新され、入力はエッジ直前の値を観測し、出力はフリップフロップと同時にコミットされます。また、メモリイメージの読み込みや値のチェックといった、initial ブロックから呼び出せるゼロ時間メソッドを公開することもできます。

依存パッケージのコンポーネントは、自分で Rust を書かずにテストベンチで使えます。このページではその使い方を説明します。自分でコンポーネントを書いて登録する方法は コンポーネントを書く を参照してください。

Rust のインストール

コンポーネントはコンパイルされた Rust コードとして実行されるため、Rust ツールチェイン のインストールを推奨します。インストールしておけば、コンポーネントはソースからビルドされ、ネイティブコードとして実行されます(重いモデルほど明確に高速です)。

Rust が無くても、依存でビルド済み wasm バイナリとして配布されているコンポーネント(多くは単純なチェッカやモデル)は使えます。cargo が利用できない場合、veryl test は自動的にビルド済みのものを使用します。

コンポーネントを追加する

あるパッケージが検証コンポーネントを宣言していれば、それを依存に追加するだけで $comp::<依存名>::<コンポーネント名> として利用できます。

[dependencies]
axi_vip = {github = "example/axi_vip", version = "1.0.0"}
#[test(test_axi)]
module test_axi {
    inst clk: $tb::clock_gen;
    inst bus: AxiIf;

    inst bfm: $comp::axi_vip::axi_master (
        clk            ,
        bus: bus.master,
    );

    // ...
}

テストでインスタンス化する

コンポーネントは #[test] モジュール内でのみインスタンス化できます。

クロック駆動コンポーネント

クロック駆動コンポーネントは inst でインスタンス化し、モジュールと同じようにパラメータを #()(ジェネリック引数ではなく)で受け取り、ポートを接続します。

#[test(test_req_ack)]
module test_req_ack {
    inst clk: $tb::clock_gen;
    inst rst: $tb::reset_gen ( clk );

    var req: logic;
    var ack: logic;

    inst dut: Peripheral ( clk, rst, req, ack );

    inst chk: $comp::my_checker #( LIMIT: 8 ) ( clk, req, ack );

    initial {
        rst.assert();
        req = 1;
        clk.next(16);
        $finish();
    }
}

ポート接続では DUT 内部の信号を階層的に参照することもできます(例: val: dut.u_sub.internal_reg)。そのため、観測のために内部信号をトップレベルまで引き出す必要はありません。インターフェースインスタンスの modport をコンポーネントのインターフェースポートに接続することもできます(bus: bus.master)。コンポーネントが宣言するすべてのポートは接続されている必要があり、接続漏れは解析時に報告されます。

メソッド専用コンポーネント

メソッド専用コンポーネントはポートを持たず、var で宣言します。

#[test(test_golden)]
module test_golden {
    var g: $comp::golden   ;
    var x: logic        <8>;

    initial {
        g.set(42);
        x = g.get();
        g.check(x);
        $finish();
    }
}

var 形式では、パラメータをジェネリック引数として、コンポーネントが宣言した順に位置指定で受け取ります。任意の定数式を指定できます。

#[test(test_wide)]
module test_wide {
    const W: u32 = 96;

    var w: $comp::wide_model::<W>    ;
    var x: logic                 <96>;

    initial {
        w.put(96'h55);
        x = w.get();
        $finish();
    }
}

メソッド呼び出し

メソッドは文の位置および式の中で呼び出せます。

#[test(test_method_call)]
module test_method_call {
    var g: $comp::golden   ;
    var x: logic        <8>;

    initial {
        g.set(42); // 文の位置
        x = g.get();
        $assert(g.get() + 1 == 43, "expression"); // 式の位置
        $finish();
    }
}

式の位置での呼び出しは、それを含む文の直前に、独立したゼロ時間のステップとして実行されます。メソッドの引数は位置指定で、名前付き引数はサポートされません。

メソッドは var 形式に限りません。inst したコンポーネントもゼロ時間の呼び出しを受け付けます(例: iss.load("test.elf");)。

乱数シード

乱数を用いるコンポーネントは、インスタンスごとに決定的なシードから乱数を導出するため、実行はそのベースシードから再現できます。既定では veryl test は実行ごとに新しいランダムなベースシードを引き、それを表示します(Test seed: ...)。実行を再現するには、その値を --seed で渡すか、[test] セクションの seed フィールドで固定します。

[test]
seed = 42