diff --git a/InstructionSets/M68k/Implementation/PerformImplementation.hpp b/InstructionSets/M68k/Implementation/PerformImplementation.hpp index ef6f3d42d..91bc447f4 100644 --- a/InstructionSets/M68k/Implementation/PerformImplementation.hpp +++ b/InstructionSets/M68k/Implementation/PerformImplementation.hpp @@ -828,14 +828,14 @@ template < set_neg_zero(v, m); \ status.overflow_flag = (Status::FlagT(value) ^ status.zero_result) & Status::FlagT(m); -#define decode_shift_count() \ +#define decode_shift_count(type) \ int shift_count = src.l & 63; \ - flow_controller.did_shift(shift_count); + flow_controller.template did_shift(shift_count); #define set_flags_w(t) set_flags(src.w, 0x8000, t) #define asl(destination, size) {\ - decode_shift_count(); \ + decode_shift_count(decltype(destination)); \ const auto value = destination; \ \ if(!shift_count) { \ @@ -865,7 +865,7 @@ template < case Operation::ASLl: asl(dest.l, 32); break; #define asr(destination, size) {\ - decode_shift_count(); \ + decode_shift_count(decltype(destination)); \ const auto value = destination; \ \ if(!shift_count) { \ @@ -909,7 +909,7 @@ template < status.carry_flag = value & (t); #define lsl(destination, size) {\ - decode_shift_count(); \ + decode_shift_count(decltype(destination)); \ const auto value = destination; \ \ if(!shift_count) { \ @@ -933,7 +933,7 @@ template < case Operation::LSLl: lsl(dest.l, 32); break; #define lsr(destination, size) {\ - decode_shift_count(); \ + decode_shift_count(decltype(destination)); \ const auto value = destination; \ \ if(!shift_count) { \ @@ -957,7 +957,7 @@ template < case Operation::LSRl: lsr(dest.l, 32); break; #define rol(destination, size) { \ - decode_shift_count(); \ + decode_shift_count(decltype(destination)); \ const auto value = destination; \ \ if(!shift_count) { \ @@ -985,7 +985,7 @@ template < case Operation::ROLl: rol(dest.l, 32); break; #define ror(destination, size) { \ - decode_shift_count(); \ + decode_shift_count(decltype(destination)); \ const auto value = destination; \ \ if(!shift_count) { \ @@ -1013,7 +1013,7 @@ template < case Operation::RORl: ror(dest.l, 32); break; #define roxl(destination, size) { \ - decode_shift_count(); \ + decode_shift_count(decltype(destination)); \ \ shift_count %= (size + 1); \ uint64_t compound = uint64_t(destination) | (status.extend_flag ? (1ull << size) : 0); \ @@ -1037,7 +1037,7 @@ template < case Operation::ROXLl: roxl(dest.l, 32); break; #define roxr(destination, size) { \ - decode_shift_count(); \ + decode_shift_count(decltype(destination)); \ \ shift_count %= (size + 1); \ uint64_t compound = uint64_t(destination) | (status.extend_flag ? (1ull << size) : 0); \ diff --git a/InstructionSets/M68k/Perform.hpp b/InstructionSets/M68k/Perform.hpp index 3df7b5736..300706b00 100644 --- a/InstructionSets/M68k/Perform.hpp +++ b/InstructionSets/M68k/Perform.hpp @@ -32,8 +32,11 @@ struct NullFlowController { /// Indicates that a @c CHK was performed, along with whether the result @c was_under zero or @c was_over the source operand. void did_chk([[maybe_unused]] bool was_under, [[maybe_unused]] bool was_over) {} - /// Indicates an in-register shift or roll occurred, providing the number of bits shifted by. - void did_shift([[maybe_unused]] int bit_count) {} + /// Indicates an in-register shift or roll occurred, providing the number of bits shifted by + /// and the type shifted. + /// + /// @c IntT may be uint8_t, uint16_t or uint32_t. + template void did_shift([[maybe_unused]] int bit_count) {} /// Indicates that a @c DIVU was performed, providing the @c dividend and @c divisor. /// If @c did_overflow is @c true then the divide ended in overflow. diff --git a/OSBindings/Mac/Clock SignalTests/68000ArithmeticTests.mm b/OSBindings/Mac/Clock SignalTests/68000ArithmeticTests.mm index c6ee45d10..e56e24a23 100644 --- a/OSBindings/Mac/Clock SignalTests/68000ArithmeticTests.mm +++ b/OSBindings/Mac/Clock SignalTests/68000ArithmeticTests.mm @@ -870,7 +870,16 @@ XCTAssertEqual(state.registers.data[1], 0x1fffffff); XCTAssertEqual(state.registers.supervisor_stack_pointer, initial_sp - 6); XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend); - XCTAssertEqual(44, self.machine->get_cycle_count()); + + // Total expected bus pattern: + // + // np | nn nn | nw nw nw np np np n np = 42 cycles + // + // Noted: Yacht shows a total of three nps for a DIVS #; + // I believe this is incorrect as it includes two in the + // '1st op (ea)' stage, but an immediate word causes + // only one elsewhere. + XCTAssertEqual(42, self.machine->get_cycle_count()); // Check stack contents; should be PC.l, PC.h and status register. // Assumed: the program counter on the stack is that of the @@ -908,7 +917,11 @@ const auto state = self.machine->get_processor_state(); XCTAssertEqual(state.registers.data[1], 0x4768f231); - XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Negative | ConditionCode::Overflow); + + // This test should produce overflow; so don't test N or Z flags. + XCTAssertEqual( + state.registers.status & (ConditionCode::Carry | ConditionCode::Overflow | ConditionCode::Extend), + ConditionCode::Extend | ConditionCode::Overflow); XCTAssertEqual(14, self.machine->get_cycle_count()); } @@ -917,7 +930,10 @@ const auto state = self.machine->get_processor_state(); XCTAssertEqual(state.registers.data[1], 0x4768f231); - XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Negative | ConditionCode::Overflow); + // This test should also produce overflow; so don't test N or Z flags. + XCTAssertEqual( + state.registers.status & (ConditionCode::Carry | ConditionCode::Overflow | ConditionCode::Extend), + ConditionCode::Extend | ConditionCode::Overflow); XCTAssertEqual(14, self.machine->get_cycle_count()); } diff --git a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp index 5e67d9417..e64edfa72 100644 --- a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp +++ b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp @@ -592,6 +592,11 @@ void Processor void ProcessorBase::did_divu(uint32_t dividend, uin } if(did_overflow) { - dynamic_instruction_length_ = 3; // Just a quick nn n, and then on to prefetch. + dynamic_instruction_length_ = 3; // Covers the nn n to get into the loop. return; } @@ -2555,13 +2556,15 @@ template void ProcessorBase::did_divu(uint32_t dividend, uin // since this is a classic divide algorithm, but would rather that // errors produce incorrect timing only, not incorrect timing plus // incorrect results. - dynamic_instruction_length_ = 3; // Covers the nn n to get into the loop. + dynamic_instruction_length_ = + 3 + // nn n to get into the loop; + 30 + // nn per iteration of the loop below; + 3; // n nn upon completion of the loop. divisor <<= 16; for(int c = 0; c < 15; ++c) { - if(dividend & 0x80000000) { + if(dividend & 0x8000'0000) { dividend = (dividend << 1) - divisor; - dynamic_instruction_length_ += 2; // The fixed nn iteration cost. } else { dividend <<= 1; @@ -2569,9 +2572,9 @@ template void ProcessorBase::did_divu(uint32_t dividend, uin // and test the sign of the result, but this is easier to follow: if (dividend >= divisor) { dividend -= divisor; - dynamic_instruction_length_ += 3; // i.e. the original nn plus one further n before going down the MSB=0 route. + dynamic_instruction_length_ += 1; // i.e. the original nn plus one further n before going down the MSB=0 route. } else { - dynamic_instruction_length_ += 4; // The costliest path (since in real life it's a subtraction and then a step + dynamic_instruction_length_ += 2; // The costliest path (since in real life it's a subtraction and then a step // back from there) — all costs accrue. So the fixed nn loop plus another n, // plus another one. } @@ -2635,7 +2638,7 @@ template void ProcessorBase::did_divs(int32_t dividend, int3 template void ProcessorBase::did_mulu(IntT multiplier) { // Count number of bits set. convert_to_bit_count_16(multiplier); - dynamic_instruction_length_ = multiplier; + dynamic_instruction_length_ = 17 + multiplier; } template void ProcessorBase::did_muls(IntT multiplier) { @@ -2644,13 +2647,17 @@ template void ProcessorBase::did_muls(IntT multiplier) { // Treat the bit to the right of b0 as 0. int number_of_pairs = (multiplier ^ (multiplier << 1)) & 0xffff; convert_to_bit_count_16(number_of_pairs); - dynamic_instruction_length_ = number_of_pairs; + dynamic_instruction_length_ = 17 + number_of_pairs; } #undef convert_to_bit_count_16 -void ProcessorBase::did_shift(int bits_shifted) { - dynamic_instruction_length_ = bits_shifted; +template void ProcessorBase::did_shift(int bits_shifted) { + if constexpr (sizeof(IntT) == 4) { + dynamic_instruction_length_ = bits_shifted + 2; + } else { + dynamic_instruction_length_ = bits_shifted + 1; + } } template void ProcessorBase::raise_exception(int vector) { diff --git a/Processors/68000Mk2/Implementation/68000Mk2Storage.hpp b/Processors/68000Mk2/Implementation/68000Mk2Storage.hpp index c0ea0a942..358dceb2c 100644 --- a/Processors/68000Mk2/Implementation/68000Mk2Storage.hpp +++ b/Processors/68000Mk2/Implementation/68000Mk2Storage.hpp @@ -148,7 +148,7 @@ struct ProcessorBase: public InstructionSet::M68k::NullFlowController { template void did_muls(IntT); inline void did_chk(bool, bool); inline void did_scc(bool); - inline void did_shift(int); + template void did_shift(int); template void did_divu(uint32_t, uint32_t); template void did_divs(int32_t, int32_t); inline void did_bit_op(int);