Commit 6000531e authored by Peter Maydell's avatar Peter Maydell
Browse files

target/arm: Activate M-profile floating point context when FPCCR.ASPEN is set



The M-profile FPCCR.ASPEN bit indicates that automatic floating-point
context preservation is enabled. Before executing any floating-point
instruction, if FPCCR.ASPEN is set and the CONTROL FPCA/SFPA bits
indicate that there is no active floating point context then we
must create a new context (by initializing FPSCR and setting
FPCA/SFPA to indicate that the context is now active). In the
pseudocode this is handled by ExecuteFPCheck().

Implement this with a new TB flag which tracks whether we
need to create a new FP context.

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
Reviewed-by: default avatarRichard Henderson <richard.henderson@linaro.org>
Message-id: 20190416125744.27770-20-peter.maydell@linaro.org
parent 6d60c67a
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -3153,6 +3153,8 @@ FIELD(TBFLAG_A32, NS, 6, 1)
FIELD(TBFLAG_A32, VFPEN, 7, 1)
FIELD(TBFLAG_A32, CONDEXEC, 8, 8)
FIELD(TBFLAG_A32, SCTLR_B, 16, 1)
/* For M profile only, set if we must create a new FP context */
FIELD(TBFLAG_A32, NEW_FP_CTXT_NEEDED, 19, 1)
/* For M profile only, set if FPCCR.S does not match current security state */
FIELD(TBFLAG_A32, FPCCR_S_WRONG, 20, 1)
/* For M profile only, Handler (ie not Thread) mode */
+13 −0
Original line number Diff line number Diff line
@@ -13422,6 +13422,19 @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
        flags = FIELD_DP32(flags, TBFLAG_A32, FPCCR_S_WRONG, 1);
    }

    if (arm_feature(env, ARM_FEATURE_M) &&
        (env->v7m.fpccr[env->v7m.secure] & R_V7M_FPCCR_ASPEN_MASK) &&
        (!(env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK) ||
         (env->v7m.secure &&
          !(env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK)))) {
        /*
         * ASPEN is set, but FPCA/SFPA indicate that there is no active
         * FP context; we must create a new FP context before executing
         * any FP insn.
         */
        flags = FIELD_DP32(flags, TBFLAG_A32, NEW_FP_CTXT_NEEDED, 1);
    }

    *pflags = flags;
    *cs_base = 0;
}
+29 −0
Original line number Diff line number Diff line
@@ -3438,6 +3438,33 @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn)
            /* Don't need to do this for any further FP insns in this TB */
            s->v8m_fpccr_s_wrong = false;
        }

        if (s->v7m_new_fp_ctxt_needed) {
            /*
             * Create new FP context by updating CONTROL.FPCA, CONTROL.SFPA
             * and the FPSCR.
             */
            TCGv_i32 control, fpscr;
            uint32_t bits = R_V7M_CONTROL_FPCA_MASK;

            fpscr = load_cpu_field(v7m.fpdscr[s->v8m_secure]);
            gen_helper_vfp_set_fpscr(cpu_env, fpscr);
            tcg_temp_free_i32(fpscr);
            /*
             * We don't need to arrange to end the TB, because the only
             * parts of FPSCR which we cache in the TB flags are the VECLEN
             * and VECSTRIDE, and those don't exist for M-profile.
             */

            if (s->v8m_secure) {
                bits |= R_V7M_CONTROL_SFPA_MASK;
            }
            control = load_cpu_field(v7m.control[M_REG_S]);
            tcg_gen_ori_i32(control, control, bits);
            store_cpu_field(control, v7m.control[M_REG_S]);
            /* Don't need to do this for any further FP insns in this TB */
            s->v7m_new_fp_ctxt_needed = false;
        }
    }

    if (extract32(insn, 28, 4) == 0xf) {
@@ -13361,6 +13388,8 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
        regime_is_secure(env, dc->mmu_idx);
    dc->v8m_stackcheck = FIELD_EX32(tb_flags, TBFLAG_A32, STACKCHECK);
    dc->v8m_fpccr_s_wrong = FIELD_EX32(tb_flags, TBFLAG_A32, FPCCR_S_WRONG);
    dc->v7m_new_fp_ctxt_needed =
        FIELD_EX32(tb_flags, TBFLAG_A32, NEW_FP_CTXT_NEEDED);
    dc->cp_regs = cpu->cp_regs;
    dc->features = env->features;

+1 −0
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ typedef struct DisasContext {
    bool v8m_secure; /* true if v8M and we're in Secure mode */
    bool v8m_stackcheck; /* true if we need to perform v8M stack limit checks */
    bool v8m_fpccr_s_wrong; /* true if v8M FPCCR.S != v8m_secure */
    bool v7m_new_fp_ctxt_needed; /* ASPEN set but no active FP context */
    /* Immediate value in AArch32 SVC insn; must be set if is_jmp == DISAS_SWI
     * so that top level loop can generate correct syndrome information.
     */