[Core/CD] improved Timer interrupt timings and CDD interrupt accuracy (fixes audio stutters during Popful Mail FMV)

This commit is contained in:
ekeeke 2020-04-14 15:51:38 +02:00
parent 33a43e34c1
commit e66b7bc83d
5 changed files with 69 additions and 73 deletions

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 MiB

After

Width:  |  Height:  |  Size: 3.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 MiB

After

Width:  |  Height:  |  Size: 3.9 MiB

View File

@ -2,7 +2,7 @@
* Genesis Plus * Genesis Plus
* Mega CD / Sega CD hardware * Mega CD / Sega CD hardware
* *
* Copyright (C) 2012-2019 Eke-Eke (Genesis Plus GX) * Copyright (C) 2012-2020 Eke-Eke (Genesis Plus GX)
* *
* Redistribution and use of this code or any derivative works are permitted * Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met: * provided that the following conditions are met:
@ -992,28 +992,6 @@ static void scd_write_byte(unsigned int address, unsigned int data)
return; return;
} }
case 0x37: /* CDD control (controlled by BIOS, byte access only ?) */
{
/* CDD communication started ? */
if ((data & 0x04) && !(scd.regs[0x37>>1].byte.l & 0x04))
{
/* reset CDD cycle counter */
cdd.cycles = (scd.cycles - s68k.cycles) * 3;
/* set pending interrupt level 4 */
scd.pending |= (1 << 4);
/* update IRQ level if interrupt is enabled */
if (scd.regs[0x32>>1].byte.l & 0x10)
{
s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);
}
}
scd.regs[0x37>>1].byte.l = data;
return;
}
default: default:
{ {
/* SUB-CPU communication words */ /* SUB-CPU communication words */
@ -1668,6 +1646,10 @@ void scd_reset(int hard)
void scd_update(unsigned int cycles) void scd_update(unsigned int cycles)
{ {
int m68k_end_cycles;
int s68k_run_cycles;
int s68k_end_cycles = scd.cycles + SCYCLES_PER_LINE;
/* update CDC DMA transfer */ /* update CDC DMA transfer */
if (cdc.dma_w) if (cdc.dma_w)
{ {
@ -1677,63 +1659,77 @@ void scd_update(unsigned int cycles)
/* run both CPU in sync until end of line */ /* run both CPU in sync until end of line */
do do
{ {
m68k_run(cycles); /* CD hardware remaining cycles until end of line */
s68k_run(scd.cycles + SCYCLES_PER_LINE); s68k_run_cycles = s68k_end_cycles - scd.cycles;
}
while ((m68k.cycles < cycles) || (s68k.cycles < (scd.cycles + SCYCLES_PER_LINE)));
/* increment CD hardware cycle counter */ /* check Timer interrupt occurence */
scd.cycles += SCYCLES_PER_LINE; if ((scd.timer > 0) && (scd.timer < s68k_run_cycles))
/* CDD processing at 75Hz (one clock = 12500000/75 = 500000/3 CPU clocks) */
cdd.cycles += (SCYCLES_PER_LINE * 3);
if (cdd.cycles >= (500000 * 4))
{
/* reload CDD cycle counter */
cdd.cycles -= (500000 * 4);
/* update CDD sector */
cdd_update();
/* check if a new CDD command has been processed */
if (!(scd.regs[0x4a>>1].byte.l & 0xf0))
{ {
/* reset CDD command wait flag */ /* adjust Sub-CPU and Main-CPU end cycle counters up to Timer interrupt occurence */
scd.regs[0x4a>>1].byte.l = 0xf0; s68k_run_cycles = scd.timer;
m68k_end_cycles = mcycles_vdp + ((s68k_run_cycles * MCYCLES_PER_LINE) / SCYCLES_PER_LINE);
}
else
{
/* default Main-CPU end cycle counter (end of line) */
m68k_end_cycles = cycles;
}
/* pending level 4 interrupt */ /* run both CPU in sync until required cycle counters */
scd.pending |= (1 << 4); m68k_run(m68k_end_cycles);
s68k_run(scd.cycles + s68k_run_cycles);
/* level 4 interrupt enabled */ /* increment CD hardware cycle counter */
if (scd.regs[0x32>>1].byte.l & 0x10) scd.cycles += s68k_run_cycles;
/* CDD processing at 75Hz (one clock = 12500000/75 = 500000/3 CPU clocks) */
cdd.cycles += (s68k_run_cycles * 3);
if (cdd.cycles >= (500000 * 4))
{
/* reload CDD cycle counter */
cdd.cycles -= (500000 * 4);
/* update CDD sector */
cdd_update();
/* check if CDD communication is enabled */
if (scd.regs[0x37>>1].byte.l & 0x04)
{ {
/* update IRQ level */ /* pending level 4 interrupt */
s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1); scd.pending |= (1 << 4);
}
} /* level 4 interrupt enabled */
} if (scd.regs[0x32>>1].byte.l & 0x10)
{
/* Timer */ /* update IRQ level */
if (scd.timer) s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);
{ }
/* decrement timer */ }
scd.timer -= SCYCLES_PER_LINE; }
if (scd.timer <= 0)
{ /* Timer */
/* reload timer (one timer clock = 384 CPU cycles) */ if (scd.timer)
scd.timer += (scd.regs[0x30>>1].byte.l * TIMERS_SCYCLES_RATIO); {
/* decrement timer */
/* level 3 interrupt enabled ? */ scd.timer -= s68k_run_cycles;
if (scd.regs[0x32>>1].byte.l & 0x08) if (scd.timer <= 0)
{ {
/* trigger level 3 interrupt */ /* reload timer (one timer clock = 384 CPU cycles) */
scd.pending |= (1 << 3); scd.timer += (scd.regs[0x30>>1].byte.l * TIMERS_SCYCLES_RATIO);
/* update IRQ level */ /* level 3 interrupt enabled ? */
s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1); if (scd.regs[0x32>>1].byte.l & 0x08)
{
/* trigger level 3 interrupt */
scd.pending |= (1 << 3);
/* update IRQ level */
s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);
}
} }
} }
} }
while ((m68k.cycles < cycles) || (s68k.cycles < s68k_end_cycles));
/* GFX processing */ /* GFX processing */
if (scd.regs[0x58>>1].byte.h & 0x80) if (scd.regs[0x58>>1].byte.h & 0x80)

View File

@ -2,7 +2,7 @@
* Genesis Plus * Genesis Plus
* Mega CD / Sega CD hardware * Mega CD / Sega CD hardware
* *
* Copyright (C) 2012-2019 Eke-Eke (Genesis Plus GX) * Copyright (C) 2012-2020 Eke-Eke (Genesis Plus GX)
* *
* Redistribution and use of this code or any derivative works are permitted * Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met: * provided that the following conditions are met: