shithub: psxe

Download patch

ref: baa9e6a32f5eb94d1c0d2314fa3ad69ad6567945
parent: 59a2d2650eac83276f32ed8dd869eb39759b2911
author: allkern <lisandroaalarcon@gmail.com>
date: Wed Jun 28 12:59:05 EDT 2023

Fix sub overflow detection

Implement ADEL and ADES exceptions
Fix initial CPU fetch

--- a/frontend/main.c
+++ b/frontend/main.c
@@ -52,7 +52,7 @@
     psx_gpu_set_udata(gpu, 0, screen);
 
     if (cfg->exe) {
-        while (psx->cpu->pc != 0x80030008) {
+        while (psx->cpu->pc != 0xBFC06FF0) {
             psx_update(psx);
         }
 
--- a/psx/cpu.c
+++ b/psx/cpu.c
@@ -50,7 +50,7 @@
     cpu->pc += 4;
 
     // Discard fetch cycles
-    cpu->last_cycles += psx_bus_get_access_cycles(cpu->bus);
+    psx_bus_get_access_cycles(cpu->bus);
 }
 
 void psx_cpu_init(psx_cpu_t* cpu, psx_bus_t* bus) {
@@ -122,11 +122,14 @@
 };
 
 psx_cpu_instruction_t g_psx_cpu_bxx_table[] = {
-    psx_cpu_i_bltz   , psx_cpu_i_bgez   , psx_cpu_i_invalid, psx_cpu_i_invalid,
-    psx_cpu_i_invalid, psx_cpu_i_invalid, psx_cpu_i_invalid, psx_cpu_i_invalid,
-    psx_cpu_i_invalid, psx_cpu_i_invalid, psx_cpu_i_invalid, psx_cpu_i_invalid,
-    psx_cpu_i_invalid, psx_cpu_i_invalid, psx_cpu_i_invalid, psx_cpu_i_invalid,
-    psx_cpu_i_bltzal , psx_cpu_i_bgezal , psx_cpu_i_invalid, psx_cpu_i_invalid
+    psx_cpu_i_bltz   , psx_cpu_i_bgez   , psx_cpu_i_bltz   , psx_cpu_i_bgez   ,
+    psx_cpu_i_bltz   , psx_cpu_i_bgez   , psx_cpu_i_bltz   , psx_cpu_i_bgez   ,
+    psx_cpu_i_bltz   , psx_cpu_i_bgez   , psx_cpu_i_bltz   , psx_cpu_i_bgez   ,
+    psx_cpu_i_bltz   , psx_cpu_i_bgez   , psx_cpu_i_bltz   , psx_cpu_i_bgez   ,
+    psx_cpu_i_bltzal , psx_cpu_i_bgezal , psx_cpu_i_bltzal , psx_cpu_i_bgezal ,
+    psx_cpu_i_bltzal , psx_cpu_i_bgezal , psx_cpu_i_bltzal , psx_cpu_i_bgezal ,
+    psx_cpu_i_bltzal , psx_cpu_i_bgezal , psx_cpu_i_bltzal , psx_cpu_i_bgezal ,
+    psx_cpu_i_bltzal , psx_cpu_i_bgezal , psx_cpu_i_bltzal , psx_cpu_i_bgezal
 };
 
 #define OP ((cpu->buf[1] >> 26) & 0x3f)
@@ -339,7 +342,7 @@
     // If we're in a delay slot, set delay slot bit
     // on CAUSE
     if (cpu->delay_slot) {
-        cpu->cop0_epc = cpu->pc - 4;
+        cpu->cop0_epc = cpu->pc - 12;
         cpu->cop0_cause |= 0x80000000;
     } else {
         cpu->cop0_epc = cpu->pc - 8;
@@ -366,9 +369,9 @@
 }
 
 void psx_cpu_i_invalid(psx_cpu_t* cpu) {
-    log_warn("%08x: Illegal instruction %08x", cpu->pc - 8, cpu->buf[1]);
+    log_fatal("%08x: Illegal instruction %08x", cpu->pc - 8, cpu->buf[1]);
 
-    //psx_cpu_exception(cpu, CAUSE_RI);
+    psx_cpu_exception(cpu, CAUSE_RI);
 }
 
 // Primary
@@ -649,8 +652,14 @@
 
     DO_PENDING_LOAD;
 
-    cpu->load_d = T;
-    cpu->load_v = SE16(psx_bus_read16(cpu->bus, s + IMM16S));
+    uint32_t addr = s + IMM16S;
+
+    if (addr & 0x1) {
+        psx_cpu_exception(cpu, CAUSE_ADEL);
+    } else {
+        cpu->load_d = T;
+        cpu->load_v = SE16(psx_bus_read16(cpu->bus, addr));
+    }
 }
 
 void psx_cpu_i_lwl(psx_cpu_t* cpu) {
@@ -676,11 +685,16 @@
     TRACE_M("lw");
 
     uint32_t s = cpu->r[S];
+    uint32_t addr = s + IMM16S;
 
     DO_PENDING_LOAD;
 
-    cpu->load_d = T;
-    cpu->load_v = psx_bus_read32(cpu->bus, s + IMM16S);
+    if (addr & 0x3) {
+        psx_cpu_exception(cpu, CAUSE_ADEL);
+    } else {
+        cpu->load_d = T;
+        cpu->load_v = psx_bus_read32(cpu->bus, addr);
+    }
 }
 
 void psx_cpu_i_lbu(psx_cpu_t* cpu) {
@@ -698,11 +712,16 @@
     TRACE_M("lhu");
 
     uint32_t s = cpu->r[S];
+    uint32_t addr = s + IMM16S;
 
     DO_PENDING_LOAD;
 
-    cpu->load_d = T;
-    cpu->load_v = psx_bus_read16(cpu->bus, s + IMM16S);
+    if (addr & 0x1) {
+        psx_cpu_exception(cpu, CAUSE_ADEL);
+    } else {
+        cpu->load_d = T;
+        cpu->load_v = psx_bus_read16(cpu->bus, addr);
+    }
 }
 
 void psx_cpu_i_lwr(psx_cpu_t* cpu) {
@@ -745,6 +764,7 @@
 
     uint32_t s = cpu->r[S];
     uint32_t t = cpu->r[T];
+    uint32_t addr = s + IMM16S;
 
     DO_PENDING_LOAD;
 
@@ -755,7 +775,11 @@
         return;
     }
 
