mirror of https://github.com/xemu-project/xemu.git
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:
parent
83234b8289
commit
c3a824b0cf
|
@ -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);
|
||||
|
|
|
@ -63,6 +63,7 @@ DEF_HELPER_FLAGS_1(cntlzw32, TCG_CALL_NO_RWG_SE, i32, i32)
|
|||
DEF_HELPER_FLAGS_2(brinc, TCG_CALL_NO_RWG_SE, tl, tl, tl)
|
||||
|
||||
DEF_HELPER_1(float_check_status, void, env)
|
||||
DEF_HELPER_1(fpscr_check_status, void, env)
|
||||
DEF_HELPER_1(reset_fpstatus, void, env)
|
||||
DEF_HELPER_2(compute_fprf_float64, void, env, i64)
|
||||
DEF_HELPER_3(store_fpscr, void, env, i64, i32)
|
||||
|
|
|
@ -769,7 +769,6 @@ static void gen_mtfsb1(DisasContext *ctx)
|
|||
return;
|
||||
}
|
||||
crb = 31 - crbD(ctx->opcode);
|
||||
gen_reset_fpstatus();
|
||||
/* XXX: we pretend we can only do IEEE floating-point computations */
|
||||
if (likely(crb != FPSCR_FEX && crb != FPSCR_VX && crb != FPSCR_NI)) {
|
||||
TCGv_i32 t0;
|
||||
|
@ -782,7 +781,7 @@ static void gen_mtfsb1(DisasContext *ctx)
|
|||
tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX);
|
||||
}
|
||||
/* We can raise a deferred exception */
|
||||
gen_helper_float_check_status(cpu_env);
|
||||
gen_helper_fpscr_check_status(cpu_env);
|
||||
}
|
||||
|
||||
/* mtfsf */
|
||||
|
@ -803,7 +802,6 @@ static void gen_mtfsf(DisasContext *ctx)
|
|||
gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
|
||||
return;
|
||||
}
|
||||
gen_reset_fpstatus();
|
||||
if (l) {
|
||||
t0 = tcg_const_i32((ctx->insns_flags2 & PPC2_ISA205) ? 0xffff : 0xff);
|
||||
} else {
|
||||
|
@ -818,7 +816,7 @@ static void gen_mtfsf(DisasContext *ctx)
|
|||
tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX);
|
||||
}
|
||||
/* We can raise a deferred exception */
|
||||
gen_helper_float_check_status(cpu_env);
|
||||
gen_helper_fpscr_check_status(cpu_env);
|
||||
tcg_temp_free_i64(t1);
|
||||
}
|
||||
|
||||
|
@ -840,7 +838,6 @@ static void gen_mtfsfi(DisasContext *ctx)
|
|||
return;
|
||||
}
|
||||
sh = (8 * w) + 7 - bf;
|
||||
gen_reset_fpstatus();
|
||||
t0 = tcg_const_i64(((uint64_t)FPIMM(ctx->opcode)) << (4 * sh));
|
||||
t1 = tcg_const_i32(1 << sh);
|
||||
gen_helper_store_fpscr(cpu_env, t0, t1);
|
||||
|
@ -851,7 +848,7 @@ static void gen_mtfsfi(DisasContext *ctx)
|
|||
tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX);
|
||||
}
|
||||
/* We can raise a deferred exception */
|
||||
gen_helper_float_check_status(cpu_env);
|
||||
gen_helper_fpscr_check_status(cpu_env);
|
||||
}
|
||||
|
||||
static void gen_qemu_ld32fs(DisasContext *ctx, TCGv_i64 dest, TCGv addr)
|
||||
|
|
Loading…
Reference in New Issue