Verylにおけるテストベンチ記述について
はじめに
Verylとは現在開発中の新しいハードウェア記述言語です。
ハードウェア記述言語でテストを記述する際には一般的にテストベンチというものを作成しますが、現時点ではVerylはテストベンチ記述をサポートしておらず、SystemVerilogやcocotb(Python)といった外部のテストベンチ記述に依存しています。
しかし、今後Verylのネイティブシミュレータの実装などが進んでくると、Verylでテストベンチを記述する方法を検討する必要が出てきます。この記事では現時点で考えているVerylのテストベンチ記述のアイデアについてまとめます。
テストベンチ用構文の導入
まず最初に思いつくのはVerylにテストベンチ用の専用構文を導入するという方法です。
ハードウェア記述言語に限らずプログラミング言語でも、実装とテストは同じ言語で記述することが一般的であるため、自然なアプローチだと言えます。
例えばVerylの場合以下のようにクロック定義やクロック待ちをする記述を導入すれば、簡単なテストベンチは記述できるでしょう。
#[clock(10, 10)] // クロック波形の定義
var clk :clock;
initial {
a = 0;
@clk; // クロック待ち
a = 1;
@clk;
$assert(b == 1);
}
これは短期的にはうまくいくように思えますが、様々なテストを書いていくにつれ
- 再利用性の高い検証コンポーネントを書きたい
- より複雑なアサーションを書きたい
といった要望が発生する可能性が高く、それらをサポートしていくとSystemVerilogと同様に長大な言語仕様になってしまうと思われます。
Verylのコンセプトの1つは、肥大化したSystemVerilogの仕様をすべてサポートするのではなく合成可能記述に特化する、というものであるためこの方向に行くのは望ましくありません。
プログラミング言語でテストベンチを書く
そもそもテストベンチの記述をハードウェア記述言語で書く必要があるのでしょうか?テストベンチを書くためには各クロックごとに信号に値を設定したり、値を読み込んだりする方法さえ提供されていればよく、制約の大きいハードウェア記述言語で書くより一般的なプログラミング言語で書く方が書きやすいかもしれません。
既存の事例としてはcocotbではテストベンチをPythonで書きますし、以前のVerilatorはC++で書く必要がありました。
プログラミング言語でテストベンチを書くメリットとしては、豊富な言語機能が使えるだけでなく、そのプログラミング言語の提供するライブラリも活用できる点にあります。
例えばjpegやpngの画像を読み込んで映像信号として入力するテストベンチをハードウェア記述言語で書こうと思うと非常に大変ですが、一般的なプログラミング言語であれば既存の画像入出力ライブラリを活用して簡単に書くことができます。
一方、プログラミング言語でテストベンチを書くことを選択した場合、いくつかの問題が考えられます。まず、Verylを書くユーザーはVerylだけでなくテストベンチを書くための何らかのプログラミング言語を習得する必要があります。最近はハードウェア記述言語とプログラミング言語を両方扱える方も増えている印象ですが、やはりハードウェア記述言語を専門に書いているユーザーは無視できる数ではないと思われます。
また、「VerylとしてはC APIを提供するから任意のプログラミング言語からテストを書いてください」というのは各ユーザーが好きな言語を選択できるというメリットはあるものの、Verylとして一般的なテストの書き方というものが存在しなくなってしまい、他人のテストベンチを見てもすべてバラバラの言語で書かれていて全くわからない、ということになってしまいます。
さらに、テストベンチを書くプログラミング言語がバラバラということは必要な実行環境やコンパイラもバラバラということなので、他人のプロジェクトを持ってきてテストを実行する敷居が上がってしまいます。
なんらかのプログラミング言語を選定して全員これで書くということが決められればいいですが、好みの問題も大きく、あまり現実的な解ではなさそうに思えます。
検証コンポーネントをプラグイン形式で導入する
Verylの標準的なテスト記述を策定しつつ、複雑なコンポーネントを柔軟なプログラミング言語で書く方法として、検証コンポーネントをプラグイン形式で導入する、という方法が考えられます。
例えば、clk_genというクロックを生成する検証コンポーネントがあるとすると、最初に示したテストベンチが以下のように書けるようになる、といったイメージです。
inst u_clk: clk_gen (
clk,
);
initial {
a = 0;
u_clk.wait();
a = 1;
u_clk.wait();
$assert(b == 1);
}
検証コンポーネント自体はプログラミング言語で記述し、Verylシミュレータがプラグインとしてロード、実行します。このような構成を取ることで、言語自体を拡張することなく
- AXIなどのトランザクタ
- 制約付きランダムシーケンス
- 複雑なアサーション
といったものをプラグインとして導入可能になると思われます。Verylシミュレータからカバレッジ情報を取得するAPIが提供されればファジングなど高度な検証機能も実現できるかもしれません。
また、この方式では既存の検証コンポーネントを利用するユーザーはVerylだけでテストを完結させることができます。既存のコンポーネントで不足に感じるようになったらプログラミング言語を習得してオリジナルのコンポーネントを書いてもいいですし、その部分を経験豊富なソフトウェアエンジニアに依頼する、といった方法も考えられます。
おわりに
現時点でVerylにおけるテストベンチ記述について考えていることをまとめてみました。今のところ3つ目の「検証コンポーネントをプラグイン形式で導入する」という案が、Verylユーザーから見たユーザー体験が最も良くなるのではないかと考えています。
特にVerylユーザーの方でなにかご意見がありましたらぜひコメントをお願いします。
Discussion
テストシナリオ実装部も、プラグイン実装部も、Verilog の fork/join の様に、簡単にスレッドを作れる仕組みが必要かと思います。
確かにそうですね。コードブロックを関数引数に取れればforkもプラグイン実装にできそうですが、さすがに書きにくいと思うのでfork/joinくらいの構文拡張は許容すべきかもしれません。