From ac374248782814606643e369abed850a60ac6985 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 15 Jun 2017 19:06:59 -0400 Subject: [PATCH 01/55] Set up a test class to allow me to discover which of the machine cycle sequences I'm in error on. --- .../Clock Signal.xcodeproj/project.pbxproj | 4 ++ .../Z80MachineCycleTests.swift | 57 +++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index a45c8b1d3..30bd9550c 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -411,6 +411,7 @@ 4BD4A8D01E077FD20020D856 /* PCMTrackTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4BD4A8CF1E077FD20020D856 /* PCMTrackTests.mm */; }; 4BD5F1951D13528900631CD1 /* CSBestEffortUpdater.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BD5F1941D13528900631CD1 /* CSBestEffortUpdater.m */; }; 4BD69F941D98760000243FE1 /* AcornADF.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BD69F921D98760000243FE1 /* AcornADF.cpp */; }; + 4BDDBA991EF3451200347E61 /* Z80MachineCycleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BDDBA981EF3451200347E61 /* Z80MachineCycleTests.swift */; }; 4BE77A2E1D84ADFB00BC3827 /* File.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BE77A2C1D84ADFB00BC3827 /* File.cpp */; }; 4BE7C9181E3D397100A5496D /* TIA.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BE7C9161E3D397100A5496D /* TIA.cpp */; }; 4BE9A6B11EDE293000CBCB47 /* zexdoc.com in Resources */ = {isa = PBXBuildFile; fileRef = 4BE9A6B01EDE293000CBCB47 /* zexdoc.com */; }; @@ -969,6 +970,7 @@ 4BD5F1941D13528900631CD1 /* CSBestEffortUpdater.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CSBestEffortUpdater.m; path = Updater/CSBestEffortUpdater.m; sourceTree = ""; }; 4BD69F921D98760000243FE1 /* AcornADF.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AcornADF.cpp; sourceTree = ""; }; 4BD69F931D98760000243FE1 /* AcornADF.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = AcornADF.hpp; sourceTree = ""; }; + 4BDDBA981EF3451200347E61 /* Z80MachineCycleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Z80MachineCycleTests.swift; sourceTree = ""; }; 4BE77A2C1D84ADFB00BC3827 /* File.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = File.cpp; path = ../../StaticAnalyser/Commodore/File.cpp; sourceTree = ""; }; 4BE77A2D1D84ADFB00BC3827 /* File.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = File.hpp; path = ../../StaticAnalyser/Commodore/File.hpp; sourceTree = ""; }; 4BE7C9161E3D397100A5496D /* TIA.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TIA.cpp; sourceTree = ""; }; @@ -1856,6 +1858,7 @@ 4B1414611B58888700E04248 /* KlausDormannTests.swift */, 4B14145F1B58885000E04248 /* WolfgangLorenzTests.swift */, 4B08A2741EE35D56008B7065 /* Z80InterruptTests.swift */, + 4BDDBA981EF3451200347E61 /* Z80MachineCycleTests.swift */, 4BFCA12A1ECBE7C400AC40C1 /* ZexallTests.swift */, 4B3BA0C41D318B44005DD7A7 /* Bridges */, 4B1414631B588A1100E04248 /* Test Binaries */, @@ -2666,6 +2669,7 @@ 4B14145E1B5887AA00E04248 /* 6502AllRAM.cpp in Sources */, 4B14145D1B5887A600E04248 /* 6502.cpp in Sources */, 4B1E85811D176468001EF87D /* 6532Tests.swift in Sources */, + 4BDDBA991EF3451200347E61 /* Z80MachineCycleTests.swift in Sources */, 4BC9E1EE1D23449A003FCEE4 /* 6502InterruptTests.swift in Sources */, 4BEF6AAA1D35CE9E00E73575 /* DigitalPhaseLockedLoopBridge.mm in Sources */, 4B924E991E74D22700B76AF1 /* AtariStaticAnalyserTests.mm in Sources */, diff --git a/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift b/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift new file mode 100644 index 000000000..0bd51f256 --- /dev/null +++ b/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift @@ -0,0 +1,57 @@ +// +// Z80MachineCycleTests.swift +// Clock Signal +// +// Created by Thomas Harte on 15/06/2017. +// Copyright © 2017 Thomas Harte. All rights reserved. +// + +import XCTest + +class Z80MachineCycleTests: XCTestCase { + + struct MachineCycle { + var operation: CSTestMachineZ80BusOperationCaptureOperation + var length: Int32 + } + + func test(program : Array, busCycles : [MachineCycle]) { + // Create a machine and install the supplied program at address 0, setting the PC to run from there + let machine = CSTestMachineZ80() + machine.setValue(0x0000, for: .programCounter) + machine.setData(Data(bytes: program), atAddress: 0x0000) + + // Figure out the total number of cycles implied by the bus cycles + var totalCycles: Int32 = 0 + for cycle in busCycles { + totalCycles += Int32(cycle.length) + } + + // Run the machine, capturing bus activity + machine.captureBusActivity = true + machine.runForNumber(ofCycles: totalCycles) + + // Check the results + totalCycles = 0 + var index = 0 + for cycle in machine.busOperationCaptures { + let length = cycle.timeStamp - totalCycles + totalCycles += length + + XCTAssertEqual(length, busCycles[index].length) + XCTAssertEqual(cycle.operation, busCycles[index].operation) + + index += 1 + } + } + + func testLDrs() { + test( + program: [0x40], + busCycles: [ + MachineCycle(operation: .read, length: 4) + ] + ) + } + +} From cf795562bf400dae816943ff35076d0b69d75d84 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 15 Jun 2017 20:59:59 -0400 Subject: [PATCH 02/55] Continued filling in tests, fleshing out what the test machine captures as a result. --- .../Bridges/TestMachineZ80.h | 2 + .../Bridges/TestMachineZ80.mm | 9 +- .../Mac/Clock SignalTests/FUSETests.swift | 10 +- .../Z80MachineCycleTests.swift | 149 +++++++++++++++++- 4 files changed, 165 insertions(+), 5 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.h b/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.h index cbb1a9c60..55f6fdcd7 100644 --- a/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.h +++ b/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.h @@ -13,10 +13,12 @@ @class CSTestMachineZ80; typedef NS_ENUM(NSInteger, CSTestMachineZ80BusOperationCaptureOperation) { + CSTestMachineZ80BusOperationCaptureOperationReadOpcode, CSTestMachineZ80BusOperationCaptureOperationRead, CSTestMachineZ80BusOperationCaptureOperationWrite, CSTestMachineZ80BusOperationCaptureOperationPortRead, CSTestMachineZ80BusOperationCaptureOperationPortWrite, + CSTestMachineZ80BusOperationCaptureOperationInternalOperation, }; @interface CSTestMachineZ80BusOperationCapture: NSObject diff --git a/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.mm b/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.mm index 9284c6917..e0b44acf0 100644 --- a/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.mm +++ b/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.mm @@ -199,10 +199,13 @@ static CPU::Z80::Register registerForRegister(CSTestMachineZ80Register reg) { break; case CPU::Z80::BusOperation::Read: - case CPU::Z80::BusOperation::ReadOpcode: capture.operation = CSTestMachineZ80BusOperationCaptureOperationRead; break; + case CPU::Z80::BusOperation::ReadOpcode: + capture.operation = CSTestMachineZ80BusOperationCaptureOperationReadOpcode; + break; + case CPU::Z80::BusOperation::Input: capture.operation = CSTestMachineZ80BusOperationCaptureOperationPortRead; break; @@ -211,6 +214,10 @@ static CPU::Z80::Register registerForRegister(CSTestMachineZ80Register reg) { capture.operation = CSTestMachineZ80BusOperationCaptureOperationPortWrite; break; + case CPU::Z80::BusOperation::Internal: + capture.operation = CSTestMachineZ80BusOperationCaptureOperationInternalOperation; + break; + default: return; } diff --git a/OSBindings/Mac/Clock SignalTests/FUSETests.swift b/OSBindings/Mac/Clock SignalTests/FUSETests.swift index 3f2d0e26b..4a54c33fb 100644 --- a/OSBindings/Mac/Clock SignalTests/FUSETests.swift +++ b/OSBindings/Mac/Clock SignalTests/FUSETests.swift @@ -246,19 +246,24 @@ class FUSETests: XCTestCase { // it counts a port access as occurring on the second. timeOffset is used to adjust // the FUSE numbers as required. var operation: CSTestMachineZ80BusOperationCaptureOperation = .read + var alternativeOperation: CSTestMachineZ80BusOperationCaptureOperation = .read var timeOffset: Int32 = 0 switch type { case "MR": operation = .read + alternativeOperation = .readOpcode case "MW": + alternativeOperation = .write operation = .write case "PR": + alternativeOperation = .portRead operation = .portRead timeOffset = 3 case "PW": + alternativeOperation = .portWrite operation = .portWrite timeOffset = 3 @@ -270,7 +275,10 @@ class FUSETests: XCTestCase { capturedBusActivity[capturedBusAcivityIndex].address == address && capturedBusActivity[capturedBusAcivityIndex].value == value! && capturedBusActivity[capturedBusAcivityIndex].timeStamp == (time + timeOffset) && - capturedBusActivity[capturedBusAcivityIndex].operation == operation, + ( + capturedBusActivity[capturedBusAcivityIndex].operation == operation || + capturedBusActivity[capturedBusAcivityIndex].operation == alternativeOperation + ), "Failed bus operation match \(name) (at time \(time) with address \(address), value was \(value != nil ? value! : 0), tracking index \(capturedBusAcivityIndex) amongst \(capturedBusActivity))") capturedBusAcivityIndex += 1 } diff --git a/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift b/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift index 0bd51f256..58aa2e9a0 100644 --- a/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift +++ b/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift @@ -10,12 +10,12 @@ import XCTest class Z80MachineCycleTests: XCTestCase { - struct MachineCycle { + private struct MachineCycle { var operation: CSTestMachineZ80BusOperationCaptureOperation var length: Int32 } - func test(program : Array, busCycles : [MachineCycle]) { + private func test(program : [UInt8], busCycles : [MachineCycle]) { // Create a machine and install the supplied program at address 0, setting the PC to run from there let machine = CSTestMachineZ80() machine.setValue(0x0000, for: .programCounter) @@ -45,13 +45,156 @@ class Z80MachineCycleTests: XCTestCase { } } + // LD r, r func testLDrs() { test( program: [0x40], busCycles: [ - MachineCycle(operation: .read, length: 4) + MachineCycle(operation: .readOpcode, length: 4) ] ) } + // LD r, nn + func testLDrn() { + test( + program: [0x3e, 0x00], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + ] + ) + } + + // LD r, (HL) + func testLDrHL() { + test( + program: [0x46], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + ] + ) + } + + // LD (HL), r + func testLDHLr() { + test( + program: [0x70], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .write, length: 3), + ] + ) + } + + // LD r, (IX+d) + func testLDrIXd() { + test( + program: [0xdd, 0x7e, 0x10], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .internalOperation, length: 5), + MachineCycle(operation: .read, length: 3), + ] + ) + } + + // LD (IX+d), r + func testLDIXdr() { + test( + program: [0xdd, 0x70, 0x10], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .internalOperation, length: 5), + MachineCycle(operation: .write, length: 3), + ] + ) + } + + // LD (HL), n + func testLDHLn() { + test( + program: [0x36, 0x10], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .write, length: 3), + ] + ) + } + + // LD A, (DE) + func testLDADE() { + test( + program: [0x1a], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + ] + ) + } + + // LD (DE), A + func testLDDEA() { + test( + program: [0x12], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .write, length: 3), + ] + ) + } + + // LD A, (nn) + func testLDAnn() { + test( + program: [0x3a, 0x23, 0x45], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .read, length: 3), + ] + ) + } + + // LD (nn), A + func testLDnnA() { + test( + program: [0x32, 0x23, 0x45], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .write, length: 3), + ] + ) + } + + // LD A, I + func testLDAI() { + test( + program: [0xed, 0x57], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 5), + ] + ) + } + + // LD I, A + func testLDIA() { + test( + program: [0xed, 0x47], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 5), + ] + ) + } } From 838b818cd36fa648011b552a9856ca5c9dda336b Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 15 Jun 2017 22:19:49 -0400 Subject: [PATCH 03/55] Finished transcribing first page of machine cycle documentation; several failures contained. --- .../Z80MachineCycleTests.swift | 210 +++++++++++++++++- 1 file changed, 207 insertions(+), 3 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift b/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift index 58aa2e9a0..f4037f7b5 100644 --- a/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift +++ b/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift @@ -55,7 +55,7 @@ class Z80MachineCycleTests: XCTestCase { ) } - // LD r, nn + // LD r, n func testLDrn() { test( program: [0x3e, 0x00], @@ -151,7 +151,7 @@ class Z80MachineCycleTests: XCTestCase { } // LD A, (nn) - func testLDAnn() { + func testLDAinn() { test( program: [0x3a, 0x23, 0x45], busCycles: [ @@ -164,7 +164,7 @@ class Z80MachineCycleTests: XCTestCase { } // LD (nn), A - func testLDnnA() { + func testLDinnA() { test( program: [0x32, 0x23, 0x45], busCycles: [ @@ -197,4 +197,208 @@ class Z80MachineCycleTests: XCTestCase { ] ) } + + // LD dd, nn + func testLDddnn() { + test( + program: [0x01, 0x12, 0x47], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .read, length: 3), + ] + ) + } + + // LD IX, nn + func testLDIXnn() { + test( + program: [0xdd, 0x21, 0x12, 0x47], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .read, length: 3), + ] + ) + } + + // LD HL, (nn) + func testLDHLinn() { + test( + program: [0x2a, 0x12, 0x47], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .read, length: 3), + ] + ) + } + + // LD (nn), HL + func testLDinnHL() { + test( + program: [0x22, 0x12, 0x47], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .write, length: 3), + MachineCycle(operation: .write, length: 3), + ] + ) + } + + // LD dd, (nn) + func testLDddinn() { + test( + program: [0xed, 0x4b, 0x12, 0x47], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .read, length: 3), + ] + ) + } + + // LD (nn), dd + func testLDinndd() { + test( + program: [0xed, 0x43, 0x12, 0x47], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .write, length: 3), + MachineCycle(operation: .write, length: 3), + ] + ) + } + + // LD IX, (nn) + func testLDIXinn() { + test( + program: [0xdd, 0x2a, 0x12, 0x47], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .read, length: 3), + ] + ) + } + + // LD (nn), IX + func testLDinnIX() { + test( + program: [0xdd, 0x22, 0x12, 0x47], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .write, length: 3), + MachineCycle(operation: .write, length: 3), + ] + ) + } + + // LD SP, HL + func testLDSPHL() { + test( + program: [0xf9], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 6), + ] + ) + } + + // LD SP, IX + func testLDSPIX() { + test( + program: [0xdd, 0xf9], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 6), + ] + ) + } + + // PUSH qq + func testPUSHqq() { + test( + program: [0xc5], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 5), + MachineCycle(operation: .write, length: 3), + MachineCycle(operation: .write, length: 3), + ] + ) + } + + // PUSH IX + func testPUSHIX() { + test( + program: [0xdd, 0xe5], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 5), + MachineCycle(operation: .write, length: 3), + MachineCycle(operation: .write, length: 3), + ] + ) + } + + // POP qq + func testPOPqq() { + test( + program: [0xe1], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .write, length: 3), + MachineCycle(operation: .write, length: 3), + ] + ) + } + + // POP IX + func testPOPIX() { + test( + program: [0xdd, 0xe1], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .write, length: 3), + MachineCycle(operation: .write, length: 3), + ] + ) + } + + // EX DE, HL + func testEXDEHL() { + test( + program: [0xeb], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + ] + ) + } + + // EX AF, AF' + func testEXAFAFDd() { + test( + program: [0x08], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + ] + ) + } } From 50cd617bd949396300c2e70e50fc42c467f34022 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 15 Jun 2017 22:33:46 -0400 Subject: [PATCH 04/55] Ensured test raises only the intentional failure exceptions. --- .../Mac/Clock SignalTests/Z80MachineCycleTests.swift | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift b/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift index f4037f7b5..af8252e6c 100644 --- a/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift +++ b/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift @@ -38,8 +38,15 @@ class Z80MachineCycleTests: XCTestCase { let length = cycle.timeStamp - totalCycles totalCycles += length - XCTAssertEqual(length, busCycles[index].length) - XCTAssertEqual(cycle.operation, busCycles[index].operation) + if index >= busCycles.count { + // this can't be reached without one of the asserts failing; + // it's to prevent an unintended exeception via out-of-bounds + // array access + break + } else { + XCTAssertEqual(length, busCycles[index].length) + XCTAssertEqual(cycle.operation, busCycles[index].operation) + } index += 1 } From efc7f9df37f1b9cf45052f20142941a9bd6a3899 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 17 Jun 2017 18:18:28 -0400 Subject: [PATCH 05/55] Combined I and R into a register pair. --- Processors/Z80/Z80.hpp | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/Processors/Z80/Z80.hpp b/Processors/Z80/Z80.hpp index 7e4a2ab71..7a1b64b6b 100644 --- a/Processors/Z80/Z80.hpp +++ b/Processors/Z80/Z80.hpp @@ -87,10 +87,11 @@ struct MachineCycle { */ template class Processor { private: - uint8_t a_, i_, r_; + uint8_t a_; RegisterPair bc_, de_, hl_; RegisterPair afDash_, bcDash_, deDash_, hlDash_; RegisterPair ix_, iy_, pc_, sp_; + RegisterPair ir_; bool iff1_, iff2_; int interrupt_mode_; uint16_t pc_increment_; @@ -392,19 +393,19 @@ template class Processor { /* 0x40 IN B, (C); 0x41 OUT (C), B */ IN_OUT(bc_.bytes.high), /* 0x42 SBC HL, BC */ SBC16(hl_, bc_), /* 0x43 LD (nn), BC */ Program(FETCH16(temp16_, pc_), STORE16L(bc_, temp16_)), /* 0x44 NEG */ Program({MicroOp::NEG}), /* 0x45 RETN */ Program(POP(pc_), {MicroOp::RETN}), - /* 0x46 IM 0 */ Program({MicroOp::IM}), /* 0x47 LD I, A */ Program(WAIT(1), {MicroOp::Move8, &a_, &i_}), + /* 0x46 IM 0 */ Program({MicroOp::IM}), /* 0x47 LD I, A */ Program(WAIT(1), {MicroOp::Move8, &a_, &ir_.bytes.high}), /* 0x40 IN B, (C); 0x41 OUT (C), B */ IN_OUT(bc_.bytes.low), /* 0x4a ADC HL, BC */ ADC16(hl_, bc_), /* 0x4b LD BC, (nn) */ Program(FETCH16(temp16_, pc_), FETCH16L(bc_, temp16_)), /* 0x4c NEG */ Program({MicroOp::NEG}), /* 0x4d RETI */ Program(POP(pc_), {MicroOp::RETN}), - /* 0x4e IM 0/1 */ Program({MicroOp::IM}), /* 0x4f LD R, A */ Program(WAIT(1), {MicroOp::Move8, &a_, &r_}), + /* 0x4e IM 0/1 */ Program({MicroOp::IM}), /* 0x4f LD R, A */ Program(WAIT(1), {MicroOp::Move8, &a_, &ir_.bytes.low}), /* 0x40 IN B, (C); 0x41 OUT (C), B */ IN_OUT(de_.bytes.high), /* 0x52 SBC HL, DE */ SBC16(hl_, de_), /* 0x53 LD (nn), DE */ Program(FETCH16(temp16_, pc_), STORE16L(de_, temp16_)), /* 0x54 NEG */ Program({MicroOp::NEG}), /* 0x55 RETN */ Program(POP(pc_), {MicroOp::RETN}), - /* 0x56 IM 1 */ Program({MicroOp::IM}), /* 0x57 LD A, I */ Program(WAIT(1), {MicroOp::Move8, &i_, &a_}, {MicroOp::SetAFlags}), + /* 0x56 IM 1 */ Program({MicroOp::IM}), /* 0x57 LD A, I */ Program(WAIT(1), {MicroOp::Move8, &ir_.bytes.high, &a_}, {MicroOp::SetAFlags}), /* 0x40 IN B, (C); 0x41 OUT (C), B */ IN_OUT(de_.bytes.low), /* 0x5a ADC HL, DE */ ADC16(hl_, de_), /* 0x5b LD DE, (nn) */ Program(FETCH16(temp16_, pc_), FETCH16L(de_, temp16_)), /* 0x5c NEG */ Program({MicroOp::NEG}), /* 0x5d RETN */ Program(POP(pc_), {MicroOp::RETN}), - /* 0x5e IM 2 */ Program({MicroOp::IM}), /* 0x5f LD A, R */ Program(WAIT(1), {MicroOp::Move8, &r_, &a_}, {MicroOp::SetAFlags}), + /* 0x5e IM 2 */ Program({MicroOp::IM}), /* 0x5f LD A, R */ Program(WAIT(1), {MicroOp::Move8, &ir_.bytes.low, &a_}, {MicroOp::SetAFlags}), /* 0x40 IN B, (C); 0x41 OUT (C), B */ IN_OUT(hl_.bytes.high), /* 0x62 SBC HL, HL */ SBC16(hl_, hl_), /* 0x63 LD (nn), HL */ Program(FETCH16(temp16_, pc_), STORE16L(hl_, temp16_)), /* 0x64 NEG */ Program({MicroOp::NEG}), /* 0x65 RETN */ Program(POP(pc_), {MicroOp::RETN}), @@ -731,7 +732,7 @@ template class Processor { { MicroOp::BeginIRQ }, { MicroOp::BusOperation, nullptr, nullptr, {BusOperation::Interrupt, 7, nullptr, &temp16_.bytes.low}}, PUSH(pc_), - { MicroOp::Move8, &i_, &temp16_.bytes.high }, + { MicroOp::Move8, &ir_.bytes.high, &temp16_.bytes.high }, FETCH16L(pc_, temp16_), { MicroOp::MoveToNextProgram } }; @@ -813,7 +814,7 @@ template class Processor { advance_operation(); break; case MicroOp::DecodeOperation: - r_ = (r_ & 0x80) | ((r_ + current_instruction_page_->r_step) & 0x7f); + ir_.bytes.low = (ir_.bytes.low & 0x80) | ((ir_.bytes.low + current_instruction_page_->r_step) & 0x7f); pc_.full += pc_increment_ & (uint16_t)halt_mask_; case MicroOp::DecodeOperationNoRChange: scheduled_program_counter_ = current_instruction_page_->instructions[operation_ & halt_mask_]; @@ -1544,7 +1545,7 @@ template class Processor { sp_.full = 0xffff; a_ = 0xff; set_flags(0xff); - i_ = r_ = 0; + ir_.full = 0; break; #pragma mark - Internal bookkeeping @@ -1661,9 +1662,9 @@ template class Processor { case Register::IYl: return iy_.bytes.low; case Register::IY: return iy_.full; - case Register::R: return r_; - case Register::I: return i_; - case Register::Refresh: return (uint16_t)(r_ | (i_ << 8)); + case Register::R: return ir_.bytes.low; + case Register::I: return ir_.bytes.high; + case Register::Refresh: return ir_.full; case Register::IFF1: return iff1_ ? 1 : 0; case Register::IFF2: return iff2_ ? 1 : 0; @@ -1720,9 +1721,9 @@ template class Processor { case Register::IYl: iy_.bytes.low = (uint8_t)value; break; case Register::IY: iy_.full = value; break; - case Register::R: r_ = (uint8_t)value; break; - case Register::I: i_ = (uint8_t)value; break; - case Register::Refresh: r_ = (uint8_t)value; i_ = (uint8_t)(value >> 8); break; + case Register::R: ir_.bytes.low = (uint8_t)value; break; + case Register::I: ir_.bytes.high = (uint8_t)value; break; + case Register::Refresh: ir_.full = (uint16_t)value; break; case Register::IFF1: iff1_ = !!value; break; case Register::IFF2: iff2_ = !!value; break; From 0f187680911d3ae3369f5d2b9451e1fabf3cf67b Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 17 Jun 2017 18:19:25 -0400 Subject: [PATCH 06/55] Disabled attempts at bus activity matching within the FUSE tests, at least until I settle on exactly what I intend to do. --- OSBindings/Mac/Clock SignalTests/FUSETests.swift | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/FUSETests.swift b/OSBindings/Mac/Clock SignalTests/FUSETests.swift index 4a54c33fb..c8c193b25 100644 --- a/OSBindings/Mac/Clock SignalTests/FUSETests.swift +++ b/OSBindings/Mac/Clock SignalTests/FUSETests.swift @@ -218,17 +218,17 @@ class FUSETests: XCTestCase { } // Compare bus operations. - let capturedBusActivity = machine.busOperationCaptures - var capturedBusAcivityIndex = 0; +// let capturedBusActivity = machine.busOperationCaptures +// var capturedBusAcivityIndex = 0; // I presently believe the FUSE unit test bus results for DJNZ — opcode 0x10 — to be // in error by omitting the final offset read. Therefore I am skipping that. // TODO: enquire with the author. - if name == "10" { - continue - } +// if name == "10" { +// continue +// } - let desiredBusActivity = outputDictionary["busActivity"] as? [[String: Any]] +/* let desiredBusActivity = outputDictionary["busActivity"] as? [[String: Any]] if let desiredBusActivity = desiredBusActivity { for action in desiredBusActivity { let type = action["type"] as! String @@ -282,7 +282,7 @@ class FUSETests: XCTestCase { "Failed bus operation match \(name) (at time \(time) with address \(address), value was \(value != nil ? value! : 0), tracking index \(capturedBusAcivityIndex) amongst \(capturedBusActivity))") capturedBusAcivityIndex += 1 } - } + }*/ } } } From b6f51474ff5db52df43678656009d2441e23ca80 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 17 Jun 2017 18:20:30 -0400 Subject: [PATCH 07/55] Ensured that -description can handle the newly-captured bus actions. --- .../Mac/Clock SignalTests/Bridges/TestMachineZ80.mm | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.mm b/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.mm index e0b44acf0..f06e15e41 100644 --- a/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.mm +++ b/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.mm @@ -79,10 +79,12 @@ static CPU::Z80::Register registerForRegister(CSTestMachineZ80Register reg) { - (NSString *)description { NSString *opName = @""; switch(self.operation) { - case CSTestMachineZ80BusOperationCaptureOperationRead: opName = @"r"; break; - case CSTestMachineZ80BusOperationCaptureOperationWrite: opName = @"w"; break; - case CSTestMachineZ80BusOperationCaptureOperationPortRead: opName = @"i"; break; - case CSTestMachineZ80BusOperationCaptureOperationPortWrite: opName = @"o"; break; + case CSTestMachineZ80BusOperationCaptureOperationReadOpcode: opName = @"ro"; break; + case CSTestMachineZ80BusOperationCaptureOperationRead: opName = @"r"; break; + case CSTestMachineZ80BusOperationCaptureOperationWrite: opName = @"w"; break; + case CSTestMachineZ80BusOperationCaptureOperationPortRead: opName = @"i"; break; + case CSTestMachineZ80BusOperationCaptureOperationPortWrite: opName = @"o"; break; + case CSTestMachineZ80BusOperationCaptureOperationInternalOperation: opName = @"iop"; break; } return [NSString stringWithFormat:@"%@ %04x %02x [%d]", opName, self.address, self.value, self.timeStamp]; } From e1a2580b2aa0ea016f6ac52bd1b76d43c42f8ddd Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 17 Jun 2017 21:53:45 -0400 Subject: [PATCH 08/55] Renamed BusOperation to MachineCycle::Operation. --- Machines/ZX8081/ZX8081.cpp | 14 +++--- .../Bridges/TestMachineZ80.mm | 20 ++++----- Processors/Z80/Z80.hpp | 44 +++++++++---------- Processors/Z80/Z80AllRAM.cpp | 14 +++--- Processors/Z80/Z80AllRAM.hpp | 2 +- 5 files changed, 46 insertions(+), 48 deletions(-) diff --git a/Machines/ZX8081/ZX8081.cpp b/Machines/ZX8081/ZX8081.cpp index 26a0dcb89..4142ba511 100644 --- a/Machines/ZX8081/ZX8081.cpp +++ b/Machines/ZX8081/ZX8081.cpp @@ -60,7 +60,7 @@ int Machine::perform_machine_cycle(const CPU::Z80::MachineCycle &cycle) { uint16_t refresh = 0; uint16_t address = cycle.address ? *cycle.address : 0; switch(cycle.operation) { - case CPU::Z80::BusOperation::Output: + case CPU::Z80::MachineCycle::Operation::Output: set_vsync(false); line_counter_ = 0; @@ -68,7 +68,7 @@ int Machine::perform_machine_cycle(const CPU::Z80::MachineCycle &cycle) { if(!(address & 1)) nmi_is_enabled_ = is_zx81_; break; - case CPU::Z80::BusOperation::Input: { + case CPU::Z80::MachineCycle::Operation::Input: { uint8_t value = 0xff; if(!(address&1)) { set_vsync(true); @@ -84,13 +84,13 @@ int Machine::perform_machine_cycle(const CPU::Z80::MachineCycle &cycle) { *cycle.value = value; } break; - case CPU::Z80::BusOperation::Interrupt: + case CPU::Z80::MachineCycle::Operation::Interrupt: line_counter_ = (line_counter_ + 1) & 7; *cycle.value = 0xff; horizontal_counter_ = 0; break; - case CPU::Z80::BusOperation::ReadOpcode: + case CPU::Z80::MachineCycle::Operation::ReadOpcode: // The ZX80 and 81 signal an interrupt while refresh is active and bit 6 of the refresh // address is low. The Z80 signals a refresh, providing the refresh address during the // final two cycles of an opcode fetch. Therefore communicate a transient signalling @@ -111,7 +111,7 @@ int Machine::perform_machine_cycle(const CPU::Z80::MachineCycle &cycle) { } } - case CPU::Z80::BusOperation::Read: + case CPU::Z80::MachineCycle::Operation::Read: if(address < ram_base_) { *cycle.value = rom_[address & rom_mask_]; } else { @@ -120,7 +120,7 @@ int Machine::perform_machine_cycle(const CPU::Z80::MachineCycle &cycle) { // If this is an M1 cycle reading from above the 32kb mark and HALT is not // currently active, perform a video output and return a NOP. Otherwise, // just return the value as read. - if(cycle.operation == CPU::Z80::BusOperation::ReadOpcode && address&0x8000 && !(value & 0x40) && !get_halt_line()) { + if(cycle.operation == CPU::Z80::MachineCycle::Operation::ReadOpcode && address&0x8000 && !(value & 0x40) && !get_halt_line()) { size_t char_address = (size_t)((refresh & 0xff00) | ((value & 0x3f) << 3) | line_counter_); if(char_address < ram_base_) { uint8_t mask = (value & 0x80) ? 0x00 : 0xff; @@ -133,7 +133,7 @@ int Machine::perform_machine_cycle(const CPU::Z80::MachineCycle &cycle) { } break; - case CPU::Z80::BusOperation::Write: + case CPU::Z80::MachineCycle::Operation::Write: if(address >= ram_base_) { ram_[address & ram_mask_] = *cycle.value; } diff --git a/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.mm b/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.mm index f06e15e41..2a5c0cf7f 100644 --- a/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.mm +++ b/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.mm @@ -11,7 +11,7 @@ #import "TestMachine+ForSubclassEyesOnly.h" @interface CSTestMachineZ80 () -- (void)testMachineDidPerformBusOperation:(CPU::Z80::BusOperation)operation address:(uint16_t)address value:(uint8_t)value timeStamp:(int)time_stamp; +- (void)testMachineDidPerformBusOperation:(CPU::Z80::MachineCycle::Operation)operation address:(uint16_t)address value:(uint8_t)value timeStamp:(int)time_stamp; @end #pragma mark - C++ delegate handlers @@ -20,7 +20,7 @@ class BusOperationHandler: public CPU::Z80::AllRAMProcessor::MemoryAccessDelegat public: BusOperationHandler(CSTestMachineZ80 *targetMachine) : target_(targetMachine) {} - void z80_all_ram_processor_did_perform_bus_operation(CPU::Z80::AllRAMProcessor &processor, CPU::Z80::BusOperation operation, uint16_t address, uint8_t value, int time_stamp) { + void z80_all_ram_processor_did_perform_bus_operation(CPU::Z80::AllRAMProcessor &processor, CPU::Z80::MachineCycle::Operation operation, uint16_t address, uint8_t value, int time_stamp) { [target_ testMachineDidPerformBusOperation:operation address:address value:value timeStamp:time_stamp]; } @@ -187,36 +187,36 @@ static CPU::Z80::Register registerForRegister(CSTestMachineZ80Register reg) { _processor->set_memory_access_delegate(captureBusActivity ? _busOperationHandler : nullptr); } -- (void)testMachineDidPerformBusOperation:(CPU::Z80::BusOperation)operation address:(uint16_t)address value:(uint8_t)value timeStamp:(int)timeStamp { +- (void)testMachineDidPerformBusOperation:(CPU::Z80::MachineCycle::Operation)operation address:(uint16_t)address value:(uint8_t)value timeStamp:(int)timeStamp { int length = timeStamp - _lastOpcodeTime; _lastOpcodeTime = timeStamp; - if(operation == CPU::Z80::BusOperation::ReadOpcode && length < _timeSeekingReadOpcode) + if(operation == CPU::Z80::MachineCycle::Operation::ReadOpcode && length < _timeSeekingReadOpcode) _isAtReadOpcode = YES; if(self.captureBusActivity) { CSTestMachineZ80BusOperationCapture *capture = [[CSTestMachineZ80BusOperationCapture alloc] init]; switch(operation) { - case CPU::Z80::BusOperation::Write: + case CPU::Z80::MachineCycle::Operation::Write: capture.operation = CSTestMachineZ80BusOperationCaptureOperationWrite; break; - case CPU::Z80::BusOperation::Read: + case CPU::Z80::MachineCycle::Operation::Read: capture.operation = CSTestMachineZ80BusOperationCaptureOperationRead; break; - case CPU::Z80::BusOperation::ReadOpcode: + case CPU::Z80::MachineCycle::Operation::ReadOpcode: capture.operation = CSTestMachineZ80BusOperationCaptureOperationReadOpcode; break; - case CPU::Z80::BusOperation::Input: + case CPU::Z80::MachineCycle::Operation::Input: capture.operation = CSTestMachineZ80BusOperationCaptureOperationPortRead; break; - case CPU::Z80::BusOperation::Output: + case CPU::Z80::MachineCycle::Operation::Output: capture.operation = CSTestMachineZ80BusOperationCaptureOperationPortWrite; break; - case CPU::Z80::BusOperation::Internal: + case CPU::Z80::MachineCycle::Operation::Internal: capture.operation = CSTestMachineZ80BusOperationCaptureOperationInternalOperation; break; diff --git a/Processors/Z80/Z80.hpp b/Processors/Z80/Z80.hpp index 7a1b64b6b..1bd751fa5 100644 --- a/Processors/Z80/Z80.hpp +++ b/Processors/Z80/Z80.hpp @@ -62,17 +62,15 @@ enum Flag: uint8_t { Subclasses will be given the task of performing bus operations, allowing them to provide whatever interface they like between a Z80 and the rest of the system. @c BusOperation lists the types of bus operation that may be requested. */ -enum BusOperation { - ReadOpcode = 0, - Read, Write, - Input, Output, - Interrupt, - BusAcknowledge, - Internal -}; - struct MachineCycle { - BusOperation operation; + enum Operation { + ReadOpcode = 0, + Read, Write, + Input, Output, + Interrupt, + BusAcknowledge, + Internal + } operation; int length; uint16_t *address; uint8_t *value; @@ -242,14 +240,14 @@ template class Processor { #define INC16(r) {(&r == &pc_) ? MicroOp::IncrementPC : MicroOp::Increment16, &r.full} /// Fetches into x from address y, and then increments y. -#define FETCH(x, y) {MicroOp::BusOperation, nullptr, nullptr, {Read, 3, &y.full, &x}}, INC16(y) +#define FETCH(x, y) {MicroOp::BusOperation, nullptr, nullptr, {MachineCycle::Read, 3, &y.full, &x}}, INC16(y) /// Fetches into x from address y. -#define FETCHL(x, y) {MicroOp::BusOperation, nullptr, nullptr, {Read, 3, &y.full, &x}} +#define FETCHL(x, y) {MicroOp::BusOperation, nullptr, nullptr, {MachineCycle::Read, 3, &y.full, &x}} /// Stores x to address y, and then increments y. -#define STORE(x, y) {MicroOp::BusOperation, nullptr, nullptr, {Write, 3, &y.full, &x}}, {MicroOp::Increment16, &y.full} +#define STORE(x, y) {MicroOp::BusOperation, nullptr, nullptr, {MachineCycle::Write, 3, &y.full, &x}}, {MicroOp::Increment16, &y.full} /// Stores x to address y. -#define STOREL(x, y) {MicroOp::BusOperation, nullptr, nullptr, {Write, 3, &y.full, &x}} +#define STOREL(x, y) {MicroOp::BusOperation, nullptr, nullptr, {MachineCycle::Write, 3, &y.full, &x}} /// Fetches the 16-bit quantity x from address y, incrementing y twice. #define FETCH16(x, y) FETCH(x.bytes.low, y), FETCH(x.bytes.high, y) @@ -260,10 +258,10 @@ template class Processor { #define STORE16L(x, y) STORE(x.bytes.low, y), STOREL(x.bytes.high, y) /// Outputs the 8-bit value to the 16-bit port -#define OUT(port, value) {MicroOp::BusOperation, nullptr, nullptr, {Output, 4, &port.full, &value}} +#define OUT(port, value) {MicroOp::BusOperation, nullptr, nullptr, {MachineCycle::Output, 4, &port.full, &value}} /// Inputs the 8-bit value from the 16-bit port -#define IN(port, value) {MicroOp::BusOperation, nullptr, nullptr, {Input, 4, &port.full, &value}} +#define IN(port, value) {MicroOp::BusOperation, nullptr, nullptr, {MachineCycle::Input, 4, &port.full, &value}} #define PUSH(x) {MicroOp::Decrement16, &sp_.full}, STOREL(x.bytes.high, sp_), {MicroOp::Decrement16, &sp_.full}, STOREL(x.bytes.low, sp_) #define POP(x) FETCHL(x.bytes.low, sp_), {MicroOp::Increment16, &sp_.full}, FETCHL(x.bytes.high, sp_), {MicroOp::Increment16, &sp_.full} @@ -327,7 +325,7 @@ template class Processor { #define ADC16(d, s) Program(WAIT(4), WAIT(3), {MicroOp::ADC16, &s.full, &d.full}) #define SBC16(d, s) Program(WAIT(4), WAIT(3), {MicroOp::SBC16, &s.full, &d.full}) -#define WAIT(n) {MicroOp::BusOperation, nullptr, nullptr, {Internal, n} } +#define WAIT(n) {MicroOp::BusOperation, nullptr, nullptr, {MachineCycle::Internal, n} } #define Program(...) { __VA_ARGS__, {MicroOp::MoveToNextProgram} } #define isTerminal(n) (n == MicroOp::MoveToNextProgram || n == MicroOp::DecodeOperation || n == MicroOp::DecodeOperationNoRChange) @@ -655,7 +653,7 @@ template class Processor { void assemble_fetch_decode_execute(InstructionPage &target, int length) { const MicroOp fetch_decode_execute[] = { - { MicroOp::BusOperation, nullptr, nullptr, {(length == 4) ? ReadOpcode : Read, length, &pc_.full, &operation_}}, + { MicroOp::BusOperation, nullptr, nullptr, {(length == 4) ? MachineCycle::ReadOpcode : MachineCycle::Read, length, &pc_.full, &operation_}}, { MicroOp::DecodeOperation } }; copy_program(fetch_decode_execute, target.fetch_decode_execute); @@ -711,26 +709,26 @@ template class Processor { MicroOp reset_program[] = Program(WAIT(3), {MicroOp::Reset}); MicroOp nmi_program[] = { { MicroOp::BeginNMI }, - { MicroOp::BusOperation, nullptr, nullptr, {ReadOpcode, 5, &pc_.full, &operation_}}, + { MicroOp::BusOperation, nullptr, nullptr, {MachineCycle::ReadOpcode, 5, &pc_.full, &operation_}}, PUSH(pc_), { MicroOp::JumpTo66, nullptr, nullptr}, { MicroOp::MoveToNextProgram } }; MicroOp irq_mode0_program[] = { { MicroOp::BeginIRQMode0 }, - { MicroOp::BusOperation, nullptr, nullptr, {BusOperation::Interrupt, 6, nullptr, &operation_}}, + { MicroOp::BusOperation, nullptr, nullptr, {MachineCycle::Operation::Interrupt, 6, nullptr, &operation_}}, { MicroOp::DecodeOperationNoRChange } }; MicroOp irq_mode1_program[] = { { MicroOp::BeginIRQ }, - { MicroOp::BusOperation, nullptr, nullptr, {BusOperation::Interrupt, 7, nullptr, &operation_}}, + { MicroOp::BusOperation, nullptr, nullptr, {MachineCycle::Operation::Interrupt, 7, nullptr, &operation_}}, PUSH(pc_), { MicroOp::Move16, &temp16_.full, &pc_.full }, { MicroOp::MoveToNextProgram } }; MicroOp irq_mode2_program[] = { { MicroOp::BeginIRQ }, - { MicroOp::BusOperation, nullptr, nullptr, {BusOperation::Interrupt, 7, nullptr, &temp16_.bytes.low}}, + { MicroOp::BusOperation, nullptr, nullptr, {MachineCycle::Operation::Interrupt, 7, nullptr, &temp16_.bytes.low}}, PUSH(pc_), { MicroOp::Move8, &ir_.bytes.high, &temp16_.bytes.high }, FETCH16L(pc_, temp16_), @@ -781,7 +779,7 @@ template class Processor { while(1) { while(bus_request_line_) { - static MachineCycle bus_acknowledge_cycle = {BusOperation::BusAcknowledge, 1}; + static MachineCycle bus_acknowledge_cycle = {MachineCycle::Operation::BusAcknowledge, 1}; number_of_cycles_ -= static_cast(this)->perform_machine_cycle(bus_acknowledge_cycle) + 1; if(!number_of_cycles_) { static_cast(this)->flush(); diff --git a/Processors/Z80/Z80AllRAM.cpp b/Processors/Z80/Z80AllRAM.cpp index 8594a2fbf..99340657c 100644 --- a/Processors/Z80/Z80AllRAM.cpp +++ b/Processors/Z80/Z80AllRAM.cpp @@ -20,30 +20,30 @@ class ConcreteAllRAMProcessor: public AllRAMProcessor, public Processor> 8; break; - case BusOperation::Internal: + case MachineCycle::Operation::Internal: break; - case BusOperation::Interrupt: + case MachineCycle::Operation::Interrupt: // A pick that means LD HL, (nn) if interpreted as an instruction but is otherwise // arbitrary. *cycle.value = 0x21; diff --git a/Processors/Z80/Z80AllRAM.hpp b/Processors/Z80/Z80AllRAM.hpp index 8999fc5bb..778437f7c 100644 --- a/Processors/Z80/Z80AllRAM.hpp +++ b/Processors/Z80/Z80AllRAM.hpp @@ -22,7 +22,7 @@ class AllRAMProcessor: static AllRAMProcessor *Processor(); struct MemoryAccessDelegate { - virtual void z80_all_ram_processor_did_perform_bus_operation(AllRAMProcessor &processor, BusOperation operation, uint16_t address, uint8_t value, int time_stamp) = 0; + virtual void z80_all_ram_processor_did_perform_bus_operation(AllRAMProcessor &processor, MachineCycle::Operation operation, uint16_t address, uint8_t value, int time_stamp) = 0; }; inline void set_memory_access_delegate(MemoryAccessDelegate *delegate) { delegate_ = delegate; From ebc7356db527b6590aa6a444a3fca3ef609e5412 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 18 Jun 2017 12:21:27 -0400 Subject: [PATCH 09/55] Reformulated the machine cycle slightly to support posting operation plus phase, thereby exposing the segue points at which waits might be inserted. So: to stick to the rule that CPUs expose the minimum amount of information sufficient completely to reconstruct bus activity. This breaks the Z80 for now. --- Processors/Z80/Z80.hpp | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/Processors/Z80/Z80.hpp b/Processors/Z80/Z80.hpp index 1bd751fa5..08596dc3d 100644 --- a/Processors/Z80/Z80.hpp +++ b/Processors/Z80/Z80.hpp @@ -65,17 +65,55 @@ enum Flag: uint8_t { struct MachineCycle { enum Operation { ReadOpcode = 0, + Refresh, Read, Write, Input, Output, Interrupt, BusAcknowledge, Internal } operation; + enum Phase { + Start, + Wait, + End + } phase; int length; uint16_t *address; uint8_t *value; }; +#define ReadOpcodeStart(addr, val) {MachineCycle::ReadOpcode, Phase::Start, 2, addr, val) +#define ReadOpcodeWait(addr, val) {MachineCycle::ReadOpcode, Phase::Wait, 1, addr, val) +#define Refresh(len) {MachineCycle::Refresh, Phase::Start, 2, &ir_.full, nullptr) + +#define ReadStart(addr, val) {MachineCycle::Read, Phase::Start, 2, addr, val) +#define ReadWait(addr, val) {MachineCycle::Read, Phase::Wait, 1, addr, val) +#define ReadEnd(addr, val) {MachineCycle::Read, Phase::End, 1, addr, val) + +#define WriteStart(addr, val) {MachineCycle::Write, Phase::Start, 2, addr, val) +#define WriteWait(addr, val) {MachineCycle::Write, Phase::Wait, 1, addr, val) +#define WriteEnd(addr, val) {MachineCycle::Write, Phase::End, 1, addr, val) + +#define InputStart(addr, val) {MachineCycle::Input, Phase::Start, 3, addr, val) +#define InputWait(addr, val) {MachineCycle::Input, Phase::Wait, 1, addr, val) +#define InputEnd(addr, val) {MachineCycle::Input, Phase::End, 1, addr, val) + +#define OutpuStart(addr, val) {MachineCycle::Output, Phase::Start, 3, addr, val) +#define OutpuWait(addr, val) {MachineCycle::Output, Phase::Wait, 1, addr, val) +#define OutpuEnd(addr, val) {MachineCycle::Output, Phase::End, 1, addr, val) + +#define BusOp(c) {MicroOp::BusOperation, nullptr, nullptr, c} + +#define Read(addr, val) BusOp(ReadStart(addr, val)), BusOp(ReadWait(addr, val)), BusOp(ReadEnd(addr, val)) +#define Write(addr, val) BusOp(WriteStart(addr, val)), BusOp(WriteWait(addr, val)), BusOp(WriteEnd(addr, val)) +#define Input(addr, val) BusOp(InputStart(addr, val)), BusOp(InputWait(addr, val)), BusOp(InputEnd(addr, val)) +#define Output(addr, val) BusOp(OutputStart(addr, val)), BusOp(OutputWait(addr, val)), BusOp(OutputEnd(addr, val)) +#define InternalOperation(n) BusOp({MachineCycle::Internal, n}) + +#define Sequence(...) { __VA_ARGS__, {MicroOp::MoveToNextProgram} } +#define Instr(r, ...) Sequence(BusOp(Refresh(r)), __VA_ARGS__) +#define StdInstr(...) Instr(2, __VA_ARGS_) + /*! @abstact An abstract base class for emulation of a Z80 processor via the curiously recurring template pattern/f-bounded polymorphism. @@ -325,9 +363,6 @@ template class Processor { #define ADC16(d, s) Program(WAIT(4), WAIT(3), {MicroOp::ADC16, &s.full, &d.full}) #define SBC16(d, s) Program(WAIT(4), WAIT(3), {MicroOp::SBC16, &s.full, &d.full}) -#define WAIT(n) {MicroOp::BusOperation, nullptr, nullptr, {MachineCycle::Internal, n} } -#define Program(...) { __VA_ARGS__, {MicroOp::MoveToNextProgram} } - #define isTerminal(n) (n == MicroOp::MoveToNextProgram || n == MicroOp::DecodeOperation || n == MicroOp::DecodeOperationNoRChange) typedef MicroOp InstructionTable[256][20]; From 194b7f60c53ff1b10ec53d7423971f77456bcabc Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 18 Jun 2017 17:08:50 -0400 Subject: [PATCH 10/55] Rephrased to allow non-conditional waits; expanded macros to cover all permitted lengths of read and write. --- Processors/Z80/Z80.hpp | 101 +++++++++++++++++++++-------------------- 1 file changed, 53 insertions(+), 48 deletions(-) diff --git a/Processors/Z80/Z80.hpp b/Processors/Z80/Z80.hpp index 08596dc3d..6d66dadbd 100644 --- a/Processors/Z80/Z80.hpp +++ b/Processors/Z80/Z80.hpp @@ -80,40 +80,58 @@ struct MachineCycle { int length; uint16_t *address; uint8_t *value; + bool was_requested; }; -#define ReadOpcodeStart(addr, val) {MachineCycle::ReadOpcode, Phase::Start, 2, addr, val) -#define ReadOpcodeWait(addr, val) {MachineCycle::ReadOpcode, Phase::Wait, 1, addr, val) -#define Refresh(len) {MachineCycle::Refresh, Phase::Start, 2, &ir_.full, nullptr) +// Elemental bus operations +#define ReadOpcodeStart(addr, val) {MachineCycle::ReadOpcode, Phase::Start, 2, addr, val, false} +#define ReadOpcodeWait(addr, val) {MachineCycle::ReadOpcode, Phase::Wait, 1, addr, val, true} +#define Refresh(len) {MachineCycle::Refresh, Phase::Start, 2, &ir_.full, nullptr, false} -#define ReadStart(addr, val) {MachineCycle::Read, Phase::Start, 2, addr, val) -#define ReadWait(addr, val) {MachineCycle::Read, Phase::Wait, 1, addr, val) -#define ReadEnd(addr, val) {MachineCycle::Read, Phase::End, 1, addr, val) +#define ReadStart(addr, val) {MachineCycle::Read, Phase::Start, 2, addr, val, false} +#define ReadWait(l, addr, val, f) {MachineCycle::Read, Phase::Wait, l, addr, val, f} +#define ReadEnd(addr, val) {MachineCycle::Read, Phase::End, 1, addr, val, false} -#define WriteStart(addr, val) {MachineCycle::Write, Phase::Start, 2, addr, val) -#define WriteWait(addr, val) {MachineCycle::Write, Phase::Wait, 1, addr, val) -#define WriteEnd(addr, val) {MachineCycle::Write, Phase::End, 1, addr, val) +#define WriteStart(addr, val) {MachineCycle::Write, Phase::Start, 2, addr, val, false} +#define WriteWait(l, addr, val, f) {MachineCycle::Write, Phase::Wait, l, addr, val, f} +#define WriteEnd(addr, val) {MachineCycle::Write, Phase::End, 1, addr, val, false} -#define InputStart(addr, val) {MachineCycle::Input, Phase::Start, 3, addr, val) -#define InputWait(addr, val) {MachineCycle::Input, Phase::Wait, 1, addr, val) -#define InputEnd(addr, val) {MachineCycle::Input, Phase::End, 1, addr, val) +#define InputStart(addr, val) {MachineCycle::Input, Phase::Start, 2, addr, val, false} +#define InputWait(addr, val, f) {MachineCycle::Input, Phase::Wait, 1, addr, val, f} +#define InputEnd(addr, val) {MachineCycle::Input, Phase::End, 1, addr, val, false} -#define OutpuStart(addr, val) {MachineCycle::Output, Phase::Start, 3, addr, val) -#define OutpuWait(addr, val) {MachineCycle::Output, Phase::Wait, 1, addr, val) -#define OutpuEnd(addr, val) {MachineCycle::Output, Phase::End, 1, addr, val) +#define OutpuStart(addr, val) {MachineCycle::Output, Phase::Start, 2, addr, val} +#define OutpuWait(addr, val, f) {MachineCycle::Output, Phase::Wait, 1, addr, val, f} +#define OutpuEnd(addr, val) {MachineCycle::Output, Phase::End, 1, addr, val} +// A wrapper to express a bus operation as a micro-op #define BusOp(c) {MicroOp::BusOperation, nullptr, nullptr, c} -#define Read(addr, val) BusOp(ReadStart(addr, val)), BusOp(ReadWait(addr, val)), BusOp(ReadEnd(addr, val)) -#define Write(addr, val) BusOp(WriteStart(addr, val)), BusOp(WriteWait(addr, val)), BusOp(WriteEnd(addr, val)) -#define Input(addr, val) BusOp(InputStart(addr, val)), BusOp(InputWait(addr, val)), BusOp(InputEnd(addr, val)) -#define Output(addr, val) BusOp(OutputStart(addr, val)), BusOp(OutputWait(addr, val)), BusOp(OutputEnd(addr, val)) +// Compound bus operations, as micro-ops +#define Read3(addr, val) BusOp(ReadStart(addr, val)), BusOp(ReadWait(1, addr, val, true)), BusOp(ReadEnd(addr, val)) +#define Read4(addr, val) BusOp(ReadStart(addr, val)), BusOp(ReadWait(1, addr, val, false)), BusOp(ReadWait(1, addr, val, true)), BusOp(ReadEnd(addr, val)) + +#define Write3(addr, val) BusOp(WriteStart(addr, val)), BusOp(WriteWait(1, addr, val, true)), BusOp(WriteEnd(addr, val)) +#define Write5(addr, val) BusOp(WriteStart(addr, val)), BusOp(WriteWait(2, addr, val, false)), BusOp(WriteWait(1, addr, val, true)), BusOp(WriteEnd(addr, val)) + +#define Input(addr, val) BusOp(InputStart(addr, val)), BusOp(InputWait(addr, val, false)), BusOp(InputWait(addr, val, true)), BusOp(InputEnd(addr, val)) +#define Output(addr, val) BusOp(OutputStart(addr, val)), BusOp(OutputWait(addr, val, false)), BusOp(OutputWait(addr, val, true)), BusOp(OutputEnd(addr, val)) #define InternalOperation(n) BusOp({MachineCycle::Internal, n}) +/// A sequence is a series of micro-ops that ends in a move-to-next-program operation. #define Sequence(...) { __VA_ARGS__, {MicroOp::MoveToNextProgram} } + +/// An instruction is the part of an instruction that follows instruction fetch; it should include two or more refresh cycles and then the work of the instruction. #define Instr(r, ...) Sequence(BusOp(Refresh(r)), __VA_ARGS__) + +/// A standard instruction is one with the most normal timing: two cycles of refresh, then the work. #define StdInstr(...) Instr(2, __VA_ARGS_) +// Assumption made: those instructions that are rated with an opcode fetch greater than four cycles spend the extra time +// providing a lengthened refresh cycle. I assume this because the CPU doesn't have foresight and presumably spends the +// normal refresh time decoding. So if it gets to cycle four and realises it has two more cycles of work, I have assumed +// it simply maintains the refresh state for an extra two cycles. + /*! @abstact An abstract base class for emulation of a Z80 processor via the curiously recurring template pattern/f-bounded polymorphism. @@ -269,43 +287,30 @@ template class Processor { InstructionPage fdcb_page_; InstructionPage ddcb_page_; -#define NOP {MicroOp::MoveToNextProgram} -#define INDEX() {MicroOp::IndexedPlaceHolder}, FETCH(temp8_, pc_), WAIT(5), {MicroOp::CalculateIndexAddress, &index} -#define FINDEX() {MicroOp::IndexedPlaceHolder}, FETCH(temp8_, pc_), {MicroOp::CalculateIndexAddress, &index} -#define INDEX_ADDR() (add_offsets ? memptr_ : index) +/* The following are helper macros that define common parts of instructions */ +#define Inc16(r) {(&r == &pc_) ? MicroOp::IncrementPC : MicroOp::Increment16, &r.full} -#define INC16(r) {(&r == &pc_) ? MicroOp::IncrementPC : MicroOp::Increment16, &r.full} +#define ReadInc(addr, val) Read(addr, val), INC16(y) +#define WriteInc(addr, val) Write(addr, val), {MicroOp::Increment16, &y.full} -/// Fetches into x from address y, and then increments y. -#define FETCH(x, y) {MicroOp::BusOperation, nullptr, nullptr, {MachineCycle::Read, 3, &y.full, &x}}, INC16(y) -/// Fetches into x from address y. -#define FETCHL(x, y) {MicroOp::BusOperation, nullptr, nullptr, {MachineCycle::Read, 3, &y.full, &x}} +#define Read16Inc(addr, val) ReadInc(addr, val.bytes.low), ReadInc(addr, val.bytes.high) +#define Read16(addr, val) ReadInc(addr, val.bytes.low), Read(addr, val.bytes.high) -/// Stores x to address y, and then increments y. -#define STORE(x, y) {MicroOp::BusOperation, nullptr, nullptr, {MachineCycle::Write, 3, &y.full, &x}}, {MicroOp::Increment16, &y.full} -/// Stores x to address y. -#define STOREL(x, y) {MicroOp::BusOperation, nullptr, nullptr, {MachineCycle::Write, 3, &y.full, &x}} +#define Write16(addr, val) WriteInc(addr, val.bytes.low), Write(addr, val.bytes.high) -/// Fetches the 16-bit quantity x from address y, incrementing y twice. -#define FETCH16(x, y) FETCH(x.bytes.low, y), FETCH(x.bytes.high, y) -/// Fetches the 16-bit quantity x from address y, incrementing y once. -#define FETCH16L(x, y) FETCH(x.bytes.low, y), FETCHL(x.bytes.high, y) +#define INDEX() {MicroOp::IndexedPlaceHolder}, Read(pc_, temp8_), InternalOperation(5), {MicroOp::CalculateIndexAddress, &index} +#define FINDEX() {MicroOp::IndexedPlaceHolder}, Read(pc_, temp8_), {MicroOp::CalculateIndexAddress, &index} +#define INDEX_ADDR() (add_offsets ? memptr_ : index) -/// Stores the 16-bit quantity x to address y, incrementing y once. -#define STORE16L(x, y) STORE(x.bytes.low, y), STOREL(x.bytes.high, y) +#define Push(x) {MicroOp::Decrement16, &sp_.full}, Write(sp_, x.bytes.high), {MicroOp::Decrement16, &sp_.full}, Write(sp_, x.bytes.low) +#define Pop(x) Read(sp_, x.bytes.low), {MicroOp::Increment16, &sp_.full}, Read(sp_, x.bytes.high), {MicroOp::Increment16, &sp_.full} -/// Outputs the 8-bit value to the 16-bit port -#define OUT(port, value) {MicroOp::BusOperation, nullptr, nullptr, {MachineCycle::Output, 4, &port.full, &value}} +/* The following are actual instructions */ +#define NOP Sequence(BusOp(Refresh(2))) -/// Inputs the 8-bit value from the 16-bit port -#define IN(port, value) {MicroOp::BusOperation, nullptr, nullptr, {MachineCycle::Input, 4, &port.full, &value}} - -#define PUSH(x) {MicroOp::Decrement16, &sp_.full}, STOREL(x.bytes.high, sp_), {MicroOp::Decrement16, &sp_.full}, STOREL(x.bytes.low, sp_) -#define POP(x) FETCHL(x.bytes.low, sp_), {MicroOp::Increment16, &sp_.full}, FETCHL(x.bytes.high, sp_), {MicroOp::Increment16, &sp_.full} - -#define JP(cc) Program(FETCH16(temp16_, pc_), {MicroOp::cc}, {MicroOp::Move16, &temp16_.full, &pc_.full}) -#define CALL(cc) Program(FETCH16(temp16_, pc_), {MicroOp::cc}, WAIT(1), PUSH(pc_), {MicroOp::Move16, &temp16_.full, &pc_.full}) +#define JP(cc) StdInstr(Read16Inc(pc_, temp16_), {MicroOp::cc}, {MicroOp::Move16, &temp16_.full, &pc_.full}) +#define CALL(cc) StdInstr(Read16Inc(pc_, temp16_), {MicroOp::cc}, WAIT(1), PUSH(pc_), {MicroOp::Move16, &temp16_.full, &pc_.full}) #define RET(cc) Program(WAIT(1), {MicroOp::cc}, POP(memptr_), {MicroOp::Move16, &memptr_.full, &pc_.full}) #define JR(cc) Program(FETCH(temp8_, pc_), {MicroOp::cc}, WAIT(5), {MicroOp::CalculateIndexAddress, &pc_.full}, {MicroOp::Move16, &memptr_.full, &pc_.full}) #define RST() Program(WAIT(1), {MicroOp::CalculateRSTDestination}, PUSH(pc_), {MicroOp::Move16, &memptr_.full, &pc_.full}) From 82a015892bbde11b55b64e7d6051e75ec7bc0c30 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 18 Jun 2017 17:18:01 -0400 Subject: [PATCH 11/55] Started adapting to the newly-segmented world. --- Processors/Z80/Z80.hpp | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/Processors/Z80/Z80.hpp b/Processors/Z80/Z80.hpp index 6d66dadbd..38c68d201 100644 --- a/Processors/Z80/Z80.hpp +++ b/Processors/Z80/Z80.hpp @@ -291,8 +291,8 @@ template class Processor { /* The following are helper macros that define common parts of instructions */ #define Inc16(r) {(&r == &pc_) ? MicroOp::IncrementPC : MicroOp::Increment16, &r.full} -#define ReadInc(addr, val) Read(addr, val), INC16(y) -#define WriteInc(addr, val) Write(addr, val), {MicroOp::Increment16, &y.full} +#define ReadInc(addr, val) Read3(addr, val), Inc16(y) +#define WriteInc(addr, val) Write3(addr, val), {MicroOp::Increment16, &y.full} #define Read16Inc(addr, val) ReadInc(addr, val.bytes.low), ReadInc(addr, val.bytes.high) #define Read16(addr, val) ReadInc(addr, val.bytes.low), Read(addr, val.bytes.high) @@ -328,21 +328,21 @@ template class Processor { Program({MicroOp::op, &a_}) #define READ_OP_GROUP_D(op) \ - Program({MicroOp::op, &bc_.bytes.high}), Program({MicroOp::op, &bc_.bytes.low}), \ - Program({MicroOp::op, &de_.bytes.high}), Program({MicroOp::op, &de_.bytes.low}), \ - Program({MicroOp::op, &index.bytes.high}), Program({MicroOp::op, &index.bytes.low}), \ - Program(INDEX(), FETCHL(temp8_, INDEX_ADDR()), WAIT(1), {MicroOp::op, &temp8_}), \ - Program({MicroOp::op, &a_}) + StdInstr({MicroOp::op, &bc_.bytes.high}), StdInstr({MicroOp::op, &bc_.bytes.low}), \ + StdInstr({MicroOp::op, &de_.bytes.high}), StdInstr({MicroOp::op, &de_.bytes.low}), \ + StdInstr({MicroOp::op, &index.bytes.high}), StdInstr({MicroOp::op, &index.bytes.low}), \ + StdInstr(INDEX(), Read4(INDEX_ADDR(), temp8_), {MicroOp::op, &temp8_}), \ + StdInstr({MicroOp::op, &a_}) -#define RMW(x, op, ...) Program(INDEX(), FETCHL(x, INDEX_ADDR()), {MicroOp::op, &x}, WAIT(1), STOREL(x, INDEX_ADDR())) -#define RMWI(x, op, ...) Program(WAIT(2), FETCHL(x, INDEX_ADDR()), {MicroOp::op, &x}, WAIT(1), STOREL(x, INDEX_ADDR())) +#define RMW(x, op, ...) StdInstr(INDEX(), Read4(INDEX_ADDR(), x), {MicroOp::op, &x}, Write3(INDEX_ADDR(), x)) +#define RMWI(x, op, ...) Instr(4, Read4(INDEX_ADDR(), x), {MicroOp::op, &x}, Write3(INDEX_ADDR(), x)) #define MODIFY_OP_GROUP(op) \ - Program({MicroOp::op, &bc_.bytes.high}), Program({MicroOp::op, &bc_.bytes.low}), \ - Program({MicroOp::op, &de_.bytes.high}), Program({MicroOp::op, &de_.bytes.low}), \ - Program({MicroOp::op, &index.bytes.high}), Program({MicroOp::op, &index.bytes.low}), \ + StdInstr({MicroOp::op, &bc_.bytes.high}), StdInstr({MicroOp::op, &bc_.bytes.low}), \ + StdInstr({MicroOp::op, &de_.bytes.high}), StdInstr({MicroOp::op, &de_.bytes.low}), \ + StdInstr({MicroOp::op, &index.bytes.high}), StdInstr({MicroOp::op, &index.bytes.low}), \ RMW(temp8_, op), \ - Program({MicroOp::op, &a_}) + StdInstr({MicroOp::op, &a_}) #define IX_MODIFY_OP_GROUP(op) \ RMWI(bc_.bytes.high, op), \ @@ -520,19 +520,19 @@ template class Processor { void assemble_base_page(InstructionPage &target, RegisterPair &index, bool add_offsets, InstructionPage &cb_page) { #define INC_DEC_LD(r) \ - Program({MicroOp::Increment8, &r}), \ - Program({MicroOp::Decrement8, &r}), \ - Program(FETCH(r, pc_)) + StdInstr({MicroOp::Increment8, &r}), \ + StdInstr({MicroOp::Decrement8, &r}), \ + StdInstr(ReadInc(pc_, r)) #define INC_INC_DEC_LD(rf, r) \ - Program(WAIT(2), {MicroOp::Increment16, &rf.full}), INC_DEC_LD(r) + Instr(4, {MicroOp::Increment16, &rf.full}), INC_DEC_LD(r) #define DEC_INC_DEC_LD(rf, r) \ Program(WAIT(2), {MicroOp::Decrement16, &rf.full}), INC_DEC_LD(r) InstructionTable base_program_table = { - /* 0x00 NOP */ NOP, /* 0x01 LD BC, nn */ Program(FETCH16(bc_, pc_)), - /* 0x02 LD (BC), A */ Program({MicroOp::Move16, &bc_.full, &memptr_.full}, STORE(a_, memptr_)), + /* 0x00 NOP */ NOP, /* 0x01 LD BC, nn */ StdInstr(Read16(pc_, bc_)), + /* 0x02 LD (BC), A */ StdInstr({MicroOp::Move16, &bc_.full, &memptr_.full}, Write(memptr_, a_)), /* 0x03 INC BC; 0x04 INC B; 0x05 DEC B; 0x06 LD B, n */ INC_INC_DEC_LD(bc_, bc_.bytes.high), From 0d1231980a0dcc6257776d35241e2f3a69a3ec81 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 18 Jun 2017 17:25:15 -0400 Subject: [PATCH 12/55] Advanced to getting specific warnings in the ed-page table. So that's progress. --- Processors/Z80/Z80.hpp | 62 +++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/Processors/Z80/Z80.hpp b/Processors/Z80/Z80.hpp index 38c68d201..2a86046ca 100644 --- a/Processors/Z80/Z80.hpp +++ b/Processors/Z80/Z80.hpp @@ -84,28 +84,28 @@ struct MachineCycle { }; // Elemental bus operations -#define ReadOpcodeStart(addr, val) {MachineCycle::ReadOpcode, Phase::Start, 2, addr, val, false} -#define ReadOpcodeWait(addr, val) {MachineCycle::ReadOpcode, Phase::Wait, 1, addr, val, true} -#define Refresh(len) {MachineCycle::Refresh, Phase::Start, 2, &ir_.full, nullptr, false} +#define ReadOpcodeStart(addr, val) {MachineCycle::ReadOpcode, MachineCycle::Phase::Start, 2, addr, val, false} +#define ReadOpcodeWait(addr, val) {MachineCycle::ReadOpcode, MachineCycle::Phase::Wait, 1, addr, val, true} +#define Refresh(len) {MachineCycle::Refresh, MachineCycle::Phase::Start, 2, &ir_.full, nullptr, false} -#define ReadStart(addr, val) {MachineCycle::Read, Phase::Start, 2, addr, val, false} -#define ReadWait(l, addr, val, f) {MachineCycle::Read, Phase::Wait, l, addr, val, f} -#define ReadEnd(addr, val) {MachineCycle::Read, Phase::End, 1, addr, val, false} +#define ReadStart(addr, val) {MachineCycle::Read, MachineCycle::Phase::Start, 2, addr, val, false} +#define ReadWait(l, addr, val, f) {MachineCycle::Read, MachineCycle::Phase::Wait, l, addr, val, f} +#define ReadEnd(addr, val) {MachineCycle::Read, MachineCycle::Phase::End, 1, addr, val, false} -#define WriteStart(addr, val) {MachineCycle::Write, Phase::Start, 2, addr, val, false} -#define WriteWait(l, addr, val, f) {MachineCycle::Write, Phase::Wait, l, addr, val, f} -#define WriteEnd(addr, val) {MachineCycle::Write, Phase::End, 1, addr, val, false} +#define WriteStart(addr, val) {MachineCycle::Write, MachineCycle::Phase::Start, 2, addr, val, false} +#define WriteWait(l, addr, val, f) {MachineCycle::Write, MachineCycle::Phase::Wait, l, addr, val, f} +#define WriteEnd(addr, val) {MachineCycle::Write, MachineCycle::Phase::End, 1, addr, val, false} -#define InputStart(addr, val) {MachineCycle::Input, Phase::Start, 2, addr, val, false} -#define InputWait(addr, val, f) {MachineCycle::Input, Phase::Wait, 1, addr, val, f} -#define InputEnd(addr, val) {MachineCycle::Input, Phase::End, 1, addr, val, false} +#define InputStart(addr, val) {MachineCycle::Input, MachineCycle::Phase::Start, 2, addr, val, false} +#define InputWait(addr, val, f) {MachineCycle::Input, MachineCycle::Phase::Wait, 1, addr, val, f} +#define InputEnd(addr, val) {MachineCycle::Input, MachineCycle::Phase::End, 1, addr, val, false} -#define OutpuStart(addr, val) {MachineCycle::Output, Phase::Start, 2, addr, val} -#define OutpuWait(addr, val, f) {MachineCycle::Output, Phase::Wait, 1, addr, val, f} -#define OutpuEnd(addr, val) {MachineCycle::Output, Phase::End, 1, addr, val} +#define OutpuStart(addr, val) {MachineCycle::Output, MachineCycle::Phase::Start, 2, addr, val} +#define OutpuWait(addr, val, f) {MachineCycle::Output, MachineCycle::Phase::Wait, 1, addr, val, f} +#define OutpuEnd(addr, val) {MachineCycle::Output, MachineCycle::Phase::End, 1, addr, val} // A wrapper to express a bus operation as a micro-op -#define BusOp(c) {MicroOp::BusOperation, nullptr, nullptr, c} +#define BusOp(op) {MicroOp::BusOperation, nullptr, nullptr, op} // Compound bus operations, as micro-ops #define Read3(addr, val) BusOp(ReadStart(addr, val)), BusOp(ReadWait(1, addr, val, true)), BusOp(ReadEnd(addr, val)) @@ -116,7 +116,7 @@ struct MachineCycle { #define Input(addr, val) BusOp(InputStart(addr, val)), BusOp(InputWait(addr, val, false)), BusOp(InputWait(addr, val, true)), BusOp(InputEnd(addr, val)) #define Output(addr, val) BusOp(OutputStart(addr, val)), BusOp(OutputWait(addr, val, false)), BusOp(OutputWait(addr, val, true)), BusOp(OutputEnd(addr, val)) -#define InternalOperation(n) BusOp({MachineCycle::Internal, n}) +#define InternalOperation(len) {MicroOp::BusOperation, nullptr, nullptr, {MachineCycle::Internal, len}} /// A sequence is a series of micro-ops that ends in a move-to-next-program operation. #define Sequence(...) { __VA_ARGS__, {MicroOp::MoveToNextProgram} } @@ -299,12 +299,12 @@ template class Processor { #define Write16(addr, val) WriteInc(addr, val.bytes.low), Write(addr, val.bytes.high) -#define INDEX() {MicroOp::IndexedPlaceHolder}, Read(pc_, temp8_), InternalOperation(5), {MicroOp::CalculateIndexAddress, &index} -#define FINDEX() {MicroOp::IndexedPlaceHolder}, Read(pc_, temp8_), {MicroOp::CalculateIndexAddress, &index} +#define INDEX() {MicroOp::IndexedPlaceHolder}, Read3(pc_, temp8_), InternalOperation(5), {MicroOp::CalculateIndexAddress, &index} +#define FINDEX() {MicroOp::IndexedPlaceHolder}, Read3(pc_, temp8_), {MicroOp::CalculateIndexAddress, &index} #define INDEX_ADDR() (add_offsets ? memptr_ : index) -#define Push(x) {MicroOp::Decrement16, &sp_.full}, Write(sp_, x.bytes.high), {MicroOp::Decrement16, &sp_.full}, Write(sp_, x.bytes.low) -#define Pop(x) Read(sp_, x.bytes.low), {MicroOp::Increment16, &sp_.full}, Read(sp_, x.bytes.high), {MicroOp::Increment16, &sp_.full} +#define Push(x) {MicroOp::Decrement16, &sp_.full}, Write3(sp_, x.bytes.high), {MicroOp::Decrement16, &sp_.full}, Write3(sp_, x.bytes.low) +#define Pop(x) Read3(sp_, x.bytes.low), {MicroOp::Increment16, &sp_.full}, Read3(sp_, x.bytes.high), {MicroOp::Increment16, &sp_.full} /* The following are actual instructions */ #define NOP Sequence(BusOp(Refresh(2))) @@ -314,18 +314,18 @@ template class Processor { #define RET(cc) Program(WAIT(1), {MicroOp::cc}, POP(memptr_), {MicroOp::Move16, &memptr_.full, &pc_.full}) #define JR(cc) Program(FETCH(temp8_, pc_), {MicroOp::cc}, WAIT(5), {MicroOp::CalculateIndexAddress, &pc_.full}, {MicroOp::Move16, &memptr_.full, &pc_.full}) #define RST() Program(WAIT(1), {MicroOp::CalculateRSTDestination}, PUSH(pc_), {MicroOp::Move16, &memptr_.full, &pc_.full}) -#define LD(a, b) Program({MicroOp::Move8, &b, &a}) +#define LD(a, b) StdInstr({MicroOp::Move8, &b, &a}) #define LD_GROUP(r, ri) \ LD(r, bc_.bytes.high), LD(r, bc_.bytes.low), LD(r, de_.bytes.high), LD(r, de_.bytes.low), \ - LD(r, index.bytes.high), LD(r, index.bytes.low), Program(INDEX(), FETCHL(ri, INDEX_ADDR())), LD(r, a_) + LD(r, index.bytes.high), LD(r, index.bytes.low), StdInstr(INDEX(), Read3(INDEX_ADDR(), ri)), LD(r, a_) #define READ_OP_GROUP(op) \ - Program({MicroOp::op, &bc_.bytes.high}), Program({MicroOp::op, &bc_.bytes.low}), \ - Program({MicroOp::op, &de_.bytes.high}), Program({MicroOp::op, &de_.bytes.low}), \ - Program({MicroOp::op, &index.bytes.high}), Program({MicroOp::op, &index.bytes.low}), \ - Program(INDEX(), FETCHL(temp8_, INDEX_ADDR()), {MicroOp::op, &temp8_}), \ - Program({MicroOp::op, &a_}) + StdInstr({MicroOp::op, &bc_.bytes.high}), StdInstr({MicroOp::op, &bc_.bytes.low}), \ + StdInstr({MicroOp::op, &de_.bytes.high}), StdInstr({MicroOp::op, &de_.bytes.low}), \ + StdInstr({MicroOp::op, &index.bytes.high}), StdInstr({MicroOp::op, &index.bytes.low}), \ + StdInstr(INDEX(), Read3(INDEX_ADDR(), temp8_), {MicroOp::op, &temp8_}), \ + StdInstr({MicroOp::op, &a_}) #define READ_OP_GROUP_D(op) \ StdInstr({MicroOp::op, &bc_.bytes.high}), StdInstr({MicroOp::op, &bc_.bytes.low}), \ @@ -364,9 +364,9 @@ template class Processor { Program(WAIT(2), FETCHL(temp8_, INDEX_ADDR()), {MicroOp::op, &temp8_}, WAIT(1)), \ Program(WAIT(2), FETCHL(temp8_, INDEX_ADDR()), {MicroOp::op, &temp8_}, WAIT(1)) -#define ADD16(d, s) Program(WAIT(4), WAIT(3), {MicroOp::ADD16, &s.full, &d.full}) -#define ADC16(d, s) Program(WAIT(4), WAIT(3), {MicroOp::ADC16, &s.full, &d.full}) -#define SBC16(d, s) Program(WAIT(4), WAIT(3), {MicroOp::SBC16, &s.full, &d.full}) +#define ADD16(d, s) Program(InternalOperation(4), InternalOperation(3), {MicroOp::ADD16, &s.full, &d.full}) +#define ADC16(d, s) Program(InternalOperation(4), InternalOperation(3), {MicroOp::ADC16, &s.full, &d.full}) +#define SBC16(d, s) Program(InternalOperation(4), InternalOperation(3), {MicroOp::SBC16, &s.full, &d.full}) #define isTerminal(n) (n == MicroOp::MoveToNextProgram || n == MicroOp::DecodeOperation || n == MicroOp::DecodeOperationNoRChange) From 0d39672d32f2e0cc66308b9946e03d972cfb63a4 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 18 Jun 2017 17:48:54 -0400 Subject: [PATCH 13/55] Fixing typos here and there, persuaded the first half of the ED table to compile. --- Processors/Z80/Z80.hpp | 58 +++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/Processors/Z80/Z80.hpp b/Processors/Z80/Z80.hpp index 2a86046ca..1ece19fb7 100644 --- a/Processors/Z80/Z80.hpp +++ b/Processors/Z80/Z80.hpp @@ -125,7 +125,7 @@ struct MachineCycle { #define Instr(r, ...) Sequence(BusOp(Refresh(r)), __VA_ARGS__) /// A standard instruction is one with the most normal timing: two cycles of refresh, then the work. -#define StdInstr(...) Instr(2, __VA_ARGS_) +#define StdInstr(...) Instr(2, __VA_ARGS__) // Assumption made: those instructions that are rated with an opcode fetch greater than four cycles spend the extra time // providing a lengthened refresh cycle. I assume this because the CPU doesn't have foresight and presumably spends the @@ -291,13 +291,13 @@ template class Processor { /* The following are helper macros that define common parts of instructions */ #define Inc16(r) {(&r == &pc_) ? MicroOp::IncrementPC : MicroOp::Increment16, &r.full} -#define ReadInc(addr, val) Read3(addr, val), Inc16(y) -#define WriteInc(addr, val) Write3(addr, val), {MicroOp::Increment16, &y.full} +#define ReadInc(addr, val) Read3(addr, val), Inc16(addr) +#define WriteInc(addr, val) Write3(addr, val), {MicroOp::Increment16, &addr.full} #define Read16Inc(addr, val) ReadInc(addr, val.bytes.low), ReadInc(addr, val.bytes.high) #define Read16(addr, val) ReadInc(addr, val.bytes.low), Read(addr, val.bytes.high) -#define Write16(addr, val) WriteInc(addr, val.bytes.low), Write(addr, val.bytes.high) +#define Write16(addr, val) WriteInc(addr, val.bytes.low), Write3(addr, val.bytes.high) #define INDEX() {MicroOp::IndexedPlaceHolder}, Read3(pc_, temp8_), InternalOperation(5), {MicroOp::CalculateIndexAddress, &index} #define FINDEX() {MicroOp::IndexedPlaceHolder}, Read3(pc_, temp8_), {MicroOp::CalculateIndexAddress, &index} @@ -429,37 +429,37 @@ template class Processor { NOP_ROW(), /* 0x20 */ NOP_ROW(), /* 0x30 */ /* 0x40 IN B, (C); 0x41 OUT (C), B */ IN_OUT(bc_.bytes.high), - /* 0x42 SBC HL, BC */ SBC16(hl_, bc_), /* 0x43 LD (nn), BC */ Program(FETCH16(temp16_, pc_), STORE16L(bc_, temp16_)), - /* 0x44 NEG */ Program({MicroOp::NEG}), /* 0x45 RETN */ Program(POP(pc_), {MicroOp::RETN}), - /* 0x46 IM 0 */ Program({MicroOp::IM}), /* 0x47 LD I, A */ Program(WAIT(1), {MicroOp::Move8, &a_, &ir_.bytes.high}), + /* 0x42 SBC HL, BC */ SBC16(hl_, bc_), /* 0x43 LD (nn), BC */ StdInstr(Read16Inc(pc_, temp16_), Write16(temp16_, bc_)), + /* 0x44 NEG */ StdInstr({MicroOp::NEG}), /* 0x45 RETN */ StdInstr(Pop(pc_), {MicroOp::RETN}), + /* 0x46 IM 0 */ StdInstr({MicroOp::IM}), /* 0x47 LD I, A */ Instr(3, {MicroOp::Move8, &a_, &ir_.bytes.high}), /* 0x40 IN B, (C); 0x41 OUT (C), B */ IN_OUT(bc_.bytes.low), - /* 0x4a ADC HL, BC */ ADC16(hl_, bc_), /* 0x4b LD BC, (nn) */ Program(FETCH16(temp16_, pc_), FETCH16L(bc_, temp16_)), - /* 0x4c NEG */ Program({MicroOp::NEG}), /* 0x4d RETI */ Program(POP(pc_), {MicroOp::RETN}), - /* 0x4e IM 0/1 */ Program({MicroOp::IM}), /* 0x4f LD R, A */ Program(WAIT(1), {MicroOp::Move8, &a_, &ir_.bytes.low}), + /* 0x4a ADC HL, BC */ ADC16(hl_, bc_), /* 0x4b LD BC, (nn) */ StdInstr(Read16Inc(pc_, temp16_), Read16(temp16_, bc_)), + /* 0x4c NEG */ StdInstr({MicroOp::NEG}), /* 0x4d RETI */ StdInstr(Pop(pc_), {MicroOp::RETN}), + /* 0x4e IM 0/1 */ StdInstr({MicroOp::IM}), /* 0x4f LD R, A */ Instr(3, {MicroOp::Move8, &a_, &ir_.bytes.low}), /* 0x40 IN B, (C); 0x41 OUT (C), B */ IN_OUT(de_.bytes.high), - /* 0x52 SBC HL, DE */ SBC16(hl_, de_), /* 0x53 LD (nn), DE */ Program(FETCH16(temp16_, pc_), STORE16L(de_, temp16_)), - /* 0x54 NEG */ Program({MicroOp::NEG}), /* 0x55 RETN */ Program(POP(pc_), {MicroOp::RETN}), - /* 0x56 IM 1 */ Program({MicroOp::IM}), /* 0x57 LD A, I */ Program(WAIT(1), {MicroOp::Move8, &ir_.bytes.high, &a_}, {MicroOp::SetAFlags}), + /* 0x52 SBC HL, DE */ SBC16(hl_, de_), /* 0x53 LD (nn), DE */ StdInstr(Read16Inc(pc_, temp16_), Write16(temp16_, de_)), + /* 0x54 NEG */ StdInstr({MicroOp::NEG}), /* 0x55 RETN */ StdInstr(Pop(pc_), {MicroOp::RETN}), + /* 0x56 IM 1 */ StdInstr({MicroOp::IM}), /* 0x57 LD A, I */ Instr(3, {MicroOp::Move8, &ir_.bytes.high, &a_}, {MicroOp::SetAFlags}), /* 0x40 IN B, (C); 0x41 OUT (C), B */ IN_OUT(de_.bytes.low), - /* 0x5a ADC HL, DE */ ADC16(hl_, de_), /* 0x5b LD DE, (nn) */ Program(FETCH16(temp16_, pc_), FETCH16L(de_, temp16_)), - /* 0x5c NEG */ Program({MicroOp::NEG}), /* 0x5d RETN */ Program(POP(pc_), {MicroOp::RETN}), - /* 0x5e IM 2 */ Program({MicroOp::IM}), /* 0x5f LD A, R */ Program(WAIT(1), {MicroOp::Move8, &ir_.bytes.low, &a_}, {MicroOp::SetAFlags}), + /* 0x5a ADC HL, DE */ ADC16(hl_, de_), /* 0x5b LD DE, (nn) */ StdInstr(Read16Inc(pc_, temp16_), Write16(temp16_, de_)), + /* 0x5c NEG */ StdInstr({MicroOp::NEG}), /* 0x5d RETN */ StdInstr(Pop(pc_), {MicroOp::RETN}), + /* 0x5e IM 2 */ StdInstr({MicroOp::IM}), /* 0x5f LD A, R */ Instr(3, {MicroOp::Move8, &ir_.bytes.low, &a_}, {MicroOp::SetAFlags}), /* 0x40 IN B, (C); 0x41 OUT (C), B */ IN_OUT(hl_.bytes.high), - /* 0x62 SBC HL, HL */ SBC16(hl_, hl_), /* 0x63 LD (nn), HL */ Program(FETCH16(temp16_, pc_), STORE16L(hl_, temp16_)), - /* 0x64 NEG */ Program({MicroOp::NEG}), /* 0x65 RETN */ Program(POP(pc_), {MicroOp::RETN}), - /* 0x66 IM 0 */ Program({MicroOp::IM}), /* 0x67 RRD */ Program(FETCHL(temp8_, hl_), WAIT(4), {MicroOp::RRD}, STOREL(temp8_, hl_)), + /* 0x62 SBC HL, HL */ SBC16(hl_, hl_), /* 0x63 LD (nn), HL */ StdInstr(Read16Inc(pc_, temp16_), Write16(temp16_, hl_)), + /* 0x64 NEG */ StdInstr({MicroOp::NEG}), /* 0x65 RETN */ StdInstr(Pop(pc_), {MicroOp::RETN}), + /* 0x66 IM 0 */ StdInstr({MicroOp::IM}), /* 0x67 RRD */ StdInstr(Read3(hl_, temp8_), InternalOperation(4), {MicroOp::RRD}, Write3(hl_, temp8_)), /* 0x40 IN B, (C); 0x41 OUT (C), B */ IN_OUT(hl_.bytes.low), - /* 0x6a ADC HL, HL */ ADC16(hl_, hl_), /* 0x6b LD HL, (nn) */ Program(FETCH16(temp16_, pc_), FETCH16L(hl_, temp16_)), - /* 0x6c NEG */ Program({MicroOp::NEG}), /* 0x6d RETN */ Program(POP(pc_), {MicroOp::RETN}), - /* 0x6e IM 0/1 */ Program({MicroOp::IM}), /* 0x6f RLD */ Program(FETCHL(temp8_, hl_), WAIT(4), {MicroOp::RLD}, STOREL(temp8_, hl_)), - /* 0x70 IN (C) */ IN_C(temp8_), /* 0x71 OUT (C), 0 */ Program({MicroOp::SetZero}, OUT(bc_, temp8_)), - /* 0x72 SBC HL, SP */ SBC16(hl_, sp_), /* 0x73 LD (nn), SP */ Program(FETCH16(temp16_, pc_), STORE16L(sp_, temp16_)), - /* 0x74 NEG */ Program({MicroOp::NEG}), /* 0x75 RETN */ Program(POP(pc_), {MicroOp::RETN}), - /* 0x76 IM 1 */ Program({MicroOp::IM}), /* 0x77 XX */ NOP, + /* 0x6a ADC HL, HL */ ADC16(hl_, hl_), /* 0x6b LD HL, (nn) */ StdInstr(Read16Inc(pc_, temp16_), Store16(temp16_, hl_)), + /* 0x6c NEG */ StdInstr({MicroOp::NEG}), /* 0x6d RETN */ StdInstr(Pop(pc_), {MicroOp::RETN}), + /* 0x6e IM 0/1 */ StdInstr({MicroOp::IM}), /* 0x6f RLD */ StdInstr(Read3(hl_, temp8_), InternalOperation(4), {MicroOp::RLD}, Write3(hl_, temp8_)), + /* 0x70 IN (C) */ IN_C(temp8_), /* 0x71 OUT (C), 0 */ StdInstr({MicroOp::SetZero}, OUT(bc_, temp8_)), + /* 0x72 SBC HL, SP */ SBC16(hl_, sp_), /* 0x73 LD (nn), SP */ StdInstr(Read16Inc(pc_, temp16_), Store16(temp16_, sp_)), + /* 0x74 NEG */ StdInstr({MicroOp::NEG}), /* 0x75 RETN */ StdInstr(Pop(pc_), {MicroOp::RETN}), + /* 0x76 IM 1 */ StdInstr({MicroOp::IM}), /* 0x77 XX */ NOP, /* 0x40 IN B, (C); 0x41 OUT (C), B */ IN_OUT(a_), - /* 0x7a ADC HL, SP */ ADC16(hl_, sp_), /* 0x7b LD SP, (nn) */ Program(FETCH16(temp16_, pc_), FETCH16L(sp_, temp16_)), - /* 0x7c NEG */ Program({MicroOp::NEG}), /* 0x7d RETN */ Program(POP(pc_), {MicroOp::RETN}), - /* 0x7e IM 2 */ Program({MicroOp::IM}), /* 0x7f XX */ NOP, + /* 0x7a ADC HL, SP */ ADC16(hl_, sp_), /* 0x7b LD SP, (nn) */ StdInstr(Read16Inc(pc_, temp16_), Store16(temp16_, sp_)), + /* 0x7c NEG */ StdInstr({MicroOp::NEG}), /* 0x7d RETN */ StdInstr(Pop(pc_), {MicroOp::RETN}), + /* 0x7e IM 2 */ StdInstr({MicroOp::IM}), /* 0x7f XX */ NOP, NOP_ROW(), /* 0x80 */ NOP_ROW(), /* 0x90 */ /* 0xa0 LDI */ Program(FETCHL(temp8_, hl_), STOREL(temp8_, de_), WAIT(2), {MicroOp::LDI}), From 69ebbe019ae5bf355fc563d4d82904d236398c5e Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 18 Jun 2017 17:56:48 -0400 Subject: [PATCH 14/55] Completed ED page conversion. Rolling onwards... --- Processors/Z80/Z80.hpp | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Processors/Z80/Z80.hpp b/Processors/Z80/Z80.hpp index 1ece19fb7..5c4531269 100644 --- a/Processors/Z80/Z80.hpp +++ b/Processors/Z80/Z80.hpp @@ -462,25 +462,25 @@ template class Processor { /* 0x7e IM 2 */ StdInstr({MicroOp::IM}), /* 0x7f XX */ NOP, NOP_ROW(), /* 0x80 */ NOP_ROW(), /* 0x90 */ - /* 0xa0 LDI */ Program(FETCHL(temp8_, hl_), STOREL(temp8_, de_), WAIT(2), {MicroOp::LDI}), - /* 0xa1 CPI */ Program(FETCHL(temp8_, hl_), WAIT(5), {MicroOp::CPI}), - /* 0xa2 INI */ Program(WAIT(1), IN(bc_, temp8_), STOREL(temp8_, hl_), {MicroOp::INI}), - /* 0xa3 OTI */ Program(WAIT(1), FETCHL(temp8_, hl_), {MicroOp::OUTI}, OUT(bc_, temp8_)), + /* 0xa0 LDI */ StdInstr(Read3(hl_, temp8_), Write5(de_, temp8_), {MicroOp::LDI}), + /* 0xa1 CPI */ StdInstr(Read3(hl_, temp8_), InternalOperation(5), {MicroOp::CPI}), + /* 0xa2 INI */ Instr(3, Input(bc_, temp8_), Write3(hl_, temp8_), {MicroOp::INI}), + /* 0xa3 OTI */ Instr(3, Read3(hl_, temp8_), {MicroOp::OUTI}, Output(bc_, temp8_)), NOP, NOP, NOP, NOP, - /* 0xa8 LDD */ Program(FETCHL(temp8_, hl_), STOREL(temp8_, de_), WAIT(2), {MicroOp::LDD}), - /* 0xa9 CPD */ Program(FETCHL(temp8_, hl_), WAIT(5), {MicroOp::CPD}), - /* 0xaa IND */ Program(WAIT(1), IN(bc_, temp8_), STOREL(temp8_, hl_), {MicroOp::IND}), - /* 0xab OTD */ Program(WAIT(1), FETCHL(temp8_, hl_), {MicroOp::OUTD}, OUT(bc_, temp8_)), + /* 0xa8 LDD */ StdInstr(Read3(hl_, temp8_), Write5(de_, temp8_), {MicroOp::LDD}), + /* 0xa9 CPD */ StdInstr(Read3(hl_, temp8_), InternalOperation(5), {MicroOp::CPD}), + /* 0xaa IND */ Instr(3, Input(bc_, temp8_), Write3(hl_, temp8_), {MicroOp::IND}), + /* 0xab OTD */ Instr(3, Read3(hl_, temp8_), {MicroOp::OUTD}, Output(bc_, temp8_)), NOP, NOP, NOP, NOP, - /* 0xb0 LDIR */ Program(FETCHL(temp8_, hl_), STOREL(temp8_, de_), WAIT(2), {MicroOp::LDIR}, WAIT(5)), - /* 0xb1 CPIR */ Program(FETCHL(temp8_, hl_), WAIT(5), {MicroOp::CPIR}, WAIT(5)), - /* 0xb2 INIR */ Program(WAIT(1), IN(bc_, temp8_), STOREL(temp8_, hl_), {MicroOp::INIR}, WAIT(5)), - /* 0xb3 OTIR */ Program(WAIT(1), FETCHL(temp8_, hl_), {MicroOp::OUTI}, OUT(bc_, temp8_), {MicroOp::OUT_R}, WAIT(5)), + /* 0xb0 LDIR */ StdInstr(Read3(hl_, temp8_), Write5(de_, temp8_), {MicroOp::LDIR}, InternalOperation(5)), + /* 0xb1 CPIR */ StdInstr(Read3(hl_, temp8_), InternalOperation(5), {MicroOp::CPIR}, InternalOperation(5)), + /* 0xb2 INIR */ Instr(3, Input(bc_, temp8_), Write3(hl_, temp8_), {MicroOp::INIR}, InternalOperation(5)), + /* 0xb3 OTIR */ Instr(3, Read(hl_, temp8_), {MicroOp::OUTI}, Output(bc_, temp8_), {MicroOp::OUT_R}, InternalOperation(5)), NOP, NOP, NOP, NOP, - /* 0xb8 LDDR */ Program(FETCHL(temp8_, hl_), STOREL(temp8_, de_), WAIT(2), {MicroOp::LDDR}, WAIT(5)), - /* 0xb9 CPDR */ Program(FETCHL(temp8_, hl_), WAIT(5), {MicroOp::CPDR}, WAIT(5)), - /* 0xba INDR */ Program(WAIT(1), IN(bc_, temp8_), STOREL(temp8_, hl_), {MicroOp::INDR}, WAIT(5)), - /* 0xbb OTDR */ Program(WAIT(1), FETCHL(temp8_, hl_), {MicroOp::OUTD}, OUT(bc_, temp8_), {MicroOp::OUT_R}, WAIT(5)), + /* 0xb8 LDDR */ StdInstr(Read3(hl_, temp8_), Write5(de_, temp8_), {MicroOp::LDDR}, InternalOperation(5)), + /* 0xb9 CPDR */ StdInstr(Read3(hl_, temp8_), InternalOperation(5), {MicroOp::CPDR}, InternalOperation(5)), + /* 0xba INDR */ Instr(3, Input(bc_, temp8_), Write3(hl_, temp8_), {MicroOp::INDR}, InternalOperation(5)), + /* 0xbb OTDR */ Instr(3, Read3(hl_, temp8_), {MicroOp::OUTD}, OUT(bc_, temp8_), {MicroOp::OUT_R}, InternalOperation(5)), NOP, NOP, NOP, NOP, NOP_ROW(), /* 0xc0 */ NOP_ROW(), /* 0xd0 */ From bb910e14a4556310f582c0280d0a7469112613a3 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 18 Jun 2017 18:01:33 -0400 Subject: [PATCH 15/55] Dealt with the CB page. --- Processors/Z80/Z80.hpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Processors/Z80/Z80.hpp b/Processors/Z80/Z80.hpp index 5c4531269..e15ecd9d2 100644 --- a/Processors/Z80/Z80.hpp +++ b/Processors/Z80/Z80.hpp @@ -355,14 +355,14 @@ template class Processor { RMWI(a_, op) #define IX_READ_OP_GROUP(op) \ - Program(WAIT(2), FETCHL(temp8_, INDEX_ADDR()), {MicroOp::op, &temp8_}, WAIT(1)), \ - Program(WAIT(2), FETCHL(temp8_, INDEX_ADDR()), {MicroOp::op, &temp8_}, WAIT(1)), \ - Program(WAIT(2), FETCHL(temp8_, INDEX_ADDR()), {MicroOp::op, &temp8_}, WAIT(1)), \ - Program(WAIT(2), FETCHL(temp8_, INDEX_ADDR()), {MicroOp::op, &temp8_}, WAIT(1)), \ - Program(WAIT(2), FETCHL(temp8_, INDEX_ADDR()), {MicroOp::op, &temp8_}, WAIT(1)), \ - Program(WAIT(2), FETCHL(temp8_, INDEX_ADDR()), {MicroOp::op, &temp8_}, WAIT(1)), \ - Program(WAIT(2), FETCHL(temp8_, INDEX_ADDR()), {MicroOp::op, &temp8_}, WAIT(1)), \ - Program(WAIT(2), FETCHL(temp8_, INDEX_ADDR()), {MicroOp::op, &temp8_}, WAIT(1)) + Instr(4, Read4(INDEX_ADDR(), temp8_), {MicroOp::op, &temp8_}), \ + Instr(4, Read4(INDEX_ADDR(), temp8_), {MicroOp::op, &temp8_}), \ + Instr(4, Read4(INDEX_ADDR(), temp8_), {MicroOp::op, &temp8_}), \ + Instr(4, Read4(INDEX_ADDR(), temp8_), {MicroOp::op, &temp8_}), \ + Instr(4, Read4(INDEX_ADDR(), temp8_), {MicroOp::op, &temp8_}), \ + Instr(4, Read4(INDEX_ADDR(), temp8_), {MicroOp::op, &temp8_}), \ + Instr(4, Read4(INDEX_ADDR(), temp8_), {MicroOp::op, &temp8_}), \ + Instr(4, Read4(INDEX_ADDR(), temp8_), {MicroOp::op, &temp8_}) #define ADD16(d, s) Program(InternalOperation(4), InternalOperation(3), {MicroOp::ADD16, &s.full, &d.full}) #define ADC16(d, s) Program(InternalOperation(4), InternalOperation(3), {MicroOp::ADC16, &s.full, &d.full}) From 3be8ffd8260248db692aa66958748218e579a69f Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 18 Jun 2017 20:31:12 -0400 Subject: [PATCH 16/55] Some correct timings have gone out the window for now, but only the final quarter of the base page now contains compiler errors. --- Processors/Z80/Z80.hpp | 80 +++++++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/Processors/Z80/Z80.hpp b/Processors/Z80/Z80.hpp index e15ecd9d2..159df8f86 100644 --- a/Processors/Z80/Z80.hpp +++ b/Processors/Z80/Z80.hpp @@ -311,9 +311,9 @@ template class Processor { #define JP(cc) StdInstr(Read16Inc(pc_, temp16_), {MicroOp::cc}, {MicroOp::Move16, &temp16_.full, &pc_.full}) #define CALL(cc) StdInstr(Read16Inc(pc_, temp16_), {MicroOp::cc}, WAIT(1), PUSH(pc_), {MicroOp::Move16, &temp16_.full, &pc_.full}) -#define RET(cc) Program(WAIT(1), {MicroOp::cc}, POP(memptr_), {MicroOp::Move16, &memptr_.full, &pc_.full}) -#define JR(cc) Program(FETCH(temp8_, pc_), {MicroOp::cc}, WAIT(5), {MicroOp::CalculateIndexAddress, &pc_.full}, {MicroOp::Move16, &memptr_.full, &pc_.full}) -#define RST() Program(WAIT(1), {MicroOp::CalculateRSTDestination}, PUSH(pc_), {MicroOp::Move16, &memptr_.full, &pc_.full}) +#define RET(cc) Instr(3, {MicroOp::cc}, Pop(memptr_), {MicroOp::Move16, &memptr_.full, &pc_.full}) +#define JR(cc) StdInstr(ReadInc(pc_, temp8_), {MicroOp::cc}, InternalOperation(5), {MicroOp::CalculateIndexAddress, &pc_.full}, {MicroOp::Move16, &memptr_.full, &pc_.full}) +#define RST() Instr(3, {MicroOp::CalculateRSTDestination}, Push(pc_), {MicroOp::Move16, &memptr_.full, &pc_.full}) #define LD(a, b) StdInstr({MicroOp::Move8, &b, &a}) #define LD_GROUP(r, ri) \ @@ -418,8 +418,8 @@ template class Processor { } void assemble_ed_page(InstructionPage &target) { -#define IN_C(r) Program(IN(bc_, r), {MicroOp::SetInFlags, &r}) -#define OUT_C(r) Program(OUT(bc_, r)) +#define IN_C(r) StdInstr(Input(bc_, r), {MicroOp::SetInFlags, &r}) +#define OUT_C(r) StdInstr(Output(bc_, r)) #define IN_OUT(r) IN_C(r), OUT_C(r) #define NOP_ROW() NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP @@ -528,7 +528,7 @@ template class Processor { Instr(4, {MicroOp::Increment16, &rf.full}), INC_DEC_LD(r) #define DEC_INC_DEC_LD(rf, r) \ - Program(WAIT(2), {MicroOp::Decrement16, &rf.full}), INC_DEC_LD(r) + Instr(4, {MicroOp::Decrement16, &rf.full}), INC_DEC_LD(r) InstructionTable base_program_table = { /* 0x00 NOP */ NOP, /* 0x01 LD BC, nn */ StdInstr(Read16(pc_, bc_)), @@ -537,60 +537,60 @@ template class Processor { /* 0x03 INC BC; 0x04 INC B; 0x05 DEC B; 0x06 LD B, n */ INC_INC_DEC_LD(bc_, bc_.bytes.high), - /* 0x07 RLCA */ Program({MicroOp::RLCA}), - /* 0x08 EX AF, AF' */ Program({MicroOp::ExAFAFDash}), /* 0x09 ADD HL, BC */ ADD16(index, bc_), - /* 0x0a LD A, (BC) */ Program({MicroOp::Move16, &bc_.full, &memptr_.full}, FETCH(a_, memptr_)), + /* 0x07 RLCA */ StdInstr({MicroOp::RLCA}), + /* 0x08 EX AF, AF' */ StdInstr({MicroOp::ExAFAFDash}), /* 0x09 ADD HL, BC */ ADD16(index, bc_), + /* 0x0a LD A, (BC) */ StdInstr({MicroOp::Move16, &bc_.full, &memptr_.full}, Read(memptr_, a_)), /* 0x0b DEC BC; 0x0c INC C; 0x0d DEC C; 0x0e LD C, n */ DEC_INC_DEC_LD(bc_, bc_.bytes.low), - /* 0x0f RRCA */ Program({MicroOp::RRCA}), - /* 0x10 DJNZ */ Program(WAIT(1), FETCH(temp8_, pc_), {MicroOp::DJNZ}, WAIT(5), {MicroOp::CalculateIndexAddress, &pc_.full}, {MicroOp::Move16, &memptr_.full, &pc_.full}), - /* 0x11 LD DE, nn */ Program(FETCH16(de_, pc_)), - /* 0x12 LD (DE), A */ Program({MicroOp::Move16, &de_.full, &memptr_.full}, STORE(a_, memptr_)), + /* 0x0f RRCA */ StdInstr({MicroOp::RRCA}), + /* 0x10 DJNZ */ Instr(3, ReadInc(pc_, temp8_), {MicroOp::DJNZ}, InternalOperation(5), {MicroOp::CalculateIndexAddress, &pc_.full}, {MicroOp::Move16, &memptr_.full, &pc_.full}), + /* 0x11 LD DE, nn */ StdInstr(Read16Inc(pc_, de_)), + /* 0x12 LD (DE), A */ StdInstr({MicroOp::Move16, &de_.full, &memptr_.full}, Write(memptr_, a_)), /* 0x13 INC DE; 0x14 INC D; 0x15 DEC D; 0x16 LD D, n */ INC_INC_DEC_LD(de_, de_.bytes.high), - /* 0x17 RLA */ Program({MicroOp::RLA}), - /* 0x18 JR */ Program(FETCH(temp8_, pc_), WAIT(5), {MicroOp::CalculateIndexAddress, &pc_.full}, {MicroOp::Move16, &memptr_.full, &pc_.full}), + /* 0x17 RLA */ StdInstr({MicroOp::RLA}), + /* 0x18 JR */ StdInstr(ReadInc(pc_, temp8_), InternalOperation(5), {MicroOp::CalculateIndexAddress, &pc_.full}, {MicroOp::Move16, &memptr_.full, &pc_.full}), /* 0x19 ADD HL, DE */ ADD16(index, de_), - /* 0x1a LD A, (DE) */ Program({MicroOp::Move16, &de_.full, &memptr_.full}, FETCH(a_, memptr_)), + /* 0x1a LD A, (DE) */ StdInstr({MicroOp::Move16, &de_.full, &memptr_.full}, Read(memptr_, a_)), /* 0x1b DEC DE; 0x1c INC E; 0x1d DEC E; 0x1e LD E, n */ DEC_INC_DEC_LD(de_, de_.bytes.low), - /* 0x1f RRA */ Program({MicroOp::RRA}), - /* 0x20 JR NZ */ JR(TestNZ), /* 0x21 LD HL, nn */ Program(FETCH16(index, pc_)), - /* 0x22 LD (nn), HL */ Program(FETCH16(temp16_, pc_), STORE16L(index, temp16_)), + /* 0x1f RRA */ StdInstr({MicroOp::RRA}), + /* 0x20 JR NZ */ JR(TestNZ), /* 0x21 LD HL, nn */ StdInstr(Read16Inc(pc_, index)), + /* 0x22 LD (nn), HL */ StdInstr(Read16Inc(pc_, temp16_), Write16(temp16_, index)), /* 0x23 INC HL; 0x24 INC H; 0x25 DEC H; 0x26 LD H, n */ INC_INC_DEC_LD(index, index.bytes.high), - /* 0x27 DAA */ Program({MicroOp::DAA}), + /* 0x27 DAA */ StdInstr({MicroOp::DAA}), /* 0x28 JR Z */ JR(TestZ), /* 0x29 ADD HL, HL */ ADD16(index, index), - /* 0x2a LD HL, (nn) */ Program(FETCH16(temp16_, pc_), FETCH16L(index, temp16_)), + /* 0x2a LD HL, (nn) */ StdInstr(Read16Inc(pc_, temp16_), Read16(temp16_, index)), /* 0x2b DEC HL; 0x2c INC L; 0x2d DEC L; 0x2e LD L, n */ DEC_INC_DEC_LD(index, index.bytes.low), - /* 0x2f CPL */ Program({MicroOp::CPL}), - /* 0x30 JR NC */ JR(TestNC), /* 0x31 LD SP, nn */ Program(FETCH16(sp_, pc_)), - /* 0x32 LD (nn), A */ Program(FETCH16(temp16_, pc_), STOREL(a_, temp16_)), - /* 0x33 INC SP */ Program(WAIT(2), {MicroOp::Increment16, &sp_.full}), - /* 0x34 INC (HL) */ Program(INDEX(), FETCHL(temp8_, INDEX_ADDR()), WAIT(1), {MicroOp::Increment8, &temp8_}, STOREL(temp8_, INDEX_ADDR())), - /* 0x35 DEC (HL) */ Program(INDEX(), FETCHL(temp8_, INDEX_ADDR()), WAIT(1), {MicroOp::Decrement8, &temp8_}, STOREL(temp8_, INDEX_ADDR())), - /* 0x36 LD (HL), n */ Program({MicroOp::IndexedPlaceHolder}, FETCH(temp8_, pc_), {MicroOp::CalculateIndexAddress, &index}, FETCH(temp8_, pc_), WAIT(add_offsets ? 2 : 0), STOREL(temp8_, INDEX_ADDR())), - /* 0x37 SCF */ Program({MicroOp::SCF}), + /* 0x2f CPL */ StdInstr({MicroOp::CPL}), + /* 0x30 JR NC */ JR(TestNC), /* 0x31 LD SP, nn */ StdInstr(Read16Inc(pc_, sp_)), + /* 0x32 LD (nn), A */ StdInstr(Read16Inc(pc_, temp16_), Write(temp16_, a_)), + /* 0x33 INC SP */ Instr(4, {MicroOp::Increment16, &sp_.full}), + /* 0x34 INC (HL) */ StdInstr(INDEX(), Read4(INDEX_ADDR(), temp8_), {MicroOp::Increment8, &temp8_}, Write3(INDEX_ADDR(), temp8_)), + /* 0x35 DEC (HL) */ StdInstr(INDEX(), Read4(INDEX_ADDR(), temp8_), {MicroOp::Decrement8, &temp8_}, Write3(INDEX_ADDR(), temp8_)), + /* 0x36 LD (HL), n */ StdInstr({MicroOp::IndexedPlaceHolder}, ReadInc(pc_, temp8_), {MicroOp::CalculateIndexAddress, &index}, Read(pc_, temp8_), Write(INDEX_ADDR(), temp8_)), // WAIT(add_offsets ? 2 : 0), + /* 0x37 SCF */ StdInstr({MicroOp::SCF}), /* 0x38 JR C */ JR(TestC), /* 0x39 ADD HL, SP */ ADD16(index, sp_), - /* 0x3a LD A, (nn) */ Program(FETCH16(memptr_, pc_), FETCH(a_, memptr_)), - /* 0x3b DEC SP */ Program(WAIT(2), {MicroOp::Decrement16, &sp_.full}), + /* 0x3a LD A, (nn) */ StdInstr(Read16Inc(pc_, memptr_), Read(memptr_, a_)), + /* 0x3b DEC SP */ Instr(4, {MicroOp::Decrement16, &sp_.full}), /* 0x3c INC A; 0x3d DEC A; 0x3e LD A, n */ INC_DEC_LD(a_), - /* 0x3f CCF */ Program({MicroOp::CCF}), + /* 0x3f CCF */ StdInstr({MicroOp::CCF}), /* 0x40 LD B, B; 0x41 LD B, C; 0x42 LD B, D; 0x43 LD B, E; 0x44 LD B, H; 0x45 LD B, L; 0x46 LD B, (HL); 0x47 LD B, A */ LD_GROUP(bc_.bytes.high, bc_.bytes.high), @@ -610,14 +610,14 @@ template class Processor { /* 0x68 LD L, B; 0x69 LD L, C; 0x6a LD L, D; 0x6b LD L, E; 0x6c LD L, H; 0x6d LD H, L; 0x6e LD L, (HL); 0x6f LD L, A */ LD_GROUP(index.bytes.low, hl_.bytes.low), - /* 0x70 LD (HL), B */ Program(INDEX(), STOREL(bc_.bytes.high, INDEX_ADDR())), - /* 0x71 LD (HL), C */ Program(INDEX(), STOREL(bc_.bytes.low, INDEX_ADDR())), - /* 0x72 LD (HL), D */ Program(INDEX(), STOREL(de_.bytes.high, INDEX_ADDR())), - /* 0x73 LD (HL), E */ Program(INDEX(), STOREL(de_.bytes.low, INDEX_ADDR())), - /* 0x74 LD (HL), H */ Program(INDEX(), STOREL(hl_.bytes.high, INDEX_ADDR())), // neither of these stores parts of the index register; - /* 0x75 LD (HL), L */ Program(INDEX(), STOREL(hl_.bytes.low, INDEX_ADDR())), // they always store exactly H and L. - /* 0x76 HALT */ Program({MicroOp::HALT}), - /* 0x77 LD (HL), A */ Program(INDEX(), STOREL(a_, INDEX_ADDR())), + /* 0x70 LD (HL), B */ StdInstr(INDEX(), Write(INDEX_ADDR(), bc_.bytes.high)), + /* 0x71 LD (HL), C */ StdInstr(INDEX(), Write(INDEX_ADDR(), bc_.bytes.low)), + /* 0x72 LD (HL), D */ StdInstr(INDEX(), Write(INDEX_ADDR(), de_.bytes.high)), + /* 0x73 LD (HL), E */ StdInstr(INDEX(), Write(INDEX_ADDR(), de_.bytes.low)), + /* 0x74 LD (HL), H */ StdInstr(INDEX(), Write(INDEX_ADDR(), hl_.bytes.high)), // neither of these stores parts of the index register; + /* 0x75 LD (HL), L */ StdInstr(INDEX(), Write(INDEX_ADDR(), hl_.bytes.low)), // they always store exactly H and L. + /* 0x76 HALT */ StdInstr({MicroOp::HALT}), + /* 0x77 LD (HL), A */ StdInstr(INDEX(), Write(INDEX_ADDR(), a_)), /* 0x78 LD A, B; 0x79 LD A, C; 0x7a LD A, D; 0x7b LD A, E; 0x7c LD A, H; 0x7d LD A, L; 0x7e LD A, (HL); 0x7f LD A, A */ LD_GROUP(a_, a_), From 6a769d39530c1a0ac7dbbd3639c4ca2b551075d8 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 18 Jun 2017 20:34:46 -0400 Subject: [PATCH 17/55] Finally dipped below the 20 error threshold that the compiler tops out at. --- Processors/Z80/Z80.hpp | 56 +++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/Processors/Z80/Z80.hpp b/Processors/Z80/Z80.hpp index 159df8f86..ce5e66486 100644 --- a/Processors/Z80/Z80.hpp +++ b/Processors/Z80/Z80.hpp @@ -310,7 +310,7 @@ template class Processor { #define NOP Sequence(BusOp(Refresh(2))) #define JP(cc) StdInstr(Read16Inc(pc_, temp16_), {MicroOp::cc}, {MicroOp::Move16, &temp16_.full, &pc_.full}) -#define CALL(cc) StdInstr(Read16Inc(pc_, temp16_), {MicroOp::cc}, WAIT(1), PUSH(pc_), {MicroOp::Move16, &temp16_.full, &pc_.full}) +#define CALL(cc) StdInstr(Read16Inc(pc_, temp16_), {MicroOp::cc}, Push(pc_), {MicroOp::Move16, &temp16_.full, &pc_.full}) // WAIT(1), #define RET(cc) Instr(3, {MicroOp::cc}, Pop(memptr_), {MicroOp::Move16, &memptr_.full, &pc_.full}) #define JR(cc) StdInstr(ReadInc(pc_, temp8_), {MicroOp::cc}, InternalOperation(5), {MicroOp::CalculateIndexAddress, &pc_.full}, {MicroOp::Move16, &memptr_.full, &pc_.full}) #define RST() Instr(3, {MicroOp::CalculateRSTDestination}, Push(pc_), {MicroOp::Move16, &memptr_.full, &pc_.full}) @@ -646,45 +646,45 @@ template class Processor { /* 0xb8 CP B; 0xb9 CP C; 0xba CP D; 0xbb CP E; 0xbc CP H; 0xbd CP L; 0xbe CP (HL); 0xbf CP A */ READ_OP_GROUP(CP8), - /* 0xc0 RET NZ */ RET(TestNZ), /* 0xc1 POP BC */ Program(POP(bc_)), - /* 0xc2 JP NZ */ JP(TestNZ), /* 0xc3 JP nn */ Program(FETCH16L(temp16_, pc_), {MicroOp::Move16, &temp16_.full, &pc_.full}), - /* 0xc4 CALL NZ */ CALL(TestNZ), /* 0xc5 PUSH BC */ Program(WAIT(1), PUSH(bc_)), - /* 0xc6 ADD A, n */ Program(FETCH(temp8_, pc_), {MicroOp::ADD8, &temp8_}), + /* 0xc0 RET NZ */ RET(TestNZ), /* 0xc1 POP BC */ StdInstr(Pop(bc_)), + /* 0xc2 JP NZ */ JP(TestNZ), /* 0xc3 JP nn */ StdInstr(Fetch16(pc_, temp16_), {MicroOp::Move16, &temp16_.full, &pc_.full}), + /* 0xc4 CALL NZ */ CALL(TestNZ), /* 0xc5 PUSH BC */ Instr(3, PUSH(bc_)), + /* 0xc6 ADD A, n */ StdInstr(ReadInc(pc_, temp8_), {MicroOp::ADD8, &temp8_}), /* 0xc7 RST 00h */ RST(), - /* 0xc8 RET Z */ RET(TestZ), /* 0xc9 RET */ Program(POP(pc_)), + /* 0xc8 RET Z */ RET(TestZ), /* 0xc9 RET */ StdInstr(Pop(pc_)), /* 0xca JP Z */ JP(TestZ), /* 0xcb [CB page] */Program(FINDEX(), {MicroOp::SetInstructionPage, &cb_page}), /* 0xcc CALL Z */ CALL(TestZ), /* 0xcd CALL */ Program(FETCH16(temp16_, pc_), WAIT(1), PUSH(pc_), {MicroOp::Move16, &temp16_.full, &pc_.full}), - /* 0xce ADC A, n */ Program(FETCH(temp8_, pc_), {MicroOp::ADC8, &temp8_}), + /* 0xce ADC A, n */ StdInstr(ReadInc(pc_, temp8_), {MicroOp::ADC8, &temp8_}), /* 0xcf RST 08h */ RST(), - /* 0xd0 RET NC */ RET(TestNC), /* 0xd1 POP DE */ Program(POP(de_)), + /* 0xd0 RET NC */ RET(TestNC), /* 0xd1 POP DE */ StdInstr(Pop(de_)), /* 0xd2 JP NC */ JP(TestNC), /* 0xd3 OUT (n), A */Program(FETCH(temp16_.bytes.low, pc_), {MicroOp::Move8, &a_, &temp16_.bytes.high}, OUT(temp16_, a_)), - /* 0xd4 CALL NC */ CALL(TestNC), /* 0xd5 PUSH DE */ Program(WAIT(1), PUSH(de_)), - /* 0xd6 SUB n */ Program(FETCH(temp8_, pc_), {MicroOp::SUB8, &temp8_}), + /* 0xd4 CALL NC */ CALL(TestNC), /* 0xd5 PUSH DE */ Instr(3, PUSH(de_)), + /* 0xd6 SUB n */ StdInstr(ReadInc(pc_, temp8_), {MicroOp::SUB8, &temp8_}), /* 0xd7 RST 10h */ RST(), - /* 0xd8 RET C */ RET(TestC), /* 0xd9 EXX */ Program({MicroOp::EXX}), + /* 0xd8 RET C */ RET(TestC), /* 0xd9 EXX */ StdInstr({MicroOp::EXX}), /* 0xda JP C */ JP(TestC), /* 0xdb IN A, (n) */Program(FETCH(temp16_.bytes.low, pc_), {MicroOp::Move8, &a_, &temp16_.bytes.high}, IN(temp16_, a_)), - /* 0xdc CALL C */ CALL(TestC), /* 0xdd [DD page] */Program({MicroOp::SetInstructionPage, &dd_page_}), - /* 0xde SBC A, n */ Program(FETCH(temp8_, pc_), {MicroOp::SBC8, &temp8_}), + /* 0xdc CALL C */ CALL(TestC), /* 0xdd [DD page] */StdInstr({MicroOp::SetInstructionPage, &dd_page_}), + /* 0xde SBC A, n */ StdInstr(ReadInc(pc_, temp8_), {MicroOp::SBC8, &temp8_}), /* 0xdf RST 18h */ RST(), - /* 0xe0 RET PO */ RET(TestPO), /* 0xe1 POP HL */ Program(POP(index)), + /* 0xe0 RET PO */ RET(TestPO), /* 0xe1 POP HL */ StdInstr(Pop(index)), /* 0xe2 JP PO */ JP(TestPO), /* 0xe3 EX (SP), HL */Program(POP(memptr_), WAIT(1), PUSH(index), WAIT(2), {MicroOp::Move16, &memptr_.full, &index.full}), - /* 0xe4 CALL PO */ CALL(TestPO), /* 0xe5 PUSH HL */ Program(WAIT(1), PUSH(index)), - /* 0xe6 AND n */ Program(FETCH(temp8_, pc_), {MicroOp::And, &temp8_}), + /* 0xe4 CALL PO */ CALL(TestPO), /* 0xe5 PUSH HL */ Instr(3, PUSH(index)), + /* 0xe6 AND n */ StdInstr(ReadInc(pc_, temp8_), {MicroOp::And, &temp8_}), /* 0xe7 RST 20h */ RST(), - /* 0xe8 RET PE */ RET(TestPE), /* 0xe9 JP (HL) */ Program({MicroOp::Move16, &index.full, &pc_.full}), - /* 0xea JP PE */ JP(TestPE), /* 0xeb EX DE, HL */Program({MicroOp::ExDEHL}), - /* 0xec CALL PE */ CALL(TestPE), /* 0xed [ED page] */Program({MicroOp::SetInstructionPage, &ed_page_}), - /* 0xee XOR n */ Program(FETCH(temp8_, pc_), {MicroOp::Xor, &temp8_}), + /* 0xe8 RET PE */ RET(TestPE), /* 0xe9 JP (HL) */ StdInstr({MicroOp::Move16, &index.full, &pc_.full}), + /* 0xea JP PE */ JP(TestPE), /* 0xeb EX DE, HL */StdInstr({MicroOp::ExDEHL}), + /* 0xec CALL PE */ CALL(TestPE), /* 0xed [ED page] */StdInstr({MicroOp::SetInstructionPage, &ed_page_}), + /* 0xee XOR n */ StdInstr(ReadInc(pc_, temp8_), {MicroOp::Xor, &temp8_}), /* 0xef RST 28h */ RST(), - /* 0xf0 RET p */ RET(TestP), /* 0xf1 POP AF */ Program(POP(temp16_), {MicroOp::DisassembleAF}), - /* 0xf2 JP P */ JP(TestP), /* 0xf3 DI */ Program({MicroOp::DI}), - /* 0xf4 CALL P */ CALL(TestP), /* 0xf5 PUSH AF */ Program(WAIT(1), {MicroOp::AssembleAF}, PUSH(temp16_)), - /* 0xf6 OR n */ Program(FETCH(temp8_, pc_), {MicroOp::Or, &temp8_}), + /* 0xf0 RET p */ RET(TestP), /* 0xf1 POP AF */ StdInstr(Pop(temp16_), {MicroOp::DisassembleAF}), + /* 0xf2 JP P */ JP(TestP), /* 0xf3 DI */ StdInstr({MicroOp::DI}), + /* 0xf4 CALL P */ CALL(TestP), /* 0xf5 PUSH AF */ Instr(3, {MicroOp::AssembleAF}, PUSH(temp16_)), + /* 0xf6 OR n */ StdInstr(ReadInc(pc_, temp8_), {MicroOp::Or, &temp8_}), /* 0xf7 RST 30h */ RST(), - /* 0xf8 RET M */ RET(TestM), /* 0xf9 LD SP, HL */Program(WAIT(2), {MicroOp::Move16, &index.full, &sp_.full}), - /* 0xfa JP M */ JP(TestM), /* 0xfb EI */ Program({MicroOp::EI}), - /* 0xfc CALL M */ CALL(TestM), /* 0xfd [FD page] */Program({MicroOp::SetInstructionPage, &fd_page_}), - /* 0xfe CP n */ Program(FETCH(temp8_, pc_), {MicroOp::CP8, &temp8_}), + /* 0xf8 RET M */ RET(TestM), /* 0xf9 LD SP, HL */Instr(4, {MicroOp::Move16, &index.full, &sp_.full}), + /* 0xfa JP M */ JP(TestM), /* 0xfb EI */ StdInstr({MicroOp::EI}), + /* 0xfc CALL M */ CALL(TestM), /* 0xfd [FD page] */StdInstr({MicroOp::SetInstructionPage, &fd_page_}), + /* 0xfe CP n */ StdInstr(ReadInc(pc_, temp8_), {MicroOp::CP8, &temp8_}), /* 0xff RST 38h */ RST(), }; assemble_cb_page(cb_page, index, add_offsets); From cb140aa06e451ee6a55f1091ae8c6b818a9aec06 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 18 Jun 2017 21:00:44 -0400 Subject: [PATCH 18/55] Managed to navigate back to building. --- Processors/Z80/Z80.hpp | 128 +++++++++++++++++++++-------------------- 1 file changed, 66 insertions(+), 62 deletions(-) diff --git a/Processors/Z80/Z80.hpp b/Processors/Z80/Z80.hpp index ce5e66486..927e66a8f 100644 --- a/Processors/Z80/Z80.hpp +++ b/Processors/Z80/Z80.hpp @@ -84,25 +84,25 @@ struct MachineCycle { }; // Elemental bus operations -#define ReadOpcodeStart(addr, val) {MachineCycle::ReadOpcode, MachineCycle::Phase::Start, 2, addr, val, false} -#define ReadOpcodeWait(addr, val) {MachineCycle::ReadOpcode, MachineCycle::Phase::Wait, 1, addr, val, true} +#define ReadOpcodeStart(addr, val) {MachineCycle::ReadOpcode, MachineCycle::Phase::Start, 2, &addr.full, &val, false} +#define ReadOpcodeWait(addr, val) {MachineCycle::ReadOpcode, MachineCycle::Phase::Wait, 1, &addr.full, &val, true} #define Refresh(len) {MachineCycle::Refresh, MachineCycle::Phase::Start, 2, &ir_.full, nullptr, false} -#define ReadStart(addr, val) {MachineCycle::Read, MachineCycle::Phase::Start, 2, addr, val, false} -#define ReadWait(l, addr, val, f) {MachineCycle::Read, MachineCycle::Phase::Wait, l, addr, val, f} -#define ReadEnd(addr, val) {MachineCycle::Read, MachineCycle::Phase::End, 1, addr, val, false} +#define ReadStart(addr, val) {MachineCycle::Read, MachineCycle::Phase::Start, 2, &addr.full, &val, false} +#define ReadWait(l, addr, val, f) {MachineCycle::Read, MachineCycle::Phase::Wait, l, &addr.full, &val, f} +#define ReadEnd(addr, val) {MachineCycle::Read, MachineCycle::Phase::End, 1, &addr.full, &val, false} -#define WriteStart(addr, val) {MachineCycle::Write, MachineCycle::Phase::Start, 2, addr, val, false} -#define WriteWait(l, addr, val, f) {MachineCycle::Write, MachineCycle::Phase::Wait, l, addr, val, f} -#define WriteEnd(addr, val) {MachineCycle::Write, MachineCycle::Phase::End, 1, addr, val, false} +#define WriteStart(addr, val) {MachineCycle::Write, MachineCycle::Phase::Start, 2, &addr.full, &val, false} +#define WriteWait(l, addr, val, f) {MachineCycle::Write, MachineCycle::Phase::Wait, l, &addr.full, &val, f} +#define WriteEnd(addr, val) {MachineCycle::Write, MachineCycle::Phase::End, 1, &addr.full, &val, false} -#define InputStart(addr, val) {MachineCycle::Input, MachineCycle::Phase::Start, 2, addr, val, false} -#define InputWait(addr, val, f) {MachineCycle::Input, MachineCycle::Phase::Wait, 1, addr, val, f} -#define InputEnd(addr, val) {MachineCycle::Input, MachineCycle::Phase::End, 1, addr, val, false} +#define InputStart(addr, val) {MachineCycle::Input, MachineCycle::Phase::Start, 2, &addr.full, &val, false} +#define InputWait(addr, val, f) {MachineCycle::Input, MachineCycle::Phase::Wait, 1, &addr.full, &val, f} +#define InputEnd(addr, val) {MachineCycle::Input, MachineCycle::Phase::End, 1, &addr.full, &val, false} -#define OutpuStart(addr, val) {MachineCycle::Output, MachineCycle::Phase::Start, 2, addr, val} -#define OutpuWait(addr, val, f) {MachineCycle::Output, MachineCycle::Phase::Wait, 1, addr, val, f} -#define OutpuEnd(addr, val) {MachineCycle::Output, MachineCycle::Phase::End, 1, addr, val} +#define OutputStart(addr, val) {MachineCycle::Output, MachineCycle::Phase::Start, 2, &addr.full, &val} +#define OutputWait(addr, val, f) {MachineCycle::Output, MachineCycle::Phase::Wait, 1, &addr.full, &val, f} +#define OutputEnd(addr, val) {MachineCycle::Output, MachineCycle::Phase::End, 1, &addr.full, &val} // A wrapper to express a bus operation as a micro-op #define BusOp(op) {MicroOp::BusOperation, nullptr, nullptr, op} @@ -116,7 +116,7 @@ struct MachineCycle { #define Input(addr, val) BusOp(InputStart(addr, val)), BusOp(InputWait(addr, val, false)), BusOp(InputWait(addr, val, true)), BusOp(InputEnd(addr, val)) #define Output(addr, val) BusOp(OutputStart(addr, val)), BusOp(OutputWait(addr, val, false)), BusOp(OutputWait(addr, val, true)), BusOp(OutputEnd(addr, val)) -#define InternalOperation(len) {MicroOp::BusOperation, nullptr, nullptr, {MachineCycle::Internal, len}} +#define InternalOperation(len) {MicroOp::BusOperation, nullptr, nullptr, {MachineCycle::Internal, MachineCycle::Phase::Start, len}} /// A sequence is a series of micro-ops that ends in a move-to-next-program operation. #define Sequence(...) { __VA_ARGS__, {MicroOp::MoveToNextProgram} } @@ -295,7 +295,7 @@ template class Processor { #define WriteInc(addr, val) Write3(addr, val), {MicroOp::Increment16, &addr.full} #define Read16Inc(addr, val) ReadInc(addr, val.bytes.low), ReadInc(addr, val.bytes.high) -#define Read16(addr, val) ReadInc(addr, val.bytes.low), Read(addr, val.bytes.high) +#define Read16(addr, val) ReadInc(addr, val.bytes.low), Read3(addr, val.bytes.high) #define Write16(addr, val) WriteInc(addr, val.bytes.low), Write3(addr, val.bytes.high) @@ -364,9 +364,9 @@ template class Processor { Instr(4, Read4(INDEX_ADDR(), temp8_), {MicroOp::op, &temp8_}), \ Instr(4, Read4(INDEX_ADDR(), temp8_), {MicroOp::op, &temp8_}) -#define ADD16(d, s) Program(InternalOperation(4), InternalOperation(3), {MicroOp::ADD16, &s.full, &d.full}) -#define ADC16(d, s) Program(InternalOperation(4), InternalOperation(3), {MicroOp::ADC16, &s.full, &d.full}) -#define SBC16(d, s) Program(InternalOperation(4), InternalOperation(3), {MicroOp::SBC16, &s.full, &d.full}) +#define ADD16(d, s) StdInstr(InternalOperation(4), InternalOperation(3), {MicroOp::ADD16, &s.full, &d.full}) +#define ADC16(d, s) StdInstr(InternalOperation(4), InternalOperation(3), {MicroOp::ADC16, &s.full, &d.full}) +#define SBC16(d, s) StdInstr(InternalOperation(4), InternalOperation(3), {MicroOp::SBC16, &s.full, &d.full}) #define isTerminal(n) (n == MicroOp::MoveToNextProgram || n == MicroOp::DecodeOperation || n == MicroOp::DecodeOperationNoRChange) @@ -449,15 +449,15 @@ template class Processor { /* 0x64 NEG */ StdInstr({MicroOp::NEG}), /* 0x65 RETN */ StdInstr(Pop(pc_), {MicroOp::RETN}), /* 0x66 IM 0 */ StdInstr({MicroOp::IM}), /* 0x67 RRD */ StdInstr(Read3(hl_, temp8_), InternalOperation(4), {MicroOp::RRD}, Write3(hl_, temp8_)), /* 0x40 IN B, (C); 0x41 OUT (C), B */ IN_OUT(hl_.bytes.low), - /* 0x6a ADC HL, HL */ ADC16(hl_, hl_), /* 0x6b LD HL, (nn) */ StdInstr(Read16Inc(pc_, temp16_), Store16(temp16_, hl_)), + /* 0x6a ADC HL, HL */ ADC16(hl_, hl_), /* 0x6b LD HL, (nn) */ StdInstr(Read16Inc(pc_, temp16_), Write16(temp16_, hl_)), /* 0x6c NEG */ StdInstr({MicroOp::NEG}), /* 0x6d RETN */ StdInstr(Pop(pc_), {MicroOp::RETN}), /* 0x6e IM 0/1 */ StdInstr({MicroOp::IM}), /* 0x6f RLD */ StdInstr(Read3(hl_, temp8_), InternalOperation(4), {MicroOp::RLD}, Write3(hl_, temp8_)), - /* 0x70 IN (C) */ IN_C(temp8_), /* 0x71 OUT (C), 0 */ StdInstr({MicroOp::SetZero}, OUT(bc_, temp8_)), - /* 0x72 SBC HL, SP */ SBC16(hl_, sp_), /* 0x73 LD (nn), SP */ StdInstr(Read16Inc(pc_, temp16_), Store16(temp16_, sp_)), + /* 0x70 IN (C) */ IN_C(temp8_), /* 0x71 OUT (C), 0 */ StdInstr({MicroOp::SetZero}, Output(bc_, temp8_)), + /* 0x72 SBC HL, SP */ SBC16(hl_, sp_), /* 0x73 LD (nn), SP */ StdInstr(Read16Inc(pc_, temp16_), Write16(temp16_, sp_)), /* 0x74 NEG */ StdInstr({MicroOp::NEG}), /* 0x75 RETN */ StdInstr(Pop(pc_), {MicroOp::RETN}), /* 0x76 IM 1 */ StdInstr({MicroOp::IM}), /* 0x77 XX */ NOP, /* 0x40 IN B, (C); 0x41 OUT (C), B */ IN_OUT(a_), - /* 0x7a ADC HL, SP */ ADC16(hl_, sp_), /* 0x7b LD SP, (nn) */ StdInstr(Read16Inc(pc_, temp16_), Store16(temp16_, sp_)), + /* 0x7a ADC HL, SP */ ADC16(hl_, sp_), /* 0x7b LD SP, (nn) */ StdInstr(Read16Inc(pc_, temp16_), Write16(temp16_, sp_)), /* 0x7c NEG */ StdInstr({MicroOp::NEG}), /* 0x7d RETN */ StdInstr(Pop(pc_), {MicroOp::RETN}), /* 0x7e IM 2 */ StdInstr({MicroOp::IM}), /* 0x7f XX */ NOP, NOP_ROW(), /* 0x80 */ @@ -475,12 +475,12 @@ template class Processor { /* 0xb0 LDIR */ StdInstr(Read3(hl_, temp8_), Write5(de_, temp8_), {MicroOp::LDIR}, InternalOperation(5)), /* 0xb1 CPIR */ StdInstr(Read3(hl_, temp8_), InternalOperation(5), {MicroOp::CPIR}, InternalOperation(5)), /* 0xb2 INIR */ Instr(3, Input(bc_, temp8_), Write3(hl_, temp8_), {MicroOp::INIR}, InternalOperation(5)), - /* 0xb3 OTIR */ Instr(3, Read(hl_, temp8_), {MicroOp::OUTI}, Output(bc_, temp8_), {MicroOp::OUT_R}, InternalOperation(5)), + /* 0xb3 OTIR */ Instr(3, Read3(hl_, temp8_), {MicroOp::OUTI}, Output(bc_, temp8_), {MicroOp::OUT_R}, InternalOperation(5)), NOP, NOP, NOP, NOP, /* 0xb8 LDDR */ StdInstr(Read3(hl_, temp8_), Write5(de_, temp8_), {MicroOp::LDDR}, InternalOperation(5)), /* 0xb9 CPDR */ StdInstr(Read3(hl_, temp8_), InternalOperation(5), {MicroOp::CPDR}, InternalOperation(5)), /* 0xba INDR */ Instr(3, Input(bc_, temp8_), Write3(hl_, temp8_), {MicroOp::INDR}, InternalOperation(5)), - /* 0xbb OTDR */ Instr(3, Read3(hl_, temp8_), {MicroOp::OUTD}, OUT(bc_, temp8_), {MicroOp::OUT_R}, InternalOperation(5)), + /* 0xbb OTDR */ Instr(3, Read3(hl_, temp8_), {MicroOp::OUTD}, Output(bc_, temp8_), {MicroOp::OUT_R}, InternalOperation(5)), NOP, NOP, NOP, NOP, NOP_ROW(), /* 0xc0 */ NOP_ROW(), /* 0xd0 */ @@ -532,14 +532,14 @@ template class Processor { InstructionTable base_program_table = { /* 0x00 NOP */ NOP, /* 0x01 LD BC, nn */ StdInstr(Read16(pc_, bc_)), - /* 0x02 LD (BC), A */ StdInstr({MicroOp::Move16, &bc_.full, &memptr_.full}, Write(memptr_, a_)), + /* 0x02 LD (BC), A */ StdInstr({MicroOp::Move16, &bc_.full, &memptr_.full}, Write3(memptr_, a_)), /* 0x03 INC BC; 0x04 INC B; 0x05 DEC B; 0x06 LD B, n */ INC_INC_DEC_LD(bc_, bc_.bytes.high), /* 0x07 RLCA */ StdInstr({MicroOp::RLCA}), /* 0x08 EX AF, AF' */ StdInstr({MicroOp::ExAFAFDash}), /* 0x09 ADD HL, BC */ ADD16(index, bc_), - /* 0x0a LD A, (BC) */ StdInstr({MicroOp::Move16, &bc_.full, &memptr_.full}, Read(memptr_, a_)), + /* 0x0a LD A, (BC) */ StdInstr({MicroOp::Move16, &bc_.full, &memptr_.full}, Read3(memptr_, a_)), /* 0x0b DEC BC; 0x0c INC C; 0x0d DEC C; 0x0e LD C, n */ DEC_INC_DEC_LD(bc_, bc_.bytes.low), @@ -547,7 +547,7 @@ template class Processor { /* 0x0f RRCA */ StdInstr({MicroOp::RRCA}), /* 0x10 DJNZ */ Instr(3, ReadInc(pc_, temp8_), {MicroOp::DJNZ}, InternalOperation(5), {MicroOp::CalculateIndexAddress, &pc_.full}, {MicroOp::Move16, &memptr_.full, &pc_.full}), /* 0x11 LD DE, nn */ StdInstr(Read16Inc(pc_, de_)), - /* 0x12 LD (DE), A */ StdInstr({MicroOp::Move16, &de_.full, &memptr_.full}, Write(memptr_, a_)), + /* 0x12 LD (DE), A */ StdInstr({MicroOp::Move16, &de_.full, &memptr_.full}, Write3(memptr_, a_)), /* 0x13 INC DE; 0x14 INC D; 0x15 DEC D; 0x16 LD D, n */ INC_INC_DEC_LD(de_, de_.bytes.high), @@ -555,7 +555,7 @@ template class Processor { /* 0x17 RLA */ StdInstr({MicroOp::RLA}), /* 0x18 JR */ StdInstr(ReadInc(pc_, temp8_), InternalOperation(5), {MicroOp::CalculateIndexAddress, &pc_.full}, {MicroOp::Move16, &memptr_.full, &pc_.full}), /* 0x19 ADD HL, DE */ ADD16(index, de_), - /* 0x1a LD A, (DE) */ StdInstr({MicroOp::Move16, &de_.full, &memptr_.full}, Read(memptr_, a_)), + /* 0x1a LD A, (DE) */ StdInstr({MicroOp::Move16, &de_.full, &memptr_.full}, Read3(memptr_, a_)), /* 0x1b DEC DE; 0x1c INC E; 0x1d DEC E; 0x1e LD E, n */ DEC_INC_DEC_LD(de_, de_.bytes.low), @@ -576,15 +576,15 @@ template class Processor { /* 0x2f CPL */ StdInstr({MicroOp::CPL}), /* 0x30 JR NC */ JR(TestNC), /* 0x31 LD SP, nn */ StdInstr(Read16Inc(pc_, sp_)), - /* 0x32 LD (nn), A */ StdInstr(Read16Inc(pc_, temp16_), Write(temp16_, a_)), + /* 0x32 LD (nn), A */ StdInstr(Read16Inc(pc_, temp16_), Write3(temp16_, a_)), /* 0x33 INC SP */ Instr(4, {MicroOp::Increment16, &sp_.full}), /* 0x34 INC (HL) */ StdInstr(INDEX(), Read4(INDEX_ADDR(), temp8_), {MicroOp::Increment8, &temp8_}, Write3(INDEX_ADDR(), temp8_)), /* 0x35 DEC (HL) */ StdInstr(INDEX(), Read4(INDEX_ADDR(), temp8_), {MicroOp::Decrement8, &temp8_}, Write3(INDEX_ADDR(), temp8_)), - /* 0x36 LD (HL), n */ StdInstr({MicroOp::IndexedPlaceHolder}, ReadInc(pc_, temp8_), {MicroOp::CalculateIndexAddress, &index}, Read(pc_, temp8_), Write(INDEX_ADDR(), temp8_)), // WAIT(add_offsets ? 2 : 0), + /* 0x36 LD (HL), n */ StdInstr({MicroOp::IndexedPlaceHolder}, ReadInc(pc_, temp8_), {MicroOp::CalculateIndexAddress, &index}, Read3(pc_, temp8_), Write3(INDEX_ADDR(), temp8_)), // WAIT(add_offsets ? 2 : 0), /* 0x37 SCF */ StdInstr({MicroOp::SCF}), /* 0x38 JR C */ JR(TestC), /* 0x39 ADD HL, SP */ ADD16(index, sp_), - /* 0x3a LD A, (nn) */ StdInstr(Read16Inc(pc_, memptr_), Read(memptr_, a_)), + /* 0x3a LD A, (nn) */ StdInstr(Read16Inc(pc_, memptr_), Read3(memptr_, a_)), /* 0x3b DEC SP */ Instr(4, {MicroOp::Decrement16, &sp_.full}), /* 0x3c INC A; 0x3d DEC A; 0x3e LD A, n */ @@ -610,14 +610,14 @@ template class Processor { /* 0x68 LD L, B; 0x69 LD L, C; 0x6a LD L, D; 0x6b LD L, E; 0x6c LD L, H; 0x6d LD H, L; 0x6e LD L, (HL); 0x6f LD L, A */ LD_GROUP(index.bytes.low, hl_.bytes.low), - /* 0x70 LD (HL), B */ StdInstr(INDEX(), Write(INDEX_ADDR(), bc_.bytes.high)), - /* 0x71 LD (HL), C */ StdInstr(INDEX(), Write(INDEX_ADDR(), bc_.bytes.low)), - /* 0x72 LD (HL), D */ StdInstr(INDEX(), Write(INDEX_ADDR(), de_.bytes.high)), - /* 0x73 LD (HL), E */ StdInstr(INDEX(), Write(INDEX_ADDR(), de_.bytes.low)), - /* 0x74 LD (HL), H */ StdInstr(INDEX(), Write(INDEX_ADDR(), hl_.bytes.high)), // neither of these stores parts of the index register; - /* 0x75 LD (HL), L */ StdInstr(INDEX(), Write(INDEX_ADDR(), hl_.bytes.low)), // they always store exactly H and L. + /* 0x70 LD (HL), B */ StdInstr(INDEX(), Write3(INDEX_ADDR(), bc_.bytes.high)), + /* 0x71 LD (HL), C */ StdInstr(INDEX(), Write3(INDEX_ADDR(), bc_.bytes.low)), + /* 0x72 LD (HL), D */ StdInstr(INDEX(), Write3(INDEX_ADDR(), de_.bytes.high)), + /* 0x73 LD (HL), E */ StdInstr(INDEX(), Write3(INDEX_ADDR(), de_.bytes.low)), + /* 0x74 LD (HL), H */ StdInstr(INDEX(), Write3(INDEX_ADDR(), hl_.bytes.high)), // neither of these stores parts of the index register; + /* 0x75 LD (HL), L */ StdInstr(INDEX(), Write3(INDEX_ADDR(), hl_.bytes.low)), // they always store exactly H and L. /* 0x76 HALT */ StdInstr({MicroOp::HALT}), - /* 0x77 LD (HL), A */ StdInstr(INDEX(), Write(INDEX_ADDR(), a_)), + /* 0x77 LD (HL), A */ StdInstr(INDEX(), Write3(INDEX_ADDR(), a_)), /* 0x78 LD A, B; 0x79 LD A, C; 0x7a LD A, D; 0x7b LD A, E; 0x7c LD A, H; 0x7d LD A, L; 0x7e LD A, (HL); 0x7f LD A, A */ LD_GROUP(a_, a_), @@ -647,28 +647,28 @@ template class Processor { READ_OP_GROUP(CP8), /* 0xc0 RET NZ */ RET(TestNZ), /* 0xc1 POP BC */ StdInstr(Pop(bc_)), - /* 0xc2 JP NZ */ JP(TestNZ), /* 0xc3 JP nn */ StdInstr(Fetch16(pc_, temp16_), {MicroOp::Move16, &temp16_.full, &pc_.full}), - /* 0xc4 CALL NZ */ CALL(TestNZ), /* 0xc5 PUSH BC */ Instr(3, PUSH(bc_)), + /* 0xc2 JP NZ */ JP(TestNZ), /* 0xc3 JP nn */ StdInstr(Read16(pc_, temp16_), {MicroOp::Move16, &temp16_.full, &pc_.full}), + /* 0xc4 CALL NZ */ CALL(TestNZ), /* 0xc5 PUSH BC */ Instr(3, Push(bc_)), /* 0xc6 ADD A, n */ StdInstr(ReadInc(pc_, temp8_), {MicroOp::ADD8, &temp8_}), /* 0xc7 RST 00h */ RST(), /* 0xc8 RET Z */ RET(TestZ), /* 0xc9 RET */ StdInstr(Pop(pc_)), - /* 0xca JP Z */ JP(TestZ), /* 0xcb [CB page] */Program(FINDEX(), {MicroOp::SetInstructionPage, &cb_page}), - /* 0xcc CALL Z */ CALL(TestZ), /* 0xcd CALL */ Program(FETCH16(temp16_, pc_), WAIT(1), PUSH(pc_), {MicroOp::Move16, &temp16_.full, &pc_.full}), + /* 0xca JP Z */ JP(TestZ), /* 0xcb [CB page] */StdInstr(FINDEX(), {MicroOp::SetInstructionPage, &cb_page}), + /* 0xcc CALL Z */ CALL(TestZ), /* 0xcd CALL */ StdInstr(Read16(pc_, temp16_), Push(pc_), {MicroOp::Move16, &temp16_.full, &pc_.full}), /* 0xce ADC A, n */ StdInstr(ReadInc(pc_, temp8_), {MicroOp::ADC8, &temp8_}), /* 0xcf RST 08h */ RST(), /* 0xd0 RET NC */ RET(TestNC), /* 0xd1 POP DE */ StdInstr(Pop(de_)), - /* 0xd2 JP NC */ JP(TestNC), /* 0xd3 OUT (n), A */Program(FETCH(temp16_.bytes.low, pc_), {MicroOp::Move8, &a_, &temp16_.bytes.high}, OUT(temp16_, a_)), - /* 0xd4 CALL NC */ CALL(TestNC), /* 0xd5 PUSH DE */ Instr(3, PUSH(de_)), + /* 0xd2 JP NC */ JP(TestNC), /* 0xd3 OUT (n), A */StdInstr(ReadInc(pc_, temp16_.bytes.low), {MicroOp::Move8, &a_, &temp16_.bytes.high}, Output(temp16_, a_)), + /* 0xd4 CALL NC */ CALL(TestNC), /* 0xd5 PUSH DE */ Instr(3, Push(de_)), /* 0xd6 SUB n */ StdInstr(ReadInc(pc_, temp8_), {MicroOp::SUB8, &temp8_}), /* 0xd7 RST 10h */ RST(), /* 0xd8 RET C */ RET(TestC), /* 0xd9 EXX */ StdInstr({MicroOp::EXX}), - /* 0xda JP C */ JP(TestC), /* 0xdb IN A, (n) */Program(FETCH(temp16_.bytes.low, pc_), {MicroOp::Move8, &a_, &temp16_.bytes.high}, IN(temp16_, a_)), + /* 0xda JP C */ JP(TestC), /* 0xdb IN A, (n) */StdInstr(ReadInc(pc_, temp16_.bytes.low), {MicroOp::Move8, &a_, &temp16_.bytes.high}, Input(temp16_, a_)), /* 0xdc CALL C */ CALL(TestC), /* 0xdd [DD page] */StdInstr({MicroOp::SetInstructionPage, &dd_page_}), /* 0xde SBC A, n */ StdInstr(ReadInc(pc_, temp8_), {MicroOp::SBC8, &temp8_}), /* 0xdf RST 18h */ RST(), /* 0xe0 RET PO */ RET(TestPO), /* 0xe1 POP HL */ StdInstr(Pop(index)), - /* 0xe2 JP PO */ JP(TestPO), /* 0xe3 EX (SP), HL */Program(POP(memptr_), WAIT(1), PUSH(index), WAIT(2), {MicroOp::Move16, &memptr_.full, &index.full}), - /* 0xe4 CALL PO */ CALL(TestPO), /* 0xe5 PUSH HL */ Instr(3, PUSH(index)), + /* 0xe2 JP PO */ JP(TestPO), /* 0xe3 EX (SP), HL */StdInstr(Pop(memptr_), Push(index), {MicroOp::Move16, &memptr_.full, &index.full}), // WAIT(1), WAIT(2), + /* 0xe4 CALL PO */ CALL(TestPO), /* 0xe5 PUSH HL */ Instr(3, Push(index)), /* 0xe6 AND n */ StdInstr(ReadInc(pc_, temp8_), {MicroOp::And, &temp8_}), /* 0xe7 RST 20h */ RST(), /* 0xe8 RET PE */ RET(TestPE), /* 0xe9 JP (HL) */ StdInstr({MicroOp::Move16, &index.full, &pc_.full}), @@ -678,7 +678,7 @@ template class Processor { /* 0xef RST 28h */ RST(), /* 0xf0 RET p */ RET(TestP), /* 0xf1 POP AF */ StdInstr(Pop(temp16_), {MicroOp::DisassembleAF}), /* 0xf2 JP P */ JP(TestP), /* 0xf3 DI */ StdInstr({MicroOp::DI}), - /* 0xf4 CALL P */ CALL(TestP), /* 0xf5 PUSH AF */ Instr(3, {MicroOp::AssembleAF}, PUSH(temp16_)), + /* 0xf4 CALL P */ CALL(TestP), /* 0xf5 PUSH AF */ Instr(3, {MicroOp::AssembleAF}, Push(temp16_)), /* 0xf6 OR n */ StdInstr(ReadInc(pc_, temp8_), {MicroOp::Or, &temp8_}), /* 0xf7 RST 30h */ RST(), /* 0xf8 RET M */ RET(TestM), /* 0xf9 LD SP, HL */Instr(4, {MicroOp::Move16, &index.full, &sp_.full}), @@ -692,11 +692,15 @@ template class Processor { } void assemble_fetch_decode_execute(InstructionPage &target, int length) { - const MicroOp fetch_decode_execute[] = { - { MicroOp::BusOperation, nullptr, nullptr, {(length == 4) ? MachineCycle::ReadOpcode : MachineCycle::Read, length, &pc_.full, &operation_}}, + const MicroOp normal_fetch_decode_execute[] = { + BusOp(ReadOpcodeStart(pc_, operation_)), { MicroOp::DecodeOperation } }; - copy_program(fetch_decode_execute, target.fetch_decode_execute); + const MicroOp short_fetch_decode_execute[] = { + BusOp(ReadOpcodeStart(pc_, operation_)), + { MicroOp::DecodeOperation } + }; + copy_program((length == 4) ? normal_fetch_decode_execute : short_fetch_decode_execute, target.fetch_decode_execute); target.fetch_decode_execute_data = target.fetch_decode_execute.data(); } @@ -746,32 +750,32 @@ template class Processor { assemble_fetch_decode_execute(fdcb_page_, 3); assemble_fetch_decode_execute(ddcb_page_, 3); - MicroOp reset_program[] = Program(WAIT(3), {MicroOp::Reset}); + MicroOp reset_program[] = Sequence(InternalOperation(3), {MicroOp::Reset}); MicroOp nmi_program[] = { { MicroOp::BeginNMI }, - { MicroOp::BusOperation, nullptr, nullptr, {MachineCycle::ReadOpcode, 5, &pc_.full, &operation_}}, - PUSH(pc_), +// { MicroOp::BusOperation, nullptr, nullptr, {MachineCycle::ReadOpcode, 5, &pc_.full, &operation_}}, + Push(pc_), { MicroOp::JumpTo66, nullptr, nullptr}, { MicroOp::MoveToNextProgram } }; MicroOp irq_mode0_program[] = { { MicroOp::BeginIRQMode0 }, - { MicroOp::BusOperation, nullptr, nullptr, {MachineCycle::Operation::Interrupt, 6, nullptr, &operation_}}, + { MicroOp::BusOperation, nullptr, nullptr, {MachineCycle::Operation::Interrupt, MachineCycle::Phase::End, 6, nullptr, &operation_}}, { MicroOp::DecodeOperationNoRChange } }; MicroOp irq_mode1_program[] = { { MicroOp::BeginIRQ }, - { MicroOp::BusOperation, nullptr, nullptr, {MachineCycle::Operation::Interrupt, 7, nullptr, &operation_}}, - PUSH(pc_), +// { MicroOp::BusOperation, nullptr, nullptr, {MachineCycle::Operation::Interrupt, 7, nullptr, &operation_}}, + Push(pc_), { MicroOp::Move16, &temp16_.full, &pc_.full }, { MicroOp::MoveToNextProgram } }; MicroOp irq_mode2_program[] = { { MicroOp::BeginIRQ }, - { MicroOp::BusOperation, nullptr, nullptr, {MachineCycle::Operation::Interrupt, 7, nullptr, &temp16_.bytes.low}}, - PUSH(pc_), +// { MicroOp::BusOperation, nullptr, nullptr, {MachineCycle::Operation::Interrupt, 7, nullptr, &temp16_.bytes.low}}, + Push(pc_), { MicroOp::Move8, &ir_.bytes.high, &temp16_.bytes.high }, - FETCH16L(pc_, temp16_), + Read16(pc_, temp16_), { MicroOp::MoveToNextProgram } }; @@ -819,7 +823,7 @@ template class Processor { while(1) { while(bus_request_line_) { - static MachineCycle bus_acknowledge_cycle = {MachineCycle::Operation::BusAcknowledge, 1}; + static MachineCycle bus_acknowledge_cycle = {MachineCycle::Operation::BusAcknowledge, MachineCycle::Phase::End, 1}; number_of_cycles_ -= static_cast(this)->perform_machine_cycle(bus_acknowledge_cycle) + 1; if(!number_of_cycles_) { static_cast(this)->flush(); From d668879ba6a3a5ac6b7c0baedb2393ce3463c42a Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 18 Jun 2017 22:03:13 -0400 Subject: [PATCH 19/55] Started trying to wade back to passing tests. Working on the new timing tests first, and focussing on getting the Objective-C test machine to compile bus operations into machine cycles, which means indicating phase to all-RAM delegates. --- .../Bridges/TestMachineZ80.mm | 69 ++++++++++-------- Processors/Z80/Z80.hpp | 2 +- Processors/Z80/Z80AllRAM.cpp | 72 ++++++++----------- Processors/Z80/Z80AllRAM.hpp | 4 +- 4 files changed, 71 insertions(+), 76 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.mm b/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.mm index 2a5c0cf7f..4137bc8a3 100644 --- a/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.mm +++ b/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.mm @@ -11,7 +11,11 @@ #import "TestMachine+ForSubclassEyesOnly.h" @interface CSTestMachineZ80 () -- (void)testMachineDidPerformBusOperation:(CPU::Z80::MachineCycle::Operation)operation address:(uint16_t)address value:(uint8_t)value timeStamp:(int)time_stamp; +- (void)testMachineDidPerformBusOperation:(CPU::Z80::MachineCycle::Operation)operation + phase:(CPU::Z80::MachineCycle::Phase)phase + address:(uint16_t)address + value:(uint8_t)value + timeStamp:(int)time_stamp; @end #pragma mark - C++ delegate handlers @@ -20,8 +24,8 @@ class BusOperationHandler: public CPU::Z80::AllRAMProcessor::MemoryAccessDelegat public: BusOperationHandler(CSTestMachineZ80 *targetMachine) : target_(targetMachine) {} - void z80_all_ram_processor_did_perform_bus_operation(CPU::Z80::AllRAMProcessor &processor, CPU::Z80::MachineCycle::Operation operation, uint16_t address, uint8_t value, int time_stamp) { - [target_ testMachineDidPerformBusOperation:operation address:address value:value timeStamp:time_stamp]; + void z80_all_ram_processor_did_perform_bus_operation(CPU::Z80::AllRAMProcessor &processor, CPU::Z80::MachineCycle::Operation operation, CPU::Z80::MachineCycle::Phase phase, uint16_t address, uint8_t value, int time_stamp) { + [target_ testMachineDidPerformBusOperation:operation phase:phase address:address value:value timeStamp:time_stamp]; } private: @@ -152,7 +156,7 @@ static CPU::Z80::Register registerForRegister(CSTestMachineZ80Register reg) { } - (int)completedCycles { - return _processor->get_length_of_completed_machine_cycles(); + return _processor->get_timestamp(); } - (void)setNmiLine:(BOOL)nmiLine { @@ -187,7 +191,7 @@ static CPU::Z80::Register registerForRegister(CSTestMachineZ80Register reg) { _processor->set_memory_access_delegate(captureBusActivity ? _busOperationHandler : nullptr); } -- (void)testMachineDidPerformBusOperation:(CPU::Z80::MachineCycle::Operation)operation address:(uint16_t)address value:(uint8_t)value timeStamp:(int)timeStamp { +- (void)testMachineDidPerformBusOperation:(CPU::Z80::MachineCycle::Operation)operation phase:(CPU::Z80::MachineCycle::Phase)phase address:(uint16_t)address value:(uint8_t)value timeStamp:(int)timeStamp { int length = timeStamp - _lastOpcodeTime; _lastOpcodeTime = timeStamp; if(operation == CPU::Z80::MachineCycle::Operation::ReadOpcode && length < _timeSeekingReadOpcode) @@ -195,39 +199,42 @@ static CPU::Z80::Register registerForRegister(CSTestMachineZ80Register reg) { if(self.captureBusActivity) { CSTestMachineZ80BusOperationCapture *capture = [[CSTestMachineZ80BusOperationCapture alloc] init]; - switch(operation) { - case CPU::Z80::MachineCycle::Operation::Write: - capture.operation = CSTestMachineZ80BusOperationCaptureOperationWrite; - break; + if(phase == CPU::Z80::MachineCycle::Phase::End) { + switch(operation) { + case CPU::Z80::MachineCycle::Operation::Write: + capture.operation = CSTestMachineZ80BusOperationCaptureOperationWrite; + break; - case CPU::Z80::MachineCycle::Operation::Read: - capture.operation = CSTestMachineZ80BusOperationCaptureOperationRead; - break; + case CPU::Z80::MachineCycle::Operation::Read: + capture.operation = CSTestMachineZ80BusOperationCaptureOperationRead; + break; - case CPU::Z80::MachineCycle::Operation::ReadOpcode: - capture.operation = CSTestMachineZ80BusOperationCaptureOperationReadOpcode; - break; + case CPU::Z80::MachineCycle::Operation::ReadOpcode: + case CPU::Z80::MachineCycle::Operation::Refresh: + capture.operation = CSTestMachineZ80BusOperationCaptureOperationReadOpcode; + break; - case CPU::Z80::MachineCycle::Operation::Input: - capture.operation = CSTestMachineZ80BusOperationCaptureOperationPortRead; - break; + case CPU::Z80::MachineCycle::Operation::Input: + capture.operation = CSTestMachineZ80BusOperationCaptureOperationPortRead; + break; - case CPU::Z80::MachineCycle::Operation::Output: - capture.operation = CSTestMachineZ80BusOperationCaptureOperationPortWrite; - break; + case CPU::Z80::MachineCycle::Operation::Output: + capture.operation = CSTestMachineZ80BusOperationCaptureOperationPortWrite; + break; - case CPU::Z80::MachineCycle::Operation::Internal: - capture.operation = CSTestMachineZ80BusOperationCaptureOperationInternalOperation; - break; + case CPU::Z80::MachineCycle::Operation::Internal: + capture.operation = CSTestMachineZ80BusOperationCaptureOperationInternalOperation; + break; - default: - return; + default: + return; + } + capture.address = address; + capture.value = value; + capture.timeStamp = timeStamp; + + [_busOperationCaptures addObject:capture]; } - capture.address = address; - capture.value = value; - capture.timeStamp = timeStamp; - - [_busOperationCaptures addObject:capture]; } } diff --git a/Processors/Z80/Z80.hpp b/Processors/Z80/Z80.hpp index 927e66a8f..7734b116c 100644 --- a/Processors/Z80/Z80.hpp +++ b/Processors/Z80/Z80.hpp @@ -86,7 +86,7 @@ struct MachineCycle { // Elemental bus operations #define ReadOpcodeStart(addr, val) {MachineCycle::ReadOpcode, MachineCycle::Phase::Start, 2, &addr.full, &val, false} #define ReadOpcodeWait(addr, val) {MachineCycle::ReadOpcode, MachineCycle::Phase::Wait, 1, &addr.full, &val, true} -#define Refresh(len) {MachineCycle::Refresh, MachineCycle::Phase::Start, 2, &ir_.full, nullptr, false} +#define Refresh(len) {MachineCycle::Refresh, MachineCycle::Phase::End, 2, &ir_.full, nullptr, false} #define ReadStart(addr, val) {MachineCycle::Read, MachineCycle::Phase::Start, 2, &addr.full, &val, false} #define ReadWait(l, addr, val, f) {MachineCycle::Read, MachineCycle::Phase::Wait, l, &addr.full, &val, f} diff --git a/Processors/Z80/Z80AllRAM.cpp b/Processors/Z80/Z80AllRAM.cpp index 99340657c..7a25b5cae 100644 --- a/Processors/Z80/Z80AllRAM.cpp +++ b/Processors/Z80/Z80AllRAM.cpp @@ -14,49 +14,47 @@ namespace { class ConcreteAllRAMProcessor: public AllRAMProcessor, public Processor { public: - ConcreteAllRAMProcessor() : AllRAMProcessor(), completed_cycles(0) {} + ConcreteAllRAMProcessor() : AllRAMProcessor() {} inline int perform_machine_cycle(const MachineCycle &cycle) { - completed_cycles += cycle.length; uint16_t address = cycle.address ? *cycle.address : 0x0000; - switch(cycle.operation) { - case MachineCycle::Operation::ReadOpcode: -// printf("! "); - check_address_for_trap(address); - case MachineCycle::Operation::Read: -// printf("r %04x [%02x] AF:%04x BC:%04x DE:%04x HL:%04x SP:%04x\n", address, memory_[address], get_value_of_register(CPU::Z80::Register::AF), get_value_of_register(CPU::Z80::Register::BC), get_value_of_register(CPU::Z80::Register::DE), get_value_of_register(CPU::Z80::Register::HL), get_value_of_register(CPU::Z80::Register::StackPointer)); - *cycle.value = memory_[address]; - break; - case MachineCycle::Operation::Write: -// printf("w %04x\n", address); - memory_[address] = *cycle.value; - break; +// if(cycle.phase == MachineCycle::Phase::End) { + switch(cycle.operation) { + case MachineCycle::Operation::ReadOpcode: + check_address_for_trap(address); + case MachineCycle::Operation::Read: + *cycle.value = memory_[address]; + break; + case MachineCycle::Operation::Write: + memory_[address] = *cycle.value; + break; - case MachineCycle::Operation::Output: - break; - case MachineCycle::Operation::Input: - // This logic is selected specifically because it seems to match - // the FUSE unit tests. It might need factoring out. - *cycle.value = address >> 8; - break; + case MachineCycle::Operation::Output: + break; + case MachineCycle::Operation::Input: + // This logic is selected specifically because it seems to match + // the FUSE unit tests. It might need factoring out. + *cycle.value = address >> 8; + break; - case MachineCycle::Operation::Internal: - break; + case MachineCycle::Operation::Internal: + break; - case MachineCycle::Operation::Interrupt: - // A pick that means LD HL, (nn) if interpreted as an instruction but is otherwise - // arbitrary. - *cycle.value = 0x21; - break; + case MachineCycle::Operation::Interrupt: + // A pick that means LD HL, (nn) if interpreted as an instruction but is otherwise + // arbitrary. + *cycle.value = 0x21; + break; - default: - printf("???\n"); - break; - } + default: + printf("???\n"); + break; + } +// } timestamp_ += cycle.length; if(delegate_ != nullptr) { - delegate_->z80_all_ram_processor_did_perform_bus_operation(*this, cycle.operation, address, cycle.value ? *cycle.value : 0x00, timestamp_); + delegate_->z80_all_ram_processor_did_perform_bus_operation(*this, cycle.operation, cycle.phase, address, cycle.value ? *cycle.value : 0x00, timestamp_); } return 0; @@ -89,14 +87,6 @@ class ConcreteAllRAMProcessor: public AllRAMProcessor, public Processor::set_non_maskable_interrupt_line(value); } - - int get_length_of_completed_machine_cycles() { - return completed_cycles; - } - - private: - int completed_cycles; - }; } diff --git a/Processors/Z80/Z80AllRAM.hpp b/Processors/Z80/Z80AllRAM.hpp index 778437f7c..3c77f943c 100644 --- a/Processors/Z80/Z80AllRAM.hpp +++ b/Processors/Z80/Z80AllRAM.hpp @@ -22,7 +22,7 @@ class AllRAMProcessor: static AllRAMProcessor *Processor(); struct MemoryAccessDelegate { - virtual void z80_all_ram_processor_did_perform_bus_operation(AllRAMProcessor &processor, MachineCycle::Operation operation, uint16_t address, uint8_t value, int time_stamp) = 0; + virtual void z80_all_ram_processor_did_perform_bus_operation(CPU::Z80::AllRAMProcessor &processor, CPU::Z80::MachineCycle::Operation operation, CPU::Z80::MachineCycle::Phase phase, uint16_t address, uint8_t value, int time_stamp) = 0; }; inline void set_memory_access_delegate(MemoryAccessDelegate *delegate) { delegate_ = delegate; @@ -36,8 +36,6 @@ class AllRAMProcessor: virtual void set_interrupt_line(bool value) = 0; virtual void set_non_maskable_interrupt_line(bool value) = 0; - virtual int get_length_of_completed_machine_cycles() = 0; - protected: MemoryAccessDelegate *delegate_; AllRAMProcessor() : ::CPU::AllRAMProcessor(65536), delegate_(nullptr) {} From 85c5c4405a92d64bf5072d4dcd57030d09100f52 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 19 Jun 2017 07:30:01 -0400 Subject: [PATCH 20/55] Ensured that wait states don't appear unless requested (TODO: requesting), and made the output of my timing tests a little easier to parse. --- .../Z80MachineCycleTests.swift | 27 ++++++++++++++++--- Processors/Z80/Z80.hpp | 6 ++++- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift b/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift index af8252e6c..be76ae49b 100644 --- a/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift +++ b/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift @@ -10,9 +10,25 @@ import XCTest class Z80MachineCycleTests: XCTestCase { - private struct MachineCycle { + private struct MachineCycle: CustomDebugStringConvertible { var operation: CSTestMachineZ80BusOperationCaptureOperation var length: Int32 + + public var debugDescription: String { + get { + var opName = "" + switch operation { + case .readOpcode: opName = "ro" + case .read: opName = "r" + case .write: opName = "w" + case .portRead: opName = "i" + case .portWrite: opName = "o" + case .internalOperation: opName = "iop" + } + return "\(opName) \(length)" + } + } + } private func test(program : [UInt8], busCycles : [MachineCycle]) { @@ -34,6 +50,7 @@ class Z80MachineCycleTests: XCTestCase { // Check the results totalCycles = 0 var index = 0 + var matches = true for cycle in machine.busOperationCaptures { let length = cycle.timeStamp - totalCycles totalCycles += length @@ -44,12 +61,16 @@ class Z80MachineCycleTests: XCTestCase { // array access break } else { - XCTAssertEqual(length, busCycles[index].length) - XCTAssertEqual(cycle.operation, busCycles[index].operation) + if length != busCycles[index].length || cycle.operation != busCycles[index].operation { + matches = false + break; + } } index += 1 } + + XCTAssert(matches, "Z80 performed \(machine.busOperationCaptures); was expected to perform \(busCycles)") } // LD r, r diff --git a/Processors/Z80/Z80.hpp b/Processors/Z80/Z80.hpp index 7734b116c..3b8781d69 100644 --- a/Processors/Z80/Z80.hpp +++ b/Processors/Z80/Z80.hpp @@ -694,10 +694,11 @@ template class Processor { void assemble_fetch_decode_execute(InstructionPage &target, int length) { const MicroOp normal_fetch_decode_execute[] = { BusOp(ReadOpcodeStart(pc_, operation_)), + BusOp(ReadOpcodeWait(pc_, operation_)), { MicroOp::DecodeOperation } }; const MicroOp short_fetch_decode_execute[] = { - BusOp(ReadOpcodeStart(pc_, operation_)), + Read3(pc_, operation_), { MicroOp::DecodeOperation } }; copy_program((length == 4) ? normal_fetch_decode_execute : short_fetch_decode_execute, target.fetch_decode_execute); @@ -843,6 +844,9 @@ template class Processor { switch(operation->type) { case MicroOp::BusOperation: + if(operation->machine_cycle.was_requested) { // TODO: && !wait_line_ + continue; + } if(number_of_cycles_ < operation->machine_cycle.length) { scheduled_program_counter_--; static_cast(this)->flush(); From 54e4643396cf3c9341b29b1aa0595df35999538c Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 19 Jun 2017 07:34:23 -0400 Subject: [PATCH 21/55] Corrected non-default refresh cycle lengths. Reduces failures of the currently-tested timing subset from 10 to 4. --- Processors/Z80/Z80.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Processors/Z80/Z80.hpp b/Processors/Z80/Z80.hpp index 3b8781d69..8435c37c7 100644 --- a/Processors/Z80/Z80.hpp +++ b/Processors/Z80/Z80.hpp @@ -86,7 +86,7 @@ struct MachineCycle { // Elemental bus operations #define ReadOpcodeStart(addr, val) {MachineCycle::ReadOpcode, MachineCycle::Phase::Start, 2, &addr.full, &val, false} #define ReadOpcodeWait(addr, val) {MachineCycle::ReadOpcode, MachineCycle::Phase::Wait, 1, &addr.full, &val, true} -#define Refresh(len) {MachineCycle::Refresh, MachineCycle::Phase::End, 2, &ir_.full, nullptr, false} +#define Refresh(len) {MachineCycle::Refresh, MachineCycle::Phase::End, len, &ir_.full, nullptr, false} #define ReadStart(addr, val) {MachineCycle::Read, MachineCycle::Phase::Start, 2, &addr.full, &val, false} #define ReadWait(l, addr, val, f) {MachineCycle::Read, MachineCycle::Phase::Wait, l, &addr.full, &val, f} From 85c6fb14300f5f157d9341436f1cef390181ad53 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 19 Jun 2017 07:36:11 -0400 Subject: [PATCH 22/55] Explained refresh cycles to the all-RAM Z80. --- Processors/Z80/Z80AllRAM.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Processors/Z80/Z80AllRAM.cpp b/Processors/Z80/Z80AllRAM.cpp index 7a25b5cae..e6b315bfc 100644 --- a/Processors/Z80/Z80AllRAM.cpp +++ b/Processors/Z80/Z80AllRAM.cpp @@ -38,6 +38,7 @@ class ConcreteAllRAMProcessor: public AllRAMProcessor, public Processor Date: Mon, 19 Jun 2017 07:39:46 -0400 Subject: [PATCH 23/55] Rephrased internal operation machine cycles as having only an end. So they're now easy to count. Hence the test machine spots them, and a couple more of the current timing subset passes. --- Processors/Z80/Z80.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Processors/Z80/Z80.hpp b/Processors/Z80/Z80.hpp index 8435c37c7..a407d8f5c 100644 --- a/Processors/Z80/Z80.hpp +++ b/Processors/Z80/Z80.hpp @@ -116,7 +116,7 @@ struct MachineCycle { #define Input(addr, val) BusOp(InputStart(addr, val)), BusOp(InputWait(addr, val, false)), BusOp(InputWait(addr, val, true)), BusOp(InputEnd(addr, val)) #define Output(addr, val) BusOp(OutputStart(addr, val)), BusOp(OutputWait(addr, val, false)), BusOp(OutputWait(addr, val, true)), BusOp(OutputEnd(addr, val)) -#define InternalOperation(len) {MicroOp::BusOperation, nullptr, nullptr, {MachineCycle::Internal, MachineCycle::Phase::Start, len}} +#define InternalOperation(len) {MicroOp::BusOperation, nullptr, nullptr, {MachineCycle::Internal, MachineCycle::Phase::End, len}} /// A sequence is a series of micro-ops that ends in a move-to-next-program operation. #define Sequence(...) { __VA_ARGS__, {MicroOp::MoveToNextProgram} } From 002098d4964e4473bfc9a2037f109c069edcbb9d Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 19 Jun 2017 07:45:41 -0400 Subject: [PATCH 24/55] =?UTF-8?q?The=20final=20two=20tests=20were=20at=20f?= =?UTF-8?q?ault=20=E2=80=94=20expecting=20POPs=20to=20write=20rather=20tha?= =?UTF-8?q?n=20read.=20Fixed,=20so=20the=20subset=20of=20timing=20tests=20?= =?UTF-8?q?as-yet=20implemented=20now=20passes.=20Which=20means=20it's=20t?= =?UTF-8?q?ime=20to=20slog=20through=20further=20tests.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Mac/Clock SignalTests/Z80MachineCycleTests.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift b/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift index be76ae49b..d07d85873 100644 --- a/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift +++ b/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift @@ -391,8 +391,8 @@ class Z80MachineCycleTests: XCTestCase { program: [0xe1], busCycles: [ MachineCycle(operation: .readOpcode, length: 4), - MachineCycle(operation: .write, length: 3), - MachineCycle(operation: .write, length: 3), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .read, length: 3), ] ) } @@ -404,8 +404,8 @@ class Z80MachineCycleTests: XCTestCase { busCycles: [ MachineCycle(operation: .readOpcode, length: 4), MachineCycle(operation: .readOpcode, length: 4), - MachineCycle(operation: .write, length: 3), - MachineCycle(operation: .write, length: 3), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .read, length: 3), ] ) } From 8d60734737c24041fa86345d878e8c2367c51157 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 19 Jun 2017 19:17:54 -0400 Subject: [PATCH 25/55] Added tests for EXX, EX (SP), HL and EX (SP), IX. The latter two currently being incorrect. --- .../Z80MachineCycleTests.swift | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift b/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift index d07d85873..a0ded5457 100644 --- a/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift +++ b/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift @@ -429,4 +429,43 @@ class Z80MachineCycleTests: XCTestCase { ] ) } + + // EXX + func testEXX() { + test( + program: [0xd9], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + ] + ) + } + + // EX (SP), HL + func testEXSPHL() { + test( + program: [0xe3], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .read, length: 4), + MachineCycle(operation: .write, length: 3), + MachineCycle(operation: .write, length: 5), + ] + ) + } + + // EX (SP), IX + func testEXSPIX() { + test( + program: [0xdd, 0xe3], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .read, length: 4), + MachineCycle(operation: .write, length: 3), + MachineCycle(operation: .write, length: 5), + ] + ) + } } From 73dbaebbc172f7e9e5cdf8c8036f30303c7e1c9e Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 19 Jun 2017 19:25:53 -0400 Subject: [PATCH 26/55] Fixed timing of EX (SP), HL/IX. --- Processors/Z80/Z80.hpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Processors/Z80/Z80.hpp b/Processors/Z80/Z80.hpp index a407d8f5c..1b33c238f 100644 --- a/Processors/Z80/Z80.hpp +++ b/Processors/Z80/Z80.hpp @@ -306,6 +306,9 @@ template class Processor { #define Push(x) {MicroOp::Decrement16, &sp_.full}, Write3(sp_, x.bytes.high), {MicroOp::Decrement16, &sp_.full}, Write3(sp_, x.bytes.low) #define Pop(x) Read3(sp_, x.bytes.low), {MicroOp::Increment16, &sp_.full}, Read3(sp_, x.bytes.high), {MicroOp::Increment16, &sp_.full} +#define Push8(x) {MicroOp::Decrement16, &sp_.full}, Write3(sp_, x.bytes.high), {MicroOp::Decrement16, &sp_.full}, Write5(sp_, x.bytes.low) +#define Pop7(x) Read3(sp_, x.bytes.low), {MicroOp::Increment16, &sp_.full}, Read4(sp_, x.bytes.high), {MicroOp::Increment16, &sp_.full} + /* The following are actual instructions */ #define NOP Sequence(BusOp(Refresh(2))) @@ -370,7 +373,7 @@ template class Processor { #define isTerminal(n) (n == MicroOp::MoveToNextProgram || n == MicroOp::DecodeOperation || n == MicroOp::DecodeOperationNoRChange) - typedef MicroOp InstructionTable[256][20]; + typedef MicroOp InstructionTable[256][30]; void assemble_page(InstructionPage &target, InstructionTable &table, bool add_offsets) { size_t number_of_micro_ops = 0; @@ -667,7 +670,7 @@ template class Processor { /* 0xde SBC A, n */ StdInstr(ReadInc(pc_, temp8_), {MicroOp::SBC8, &temp8_}), /* 0xdf RST 18h */ RST(), /* 0xe0 RET PO */ RET(TestPO), /* 0xe1 POP HL */ StdInstr(Pop(index)), - /* 0xe2 JP PO */ JP(TestPO), /* 0xe3 EX (SP), HL */StdInstr(Pop(memptr_), Push(index), {MicroOp::Move16, &memptr_.full, &index.full}), // WAIT(1), WAIT(2), + /* 0xe2 JP PO */ JP(TestPO), /* 0xe3 EX (SP), HL */StdInstr(Pop7(memptr_), Push8(index), {MicroOp::Move16, &memptr_.full, &index.full}), /* 0xe4 CALL PO */ CALL(TestPO), /* 0xe5 PUSH HL */ Instr(3, Push(index)), /* 0xe6 AND n */ StdInstr(ReadInc(pc_, temp8_), {MicroOp::And, &temp8_}), /* 0xe7 RST 20h */ RST(), From ba15371948a4410c3f66092e5bd2c6af0258c890 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 19 Jun 2017 19:47:00 -0400 Subject: [PATCH 27/55] Introduced timing tests for LDI[R] and CPI[R], fixing a latent issue in the rejig of LD BC, nn while I'm here. --- .../Z80MachineCycleTests.swift | 88 +++++++++++++++++++ Processors/Z80/Z80.hpp | 2 +- 2 files changed, 89 insertions(+), 1 deletion(-) diff --git a/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift b/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift index a0ded5457..ad7b63f9a 100644 --- a/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift +++ b/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift @@ -468,4 +468,92 @@ class Z80MachineCycleTests: XCTestCase { ] ) } + + // LDI + func testLDI() { + test( + program: [0xed, 0xa0], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .write, length: 5), + ] + ) + } + + // CPI (NB: I've diverted from the documentation by assuming the five-cycle 'write' is an internal operation) + func testCPI() { + test( + program: [0xed, 0xa1], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .internalOperation, length: 5), + ] + ) + } + + // LDIR + func testLDIR() { + test( + program: [ + 0x01, 0x02, 0x00, // LD BC, 2 + 0xed, 0xb0, // LDIR + 0x00, 0x00, 0x00 // NOP, NOP, NOP + ], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .read, length: 3), + + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .write, length: 5), + MachineCycle(operation: .internalOperation, length: 5), + + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .write, length: 5), + + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + ] + ) + } + + // CPIR (as per CPI; assumed no writes) + func testCPIR() { + test( + program: [ + 0x01, 0x02, 0x00, // LD BC, 2 + 0xed, 0xb1, // CPIR + 0x00, 0x00, 0x00 // NOP, NOP, NOP + ], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .read, length: 3), + + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .internalOperation, length: 5), + MachineCycle(operation: .internalOperation, length: 5), + + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .internalOperation, length: 5), + + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + ] + ) + } } diff --git a/Processors/Z80/Z80.hpp b/Processors/Z80/Z80.hpp index 1b33c238f..ce940216e 100644 --- a/Processors/Z80/Z80.hpp +++ b/Processors/Z80/Z80.hpp @@ -534,7 +534,7 @@ template class Processor { Instr(4, {MicroOp::Decrement16, &rf.full}), INC_DEC_LD(r) InstructionTable base_program_table = { - /* 0x00 NOP */ NOP, /* 0x01 LD BC, nn */ StdInstr(Read16(pc_, bc_)), + /* 0x00 NOP */ NOP, /* 0x01 LD BC, nn */ StdInstr(Read16Inc(pc_, bc_)), /* 0x02 LD (BC), A */ StdInstr({MicroOp::Move16, &bc_.full, &memptr_.full}, Write3(memptr_, a_)), /* 0x03 INC BC; 0x04 INC B; 0x05 DEC B; 0x06 LD B, n */ From 23177df26ae7ac5ddafb9cd9fd10bf5077ca6b19 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 19 Jun 2017 19:53:26 -0400 Subject: [PATCH 28/55] Added various tests of the basic ALU ops. --- .../Z80MachineCycleTests.swift | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift b/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift index ad7b63f9a..e4e2f49db 100644 --- a/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift +++ b/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift @@ -556,4 +556,50 @@ class Z80MachineCycleTests: XCTestCase { ] ) } + + // ADD A,r + func testADDAr() { + test( + program: [0x80], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + ] + ) + } + + // ADD A,n + func testADDAn() { + test( + program: [0xc6, 0x00], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + ] + ) + } + + // ADD A,(HL) + func testADDAHL() { + test( + program: [0x86], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + ] + ) + } + + // ADD A,(IX+d) + func testADDAIXd() { + test( + program: [0xdd, 0x86], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .internalOperation, length: 5), + MachineCycle(operation: .read, length: 3), + ] + ) + } } From 351d90ca555ca2a9b3628f26b4774e99a7141cec Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 19 Jun 2017 20:04:55 -0400 Subject: [PATCH 29/55] Added tests down to INC IX. No additional failures yet, though I've yet to reach conditional CALL. --- .../Z80MachineCycleTests.swift | 116 ++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift b/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift index e4e2f49db..46f54bb0c 100644 --- a/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift +++ b/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift @@ -602,4 +602,120 @@ class Z80MachineCycleTests: XCTestCase { ] ) } + + // INC r, DEC r + func testINCrDECr() { + test( + program: [0x3c, 0x3d], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + ] + ) + } + + // INC (HL), DEC (HL) + func testINCHLDECHL() { + test( + program: [0x34, 0x34], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 4), + MachineCycle(operation: .write, length: 3), + + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 4), + MachineCycle(operation: .write, length: 3), + ] + ) + } + + // DAA, CPL, CCF, SCF, NOP, DI, EI, HALT + func testDAACPLCCFSCFNOPDIEIHALT() { + test( + program: [0x27, 0x2f, 0x3f, 0x37, 0x00, 0xf3, 0xfb, 0x76], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), // one more for luck + ] + ) + } + + func testNEGIMs() { + test( + program: [0xed, 0x44, 0xed, 0x46, 0xed, 0x56, 0xed, 0x5e], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + ] + ) + } + + func testADDHL() { + test( + program: [0x09], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .internalOperation, length: 4), + MachineCycle(operation: .internalOperation, length: 3), + ] + ) + } + + func testADDIX() { + test( + program: [0xdd, 0x09], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .internalOperation, length: 4), + MachineCycle(operation: .internalOperation, length: 3), + ] + ) + } + + func testADCHL() { + test( + program: [0xed, 0x4a], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .internalOperation, length: 4), + MachineCycle(operation: .internalOperation, length: 3), + ] + ) + } + + func testINCss() { + test( + program: [0x03], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 6), + ] + ) + } + + func testINCIX() { + test( + program: [0xdd, 0x23], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 6), + ] + ) + } } From b684254908e9e73906369a7bab20d75e08730732 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 19 Jun 2017 20:33:34 -0400 Subject: [PATCH 30/55] Introduced further tests down to a failing attempt at RLC (IX+d). Made an initial attempt to fix, failed. --- .../Z80MachineCycleTests.swift | 46 +++++++++++++++++++ Processors/Z80/Z80.hpp | 2 +- 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift b/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift index 46f54bb0c..a2dddb2ec 100644 --- a/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift +++ b/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift @@ -718,4 +718,50 @@ class Z80MachineCycleTests: XCTestCase { ] ) } + + func testRLCA() { + test( + program: [0x07], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + ] + ) + } + + func testRLCr() { + test( + program: [0xcb, 0x00], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + ] + ) + } + + func testRLCHL() { + test( + program: [0xcb, 0x06], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 4), + MachineCycle(operation: .write, length: 3), + ] + ) + } + + // RLC (IX+d) (NB: the official table doesn't read the final part of the instruction; I've assumed a five-cycle version of read opcode replaces the internal operation) + func testRLCIX() { + test( + program: [0xdd, 0xcb, 0x00, 0x06], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .readOpcode, length: 5), + MachineCycle(operation: .read, length: 4), + MachineCycle(operation: .write, length: 3), + ] + ) + } } diff --git a/Processors/Z80/Z80.hpp b/Processors/Z80/Z80.hpp index ce940216e..223df2dd4 100644 --- a/Processors/Z80/Z80.hpp +++ b/Processors/Z80/Z80.hpp @@ -338,7 +338,7 @@ template class Processor { StdInstr({MicroOp::op, &a_}) #define RMW(x, op, ...) StdInstr(INDEX(), Read4(INDEX_ADDR(), x), {MicroOp::op, &x}, Write3(INDEX_ADDR(), x)) -#define RMWI(x, op, ...) Instr(4, Read4(INDEX_ADDR(), x), {MicroOp::op, &x}, Write3(INDEX_ADDR(), x)) +#define RMWI(x, op, ...) Instr(3, Read4(INDEX_ADDR(), x), {MicroOp::op, &x}, Write3(INDEX_ADDR(), x)) #define MODIFY_OP_GROUP(op) \ StdInstr({MicroOp::op, &bc_.bytes.high}), StdInstr({MicroOp::op, &bc_.bytes.low}), \ From cc8f3169417e7f2db1daa2b94242d5806d16f5dc Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 19 Jun 2017 20:51:28 -0400 Subject: [PATCH 31/55] Resolved read-modify-write (IX+d) timing, and therefore RLC (IX+d). --- Processors/Z80/Z80.hpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Processors/Z80/Z80.hpp b/Processors/Z80/Z80.hpp index 223df2dd4..9d4aba26a 100644 --- a/Processors/Z80/Z80.hpp +++ b/Processors/Z80/Z80.hpp @@ -84,9 +84,9 @@ struct MachineCycle { }; // Elemental bus operations -#define ReadOpcodeStart(addr, val) {MachineCycle::ReadOpcode, MachineCycle::Phase::Start, 2, &addr.full, &val, false} -#define ReadOpcodeWait(addr, val) {MachineCycle::ReadOpcode, MachineCycle::Phase::Wait, 1, &addr.full, &val, true} -#define Refresh(len) {MachineCycle::Refresh, MachineCycle::Phase::End, len, &ir_.full, nullptr, false} +#define ReadOpcodeStart(addr, val) {MachineCycle::ReadOpcode, MachineCycle::Phase::Start, 2, &addr.full, &val, false} +#define ReadOpcodeWait(addr, val, f) {MachineCycle::ReadOpcode, MachineCycle::Phase::Wait, 1, &addr.full, &val, f} +#define Refresh(len) {MachineCycle::Refresh, MachineCycle::Phase::End, len, &ir_.full, nullptr, false} #define ReadStart(addr, val) {MachineCycle::Read, MachineCycle::Phase::Start, 2, &addr.full, &val, false} #define ReadWait(l, addr, val, f) {MachineCycle::Read, MachineCycle::Phase::Wait, l, &addr.full, &val, f} @@ -338,7 +338,7 @@ template class Processor { StdInstr({MicroOp::op, &a_}) #define RMW(x, op, ...) StdInstr(INDEX(), Read4(INDEX_ADDR(), x), {MicroOp::op, &x}, Write3(INDEX_ADDR(), x)) -#define RMWI(x, op, ...) Instr(3, Read4(INDEX_ADDR(), x), {MicroOp::op, &x}, Write3(INDEX_ADDR(), x)) +#define RMWI(x, op, ...) StdInstr(Read4(INDEX_ADDR(), x), {MicroOp::op, &x}, Write3(INDEX_ADDR(), x)) #define MODIFY_OP_GROUP(op) \ StdInstr({MicroOp::op, &bc_.bytes.high}), StdInstr({MicroOp::op, &bc_.bytes.low}), \ @@ -697,11 +697,13 @@ template class Processor { void assemble_fetch_decode_execute(InstructionPage &target, int length) { const MicroOp normal_fetch_decode_execute[] = { BusOp(ReadOpcodeStart(pc_, operation_)), - BusOp(ReadOpcodeWait(pc_, operation_)), + BusOp(ReadOpcodeWait(pc_, operation_, true)), { MicroOp::DecodeOperation } }; const MicroOp short_fetch_decode_execute[] = { - Read3(pc_, operation_), + BusOp(ReadOpcodeStart(pc_, operation_)), + BusOp(ReadOpcodeWait(pc_, operation_, false)), + BusOp(ReadOpcodeWait(pc_, operation_, true)), { MicroOp::DecodeOperation } }; copy_program((length == 4) ? normal_fetch_decode_execute : short_fetch_decode_execute, target.fetch_decode_execute); From f903408980c7346332870b595d1691f93311b617 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 19 Jun 2017 20:53:22 -0400 Subject: [PATCH 32/55] Caught up on comments. --- .../Mac/Clock SignalTests/Z80MachineCycleTests.swift | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift b/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift index a2dddb2ec..a8af82ad1 100644 --- a/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift +++ b/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift @@ -648,6 +648,7 @@ class Z80MachineCycleTests: XCTestCase { ) } + // NEG, IM 0, IM 1, IM 2 func testNEGIMs() { test( program: [0xed, 0x44, 0xed, 0x46, 0xed, 0x56, 0xed, 0x5e], @@ -665,6 +666,7 @@ class Z80MachineCycleTests: XCTestCase { ) } + // ADD HL, rr func testADDHL() { test( program: [0x09], @@ -676,6 +678,7 @@ class Z80MachineCycleTests: XCTestCase { ) } + // ADD IX, rr func testADDIX() { test( program: [0xdd, 0x09], @@ -688,6 +691,7 @@ class Z80MachineCycleTests: XCTestCase { ) } + // ADD A, (HL) func testADCHL() { test( program: [0xed, 0x4a], @@ -700,6 +704,7 @@ class Z80MachineCycleTests: XCTestCase { ) } + // INC rr func testINCss() { test( program: [0x03], @@ -709,6 +714,7 @@ class Z80MachineCycleTests: XCTestCase { ) } + // INC IX func testINCIX() { test( program: [0xdd, 0x23], @@ -719,6 +725,7 @@ class Z80MachineCycleTests: XCTestCase { ) } + // RLCA func testRLCA() { test( program: [0x07], @@ -728,6 +735,7 @@ class Z80MachineCycleTests: XCTestCase { ) } + // RLC r func testRLCr() { test( program: [0xcb, 0x00], @@ -738,6 +746,7 @@ class Z80MachineCycleTests: XCTestCase { ) } + // RLC (HL) func testRLCHL() { test( program: [0xcb, 0x06], From 378233f53d2d87a859de85cf4f4a2cf995e3470b Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 19 Jun 2017 21:01:30 -0400 Subject: [PATCH 33/55] Extended to BITs and SETs, accruing three new failures. --- .../Z80MachineCycleTests.swift | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift b/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift index a8af82ad1..3e9f6c1af 100644 --- a/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift +++ b/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift @@ -773,4 +773,96 @@ class Z80MachineCycleTests: XCTestCase { ] ) } + + // RLD + func testRLD() { + test( + program: [0xed, 0x6f], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .internalOperation, length: 4), + MachineCycle(operation: .write, length: 3), + ] + ) + } + + // BIT n,r + func testBITr() { + test( + program: [0xcb, 0x40], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + ] + ) + } + + // SET n,r + func testSETr() { + test( + program: [0xcb, 0xc0], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 4), + MachineCycle(operation: .write, length: 3), + ] + ) + } + + // BIT n,(HL) + func testBITHL() { + test( + program: [0xcb, 0x46], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 4), + ] + ) + } + + // SET n,(HL) + func testSETHL() { + test( + program: [0xcb, 0xc6], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 4), + MachineCycle(operation: .write, length: 3), + ] + ) + } + + // BIT n,(IX+d) + func testBITIX() { + test( + program: [0xdb, 0xcb, 0x00, 0x46], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .readOpcode, length: 5), + MachineCycle(operation: .read, length: 4), + ] + ) + } + + // SET n,(IX+d) + func testSETIX() { + test( + program: [0xdb, 0xcb, 0x00, 0xc6], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 4), + MachineCycle(operation: .readOpcode, length: 5), + MachineCycle(operation: .read, length: 4), + MachineCycle(operation: .write, length: 3), + ] + ) + } } From 99ede3a9ef2873dfab1f40b92ff0b5a8c8a91552 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 19 Jun 2017 21:04:14 -0400 Subject: [PATCH 34/55] BIT/SET (IX+d) were incorrectly encoded. Hence fixed BIT (IX+d). --- OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift b/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift index 3e9f6c1af..4d691d63f 100644 --- a/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift +++ b/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift @@ -840,7 +840,7 @@ class Z80MachineCycleTests: XCTestCase { // BIT n,(IX+d) func testBITIX() { test( - program: [0xdb, 0xcb, 0x00, 0x46], + program: [0xdd, 0xcb, 0x00, 0x46], busCycles: [ MachineCycle(operation: .readOpcode, length: 4), MachineCycle(operation: .readOpcode, length: 4), @@ -854,7 +854,7 @@ class Z80MachineCycleTests: XCTestCase { // SET n,(IX+d) func testSETIX() { test( - program: [0xdb, 0xcb, 0x00, 0xc6], + program: [0xdd, 0xcb, 0x00, 0xc6], busCycles: [ MachineCycle(operation: .readOpcode, length: 4), MachineCycle(operation: .readOpcode, length: 4), From 234f14dbbef893812e544740aaa0348cb784c560 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 19 Jun 2017 21:14:40 -0400 Subject: [PATCH 35/55] Tests were at fault; all passing now. --- OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift b/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift index 4d691d63f..e9ada6bb2 100644 --- a/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift +++ b/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift @@ -806,8 +806,6 @@ class Z80MachineCycleTests: XCTestCase { busCycles: [ MachineCycle(operation: .readOpcode, length: 4), MachineCycle(operation: .readOpcode, length: 4), - MachineCycle(operation: .read, length: 4), - MachineCycle(operation: .write, length: 3), ] ) } @@ -858,7 +856,7 @@ class Z80MachineCycleTests: XCTestCase { busCycles: [ MachineCycle(operation: .readOpcode, length: 4), MachineCycle(operation: .readOpcode, length: 4), - MachineCycle(operation: .read, length: 4), + MachineCycle(operation: .read, length: 3), MachineCycle(operation: .readOpcode, length: 5), MachineCycle(operation: .read, length: 4), MachineCycle(operation: .write, length: 3), From cb277b8d1eda039b3ef1882a2593aef4cf8026af Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 19 Jun 2017 21:27:23 -0400 Subject: [PATCH 36/55] Added JP and JR tests. --- .../Z80MachineCycleTests.swift | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift b/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift index e9ada6bb2..c37cb98ba 100644 --- a/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift +++ b/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift @@ -863,4 +863,97 @@ class Z80MachineCycleTests: XCTestCase { ] ) } + + // JP nn + func testJPnn() { + test( + program: [0xc3, 0x00, 0x80], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .read, length: 3), + ] + ) + } + + // JP cc, nn + func testJPccnn() { + test( + program: [ + 0x37, // SCF + 0xd2, 0x00, 0x80, // JP NC, 0x8000 + 0xda, 0x00, 0x80, // JP C, 0x8000 + ], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .read, length: 3), + + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .read, length: 3), + ] + ) + } + + // JR e + func testJRe() { + test( + program: [0x18, 0x80], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .internalOperation, length: 5), + MachineCycle(operation: .readOpcode, length: 4), + ] + ) + } + + // JR cc, e + func testJRcce() { + test( + program: [ + 0x37, // SCF + 0x30, 0x80, // JR NC, 0x8000 + 0x38, 0x80, // JR C, 0x8000 + ], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .internalOperation, length: 5), + + MachineCycle(operation: .readOpcode, length: 4), + ] + ) + } + + // JP (HL) + func testJPHL() { + test( + program: [0xe9], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + ] + ) + } + + // JP (IX) + func testJPIX() { + test( + program: [0xdd, 0xe9], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + ] + ) + } } From fadbfdf801feb5b57bd1d434216e67370e499171 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 19 Jun 2017 21:31:56 -0400 Subject: [PATCH 37/55] Added DJNZ test. --- .../Z80MachineCycleTests.swift | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift b/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift index c37cb98ba..c32b8d529 100644 --- a/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift +++ b/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift @@ -956,4 +956,27 @@ class Z80MachineCycleTests: XCTestCase { ] ) } + + // DJNZ + func testDJNZ() { + test( + program: [ + 0x06, 0x02, // LD B, 2 + 0x10, 0xfe, // DJNZ -2 + ], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + + MachineCycle(operation: .readOpcode, length: 5), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .internalOperation, length: 5), + + MachineCycle(operation: .readOpcode, length: 5), + MachineCycle(operation: .read, length: 3), + + MachineCycle(operation: .readOpcode, length: 4), + ] + ) + } } From e05076b25831c26cde145464cabe7921a1a8f769 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 19 Jun 2017 22:00:04 -0400 Subject: [PATCH 38/55] Added tests for everything except CALL. All passing. --- .../Z80MachineCycleTests.swift | 211 ++++++++++++++++++ 1 file changed, 211 insertions(+) diff --git a/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift b/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift index c32b8d529..0db6bcaf1 100644 --- a/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift +++ b/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift @@ -979,4 +979,215 @@ class Z80MachineCycleTests: XCTestCase { ] ) } + + // TODO: CALL + + // RET + func testRET() { + test( + program: [0xc9], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .read, length: 3), + + MachineCycle(operation: .readOpcode, length: 4), + ] + ) + } + + // RET cc + func testRETcc() { + test( + program: [ + 0x37, // SCF + 0xd0, // RET NC + 0xd8, // RET C + ], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + + MachineCycle(operation: .readOpcode, length: 5), + + MachineCycle(operation: .readOpcode, length: 5), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .read, length: 3), + + MachineCycle(operation: .readOpcode, length: 4), + ] + ) + } + + // RETI + func testRETI() { + test( + program: [0xed, 0x4d], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .read, length: 3), + + MachineCycle(operation: .readOpcode, length: 4), + ] + ) + } + + // RST + func testRST() { + test( + program: [0xc7], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 5), + MachineCycle(operation: .write, length: 3), + MachineCycle(operation: .write, length: 3), + + MachineCycle(operation: .readOpcode, length: 4), + ] + ) + } + + // IN A, (n) + func testINAn() { + test( + program: [0xdb, 0xfe], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .portRead, length: 4), + + MachineCycle(operation: .readOpcode, length: 4), + ] + ) + } + + // IN r, (C) + func testINrC() { + test( + program: [0xed, 0x40], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .portRead, length: 4), + + MachineCycle(operation: .readOpcode, length: 4), + ] + ) + } + + // INI + func testINI() { + test( + program: [0xed, 0xa2], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 5), + MachineCycle(operation: .portRead, length: 4), + MachineCycle(operation: .write, length: 3), + + MachineCycle(operation: .readOpcode, length: 4), + ] + ) + } + + // INIR + func testINIR() { + test( + program: [ + 0x01, 0x02, 0x00, // LD BC, 2 + 0xed, 0xb2, // INIR + 0x00, 0x00, 0x00 // NOP, NOP, NOP + ], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .read, length: 3), + + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 5), + MachineCycle(operation: .portRead, length: 4), + MachineCycle(operation: .write, length: 3), + MachineCycle(operation: .internalOperation, length: 5), + + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 5), + MachineCycle(operation: .portRead, length: 4), + MachineCycle(operation: .write, length: 3), + + MachineCycle(operation: .readOpcode, length: 4), + ] + ) + } + + // OUT (n), A + func testOUTnA() { + test( + program: [0xd3, 0xfe], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .portWrite, length: 4), + + MachineCycle(operation: .readOpcode, length: 4), + ] + ) + } + + // OUT (C), r + func testOUTCr() { + test( + program: [0xed, 0x41], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .portWrite, length: 4), + + MachineCycle(operation: .readOpcode, length: 4), + ] + ) + } + + // OUTI + func testOUTI() { + test( + program: [0xed, 0xa3], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 5), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .portWrite, length: 4), + + MachineCycle(operation: .readOpcode, length: 4), + ] + ) + } + + // OTIR + func testOTIR() { + test( + program: [ + 0x01, 0x02, 0x00, // LD BC, 2 + 0xed, 0xb3, // OTIR + 0x00, 0x00, 0x00 // NOP, NOP, NOP + ], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .read, length: 3), + + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 5), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .portWrite, length: 4), + MachineCycle(operation: .internalOperation, length: 5), + + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 5), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .portWrite, length: 4), + + MachineCycle(operation: .readOpcode, length: 4), + ] + ) + } } From 6752f165db8f8ffc62a75c0e171bc4f11a2c4076 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 19 Jun 2017 22:03:29 -0400 Subject: [PATCH 39/55] Added failing tests for both kinds of CALL. --- .../Z80MachineCycleTests.swift | 42 ++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift b/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift index 0db6bcaf1..623198eee 100644 --- a/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift +++ b/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift @@ -980,7 +980,47 @@ class Z80MachineCycleTests: XCTestCase { ) } - // TODO: CALL + // CALL + func testCALL() { + test( + program: [0xcd, 0x00, 0x80], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .read, length: 4), + MachineCycle(operation: .write, length: 3), + MachineCycle(operation: .write, length: 3), + + MachineCycle(operation: .readOpcode, length: 4), + ] + ) + } + + // CALL cc + func testCALLcc() { + test( + program: [ + 0x37, // SCF + 0xd4, // CALL NC + 0xdc, // CALL C + ], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .read, length: 3), + + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .read, length: 4), + MachineCycle(operation: .write, length: 3), + MachineCycle(operation: .write, length: 3), + + MachineCycle(operation: .readOpcode, length: 4), + ] + ) + } // RET func testRET() { From a0d0f383c8976a15f7042c194b592490c766a7b7 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 19 Jun 2017 22:07:36 -0400 Subject: [PATCH 40/55] =?UTF-8?q?Corrected=20unconditional=20CALL=20timing?= =?UTF-8?q?.=20Conditional's=20going=20to=20require=20more=20work=20becaus?= =?UTF-8?q?e=20once=20the=20wait=20state=20is=20put=20into=20the=20right?= =?UTF-8?q?=20place,=20it=20breaks=20the=20assumption=20under=20which=20th?= =?UTF-8?q?e=20Z80=20handles=20conditions=20=E2=80=94=20that=20they're=20e?= =?UTF-8?q?ither=20do=20something=20or=20else=20do=20nothing.=20So=20that?= =?UTF-8?q?=20can=20wait=20a=20day.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Processors/Z80/Z80.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Processors/Z80/Z80.hpp b/Processors/Z80/Z80.hpp index 9d4aba26a..1bddc6d40 100644 --- a/Processors/Z80/Z80.hpp +++ b/Processors/Z80/Z80.hpp @@ -656,7 +656,7 @@ template class Processor { /* 0xc7 RST 00h */ RST(), /* 0xc8 RET Z */ RET(TestZ), /* 0xc9 RET */ StdInstr(Pop(pc_)), /* 0xca JP Z */ JP(TestZ), /* 0xcb [CB page] */StdInstr(FINDEX(), {MicroOp::SetInstructionPage, &cb_page}), - /* 0xcc CALL Z */ CALL(TestZ), /* 0xcd CALL */ StdInstr(Read16(pc_, temp16_), Push(pc_), {MicroOp::Move16, &temp16_.full, &pc_.full}), + /* 0xcc CALL Z */ CALL(TestZ), /* 0xcd CALL */ StdInstr(ReadInc(pc_, temp16_.bytes.low), Read4(pc_, temp16_.bytes.high), Push(pc_), {MicroOp::Move16, &temp16_.full, &pc_.full}), /* 0xce ADC A, n */ StdInstr(ReadInc(pc_, temp8_), {MicroOp::ADC8, &temp8_}), /* 0xcf RST 08h */ RST(), /* 0xd0 RET NC */ RET(TestNC), /* 0xd1 POP DE */ StdInstr(Pop(de_)), From 25aba16ef8c795b6a8d8ea39c99a5a5c8ec805a3 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 19 Jun 2017 22:20:23 -0400 Subject: [PATCH 41/55] Quickly checking the FUSE tests, corrected a handful of instances where PC should be modified but isn't, correcting around 800 new failures. --- Processors/Z80/Z80.hpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Processors/Z80/Z80.hpp b/Processors/Z80/Z80.hpp index 1bddc6d40..0a051965c 100644 --- a/Processors/Z80/Z80.hpp +++ b/Processors/Z80/Z80.hpp @@ -292,6 +292,7 @@ template class Processor { #define Inc16(r) {(&r == &pc_) ? MicroOp::IncrementPC : MicroOp::Increment16, &r.full} #define ReadInc(addr, val) Read3(addr, val), Inc16(addr) +#define Read4Inc(addr, val) Read4(addr, val), Inc16(addr) #define WriteInc(addr, val) Write3(addr, val), {MicroOp::Increment16, &addr.full} #define Read16Inc(addr, val) ReadInc(addr, val.bytes.low), ReadInc(addr, val.bytes.high) @@ -299,8 +300,8 @@ template class Processor { #define Write16(addr, val) WriteInc(addr, val.bytes.low), Write3(addr, val.bytes.high) -#define INDEX() {MicroOp::IndexedPlaceHolder}, Read3(pc_, temp8_), InternalOperation(5), {MicroOp::CalculateIndexAddress, &index} -#define FINDEX() {MicroOp::IndexedPlaceHolder}, Read3(pc_, temp8_), {MicroOp::CalculateIndexAddress, &index} +#define INDEX() {MicroOp::IndexedPlaceHolder}, ReadInc(pc_, temp8_), InternalOperation(5), {MicroOp::CalculateIndexAddress, &index} +#define FINDEX() {MicroOp::IndexedPlaceHolder}, ReadInc(pc_, temp8_), {MicroOp::CalculateIndexAddress, &index} #define INDEX_ADDR() (add_offsets ? memptr_ : index) #define Push(x) {MicroOp::Decrement16, &sp_.full}, Write3(sp_, x.bytes.high), {MicroOp::Decrement16, &sp_.full}, Write3(sp_, x.bytes.low) @@ -583,7 +584,7 @@ template class Processor { /* 0x33 INC SP */ Instr(4, {MicroOp::Increment16, &sp_.full}), /* 0x34 INC (HL) */ StdInstr(INDEX(), Read4(INDEX_ADDR(), temp8_), {MicroOp::Increment8, &temp8_}, Write3(INDEX_ADDR(), temp8_)), /* 0x35 DEC (HL) */ StdInstr(INDEX(), Read4(INDEX_ADDR(), temp8_), {MicroOp::Decrement8, &temp8_}, Write3(INDEX_ADDR(), temp8_)), - /* 0x36 LD (HL), n */ StdInstr({MicroOp::IndexedPlaceHolder}, ReadInc(pc_, temp8_), {MicroOp::CalculateIndexAddress, &index}, Read3(pc_, temp8_), Write3(INDEX_ADDR(), temp8_)), // WAIT(add_offsets ? 2 : 0), + /* 0x36 LD (HL), n */ StdInstr({MicroOp::IndexedPlaceHolder}, ReadInc(pc_, temp8_), {MicroOp::CalculateIndexAddress, &index}, ReadInc(pc_, temp8_), Write3(INDEX_ADDR(), temp8_)), /* 0x37 SCF */ StdInstr({MicroOp::SCF}), /* 0x38 JR C */ JR(TestC), /* 0x39 ADD HL, SP */ ADD16(index, sp_), @@ -656,7 +657,7 @@ template class Processor { /* 0xc7 RST 00h */ RST(), /* 0xc8 RET Z */ RET(TestZ), /* 0xc9 RET */ StdInstr(Pop(pc_)), /* 0xca JP Z */ JP(TestZ), /* 0xcb [CB page] */StdInstr(FINDEX(), {MicroOp::SetInstructionPage, &cb_page}), - /* 0xcc CALL Z */ CALL(TestZ), /* 0xcd CALL */ StdInstr(ReadInc(pc_, temp16_.bytes.low), Read4(pc_, temp16_.bytes.high), Push(pc_), {MicroOp::Move16, &temp16_.full, &pc_.full}), + /* 0xcc CALL Z */ CALL(TestZ), /* 0xcd CALL */ StdInstr(ReadInc(pc_, temp16_.bytes.low), Read4Inc(pc_, temp16_.bytes.high), Push(pc_), {MicroOp::Move16, &temp16_.full, &pc_.full}), /* 0xce ADC A, n */ StdInstr(ReadInc(pc_, temp8_), {MicroOp::ADC8, &temp8_}), /* 0xcf RST 08h */ RST(), /* 0xd0 RET NC */ RET(TestNC), /* 0xd1 POP DE */ StdInstr(Pop(de_)), From 27ac3429281456ba8a5525004463f347a13f532b Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 20 Jun 2017 20:57:23 -0400 Subject: [PATCH 42/55] Corrected conditional call timing, and its test. --- .../Z80MachineCycleTests.swift | 6 ++-- Processors/Z80/Z80.hpp | 31 +++++++++++++------ 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift b/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift index 623198eee..29a489a8a 100644 --- a/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift +++ b/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift @@ -1000,9 +1000,9 @@ class Z80MachineCycleTests: XCTestCase { func testCALLcc() { test( program: [ - 0x37, // SCF - 0xd4, // CALL NC - 0xdc, // CALL C + 0x37, // SCF + 0xd4, 0x00, 0x80, // CALL NC + 0xdc, 0x00, 0x80 // CALL C ], busCycles: [ MachineCycle(operation: .readOpcode, length: 4), diff --git a/Processors/Z80/Z80.hpp b/Processors/Z80/Z80.hpp index 0a051965c..87c54648d 100644 --- a/Processors/Z80/Z80.hpp +++ b/Processors/Z80/Z80.hpp @@ -273,6 +273,7 @@ template class Processor { InstructionPage() : r_step(1), is_indexed(false) {} }; + std::vector conditional_call_untaken_program_; std::vector reset_program_; std::vector irq_program_[3]; std::vector nmi_program_; @@ -314,7 +315,7 @@ template class Processor { #define NOP Sequence(BusOp(Refresh(2))) #define JP(cc) StdInstr(Read16Inc(pc_, temp16_), {MicroOp::cc}, {MicroOp::Move16, &temp16_.full, &pc_.full}) -#define CALL(cc) StdInstr(Read16Inc(pc_, temp16_), {MicroOp::cc}, Push(pc_), {MicroOp::Move16, &temp16_.full, &pc_.full}) // WAIT(1), +#define CALL(cc) StdInstr(ReadInc(pc_, temp16_.bytes.low), {MicroOp::cc, conditional_call_untaken_program_.data()}, Read4Inc(pc_, temp16_.bytes.high), Push(pc_), {MicroOp::Move16, &temp16_.full, &pc_.full}) #define RET(cc) Instr(3, {MicroOp::cc}, Pop(memptr_), {MicroOp::Move16, &memptr_.full, &pc_.full}) #define JR(cc) StdInstr(ReadInc(pc_, temp8_), {MicroOp::cc}, InternalOperation(5), {MicroOp::CalculateIndexAddress, &pc_.full}, {MicroOp::Move16, &memptr_.full, &pc_.full}) #define RST() Instr(3, {MicroOp::CalculateRSTDestination}, Push(pc_), {MicroOp::Move16, &memptr_.full, &pc_.full}) @@ -735,6 +736,9 @@ template class Processor { scheduled_program_counter_(nullptr) { set_flags(0xff); + MicroOp conditional_call_untaken_program[] = Sequence(ReadInc(pc_, temp16_.bytes.high)); + copy_program(conditional_call_untaken_program, conditional_call_untaken_program_); + assemble_base_page(base_page_, hl_, false, cb_page_); assemble_base_page(dd_page_, ix_, true, ddcb_page_); assemble_base_page(fd_page_, iy_, true, fdcb_page_); @@ -1190,14 +1194,23 @@ template class Processor { #pragma mark - Conditionals - case MicroOp::TestNZ: if(!zero_result_) { advance_operation(); } break; - case MicroOp::TestZ: if(zero_result_) { advance_operation(); } break; - case MicroOp::TestNC: if(carry_result_ & Flag::Carry) { advance_operation(); } break; - case MicroOp::TestC: if(!(carry_result_ & Flag::Carry)) { advance_operation(); } break; - case MicroOp::TestPO: if(parity_overflow_result_ & Flag::Parity) { advance_operation(); } break; - case MicroOp::TestPE: if(!(parity_overflow_result_ & Flag::Parity)) { advance_operation(); } break; - case MicroOp::TestP: if(sign_result_ & Flag::Sign) { advance_operation(); } break; - case MicroOp::TestM: if(!(sign_result_ & Flag::Sign)) { advance_operation(); } break; +#define decline_conditional() \ + if(operation->source) { \ + scheduled_program_counter_ = (MicroOp *)operation->source; \ + } else { \ + advance_operation(); \ + } + + case MicroOp::TestNZ: if(!zero_result_) { decline_conditional(); } break; + case MicroOp::TestZ: if(zero_result_) { decline_conditional(); } break; + case MicroOp::TestNC: if(carry_result_ & Flag::Carry) { decline_conditional(); } break; + case MicroOp::TestC: if(!(carry_result_ & Flag::Carry)) { decline_conditional(); } break; + case MicroOp::TestPO: if(parity_overflow_result_ & Flag::Parity) { decline_conditional(); } break; + case MicroOp::TestPE: if(!(parity_overflow_result_ & Flag::Parity)) { decline_conditional(); } break; + case MicroOp::TestP: if(sign_result_ & Flag::Sign) { decline_conditional(); } break; + case MicroOp::TestM: if(!(sign_result_ & Flag::Sign)) { decline_conditional(); } break; + +#undef decline_conditional #pragma mark - Exchange From 48942848e70de0cc12fa62f1ca603a6576da3e5f Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 20 Jun 2017 21:15:56 -0400 Subject: [PATCH 43/55] Fixed (Ix+d) read timing. I've put an extra wait cycle into the read, so no need to extend the refresh. --- Processors/Z80/Z80.hpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Processors/Z80/Z80.hpp b/Processors/Z80/Z80.hpp index 87c54648d..ca208d9f2 100644 --- a/Processors/Z80/Z80.hpp +++ b/Processors/Z80/Z80.hpp @@ -360,14 +360,14 @@ template class Processor { RMWI(a_, op) #define IX_READ_OP_GROUP(op) \ - Instr(4, Read4(INDEX_ADDR(), temp8_), {MicroOp::op, &temp8_}), \ - Instr(4, Read4(INDEX_ADDR(), temp8_), {MicroOp::op, &temp8_}), \ - Instr(4, Read4(INDEX_ADDR(), temp8_), {MicroOp::op, &temp8_}), \ - Instr(4, Read4(INDEX_ADDR(), temp8_), {MicroOp::op, &temp8_}), \ - Instr(4, Read4(INDEX_ADDR(), temp8_), {MicroOp::op, &temp8_}), \ - Instr(4, Read4(INDEX_ADDR(), temp8_), {MicroOp::op, &temp8_}), \ - Instr(4, Read4(INDEX_ADDR(), temp8_), {MicroOp::op, &temp8_}), \ - Instr(4, Read4(INDEX_ADDR(), temp8_), {MicroOp::op, &temp8_}) + StdInstr(Read4(INDEX_ADDR(), temp8_), {MicroOp::op, &temp8_}), \ + StdInstr(Read4(INDEX_ADDR(), temp8_), {MicroOp::op, &temp8_}), \ + StdInstr(Read4(INDEX_ADDR(), temp8_), {MicroOp::op, &temp8_}), \ + StdInstr(Read4(INDEX_ADDR(), temp8_), {MicroOp::op, &temp8_}), \ + StdInstr(Read4(INDEX_ADDR(), temp8_), {MicroOp::op, &temp8_}), \ + StdInstr(Read4(INDEX_ADDR(), temp8_), {MicroOp::op, &temp8_}), \ + StdInstr(Read4(INDEX_ADDR(), temp8_), {MicroOp::op, &temp8_}), \ + StdInstr(Read4(INDEX_ADDR(), temp8_), {MicroOp::op, &temp8_}) #define ADD16(d, s) StdInstr(InternalOperation(4), InternalOperation(3), {MicroOp::ADD16, &s.full, &d.full}) #define ADC16(d, s) StdInstr(InternalOperation(4), InternalOperation(3), {MicroOp::ADC16, &s.full, &d.full}) From b0375bb037448da99d885ec3681c73c7b261ce1f Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 20 Jun 2017 21:32:23 -0400 Subject: [PATCH 44/55] Fixed the three LD rr, (nn) operations. Back down to four FUSE failures. --- Processors/Z80/Z80.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Processors/Z80/Z80.hpp b/Processors/Z80/Z80.hpp index ca208d9f2..3030d28c4 100644 --- a/Processors/Z80/Z80.hpp +++ b/Processors/Z80/Z80.hpp @@ -446,7 +446,7 @@ template class Processor { /* 0x54 NEG */ StdInstr({MicroOp::NEG}), /* 0x55 RETN */ StdInstr(Pop(pc_), {MicroOp::RETN}), /* 0x56 IM 1 */ StdInstr({MicroOp::IM}), /* 0x57 LD A, I */ Instr(3, {MicroOp::Move8, &ir_.bytes.high, &a_}, {MicroOp::SetAFlags}), /* 0x40 IN B, (C); 0x41 OUT (C), B */ IN_OUT(de_.bytes.low), - /* 0x5a ADC HL, DE */ ADC16(hl_, de_), /* 0x5b LD DE, (nn) */ StdInstr(Read16Inc(pc_, temp16_), Write16(temp16_, de_)), + /* 0x5a ADC HL, DE */ ADC16(hl_, de_), /* 0x5b LD DE, (nn) */ StdInstr(Read16Inc(pc_, temp16_), Read16(temp16_, de_)), /* 0x5c NEG */ StdInstr({MicroOp::NEG}), /* 0x5d RETN */ StdInstr(Pop(pc_), {MicroOp::RETN}), /* 0x5e IM 2 */ StdInstr({MicroOp::IM}), /* 0x5f LD A, R */ Instr(3, {MicroOp::Move8, &ir_.bytes.low, &a_}, {MicroOp::SetAFlags}), /* 0x40 IN B, (C); 0x41 OUT (C), B */ IN_OUT(hl_.bytes.high), @@ -454,7 +454,7 @@ template class Processor { /* 0x64 NEG */ StdInstr({MicroOp::NEG}), /* 0x65 RETN */ StdInstr(Pop(pc_), {MicroOp::RETN}), /* 0x66 IM 0 */ StdInstr({MicroOp::IM}), /* 0x67 RRD */ StdInstr(Read3(hl_, temp8_), InternalOperation(4), {MicroOp::RRD}, Write3(hl_, temp8_)), /* 0x40 IN B, (C); 0x41 OUT (C), B */ IN_OUT(hl_.bytes.low), - /* 0x6a ADC HL, HL */ ADC16(hl_, hl_), /* 0x6b LD HL, (nn) */ StdInstr(Read16Inc(pc_, temp16_), Write16(temp16_, hl_)), + /* 0x6a ADC HL, HL */ ADC16(hl_, hl_), /* 0x6b LD HL, (nn) */ StdInstr(Read16Inc(pc_, temp16_), Read16(temp16_, hl_)), /* 0x6c NEG */ StdInstr({MicroOp::NEG}), /* 0x6d RETN */ StdInstr(Pop(pc_), {MicroOp::RETN}), /* 0x6e IM 0/1 */ StdInstr({MicroOp::IM}), /* 0x6f RLD */ StdInstr(Read3(hl_, temp8_), InternalOperation(4), {MicroOp::RLD}, Write3(hl_, temp8_)), /* 0x70 IN (C) */ IN_C(temp8_), /* 0x71 OUT (C), 0 */ StdInstr({MicroOp::SetZero}, Output(bc_, temp8_)), @@ -462,7 +462,7 @@ template class Processor { /* 0x74 NEG */ StdInstr({MicroOp::NEG}), /* 0x75 RETN */ StdInstr(Pop(pc_), {MicroOp::RETN}), /* 0x76 IM 1 */ StdInstr({MicroOp::IM}), /* 0x77 XX */ NOP, /* 0x40 IN B, (C); 0x41 OUT (C), B */ IN_OUT(a_), - /* 0x7a ADC HL, SP */ ADC16(hl_, sp_), /* 0x7b LD SP, (nn) */ StdInstr(Read16Inc(pc_, temp16_), Write16(temp16_, sp_)), + /* 0x7a ADC HL, SP */ ADC16(hl_, sp_), /* 0x7b LD SP, (nn) */ StdInstr(Read16Inc(pc_, temp16_), Read16(temp16_, sp_)), /* 0x7c NEG */ StdInstr({MicroOp::NEG}), /* 0x7d RETN */ StdInstr(Pop(pc_), {MicroOp::RETN}), /* 0x7e IM 2 */ StdInstr({MicroOp::IM}), /* 0x7f XX */ NOP, NOP_ROW(), /* 0x80 */ From 184b3716490c3b1b946b89d91b4c5677ca02629c Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 20 Jun 2017 21:48:50 -0400 Subject: [PATCH 45/55] Attempted to get to 'proper' timing for LD (IX+d),n, albeit that proper is a guess. --- .../Clock SignalTests/Z80MachineCycleTests.swift | 14 ++++++++++++++ Processors/Z80/Z80.hpp | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift b/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift index 29a489a8a..1109db5d6 100644 --- a/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift +++ b/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift @@ -156,6 +156,20 @@ class Z80MachineCycleTests: XCTestCase { ) } + // LD (IX+d), n + func testLDIXdn() { + test( + program: [0xdd, 0x36, 0x10, 0x80], + busCycles: [ + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .readOpcode, length: 4), + MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .internalOperation, length: 5), + MachineCycle(operation: .read, length: 3), + ] + ) + } + // LD A, (DE) func testLDADE() { test( diff --git a/Processors/Z80/Z80.hpp b/Processors/Z80/Z80.hpp index 3030d28c4..fd76f474e 100644 --- a/Processors/Z80/Z80.hpp +++ b/Processors/Z80/Z80.hpp @@ -585,7 +585,7 @@ template class Processor { /* 0x33 INC SP */ Instr(4, {MicroOp::Increment16, &sp_.full}), /* 0x34 INC (HL) */ StdInstr(INDEX(), Read4(INDEX_ADDR(), temp8_), {MicroOp::Increment8, &temp8_}, Write3(INDEX_ADDR(), temp8_)), /* 0x35 DEC (HL) */ StdInstr(INDEX(), Read4(INDEX_ADDR(), temp8_), {MicroOp::Decrement8, &temp8_}, Write3(INDEX_ADDR(), temp8_)), - /* 0x36 LD (HL), n */ StdInstr({MicroOp::IndexedPlaceHolder}, ReadInc(pc_, temp8_), {MicroOp::CalculateIndexAddress, &index}, ReadInc(pc_, temp8_), Write3(INDEX_ADDR(), temp8_)), + /* 0x36 LD (HL), n */ StdInstr(INDEX(), ReadInc(pc_, temp8_), Write3(INDEX_ADDR(), temp8_)), /* 0x37 SCF */ StdInstr({MicroOp::SCF}), /* 0x38 JR C */ JR(TestC), /* 0x39 ADD HL, SP */ ADD16(index, sp_), From f85b46286e92651b060c9c396c8e6770d04704b2 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 20 Jun 2017 22:20:58 -0400 Subject: [PATCH 46/55] Resolved the timing disparity between LD (HL),n and LD (IX+d), n, hopefully having come up with a convincing theory of timing for the latter. --- Processors/Z80/Z80.hpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/Processors/Z80/Z80.hpp b/Processors/Z80/Z80.hpp index fd76f474e..143a65b4a 100644 --- a/Processors/Z80/Z80.hpp +++ b/Processors/Z80/Z80.hpp @@ -110,6 +110,7 @@ struct MachineCycle { // Compound bus operations, as micro-ops #define Read3(addr, val) BusOp(ReadStart(addr, val)), BusOp(ReadWait(1, addr, val, true)), BusOp(ReadEnd(addr, val)) #define Read4(addr, val) BusOp(ReadStart(addr, val)), BusOp(ReadWait(1, addr, val, false)), BusOp(ReadWait(1, addr, val, true)), BusOp(ReadEnd(addr, val)) +#define Read5(addr, val) BusOp(ReadStart(addr, val)), BusOp(ReadWait(2, addr, val, false)), BusOp(ReadWait(1, addr, val, true)), BusOp(ReadEnd(addr, val)) #define Write3(addr, val) BusOp(WriteStart(addr, val)), BusOp(WriteWait(1, addr, val, true)), BusOp(WriteEnd(addr, val)) #define Write5(addr, val) BusOp(WriteStart(addr, val)), BusOp(WriteWait(2, addr, val, false)), BusOp(WriteWait(1, addr, val, true)), BusOp(WriteEnd(addr, val)) @@ -294,6 +295,7 @@ template class Processor { #define ReadInc(addr, val) Read3(addr, val), Inc16(addr) #define Read4Inc(addr, val) Read4(addr, val), Inc16(addr) +#define Read5Inc(addr, val) Read5(addr, val), Inc16(addr) #define WriteInc(addr, val) Write3(addr, val), {MicroOp::Increment16, &addr.full} #define Read16Inc(addr, val) ReadInc(addr, val.bytes.low), ReadInc(addr, val.bytes.high) @@ -585,7 +587,7 @@ template class Processor { /* 0x33 INC SP */ Instr(4, {MicroOp::Increment16, &sp_.full}), /* 0x34 INC (HL) */ StdInstr(INDEX(), Read4(INDEX_ADDR(), temp8_), {MicroOp::Increment8, &temp8_}, Write3(INDEX_ADDR(), temp8_)), /* 0x35 DEC (HL) */ StdInstr(INDEX(), Read4(INDEX_ADDR(), temp8_), {MicroOp::Decrement8, &temp8_}, Write3(INDEX_ADDR(), temp8_)), - /* 0x36 LD (HL), n */ StdInstr(INDEX(), ReadInc(pc_, temp8_), Write3(INDEX_ADDR(), temp8_)), + /* 0x36 LD (HL), n */ StdInstr(ReadInc(pc_, temp8_), Write3(INDEX_ADDR(), temp8_)), /* 0x37 SCF */ StdInstr({MicroOp::SCF}), /* 0x38 JR C */ JR(TestC), /* 0x39 ADD HL, SP */ ADD16(index, sp_), @@ -692,6 +694,16 @@ template class Processor { /* 0xfe CP n */ StdInstr(ReadInc(pc_, temp8_), {MicroOp::CP8, &temp8_}), /* 0xff RST 38h */ RST(), }; + + if(add_offsets) { + // The indexed version of 0x36 differs substantially from the non-indexed by building index calculation into + // the cycle that fetches the final operand. So patch in a different microprogram if building an indexed table. + InstructionTable copy_table = { + StdInstr(FINDEX(), Read5Inc(pc_, temp8_), Write3(INDEX_ADDR(), temp8_)) + }; + memcpy(&base_program_table[0x36], ©_table[0], sizeof(copy_table[0])); + } + assemble_cb_page(cb_page, index, add_offsets); assemble_page(target, base_program_table, add_offsets); } From 108da64562cca02e0c86fc6d04c8028f6f90193e Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 20 Jun 2017 22:25:00 -0400 Subject: [PATCH 47/55] Fixed LD H, (HL) and LD L, (HL) by ensuring that whatever the subclass does goes to a temporary place before updating the address. Corrected the LD (IX+d), n machine cycle test for my new best-guess timing. This should leave only interrupt timing as currently amiss. --- OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift | 4 ++-- Processors/Z80/Z80.hpp | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift b/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift index 1109db5d6..a8a115827 100644 --- a/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift +++ b/OSBindings/Mac/Clock SignalTests/Z80MachineCycleTests.swift @@ -164,8 +164,8 @@ class Z80MachineCycleTests: XCTestCase { MachineCycle(operation: .readOpcode, length: 4), MachineCycle(operation: .readOpcode, length: 4), MachineCycle(operation: .read, length: 3), - MachineCycle(operation: .internalOperation, length: 5), - MachineCycle(operation: .read, length: 3), + MachineCycle(operation: .read, length: 5), + MachineCycle(operation: .write, length: 3), ] ) } diff --git a/Processors/Z80/Z80.hpp b/Processors/Z80/Z80.hpp index 143a65b4a..70bc9d51a 100644 --- a/Processors/Z80/Z80.hpp +++ b/Processors/Z80/Z80.hpp @@ -325,7 +325,9 @@ template class Processor { #define LD_GROUP(r, ri) \ LD(r, bc_.bytes.high), LD(r, bc_.bytes.low), LD(r, de_.bytes.high), LD(r, de_.bytes.low), \ - LD(r, index.bytes.high), LD(r, index.bytes.low), StdInstr(INDEX(), Read3(INDEX_ADDR(), ri)), LD(r, a_) + LD(r, index.bytes.high), LD(r, index.bytes.low), \ + StdInstr(INDEX(), Read3(INDEX_ADDR(), temp8_), {MicroOp::Move8, &temp8_, &ri}), \ + LD(r, a_) #define READ_OP_GROUP(op) \ StdInstr({MicroOp::op, &bc_.bytes.high}), StdInstr({MicroOp::op, &bc_.bytes.low}), \ From 10cc94f5814ddbbb6a149f2ca3ffcaefeca75c3b Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 21 Jun 2017 18:47:00 -0400 Subject: [PATCH 48/55] Attempted to fix interrupt response timing; ensured initial interrupt mode is one that won't jump beyond the interrupt response program table's length, and that the conditionals other than CALL definitely have no alternative program attached. --- Processors/Z80/Z80.hpp | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/Processors/Z80/Z80.hpp b/Processors/Z80/Z80.hpp index 70bc9d51a..adff02d78 100644 --- a/Processors/Z80/Z80.hpp +++ b/Processors/Z80/Z80.hpp @@ -84,9 +84,9 @@ struct MachineCycle { }; // Elemental bus operations -#define ReadOpcodeStart(addr, val) {MachineCycle::ReadOpcode, MachineCycle::Phase::Start, 2, &addr.full, &val, false} -#define ReadOpcodeWait(addr, val, f) {MachineCycle::ReadOpcode, MachineCycle::Phase::Wait, 1, &addr.full, &val, f} -#define Refresh(len) {MachineCycle::Refresh, MachineCycle::Phase::End, len, &ir_.full, nullptr, false} +#define ReadOpcodeStart() {MachineCycle::ReadOpcode, MachineCycle::Phase::Start, 2, &pc_.full, &operation_, false} +#define ReadOpcodeWait(length, f) {MachineCycle::ReadOpcode, MachineCycle::Phase::Wait, length, &pc_.full, &operation_, f} +#define Refresh(len) {MachineCycle::Refresh, MachineCycle::Phase::End, len, &ir_.full, nullptr, false} #define ReadStart(addr, val) {MachineCycle::Read, MachineCycle::Phase::Start, 2, &addr.full, &val, false} #define ReadWait(l, addr, val, f) {MachineCycle::Read, MachineCycle::Phase::Wait, l, &addr.full, &val, f} @@ -104,6 +104,8 @@ struct MachineCycle { #define OutputWait(addr, val, f) {MachineCycle::Output, MachineCycle::Phase::Wait, 1, &addr.full, &val, f} #define OutputEnd(addr, val) {MachineCycle::Output, MachineCycle::Phase::End, 1, &addr.full, &val} +#define IntAck(length) {MachineCycle::Operation::Interrupt, MachineCycle::Phase::End, length, nullptr, &operation_} + // A wrapper to express a bus operation as a micro-op #define BusOp(op) {MicroOp::BusOperation, nullptr, nullptr, op} @@ -316,10 +318,10 @@ template class Processor { /* The following are actual instructions */ #define NOP Sequence(BusOp(Refresh(2))) -#define JP(cc) StdInstr(Read16Inc(pc_, temp16_), {MicroOp::cc}, {MicroOp::Move16, &temp16_.full, &pc_.full}) +#define JP(cc) StdInstr(Read16Inc(pc_, temp16_), {MicroOp::cc, nullptr}, {MicroOp::Move16, &temp16_.full, &pc_.full}) #define CALL(cc) StdInstr(ReadInc(pc_, temp16_.bytes.low), {MicroOp::cc, conditional_call_untaken_program_.data()}, Read4Inc(pc_, temp16_.bytes.high), Push(pc_), {MicroOp::Move16, &temp16_.full, &pc_.full}) -#define RET(cc) Instr(3, {MicroOp::cc}, Pop(memptr_), {MicroOp::Move16, &memptr_.full, &pc_.full}) -#define JR(cc) StdInstr(ReadInc(pc_, temp8_), {MicroOp::cc}, InternalOperation(5), {MicroOp::CalculateIndexAddress, &pc_.full}, {MicroOp::Move16, &memptr_.full, &pc_.full}) +#define RET(cc) Instr(3, {MicroOp::cc, nullptr}, Pop(memptr_), {MicroOp::Move16, &memptr_.full, &pc_.full}) +#define JR(cc) StdInstr(ReadInc(pc_, temp8_), {MicroOp::cc, nullptr}, InternalOperation(5), {MicroOp::CalculateIndexAddress, &pc_.full}, {MicroOp::Move16, &memptr_.full, &pc_.full}) #define RST() Instr(3, {MicroOp::CalculateRSTDestination}, Push(pc_), {MicroOp::Move16, &memptr_.full, &pc_.full}) #define LD(a, b) StdInstr({MicroOp::Move8, &b, &a}) @@ -712,14 +714,14 @@ template class Processor { void assemble_fetch_decode_execute(InstructionPage &target, int length) { const MicroOp normal_fetch_decode_execute[] = { - BusOp(ReadOpcodeStart(pc_, operation_)), - BusOp(ReadOpcodeWait(pc_, operation_, true)), + BusOp(ReadOpcodeStart()), + BusOp(ReadOpcodeWait(1, true)), { MicroOp::DecodeOperation } }; const MicroOp short_fetch_decode_execute[] = { - BusOp(ReadOpcodeStart(pc_, operation_)), - BusOp(ReadOpcodeWait(pc_, operation_, false)), - BusOp(ReadOpcodeWait(pc_, operation_, true)), + BusOp(ReadOpcodeStart()), + BusOp(ReadOpcodeWait(1, false)), + BusOp(ReadOpcodeWait(1, true)), { MicroOp::DecodeOperation } }; copy_program((length == 4) ? normal_fetch_decode_execute : short_fetch_decode_execute, target.fetch_decode_execute); @@ -742,6 +744,7 @@ template class Processor { Processor() : halt_mask_(0xff), number_of_cycles_(0), + interrupt_mode_(0), request_status_(Interrupt::PowerOn), last_request_status_(Interrupt::PowerOn), irq_line_(false), @@ -778,26 +781,28 @@ template class Processor { MicroOp reset_program[] = Sequence(InternalOperation(3), {MicroOp::Reset}); MicroOp nmi_program[] = { { MicroOp::BeginNMI }, -// { MicroOp::BusOperation, nullptr, nullptr, {MachineCycle::ReadOpcode, 5, &pc_.full, &operation_}}, + BusOp(ReadOpcodeStart()), + BusOp(ReadOpcodeWait(1, false)), + BusOp(Refresh(2)), Push(pc_), { MicroOp::JumpTo66, nullptr, nullptr}, { MicroOp::MoveToNextProgram } }; MicroOp irq_mode0_program[] = { { MicroOp::BeginIRQMode0 }, - { MicroOp::BusOperation, nullptr, nullptr, {MachineCycle::Operation::Interrupt, MachineCycle::Phase::End, 6, nullptr, &operation_}}, + BusOp(IntAck(6)), { MicroOp::DecodeOperationNoRChange } }; MicroOp irq_mode1_program[] = { { MicroOp::BeginIRQ }, -// { MicroOp::BusOperation, nullptr, nullptr, {MachineCycle::Operation::Interrupt, 7, nullptr, &operation_}}, + BusOp(IntAck(7)), Push(pc_), { MicroOp::Move16, &temp16_.full, &pc_.full }, { MicroOp::MoveToNextProgram } }; MicroOp irq_mode2_program[] = { { MicroOp::BeginIRQ }, -// { MicroOp::BusOperation, nullptr, nullptr, {MachineCycle::Operation::Interrupt, 7, nullptr, &temp16_.bytes.low}}, + BusOp(IntAck(7)), Push(pc_), { MicroOp::Move8, &ir_.bytes.high, &temp16_.bytes.high }, Read16(pc_, temp16_), From db743c90d87cd6ad8f169ca3bebab837ff544f22 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 21 Jun 2017 18:58:44 -0400 Subject: [PATCH 49/55] Had neglected to count refresh time in my interrupt programs. Corrected. Mode 0 timing test succeeds again. Only Mode 2 is now at fault. --- Processors/Z80/Z80.hpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Processors/Z80/Z80.hpp b/Processors/Z80/Z80.hpp index adff02d78..e465798aa 100644 --- a/Processors/Z80/Z80.hpp +++ b/Processors/Z80/Z80.hpp @@ -790,19 +790,21 @@ template class Processor { }; MicroOp irq_mode0_program[] = { { MicroOp::BeginIRQMode0 }, - BusOp(IntAck(6)), + BusOp(IntAck(4)), { MicroOp::DecodeOperationNoRChange } }; MicroOp irq_mode1_program[] = { { MicroOp::BeginIRQ }, - BusOp(IntAck(7)), + BusOp(IntAck(5)), + BusOp(Refresh(2)), Push(pc_), { MicroOp::Move16, &temp16_.full, &pc_.full }, { MicroOp::MoveToNextProgram } }; MicroOp irq_mode2_program[] = { { MicroOp::BeginIRQ }, - BusOp(IntAck(7)), + BusOp(IntAck(5)), + BusOp(Refresh(2)), Push(pc_), { MicroOp::Move8, &ir_.bytes.high, &temp16_.bytes.high }, Read16(pc_, temp16_), From 45f442ea6388e4279892b21517a45659f2c78f6f Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 21 Jun 2017 19:08:48 -0400 Subject: [PATCH 50/55] Corrected interrupt mode 2: was both failing properly to load the vector address, and failing to read from it. --- Processors/Z80/Z80.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Processors/Z80/Z80.hpp b/Processors/Z80/Z80.hpp index e465798aa..0b4a6e776 100644 --- a/Processors/Z80/Z80.hpp +++ b/Processors/Z80/Z80.hpp @@ -104,7 +104,7 @@ struct MachineCycle { #define OutputWait(addr, val, f) {MachineCycle::Output, MachineCycle::Phase::Wait, 1, &addr.full, &val, f} #define OutputEnd(addr, val) {MachineCycle::Output, MachineCycle::Phase::End, 1, &addr.full, &val} -#define IntAck(length) {MachineCycle::Operation::Interrupt, MachineCycle::Phase::End, length, nullptr, &operation_} +#define IntAck(length, val) {MachineCycle::Operation::Interrupt, MachineCycle::Phase::End, length, nullptr, &val} // A wrapper to express a bus operation as a micro-op #define BusOp(op) {MicroOp::BusOperation, nullptr, nullptr, op} @@ -790,12 +790,12 @@ template class Processor { }; MicroOp irq_mode0_program[] = { { MicroOp::BeginIRQMode0 }, - BusOp(IntAck(4)), + BusOp(IntAck(4, operation_)), { MicroOp::DecodeOperationNoRChange } }; MicroOp irq_mode1_program[] = { { MicroOp::BeginIRQ }, - BusOp(IntAck(5)), + BusOp(IntAck(5, operation_)), BusOp(Refresh(2)), Push(pc_), { MicroOp::Move16, &temp16_.full, &pc_.full }, @@ -803,11 +803,11 @@ template class Processor { }; MicroOp irq_mode2_program[] = { { MicroOp::BeginIRQ }, - BusOp(IntAck(5)), + BusOp(IntAck(5, temp16_.bytes.low)), BusOp(Refresh(2)), Push(pc_), { MicroOp::Move8, &ir_.bytes.high, &temp16_.bytes.high }, - Read16(pc_, temp16_), + Read16(temp16_, pc_), { MicroOp::MoveToNextProgram } }; From 36e8a115053c57d27f90135d8884b3063238ad9b Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 21 Jun 2017 20:32:08 -0400 Subject: [PATCH 51/55] Sought to simplify the way partial machine cycles are communicated, for ease of machine implementation. Also implemented the wait line. --- Machines/ZX8081/ZX8081.cpp | 7 +- .../Bridges/TestMachineZ80.h | 1 - .../Bridges/TestMachineZ80.mm | 75 ++++++---------- Processors/Z80/Z80.hpp | 90 ++++++++++++------- Processors/Z80/Z80AllRAM.cpp | 74 +++++++-------- Processors/Z80/Z80AllRAM.hpp | 2 +- 6 files changed, 131 insertions(+), 118 deletions(-) diff --git a/Machines/ZX8081/ZX8081.cpp b/Machines/ZX8081/ZX8081.cpp index 4142ba511..346030674 100644 --- a/Machines/ZX8081/ZX8081.cpp +++ b/Machines/ZX8081/ZX8081.cpp @@ -59,6 +59,7 @@ int Machine::perform_machine_cycle(const CPU::Z80::MachineCycle &cycle) { uint16_t refresh = 0; uint16_t address = cycle.address ? *cycle.address : 0; + bool is_opcode_read = false; switch(cycle.operation) { case CPU::Z80::MachineCycle::Operation::Output: set_vsync(false); @@ -90,7 +91,8 @@ int Machine::perform_machine_cycle(const CPU::Z80::MachineCycle &cycle) { horizontal_counter_ = 0; break; - case CPU::Z80::MachineCycle::Operation::ReadOpcode: + case CPU::Z80::MachineCycle::Operation::ReadOpcodeStart: + case CPU::Z80::MachineCycle::Operation::ReadOpcodeWait: // The ZX80 and 81 signal an interrupt while refresh is active and bit 6 of the refresh // address is low. The Z80 signals a refresh, providing the refresh address during the // final two cycles of an opcode fetch. Therefore communicate a transient signalling @@ -110,6 +112,7 @@ int Machine::perform_machine_cycle(const CPU::Z80::MachineCycle &cycle) { return 0; } } + is_opcode_read = true; case CPU::Z80::MachineCycle::Operation::Read: if(address < ram_base_) { @@ -120,7 +123,7 @@ int Machine::perform_machine_cycle(const CPU::Z80::MachineCycle &cycle) { // If this is an M1 cycle reading from above the 32kb mark and HALT is not // currently active, perform a video output and return a NOP. Otherwise, // just return the value as read. - if(cycle.operation == CPU::Z80::MachineCycle::Operation::ReadOpcode && address&0x8000 && !(value & 0x40) && !get_halt_line()) { + if(is_opcode_read && address&0x8000 && !(value & 0x40) && !get_halt_line()) { size_t char_address = (size_t)((refresh & 0xff00) | ((value & 0x3f) << 3) | line_counter_); if(char_address < ram_base_) { uint8_t mask = (value & 0x80) ? 0x00 : 0xff; diff --git a/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.h b/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.h index 55f6fdcd7..f1d0ec6a3 100644 --- a/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.h +++ b/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.h @@ -52,7 +52,6 @@ typedef NS_ENUM(NSInteger, CSTestMachineZ80Register) { - (uint8_t)valueAtAddress:(uint16_t)address; - (void)runForNumberOfCycles:(int)cycles; -- (void)runToNextInstruction; - (void)setValue:(uint16_t)value forRegister:(CSTestMachineZ80Register)reg; - (uint16_t)valueForRegister:(CSTestMachineZ80Register)reg; diff --git a/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.mm b/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.mm index 4137bc8a3..fa05a7e38 100644 --- a/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.mm +++ b/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.mm @@ -12,7 +12,6 @@ @interface CSTestMachineZ80 () - (void)testMachineDidPerformBusOperation:(CPU::Z80::MachineCycle::Operation)operation - phase:(CPU::Z80::MachineCycle::Phase)phase address:(uint16_t)address value:(uint8_t)value timeStamp:(int)time_stamp; @@ -24,8 +23,8 @@ class BusOperationHandler: public CPU::Z80::AllRAMProcessor::MemoryAccessDelegat public: BusOperationHandler(CSTestMachineZ80 *targetMachine) : target_(targetMachine) {} - void z80_all_ram_processor_did_perform_bus_operation(CPU::Z80::AllRAMProcessor &processor, CPU::Z80::MachineCycle::Operation operation, CPU::Z80::MachineCycle::Phase phase, uint16_t address, uint8_t value, int time_stamp) { - [target_ testMachineDidPerformBusOperation:operation phase:phase address:address value:value timeStamp:time_stamp]; + void z80_all_ram_processor_did_perform_bus_operation(CPU::Z80::AllRAMProcessor &processor, CPU::Z80::MachineCycle::Operation operation, uint16_t address, uint8_t value, int time_stamp) { + [target_ testMachineDidPerformBusOperation:operation address:address value:value timeStamp:time_stamp]; } private: @@ -102,7 +101,6 @@ static CPU::Z80::Register registerForRegister(CSTestMachineZ80Register reg) { BusOperationHandler *_busOperationHandler; NSMutableArray *_busOperationCaptures; - BOOL _isAtReadOpcode; int _timeSeekingReadOpcode; int _lastOpcodeTime; } @@ -173,17 +171,6 @@ static CPU::Z80::Register registerForRegister(CSTestMachineZ80Register reg) { return _processor; } -#pragma mark - Z80-specific Runner - -- (void)runToNextInstruction { - _isAtReadOpcode = NO; - _timeSeekingReadOpcode = 0; - while(!_isAtReadOpcode) { - _timeSeekingReadOpcode++; - _processor->run_for_cycles(1); - } -} - #pragma mark - Bus operation accumulation - (void)setCaptureBusActivity:(BOOL)captureBusActivity { @@ -191,50 +178,44 @@ static CPU::Z80::Register registerForRegister(CSTestMachineZ80Register reg) { _processor->set_memory_access_delegate(captureBusActivity ? _busOperationHandler : nullptr); } -- (void)testMachineDidPerformBusOperation:(CPU::Z80::MachineCycle::Operation)operation phase:(CPU::Z80::MachineCycle::Phase)phase address:(uint16_t)address value:(uint8_t)value timeStamp:(int)timeStamp { +- (void)testMachineDidPerformBusOperation:(CPU::Z80::MachineCycle::Operation)operation address:(uint16_t)address value:(uint8_t)value timeStamp:(int)timeStamp { int length = timeStamp - _lastOpcodeTime; _lastOpcodeTime = timeStamp; - if(operation == CPU::Z80::MachineCycle::Operation::ReadOpcode && length < _timeSeekingReadOpcode) - _isAtReadOpcode = YES; if(self.captureBusActivity) { CSTestMachineZ80BusOperationCapture *capture = [[CSTestMachineZ80BusOperationCapture alloc] init]; - if(phase == CPU::Z80::MachineCycle::Phase::End) { - switch(operation) { - case CPU::Z80::MachineCycle::Operation::Write: - capture.operation = CSTestMachineZ80BusOperationCaptureOperationWrite; - break; + switch(operation) { + case CPU::Z80::MachineCycle::Operation::Write: + capture.operation = CSTestMachineZ80BusOperationCaptureOperationWrite; + break; - case CPU::Z80::MachineCycle::Operation::Read: - capture.operation = CSTestMachineZ80BusOperationCaptureOperationRead; - break; + case CPU::Z80::MachineCycle::Operation::Read: + capture.operation = CSTestMachineZ80BusOperationCaptureOperationRead; + break; - case CPU::Z80::MachineCycle::Operation::ReadOpcode: - case CPU::Z80::MachineCycle::Operation::Refresh: - capture.operation = CSTestMachineZ80BusOperationCaptureOperationReadOpcode; - break; + case CPU::Z80::MachineCycle::Operation::Refresh: + capture.operation = CSTestMachineZ80BusOperationCaptureOperationReadOpcode; + break; - case CPU::Z80::MachineCycle::Operation::Input: - capture.operation = CSTestMachineZ80BusOperationCaptureOperationPortRead; - break; + case CPU::Z80::MachineCycle::Operation::Input: + capture.operation = CSTestMachineZ80BusOperationCaptureOperationPortRead; + break; - case CPU::Z80::MachineCycle::Operation::Output: - capture.operation = CSTestMachineZ80BusOperationCaptureOperationPortWrite; - break; + case CPU::Z80::MachineCycle::Operation::Output: + capture.operation = CSTestMachineZ80BusOperationCaptureOperationPortWrite; + break; - case CPU::Z80::MachineCycle::Operation::Internal: - capture.operation = CSTestMachineZ80BusOperationCaptureOperationInternalOperation; - break; + case CPU::Z80::MachineCycle::Operation::Internal: + capture.operation = CSTestMachineZ80BusOperationCaptureOperationInternalOperation; + break; - default: - return; - } - capture.address = address; - capture.value = value; - capture.timeStamp = timeStamp; - - [_busOperationCaptures addObject:capture]; + default: return; } + capture.address = address; + capture.value = value; + capture.timeStamp = timeStamp; + + [_busOperationCaptures addObject:capture]; } } diff --git a/Processors/Z80/Z80.hpp b/Processors/Z80/Z80.hpp index 0b4a6e776..f7b993ba4 100644 --- a/Processors/Z80/Z80.hpp +++ b/Processors/Z80/Z80.hpp @@ -64,47 +64,62 @@ enum Flag: uint8_t { */ struct MachineCycle { enum Operation { - ReadOpcode = 0, - Refresh, - Read, Write, - Input, Output, + ReadOpcodeStart = 0, + ReadOpcodeWait, + Read, + Write, + Input, + Output, Interrupt, + + Refresh, + Internal, BusAcknowledge, - Internal + + ReadStart, + ReadWait, + WriteStart, + WriteWait, + InputStart, + InputWait, + OutputStart, + OutputWait } operation; - enum Phase { - Start, - Wait, - End - } phase; int length; uint16_t *address; uint8_t *value; bool was_requested; + + inline bool expects_action() const { + return operation <= Operation::Interrupt; + } + inline bool is_terminal() const { + return operation <= Operation::BusAcknowledge; + } }; // Elemental bus operations -#define ReadOpcodeStart() {MachineCycle::ReadOpcode, MachineCycle::Phase::Start, 2, &pc_.full, &operation_, false} -#define ReadOpcodeWait(length, f) {MachineCycle::ReadOpcode, MachineCycle::Phase::Wait, length, &pc_.full, &operation_, f} -#define Refresh(len) {MachineCycle::Refresh, MachineCycle::Phase::End, len, &ir_.full, nullptr, false} +#define ReadOpcodeStart() {MachineCycle::ReadOpcodeStart, 2, &pc_.full, &operation_, false} +#define ReadOpcodeWait(length, f) {MachineCycle::ReadOpcodeWait, length, &pc_.full, &operation_, f} +#define Refresh(len) {MachineCycle::Refresh, len, &ir_.full, nullptr, false} -#define ReadStart(addr, val) {MachineCycle::Read, MachineCycle::Phase::Start, 2, &addr.full, &val, false} -#define ReadWait(l, addr, val, f) {MachineCycle::Read, MachineCycle::Phase::Wait, l, &addr.full, &val, f} -#define ReadEnd(addr, val) {MachineCycle::Read, MachineCycle::Phase::End, 1, &addr.full, &val, false} +#define ReadStart(addr, val) {MachineCycle::ReadStart, 2, &addr.full, &val, false} +#define ReadWait(l, addr, val, f) {MachineCycle::ReadWait, l, &addr.full, &val, f} +#define ReadEnd(addr, val) {MachineCycle::Read, 1, &addr.full, &val, false} -#define WriteStart(addr, val) {MachineCycle::Write, MachineCycle::Phase::Start, 2, &addr.full, &val, false} -#define WriteWait(l, addr, val, f) {MachineCycle::Write, MachineCycle::Phase::Wait, l, &addr.full, &val, f} -#define WriteEnd(addr, val) {MachineCycle::Write, MachineCycle::Phase::End, 1, &addr.full, &val, false} +#define WriteStart(addr, val) {MachineCycle::WriteStart, 2, &addr.full, &val, false} +#define WriteWait(l, addr, val, f) {MachineCycle::WriteWait, l, &addr.full, &val, f} +#define WriteEnd(addr, val) {MachineCycle::Write, 1, &addr.full, &val, false} -#define InputStart(addr, val) {MachineCycle::Input, MachineCycle::Phase::Start, 2, &addr.full, &val, false} -#define InputWait(addr, val, f) {MachineCycle::Input, MachineCycle::Phase::Wait, 1, &addr.full, &val, f} -#define InputEnd(addr, val) {MachineCycle::Input, MachineCycle::Phase::End, 1, &addr.full, &val, false} +#define InputStart(addr, val) {MachineCycle::InputStart, 2, &addr.full, &val, false} +#define InputWait(addr, val, f) {MachineCycle::InputWait, 1, &addr.full, &val, f} +#define InputEnd(addr, val) {MachineCycle::Input, 1, &addr.full, &val, false} -#define OutputStart(addr, val) {MachineCycle::Output, MachineCycle::Phase::Start, 2, &addr.full, &val} -#define OutputWait(addr, val, f) {MachineCycle::Output, MachineCycle::Phase::Wait, 1, &addr.full, &val, f} -#define OutputEnd(addr, val) {MachineCycle::Output, MachineCycle::Phase::End, 1, &addr.full, &val} +#define OutputStart(addr, val) {MachineCycle::OutputStart, 2, &addr.full, &val} +#define OutputWait(addr, val, f) {MachineCycle::OutputWait, 1, &addr.full, &val, f} +#define OutputEnd(addr, val) {MachineCycle::Output, 1, &addr.full, &val} -#define IntAck(length, val) {MachineCycle::Operation::Interrupt, MachineCycle::Phase::End, length, nullptr, &val} +#define IntAck(length, val) {MachineCycle::Interrupt, length, nullptr, &val} // A wrapper to express a bus operation as a micro-op #define BusOp(op) {MicroOp::BusOperation, nullptr, nullptr, op} @@ -119,7 +134,7 @@ struct MachineCycle { #define Input(addr, val) BusOp(InputStart(addr, val)), BusOp(InputWait(addr, val, false)), BusOp(InputWait(addr, val, true)), BusOp(InputEnd(addr, val)) #define Output(addr, val) BusOp(OutputStart(addr, val)), BusOp(OutputWait(addr, val, false)), BusOp(OutputWait(addr, val, true)), BusOp(OutputEnd(addr, val)) -#define InternalOperation(len) {MicroOp::BusOperation, nullptr, nullptr, {MachineCycle::Internal, MachineCycle::Phase::End, len}} +#define InternalOperation(len) {MicroOp::BusOperation, nullptr, nullptr, {MachineCycle::Internal, len}} /// A sequence is a series of micro-ops that ends in a move-to-next-program operation. #define Sequence(...) { __VA_ARGS__, {MicroOp::MoveToNextProgram} } @@ -173,6 +188,7 @@ template class Processor { uint8_t last_request_status_; bool irq_line_; bool bus_request_line_; + bool wait_line_; uint8_t operation_; RegisterPair temp16_, memptr_; @@ -745,6 +761,7 @@ template class Processor { halt_mask_(0xff), number_of_cycles_(0), interrupt_mode_(0), + wait_line_(false), request_status_(Interrupt::PowerOn), last_request_status_(Interrupt::PowerOn), irq_line_(false), @@ -855,7 +872,7 @@ template class Processor { while(1) { while(bus_request_line_) { - static MachineCycle bus_acknowledge_cycle = {MachineCycle::Operation::BusAcknowledge, MachineCycle::Phase::End, 1}; + static MachineCycle bus_acknowledge_cycle = {MachineCycle::Operation::BusAcknowledge, 1}; number_of_cycles_ -= static_cast(this)->perform_machine_cycle(bus_acknowledge_cycle) + 1; if(!number_of_cycles_) { static_cast(this)->flush(); @@ -875,14 +892,18 @@ template class Processor { switch(operation->type) { case MicroOp::BusOperation: - if(operation->machine_cycle.was_requested) { // TODO: && !wait_line_ - continue; - } if(number_of_cycles_ < operation->machine_cycle.length) { scheduled_program_counter_--; static_cast(this)->flush(); return; } + if(operation->machine_cycle.was_requested) { + if(wait_line_) { + scheduled_program_counter_--; + } else { + continue; + } + } number_of_cycles_ -= operation->machine_cycle.length; last_request_status_ = request_status_; number_of_cycles_ -= static_cast(this)->perform_machine_cycle(operation->machine_cycle); @@ -1892,6 +1913,13 @@ template class Processor { last_request_status_ &= ~Interrupt::PowerOn; } + /*! + Sets the logical value of the wait line. + */ + inline void set_wait_line(bool value) { + wait_line_ = value; + } + /*! For receivers of perform_machine_cycle only. Temporarily rejects the current machine cycle, causing time to be rewinded to its beginning. diff --git a/Processors/Z80/Z80AllRAM.cpp b/Processors/Z80/Z80AllRAM.cpp index e6b315bfc..0fc493bf4 100644 --- a/Processors/Z80/Z80AllRAM.cpp +++ b/Processors/Z80/Z80AllRAM.cpp @@ -17,45 +17,47 @@ class ConcreteAllRAMProcessor: public AllRAMProcessor, public Processor> 8; - break; - - case MachineCycle::Operation::Internal: - case MachineCycle::Operation::Refresh: - break; - - case MachineCycle::Operation::Interrupt: - // A pick that means LD HL, (nn) if interpreted as an instruction but is otherwise - // arbitrary. - *cycle.value = 0x21; - break; - - default: - printf("???\n"); - break; - } -// } timestamp_ += cycle.length; + if(!cycle.is_terminal()) { + return 0; + } + + uint16_t address = cycle.address ? *cycle.address : 0x0000; + switch(cycle.operation) { + case MachineCycle::Operation::ReadOpcodeStart: + check_address_for_trap(address); + case MachineCycle::Operation::Read: + *cycle.value = memory_[address]; + break; + case MachineCycle::Operation::Write: + memory_[address] = *cycle.value; + break; + + case MachineCycle::Operation::Output: + break; + case MachineCycle::Operation::Input: + // This logic is selected specifically because it seems to match + // the FUSE unit tests. It might need factoring out. + *cycle.value = address >> 8; + break; + + case MachineCycle::Operation::Internal: + case MachineCycle::Operation::Refresh: + break; + + case MachineCycle::Operation::Interrupt: + // A pick that means LD HL, (nn) if interpreted as an instruction but is otherwise + // arbitrary. + *cycle.value = 0x21; + break; + + default: + printf("???\n"); + break; + } if(delegate_ != nullptr) { - delegate_->z80_all_ram_processor_did_perform_bus_operation(*this, cycle.operation, cycle.phase, address, cycle.value ? *cycle.value : 0x00, timestamp_); + delegate_->z80_all_ram_processor_did_perform_bus_operation(*this, cycle.operation, address, cycle.value ? *cycle.value : 0x00, timestamp_); } return 0; diff --git a/Processors/Z80/Z80AllRAM.hpp b/Processors/Z80/Z80AllRAM.hpp index 3c77f943c..e4890fa73 100644 --- a/Processors/Z80/Z80AllRAM.hpp +++ b/Processors/Z80/Z80AllRAM.hpp @@ -22,7 +22,7 @@ class AllRAMProcessor: static AllRAMProcessor *Processor(); struct MemoryAccessDelegate { - virtual void z80_all_ram_processor_did_perform_bus_operation(CPU::Z80::AllRAMProcessor &processor, CPU::Z80::MachineCycle::Operation operation, CPU::Z80::MachineCycle::Phase phase, uint16_t address, uint8_t value, int time_stamp) = 0; + virtual void z80_all_ram_processor_did_perform_bus_operation(CPU::Z80::AllRAMProcessor &processor, CPU::Z80::MachineCycle::Operation operation, uint16_t address, uint8_t value, int time_stamp) = 0; }; inline void set_memory_access_delegate(MemoryAccessDelegate *delegate) { delegate_ = delegate; From 0e0ce379b43bbea40cd2d9ec2d7b73bf16c1c4e0 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 21 Jun 2017 20:38:08 -0400 Subject: [PATCH 52/55] Renamed MachineCycle to PartialMachineCycle given that it mostly no longer intends to describe an entire machine cycle. --- Machines/ZX8081/ZX8081.cpp | 16 +++---- Machines/ZX8081/ZX8081.hpp | 2 +- .../Bridges/TestMachineZ80.mm | 18 ++++---- Processors/Z80/Z80.hpp | 46 +++++++++---------- Processors/Z80/Z80AllRAM.cpp | 18 ++++---- Processors/Z80/Z80AllRAM.hpp | 2 +- 6 files changed, 51 insertions(+), 51 deletions(-) diff --git a/Machines/ZX8081/ZX8081.cpp b/Machines/ZX8081/ZX8081.cpp index 346030674..0406a2927 100644 --- a/Machines/ZX8081/ZX8081.cpp +++ b/Machines/ZX8081/ZX8081.cpp @@ -27,7 +27,7 @@ Machine::Machine() : clear_all_keys(); } -int Machine::perform_machine_cycle(const CPU::Z80::MachineCycle &cycle) { +int Machine::perform_machine_cycle(const CPU::Z80::PartialMachineCycle &cycle) { int wait_cycles = 0; int previous_counter = horizontal_counter_; @@ -61,7 +61,7 @@ int Machine::perform_machine_cycle(const CPU::Z80::MachineCycle &cycle) { uint16_t address = cycle.address ? *cycle.address : 0; bool is_opcode_read = false; switch(cycle.operation) { - case CPU::Z80::MachineCycle::Operation::Output: + case CPU::Z80::PartialMachineCycle::Output: set_vsync(false); line_counter_ = 0; @@ -69,7 +69,7 @@ int Machine::perform_machine_cycle(const CPU::Z80::MachineCycle &cycle) { if(!(address & 1)) nmi_is_enabled_ = is_zx81_; break; - case CPU::Z80::MachineCycle::Operation::Input: { + case CPU::Z80::PartialMachineCycle::Input: { uint8_t value = 0xff; if(!(address&1)) { set_vsync(true); @@ -85,14 +85,14 @@ int Machine::perform_machine_cycle(const CPU::Z80::MachineCycle &cycle) { *cycle.value = value; } break; - case CPU::Z80::MachineCycle::Operation::Interrupt: + case CPU::Z80::PartialMachineCycle::Interrupt: line_counter_ = (line_counter_ + 1) & 7; *cycle.value = 0xff; horizontal_counter_ = 0; break; - case CPU::Z80::MachineCycle::Operation::ReadOpcodeStart: - case CPU::Z80::MachineCycle::Operation::ReadOpcodeWait: + case CPU::Z80::PartialMachineCycle::ReadOpcodeStart: + case CPU::Z80::PartialMachineCycle::ReadOpcodeWait: // The ZX80 and 81 signal an interrupt while refresh is active and bit 6 of the refresh // address is low. The Z80 signals a refresh, providing the refresh address during the // final two cycles of an opcode fetch. Therefore communicate a transient signalling @@ -114,7 +114,7 @@ int Machine::perform_machine_cycle(const CPU::Z80::MachineCycle &cycle) { } is_opcode_read = true; - case CPU::Z80::MachineCycle::Operation::Read: + case CPU::Z80::PartialMachineCycle::Read: if(address < ram_base_) { *cycle.value = rom_[address & rom_mask_]; } else { @@ -136,7 +136,7 @@ int Machine::perform_machine_cycle(const CPU::Z80::MachineCycle &cycle) { } break; - case CPU::Z80::MachineCycle::Operation::Write: + case CPU::Z80::PartialMachineCycle::Write: if(address >= ram_base_) { ram_[address & ram_mask_] = *cycle.value; } diff --git a/Machines/ZX8081/ZX8081.hpp b/Machines/ZX8081/ZX8081.hpp index 5778b85fe..b86367dfc 100644 --- a/Machines/ZX8081/ZX8081.hpp +++ b/Machines/ZX8081/ZX8081.hpp @@ -45,7 +45,7 @@ class Machine: public: Machine(); - int perform_machine_cycle(const CPU::Z80::MachineCycle &cycle); + int perform_machine_cycle(const CPU::Z80::PartialMachineCycle &cycle); void flush(); void setup_output(float aspect_ratio); diff --git a/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.mm b/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.mm index fa05a7e38..0a127c159 100644 --- a/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.mm +++ b/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.mm @@ -11,7 +11,7 @@ #import "TestMachine+ForSubclassEyesOnly.h" @interface CSTestMachineZ80 () -- (void)testMachineDidPerformBusOperation:(CPU::Z80::MachineCycle::Operation)operation +- (void)testMachineDidPerformBusOperation:(CPU::Z80::PartialMachineCycle::Operation)operation address:(uint16_t)address value:(uint8_t)value timeStamp:(int)time_stamp; @@ -23,7 +23,7 @@ class BusOperationHandler: public CPU::Z80::AllRAMProcessor::MemoryAccessDelegat public: BusOperationHandler(CSTestMachineZ80 *targetMachine) : target_(targetMachine) {} - void z80_all_ram_processor_did_perform_bus_operation(CPU::Z80::AllRAMProcessor &processor, CPU::Z80::MachineCycle::Operation operation, uint16_t address, uint8_t value, int time_stamp) { + void z80_all_ram_processor_did_perform_bus_operation(CPU::Z80::AllRAMProcessor &processor, CPU::Z80::PartialMachineCycle::Operation operation, uint16_t address, uint8_t value, int time_stamp) { [target_ testMachineDidPerformBusOperation:operation address:address value:value timeStamp:time_stamp]; } @@ -178,34 +178,34 @@ static CPU::Z80::Register registerForRegister(CSTestMachineZ80Register reg) { _processor->set_memory_access_delegate(captureBusActivity ? _busOperationHandler : nullptr); } -- (void)testMachineDidPerformBusOperation:(CPU::Z80::MachineCycle::Operation)operation address:(uint16_t)address value:(uint8_t)value timeStamp:(int)timeStamp { +- (void)testMachineDidPerformBusOperation:(CPU::Z80::PartialMachineCycle::Operation)operation address:(uint16_t)address value:(uint8_t)value timeStamp:(int)timeStamp { int length = timeStamp - _lastOpcodeTime; _lastOpcodeTime = timeStamp; if(self.captureBusActivity) { CSTestMachineZ80BusOperationCapture *capture = [[CSTestMachineZ80BusOperationCapture alloc] init]; switch(operation) { - case CPU::Z80::MachineCycle::Operation::Write: + case CPU::Z80::PartialMachineCycle::Write: capture.operation = CSTestMachineZ80BusOperationCaptureOperationWrite; break; - case CPU::Z80::MachineCycle::Operation::Read: + case CPU::Z80::PartialMachineCycle::Read: capture.operation = CSTestMachineZ80BusOperationCaptureOperationRead; break; - case CPU::Z80::MachineCycle::Operation::Refresh: + case CPU::Z80::PartialMachineCycle::Refresh: capture.operation = CSTestMachineZ80BusOperationCaptureOperationReadOpcode; break; - case CPU::Z80::MachineCycle::Operation::Input: + case CPU::Z80::PartialMachineCycle::Input: capture.operation = CSTestMachineZ80BusOperationCaptureOperationPortRead; break; - case CPU::Z80::MachineCycle::Operation::Output: + case CPU::Z80::PartialMachineCycle::Output: capture.operation = CSTestMachineZ80BusOperationCaptureOperationPortWrite; break; - case CPU::Z80::MachineCycle::Operation::Internal: + case CPU::Z80::PartialMachineCycle::Internal: capture.operation = CSTestMachineZ80BusOperationCaptureOperationInternalOperation; break; diff --git a/Processors/Z80/Z80.hpp b/Processors/Z80/Z80.hpp index f7b993ba4..30b5517c9 100644 --- a/Processors/Z80/Z80.hpp +++ b/Processors/Z80/Z80.hpp @@ -62,7 +62,7 @@ enum Flag: uint8_t { Subclasses will be given the task of performing bus operations, allowing them to provide whatever interface they like between a Z80 and the rest of the system. @c BusOperation lists the types of bus operation that may be requested. */ -struct MachineCycle { +struct PartialMachineCycle { enum Operation { ReadOpcodeStart = 0, ReadOpcodeWait, @@ -99,27 +99,27 @@ struct MachineCycle { }; // Elemental bus operations -#define ReadOpcodeStart() {MachineCycle::ReadOpcodeStart, 2, &pc_.full, &operation_, false} -#define ReadOpcodeWait(length, f) {MachineCycle::ReadOpcodeWait, length, &pc_.full, &operation_, f} -#define Refresh(len) {MachineCycle::Refresh, len, &ir_.full, nullptr, false} +#define ReadOpcodeStart() {PartialMachineCycle::ReadOpcodeStart, 2, &pc_.full, &operation_, false} +#define ReadOpcodeWait(length, f) {PartialMachineCycle::ReadOpcodeWait, length, &pc_.full, &operation_, f} +#define Refresh(len) {PartialMachineCycle::Refresh, len, &ir_.full, nullptr, false} -#define ReadStart(addr, val) {MachineCycle::ReadStart, 2, &addr.full, &val, false} -#define ReadWait(l, addr, val, f) {MachineCycle::ReadWait, l, &addr.full, &val, f} -#define ReadEnd(addr, val) {MachineCycle::Read, 1, &addr.full, &val, false} +#define ReadStart(addr, val) {PartialMachineCycle::ReadStart, 2, &addr.full, &val, false} +#define ReadWait(l, addr, val, f) {PartialMachineCycle::ReadWait, l, &addr.full, &val, f} +#define ReadEnd(addr, val) {PartialMachineCycle::Read, 1, &addr.full, &val, false} -#define WriteStart(addr, val) {MachineCycle::WriteStart, 2, &addr.full, &val, false} -#define WriteWait(l, addr, val, f) {MachineCycle::WriteWait, l, &addr.full, &val, f} -#define WriteEnd(addr, val) {MachineCycle::Write, 1, &addr.full, &val, false} +#define WriteStart(addr, val) {PartialMachineCycle::WriteStart, 2, &addr.full, &val, false} +#define WriteWait(l, addr, val, f) {PartialMachineCycle::WriteWait, l, &addr.full, &val, f} +#define WriteEnd(addr, val) {PartialMachineCycle::Write, 1, &addr.full, &val, false} -#define InputStart(addr, val) {MachineCycle::InputStart, 2, &addr.full, &val, false} -#define InputWait(addr, val, f) {MachineCycle::InputWait, 1, &addr.full, &val, f} -#define InputEnd(addr, val) {MachineCycle::Input, 1, &addr.full, &val, false} +#define InputStart(addr, val) {PartialMachineCycle::InputStart, 2, &addr.full, &val, false} +#define InputWait(addr, val, f) {PartialMachineCycle::InputWait, 1, &addr.full, &val, f} +#define InputEnd(addr, val) {PartialMachineCycle::Input, 1, &addr.full, &val, false} -#define OutputStart(addr, val) {MachineCycle::OutputStart, 2, &addr.full, &val} -#define OutputWait(addr, val, f) {MachineCycle::OutputWait, 1, &addr.full, &val, f} -#define OutputEnd(addr, val) {MachineCycle::Output, 1, &addr.full, &val} +#define OutputStart(addr, val) {PartialMachineCycle::OutputStart, 2, &addr.full, &val} +#define OutputWait(addr, val, f) {PartialMachineCycle::OutputWait, 1, &addr.full, &val, f} +#define OutputEnd(addr, val) {PartialMachineCycle::Output, 1, &addr.full, &val} -#define IntAck(length, val) {MachineCycle::Interrupt, length, nullptr, &val} +#define IntAck(length, val) {PartialMachineCycle::Interrupt, length, nullptr, &val} // A wrapper to express a bus operation as a micro-op #define BusOp(op) {MicroOp::BusOperation, nullptr, nullptr, op} @@ -134,7 +134,7 @@ struct MachineCycle { #define Input(addr, val) BusOp(InputStart(addr, val)), BusOp(InputWait(addr, val, false)), BusOp(InputWait(addr, val, true)), BusOp(InputEnd(addr, val)) #define Output(addr, val) BusOp(OutputStart(addr, val)), BusOp(OutputWait(addr, val, false)), BusOp(OutputWait(addr, val, true)), BusOp(OutputEnd(addr, val)) -#define InternalOperation(len) {MicroOp::BusOperation, nullptr, nullptr, {MachineCycle::Internal, len}} +#define InternalOperation(len) {MicroOp::BusOperation, nullptr, nullptr, {PartialMachineCycle::Internal, len}} /// A sequence is a series of micro-ops that ends in a move-to-next-program operation. #define Sequence(...) { __VA_ARGS__, {MicroOp::MoveToNextProgram} } @@ -277,7 +277,7 @@ template class Processor { Type type; void *source; void *destination; - MachineCycle machine_cycle; + PartialMachineCycle machine_cycle; }; const MicroOp *scheduled_program_counter_; @@ -838,7 +838,7 @@ template class Processor { /*! Runs the Z80 for a supplied number of cycles. - @discussion Subclasses must implement @c perform_machine_cycle(const MachineCycle &cycle) . + @discussion Subclasses must implement @c perform_machine_cycle(const PartialMachineCycle &cycle) . If it is a read operation then @c value will be seeded with the value 0xff. @@ -872,7 +872,7 @@ template class Processor { while(1) { while(bus_request_line_) { - static MachineCycle bus_acknowledge_cycle = {MachineCycle::Operation::BusAcknowledge, 1}; + static PartialMachineCycle bus_acknowledge_cycle = {PartialMachineCycle::BusAcknowledge, 1}; number_of_cycles_ -= static_cast(this)->perform_machine_cycle(bus_acknowledge_cycle) + 1; if(!number_of_cycles_) { static_cast(this)->flush(); @@ -1683,7 +1683,7 @@ template class Processor { */ void flush() {} - int perform_machine_cycle(const MachineCycle &cycle) { + int perform_machine_cycle(const PartialMachineCycle &cycle) { return 0; } @@ -1936,7 +1936,7 @@ template class Processor { /*! Returns the bus cycle that the Z80 is currently in the process of performing. */ -// const MachineCycle &get_current_bus_cycle(int &cycles_since_start) { +// const PartialMachineCycle &get_current_bus_cycle(int &cycles_since_start) { // } }; diff --git a/Processors/Z80/Z80AllRAM.cpp b/Processors/Z80/Z80AllRAM.cpp index 0fc493bf4..49292aa72 100644 --- a/Processors/Z80/Z80AllRAM.cpp +++ b/Processors/Z80/Z80AllRAM.cpp @@ -16,7 +16,7 @@ class ConcreteAllRAMProcessor: public AllRAMProcessor, public Processor> 8; break; - case MachineCycle::Operation::Internal: - case MachineCycle::Operation::Refresh: + case PartialMachineCycle::Internal: + case PartialMachineCycle::Refresh: break; - case MachineCycle::Operation::Interrupt: + case PartialMachineCycle::Interrupt: // A pick that means LD HL, (nn) if interpreted as an instruction but is otherwise // arbitrary. *cycle.value = 0x21; diff --git a/Processors/Z80/Z80AllRAM.hpp b/Processors/Z80/Z80AllRAM.hpp index e4890fa73..9ec9726da 100644 --- a/Processors/Z80/Z80AllRAM.hpp +++ b/Processors/Z80/Z80AllRAM.hpp @@ -22,7 +22,7 @@ class AllRAMProcessor: static AllRAMProcessor *Processor(); struct MemoryAccessDelegate { - virtual void z80_all_ram_processor_did_perform_bus_operation(CPU::Z80::AllRAMProcessor &processor, CPU::Z80::MachineCycle::Operation operation, uint16_t address, uint8_t value, int time_stamp) = 0; + virtual void z80_all_ram_processor_did_perform_bus_operation(CPU::Z80::AllRAMProcessor &processor, CPU::Z80::PartialMachineCycle::Operation operation, uint16_t address, uint8_t value, int time_stamp) = 0; }; inline void set_memory_access_delegate(MemoryAccessDelegate *delegate) { delegate_ = delegate; From 4bf13610ce37db6d53a741e6b1ec073ee7c739c0 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 21 Jun 2017 21:03:39 -0400 Subject: [PATCH 53/55] Reinstated interrupts by moving the refresh test back into the refresh cycle. --- Machines/ZX8081/ZX8081.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/Machines/ZX8081/ZX8081.cpp b/Machines/ZX8081/ZX8081.cpp index 0406a2927..0f8654dd0 100644 --- a/Machines/ZX8081/ZX8081.cpp +++ b/Machines/ZX8081/ZX8081.cpp @@ -57,6 +57,10 @@ int Machine::perform_machine_cycle(const CPU::Z80::PartialMachineCycle &cycle) { // tape_player_.run_for_cycles(cycle.length + wait_cycles); + if(!cycle.is_terminal()) { + return wait_cycles; + } + uint16_t refresh = 0; uint16_t address = cycle.address ? *cycle.address : 0; bool is_opcode_read = false; @@ -91,15 +95,21 @@ int Machine::perform_machine_cycle(const CPU::Z80::PartialMachineCycle &cycle) { horizontal_counter_ = 0; break; + case CPU::Z80::PartialMachineCycle::Refresh: + if(!(address & 0x40)) { + set_interrupt_line(true, -2); + set_interrupt_line(false); + } + break; + case CPU::Z80::PartialMachineCycle::ReadOpcodeStart: case CPU::Z80::PartialMachineCycle::ReadOpcodeWait: +// printf("%04x ", address); // The ZX80 and 81 signal an interrupt while refresh is active and bit 6 of the refresh // address is low. The Z80 signals a refresh, providing the refresh address during the // final two cycles of an opcode fetch. Therefore communicate a transient signalling // of the IRQ line if necessary. - refresh = get_value_of_register(CPU::Z80::Register::Refresh); - set_interrupt_line(!(refresh & 0x40), -2); - set_interrupt_line(false); +// refresh = get_value_of_register(CPU::Z80::Register::Refresh); // Check for use of the fast tape hack. if(address == tape_trap_address_) { // TODO: && fast_tape_hack_enabled_ From 7eeac3b5863e8fdbc46e11939dd473e092763e52 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 21 Jun 2017 21:11:00 -0400 Subject: [PATCH 54/55] Switched R back to incrementing after the refresh cycle. It had snuck to before by virtue of subdivision of the M1 cycle. Which shortened the ZX80 line time, breaking synchronisation. --- Processors/Z80/Z80.hpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Processors/Z80/Z80.hpp b/Processors/Z80/Z80.hpp index 30b5517c9..20622b965 100644 --- a/Processors/Z80/Z80.hpp +++ b/Processors/Z80/Z80.hpp @@ -101,7 +101,7 @@ struct PartialMachineCycle { // Elemental bus operations #define ReadOpcodeStart() {PartialMachineCycle::ReadOpcodeStart, 2, &pc_.full, &operation_, false} #define ReadOpcodeWait(length, f) {PartialMachineCycle::ReadOpcodeWait, length, &pc_.full, &operation_, f} -#define Refresh(len) {PartialMachineCycle::Refresh, len, &ir_.full, nullptr, false} +#define Refresh(len) {PartialMachineCycle::Refresh, len, &refresh_addr_.full, nullptr, false} #define ReadStart(addr, val) {PartialMachineCycle::ReadStart, 2, &addr.full, &val, false} #define ReadWait(l, addr, val, f) {PartialMachineCycle::ReadWait, l, &addr.full, &val, f} @@ -163,7 +163,7 @@ template class Processor { RegisterPair bc_, de_, hl_; RegisterPair afDash_, bcDash_, deDash_, hlDash_; RegisterPair ix_, iy_, pc_, sp_; - RegisterPair ir_; + RegisterPair ir_, refresh_addr_; bool iff1_, iff2_; int interrupt_mode_; uint16_t pc_increment_; @@ -912,9 +912,14 @@ template class Processor { advance_operation(); break; case MicroOp::DecodeOperation: + refresh_addr_ = ir_; ir_.bytes.low = (ir_.bytes.low & 0x80) | ((ir_.bytes.low + current_instruction_page_->r_step) & 0x7f); pc_.full += pc_increment_ & (uint16_t)halt_mask_; + scheduled_program_counter_ = current_instruction_page_->instructions[operation_ & halt_mask_]; + break; case MicroOp::DecodeOperationNoRChange: + refresh_addr_ = ir_; + pc_.full += pc_increment_ & (uint16_t)halt_mask_; scheduled_program_counter_ = current_instruction_page_->instructions[operation_ & halt_mask_]; break; From e1355d4b627c6ee7e8fa5b5fa55c26ea6dcb2a47 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 21 Jun 2017 21:18:09 -0400 Subject: [PATCH 55/55] Restored proper video output. --- Machines/ZX8081/ZX8081.cpp | 30 +++++++++++++++--------------- Machines/ZX8081/ZX8081.hpp | 1 + 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/Machines/ZX8081/ZX8081.cpp b/Machines/ZX8081/ZX8081.cpp index 0f8654dd0..b7c28a678 100644 --- a/Machines/ZX8081/ZX8081.cpp +++ b/Machines/ZX8081/ZX8081.cpp @@ -61,7 +61,6 @@ int Machine::perform_machine_cycle(const CPU::Z80::PartialMachineCycle &cycle) { return wait_cycles; } - uint16_t refresh = 0; uint16_t address = cycle.address ? *cycle.address : 0; bool is_opcode_read = false; switch(cycle.operation) { @@ -96,21 +95,28 @@ int Machine::perform_machine_cycle(const CPU::Z80::PartialMachineCycle &cycle) { break; case CPU::Z80::PartialMachineCycle::Refresh: + // The ZX80 and 81 signal an interrupt while refresh is active and bit 6 of the refresh + // address is low. The Z80 signals a refresh, providing the refresh address during the + // final two cycles of an opcode fetch. Therefore communicate a transient signalling + // of the IRQ line if necessary. if(!(address & 0x40)) { set_interrupt_line(true, -2); set_interrupt_line(false); } + if(latched_video_byte_) { + size_t char_address = (size_t)((address & 0xff00) | ((latched_video_byte_ & 0x3f) << 3) | line_counter_); + if(char_address < ram_base_) { + uint8_t mask = (latched_video_byte_ & 0x80) ? 0x00 : 0xff; + latched_video_byte_ = rom_[char_address & rom_mask_] ^ mask; + } + + video_->output_byte(latched_video_byte_); + latched_video_byte_ = 0; + } break; case CPU::Z80::PartialMachineCycle::ReadOpcodeStart: case CPU::Z80::PartialMachineCycle::ReadOpcodeWait: -// printf("%04x ", address); - // The ZX80 and 81 signal an interrupt while refresh is active and bit 6 of the refresh - // address is low. The Z80 signals a refresh, providing the refresh address during the - // final two cycles of an opcode fetch. Therefore communicate a transient signalling - // of the IRQ line if necessary. -// refresh = get_value_of_register(CPU::Z80::Register::Refresh); - // Check for use of the fast tape hack. if(address == tape_trap_address_) { // TODO: && fast_tape_hack_enabled_ int next_byte = parser_.get_next_byte(tape_player_.get_tape()); @@ -134,13 +140,7 @@ int Machine::perform_machine_cycle(const CPU::Z80::PartialMachineCycle &cycle) { // currently active, perform a video output and return a NOP. Otherwise, // just return the value as read. if(is_opcode_read && address&0x8000 && !(value & 0x40) && !get_halt_line()) { - size_t char_address = (size_t)((refresh & 0xff00) | ((value & 0x3f) << 3) | line_counter_); - if(char_address < ram_base_) { - uint8_t mask = (value & 0x80) ? 0x00 : 0xff; - value = rom_[char_address & rom_mask_] ^ mask; - } - - video_->output_byte(value); + latched_video_byte_ = value; *cycle.value = 0; } else *cycle.value = value; } diff --git a/Machines/ZX8081/ZX8081.hpp b/Machines/ZX8081/ZX8081.hpp index b86367dfc..f44d7580d 100644 --- a/Machines/ZX8081/ZX8081.hpp +++ b/Machines/ZX8081/ZX8081.hpp @@ -89,6 +89,7 @@ class Machine: bool is_zx81_; bool nmi_is_enabled_; int vsync_start_cycle_, vsync_end_cycle_; + uint8_t latched_video_byte_; }; }