From 70e6c3b2f67a08a8a3db7aeff7e19e3cbc01b172 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 7 May 2018 21:57:54 -0400 Subject: [PATCH 01/10] Introduces the `ActivityObserver` protocol for LEDs, drive events, etc. The Electron's caps lock LED is the test case. --- ActivityObserver/ActivityObserver.hpp | 47 +++++++++++++++++++ .../Dynamic/MultiMachine/MultiMachine.cpp | 4 ++ .../Dynamic/MultiMachine/MultiMachine.hpp | 1 + Machines/ActivitySource.hpp | 24 ++++++++++ Machines/DynamicMachine.hpp | 3 ++ Machines/Electron/Electron.cpp | 28 ++++++++--- Machines/Utility/TypedDynamicMachine.hpp | 4 ++ .../Clock Signal.xcodeproj/project.pbxproj | 13 +++++ 8 files changed, 118 insertions(+), 6 deletions(-) create mode 100644 ActivityObserver/ActivityObserver.hpp create mode 100644 Machines/ActivitySource.hpp diff --git a/ActivityObserver/ActivityObserver.hpp b/ActivityObserver/ActivityObserver.hpp new file mode 100644 index 000000000..48115e374 --- /dev/null +++ b/ActivityObserver/ActivityObserver.hpp @@ -0,0 +1,47 @@ +// +// Header.h +// Clock Signal +// +// Created by Thomas Harte on 07/05/2018. +// Copyright © 2018 Thomas Harte. All rights reserved. +// + +#ifndef Header_h +#define Header_h + +#include + +/*! + Provides a purely virtual base class for anybody that wants to receive notifications of + 'activity' — any feedback from an emulated system which a user could perceive other than + through the machine's native audio and video outputs. + + So: status LEDs, drive activity, etc. A receiver may choose to make appropriate noises + and/or to show or unshow status indicators. +*/ +class ActivityObserver { + public: + /// Announces to the receiver that there is an LED of name @c name. + virtual void register_led(const std::string &name) = 0; + + /// Announces to the receiver that there is a drive of name @c name. + virtual void register_drive(const std::string &name) = 0; + + /// Informs the receiver of the new state of the LED with name @c name. + virtual void set_led_status(const std::string &name, bool lit) = 0; + + enum class DriveEvent { + Step, + StepBelowZero, + StepBeyondMaximum + }; + + /// Informs the receiver that the named event just occurred for the drive with name @c name. + virtual void announce_drive_event(const std::string &name, DriveEvent event) = 0; + + /// Informs the receiver of the motor-on status of the drive with name @c name. + virtual void set_drive_motor_status(const std::string &name, bool is_on) = 0; + +}; + +#endif /* Header_h */ diff --git a/Analyser/Dynamic/MultiMachine/MultiMachine.cpp b/Analyser/Dynamic/MultiMachine/MultiMachine.cpp index 9e33047dd..6343bcc1c 100644 --- a/Analyser/Dynamic/MultiMachine/MultiMachine.cpp +++ b/Analyser/Dynamic/MultiMachine/MultiMachine.cpp @@ -22,6 +22,10 @@ MultiMachine::MultiMachine(std::vector> &&machin crt_machine_.set_delegate(this); } +ActivitySource::Machine *MultiMachine::activity_source() { + return nullptr; // TODO +} + ConfigurationTarget::Machine *MultiMachine::configuration_target() { if(has_picked_) { return machines_.front()->configuration_target(); diff --git a/Analyser/Dynamic/MultiMachine/MultiMachine.hpp b/Analyser/Dynamic/MultiMachine/MultiMachine.hpp index de343e9c3..9b4124cca 100644 --- a/Analyser/Dynamic/MultiMachine/MultiMachine.hpp +++ b/Analyser/Dynamic/MultiMachine/MultiMachine.hpp @@ -50,6 +50,7 @@ class MultiMachine: public ::Machine::DynamicMachine, public MultiCRTMachine::De static bool would_collapse(const std::vector> &machines); MultiMachine(std::vector> &&machines); + ActivitySource::Machine *activity_source() override; ConfigurationTarget::Machine *configuration_target() override; CRTMachine::Machine *crt_machine() override; JoystickMachine::Machine *joystick_machine() override; diff --git a/Machines/ActivitySource.hpp b/Machines/ActivitySource.hpp new file mode 100644 index 000000000..2747ebf00 --- /dev/null +++ b/Machines/ActivitySource.hpp @@ -0,0 +1,24 @@ +// +// ActivitySource.h +// Clock Signal +// +// Created by Thomas Harte on 07/05/2018. +// Copyright © 2018 Thomas Harte. All rights reserved. +// + +#ifndef ActivitySource_h +#define ActivitySource_h + +#include "../ActivityObserver/ActivityObserver.hpp" + +namespace ActivitySource { + +class Machine { + public: + virtual void set_activity_observer(ActivityObserver *receiver) = 0; +}; + +} + + +#endif /* ActivitySource_h */ diff --git a/Machines/DynamicMachine.hpp b/Machines/DynamicMachine.hpp index 6d261b6da..2b51c5e60 100644 --- a/Machines/DynamicMachine.hpp +++ b/Machines/DynamicMachine.hpp @@ -10,6 +10,7 @@ #define DynamicMachine_h #include "../Configurable/Configurable.hpp" +#include "ActivitySource.hpp" #include "ConfigurationTarget.hpp" #include "CRTMachine.hpp" #include "JoystickMachine.hpp" @@ -24,6 +25,8 @@ namespace Machine { */ struct DynamicMachine { virtual ~DynamicMachine() {} + + virtual ActivitySource::Machine *activity_source() = 0; virtual ConfigurationTarget::Machine *configuration_target() = 0; virtual CRTMachine::Machine *crt_machine() = 0; virtual JoystickMachine::Machine *joystick_machine() = 0; diff --git a/Machines/Electron/Electron.cpp b/Machines/Electron/Electron.cpp index 36a2ff5fd..9b4c18762 100644 --- a/Machines/Electron/Electron.cpp +++ b/Machines/Electron/Electron.cpp @@ -8,6 +8,7 @@ #include "Electron.hpp" +#include "../ActivitySource.hpp" #include "../ConfigurationTarget.hpp" #include "../CRTMachine.hpp" #include "../KeyboardMachine.hpp" @@ -45,7 +46,8 @@ class ConcreteMachine: public Configurable::Device, public CPU::MOS6502::BusHandler, public Tape::Delegate, - public Utility::TypeRecipient { + public Utility::TypeRecipient, + public ActivitySource::Machine { public: ConcreteMachine() : m6502_(*this), @@ -215,12 +217,15 @@ class ConcreteMachine: tape_.set_is_enabled((*value & 6) != 6); tape_.set_is_in_input_mode((*value & 6) == 0); - tape_.set_is_running(((*value)&0x40) ? true : false); + tape_.set_is_running((*value & 0x40) ? true : false); - // TODO: caps lock LED + caps_led_state_ = !!(*value & 0x80); + if(activity_observer_) + activity_observer_->set_led_status(caps_led, caps_led_state_); } - // deliberate fallthrough + // deliberate fallthrough; fe07 contains the display mode. + case 0xfe02: case 0xfe03: case 0xfe08: case 0xfe09: case 0xfe0a: case 0xfe0b: case 0xfe0c: case 0xfe0d: case 0xfe0e: case 0xfe0f: @@ -322,8 +327,6 @@ class ConcreteMachine: if(!ram_[0x247] && service_call == 14) { tape_.set_delegate(nullptr); - // TODO: handle tape wrap around. - int cycles_left_while_plausibly_in_data = 50; tape_.clear_interrupts(Interrupt::ReceiveDataFull); while(!tape_.get_tape()->is_at_end()) { @@ -477,6 +480,14 @@ class ConcreteMachine: return selection_set; } + void set_activity_observer(ActivityObserver *observer) override { + activity_observer_ = observer; + if(activity_observer_) { + activity_observer_->register_led(caps_led); + activity_observer_->set_led_status(caps_led, caps_led_state_); + } + } + private: // MARK: - Work deferral updates. inline void update_display() { @@ -563,6 +574,11 @@ class ConcreteMachine: Outputs::Speaker::LowpassSpeaker speaker_; bool speaker_is_enabled_ = false; + + // MARK: - Caps Lock status and the activity observer. + const std::string caps_led = "CAPS"; + bool caps_led_state_ = false; + ActivityObserver *activity_observer_ = nullptr; }; } diff --git a/Machines/Utility/TypedDynamicMachine.hpp b/Machines/Utility/TypedDynamicMachine.hpp index d0ecc70c8..07084b035 100644 --- a/Machines/Utility/TypedDynamicMachine.hpp +++ b/Machines/Utility/TypedDynamicMachine.hpp @@ -25,6 +25,10 @@ template class TypedDynamicMachine: public ::Machine::DynamicMachine return *this; } + ActivitySource::Machine *activity_source() override { + return get(); + } + ConfigurationTarget::Machine *configuration_target() override { return get(); } diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index d16ca4732..dabdcccbb 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -697,6 +697,8 @@ 4B055ABE1FAE98000060FFFF /* MachineForTarget.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MachineForTarget.cpp; sourceTree = ""; }; 4B055ABF1FAE98000060FFFF /* MachineForTarget.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = MachineForTarget.hpp; sourceTree = ""; }; 4B055AF01FAE9C080060FFFF /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; + 4B055C1E20A113B00014E5AB /* ActivityObserver.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ActivityObserver.hpp; sourceTree = ""; }; + 4B055C1F20A1166A0014E5AB /* ActivitySource.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ActivitySource.hpp; sourceTree = ""; }; 4B0783591FC11D10001D12BB /* Configurable.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Configurable.cpp; sourceTree = ""; }; 4B08A2741EE35D56008B7065 /* Z80InterruptTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Z80InterruptTests.swift; sourceTree = ""; }; 4B08A2761EE39306008B7065 /* TestMachine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TestMachine.h; sourceTree = ""; }; @@ -1496,6 +1498,15 @@ path = ../SDL; sourceTree = ""; }; + 4B055C1D20A113B00014E5AB /* ActivityObserver */ = { + isa = PBXGroup; + children = ( + 4B055C1E20A113B00014E5AB /* ActivityObserver.hpp */, + ); + name = ActivityObserver; + path = ../../ActivityObserver; + sourceTree = ""; + }; 4B0CCC411C62D0B3001CAC5F /* CRT */ = { isa = PBXGroup; children = ( @@ -2697,6 +2708,7 @@ isa = PBXGroup; children = ( 4BC76E6A1C98F43700E6EF73 /* Accelerate.framework */, + 4B055C1D20A113B00014E5AB /* ActivityObserver */, 4B8944E2201967B4007DE474 /* Analyser */, 4BB73EA01B587A5100552FC2 /* Clock Signal */, 4BB73EB51B587A5100552FC2 /* Clock SignalTests */, @@ -2800,6 +2812,7 @@ isa = PBXGroup; children = ( 4B54C0BB1F8D8E790050900F /* KeyboardMachine.cpp */, + 4B055C1F20A1166A0014E5AB /* ActivitySource.hpp */, 4BA9C3CF1D8164A9002DDB61 /* ConfigurationTarget.hpp */, 4B046DC31CFE651500E9E45E /* CRTMachine.hpp */, 4BBB709C2020109C002FE009 /* DynamicMachine.hpp */, From ef19a03efc17bb8412483a7c9a6f65da01da141d Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 10 May 2018 21:54:10 -0400 Subject: [PATCH 02/10] Drives can now deliver activity events. --- .../Observer.hpp | 14 ++++++---- .../ActivitySource.hpp => Activity/Source.hpp | 8 +++--- .../Dynamic/MultiMachine/MultiMachine.cpp | 2 +- .../Dynamic/MultiMachine/MultiMachine.hpp | 2 +- Machines/DynamicMachine.hpp | 4 +-- Machines/Electron/Electron.cpp | 8 +++--- Machines/Electron/Plus3.cpp | 5 ++++ Machines/Electron/Plus3.hpp | 2 ++ Machines/Utility/TypedDynamicMachine.hpp | 4 +-- .../Clock Signal.xcodeproj/project.pbxproj | 26 +++++++++---------- Storage/Disk/Drive.cpp | 24 +++++++++++++++++ Storage/Disk/Drive.hpp | 10 +++++++ 12 files changed, 77 insertions(+), 32 deletions(-) rename ActivityObserver/ActivityObserver.hpp => Activity/Observer.hpp (90%) rename Machines/ActivitySource.hpp => Activity/Source.hpp (60%) diff --git a/ActivityObserver/ActivityObserver.hpp b/Activity/Observer.hpp similarity index 90% rename from ActivityObserver/ActivityObserver.hpp rename to Activity/Observer.hpp index 48115e374..6cf99095e 100644 --- a/ActivityObserver/ActivityObserver.hpp +++ b/Activity/Observer.hpp @@ -1,16 +1,18 @@ // -// Header.h +// ActivityObserver.h // Clock Signal // // Created by Thomas Harte on 07/05/2018. // Copyright © 2018 Thomas Harte. All rights reserved. // -#ifndef Header_h -#define Header_h +#ifndef ActivityObserver_h +#define ActivityObserver_h #include +namespace Activity { + /*! Provides a purely virtual base class for anybody that wants to receive notifications of 'activity' — any feedback from an emulated system which a user could perceive other than @@ -19,7 +21,7 @@ So: status LEDs, drive activity, etc. A receiver may choose to make appropriate noises and/or to show or unshow status indicators. */ -class ActivityObserver { +class Observer { public: /// Announces to the receiver that there is an LED of name @c name. virtual void register_led(const std::string &name) = 0; @@ -44,4 +46,6 @@ class ActivityObserver { }; -#endif /* Header_h */ +} + +#endif /* ActivityObserver_h */ diff --git a/Machines/ActivitySource.hpp b/Activity/Source.hpp similarity index 60% rename from Machines/ActivitySource.hpp rename to Activity/Source.hpp index 2747ebf00..9db6b7a53 100644 --- a/Machines/ActivitySource.hpp +++ b/Activity/Source.hpp @@ -9,13 +9,13 @@ #ifndef ActivitySource_h #define ActivitySource_h -#include "../ActivityObserver/ActivityObserver.hpp" +#include "Observer.hpp" -namespace ActivitySource { +namespace Activity { -class Machine { +class Source { public: - virtual void set_activity_observer(ActivityObserver *receiver) = 0; + virtual void set_activity_observer(Observer *observer) = 0; }; } diff --git a/Analyser/Dynamic/MultiMachine/MultiMachine.cpp b/Analyser/Dynamic/MultiMachine/MultiMachine.cpp index 6343bcc1c..5f7a92f29 100644 --- a/Analyser/Dynamic/MultiMachine/MultiMachine.cpp +++ b/Analyser/Dynamic/MultiMachine/MultiMachine.cpp @@ -22,7 +22,7 @@ MultiMachine::MultiMachine(std::vector> &&machin crt_machine_.set_delegate(this); } -ActivitySource::Machine *MultiMachine::activity_source() { +Activity::Source *MultiMachine::activity_source() { return nullptr; // TODO } diff --git a/Analyser/Dynamic/MultiMachine/MultiMachine.hpp b/Analyser/Dynamic/MultiMachine/MultiMachine.hpp index 9b4124cca..f1a8ea845 100644 --- a/Analyser/Dynamic/MultiMachine/MultiMachine.hpp +++ b/Analyser/Dynamic/MultiMachine/MultiMachine.hpp @@ -50,7 +50,7 @@ class MultiMachine: public ::Machine::DynamicMachine, public MultiCRTMachine::De static bool would_collapse(const std::vector> &machines); MultiMachine(std::vector> &&machines); - ActivitySource::Machine *activity_source() override; + Activity::Source *activity_source() override; ConfigurationTarget::Machine *configuration_target() override; CRTMachine::Machine *crt_machine() override; JoystickMachine::Machine *joystick_machine() override; diff --git a/Machines/DynamicMachine.hpp b/Machines/DynamicMachine.hpp index 2b51c5e60..a8f2595b5 100644 --- a/Machines/DynamicMachine.hpp +++ b/Machines/DynamicMachine.hpp @@ -10,7 +10,7 @@ #define DynamicMachine_h #include "../Configurable/Configurable.hpp" -#include "ActivitySource.hpp" +#include "../Activity/Source.hpp" #include "ConfigurationTarget.hpp" #include "CRTMachine.hpp" #include "JoystickMachine.hpp" @@ -26,7 +26,7 @@ namespace Machine { struct DynamicMachine { virtual ~DynamicMachine() {} - virtual ActivitySource::Machine *activity_source() = 0; + virtual Activity::Source *activity_source() = 0; virtual ConfigurationTarget::Machine *configuration_target() = 0; virtual CRTMachine::Machine *crt_machine() = 0; virtual JoystickMachine::Machine *joystick_machine() = 0; diff --git a/Machines/Electron/Electron.cpp b/Machines/Electron/Electron.cpp index 9b4c18762..103c2f855 100644 --- a/Machines/Electron/Electron.cpp +++ b/Machines/Electron/Electron.cpp @@ -8,7 +8,7 @@ #include "Electron.hpp" -#include "../ActivitySource.hpp" +#include "../../Activity/Source.hpp" #include "../ConfigurationTarget.hpp" #include "../CRTMachine.hpp" #include "../KeyboardMachine.hpp" @@ -47,7 +47,7 @@ class ConcreteMachine: public CPU::MOS6502::BusHandler, public Tape::Delegate, public Utility::TypeRecipient, - public ActivitySource::Machine { + public Activity::Source { public: ConcreteMachine() : m6502_(*this), @@ -480,7 +480,7 @@ class ConcreteMachine: return selection_set; } - void set_activity_observer(ActivityObserver *observer) override { + void set_activity_observer(Activity::Observer *observer) override { activity_observer_ = observer; if(activity_observer_) { activity_observer_->register_led(caps_led); @@ -578,7 +578,7 @@ class ConcreteMachine: // MARK: - Caps Lock status and the activity observer. const std::string caps_led = "CAPS"; bool caps_led_state_ = false; - ActivityObserver *activity_observer_ = nullptr; + Activity::Observer *activity_observer_ = nullptr; }; } diff --git a/Machines/Electron/Plus3.cpp b/Machines/Electron/Plus3.cpp index 95178291a..1338bd11d 100644 --- a/Machines/Electron/Plus3.cpp +++ b/Machines/Electron/Plus3.cpp @@ -53,3 +53,8 @@ void Plus3::set_motor_on(bool on) { // writing state, so plenty of work to do in general here. get_drive().set_motor_on(on); } + +void Plus3::set_activity_observer(Activity::Observer *observer) { + drives_[0]->set_activity_observer(observer, "Drive 1", true); + drives_[1]->set_activity_observer(observer, "Drive 2", true); +} diff --git a/Machines/Electron/Plus3.hpp b/Machines/Electron/Plus3.hpp index 71b8b1c4b..d5bf1a7c9 100644 --- a/Machines/Electron/Plus3.hpp +++ b/Machines/Electron/Plus3.hpp @@ -10,6 +10,7 @@ #define Plus3_hpp #include "../../Components/1770/1770.hpp" +#include "../../Activity/Observer.hpp" namespace Electron { @@ -19,6 +20,7 @@ class Plus3 : public WD::WD1770 { void set_disk(std::shared_ptr disk, int drive); void set_control_register(uint8_t control); + void set_activity_observer(Activity::Observer *observer); private: void set_control_register(uint8_t control, uint8_t changes); diff --git a/Machines/Utility/TypedDynamicMachine.hpp b/Machines/Utility/TypedDynamicMachine.hpp index 07084b035..db3632733 100644 --- a/Machines/Utility/TypedDynamicMachine.hpp +++ b/Machines/Utility/TypedDynamicMachine.hpp @@ -25,8 +25,8 @@ template class TypedDynamicMachine: public ::Machine::DynamicMachine return *this; } - ActivitySource::Machine *activity_source() override { - return get(); + Activity::Source *activity_source() override { + return get(); } ConfigurationTarget::Machine *configuration_target() override { diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 6a98f57b7..cab4b4feb 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -697,8 +697,6 @@ 4B055ABE1FAE98000060FFFF /* MachineForTarget.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MachineForTarget.cpp; sourceTree = ""; }; 4B055ABF1FAE98000060FFFF /* MachineForTarget.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = MachineForTarget.hpp; sourceTree = ""; }; 4B055AF01FAE9C080060FFFF /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; - 4B055C1E20A113B00014E5AB /* ActivityObserver.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ActivityObserver.hpp; sourceTree = ""; }; - 4B055C1F20A1166A0014E5AB /* ActivitySource.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ActivitySource.hpp; sourceTree = ""; }; 4B0783591FC11D10001D12BB /* Configurable.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Configurable.cpp; sourceTree = ""; }; 4B08A2741EE35D56008B7065 /* Z80InterruptTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Z80InterruptTests.swift; sourceTree = ""; }; 4B08A2761EE39306008B7065 /* TestMachine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TestMachine.h; sourceTree = ""; }; @@ -865,6 +863,8 @@ 4B5073051DDD3B9400C48FBD /* ArrayBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ArrayBuilder.cpp; sourceTree = ""; }; 4B5073061DDD3B9400C48FBD /* ArrayBuilder.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ArrayBuilder.hpp; sourceTree = ""; }; 4B5073091DDFCFDF00C48FBD /* ArrayBuilderTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ArrayBuilderTests.mm; sourceTree = ""; }; + 4B51F70920A521D700AFA2C1 /* Source.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Source.hpp; sourceTree = ""; }; + 4B51F70A20A521D700AFA2C1 /* Observer.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Observer.hpp; sourceTree = ""; }; 4B54C0BB1F8D8E790050900F /* KeyboardMachine.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = KeyboardMachine.cpp; sourceTree = ""; }; 4B54C0BD1F8D8F450050900F /* Keyboard.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Keyboard.cpp; path = Oric/Keyboard.cpp; sourceTree = ""; }; 4B54C0BE1F8D8F450050900F /* Keyboard.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Keyboard.hpp; path = Oric/Keyboard.hpp; sourceTree = ""; }; @@ -1498,15 +1498,6 @@ path = ../SDL; sourceTree = ""; }; - 4B055C1D20A113B00014E5AB /* ActivityObserver */ = { - isa = PBXGroup; - children = ( - 4B055C1E20A113B00014E5AB /* ActivityObserver.hpp */, - ); - name = ActivityObserver; - path = ../../ActivityObserver; - sourceTree = ""; - }; 4B0CCC411C62D0B3001CAC5F /* CRT */ = { isa = PBXGroup; children = ( @@ -1972,6 +1963,16 @@ path = 1540; sourceTree = ""; }; + 4B51F70820A521D700AFA2C1 /* Activity */ = { + isa = PBXGroup; + children = ( + 4B51F70920A521D700AFA2C1 /* Source.hpp */, + 4B51F70A20A521D700AFA2C1 /* Observer.hpp */, + ); + name = Activity; + path = ../../Activity; + sourceTree = ""; + }; 4B55CE551C3B7D360093A61B /* Documents */ = { isa = PBXGroup; children = ( @@ -2708,7 +2709,7 @@ isa = PBXGroup; children = ( 4BC76E6A1C98F43700E6EF73 /* Accelerate.framework */, - 4B055C1D20A113B00014E5AB /* ActivityObserver */, + 4B51F70820A521D700AFA2C1 /* Activity */, 4B8944E2201967B4007DE474 /* Analyser */, 4BB73EA01B587A5100552FC2 /* Clock Signal */, 4BB73EB51B587A5100552FC2 /* Clock SignalTests */, @@ -2812,7 +2813,6 @@ isa = PBXGroup; children = ( 4B54C0BB1F8D8E790050900F /* KeyboardMachine.cpp */, - 4B055C1F20A1166A0014E5AB /* ActivitySource.hpp */, 4BA9C3CF1D8164A9002DDB61 /* ConfigurationTarget.hpp */, 4B046DC31CFE651500E9E45E /* CRTMachine.hpp */, 4BBB709C2020109C002FE009 /* DynamicMachine.hpp */, diff --git a/Storage/Disk/Drive.cpp b/Storage/Disk/Drive.cpp index d62654171..8f5648b12 100644 --- a/Storage/Disk/Drive.cpp +++ b/Storage/Disk/Drive.cpp @@ -88,6 +88,14 @@ bool Drive::get_is_ready() { void Drive::set_motor_on(bool motor_is_on) { motor_is_on_ = motor_is_on; + + if(observer_) { + observer_->set_drive_motor_status(drive_name_, motor_is_on_); + if(announce_motor_led_) { + observer_->set_led_status(drive_name_, motor_is_on_); + } + } + if(!motor_is_on) { ready_index_count_ = 0; if(disk_) disk_->flush_tracks(); @@ -265,3 +273,19 @@ void Drive::end_writing() { invalidate_track(); } } + +void Drive::set_activity_observer(Activity::Observer *observer, const std::string &name, bool add_motor_led) { + observer_ = observer; + announce_motor_led_ = add_motor_led; + if(observer) { + drive_name_ = name; + + observer->register_drive(drive_name_); + observer->set_drive_motor_status(drive_name_, motor_is_on_); + + if(add_motor_led) { + observer->register_led(drive_name_); + observer->set_led_status(drive_name_, motor_is_on_); + } + } +} diff --git a/Storage/Disk/Drive.hpp b/Storage/Disk/Drive.hpp index be32071e7..e10ab4099 100644 --- a/Storage/Disk/Drive.hpp +++ b/Storage/Disk/Drive.hpp @@ -14,6 +14,7 @@ #include "Track/PCMPatchedTrack.hpp" #include "../TimedEventLoop.hpp" +#include "../../Activity/Observer.hpp" #include "../../ClockReceiver/Sleeper.hpp" #include @@ -122,6 +123,10 @@ class Drive: public Sleeper, public TimedEventLoop { // As per Sleeper. bool is_sleeping(); + /// Adds an activity observer; it'll be notified of disk activity. + /// The caller can specify whether to add an LED based on disk motor. + void set_activity_observer(Activity::Observer *observer, const std::string &name, bool add_motor_led); + private: // Drives contain an entire disk; from that a certain track // will be currently under the head. @@ -189,6 +194,11 @@ class Drive: public Sleeper, public TimedEventLoop { void setup_track(); void invalidate_track(); + + // Activity observer description. + Activity::Observer *observer_ = nullptr; + std::string drive_name_; + bool announce_motor_led_ = false; }; From 9089bf6535de436cd936dd9eb1de7b92ae2c8b07 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 10 May 2018 21:58:14 -0400 Subject: [PATCH 03/10] Adds step events. --- Storage/Disk/Drive.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Storage/Disk/Drive.cpp b/Storage/Disk/Drive.cpp index 8f5648b12..0f0d14812 100644 --- a/Storage/Disk/Drive.cpp +++ b/Storage/Disk/Drive.cpp @@ -50,7 +50,11 @@ bool Drive::get_is_track_zero() { void Drive::step(HeadPosition offset) { HeadPosition old_head_position = head_position_; head_position_ += offset; - if(head_position_ < HeadPosition(0)) head_position_ = HeadPosition(0); + if(observer_) observer_->announce_drive_event(drive_name_, Activity::Observer::DriveEvent::Step); + if(head_position_ < HeadPosition(0)) { + head_position_ = HeadPosition(0); + if(observer_) observer_->announce_drive_event(drive_name_, Activity::Observer::DriveEvent::StepBelowZero); + } // If the head moved, flush the old track. if(head_position_ != old_head_position) { From a43ca0db350452f103064ee7ec440045f949d477 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 10 May 2018 22:17:13 -0400 Subject: [PATCH 04/10] Makes the Apple II an activity source. --- Components/DiskII/DiskII.cpp | 4 ++++ Components/DiskII/DiskII.hpp | 4 ++++ Machines/AppleII/AppleII.cpp | 18 ++++++++++++++---- Machines/AppleII/Card.hpp | 4 ++++ Machines/AppleII/DiskIICard.cpp | 4 ++++ Machines/AppleII/DiskIICard.hpp | 3 +++ 6 files changed, 33 insertions(+), 4 deletions(-) diff --git a/Components/DiskII/DiskII.cpp b/Components/DiskII/DiskII.cpp index da897c36c..373c5ccf6 100644 --- a/Components/DiskII/DiskII.cpp +++ b/Components/DiskII/DiskII.cpp @@ -236,3 +236,7 @@ uint8_t DiskII::trigger_address(int address, uint8_t value) { return 0xff; } +void DiskII::set_activity_observer(Activity::Observer *observer) { + drives_[0].set_activity_observer(observer, "Drive 1", true); + drives_[1].set_activity_observer(observer, "Drive 2", true); +} diff --git a/Components/DiskII/DiskII.hpp b/Components/DiskII/DiskII.hpp index fd37e9353..37e083ef8 100644 --- a/Components/DiskII/DiskII.hpp +++ b/Components/DiskII/DiskII.hpp @@ -15,6 +15,8 @@ #include "../../Storage/Disk/Disk.hpp" #include "../../Storage/Disk/Drive.hpp" +#include "../../Activity/Observer.hpp" + #include #include #include @@ -40,6 +42,8 @@ class DiskII: void set_disk(const std::shared_ptr &disk, int drive); bool is_sleeping() override; + void set_activity_observer(Activity::Observer *observer); + private: enum class Control { P0, P1, P2, P3, diff --git a/Machines/AppleII/AppleII.cpp b/Machines/AppleII/AppleII.cpp index f75655762..85eccd9ec 100644 --- a/Machines/AppleII/AppleII.cpp +++ b/Machines/AppleII/AppleII.cpp @@ -8,6 +8,7 @@ #include "AppleII.hpp" +#include "../../Activity/Source.hpp" #include "../ConfigurationTarget.hpp" #include "../CRTMachine.hpp" #include "../KeyboardMachine.hpp" @@ -24,6 +25,7 @@ #include "../../Analyser/Static/AppleII/Target.hpp" +#include #include namespace { @@ -34,7 +36,8 @@ class ConcreteMachine: public KeyboardMachine::Machine, public CPU::MOS6502::BusHandler, public Inputs::Keyboard, - public AppleII::Machine { + public AppleII::Machine, + public Activity::Source { private: struct VideoBusHandler : public AppleII::Video::BusHandler { public: @@ -62,8 +65,8 @@ class ConcreteMachine: speaker_.run_for(audio_queue_, cycles_since_audio_update_.divide(Cycles(audio_divider))); } void update_cards() { - for(int c = 0; c < 7; ++c) { - if(cards_[c]) cards_[c]->run_for(cycles_since_card_update_, stretched_cycles_since_card_update_); + for(const auto &card : cards_) { + if(card) card->run_for(cycles_since_card_update_, stretched_cycles_since_card_update_); } cycles_since_card_update_ = 0; stretched_cycles_since_card_update_ = 0; @@ -80,7 +83,7 @@ class ConcreteMachine: Cycles cycles_since_audio_update_; ROMMachine::ROMFetcher rom_fetcher_; - std::unique_ptr cards_[7]; + std::array, 7> cards_; Cycles cycles_since_card_update_; int stretched_cycles_since_card_update_ = 0; @@ -372,6 +375,13 @@ class ConcreteMachine: } return true; } + + // MARK: Activity::Source + void set_activity_observer(Activity::Observer *observer) override { + for(const auto &card: cards_) { + if(card) card->set_activity_observer(observer); + } + } }; } diff --git a/Machines/AppleII/Card.hpp b/Machines/AppleII/Card.hpp index d7c00cdb6..de89bb75e 100644 --- a/Machines/AppleII/Card.hpp +++ b/Machines/AppleII/Card.hpp @@ -11,6 +11,7 @@ #include "../../Processors/6502/6502.hpp" #include "../../ClockReceiver/ClockReceiver.hpp" +#include "../../Activity/Observer.hpp" namespace AppleII { @@ -21,6 +22,9 @@ class Card { /*! Performs a bus operation; the card is implicitly selected. */ virtual void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) = 0; + + /*! Supplies a target for observers. */ + virtual void set_activity_observer(Activity::Observer *observer) {} }; } diff --git a/Machines/AppleII/DiskIICard.cpp b/Machines/AppleII/DiskIICard.cpp index b0941b28e..527b23b39 100644 --- a/Machines/AppleII/DiskIICard.cpp +++ b/Machines/AppleII/DiskIICard.cpp @@ -40,3 +40,7 @@ void DiskIICard::run_for(Cycles cycles, int stretches) { void DiskIICard::set_disk(const std::shared_ptr &disk, int drive) { diskii_.set_disk(disk, drive); } + +void DiskIICard::set_activity_observer(Activity::Observer *observer) { + diskii_.set_activity_observer(observer); +} diff --git a/Machines/AppleII/DiskIICard.hpp b/Machines/AppleII/DiskIICard.hpp index 7f03d0ddc..849e37f94 100644 --- a/Machines/AppleII/DiskIICard.hpp +++ b/Machines/AppleII/DiskIICard.hpp @@ -24,8 +24,11 @@ namespace AppleII { class DiskIICard: public Card { public: DiskIICard(const ROMMachine::ROMFetcher &rom_fetcher, bool is_16_sector); + void perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) override; void run_for(Cycles cycles, int stretches) override; + void set_activity_observer(Activity::Observer *observer) override; + void set_disk(const std::shared_ptr &disk, int drive); private: From 0cb5362c6f74816f1b4d97a85ebe792924983d5b Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 11 May 2018 21:44:08 -0400 Subject: [PATCH 05/10] Disambiguates whether Step will occur in addition to below zero/beyond maximum. --- Activity/Observer.hpp | 2 +- Storage/Disk/Drive.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Activity/Observer.hpp b/Activity/Observer.hpp index 6cf99095e..2690dc0a0 100644 --- a/Activity/Observer.hpp +++ b/Activity/Observer.hpp @@ -33,7 +33,7 @@ class Observer { virtual void set_led_status(const std::string &name, bool lit) = 0; enum class DriveEvent { - Step, + StepNormal, StepBelowZero, StepBeyondMaximum }; diff --git a/Storage/Disk/Drive.cpp b/Storage/Disk/Drive.cpp index 0f0d14812..8418aa1ff 100644 --- a/Storage/Disk/Drive.cpp +++ b/Storage/Disk/Drive.cpp @@ -50,10 +50,11 @@ bool Drive::get_is_track_zero() { void Drive::step(HeadPosition offset) { HeadPosition old_head_position = head_position_; head_position_ += offset; - if(observer_) observer_->announce_drive_event(drive_name_, Activity::Observer::DriveEvent::Step); if(head_position_ < HeadPosition(0)) { head_position_ = HeadPosition(0); if(observer_) observer_->announce_drive_event(drive_name_, Activity::Observer::DriveEvent::StepBelowZero); + } else { + if(observer_) observer_->announce_drive_event(drive_name_, Activity::Observer::DriveEvent::StepNormal); } // If the head moved, flush the old track. From 39d779edf089761332d5b689763f8187539b2be6 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 11 May 2018 21:45:46 -0400 Subject: [PATCH 06/10] Makes CPC an activity source. --- Machines/AmstradCPC/AmstradCPC.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/Machines/AmstradCPC/AmstradCPC.cpp b/Machines/AmstradCPC/AmstradCPC.cpp index db1720cb5..fa60a0d4f 100644 --- a/Machines/AmstradCPC/AmstradCPC.cpp +++ b/Machines/AmstradCPC/AmstradCPC.cpp @@ -20,6 +20,7 @@ #include "../Utility/MemoryFuzzer.hpp" #include "../Utility/Typer.hpp" +#include "../../Activity/Source.hpp" #include "../ConfigurationTarget.hpp" #include "../CRTMachine.hpp" #include "../KeyboardMachine.hpp" @@ -607,6 +608,10 @@ class FDC: public Intel::i8272::i8272 { void set_disk(std::shared_ptr disk, int drive) { drive_->set_disk(disk); } + + void set_activity_observer(Activity::Observer *observer) { + drive_->set_activity_observer(observer, "Drive 1", true); + } }; /*! @@ -690,7 +695,8 @@ class ConcreteMachine: public Utility::TypeRecipient, public CPU::Z80::BusHandler, public Sleeper::SleepObserver, - public Machine { + public Machine, + public Activity::Source { public: ConcreteMachine() : z80_(*this), @@ -995,6 +1001,12 @@ class ConcreteMachine: return &keyboard_mapper_; } + // MARK: - Activity Source + void set_activity_observer(Activity::Observer *observer) override { + if(has_fdc_) fdc_.set_activity_observer(observer); + } + + private: inline void write_to_gate_array(uint8_t value) { switch(value >> 6) { From c23f6d8d190a45bd9084fc0e3948c8488c86e00b Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 11 May 2018 21:46:30 -0400 Subject: [PATCH 07/10] Corrects type for array accesses. --- Machines/AppleII/AppleII.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Machines/AppleII/AppleII.cpp b/Machines/AppleII/AppleII.cpp index 85eccd9ec..e312e05b8 100644 --- a/Machines/AppleII/AppleII.cpp +++ b/Machines/AppleII/AppleII.cpp @@ -257,7 +257,7 @@ class ConcreteMachine: Decode the area conventionally used by cards for ROMs: 0xCn00 — 0xCnff: card n. */ - const int card_number = (address - 0xc100) >> 8; + const size_t card_number = (address - 0xc100) >> 8; if(cards_[card_number]) { update_cards(); cards_[card_number]->perform_bus_operation(operation, address & 0xff, value); @@ -267,7 +267,7 @@ class ConcreteMachine: Decode the area conventionally used by cards for registers: C0n0--C0nF: card n - 8. */ - const int card_number = (address - 0xc090) >> 4; + const size_t card_number = (address - 0xc090) >> 4; if(cards_[card_number]) { update_cards(); cards_[card_number]->perform_bus_operation(operation, 0x100 | (address&0xf), value); From bc464e247f53d7f60837dbefc788029673976645 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 11 May 2018 22:24:33 -0400 Subject: [PATCH 08/10] The 1540 and, by extension, the Vic-20 are now activity sources. --- Components/6522/6522.hpp | 3 +++ .../Implementation/6522Implementation.hpp | 4 ++++ .../Commodore/1540/Implementation/C1540.cpp | 19 +++++++++++++++---- .../1540/Implementation/C1540Base.hpp | 19 ++++++++++++------- Machines/Commodore/Vic-20/Vic20.cpp | 9 ++++++++- 5 files changed, 42 insertions(+), 12 deletions(-) diff --git a/Components/6522/6522.hpp b/Components/6522/6522.hpp index 45ef59fc9..d21e2190c 100644 --- a/Components/6522/6522.hpp +++ b/Components/6522/6522.hpp @@ -113,6 +113,9 @@ template class MOS6522: public MOS6522Base { /*! Gets a register value. */ uint8_t get_register(int address); + /*! @returns the bus handler. */ + T &bus_handler(); + private: T &bus_handler_; diff --git a/Components/6522/Implementation/6522Implementation.hpp b/Components/6522/Implementation/6522Implementation.hpp index eac2a0648..5efe8905e 100644 --- a/Components/6522/Implementation/6522Implementation.hpp +++ b/Components/6522/Implementation/6522Implementation.hpp @@ -145,6 +145,10 @@ template uint8_t MOS6522::get_port_input(Port port, uint8_t outp return (input & ~output_mask) | (output & output_mask); } +template T &MOS6522::bus_handler() { + return bus_handler_; +} + // Delegate and communications template void MOS6522::reevaluate_interrupts() { bool new_interrupt_status = get_interrupt_line(); diff --git a/Machines/Commodore/1540/Implementation/C1540.cpp b/Machines/Commodore/1540/Implementation/C1540.cpp index f08deb661..ec0140f71 100644 --- a/Machines/Commodore/1540/Implementation/C1540.cpp +++ b/Machines/Commodore/1540/Implementation/C1540.cpp @@ -108,6 +108,11 @@ void Machine::run_for(const Cycles cycles) { Storage::Disk::Controller::run_for(cycles); } +void MachineBase::set_activity_observer(Activity::Observer *observer) { + drive_VIA_.bus_handler().set_activity_observer(observer); + drive_->set_activity_observer(observer, "Drive", false); +} + // MARK: - 6522 delegate void MachineBase::mos6522_did_change_interrupt_status(void *mos6522) { @@ -209,8 +214,6 @@ void DriveVIA::set_delegate(Delegate *delegate) { } // write protect tab uncovered -DriveVIA::DriveVIA() : port_b_(0xff), port_a_(0xff), delegate_(nullptr) {} - uint8_t DriveVIA::get_port_input(MOS::MOS6522::Port port) { return port ? port_b_ : port_a_; } @@ -255,14 +258,22 @@ void DriveVIA::set_port_output(MOS::MOS6522::Port port, uint8_t value, uint8_t d delegate_->drive_via_did_set_data_density(this, (value >> 5)&3); } - // TODO: something with the drive LED -// printf("LED: %s\n", value&8 ? "On" : "Off"); + // post the LED status + if(observer_) observer_->set_led_status("Drive", !!(value&8)); previous_port_b_output_ = value; } } } +void DriveVIA::set_activity_observer(Activity::Observer *observer) { + observer_ = observer; + if(observer) { + observer->register_led("Drive"); + observer->set_led_status("Drive", !!(previous_port_b_output_&8)); + } +} + // MARK: - SerialPort void SerialPort::set_input(::Commodore::Serial::Line line, ::Commodore::Serial::LineLevel level) { diff --git a/Machines/Commodore/1540/Implementation/C1540Base.hpp b/Machines/Commodore/1540/Implementation/C1540Base.hpp index 3b54788e7..aef0b8686 100644 --- a/Machines/Commodore/1540/Implementation/C1540Base.hpp +++ b/Machines/Commodore/1540/Implementation/C1540Base.hpp @@ -14,6 +14,7 @@ #include "../../SerialBus.hpp" +#include "../../../../Activity/Source.hpp" #include "../../../../Storage/Disk/Disk.hpp" #include "../../../../Storage/Disk/Controller/DiskController.hpp" @@ -83,8 +84,6 @@ class DriveVIA: public MOS::MOS6522::IRQDelegatePortHandler { }; void set_delegate(Delegate *); - DriveVIA(); - uint8_t get_port_input(MOS::MOS6522::Port port); void set_sync_detected(bool); @@ -96,12 +95,15 @@ class DriveVIA: public MOS::MOS6522::IRQDelegatePortHandler { void set_port_output(MOS::MOS6522::Port, uint8_t value, uint8_t direction_mask); + void set_activity_observer(Activity::Observer *observer); + private: - uint8_t port_b_, port_a_; - bool should_set_overflow_; - bool drive_motor_; - uint8_t previous_port_b_output_; - Delegate *delegate_; + uint8_t port_b_ = 0xff, port_a_ = 0xff; + bool should_set_overflow_ = false; + bool drive_motor_ = false; + uint8_t previous_port_b_output_ = 0; + Delegate *delegate_ = nullptr; + Activity::Observer *observer_ = nullptr; }; /*! @@ -135,6 +137,9 @@ class MachineBase: void drive_via_did_step_head(void *driveVIA, int direction); void drive_via_did_set_data_density(void *driveVIA, int density); + /// Attaches the activity observer to this C1540. + void set_activity_observer(Activity::Observer *observer); + protected: CPU::MOS6502::Processor m6502_; std::shared_ptr drive_; diff --git a/Machines/Commodore/Vic-20/Vic20.cpp b/Machines/Commodore/Vic-20/Vic20.cpp index e119014bd..d2066ec9e 100644 --- a/Machines/Commodore/Vic-20/Vic20.cpp +++ b/Machines/Commodore/Vic-20/Vic20.cpp @@ -10,6 +10,7 @@ #include "Keyboard.hpp" +#include "../../../Activity/Source.hpp" #include "../../ConfigurationTarget.hpp" #include "../../CRTMachine.hpp" #include "../../KeyboardMachine.hpp" @@ -303,7 +304,8 @@ class ConcreteMachine: public Utility::TypeRecipient, public Storage::Tape::BinaryTapePlayer::Delegate, public Machine, - public Sleeper::SleepObserver { + public Sleeper::SleepObserver, + public Activity::Source { public: ConcreteMachine() : m6502_(*this), @@ -752,6 +754,11 @@ class ConcreteMachine: set_use_fast_tape(); } + // MARK: - Activity Source + void set_activity_observer(Activity::Observer *observer) override { + if(c1540_) c1540_->set_activity_observer(observer); + } + private: void update_video() { mos6560_->run_for(cycles_since_mos6560_update_.flush()); From 3ba6b6f1ee15cd62b69550774cea4f72c472461f Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 11 May 2018 23:05:36 -0400 Subject: [PATCH 09/10] Makes the Oric an event source. --- Machines/Oric/Microdisc.cpp | 30 +++++++++++++++++++++++++----- Machines/Oric/Microdisc.hpp | 13 ++++++++++--- Machines/Oric/Oric.cpp | 20 +++++++++++++++++--- 3 files changed, 52 insertions(+), 11 deletions(-) diff --git a/Machines/Oric/Microdisc.cpp b/Machines/Oric/Microdisc.cpp index a9701967e..a19966c30 100644 --- a/Machines/Oric/Microdisc.cpp +++ b/Machines/Oric/Microdisc.cpp @@ -22,10 +22,11 @@ Microdisc::Microdisc() : WD1770(P1793) { set_control_register(last_control_, 0xff); } -void Microdisc::set_disk(std::shared_ptr disk, int drive) { +void Microdisc::set_disk(std::shared_ptr disk, size_t drive) { if(!drives_[drive]) { drives_[drive].reset(new Storage::Disk::Drive(8000000, 300, 2)); if(drive == selected_drive_) set_drive(drives_[drive]); + drives_[drive]->set_activity_observer(observer_, "Drive" + std::to_string(drive), false); } drives_[drive]->set_disk(disk); } @@ -48,8 +49,8 @@ void Microdisc::set_control_register(uint8_t control, uint8_t changes) { // b4: side select if(changes & 0x10) { int head = (control & 0x10) ? 1 : 0; - for(int c = 0; c < 4; c++) { - if(drives_[c]) drives_[c]->set_head(head); + for(auto &drive : drives_) { + if(drive) drive->set_head(head); } } @@ -89,10 +90,12 @@ uint8_t Microdisc::get_data_request_register() { } void Microdisc::set_head_load_request(bool head_load) { + head_load_request_ = head_load; + // The drive motors (at present: I believe **all drive motors** regardless of the selected drive) receive // the current head load request state. - for(int c = 0; c < 4; c++) { - if(drives_[c]) drives_[c]->set_motor_on(head_load); + for(auto &drive : drives_) { + if(drive) drive->set_motor_on(head_load); } // A request to load the head results in a delay until the head is confirmed loaded. This delay is handled @@ -103,6 +106,10 @@ void Microdisc::set_head_load_request(bool head_load) { head_load_request_counter_ = head_load_request_counter_target; set_head_loaded(head_load); } + + if(observer_) { + observer_->set_led_status("Microdisc", head_load); + } } void Microdisc::run_for(const Cycles cycles) { @@ -116,3 +123,16 @@ void Microdisc::run_for(const Cycles cycles) { bool Microdisc::get_drive_is_ready() { return true; } + +void Microdisc::set_activity_observer(Activity::Observer *observer) { + observer_ = observer; + if(observer) { + observer->register_led("Microdisc"); + observer_->set_led_status("Microdisc", head_load_request_); + } + size_t c = 0; + for(auto &drive : drives_) { + if(drive) drive->set_activity_observer(observer, "Drive" + std::to_string(c), false); + ++c; + } +} diff --git a/Machines/Oric/Microdisc.hpp b/Machines/Oric/Microdisc.hpp index 1ea325dc7..f8e847ff3 100644 --- a/Machines/Oric/Microdisc.hpp +++ b/Machines/Oric/Microdisc.hpp @@ -10,6 +10,9 @@ #define Microdisc_hpp #include "../../Components/1770/1770.hpp" +#include "../../Activity/Observer.hpp" + +#include namespace Oric { @@ -17,7 +20,7 @@ class Microdisc: public WD::WD1770 { public: Microdisc(); - void set_disk(std::shared_ptr disk, int drive); + void set_disk(std::shared_ptr disk, size_t drive); void set_control_register(uint8_t control); uint8_t get_interrupt_request_register(); uint8_t get_data_request_register(); @@ -39,17 +42,21 @@ class Microdisc: public WD::WD1770 { inline void set_delegate(Delegate *delegate) { delegate_ = delegate; WD1770::set_delegate(delegate); } inline int get_paging_flags() { return paging_flags_; } + void set_activity_observer(Activity::Observer *observer); + private: void set_control_register(uint8_t control, uint8_t changes); void set_head_load_request(bool head_load); bool get_drive_is_ready(); - std::shared_ptr drives_[4]; - int selected_drive_; + std::array, 4> drives_; + size_t selected_drive_; bool irq_enable_ = false; int paging_flags_ = BASICDisable; int head_load_request_counter_ = -1; + bool head_load_request_ = false; Delegate *delegate_ = nullptr; uint8_t last_control_ = 0; + Activity::Observer *observer_ = nullptr; }; } diff --git a/Machines/Oric/Oric.cpp b/Machines/Oric/Oric.cpp index c5a8492a9..b1d8b0a2e 100644 --- a/Machines/Oric/Oric.cpp +++ b/Machines/Oric/Oric.cpp @@ -12,6 +12,7 @@ #include "Microdisc.hpp" #include "Video.hpp" +#include "../../Activity/Source.hpp" #include "../ConfigurationTarget.hpp" #include "../CRTMachine.hpp" #include "../KeyboardMachine.hpp" @@ -200,6 +201,7 @@ template class Co public Utility::TypeRecipient, public Storage::Tape::BinaryTapePlayer::Delegate, public Microdisc::Delegate, + public Activity::Source, public Machine { public: @@ -329,10 +331,10 @@ template class Co switch(disk_interface) { case Analyser::Static::Oric::Target::DiskInterface::Microdisc: { inserted = true; - int drive_index = 0; + size_t drive_index = 0; for(auto &disk : media.disks) { if(drive_index < 4) microdisc_.set_disk(disk, drive_index); - drive_index++; + ++drive_index; } } break; case Analyser::Static::Oric::Target::DiskInterface::Pravetz: { @@ -340,7 +342,7 @@ template class Co int drive_index = 0; for(auto &disk : media.disks) { if(drive_index < 2) diskii_.set_disk(disk, drive_index); - drive_index++; + ++drive_index; } } break; @@ -551,6 +553,18 @@ template class Co return selection_set; } + void set_activity_observer(Activity::Observer *observer) override { + switch(disk_interface) { + default: break; + case Analyser::Static::Oric::Target::DiskInterface::Microdisc: + microdisc_.set_activity_observer(observer); + break; + case Analyser::Static::Oric::Target::DiskInterface::Pravetz: + diskii_.set_activity_observer(observer); + break; + } + } + private: const uint16_t basic_invisible_ram_top_ = 0xffff; const uint16_t basic_visible_ram_top_ = 0xbfff; From d0fd4dd4db9f54ea2ae2902f241f37515b96f28d Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 12 May 2018 17:32:53 -0400 Subject: [PATCH 10/10] The MSX is now an activity source. Completing the set. --- Machines/MSX/DiskROM.cpp | 16 +++++++++++++++- Machines/MSX/DiskROM.hpp | 12 +++++++++--- Machines/MSX/MSX.cpp | 29 ++++++++++++++++++++++------- Machines/Oric/Microdisc.cpp | 8 ++++++-- Machines/Oric/Microdisc.hpp | 2 ++ 5 files changed, 54 insertions(+), 13 deletions(-) diff --git a/Machines/MSX/DiskROM.cpp b/Machines/MSX/DiskROM.cpp index 2025098b9..af414657a 100644 --- a/Machines/MSX/DiskROM.cpp +++ b/Machines/MSX/DiskROM.cpp @@ -56,11 +56,12 @@ void DiskROM::run_for(HalfCycles half_cycles) { controller_cycles_ %= 715909; } -void DiskROM::set_disk(std::shared_ptr disk, int drive) { +void DiskROM::set_disk(std::shared_ptr disk, size_t drive) { if(!drives_[drive]) { drives_[drive].reset(new Storage::Disk::Drive(8000000, 300, 2)); drives_[drive]->set_head(selected_head_); if(drive == selected_drive_) set_drive(drives_[drive]); + drives_[drive]->set_activity_observer(observer_, drive_name(drive), true); } drives_[drive]->set_disk(disk); } @@ -69,3 +70,16 @@ void DiskROM::set_head_load_request(bool head_load) { // Magic! set_head_loaded(head_load); } + +void DiskROM::set_activity_observer(Activity::Observer *observer) { + size_t c = 0; + observer_ = observer; + for(auto &drive: drives_) { + if(drive) drive->set_activity_observer(observer, drive_name(c), true); + ++c; + } +} + +std::string DiskROM::drive_name(size_t index) { + return "Drive " + std::to_string(index); +} diff --git a/Machines/MSX/DiskROM.hpp b/Machines/MSX/DiskROM.hpp index bab03d380..b3f56d92d 100644 --- a/Machines/MSX/DiskROM.hpp +++ b/Machines/MSX/DiskROM.hpp @@ -11,9 +11,12 @@ #include "ROMSlotHandler.hpp" +#include "../../Activity/Source.hpp" #include "../../Components/1770/1770.hpp" +#include #include +#include #include namespace MSX { @@ -26,17 +29,20 @@ class DiskROM: public ROMSlotHandler, public WD::WD1770 { uint8_t read(uint16_t address) override; void run_for(HalfCycles half_cycles) override; - void set_disk(std::shared_ptr disk, int drive); + void set_disk(std::shared_ptr disk, size_t drive); + void set_activity_observer(Activity::Observer *observer); private: const std::vector &rom_; long int controller_cycles_ = 0; - int selected_drive_ = 0; + size_t selected_drive_ = 0; int selected_head_ = 0; - std::shared_ptr drives_[4]; + std::array, 2> drives_; void set_head_load_request(bool head_load) override; + std::string drive_name(size_t index); + Activity::Observer *observer_ = nullptr; }; } diff --git a/Machines/MSX/MSX.cpp b/Machines/MSX/MSX.cpp index 6b57f714c..daed39b44 100644 --- a/Machines/MSX/MSX.cpp +++ b/Machines/MSX/MSX.cpp @@ -30,6 +30,7 @@ #include "../../Storage/Tape/Parsers/MSX.hpp" #include "../../Storage/Tape/Tape.hpp" +#include "../../Activity/Source.hpp" #include "../CRTMachine.hpp" #include "../ConfigurationTarget.hpp" #include "../KeyboardMachine.hpp" @@ -87,7 +88,8 @@ class ConcreteMachine: public KeyboardMachine::Machine, public Configurable::Device, public MemoryMap, - public Sleeper::SleepObserver { + public Sleeper::SleepObserver, + public Activity::Source { public: ConcreteMachine(): z80_(*this), @@ -200,12 +202,14 @@ class ConcreteMachine: } if(!media.disks.empty()) { - DiskROM *disk_rom = dynamic_cast(memory_slots_[2].handler.get()); - int drive = 0; - for(auto &disk : media.disks) { - disk_rom->set_disk(disk, drive); - drive++; - if(drive == 2) break; + DiskROM *disk_rom = get_disk_rom(); + if(disk_rom) { + size_t drive = 0; + for(auto &disk : media.disks) { + disk_rom->set_disk(disk, drive); + drive++; + if(drive == 2) break; + } } } @@ -556,7 +560,18 @@ class ConcreteMachine: set_use_fast_tape(); } + // MARK: - Activity::Source + void set_activity_observer(Activity::Observer *observer) override { + DiskROM *disk_rom = get_disk_rom(); + if(disk_rom) { + disk_rom->set_activity_observer(observer); + } + } + private: + DiskROM *get_disk_rom() { + return dynamic_cast(memory_slots_[2].handler.get()); + } void update_audio() { speaker_.run_for(audio_queue_, time_since_ay_update_.divide_cycles(Cycles(2))); } diff --git a/Machines/Oric/Microdisc.cpp b/Machines/Oric/Microdisc.cpp index a19966c30..e040ce5fb 100644 --- a/Machines/Oric/Microdisc.cpp +++ b/Machines/Oric/Microdisc.cpp @@ -26,7 +26,7 @@ void Microdisc::set_disk(std::shared_ptr disk, size_t drive if(!drives_[drive]) { drives_[drive].reset(new Storage::Disk::Drive(8000000, 300, 2)); if(drive == selected_drive_) set_drive(drives_[drive]); - drives_[drive]->set_activity_observer(observer_, "Drive" + std::to_string(drive), false); + drives_[drive]->set_activity_observer(observer_, drive_name(drive), false); } drives_[drive]->set_disk(disk); } @@ -132,7 +132,11 @@ void Microdisc::set_activity_observer(Activity::Observer *observer) { } size_t c = 0; for(auto &drive : drives_) { - if(drive) drive->set_activity_observer(observer, "Drive" + std::to_string(c), false); + if(drive) drive->set_activity_observer(observer, drive_name(c), false); ++c; } } + +std::string Microdisc::drive_name(size_t index) { + return "Drive " + std::to_string(index); +} diff --git a/Machines/Oric/Microdisc.hpp b/Machines/Oric/Microdisc.hpp index f8e847ff3..862e7ec8e 100644 --- a/Machines/Oric/Microdisc.hpp +++ b/Machines/Oric/Microdisc.hpp @@ -57,6 +57,8 @@ class Microdisc: public WD::WD1770 { Delegate *delegate_ = nullptr; uint8_t last_control_ = 0; Activity::Observer *observer_ = nullptr; + + std::string drive_name(size_t index); }; }