Binary Translation型エミュレータにおいてシフト命令を実装した。Binary Translation型エミュレータでは、ゲストマシンの命令(今回はRISC-V)からホストマシンの命令(今回はx86)に直接変換することで高速実行を可能にするシミュレータだ。
前回ついにriscv-tests
のrv64ui-p-simple
をPassさせることに成功した。大きな一歩だ。少しずつ別のテストパタンをPassさせるべくサポートを増やしていこう。次はrv64ui-p-add
のサポートだ。
このテストパタンはRISC-VのADD
命令についてのテストを行う。多くのテストは対象となる命令を実行して、その結果を想定する値と比較するようになっている。もしテストに失敗するとテスト番号をレジスタに保存して終了するのでそれを確認する。
多くのテストパタンについては、実装し忘れた詳細な部分については少しずつ修正を加えるものの、その中でどうしてもADDIW
命令を正しく実装する必要があった。ADDIW
命令はRV64で定義されている命令で、64ビットレジスタの中で下位32ビットを使用する。このため、演算自体は64ビットでも良いが、最後に計算結果のうち32ビットを符号拡張して64ビットに変換する必要がある。
符号拡張はどのようにX86で実現すればよいかについて調査していると、どうやらX86には符号拡張の専用命令があるらしい。しかもAレジスタ専用だ。
$ cstool -d x64 "48 98" 0 48 98 cdqe Prefix:0x00 0x00 0x00 0x00 Opcode:0x98 0x00 0x00 0x00 rex: 0x48 addr_size: 8 modrm: 0x0 disp: 0x0 sib: 0x0 Registers read: eax Registers modified: rax
ADDIW命令のTCGからX86命令への変換プロセスでは、レジスタに計算結果を格納する前にこの命令を挿入する。
fn tcg_gen_store_gpr_32bit( emu: &EmuEnv, source: X86TargetRM, dest: u64, mc: &mut Vec<u8>, ) -> usize { let mut gen_size = 0; gen_size += Self::tcg_64bit_out(X86Opcode::SIGN_EXT_A, mc); gen_size += Self::tcg_modrm_64bit_out(X86Opcode::MOV_EV_GV, X86ModRM::MOD_10_DISP_RBP, source, mc); gen_size += Self::tcg_out(emu.calc_gpr_relat_address(dest) as u64, 4, mc); return gen_size; }
この結果、rv64ui-p-add
については最後までテストをPassさせることができたようだ!やったぜ!
$ cargo run /home/msyksphinz/riscv64/riscv64-unknown-elf/share/riscv-tests/isa/rv64ui-p-addi
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 = 0x7fd7fa950000 ans = 0x40 x00 = 0000000000000000 x01 = 0000000000000010 x02 = 000000000000001e x03 = 0000000000000001 x04 = 0000000000000002 x05 = 0000000000000002 x06 = 000000000000001a 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 Result: MEM[0x1000] = 00000001
最後に0x1000に1が格納されており、テストがPassしていることが確認できる。そしてついでにrv64ui-p-addiw
も確認しておく。
$ cargo run /home/msyksphinz/riscv64/riscv64-unknown-elf/share/riscv-tests/isa/rv64ui-p-addiw
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 = 0x7fce62d20000 ans = 0x40 x00 = 0000000000000000 x01 = 0000000000000021 x02 = 0000000000000000 x03 = 0000000000000001 x04 = 0000000000000002 x05 = 0000000000000002 x06 = 0000000000000016 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 Result: MEM[0x1000] = 00000001