diff --git a/Machines/Enterprise/Nick.cpp b/Machines/Enterprise/Nick.cpp index ff87820a3..ddaae8324 100644 --- a/Machines/Enterprise/Nick.cpp +++ b/Machines/Enterprise/Nick.cpp @@ -116,6 +116,9 @@ void Nick::run_for(Cycles duration) { // Special: set mode as soon as it's known. It'll be needed at the end of HSYNC. if(window < 2 && fetch_spot >= 2) { + // Set length of mode line. + lines_remaining_ = line_parameters_[0]; + // Set the new interrupt line output. interrupt_line_ = line_parameters_[1] & 0x80; @@ -150,9 +153,6 @@ void Nick::run_for(Cycles duration) { if(fetch_spot == 8) { should_reload_line_parameters_ = false; - // Set length of mode line. - lines_remaining_ = line_parameters_[0]; - // Determine the line data pointers. line_data_pointer_[0] = uint16_t(line_parameters_[4] | (line_parameters_[5] << 8)); line_data_pointer_[1] = uint16_t(line_parameters_[6] | (line_parameters_[7] << 8)); @@ -338,12 +338,14 @@ Cycles Nick::get_next_sequence_point() { // Changing to e.g. Cycles(1) reveals the relevant discrepancy. // return Cycles(1); + constexpr int load_point = 2*16; + // Any mode line may cause a change in the interrupt output, so as a first blush // just always report the time until the end of the mode line. - if(lines_remaining_ || horizontal_counter_ >= 2) { - return Cycles(2 + (912 - horizontal_counter_) + (0xff - lines_remaining_) * 912); + if(lines_remaining_ || horizontal_counter_ >= load_point) { + return Cycles(load_point + (912 - horizontal_counter_) + (0xff - lines_remaining_) * 912); } else { - return Cycles(2 - horizontal_counter_); + return Cycles(load_point - horizontal_counter_); } } diff --git a/Machines/Enterprise/Nick.hpp b/Machines/Enterprise/Nick.hpp index 8926a0252..2e4dcf1cb 100644 --- a/Machines/Enterprise/Nick.hpp +++ b/Machines/Enterprise/Nick.hpp @@ -50,7 +50,7 @@ class Nick { int horizontal_counter_ = 0; uint16_t line_parameter_pointer_ = 0x0000; uint8_t line_parameters_[16]; - bool should_reload_line_parameters_ = false; + bool should_reload_line_parameters_ = true; uint16_t line_data_pointer_[2]; // Current mode line parameters. diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 1dbe4c55c..127657d64 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -25,6 +25,7 @@ 4B051CAD26783E2000CA44E8 /* Nick.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B051CAA26783E2000CA44E8 /* Nick.cpp */; }; 4B051CB0267C1CA200CA44E8 /* Keyboard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B051CAE267C1CA200CA44E8 /* Keyboard.cpp */; }; 4B051CB1267C1CA200CA44E8 /* Keyboard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B051CAE267C1CA200CA44E8 /* Keyboard.cpp */; }; + 4B051CB3267D3FF800CA44E8 /* EnterpriseNickTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B051CB2267D3FF800CA44E8 /* EnterpriseNickTests.mm */; }; 4B05401E219D1618001BF69C /* ScanTarget.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B05401D219D1618001BF69C /* ScanTarget.cpp */; }; 4B05401F219D1618001BF69C /* ScanTarget.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B05401D219D1618001BF69C /* ScanTarget.cpp */; }; 4B055A7A1FAE78A00060FFFF /* SDL2.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B055A771FAE78210060FFFF /* SDL2.framework */; }; @@ -1045,6 +1046,7 @@ 4B051CAB26783E2000CA44E8 /* Nick.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Nick.hpp; sourceTree = "<group>"; }; 4B051CAE267C1CA200CA44E8 /* Keyboard.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Keyboard.cpp; sourceTree = "<group>"; }; 4B051CAF267C1CA200CA44E8 /* Keyboard.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Keyboard.hpp; sourceTree = "<group>"; }; + 4B051CB2267D3FF800CA44E8 /* EnterpriseNickTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = EnterpriseNickTests.mm; sourceTree = "<group>"; }; 4B05401D219D1618001BF69C /* ScanTarget.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ScanTarget.cpp; sourceTree = "<group>"; }; 4B055A6A1FAE763F0060FFFF /* Clock Signal Kiosk */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "Clock Signal Kiosk"; sourceTree = BUILT_PRODUCTS_DIR; }; 4B055A771FAE78210060FFFF /* SDL2.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL2.framework; path = ../../../../Library/Frameworks/SDL2.framework; sourceTree = SOURCE_ROOT; }; @@ -4031,12 +4033,8 @@ 4BB73EB51B587A5100552FC2 /* Clock SignalTests */ = { isa = PBXGroup; children = ( - 4BC9E1ED1D23449A003FCEE4 /* 6502InterruptTests.swift */, - 4B92EAC91B7C112B00246143 /* 6502TimingTests.swift */, - 4BC751B11D157E61006C31D9 /* 6522Tests.swift */, - 4B1E85801D176468001EF87D /* 6532Tests.swift */, - 4B4F478925367EDC004245B8 /* 65816AddressingTests.swift */, - 4B8DF5132550D62900F3433C /* 65816kromTests.swift */, + 4B85322922778E4200F26553 /* Comparative68000.hpp */, + 4B90467222C6FA31000E2074 /* TestRunner68000.hpp */, 4B90467522C6FD6E000E2074 /* 68000ArithmeticTests.mm */, 4B9D0C4A22C7D70900DE1AD3 /* 68000BCDTests.mm */, 4B90467322C6FADD000E2074 /* 68000BitwiseTests.mm */, @@ -4045,43 +4043,48 @@ 4BC5C3DF22C994CC00795658 /* 68000MoveTests.mm */, 4B9D0C4E22C7E0CF00DE1AD3 /* 68000RollShiftTests.mm */, 4BD388872239E198002D14B5 /* 68000Tests.mm */, - 4BB73EB61B587A5100552FC2 /* AllSuiteATests.swift */, 4B924E981E74D22700B76AF1 /* AtariStaticAnalyserTests.mm */, 4BE34437238389E10058E78F /* AtariSTVideoTests.mm */, - 4B049CDC1DA3C82F00322067 /* BCDTest.swift */, - 4B3BA0C41D318B44005DD7A7 /* Bridges */, - 4B3BA0C21D318AEB005DD7A7 /* C1540Tests.swift */, - 4B85322922778E4200F26553 /* Comparative68000.hpp */, 4BB2A9AE1E13367E001A5C23 /* CRCTests.mm */, - 4BEF6AAB1D35D1C400E73575 /* DPLLTests.swift */, 4BFF1D3C2235C3C100838EA1 /* EmuTOSTests.mm */, - 4BBF49AE1ED2880200AB3669 /* FUSETests.swift */, + 4B051CB2267D3FF800CA44E8 /* EnterpriseNickTests.mm */, 4B8DF4D725465B7500F3433C /* IIgsMemoryMapTests.mm */, - 4BB73EB81B587A5100552FC2 /* Info.plist */, - 4B4F477B253530B7004245B8 /* Jeek816Tests.swift */, - 4B1414611B58888700E04248 /* KlausDormannTests.swift */, 4BEE1EBF22B5E236000A26A6 /* MacGCRTests.mm */, 4BE90FFC22D5864800FB464D /* MacintoshVideoTests.mm */, 4BA91E1C216D85BA00F79557 /* MasterSystemVDPTests.mm */, 4B98A0601FFADCDE00ADF63B /* MSXStaticAnalyserTests.mm */, 4BC0CB272446BC7B00A79DBB /* OPLTests.mm */, - 4BD91D762401C2B8007BDC91 /* PatrikRakTests.swift */, 4B121F9A1E06293F00BFDA12 /* PCMSegmentEventSourceTests.mm */, 4BD4A8CF1E077FD20020D856 /* PCMTrackTests.mm */, 4B3F76B825A1635300178AEC /* PowerPCDecoderTests.mm */, 4BE76CF822641ED300ACD6FA /* QLTests.mm */, 4B8DD3672633B2D400B3C866 /* SpectrumVideoContentionTests.mm */, - 4B1414631B588A1100E04248 /* Test Binaries */, - 4B90467222C6FA31000E2074 /* TestRunner68000.hpp */, 4B2AF8681E513FC20027EE29 /* TIATests.mm */, 4B1D08051E0F7A1100763741 /* TimeTests.mm */, - 4B14145F1B58885000E04248 /* WolfgangLorenzTests.swift */, 4BEE4BD325A26E2B00011BD2 /* x86DecoderTests.mm */, 4BDA8234261E8E000021AA19 /* Z80ContentionTests.mm */, + 4BB73EB81B587A5100552FC2 /* Info.plist */, + 4BC9E1ED1D23449A003FCEE4 /* 6502InterruptTests.swift */, + 4B92EAC91B7C112B00246143 /* 6502TimingTests.swift */, + 4BC751B11D157E61006C31D9 /* 6522Tests.swift */, + 4B1E85801D176468001EF87D /* 6532Tests.swift */, + 4B4F478925367EDC004245B8 /* 65816AddressingTests.swift */, + 4B8DF5132550D62900F3433C /* 65816kromTests.swift */, + 4BB73EB61B587A5100552FC2 /* AllSuiteATests.swift */, + 4B049CDC1DA3C82F00322067 /* BCDTest.swift */, + 4B3BA0C21D318AEB005DD7A7 /* C1540Tests.swift */, + 4BEF6AAB1D35D1C400E73575 /* DPLLTests.swift */, + 4BBF49AE1ED2880200AB3669 /* FUSETests.swift */, + 4B4F477B253530B7004245B8 /* Jeek816Tests.swift */, + 4B1414611B58888700E04248 /* KlausDormannTests.swift */, + 4BD91D762401C2B8007BDC91 /* PatrikRakTests.swift */, + 4B14145F1B58885000E04248 /* WolfgangLorenzTests.swift */, 4B08A2741EE35D56008B7065 /* Z80InterruptTests.swift */, 4BDDBA981EF3451200347E61 /* Z80MachineCycleTests.swift */, 4B01A6871F22F0DB001FD6E3 /* Z80MemptrTests.swift */, 4BFCA12A1ECBE7C400AC40C1 /* ZexallTests.swift */, + 4B3BA0C41D318B44005DD7A7 /* Bridges */, + 4B1414631B588A1100E04248 /* Test Binaries */, ); path = "Clock SignalTests"; sourceTree = "<group>"; @@ -5742,6 +5745,7 @@ 4BFCA12B1ECBE7C400AC40C1 /* ZexallTests.swift in Sources */, 4B778F2223A5EDDD0000D260 /* PulseQueuedTape.cpp in Sources */, 4B778EF123A5D6B50000D260 /* 9918.cpp in Sources */, + 4B051CB3267D3FF800CA44E8 /* EnterpriseNickTests.mm in Sources */, 4B9D0C4D22C7DA1A00DE1AD3 /* 68000ControlFlowTests.mm in Sources */, 4BB2A9AF1E13367E001A5C23 /* CRCTests.mm in Sources */, 4B778F5623A5F2AF0000D260 /* CPM.cpp in Sources */, @@ -6105,7 +6109,7 @@ CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = DV3346VVUN; - ENABLE_HARDENED_RUNTIME = YES; + ENABLE_HARDENED_RUNTIME = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(USER_LIBRARY_DIR)/Frameworks", @@ -6155,7 +6159,7 @@ CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = DV3346VVUN; - ENABLE_HARDENED_RUNTIME = YES; + ENABLE_HARDENED_RUNTIME = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(USER_LIBRARY_DIR)/Frameworks", diff --git a/OSBindings/Mac/Clock SignalTests/EnterpriseNickTests.mm b/OSBindings/Mac/Clock SignalTests/EnterpriseNickTests.mm new file mode 100644 index 000000000..2799b70ae --- /dev/null +++ b/OSBindings/Mac/Clock SignalTests/EnterpriseNickTests.mm @@ -0,0 +1,72 @@ +// +// EnterpriseNickTests.m +// Clock SignalTests +// +// Created by Thomas Harte on 18/06/2021. +// Copyright © 2021 Thomas Harte. All rights reserved. +// + +#import <XCTest/XCTest.h> + +#include "../../../Machines/Enterprise/Nick.hpp" +#include <memory> + +@interface EnterpriseNickTests : XCTestCase +@end + +@implementation EnterpriseNickTests { + std::unique_ptr<Enterprise::Nick> _nick; + uint8_t _ram[64*1024]; + int _totalLines; +} + +- (void)setUp { + [super setUp]; + + // Create a Nick. + _nick = std::make_unique<Enterprise::Nick>(_ram); + + // Add a basic line table of blocks proceeding in length: 1, 2, 3, 4, etc and toggling the interrupt bit. + _totalLines = 0; + int nextLength = 0; + int pointer = 0; + uint8_t interruptFlag = 0x80; + while(nextLength < 256) { + _ram[pointer] = 0x100 - nextLength; + _ram[pointer+1] = interruptFlag; + + pointer += 16; + ++nextLength; + interruptFlag ^= 0x80; + _totalLines += nextLength; + } + + // For now: assume Nick starts at address 0 from creation. +} + +- (void)testInterruptPrediction { + // Run for the number of cycles implied by the number of lines. + int next_sequence_point = _nick->get_next_sequence_point().as<int>(); + bool last_interrupt_line = _nick->get_interrupt_line(); + + for(int c = 0; c < _totalLines*912; c++) { + // Check that interrupt line transitions happen only on declared sequence points. + _nick->run_for(Cycles(1)); + --next_sequence_point; + const bool interrupt_line = _nick->get_interrupt_line(); + + if(interrupt_line != last_interrupt_line) { + XCTAssertEqual(next_sequence_point, 0); + } + last_interrupt_line = interrupt_line; + + if(!next_sequence_point) { + next_sequence_point = _nick->get_next_sequence_point().as<int>(); + } else { + const int expected_next_sequence_point = _nick->get_next_sequence_point().as<int>(); + XCTAssertEqual(next_sequence_point, expected_next_sequence_point); + } + } +} + +@end