shithub: psxe

Download patch

ref: df3292dd771872c3f00b3bbaa4c3ae564fc6e5bb
parent: 6ab50aa9b610a087c7b2543571e23a4b3cc389bb
author: allkern <lisandroaalarcon@gmail.com>
date: Sat Jul 15 18:38:28 EDT 2023

Implement timer sync modes

--- a/psx/cpu.c
+++ b/psx/cpu.c
@@ -1386,6 +1386,7 @@
     ((uint32_t*)(&cpu->cop2_cr))[D] = t;
 }
 
+#define R_IR0 cpu->cop2_dr.ir0
 #define R_IR1 cpu->cop2_dr.ir1
 #define R_IR2 cpu->cop2_dr.ir2
 #define R_IR3 cpu->cop2_dr.ir3
@@ -1427,7 +1428,12 @@
 #define R_SZ3 cpu->cop2_dr.sz3
 #define R_ZSF3 cpu->cop2_cr.zsf3
 #define R_ZSF4 cpu->cop2_cr.zsf4
+#define R_OFX cpu->cop2_cr.ofx
+#define R_OFY cpu->cop2_cr.ofy
 #define R_OTZ cpu->cop2_dr.otz
+#define R_H cpu->cop2_cr.h
+#define R_DQA cpu->cop2_cr.dqa
+#define R_DQB cpu->cop2_cr.dqb
 
 #define CLAMPU32(v, min, max) ((uint32_t)v < (uint32_t)min ? min : ((uint32_t)v > (uint32_t)max ? max : (uint32_t)v))
 #define CLAMPS32(v, min, max) ((int32_t)v < (int32_t)min ? min : ((int32_t)v > (int32_t)max ? max : (int32_t)v))
@@ -1467,6 +1473,19 @@
     R_SZ1 = R_SZ2;
     R_SZ2 = R_SZ3;
     R_SZ3 = CLAMPU32(R_MAC3 >> (12 * !sf), 0x0000, 0xffff);
