diff --git a/crates/xenia-cpu/src/interpreter.rs b/crates/xenia-cpu/src/interpreter.rs index 31d54f5..4f0b8e6 100644 --- a/crates/xenia-cpu/src/interpreter.rs +++ b/crates/xenia-cpu/src/interpreter.rs @@ -982,6 +982,16 @@ fn execute(ctx: &mut PpcContext, mem: &dyn MemoryAccess, instr: &DecodedInstr) - // ===== System call ===== PpcOpcode::sc => { + // PPCBUG-064: log non-zero LEV (`sc 2` is the Xbox 360 hypervisor-call + // convention; canary dispatches it to a different handler than `sc 0`). + // Routing LEV=2 requires a StepResult variant extension; deferred. + let lev = (instr.raw >> 5) & 0x7F; + if lev != 0 { + tracing::warn!( + "sc with LEV={} at {:#010x}: dispatched as plain SystemCall (HVcall routing not implemented)", + lev, ctx.pc + ); + } ctx.pc += 4; return StepResult::SystemCall; } @@ -1733,6 +1743,14 @@ fn execute(ctx: &mut PpcContext, mem: &dyn MemoryAccess, instr: &DecodedInstr) - // ===== Trap ===== PpcOpcode::tw | PpcOpcode::twi | PpcOpcode::td | PpcOpcode::tdi => { + // PPCBUG-063: save CIA before incrementing so a trap handler reads + // the faulting instruction address, not CIA+4. + // PPCBUG-065: log the SIMM type code on `twi 31, r0, IMM` (Xbox 360 + // typed-trap convention used by the CRT/kernel for C++ exception + // class dispatch). The audit notes this is relevant to the Sylpheed + // throw investigation; routing the type code via a payload requires + // a StepResult enum extension that's deferred for now. + let trap_pc = ctx.pc; let a = ctx.gpr[instr.ra()]; let b = match instr.opcode { PpcOpcode::twi | PpcOpcode::tdi => instr.simm16() as i64 as u64, @@ -1743,14 +1761,21 @@ fn execute(ctx: &mut PpcContext, mem: &dyn MemoryAccess, instr: &DecodedInstr) - _ => trap::TrapWidth::Doubleword, }; let fired = trap::evaluate(instr.to(), a, b, width); - ctx.pc += 4; if fired { + let typed_trap_simm = if matches!(instr.opcode, PpcOpcode::twi) + && instr.to() == 31 && instr.ra() == 0 { + Some(instr.simm16() as u16) + } else { None }; tracing::warn!( - "Trap fired at {:#010x}: {:?} TO={} a={:#x} b={:#x}", - ctx.pc.wrapping_sub(4), instr.opcode, instr.to(), a, b + "Trap fired at {:#010x}: {:?} TO={} a={:#x} b={:#x}{}", + trap_pc, instr.opcode, instr.to(), a, b, + typed_trap_simm.map_or(String::new(), |t| format!(" typed_trap_simm={:#06x}", t)) ); + // Leave ctx.pc at CIA (NOT NIA) so trap handlers / SEH delivery + // can read the faulting instruction address from ctx.pc. return StepResult::Trap; } + ctx.pc += 4; } // ===== Byte-reverse loads =====