target/microblaze: Fix cpu unwind for fpu exceptions

Restore the correct PC when an exception must be raised.

Tested-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2020-08-19 09:11:37 -07:00
parent d5aead3df4
commit 7bca6ddf90
1 changed files with 20 additions and 17 deletions

View File

@ -104,13 +104,16 @@ uint32_t helper_divu(CPUMBState *env, uint32_t a, uint32_t b)
} }
/* raise FPU exception. */ /* raise FPU exception. */
static void raise_fpu_exception(CPUMBState *env) static void raise_fpu_exception(CPUMBState *env, uintptr_t ra)
{ {
CPUState *cs = env_cpu(env);
env->esr = ESR_EC_FPU; env->esr = ESR_EC_FPU;
helper_raise_exception(env, EXCP_HW_EXCP); cs->exception_index = EXCP_HW_EXCP;
cpu_loop_exit_restore(cs, ra);
} }
static void update_fpu_flags(CPUMBState *env, int flags) static void update_fpu_flags(CPUMBState *env, int flags, uintptr_t ra)
{ {
int raise = 0; int raise = 0;
@ -133,7 +136,7 @@ static void update_fpu_flags(CPUMBState *env, int flags)
if (raise if (raise
&& (env->pvr.regs[2] & PVR2_FPU_EXC_MASK) && (env->pvr.regs[2] & PVR2_FPU_EXC_MASK)
&& (env->msr & MSR_EE)) { && (env->msr & MSR_EE)) {
raise_fpu_exception(env); raise_fpu_exception(env, ra);
} }
} }
@ -148,7 +151,7 @@ uint32_t helper_fadd(CPUMBState *env, uint32_t a, uint32_t b)
fd.f = float32_add(fa.f, fb.f, &env->fp_status); fd.f = float32_add(fa.f, fb.f, &env->fp_status);
flags = get_float_exception_flags(&env->fp_status); flags = get_float_exception_flags(&env->fp_status);
update_fpu_flags(env, flags); update_fpu_flags(env, flags, GETPC());
return fd.l; return fd.l;
} }
@ -162,7 +165,7 @@ uint32_t helper_frsub(CPUMBState *env, uint32_t a, uint32_t b)
fb.l = b; fb.l = b;
fd.f = float32_sub(fb.f, fa.f, &env->fp_status); fd.f = float32_sub(fb.f, fa.f, &env->fp_status);
flags = get_float_exception_flags(&env->fp_status); flags = get_float_exception_flags(&env->fp_status);
update_fpu_flags(env, flags); update_fpu_flags(env, flags, GETPC());
return fd.l; return fd.l;
} }
@ -176,7 +179,7 @@ uint32_t helper_fmul(CPUMBState *env, uint32_t a, uint32_t b)
fb.l = b; fb.l = b;
fd.f = float32_mul(fa.f, fb.f, &env->fp_status); fd.f = float32_mul(fa.f, fb.f, &env->fp_status);
flags = get_float_exception_flags(&env->fp_status); flags = get_float_exception_flags(&env->fp_status);
update_fpu_flags(env, flags); update_fpu_flags(env, flags, GETPC());
return fd.l; return fd.l;
} }
@ -191,7 +194,7 @@ uint32_t helper_fdiv(CPUMBState *env, uint32_t a, uint32_t b)
fb.l = b; fb.l = b;
fd.f = float32_div(fb.f, fa.f, &env->fp_status); fd.f = float32_div(fb.f, fa.f, &env->fp_status);
flags = get_float_exception_flags(&env->fp_status); flags = get_float_exception_flags(&env->fp_status);
update_fpu_flags(env, flags); update_fpu_flags(env, flags, GETPC());
return fd.l; return fd.l;
} }
@ -206,7 +209,7 @@ uint32_t helper_fcmp_un(CPUMBState *env, uint32_t a, uint32_t b)
if (float32_is_signaling_nan(fa.f, &env->fp_status) || if (float32_is_signaling_nan(fa.f, &env->fp_status) ||
float32_is_signaling_nan(fb.f, &env->fp_status)) { float32_is_signaling_nan(fb.f, &env->fp_status)) {
update_fpu_flags(env, float_flag_invalid); update_fpu_flags(env, float_flag_invalid, GETPC());
r = 1; r = 1;
} }
@ -229,7 +232,7 @@ uint32_t helper_fcmp_lt(CPUMBState *env, uint32_t a, uint32_t b)
fb.l = b; fb.l = b;
r = float32_lt(fb.f, fa.f, &env->fp_status); r = float32_lt(fb.f, fa.f, &env->fp_status);
flags = get_float_exception_flags(&env->fp_status); flags = get_float_exception_flags(&env->fp_status);
update_fpu_flags(env, flags & float_flag_invalid); update_fpu_flags(env, flags & float_flag_invalid, GETPC());
return r; return r;
} }
@ -245,7 +248,7 @@ uint32_t helper_fcmp_eq(CPUMBState *env, uint32_t a, uint32_t b)
fb.l = b; fb.l = b;
r = float32_eq_quiet(fa.f, fb.f, &env->fp_status); r = float32_eq_quiet(fa.f, fb.f, &env->fp_status);
flags = get_float_exception_flags(&env->fp_status); flags = get_float_exception_flags(&env->fp_status);
update_fpu_flags(env, flags & float_flag_invalid); update_fpu_flags(env, flags & float_flag_invalid, GETPC());
return r; return r;
} }
@ -261,7 +264,7 @@ uint32_t helper_fcmp_le(CPUMBState *env, uint32_t a, uint32_t b)
set_float_exception_flags(0, &env->fp_status); set_float_exception_flags(0, &env->fp_status);
r = float32_le(fa.f, fb.f, &env->fp_status); r = float32_le(fa.f, fb.f, &env->fp_status);
flags = get_float_exception_flags(&env->fp_status); flags = get_float_exception_flags(&env->fp_status);
update_fpu_flags(env, flags & float_flag_invalid); update_fpu_flags(env, flags & float_flag_invalid, GETPC());
return r; return r;
@ -277,7 +280,7 @@ uint32_t helper_fcmp_gt(CPUMBState *env, uint32_t a, uint32_t b)
set_float_exception_flags(0, &env->fp_status); set_float_exception_flags(0, &env->fp_status);
r = float32_lt(fa.f, fb.f, &env->fp_status); r = float32_lt(fa.f, fb.f, &env->fp_status);
flags = get_float_exception_flags(&env->fp_status); flags = get_float_exception_flags(&env->fp_status);
update_fpu_flags(env, flags & float_flag_invalid); update_fpu_flags(env, flags & float_flag_invalid, GETPC());
return r; return r;
} }
@ -291,7 +294,7 @@ uint32_t helper_fcmp_ne(CPUMBState *env, uint32_t a, uint32_t b)
set_float_exception_flags(0, &env->fp_status); set_float_exception_flags(0, &env->fp_status);
r = !float32_eq_quiet(fa.f, fb.f, &env->fp_status); r = !float32_eq_quiet(fa.f, fb.f, &env->fp_status);
flags = get_float_exception_flags(&env->fp_status); flags = get_float_exception_flags(&env->fp_status);
update_fpu_flags(env, flags & float_flag_invalid); update_fpu_flags(env, flags & float_flag_invalid, GETPC());
return r; return r;
} }
@ -306,7 +309,7 @@ uint32_t helper_fcmp_ge(CPUMBState *env, uint32_t a, uint32_t b)
set_float_exception_flags(0, &env->fp_status); set_float_exception_flags(0, &env->fp_status);
r = !float32_lt(fa.f, fb.f, &env->fp_status); r = !float32_lt(fa.f, fb.f, &env->fp_status);
flags = get_float_exception_flags(&env->fp_status); flags = get_float_exception_flags(&env->fp_status);
update_fpu_flags(env, flags & float_flag_invalid); update_fpu_flags(env, flags & float_flag_invalid, GETPC());
return r; return r;
} }
@ -330,7 +333,7 @@ uint32_t helper_fint(CPUMBState *env, uint32_t a)
fa.l = a; fa.l = a;
r = float32_to_int32(fa.f, &env->fp_status); r = float32_to_int32(fa.f, &env->fp_status);
flags = get_float_exception_flags(&env->fp_status); flags = get_float_exception_flags(&env->fp_status);
update_fpu_flags(env, flags); update_fpu_flags(env, flags, GETPC());
return r; return r;
} }
@ -344,7 +347,7 @@ uint32_t helper_fsqrt(CPUMBState *env, uint32_t a)
fa.l = a; fa.l = a;
fd.l = float32_sqrt(fa.f, &env->fp_status); fd.l = float32_sqrt(fa.f, &env->fp_status);
flags = get_float_exception_flags(&env->fp_status); flags = get_float_exception_flags(&env->fp_status);
update_fpu_flags(env, flags); update_fpu_flags(env, flags, GETPC());
return fd.l; return fd.l;
} }