cdrom: change pause timing again
[pcsx_rearmed.git] / libpcsxcore / psxinterpreter.c
index f3bf7b6..3060853 100644 (file)
@@ -112,7 +112,8 @@ static void intException(psxRegisters *regs, u32 pc, u32 cause)
        if (cause != 0x20) {
                //FILE *f = fopen("/tmp/psx_ram.bin", "wb");
                //fwrite(psxM, 1, 0x200000, f); fclose(f);
-               log_unhandled("exception %08x @%08x\n", cause, pc);
+               log_unhandled("exception %08x @%08x ra=%08x\n",
+                       cause, pc, regs->GPR.n.ra);
        }
        dloadFlush(regs);
        regs->pc = pc;
@@ -127,6 +128,19 @@ static void intExceptionInsn(psxRegisters *regs, u32 cause)
        intException(regs, regs->pc - 4, cause);
 }
 
+static noinline void intExceptionReservedInsn(psxRegisters *regs)
+{
+#ifdef DO_EXCEPTION_RESERVEDI
+       static u32 ppc_ = ~0u;
+       if (regs->pc != ppc_) {
+               SysPrintf("reserved instruction %08x @%08x ra=%08x\n",
+                       regs->code, regs->pc - 4, regs->GPR.n.ra);
+               ppc_ = regs->pc;
+       }
+       intExceptionInsn(regs, R3000E_RI << 2);
+#endif
+}
+
 // 29  Enable for 80000000-ffffffff
 // 30  Enable for 00000000-7fffffff
 // 31  Enable exception
