#define DO_EXCEPTION_RESERVEDI
#define HANDLE_LOAD_DELAY
-static int branchSeen = 0;
-
#ifdef __i386__
#define INT_ATTR __attribute__((regparm(2)))
#else
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
cp0->n.Cause |= (regs->branching << 30) | (R3000E_Bp << 2);
cp0->n.SR = (cp0->n.SR & ~0x3f) | ((cp0->n.SR & 0x0f) << 2);
cp0->n.EPC = regs->branching ? pc - 4 : pc;
- psxRegs.pc = 0x80000040;
+ regs->pc = 0x80000040;
}
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);
}
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
static void doBranch(psxRegisters *regs, u32 tar, enum R3000Abdt taken) {
u32 code, pc, pc_final;
- branchSeen = regs->branching = taken;
+ regs->branchSeen = regs->branching = taken;
pc_final = taken == R3000A_BRANCH_TAKEN ? tar : regs->pc + 4;
// fetch the delay slot
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)) {
return 0;
}
if (unlikely(BUS_LOCKED_ADDR(addr))) {
+ log_unhandled("bus error read addr=%08x @%08x ra=%08x\n",
+ addr, regs->pc - 4, regs->GPR.n.ra);
intException(regs, regs->pc - 4, R3000E_DBE << 2);
return 0;
}
return 0;
}
if (unlikely(BUS_LOCKED_ADDR(addr))) {
+ log_unhandled("bus error write addr=%08x @%08x ra=%08x\n",
+ addr, regs->pc - 4, regs->GPR.n.ra);
intException(regs, regs->pc - 4, R3000E_DBE << 2);
return 0;
}
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) {
*********************************************************/
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]);
}
// SysPrintf("MTC0 %d: %x\n", reg, val);
switch (reg) {
case 12: // SR
- if (unlikely((regs_->CP0.n.SR ^ val) & (1 << 16)))
+ if (unlikely((regs_->CP0.n.SR ^ val) & (1u << 16)))
psxMemOnIsolate((val >> 16) & 1);
- if (unlikely((regs_->CP0.n.SR ^ val) & (7 << 29)))
+ if (unlikely((regs_->CP0.n.SR ^ val) & (7u << 29)))
setupCop(val);
regs_->CP0.n.SR = val;
psxTestSWInts(regs_, 1);
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(psxNULL) {
psxNULLne(regs_);
-#ifdef DO_EXCEPTION_RESERVEDI
- intExceptionInsn(regs_, R3000E_RI << 2);
-#endif
+ intExceptionReservedInsn(regs_);
}
void gteNULL(struct psxCP2Regs *regs) {
psxSWCx(regs_, code);
return;
}
+ dloadFlush(regs_);
psxHLEt[hleCode]();
+ regs_->branchSeen = 1;
}
static void (INT_ATTR *psxBSC[64])(psxRegisters *regs_, u32 code) = {
///////////////////////////////////////////
static int intInit() {
+ intApplyConfig();
return 0;
}
psxBSC[regs->code >> 26](regs, regs->code);
}
-static void intExecute() {
- psxRegisters *regs_ = &psxRegs;
+static void intExecute(psxRegisters *regs) {
+ u8 **memRLUT = psxMemRLUT;
+
+ while (!regs->stop)
+ execI_(memRLUT, regs);
+}
+
+static void intExecuteBp(psxRegisters *regs) {
u8 **memRLUT = psxMemRLUT;
- extern int stop;
- while (!stop)
- execI_(memRLUT, regs_);
+ while (!regs->stop)
+ execIbp(memRLUT, regs);
}
-static void intExecuteBp() {
- psxRegisters *regs_ = &psxRegs;
+static void intExecuteBlock(psxRegisters *regs, enum blockExecCaller caller) {
u8 **memRLUT = psxMemRLUT;
- extern int stop;
- while (!stop)
- execIbp(memRLUT, regs_);
+ regs->branchSeen = 0;
+ while (!regs->branchSeen)
+ execI_(memRLUT, regs);
}
-void intExecuteBlock(enum blockExecCaller caller) {
- psxRegisters *regs_ = &psxRegs;
+static void intExecuteBlockBp(psxRegisters *regs, enum blockExecCaller caller) {
u8 **memRLUT = psxMemRLUT;
- branchSeen = 0;
- while (!branchSeen)
- execI_(memRLUT, regs_);
+ regs->branchSeen = 0;
+ while (!regs->branchSeen)
+ execIbp(memRLUT, regs);
}
static void intClear(u32 Addr, u32 Size) {
setupCop(psxRegs.CP0.n.SR);
// fallthrough
case R3000ACPU_NOTIFY_CACHE_ISOLATED: // Armored Core?
- memset(&ICache, 0xff, sizeof(ICache));
+ if (fetch == fetchICache)
+ memset(&ICache, 0xff, sizeof(ICache));
break;
case R3000ACPU_NOTIFY_CACHE_UNISOLATED:
break;
psxSPC[0x08] = psxJRe;
psxSPC[0x09] = psxJALRe;
psxInt.Execute = intExecuteBp;
+ psxInt.ExecuteBlock = intExecuteBlockBp;
} else {
psxBSC[0x20] = psxLB;
psxBSC[0x21] = psxLH;
psxSPC[0x08] = psxJR;
psxSPC[0x09] = psxJALR;
psxInt.Execute = intExecute;
+ psxInt.ExecuteBlock = intExecuteBlock;
}
// the dynarec may occasionally call the interpreter, in such a case the
// cache won't work (cache only works right if all fetches go through it)
- if (!Config.icache_emulation || psxCpu != &psxInt)
+ if (!Config.icache_emulation || psxCpu != &psxInt) {
fetch = fetchNoCache;
+ memset(&ICache, 0xff, sizeof(ICache));
+ }
else
fetch = fetchICache;
}
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 = {