From 3e9212aaff6305a3d3df5dd6e1e28fd81aff92bb Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 3 Jun 2017 17:41:45 -0400 Subject: [PATCH] Plumbed through to allow interrupt tests, wrote an NMI test, corrected the error revealed. --- .../Clock Signal.xcodeproj/project.pbxproj | 4 ++ .../Bridges/TestMachineZ80.h | 3 ++ .../Bridges/TestMachineZ80.mm | 10 +++++ .../Clock SignalTests/Z80InterruptTests.swift | 45 +++++++++++++++++++ Processors/Z80/Z80.hpp | 6 +++ Processors/Z80/Z80AllRAM.cpp | 8 ++++ Processors/Z80/Z80AllRAM.hpp | 2 + 7 files changed, 78 insertions(+) create mode 100644 OSBindings/Mac/Clock SignalTests/Z80InterruptTests.swift diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 30a5574bb..8d2395e20 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ 4B049CDD1DA3C82F00322067 /* BCDTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B049CDC1DA3C82F00322067 /* BCDTest.swift */; }; + 4B08A2751EE35D56008B7065 /* Z80InterruptTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B08A2741EE35D56008B7065 /* Z80InterruptTests.swift */; }; 4B0BE4281D3481E700D5256B /* DigitalPhaseLockedLoop.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0BE4261D3481E700D5256B /* DigitalPhaseLockedLoop.cpp */; }; 4B0CCC451C62D0B3001CAC5F /* CRT.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0CCC421C62D0B3001CAC5F /* CRT.cpp */; }; 4B121F951E05E66800BFDA12 /* PCMPatchedTrackTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B121F941E05E66800BFDA12 /* PCMPatchedTrackTests.mm */; }; @@ -442,6 +443,7 @@ /* Begin PBXFileReference section */ 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 = ""; }; 4B0B6E121C9DBD5D00FFB60D /* CRTConstants.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = CRTConstants.hpp; sourceTree = ""; }; 4B0BE4261D3481E700D5256B /* DigitalPhaseLockedLoop.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DigitalPhaseLockedLoop.cpp; sourceTree = ""; }; 4B0BE4271D3481E700D5256B /* DigitalPhaseLockedLoop.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = DigitalPhaseLockedLoop.hpp; sourceTree = ""; }; @@ -1795,6 +1797,7 @@ 4BBF49AE1ED2880200AB3669 /* FUSETests.swift */, 4B1414611B58888700E04248 /* KlausDormannTests.swift */, 4B14145F1B58885000E04248 /* WolfgangLorenzTests.swift */, + 4B08A2741EE35D56008B7065 /* Z80InterruptTests.swift */, 4BFCA12A1ECBE7C400AC40C1 /* ZexallTests.swift */, 4B3BA0C41D318B44005DD7A7 /* Bridges */, 4B1414631B588A1100E04248 /* Test Binaries */, @@ -2599,6 +2602,7 @@ 4BC9E1EE1D23449A003FCEE4 /* 6502InterruptTests.swift in Sources */, 4BEF6AAA1D35CE9E00E73575 /* DigitalPhaseLockedLoopBridge.mm in Sources */, 4B924E991E74D22700B76AF1 /* AtariStaticAnalyserTests.mm in Sources */, + 4B08A2751EE35D56008B7065 /* Z80InterruptTests.swift in Sources */, 4BFCA1241ECBDCB400AC40C1 /* AllRAMProcessor.cpp in Sources */, 4B50730A1DDFCFDF00C48FBD /* ArrayBuilderTests.mm in Sources */, 4BBF49AF1ED2880200AB3669 /* FUSETests.swift in Sources */, diff --git a/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.h b/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.h index df202a892..d170dafd7 100644 --- a/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.h +++ b/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.h @@ -66,4 +66,7 @@ typedef NS_ENUM(NSInteger, CSTestMachineZ80Register) { @property(nonatomic, readonly) BOOL isHalted; +@property(nonatomic) BOOL nmiLine; +@property(nonatomic) BOOL irqLine; + @end diff --git a/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.mm b/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.mm index 73274866e..979aaa868 100644 --- a/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.mm +++ b/OSBindings/Mac/Clock SignalTests/Bridges/TestMachineZ80.mm @@ -173,6 +173,16 @@ static CPU::Z80::Register registerForRegister(CSTestMachineZ80Register reg) { return _processor->get_halt_line() ? YES : NO; } +- (void)setNmiLine:(BOOL)nmiLine { + _nmiLine = nmiLine; + _processor->set_non_maskable_interrupt_line(nmiLine ? true : false); +} + +- (void)setIrqLine:(BOOL)irqLine { + _irqLine = irqLine; + _processor->set_interrupt_line(irqLine ? true : false); +} + #pragma mark - Z80-specific Runner - (void)runToNextInstruction { diff --git a/OSBindings/Mac/Clock SignalTests/Z80InterruptTests.swift b/OSBindings/Mac/Clock SignalTests/Z80InterruptTests.swift new file mode 100644 index 000000000..23715677a --- /dev/null +++ b/OSBindings/Mac/Clock SignalTests/Z80InterruptTests.swift @@ -0,0 +1,45 @@ +// +// Z80InterruptTests.swift +// Clock Signal +// +// Created by Thomas Harte on 03/06/2017. +// Copyright © 2017 Thomas Harte. All rights reserved. +// + +import XCTest + +class Z80InterruptTests: XCTestCase { + + func testNMI() { + let machine = CSTestMachineZ80() + + // start the PC at 0x0100 and install two NOPs for it + machine.setValue(0x0100, for: .programCounter) + machine.setValue(0, for: .IFF1) + machine.setValue(1, for: .IFF2) + machine.setValue(0x00, atAddress: 0x0100) + machine.setValue(0x00, atAddress: 0x0101) + + // put the stack at the top of memory + machine.setValue(0, for: .stackPointer) + + // run for four cycles, and signal an NMI + machine.runForNumber(ofCycles: 4) + machine.nmiLine = true + + // run for four more cycles to get to where the NMI should be recognised + machine.runForNumber(ofCycles: 4) + XCTAssertEqual(machine.value(for: .programCounter), 0x0102) + + // run for eleven more cycles to allow the NMI to begin + machine.runForNumber(ofCycles: 11) + + // confirm that the PC is now at 0x66, that the old is on the stack and + // that IFF1 has migrated to IFF2 + XCTAssertEqual(machine.value(for: .programCounter), 0x66) + XCTAssertEqual(machine.value(atAddress: 0xffff), 0x01) + XCTAssertEqual(machine.value(atAddress: 0xfffe), 0x02) + XCTAssertEqual(machine.value(for: .IFF2), 0) + } + +} diff --git a/Processors/Z80/Z80.hpp b/Processors/Z80/Z80.hpp index a230edebd..c04111a99 100644 --- a/Processors/Z80/Z80.hpp +++ b/Processors/Z80/Z80.hpp @@ -136,6 +136,7 @@ struct MicroOp { BeginIRQ, BeginIRQMode0, RETN, + JumpTo66, HALT, DJNZ, @@ -701,6 +702,7 @@ template class Processor: public MicroOpScheduler { { MicroOp::BeginNMI }, { MicroOp::BusOperation, nullptr, nullptr, {ReadOpcode, 5, &pc_.full, &operation_}}, PUSH(pc_), + { MicroOp::JumpTo66, nullptr, nullptr}, { MicroOp::MoveToNextProgram } }; MicroOp irq_mode0_program[] = { @@ -1476,6 +1478,10 @@ template class Processor: public MicroOpScheduler { request_status_ &= ~Interrupt::IRQ; break; + case MicroOp::JumpTo66: + pc_.full = 0x66; + break; + case MicroOp::RETN: iff1_ = iff2_; if(irq_line_ && iff1_) request_status_ |= Interrupt::IRQ; diff --git a/Processors/Z80/Z80AllRAM.cpp b/Processors/Z80/Z80AllRAM.cpp index 194fe0cb6..5cdd02ac3 100644 --- a/Processors/Z80/Z80AllRAM.cpp +++ b/Processors/Z80/Z80AllRAM.cpp @@ -74,6 +74,14 @@ class ConcreteAllRAMProcessor: public AllRAMProcessor, public Processor::reset_power_on(); } + + void set_interrupt_line(bool value) { + CPU::Z80::Processor::set_interrupt_line(value); + } + + void set_non_maskable_interrupt_line(bool value) { + CPU::Z80::Processor::set_non_maskable_interrupt_line(value); + } }; } diff --git a/Processors/Z80/Z80AllRAM.hpp b/Processors/Z80/Z80AllRAM.hpp index 5307b3bae..e31e41768 100644 --- a/Processors/Z80/Z80AllRAM.hpp +++ b/Processors/Z80/Z80AllRAM.hpp @@ -33,6 +33,8 @@ class AllRAMProcessor: virtual void set_value_of_register(Register r, uint16_t value) = 0; virtual bool get_halt_line() = 0; virtual void reset_power_on() = 0; + virtual void set_interrupt_line(bool value) = 0; + virtual void set_non_maskable_interrupt_line(bool value) = 0; protected: MemoryAccessDelegate *delegate_;