diff mbox series

[2/7] target/arm: Handle FPU being disabled in FPCXT_NS accesses

Message ID 20210618141019.10671-3-peter.maydell@linaro.org (mailing list archive)
State New, archived
Headers show
Series target/arm: Fix FPCXT_NS accesses when FPU disabled | expand

Commit Message

Peter Maydell June 18, 2021, 2:10 p.m. UTC
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.

Cc: qemu-stable@nongnu.org
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().
---
 target/arm/translate-vfp.c | 32 ++++++++++++++++++++++++++++++--
 1 file changed, 30 insertions(+), 2 deletions(-)

Comments

Richard Henderson June 18, 2021, 3:10 p.m. UTC | #1
On 6/18/21 7:10 AM, Peter Maydell wrote:
> 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.
> 
> Cc:qemu-stable@nongnu.org
> Signed-off-by: Peter Maydell<peter.maydell@linaro.org>
> ---

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~
diff mbox series

Patch

diff --git a/target/arm/translate-vfp.c b/target/arm/translate-vfp.c
index 5a4a13ec1e1..107d6143be8 100644
--- a/target/arm/translate-vfp.c
+++ b/target/arm/translate-vfp.c
@@ -821,7 +821,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:
@@ -961,7 +975,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();