diff --git a/HISTORY.txt b/HISTORY.txt index 85fac63..0760d85 100644 --- a/HISTORY.txt +++ b/HISTORY.txt @@ -24,7 +24,8 @@ Genesis Plus GX 1.7.5 (xx/xx/xxxx) (Eke-Eke) * improved Timer interrupt timings and CDD interrupt accuracy (fixes audio stutters during Popful Mail FMV) * improved CDC emulation (fixes random freezes during Jeopardy & ESPN Sunday Night NFL intro) * improved accuracy of Main-CPU & Sub-CPU access to CDC registers (verified on real hardware, cf. Krikzz's mcd-verificator) -* improved accuracy of CDC transfer to Main-CPU & Sub-CPU (verified on real hardware, cf. Krikzz's mcd-verificator) +* improved accuracy of CDC data transfer to Main-CPU & Sub-CPU (verified on real hardware, cf. Krikzz's mcd-verificator) +* improved accuracy of CDC DMA processing (verified on real hardware, cf. Krikzz's mcd-verificator) * improved emulation of mirrored memory areas * improved savestate format * improved Sub-CPU synchronization with Main-CPU (fixes "Soul Star") diff --git a/builds/genesis_plus_gx_libretro.dll b/builds/genesis_plus_gx_libretro.dll index d5ce4c2..24cbc93 100644 Binary files a/builds/genesis_plus_gx_libretro.dll and b/builds/genesis_plus_gx_libretro.dll differ diff --git a/builds/genplus_cube.dol b/builds/genplus_cube.dol index e292443..7136ec7 100644 Binary files a/builds/genplus_cube.dol and b/builds/genplus_cube.dol differ diff --git a/builds/genplus_wii.dol b/builds/genplus_wii.dol index befa6a2..bc7a8cc 100644 Binary files a/builds/genplus_wii.dol and b/builds/genplus_wii.dol differ diff --git a/core/cd_hw/cdc.c b/core/cd_hw/cdc.c index db6efa6..0dabad3 100644 --- a/core/cd_hw/cdc.c +++ b/core/cd_hw/cdc.c @@ -62,8 +62,11 @@ /* STAT3 register bitmask */ #define BIT_VALST 0x80 -/* TODO: figure exact DMA transfer rate */ -#define DMA_BYTES_PER_LINE 512 +/* DMA transfer rate */ +/* min. 4 x SUB-CPU cycles (i.e 16 x SCD cycles) per byte (cf https://github.com/MiSTer-devel/MegaCD_MiSTer/tree/master/docs/mcd%20logs) */ +/* additional delays caused by SUB-CPU access & periodic refresh (all RAM), GPU operation (Word-RAM only) or PCM playback (PCM RAM only) */ +/* are not emulated */ +#define DMA_CYCLES_PER_BYTE 16 void cdc_init(void) { @@ -105,11 +108,11 @@ void cdc_reset(void) cdc.head[1][2] = 0x00; cdc.head[1][3] = 0x00; - /* reset CDC cycle counter */ + /* reset CDC DMA cycle counter */ cdc.cycles = 0; - /* DMA transfer disabled */ - cdc.dma_w = 0; + /* disable CDC DMA */ + cdc.dma_w = cdc.halted_dma_w = 0; /* clear any pending IRQ */ if (scd.pending & (1 << 5)) @@ -147,12 +150,19 @@ int cdc_context_save(uint8 *state) { tmp8 = 5; } + else if (cdc.halted_dma_w == prg_ram_dma_w) + { + tmp8 = 6; + } + else if (cdc.halted_dma_w == word_ram_2M_dma_w) + { + tmp8 = 7; + } else { tmp8 = 0; } - save_param(&cdc.ifstat, sizeof(cdc.ifstat)); save_param(&cdc.ifctrl, sizeof(cdc.ifctrl)); save_param(&cdc.dbc, sizeof(cdc.dbc)); @@ -194,31 +204,181 @@ int cdc_context_load(uint8 *state) { case 1: cdc.dma_w = pcm_ram_dma_w; + cdc.halted_dma_w = 0; break; case 2: cdc.dma_w = prg_ram_dma_w; + cdc.halted_dma_w = 0; break; case 3: cdc.dma_w = word_ram_0_dma_w; + cdc.halted_dma_w = 0; break; case 4: cdc.dma_w = word_ram_1_dma_w; + cdc.halted_dma_w = 0; break; case 5: cdc.dma_w = word_ram_2M_dma_w; + cdc.halted_dma_w = 0; + break; + case 6: + cdc.dma_w = 0; + cdc.halted_dma_w = prg_ram_dma_w; + break; + case 7: + cdc.dma_w = 0; + cdc.halted_dma_w = word_ram_2M_dma_w; break; default: cdc.dma_w = 0; + cdc.halted_dma_w = 0; break; } return bufferptr; } -void cdc_dma_update(void) +void cdc_dma_init(void) { + /* no effect if data transfer is not started */ + if (cdc.ifstat & BIT_DTEN) + return; + + /* disable DMA by default */ + cdc.dma_w = cdc.halted_dma_w = 0; + + /* check data transfer destination */ + switch (scd.regs[0x04>>1].byte.h & 0x07) + { + case 2: /* MAIN-CPU host read */ + case 3: /* SUB-CPU host read */ + { + /* read 16-bit word from CDC RAM buffer (big-endian format) into gate-array register $08 */ + /* Note: on real-hardware, 16-bit word is not immediately available, cf. https://github.com/MiSTer-devel/MegaCD_MiSTer/blob/master/docs/mcd%20logs/dma_sub_read.jpg for transfer timings */ + scd.regs[0x08>>1].w = READ_WORD(cdc.ram, cdc.dac.w & 0x3ffe); +#ifdef LOG_CDC + error("CDC host read 0x%04x -> 0x%04x (dbc=0x%x) (%X)\n", cdc.dac.w, scd.regs[0x08>>1].w, cdc.dbc.w, s68k.pc); +#endif + + /* set DSR bit (gate-array register $04) */ + scd.regs[0x04>>1].byte.h |= 0x40; + + /* increment data address counter */ + cdc.dac.w += 2; + + /* decrement data byte counter */ + cdc.dbc.w -= 2; + + /* end of transfer ? */ + if ((int16)cdc.dbc.w < 0) + { + /* reset data byte counter (DBCH bits 4-7 should also be set to 1) */ + cdc.dbc.w = 0xffff; + + /* clear !DTEN and !DTBSY */ + cdc.ifstat |= (BIT_DTBSY | BIT_DTEN); + + /* pending Data Transfer End interrupt */ + cdc.ifstat &= ~BIT_DTEI; + + /* Data Transfer End interrupt enabled ? */ + if (cdc.ifctrl & BIT_DTEIEN) + { + /* pending level 5 interrupt */ + scd.pending |= (1 << 5); + + /* level 5 interrupt enabled ? */ + if (scd.regs[0x32>>1].byte.l & 0x20) + { + /* update IRQ level */ + s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1); + } + } + + /* set EDT bit (gate-array register $04) */ + scd.regs[0x04>>1].byte.h |= 0x80; + } + + break; + } + + case 4: /* PCM RAM DMA */ + { + cdc.dma_w = pcm_ram_dma_w; + break; + } + + case 5: /* PRG-RAM DMA */ + { + /* check if MAIN-CPU has access to PRG-RAM */ + if (scd.regs[0x00].byte.l & 0x02) + { + /* halt DMA to PRG-RAM */ + cdc.halted_dma_w = prg_ram_dma_w; + } + else + { + /* enable DMA to PRG-RAM */ + cdc.dma_w = prg_ram_dma_w; + } + break; + } + + case 7: /* Word-RAM DMA */ + { + /* check memory mode */ + if (scd.regs[0x02 >> 1].byte.l & 0x04) + { + /* 1M mode */ + if (scd.regs[0x02 >> 1].byte.l & 0x01) + { + /* Word-RAM bank 0 is assigned to SUB-CPU */ + cdc.dma_w = word_ram_0_dma_w; + } + else + { + /* Word-RAM bank 1 is assigned to SUB-CPU */ + cdc.dma_w = word_ram_1_dma_w; + } + } + else + { + /* check if MAIN-CPU has access to 2M Word-RAM */ + if (scd.regs[0x02 >> 1].byte.l & 0x01) + { + /* halt DMA to 2M Word-RAM */ + cdc.halted_dma_w = word_ram_2M_dma_w; + } + else + { + /* enable DMA to 2M Word-RAM */ + cdc.dma_w = word_ram_2M_dma_w; + } + } + break; + } + + default: /* invalid */ + { +#ifdef LOG_CDC + error("invalid CDC transfer destination (%d)\n", scd.regs[0x04>>1].byte.h & 0x07); +#endif + break; + } + } +} + +void cdc_dma_update(unsigned int cycles) +{ + /* max number of bytes that can be transfered */ + int dma_bytes = (cycles - cdc.cycles + DMA_CYCLES_PER_BYTE - 1) / DMA_CYCLES_PER_BYTE; + + /* always process blocks of 8 bytes */ + dma_bytes = (dma_bytes / 8) * 8; + /* end of DMA transfer ? */ - if (cdc.dbc.w < DMA_BYTES_PER_LINE) + if (cdc.dbc.w < dma_bytes) { /* transfer remaining bytes using DMA */ cdc.dma_w(cdc.dbc.w + 1); @@ -252,8 +412,8 @@ void cdc_dma_update(void) /* SUB-CPU idle on register $04 polling ? */ if (s68k.stopped & (1<<0x04)) { - /* sync SUB-CPU with CDC */ - s68k.cycles = scd.cycles; + /* sync SUB-CPU with CDC DMA */ + s68k.cycles = cdc.cycles; /* restart SUB-CPU */ s68k.stopped = 0; @@ -262,16 +422,19 @@ void cdc_dma_update(void) #endif } - /* disable DMA transfer */ - cdc.dma_w = 0; + /* disable DMA */ + cdc.dma_w = cdc.halted_dma_w = 0; } - else + else if (dma_bytes > 0) { /* transfer limited amount of bytes using DMA */ - cdc.dma_w(DMA_BYTES_PER_LINE); + cdc.dma_w(dma_bytes); /* decrement data byte counter */ - cdc.dbc.w -= DMA_BYTES_PER_LINE; + cdc.dbc.w -= dma_bytes; + + /* update DMA cycle counter */ + cdc.cycles += dma_bytes * DMA_CYCLES_PER_BYTE; } } @@ -403,6 +566,9 @@ void cdc_reg_w(unsigned char data) { /* clear !DTBSY and !DTEN */ cdc.ifstat |= (BIT_DTBSY | BIT_DTEN); + + /* disable DMA */ + cdc.dma_w = cdc.halted_dma_w = 0; } cdc.ifctrl = data; @@ -436,110 +602,11 @@ void cdc_reg_w(unsigned char data) /* clear EDT & DSR bits (gate-array register $04) */ scd.regs[0x04>>1].byte.h &= 0x07; - /* setup data transfer destination */ - switch (scd.regs[0x04>>1].byte.h & 0x07) - { - case 2: /* MAIN-CPU host read */ - case 3: /* SUB-CPU host read */ - { - /* read 16-bit word from CDC RAM buffer (big-endian format) into gate-array register $08 */ - /* Note: on real-hardware, 16-bit word is not immediately available, cf. https://github.com/MiSTer-devel/MegaCD_MiSTer/blob/master/docs/mcd%20logs/dma_sub_read.jpg for transfer timings */ - scd.regs[0x08>>1].w = READ_WORD(cdc.ram, cdc.dac.w & 0x3ffe); -#ifdef LOG_CDC - error("CDC host read 0x%04x -> 0x%04x (dbc=0x%x) (%X)\n", cdc.dac.w, scd.regs[0x08>>1].w, cdc.dbc.w, s68k.pc); -#endif + /* initialize data transfer destination */ + cdc_dma_init(); - /* set DSR bit (gate-array register $04) */ - scd.regs[0x04>>1].byte.h |= 0x40; - - /* increment data address counter */ - cdc.dac.w += 2; - - /* decrement data byte counter */ - cdc.dbc.w -= 2; - - /* end of transfer ? */ - if ((int16)cdc.dbc.w < 0) - { - /* reset data byte counter (DBCH bits 4-7 should also be set to 1) */ - cdc.dbc.w = 0xffff; - - /* clear !DTEN and !DTBSY */ - cdc.ifstat |= (BIT_DTBSY | BIT_DTEN); - - /* pending Data Transfer End interrupt */ - cdc.ifstat &= ~BIT_DTEI; - - /* Data Transfer End interrupt enabled ? */ - if (cdc.ifctrl & BIT_DTEIEN) - { - /* pending level 5 interrupt */ - scd.pending |= (1 << 5); - - /* level 5 interrupt enabled ? */ - if (scd.regs[0x32>>1].byte.l & 0x20) - { - /* update IRQ level */ - s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1); - } - } - - /* set EDT bit (gate-array register $04) */ - scd.regs[0x04>>1].byte.h |= 0x80; - } - - break; - } - - case 4: /* PCM RAM DMA */ - { - cdc.dma_w = pcm_ram_dma_w; - break; - } - - case 5: /* PRG-RAM DMA */ - { - cdc.dma_w = prg_ram_dma_w; - break; - } - - case 7: /* WORD-RAM DMA */ - { - /* check memory mode */ - if (scd.regs[0x02 >> 1].byte.l & 0x04) - { - /* 1M mode */ - if (scd.regs[0x02 >> 1].byte.l & 0x01) - { - /* Word-RAM bank 0 is assigned to SUB-CPU */ - cdc.dma_w = word_ram_0_dma_w; - } - else - { - /* Word-RAM bank 1 is assigned to SUB-CPU */ - cdc.dma_w = word_ram_1_dma_w; - } - } - else - { - /* 2M mode */ - if (scd.regs[0x02 >> 1].byte.l & 0x02) - { - /* only process DMA if Word-RAM is assigned to SUB-CPU */ - cdc.dma_w = word_ram_2M_dma_w; - } - } - break; - } - - default: /* invalid */ - { - #ifdef LOG_CDC - error("invalid CDC transfer destination (%d)\n", scd.regs[0x04>>1].byte.h & 0x07); - #endif - break; - } - } + /* initialize DMA cycle counter */ + cdc.cycles = s68k.cycles; } break; @@ -623,7 +690,7 @@ void cdc_reg_w(unsigned char data) cdc_reset(); break; - default: /* unemulated registers*/ + default: /* unemulated registers */ break; } @@ -757,7 +824,7 @@ unsigned char cdc_reg_r(void) } #ifdef LOG_CDC - error("CDC register %d read 0x%02X (%X)\n", scd.regs[0x04>>1].byte.l, data, s68k.pc); + error("CDC register %d read 0x%02X (%X)\n", scd.regs[0x04>>1].byte.l, data, s68k.pc); #endif /* increment address register (except when register #0 is selected) */ diff --git a/core/cd_hw/cdc.h b/core/cd_hw/cdc.h index a33af9d..03193e2 100644 --- a/core/cd_hw/cdc.h +++ b/core/cd_hw/cdc.h @@ -55,8 +55,9 @@ typedef struct uint8 ctrl[2]; uint8 head[2][4]; uint8 stat[4]; - int cycles; - void (*dma_w)(unsigned int length); /* DMA transfer callback */ + unsigned int cycles; + void (*dma_w)(unsigned int length); /* active DMA callback */ + void (*halted_dma_w)(unsigned int length); /* halted DMA callback */ uint8 ram[0x4000 + 2352]; /* 16K external RAM (with one block overhead to handle buffer overrun) */ uint8 ar_mask; } cdc_t; @@ -66,7 +67,8 @@ extern void cdc_init(void); extern void cdc_reset(void); extern int cdc_context_save(uint8 *state); extern int cdc_context_load(uint8 *state); -extern void cdc_dma_update(void); +extern void cdc_dma_init(void); +extern void cdc_dma_update(unsigned int cycles); extern void cdc_decoder_update(uint32 header); extern void cdc_reg_w(unsigned char data); extern unsigned char cdc_reg_r(void); diff --git a/core/cd_hw/scd.c b/core/cd_hw/scd.c index 0fb03a8..6a48817 100644 --- a/core/cd_hw/scd.c +++ b/core/cd_hw/scd.c @@ -1003,6 +1003,17 @@ static void scd_write_byte(unsigned int address, unsigned int data) gfx_update(s68k.cycles); } + /* check if CDC DMA to 2M Word-RAM is running */ + if (cdc.dma_w == word_ram_2M_dma_w) + { + /* synchronize CDC DMA with SUB-CPU */ + cdc_dma_update(s68k.cycles); + + /* halt CDC DMA to 2M Word-RAM */ + cdc.dma_w = 0; + cdc.halted_dma_w = word_ram_2M_dma_w; + } + /* Word-RAM is returned to MAIN-CPU */ scd.dmna = 0; @@ -1038,6 +1049,24 @@ static void scd_write_byte(unsigned int address, unsigned int data) return; } + case 0x04: /* CDC mode */ + { + scd.regs[0x04 >> 1].byte.h = data & 0x07; + + /* synchronize CDC DMA (if running) with SUB-CPU */ + if (cdc.dma_w) + { + cdc_dma_update(s68k.cycles); + } + + /* reinitialize CDC data transfer destination (verified on real hardware, cf. Krikzz's mcd-verificator) */ + cdc_dma_init(); + + /* reset CDC DMA address (verified on real hardware, cf. Krikzz's mcd-verificator) */ + scd.regs[0x0a >> 1].w = 0; + return; + } + case 0x05: /* CDC register address */ { scd.regs[0x04 >> 1].byte.l = data & cdc.ar_mask; @@ -1312,6 +1341,17 @@ static void scd_write_word(unsigned int address, unsigned int data) gfx_update(s68k.cycles); } + /* check if CDC DMA to 2M Word-RAM is running */ + if (cdc.dma_w == word_ram_2M_dma_w) + { + /* synchronize CDC DMA with SUB-CPU */ + cdc_dma_update(s68k.cycles); + + /* halt CDC DMA to 2M Word-RAM */ + cdc.dma_w = 0; + cdc.halted_dma_w = word_ram_2M_dma_w; + } + /* Word-RAM is returned to MAIN-CPU */ scd.dmna = 0; @@ -1350,6 +1390,18 @@ static void scd_write_word(unsigned int address, unsigned int data) case 0x04: /* CDC mode & register address */ { scd.regs[0x04 >> 1].w = data & (0x0700 | cdc.ar_mask); + + /* synchronize CDC DMA (if running) with SUB-CPU */ + if (cdc.dma_w) + { + cdc_dma_update(s68k.cycles); + } + + /* reinitialize CDC data transfer destination (verified on real hardware, cf. Krikzz's mcd-verificator) */ + cdc_dma_init(); + + /* reset CDC DMA address (verified on real hardware, cf. Krikzz's mcd-verificator) */ + scd.regs[0x0a >> 1].w = 0; return; } @@ -1833,16 +1885,6 @@ void scd_update(unsigned int cycles) int s68k_run_cycles; int s68k_end_cycles = scd.cycles + SCYCLES_PER_LINE; - /* update CDC DMA transfer */ - if (cdc.dma_w) - { - /* check if Word-RAM is returned to SUB-CPU in 2M mode */ - if ((cdc.dma_w != word_ram_2M_dma_w) || scd.dmna) - { - cdc_dma_update(); - } - } - /* run both CPU in sync until end of line */ do { @@ -1918,10 +1960,15 @@ void scd_update(unsigned int cycles) } while ((m68k.cycles < cycles) || (s68k.cycles < s68k_end_cycles)); - /* GFX processing */ + /* update CDC DMA processing (if running) */ + if (cdc.dma_w) + { + cdc_dma_update(scd.cycles); + } + + /* update GFX processing (if started) */ if (scd.regs[0x58>>1].byte.h & 0x80) { - /* update graphics operation if running */ gfx_update(scd.cycles); } } diff --git a/core/mem68k.c b/core/mem68k.c index 43f9bb7..414da90 100644 --- a/core/mem68k.c +++ b/core/mem68k.c @@ -756,6 +756,17 @@ void ctrl_io_write_byte(unsigned int address, unsigned int data) m68k.memory_map[base].write16 = m68k.memory_map[base+1].write16 = NULL; zbank_memory_map[base].read = zbank_memory_map[base+1].read = NULL; zbank_memory_map[base].write = zbank_memory_map[base+1].write = NULL; + + /* check if CDC DMA to PRG-RAM is running */ + if (cdc.dma_w == prg_ram_dma_w) + { + /* synchronize CDC DMA with MAIN-CPU */ + cdc_dma_update((m68k.cycles * SCYCLES_PER_LINE) / MCYCLES_PER_LINE); + + /* halt CDC DMA to PRG-RAM */ + cdc.dma_w = 0; + cdc.halted_dma_w = prg_ram_dma_w; + } } else { @@ -765,6 +776,23 @@ void ctrl_io_write_byte(unsigned int address, unsigned int data) m68k.memory_map[base].write16 = m68k.memory_map[base+1].write16 = m68k_unused_16_w; zbank_memory_map[base].read = zbank_memory_map[base+1].read = zbank_unused_r; zbank_memory_map[base].write = zbank_memory_map[base+1].write = zbank_unused_w; + + /* check if CDC DMA to PRG-RAM is halted */ + if (cdc.halted_dma_w == prg_ram_dma_w) + { + /* relative SUB-CPU cycle counter */ + unsigned int cycles = (m68k.cycles * SCYCLES_PER_LINE) / MCYCLES_PER_LINE; + + /* enable CDC DMA to PRG-RAM */ + cdc.dma_w = prg_ram_dma_w; + cdc.halted_dma_w = 0; + + /* synchronize CDC DMA with MAIN-CPU (only if not already ahead) */ + if (cdc.cycles < cycles) + { + cdc.cycles = cycles; + } + } } } @@ -840,7 +868,7 @@ void ctrl_io_write_byte(unsigned int address, unsigned int data) /* check if SUB-CPU is waiting for Word-RAM access */ if (s68k.stopped & 0x04) { - /* sync SUB-CPU with MAIN-CPU */ + /* synchronize SUB-CPU with MAIN-CPU */ s68k.cycles = (m68k.cycles * SCYCLES_PER_LINE) / MCYCLES_PER_LINE; /* restart SUB-CPU */ @@ -850,18 +878,36 @@ void ctrl_io_write_byte(unsigned int address, unsigned int data) #endif } - /* check if graphics operation is running */ + /* check if graphics operation is started */ if (scd.regs[0x58>>1].byte.h & 0x80) { /* relative SUB-CPU cycle counter */ unsigned int cycles = (m68k.cycles * SCYCLES_PER_LINE) / MCYCLES_PER_LINE; - /* synchronize GFX processing with SUB-CPU (only if not already ahead) */ + /* synchronize GFX processing with MAIN-CPU (only if not already ahead) */ if (gfx.cycles < cycles) { gfx.cycles = cycles; } } + + /* check if CDC DMA to 2M Word-RAM is halted */ + if (cdc.halted_dma_w == word_ram_2M_dma_w) + { + /* relative SUB-CPU cycle counter */ + unsigned int cycles = (m68k.cycles * SCYCLES_PER_LINE) / MCYCLES_PER_LINE; + + /* enable CDC DMA to 2M Word-RAM */ + cdc.dma_w = word_ram_2M_dma_w; + cdc.halted_dma_w = 0; + + /* synchronize CDC DMA with MAIN-CPU (only if not already ahead) */ + if (cdc.cycles < cycles) + { + cdc.cycles = cycles; + } + } + return; } } @@ -1039,6 +1085,17 @@ void ctrl_io_write_word(unsigned int address, unsigned int data) m68k.memory_map[base].write16 = m68k.memory_map[base+1].write16 = NULL; zbank_memory_map[base].read = zbank_memory_map[base+1].read = NULL; zbank_memory_map[base].write = zbank_memory_map[base+1].write = NULL; + + /* check if CDC DMA to PRG-RAM is running */ + if (cdc.dma_w == prg_ram_dma_w) + { + /* synchronize CDC DMA with MAIN-CPU */ + cdc_dma_update((m68k.cycles * SCYCLES_PER_LINE) / MCYCLES_PER_LINE); + + /* halt CDC DMA to PRG-RAM */ + cdc.dma_w = 0; + cdc.halted_dma_w = prg_ram_dma_w; + } } else { @@ -1048,6 +1105,23 @@ void ctrl_io_write_word(unsigned int address, unsigned int data) m68k.memory_map[base].write16 = m68k.memory_map[base+1].write16 = m68k_unused_16_w; zbank_memory_map[base].read = zbank_memory_map[base+1].read = zbank_unused_r; zbank_memory_map[base].write = zbank_memory_map[base+1].write = zbank_unused_w; + + /* check if CDC DMA to PRG-RAM is halted */ + if (cdc.halted_dma_w == prg_ram_dma_w) + { + /* relative SUB-CPU cycle counter */ + unsigned int cycles = (m68k.cycles * SCYCLES_PER_LINE) / MCYCLES_PER_LINE; + + /* enable CDC DMA to PRG-RAM */ + cdc.dma_w = prg_ram_dma_w; + cdc.halted_dma_w = 0; + + /* synchronize CDC DMA with MAIN-CPU (only if not already ahead) */ + if (cdc.cycles < cycles) + { + cdc.cycles = cycles; + } + } } } @@ -1133,7 +1207,7 @@ void ctrl_io_write_word(unsigned int address, unsigned int data) /* check if SUB-CPU is waiting for Word-RAM access */ if (s68k.stopped & 0x04) { - /* sync SUB-CPU with MAIN-CPU */ + /* synchronize SUB-CPU with MAIN-CPU */ s68k.cycles = (m68k.cycles * SCYCLES_PER_LINE) / MCYCLES_PER_LINE; /* restart SUB-CPU */ @@ -1143,18 +1217,35 @@ void ctrl_io_write_word(unsigned int address, unsigned int data) #endif } - /* check if graphics operation is running */ + /* check if graphics operation is started */ if (scd.regs[0x58>>1].byte.h & 0x80) { /* relative SUB-CPU cycle counter */ unsigned int cycles = (m68k.cycles * SCYCLES_PER_LINE) / MCYCLES_PER_LINE; - /* synchronize GFX processing with SUB-CPU (only if not already ahead) */ + /* synchronize GFX processing with MAIN-CPU (only if not already ahead) */ if (gfx.cycles < cycles) { gfx.cycles = cycles; } } + + /* check if CDC DMA to 2M Word-RAM is halted */ + if (cdc.halted_dma_w == word_ram_2M_dma_w) + { + /* relative SUB-CPU cycle counter */ + unsigned int cycles = (m68k.cycles * SCYCLES_PER_LINE) / MCYCLES_PER_LINE; + + /* enable CDC DMA to 2M Word-RAM */ + cdc.dma_w = word_ram_2M_dma_w; + cdc.halted_dma_w = 0; + + /* synchronize CDC DMA with MAIN-CPU (only if not already ahead) */ + if (cdc.cycles < cycles) + { + cdc.cycles = cycles; + } + } return; } }