From f89ba103f2f2a1daf729d4dd93cc97410db8d739 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 5 Apr 2026 10:47:26 -0400 Subject: [PATCH 1/9] Add note. --- Machines/Thomson/MO5/CD90-640.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Machines/Thomson/MO5/CD90-640.cpp b/Machines/Thomson/MO5/CD90-640.cpp index f3e5cc3a8..2d51fbf8c 100644 --- a/Machines/Thomson/MO5/CD90-640.cpp +++ b/Machines/Thomson/MO5/CD90-640.cpp @@ -14,7 +14,9 @@ CD90_640::CD90_640() : WD::WD1770(P1770) { // 325 is a peculiar RPM, but seems to match a spin-up test in the disk ROM that polls the WD1770's status register // index hole bit and counts time. Furthermore there are other machines with unusual RPMs. Could definitely // still just imply an issue elsewhere in the emulator though. - emplace_drives(2, 8000000, 325, 2); + // + // TODO: I think the 325 proves some sort of timing issue elsewhere. Should be 360. Investigate. + emplace_drives(2, 8'000'000, 325, 2); } uint8_t CD90_640::control() { From 2c76c4808f6d76cd175ad3f298e8c5001789118b Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 6 Apr 2026 09:50:38 -0400 Subject: [PATCH 2/9] Add extra debugging capability. --- Storage/TimedEventLoop.cpp | 24 ++++++++++++++++++------ Storage/TimedEventLoop.hpp | 5 +++++ 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/Storage/TimedEventLoop.cpp b/Storage/TimedEventLoop.cpp index 89a3fb15e..782e91c4b 100644 --- a/Storage/TimedEventLoop.cpp +++ b/Storage/TimedEventLoop.cpp @@ -14,7 +14,7 @@ using namespace Storage; -TimedEventLoop::TimedEventLoop(Cycles::IntType input_clock_rate) : +TimedEventLoop::TimedEventLoop(const Cycles::IntType input_clock_rate) : input_clock_rate_(input_clock_rate) {} void TimedEventLoop::add_delay(const Cycles cycles) { @@ -73,24 +73,36 @@ void TimedEventLoop::jump_to_next_event() { process_next_event(); } -void TimedEventLoop::set_next_event_time_interval(Time interval) { +void TimedEventLoop::set_next_event_time_interval(const Time interval) { set_next_event_time_interval(interval.get()); } -void TimedEventLoop::set_next_event_time_interval(float interval) { +void TimedEventLoop::set_next_event_time_interval(const float interval) { // Calculate [interval]*[input clock rate] + [subcycles until this event] - const float float_interval = interval * float(input_clock_rate_) + subcycles_until_event_; + const float cycles = interval * float(input_clock_rate_) + subcycles_until_event_; // This event will fire in the integral number of cycles from now, putting us at the remainder // number of subcycles. - const Cycles::IntType addition = Cycles::IntType(float_interval); + const Cycles::IntType addition = Cycles::IntType(cycles); cycles_until_event_ += addition; - subcycles_until_event_ = fmodf(float_interval, 1.0f); + subcycles_until_event_ = std::fmod(cycles, 1.0f); + +#ifndef NDEBUG + cycles_total_ += addition; +#endif assert(cycles_until_event_ >= 0); assert(subcycles_until_event_ >= 0.0f); } +#ifndef NDEBUG +float TimedEventLoop::get_reset_cycles_total() { + const auto result = cycles_total_; + cycles_total_ = 0; + return result; +} +#endif + Time TimedEventLoop::get_time_into_next_event() { // TODO: calculate, presumably as [length of interval] - ([cycles left] + [subcycles left]) Time zero; diff --git a/Storage/TimedEventLoop.hpp b/Storage/TimedEventLoop.hpp index f7e280aea..fa42a68ed 100644 --- a/Storage/TimedEventLoop.hpp +++ b/Storage/TimedEventLoop.hpp @@ -111,12 +111,17 @@ protected: */ Time get_time_into_next_event(); +#ifndef NDEBUG + float get_reset_cycles_total(); +#endif + private: Cycles::IntType input_clock_rate_ = 0; Cycles::IntType cycles_until_event_ = 0; float subcycles_until_event_ = 0.0f; #ifndef NDEBUG int event_count_ = 0; + float cycles_total_ = 0.0f; #endif }; From ee9dae6922667f37ce11470f6c6b4a946f213d8b Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 6 Apr 2026 09:54:28 -0400 Subject: [PATCH 3/9] Make minor style improvements. --- Storage/Disk/Drive.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Storage/Disk/Drive.cpp b/Storage/Disk/Drive.cpp index 42ad569c9..931877bd1 100644 --- a/Storage/Disk/Drive.cpp +++ b/Storage/Disk/Drive.cpp @@ -33,7 +33,7 @@ Drive::Drive( // Get at least 64 bits of random information; rounding is likey to give this a slight bias. random_source_ = 0; - auto half_range = (randomiser.max() - randomiser.min()) / 2; + const auto half_range = (randomiser.max() - randomiser.min()) / 2; for(int bit = 0; bit < 64; ++bit) { random_source_ <<= 1; random_source_ |= ((randomiser() - randomiser.min()) >= half_range) ? 1 : 0; @@ -233,11 +233,11 @@ void Drive::run_for(const Cycles cycles) { if(disk_is_rotating_) { if(has_disk_) { - Time zero(0); + static constexpr Time zero(0); auto number_of_cycles = cycles.get(); while(number_of_cycles) { - auto cycles_until_next_event = get_cycles_until_next_event(); + const auto cycles_until_next_event = get_cycles_until_next_event(); auto cycles_to_run_for = std::min(cycles_until_next_event, number_of_cycles); if(!is_reading_ && cycles_until_bits_written_ > zero) { auto write_cycles_target = cycles_until_bits_written_.get(); @@ -248,7 +248,7 @@ void Drive::run_for(const Cycles cycles) { number_of_cycles -= cycles_to_run_for; if(!is_reading_) { if(cycles_until_bits_written_ > zero) { - Storage::Time cycles_to_run_for_time(static_cast(cycles_to_run_for)); + const 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_) { @@ -347,7 +347,10 @@ void Drive::get_next_event(const float duration_already_passed) { void Drive::process_next_event() { if(current_event_.type == Track::Event::IndexHole) { ++ready_index_count_; - if(ready_index_count_ == 2 && (ready_type_ == ReadyType::ShugartRDY || ready_type_ == ReadyType::ShugartModifiedRDY)) { + if( + ready_index_count_ == 2 && + (ready_type_ == ReadyType::ShugartRDY || ready_type_ == ReadyType::ShugartModifiedRDY) + ) { is_ready_ = true; } cycles_since_index_hole_ = 0; From 3c0b4b35b239313a6d12c4356afe88a93e409cfc Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 6 Apr 2026 10:09:08 -0400 Subject: [PATCH 4/9] Transcribe notes. --- Machines/Thomson/MO5/CD90-640.cpp | 78 ++++++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 2 deletions(-) diff --git a/Machines/Thomson/MO5/CD90-640.cpp b/Machines/Thomson/MO5/CD90-640.cpp index 2d51fbf8c..2c4245fc1 100644 --- a/Machines/Thomson/MO5/CD90-640.cpp +++ b/Machines/Thomson/MO5/CD90-640.cpp @@ -14,9 +14,83 @@ CD90_640::CD90_640() : WD::WD1770(P1770) { // 325 is a peculiar RPM, but seems to match a spin-up test in the disk ROM that polls the WD1770's status register // index hole bit and counts time. Furthermore there are other machines with unusual RPMs. Could definitely // still just imply an issue elsewhere in the emulator though. - // - // TODO: I think the 325 proves some sort of timing issue elsewhere. Should be 360. Investigate. emplace_drives(2, 8'000'000, 325, 2); + + // + // On "325 RPM": + // + // The DOS ROM verifies that a disk is present and spinning before proceeding. + // Part of that test is of spin speed. + // + // Specifically, with X = 0xa7d0 it performs: + // + // ; + // ; Wait for index hole set. + // ; + // a29b LDA ,X ; 4 µs + // a29d ANDA #$02 ; 2 µs + // a29f BEQ ZA29B ; 3 µs + // + // ; + // ; i.e. start of track falls about here + // ; + // + // ; + // ; Fixed delay... + // ; + // a2a1 LDY #M09C4 ; 4 µs + // a2a5 DEY ; 4 µs + // a2a7 BNE ZA2A5 ; 3 µs = net delay of 4 + 9C4*8 = 20,004 µs + // + // a2a9 PSHS CC ; 6 µs + // a2ab SEIF ; 3 µs + // + // ; + // ; Count time until index hole is set again + // ; + // a2ad LDA ,X ; 4 µs, read WD status + // a2af INY ; 4 µs + // a2b1 ANDA #$02 ; 2 µs + // a2b3 BEQ ZA2AD ; 3 µs + // + // a2b5 PULS CC + // + // ; + // ; Check whether rotation speed was within bounds + // ; + // a2b7 CMPY #M311B + // a2bb BMI ZA2C7 + // a2bd CMPY #M3357 + // a2c1 BPL ZA2C7 + // + // [test passed code here, test failed code from a2c7] + // + // If I've disassembled that correctly, then the process is: + // + // (1) wait for index hole, with up to 9 µs of latency; + // (2) spin in a loop for 20,004 µs; + // (3) do minor stack/flag work for 9 µs; + // (4) count time from here until next index hole, ending with Y = time/13; + // (5) test that that is within the bounds 0x311b, 0x3357. + // + // Ignoring minor potential latencies in loop exists, that's: + // + // (1) wait for index hole; + // (2) spend 20,013 µs doing something else; + // (3) get Y = time from there to next index hole. + // + // i.e. it's a test that the rotation it samples takes n cycles, where: + // + // 13 * 0x311b < n - 20,013 < 13 * 0x3357 + // 183436 µs < n < 190872 µs + // + // i.e. + // + // 327 >= RPM >= 314 RPM. + // + // So 325 RPM is a really weird number but I can't currently say why it should be + // wrong rather than merely unexpected. So here it is. + } uint8_t CD90_640::control() { From b17846304d52f5c4cc991511f8485dde1b14e281 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 6 Apr 2026 10:13:35 -0400 Subject: [PATCH 5/9] Correct typo. --- Machines/Thomson/MO5/CD90-640.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Machines/Thomson/MO5/CD90-640.cpp b/Machines/Thomson/MO5/CD90-640.cpp index 2c4245fc1..0a693986e 100644 --- a/Machines/Thomson/MO5/CD90-640.cpp +++ b/Machines/Thomson/MO5/CD90-640.cpp @@ -73,7 +73,7 @@ CD90_640::CD90_640() : WD::WD1770(P1770) { // (4) count time from here until next index hole, ending with Y = time/13; // (5) test that that is within the bounds 0x311b, 0x3357. // - // Ignoring minor potential latencies in loop exists, that's: + // Ignoring minor potential latencies in loop exits, that's: // // (1) wait for index hole; // (2) spend 20,013 µs doing something else; From 169bb63a84c8d57eb4c48904687145031c64d695 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 6 Apr 2026 10:14:31 -0400 Subject: [PATCH 6/9] Improve wording. --- Machines/Thomson/MO5/CD90-640.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Machines/Thomson/MO5/CD90-640.cpp b/Machines/Thomson/MO5/CD90-640.cpp index 0a693986e..0be7adc4b 100644 --- a/Machines/Thomson/MO5/CD90-640.cpp +++ b/Machines/Thomson/MO5/CD90-640.cpp @@ -77,12 +77,12 @@ CD90_640::CD90_640() : WD::WD1770(P1770) { // // (1) wait for index hole; // (2) spend 20,013 µs doing something else; - // (3) get Y = time from there to next index hole. + // (3) get Y = [µs from there to next index hole] / 13. // - // i.e. it's a test that the rotation it samples takes n cycles, where: + // i.e. it's a test that the rotation it samples takes n µs, where: // // 13 * 0x311b < n - 20,013 < 13 * 0x3357 - // 183436 µs < n < 190872 µs + // 183436 < n < 190872 // // i.e. // From c9213c9eadd00e86b0a8f0b86a01ae579a924ab1 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 6 Apr 2026 10:40:06 -0400 Subject: [PATCH 7/9] Correct arithmetic. --- Machines/Thomson/MO5/CD90-640.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Machines/Thomson/MO5/CD90-640.cpp b/Machines/Thomson/MO5/CD90-640.cpp index 0be7adc4b..831c7a83b 100644 --- a/Machines/Thomson/MO5/CD90-640.cpp +++ b/Machines/Thomson/MO5/CD90-640.cpp @@ -40,7 +40,7 @@ CD90_640::CD90_640() : WD::WD1770(P1770) { // ; // a2a1 LDY #M09C4 ; 4 µs // a2a5 DEY ; 4 µs - // a2a7 BNE ZA2A5 ; 3 µs = net delay of 4 + 9C4*8 = 20,004 µs + // a2a7 BNE ZA2A5 ; 3 µs = net delay of 4 + 9C4*7 = 17,500 µs // // a2a9 PSHS CC ; 6 µs // a2ab SEIF ; 3 µs @@ -68,7 +68,7 @@ CD90_640::CD90_640() : WD::WD1770(P1770) { // If I've disassembled that correctly, then the process is: // // (1) wait for index hole, with up to 9 µs of latency; - // (2) spin in a loop for 20,004 µs; + // (2) spin in a loop for 17,500 µs; // (3) do minor stack/flag work for 9 µs; // (4) count time from here until next index hole, ending with Y = time/13; // (5) test that that is within the bounds 0x311b, 0x3357. @@ -76,17 +76,18 @@ CD90_640::CD90_640() : WD::WD1770(P1770) { // Ignoring minor potential latencies in loop exits, that's: // // (1) wait for index hole; - // (2) spend 20,013 µs doing something else; + // (2) spend 17,509 µs doing something else; // (3) get Y = [µs from there to next index hole] / 13. // // i.e. it's a test that the rotation it samples takes n µs, where: // - // 13 * 0x311b < n - 20,013 < 13 * 0x3357 - // 183436 < n < 190872 + // 13 * 0x311b < n - 17,509 < 13 * 0x3357 + // 13 * 12,571 + 17,509 < n < 13 * 13,143 + 17,509 + // 180,932 < n < 188,368 // // i.e. // - // 327 >= RPM >= 314 RPM. + // 331 >= RPM >= 319 RPM. // // So 325 RPM is a really weird number but I can't currently say why it should be // wrong rather than merely unexpected. So here it is. From 4bf2e471e689f25c8ec8a4df755fbef013467c1f Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 6 Apr 2026 10:41:24 -0400 Subject: [PATCH 8/9] Tweak again. --- Machines/Thomson/MO5/CD90-640.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Machines/Thomson/MO5/CD90-640.cpp b/Machines/Thomson/MO5/CD90-640.cpp index 831c7a83b..0a0fb75d1 100644 --- a/Machines/Thomson/MO5/CD90-640.cpp +++ b/Machines/Thomson/MO5/CD90-640.cpp @@ -40,7 +40,7 @@ CD90_640::CD90_640() : WD::WD1770(P1770) { // ; // a2a1 LDY #M09C4 ; 4 µs // a2a5 DEY ; 4 µs - // a2a7 BNE ZA2A5 ; 3 µs = net delay of 4 + 9C4*7 = 17,500 µs + // a2a7 BNE ZA2A5 ; 3 µs = net delay of 4 + 9C4*7 = 17,504 µs // // a2a9 PSHS CC ; 6 µs // a2ab SEIF ; 3 µs @@ -68,7 +68,7 @@ CD90_640::CD90_640() : WD::WD1770(P1770) { // If I've disassembled that correctly, then the process is: // // (1) wait for index hole, with up to 9 µs of latency; - // (2) spin in a loop for 17,500 µs; + // (2) spin in a loop for 17,504 µs; // (3) do minor stack/flag work for 9 µs; // (4) count time from here until next index hole, ending with Y = time/13; // (5) test that that is within the bounds 0x311b, 0x3357. @@ -76,18 +76,18 @@ CD90_640::CD90_640() : WD::WD1770(P1770) { // Ignoring minor potential latencies in loop exits, that's: // // (1) wait for index hole; - // (2) spend 17,509 µs doing something else; + // (2) spend 17,513 µs doing something else; // (3) get Y = [µs from there to next index hole] / 13. // // i.e. it's a test that the rotation it samples takes n µs, where: // - // 13 * 0x311b < n - 17,509 < 13 * 0x3357 - // 13 * 12,571 + 17,509 < n < 13 * 13,143 + 17,509 - // 180,932 < n < 188,368 + // 13 * 0x311b < n - 17,513 < 13 * 0x3357 + // 13 * 12,571 + 17,513 < n < 13 * 13,143 + 17,513 + // 180,936 < n < 188,372 // // i.e. // - // 331 >= RPM >= 319 RPM. + // ~331 >= RPM >= ~319 RPM. // // So 325 RPM is a really weird number but I can't currently say why it should be // wrong rather than merely unexpected. So here it is. From 56aecc265b8a7110d7a8e25b986b3f732766e394 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 6 Apr 2026 11:08:08 -0400 Subject: [PATCH 9/9] Record resolution. --- Machines/Thomson/MO5/CD90-640.cpp | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/Machines/Thomson/MO5/CD90-640.cpp b/Machines/Thomson/MO5/CD90-640.cpp index 0a0fb75d1..12620498c 100644 --- a/Machines/Thomson/MO5/CD90-640.cpp +++ b/Machines/Thomson/MO5/CD90-640.cpp @@ -19,6 +19,9 @@ CD90_640::CD90_640() : WD::WD1770(P1770) { // // On "325 RPM": // + // Faulty reasoning was: + // --------------------- + // // The DOS ROM verifies that a disk is present and spinning before proceeding. // Part of that test is of spin speed. // @@ -39,7 +42,7 @@ CD90_640::CD90_640() : WD::WD1770(P1770) { // ; Fixed delay... // ; // a2a1 LDY #M09C4 ; 4 µs - // a2a5 DEY ; 4 µs + // a2a5 DEY ; 5 µs // a2a7 BNE ZA2A5 ; 3 µs = net delay of 4 + 9C4*7 = 17,504 µs // // a2a9 PSHS CC ; 6 µs @@ -49,7 +52,7 @@ CD90_640::CD90_640() : WD::WD1770(P1770) { // ; Count time until index hole is set again // ; // a2ad LDA ,X ; 4 µs, read WD status - // a2af INY ; 4 µs + // a2af INY ; 5 µs // a2b1 ANDA #$02 ; 2 µs // a2b3 BEQ ZA2AD ; 3 µs // @@ -81,9 +84,9 @@ CD90_640::CD90_640() : WD::WD1770(P1770) { // // i.e. it's a test that the rotation it samples takes n µs, where: // - // 13 * 0x311b < n - 17,513 < 13 * 0x3357 - // 13 * 12,571 + 17,513 < n < 13 * 13,143 + 17,513 - // 180,936 < n < 188,372 + // 14 * 0x311b < n - 17,513 < 14 * 0x3357 + // 14 * 12,571 + 20,009 < n < 14 * 13,143 + 20,009 + // 196,003 < n < 204,011 // // i.e. // @@ -91,7 +94,14 @@ CD90_640::CD90_640() : WD::WD1770(P1770) { // // So 325 RPM is a really weird number but I can't currently say why it should be // wrong rather than merely unexpected. So here it is. - + // + // Correct reasoning is: + // --------------------- + // + // The LEAYs that constitute INY and DEY above should be _five_ cycles long, not four. + // My 6809 timing is adrift. + // If loops were properly timed then 300 RPM looks appropriate. + // Cf. https://forum.system-cfg.com/viewtopic.php?f=1&t=17137 } uint8_t CD90_640::control() {