summaryrefslogtreecommitdiff
path: root/target/arm/translate-vfp.c
diff options
context:
space:
mode:
Diffstat (limited to 'target/arm/translate-vfp.c')
-rw-r--r--target/arm/translate-vfp.c33
1 files changed, 27 insertions, 6 deletions
diff --git a/target/arm/translate-vfp.c b/target/arm/translate-vfp.c
index e2eb797c82..59bcaec5be 100644
--- a/target/arm/translate-vfp.c
+++ b/target/arm/translate-vfp.c
@@ -109,7 +109,7 @@ static inline long vfp_f16_offset(unsigned reg, bool top)
* Generate code for M-profile lazy FP state preservation if needed;
* this corresponds to the pseudocode PreserveFPState() function.
*/
-static void gen_preserve_fp_state(DisasContext *s)
+static void gen_preserve_fp_state(DisasContext *s, bool skip_context_update)
{
if (s->v7m_lspact) {
/*
@@ -128,6 +128,20 @@ static void gen_preserve_fp_state(DisasContext *s)
* any further FP insns in this TB.
*/
s->v7m_lspact = false;
+ /*
+ * The helper might have zeroed VPR, so we do not know the
+ * correct value for the MVE_NO_PRED TB flag any more.
+ * If we're about to create a new fp context then that
+ * will precisely determine the MVE_NO_PRED value (see
+ * gen_update_fp_context()). Otherwise, we must:
+ * - set s->mve_no_pred to false, so this instruction
+ * is generated to use helper functions
+ * - end the TB now, without chaining to the next TB
+ */
+ if (skip_context_update || !s->v7m_new_fp_ctxt_needed) {
+ s->mve_no_pred = false;
+ s->base.is_jmp = DISAS_UPDATE_NOCHAIN;
+ }
}
}
@@ -169,12 +183,19 @@ static void gen_update_fp_context(DisasContext *s)
TCGv_i32 z32 = tcg_const_i32(0);
store_cpu_field(z32, v7m.vpr);
}
-
/*
- * 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.
+ * We just updated the FPSCR and VPR. Some of this state is cached
+ * in the MVE_NO_PRED TB flag. We want to avoid having to end the
+ * TB here, which means we need the new value of the MVE_NO_PRED
+ * flag to be exactly known here and the same for all executions.
+ * Luckily FPDSCR.LTPSIZE is always constant 4 and the VPR is
+ * always set to 0, so the new MVE_NO_PRED flag is always 1
+ * if and only if we have MVE.
+ *
+ * (The other FPSCR state cached in TB flags is VECLEN and VECSTRIDE,
+ * but those do not exist for M-profile, so are not relevant here.)
*/
+ s->mve_no_pred = dc_isar_feature(aa32_mve, s);
if (s->v8m_secure) {
bits |= R_V7M_CONTROL_SFPA_MASK;
@@ -238,7 +259,7 @@ bool vfp_access_check_m(DisasContext *s, bool skip_context_update)
/* Handle M-profile lazy FP state mechanics */
/* Trigger lazy-state preservation if necessary */
- gen_preserve_fp_state(s);
+ gen_preserve_fp_state(s, skip_context_update);
if (!skip_context_update) {
/* Update ownership of FP context and create new FP context if needed */