cdrom: change pause timing again
[pcsx_rearmed.git] / libpcsxcore / gte.c
index dc56b7f..991a445 100644 (file)
 #include "gte.h"
 #include "psxmem.h"
 
-typedef struct psxCP2Regs {
-       psxCP2Data CP2D;        /* Cop2 data registers */
-       psxCP2Ctrl CP2C;        /* Cop2 control registers */
-} psxCP2Regs;
-
 #define VX(n) (n < 3 ? regs->CP2D.p[n << 1].sw.l : regs->CP2D.p[9].sw.l)
 #define VY(n) (n < 3 ? regs->CP2D.p[n << 1].sw.h : regs->CP2D.p[10].sw.l)
 #define VZ(n) (n < 3 ? regs->CP2D.p[(n << 1) + 1].sw.l : regs->CP2D.p[11].sw.l)
@@ -154,7 +149,13 @@ typedef struct psxCP2Regs {
 #define gteBFC (((s32 *)regs->CP2C.r)[23])
 #define gteOFX (((s32 *)regs->CP2C.r)[24])
 #define gteOFY (((s32 *)regs->CP2C.r)[25])
-#define gteH   (regs->CP2C.p[26].sw.l)
+// senquack - gteH register is u16, not s16, and used in GTE that way.
+//  HOWEVER when read back by CPU using CFC2, it will be incorrectly
+//  sign-extended by bug in original hardware, according to Nocash docs
+//  GTE section 'Screen Offset and Distance'. The emulator does this
+//  sign extension when it is loaded to GTE by CTC2.
+//#define gteH   (regs->CP2C.p[26].sw.l)
+#define gteH   (regs->CP2C.p[26].w.l)
 #define gteDQA (regs->CP2C.p[27].sw.l)
 #define gteDQB (((s32 *)regs->CP2C.r)[28])
 #define gteZSF3 (regs->CP2C.p[29].sw.l)
@@ -175,7 +176,7 @@ typedef struct psxCP2Regs {
 
 #ifndef FLAGLESS
 
-static inline s32 BOUNDS_(psxCP2Regs *regs, s64 n_value, s64 n_max, int n_maxflag, s64 n_min, int n_minflag) {
+static inline s64 BOUNDS_(psxCP2Regs *regs, s64 n_value, s64 n_max, int n_maxflag, s64 n_min, int n_minflag) {
        if (n_value > n_max) {
                gteFLAG |= n_maxflag;
        } else if (n_value < n_min) {
@@ -259,12 +260,48 @@ static inline u32 limE_(psxCP2Regs *regs, u32 result) {
 #define A3U(x) (x)
 #endif
 
+
+//senquack - n param should be unsigned (will be 'gteH' reg which is u16)
+#ifdef GTE_USE_NATIVE_DIVIDE
+INLINE u32 DIVIDE(u16 n, u16 d) {
+       if (n < d * 2) {
+               return ((u32)n << 16) / d;
+       }
+       return 0xffffffff;
+}
+#else
 #include "gte_divider.h"
+#endif // GTE_USE_NATIVE_DIVIDE
 
 #ifndef FLAGLESS
 
-static inline u32 MFC2(int reg) {
-       psxCP2Regs *regs = (psxCP2Regs *)&psxRegs.CP2D;
+const unsigned char gte_cycletab[64] = {
+       /*   1   2   3   4   5   6   7   8   9   a   b   c   d   e   f */
+        0, 15,  0,  0,  0,  0,  8,  0,  0,  0,  0,  0,  6,  0,  0,  0,
+        8,  8,  8, 19, 13,  0, 44,  0,  0,  0,  0, 17, 11,  0, 14,  0,
+       30,  0,  0,  0,  0,  0,  0,  0,  5,  8, 17,  0,  0,  5,  6,  0,
+       23,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  5,  5, 39,
+};
+
+// warning: called by the dynarec
+int gteCheckStallRaw(u32 op_cycles, psxRegisters *regs) {
+       u32 left = regs->gteBusyCycle - regs->cycle;
+       int stall = 0;
+
+       if (left <= 44) {
+               //printf("c %2u stall %2u %u\n", op_cycles, left, regs->cycle);
+               regs->cycle = regs->gteBusyCycle;
+               stall = left;
+       }
+       regs->gteBusyCycle = regs->cycle + op_cycles;
+       return stall;
+}
+
+void gteCheckStall(u32 op) {
+       gteCheckStallRaw(gte_cycletab[op], &psxRegs);
+}
+
+u32 MFC2(struct psxCP2Regs *regs, int reg) {
        switch (reg) {
                case 1:
                case 3:
@@ -273,7 +310,7 @@ static inline u32 MFC2(int reg) {
                case 9:
                case 10:
                case 11:
-                       psxRegs.CP2D.r[reg] = (s32)psxRegs.CP2D.p[reg].sw.l;
+                       regs->CP2D.r[reg] = (s32)regs->CP2D.p[reg].sw.l;
                        break;
 
                case 7:
@@ -281,25 +318,24 @@ static inline u32 MFC2(int reg) {
                case 17:
                case 18:
                case 19:
-                       psxRegs.CP2D.r[reg] = (u32)psxRegs.CP2D.p[reg].w.l;
+                       regs->CP2D.r[reg] = (u32)regs->CP2D.p[reg].w.l;
                        break;
 
                case 15:
-                       psxRegs.CP2D.r[reg] = gteSXY2;
+                       regs->CP2D.r[reg] = gteSXY2;
                        break;
 
                case 28:
                case 29:
-                       psxRegs.CP2D.r[reg] = LIM(gteIR1 >> 7, 0x1f, 0, 0) |
+                       regs->CP2D.r[reg] = LIM(gteIR1 >> 7, 0x1f, 0, 0) |
                                                                        (LIM(gteIR2 >> 7, 0x1f, 0, 0) << 5) |
                                                                        (LIM(gteIR3 >> 7, 0x1f, 0, 0) << 10);
                        break;
        }
-       return psxRegs.CP2D.r[reg];
+       return regs->CP2D.r[reg];
 }
 
-static inline void MTC2(u32 value, int reg) {
-       psxCP2Regs *regs = (psxCP2Regs *)&psxRegs.CP2D;
+void MTC2(struct psxCP2Regs *regs, u32 value, int reg) {
        switch (reg) {
                case 15:
                        gteSXY0 = gteSXY1;
@@ -310,9 +346,10 @@ static inline void MTC2(u32 value, int reg) {
 
                case 28:
                        gteIRGB = value;
-                       gteIR1 = (value & 0x1f) << 7;
-                       gteIR2 = (value & 0x3e0) << 2;
-                       gteIR3 = (value & 0x7c00) >> 3;
+                       // not gteIR1 etc. just to be consistent with dynarec
+                       regs->CP2D.n.ir1 = (value & 0x1f) << 7;
+                       regs->CP2D.n.ir2 = (value & 0x3e0) << 2;
+                       regs->CP2D.n.ir3 = (value & 0x7c00) >> 3;
                        break;
 
                case 30:
@@ -340,11 +377,11 @@ static inline void MTC2(u32 value, int reg) {
                        return;
 
                default:
-                       psxRegs.CP2D.r[reg] = value;
+                       regs->CP2D.r[reg] = value;
        }
 }
 
-static inline void CTC2(u32 value, int reg) {
+void CTC2(struct psxCP2Regs *regs, u32 value, int reg) {
        switch (reg) {
                case 4:
                case 12:
@@ -362,35 +399,7 @@ static inline void CTC2(u32 value, int reg) {
                        break;
        }
 
-       psxRegs.CP2C.r[reg] = value;
-}
-
-void gteMFC2() {
-       if (!_Rt_) return;
-       psxRegs.GPR.r[_Rt_] = MFC2(_Rd_);
-}
-
-void gteCFC2() {
-       if (!_Rt_) return;
-       psxRegs.GPR.r[_Rt_] = psxRegs.CP2C.r[_Rd_];
-}
-
-void gteMTC2() {
-       MTC2(psxRegs.GPR.r[_Rt_], _Rd_);
-}
-
-void gteCTC2() {
-       CTC2(psxRegs.GPR.r[_Rt_], _Rd_);
-}
-
-#define _oB_ (psxRegs.GPR.r[_Rs_] + _Imm_)
-
-void gteLWC2() {
-       MTC2(psxMemRead32(_oB_), _Rt_);
-}
-
-void gteSWC2() {
-       psxMemWrite32(_oB_, MFC2(_Rt_));
+       regs->CP2C.r[reg] = value;
 }
 
 #endif // FLAGLESS
@@ -409,6 +418,7 @@ static u32 DIVIDE_(s16 n, u16 d) {
 
 void gteRTPS(psxCP2Regs *regs) {
        int quotient;
+       s64 tmp;
 
 #ifdef GTE_LOG
        GTE_LOG("GTE RTPS\n");
@@ -431,14 +441,16 @@ void gteRTPS(psxCP2Regs *regs) {
        gteSX2 = limG1(F((s64)gteOFX + ((s64)gteIR1 * quotient)) >> 16);
        gteSY2 = limG2(F((s64)gteOFY + ((s64)gteIR2 * quotient)) >> 16);
 
-       gteMAC0 = F((s64)gteDQB + ((s64)gteDQA * quotient));
-       gteIR0 = limH(gteMAC0 >> 12);
+       tmp = (s64)gteDQB + ((s64)gteDQA * quotient);
+       gteMAC0 = F(tmp);
+       gteIR0 = limH(tmp >> 12);
 }
 
 void gteRTPT(psxCP2Regs *regs) {
        int quotient;
        int v;
        s32 vx, vy, vz;
+       s64 tmp;
 
 #ifdef GTE_LOG
        GTE_LOG("GTE RTPT\n");
@@ -461,8 +473,10 @@ void gteRTPT(psxCP2Regs *regs) {
                fSX(v) = limG1(F((s64)gteOFX + ((s64)gteIR1 * quotient)) >> 16);
                fSY(v) = limG2(F((s64)gteOFY + ((s64)gteIR2 * quotient)) >> 16);
        }
-       gteMAC0 = F((s64)gteDQB + ((s64)gteDQA * quotient));
-       gteIR0 = limH(gteMAC0 >> 12);
+
+       tmp = (s64)gteDQB + ((s64)gteDQA * quotient);
+       gteMAC0 = F(tmp);
+       gteIR0 = limH(tmp >> 12);
 }
 
 void gteMVMVA(psxCP2Regs *regs) {