From 800c76a4fe0b2d34cd7b098241df357f264ac4b9 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 9 Nov 2023 11:55:04 -0500 Subject: [PATCH] Capture and respond to IDIV_REP. --- InstructionSets/x86/Decoder.cpp | 2 +- .../x86/Implementation/Arithmetic.hpp | 11 +++++++++-- .../Implementation/PerformImplementation.hpp | 9 +++++---- InstructionSets/x86/Instruction.cpp | 17 +++++++++-------- InstructionSets/x86/Instruction.hpp | 9 +++++++++ 5 files changed, 33 insertions(+), 15 deletions(-) diff --git a/InstructionSets/x86/Decoder.cpp b/InstructionSets/x86/Decoder.cpp index 32d676b1d..4b6c788d9 100644 --- a/InstructionSets/x86/Decoder.cpp +++ b/InstructionSets/x86/Decoder.cpp @@ -33,7 +33,7 @@ std::pair::InstructionT> Decoder::decode(con /// Sets the operation and verifies that the current repetition, if any, is compatible, discarding it otherwise. #define SetOperation(op) \ - operation_ = rep_operation(op, repetition_); + operation_ = rep_operation(op, repetition_); /// Helper macro for those that follow. #define SetOpSrcDestSize(op, src, dest, size) \ diff --git a/InstructionSets/x86/Implementation/Arithmetic.hpp b/InstructionSets/x86/Implementation/Arithmetic.hpp index 971a877cb..ecc36508b 100644 --- a/InstructionSets/x86/Implementation/Arithmetic.hpp +++ b/InstructionSets/x86/Implementation/Arithmetic.hpp @@ -227,7 +227,7 @@ void div( destination_high = dividend % source; } -template +template void idiv( modify_t destination_high, modify_t destination_low, @@ -279,7 +279,14 @@ void idiv( // TEMPORARY HACK. Will not work with DWords. using sIntT = typename std::make_signed::type; const int32_t dividend = (sIntT(destination_high) << (8 * sizeof(IntT))) + destination_low; - const auto result = dividend / sIntT(source); + auto result = dividend / sIntT(source); + + // An 8086 quirk: rep IDIV performs an IDIV that switches the sign on its result, + // due to reuse of an internal flag. + if constexpr (invert) { + result = -result; + } + if(sIntT(result) != result) { interrupt(Interrupt::DivideError, context); return; diff --git a/InstructionSets/x86/Implementation/PerformImplementation.hpp b/InstructionSets/x86/Implementation/PerformImplementation.hpp index a28073a1b..1808366e4 100644 --- a/InstructionSets/x86/Implementation/PerformImplementation.hpp +++ b/InstructionSets/x86/Implementation/PerformImplementation.hpp @@ -207,10 +207,11 @@ template < Primitive::test(destination_r(), source_r(), context); return; - case Operation::MUL: Primitive::mul(pair_high(), pair_low(), source_r(), context); return; - case Operation::IMUL_1: Primitive::imul(pair_high(), pair_low(), source_r(), context); return; - case Operation::DIV: Primitive::div(pair_high(), pair_low(), source_r(), context); return; - case Operation::IDIV: Primitive::idiv(pair_high(), pair_low(), source_r(), context); return; + case Operation::MUL: Primitive::mul(pair_high(), pair_low(), source_r(), context); return; + case Operation::IMUL_1: Primitive::imul(pair_high(), pair_low(), source_r(), context); return; + case Operation::DIV: Primitive::div(pair_high(), pair_low(), source_r(), context); return; + case Operation::IDIV: Primitive::idiv(pair_high(), pair_low(), source_r(), context); return; + case Operation::IDIV_REP: Primitive::idiv(pair_high(), pair_low(), source_r(), context); return; case Operation::INC: Primitive::inc(destination_rmw(), context); break; case Operation::DEC: Primitive::dec(destination_rmw(), context); break; diff --git a/InstructionSets/x86/Instruction.cpp b/InstructionSets/x86/Instruction.cpp index d66a43d3c..edcf2b738 100644 --- a/InstructionSets/x86/Instruction.cpp +++ b/InstructionSets/x86/Instruction.cpp @@ -105,14 +105,15 @@ std::string InstructionSet::x86::to_string(Operation operation, DataSize size, M case Operation::HLT: return "hlt"; case Operation::WAIT: return "wait"; - case Operation::ADC: return "adc"; - case Operation::ADD: return "add"; - case Operation::SBB: return "sbb"; - case Operation::SUB: return "sub"; - case Operation::MUL: return "mul"; - case Operation::IMUL_1: return "imul"; - case Operation::DIV: return "div"; - case Operation::IDIV: return "idiv"; + case Operation::ADC: return "adc"; + case Operation::ADD: return "add"; + case Operation::SBB: return "sbb"; + case Operation::SUB: return "sub"; + case Operation::MUL: return "mul"; + case Operation::IMUL_1: return "imul"; + case Operation::DIV: return "div"; + case Operation::IDIV: return "idiv"; + case Operation::IDIV_REP: return "idiv"; case Operation::INC: return "inc"; case Operation::DEC: return "dec"; diff --git a/InstructionSets/x86/Instruction.hpp b/InstructionSets/x86/Instruction.hpp index 86326657f..23239bb66 100644 --- a/InstructionSets/x86/Instruction.hpp +++ b/InstructionSets/x86/Instruction.hpp @@ -231,6 +231,8 @@ enum class Operation: uint8_t { SETMOC, /// Set destination to ~0. SETMO, + /// Perform an IDIV and negative the result. + IDIV_REP, // // 80186 additions. @@ -474,8 +476,15 @@ enum class Repetition: uint8_t { }; /// @returns @c true if @c operation supports repetition mode @c repetition; @c false otherwise. +template constexpr Operation rep_operation(Operation operation, Repetition repetition) { switch(operation) { + case Operation::IDIV: + if constexpr (model == Model::i8086) { + return repetition != Repetition::None ? Operation::IDIV_REP : Operation::IDIV; + } + [[fallthrough]]; + default: return operation; case Operation::INS: