From 2332f72875b25b2fdad4830a2adf631dc4e68b36 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 31 Jul 2016 13:32:30 -0400 Subject: [PATCH] Formalised clock-rate multiplication within disk drives, discovered that the stepper didn't have ideal behaviour for my timed event loop and hence nailed down the semantics a ilttle more. (obiter: the 1540 now appears to discern the correct sequence of bits. Framing is off in my test printfs but that's neither here nor there). --- Machines/Commodore/1540/C1540.cpp | 4 +-- Machines/Electron/Electron.cpp | 2 +- SignalProcessing/Stepper.hpp | 5 +++- Storage/Disk/DiskDrive.cpp | 43 +++++++++++++++++++++++++------ Storage/Disk/DiskDrive.hpp | 3 ++- Storage/Disk/PCMTrack.cpp | 11 +++++++- Storage/Storage.hpp | 5 ++++ 7 files changed, 59 insertions(+), 14 deletions(-) diff --git a/Machines/Commodore/1540/C1540.cpp b/Machines/Commodore/1540/C1540.cpp index 9f2cb4aa5..5d3000b7e 100644 --- a/Machines/Commodore/1540/C1540.cpp +++ b/Machines/Commodore/1540/C1540.cpp @@ -14,7 +14,7 @@ using namespace Commodore::C1540; Machine::Machine() : _shift_register(0), - Storage::DiskDrive(1000000, 300) + Storage::DiskDrive(1000000, 16, 300) { // create a serial port and a VIA to run it _serialPortVIA.reset(new SerialPortVIA); @@ -115,7 +115,7 @@ void Machine::mos6522_did_change_interrupt_status(void *mos6522) void Machine::process_input_bit(int value, unsigned int cycles_since_index_hole) { - _shift_register = (_shift_register >> 1) | (value << 10); + _shift_register = (_shift_register << 1) | value; static int bitCount = 0; bitCount++; diff --git a/Machines/Electron/Electron.cpp b/Machines/Electron/Electron.cpp index c6a0e2688..cc4c02be3 100644 --- a/Machines/Electron/Electron.cpp +++ b/Machines/Electron/Electron.cpp @@ -1008,7 +1008,7 @@ inline void Tape::run_for_cycles(unsigned int number_of_cycles) { if(_is_running) { - TapePlayer::run_for_cycles(number_of_cycles); + TapePlayer::run_for_cycles((int)number_of_cycles); } } else diff --git a/SignalProcessing/Stepper.hpp b/SignalProcessing/Stepper.hpp index 2137104b6..a874d8a51 100644 --- a/SignalProcessing/Stepper.hpp +++ b/SignalProcessing/Stepper.hpp @@ -19,6 +19,9 @@ namespace SignalProcessing { clock to sample something with another. Uses a Bresenham-like error term internally for full-integral storage with no drift. + + Pegs the beginning of both clocks to the time at which the stepper is created. So e.g. a stepper + that converts from an input clock of 1200 to an output clock of 2 will first fire on cycle 600. */ class Stepper { @@ -33,7 +36,7 @@ class Stepper of steps that should be taken at the @c output_rate. */ Stepper(uint64_t output_rate, uint64_t input_rate) : - accumulated_error_(0), + accumulated_error_(-((int64_t)input_rate << 1)), input_rate_(input_rate), output_rate_(output_rate), whole_step_(output_rate / input_rate), diff --git a/Storage/Disk/DiskDrive.cpp b/Storage/Disk/DiskDrive.cpp index 54165420b..4f0cdaeef 100644 --- a/Storage/Disk/DiskDrive.cpp +++ b/Storage/Disk/DiskDrive.cpp @@ -10,17 +10,19 @@ using namespace Storage; -DiskDrive::DiskDrive(unsigned int clock_rate, unsigned int revolutions_per_minute) : - _clock_rate(clock_rate * 16), +DiskDrive::DiskDrive(unsigned int clock_rate, unsigned int clock_rate_multiplier, unsigned int revolutions_per_minute) : + _clock_rate(clock_rate * clock_rate_multiplier), + _clock_rate_multiplier(clock_rate_multiplier), _revolutions_per_minute(revolutions_per_minute), _head_position(0), - TimedEventLoop(clock_rate * 16) + TimedEventLoop(clock_rate * clock_rate_multiplier) {} void DiskDrive::set_expected_bit_length(Time bit_length) { _bit_length = bit_length; + printf("expected bit length: %0.4f\n", bit_length.get_float() * 1000.0); // this conversion doesn't need to be exact because there's a lot of variation to be taken // account of in rotation speed, air turbulence, etc, so a direct conversion will do @@ -54,6 +56,28 @@ void DiskDrive::step(int direction) void DiskDrive::set_track() { _track = _disk->get_track_at_position((unsigned int)_head_position); + +// printf("***"); +// int calibration = -1; +// int bit = 0, shift = 0; +// while(1) +// { +// Track::Event event = _track->get_next_event(); +// if(event.type == Track::Event::IndexHole) break; +// if(calibration < 0) calibration = event.length.length; +// +// int number_of_bits = event.length.length / calibration; +// while(number_of_bits > 1) +// { +// shift = (shift << 1)&0xff; +// number_of_bits--; +// bit++; if(bit == 8) { printf("%02x.", shift); bit = 0; } +// } +// shift = ((shift << 1) | 0x01)&0xff; +// bit++; if(bit == 8) { printf("%02x.", shift); bit = 0; } +// } +// printf("***\n"); + reset_timer(); get_next_event(); } @@ -62,11 +86,13 @@ void DiskDrive::run_for_cycles(int number_of_cycles) { if(has_disk()) { - _cycles_since_index_hole += (unsigned int)number_of_cycles; - - number_of_cycles *= 16; - _pll->run_for_cycles(number_of_cycles); - TimedEventLoop::run_for_cycles(number_of_cycles); + number_of_cycles *= _clock_rate_multiplier; + while(number_of_cycles--) + { + _cycles_since_index_hole ++; + _pll->run_for_cycles(1); + TimedEventLoop::run_for_cycles(1); + } } } @@ -90,6 +116,7 @@ void DiskDrive::get_next_event() event_interval.clock_rate *= _revolutions_per_minute; event_interval.simplify(); set_next_event_time_interval(event_interval); +// printf("bit length: %0.4f\n", event_interval.get_float() * 1000.0); } void DiskDrive::process_next_event() diff --git a/Storage/Disk/DiskDrive.hpp b/Storage/Disk/DiskDrive.hpp index 2c2923927..7d3cb560a 100644 --- a/Storage/Disk/DiskDrive.hpp +++ b/Storage/Disk/DiskDrive.hpp @@ -17,7 +17,7 @@ namespace Storage { class DiskDrive: public DigitalPhaseLockedLoop::Delegate, public TimedEventLoop { public: - DiskDrive(unsigned int clock_rate, unsigned int revolutions_per_minute); + DiskDrive(unsigned int clock_rate, unsigned int clock_rate_multiplier, unsigned int revolutions_per_minute); void set_expected_bit_length(Time bit_length); @@ -43,6 +43,7 @@ class DiskDrive: public DigitalPhaseLockedLoop::Delegate, public TimedEventLoop private: Time _bit_length; unsigned int _clock_rate; + unsigned int _clock_rate_multiplier; unsigned int _revolutions_per_minute; std::shared_ptr _pll; diff --git a/Storage/Disk/PCMTrack.cpp b/Storage/Disk/PCMTrack.cpp index 3b96873b6..6723b6191 100644 --- a/Storage/Disk/PCMTrack.cpp +++ b/Storage/Disk/PCMTrack.cpp @@ -32,6 +32,8 @@ PCMTrack::Event PCMTrack::get_next_event() while(_segment_pointer < _segments.size()) { unsigned int clock_multiplier = _track_clock_rate / _segments[_segment_pointer].length_of_a_bit.clock_rate; + unsigned int bit_length = clock_multiplier * _segments[_segment_pointer].length_of_a_bit.length; + const uint8_t *segment_data = _segments[_segment_pointer].data.get(); while(_bit_pointer < _segments[_segment_pointer].number_of_bits) { @@ -39,7 +41,7 @@ PCMTrack::Event PCMTrack::get_next_event() // TODO: should I account for the converse bit ordering? Or can I assume MSB first? int bit = segment_data[_bit_pointer >> 3] & (0x80 >> (_bit_pointer&7)); _bit_pointer++; - _next_event.length.length += clock_multiplier * _segments[_segment_pointer].length_of_a_bit.length; + _next_event.length.length += bit_length; if(bit) return _next_event; } @@ -74,5 +76,12 @@ void PCMTrack::fix_length() _next_event.length.clock_rate += _segments[c].length_of_a_bit.length * _segments[c].number_of_bits * multiplier; } + uint8_t *data = _segments[0].data.get(); + for(int c = 0; c < _segments[0].number_of_bits >> 3; c++) + { + printf("%02x.", data[c]); + } + printf("===\n"); + _segment_pointer = _bit_pointer = 0; } diff --git a/Storage/Storage.hpp b/Storage/Storage.hpp index d4446b537..91abe794e 100644 --- a/Storage/Storage.hpp +++ b/Storage/Storage.hpp @@ -22,6 +22,11 @@ struct Time { length /= common_divisor; clock_rate /= common_divisor; } + + inline float get_float() + { + return (float)length / (float)clock_rate; + } }; }