shithub: psxe

Download patch

ref: b81987ecacac88d3cfeea1f094be08b3fec2b068
parent: 2e6491c20b71356eb4450b1180a6a11fb1df13bb
author: allkern <lisandroaalarcon@gmail.com>
date: Mon Jul 24 12:37:04 EDT 2023

Several improvements

--- a/psx/dev/cdrom.c
+++ b/psx/dev/cdrom.c
@@ -306,8 +306,58 @@
 }
 void cdrom_cmd_getlocl(psx_cdrom_t* cdrom) { log_fatal("getlocl: Unimplemented"); exit(1); }
 void cdrom_cmd_getlocp(psx_cdrom_t* cdrom) { log_fatal("getlocp: Unimplemented"); exit(1); }
-void cdrom_cmd_gettn(psx_cdrom_t* cdrom) { log_fatal("gettn: Unimplemented"); exit(1); }
-void cdrom_cmd_gettd(psx_cdrom_t* cdrom) { log_fatal("gettd: Unimplemented"); exit(1); }
+void cdrom_cmd_gettn(psx_cdrom_t* cdrom) {
+    switch (cdrom->state) {
+        case CD_STATE_CMD: {
+            if (cdrom->pfifo_index) {
+                log_fatal("CdlGetTN: Expected exactly 0 parameters");
+
+                return;
+            }
+
+            cdrom->irq_delay = DELAY_1MS;
+            cdrom->delayed_command = CDL_GETTN;
+            cdrom->state = CD_STATE_RESP1;
+        } break;
+
+        case CD_STATE_RESP1: {
+            SET_BITS(ifr, IFR_INT, IFR_INT3);
+            RESP_PUSH(0x14);
+            RESP_PUSH(0x01);
+            RESP_PUSH(cdrom->stat);
+
+            cdrom->delayed_command = CDL_NONE;
+            cdrom->state = CD_STATE_CMD;
+        } break;
+    }
+}
+void cdrom_cmd_gettd(psx_cdrom_t* cdrom) {
+    switch (cdrom->state) {
+        case CD_STATE_CMD: {
+            if (cdrom->pfifo_index != 1) {
+                log_fatal("CdlGetTD: Expected exactly 0 parameters");
+
+                return;
+            }
+
+            int track = PFIFO_POP;
+
+            cdrom->irq_delay = DELAY_1MS;
+            cdrom->delayed_command = CDL_GETTD;
+            cdrom->state = CD_STATE_RESP1;
+        } break;
+
+        case CD_STATE_RESP1: {
+            SET_BITS(ifr, IFR_INT, IFR_INT3);
+            RESP_PUSH(0x14);
+            RESP_PUSH(0x01);
+            RESP_PUSH(cdrom->stat);
+
+            cdrom->delayed_command = CDL_NONE;
+            cdrom->state = CD_STATE_CMD;
+        } break;
+    }
+}
 void cdrom_cmd_seekl(psx_cdrom_t* cdrom) {
     switch (cdrom->state) {
         case CD_STATE_CMD: {
@@ -427,7 +477,58 @@
         } break;
     }
 }
-void cdrom_cmd_reads(psx_cdrom_t* cdrom) { log_fatal("reads: Unimplemented"); exit(1); }
+void cdrom_cmd_reads(psx_cdrom_t* cdrom) {
+    switch (cdrom->state) {
+        case CD_STATE_CMD: {
+            log_fatal("CdlReadS: CD_STATE_CMD");
+            cdrom->irq_delay = DELAY_1MS;
+            cdrom->state = CD_STATE_RESP1;
+            cdrom->delayed_command = CDL_READS;
+        } break;
+
+        case CD_STATE_RESP1: {
+            log_fatal("CdlReadS: CD_STATE_RESP1");
+
+            SET_BITS(ifr, IFR_INT, 3);
+            RESP_PUSH(GETSTAT_MOTOR);
+
+            fseek(cdrom->disc, cdrom->seek_offset, 0);
+
+            int double_speed = cdrom->mode & MODE_SPEED;
+
+            cdrom->irq_delay = double_speed ? READ_DOUBLE_DELAY : READ_SINGLE_DELAY;
+            cdrom->state = CD_STATE_RESP2;
+            cdrom->delayed_command = CDL_READS;
+
+            if (cdrom->spin_delay) {
+                cdrom->irq_delay += cdrom->spin_delay;
+                cdrom->spin_delay = 0;
+            }
+        } break;
+
+        case CD_STATE_RESP2: {
+            log_fatal("CdlReadS: CD_STATE_RESP2");
+
+            SET_BITS(ifr, IFR_INT, 1);
+            RESP_PUSH(GETSTAT_MOTOR | GETSTAT_READ);
+
+            log_fatal("Reading data from disc. offset=%02x:%02x:%02x (%08x, tellg=%08x)",
+                cdrom->seek_mm, cdrom->seek_ss, cdrom->seek_sect,
+                cdrom->seek_offset, ftell(cdrom->disc)
+            );
+
+            cdrom->dfifo_index = 0;
+
+            fread(cdrom->dfifo, 1, CD_SECTOR_SIZE, cdrom->disc);
+
+            int double_speed = cdrom->mode & MODE_SPEED;
+
+            cdrom->irq_delay = double_speed ? READ_DOUBLE_DELAY : READ_SINGLE_DELAY;
+            cdrom->state = CD_STATE_CMD;
+            cdrom->delayed_command = CDL_NONE;
+        } break;
+    }
+}
 void cdrom_cmd_readtoc(psx_cdrom_t* cdrom) { log_fatal("readtoc: Unimplemented"); exit(1); }
 
 typedef void (*cdrom_cmd_t)(psx_cdrom_t*);
