From f715cd89a9f4594af2c36c15a340d9b20a6b51ba Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 19 Oct 2023 14:07:59 -0400 Subject: [PATCH] Attempt CMPS, changing storage of direction; add flags check. --- .../Implementation/PerformImplementation.hpp | 71 +++++++++++ InstructionSets/x86/Status.hpp | 112 +++++++++--------- OSBindings/Mac/Clock SignalTests/8088Tests.mm | 36 +++++- 3 files changed, 160 insertions(+), 59 deletions(-) diff --git a/InstructionSets/x86/Implementation/PerformImplementation.hpp b/InstructionSets/x86/Implementation/PerformImplementation.hpp index 1f030f771..ae3449635 100644 --- a/InstructionSets/x86/Implementation/PerformImplementation.hpp +++ b/InstructionSets/x86/Implementation/PerformImplementation.hpp @@ -1354,6 +1354,72 @@ void pushf(MemoryT &memory, RegistersT ®isters, Status &status) { push(value, memory, registers); } +template +bool repetition_over(const InstructionT &instruction, RegistersT ®isters) { + if(instruction.repetition() == Repetition::None) { + return false; + } + + if constexpr (std::is_same_v) { + return !registers.cx(); + } else { + return !registers.ecx(); + } +} + +template +void repeat(const InstructionT &instruction, Status &status, RegistersT ®isters, FlowControllerT &flow_controller) { + if(instruction.repetition() == Repetition::None) { + return; + } + + bool count_exhausted = false; + + if constexpr (std::is_same_v) { + count_exhausted = !(--registers.cx()); + } else { + count_exhausted = !(--registers.ecx()); + } + + if(count_exhausted) { + return; + } + const bool zero = status.flag(); + if(instruction.repetition() == Repetition::RepE && !zero) { + return; + } else if(instruction.repetition() == Repetition::RepNE && zero) { + return; + } + + flow_controller.repeat_last(); +} + +template +void cmps(const InstructionT &instruction, MemoryT &memory, RegistersT ®isters, Status &status, FlowControllerT &flow_controller) { + if(repetition_over(instruction, registers)) { + return; + } + + Source source_segment = instruction.segment_override(); + if(source_segment == Source::None) source_segment = Source::DS; + + if constexpr (std::is_same_v) { + IntT source = memory.template access(source_segment, registers.si()); + IntT destination = memory.template access(Source::ES, registers.di()); + Primitive::sub(destination, source, status); + registers.si() += status.direction(); + registers.di() += status.direction(); + } else { + IntT source = memory.template access(source_segment, registers.esi()); + IntT destination = memory.template access(Source::ES, registers.edi()); + Primitive::sub(destination, source, status); + registers.esi() += status.direction(); + registers.edi() += status.direction(); + } + + repeat(instruction, status, registers, flow_controller); +} + } template < @@ -1569,6 +1635,11 @@ template < case Operation::PUSH: Primitive::push(source(), memory, registers); break; case Operation::POPF: Primitive::popf(memory, registers, status); break; case Operation::PUSHF: Primitive::pushf(memory, registers, status); break; + + // TODO: don't assume address size below. + case Operation::CMPS: + Primitive::cmps(instruction, memory, registers, status, flow_controller); + break; } // Write to memory if required to complete this operation. diff --git a/InstructionSets/x86/Status.hpp b/InstructionSets/x86/Status.hpp index a79146200..24797bbab 100644 --- a/InstructionSets/x86/Status.hpp +++ b/InstructionSets/x86/Status.hpp @@ -84,14 +84,14 @@ class Status { // Flag getters. template bool flag() const { switch(flag) { - case Flag::Carry: return carry; - case Flag::AuxiliaryCarry: return auxiliary_carry; - case Flag::Sign: return sign; - case Flag::Overflow: return overflow; - case Flag::Trap: return trap; - case Flag::Interrupt: return interrupt; - case Flag::Direction: return direction; - case Flag::Zero: return !zero; + case Flag::Carry: return carry_; + case Flag::AuxiliaryCarry: return auxiliary_carry_; + case Flag::Sign: return sign_; + case Flag::Overflow: return overflow_; + case Flag::Trap: return trap_; + case Flag::Interrupt: return interrupt_; + case Flag::Direction: return direction_ < 0; + case Flag::Zero: return !zero_; case Flag::ParityOdd: return not_parity_bit(); } } @@ -126,15 +126,15 @@ class Status { for(const auto flag: {flags...}) { switch(flag) { default: break; - case Flag::Zero: zero = value; break; - case Flag::Sign: sign = value & Numeric::top_bit(); break; - case Flag::ParityOdd: parity = value; break; - case Flag::Carry: carry = value; break; - case Flag::AuxiliaryCarry: auxiliary_carry = value; break; - case Flag::Overflow: overflow = value; break; - case Flag::Interrupt: interrupt = value; break; - case Flag::Trap: trap = value; break; - case Flag::Direction: direction = value; break; + case Flag::Zero: zero_ = value; break; + case Flag::Sign: sign_ = value & Numeric::top_bit(); break; + case Flag::ParityOdd: parity_ = value; break; + case Flag::Carry: carry_ = value; break; + case Flag::AuxiliaryCarry: auxiliary_carry_ = value; break; + case Flag::Overflow: overflow_ = value; break; + case Flag::Interrupt: interrupt_ = value; break; + case Flag::Trap: trap_ = value; break; + case Flag::Direction: direction_ = value ? -1 : 1; break; } } } @@ -142,44 +142,45 @@ class Status { set_from(value); } - template IntT carry_bit() const { return carry ? 1 : 0; } + template IntT carry_bit() const { return carry_ ? 1 : 0; } bool not_parity_bit() const { // x86 parity always considers the lowest 8-bits only. - auto result = static_cast(parity); + auto result = static_cast(parity_); result ^= result >> 4; result ^= result >> 2; result ^= result >> 1; return result & 1; } + template IntT direction() const { return static_cast(direction_); } + // Complete value get and set. void set(uint16_t value) { - carry = value & ConditionCode::Carry; - auxiliary_carry = value & ConditionCode::AuxiliaryCarry; - sign = value & ConditionCode::Sign; - overflow = value & ConditionCode::Overflow; - trap = value & ConditionCode::Trap; - interrupt = value & ConditionCode::Interrupt; - direction = value & ConditionCode::Direction; + carry_ = value & ConditionCode::Carry; + auxiliary_carry_ = value & ConditionCode::AuxiliaryCarry; + sign_ = value & ConditionCode::Sign; + overflow_ = value & ConditionCode::Overflow; + trap_ = value & ConditionCode::Trap; + interrupt_ = value & ConditionCode::Interrupt; + direction_ = (value & ConditionCode::Direction) ? -1 : 1; - zero = (~value) & ConditionCode::Zero; + zero_ = (~value) & ConditionCode::Zero; - parity = (~value) & ConditionCode::Parity; + parity_ = (~value) & ConditionCode::Parity; } uint16_t get() const { return 0xf002 | - (carry ? ConditionCode::Carry : 0) | - (auxiliary_carry ? ConditionCode::AuxiliaryCarry : 0) | - (sign ? ConditionCode::Sign : 0) | - (overflow ? ConditionCode::Overflow : 0) | - (trap ? ConditionCode::Trap : 0) | - (interrupt ? ConditionCode::Interrupt : 0) | - (direction ? ConditionCode::Direction : 0) | - - (zero ? 0 : ConditionCode::Zero) | + (flag() ? ConditionCode::Carry : 0) | + (flag() ? ConditionCode::AuxiliaryCarry : 0) | + (flag() ? ConditionCode::Sign : 0) | + (flag() ? ConditionCode::Overflow : 0) | + (flag() ? ConditionCode::Trap : 0) | + (flag() ? ConditionCode::Interrupt : 0) | + (flag() ? ConditionCode::Direction : 0) | + (flag() ? ConditionCode::Zero : 0) | (not_parity_bit() ? 0 : ConditionCode::Parity); } @@ -187,18 +188,18 @@ class Status { std::string to_string() const { std::string result; - if(overflow) result += "O"; else result += "-"; - if(direction) result += "D"; else result += "-"; - if(interrupt) result += "I"; else result += "-"; - if(trap) result += "T"; else result += "-"; - if(sign) result += "S"; else result += "-"; - if(!zero) result += "S"; else result += "-"; + if(overflow_) result += "O"; else result += "-"; + if(direction_) result += "D"; else result += "-"; + if(interrupt_) result += "I"; else result += "-"; + if(trap_) result += "T"; else result += "-"; + if(sign_) result += "S"; else result += "-"; + if(!zero_) result += "Z"; else result += "-"; result += "-"; - if(auxiliary_carry) result += "A"; else result += "-"; + if(auxiliary_carry_) result += "A"; else result += "-"; result += "-"; if(!not_parity_bit()) result += "P"; else result += "-"; result += "-"; - if(carry) result += "C"; else result += "-"; + if(carry_) result += "C"; else result += "-"; return result; } @@ -209,19 +210,22 @@ class Status { private: // Non-zero => set; zero => unset. - uint32_t carry; - uint32_t auxiliary_carry; - uint32_t sign; - uint32_t overflow; - uint32_t trap; - uint32_t interrupt; - uint32_t direction; + uint32_t carry_; + uint32_t auxiliary_carry_; + uint32_t sign_; + uint32_t overflow_; + uint32_t trap_; + uint32_t interrupt_; + + // +1 = direction flag not set; + // -1 = direction flag set. + int32_t direction_; // Zero => set; non-zero => unset. - uint32_t zero; + uint32_t zero_; // Odd number of bits => set; even => unset. - uint32_t parity; + uint32_t parity_; }; } diff --git a/OSBindings/Mac/Clock SignalTests/8088Tests.mm b/OSBindings/Mac/Clock SignalTests/8088Tests.mm index ed06d0cc3..fa3adf2dd 100644 --- a/OSBindings/Mac/Clock SignalTests/8088Tests.mm +++ b/OSBindings/Mac/Clock SignalTests/8088Tests.mm @@ -230,6 +230,10 @@ class FlowController { void halt() {} void wait() {} + void repeat_last() { + // TODO. + } + private: Memory &memory_; Registers ®isters_; @@ -390,8 +394,11 @@ struct FailedExecution { @"C4.json.gz", // LES @"8D.json.gz", // LEA - // TODO: CMPS, LODS, MOVS, SCAS, STOS - + // TODO: LODS, MOVS, SCAS, STOS +*/ + // CMPS + @"A6.json.gz", //@"A7.json.gz", +/* @"E0.json.gz", // LOOPNE @"E1.json.gz", // LOOPE @"E2.json.gz", // LOOP @@ -426,7 +433,7 @@ struct FailedExecution { // NOP @"90.json.gz", -*/ + // POP @"07.json.gz", @"0F.json.gz", @"17.json.gz", @"1F.json.gz", @"58.json.gz", @"59.json.gz", @"5A.json.gz", @"5B.json.gz", @@ -444,7 +451,7 @@ struct FailedExecution { // PUSHF @"9C.json.gz", -/* + // RCL @"D0.2.json.gz", @"D2.2.json.gz", @"D1.2.json.gz", @"D3.2.json.gz", @@ -653,7 +660,26 @@ struct FailedExecution { registers.ss_ = [value[@"ss"] intValue]; registers.ip_ = [value[@"ip"] intValue]; - status.set([value[@"flags"] intValue]); + const uint16_t flags = [value[@"flags"] intValue]; + status.set(flags); + + // Apply a quick test of flag packing/unpacking. + constexpr auto defined_flags = static_cast( + InstructionSet::x86::ConditionCode::Carry | + InstructionSet::x86::ConditionCode::Parity | + InstructionSet::x86::ConditionCode::AuxiliaryCarry | + InstructionSet::x86::ConditionCode::Zero | + InstructionSet::x86::ConditionCode::Sign | + InstructionSet::x86::ConditionCode::Trap | + InstructionSet::x86::ConditionCode::Interrupt | + InstructionSet::x86::ConditionCode::Direction | + InstructionSet::x86::ConditionCode::Overflow + ); + XCTAssert((status.get() & defined_flags) == (flags & defined_flags), + "Set status of %04x was returned as %04x", + flags & defined_flags, + (status.get() & defined_flags) + ); } - (void)applyExecutionTest:(NSDictionary *)test metadata:(NSDictionary *)metadata {