Chiselを使って、非常にシンプルなCPUを作ってみるプロジェクト。RISC-Vにはfromhostやtohostといったレジスタ(メモリマップドレジスタ)が定義されており、それを使用してシミュレーションの制御を行う。
このメモリマップドレジスタはだいたい0x1000あたりに定義されており、そこにストアした値が0であればPassでテスト終了、などといった条件でPass / Failを判定する。
テストパタンの終了条件は、Scalaのテストベンチ側に以下のように記述することで実現した。
import util.control.Breaks._ ... breakable { for (cycle <- 0 to 512) { val inst_valid = peek(cpu_tb.io.dbg_monitor.inst_valid) if (inst_valid == 1) { writer.printf("%10d : ".format(cycle)) val reg_wren = peek(cpu_tb.io.dbg_monitor.reg_wren) val reg_wraddr : Long = peek(cpu_tb.io.dbg_monitor.reg_wraddr).toLong val reg_wrdata : Long = peek(cpu_tb.io.dbg_monitor.reg_wrdata).toLong ... if (data_bus_req == 1 && data_bus_cmd == peek(CMD_WR) && data_bus_addr == 0x1000) { if (data_bus_wrdata == 0x1) { writer.printf(" PASS : Simulation Finished\n") } else { writer.printf(" FAIL : Simulation Finished\n") } break } }
ScalaにはどうやらデフォルトでBreakが無いらしく、util.control.Breaks
をインポートしてbreakしたいループをbreakable
で囲むらしい。
私の環境では、パイプライントレーサがメモリアクセスを監視しているので、CMD_WR
が出力され、かつ data_bus_addr == 0x1000
であるときは終了条件であるとし、ストアデータが0x1であればPass、それ以外であればFailとしてテストパタンを終了させることにした。
実行結果は以下となる。
make cpu_run && spike-dasm < pipetrace.log > pipetrace.dasm.log
- pipetrace.dasm.log
489 : x00<=0x0000000000000000 (15, 0000000000000000, 0000000000000000) : 0x0000060c : INST(0x00000073) : ecall 490 : x00<=0x0000000000000000 (21, 0000000000000000, 0000000000000000) : 0x00000610 : INST(0xc0001073) : csrw cycle, zero 491 : x30<=0x0000000000000008 (21, 0000000000000000, 0000000000000008) : 0x00000004 : INST(0x34202f73) : csrr t5, mcause 492 : x31<=0x0000000000000008 ( 1, 0000000000000000, 0000000000000008) : 0x00000008 : INST(0x00800f93) : li t6, 8 493 : : 0x0000000c : INST(0x03ff0a63) : beq t5, t6, pc + 52 495 : x30<=0x0000000000001040 ( 1, 0000000000001000, 0000000000000040) : 0x00000040 : INST(0x00001f17) : auipc t5, 0x1 496 : [00001000]<=0x0000000000000001 : 0x00000044 : INST(0xfc3f2023) : sw gp, -64(t5) PASS : Simulation Finished
無事にテストパタンがPassして、終了することが確認できた。