summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2020-07-18 17:29:50 +0200
committerAndreas Kling <kling@serenityos.org>2020-07-18 17:57:40 +0200
commite4b068aec52fb13b877414a773fc08ba8d231eca (patch)
tree68d92c193516439261406646f21665db660b1f27
parent9e6d002660246a77fa677f39d8c7122e009c5ceb (diff)
downloadserenity-e4b068aec52fb13b877414a773fc08ba8d231eca.zip
UserspaceEmulator: Fix buggy IDIV instructions
These were not doing mashing together the signed double-size results correctly and lost bits in the signed/unsigned casting process.
-rw-r--r--DevTools/UserspaceEmulator/SoftCPU.cpp29
1 files changed, 23 insertions, 6 deletions
diff --git a/DevTools/UserspaceEmulator/SoftCPU.cpp b/DevTools/UserspaceEmulator/SoftCPU.cpp
index b9addb76d9..4135f3281b 100644
--- a/DevTools/UserspaceEmulator/SoftCPU.cpp
+++ b/DevTools/UserspaceEmulator/SoftCPU.cpp
@@ -1257,18 +1257,35 @@ void SoftCPU::ESCAPE(const X86::Instruction&)
}
void SoftCPU::HLT(const X86::Instruction&) { TODO(); }
-void SoftCPU::IDIV_RM16(const X86::Instruction&) { TODO(); }
+
+void SoftCPU::IDIV_RM16(const X86::Instruction& insn)
+{
+ auto divisor = (i16)insn.modrm().read16(*this, insn);
+ if (divisor == 0) {
+ warn() << "Divide by zero";
+ TODO();
+ }
+ i32 dividend = (i32)(((u32)dx() << 16) | (u32)ax());
+ i32 result = dividend / divisor;
+ if (result > NumericLimits<i16>::max() || result < NumericLimits<i16>::min()) {
+ warn() << "Divide overflow";
+ TODO();
+ }
+
+ set_ax(result);
+ set_dx(dividend % divisor);
+}
void SoftCPU::IDIV_RM32(const X86::Instruction& insn)
{
- auto divisor = insn.modrm().read32(*this, insn);
+ auto divisor = (i32)insn.modrm().read32(*this, insn);
if (divisor == 0) {
warn() << "Divide by zero";
TODO();
}
- i64 dividend = ((i64)edx() << 32) | eax();
- auto result = dividend / divisor;
- if (result > NumericLimits<i32>::max()) {
+ i64 dividend = (i64)(((u64)edx() << 32) | (u64)eax());
+ i64 result = dividend / divisor;
+ if (result > NumericLimits<i32>::max() || result < NumericLimits<i32>::min()) {
warn() << "Divide overflow";
TODO();
}
@@ -1279,7 +1296,7 @@ void SoftCPU::IDIV_RM32(const X86::Instruction& insn)
void SoftCPU::IDIV_RM8(const X86::Instruction& insn)
{
- auto divisor = (i16)insn.modrm().read8(*this, insn);
+ auto divisor = (i8)insn.modrm().read8(*this, insn);
if (divisor == 0) {
warn() << "Divide by zero";
TODO();