From 8a2bdb8d22f6618f8c6464361c3a84999c3fc95b Mon Sep 17 00:00:00 2001
From: Thomas Harte <thomas.harte@gmail.com>
Date: Mon, 24 Jul 2017 21:19:05 -0400
Subject: [PATCH] Converted the TimedEventLoop and the things that sit atop it
 into `ClockReceiver`s.

---
 Components/1770/1770.cpp            |  5 +++--
 Components/1770/1770.hpp            |  5 +++--
 Machines/Commodore/1540/C1540.cpp   |  2 +-
 Machines/Commodore/Vic-20/Vic20.cpp |  2 +-
 Machines/Electron/Electron.cpp      |  2 +-
 Machines/Electron/Tape.cpp          |  2 +-
 Machines/Oric/Microdisc.cpp         |  2 +-
 Machines/Oric/Oric.cpp              |  2 +-
 Machines/ZX8081/ZX8081.cpp          |  2 +-
 StaticAnalyser/Commodore/Disk.cpp   |  8 ++++----
 Storage/Disk/DiskController.cpp     |  2 +-
 Storage/Disk/Encodings/MFM.cpp      | 10 +++++-----
 Storage/Tape/Tape.cpp               |  8 ++++----
 Storage/Tape/Tape.hpp               |  9 +++++----
 Storage/TimedEventLoop.cpp          |  4 ++--
 Storage/TimedEventLoop.hpp          |  5 +++--
 16 files changed, 37 insertions(+), 33 deletions(-)

diff --git a/Components/1770/1770.cpp b/Components/1770/1770.cpp
index 6e2011f45..168dfb817 100644
--- a/Components/1770/1770.cpp
+++ b/Components/1770/1770.cpp
@@ -124,10 +124,11 @@ uint8_t WD1770::get_register(int address) {
 	}
 }
 
