From 16423b8a1fceb4d1145e181fface39b1a0b9fb18 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 26 May 2026 11:19:21 -0400 Subject: [PATCH] Introduce concept of a resettable machine. --- .../Implementation/MultiResettable.cpp | 45 +++++++++++++++++++ .../Implementation/MultiResettable.hpp | 38 ++++++++++++++++ .../Dynamic/MultiMachine/MultiMachine.cpp | 20 ++++++++- .../Dynamic/MultiMachine/MultiMachine.hpp | 5 +++ Machines/DynamicMachine.hpp | 4 ++ Machines/MachineTypes.hpp | 1 + Machines/Resettable.hpp | 21 +++++++++ Machines/Utility/TypedDynamicMachine.hpp | 2 + .../Clock Signal.xcodeproj/project.pbxproj | 16 ++++++- .../Mac/Clock Signal/Base.lproj/MainMenu.xib | 3 ++ .../Documents/MachineDocument.swift | 14 ++++++ .../Mac/Clock Signal/Machine/CSMachine.h | 7 +++ .../Mac/Clock Signal/Machine/CSMachine.mm | 40 +++++++++++++++++ cmake/CLK_SOURCES.cmake | 1 + 14 files changed, 213 insertions(+), 4 deletions(-) create mode 100644 Analyser/Dynamic/MultiMachine/Implementation/MultiResettable.cpp create mode 100644 Analyser/Dynamic/MultiMachine/Implementation/MultiResettable.hpp create mode 100644 Machines/Resettable.hpp diff --git a/Analyser/Dynamic/MultiMachine/Implementation/MultiResettable.cpp b/Analyser/Dynamic/MultiMachine/Implementation/MultiResettable.cpp new file mode 100644 index 000000000..3e498a88b --- /dev/null +++ b/Analyser/Dynamic/MultiMachine/Implementation/MultiResettable.cpp @@ -0,0 +1,45 @@ +// +// MultiResettable.cpp +// Clock Signal +// +// Created by Thomas Harte on 26/05/2026. +// Copyright © 2026 Thomas Harte. All rights reserved. +// + +#include "MultiResettable.hpp" + +using namespace Analyser::Dynamic; + +MultiSoftResettable::MultiSoftResettable(const std::vector> &machines) { + for(auto &machine : machines) { + auto *const resettable = machine->soft_resettable(); + if(resettable) machines_.push_back(resettable); + } +} + +bool MultiSoftResettable::empty() const { + return machines_.empty(); +} + +void MultiSoftResettable::soft_reset() { + for(auto &machine : machines_) { + machine->soft_reset(); + } +} + +MultiHardResettable::MultiHardResettable(const std::vector> &machines) { + for(auto &machine : machines) { + auto *const resettable = machine->hard_resettable(); + if(resettable) machines_.push_back(resettable); + } +} + +bool MultiHardResettable::empty() const { + return machines_.empty(); +} + +void MultiHardResettable::hard_reset() { + for(auto &machine : machines_) { + machine->hard_reset(); + } +} diff --git a/Analyser/Dynamic/MultiMachine/Implementation/MultiResettable.hpp b/Analyser/Dynamic/MultiMachine/Implementation/MultiResettable.hpp new file mode 100644 index 000000000..81bae5cc4 --- /dev/null +++ b/Analyser/Dynamic/MultiMachine/Implementation/MultiResettable.hpp @@ -0,0 +1,38 @@ +// +// MultiResettable.hpp +// Clock Signal +// +// Created by Thomas Harte on 26/05/2026. +// Copyright © 2026 Thomas Harte. All rights reserved. +// + +#pragma once + +#include "Machines/DynamicMachine.hpp" + +namespace Analyser::Dynamic { + +class MultiSoftResettable: public MachineTypes::SoftResettable { +public: + MultiSoftResettable(const std::vector> &); + bool empty() const; + + void soft_reset() final; + +private: + std::vector machines_; +}; + +class MultiHardResettable: public MachineTypes::HardResettable { +public: + MultiHardResettable(const std::vector> &); + bool empty() const; + + void hard_reset() final; + +private: + std::vector machines_; + +}; + +} diff --git a/Analyser/Dynamic/MultiMachine/MultiMachine.cpp b/Analyser/Dynamic/MultiMachine/MultiMachine.cpp index 5b9a04db4..a5f6e7f3e 100644 --- a/Analyser/Dynamic/MultiMachine/MultiMachine.cpp +++ b/Analyser/Dynamic/MultiMachine/MultiMachine.cpp @@ -26,7 +26,9 @@ MultiMachine::MultiMachine(std::vector> &&machin joystick_machine_(machines_), keyboard_machine_(machines_), media_target_(machines_), - media_change_observer_(machines_) + media_change_observer_(machines_), + soft_resettable_(machines_), + hard_resettable_(machines_) { timed_machine_.set_delegate(this); } @@ -53,12 +55,26 @@ Provider(MachineTypes::KeyboardMachine, keyboard_machine, keyboard_machine_) Provider(MachineTypes::MediaTarget, media_target, media_target_) Provider(MachineTypes::MediaChangeObserver, media_change_observer, media_change_observer_) +#undef Provider + MachineTypes::MouseMachine *MultiMachine::mouse_machine() { // TODO. return nullptr; } -#undef Provider +MachineTypes::SoftResettable *MultiMachine::soft_resettable() { + if(has_picked_ || soft_resettable_.empty()) { + return machines_.front()->soft_resettable(); + } + return &soft_resettable_; +} + +MachineTypes::HardResettable *MultiMachine::hard_resettable() { + if(has_picked_ || hard_resettable_.empty()) { + return machines_.front()->hard_resettable(); + } + return &hard_resettable_; +} bool MultiMachine::would_collapse(const std::vector> &machines) { return diff --git a/Analyser/Dynamic/MultiMachine/MultiMachine.hpp b/Analyser/Dynamic/MultiMachine/MultiMachine.hpp index 9c7d4f764..20ac01462 100644 --- a/Analyser/Dynamic/MultiMachine/MultiMachine.hpp +++ b/Analyser/Dynamic/MultiMachine/MultiMachine.hpp @@ -16,6 +16,7 @@ #include "Analyser/Dynamic/MultiMachine/Implementation/MultiJoystickMachine.hpp" #include "Analyser/Dynamic/MultiMachine/Implementation/MultiKeyboardMachine.hpp" #include "Analyser/Dynamic/MultiMachine/Implementation/MultiMediaTarget.hpp" +#include "Analyser/Dynamic/MultiMachine/Implementation/MultiResettable.hpp" #include #include @@ -59,6 +60,8 @@ public: MachineTypes::MouseMachine *mouse_machine() final; MachineTypes::MediaTarget *media_target() final; MachineTypes::MediaChangeObserver *media_change_observer() final; + MachineTypes::SoftResettable *soft_resettable() final; + MachineTypes::HardResettable *hard_resettable() final; void *raw_pointer() final; private: @@ -75,6 +78,8 @@ private: MultiKeyboardMachine keyboard_machine_; MultiMediaTarget media_target_; MultiMediaChangeObserver media_change_observer_; + MultiSoftResettable soft_resettable_; + MultiHardResettable hard_resettable_; void pick_first(); bool has_picked_ = false; diff --git a/Machines/DynamicMachine.hpp b/Machines/DynamicMachine.hpp index 5fbdada9b..44ac698ed 100644 --- a/Machines/DynamicMachine.hpp +++ b/Machines/DynamicMachine.hpp @@ -32,6 +32,8 @@ struct DynamicMachine { virtual MachineTypes::MouseMachine *mouse_machine() = 0; virtual MachineTypes::MediaTarget *media_target() = 0; virtual MachineTypes::MediaChangeObserver *media_change_observer() = 0; + virtual MachineTypes::SoftResettable *soft_resettable() = 0; + virtual MachineTypes::HardResettable *hard_resettable() = 0; /*! Provides a raw pointer to the underlying machine if and only if this dynamic machine really is @@ -67,6 +69,8 @@ SpecialisedGet(MachineTypes::KeyboardMachine, keyboard_machine) SpecialisedGet(MachineTypes::MouseMachine, mouse_machine) SpecialisedGet(MachineTypes::MediaTarget, media_target) SpecialisedGet(MachineTypes::MediaChangeObserver, media_change_observer) +SpecialisedGet(MachineTypes::SoftResettable, soft_resettable) +SpecialisedGet(MachineTypes::HardResettable, hard_resettable) #undef SpecialisedGet diff --git a/Machines/MachineTypes.hpp b/Machines/MachineTypes.hpp index fd7a8300a..32e5ebbab 100644 --- a/Machines/MachineTypes.hpp +++ b/Machines/MachineTypes.hpp @@ -18,6 +18,7 @@ #include "KeyboardMachine.hpp" #include "MediaTarget.hpp" #include "MouseMachine.hpp" +#include "Resettable.hpp" #include "ScanProducer.hpp" #include "StateProducer.hpp" #include "TimedMachine.hpp" diff --git a/Machines/Resettable.hpp b/Machines/Resettable.hpp new file mode 100644 index 000000000..5a209fe89 --- /dev/null +++ b/Machines/Resettable.hpp @@ -0,0 +1,21 @@ +// +// Resettable.hpp +// Clock Signal +// +// Created by Thomas Harte on 26/05/2026. +// Copyright © 2026 Thomas Harte. All rights reserved. +// + +#pragma once + +namespace MachineTypes { + +struct SoftResettable { + virtual void soft_reset() = 0; +}; + +struct HardResettable { + virtual void hard_reset() = 0; +}; + +} diff --git a/Machines/Utility/TypedDynamicMachine.hpp b/Machines/Utility/TypedDynamicMachine.hpp index 348eb0dea..16d7ee2df 100644 --- a/Machines/Utility/TypedDynamicMachine.hpp +++ b/Machines/Utility/TypedDynamicMachine.hpp @@ -41,6 +41,8 @@ public: Provide(MachineTypes::MouseMachine, mouse_machine) Provide(MachineTypes::MediaTarget, media_target) Provide(MachineTypes::MediaChangeObserver, media_change_observer) + Provide(MachineTypes::SoftResettable, soft_resettable) + Provide(MachineTypes::HardResettable, hard_resettable) #undef Provide diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index adfe1446d..aeccffcf9 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -1270,6 +1270,9 @@ 4BF0BC712973318E00CCA2B5 /* RP5C01.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF0BC6F2973318E00CCA2B5 /* RP5C01.cpp */; }; 4BF0BC722973318E00CCA2B5 /* RP5C01.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF0BC6F2973318E00CCA2B5 /* RP5C01.cpp */; }; 4BF2FD962F69C0A400FB4A0C /* 6809tests.json.gz in Resources */ = {isa = PBXBuildFile; fileRef = 4BF2FD942F69C0A400FB4A0C /* 6809tests.json.gz */; }; + 4BF346B12FC5EDB200B3AF59 /* MultiResettable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF346B02FC5EDB200B3AF59 /* MultiResettable.cpp */; }; + 4BF346B22FC5EDB200B3AF59 /* MultiResettable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF346B02FC5EDB200B3AF59 /* MultiResettable.cpp */; }; + 4BF346B32FC5EDB200B3AF59 /* MultiResettable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF346B02FC5EDB200B3AF59 /* MultiResettable.cpp */; }; 4BF437EE209D0F7E008CBD6B /* SegmentParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF437EC209D0F7E008CBD6B /* SegmentParser.cpp */; }; 4BF437EF209D0F7E008CBD6B /* SegmentParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF437EC209D0F7E008CBD6B /* SegmentParser.cpp */; }; 4BF64D672F33D27B001EB900 /* LineOutputShader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BF64D662F33D27B001EB900 /* LineOutputShader.cpp */; }; @@ -2669,6 +2672,9 @@ 4BF0BC732982E54700CCA2B5 /* YamahaCommands.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = YamahaCommands.hpp; sourceTree = ""; }; 4BF0BC742982E6D300CCA2B5 /* AccessEnums.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = AccessEnums.hpp; sourceTree = ""; }; 4BF2FD942F69C0A400FB4A0C /* 6809tests.json.gz */ = {isa = PBXFileReference; lastKnownFileType = archive.gzip; path = 6809tests.json.gz; sourceTree = ""; }; + 4BF346AE2FC5E51C00B3AF59 /* Resettable.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Resettable.hpp; sourceTree = ""; }; + 4BF346AF2FC5EDB200B3AF59 /* MultiResettable.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = MultiResettable.hpp; sourceTree = ""; }; + 4BF346B02FC5EDB200B3AF59 /* MultiResettable.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MultiResettable.cpp; sourceTree = ""; }; 4BF40A5525424C770033EA39 /* LanguageCardSwitches.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = LanguageCardSwitches.hpp; sourceTree = ""; }; 4BF40A5A254263140033EA39 /* AuxiliaryMemorySwitches.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = AuxiliaryMemorySwitches.hpp; sourceTree = ""; }; 4BF437EC209D0F7E008CBD6B /* SegmentParser.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = SegmentParser.cpp; sourceTree = ""; }; @@ -5201,6 +5207,7 @@ 4BA9C3CF1D8164A9002DDB61 /* MediaTarget.hpp */, 4B92294222B04A3D00A1458F /* MouseMachine.hpp */, 4B41EF782FA7AAC80086D909 /* Registry.hpp */, + 4BF346AE2FC5E51C00B3AF59 /* Resettable.hpp */, 4BDCC5F81FB27A5E001220C5 /* ROMMachine.hpp */, 4B046DC31CFE651500E9E45E /* ScanProducer.hpp */, 4B8DD375263481BB00B3C866 /* StateProducer.hpp */, @@ -5259,16 +5266,18 @@ isa = PBXGroup; children = ( 4B1B88BE202E3DB200B67DFF /* MultiConfigurable.cpp */, - 4BBB70A6202014E2002FE009 /* MultiProducer.cpp */, 4B1B88C6202E469300B67DFF /* MultiJoystickMachine.cpp */, 4B1B88B9202E2EC100B67DFF /* MultiKeyboardMachine.cpp */, 4BBB70A3202011C2002FE009 /* MultiMediaTarget.cpp */, + 4BBB70A6202014E2002FE009 /* MultiProducer.cpp */, + 4BF346B02FC5EDB200B3AF59 /* MultiResettable.cpp */, 4B9BE3FE203A0C0600FFAE60 /* MultiSpeaker.cpp */, 4B1B88BF202E3DB200B67DFF /* MultiConfigurable.hpp */, - 4BBB70A7202014E2002FE009 /* MultiProducer.hpp */, 4B1B88C7202E469300B67DFF /* MultiJoystickMachine.hpp */, 4B1B88BA202E2EC100B67DFF /* MultiKeyboardMachine.hpp */, 4BBB70A2202011C2002FE009 /* MultiMediaTarget.hpp */, + 4BBB70A7202014E2002FE009 /* MultiProducer.hpp */, + 4BF346AF2FC5EDB200B3AF59 /* MultiResettable.hpp */, 4B9BE3FF203A0C0600FFAE60 /* MultiSpeaker.hpp */, ); path = Implementation; @@ -6596,6 +6605,7 @@ 4B12C0EE1FCFAD1A005BFD93 /* Keyboard.cpp in Sources */, 4B41EF832FA8FDF80086D909 /* 6847.cpp in Sources */, 4BCD634A22D6756400F567F1 /* MacintoshDoubleDensityDrive.cpp in Sources */, + 4BF346B32FC5EDB200B3AF59 /* MultiResettable.cpp in Sources */, 4B05401F219D1618001BF69C /* ScanTarget.cpp in Sources */, 4BBC7DC92F7182CC00E71794 /* K7.cpp in Sources */, 4B055AE81FAE9B7B0060FFFF /* FIRFilter.cpp in Sources */, @@ -7013,6 +7023,7 @@ 4B0DA67B282DCDF100C12F17 /* Instruction.cpp in Sources */, 4B74CF812312FA9C00500CE8 /* HFV.cpp in Sources */, 4B17B58B20A8A9D9007CCA8F /* StringSerialiser.cpp in Sources */, + 4BF346B22FC5EDB200B3AF59 /* MultiResettable.cpp in Sources */, 4B051CA826781D6500CA44E8 /* StaticAnalyser.cpp in Sources */, 4B69FB3D1C4D908A00B5F0AA /* Tape.cpp in Sources */, 4BB5057E2B962DDF0031C43C /* Tape.cpp in Sources */, @@ -7317,6 +7328,7 @@ 4BBC7DD52F7186D600E71794 /* StaticAnalyser.cpp in Sources */, 4B884C7E2EA8640700073840 /* 6502Mk2Tests.mm in Sources */, 4B7752A728217E060073E2C5 /* Blitter.cpp in Sources */, + 4BF346B12FC5EDB200B3AF59 /* MultiResettable.cpp in Sources */, 4B06AAD22C645F190034D014 /* I2C.cpp in Sources */, 4B778F4F23A5F21C0000D260 /* StaticAnalyser.cpp in Sources */, 4B06AAE72C645FBC0034D014 /* DMAController.cpp in Sources */, diff --git a/OSBindings/Mac/Clock Signal/Base.lproj/MainMenu.xib b/OSBindings/Mac/Clock Signal/Base.lproj/MainMenu.xib index 854257f5c..7483cb60c 100644 --- a/OSBindings/Mac/Clock Signal/Base.lproj/MainMenu.xib +++ b/OSBindings/Mac/Clock Signal/Base.lproj/MainMenu.xib @@ -160,6 +160,9 @@ + + + diff --git a/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift b/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift index cbb53d17b..1f4be7bf2 100644 --- a/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift +++ b/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift @@ -603,6 +603,14 @@ class MachineDocument: machine.inputMode = .joystick } + @IBAction func softReset(_ sender: NSMenuItem?) { + machine.softReset() + } + + @IBAction func hardReset(_ sender: NSMenuItem?) { + machine.hardReset() + } + /// Determines which of the menu items to enable and disable based on the ability of the /// current machine to handle keyboard and joystick input, accept new media and whether /// it has an associted activity window. @@ -639,6 +647,12 @@ class MachineDocument: case #selector(self.insertMedia(_:)): return self.machine != nil && self.machine.canInsertMedia + case #selector(self.softReset(_:)): + return self.machine != nil && self.machine.canSoftReset + + case #selector(self.hardReset(_:)): + return self.machine != nil && self.machine.canHardReset + default: break } } diff --git a/OSBindings/Mac/Clock Signal/Machine/CSMachine.h b/OSBindings/Mac/Clock Signal/Machine/CSMachine.h index fc6c7b86a..6ac3ec01c 100644 --- a/OSBindings/Mac/Clock Signal/Machine/CSMachine.h +++ b/OSBindings/Mac/Clock Signal/Machine/CSMachine.h @@ -114,6 +114,13 @@ typedef NS_ENUM(NSInteger, CSMachineChangeEffect) { @property (nonatomic, assign) CSMachineKeyboardInputMode inputMode; @property (nonatomic, nullable) CSJoystickManager *joystickManager; +// Reset. +- (void)hardReset; +@property (nonatomic, readonly) BOOL canHardReset; + +- (void)softReset; +@property (nonatomic, readonly) BOOL canSoftReset; + // LED list. @property (nonatomic, readonly, nonnull) NSArray *leds; diff --git a/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm b/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm index c0f23d44a..ad09eaa0d 100644 --- a/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm +++ b/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm @@ -879,4 +879,44 @@ struct ActivityObserver: public Activity::Observer { return CSInstallROM(url); } +- (void)hardReset { + const auto updater = _updater.load(std::memory_order_relaxed); + if(!updater) return; + + __weak CSMachine *weakSelf = self; + updater->enqueue([weakSelf, updater] { + CSMachine *const strongSelf = weakSelf; + if(strongSelf) { + auto *const resettable = updater->performer.machine->hard_resettable(); + if(resettable) resettable->hard_reset(); + } + }); +} + +- (BOOL)canHardReset { + const auto updater = _updater.load(std::memory_order_relaxed); + if(!updater) return NO; + return updater->performer.machine->hard_resettable(); +} + +- (void)softReset { + const auto updater = _updater.load(std::memory_order_relaxed); + if(!updater) return; + + __weak CSMachine *weakSelf = self; + updater->enqueue([weakSelf, updater] { + CSMachine *const strongSelf = weakSelf; + if(strongSelf) { + auto *const resettable = updater->performer.machine->soft_resettable(); + if(resettable) resettable->soft_reset(); + } + }); +} + +- (BOOL)canSoftReset { + const auto updater = _updater.load(std::memory_order_relaxed); + if(!updater) return NO; + return updater->performer.machine->soft_resettable(); +} + @end diff --git a/cmake/CLK_SOURCES.cmake b/cmake/CLK_SOURCES.cmake index ea6100121..3ee1a6c07 100644 --- a/cmake/CLK_SOURCES.cmake +++ b/cmake/CLK_SOURCES.cmake @@ -8,6 +8,7 @@ set(CLK_SOURCES Analyser/Dynamic/MultiMachine/Implementation/MultiKeyboardMachine.cpp Analyser/Dynamic/MultiMachine/Implementation/MultiMediaTarget.cpp Analyser/Dynamic/MultiMachine/Implementation/MultiProducer.cpp + Analyser/Dynamic/MultiMachine/Implementation/MultiResettable.cpp Analyser/Dynamic/MultiMachine/Implementation/MultiSpeaker.cpp Analyser/Dynamic/MultiMachine/MultiMachine.cpp Analyser/Static/Acorn/Disk.cpp