From f0d5bbecf2a0d98aea9446480068e3b81ce55c18 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 4 Jan 2020 23:22:07 -0500 Subject: [PATCH 1/2] Introduces a test of stack contents after an address error. Fixes: stacked PC, address of fault. --- .../Mac/Clock SignalTests/68000Tests.mm | 33 +++++++++++++++++-- .../Implementation/68000Implementation.hpp | 1 + .../68000/Implementation/68000Storage.cpp | 4 +-- 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/68000Tests.mm b/OSBindings/Mac/Clock SignalTests/68000Tests.mm index bd069d7c7..d2d8935e4 100644 --- a/OSBindings/Mac/Clock SignalTests/68000Tests.mm +++ b/OSBindings/Mac/Clock SignalTests/68000Tests.mm @@ -223,8 +223,37 @@ class CPU::MC68000::ProcessorStorageTests { _machine->run_for_instructions(1); const auto state = _machine->processor().get_state(); - XCTAssert(state.program_counter == 0x1008); // i.e. the interrupt happened, the instruction performed was the one at 1004, and therefore - // by the wonders of prefetch the program counter is now at 1008. + XCTAssertEqual(state.program_counter, 0x1008); // i.e. the interrupt happened, the instruction performed was the one at 1004, and therefore + // by the wonders of prefetch the program counter is now at 1008. +} + +- (void)testAddressErrorStack { + // Cause an address error. + _machine->set_program({ + 0x3c7c, 0x2001, // MOVEA.w #$2001, A6 + 0x4a9e, // TST (A6)+ + }); + _machine->run_for_instructions(2); + + // Check what was left on the stack for appropriate fields. + const auto stack_frame = _machine->ram_at(0x1f8); + + // Function code et al. +// XCTAssertEqual(stack_frame[0], 0x0000); // ?? + + // Access address. + XCTAssertEqual(stack_frame[1], 0x0000); + XCTAssertEqual(stack_frame[2], 0x2001); + + // Instruction. + XCTAssertEqual(stack_frame[3], 0x4a9e); + + // Status. + XCTAssertEqual(stack_frame[4], 0x2700); + + // PC. + XCTAssertEqual(stack_frame[5], 0x0000); + XCTAssertEqual(stack_frame[6], 0x1004); } - (void)testOpcodeCoverage { diff --git a/Processors/68000/Implementation/68000Implementation.hpp b/Processors/68000/Implementation/68000Implementation.hpp index b287c398b..7b9211f6c 100644 --- a/Processors/68000/Implementation/68000Implementation.hpp +++ b/Processors/68000/Implementation/68000Implementation.hpp @@ -116,6 +116,7 @@ template void Proces active_micro_op_ = long_exception_micro_ops_; active_step_ = &all_bus_steps_[active_micro_op_->bus_program]; populate_bus_error_steps(3, get_status(), get_bus_code(), offending_address); + program_counter_.full -= 4; } // Perform the microcycle if it is of non-zero length. If this is an operation that diff --git a/Processors/68000/Implementation/68000Storage.cpp b/Processors/68000/Implementation/68000Storage.cpp index 1bbd45d7f..00532fd84 100644 --- a/Processors/68000/Implementation/68000Storage.cpp +++ b/Processors/68000/Implementation/68000Storage.cpp @@ -3262,9 +3262,9 @@ CPU::MC68000::ProcessorStorage::ProcessorStorage() { &destination_bus_data_[0].halves.low, &program_counter_.halves.high, &decoded_instruction_, - &effective_address_[0].halves.low, + &effective_address_[1].halves.low, &destination_bus_data_[0].halves.high, - &effective_address_[0].halves.high + &effective_address_[1].halves.high }); // Also relink the RTE and RTR bus steps to collect the program counter. From 9f2f54793232830f315ecb872b9379a9d810f9a7 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 4 Jan 2020 23:58:07 -0500 Subject: [PATCH 2/2] Adds and satisfies test on the function code word. Thanks to ijor's "68000 Address and Bus Error Stack Frame" re: contents. --- OSBindings/Mac/Clock SignalTests/68000Tests.mm | 7 ++++++- .../68000/Implementation/68000Implementation.hpp | 15 ++++++++++++--- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/68000Tests.mm b/OSBindings/Mac/Clock SignalTests/68000Tests.mm index d2d8935e4..a192a05fe 100644 --- a/OSBindings/Mac/Clock SignalTests/68000Tests.mm +++ b/OSBindings/Mac/Clock SignalTests/68000Tests.mm @@ -239,7 +239,12 @@ class CPU::MC68000::ProcessorStorageTests { const auto stack_frame = _machine->ram_at(0x1f8); // Function code et al. -// XCTAssertEqual(stack_frame[0], 0x0000); // ?? + XCTAssertEqual(stack_frame[0], + (0x4a9e & 0xffe0) | // Top 11 bits: decoded instruction; + 0x10 | // Bit 4: read or write; + 0x0 | // Bit 3: 0 = in instruction, 1 = not; + 0x5 // Bits 0–2: FC0–2, i.e. bit 2 = supervisor, bit 1 = is program, bit 0 = is data. + ); // Access address. XCTAssertEqual(stack_frame[1], 0x0000); diff --git a/Processors/68000/Implementation/68000Implementation.hpp b/Processors/68000/Implementation/68000Implementation.hpp index 7b9211f6c..e3b61d156 100644 --- a/Processors/68000/Implementation/68000Implementation.hpp +++ b/Processors/68000/Implementation/68000Implementation.hpp @@ -41,7 +41,8 @@ ((active_step_->microcycle.operation & Microcycle::IsProgram) ? 0x02 : 0x01) | \ (is_supervisor_ << 2) | \ (active_program_ ? 0x08 : 0) | \ - ((active_step_->microcycle.operation & Microcycle::Read) ? 0x10 : 0) \ + ((active_step_->microcycle.operation & Microcycle::Read) ? 0x10 : 0) | \ + (decoded_instruction_.full & 0xffe0) \ ) #define u_extend16(x) uint32_t(int16_t(x)) @@ -100,8 +101,9 @@ template void Proces const auto offending_address = *active_step_->microcycle.address; active_program_ = nullptr; active_micro_op_ = long_exception_micro_ops_; - active_step_ = &all_bus_steps_[active_micro_op_->bus_program]; populate_bus_error_steps(2, get_status(), get_bus_code(), offending_address); + program_counter_.full -= 4; + active_step_ = &all_bus_steps_[active_micro_op_->bus_program]; } } @@ -114,9 +116,16 @@ template void Proces const auto offending_address = *active_step_->microcycle.address; active_program_ = nullptr; active_micro_op_ = long_exception_micro_ops_; - active_step_ = &all_bus_steps_[active_micro_op_->bus_program]; populate_bus_error_steps(3, get_status(), get_bus_code(), offending_address); program_counter_.full -= 4; + active_step_ = &all_bus_steps_[active_micro_op_->bus_program]; + + // TODO: the above is only correct prior to the final microcycle of an + // instruction. If an exception occurs in the final microcycle then + // the next instruction will already have moved into the current instruction + // slot (decoded_instruction_ in my terms). + + // TODO: it's also not correct for a bus error that occurs during another exception. } // Perform the microcycle if it is of non-zero length. If this is an operation that