aboutsummaryrefslogtreecommitdiff
path: root/target
diff options
context:
space:
mode:
Diffstat (limited to 'target')
-rw-r--r--target/arm/arch_dump.c11
-rw-r--r--target/arm/cpu.c44
-rw-r--r--target/arm/cpu.h88
-rw-r--r--target/arm/cpu64.c5
-rw-r--r--target/arm/helper.c23
-rw-r--r--target/arm/kvm32.c5
-rw-r--r--target/arm/kvm64.c1
-rw-r--r--target/arm/m_helper.c11
-rw-r--r--target/arm/machine.c5
-rw-r--r--target/arm/translate-a64.c114
-rw-r--r--target/arm/translate-vfp.inc.c446
-rw-r--r--target/arm/translate.c122
-rw-r--r--target/arm/vfp-uncond.decode12
-rw-r--r--target/arm/vfp.decode171
-rw-r--r--target/s390x/cpu.c18
-rw-r--r--target/s390x/cpu.h3
-rw-r--r--target/s390x/helper.c2
-rw-r--r--target/s390x/kvm-stub.c10
-rw-r--r--target/s390x/kvm.c42
-rw-r--r--target/s390x/kvm_s390x.h4
-rw-r--r--target/s390x/translate.c2
21 files changed, 696 insertions, 443 deletions
diff --git a/target/arm/arch_dump.c b/target/arm/arch_dump.c
index 2345dec3c2..7693e17e96 100644
--- a/target/arm/arch_dump.c
+++ b/target/arm/arch_dump.c
@@ -363,9 +363,11 @@ int arm_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
int cpuid, void *opaque)
{
struct arm_note note;
- CPUARMState *env = &ARM_CPU(cs)->env;
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
DumpState *s = opaque;
- int ret, i, fpvalid = !!arm_feature(env, ARM_FEATURE_VFP);
+ int ret, i;
+ bool fpvalid = cpu_isar_feature(aa32_vfp_simd, cpu);
arm_note_init(&note, s, "CORE", 5, NT_PRSTATUS, sizeof(note.prstatus));
@@ -444,7 +446,6 @@ int cpu_get_dump_info(ArchDumpInfo *info,
ssize_t cpu_get_note_size(int class, int machine, int nr_cpus)
{
ARMCPU *cpu = ARM_CPU(first_cpu);
- CPUARMState *env = &cpu->env;
size_t note_size;
if (class == ELFCLASS64) {
@@ -452,12 +453,12 @@ ssize_t cpu_get_note_size(int class, int machine, int nr_cpus)
note_size += AARCH64_PRFPREG_NOTE_SIZE;
#ifdef TARGET_AARCH64
if (cpu_isar_feature(aa64_sve, cpu)) {
- note_size += AARCH64_SVE_NOTE_SIZE(env);
+ note_size += AARCH64_SVE_NOTE_SIZE(&cpu->env);
}
#endif
} else {
note_size = ARM_PRSTATUS_NOTE_SIZE;
- if (arm_feature(env, ARM_FEATURE_VFP)) {
+ if (cpu_isar_feature(aa32_vfp_simd, cpu)) {
note_size += ARM_VFP_NOTE_SIZE;
}
}
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 2eadf4dcb8..e6016e33ce 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -293,7 +293,7 @@ static void arm_cpu_reset(CPUState *s)
env->v7m.ccr[M_REG_S] |= R_V7M_CCR_UNALIGN_TRP_MASK;
}
- if (arm_feature(env, ARM_FEATURE_VFP)) {
+ if (cpu_isar_feature(aa32_vfp_simd, cpu)) {
env->v7m.fpccr[M_REG_NS] = R_V7M_FPCCR_ASPEN_MASK;
env->v7m.fpccr[M_REG_S] = R_V7M_FPCCR_ASPEN_MASK |
R_V7M_FPCCR_LSPEN_MASK | R_V7M_FPCCR_S_MASK;
@@ -1011,7 +1011,7 @@ static void arm_cpu_dump_state(CPUState *cs, FILE *f, int flags)
int numvfpregs = 0;
if (cpu_isar_feature(aa32_simd_r32, cpu)) {
numvfpregs = 32;
- } else if (arm_feature(env, ARM_FEATURE_VFP)) {
+ } else if (cpu_isar_feature(aa32_vfp_simd, cpu)) {
numvfpregs = 16;
}
for (i = 0; i < numvfpregs; i++) {
@@ -1208,13 +1208,6 @@ void arm_cpu_post_init(Object *obj)
if (arm_feature(&cpu->env, ARM_FEATURE_M)) {
set_feature(&cpu->env, ARM_FEATURE_PMSA);
}
- /* Similarly for the VFP feature bits */
- if (arm_feature(&cpu->env, ARM_FEATURE_VFP4)) {
- set_feature(&cpu->env, ARM_FEATURE_VFP3);
- }
- if (arm_feature(&cpu->env, ARM_FEATURE_VFP3)) {
- set_feature(&cpu->env, ARM_FEATURE_VFP);
- }
if (arm_feature(&cpu->env, ARM_FEATURE_CBAR) ||
arm_feature(&cpu->env, ARM_FEATURE_CBAR_RO)) {
@@ -1260,7 +1253,9 @@ void arm_cpu_post_init(Object *obj)
* KVM does not currently allow us to lie to the guest about its
* ID/feature registers, so the guest always sees what the host has.
*/
- if (arm_feature(&cpu->env, ARM_FEATURE_VFP)) {
+ if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)
+ ? cpu_isar_feature(aa64_fp_simd, cpu)
+ : cpu_isar_feature(aa32_vfp, cpu)) {
cpu->has_vfp = true;
if (!kvm_enabled()) {
qdev_property_add_static(DEVICE(obj), &arm_cpu_has_vfp_property);
@@ -1440,10 +1435,6 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
uint64_t t;
uint32_t u;
- unset_feature(env, ARM_FEATURE_VFP);
- unset_feature(env, ARM_FEATURE_VFP3);
- unset_feature(env, ARM_FEATURE_VFP4);
-
t = cpu->isar.id_aa64isar1;
t = FIELD_DP64(t, ID_AA64ISAR1, JSCVT, 0);
cpu->isar.id_aa64isar1 = t;
@@ -1510,7 +1501,6 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
u = FIELD_DP32(u, MVFR1, SIMDINT, 0);
u = FIELD_DP32(u, MVFR1, SIMDSP, 0);
u = FIELD_DP32(u, MVFR1, SIMDHP, 0);
- u = FIELD_DP32(u, MVFR1, SIMDFMAC, 0);
cpu->isar.mvfr1 = u;
u = cpu->isar.mvfr2;
@@ -1533,6 +1523,11 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
u = cpu->isar.mvfr0;
u = FIELD_DP32(u, MVFR0, SIMDREG, 0);
cpu->isar.mvfr0 = u;
+
+ /* Despite the name, this field covers both VFP and Neon */
+ u = cpu->isar.mvfr1;
+ u = FIELD_DP32(u, MVFR1, SIMDFMAC, 0);
+ cpu->isar.mvfr1 = u;
}
if (arm_feature(env, ARM_FEATURE_M) && !cpu->has_dsp) {
@@ -1636,8 +1631,9 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
* We rely on no XScale CPU having VFP so we can use the same bits in the
* TB flags field for VECSTRIDE and XSCALE_CPAR.
*/
- assert(!(arm_feature(env, ARM_FEATURE_VFP) &&
- arm_feature(env, ARM_FEATURE_XSCALE)));
+ assert(arm_feature(&cpu->env, ARM_FEATURE_AARCH64) ||
+ !cpu_isar_feature(aa32_vfp_simd, cpu) ||
+ !arm_feature(env, ARM_FEATURE_XSCALE));
if (arm_feature(env, ARM_FEATURE_V7) &&
!arm_feature(env, ARM_FEATURE_M) &&
@@ -1858,7 +1854,6 @@ static void arm926_initfn(Object *obj)
cpu->dtb_compatible = "arm,arm926";
set_feature(&cpu->env, ARM_FEATURE_V5);
- set_feature(&cpu->env, ARM_FEATURE_VFP);
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
set_feature(&cpu->env, ARM_FEATURE_CACHE_TEST_CLEAN);
cpu->midr = 0x41069265;
@@ -1899,7 +1894,6 @@ static void arm1026_initfn(Object *obj)
cpu->dtb_compatible = "arm,arm1026";
set_feature(&cpu->env, ARM_FEATURE_V5);
- set_feature(&cpu->env, ARM_FEATURE_VFP);
set_feature(&cpu->env, ARM_FEATURE_AUXCR);
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
set_feature(&cpu->env, ARM_FEATURE_CACHE_TEST_CLEAN);
@@ -1947,7 +1941,6 @@ static void arm1136_r2_initfn(Object *obj)
cpu->dtb_compatible = "arm,arm1136";
set_feature(&cpu->env, ARM_FEATURE_V6);
- set_feature(&cpu->env, ARM_FEATURE_VFP);
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
set_feature(&cpu->env, ARM_FEATURE_CACHE_DIRTY_REG);
set_feature(&cpu->env, ARM_FEATURE_CACHE_BLOCK_OPS);
@@ -1979,7 +1972,6 @@ static void arm1136_initfn(Object *obj)
cpu->dtb_compatible = "arm,arm1136";
set_feature(&cpu->env, ARM_FEATURE_V6K);
set_feature(&cpu->env, ARM_FEATURE_V6);
- set_feature(&cpu->env, ARM_FEATURE_VFP);
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
set_feature(&cpu->env, ARM_FEATURE_CACHE_DIRTY_REG);
set_feature(&cpu->env, ARM_FEATURE_CACHE_BLOCK_OPS);
@@ -2010,7 +2002,6 @@ static void arm1176_initfn(Object *obj)
cpu->dtb_compatible = "arm,arm1176";
set_feature(&cpu->env, ARM_FEATURE_V6K);
- set_feature(&cpu->env, ARM_FEATURE_VFP);
set_feature(&cpu->env, ARM_FEATURE_VAPA);
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
set_feature(&cpu->env, ARM_FEATURE_CACHE_DIRTY_REG);
@@ -2043,7 +2034,6 @@ static void arm11mpcore_initfn(Object *obj)
cpu->dtb_compatible = "arm,arm11mpcore";
set_feature(&cpu->env, ARM_FEATURE_V6K);
- set_feature(&cpu->env, ARM_FEATURE_VFP);
set_feature(&cpu->env, ARM_FEATURE_VAPA);
set_feature(&cpu->env, ARM_FEATURE_MPIDR);
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
@@ -2109,7 +2099,6 @@ static void cortex_m4_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_M);
set_feature(&cpu->env, ARM_FEATURE_M_MAIN);
set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP);
- set_feature(&cpu->env, ARM_FEATURE_VFP4);
cpu->midr = 0x410fc240; /* r0p0 */
cpu->pmsav7_dregion = 8;
cpu->isar.mvfr0 = 0x10110021;
@@ -2140,7 +2129,6 @@ static void cortex_m7_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_M);
set_feature(&cpu->env, ARM_FEATURE_M_MAIN);
set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP);
- set_feature(&cpu->env, ARM_FEATURE_VFP4);
cpu->midr = 0x411fc272; /* r1p2 */
cpu->pmsav7_dregion = 8;
cpu->isar.mvfr0 = 0x10110221;
@@ -2172,7 +2160,6 @@ static void cortex_m33_initfn(Object *obj)
set_feature(&cpu->env, ARM_FEATURE_M_MAIN);
set_feature(&cpu->env, ARM_FEATURE_M_SECURITY);
set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP);
- set_feature(&cpu->env, ARM_FEATURE_VFP4);
cpu->midr = 0x410fd213; /* r0p3 */
cpu->pmsav7_dregion = 16;
cpu->sau_sregion = 8;
@@ -2256,7 +2243,6 @@ static void cortex_r5f_initfn(Object *obj)
ARMCPU *cpu = ARM_CPU(obj);
cortex_r5_initfn(obj);
- set_feature(&cpu->env, ARM_FEATURE_VFP3);
cpu->isar.mvfr0 = 0x10110221;
cpu->isar.mvfr1 = 0x00000011;
}
@@ -2275,7 +2261,6 @@ static void cortex_a8_initfn(Object *obj)
cpu->dtb_compatible = "arm,cortex-a8";
set_feature(&cpu->env, ARM_FEATURE_V7);
- set_feature(&cpu->env, ARM_FEATURE_VFP3);
set_feature(&cpu->env, ARM_FEATURE_NEON);
set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
@@ -2343,7 +2328,6 @@ static void cortex_a9_initfn(Object *obj)
cpu->dtb_compatible = "arm,cortex-a9";
set_feature(&cpu->env, ARM_FEATURE_V7);
- set_feature(&cpu->env, ARM_FEATURE_VFP3);
set_feature(&cpu->env, ARM_FEATURE_NEON);
set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
set_feature(&cpu->env, ARM_FEATURE_EL3);
@@ -2408,7 +2392,6 @@ static void cortex_a7_initfn(Object *obj)
cpu->dtb_compatible = "arm,cortex-a7";
set_feature(&cpu->env, ARM_FEATURE_V7VE);
- set_feature(&cpu->env, ARM_FEATURE_VFP4);
set_feature(&cpu->env, ARM_FEATURE_NEON);
set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
@@ -2454,7 +2437,6 @@ static void cortex_a15_initfn(Object *obj)
cpu->dtb_compatible = "arm,cortex-a15";
set_feature(&cpu->env, ARM_FEATURE_V7VE);
- set_feature(&cpu->env, ARM_FEATURE_VFP4);
set_feature(&cpu->env, ARM_FEATURE_NEON);
set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 65171cb30e..0b84742b66 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -904,7 +904,7 @@ struct ARMCPU {
/* The elements of this array are the CCSIDR values for each cache,
* in the order L1DCache, L1ICache, L2DCache, L2ICache, etc.
*/
- uint32_t ccsidr[16];
+ uint64_t ccsidr[16];
uint64_t reset_cbar;
uint32_t reset_auxcr;
bool reset_hivecs;
@@ -1880,7 +1880,6 @@ QEMU_BUILD_BUG_ON(ARRAY_SIZE(((ARMCPU *)0)->ccsidr) <= R_V7M_CSSELR_INDEX_MASK);
* mapping in linux-user/elfload.c:get_elf_hwcap().
*/
enum arm_features {
- ARM_FEATURE_VFP,
ARM_FEATURE_AUXCR, /* ARM1026 Auxiliary control register. */
ARM_FEATURE_XSCALE, /* Intel XScale extensions. */
ARM_FEATURE_IWMMXT, /* Intel iwMMXt extension. */
@@ -1889,7 +1888,6 @@ enum arm_features {
ARM_FEATURE_V7,
ARM_FEATURE_THUMB2,
ARM_FEATURE_PMSA, /* no MMU; may have Memory Protection Unit */
- ARM_FEATURE_VFP3,
ARM_FEATURE_NEON,
ARM_FEATURE_M, /* Microcontroller profile. */
ARM_FEATURE_OMAPCP, /* OMAP specific CP15 ops handling. */
@@ -1900,7 +1898,6 @@ enum arm_features {
ARM_FEATURE_V5,
ARM_FEATURE_STRONGARM,
ARM_FEATURE_VAPA, /* cp15 VA to PA lookups */
- ARM_FEATURE_VFP4, /* VFPv4 (implies that NEON is v2) */
ARM_FEATURE_GENERIC_TIMER,
ARM_FEATURE_MVFR, /* Media and VFP Feature Registers 0 and 1 */
ARM_FEATURE_DUMMY_C15_REGS, /* RAZ/WI all of cp15 crn=15 */
@@ -3450,6 +3447,15 @@ static inline bool isar_feature_aa32_fp16_arith(const ARMISARegisters *id)
return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, FP) == 1;
}
+static inline bool isar_feature_aa32_vfp_simd(const ARMISARegisters *id)
+{
+ /*
+ * Return true if either VFP or SIMD is implemented.
+ * In this case, a minimum of VFP w/ D0-D15.
+ */
+ return FIELD_EX32(id->mvfr0, MVFR0, SIMDREG) > 0;
+}
+
static inline bool isar_feature_aa32_simd_r32(const ARMISARegisters *id)
{
/* Return true if D16-D31 are implemented */
@@ -3461,12 +3467,35 @@ static inline bool isar_feature_aa32_fpshvec(const ARMISARegisters *id)
return FIELD_EX32(id->mvfr0, MVFR0, FPSHVEC) > 0;
}
-static inline bool isar_feature_aa32_fpdp(const ARMISARegisters *id)
+static inline bool isar_feature_aa32_fpsp_v2(const ARMISARegisters *id)
+{
+ /* Return true if CPU supports single precision floating point, VFPv2 */
+ return FIELD_EX32(id->mvfr0, MVFR0, FPSP) > 0;
+}
+
+static inline bool isar_feature_aa32_fpsp_v3(const ARMISARegisters *id)
+{
+ /* Return true if CPU supports single precision floating point, VFPv3 */
+ return FIELD_EX32(id->mvfr0, MVFR0, FPSP) >= 2;
+}
+
+static inline bool isar_feature_aa32_fpdp_v2(const ARMISARegisters *id)
{
- /* Return true if CPU supports double precision floating point */
+ /* Return true if CPU supports double precision floating point, VFPv2 */
return FIELD_EX32(id->mvfr0, MVFR0, FPDP) > 0;
}
+static inline bool isar_feature_aa32_fpdp_v3(const ARMISARegisters *id)
+{
+ /* Return true if CPU supports double precision floating point, VFPv3 */
+ return FIELD_EX32(id->mvfr0, MVFR0, FPDP) >= 2;
+}
+
+static inline bool isar_feature_aa32_vfp(const ARMISARegisters *id)
+{
+ return isar_feature_aa32_fpsp_v2(id) || isar_feature_aa32_fpdp_v2(id);
+}
+
/*
* We always set the FP and SIMD FP16 fields to indicate identical
* levels of support (assuming SIMD is implemented at all), so
@@ -3482,6 +3511,18 @@ static inline bool isar_feature_aa32_fp16_dpconv(const ARMISARegisters *id)
return FIELD_EX32(id->mvfr1, MVFR1, FPHP) > 1;
}
+/*
+ * Note that this ID register field covers both VFP and Neon FMAC,
+ * so should usually be tested in combination with some other
+ * check that confirms the presence of whichever of VFP or Neon is
+ * relevant, to avoid accidentally enabling a Neon feature on
+ * a VFP-no-Neon core or vice-versa.
+ */
+static inline bool isar_feature_aa32_simdfmac(const ARMISARegisters *id)
+{
+ return FIELD_EX32(id->mvfr1, MVFR1, SIMDFMAC) != 0;
+}
+
static inline bool isar_feature_aa32_vsel(const ARMISARegisters *id)
{
return FIELD_EX32(id->mvfr2, MVFR2, FPMISC) >= 1;
@@ -3536,6 +3577,11 @@ static inline bool isar_feature_aa32_ac2(const ARMISARegisters *id)
return FIELD_EX32(id->id_mmfr4, ID_MMFR4, AC2) != 0;
}
+static inline bool isar_feature_aa32_ccidx(const ARMISARegisters *id)
+{
+ return FIELD_EX32(id->id_mmfr4, ID_MMFR4, CCIDX) != 0;
+}
+
/*
* 64-bit feature tests via id registers.
*/
@@ -3669,6 +3715,12 @@ static inline bool isar_feature_aa64_dcpodp(const ARMISARegisters *id)
return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, DPB) >= 2;
}
+static inline bool isar_feature_aa64_fp_simd(const ARMISARegisters *id)
+{
+ /* We always set the AdvSIMD and FP fields identically. */
+ return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, FP) != 0xf;
+}
+
static inline bool isar_feature_aa64_fp16(const ARMISARegisters *id)
{
/* We always set the AdvSIMD and FP fields identically wrt FP16. */
@@ -3723,8 +3775,23 @@ static inline bool isar_feature_aa64_pmu_8_1(const ARMISARegisters *id)
static inline bool isar_feature_aa64_pmu_8_4(const ARMISARegisters *id)
{
- return FIELD_EX32(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) >= 5 &&
- FIELD_EX32(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) != 0xf;
+ return FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) >= 5 &&
+ FIELD_EX64(id->id_aa64dfr0, ID_AA64DFR0, PMUVER) != 0xf;
+}
+
+static inline bool isar_feature_aa64_rcpc_8_3(const ARMISARegisters *id)
+{
+ return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, LRCPC) != 0;
+}
+
+static inline bool isar_feature_aa64_rcpc_8_4(const ARMISARegisters *id)
+{
+ return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, LRCPC) >= 2;
+}
+
+static inline bool isar_feature_aa64_ccidx(const ARMISARegisters *id)
+{
+ return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, CCIDX) != 0;
}
/*
@@ -3750,6 +3817,11 @@ static inline bool isar_feature_any_pmu_8_4(const ARMISARegisters *id)
return isar_feature_aa64_pmu_8_4(id) || isar_feature_aa32_pmu_8_4(id);
}
+static inline bool isar_feature_any_ccidx(const ARMISARegisters *id)
+{
+ return isar_feature_aa64_ccidx(id) || isar_feature_aa32_ccidx(id);
+}
+
/*
* Forward to the above feature tests given an ARMCPU pointer.
*/
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index 0929401a4d..b842e2b664 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -102,7 +102,6 @@ static void aarch64_a57_initfn(Object *obj)
cpu->dtb_compatible = "arm,cortex-a57";
set_feature(&cpu->env, ARM_FEATURE_V8);
- set_feature(&cpu->env, ARM_FEATURE_VFP4);
set_feature(&cpu->env, ARM_FEATURE_NEON);
set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
set_feature(&cpu->env, ARM_FEATURE_AARCH64);
@@ -156,7 +155,6 @@ static void aarch64_a53_initfn(Object *obj)
cpu->dtb_compatible = "arm,cortex-a53";
set_feature(&cpu->env, ARM_FEATURE_V8);
- set_feature(&cpu->env, ARM_FEATURE_VFP4);
set_feature(&cpu->env, ARM_FEATURE_NEON);
set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
set_feature(&cpu->env, ARM_FEATURE_AARCH64);
@@ -210,7 +208,6 @@ static void aarch64_a72_initfn(Object *obj)
cpu->dtb_compatible = "arm,cortex-a72";
set_feature(&cpu->env, ARM_FEATURE_V8);
- set_feature(&cpu->env, ARM_FEATURE_VFP4);
set_feature(&cpu->env, ARM_FEATURE_NEON);
set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
set_feature(&cpu->env, ARM_FEATURE_AARCH64);
@@ -657,6 +654,7 @@ static void aarch64_max_initfn(Object *obj)
t = FIELD_DP64(t, ID_AA64ISAR1, SB, 1);
t = FIELD_DP64(t, ID_AA64ISAR1, SPECRES, 1);
t = FIELD_DP64(t, ID_AA64ISAR1, FRINTTS, 1);
+ t = FIELD_DP64(t, ID_AA64ISAR1, LRCPC, 2); /* ARMv8.4-RCPC */
cpu->isar.id_aa64isar1 = t;
t = cpu->isar.id_aa64pfr0;
@@ -704,6 +702,7 @@ static void aarch64_max_initfn(Object *obj)
cpu->isar.id_mmfr3 = u;
u = cpu->isar.id_mmfr4;
+ u = FIELD_DP32(u, ID_MMFR4, HPDS, 1); /* AA32HPD */
u = FIELD_DP32(u, ID_MMFR4, AC2, 1); /* ACTLR2, HACTLR2 */
cpu->isar.id_mmfr4 = u;
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 79db169e04..6be9ffa09e 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -894,7 +894,7 @@ static void cpacr_write(CPUARMState *env, const ARMCPRegInfo *ri,
* ASEDIS [31] and D32DIS [30] are both UNK/SBZP without VFP.
* TRCDIS [28] is RAZ/WI since we do not implement a trace macrocell.
*/
- if (arm_feature(env, ARM_FEATURE_VFP)) {
+ if (cpu_isar_feature(aa32_vfp_simd, env_archcpu(env))) {
/* VFP coprocessor: cp10 & cp11 [23:20] */
mask |= (1 << 31) | (1 << 30) | (0xf << 20);
@@ -6726,6 +6726,21 @@ static const ARMCPRegInfo predinv_reginfo[] = {
REGINFO_SENTINEL
};
+static uint64_t ccsidr2_read(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+ /* Read the high 32 bits of the current CCSIDR */
+ return extract64(ccsidr_read(env, ri), 32, 32);
+}
+
+static const ARMCPRegInfo ccsidr2_reginfo[] = {
+ { .name = "CCSIDR2", .state = ARM_CP_STATE_BOTH,
+ .opc0 = 3, .opc1 = 1, .crn = 0, .crm = 0, .opc2 = 2,
+ .access = PL1_R,
+ .accessfn = access_aa64_tid2,
+ .readfn = ccsidr2_read, .type = ARM_CP_NO_RAW },
+ REGINFO_SENTINEL
+};
+
static CPAccessResult access_aa64_tid3(CPUARMState *env, const ARMCPRegInfo *ri,
bool isread)
{
@@ -7788,6 +7803,10 @@ void register_cp_regs_for_features(ARMCPU *cpu)
define_arm_cp_regs(cpu, predinv_reginfo);
}
+ if (cpu_isar_feature(any_ccidx, cpu)) {
+ define_arm_cp_regs(cpu, ccsidr2_reginfo);
+ }
+
#ifndef CONFIG_USER_ONLY
/*
* Register redirections and aliases must be done last,
@@ -7814,7 +7833,7 @@ void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu)
} else if (cpu_isar_feature(aa32_simd_r32, cpu)) {
gdb_register_coprocessor(cs, vfp_gdb_get_reg, vfp_gdb_set_reg,
35, "arm-vfp3.xml", 0);
- } else if (arm_feature(env, ARM_FEATURE_VFP)) {
+ } else if (cpu_isar_feature(aa32_vfp_simd, cpu)) {
gdb_register_coprocessor(cs, vfp_gdb_get_reg, vfp_gdb_set_reg,
19, "arm-vfp.xml", 0);
}
diff --git a/target/arm/kvm32.c b/target/arm/kvm32.c
index 7981ae3bc4..f703c4fcad 100644
--- a/target/arm/kvm32.c
+++ b/target/arm/kvm32.c
@@ -147,7 +147,6 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
* bits, but a few must be tested.
*/
set_feature(&features, ARM_FEATURE_V7VE);
- set_feature(&features, ARM_FEATURE_VFP3);
set_feature(&features, ARM_FEATURE_GENERIC_TIMER);
if (extract32(id_pfr0, 12, 4) == 1) {
@@ -156,10 +155,6 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
if (extract32(ahcf->isar.mvfr1, 12, 4) == 1) {
set_feature(&features, ARM_FEATURE_NEON);
}
- if (extract32(ahcf->isar.mvfr1, 28, 4) == 1) {
- /* FMAC support implies VFPv4 */
- set_feature(&features, ARM_FEATURE_VFP4);
- }
ahcf->features = features;
diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c
index 0ad96c3500..93ba1448da 100644
--- a/target/arm/kvm64.c
+++ b/target/arm/kvm64.c
@@ -649,7 +649,6 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
* feature bits.
*/
set_feature(&features, ARM_FEATURE_V8);
- set_feature(&features, ARM_FEATURE_VFP4);
set_feature(&features, ARM_FEATURE_NEON);
set_feature(&features, ARM_FEATURE_AARCH64);
set_feature(&features, ARM_FEATURE_PMU);
diff --git a/target/arm/m_helper.c b/target/arm/m_helper.c
index 33d414a684..5e8a795d20 100644
--- a/target/arm/m_helper.c
+++ b/target/arm/m_helper.c
@@ -738,7 +738,8 @@ static uint32_t v7m_integrity_sig(CPUARMState *env, uint32_t lr)
*/
uint32_t sig = 0xfefa125a;
- if (!arm_feature(env, ARM_FEATURE_VFP) || (lr & R_V7M_EXCRET_FTYPE_MASK)) {
+ if (!cpu_isar_feature(aa32_vfp_simd, env_archcpu(env))
+ || (lr & R_V7M_EXCRET_FTYPE_MASK)) {
sig |= 1;
}
return sig;
@@ -841,7 +842,7 @@ static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr, bool dotailchain,
if (dotailchain) {
/* Sanitize LR FType and PREFIX bits */
- if (!arm_feature(env, ARM_FEATURE_VFP)) {
+ if (!cpu_isar_feature(aa32_vfp_simd, cpu)) {
lr |= R_V7M_EXCRET_FTYPE_MASK;
}
lr = deposit32(lr, 24, 8, 0xff);
@@ -1373,7 +1374,7 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
ftype = excret & R_V7M_EXCRET_FTYPE_MASK;
- if (!arm_feature(env, ARM_FEATURE_VFP) && !ftype) {
+ if (!ftype && !cpu_isar_feature(aa32_vfp_simd, cpu)) {
qemu_log_mask(LOG_GUEST_ERROR, "M profile: zero FTYPE in exception "
"exit PC value 0x%" PRIx32 " is UNPREDICTABLE "
"if FPU not present\n",
@@ -2450,7 +2451,7 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val)
* SFPA is RAZ/WI from NS. FPCA is RO if NSACR.CP10 == 0,
* RES0 if the FPU is not present, and is stored in the S bank
*/
- if (arm_feature(env, ARM_FEATURE_VFP) &&
+ if (cpu_isar_feature(aa32_vfp_simd, env_archcpu(env)) &&
extract32(env->v7m.nsacr, 10, 1)) {
env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_FPCA_MASK;
env->v7m.control[M_REG_S] |= val & R_V7M_CONTROL_FPCA_MASK;
@@ -2565,7 +2566,7 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val)
env->v7m.control[env->v7m.secure] &= ~R_V7M_CONTROL_NPRIV_MASK;
env->v7m.control[env->v7m.secure] |= val & R_V7M_CONTROL_NPRIV_MASK;
}
- if (arm_feature(env, ARM_FEATURE_VFP)) {
+ if (cpu_isar_feature(aa32_vfp_simd, env_archcpu(env))) {
/*
* SFPA is RAZ/WI from NS or if no FPU.
* FPCA is RO if NSACR.CP10 == 0, RES0 if the FPU is not present.
diff --git a/target/arm/machine.c b/target/arm/machine.c
index 241890ac8c..c5a2114f51 100644
--- a/target/arm/machine.c
+++ b/target/arm/machine.c
@@ -9,9 +9,10 @@
static bool vfp_needed(void *opaque)
{
ARMCPU *cpu = opaque;
- CPUARMState *env = &cpu->env;
- return arm_feature(env, ARM_FEATURE_VFP);
+ return (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)
+ ? cpu_isar_feature(aa64_fp_simd, cpu)
+ : cpu_isar_feature(aa32_vfp_simd, cpu));
}
static int get_fpscr(QEMUFile *f, void *opaque, size_t size,
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
index 596bf4cf73..579180af0a 100644
--- a/target/arm/translate-a64.c
+++ b/target/arm/translate-a64.c
@@ -3142,6 +3142,8 @@ static void disas_ldst_atomic(DisasContext *s, uint32_t insn,
int rs = extract32(insn, 16, 5);
int rn = extract32(insn, 5, 5);
int o3_opc = extract32(insn, 12, 4);
+ bool r = extract32(insn, 22, 1);
+ bool a = extract32(insn, 23, 1);
TCGv_i64 tcg_rs, clean_addr;
AtomicThreeOpFn *fn;
@@ -3177,6 +3179,13 @@ static void disas_ldst_atomic(DisasContext *s, uint32_t insn,
case 010: /* SWP */
fn = tcg_gen_atomic_xchg_i64;
break;
+ case 014: /* LDAPR, LDAPRH, LDAPRB */
+ if (!dc_isar_feature(aa64_rcpc_8_3, s) ||
+ rs != 31 || a != 1 || r != 0) {
+ unallocated_encoding(s);
+ return;
+ }
+ break;
default:
unallocated_encoding(s);
return;
@@ -3186,6 +3195,21 @@ static void disas_ldst_atomic(DisasContext *s, uint32_t insn,
gen_check_sp_alignment(s);
}
clean_addr = clean_data_tbi(s, cpu_reg_sp(s, rn));
+
+ if (o3_opc == 014) {
+ /*
+ * LDAPR* are a special case because they are a simple load, not a
+ * fetch-and-do-something op.
+ * The architectural consistency requirements here are weaker than
+ * full load-acquire (we only need "load-acquire processor consistent"),
+ * but we choose to implement them as full LDAQ.
+ */
+ do_gpr_ld(s, cpu_reg(s, rt), clean_addr, size, false, false,
+ true, rt, disas_ldst_compute_iss_sf(size, false, 0), true);
+ tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
+ return;
+ }
+
tcg_rs = read_cpu_reg(s, rs, true);
if (o3_opc == 1) { /* LDCLR */
@@ -3259,6 +3283,88 @@ static void disas_ldst_pac(DisasContext *s, uint32_t insn,
}
}
+/*
+ * LDAPR/STLR (unscaled immediate)
+ *
+ * 31 30 24 22 21 12 10 5 0
+ * +------+-------------+-----+---+--------+-----+----+-----+
+ * | size | 0 1 1 0 0 1 | opc | 0 | imm9 | 0 0 | Rn | Rt |
+ * +------+-------------+-----+---+--------+-----+----+-----+
+ *
+ * Rt: source or destination register
+ * Rn: base register
+ * imm9: unscaled immediate offset
+ * opc: 00: STLUR*, 01/10/11: various LDAPUR*
+ * size: size of load/store
+ */
+static void disas_ldst_ldapr_stlr(DisasContext *s, uint32_t insn)
+{
+ int rt = extract32(insn, 0, 5);
+ int rn = extract32(insn, 5, 5);
+ int offset = sextract32(insn, 12, 9);
+ int opc = extract32(insn, 22, 2);
+ int size = extract32(insn, 30, 2);
+ TCGv_i64 clean_addr, dirty_addr;
+ bool is_store = false;
+ bool is_signed = false;
+ bool extend = false;
+ bool iss_sf;
+
+ if (!dc_isar_feature(aa64_rcpc_8_4, s)) {
+ unallocated_encoding(s);
+ return;
+ }
+
+ switch (opc) {
+ case 0: /* STLURB */
+ is_store = true;
+ break;
+ case 1: /* LDAPUR* */
+ break;
+ case 2: /* LDAPURS* 64-bit variant */
+ if (size == 3) {
+ unallocated_encoding(s);
+ return;
+ }
+ is_signed = true;
+ break;
+ case 3: /* LDAPURS* 32-bit variant */
+ if (size > 1) {
+ unallocated_encoding(s);
+ return;
+ }
+ is_signed = true;
+ extend = true; /* zero-extend 32->64 after signed load */
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ iss_sf = disas_ldst_compute_iss_sf(size, is_signed, opc);
+
+ if (rn == 31) {
+ gen_check_sp_alignment(s);
+ }
+
+ dirty_addr = read_cpu_reg_sp(s, rn, 1);
+ tcg_gen_addi_i64(dirty_addr, dirty_addr, offset);
+ clean_addr = clean_data_tbi(s, dirty_addr);
+
+ if (is_store) {
+ /* Store-Release semantics */
+ tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
+ do_gpr_st(s, cpu_reg(s, rt), clean_addr, size, true, rt, iss_sf, true);
+ } else {
+ /*
+ * Load-AcquirePC semantics; we implement as the slightly more
+ * restrictive Load-Acquire.
+ */
+ do_gpr_ld(s, cpu_reg(s, rt), clean_addr, size, is_signed, extend,
+ true, rt, iss_sf, true);
+ tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
+ }
+}
+
/* Load/store register (all forms) */
static void disas_ldst_reg(DisasContext *s, uint32_t insn)
{
@@ -3610,6 +3716,14 @@ static void disas_ldst(DisasContext *s, uint32_t insn)
case 0x0d: /* AdvSIMD load/store single structure */
disas_ldst_single_struct(s, insn);
break;
+ case 0x19: /* LDAPR/STLR (unscaled immediate) */
+ if (extract32(insn, 10, 2) != 0 ||
+ extract32(insn, 21, 1) != 0) {
+ unallocated_encoding(s);
+ break;
+ }
+ disas_ldst_ldapr_stlr(s, insn);
+ break;
default:
unallocated_encoding(s);
break;
diff --git a/target/arm/translate-vfp.inc.c b/target/arm/translate-vfp.inc.c
index ba46e2557a..b087bbd812 100644
--- a/target/arm/translate-vfp.inc.c
+++ b/target/arm/translate-vfp.inc.c
@@ -200,13 +200,13 @@ static bool trans_VSEL(DisasContext *s, arg_VSEL *a)
return false;
}
- /* UNDEF accesses to D16-D31 if they don't exist */
- if (dp && !dc_isar_feature(aa32_simd_r32, s) &&
- ((a->vm | a->vn | a->vd) & 0x10)) {
+ if (dp && !dc_isar_feature(aa32_fpdp_v2, s)) {
return false;
}
- if (dp && !dc_isar_feature(aa32_fpdp, s)) {
+ /* UNDEF accesses to D16-D31 if they don't exist */
+ if (dp && !dc_isar_feature(aa32_simd_r32, s) &&
+ ((a->vm | a->vn | a->vd) & 0x10)) {
return false;
}
@@ -322,79 +322,6 @@ static bool trans_VSEL(DisasContext *s, arg_VSEL *a)
return true;
}
-static bool trans_VMINMAXNM(DisasContext *s, arg_VMINMAXNM *a)
-{
- uint32_t rd, rn, rm;
- bool dp = a->dp;
- bool vmin = a->op;
- TCGv_ptr fpst;
-
- if (!dc_isar_feature(aa32_vminmaxnm, s)) {
- return false;
- }
-
- /* UNDEF accesses to D16-D31 if they don't exist */
- if (dp && !dc_isar_feature(aa32_simd_r32, s) &&
- ((a->vm | a->vn | a->vd) & 0x10)) {
- return false;
- }
-
- if (dp && !dc_isar_feature(aa32_fpdp, s)) {
- return false;
- }
-
- rd = a->vd;
- rn = a->vn;
- rm = a->vm;
-
- if (!vfp_access_check(s)) {
- return true;
- }
-
- fpst = get_fpstatus_ptr(0);
-
- if (dp) {
- TCGv_i64 frn, frm, dest;
-
- frn = tcg_temp_new_i64();
- frm = tcg_temp_new_i64();
- dest = tcg_temp_new_i64();
-
- neon_load_reg64(frn, rn);
- neon_load_reg64(frm, rm);
- if (vmin) {
- gen_helper_vfp_minnumd(dest, frn, frm, fpst);
- } else {
- gen_helper_vfp_maxnumd(dest, frn, frm, fpst);
- }
- neon_store_reg64(dest, rd);
- tcg_temp_free_i64(frn);
- tcg_temp_free_i64(frm);
- tcg_temp_free_i64(dest);
- } else {
- TCGv_i32 frn, frm, dest;
-
- frn = tcg_temp_new_i32();
- frm = tcg_temp_new_i32();
- dest = tcg_temp_new_i32();
-
- neon_load_reg32(frn, rn);
- neon_load_reg32(frm, rm);
- if (vmin) {
- gen_helper_vfp_minnums(dest, frn, frm, fpst);
- } else {
- gen_helper_vfp_maxnums(dest, frn, frm, fpst);
- }
- neon_store_reg32(dest, rd);
- tcg_temp_free_i32(frn);
- tcg_temp_free_i32(frm);
- tcg_temp_free_i32(dest);
- }
-
- tcg_temp_free_ptr(fpst);
- return true;
-}
-
/*
* Table for converting the most common AArch32 encoding of
* rounding mode to arm_fprounding order (which matches the
@@ -419,13 +346,13 @@ static bool trans_VRINT(DisasContext *s, arg_VRINT *a)
return false;
}
- /* UNDEF accesses to D16-D31 if they don't exist */
- if (dp && !dc_isar_feature(aa32_simd_r32, s) &&
- ((a->vm | a->vd) & 0x10)) {
+ if (dp && !dc_isar_feature(aa32_fpdp_v2, s)) {
return false;
}
- if (dp && !dc_isar_feature(aa32_fpdp, s)) {
+ /* UNDEF accesses to D16-D31 if they don't exist */
+ if (dp && !dc_isar_feature(aa32_simd_r32, s) &&
+ ((a->vm | a->vd) & 0x10)) {
return false;
}
@@ -483,12 +410,12 @@ static bool trans_VCVT(DisasContext *s, arg_VCVT *a)
return false;
}
- /* UNDEF accesses to D16-D31 if they don't exist */
- if (dp && !dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) {
+ if (dp && !dc_isar_feature(aa32_fpdp_v2, s)) {
return false;
}
- if (dp && !dc_isar_feature(aa32_fpdp, s)) {
+ /* UNDEF accesses to D16-D31 if they don't exist */
+ if (dp && !dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) {
return false;
}
@@ -555,6 +482,13 @@ static bool trans_VMOV_to_gp(DisasContext *s, arg_VMOV_to_gp *a)
int pass;
uint32_t offset;
+ /* SIZE == 2 is a VFP instruction; otherwise NEON. */
+ if (a->size == 2
+ ? !dc_isar_feature(aa32_fpsp_v2, s)
+ : !arm_dc_feature(s, ARM_FEATURE_NEON)) {
+ return false;
+ }
+
/* UNDEF accesses to D16-D31 if they don't exist */
if (!dc_isar_feature(aa32_simd_r32, s) && (a->vn & 0x10)) {
return false;
@@ -564,10 +498,6 @@ static bool trans_VMOV_to_gp(DisasContext *s, arg_VMOV_to_gp *a)
pass = extract32(offset, 2, 1);
offset = extract32(offset, 0, 2) * 8;
- if (a->size != 2 && !arm_dc_feature(s, ARM_FEATURE_NEON)) {
- return false;
- }
-
if (!vfp_access_check(s)) {
return true;
}
@@ -614,6 +544,13 @@ static bool trans_VMOV_from_gp(DisasContext *s, arg_VMOV_from_gp *a)
int pass;
uint32_t offset;
+ /* SIZE == 2 is a VFP instruction; otherwise NEON. */
+ if (a->size == 2
+ ? !dc_isar_feature(aa32_fpsp_v2, s)
+ : !arm_dc_feature(s, ARM_FEATURE_NEON)) {
+ return false;
+ }
+
/* UNDEF accesses to D16-D31 if they don't exist */
if (!dc_isar_feature(aa32_simd_r32, s) && (a->vn & 0x10)) {
return false;
@@ -623,10 +560,6 @@ static bool trans_VMOV_from_gp(DisasContext *s, arg_VMOV_from_gp *a)
pass = extract32(offset, 2, 1);
offset = extract32(offset, 0, 2) * 8;
- if (a->size != 2 && !arm_dc_feature(s, ARM_FEATURE_NEON)) {
- return false;
- }
-
if (!vfp_access_check(s)) {
return true;
}
@@ -700,6 +633,10 @@ 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)) {
/*
* The only M-profile VFP vmrs/vmsr sysreg is FPSCR.
@@ -717,7 +654,7 @@ static bool trans_VMSR_VMRS(DisasContext *s, arg_VMSR_VMRS *a)
* VFPv2 allows access to FPSID from userspace; VFPv3 restricts
* all ID registers to privileged access only.
*/
- if (IS_USER(s) && arm_dc_feature(s, ARM_FEATURE_VFP3)) {
+ if (IS_USER(s) && dc_isar_feature(aa32_fpsp_v3, s)) {
return false;
}
ignore_vfp_enabled = true;
@@ -746,7 +683,7 @@ static bool trans_VMSR_VMRS(DisasContext *s, arg_VMSR_VMRS *a)
case ARM_VFP_FPINST:
case ARM_VFP_FPINST2:
/* Not present in VFPv3 */
- if (IS_USER(s) || arm_dc_feature(s, ARM_FEATURE_VFP3)) {
+ if (IS_USER(s) || dc_isar_feature(aa32_fpsp_v3, s)) {
return false;
}
break;
@@ -844,6 +781,10 @@ static bool trans_VMOV_single(DisasContext *s, arg_VMOV_single *a)
{
TCGv_i32 tmp;
+ if (!dc_isar_feature(aa32_fpsp_v2, s)) {
+ return false;
+ }
+
if (!vfp_access_check(s)) {
return true;
}
@@ -873,6 +814,10 @@ static bool trans_VMOV_64_sp(DisasContext *s, arg_VMOV_64_sp *a)
{
TCGv_i32 tmp;
+ if (!dc_isar_feature(aa32_fpsp_v2, s)) {
+ return false;
+ }
+
/*
* VMOV between two general-purpose registers and two single precision
* floating point registers
@@ -908,8 +853,12 @@ static bool trans_VMOV_64_dp(DisasContext *s, arg_VMOV_64_dp *a)
/*
* VMOV between two general-purpose registers and one double precision
- * floating point register
+ * floating point register. Note that this does not require support
+ * for double precision arithmetic.
*/
+ if (!dc_isar_feature(aa32_fpsp_v2, s)) {
+ return false;
+ }
/* UNDEF accesses to D16-D31 if they don't exist */
if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) {
@@ -946,6 +895,10 @@ static bool trans_VLDR_VSTR_sp(DisasContext *s, arg_VLDR_VSTR_sp *a)
uint32_t offset;
TCGv_i32 addr, tmp;
+ if (!dc_isar_feature(aa32_fpsp_v2, s)) {
+ return false;
+ }
+
if (!vfp_access_check(s)) {
return true;
}
@@ -977,6 +930,11 @@ static bool trans_VLDR_VSTR_dp(DisasContext *s, arg_VLDR_VSTR_dp *a)
TCGv_i32 addr;
TCGv_i64 tmp;
+ /* Note that this does not require support for double arithmetic. */
+ if (!dc_isar_feature(aa32_fpsp_v2, s)) {
+ return false;
+ }
+
/* UNDEF accesses to D16-D31 if they don't exist */
if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
return false;
@@ -1013,6 +971,10 @@ static bool trans_VLDM_VSTM_sp(DisasContext *s, arg_VLDM_VSTM_sp *a)
TCGv_i32 addr, tmp;
int i, n;
+ if (!dc_isar_feature(aa32_fpsp_v2, s)) {
+ return false;
+ }
+
n = a->imm;
if (n == 0 || (a->vd + n) > 32) {
@@ -1086,6 +1048,11 @@ static bool trans_VLDM_VSTM_dp(DisasContext *s, arg_VLDM_VSTM_dp *a)
TCGv_i64 tmp;
int i, n;
+ /* Note that this does not require support for double arithmetic. */
+ if (!dc_isar_feature(aa32_fpsp_v2, s)) {
+ return false;
+ }
+
n = a->imm >> 1;
if (n == 0 || (a->vd + n) > 32 || n > 16) {
@@ -1234,6 +1201,10 @@ static bool do_vfp_3op_sp(DisasContext *s, VFPGen3OpSPFn *fn,
TCGv_i32 f0, f1, fd;
TCGv_ptr fpst;
+ if (!dc_isar_feature(aa32_fpsp_v2, s)) {
+ return false;
+ }
+
if (!dc_isar_feature(aa32_fpshvec, s) &&
(veclen != 0 || s->vec_stride != 0)) {
return false;
@@ -1308,12 +1279,12 @@ static bool do_vfp_3op_dp(DisasContext *s, VFPGen3OpDPFn *fn,
TCGv_i64 f0, f1, fd;
TCGv_ptr fpst;
- /* UNDEF accesses to D16-D31 if they don't exist */
- if (!dc_isar_feature(aa32_simd_r32, s) && ((vd | vn | vm) & 0x10)) {
+ if (!dc_isar_feature(aa32_fpdp_v2, s)) {
return false;
}
- if (!dc_isar_feature(aa32_fpdp, s)) {
+ /* UNDEF accesses to D16-D31 if they don't exist */
+ if (!dc_isar_feature(aa32_simd_r32, s) && ((vd | vn | vm) & 0x10)) {
return false;
}
@@ -1388,6 +1359,10 @@ static bool do_vfp_2op_sp(DisasContext *s, VFPGen2OpSPFn *fn, int vd, int vm)
int veclen = s->vec_len;
TCGv_i32 f0, fd;
+ if (!dc_isar_feature(aa32_fpsp_v2, s)) {
+ return false;
+ }
+
if (!dc_isar_feature(aa32_fpshvec, s) &&
(veclen != 0 || s->vec_stride != 0)) {
return false;
@@ -1457,12 +1432,12 @@ static bool do_vfp_2op_dp(DisasContext *s, VFPGen2OpDPFn *fn, int vd, int vm)
int veclen = s->vec_len;
TCGv_i64 f0, fd;
- /* UNDEF accesses to D16-D31 if they don't exist */
- if (!dc_isar_feature(aa32_simd_r32, s) && ((vd | vm) & 0x10)) {
+ if (!dc_isar_feature(aa32_fpdp_v2, s)) {
return false;
}
- if (!dc_isar_feature(aa32_fpdp, s)) {
+ /* UNDEF accesses to D16-D31 if they don't exist */
+ if (!dc_isar_feature(aa32_simd_r32, s) && ((vd | vm) & 0x10)) {
return false;
}
@@ -1736,7 +1711,43 @@ static bool trans_VDIV_dp(DisasContext *s, arg_VDIV_dp *a)
return do_vfp_3op_dp(s, gen_helper_vfp_divd, a->vd, a->vn, a->vm, false);
}
-static bool trans_VFM_sp(DisasContext *s, arg_VFM_sp *a)
+static bool trans_VMINNM_sp(DisasContext *s, arg_VMINNM_sp *a)
+{
+ if (!dc_isar_feature(aa32_vminmaxnm, s)) {
+ return false;
+ }
+ return do_vfp_3op_sp(s, gen_helper_vfp_minnums,
+ a->vd, a->vn, a->vm, false);
+}
+
+static bool trans_VMAXNM_sp(DisasContext *s, arg_VMAXNM_sp *a)
+{
+ if (!dc_isar_feature(aa32_vminmaxnm, s)) {
+ return false;
+ }
+ return do_vfp_3op_sp(s, gen_helper_vfp_maxnums,
+ a->vd, a->vn, a->vm, false);
+}
+
+static bool trans_VMINNM_dp(DisasContext *s, arg_VMINNM_dp *a)
+{
+ if (!dc_isar_feature(aa32_vminmaxnm, s)) {
+ return false;
+ }
+ return do_vfp_3op_dp(s, gen_helper_vfp_minnumd,
+ a->vd, a->vn, a->vm, false);
+}
+
+static bool trans_VMAXNM_dp(DisasContext *s, arg_VMAXNM_dp *a)
+{
+ if (!dc_isar_feature(aa32_vminmaxnm, s)) {
+ return false;
+ }
+ return do_vfp_3op_dp(s, gen_helper_vfp_maxnumd,
+ a->vd, a->vn, a->vm, false);
+}
+
+static bool do_vfm_sp(DisasContext *s, arg_VFMA_sp *a, bool neg_n, bool neg_d)
{
/*
* VFNMA : fd = muladd(-fd, fn, fm)
@@ -1755,11 +1766,18 @@ static bool trans_VFM_sp(DisasContext *s, arg_VFM_sp *a)
/*
* Present in VFPv4 only.
+ * Note that we can't rely on the SIMDFMAC check alone, because
+ * in a Neon-no-VFP core that ID register field will be non-zero.
+ */
+ if (!dc_isar_feature(aa32_simdfmac, s) ||
+ !dc_isar_feature(aa32_fpsp_v2, s)) {
+ return false;
+ }
+ /*
* In v7A, UNPREDICTABLE with non-zero vector length/stride; from
* v8A, must UNDEF. We choose to UNDEF for both v7A and v8A.
*/
- if (!arm_dc_feature(s, ARM_FEATURE_VFP4) ||
- (s->vec_len != 0 || s->vec_stride != 0)) {
+ if (s->vec_len != 0 || s->vec_stride != 0) {
return false;
}
@@ -1773,12 +1791,12 @@ static bool trans_VFM_sp(DisasContext *s, arg_VFM_sp *a)
neon_load_reg32(vn, a->vn);
neon_load_reg32(vm, a->vm);
- if (a->o2) {
+ if (neg_n) {
/* VFNMS, VFMS */
gen_helper_vfp_negs(vn, vn);
}
neon_load_reg32(vd, a->vd);
- if (a->o1 & 1) {
+ if (neg_d) {
/* VFNMA, VFNMS */
gen_helper_vfp_negs(vd, vd);
}
@@ -1794,7 +1812,27 @@ static bool trans_VFM_sp(DisasContext *s, arg_VFM_sp *a)
return true;
}
-static bool trans_VFM_dp(DisasContext *s, arg_VFM_dp *a)
+static bool trans_VFMA_sp(DisasContext *s, arg_VFMA_sp *a)
+{
+ return do_vfm_sp(s, a, false, false);
+}
+
+static bool trans_VFMS_sp(DisasContext *s, arg_VFMS_sp *a)
+{
+ return do_vfm_sp(s, a, true, false);
+}
+
+static bool trans_VFNMA_sp(DisasContext *s, arg_VFNMA_sp *a)
+{
+ return do_vfm_sp(s, a, false, true);
+}
+
+static bool trans_VFNMS_sp(DisasContext *s, arg_VFNMS_sp *a)
+{
+ return do_vfm_sp(s, a, true, true);
+}
+
+static bool do_vfm_dp(DisasContext *s, arg_VFMA_dp *a, bool neg_n, bool neg_d)
{
/*
* VFNMA : fd = muladd(-fd, fn, fm)
@@ -1813,11 +1851,18 @@ static bool trans_VFM_dp(DisasContext *s, arg_VFM_dp *a)
/*
* Present in VFPv4 only.
+ * Note that we can't rely on the SIMDFMAC check alone, because
+ * in a Neon-no-VFP core that ID register field will be non-zero.
+ */
+ if (!dc_isar_feature(aa32_simdfmac, s) ||
+ !dc_isar_feature(aa32_fpdp_v2, s)) {
+ return false;
+ }
+ /*
* In v7A, UNPREDICTABLE with non-zero vector length/stride; from
* v8A, must UNDEF. We choose to UNDEF for both v7A and v8A.
*/
- if (!arm_dc_feature(s, ARM_FEATURE_VFP4) ||
- (s->vec_len != 0 || s->vec_stride != 0)) {
+ if (s->vec_len != 0 || s->vec_stride != 0) {
return false;
}
@@ -1827,7 +1872,9 @@ static bool trans_VFM_dp(DisasContext *s, arg_VFM_dp *a)
return false;
}
- if (!dc_isar_feature(aa32_fpdp, s)) {
+ /* UNDEF accesses to D16-D31 if they don't exist. */
+ if (!dc_isar_feature(aa32_simd_r32, s) &&
+ ((a->vd | a->vn | a->vm) & 0x10)) {
return false;
}
@@ -1841,12 +1888,12 @@ static bool trans_VFM_dp(DisasContext *s, arg_VFM_dp *a)
neon_load_reg64(vn, a->vn);
neon_load_reg64(vm, a->vm);
- if (a->o2) {
+ if (neg_n) {
/* VFNMS, VFMS */
gen_helper_vfp_negd(vn, vn);
}
neon_load_reg64(vd, a->vd);
- if (a->o1 & 1) {
+ if (neg_d) {
/* VFNMA, VFNMS */
gen_helper_vfp_negd(vd, vd);
}
@@ -1862,6 +1909,26 @@ static bool trans_VFM_dp(DisasContext *s, arg_VFM_dp *a)
return true;
}
+static bool trans_VFMA_dp(DisasContext *s, arg_VFMA_dp *a)
+{
+ return do_vfm_dp(s, a, false, false);
+}
+
+static bool trans_VFMS_dp(DisasContext *s, arg_VFMS_dp *a)
+{
+ return do_vfm_dp(s, a, true, false);
+}
+
+static bool trans_VFNMA_dp(DisasContext *s, arg_VFNMA_dp *a)
+{
+ return do_vfm_dp(s, a, false, true);
+}
+
+static bool trans_VFNMS_dp(DisasContext *s, arg_VFNMS_dp *a)
+{
+ return do_vfm_dp(s, a, true, true);
+}
+
static bool trans_VMOV_imm_sp(DisasContext *s, arg_VMOV_imm_sp *a)
{
uint32_t delta_d = 0;
@@ -1871,12 +1938,12 @@ static bool trans_VMOV_imm_sp(DisasContext *s, arg_VMOV_imm_sp *a)
vd = a->vd;
- if (!dc_isar_feature(aa32_fpshvec, s) &&
- (veclen != 0 || s->vec_stride != 0)) {
+ if (!dc_isar_feature(aa32_fpsp_v3, s)) {
return false;
}
- if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) {
+ if (!dc_isar_feature(aa32_fpshvec, s) &&
+ (veclen != 0 || s->vec_stride != 0)) {
return false;
}
@@ -1921,12 +1988,12 @@ static bool trans_VMOV_imm_dp(DisasContext *s, arg_VMOV_imm_dp *a)
vd = a->vd;
- /* UNDEF accesses to D16-D31 if they don't exist. */
- if (!dc_isar_feature(aa32_simd_r32, s) && (vd & 0x10)) {
+ if (!dc_isar_feature(aa32_fpdp_v3, s)) {
return false;
}
- if (!dc_isar_feature(aa32_fpdp, s)) {
+ /* UNDEF accesses to D16-D31 if they don't exist. */
+ if (!dc_isar_feature(aa32_simd_r32, s) && (vd & 0x10)) {
return false;
}
@@ -1935,10 +2002,6 @@ static bool trans_VMOV_imm_dp(DisasContext *s, arg_VMOV_imm_dp *a)
return false;
}
- if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) {
- return false;
- }
-
if (!vfp_access_check(s)) {
return true;
}
@@ -2025,6 +2088,10 @@ static bool trans_VCMP_sp(DisasContext *s, arg_VCMP_sp *a)
{
TCGv_i32 vd, vm;
+ if (!dc_isar_feature(aa32_fpsp_v2, s)) {
+ return false;
+ }
+
/* Vm/M bits must be zero for the Z variant */
if (a->z && a->vm != 0) {
return false;
@@ -2060,6 +2127,10 @@ static bool trans_VCMP_dp(DisasContext *s, arg_VCMP_dp *a)
{
TCGv_i64 vd, vm;
+ if (!dc_isar_feature(aa32_fpdp_v2, s)) {
+ return false;
+ }
+
/* Vm/M bits must be zero for the Z variant */
if (a->z && a->vm != 0) {
return false;
@@ -2070,10 +2141,6 @@ static bool trans_VCMP_dp(DisasContext *s, arg_VCMP_dp *a)
return false;
}
- if (!dc_isar_feature(aa32_fpdp, s)) {
- return false;
- }
-
if (!vfp_access_check(s)) {
return true;
}
@@ -2134,16 +2201,16 @@ static bool trans_VCVT_f64_f16(DisasContext *s, arg_VCVT_f64_f16 *a)
TCGv_i32 tmp;
TCGv_i64 vd;
- if (!dc_isar_feature(aa32_fp16_dpconv, s)) {
+ if (!dc_isar_feature(aa32_fpdp_v2, s)) {
return false;
}
- /* UNDEF accesses to D16-D31 if they don't exist. */
- if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
+ if (!dc_isar_feature(aa32_fp16_dpconv, s)) {
return false;
}
- if (!dc_isar_feature(aa32_fpdp, s)) {
+ /* UNDEF accesses to D16-D31 if they don't exist. */
+ if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
return false;
}
@@ -2200,16 +2267,16 @@ static bool trans_VCVT_f16_f64(DisasContext *s, arg_VCVT_f16_f64 *a)
TCGv_i32 tmp;
TCGv_i64 vm;
- if (!dc_isar_feature(aa32_fp16_dpconv, s)) {
+ if (!dc_isar_feature(aa32_fpdp_v2, s)) {
return false;
}
- /* UNDEF accesses to D16-D31 if they don't exist. */
- if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) {
+ if (!dc_isar_feature(aa32_fp16_dpconv, s)) {
return false;
}
- if (!dc_isar_feature(aa32_fpdp, s)) {
+ /* UNDEF accesses to D16-D31 if they don't exist. */
+ if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) {
return false;
}
@@ -2260,16 +2327,16 @@ static bool trans_VRINTR_dp(DisasContext *s, arg_VRINTR_dp *a)
TCGv_ptr fpst;
TCGv_i64 tmp;
- if (!dc_isar_feature(aa32_vrint, s)) {
+ if (!dc_isar_feature(aa32_fpdp_v2, s)) {
return false;
}
- /* UNDEF accesses to D16-D31 if they don't exist. */
- if (!dc_isar_feature(aa32_simd_r32, s) && ((a->vd | a->vm) & 0x10)) {
+ if (!dc_isar_feature(aa32_vrint, s)) {
return false;
}
- if (!dc_isar_feature(aa32_fpdp, s)) {
+ /* UNDEF accesses to D16-D31 if they don't exist. */
+ if (!dc_isar_feature(aa32_simd_r32, s) && ((a->vd | a->vm) & 0x10)) {
return false;
}
@@ -2321,16 +2388,16 @@ static bool trans_VRINTZ_dp(DisasContext *s, arg_VRINTZ_dp *a)
TCGv_i64 tmp;
TCGv_i32 tcg_rmode;
- if (!dc_isar_feature(aa32_vrint, s)) {
+ if (!dc_isar_feature(aa32_fpdp_v2, s)) {
return false;
}
- /* UNDEF accesses to D16-D31 if they don't exist. */
- if (!dc_isar_feature(aa32_simd_r32, s) && ((a->vd | a->vm) & 0x10)) {
+ if (!dc_isar_feature(aa32_vrint, s)) {
return false;
}
- if (!dc_isar_feature(aa32_fpdp, s)) {
+ /* UNDEF accesses to D16-D31 if they don't exist. */
+ if (!dc_isar_feature(aa32_simd_r32, s) && ((a->vd | a->vm) & 0x10)) {
return false;
}
@@ -2380,16 +2447,16 @@ static bool trans_VRINTX_dp(DisasContext *s, arg_VRINTX_dp *a)
TCGv_ptr fpst;
TCGv_i64 tmp;
- if (!dc_isar_feature(aa32_vrint, s)) {
+ if (!dc_isar_feature(aa32_fpdp_v2, s)) {
return false;
}
- /* UNDEF accesses to D16-D31 if they don't exist. */
- if (!dc_isar_feature(aa32_simd_r32, s) && ((a->vd | a->vm) & 0x10)) {
+ if (!dc_isar_feature(aa32_vrint, s)) {
return false;
}
- if (!dc_isar_feature(aa32_fpdp, s)) {
+ /* UNDEF accesses to D16-D31 if they don't exist. */
+ if (!dc_isar_feature(aa32_simd_r32, s) && ((a->vd | a->vm) & 0x10)) {
return false;
}
@@ -2412,12 +2479,12 @@ static bool trans_VCVT_sp(DisasContext *s, arg_VCVT_sp *a)
TCGv_i64 vd;
TCGv_i32 vm;
- /* UNDEF accesses to D16-D31 if they don't exist. */
- if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
+ if (!dc_isar_feature(aa32_fpdp_v2, s)) {
return false;
}
- if (!dc_isar_feature(aa32_fpdp, s)) {
+ /* UNDEF accesses to D16-D31 if they don't exist. */
+ if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
return false;
}
@@ -2440,12 +2507,12 @@ static bool trans_VCVT_dp(DisasContext *s, arg_VCVT_dp *a)
TCGv_i64 vm;
TCGv_i32 vd;
- /* UNDEF accesses to D16-D31 if they don't exist. */
- if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) {
+ if (!dc_isar_feature(aa32_fpdp_v2, s)) {
return false;
}
- if (!dc_isar_feature(aa32_fpdp, s)) {
+ /* UNDEF accesses to D16-D31 if they don't exist. */
+ if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) {
return false;
}
@@ -2468,6 +2535,10 @@ static bool trans_VCVT_int_sp(DisasContext *s, arg_VCVT_int_sp *a)
TCGv_i32 vm;
TCGv_ptr fpst;
+ if (!dc_isar_feature(aa32_fpsp_v2, s)) {
+ return false;
+ }
+
if (!vfp_access_check(s)) {
return true;
}
@@ -2494,12 +2565,12 @@ static bool trans_VCVT_int_dp(DisasContext *s, arg_VCVT_int_dp *a)
TCGv_i64 vd;
TCGv_ptr fpst;
- /* UNDEF accesses to D16-D31 if they don't exist. */
- if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
+ if (!dc_isar_feature(aa32_fpdp_v2, s)) {
return false;
}
- if (!dc_isar_feature(aa32_fpdp, s)) {
+ /* UNDEF accesses to D16-D31 if they don't exist. */
+ if (!dc_isar_feature(aa32_simd_r32, s) && (a->vd & 0x10)) {
return false;
}
@@ -2530,16 +2601,16 @@ static bool trans_VJCVT(DisasContext *s, arg_VJCVT *a)
TCGv_i32 vd;
TCGv_i64 vm;
- if (!dc_isar_feature(aa32_jscvt, s)) {
+ if (!dc_isar_feature(aa32_fpdp_v2, s)) {
return false;
}
- /* UNDEF accesses to D16-D31 if they don't exist. */
- if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) {
+ if (!dc_isar_feature(aa32_jscvt, s)) {
return false;
}
- if (!dc_isar_feature(aa32_fpdp, s)) {
+ /* UNDEF accesses to D16-D31 if they don't exist. */
+ if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) {
return false;
}
@@ -2563,7 +2634,7 @@ static bool trans_VCVT_fix_sp(DisasContext *s, arg_VCVT_fix_sp *a)
TCGv_ptr fpst;
int frac_bits;
- if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) {
+ if (!dc_isar_feature(aa32_fpsp_v3, s)) {
return false;
}
@@ -2623,7 +2694,7 @@ static bool trans_VCVT_fix_dp(DisasContext *s, arg_VCVT_fix_dp *a)
TCGv_ptr fpst;
int frac_bits;
- if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) {
+ if (!dc_isar_feature(aa32_fpdp_v3, s)) {
return false;
}
@@ -2632,10 +2703,6 @@ static bool trans_VCVT_fix_dp(DisasContext *s, arg_VCVT_fix_dp *a)
return false;
}
- if (!dc_isar_feature(aa32_fpdp, s)) {
- return false;
- }
-
if (!vfp_access_check(s)) {
return true;
}
@@ -2690,6 +2757,10 @@ static bool trans_VCVT_sp_int(DisasContext *s, arg_VCVT_sp_int *a)
TCGv_i32 vm;
TCGv_ptr fpst;
+ if (!dc_isar_feature(aa32_fpsp_v2, s)) {
+ return false;
+ }
+
if (!vfp_access_check(s)) {
return true;
}
@@ -2723,12 +2794,12 @@ static bool trans_VCVT_dp_int(DisasContext *s, arg_VCVT_dp_int *a)
TCGv_i64 vm;
TCGv_ptr fpst;
- /* UNDEF accesses to D16-D31 if they don't exist. */
- if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) {
+ if (!dc_isar_feature(aa32_fpdp_v2, s)) {
return false;
}
- if (!dc_isar_feature(aa32_fpdp, s)) {
+ /* UNDEF accesses to D16-D31 if they don't exist. */
+ if (!dc_isar_feature(aa32_simd_r32, s) && (a->vm & 0x10)) {
return false;
}
@@ -2760,3 +2831,42 @@ static bool trans_VCVT_dp_int(DisasContext *s, arg_VCVT_dp_int *a)
tcg_temp_free_ptr(fpst);
return true;
}
+
+/*
+ * Decode VLLDM and VLSTM are nonstandard because:
+ * * if there is no FPU then these insns must NOP in
+ * Secure state and UNDEF in Nonsecure state
+ * * if there is an FPU then these insns do not have
+ * the usual behaviour that vfp_access_check() provides of
+ * being controlled by CPACR/NSACR enable bits or the
+ * lazy-stacking logic.
+ */
+static bool trans_VLLDM_VLSTM(DisasContext *s, arg_VLLDM_VLSTM *a)
+{
+ TCGv_i32 fptr;
+
+ if (!arm_dc_feature(s, ARM_FEATURE_M) ||
+ !arm_dc_feature(s, ARM_FEATURE_V8)) {
+ return false;
+ }
+ /* If not secure, UNDEF. */
+ if (!s->v8m_secure) {
+ return false;
+ }
+ /* If no fpu, NOP. */
+ if (!dc_isar_feature(aa32_vfp, s)) {
+ return true;
+ }
+
+ fptr = load_reg(s, a->rn);
+ if (a->l) {
+ gen_helper_v7m_vlldm(cpu_env, fptr);
+ } else {
+ gen_helper_v7m_vlstm(cpu_env, fptr);
+ }
+ tcg_temp_free_i32(fptr);
+
+ /* End the TB, because we have updated FP control bits */
+ s->base.is_jmp = DISAS_UPDATE;
+ return true;
+}
diff --git a/target/arm/translate.c b/target/arm/translate.c
index 79880adaad..6259064ea7 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -2646,35 +2646,6 @@ static void gen_neon_dup_high16(TCGv_i32 var)
tcg_temp_free_i32(tmp);
}
-/*
- * Disassemble a VFP instruction. Returns nonzero if an error occurred
- * (ie. an undefined instruction).
- */
-static int disas_vfp_insn(DisasContext *s, uint32_t insn)
-{
- if (!arm_dc_feature(s, ARM_FEATURE_VFP)) {
- return 1;
- }
-
- /*
- * If the decodetree decoder handles this insn it will always
- * emit code to either execute the insn or generate an appropriate
- * exception; so we don't need to ever return non-zero to tell
- * the calling code to emit an UNDEF exception.
- */
- if (extract32(insn, 28, 4) == 0xf) {
- if (disas_vfp_uncond(s, insn)) {
- return 0;
- }
- } else {
- if (disas_vfp(s, insn)) {
- return 0;
- }
- }
- /* If the decodetree decoder didn't handle this insn, it must be UNDEF */
- return 1;
-}
-
static inline bool use_goto_tb(DisasContext *s, target_ulong dest)
{
#ifndef CONFIG_USER_ONLY
@@ -5150,7 +5121,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
}
break;
case NEON_3R_VFM_VQRDMLSH:
- if (!arm_dc_feature(s, ARM_FEATURE_VFP4)) {
+ if (!dc_isar_feature(aa32_simdfmac, s)) {
return 1;
}
break;
@@ -10782,7 +10753,9 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
ARCH(5);
/* Unconditional instructions. */
- if (disas_a32_uncond(s, insn)) {
+ /* TODO: Perhaps merge these into one decodetree output file. */
+ if (disas_a32_uncond(s, insn) ||
+ disas_vfp_uncond(s, insn)) {
return;
}
/* fall back to legacy decoder */
@@ -10809,13 +10782,6 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
}
return;
}
- if ((insn & 0x0f000e10) == 0x0e000a00) {
- /* VFP. */
- if (disas_vfp_insn(s, insn)) {
- goto illegal_op;
- }
- return;
- }
if ((insn & 0x0e000f00) == 0x0c000100) {
if (arm_dc_feature(s, ARM_FEATURE_IWMMXT)) {
/* iWMMXt register transfer. */
@@ -10846,7 +10812,9 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
arm_skip_unless(s, cond);
}
- if (disas_a32(s, insn)) {
+ /* TODO: Perhaps merge these into one decodetree output file. */
+ if (disas_a32(s, insn) ||
+ disas_vfp(s, insn)) {
return;
}
/* fall back to legacy decoder */
@@ -10856,11 +10824,10 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
case 0xd:
case 0xe:
if (((insn >> 8) & 0xe) == 10) {
- /* VFP. */
- if (disas_vfp_insn(s, insn)) {
- goto illegal_op;
- }
- } else if (disas_coproc_insn(s, insn)) {
+ /* VFP, but failed disas_vfp. */
+ goto illegal_op;
+ }
+ if (disas_coproc_insn(s, insn)) {
/* Coprocessor. */
goto illegal_op;
}
@@ -10949,7 +10916,14 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
ARCH(6T2);
}
- if (disas_t32(s, insn)) {
+ /*
+ * TODO: Perhaps merge these into one decodetree output file.
+ * Note disas_vfp is written for a32 with cond field in the
+ * top nibble. The t32 encoding requires 0xe in the top nibble.
+ */
+ if (disas_t32(s, insn) ||
+ disas_vfp_uncond(s, insn) ||
+ ((insn >> 28) == 0xe && disas_vfp(s, insn))) {
return;
}
/* fall back to legacy decoder */
@@ -10966,53 +10940,16 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
goto illegal_op; /* op0 = 0b11 : unallocated */
}
- /*
- * Decode VLLDM and VLSTM first: these are nonstandard because:
- * * if there is no FPU then these insns must NOP in
- * Secure state and UNDEF in Nonsecure state
- * * if there is an FPU then these insns do not have
- * the usual behaviour that disas_vfp_insn() provides of
- * being controlled by CPACR/NSACR enable bits or the
- * lazy-stacking logic.
- */
- if (arm_dc_feature(s, ARM_FEATURE_V8) &&
- (insn & 0xffa00f00) == 0xec200a00) {
- /* 0b1110_1100_0x1x_xxxx_xxxx_1010_xxxx_xxxx
- * - VLLDM, VLSTM
- * We choose to UNDEF if the RAZ bits are non-zero.
- */
- if (!s->v8m_secure || (insn & 0x0040f0ff)) {
- goto illegal_op;
- }
-
- if (arm_dc_feature(s, ARM_FEATURE_VFP)) {
- uint32_t rn = (insn >> 16) & 0xf;
- TCGv_i32 fptr = load_reg(s, rn);
-
- if (extract32(insn, 20, 1)) {
- gen_helper_v7m_vlldm(cpu_env, fptr);
- } else {
- gen_helper_v7m_vlstm(cpu_env, fptr);
- }
- tcg_temp_free_i32(fptr);
-
- /* End the TB, because we have updated FP control bits */
- s->base.is_jmp = DISAS_UPDATE;
- }
- break;
- }
- if (arm_dc_feature(s, ARM_FEATURE_VFP) &&
- ((insn >> 8) & 0xe) == 10) {
+ if (((insn >> 8) & 0xe) == 10 &&
+ dc_isar_feature(aa32_fpsp_v2, s)) {
/* FP, and the CPU supports it */
- if (disas_vfp_insn(s, insn)) {
- goto illegal_op;
- }
- break;
+ goto illegal_op;
+ } else {
+ /* All other insns: NOCP */
+ gen_exception_insn(s, s->pc_curr, EXCP_NOCP,
+ syn_uncategorized(),
+ default_exception_el(s));
}
-
- /* All other insns: NOCP */
- gen_exception_insn(s, s->pc_curr, EXCP_NOCP, syn_uncategorized(),
- default_exception_el(s));
break;
}
if ((insn & 0xfe000a00) == 0xfc000800
@@ -11034,9 +10971,8 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
goto illegal_op;
}
} else if (((insn >> 8) & 0xe) == 10) {
- if (disas_vfp_insn(s, insn)) {
- goto illegal_op;
- }
+ /* VFP, but failed disas_vfp. */
+ goto illegal_op;
} else {
if (insn & (1 << 28))
goto illegal_op;
diff --git a/target/arm/vfp-uncond.decode b/target/arm/vfp-uncond.decode
index 5af1f2ee66..34ca164266 100644
--- a/target/arm/vfp-uncond.decode
+++ b/target/arm/vfp-uncond.decode
@@ -41,15 +41,19 @@
%vd_dp 22:1 12:4
%vd_sp 12:4 22:1
+@vfp_dnm_s ................................ vm=%vm_sp vn=%vn_sp vd=%vd_sp
+@vfp_dnm_d ................................ vm=%vm_dp vn=%vn_dp vd=%vd_dp
+
VSEL 1111 1110 0. cc:2 .... .... 1010 .0.0 .... \
vm=%vm_sp vn=%vn_sp vd=%vd_sp dp=0
VSEL 1111 1110 0. cc:2 .... .... 1011 .0.0 .... \
vm=%vm_dp vn=%vn_dp vd=%vd_dp dp=1
-VMINMAXNM 1111 1110 1.00 .... .... 1010 . op:1 .0 .... \
- vm=%vm_sp vn=%vn_sp vd=%vd_sp dp=0
-VMINMAXNM 1111 1110 1.00 .... .... 1011 . op:1 .0 .... \
- vm=%vm_dp vn=%vn_dp vd=%vd_dp dp=1
+VMAXNM_sp 1111 1110 1.00 .... .... 1010 .0.0 .... @vfp_dnm_s
+VMINNM_sp 1111 1110 1.00 .... .... 1010 .1.0 .... @vfp_dnm_s
+
+VMAXNM_dp 1111 1110 1.00 .... .... 1011 .0.0 .... @vfp_dnm_d
+VMINNM_dp 1111 1110 1.00 .... .... 1011 .1.0 .... @vfp_dnm_d
VRINT 1111 1110 1.11 10 rm:2 .... 1010 01.0 .... \
vm=%vm_sp vd=%vd_sp dp=0
diff --git a/target/arm/vfp.decode b/target/arm/vfp.decode
index a67b3f29ee..5fd70f975a 100644
--- a/target/arm/vfp.decode
+++ b/target/arm/vfp.decode
@@ -46,6 +46,14 @@
%vmov_imm 16:4 0:4
+@vfp_dnm_s ................................ vm=%vm_sp vn=%vn_sp vd=%vd_sp
+@vfp_dnm_d ................................ vm=%vm_dp vn=%vn_dp vd=%vd_dp
+
+@vfp_dm_ss ................................ vm=%vm_sp vd=%vd_sp
+@vfp_dm_dd ................................ vm=%vm_dp vd=%vd_dp
+@vfp_dm_ds ................................ vm=%vm_sp vd=%vd_dp
+@vfp_dm_sd ................................ vm=%vm_dp vd=%vd_sp
+
# VMOV scalar to general-purpose register; note that this does
# include some Neon cases.
VMOV_to_gp ---- 1110 u:1 1. 1 .... rt:4 1011 ... 1 0000 \
@@ -66,20 +74,15 @@ VDUP ---- 1110 1 b:1 q:1 0 .... rt:4 1011 . 0 e:1 1 0000 \
vn=%vn_dp
VMSR_VMRS ---- 1110 111 l:1 reg:4 rt:4 1010 0001 0000
-VMOV_single ---- 1110 000 l:1 .... rt:4 1010 . 001 0000 \
- vn=%vn_sp
+VMOV_single ---- 1110 000 l:1 .... rt:4 1010 . 001 0000 vn=%vn_sp
-VMOV_64_sp ---- 1100 010 op:1 rt2:4 rt:4 1010 00.1 .... \
- vm=%vm_sp
-VMOV_64_dp ---- 1100 010 op:1 rt2:4 rt:4 1011 00.1 .... \
- vm=%vm_dp
+VMOV_64_sp ---- 1100 010 op:1 rt2:4 rt:4 1010 00.1 .... vm=%vm_sp
+VMOV_64_dp ---- 1100 010 op:1 rt2:4 rt:4 1011 00.1 .... vm=%vm_dp
# Note that the half-precision variants of VLDR and VSTR are
# not part of this decodetree at all because they have bits [9:8] == 0b01
-VLDR_VSTR_sp ---- 1101 u:1 .0 l:1 rn:4 .... 1010 imm:8 \
- vd=%vd_sp
-VLDR_VSTR_dp ---- 1101 u:1 .0 l:1 rn:4 .... 1011 imm:8 \
- vd=%vd_dp
+VLDR_VSTR_sp ---- 1101 u:1 .0 l:1 rn:4 .... 1010 imm:8 vd=%vd_sp
+VLDR_VSTR_dp ---- 1101 u:1 .0 l:1 rn:4 .... 1011 imm:8 vd=%vd_dp
# We split the load/store multiple up into two patterns to avoid
# overlap with other insns in the "Advanced SIMD load/store and 64-bit move"
@@ -100,84 +103,59 @@ VLDM_VSTM_dp ---- 1101 0.1 l:1 rn:4 .... 1011 imm:8 \
vd=%vd_dp p=1 u=0 w=1
# 3-register VFP data-processing; bits [23,21:20,6] identify the operation.
-VMLA_sp ---- 1110 0.00 .... .... 1010 .0.0 .... \
- vm=%vm_sp vn=%vn_sp vd=%vd_sp
-VMLA_dp ---- 1110 0.00 .... .... 1011 .0.0 .... \
- vm=%vm_dp vn=%vn_dp vd=%vd_dp
-
-VMLS_sp ---- 1110 0.00 .... .... 1010 .1.0 .... \
- vm=%vm_sp vn=%vn_sp vd=%vd_sp
-VMLS_dp ---- 1110 0.00 .... .... 1011 .1.0 .... \
- vm=%vm_dp vn=%vn_dp vd=%vd_dp
-
-VNMLS_sp ---- 1110 0.01 .... .... 1010 .0.0 .... \
- vm=%vm_sp vn=%vn_sp vd=%vd_sp
-VNMLS_dp ---- 1110 0.01 .... .... 1011 .0.0 .... \
- vm=%vm_dp vn=%vn_dp vd=%vd_dp
-
-VNMLA_sp ---- 1110 0.01 .... .... 1010 .1.0 .... \
- vm=%vm_sp vn=%vn_sp vd=%vd_sp
-VNMLA_dp ---- 1110 0.01 .... .... 1011 .1.0 .... \
- vm=%vm_dp vn=%vn_dp vd=%vd_dp
-
-VMUL_sp ---- 1110 0.10 .... .... 1010 .0.0 .... \
- vm=%vm_sp vn=%vn_sp vd=%vd_sp
-VMUL_dp ---- 1110 0.10 .... .... 1011 .0.0 .... \
- vm=%vm_dp vn=%vn_dp vd=%vd_dp
-
-VNMUL_sp ---- 1110 0.10 .... .... 1010 .1.0 .... \
- vm=%vm_sp vn=%vn_sp vd=%vd_sp
-VNMUL_dp ---- 1110 0.10 .... .... 1011 .1.0 .... \
- vm=%vm_dp vn=%vn_dp vd=%vd_dp
-
-VADD_sp ---- 1110 0.11 .... .... 1010 .0.0 .... \
- vm=%vm_sp vn=%vn_sp vd=%vd_sp
-VADD_dp ---- 1110 0.11 .... .... 1011 .0.0 .... \
- vm=%vm_dp vn=%vn_dp vd=%vd_dp
-
-VSUB_sp ---- 1110 0.11 .... .... 1010 .1.0 .... \
- vm=%vm_sp vn=%vn_sp vd=%vd_sp
-VSUB_dp ---- 1110 0.11 .... .... 1011 .1.0 .... \
- vm=%vm_dp vn=%vn_dp vd=%vd_dp
-
-VDIV_sp ---- 1110 1.00 .... .... 1010 .0.0 .... \
- vm=%vm_sp vn=%vn_sp vd=%vd_sp
-VDIV_dp ---- 1110 1.00 .... .... 1011 .0.0 .... \
- vm=%vm_dp vn=%vn_dp vd=%vd_dp
-
-VFM_sp ---- 1110 1.01 .... .... 1010 . o2:1 . 0 .... \
- vm=%vm_sp vn=%vn_sp vd=%vd_sp o1=1
-VFM_dp ---- 1110 1.01 .... .... 1011 . o2:1 . 0 .... \
- vm=%vm_dp vn=%vn_dp vd=%vd_dp o1=1
-VFM_sp ---- 1110 1.10 .... .... 1010 . o2:1 . 0 .... \
- vm=%vm_sp vn=%vn_sp vd=%vd_sp o1=2
-VFM_dp ---- 1110 1.10 .... .... 1011 . o2:1 . 0 .... \
- vm=%vm_dp vn=%vn_dp vd=%vd_dp o1=2
+VMLA_sp ---- 1110 0.00 .... .... 1010 .0.0 .... @vfp_dnm_s
+VMLA_dp ---- 1110 0.00 .... .... 1011 .0.0 .... @vfp_dnm_d
+
+VMLS_sp ---- 1110 0.00 .... .... 1010 .1.0 .... @vfp_dnm_s
+VMLS_dp ---- 1110 0.00 .... .... 1011 .1.0 .... @vfp_dnm_d
+
+VNMLS_sp ---- 1110 0.01 .... .... 1010 .0.0 .... @vfp_dnm_s
+VNMLS_dp ---- 1110 0.01 .... .... 1011 .0.0 .... @vfp_dnm_d
+
+VNMLA_sp ---- 1110 0.01 .... .... 1010 .1.0 .... @vfp_dnm_s
+VNMLA_dp ---- 1110 0.01 .... .... 1011 .1.0 .... @vfp_dnm_d
+
+VMUL_sp ---- 1110 0.10 .... .... 1010 .0.0 .... @vfp_dnm_s
+VMUL_dp ---- 1110 0.10 .... .... 1011 .0.0 .... @vfp_dnm_d
+
+VNMUL_sp ---- 1110 0.10 .... .... 1010 .1.0 .... @vfp_dnm_s
+VNMUL_dp ---- 1110 0.10 .... .... 1011 .1.0 .... @vfp_dnm_d
+
+VADD_sp ---- 1110 0.11 .... .... 1010 .0.0 .... @vfp_dnm_s
+VADD_dp ---- 1110 0.11 .... .... 1011 .0.0 .... @vfp_dnm_d
+
+VSUB_sp ---- 1110 0.11 .... .... 1010 .1.0 .... @vfp_dnm_s
+VSUB_dp ---- 1110 0.11 .... .... 1011 .1.0 .... @vfp_dnm_d
+
+VDIV_sp ---- 1110 1.00 .... .... 1010 .0.0 .... @vfp_dnm_s
+VDIV_dp ---- 1110 1.00 .... .... 1011 .0.0 .... @vfp_dnm_d
+
+VFMA_sp ---- 1110 1.10 .... .... 1010 .0. 0 .... @vfp_dnm_s
+VFMS_sp ---- 1110 1.10 .... .... 1010 .1. 0 .... @vfp_dnm_s
+VFNMA_sp ---- 1110 1.01 .... .... 1010 .0. 0 .... @vfp_dnm_s
+VFNMS_sp ---- 1110 1.01 .... .... 1010 .1. 0 .... @vfp_dnm_s
+
+VFMA_dp ---- 1110 1.10 .... .... 1011 .0.0 .... @vfp_dnm_d
+VFMS_dp ---- 1110 1.10 .... .... 1011 .1.0 .... @vfp_dnm_d
+VFNMA_dp ---- 1110 1.01 .... .... 1011 .0.0 .... @vfp_dnm_d
+VFNMS_dp ---- 1110 1.01 .... .... 1011 .1.0 .... @vfp_dnm_d
VMOV_imm_sp ---- 1110 1.11 .... .... 1010 0000 .... \
vd=%vd_sp imm=%vmov_imm
VMOV_imm_dp ---- 1110 1.11 .... .... 1011 0000 .... \
vd=%vd_dp imm=%vmov_imm
-VMOV_reg_sp ---- 1110 1.11 0000 .... 1010 01.0 .... \
- vd=%vd_sp vm=%vm_sp
-VMOV_reg_dp ---- 1110 1.11 0000 .... 1011 01.0 .... \
- vd=%vd_dp vm=%vm_dp
+VMOV_reg_sp ---- 1110 1.11 0000 .... 1010 01.0 .... @vfp_dm_ss
+VMOV_reg_dp ---- 1110 1.11 0000 .... 1011 01.0 .... @vfp_dm_dd
-VABS_sp ---- 1110 1.11 0000 .... 1010 11.0 .... \
- vd=%vd_sp vm=%vm_sp
-VABS_dp ---- 1110 1.11 0000 .... 1011 11.0 .... \
- vd=%vd_dp vm=%vm_dp
+VABS_sp ---- 1110 1.11 0000 .... 1010 11.0 .... @vfp_dm_ss
+VABS_dp ---- 1110 1.11 0000 .... 1011 11.0 .... @vfp_dm_dd
-VNEG_sp ---- 1110 1.11 0001 .... 1010 01.0 .... \
- vd=%vd_sp vm=%vm_sp
-VNEG_dp ---- 1110 1.11 0001 .... 1011 01.0 .... \
- vd=%vd_dp vm=%vm_dp
+VNEG_sp ---- 1110 1.11 0001 .... 1010 01.0 .... @vfp_dm_ss
+VNEG_dp ---- 1110 1.11 0001 .... 1011 01.0 .... @vfp_dm_dd
-VSQRT_sp ---- 1110 1.11 0001 .... 1010 11.0 .... \
- vd=%vd_sp vm=%vm_sp
-VSQRT_dp ---- 1110 1.11 0001 .... 1011 11.0 .... \
- vd=%vd_dp vm=%vm_dp
+VSQRT_sp ---- 1110 1.11 0001 .... 1010 11.0 .... @vfp_dm_ss
+VSQRT_dp ---- 1110 1.11 0001 .... 1011 11.0 .... @vfp_dm_dd
VCMP_sp ---- 1110 1.11 010 z:1 .... 1010 e:1 1.0 .... \
vd=%vd_sp vm=%vm_sp
@@ -190,32 +168,26 @@ VCVT_f32_f16 ---- 1110 1.11 0010 .... 1010 t:1 1.0 .... \
VCVT_f64_f16 ---- 1110 1.11 0010 .... 1011 t:1 1.0 .... \
vd=%vd_dp vm=%vm_sp
-# VCVTB and VCVTT to f16: Vd format is always vd_sp; Vm format depends on size bit
+# VCVTB and VCVTT to f16: Vd format is always vd_sp;
+# Vm format depends on size bit
VCVT_f16_f32 ---- 1110 1.11 0011 .... 1010 t:1 1.0 .... \
vd=%vd_sp vm=%vm_sp
VCVT_f16_f64 ---- 1110 1.11 0011 .... 1011 t:1 1.0 .... \
vd=%vd_sp vm=%vm_dp
-VRINTR_sp ---- 1110 1.11 0110 .... 1010 01.0 .... \
- vd=%vd_sp vm=%vm_sp
-VRINTR_dp ---- 1110 1.11 0110 .... 1011 01.0 .... \
- vd=%vd_dp vm=%vm_dp
+VRINTR_sp ---- 1110 1.11 0110 .... 1010 01.0 .... @vfp_dm_ss
+VRINTR_dp ---- 1110 1.11 0110 .... 1011 01.0 .... @vfp_dm_dd
-VRINTZ_sp ---- 1110 1.11 0110 .... 1010 11.0 .... \
- vd=%vd_sp vm=%vm_sp
-VRINTZ_dp ---- 1110 1.11 0110 .... 1011 11.0 .... \
- vd=%vd_dp vm=%vm_dp
+VRINTZ_sp ---- 1110 1.11 0110 .... 1010 11.0 .... @vfp_dm_ss
+VRINTZ_dp ---- 1110 1.11 0110 .... 1011 11.0 .... @vfp_dm_dd
-VRINTX_sp ---- 1110 1.11 0111 .... 1010 01.0 .... \
- vd=%vd_sp vm=%vm_sp
-VRINTX_dp ---- 1110 1.11 0111 .... 1011 01.0 .... \
- vd=%vd_dp vm=%vm_dp
+VRINTX_sp ---- 1110 1.11 0111 .... 1010 01.0 .... @vfp_dm_ss
+VRINTX_dp ---- 1110 1.11 0111 .... 1011 01.0 .... @vfp_dm_dd
-# VCVT between single and double: Vm precision depends on size; Vd is its reverse
-VCVT_sp ---- 1110 1.11 0111 .... 1010 11.0 .... \
- vd=%vd_dp vm=%vm_sp
-VCVT_dp ---- 1110 1.11 0111 .... 1011 11.0 .... \
- vd=%vd_sp vm=%vm_dp
+# VCVT between single and double:
+# Vm precision depends on size; Vd is its reverse
+VCVT_sp ---- 1110 1.11 0111 .... 1010 11.0 .... @vfp_dm_ds
+VCVT_dp ---- 1110 1.11 0111 .... 1011 11.0 .... @vfp_dm_sd
# VCVT from integer to floating point: Vm always single; Vd depends on size
VCVT_int_sp ---- 1110 1.11 1000 .... 1010 s:1 1.0 .... \
@@ -224,8 +196,7 @@ VCVT_int_dp ---- 1110 1.11 1000 .... 1011 s:1 1.0 .... \
vd=%vd_dp vm=%vm_sp
# VJCVT is always dp to sp
-VJCVT ---- 1110 1.11 1001 .... 1011 11.0 .... \
- vd=%vd_sp vm=%vm_dp
+VJCVT ---- 1110 1.11 1001 .... 1011 11.0 .... @vfp_dm_sd
# VCVT between floating-point and fixed-point. The immediate value
# is in the same format as a Vm single-precision register number.
@@ -242,3 +213,5 @@ 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
diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c
index cf84d307c6..3dd396e870 100644
--- a/target/s390x/cpu.c
+++ b/target/s390x/cpu.c
@@ -78,13 +78,13 @@ static void s390_cpu_load_normal(CPUState *s)
S390CPU *cpu = S390_CPU(s);
uint64_t spsw = ldq_phys(s->as, 0);
- cpu->env.psw.mask = spsw & 0xffffffff80000000ULL;
+ cpu->env.psw.mask = spsw & PSW_MASK_SHORT_CTRL;
/*
* Invert short psw indication, so SIE will report a specification
* exception if it was not set.
*/
cpu->env.psw.mask ^= PSW_MASK_SHORTPSW;
- cpu->env.psw.addr = spsw & 0x7fffffffULL;
+ cpu->env.psw.addr = spsw & PSW_MASK_SHORT_ADDR;
s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu);
}
@@ -144,8 +144,18 @@ static void s390_cpu_reset(CPUState *s, cpu_reset_type type)
}
/* Reset state inside the kernel that we cannot access yet from QEMU. */
- if (kvm_enabled() && type != S390_CPU_RESET_NORMAL) {
- kvm_s390_reset_vcpu(cpu);
+ if (kvm_enabled()) {
+ switch (type) {
+ case S390_CPU_RESET_CLEAR:
+ kvm_s390_reset_vcpu_clear(cpu);
+ break;
+ case S390_CPU_RESET_INITIAL:
+ kvm_s390_reset_vcpu_initial(cpu);
+ break;
+ case S390_CPU_RESET_NORMAL:
+ kvm_s390_reset_vcpu_normal(cpu);
+ break;
+ }
}
}
diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h
index 8a557fd8d1..1d17709d6e 100644
--- a/target/s390x/cpu.h
+++ b/target/s390x/cpu.h
@@ -276,7 +276,8 @@ extern const VMStateDescription vmstate_s390_cpu;
#define PSW_MASK_RI 0x0000008000000000ULL
#define PSW_MASK_64 0x0000000100000000ULL
#define PSW_MASK_32 0x0000000080000000ULL
-#define PSW_MASK_ESA_ADDR 0x000000007fffffffULL
+#define PSW_MASK_SHORT_ADDR 0x000000007fffffffULL
+#define PSW_MASK_SHORT_CTRL 0xffffffff80000000ULL
#undef PSW_ASC_PRIMARY
#undef PSW_ASC_ACCREG
diff --git a/target/s390x/helper.c b/target/s390x/helper.c
index b810ad431e..ed72684911 100644
--- a/target/s390x/helper.c
+++ b/target/s390x/helper.c
@@ -89,7 +89,7 @@ hwaddr s390_cpu_get_phys_addr_debug(CPUState *cs, vaddr vaddr)
static inline bool is_special_wait_psw(uint64_t psw_addr)
{
/* signal quiesce */
- return psw_addr == 0xfffUL;
+ return (psw_addr & 0xfffUL) == 0xfffUL;
}
void s390_handle_wait(S390CPU *cpu)
diff --git a/target/s390x/kvm-stub.c b/target/s390x/kvm-stub.c
index 5152e2bdf1..c4cd497f85 100644
--- a/target/s390x/kvm-stub.c
+++ b/target/s390x/kvm-stub.c
@@ -83,7 +83,15 @@ void kvm_s390_cmma_reset(void)
{
}
-void kvm_s390_reset_vcpu(S390CPU *cpu)
+void kvm_s390_reset_vcpu_initial(S390CPU *cpu)
+{
+}
+
+void kvm_s390_reset_vcpu_clear(S390CPU *cpu)
+{
+}
+
+void kvm_s390_reset_vcpu_normal(S390CPU *cpu)
{
}
diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c
index 30112e529c..1d6fd6a27b 100644
--- a/target/s390x/kvm.c
+++ b/target/s390x/kvm.c
@@ -151,6 +151,7 @@ static int cap_s390_irq;
static int cap_ri;
static int cap_gs;
static int cap_hpage_1m;
+static int cap_vcpu_resets;
static int active_cmma;
@@ -342,6 +343,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
cap_async_pf = kvm_check_extension(s, KVM_CAP_ASYNC_PF);
cap_mem_op = kvm_check_extension(s, KVM_CAP_S390_MEM_OP);
cap_s390_irq = kvm_check_extension(s, KVM_CAP_S390_INJECT_IRQ);
+ cap_vcpu_resets = kvm_check_extension(s, KVM_CAP_S390_VCPU_RESETS);
if (!kvm_check_extension(s, KVM_CAP_S390_GMAP)
|| !kvm_check_extension(s, KVM_CAP_S390_COW)) {
@@ -406,17 +408,41 @@ int kvm_arch_destroy_vcpu(CPUState *cs)
return 0;
}
-void kvm_s390_reset_vcpu(S390CPU *cpu)
+static void kvm_s390_reset_vcpu(S390CPU *cpu, unsigned long type)
{
CPUState *cs = CPU(cpu);
- /* The initial reset call is needed here to reset in-kernel
- * vcpu data that we can't access directly from QEMU
- * (i.e. with older kernels which don't support sync_regs/ONE_REG).
- * Before this ioctl cpu_synchronize_state() is called in common kvm
- * code (kvm-all) */
- if (kvm_vcpu_ioctl(cs, KVM_S390_INITIAL_RESET, NULL)) {
- error_report("Initial CPU reset failed on CPU %i", cs->cpu_index);
+ /*
+ * The reset call is needed here to reset in-kernel vcpu data that
+ * we can't access directly from QEMU (i.e. with older kernels
+ * which don't support sync_regs/ONE_REG). Before this ioctl
+ * cpu_synchronize_state() is called in common kvm code
+ * (kvm-all).
+ */
+ if (kvm_vcpu_ioctl(cs, type)) {
+ error_report("CPU reset failed on CPU %i type %lx",
+ cs->cpu_index, type);
+ }
+}
+
+void kvm_s390_reset_vcpu_initial(S390CPU *cpu)
+{
+ kvm_s390_reset_vcpu(cpu, KVM_S390_INITIAL_RESET);
+}
+
+void kvm_s390_reset_vcpu_clear(S390CPU *cpu)
+{
+ if (cap_vcpu_resets) {
+ kvm_s390_reset_vcpu(cpu, KVM_S390_CLEAR_RESET);
+ } else {
+ kvm_s390_reset_vcpu(cpu, KVM_S390_INITIAL_RESET);
+ }
+}
+
+void kvm_s390_reset_vcpu_normal(S390CPU *cpu)
+{
+ if (cap_vcpu_resets) {
+ kvm_s390_reset_vcpu(cpu, KVM_S390_NORMAL_RESET);
}
}
diff --git a/target/s390x/kvm_s390x.h b/target/s390x/kvm_s390x.h
index caf985955b..0b21789796 100644
--- a/target/s390x/kvm_s390x.h
+++ b/target/s390x/kvm_s390x.h
@@ -34,7 +34,9 @@ int kvm_s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch,
int vq, bool assign);
int kvm_s390_cmma_active(void);
void kvm_s390_cmma_reset(void);
-void kvm_s390_reset_vcpu(S390CPU *cpu);
+void kvm_s390_reset_vcpu_clear(S390CPU *cpu);
+void kvm_s390_reset_vcpu_normal(S390CPU *cpu);
+void kvm_s390_reset_vcpu_initial(S390CPU *cpu);
int kvm_s390_set_mem_limit(uint64_t new_limit, uint64_t *hw_limit);
void kvm_s390_set_max_pagesize(uint64_t pagesize, Error **errp);
void kvm_s390_crypto_reset(void);
diff --git a/target/s390x/translate.c b/target/s390x/translate.c
index 0bd2073718..4f6f1e31cd 100644
--- a/target/s390x/translate.c
+++ b/target/s390x/translate.c
@@ -3874,7 +3874,7 @@ static DisasJumpType op_rosbg(DisasContext *s, DisasOps *o)
/* Operate. */
switch (s->fields.op2) {
- case 0x55: /* AND */
+ case 0x54: /* AND */
tcg_gen_ori_i64(o->in2, o->in2, ~mask);
tcg_gen_and_i64(o->out, o->out, o->in2);
break;