--- a/psx/dev/dma.c
+++ b/psx/dev/dma.c
@@ -106,8 +106,11 @@
                 dma->dicr &= ~(value & DICR_FLAGS);
 
                 // Write other fields
-                dma->dicr &= DICR_FLAGS;
+                uint32_t flags = dma->dicr & DICR_FLAGS;
+
+                dma->dicr &= ~DICR_FLAGS;
                 dma->dicr |= value & (~DICR_FLAGS);
+                dma->dicr |= flags;
             } break;
 
             default: {
@@ -122,7 +125,7 @@
         default: {
             log_fatal("Unhandled 16-bit DMA write at offset %08x (%04x)", offset, value);
 
-            exit(1);
+            //exit(1);
         } break;
     }
 }
@@ -132,7 +135,7 @@
         default: {
             log_fatal("Unhandled 8-bit DMA write at offset %08x (%02x)", offset, value);
 
-            exit(1);
+            //exit(1);
         } break;
     }
 }
@@ -152,6 +155,8 @@
     uint32_t size = hdr >> 24;
     uint32_t addr = dma->gpu.madr;
 
+    int count = 0;
+
     while (true) {
         while (size--) {
             addr = (addr + (CHCR_STEP(gpu) ? -4 : 4)) & 0x1ffffc;
@@ -161,6 +166,8 @@
 
             // Write to GP0
             psx_bus_write32(dma->bus, 0x1f801810, cmd);
+
+            dma->gpu_irq_delay++;
         }
 
         addr = hdr & 0xffffff;
@@ -195,6 +202,8 @@
             dma->gpu.madr += CHCR_STEP(gpu) ? -4 : 4;
         }
     }
+
+    dma->gpu_irq_delay = size;
 }
 
 void psx_dma_do_gpu_burst(psx_dma_t* dma) {
@@ -249,7 +258,7 @@
         (dma->dicr >> 24) & 0x7f
     );
 
-    uint32_t size = BCR_SIZE(cdrom) * BCR_BCNT(cdrom);
+    uint32_t size = BCR_SIZE(cdrom);
 
     if (!size) {
         log_fatal("0 sized CDROM DMA");
@@ -310,23 +319,6 @@
     }
 
     dma->spu_irq_delay = size * 4;
-
-    if (!CHCR_TDIR(spu)) {
-        for (int i = 0; i < size; i++) {
-            uint32_t data = 0;
-            
-            data |= psx_bus_read8(dma->bus, 0x1f801802) << 0;
-            data |= psx_bus_read8(dma->bus, 0x1f801802) << 8;
-            data |= psx_bus_read8(dma->bus, 0x1f801802) << 16;
-            data |= psx_bus_read8(dma->bus, 0x1f801802) << 24;
-
-            psx_bus_write32(dma->bus, dma->spu.madr, data);
-
-            dma->spu.madr += CHCR_STEP(spu) ? -4 : 4;
-        }
-    } else {
-        log_fatal("Invalid SPU DMA transfer direction");
-    }
     
     // Clear BCR and CHCR trigger and busy bits
     dma->spu.chcr = 0;
@@ -358,6 +350,8 @@
         dma->otc.madr -= 4;
     }
 
+    dma->otc_irq_delay = BCR_SIZE(otc);
+
     // Clear BCR and CHCR trigger and busy bits
     dma->otc.chcr = 0;
     //dma->otc.chcr &= ~(CHCR_BUSY_MASK | CHCR_TRIG_MASK);