+
+    uint32_t f = R_H / R_SZ3;
+
+    R_SX0 = R_SX1;
+    R_SX1 = R_SX2;
+    R_SX2 = R_OFX + R_IR1 * f;
+
+    R_SY0 = R_SY1;
+    R_SY1 = R_SY2;
+    R_SY2 = R_OFY + R_IR2 * f;
+
+    R_IR0 = R_DQB + R_DQA * f;
+    R_MAC0 = R_IR0;
 }
 
 void psx_gte_i_nclip(psx_cpu_t* cpu) {
@@ -1546,7 +1565,38 @@
 }
 
 void psx_gte_i_rtpt(psx_cpu_t* cpu) {
-    log_fatal("rtpt: Unimplemented GTE instruction");   
+    int sf = (cpu->opcode >> 19) & 1;
+    int lm = (cpu->opcode >> 9) & 2;
+    int shift = 12 * sf;
+
+    int16_t ir_upper = g_psx_gte_ir_clamp_table[lm];
+    int16_t ir_lower = g_psx_gte_ir_clamp_table[lm + 1];
+
+    R_MAC1 = (R_TRX << 12) + (R_RT11 * R_VX0 + R_RT12 * R_VY0 + R_RT13 * R_VZ0);
+    R_MAC2 = (R_TRY << 12) + (R_RT21 * R_VX0 + R_RT22 * R_VY0 + R_RT23 * R_VZ0);
+    R_MAC3 = (R_TRZ << 12) + (R_RT31 * R_VX0 + R_RT32 * R_VY0 + R_RT33 * R_VZ0);
+
+    R_IR1 = CLAMPS16(R_MAC1 >> shift, ir_lower, ir_upper);
+    R_IR2 = CLAMPS16(R_MAC2 >> shift, ir_lower, ir_upper);
+    R_IR3 = CLAMPS16(R_MAC3 >> shift, ir_lower, ir_upper);
+
+    R_SZ0 = R_SZ1;
+    R_SZ1 = R_SZ2;
+    R_SZ2 = R_SZ3;
+    R_SZ3 = CLAMPU32(R_MAC3 >> (12 * !sf), 0x0000, 0xffff);
+
+    uint32_t f = R_H / R_SZ3;
+
+    R_SX0 = R_SX1;
+    R_SX1 = R_SX2;
+    R_SX2 = R_OFX + R_IR1 * f;
+
+    R_SY0 = R_SY1;
+    R_SY1 = R_SY2;
+    R_SY2 = R_OFY + R_IR2 * f;
+
+    R_IR0 = R_DQB + R_DQA * f;
+    R_MAC0 = R_IR0;
 }
 
 void psx_gte_i_gpf(psx_cpu_t* cpu) {
--- a/psx/cpu.h
+++ b/psx/cpu.h
@@ -16,24 +16,6 @@
 typedef void (*psx_cpu_kcall_hook_t)(psx_cpu_t*);
 
 /*
-  Name       Alias    Common Usage
-  R0         zero     Constant (always 0)
-  R1         at       Assembler temporary (destroyed by some assembler pseudoinstructions!)
-  R2-R3      v0-v1    Subroutine return values, may be changed by subroutines
-  R4-R7      a0-a3    Subroutine arguments, may be changed by subroutines
-  R8-R15     t0-t7    Temporaries, may be changed by subroutines
-  R16-R23    s0-s7    Static variables, must be saved by subs
-  R24-R25    t8-t9    Temporaries, may be changed by subroutines
-  R26-R27    k0-k1    Reserved for kernel (destroyed by some IRQ handlers!)
-  R28        gp       Global pointer (rarely used)
-  R29        sp       Stack pointer
-  R30        fp(s8)   Frame Pointer, or 9th Static variable, must be saved
-  R31        ra       Return address (used so by JAL,BLTZAL,BGEZAL opcodes)
-  -          pc       Program counter
-  -          hi,lo    Multiply/divide results, may be changed by subroutines
-*/
-
-/*
     cop0r0      - N/A
     cop0r1      - N/A
     cop0r2      - N/A
@@ -63,6 +45,24 @@
 #define COP0_CAUSE    13
 #define COP0_EPC      14
 #define COP0_PRID     15
+
+/*
+  Name       Alias    Common Usage
+  R0         zero     Constant (always 0)
+  R1         at       Assembler temporary (destroyed by some assembler pseudoinstructions!)
+  R2-R3      v0-v1    Subroutine return values, may be changed by subroutines
+  R4-R7      a0-a3    Subroutine arguments, may be changed by subroutines
+  R8-R15     t0-t7    Temporaries, may be changed by subroutines
+  R16-R23    s0-s7    Static variables, must be saved by subs
+  R24-R25    t8-t9    Temporaries, may be changed by subroutines
+  R26-R27    k0-k1    Reserved for kernel (destroyed by some IRQ handlers!)
+  R28        gp       Global pointer (rarely used)
+  R29        sp       Stack pointer
+  R30        fp(s8)   Frame Pointer, or 9th Static variable, must be saved
+  R31        ra       Return address (used so by JAL,BLTZAL,BGEZAL opcodes)
+  -          pc       Program counter
+  -          hi,lo    Multiply/divide results, may be changed by subroutines
+*/
 
 struct psx_cpu_t {
     uint32_t r[32];
--- a/psx/dev/timer.c
+++ b/psx/dev/timer.c
@@ -107,44 +107,12 @@
 }
 
 void timer_update_timer0(psx_timer_t* timer, int cyc) {
-    int src = T0_MODE & 0x100;
 
-    // if (src) {
-    //     log_fatal("Unimplemented T0 clock source: dotclock");
-
-    //     exit(1);
-    // }
-
-    T0_PREV = T0_COUNTER;
-
-    if (!T0_PAUSED)
-        T0_COUNTER += cyc;
-
-    uint16_t reset = (T0_MODE & MODE_RESETC) ? T0_TARGET : 0xffff;
-
-    if ((T0_COUNTER >= reset) && (T0_PREV <= reset)) {
-        T0_COUNTER -= reset;
-        T0_MODE |= 0x800;
-
-        if (reset == 0xffff)
-            T0_MODE |= 0x1000;
-    }
-
-    if ((T0_COUNTER >= 0xffff) && (T0_PREV <= 0xffff)) {
-        T0_COUNTER &= 0xffff;
-        T0_MODE |= 0x1000;
-    }
 }
 
 void timer_update_timer1(psx_timer_t* timer, int cyc) {
     int src = T1_MODE & 0x100;
 
-    // if (src) {
-    //     log_fatal("Unimplemented T1 clock source: dotclock");
-
-    //     exit(1);
-    // }
-
     T1_PREV = T1_COUNTER;
 
     if (!T1_PAUSED)
@@ -168,12 +136,6 @@
 void timer_update_timer2(psx_timer_t* timer, int cyc) {
     int src = T2_MODE & 0x100;
 
-    // if (src) {
-    //     log_fatal("Unimplemented T2 clock source: dotclock");
-
-    //     exit(1);
-    // }
-
     T2_PREV = T2_COUNTER;
 
     if (!T2_PAUSED)
@@ -201,8 +163,47 @@
     timer_update_timer2(timer, cyc);
 }
 
-void psxe_gpu_hblank_event_cb(psx_gpu_t* gpu) {}
-void psxe_gpu_hblank_end_event_cb(psx_gpu_t* gpu) {}
+void psxe_gpu_hblank_event_cb(psx_gpu_t* gpu) {
+    psx_timer_t* timer = gpu->udata[1];
+
+    if (T0_MODE & MODE_SYNCEN) {
+        switch (T0_MODE & 6) {
+            case 0: {
+                T0_PAUSED = 1;
+            } break;
+
+            case 2: {
+                T0_COUNTER = 0;
+            } break;
+
+            case 4: {
+                T0_COUNTER = 0;
+                T0_PAUSED = 0;
+            } break;
+
+            case 6: {
+                T0_MODE &= ~MODE_SYNCEN;
+            } break;
+        }
+    }
+}
+
+void psxe_gpu_hblank_end_event_cb(psx_gpu_t* gpu) {
+    psx_timer_t* timer = gpu->udata[1];
+
+    if (T0_MODE & MODE_SYNCEN) {
+        switch (T0_MODE & 6) {
+            case 0: {
+                T0_PAUSED = 0;
+            } break;
+
+            case 4: {
+                T0_PAUSED = 1;
+            } break;
+        }
+    }
+}
+
 void psxe_gpu_vblank_end_event_cb(psx_gpu_t* gpu) {}
 
 void psx_timer_destroy(psx_timer_t* timer) {
--