shithub: psxe

Download patch

ref: 69a1076197fd30228ab21b06961bc5d7b305ff79
parent: 9fc807ccb8c9aacbe22e81fbde9b052e1a9ebcee
author: allkern <lisandroaalarcon@gmail.com>
date: Sat Jul 22 07:46:45 EDT 2023

Implement CDROM DMA IRQs

Fix DICR writing

--- a/psx/dev/dma.c
+++ b/psx/dev/dma.c
@@ -99,25 +99,15 @@
         switch (offset) {
             case 0x70: log_error("DMA control write %08x", value); dma->dpcr = value; break;
             case 0x74: {
-                value &= 0x7fffffff;
+                // IRQ signal is read-only
+                value &= ~DICR_IRQSI;
 
-                uint32_t irqf = (dma->dicr >> 24) & 0x7f;
-                uint32_t irqfr = (value >> 24) & 0x7f;
+                // Reset flags
+                dma->dicr &= ~(value & DICR_FLAGS);
 
-                dma->dicr &= ~0x7f000000;
-
-                irqf &= ~irqfr;
-                irqf &= 0x7f;
-
-                dma->dicr |= irqf << 24;
-
-                if (dma->dicr & 0x00008000) {
-                    dma->dicr |= 0x80000000;
-
-                    psx_ic_irq(dma->ic, IC_DMA);
-                }
-                
-                log_error("DMA irqc    write %08x irqfr=%08x", value, irqfr);
+                // Write other fields
+                dma->dicr &= DICR_FLAGS;
+                dma->dicr |= value & (~DICR_FLAGS);
             } break;
 
             default: {
@@ -130,7 +120,9 @@
 void psx_dma_write16(psx_dma_t* dma, uint32_t offset, uint16_t value) {
     switch (offset) {
         default: {
-            log_error("Unhandled 16-bit DMA write at offset %08x (%04x)", offset, value);
+            log_fatal("Unhandled 16-bit DMA write at offset %08x (%04x)", offset, value);
+
+            exit(1);
         } break;
     }
 }
@@ -138,7 +130,9 @@
 void psx_dma_write8(psx_dma_t* dma, uint32_t offset, uint8_t value) {
     switch (offset) {
         default: {
-            log_error("Unhandled 8-bit DMA write at offset %08x (%02x)", offset, value);
+            log_fatal("Unhandled 8-bit DMA write at offset %08x (%02x)", offset, value);
+
+            exit(1);
         } break;
     }
 }
@@ -260,6 +254,13 @@
         BCR_SIZE(cdrom)
     );
 
+    log_fatal("DICR: force=%u, en=%02x, irqen=%u, flags=%02x",
+        (dma->dicr >> 15) & 1,
+        (dma->dicr >> 16) & 0x7f,
+        (dma->dicr >> 23) & 1,
+        (dma->dicr >> 24) & 0x7f
+    );
+
     uint32_t size = BCR_SIZE(cdrom) * BCR_BCNT(cdrom);
 
     if (!size) {
@@ -325,18 +326,6 @@
     dma->otc.chcr = 0;
     //dma->otc.chcr &= ~(CHCR_BUSY_MASK | CHCR_TRIG_MASK);
     dma->otc.bcr = 0;
-
-    // if (dma->dicr & 0x00400000) {
-    //     dma->dicr |= 0x40000000;
-
-    //     if ((dma->dicr & 0x8000) || ((dma->dicr & 0x800000) && (dma->dicr & 0x7f000000))) {
-    //         dma->dicr |= 0x80000000;
-
-    //         psx_ic_irq(dma->ic, IC_DMA);
-    //     } else {
-    //         dma->dicr &= 0x7fffffff;
-    //     }
-    // }
 }
 
 void psx_dma_update(psx_dma_t* dma, int cyc) {
@@ -344,23 +333,25 @@
         dma->cdrom_irq_delay -= cyc;
 
         if (dma->cdrom_irq_delay <= 0) {
-            if (dma->dicr & 0x00400000) {
-                dma->dicr |= 0x40000000;
+            if (dma->dicr & DICR_DMA3EN)
+                dma->dicr |= DICR_DMA3FL;
 
-                if ((dma->dicr & 0x8000) || ((dma->dicr & 0x800000) && (dma->dicr & 0x7f000000))) {
-                    dma->dicr |= 0x80000000;
-
-                    log_fatal("DMA IRQ!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
-
-                    psx_ic_irq(dma->ic, IC_DMA);
-                } else {
-                    dma->dicr &= 0x7fffffff;
-                }
-            }
-
             dma->cdrom_irq_delay = 0;
         }
     }
+
+    int prev_irq_signal = (dma->dicr & DICR_IRQSI) != 0;
+    int irq_on_flags = (dma->dicr & DICR_IRQEN) != 0;
+    int force_irq = (dma->dicr & DICR_FORCE) != 0;
+    int irq = (dma->dicr & DICR_FLAGS) != 0;
+
+    int irq_signal = force_irq || (irq && irq_on_flags);
+
+    if (irq_signal && !prev_irq_signal)
+        psx_ic_irq(dma->ic, IC_DMA);
+    
+    dma->dicr &= ~DICR_IRQSI;
+    dma->dicr |= irq_signal << 31;
 }
 
 void psx_dma_destroy(psx_dma_t* dma) {
--- a/psx/dev/dma.h
+++ b/psx/dev/dma.h
@@ -105,7 +105,34 @@
 #define BCR_SIZE(c) (dma->c.bcr & 0xffff)
 #define BCR_BCNT(c) ((dma->c.bcr >> 16) & 0xffff)
 
-#define DICR_FIRQ 0x00008000
-#define DICR_IRQE 0x00000000
+/*
+  0-5   Unknown  (read/write-able)
+  6-14  Not used (always zero)
+  15    Force IRQ (sets bit31)                        (0=None, 1=Force Bit31=1)
+  16-22 IRQ Enable setting bit24-30 upon DMA0..DMA6    (0=None, 1=Enable)
+  23    IRQ Enable setting bit31 when bit24-30=nonzero (0=None, 1=Enable)
+  24-30 IRQ Flags for DMA0..DMA6    (Write 1 to reset) (0=None, 1=IRQ)
+  31    IRQ Signal (0-to-1 triggers 1F801070h.bit3)    (0=None, 1=IRQ) (R)
+*/
+
+#define DICR_FORCE 0x00008000
+#define DICR_FLGEN 0x007f0000
+#define DICR_IRQEN 0x00800000
+#define DICR_FLAGS 0x7f000000
+#define DICR_IRQSI 0x80000000
+#define DICR_DMA0EN 0x00010000
+#define DICR_DMA1EN 0x00020000
+#define DICR_DMA2EN 0x00040000
+#define DICR_DMA3EN 0x00080000
+#define DICR_DMA4EN 0x00100000
+#define DICR_DMA5EN 0x00200000
+#define DICR_DMA6EN 0x00400000
+#define DICR_DMA0FL 0x01000000
+#define DICR_DMA1FL 0x02000000
+#define DICR_DMA2FL 0x04000000
+#define DICR_DMA3FL 0x08000000
+#define DICR_DMA4FL 0x10000000
+#define DICR_DMA5FL 0x20000000
+#define DICR_DMA6FL 0x40000000
 
 #endif
\ No newline at end of file
--