From 12d923bb7eeb99a116ef15084fa19959ec236ddb Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sat, 14 Nov 2020 23:43:31 +0100 Subject: [PATCH] UserspaceEmulator: Fix some FPU instructions' handling of RM32/RM64 m32int is a 32-bit integer stored in memory, and should not be mistaken for a floating point number. :^) Also add missing handling of 64-bit FPU register operands to some of the RM64 instructions. --- DevTools/UserspaceEmulator/SoftCPU.cpp | 74 +++++++++++++++++--------- 1 file changed, 48 insertions(+), 26 deletions(-) diff --git a/DevTools/UserspaceEmulator/SoftCPU.cpp b/DevTools/UserspaceEmulator/SoftCPU.cpp index 4774c47ef6..a6e7a99171 100644 --- a/DevTools/UserspaceEmulator/SoftCPU.cpp +++ b/DevTools/UserspaceEmulator/SoftCPU.cpp @@ -1635,15 +1635,24 @@ void SoftCPU::FSIN(const X86::Instruction&) } void SoftCPU::FCOS(const X86::Instruction&) { TODO_INSN(); } -void SoftCPU::FIADD_RM32(const X86::Instruction&) { TODO_INSN(); } + +void SoftCPU::FIADD_RM32(const X86::Instruction& insn) +{ + ASSERT(!insn.modrm().is_register()); + auto m32int = (i32)insn.modrm().read32(*this, insn).value(); + // FIXME: Respect shadow values + auto f64 = (long double)m32int; + fpu_set(0, fpu_get(0) - f64); +} + void SoftCPU::FCMOVB(const X86::Instruction&) { TODO_INSN(); } void SoftCPU::FIMUL_RM32(const X86::Instruction& insn) { ASSERT(!insn.modrm().is_register()); - auto new_s32 = insn.modrm().read32(*this, insn); + auto m32int = (i32)insn.modrm().read32(*this, insn).value(); // FIXME: Respect shadow values - fpu_set(0, fpu_get(0) * (long double)(int32_t)new_s32.value()); + fpu_set(0, fpu_get(0) * (long double)m32int); } void SoftCPU::FCMOVE(const X86::Instruction&) { TODO_INSN(); } @@ -1660,15 +1669,11 @@ void SoftCPU::FCMOVU(const X86::Instruction&) { TODO_INSN(); } void SoftCPU::FISUB_RM32(const X86::Instruction& insn) { - if (insn.modrm().is_register()) { - fpu_set(0, fpu_get(insn.modrm().register_index()) - fpu_get(0)); - } else { - auto new_f32 = insn.modrm().read32(*this, insn); - // FIXME: Respect shadow values - auto f32 = bit_cast(new_f32.value()); - auto f64 = (double)f32; - fpu_set(0, fpu_get(0) - f64); - } + ASSERT(!insn.modrm().is_register()); + auto m32int = (i32)insn.modrm().read32(*this, insn).value(); + // FIXME: Respect shadow values + auto f64 = (long double)m32int; + fpu_set(0, fpu_get(0) - f64); } void SoftCPU::FISUBR_RM32(const X86::Instruction&) { TODO_INSN(); } @@ -1678,10 +1683,10 @@ void SoftCPU::FIDIV_RM32(const X86::Instruction&) { TODO_INSN(); } void SoftCPU::FIDIVR_RM32(const X86::Instruction& insn) { ASSERT(!insn.modrm().is_register()); - auto new_s32 = insn.modrm().read32(*this, insn); + auto m32int = (i32)insn.modrm().read32(*this, insn).value(); // FIXME: Respect shadow values // FIXME: Raise IA on 0 / _=0, raise Z on finite / +-0 - fpu_set(0, (long double)(int32_t)new_s32.value() / fpu_get(0)); + fpu_set(0, (long double)m32int / fpu_get(0)); } void SoftCPU::FILD_RM32(const X86::Instruction& insn) @@ -1791,25 +1796,42 @@ void SoftCPU::FMUL_RM64(const X86::Instruction& insn) void SoftCPU::FCOM_RM64(const X86::Instruction&) { TODO_INSN(); } void SoftCPU::FCOMP_RM64(const X86::Instruction&) { TODO_INSN(); } -void SoftCPU::FSUB_RM64(const X86::Instruction&) { TODO_INSN(); } + +void SoftCPU::FSUB_RM64(const X86::Instruction& insn) +{ + if (insn.modrm().is_register()) { + fpu_set(insn.modrm().register_index(), fpu_get(insn.modrm().register_index()) - fpu_get(0)); + } else { + auto new_f64 = insn.modrm().read64(*this, insn); + // FIXME: Respect shadow values + auto f64 = bit_cast(new_f64.value()); + fpu_set(0, fpu_get(0) - f64); + } +} void SoftCPU::FSUBR_RM64(const X86::Instruction& insn) { - ASSERT(!insn.modrm().is_register()); // FIXME - auto new_f64 = insn.modrm().read64(*this, insn); - // FIXME: Respect shadow values - auto f64 = bit_cast(new_f64.value()); - fpu_set(0, f64 - fpu_get(0)); + if (insn.modrm().is_register()) { + fpu_set(insn.modrm().register_index(), fpu_get(insn.modrm().register_index()) - fpu_get(0)); + } else { + auto new_f64 = insn.modrm().read64(*this, insn); + // FIXME: Respect shadow values + auto f64 = bit_cast(new_f64.value()); + fpu_set(0, f64 - fpu_get(0)); + } } void SoftCPU::FDIV_RM64(const X86::Instruction& insn) { - ASSERT(!insn.modrm().is_register()); // FIXME - auto new_f64 = insn.modrm().read64(*this, insn); - // FIXME: Respect shadow values - auto f64 = bit_cast(new_f64.value()); - // FIXME: Raise IA on + infinity / +-infinitiy, +-0 / +-0, raise Z on finite / +-0 - fpu_set(0, fpu_get(0) / f64); + if (insn.modrm().is_register()) { + fpu_set(insn.modrm().register_index(), fpu_get(insn.modrm().register_index()) / fpu_get(0)); + } else { + auto new_f64 = insn.modrm().read64(*this, insn); + // FIXME: Respect shadow values + auto f64 = bit_cast(new_f64.value()); + // FIXME: Raise IA on + infinity / +-infinitiy, +-0 / +-0, raise Z on finite / +-0 + fpu_set(0, fpu_get(0) / f64); + } } void SoftCPU::FDIVR_RM64(const X86::Instruction& insn)