diff --git a/HISTORY.txt b/HISTORY.txt index 0760d8549..57a713974 100644 --- a/HISTORY.txt +++ b/HISTORY.txt @@ -26,6 +26,8 @@ Genesis Plus GX 1.7.5 (xx/xx/xxxx) (Eke-Eke) * improved accuracy of Main-CPU & Sub-CPU access to CDC registers (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 accuracy of CDC decoder processing (verified on real hardware, cf. Krikzz's mcd-verificator) +* improved accuracy of CDC interrupt 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 878444415..7264f77c1 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 d01d13cee..9aa4eb651 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 cbefd17ab..762c9727b 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 0dabad3e0..493623360 100644 --- a/core/cd_hw/cdc.c +++ b/core/cd_hw/cdc.c @@ -108,12 +108,15 @@ void cdc_reset(void) cdc.head[1][2] = 0x00; cdc.head[1][3] = 0x00; - /* reset CDC DMA cycle counter */ - cdc.cycles = 0; + /* reset CDC DMA & decoder cycle counters */ + cdc.cycles[0] = cdc.cycles[1] = 0; /* disable CDC DMA */ cdc.dma_w = cdc.halted_dma_w = 0; + /* reset CDC IRQ state */ + cdc.irq = 0; + /* clear any pending IRQ */ if (scd.pending & (1 << 5)) { @@ -173,7 +176,6 @@ int cdc_context_save(uint8 *state) save_param(&cdc.head, sizeof(cdc.head)); save_param(&cdc.stat, sizeof(cdc.stat)); save_param(&cdc.cycles, sizeof(cdc.cycles)); - save_param(&cdc.dma_w, sizeof(cdc.dma_w)); save_param(&cdc.ram, sizeof(cdc.ram)); save_param(&tmp8, 1); @@ -195,7 +197,6 @@ int cdc_context_load(uint8 *state) load_param(&cdc.head, sizeof(cdc.head)); load_param(&cdc.stat, sizeof(cdc.stat)); load_param(&cdc.cycles, sizeof(cdc.cycles)); - load_param(&cdc.dma_w, sizeof(cdc.dma_w)); load_param(&cdc.ram, sizeof(cdc.ram)); load_param(&tmp8, 1); @@ -236,6 +237,8 @@ int cdc_context_load(uint8 *state) break; } + cdc.irq = ~cdc.ifstat & cdc.ifctrl & (BIT_DTEIEN | BIT_DECIEN); + return bufferptr; } @@ -285,15 +288,28 @@ void cdc_dma_init(void) /* Data Transfer End interrupt enabled ? */ if (cdc.ifctrl & BIT_DTEIEN) { - /* pending level 5 interrupt */ - scd.pending |= (1 << 5); + /* check end of CDC decoder active period */ + if ((cdc.irq & BIT_DECI) && (cdc.cycles[0] > cdc.cycles[1])) + { + /* clear pending decoder interrupt */ + cdc.ifstat |= BIT_DECI; - /* level 5 interrupt enabled ? */ - if (scd.regs[0x32>>1].byte.l & 0x20) + /* update CDC IRQ state */ + cdc.irq &= ~BIT_DECI; + } + + /* level 5 interrupt triggered only on CDC /INT falling edge with interrupt enabled on gate-array side */ + if (!cdc.irq && (scd.regs[0x32>>1].byte.l & 0x20)) { + /* pending level 5 interrupt */ + scd.pending |= (1 << 5); + /* update IRQ level */ s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1); } + + /* update CDC IRQ state */ + cdc.irq |= BIT_DTEI; } /* set EDT bit (gate-array register $04) */ @@ -372,7 +388,7 @@ void cdc_dma_init(void) 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; + int dma_bytes = (cycles - cdc.cycles[0] + DMA_CYCLES_PER_BYTE - 1) / DMA_CYCLES_PER_BYTE; /* always process blocks of 8 bytes */ dma_bytes = (dma_bytes / 8) * 8; @@ -383,6 +399,9 @@ void cdc_dma_update(unsigned int cycles) /* transfer remaining bytes using DMA */ cdc.dma_w(cdc.dbc.w + 1); + /* update DMA cycle counter */ + cdc.cycles[0] += (cdc.dbc.w + 1) * DMA_CYCLES_PER_BYTE; + /* reset data byte counter (DBCH bits 4-7 should also be set to 1) */ cdc.dbc.w = 0xffff; @@ -395,15 +414,28 @@ void cdc_dma_update(unsigned int cycles) /* Data Transfer End interrupt enabled ? */ if (cdc.ifctrl & BIT_DTEIEN) { - /* pending level 5 interrupt */ - scd.pending |= (1 << 5); + /* check end of CDC decoder active period */ + if ((cdc.irq & BIT_DECI) && (cdc.cycles[0] > cdc.cycles[1])) + { + /* clear pending decoder interrupt */ + cdc.ifstat |= BIT_DECI; - /* level 5 interrupt enabled ? */ - if (scd.regs[0x32>>1].byte.l & 0x20) + /* update CDC IRQ state */ + cdc.irq &= ~BIT_DECI; + } + + /* level 5 interrupt triggered only on CDC /INT falling edge with interrupt enabled on gate-array side*/ + if (!cdc.irq && (scd.regs[0x32>>1].byte.l & 0x20)) { + /* pending level 5 interrupt */ + scd.pending |= (1 << 5); + /* update IRQ level */ s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1); } + + /* update CDC IRQ state */ + cdc.irq |= BIT_DTEI; } /* clear DSR bit & set EDT bit (CD register $04) */ @@ -413,7 +445,7 @@ void cdc_dma_update(unsigned int cycles) if (s68k.stopped & (1<<0x04)) { /* sync SUB-CPU with CDC DMA */ - s68k.cycles = cdc.cycles; + s68k.cycles = cdc.cycles[0]; /* restart SUB-CPU */ s68k.stopped = 0; @@ -434,7 +466,7 @@ void cdc_dma_update(unsigned int cycles) cdc.dbc.w -= dma_bytes; /* update DMA cycle counter */ - cdc.cycles += dma_bytes * DMA_CYCLES_PER_BYTE; + cdc.cycles[0] += dma_bytes * DMA_CYCLES_PER_BYTE; } } @@ -452,18 +484,25 @@ void cdc_decoder_update(uint32 header) /* pending decoder interrupt */ cdc.ifstat &= ~BIT_DECI; + /* update CDC decoder end cycle (value adjusted for MCD-verificator CDC FLAGS Tests #40 & #41) */ + cdc.cycles[1] = s68k.cycles + 269000; + /* decoder interrupt enabled ? */ if (cdc.ifctrl & BIT_DECIEN) { - /* pending level 5 interrupt */ - scd.pending |= (1 << 5); - - /* level 5 interrupt enabled ? */ - if (scd.regs[0x32>>1].byte.l & 0x20) + /* level 5 interrupt triggered only on CDC /INT falling edge with interrupt enabled on gate-array side */ + /* note: only check DTEI as DECI is cleared automatically between decoder interrupt triggering */ + if (!(cdc.irq & BIT_DTEI) && (scd.regs[0x32>>1].byte.l & 0x20)) { + /* pending level 5 interrupt */ + scd.pending |= (1 << 5); + /* update IRQ level */ s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1); } + + /* update CDC IRQ state */ + cdc.irq |= BIT_DECI; } /* buffer RAM write enabled ? */ @@ -538,24 +577,27 @@ void cdc_reg_w(unsigned char data) { case 0x01: /* IFCTRL */ { - /* pending interrupts ? */ - if (((data & BIT_DTEIEN) && !(cdc.ifstat & BIT_DTEI)) || - ((data & BIT_DECIEN) && !(cdc.ifstat & BIT_DECI))) + /* previous CDC IRQ state */ + uint8 prev_irq = cdc.irq; + + /* check end of CDC decoder active period */ + if (s68k.cycles > cdc.cycles[1]) { - /* pending level 5 interrupt */ - scd.pending |= (1 << 5); + /* clear pending decoder interrupt */ + cdc.ifstat |= BIT_DECI; - /* 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); - } + /* update previous CDC IRQ state */ + prev_irq &= ~BIT_DECI; } - else if (scd.pending & (1 << 5)) + + /* update CDC IRQ state according to DTEIEN and DECIEN bits */ + cdc.irq = ~cdc.ifstat & data & (BIT_DTEIEN | BIT_DECIEN); + + /* level 5 interrupt is triggered on CDC /INT falling edge if interrupt enabled on gate-array side */ + if (cdc.irq && !prev_irq && (scd.regs[0x32>>1].byte.l & 0x20)) { - /* clear pending level 5 interrupts */ - scd.pending &= ~(1 << 5); + /* pending level 5 interrupt */ + scd.pending |= (1 << 5); /* update IRQ level */ s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1); @@ -606,7 +648,7 @@ void cdc_reg_w(unsigned char data) cdc_dma_init(); /* initialize DMA cycle counter */ - cdc.cycles = s68k.cycles; + cdc.cycles[0] = s68k.cycles; } break; @@ -617,17 +659,8 @@ void cdc_reg_w(unsigned char data) /* clear pending data transfer end interrupt */ cdc.ifstat |= BIT_DTEI; -#if 0 - /* no pending decoder interrupt ? */ - if ((cdc.ifstat | BIT_DECI) || !(cdc.ifctrl & BIT_DECIEN)) - { - /* clear pending level 5 interrupt */ - scd.pending &= ~(1 << 5); - - /* update IRQ level */ - s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1); - } -#endif + /* update CDC IRQ state */ + cdc.irq &= ~BIT_DTEI; break; } @@ -709,6 +742,16 @@ unsigned char cdc_reg_r(void) { case 0x01: /* IFSTAT */ { + /* check end of CDC decoder active period */ + if (s68k.cycles > cdc.cycles[1]) + { + /* clear pending decoder interrupt */ + cdc.ifstat |= BIT_DECI; + + /* update CDC IRQ state */ + cdc.irq &= ~BIT_DECI; + } + data = cdc.ifstat; break; } @@ -801,18 +844,8 @@ unsigned char cdc_reg_r(void) /* clear pending decoder interrupt */ cdc.ifstat |= BIT_DECI; -#if 0 - /* no pending data transfer end interrupt */ - if ((cdc.ifstat | BIT_DTEI) || !(cdc.ifctrl & BIT_DTEIEN)) - { - /* clear pending level 5 interrupt */ - scd.pending &= ~(1 << 5); - - /* update IRQ level */ - s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1); - } -#endif - + /* update CDC IRQ state */ + cdc.irq &= ~BIT_DECI; break; } @@ -880,15 +913,28 @@ unsigned short cdc_host_r(uint8 cpu_access) /* Data Transfer End interrupt enabled ? */ if (cdc.ifctrl & BIT_DTEIEN) { - /* pending level 5 interrupt */ - scd.pending |= (1 << 5); + /* check end of CDC decoder active period */ + if ((cdc.irq & BIT_DECI) && (cdc.cycles[0] > cdc.cycles[1])) + { + /* clear pending decoder interrupt */ + cdc.ifstat |= BIT_DECI; + + /* update CDC IRQ state */ + cdc.irq &= ~BIT_DECI; + } - /* level 5 interrupt enabled ? */ - if (scd.regs[0x32>>1].byte.l & 0x20) + /* level 5 interrupt triggered only on CDC /INT falling edge with interrupt enabled on gate-array side */ + if (!cdc.irq && (scd.regs[0x32>>1].byte.l & 0x20)) { + /* pending level 5 interrupt */ + scd.pending |= (1 << 5); + /* update IRQ level */ s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1); } + + /* update CDC IRQ state */ + cdc.irq |= BIT_DTEI; } /* set EDT bit (gate-array register $04) */ diff --git a/core/cd_hw/cdc.h b/core/cd_hw/cdc.h index 03193e2da..2ed7b35a6 100644 --- a/core/cd_hw/cdc.h +++ b/core/cd_hw/cdc.h @@ -55,11 +55,12 @@ typedef struct uint8 ctrl[2]; uint8 head[2][4]; uint8 stat[4]; - unsigned int cycles; + int cycles[2]; 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; + uint8 irq; /* invert of CDC /INT output */ } cdc_t; /* Function prototypes */ diff --git a/core/cd_hw/cdd.c b/core/cd_hw/cdd.c index 7a27c9800..24d04c905 100644 --- a/core/cd_hw/cdd.c +++ b/core/cd_hw/cdd.c @@ -2,7 +2,7 @@ * Genesis Plus * CD drive processor & CD-DA fader * - * Copyright (C) 2012-2023 Eke-Eke (Genesis Plus GX) + * Copyright (C) 2012-2024 Eke-Eke (Genesis Plus GX) * * Redistribution and use of this code or any derivative works are permitted * provided that the following conditions are met: @@ -1855,9 +1855,14 @@ void cdd_update(void) scd.regs[0x36>>1].byte.h = 0x01; } } + else + { + /* CDC decoder is still running while disc is not being read (fixes MCD-verificator CDC Flags Test #30) */ + cdc_decoder_update(0); + } /* scanning disc */ - else if (cdd.status == CD_SCAN) + if (cdd.status == CD_SCAN) { /* current track index */ int index = cdd.index; diff --git a/core/cd_hw/cdd.h b/core/cd_hw/cdd.h index 03f5b5416..f2f780026 100644 --- a/core/cd_hw/cdd.h +++ b/core/cd_hw/cdd.h @@ -2,7 +2,7 @@ * Genesis Plus * CD drive processor & CD-DA fader * - * Copyright (C) 2012-2023 Eke-Eke (Genesis Plus GX) + * Copyright (C) 2012-2024 Eke-Eke (Genesis Plus GX) * * Redistribution and use of this code or any derivative works are permitted * provided that the following conditions are met: diff --git a/core/cd_hw/scd.c b/core/cd_hw/scd.c index 24bdbd017..c9762db78 100644 --- a/core/cd_hw/scd.c +++ b/core/cd_hw/scd.c @@ -1988,9 +1988,11 @@ void scd_end_frame(unsigned int cycles) /* adjust Stopwatch counter for next frame (can be negative) */ scd.stopwatch += (ticks * TIMERS_SCYCLES_RATIO) - cycles; - /* adjust SUB-CPU & GPU cycle counters for next frame */ - s68k.cycles -= cycles; - gfx.cycles -= cycles; + /* adjust SUB-CPU, GPU and CDC cycle counters for next frame */ + s68k.cycles -= cycles; + gfx.cycles -= cycles; + cdc.cycles[0] -= cycles; + cdc.cycles[1] -= cycles; /* reset CPU registers polling */ m68k.poll.cycle = 0; @@ -2348,24 +2350,18 @@ int scd_68k_irq_ack(int level) error("INT ack level %d (%X)\n", level, s68k.pc); #endif -#if 0 - /* level 5 interrupt is normally acknowledged by CDC */ - if (level != 5) -#endif - { - /* clear pending interrupt flag */ - scd.pending &= ~(1 << level); + /* clear pending interrupt flag */ + scd.pending &= ~(1 << level); - /* level 2 interrupt acknowledge */ - if (level == 2) - { - /* clear IFL2 flag */ - scd.regs[0x00].byte.h &= ~0x01; - } - - /* update IRQ level */ - s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1); + /* level 2 interrupt acknowledge */ + if (level == 2) + { + /* clear IFL2 flag */ + scd.regs[0x00].byte.h &= ~0x01; } + /* update IRQ level */ + s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1); + return M68K_INT_ACK_AUTOVECTOR; } diff --git a/core/m68k/m68kops.h b/core/m68k/m68kops.h index a3db55827..f8e2b8731 100644 --- a/core/m68k/m68kops.h +++ b/core/m68k/m68kops.h @@ -1868,6 +1868,9 @@ static void m68k_op_addq_8_d(void) FLAG_Z = MASK_OUT_ABOVE_8(res); *r_dst = MASK_OUT_BELOW_8(*r_dst) | FLAG_Z; + + /* reset idle loop detection (fixes cases where instruction is used in tight counter incrementing loop) */ + m68ki_cpu.poll.detected = 0; } @@ -2028,6 +2031,9 @@ static void m68k_op_addq_16_d(void) FLAG_Z = MASK_OUT_ABOVE_16(res); *r_dst = MASK_OUT_BELOW_16(*r_dst) | FLAG_Z; + + /* reset idle loop detection (fixes cases where instruction is used in tight counter incrementing loop) */ + m68ki_cpu.poll.detected = 0; } @@ -2164,6 +2170,9 @@ static void m68k_op_addq_32_d(void) FLAG_Z = MASK_OUT_ABOVE_32(res); *r_dst = FLAG_Z; + + /* reset idle loop detection (fixes cases where instruction is used in tight counter incrementing loop) */ + m68ki_cpu.poll.detected = 0; } diff --git a/core/mem68k.c b/core/mem68k.c index a8c81cefe..b06004027 100644 --- a/core/mem68k.c +++ b/core/mem68k.c @@ -788,9 +788,9 @@ void ctrl_io_write_byte(unsigned int address, unsigned int data) cdc.halted_dma_w = 0; /* synchronize CDC DMA with MAIN-CPU (only if not already ahead) */ - if (cdc.cycles < cycles) + if (cdc.cycles[0] < cycles) { - cdc.cycles = cycles; + cdc.cycles[0] = cycles; } } } @@ -902,9 +902,9 @@ void ctrl_io_write_byte(unsigned int address, unsigned int data) cdc.halted_dma_w = 0; /* synchronize CDC DMA with MAIN-CPU (only if not already ahead) */ - if (cdc.cycles < cycles) + if (cdc.cycles[0] < cycles) { - cdc.cycles = cycles; + cdc.cycles[0] = cycles; } } @@ -1117,9 +1117,9 @@ void ctrl_io_write_word(unsigned int address, unsigned int data) cdc.halted_dma_w = 0; /* synchronize CDC DMA with MAIN-CPU (only if not already ahead) */ - if (cdc.cycles < cycles) + if (cdc.cycles[0] < cycles) { - cdc.cycles = cycles; + cdc.cycles[0] = cycles; } } } @@ -1241,9 +1241,9 @@ void ctrl_io_write_word(unsigned int address, unsigned int data) cdc.halted_dma_w = 0; /* synchronize CDC DMA with MAIN-CPU (only if not already ahead) */ - if (cdc.cycles < cycles) + if (cdc.cycles[0] < cycles) { - cdc.cycles = cycles; + cdc.cycles[0] = cycles; } } return;