diff cdd_mcu.c @ 2116:cd057d6fe030

Initial stab at subcode emulation
author Michael Pavone <pavone@retrodev.com>
date Sun, 06 Mar 2022 22:03:52 -0800
parents e93ced356a21
children 03304d350339
line wrap: on
line diff
--- a/cdd_mcu.c	Sat Mar 05 14:17:59 2022 -0800
+++ b/cdd_mcu.c	Sun Mar 06 22:03:52 2022 -0800
@@ -7,6 +7,7 @@
 #define SECTOR_CLOCKS (CD_BLOCK_CLKS/75)
 #define NIBBLE_CLOCKS (CDD_MCU_DIVIDER * 77)
 #define BYTE_CLOCKS (SECTOR_CLOCKS/2352) // 96
+#define SUBCODE_CLOCKS (SECTOR_CLOCKS/98)
 #define PROCESSING_DELAY 54000 //approximate, based on Wondermega M1 measurements
 
 //lead in start max diameter 46 mm
@@ -38,20 +39,26 @@
 void cdd_mcu_init(cdd_mcu *context, system_media *media)
 {
 	context->next_int_cycle = CYCLE_NEVER;
-	context->last_subcode_cycle = CYCLE_NEVER;
+	context->next_subcode_int_cycle = CYCLE_NEVER;
+	context->last_sector_cycle = CYCLE_NEVER;
 	context->last_nibble_cycle = CYCLE_NEVER;
 	context->next_byte_cycle = 0;
+	context->next_subcode_cycle = CYCLE_NEVER;
 	context->requested_format = SF_NOTREADY;
 	context->media = media;
 	context->current_status_nibble = -1;
 	context->current_cmd_nibble = -1;
 	context->current_sector_byte = -1;
+	context->current_subcode_byte = -1;
+	context->current_subcode_dest = 0;
 }
 
 enum {
 	GAO_CDD_CTRL,
 	GAO_CDD_STATUS,
-	GAO_CDD_CMD = GAO_CDD_STATUS+5
+	GAO_CDD_CMD = GAO_CDD_STATUS+5,
+	GAO_SUBCODE_ADDR = (0x68-0x36)/2,
+	GAO_SUBCODE_START = (0x100-0x36)/2
 };
 //GAO_CDD_CTRL
 #define BIT_MUTE 0x100
@@ -376,7 +383,7 @@
 			context->error_status = DS_CMD_ERROR;
 			break;
 		}
