+// load delay
+static void doLoad(psxRegisters *regs, u32 r, u32 val)
+{
+#ifdef HANDLE_LOAD_DELAY
+ int sel = regs->dloadSel ^ 1;
+ assert(regs->dloadReg[sel] == 0);
+ regs->dloadReg[sel] = r;
+ regs->dloadVal[sel] = r ? val : 0;
+ if (regs->dloadReg[sel ^ 1] == r)
+ regs->dloadVal[sel ^ 1] = regs->dloadReg[sel ^ 1] = 0;
+#else
+ regs->GPR.r[r] = r ? val : 0;
+#endif
+}
+
+static void dloadRt(psxRegisters *regs, u32 r, u32 val)
+{
+#ifdef HANDLE_LOAD_DELAY
+ int sel = regs->dloadSel;
+ if (unlikely(regs->dloadReg[sel] == r))
+ regs->dloadVal[sel] = regs->dloadReg[sel] = 0;
+#endif
+ regs->GPR.r[r] = r ? val : 0;
+}
+
+static void dloadStep(psxRegisters *regs)
+{
+#ifdef HANDLE_LOAD_DELAY
+ int sel = regs->dloadSel;
+ regs->GPR.r[regs->dloadReg[sel]] = regs->dloadVal[sel];
+ regs->dloadVal[sel] = regs->dloadReg[sel] = 0;
+ regs->dloadSel ^= 1;
+ assert(regs->GPR.r[0] == 0);
+#endif
+}
+
+static void dloadFlush(psxRegisters *regs)
+{
+#ifdef HANDLE_LOAD_DELAY
+ regs->GPR.r[regs->dloadReg[0]] = regs->dloadVal[0];
+ regs->GPR.r[regs->dloadReg[1]] = regs->dloadVal[1];
+ regs->dloadVal[0] = regs->dloadVal[1] = 0;
+ regs->dloadReg[0] = regs->dloadReg[1] = 0;
+ assert(regs->GPR.r[0] == 0);
+#endif
+}
+
+static void dloadClear(psxRegisters *regs)
+{
+#ifdef HANDLE_LOAD_DELAY
+ regs->dloadVal[0] = regs->dloadVal[1] = 0;
+ regs->dloadReg[0] = regs->dloadReg[1] = 0;
+ regs->dloadSel = 0;
+#endif
+}
+
+static void intException(psxRegisters *regs, u32 pc, u32 cause)
+{
+ dloadFlush(regs);
+ regs->pc = pc;
+ psxException(cause, branch, ®s->CP0);
+}
+
+// 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))
+ return 0; // nop
+ code = (u32 *)(base + (pc & 0xfffc));
+ return SWAP32(*code);
+
+}
+
+static u32 INT_ATTR fetchNoCache(psxRegisters *regs, u8 **memRLUT, u32 pc)