changeset 2152:c3ee42c89b27

More accurate seek times and basic emulation of extended time between CDD interrupts during coarse seeking
author Michael Pavone <pavone@retrodev.com>
date Wed, 06 Apr 2022 21:44:46 -0700
parents 01ad74197414
children 8a30e44e8223 237068a25523
files cdd_mcu.c cdd_mcu.h
diffstat 2 files changed, 48 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/cdd_mcu.c	Wed Mar 30 23:20:45 2022 -0700
+++ b/cdd_mcu.c	Wed Apr 06 21:44:46 2022 -0700
@@ -85,25 +85,27 @@
 // circumference ~ 364.42 mm
 // ~ 21 sectors per physical track at edge
 // ~8 sectors per physical track at start of lead-in
-#define COARSE_SEEK 2200 //made up numbers
-#define FINE_SEEK 10
+#define COARSE_SEEK_TRACKS 57 //estimate based on seek test
 static void handle_seek(cdd_mcu *context)
 {
-	//TODO: more realistic seeking behavior
+	uint32_t old_coarse = context->coarse_seek;
 	if (context->seeking) {
 		if (context->seek_pba == context->head_pba) {
 			context->seeking = 0;
+			context->coarse_seek = 0;
 			if (context->status == DS_PAUSE) {
 				context->pause_pba = context->head_pba;
 			}
 		} else {
 			//TODO: better estimate of sectors per track at current head location
+			//TODO: drive will periodically lose tracking when seeking which slows
+			//things down from this ideal speed I'm curently estimating
 			float circumference = (MAX_CIRCUMFERENCE-MIN_CIRCUMFERENCE) * ((float)context->head_pba) / (74 * 60 * SECTORS_PER_SECOND) + MIN_CIRCUMFERENCE;
 			float sectors_per_track = circumference / SECTOR_LENGTH;
-			uint32_t max_seek = sectors_per_track * 190;
+			uint32_t max_seek = sectors_per_track * COARSE_SEEK_TRACKS;
 			uint32_t min_seek = sectors_per_track;
 
-
+			uint32_t old_pba = context->head_pba;
 			if (context->seek_pba > context->head_pba) {
 				uint32_t seek_amount;
 				for (seek_amount = max_seek; seek_amount >= min_seek; seek_amount >>= 1)
@@ -133,8 +135,15 @@
 					context->head_pba = 0;
 				}
 			}
+			if (context->head_pba != old_pba + 1) {
+				context->coarse_seek++;
+			} else {
+				context->coarse_seek = 0;
+			}
 		}
 	}
+	if (old_coarse && !context->coarse_seek) {
+	}
 }
 
 static void lba_to_status(cdd_mcu *context, uint32_t lba)
