From 540a03f75cede95c588832a4c467ab0bc7d12de6 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 21 Jul 2017 22:31:42 -0400 Subject: [PATCH 01/11] Exposed the memptr register. --- Processors/Z80/Z80.hpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Processors/Z80/Z80.hpp b/Processors/Z80/Z80.hpp index 7d260855a..d59898f10 100644 --- a/Processors/Z80/Z80.hpp +++ b/Processors/Z80/Z80.hpp @@ -40,7 +40,9 @@ enum Register { IYh, IYl, IY, R, I, Refresh, - IFF1, IFF2, IM + IFF1, IFF2, IM, + + MemPtr }; /* @@ -1796,6 +1798,8 @@ template class Processor { case Register::IFF2: return iff2_ ? 1 : 0; case Register::IM: return (uint16_t)interrupt_mode_; + case Register::MemPtr: return memptr_.full; + default: return 0; } } @@ -1855,6 +1859,8 @@ template class Processor { case Register::IFF2: iff2_ = !!value; break; case Register::IM: interrupt_mode_ = value % 3; break; + case Register::MemPtr: memptr_.full = value; break; + default: break; } } From 660f0e4c40bdd1a3deaf0d9033cc4767fb0e5b70 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 21 Jul 2017 22:52:25 -0400 Subject: [PATCH 02/11] Added Objective-C through wiring and a Swift test class for Memptr modifications. So far with a single test, that fails. --- .../Clock Signal.xcodeproj/project.pbxproj | 4 +++ .../Bridges/TestMachineZ80.h | 3 +- .../Bridges/TestMachineZ80.mm | 2 ++ .../Clock SignalTests/Z80MemptrTests.swift | 34 +++++++++++++++++++ 4 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 OSBindings/Mac/Clock SignalTests/Z80MemptrTests.swift diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 2925ec984..2b7baf4c3 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 4B01A6881F22F0DB001FD6E3 /* Z80MemptrTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B01A6871F22F0DB001FD6E3 /* Z80MemptrTests.swift */; }; 4B049CDD1DA3C82F00322067 /* BCDTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B049CDC1DA3C82F00322067 /* BCDTest.swift */; }; 4B08A2751EE35D56008B7065 /* Z80InterruptTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B08A2741EE35D56008B7065 /* Z80InterruptTests.swift */; }; 4B08A2781EE39306008B7065 /* TestMachine.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B08A2771EE39306008B7065 /* TestMachine.mm */; }; @@ -456,6 +457,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 4B01A6871F22F0DB001FD6E3 /* Z80MemptrTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Z80MemptrTests.swift; sourceTree = ""; }; 4B046DC31CFE651500E9E45E /* CRTMachine.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CRTMachine.hpp; sourceTree = ""; }; 4B049CDC1DA3C82F00322067 /* BCDTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BCDTest.swift; sourceTree = ""; }; 4B08A2741EE35D56008B7065 /* Z80InterruptTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Z80InterruptTests.swift; sourceTree = ""; }; @@ -1880,6 +1882,7 @@ 4B14145F1B58885000E04248 /* WolfgangLorenzTests.swift */, 4B08A2741EE35D56008B7065 /* Z80InterruptTests.swift */, 4BDDBA981EF3451200347E61 /* Z80MachineCycleTests.swift */, + 4B01A6871F22F0DB001FD6E3 /* Z80MemptrTests.swift */, 4BFCA12A1ECBE7C400AC40C1 /* ZexallTests.swift */, 4B3BA0C41D318B44005DD7A7 /* Bridges */, 4B1414631B588A1100E04248 /* Test Binaries */, @@ -2709,6 +2712,7 @@ 4B92EACA1B7C112B00246143 /* 6502TimingTests.swift in Sources */, 4BFCA1201ECBDC1500AC40C1 /* Z80AllRAM.cpp in Sources */, 4BB73EB71B587A5100552FC2 /* AllSuiteATests.swift in Sources */, + 4B01A6881F22F0DB001FD6E3 /* Z80MemptrTests.swift in Sources */, 4B121F9B1E06293F00BFDA12 /* PCMSegmentEventSourceTests.mm in Sources */, 4BEF6AAC1D35D1C400E73575 /* DPLLTests.swift in Sources */, 4B3BA0CF1D318B44005DD7A7 /* MOS6522Bridge.mm in Sources */, diff --git a/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.h b/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.h index 592b1bca3..1abdf63d8 100644 --- a/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.h +++ b/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.h @@ -42,7 +42,8 @@ typedef NS_ENUM(NSInteger, CSTestMachineZ80Register) { CSTestMachineZ80RegisterHLDash, CSTestMachineZ80RegisterIX, CSTestMachineZ80RegisterIY, CSTestMachineZ80RegisterI, CSTestMachineZ80RegisterR, - CSTestMachineZ80RegisterIFF1, CSTestMachineZ80RegisterIFF2, CSTestMachineZ80RegisterIM + CSTestMachineZ80RegisterIFF1, CSTestMachineZ80RegisterIFF2, CSTestMachineZ80RegisterIM, + CSTestMachineZ80RegisterMemPtr }; @interface CSTestMachineZ80 : CSTestMachine diff --git a/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.mm b/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.mm index 37f64f599..83cc41033 100644 --- a/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.mm +++ b/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.mm @@ -65,6 +65,8 @@ static CPU::Z80::Register registerForRegister(CSTestMachineZ80Register reg) { case CSTestMachineZ80RegisterProgramCounter: return CPU::Z80::Register::ProgramCounter; case CSTestMachineZ80RegisterStackPointer: return CPU::Z80::Register::StackPointer; + + case CSTestMachineZ80RegisterMemPtr: return CPU::Z80::Register::MemPtr; } } diff --git a/OSBindings/Mac/Clock SignalTests/Z80MemptrTests.swift b/OSBindings/Mac/Clock SignalTests/Z80MemptrTests.swift new file mode 100644 index 000000000..5b7dd6aef --- /dev/null +++ b/OSBindings/Mac/Clock SignalTests/Z80MemptrTests.swift @@ -0,0 +1,34 @@ +// +// Z80MemptrTests.swift +// Clock Signal +// +// Created by Thomas Harte on 21/07/2017. +// Copyright © 2017 Thomas Harte. All rights reserved. +// + +import XCTest + +class Z80MemptrTests: XCTestCase { + private func test(program : [UInt8], length : Int32, initialValue : UInt16) -> UInt16 { + // 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) + + // Set the initial value of memptr, run for the requested number of cycles, + // return the new value + machine.setValue(initialValue, for: .memPtr) + machine.runForNumber(ofCycles: length) + return machine.value(for: .memPtr) + } + + // LD A,(addr) + func testLDAnn() { + let program: [UInt8] = [ + 0x3a, 0x00, 0x00 + ] + let result = test(program: program, length: 13, initialValue: 0xffff) + XCTAssertEqual(result, 0x0001) + } + +} From d51b66c204c807d3c1659e0c82a847d5233897e9 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 21 Jul 2017 23:01:35 -0400 Subject: [PATCH 03/11] Expanded test to hit all 65536 possibilities (and not to allocate a fresh Z80 test machine each time, as that's unnecessary and slow), and fixed implementation to pass test. --- .../Mac/Clock SignalTests/Z80MemptrTests.swift | 15 +++++++++++---- Processors/Z80/Z80.hpp | 2 +- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/Z80MemptrTests.swift b/OSBindings/Mac/Clock SignalTests/Z80MemptrTests.swift index 5b7dd6aef..2b5e82f78 100644 --- a/OSBindings/Mac/Clock SignalTests/Z80MemptrTests.swift +++ b/OSBindings/Mac/Clock SignalTests/Z80MemptrTests.swift @@ -9,9 +9,10 @@ import XCTest class Z80MemptrTests: XCTestCase { + private let machine = CSTestMachineZ80() + private func test(program : [UInt8], length : Int32, initialValue : UInt16) -> UInt16 { // 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) @@ -24,11 +25,17 @@ class Z80MemptrTests: XCTestCase { // LD A,(addr) func testLDAnn() { - let program: [UInt8] = [ + var program: [UInt8] = [ 0x3a, 0x00, 0x00 ] - let result = test(program: program, length: 13, initialValue: 0xffff) - XCTAssertEqual(result, 0x0001) + for addr in 0 ..< 65536 { + program[1] = UInt8(addr & 0x00ff) + program[2] = UInt8(addr >> 8) + let expectedResult = UInt16((addr + 1) & 0xffff) + + let result = test(program: program, length: 13, initialValue: 0xffff) + XCTAssertEqual(result, expectedResult) + } } } diff --git a/Processors/Z80/Z80.hpp b/Processors/Z80/Z80.hpp index d59898f10..6849613e9 100644 --- a/Processors/Z80/Z80.hpp +++ b/Processors/Z80/Z80.hpp @@ -619,7 +619,7 @@ template class Processor { /* 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_), Read3(memptr_, a_)), + /* 0x3a LD A, (nn) */ StdInstr(Read16Inc(pc_, memptr_), Read3(memptr_, a_), Inc16(memptr_)), /* 0x3b DEC SP */ Instr(4, {MicroOp::Decrement16, &sp_.full}), /* 0x3c INC A; 0x3d DEC A; 0x3e LD A, n */ From eaf313b0f61e7340f59dcad194279dfc1e6b48c0 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 22 Jul 2017 11:20:21 -0400 Subject: [PATCH 04/11] Added a test on LD A, (DE) and LD A, (BC), and adjusted implementation to pass. --- .../Clock SignalTests/Z80MemptrTests.swift | 24 ++++++++++++++++++- Processors/Z80/Z80.hpp | 4 ++-- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/Z80MemptrTests.swift b/OSBindings/Mac/Clock SignalTests/Z80MemptrTests.swift index 2b5e82f78..c1e49c6c2 100644 --- a/OSBindings/Mac/Clock SignalTests/Z80MemptrTests.swift +++ b/OSBindings/Mac/Clock SignalTests/Z80MemptrTests.swift @@ -23,7 +23,7 @@ class Z80MemptrTests: XCTestCase { return machine.value(for: .memPtr) } - // LD A,(addr) + // LD A, (addr) func testLDAnn() { var program: [UInt8] = [ 0x3a, 0x00, 0x00 @@ -38,4 +38,26 @@ class Z80MemptrTests: XCTestCase { } } + // LD A, (rp) + func testLDArp() { + let bcProgram: [UInt8] = [ + 0x0a + ] + let deProgram: [UInt8] = [ + 0x1a + ] + for addr in 0 ..< 65536 { + machine.setValue(UInt16(addr), for: .BC) + machine.setValue(UInt16(addr), for: .DE) + + let expectedResult = UInt16((addr + 1) & 0xffff) + + let bcResult = test(program: bcProgram, length: 7, initialValue: 0xffff) + let deResult = test(program: deProgram, length: 7, initialValue: 0xffff) + + XCTAssertEqual(bcResult, expectedResult) + XCTAssertEqual(deResult, expectedResult) + } + } + } diff --git a/Processors/Z80/Z80.hpp b/Processors/Z80/Z80.hpp index 6849613e9..57173e695 100644 --- a/Processors/Z80/Z80.hpp +++ b/Processors/Z80/Z80.hpp @@ -574,7 +574,7 @@ template class Processor { /* 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}, Read3(memptr_, a_)), + /* 0x0a LD A, (BC) */ StdInstr({MicroOp::Move16, &bc_.full, &memptr_.full}, Read3(memptr_, a_), Inc16(memptr_)), /* 0x0b DEC BC; 0x0c INC C; 0x0d DEC C; 0x0e LD C, n */ DEC_INC_DEC_LD(bc_, bc_.bytes.low), @@ -590,7 +590,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}, Read3(memptr_, a_)), + /* 0x1a LD A, (DE) */ StdInstr({MicroOp::Move16, &de_.full, &memptr_.full}, Read3(memptr_, a_), Inc16(memptr_)), /* 0x1b DEC DE; 0x1c INC E; 0x1d DEC E; 0x1e LD E, n */ DEC_INC_DEC_LD(de_, de_.bytes.low), From 20a6bcc6768a48ba7f1498bbef3168a1328870f0 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 22 Jul 2017 11:39:13 -0400 Subject: [PATCH 05/11] Added tests for the various `LD (nn), rr` instructions and corrected implementation to pass. --- .../Clock SignalTests/Z80MemptrTests.swift | 57 +++++++++++++++++++ Processors/Z80/Z80.hpp | 10 ++-- 2 files changed, 62 insertions(+), 5 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/Z80MemptrTests.swift b/OSBindings/Mac/Clock SignalTests/Z80MemptrTests.swift index c1e49c6c2..f0b8375d4 100644 --- a/OSBindings/Mac/Clock SignalTests/Z80MemptrTests.swift +++ b/OSBindings/Mac/Clock SignalTests/Z80MemptrTests.swift @@ -60,4 +60,61 @@ class Z80MemptrTests: XCTestCase { } } + // LD (addr), rp + func testLDnnrp() { + var hlBaseProgram: [UInt8] = [ + 0x22, 0x00, 0x00 + ] + + var bcEDProgram: [UInt8] = [ + 0xed, 0x43, 0x00, 0x00 + ] + var deEDProgram: [UInt8] = [ + 0xed, 0x53, 0x00, 0x00 + ] + var hlEDProgram: [UInt8] = [ + 0xed, 0x63, 0x00, 0x00 + ] + var spEDProgram: [UInt8] = [ + 0xed, 0x73, 0x00, 0x00 + ] + + var ixProgram: [UInt8] = [ + 0xdd, 0x22, 0x00, 0x00 + ] + var iyProgram: [UInt8] = [ + 0xfd, 0x22, 0x00, 0x00 + ] + + for addr in 0 ..< 65536 { + hlBaseProgram[1] = UInt8(addr & 0x00ff) + hlBaseProgram[2] = UInt8(addr >> 8) + + bcEDProgram[2] = UInt8(addr & 0x00ff) + bcEDProgram[3] = UInt8(addr >> 8) + deEDProgram[2] = UInt8(addr & 0x00ff) + deEDProgram[3] = UInt8(addr >> 8) + hlEDProgram[2] = UInt8(addr & 0x00ff) + hlEDProgram[3] = UInt8(addr >> 8) + spEDProgram[2] = UInt8(addr & 0x00ff) + spEDProgram[3] = UInt8(addr >> 8) + + ixProgram[2] = UInt8(addr & 0x00ff) + ixProgram[3] = UInt8(addr >> 8) + iyProgram[2] = UInt8(addr & 0x00ff) + iyProgram[3] = UInt8(addr >> 8) + + let expectedResult = UInt16((addr + 1) & 0xffff) + + XCTAssertEqual(test(program: hlBaseProgram, length: 16, initialValue: 0xffff), expectedResult) + + XCTAssertEqual(test(program: bcEDProgram, length: 20, initialValue: 0xffff), expectedResult) + XCTAssertEqual(test(program: deEDProgram, length: 20, initialValue: 0xffff), expectedResult) + XCTAssertEqual(test(program: hlEDProgram, length: 20, initialValue: 0xffff), expectedResult) + XCTAssertEqual(test(program: spEDProgram, length: 20, initialValue: 0xffff), expectedResult) + + XCTAssertEqual(test(program: ixProgram, length: 20, initialValue: 0xffff), expectedResult) + XCTAssertEqual(test(program: iyProgram, length: 20, initialValue: 0xffff), expectedResult) + } + } } diff --git a/Processors/Z80/Z80.hpp b/Processors/Z80/Z80.hpp index 57173e695..e50d8df70 100644 --- a/Processors/Z80/Z80.hpp +++ b/Processors/Z80/Z80.hpp @@ -464,7 +464,7 @@ 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 */ StdInstr(Read16Inc(pc_, temp16_), Write16(temp16_, bc_)), + /* 0x42 SBC HL, BC */ SBC16(hl_, bc_), /* 0x43 LD (nn), BC */ StdInstr(Read16Inc(pc_, memptr_), Write16(memptr_, 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), @@ -472,7 +472,7 @@ template class Processor { /* 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 */ StdInstr(Read16Inc(pc_, temp16_), Write16(temp16_, de_)), + /* 0x52 SBC HL, DE */ SBC16(hl_, de_), /* 0x53 LD (nn), DE */ StdInstr(Read16Inc(pc_, memptr_), Write16(memptr_, 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), @@ -480,7 +480,7 @@ template class Processor { /* 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 */ StdInstr(Read16Inc(pc_, temp16_), Write16(temp16_, hl_)), + /* 0x62 SBC HL, HL */ SBC16(hl_, hl_), /* 0x63 LD (nn), HL */ StdInstr(Read16Inc(pc_, memptr_), Write16(memptr_, 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), @@ -488,7 +488,7 @@ template class Processor { /* 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_)), - /* 0x72 SBC HL, SP */ SBC16(hl_, sp_), /* 0x73 LD (nn), SP */ StdInstr(Read16Inc(pc_, temp16_), Write16(temp16_, sp_)), + /* 0x72 SBC HL, SP */ SBC16(hl_, sp_), /* 0x73 LD (nn), SP */ StdInstr(Read16Inc(pc_, memptr_), Write16(memptr_, 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_), @@ -597,7 +597,7 @@ template class Processor { /* 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)), + /* 0x22 LD (nn), HL */ StdInstr(Read16Inc(pc_, memptr_), Write16(memptr_, index)), /* 0x23 INC HL; 0x24 INC H; 0x25 DEC H; 0x26 LD H, n */ INC_INC_DEC_LD(index, index.bytes.high), From 5928a24803e8640b23a5cdee260487aab69604fb Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 22 Jul 2017 11:44:17 -0400 Subject: [PATCH 06/11] Transcribed missing tests as TODOs. --- .../Clock SignalTests/Z80MemptrTests.swift | 149 +++++++++++++++++- 1 file changed, 148 insertions(+), 1 deletion(-) diff --git a/OSBindings/Mac/Clock SignalTests/Z80MemptrTests.swift b/OSBindings/Mac/Clock SignalTests/Z80MemptrTests.swift index f0b8375d4..118e65ceb 100644 --- a/OSBindings/Mac/Clock SignalTests/Z80MemptrTests.swift +++ b/OSBindings/Mac/Clock SignalTests/Z80MemptrTests.swift @@ -38,6 +38,12 @@ class Z80MemptrTests: XCTestCase { } } + /* TODO: + LD (addr),A + MEMPTR_low = (addr + 1) & #FF, MEMPTR_hi = A + Note for *BM1: MEMPTR_low = (addr + 1) & #FF, MEMPTR_hi = 0 + */ + // LD A, (rp) func testLDArp() { let bcProgram: [UInt8] = [ @@ -60,7 +66,18 @@ class Z80MemptrTests: XCTestCase { } } - // LD (addr), rp + /* TODO: + LD (rp),A where rp -- BC or DE + MEMPTR_low = (rp + 1) & #FF, MEMPTR_hi = A + Note for *BM1: MEMPTR_low = (rp + 1) & #FF, MEMPTR_hi = 0 + */ + + /* TODO: + LD (addr), rp + MEMPTR = addr + 1 + */ + + // LD rp, (addr) func testLDnnrp() { var hlBaseProgram: [UInt8] = [ 0x22, 0x00, 0x00 @@ -117,4 +134,134 @@ class Z80MemptrTests: XCTestCase { XCTAssertEqual(test(program: iyProgram, length: 20, initialValue: 0xffff), expectedResult) } } + + /* TODO: + EX (SP),rp + MEMPTR = rp value after the operation + */ + + /* TODO: + ADD/ADC/SBC rp1,rp2 + MEMPTR = rp1_before_operation + 1 + */ + + /* TODO: + RLD/RRD + MEMPTR = HL + 1 + */ + + /* TODO: + JR/DJNZ/RET/RETI/RST (jumping to addr) + MEMPTR = addr + */ + + /* TODO: + JP(except JP rp)/CALL addr (even in case of conditional call/jp, independantly on condition satisfied or not) + MEMPTR = addr + */ + + /* TODO: + IN A,(port) + MEMPTR = (A_before_operation << 8) + port + 1 + */ + + /* TODO: + IN A,(C) + MEMPTR = BC + 1 + */ + + /* TODO: + OUT (port),A + MEMPTR_low = (port + 1) & #FF, MEMPTR_hi = A + Note for *BM1: MEMPTR_low = (port + 1) & #FF, MEMPTR_hi = 0 + */ + + /* TODO: + OUT (C),A + MEMPTR = BC + 1 + */ + + /* TODO: + LDIR/LDDR + when BC == 1: MEMPTR is not changed + when BC <> 1: MEMPTR = PC + 1, where PC = instruction address + */ + + /* TODO: + CPI + MEMPTR = MEMPTR + 1 + */ + + /* TODO: + CPD + MEMPTR = MEMPTR - 1 + */ + + /* TODO: + CPIR + when BC=1 or A=(HL): exactly as CPI + In other cases MEMPTR = PC + 1 on each step, where PC = instruction address. + Note* since at the last execution BC=1 or A=(HL), resulting MEMPTR = PC + 1 + 1 + (if there were not interrupts during the execution) + */ + + /* TODO: + CPDR + when BC=1 or A=(HL): exactly as CPD + In other cases MEMPTR = PC + 1 on each step, where PC = instruction address. + Note* since at the last execution BC=1 or A=(HL), resulting MEMPTR = PC + 1 - 1 + (if there were not interrupts during the execution) + */ + + /* TODO: + INI + MEMPTR = BC_before_decrementing_B + 1 + */ + + /* TODO: + IND + MEMPTR = BC_before_decrementing_B - 1 + */ + + /* TODO: + INIR + exactly as INI on each execution. + I.e. resulting MEMPTR = ((1 << 8) + C) + 1 + */ + + /* TODO: + INDR + exactly as IND on each execution. + I.e. resulting MEMPTR = ((1 << 8) + C) - 1 + */ + + /* TODO: + OUTI + MEMPTR = BC_after_decrementing_B + 1 + */ + + /* TODO: + OUTD + MEMPTR = BC_after_decrementing_B - 1 + */ + + /* TODO: + OTIR + exactly as OUTI on each execution. I.e. resulting MEMPTR = C + 1 + */ + + /* TODO: + OTDR + exactly as OUTD on each execution. I.e. resulting MEMPTR = C - 1 + */ + + /* TODO: + Any instruction with (INDEX+d): + MEMPTR = INDEX+d + */ + + /* TODO: + Interrupt call to addr: + As usual CALL. I.e. MEMPTR = addr + */ } From 6437c431472f0a8855da724da5977b84c10c1c94 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 22 Jul 2017 12:38:18 -0400 Subject: [PATCH 07/11] Added CPI and CPD tests: at last two that pass without requiring implementation changes! --- .../Clock SignalTests/Z80MemptrTests.swift | 36 ++++++++++++++----- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/Z80MemptrTests.swift b/OSBindings/Mac/Clock SignalTests/Z80MemptrTests.swift index 118e65ceb..53c577c13 100644 --- a/OSBindings/Mac/Clock SignalTests/Z80MemptrTests.swift +++ b/OSBindings/Mac/Clock SignalTests/Z80MemptrTests.swift @@ -187,15 +187,35 @@ class Z80MemptrTests: XCTestCase { when BC <> 1: MEMPTR = PC + 1, where PC = instruction address */ - /* TODO: - CPI - MEMPTR = MEMPTR + 1 - */ + func testCPI() { + // CPI: MEMPTR = MEMPTR + 1 + let program: [UInt8] = [ + 0xed, 0xa1 + ] + machine.setData(Data(bytes: program), atAddress: 0x0000) + machine.setValue(0, for: .memPtr) - /* TODO: - CPD - MEMPTR = MEMPTR - 1 - */ + for c in 1 ..< 65536 { + machine.setValue(0x0000, for: .programCounter) + machine.runForNumber(ofCycles: 16) + XCTAssertEqual(UInt16(c), machine.value(for: .memPtr)) + } + } + + func testCPD() { + // CPD: MEMPTR = MEMPTR - 1 + let program: [UInt8] = [ + 0xed, 0xa9 + ] + machine.setData(Data(bytes: program), atAddress: 0x0000) + machine.setValue(0, for: .memPtr) + + for c in 1 ..< 65536 { + machine.setValue(0x0000, for: .programCounter) + machine.runForNumber(ofCycles: 16) + XCTAssertEqual(UInt16(65536 - c), machine.value(for: .memPtr)) + } + } /* TODO: CPIR From 4ea835e50b6219300803021134b32909a7dd47c9 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 22 Jul 2017 17:17:32 -0400 Subject: [PATCH 08/11] Added test for EX (SP), rp, which passes. --- .../Clock SignalTests/Z80MemptrTests.swift | 41 ++++++++++++++++--- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/Z80MemptrTests.swift b/OSBindings/Mac/Clock SignalTests/Z80MemptrTests.swift index 53c577c13..445f816ac 100644 --- a/OSBindings/Mac/Clock SignalTests/Z80MemptrTests.swift +++ b/OSBindings/Mac/Clock SignalTests/Z80MemptrTests.swift @@ -25,6 +25,7 @@ class Z80MemptrTests: XCTestCase { // LD A, (addr) func testLDAnn() { + // MEMPTR = addr+1 var program: [UInt8] = [ 0x3a, 0x00, 0x00 ] @@ -46,6 +47,7 @@ class Z80MemptrTests: XCTestCase { // LD A, (rp) func testLDArp() { + // MEMPTR = rp+1 let bcProgram: [UInt8] = [ 0x0a ] @@ -79,6 +81,7 @@ class Z80MemptrTests: XCTestCase { // LD rp, (addr) func testLDnnrp() { + // MEMPTR = addr+1 var hlBaseProgram: [UInt8] = [ 0x22, 0x00, 0x00 ] @@ -135,10 +138,34 @@ class Z80MemptrTests: XCTestCase { } } - /* TODO: - EX (SP),rp - MEMPTR = rp value after the operation - */ + // EX (SP), rp + func testEXSPrp() { + // MEMPTR = rp at end + var hlProgram: [UInt8] = [ + 0xe3, 0x00, 0x00, 0x00 + ] + var ixProgram: [UInt8] = [ + 0xdd, 0xe3, 0x00, 0x00 + ] + var iyProgram: [UInt8] = [ + 0xfd, 0xe3, 0x00, 0x00 + ] + + machine.setValue(2, for: .stackPointer) + + for addr in 0 ..< 65536 { + hlProgram[2] = UInt8(addr & 0x00ff) + hlProgram[3] = UInt8(addr >> 8) + ixProgram[2] = UInt8(addr & 0x00ff) + ixProgram[3] = UInt8(addr >> 8) + iyProgram[2] = UInt8(addr & 0x00ff) + iyProgram[3] = UInt8(addr >> 8) + + XCTAssertEqual(test(program: hlProgram, length: 19, initialValue: 0xffff), UInt16(addr)) + XCTAssertEqual(test(program: ixProgram, length: 23, initialValue: 0xffff), UInt16(addr)) + XCTAssertEqual(test(program: iyProgram, length: 23, initialValue: 0xffff), UInt16(addr)) + } + } /* TODO: ADD/ADC/SBC rp1,rp2 @@ -187,8 +214,9 @@ class Z80MemptrTests: XCTestCase { when BC <> 1: MEMPTR = PC + 1, where PC = instruction address */ + // CPI func testCPI() { - // CPI: MEMPTR = MEMPTR + 1 + // MEMPTR = MEMPTR + 1 let program: [UInt8] = [ 0xed, 0xa1 ] @@ -202,8 +230,9 @@ class Z80MemptrTests: XCTestCase { } } + // CPD func testCPD() { - // CPD: MEMPTR = MEMPTR - 1 + // MEMPTR = MEMPTR - 1 let program: [UInt8] = [ 0xed, 0xa9 ] From 728143247db8e3b91883026affd9a504e4dd4b85 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 26 Jul 2017 18:56:35 -0400 Subject: [PATCH 09/11] Added a test for RLD and RRD. Which already passes. --- .../Clock SignalTests/Z80MemptrTests.swift | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/Z80MemptrTests.swift b/OSBindings/Mac/Clock SignalTests/Z80MemptrTests.swift index 445f816ac..75bfde211 100644 --- a/OSBindings/Mac/Clock SignalTests/Z80MemptrTests.swift +++ b/OSBindings/Mac/Clock SignalTests/Z80MemptrTests.swift @@ -172,10 +172,24 @@ class Z80MemptrTests: XCTestCase { MEMPTR = rp1_before_operation + 1 */ - /* TODO: - RLD/RRD - MEMPTR = HL + 1 - */ + // RLD/RRD + func testRLDRRD() { + // MEMPTR = HL + 1 + let rldProgram: [UInt8] = [ + 0xed, 0x6f + ] + let rrdProgram: [UInt8] = [ + 0xed, 0x67 + ] + + for addr in 0 ..< 65536 { + let expectedResult = UInt16((addr + 1) & 0xffff) + machine.setValue(UInt16(addr), for: .HL) + + XCTAssertEqual(test(program: rldProgram, length: 18, initialValue: 0xffff), expectedResult) + XCTAssertEqual(test(program: rrdProgram, length: 18, initialValue: 0xffff), expectedResult) + } + } /* TODO: JR/DJNZ/RET/RETI/RST (jumping to addr) From 9257a3f6d7bd0037c7271e178e4683881c26b5ad Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 26 Jul 2017 19:04:52 -0400 Subject: [PATCH 10/11] Added test for 16-bit arithmetic, and fixed implementation. --- .../Clock SignalTests/Z80MemptrTests.swift | 26 ++++++++++++++++--- Processors/Z80/Z80.hpp | 21 ++++++++------- 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/OSBindings/Mac/Clock SignalTests/Z80MemptrTests.swift b/OSBindings/Mac/Clock SignalTests/Z80MemptrTests.swift index 75bfde211..6b6c108e2 100644 --- a/OSBindings/Mac/Clock SignalTests/Z80MemptrTests.swift +++ b/OSBindings/Mac/Clock SignalTests/Z80MemptrTests.swift @@ -167,10 +167,28 @@ class Z80MemptrTests: XCTestCase { } } - /* TODO: - ADD/ADC/SBC rp1,rp2 - MEMPTR = rp1_before_operation + 1 - */ + // ADD/ADC/SBC dest, src + func testADDADCSBCrr() { + // MEMPTR = dest prior to modification + 1 + let addProgram: [UInt8] = [ + 0x09 + ] + let adcProgram: [UInt8] = [ + 0xed, 0x4a + ] + let sbcProgram: [UInt8] = [ + 0xed, 0x42 + ] + + for addr in 0 ..< 65536 { + let expectedResult = UInt16((addr + 1) & 0xffff) + machine.setValue(UInt16(addr), for: .HL) + + XCTAssertEqual(test(program: addProgram, length: 11, initialValue: 0xffff), expectedResult) + XCTAssertEqual(test(program: adcProgram, length: 15, initialValue: 0xffff), expectedResult) + XCTAssertEqual(test(program: sbcProgram, length: 15, initialValue: 0xffff), expectedResult) + } + } // RLD/RRD func testRLDRRD() { diff --git a/Processors/Z80/Z80.hpp b/Processors/Z80/Z80.hpp index b99b3446c..ab842695e 100644 --- a/Processors/Z80/Z80.hpp +++ b/Processors/Z80/Z80.hpp @@ -1199,9 +1199,9 @@ template class Processor: public ClockReceiver> { #pragma mark - 16-bit arithmetic case MicroOp::ADD16: { - memptr_.full = *(uint16_t *)operation->source; - uint16_t sourceValue = memptr_.full; - uint16_t destinationValue = *(uint16_t *)operation->destination; + memptr_.full = *(uint16_t *)operation->destination; + uint16_t sourceValue = *(uint16_t *)operation->source; + uint16_t destinationValue = memptr_.full; int result = sourceValue + destinationValue; int halfResult = (sourceValue&0xfff) + (destinationValue&0xfff); @@ -1211,12 +1211,13 @@ template class Processor: public ClockReceiver> { subtract_flag_ = 0; *(uint16_t *)operation->destination = (uint16_t)result; + memptr_.full++; } break; case MicroOp::ADC16: { - memptr_.full = *(uint16_t *)operation->source; - uint16_t sourceValue = memptr_.full; - uint16_t destinationValue = *(uint16_t *)operation->destination; + memptr_.full = *(uint16_t *)operation->destination; + uint16_t sourceValue = *(uint16_t *)operation->source; + uint16_t destinationValue = memptr_.full; int result = sourceValue + destinationValue + (carry_result_ & Flag::Carry); int halfResult = (sourceValue&0xfff) + (destinationValue&0xfff) + (carry_result_ & Flag::Carry); @@ -1231,12 +1232,13 @@ template class Processor: public ClockReceiver> { parity_overflow_result_ = (uint8_t)(overflow >> 13); *(uint16_t *)operation->destination = (uint16_t)result; + memptr_.full++; } break; case MicroOp::SBC16: { - memptr_.full = *(uint16_t *)operation->source; - uint16_t sourceValue = memptr_.full; - uint16_t destinationValue = *(uint16_t *)operation->destination; + memptr_.full = *(uint16_t *)operation->destination; + uint16_t sourceValue = *(uint16_t *)operation->source; + uint16_t destinationValue = memptr_.full; int result = destinationValue - sourceValue - (carry_result_ & Flag::Carry); int halfResult = (destinationValue&0xfff) - (sourceValue&0xfff) - (carry_result_ & Flag::Carry); @@ -1254,6 +1256,7 @@ template class Processor: public ClockReceiver> { parity_overflow_result_ = (uint8_t)(overflow >> 13); *(uint16_t *)operation->destination = (uint16_t)result; + memptr_.full++; } break; #pragma mark - Conditionals From 1da24d10fd11700931ba054f5b0ae44a810ba95b Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 27 Jul 2017 08:05:14 -0400 Subject: [PATCH 11/11] Corrected a couple of build errors. --- Components/6522/6522.hpp | 2 ++ Components/6532/6532.hpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/Components/6522/6522.hpp b/Components/6522/6522.hpp index 0a7ea313c..6ce92d8e4 100644 --- a/Components/6522/6522.hpp +++ b/Components/6522/6522.hpp @@ -13,6 +13,8 @@ #include #include +#include "../../ClockReceiver/ClockReceiver.hpp" + namespace MOS { /*! diff --git a/Components/6532/6532.hpp b/Components/6532/6532.hpp index 854f1068c..c30218a81 100644 --- a/Components/6532/6532.hpp +++ b/Components/6532/6532.hpp @@ -12,6 +12,8 @@ #include #include +#include "../../ClockReceiver/ClockReceiver.hpp" + namespace MOS { /*!