diff --git a/InstructionSets/M68k/Implementation/PerformImplementation.hpp b/InstructionSets/M68k/Implementation/PerformImplementation.hpp index 5dc0cc0b3..c5bf3f401 100644 --- a/InstructionSets/M68k/Implementation/PerformImplementation.hpp +++ b/InstructionSets/M68k/Implementation/PerformImplementation.hpp @@ -251,6 +251,74 @@ template void set_neg_zero(IntT result, Status &status) { status.negative_flag = result & top_bit(); } +/// 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( + operation == Operation::ASLb || operation == Operation::ASLw || operation == Operation::ASLl || + operation == Operation::ASRb || operation == Operation::ASRw || operation == Operation::ASRl || + operation == Operation::LSLb || operation == Operation::LSLw || operation == Operation::LSLl || + operation == Operation::LSRb || operation == Operation::LSRw || operation == Operation::LSRl + ); + + const auto size = bit_size(); + const auto shift = shift_count(uint8_t(source), flow_controller); + + if(!shift) { + status.carry_flag = status.overflow_flag = 0; + } else { + enum class Type { + ASL, LSL, ASR, LSR + } type; + switch(operation) { + case Operation::ASLb: case Operation::ASLw: case Operation::ASLl: + type = Type::ASL; + break; + case Operation::LSLb: case Operation::LSLw: case Operation::LSLl: + type = Type::LSL; + break; + case Operation::ASRb: case Operation::ASRw: case Operation::ASRl: + type = Type::ASR; + break; + case Operation::LSRb: case Operation::LSRw: case Operation::LSRl: + type = Type::LSR; + break; + } + + switch(type) { + case Type::ASL: + case Type::LSL: + status.overflow_flag = + type == Type::LSL ? + 0 : (destination ^ (destination << shift)) & top_bit(); + if(shift < size) { + status.carry_flag = status.extend_flag = (destination >> (size - shift)) & 1; + } else { + status.carry_flag = status.extend_flag = 0; + } + destination <<= shift; + break; + + case Type::ASR: + case Type::LSR: { + const IntT sign_word = + type == Type::LSR ? + 0 : (destination & top_bit() ? IntT(~0) : 0); + + status.overflow_flag = 0; + status.carry_flag = status.extend_flag = (destination >> (shift - 1)) & 1; + + if(shift < size) { + destination = IntT((destination >> shift) | (sign_word << (size - shift))); + } else { + destination = sign_word; + } + } break; + } + } + + set_neg_zero(destination, status); +} + /// Perform a rotate without extend, i.e. any of RO[L/R].[b/w/l]. template void rotate(uint32_t source, IntT &destination, Status &status, FlowController &flow_controller) { static_assert( @@ -770,62 +838,24 @@ template < set_neg_zero(v, m); \ status.overflow_flag = (Status::FlagT(value) ^ status.zero_result) & Status::FlagT(m); -#define decode_shift_count(type) \ - int shift_count = src.l & 63; \ - flow_controller.template did_shift(shift_count); +#undef set_flags +#define set_flags(v, m, t) \ + status.zero_result = v; \ + status.negative_flag = status.zero_result & (m); \ + status.overflow_flag = 0; \ + status.carry_flag = value & (t); #define set_flags_w(t) set_flags(src.w, 0x8000, t) -#define asl(destination, size) {\ - decode_shift_count(decltype(destination)); \ - const auto value = destination; \ - \ - if(!shift_count) { \ - status.carry_flag = status.overflow_flag = 0; \ - } else { \ - destination = (shift_count < size) ? decltype(destination)(value << shift_count) : 0; \ - status.extend_flag = status.carry_flag = Status::FlagT(value) & Status::FlagT( (1u << (size - 1)) >> (shift_count - 1) ); \ - \ - if(shift_count >= size) status.overflow_flag = value && (value != decltype(value)(-1)); \ - else { \ - const auto mask = decltype(destination)(0xffffffff << (size - shift_count)); \ - status.overflow_flag = mask & value && ((mask & value) != mask); \ - } \ - } \ - \ - set_neg_zero(destination, 1 << (size - 1)); \ -} - case Operation::ASLm: { const auto value = src.w; src.w = uint16_t(value << 1); status.extend_flag = status.carry_flag = value & 0x8000; set_neg_zero_overflow(src.w, 0x8000); } break; - case Operation::ASLb: asl(dest.b, 8); break; - case Operation::ASLw: asl(dest.w, 16); break; - case Operation::ASLl: asl(dest.l, 32); break; - -#define asr(destination, size) {\ - decode_shift_count(decltype(destination)); \ - const auto value = destination; \ - \ - if(!shift_count) { \ - status.carry_flag = 0; \ - } else { \ - destination = (shift_count < size) ? \ - decltype(destination)(\ - (value >> shift_count) | \ - ((value & decltype(value)(1 << (size - 1)) ? 0xffffffff : 0x000000000) << (size - shift_count)) \ - ) : \ - decltype(destination)( \ - (value & decltype(value)(1 << (size - 1))) ? 0xffffffff : 0x000000000 \ - ); \ - status.extend_flag = status.carry_flag = Status::FlagT(value) & Status::FlagT(1 << (shift_count - 1)); \ - } \ - \ - set_neg_zero_overflow(destination, 1 << (size - 1)); \ -} + case Operation::ASLb: Primitive::shift(src.l, dest.b, status, flow_controller); break; + case Operation::ASLw: Primitive::shift(src.l, dest.w, status, flow_controller); break; + case Operation::ASLl: Primitive::shift(src.l, dest.l, status, flow_controller); break; case Operation::ASRm: { const auto value = src.w; @@ -833,36 +863,9 @@ template < status.extend_flag = status.carry_flag = value & 1; set_neg_zero_overflow(src.w, 0x8000); } break; - case Operation::ASRb: asr(dest.b, 8); break; - case Operation::ASRw: asr(dest.w, 16); break; - case Operation::ASRl: asr(dest.l, 32); break; - - -#undef set_neg_zero_overflow -#define set_neg_zero_overflow(v, m) \ - set_neg_zero(v, m); \ - status.overflow_flag = 0; - -#undef set_flags -#define set_flags(v, m, t) \ - status.zero_result = v; \ - status.negative_flag = status.zero_result & (m); \ - status.overflow_flag = 0; \ - status.carry_flag = value & (t); - -#define lsl(destination, size) {\ - decode_shift_count(decltype(destination)); \ - const auto value = destination; \ - \ - if(!shift_count) { \ - status.carry_flag = 0; \ - } else { \ - destination = (shift_count < size) ? decltype(destination)(value << shift_count) : 0; \ - status.extend_flag = status.carry_flag = Status::FlagT(value) & Status::FlagT( (1u << (size - 1)) >> (shift_count - 1) ); \ - } \ - \ - set_neg_zero_overflow(destination, 1 << (size - 1)); \ -} + case Operation::ASRb: Primitive::shift(src.l, dest.b, status, flow_controller); break; + case Operation::ASRw: Primitive::shift(src.l, dest.w, status, flow_controller); break; + case Operation::ASRl: Primitive::shift(src.l, dest.l, status, flow_controller); break; case Operation::LSLm: { const auto value = src.w; @@ -870,23 +873,9 @@ template < status.extend_flag = status.carry_flag = value & 0x8000; set_neg_zero_overflow(src.w, 0x8000); } break; - case Operation::LSLb: lsl(dest.b, 8); break; - case Operation::LSLw: lsl(dest.w, 16); break; - case Operation::LSLl: lsl(dest.l, 32); break; - -#define lsr(destination, size) {\ - decode_shift_count(decltype(destination)); \ - const auto value = destination; \ - \ - if(!shift_count) { \ - status.carry_flag = 0; \ - } else { \ - destination = (shift_count < size) ? (value >> shift_count) : 0; \ - status.extend_flag = status.carry_flag = value & Status::FlagT(1 << (shift_count - 1)); \ - } \ - \ - set_neg_zero_overflow(destination, 1 << (size - 1)); \ -} + case Operation::LSLb: Primitive::shift(src.l, dest.b, status, flow_controller); break; + case Operation::LSLw: Primitive::shift(src.l, dest.w, status, flow_controller); break; + case Operation::LSLl: Primitive::shift(src.l, dest.l, status, flow_controller); break; case Operation::LSRm: { const auto value = src.w; @@ -894,11 +883,9 @@ template < status.extend_flag = status.carry_flag = value & 1; set_neg_zero_overflow(src.w, 0x8000); } break; - case Operation::LSRb: lsr(dest.b, 8); break; - case Operation::LSRw: lsr(dest.w, 16); break; - case Operation::LSRl: lsr(dest.l, 32); break; - - // --- + case Operation::LSRb: Primitive::shift(src.l, dest.b, status, flow_controller); break; + case Operation::LSRw: Primitive::shift(src.l, dest.w, status, flow_controller); break; + case Operation::LSRl: Primitive::shift(src.l, dest.l, status, flow_controller); break; case Operation::ROLm: { const auto value = src.w; @@ -940,15 +927,7 @@ template < case Operation::ROXRw: Primitive::rox(src.l, dest.w, status, flow_controller); break; case Operation::ROXRl: Primitive::rox(src.l, dest.l, status, flow_controller); break; -#undef ror -#undef rol -#undef asr -#undef lsr -#undef lsl -#undef asl - #undef set_flags -#undef decode_shift_count #undef set_flags_w #undef set_neg_zero_overflow #undef set_neg_zero