@@ -173,8 +182,13 @@
 		handle_seek(context);
 		if (!context->seeking) {
 			context->head_pba++;
-			if (context->head_pba > context->pause_pba + FINE_SEEK) {
-				context->head_pba = context->pause_pba - FINE_SEEK;
+			//TODO: better estimate of sectors per track at current head location
+			float circumference = (MAX_CIRCUMFERENCE-MIN_CIRCUMFERENCE) * ((float)context->head_pba) / (74 * 60 * SECTORS_PER_SECOND) + MIN_CIRCUMFERENCE;
+			float sectors_per_track = circumference / SECTOR_LENGTH;
+			//TODO: check the exact behavior during pause on hardware
+			uint32_t diff = sectors_per_track * 0.5f + 0.5f;
+			if (context->head_pba > context->pause_pba + diff) {
+				context->head_pba = context->pause_pba - diff;
 				if (context->head_pba < LEADIN_SECTORS) {
 					context->head_pba = LEADIN_SECTORS;
 				}
@@ -216,7 +230,8 @@
 		break;
 	}
 	uint8_t force_not_ready = 0;
-	if (context->seeking && context->head_pba - prev_pba != 1) {
+	if (context->coarse_seek  && !(context->coarse_seek % 15)) {
+		//TODO: adjust seeking for focus error when these bad statuses happen
 		//BIOS depends on getting a not ready status during seeking to clear certain state
 		force_not_ready = context->status_buffer.format != SF_NOTREADY;
 	}
@@ -586,6 +601,9 @@
 		next_nibble = context->last_nibble_cycle + NIBBLE_CLOCKS;
 	} else if (!context->current_status_nibble) {
 		next_nibble = context->last_sector_cycle + PROCESSING_DELAY;
+		if (context->coarse_seek % 3) {
+			next_nibble += SECTOR_CLOCKS * (3 - (context->coarse_seek % 3));
+		}
 	} else {
 		next_nibble = CYCLE_NEVER;
 	}
@@ -594,10 +612,14 @@
 	for (; context->cycle < cd_cycle; context->cycle += CDD_MCU_DIVIDER)
 	{
 		if (context->cycle >= next_subcode) {
+			uint32_t old_coarse = context->coarse_seek;
 			context->last_sector_cycle = context->cycle;
 			next_subcode = context->cycle + SECTOR_CLOCKS;
 			update_status(context, gate_array);
 			next_nibble = context->cycle + PROCESSING_DELAY;
+			if (context->coarse_seek % 3) {
+				next_nibble += SECTOR_CLOCKS * (3 - (context->coarse_seek % 3));
+			}
 			context->current_status_nibble = 0;
 			if (context->next_subcode_int_cycle != CYCLE_NEVER) {
 				context->subcode_int_pending = 1;
@@ -610,6 +632,12 @@
 			} else {
 				context->next_subcode_int_cycle = CYCLE_NEVER;
 			}
+			if (old_coarse != context->coarse_seek) {
+				context->next_int_cycle = cd_block_to_mclks(context->cycle + PROCESSING_DELAY + 7 * NIBBLE_CLOCKS);
+				if (context->coarse_seek % 3) {
+					context->next_int_cycle += cd_block_to_mclks(SECTOR_CLOCKS * (3 - (context->coarse_seek % 3)));
+				}
+			}
 		}
 		if (context->cycle >= next_nibble) {
 			if (context->current_status_nibble == sizeof(cdd_status)) {
@@ -634,8 +662,14 @@
 					gate_array[ga_index] = (value << 8) | (gate_array[ga_index]  & 0x00FF);
 				}
 				if (context->current_status_nibble == 7) {
-					context->int_pending = 1;
-					context->next_int_cycle = cd_block_to_mclks(context->cycle + SECTOR_CLOCKS);
+					if (!(context->coarse_seek % 3)) {
+						context->int_pending = 1;
+						if (context->coarse_seek) {
+							context->next_int_cycle = cd_block_to_mclks(context->cycle + 3 * SECTOR_CLOCKS);
+						} else {
+							context->next_int_cycle = cd_block_to_mclks(context->cycle + SECTOR_CLOCKS);
+						}
+					}
 				}
 				context->current_status_nibble++;
 				context->last_nibble_cycle = context->cycle;
@@ -726,6 +760,9 @@
 {
 	context->last_sector_cycle = context->cycle;
 	context->next_int_cycle = cd_block_to_mclks(context->cycle + SECTOR_CLOCKS + PROCESSING_DELAY + 7 * NIBBLE_CLOCKS);
+	if (context->coarse_seek % 3) {
+		context->next_int_cycle += cd_block_to_mclks(SECTOR_CLOCKS * (3 - (context->coarse_seek % 3)));
+	}
 }
 
 void cdd_hock_disabled(cdd_mcu *context)
--- a/cdd_mcu.h	Wed Mar 30 23:20:45 2022 -0700
+++ b/cdd_mcu.h	Wed Apr 06 21:44:46 2022 -0700
@@ -149,6 +149,7 @@
 	uint32_t      head_pba;
 	uint32_t      seek_pba;
 	uint32_t      pause_pba;
+	uint32_t      coarse_seek;
 	cdd_status    status_buffer;
 	cdd_cmd       cmd_buffer;
 	status_format requested_format;