From 57aa8d2f17139b65cc6bf0a0354aab42549f585e Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 29 May 2022 14:34:06 -0400 Subject: [PATCH 01/15] Correct timing of ADDQ. --- .../Implementation/68000Mk2Implementation.hpp | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp index e75ad731e..3577f79fa 100644 --- a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp +++ b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp @@ -747,18 +747,25 @@ void Processor Date: Sun, 29 May 2022 14:49:42 -0400 Subject: [PATCH 02/15] Fix timing of CMPM. --- Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp index 3577f79fa..a5a83dcb5 100644 --- a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp +++ b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp @@ -698,7 +698,9 @@ void Processor Date: Sun, 29 May 2022 14:55:24 -0400 Subject: [PATCH 03/15] Make `requires_supervisor` explicitly compile-time usable. --- InstructionSets/M68k/Instruction.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/InstructionSets/M68k/Instruction.hpp b/InstructionSets/M68k/Instruction.hpp index 314729f8d..ce211dbec 100644 --- a/InstructionSets/M68k/Instruction.hpp +++ b/InstructionSets/M68k/Instruction.hpp @@ -104,9 +104,9 @@ enum class Operation: uint8_t { Max = RESET }; -template -constexpr bool requires_supervisor(Operation op) { - switch(op) { +template +constexpr bool requires_supervisor(Operation r_op = Operation::Undefined) { + switch(t_op != Operation::Undefined ? t_op : r_op) { case Operation::MOVEfromSR: if constexpr (model == Model::M68000) { return false; From d6f72d9862296d125f0e3353302dc4c76620737a Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 29 May 2022 14:56:44 -0400 Subject: [PATCH 04/15] Avoid runtime checking of instruction supervisor requirements. --- .../Implementation/68000Mk2Implementation.hpp | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp index a5a83dcb5..f99d9f7b8 100644 --- a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp +++ b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp @@ -602,18 +602,21 @@ void Processor()) { \ + if(!status_.is_supervisor) { \ + RaiseException(InstructionSet::M68k::Exception::PrivilegeViolation); \ + } \ + } + +#define CASE(x) \ + case InstructionSet::M68k::Operation::x: \ + CheckSupervisor(x); \ operand_flags_ = InstructionSet::M68k::operand_flags(); #define StdCASE(x, y) \ @@ -642,7 +645,7 @@ void Processor Date: Sun, 29 May 2022 15:26:56 -0400 Subject: [PATCH 05/15] Fix CHK tests: timing and expected flags. --- .../68000ControlFlowTests.mm | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/68000ControlFlowTests.mm b/OSBindings/Mac/Clock SignalTests/68000ControlFlowTests.mm index 88ccae157..2f8db01fc 100644 --- a/OSBindings/Mac/Clock SignalTests/68000ControlFlowTests.mm +++ b/OSBindings/Mac/Clock SignalTests/68000ControlFlowTests.mm @@ -157,41 +157,48 @@ XCTAssertEqual(state.registers.data[2], d2); } +// Re: CHK, below; the final state of N is undocumented if Dn >= 0 and Dn < . +// Z, V and C are also undocumented by Motorola, but are documneted by 68knotes.txt. + - (void)testCHK_1111v1111 { - [self performCHKd1:0x1111 d2:0x1111]; + [self performCHKd1:0x1111 d2:0x1111]; // Neither exception-generating state applies. const auto state = _machine->get_processor_state(); XCTAssertEqual(state.registers.program_counter, 0x1002 + 4); - XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend); + XCTAssertEqual( + state.registers.status & (ConditionCode::Extend | ConditionCode::Zero | ConditionCode::Overflow | ConditionCode::Carry), + ConditionCode::Extend); XCTAssertEqual(10, _machine->get_cycle_count()); } - (void)testCHK_1111v0000 { - [self performCHKd1:0x1111 d2:0x0000]; + [self performCHKd1:0x1111 d2:0x0000]; // Neither exception-generating state applies. const auto state = _machine->get_processor_state(); XCTAssertEqual(state.registers.program_counter, 0x1002 + 4); - XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Zero); + XCTAssertEqual( + state.registers.status & (ConditionCode::Extend | ConditionCode::Zero | ConditionCode::Overflow | ConditionCode::Carry), + ConditionCode::Extend | ConditionCode::Zero); XCTAssertEqual(10, _machine->get_cycle_count()); } - (void)testCHK_8000v8001 { - [self performCHKd1:0x8000 d2:0x8001]; + [self performCHKd1:0x8000 d2:0x8001]; // Both less than 0 and D2 greater than D1. const auto state = _machine->get_processor_state(); XCTAssertNotEqual(state.registers.program_counter, 0x1002 + 4); XCTAssertEqual(state.registers.stack_pointer(), 0xfffffffa); - XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend); - XCTAssertEqual(42, _machine->get_cycle_count()); + XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Negative); + XCTAssertEqual(38, _machine->get_cycle_count()); } - (void)testCHK_8000v8000 { - [self performCHKd1:0x8000 d2:0x8000]; + [self performCHKd1:0x8000 d2:0x8000]; // Less than 0. const auto state = _machine->get_processor_state(); XCTAssertNotEqual(state.registers.program_counter, 0x1002 + 4); XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Negative); - XCTAssertEqual(44, _machine->get_cycle_count()); + XCTAssertEqual(40, _machine->get_cycle_count()); } // MARK: DBcc From 3ef53315a2b500678b9349d8cd682b1f139307fe Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 29 May 2022 15:28:16 -0400 Subject: [PATCH 06/15] Don't try to append operands to 'None'. --- InstructionSets/M68k/Instruction.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InstructionSets/M68k/Instruction.cpp b/InstructionSets/M68k/Instruction.cpp index b4184c868..c52ebe0ee 100644 --- a/InstructionSets/M68k/Instruction.cpp +++ b/InstructionSets/M68k/Instruction.cpp @@ -61,7 +61,7 @@ std::string Preinstruction::to_string(int opcode) const { const char *instruction; switch(operation) { - case Operation::Undefined: instruction = "None"; break; + case Operation::Undefined: return "None"; case Operation::NOP: instruction = "NOP"; break; case Operation::ABCD: instruction = "ABCD"; break; case Operation::SBCD: instruction = "SBCD"; break; From 9eea471e72a88b8bfe696435971d701f3a0a8351 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 29 May 2022 20:39:22 -0400 Subject: [PATCH 07/15] Resolve infinite recursion. --- OSBindings/Mac/Clock SignalTests/68000ArithmeticTests.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OSBindings/Mac/Clock SignalTests/68000ArithmeticTests.mm b/OSBindings/Mac/Clock SignalTests/68000ArithmeticTests.mm index ec2e70d0f..b0ae2b872 100644 --- a/OSBindings/Mac/Clock SignalTests/68000ArithmeticTests.mm +++ b/OSBindings/Mac/Clock SignalTests/68000ArithmeticTests.mm @@ -726,7 +726,7 @@ } - (void)performDIVS:(uint16_t)divisor d1:(uint32_t)d1 { - [self performDIVS:divisor d1:d1]; + [self performDIVS:divisor d1:d1 sp:0]; } - (void)performDIVSOverflowTestDivisor:(uint16_t)divisor { From 7788a109b030a7eab79389a2d7c2b1fad347938a Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 29 May 2022 20:51:50 -0400 Subject: [PATCH 08/15] Tweak more overtly to avoid divide by zero. --- InstructionSets/M68k/Implementation/PerformImplementation.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/InstructionSets/M68k/Implementation/PerformImplementation.hpp b/InstructionSets/M68k/Implementation/PerformImplementation.hpp index 03b353376..a551f11ec 100644 --- a/InstructionSets/M68k/Implementation/PerformImplementation.hpp +++ b/InstructionSets/M68k/Implementation/PerformImplementation.hpp @@ -522,7 +522,8 @@ template < #define DIV(Type16, Type32, flow_function) { \ status.carry_flag = 0; \ \ - if(!src.w) { \ + const auto divisor = Type32(Type16(src.w)); \ + if(!divisor) { \ status.negative_flag = status.overflow_flag = 0; \ status.zero_result = 1; \ flow_controller.raise_exception(Exception::IntegerDivideByZero); \ @@ -530,7 +531,6 @@ template < } \ \ const auto dividend = Type32(dest.l); \ - const auto divisor = Type32(Type16(src.w)); \ const auto quotient = dividend / divisor; \ \ if(quotient != Type32(Type16(quotient))) { \ From 8ffaf1a8e4a4b3878b120a3a59e1ebe8ba9b55e9 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 29 May 2022 21:18:19 -0400 Subject: [PATCH 09/15] Ensure did_divu/s are performed even upon divide by zero. --- .../M68k/Implementation/PerformImplementation.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/InstructionSets/M68k/Implementation/PerformImplementation.hpp b/InstructionSets/M68k/Implementation/PerformImplementation.hpp index a551f11ec..ef6f3d42d 100644 --- a/InstructionSets/M68k/Implementation/PerformImplementation.hpp +++ b/InstructionSets/M68k/Implementation/PerformImplementation.hpp @@ -522,17 +522,18 @@ template < #define DIV(Type16, Type32, flow_function) { \ status.carry_flag = 0; \ \ + const auto dividend = Type32(dest.l); \ const auto divisor = Type32(Type16(src.w)); \ + \ if(!divisor) { \ status.negative_flag = status.overflow_flag = 0; \ status.zero_result = 1; \ flow_controller.raise_exception(Exception::IntegerDivideByZero); \ + flow_controller.template flow_function(dividend, divisor); \ return; \ } \ \ - const auto dividend = Type32(dest.l); \ const auto quotient = dividend / divisor; \ - \ if(quotient != Type32(Type16(quotient))) { \ status.overflow_flag = 1; \ flow_controller.template flow_function(dividend, divisor); \ From 8e0fa3bb5fe70d65e8b7d9cb57a532a5171f0086 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 29 May 2022 21:22:45 -0400 Subject: [PATCH 10/15] DIV # with a divide by zero should be 44 cycles. --- OSBindings/Mac/Clock SignalTests/68000ArithmeticTests.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OSBindings/Mac/Clock SignalTests/68000ArithmeticTests.mm b/OSBindings/Mac/Clock SignalTests/68000ArithmeticTests.mm index b0ae2b872..556040c54 100644 --- a/OSBindings/Mac/Clock SignalTests/68000ArithmeticTests.mm +++ b/OSBindings/Mac/Clock SignalTests/68000ArithmeticTests.mm @@ -865,7 +865,7 @@ XCTAssertEqual(state.registers.data[1], 0x1fffffff); XCTAssertEqual(state.registers.supervisor_stack_pointer, initial_sp - 6); XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend); - XCTAssertEqual(42, self.machine->get_cycle_count()); + XCTAssertEqual(44, 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 e1abf431cbc1510359bc84987b514b6eebdf1572 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 30 May 2022 16:23:51 -0400 Subject: [PATCH 11/15] Don't test undefined flags. --- OSBindings/Mac/Clock SignalTests/68000ArithmeticTests.mm | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/OSBindings/Mac/Clock SignalTests/68000ArithmeticTests.mm b/OSBindings/Mac/Clock SignalTests/68000ArithmeticTests.mm index 556040c54..c6ee45d10 100644 --- a/OSBindings/Mac/Clock SignalTests/68000ArithmeticTests.mm +++ b/OSBindings/Mac/Clock SignalTests/68000ArithmeticTests.mm @@ -734,7 +734,12 @@ 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); + + // N and Z are officially undefined upon DIVS overflow, and I've found no + // other relevant information. + XCTAssertEqual( + state.registers.status & (ConditionCode::Extend | ConditionCode::Overflow | ConditionCode::Carry), + ConditionCode::Extend | ConditionCode::Overflow); XCTAssertEqual(20, self.machine->get_cycle_count()); } From 73815ba1dd14fbe569a3869d0919c6a93e5ff85d Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 1 Jun 2022 08:20:06 -0400 Subject: [PATCH 12/15] No need for this hoop jumping here. --- InstructionSets/M68k/Instruction.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/InstructionSets/M68k/Instruction.hpp b/InstructionSets/M68k/Instruction.hpp index ce211dbec..314729f8d 100644 --- a/InstructionSets/M68k/Instruction.hpp +++ b/InstructionSets/M68k/Instruction.hpp @@ -104,9 +104,9 @@ enum class Operation: uint8_t { Max = RESET }; -template -constexpr bool requires_supervisor(Operation r_op = Operation::Undefined) { - switch(t_op != Operation::Undefined ? t_op : r_op) { +template +constexpr bool requires_supervisor(Operation op) { + switch(op) { case Operation::MOVEfromSR: if constexpr (model == Model::M68000) { return false; From 75e85b80aa515b599cc803024e4510f4e2f4708f Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 1 Jun 2022 08:20:33 -0400 Subject: [PATCH 13/15] Factor out the common stuff of exception state. --- InstructionSets/M68k/Status.hpp | 17 +++++++++++ .../Implementation/68000Mk2Implementation.hpp | 29 ++++++------------- 2 files changed, 26 insertions(+), 20 deletions(-) diff --git a/InstructionSets/M68k/Status.hpp b/InstructionSets/M68k/Status.hpp index d43a6dbd4..7fe42b5f1 100644 --- a/InstructionSets/M68k/Status.hpp +++ b/InstructionSets/M68k/Status.hpp @@ -95,6 +95,23 @@ struct Status { return is_supervisor; } + /// Adjusts the status for exception processing — sets supervisor mode, disables trace, + /// and if @c new_interrupt_level is greater than or equal to 0 sets that as the new + /// interrupt level. + /// + /// @returns The status prior to those changes. + uint16_t begin_exception(int new_interrupt_level = -1) { + const uint16_t initial_status = status(); + + if(new_interrupt_level >= 0) { + interrupt_level = new_interrupt_level; + } + is_supervisor = true; + trace_flag = 0; + + return initial_status; + } + /// Evaluates @c condition. bool evaluate_condition(Condition condition) { switch(condition) { diff --git a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp index f99d9f7b8..855c8c4bf 100644 --- a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp +++ b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp @@ -355,9 +355,7 @@ void Processor()) { \ - if(!status_.is_supervisor) { \ - RaiseException(InstructionSet::M68k::Exception::PrivilegeViolation); \ - } \ +#define CheckSupervisor(x) \ + if constexpr (InstructionSet::M68k::requires_supervisor(InstructionSet::M68k::Operation::x)) { \ + if(!status_.is_supervisor) { \ + RaiseException(InstructionSet::M68k::Exception::PrivilegeViolation); \ + } \ } #define CASE(x) \ From d1298c8863531baee6981511a0c9e099efbcc411 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 1 Jun 2022 08:50:43 -0400 Subject: [PATCH 14/15] Correct MOVE timing without breaking PEA, LEA, etc. --- .../Implementation/68000Mk2Implementation.hpp | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp index 855c8c4bf..2792d38ed 100644 --- a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp +++ b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp @@ -91,12 +91,16 @@ enum ExecutionState: int { CalcAddressRegisterIndirectWithPostincrement, // - CalcAddressRegisterIndirectWithPredecrement, // - CalcAddressRegisterIndirectWithDisplacement, // np - CalcAddressRegisterIndirectWithIndex8bitDisplacement, // n np n + CalcAddressRegisterIndirectWithIndex8bitDisplacement, // np n CalcProgramCounterIndirectWithDisplacement, // np - CalcProgramCounterIndirectWithIndex8bitDisplacement, // n np n + CalcProgramCounterIndirectWithIndex8bitDisplacement, // np n CalcAbsoluteShort, // np CalcAbsoluteLong, // np np + CalcEffectiveAddressIdleFor8bitDisplacement, // As per CalcEffectiveAddress unless one of the + // 8-bit displacement modes is in use, in which case + // an extra idle bus state is prefixed. + // Various forms of perform; each of these will // perform the current instruction, then do the // indicated bus cycle. @@ -923,11 +927,11 @@ void Processor Date: Wed, 1 Jun 2022 09:22:47 -0400 Subject: [PATCH 15/15] Fix MOVE CCR permissions. --- .../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 2792d38ed..5e67d9417 100644 --- a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp +++ b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp @@ -631,11 +631,13 @@ void Processor() == \ - InstructionSet::M68k::operand_flags() && \ - InstructionSet::M68k::operand_size() == \ - InstructionSet::M68k::operand_size() \ - ); \ + InstructionSet::M68k::operand_flags() == \ + InstructionSet::M68k::operand_flags() && \ + InstructionSet::M68k::operand_size() == \ + InstructionSet::M68k::operand_size() && \ + InstructionSet::M68k::requires_supervisor(InstructionSet::M68k::Operation::x) == \ + InstructionSet::M68k::requires_supervisor(InstructionSet::M68k::Operation::y) \ + ); \ [[fallthrough]]; #define SpecialCASE(x) case InstructionSet::M68k::Operation::x: CheckSupervisor(x); MoveToStateSpecific(x) @@ -947,7 +949,7 @@ void Processor