aboutsummaryrefslogtreecommitdiff
path: root/target/arm
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2020-11-19 21:55:53 +0000
committerPeter Maydell <peter.maydell@linaro.org>2020-12-10 11:44:55 +0000
commit83ff3d6add965c9752324de11eac5687121ea826 (patch)
tree9b2a432d974acc6bb8ffddc3f0329c8111b023f8 /target/arm
parent4018818840f499d0a478508aedbb6802c8eae928 (diff)
target/arm: Implement VSCCLRM insn
Implement the v8.1M VSCCLRM insn, which zeros floating point registers if there is an active floating point context. This requires support in write_neon_element32() for the MO_32 element size, so add it. Because we want to use arm_gen_condlabel(), we need to move the definition of that function up in translate.c so it is before the #include of translate-vfp.c.inc. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20201119215617.29887-5-peter.maydell@linaro.org
Diffstat (limited to 'target/arm')
-rw-r--r--target/arm/cpu.h9
-rw-r--r--target/arm/m-nocp.decode8
-rw-r--r--target/arm/translate-vfp.c.inc84
-rw-r--r--target/arm/translate.c21
4 files changed, 111 insertions, 11 deletions
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index e5514c8286..11400a9d24 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -3555,6 +3555,15 @@ static inline bool isar_feature_aa32_mprofile(const ARMISARegisters *id)
return FIELD_EX32(id->id_pfr1, ID_PFR1, MPROGMOD) != 0;
}
+static inline bool isar_feature_aa32_m_sec_state(const ARMISARegisters *id)
+{
+ /*
+ * Return true if M-profile state handling insns
+ * (VSCCLRM, CLRM, FPCTX access insns) are implemented
+ */
+ return FIELD_EX32(id->id_pfr1, ID_PFR1, SECURITY) >= 3;
+}
+
static inline bool isar_feature_aa32_fp16_arith(const ARMISARegisters *id)
{
/* Sadly this is encoded differently for A-profile and M-profile */
diff --git a/target/arm/m-nocp.decode b/target/arm/m-nocp.decode
index 28c8ac6b94..ccd62e8739 100644
--- a/target/arm/m-nocp.decode
+++ b/target/arm/m-nocp.decode
@@ -29,13 +29,17 @@
# 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.
+%vd_dp 22:1 12:4
+%vd_sp 12:4 22:1
+
&nocp cp
{
# 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
+ # VSCCLRM (new in v8.1M) is similar:
+ VSCCLRM 1110 1100 1.01 1111 .... 1011 imm:7 0 vd=%vd_dp size=3
+ VSCCLRM 1110 1100 1.01 1111 .... 1010 imm:8 vd=%vd_sp size=2
NOCP 111- 1110 ---- ---- ---- cp:4 ---- ---- &nocp
NOCP 111- 110- ---- ---- ---- cp:4 ---- ---- &nocp
diff --git a/target/arm/translate-vfp.c.inc b/target/arm/translate-vfp.c.inc
index 96948f5a2d..2a67ed0f6e 100644
--- a/target/arm/translate-vfp.c.inc
+++ b/target/arm/translate-vfp.c.inc
@@ -3406,6 +3406,90 @@ static bool trans_VLLDM_VLSTM(DisasContext *s, arg_VLLDM_VLSTM *a)
return true;
}
+static bool trans_VSCCLRM(DisasContext *s, arg_VSCCLRM *a)
+{
+ int btmreg, topreg;
+ TCGv_i64 zero;
+ TCGv_i32 aspen, sfpa;
+
+ if (!dc_isar_feature(aa32_m_sec_state, s)) {
+ /* Before v8.1M, fall through in decode to NOCP check */
+ return false;
+ }
+
+ /* Explicitly UNDEF because this takes precedence over NOCP */
+ if (!arm_dc_feature(s, ARM_FEATURE_M_MAIN) || !s->v8m_secure) {
+ unallocated_encoding(s);
+ return true;
+ }
+
+ if (!dc_isar_feature(aa32_vfp_simd, s)) {
+ /* NOP if we have neither FP nor MVE */
+ return true;
+ }
+
+ /*
+ * If FPCCR.ASPEN != 0 && CONTROL_S.SFPA == 0 then there is no
+ * active floating point context so we must NOP (without doing
+ * any lazy state preservation or the NOCP check).
+ */
+ aspen = load_cpu_field(v7m.fpccr[M_REG_S]);
+ sfpa = load_cpu_field(v7m.control[M_REG_S]);
+ tcg_gen_andi_i32(aspen, aspen, R_V7M_FPCCR_ASPEN_MASK);
+ tcg_gen_xori_i32(aspen, aspen, R_V7M_FPCCR_ASPEN_MASK);
+ tcg_gen_andi_i32(sfpa, sfpa, R_V7M_CONTROL_SFPA_MASK);
+ tcg_gen_or_i32(sfpa, sfpa, aspen);
+ arm_gen_condlabel(s);
+ tcg_gen_brcondi_i32(TCG_COND_EQ, sfpa, 0, s->condlabel);
+
+ if (s->fp_excp_el != 0) {
+ gen_exception_insn(s, s->pc_curr, EXCP_NOCP,
+ syn_uncategorized(), s->fp_excp_el);
+ return true;
+ }
+
+ topreg = a->vd + a->imm - 1;
+ btmreg = a->vd;
+
+ /* Convert to Sreg numbers if the insn specified in Dregs */
+ if (a->size == 3) {
+ topreg = topreg * 2 + 1;
+ btmreg *= 2;
+ }
+
+ if (topreg > 63 || (topreg > 31 && !(topreg & 1))) {
+ /* UNPREDICTABLE: we choose to undef */
+ unallocated_encoding(s);
+ return true;
+ }
+
+ /* Silently ignore requests to clear D16-D31 if they don't exist */
+ if (topreg > 31 && !dc_isar_feature(aa32_simd_r32, s)) {
+ topreg = 31;
+ }
+
+ if (!vfp_access_check(s)) {
+ return true;
+ }
+
+ /* Zero the Sregs from btmreg to topreg inclusive. */
+ zero = tcg_const_i64(0);
+ if (btmreg & 1) {
+ write_neon_element64(zero, btmreg >> 1, 1, MO_32);
+ btmreg++;
+ }
+ for (; btmreg + 1 <= topreg; btmreg += 2) {
+ write_neon_element64(zero, btmreg >> 1, 0, MO_64);
+ }
+ if (btmreg == topreg) {
+ write_neon_element64(zero, btmreg >> 1, 0, MO_32);
+ btmreg++;
+ }
+ assert(btmreg == topreg + 1);
+ /* TODO: when MVE is implemented, zero VPR here */
+ return true;
+}
+
static bool trans_NOCP(DisasContext *s, arg_nocp *a)
{
/*
diff --git a/target/arm/translate.c b/target/arm/translate.c
index 6d04ca3a8a..9f2b6018a2 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -100,6 +100,15 @@ void arm_translate_init(void)
a64_translate_init();
}
+/* Generate a label used for skipping this instruction */
+static void arm_gen_condlabel(DisasContext *s)
+{
+ if (!s->condjmp) {
+ s->condlabel = gen_new_label();
+ s->condjmp = 1;
+ }
+}
+
/* Flags for the disas_set_da_iss info argument:
* lower bits hold the Rt register number, higher bits are flags.
*/
@@ -1221,6 +1230,9 @@ static void write_neon_element64(TCGv_i64 src, int reg, int ele, MemOp memop)
long off = neon_element_offset(reg, ele, memop);
switch (memop) {
+ case MO_32:
+ tcg_gen_st32_i64(src, cpu_env, off);
+ break;
case MO_64:
tcg_gen_st_i64(src, cpu_env, off);
break;
@@ -5156,15 +5168,6 @@ static void gen_srs(DisasContext *s,
s->base.is_jmp = DISAS_UPDATE_EXIT;
}
-/* Generate a label used for skipping this instruction */
-static void arm_gen_condlabel(DisasContext *s)
-{
- if (!s->condjmp) {
- s->condlabel = gen_new_label();
- s->condjmp = 1;
- }
-}
-
/* Skip this instruction if the ARM condition is false */
static void arm_skip_unless(DisasContext *s, uint32_t cond)
{