From 0857dd0ae58e3d1da07c8bc55d0410fd2c7f2561 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 1 Jun 2022 14:05:23 -0400 Subject: [PATCH 1/7] Include fixed base cost in MULU and MULS. --- Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp index 5e67d9417..04d589295 100644 --- a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp +++ b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp @@ -2635,7 +2635,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,7 +2644,7 @@ 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 From 91a6911a51deb2629737609c30b94330ce313a15 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 1 Jun 2022 15:03:03 -0400 Subject: [PATCH 2/7] Correct ADDA/SUBA timing. --- .../Implementation/68000Mk2Implementation.hpp | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp index 04d589295..3b4cde002 100644 --- a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp +++ b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp @@ -772,19 +772,15 @@ void Processor Date: Wed, 1 Jun 2022 15:27:09 -0400 Subject: [PATCH 3/7] Ensure proper resumption after a forced exit in `will_perform`. --- .../68000Mk2/Implementation/68000Mk2Implementation.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp index 3b4cde002..1b390a1e1 100644 --- a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp +++ b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp @@ -592,6 +592,11 @@ void Processor Date: Wed, 1 Jun 2022 20:30:51 -0400 Subject: [PATCH 4/7] Include fixed cost of rolls. Which includes providing slightly more information to `did_shift`. --- .../Implementation/PerformImplementation.hpp | 20 +++++++++---------- InstructionSets/M68k/Perform.hpp | 7 +++++-- .../Implementation/68000Mk2Implementation.hpp | 8 ++++++-- .../Implementation/68000Mk2Storage.hpp | 2 +- 4 files changed, 22 insertions(+), 15 deletions(-) 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/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp index 04d589295..45cf61952 100644 --- a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp +++ b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp @@ -2649,8 +2649,12 @@ template void ProcessorBase::did_muls(IntT multiplier) { #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); From 6dd89eb0d7d1ff76ec83e8d17b5b6f77a18ebb1b Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 2 Jun 2022 12:11:54 -0400 Subject: [PATCH 5/7] Adjust my expectation as to length. --- .../Mac/Clock SignalTests/68000ArithmeticTests.mm | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/OSBindings/Mac/Clock SignalTests/68000ArithmeticTests.mm b/OSBindings/Mac/Clock SignalTests/68000ArithmeticTests.mm index c6ee45d10..5811bfade 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 From f8e933438e97b8b197a12c1d59472f21a9e095fc Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 2 Jun 2022 12:26:25 -0400 Subject: [PATCH 6/7] Add missing tail cost. --- .../Implementation/68000Mk2Implementation.hpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp index bc067a8f6..e64edfa72 100644 --- a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp +++ b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp @@ -2547,7 +2547,7 @@ template 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; } @@ -2556,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; @@ -2570,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. } From 90d720ca288b2211fd20c60bba481af02edf0714 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 2 Jun 2022 12:30:39 -0400 Subject: [PATCH 7/7] Don't test undocumented flags. --- .../Mac/Clock SignalTests/68000ArithmeticTests.mm | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/68000ArithmeticTests.mm b/OSBindings/Mac/Clock SignalTests/68000ArithmeticTests.mm index 5811bfade..e56e24a23 100644 --- a/OSBindings/Mac/Clock SignalTests/68000ArithmeticTests.mm +++ b/OSBindings/Mac/Clock SignalTests/68000ArithmeticTests.mm @@ -917,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()); } @@ -926,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()); }