diff options
author | Hendiadyoin1 <leon2002.la@gmail.com> | 2021-07-10 16:21:06 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-07-22 23:33:21 +0200 |
commit | 7da12f0faf0a9af7bb69f89539a04fa2a63745ef (patch) | |
tree | 3e509582e4f77b4071f65bc2ff0ceef3f169b41e /Userland/DevTools/UserspaceEmulator | |
parent | 45d0f84a273ab6ead8aefd32056cbc2c36ad5868 (diff) | |
download | serenity-7da12f0faf0a9af7bb69f89539a04fa2a63745ef.zip |
UserspaceEmulator: Move to using the new SoftFPU
Diffstat (limited to 'Userland/DevTools/UserspaceEmulator')
-rw-r--r-- | Userland/DevTools/UserspaceEmulator/CMakeLists.txt | 3 | ||||
-rw-r--r-- | Userland/DevTools/UserspaceEmulator/SoftCPU.cpp | 1016 | ||||
-rw-r--r-- | Userland/DevTools/UserspaceEmulator/SoftCPU.h | 50 |
3 files changed, 202 insertions, 867 deletions
diff --git a/Userland/DevTools/UserspaceEmulator/CMakeLists.txt b/Userland/DevTools/UserspaceEmulator/CMakeLists.txt index f3b67312e7..224e837f8f 100644 --- a/Userland/DevTools/UserspaceEmulator/CMakeLists.txt +++ b/Userland/DevTools/UserspaceEmulator/CMakeLists.txt @@ -14,9 +14,12 @@ set(SOURCES Region.cpp SimpleRegion.cpp SoftCPU.cpp + SoftFPU.cpp SoftMMU.cpp main.cpp ) +add_compile_options(-mmmx) + serenity_bin(UserspaceEmulator) target_link_libraries(UserspaceEmulator LibX86 LibDebug LibCore LibPthread LibLine) diff --git a/Userland/DevTools/UserspaceEmulator/SoftCPU.cpp b/Userland/DevTools/UserspaceEmulator/SoftCPU.cpp index 6063d812ef..a2b325d5b4 100644 --- a/Userland/DevTools/UserspaceEmulator/SoftCPU.cpp +++ b/Userland/DevTools/UserspaceEmulator/SoftCPU.cpp @@ -26,6 +26,12 @@ _exit(0); \ } while (0) +#define FPU_INSTRUCTION(name) \ + void SoftCPU::name(const X86::Instruction& insn) \ + { \ + m_fpu.name(insn); \ + } + #define DEFINE_GENERIC_SHIFT_ROTATE_INSN_HANDLERS(mnemonic, op) \ void SoftCPU::mnemonic##_RM8_1(const X86::Instruction& insn) { generic_RM8_1(op<ValueWithShadow<u8>>, insn); } \ void SoftCPU::mnemonic##_RM8_CL(const X86::Instruction& insn) { generic_RM8_CL(op<ValueWithShadow<u8>>, insn); } \ @@ -66,6 +72,7 @@ constexpr T sign_extended_to(U value) SoftCPU::SoftCPU(Emulator& emulator) : m_emulator(emulator) + , m_fpu(emulator, *this) { memset(m_gpr, 0, sizeof(m_gpr)); memset(m_gpr_shadow, 1, sizeof(m_gpr_shadow)); @@ -1439,777 +1446,126 @@ void SoftCPU::ESCAPE(const X86::Instruction&) m_emulator.dump_backtrace(); TODO(); } +FPU_INSTRUCTION(FADD_RM32); +FPU_INSTRUCTION(FMUL_RM32); +FPU_INSTRUCTION(FCOM_RM32); +FPU_INSTRUCTION(FCOMP_RM32); +FPU_INSTRUCTION(FSUB_RM32); +FPU_INSTRUCTION(FSUBR_RM32); +FPU_INSTRUCTION(FDIV_RM32); +FPU_INSTRUCTION(FDIVR_RM32); +FPU_INSTRUCTION(FLD_RM32); +FPU_INSTRUCTION(FXCH); +FPU_INSTRUCTION(FST_RM32); +FPU_INSTRUCTION(FNOP); +FPU_INSTRUCTION(FSTP_RM32); +FPU_INSTRUCTION(FLDENV); +FPU_INSTRUCTION(FCHS); +FPU_INSTRUCTION(FABS); +FPU_INSTRUCTION(FTST); +FPU_INSTRUCTION(FXAM); +FPU_INSTRUCTION(FLDCW); +FPU_INSTRUCTION(FLD1); +FPU_INSTRUCTION(FLDL2T); +FPU_INSTRUCTION(FLDL2E); +FPU_INSTRUCTION(FLDPI); +FPU_INSTRUCTION(FLDLG2); +FPU_INSTRUCTION(FLDLN2); +FPU_INSTRUCTION(FLDZ); +FPU_INSTRUCTION(FNSTENV); +FPU_INSTRUCTION(F2XM1); +FPU_INSTRUCTION(FYL2X); +FPU_INSTRUCTION(FPTAN); +FPU_INSTRUCTION(FPATAN); +FPU_INSTRUCTION(FXTRACT); +FPU_INSTRUCTION(FPREM1); +FPU_INSTRUCTION(FDECSTP); +FPU_INSTRUCTION(FINCSTP); +FPU_INSTRUCTION(FNSTCW); +FPU_INSTRUCTION(FPREM); +FPU_INSTRUCTION(FYL2XP1); +FPU_INSTRUCTION(FSQRT); +FPU_INSTRUCTION(FSINCOS); +FPU_INSTRUCTION(FRNDINT); +FPU_INSTRUCTION(FSCALE); +FPU_INSTRUCTION(FSIN); +FPU_INSTRUCTION(FCOS); +FPU_INSTRUCTION(FIADD_RM32); +FPU_INSTRUCTION(FCMOVB); +FPU_INSTRUCTION(FIMUL_RM32); +FPU_INSTRUCTION(FCMOVE); +FPU_INSTRUCTION(FICOM_RM32); +FPU_INSTRUCTION(FCMOVBE); +FPU_INSTRUCTION(FICOMP_RM32); +FPU_INSTRUCTION(FCMOVU); +FPU_INSTRUCTION(FISUB_RM32); +FPU_INSTRUCTION(FISUBR_RM32); +FPU_INSTRUCTION(FUCOMPP); +FPU_INSTRUCTION(FIDIV_RM32); +FPU_INSTRUCTION(FIDIVR_RM32); +FPU_INSTRUCTION(FILD_RM32); +FPU_INSTRUCTION(FCMOVNB); +FPU_INSTRUCTION(FISTTP_RM32); +FPU_INSTRUCTION(FCMOVNE); +FPU_INSTRUCTION(FIST_RM32); +FPU_INSTRUCTION(FCMOVNBE); +FPU_INSTRUCTION(FISTP_RM32); +FPU_INSTRUCTION(FCMOVNU); +FPU_INSTRUCTION(FNENI); +FPU_INSTRUCTION(FNDISI); +FPU_INSTRUCTION(FNCLEX); +FPU_INSTRUCTION(FNINIT); +FPU_INSTRUCTION(FNSETPM); +FPU_INSTRUCTION(FLD_RM80); +FPU_INSTRUCTION(FUCOMI); +FPU_INSTRUCTION(FCOMI); +FPU_INSTRUCTION(FSTP_RM80); +FPU_INSTRUCTION(FADD_RM64); +FPU_INSTRUCTION(FMUL_RM64); +FPU_INSTRUCTION(FCOM_RM64); +FPU_INSTRUCTION(FCOMP_RM64); +FPU_INSTRUCTION(FSUB_RM64); +FPU_INSTRUCTION(FSUBR_RM64); +FPU_INSTRUCTION(FDIV_RM64); +FPU_INSTRUCTION(FDIVR_RM64); +FPU_INSTRUCTION(FLD_RM64); +FPU_INSTRUCTION(FFREE); +FPU_INSTRUCTION(FISTTP_RM64); +FPU_INSTRUCTION(FST_RM64); +FPU_INSTRUCTION(FSTP_RM64); +FPU_INSTRUCTION(FRSTOR); +FPU_INSTRUCTION(FUCOM); +FPU_INSTRUCTION(FUCOMP); +FPU_INSTRUCTION(FNSAVE); +FPU_INSTRUCTION(FNSTSW); +FPU_INSTRUCTION(FIADD_RM16); +FPU_INSTRUCTION(FADDP); +FPU_INSTRUCTION(FIMUL_RM16); +FPU_INSTRUCTION(FMULP); +FPU_INSTRUCTION(FICOM_RM16); +FPU_INSTRUCTION(FICOMP_RM16); +FPU_INSTRUCTION(FCOMPP); +FPU_INSTRUCTION(FISUB_RM16); +FPU_INSTRUCTION(FSUBRP); +FPU_INSTRUCTION(FISUBR_RM16); +FPU_INSTRUCTION(FSUBP); +FPU_INSTRUCTION(FIDIV_RM16); +FPU_INSTRUCTION(FDIVRP); +FPU_INSTRUCTION(FIDIVR_RM16); +FPU_INSTRUCTION(FDIVP); +FPU_INSTRUCTION(FILD_RM16); +FPU_INSTRUCTION(FFREEP); +FPU_INSTRUCTION(FISTTP_RM16); +FPU_INSTRUCTION(FIST_RM16); +FPU_INSTRUCTION(FISTP_RM16); +FPU_INSTRUCTION(FBLD_M80); +FPU_INSTRUCTION(FNSTSW_AX); +FPU_INSTRUCTION(FILD_RM64); +FPU_INSTRUCTION(FUCOMIP); +FPU_INSTRUCTION(FBSTP_M80); +FPU_INSTRUCTION(FCOMIP); +FPU_INSTRUCTION(FISTP_RM64); -void SoftCPU::FADD_RM32(const X86::Instruction& insn) -{ - // XXX look at ::INC_foo for how mem/reg stuff is handled, and use that here too to make sure this is only called for mem32 ops - 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<float>(new_f32.value()); - fpu_set(0, fpu_get(0) + f32); - } -} - -void SoftCPU::FMUL_RM32(const X86::Instruction& insn) -{ - // XXX look at ::INC_foo for how mem/reg stuff is handled, and use that here too to make sure this is only called for mem32 ops - if (insn.modrm().is_register()) { - fpu_set(0, fpu_get(0) * fpu_get(insn.modrm().register_index())); - } else { - auto new_f32 = insn.modrm().read32(*this, insn); - // FIXME: Respect shadow values - auto f32 = bit_cast<float>(new_f32.value()); - fpu_set(0, fpu_get(0) * f32); - } -} - -void SoftCPU::FCOM_RM32(const X86::Instruction&) { TODO_INSN(); } -void SoftCPU::FCOMP_RM32(const X86::Instruction&) { TODO_INSN(); } - -void SoftCPU::FSUB_RM32(const X86::Instruction& insn) -{ - if (insn.modrm().is_register()) { - fpu_set(0, fpu_get(0) - fpu_get(insn.modrm().register_index())); - } else { - auto new_f32 = insn.modrm().read32(*this, insn); - // FIXME: Respect shadow values - auto f32 = bit_cast<float>(new_f32.value()); - fpu_set(0, fpu_get(0) - f32); - } -} - -void SoftCPU::FSUBR_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<float>(new_f32.value()); - fpu_set(0, f32 - fpu_get(0)); - } -} - -void SoftCPU::FDIV_RM32(const X86::Instruction& insn) -{ - if (insn.modrm().is_register()) { - fpu_set(0, fpu_get(0) / fpu_get(insn.modrm().register_index())); - } else { - auto new_f32 = insn.modrm().read32(*this, insn); - // FIXME: Respect shadow values - auto f32 = bit_cast<float>(new_f32.value()); - // FIXME: Raise IA on + infinity / +-infinity, +-0 / +-0, raise Z on finite / +-0 - fpu_set(0, fpu_get(0) / f32); - } -} - -void SoftCPU::FDIVR_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<float>(new_f32.value()); - // FIXME: Raise IA on + infinity / +-infinity, +-0 / +-0, raise Z on finite / +-0 - fpu_set(0, f32 / fpu_get(0)); - } -} - -void SoftCPU::FLD_RM32(const X86::Instruction& insn) -{ - if (insn.modrm().is_register()) { - fpu_push(fpu_get(insn.modrm().register_index())); - } else { - auto new_f32 = insn.modrm().read32(*this, insn); - // FIXME: Respect shadow values - fpu_push(bit_cast<float>(new_f32.value())); - } -} - -void SoftCPU::FXCH(const X86::Instruction& insn) -{ - VERIFY(insn.modrm().is_register()); - auto tmp = fpu_get(0); - fpu_set(0, fpu_get(insn.modrm().register_index())); - fpu_set(insn.modrm().register_index(), tmp); -} - -void SoftCPU::FST_RM32(const X86::Instruction& insn) -{ - VERIFY(!insn.modrm().is_register()); - float f32 = (float)fpu_get(0); - // FIXME: Respect shadow values - insn.modrm().write32(*this, insn, shadow_wrap_as_initialized(bit_cast<u32>(f32))); -} - -void SoftCPU::FNOP(const X86::Instruction&) -{ -} - -void SoftCPU::FSTP_RM32(const X86::Instruction& insn) -{ - FST_RM32(insn); - fpu_pop(); -} - -void SoftCPU::FLDENV(const X86::Instruction&) { TODO_INSN(); } - -void SoftCPU::FCHS(const X86::Instruction&) -{ - fpu_set(0, -fpu_get(0)); -} - -void SoftCPU::FABS(const X86::Instruction&) -{ - fpu_set(0, __builtin_fabsl(fpu_get(0))); -} - -void SoftCPU::FTST(const X86::Instruction&) { TODO_INSN(); } -void SoftCPU::FXAM(const X86::Instruction&) { TODO_INSN(); } - -void SoftCPU::FLDCW(const X86::Instruction& insn) -{ - m_fpu_cw = insn.modrm().read16(*this, insn); -} - -void SoftCPU::FLD1(const X86::Instruction&) -{ - fpu_push(1.0); -} - -void SoftCPU::FLDL2T(const X86::Instruction&) -{ - fpu_push(log2f(10.0f)); -} - -void SoftCPU::FLDL2E(const X86::Instruction&) -{ - fpu_push(log2f(M_E)); -} - -void SoftCPU::FLDPI(const X86::Instruction&) -{ - fpu_push(M_PI); -} - -void SoftCPU::FLDLG2(const X86::Instruction&) -{ - fpu_push(log10f(2.0f)); -} - -void SoftCPU::FLDLN2(const X86::Instruction&) -{ - fpu_push(M_LN2); -} - -void SoftCPU::FLDZ(const X86::Instruction&) -{ - fpu_push(0.0); -} - -void SoftCPU::FNSTENV(const X86::Instruction&) { TODO_INSN(); } - -void SoftCPU::F2XM1(const X86::Instruction&) -{ - // FIXME: validate ST(0) is in range –1.0 to +1.0 - auto f32 = fpu_get(0); - // FIXME: Set C0, C2, C3 in FPU status word. - fpu_set(0, powf(2, f32) - 1.0f); -} - -void SoftCPU::FYL2X(const X86::Instruction&) -{ - // FIXME: Raise IA on +-infinity, +-0, raise Z on +-0 - auto f32 = fpu_get(0); - // FIXME: Set C0, C2, C3 in FPU status word. - fpu_set(1, fpu_get(1) * log2f(f32)); - fpu_pop(); -} - -void SoftCPU::FYL2XP1(const X86::Instruction&) -{ - // FIXME: validate ST(0) range - auto f32 = fpu_get(0); - // FIXME: Set C0, C2, C3 in FPU status word. - fpu_set(1, (fpu_get(1) * log2f(f32 + 1.0f))); - fpu_pop(); -} - -void SoftCPU::FPTAN(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 0 - fpu_set(0, tanf(fpu_get(0))); - fpu_push(1.0f); -} - -void SoftCPU::FPATAN(const X86::Instruction&) { TODO_INSN(); } -void SoftCPU::FXTRACT(const X86::Instruction&) { TODO_INSN(); } -void SoftCPU::FPREM1(const X86::Instruction&) { TODO_INSN(); } - -void SoftCPU::FDECSTP(const X86::Instruction&) -{ - m_fpu_top = (m_fpu_top == 0) ? 7 : m_fpu_top - 1; - set_cf(0); -} - -void SoftCPU::FINCSTP(const X86::Instruction&) -{ - m_fpu_top = (m_fpu_top == 7) ? 0 : m_fpu_top + 1; - set_cf(0); -} - -void SoftCPU::FNSTCW(const X86::Instruction& insn) -{ - insn.modrm().write16(*this, insn, m_fpu_cw); -} - -void SoftCPU::FPREM(const X86::Instruction&) -{ - fpu_set(0, - fmodl(fpu_get(0), fpu_get(1))); -} - -void SoftCPU::FSQRT(const X86::Instruction&) -{ - fpu_set(0, sqrt(fpu_get(0))); -} - -void SoftCPU::FSINCOS(const X86::Instruction&) -{ - long double sin = sinl(fpu_get(0)); - long double cos = cosl(fpu_get(0)); - fpu_set(0, sin); - fpu_push(cos); -} - -void SoftCPU::FRNDINT(const X86::Instruction&) -{ - // FIXME: support rounding mode - fpu_set(0, round(fpu_get(0))); -} - -void SoftCPU::FSCALE(const X86::Instruction&) -{ - // FIXME: set C1 upon stack overflow or if result was rounded - fpu_set(0, fpu_get(0) * powf(2, floorf(fpu_get(1)))); -} - -void SoftCPU::FSIN(const X86::Instruction&) -{ - fpu_set(0, sin(fpu_get(0))); -} - -void SoftCPU::FCOS(const X86::Instruction&) -{ - fpu_set(0, cos(fpu_get(0))); -} - -void SoftCPU::FIADD_RM32(const X86::Instruction& insn) -{ - VERIFY(!insn.modrm().is_register()); - auto m32int = (i32)insn.modrm().read32(*this, insn).value(); - // FIXME: Respect shadow values - fpu_set(0, fpu_get(0) + (long double)m32int); -} - -void SoftCPU::FCMOVB(const X86::Instruction& insn) -{ - VERIFY(insn.modrm().is_register()); - if (cf()) - fpu_set(0, fpu_get(insn.modrm().rm())); -} - -void SoftCPU::FIMUL_RM32(const X86::Instruction& insn) -{ - VERIFY(!insn.modrm().is_register()); - auto m32int = (i32)insn.modrm().read32(*this, insn).value(); - // FIXME: Respect shadow values - fpu_set(0, fpu_get(0) * (long double)m32int); -} - -void SoftCPU::FCMOVE(const X86::Instruction& insn) -{ - VERIFY(insn.modrm().is_register()); - if (zf()) - fpu_set(0, fpu_get(insn.modrm().rm())); -} - -void SoftCPU::FICOM_RM32(const X86::Instruction&) { TODO_INSN(); } - -void SoftCPU::FCMOVBE(const X86::Instruction& insn) -{ - if (evaluate_condition(6)) - fpu_set(0, fpu_get(insn.modrm().rm())); -} - -void SoftCPU::FICOMP_RM32(const X86::Instruction&) { TODO_INSN(); } - -void SoftCPU::FCMOVU(const X86::Instruction& insn) -{ - VERIFY(insn.modrm().is_register()); - if (pf()) - fpu_set(0, fpu_get((insn.modrm().reg_fpu()))); -} - -void SoftCPU::FISUB_RM32(const X86::Instruction& insn) -{ - VERIFY(!insn.modrm().is_register()); - auto m32int = (i32)insn.modrm().read32(*this, insn).value(); - // FIXME: Respect shadow values - fpu_set(0, fpu_get(0) - (long double)m32int); -} - -void SoftCPU::FISUBR_RM32(const X86::Instruction& insn) -{ - VERIFY(!insn.modrm().is_register()); - auto m32int = (i32)insn.modrm().read32(*this, insn).value(); - // FIXME: Respect shadow values - fpu_set(0, (long double)m32int - fpu_get(0)); -} - -void SoftCPU::FIDIV_RM32(const X86::Instruction& insn) -{ - VERIFY(!insn.modrm().is_register()); - 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, fpu_get(0) / (long double)m32int); -} - -void SoftCPU::FIDIVR_RM32(const X86::Instruction& insn) -{ - VERIFY(!insn.modrm().is_register()); - 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)m32int / fpu_get(0)); -} - -void SoftCPU::FILD_RM32(const X86::Instruction& insn) -{ - VERIFY(!insn.modrm().is_register()); - auto m32int = (i32)insn.modrm().read32(*this, insn).value(); - // FIXME: Respect shadow values - fpu_push((long double)m32int); -} - -void SoftCPU::FCMOVNB(const X86::Instruction& insn) -{ - VERIFY(insn.modrm().is_register()); - if (!cf()) - fpu_set(0, fpu_get((insn.modrm().reg_fpu()))); -} - -void SoftCPU::FISTTP_RM32(const X86::Instruction& insn) -{ - VERIFY(!insn.modrm().is_register()); - i32 value = static_cast<i32>(fpu_pop()); - insn.modrm().write32(*this, insn, shadow_wrap_as_initialized(bit_cast<u32>(value))); -} - -void SoftCPU::FCMOVNE(const X86::Instruction& insn) -{ - VERIFY(insn.modrm().is_register()); - if (!zf()) - fpu_set(0, fpu_get((insn.modrm().reg_fpu()))); -} - -void SoftCPU::FIST_RM32(const X86::Instruction& insn) -{ - VERIFY(!insn.modrm().is_register()); - auto f = fpu_get(0); - // FIXME: Respect rounding mode in m_fpu_cw. - auto value = static_cast<i32>(f); - // FIXME: Respect shadow values - insn.modrm().write32(*this, insn, shadow_wrap_as_initialized(bit_cast<u32>(value))); -} - -void SoftCPU::FCMOVNBE(const X86::Instruction& insn) -{ - if (evaluate_condition(7)) - fpu_set(0, fpu_get(insn.modrm().rm())); -} - -void SoftCPU::FISTP_RM32(const X86::Instruction& insn) -{ - FIST_RM32(insn); - fpu_pop(); -} - -void SoftCPU::FCMOVNU(const X86::Instruction& insn) -{ - VERIFY(insn.modrm().is_register()); - if (!pf()) - fpu_set(0, fpu_get((insn.modrm().reg_fpu()))); -} - -void SoftCPU::FNENI(const X86::Instruction&) { TODO_INSN(); } -void SoftCPU::FNDISI(const X86::Instruction&) { TODO_INSN(); } -void SoftCPU::FNCLEX(const X86::Instruction&) { TODO_INSN(); } -void SoftCPU::FNINIT(const X86::Instruction&) { TODO_INSN(); } -void SoftCPU::FNSETPM(const X86::Instruction&) { TODO_INSN(); } - -void SoftCPU::FLD_RM80(const X86::Instruction& insn) -{ - VERIFY(!insn.modrm().is_register()); - - // long doubles can be up to 128 bits wide in memory for reasons (alignment) and only uses 80 bits of precision - // GCC uses 12 bytes in 32 bit and 16 bytes in 64 bit mode - // so in the 32 bit case we read a bit to much, but that shouldn't be an issue. - // FIXME: Respect shadow values - auto new_f80 = insn.modrm().read128(*this, insn).value(); - - fpu_push(*(long double*)new_f80.bytes().data()); -} - -void SoftCPU::FUCOMI(const X86::Instruction& insn) -{ - auto i = insn.modrm().rm(); - // FIXME: Unordered comparison checks. - // FIXME: QNaN / exception handling. - // FIXME: Set C0, C2, C3 in FPU status word. - if (__builtin_isnan(fpu_get(0)) || __builtin_isnan(fpu_get(i))) { - set_zf(true); - set_pf(true); - set_cf(true); - } else { - set_zf(fpu_get(0) == fpu_get(i)); - set_pf(false); - set_cf(fpu_get(0) < fpu_get(i)); - set_of(false); - } - - // FIXME: Taint should be based on ST(0) and ST(i) - m_flags_tainted = false; -} - -void SoftCPU::FCOMI(const X86::Instruction& insn) -{ - auto i = insn.modrm().rm(); - // FIXME: QNaN / exception handling. - // FIXME: Set C0, C2, C3 in FPU status word. - set_zf(fpu_get(0) == fpu_get(i)); - set_pf(false); - set_cf(fpu_get(0) < fpu_get(i)); - set_of(false); - - // FIXME: Taint should be based on ST(0) and ST(i) - m_flags_tainted = false; -} - -void SoftCPU::FSTP_RM80(const X86::Instruction& insn) -{ - if (insn.modrm().is_register()) { - fpu_set(insn.modrm().register_index(), fpu_pop()); - } else { - // FIXME: Respect shadow values - // long doubles can be up to 128 bits wide in memory for reasons (alignment) and only uses 80 bits of precision - // gcc uses 12 byte in 32 bit and 16 byte in 64 bit mode - // so in the 32 bit case we have to read first, to not override data on the overly big write - u128 f80 {}; - if constexpr (sizeof(long double) == 12) - f80 = insn.modrm().read128(*this, insn).value(); - - *(long double*)f80.bytes().data() = fpu_pop(); - - insn.modrm().write128(*this, insn, shadow_wrap_as_initialized(f80)); - } -} - -void SoftCPU::FADD_RM64(const X86::Instruction& insn) -{ - // XXX look at ::INC_foo for how mem/reg stuff is handled, and use that here too to make sure this is only called for mem64 ops - 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<double>(new_f64.value()); - fpu_set(0, fpu_get(0) + f64); - } -} - -void SoftCPU::FMUL_RM64(const X86::Instruction& insn) -{ - // XXX look at ::INC_foo for how mem/reg stuff is handled, and use that here too to make sure this is only called for mem64 ops - 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<double>(new_f64.value()); - fpu_set(0, fpu_get(0) * f64); - } -} - -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& 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<double>(new_f64.value()); - fpu_set(0, fpu_get(0) - f64); - } -} - -void SoftCPU::FSUBR_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<double>(new_f64.value()); - fpu_set(0, f64 - fpu_get(0)); - } -} - -void SoftCPU::FDIV_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<double>(new_f64.value()); - // FIXME: Raise IA on + infinity / +-infinity, +-0 / +-0, raise Z on finite / +-0 - fpu_set(0, fpu_get(0) / f64); - } -} - -void SoftCPU::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())); - 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<double>(new_f64.value()); - // FIXME: Raise IA on + infinity / +-infinity, +-0 / +-0, raise Z on finite / +-0 - fpu_set(0, f64 / fpu_get(0)); - } -} - -void SoftCPU::FLD_RM64(const X86::Instruction& insn) -{ - VERIFY(!insn.modrm().is_register()); - auto new_f64 = insn.modrm().read64(*this, insn); - // FIXME: Respect shadow values - fpu_push(bit_cast<double>(new_f64.value())); -} - -void SoftCPU::FFREE(const X86::Instruction&) { TODO_INSN(); } - -void SoftCPU::FISTTP_RM64(const X86::Instruction& insn) -{ - // is this allowed to be a register? - VERIFY(!insn.modrm().is_register()); - i64 value = static_cast<i64>(fpu_pop()); - insn.modrm().write64(*this, insn, shadow_wrap_as_initialized(bit_cast<u64>(value))); -} - -void SoftCPU::FST_RM64(const X86::Instruction& insn) -{ - if (insn.modrm().is_register()) { - fpu_set(insn.modrm().register_index(), fpu_get(0)); - } else { - // FIXME: Respect shadow values - double f64 = (double)fpu_get(0); - insn.modrm().write64(*this, insn, shadow_wrap_as_initialized(bit_cast<u64>(f64))); - } -} - -void SoftCPU::FSTP_RM64(const X86::Instruction& insn) -{ - FST_RM64(insn); - fpu_pop(); -} - -void SoftCPU::FRSTOR(const X86::Instruction&) { TODO_INSN(); } -void SoftCPU::FUCOM(const X86::Instruction&) { TODO_INSN(); } -void SoftCPU::FUCOMP(const X86::Instruction&) { TODO_INSN(); } -void SoftCPU::FUCOMPP(const X86::Instruction&) { TODO_INSN(); } -void SoftCPU::FNSAVE(const X86::Instruction&) { TODO_INSN(); } -void SoftCPU::FNSTSW(const X86::Instruction&) { TODO_INSN(); } - -void SoftCPU::FIADD_RM16(const X86::Instruction& insn) -{ - VERIFY(!insn.modrm().is_register()); - auto m16int = (i16)insn.modrm().read16(*this, insn).value(); - // FIXME: Respect shadow values - fpu_set(0, fpu_get(0) + (long double)m16int); -} - -void SoftCPU::FADDP(const X86::Instruction& insn) -{ - VERIFY(insn.modrm().is_register()); - fpu_set(insn.modrm().register_index(), fpu_get(insn.modrm().register_index()) + fpu_get(0)); - fpu_pop(); -} - -void SoftCPU::FIMUL_RM16(const X86::Instruction& insn) -{ - VERIFY(!insn.modrm().is_register()); - auto m16int = (i16)insn.modrm().read16(*this, insn).value(); - // FIXME: Respect shadow values - fpu_set(0, fpu_get(0) * (long double)m16int); -} - -void SoftCPU::FMULP(const X86::Instruction& insn) -{ - VERIFY(insn.modrm().is_register()); - fpu_set(insn.modrm().register_index(), fpu_get(insn.modrm().register_index()) * fpu_get(0)); - fpu_pop(); -} - -void SoftCPU::FICOM_RM16(const X86::Instruction&) { TODO_INSN(); } -void SoftCPU::FICOMP_RM16(const X86::Instruction&) { TODO_INSN(); } -void SoftCPU::FCOMPP(const X86::Instruction&) { TODO_INSN(); } - -void SoftCPU::FISUB_RM16(const X86::Instruction& insn) -{ - VERIFY(!insn.modrm().is_register()); - auto m16int = (i16)insn.modrm().read16(*this, insn).value(); - // FIXME: Respect shadow values - fpu_set(0, fpu_get(0) - (long double)m16int); -} - -void SoftCPU::FSUBRP(const X86::Instruction& insn) -{ - VERIFY(insn.modrm().is_register()); - fpu_set(insn.modrm().register_index(), fpu_get(0) - fpu_get(insn.modrm().register_index())); - fpu_pop(); -} - -void SoftCPU::FISUBR_RM16(const X86::Instruction& insn) -{ - VERIFY(!insn.modrm().is_register()); - auto m16int = (i16)insn.modrm().read16(*this, insn).value(); - // FIXME: Respect shadow values - fpu_set(0, (long double)m16int - fpu_get(0)); -} - -void SoftCPU::FSUBP(const X86::Instruction& insn) -{ - VERIFY(insn.modrm().is_register()); - fpu_set(insn.modrm().register_index(), fpu_get(insn.modrm().register_index()) - fpu_get(0)); - fpu_pop(); -} - -void SoftCPU::FIDIV_RM16(const X86::Instruction& insn) -{ - VERIFY(!insn.modrm().is_register()); - auto m16int = (i16)insn.modrm().read16(*this, insn).value(); - // FIXME: Respect shadow values - // FIXME: Raise IA on 0 / _=0, raise Z on finite / +-0 - fpu_set(0, fpu_get(0) / (long double)m16int); -} - -void SoftCPU::FDIVRP(const X86::Instruction& insn) -{ - VERIFY(insn.modrm().is_register()); - // FIXME: Raise IA on + infinity / +-infinity, +-0 / +-0, raise Z on finite / +-0 - fpu_set(insn.modrm().register_index(), fpu_get(0) / fpu_get(insn.modrm().register_index())); - fpu_pop(); -} - -void SoftCPU::FIDIVR_RM16(const X86::Instruction& insn) -{ - VERIFY(!insn.modrm().is_register()); - auto m16int = (i16)insn.modrm().read16(*this, insn).value(); - // FIXME: Respect shadow values - // FIXME: Raise IA on 0 / _=0, raise Z on finite / +-0 - fpu_set(0, (long double)m16int / fpu_get(0)); -} - -void SoftCPU::FDIVP(const X86::Instruction& insn) -{ - VERIFY(insn.modrm().is_register()); - // FIXME: Raise IA on + infinity / +-infinity, +-0 / +-0, raise Z on finite / +-0 - fpu_set(insn.modrm().register_index(), fpu_get(insn.modrm().register_index()) / fpu_get(0)); - fpu_pop(); -} - -void SoftCPU::FILD_RM16(const X86::Instruction& insn) -{ - VERIFY(!insn.modrm().is_register()); - auto m16int = (i16)insn.modrm().read16(*this, insn).value(); - // FIXME: Respect shadow values - fpu_push((long double)m16int); -} - -void SoftCPU::FFREEP(const X86::Instruction&) { TODO_INSN(); } - -void SoftCPU::FISTTP_RM16(const X86::Instruction& insn) -{ - // is this allowed to be a register? - VERIFY(!insn.modrm().is_register()); - i16 value = static_cast<i16>(fpu_pop()); - insn.modrm().write16(*this, insn, shadow_wrap_as_initialized(bit_cast<u16>(value))); -} - -void SoftCPU::FIST_RM16(const X86::Instruction& insn) -{ - VERIFY(!insn.modrm().is_register()); - auto f = fpu_get(0); - // FIXME: Respect rounding mode in m_fpu_cw. - auto value = static_cast<i16>(f); - // FIXME: Respect shadow values - insn.modrm().write16(*this, insn, shadow_wrap_as_initialized(bit_cast<u16>(value))); -} - -void SoftCPU::FISTP_RM16(const X86::Instruction& insn) -{ - FIST_RM16(insn); - fpu_pop(); -} - -void SoftCPU::FBLD_M80(const X86::Instruction&) { TODO_INSN(); } -void SoftCPU::FNSTSW_AX(const X86::Instruction&) { TODO_INSN(); } - -void SoftCPU::FILD_RM64(const X86::Instruction& insn) -{ - VERIFY(!insn.modrm().is_register()); - auto m64int = (i64)insn.modrm().read64(*this, insn).value(); - // FIXME: Respect shadow values - fpu_push((long double)m64int); -} - -void SoftCPU::FUCOMIP(const X86::Instruction& insn) -{ - FUCOMI(insn); - fpu_pop(); -} - -void SoftCPU::FBSTP_M80(const X86::Instruction&) { TODO_INSN(); } - -void SoftCPU::FCOMIP(const X86::Instruction& insn) -{ - FCOMI(insn); - fpu_pop(); -} - -void SoftCPU::FISTP_RM64(const X86::Instruction& insn) -{ - VERIFY(!insn.modrm().is_register()); - auto f = fpu_pop(); - // FIXME: Respect rounding mode in m_fpu_cw. - auto value = static_cast<i64>(f); - // FIXME: Respect shadow values - insn.modrm().write64(*this, insn, shadow_wrap_as_initialized(bit_cast<u64>(value))); -} void SoftCPU::HLT(const X86::Instruction&) { TODO_INSN(); } void SoftCPU::IDIV_RM16(const X86::Instruction& insn) @@ -2815,27 +2171,28 @@ void SoftCPU::OUT_DX_EAX(const X86::Instruction&) { TODO_INSN(); } void SoftCPU::OUT_imm8_AL(const X86::Instruction&) { TODO_INSN(); } void SoftCPU::OUT_imm8_AX(const X86::Instruction&) { TODO_INSN(); } void SoftCPU::OUT_imm8_EAX(const X86::Instruction&) { TODO_INSN(); } -void SoftCPU::PACKSSDW_mm1_mm2m64(const X86::Instruction&) { TODO_INSN(); } -void SoftCPU::PACKSSWB_mm1_mm2m64(const X86::Instruction&) { TODO_INSN(); } -void SoftCPU::PACKUSWB_mm1_mm2m64(const X86::Instruction&) { TODO_INSN(); } -void SoftCPU::PADDB_mm1_mm2m64(const X86::Instruction&) { TODO_INSN(); } -void SoftCPU::PADDW_mm1_mm2m64(const X86::Instruction&) { TODO_INSN(); } -void SoftCPU::PADDD_mm1_mm2m64(const X86::Instruction&) { TODO_INSN(); } -void SoftCPU::PADDSB_mm1_mm2m64(const X86::Instruction&) { TODO_INSN(); } -void SoftCPU::PADDSW_mm1_mm2m64(const X86::Instruction&) { TODO_INSN(); } -void SoftCPU::PADDUSB_mm1_mm2m64(const X86::Instruction&) { TODO_INSN(); } -void SoftCPU::PADDUSW_mm1_mm2m64(const X86::Instruction&) { TODO_INSN(); } -void SoftCPU::PAND_mm1_mm2m64(const X86::Instruction&) { TODO_INSN(); } -void SoftCPU::PANDN_mm1_mm2m64(const X86::Instruction&) { TODO_INSN(); } -void SoftCPU::PCMPEQB_mm1_mm2m64(const X86::Instruction&) { TODO_INSN(); } -void SoftCPU::PCMPEQW_mm1_mm2m64(const X86::Instruction&) { TODO_INSN(); } -void SoftCPU::PCMPEQD_mm1_mm2m64(const X86::Instruction&) { TODO_INSN(); } -void SoftCPU::PCMPGTB_mm1_mm2m64(const X86::Instruction&) { TODO_INSN(); } -void SoftCPU::PCMPGTW_mm1_mm2m64(const X86::Instruction&) { TODO_INSN(); } -void SoftCPU::PCMPGTD_mm1_mm2m64(const X86::Instruction&) { TODO_INSN(); } -void SoftCPU::PMADDWD_mm1_mm2m64(const X86::Instruction&) { TODO_INSN(); } -void SoftCPU::PMULHW_mm1_mm2m64(const X86::Instruction&) { TODO_INSN(); } -void SoftCPU::PMULLW_mm1_mm2m64(const X86::Instruction&) { TODO_INSN(); } + +FPU_INSTRUCTION(PACKSSDW_mm1_mm2m64); +FPU_INSTRUCTION(PACKSSWB_mm1_mm2m64); +FPU_INSTRUCTION(PACKUSWB_mm1_mm2m64); +FPU_INSTRUCTION(PADDB_mm1_mm2m64); +FPU_INSTRUCTION(PADDW_mm1_mm2m64); +FPU_INSTRUCTION(PADDD_mm1_mm2m64); +FPU_INSTRUCTION(PADDSB_mm1_mm2m64); +FPU_INSTRUCTION(PADDSW_mm1_mm2m64); +FPU_INSTRUCTION(PADDUSB_mm1_mm2m64); +FPU_INSTRUCTION(PADDUSW_mm1_mm2m64); +FPU_INSTRUCTION(PAND_mm1_mm2m64); +FPU_INSTRUCTION(PANDN_mm1_mm2m64); +FPU_INSTRUCTION(PCMPEQB_mm1_mm2m64); +FPU_INSTRUCTION(PCMPEQW_mm1_mm2m64); +FPU_INSTRUCTION(PCMPEQD_mm1_mm2m64); +FPU_INSTRUCTION(PCMPGTB_mm1_mm2m64); +FPU_INSTRUCTION(PCMPGTW_mm1_mm2m64); +FPU_INSTRUCTION(PCMPGTD_mm1_mm2m64); +FPU_INSTRUCTION(PMADDWD_mm1_mm2m64); +FPU_INSTRUCTION(PMULHW_mm1_mm2m64); +FPU_INSTRUCTION(PMULLW_mm1_mm2m64); void SoftCPU::POPA(const X86::Instruction&) { @@ -2908,36 +2265,36 @@ void SoftCPU::POP_reg32(const X86::Instruction& insn) gpr32(insn.reg32()) = pop32(); } -void SoftCPU::POR_mm1_mm2m64(const X86::Instruction&) { TODO_INSN(); }; -void SoftCPU::PSLLW_mm1_mm2m64(const X86::Instruction&) { TODO_INSN(); }; -void SoftCPU::PSLLW_mm1_imm8(const X86::Instruction&) { TODO_INSN(); }; -void SoftCPU::PSLLD_mm1_mm2m64(const X86::Instruction&) { TODO_INSN(); }; -void SoftCPU::PSLLD_mm1_imm8(const X86::Instruction&) { TODO_INSN(); }; -void SoftCPU::PSLLQ_mm1_mm2m64(const X86::Instruction&) { TODO_INSN(); }; -void SoftCPU::PSLLQ_mm1_imm8(const X86::Instruction&) { TODO_INSN(); }; -void SoftCPU::PSRAW_mm1_mm2m64(const X86::Instruction&) { TODO_INSN(); }; -void SoftCPU::PSRAW_mm1_imm8(const X86::Instruction&) { TODO_INSN(); }; -void SoftCPU::PSRAD_mm1_mm2m64(const X86::Instruction&) { TODO_INSN(); }; -void SoftCPU::PSRAD_mm1_imm8(const X86::Instruction&) { TODO_INSN(); }; -void SoftCPU::PSRLW_mm1_mm2m64(const X86::Instruction&) { TODO_INSN(); }; -void SoftCPU::PSRLW_mm1_imm8(const X86::Instruction&) { TODO_INSN(); }; -void SoftCPU::PSRLD_mm1_mm2m64(const X86::Instruction&) { TODO_INSN(); }; -void SoftCPU::PSRLD_mm1_imm8(const X86::Instruction&) { TODO_INSN(); }; -void SoftCPU::PSRLQ_mm1_mm2m64(const X86::Instruction&) { TODO_INSN(); }; -void SoftCPU::PSRLQ_mm1_imm8(const X86::Instruction&) { TODO_INSN(); }; -void SoftCPU::PSUBB_mm1_mm2m64(const X86::Instruction&) { TODO_INSN(); }; -void SoftCPU::PSUBW_mm1_mm2m64(const X86::Instruction&) { TODO_INSN(); }; -void SoftCPU::PSUBD_mm1_mm2m64(const X86::Instruction&) { TODO_INSN(); }; -void SoftCPU::PSUBSB_mm1_mm2m64(const X86::Instruction&) { TODO_INSN(); }; -void SoftCPU::PSUBSW_mm1_mm2m64(const X86::Instruction&) { TODO_INSN(); }; -void SoftCPU::PSUBUSB_mm1_mm2m64(const X86::Instruction&) { TODO_INSN(); }; -void SoftCPU::PSUBUSW_mm1_mm2m64(const X86::Instruction&) { TODO_INSN(); }; -void SoftCPU::PUNPCKHBW_mm1_mm2m64(const X86::Instruction&) { TODO_INSN(); }; -void SoftCPU::PUNPCKHWD_mm1_mm2m64(const X86::Instruction&) { TODO_INSN(); }; -void SoftCPU::PUNPCKHDQ_mm1_mm2m64(const X86::Instruction&) { TODO_INSN(); }; -void SoftCPU::PUNPCKLBW_mm1_mm2m32(const X86::Instruction&) { TODO_INSN(); }; -void SoftCPU::PUNPCKLWD_mm1_mm2m32(const X86::Instruction&) { TODO_INSN(); }; -void SoftCPU::PUNPCKLDQ_mm1_mm2m32(const X86::Instruction&) { TODO_INSN(); }; +FPU_INSTRUCTION(POR_mm1_mm2m64); +FPU_INSTRUCTION(PSLLW_mm1_mm2m64); +FPU_INSTRUCTION(PSLLW_mm1_imm8); +FPU_INSTRUCTION(PSLLD_mm1_mm2m64); +FPU_INSTRUCTION(PSLLD_mm1_imm8); +FPU_INSTRUCTION(PSLLQ_mm1_mm2m64); +FPU_INSTRUCTION(PSLLQ_mm1_imm8); +FPU_INSTRUCTION(PSRAW_mm1_mm2m64); +FPU_INSTRUCTION(PSRAW_mm1_imm8); +FPU_INSTRUCTION(PSRAD_mm1_mm2m64); +FPU_INSTRUCTION(PSRAD_mm1_imm8); +FPU_INSTRUCTION(PSRLW_mm1_mm2m64); +FPU_INSTRUCTION(PSRLW_mm1_imm8); +FPU_INSTRUCTION(PSRLD_mm1_mm2m64); +FPU_INSTRUCTION(PSRLD_mm1_imm8); +FPU_INSTRUCTION(PSRLQ_mm1_mm2m64); +FPU_INSTRUCTION(PSRLQ_mm1_imm8); +FPU_INSTRUCTION(PSUBB_mm1_mm2m64); +FPU_INSTRUCTION(PSUBW_mm1_mm2m64); +FPU_INSTRUCTION(PSUBD_mm1_mm2m64); +FPU_INSTRUCTION(PSUBSB_mm1_mm2m64); +FPU_INSTRUCTION(PSUBSW_mm1_mm2m64); +FPU_INSTRUCTION(PSUBUSB_mm1_mm2m64); +FPU_INSTRUCTION(PSUBUSW_mm1_mm2m64); +FPU_INSTRUCTION(PUNPCKHBW_mm1_mm2m64); +FPU_INSTRUCTION(PUNPCKHWD_mm1_mm2m64); +FPU_INSTRUCTION(PUNPCKHDQ_mm1_mm2m64); +FPU_INSTRUCTION(PUNPCKLBW_mm1_mm2m32); +FPU_INSTRUCTION(PUNPCKLWD_mm1_mm2m32); +FPU_INSTRUCTION(PUNPCKLDQ_mm1_mm2m32); void SoftCPU::PUSHA(const X86::Instruction&) { @@ -3028,7 +2385,7 @@ void SoftCPU::PUSH_reg32(const X86::Instruction& insn) push32(gpr32(insn.reg32())); } -void SoftCPU::PXOR_mm1_mm2m64(const X86::Instruction&) { TODO_INSN(); }; +FPU_INSTRUCTION(PXOR_mm1_mm2m64); template<typename T, bool cf> ALWAYS_INLINE static T op_rcl_impl(SoftCPU& cpu, T data, ValueWithShadow<u8> steps) @@ -3528,13 +2885,14 @@ DEFINE_GENERIC_INSN_HANDLERS(AND, op_and, true, false, false) DEFINE_GENERIC_INSN_HANDLERS(CMP, op_sub, false, false, false) DEFINE_GENERIC_INSN_HANDLERS_PARTIAL(TEST, op_and, false, false, false) -void SoftCPU::MOVQ_mm1_mm2m64(const X86::Instruction&) { TODO_INSN(); }; -void SoftCPU::MOVQ_mm1m64_mm2(const X86::Instruction&) { TODO_INSN(); }; -void SoftCPU::MOVD_mm1_rm32(const X86::Instruction&) { TODO_INSN(); }; -void SoftCPU::MOVQ_mm1_rm64(const X86::Instruction&) { TODO_INSN(); }; // long mode -void SoftCPU::MOVD_rm32_mm2(const X86::Instruction&) { TODO_INSN(); }; -void SoftCPU::MOVQ_rm64_mm2(const X86::Instruction&) { TODO_INSN(); }; // long mode -void SoftCPU::EMMS(const X86::Instruction&) { TODO_INSN(); } +FPU_INSTRUCTION(MOVQ_mm1_mm2m64); +FPU_INSTRUCTION(MOVQ_mm1m64_mm2); +FPU_INSTRUCTION(MOVD_mm1_rm32); +FPU_INSTRUCTION(MOVQ_mm1_rm64); // long mode +FPU_INSTRUCTION(MOVD_rm32_mm2); +FPU_INSTRUCTION(MOVQ_rm64_mm2); // long mode +FPU_INSTRUCTION(EMMS); + void SoftCPU::wrap_0xC0(const X86::Instruction&) { TODO_INSN(); } void SoftCPU::wrap_0xC1_16(const X86::Instruction&) { TODO_INSN(); } void SoftCPU::wrap_0xC1_32(const X86::Instruction&) { TODO_INSN(); } diff --git a/Userland/DevTools/UserspaceEmulator/SoftCPU.h b/Userland/DevTools/UserspaceEmulator/SoftCPU.h index 601d7f82c0..1eed1e3e17 100644 --- a/Userland/DevTools/UserspaceEmulator/SoftCPU.h +++ b/Userland/DevTools/UserspaceEmulator/SoftCPU.h @@ -7,6 +7,7 @@ #pragma once #include "Region.h" +#include "SoftFPU.h" #include "ValueWithShadow.h" #include <AK/ByteReader.h> #include <LibX86/Instruction.h> @@ -35,6 +36,8 @@ union PartAddressableRegister { class SoftCPU final : public X86::Interpreter , public X86::InstructionStream { + friend SoftFPU; + public: using ValueWithShadowType8 = ValueWithShadow<u8>; using ValueWithShadowType16 = ValueWithShadow<u16>; @@ -264,6 +267,10 @@ public: ValueWithShadow<u8> dl() const { return const_gpr8(X86::RegisterDL); } ValueWithShadow<u8> dh() const { return const_gpr8(X86::RegisterDH); } + long double fpu_get(u8 index) const { return m_fpu.fpu_get(index); } + long double fpu_pop() { return m_fpu.fpu_pop(); } + MMX mmx_get(u8 index) const { return m_fpu.mmx_get(index); }; + void set_eax(ValueWithShadow<u32> value) { gpr32(X86::RegisterEAX) = value; } void set_ebx(ValueWithShadow<u32> value) { gpr32(X86::RegisterEBX) = value; } void set_ecx(ValueWithShadow<u32> value) { gpr32(X86::RegisterECX) = value; } @@ -291,6 +298,10 @@ public: void set_dl(ValueWithShadow<u8> value) { gpr8(X86::RegisterDL) = value; } void set_dh(ValueWithShadow<u8> value) { gpr8(X86::RegisterDH) = value; } + void fpu_push(long double value) { m_fpu.fpu_push(value); } + void fpu_set(u8 index, long double value) { m_fpu.fpu_set(index, value); } + void mmx_set(u8 index, MMX value) { m_fpu.mmx_set(index, value); } + bool of() const { return m_eflags & Flags::OF; } bool sf() const { return m_eflags & Flags::SF; } bool zf() const { return m_eflags & Flags::ZF; } @@ -1160,6 +1171,7 @@ private: private: Emulator& m_emulator; + SoftFPU m_fpu; PartAddressableRegister m_gpr[8]; PartAddressableRegister m_gpr_shadow[8]; @@ -1172,44 +1184,6 @@ private: u32 m_eip { 0 }; u32 m_base_eip { 0 }; - long double m_fpu[8]; - // FIXME: Shadow for m_fpu. - - // FIXME: Use bits 11 to 13 in the FPU status word for this. - int m_fpu_top { -1 }; - - void fpu_push(long double n) - { - ++m_fpu_top; - fpu_set(0, n); - } - long double fpu_pop() - { - auto n = fpu_get(0); - m_fpu_top--; - return n; - } - long double fpu_get(int i) - { - VERIFY(i >= 0 && i <= m_fpu_top); - return m_fpu[m_fpu_top - i]; - } - void fpu_set(int i, long double n) - { - VERIFY(i >= 0 && i <= m_fpu_top); - m_fpu[m_fpu_top - i] = n; - } - - // FIXME: Or just something like m_flags_tainted? - ValueWithShadow<u16> m_fpu_cw { 0, 0 }; - - // FIXME: Make FPU/MMX memory its own struct - // FIXME: FPU Status word - // FIXME: FPU Tag Word - // FIXME: FPU Data Pointer - // FIXME: FPU Instruction Pointer ? - // FIXME: FPU Last OP Code ? - Region* m_cached_code_region { nullptr }; u8* m_cached_code_base_ptr { nullptr }; }; |