-void WD1770::run_for_cycles(unsigned int number_of_cycles) {
-	Storage::Disk::Controller::run_for_cycles((int)number_of_cycles);
+void WD1770::run_for(const Cycles &cycles) {
+	Storage::Disk::Controller::run_for(cycles);
 
 	if(delay_time_) {
+		unsigned int number_of_cycles = (unsigned int)cycles.as_int();
 		if(delay_time_ <= number_of_cycles) {
 			delay_time_ = 0;
 			posit_event(Event::Timer);
diff --git a/Components/1770/1770.hpp b/Components/1770/1770.hpp
index 507393946..0272a74d5 100644
--- a/Components/1770/1770.hpp
+++ b/Components/1770/1770.hpp
@@ -11,6 +11,7 @@
 
 #include "../../Storage/Disk/DiskController.hpp"
 #include "../../NumberTheory/CRC.hpp"
+#include "../ClockReceiver.hpp"
 
 namespace WD {
 
@@ -18,7 +19,7 @@ namespace WD {
 	Provides an emulation of various Western Digital drive controllers, including the
 	WD1770, WD1772, FDC1773 and FDC1793.
 */
-class WD1770: public Storage::Disk::Controller {
+class WD1770: public ClockReceiver<WD1770>, public Storage::Disk::Controller {
 	public:
 		enum Personality {
 			P1770,	// implies automatic motor-on management, with Type 2 commands offering a spin-up disable
@@ -43,7 +44,7 @@ class WD1770: public Storage::Disk::Controller {
 		uint8_t get_register(int address);
 
 		/// Runs the controller for @c number_of_cycles cycles.
-		void run_for_cycles(unsigned int number_of_cycles);
+		void run_for(const Cycles &cycles);
 
 		enum Flag: uint8_t {
 			NotReady		= 0x80,
diff --git a/Machines/Commodore/1540/C1540.cpp b/Machines/Commodore/1540/C1540.cpp
index ae3266038..8e379ee37 100644
--- a/Machines/Commodore/1540/C1540.cpp
+++ b/Machines/Commodore/1540/C1540.cpp
@@ -83,7 +83,7 @@ void Machine::run_for_cycles(int number_of_cycles) {
 	CPU::MOS6502::Processor<Machine>::run_for(Cycles(number_of_cycles));
 	set_motor_on(drive_VIA_.get_motor_enabled());
 	if(drive_VIA_.get_motor_enabled()) // TODO: motor speed up/down
-		Storage::Disk::Controller::run_for_cycles(number_of_cycles);
+		Storage::Disk::Controller::run_for(Cycles(number_of_cycles));
 }
 
 #pragma mark - 6522 delegate
diff --git a/Machines/Commodore/Vic-20/Vic20.cpp b/Machines/Commodore/Vic-20/Vic20.cpp
index 67513e38a..dc85fbc32 100644
--- a/Machines/Commodore/Vic-20/Vic20.cpp
+++ b/Machines/Commodore/Vic-20/Vic20.cpp
@@ -187,7 +187,7 @@ unsigned int Machine::perform_bus_operation(CPU::MOS6502::BusOperation operation
 			typer_.reset();
 		}
 	}
-	tape_->run_for_cycles(1);
+	tape_->run_for(Cycles(1));
 	if(c1540_) c1540_->run_for_cycles(1);
 
 	return 1;
diff --git a/Machines/Electron/Electron.cpp b/Machines/Electron/Electron.cpp
index 7441c7f90..f27e26ce6 100644
--- a/Machines/Electron/Electron.cpp
+++ b/Machines/Electron/Electron.cpp
@@ -329,7 +329,7 @@ unsigned int Machine::perform_bus_operation(CPU::MOS6502::BusOperation operation
 	}
 
 	if(typer_) typer_->update((int)cycles);
-	if(plus3_) plus3_->run_for_cycles(4*cycles);
+	if(plus3_) plus3_->run_for(Cycles(4*(int)cycles));
 	if(shift_restart_counter_) {
 		shift_restart_counter_ -= cycles;
 		if(shift_restart_counter_ <= 0) {
diff --git a/Machines/Electron/Tape.cpp b/Machines/Electron/Tape.cpp
index 4d0d37959..a328bc23d 100644
--- a/Machines/Electron/Tape.cpp
+++ b/Machines/Electron/Tape.cpp
@@ -84,7 +84,7 @@ void Tape::run_for_cycles(unsigned int number_of_cycles) {
 	if(is_enabled_) {
 		if(is_in_input_mode_) {
 			if(is_running_) {
-				TapePlayer::run_for_cycles((int)number_of_cycles);
+				TapePlayer::run_for(Cycles((int)number_of_cycles));
 			}
 		} else {
 			output_.cycles_into_pulse += number_of_cycles;
diff --git a/Machines/Oric/Microdisc.cpp b/Machines/Oric/Microdisc.cpp
index f9bed5a0e..e5f248fbc 100644
--- a/Machines/Oric/Microdisc.cpp
+++ b/Machines/Oric/Microdisc.cpp
@@ -109,7 +109,7 @@ void Microdisc::run_for_cycles(unsigned int number_of_cycles) {
 		head_load_request_counter_ += number_of_cycles;
 		if(head_load_request_counter_ >= head_load_request_counter_target) set_head_loaded(true);
 	}
-	WD::WD1770::run_for_cycles(number_of_cycles);
+	WD::WD1770::run_for(Cycles((int)number_of_cycles));
 }
 
 bool Microdisc::get_drive_is_ready() {
diff --git a/Machines/Oric/Oric.cpp b/Machines/Oric/Oric.cpp
index 8c4a6d52f..3dd709834 100644
--- a/Machines/Oric/Oric.cpp
+++ b/Machines/Oric/Oric.cpp
@@ -243,7 +243,7 @@ void Machine::VIA::flush() {
 void Machine::VIA::run_for_cycles(unsigned int number_of_cycles) {
 	cycles_since_ay_update_ += number_of_cycles;
 	MOS::MOS6522<VIA>::run_for_cycles(number_of_cycles);
-	tape->run_for_cycles((int)number_of_cycles);
+	tape->run_for(Cycles((int)number_of_cycles));
 }
 
 void Machine::VIA::update_ay() {
diff --git a/Machines/ZX8081/ZX8081.cpp b/Machines/ZX8081/ZX8081.cpp
index 5641ee94b..8c6dc32d8 100644
--- a/Machines/ZX8081/ZX8081.cpp
+++ b/Machines/ZX8081/ZX8081.cpp
@@ -55,7 +55,7 @@ int Machine::perform_machine_cycle(const CPU::Z80::PartialMachineCycle &cycle) {
 
 	if(is_zx81_) horizontal_counter_ %= HalfCycles(Cycles(207));
 	if(!tape_advance_delay_) {
-		tape_player_.run_for_cycles(cycle.length.as_int());
+		tape_player_.run_for(cycle.length);
 	} else {
 		tape_advance_delay_ = std::max(tape_advance_delay_ - cycle.length, HalfCycles(0));
 	}
diff --git a/StaticAnalyser/Commodore/Disk.cpp b/StaticAnalyser/Commodore/Disk.cpp
index fa54e613c..37c89c015 100644
--- a/StaticAnalyser/Commodore/Disk.cpp
+++ b/StaticAnalyser/Commodore/Disk.cpp
@@ -78,13 +78,13 @@ class CommodoreGCRParser: public Storage::Disk::Controller {
 
 			// find end of lead-in
 			while(shift_register_ == 0x3ff && index_count_ < 2) {
-				run_for_cycles(1);
+				run_for(Cycles(1));
 			}
 
 			// continue for a further nine bits
 			bit_count_ = 0;
 			while(bit_count_ < 9 && index_count_ < 2) {
-				run_for_cycles(1);
+				run_for(Cycles(1));
 			}
 
 			return Storage::Encodings::CommodoreGCR::decoding_from_dectet(shift_register_);
@@ -92,14 +92,14 @@ class CommodoreGCRParser: public Storage::Disk::Controller {
 
 		unsigned int get_next_byte() {
 			bit_count_ = 0;
-			while(bit_count_ < 10) run_for_cycles(1);
+			while(bit_count_ < 10) run_for(Cycles(1));
 			return Storage::Encodings::CommodoreGCR::decoding_from_dectet(shift_register_);
 		}
 
 		void proceed_to_shift_value(unsigned int shift_value) {
 			index_count_ = 0;
 			while(shift_register_ != shift_value && index_count_ < 2) {
-				run_for_cycles(1);
+				run_for(Cycles(1));
 			}
 		}
 
diff --git a/Storage/Disk/DiskController.cpp b/Storage/Disk/DiskController.cpp
index 675be3403..2c48b7541 100644
--- a/Storage/Disk/DiskController.cpp
+++ b/Storage/Disk/DiskController.cpp
@@ -75,7 +75,7 @@ void Controller::run_for(const Cycles &cycles) {
 					}
 				}
 			}
-			TimedEventLoop::run_for_cycles(cycles_to_run_for);
+			TimedEventLoop::run_for(Cycles(cycles_to_run_for));
 		}
 	}
 }
diff --git a/Storage/Disk/Encodings/MFM.cpp b/Storage/Disk/Encodings/MFM.cpp
index 33c69e0b3..1aa908e15 100644
--- a/Storage/Disk/Encodings/MFM.cpp
+++ b/Storage/Disk/Encodings/MFM.cpp
@@ -294,7 +294,7 @@ uint8_t Parser::get_byte_for_shift_value(uint16_t value) {
 
 uint8_t Parser::get_next_byte() {
 	bit_count_ = 0;
-	while(bit_count_ < 16) run_for_cycles(1);
+	while(bit_count_ < 16) run_for(Cycles(1));
 	uint8_t byte = get_byte_for_shift_value((uint16_t)shift_register_);
 	crc_generator_.add(byte);
 	return byte;
@@ -309,7 +309,7 @@ std::vector<uint8_t> Parser::get_track() {
 
 	// align to the next index hole
 	index_count_ = 0;
-	while(!index_count_) run_for_cycles(1);
+	while(!index_count_) run_for(Cycles(1));
 
 	// capture every other bit until the next index hole
 	index_count_ = 0;
@@ -319,7 +319,7 @@ std::vector<uint8_t> Parser::get_track() {
 		bool found_sync = false;
 		while(!index_count_ && !found_sync && bit_count_ < 16) {
 			int previous_bit_count = bit_count_;
-			run_for_cycles(1);
+			run_for(Cycles(1));
 
 			if(!distance_until_permissible_sync && bit_count_ != previous_bit_count) {
 				uint16_t low_shift_register = (shift_register_&0xffff);
@@ -393,7 +393,7 @@ std::shared_ptr<Sector> Parser::get_next_sector()
 		// look for an ID address mark
 		bool id_found = false;
 		while(!id_found) {
-			run_for_cycles(1);
+			run_for(Cycles(1));
 			if(is_mfm_) {
 				while(shift_register_ == MFMSync) {
 					uint8_t mark = get_next_byte();
@@ -424,7 +424,7 @@ std::shared_ptr<Sector> Parser::get_next_sector()
 		// look for data mark
 		bool data_found = false;
 		while(!data_found) {
-			run_for_cycles(1);
+			run_for(Cycles(1));
 			if(is_mfm_) {
 				while(shift_register_ == MFMSync) {
 					uint8_t mark = get_next_byte();
diff --git a/Storage/Tape/Tape.cpp b/Storage/Tape/Tape.cpp
index e0e3e81e3..8cb536557 100644
--- a/Storage/Tape/Tape.cpp
+++ b/Storage/Tape/Tape.cpp
@@ -92,9 +92,9 @@ void TapePlayer::get_next_pulse() {
 	set_next_event_time_interval(current_pulse_.length);
 }
 
-void TapePlayer::run_for_cycles(int number_of_cycles) {
+void TapePlayer::run_for(const Cycles &cycles) {
 	if(has_tape()) {
-		TimedEventLoop::run_for_cycles(number_of_cycles);
+		TimedEventLoop::run_for(cycles);
 	}
 }
 
@@ -125,8 +125,8 @@ bool BinaryTapePlayer::get_input() {
 	return motor_is_running_ && input_level_;
 }
 
-void BinaryTapePlayer::run_for_cycles(int number_of_cycles) {
-	if(motor_is_running_) TapePlayer::run_for_cycles(number_of_cycles);
+void BinaryTapePlayer::run_for(const Cycles &cycles) {
+	if(motor_is_running_) TapePlayer::run_for(cycles);
 }
 
 void BinaryTapePlayer::set_delegate(Delegate *delegate) {
diff --git a/Storage/Tape/Tape.hpp b/Storage/Tape/Tape.hpp
index 6f72ee4f7..f978fb55e 100644
--- a/Storage/Tape/Tape.hpp
+++ b/Storage/Tape/Tape.hpp
@@ -11,6 +11,7 @@
 
 #include <memory>
 #include "../TimedEventLoop.hpp"
+#include "../../Components/ClockReceiver.hpp"
 
 namespace Storage {
 namespace Tape {
@@ -91,7 +92,7 @@ class Tape {
 	Will call @c process_input_pulse instantaneously upon reaching *the end* of a pulse. Therefore a subclass
 	can decode pulses into data within process_input_pulse, using the supplied pulse's @c length and @c type.
 */
-class TapePlayer: public TimedEventLoop {
+class TapePlayer: public ClockReceiver<TapePlayer>, public TimedEventLoop {
 	public:
 		TapePlayer(unsigned int input_clock_rate);
 
@@ -99,7 +100,7 @@ class TapePlayer: public TimedEventLoop {
 		bool has_tape();
 		std::shared_ptr<Storage::Tape::Tape> get_tape();
 
-		void run_for_cycles(int number_of_cycles);
+		void run_for(const Cycles &cycles);
 		void run_for_input_pulse();
 
 	protected:
@@ -121,14 +122,14 @@ class TapePlayer: public TimedEventLoop {
 
 	They can also provide a delegate to be notified upon any change in the input level.
 */
-class BinaryTapePlayer: public TapePlayer {
+class BinaryTapePlayer: public ClockReceiver<BinaryTapePlayer>, public TapePlayer {
 	public:
 		BinaryTapePlayer(unsigned int input_clock_rate);
 		void set_motor_control(bool enabled);
 		void set_tape_output(bool set);
 		bool get_input();
 
-		void run_for_cycles(int number_of_cycles);
+		void run_for(const Cycles &cycles);
 
 		class Delegate {
 			public:
diff --git a/Storage/TimedEventLoop.cpp b/Storage/TimedEventLoop.cpp
index 25cb2456d..9587a550c 100644
--- a/Storage/TimedEventLoop.cpp
+++ b/Storage/TimedEventLoop.cpp
@@ -15,8 +15,8 @@ using namespace Storage;
 TimedEventLoop::TimedEventLoop(unsigned int input_clock_rate) :
 	input_clock_rate_(input_clock_rate) {}
 
-void TimedEventLoop::run_for_cycles(int number_of_cycles) {
-	cycles_until_event_ -= number_of_cycles;
+void TimedEventLoop::run_for(const Cycles &cycles) {
+	cycles_until_event_ -= cycles.as_int();
 	while(cycles_until_event_ <= 0) {
 		process_next_event();
 	}
diff --git a/Storage/TimedEventLoop.hpp b/Storage/TimedEventLoop.hpp
index cd4e3af42..e2cee9a0f 100644
--- a/Storage/TimedEventLoop.hpp
+++ b/Storage/TimedEventLoop.hpp
@@ -13,6 +13,7 @@
 
 #include <memory>
 #include "../SignalProcessing/Stepper.hpp"
+#include "../Components/ClockReceiver.hpp"
 
 namespace Storage {
 
@@ -36,7 +37,7 @@ namespace Storage {
 		@c reset_timer to initiate a distinctly-timed stream or @c jump_to_next_event to short-circuit the timing
 		loop and fast forward immediately to the next event.
 	*/
-	class TimedEventLoop {
+	class TimedEventLoop: public ClockReceiver<TimedEventLoop> {
 		public:
 			/*!
 				Constructs a timed event loop that will be clocked at @c input_clock_rate.
@@ -46,7 +47,7 @@ namespace Storage {
 			/*!
 				Advances the event loop by @c number_of_cycles cycles.
 			*/
-			void run_for_cycles(int number_of_cycles);
+			void run_for(const Cycles &cycles);
 
 			/*!
 				@returns the number of whole cycles remaining until the next event is triggered.