diff --git a/Components/8272/i8272.cpp b/Components/8272/i8272.cpp index 926879f1d..664bf54b8 100644 --- a/Components/8272/i8272.cpp +++ b/Components/8272/i8272.cpp @@ -88,6 +88,10 @@ i8272::i8272(BusHandler &bus_handler, Cycles clock_rate, int clock_rate_multipli posit_event((int)Event8272::CommandByte); } +bool i8272::is_sleeping() { + return is_sleeping_ && Storage::Disk::MFMController::is_sleeping(); +} + void i8272::run_for(Cycles cycles) { Storage::Disk::MFMController::run_for(cycles); @@ -154,6 +158,7 @@ void i8272::run_for(Cycles cycles) { } is_sleeping_ = !delay_time_ && !drives_seeking_ && !head_timers_running_; + if(is_sleeping_) update_sleep_observer(); } void i8272::set_register(int address, uint8_t value) { @@ -198,7 +203,7 @@ void i8272::set_disk(std::shared_ptr disk, int drive) { #define MS_TO_CYCLES(x) x * 8000 #define WAIT_FOR_EVENT(mask) resume_point_ = __LINE__; interesting_event_mask_ = (int)mask; return; case __LINE__: -#define WAIT_FOR_TIME(ms) resume_point_ = __LINE__; interesting_event_mask_ = (int)Event8272::Timer; delay_time_ = MS_TO_CYCLES(ms); is_sleeping_ = false; case __LINE__: if(delay_time_) return; +#define WAIT_FOR_TIME(ms) resume_point_ = __LINE__; interesting_event_mask_ = (int)Event8272::Timer; delay_time_ = MS_TO_CYCLES(ms); is_sleeping_ = false; update_sleep_observer(); case __LINE__: if(delay_time_) return; #define PASTE(x, y) x##y #define CONCAT(x, y) PASTE(x, y) @@ -257,6 +262,7 @@ void i8272::set_disk(std::shared_ptr disk, int drive) { if(drives_[active_drive_].head_unload_delay[active_head_] == 0) { \ head_timers_running_++; \ is_sleeping_ = false; \ + update_sleep_observer(); \ } \ drives_[active_drive_].head_unload_delay[active_head_] = MS_TO_CYCLES(head_unload_time_);\ } @@ -711,6 +717,7 @@ void i8272::posit_event(int event_type) { if(drives_[drive].phase != Drive::Seeking) { drives_seeking_++; is_sleeping_ = false; + update_sleep_observer(); } // Set currently seeking, with a step to occur right now (yes, it sounds like jamming these diff --git a/Components/8272/i8272.hpp b/Components/8272/i8272.hpp index 9c216aa7c..6c31a9517 100644 --- a/Components/8272/i8272.hpp +++ b/Components/8272/i8272.hpp @@ -41,6 +41,8 @@ class i8272: public Storage::Disk::MFMController { void set_disk(std::shared_ptr disk, int drive); + bool is_sleeping(); + private: // The bus handler, for interrupt and DMA-driven usage. BusHandler &bus_handler_; diff --git a/Machines/AmstradCPC/AmstradCPC.cpp b/Machines/AmstradCPC/AmstradCPC.cpp index 3fdded550..593393946 100644 --- a/Machines/AmstradCPC/AmstradCPC.cpp +++ b/Machines/AmstradCPC/AmstradCPC.cpp @@ -76,7 +76,12 @@ class InterruptTimer { /// @returns @c true if an interrupt is currently requested; @c false otherwise. inline bool get_request() { - return interrupt_request_; + return last_interrupt_request_ = interrupt_request_; + } + + /// Asks whether the interrupt status has changed. + inline bool request_has_changed() { + return last_interrupt_request_ != interrupt_request_; } /// Resets the timer. @@ -88,6 +93,7 @@ class InterruptTimer { private: int reset_counter_; bool interrupt_request_; + bool last_interrupt_request_; int timer_; }; @@ -659,6 +665,7 @@ class i8255PortHandler : public Intel::i8255::PortHandler { class ConcreteMachine: public Utility::TypeRecipient, public CPU::Z80::BusHandler, + public Sleeper::SleepObserver, public Machine { public: ConcreteMachine() : @@ -674,6 +681,10 @@ class ConcreteMachine: // ensure memory starts in a random state Memory::Fuzz(ram_, sizeof(ram_)); + + // register this class as the sleep observer for the FDC + fdc_.set_sleep_observer(this); + fdc_is_sleeping_ = fdc_.is_sleeping(); } /// The entry point for performing a partial Z80 machine cycle. @@ -689,7 +700,7 @@ class ConcreteMachine: crtc_counter_ += cycle.length; Cycles crtc_cycles = crtc_counter_.divide_cycles(Cycles(4)); if(crtc_cycles > Cycles(0)) crtc_.run_for(crtc_cycles); - z80_.set_interrupt_line(interrupt_timer_.get_request()); + if(interrupt_timer_.request_has_changed()) z80_.set_interrupt_line(interrupt_timer_.get_request()); // TODO (in the player, not here): adapt it to accept an input clock rate and // run_for as HalfCycles @@ -699,7 +710,7 @@ class ConcreteMachine: ay_.run_for(cycle.length); // Clock the FDC, if connected, using a lazy scale by two - if(has_fdc_) fdc_.run_for(Cycles(cycle.length.as_int())); + if(has_fdc_ && !fdc_is_sleeping_) fdc_.run_for(Cycles(cycle.length.as_int())); // Update typing activity if(typer_) typer_->run_for(cycle.length); @@ -902,6 +913,11 @@ class ConcreteMachine: roms_[(int)type] = data; } + void set_component_is_sleeping(void *component, bool is_sleeping) { + // The FDC is the only thing this registers with as a sleep observer. + fdc_is_sleeping_ = is_sleeping; + } + #pragma mark - Keyboard void set_typer_for_string(const char *string) { @@ -995,7 +1011,7 @@ class ConcreteMachine: std::vector roms_[7]; int rom_model_; - bool has_fdc_; + bool has_fdc_, fdc_is_sleeping_; bool has_128k_; bool upper_rom_is_paged_; int upper_rom_;