mirror of https://gitee.com/openkylin/qemu.git
target/microblaze: Unwind properly when raising divide-by-zero
Restore the correct pc when raising divide-by-zero. Also, the MSR[DZO] bit is sticky -- it is not cleared with a successful divide. 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:
parent
b1354342c1
commit
e98651d9ca
|
@ -1,7 +1,7 @@
|
|||
DEF_HELPER_FLAGS_2(raise_exception, TCG_CALL_NO_WG, noreturn, env, i32)
|
||||
|
||||
DEF_HELPER_3(divs, i32, env, i32, i32)
|
||||
DEF_HELPER_3(divu, i32, env, i32, i32)
|
||||
DEF_HELPER_FLAGS_3(divs, TCG_CALL_NO_WG, i32, env, i32, i32)
|
||||
DEF_HELPER_FLAGS_3(divu, TCG_CALL_NO_WG, i32, env, i32, i32)
|
||||
|
||||
DEF_HELPER_3(fadd, i32, env, i32, i32)
|
||||
DEF_HELPER_3(frsub, i32, env, i32, i32)
|
||||
|
|
|
@ -69,26 +69,27 @@ void helper_raise_exception(CPUMBState *env, uint32_t index)
|
|||
cpu_loop_exit(cs);
|
||||
}
|
||||
|
||||
static inline int div_prepare(CPUMBState *env, uint32_t a, uint32_t b)
|
||||
static bool check_divz(CPUMBState *env, uint32_t a, uint32_t b, uintptr_t ra)
|
||||
{
|
||||
MicroBlazeCPU *cpu = env_archcpu(env);
|
||||
|
||||
if (b == 0) {
|
||||
if (unlikely(b == 0)) {
|
||||
env->msr |= MSR_DZ;
|
||||
|
||||
if ((env->msr & MSR_EE) && cpu->cfg.div_zero_exception) {
|
||||
if ((env->msr & MSR_EE) &&
|
||||
env_archcpu(env)->cfg.div_zero_exception) {
|
||||
CPUState *cs = env_cpu(env);
|
||||
|
||||
env->esr = ESR_EC_DIVZERO;
|
||||
helper_raise_exception(env, EXCP_HW_EXCP);
|
||||
cs->exception_index = EXCP_HW_EXCP;
|
||||
cpu_loop_exit_restore(cs, ra);
|
||||
}
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
env->msr &= ~MSR_DZ;
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t helper_divs(CPUMBState *env, uint32_t a, uint32_t b)
|
||||
{
|
||||
if (!div_prepare(env, a, b)) {
|
||||
if (!check_divz(env, a, b, GETPC())) {
|
||||
return 0;
|
||||
}
|
||||
return (int32_t)a / (int32_t)b;
|
||||
|
@ -96,7 +97,7 @@ uint32_t helper_divs(CPUMBState *env, uint32_t a, uint32_t b)
|
|||
|
||||
uint32_t helper_divu(CPUMBState *env, uint32_t a, uint32_t b)
|
||||
{
|
||||
if (!div_prepare(env, a, b)) {
|
||||
if (!check_divz(env, a, b, GETPC())) {
|
||||
return 0;
|
||||
}
|
||||
return a / b;
|
||||
|
|
Loading…
Reference in New Issue