diff options
author | Andreas Kling <kling@serenityos.org> | 2020-07-18 17:29:50 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-07-18 17:57:40 +0200 |
commit | e4b068aec52fb13b877414a773fc08ba8d231eca (patch) | |
tree | 68d92c193516439261406646f21665db660b1f27 /DevTools/UserspaceEmulator | |
parent | 9e6d002660246a77fa677f39d8c7122e009c5ceb (diff) | |
download | serenity-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.
Diffstat (limited to 'DevTools/UserspaceEmulator')
-rw-r--r-- | DevTools/UserspaceEmulator/SoftCPU.cpp | 29 |
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(); |