From 0d1ce68d191ae46a3afa7dbccd82c69c25747e32 Mon Sep 17 00:00:00 2001 From: joevt Date: Tue, 9 Apr 2024 01:31:09 -0700 Subject: [PATCH] poweropcodes: Fix divs. dividend and divisor are supposed to be a twos compliment numbers. Fix OV calculation. Previously, it was using power_setsoov which I think is only for add and subtract operations. Fix CR calculation. It depends on the remainder, not the quotient. --- cpu/ppc/poweropcodes.cpp | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/cpu/ppc/poweropcodes.cpp b/cpu/ppc/poweropcodes.cpp index fb099b5..293d709 100644 --- a/cpu/ppc/poweropcodes.cpp +++ b/cpu/ppc/poweropcodes.cpp @@ -140,16 +140,31 @@ template void dppc_interpreter::power_div(); template void dppc_interpreter::power_divs() { + uint32_t ppc_result_d; + int32_t remainder; ppc_grab_regsdab(ppc_cur_instruction); - uint32_t ppc_result_d = ppc_result_a / ppc_result_b; - ppc_state.spr[SPR::MQ] = (ppc_result_a % ppc_result_b); - if (ov) - power_setsoov(ppc_result_b, ppc_result_a, ppc_result_d); + if (!ppc_result_b) { // handle the "anything / 0" case + ppc_result_d = -1; + remainder = ppc_result_a; + if (ov) + ppc_state.spr[SPR::XER] |= XER::SO | XER::OV; + } else if (ppc_result_a == 0x80000000U && ppc_result_b == 0xFFFFFFFFU) { + ppc_result_d = 0x80000000U; + remainder = 0; + if (ov) + ppc_state.spr[SPR::XER] |= XER::SO | XER::OV; + } else { // normal signed devision + ppc_result_d = int32_t(ppc_result_a) / int32_t(ppc_result_b); + remainder = (int32_t(ppc_result_a) % int32_t(ppc_result_b)); + if (ov) + ppc_state.spr[SPR::XER] &= ~XER::OV; + } if (rec) - ppc_changecrf0(ppc_result_d); + ppc_changecrf0(remainder); ppc_store_iresult_reg(reg_d, ppc_result_d); + ppc_state.spr[SPR::MQ] = remainder; } template void dppc_interpreter::power_divs();