mirror of
https://github.com/dingusdev/dingusppc.git
synced 2024-12-27 00:29:18 +00:00
poweropcodes: Fix div.
dividend is supposed to be a twos compliment number. Fix test for dividend = -0x80000000 and divisor = -1. Previously, the test was assuming dividend was a 32-bit value from rA. 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.
This commit is contained in:
parent
ff626ae0b5
commit
88aa249ce1
@ -98,23 +98,39 @@ void dppc_interpreter::power_div() {
|
|||||||
uint32_t ppc_result_d;
|
uint32_t ppc_result_d;
|
||||||
ppc_grab_regsdab(ppc_cur_instruction);
|
ppc_grab_regsdab(ppc_cur_instruction);
|
||||||
|
|
||||||
uint64_t dividend = ((uint64_t)ppc_result_a << 32) | ppc_state.spr[SPR::MQ];
|
int64_t dividend = (uint64_t(ppc_result_a) << 32) | ppc_state.spr[SPR::MQ];
|
||||||
int32_t divisor = ppc_result_b;
|
int32_t divisor = ppc_result_b;
|
||||||
|
int64_t quotient;
|
||||||
|
int32_t remainder;
|
||||||
|
|
||||||
if ((ppc_result_a == 0x80000000UL && divisor == -1) || !divisor) {
|
if (dividend == -0x80000000 && divisor == -1) {
|
||||||
ppc_state.spr[SPR::MQ] = 0;
|
remainder = 0;
|
||||||
ppc_result_d = 0x80000000UL; // -2^31 aka INT32_MIN
|
ppc_result_d = 0x80000000U; // -2^31 aka INT32_MIN
|
||||||
|
if (ov)
|
||||||
|
ppc_state.spr[SPR::XER] |= XER::SO | XER::OV;
|
||||||
|
} else if (!divisor) {
|
||||||
|
remainder = 0;
|
||||||
|
ppc_result_d = 0x80000000U; // -2^31 aka INT32_MIN
|
||||||
|
if (ov)
|
||||||
|
ppc_state.spr[SPR::XER] |= XER::SO | XER::OV;
|
||||||
} else {
|
} else {
|
||||||
ppc_result_d = uint32_t(dividend / divisor);
|
quotient = dividend / divisor;
|
||||||
ppc_state.spr[SPR::MQ] = dividend % divisor;
|
remainder = dividend % divisor;
|
||||||
|
ppc_result_d = uint32_t(quotient);
|
||||||
|
if (ov) {
|
||||||
|
if (((quotient >> 31) + 1) & ~1) {
|
||||||
|
ppc_state.spr[SPR::XER] |= XER::SO | XER::OV;
|
||||||
|
} else {
|
||||||
|
ppc_state.spr[SPR::XER] &= ~XER::OV;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ov)
|
|
||||||
power_setsoov(ppc_result_b, ppc_result_a, ppc_result_d);
|
|
||||||
if (rec)
|
if (rec)
|
||||||
ppc_changecrf0(ppc_result_d);
|
ppc_changecrf0(remainder);
|
||||||
|
|
||||||
ppc_store_iresult_reg(reg_d, ppc_result_d);
|
ppc_store_iresult_reg(reg_d, ppc_result_d);
|
||||||
|
ppc_state.spr[SPR::MQ] = remainder;
|
||||||
}
|
}
|
||||||
|
|
||||||
template void dppc_interpreter::power_div<RC0, OV0>();
|
template void dppc_interpreter::power_div<RC0, OV0>();
|
||||||
|
Loading…
Reference in New Issue
Block a user