All of lore.kernel.org
 help / color / mirror / Atom feed
From: Peter Maydell <peter.maydell@linaro.org>
To: qemu-arm@nongnu.org, qemu-devel@nongnu.org
Subject: [PATCH 07/15] target/arm: Refactor M-profile VMSR/VMRS handling
Date: Mon, 16 Nov 2020 16:08:23 +0000	[thread overview]
Message-ID: <20201116160831.31000-8-peter.maydell@linaro.org> (raw)
In-Reply-To: <20201116160831.31000-1-peter.maydell@linaro.org>

Currently M-profile borrows the A-profile code for VMSR and VMRS
(access to the FP system registers), because all it needs to support
is the FPSCR.  In v8.1M things become significantly more complicated
in two ways:

 * there are several new FP system registers; some have side effects
   on read, and one (FPCXT_NS) needs to avoid the usual
   vfp_access_check() and the "only if FPU implemented" check

 * all sysregs are now accessible both by VMRS/VMSR (which
   reads/writes a general purpose register) and also by VLDR/VSTR
   (which reads/writes them directly to memory)

Refactor the structure of how we handle VMSR/VMRS to cope with this:

 * keep the M-profile code entirely separate from the A-profile code

 * abstract out the "read or write the general purpose register" part
   of the code into a loadfn or storefn function pointer, so we can
   reuse it for VLDR/VSTR.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target/arm/cpu.h               |   3 +
 target/arm/translate-vfp.c.inc | 181 ++++++++++++++++++++++++++++++---
 2 files changed, 170 insertions(+), 14 deletions(-)

diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 806c18a499f..3b20f935174 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -1569,6 +1569,9 @@ enum arm_cpu_mode {
 #define ARM_VFP_FPINST  9
 #define ARM_VFP_FPINST2 10
 
+/* QEMU-internal value meaning "FPSCR, but we care only about NZCV" */
+#define QEMU_VFP_FPSCR_NZCV 0xffff
+
 /* iwMMXt coprocessor control registers.  */
 #define ARM_IWMMXT_wCID  0
 #define ARM_IWMMXT_wCon  1
diff --git a/target/arm/translate-vfp.c.inc b/target/arm/translate-vfp.c.inc
index aee60ff98b3..5d880d12116 100644
--- a/target/arm/translate-vfp.c.inc
+++ b/target/arm/translate-vfp.c.inc
@@ -607,27 +607,180 @@ static bool trans_VDUP(DisasContext *s, arg_VDUP *a)
     return true;
 }
 
