shithub: psxe

Download patch

ref: 35e060d44959b30447b51c5a3ef2100124b61725
parent: 40fb4a3ae2f05f500cc3e1c0b5fc7031ce02b4ab
author: allkern <lisandroaalarcon@gmail.com>
date: Sun Jul 2 19:31:18 EDT 2023

Improve IRQ handling

--- a/psx/cpu.c
+++ b/psx/cpu.c
@@ -65,6 +65,25 @@
     psx_cpu_i_bltz   , psx_cpu_i_bgez   , psx_cpu_i_bltz   , psx_cpu_i_bgez
 };
 
+uint32_t g_psx_cpu_cop0_write_mask_table[] = {
+    0x00000000, // cop0r0-r2   - N/A
+    0x00000000, // cop0r0-r2   - N/A
+    0x00000000, // cop0r0-r2   - N/A
+    0xffffffff, // cop0r3      - BPC - Breakpoint on execute (R/W)
+    0x00000000, // cop0r4      - N/A
+    0xffffffff, // cop0r5      - BDA - Breakpoint on data access (R/W)
+    0x00000000, // cop0r6      - JUMPDEST - Randomly memorized jump address (R)
+    0xffc0f03f, // cop0r7      - DCIC - Breakpoint control (R/W)
+    0x00000000, // cop0r8      - BadVaddr - Bad Virtual Address (R)
+    0xffffffff, // cop0r9      - BDAM - Data Access breakpoint mask (R/W)
+    0x00000000, // cop0r10     - N/A
+    0xffffffff, // cop0r11     - BPCM - Execute breakpoint mask (R/W)
+    0xffffffff, // cop0r12     - SR - System status register (R/W)
+    0x00000300, // cop0r13     - CAUSE - (R)  Describes the most recently recognised exception
+    0x00000000, // cop0r14     - EPC - Return Address from Trap (R)
+    0x00000000  // cop0r15     - PRID - Processor ID (R)
+};
+
 #define OP ((cpu->buf[1] >> 26) & 0x3f)
 #define S ((cpu->buf[1] >> 21) & 0x1f)
 #define T ((cpu->buf[1] >> 16) & 0x1f)
@@ -326,6 +345,9 @@
         return;
     }
 
+    if (psx_cpu_check_irq(cpu))
+        return;
+
     psx_cpu_fetch(cpu);
 
     cpu->delay_slot = cpu->branch;
@@ -333,32 +355,20 @@
 
     g_psx_cpu_primary_table[OP](cpu);
 
-    if ((cpu->cop0_r[COP0_SR] & SR_IEC) && (cpu->cop0_r[COP0_CAUSE] & cpu->cop0_r[COP0_SR] & SR_IM2)) {
-        psx_cpu_exception(cpu, CAUSE_INT);
-    }
+    cpu->last_cycles = 2;
+    cpu->total_cycles += cpu->last_cycles;
 
-    cpu->last_cycles = 2 + psx_bus_get_access_cycles(cpu->bus);
-
     cpu->r[0] = 0;
 }
 
