From dfa6b1173770f13f2c618290d3b0143ddbdb73f8 Mon Sep 17 00:00:00 2001
From: Thomas Harte <thomas.harte@gmail.com>
Date: Tue, 24 Dec 2019 20:53:37 -0500
Subject: [PATCH] Adds responsibility for an ongoing index pulse to the drive.

---
 Components/1770/1770.cpp   |  4 ++--
 Storage/Disk/Drive.cpp     | 24 ++++++++++++++----------
 Storage/Disk/Drive.hpp     | 28 ++++++++++++++++++----------
 Storage/TimedEventLoop.cpp |  4 ++--
 Storage/TimedEventLoop.hpp |  4 ++--
 5 files changed, 38 insertions(+), 26 deletions(-)

diff --git a/Components/1770/1770.cpp b/Components/1770/1770.cpp
index 61c476088..b91aeb6dd 100644
--- a/Components/1770/1770.cpp
+++ b/Components/1770/1770.cpp
@@ -68,8 +68,8 @@ uint8_t WD1770::get_register(int address) {
 					status |=
 						(get_drive().get_is_track_zero() ? Flag::TrackZero : 0) |
 						(status_.seek_error ? Flag::SeekError : 0) |
-						(get_drive().get_is_read_only() ? Flag::WriteProtect : 0);
-						// TODO: index hole
+						(get_drive().get_is_read_only() ? Flag::WriteProtect : 0) |
+						(get_drive().get_index_pulse() ? Flag::Index : 0);
 				break;
 
 				case Status::Two:
diff --git a/Storage/Disk/Drive.cpp b/Storage/Disk/Drive.cpp
index c4087236c..fea9cc277 100644
--- a/Storage/Disk/Drive.cpp
+++ b/Storage/Disk/Drive.cpp
@@ -63,7 +63,7 @@ void Drive::set_disk(const std::shared_ptr<Disk> &disk) {
 	update_clocking_observer();
 }
 
-bool Drive::has_disk() {
+bool Drive::has_disk() const {
 	return has_disk_;
 }
 
@@ -71,7 +71,7 @@ ClockingHint::Preference Drive::preferred_clocking() {
 	return (!motor_is_on_ || !has_disk_) ? ClockingHint::Preference::None : ClockingHint::Preference::JustInTime;
 }
 
-bool Drive::get_is_track_zero() {
+bool Drive::get_is_track_zero() const {
 	return head_position_ == HeadPosition(0);
 }
 
@@ -114,11 +114,11 @@ void Drive::set_head(int head) {
 	}
 }
 
-int Drive::get_head_count() {
+int Drive::get_head_count() const {
 	return available_heads_;
 }
 
-bool Drive::get_tachometer() {
+bool Drive::get_tachometer() const {
 	// I have made a guess here that the tachometer is a symmetric square wave;
 	// if that is correct then around 60 beats per rotation appears to be correct
 	// to proceed beyond the speed checks I've so far uncovered.
@@ -126,22 +126,22 @@ bool Drive::get_tachometer() {
 	return int(get_rotation() * 2.0f * ticks_per_rotation) & 1;
 }
 
-float Drive::get_rotation() {
+float Drive::get_rotation() const {
 	return get_time_into_track();
 }
 
-float Drive::get_time_into_track() {
+float Drive::get_time_into_track() const {
 	// i.e. amount of time since the index hole was seen, as a proportion of a second,
 	// converted to a proportion of a rotation.
 	return float(cycles_since_index_hole_) / (float(get_input_clock_rate()) * rotational_multiplier_);
 }
 
-bool Drive::get_is_read_only() {
+bool Drive::get_is_read_only() const {
 	if(disk_) return disk_->get_is_read_only();
 	return true;
 }
 
-bool Drive::get_is_ready() {
+bool Drive::get_is_ready() const {
 	return ready_index_count_ == 2;
 }
 
@@ -164,10 +164,14 @@ void Drive::set_motor_on(bool motor_is_on) {
 	}
 }
 
-bool Drive::get_motor_on() {
+bool Drive::get_motor_on() const {
 	return motor_is_on_;
 }
 
+bool Drive::get_index_pulse() const {
+	return index_pulse_remaining_ > Cycles(0);
+}
+
 void Drive::set_event_delegate(Storage::Disk::Drive::EventDelegate *delegate) {
 	event_delegate_ = delegate;
 }
@@ -384,7 +388,7 @@ void Drive::end_writing() {
 	}
 }
 
-bool Drive::is_writing() {
+bool Drive::is_writing() const {
 	return !is_reading_;
 }
 
diff --git a/Storage/Disk/Drive.hpp b/Storage/Disk/Drive.hpp
index f33b0d23a..330cdd734 100644
--- a/Storage/Disk/Drive.hpp
+++ b/Storage/Disk/Drive.hpp
@@ -36,12 +36,12 @@ class Drive: public ClockingHint::Source, public TimedEventLoop {
 		/*!
 			@returns @c true if a disk is currently inserted; @c false otherwise.
 		*/
-		bool has_disk();
+		bool has_disk() const;
 
 		/*!
 			@returns @c true if the drive head is currently at track zero; @c false otherwise.
 		*/
-		bool get_is_track_zero();
+		bool get_is_track_zero() const;
 
 		/*!
 			Steps the disk head the specified number of tracks. Positive numbers step inwards (i.e. away from track 0),
@@ -57,17 +57,17 @@ class Drive: public ClockingHint::Source, public TimedEventLoop {
 		/*!
 			Gets the head count for this disk.
 		*/
-		int get_head_count();
+		int get_head_count() const;
 
 		/*!
 			@returns @c true if the inserted disk is read-only or no disk is inserted; @c false otherwise.
 		*/
-		bool get_is_read_only();
+		bool get_is_read_only() const;
 
 		/*!
 			@returns @c true if the drive is ready; @c false otherwise.
 		*/
-		bool get_is_ready();
+		bool get_is_ready() const;
 
 		/*!
 			Sets whether the disk motor is on.
@@ -77,7 +77,12 @@ class Drive: public ClockingHint::Source, public TimedEventLoop {
 		/*!
 			@returns @c true if the motor is on; @c false otherwise.
 		*/
-		bool get_motor_on();
+		bool get_motor_on() const;
+
+		/*!
+			@returns @c true if the index pulse output is active; @c false otherwise.
+		*/
+		bool get_index_pulse() const;
 
 		/*!
 			Begins write mode, initiating a PCM sampled region of data. Bits should be written via
@@ -104,7 +109,7 @@ class Drive: public ClockingHint::Source, public TimedEventLoop {
 			@returns @c true if the drive has received a call to begin_writing but not yet a call to
 			end_writing; @c false otherwise.
 		*/
-		bool is_writing();
+		bool is_writing() const;
 
 		/*!
 			Advances the drive by @c number_of_cycles cycles.
@@ -163,7 +168,7 @@ class Drive: public ClockingHint::Source, public TimedEventLoop {
 		/*!
 			@returns the current value of the tachometer pulse offered by some drives.
 		*/
-		bool get_tachometer();
+		bool get_tachometer() const;
 
 	protected:
 		/*!
@@ -180,7 +185,7 @@ class Drive: public ClockingHint::Source, public TimedEventLoop {
 			@returns the current rotation of the disk, a float in the half-open range
 				0.0 (the index hole) to 1.0 (back to the index hole, a whole rotation later).
 		*/
-		float get_rotation();
+		float get_rotation() const;
 
 	private:
 		// Drives contain an entire disk; from that a certain track
@@ -210,6 +215,9 @@ class Drive: public ClockingHint::Source, public TimedEventLoop {
 		// Motor control state.
 		bool motor_is_on_ = false;
 
+		// Current state of the index pulse output.
+		Cycles index_pulse_remaining_;
+
 		// If the drive is not currently reading then it is writing. While writing
 		// it can optionally be told to clamp to the index hole.
 		bool is_reading_ = true;
@@ -235,7 +243,7 @@ class Drive: public ClockingHint::Source, public TimedEventLoop {
 		void advance(const Cycles cycles) override;
 
 		// Helper for track changes.
-		float get_time_into_track();
+		float get_time_into_track() const;
 
 		// The target (if any) for track events.
 		EventDelegate *event_delegate_ = nullptr;
diff --git a/Storage/TimedEventLoop.cpp b/Storage/TimedEventLoop.cpp
index c7326bb13..aba194ae2 100644
--- a/Storage/TimedEventLoop.cpp
+++ b/Storage/TimedEventLoop.cpp
@@ -46,11 +46,11 @@ void TimedEventLoop::run_for(const Cycles cycles) {
 	assert(cycles_until_event_ > 0);
 }
 
-Cycles::IntType TimedEventLoop::get_cycles_until_next_event() {
+Cycles::IntType TimedEventLoop::get_cycles_until_next_event() const {
 	return std::max(cycles_until_event_, Cycles::IntType(0));
 }
 
-Cycles::IntType TimedEventLoop::get_input_clock_rate() {
+Cycles::IntType TimedEventLoop::get_input_clock_rate() const {
 	return input_clock_rate_;
 }
 
diff --git a/Storage/TimedEventLoop.hpp b/Storage/TimedEventLoop.hpp
index 465e47292..64d4ce3a0 100644
--- a/Storage/TimedEventLoop.hpp
+++ b/Storage/TimedEventLoop.hpp
@@ -52,12 +52,12 @@ namespace Storage {
 			/*!
 				@returns the number of whole cycles remaining until the next event is triggered.
 			*/
-			Cycles::IntType get_cycles_until_next_event();
+			Cycles::IntType get_cycles_until_next_event() const;
 
 			/*!
 				@returns the input clock rate.
 			*/
-			Cycles::IntType get_input_clock_rate();
+			Cycles::IntType get_input_clock_rate() const;
 
 		protected:
 			/*!