1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-25 21:15:06 +00:00

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.
This commit is contained in:
Andreas Kling 2020-11-14 23:43:31 +01:00
parent 647e92b74f
commit 12d923bb7e

View file

@ -1635,15 +1635,24 @@ void SoftCPU::FSIN(const X86::Instruction&)
} }
void SoftCPU::FCOS(const X86::Instruction&) { TODO_INSN(); } 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::FCMOVB(const X86::Instruction&) { TODO_INSN(); }
void SoftCPU::FIMUL_RM32(const X86::Instruction& insn) void SoftCPU::FIMUL_RM32(const X86::Instruction& insn)
{ {
ASSERT(!insn.modrm().is_register()); 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: 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(); } 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) void SoftCPU::FISUB_RM32(const X86::Instruction& insn)
{ {
if (insn.modrm().is_register()) { ASSERT(!insn.modrm().is_register());
fpu_set(0, fpu_get(insn.modrm().register_index()) - fpu_get(0)); auto m32int = (i32)insn.modrm().read32(*this, insn).value();
} else { // FIXME: Respect shadow values
auto new_f32 = insn.modrm().read32(*this, insn); auto f64 = (long double)m32int;
// FIXME: Respect shadow values fpu_set(0, fpu_get(0) - f64);
auto f32 = bit_cast<float>(new_f32.value());
auto f64 = (double)f32;
fpu_set(0, fpu_get(0) - f64);
}
} }
void SoftCPU::FISUBR_RM32(const X86::Instruction&) { TODO_INSN(); } 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) void SoftCPU::FIDIVR_RM32(const X86::Instruction& insn)
{ {
ASSERT(!insn.modrm().is_register()); 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: Respect shadow values
// FIXME: Raise IA on 0 / _=0, raise Z on finite / +-0 // 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) 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::FCOM_RM64(const X86::Instruction&) { TODO_INSN(); }
void SoftCPU::FCOMP_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<double>(new_f64.value());
fpu_set(0, fpu_get(0) - f64);
}
}
void SoftCPU::FSUBR_RM64(const X86::Instruction& insn) void SoftCPU::FSUBR_RM64(const X86::Instruction& insn)
{ {
ASSERT(!insn.modrm().is_register()); // FIXME if (insn.modrm().is_register()) {
auto new_f64 = insn.modrm().read64(*this, insn); fpu_set(insn.modrm().register_index(), fpu_get(insn.modrm().register_index()) - fpu_get(0));
// FIXME: Respect shadow values } else {
auto f64 = bit_cast<double>(new_f64.value()); auto new_f64 = insn.modrm().read64(*this, insn);
fpu_set(0, f64 - fpu_get(0)); // 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) void SoftCPU::FDIV_RM64(const X86::Instruction& insn)
{ {
ASSERT(!insn.modrm().is_register()); // FIXME if (insn.modrm().is_register()) {
auto new_f64 = insn.modrm().read64(*this, insn); fpu_set(insn.modrm().register_index(), fpu_get(insn.modrm().register_index()) / fpu_get(0));
// FIXME: Respect shadow values } else {
auto f64 = bit_cast<double>(new_f64.value()); auto new_f64 = insn.modrm().read64(*this, insn);
// FIXME: Raise IA on + infinity / +-infinitiy, +-0 / +-0, raise Z on finite / +-0 // FIXME: Respect shadow values
fpu_set(0, fpu_get(0) / f64); auto f64 = bit_cast<double>(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) void SoftCPU::FDIVR_RM64(const X86::Instruction& insn)