From c2eee46bfb8a3fde297735a8b115330498d442b4 Mon Sep 17 00:00:00 2001 From: notaz Date: Sat, 14 Oct 2023 19:18:01 +0300 Subject: [PATCH] spu: implement irq on dma notaz/pcsx_rearmed#295 --- frontend/plugin.c | 2 +- libpcsxcore/plugins.h | 2 +- libpcsxcore/psxevents.c | 1 + libpcsxcore/psxevents.h | 2 +- libpcsxcore/spu.c | 11 ++++++++++- libpcsxcore/spu.h | 3 ++- plugins/dfsound/dma.c | 23 +++++++++++++++-------- plugins/dfsound/externals.h | 2 +- plugins/dfsound/spu.c | 4 ++-- 9 files changed, 34 insertions(+), 16 deletions(-) diff --git a/frontend/plugin.c b/frontend/plugin.c index a0942df4..e9dbcacb 100644 --- a/frontend/plugin.c +++ b/frontend/plugin.c @@ -55,7 +55,7 @@ extern unsigned short CALLBACK SPUreadRegister(unsigned long, unsigned int); extern void CALLBACK SPUwriteDMAMem(unsigned short *, int, unsigned int); extern void CALLBACK SPUreadDMAMem(unsigned short *, int, unsigned int); extern void CALLBACK SPUplayADPCMchannel(void *, unsigned int, int); -extern void CALLBACK SPUregisterCallback(void (*cb)(void)); +extern void CALLBACK SPUregisterCallback(void (*cb)(int)); extern void CALLBACK SPUregisterScheduleCb(void (*cb)(unsigned int)); extern long CALLBACK SPUfreeze(unsigned int, void *, unsigned int); extern void CALLBACK SPUasync(unsigned int, unsigned int); diff --git a/libpcsxcore/plugins.h b/libpcsxcore/plugins.h index cb9b88a2..d2086656 100644 --- a/libpcsxcore/plugins.h +++ b/libpcsxcore/plugins.h @@ -170,7 +170,7 @@ typedef unsigned short (CALLBACK* SPUreadRegister)(unsigned long, unsigned int); typedef void (CALLBACK* SPUwriteDMAMem)(unsigned short *, int, unsigned int); typedef void (CALLBACK* SPUreadDMAMem)(unsigned short *, int, unsigned int); typedef void (CALLBACK* SPUplayADPCMchannel)(xa_decode_t *, unsigned int, int); -typedef void (CALLBACK* SPUregisterCallback)(void (CALLBACK *callback)(void)); +typedef void (CALLBACK* SPUregisterCallback)(void (CALLBACK *callback)(int)); typedef void (CALLBACK* SPUregisterScheduleCb)(void (CALLBACK *callback)(unsigned int cycles_after)); typedef struct { unsigned char PluginName[8]; diff --git a/libpcsxcore/psxevents.c b/libpcsxcore/psxevents.c index 06089f2e..28c1b5df 100644 --- a/libpcsxcore/psxevents.c +++ b/libpcsxcore/psxevents.c @@ -50,6 +50,7 @@ static irq_func * const irq_funcs[] = { [PSXINT_CDRLID] = cdrLidSeekInterrupt, [PSXINT_IRQ10] = irq10Interrupt, [PSXINT_SPU_UPDATE] = spuUpdate, + [PSXINT_SPU_IRQ] = spuDelayedIrq, [PSXINT_RCNT] = psxRcntUpdate, }; diff --git a/libpcsxcore/psxevents.h b/libpcsxcore/psxevents.h index 2f84a4a5..1f1067ef 100644 --- a/libpcsxcore/psxevents.h +++ b/libpcsxcore/psxevents.h @@ -10,7 +10,7 @@ enum { PSXINT_GPUDMA, // gpuInterrupt PSXINT_MDECOUTDMA, // mdec1Interrupt PSXINT_SPUDMA, // spuInterrupt - PSXINT_UNUSED, // + PSXINT_SPU_IRQ, // spuDelayedIrq PSXINT_MDECINDMA, // mdec0Interrupt PSXINT_GPUOTCDMA, // gpuotcInterrupt PSXINT_CDRDMA, // cdrDmaInterrupt diff --git a/libpcsxcore/spu.c b/libpcsxcore/spu.c index 69d65bef..56a1de3b 100644 --- a/libpcsxcore/spu.c +++ b/libpcsxcore/spu.c @@ -24,7 +24,16 @@ #include "spu.h" #include "psxevents.h" -void CALLBACK SPUirq(void) { +void CALLBACK SPUirq(int cycles_after) { + if (cycles_after > 0) { + set_event(PSXINT_SPU_IRQ, cycles_after); + return; + } + + psxHu32ref(0x1070) |= SWAPu32(0x200); +} + +void spuDelayedIrq() { psxHu32ref(0x1070) |= SWAPu32(0x200); } diff --git a/libpcsxcore/spu.h b/libpcsxcore/spu.h index 44a35d5f..6b8699b9 100644 --- a/libpcsxcore/spu.h +++ b/libpcsxcore/spu.h @@ -39,8 +39,9 @@ extern "C" { #define H_SPUoff1 0x0d8c #define H_SPUoff2 0x0d8e -void CALLBACK SPUirq(void); +void CALLBACK SPUirq(int cycles_after); void CALLBACK SPUschedule(unsigned int cycles_after); +void spuDelayedIrq(); void spuUpdate(); #ifdef __cplusplus diff --git a/plugins/dfsound/dma.c b/plugins/dfsound/dma.c index 1aebfce5..13f9c269 100644 --- a/plugins/dfsound/dma.c +++ b/plugins/dfsound/dma.c @@ -39,10 +39,10 @@ void CALLBACK SPUreadDMAMem(unsigned short *pusPSXMem, int iSize, unsigned int cycles) { unsigned int addr = spu.spuAddr, irq_addr = regAreaGet(H_SPUirqAddr) << 3; - int i, irq; + int i, irq_after; do_samples_if_needed(cycles, 1, 2); - irq = addr <= irq_addr && irq_addr < addr + iSize*2; + irq_after = (irq_addr - addr) & 0x7ffff; for(i = 0; i < iSize; i++) { @@ -50,8 +50,10 @@ void CALLBACK SPUreadDMAMem(unsigned short *pusPSXMem, int iSize, addr += 2; addr &= 0x7fffe; } - if (irq && (spu.spuCtrl & CTRL_IRQ)) + if ((spu.spuCtrl & CTRL_IRQ) && irq_after < iSize * 2) { log_unhandled("rdma spu irq: %x/%x+%x\n", irq_addr, spu.spuAddr, iSize * 2); + spu.irqCallback(irq_after); + } spu.spuAddr = addr; set_dma_end(iSize, cycles); } @@ -64,11 +66,11 @@ void CALLBACK SPUwriteDMAMem(unsigned short *pusPSXMem, int iSize, unsigned int cycles) { unsigned int addr = spu.spuAddr, irq_addr = regAreaGet(H_SPUirqAddr) << 3; - int i, irq; + int i, irq_after; do_samples_if_needed(cycles, 1, 2); + irq_after = (irq_addr - addr) & 0x7ffff; spu.bMemDirty = 1; - irq = addr <= irq_addr && irq_addr < addr + iSize*2; if (addr + iSize*2 < 0x80000) { @@ -77,7 +79,6 @@ void CALLBACK SPUwriteDMAMem(unsigned short *pusPSXMem, int iSize, } else { - irq |= irq_addr < ((addr + iSize*2) & 0x7ffff); for (i = 0; i < iSize; i++) { *(unsigned short *)(spu.spuMemC + addr) = *pusPSXMem++; @@ -85,10 +86,16 @@ void CALLBACK SPUwriteDMAMem(unsigned short *pusPSXMem, int iSize, addr &= 0x7fffe; } } - if (irq && (spu.spuCtrl & CTRL_IRQ)) // unhandled because need to implement delay - log_unhandled("wdma spu irq: %x/%x+%x\n", irq_addr, spu.spuAddr, iSize * 2); + if ((spu.spuCtrl & CTRL_IRQ) && irq_after < iSize * 2) { + log_unhandled("wdma spu irq: %x/%x+%x (%u)\n", + irq_addr, spu.spuAddr, iSize * 2, irq_after); + // this should be consistent with psxdma.c timing + // might also need more delay like in set_dma_end() + spu.irqCallback(irq_after); + } spu.spuAddr = addr; set_dma_end(iSize, cycles); } //////////////////////////////////////////////////////////////////////// +// vim:shiftwidth=1:expandtab diff --git a/plugins/dfsound/externals.h b/plugins/dfsound/externals.h index d752acf2..4f48c65d 100644 --- a/plugins/dfsound/externals.h +++ b/plugins/dfsound/externals.h @@ -241,7 +241,7 @@ typedef struct int * SSumLR; - void (CALLBACK *irqCallback)(void); // func of main emu, called on spu irq + void (CALLBACK *irqCallback)(int); //void (CALLBACK *cddavCallback)(short, short); void (CALLBACK *scheduleCallback)(unsigned int); diff --git a/plugins/dfsound/spu.c b/plugins/dfsound/spu.c index f29ca4fa..057502e4 100644 --- a/plugins/dfsound/spu.c +++ b/plugins/dfsound/spu.c @@ -203,7 +203,7 @@ static void do_irq(void) //if(!(spu.spuStat & STAT_IRQ)) { spu.spuStat |= STAT_IRQ; // asserted status? - if(spu.irqCallback) spu.irqCallback(); + if(spu.irqCallback) spu.irqCallback(0); } } @@ -1602,7 +1602,7 @@ long CALLBACK SPUshutdown(void) // SETUP CALLBACKS // this functions will be called once, // passes a callback that should be called on SPU-IRQ/cdda volume change -void CALLBACK SPUregisterCallback(void (CALLBACK *callback)(void)) +void CALLBACK SPUregisterCallback(void (CALLBACK *callback)(int)) { spu.irqCallback = callback; } -- 2.39.2