@@ -366,25 +360,31 @@
 
 void psx_dma_update(psx_dma_t* dma, int cyc) {
     if (dma->cdrom_irq_delay) {
-        dma->cdrom_irq_delay -= cyc;
+        if (dma->dicr & DICR_DMA3EN)
+            dma->dicr |= DICR_DMA3FL;
 
-        if (dma->cdrom_irq_delay <= 0) {
-            if (dma->dicr & DICR_DMA3EN)
-                dma->dicr |= DICR_DMA3FL;
-
-            dma->cdrom_irq_delay = 0;
-        }
+        dma->cdrom_irq_delay = 0;
     }
 
     if (dma->spu_irq_delay) {
-        dma->spu_irq_delay -= cyc;
+        if (dma->dicr & DICR_DMA4EN)
+            dma->dicr |= DICR_DMA4FL;
+        
+        dma->spu_irq_delay = 0;
+    }
 
-        if (dma->spu_irq_delay <= 0) {
-            if (dma->dicr & DICR_DMA4EN)
-                dma->dicr |= DICR_DMA4FL;
+    if (dma->gpu_irq_delay) {
+        if (dma->dicr & DICR_DMA2EN)
+                dma->dicr |= DICR_DMA2FL;
 
-            dma->spu_irq_delay = 0;
-        }
+        dma->gpu_irq_delay = 0;
+    }
+
+    if (dma->otc_irq_delay) {
+        if (dma->dicr & DICR_DMA6EN)
+            dma->dicr |= DICR_DMA6FL;
+
+        dma->otc_irq_delay = 0;
     }
 
     int prev_irq_signal = (dma->dicr & DICR_IRQSI) != 0;
--- a/psx/dev/dma.h
+++ b/psx/dev/dma.h
@@ -32,6 +32,8 @@
 
     int cdrom_irq_delay;
     int spu_irq_delay;
+    int gpu_irq_delay;
+    int otc_irq_delay;
 
     uint32_t dpcr;
     uint32_t dicr;
--- a/psx/dev/gpu.c
+++ b/psx/dev/gpu.c
@@ -62,6 +62,25 @@
                 gpu->c0_tsiz -= 2;
             }
 
+            if (gpu->gp1_10h_req) {
+                switch (gpu->gp1_10h_req & 7) {
+                    case 2: {
+                        data = ((gpu->texw_oy / 8) << 15) | ((gpu->texw_ox / 8) << 10) | ((gpu->texw_my / 8) << 5) | (gpu->texw_mx / 8);
+                    } break;
+                    case 3: {
+                        data = (gpu->draw_y1 << 10) | gpu->draw_x1;
+                    } break;
+                    case 4: {
+                        data = (gpu->draw_y2 << 10) | gpu->draw_x2;
+                    } break;
+                    case 5: {
+                        data = (gpu->off_y << 10) | gpu->off_x;
+                    } break;
+                }
+
+                gpu->gp1_10h_req = 0;
+            }
+
             return data;
         } break;
         case 0x04: return gpu->gpustat | 0x1c000000;
@@ -73,23 +92,15 @@
 }
 
 uint16_t psx_gpu_read16(psx_gpu_t* gpu, uint32_t offset) {
-    switch (offset) {
-        case 0x00: return 0xaaaa;
-        case 0x04: return gpu->gpustat;
-    }
+     log_fatal("Unhandled 16-bit GPU read at offset %08x", offset);
 
-    log_warn("Unhandled 16-bit GPU read at offset %08x", offset);
-
-    return 0x0;
+    exit(1);
 }
 
 uint8_t psx_gpu_read8(psx_gpu_t* gpu, uint32_t offset) {
-    switch (offset) {
-        case 0x00: return gpu->gpuread;
-        case 0x04: return gpu->gpustat;
-    }
+    log_fatal("Unhandled 8-bit GPU read at offset %08x", offset);
 
-    log_warn("Unhandled 8-bit GPU read at offset %08x", offset);
+    exit(1);
 
     return 0x0;
 }
@@ -445,6 +456,21 @@
                 gpu->ysiz = ((gpu->ysiz - 1) & 0x1ff) + 1;
                 gpu->tsiz = ((gpu->xsiz * gpu->ysiz) + 1) & 0xfffffffe;
                 gpu->addr = gpu->xpos + (gpu->ypos * 1024);
+
+                //log_set_quiet(0);
+
+                log_fatal("pos=(%u, %u), siz=(%u, %u), tsiz=%08x, addr=%08x",
+                    gpu->xpos, gpu->ypos,
+                    gpu->xsiz, gpu->ysiz,
+                    gpu->tsiz, gpu->addr
+                );
+
+                // system("pause > nul");
+
+                // if (gpu->event_cb_table[GPU_EVENT_VBLANK])
+                //     gpu->event_cb_table[GPU_EVENT_VBLANK](gpu);
+
+                //log_set_quiet(1);
             }
         } break;
 
