Chisel3にはIOTestersというテスト用の環境が備わっており、Chiselのモジュールをテストするための機能が備わっている。
しかしこのIOTestersの弱点の一つは、ターゲットとなるモジュールのインタフェースにしかアクセスできず、内部信号にアクセスできない。したがってデバッグがとてもやりにくい、ということだ。 いろいろ試行錯誤したのだが結局IOポートにテストポートを引っ張り出すしか方法がなく、他にやり方は無いものかなあと思っていた。
// 基本的に触れるのはIOポートだけ。内部信号には触れない。 poke(dut.io.inA, inA) poke(dut.io.inB, inB) poke(dut.io.inC, inC) poke(dut.io.exp_ans, exp_val) poke(dut.io.exp_flag, exp_flag) poke(dut.io.valid, true) step(1) expect(dut.io.ans_ok, true) expect(dut.io.flag_ok, true) poke(dut.io.valid, false) step(9)
しかし、どうも調べてみるとBoringUtilsというものを使えば内部信号を外に引っ張り出すことが可能らしい。やってみよう。
package boringutils import chisel3._ import chisel3.util.experimental._ class Constant extends Module { val io = IO(new Bundle{}) val x = Wire(UInt(6.W)) x := 42.U BoringUtils.addSource(x, "uniqueId") } class Expect extends Module { val io = IO(new Bundle{}) val y = Wire(UInt(6.W)) y := 0.U // This assertion will fail unless we bore! chisel3.assert(y === 42.U, "y should be 42 in module Expect") BoringUtils.addSink(y, "uniqueId") } class Top extends Module { val io = IO(new Bundle{}) val constant = Module(new Constant) val expect = Module(new Expect) } object Main extends App { chisel3.Driver.execute(args, () => new Top()) }
BoringUtils.addSource(x, "uniqueId")
によって、信号線をモジュールの外に引っ張り出している。
そして、BoringUtils.addSink(y, "uniqueId")
でモジュールの中に引きこんでいるわけだ。この時の信号背の名前としてuniqueId
という名前で一致を取っている。
Verilogファイルを生成して、どのようになるかを観察してみる。
それぞれの下位のモジュールは以下のようにポートが自動的に生成される。
module Constant( output [5:0] x_0 ); wire [5:0] x; // @[boringutils.scala 8:15 boringutils.scala 9:5] assign x = 6'h2a; // @[boringutils.scala 8:15 boringutils.scala 9:5] assign x_0 = x; endmodule module Expect( input clock, input reset, input [5:0] uniqueId ); ... assign _T = uniqueId == 6'h2a; // @[boringutils.scala 17:20] ... endmodule
接続部分のTopモジュールは以下のようになっている。
module Top( input clock, input reset ); wire [5:0] constant_x_0; // @[boringutils.scala 22:24] wire expect__clock; // @[boringutils.scala 23:22] wire expect__reset; // @[boringutils.scala 23:22] wire [5:0] expect__uniqueId; // @[boringutils.scala 23:22] Constant constant ( // @[boringutils.scala 22:24] .x_0(constant_x_0) ); Expect expect_ ( // @[boringutils.scala 23:22] .clock(expect__clock), .reset(expect__reset), .uniqueId(expect__uniqueId) ); assign expect__clock = clock; assign expect__reset = reset; assign expect__uniqueId = constant_x_0; endmodule