// // ZexallTests.swift // Clock Signal // // Created by Thomas Harte on 16/05/2017. // Copyright 2017 Thomas Harte. All rights reserved. // import XCTest import Foundation class ZexallTests: XCTestCase, CSTestMachineTrapHandler { fileprivate var done = false fileprivate var output = "" private func runTest(_ name: String) { if let filename = Bundle(for: type(of: self)).path(forResource: name, ofType: "com") { if let testData = try? Data(contentsOf: URL(fileURLWithPath: filename)) { // install test program, at the usual CP/M place let machine = CSTestMachineZ80() machine.setData(testData, atAddress: 0x0100) // add a RET at the CP/M entry location, and establish it as a trap location machine.setValue(0xc9, atAddress: 0x0005) machine.setValue(0xff, atAddress: 0x0006) machine.setValue(0xff, atAddress: 0x0007) machine.addTrapAddress(0x0005); machine.trapHandler = self // establish 0 as another trap location, as RST 0h is one of the ways that // CP/M programs can exit machine.addTrapAddress(0); // ensure that if the CPU hits zero, it stays there until the end of the // sampling window machine.setValue(0xc3, atAddress: 0x0000) machine.setValue(0x00, atAddress: 0x0001) machine.setValue(0x00, atAddress: 0x0002) // seed execution at 0x0100 machine.setValue(0x0100, for: .programCounter) // run! let cyclesPerIteration: Int32 = 400_000_000 var cyclesToDate: TimeInterval = 0 let startDate = Date() var printDate = Date() let printMhz = false while !done { machine.runForNumber(ofCycles: cyclesPerIteration) cyclesToDate += TimeInterval(cyclesPerIteration) if printMhz && printDate.timeIntervalSinceNow < -5.0 { print("\(cyclesToDate / -startDate.timeIntervalSinceNow) Mhz") printDate = Date() } } let targetOutput = " hl,.... OK\n\r" + "add hl,.......... OK\n\r" + "add ix,.......... OK\n\r" + "add iy,.......... OK\n\r" + "aluop a,nn.................... OK\n\r" + "aluop a,.. OK\n\r" + "aluop a,..... OK\n\r" + "aluop a,(+1)........... OK\n\r" + "bit n,(+1)............. OK\n\r" + "bit n,.... OK\n\r" + "cpd........................ OK\n\r" + "cpi........................ OK\n\r" + "............. OK\n\r" + " a................... OK\n\r" + " b................... OK\n\r" + " bc.................. OK\n\r" + " c................... OK\n\r" + " d................... OK\n\r" + " de.................. OK\n\r" + " e................... OK\n\r" + " h................... OK\n\r" + " hl.................. OK\n\r" + " ix.................. OK\n\r" + " iy.................. OK\n\r" + " l................... OK\n\r" + " (hl)................ OK\n\r" + " sp.................. OK\n\r" + " (+1)......... OK\n\r" + " ixh................. OK\n\r" + " ixl................. OK\n\r" + " iyh................. OK\n\r" + " iyl................. OK\n\r" + "ld ,(nnnn)............. OK\n\r" + "ld hl,(nnnn).................. OK\n\r" + "ld sp,(nnnn).................. OK\n\r" + "ld ,(nnnn)............. OK\n\r" + "ld (nnnn),............. OK\n\r" + "ld (nnnn),hl.................. OK\n\r" + "ld (nnnn),sp.................. OK\n\r" + "ld (nnnn),............. OK\n\r" + "ld ,nnnn......... OK\n\r" + "ld ,nnnn............... OK\n\r" + "ld a,<(bc),(de)>.............. OK\n\r" + "ld ,nn.... OK\n\r" + "ld (+1),nn............. OK\n\r" + "ld ,(+1)...... OK\n\r" + "ld ,(+1).......... OK\n\r" + "ld a,(+1).............. OK\n\r" + "ld ,nn....... OK\n\r" + "ld ,........ OK\n\r" + "ld ,........ OK\n\r" + "ld a,(nnnn) / ld (nnnn),a..... OK\n\r" + "ldd (1).................... OK\n\r" + "ldd (2).................... OK\n\r" + "ldi (1).................... OK\n\r" + "ldi (2).................... OK\n\r" + "neg........................... OK\n\r" + "..................... OK\n\r" + "........... OK\n\r" + "shf/rot (+1)........... OK\n\r" + "shf/rot .. OK\n\r" + " n,..... OK\n\r" + " n,(+1)....... OK\n\r" + "ld (+1),...... OK\n\r" + "ld (+1),.......... OK\n\r" + "ld (+1),a.............. OK\n\r" + "ld (),a................ OK\n\r" + "Tests complete\n\r" let successRange = output.range(of: targetOutput) XCTAssertNotEqual(successRange, nil, output); } } } func testZexAll() { runTest("zexall") } func testZexDoc() { runTest("zexdoc") } func testMachine(_ testMachine: CSTestMachine, didTrapAtAddress address: UInt16) { let testMachineZ80 = testMachine as! CSTestMachineZ80 switch address { case 0x0005: let cRegister = testMachineZ80.value(for: .C) var textToAppend = "" switch cRegister { case 9: var address = testMachineZ80.value(for: .DE) var character: Character = " " while true { character = Character(UnicodeScalar(testMachineZ80.value(atAddress: address))) if character == "$" { break } textToAppend += String(character) address = address + 1 } case 5: textToAppend = String(describing: UnicodeScalar(testMachineZ80.value(for: .E))) case 0: done = true default: break } output += textToAppend print(textToAppend) case 0x0000: done = true default: break } } }