+/*
+ * M-profile provides two different sets of instructions that can
+ * access floating point system registers: VMSR/VMRS (which move
+ * to/from a general purpose register) and VLDR/VSTR sysreg (which
+ * move directly to/from memory). In some cases there are also side
+ * effects which must happen after any write to memory (which could
+ * cause an exception). So we implement the common logic for the
+ * sysreg access in gen_M_fp_sysreg_write() and gen_M_fp_sysreg_read(),
+ * which take pointers to callback functions which will perform the
+ * actual "read/write general purpose register" and "read/write
+ * memory" operations.
+ */
+
+/*
+ * Emit code to store the sysreg to its final destination; frees the
+ * TCG temp 'value' it is passed.
+ */
+typedef void fp_sysreg_storefn(DisasContext *s, void *opaque, TCGv_i32 value);
+/*
+ * Emit code to load the value to be copied to the sysreg; returns
+ * a new TCG temporary
+ */
+typedef TCGv_i32 fp_sysreg_loadfn(DisasContext *s, void *opaque);
+
+/* Common decode/access checks for fp sysreg read/write */
+typedef enum fp_sysreg_check_result {
+    fp_sysreg_check_failed, /* caller should return false */
+    fp_sysreg_check_done, /* caller should return true */
+    fp_sysreg_check_continue, /* caller should continue generating code */
+} fp_sysreg_check_result;
+
+static fp_sysreg_check_result fp_sysreg_checks(DisasContext *s, int regno)
+{
+    if (!dc_isar_feature(aa32_fpsp_v2, s)) {
+        return fp_sysreg_check_failed;
+    }
+
+    switch (regno) {
+    case ARM_VFP_FPSCR:
+    case QEMU_VFP_FPSCR_NZCV:
+        break;
+    default:
+        return fp_sysreg_check_failed;
+    }
+
+    if (!vfp_access_check(s)) {
+        return fp_sysreg_check_done;
+    }
+
+    return fp_sysreg_check_continue;
+}
+
+static bool gen_M_fp_sysreg_write(DisasContext *s, int regno,
+                                 fp_sysreg_loadfn *loadfn,
+                                 void *opaque)
+{
+    /* Do a write to an M-profile floating point system register */
+    TCGv_i32 tmp;
+
+    switch (fp_sysreg_checks(s, regno)) {
+    case fp_sysreg_check_failed:
+        return false;
+    case fp_sysreg_check_done:
+        return true;
+    case fp_sysreg_check_continue:
+        break;
+    }
+
+    switch (regno) {
+    case ARM_VFP_FPSCR:
+        tmp = loadfn(s, opaque);
+        gen_helper_vfp_set_fpscr(cpu_env, tmp);
+        tcg_temp_free_i32(tmp);
+        gen_lookup_tb(s);
+        break;
+    default:
+        g_assert_not_reached();
+    }
+    return true;
+}
+
+static bool gen_M_fp_sysreg_read(DisasContext *s, int regno,
+                                fp_sysreg_storefn *storefn,
+                                void *opaque)
+{
+    /* Do a read from an M-profile floating point system register */
+    TCGv_i32 tmp;
+
+    switch (fp_sysreg_checks(s, regno)) {
+    case fp_sysreg_check_failed:
+        return false;
+    case fp_sysreg_check_done:
+        return true;
+    case fp_sysreg_check_continue:
+        break;
+    }
+
+    switch (regno) {
+    case ARM_VFP_FPSCR:
+        tmp = tcg_temp_new_i32();
+        gen_helper_vfp_get_fpscr(tmp, cpu_env);
+        storefn(s, opaque, tmp);
+        break;
+    case QEMU_VFP_FPSCR_NZCV:
+        /*
+         * Read just NZCV; this is a special case to avoid the
+         * helper call for the "VMRS to CPSR.NZCV" insn.
+         */
+        tmp = load_cpu_field(vfp.xregs[ARM_VFP_FPSCR]);
+        tcg_gen_andi_i32(tmp, tmp, 0xf0000000);
+        storefn(s, opaque, tmp);
+        break;
+    default:
+        g_assert_not_reached();
+    }
+    return true;
+}
+
+static void fp_sysreg_to_gpr(DisasContext *s, void *opaque, TCGv_i32 value)
+{
+    arg_VMSR_VMRS *a = opaque;
+
+    if (a->rt == 15) {
+        /* Set the 4 flag bits in the CPSR */
+        gen_set_nzcv(value);
+        tcg_temp_free_i32(value);
+    } else {
+        store_reg(s, a->rt, value);
+    }
+}
+
+static TCGv_i32 gpr_to_fp_sysreg(DisasContext *s, void *opaque)
+{
+    arg_VMSR_VMRS *a = opaque;
+
+    return load_reg(s, a->rt);
+}
+
+static bool gen_M_VMSR_VMRS(DisasContext *s, arg_VMSR_VMRS *a)
+{
+    /*
+     * Accesses to R15 are UNPREDICTABLE; we choose to undef.
+     * FPSCR -> r15 is a special case which writes to the PSR flags;
+     * set a->reg to a special value to tell gen_M_fp_sysreg_read()
+     * we only care about the top 4 bits of FPSCR there.
+     */
+    if (a->rt == 15) {
+        if (a->l && a->reg == ARM_VFP_FPSCR) {
+            a->reg = QEMU_VFP_FPSCR_NZCV;
+        } else {
+            return false;
+        }
+    }
+
+    if (a->l) {
+        /* VMRS, move FP system register to gp register */
+        return gen_M_fp_sysreg_read(s, a->reg, fp_sysreg_to_gpr, a);
+    } else {
+        /* VMSR, move gp register to FP system register */
+        return gen_M_fp_sysreg_write(s, a->reg, gpr_to_fp_sysreg, a);
+    }
+}
+
 static bool trans_VMSR_VMRS(DisasContext *s, arg_VMSR_VMRS *a)
 {
     TCGv_i32 tmp;
     bool ignore_vfp_enabled = false;
 
-    if (!dc_isar_feature(aa32_fpsp_v2, s)) {
-        return false;
+    if (arm_dc_feature(s, ARM_FEATURE_M)) {
+        return gen_M_VMSR_VMRS(s, a);
     }
 
-    if (arm_dc_feature(s, ARM_FEATURE_M)) {
-        /*
-         * The only M-profile VFP vmrs/vmsr sysreg is FPSCR.
-         * Accesses to R15 are UNPREDICTABLE; we choose to undef.
-         * (FPSCR -> r15 is a special case which writes to the PSR flags.)
-         */
-        if (a->reg != ARM_VFP_FPSCR) {
-            return false;
-        }
-        if (a->rt == 15 && !a->l) {
-            return false;
-        }
+    if (!dc_isar_feature(aa32_fpsp_v2, s)) {
+        return false;
     }
 
     switch (a->reg) {
-- 
2.20.1



  parent reply	other threads:[~2020-11-16 16:25 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-11-16 16:08 [PATCH 00/15] target/arm: More v8.1M features Peter Maydell
2020-11-16 16:08 ` [PATCH 01/15] hw/intc/armv7m_nvic: Make all of system PPB range be RAZWI/BusFault Peter Maydell
2020-11-17 19:07   ` Richard Henderson
2020-11-16 16:08 ` [PATCH 02/15] target/arm: Implement v8.1M PXN extension Peter Maydell
2020-11-17 19:10   ` Richard Henderson
2020-11-16 16:08 ` [PATCH 03/15] target/arm: Don't clobber ID_PFR1.Security on M-profile cores Peter Maydell
2020-11-17 19:12   ` Richard Henderson
2020-11-16 16:08 ` [PATCH 04/15] target/arm: Implement VSCCLRM insn Peter Maydell
2020-11-17 19:31   ` Richard Henderson
2020-11-16 16:08 ` [PATCH 05/15] target/arm: Implement CLRM instruction Peter Maydell
2020-11-17 19:38   ` Richard Henderson
2020-11-16 16:08 ` [PATCH 06/15] target/arm: Enforce M-profile VMRS/VMSR register restrictions Peter Maydell
2020-11-17 19:42   ` Richard Henderson
2020-11-17 21:18     ` Peter Maydell
2020-11-16 16:08 ` Peter Maydell [this message]
2020-11-16 16:08 ` [PATCH 08/15] target/arm: Move general-use constant expanders up in translate.c Peter Maydell
2020-11-17 19:47   ` Richard Henderson
2020-11-16 16:08 ` [PATCH 09/15] target/arm: Implement VLDR/VSTR system register Peter Maydell
2020-11-16 16:08 ` [PATCH 10/15] target/arm: Implement M-profile FPSCR_nzcvqc Peter Maydell
2020-11-16 16:08 ` [PATCH 11/15] target/arm: Use new FPCR_NZCV_MASK constant Peter Maydell
2020-11-17 19:49   ` Richard Henderson
2020-11-16 16:08 ` [PATCH 12/15] target/arm: Factor out preserve-fp-state from full_vfp_access_check() Peter Maydell
2020-11-17 19:50   ` Richard Henderson
2020-11-16 16:08 ` [PATCH 13/15] target/arm: Implement FPCXT_S fp system register Peter Maydell
2020-11-16 16:08 ` [PATCH 14/15] target/arm: Implement FPCXT_NS " Peter Maydell
2020-11-16 16:08 ` [PATCH 15/15] hw/intc/armv7m_nvic: Update FPDSCR masking for v8.1M Peter Maydell

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20201116160831.31000-8-peter.maydell@linaro.org \
    --to=peter.maydell@linaro.org \
    --cc=qemu-arm@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.