aboutsummaryrefslogtreecommitdiff
path: root/target
diff options
context:
space:
mode:
Diffstat (limited to 'target')
-rw-r--r--target/arm/cpu.c179
-rw-r--r--target/arm/cpu.h12
-rw-r--r--target/arm/translate-a64.c32
-rw-r--r--target/arm/translate-a64.h1
-rw-r--r--target/arm/translate-vfp.inc.c173
-rw-r--r--target/arm/translate.c240
-rw-r--r--target/arm/translate.h7
-rw-r--r--target/arm/vfp.decode10
8 files changed, 416 insertions, 238 deletions
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 2335659..376db15 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -763,6 +763,15 @@ static Property arm_cpu_cfgend_property =
static Property arm_cpu_has_pmu_property =
DEFINE_PROP_BOOL("pmu", ARMCPU, has_pmu, true);
+static Property arm_cpu_has_vfp_property =
+ DEFINE_PROP_BOOL("vfp", ARMCPU, has_vfp, true);
+
+static Property arm_cpu_has_neon_property =
+ DEFINE_PROP_BOOL("neon", ARMCPU, has_neon, true);
+
+static Property arm_cpu_has_dsp_property =
+ DEFINE_PROP_BOOL("dsp", ARMCPU, has_dsp, true);
+
static Property arm_cpu_has_mpu_property =
DEFINE_PROP_BOOL("has-mpu", ARMCPU, has_mpu, true);
@@ -803,6 +812,13 @@ 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)) {
@@ -847,6 +863,33 @@ void arm_cpu_post_init(Object *obj)
&error_abort);
}
+ /*
+ * Allow user to turn off VFP and Neon support, but only for TCG --
+ * 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)) {
+ cpu->has_vfp = true;
+ if (!kvm_enabled()) {
+ qdev_property_add_static(DEVICE(obj), &arm_cpu_has_vfp_property,
+ &error_abort);
+ }
+ }
+
+ if (arm_feature(&cpu->env, ARM_FEATURE_NEON)) {
+ cpu->has_neon = true;
+ if (!kvm_enabled()) {
+ qdev_property_add_static(DEVICE(obj), &arm_cpu_has_neon_property,
+ &error_abort);
+ }
+ }
+
+ if (arm_feature(&cpu->env, ARM_FEATURE_M) &&
+ arm_feature(&cpu->env, ARM_FEATURE_THUMB_DSP)) {
+ qdev_property_add_static(DEVICE(obj), &arm_cpu_has_dsp_property,
+ &error_abort);
+ }
+
if (arm_feature(&cpu->env, ARM_FEATURE_PMSA)) {
qdev_property_add_static(DEVICE(obj), &arm_cpu_has_mpu_property,
&error_abort);
@@ -956,6 +999,136 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
return;
}
+ if (arm_feature(env, ARM_FEATURE_AARCH64) &&
+ cpu->has_vfp != cpu->has_neon) {
+ /*
+ * This is an architectural requirement for AArch64; AArch32 is
+ * more flexible and permits VFP-no-Neon and Neon-no-VFP.
+ */
+ error_setg(errp,
+ "AArch64 CPUs must have both VFP and Neon or neither");
+ return;
+ }
+
+ if (!cpu->has_vfp) {
+ 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;
+
+ t = cpu->isar.id_aa64pfr0;
+ t = FIELD_DP64(t, ID_AA64PFR0, FP, 0xf);
+ cpu->isar.id_aa64pfr0 = t;
+
+ u = cpu->isar.id_isar6;
+ u = FIELD_DP32(u, ID_ISAR6, JSCVT, 0);
+ cpu->isar.id_isar6 = u;
+
+ u = cpu->isar.mvfr0;
+ u = FIELD_DP32(u, MVFR0, FPSP, 0);
+ u = FIELD_DP32(u, MVFR0, FPDP, 0);
+ u = FIELD_DP32(u, MVFR0, FPTRAP, 0);
+ u = FIELD_DP32(u, MVFR0, FPDIVIDE, 0);
+ u = FIELD_DP32(u, MVFR0, FPSQRT, 0);
+ u = FIELD_DP32(u, MVFR0, FPSHVEC, 0);
+ u = FIELD_DP32(u, MVFR0, FPROUND, 0);
+ cpu->isar.mvfr0 = u;
+
+ u = cpu->isar.mvfr1;
+ u = FIELD_DP32(u, MVFR1, FPFTZ, 0);
+ u = FIELD_DP32(u, MVFR1, FPDNAN, 0);
+ u = FIELD_DP32(u, MVFR1, FPHP, 0);
+ cpu->isar.mvfr1 = u;
+
+ u = cpu->isar.mvfr2;
+ u = FIELD_DP32(u, MVFR2, FPMISC, 0);
+ cpu->isar.mvfr2 = u;
+ }
+
+ if (!cpu->has_neon) {
+ uint64_t t;
+ uint32_t u;
+
+ unset_feature(env, ARM_FEATURE_NEON);
+
+ t = cpu->isar.id_aa64isar0;
+ t = FIELD_DP64(t, ID_AA64ISAR0, DP, 0);
+ cpu->isar.id_aa64isar0 = t;
+
+ t = cpu->isar.id_aa64isar1;
+ t = FIELD_DP64(t, ID_AA64ISAR1, FCMA, 0);
+ cpu->isar.id_aa64isar1 = t;
+
+ t = cpu->isar.id_aa64pfr0;
+ t = FIELD_DP64(t, ID_AA64PFR0, ADVSIMD, 0xf);
+ cpu->isar.id_aa64pfr0 = t;
+
+ u = cpu->isar.id_isar5;
+ u = FIELD_DP32(u, ID_ISAR5, RDM, 0);
+ u = FIELD_DP32(u, ID_ISAR5, VCMA, 0);
+ cpu->isar.id_isar5 = u;
+
+ u = cpu->isar.id_isar6;
+ u = FIELD_DP32(u, ID_ISAR6, DP, 0);
+ u = FIELD_DP32(u, ID_ISAR6, FHM, 0);
+ cpu->isar.id_isar6 = u;
+
+ u = cpu->isar.mvfr1;
+ u = FIELD_DP32(u, MVFR1, SIMDLS, 0);
+ 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;
+ u = FIELD_DP32(u, MVFR2, SIMDMISC, 0);
+ cpu->isar.mvfr2 = u;
+ }
+
+ if (!cpu->has_neon && !cpu->has_vfp) {
+ uint64_t t;
+ uint32_t u;
+
+ t = cpu->isar.id_aa64isar0;
+ t = FIELD_DP64(t, ID_AA64ISAR0, FHM, 0);
+ cpu->isar.id_aa64isar0 = t;
+
+ t = cpu->isar.id_aa64isar1;
+ t = FIELD_DP64(t, ID_AA64ISAR1, FRINTTS, 0);
+ cpu->isar.id_aa64isar1 = t;
+
+ u = cpu->isar.mvfr0;
+ u = FIELD_DP32(u, MVFR0, SIMDREG, 0);
+ cpu->isar.mvfr0 = u;
+ }
+
+ if (arm_feature(env, ARM_FEATURE_M) && !cpu->has_dsp) {
+ uint32_t u;
+
+ unset_feature(env, ARM_FEATURE_THUMB_DSP);
+
+ u = cpu->isar.id_isar1;
+ u = FIELD_DP32(u, ID_ISAR1, EXTEND, 1);
+ cpu->isar.id_isar1 = u;
+
+ u = cpu->isar.id_isar2;
+ u = FIELD_DP32(u, ID_ISAR2, MULTU, 1);
+ u = FIELD_DP32(u, ID_ISAR2, MULTS, 1);
+ cpu->isar.id_isar2 = u;
+
+ u = cpu->isar.id_isar3;
+ u = FIELD_DP32(u, ID_ISAR3, SIMD, 1);
+ u = FIELD_DP32(u, ID_ISAR3, SATURATE, 0);
+ cpu->isar.id_isar3 = u;
+ }
+
/* Some features automatically imply others: */
if (arm_feature(env, ARM_FEATURE_V8)) {
if (arm_feature(env, ARM_FEATURE_M)) {
@@ -1016,12 +1189,6 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
if (arm_feature(env, ARM_FEATURE_V5)) {
set_feature(env, ARM_FEATURE_V4T);
}
- if (arm_feature(env, ARM_FEATURE_VFP4)) {
- set_feature(env, ARM_FEATURE_VFP3);
- }
- if (arm_feature(env, ARM_FEATURE_VFP3)) {
- set_feature(env, ARM_FEATURE_VFP);
- }
if (arm_feature(env, ARM_FEATURE_LPAE)) {
set_feature(env, ARM_FEATURE_V7MP);
set_feature(env, ARM_FEATURE_PXN);
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 9229862..f9da672 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -786,6 +786,12 @@ struct ARMCPU {
bool has_el3;
/* CPU has PMU (Performance Monitor Unit) */
bool has_pmu;
+ /* CPU has VFP */
+ bool has_vfp;
+ /* CPU has Neon */
+ bool has_neon;
+ /* CPU has M-profile DSP extension */
+ bool has_dsp;
/* CPU has memory protection unit */
bool has_mpu;
@@ -3382,6 +3388,12 @@ static inline bool isar_feature_aa32_fpshvec(const ARMISARegisters *id)
return FIELD_EX64(id->mvfr0, MVFR0, FPSHVEC) > 0;
}
+static inline bool isar_feature_aa32_fpdp(const ARMISARegisters *id)
+{
+ /* Return true if CPU supports double precision floating point */
+ return FIELD_EX64(id->mvfr0, MVFR0, FPDP) > 0;
+}
+
/*
* We always set the FP and SIMD FP16 fields to indicate identical
* levels of support (assuming SIMD is implemented at all), so
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
index ae739f6..97f4164 100644
--- a/target/arm/translate-a64.c
+++ b/target/arm/translate-a64.c
@@ -6380,38 +6380,6 @@ static void disas_fp_3src(DisasContext *s, uint32_t insn)
}
}
-/* The imm8 encodes the sign bit, enough bits to represent an exponent in
- * the range 01....1xx to 10....0xx, and the most significant 4 bits of
- * the mantissa; see VFPExpandImm() in the v8 ARM ARM.
- */
-uint64_t vfp_expand_imm(int size, uint8_t imm8)
-{
- uint64_t imm;
-
- switch (size) {
- case MO_64:
- imm = (extract32(imm8, 7, 1) ? 0x8000 : 0) |
- (extract32(imm8, 6, 1) ? 0x3fc0 : 0x4000) |
- extract32(imm8, 0, 6);
- imm <<= 48;
- break;
- case MO_32:
- imm = (extract32(imm8, 7, 1) ? 0x8000 : 0) |
- (extract32(imm8, 6, 1) ? 0x3e00 : 0x4000) |
- (extract32(imm8, 0, 6) << 3);
- imm <<= 16;
- break;
- case MO_16:
- imm = (extract32(imm8, 7, 1) ? 0x8000 : 0) |
- (extract32(imm8, 6, 1) ? 0x3000 : 0x4000) |
- (extract32(imm8, 0, 6) << 6);
- break;
- default:
- g_assert_not_reached();
- }
- return imm;
-}
-
/* Floating point immediate
* 31 30 29 28 24 23 22 21 20 13 12 10 9 5 4 0
* +---+---+---+-----------+------+---+------------+-------+------+------+
diff --git a/target/arm/translate-a64.h b/target/arm/translate-a64.h
index 9569bc5..9ab4087 100644
--- a/target/arm/translate-a64.h
+++ b/target/arm/translate-a64.h
@@ -39,7 +39,6 @@ void write_fp_dreg(DisasContext *s, int reg, TCGv_i64 v);
TCGv_ptr get_fpstatus_ptr(bool);
bool logic_imm_decode_wmask(uint64_t *result, unsigned int immn,
unsigned int imms, unsigned int immr);
-uint64_t vfp_expand_imm(int size, uint8_t imm8);
bool sve_access_check(DisasContext *s);
/* We should have at some point before trying to access an FP register
diff --git a/target/arm/translate-vfp.inc.c b/target/arm/translate-vfp.inc.c
index 709fc65..348173d 100644
--- a/target/arm/translate-vfp.inc.c
+++ b/target/arm/translate-vfp.inc.c
@@ -31,6 +31,39 @@
#include "decode-vfp-uncond.inc.c"
/*
+ * The imm8 encodes the sign bit, enough bits to represent an exponent in
+ * the range 01....1xx to 10....0xx, and the most significant 4 bits of
+ * the mantissa; see VFPExpandImm() in the v8 ARM ARM.
+ */
+uint64_t vfp_expand_imm(int size, uint8_t imm8)
+{
+ uint64_t imm;
+
+ switch (size) {
+ case MO_64:
+ imm = (extract32(imm8, 7, 1) ? 0x8000 : 0) |
+ (extract32(imm8, 6, 1) ? 0x3fc0 : 0x4000) |
+ extract32(imm8, 0, 6);
+ imm <<= 48;
+ break;
+ case MO_32:
+ imm = (extract32(imm8, 7, 1) ? 0x8000 : 0) |
+ (extract32(imm8, 6, 1) ? 0x3e00 : 0x4000) |
+ (extract32(imm8, 0, 6) << 3);
+ imm <<= 16;
+ break;
+ case MO_16:
+ imm = (extract32(imm8, 7, 1) ? 0x8000 : 0) |
+ (extract32(imm8, 6, 1) ? 0x3000 : 0x4000) |
+ (extract32(imm8, 0, 6) << 6);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ return imm;
+}
+
+/*
* Return the offset of a 16-bit half of the specified VFP single-precision
* register. If top is true, returns the top 16 bits; otherwise the bottom
* 16 bits.
@@ -173,6 +206,11 @@ static bool trans_VSEL(DisasContext *s, arg_VSEL *a)
((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;
@@ -301,6 +339,11 @@ static bool trans_VMINMAXNM(DisasContext *s, arg_VMINMAXNM *a)
((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;
@@ -382,6 +425,11 @@ static bool trans_VRINT(DisasContext *s, arg_VRINT *a)
((a->vm | a->vd) & 0x10)) {
return false;
}
+
+ if (dp && !dc_isar_feature(aa32_fpdp, s)) {
+ return false;
+ }
+
rd = a->vd;
rm = a->vm;
@@ -440,6 +488,11 @@ static bool trans_VCVT(DisasContext *s, arg_VCVT *a)
if (dp && !dc_isar_feature(aa32_fp_d32, s) && (a->vm & 0x10)) {
return false;
}
+
+ if (dp && !dc_isar_feature(aa32_fpdp, s)) {
+ return false;
+ }
+
rd = a->vd;
rm = a->vm;
@@ -835,7 +888,7 @@ static bool trans_VMOV_64_sp(DisasContext *s, arg_VMOV_64_sp *a)
return true;
}
-static bool trans_VMOV_64_dp(DisasContext *s, arg_VMOV_64_sp *a)
+static bool trans_VMOV_64_dp(DisasContext *s, arg_VMOV_64_dp *a)
{
TCGv_i32 tmp;
@@ -910,7 +963,7 @@ static bool trans_VLDR_VSTR_sp(DisasContext *s, arg_VLDR_VSTR_sp *a)
return true;
}
-static bool trans_VLDR_VSTR_dp(DisasContext *s, arg_VLDR_VSTR_sp *a)
+static bool trans_VLDR_VSTR_dp(DisasContext *s, arg_VLDR_VSTR_dp *a)
{
uint32_t offset;
TCGv_i32 addr;
@@ -1268,6 +1321,10 @@ static bool do_vfp_3op_dp(DisasContext *s, VFPGen3OpDPFn *fn,
return false;
}
+ if (!dc_isar_feature(aa32_fpdp, s)) {
+ return false;
+ }
+
if (!dc_isar_feature(aa32_fpshvec, s) &&
(veclen != 0 || s->vec_stride != 0)) {
return false;
@@ -1413,6 +1470,10 @@ static bool do_vfp_2op_dp(DisasContext *s, VFPGen2OpDPFn *fn, int vd, int vm)
return false;
}
+ if (!dc_isar_feature(aa32_fpdp, s)) {
+ return false;
+ }
+
if (!dc_isar_feature(aa32_fpshvec, s) &&
(veclen != 0 || s->vec_stride != 0)) {
return false;
@@ -1500,7 +1561,7 @@ static void gen_VMLA_dp(TCGv_i64 vd, TCGv_i64 vn, TCGv_i64 vm, TCGv_ptr fpst)
tcg_temp_free_i64(tmp);
}
-static bool trans_VMLA_dp(DisasContext *s, arg_VMLA_sp *a)
+static bool trans_VMLA_dp(DisasContext *s, arg_VMLA_dp *a)
{
return do_vfp_3op_dp(s, gen_VMLA_dp, a->vd, a->vn, a->vm, true);
}
@@ -1538,7 +1599,7 @@ static void gen_VMLS_dp(TCGv_i64 vd, TCGv_i64 vn, TCGv_i64 vm, TCGv_ptr fpst)
tcg_temp_free_i64(tmp);
}
-static bool trans_VMLS_dp(DisasContext *s, arg_VMLS_sp *a)
+static bool trans_VMLS_dp(DisasContext *s, arg_VMLS_dp *a)
{
return do_vfp_3op_dp(s, gen_VMLS_dp, a->vd, a->vn, a->vm, true);
}
@@ -1580,7 +1641,7 @@ static void gen_VNMLS_dp(TCGv_i64 vd, TCGv_i64 vn, TCGv_i64 vm, TCGv_ptr fpst)
tcg_temp_free_i64(tmp);
}
-static bool trans_VNMLS_dp(DisasContext *s, arg_VNMLS_sp *a)
+static bool trans_VNMLS_dp(DisasContext *s, arg_VNMLS_dp *a)
{
return do_vfp_3op_dp(s, gen_VNMLS_dp, a->vd, a->vn, a->vm, true);
}
@@ -1614,7 +1675,7 @@ static void gen_VNMLA_dp(TCGv_i64 vd, TCGv_i64 vn, TCGv_i64 vm, TCGv_ptr fpst)
tcg_temp_free_i64(tmp);
}
-static bool trans_VNMLA_dp(DisasContext *s, arg_VNMLA_sp *a)
+static bool trans_VNMLA_dp(DisasContext *s, arg_VNMLA_dp *a)
{
return do_vfp_3op_dp(s, gen_VNMLA_dp, a->vd, a->vn, a->vm, true);
}
@@ -1624,7 +1685,7 @@ static bool trans_VMUL_sp(DisasContext *s, arg_VMUL_sp *a)
return do_vfp_3op_sp(s, gen_helper_vfp_muls, a->vd, a->vn, a->vm, false);
}
-static bool trans_VMUL_dp(DisasContext *s, arg_VMUL_sp *a)
+static bool trans_VMUL_dp(DisasContext *s, arg_VMUL_dp *a)
{
return do_vfp_3op_dp(s, gen_helper_vfp_muld, a->vd, a->vn, a->vm, false);
}
@@ -1648,7 +1709,7 @@ static void gen_VNMUL_dp(TCGv_i64 vd, TCGv_i64 vn, TCGv_i64 vm, TCGv_ptr fpst)
gen_helper_vfp_negd(vd, vd);
}
-static bool trans_VNMUL_dp(DisasContext *s, arg_VNMUL_sp *a)
+static bool trans_VNMUL_dp(DisasContext *s, arg_VNMUL_dp *a)
{
return do_vfp_3op_dp(s, gen_VNMUL_dp, a->vd, a->vn, a->vm, false);
}
@@ -1658,7 +1719,7 @@ static bool trans_VADD_sp(DisasContext *s, arg_VADD_sp *a)
return do_vfp_3op_sp(s, gen_helper_vfp_adds, a->vd, a->vn, a->vm, false);
}
-static bool trans_VADD_dp(DisasContext *s, arg_VADD_sp *a)
+static bool trans_VADD_dp(DisasContext *s, arg_VADD_dp *a)
{
return do_vfp_3op_dp(s, gen_helper_vfp_addd, a->vd, a->vn, a->vm, false);
}
@@ -1668,7 +1729,7 @@ static bool trans_VSUB_sp(DisasContext *s, arg_VSUB_sp *a)
return do_vfp_3op_sp(s, gen_helper_vfp_subs, a->vd, a->vn, a->vm, false);
}
-static bool trans_VSUB_dp(DisasContext *s, arg_VSUB_sp *a)
+static bool trans_VSUB_dp(DisasContext *s, arg_VSUB_dp *a)
{
return do_vfp_3op_dp(s, gen_helper_vfp_subd, a->vd, a->vn, a->vm, false);
}
@@ -1678,7 +1739,7 @@ static bool trans_VDIV_sp(DisasContext *s, arg_VDIV_sp *a)
return do_vfp_3op_sp(s, gen_helper_vfp_divs, a->vd, a->vn, a->vm, false);
}
-static bool trans_VDIV_dp(DisasContext *s, arg_VDIV_sp *a)
+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);
}
@@ -1710,6 +1771,10 @@ static bool trans_VFM_sp(DisasContext *s, arg_VFM_sp *a)
return false;
}
+ if (!dc_isar_feature(aa32_fpdp, s)) {
+ return false;
+ }
+
if (!vfp_access_check(s)) {
return true;
}
@@ -1741,7 +1806,7 @@ static bool trans_VFM_sp(DisasContext *s, arg_VFM_sp *a)
return true;
}
-static bool trans_VFM_dp(DisasContext *s, arg_VFM_sp *a)
+static bool trans_VFM_dp(DisasContext *s, arg_VFM_dp *a)
{
/*
* VFNMA : fd = muladd(-fd, fn, fm)
@@ -1809,7 +1874,7 @@ static bool trans_VMOV_imm_sp(DisasContext *s, arg_VMOV_imm_sp *a)
uint32_t delta_d = 0;
int veclen = s->vec_len;
TCGv_i32 fd;
- uint32_t n, i, vd;
+ uint32_t vd;
vd = a->vd;
@@ -1836,17 +1901,7 @@ static bool trans_VMOV_imm_sp(DisasContext *s, arg_VMOV_imm_sp *a)
}
}
- n = (a->imm4h << 28) & 0x80000000;
- i = ((a->imm4h << 4) & 0x70) | a->imm4l;
- if (i & 0x40) {
- i |= 0x780;
- } else {
- i |= 0x800;
- }
- n |= i << 19;
-
- fd = tcg_temp_new_i32();
- tcg_gen_movi_i32(fd, n);
+ fd = tcg_const_i32(vfp_expand_imm(MO_32, a->imm));
for (;;) {
neon_store_reg32(fd, vd);
@@ -1869,7 +1924,7 @@ static bool trans_VMOV_imm_dp(DisasContext *s, arg_VMOV_imm_dp *a)
uint32_t delta_d = 0;
int veclen = s->vec_len;
TCGv_i64 fd;
- uint32_t n, i, vd;
+ uint32_t vd;
vd = a->vd;
@@ -1878,6 +1933,10 @@ static bool trans_VMOV_imm_dp(DisasContext *s, arg_VMOV_imm_dp *a)
return false;
}
+ if (!dc_isar_feature(aa32_fpdp, s)) {
+ return false;
+ }
+
if (!dc_isar_feature(aa32_fpshvec, s) &&
(veclen != 0 || s->vec_stride != 0)) {
return false;
@@ -1901,17 +1960,7 @@ static bool trans_VMOV_imm_dp(DisasContext *s, arg_VMOV_imm_dp *a)
}
}
- n = (a->imm4h << 28) & 0x80000000;
- i = ((a->imm4h << 4) & 0x70) | a->imm4l;
- if (i & 0x40) {
- i |= 0x3f80;
- } else {
- i |= 0x4000;
- }
- n |= i << 16;
-
- fd = tcg_temp_new_i64();
- tcg_gen_movi_i64(fd, ((uint64_t)n) << 32);
+ fd = tcg_const_i64(vfp_expand_imm(MO_64, a->imm));
for (;;) {
neon_store_reg64(fd, vd);
@@ -2028,6 +2077,10 @@ 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;
}
@@ -2097,6 +2150,10 @@ static bool trans_VCVT_f64_f16(DisasContext *s, arg_VCVT_f64_f16 *a)
return false;
}
+ if (!dc_isar_feature(aa32_fpdp, s)) {
+ return false;
+ }
+
if (!vfp_access_check(s)) {
return true;
}
@@ -2159,6 +2216,10 @@ static bool trans_VCVT_f16_f64(DisasContext *s, arg_VCVT_f16_f64 *a)
return false;
}
+ if (!dc_isar_feature(aa32_fpdp, s)) {
+ return false;
+ }
+
if (!vfp_access_check(s)) {
return true;
}
@@ -2201,7 +2262,7 @@ static bool trans_VRINTR_sp(DisasContext *s, arg_VRINTR_sp *a)
return true;
}
-static bool trans_VRINTR_dp(DisasContext *s, arg_VRINTR_sp *a)
+static bool trans_VRINTR_dp(DisasContext *s, arg_VRINTR_dp *a)
{
TCGv_ptr fpst;
TCGv_i64 tmp;
@@ -2215,6 +2276,10 @@ static bool trans_VRINTR_dp(DisasContext *s, arg_VRINTR_sp *a)
return false;
}
+ if (!dc_isar_feature(aa32_fpdp, s)) {
+ return false;
+ }
+
if (!vfp_access_check(s)) {
return true;
}
@@ -2257,7 +2322,7 @@ static bool trans_VRINTZ_sp(DisasContext *s, arg_VRINTZ_sp *a)
return true;
}
-static bool trans_VRINTZ_dp(DisasContext *s, arg_VRINTZ_sp *a)
+static bool trans_VRINTZ_dp(DisasContext *s, arg_VRINTZ_dp *a)
{
TCGv_ptr fpst;
TCGv_i64 tmp;
@@ -2272,6 +2337,10 @@ static bool trans_VRINTZ_dp(DisasContext *s, arg_VRINTZ_sp *a)
return false;
}
+ if (!dc_isar_feature(aa32_fpdp, s)) {
+ return false;
+ }
+
if (!vfp_access_check(s)) {
return true;
}
@@ -2327,6 +2396,10 @@ static bool trans_VRINTX_dp(DisasContext *s, arg_VRINTX_dp *a)
return false;
}
+ if (!dc_isar_feature(aa32_fpdp, s)) {
+ return false;
+ }
+
if (!vfp_access_check(s)) {
return true;
}
@@ -2351,6 +2424,10 @@ static bool trans_VCVT_sp(DisasContext *s, arg_VCVT_sp *a)
return false;
}
+ if (!dc_isar_feature(aa32_fpdp, s)) {
+ return false;
+ }
+
if (!vfp_access_check(s)) {
return true;
}
@@ -2375,6 +2452,10 @@ static bool trans_VCVT_dp(DisasContext *s, arg_VCVT_dp *a)
return false;
}
+ if (!dc_isar_feature(aa32_fpdp, s)) {
+ return false;
+ }
+
if (!vfp_access_check(s)) {
return true;
}
@@ -2425,6 +2506,10 @@ static bool trans_VCVT_int_dp(DisasContext *s, arg_VCVT_int_dp *a)
return false;
}
+ if (!dc_isar_feature(aa32_fpdp, s)) {
+ return false;
+ }
+
if (!vfp_access_check(s)) {
return true;
}
@@ -2461,6 +2546,10 @@ static bool trans_VJCVT(DisasContext *s, arg_VJCVT *a)
return false;
}
+ if (!dc_isar_feature(aa32_fpdp, s)) {
+ return false;
+ }
+
if (!vfp_access_check(s)) {
return true;
}
@@ -2550,6 +2639,10 @@ 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;
}
@@ -2642,6 +2735,10 @@ static bool trans_VCVT_dp_int(DisasContext *s, arg_VCVT_dp_int *a)
return false;
}
+ if (!dc_isar_feature(aa32_fpdp, s)) {
+ return false;
+ }
+
if (!vfp_access_check(s)) {
return true;
}
diff --git a/target/arm/translate.c b/target/arm/translate.c
index c274c8b..4750b9f 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -67,10 +67,6 @@ TCGv_i32 cpu_CF, cpu_NF, cpu_VF, cpu_ZF;
TCGv_i64 cpu_exclusive_addr;
TCGv_i64 cpu_exclusive_val;
-/* FIXME: These should be removed. */
-static TCGv_i32 cpu_F0s, cpu_F1s;
-static TCGv_i64 cpu_F0d, cpu_F1d;
-
#include "exec/gen-icount.h"
static const char * const regnames[] =
@@ -80,6 +76,8 @@ static const char * const regnames[] =
/* Function prototypes for gen_ functions calling Neon helpers. */
typedef void NeonGenThreeOpEnvFn(TCGv_i32, TCGv_env, TCGv_i32,
TCGv_i32, TCGv_i32);
+/* Function prototypes for gen_ functions for fix point conversions */
+typedef void VFPGenFixPointFn(TCGv_i32, TCGv_i32, TCGv_i32, TCGv_ptr);
/* initialize TCG globals. */
void arm_translate_init(void)
@@ -1374,75 +1372,6 @@ static TCGv_ptr get_fpstatus_ptr(int neon)
return statusptr;
}
-static inline void gen_vfp_abs(int dp)
-{
- if (dp)
- gen_helper_vfp_absd(cpu_F0d, cpu_F0d);
- else
- gen_helper_vfp_abss(cpu_F0s, cpu_F0s);
-}
-
-static inline void gen_vfp_neg(int dp)
-{
- if (dp)
- gen_helper_vfp_negd(cpu_F0d, cpu_F0d);
- else
- gen_helper_vfp_negs(cpu_F0s, cpu_F0s);
-}
-
-#define VFP_GEN_ITOF(name) \
-static inline void gen_vfp_##name(int dp, int neon) \
-{ \
- TCGv_ptr statusptr = get_fpstatus_ptr(neon); \
- if (dp) { \
- gen_helper_vfp_##name##d(cpu_F0d, cpu_F0s, statusptr); \
- } else { \
- gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, statusptr); \
- } \
- tcg_temp_free_ptr(statusptr); \
-}
-
-VFP_GEN_ITOF(uito)
-VFP_GEN_ITOF(sito)
-#undef VFP_GEN_ITOF
-
-#define VFP_GEN_FTOI(name) \
-static inline void gen_vfp_##name(int dp, int neon) \
-{ \
- TCGv_ptr statusptr = get_fpstatus_ptr(neon); \
- if (dp) { \
- gen_helper_vfp_##name##d(cpu_F0s, cpu_F0d, statusptr); \
- } else { \
- gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, statusptr); \
- } \
- tcg_temp_free_ptr(statusptr); \
-}
-
-VFP_GEN_FTOI(touiz)
-VFP_GEN_FTOI(tosiz)
-#undef VFP_GEN_FTOI
-
-#define VFP_GEN_FIX(name, round) \
-static inline void gen_vfp_##name(int dp, int shift, int neon) \
-{ \
- TCGv_i32 tmp_shift = tcg_const_i32(shift); \
- TCGv_ptr statusptr = get_fpstatus_ptr(neon); \
- if (dp) { \
- gen_helper_vfp_##name##d##round(cpu_F0d, cpu_F0d, tmp_shift, \
- statusptr); \
- } else { \
- gen_helper_vfp_##name##s##round(cpu_F0s, cpu_F0s, tmp_shift, \
- statusptr); \
- } \
- tcg_temp_free_i32(tmp_shift); \
- tcg_temp_free_ptr(statusptr); \
-}
-VFP_GEN_FIX(tosl, _round_to_zero)
-VFP_GEN_FIX(toul, _round_to_zero)
-VFP_GEN_FIX(slto, )
-VFP_GEN_FIX(ulto, )
-#undef VFP_GEN_FIX
-
static inline long vfp_reg_offset(bool dp, unsigned reg)
{
if (dp) {
@@ -1609,9 +1538,6 @@ static TCGv_ptr vfp_reg_ptr(bool dp, int reg)
return ret;
}
-#define tcg_gen_ld_f32 tcg_gen_ld_i32
-#define tcg_gen_st_f32 tcg_gen_st_i32
-
#define ARM_CP_RW_BIT (1 << 20)
/* Include the VFP decoder */
@@ -4189,16 +4115,6 @@ static const uint8_t neon_3r_sizes[] = {
#define NEON_2RM_VCVT_SF 62
#define NEON_2RM_VCVT_UF 63
-static int neon_2rm_is_float_op(int op)
-{
- /* Return true if this neon 2reg-misc op is float-to-float */
- return (op == NEON_2RM_VABS_F || op == NEON_2RM_VNEG_F ||
- (op >= NEON_2RM_VRINTN && op <= NEON_2RM_VRINTZ) ||
- op == NEON_2RM_VRINTM ||
- (op >= NEON_2RM_VRINTP && op <= NEON_2RM_VCVTMS) ||
- op >= NEON_2RM_VRECPE_F);
-}
-
static bool neon_2rm_is_v8_op(int op)
{
/* Return true if this neon 2reg-misc op is ARMv8 and up */
@@ -5779,28 +5695,41 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
}
} else if (op >= 14) {
/* VCVT fixed-point. */
+ TCGv_ptr fpst;
+ TCGv_i32 shiftv;
+ VFPGenFixPointFn *fn;
+
if (!(insn & (1 << 21)) || (q && ((rd | rm) & 1))) {
return 1;
}
+
+ if (!(op & 1)) {
+ if (u) {
+ fn = gen_helper_vfp_ultos;
+ } else {
+ fn = gen_helper_vfp_sltos;
+ }
+ } else {
+ if (u) {
+ fn = gen_helper_vfp_touls_round_to_zero;
+ } else {
+ fn = gen_helper_vfp_tosls_round_to_zero;
+ }
+ }
+
/* We have already masked out the must-be-1 top bit of imm6,
* hence this 32-shift where the ARM ARM has 64-imm6.
*/
shift = 32 - shift;
+ fpst = get_fpstatus_ptr(1);
+ shiftv = tcg_const_i32(shift);
for (pass = 0; pass < (q ? 4 : 2); pass++) {
- tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, pass));
- if (!(op & 1)) {
- if (u)
- gen_vfp_ulto(0, shift, 1);
- else
- gen_vfp_slto(0, shift, 1);
- } else {
- if (u)
- gen_vfp_toul(0, shift, 1);
- else
- gen_vfp_tosl(0, shift, 1);
- }
- tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, pass));
+ TCGv_i32 tmpf = neon_load_reg(rm, pass);
+ fn(tmpf, tmpf, shiftv, fpst);
+ neon_store_reg(rd, pass, tmpf);
}
+ tcg_temp_free_ptr(fpst);
+ tcg_temp_free_i32(shiftv);
} else {
return 1;
}
@@ -6489,25 +6418,23 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
q || (rm & 1)) {
return 1;
}
- tmp = tcg_temp_new_i32();
- tmp2 = tcg_temp_new_i32();
fpst = get_fpstatus_ptr(true);
ahp = get_ahp_flag();
- tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 0));
- gen_helper_vfp_fcvt_f32_to_f16(tmp, cpu_F0s, fpst, ahp);
- tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 1));
- gen_helper_vfp_fcvt_f32_to_f16(tmp2, cpu_F0s, fpst, ahp);
+ tmp = neon_load_reg(rm, 0);
+ gen_helper_vfp_fcvt_f32_to_f16(tmp, tmp, fpst, ahp);
+ tmp2 = neon_load_reg(rm, 1);
+ gen_helper_vfp_fcvt_f32_to_f16(tmp2, tmp2, fpst, ahp);
tcg_gen_shli_i32(tmp2, tmp2, 16);
tcg_gen_or_i32(tmp2, tmp2, tmp);
- tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 2));
- gen_helper_vfp_fcvt_f32_to_f16(tmp, cpu_F0s, fpst, ahp);
- tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 3));
+ tcg_temp_free_i32(tmp);
+ tmp = neon_load_reg(rm, 2);
+ gen_helper_vfp_fcvt_f32_to_f16(tmp, tmp, fpst, ahp);
+ tmp3 = neon_load_reg(rm, 3);
neon_store_reg(rd, 0, tmp2);
- tmp2 = tcg_temp_new_i32();
- gen_helper_vfp_fcvt_f32_to_f16(tmp2, cpu_F0s, fpst, ahp);
- tcg_gen_shli_i32(tmp2, tmp2, 16);
- tcg_gen_or_i32(tmp2, tmp2, tmp);
- neon_store_reg(rd, 1, tmp2);
+ gen_helper_vfp_fcvt_f32_to_f16(tmp3, tmp3, fpst, ahp);
+ tcg_gen_shli_i32(tmp3, tmp3, 16);
+ tcg_gen_or_i32(tmp3, tmp3, tmp);
+ neon_store_reg(rd, 1, tmp3);
tcg_temp_free_i32(tmp);
tcg_temp_free_i32(ahp);
tcg_temp_free_ptr(fpst);
@@ -6527,20 +6454,18 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
tmp = neon_load_reg(rm, 0);
tmp2 = neon_load_reg(rm, 1);
tcg_gen_ext16u_i32(tmp3, tmp);
- gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp3, fpst, ahp);
- tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 0));
- tcg_gen_shri_i32(tmp3, tmp, 16);
- gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp3, fpst, ahp);
- tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 1));
- tcg_temp_free_i32(tmp);
+ gen_helper_vfp_fcvt_f16_to_f32(tmp3, tmp3, fpst, ahp);
+ neon_store_reg(rd, 0, tmp3);
+ tcg_gen_shri_i32(tmp, tmp, 16);
+ gen_helper_vfp_fcvt_f16_to_f32(tmp, tmp, fpst, ahp);
+ neon_store_reg(rd, 1, tmp);
+ tmp3 = tcg_temp_new_i32();
tcg_gen_ext16u_i32(tmp3, tmp2);
- gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp3, fpst, ahp);
- tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 2));
- tcg_gen_shri_i32(tmp3, tmp2, 16);
- gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp3, fpst, ahp);
- tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 3));
- tcg_temp_free_i32(tmp2);
- tcg_temp_free_i32(tmp3);
+ gen_helper_vfp_fcvt_f16_to_f32(tmp3, tmp3, fpst, ahp);
+ neon_store_reg(rd, 2, tmp3);
+ tcg_gen_shri_i32(tmp2, tmp2, 16);
+ gen_helper_vfp_fcvt_f16_to_f32(tmp2, tmp2, fpst, ahp);
+ neon_store_reg(rd, 3, tmp2);
tcg_temp_free_i32(ahp);
tcg_temp_free_ptr(fpst);
break;
@@ -6614,13 +6539,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
default:
elementwise:
for (pass = 0; pass < (q ? 4 : 2); pass++) {
- if (neon_2rm_is_float_op(op)) {
- tcg_gen_ld_f32(cpu_F0s, cpu_env,
- neon_reg_offset(rm, pass));
- tmp = NULL;
- } else {
- tmp = neon_load_reg(rm, pass);
- }
+ tmp = neon_load_reg(rm, pass);
switch (op) {
case NEON_2RM_VREV32:
switch (size) {
@@ -6761,10 +6680,10 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
break;
}
case NEON_2RM_VABS_F:
- gen_vfp_abs(0);
+ gen_helper_vfp_abss(tmp, tmp);
break;
case NEON_2RM_VNEG_F:
- gen_vfp_neg(0);
+ gen_helper_vfp_negs(tmp, tmp);
break;
case NEON_2RM_VSWP:
tmp2 = neon_load_reg(rd, pass);
@@ -6798,7 +6717,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
tcg_rmode = tcg_const_i32(arm_rmode_to_sf(rmode));
gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode,
cpu_env);
- gen_helper_rints(cpu_F0s, cpu_F0s, fpstatus);
+ gen_helper_rints(tmp, tmp, fpstatus);
gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode,
cpu_env);
tcg_temp_free_ptr(fpstatus);
@@ -6808,7 +6727,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
case NEON_2RM_VRINTX:
{
TCGv_ptr fpstatus = get_fpstatus_ptr(1);
- gen_helper_rints_exact(cpu_F0s, cpu_F0s, fpstatus);
+ gen_helper_rints_exact(tmp, tmp, fpstatus);
tcg_temp_free_ptr(fpstatus);
break;
}
@@ -6832,10 +6751,10 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
cpu_env);
if (is_signed) {
- gen_helper_vfp_tosls(cpu_F0s, cpu_F0s,
+ gen_helper_vfp_tosls(tmp, tmp,
tcg_shift, fpst);
} else {
- gen_helper_vfp_touls(cpu_F0s, cpu_F0s,
+ gen_helper_vfp_touls(tmp, tmp,
tcg_shift, fpst);
}
@@ -6863,41 +6782,52 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
case NEON_2RM_VRECPE_F:
{
TCGv_ptr fpstatus = get_fpstatus_ptr(1);
- gen_helper_recpe_f32(cpu_F0s, cpu_F0s, fpstatus);
+ gen_helper_recpe_f32(tmp, tmp, fpstatus);
tcg_temp_free_ptr(fpstatus);
break;
}
case NEON_2RM_VRSQRTE_F:
{
TCGv_ptr fpstatus = get_fpstatus_ptr(1);
- gen_helper_rsqrte_f32(cpu_F0s, cpu_F0s, fpstatus);
+ gen_helper_rsqrte_f32(tmp, tmp, fpstatus);
tcg_temp_free_ptr(fpstatus);
break;
}
case NEON_2RM_VCVT_FS: /* VCVT.F32.S32 */
- gen_vfp_sito(0, 1);
+ {
+ TCGv_ptr fpstatus = get_fpstatus_ptr(1);
+ gen_helper_vfp_sitos(tmp, tmp, fpstatus);
+ tcg_temp_free_ptr(fpstatus);
break;
+ }
case NEON_2RM_VCVT_FU: /* VCVT.F32.U32 */
- gen_vfp_uito(0, 1);
+ {
+ TCGv_ptr fpstatus = get_fpstatus_ptr(1);
+ gen_helper_vfp_uitos(tmp, tmp, fpstatus);
+ tcg_temp_free_ptr(fpstatus);
break;
+ }
case NEON_2RM_VCVT_SF: /* VCVT.S32.F32 */
- gen_vfp_tosiz(0, 1);
+ {
+ TCGv_ptr fpstatus = get_fpstatus_ptr(1);
+ gen_helper_vfp_tosizs(tmp, tmp, fpstatus);
+ tcg_temp_free_ptr(fpstatus);
break;
+ }
case NEON_2RM_VCVT_UF: /* VCVT.U32.F32 */
- gen_vfp_touiz(0, 1);
+ {
+ TCGv_ptr fpstatus = get_fpstatus_ptr(1);
+ gen_helper_vfp_touizs(tmp, tmp, fpstatus);
+ tcg_temp_free_ptr(fpstatus);
break;
+ }
default:
/* Reserved op values were caught by the
* neon_2rm_sizes[] check earlier.
*/
abort();
}
- if (neon_2rm_is_float_op(op)) {
- tcg_gen_st_f32(cpu_F0s, cpu_env,
- neon_reg_offset(rd, pass));
- } else {
- neon_store_reg(rd, pass, tmp);
- }
+ neon_store_reg(rd, pass, tmp);
}
break;
}
@@ -11977,12 +11907,8 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
dc->base.max_insns = MIN(dc->base.max_insns, bound);
}
- cpu_F0s = tcg_temp_new_i32();
- cpu_F1s = tcg_temp_new_i32();
- cpu_F0d = tcg_temp_new_i64();
- cpu_F1d = tcg_temp_new_i64();
- cpu_V0 = cpu_F0d;
- cpu_V1 = cpu_F1d;
+ cpu_V0 = tcg_temp_new_i64();
+ cpu_V1 = tcg_temp_new_i64();
/* FIXME: cpu_M0 can probably be the same as cpu_V0. */
cpu_M0 = tcg_temp_new_i64();
}
diff --git a/target/arm/translate.h b/target/arm/translate.h
index dc06dce..bc16178 100644
--- a/target/arm/translate.h
+++ b/target/arm/translate.h
@@ -237,6 +237,13 @@ static inline void gen_ss_advance(DisasContext *s)
}
}
+/*
+ * Given a VFP floating point constant encoded into an 8 bit immediate in an
+ * instruction, expand it to the actual constant value of the specified
+ * size, as per the VFPExpandImm() pseudocode in the Arm ARM.
+ */
+uint64_t vfp_expand_imm(int size, uint8_t imm8);
+
/* Vector operations shared between ARM and AArch64. */
extern const GVecGen3 mla_op[4];
extern const GVecGen3 mls_op[4];
diff --git a/target/arm/vfp.decode b/target/arm/vfp.decode
index ea24365..a67b3f2 100644
--- a/target/arm/vfp.decode
+++ b/target/arm/vfp.decode
@@ -44,6 +44,8 @@
%vmov_idx_b 21:1 5:2
%vmov_idx_h 21:1 6:1
+%vmov_imm 16:4 0:4
+
# 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 \
@@ -152,10 +154,10 @@ VFM_sp ---- 1110 1.10 .... .... 1010 . o2:1 . 0 .... \
VFM_dp ---- 1110 1.10 .... .... 1011 . o2:1 . 0 .... \
vm=%vm_dp vn=%vn_dp vd=%vd_dp o1=2
-VMOV_imm_sp ---- 1110 1.11 imm4h:4 .... 1010 0000 imm4l:4 \
- vd=%vd_sp
-VMOV_imm_dp ---- 1110 1.11 imm4h:4 .... 1011 0000 imm4l:4 \
- vd=%vd_dp
+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