summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2020-11-14 15:15:41 +0100
committerAndreas Kling <kling@serenityos.org>2020-11-14 15:33:56 +0100
commit60ff27c63358ccf147c05c7cdfa6ca0d5d5a547c (patch)
treef46f7be95757757c3539f382f44d2a9394c83ffe
parentd4509647d8ebbab89daedf705c25f8929cc1adb4 (diff)
downloadserenity-60ff27c63358ccf147c05c7cdfa6ca0d5d5a547c.zip
UserspaceEmulator: Improve FCOMI/FCOMIP/FUCOMI/FUCOMIP
These instructions now operate on the specified FPU stack entry instead of always using ST(0) and ST(1). FUCOMI and FUCOMIP also handle NaN values slightly better.
-rw-r--r--DevTools/UserspaceEmulator/SoftCPU.cpp24
1 files changed, 16 insertions, 8 deletions
diff --git a/DevTools/UserspaceEmulator/SoftCPU.cpp b/DevTools/UserspaceEmulator/SoftCPU.cpp
index 94de431e56..e86db38ea9 100644
--- a/DevTools/UserspaceEmulator/SoftCPU.cpp
+++ b/DevTools/UserspaceEmulator/SoftCPU.cpp
@@ -1709,24 +1709,32 @@ void SoftCPU::FNINIT(const X86::Instruction&) { TODO_INSN(); }
void SoftCPU::FNSETPM(const X86::Instruction&) { TODO_INSN(); }
void SoftCPU::FLD_RM80(const X86::Instruction&) { TODO_INSN(); }
-void SoftCPU::FUCOMI(const X86::Instruction&)
+void SoftCPU::FUCOMI(const X86::Instruction& insn)
{
+ auto i = insn.rm() & 7;
// FIXME: Unordered comparison checks.
// FIXME: QNaN / exception handling.
// FIXME: Set C0, C2, C3 in FPU status word.
- set_zf(fpu_get(0) == fpu_get(1));
- set_pf(false);
- set_cf(fpu_get(0) < fpu_get(1));
- set_of(false);
+ 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);
+ }
}
-void SoftCPU::FCOMI(const X86::Instruction&)
+void SoftCPU::FCOMI(const X86::Instruction& insn)
{
+ auto i = insn.rm() & 7;
// FIXME: QNaN / exception handling.
// FIXME: Set C0, C2, C3 in FPU status word.
- set_zf(fpu_get(0) == fpu_get(1));
+ set_zf(fpu_get(0) == fpu_get(i));
set_pf(false);
- set_cf(fpu_get(0) < fpu_get(1));
+ set_cf(fpu_get(0) < fpu_get(i));
set_of(false);
}