From 60cb5b8dfaef207bf267bc968586ecee5e2dc1d8 Mon Sep 17 00:00:00 2001 From: Hendiadyoin1 Date: Thu, 3 Feb 2022 12:42:41 +0100 Subject: [PATCH] UserspaceEmulator: Add more FIXMES to SoftFPU This also includes an exception check for sqrt and two pow(2,...) -> exp2(...) changes. --- .../DevTools/UserspaceEmulator/SoftFPU.cpp | 53 ++++++++++++------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/Userland/DevTools/UserspaceEmulator/SoftFPU.cpp b/Userland/DevTools/UserspaceEmulator/SoftFPU.cpp index 8b475ad280..1cc48b66fd 100644 --- a/Userland/DevTools/UserspaceEmulator/SoftFPU.cpp +++ b/Userland/DevTools/UserspaceEmulator/SoftFPU.cpp @@ -400,7 +400,6 @@ void SoftFPU::FBSTP_M80(const X86::Instruction&) { TODO_INSN(); } void SoftFPU::FXCH(const X86::Instruction& insn) { - // FIXME: implicit argument `D9 C9` -> st[0] <-> st[1]? VERIFY(insn.modrm().is_register()); set_c1(0); auto tmp = fpu_get(0); @@ -520,6 +519,7 @@ void SoftFPU::FSUB_RM32(const X86::Instruction& insn) void SoftFPU::FSUB_RM64(const X86::Instruction& insn) { if (insn.modrm().is_register()) { + // Note: This is FSUBR (DC E8+i FSUBR st(i) st(0)) in the spec fpu_set(insn.modrm().register_index(), fpu_get(insn.modrm().register_index()) - fpu_get(0)); } else { auto new_f64 = insn.modrm().read64(m_cpu, insn); @@ -549,6 +549,7 @@ void SoftFPU::FSUBR_RM32(const X86::Instruction& insn) void SoftFPU::FSUBR_RM64(const X86::Instruction& insn) { if (insn.modrm().is_register()) { + // Note: This is FSUB (DC E0+i FSUB st(i) st(0)) in the spec fpu_set(insn.modrm().register_index(), fpu_get(insn.modrm().register_index()) - fpu_get(0)); } else { auto new_f64 = insn.modrm().read64(m_cpu, insn); @@ -655,6 +656,7 @@ void SoftFPU::FDIV_RM32(const X86::Instruction& insn) void SoftFPU::FDIV_RM64(const X86::Instruction& insn) { if (insn.modrm().is_register()) { + // Note: This is FDIVR (DC F0+i FDIVR st(i) st(0)) in the spec fpu_set(insn.modrm().register_index(), fpu_get(insn.modrm().register_index()) / fpu_get(0)); } else { auto new_f64 = insn.modrm().read64(m_cpu, insn); @@ -687,8 +689,7 @@ void SoftFPU::FDIVR_RM32(const X86::Instruction& insn) void SoftFPU::FDIVR_RM64(const X86::Instruction& insn) { if (insn.modrm().is_register()) { - // XXX this is FDIVR, Instruction decodes this weirdly - // fpu_set(insn.modrm().register_index(), fpu_get(0) / fpu_get(insn.modrm().register_index())); + // Note: This is FDIV (DC F8+i FDIV st(i) st(0)) in the spec fpu_set(insn.modrm().register_index(), fpu_get(insn.modrm().register_index()) / fpu_get(0)); } else { auto new_f64 = insn.modrm().read64(m_cpu, insn); @@ -742,7 +743,8 @@ void SoftFPU::FIDIVR_RM32(const X86::Instruction& insn) void SoftFPU::FPREM(const X86::Instruction&) { - // FIXME: There are some exponent shenanigans supposed to be here + // FIXME: FPREM should only be able to reduce top's exponent by a maximum + // amount of 32-63 (impl-specific) long double top = fpu_get(0); long double one = fpu_get(1); @@ -757,7 +759,8 @@ void SoftFPU::FPREM(const X86::Instruction&) } void SoftFPU::FPREM1(const X86::Instruction&) { - // FIXME: There are some exponent shenanigans supposed to be here + // FIXME: FPREM1 should only be able to reduce top's exponent by a maximum + // amount of 32-63 (impl-specific) long double top = fpu_get(0); long double one = fpu_get(1); @@ -783,19 +786,22 @@ void SoftFPU::FCHS(const X86::Instruction&) void SoftFPU::FRNDINT(const X86::Instruction&) { + // FIXME: Raise #IA #D auto res = fpu_round_checked(fpu_get(0)); fpu_set(0, res); } void SoftFPU::FSCALE(const X86::Instruction&) { - // FIXME: set C1 upon stack overflow or if result was rounded - fpu_set(0, fpu_get(0) * powl(2, truncl(fpu_get(1)))); + // FIXME: Raise #IA #D #U #O #P + fpu_set(0, fpu_get(0) * exp2l(truncl(fpu_get(1)))); } void SoftFPU::FSQRT(const X86::Instruction&) { - // FIXME: set C1 upon stack overflow or if result was rounded + // FIXME: Raise #IA #D #P + if (fpu_get(0) < 0) + fpu_set_exception(FPU_Exception::InvalidOperation); fpu_set(0, sqrtl(fpu_get(0))); } @@ -993,20 +999,26 @@ void SoftFPU::FXAM(const X86::Instruction&) // TRANSCENDENTAL void SoftFPU::FSIN(const X86::Instruction&) { - // FIXME: set C1 upon stack overflow or if result was rounded + // FIXME: Raise #IA #D #P + // FIXME: Set C1 on when result was rounded up, cleared otherwise // FIXME: Set C2 to 1 if ST(0) is outside range of -2^63 to +2^63; else set to 0 + // ST(0) shall remain unchanged in this case fpu_set(0, sinl(fpu_get(0))); } void SoftFPU::FCOS(const X86::Instruction&) { - // FIXME: set C1 upon stack overflow or if result was rounded + // FIXME: Raise #IA #D #P + // FIXME: Set C1 on when result was rounded up, cleared otherwise // FIXME: Set C2 to 1 if ST(0) is outside range of -2^63 to +2^63; else set to 0 + // ST(0) shall remain unchanged in this case fpu_set(0, cosl(fpu_get(0))); } void SoftFPU::FSINCOS(const X86::Instruction&) { - // FIXME: set C1 upon stack overflow or if result was rounded - // FIXME: Set C2 to 1 if ST(0) is outside range of -2^63 to +2^63; else set to 0s + // FIXME: Raise #IA #D #P + // FIXME: Set C1 on when result was rounded up, cleared otherwise + // FIXME: Set C2 to 1 if ST(0) is outside range of -2^63 to +2^63; else set to 0 + // ST(0) shall remain unchanged in this case long double sin = sinl(fpu_get(0)); long double cos = cosl(fpu_get(0)); fpu_set(0, sin); @@ -1015,25 +1027,30 @@ void SoftFPU::FSINCOS(const X86::Instruction&) void SoftFPU::FPTAN(const X86::Instruction&) { - // FIXME: set C1 upon stack overflow or if result was rounded + // FIXME: Raise #IA #D #U #P + // FIXME: Set C1 on when result was rounded up, cleared otherwise // FIXME: Set C2 to 1 if ST(0) is outside range of -2^63 to +2^63; else set to 0 + // ST(0) shall remain unchanged in this case fpu_set(0, tanl(fpu_get(0))); fpu_push(1.0f); } void SoftFPU::FPATAN(const X86::Instruction&) { - // FIXME: set C1 on stack underflow, or on rounding - // FIXME: Exceptions + // FIXME: Raise #IA #D #U #P + // FIXME: Set C1 on when result was rounded up, cleared otherwise + // Note: Not implemented 80287 quirk: + // Restriction to 0 ≤ |ST(1)| < |ST(0)| < +∞ fpu_set(1, atan2l(fpu_get(1), fpu_get(0))); fpu_pop(); } void SoftFPU::F2XM1(const X86::Instruction&) { - // FIXME: validate ST(0) is in range –1.0 to +1.0 + // FIXME: Raise #IA #D #U #P + // FIXME: Set C1 on when result was rounded up, cleared otherwise + // FIXME: Validate ST(0) is in range –1.0 to +1.0 auto val = fpu_get(0); - // FIXME: Set C0, C2, C3 in FPU status word. - fpu_set(0, powl(2, val) - 1.0l); + fpu_set(0, exp2(val) - 1.0l); } void SoftFPU::FYL2X(const X86::Instruction&) {