@@ -162,25 +176,21 @@ static int execBreakCheck(psxRegisters *regs, u32 pc)
 // get an opcode without triggering exceptions or affecting cache
 u32 intFakeFetch(u32 pc)
 {
-       u8 *base = psxMemRLUT[pc >> 16];
-       u32 *code;
-       if (unlikely(base == INVALID_PTR))
+       u32 *code = (u32 *)psxm(pc & ~0x3, 0);
+       if (unlikely(code == INVALID_PTR))
                return 0; // nop
-       code = (u32 *)(base + (pc & 0xfffc));
        return SWAP32(*code);
 
 }
 
 static u32 INT_ATTR fetchNoCache(psxRegisters *regs, u8 **memRLUT, u32 pc)
 {
-       u8 *base = memRLUT[pc >> 16];
-       u32 *code;
-       if (unlikely(base == INVALID_PTR)) {
+       u32 *code = (u32 *)psxm_lut(pc & ~0x3, 0, memRLUT);
+       if (unlikely(code == INVALID_PTR)) {
                SysPrintf("game crash @%08x, ra=%08x\n", pc, regs->GPR.n.ra);
                intException(regs, pc, R3000E_IBE << 2);
                return 0; // execute as nop
        }
-       code = (u32 *)(base + (pc & 0xfffc));
        return SWAP32(*code);
 }
 
@@ -203,14 +213,12 @@ static u32 INT_ATTR fetchICache(psxRegisters *regs, u8 **memRLUT, u32 pc)
 
                if (((entry->tag ^ pc) & 0xfffffff0) != 0 || pc < entry->tag)
                {
-                       const u8 *base = memRLUT[pc >> 16];
-                       const u32 *code;
-                       if (unlikely(base == INVALID_PTR)) {
+                       const u32 *code = (u32 *)psxm_lut(pc & ~0xf, 0, memRLUT);
+                       if (unlikely(code == INVALID_PTR)) {
                                SysPrintf("game crash @%08x, ra=%08x\n", pc, regs->GPR.n.ra);
                                intException(regs, pc, R3000E_IBE << 2);
                                return 0; // execute as nop
                        }
-                       code = (u32 *)(base + (pc & 0xfff0));
 
                        entry->tag = pc;
                        // treat as 4 words, although other configurations are said to be possible
@@ -454,14 +462,6 @@ static void doBranchRegE(psxRegisters *regs, u32 tar) {
        doBranch(regs, tar, R3000A_BRANCH_TAKEN);
 }
 
-#if __has_builtin(__builtin_add_overflow) || (defined(__GNUC__) && __GNUC__ >= 5)
-#define add_overflow(a, b, r) __builtin_add_overflow(a, b, &(r))
-#define sub_overflow(a, b, r) __builtin_sub_overflow(a, b, &(r))
-#else
-#define add_overflow(a, b, r) ({r = (u32)a + (u32)b; (a ^ ~b) & (a ^ r) & (1u<<31);})
-#define sub_overflow(a, b, r) ({r = (u32)a - (u32)b; (a ^  b) & (a ^ r) & (1u<<31);})
-#endif
-
 static void addExc(psxRegisters *regs, u32 rt, s32 a1, s32 a2) {
        s32 val;
        if (add_overflow(a1, a2, val)) {
@@ -869,12 +869,12 @@ OP(psxLWR) { doLWR(regs_, _Rt_, _oB_); }
 OP(psxLWLe) { if (checkLD(regs_, _oB_ & ~3, 0)) doLWL(regs_, _Rt_, _oB_); }
 OP(psxLWRe) { if (checkLD(regs_, _oB_     , 0)) doLWR(regs_, _Rt_, _oB_); }
 
-OP(psxSB) { psxMemWrite8 (_oB_, _rRt_ &   0xff); }
-OP(psxSH) { psxMemWrite16(_oB_, _rRt_ & 0xffff); }
+OP(psxSB) { psxMemWrite8 (_oB_, _rRt_); }
+OP(psxSH) { psxMemWrite16(_oB_, _rRt_); }
 OP(psxSW) { psxMemWrite32(_oB_, _rRt_); }
 
-OP(psxSBe) { if (checkST(regs_, _oB_, 0)) psxMemWrite8 (_oB_, _rRt_ &   0xff); }
-OP(psxSHe) { if (checkST(regs_, _oB_, 1)) psxMemWrite16(_oB_, _rRt_ & 0xffff); }
+OP(psxSBe) { if (checkST(regs_, _oB_, 0)) psxMemWrite8 (_oB_, _rRt_); }
+OP(psxSHe) { if (checkST(regs_, _oB_, 1)) psxMemWrite16(_oB_, _rRt_); }
 OP(psxSWe) { if (checkST(regs_, _oB_, 3)) psxMemWrite32(_oB_, _rRt_); }
 
 static void doSWL(psxRegisters *regs, u32 rt, u32 addr) {
@@ -930,17 +930,13 @@ OP(psxSWRe) { if (checkST(regs_, _oB_     , 0)) doSWR(regs_, _Rt_, _oB_); }
 *********************************************************/
 OP(psxMFC0) {
        u32 r = _Rd_;
-#ifdef DO_EXCEPTION_RESERVEDI
        if (unlikely(0x00000417u & (1u << r)))
-               intExceptionInsn(regs_, R3000E_RI << 2);
-#endif
+               intExceptionReservedInsn(regs_);
        doLoad(regs_, _Rt_, regs_->CP0.r[r]);
 }
 
 static void setupCop(u32 sr);
 
-OP(psxCFC0) { doLoad(regs_, _Rt_, regs_->CP0.r[_Rd_]); }
-
 void MTC0(psxRegisters *regs_, int reg, u32 val) {
 //     SysPrintf("MTC0 %d: %x\n", reg, val);
        switch (reg) {
@@ -962,15 +958,20 @@ void MTC0(psxRegisters *regs_, int reg, u32 val) {
                case 7:
                        if ((regs_->CP0.n.DCIC ^ val) & 0xff800000)
                                log_unhandled("DCIC: %08x->%08x\n", regs_->CP0.n.DCIC, val);
-                       // fallthrough
+                       goto default_;
+               case 3:
+                       if (regs_->CP0.n.BPC != val)
+                               log_unhandled("BPC: %08x->%08x\n", regs_->CP0.n.BPC, val);
+                       goto default_;
+
                default:
+               default_:
                        regs_->CP0.r[reg] = val;
                        break;
        }
 }
 
 OP(psxMTC0) { MTC0(regs_, _Rd_, _u32(_rRt_)); }
-OP(psxCTC0) { MTC0(regs_, _Rd_, _u32(_rRt_)); }
 
 // no exception
 static inline void psxNULLne(psxRegisters *regs) {
@@ -984,9 +985,7 @@ static inline void psxNULLne(psxRegisters *regs) {
 
 OP(psxNULL) {
        psxNULLne(regs_);
-#ifdef DO_EXCEPTION_RESERVEDI
-       intExceptionInsn(regs_, R3000E_RI << 2);
-#endif
+       intExceptionReservedInsn(regs_);
 }
 
 void gteNULL(struct psxCP2Regs *regs) {
@@ -999,12 +998,26 @@ OP(psxSPECIAL) {
 }
 
 OP(psxCOP0) {
-       switch (_Rs_) {
+       u32 rs = _Rs_;
+       if (rs & 0x10) {
+               u32 op2 = code & 0x1f;
+               switch (op2) {
+                       case 0x01:
+                       case 0x02:
+                       case 0x06:
+                       case 0x08: psxNULL(regs_, code); break;
+                       case 0x10: psxRFE(regs_, code);  break;
+                       default:   psxNULLne(regs_);     break;
+               }
+               return;
+       }
+       switch (rs) {
                case 0x00: psxMFC0(regs_, code); break;
-               case 0x02: psxCFC0(regs_, code); break;
                case 0x04: psxMTC0(regs_, code); break;
-               case 0x06: psxCTC0(regs_, code); break;
-               case 0x10: psxRFE(regs_, code);  break;
+               case 0x02:                              // CFC
+               case 0x06: psxNULL(regs_, code); break; // CTC -> exception
+               case 0x08:
+               case 0x0c: log_unhandled("BC0 %08x @%08x\n", code, regs_->pc - 4);
                default:   psxNULLne(regs_);     break;
        }
 }
@@ -1014,31 +1027,27 @@ OP(psxCOP1) {
        log_unhandled("COP1 %08x @%08x\n", code, regs_->pc - 4);
 }
 
-// TODO: wrong COP2 decoding
 OP(psxCOP2) {
-       psxCP2[_Funct_](&regs_->CP2);
+       u32 rt = _Rt_, rd = _Rd_, rs = _Rs_;
+       if (rs & 0x10) {
+               psxCP2[_Funct_](&regs_->CP2);
+               return;
+       }
+       switch (rs) {
+               case 0x00: doLoad(regs_, rt, MFC2(&regs_->CP2, rd)); break; // MFC2
+               case 0x02: doLoad(regs_, rt, regs_->CP2C.r[rd]);     break; // CFC2
+               case 0x04: MTC2(&regs_->CP2, regs_->GPR.r[rt], rd);  break; // MTC2
+               case 0x06: CTC2(&regs_->CP2, regs_->GPR.r[rt], rd);  break; // CTC2
+               case 0x08:
+               case 0x0c: log_unhandled("BC2 %08x @%08x\n", code, regs_->pc - 4);
+               default:   psxNULLne(regs_); break;
+       }
 }
 
 OP(psxCOP2_stall) {
        u32 f = _Funct_;
        gteCheckStall(f);
-       psxCP2[f](&regs_->CP2);
-}
-
-OP(gteMFC2) {
-       doLoad(regs_, _Rt_, MFC2(&regs_->CP2, _Rd_));
-}
-
-OP(gteCFC2) {
-       doLoad(regs_, _Rt_, regs_->CP2C.r[_Rd_]);
-}
-
-OP(gteMTC2) {
-       MTC2(&regs_->CP2, regs_->GPR.r[_Rt_], _Rd_);
-}
-
-OP(gteCTC2) {
-       CTC2(&regs_->CP2, regs_->GPR.r[_Rt_], _Rd_);
+       psxCOP2(regs_, code);
 }
 
 OP(gteLWC2) {
@@ -1094,21 +1103,6 @@ OP(psxSWCx) {
        checkST(regs_, _oB_, 3);
 }
 
-static void psxBASIC(struct psxCP2Regs *cp2regs) {
-       psxRegisters *regs = (void *)((u8 *)cp2regs - offsetof(psxRegisters, CP2));
-       u32 code = regs->code;
-       assert(regs == &psxRegs);
-       switch (_Rs_) {
-               case 0x00: gteMFC2(regs, code); break;
-               case 0x02: gteCFC2(regs, code); break;
-               case 0x04: gteMTC2(regs, code); break;
-               case 0x06: gteCTC2(regs, code); break;
-               case 0x08:
-               case 0x0c: log_unhandled("BC2 %08x @%08x\n", code, regs->pc - 4);
-               default:   psxNULLne(regs);     break;
-       }
-}
-
 OP(psxREGIMM) {
        u32 rt = _Rt_;
        switch (rt) {
@@ -1133,7 +1127,9 @@ OP(psxHLE) {
                psxSWCx(regs_, code);
                return;
        }
+       dloadFlush(regs_);
        psxHLEt[hleCode]();
+       branchSeen = 1;
 }
 
 static void (INT_ATTR *psxBSC[64])(psxRegisters *regs_, u32 code) = {
@@ -1159,7 +1155,7 @@ static void (INT_ATTR *psxSPC[64])(psxRegisters *regs_, u32 code) = {
 };
 
 void (*psxCP2[64])(struct psxCP2Regs *regs) = {
-       psxBASIC, gteRTPS , gteNULL , gteNULL, gteNULL, gteNULL , gteNCLIP, gteNULL, // 00
+       gteNULL , gteRTPS , gteNULL , gteNULL, gteNULL, gteNULL , gteNCLIP, gteNULL, // 00
        gteNULL , gteNULL , gteNULL , gteNULL, gteOP  , gteNULL , gteNULL , gteNULL, // 08
        gteDPCS , gteINTPL, gteMVMVA, gteNCDS, gteCDP , gteNULL , gteNCDT , gteNULL, // 10
        gteNULL , gteNULL , gteNULL , gteNCCS, gteCC  , gteNULL , gteNCS  , gteNULL, // 18
@@ -1177,6 +1173,7 @@ static int intInit() {
 
 static void intReset() {
        dloadClear(&psxRegs);
+       psxRegs.subCycle = 0;
 }
 
 static inline void execI_(u8 **memRLUT, psxRegisters *regs) {
@@ -1241,6 +1238,7 @@ static void intNotify(enum R3000Anote note, void *data) {
                break;
        case R3000ACPU_NOTIFY_AFTER_LOAD:
                dloadClear(&psxRegs);
+               psxRegs.subCycle = 0;
                setupCop(psxRegs.CP0.n.SR);
                // fallthrough
        case R3000ACPU_NOTIFY_CACHE_ISOLATED: // Armored Core?
@@ -1350,12 +1348,15 @@ void intApplyConfig() {
 }
 
 static void intShutdown() {
+       dloadClear(&psxRegs);
 }
 
-// single step (may do several ops in case of a branch)
+// single step (may do several ops in case of a branch or load delay)
+// called by asm/dynarec
 void execI(psxRegisters *regs) {
-       execI_(psxMemRLUT, regs);
-       dloadFlush(regs);
+       do {
+               execIbp(psxMemRLUT, regs);
+       } while (regs->dloadReg[0] || regs->dloadReg[1]);
 }
 
 R3000Acpu psxInt = {