From c90a18eca18bc4d9ea178d63edc48a7f5f126e8b Mon Sep 17 00:00:00 2001 From: Mihai Parparita Date: Fri, 9 Oct 2026 15:54:15 -0700 Subject: [PATCH 1/2] ppc: allow rA=0 for 601 integer store-update instructions Normally rA (where the effective address is stored) cannot be 0, but the MPC601 user manual explicitly says that it's allowed for POWER compatibility (the update is skipped in that case). Fixes mouse movement in Barrack under on the 6100, which would previously stop executing because of an illegal opcode exeception being raised (and unhandled). --- cpu/ppc/ppcopcodes.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/cpu/ppc/ppcopcodes.cpp b/cpu/ppc/ppcopcodes.cpp index 9fc410d9a1..4638776e18 100644 --- a/cpu/ppc/ppcopcodes.cpp +++ b/cpu/ppc/ppcopcodes.cpp @@ -1700,11 +1700,13 @@ void dppc_interpreter::ppc_stu(uint32_t opcode) { #endif ppc_grab_regssa(opcode); - if (reg_a != 0) { + // MPC601 permits RA=0 for POWER compatibility and suppresses the update. + if (reg_a != 0 || is_601) { uint32_t ea = int32_t(int16_t(opcode)); - ea += ppc_result_a; + ea += reg_a ? ppc_result_a : 0; mmu_write_vmem(opcode, ea, ppc_result_d); - ppc_state.gpr[reg_a] = ea; + if (reg_a != 0) + ppc_state.gpr[reg_a] = ea; } else { ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP); @@ -1723,10 +1725,12 @@ void dppc_interpreter::ppc_stux(uint32_t opcode) { #endif ppc_grab_regssab(opcode); - if (reg_a != 0) { - uint32_t ea = ppc_result_a + ppc_result_b; + // MPC601 permits RA=0 for POWER compatibility and suppresses the update. + if (reg_a != 0 || is_601) { + uint32_t ea = (reg_a ? ppc_result_a : 0) + ppc_result_b; mmu_write_vmem(opcode, ea, ppc_result_d); - ppc_state.gpr[reg_a] = ea; + if (reg_a != 0) + ppc_state.gpr[reg_a] = ea; } else { ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP); From 63a3fdcb850fe494802dac6320f937638e64699a Mon Sep 17 00:00:00 2001 From: Mihai Parparita Date: Fri, 9 Oct 2026 15:48:34 -0700 Subject: [PATCH 2/2] ppc: make illegal instructions more obvious Log a warning whenever an illegal opcode exception is being raised, since it's usually a clue that we have a correctness bug. Just a warning (as opposed to an error) because the guest OS may handle the exception and continue execution. --- cpu/ppc/ppcexec.cpp | 11 +++++++++++ cpu/ppc/ppcfpopcodes.cpp | 16 ++++++++-------- cpu/ppc/ppcmmu.cpp | 2 +- cpu/ppc/ppcopcodes.cpp | 28 ++++++++++++++-------------- 4 files changed, 34 insertions(+), 23 deletions(-) diff --git a/cpu/ppc/ppcexec.cpp b/cpu/ppc/ppcexec.cpp index 3248165486..2a1371b120 100644 --- a/cpu/ppc/ppcexec.cpp +++ b/cpu/ppc/ppcexec.cpp @@ -275,6 +275,17 @@ PPCOpcode* ppc_opcode_grabber = OpcodeGrabberNoFPU; /** Exception helpers. */ void ppc_illegalop(uint32_t opcode) { + // Zero values are used as sentinels in the TNT ROM and are thus somewhat + // common, don't log them. + if (opcode) { + PPCDisasmContext ctx; + ctx.instr_code = opcode; + ctx.instr_addr = 0; + ctx.simplified = false; + auto op_name = disassemble_single(&ctx); + LOG_F(WARNING, "Illegal opcode exception raised for 0x%08x (decoded as %s). The PC was 0x%08x.", opcode, op_name.c_str(), ppc_state.pc); + } + ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP); } diff --git a/cpu/ppc/ppcfpopcodes.cpp b/cpu/ppc/ppcfpopcodes.cpp index 88263b0faf..d62deb9b5f 100644 --- a/cpu/ppc/ppcfpopcodes.cpp +++ b/cpu/ppc/ppcfpopcodes.cpp @@ -1025,7 +1025,7 @@ void dppc_interpreter::ppc_lfsu(uint32_t opcode) { ppc_store_iresult_reg(reg_a, ea); } else { - ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP); + ppc_illegalop(opcode); } } @@ -1046,7 +1046,7 @@ void dppc_interpreter::ppc_lfsux(uint32_t opcode) { ppc_store_iresult_reg(reg_a, ea); } else { - ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP); + ppc_illegalop(opcode); return; } } @@ -1070,7 +1070,7 @@ void dppc_interpreter::ppc_lfdu(uint32_t opcode) { ppc_store_iresult_reg(reg_a, ea); } else { - ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP); + ppc_illegalop(opcode); } } @@ -1091,7 +1091,7 @@ void dppc_interpreter::ppc_lfdux(uint32_t opcode) { ppc_store_iresult_reg(reg_a, ea); } else { - ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP); + ppc_illegalop(opcode); } } @@ -1114,7 +1114,7 @@ void dppc_interpreter::ppc_stfsu(uint32_t opcode) { ppc_store_iresult_reg(reg_a, ea); } else { - ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP); + ppc_illegalop(opcode); } } @@ -1135,7 +1135,7 @@ void dppc_interpreter::ppc_stfsux(uint32_t opcode) { ppc_store_iresult_reg(reg_a, ea); } else { - ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP); + ppc_illegalop(opcode); } } @@ -1156,7 +1156,7 @@ void dppc_interpreter::ppc_stfdu(uint32_t opcode) { ppc_store_iresult_reg(reg_a, ea); } else { - ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP); + ppc_illegalop(opcode); } } @@ -1175,7 +1175,7 @@ void dppc_interpreter::ppc_stfdux(uint32_t opcode) { ppc_store_iresult_reg(reg_a, ea); } else { - ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP); + ppc_illegalop(opcode); } } diff --git a/cpu/ppc/ppcmmu.cpp b/cpu/ppc/ppcmmu.cpp index 765b51a30b..09c434a752 100644 --- a/cpu/ppc/ppcmmu.cpp +++ b/cpu/ppc/ppcmmu.cpp @@ -1088,7 +1088,7 @@ static void mpc601_bat_update(uint32_t bat_reg) static void mpc601_dbat_update(uint32_t /*bat_reg*/) { - // ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP); + // ppc_illegalop(opcode); } static void ppc_ibat_update(uint32_t bat_reg) diff --git a/cpu/ppc/ppcopcodes.cpp b/cpu/ppc/ppcopcodes.cpp index 4638776e18..3faeaa7713 100644 --- a/cpu/ppc/ppcopcodes.cpp +++ b/cpu/ppc/ppcopcodes.cpp @@ -1002,14 +1002,14 @@ void dppc_interpreter::ppc_mfspr(uint32_t opcode) { switch (ref_spr) { case SPR::MQ: if (!(is_601 || include_601)) { - ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP); + ppc_illegalop(opcode); return; } ppc_state.gpr[reg_d] = ppc_state.spr[ref_spr]; break; case SPR::RTCL_U: if (!is_601) { - ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP); + ppc_illegalop(opcode); return; } calc_rtcl_value(); @@ -1019,7 +1019,7 @@ void dppc_interpreter::ppc_mfspr(uint32_t opcode) { break; case SPR::RTCU_U: if (!is_601) { - ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP); + ppc_illegalop(opcode); return; } calc_rtcl_value(); @@ -1029,7 +1029,7 @@ void dppc_interpreter::ppc_mfspr(uint32_t opcode) { break; case SPR::DEC_U: if (!is_601) { - ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP); + ppc_illegalop(opcode); return; } // fallthrough @@ -1093,13 +1093,13 @@ void dppc_interpreter::ppc_mtspr(uint32_t opcode) { if (is_601 || include_601) ppc_state.spr[ref_spr] = val; else - ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP); + ppc_illegalop(opcode); break; case SPR::RTCL_U: case SPR::RTCU_U: case SPR::DEC_U: if (!is_601) { - ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP); + ppc_illegalop(opcode); } break; case SPR::XER: @@ -1214,7 +1214,7 @@ void dppc_interpreter::ppc_mftb(uint32_t opcode) { ppc_state.spr[TBL_S] = uint32_t(tbr_value); break; default: - ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP); + ppc_illegalop(opcode); } } @@ -1709,7 +1709,7 @@ void dppc_interpreter::ppc_stu(uint32_t opcode) { ppc_state.gpr[reg_a] = ea; } else { - ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP); + ppc_illegalop(opcode); } } @@ -1733,7 +1733,7 @@ void dppc_interpreter::ppc_stux(uint32_t opcode) { ppc_state.gpr[reg_a] = ea; } else { - ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP); + ppc_illegalop(opcode); } } @@ -1825,7 +1825,7 @@ void dppc_interpreter::ppc_lzu(uint32_t opcode) { ppc_result_a = ea; ppc_store_iresult_reg(reg_a, ppc_result_a); } else { - ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP); + ppc_illegalop(opcode); } } @@ -1861,7 +1861,7 @@ void dppc_interpreter::ppc_lzux(uint32_t opcode) { ppc_result_a = ea; ppc_store_iresult_reg(reg_a, ppc_result_a); } else { - ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP); + ppc_illegalop(opcode); } } @@ -1893,7 +1893,7 @@ void dppc_interpreter::ppc_lhau(uint32_t opcode) { ppc_result_a = ea; ppc_store_iresult_reg(reg_a, ppc_result_a); } else { - ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP); + ppc_illegalop(opcode); } } @@ -1910,7 +1910,7 @@ void dppc_interpreter::ppc_lhaux(uint32_t opcode) { ppc_store_iresult_reg(reg_a, ppc_result_a); } else { - ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP); + ppc_illegalop(opcode); } } @@ -2018,7 +2018,7 @@ void dppc_interpreter::ppc_lswx(uint32_t opcode) { if ((reg_d == 0 && reg_a == 0) || (reg_d == reg_a) || (reg_d == reg_b)) { // UNTESTED! Does invalid form really cause exception? // G4 doesn't do exception - ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP); + ppc_illegalop(opcode); } */