From 15acb1fc7ca4706b8f5c4e11ddb93d5b62041147 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 5 Oct 2023 15:49:07 -0400 Subject: [PATCH] Add ADC and ADD. --- .../Implementation/PerformImplementation.hpp | 92 +++++++++++++++++++ InstructionSets/x86/Status.hpp | 4 + OSBindings/Mac/Clock SignalTests/8088Tests.mm | 2 +- 3 files changed, 97 insertions(+), 1 deletion(-) diff --git a/InstructionSets/x86/Implementation/PerformImplementation.hpp b/InstructionSets/x86/Implementation/PerformImplementation.hpp index dbe68bc5d..8d20ab5b2 100644 --- a/InstructionSets/x86/Implementation/PerformImplementation.hpp +++ b/InstructionSets/x86/Implementation/PerformImplementation.hpp @@ -9,10 +9,51 @@ #ifndef PerformImplementation_h #define PerformImplementation_h +#include "../../../Numeric/Carry.hpp" + namespace InstructionSet::x86 { namespace Primitive { +// +// BEGIN TEMPORARY COPY AND PASTE SECTION. +// +// The following are largely excised from the M68k PerformImplementation.hpp; if there proves to be no +// reason further to specialise them, there'll be a factoring out. In some cases I've tightened the documentation. +// + +/// @returns An int of type @c IntT with only the most-significant bit set. +template constexpr IntT top_bit() { + static_assert(!std::numeric_limits::is_signed); + constexpr IntT max = std::numeric_limits::max(); + return max - (max >> 1); +} + +/// @returns The number of bits in @c IntT. +template constexpr int bit_size() { + return sizeof(IntT) * 8; +} + +/// @returns An int with the top bit indicating whether overflow occurred during the calculation of +/// • @c lhs + @c rhs (if @c is_add is true); or +/// • @c lhs - @c rhs (if @c is_add is false) +/// and the result was @c result. All other bits will be clear. +template +IntT overflow(IntT lhs, IntT rhs, IntT result) { + const IntT output_changed = result ^ rhs; + const IntT input_differed = lhs ^ rhs; + + if constexpr (is_add) { + return top_bit() & output_changed & ~input_differed; + } else { + return top_bit() & output_changed & input_differed; + } +} + +// +// END COPY AND PASTE SECTION. +// + void aaa(CPU::RegisterPair16 &ax, Status &status) { /* IF ((AL AND 0FH) > 9) OR (AF = 1) @@ -101,6 +142,42 @@ void aas(CPU::RegisterPair16 &ax, Status &status) { ax.halves.low &= 0x0f; } +template +void adc(IntT &destination, IntT source, Status &status) { + /* + DEST ← DEST + SRC + CF; + */ + /* + The OF, SF, ZF, AF, CF, and PF flags are set according to the result. + */ + const IntT result = destination + source + status.carry_bit(); + + status.carry = Numeric::carried_out() - 1>(destination, source, result); + status.auxiliary_carry = Numeric::carried_in<4>(destination, source, result); + status.sign = status.zero = status.parity = result; + status.overflow = overflow(destination, source, result); + + destination = result; +} + +template +void add(IntT &destination, IntT source, Status &status) { + /* + DEST ← DEST + SRC; + */ + /* + The OF, SF, ZF, AF, CF, and PF flags are set according to the result. + */ + const IntT result = destination + source; + + status.carry = Numeric::carried_out() - 1>(destination, source, result); + status.auxiliary_carry = Numeric::carried_in<4>(destination, source, result); + status.sign = status.zero = status.parity = result; + status.overflow = overflow(destination, source, result); + + destination = result; +} + } template < @@ -119,6 +196,21 @@ template < case Operation::AAD: Primitive::aad(destination, source.halves.low, status); break; case Operation::AAM: Primitive::aam(destination, source.halves.low, status); break; case Operation::AAS: Primitive::aas(destination, status); break; + + case Operation::ADC: + static_assert(operation != Operation::ADC || data_size == DataSize::Byte || data_size == DataSize::Word); + switch(data_size) { + case DataSize::Byte: Primitive::adc(destination.halves.low, source.halves.low, status); break; + case DataSize::Word: Primitive::adc(destination.full, source.full, status); break; + } + break; + case Operation::ADD: + static_assert(operation != Operation::ADD || data_size == DataSize::Byte || data_size == DataSize::Word); + switch(data_size) { + case DataSize::Byte: Primitive::add(destination.halves.low, source.halves.low, status); break; + case DataSize::Word: Primitive::add(destination.full, source.full, status); break; + } + break; } (void)flow_controller; diff --git a/InstructionSets/x86/Status.hpp b/InstructionSets/x86/Status.hpp index 4c922ca6b..dbb9b4295 100644 --- a/InstructionSets/x86/Status.hpp +++ b/InstructionSets/x86/Status.hpp @@ -58,12 +58,16 @@ struct Status { uint32_t carry; uint32_t auxiliary_carry; uint32_t sign; + uint32_t overflow; // Zero => set; non-zero => unset. uint32_t zero; // Odd number of bits => set; even => unset. uint32_t parity; + + // Convenience getters. + template IntT carry_bit() { return carry ? 1 : 0; } }; } diff --git a/OSBindings/Mac/Clock SignalTests/8088Tests.mm b/OSBindings/Mac/Clock SignalTests/8088Tests.mm index ce5fa332a..bf5577be3 100644 --- a/OSBindings/Mac/Clock SignalTests/8088Tests.mm +++ b/OSBindings/Mac/Clock SignalTests/8088Tests.mm @@ -197,7 +197,7 @@ constexpr char TestSuiteHome[] = "/Users/tharte/Projects/ProcessorTests/8088/v1" InstructionSet::x86::perform< InstructionSet::x86::Model::i8086, - InstructionSet::x86::Operation::AAD, + InstructionSet::x86::Operation::ADD, InstructionSet::x86::DataSize::Byte >( dest,