From 426e90eebff1f45fcd700d435300d86ad230ae89 Mon Sep 17 00:00:00 2001
From: Thomas Harte <thomas.harte@gmail.com>
Date: Tue, 3 Nov 2020 14:18:40 -0500
Subject: [PATCH] Adds logic to work around Nintendo dependence in the krom
 tests.

Let the real work begin!
---
 .../Clock SignalTests/65816kromTests.swift    | 114 +++++++++++++-----
 1 file changed, 81 insertions(+), 33 deletions(-)

diff --git a/OSBindings/Mac/Clock SignalTests/65816kromTests.swift b/OSBindings/Mac/Clock SignalTests/65816kromTests.swift
index 53408eb48..62a3af6f5 100644
--- a/OSBindings/Mac/Clock SignalTests/65816kromTests.swift	
+++ b/OSBindings/Mac/Clock SignalTests/65816kromTests.swift	
@@ -52,55 +52,103 @@ class Krom65816Tests: XCTestCase {
 		machine.setValue(0x00ff, for: .stackPointer)
 		machine.setValue(0x34, for: .flags)
 
+		// Poke some fixed values for SNES registers to get past initial setup.
+		machine.setValue(0x42, forAddress: 0x4210)	// "RDNMI", apparently; this says: CPU version 2, vblank interrupt request.
+		var allowNegativeError = false
+
 		var lineNumber = 1
+		var previousPC = 0
 		for line in outputLines {
 			machine.runForNumber(ofInstructions: 1)
 
-			// Formulate my 65816 state in the same form as the test machine
-			var cpuState = ""
-			let emulationFlag = machine.value(for: .emulationFlag) != 0
-			cpuState += String(format: "%06x ", machine.value(for: .lastOperationAddress))
-			cpuState += String(format: "A:%04x ", machine.value(for: .A))
-			cpuState += String(format: "X:%04x ", machine.value(for: .X))
-			cpuState += String(format: "Y:%04x ", machine.value(for: .Y))
-			if emulationFlag {
-				cpuState += String(format: "S:01%02x ", machine.value(for: .stackPointer))
-			} else {
-				cpuState += String(format: "S:%04x ", machine.value(for: .stackPointer))
+			func machineState() -> String {
+				// Formulate my 65816 state in the same form as the test machine
+				var cpuState = ""
+				let emulationFlag = machine.value(for: .emulationFlag) != 0
+				cpuState += String(format: "%06x ", machine.value(for: .lastOperationAddress))
+				cpuState += String(format: "A:%04x ", machine.value(for: .A))
+				cpuState += String(format: "X:%04x ", machine.value(for: .X))
+				cpuState += String(format: "Y:%04x ", machine.value(for: .Y))
+				if emulationFlag {
+					cpuState += String(format: "S:01%02x ", machine.value(for: .stackPointer))
+				} else {
+					cpuState += String(format: "S:%04x ", machine.value(for: .stackPointer))
+				}
+				cpuState += String(format: "D:%04x ", machine.value(for: .direct))
+				cpuState += String(format: "DB:%02x ", machine.value(for: .dataBank))
+
+				let flags = machine.value(for: .flags)
+				cpuState += (flags & 0x80) != 0 ? "N" : "n"
+				cpuState += (flags & 0x40) != 0 ? "V" : "v"
+				if emulationFlag {
+					cpuState += "1B"
+				} else {
+					cpuState += (flags & 0x20) != 0 ? "M" : "m"
+					cpuState += (flags & 0x10) != 0 ? "X" : "x"
+				}
+				cpuState += (flags & 0x08) != 0 ? "D" : "d"
+				cpuState += (flags & 0x04) != 0 ? "I" : "i"
+				cpuState += (flags & 0x02) != 0 ? "Z" : "z"
+				cpuState += (flags & 0x01) != 0 ? "C" : "c"
+
+				cpuState += " "
+
+				return cpuState
 			}
-			cpuState += String(format: "D:%04x ", machine.value(for: .direct))
-			cpuState += String(format: "DB:%02x ", machine.value(for: .dataBank))
 
-			let flags = machine.value(for: .flags)
-			cpuState += (flags & 0x80) != 0 ? "N" : "n"
-			cpuState += (flags & 0x40) != 0 ? "V" : "v"
-			if emulationFlag {
-				// These logs seem always to have the break flag set (?)
-				cpuState += (flags & 0x20) != 0 ? "1" : "?"
-				cpuState += "B" 	//(flags & 0x10) != 0 ? "B" : "b"
-			} else {
-				cpuState += (flags & 0x20) != 0 ? "M" : "m"
-				cpuState += (flags & 0x10) != 0 ? "X" : "x"
+			// Permit a fix-up of the negative flag only if this line followed a test of $4210.
+			var cpuState = machineState()
+			if cpuState != line && allowNegativeError {
+				machine.setValue(machine.value(for: .flags) ^ 0x80, for: .flags)
+				cpuState = machineState()
 			}
-			cpuState += (flags & 0x08) != 0 ? "D" : "d"
-			cpuState += (flags & 0x04) != 0 ? "I" : "i"
-			cpuState += (flags & 0x02) != 0 ? "Z" : "z"
-			cpuState += (flags & 0x01) != 0 ? "C" : "c"
 
-			cpuState += " "
-
-			XCTAssertEqual(cpuState, line, "Mismatch on line #\(lineNumber)")
+			XCTAssertEqual(cpuState, line, "Mismatch on line #\(lineNumber); after instruction #\(String(format:"%02x", machine.value(forAddress: UInt32(previousPC))))")
 			if cpuState != line {
 				break
 			}
 			lineNumber += 1
+			previousPC = Int(machine.value(for: .lastOperationAddress))
+
+			// Check whether a 'RDNMI' toggle needs to happen by peeking at the next instruction;
+			// if it's BIT $4210 then toggle the top bit at address $4210.
+			//
+			// Coupling here: assume that by the time the test 65816 is aware it's on a new instruction
+			// it's because the actual 65816 has read a new opcode, and that if the 65816 has just read
+			// a new opcode then it has already advanced the program counter.
+			let programCounter = machine.value(for: .programCounter)
+			let nextInstr = [
+				machine.value(forAddress: UInt32(programCounter - 1)),
+				machine.value(forAddress: UInt32(programCounter + 0)),
+				machine.value(forAddress: UInt32(programCounter + 1))
+			]
+			allowNegativeError = nextInstr[0] == 0x2c && nextInstr[1] == 0x10 && nextInstr[2] == 0x42
 		}
 	}
 
 	// MARK: - Tests
 
-	func testADC() {
-		runTest("CPUADC")
-	}
+	func testADC() {	runTest("CPUADC")	}
+	func testAND() {	runTest("CPUAND")	}
+	func testASL() {	runTest("CPUASL")	}
+	func testBIT() {	runTest("CPUBIT")	}
+	func testBRA() {	runTest("CPUBRA")	}
+	func testCMP() {	runTest("CPUCMP")	}
+	func testDEC() {	runTest("CPUDEC")	}
+	func testEOR() {	runTest("CPUEOR")	}
+	func testINC() {	runTest("CPUINC")	}
+	func testJMP() {	runTest("CPUJMP")	}
+	func testLDR() {	runTest("CPULDR")	}
+	func testLSR() {	runTest("CPULSR")	}
+	func testMOV() {	runTest("CPUMOV")	}
+	func testMSC() {	runTest("CPUMSC")	}
+	func testORA() {	runTest("CPUORA")	}
+	func testPHL() {	runTest("CPUPHL")	}
+	func testPSR() {	runTest("CPUPSR")	}
+	func testROL() {	runTest("CPUROL")	}
+	func testROR() {	runTest("CPUROR")	}
+	func testSBC() {	runTest("CPUSBC")	}
+	func testSTR() {	runTest("CPUSTR")	}
+	func testTRN() {	runTest("CPUTRN")	}
 
 }