From cfafbfd141221e20f2853c9aa0b930639ad05178 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 4 Jun 2022 15:20:38 -0400 Subject: [PATCH 01/62] Fix interrupt acknowledge cycle: signals and data size. --- .../Implementation/68000Mk2Implementation.hpp | 12 ++++++------ .../68000Mk2/Implementation/68000Mk2Storage.hpp | 6 ++++++ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp index 2d5dc60f7..faed7b03f 100644 --- a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp +++ b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp @@ -547,13 +547,14 @@ void Processor Date: Sun, 5 Jun 2022 09:08:36 -0400 Subject: [PATCH 02/62] Add missing `flush`. --- Machines/Apple/Macintosh/Macintosh.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Machines/Apple/Macintosh/Macintosh.cpp b/Machines/Apple/Macintosh/Macintosh.cpp index 47267a550..add620202 100644 --- a/Machines/Apple/Macintosh/Macintosh.cpp +++ b/Machines/Apple/Macintosh/Macintosh.cpp @@ -190,6 +190,7 @@ template class ConcreteMachin void run_for(const Cycles cycles) final { mc68000_.run_for(cycles); + flush(); } using Microcycle = CPU::MC68000Mk2::Microcycle; From a4baa33e2f70efdf7edd82609bab60f8421a84ac Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 6 Jun 2022 16:08:50 -0400 Subject: [PATCH 03/62] Ensure RTE triggers a stack pointer change if needed. --- Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp index faed7b03f..daab0ad62 100644 --- a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp +++ b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp @@ -2397,6 +2397,7 @@ void Processor Date: Mon, 6 Jun 2022 21:19:57 -0400 Subject: [PATCH 04/62] Start sketching out an old vs new 68000 test. --- .../Clock Signal.xcodeproj/project.pbxproj | 4 ++ .../Mac/Clock SignalTests/68000OldVsNew.mm | 45 +++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 47c6a8f14..9fde13679 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -641,6 +641,7 @@ 4B9F11CC22729B3600701480 /* OPCLOGR2.BIN in Resources */ = {isa = PBXBuildFile; fileRef = 4B9F11CB22729B3500701480 /* OPCLOGR2.BIN */; }; 4BA0F68E1EEA0E8400E9489E /* ZX8081.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BA0F68C1EEA0E8400E9489E /* ZX8081.cpp */; }; 4BA61EB01D91515900B3C876 /* NSData+StdVector.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4BA61EAF1D91515900B3C876 /* NSData+StdVector.mm */; }; + 4BA6B6AE284EDAC100A3B7A8 /* 68000OldVsNew.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4BA6B6AD284EDAC000A3B7A8 /* 68000OldVsNew.mm */; }; 4BA91E1D216D85BA00F79557 /* MasterSystemVDPTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4BA91E1C216D85BA00F79557 /* MasterSystemVDPTests.mm */; }; 4BAD13441FF709C700FD114A /* MSX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0E61051FF34737002A9DBD /* MSX.cpp */; }; 4BAE49582032881E004BE78E /* CSZX8081.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B14978E1EE4B4D200CE2596 /* CSZX8081.mm */; }; @@ -1683,6 +1684,7 @@ 4BA3AE44283317CB00328FED /* RegisterSet.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = RegisterSet.hpp; sourceTree = ""; }; 4BA61EAE1D91515900B3C876 /* NSData+StdVector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+StdVector.h"; sourceTree = ""; }; 4BA61EAF1D91515900B3C876 /* NSData+StdVector.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSData+StdVector.mm"; sourceTree = ""; }; + 4BA6B6AD284EDAC000A3B7A8 /* 68000OldVsNew.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = 68000OldVsNew.mm; sourceTree = ""; }; 4BA91E1C216D85BA00F79557 /* MasterSystemVDPTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MasterSystemVDPTests.mm; sourceTree = ""; }; 4BA9C3CF1D8164A9002DDB61 /* MediaTarget.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = MediaTarget.hpp; sourceTree = ""; }; 4BAA167B21582B1D008A3276 /* Target.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Target.hpp; sourceTree = ""; }; @@ -4235,6 +4237,7 @@ 4B75F978280D7C5100121055 /* 68000DecoderTests.mm */, 4B7C79FF282C3BCA002D6C0B /* 68000flamewingTests.mm */, 4BC5C3DF22C994CC00795658 /* 68000MoveTests.mm */, + 4BA6B6AD284EDAC000A3B7A8 /* 68000OldVsNew.mm */, 4B9D0C4E22C7E0CF00DE1AD3 /* 68000RollShiftTests.mm */, 4BD388872239E198002D14B5 /* 68000Tests.mm */, 4BF7019F26FFD32300996424 /* AmigaBlitterTests.mm */, @@ -5975,6 +5978,7 @@ 4B3F76B925A1635300178AEC /* PowerPCDecoderTests.mm in Sources */, 4B778F0A23A5EC150000D260 /* TapePRG.cpp in Sources */, 4B778F0823A5EC150000D260 /* CSW.cpp in Sources */, + 4BA6B6AE284EDAC100A3B7A8 /* 68000OldVsNew.mm in Sources */, 4B778F5323A5F23F0000D260 /* SerialBus.cpp in Sources */, 4B1E85811D176468001EF87D /* 6532Tests.swift in Sources */, 4B7752BA28217F160073E2C5 /* Bitplanes.cpp in Sources */, diff --git a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm new file mode 100644 index 000000000..95cb01e76 --- /dev/null +++ b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm @@ -0,0 +1,45 @@ +// +// 68000ArithmeticTests.m +// Clock SignalTests +// +// Created by Thomas Harte on 28/06/2019. +// +// Largely ported from the tests of the Portable 68k Emulator. +// + +#import + +#include "TestRunner68000.hpp" +#include "68000.hpp" +#include "68000Mk2.hpp" + +namespace { + +struct BusHandler { + +}; + +using OldProcessor = CPU::MC68000::Processor; +using NewProcessor = CPU::MC68000Mk2::Processor; + +template struct Tester { + Tester() : processor_(bus_handler_) {} + + BusHandler bus_handler_; + M68000 processor_; +}; + +} + +@interface M68000OldVsNewTests : XCTestCase +@end + +@implementation M68000OldVsNewTests { +} + +- (void)testOldVsNew { + Tester oldTester; + Tester newTester; +} + +@end From c4ae5d4c8dbc13555749d68f01f44524d171b4e3 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 6 Jun 2022 21:47:10 -0400 Subject: [PATCH 05/62] Establishes at least that both 68000s can run. --- .../Mac/Clock SignalTests/68000OldVsNew.mm | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm index 95cb01e76..bc7fcec02 100644 --- a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm +++ b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm @@ -16,14 +16,23 @@ namespace { struct BusHandler { + template HalfCycles perform_bus_operation(const Microcycle &cycle, bool is_supervisor) { + return HalfCycles(0); + } + void flush() {} }; using OldProcessor = CPU::MC68000::Processor; using NewProcessor = CPU::MC68000Mk2::Processor; template struct Tester { - Tester() : processor_(bus_handler_) {} + Tester() : processor_(bus_handler_) { + } + + void advance(int cycles) { + processor_.run_for(HalfCycles(cycles << 1)); + } BusHandler bus_handler_; M68000 processor_; @@ -40,6 +49,11 @@ template struct Tester { - (void)testOldVsNew { Tester oldTester; Tester newTester; + + for(int c = 0; c < 2000; c++) { + oldTester.advance(1); + newTester.advance(1); + } } @end From 9009645cea576c70bf803235cf3a9a9660b31959 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 7 Jun 2022 16:55:39 -0400 Subject: [PATCH 06/62] Add 'reset' functions. --- Processors/68000/68000.hpp | 2 ++ Processors/68000/Implementation/68000Implementation.hpp | 7 +++++++ Processors/68000Mk2/68000Mk2.hpp | 2 ++ .../68000Mk2/Implementation/68000Mk2Implementation.hpp | 6 ++++++ 4 files changed, 17 insertions(+) diff --git a/Processors/68000/68000.hpp b/Processors/68000/68000.hpp index 068cee4e3..94f11c95c 100644 --- a/Processors/68000/68000.hpp +++ b/Processors/68000/68000.hpp @@ -462,6 +462,8 @@ template cla return e_clock_phase_; } + void reset(); + private: T &bus_handler_; }; diff --git a/Processors/68000/Implementation/68000Implementation.hpp b/Processors/68000/Implementation/68000Implementation.hpp index 812d2a0ab..f547d16a9 100644 --- a/Processors/68000/Implementation/68000Implementation.hpp +++ b/Processors/68000/Implementation/68000Implementation.hpp @@ -2237,6 +2237,13 @@ void ProcessorStorage::set_status(uint16_t status) { apply_status(status); } +template void Processor::reset() { + execution_state_ = ExecutionState::Executing; + active_step_ = reset_bus_steps_; + is_supervisor_ = 1; + interrupt_level_ = 7; +} + #undef status #undef apply_status #undef apply_ccr diff --git a/Processors/68000Mk2/68000Mk2.hpp b/Processors/68000Mk2/68000Mk2.hpp index f58777494..5defa8eac 100644 --- a/Processors/68000Mk2/68000Mk2.hpp +++ b/Processors/68000Mk2/68000Mk2.hpp @@ -441,6 +441,8 @@ class Processor: private ProcessorBase { return e_clock_phase_; } + void reset(); + private: BusHandler &bus_handler_; }; diff --git a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp index daab0ad62..55f0569b8 100644 --- a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp +++ b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp @@ -2782,6 +2782,12 @@ void Processor +void Processor::reset() { + state_ = Reset; + status_.begin_exception(7); +} + } } From 788b026cf54b726553479c420a02b68336cb3105 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 7 Jun 2022 16:56:05 -0400 Subject: [PATCH 07/62] Log and attempt to compare some activity. Sort of. --- .../Mac/Clock SignalTests/68000OldVsNew.mm | 144 ++++++++++++++++-- 1 file changed, 134 insertions(+), 10 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm index bc7fcec02..a533743ba 100644 --- a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm +++ b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm @@ -9,33 +9,122 @@ #import -#include "TestRunner68000.hpp" #include "68000.hpp" #include "68000Mk2.hpp" +#include + namespace { +struct Transaction { + uint8_t function_code = 0; + uint32_t address = 0; + uint16_t value = 0; + bool address_strobe = false; + bool data_strobe = false; + + bool operator !=(const Transaction &rhs) { + return false; + } +}; + struct BusHandler { template HalfCycles perform_bus_operation(const Microcycle &cycle, bool is_supervisor) { + Transaction transaction; + + // Fill all of the transaction record except the data field; will do that after + // any potential read. + if(cycle.operation & Microcycle::InterruptAcknowledge) { + transaction.function_code = 0b111; + } else { + transaction.function_code = is_supervisor ? 0x4 : 0x0; + transaction.function_code |= (cycle.operation & Microcycle::IsData) ? 0x1 : 0x2; + } + transaction.address_strobe = cycle.operation & (Microcycle::NewAddress | Microcycle::SameAddress); + transaction.data_strobe = cycle.operation & (Microcycle::SelectByte | Microcycle::SelectWord); + if(cycle.address) transaction.address = *cycle.address & 0xffff'ff; + + // TODO: generate a random value if this is a read from an address not yet written to; + // use a shared store in order to ensure that both devices get the same random values. + + // Do the operation... + const uint32_t address = cycle.address ? (*cycle.address & 0xffff'ff) : 0; + switch(cycle.operation & (Microcycle::SelectWord | Microcycle::SelectByte | Microcycle::Read)) { + default: break; + + case Microcycle::SelectWord | Microcycle::Read: + cycle.set_value16((ram[address] << 8) | ram[address + 1]); + break; + case Microcycle::SelectByte | Microcycle::Read: + if(address & 1) { + cycle.set_value8_low(ram[address]); + } else { + cycle.set_value8_high(ram[address]); + } + break; + case Microcycle::SelectWord: + ram[address] = cycle.value8_high(); + ram[address+1] = cycle.value8_low(); + break; + case Microcycle::SelectByte: + ram[address] = (address & 1) ? cycle.value8_low() : cycle.value8_high(); + break; + } + + + // Add the data value if relevant. + if(transaction.data_strobe) { + transaction.value = cycle.value16(); + } + + // Push back only if interesting. + if(transaction.address_strobe || transaction.data_strobe || transaction.function_code == 7) { + transactions.push_back(transaction); + } + return HalfCycles(0); } void flush() {} + + std::vector transactions; + std::array ram; + + void set_default_vectors() { + // Establish that all exception vectors point to 1024-byte blocks of memory. + for(int c = 0; c < 256; c++) { + const uint32_t target = (c + 1) << 10; + ram[(c << 2) + 0] = uint8_t(target >> 24); + ram[(c << 2) + 1] = uint8_t(target >> 16); + ram[(c << 2) + 2] = uint8_t(target >> 8); + ram[(c << 2) + 3] = uint8_t(target >> 0); + } + } }; using OldProcessor = CPU::MC68000::Processor; using NewProcessor = CPU::MC68000Mk2::Processor; template struct Tester { - Tester() : processor_(bus_handler_) { + Tester() : processor(bus_handler) { } void advance(int cycles) { - processor_.run_for(HalfCycles(cycles << 1)); + processor.run_for(HalfCycles(cycles << 1)); } - BusHandler bus_handler_; - M68000 processor_; + void reset_with_opcode(uint16_t opcode) { + bus_handler.transactions.clear(); + bus_handler.set_default_vectors(); + + bus_handler.ram[(2 << 10) + 0] = uint8_t(opcode >> 8); + bus_handler.ram[(2 << 10) + 1] = uint8_t(opcode >> 0); + + processor.reset(); + } + + BusHandler bus_handler; + M68000 processor; }; } @@ -47,12 +136,47 @@ template struct Tester { } - (void)testOldVsNew { - Tester oldTester; - Tester newTester; + auto oldTester = std::make_unique>(); + auto newTester = std::make_unique>(); + InstructionSet::M68k::Predecoder decoder; - for(int c = 0; c < 2000; c++) { - oldTester.advance(1); - newTester.advance(1); + for(int c = 0; c < 65536; c++) { + // Test only defined opcodes. + const auto instruction = decoder.decode(uint16_t(c)); + if(instruction.operation == InstructionSet::M68k::Operation::Undefined) { + continue; + } + + // Test each 1000 times. + for(int test = 0; test < 1000; test++) { + oldTester->reset_with_opcode(c); + newTester->reset_with_opcode(c); + + // For arbitrary resons, only run for 200 cycles. + newTester->advance(200); + oldTester->advance(200); + + // Compare bus activity. + const auto &oldTransactions = oldTester->bus_handler.transactions; + const auto &newTransactions = newTester->bus_handler.transactions; + if( + oldTransactions.size() != newTransactions.size() + ) { + printf("Size mismatch: %zu vs %zu\n", newTransactions.size(), oldTransactions.size()); + continue; + } + + auto newIt = newTransactions.begin(); + auto oldIt = oldTransactions.begin(); + while(newIt != newTransactions.end()) { +// if(*newIt != *oldIt) { +// printf("Peekaboo!"); +// } + + ++newIt; + ++oldIt; + } + } } } From 400b73b5a22e8eb643ca14da1e15cd3a479d7379 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 8 Jun 2022 09:49:27 -0400 Subject: [PATCH 08/62] Allow capture to be limited; retain timestamps. --- .../Mac/Clock SignalTests/68000OldVsNew.mm | 51 +++++++++++++------ 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm index a533743ba..b2f4a4312 100644 --- a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm +++ b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm @@ -17,13 +17,14 @@ namespace { struct Transaction { + HalfCycles timestamp; uint8_t function_code = 0; uint32_t address = 0; uint16_t value = 0; bool address_strobe = false; bool data_strobe = false; - bool operator !=(const Transaction &rhs) { + bool operator !=(const Transaction &rhs) const { return false; } }; @@ -43,6 +44,9 @@ struct BusHandler { transaction.address_strobe = cycle.operation & (Microcycle::NewAddress | Microcycle::SameAddress); transaction.data_strobe = cycle.operation & (Microcycle::SelectByte | Microcycle::SelectWord); if(cycle.address) transaction.address = *cycle.address & 0xffff'ff; + transaction.timestamp = time; + + time += cycle.length; // TODO: generate a random value if this is a read from an address not yet written to; // use a shared store in order to ensure that both devices get the same random values. @@ -79,7 +83,13 @@ struct BusHandler { // Push back only if interesting. if(transaction.address_strobe || transaction.data_strobe || transaction.function_code == 7) { - transactions.push_back(transaction); + if(transaction_delay) { + --transaction_delay; + } else { + if(transaction.timestamp < time_cutoff) { + transactions.push_back(transaction); + } + } } return HalfCycles(0); @@ -87,6 +97,10 @@ struct BusHandler { void flush() {} + int transaction_delay; + HalfCycles time_cutoff; + + HalfCycles time; std::vector transactions; std::array ram; @@ -109,7 +123,8 @@ template struct Tester { Tester() : processor(bus_handler) { } - void advance(int cycles) { + void advance(int cycles, HalfCycles time_cutoff) { + bus_handler.time_cutoff = time_cutoff; processor.run_for(HalfCycles(cycles << 1)); } @@ -120,6 +135,10 @@ template struct Tester { bus_handler.ram[(2 << 10) + 0] = uint8_t(opcode >> 8); bus_handler.ram[(2 << 10) + 1] = uint8_t(opcode >> 0); + bus_handler.transaction_delay = 8; // i.e. ignore the first eight transactions, + // which will just be the reset procedure. + bus_handler.time = HalfCycles(0); + processor.reset(); } @@ -152,26 +171,26 @@ template struct Tester { oldTester->reset_with_opcode(c); newTester->reset_with_opcode(c); - // For arbitrary resons, only run for 200 cycles. - newTester->advance(200); - oldTester->advance(200); + // For arbitrary resons, only run for 200 bus cycles, capturing up to 200 cycles of activity. + newTester->advance(200, HalfCycles(400)); + oldTester->advance(200, HalfCycles(400)); // Compare bus activity. const auto &oldTransactions = oldTester->bus_handler.transactions; const auto &newTransactions = newTester->bus_handler.transactions; - if( - oldTransactions.size() != newTransactions.size() - ) { - printf("Size mismatch: %zu vs %zu\n", newTransactions.size(), oldTransactions.size()); - continue; - } +// if( +// oldTransactions.size() != newTransactions.size() +// ) { +// printf("Size mismatch: %zu vs %zu\n", newTransactions.size(), oldTransactions.size()); +// continue; +// } auto newIt = newTransactions.begin(); auto oldIt = oldTransactions.begin(); - while(newIt != newTransactions.end()) { -// if(*newIt != *oldIt) { -// printf("Peekaboo!"); -// } + while(newIt != newTransactions.end() && oldIt != oldTransactions.end()) { + if(*newIt != *oldIt) { + printf("Peekaboo!"); + } ++newIt; ++oldIt; From c7fa93a5bc3d147d648d7d25210bebf99a800edc Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 8 Jun 2022 10:51:05 -0400 Subject: [PATCH 09/62] Attempt human-legible explanation of differences encountered. --- .../Mac/Clock SignalTests/68000OldVsNew.mm | 37 +++++++++++++++---- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm index b2f4a4312..3a379cd28 100644 --- a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm +++ b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm @@ -25,8 +25,26 @@ struct Transaction { bool data_strobe = false; bool operator !=(const Transaction &rhs) const { + if(timestamp != rhs.timestamp) return true; + if(function_code != rhs.function_code) return true; + if(address != rhs.address) return true; + if(value != rhs.value) return true; + if(address_strobe != rhs.address_strobe) return true; + if(data_strobe != rhs.data_strobe) return true; return false; } + + void print() const { + printf("%d: %d%d%d %c %c @ %06x with %04x\n", + timestamp.as(), + (function_code >> 2) & 1, + (function_code >> 1) & 1, + (function_code >> 0) & 1, + address_strobe ? 'a' : '-', + data_strobe ? 'd' : '-', + address, + value); + } }; struct BusHandler { @@ -178,18 +196,23 @@ template struct Tester { // Compare bus activity. const auto &oldTransactions = oldTester->bus_handler.transactions; const auto &newTransactions = newTester->bus_handler.transactions; -// if( -// oldTransactions.size() != newTransactions.size() -// ) { -// printf("Size mismatch: %zu vs %zu\n", newTransactions.size(), oldTransactions.size()); -// continue; -// } auto newIt = newTransactions.begin(); auto oldIt = oldTransactions.begin(); while(newIt != newTransactions.end() && oldIt != oldTransactions.end()) { if(*newIt != *oldIt) { - printf("Peekaboo!"); + printf("Mismatch in %s, test %d:", instruction.to_string().c_str(), test); + + auto repeatIt = newTransactions.begin(); + while(repeatIt != newIt) { + repeatIt->print(); + ++repeatIt; + } + printf("---\n"); + printf("< "); oldIt->print(); + printf("> "); newIt->print(); + + break; } ++newIt; From ab52c5cef2541d790a3522e37a0c07b14b5fd39c Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 8 Jun 2022 10:56:54 -0400 Subject: [PATCH 10/62] Pass first all-zeroes test, establishing that processors aren't being fully reset. --- OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm index 3a379cd28..d554d4932 100644 --- a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm +++ b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm @@ -103,6 +103,11 @@ struct BusHandler { if(transaction.address_strobe || transaction.data_strobe || transaction.function_code == 7) { if(transaction_delay) { --transaction_delay; + + // Start counting time only from the first recorded transaction. + if(!transaction_delay) { + time = HalfCycles(0); + } } else { if(transaction.timestamp < time_cutoff) { transactions.push_back(transaction); @@ -153,7 +158,7 @@ template struct Tester { bus_handler.ram[(2 << 10) + 0] = uint8_t(opcode >> 8); bus_handler.ram[(2 << 10) + 1] = uint8_t(opcode >> 0); - bus_handler.transaction_delay = 8; // i.e. ignore the first eight transactions, + bus_handler.transaction_delay = 12; // i.e. ignore the first eight transactions, // which will just be the reset procedure. bus_handler.time = HalfCycles(0); @@ -201,7 +206,7 @@ template struct Tester { auto oldIt = oldTransactions.begin(); while(newIt != newTransactions.end() && oldIt != oldTransactions.end()) { if(*newIt != *oldIt) { - printf("Mismatch in %s, test %d:", instruction.to_string().c_str(), test); + printf("Mismatch in %s, test %d:\n", instruction.to_string().c_str(), test); auto repeatIt = newTransactions.begin(); while(repeatIt != newIt) { From 50130b70049237e19d8bd262c82788f32b7bf306 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 8 Jun 2022 11:42:42 -0400 Subject: [PATCH 11/62] Minor layout tweak. --- OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm index d554d4932..16a494c9c 100644 --- a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm +++ b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm @@ -191,10 +191,10 @@ template struct Tester { // Test each 1000 times. for(int test = 0; test < 1000; test++) { - oldTester->reset_with_opcode(c); newTester->reset_with_opcode(c); + oldTester->reset_with_opcode(c); - // For arbitrary resons, only run for 200 bus cycles, capturing up to 200 cycles of activity. + // For arbitrary resons, only run for 200 bus cycles, capturing up to 200 clock cycles of activity. newTester->advance(200, HalfCycles(400)); oldTester->advance(200, HalfCycles(400)); From 8cbf929671d719166253baa3a00b08f884f51d2d Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 8 Jun 2022 11:42:56 -0400 Subject: [PATCH 12/62] Don't duplicate work that the RESET program already does. --- Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp index 55f0569b8..1c5be2c87 100644 --- a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp +++ b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp @@ -2785,7 +2785,6 @@ void Processor void Processor::reset() { state_ = Reset; - status_.begin_exception(7); } } From 079c3fd263834b81560d92cad5c6e5df4ebb6cdf Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 8 Jun 2022 14:43:31 -0400 Subject: [PATCH 13/62] Abort address error-causing exceptions before they begin. --- .../Implementation/68000Mk2Implementation.hpp | 42 +++++++++++-------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp index 1c5be2c87..249d15fd1 100644 --- a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp +++ b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp @@ -241,6 +241,19 @@ void Processor> 1) & 1)) { \ - bus_error_ = x; \ - exception_vector_ = berr_ ? InstructionSet::M68k::AccessFault : InstructionSet::M68k::AddressError; \ - MoveToStateSpecific(BusOrAddressErrorException); \ + if(berr_) { \ + RaiseBusOrAddressError(AccessFault, x); \ } \ if(vpa_) { \ x.length = HalfCycles(20) + (HalfCycles(20) + (e_clock_phase_ - time_remaining_) % HalfCycles(20)) % HalfCycles(20); \ @@ -288,13 +299,16 @@ void Processor> 1) & 1) { \ + RaiseBusOrAddressError(AddressError, perform); \ + } \ + PerformBusOperation(announce); \ + WaitForDTACK(announce); \ CompleteAccess(perform); // Sets up the next data access size and read flags. @@ -322,12 +336,6 @@ void Processor Date: Wed, 8 Jun 2022 14:43:51 -0400 Subject: [PATCH 14/62] Randomise all parts of memory other than the opcode. --- .../Mac/Clock SignalTests/68000OldVsNew.mm | 108 ++++++++++++++---- 1 file changed, 86 insertions(+), 22 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm index 16a494c9c..a505d5a0d 100644 --- a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm +++ b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm @@ -13,9 +13,42 @@ #include "68000Mk2.hpp" #include +#include namespace { +struct RandomStore { + using CollectionT = std::unordered_map>; + CollectionT values; + + void flag(uint32_t address, uint8_t participant) { + values[address].first |= participant; + } + + bool has(uint32_t address, uint8_t participant) { + auto entry = values.find(address); + if(entry == values.end()) return false; + return entry->second.first & participant; + } + + uint8_t value(uint32_t address, uint8_t participant) { + auto entry = values.find(address); + if(entry != values.end()) { + entry->second.first |= participant; + return entry->second.second; + } + + const uint8_t value = uint8_t(rand() >> 8); + values[address] = std::make_pair(participant, value); + return value; + } + + void clear() { + values.clear(); + } + +}; + struct Transaction { HalfCycles timestamp; uint8_t function_code = 0; @@ -25,8 +58,8 @@ struct Transaction { bool data_strobe = false; bool operator !=(const Transaction &rhs) const { - if(timestamp != rhs.timestamp) return true; - if(function_code != rhs.function_code) return true; +// if(timestamp != rhs.timestamp) return true; +// if(function_code != rhs.function_code) return true; if(address != rhs.address) return true; if(value != rhs.value) return true; if(address_strobe != rhs.address_strobe) return true; @@ -48,6 +81,8 @@ struct Transaction { }; struct BusHandler { + BusHandler(RandomStore &_store, uint8_t _participant) : store(_store), participant(_participant) {} + template HalfCycles perform_bus_operation(const Microcycle &cycle, bool is_supervisor) { Transaction transaction; @@ -66,18 +101,26 @@ struct BusHandler { time += cycle.length; - // TODO: generate a random value if this is a read from an address not yet written to; - // use a shared store in order to ensure that both devices get the same random values. - // Do the operation... const uint32_t address = cycle.address ? (*cycle.address & 0xffff'ff) : 0; switch(cycle.operation & (Microcycle::SelectWord | Microcycle::SelectByte | Microcycle::Read)) { default: break; case Microcycle::SelectWord | Microcycle::Read: + if(!store.has(address, participant)) { + ram[address] = store.value(address, participant); + } + if(!store.has(address+1, participant)) { + ram[address+1] = store.value(address+1, participant); + } + cycle.set_value16((ram[address] << 8) | ram[address + 1]); break; case Microcycle::SelectByte | Microcycle::Read: + if(!store.has(address, participant)) { + ram[address] = store.value(address, participant); + } + if(address & 1) { cycle.set_value8_low(ram[address]); } else { @@ -87,9 +130,12 @@ struct BusHandler { case Microcycle::SelectWord: ram[address] = cycle.value8_high(); ram[address+1] = cycle.value8_low(); + store.flag(address, participant); + store.flag(address+1, participant); break; case Microcycle::SelectByte: ram[address] = (address & 1) ? cycle.value8_low() : cycle.value8_high(); + store.flag(address, participant); break; } @@ -130,21 +176,29 @@ struct BusHandler { void set_default_vectors() { // Establish that all exception vectors point to 1024-byte blocks of memory. for(int c = 0; c < 256; c++) { - const uint32_t target = (c + 1) << 10; - ram[(c << 2) + 0] = uint8_t(target >> 24); - ram[(c << 2) + 1] = uint8_t(target >> 16); - ram[(c << 2) + 2] = uint8_t(target >> 8); - ram[(c << 2) + 3] = uint8_t(target >> 0); + const uint32_t target = (c + 2) << 10; + const uint32_t address = c << 2; + ram[address + 0] = uint8_t(target >> 24); + ram[address + 1] = uint8_t(target >> 16); + ram[address + 2] = uint8_t(target >> 8); + ram[address + 3] = uint8_t(target >> 0); + + store.flag(address+0, participant); + store.flag(address+1, participant); + store.flag(address+2, participant); + store.flag(address+3, participant); } } + + RandomStore &store; + const uint8_t participant; }; using OldProcessor = CPU::MC68000::Processor; using NewProcessor = CPU::MC68000Mk2::Processor; template struct Tester { - Tester() : processor(bus_handler) { - } + Tester(RandomStore &store, uint8_t participant) : bus_handler(store, participant), processor(bus_handler) {} void advance(int cycles, HalfCycles time_cutoff) { bus_handler.time_cutoff = time_cutoff; @@ -155,11 +209,16 @@ template struct Tester { bus_handler.transactions.clear(); bus_handler.set_default_vectors(); - bus_handler.ram[(2 << 10) + 0] = uint8_t(opcode >> 8); - bus_handler.ram[(2 << 10) + 1] = uint8_t(opcode >> 0); + const uint32_t address = 3 << 10; + bus_handler.ram[address + 0] = uint8_t(opcode >> 8); + bus_handler.ram[address + 1] = uint8_t(opcode >> 0); + bus_handler.store.flag(address, bus_handler.participant); + bus_handler.store.flag(address+1, bus_handler.participant); - bus_handler.transaction_delay = 12; // i.e. ignore the first eight transactions, - // which will just be the reset procedure. + bus_handler.transaction_delay = 8; // i.e. ignore the first eight transactions, + // which will just be the vector fetch part of + // the reset procedure. Instead assume logging + // at the initial prefetch fill. bus_handler.time = HalfCycles(0); processor.reset(); @@ -174,14 +233,17 @@ template struct Tester { @interface M68000OldVsNewTests : XCTestCase @end -@implementation M68000OldVsNewTests { -} +@implementation M68000OldVsNewTests - (void)testOldVsNew { - auto oldTester = std::make_unique>(); - auto newTester = std::make_unique>(); + RandomStore random_store; + auto oldTester = std::make_unique>(random_store, 0x01); + auto newTester = std::make_unique>(random_store, 0x02); InstructionSet::M68k::Predecoder decoder; + // Use a fixed seed to guarantee continuity across repeated runs. + srand(68000); + for(int c = 0; c < 65536; c++) { // Test only defined opcodes. const auto instruction = decoder.decode(uint16_t(c)); @@ -191,6 +253,7 @@ template struct Tester { // Test each 1000 times. for(int test = 0; test < 1000; test++) { + random_store.clear(); newTester->reset_with_opcode(c); oldTester->reset_with_opcode(c); @@ -214,8 +277,9 @@ template struct Tester { ++repeatIt; } printf("---\n"); - printf("< "); oldIt->print(); - printf("> "); newIt->print(); + printf("o: "); oldIt->print(); + printf("n: "); newIt->print(); + printf("\n"); break; } From 6efb9b24e077ae335434c8110867cb9fceeea078 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 8 Jun 2022 14:44:15 -0400 Subject: [PATCH 15/62] Ensure that a phoney reset gets the proper vector. --- Processors/68000/Implementation/68000Implementation.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Processors/68000/Implementation/68000Implementation.hpp b/Processors/68000/Implementation/68000Implementation.hpp index f547d16a9..08eea1289 100644 --- a/Processors/68000/Implementation/68000Implementation.hpp +++ b/Processors/68000/Implementation/68000Implementation.hpp @@ -2240,6 +2240,7 @@ void ProcessorStorage::set_status(uint16_t status) { template void Processor::reset() { execution_state_ = ExecutionState::Executing; active_step_ = reset_bus_steps_; + effective_address_[0] = 0; is_supervisor_ = 1; interrupt_level_ = 7; } From f4f93f4836b23b6b955f894f2cfac66cf16dac89 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 8 Jun 2022 14:53:04 -0400 Subject: [PATCH 16/62] Test a single, whole instruction; record read/write. --- .../Mac/Clock SignalTests/68000OldVsNew.mm | 39 ++++++++++++------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm index a505d5a0d..48f6c6014 100644 --- a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm +++ b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm @@ -56,6 +56,7 @@ struct Transaction { uint16_t value = 0; bool address_strobe = false; bool data_strobe = false; + bool read = false; bool operator !=(const Transaction &rhs) const { // if(timestamp != rhs.timestamp) return true; @@ -68,7 +69,7 @@ struct Transaction { } void print() const { - printf("%d: %d%d%d %c %c @ %06x with %04x\n", + printf("%d: %d%d%d %c %c @ %06x %s %04x\n", timestamp.as(), (function_code >> 2) & 1, (function_code >> 1) & 1, @@ -76,13 +77,23 @@ struct Transaction { address_strobe ? 'a' : '-', data_strobe ? 'd' : '-', address, + read ? "->" : "<-", value); } }; +struct HarmlessStopException {}; + struct BusHandler { BusHandler(RandomStore &_store, uint8_t _participant) : store(_store), participant(_participant) {} + void will_perform(uint32_t, uint16_t) { + --instructions; + if(instructions < 0) { + throw HarmlessStopException{}; + } + } + template HalfCycles perform_bus_operation(const Microcycle &cycle, bool is_supervisor) { Transaction transaction; @@ -98,6 +109,7 @@ struct BusHandler { transaction.data_strobe = cycle.operation & (Microcycle::SelectByte | Microcycle::SelectWord); if(cycle.address) transaction.address = *cycle.address & 0xffff'ff; transaction.timestamp = time; + transaction.read = cycle.operation & Microcycle::Read; time += cycle.length; @@ -155,9 +167,7 @@ struct BusHandler { time = HalfCycles(0); } } else { - if(transaction.timestamp < time_cutoff) { - transactions.push_back(transaction); - } + transactions.push_back(transaction); } } @@ -167,7 +177,7 @@ struct BusHandler { void flush() {} int transaction_delay; - HalfCycles time_cutoff; + int instructions; HalfCycles time; std::vector transactions; @@ -194,15 +204,18 @@ struct BusHandler { const uint8_t participant; }; -using OldProcessor = CPU::MC68000::Processor; -using NewProcessor = CPU::MC68000Mk2::Processor; +using OldProcessor = CPU::MC68000::Processor; +using NewProcessor = CPU::MC68000Mk2::Processor; template struct Tester { Tester(RandomStore &store, uint8_t participant) : bus_handler(store, participant), processor(bus_handler) {} - void advance(int cycles, HalfCycles time_cutoff) { - bus_handler.time_cutoff = time_cutoff; - processor.run_for(HalfCycles(cycles << 1)); + void run_instructions(int instructions) { + bus_handler.instructions = instructions; + + try { + processor.run_for(HalfCycles::max()); + } catch (const HarmlessStopException &) {} } void reset_with_opcode(uint16_t opcode) { @@ -257,9 +270,9 @@ template struct Tester { newTester->reset_with_opcode(c); oldTester->reset_with_opcode(c); - // For arbitrary resons, only run for 200 bus cycles, capturing up to 200 clock cycles of activity. - newTester->advance(200, HalfCycles(400)); - oldTester->advance(200, HalfCycles(400)); + // Run a single instruction. + newTester->run_instructions(1); + oldTester->run_instructions(1); // Compare bus activity. const auto &oldTransactions = oldTester->bus_handler.transactions; From ab35016aae447ec3b0458efbd3cb2ef78de5b881 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 8 Jun 2022 15:12:32 -0400 Subject: [PATCH 17/62] Clear any time debt upon phoney reset. --- Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp index 249d15fd1..fd337f724 100644 --- a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp +++ b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp @@ -2793,6 +2793,7 @@ void Processor void Processor::reset() { state_ = Reset; + time_remaining_ = HalfCycles(0); } } From fd1955e15bd23a587de60b82d47720f32eb76294 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 8 Jun 2022 15:12:47 -0400 Subject: [PATCH 18/62] Attempt to randomise and test register contents. --- .../Mac/Clock SignalTests/68000OldVsNew.mm | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm index 48f6c6014..2f8631488 100644 --- a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm +++ b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm @@ -214,7 +214,7 @@ template struct Tester { bus_handler.instructions = instructions; try { - processor.run_for(HalfCycles::max()); + processor.run_for(HalfCycles(5000)); } catch (const HarmlessStopException &) {} } @@ -266,10 +266,25 @@ template struct Tester { // Test each 1000 times. for(int test = 0; test < 1000; test++) { + // Establish with certainty the initial memory state. random_store.clear(); newTester->reset_with_opcode(c); oldTester->reset_with_opcode(c); + // Generate a random initial register state. + auto oldState = oldTester->processor.get_state(); + auto newState = newTester->processor.get_state(); + + for(int c = 0; c < 8; c++) { + oldState.data[c] = newState.registers.data[c] = rand() ^ (rand() << 1); + if(c != 7) oldState.address[c] = newState.registers.address[c] = rand() << 1; + } + oldState.status = newState.registers.status = rand() | (1 << 13); + oldState.user_stack_pointer = newState.registers.user_stack_pointer = rand() << 1; + + oldTester->processor.set_state(oldState); + newTester->processor.set_state(newState); + // Run a single instruction. newTester->run_instructions(1); oldTester->run_instructions(1); @@ -300,6 +315,25 @@ template struct Tester { ++newIt; ++oldIt; } + + // Compare registers. + oldState = oldTester->processor.get_state(); + newState = newTester->processor.get_state(); + + bool mismatch = false; + for(int c = 0; c < 8; c++) { + mismatch |= oldState.data[c] != newState.registers.data[c]; + if(c != 7) mismatch |= oldState.address[c] != newState.registers.address[c]; + } + mismatch |= oldState.status != newState.registers.status; + mismatch |= oldState.program_counter != newState.registers.program_counter; + mismatch |= oldState.user_stack_pointer != newState.registers.user_stack_pointer; + mismatch |= oldState.supervisor_stack_pointer != newState.registers.supervisor_stack_pointer; + + if(mismatch) { + printf("Registers don't match after %s, test %d\n", instruction.to_string().c_str(), test); + // TODO: more detail here! + } } } } From 168dc12e270dbb862ad0c557beb86da6fb7097d7 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 8 Jun 2022 16:03:02 -0400 Subject: [PATCH 19/62] Avoid spurious mismatches. --- OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm index 2f8631488..605957e94 100644 --- a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm +++ b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm @@ -214,7 +214,7 @@ template struct Tester { bus_handler.instructions = instructions; try { - processor.run_for(HalfCycles(5000)); + processor.run_for(HalfCycles(5000)); // Arbitrary, but will definitely exceed any one instruction (by quite a distance). } catch (const HarmlessStopException &) {} } @@ -279,11 +279,17 @@ template struct Tester { oldState.data[c] = newState.registers.data[c] = rand() ^ (rand() << 1); if(c != 7) oldState.address[c] = newState.registers.address[c] = rand() << 1; } - oldState.status = newState.registers.status = rand() | (1 << 13); + // Fully to paper over the two 68000s' different ways of doing a faked + // reset, pick a random status such that: + // + // (i) supervisor mode is active; + // (ii) trace is inactive; and + // (iii) interrupt level is 7. + oldState.status = newState.registers.status = (rand() | (1 << 13) | (7 << 8)) & ~(1 << 15); oldState.user_stack_pointer = newState.registers.user_stack_pointer = rand() << 1; - oldTester->processor.set_state(oldState); newTester->processor.set_state(newState); + oldTester->processor.set_state(oldState); // Run a single instruction. newTester->run_instructions(1); From 670201fcc2aa42769aaeb551cb1530dbdb73bce6 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 8 Jun 2022 16:03:16 -0400 Subject: [PATCH 20/62] Reset time debt upon 'reset'. --- Processors/68000/Implementation/68000Implementation.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Processors/68000/Implementation/68000Implementation.hpp b/Processors/68000/Implementation/68000Implementation.hpp index 08eea1289..18441397e 100644 --- a/Processors/68000/Implementation/68000Implementation.hpp +++ b/Processors/68000/Implementation/68000Implementation.hpp @@ -2243,6 +2243,7 @@ template void Proces effective_address_[0] = 0; is_supervisor_ = 1; interrupt_level_ = 7; + half_cycles_left_to_run_ = HalfCycles(0); } #undef status From da8e6737c6f4fedaa5c522f5b43274049bee1287 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 8 Jun 2022 16:15:11 -0400 Subject: [PATCH 21/62] Fix standard exception stack write order. --- .../Implementation/68000Mk2Implementation.hpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp index fd337f724..89705e168 100644 --- a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp +++ b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp @@ -409,15 +409,14 @@ void Processor Date: Wed, 8 Jun 2022 16:15:33 -0400 Subject: [PATCH 22/62] Permit instructions that end in an address error to differ in transactions. --- .../Mac/Clock SignalTests/68000OldVsNew.mm | 66 +++++++++++-------- 1 file changed, 38 insertions(+), 28 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm index 605957e94..24df61569 100644 --- a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm +++ b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm @@ -258,6 +258,8 @@ template struct Tester { srand(68000); for(int c = 0; c < 65536; c++) { + printf("%04x\n", c); + // Test only defined opcodes. const auto instruction = decoder.decode(uint16_t(c)); if(instruction.operation == InstructionSet::M68k::Operation::Undefined) { @@ -295,37 +297,45 @@ template struct Tester { newTester->run_instructions(1); oldTester->run_instructions(1); - // Compare bus activity. - const auto &oldTransactions = oldTester->bus_handler.transactions; - const auto &newTransactions = newTester->bus_handler.transactions; - - auto newIt = newTransactions.begin(); - auto oldIt = oldTransactions.begin(); - while(newIt != newTransactions.end() && oldIt != oldTransactions.end()) { - if(*newIt != *oldIt) { - printf("Mismatch in %s, test %d:\n", instruction.to_string().c_str(), test); - - auto repeatIt = newTransactions.begin(); - while(repeatIt != newIt) { - repeatIt->print(); - ++repeatIt; - } - printf("---\n"); - printf("o: "); oldIt->print(); - printf("n: "); newIt->print(); - printf("\n"); - - break; - } - - ++newIt; - ++oldIt; - } - - // Compare registers. + // Grab final states. oldState = oldTester->processor.get_state(); newState = newTester->processor.get_state(); + // Compare bus activity only if it doesn't look like an address + // error occurred. Don't check those as I don't have good information + // on the proper stack write order, so transactions are permitted to differ. + // + // Net effect will be 50% fewer transaction comparisons for instructions that + // can trigger an address error. + if(oldState.program_counter != 0x1404 || newState.registers.program_counter != 0x1404) { + const auto &oldTransactions = oldTester->bus_handler.transactions; + const auto &newTransactions = newTester->bus_handler.transactions; + + auto newIt = newTransactions.begin(); + auto oldIt = oldTransactions.begin(); + while(newIt != newTransactions.end() && oldIt != oldTransactions.end()) { + if(*newIt != *oldIt) { + printf("Mismatch in %s, test %d:\n", instruction.to_string().c_str(), test); + + auto repeatIt = newTransactions.begin(); + while(repeatIt != newIt) { + repeatIt->print(); + ++repeatIt; + } + printf("---\n"); + printf("o: "); oldIt->print(); + printf("n: "); newIt->print(); + printf("\n"); + + break; + } + + ++newIt; + ++oldIt; + } + } + + // Compare registers. bool mismatch = false; for(int c = 0; c < 8; c++) { mismatch |= oldState.data[c] != newState.registers.data[c]; From cc7a4f7f917aa675aed3a61d6d5af8362c825861 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 8 Jun 2022 21:15:11 -0400 Subject: [PATCH 23/62] Fix test build. --- OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 9fde13679..5ced38bd7 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -278,6 +278,7 @@ 4B595FAE2086DFBA0083CAA8 /* AudioToggle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B595FAC2086DFBA0083CAA8 /* AudioToggle.cpp */; }; 4B5B37312777C7FC0047F238 /* IPF.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B5B372F2777C7FC0047F238 /* IPF.cpp */; }; 4B5B37322777C7FC0047F238 /* IPF.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B5B372F2777C7FC0047F238 /* IPF.cpp */; }; + 4B5D497C28513F870076E2F9 /* IPF.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B5B372F2777C7FC0047F238 /* IPF.cpp */; }; 4B5D5C9725F56FC7001B4623 /* Spectrum.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B5D5C9525F56FC7001B4623 /* Spectrum.cpp */; }; 4B5D5C9825F56FC7001B4623 /* Spectrum.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B5D5C9525F56FC7001B4623 /* Spectrum.cpp */; }; 4B5FADBA1DE3151600AEC565 /* FileHolder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B5FADB81DE3151600AEC565 /* FileHolder.cpp */; }; @@ -6122,6 +6123,7 @@ 4B7752C328217F720073E2C5 /* Z80.cpp in Sources */, 4B778F1A23A5ED320000D260 /* Video.cpp in Sources */, 4B778F3B23A5F1650000D260 /* KeyboardMachine.cpp in Sources */, + 4B5D497C28513F870076E2F9 /* IPF.cpp in Sources */, 4B778F2E23A5F09E0000D260 /* IRQDelegatePortHandler.cpp in Sources */, 4B778EF323A5DB230000D260 /* PCMSegment.cpp in Sources */, 4B778F0D23A5EC150000D260 /* ZX80O81P.cpp in Sources */, From fdcbf617d8d020a87d5cf2dbb53505e0c1134680 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 9 Jun 2022 08:42:31 -0400 Subject: [PATCH 24/62] Avoid STOP. --- OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm index 24df61569..d64f2d0ae 100644 --- a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm +++ b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm @@ -262,7 +262,10 @@ template struct Tester { // Test only defined opcodes. const auto instruction = decoder.decode(uint16_t(c)); - if(instruction.operation == InstructionSet::M68k::Operation::Undefined) { + if( + instruction.operation == InstructionSet::M68k::Operation::Undefined || + instruction.operation == InstructionSet::M68k::Operation::STOP + ) { continue; } From ba2803c8075f3d7e577574b722b63cc3cd2769d9 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 9 Jun 2022 11:30:22 -0400 Subject: [PATCH 25/62] Include all bus activity after the split. --- OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm index d64f2d0ae..6cbb0264a 100644 --- a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm +++ b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm @@ -257,7 +257,7 @@ template struct Tester { // Use a fixed seed to guarantee continuity across repeated runs. srand(68000); - for(int c = 0; c < 65536; c++) { + for(int c = 0x4e72; c < 65536; c++) { printf("%04x\n", c); // Test only defined opcodes. @@ -326,8 +326,15 @@ template struct Tester { ++repeatIt; } printf("---\n"); - printf("o: "); oldIt->print(); - printf("n: "); newIt->print(); + while(newIt != newTransactions.end()) { + printf("n: "); newIt->print(); + ++newIt; + } + printf("\n"); + while(oldIt != oldTransactions.end()) { + printf("o: "); oldIt->print(); + ++oldIt; + } printf("\n"); break; From 5af03d74eca1d04b4364b513cd9749726de621d7 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 9 Jun 2022 12:21:39 -0400 Subject: [PATCH 26/62] Add note to self about first diagnosis. --- OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm index 6cbb0264a..cae12669f 100644 --- a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm +++ b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm @@ -248,6 +248,10 @@ template struct Tester { @implementation M68000OldVsNewTests +// List of known deviations of the new from the old, to check out: +// +// 1) address error following an RTE now raises the interrupt level to 7; before it left it untouched. + - (void)testOldVsNew { RandomStore random_store; auto oldTester = std::make_unique>(random_store, 0x01); @@ -262,6 +266,11 @@ template struct Tester { // Test only defined opcodes. const auto instruction = decoder.decode(uint16_t(c)); +// if( +// instruction.operation != InstructionSet::M68k::Operation::RTE +// ) { +// continue; +// } if( instruction.operation == InstructionSet::M68k::Operation::Undefined || instruction.operation == InstructionSet::M68k::Operation::STOP From a59ad064386d54d3b71c38d7a384e0ac7181eda5 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 9 Jun 2022 13:13:33 -0400 Subject: [PATCH 27/62] Print out summary of failure. --- OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm index cae12669f..133205668 100644 --- a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm +++ b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm @@ -14,6 +14,7 @@ #include #include +#include namespace { @@ -261,7 +262,8 @@ template struct Tester { // Use a fixed seed to guarantee continuity across repeated runs. srand(68000); - for(int c = 0x4e72; c < 65536; c++) { + std::set failing_operations; + for(int c = 0; c < 65536; c++) { printf("%04x\n", c); // Test only defined opcodes. @@ -346,6 +348,7 @@ template struct Tester { } printf("\n"); + failing_operations.insert(instruction.operation); break; } @@ -366,11 +369,17 @@ template struct Tester { mismatch |= oldState.supervisor_stack_pointer != newState.registers.supervisor_stack_pointer; if(mismatch) { + failing_operations.insert(instruction.operation); printf("Registers don't match after %s, test %d\n", instruction.to_string().c_str(), test); // TODO: more detail here! } } } + + printf("\nAll failing operations:\n"); + for(const auto operation: failing_operations) { + printf("%d,\n", int(operation)); + } } @end From 64053d697f769a8c1150f0f3e2130a0482c2a9d9 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 9 Jun 2022 16:17:09 -0400 Subject: [PATCH 28/62] Take improved guess at address error stacking order. --- .../Mac/Clock SignalTests/68000Tests.mm | 3 +++ .../Implementation/68000Mk2Implementation.hpp | 21 ++++++++++++------- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/68000Tests.mm b/OSBindings/Mac/Clock SignalTests/68000Tests.mm index 8cebc0385..b1289b5aa 100644 --- a/OSBindings/Mac/Clock SignalTests/68000Tests.mm +++ b/OSBindings/Mac/Clock SignalTests/68000Tests.mm @@ -189,6 +189,9 @@ // PC. XCTAssertEqual(stack_frame[5], 0x0000); XCTAssertEqual(stack_frame[6], 0x1004); + + // Check that A7 ended up in the proper location. + XCTAssertEqual(_machine->get_processor_state().registers.stack_pointer(), 0x1f8); } - (void)testShiftDuration { diff --git a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp index 89705e168..cafdee677 100644 --- a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp +++ b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp @@ -461,8 +461,13 @@ void Processor Date: Thu, 9 Jun 2022 16:18:04 -0400 Subject: [PATCH 29/62] Add an optional testing whitelist. --- .../Mac/Clock SignalTests/68000OldVsNew.mm | 32 ++++++++++++++----- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm index 133205668..e96513e60 100644 --- a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm +++ b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm @@ -262,17 +262,28 @@ template struct Tester { // Use a fixed seed to guarantee continuity across repeated runs. srand(68000); + std::set test_set = { + InstructionSet::M68k::Operation::ABCD, + InstructionSet::M68k::Operation::SBCD, + InstructionSet::M68k::Operation::MOVEb, + InstructionSet::M68k::Operation::MOVEw, + InstructionSet::M68k::Operation::MOVEl, + InstructionSet::M68k::Operation::PEA, + InstructionSet::M68k::Operation::MOVEtoSR, + InstructionSet::M68k::Operation::MOVEtoCCR, + InstructionSet::M68k::Operation::JSR, + InstructionSet::M68k::Operation::DIVU, + InstructionSet::M68k::Operation::RTE, + InstructionSet::M68k::Operation::RTR, + InstructionSet::M68k::Operation::TAS, + }; + std::set failing_operations; for(int c = 0; c < 65536; c++) { printf("%04x\n", c); - // Test only defined opcodes. + // Test only defined opcodes that aren't STOP (which will never teminate). const auto instruction = decoder.decode(uint16_t(c)); -// if( -// instruction.operation != InstructionSet::M68k::Operation::RTE -// ) { -// continue; -// } if( instruction.operation == InstructionSet::M68k::Operation::Undefined || instruction.operation == InstructionSet::M68k::Operation::STOP @@ -280,6 +291,11 @@ template struct Tester { continue; } + // If a whitelist is in place, adhere to it. + if(!test_set.empty() && test_set.find(instruction.operation) == test_set.end()) { + continue; + } + // Test each 1000 times. for(int test = 0; test < 1000; test++) { // Establish with certainty the initial memory state. @@ -321,7 +337,7 @@ template struct Tester { // // Net effect will be 50% fewer transaction comparisons for instructions that // can trigger an address error. - if(oldState.program_counter != 0x1404 || newState.registers.program_counter != 0x1404) { +// if(oldState.program_counter != 0x1404 || newState.registers.program_counter != 0x1404) { const auto &oldTransactions = oldTester->bus_handler.transactions; const auto &newTransactions = newTester->bus_handler.transactions; @@ -355,7 +371,7 @@ template struct Tester { ++newIt; ++oldIt; } - } +// } // Compare registers. bool mismatch = false; From 2e1675066de2856a4d49ceb3ce2c7855e98c7fa4 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 9 Jun 2022 16:59:06 -0400 Subject: [PATCH 30/62] Reinstate address error non-testing. --- OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm index e96513e60..370f9d70b 100644 --- a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm +++ b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm @@ -262,7 +262,7 @@ template struct Tester { // Use a fixed seed to guarantee continuity across repeated runs. srand(68000); - std::set test_set = { + std::set test_set;/* = { InstructionSet::M68k::Operation::ABCD, InstructionSet::M68k::Operation::SBCD, InstructionSet::M68k::Operation::MOVEb, @@ -276,7 +276,7 @@ template struct Tester { InstructionSet::M68k::Operation::RTE, InstructionSet::M68k::Operation::RTR, InstructionSet::M68k::Operation::TAS, - }; + };*/ std::set failing_operations; for(int c = 0; c < 65536; c++) { @@ -332,12 +332,12 @@ template struct Tester { newState = newTester->processor.get_state(); // Compare bus activity only if it doesn't look like an address - // error occurred. Don't check those as I don't have good information - // on the proper stack write order, so transactions are permitted to differ. + // error occurred. Don't check those as the old 68000 appears to be wrong + // most of the time about function codes, and that bleeds into the stacked data. // // Net effect will be 50% fewer transaction comparisons for instructions that // can trigger an address error. -// if(oldState.program_counter != 0x1404 || newState.registers.program_counter != 0x1404) { + if(oldState.program_counter != 0x1404 || newState.registers.program_counter != 0x1404) { const auto &oldTransactions = oldTester->bus_handler.transactions; const auto &newTransactions = newTester->bus_handler.transactions; @@ -371,7 +371,7 @@ template struct Tester { ++newIt; ++oldIt; } -// } + } // Compare registers. bool mismatch = false; From dd5c903fd69b8794c72b9f596ae69044ef7d8a39 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 9 Jun 2022 20:19:39 -0400 Subject: [PATCH 31/62] DIVS also appears sometimes to differ. --- OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm index 370f9d70b..d1a35816b 100644 --- a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm +++ b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm @@ -262,7 +262,7 @@ template struct Tester { // Use a fixed seed to guarantee continuity across repeated runs. srand(68000); - std::set test_set;/* = { + std::set test_set = { InstructionSet::M68k::Operation::ABCD, InstructionSet::M68k::Operation::SBCD, InstructionSet::M68k::Operation::MOVEb, @@ -273,10 +273,11 @@ template struct Tester { InstructionSet::M68k::Operation::MOVEtoCCR, InstructionSet::M68k::Operation::JSR, InstructionSet::M68k::Operation::DIVU, + InstructionSet::M68k::Operation::DIVS, InstructionSet::M68k::Operation::RTE, InstructionSet::M68k::Operation::RTR, InstructionSet::M68k::Operation::TAS, - };*/ + }; std::set failing_operations; for(int c = 0; c < 65536; c++) { From f8643a62e6b06a481f0daea0debe443af52d677e Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 9 Jun 2022 21:47:28 -0400 Subject: [PATCH 32/62] Change RTE and RTR read order. --- .../Implementation/68000Mk2Implementation.hpp | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp index cafdee677..ef8d84ef4 100644 --- a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp +++ b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp @@ -2396,18 +2396,25 @@ void Processor Date: Thu, 9 Jun 2022 21:48:15 -0400 Subject: [PATCH 33/62] Notarise digressions that appear to be correct, remove now-working RTE/RTR. --- .../Mac/Clock SignalTests/68000OldVsNew.mm | 49 ++++++++++--------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm index d1a35816b..e78053ddc 100644 --- a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm +++ b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm @@ -249,10 +249,6 @@ template struct Tester { @implementation M68000OldVsNewTests -// List of known deviations of the new from the old, to check out: -// -// 1) address error following an RTE now raises the interrupt level to 7; before it left it untouched. - - (void)testOldVsNew { RandomStore random_store; auto oldTester = std::make_unique>(random_store, 0x01); @@ -263,20 +259,18 @@ template struct Tester { srand(68000); std::set test_set = { - InstructionSet::M68k::Operation::ABCD, - InstructionSet::M68k::Operation::SBCD, - InstructionSet::M68k::Operation::MOVEb, - InstructionSet::M68k::Operation::MOVEw, - InstructionSet::M68k::Operation::MOVEl, - InstructionSet::M68k::Operation::PEA, - InstructionSet::M68k::Operation::MOVEtoSR, - InstructionSet::M68k::Operation::MOVEtoCCR, - InstructionSet::M68k::Operation::JSR, - InstructionSet::M68k::Operation::DIVU, - InstructionSet::M68k::Operation::DIVS, - InstructionSet::M68k::Operation::RTE, - InstructionSet::M68k::Operation::RTR, - InstructionSet::M68k::Operation::TAS, +// InstructionSet::M68k::Operation::ABCD, // Old implementation doesn't match flamewing tests, sometimes produces incorrect results. +// InstructionSet::M68k::Operation::SBCD, // Old implementation doesn't match flamewing tests, sometimes produces incorrect results. +// InstructionSet::M68k::Operation::MOVEb, +// InstructionSet::M68k::Operation::MOVEw, +// InstructionSet::M68k::Operation::MOVEl, +// InstructionSet::M68k::Operation::PEA, +// InstructionSet::M68k::Operation::MOVEtoSR, // Old implementation doesn't repeat a PC fetch. +// InstructionSet::M68k::Operation::MOVEtoCCR, // Old implementation doesn't repeat a PC fetch. +// InstructionSet::M68k::Operation::JSR, // Old implementation ends up skipping stack space if the destination throws an address error. +// InstructionSet::M68k::Operation::DIVU, +// InstructionSet::M68k::Operation::DIVS, +// InstructionSet::M68k::Operation::TAS, }; std::set failing_operations; @@ -298,7 +292,7 @@ template struct Tester { } // Test each 1000 times. - for(int test = 0; test < 1000; test++) { + for(int test = 0; test < 100; test++) { // Establish with certainty the initial memory state. random_store.clear(); newTester->reset_with_opcode(c); @@ -320,6 +314,9 @@ template struct Tester { // (iii) interrupt level is 7. oldState.status = newState.registers.status = (rand() | (1 << 13) | (7 << 8)) & ~(1 << 15); oldState.user_stack_pointer = newState.registers.user_stack_pointer = rand() << 1; + oldState.supervisor_stack_pointer = newState.registers.supervisor_stack_pointer = 0x800; + + auto initialState = oldState; newTester->processor.set_state(newState); oldTester->processor.set_state(oldState); @@ -338,10 +335,9 @@ template struct Tester { // // Net effect will be 50% fewer transaction comparisons for instructions that // can trigger an address error. + const auto &oldTransactions = oldTester->bus_handler.transactions; + const auto &newTransactions = newTester->bus_handler.transactions; if(oldState.program_counter != 0x1404 || newState.registers.program_counter != 0x1404) { - const auto &oldTransactions = oldTester->bus_handler.transactions; - const auto &newTransactions = newTester->bus_handler.transactions; - auto newIt = newTransactions.begin(); auto oldIt = oldTransactions.begin(); while(newIt != newTransactions.end() && oldIt != oldTransactions.end()) { @@ -388,6 +384,15 @@ template struct Tester { if(mismatch) { failing_operations.insert(instruction.operation); printf("Registers don't match after %s, test %d\n", instruction.to_string().c_str(), test); + for(const auto &transaction: newTransactions) { + printf("n: "); transaction.print(); + } + printf("\n"); + for(const auto &transaction: oldTransactions) { + printf("o: "); transaction.print(); + } + printf("\n"); + // TODO: more detail here! } } From aec4bf9d4569567841a51d9ec93fdef0cc3a36d9 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 10 Jun 2022 15:57:35 -0400 Subject: [PATCH 34/62] Correct TAS timing. --- .../Implementation/68000Mk2Implementation.hpp | 37 ++++++++++++++----- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp index ef8d84ef4..bfc95f9d7 100644 --- a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp +++ b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp @@ -97,7 +97,7 @@ enum ExecutionState: int { CalcAbsoluteShort, // np CalcAbsoluteLong, // np np - CalcEffectiveAddressIdleFor8bitDisplacement, // As per CalcEffectiveAddress unless one of the + CalcEffectiveAddressIdleFor8bitDisplacementAndPreDec, // As per CalcEffectiveAddress unless one of the // 8-bit displacement modes is in use, in which case // an extra idle bus state is prefixed. @@ -173,6 +173,7 @@ enum ExecutionState: int { LEA, PEA, TAS, + TASAddressRegisterIndirectWithIndex8bitDisplacement, MOVEtoCCRSR, RTR, RTE, @@ -964,24 +965,33 @@ void Processor Date: Fri, 10 Jun 2022 15:57:54 -0400 Subject: [PATCH 35/62] Remove entire RESET sequence, move to testing PEA. --- OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm index e78053ddc..02b52b8a4 100644 --- a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm +++ b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm @@ -229,10 +229,7 @@ template struct Tester { bus_handler.store.flag(address, bus_handler.participant); bus_handler.store.flag(address+1, bus_handler.participant); - bus_handler.transaction_delay = 8; // i.e. ignore the first eight transactions, - // which will just be the vector fetch part of - // the reset procedure. Instead assume logging - // at the initial prefetch fill. + bus_handler.transaction_delay = 12; // i.e. ignore everything from the RESET sequence. bus_handler.time = HalfCycles(0); processor.reset(); @@ -264,13 +261,13 @@ template struct Tester { // InstructionSet::M68k::Operation::MOVEb, // InstructionSet::M68k::Operation::MOVEw, // InstructionSet::M68k::Operation::MOVEl, -// InstructionSet::M68k::Operation::PEA, + InstructionSet::M68k::Operation::PEA, // InstructionSet::M68k::Operation::MOVEtoSR, // Old implementation doesn't repeat a PC fetch. // InstructionSet::M68k::Operation::MOVEtoCCR, // Old implementation doesn't repeat a PC fetch. // InstructionSet::M68k::Operation::JSR, // Old implementation ends up skipping stack space if the destination throws an address error. // InstructionSet::M68k::Operation::DIVU, // InstructionSet::M68k::Operation::DIVS, -// InstructionSet::M68k::Operation::TAS, +// InstructionSet::M68k::Operation::TAS, // Old implementation just doesn't match published cycle counts. }; std::set failing_operations; From 43c0dea1bd9f230d5ec61307c5ee996881401763 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 10 Jun 2022 16:12:54 -0400 Subject: [PATCH 36/62] With the difference in RESET times now factored out, test timing too. --- OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm index 02b52b8a4..1a5ce3e65 100644 --- a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm +++ b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm @@ -60,7 +60,7 @@ struct Transaction { bool read = false; bool operator !=(const Transaction &rhs) const { -// if(timestamp != rhs.timestamp) return true; + if(timestamp != rhs.timestamp) return true; // if(function_code != rhs.function_code) return true; if(address != rhs.address) return true; if(value != rhs.value) return true; @@ -255,7 +255,7 @@ template struct Tester { // Use a fixed seed to guarantee continuity across repeated runs. srand(68000); - std::set test_set = { + std::set test_set;/* = { // InstructionSet::M68k::Operation::ABCD, // Old implementation doesn't match flamewing tests, sometimes produces incorrect results. // InstructionSet::M68k::Operation::SBCD, // Old implementation doesn't match flamewing tests, sometimes produces incorrect results. // InstructionSet::M68k::Operation::MOVEb, @@ -268,7 +268,7 @@ template struct Tester { // InstructionSet::M68k::Operation::DIVU, // InstructionSet::M68k::Operation::DIVS, // InstructionSet::M68k::Operation::TAS, // Old implementation just doesn't match published cycle counts. - }; + };*/ std::set failing_operations; for(int c = 0; c < 65536; c++) { From 97715e7ccc43f4478b213e0376af83ed7d5fe119 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 10 Jun 2022 16:34:05 -0400 Subject: [PATCH 37/62] Expand test set to include those with timing discrepancies. --- .../Mac/Clock SignalTests/68000OldVsNew.mm | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm index 1a5ce3e65..e87ce7023 100644 --- a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm +++ b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm @@ -255,7 +255,7 @@ template struct Tester { // Use a fixed seed to guarantee continuity across repeated runs. srand(68000); - std::set test_set;/* = { + std::set test_set = { // InstructionSet::M68k::Operation::ABCD, // Old implementation doesn't match flamewing tests, sometimes produces incorrect results. // InstructionSet::M68k::Operation::SBCD, // Old implementation doesn't match flamewing tests, sometimes produces incorrect results. // InstructionSet::M68k::Operation::MOVEb, @@ -264,11 +264,30 @@ template struct Tester { InstructionSet::M68k::Operation::PEA, // InstructionSet::M68k::Operation::MOVEtoSR, // Old implementation doesn't repeat a PC fetch. // InstructionSet::M68k::Operation::MOVEtoCCR, // Old implementation doesn't repeat a PC fetch. +// InstructionSet::M68k::Operation::CMPAl, // InstructionSet::M68k::Operation::JSR, // Old implementation ends up skipping stack space if the destination throws an address error. +// InstructionSet::M68k::Operation::CLRb, +// InstructionSet::M68k::Operation::CLRw, +// InstructionSet::M68k::Operation::NEGXb, +// InstructionSet::M68k::Operation::NEGXw, +// InstructionSet::M68k::Operation::NEGb, +// InstructionSet::M68k::Operation::NEGw, +// InstructionSet::M68k::Operation::MOVEMtoRl, +// InstructionSet::M68k::Operation::MOVEMtoRw, +// InstructionSet::M68k::Operation::MOVEMtoMl, +// InstructionSet::M68k::Operation::MOVEMtoMw, +// InstructionSet::M68k::Operation::NOTb, +// InstructionSet::M68k::Operation::NOTw, +// InstructionSet::M68k::Operation::MULU, +// InstructionSet::M68k::Operation::MULS, // InstructionSet::M68k::Operation::DIVU, // InstructionSet::M68k::Operation::DIVS, +// InstructionSet::M68k::Operation::RTE, +// InstructionSet::M68k::Operation::TRAP, +// InstructionSet::M68k::Operation::TRAPV, +// InstructionSet::M68k::Operation::CHK, // InstructionSet::M68k::Operation::TAS, // Old implementation just doesn't match published cycle counts. - };*/ + }; std::set failing_operations; for(int c = 0; c < 65536; c++) { From 917b7fbf801e75e699fa4227e1ffccbe876f94c1 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 10 Jun 2022 16:50:38 -0400 Subject: [PATCH 38/62] Notarise won't fix status of CLR, NEGX, NEG, NOT. --- .../Mac/Clock SignalTests/68000OldVsNew.mm | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm index e87ce7023..1a1658fed 100644 --- a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm +++ b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm @@ -261,23 +261,23 @@ template struct Tester { // InstructionSet::M68k::Operation::MOVEb, // InstructionSet::M68k::Operation::MOVEw, // InstructionSet::M68k::Operation::MOVEl, - InstructionSet::M68k::Operation::PEA, +// InstructionSet::M68k::Operation::PEA, // InstructionSet::M68k::Operation::MOVEtoSR, // Old implementation doesn't repeat a PC fetch. // InstructionSet::M68k::Operation::MOVEtoCCR, // Old implementation doesn't repeat a PC fetch. // InstructionSet::M68k::Operation::CMPAl, // InstructionSet::M68k::Operation::JSR, // Old implementation ends up skipping stack space if the destination throws an address error. -// InstructionSet::M68k::Operation::CLRb, -// InstructionSet::M68k::Operation::CLRw, -// InstructionSet::M68k::Operation::NEGXb, -// InstructionSet::M68k::Operation::NEGXw, -// InstructionSet::M68k::Operation::NEGb, -// InstructionSet::M68k::Operation::NEGw, -// InstructionSet::M68k::Operation::MOVEMtoRl, -// InstructionSet::M68k::Operation::MOVEMtoRw, -// InstructionSet::M68k::Operation::MOVEMtoMl, -// InstructionSet::M68k::Operation::MOVEMtoMw, -// InstructionSet::M68k::Operation::NOTb, -// InstructionSet::M68k::Operation::NOTw, +// InstructionSet::M68k::Operation::CLRb, // Old implementation omits an idle cycle before -(An) +// InstructionSet::M68k::Operation::CLRw, // Old implementation omits an idle cycle before -(An) +// InstructionSet::M68k::Operation::NEGXb, // Old implementation omits an idle cycle before -(An) +// InstructionSet::M68k::Operation::NEGXw, // Old implementation omits an idle cycle before -(An) +// InstructionSet::M68k::Operation::NEGb, // Old implementation omits an idle cycle before -(An) +// InstructionSet::M68k::Operation::NEGw, // Old implementation omits an idle cycle before -(An) + InstructionSet::M68k::Operation::MOVEMtoRl, + InstructionSet::M68k::Operation::MOVEMtoRw, + InstructionSet::M68k::Operation::MOVEMtoMl, + InstructionSet::M68k::Operation::MOVEMtoMw, +// InstructionSet::M68k::Operation::NOTb, // Old implementation omits an idle cycle before -(An) +// InstructionSet::M68k::Operation::NOTw, // Old implementation omits an idle cycle before -(An) // InstructionSet::M68k::Operation::MULU, // InstructionSet::M68k::Operation::MULS, // InstructionSet::M68k::Operation::DIVU, @@ -291,7 +291,7 @@ template struct Tester { std::set failing_operations; for(int c = 0; c < 65536; c++) { - printf("%04x\n", c); +// printf("%04x\n", c); // Test only defined opcodes that aren't STOP (which will never teminate). const auto instruction = decoder.decode(uint16_t(c)); From c3345dd839c2360f0078318484030732a5e3bdf0 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 10 Jun 2022 21:52:07 -0400 Subject: [PATCH 39/62] Fix MOVEM timing. --- .../Mac/Clock SignalTests/68000OldVsNew.mm | 4 - .../Implementation/68000Mk2Implementation.hpp | 78 ++++++++++++------- 2 files changed, 52 insertions(+), 30 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm index 1a1658fed..b5defaed1 100644 --- a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm +++ b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm @@ -272,10 +272,6 @@ template struct Tester { // InstructionSet::M68k::Operation::NEGXw, // Old implementation omits an idle cycle before -(An) // InstructionSet::M68k::Operation::NEGb, // Old implementation omits an idle cycle before -(An) // InstructionSet::M68k::Operation::NEGw, // Old implementation omits an idle cycle before -(An) - InstructionSet::M68k::Operation::MOVEMtoRl, - InstructionSet::M68k::Operation::MOVEMtoRw, - InstructionSet::M68k::Operation::MOVEMtoMl, - InstructionSet::M68k::Operation::MOVEMtoMw, // InstructionSet::M68k::Operation::NOTb, // Old implementation omits an idle cycle before -(An) // InstructionSet::M68k::Operation::NOTw, // Old implementation omits an idle cycle before -(An) // InstructionSet::M68k::Operation::MULU, diff --git a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp index bfc95f9d7..a8139521e 100644 --- a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp +++ b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp @@ -173,7 +173,6 @@ enum ExecutionState: int { LEA, PEA, TAS, - TASAddressRegisterIndirectWithIndex8bitDisplacement, MOVEtoCCRSR, RTR, RTE, @@ -185,6 +184,9 @@ enum ExecutionState: int { STOP, TRAP, TRAPV, + + AddressRegisterIndirectWithIndex8bitDisplacement_n_np, + ProgramCounterIndirectWithIndex8bitDisplacement_n_np, }; // MARK: - The state machine. @@ -983,15 +985,13 @@ void Processor Date: Sat, 11 Jun 2022 11:17:18 -0400 Subject: [PATCH 40/62] Verify newer CMPA.l, RTE, TRAP[V] and CHK. --- OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm index b5defaed1..46b9f3d24 100644 --- a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm +++ b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm @@ -264,7 +264,7 @@ template struct Tester { // InstructionSet::M68k::Operation::PEA, // InstructionSet::M68k::Operation::MOVEtoSR, // Old implementation doesn't repeat a PC fetch. // InstructionSet::M68k::Operation::MOVEtoCCR, // Old implementation doesn't repeat a PC fetch. -// InstructionSet::M68k::Operation::CMPAl, +// InstructionSet::M68k::Operation::CMPAl, // Old implementation omits an idle cycle before -(An) // InstructionSet::M68k::Operation::JSR, // Old implementation ends up skipping stack space if the destination throws an address error. // InstructionSet::M68k::Operation::CLRb, // Old implementation omits an idle cycle before -(An) // InstructionSet::M68k::Operation::CLRw, // Old implementation omits an idle cycle before -(An) @@ -278,10 +278,10 @@ template struct Tester { // InstructionSet::M68k::Operation::MULS, // InstructionSet::M68k::Operation::DIVU, // InstructionSet::M68k::Operation::DIVS, -// InstructionSet::M68k::Operation::RTE, -// InstructionSet::M68k::Operation::TRAP, -// InstructionSet::M68k::Operation::TRAPV, -// InstructionSet::M68k::Operation::CHK, +// InstructionSet::M68k::Operation::RTE, // When an address error is thrown, the old implementation will enter it at the interrupt level reinstalled from the RTE. +// InstructionSet::M68k::Operation::TRAP, // Old implementation relocates the idle state near the end to the beginning. +// InstructionSet::M68k::Operation::TRAPV, // Old implementation relocates the idle state near the end to the beginning. +// InstructionSet::M68k::Operation::CHK, // Old implementation pauses four cycles too long. // InstructionSet::M68k::Operation::TAS, // Old implementation just doesn't match published cycle counts. }; From 2a9a05785c5c1c17723eda57eebcd6d6cc53592b Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 11 Jun 2022 21:10:24 -0400 Subject: [PATCH 41/62] Bus and address error don't affect interrupt level. --- Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp index a8139521e..b5528d16a 100644 --- a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp +++ b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp @@ -475,7 +475,7 @@ void Processor Date: Sat, 11 Jun 2022 21:15:08 -0400 Subject: [PATCH 42/62] The old implementation was correct. --- OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm | 1 - 1 file changed, 1 deletion(-) diff --git a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm index 46b9f3d24..a7b935bcc 100644 --- a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm +++ b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm @@ -278,7 +278,6 @@ template struct Tester { // InstructionSet::M68k::Operation::MULS, // InstructionSet::M68k::Operation::DIVU, // InstructionSet::M68k::Operation::DIVS, -// InstructionSet::M68k::Operation::RTE, // When an address error is thrown, the old implementation will enter it at the interrupt level reinstalled from the RTE. // InstructionSet::M68k::Operation::TRAP, // Old implementation relocates the idle state near the end to the beginning. // InstructionSet::M68k::Operation::TRAPV, // Old implementation relocates the idle state near the end to the beginning. // InstructionSet::M68k::Operation::CHK, // Old implementation pauses four cycles too long. From 8ada73b28378a76a9ba37d4e98cbf9b372a3aca4 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 13 Jun 2022 08:57:49 -0400 Subject: [PATCH 43/62] Use the outer switch for addressing mode dispatch, saving a lot of syntax. --- InstructionSets/M68k/Instruction.hpp | 2 + .../Implementation/68000Mk2Implementation.hpp | 259 +++++++----------- 2 files changed, 94 insertions(+), 167 deletions(-) diff --git a/InstructionSets/M68k/Instruction.hpp b/InstructionSets/M68k/Instruction.hpp index 314729f8d..75c55ed29 100644 --- a/InstructionSets/M68k/Instruction.hpp +++ b/InstructionSets/M68k/Instruction.hpp @@ -250,6 +250,8 @@ enum class AddressingMode: uint8_t { /// .q; value is embedded in the opcode. Quick = 0b01'110, }; +/// Guaranteed to be 1+[largest value used by AddressingMode]. +static constexpr int AddressingModeCount = 0b10'110; /*! A preinstruction is as much of an instruction as can be decoded with diff --git a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp index b5528d16a..d87e7f656 100644 --- a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp +++ b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp @@ -17,6 +17,9 @@ namespace CPU { namespace MC68000Mk2 { +#define AddressingDispatch(x) \ + x, x##__end = x + InstructionSet::M68k::AddressingModeCount + /// States for the state machine which are named by /// me for their purpose rather than automatically by file position. /// These are negative to avoid ambiguity with the other group. @@ -25,11 +28,6 @@ enum ExecutionState: int { Decode, WaitForDTACK, - /// Perform the proper sequence to fetch a byte or word operand. - FetchOperand_bw, - /// Perform the proper sequence to fetch a long-word operand. - FetchOperand_l, - StoreOperand, StoreOperand_bw, StoreOperand_l, @@ -64,42 +62,26 @@ enum ExecutionState: int { // Further consideration may be necessary. Especially once this is // up on its feet and profiling becomes an option. - FetchAddressRegisterIndirect_bw, - FetchAddressRegisterIndirectWithPostincrement_bw, - FetchAddressRegisterIndirectWithPredecrement_bw, - FetchAddressRegisterIndirectWithDisplacement_bw, - FetchAddressRegisterIndirectWithIndex8bitDisplacement_bw, - FetchProgramCounterIndirectWithDisplacement_bw, - FetchProgramCounterIndirectWithIndex8bitDisplacement_bw, - FetchAbsoluteShort_bw, - FetchAbsoluteLong_bw, - FetchImmediateData_bw, - - FetchAddressRegisterIndirect_l, - FetchAddressRegisterIndirectWithPostincrement_l, - FetchAddressRegisterIndirectWithPredecrement_l, - FetchAddressRegisterIndirectWithDisplacement_l, - FetchAddressRegisterIndirectWithIndex8bitDisplacement_l, - FetchProgramCounterIndirectWithDisplacement_l, - FetchProgramCounterIndirectWithIndex8bitDisplacement_l, - FetchAbsoluteShort_l, - FetchAbsoluteLong_l, - FetchImmediateData_l, - - CalcEffectiveAddress, // - - CalcAddressRegisterIndirect, // - - CalcAddressRegisterIndirectWithPostincrement, // - - CalcAddressRegisterIndirectWithPredecrement, // - - CalcAddressRegisterIndirectWithDisplacement, // np - CalcAddressRegisterIndirectWithIndex8bitDisplacement, // np n - CalcProgramCounterIndirectWithDisplacement, // np - CalcProgramCounterIndirectWithIndex8bitDisplacement, // np n - CalcAbsoluteShort, // np - CalcAbsoluteLong, // np np - - CalcEffectiveAddressIdleFor8bitDisplacementAndPreDec, // As per CalcEffectiveAddress unless one of the - // 8-bit displacement modes is in use, in which case - // an extra idle bus state is prefixed. + /// Perform the proper sequence to fetch a byte or word operand. + AddressingDispatch(FetchOperand_bw), + /// Perform the proper sequence to fetch a long-word operand. + AddressingDispatch(FetchOperand_l), + /// Perform the sequence to calculate an effective address, but don't fetch from it. + /// There's a lack of uniformity in the bus programs used by the 68000 for relevant + /// instructions; this entry point uses: + /// + /// Dn - An - + /// (An)+ - -(An) - + /// (d16, An) np (d8, An, Xn) np n + /// (d16, PC) np (d8, PC, Xn) np n + /// (xxx).w np (xxx).l np np + AddressingDispatch(CalcEffectiveAddress), + /// Similar to CalcEffectiveAddress, but varies slightly in the patterns: + /// + /// -(An) n + /// (d8, An, Xn) n np n + /// (d8, PC, Xn) n np n + CalcEffectiveAddressIdleFor8bitDisplacementAndPreDec, // Various forms of perform; each of these will // perform the current instruction, then do the @@ -189,6 +171,8 @@ enum ExecutionState: int { ProgramCounterIndirectWithIndex8bitDisplacement_n_np, }; +#undef AddressingDispatch + // MARK: - The state machine. template @@ -215,7 +199,15 @@ void Processor> 12].w))) + \ uint32_t(int8_t(prefetch_.b)); - BeginState(FetchAddressRegisterIndirectWithIndex8bitDisplacement_bw): + BeginStateMode(FetchOperand_bw, AddressRegisterIndirectWithIndex8bitDisplacement): effective_address_[next_operand_].l = d8Xn(registers_[8 + instruction_.reg(next_operand_)].l); SetDataAddress(effective_address_[next_operand_].l); @@ -1375,7 +1298,7 @@ void Processor Date: Mon, 13 Jun 2022 10:27:22 -0400 Subject: [PATCH 44/62] Avoid double conditional for CalcEffectiveAddressIdleFor8bitDisplacementAndPreDec. --- .../Implementation/68000Mk2Implementation.hpp | 30 ++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp index d87e7f656..62ced29af 100644 --- a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp +++ b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp @@ -81,7 +81,7 @@ enum ExecutionState: int { /// -(An) n /// (d8, An, Xn) n np n /// (d8, PC, Xn) n np n - CalcEffectiveAddressIdleFor8bitDisplacementAndPreDec, + AddressingDispatch(CalcEffectiveAddressIdleFor8bitDisplacementAndPreDec), // Various forms of perform; each of these will // perform the current instruction, then do the @@ -1073,16 +1073,8 @@ void Processor Date: Mon, 13 Jun 2022 10:39:06 -0400 Subject: [PATCH 45/62] Expand test to make sure that correct data strobes are active. --- .../Mac/Clock SignalTests/68000OldVsNew.mm | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm index a7b935bcc..0a70594f9 100644 --- a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm +++ b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm @@ -56,8 +56,8 @@ struct Transaction { uint32_t address = 0; uint16_t value = 0; bool address_strobe = false; - bool data_strobe = false; bool read = false; + int data_strobes = 0; bool operator !=(const Transaction &rhs) const { if(timestamp != rhs.timestamp) return true; @@ -65,18 +65,19 @@ struct Transaction { if(address != rhs.address) return true; if(value != rhs.value) return true; if(address_strobe != rhs.address_strobe) return true; - if(data_strobe != rhs.data_strobe) return true; + if(data_strobes != rhs.data_strobes) return true; return false; } void print() const { - printf("%d: %d%d%d %c %c @ %06x %s %04x\n", + printf("%d: %d%d%d %c %c%c @ %06x %s %04x\n", timestamp.as(), (function_code >> 2) & 1, (function_code >> 1) & 1, (function_code >> 0) & 1, address_strobe ? 'a' : '-', - data_strobe ? 'd' : '-', + (address_strobe & 1) ? 'b' : '-', + (address_strobe & 2) ? 'w' : '-', address, read ? "->" : "<-", value); @@ -107,7 +108,7 @@ struct BusHandler { transaction.function_code |= (cycle.operation & Microcycle::IsData) ? 0x1 : 0x2; } transaction.address_strobe = cycle.operation & (Microcycle::NewAddress | Microcycle::SameAddress); - transaction.data_strobe = cycle.operation & (Microcycle::SelectByte | Microcycle::SelectWord); + transaction.data_strobes = cycle.operation & (Microcycle::SelectByte | Microcycle::SelectWord); if(cycle.address) transaction.address = *cycle.address & 0xffff'ff; transaction.timestamp = time; transaction.read = cycle.operation & Microcycle::Read; @@ -154,12 +155,12 @@ struct BusHandler { // Add the data value if relevant. - if(transaction.data_strobe) { + if(transaction.data_strobes) { transaction.value = cycle.value16(); } // Push back only if interesting. - if(transaction.address_strobe || transaction.data_strobe || transaction.function_code == 7) { + if(transaction.address_strobe || transaction.data_strobes || transaction.function_code == 7) { if(transaction_delay) { --transaction_delay; @@ -327,8 +328,6 @@ template struct Tester { oldState.user_stack_pointer = newState.registers.user_stack_pointer = rand() << 1; oldState.supervisor_stack_pointer = newState.registers.supervisor_stack_pointer = 0x800; - auto initialState = oldState; - newTester->processor.set_state(newState); oldTester->processor.set_state(oldState); From 7dc66128c229b27ac86a9711184a610c837dd76b Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 13 Jun 2022 10:49:47 -0400 Subject: [PATCH 46/62] Fix strobe output. --- OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm index 0a70594f9..9f924f7bd 100644 --- a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm +++ b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm @@ -76,8 +76,8 @@ struct Transaction { (function_code >> 1) & 1, (function_code >> 0) & 1, address_strobe ? 'a' : '-', - (address_strobe & 1) ? 'b' : '-', - (address_strobe & 2) ? 'w' : '-', + (data_strobes & 1) ? 'b' : '-', + (data_strobes & 2) ? 'w' : '-', address, read ? "->" : "<-", value); From e066546c13ccd2c0367c55cdbb573b1313e29e11 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 13 Jun 2022 14:08:42 -0400 Subject: [PATCH 47/62] Resolve PEA timing errors. --- .../Mac/Clock SignalTests/68000OldVsNew.mm | 15 +++-- .../Implementation/68000Mk2Implementation.hpp | 64 +++++++++++++++++-- 2 files changed, 70 insertions(+), 9 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm index 9f924f7bd..1665652fd 100644 --- a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm +++ b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm @@ -262,7 +262,6 @@ template struct Tester { // InstructionSet::M68k::Operation::MOVEb, // InstructionSet::M68k::Operation::MOVEw, // InstructionSet::M68k::Operation::MOVEl, -// InstructionSet::M68k::Operation::PEA, // InstructionSet::M68k::Operation::MOVEtoSR, // Old implementation doesn't repeat a PC fetch. // InstructionSet::M68k::Operation::MOVEtoCCR, // Old implementation doesn't repeat a PC fetch. // InstructionSet::M68k::Operation::CMPAl, // Old implementation omits an idle cycle before -(An) @@ -285,6 +284,7 @@ template struct Tester { // InstructionSet::M68k::Operation::TAS, // Old implementation just doesn't match published cycle counts. }; + int testsRun = 0; std::set failing_operations; for(int c = 0; c < 65536; c++) { // printf("%04x\n", c); @@ -305,6 +305,8 @@ template struct Tester { // Test each 1000 times. for(int test = 0; test < 100; test++) { + ++testsRun; + // Establish with certainty the initial memory state. random_store.clear(); newTester->reset_with_opcode(c); @@ -408,9 +410,14 @@ template struct Tester { } } - printf("\nAll failing operations:\n"); - for(const auto operation: failing_operations) { - printf("%d,\n", int(operation)); + printf("%d tests run\n", testsRun); + if(failing_operations.empty()) { + printf("No failures\n"); + } else { + printf("\nAll failing operations:\n"); + for(const auto operation: failing_operations) { + printf("%d,\n", int(operation)); + } } } diff --git a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp index 62ced29af..4b207b005 100644 --- a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp +++ b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp @@ -64,8 +64,10 @@ enum ExecutionState: int { /// Perform the proper sequence to fetch a byte or word operand. AddressingDispatch(FetchOperand_bw), + /// Perform the proper sequence to fetch a long-word operand. AddressingDispatch(FetchOperand_l), + /// Perform the sequence to calculate an effective address, but don't fetch from it. /// There's a lack of uniformity in the bus programs used by the 68000 for relevant /// instructions; this entry point uses: @@ -76,6 +78,7 @@ enum ExecutionState: int { /// (d16, PC) np (d8, PC, Xn) np n /// (xxx).w np (xxx).l np np AddressingDispatch(CalcEffectiveAddress), + /// Similar to CalcEffectiveAddress, but varies slightly in the patterns: /// /// -(An) n @@ -153,7 +156,6 @@ enum ExecutionState: int { DIVU_DIVS, Perform_idle_dyamic_Dn, LEA, - PEA, TAS, MOVEtoCCRSR, RTR, @@ -169,6 +171,10 @@ enum ExecutionState: int { AddressRegisterIndirectWithIndex8bitDisplacement_n_np, ProgramCounterIndirectWithIndex8bitDisplacement_n_np, + + AddressingDispatch(PEA), + PEA_np_nS_ns, // Used to complete (An), (d16, [An/PC]) and (d8, [An/PC], Xn). + PEA_np_nS_ns_np, // Used to complete (xxx).w and (xxx).l }; #undef AddressingDispatch @@ -961,10 +967,7 @@ void Processor Date: Mon, 13 Jun 2022 15:27:23 -0400 Subject: [PATCH 48/62] Provide more thorough documentation. --- .../Implementation/68000Mk2Implementation.hpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp index 4b207b005..857d4f6e5 100644 --- a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp +++ b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp @@ -63,16 +63,32 @@ enum ExecutionState: int { // up on its feet and profiling becomes an option. /// Perform the proper sequence to fetch a byte or word operand. + /// i.e. + /// + /// Dn/An/Q - (An) nr + /// (An)+ nr -(An) n nr + /// (d16, An) np nr (d8, An, Xn) n np nr + /// (d16, PC) np nr (d8, PC, Xn) n np nr + /// (xxx).w np nr (xxx).l np np nr + /// # np AddressingDispatch(FetchOperand_bw), /// Perform the proper sequence to fetch a long-word operand. + /// i.e. + /// + /// Dn/An/Q - (An) nR nr + /// (An)+ nR nr -(An) n nR nr + /// (d16, An) np nR nr (d8, An, Xn) n np nR nr + /// (d16, PC) np nR nr (d8, PC, Xn) n np nR nr + /// (xxx).w np nR nr (xxx).l np np nR nr + /// # np np AddressingDispatch(FetchOperand_l), /// Perform the sequence to calculate an effective address, but don't fetch from it. /// There's a lack of uniformity in the bus programs used by the 68000 for relevant /// instructions; this entry point uses: /// - /// Dn - An - + /// Dn/An - (An) - /// (An)+ - -(An) - /// (d16, An) np (d8, An, Xn) np n /// (d16, PC) np (d8, PC, Xn) np n From 61e0f60e9465645c6cce1d10e1c4bf1503d186e4 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 13 Jun 2022 21:49:00 -0400 Subject: [PATCH 49/62] Add specialised MOVE.b to correct bus sequencing. This is a bit of a trial balloon; .w and .l to come. --- .../Implementation/68000Mk2Implementation.hpp | 131 +++++++++++++++++- 1 file changed, 130 insertions(+), 1 deletion(-) diff --git a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp index 857d4f6e5..025ad01d7 100644 --- a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp +++ b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp @@ -191,6 +191,8 @@ enum ExecutionState: int { AddressingDispatch(PEA), PEA_np_nS_ns, // Used to complete (An), (d16, [An/PC]) and (d8, [An/PC], Xn). PEA_np_nS_ns_np, // Used to complete (xxx).w and (xxx).l + + AddressingDispatch(MOVE_b), MOVE_b_AbsoluteLong_prefetch_first, }; #undef AddressingDispatch @@ -744,7 +746,7 @@ void Processor Date: Tue, 14 Jun 2022 17:04:11 -0400 Subject: [PATCH 50/62] Extend MOVE.b fix to cover MOVE.w. --- .../Implementation/68000Mk2Implementation.hpp | 81 ++++++++++++------- 1 file changed, 53 insertions(+), 28 deletions(-) diff --git a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp index 025ad01d7..60d3fe521 100644 --- a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp +++ b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp @@ -192,11 +192,17 @@ enum ExecutionState: int { PEA_np_nS_ns, // Used to complete (An), (d16, [An/PC]) and (d8, [An/PC], Xn). PEA_np_nS_ns_np, // Used to complete (xxx).w and (xxx).l - AddressingDispatch(MOVE_b), MOVE_b_AbsoluteLong_prefetch_first, + MOVE_b, MOVE_w, + AddressingDispatch(MOVE_bw), MOVE_bw_AbsoluteLong_prefetch_first, }; #undef AddressingDispatch +/// @returns The proper select lines for @c instruction's operand size, assuming it is either byte or word. +template Microcycle::OperationT data_select(const InstructionT &instruction) { + return Microcycle::OperationT(1 << int(instruction.operand_size())); +} + // MARK: - The state machine. template @@ -748,7 +754,7 @@ void Processor Date: Tue, 14 Jun 2022 21:22:28 -0400 Subject: [PATCH 51/62] At huge copy-and-paste cost, fix MOVE.l. --- .../Implementation/68000Mk2Implementation.hpp | 271 ++++++++++-------- 1 file changed, 156 insertions(+), 115 deletions(-) diff --git a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp index 60d3fe521..1fae61432 100644 --- a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp +++ b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp @@ -110,13 +110,6 @@ enum ExecutionState: int { Perform_np_n, Perform_np_nn, - MOVE, - MOVE_predec, - MOVE_predec_l, - MOVE_prefetch_decode, - MOVE_complete, - MOVE_complete_l, - TwoOp_Predec_bw, TwoOp_Predec_l, @@ -194,6 +187,7 @@ enum ExecutionState: int { MOVE_b, MOVE_w, AddressingDispatch(MOVE_bw), MOVE_bw_AbsoluteLong_prefetch_first, + AddressingDispatch(MOVE_l), MOVE_l_AbsoluteLong_prefetch_first, }; #undef AddressingDispatch @@ -756,7 +750,7 @@ void Processor Date: Tue, 14 Jun 2022 21:56:48 -0400 Subject: [PATCH 52/62] Fix MOVEA. --- .../68000Mk2/Implementation/68000Mk2Implementation.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp index 1fae61432..1acfef412 100644 --- a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp +++ b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp @@ -1118,7 +1118,7 @@ void Processor Date: Tue, 14 Jun 2022 21:57:14 -0400 Subject: [PATCH 53/62] Flip presumption, reenabling most tests. --- .../Mac/Clock SignalTests/68000OldVsNew.mm | 70 +++++++++++-------- 1 file changed, 41 insertions(+), 29 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm index 1665652fd..0fc64a73f 100644 --- a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm +++ b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm @@ -256,32 +256,41 @@ template struct Tester { // Use a fixed seed to guarantee continuity across repeated runs. srand(68000); - std::set test_set = { -// InstructionSet::M68k::Operation::ABCD, // Old implementation doesn't match flamewing tests, sometimes produces incorrect results. -// InstructionSet::M68k::Operation::SBCD, // Old implementation doesn't match flamewing tests, sometimes produces incorrect results. -// InstructionSet::M68k::Operation::MOVEb, -// InstructionSet::M68k::Operation::MOVEw, -// InstructionSet::M68k::Operation::MOVEl, -// InstructionSet::M68k::Operation::MOVEtoSR, // Old implementation doesn't repeat a PC fetch. -// InstructionSet::M68k::Operation::MOVEtoCCR, // Old implementation doesn't repeat a PC fetch. -// InstructionSet::M68k::Operation::CMPAl, // Old implementation omits an idle cycle before -(An) -// InstructionSet::M68k::Operation::JSR, // Old implementation ends up skipping stack space if the destination throws an address error. -// InstructionSet::M68k::Operation::CLRb, // Old implementation omits an idle cycle before -(An) -// InstructionSet::M68k::Operation::CLRw, // Old implementation omits an idle cycle before -(An) -// InstructionSet::M68k::Operation::NEGXb, // Old implementation omits an idle cycle before -(An) -// InstructionSet::M68k::Operation::NEGXw, // Old implementation omits an idle cycle before -(An) -// InstructionSet::M68k::Operation::NEGb, // Old implementation omits an idle cycle before -(An) -// InstructionSet::M68k::Operation::NEGw, // Old implementation omits an idle cycle before -(An) -// InstructionSet::M68k::Operation::NOTb, // Old implementation omits an idle cycle before -(An) -// InstructionSet::M68k::Operation::NOTw, // Old implementation omits an idle cycle before -(An) -// InstructionSet::M68k::Operation::MULU, -// InstructionSet::M68k::Operation::MULS, -// InstructionSet::M68k::Operation::DIVU, -// InstructionSet::M68k::Operation::DIVS, -// InstructionSet::M68k::Operation::TRAP, // Old implementation relocates the idle state near the end to the beginning. -// InstructionSet::M68k::Operation::TRAPV, // Old implementation relocates the idle state near the end to the beginning. -// InstructionSet::M68k::Operation::CHK, // Old implementation pauses four cycles too long. -// InstructionSet::M68k::Operation::TAS, // Old implementation just doesn't match published cycle counts. + std::set ignore_list = { + // + // Operations that do the wrong thing on the old 68000: + // + InstructionSet::M68k::Operation::ABCD, // Old implementation doesn't match flamewing tests, sometimes produces incorrect results. + InstructionSet::M68k::Operation::SBCD, // Old implementation doesn't match flamewing tests, sometimes produces incorrect results. + InstructionSet::M68k::Operation::JSR, // Old implementation ends up skipping stack space if the destination throws an address error. + InstructionSet::M68k::Operation::MOVEtoSR, // Old implementation doesn't repeat a PC fetch. + InstructionSet::M68k::Operation::MOVEtoCCR, // Old implementation doesn't repeat a PC fetch. + + // + // Operations with definite timing deficiencies versus Yacht.txt on the old 68000: + // + InstructionSet::M68k::Operation::CMPAl, // Old implementation omits an idle cycle before -(An) + InstructionSet::M68k::Operation::CLRb, // Old implementation omits an idle cycle before -(An) + InstructionSet::M68k::Operation::CLRw, // Old implementation omits an idle cycle before -(An) + InstructionSet::M68k::Operation::NEGXb, // Old implementation omits an idle cycle before -(An) + InstructionSet::M68k::Operation::NEGXw, // Old implementation omits an idle cycle before -(An) + InstructionSet::M68k::Operation::NEGb, // Old implementation omits an idle cycle before -(An) + InstructionSet::M68k::Operation::NEGw, // Old implementation omits an idle cycle before -(An) + InstructionSet::M68k::Operation::NOTb, // Old implementation omits an idle cycle before -(An) + InstructionSet::M68k::Operation::NOTw, // Old implementation omits an idle cycle before -(An) + InstructionSet::M68k::Operation::TRAP, // Old implementation relocates the idle state near the end to the beginning. + InstructionSet::M68k::Operation::TRAPV, // Old implementation relocates the idle state near the end to the beginning. + InstructionSet::M68k::Operation::CHK, // Old implementation pauses four cycles too long. + InstructionSet::M68k::Operation::TAS, // Old implementation just doesn't match published cycle counts. + + // + // Operations with timing discrepancies between the two 68000 implementations + // that I think are _more_ accurate now, but possibly still need work: + // + InstructionSet::M68k::Operation::MULU, + InstructionSet::M68k::Operation::MULS, + InstructionSet::M68k::Operation::DIVU, + InstructionSet::M68k::Operation::DIVS, }; int testsRun = 0; @@ -298,13 +307,13 @@ template struct Tester { continue; } - // If a whitelist is in place, adhere to it. - if(!test_set.empty() && test_set.find(instruction.operation) == test_set.end()) { + // If this operation is known to diverge, ignore it. It's dealt with. + if(ignore_list.find(instruction.operation) != ignore_list.end()) { continue; } // Test each 1000 times. - for(int test = 0; test < 100; test++) { + for(int test = 0; test < 10; test++) { ++testsRun; // Establish with certainty the initial memory state. @@ -419,6 +428,9 @@ template struct Tester { printf("%d,\n", int(operation)); } } + + // Mark the test as passed or failed. + XCTAssert(failing_operations.empty()); } @end From 6cc41d6dda99612cab536d608f4c330b7b60bb17 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 14 Jun 2022 22:02:53 -0400 Subject: [PATCH 54/62] Restore 1000 test count. --- OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm index 0fc64a73f..3b1efcdef 100644 --- a/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm +++ b/OSBindings/Mac/Clock SignalTests/68000OldVsNew.mm @@ -313,7 +313,7 @@ template struct Tester { } // Test each 1000 times. - for(int test = 0; test < 10; test++) { + for(int test = 0; test < 1000; test++) { ++testsRun; // Establish with certainty the initial memory state. From 93615f6647eeedb05068627daa87bd62af801406 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 15 Jun 2022 10:50:03 -0400 Subject: [PATCH 55/62] Apply new status before entering STOP loop. --- .../Implementation/68000Mk2Implementation.hpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp index 1acfef412..8eb34a825 100644 --- a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp +++ b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp @@ -27,6 +27,7 @@ enum ExecutionState: int { Reset = std::numeric_limits::min(), Decode, WaitForDTACK, + WaitForInterrupt, StoreOperand, StoreOperand_bw, @@ -377,14 +378,20 @@ void Processor Date: Wed, 15 Jun 2022 10:54:14 -0400 Subject: [PATCH 56/62] Fix: new status word is still in prefetch. --- Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp index 8eb34a825..b1222483f 100644 --- a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp +++ b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp @@ -380,7 +380,7 @@ void Processor Date: Wed, 15 Jun 2022 10:56:45 -0400 Subject: [PATCH 57/62] Don't allow STOP state to block execution. --- Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp index b1222483f..7b043d56c 100644 --- a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp +++ b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp @@ -391,6 +391,7 @@ void Processor Date: Wed, 15 Jun 2022 11:00:27 -0400 Subject: [PATCH 58/62] Add spurious interrupt support. --- .../68000Mk2/Implementation/68000Mk2Implementation.hpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp index 7b043d56c..f26df65c8 100644 --- a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp +++ b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp @@ -595,8 +595,12 @@ void Processor Date: Wed, 15 Jun 2022 12:59:03 -0400 Subject: [PATCH 59/62] Disallow copying, add some basic asserts. --- Processors/68000Mk2/68000Mk2.hpp | 2 ++ Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp | 2 ++ Processors/68000Mk2/Implementation/68000Mk2Storage.hpp | 2 ++ 3 files changed, 6 insertions(+) diff --git a/Processors/68000Mk2/68000Mk2.hpp b/Processors/68000Mk2/68000Mk2.hpp index 5defa8eac..b3f4617af 100644 --- a/Processors/68000Mk2/68000Mk2.hpp +++ b/Processors/68000Mk2/68000Mk2.hpp @@ -394,6 +394,8 @@ template = 0 && next_operand_ < 2); if(!(operand_flags_ & (1 << next_operand_))) { MoveToStateDynamic(perform_state_); } @@ -1099,6 +1100,7 @@ void Processor= 0 && next_operand_ < 2); if(!(operand_flags_ & (1 << next_operand_))) { MoveToStateDynamic(perform_state_); } diff --git a/Processors/68000Mk2/Implementation/68000Mk2Storage.hpp b/Processors/68000Mk2/Implementation/68000Mk2Storage.hpp index 243c0c86b..95e0a7662 100644 --- a/Processors/68000Mk2/Implementation/68000Mk2Storage.hpp +++ b/Processors/68000Mk2/Implementation/68000Mk2Storage.hpp @@ -22,6 +22,8 @@ struct ProcessorBase: public InstructionSet::M68k::NullFlowController { ProcessorBase() { read_program_announce.address = read_program.address = &program_counter_.l; } + ProcessorBase(const ProcessorBase& rhs) = delete; + ProcessorBase& operator=(const ProcessorBase& rhs) = delete; int state_ = std::numeric_limits::min(); From 8ff09a1923cebcc76ab13cb2a570f2423cd970d9 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 15 Jun 2022 17:06:40 -0400 Subject: [PATCH 60/62] Fix `value8_high`. --- Processors/68000Mk2/68000Mk2.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Processors/68000Mk2/68000Mk2.hpp b/Processors/68000Mk2/68000Mk2.hpp index b3f4617af..fafba7f79 100644 --- a/Processors/68000Mk2/68000Mk2.hpp +++ b/Processors/68000Mk2/68000Mk2.hpp @@ -233,7 +233,7 @@ struct Microcycle { @c 0xff otherwise. Assumes this is a write cycle. */ forceinline uint8_t value8_high() const { - const uint8_t values[] = { uint8_t(value->w), value->b}; + const uint8_t values[] = { uint8_t(value->w >> 8), value->b}; return values[operation & SelectByte]; } From 12b058867eb7d2c4b68e54aab6104f3d8c8770f5 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 15 Jun 2022 17:06:56 -0400 Subject: [PATCH 61/62] Correct very minor typo. --- Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp index 2134522b2..9eef84cee 100644 --- a/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp +++ b/Processors/68000Mk2/Implementation/68000Mk2Implementation.hpp @@ -1185,7 +1185,7 @@ void Processor Date: Wed, 15 Jun 2022 21:11:31 -0400 Subject: [PATCH 62/62] Fix upper/lower_data_select; simplify value8_low. --- Processors/68000Mk2/68000Mk2.hpp | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/Processors/68000Mk2/68000Mk2.hpp b/Processors/68000Mk2/68000Mk2.hpp index fafba7f79..3e43de1b8 100644 --- a/Processors/68000Mk2/68000Mk2.hpp +++ b/Processors/68000Mk2/68000Mk2.hpp @@ -175,17 +175,17 @@ struct Microcycle { } /*! - @returns non-zero if this is a byte read and 68000 LDS is asserted. + @returns non-zero if the 68000 LDS is asserted; zero otherwise. */ forceinline int lower_data_select() const { - return (operation & SelectByte) & ((*address & 1) << 3); + return ((operation & SelectByte) & (*address & 1)) | (operation & SelectWord); } /*! - @returns non-zero if this is a byte read and 68000 UDS is asserted. + @returns non-zero if the 68000 UDS is asserted; zero otherwise. */ forceinline int upper_data_select() const { - return (operation & SelectByte) & ~((*address & 1) << 3); + return ((operation & SelectByte) & ~(*address & 1)) | (operation & SelectWord); } /*! @@ -229,8 +229,7 @@ struct Microcycle { } /*! - @returns the value currently on the high 8 lines of the data bus if any; - @c 0xff otherwise. Assumes this is a write cycle. + @returns the value currently on the high 8 lines of the data bus. */ forceinline uint8_t value8_high() const { const uint8_t values[] = { uint8_t(value->w >> 8), value->b}; @@ -238,12 +237,10 @@ struct Microcycle { } /*! - @returns the value currently on the low 8 lines of the data bus if any; - @c 0xff otherwise. Assumes this is a write cycle. + @returns the value currently on the low 8 lines of the data bus. */ forceinline uint8_t value8_low() const { - const uint8_t values[] = { uint8_t(value->w), value->b}; - return values[operation & SelectByte]; + return value->b; } /*!