target/ppc: Fixed call to deferred exception

mtfsf, mtfsfi and mtfsb1 instructions call helper_float_check_status
after updating the value of FPSCR, but helper_float_check_status
checks fp_status and fp_status isn't updated based on FPSCR and
since the value of fp_status is reset earlier in the instruction,
it's always 0.

Because of this helper_float_check_status would change the FI bit to 0
as this bit checks if the last operation was inexact and
float_flag_inexact is always 0.

These instructions also don't throw exceptions correctly since
helper_float_check_status throw exceptions based on fp_status.

This commit created a new helper, helper_fpscr_check_status that checks
FPSCR value instead of fp_status and checks for a larger variety of
exceptions than do_float_check_status.

Since fp_status isn't used, gen_reset_fpstatus() was removed.

The hardware used to compare QEMU's behavior to was a Power9.

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Lucas Mateus Castro (alqotel) <lucas.araujo@eldorado.org.br>
Message-Id: <20211201163808.440385-2-lucas.araujo@eldorado.org.br>
Signed-off-by: Cédric Le Goater <clg@kaod.org>
This commit is contained in:
Lucas Mateus Castro (alqotel) 2021-12-17 17:57:12 +01:00 committed by Cédric Le Goater
parent 83234b8289
commit c3a824b0cf
3 changed files with 52 additions and 6 deletions

View file

@ -414,6 +414,54 @@ void helper_store_fpscr(CPUPPCState *env, uint64_t val, uint32_t nibbles)
ppc_store_fpscr(env, val);
}
void helper_fpscr_check_status(CPUPPCState *env)
{
CPUState *cs = env_cpu(env);
target_ulong fpscr = env->fpscr;
int error = 0;
if ((fpscr & FP_OX) && (fpscr & FP_OE)) {
error = POWERPC_EXCP_FP_OX;
} else if ((fpscr & FP_UX) && (fpscr & FP_UE)) {
error = POWERPC_EXCP_FP_UX;
} else if ((fpscr & FP_XX) && (fpscr & FP_XE)) {
error = POWERPC_EXCP_FP_XX;
} else if ((fpscr & FP_ZX) && (fpscr & FP_ZE)) {
error = POWERPC_EXCP_FP_ZX;
} else if (fpscr & FP_VE) {
if (fpscr & FP_VXSOFT) {
error = POWERPC_EXCP_FP_VXSOFT;
} else if (fpscr & FP_VXSNAN) {
error = POWERPC_EXCP_FP_VXSNAN;
} else if (fpscr & FP_VXISI) {
error = POWERPC_EXCP_FP_VXISI;
} else if (fpscr & FP_VXIDI) {
error = POWERPC_EXCP_FP_VXIDI;
} else if (fpscr & FP_VXZDZ) {
error = POWERPC_EXCP_FP_VXZDZ;
} else if (fpscr & FP_VXIMZ) {
error = POWERPC_EXCP_FP_VXIMZ;
} else if (fpscr & FP_VXVC) {
error = POWERPC_EXCP_FP_VXVC;
} else if (fpscr & FP_VXSQRT) {
error = POWERPC_EXCP_FP_VXSQRT;
} else if (fpscr & FP_VXCVI) {
error = POWERPC_EXCP_FP_VXCVI;
} else {
return;
}
} else {
return;
}
cs->exception_index = POWERPC_EXCP_PROGRAM;
env->error_code = error | POWERPC_EXCP_FP;
/* Deferred floating-point exception after target FPSCR update */
if (fp_exceptions_enabled(env)) {
raise_exception_err_ra(env, cs->exception_index,
env->error_code, GETPC());
}
}
static void do_float_check_status(CPUPPCState *env, uintptr_t raddr)
{
CPUState *cs = env_cpu(env);