Binary Translation方式のエミュレータをRustで作る実装、浮動小数点命令を実装している。倍精度の命令についてはおおよそ実装が完了したので、次は単精度の命令を実装したい。実装方針は全く同一で、単精度の命令についてサポート関数を追加していけばよい。
下記が単精度版だ。倍精度版と比較してみる。
pub fn helper_func_fadd_s(emu: &mut EmuEnv, fd: u32, fs1: u32, fs2: u32, _dummy: u32) -> usize { println!("fadd(emu, {:}, {:}, {:}) is called!", fd, fs1, fs2); let fs1_data = F32::from_bits((emu.m_fregs[fs1 as usize] & 0xffffffff) as u32); let fs2_data = F32::from_bits((emu.m_fregs[fs2 as usize] & 0xffffffff) as u32); let mut flag = ExceptionFlags::default(); flag.set(); let fd_data = fs1_data.add(fs2_data, RoundingMode::TiesToEven); flag.get(); let ret_flag = flag.bits(); emu.m_fregs[fd as usize] = fd_data.bits() as u64; emu.m_csr.csrrw(CsrAddr::FFlags, ret_flag as i64); return 0; } pub fn helper_func_fadd_d(emu: &mut EmuEnv, fd: u32, fs1: u32, fs2: u32, _dummy: u32) -> usize { println!("fadd(emu, {:}, {:}, {:}) is called!", fd, fs1, fs2); let fs1_data = F64::from_bits(emu.m_fregs[fs1 as usize]); let fs2_data = F64::from_bits(emu.m_fregs[fs2 as usize]); let mut flag = ExceptionFlags::default(); flag.set(); let fd_data = fs1_data.add(fs2_data, RoundingMode::TiesToEven); flag.get(); let ret_flag = flag.bits(); emu.m_fregs[fd as usize] = fd_data.bits() as u64; emu.m_csr.csrrw(CsrAddr::FFlags, ret_flag as i64); return 0; }
データ型で演算をすべてラップすることができたので、実装はほとんど同一になっている。これだったらもっとまとめるように記述すればよかったかも。
とりあえず同様の手法で倍精度命令のために定義したすべての関数を単精度にも移植した。
RiscvInstId::FADD_S => TranslateRiscv::translate_fadd_s(inst), RiscvInstId::FSUB_S => TranslateRiscv::translate_fsub_s(inst), RiscvInstId::FMUL_S => TranslateRiscv::translate_fmul_s(inst), RiscvInstId::FDIV_S => TranslateRiscv::translate_fdiv_s(inst), RiscvInstId::FMADD_S => TranslateRiscv::translate_fmadd_s(inst), RiscvInstId::FMSUB_S => TranslateRiscv::translate_fmsub_s(inst), RiscvInstId::FNMSUB_S => TranslateRiscv::translate_fnmsub_s(inst), RiscvInstId::FNMADD_S => TranslateRiscv::translate_fnmadd_s(inst), ...
テストを通してみる。いつも通りのriscv-tests
で単精度関連のテストを追加し、実行してみた。
$ cargo run /home/msyksphinz/riscv64/riscv64-unknown-elf/share/riscv-tests/isa/rv64uf-p-fadd
... 000000d0 : 03 00 00 00 00 00 00 00 48 ba 00 00 00 00 00 00 000000e0 : 00 00 48 b9 01 00 00 00 00 00 00 00 ff 95 b8 03 000000f0 : 00 00 8b 85 20 01 00 00 48 98 48 89 85 58 00 00 reflect tb address = 0x7f257e710000 fadd(emu, 3, 0, 1) is called! csrrw = 0000000000000000 helper_csrrw(emu, 11, 0, 0x001) is called! csrrw = 0000000000000000 x00 = 0000000000000000 x01 = 0000000000000000 x02 = 0000000000000000 x03 = 0000000000000002 x04 = 0000000000000000 x05 = 0000000000000108 x06 = 000000000000b109 x07 = 0000000000000000 x08 = 0000000000000000 x09 = 0000000000000000 x10 = 0000000040600000 x11 = 0000000000000000 x12 = 0000000000000000 x13 = 0000000040600000 x14 = 0000000000000000 x15 = 0000000000000000 ...
fadd()
のサポート関数が呼ばれている。上手く行っているようだ。テストもすべてPassできることを確認できた。
$ cargo test
test result: ok. 60 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out Doc-tests uint_execute running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out