-void psx_cpu_check_irq(psx_cpu_t* cpu) {
-    if ((cpu->cop0_r[COP0_SR] & SR_IEC) && (cpu->cop0_r[COP0_CAUSE] & cpu->cop0_r[COP0_SR] & SR_IM2)) {
-        // log_fatal("(before) IRQ pc=%08x, epc=%08x, cause=%08x, sr=%08x, tc=%u (%08x), istat=%08x, imask=%08x, [0]=%08x, [1]=%08x",
-        //     cpu->pc,
-        //     cpu->cop0_r[COP0_EPC],
-        //     cpu->cop0_r[COP0_CAUSE],
-        //     cpu->cop0_r[COP0_SR],
-        //     cpu->total_cycles,
-        //     cpu->total_cycles,
-        //     psx_bus_read32(cpu->bus, 0x1F801070),
-        //     psx_bus_read32(cpu->bus, 0x1F801074),
-        //     cpu->buf[0],
-        //     cpu->buf[1]
-        // );
-
+int psx_cpu_check_irq(psx_cpu_t* cpu) {
+    if ((cpu->cop0_r[COP0_SR] & SR_IEC) && (cpu->cop0_r[COP0_SR] & cpu->cop0_r[COP0_CAUSE] & 0x00000700)) {
         psx_cpu_exception(cpu, CAUSE_INT);
+
+        return 1;
     }
+
+    return 0;
 }
 
 void psx_cpu_exception(psx_cpu_t* cpu, uint32_t cause) {
@@ -366,13 +376,18 @@
     cpu->cop0_r[COP0_CAUSE] &= 0xffffff80;
     cpu->cop0_r[COP0_CAUSE] |= cause;
 
+    if (cause == CAUSE_INT) {
+        cpu->cop0_r[COP0_EPC] = cpu->pc - 4;
+    } else {
+        cpu->cop0_r[COP0_EPC] = cpu->pc - 8;
+    }
+
     // If we're in a delay slot, set delay slot bit
     // on CAUSE
     if (cpu->delay_slot) {
-        cpu->cop0_r[COP0_EPC] = cpu->pc - 12;
+        cpu->cop0_r[COP0_EPC] -= 4;
         cpu->cop0_r[COP0_CAUSE] |= 0x80000000;
     } else {
-        cpu->cop0_r[COP0_EPC] = cpu->pc - 8;
         cpu->cop0_r[COP0_CAUSE] &= 0x7fffffff;
     }
 
@@ -1266,7 +1281,7 @@
 
     DO_PENDING_LOAD;
 
-    cpu->cop0_r[D] = t;
+    cpu->cop0_r[D] = t & g_psx_cpu_cop0_write_mask_table[D];
 }
 
 void psx_cpu_i_ctc0(psx_cpu_t* cpu) {
--- a/psx/cpu.h
+++ b/psx/cpu.h
@@ -161,7 +161,7 @@
 void psx_cpu_fetch(psx_cpu_t*);
 void psx_cpu_set_a_kcall_hook(psx_cpu_t*, psx_cpu_kcall_hook_t);
 void psx_cpu_set_b_kcall_hook(psx_cpu_t*, psx_cpu_kcall_hook_t);
-void psx_cpu_check_irq(psx_cpu_t*);
+int psx_cpu_check_irq(psx_cpu_t*);
 
 /*
     00h INT     Interrupt
--- a/psx/dev/gpu.c
+++ b/psx/dev/gpu.c
@@ -759,7 +759,7 @@
     if (gpu->line == GPU_SCANS_PER_VDRAW_NTSC) {
         // Disable Vblank for now
         // log_fatal("Vblank");
-        // psx_ic_irq(gpu->ic, IC_VBLANK);
+        psx_ic_irq(gpu->ic, IC_VBLANK);
     } else if (gpu->line == GPU_SCANS_PER_FRAME_NTSC) {
         gpu->line = 0;
     }
@@ -780,7 +780,7 @@
     //     Tick Hblank timer
 
     if (gpu->cycles >= (float)GPU_CYCLES_PER_SCANL_NTSC) {
-        gpu->cycles = 0;
+        gpu->cycles -= (float)GPU_CYCLES_PER_SCANL_NTSC;
 
         gpu_scanline_event(gpu);
     }
--- a/psx/dev/pad.c
+++ b/psx/dev/pad.c
@@ -42,7 +42,7 @@
 uint16_t psx_pad_read16(psx_pad_t* pad, uint32_t offset) {
     switch (offset) {
         // case 0: return 0x00;
-        // case 4: return 0x03;
+        case 4: return 0x05;
         // case 8: return pad->mode;
         case 10: return pad->ctrl;
         // case 14: return pad->baud;
--- a/psx/dev/timer.c
+++ b/psx/dev/timer.c
@@ -38,16 +38,16 @@
         return 0x000016b0;
     }
 
-    // int t = (offset >> 4) & 0x3;
-    // int r = offset & 0xf;
+    int t = (offset >> 4) & 0x3;
+    int r = offset & 0xf;
 
-    // if (r == 0) {
-    //     switch (t) {
-    //         case 0: return timer->t0_stub++;
-    //         case 1: return timer->t1_stub++;
-    //         case 2: return timer->t2_stub++;
-    //     }
-    // }
+    if (r == 0) {
+        switch (t) {
+            case 0: return timer->t0_stub++;
+            case 1: return timer->t1_stub++;
+            case 2: return timer->t2_stub++;
+        }
+    }
 
     log_fatal("Unhandled 16-bit TIMER read at offset %08x", offset);
 
--- a/psx/psx.c
+++ b/psx/psx.c
@@ -28,7 +28,7 @@
     psx_cpu_cycle(psx->cpu);
     psx_cdrom_update(psx->cdrom);
     psx_gpu_update(psx->gpu, psx->cpu->last_cycles);
-    psx_cpu_check_irq(psx->cpu);
+    //psx_cpu_check_irq(psx->cpu);
 }
 
 void psx_run_frame(psx_t* psx) {
--