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;
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
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)) {
*********************************************************/
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) {
}
OP(psxMTC0) { MTC0(regs_, _Rd_, _u32(_rRt_)); }
-OP(psxCTC0) { MTC0(regs_, _Rd_, _u32(_rRt_)); }
// no exception
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) {
}
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;
}
}
log_unhandled("COP1 %08x @%08x\n", code, regs_->pc - 4);
}
-// TODO: wrong COP2 decoding
OP(psxCOP2) {
- psxCP2[_Funct_](®s_->CP2);
+ u32 rt = _Rt_, rd = _Rd_, rs = _Rs_;
+ if (rs & 0x10) {
+ psxCP2[_Funct_](®s_->CP2);
+ return;
+ }
+ switch (rs) {
+ case 0x00: doLoad(regs_, rt, MFC2(®s_->CP2, rd)); break; // MFC2
+ case 0x02: doLoad(regs_, rt, regs_->CP2C.r[rd]); break; // CFC2
+ case 0x04: MTC2(®s_->CP2, regs_->GPR.r[rt], rd); break; // MTC2
+ case 0x06: CTC2(®s_->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](®s_->CP2);
-}
-
-OP(gteMFC2) {
- doLoad(regs_, _Rt_, MFC2(®s_->CP2, _Rd_));
-}
-
-OP(gteCFC2) {
- doLoad(regs_, _Rt_, regs_->CP2C.r[_Rd_]);
-}
-
-OP(gteMTC2) {
- MTC2(®s_->CP2, regs_->GPR.r[_Rt_], _Rd_);
-}
-
-OP(gteCTC2) {
- CTC2(®s_->CP2, regs_->GPR.r[_Rt_], _Rd_);
+ psxCOP2(regs_, code);
}
OP(gteLWC2) {
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) {
psxSWCx(regs_, code);
return;
}
+ dloadFlush(regs_);
psxHLEt[hleCode]();
+ branchSeen = 1;
}
static void (INT_ATTR *psxBSC[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
static void intReset() {
dloadClear(&psxRegs);
+ psxRegs.subCycle = 0;
}
static inline void execI_(u8 **memRLUT, psxRegisters *regs) {
break;
case R3000ACPU_NOTIFY_AFTER_LOAD:
dloadClear(&psxRegs);
+ psxRegs.subCycle = 0;
setupCop(psxRegs.CP0.n.SR);
// fallthrough
case R3000ACPU_NOTIFY_CACHE_ISOLATED: // Armored Core?
}
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 = {