Chisel-Testers2のアナウンスが流れていた。時間が経っていたが試してみようと思う。
ChiselにはすでにIOTestersというテスト環境があるが、ぶっちゃけこれはあまり使いやすくない。 chisel-testers2は以下の改良(というか特徴)が加わっており、使いやすくなるように改善が行われている。
紹介分から抜粋する。
Overview
Testers2 is a test harness for Chisel-based RTL designs, currently supporting directed testing (all test stimulus manually specified - no constrained random and > coverage-driven flows). Testers2 emphasizes tests that are lightweight (minimizes boilerplate code), easy to read and write (understandability), and compose (for better test code reuse).
The core primitives are similar to nonsynthesizable Verilog: input pin assignment (poke), pin value assertion (expect), and time advance (step). Threading concurrency is also supported with the use of fork and join, and concurrent accesses to wires are checked to prevent race conditions.
Migrating from chisel-testers
The core abstractions (poke, expect, step) are similar to chisel-testers, but the syntax is inverted: instead of doing tester.poke(wire, value) with a Scala number value, in testers2 you would write write.poke(value) with a Chisel literal value. Furthermore, as no reference to the tester context is needed, test helper functions can be defined outside a test class and written as libraries.
Currently, this should support all the functionality that was in chisel-testers, and provides additional features. This project is meant to supersede chisel-testers, and eventually may become a default part of chisel3.
Test cases written in chisel-testers cannot be directly used in testers2, as the syntax is significantly different.
Testers2の特徴としては、基本的なテストの方法はIOTestersと変わらずpoke(ピンの値割り当て)、expect(ピンの値の比較)、step(時間を進める)であるが、スレッドを導入することにより並列なテスト記述ができるようになる。つまり、fork
とjoin
が使えるようになり、テストがより記述しやすくなるのである。
さらにテストの記述方法としては、これまでのIOTestersではtester.poke(wire, value)
と書いていたものを、wire.poke(value)
と記述することができるようになり、信号線に対して直接pokeを送ることができるようになる。これは便利かも。
という訳で試してみる。まずはtesters2のリポジトリ全体をダウンロードしてリグレッションテストから。
git clone https://github.com/ucb-bar/chisel-testers2.git cd chisel-testers2.git sbt test
なんとなくPassしたぞ。下記のキャプチャ画像は最後のVerilatorテストのみ。
次に、自分でデザインを書いてみる。シフトレジスタを設計した。
src/main/scala/iotesters2-simple/iotesters2-simple.scala
package iotesters2_simple import chisel3._ import chisel3.util._ class ShiftRegister(length: Int) extends Module { val io = IO(new Bundle { val in = Input(UInt(32.W)) val out = Output(UInt(32.W)) }) require(length >= 1) val shift_reg = Reg(Vec(length, UInt(32.W))) shift_reg(0) := io.in for(i <- 1 until length) { shift_reg(i) := shift_reg(i-1) } io.out := shift_reg(length-1) }
次に、テストを書いた。と言っても、サンプルプログラムをほぼコピーしたのだが...
https://github.com/ucb-bar/chisel-testers2/blob/master/src/test/scala/chisel3/tests/ShiftRegisterTest.scalagithub.com
src/test/scala/iotesters2-simple/iotesters2-simple.scala
package iotesters2_simple import org.scalatest._ import chisel3._ import chisel3.tester._ class ShiftRegisterTest extends FlatSpec with ChiselScalatestTester with Matchers { behavior of "Testers2" it should "test shift registers with abstractions" in { // TODO: this actually relies on total thread ordering def shiftTest(in: UInt, out: UInt, clk: Clock, value: UInt) { timescope { in.poke(value) clk.step(1) } clk.step(3) out.expect(value) } test(new ShiftRegister(4)) { c => fork { shiftTest(c.io.in, c.io.out, c.clock, 42.U) } c.clock.step(1) fork { shiftTest(c.io.in, c.io.out, c.clock, 43.U) } c.clock.step(1) fork { shiftTest(c.io.in, c.io.out, c.clock, 44.U) } c.clock.step(1) fork { shiftTest(c.io.in, c.io.out, c.clock, 45.U) } c.clock.step(1) fork { shiftTest(c.io.in, c.io.out, c.clock, 46.U) } c.clock.step(1) fork { shiftTest(c.io.in, c.io.out, c.clock, 47.U) }.join } } }
この時に注意すべきことなのだが、build.sbt
に記述するchisel3
のバージョンとchisel3-testers2
のバージョンを調整する必要がある。
build.sbt
... val defaultVersions = Map( // "chisel3" -> "3.2.+", "chisel3" -> "3.3-SNAPSHOT", "chisel-iotesters" -> "1.3.+", "chisel-testers2" -> "0.2-SNAPSHOT", "dsptools" -> "1.1.+" ) libraryDependencies ++= (Seq("chisel3", "chisel-iotesters", "dsptools", "chisel-testers2").map { dep: String => "edu.berkeley.cs" %% dep % sys.props.getOrElse(dep + "Version", defaultVersions(dep)) }) ...
テストを実行する。
sbt 'testOnly iotesters2_simple.ShiftRegisterTest'
... Total FIRRTL Compile Time: 516.1 ms file loaded in 0.0921011 seconds, 13 symbols, 10 statements test ShiftRegister Success: 0 tests passed in 11 cycles in 0.078559 seconds 140.02 Hz [info] ShiftRegisterTest: [info] Testers2 [info] - should test shift registers with abstractions [info] ScalaTest [info] Run completed in 2 seconds, 224 milliseconds. [info] Total number of tests run: 1 [info] Suites: completed 1, aborted 0 [info] Tests: succeeded 1, failed 0, canceled 0, ignored 0, pending 0 [info] All tests passed. [info] Passed: Total 1, Failed 0, Errors 0, Passed 1 [success] Total time: 6 s, completed 2019/12/07 13:11:58
テスト結果は問題ない様だ。forkによるテストも問題なく実行できた。