mirror of https://github.com/xemu-project/xemu.git
target/arm: Implement M-profile trapping on division by zero
Unlike A-profile, for M-profile the UDIV and SDIV insns can be configured to raise an exception on division by zero, using the CCR DIV_0_TRP bit. Implement support for setting this bit by making the helper functions raise the appropriate exception. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20210730151636.17254-3-peter.maydell@linaro.org
This commit is contained in:
parent
fc7a5038a6
commit
e534629296
|
@ -54,6 +54,7 @@
|
||||||
#define EXCP_LAZYFP 20 /* v7M fault during lazy FP stacking */
|
#define EXCP_LAZYFP 20 /* v7M fault during lazy FP stacking */
|
||||||
#define EXCP_LSERR 21 /* v8M LSERR SecureFault */
|
#define EXCP_LSERR 21 /* v8M LSERR SecureFault */
|
||||||
#define EXCP_UNALIGNED 22 /* v7M UNALIGNED UsageFault */
|
#define EXCP_UNALIGNED 22 /* v7M UNALIGNED UsageFault */
|
||||||
|
#define EXCP_DIVBYZERO 23 /* v7M DIVBYZERO UsageFault */
|
||||||
/* NB: add new EXCP_ defines to the array in arm_log_exception() too */
|
/* NB: add new EXCP_ defines to the array in arm_log_exception() too */
|
||||||
|
|
||||||
#define ARMV7M_EXCP_RESET 1
|
#define ARMV7M_EXCP_RESET 1
|
||||||
|
|
|
@ -9345,6 +9345,18 @@ uint32_t HELPER(sxtb16)(uint32_t x)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void handle_possible_div0_trap(CPUARMState *env, uintptr_t ra)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Take a division-by-zero exception if necessary; otherwise return
|
||||||
|
* to get the usual non-trapping division behaviour (result of 0)
|
||||||
|
*/
|
||||||
|
if (arm_feature(env, ARM_FEATURE_M)
|
||||||
|
&& (env->v7m.ccr[env->v7m.secure] & R_V7M_CCR_DIV_0_TRP_MASK)) {
|
||||||
|
raise_exception_ra(env, EXCP_DIVBYZERO, 0, 1, ra);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t HELPER(uxtb16)(uint32_t x)
|
uint32_t HELPER(uxtb16)(uint32_t x)
|
||||||
{
|
{
|
||||||
uint32_t res;
|
uint32_t res;
|
||||||
|
@ -9353,9 +9365,10 @@ uint32_t HELPER(uxtb16)(uint32_t x)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t HELPER(sdiv)(int32_t num, int32_t den)
|
int32_t HELPER(sdiv)(CPUARMState *env, int32_t num, int32_t den)
|
||||||
{
|
{
|
||||||
if (den == 0) {
|
if (den == 0) {
|
||||||
|
handle_possible_div0_trap(env, GETPC());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (num == INT_MIN && den == -1) {
|
if (num == INT_MIN && den == -1) {
|
||||||
|
@ -9364,9 +9377,10 @@ int32_t HELPER(sdiv)(int32_t num, int32_t den)
|
||||||
return num / den;
|
return num / den;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t HELPER(udiv)(uint32_t num, uint32_t den)
|
uint32_t HELPER(udiv)(CPUARMState *env, uint32_t num, uint32_t den)
|
||||||
{
|
{
|
||||||
if (den == 0) {
|
if (den == 0) {
|
||||||
|
handle_possible_div0_trap(env, GETPC());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return num / den;
|
return num / den;
|
||||||
|
@ -9567,6 +9581,7 @@ void arm_log_exception(int idx)
|
||||||
[EXCP_LAZYFP] = "v7M exception during lazy FP stacking",
|
[EXCP_LAZYFP] = "v7M exception during lazy FP stacking",
|
||||||
[EXCP_LSERR] = "v8M LSERR UsageFault",
|
[EXCP_LSERR] = "v8M LSERR UsageFault",
|
||||||
[EXCP_UNALIGNED] = "v7M UNALIGNED UsageFault",
|
[EXCP_UNALIGNED] = "v7M UNALIGNED UsageFault",
|
||||||
|
[EXCP_DIVBYZERO] = "v7M DIVBYZERO UsageFault",
|
||||||
};
|
};
|
||||||
|
|
||||||
if (idx >= 0 && idx < ARRAY_SIZE(excnames)) {
|
if (idx >= 0 && idx < ARRAY_SIZE(excnames)) {
|
||||||
|
|
|
@ -6,8 +6,8 @@ DEF_HELPER_3(add_saturate, i32, env, i32, i32)
|
||||||
DEF_HELPER_3(sub_saturate, i32, env, i32, i32)
|
DEF_HELPER_3(sub_saturate, i32, env, i32, i32)
|
||||||
DEF_HELPER_3(add_usaturate, i32, env, i32, i32)
|
DEF_HELPER_3(add_usaturate, i32, env, i32, i32)
|
||||||
DEF_HELPER_3(sub_usaturate, i32, env, i32, i32)
|
DEF_HELPER_3(sub_usaturate, i32, env, i32, i32)
|
||||||
DEF_HELPER_FLAGS_2(sdiv, TCG_CALL_NO_RWG_SE, s32, s32, s32)
|
DEF_HELPER_FLAGS_3(sdiv, TCG_CALL_NO_RWG, s32, env, s32, s32)
|
||||||
DEF_HELPER_FLAGS_2(udiv, TCG_CALL_NO_RWG_SE, i32, i32, i32)
|
DEF_HELPER_FLAGS_3(udiv, TCG_CALL_NO_RWG, i32, env, i32, i32)
|
||||||
DEF_HELPER_FLAGS_1(rbit, TCG_CALL_NO_RWG_SE, i32, i32)
|
DEF_HELPER_FLAGS_1(rbit, TCG_CALL_NO_RWG_SE, i32, i32)
|
||||||
|
|
||||||
#define PAS_OP(pfx) \
|
#define PAS_OP(pfx) \
|
||||||
|
|
|
@ -2252,6 +2252,10 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
|
||||||
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
|
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
|
||||||
env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_UNALIGNED_MASK;
|
env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_UNALIGNED_MASK;
|
||||||
break;
|
break;
|
||||||
|
case EXCP_DIVBYZERO:
|
||||||
|
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
|
||||||
|
env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_DIVBYZERO_MASK;
|
||||||
|
break;
|
||||||
case EXCP_SWI:
|
case EXCP_SWI:
|
||||||
/* The PC already points to the next instruction. */
|
/* The PC already points to the next instruction. */
|
||||||
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SVC, env->v7m.secure);
|
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SVC, env->v7m.secure);
|
||||||
|
|
|
@ -7992,9 +7992,9 @@ static bool op_div(DisasContext *s, arg_rrr *a, bool u)
|
||||||
t1 = load_reg(s, a->rn);
|
t1 = load_reg(s, a->rn);
|
||||||
t2 = load_reg(s, a->rm);
|
t2 = load_reg(s, a->rm);
|
||||||
if (u) {
|
if (u) {
|
||||||
gen_helper_udiv(t1, t1, t2);
|
gen_helper_udiv(t1, cpu_env, t1, t2);
|
||||||
} else {
|
} else {
|
||||||
gen_helper_sdiv(t1, t1, t2);
|
gen_helper_sdiv(t1, cpu_env, t1, t2);
|
||||||
}
|
}
|
||||||
tcg_temp_free_i32(t2);
|
tcg_temp_free_i32(t2);
|
||||||
store_reg(s, a->rd, t1);
|
store_reg(s, a->rd, t1);
|
||||||
|
|
Loading…
Reference in New Issue