@@ -815,6 +841,36 @@
     }
 }
 
+void gpu_cmd_80(psx_gpu_t* gpu) {
+    switch (gpu->state) {
+        case GPU_STATE_RECV_CMD: {
+            gpu->state = GPU_STATE_RECV_ARGS;
+            gpu->cmd_args_remaining = 3;
+        } break;
+
+        case GPU_STATE_RECV_ARGS: {
+            if (!gpu->cmd_args_remaining) {
+                gpu->state = GPU_STATE_RECV_DATA;
+
+                uint32_t srcx = gpu->buf[1] & 0xffff;
+                uint32_t srcy = gpu->buf[1] >> 16;
+                uint32_t dstx = gpu->buf[2] & 0xffff;
+                uint32_t dsty = gpu->buf[2] >> 16;
+                uint32_t xsiz = gpu->buf[3] & 0xffff;
+                uint32_t ysiz = gpu->buf[3] >> 16;
+
+                for (int y = 0; y < ysiz; y++) {
+                    for (int x = 0; x < xsiz; x++) {
+                        gpu->vram[(dstx + x) + (dsty + y) * 1024] = gpu->vram[(srcx + x) + (srcy + y) * 1024];
+                    }
+                }
+
+                gpu->state = GPU_STATE_RECV_CMD;
+            }
+        } break;
+    }
+}
+
 void psx_gpu_update_cmd(psx_gpu_t* gpu) {
     switch (gpu->buf[0] >> 24) {
         case 0x00: /* nop */ break;
@@ -833,6 +889,7 @@
         case 0x65: gpu_cmd_64(gpu); break;
         case 0x66: gpu_cmd_64(gpu); break;
         case 0x68: gpu_cmd_68(gpu); break;
+        case 0x80: gpu_cmd_80(gpu); break;
         case 0xa0: gpu_cmd_a0(gpu); break;
         case 0xc0: gpu_cmd_c0(gpu); break;
         case 0xe1: {
@@ -901,6 +958,11 @@
             uint8_t cmd = value >> 24;
 
             switch (cmd) {
+                case 0x04: {
+                    // log_set_quiet(0);
+                    // log_fatal("GP1(04h) !!!!!!!!!!!!!!!!!");
+                    // log_set_quiet(1);
+                } break;
                 case 0x08:
                     gpu->display_mode = value & 0xffffff;
 
@@ -908,23 +970,13 @@
                         gpu->event_cb_table[GPU_EVENT_DMODE](gpu);
                 break;
 
-                case 0x10:
-                     switch (value & 7) {
-                        case 2:
-                            gpu->gpuread = ((gpu->texw_oy / 8) << 15) | ((gpu->texw_ox / 8) << 10) | ((gpu->texw_my / 8) << 5) | (gpu->texw_mx / 8);
-                            break;
-                        case 3:
-                            gpu->gpuread = (gpu->draw_y1 << 10) | gpu->draw_x1;
-                            break;
-                        case 4:
-                            gpu->gpuread = (gpu->draw_y2 << 10) | gpu->draw_x2;
-                            break;
-                        case 5: // Drawing Offset
-                            gpu->gpuread = (gpu->off_y << 10) | gpu->off_x;
-                            break;
-                        default:
-                            break;
-                     }
+                case 0x10: {
+                    gpu->gp1_10h_req = value & 7;
+
+                    // log_set_quiet(0);
+                    // log_fatal("GP1(10h) %u !!!!!!!!!!!!!!!!!", value & 7);
+                    // log_set_quiet(1);
+                } break;
             }
 
             log_error("GP1(%02Xh) args=%06x", value >> 24, value & 0xffffff);
--- a/psx/dev/gpu.h
+++ b/psx/dev/gpu.h
@@ -78,6 +78,7 @@
     uint32_t c0_addr;
     int c0_xsiz, c0_ysiz;
     int c0_tsiz;
+    int gp1_10h_req;
 
     // GPU state
     uint32_t state;
--- a/psx/input/sda.c
+++ b/psx/input/sda.c
@@ -39,6 +39,13 @@
                 sda->tx_data = 0xff;
                 sda->state = SDA_STATE_WFR;
             }
+
+            // Memory card access
+            if (data == 0x81) {
+                sda->tx_data_ready = 1;
+                sda->tx_data = 0xff;
+                sda->state = SDA_STATE_WFR;
+            }
         } break;
 
         case SDA_STATE_WFR: {
@@ -45,6 +52,9 @@
             if (data == 'B') {
                 sda->tx_data = sda->model;
                 sda->state = SDA_STATE_TX_IDH;
+            } else if (data == 'R') {
+                sda->tx_data = 0xff;
+                sda->state = SDA_STATE_WFR;
             }
         } break;
 
--