spu: implement irq on dma
authornotaz <notasas@gmail.com>
Sat, 14 Oct 2023 16:18:01 +0000 (19:18 +0300)
committernotaz <notasas@gmail.com>
Sat, 14 Oct 2023 16:42:36 +0000 (19:42 +0300)
notaz/pcsx_rearmed#295

frontend/plugin.c
libpcsxcore/plugins.h
libpcsxcore/psxevents.c
libpcsxcore/psxevents.h
libpcsxcore/spu.c
libpcsxcore/spu.h
plugins/dfsound/dma.c
plugins/dfsound/externals.h
plugins/dfsound/spu.c

index a0942df..e9dbcac 100644 (file)
@@ -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);
index cb9b88a..d208665 100644 (file)
@@ -170,7 +170,7 @@ typedef unsigned short (CALLBACK* SPUreadRegister)(unsigned long, unsigned int);
 typedef void (CALLBACK* SPUwriteDMAMem)(unsigned short *, int, unsigned int);\r
 typedef void (CALLBACK* SPUreadDMAMem)(unsigned short *, int, unsigned int);\r
 typedef void (CALLBACK* SPUplayADPCMchannel)(xa_decode_t *, unsigned int, int);\r
-typedef void (CALLBACK* SPUregisterCallback)(void (CALLBACK *callback)(void));\r
+typedef void (CALLBACK* SPUregisterCallback)(void (CALLBACK *callback)(int));\r
 typedef void (CALLBACK* SPUregisterScheduleCb)(void (CALLBACK *callback)(unsigned int cycles_after));\r
 typedef struct {\r
        unsigned char PluginName[8];\r
index 06089f2..28c1b5d 100644 (file)
@@ -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,
 };
 
index 2f84a4a..1f1067e 100644 (file)
@@ -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
index 69d65be..56a1de3 100644 (file)
 #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);
 }
 
index 44a35d5..6b8699b 100644 (file)
@@ -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
index 1aebfce..13f9c26 100644 (file)
@@ -39,10 +39,10 @@ void CALLBACK SPUreadDMAMem(unsigned short *pusPSXMem, int iSize,
  unsigned int cycles)\r
 {\r
  unsigned int addr = spu.spuAddr, irq_addr = regAreaGet(H_SPUirqAddr) << 3;\r
- int i, irq;\r
+ int i, irq_after;\r
 \r
  do_samples_if_needed(cycles, 1, 2);\r
- irq = addr <= irq_addr && irq_addr < addr + iSize*2;\r
+ irq_after = (irq_addr - addr) & 0x7ffff;\r
 \r
  for(i = 0; i < iSize; i++)\r
  {\r
@@ -50,8 +50,10 @@ void CALLBACK SPUreadDMAMem(unsigned short *pusPSXMem, int iSize,
   addr += 2;\r
   addr &= 0x7fffe;\r
  }\r
- if (irq && (spu.spuCtrl & CTRL_IRQ))\r
+ if ((spu.spuCtrl & CTRL_IRQ) && irq_after < iSize * 2) {\r
   log_unhandled("rdma spu irq: %x/%x+%x\n", irq_addr, spu.spuAddr, iSize * 2);\r
+  spu.irqCallback(irq_after);\r
+ }\r
  spu.spuAddr = addr;\r
  set_dma_end(iSize, cycles);\r
 }\r
@@ -64,11 +66,11 @@ void CALLBACK SPUwriteDMAMem(unsigned short *pusPSXMem, int iSize,
  unsigned int cycles)\r
 {\r
  unsigned int addr = spu.spuAddr, irq_addr = regAreaGet(H_SPUirqAddr) << 3;\r
- int i, irq;\r
+ int i, irq_after;\r
  \r
  do_samples_if_needed(cycles, 1, 2);\r
+ irq_after = (irq_addr - addr) & 0x7ffff;\r
  spu.bMemDirty = 1;\r
- irq = addr <= irq_addr && irq_addr < addr + iSize*2;\r
 \r
  if (addr + iSize*2 < 0x80000)\r
  {\r
@@ -77,7 +79,6 @@ void CALLBACK SPUwriteDMAMem(unsigned short *pusPSXMem, int iSize,
  }\r
  else\r
  {\r
-  irq |= irq_addr < ((addr + iSize*2) & 0x7ffff);\r
   for (i = 0; i < iSize; i++)\r
   {\r
    *(unsigned short *)(spu.spuMemC + addr) = *pusPSXMem++;\r
@@ -85,10 +86,16 @@ void CALLBACK SPUwriteDMAMem(unsigned short *pusPSXMem, int iSize,
    addr &= 0x7fffe;\r
   }\r
  }\r
- if (irq && (spu.spuCtrl & CTRL_IRQ)) // unhandled because need to implement delay\r
-  log_unhandled("wdma spu irq: %x/%x+%x\n", irq_addr, spu.spuAddr, iSize * 2);\r
+ if ((spu.spuCtrl & CTRL_IRQ) && irq_after < iSize * 2) {\r
+  log_unhandled("wdma spu irq: %x/%x+%x (%u)\n",\r
+    irq_addr, spu.spuAddr, iSize * 2, irq_after);\r
+  // this should be consistent with psxdma.c timing\r
+  // might also need more delay like in set_dma_end()\r
+  spu.irqCallback(irq_after);\r
+ }\r
  spu.spuAddr = addr;\r
  set_dma_end(iSize, cycles);\r
 }\r
 \r
 ////////////////////////////////////////////////////////////////////////\r
+// vim:shiftwidth=1:expandtab\r
index d752acf..4f48c65 100644 (file)
@@ -241,7 +241,7 @@ typedef struct
 \r
  int           * SSumLR;\r
 \r
- void (CALLBACK *irqCallback)(void);   // func of main emu, called on spu irq\r
+ void (CALLBACK *irqCallback)(int);\r
  //void (CALLBACK *cddavCallback)(short, short);\r
  void (CALLBACK *scheduleCallback)(unsigned int);\r
 \r
index f29ca4f..057502e 100644 (file)
@@ -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;
 }