aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2021-06-18 11:02:39 +0100
committerPeter Maydell <peter.maydell@linaro.org>2021-06-18 11:02:39 +0100
commitc4c3bc77ab7e405814c63cef94dfba3d1e44e699 (patch)
tree38bdd9774e5b57f8156b2b93dea9e855359c9c0f
parentb9eb0b4a0be3713a072231d5ce674c5977b4f42e (diff)
target/arm: Handle FPU being disabled in FPCXT_NS accesses
If the guest makes an FPCXT_NS access when the FPU is disabled, one of two things happens: * if there is no active FP context, then the insn behaves the same way as if the FPU was enabled: writes ignored, reads same value as FPDSCR_NS * if there is an active FP context, then we take a NOCP exception Add code to the sysreg read/write functions which emits code to take the NOCP exception in the latter case. At the moment this will never be used, because the NOCP checks in m-nocp.decode happen first, and so the trans functions are never called when the FPU is disabled. The code will be needed when we move the sysreg access insns to before the NOCP patterns in the following commit. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- The "check for exception; then call gen_preserve_fp_state()" is a little repetitive. We'll clean this up in a bit of refactoring at the end of the patchseries, because the nicest way to do it involves restructuring vfp_access_check().
-rw-r--r--target/arm/translate-vfp.c32
1 files changed, 30 insertions, 2 deletions
diff --git a/target/arm/translate-vfp.c b/target/arm/translate-vfp.c
index 659e7440f4..fd9ae9bf56 100644
--- a/target/arm/translate-vfp.c
+++ b/target/arm/translate-vfp.c
@@ -887,7 +887,21 @@ static bool gen_M_fp_sysreg_write(DisasContext *s, int regno,
lab_end = gen_new_label();
/* fpInactive case: write is a NOP, so branch to end */
gen_branch_fpInactive(s, TCG_COND_NE, lab_end);
- /* !fpInactive: PreserveFPState(), and reads same as FPCXT_S */
+ /*
+ * !fpInactive: if FPU disabled, take NOCP exception;
+ * otherwise PreserveFPState(), and then FPCXT_NS writes
+ * behave the same as FPCXT_S writes.
+ */
+ if (s->fp_excp_el) {
+ gen_exception_insn(s, s->pc_curr, EXCP_NOCP,
+ syn_uncategorized(), s->fp_excp_el);
+ /*
+ * This was only a conditional exception, so override
+ * gen_exception_insn()'s default to DISAS_NORETURN
+ */
+ s->base.is_jmp = DISAS_NEXT;
+ break;
+ }
gen_preserve_fp_state(s);
/* fall through */
case ARM_VFP_FPCXT_S:
@@ -1027,7 +1041,21 @@ static bool gen_M_fp_sysreg_read(DisasContext *s, int regno,
tcg_gen_br(lab_end);
gen_set_label(lab_active);
- /* !fpInactive: Reads the same as FPCXT_S, but side effects differ */
+ /*
+ * !fpInactive: if FPU disabled, take NOCP exception;
+ * otherwise PreserveFPState(), and then FPCXT_NS
+ * reads the same as FPCXT_S.
+ */
+ if (s->fp_excp_el) {
+ gen_exception_insn(s, s->pc_curr, EXCP_NOCP,
+ syn_uncategorized(), s->fp_excp_el);
+ /*
+ * This was only a conditional exception, so override
+ * gen_exception_insn()'s default to DISAS_NORETURN
+ */
+ s->base.is_jmp = DISAS_NEXT;
+ break;
+ }
gen_preserve_fp_state(s);
tmp = tcg_temp_new_i32();
sfpa = tcg_temp_new_i32();