From 1a44ef046940e5ca12b20b3f76baa5e1a8fc5260 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 6 Aug 2018 21:48:43 -0400 Subject: [PATCH] Introduces Klaus Dorman's 65C02 tests. All failing. --- .../Clock Signal.xcodeproj/project.pbxproj | 8 ++- .../6502InterruptTests.swift | 2 +- .../Clock SignalTests/6502TimingTests.swift | 2 +- .../Clock SignalTests/AllSuiteATests.swift | 2 +- .../Mac/Clock SignalTests/BCDTest.swift | 2 +- .../Bridges/TestMachine6502.h | 6 +- .../Bridges/TestMachine6502.mm | 5 +- .../65C02_extended_opcodes_test.bin | Bin 0 -> 65536 bytes .../Clock SignalTests/KlausDormannTests.swift | 66 +++++++++++++----- .../WolfgangLorenzTests.swift | 2 +- .../6502/Implementation/6502Storage.cpp | 8 ++- 11 files changed, 73 insertions(+), 30 deletions(-) create mode 100644 OSBindings/Mac/Clock SignalTests/Klaus Dormann/65C02_extended_opcodes_test.bin diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 1cc8e6880..5a1ab50bb 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 4B018B89211930DE002A3937 /* 65C02_extended_opcodes_test.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4B018B88211930DE002A3937 /* 65C02_extended_opcodes_test.bin */; }; 4B01A6881F22F0DB001FD6E3 /* Z80MemptrTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B01A6871F22F0DB001FD6E3 /* Z80MemptrTests.swift */; }; 4B0333AF2094081A0050B93D /* AppleDSK.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0333AD2094081A0050B93D /* AppleDSK.cpp */; }; 4B0333B02094081A0050B93D /* AppleDSK.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0333AD2094081A0050B93D /* AppleDSK.cpp */; }; @@ -690,6 +691,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 4B018B88211930DE002A3937 /* 65C02_extended_opcodes_test.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; name = 65C02_extended_opcodes_test.bin; path = "Klaus Dormann/65C02_extended_opcodes_test.bin"; sourceTree = ""; }; 4B01A6871F22F0DB001FD6E3 /* Z80MemptrTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Z80MemptrTests.swift; sourceTree = ""; }; 4B0333AD2094081A0050B93D /* AppleDSK.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = AppleDSK.cpp; sourceTree = ""; }; 4B0333AE2094081A0050B93D /* AppleDSK.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = AppleDSK.hpp; sourceTree = ""; }; @@ -1545,14 +1547,15 @@ 4B1414631B588A1100E04248 /* Test Binaries */ = { isa = PBXGroup; children = ( - 4B98A1CD1FFADEC400ADF63B /* MSX ROMs */, 4B9252CD1E74D28200B76AF1 /* Atari ROMs */, 4B44EBF81DC9898E00A7820C /* BCDTEST_beeb */, + 4B98A1CD1FFADEC400ADF63B /* MSX ROMs */, + 4B018B88211930DE002A3937 /* 65C02_extended_opcodes_test.bin */, 4B44EBF61DC9883B00A7820C /* 6502_functional_test.bin */, 4B44EBF41DC987AE00A7820C /* AllSuiteA.bin */, - 4BE9A6B21EDE294200CBCB47 /* Zexall */, 4BBF49B41ED2881600AB3669 /* FUSE */, 4BB297E41B587D8300A49093 /* Wolfgang Lorenz 6502 test suite */, + 4BE9A6B21EDE294200CBCB47 /* Zexall */, ); name = "Test Binaries"; sourceTree = ""; @@ -3330,6 +3333,7 @@ 4BB2998A1B587D8400A49093 /* lseix in Resources */, 4BB2994E1B587D8400A49093 /* dexn in Resources */, 4BB299971B587D8400A49093 /* nopa in Resources */, + 4B018B89211930DE002A3937 /* 65C02_extended_opcodes_test.bin in Resources */, 4BFCA1291ECBE7A700AC40C1 /* zexall.com in Resources */, 4BB299521B587D8400A49093 /* eoray in Resources */, 4BB299411B587D8400A49093 /* cpyb in Resources */, diff --git a/OSBindings/Mac/Clock SignalTests/6502InterruptTests.swift b/OSBindings/Mac/Clock SignalTests/6502InterruptTests.swift index 98c9c6b8c..a6c0def50 100644 --- a/OSBindings/Mac/Clock SignalTests/6502InterruptTests.swift +++ b/OSBindings/Mac/Clock SignalTests/6502InterruptTests.swift @@ -15,7 +15,7 @@ class MOS6502InterruptTests: XCTestCase { super.setUp() // create a machine full of NOPs - machine = CSTestMachine6502() + machine = CSTestMachine6502(is65C02: false) for c in 0...65535 { machine.setValue(0xea, forAddress: UInt16(c)) } diff --git a/OSBindings/Mac/Clock SignalTests/6502TimingTests.swift b/OSBindings/Mac/Clock SignalTests/6502TimingTests.swift index fdccca3a7..514b41413 100644 --- a/OSBindings/Mac/Clock SignalTests/6502TimingTests.swift +++ b/OSBindings/Mac/Clock SignalTests/6502TimingTests.swift @@ -12,7 +12,7 @@ import XCTest class MOS6502TimingTests: XCTestCase, CSTestMachineTrapHandler { private var endTime: UInt32 = 0 - private let machine = CSTestMachine6502() + private let machine = CSTestMachine6502(is65C02: false) func testImplied() { let code: [UInt8] = [ diff --git a/OSBindings/Mac/Clock SignalTests/AllSuiteATests.swift b/OSBindings/Mac/Clock SignalTests/AllSuiteATests.swift index 2aa7f992a..5c0a13607 100644 --- a/OSBindings/Mac/Clock SignalTests/AllSuiteATests.swift +++ b/OSBindings/Mac/Clock SignalTests/AllSuiteATests.swift @@ -13,7 +13,7 @@ class AllSuiteATests: XCTestCase { func testAllSuiteA() { if let filename = Bundle(for: type(of: self)).path(forResource: "AllSuiteA", ofType: "bin") { if let allSuiteA = try? Data(contentsOf: URL(fileURLWithPath: filename)) { - let machine = CSTestMachine6502() + let machine = CSTestMachine6502(is65C02: false) machine.setData(allSuiteA, atAddress: 0x4000) machine.setValue(CSTestMachine6502JamOpcode, forAddress:0x45c0); // end diff --git a/OSBindings/Mac/Clock SignalTests/BCDTest.swift b/OSBindings/Mac/Clock SignalTests/BCDTest.swift index 7dbcfa435..6eb9850b0 100644 --- a/OSBindings/Mac/Clock SignalTests/BCDTest.swift +++ b/OSBindings/Mac/Clock SignalTests/BCDTest.swift @@ -14,7 +14,7 @@ class BCDTest: XCTestCase, CSTestMachineTrapHandler { func testBCD() { if let filename = Bundle(for: type(of: self)).path(forResource: "BCDTEST_beeb", ofType: nil) { if let bcdTest = try? Data(contentsOf: URL(fileURLWithPath: filename)) { - let machine = CSTestMachine6502() + let machine = CSTestMachine6502(is65C02: false) machine.trapHandler = self machine.setData(bcdTest, atAddress: 0x2900) diff --git a/OSBindings/Mac/Clock SignalTests/Bridges/TestMachine6502.h b/OSBindings/Mac/Clock SignalTests/Bridges/TestMachine6502.h index 5d78b5306..59b5f0aed 100644 --- a/OSBindings/Mac/Clock SignalTests/Bridges/TestMachine6502.h +++ b/OSBindings/Mac/Clock SignalTests/Bridges/TestMachine6502.h @@ -23,7 +23,11 @@ extern const uint8_t CSTestMachine6502JamOpcode; @interface CSTestMachine6502 : CSTestMachine -- (void)setData:(NSData *)data atAddress:(uint16_t)startAddress; +- (nonnull instancetype)init NS_UNAVAILABLE; + +- (nonnull instancetype)initIs65C02:(BOOL)is65C02; + +- (void)setData:(nonnull NSData *)data atAddress:(uint16_t)startAddress; - (void)runForNumberOfCycles:(int)cycles; - (void)setValue:(uint8_t)value forAddress:(uint16_t)address; diff --git a/OSBindings/Mac/Clock SignalTests/Bridges/TestMachine6502.mm b/OSBindings/Mac/Clock SignalTests/Bridges/TestMachine6502.mm index 7477a0370..d5a7787e9 100644 --- a/OSBindings/Mac/Clock SignalTests/Bridges/TestMachine6502.mm +++ b/OSBindings/Mac/Clock SignalTests/Bridges/TestMachine6502.mm @@ -35,11 +35,12 @@ static CPU::MOS6502::Register registerForRegister(CSTestMachine6502Register reg) #pragma mark - Lifecycle -- (instancetype)init { +- (instancetype)initIs65C02:(BOOL)is65C02 { self = [super init]; if(self) { - _processor = CPU::MOS6502::AllRAMProcessor::Processor(CPU::MOS6502::Personality::P6502); + _processor = CPU::MOS6502::AllRAMProcessor::Processor( + is65C02 ? CPU::MOS6502::Personality::P65C02 : CPU::MOS6502::Personality::P6502); } return self; diff --git a/OSBindings/Mac/Clock SignalTests/Klaus Dormann/65C02_extended_opcodes_test.bin b/OSBindings/Mac/Clock SignalTests/Klaus Dormann/65C02_extended_opcodes_test.bin new file mode 100644 index 0000000000000000000000000000000000000000..b1ea946a1767f9b453325cf02df0bbbaba0cbf1e GIT binary patch literal 65536 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 UInt16 { + if let filename = Bundle(for: type(of: self)).path(forResource: resource, ofType: "bin") { + if let functionalTest = try? Data(contentsOf: URL(fileURLWithPath: filename)) { + let machine = CSTestMachine6502(is65C02: is65C02) + machine.setData(functionalTest, atAddress: 0) + machine.setValue(0x400, for: .programCounter) + + while true { + let oldPC = machine.value(for: .lastOperationAddress) + machine.runForNumber(ofCycles: 1000) + let newPC = machine.value(for: .lastOperationAddress) + + if newPC == oldPC { + return newPC + } + } + } + } + + return 0 + } + + /// Runs Klaus Dorman's 6502 tests. + func test6502() { func errorForTrapAddress(_ address: UInt16) -> String? { - let hexAddress = String(format:"%04x", address) switch address { case 0x3399: return nil // success! @@ -28,29 +50,35 @@ class KlausDormannTests: XCTestCase { case 0x26d2: return "ASL zpg,x produced incorrect flags" case 0x36c6: return "Unexpected RESET" - default: return "Unknown error at \(hexAddress)" + case 0: return "Didn't find tests" + + default: return "Unknown error at \(String(format:"%04x", address))" } } - if let filename = Bundle(for: type(of: self)).path(forResource: "6502_functional_test", ofType: "bin") { - if let functionalTest = try? Data(contentsOf: URL(fileURLWithPath: filename)) { - let machine = CSTestMachine6502() + let destination = runTest(resource: "6502_functional_test", is65C02: false) + let error = errorForTrapAddress(destination) + XCTAssert(error == nil, "Failed with error \(error!)") + } - machine.setData(functionalTest, atAddress: 0) - machine.setValue(0x400, for: .programCounter) + /// Runs Klaus Dorman's 65C02 tests. + func test65C02() { + func errorForTrapAddress(_ address: UInt16) -> String? { + switch address { + case 0x0423: return "PHX: value of X not on stack page" + case 0x0428: return "PHX: stack pointer not decremented" + case 0x042d: return "PLY: didn't acquire value 0xaa from stack" + case 0x0432: return "PLY: didn't acquire value 0x55 from stack" + case 0x0437: return "PLY: stack pointer not incremented" + case 0x043c: return "PLY: stack pointer not incremented" - while true { - let oldPC = machine.value(for: .lastOperationAddress) - machine.runForNumber(ofCycles: 1000) - let newPC = machine.value(for: .lastOperationAddress) - - if newPC == oldPC { - let error = errorForTrapAddress(oldPC) - XCTAssert(error == nil, "Failed with error \(error!)") - return - } - } + case 0: return "Didn't find tests" + default: return "Unknown error at \(String(format:"%04x", address))" } } + + let destination = runTest(resource: "65C02_extended_opcodes_test", is65C02: true) + let error = errorForTrapAddress(destination) + XCTAssert(error == nil, "Failed with error \(error!)") } } diff --git a/OSBindings/Mac/Clock SignalTests/WolfgangLorenzTests.swift b/OSBindings/Mac/Clock SignalTests/WolfgangLorenzTests.swift index 9f0660853..4ec9be87b 100644 --- a/OSBindings/Mac/Clock SignalTests/WolfgangLorenzTests.swift +++ b/OSBindings/Mac/Clock SignalTests/WolfgangLorenzTests.swift @@ -200,7 +200,7 @@ class WolfgangLorenzTests: XCTestCase, CSTestMachineTrapHandler { if let filename = Bundle(for: type(of: self)).path(forResource: name, ofType: nil) { if let testData = try? Data(contentsOf: URL(fileURLWithPath: filename)) { - machine = CSTestMachine6502() + machine = CSTestMachine6502(is65C02: false) machine.trapHandler = self // machine.logActivity = true output = "" diff --git a/Processors/6502/Implementation/6502Storage.cpp b/Processors/6502/Implementation/6502Storage.cpp index c6a916b22..6dd33f569 100644 --- a/Processors/6502/Implementation/6502Storage.cpp +++ b/Processors/6502/Implementation/6502Storage.cpp @@ -69,7 +69,7 @@ using namespace CPU::MOS6502; #define JAM {CycleFetchOperand, CycleScheduleJam} -ProcessorStorage::ProcessorStorage(Personality) { +ProcessorStorage::ProcessorStorage(Personality personality) { // only the interrupt flag is defined upon reset but get_flags isn't going to // mask the other flags so we need to do that, at least carry_flag_ &= Flag::Carry; @@ -214,7 +214,13 @@ ProcessorStorage::ProcessorStorage(Personality) { /* 0xfe INC abs, x */ AbsoluteXReadModifyWrite(OperationINC), /* 0xff INS abs, x */ AbsoluteXReadModifyWrite(OperationINS), }; + // Install the basic 6502 table. memcpy(operations_, operations_6502, sizeof(operations_)); + + // Patch the table according to the chip's personality. + switch(personality) { + default: break; + } } #undef Program