FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

Chiselを使ってCPUを作ろう(9. テストベンチを走らせる)

Chiselを使って、非常にシンプルなCPUを作ってみるプロジェクト、算術演算命令、ロード・ストア命令、CSR命令が多少動くようになってきたので、RISC-Vのテストパタンを動かしてみてもよさそうな気がしてくる。

f:id:msyksphinz:20181123005953p:plain

riscv-testesに乗っているテストパタンを動かしてどのようになるかチェックしてみたい。そのための環境を構築した。

riscv-testsのパタンはデフォルトだと0x80000000番地に構築されるので、テストパタンを修正して0x00000000番地から始まるように修正する。

diff --git a/isa/Makefile b/isa/Makefile
index 4e1ba20..ca329b6 100644
--- a/isa/Makefile
+++ b/isa/Makefile
@@ -35,6 +35,7 @@ RISCV_PREFIX ?= riscv$(XLEN)-unknown-elf-
 RISCV_GCC ?= $(RISCV_PREFIX)gcc
 RISCV_GCC_OPTS ?= -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles
 RISCV_OBJDUMP ?= $(RISCV_PREFIX)objdump --disassemble-all --disassemble-zeroes --section=.text --section=.text.startup --section=.text.init --section=.data
+RISCV_OBJCOPY ?= riscv64-unknown-elf-objcopy --gap-fill 0 -O binary
 RISCV_SIM ?= spike

 vpath %.S $(src_dir)
@@ -45,6 +46,10 @@ vpath %.S $(src_dir)
 %.dump: %
        $(RISCV_OBJDUMP) $< > $@

+%.hex: %
+       $(RISCV_OBJCOPY) $< $<.bin
+       od -tx4 -v -w4 -Ax $<.bin | sed 's/^/0x/g' | gawk -F ' ' '{printf "@%08x %s\n", rshift(strtonum($$1), 2), $$2}' > $@
+
 %.out: %
        $(RISCV_SIM) --isa=rv64gc $< 2> $@

@@ -102,7 +107,7 @@ junk += $(tests) $(tests_dump) $(tests_hex) $(tests_out) $(tests32_out)
 #------------------------------------------------------------
 # Default

-all: $(tests_dump)
+all: $(tests_dump) $(tests_hex)

これでテストを流してみると、トレースとしては以下のようになる。何となく流れているようだが、途中で止まっている。

        31 : x05<=0x00000000000000c0                                : 0x000000c0 : INST(0x00000297) : auipc   t0, 0x0
        32 : x05<=0x0000000000000000                                : 0x000000c4 : INST(0xf4028293) : addi    t0, t0, -192
        33 :                                                        : 0x000000c8 : INST(0x00028e63) : beqz    t0, pc + 28
        35 :                                                        : 0x000000e4 : INST(0x30005073) : csrwi   mstatus, 0
        36 : x05<=0x00000000000000e8                                : 0x000000e8 : INST(0x00000297) : auipc   t0, 0x0
        37 : x05<=0x00000000000000fc                                : 0x000000ec : INST(0x01428293) : addi    t0, t0, 20
        38 :                                                        : 0x000000f0 : INST(0x34129073) : csrw    mepc, t0
        39 : x10<=0x0000000000000000                                : 0x000000f4 : INST(0xf1402573) : csrr    a0, mhartid
        40 :                                                        : 0x000000f8 : INST(0x30200073) : mret
        42 : x01<=0x0000000000000000                                : 0x000000fc : INST(0x00000093) : li      ra, 0
        43 : x02<=0x0000000000000000                                : 0x00000100 : INST(0x00000113) : li      sp, 0
        44 : x30<=0x0000000000000000                                : 0x00000104 : INST(0x00208f33) : add     t5, ra, sp
        45 : x29<=0x0000000000000000                                : 0x00000108 : INST(0x00000e93) : li      t4, 0
        46 : x03<=0x0000000000000002                                : 0x0000010c : INST(0x00200193) : li      gp, 2
        47 :                                                        : 0x00000110 : INST(0x4fdf1063) : bne     t5, t4, pc + 1248
        48 : x01<=0x0000000000000001                                : 0x00000114 : INST(0x00100093) : li      ra, 1
        49 : x02<=0x0000000000000001                                : 0x00000118 : INST(0x00100113) : li      sp, 1
        50 : x30<=0x0000000000000002                                : 0x0000011c : INST(0x00208f33) : add     t5, ra, sp
        51 : x29<=0x0000000000000002                                : 0x00000120 : INST(0x00200e93) : li      t4, 2
        52 : x03<=0x0000000000000003                                : 0x00000124 : INST(0x00300193) : li      gp, 3
        53 :                                                        : 0x00000128 : INST(0x4ddf1463) : bne     t5, t4, pc + 1224
        54 : x01<=0x0000000000000003                                : 0x0000012c : INST(0x00300093) : li      ra, 3
        55 : x02<=0x0000000000000007                                : 0x00000130 : INST(0x00700113) : li      sp, 7...

この時に、mretなどの基本的な命令はサポートしておく必要がある。mretはあまり考えなければ単純で、次のPCをMEPCに設定するだけだ(権限の概念が存在しないCPUであれば)。

  when(if_inst_en & dec_jalr_en) {
    if_inst_addr := dec_reg_op0.asUInt
  } .elsewhen (if_inst_en & dec_jal_en) {
    if_inst_addr := dec_inst_addr + dec_imm_j
  } .elsewhen (if_inst_en & dec_br_en) {
    if_inst_addr := dec_inst_addr + dec_imm_b_sext
  } .elsewhen (if_inst_en & dec_mret_en) {
    if_inst_addr := u_csrfile.io.mepc
  } .elsewhen(if_inst_en & io.inst_bus.ack) {
    if_inst_addr := if_inst_addr + 4.U
  }

上記のwhen文の羅列は、MuxCaseで書くこともできるらしい。以下と等価だ。

  if_inst_addr := MuxCase (0.U, Array (
    (if_inst_en & dec_jalr_en) -> dec_reg_op0.asUInt,
    (if_inst_en & dec_jal_en)  -> (dec_inst_addr + dec_imm_j),
    (if_inst_en & dec_br_en)   -> (dec_inst_addr + dec_imm_b_sext),
    (if_inst_en & dec_mret_en) -> u_csrfile.io.mepc,
    (if_inst_en & io.inst_bus.ack) -> (if_inst_addr + 4.U)
  ))