前回の記事でChiselFlatSpec
を使ったBDDスタイルの開発例、、、、みたいな記事を書いてみた。
その際にデバッグの時に引数とか追加できんのかいねー??とか思って、方法を探してみたのでそれを書いてみようと思う。
Chiselのテスト実行時にプログラム引数を指定する方法
きっかけは単純で、最初は以下のような感じでChiselFlatSpec
内のテストケースのexecute
の第一引数に直接Array
で書いておいた固定の引数を使っていた(以下はChisel-templateのもの)
class GCDTester extends ChiselFlatSpec { ~いろいろ省略~ "using --backend-name verilator" should "be an alternative way to run using verilator" in { if(backendNames.contains("verilator")) { iotesters.Driver.execute(Array("--backend-name", "verilator"), () => new GCD) { c => new GCDUnitTester(c) } should be(true) } } ~いろいろ省略~ }
で、いろいろfirrtlやらtreadleやらverilatorを切り替えて何がどう変わるんだろー??とかこのテストだけFAILしたからピンポイントで波形とって実行したいなーとか、出てくるわけで。 とりあえず苦肉の策で、
val args = Array( "--generate-vcd-output", "on", //"--backend-name", "verilator", "--target-dir", "test_run_dir/fifo_test", "--top-name", "fifo_dtm" //"--is-verbose" )
こんな感じで書いといて、実行時にソースを編集して切り替えたりしていた。 流石に面倒なので、ちょっと真面目に調べてみた結果をご紹介
BeforeAndAfterAllConfigMap
を使ってConfigMap
を操作する方法
やり方としては、ほぼそのままで見たほうが早いと思うので早速コードを。 因みにこの方法は検索してきて出てきたstack overflowのトピックを参考にしました。
class MyTester extends ChiselFlatSpec with BeforeAndAfterAllConfigMap { val defaultArgs = scala.collection.mutable.Map( "--generate-vcd-output" -> "off", "--backend-name" -> "verilator", "--is-verbose" -> false ) override def beforeAll(configMap: ConfigMap): Unit = { if (configMap.get("--backend-name").isDefined) { defaultArgs("--backend-name") = configMap.get("--backend-name").fold("")(_.toString) } if (configMap.get("--generate-vcd-output").isDefined) { defaultArgs("--generate-vcd-output") = configMap.get("--generate-vcd-output").fold("")(_.toString) } if (configMap.get("--is-verbose").isDefined) { defaultArgs("--is-verbose") = true } } def getArgs(optArgs: Map[String, Any]): Array[String] = { val argsMap = defaultArgs ++ optArgs argsMap.map { case (key: String, value: String) => s"$key=$value" case (key: String, value: Boolean) => if (value) key else "" }.toArray }
ポイントとしては以下の3点。
trait BeforeAndAfterAllConfigMap
をミックスインするBeforeAndAfterAllConfigMap
のメソッドbeforeAll
をオーバーライドし引数のConfigMap
からプログラム引数を取り出し、定義しておいたdefaultArgs
にセットするDriver.execute
に渡す用の引数を構築するメソッドgetArgs
を操作する方法
毎回作んのも面倒なので、上記の要素を含むクラスを作っといて、それを使うようにしたほうが楽なのかも。
テスト実行時のプログラム引数の指定方法
実装は上記のものでOKで実行時にはどうするか、、という話だがScalaTestのマニュアルによると-D
を使うと設定した値がConfigMap
に設定されると書いてあるので、それを使えばOK。
上記の例だと、以下のようになる。
sbt "testOnly MyTester -- -D--backend-name=firrtl -D--generate-vcd-output=on -D--is-verbose=true"
上記の例でプログラム引数を指定した場合としなかった場合での実行結果は以下のようになった。
なお、以下の結果はテストケース内でgetArgs
で取得したArray
のデータを展開したもの。
- 実行(デフォルト引数をそのまま使用)
デフォルト引数(defaultArgs
)の中身が変更されないため--is-verbose
が含まれてない。
--backend-name=treadle --generate-vcd-output=off
- 実行(testOnlyの引数を指定)
こちらはsbtコマンドtestOnly
実行時に引数を指定した場合。
各々の引数が変更されているのがわかるかと思う。
--backend-name=firrtl <-- firrtlに --is-verbose <-- --is-verboseが追加 --generate-vcd-output=on <-- 波形取得がonになった
とりあえずこれでFAILしたテストだけ、波形とって流し直しとかも出来るようになるので効率が上げられる!!はず。。。
これを調べてる際にDriver.execute
の他の引数についても気になったものがあるので、いずれ紹介出来ると良いなぁ。