diff --git a/InstructionSets/M68k/Implementation/PerformImplementation.hpp b/InstructionSets/M68k/Implementation/PerformImplementation.hpp index c5f7fda1c..95a484e30 100644 --- a/InstructionSets/M68k/Implementation/PerformImplementation.hpp +++ b/InstructionSets/M68k/Implementation/PerformImplementation.hpp @@ -9,6 +9,7 @@ #ifndef InstructionSets_M68k_PerformImplementation_h #define InstructionSets_M68k_PerformImplementation_h +#include "../../../Numeric/Carry.hpp" #include "../ExceptionVectors.hpp" #include @@ -25,28 +26,6 @@ inline int32_t s_extend16(uint16_t x) { return int32_t(int16_t(x)); } namespace Primitive { -/// @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 An int with the top bit indicating whether overflow occurred when @c source and @c destination -/// were either added (if @c is_add is true) or subtracted (if @c is_add is false) and the result was @c result. -/// All other bits will be clear. -template -static Status::FlagT overflow(IntT source, IntT destination, IntT result) { - const IntT output_changed = result ^ destination; - const IntT input_differed = source ^ destination; - - if constexpr (is_add) { - return top_bit() & output_changed & ~input_differed; - } else { - return top_bit() & output_changed & input_differed; - } -} - /// Performs an add or subtract (as per @c is_add) between @c source and @c destination, /// updating @c status. @c is_extend indicates whether this is an extend operation (e.g. ADDX) /// or a plain one (e.g. ADD). @@ -81,7 +60,7 @@ static void add_sub(IntT source, IntT &destination, Status &status) { status.zero_result = Status::FlagT(result); } status.set_negative(result); - status.overflow_flag = overflow(source, destination, result); + status.overflow_flag = Numeric::overflow(destination, source, result); destination = result; } @@ -143,7 +122,7 @@ void compare(IntT source, IntT destination, Status &status) { const IntT result = destination - source; status.carry_flag = result > destination; status.set_neg_zero(result); - status.overflow_flag = Primitive::overflow(source, destination, result); + status.overflow_flag = Numeric::overflow(destination, source, result); } /// @returns the name of the bit to be used as a mask for BCLR, BCHG, BSET or BTST for @@ -293,7 +272,7 @@ template void negative(IntT &source, Status &sta } status.extend_flag = status.carry_flag = result; // i.e. any value other than 0 will result in carry. status.set_negative(result); - status.overflow_flag = Primitive::overflow(source, IntT(0), result); + status.overflow_flag = Numeric::overflow(IntT(0), source, result); source = result; } @@ -311,11 +290,6 @@ template int shift_count(uint8_t source return count; } -/// @returns The number of bits in @c IntT. -template constexpr int bit_size() { - return sizeof(IntT) * 8; -} - /// Perform an arithmetic or logical shift, i.e. any of LSL, LSR, ASL or ASR. template void shift(uint32_t source, IntT &destination, Status &status, FlowController &flow_controller) { static_assert( @@ -325,7 +299,7 @@ template void shif operation == Operation::LSRb || operation == Operation::LSRw || operation == Operation::LSRl ); - constexpr auto size = bit_size(); + constexpr auto size = Numeric::bit_size(); const auto shift = shift_count(uint8_t(source), flow_controller); if(!shift) { @@ -355,7 +329,7 @@ template void shif if(shift > size) { status.carry_flag = status.extend_flag = 0; } else { - status.carry_flag = status.extend_flag = (destination << (shift - 1)) & top_bit(); + status.carry_flag = status.extend_flag = (destination << (shift - 1)) & Numeric::top_bit(); } if(type == Type::LSL) { @@ -370,7 +344,7 @@ template void shif // For a shift of n places, overflow will be set if the top n+1 bits were not // all the same value. const auto affected_bits = IntT( - ~((top_bit() >> shift) - 1) + ~((Numeric::top_bit() >> shift) - 1) ); // e.g. shift = 1 => ~((0x80 >> 1) - 1) = ~(0x40 - 1) = ~0x3f = 0xc0, i.e. if shift is // 1 then the top two bits are relevant to whether there was overflow. If they have the // same value, i.e. are both 0 or are both 1, then there wasn't. Otherwise there was. @@ -396,7 +370,7 @@ template void shif const IntT sign_word = type == Type::LSR ? - 0 : (destination & top_bit() ? IntT(~0) : 0); + 0 : (destination & Numeric::top_bit() ? IntT(~0) : 0); if(shift >= size) { destination = sign_word; @@ -417,7 +391,7 @@ template void rota operation == Operation::RORb || operation == Operation::RORw || operation == Operation::RORl ); - constexpr auto size = bit_size(); + constexpr auto size = Numeric::bit_size(); auto shift = shift_count(uint8_t(source), flow_controller); if(!shift) { @@ -442,7 +416,7 @@ template void rota (destination << (size - shift)) ); } - status.carry_flag = Status::FlagT(destination & top_bit()); + status.carry_flag = Status::FlagT(destination & Numeric::top_bit()); break; } } @@ -458,7 +432,7 @@ template void rox( operation == Operation::ROXRb || operation == Operation::ROXRw || operation == Operation::ROXRl ); - constexpr auto size = bit_size(); + constexpr auto size = Numeric::bit_size(); auto shift = shift_count(uint8_t(source), flow_controller) % (size + 1); if(!shift) { @@ -469,9 +443,9 @@ template void rox( case Operation::ROXLb: case Operation::ROXLw: case Operation::ROXLl: status.carry_flag = Status::FlagT((destination >> (size - shift)) & 1); - if(shift == bit_size()) { + if(shift == Numeric::bit_size()) { destination = IntT( - (status.extend_flag ? top_bit() : 0) | + (status.extend_flag ? Numeric::top_bit() : 0) | (destination >> 1) ); } else if(shift == 1) { @@ -491,7 +465,7 @@ template void rox( case Operation::ROXRb: case Operation::ROXRw: case Operation::ROXRl: status.carry_flag = Status::FlagT(destination & (1 << (shift - 1))); - if(shift == bit_size()) { + if(shift == Numeric::bit_size()) { destination = IntT( (status.extend_flag ? 1 : 0) | (destination << 1) @@ -499,12 +473,12 @@ template void rox( } else if(shift == 1) { destination = IntT( (destination >> 1) | - (status.extend_flag ? top_bit() : 0) + (status.extend_flag ? Numeric::top_bit() : 0) ); } else { destination = IntT( (destination >> shift) | - ((status.extend_flag ? top_bit() : 0) >> (shift - 1)) | + ((status.extend_flag ? Numeric::top_bit() : 0) >> (shift - 1)) | (destination << (size + 1 - shift)) ); } @@ -882,14 +856,14 @@ template < Shifts and rotates. */ case Operation::ASLm: - status.extend_flag = status.carry_flag = src.w & Primitive::top_bit(); - status.overflow_flag = (src.w ^ (src.w << 1)) & Primitive::top_bit(); + status.extend_flag = status.carry_flag = src.w & Numeric::top_bit(); + status.overflow_flag = (src.w ^ (src.w << 1)) & Numeric::top_bit(); src.w <<= 1; status.set_neg_zero(src.w); break; case Operation::LSLm: - status.extend_flag = status.carry_flag = src.w & Primitive::top_bit(); + status.extend_flag = status.carry_flag = src.w & Numeric::top_bit(); status.overflow_flag = 0; src.w <<= 1; status.set_neg_zero(src.w); @@ -898,7 +872,7 @@ template < case Operation::ASRm: status.extend_flag = status.carry_flag = src.w & 1; status.overflow_flag = 0; - src.w = (src.w & Primitive::top_bit()) | (src.w >> 1); + src.w = (src.w & Numeric::top_bit()) | (src.w >> 1); status.set_neg_zero(src.w); break; @@ -918,13 +892,13 @@ template < case Operation::RORm: src.w = uint16_t((src.w >> 1) | (src.w << 15)); - status.carry_flag = src.w & Primitive::top_bit(); + status.carry_flag = src.w & Numeric::top_bit(); status.overflow_flag = 0; status.set_neg_zero(src.w); break; case Operation::ROXLm: - status.carry_flag = src.w & Primitive::top_bit(); + status.carry_flag = src.w & Numeric::top_bit(); src.w = uint16_t((src.w << 1) | (status.extend_flag ? 0x0001 : 0x0000)); status.extend_flag = status.carry_flag; status.overflow_flag = 0;