Binary Translation型エミュレータにおいてシフト命令を実装した。Binary Translation型エミュレータでは、ゲストマシンの命令(今回はRISC-V)からホストマシンの命令(今回はx86)に直接変換することで高速実行を可能にするシミュレータだ。
CSR命令などのPrivileged命令の実装もかなり進んできたので、RISC-Vが提供しているテストパタンも動作するはずだ。今回はriscv-tests
のテストパタンのうち最も簡単なrv64ui-p-simple
をPassさせることに挑戦しよう。
https://github.com/riscv/riscv-tests
rv64ui-p-simple
のコンパイル方法はあまり本質的ではないので省略。このテストパタンは何かをテストするわけではなく、単純にブートコードが動いてFinishするだけである。ブートコードの動きを簡単に追いかけてみる。
start
から始まるテストパタンは、reset_vector
にジャンプする。
0000000080000000 <_start>: 80000000: 04c0006f j 8000004c <reset_vector>
reset_vector
はいくつかのシステムレジスタを設定している。まずはmhartid
の設定。もしHartIDが0ではなかったら、初期化プロセスを実行する必要はない(というか無限ループに入り割り込みを待つ状態になる)。
8000004c: f1402573 csrr a0,mhartid 80000050: 00051063 bnez a0,80000050 <reset_vector+0x4>
mtvec
、satp
、pmpaddr0
、pmpcfg0
、medeleg
、mideleg
、mie
の設定を行う。
80000054: 00000297 auipc t0,0x0 80000058: 01028293 addi t0,t0,16 # 80000064 <reset_vector+0x18> 8000005c: 30529073 csrw mtvec,t0 80000060: 18005073 csrwi satp,0 80000064: 00000297 auipc t0,0x0 80000068: 01c28293 addi t0,t0,28 # 80000080 <reset_vector+0x34> 8000006c: 30529073 csrw mtvec,t0 80000070: fff00293 li t0,-1 80000074: 3b029073 csrw pmpaddr0,t0 80000078: 01f00293 li t0,31 8000007c: 3a029073 csrw pmpcfg0,t0 80000080: 00000297 auipc t0,0x0 80000084: 01828293 addi t0,t0,24 # 80000098 <reset_vector+0x4c> 80000088: 30529073 csrw mtvec,t0 8000008c: 30205073 csrwi medeleg,0 80000090: 30305073 csrwi mideleg,0 80000094: 30405073 csrwi mie,0
次はRV64の確認かな?32ビットレジスタならマイナス値になるのでエラーとなる。そうでなければ次の設定に進む。
80000098: 00000193 li gp,0 8000009c: 00000297 auipc t0,0x0 800000a0: f6828293 addi t0,t0,-152 # 80000004 <trap_vector> 800000a4: 30529073 csrw mtvec,t0 800000a8: 00100513 li a0,1 800000ac: 01f51513 slli a0,a0,0x1f 800000b0: 00055863 bgez a0,800000c0 <reset_vector+0x74> 800000b4: 0ff0000f fence
さらに設定を続ける。stvec
、 medeleg
、mstatus
などの設定を行う。
800000c0: 80000297 auipc t0,0x80000 800000c4: f4028293 addi t0,t0,-192 # 0 <_start-0x80000000> 800000c8: 00028e63 beqz t0,800000e4 <reset_vector+0x98> 800000cc: 10529073 csrw stvec,t0 800000d0: 0000b2b7 lui t0,0xb 800000d4: 1092829b addiw t0,t0,265 800000d8: 30229073 csrw medeleg,t0 800000dc: 30202373 csrr t1,medeleg 800000e0: f4629ee3 bne t0,t1,8000003c <handle_exception> 800000e4: 30005073 csrwi mstatus,0
mepc
に0x800000fc
を設定しmret
する。つまりPC=0x800000fcにジャンプすることになる。
800000e8: 00000297 auipc t0,0x0 800000ec: 01428293 addi t0,t0,20 # 800000fc <reset_vector+0xb0> 800000f0: 34129073 csrw mepc,t0 800000f4: f1402573 csrr a0,mhartid 800000f8: 30200073 mret
最後にecall
によってジャンプする。ecall
はmepc
を使用し、これには0x00000004
が設定されているので、trap_vector
にジャンプする。また、あらかじめgp
に1が設定されている。
800000fc: 0ff0000f fence 80000100: 00100193 li gp,1 80000104: 00000073 ecall 80000108: c0001073 unimp
trap_vector
では、mcause
の内容をチェックし、想定している例外要因コード(今回は0x0b)であればwrite_tohost
にジャンプする。
0000000080000004 <trap_vector>: 80000004: 34202f73 csrr t5,mcause 80000008: 00800f93 li t6,8 8000000c: 03ff0a63 beq t5,t6,80000040 <write_tohost> 80000010: 00900f93 li t6,9 80000014: 03ff0663 beq t5,t6,80000040 <write_tohost> 80000018: 00b00f93 li t6,11 8000001c: 03ff0263 beq t5,t6,80000040 <write_tohost> 80000020: 80000f17 auipc t5,0x80000 80000024: fe0f0f13 addi t5,t5,-32 # 0 <_start-0x80000000> 80000028: 000f0463 beqz t5,80000030 <trap_vector+0x2c> 8000002c: 000f0067 jr t5 80000030: 34202f73 csrr t5,mcause 80000034: 000f5463 bgez t5,8000003c <handle_exception> 80000038: 0040006f j 8000003c <handle_exception>
write_tohost
ではtohost
セクションに最終結果を書き込む。gp
はあらかじめ1に設定されているので1がメモリにストアされる。最後にこれを無限ループで繰り返す。
0000000080000040 <write_tohost>: 80000040: 00001f17 auipc t5,0x1 80000044: fc3f2023 sw gp,-64(t5) # 80001000 <tohost> 80000048: ff9ff06f j 80000040 <write_tohost>
これまで実装した命令で、ここまでの機能をシミュレーションできるはずだ。さっそく実行してみる。
cargo run /home/msyksphinz/riscv64/riscv64-unknown-elf/share/riscv-tests/isa/rv64ui-p-simple
000000a0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 000000b0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 000000c0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 000000d0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 000000e0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 000000f0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 reflect tb address = 0x7f5239a80000 ans = 0x40 x00 = 0000000000000000 x01 = 0000000000000000 x02 = 0000000000000000 x03 = 0000000000000001 x04 = 0000000000000000 x05 = 00000000000000fc x06 = 000000000000b109 x07 = 0000000000000000 x08 = 0000000000000000 x09 = 0000000000000000 x10 = 0000000000000000 x11 = 0000000000000000 x12 = 0000000000000000 x13 = 0000000000000000 x14 = 0000000000000000 x15 = 0000000000000000 x16 = 0000000000000000 x17 = 0000000000000000 x18 = 0000000000000000 x19 = 0000000000000000 x20 = 0000000000000000 x21 = 0000000000000000 x22 = 0000000000000000 x23 = 0000000000000000 x24 = 0000000000000000 x25 = 0000000000000000 x26 = 0000000000000000 x27 = 0000000000000000 x28 = 0000000000000000 x29 = 0000000000000000 x30 = 0000000000001040 x31 = 000000000000000b PC = 0000000000000040
いいぞ。最後の0x40まで到達できた。テストパタンの実行は成功だ。やったぞ!
![f:id:msyksphinz:20200916000940p:plain f:id:msyksphinz:20200916000940p:plain](https://cdn-ak.f.st-hatena.com/images/fotolife/m/msyksphinz/20200916/20200916000940.png)