aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--target/arm/m-nocp.decode42
-rw-r--r--target/arm/meson.build1
-rw-r--r--target/arm/translate-vfp.c.inc52
-rw-r--r--target/arm/translate.c30
-rw-r--r--target/arm/vfp.decode2
5 files changed, 100 insertions, 27 deletions
diff --git a/target/arm/m-nocp.decode b/target/arm/m-nocp.decode
new file mode 100644
index 0000000000..7182d7d121
--- /dev/null
+++ b/target/arm/m-nocp.decode
@@ -0,0 +1,42 @@
+# M-profile UserFault.NOCP exception handling
+#
+# Copyright (c) 2020 Linaro, Ltd
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, see <http://www.gnu.org/licenses/>.
+
+#
+# This file is processed by scripts/decodetree.py
+#
+# For M-profile, the architecture specifies that NOCP UsageFaults
+# should take precedence over UNDEF faults over the whole wide
+# range of coprocessor-space encodings, with the exception of
+# VLLDM and VLSTM. (Compare v8.1M IsCPInstruction() pseudocode and
+# v8M Arm ARM rule R_QLGM.) This isn't mandatory for v8.0M but we choose
+# to behave the same as v8.1M.
+# This decode is handled before any others (and in particular before
+# decoding FP instructions which are in the coprocessor space).
+# If the coprocessor is not present or disabled then we will generate
+# the NOCP exception; otherwise we let the insn through to the main decode.
+
+{
+ # Special cases which do not take an early NOCP: VLLDM and VLSTM
+ VLLDM_VLSTM 1110 1100 001 l:1 rn:4 0000 1010 0000 0000
+ # TODO: VSCCLRM (new in v8.1M) is similar:
+ #VSCCLRM 1110 1100 1-01 1111 ---- 1011 ---- ---0
+
+ NOCP 111- 1110 ---- ---- ---- cp:4 ---- ----
+ NOCP 111- 110- ---- ---- ---- cp:4 ---- ----
+ # TODO: From v8.1M onwards we will also want this range to NOCP
+ #NOCP_8_1 111- 1111 ---- ---- ---- ---- ---- ---- cp=10
+}
diff --git a/target/arm/meson.build b/target/arm/meson.build
index bd46cdb523..8990090712 100644
--- a/target/arm/meson.build
+++ b/target/arm/meson.build
@@ -5,6 +5,7 @@ gen = [
decodetree.process('neon-ls.decode', extra_args: '--static-decode=disas_neon_ls'),
decodetree.process('vfp.decode', extra_args: '--static-decode=disas_vfp'),
decodetree.process('vfp-uncond.decode', extra_args: '--static-decode=disas_vfp_uncond'),
+ decodetree.process('m-nocp.decode', extra_args: '--static-decode=disas_m_nocp'),
decodetree.process('a32.decode', extra_args: '--static-decode=disas_a32'),
decodetree.process('a32-uncond.decode', extra_args: '--static-decode=disas_a32_uncond'),
decodetree.process('t32.decode', extra_args: '--static-decode=disas_t32'),
diff --git a/target/arm/translate-vfp.c.inc b/target/arm/translate-vfp.c.inc
index 2d63fa0d39..d376bd1c1a 100644
--- a/target/arm/translate-vfp.c.inc
+++ b/target/arm/translate-vfp.c.inc
@@ -95,14 +95,11 @@ static inline long vfp_f16_offset(unsigned reg, bool top)
static bool full_vfp_access_check(DisasContext *s, bool ignore_vfp_enabled)
{
if (s->fp_excp_el) {
- if (arm_dc_feature(s, ARM_FEATURE_M)) {
- gen_exception_insn(s, s->pc_curr, EXCP_NOCP, syn_uncategorized(),
- s->fp_excp_el);
- } else {
- gen_exception_insn(s, s->pc_curr, EXCP_UDEF,
- syn_fp_access_trap(1, 0xe, false),
- s->fp_excp_el);
- }
+ /* M-profile handled this earlier, in disas_m_nocp() */
+ assert (!arm_dc_feature(s, ARM_FEATURE_M));
+ gen_exception_insn(s, s->pc_curr, EXCP_UDEF,
+ syn_fp_access_trap(1, 0xe, false),
+ s->fp_excp_el);
return false;
}
@@ -2842,9 +2839,14 @@ static bool trans_VLLDM_VLSTM(DisasContext *s, arg_VLLDM_VLSTM *a)
!arm_dc_feature(s, ARM_FEATURE_V8)) {
return false;
}
- /* If not secure, UNDEF. */
+ /*
+ * If not secure, UNDEF. We must emit code for this
+ * rather than returning false so that this takes
+ * precedence over the m-nocp.decode NOCP fallback.
+ */
if (!s->v8m_secure) {
- return false;
+ unallocated_encoding(s);
+ return true;
}
/* If no fpu, NOP. */
if (!dc_isar_feature(aa32_vfp, s)) {
@@ -2863,3 +2865,33 @@ static bool trans_VLLDM_VLSTM(DisasContext *s, arg_VLLDM_VLSTM *a)
s->base.is_jmp = DISAS_UPDATE_EXIT;
return true;
}
+
+static bool trans_NOCP(DisasContext *s, arg_NOCP *a)
+{
+ /*
+ * Handle M-profile early check for disabled coprocessor:
+ * all we need to do here is emit the NOCP exception if
+ * the coprocessor is disabled. Otherwise we return false
+ * and the real VFP/etc decode will handle the insn.
+ */
+ assert(arm_dc_feature(s, ARM_FEATURE_M));
+
+ if (a->cp == 11) {
+ a->cp = 10;
+ }
+ /* TODO: in v8.1M cp 8, 9, 14, 15 also are governed by the cp10 enable */
+
+ if (a->cp != 10) {
+ gen_exception_insn(s, s->pc_curr, EXCP_NOCP,
+ syn_uncategorized(), default_exception_el(s));
+ return true;
+ }
+
+ if (s->fp_excp_el != 0) {
+ gen_exception_insn(s, s->pc_curr, EXCP_NOCP,
+ syn_uncategorized(), s->fp_excp_el);
+ return true;
+ }
+
+ return false;
+}
diff --git a/target/arm/translate.c b/target/arm/translate.c
index 362d1cc50f..958e9b6699 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -1176,6 +1176,7 @@ static TCGv_ptr vfp_reg_ptr(bool dp, int reg)
#define ARM_CP_RW_BIT (1 << 20)
/* Include the VFP and Neon decoders */
+#include "decode-m-nocp.c.inc"
#include "translate-vfp.c.inc"
#include "translate-neon.c.inc"
@@ -8433,6 +8434,19 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
ARCH(6T2);
}
+ if (arm_dc_feature(s, ARM_FEATURE_M)) {
+ /*
+ * NOCP takes precedence over any UNDEF for (almost) the
+ * entire wide range of coprocessor-space encodings, so check
+ * for it first before proceeding to actually decode eg VFP
+ * insns. This decode also handles the few insns which are
+ * in copro space but do not have NOCP checks (eg VLLDM, VLSTM).
+ */
+ if (disas_m_nocp(s, insn)) {
+ return;
+ }
+ }
+
if ((insn & 0xef000000) == 0xef000000) {
/*
* T32 encodings 0b111p_1111_qqqq_qqqq_qqqq_qqqq_qqqq_qqqq
@@ -8481,21 +8495,7 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
/* Coprocessor. */
if (arm_dc_feature(s, ARM_FEATURE_M)) {
/* 0b111x_11xx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx */
- if (extract32(insn, 24, 2) == 3) {
- goto illegal_op; /* op0 = 0b11 : unallocated */
- }
-
- if (((insn >> 8) & 0xe) == 10 &&
- dc_isar_feature(aa32_fpsp_v2, s)) {
- /* FP, and the CPU supports it */
- goto illegal_op;
- } else {
- /* All other insns: NOCP */
- gen_exception_insn(s, s->pc_curr, EXCP_NOCP,
- syn_uncategorized(),
- default_exception_el(s));
- }
- break;
+ goto illegal_op;
}
if (((insn >> 24) & 3) == 3) {
/* Neon DP, but failed disas_neon_dp() */
diff --git a/target/arm/vfp.decode b/target/arm/vfp.decode
index 5fd70f975a..2c793e3e87 100644
--- a/target/arm/vfp.decode
+++ b/target/arm/vfp.decode
@@ -213,5 +213,3 @@ VCVT_sp_int ---- 1110 1.11 110 s:1 .... 1010 rz:1 1.0 .... \
vd=%vd_sp vm=%vm_sp
VCVT_dp_int ---- 1110 1.11 110 s:1 .... 1011 rz:1 1.0 .... \
vd=%vd_sp vm=%vm_dp
-
-VLLDM_VLSTM 1110 1100 001 l:1 rn:4 0000 1010 0000 0000