今作り直してるオレオレRISC-V(dirv)の対向に接続するメモリモデルがバグってるので、バグ再現パターンを起こしてシミュレーションを行っていた。その際に出くわした「いや、当たり前でしょ」な話をメモ書き程度に残しておく。ScalaTest使ってる人は多分タイトルでわかる方もいる気が。。
メモリモデルがバグってて。。
とりあえず簡単に状況説明。現在以下の構成のオレオレRISC-Vにおいてdirvブロックの対向に接続しているメモリモデルを書き直している。
メモリ用の簡単なテストモジュールを作成して実装を進めてなんとなーく形になったなぁ、と思ってdirvに接続してみたところメモリアクセス系の命令が軒並みFAILした。
解析を進めて理由が分かったので、メモリモデル用のテストクラスにパターンを追加するか、、と思ってテストを作成している際にこの記事のタイトルにあるshould be (true)
でハマったのでその内容をメモ。
バグ再現パターン
以下のようなテストを書いていて、コメント部分を読んでもらうとわかるのだがstep3の部分でバグのトリガーとなる動作が実行されてstep4で期待値比較がFAILすることを期待した内容になっている。
it should f"keep Mbus.r.valid high if Mbus r.ready is Low. [$dutName-BUG-100]" in { val outDir = dutName + "-BUG-100" val args = getArgs(Map( "--top-name" -> dutName, "--target-dir" -> s"test_run_dir/$outDir" )) Driver.execute(args, () => new SimDTMMemTop(base_p)(timeoutCycle)) { c => new MemTopUnitTester(c) { idle(10) val wrData = Seq( 0xf0008093, 0x00008f03, 0xfff00e93, 0x00200193) // Set value for ((data, idx) <- wrData.zipWithIndex) { single_write(idx * 4, 0xf, data) } // step 1 var data = wrData(0) set_imem(true, 0x4, MemCmd.rd, true) comp_imem(true, true, wrData(0), MemResp.ok) step(1) // step 2 set_imem(true, 0x8,MemCmd.rd, true) comp_imem(true, true, wrData(1), MemResp.ok) step(1) // step 3 // change ready signal to LOW, so mbus read data will be kept in next cycle. set_imem(true, 0xc, MemCmd.rd, false) comp_imem(true, true, wrData(2), MemResp.ok) step(1) // step 4 // This bug regeneration pattern expose that // mbus read data doesn't keep the value in previous cycle. set_imem(true, 0xc, MemCmd.rd, true) comp_imem(true, true, wrData(2), MemResp.ok) step(1) // step 5 set_imem(true, 0x10, MemCmd.rd, true) comp_imem(true, true, wrData(3), MemResp.ok) step(1) idle(10) } } }
このパターンを実行してみると、以下のようにテストがPASSする結果になる。
STARTING test_run_dir/MemTopTester-BUG-100/VSimDTMMemTop [info] [0.001] SEED 1566016484339 [info] [0.022] (cmd_ready, w_ready) = (1, 1) [info] [0.024] (cmd_ready, w_ready) = (1, 1) [info] [0.026] (cmd_ready, w_ready) = (1, 1) [info] [0.027] (cmd_ready, w_ready) = (1, 1) Enabling waves.. Exit Code: 0 [info] [0.036] RAN 33 CYCLES FAILED FIRST AT CYCLE 18 [info] MemTopTester: [info] MemTopTester [info] - should keep Mbus.r.valid high if Mbus r.ready is Low. [MemTopTester-BUG-100] [info] ScalaTest [info] Run completed in 4 seconds, 129 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
おかしいなーと思って--is-verbose
オプションを有効にして再実行。
[info] [0.028] STEP 18 -> 19 [info] [0.029] POKE SimDTMMemTop.io_dut_imem_valid <- 1 [info] [0.029] POKE SimDTMMemTop.io_dut_imem_addr <- 8 [info] [0.029] POKE SimDTMMemTop.io_dut_imem_cmd <- 0 [info] [0.029] POKE SimDTMMemTop.io_dut_imem_r_ready <- 1 [info] [0.029] PEEK SimDTMMemTop.io_dut_imem_ready -> 1 [info] [0.029] EXPECT SimDTMMemTop.io_dut_imem_ready -> 1 == 1 PASS [info] [0.029] PEEK SimDTMMemTop.io_dut_imem_r_valid -> 1 [info] [0.029] EXPECT SimDTMMemTop.io_dut_imem_r_valid -> 1 == 1 PASS [info] [0.029] PEEK SimDTMMemTop.io_dut_imem_r_data -> 36611 [info] [0.029] EXPECT SimDTMMemTop.io_dut_imem_r_data -> 36611 == 36611 PASS [info] [0.030] PEEK SimDTMMemTop.io_dut_imem_r_resp -> 0 [info] [0.030] EXPECT SimDTMMemTop.io_dut_imem_r_resp -> 0 == 0 PASS [info] [0.030] STEP 19 -> 20 [info] [0.030] POKE SimDTMMemTop.io_dut_imem_valid <- 1 [info] [0.030] POKE SimDTMMemTop.io_dut_imem_addr <- 12 [info] [0.030] POKE SimDTMMemTop.io_dut_imem_cmd <- 0 [info] [0.030] POKE SimDTMMemTop.io_dut_imem_r_ready <- 0 [info] [0.031] PEEK SimDTMMemTop.io_dut_imem_ready -> 1 [info] [0.031] EXPECT SimDTMMemTop.io_dut_imem_ready -> 1 == 1 PASS [info] [0.031] PEEK SimDTMMemTop.io_dut_imem_r_valid -> 1 [info] [0.031] EXPECT SimDTMMemTop.io_dut_imem_r_valid -> 1 == 1 PASS [info] [0.031] PEEK SimDTMMemTop.io_dut_imem_r_data -> 4293922451 [info] [0.031] EXPECT SimDTMMemTop.io_dut_imem_r_data -> 4293922451 == -1044845 FAIL ***** [info] [0.031] PEEK SimDTMMemTop.io_dut_imem_r_resp -> 0 [info] [0.031] EXPECT SimDTMMemTop.io_dut_imem_r_resp -> 0 == 0 PASS [info] [0.031] STEP 20 -> 21 [info] [0.032] POKE SimDTMMemTop.io_dut_imem_valid <- 1 [info] [0.032] POKE SimDTMMemTop.io_dut_imem_addr <- 12 [info] [0.032] POKE SimDTMMemTop.io_dut_imem_cmd <- 0 [info] [0.032] POKE SimDTMMemTop.io_dut_imem_r_ready <- 1 [info] [0.032] PEEK SimDTMMemTop.io_dut_imem_ready -> 1 [info] [0.032] EXPECT SimDTMMemTop.io_dut_imem_ready -> 1 == 1 PASS [info] [0.032] PEEK SimDTMMemTop.io_dut_imem_r_valid -> 1 [info] [0.032] EXPECT SimDTMMemTop.io_dut_imem_r_valid -> 1 == 1 PASS [info] [0.032] PEEK SimDTMMemTop.io_dut_imem_r_data -> 2097555 [info] [0.032] EXPECT SimDTMMemTop.io_dut_imem_r_data -> 2097555 == -1044845 FAIL ***** [info] [0.033] PEEK SimDTMMemTop.io_dut_imem_r_resp -> 0 [info] [0.033] EXPECT SimDTMMemTop.io_dut_imem_r_resp -> 0 == 0 PASS [info] [0.033] STEP 21 -> 22 [info] [0.033] POKE SimDTMMemTop.io_dut_imem_valid <- 1 [info] [0.033] POKE SimDTMMemTop.io_dut_imem_addr <- 16 [info] [0.034] POKE SimDTMMemTop.io_dut_imem_cmd <- 0 [info] [0.034] POKE SimDTMMemTop.io_dut_imem_r_ready <- 1 [info] [0.034] PEEK SimDTMMemTop.io_dut_imem_ready -> 1 [info] [0.034] EXPECT SimDTMMemTop.io_dut_imem_ready -> 1 == 1 PASS [info] [0.034] PEEK SimDTMMemTop.io_dut_imem_r_valid -> 1 [info] [0.034] EXPECT SimDTMMemTop.io_dut_imem_r_valid -> 1 == 1 PASS [info] [0.034] PEEK SimDTMMemTop.io_dut_imem_r_data -> 2097555 [info] [0.034] EXPECT SimDTMMemTop.io_dut_imem_r_data -> 2097555 == 2097555 PASS [info] [0.034] PEEK SimDTMMemTop.io_dut_imem_r_resp -> 0 [info] [0.035] EXPECT SimDTMMemTop.io_dut_imem_r_resp -> 0 == 0 PASS
STEP19 -> 20 / STEP 20 -> 21がFAILしている。FAILしてるのにPASSってなんでだろう、、、ともってテストを確認してたところ、テスト結果判定の構文が抜けていた。
set_imem(true, 0x10, MemCmd.rd, true) comp_imem(true, true, wrData(3), MemResp.ok) step(1) idle(10) } } // ここにテスト結果を確認する "should be (true)"が必要
should be (true) を付与して再度実行
修正して流した結果は以下の通り、ちゃんとFAILすることが確認できた。
[info] [0.028] RAN 33 CYCLES FAILED FIRST AT CYCLE 18 [info] MemTopTester: [info] MemTopTester [info] - should keep Mbus.r.valid high if Mbus r.ready is Low. [MemTopTester-BUG-100] *** FAILED *** [info] false was not true (MemTopTester.scala:308) [info] ScalaTest [info] Run completed in 3 seconds, 657 milliseconds. [info] Total number of tests run: 1 [info] Suites: completed 1, aborted 0 [info] Tests: succeeded 0, failed 1, canceled 0, ignored 0, pending 0 [info] *** 1 TEST FAILED ***
ということで「当たり前だろー、そんなのー」という声が聞こえてきそうですがshould be (true)
忘れてプチハマりした話でした。やっぱりもう少しScalaTest自体の仕組みを学ばければと思う一件だった。。。