changeset 2062:07ed42bd7b4c segacd

Some progress on CDC and CDD emulation. Now passes first 3 "CDC INIT" tests in mcd-verificator
author Michael Pavone <pavone@retrodev.com>
date Fri, 28 Jan 2022 00:50:17 -0800
parents 7c1760b5b3e5
children d59ace2d7a6a
files cdd_mcu.c cdd_mcu.h cue.c lc8951.c lc8951.h segacd.c
diffstat 6 files changed, 280 insertions(+), 33 deletions(-) [+]
line wrap: on
line diff
--- a/cdd_mcu.c	Thu Jan 27 00:33:41 2022 -0800
+++ b/cdd_mcu.c	Fri Jan 28 00:50:17 2022 -0800
@@ -6,6 +6,7 @@
 #define CDD_MCU_DIVIDER 8
 #define SECTOR_CLOCKS (CD_BLOCK_CLKS/75)
 #define NIBBLE_CLOCKS (CDD_MCU_DIVIDER * 77)
+#define BYTE_CLOCKS (SECTOR_CLOCKS/2352) // 96
 
 //lead in start max diameter 46 mm
 //program area start max diameter 50 mm
@@ -102,6 +103,24 @@
 		handle_seek(context);
 		if (!context->seeking) {
 			context->head_pba++;
+			uint32_t lba = context->head_pba - LEADIN_SECTORS;
+			for (uint32_t i = 0; i < context->media->num_tracks; i++)
+			{
+				if (lba < context->media->tracks[i].fake_pregap) {
+					context->in_fake_pregap = 1;
+					break;
+				}
+				lba -= context->media->tracks[i].fake_pregap;
+				if (lba < context->media->tracks[i].start_lba) {
+					context->in_fake_pregap = 1;
+					break;
+				}
+				if (lba < context->media->tracks[i].end_lba) {
+					fseek(context->media->f, lba * 2352, SEEK_SET);
+					context->in_fake_pregap = 0;
+					break;
+				}
+			}
 		}
 		break;
 	case DS_PAUSE:
@@ -115,7 +134,7 @@
 				if (context->head_pba > 3*context->media->num_tracks + 1) {
 					context->toc_valid = 1;
 					context->seeking = 1;
-					context->seek_pba = LEADIN_SECTORS + context->media->tracks[0].start_lba + context->media->tracks[0].fake_pregap;
+					context->seek_pba = LEADIN_SECTORS + context->media->tracks[0].start_lba;
 					context->status = DS_PAUSE;
 				}
 
@@ -170,7 +189,7 @@
 		break;
 	case SF_TOCO:
 		if (context->toc_valid) {
-			lba_to_status(context, context->media->tracks[context->media->num_tracks - 1].end_lba + context->media->tracks[0].fake_pregap);
+			lba_to_status(context, context->media->tracks[context->media->num_tracks - 1].end_lba + (context->media->num_tracks > 1 ? context->media->tracks[1].fake_pregap : 0));
 			context->status_buffer.format = SF_TOCO;
 		} else {
 			context->status_buffer.format = SF_NOTREADY;
@@ -190,7 +209,11 @@
 		break;
 	case SF_TOCN:
 		if (context->toc_valid) {
-			lba_to_status(context, context->media->tracks[context->requested_track].start_lba + context->media->tracks[0].fake_pregap);
+			uint32_t lba = context->media->tracks[context->requested_track - 1].start_lba;
+			if (context->requested_track > 1) {
+				lba += context->media->tracks[1].fake_pregap;
+			}
+			lba_to_status(context, lba);
 			context->status_buffer.b.tocn.track_low = context->requested_track % 10;
 			context->status_buffer.format = SF_TOCN;
 		} else {
@@ -213,7 +236,7 @@
 	}
 	context->status_buffer.checksum = checksum((uint8_t *)&context->status_buffer);
 	if (context->status_buffer.format != SF_NOTREADY) {
-		printf("CDD Status %d%d.%d%d%d%d%d%d.%d%d\n",
+		printf("CDD Status %X%X.%X%X%X%X%X%X.%X%X\n",
 			context->status_buffer.status, context->status_buffer.format,
 			context->status_buffer.b.time.min_high, context->status_buffer.b.time.min_low,
 			context->status_buffer.b.time.sec_high, context->status_buffer.b.time.sec_low,
@@ -242,6 +265,34 @@
 		puts("CDD CMD: STOP");
 		context->status = DS_STOP;
 		break;
+	case CMD_READ:
+	case CMD_SEEK: {
+		if (context->status == DS_DOOR_OPEN || context->status == DS_TRAY_MOVING || context->status == DS_DISC_LEADOUT || context->status == DS_DISC_LEADIN) {
+			context->error_status = DS_CMD_ERROR;
+			break;
+		}
+		if (context->requested_format == SF_TOCT || context->requested_format == SF_TOCN) {
+			context->requested_format = SF_ABSOLUTE;
+		}
+		if (!context->toc_valid) {
+			context->error_status = DS_CMD_ERROR;
+			break;
+		}
+		uint32_t lba = context->cmd_buffer.b.time.min_high * 10 + context->cmd_buffer.b.time.min_low;
+		lba *= 60;
+		lba += context->cmd_buffer.b.time.sec_high * 10 + context->cmd_buffer.b.time.sec_low;
+		lba *= 75;
+		lba += context->cmd_buffer.b.time.frame_high * 10 + context->cmd_buffer.b.time.frame_low;
+		printf("READ/SEEK cmd for lba %d\n", lba);
+		if (lba >= context->media->tracks[0].fake_pregap + context->media->tracks[context->media->num_tracks - 1].end_lba) {
+			context->error_status = DS_CMD_ERROR;
+			break;
+		}
+		context->seek_pba = lba + LEADIN_SECTORS - 4;
+		context->seeking = 1;
+		context->status = context->cmd_buffer.cmd_type == CMD_READ ? DS_PLAY : DS_PAUSE;
+		break;
+	}
 	case CMD_REPORT_REQUEST:
 		switch (context->cmd_buffer.b.format.status_type)
 		{
@@ -275,6 +326,10 @@
 		case SF_TOCN:
 			context->requested_track = context->cmd_buffer.b.format.track_high * 10;
 			context->requested_track += context->cmd_buffer.b.format.track_low;
+			if (!context->media || context->requested_track > context->media->num_tracks) {
+				context->requested_format = SF_ABSOLUTE;
+				context->error_status = DS_CMD_ERROR;
+			}
 			context->status = DS_TOC_READ;
 			context->seeking = 1;
 			context->seek_pba = 0;
@@ -292,7 +347,7 @@
 #define BIT_DRS  0x2
 #define BIT_DTS  0x1
 
-void cdd_mcu_run(cdd_mcu *context, uint32_t cycle, uint16_t *gate_array)
+void cdd_mcu_run(cdd_mcu *context, uint32_t cycle, uint16_t *gate_array, lc8951* cdc)
 {
 	uint32_t cd_cycle = mclks_to_cd_block(cycle);
 	if (!(gate_array[GAO_CDD_CTRL] & BIT_HOCK)) {
@@ -304,6 +359,7 @@
 	uint32_t next_subcode = context->last_subcode_cycle + SECTOR_CLOCKS;
 	uint32_t next_nibble = context->current_status_nibble >= 0 ? context->last_nibble_cycle + NIBBLE_CLOCKS : CYCLE_NEVER;
 	uint32_t next_cmd_nibble = context->current_cmd_nibble >= 0 ? context->last_nibble_cycle + NIBBLE_CLOCKS : CYCLE_NEVER;
+	uint32_t next_byte = context->current_sector_byte >= 0 ? context->last_byte_cycle + BYTE_CLOCKS : CYCLE_NEVER;
 	for (; context->cycle < cd_cycle; context->cycle += CDD_MCU_DIVIDER)
 	{
 		if (context->cycle >= next_subcode) {
@@ -313,6 +369,10 @@
 			next_nibble = context->cycle;
 			context->current_status_nibble = 0;
 			gate_array[GAO_CDD_STATUS] |= BIT_DRS;
+			if (context->status == DS_PLAY && !context->seeking) {
+				next_byte = context->cycle;
+				context->current_sector_byte = 0;
+			}
 		}
 		if (context->cycle >= next_nibble) {
 			if (context->current_status_nibble == sizeof(cdd_status)) {
@@ -358,6 +418,37 @@
 				next_cmd_nibble = context->cycle + NIBBLE_CLOCKS;
 			}
 		}
+		if (context->cycle >= next_byte) {
+			uint8_t byte;
+			if (context->in_fake_pregap) {
+				if (!context->current_sector_byte || (context->current_sector_byte >= 16)) {
+					byte = 0;
+					//TODO: error detection and correction bytes
+				} else if (context->current_sector_byte < 12) {
+					byte = 0xFF;
+				} else if (context->current_sector_byte == 12) {
+					uint32_t minute = ((context->head_pba - LEADIN_SECTORS) / 75) / 60;
+					byte = (minute % 10) | ((minute / 10 ) << 4);
+				} else if (context->current_sector_byte == 13) {
+					uint32_t seconds = ((context->head_pba - LEADIN_SECTORS) / 75) % 60;
+					byte = (seconds % 10) | ((seconds / 10 ) << 4);
+				} else if (context->current_sector_byte == 14) {
+					uint32_t frames = (context->head_pba - LEADIN_SECTORS) % 75;
+					byte = (frames % 10) | ((frames / 10 ) << 4);
+				} else {
+					byte = 1;
+				}
+			} else {
+				byte = fgetc(context->media->f);
+			}
+			lc8951_write_byte(cdc, cd_block_to_mclks(context->cycle), context->current_sector_byte++, byte);
+			context->last_byte_cycle = context->cycle;
+			next_byte = context->cycle + BYTE_CLOCKS;
+			if (context->current_sector_byte == 2352) {
+				context->current_sector_byte = -1;
+
+			}
+		}
 	}
 }
 
@@ -400,4 +491,7 @@
 	if (context->last_nibble_cycle != CYCLE_NEVER) {
 		context->last_nibble_cycle -= cd_deduction;
 	}
+	if (context->last_byte_cycle != CYCLE_NEVER) {
+		context->last_byte_cycle -= cd_deduction;
+	}
 }
--- a/cdd_mcu.h	Thu Jan 27 00:33:41 2022 -0800
+++ b/cdd_mcu.h	Fri Jan 28 00:50:17 2022 -0800
@@ -1,7 +1,7 @@
 #ifndef CDD_MCU_H_
 #define CDD_MCU_H_
 #include "system.h"
-
+#include "lc8951.h"
 
 typedef enum {
 	SF_ABSOLUTE,
@@ -137,8 +137,10 @@
 	uint32_t      next_int_cycle; //this is in SCD MCLKS
 	uint32_t      last_subcode_cycle;
 	uint32_t      last_nibble_cycle;
+	uint32_t      last_byte_cycle;
 	int           current_status_nibble;
 	int           current_cmd_nibble;
+	int           current_sector_byte;
 	uint32_t      head_pba;
 	uint32_t      seek_pba;
 	cdd_status    status_buffer;
@@ -152,10 +154,11 @@
 	uint8_t       int_pending;
 	uint8_t       toc_valid;
 	uint8_t       seeking;
+	uint8_t       in_fake_pregap;
 } cdd_mcu;
 
 void cdd_mcu_init(cdd_mcu *context, system_media *media);
-void cdd_mcu_run(cdd_mcu *context, uint32_t cycle, uint16_t *gate_array);
+void cdd_mcu_run(cdd_mcu *context, uint32_t cycle, uint16_t *gate_array, lc8951* cdc);
 void cdd_hock_enabled(cdd_mcu *context);
 void cdd_hock_disabled(cdd_mcu *context);
 void cdd_mcu_start_cmd_recv(cdd_mcu *context, uint16_t *gate_array);
--- a/cue.c	Thu Jan 27 00:33:41 2022 -0800
+++ b/cue.c	Fri Jan 28 00:50:17 2022 -0800
@@ -141,6 +141,15 @@
 		//replace cue sheet with first sector
 		free(media->buffer);
 		media->buffer = calloc(2048, 1);
+		if (tracks[0].type = TRACK_DATA) {
+			// if the first track is a data track, don't trust the CUE sheet and look at the MM:SS:FF from first sector
+			uint8_t msf[3];
+			fseek(media->f, 12, SEEK_SET);
+			if (sizeof(msf) == fread(msf, 1, sizeof(msf), media->f)) {
+				tracks[0].fake_pregap = msf[2] + (msf[0] * 60 + msf[1]) * 75;
+			}
+		}
+
 		fseek(media->f, 16, SEEK_SET);
 		media->size = fread(media->buffer, 1, 2048, media->f);
 	}
--- a/lc8951.c	Thu Jan 27 00:33:41 2022 -0800
+++ b/lc8951.c	Fri Jan 28 00:50:17 2022 -0800
@@ -1,4 +1,5 @@
 #include "lc8951.h"
+#include "backend.h"
 
 enum {
 	COMIN,
@@ -36,7 +37,7 @@
 //IFCTRL
 #define BIT_CMDIEN 0x80
 #define BIT_DTEIEN 0x40
-#define BIT_CECIEN 0x20
+#define BIT_DECIEN 0x20
 #define BIT_CMDBK  0x10
 #define BIT_DTWAI  0x08
 #define BIT_STWAI  0x04
@@ -52,6 +53,13 @@
 #define BIT_DTEN   0x02
 #define BIT_STEN   0x01
 
+//CTRL0
+#define BIT_DECEN 0x80
+#define BIT_WRRQ  0x04
+
+//STAT3
+#define BIT_VALST 0x80
+
 //datasheet timing info
 //3 cycles for memory operation
 //6 cycles min for DMA-mode host transfer
@@ -62,10 +70,12 @@
 	//unclear if the difference is in the lc8951 or gate array
 	context->regs[IFSTAT] = 0xFF;
 	context->ar_mask = 0x1F;
+	context->clock_step = (2 + 2) * 6; // external divider, internal divider + DMA period
 }
 
 void lc8951_reg_write(lc8951 *context, uint8_t value)
 {
+	printf("CDC write %X: %X\n", context->ar, value);
 	switch (context->ar)
 	{
 	case SBOUT:
@@ -100,6 +110,8 @@
 	case DTTRG:
 		if (value & BIT_DOUTEN) {
 			context->regs[IFSTAT] &= ~BIT_DTBSY;
+			uint16_t transfer_size = context->regs[DBCL] | (context->regs[DBCH] << 8);
+			context->transfer_end = context->cycle + transfer_size * context->clock_step;
 		}
 		break;
 	case DTACK:
@@ -111,11 +123,20 @@
 	case WAH_WRITE:
 		context->regs[WAH] = value;
 		break;
+	case CTRL0:
+		context->ctrl0 = value;
+		break;
+	case CTRL1:
+		context->ctrl1 = value;
+		break;
 	case PTL_WRITE:
 		context->regs[PTL] = value;
 		break;
 	case PTH_WRITE:
 		context->regs[PTH] = value;
+		context->ptl_internal = (context->regs[PTL] | (context->regs[PTH] << 8)) & (sizeof(context->buffer) - 1);
+		context->decoding = 1;
+		context->decode_end = context->cycle + 2352 * context->clock_step * 4;
 		break;
 	case RESET:
 		context->comin_count = 0;
@@ -152,6 +173,7 @@
 	} else {
 		value = context->regs[context->ar];
 	}
+	printf("CDC read %X: %X\n", context->ar, value);
 	context->ar++;
 	context->ar &= context->ar_mask;
 	return value;
@@ -161,3 +183,96 @@
 {
 	context->ar = value & context->ar_mask;
 }
+
+//25 MHz clock input (1/2 SCD MCLK)
+//internal /2 divider
+//3 cycles for each SRAM access (though might be crystal frequency rather than internal frequency)
+//6 cycle period for DMA transfer out
+//
+
+void lc8951_run(lc8951 *context, uint32_t cycle)
+{
+	for(; context->cycle < cycle; context->cycle += context->clock_step)
+	{
+		if (context->cycle >= context->decode_end) {
+			context->decode_end = CYCLE_NEVER;
+			context->regs[IFSTAT] &= ~BIT_DECI;
+			context->regs[STAT3] &= ~BIT_VALST;
+			uint16_t block_start = (context->regs[PTL] | (context->regs[PTH] << 8)) & (sizeof(context->buffer)-1);
+			for (int reg = HEAD0; reg < PTL; reg++)
+			{
+				printf("Setting HEAD%d to buffer[%X]\n", reg - HEAD0, block_start);
+				context->regs[reg] =context->buffer[block_start++];
+				block_start &= (sizeof(context->buffer)-1);
+			}
+			printf("Decode done %X:%X:%X mode %X\n", context->regs[HEAD0], context->regs[HEAD1], context->regs[HEAD2], context->regs[HEAD3]);
+		}
+		if (context->transfer_end != CYCLE_NEVER) {
+			//TODO: transfer byte to gate array destination
+			context->dac++;
+			context->regs[DBCL]--;
+			if (!context->regs[DBCL]) {
+				context->regs[DBCH]--;
+				if (!context->regs[DBCH]) {
+					context->regs[IFSTAT] &= ~BIT_DTEI;
+					if (context->cycle != context->transfer_end) {
+						printf("Expected transfer end at %u but ended at %u\n", context->transfer_end, context->cycle);
+					}
+					context->transfer_end = CYCLE_NEVER;
+				}
+			}
+		}
+	}
+}
+
+void lc8951_write_byte(lc8951 *context, uint32_t cycle, int sector_offset, uint8_t byte)
+{
+	lc8951_run(context, cycle);
+	uint16_t current_write_addr = context->regs[WAL] | (context->regs[WAH] << 8);
+	if (sector_offset == 12) {
+		//we've recevied the sync pattern for the next block
+
+		//header/status regs no longer considered "valid"
+		context->regs[STAT3] |= BIT_VALST;
+		if ((context->ctrl0 & (BIT_DECEN|BIT_WRRQ)) == (BIT_DECEN|BIT_WRRQ)) {
+			uint16_t block_start = current_write_addr - 2352;
+			context->regs[PTL] = block_start;
+			context->regs[PTH] = block_start >> 8;
+			printf("Decoding block starting at %X\n", block_start);
+			context->ptl_internal = block_start & (sizeof(context->buffer)-1);
+			context->decode_end = context->cycle + 2352 * context->clock_step * 4;
+		}
+	}
+	if (sector_offset >= 12 && sector_offset < 16) {
+		//TODO: Handle SHDREN = 1
+		if ((context->ctrl0 & (BIT_DECEN|BIT_WRRQ)) == (BIT_DECEN)) {
+			//monitor only mode
+			context->regs[HEAD0 + sector_offset - 12] = byte;
+		}
+	}
+	if ((context->ctrl0 & (BIT_DECEN|BIT_WRRQ)) == (BIT_DECEN|BIT_WRRQ)) {
+		printf("lc8951_write_byte: %X - [%X] = %X\n", sector_offset, current_write_addr, byte);
+		context->buffer[current_write_addr & (sizeof(context->buffer)-1)] = byte;
+		context->regs[WAL]++;
+		if (!context->regs[WAL]) {
+			context->regs[WAH]++;
+		}
+	}
+}
+
+uint32_t lc8951_next_interrupt(lc8951 *context)
+{
+	if ((!context->regs[IFSTAT]) & context->ifctrl & (BIT_CMDI|BIT_DTEI|BIT_DECI)) {
+		//interrupt already pending
+		return context->cycle;
+	}
+	uint32_t deci_cycle = CYCLE_NEVER;
+	if (context->ifctrl & BIT_DECI) {
+		deci_cycle = context->decode_end;
+	}
+	uint32_t dtei_cycle = CYCLE_NEVER;
+	if (context->ifctrl & BIT_DTEI) {
+		dtei_cycle = context->transfer_end;
+	}
+	return deci_cycle < dtei_cycle ? deci_cycle : dtei_cycle;
+}
--- a/lc8951.h	Thu Jan 27 00:33:41 2022 -0800
+++ b/lc8951.h	Fri Jan 28 00:50:17 2022 -0800
@@ -4,7 +4,10 @@
 #include <stdint.h>
 
 typedef struct {
-	uint32_t cycles;
+	uint32_t cycle;
+	uint32_t clock_step;
+	uint32_t decode_end;
+	uint32_t transfer_end;
 
 	uint8_t buffer[0x4000];
 
@@ -19,12 +22,16 @@
 	uint8_t ctrl1;
 	uint8_t ar;
 	uint8_t ar_mask;
+	uint8_t decoding;
+	uint16_t ptl_internal;
 } lc8951;
 
 void lc8951_init(lc8951 *context);
-//void lc8951_run(lc8951 *context, uint32_t cycle);
+void lc8951_run(lc8951 *context, uint32_t cycle);
 void lc8951_reg_write(lc8951 *context, uint8_t value);
 uint8_t lc8951_reg_read(lc8951 *context);
 void lc8951_ar_write(lc8951 *context, uint8_t value);
+void lc8951_write_byte(lc8951 *context, uint32_t cycle, int sector_offset, uint8_t byte);
+uint32_t lc8951_next_interrupt(lc8951 *context);
 
 #endif //LC8951_H_
--- a/segacd.c	Thu Jan 27 00:33:41 2022 -0800
+++ b/segacd.c	Fri Jan 28 00:50:17 2022 -0800
@@ -292,6 +292,12 @@
 	}
 }
 
+static void cdd_run(segacd_context *cd, uint32_t cycle)
+{
+	cdd_mcu_run(&cd->cdd, cycle, cd->gate_array + GA_CDD_CTRL, &cd->cdc);
+	lc8951_run(&cd->cdc, cycle);
+}
+
 static uint32_t next_timer_int(segacd_context *cd)
 {
 	if (cd->timer_pending) {
@@ -311,27 +317,36 @@
 	segacd_context *cd = context->system;
 	context->int_cycle = CYCLE_NEVER;
 	uint8_t mask = context->status & 0x7;
-	if (mask < 4) {
-		if (cd->gate_array[GA_INT_MASK] & BIT_MASK_IEN4) {
-			uint32_t cdd_cycle = cd->cdd.int_pending ? context->current_cycle : cd->cdd.next_int_cycle;
-			if (cdd_cycle < context->int_cycle) {
-				context->int_cycle = cdd_cycle;
-				context->int_num = 4;
+	if (mask < 5) {
+		if (cd->gate_array[GA_INT_MASK] & BIT_MASK_IEN5) {
+			uint32_t cdc_cycle = lc8951_next_interrupt(&cd->cdc);
+			if (cdc_cycle < context->int_cycle) {
+				context->int_cycle = cdc_cycle;
+				context->int_num = 5;
 			}
 		}
-		if (mask < 3) {
-			uint32_t next_timer;
-			if (cd->gate_array[GA_INT_MASK] & BIT_MASK_IEN3) {
-				uint32_t next_timer_cycle = next_timer_int(cd);
-				if (next_timer_cycle < context->int_cycle) {
-					context->int_cycle = next_timer_cycle;
-					context->int_num = 3;
+		if (mask < 4) {
+			if (cd->gate_array[GA_INT_MASK] & BIT_MASK_IEN4) {
+				uint32_t cdd_cycle = cd->cdd.int_pending ? context->current_cycle : cd->cdd.next_int_cycle;
+				if (cdd_cycle < context->int_cycle) {
+					context->int_cycle = cdd_cycle;
+					context->int_num = 4;
 				}
 			}
-			if (mask < 2) {
-				if (cd->int2_cycle < context->int_cycle && (cd->gate_array[GA_INT_MASK] & BIT_MASK_IEN2)) {
-					context->int_cycle = cd->int2_cycle;
-					context->int_num = 2;
+			if (mask < 3) {
+				uint32_t next_timer;
+				if (cd->gate_array[GA_INT_MASK] & BIT_MASK_IEN3) {
+					uint32_t next_timer_cycle = next_timer_int(cd);
+					if (next_timer_cycle < context->int_cycle) {
+						context->int_cycle = next_timer_cycle;
+						context->int_num = 3;
+					}
+				}
+				if (mask < 2) {
+					if (cd->int2_cycle < context->int_cycle && (cd->gate_array[GA_INT_MASK] & BIT_MASK_IEN2)) {
+						context->int_cycle = cd->int2_cycle;
+						context->int_num = 2;
+					}
 				}
 			}
 		}
@@ -370,6 +385,7 @@
 	case GA_CDC_CTRL:
 		return cd->gate_array[reg] | cd->cdc.ar;
 	case GA_CDC_REG_DATA:
+		cdd_run(cd, m68k->current_cycle);
 		return lc8951_reg_read(&cd->cdc);
 	case GA_STOP_WATCH:
 	case GA_TIMER:
@@ -380,7 +396,7 @@
 	case GA_CDD_STATUS2:
 	case GA_CDD_STATUS3:
 	case GA_CDD_STATUS4:
-		cdd_mcu_run(&cd->cdd, m68k->current_cycle, cd->gate_array + GA_CDD_CTRL);
+		cdd_run(cd, m68k->current_cycle);
 		return cd->gate_array[reg];
 		break;
 	case GA_FONT_DATA0:
@@ -482,12 +498,15 @@
 		break;
 	}
 	case GA_CDC_CTRL:
+		cdd_run(cd, m68k->current_cycle);
 		lc8951_ar_write(&cd->cdc, value);
 		cd->gate_array[reg] &= 0xC000;
 		cd->gate_array[reg] = value & 0x0700;
 		break;
 	case GA_CDC_REG_DATA:
+		cdd_run(cd, m68k->current_cycle);
 		lc8951_reg_write(&cd->cdc, value);
+		calculate_target_cycle(m68k);
 		break;
 	case GA_STOP_WATCH:
 		//docs say you should only write zero to reset
@@ -520,7 +539,7 @@
 		calculate_target_cycle(m68k);
 		break;
 	case GA_CDD_CTRL: {
-		cdd_mcu_run(&cd->cdd, m68k->current_cycle, cd->gate_array + GA_CDD_CTRL);
+		cdd_run(cd, m68k->current_cycle);
 		uint16_t changed = cd->gate_array[reg] ^ value;
 		cd->gate_array[reg] &= ~BIT_HOCK;
 		cd->gate_array[reg] |= value & BIT_HOCK;
@@ -538,11 +557,11 @@
 	case GA_CDD_CMD1:
 	case GA_CDD_CMD2:
 	case GA_CDD_CMD3:
-		cdd_mcu_run(&cd->cdd, m68k->current_cycle, cd->gate_array + GA_CDD_CTRL);
+		cdd_run(cd, m68k->current_cycle);
 		cd->gate_array[reg] = value & 0x0F0F;
 		break;
 	case GA_CDD_CMD4:
-		cdd_mcu_run(&cd->cdd, m68k->current_cycle, cd->gate_array + GA_CDD_CTRL);
+		cdd_run(cd, m68k->current_cycle);
 		cd->gate_array[reg] = value & 0x0F0F;
 		cdd_mcu_start_cmd_recv(&cd->cdd, cd->gate_array + GA_CDD_CTRL);
 		break;
@@ -586,7 +605,7 @@
 	case GA_CDD_CMD4:
 		if (!address) {
 			//byte write to $FF804A should not trigger transfer
-			cdd_mcu_run(&cd->cdd, m68k->current_cycle, cd->gate_array + GA_CDD_CTRL);
+			cdd_run(cd, m68k->current_cycle);
 			cd->gate_array[reg] &= 0x0F;
 			cd->gate_array[reg] |= (value << 8 & 0x0F00);
 			return vcontext;
@@ -611,7 +630,7 @@
 static void scd_peripherals_run(segacd_context *cd, uint32_t cycle)
 {
 	timers_run(cd, cycle);
-	cdd_mcu_run(&cd->cdd, cycle, cd->gate_array + GA_CDD_CTRL);
+	cdd_run(cd, cycle);
 }
 
 static m68k_context *sync_components(m68k_context * context, uint32_t address)