-		if (context->requested_format == SF_TOCT || context->requested_format == SF_TOCN) {
+		if (context->requested_format == SF_TOCT || context->requested_format == SF_TOCN || context->requested_format == SF_TOCO) {
 			context->requested_format = SF_ABSOLUTE;
 		}
 		if (!context->toc_valid) {
@@ -541,12 +548,12 @@
 		gate_array[GAO_CDD_CTRL] |= BIT_MUTE;
 		return;
 	}
-	uint32_t next_subcode = context->last_subcode_cycle + SECTOR_CLOCKS;
+	uint32_t next_subcode = context->last_sector_cycle + SECTOR_CLOCKS;
 	uint32_t next_nibble;
 	if (context->current_status_nibble > 0) {
 		next_nibble = context->last_nibble_cycle + NIBBLE_CLOCKS;
 	} else if (!context->current_status_nibble) {
-		next_nibble = context->last_subcode_cycle + PROCESSING_DELAY;
+		next_nibble = context->last_sector_cycle + PROCESSING_DELAY;
 	} else {
 		next_nibble = CYCLE_NEVER;
 	}
@@ -555,14 +562,22 @@
 	for (; context->cycle < cd_cycle; context->cycle += CDD_MCU_DIVIDER)
 	{
 		if (context->cycle >= next_subcode) {
-			context->last_subcode_cycle = context->cycle;
+			context->last_sector_cycle = context->cycle;
 			next_subcode = context->cycle + SECTOR_CLOCKS;
 			update_status(context, gate_array);
 			next_nibble = context->cycle + PROCESSING_DELAY;
 			context->current_status_nibble = 0;
 			gate_array[GAO_CDD_STATUS] |= BIT_DRS;
+			if (context->next_subcode_int_cycle != CYCLE_NEVER) {
+				context->subcode_int_pending = 1;
+			}
 			if ((context->status == DS_PLAY || context->status == DS_PAUSE) && context->head_pba >= LEADIN_SECTORS) {
 				context->current_sector_byte = 0;
+				context->current_subcode_byte = 0;
+				context->next_subcode_cycle = context->cycle;
+				context->next_subcode_int_cycle = cd_block_to_mclks(next_subcode);
+			} else {
+				context->next_subcode_int_cycle = CYCLE_NEVER;
 			}
 		}
 		if (context->cycle >= next_nibble) {
@@ -618,7 +633,7 @@
 				cdd_fader_data(fader, 0);
 				if (context->current_sector_byte >= 0) {
 					next_subcode += BYTE_CLOCKS;
-					context->last_subcode_cycle += BYTE_CLOCKS;
+					context->last_sector_cycle += BYTE_CLOCKS;
 				}
 			}
 			if (context->current_sector_byte == 2352) {
@@ -626,6 +641,36 @@
 			}
 			context->next_byte_cycle += BYTE_CLOCKS;
 		}
+		if (context->cycle >= context->next_subcode_cycle) {
+			uint8_t byte;
+			if (!context->current_subcode_byte) {
+				byte = 0x9F;
+				//This probably happens after the second sync symbol, but doing it here simplifies things a little
+				context->current_subcode_dest &= 0x7E;
+				gate_array[GAO_SUBCODE_ADDR] = (context->current_subcode_dest - 96) & 0x7E;
+			} else if (context->current_subcode_byte == 1) {
+				byte = 0xFD;
+			} else {
+				byte = context->media->read_subcodes(context->media, context->current_subcode_byte - 2);
+			}
+			int offset = GAO_SUBCODE_START + (context->current_subcode_dest >> 1);
+			if (context->current_subcode_dest & 1) {
+				gate_array[offset] &= 0xFF00;
+				gate_array[offset] |= byte;
+			} else {
+				gate_array[offset] &= 0x00FF;
+				gate_array[offset] |= byte << 8;
+			}
+			context->current_subcode_byte++;
+			if (context->current_subcode_byte == 98) {
+				context->current_subcode_byte = 0;
+			} else if (context->current_subcode_byte == 32) {
+				gate_array[GAO_SUBCODE_ADDR] |= 0x80;
+			}
+			context->current_subcode_dest++;
+			context->current_subcode_dest &= 0x7F;
+			context->next_subcode_cycle += SUBCODE_CLOCKS;
+		}
 	}
 }
 
@@ -643,13 +688,13 @@
 
 void cdd_hock_enabled(cdd_mcu *context)
 {
-	context->last_subcode_cycle = context->cycle;
+	context->last_sector_cycle = context->cycle;
 	context->next_int_cycle = cd_block_to_mclks(context->cycle + SECTOR_CLOCKS + PROCESSING_DELAY + 7 * NIBBLE_CLOCKS);
 }
 
 void cdd_hock_disabled(cdd_mcu *context)
 {
-	context->last_subcode_cycle = CYCLE_NEVER;
+	context->last_sector_cycle = CYCLE_NEVER;
 	context->next_int_cycle = CYCLE_NEVER;
 	context->last_nibble_cycle = CYCLE_NEVER;
 	context->current_status_nibble = -1;
@@ -667,11 +712,11 @@
 	if (context->next_int_cycle != CYCLE_NEVER) {
 		context->next_int_cycle -= deduction;
 	}
-	if (context->last_subcode_cycle != CYCLE_NEVER) {
-		if (context->last_subcode_cycle > cd_deduction) {
-			context->last_subcode_cycle -= cd_deduction;
+	if (context->last_sector_cycle != CYCLE_NEVER) {
+		if (context->last_sector_cycle > cd_deduction) {
+			context->last_sector_cycle -= cd_deduction;
 		} else {
-			context->last_subcode_cycle = 0;
+			context->last_sector_cycle = 0;
 		}
 	}
 	if (context->last_nibble_cycle != CYCLE_NEVER) {
@@ -682,4 +727,7 @@
 		}
 	}
 	context->next_byte_cycle -= cd_deduction;
+	if (context->next_subcode_cycle != CYCLE_NEVER) {
+		context->next_subcode_cycle -= cd_deduction;
+	}
 }