From 389ba95e5a603aff88b4ff70add4a7c13056caf8 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 11 Dec 2024 21:30:58 -0500 Subject: [PATCH] Template out the usual repetitive stuff of segment finding. --- Machines/Commodore/Plus4/Video.hpp | 156 ++++++++++-------- Numeric/UpperBound.hpp | 50 ++++++ .../Clock Signal.xcodeproj/project.pbxproj | 4 +- 3 files changed, 137 insertions(+), 73 deletions(-) create mode 100644 Numeric/UpperBound.hpp diff --git a/Machines/Commodore/Plus4/Video.hpp b/Machines/Commodore/Plus4/Video.hpp index 33a681962..944ad8262 100644 --- a/Machines/Commodore/Plus4/Video.hpp +++ b/Machines/Commodore/Plus4/Video.hpp @@ -8,6 +8,8 @@ #pragma once +#include "../../../Numeric/UpperBound.hpp" + namespace Commodore::Plus4 { struct Video { @@ -76,78 +78,9 @@ public: // see page 34 of plus4_tech.pdf for event times. auto ticks_remaining = cycles.as() * 8; - while(ticks_remaining--) { - ++horizontal_counter_; - switch(horizontal_counter_) { - case 3: // 38-column screen start. - break; - - case 288: // External fetch window end, refresh single clock start, increment character position end. - break; - - case 290: // Latch character position to reload. - break; - - case 296: // Character window end, character window single clock end, increment refresh start. - break; - - case 304: // Video shift register end. - break; - - case 307: // 38-column screen stop. - break; - - case 315: // 40-column screen end. - break; - - case 328: // Refresh single clock end. - break; - - case 336: // Increment blink, increment refresh end. - break; - - case 344: // Horizontal blanking start. - break; - - case 358: // Horizontal sync start. - break; - - case 376: // Increment vertical line. - ++vertical_counter_; - break; - - case 384: // Burst start, end of screen — clear vertical line, vertical sub and character reload registers. - break; - - case 390: // Horizontal sync end. - break; - - case 408: // Burst end. - break; - - case 400: // External fetch window start. - break; - - case 416: // Horizontal blanking end. - break; - - case 424: // Increment character position reload. - break; - - case 432: // Character window start, character window single clock start, increment character position start. - break; - - case 440: // Video shift register start. - break; - - case 451: // 40-column screen start. - break; - - case 465: // Wraparound. - horizontal_counter_ = 0; - break; - } - + while(ticks_remaining) { + // Test vertical first; this will catch both any programmed change that has occurred outside + // of the loop and any change to the vertical counter that occurs during the horizontal runs. const auto attribute_fetch_start = []{}; switch(vertical_counter_) { case 261: // End of screen NTSC. [and hence 0: Attribute fetch start]. @@ -203,6 +136,85 @@ public: case 269: // PAL vertical blank end. break; } + + const auto next = Numeric::upper_bound< + 0, 3, 288, 290, 296, 304, 307, 315, 328, 336, 344, 358, 376, 384, 390, 400, 416, 424, 432, 440, 451, 465 + >(horizontal_counter_); + const auto period = std::min(next - horizontal_counter_, ticks_remaining); + +// printf("From %d next is %d\n", horizontal_counter_, next); + + horizontal_counter_ += period; + ticks_remaining -= period; + switch(horizontal_counter_) { + case 3: // 38-column screen start. + break; + + case 288: // External fetch window end, refresh single clock start, increment character position end. + break; + + case 290: // Latch character position to reload. + break; + + case 296: // Character window end, character window single clock end, increment refresh start. + break; + + case 304: // Video shift register end. + break; + + case 307: // 38-column screen stop. + break; + + case 315: // 40-column screen end. + break; + + case 328: // Refresh single clock end. + break; + + case 336: // Increment blink, increment refresh end. + break; + + case 344: // Horizontal blanking start. + break; + + case 358: // Horizontal sync start. + break; + + case 376: // Increment vertical line. + ++vertical_counter_; + break; + + case 384: // Burst start, end of screen — clear vertical line, vertical sub and character reload registers. + break; + + case 390: // Horizontal sync end. + break; + + case 400: // External fetch window start. + break; + + case 408: // Burst end. + break; + + case 416: // Horizontal blanking end. + break; + + case 424: // Increment character position reload. + break; + + case 432: // Character window start, character window single clock start, increment character position start. + break; + + case 440: // Video shift register start. + break; + + case 451: // 40-column screen start. + break; + + case 465: // Wraparound. + horizontal_counter_ = 0; + break; + } } } diff --git a/Numeric/UpperBound.hpp b/Numeric/UpperBound.hpp new file mode 100644 index 000000000..f00d08a80 --- /dev/null +++ b/Numeric/UpperBound.hpp @@ -0,0 +1,50 @@ +// +// UpperBound.hpp +// Clock Signal +// +// Created by Thomas Harte on 11/12/2024. +// Copyright © 2024 Thomas Harte. All rights reserved. +// + +#pragma once + +namespace Numeric { + +/// @returns The element that is `index - offset` into the list given by the rest of the +/// variadic arguments or the final element if `offset` is out of bounds. +/// +/// E.g. @c at_index<0, 3, 5, 6, 7, 8, 9>() returns the `3 - 0` = 4th element from the +/// list 5, 6, 7, 8, 9, i.e. 8. +template +int at_index() { + if constexpr (origin == index || sizeof...(Args) == 0) { + return T; + } else { + return at_index(); + } +} + +/// @returns The result of binary searching for the first thing in the range `[left, right)` within +/// the other template arguments that is strictly greater than @c location. +template +int upper_bound_bounded(int location) { + if constexpr (left + 1 == right) { + return at_index<0, left+1, Args...>(); + } + + constexpr auto midpoint = (left + right) >> 1; + if(location >= at_index<0, midpoint, Args...>()) { + return upper_bound_bounded(location); + } else { + return upper_bound_bounded(location); + } +} + +/// @returns The result of binary searching for the first thing in the template arguments +/// is strictly greater than @c location. +template +int upper_bound(int location) { + return upper_bound_bounded<0, sizeof...(Args), Args...>(location); +} + +} diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index f723807c1..c6f89df4b 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -1297,6 +1297,7 @@ 4B018B88211930DE002A3937 /* 65C02_extended_opcodes_test.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; name = 65C02_extended_opcodes_test.bin; path = "Klaus Dormann/65C02_extended_opcodes_test.bin"; sourceTree = ""; }; 4B01A6871F22F0DB001FD6E3 /* Z80MemptrTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Z80MemptrTests.swift; sourceTree = ""; }; 4B03291F2D0923E300C51EB5 /* Video.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Video.hpp; sourceTree = ""; }; + 4B0329202D0A78DC00C51EB5 /* UpperBound.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = UpperBound.hpp; sourceTree = ""; }; 4B0333AD2094081A0050B93D /* AppleDSK.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = AppleDSK.cpp; sourceTree = ""; }; 4B0333AE2094081A0050B93D /* AppleDSK.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = AppleDSK.hpp; sourceTree = ""; }; 4B046DC31CFE651500E9E45E /* ScanProducer.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ScanProducer.hpp; sourceTree = ""; }; @@ -3637,13 +3638,14 @@ children = ( 4B43984129674943006B0BFC /* BitReverse.hpp */, 4BD155312716362A00410C6E /* BitSpread.hpp */, + 4281572E2AA0334300E16AA1 /* Carry.hpp */, 4B7BA03E23D55E7900B98D9E /* CRC.hpp */, 4B7BA03F23D55E7900B98D9E /* LFSR.hpp */, 4B66E1A8297719270057ED0F /* NumericCoder.hpp */, 4BB5B995281B1D3E00522DA9 /* RegisterSizes.hpp */, 4BFEA2F12682A90200EBF94C /* Sizes.hpp */, - 4281572E2AA0334300E16AA1 /* Carry.hpp */, 4BD9713A2BFD7E7100C907AA /* StringSimilarity.hpp */, + 4B0329202D0A78DC00C51EB5 /* UpperBound.hpp */, ); name = Numeric; path = ../../Numeric;