前回の記事ではChisel BootcampはModule3.2の続きでModule2で扱った4-tapのFIRフィルタ・ジェネレータをN-tap対応版に変更していった。
今回は一連の変更作業の最後のフェイズでN-tap版FIRフィルタ・ジェネレータに対応したChiselのテストを作成していく。
Module 3.2: ジェネレータ:コレクション
tap数を可変にしたFIRフィルタ・ジェネレータのテスト
これまでの一連の変更作業において、FIRフィルタのテストは以下の様な変遷をしてきた。
- 1step毎に入力値・期待値をベタ書きにしたChiselモジュールのテスト
- Scalaで書いたFIRフィルタのリファレンスモデルのテスト
- 2.のリファレンスモデルを組み込んだChiselモジュールのテスト
そして最後のステップとして、3.のChiselモジュールでは4-tap固定だったテストをN-tap対応版に変更していく 早速だが、テストを見ていこう。
/** * Int型の乱数取得ヘルパー関数 */ def r(): Int = { scala.util.Random.nextInt(1024) } /** * ソフトのリファレンスモデルとハードウェアのFIRフィルタの比較する。 * 複数個のtap設定に対して最低2回のテストが実施される。 */ def runOneTest(taps: Seq[Int]) { // ScalaのFIRフィルタのインスタンス、これで期待値生成を行う。 val goldenModel = new ScalaFirFilter(taps) // Chiselモジュールのテストコード Driver(() => new MyManyElementFir(taps, 32)) { c => new PeekPokeTester(c) { for(i <- 0 until 2 * taps.length) { val input = r() val goldenModelResult = goldenModel.poke(input) poke(c.io.in, input) expect(c.io.out, goldenModelResult, s"i $i, input $input, gm $goldenModelResult, ${peek(c.io.out)}") step(1) } } } } // 全体のテスト実行ブロック for(tapSize <- 2 until 100 by 10) { val taps = Seq.fill(tapSize)(r()) // coefのための乱数生成 runOneTest(taps) }
ここでは前回のScalaのFIRフィルタを期待値生成に使っていたテストコード部分自体を関数化して、その関数をfor
文で複数回ループすることによって、様々なtap数でテストを実行している。
N-tap版のテストの実行結果
runOneTest
がfor
文の中で複数回呼ばれるため、その文だけテストが実行されているのがわかるかと思う。
[info] [0.000] Elaborating design... [info] [0.055] Done elaborating. Total FIRRTL Compile Time: 8.0 ms Total FIRRTL Compile Time: 7.2 ms End of dependency graph Circuit state created [info] [0.000] SEED 1543148634906 test cmd9HelperMyManyElementFir Success: 4 tests passed in 9 cycles taking 0.002159 seconds [info] [0.002] RAN 4 CYCLES PASSED [info] [0.000] Elaborating design... [info] [0.002] Done elaborating. Total FIRRTL Compile Time: 15.4 ms Total FIRRTL Compile Time: 10.0 ms End of dependency graph Circuit state created [info] [0.000] SEED 1543148634987 test cmd9HelperMyManyElementFir Success: 24 tests passed in 29 cycles taking 0.005227 seconds [info] [0.005] RAN 24 CYCLES PASSED [info] [0.000] Elaborating design... [info] [0.003] Done elaborating. Total FIRRTL Compile Time: 23.6 ms Total FIRRTL Compile Time: 13.5 ms End of dependency graph Circuit state created [info] [0.000] SEED 1543148635029 test cmd9HelperMyManyElementFir Success: 44 tests passed in 49 cycles taking 0.014659 seconds [info] [0.014] RAN 44 CYCLES PASSED [info] [0.000] Elaborating design... [info] [0.006] Done elaborating. Total FIRRTL Compile Time: 28.9 ms Total FIRRTL Compile Time: 26.8 ms End of dependency graph Circuit state created [info] [0.000] SEED 1543148635097 test cmd9HelperMyManyElementFir Success: 64 tests passed in 69 cycles taking 0.054054 seconds [info] [0.052] RAN 64 CYCLES PASSED [info] [0.000] Elaborating design... [info] [0.048] Done elaborating. Total FIRRTL Compile Time: 22.6 ms Total FIRRTL Compile Time: 21.8 ms End of dependency graph Circuit state created [info] [0.000] SEED 1543148635228 test cmd9HelperMyManyElementFir Success: 84 tests passed in 89 cycles taking 0.046130 seconds [info] [0.044] RAN 84 CYCLES PASSED [info] [0.000] Elaborating design... [info] [0.002] Done elaborating. Total FIRRTL Compile Time: 27.2 ms Total FIRRTL Compile Time: 24.2 ms End of dependency graph Circuit state created [info] [0.000] SEED 1543148635381 test cmd9HelperMyManyElementFir Success: 104 tests passed in 109 cycles taking 0.066405 seconds [info] [0.065] RAN 104 CYCLES PASSED [info] [0.000] Elaborating design... [info] [0.004] Done elaborating. Total FIRRTL Compile Time: 39.3 ms Total FIRRTL Compile Time: 52.9 ms End of dependency graph Circuit state created [info] [0.000] SEED 1543148635516 test cmd9HelperMyManyElementFir Success: 124 tests passed in 129 cycles taking 0.093540 seconds [info] [0.090] RAN 124 CYCLES PASSED [info] [0.000] Elaborating design... [info] [0.003] Done elaborating. Total FIRRTL Compile Time: 44.3 ms Total FIRRTL Compile Time: 32.1 ms End of dependency graph Circuit state created [info] [0.000] SEED 1543148635723 test cmd9HelperMyManyElementFir Success: 144 tests passed in 149 cycles taking 0.146260 seconds [info] [0.143] RAN 144 CYCLES PASSED [info] [0.000] Elaborating design... [info] [0.051] Done elaborating. Total FIRRTL Compile Time: 39.1 ms Total FIRRTL Compile Time: 33.4 ms End of dependency graph Circuit state created [info] [0.000] SEED 1543148635965 test cmd9HelperMyManyElementFir Success: 164 tests passed in 169 cycles taking 0.159079 seconds [info] [0.155] RAN 164 CYCLES PASSED [info] [0.000] Elaborating design... [info] [0.003] Done elaborating. Total FIRRTL Compile Time: 45.1 ms Total FIRRTL Compile Time: 60.5 ms End of dependency graph Circuit state created [info] [0.000] SEED 1543148636266 test cmd9HelperMyManyElementFir Success: 184 tests passed in 189 cycles taking 0.198398 seconds [info] [0.195] RAN 184 CYCLES PASSED
tap数500のテストと結果
テストもN-tapのFIRフィルタ用に一般化した結果、以下の一文で所望のtap数のフィルタの構築とテストが出来るようになっている。
runOneTest(Seq.fill(500)(r())) // tap数==500のテストを実行
[info] [0.000] Elaborating design... [info] [0.048] Done elaborating. Total FIRRTL Compile Time: 279.3 ms Total FIRRTL Compile Time: 183.9 ms End of dependency graph Circuit state created [info] [0.000] SEED 1543148785173 test cmd9HelperMyManyElementFir Success: 1000 tests passed in 1005 cycles taking 6.456169 seconds [info] [6.424] RAN 1000 CYCLES PASSED
うーーん、やっぱりVerilogでテストベンチを構築するのに比べると遥かに準備が少ないから楽だな。。
最後に、ここまでの設計の手順をまとめてみよう。
ここまでは「固定(4-tap)のFIRフィルタ・ジェネレータをN-tapで可変に出来るFIRフィルタ・ジェネレータに変換する」というのを所謂TDDのフローに則って実行してきた。それは以下のような手順となる。
1. 4-tap版のFIRフィルタテストの作成
2. Chiselで4-tap版FIRフィルタ・ジェネレータを作成→1.のテストをPASSさせる。
ここまでがModule2.5の内容。これを扱った記事は以下になる。
3. ScalaでFIRフィルタのリファレンスモデルを作成
ここからはModule3.1の内容。
4. FIRフィルタのリファレンスモデルをChiselのテスト関数に組み込み
Verilogで複雑な期待値生成を作るのは面倒だけど、Scalaなら随分楽が出来る。こうして作ったリファレンスモデルを直接Chiselのモジュールのテストに組み込んで扱えるというのはかなり大きい。
5. Chiselの4-tap版FIRフィルタ・ジェネレータをN-tap版に修正してテスト
6. 4.のChiselモジュールテストをN-tap版に適応するように変更
これは本記事で扱った内容。VerilogやSystem Verilogに比べてScalaはやりたいことだけを書けるので、同じことをやるにしても効率が著しく良いと感じた。
このようにテスト作成→テストをパスするようにモジュール作成というイタレーションを繰り返すことで、それまでに作成した機能を確認しながら所望のデザインを構築していくことが出来る。
せっかくChisel(とScala)でハードウェアを作るんだから、この辺をきっちり意識して楽が出来るようにしないとなぁ。。
今回は内容的には薄いがキリがいいのでここまでにする。
次回はModule3.2の最後の項目でこのモジュールの冒頭で学んだScalaのコレクション型のChisel版に相当するVec
についてを見ていく。