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