diff mbox series

[02/55] target/arm: Enable FPSCR.QC bit for MVE

Message ID 20210607165821.9892-3-peter.maydell@linaro.org
State Superseded
Headers show
Series target/arm: First slice of MVE implementation | expand

Commit Message

Peter Maydell June 7, 2021, 4:57 p.m. UTC
MVE has an FPSCR.QC bit similar to the A-profile Neon one; when MVE
is implemented make the bit writeable, both in the generic "load and
store FPSCR" helper functions and in the code for handling the NZCVQC
sysreg which we had previously left as "TODO when we implement MVE".

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

---
 target/arm/translate-vfp.c | 32 +++++++++++++++++++++++---------
 target/arm/vfp_helper.c    |  3 ++-
 2 files changed, 25 insertions(+), 10 deletions(-)

-- 
2.20.1

Comments

Richard Henderson June 7, 2021, 7:02 p.m. UTC | #1
On 6/7/21 9:57 AM, Peter Maydell wrote:
> MVE has an FPSCR.QC bit similar to the A-profile Neon one; when MVE

> is implemented make the bit writeable, both in the generic "load and

> store FPSCR" helper functions and in the code for handling the NZCVQC

> sysreg which we had previously left as "TODO when we implement MVE".

> 

> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

> ---

>   target/arm/translate-vfp.c | 32 +++++++++++++++++++++++---------

>   target/arm/vfp_helper.c    |  3 ++-

>   2 files changed, 25 insertions(+), 10 deletions(-)

> 

> diff --git a/target/arm/translate-vfp.c b/target/arm/translate-vfp.c

> index d01e465821b..22a619eb2c5 100644

> --- a/target/arm/translate-vfp.c

> +++ b/target/arm/translate-vfp.c

> @@ -784,10 +784,19 @@ static bool gen_M_fp_sysreg_write(DisasContext *s, int regno,

>       {

>           TCGv_i32 fpscr;

>           tmp = loadfn(s, opaque);

> -        /*

> -         * TODO: when we implement MVE, write the QC bit.

> -         * For non-MVE, QC is RES0.

> -         */

> +        if (dc_isar_feature(aa32_mve, s)) {

> +            /* QC is only present for MVE; otherwise RES0 */

> +            TCGv_i32 qc = tcg_temp_new_i32();

> +            TCGv_i32 zero;

> +            tcg_gen_andi_i32(qc, tmp, FPCR_QC);

> +            store_cpu_field(qc, vfp.qc[0]);

> +            zero = tcg_const_i32(0);

> +            store_cpu_field(zero, vfp.qc[1]);

> +            zero = tcg_const_i32(0);

> +            store_cpu_field(zero, vfp.qc[2]);

> +            zero = tcg_const_i32(0);

> +            store_cpu_field(zero, vfp.qc[3]);

> +        }


Ok I guess.  You could store the same i32 into all elements:

     tcg_gen_gvec_dup_i32(MO_32, offsetof(CPUARMState, vfp.qc),
                          16, 16, qc);

Either way,
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 d01e465821b..22a619eb2c5 100644
--- a/target/arm/translate-vfp.c
+++ b/target/arm/translate-vfp.c
@@ -784,10 +784,19 @@  static bool gen_M_fp_sysreg_write(DisasContext *s, int regno,
     {
         TCGv_i32 fpscr;
         tmp = loadfn(s, opaque);
-        /*
-         * TODO: when we implement MVE, write the QC bit.
-         * For non-MVE, QC is RES0.
-         */
+        if (dc_isar_feature(aa32_mve, s)) {
+            /* QC is only present for MVE; otherwise RES0 */
+            TCGv_i32 qc = tcg_temp_new_i32();
+            TCGv_i32 zero;
+            tcg_gen_andi_i32(qc, tmp, FPCR_QC);
+            store_cpu_field(qc, vfp.qc[0]);
+            zero = tcg_const_i32(0);
+            store_cpu_field(zero, vfp.qc[1]);
+            zero = tcg_const_i32(0);
+            store_cpu_field(zero, vfp.qc[2]);
+            zero = tcg_const_i32(0);
+            store_cpu_field(zero, vfp.qc[3]);
+        }
         tcg_gen_andi_i32(tmp, tmp, FPCR_NZCV_MASK);
         fpscr = load_cpu_field(vfp.xregs[ARM_VFP_FPSCR]);
         tcg_gen_andi_i32(fpscr, fpscr, ~FPCR_NZCV_MASK);
@@ -869,6 +878,11 @@  static bool gen_M_fp_sysreg_read(DisasContext *s, int regno,
         break;
     }
 
+    if (regno == ARM_VFP_FPSCR_NZCVQC && !dc_isar_feature(aa32_mve, s)) {
+        /* QC is RES0 without MVE, so NZCVQC simplifies to NZCV */
+        regno = QEMU_VFP_FPSCR_NZCV;
+    }
+
     switch (regno) {
     case ARM_VFP_FPSCR:
         tmp = tcg_temp_new_i32();
@@ -876,11 +890,11 @@  static bool gen_M_fp_sysreg_read(DisasContext *s, int regno,
         storefn(s, opaque, tmp);
         break;
     case ARM_VFP_FPSCR_NZCVQC:
-        /*
-         * TODO: MVE has a QC bit, which we probably won't store
-         * in the xregs[] field. For non-MVE, where QC is RES0,
-         * we can just fall through to the FPSCR_NZCV case.
-         */
+        tmp = tcg_temp_new_i32();
+        gen_helper_vfp_get_fpscr(tmp, cpu_env);
+        tcg_gen_andi_i32(tmp, tmp, FPCR_NZCVQC_MASK);
+        storefn(s, opaque, tmp);
+        break;
     case QEMU_VFP_FPSCR_NZCV:
         /*
          * Read just NZCV; this is a special case to avoid the
diff --git a/target/arm/vfp_helper.c b/target/arm/vfp_helper.c
index 496f0034772..8a716600592 100644
--- a/target/arm/vfp_helper.c
+++ b/target/arm/vfp_helper.c
@@ -220,7 +220,8 @@  void HELPER(vfp_set_fpscr)(CPUARMState *env, uint32_t val)
                                      FPCR_LTPSIZE_LENGTH);
     }
 
-    if (arm_feature(env, ARM_FEATURE_NEON)) {
+    if (arm_feature(env, ARM_FEATURE_NEON) ||
+        cpu_isar_feature(aa32_mve, cpu)) {
         /*
          * The bit we set within fpscr_q is arbitrary; the register as a
          * whole being zero/non-zero is what counts.