summaryrefslogtreecommitdiffstats
path: root/target/ppc/fpu_helper.c
diff options
context:
space:
mode:
authorLucas Mateus Castro (alqotel)2021-12-17 17:57:12 +0100
committerCédric Le Goater2021-12-17 17:57:12 +0100
commitc3a824b0cf23f98353fa91c715fe4918432d7928 (patch)
tree27950607a47f2f2391b188f9d37ad41f44990bb3 /target/ppc/fpu_helper.c
parenthw/ppc/mac.h: Remove MAX_CPUS macro (diff)
downloadqemu-c3a824b0cf23f98353fa91c715fe4918432d7928.tar.gz
qemu-c3a824b0cf23f98353fa91c715fe4918432d7928.tar.xz
qemu-c3a824b0cf23f98353fa91c715fe4918432d7928.zip
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>
Diffstat (limited to 'target/ppc/fpu_helper.c')
-rw-r--r--target/ppc/fpu_helper.c48
1 files changed, 48 insertions, 0 deletions
diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c
index c4896cecc8..bb72715827 100644
--- a/target/ppc/fpu_helper.c
+++ b/target/ppc/fpu_helper.c
@@ -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);