shithub: psxe

Download patch

ref: 854e59a15b1df3aa4525310436d175b6aea58709
parent: c24fbe43df2a63e990814887986b8744e43aab66
author: allkern <lisandroaalarcon@gmail.com>
date: Wed Aug 23 13:11:08 EDT 2023

Improve OTC DMA emulation

Passing all OTC DMA tests

--- a/psx/dev/dma.c
+++ b/psx/dev/dma.c
@@ -10,6 +10,18 @@
     return (psx_dma_t*)malloc(sizeof(psx_dma_t));
 }
 
+const uint32_t g_psx_dma_ctrl_hw_1_table[] = {
+    0x00000000, 0x00000000, 0x00000000,
+    0x00000000, 0x00000000, 0x00000000,
+    0x00000002
+};
+
+const uint32_t g_psx_dma_ctrl_hw_0_table[] = {
+    0x71770703, 0x71770703, 0x71770703,
+    0x71770703, 0x71770703, 0x71770703,
+    0x50000002
+};
+
 const psx_dma_do_fn_t g_psx_dma_do_table[] = {
     psx_dma_do_mdec_in,
     psx_dma_do_mdec_out,
@@ -32,7 +44,6 @@
     dma->ic = ic;
 
     dma->dpcr = 0x07654321;
-    dma->otc.chcr = 0x00000002;
 }
 
 uint32_t psx_dma_read32(psx_dma_t* dma, uint32_t offset) {
@@ -39,10 +50,16 @@
     if (offset < 0x70) {
         int channel = (offset >> 4) & 0x7;
         int reg = (offset >> 2) & 0x3;
+        uint32_t cr = CR(channel, reg);
 
-        log_error("DMA channel %u register %u (%08x) read %08x", channel, reg, PSX_DMAR_BEGIN + offset, (CR(channel, reg)));
+        if (reg == 2) {
+            cr |= g_psx_dma_ctrl_hw_1_table[channel];
+            cr &= g_psx_dma_ctrl_hw_0_table[channel];
+        }
+
+        log_error("DMA channel %u register %u (%08x) read %08x", channel, reg, PSX_DMAR_BEGIN + offset, cr);
         
-        return CR(channel, reg);
+        return cr;
     } else {
         switch (offset) {
             case 0x70: log_error("DMA control read %08x", dma->dpcr); return dma->dpcr;
@@ -92,9 +109,8 @@
 
         log_error("DMA channel %u register %u write (%08x) %08x", channel, reg, PSX_DMAR_BEGIN + offset, value);
 
-        if (reg == 2) {
+        if (reg == 2)
             g_psx_dma_do_table[channel](dma);
-        }
     } else {
         switch (offset) {
             case 0x70: log_error("DMA control write %08x", value); dma->dpcr = value; break;
@@ -351,10 +367,22 @@
 }
 
 void psx_dma_do_otc(psx_dma_t* dma) {
-    if (!CHCR_TRIG(otc))
+    if ((!(dma->dpcr & DPCR_DMA6EN)) || (!CHCR_TRIG(otc)) || (!CHCR_BUSY(otc)))
         return;
+    
+    log_fatal("OTC DMA transfer: madr=%08x, dir=%s, sync=%s, step=%s, size=%x",
+        dma->otc.madr,
+        CHCR_TDIR(otc) ? "to device" : "to RAM",
+        CHCR_SYNC(otc) ? "other" : "burst",
+        CHCR_STEP(otc) ? "decrementing" : "incrementing",
+        BCR_SIZE(otc)
+    );
 
-    for (int i = BCR_SIZE(otc); i > 0; i--) {
+    uint32_t size = BCR_SIZE(otc);
+
+    if (!size) size = 0x10000;
+
+    for (int i = size; i > 0; i--) {
         uint32_t addr = (i != 1) ? (dma->otc.madr - 4) : 0xffffff;
 
         psx_bus_write32(dma->bus, dma->otc.madr, addr & 0xffffff);
@@ -387,7 +415,7 @@
 
     if (dma->gpu_irq_delay) {
         if (dma->dicr & DICR_DMA2EN)
-                dma->dicr |= DICR_DMA2FL;
+            dma->dicr |= DICR_DMA2FL;
 
         dma->gpu_irq_delay = 0;
     }
--- a/psx/dev/dma.h
+++ b/psx/dev/dma.h
@@ -61,6 +61,33 @@
 typedef void (*psx_dma_do_fn_t)(psx_dma_t*);
 
 /*
+  0-2   DMA0, MDECin  Priority      (0..7; 0=Highest, 7=Lowest)
+  3     DMA0, MDECin  Master Enable (0=Disable, 1=Enable)
+  4-6   DMA1, MDECout Priority      (0..7; 0=Highest, 7=Lowest)
+  7     DMA1, MDECout Master Enable (0=Disable, 1=Enable)
+  8-10  DMA2, GPU     Priority      (0..7; 0=Highest, 7=Lowest)
+  11    DMA2, GPU     Master Enable (0=Disable, 1=Enable)
+  12-14 DMA3, CDROM   Priority      (0..7; 0=Highest, 7=Lowest)
+  15    DMA3, CDROM   Master Enable (0=Disable, 1=Enable)
+  16-18 DMA4, SPU     Priority      (0..7; 0=Highest, 7=Lowest)
+  19    DMA4, SPU     Master Enable (0=Disable, 1=Enable)
+  20-22 DMA5, PIO     Priority      (0..7; 0=Highest, 7=Lowest)
+  23    DMA5, PIO     Master Enable (0=Disable, 1=Enable)
+  24-26 DMA6, OTC     Priority      (0..7; 0=Highest, 7=Lowest)
+  27    DMA6, OTC     Master Enable (0=Disable, 1=Enable)
+  28-30 Unknown, Priority Offset or so? (R/W)
+  31    Unknown, no effect? (R/W)
+*/
+
+#define DPCR_DMA0EN 0x00000008
+#define DPCR_DMA1EN 0x00000080
+#define DPCR_DMA2EN 0x00000800
+#define DPCR_DMA3EN 0x00008000
+#define DPCR_DMA4EN 0x00080000
+#define DPCR_DMA5EN 0x00800000
+#define DPCR_DMA6EN 0x08000000
+
+/*
   0       Transfer Direction    (0=To Main RAM, 1=From Main RAM)
   1       Memory Address Step   (0=Forward;+4, 1=Backward;-4)
   2-7     Not used              (always zero)
--