[Core/CD] improved accuracy of CDC interrupt processing (verified on real hardware, cf. Krikzz's mcd-verificator)

This commit is contained in:
ekeeke 2024-02-05 23:53:57 +01:00
parent 79bd0e7582
commit 90c9c730f0
7 changed files with 62 additions and 74 deletions

View File

@ -26,6 +26,7 @@ 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 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 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 DMA 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 emulation of mirrored memory areas
* improved savestate format * improved savestate format
* improved Sub-CPU synchronization with Main-CPU (fixes "Soul Star") * improved Sub-CPU synchronization with Main-CPU (fixes "Soul Star")

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 MiB

After

Width:  |  Height:  |  Size: 3.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 MiB

After

Width:  |  Height:  |  Size: 4.0 MiB

View File

@ -114,6 +114,9 @@ void cdc_reset(void)
/* disable CDC DMA */ /* disable CDC DMA */
cdc.dma_w = cdc.halted_dma_w = 0; cdc.dma_w = cdc.halted_dma_w = 0;
/* reset CDC IRQ state */
cdc.irq = 0;
/* clear any pending IRQ */ /* clear any pending IRQ */
if (scd.pending & (1 << 5)) if (scd.pending & (1 << 5))
{ {
@ -236,6 +239,8 @@ int cdc_context_load(uint8 *state)
break; break;
} }
cdc.irq = ~cdc.ifstat & cdc.ifctrl & (BIT_DTEIEN | BIT_DECIEN);
return bufferptr; return bufferptr;
} }
@ -285,15 +290,18 @@ void cdc_dma_init(void)
/* Data Transfer End interrupt enabled ? */ /* Data Transfer End interrupt enabled ? */
if (cdc.ifctrl & BIT_DTEIEN) if (cdc.ifctrl & BIT_DTEIEN)
{ {
/* pending level 5 interrupt */ /* level 5 interrupt triggered only on CDC /INT falling edge with interrupt enabled on gate-array side */
scd.pending |= (1 << 5); if (!cdc.irq && (scd.regs[0x32>>1].byte.l & 0x20))
/* level 5 interrupt enabled ? */
if (scd.regs[0x32>>1].byte.l & 0x20)
{ {
/* pending level 5 interrupt */
scd.pending |= (1 << 5);
/* update IRQ level */ /* update IRQ level */
s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1); 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) */ /* set EDT bit (gate-array register $04) */
@ -395,15 +403,18 @@ void cdc_dma_update(unsigned int cycles)
/* Data Transfer End interrupt enabled ? */ /* Data Transfer End interrupt enabled ? */
if (cdc.ifctrl & BIT_DTEIEN) if (cdc.ifctrl & BIT_DTEIEN)
{ {
/* pending level 5 interrupt */ /* level 5 interrupt triggered only on CDC /INT falling edge with interrupt enabled on gate-array side*/
scd.pending |= (1 << 5); if (!cdc.irq && (scd.regs[0x32>>1].byte.l & 0x20))
/* level 5 interrupt enabled ? */
if (scd.regs[0x32>>1].byte.l & 0x20)
{ {
/* pending level 5 interrupt */
scd.pending |= (1 << 5);
/* update IRQ level */ /* update IRQ level */
s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1); 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) */ /* clear DSR bit & set EDT bit (CD register $04) */
@ -455,15 +466,19 @@ void cdc_decoder_update(uint32 header)
/* decoder interrupt enabled ? */ /* decoder interrupt enabled ? */
if (cdc.ifctrl & BIT_DECIEN) if (cdc.ifctrl & BIT_DECIEN)
{ {
/* pending level 5 interrupt */ /* level 5 interrupt triggered only on CDC /INT falling edge with interrupt enabled on gate-array side */
scd.pending |= (1 << 5); /* 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))
/* level 5 interrupt enabled ? */
if (scd.regs[0x32>>1].byte.l & 0x20)
{ {
/* pending level 5 interrupt */
scd.pending |= (1 << 5);
/* update IRQ level */ /* update IRQ level */
s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1); s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);
} }
/* update CDC IRQ state */
cdc.irq |= BIT_DECI;
} }
/* buffer RAM write enabled ? */ /* buffer RAM write enabled ? */
@ -538,25 +553,18 @@ void cdc_reg_w(unsigned char data)
{ {
case 0x01: /* IFCTRL */ case 0x01: /* IFCTRL */
{ {
/* pending interrupts ? */ /* previous CDC IRQ state */
if (((data & BIT_DTEIEN) && !(cdc.ifstat & BIT_DTEI)) || uint8 prev_irq = cdc.irq;
((data & BIT_DECIEN) && !(cdc.ifstat & BIT_DECI)))
/* 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))
{ {
/* pending level 5 interrupt */ /* pending level 5 interrupt */
scd.pending |= (1 << 5); 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);
}
}
else if (scd.pending & (1 << 5))
{
/* clear pending level 5 interrupts */
scd.pending &= ~(1 << 5);
/* update IRQ level */ /* update IRQ level */
s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1); s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);
} }
@ -617,17 +625,8 @@ void cdc_reg_w(unsigned char data)
/* clear pending data transfer end interrupt */ /* clear pending data transfer end interrupt */
cdc.ifstat |= BIT_DTEI; cdc.ifstat |= BIT_DTEI;
#if 0 /* update CDC IRQ state */
/* no pending decoder interrupt ? */ cdc.irq &= ~BIT_DTEI;
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
break; break;
} }
@ -801,18 +800,8 @@ unsigned char cdc_reg_r(void)
/* clear pending decoder interrupt */ /* clear pending decoder interrupt */
cdc.ifstat |= BIT_DECI; cdc.ifstat |= BIT_DECI;
#if 0 /* update CDC IRQ state */
/* no pending data transfer end interrupt */ cdc.irq &= ~BIT_DECI;
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
break; break;
} }
@ -880,15 +869,18 @@ unsigned short cdc_host_r(uint8 cpu_access)
/* Data Transfer End interrupt enabled ? */ /* Data Transfer End interrupt enabled ? */
if (cdc.ifctrl & BIT_DTEIEN) if (cdc.ifctrl & BIT_DTEIEN)
{ {
/* pending level 5 interrupt */ /* level 5 interrupt triggered only on CDC /INT falling edge with interrupt enabled on gate-array side */
scd.pending |= (1 << 5); if (!cdc.irq && (scd.regs[0x32>>1].byte.l & 0x20))
/* level 5 interrupt enabled ? */
if (scd.regs[0x32>>1].byte.l & 0x20)
{ {
/* pending level 5 interrupt */
scd.pending |= (1 << 5);
/* update IRQ level */ /* update IRQ level */
s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1); 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) */ /* set EDT bit (gate-array register $04) */

View File

@ -60,6 +60,7 @@ typedef struct
void (*halted_dma_w)(unsigned int length); /* halted 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 ram[0x4000 + 2352]; /* 16K external RAM (with one block overhead to handle buffer overrun) */
uint8 ar_mask; uint8 ar_mask;
uint8 irq; /* invert of CDC /INT output */
} cdc_t; } cdc_t;
/* Function prototypes */ /* Function prototypes */

View File

@ -2343,24 +2343,18 @@ int scd_68k_irq_ack(int level)
error("INT ack level %d (%X)\n", level, s68k.pc); error("INT ack level %d (%X)\n", level, s68k.pc);
#endif #endif
#if 0 /* clear pending interrupt flag */
/* level 5 interrupt is normally acknowledged by CDC */ scd.pending &= ~(1 << level);
if (level != 5)
#endif /* level 2 interrupt acknowledge */
if (level == 2)
{ {
/* clear pending interrupt flag */ /* clear IFL2 flag */
scd.pending &= ~(1 << level); scd.regs[0x00].byte.h &= ~0x01;
/* 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);
} }
/* update IRQ level */
s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);
return M68K_INT_ACK_AUTOVECTOR; return M68K_INT_ACK_AUTOVECTOR;
} }