# HG changeset patch # User Michael Pavone # Date 1643359817 28800 # Node ID 07ed42bd7b4cb86ced51c760f9b6a8fb4efe4489 # Parent 7c1760b5b3e5885c8d8f76ea210c9fff6d791c3c Some progress on CDC and CDD emulation. Now passes first 3 "CDC INIT" tests in mcd-verificator diff -r 7c1760b5b3e5 -r 07ed42bd7b4c cdd_mcu.c --- 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; + } } diff -r 7c1760b5b3e5 -r 07ed42bd7b4c cdd_mcu.h --- 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); diff -r 7c1760b5b3e5 -r 07ed42bd7b4c cue.c --- 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); } diff -r 7c1760b5b3e5 -r 07ed42bd7b4c lc8951.c --- 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; +} diff -r 7c1760b5b3e5 -r 07ed42bd7b4c lc8951.h --- 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 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_ diff -r 7c1760b5b3e5 -r 07ed42bd7b4c segacd.c --- 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)