From 2a0208c5545fb268145826da0bb96f8785956626 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 18 Nov 2025 18:26:02 -0500 Subject: [PATCH] Set up more realistic feedback loop. --- .../Commodore/1540/Implementation/C1540.cpp | 48 +++++++++---------- .../1540/Implementation/C1540Base.hpp | 4 ++ Storage/Disk/Controller/DiskController.cpp | 4 ++ Storage/Disk/Controller/DiskController.hpp | 8 +++- Storage/Disk/Drive.cpp | 11 ++++- Storage/Disk/Drive.hpp | 9 +++- 6 files changed, 54 insertions(+), 30 deletions(-) diff --git a/Machines/Commodore/1540/Implementation/C1540.cpp b/Machines/Commodore/1540/Implementation/C1540.cpp index cc75f4721..4661b8dcb 100644 --- a/Machines/Commodore/1540/Implementation/C1540.cpp +++ b/Machines/Commodore/1540/Implementation/C1540.cpp @@ -161,19 +161,23 @@ void MachineBase::process_input_bit(const int value) { } } -void MachineBase::process_write_completed() { +void MachineBase::is_writing_final_bit() { if(set_cpu_overflow_) { - // TODO: REMOVE UGLY HACK HERE. - // - // The issue here is that I want overflow to go high for one shift of the - // underlying register. But Storage::Disk::Controller doesn't current reveal - // that level of detail. Instead I'm raising the overflow interrupt momentarily - // because I know that'll set the proper flag in the processor as a biproduct - // of its current implementation. - // - // Yuck. m6502_.set(true); - m6502_.set(false); + } +} + +void MachineBase::process_write_completed() { + m6502_.set(false); + serialise_shift_output(); +} + +void MachineBase::serialise_shift_output() { + auto &drive = get_drive(); + uint8_t value = port_a_output_; + for(int c = 0; c < 8; c++) { + drive.write_bit(value & 0x80); + value <<= 1; } } @@ -195,25 +199,16 @@ void MachineBase::drive_via_did_set_drive_motor(DriveVIA &, const bool enabled) } void MachineBase::drive_via_did_set_write_mode(DriveVIA &, const bool enabled) { - auto &drive = get_drive(); if(enabled) { - drive.begin_writing(expected_bit_length(), false); + begin_writing(false); + serialise_shift_output(); } else { - drive.end_writing(); + end_writing(); } } -void MachineBase::drive_via_set_to_shifter_output(DriveVIA &, uint8_t value) { - // TODO: this should actually latch only at some point after the processor's reaction - // to overflow being set in process_write_completed. I'm fuzzy on the exact timing, but - // if I take it as true that overflow goes high as the final bit starts to go out then - // presumably the shift register grabs whatever is coming out of the VIA just shortly - // before it needs to shift again. - auto &drive = get_drive(); - for(int c = 0; c < 8; c++) { - drive.write_bit(value & 0x80); - value <<= 1; - } +void MachineBase::drive_via_set_to_shifter_output(DriveVIA &, const uint8_t value) { + port_a_output_ = value; } void MachineBase::drive_via_should_set_cpu_overflow(DriveVIA &, const bool overflow) { @@ -271,7 +266,8 @@ void SerialPortVIA::set_serial_port(Commodore::Serial::Port &port) { } void SerialPortVIA::update_data_line() { - // "ATN (Attention) is an input on pin 3 of P2 and P3 that is sensed at PB7 and CA1 of UC3 after being inverted by UA1" + // "ATN (Attention) is an input on pin 3 of P2 and P3 that + // is sensed at PB7 and CA1 of UC3 after being inverted by UA1" serial_port_->set_output( ::Commodore::Serial::Line::Data, Serial::LineLevel(!data_level_output_ && (attention_level_input_ != attention_acknowledge_level_)) diff --git a/Machines/Commodore/1540/Implementation/C1540Base.hpp b/Machines/Commodore/1540/Implementation/C1540Base.hpp index fa9fb48e3..4d1e797ec 100644 --- a/Machines/Commodore/1540/Implementation/C1540Base.hpp +++ b/Machines/Commodore/1540/Implementation/C1540Base.hpp @@ -178,6 +178,10 @@ protected: void process_input_bit(int value) override; void process_index_hole() override; void process_write_completed() override; + void is_writing_final_bit() override; + + uint8_t port_a_output_ = 0xff; + void serialise_shift_output(); }; } diff --git a/Storage/Disk/Controller/DiskController.cpp b/Storage/Disk/Controller/DiskController.cpp index f781c73c7..3ca1f625c 100644 --- a/Storage/Disk/Controller/DiskController.cpp +++ b/Storage/Disk/Controller/DiskController.cpp @@ -71,6 +71,10 @@ void Controller::process_write_completed() { // Provided for subclasses to override. } +void Controller::is_writing_final_bit() { + // Provided for subclasses to override. +} + // MARK: - PLL control and delegate void Controller::set_expected_bit_length(const Time bit_length) { diff --git a/Storage/Disk/Controller/DiskController.hpp b/Storage/Disk/Controller/DiskController.hpp index 7ac6f73fd..8cbb76321 100644 --- a/Storage/Disk/Controller/DiskController.hpp +++ b/Storage/Disk/Controller/DiskController.hpp @@ -86,10 +86,16 @@ protected: /*! Should be implemented by subclasses if they implement writing; communicates that - all bits supplied to write_bit have now been written. + all bits supplied to `write_bit` have now been written. */ virtual void process_write_completed() override; + /*! + Can be implemented by subclasses that perform writing; indicates that the final + bit previously provided to the drive has started its output. + */ + virtual void is_writing_final_bit() override; + /*! Puts the controller and the drive returned by get_drive() into write mode, supplying to the drive the current bit length. diff --git a/Storage/Disk/Drive.cpp b/Storage/Disk/Drive.cpp index 10384fcca..cec023622 100644 --- a/Storage/Disk/Drive.cpp +++ b/Storage/Disk/Drive.cpp @@ -237,12 +237,21 @@ void Drive::run_for(const Cycles cycles) { if(cycles_until_bits_written_ > zero) { Storage::Time cycles_to_run_for_time(static_cast(cycles_to_run_for)); if(cycles_until_bits_written_ <= cycles_to_run_for_time) { + cycles_until_bits_written_.set_zero(); if(event_delegate_) { event_delegate_->process_write_completed(); } - cycles_until_bits_written_.set_zero(); } else { + const auto previous_cycles = cycles_until_bits_written_; cycles_until_bits_written_ -= cycles_to_run_for_time; + + if( + previous_cycles > cycles_per_bit_ && + cycles_until_bits_written_ <= cycles_per_bit_ && + event_delegate_ + ) { + event_delegate_->is_writing_final_bit(); + } } } } diff --git a/Storage/Disk/Drive.hpp b/Storage/Disk/Drive.hpp index ffc52f70c..b91f25afe 100644 --- a/Storage/Disk/Drive.hpp +++ b/Storage/Disk/Drive.hpp @@ -149,7 +149,7 @@ public: */ struct EventDelegate { /// Informs the delegate that @c event has been reached. - virtual void process_event(const Event &event) = 0; + virtual void process_event(const Event &) = 0; /*! If the drive is in write mode, announces that all queued bits have now been written. @@ -157,8 +157,13 @@ public: */ virtual void process_write_completed() {} + /*! + When in write mode, indicates that output of the final bit has begun. + */ + virtual void is_writing_final_bit() {} + /// Informs the delegate of the passing of @c cycles. - virtual void advance([[maybe_unused]] Cycles cycles) {} + virtual void advance(Cycles) {} }; /// Sets the current event delegate.