From 923287bf01b0c55a8ede9cc1b24ebadc601c8d7a Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 14 Dec 2019 14:26:33 -0500 Subject: [PATCH] Attempts to introduce a basic means for comparative 68000 testing. i.e. mine versus another source. --- .../Clock Signal.xcodeproj/project.pbxproj | 20 ++- .../xcschemes/Clock Signal.xcscheme | 2 +- .../68000 Comparative Tests/ori.json | 153 ++++++++++++++++++ .../68000ComparativeTests.mm | 139 ++++++++++++++++ 4 files changed, 308 insertions(+), 6 deletions(-) create mode 100644 OSBindings/Mac/Clock SignalTests/68000 Comparative Tests/ori.json create mode 100644 OSBindings/Mac/Clock SignalTests/68000ComparativeTests.mm diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 04af4156d..e1e088a11 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -225,6 +225,8 @@ 4B643F3F1D77B88000D431D6 /* DocumentController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B643F3E1D77B88000D431D6 /* DocumentController.swift */; }; 4B65086022F4CF8D009C1100 /* Keyboard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B65085F22F4CF8D009C1100 /* Keyboard.cpp */; }; 4B65086122F4CFE0009C1100 /* Keyboard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B65085F22F4CF8D009C1100 /* Keyboard.cpp */; }; + 4B680CE223A5553100451D43 /* 68000ComparativeTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B680CE123A5553100451D43 /* 68000ComparativeTests.mm */; }; + 4B680CE423A555CA00451D43 /* 68000 Comparative Tests in Resources */ = {isa = PBXBuildFile; fileRef = 4B680CE323A555CA00451D43 /* 68000 Comparative Tests */; }; 4B69FB3D1C4D908A00B5F0AA /* Tape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B69FB3B1C4D908A00B5F0AA /* Tape.cpp */; }; 4B69FB441C4D941400B5F0AA /* TapeUEF.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B69FB421C4D941400B5F0AA /* TapeUEF.cpp */; }; 4B69FB461C4D950F00B5F0AA /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B69FB451C4D950F00B5F0AA /* libz.tbd */; }; @@ -1009,6 +1011,8 @@ 4B643F3C1D77AE5C00D431D6 /* CSMachine+Target.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "CSMachine+Target.h"; sourceTree = ""; }; 4B643F3E1D77B88000D431D6 /* DocumentController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DocumentController.swift; sourceTree = ""; }; 4B65085F22F4CF8D009C1100 /* Keyboard.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Keyboard.cpp; sourceTree = ""; }; + 4B680CE123A5553100451D43 /* 68000ComparativeTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = 68000ComparativeTests.mm; sourceTree = ""; }; + 4B680CE323A555CA00451D43 /* 68000 Comparative Tests */ = {isa = PBXFileReference; lastKnownFileType = folder; path = "68000 Comparative Tests"; sourceTree = ""; }; 4B698D1A1FE768A100696C91 /* SampleSource.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = SampleSource.hpp; sourceTree = ""; }; 4B69FB3B1C4D908A00B5F0AA /* Tape.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Tape.cpp; sourceTree = ""; }; 4B69FB3C1C4D908A00B5F0AA /* Tape.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Tape.hpp; sourceTree = ""; }; @@ -1793,6 +1797,7 @@ 4B1414631B588A1100E04248 /* Test Binaries */ = { isa = PBXGroup; children = ( + 4B680CE323A555CA00451D43 /* 68000 Comparative Tests */, 4B85322B227793CA00F26553 /* TOS Startup */, 4B9252CD1E74D28200B76AF1 /* Atari ROMs */, 4B44EBF81DC9898E00A7820C /* BCDTEST_beeb */, @@ -3140,17 +3145,18 @@ 4BB73EB51B587A5100552FC2 /* Clock SignalTests */ = { isa = PBXGroup; children = ( - 4BE34437238389E10058E78F /* AtariSTVideoTests.mm */, 4B85322922778E4200F26553 /* Comparative68000.hpp */, 4B90467222C6FA31000E2074 /* TestRunner68000.hpp */, 4B97ADC722C6FD9B00A22A41 /* 68000ArithmeticTests.mm */, 4B9D0C4A22C7D70900DE1AD3 /* 68000BCDTests.mm */, 4B90467322C6FADD000E2074 /* 68000BitwiseTests.mm */, + 4B680CE123A5553100451D43 /* 68000ComparativeTests.mm */, 4B9D0C4C22C7DA1A00DE1AD3 /* 68000ControlFlowTests.mm */, 4BC5C3DF22C994CC00795658 /* 68000MoveTests.mm */, 4B9D0C4E22C7E0CF00DE1AD3 /* 68000RollShiftTests.mm */, 4BD388872239E198002D14B5 /* 68000Tests.mm */, 4B924E981E74D22700B76AF1 /* AtariStaticAnalyserTests.mm */, + 4BE34437238389E10058E78F /* AtariSTVideoTests.mm */, 4BB2A9AE1E13367E001A5C23 /* CRCTests.mm */, 4BFF1D3C2235C3C100838EA1 /* EmuTOSTests.mm */, 4BEE1EBF22B5E236000A26A6 /* MacGCRTests.mm */, @@ -4059,6 +4065,7 @@ 4BB2999A1B587D8400A49093 /* nopn in Resources */, 4BB2996D1B587D8400A49093 /* lasay in Resources */, 4BB299421B587D8400A49093 /* cpyz in Resources */, + 4B680CE423A555CA00451D43 /* 68000 Comparative Tests in Resources */, 4BB299DE1B587D8400A49093 /* stxz in Resources */, 4BB2991C1B587D8400A49093 /* bner in Resources */, 4BB2996B1B587D8400A49093 /* jmpw in Resources */, @@ -4476,6 +4483,7 @@ 4B98A05F1FFAD62400ADF63B /* CSROMFetcher.mm in Sources */, 4BC9E1EE1D23449A003FCEE4 /* 6502InterruptTests.swift in Sources */, 4BEF6AAA1D35CE9E00E73575 /* DigitalPhaseLockedLoopBridge.mm in Sources */, + 4B680CE223A5553100451D43 /* 68000ComparativeTests.mm in Sources */, 4B90467422C6FADD000E2074 /* 68000BitwiseTests.mm in Sources */, 4B924E991E74D22700B76AF1 /* AtariStaticAnalyserTests.mm in Sources */, 4B90467622C6FD6E000E2074 /* 68000ArithmeticTests.mm in Sources */, @@ -4648,7 +4656,7 @@ buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LANGUAGE_STANDARD = "c++17"; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_IDENTITY = "-"; @@ -4668,7 +4676,7 @@ buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LANGUAGE_STANDARD = "c++17"; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_IDENTITY = "-"; @@ -4793,7 +4801,7 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_CXX_LANGUAGE_STANDARD = "c++14"; + CLANG_CXX_LANGUAGE_STANDARD = "c++17"; CLANG_ENABLE_MODULES = YES; CLANG_WARN_ASSIGN_ENUM = YES; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; @@ -4835,7 +4843,7 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_CXX_LANGUAGE_STANDARD = "c++14"; + CLANG_CXX_LANGUAGE_STANDARD = "c++17"; CLANG_ENABLE_MODULES = YES; CLANG_WARN_ASSIGN_ENUM = YES; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; @@ -4878,6 +4886,7 @@ isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; + CLANG_CXX_LANGUAGE_STANDARD = "c++17"; CLANG_ENABLE_MODULES = YES; COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = "Clock SignalTests/Info.plist"; @@ -4895,6 +4904,7 @@ isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; + CLANG_CXX_LANGUAGE_STANDARD = "c++17"; CLANG_ENABLE_MODULES = YES; COMBINE_HIDPI_IMAGES = YES; GCC_OPTIMIZATION_LEVEL = fast; diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme b/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme index 47f9c7286..1465a4f62 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme +++ b/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme @@ -67,7 +67,7 @@ + +#include "../../../Processors/68000/68000.hpp" + +#include +#include + +@interface M68000ComparativeTests : XCTestCase +@end + +@implementation M68000ComparativeTests + +- (void)testAll { + NSBundle *const bundle = [NSBundle bundleForClass:[self class]]; + NSArray *const tests = [bundle URLsForResourcesWithExtension:@"json" subdirectory:@"68000 Comparative Tests"]; + for(NSURL *url in tests) { + [self testJSONAtURL:url]; + } +} + +- (void)testJSONAtURL:(NSURL *)url { + NSData *const data = [NSData dataWithContentsOfURL:url]; + NSError *error; + NSArray *const jsonContents = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error]; + + if(!data || error || ![jsonContents isKindOfClass:[NSArray class]]) { + return; + } + + for(NSDictionary *test in jsonContents) { + if(![test isKindOfClass:[NSDictionary class]]) continue; + [self testOperation:test]; + } +} + +- (void)testOperation:(NSDictionary *)test { + // Only entries with a name are valid. + NSString *const name = test[@"name"]; + if(!name) return; + + // This is the test class for 68000 execution. + struct Test68000: public CPU::MC68000::BusHandler { + std::array ram; + CPU::MC68000::Processor processor; + + Test68000() : processor(*this) { + } + + void will_perform(uint32_t address, uint16_t opcode) { + --instructions_remaining_; + } + + HalfCycles perform_bus_operation(const CPU::MC68000::Microcycle &cycle, int is_supervisor) { + using Microcycle = CPU::MC68000::Microcycle; + if(cycle.data_select_active()) { + cycle.apply(&ram[cycle.host_endian_byte_address()]); + } + return HalfCycles(0); + } + + void run_for_instructions(int instructions) { + instructions_remaining_ = instructions + 1; // i.e. run up to the will_perform of the instruction after. + while(instructions_remaining_) { + processor.run_for(HalfCycles(2)); + } + } + + private: + int instructions_remaining_; + }; + auto test68000 = std::make_unique(); + + // Apply initial memory state. + NSArray *const initialMemory = test[@"initial memory"]; + NSEnumerator *enumerator = [initialMemory objectEnumerator]; + while(true) { + NSNumber *const address = [enumerator nextObject]; + NSNumber *const value = [enumerator nextObject]; + + if(!address || !value) break; + test68000->ram[address.intValue ^ 1] = value.intValue; // Effect a short-resolution endianness swap. + } + + // Apply initial processor state. + NSDictionary *const initialState = test[@"initial state"]; + auto state = test68000->processor.get_state(); + for(int c = 0; c < 8; ++c) { + const NSString *dX = [@"d" stringByAppendingFormat:@"%d", c]; + const NSString *aX = [@"a" stringByAppendingFormat:@"%d", c]; + + state.data[c] = [initialState[dX] intValue]; + if(c < 8) + state.address[c] = [initialState[aX] intValue]; + } + state.supervisor_stack_pointer = [initialState[@"a7"] intValue]; + state.user_stack_pointer = [initialState[@"usp"] intValue]; + state.status = [initialState[@"sr"] intValue]; + test68000->processor.set_state(state); + + // Run the thing. + test68000->run_for_instructions(1); + + // Test the end state. + NSDictionary *const finalState = test[@"final state"]; + state = test68000->processor.get_state(); + for(int c = 0; c < 8; ++c) { + const NSString *dX = [@"d" stringByAppendingFormat:@"%d", c]; + const NSString *aX = [@"a" stringByAppendingFormat:@"%d", c]; + + XCTAssertEqual(state.data[c], [finalState[dX] intValue], @"%@: D%d inconsistent", name, c); + if(c < 8) { + XCTAssertEqual(state.address[c], [finalState[aX] intValue], @"%@: A%d inconsistent", name, c); + } + } + XCTAssertEqual(state.supervisor_stack_pointer, [initialState[@"a7"] intValue], @"%@: A7 inconsistent", name); + XCTAssertEqual(state.user_stack_pointer, [initialState[@"usp"] intValue], @"%@: USP inconsistent", name); + XCTAssertEqual(state.status, [initialState[@"sr"] intValue], @"%@: Status inconsistent", name); + + // Test final memory state. + NSArray *const finalMemory = test[@"final memory"]; + enumerator = [finalMemory objectEnumerator]; + while(true) { + NSNumber *const address = [enumerator nextObject]; + NSNumber *const value = [enumerator nextObject]; + + if(!address || !value) break; + XCTAssertEqual(test68000->ram[address.intValue ^ 1], value.intValue, @"%@: Memory at location %@ inconsistent", name, address); + } +} + +@end