Commit b8b8ea05 authored by Peter Maydell's avatar Peter Maydell
Browse files

target-arm: Add ARM UDIV/SDIV support



Add support for UDIV and SDIV in ARM mode. This is a new optional
feature for A profile cores (Thumb mode has had UDIV and SDIV for
M profile cores for some time).

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parent 47789990
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -375,6 +375,7 @@ enum arm_features {
    ARM_FEATURE_V5,
    ARM_FEATURE_STRONGARM,
    ARM_FEATURE_VAPA, /* cp15 VA to PA lookups */
    ARM_FEATURE_ARM_DIV, /* divide supported in ARM encoding */
};

static inline int arm_feature(CPUARMState *env, int feature)
+4 −1
Original line number Diff line number Diff line
@@ -207,7 +207,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
        set_feature(env, ARM_FEATURE_VFP_FP16);
        set_feature(env, ARM_FEATURE_NEON);
        set_feature(env, ARM_FEATURE_THUMB2EE);
        set_feature(env, ARM_FEATURE_THUMB_DIV);
        set_feature(env, ARM_FEATURE_ARM_DIV);
        set_feature(env, ARM_FEATURE_V7MP);
        break;
    case ARM_CPUID_TI915T:
@@ -261,6 +261,9 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
    if (arm_feature(env, ARM_FEATURE_V7)) {
        set_feature(env, ARM_FEATURE_VAPA);
    }
    if (arm_feature(env, ARM_FEATURE_ARM_DIV)) {
        set_feature(env, ARM_FEATURE_THUMB_DIV);
    }
}

void cpu_reset(CPUARMState *env)
+19 −0
Original line number Diff line number Diff line
@@ -7639,6 +7639,25 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                            store_reg(s, rn, tmp);
                        }
                        break;
                    case 1:
                    case 3:
                        /* SDIV, UDIV */
                        if (!arm_feature(env, ARM_FEATURE_ARM_DIV)) {
                            goto illegal_op;
                        }
                        if (((insn >> 5) & 7) || (rd != 15)) {
                            goto illegal_op;
                        }
                        tmp = load_reg(s, rm);
                        tmp2 = load_reg(s, rs);
                        if (insn & (1 << 21)) {
                            gen_helper_udiv(tmp, tmp, tmp2);
                        } else {
                            gen_helper_sdiv(tmp, tmp, tmp2);
                        }
                        tcg_temp_free_i32(tmp2);
                        store_reg(s, rn, tmp);
                        break;
                    default:
                        goto illegal_op;
                    }