From f26a200d78425336285143d756b106c66865cb23 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 7 Aug 2019 21:28:02 -0400 Subject: [PATCH 1/2] Switches to a JustInTimeActor to wrap the IWM. Also simplifies potential future usage of the IWM template. --- ClockReceiver/JustInTime.hpp | 4 ++-- Machines/Apple/Macintosh/Macintosh.cpp | 33 ++++++++------------------ 2 files changed, 12 insertions(+), 25 deletions(-) diff --git a/ClockReceiver/JustInTime.hpp b/ClockReceiver/JustInTime.hpp index eff555061..4f7bafe05 100644 --- a/ClockReceiver/JustInTime.hpp +++ b/ClockReceiver/JustInTime.hpp @@ -21,7 +21,7 @@ Machines that accumulate HalfCycle time but supply to a Cycle-counted device may supply a separate @c TargetTimeScale at template declaration. */ -template class JustInTimeActor { +template class JustInTimeActor { public: /// Constructs a new JustInTimeActor using the same construction arguments as the included object. template JustInTimeActor(Args&&... args) : object_(std::forward(args)...) {} @@ -60,7 +60,7 @@ template Any time the amount of accumulated time crosses a threshold provided at construction time, the object will be updated on the AsyncTaskQueue. */ -template class AsyncJustInTimeActor { +template class AsyncJustInTimeActor { public: /// Constructs a new AsyncJustInTimeActor using the same construction arguments as the included object. template AsyncJustInTimeActor(TargetTimeScale threshold, Args&&... args) : diff --git a/Machines/Apple/Macintosh/Macintosh.cpp b/Machines/Apple/Macintosh/Macintosh.cpp index b0ad76256..89b303775 100644 --- a/Machines/Apple/Macintosh/Macintosh.cpp +++ b/Machines/Apple/Macintosh/Macintosh.cpp @@ -115,8 +115,8 @@ template class ConcreteMachin Memory::Fuzz(ram_, sizeof(ram_) / sizeof(*ram_)); // Attach the drives to the IWM. - iwm_.iwm.set_drive(0, &drives_[0]); - iwm_.iwm.set_drive(1, &drives_[1]); + iwm_->set_drive(0, &drives_[0]); + iwm_->set_drive(1, &drives_[1]); // If they are 400kb drives, also attach them to the drive-speed accumulator. if(!drives_[0].is_800k()) drive_speed_accumulator_.add_drive(&drives_[0]); @@ -218,11 +218,10 @@ template class ConcreteMachin const int register_address = word_address >> 8; // The IWM; this is a purely polled device, so can be run on demand. - iwm_.flush(); if(cycle.operation & Microcycle::Read) { - cycle.value->halves.low = iwm_.iwm.read(register_address); + cycle.value->halves.low = iwm_->read(register_address); } else { - iwm_.iwm.write(register_address, cycle.value->halves.low); + iwm_->write(register_address, cycle.value->halves.low); } if(cycle.operation & Microcycle::SelectWord) cycle.value->halves.high = 0xff; @@ -441,7 +440,7 @@ template class ConcreteMachin // MARK: - Activity Source void set_activity_observer(Activity::Observer *observer) override { - iwm_.iwm.set_activity_observer(observer); + iwm_->set_activity_observer(observer); } private: @@ -461,7 +460,7 @@ template class ConcreteMachin /// Advances all non-CPU components by @c duration half cycles. forceinline void advance_time(HalfCycles duration) { time_since_video_update_ += duration; - iwm_.time_since_update += duration; + iwm_ += duration; ram_subcycle_ = (ram_subcycle_ + duration.as_int()) & 15; // The VIA runs at one-tenth of the 68000's clock speed, in sync with the E clock. @@ -537,20 +536,9 @@ template class ConcreteMachin return mouse_; } - struct IWM { - IWM(int clock_rate) : iwm(clock_rate) {} - - HalfCycles time_since_update; - Apple::IWM iwm; - - void flush() { - iwm.run_for(time_since_update.flush()); - } - }; - class VIAPortHandler: public MOS::MOS6522::PortHandler { public: - VIAPortHandler(ConcreteMachine &machine, RealTimeClock &clock, Keyboard &keyboard, Video &video, DeferredAudio &audio, IWM &iwm, Inputs::QuadratureMouse &mouse) : + VIAPortHandler(ConcreteMachine &machine, RealTimeClock &clock, Keyboard &keyboard, Video &video, DeferredAudio &audio, JustInTimeActor &iwm, Inputs::QuadratureMouse &mouse) : machine_(machine), clock_(clock), keyboard_(keyboard), video_(video), audio_(audio), iwm_(iwm), mouse_(mouse) {} using Port = MOS::MOS6522::Port; @@ -572,8 +560,7 @@ template class ConcreteMachin b3: 0 = use alternate sound buffer, 1 = use ordinary sound buffer b2–b0: audio output volume */ - iwm_.flush(); - iwm_.iwm.set_select(!!(value & 0x20)); + iwm_->set_select(!!(value & 0x20)); machine_.set_use_alternate_buffers(!(value & 0x40), !(value&0x08)); machine_.set_rom_is_overlay(!!(value & 0x10)); @@ -658,14 +645,14 @@ template class ConcreteMachin Keyboard &keyboard_; Video &video_; DeferredAudio &audio_; - IWM &iwm_; + JustInTimeActor &iwm_; Inputs::QuadratureMouse &mouse_; }; CPU::MC68000::Processor mc68000_; DriveSpeedAccumulator drive_speed_accumulator_; - IWM iwm_; + JustInTimeActor iwm_; DeferredAudio audio_; Video video_; From bac0461f7f2f7277cb5d1f6a9a59ff368d0a32b6 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 7 Aug 2019 21:39:23 -0400 Subject: [PATCH 2/2] Switches the drive-speed accumulator to the delegate pattern. This allows the Macintosh to ensure that the IWM is kept up just-in-time with drive speed changes. --- .../Apple/Macintosh/DriveSpeedAccumulator.cpp | 11 ++--------- .../Apple/Macintosh/DriveSpeedAccumulator.hpp | 16 ++++++++-------- Machines/Apple/Macintosh/Macintosh.cpp | 14 +++++++++++--- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/Machines/Apple/Macintosh/DriveSpeedAccumulator.cpp b/Machines/Apple/Macintosh/DriveSpeedAccumulator.cpp index f51f0f5a7..b4277def4 100644 --- a/Machines/Apple/Macintosh/DriveSpeedAccumulator.cpp +++ b/Machines/Apple/Macintosh/DriveSpeedAccumulator.cpp @@ -11,7 +11,7 @@ using namespace Apple::Macintosh; void DriveSpeedAccumulator::post_sample(uint8_t sample) { - if(!number_of_drives_) return; + if(!delegate_) return; // An Euler-esque approximation is used here: just collect all // the samples until there is a certain small quantity of them, @@ -50,14 +50,7 @@ void DriveSpeedAccumulator::post_sample(uint8_t sample) { const float normalised_sum = float(sum) / float(samples_.size()); const float rotation_speed = (normalised_sum * 27.08f) - 259.0f; - for(int c = 0; c < number_of_drives_; ++c) { - drives_[c]->set_rotation_speed(rotation_speed); - } -// printf("RPM: %0.2f (%d sum)\n", rotation_speed, sum); + delegate_->drive_speed_accumulator_set_drive_speed(this, rotation_speed); } } -void DriveSpeedAccumulator::add_drive(Apple::Macintosh::DoubleDensityDrive *drive) { - drives_[number_of_drives_] = drive; - ++number_of_drives_; -} diff --git a/Machines/Apple/Macintosh/DriveSpeedAccumulator.hpp b/Machines/Apple/Macintosh/DriveSpeedAccumulator.hpp index 18a8d41b8..f626217d1 100644 --- a/Machines/Apple/Macintosh/DriveSpeedAccumulator.hpp +++ b/Machines/Apple/Macintosh/DriveSpeedAccumulator.hpp @@ -13,8 +13,6 @@ #include #include -#include "../../../Components/DiskII/MacintoshDoubleDensityDrive.hpp" - namespace Apple { namespace Macintosh { @@ -25,18 +23,20 @@ class DriveSpeedAccumulator { */ void post_sample(uint8_t sample); + struct Delegate { + virtual void drive_speed_accumulator_set_drive_speed(DriveSpeedAccumulator *, float speed) = 0; + }; /*! - Adds a connected drive. Up to two of these - can be supplied. Only Macintosh DoubleDensityDrives - are supported. + Sets the delegate to receive drive speed changes. */ - void add_drive(Apple::Macintosh::DoubleDensityDrive *drive); + void set_delegate(Delegate *delegate) { + delegate_ = delegate;; + } private: std::array samples_; std::size_t sample_pointer_ = 0; - Apple::Macintosh::DoubleDensityDrive *drives_[2] = {nullptr, nullptr}; - int number_of_drives_ = 0; + Delegate *delegate_ = nullptr; }; } diff --git a/Machines/Apple/Macintosh/Macintosh.cpp b/Machines/Apple/Macintosh/Macintosh.cpp index 89b303775..16d8c6bef 100644 --- a/Machines/Apple/Macintosh/Macintosh.cpp +++ b/Machines/Apple/Macintosh/Macintosh.cpp @@ -57,7 +57,8 @@ template class ConcreteMachin public CPU::MC68000::BusHandler, public KeyboardMachine::MappedMachine, public Zilog::SCC::z8530::Delegate, - public Activity::Source { + public Activity::Source, + public DriveSpeedAccumulator::Delegate { public: using Target = Analyser::Static::Macintosh::Target; @@ -119,8 +120,9 @@ template class ConcreteMachin iwm_->set_drive(1, &drives_[1]); // If they are 400kb drives, also attach them to the drive-speed accumulator. - if(!drives_[0].is_800k()) drive_speed_accumulator_.add_drive(&drives_[0]); - if(!drives_[1].is_800k()) drive_speed_accumulator_.add_drive(&drives_[1]); + if(!drives_[0].is_800k() || !drives_[1].is_800k()) { + drive_speed_accumulator_.set_delegate(this); + } // Make sure interrupt changes from the SCC are observed. scc_.set_delegate(this); @@ -444,6 +446,12 @@ template class ConcreteMachin } private: + void drive_speed_accumulator_set_drive_speed(DriveSpeedAccumulator *, float speed) override { + iwm_.flush(); + drives_[0].set_rotation_speed(speed); + drives_[1].set_rotation_speed(speed); + } + forceinline void adjust_phase() { ++phase_; }