-    psx_bus_write16(cpu->bus, s + IMM16S, t);
+    if (addr & 0x1) {
+        psx_cpu_exception(cpu, CAUSE_ADES);
+    } else {
+        psx_bus_write16(cpu->bus, addr, t);
+    }
 }
 
 void psx_cpu_i_swl(psx_cpu_t* cpu) {
@@ -784,6 +808,7 @@
 
     uint32_t s = cpu->r[S];
     uint32_t t = cpu->r[T];
+    uint32_t addr = s + IMM16S;
 
     DO_PENDING_LOAD;
 
@@ -794,7 +819,11 @@
         return;
     }
 
-    psx_bus_write32(cpu->bus, s + IMM16S, t);
+    if (addr & 0x3) {
+        psx_cpu_exception(cpu, CAUSE_ADES);
+    } else {
+        psx_bus_write32(cpu->bus, addr, t);
+    }
 }
 
 void psx_cpu_i_swr(psx_cpu_t* cpu) {
@@ -1093,18 +1122,16 @@
 
     int32_t s = (int32_t)cpu->r[S];
     int32_t t = (int32_t)cpu->r[T];
+    int32_t r;
 
     DO_PENDING_LOAD;
 
-    int32_t r = s - t;
+    int o = __builtin_ssub_overflow(s, t, &r);
 
-    // To-do: Check SUB overflow check
-    uint32_t o = (s ^ t) & (t & r);
-
-    if (o & 0x80000000) {
+    if (o) {
         psx_cpu_exception(cpu, CAUSE_OV);
     } else {
-        cpu->r[D] = (uint32_t)r;
+        cpu->r[D] = r;
     }
 }
 
@@ -1249,7 +1276,7 @@
 
     DO_PENDING_LOAD;
 
-    uint32_t mode = cpu->cop0_sr & 0xf;
+    uint32_t mode = cpu->cop0_sr & 0x3f;
 
     cpu->cop0_sr &= 0xfffffff0;
     cpu->cop0_sr |= mode >> 2;
--- a/psx/cpu.h
+++ b/psx/cpu.h
@@ -186,11 +186,11 @@
 #define CAUSE_ADES      0x05
 #define CAUSE_IBE       0x06
 #define CAUSE_DBE       0x07
-#define CAUSE_SYSCALL   0x08   
-#define CAUSE_BP        0x09   
-#define CAUSE_RI        0x0a   
-#define CAUSE_CPU       0x0b   
-#define CAUSE_OV        0x0c   
+#define CAUSE_SYSCALL   0x08
+#define CAUSE_BP        0x09
+#define CAUSE_RI        0x0a
+#define CAUSE_CPU       0x0b
+#define CAUSE_OV        0x0c
 
 void psx_cpu_i_invalid(psx_cpu_t*);
 
--- a/psx/dev/gpu.c
+++ b/psx/dev/gpu.c
@@ -712,7 +712,7 @@
         gpu->line++;
 
         if (gpu->line == GPU_SCANS_PER_FRAME_NTSC) {
-            psx_ic_irq(gpu->ic, IC_VBLANK);
+            // psx_ic_irq(gpu->ic, IC_VBLANK);
 
             gpu->line = 0;
         } else {
--- a/psx/psx.c
+++ b/psx/psx.c
@@ -106,14 +106,11 @@
     psx_scratchpad_init(psx->scratchpad);
     psx_gpu_init(psx->gpu, psx->ic);
     psx_spu_init(psx->spu);
-    psx_cpu_init(psx->cpu, psx->bus);
     psx_timer_init(psx->timer);
     psx_cdrom_init(psx->cdrom, psx->ic);
     psx_pad_init(psx->pad);
-
     psx_bios_load(psx->bios, bios_path);
-
-    psx_cpu_fetch(psx->cpu);
+    psx_cpu_init(psx->cpu, psx->bus);
 }
 
 void psx_hard_reset(psx_t* psx) {
--