aboutsummaryrefslogtreecommitdiff
path: root/target/arm/translate.c
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2019-04-29 17:36:02 +0100
committerPeter Maydell <peter.maydell@linaro.org>2019-04-29 17:36:02 +0100
commite33cf0f8d8c9998a7616684f9d6aa0d181b88803 (patch)
tree0bc446ee91b8d04c84feb3b2ef6a916e5d5bbd62 /target/arm/translate.c
parenta356dacf647506bccdf8ecd23574246a8bf615ac (diff)
target/arm: Implement M-profile lazy FP state preservation
The M-profile architecture floating point system supports lazy FP state preservation, where FP registers are not pushed to the stack when an exception occurs but are instead only saved if and when the first FP instruction in the exception handler is executed. Implement this in QEMU, corresponding to the check of LSPACT in the pseudocode ExecuteFPCheck(). Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20190416125744.27770-24-peter.maydell@linaro.org
Diffstat (limited to 'target/arm/translate.c')
-rw-r--r--target/arm/translate.c22
1 files changed, 22 insertions, 0 deletions
diff --git a/target/arm/translate.c b/target/arm/translate.c
index edb66e7be8..4f29d09a28 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -3424,6 +3424,27 @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn)
if (arm_dc_feature(s, ARM_FEATURE_M)) {
/* Handle M-profile lazy FP state mechanics */
+ /* Trigger lazy-state preservation if necessary */
+ if (s->v7m_lspact) {
+ /*
+ * Lazy state saving affects external memory and also the NVIC,
+ * so we must mark it as an IO operation for icount.
+ */
+ if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
+ gen_io_start();
+ }
+ gen_helper_v7m_preserve_fp_state(cpu_env);
+ if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
+ gen_io_end();
+ }
+ /*
+ * If the preserve_fp_state helper doesn't throw an exception
+ * then it will clear LSPACT; we don't need to repeat this for
+ * any further FP insns in this TB.
+ */
+ s->v7m_lspact = false;
+ }
+
/* Update ownership of FP context: set FPCCR.S to match current state */
if (s->v8m_fpccr_s_wrong) {
TCGv_i32 tmp;
@@ -13390,6 +13411,7 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
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->v7m_lspact = FIELD_EX32(tb_flags, TBFLAG_A32, LSPACT);
dc->cp_regs = cpu->cp_regs;
dc->features = env->features;