mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-26 18:25:35 -04:00
welll
This commit is contained in:
@@ -77,6 +77,26 @@ int g_precise_mode = 0;
|
||||
int g_ls_dirty_observe = 0;
|
||||
extern int g_ls_replay_active; /* defined in the lockstep section; used by exec_one's jal/jalr guard */
|
||||
|
||||
/* ===== Minimal exception delivery from the interpreter path =====
|
||||
* Sets COP0 registers (BadVAddr, Cause, EPC, Status) and redirects PC to the
|
||||
* hardware exception vector. Used for alignment errors caught by the
|
||||
* interpreter. Returns 1 (control transferred). */
|
||||
static int interp_exception(CPUState *cpu, uint32_t exc_code,
|
||||
uint32_t badvaddr, uint32_t epc_pc) {
|
||||
uint32_t sr = cpu->cop0[12];
|
||||
/* BadVAddr */
|
||||
cpu->cop0[8] = badvaddr;
|
||||
/* Cause: ExcCode, clear BD (not tracking delay-slot exception here) */
|
||||
cpu->cop0[13] = (cpu->cop0[13] & ~0x8000007Cu) | (exc_code << 2);
|
||||
/* Push SR exception stack: shift bits [5:0] left by 2 */
|
||||
cpu->cop0[12] = (sr & ~0x3Fu) | ((sr & 0x0Fu) << 2);
|
||||
/* EPC */
|
||||
cpu->cop0[14] = epc_pc;
|
||||
/* Vector: BEV selects between KSEG1 (BIOS ROM) and KSEG0 (RAM) */
|
||||
cpu->pc = (sr & 0x00400000u) ? 0xBFC00180u : 0x80000080u;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef PSX_COSIM
|
||||
static int g_cosim_exec_one_hooked = 0;
|
||||
static void cosim_exec_one_begin(void) { g_cosim_exec_one_hooked = 0; }
|
||||
@@ -1248,6 +1268,7 @@ static int exec_one(CPUState *cpu, uint32_t pc, uint32_t *next_pc_out) {
|
||||
return 0;
|
||||
case 0x08: { /* JR rs */
|
||||
uint32_t target = cpu->gpr[rs];
|
||||
if (target & 3) return interp_exception(cpu, 4, target, pc); /* LoadAddressError */
|
||||
exec_delay_slot(cpu, pc + 4);
|
||||
cosim_exec_one_transfer_hook(pc + 4);
|
||||
/* crossing (if target is compiled) is counted at the block-loop
|
||||
@@ -1258,6 +1279,7 @@ static int exec_one(CPUState *cpu, uint32_t pc, uint32_t *next_pc_out) {
|
||||
}
|
||||
case 0x09: { /* JALR rd, rs */
|
||||
uint32_t target = cpu->gpr[rs];
|
||||
if (target & 3) return interp_exception(cpu, 4, target, pc); /* LoadAddressError */
|
||||
uint32_t return_pc = pc + 8;
|
||||
cpu->gpr[rd ? rd : 31] = return_pc;
|
||||
cpu->gpr[0] = 0;
|
||||
@@ -1587,18 +1609,74 @@ static int exec_one(CPUState *cpu, uint32_t pc, uint32_t *next_pc_out) {
|
||||
#ifdef PSX_ENABLE_BLOCK_CYCLES
|
||||
cpu->ld_absorb = 0u;
|
||||
cpu->ld_which_t = (uint8_t)rt;
|
||||
#endif
|
||||
cpu->gpr[rt] = cpu->cop0[rd];
|
||||
cpu->gpr[0] = 0;
|
||||
return 0;
|
||||
}
|
||||
if (cop_op == 0x02) { /* CFC0 — identical to MFC0 on PSX */
|
||||
#ifdef PSX_ENABLE_BLOCK_CYCLES
|
||||
cpu->ld_absorb = 0u;
|
||||
cpu->ld_which_t = (uint8_t)rt;
|
||||
#endif
|
||||
cpu->gpr[rt] = cpu->cop0[rd];
|
||||
cpu->gpr[0] = 0;
|
||||
return 0;
|
||||
}
|
||||
if (cop_op == 0x04) { /* MTC0 */
|
||||
cpu->cop0[rd] = cpu->gpr[rt];
|
||||
uint32_t val = cpu->gpr[rt];
|
||||
if (rd == 13) {
|
||||
/* Cause register: bits [15:10] are software IP (R/W),
|
||||
* bits [9:8] are hardware IP (read-only from software),
|
||||
* ExcCode [6:2] is read-only. Only allow writes to [15:10]. */
|
||||
cpu->cop0[13] = (cpu->cop0[13] & 0x03FFu) | (val & 0xFC00u);
|
||||
} else {
|
||||
cpu->cop0[rd] = val;
|
||||
}
|
||||
/* psxTestSWInts: after writing Status or Cause, check if a
|
||||
* software interrupt is now deliverable (Cause & Status & 0x0300
|
||||
* with Status.IEc set). Matches PCSX-Redux's MTC0 path. */
|
||||
if ((rd == 12 /* Status */ || rd == 13 /* Cause */) &&
|
||||
(cpu->cop0[13] & cpu->cop0[12] & 0x0300u) &&
|
||||
(cpu->cop0[12] & 0x1u)) {
|
||||
g_dirty_safe_resume_pc = pc + 4;
|
||||
cpu->pc = pc + 4;
|
||||
psx_check_interrupts(cpu);
|
||||
g_dirty_safe_resume_pc = 0;
|
||||
return (cpu->pc != pc + 4); /* transferred if exception taken */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (cop_op == 0x06) { /* CTC0 — identical to MTC0 on PSX */
|
||||
uint32_t val = cpu->gpr[rt];
|
||||
if (rd == 13) {
|
||||
cpu->cop0[13] = (cpu->cop0[13] & 0x03FFu) | (val & 0xFC00u);
|
||||
} else {
|
||||
cpu->cop0[rd] = val;
|
||||
}
|
||||
if ((rd == 12 || rd == 13) &&
|
||||
(cpu->cop0[13] & cpu->cop0[12] & 0x0300u) &&
|
||||
(cpu->cop0[12] & 0x1u)) {
|
||||
g_dirty_safe_resume_pc = pc + 4;
|
||||
cpu->pc = pc + 4;
|
||||
psx_check_interrupts(cpu);
|
||||
g_dirty_safe_resume_pc = 0;
|
||||
return (cpu->pc != pc + 4);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (cop_op == 0x10 && fnt == 0x10) { /* RFE */
|
||||
uint32_t sr = cpu->cop0[12];
|
||||
cpu->cop0[12] = (sr & 0xFFFFFFF0u) | ((sr >> 2) & 0x0Fu);
|
||||
/* psxTestSWInts: after RFE, interrupts may become deliverable. */
|
||||
if ((cpu->cop0[13] & cpu->cop0[12] & 0x0300u) &&
|
||||
(cpu->cop0[12] & 0x1u)) {
|
||||
g_dirty_safe_resume_pc = pc + 4;
|
||||
cpu->pc = pc + 4;
|
||||
psx_check_interrupts(cpu);
|
||||
g_dirty_safe_resume_pc = 0;
|
||||
return (cpu->pc != pc + 4);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return abort_unsupported(pc, insn, "COP0 op");
|
||||
@@ -1656,6 +1734,7 @@ static int exec_one(CPUState *cpu, uint32_t pc, uint32_t *next_pc_out) {
|
||||
}
|
||||
case 0x21: { /* LH */
|
||||
uint32_t addr = cpu->gpr[rs] + (uint32_t)simm;
|
||||
if (addr & 1) return interp_exception(cpu, 4, addr, pc); /* LoadAddressError */
|
||||
cpu->gpr[rt] = (uint32_t)(int32_t)(int16_t)psx_cyc_load_half(cpu, addr, rt, 1u << rs);
|
||||
cpu->gpr[0] = 0;
|
||||
return 0;
|
||||
@@ -1669,6 +1748,7 @@ static int exec_one(CPUState *cpu, uint32_t pc, uint32_t *next_pc_out) {
|
||||
}
|
||||
case 0x23: { /* LW */
|
||||
uint32_t addr = cpu->gpr[rs] + (uint32_t)simm;
|
||||
if (addr & 3) return interp_exception(cpu, 4, addr, pc); /* LoadAddressError */
|
||||
cpu->gpr[rt] = psx_cyc_load_word(cpu, addr, rt, 1u << rs);
|
||||
cpu->gpr[0] = 0;
|
||||
return 0;
|
||||
@@ -1681,6 +1761,7 @@ static int exec_one(CPUState *cpu, uint32_t pc, uint32_t *next_pc_out) {
|
||||
}
|
||||
case 0x25: { /* LHU */
|
||||
uint32_t addr = cpu->gpr[rs] + (uint32_t)simm;
|
||||
if (addr & 1) return interp_exception(cpu, 4, addr, pc); /* LoadAddressError */
|
||||
cpu->gpr[rt] = (uint32_t)psx_cyc_load_half(cpu, addr, rt, 1u << rs);
|
||||
cpu->gpr[0] = 0;
|
||||
return 0;
|
||||
@@ -1699,6 +1780,7 @@ static int exec_one(CPUState *cpu, uint32_t pc, uint32_t *next_pc_out) {
|
||||
}
|
||||
case 0x29: { /* SH */
|
||||
uint32_t addr = cpu->gpr[rs] + (uint32_t)simm;
|
||||
if (addr & 1) return interp_exception(cpu, 5, addr, pc); /* StoreAddressError */
|
||||
uint16_t val = (uint16_t)cpu->gpr[rt];
|
||||
/* Widescreen backdrop screenX squash on the interpreter path: mirrors
|
||||
* the recompiler emit at [widescreen.backdrop] x_sites. Overlay code
|
||||
@@ -1717,6 +1799,7 @@ static int exec_one(CPUState *cpu, uint32_t pc, uint32_t *next_pc_out) {
|
||||
}
|
||||
case 0x2B: { /* SW */
|
||||
uint32_t addr = cpu->gpr[rs] + (uint32_t)simm;
|
||||
if (addr & 3) return interp_exception(cpu, 5, addr, pc); /* StoreAddressError */
|
||||
cpu->write_word(addr, cpu->gpr[rt]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user