diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme b/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme index cdac581d4..9c2dca9ce 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme +++ b/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme @@ -69,7 +69,7 @@ </AdditionalOptions> </TestAction> <LaunchAction - buildConfiguration = "Release" + buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" enableASanStackUseAfterReturn = "YES" diff --git a/OSBindings/Mac/Clock SignalTests/68000Tests.mm b/OSBindings/Mac/Clock SignalTests/68000Tests.mm index 7358070fc..ac3955010 100644 --- a/OSBindings/Mac/Clock SignalTests/68000Tests.mm +++ b/OSBindings/Mac/Clock SignalTests/68000Tests.mm @@ -925,6 +925,40 @@ class CPU::MC68000::ProcessorStorageTests { XCTAssertEqual(_machine->get_cycle_count(), 8); } +- (void)performBSETD1Ind:(uint32_t)d1 { + _machine->set_program({ + 0x03d0 // BSET D1, (A0) + }); + auto state = _machine->get_processor_state(); + state.address[0] = 0x3000; + state.data[1] = d1; + *_machine->ram_at(0x3000) = 0x7800; + + _machine->set_processor_state(state); + _machine->run_for_instructions(1); + + state = _machine->get_processor_state(); + XCTAssertEqual(state.data[1], d1); + XCTAssertEqual(state.address[0], 0x3000); + XCTAssertEqual(_machine->get_cycle_count(), 12); +} + +- (void)testBSET_D1Ind_50 { + [self performBSETD1Ind:50]; + + const auto state = _machine->get_processor_state(); + XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Zero); + XCTAssertEqual(*_machine->ram_at(0x3000), 0x7c00); +} + +- (void)testBSET_D1Ind_3 { + [self performBSETD1Ind:3]; + + const auto state = _machine->get_processor_state(); + XCTAssertEqual(state.status & Flag::ConditionCodes, 0); + XCTAssertEqual(*_machine->ram_at(0x3000), 0x7800); +} + // MARK: DBcc - (void)performDBccTestOpcode:(uint16_t)opcode status:(uint16_t)status d2Outcome:(uint32_t)d2Output { diff --git a/Processors/68000/Implementation/68000Implementation.hpp b/Processors/68000/Implementation/68000Implementation.hpp index 11f81e4d6..69cdd006b 100644 --- a/Processors/68000/Implementation/68000Implementation.hpp +++ b/Processors/68000/Implementation/68000Implementation.hpp @@ -49,6 +49,12 @@ #define s_extend16(x) int32_t(int16_t(x)) #define s_extend8(x) int32_t(int8_t(x)) +// Sets the length of the next microcycle; if this is a debug build, also confirms +// that the microcycle being adjusted is the one that it's permissible to adjust. +#define set_next_microcycle_length(x) \ + assert(resizeable_microcycle_ == &bus_program->microcycle); \ + bus_program->microcycle.length = x + template <class T, bool dtack_is_implicit, bool signal_will_perform> void Processor<T, dtack_is_implicit, signal_will_perform>::run_for(HalfCycles duration) { const HalfCycles remaining_duration = duration + half_cycles_left_to_run_; @@ -623,13 +629,13 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces active_program_->destination->full &= ~(1 << (active_program_->source->full & 31)); // Clearing in the top word requires an extra four cycles. - active_step_->microcycle.length = HalfCycles(8 + ((active_program_->source->full & 31) / 16) * 4); + set_next_microcycle_length(HalfCycles(8 + ((active_program_->source->full & 31) / 16) * 4)); break; case Operation::BCHGl: zero_result_ = active_program_->destination->full & (1 << (active_program_->source->full & 31)); active_program_->destination->full ^= 1 << (active_program_->source->full & 31); - active_step_->microcycle.length = HalfCycles(4 + (((active_program_->source->full & 31) / 16) * 4)); + set_next_microcycle_length(HalfCycles(4 + (((active_program_->source->full & 31) / 16) * 4))); break; case Operation::BCHGb: @@ -640,7 +646,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces case Operation::BSETl: zero_result_ = active_program_->destination->full & (1 << (active_program_->source->full & 31)); active_program_->destination->full |= 1 << (active_program_->source->full & 31); - bus_program->microcycle.length = HalfCycles(4 + (((active_program_->source->full & 31) / 16) * 4)); + set_next_microcycle_length(HalfCycles(4 + (((active_program_->source->full & 31) / 16) * 4))); break; case Operation::BSETb: @@ -908,7 +914,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces } // Time taken = 38 cycles + 2 cycles per 1 in the source. - active_step_->microcycle.length = HalfCycles(4 * number_of_ones + 38*2); + set_next_microcycle_length(HalfCycles(4 * number_of_ones + 38*2)); } break; case Operation::MULS: { @@ -929,7 +935,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces } // Time taken = 38 cycles + 2 cycles per 1 in the source. - active_step_->microcycle.length = HalfCycles(4 * number_of_pairs + 38*2); + set_next_microcycle_length(HalfCycles(4 * number_of_pairs + 38*2)); } break; /* @@ -942,7 +948,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces bus_program = active_micro_op_->bus_program; \ \ populate_trap_steps(5, get_status()); \ - bus_program->microcycle.length = HalfCycles(8); \ + set_next_microcycle_length(HalfCycles(8)); \ \ program_counter_.full -= 2; @@ -964,7 +970,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces if(quotient >= 65536) { overflow_flag_ = 1; // TODO: is what should happen to the other flags known? - active_step_->microcycle.length = HalfCycles(3*2*2); + set_next_microcycle_length(HalfCycles(3*2*2)); break; } @@ -1002,7 +1008,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces } } } - active_step_->microcycle.length = HalfCycles(cycles_expended * 2); + set_next_microcycle_length(HalfCycles(cycles_expended * 2)); } break; case Operation::DIVS: { @@ -1027,7 +1033,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces // Check for overflow. If it exists, work here is already done. if(quotient > 32767 || quotient < -32768) { overflow_flag_ = 1; - active_step_->microcycle.length = HalfCycles(3*2*2); + set_next_microcycle_length(HalfCycles(3*2*2)); // These are officially undefined for results that overflow, so the below is a guess. zero_result_ = decltype(zero_result_)(divisor & 0xffff); @@ -1064,7 +1070,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces } else if(dividend < 0) { cycles_expended += 4; } - active_step_->microcycle.length = HalfCycles(cycles_expended * 2); + set_next_microcycle_length(HalfCycles(cycles_expended * 2)); } break; #undef announce_divide_by_zero @@ -1254,7 +1260,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces // Select the trap steps as next; the initial microcycle should be 4 cycles long. bus_program = trap_steps_; populate_trap_steps((decoded_instruction_.full & 15) + 32, get_status()); - bus_program->microcycle.length = HalfCycles(8); + set_next_microcycle_length(HalfCycles(8)); // The program counter to push is actually one slot ago. program_counter_.full -= 2; @@ -1265,7 +1271,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces // Select the trap steps as next; the initial microcycle should be 4 cycles long. bus_program = trap_steps_; populate_trap_steps(7, get_status()); - bus_program->microcycle.length = HalfCycles(0); + set_next_microcycle_length(HalfCycles(0)); program_counter_.full -= 4; } } break; @@ -1282,9 +1288,9 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces bus_program = trap_steps_; populate_trap_steps(6, get_status()); if(is_under) { - bus_program->microcycle.length = HalfCycles(16); + set_next_microcycle_length(HalfCycles(16)); } else { - bus_program->microcycle.length = HalfCycles(8); + set_next_microcycle_length(HalfCycles(8)); } // The program counter to push is two slots ago as whatever was the correct prefetch @@ -1538,7 +1544,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces #define decode_shift_count() \ int shift_count = (decoded_instruction_.full & 32) ? data_[(decoded_instruction_.full >> 9) & 7].full&63 : ( ((decoded_instruction_.full >> 9)&7) ? ((decoded_instruction_.full >> 9)&7) : 8) ; \ - bus_program->microcycle.length = HalfCycles(4 * shift_count); + set_next_microcycle_length(HalfCycles(4 * shift_count)); #define set_flags_b(t) set_flags(active_program_->destination->halves.low.halves.low, 0x80, t) #define set_flags_w(t) set_flags(active_program_->destination->halves.low.full, 0x8000, t) @@ -2139,3 +2145,4 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces #undef u_extend8 #undef s_extend16 #undef s_extend8 +#undef set_next_microcycle_length diff --git a/Processors/68000/Implementation/68000Storage.cpp b/Processors/68000/Implementation/68000Storage.cpp index c6110489e..da3484d82 100644 --- a/Processors/68000/Implementation/68000Storage.cpp +++ b/Processors/68000/Implementation/68000Storage.cpp @@ -3045,6 +3045,19 @@ struct ProcessorStorageConstructor { storage_.interrupt_micro_ops_ = &storage_.all_micro_ops_[interrupt_pointer]; link_operations(storage_.interrupt_micro_ops_, &arbitrary_base); + // If this is a debug build, not where the resizeable microcycle is + // (and double check that there's only the one). +#ifndef NDEBUG + for(size_t c = 0; c < storage_.all_bus_steps_.size() - 1; ++c) { + if(!storage_.all_bus_steps_[c+1].is_terminal()) continue; + + if(storage_.all_bus_steps_[c].microcycle.length == HalfCycles(0)) { + assert(!storage_.resizeable_microcycle_); + storage_.resizeable_microcycle_ = &storage_.all_bus_steps_[c].microcycle; + } + } +#endif + std::cout << storage_.all_bus_steps_.size() << " total steps" << std::endl; } diff --git a/Processors/68000/Implementation/68000Storage.hpp b/Processors/68000/Implementation/68000Storage.hpp index c68d44ac2..e34eb00aa 100644 --- a/Processors/68000/Implementation/68000Storage.hpp +++ b/Processors/68000/Implementation/68000Storage.hpp @@ -411,6 +411,11 @@ class ProcessorStorage { RegisterPair16 throwaway_value_; uint32_t movem_final_address_; + // Sanity checking for the debug build. +#ifndef NDEBUG + const Microcycle *resizeable_microcycle_ = nullptr; +#endif + /*! Evaluates the conditional described by @c code and returns @c true or @c false to indicate the result of that evaluation.