From c62288072c9c6c275a28c074612941a44572691d Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 22 Jun 2020 17:22:00 +0100 Subject: [PATCH 01/42] hw/arm/virt: Add 5.0 HW compat props Cc: Cornelia Huck Signed-off-by: Andrew Jones Reviewed-by: Cornelia Huck Message-id: 20200616140803.25515-1-drjones@redhat.com Signed-off-by: Peter Maydell --- hw/arm/virt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index caceb1e4a0..8b6e6aa7b1 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -2375,6 +2375,7 @@ DEFINE_VIRT_MACHINE_AS_LATEST(5, 1) static void virt_machine_5_0_options(MachineClass *mc) { virt_machine_5_1_options(mc); + compat_props_add(mc->compat_props, hw_compat_5_0, hw_compat_5_0_len); } DEFINE_VIRT_MACHINE(5, 0) From 2032e243a52c9834e5536463bcaa179f18d3319f Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Mon, 22 Jun 2020 17:22:00 +0100 Subject: [PATCH 02/42] util/oslib-posix : qemu_init_exec_dir implementation for Mac From 3025a0ce3fdf7d3559fc35a52c659f635f5c750c Mon Sep 17 00:00:00 2001 From: David Carlier Date: Tue, 26 May 2020 21:35:27 +0100 Subject: [PATCH] util/oslib-posix : qemu_init_exec_dir implementation for Mac Using dyld API to get the full path of the current process. Signed-off-by: David Carlier Message-id: CA+XhMqxwC10XHVs4Z-JfE0-WLAU3ztDuU9QKVi31mjr59HWCxg@mail.gmail.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- util/oslib-posix.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/util/oslib-posix.c b/util/oslib-posix.c index 916f1be224..39ddc77c85 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -57,6 +57,10 @@ #include #endif +#ifdef __APPLE__ +#include +#endif + #include "qemu/mmap-alloc.h" #ifdef CONFIG_DEBUG_STACK_USAGE @@ -375,6 +379,17 @@ void qemu_init_exec_dir(const char *argv0) p = buf; } } +#elif defined(__APPLE__) + { + char fpath[PATH_MAX]; + uint32_t len = sizeof(fpath); + if (_NSGetExecutablePath(fpath, &len) == 0) { + p = realpath(fpath, buf); + if (!p) { + return; + } + } + } #endif /* If we don't have any way of figuring out the actual executable location then try argv[0]. */ From 353d2b85058711a5e44c2dc63eb5b620db50a602 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 18:08:24 +0100 Subject: [PATCH 03/42] target/arm: Convert Neon 2-reg-misc VREV64 to decodetree Convert the Neon VREV64 insn from the 2-reg-misc grouping to decodetree. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200616170844.13318-2-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 12 ++++++++ target/arm/translate-neon.inc.c | 50 +++++++++++++++++++++++++++++++++ target/arm/translate.c | 24 ++-------------- 3 files changed, 64 insertions(+), 22 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 6d890b2161..e12fdf3095 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -429,6 +429,18 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm vm=%vm_dp vd=%vd_dp size=1 VDUP_scalar 1111 001 1 1 . 11 index:1 100 .... 11 000 q:1 . 0 .... \ vm=%vm_dp vd=%vd_dp size=2 + + ################################################################## + # 2-reg-misc grouping: + # 1111 001 11 D 11 size:2 opc1:2 Vd:4 0 opc2:4 q:1 M 0 Vm:4 + ################################################################## + + &2misc vd vm q size + + @2misc .... ... .. . .. size:2 .. .... . .... q:1 . . .... \ + &2misc vm=%vm_dp vd=%vd_dp + + VREV64 1111 001 11 . 11 .. 00 .... 0 0000 . . 0 .... @2misc ] # Subgroup for size != 0b11 diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index a5aa56bbde..90431a5383 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -2970,3 +2970,53 @@ static bool trans_VDUP_scalar(DisasContext *s, arg_VDUP_scalar *a) a->q ? 16 : 8, a->q ? 16 : 8); return true; } + +static bool trans_VREV64(DisasContext *s, arg_VREV64 *a) +{ + int pass, half; + + if (!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->vd | a->vm) & 0x10)) { + return false; + } + + if ((a->vd | a->vm) & a->q) { + return false; + } + + if (a->size == 3) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + for (pass = 0; pass < (a->q ? 2 : 1); pass++) { + TCGv_i32 tmp[2]; + + for (half = 0; half < 2; half++) { + tmp[half] = neon_load_reg(a->vm, pass * 2 + half); + switch (a->size) { + case 0: + tcg_gen_bswap32_i32(tmp[half], tmp[half]); + break; + case 1: + gen_swap_half(tmp[half]); + break; + case 2: + break; + default: + g_assert_not_reached(); + } + } + neon_store_reg(a->vd, pass * 2, tmp[1]); + neon_store_reg(a->vd, pass * 2 + 1, tmp[0]); + } + return true; +} diff --git a/target/arm/translate.c b/target/arm/translate.c index 6d18892ade..5fca38b5fa 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -5092,28 +5092,8 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) } switch (op) { case NEON_2RM_VREV64: - for (pass = 0; pass < (q ? 2 : 1); pass++) { - tmp = neon_load_reg(rm, pass * 2); - tmp2 = neon_load_reg(rm, pass * 2 + 1); - switch (size) { - case 0: tcg_gen_bswap32_i32(tmp, tmp); break; - case 1: gen_swap_half(tmp); break; - case 2: /* no-op */ break; - default: abort(); - } - neon_store_reg(rd, pass * 2 + 1, tmp); - if (size == 2) { - neon_store_reg(rd, pass * 2, tmp2); - } else { - switch (size) { - case 0: tcg_gen_bswap32_i32(tmp2, tmp2); break; - case 1: gen_swap_half(tmp2); break; - default: abort(); - } - neon_store_reg(rd, pass * 2, tmp2); - } - } - break; + /* handled by decodetree */ + return 1; case NEON_2RM_VPADDL: case NEON_2RM_VPADDL_U: case NEON_2RM_VPADAL: case NEON_2RM_VPADAL_U: for (pass = 0; pass < q + 1; pass++) { From 6106af3aa2304fccee91a3a90138352b0c2af998 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 18:08:25 +0100 Subject: [PATCH 04/42] target/arm: Convert Neon 2-reg-misc pairwise ops to decodetree Convert the pairwise ops VPADDL and VPADAL in the 2-reg-misc grouping to decodetree. At this point we can get rid of the weird CPU_V001 #define that was used to avoid having to explicitly list all the arguments being passed to some TCG gen/helper functions. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200616170844.13318-3-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 6 ++ target/arm/translate-neon.inc.c | 149 ++++++++++++++++++++++++++++++++ target/arm/translate.c | 35 +------- 3 files changed, 157 insertions(+), 33 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index e12fdf3095..dd521baa07 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -441,6 +441,12 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm &2misc vm=%vm_dp vd=%vd_dp VREV64 1111 001 11 . 11 .. 00 .... 0 0000 . . 0 .... @2misc + + VPADDL_S 1111 001 11 . 11 .. 00 .... 0 0100 . . 0 .... @2misc + VPADDL_U 1111 001 11 . 11 .. 00 .... 0 0101 . . 0 .... @2misc + + VPADAL_S 1111 001 11 . 11 .. 00 .... 0 1100 . . 0 .... @2misc + VPADAL_U 1111 001 11 . 11 .. 00 .... 0 1101 . . 0 .... @2misc ] # Subgroup for size != 0b11 diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 90431a5383..2f7bd0d556 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -3020,3 +3020,152 @@ static bool trans_VREV64(DisasContext *s, arg_VREV64 *a) } return true; } + +static bool do_2misc_pairwise(DisasContext *s, arg_2misc *a, + NeonGenWidenFn *widenfn, + NeonGenTwo64OpFn *opfn, + NeonGenTwo64OpFn *accfn) +{ + /* + * Pairwise long operations: widen both halves of the pair, + * combine the pairs with the opfn, and then possibly accumulate + * into the destination with the accfn. + */ + int pass; + + if (!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->vd | a->vm) & 0x10)) { + return false; + } + + if ((a->vd | a->vm) & a->q) { + return false; + } + + if (!widenfn) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + for (pass = 0; pass < a->q + 1; pass++) { + TCGv_i32 tmp; + TCGv_i64 rm0_64, rm1_64, rd_64; + + rm0_64 = tcg_temp_new_i64(); + rm1_64 = tcg_temp_new_i64(); + rd_64 = tcg_temp_new_i64(); + tmp = neon_load_reg(a->vm, pass * 2); + widenfn(rm0_64, tmp); + tcg_temp_free_i32(tmp); + tmp = neon_load_reg(a->vm, pass * 2 + 1); + widenfn(rm1_64, tmp); + tcg_temp_free_i32(tmp); + opfn(rd_64, rm0_64, rm1_64); + tcg_temp_free_i64(rm0_64); + tcg_temp_free_i64(rm1_64); + + if (accfn) { + TCGv_i64 tmp64 = tcg_temp_new_i64(); + neon_load_reg64(tmp64, a->vd + pass); + accfn(rd_64, tmp64, rd_64); + tcg_temp_free_i64(tmp64); + } + neon_store_reg64(rd_64, a->vd + pass); + tcg_temp_free_i64(rd_64); + } + return true; +} + +static bool trans_VPADDL_S(DisasContext *s, arg_2misc *a) +{ + static NeonGenWidenFn * const widenfn[] = { + gen_helper_neon_widen_s8, + gen_helper_neon_widen_s16, + tcg_gen_ext_i32_i64, + NULL, + }; + static NeonGenTwo64OpFn * const opfn[] = { + gen_helper_neon_paddl_u16, + gen_helper_neon_paddl_u32, + tcg_gen_add_i64, + NULL, + }; + + return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], NULL); +} + +static bool trans_VPADDL_U(DisasContext *s, arg_2misc *a) +{ + static NeonGenWidenFn * const widenfn[] = { + gen_helper_neon_widen_u8, + gen_helper_neon_widen_u16, + tcg_gen_extu_i32_i64, + NULL, + }; + static NeonGenTwo64OpFn * const opfn[] = { + gen_helper_neon_paddl_u16, + gen_helper_neon_paddl_u32, + tcg_gen_add_i64, + NULL, + }; + + return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], NULL); +} + +static bool trans_VPADAL_S(DisasContext *s, arg_2misc *a) +{ + static NeonGenWidenFn * const widenfn[] = { + gen_helper_neon_widen_s8, + gen_helper_neon_widen_s16, + tcg_gen_ext_i32_i64, + NULL, + }; + static NeonGenTwo64OpFn * const opfn[] = { + gen_helper_neon_paddl_u16, + gen_helper_neon_paddl_u32, + tcg_gen_add_i64, + NULL, + }; + static NeonGenTwo64OpFn * const accfn[] = { + gen_helper_neon_addl_u16, + gen_helper_neon_addl_u32, + tcg_gen_add_i64, + NULL, + }; + + return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], + accfn[a->size]); +} + +static bool trans_VPADAL_U(DisasContext *s, arg_2misc *a) +{ + static NeonGenWidenFn * const widenfn[] = { + gen_helper_neon_widen_u8, + gen_helper_neon_widen_u16, + tcg_gen_extu_i32_i64, + NULL, + }; + static NeonGenTwo64OpFn * const opfn[] = { + gen_helper_neon_paddl_u16, + gen_helper_neon_paddl_u32, + tcg_gen_add_i64, + NULL, + }; + static NeonGenTwo64OpFn * const accfn[] = { + gen_helper_neon_addl_u16, + gen_helper_neon_addl_u32, + tcg_gen_add_i64, + NULL, + }; + + return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], + accfn[a->size]); +} diff --git a/target/arm/translate.c b/target/arm/translate.c index 5fca38b5fa..4405b034f7 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -2934,8 +2934,6 @@ static void gen_exception_return(DisasContext *s, TCGv_i32 pc) gen_rfe(s, pc, load_cpu_field(spsr)); } -#define CPU_V001 cpu_V0, cpu_V0, cpu_V1 - static int gen_neon_unzip(int rd, int rm, int size, int q) { TCGv_ptr pd, pm; @@ -3117,16 +3115,6 @@ static inline void gen_neon_widen(TCGv_i64 dest, TCGv_i32 src, int size, int u) tcg_temp_free_i32(src); } -static inline void gen_neon_addl(int size) -{ - switch (size) { - case 0: gen_helper_neon_addl_u16(CPU_V001); break; - case 1: gen_helper_neon_addl_u32(CPU_V001); break; - case 2: tcg_gen_add_i64(CPU_V001); break; - default: abort(); - } -} - static void gen_neon_narrow_op(int op, int u, int size, TCGv_i32 dest, TCGv_i64 src) { @@ -5092,29 +5080,10 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) } switch (op) { case NEON_2RM_VREV64: - /* handled by decodetree */ - return 1; case NEON_2RM_VPADDL: case NEON_2RM_VPADDL_U: case NEON_2RM_VPADAL: case NEON_2RM_VPADAL_U: - for (pass = 0; pass < q + 1; pass++) { - tmp = neon_load_reg(rm, pass * 2); - gen_neon_widen(cpu_V0, tmp, size, op & 1); - tmp = neon_load_reg(rm, pass * 2 + 1); - gen_neon_widen(cpu_V1, tmp, size, op & 1); - switch (size) { - case 0: gen_helper_neon_paddl_u16(CPU_V001); break; - case 1: gen_helper_neon_paddl_u32(CPU_V001); break; - case 2: tcg_gen_add_i64(CPU_V001); break; - default: abort(); - } - if (op >= NEON_2RM_VPADAL) { - /* Accumulate. */ - neon_load_reg64(cpu_V1, rd + pass); - gen_neon_addl(size); - } - neon_store_reg64(cpu_V0, rd + pass); - } - break; + /* handled by decodetree */ + return 1; case NEON_2RM_VTRN: if (size == 2) { int n; From 567663a2af2457da8aa74f221b1f3f8a6d2eddf6 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 18:08:26 +0100 Subject: [PATCH 05/42] target/arm: Convert VZIP, VUZP to decodetree Convert the Neon VZIP and VUZP insns in the 2-reg-misc group to decodetree. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200616170844.13318-4-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 3 ++ target/arm/translate-neon.inc.c | 74 ++++++++++++++++++++++++++ target/arm/translate.c | 92 +-------------------------------- 3 files changed, 79 insertions(+), 90 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index dd521baa07..ad9e17fd73 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -447,6 +447,9 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm VPADAL_S 1111 001 11 . 11 .. 00 .... 0 1100 . . 0 .... @2misc VPADAL_U 1111 001 11 . 11 .. 00 .... 0 1101 . . 0 .... @2misc + + VUZP 1111 001 11 . 11 .. 10 .... 0 0010 . . 0 .... @2misc + VZIP 1111 001 11 . 11 .. 10 .... 0 0011 . . 0 .... @2misc ] # Subgroup for size != 0b11 diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 2f7bd0d556..f4799dd977 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -3169,3 +3169,77 @@ static bool trans_VPADAL_U(DisasContext *s, arg_2misc *a) return do_2misc_pairwise(s, a, widenfn[a->size], opfn[a->size], accfn[a->size]); } + +typedef void ZipFn(TCGv_ptr, TCGv_ptr); + +static bool do_zip_uzp(DisasContext *s, arg_2misc *a, + ZipFn *fn) +{ + TCGv_ptr pd, pm; + + if (!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->vd | a->vm) & 0x10)) { + return false; + } + + if ((a->vd | a->vm) & a->q) { + return false; + } + + if (!fn) { + /* Bad size or size/q combination */ + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + pd = vfp_reg_ptr(true, a->vd); + pm = vfp_reg_ptr(true, a->vm); + fn(pd, pm); + tcg_temp_free_ptr(pd); + tcg_temp_free_ptr(pm); + return true; +} + +static bool trans_VUZP(DisasContext *s, arg_2misc *a) +{ + static ZipFn * const fn[2][4] = { + { + gen_helper_neon_unzip8, + gen_helper_neon_unzip16, + NULL, + NULL, + }, { + gen_helper_neon_qunzip8, + gen_helper_neon_qunzip16, + gen_helper_neon_qunzip32, + NULL, + } + }; + return do_zip_uzp(s, a, fn[a->q][a->size]); +} + +static bool trans_VZIP(DisasContext *s, arg_2misc *a) +{ + static ZipFn * const fn[2][4] = { + { + gen_helper_neon_zip8, + gen_helper_neon_zip16, + NULL, + NULL, + }, { + gen_helper_neon_qzip8, + gen_helper_neon_qzip16, + gen_helper_neon_qzip32, + NULL, + } + }; + return do_zip_uzp(s, a, fn[a->q][a->size]); +} diff --git a/target/arm/translate.c b/target/arm/translate.c index 4405b034f7..442f287d86 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -2934,86 +2934,6 @@ static void gen_exception_return(DisasContext *s, TCGv_i32 pc) gen_rfe(s, pc, load_cpu_field(spsr)); } -static int gen_neon_unzip(int rd, int rm, int size, int q) -{ - TCGv_ptr pd, pm; - - if (!q && size == 2) { - return 1; - } - pd = vfp_reg_ptr(true, rd); - pm = vfp_reg_ptr(true, rm); - if (q) { - switch (size) { - case 0: - gen_helper_neon_qunzip8(pd, pm); - break; - case 1: - gen_helper_neon_qunzip16(pd, pm); - break; - case 2: - gen_helper_neon_qunzip32(pd, pm); - break; - default: - abort(); - } - } else { - switch (size) { - case 0: - gen_helper_neon_unzip8(pd, pm); - break; - case 1: - gen_helper_neon_unzip16(pd, pm); - break; - default: - abort(); - } - } - tcg_temp_free_ptr(pd); - tcg_temp_free_ptr(pm); - return 0; -} - -static int gen_neon_zip(int rd, int rm, int size, int q) -{ - TCGv_ptr pd, pm; - - if (!q && size == 2) { - return 1; - } - pd = vfp_reg_ptr(true, rd); - pm = vfp_reg_ptr(true, rm); - if (q) { - switch (size) { - case 0: - gen_helper_neon_qzip8(pd, pm); - break; - case 1: - gen_helper_neon_qzip16(pd, pm); - break; - case 2: - gen_helper_neon_qzip32(pd, pm); - break; - default: - abort(); - } - } else { - switch (size) { - case 0: - gen_helper_neon_zip8(pd, pm); - break; - case 1: - gen_helper_neon_zip16(pd, pm); - break; - default: - abort(); - } - } - tcg_temp_free_ptr(pd); - tcg_temp_free_ptr(pm); - return 0; -} - static void gen_neon_trn_u8(TCGv_i32 t0, TCGv_i32 t1) { TCGv_i32 rd, tmp; @@ -5082,6 +5002,8 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_2RM_VREV64: case NEON_2RM_VPADDL: case NEON_2RM_VPADDL_U: case NEON_2RM_VPADAL: case NEON_2RM_VPADAL_U: + case NEON_2RM_VUZP: + case NEON_2RM_VZIP: /* handled by decodetree */ return 1; case NEON_2RM_VTRN: @@ -5097,16 +5019,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) goto elementwise; } break; - case NEON_2RM_VUZP: - if (gen_neon_unzip(rd, rm, size, q)) { - return 1; - } - break; - case NEON_2RM_VZIP: - if (gen_neon_zip(rd, rm, size, q)) { - return 1; - } - break; case NEON_2RM_VMOVN: case NEON_2RM_VQMOVN: /* also VQMOVUN; op field and mnemonics don't line up */ if (rm & 1) { From 3882bdacb0ad548864b9f2582a32bb5c785e3165 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 18:08:27 +0100 Subject: [PATCH 06/42] target/arm: Convert Neon narrowing moves to decodetree Convert the Neon narrowing moves VMQNV, VQMOVN, VQMOVUN in the 2-reg-misc group to decodetree. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200616170844.13318-5-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 9 ++++ target/arm/translate-neon.inc.c | 59 ++++++++++++++++++++++++ target/arm/translate.c | 81 +-------------------------------- 3 files changed, 70 insertions(+), 79 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index ad9e17fd73..2277b4c7b5 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -439,6 +439,8 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm @2misc .... ... .. . .. size:2 .. .... . .... q:1 . . .... \ &2misc vm=%vm_dp vd=%vd_dp + @2misc_q0 .... ... .. . .. size:2 .. .... . .... . . . .... \ + &2misc vm=%vm_dp vd=%vd_dp q=0 VREV64 1111 001 11 . 11 .. 00 .... 0 0000 . . 0 .... @2misc @@ -450,6 +452,13 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm VUZP 1111 001 11 . 11 .. 10 .... 0 0010 . . 0 .... @2misc VZIP 1111 001 11 . 11 .. 10 .... 0 0011 . . 0 .... @2misc + + VMOVN 1111 001 11 . 11 .. 10 .... 0 0100 0 . 0 .... @2misc_q0 + # VQMOVUN: unsigned result (source is always signed) + VQMOVUN 1111 001 11 . 11 .. 10 .... 0 0100 1 . 0 .... @2misc_q0 + # VQMOVN: signed result, source may be signed (_S) or unsigned (_U) + VQMOVN_S 1111 001 11 . 11 .. 10 .... 0 0101 0 . 0 .... @2misc_q0 + VQMOVN_U 1111 001 11 . 11 .. 10 .... 0 0101 1 . 0 .... @2misc_q0 ] # Subgroup for size != 0b11 diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index f4799dd977..b062097285 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -3243,3 +3243,62 @@ static bool trans_VZIP(DisasContext *s, arg_2misc *a) }; return do_zip_uzp(s, a, fn[a->q][a->size]); } + +static bool do_vmovn(DisasContext *s, arg_2misc *a, + NeonGenNarrowEnvFn *narrowfn) +{ + TCGv_i64 rm; + TCGv_i32 rd0, rd1; + + if (!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->vd | a->vm) & 0x10)) { + return false; + } + + if (a->vm & 1) { + return false; + } + + if (!narrowfn) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + rm = tcg_temp_new_i64(); + rd0 = tcg_temp_new_i32(); + rd1 = tcg_temp_new_i32(); + + neon_load_reg64(rm, a->vm); + narrowfn(rd0, cpu_env, rm); + neon_load_reg64(rm, a->vm + 1); + narrowfn(rd1, cpu_env, rm); + neon_store_reg(a->vd, 0, rd0); + neon_store_reg(a->vd, 1, rd1); + tcg_temp_free_i64(rm); + return true; +} + +#define DO_VMOVN(INSN, FUNC) \ + static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ + { \ + static NeonGenNarrowEnvFn * const narrowfn[] = { \ + FUNC##8, \ + FUNC##16, \ + FUNC##32, \ + NULL, \ + }; \ + return do_vmovn(s, a, narrowfn[a->size]); \ + } + +DO_VMOVN(VMOVN, gen_neon_narrow_u) +DO_VMOVN(VQMOVUN, gen_helper_neon_unarrow_sat) +DO_VMOVN(VQMOVN_S, gen_helper_neon_narrow_sat_s) +DO_VMOVN(VQMOVN_U, gen_helper_neon_narrow_sat_u) diff --git a/target/arm/translate.c b/target/arm/translate.c index 442f287d86..8ecae264e1 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -2975,46 +2975,6 @@ static void gen_neon_trn_u16(TCGv_i32 t0, TCGv_i32 t1) tcg_temp_free_i32(rd); } -static inline void gen_neon_narrow(int size, TCGv_i32 dest, TCGv_i64 src) -{ - switch (size) { - case 0: gen_helper_neon_narrow_u8(dest, src); break; - case 1: gen_helper_neon_narrow_u16(dest, src); break; - case 2: tcg_gen_extrl_i64_i32(dest, src); break; - default: abort(); - } -} - -static inline void gen_neon_narrow_sats(int size, TCGv_i32 dest, TCGv_i64 src) -{ - switch (size) { - case 0: gen_helper_neon_narrow_sat_s8(dest, cpu_env, src); break; - case 1: gen_helper_neon_narrow_sat_s16(dest, cpu_env, src); break; - case 2: gen_helper_neon_narrow_sat_s32(dest, cpu_env, src); break; - default: abort(); - } -} - -static inline void gen_neon_narrow_satu(int size, TCGv_i32 dest, TCGv_i64 src) -{ - switch (size) { - case 0: gen_helper_neon_narrow_sat_u8(dest, cpu_env, src); break; - case 1: gen_helper_neon_narrow_sat_u16(dest, cpu_env, src); break; - case 2: gen_helper_neon_narrow_sat_u32(dest, cpu_env, src); break; - default: abort(); - } -} - -static inline void gen_neon_unarrow_sats(int size, TCGv_i32 dest, TCGv_i64 src) -{ - switch (size) { - case 0: gen_helper_neon_unarrow_sat8(dest, cpu_env, src); break; - case 1: gen_helper_neon_unarrow_sat16(dest, cpu_env, src); break; - case 2: gen_helper_neon_unarrow_sat32(dest, cpu_env, src); break; - default: abort(); - } -} - static inline void gen_neon_widen(TCGv_i64 dest, TCGv_i32 src, int size, int u) { if (u) { @@ -3035,24 +2995,6 @@ static inline void gen_neon_widen(TCGv_i64 dest, TCGv_i32 src, int size, int u) tcg_temp_free_i32(src); } -static void gen_neon_narrow_op(int op, int u, int size, - TCGv_i32 dest, TCGv_i64 src) -{ - if (op) { - if (u) { - gen_neon_unarrow_sats(size, dest, src); - } else { - gen_neon_narrow(size, dest, src); - } - } else { - if (u) { - gen_neon_narrow_satu(size, dest, src); - } else { - gen_neon_narrow_sats(size, dest, src); - } - } -} - /* Symbolic constants for op fields for Neon 2-register miscellaneous. * The values correspond to bits [17:16,10:7]; see the ARM ARM DDI0406B * table A7-13. @@ -4994,8 +4936,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) !arm_dc_feature(s, ARM_FEATURE_V8)) { return 1; } - if ((op != NEON_2RM_VMOVN && op != NEON_2RM_VQMOVN) && - q && ((rm | rd) & 1)) { + if (q && ((rm | rd) & 1)) { return 1; } switch (op) { @@ -5004,6 +4945,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_2RM_VPADAL: case NEON_2RM_VPADAL_U: case NEON_2RM_VUZP: case NEON_2RM_VZIP: + case NEON_2RM_VMOVN: case NEON_2RM_VQMOVN: /* handled by decodetree */ return 1; case NEON_2RM_VTRN: @@ -5019,25 +4961,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) goto elementwise; } break; - case NEON_2RM_VMOVN: case NEON_2RM_VQMOVN: - /* also VQMOVUN; op field and mnemonics don't line up */ - if (rm & 1) { - return 1; - } - tmp2 = NULL; - for (pass = 0; pass < 2; pass++) { - neon_load_reg64(cpu_V0, rm + pass); - tmp = tcg_temp_new_i32(); - gen_neon_narrow_op(op == NEON_2RM_VMOVN, q, size, - tmp, cpu_V0); - if (pass == 0) { - tmp2 = tmp; - } else { - neon_store_reg(rd, 0, tmp2); - neon_store_reg(rd, 1, tmp); - } - } - break; case NEON_2RM_VSHLL: if (q || (rd & 1)) { return 1; From 749e2be36d75f11d5fa8f8277e2a0569bd2a1c97 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 18:08:28 +0100 Subject: [PATCH 07/42] target/arm: Convert Neon 2-reg-misc VSHLL to decodetree Convert the VSHLL insn in the 2-reg-misc Neon group to decodetree. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200616170844.13318-6-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 2 ++ target/arm/translate-neon.inc.c | 52 +++++++++++++++++++++++++++++++++ target/arm/translate.c | 35 +--------------------- 3 files changed, 55 insertions(+), 34 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 2277b4c7b5..0102aa7254 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -459,6 +459,8 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm # VQMOVN: signed result, source may be signed (_S) or unsigned (_U) VQMOVN_S 1111 001 11 . 11 .. 10 .... 0 0101 0 . 0 .... @2misc_q0 VQMOVN_U 1111 001 11 . 11 .. 10 .... 0 0101 1 . 0 .... @2misc_q0 + + VSHLL 1111 001 11 . 11 .. 10 .... 0 0110 0 . 0 .... @2misc_q0 ] # Subgroup for size != 0b11 diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index b062097285..78239ec1c1 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -3302,3 +3302,55 @@ DO_VMOVN(VMOVN, gen_neon_narrow_u) DO_VMOVN(VQMOVUN, gen_helper_neon_unarrow_sat) DO_VMOVN(VQMOVN_S, gen_helper_neon_narrow_sat_s) DO_VMOVN(VQMOVN_U, gen_helper_neon_narrow_sat_u) + +static bool trans_VSHLL(DisasContext *s, arg_2misc *a) +{ + TCGv_i32 rm0, rm1; + TCGv_i64 rd; + static NeonGenWidenFn * const widenfns[] = { + gen_helper_neon_widen_u8, + gen_helper_neon_widen_u16, + tcg_gen_extu_i32_i64, + NULL, + }; + NeonGenWidenFn *widenfn = widenfns[a->size]; + + if (!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->vd | a->vm) & 0x10)) { + return false; + } + + if (a->vd & 1) { + return false; + } + + if (!widenfn) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + rd = tcg_temp_new_i64(); + + rm0 = neon_load_reg(a->vm, 0); + rm1 = neon_load_reg(a->vm, 1); + + widenfn(rd, rm0); + tcg_gen_shli_i64(rd, rd, 8 << a->size); + neon_store_reg64(rd, a->vd); + widenfn(rd, rm1); + tcg_gen_shli_i64(rd, rd, 8 << a->size); + neon_store_reg64(rd, a->vd + 1); + + tcg_temp_free_i64(rd); + tcg_temp_free_i32(rm0); + tcg_temp_free_i32(rm1); + return true; +} diff --git a/target/arm/translate.c b/target/arm/translate.c index 8ecae264e1..94d5e34fff 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -2975,26 +2975,6 @@ static void gen_neon_trn_u16(TCGv_i32 t0, TCGv_i32 t1) tcg_temp_free_i32(rd); } -static inline void gen_neon_widen(TCGv_i64 dest, TCGv_i32 src, int size, int u) -{ - if (u) { - switch (size) { - case 0: gen_helper_neon_widen_u8(dest, src); break; - case 1: gen_helper_neon_widen_u16(dest, src); break; - case 2: tcg_gen_extu_i32_i64(dest, src); break; - default: abort(); - } - } else { - switch (size) { - case 0: gen_helper_neon_widen_s8(dest, src); break; - case 1: gen_helper_neon_widen_s16(dest, src); break; - case 2: tcg_gen_ext_i32_i64(dest, src); break; - default: abort(); - } - } - tcg_temp_free_i32(src); -} - /* Symbolic constants for op fields for Neon 2-register miscellaneous. * The values correspond to bits [17:16,10:7]; see the ARM ARM DDI0406B * table A7-13. @@ -4946,6 +4926,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_2RM_VUZP: case NEON_2RM_VZIP: case NEON_2RM_VMOVN: case NEON_2RM_VQMOVN: + case NEON_2RM_VSHLL: /* handled by decodetree */ return 1; case NEON_2RM_VTRN: @@ -4961,20 +4942,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) goto elementwise; } break; - case NEON_2RM_VSHLL: - if (q || (rd & 1)) { - return 1; - } - tmp = neon_load_reg(rm, 0); - tmp2 = neon_load_reg(rm, 1); - for (pass = 0; pass < 2; pass++) { - if (pass == 1) - tmp = tmp2; - gen_neon_widen(cpu_V0, tmp, size, 1); - tcg_gen_shli_i64(cpu_V0, cpu_V0, 8 << size); - neon_store_reg64(cpu_V0, rd + pass); - } - break; case NEON_2RM_VCVT_F16_F32: { TCGv_ptr fpst; From 654a517355e249435505ae5ff14a7520410cf7a4 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 18:08:29 +0100 Subject: [PATCH 08/42] target/arm: Convert Neon VCVT f16/f32 insns to decodetree Convert the Neon insns in the 2-reg-misc group which are VCVT between f32 and f16 to decodetree. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200616170844.13318-7-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 3 ++ target/arm/translate-neon.inc.c | 96 +++++++++++++++++++++++++++++++++ target/arm/translate.c | 65 ++-------------------- 3 files changed, 102 insertions(+), 62 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 0102aa7254..8174f2f92f 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -461,6 +461,9 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm VQMOVN_U 1111 001 11 . 11 .. 10 .... 0 0101 1 . 0 .... @2misc_q0 VSHLL 1111 001 11 . 11 .. 10 .... 0 0110 0 . 0 .... @2misc_q0 + + VCVT_F16_F32 1111 001 11 . 11 .. 10 .... 0 1100 0 . 0 .... @2misc_q0 + VCVT_F32_F16 1111 001 11 . 11 .. 10 .... 0 1110 0 . 0 .... @2misc_q0 ] # Subgroup for size != 0b11 diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 78239ec1c1..d37be597cf 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -3354,3 +3354,99 @@ static bool trans_VSHLL(DisasContext *s, arg_2misc *a) tcg_temp_free_i32(rm1); return true; } + +static bool trans_VCVT_F16_F32(DisasContext *s, arg_2misc *a) +{ + TCGv_ptr fpst; + TCGv_i32 ahp, tmp, tmp2, tmp3; + + if (!arm_dc_feature(s, ARM_FEATURE_NEON) || + !dc_isar_feature(aa32_fp16_spconv, 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)) { + return false; + } + + if ((a->vm & 1) || (a->size != 1)) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + fpst = get_fpstatus_ptr(true); + ahp = get_ahp_flag(); + tmp = neon_load_reg(a->vm, 0); + gen_helper_vfp_fcvt_f32_to_f16(tmp, tmp, fpst, ahp); + tmp2 = neon_load_reg(a->vm, 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_temp_free_i32(tmp); + tmp = neon_load_reg(a->vm, 2); + gen_helper_vfp_fcvt_f32_to_f16(tmp, tmp, fpst, ahp); + tmp3 = neon_load_reg(a->vm, 3); + neon_store_reg(a->vd, 0, 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(a->vd, 1, tmp3); + tcg_temp_free_i32(tmp); + tcg_temp_free_i32(ahp); + tcg_temp_free_ptr(fpst); + + return true; +} + +static bool trans_VCVT_F32_F16(DisasContext *s, arg_2misc *a) +{ + TCGv_ptr fpst; + TCGv_i32 ahp, tmp, tmp2, tmp3; + + if (!arm_dc_feature(s, ARM_FEATURE_NEON) || + !dc_isar_feature(aa32_fp16_spconv, 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)) { + return false; + } + + if ((a->vd & 1) || (a->size != 1)) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + fpst = get_fpstatus_ptr(true); + ahp = get_ahp_flag(); + tmp3 = tcg_temp_new_i32(); + tmp = neon_load_reg(a->vm, 0); + tmp2 = neon_load_reg(a->vm, 1); + tcg_gen_ext16u_i32(tmp3, tmp); + gen_helper_vfp_fcvt_f16_to_f32(tmp3, tmp3, fpst, ahp); + neon_store_reg(a->vd, 0, tmp3); + tcg_gen_shri_i32(tmp, tmp, 16); + gen_helper_vfp_fcvt_f16_to_f32(tmp, tmp, fpst, ahp); + neon_store_reg(a->vd, 1, tmp); + tmp3 = tcg_temp_new_i32(); + tcg_gen_ext16u_i32(tmp3, tmp2); + gen_helper_vfp_fcvt_f16_to_f32(tmp3, tmp3, fpst, ahp); + neon_store_reg(a->vd, 2, tmp3); + tcg_gen_shri_i32(tmp2, tmp2, 16); + gen_helper_vfp_fcvt_f16_to_f32(tmp2, tmp2, fpst, ahp); + neon_store_reg(a->vd, 3, tmp2); + tcg_temp_free_i32(ahp); + tcg_temp_free_ptr(fpst); + + return true; +} diff --git a/target/arm/translate.c b/target/arm/translate.c index 94d5e34fff..1ea0969554 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -4860,7 +4860,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) int pass; int u; int vec_size; - TCGv_i32 tmp, tmp2, tmp3; + TCGv_i32 tmp, tmp2; if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { return 1; @@ -4927,6 +4927,8 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_2RM_VZIP: case NEON_2RM_VMOVN: case NEON_2RM_VQMOVN: case NEON_2RM_VSHLL: + case NEON_2RM_VCVT_F16_F32: + case NEON_2RM_VCVT_F32_F16: /* handled by decodetree */ return 1; case NEON_2RM_VTRN: @@ -4942,67 +4944,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) goto elementwise; } break; - case NEON_2RM_VCVT_F16_F32: - { - TCGv_ptr fpst; - TCGv_i32 ahp; - - if (!dc_isar_feature(aa32_fp16_spconv, s) || - q || (rm & 1)) { - return 1; - } - fpst = get_fpstatus_ptr(true); - ahp = get_ahp_flag(); - 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_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); - 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); - break; - } - case NEON_2RM_VCVT_F32_F16: - { - TCGv_ptr fpst; - TCGv_i32 ahp; - if (!dc_isar_feature(aa32_fp16_spconv, s) || - q || (rd & 1)) { - return 1; - } - fpst = get_fpstatus_ptr(true); - ahp = get_ahp_flag(); - tmp3 = tcg_temp_new_i32(); - 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(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(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; - } case NEON_2RM_AESE: case NEON_2RM_AESMC: if (!dc_isar_feature(aa32_aes, s) || ((rm | rd) & 1)) { return 1; From 75153179e9928775d5333243ea4b278f438d75ae Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 18:08:30 +0100 Subject: [PATCH 09/42] target/arm: Convert vectorised 2-reg-misc Neon ops to decodetree Convert to decodetree the insns in the Neon 2-reg-misc grouping which we implement using gvec. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200616170844.13318-8-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 11 +++++++ target/arm/translate-neon.inc.c | 55 +++++++++++++++++++++++++++++++++ target/arm/translate.c | 35 +++++---------------- 3 files changed, 74 insertions(+), 27 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 8174f2f92f..b5692070d6 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -447,9 +447,20 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm VPADDL_S 1111 001 11 . 11 .. 00 .... 0 0100 . . 0 .... @2misc VPADDL_U 1111 001 11 . 11 .. 00 .... 0 0101 . . 0 .... @2misc + VMVN 1111 001 11 . 11 .. 00 .... 0 1011 . . 0 .... @2misc + VPADAL_S 1111 001 11 . 11 .. 00 .... 0 1100 . . 0 .... @2misc VPADAL_U 1111 001 11 . 11 .. 00 .... 0 1101 . . 0 .... @2misc + VCGT0 1111 001 11 . 11 .. 01 .... 0 0000 . . 0 .... @2misc + VCGE0 1111 001 11 . 11 .. 01 .... 0 0001 . . 0 .... @2misc + VCEQ0 1111 001 11 . 11 .. 01 .... 0 0010 . . 0 .... @2misc + VCLE0 1111 001 11 . 11 .. 01 .... 0 0011 . . 0 .... @2misc + VCLT0 1111 001 11 . 11 .. 01 .... 0 0100 . . 0 .... @2misc + + VABS 1111 001 11 . 11 .. 01 .... 0 0110 . . 0 .... @2misc + VNEG 1111 001 11 . 11 .. 01 .... 0 0111 . . 0 .... @2misc + VUZP 1111 001 11 . 11 .. 10 .... 0 0010 . . 0 .... @2misc VZIP 1111 001 11 . 11 .. 10 .... 0 0011 . . 0 .... @2misc diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index d37be597cf..d80123514c 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -3450,3 +3450,58 @@ static bool trans_VCVT_F32_F16(DisasContext *s, arg_2misc *a) return true; } + +static bool do_2misc_vec(DisasContext *s, arg_2misc *a, GVecGen2Fn *fn) +{ + int vec_size = a->q ? 16 : 8; + int rd_ofs = neon_reg_offset(a->vd, 0); + int rm_ofs = neon_reg_offset(a->vm, 0); + + if (!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->vd | a->vm) & 0x10)) { + return false; + } + + if (a->size == 3) { + return false; + } + + if ((a->vd | a->vm) & a->q) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + fn(a->size, rd_ofs, rm_ofs, vec_size, vec_size); + + return true; +} + +#define DO_2MISC_VEC(INSN, FN) \ + static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ + { \ + return do_2misc_vec(s, a, FN); \ + } + +DO_2MISC_VEC(VNEG, tcg_gen_gvec_neg) +DO_2MISC_VEC(VABS, tcg_gen_gvec_abs) +DO_2MISC_VEC(VCEQ0, gen_gvec_ceq0) +DO_2MISC_VEC(VCGT0, gen_gvec_cgt0) +DO_2MISC_VEC(VCLE0, gen_gvec_cle0) +DO_2MISC_VEC(VCGE0, gen_gvec_cge0) +DO_2MISC_VEC(VCLT0, gen_gvec_clt0) + +static bool trans_VMVN(DisasContext *s, arg_2misc *a) +{ + if (a->size != 0) { + return false; + } + return do_2misc_vec(s, a, tcg_gen_gvec_not); +} diff --git a/target/arm/translate.c b/target/arm/translate.c index 1ea0969554..0f0741a37b 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -4859,7 +4859,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) int size; int pass; int u; - int vec_size; TCGv_i32 tmp, tmp2; if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { @@ -4883,7 +4882,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) VFP_DREG_D(rd, insn); VFP_DREG_M(rm, insn); size = (insn >> 20) & 3; - vec_size = q ? 16 : 8; rd_ofs = neon_reg_offset(rd, 0); rm_ofs = neon_reg_offset(rm, 0); @@ -4929,6 +4927,14 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_2RM_VSHLL: case NEON_2RM_VCVT_F16_F32: case NEON_2RM_VCVT_F32_F16: + case NEON_2RM_VMVN: + case NEON_2RM_VNEG: + case NEON_2RM_VABS: + case NEON_2RM_VCEQ0: + case NEON_2RM_VCGT0: + case NEON_2RM_VCLE0: + case NEON_2RM_VCGE0: + case NEON_2RM_VCLT0: /* handled by decodetree */ return 1; case NEON_2RM_VTRN: @@ -4989,31 +4995,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) q ? gen_helper_crypto_sha256su0 : gen_helper_crypto_sha1su1); break; - case NEON_2RM_VMVN: - tcg_gen_gvec_not(0, rd_ofs, rm_ofs, vec_size, vec_size); - break; - case NEON_2RM_VNEG: - tcg_gen_gvec_neg(size, rd_ofs, rm_ofs, vec_size, vec_size); - break; - case NEON_2RM_VABS: - tcg_gen_gvec_abs(size, rd_ofs, rm_ofs, vec_size, vec_size); - break; - - case NEON_2RM_VCEQ0: - gen_gvec_ceq0(size, rd_ofs, rm_ofs, vec_size, vec_size); - break; - case NEON_2RM_VCGT0: - gen_gvec_cgt0(size, rd_ofs, rm_ofs, vec_size, vec_size); - break; - case NEON_2RM_VCLE0: - gen_gvec_cle0(size, rd_ofs, rm_ofs, vec_size, vec_size); - break; - case NEON_2RM_VCGE0: - gen_gvec_cge0(size, rd_ofs, rm_ofs, vec_size, vec_size); - break; - case NEON_2RM_VCLT0: - gen_gvec_clt0(size, rd_ofs, rm_ofs, vec_size, vec_size); - break; default: elementwise: From 0b30dd5b85e20aba259768cb7aaa952b3e319468 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 18:08:31 +0100 Subject: [PATCH 10/42] target/arm: Convert Neon 2-reg-misc crypto operations to decodetree Convert the Neon-2-reg misc crypto ops (AESE, AESMC, SHA1H, SHA1SU1) to decodetree. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200616170844.13318-9-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 12 ++++++++ target/arm/translate-neon.inc.c | 42 ++++++++++++++++++++++++++ target/arm/translate.c | 52 +++------------------------------ 3 files changed, 58 insertions(+), 48 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index b5692070d6..86b1b9e34b 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -441,12 +441,19 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm &2misc vm=%vm_dp vd=%vd_dp @2misc_q0 .... ... .. . .. size:2 .. .... . .... . . . .... \ &2misc vm=%vm_dp vd=%vd_dp q=0 + @2misc_q1 .... ... .. . .. size:2 .. .... . .... . . . .... \ + &2misc vm=%vm_dp vd=%vd_dp q=1 VREV64 1111 001 11 . 11 .. 00 .... 0 0000 . . 0 .... @2misc VPADDL_S 1111 001 11 . 11 .. 00 .... 0 0100 . . 0 .... @2misc VPADDL_U 1111 001 11 . 11 .. 00 .... 0 0101 . . 0 .... @2misc + AESE 1111 001 11 . 11 .. 00 .... 0 0110 0 . 0 .... @2misc_q1 + AESD 1111 001 11 . 11 .. 00 .... 0 0110 1 . 0 .... @2misc_q1 + AESMC 1111 001 11 . 11 .. 00 .... 0 0111 0 . 0 .... @2misc_q1 + AESIMC 1111 001 11 . 11 .. 00 .... 0 0111 1 . 0 .... @2misc_q1 + VMVN 1111 001 11 . 11 .. 00 .... 0 1011 . . 0 .... @2misc VPADAL_S 1111 001 11 . 11 .. 00 .... 0 1100 . . 0 .... @2misc @@ -458,6 +465,8 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm VCLE0 1111 001 11 . 11 .. 01 .... 0 0011 . . 0 .... @2misc VCLT0 1111 001 11 . 11 .. 01 .... 0 0100 . . 0 .... @2misc + SHA1H 1111 001 11 . 11 .. 01 .... 0 0101 1 . 0 .... @2misc_q1 + VABS 1111 001 11 . 11 .. 01 .... 0 0110 . . 0 .... @2misc VNEG 1111 001 11 . 11 .. 01 .... 0 0111 . . 0 .... @2misc @@ -473,6 +482,9 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm VSHLL 1111 001 11 . 11 .. 10 .... 0 0110 0 . 0 .... @2misc_q0 + SHA1SU1 1111 001 11 . 11 .. 10 .... 0 0111 0 . 0 .... @2misc_q1 + SHA256SU0 1111 001 11 . 11 .. 10 .... 0 0111 1 . 0 .... @2misc_q1 + VCVT_F16_F32 1111 001 11 . 11 .. 10 .... 0 1100 0 . 0 .... @2misc_q0 VCVT_F32_F16 1111 001 11 . 11 .. 10 .... 0 1110 0 . 0 .... @2misc_q0 ] diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index d80123514c..5e2cd18bf7 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -3505,3 +3505,45 @@ static bool trans_VMVN(DisasContext *s, arg_2misc *a) } return do_2misc_vec(s, a, tcg_gen_gvec_not); } + +#define WRAP_2M_3_OOL_FN(WRAPNAME, FUNC, DATA) \ + static void WRAPNAME(unsigned vece, uint32_t rd_ofs, \ + uint32_t rm_ofs, uint32_t oprsz, \ + uint32_t maxsz) \ + { \ + tcg_gen_gvec_3_ool(rd_ofs, rd_ofs, rm_ofs, oprsz, maxsz, \ + DATA, FUNC); \ + } + +#define WRAP_2M_2_OOL_FN(WRAPNAME, FUNC, DATA) \ + static void WRAPNAME(unsigned vece, uint32_t rd_ofs, \ + uint32_t rm_ofs, uint32_t oprsz, \ + uint32_t maxsz) \ + { \ + tcg_gen_gvec_2_ool(rd_ofs, rm_ofs, oprsz, maxsz, DATA, FUNC); \ + } + +WRAP_2M_3_OOL_FN(gen_AESE, gen_helper_crypto_aese, 0) +WRAP_2M_3_OOL_FN(gen_AESD, gen_helper_crypto_aese, 1) +WRAP_2M_2_OOL_FN(gen_AESMC, gen_helper_crypto_aesmc, 0) +WRAP_2M_2_OOL_FN(gen_AESIMC, gen_helper_crypto_aesmc, 1) +WRAP_2M_2_OOL_FN(gen_SHA1H, gen_helper_crypto_sha1h, 0) +WRAP_2M_2_OOL_FN(gen_SHA1SU1, gen_helper_crypto_sha1su1, 0) +WRAP_2M_2_OOL_FN(gen_SHA256SU0, gen_helper_crypto_sha256su0, 0) + +#define DO_2M_CRYPTO(INSN, FEATURE, SIZE) \ + static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ + { \ + if (!dc_isar_feature(FEATURE, s) || a->size != SIZE) { \ + return false; \ + } \ + return do_2misc_vec(s, a, gen_##INSN); \ + } + +DO_2M_CRYPTO(AESE, aa32_aes, 0) +DO_2M_CRYPTO(AESD, aa32_aes, 0) +DO_2M_CRYPTO(AESMC, aa32_aes, 0) +DO_2M_CRYPTO(AESIMC, aa32_aes, 0) +DO_2M_CRYPTO(SHA1H, aa32_sha1, 2) +DO_2M_CRYPTO(SHA1SU1, aa32_sha1, 2) +DO_2M_CRYPTO(SHA256SU0, aa32_sha2, 2) diff --git a/target/arm/translate.c b/target/arm/translate.c index 0f0741a37b..38644995ab 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -4855,7 +4855,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) { int op; int q; - int rd, rm, rd_ofs, rm_ofs; + int rd, rm; int size; int pass; int u; @@ -4882,8 +4882,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) VFP_DREG_D(rd, insn); VFP_DREG_M(rm, insn); size = (insn >> 20) & 3; - rd_ofs = neon_reg_offset(rd, 0); - rm_ofs = neon_reg_offset(rm, 0); if ((insn & (1 << 23)) == 0) { /* Three register same length: handled by decodetree */ @@ -4935,6 +4933,9 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_2RM_VCLE0: case NEON_2RM_VCGE0: case NEON_2RM_VCLT0: + case NEON_2RM_AESE: case NEON_2RM_AESMC: + case NEON_2RM_SHA1H: + case NEON_2RM_SHA1SU1: /* handled by decodetree */ return 1; case NEON_2RM_VTRN: @@ -4950,51 +4951,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) goto elementwise; } break; - case NEON_2RM_AESE: case NEON_2RM_AESMC: - if (!dc_isar_feature(aa32_aes, s) || ((rm | rd) & 1)) { - return 1; - } - /* - * Bit 6 is the lowest opcode bit; it distinguishes - * between encryption (AESE/AESMC) and decryption - * (AESD/AESIMC). - */ - if (op == NEON_2RM_AESE) { - tcg_gen_gvec_3_ool(vfp_reg_offset(true, rd), - vfp_reg_offset(true, rd), - vfp_reg_offset(true, rm), - 16, 16, extract32(insn, 6, 1), - gen_helper_crypto_aese); - } else { - tcg_gen_gvec_2_ool(vfp_reg_offset(true, rd), - vfp_reg_offset(true, rm), - 16, 16, extract32(insn, 6, 1), - gen_helper_crypto_aesmc); - } - break; - case NEON_2RM_SHA1H: - if (!dc_isar_feature(aa32_sha1, s) || ((rm | rd) & 1)) { - return 1; - } - tcg_gen_gvec_2_ool(rd_ofs, rm_ofs, 16, 16, 0, - gen_helper_crypto_sha1h); - break; - case NEON_2RM_SHA1SU1: - if ((rm | rd) & 1) { - return 1; - } - /* bit 6 (q): set -> SHA256SU0, cleared -> SHA1SU1 */ - if (q) { - if (!dc_isar_feature(aa32_sha2, s)) { - return 1; - } - } else if (!dc_isar_feature(aa32_sha1, s)) { - return 1; - } - tcg_gen_gvec_2_ool(rd_ofs, rm_ofs, 16, 16, 0, - q ? gen_helper_crypto_sha256su0 - : gen_helper_crypto_sha1su1); - break; default: elementwise: From 039f4e809ad2772fb33de4511ff68a485d875618 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 18:08:32 +0100 Subject: [PATCH 11/42] target/arm: Rename NeonGenOneOpFn to NeonGenOne64OpFn The NeonGenOneOpFn typedef breaks with the pattern of the other NeonGen*Fn typedefs, because it is a TCGv_i64 -> TCGv_i64 operation but it does not have '64' in its name. Rename it to NeonGenOne64OpFn, so that the old name is available for a TCGv_i32 -> TCGv_i32 operation (which we will need in a subsequent commit). Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200616170844.13318-10-peter.maydell@linaro.org --- target/arm/translate-a64.c | 4 ++-- target/arm/translate.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index a0e72ad694..7cb5fbfba8 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -11917,8 +11917,8 @@ static void handle_2misc_pairwise(DisasContext *s, int opcode, bool u, } else { for (pass = 0; pass < maxpass; pass++) { TCGv_i64 tcg_op = tcg_temp_new_i64(); - NeonGenOneOpFn *genfn; - static NeonGenOneOpFn * const fns[2][2] = { + NeonGenOne64OpFn *genfn; + static NeonGenOne64OpFn * const fns[2][2] = { { gen_helper_neon_addlp_s8, gen_helper_neon_addlp_u8 }, { gen_helper_neon_addlp_s16, gen_helper_neon_addlp_u16 }, }; diff --git a/target/arm/translate.h b/target/arm/translate.h index 62ed5c4780..35218b3fdf 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -374,7 +374,7 @@ typedef void NeonGenWidenFn(TCGv_i64, TCGv_i32); typedef void NeonGenTwoOpWidenFn(TCGv_i64, TCGv_i32, TCGv_i32); typedef void NeonGenTwoSingleOPFn(TCGv_i32, TCGv_i32, TCGv_i32, TCGv_ptr); typedef void NeonGenTwoDoubleOPFn(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_ptr); -typedef void NeonGenOneOpFn(TCGv_i64, TCGv_i64); +typedef void NeonGenOne64OpFn(TCGv_i64, TCGv_i64); typedef void CryptoTwoOpFn(TCGv_ptr, TCGv_ptr); typedef void CryptoThreeOpIntFn(TCGv_ptr, TCGv_ptr, TCGv_i32); typedef void CryptoThreeOpFn(TCGv_ptr, TCGv_ptr, TCGv_ptr); From 5de3fd045be11b74cd0fbf36c6d4fb8387d5463b Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 18:08:33 +0100 Subject: [PATCH 12/42] target/arm: Fix capitalization in NeonGenTwo{Single, Double}OPFn typedefs All the other typedefs like these spell "Op" with a lowercase 'p'; remane the NeonGenTwoSingleOPFn and NeonGenTwoDoubleOPFn typedefs to match. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200616170844.13318-11-peter.maydell@linaro.org --- target/arm/translate-a64.c | 4 ++-- target/arm/translate-neon.inc.c | 2 +- target/arm/translate.h | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 7cb5fbfba8..1204098498 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -9534,7 +9534,7 @@ static void handle_2misc_fcmp_zero(DisasContext *s, int opcode, TCGv_i64 tcg_op = tcg_temp_new_i64(); TCGv_i64 tcg_zero = tcg_const_i64(0); TCGv_i64 tcg_res = tcg_temp_new_i64(); - NeonGenTwoDoubleOPFn *genfn; + NeonGenTwoDoubleOpFn *genfn; bool swap = false; int pass; @@ -9576,7 +9576,7 @@ static void handle_2misc_fcmp_zero(DisasContext *s, int opcode, TCGv_i32 tcg_op = tcg_temp_new_i32(); TCGv_i32 tcg_zero = tcg_const_i32(0); TCGv_i32 tcg_res = tcg_temp_new_i32(); - NeonGenTwoSingleOPFn *genfn; + NeonGenTwoSingleOpFn *genfn; bool swap = false; int pass, maxpasses; diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 5e2cd18bf7..c39443c8ca 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -1664,7 +1664,7 @@ static bool trans_VSHLL_U_2sh(DisasContext *s, arg_2reg_shift *a) } static bool do_fp_2sh(DisasContext *s, arg_2reg_shift *a, - NeonGenTwoSingleOPFn *fn) + NeonGenTwoSingleOpFn *fn) { /* FP operations in 2-reg-and-shift group */ TCGv_i32 tmp, shiftv; diff --git a/target/arm/translate.h b/target/arm/translate.h index 35218b3fdf..467c529110 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -372,8 +372,8 @@ typedef void NeonGenNarrowFn(TCGv_i32, TCGv_i64); typedef void NeonGenNarrowEnvFn(TCGv_i32, TCGv_ptr, TCGv_i64); typedef void NeonGenWidenFn(TCGv_i64, TCGv_i32); typedef void NeonGenTwoOpWidenFn(TCGv_i64, TCGv_i32, TCGv_i32); -typedef void NeonGenTwoSingleOPFn(TCGv_i32, TCGv_i32, TCGv_i32, TCGv_ptr); -typedef void NeonGenTwoDoubleOPFn(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_ptr); +typedef void NeonGenTwoSingleOpFn(TCGv_i32, TCGv_i32, TCGv_i32, TCGv_ptr); +typedef void NeonGenTwoDoubleOpFn(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_ptr); typedef void NeonGenOne64OpFn(TCGv_i64, TCGv_i64); typedef void CryptoTwoOpFn(TCGv_ptr, TCGv_ptr); typedef void CryptoThreeOpIntFn(TCGv_ptr, TCGv_ptr, TCGv_i32); From 8ec3de7018a8198624aae49eef5568256114a829 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 18:08:34 +0100 Subject: [PATCH 13/42] target/arm: Make gen_swap_half() take separate src and dest Make gen_swap_half() take a source and destination TCGv_i32 rather than modifying the input TCGv_i32; we're going to want to be able to use it with the more flexible function signature, and this also brings it into line with other functions like gen_rev16() and gen_revsh(). Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200616170844.13318-12-peter.maydell@linaro.org --- target/arm/translate-neon.inc.c | 2 +- target/arm/translate.c | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index c39443c8ca..4967e97438 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -3007,7 +3007,7 @@ static bool trans_VREV64(DisasContext *s, arg_VREV64 *a) tcg_gen_bswap32_i32(tmp[half], tmp[half]); break; case 1: - gen_swap_half(tmp[half]); + gen_swap_half(tmp[half], tmp[half]); break; case 2: break; diff --git a/target/arm/translate.c b/target/arm/translate.c index 38644995ab..64b18a95b6 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -378,9 +378,9 @@ static void gen_revsh(TCGv_i32 dest, TCGv_i32 var) } /* Swap low and high halfwords. */ -static void gen_swap_half(TCGv_i32 var) +static void gen_swap_half(TCGv_i32 dest, TCGv_i32 var) { - tcg_gen_rotri_i32(var, var, 16); + tcg_gen_rotri_i32(dest, var, 16); } /* Dual 16-bit add. Result placed in t0 and t1 is marked as dead. @@ -4960,7 +4960,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_2RM_VREV32: switch (size) { case 0: tcg_gen_bswap32_i32(tmp, tmp); break; - case 1: gen_swap_half(tmp); break; + case 1: gen_swap_half(tmp, tmp); break; default: abort(); } break; @@ -8046,7 +8046,7 @@ static bool op_smlad(DisasContext *s, arg_rrrr *a, bool m_swap, bool sub) t1 = load_reg(s, a->rn); t2 = load_reg(s, a->rm); if (m_swap) { - gen_swap_half(t2); + gen_swap_half(t2, t2); } gen_smul_dual(t1, t2); @@ -8104,7 +8104,7 @@ static bool op_smlald(DisasContext *s, arg_rrrr *a, bool m_swap, bool sub) t1 = load_reg(s, a->rn); t2 = load_reg(s, a->rm); if (m_swap) { - gen_swap_half(t2); + gen_swap_half(t2, t2); } gen_smul_dual(t1, t2); From 8966808205b59d6c196b380b638475bcd1657ef4 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 18:08:35 +0100 Subject: [PATCH 14/42] target/arm: Convert Neon 2-reg-misc VREV32 and VREV16 to decodetree Convert the VREV32 and VREV16 insns in the Neon 2-reg-misc group to decodetree. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200616170844.13318-13-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 2 ++ target/arm/translate-neon.inc.c | 55 +++++++++++++++++++++++++++++++++ target/arm/translate.c | 12 ++----- target/arm/translate.h | 1 + 4 files changed, 60 insertions(+), 10 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 86b1b9e34b..0a791af46c 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -445,6 +445,8 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm &2misc vm=%vm_dp vd=%vd_dp q=1 VREV64 1111 001 11 . 11 .. 00 .... 0 0000 . . 0 .... @2misc + VREV32 1111 001 11 . 11 .. 00 .... 0 0001 . . 0 .... @2misc + VREV16 1111 001 11 . 11 .. 00 .... 0 0010 . . 0 .... @2misc VPADDL_S 1111 001 11 . 11 .. 00 .... 0 0100 . . 0 .... @2misc VPADDL_U 1111 001 11 . 11 .. 00 .... 0 0101 . . 0 .... @2misc diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 4967e97438..0a779980d0 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -3547,3 +3547,58 @@ DO_2M_CRYPTO(AESIMC, aa32_aes, 0) DO_2M_CRYPTO(SHA1H, aa32_sha1, 2) DO_2M_CRYPTO(SHA1SU1, aa32_sha1, 2) DO_2M_CRYPTO(SHA256SU0, aa32_sha2, 2) + +static bool do_2misc(DisasContext *s, arg_2misc *a, NeonGenOneOpFn *fn) +{ + int pass; + + /* Handle a 2-reg-misc operation by iterating 32 bits at a time */ + if (!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->vd | a->vm) & 0x10)) { + return false; + } + + if (!fn) { + return false; + } + + if ((a->vd | a->vm) & a->q) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + for (pass = 0; pass < (a->q ? 4 : 2); pass++) { + TCGv_i32 tmp = neon_load_reg(a->vm, pass); + fn(tmp, tmp); + neon_store_reg(a->vd, pass, tmp); + } + + return true; +} + +static bool trans_VREV32(DisasContext *s, arg_2misc *a) +{ + static NeonGenOneOpFn * const fn[] = { + tcg_gen_bswap32_i32, + gen_swap_half, + NULL, + NULL, + }; + return do_2misc(s, a, fn[a->size]); +} + +static bool trans_VREV16(DisasContext *s, arg_2misc *a) +{ + if (a->size != 0) { + return false; + } + return do_2misc(s, a, gen_rev16); +} diff --git a/target/arm/translate.c b/target/arm/translate.c index 64b18a95b6..5b50eddd11 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -4936,6 +4936,8 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_2RM_AESE: case NEON_2RM_AESMC: case NEON_2RM_SHA1H: case NEON_2RM_SHA1SU1: + case NEON_2RM_VREV32: + case NEON_2RM_VREV16: /* handled by decodetree */ return 1; case NEON_2RM_VTRN: @@ -4957,16 +4959,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) for (pass = 0; pass < (q ? 4 : 2); pass++) { tmp = neon_load_reg(rm, pass); switch (op) { - case NEON_2RM_VREV32: - switch (size) { - case 0: tcg_gen_bswap32_i32(tmp, tmp); break; - case 1: gen_swap_half(tmp, tmp); break; - default: abort(); - } - break; - case NEON_2RM_VREV16: - gen_rev16(tmp, tmp); - break; case NEON_2RM_VCLS: switch (size) { case 0: gen_helper_neon_cls_s8(tmp, tmp); break; diff --git a/target/arm/translate.h b/target/arm/translate.h index 467c529110..4dbeee4c89 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -363,6 +363,7 @@ typedef void GVecGen4Fn(unsigned, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); /* Function prototype for gen_ functions for calling Neon helpers */ +typedef void NeonGenOneOpFn(TCGv_i32, TCGv_i32); typedef void NeonGenOneOpEnvFn(TCGv_i32, TCGv_ptr, TCGv_i32); typedef void NeonGenTwoOpFn(TCGv_i32, TCGv_i32, TCGv_i32); typedef void NeonGenTwoOpEnvFn(TCGv_i32, TCGv_ptr, TCGv_i32, TCGv_i32); From 84eae770af69c37a92496a4c4248875c070d5ee3 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 18:08:36 +0100 Subject: [PATCH 15/42] target/arm: Convert remaining simple 2-reg-misc Neon ops Convert the remaining ops in the Neon 2-reg-misc group which can be implemented simply with our do_2misc() helper. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200616170844.13318-14-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 10 +++++ target/arm/translate-neon.inc.c | 69 +++++++++++++++++++++++++++++++++ target/arm/translate.c | 38 ++++-------------- 3 files changed, 86 insertions(+), 31 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 0a791af46c..f947f7d09f 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -456,6 +456,10 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm AESMC 1111 001 11 . 11 .. 00 .... 0 0111 0 . 0 .... @2misc_q1 AESIMC 1111 001 11 . 11 .. 00 .... 0 0111 1 . 0 .... @2misc_q1 + VCLS 1111 001 11 . 11 .. 00 .... 0 1000 . . 0 .... @2misc + VCLZ 1111 001 11 . 11 .. 00 .... 0 1001 . . 0 .... @2misc + VCNT 1111 001 11 . 11 .. 00 .... 0 1010 . . 0 .... @2misc + VMVN 1111 001 11 . 11 .. 00 .... 0 1011 . . 0 .... @2misc VPADAL_S 1111 001 11 . 11 .. 00 .... 0 1100 . . 0 .... @2misc @@ -472,6 +476,9 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm VABS 1111 001 11 . 11 .. 01 .... 0 0110 . . 0 .... @2misc VNEG 1111 001 11 . 11 .. 01 .... 0 0111 . . 0 .... @2misc + VABS_F 1111 001 11 . 11 .. 01 .... 0 1110 . . 0 .... @2misc + VNEG_F 1111 001 11 . 11 .. 01 .... 0 1111 . . 0 .... @2misc + VUZP 1111 001 11 . 11 .. 10 .... 0 0010 . . 0 .... @2misc VZIP 1111 001 11 . 11 .. 10 .... 0 0011 . . 0 .... @2misc @@ -489,6 +496,9 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm VCVT_F16_F32 1111 001 11 . 11 .. 10 .... 0 1100 0 . 0 .... @2misc_q0 VCVT_F32_F16 1111 001 11 . 11 .. 10 .... 0 1110 0 . 0 .... @2misc_q0 + + VRECPE 1111 001 11 . 11 .. 11 .... 0 1000 . . 0 .... @2misc + VRSQRTE 1111 001 11 . 11 .. 11 .... 0 1001 . . 0 .... @2misc ] # Subgroup for size != 0b11 diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 0a779980d0..336c2b312e 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -3602,3 +3602,72 @@ static bool trans_VREV16(DisasContext *s, arg_2misc *a) } return do_2misc(s, a, gen_rev16); } + +static bool trans_VCLS(DisasContext *s, arg_2misc *a) +{ + static NeonGenOneOpFn * const fn[] = { + gen_helper_neon_cls_s8, + gen_helper_neon_cls_s16, + gen_helper_neon_cls_s32, + NULL, + }; + return do_2misc(s, a, fn[a->size]); +} + +static void do_VCLZ_32(TCGv_i32 rd, TCGv_i32 rm) +{ + tcg_gen_clzi_i32(rd, rm, 32); +} + +static bool trans_VCLZ(DisasContext *s, arg_2misc *a) +{ + static NeonGenOneOpFn * const fn[] = { + gen_helper_neon_clz_u8, + gen_helper_neon_clz_u16, + do_VCLZ_32, + NULL, + }; + return do_2misc(s, a, fn[a->size]); +} + +static bool trans_VCNT(DisasContext *s, arg_2misc *a) +{ + if (a->size != 0) { + return false; + } + return do_2misc(s, a, gen_helper_neon_cnt_u8); +} + +static bool trans_VABS_F(DisasContext *s, arg_2misc *a) +{ + if (a->size != 2) { + return false; + } + /* TODO: FP16 : size == 1 */ + return do_2misc(s, a, gen_helper_vfp_abss); +} + +static bool trans_VNEG_F(DisasContext *s, arg_2misc *a) +{ + if (a->size != 2) { + return false; + } + /* TODO: FP16 : size == 1 */ + return do_2misc(s, a, gen_helper_vfp_negs); +} + +static bool trans_VRECPE(DisasContext *s, arg_2misc *a) +{ + if (a->size != 2) { + return false; + } + return do_2misc(s, a, gen_helper_recpe_u32); +} + +static bool trans_VRSQRTE(DisasContext *s, arg_2misc *a) +{ + if (a->size != 2) { + return false; + } + return do_2misc(s, a, gen_helper_rsqrte_u32); +} diff --git a/target/arm/translate.c b/target/arm/translate.c index 5b50eddd11..1737374388 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -4938,6 +4938,13 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_2RM_SHA1SU1: case NEON_2RM_VREV32: case NEON_2RM_VREV16: + case NEON_2RM_VCLS: + case NEON_2RM_VCLZ: + case NEON_2RM_VCNT: + case NEON_2RM_VABS_F: + case NEON_2RM_VNEG_F: + case NEON_2RM_VRECPE: + case NEON_2RM_VRSQRTE: /* handled by decodetree */ return 1; case NEON_2RM_VTRN: @@ -4959,25 +4966,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) for (pass = 0; pass < (q ? 4 : 2); pass++) { tmp = neon_load_reg(rm, pass); switch (op) { - case NEON_2RM_VCLS: - switch (size) { - case 0: gen_helper_neon_cls_s8(tmp, tmp); break; - case 1: gen_helper_neon_cls_s16(tmp, tmp); break; - case 2: gen_helper_neon_cls_s32(tmp, tmp); break; - default: abort(); - } - break; - case NEON_2RM_VCLZ: - switch (size) { - case 0: gen_helper_neon_clz_u8(tmp, tmp); break; - case 1: gen_helper_neon_clz_u16(tmp, tmp); break; - case 2: tcg_gen_clzi_i32(tmp, tmp, 32); break; - default: abort(); - } - break; - case NEON_2RM_VCNT: - gen_helper_neon_cnt_u8(tmp, tmp); - break; case NEON_2RM_VQABS: switch (size) { case 0: @@ -5051,12 +5039,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) tcg_temp_free_ptr(fpstatus); break; } - case NEON_2RM_VABS_F: - gen_helper_vfp_abss(tmp, tmp); - break; - case NEON_2RM_VNEG_F: - gen_helper_vfp_negs(tmp, tmp); - break; case NEON_2RM_VSWP: tmp2 = neon_load_reg(rd, pass); neon_store_reg(rm, pass, tmp2); @@ -5137,12 +5119,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) tcg_temp_free_ptr(fpst); break; } - case NEON_2RM_VRECPE: - gen_helper_recpe_u32(tmp, tmp); - break; - case NEON_2RM_VRSQRTE: - gen_helper_rsqrte_u32(tmp, tmp); - break; case NEON_2RM_VRECPE_F: { TCGv_ptr fpstatus = get_fpstatus_ptr(1); From 4936f38abe6db0a9d23fd04e4cb0cf4d51cff174 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 18:08:37 +0100 Subject: [PATCH 16/42] target/arm: Convert Neon VQABS, VQNEG to decodetree Convert the Neon VQABS and VQNEG insns to decodetree. Since these are the only ones which need cpu_env passing to the helper, we wrap the helper rather than creating a whole new do_2misc_env() function. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200616170844.13318-15-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 3 +++ target/arm/translate-neon.inc.c | 35 +++++++++++++++++++++++++++++++++ target/arm/translate.c | 30 ++-------------------------- 3 files changed, 40 insertions(+), 28 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index f947f7d09f..f0bb34a49e 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -465,6 +465,9 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm VPADAL_S 1111 001 11 . 11 .. 00 .... 0 1100 . . 0 .... @2misc VPADAL_U 1111 001 11 . 11 .. 00 .... 0 1101 . . 0 .... @2misc + VQABS 1111 001 11 . 11 .. 00 .... 0 1110 . . 0 .... @2misc + VQNEG 1111 001 11 . 11 .. 00 .... 0 1111 . . 0 .... @2misc + VCGT0 1111 001 11 . 11 .. 01 .... 0 0000 . . 0 .... @2misc VCGE0 1111 001 11 . 11 .. 01 .... 0 0001 . . 0 .... @2misc VCEQ0 1111 001 11 . 11 .. 01 .... 0 0010 . . 0 .... @2misc diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 336c2b312e..2b5dc86f62 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -3671,3 +3671,38 @@ static bool trans_VRSQRTE(DisasContext *s, arg_2misc *a) } return do_2misc(s, a, gen_helper_rsqrte_u32); } + +#define WRAP_1OP_ENV_FN(WRAPNAME, FUNC) \ + static void WRAPNAME(TCGv_i32 d, TCGv_i32 m) \ + { \ + FUNC(d, cpu_env, m); \ + } + +WRAP_1OP_ENV_FN(gen_VQABS_s8, gen_helper_neon_qabs_s8) +WRAP_1OP_ENV_FN(gen_VQABS_s16, gen_helper_neon_qabs_s16) +WRAP_1OP_ENV_FN(gen_VQABS_s32, gen_helper_neon_qabs_s32) +WRAP_1OP_ENV_FN(gen_VQNEG_s8, gen_helper_neon_qneg_s8) +WRAP_1OP_ENV_FN(gen_VQNEG_s16, gen_helper_neon_qneg_s16) +WRAP_1OP_ENV_FN(gen_VQNEG_s32, gen_helper_neon_qneg_s32) + +static bool trans_VQABS(DisasContext *s, arg_2misc *a) +{ + static NeonGenOneOpFn * const fn[] = { + gen_VQABS_s8, + gen_VQABS_s16, + gen_VQABS_s32, + NULL, + }; + return do_2misc(s, a, fn[a->size]); +} + +static bool trans_VQNEG(DisasContext *s, arg_2misc *a) +{ + static NeonGenOneOpFn * const fn[] = { + gen_VQNEG_s8, + gen_VQNEG_s16, + gen_VQNEG_s32, + NULL, + }; + return do_2misc(s, a, fn[a->size]); +} diff --git a/target/arm/translate.c b/target/arm/translate.c index 1737374388..3cbd2ab0c9 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -4945,6 +4945,8 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_2RM_VNEG_F: case NEON_2RM_VRECPE: case NEON_2RM_VRSQRTE: + case NEON_2RM_VQABS: + case NEON_2RM_VQNEG: /* handled by decodetree */ return 1; case NEON_2RM_VTRN: @@ -4966,34 +4968,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) for (pass = 0; pass < (q ? 4 : 2); pass++) { tmp = neon_load_reg(rm, pass); switch (op) { - case NEON_2RM_VQABS: - switch (size) { - case 0: - gen_helper_neon_qabs_s8(tmp, cpu_env, tmp); - break; - case 1: - gen_helper_neon_qabs_s16(tmp, cpu_env, tmp); - break; - case 2: - gen_helper_neon_qabs_s32(tmp, cpu_env, tmp); - break; - default: abort(); - } - break; - case NEON_2RM_VQNEG: - switch (size) { - case 0: - gen_helper_neon_qneg_s8(tmp, cpu_env, tmp); - break; - case 1: - gen_helper_neon_qneg_s16(tmp, cpu_env, tmp); - break; - case 2: - gen_helper_neon_qneg_s32(tmp, cpu_env, tmp); - break; - default: abort(); - } - break; case NEON_2RM_VCGT0_F: { TCGv_ptr fpstatus = get_fpstatus_ptr(1); From 3e96b205286dfb8bbf363229709e4f8648fce379 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 18:08:38 +0100 Subject: [PATCH 17/42] target/arm: Convert simple fp Neon 2-reg-misc insns Convert the Neon 2-reg-misc insns which are implemented with simple calls to functions that take the input, output and fpstatus pointer. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200616170844.13318-16-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 8 +++++ target/arm/translate-neon.inc.c | 62 +++++++++++++++++++++++++++++++++ target/arm/translate.c | 56 ++++------------------------- target/arm/translate.h | 1 + 4 files changed, 78 insertions(+), 49 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index f0bb34a49e..ea8d5fd99c 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -497,11 +497,19 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm SHA1SU1 1111 001 11 . 11 .. 10 .... 0 0111 0 . 0 .... @2misc_q1 SHA256SU0 1111 001 11 . 11 .. 10 .... 0 0111 1 . 0 .... @2misc_q1 + VRINTX 1111 001 11 . 11 .. 10 .... 0 1001 . . 0 .... @2misc + VCVT_F16_F32 1111 001 11 . 11 .. 10 .... 0 1100 0 . 0 .... @2misc_q0 VCVT_F32_F16 1111 001 11 . 11 .. 10 .... 0 1110 0 . 0 .... @2misc_q0 VRECPE 1111 001 11 . 11 .. 11 .... 0 1000 . . 0 .... @2misc VRSQRTE 1111 001 11 . 11 .. 11 .... 0 1001 . . 0 .... @2misc + VRECPE_F 1111 001 11 . 11 .. 11 .... 0 1010 . . 0 .... @2misc + VRSQRTE_F 1111 001 11 . 11 .. 11 .... 0 1011 . . 0 .... @2misc + VCVT_FS 1111 001 11 . 11 .. 11 .... 0 1100 . . 0 .... @2misc + VCVT_FU 1111 001 11 . 11 .. 11 .... 0 1101 . . 0 .... @2misc + VCVT_SF 1111 001 11 . 11 .. 11 .... 0 1110 . . 0 .... @2misc + VCVT_UF 1111 001 11 . 11 .. 11 .... 0 1111 . . 0 .... @2misc ] # Subgroup for size != 0b11 diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 2b5dc86f62..ab183e47d7 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -3706,3 +3706,65 @@ static bool trans_VQNEG(DisasContext *s, arg_2misc *a) }; return do_2misc(s, a, fn[a->size]); } + +static bool do_2misc_fp(DisasContext *s, arg_2misc *a, + NeonGenOneSingleOpFn *fn) +{ + int pass; + TCGv_ptr fpst; + + /* Handle a 2-reg-misc operation by iterating 32 bits at a time */ + if (!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->vd | a->vm) & 0x10)) { + return false; + } + + if (a->size != 2) { + /* TODO: FP16 will be the size == 1 case */ + return false; + } + + if ((a->vd | a->vm) & a->q) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + fpst = get_fpstatus_ptr(1); + for (pass = 0; pass < (a->q ? 4 : 2); pass++) { + TCGv_i32 tmp = neon_load_reg(a->vm, pass); + fn(tmp, tmp, fpst); + neon_store_reg(a->vd, pass, tmp); + } + tcg_temp_free_ptr(fpst); + + return true; +} + +#define DO_2MISC_FP(INSN, FUNC) \ + static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ + { \ + return do_2misc_fp(s, a, FUNC); \ + } + +DO_2MISC_FP(VRECPE_F, gen_helper_recpe_f32) +DO_2MISC_FP(VRSQRTE_F, gen_helper_rsqrte_f32) +DO_2MISC_FP(VCVT_FS, gen_helper_vfp_sitos) +DO_2MISC_FP(VCVT_FU, gen_helper_vfp_uitos) +DO_2MISC_FP(VCVT_SF, gen_helper_vfp_tosizs) +DO_2MISC_FP(VCVT_UF, gen_helper_vfp_touizs) + +static bool trans_VRINTX(DisasContext *s, arg_2misc *a) +{ + if (!arm_dc_feature(s, ARM_FEATURE_V8)) { + return false; + } + return do_2misc_fp(s, a, gen_helper_rints_exact); +} diff --git a/target/arm/translate.c b/target/arm/translate.c index 3cbd2ab0c9..48377860c7 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -4947,6 +4947,13 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_2RM_VRSQRTE: case NEON_2RM_VQABS: case NEON_2RM_VQNEG: + case NEON_2RM_VRECPE_F: + case NEON_2RM_VRSQRTE_F: + case NEON_2RM_VCVT_FS: + case NEON_2RM_VCVT_FU: + case NEON_2RM_VCVT_SF: + case NEON_2RM_VCVT_UF: + case NEON_2RM_VRINTX: /* handled by decodetree */ return 1; case NEON_2RM_VTRN: @@ -5052,13 +5059,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) tcg_temp_free_i32(tcg_rmode); break; } - case NEON_2RM_VRINTX: - { - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - gen_helper_rints_exact(tmp, tmp, fpstatus); - tcg_temp_free_ptr(fpstatus); - break; - } case NEON_2RM_VCVTAU: case NEON_2RM_VCVTAS: case NEON_2RM_VCVTNU: @@ -5093,48 +5093,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) tcg_temp_free_ptr(fpst); break; } - case NEON_2RM_VRECPE_F: - { - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - 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(tmp, tmp, fpstatus); - tcg_temp_free_ptr(fpstatus); - break; - } - case NEON_2RM_VCVT_FS: /* VCVT.F32.S32 */ - { - 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 */ - { - 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 */ - { - 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 */ - { - 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. diff --git a/target/arm/translate.h b/target/arm/translate.h index 4dbeee4c89..19650a9e2d 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -373,6 +373,7 @@ typedef void NeonGenNarrowFn(TCGv_i32, TCGv_i64); typedef void NeonGenNarrowEnvFn(TCGv_i32, TCGv_ptr, TCGv_i64); typedef void NeonGenWidenFn(TCGv_i64, TCGv_i32); typedef void NeonGenTwoOpWidenFn(TCGv_i64, TCGv_i32, TCGv_i32); +typedef void NeonGenOneSingleOpFn(TCGv_i32, TCGv_i32, TCGv_ptr); typedef void NeonGenTwoSingleOpFn(TCGv_i32, TCGv_i32, TCGv_i32, TCGv_ptr); typedef void NeonGenTwoDoubleOpFn(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_ptr); typedef void NeonGenOne64OpFn(TCGv_i64, TCGv_i64); From baa59323e841f76523f6ad4d746cdeb47ea574cd Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 18:08:39 +0100 Subject: [PATCH 18/42] target/arm: Convert Neon 2-reg-misc fp-compare-with-zero insns to decodetree Convert the fp-compare-with-zero insns in the Neon 2-reg-misc group to decodetree. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200616170844.13318-17-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 6 ++++ target/arm/translate-neon.inc.c | 28 ++++++++++++++++++ target/arm/translate.c | 50 ++++----------------------------- 3 files changed, 39 insertions(+), 45 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index ea8d5fd99c..c9acd00f1e 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -479,6 +479,12 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm VABS 1111 001 11 . 11 .. 01 .... 0 0110 . . 0 .... @2misc VNEG 1111 001 11 . 11 .. 01 .... 0 0111 . . 0 .... @2misc + VCGT0_F 1111 001 11 . 11 .. 01 .... 0 1000 . . 0 .... @2misc + VCGE0_F 1111 001 11 . 11 .. 01 .... 0 1001 . . 0 .... @2misc + VCEQ0_F 1111 001 11 . 11 .. 01 .... 0 1010 . . 0 .... @2misc + VCLE0_F 1111 001 11 . 11 .. 01 .... 0 1011 . . 0 .... @2misc + VCLT0_F 1111 001 11 . 11 .. 01 .... 0 1100 . . 0 .... @2misc + VABS_F 1111 001 11 . 11 .. 01 .... 0 1110 . . 0 .... @2misc VNEG_F 1111 001 11 . 11 .. 01 .... 0 1111 . . 0 .... @2misc diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index ab183e47d7..a62da21b15 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -3768,3 +3768,31 @@ static bool trans_VRINTX(DisasContext *s, arg_2misc *a) } return do_2misc_fp(s, a, gen_helper_rints_exact); } + +#define WRAP_FP_CMP0_FWD(WRAPNAME, FUNC) \ + static void WRAPNAME(TCGv_i32 d, TCGv_i32 m, TCGv_ptr fpst) \ + { \ + TCGv_i32 zero = tcg_const_i32(0); \ + FUNC(d, m, zero, fpst); \ + tcg_temp_free_i32(zero); \ + } +#define WRAP_FP_CMP0_REV(WRAPNAME, FUNC) \ + static void WRAPNAME(TCGv_i32 d, TCGv_i32 m, TCGv_ptr fpst) \ + { \ + TCGv_i32 zero = tcg_const_i32(0); \ + FUNC(d, zero, m, fpst); \ + tcg_temp_free_i32(zero); \ + } + +#define DO_FP_CMP0(INSN, FUNC, REV) \ + WRAP_FP_CMP0_##REV(gen_##INSN, FUNC) \ + static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ + { \ + return do_2misc_fp(s, a, gen_##INSN); \ + } + +DO_FP_CMP0(VCGT0_F, gen_helper_neon_cgt_f32, FWD) +DO_FP_CMP0(VCGE0_F, gen_helper_neon_cge_f32, FWD) +DO_FP_CMP0(VCEQ0_F, gen_helper_neon_ceq_f32, FWD) +DO_FP_CMP0(VCLE0_F, gen_helper_neon_cge_f32, REV) +DO_FP_CMP0(VCLT0_F, gen_helper_neon_cgt_f32, REV) diff --git a/target/arm/translate.c b/target/arm/translate.c index 48377860c7..dc98928856 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -4954,6 +4954,11 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_2RM_VCVT_SF: case NEON_2RM_VCVT_UF: case NEON_2RM_VRINTX: + case NEON_2RM_VCGT0_F: + case NEON_2RM_VCGE0_F: + case NEON_2RM_VCEQ0_F: + case NEON_2RM_VCLE0_F: + case NEON_2RM_VCLT0_F: /* handled by decodetree */ return 1; case NEON_2RM_VTRN: @@ -4975,51 +4980,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) for (pass = 0; pass < (q ? 4 : 2); pass++) { tmp = neon_load_reg(rm, pass); switch (op) { - case NEON_2RM_VCGT0_F: - { - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - tmp2 = tcg_const_i32(0); - gen_helper_neon_cgt_f32(tmp, tmp, tmp2, fpstatus); - tcg_temp_free_i32(tmp2); - tcg_temp_free_ptr(fpstatus); - break; - } - case NEON_2RM_VCGE0_F: - { - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - tmp2 = tcg_const_i32(0); - gen_helper_neon_cge_f32(tmp, tmp, tmp2, fpstatus); - tcg_temp_free_i32(tmp2); - tcg_temp_free_ptr(fpstatus); - break; - } - case NEON_2RM_VCEQ0_F: - { - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - tmp2 = tcg_const_i32(0); - gen_helper_neon_ceq_f32(tmp, tmp, tmp2, fpstatus); - tcg_temp_free_i32(tmp2); - tcg_temp_free_ptr(fpstatus); - break; - } - case NEON_2RM_VCLE0_F: - { - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - tmp2 = tcg_const_i32(0); - gen_helper_neon_cge_f32(tmp, tmp2, tmp, fpstatus); - tcg_temp_free_i32(tmp2); - tcg_temp_free_ptr(fpstatus); - break; - } - case NEON_2RM_VCLT0_F: - { - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - tmp2 = tcg_const_i32(0); - gen_helper_neon_cgt_f32(tmp, tmp2, tmp, fpstatus); - tcg_temp_free_i32(tmp2); - tcg_temp_free_ptr(fpstatus); - break; - } case NEON_2RM_VSWP: tmp2 = neon_load_reg(rd, pass); neon_store_reg(rm, pass, tmp2); From 128123ea34e9e6afe4842aefcb9cf84b9642ac22 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 18:08:40 +0100 Subject: [PATCH 19/42] target/arm: Convert Neon 2-reg-misc VRINT insns to decodetree Convert the Neon 2-reg-misc VRINT insns to decodetree. Giving these insns their own do_vrint() function allows us to change the rounding mode just once at the start and end rather than doing it for every element in the vector. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200616170844.13318-18-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 8 +++++ target/arm/translate-neon.inc.c | 61 +++++++++++++++++++++++++++++++++ target/arm/translate.c | 31 +++-------------- 3 files changed, 74 insertions(+), 26 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index c9acd00f1e..e0717c7e4a 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -503,11 +503,19 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm SHA1SU1 1111 001 11 . 11 .. 10 .... 0 0111 0 . 0 .... @2misc_q1 SHA256SU0 1111 001 11 . 11 .. 10 .... 0 0111 1 . 0 .... @2misc_q1 + VRINTN 1111 001 11 . 11 .. 10 .... 0 1000 . . 0 .... @2misc VRINTX 1111 001 11 . 11 .. 10 .... 0 1001 . . 0 .... @2misc + VRINTA 1111 001 11 . 11 .. 10 .... 0 1010 . . 0 .... @2misc + VRINTZ 1111 001 11 . 11 .. 10 .... 0 1011 . . 0 .... @2misc VCVT_F16_F32 1111 001 11 . 11 .. 10 .... 0 1100 0 . 0 .... @2misc_q0 + + VRINTM 1111 001 11 . 11 .. 10 .... 0 1101 . . 0 .... @2misc + VCVT_F32_F16 1111 001 11 . 11 .. 10 .... 0 1110 0 . 0 .... @2misc_q0 + VRINTP 1111 001 11 . 11 .. 10 .... 0 1111 . . 0 .... @2misc + VRECPE 1111 001 11 . 11 .. 11 .... 0 1000 . . 0 .... @2misc VRSQRTE 1111 001 11 . 11 .. 11 .... 0 1001 . . 0 .... @2misc VRECPE_F 1111 001 11 . 11 .. 11 .... 0 1010 . . 0 .... @2misc diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index a62da21b15..0e7f86ad15 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -3796,3 +3796,64 @@ DO_FP_CMP0(VCGE0_F, gen_helper_neon_cge_f32, FWD) DO_FP_CMP0(VCEQ0_F, gen_helper_neon_ceq_f32, FWD) DO_FP_CMP0(VCLE0_F, gen_helper_neon_cge_f32, REV) DO_FP_CMP0(VCLT0_F, gen_helper_neon_cgt_f32, REV) + +static bool do_vrint(DisasContext *s, arg_2misc *a, int rmode) +{ + /* + * Handle a VRINT* operation by iterating 32 bits at a time, + * with a specified rounding mode in operation. + */ + int pass; + TCGv_ptr fpst; + TCGv_i32 tcg_rmode; + + if (!arm_dc_feature(s, ARM_FEATURE_NEON) || + !arm_dc_feature(s, ARM_FEATURE_V8)) { + 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)) { + return false; + } + + if (a->size != 2) { + /* TODO: FP16 will be the size == 1 case */ + return false; + } + + if ((a->vd | a->vm) & a->q) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + fpst = get_fpstatus_ptr(1); + tcg_rmode = tcg_const_i32(arm_rmode_to_sf(rmode)); + gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode, cpu_env); + for (pass = 0; pass < (a->q ? 4 : 2); pass++) { + TCGv_i32 tmp = neon_load_reg(a->vm, pass); + gen_helper_rints(tmp, tmp, fpst); + neon_store_reg(a->vd, pass, tmp); + } + gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode, cpu_env); + tcg_temp_free_i32(tcg_rmode); + tcg_temp_free_ptr(fpst); + + return true; +} + +#define DO_VRINT(INSN, RMODE) \ + static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ + { \ + return do_vrint(s, a, RMODE); \ + } + +DO_VRINT(VRINTN, FPROUNDING_TIEEVEN) +DO_VRINT(VRINTA, FPROUNDING_TIEAWAY) +DO_VRINT(VRINTZ, FPROUNDING_ZERO) +DO_VRINT(VRINTM, FPROUNDING_NEGINF) +DO_VRINT(VRINTP, FPROUNDING_POSINF) diff --git a/target/arm/translate.c b/target/arm/translate.c index dc98928856..61dfc3ae7a 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -4959,6 +4959,11 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_2RM_VCEQ0_F: case NEON_2RM_VCLE0_F: case NEON_2RM_VCLT0_F: + case NEON_2RM_VRINTN: + case NEON_2RM_VRINTA: + case NEON_2RM_VRINTM: + case NEON_2RM_VRINTP: + case NEON_2RM_VRINTZ: /* handled by decodetree */ return 1; case NEON_2RM_VTRN: @@ -4993,32 +4998,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) } neon_store_reg(rm, pass, tmp2); break; - case NEON_2RM_VRINTN: - case NEON_2RM_VRINTA: - case NEON_2RM_VRINTM: - case NEON_2RM_VRINTP: - case NEON_2RM_VRINTZ: - { - TCGv_i32 tcg_rmode; - TCGv_ptr fpstatus = get_fpstatus_ptr(1); - int rmode; - - if (op == NEON_2RM_VRINTZ) { - rmode = FPROUNDING_ZERO; - } else { - rmode = fp_decode_rm[((op & 0x6) >> 1) ^ 1]; - } - - tcg_rmode = tcg_const_i32(arm_rmode_to_sf(rmode)); - gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode, - cpu_env); - gen_helper_rints(tmp, tmp, fpstatus); - gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode, - cpu_env); - tcg_temp_free_ptr(fpstatus); - tcg_temp_free_i32(tcg_rmode); - break; - } case NEON_2RM_VCVTAU: case NEON_2RM_VCVTAS: case NEON_2RM_VCVTNU: From a183d5fb38b07bab2a840196186c4806f3c67c0d Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 18:08:41 +0100 Subject: [PATCH 20/42] target/arm: Convert Neon 2-reg-misc VCVT insns to decodetree Convert the VCVT instructions in the 2-reg-misc grouping to decodetree. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200616170844.13318-19-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 9 +++++ target/arm/translate-neon.inc.c | 70 +++++++++++++++++++++++++++++++++ target/arm/translate.c | 70 ++++----------------------------- 3 files changed, 87 insertions(+), 62 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index e0717c7e4a..5507c3e462 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -516,6 +516,15 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm VRINTP 1111 001 11 . 11 .. 10 .... 0 1111 . . 0 .... @2misc + VCVTAS 1111 001 11 . 11 .. 11 .... 0 0000 . . 0 .... @2misc + VCVTAU 1111 001 11 . 11 .. 11 .... 0 0001 . . 0 .... @2misc + VCVTNS 1111 001 11 . 11 .. 11 .... 0 0010 . . 0 .... @2misc + VCVTNU 1111 001 11 . 11 .. 11 .... 0 0011 . . 0 .... @2misc + VCVTPS 1111 001 11 . 11 .. 11 .... 0 0100 . . 0 .... @2misc + VCVTPU 1111 001 11 . 11 .. 11 .... 0 0101 . . 0 .... @2misc + VCVTMS 1111 001 11 . 11 .. 11 .... 0 0110 . . 0 .... @2misc + VCVTMU 1111 001 11 . 11 .. 11 .... 0 0111 . . 0 .... @2misc + VRECPE 1111 001 11 . 11 .. 11 .... 0 1000 . . 0 .... @2misc VRSQRTE 1111 001 11 . 11 .. 11 .... 0 1001 . . 0 .... @2misc VRECPE_F 1111 001 11 . 11 .. 11 .... 0 1010 . . 0 .... @2misc diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 0e7f86ad15..29bc161f36 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -3857,3 +3857,73 @@ DO_VRINT(VRINTA, FPROUNDING_TIEAWAY) DO_VRINT(VRINTZ, FPROUNDING_ZERO) DO_VRINT(VRINTM, FPROUNDING_NEGINF) DO_VRINT(VRINTP, FPROUNDING_POSINF) + +static bool do_vcvt(DisasContext *s, arg_2misc *a, int rmode, bool is_signed) +{ + /* + * Handle a VCVT* operation by iterating 32 bits at a time, + * with a specified rounding mode in operation. + */ + int pass; + TCGv_ptr fpst; + TCGv_i32 tcg_rmode, tcg_shift; + + if (!arm_dc_feature(s, ARM_FEATURE_NEON) || + !arm_dc_feature(s, ARM_FEATURE_V8)) { + 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)) { + return false; + } + + if (a->size != 2) { + /* TODO: FP16 will be the size == 1 case */ + return false; + } + + if ((a->vd | a->vm) & a->q) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + fpst = get_fpstatus_ptr(1); + tcg_shift = tcg_const_i32(0); + tcg_rmode = tcg_const_i32(arm_rmode_to_sf(rmode)); + gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode, cpu_env); + for (pass = 0; pass < (a->q ? 4 : 2); pass++) { + TCGv_i32 tmp = neon_load_reg(a->vm, pass); + if (is_signed) { + gen_helper_vfp_tosls(tmp, tmp, tcg_shift, fpst); + } else { + gen_helper_vfp_touls(tmp, tmp, tcg_shift, fpst); + } + neon_store_reg(a->vd, pass, tmp); + } + gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode, cpu_env); + tcg_temp_free_i32(tcg_rmode); + tcg_temp_free_i32(tcg_shift); + tcg_temp_free_ptr(fpst); + + return true; +} + +#define DO_VCVT(INSN, RMODE, SIGNED) \ + static bool trans_##INSN(DisasContext *s, arg_2misc *a) \ + { \ + return do_vcvt(s, a, RMODE, SIGNED); \ + } + +DO_VCVT(VCVTAU, FPROUNDING_TIEAWAY, false) +DO_VCVT(VCVTAS, FPROUNDING_TIEAWAY, true) +DO_VCVT(VCVTNU, FPROUNDING_TIEEVEN, false) +DO_VCVT(VCVTNS, FPROUNDING_TIEEVEN, true) +DO_VCVT(VCVTPU, FPROUNDING_POSINF, false) +DO_VCVT(VCVTPS, FPROUNDING_POSINF, true) +DO_VCVT(VCVTMU, FPROUNDING_NEGINF, false) +DO_VCVT(VCVTMS, FPROUNDING_NEGINF, true) diff --git a/target/arm/translate.c b/target/arm/translate.c index 61dfc3ae7a..b018106202 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -3042,30 +3042,6 @@ static void gen_neon_trn_u16(TCGv_i32 t0, TCGv_i32 t1) #define NEON_2RM_VCVT_SF 62 #define NEON_2RM_VCVT_UF 63 -static bool neon_2rm_is_v8_op(int op) -{ - /* Return true if this neon 2reg-misc op is ARMv8 and up */ - switch (op) { - case NEON_2RM_VRINTN: - case NEON_2RM_VRINTA: - case NEON_2RM_VRINTM: - case NEON_2RM_VRINTP: - case NEON_2RM_VRINTZ: - case NEON_2RM_VRINTX: - case NEON_2RM_VCVTAU: - case NEON_2RM_VCVTAS: - case NEON_2RM_VCVTNU: - case NEON_2RM_VCVTNS: - case NEON_2RM_VCVTPU: - case NEON_2RM_VCVTPS: - case NEON_2RM_VCVTMU: - case NEON_2RM_VCVTMS: - return true; - default: - return false; - } -} - /* Each entry in this array has bit n set if the insn allows * size value n (otherwise it will UNDEF). Since unallocated * op values will have no bits set they always UNDEF. @@ -4908,10 +4884,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) if ((neon_2rm_sizes[op] & (1 << size)) == 0) { return 1; } - if (neon_2rm_is_v8_op(op) && - !arm_dc_feature(s, ARM_FEATURE_V8)) { - return 1; - } if (q && ((rm | rd) & 1)) { return 1; } @@ -4964,6 +4936,14 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_2RM_VRINTM: case NEON_2RM_VRINTP: case NEON_2RM_VRINTZ: + case NEON_2RM_VCVTAU: + case NEON_2RM_VCVTAS: + case NEON_2RM_VCVTNU: + case NEON_2RM_VCVTNS: + case NEON_2RM_VCVTPU: + case NEON_2RM_VCVTPS: + case NEON_2RM_VCVTMU: + case NEON_2RM_VCVTMS: /* handled by decodetree */ return 1; case NEON_2RM_VTRN: @@ -4998,40 +4978,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) } neon_store_reg(rm, pass, tmp2); break; - case NEON_2RM_VCVTAU: - case NEON_2RM_VCVTAS: - case NEON_2RM_VCVTNU: - case NEON_2RM_VCVTNS: - case NEON_2RM_VCVTPU: - case NEON_2RM_VCVTPS: - case NEON_2RM_VCVTMU: - case NEON_2RM_VCVTMS: - { - bool is_signed = !extract32(insn, 7, 1); - TCGv_ptr fpst = get_fpstatus_ptr(1); - TCGv_i32 tcg_rmode, tcg_shift; - int rmode = fp_decode_rm[extract32(insn, 8, 2)]; - - tcg_shift = tcg_const_i32(0); - tcg_rmode = tcg_const_i32(arm_rmode_to_sf(rmode)); - gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode, - cpu_env); - - if (is_signed) { - gen_helper_vfp_tosls(tmp, tmp, - tcg_shift, fpst); - } else { - gen_helper_vfp_touls(tmp, tmp, - tcg_shift, fpst); - } - - gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode, - cpu_env); - tcg_temp_free_i32(tcg_rmode); - tcg_temp_free_i32(tcg_shift); - tcg_temp_free_ptr(fpst); - break; - } default: /* Reserved op values were caught by the * neon_2rm_sizes[] check earlier. From 8ab3a227a0f13f0ff85846f36f7c466769aef4fc Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 18:08:42 +0100 Subject: [PATCH 21/42] target/arm: Convert Neon VSWP to decodetree Convert the Neon VSWP insn to decodetree. Since the new implementation doesn't have to share a pass-loop with the other 2-reg-misc operations we can implement the swap with 64-bit accesses rather than 32-bits (which brings us into line with the pseudocode and is more efficient). Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200616170844.13318-20-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 2 ++ target/arm/translate-neon.inc.c | 41 +++++++++++++++++++++++++++++++++ target/arm/translate.c | 5 +--- 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 5507c3e462..2f64841de5 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -488,6 +488,8 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm VABS_F 1111 001 11 . 11 .. 01 .... 0 1110 . . 0 .... @2misc VNEG_F 1111 001 11 . 11 .. 01 .... 0 1111 . . 0 .... @2misc + VSWP 1111 001 11 . 11 .. 10 .... 0 0000 . . 0 .... @2misc + VUZP 1111 001 11 . 11 .. 10 .... 0 0010 . . 0 .... @2misc VZIP 1111 001 11 . 11 .. 10 .... 0 0011 . . 0 .... @2misc diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 29bc161f36..01da7fad46 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -3927,3 +3927,44 @@ DO_VCVT(VCVTPU, FPROUNDING_POSINF, false) DO_VCVT(VCVTPS, FPROUNDING_POSINF, true) DO_VCVT(VCVTMU, FPROUNDING_NEGINF, false) DO_VCVT(VCVTMS, FPROUNDING_NEGINF, true) + +static bool trans_VSWP(DisasContext *s, arg_2misc *a) +{ + TCGv_i64 rm, rd; + int pass; + + if (!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->vd | a->vm) & 0x10)) { + return false; + } + + if (a->size != 0) { + return false; + } + + if ((a->vd | a->vm) & a->q) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + rm = tcg_temp_new_i64(); + rd = tcg_temp_new_i64(); + for (pass = 0; pass < (a->q ? 2 : 1); pass++) { + neon_load_reg64(rm, a->vm + pass); + neon_load_reg64(rd, a->vd + pass); + neon_store_reg64(rm, a->vd + pass); + neon_store_reg64(rd, a->vm + pass); + } + tcg_temp_free_i64(rm); + tcg_temp_free_i64(rd); + + return true; +} diff --git a/target/arm/translate.c b/target/arm/translate.c index b018106202..e8cd4a9c61 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -4944,6 +4944,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) case NEON_2RM_VCVTPS: case NEON_2RM_VCVTMU: case NEON_2RM_VCVTMS: + case NEON_2RM_VSWP: /* handled by decodetree */ return 1; case NEON_2RM_VTRN: @@ -4965,10 +4966,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) for (pass = 0; pass < (q ? 4 : 2); pass++) { tmp = neon_load_reg(rm, pass); switch (op) { - case NEON_2RM_VSWP: - tmp2 = neon_load_reg(rd, pass); - neon_store_reg(rm, pass, tmp2); - break; case NEON_2RM_VTRN: tmp2 = neon_load_reg(rd, pass); switch (size) { From d4366190f84fe89cc5d46da995dac1e7d541b98e Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 18:08:43 +0100 Subject: [PATCH 22/42] target/arm: Convert Neon VTRN to decodetree Convert the Neon VTRN insn to decodetree. This is the last insn in the Neon data-processing group, so we can remove all the now-unused old decoder framework. It's possible that there's a more efficient implementation of VTRN, but for this conversion we just copy the existing approach. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200616170844.13318-21-peter.maydell@linaro.org --- target/arm/neon-dp.decode | 2 +- target/arm/translate-neon.inc.c | 90 ++++++++ target/arm/translate.c | 363 +------------------------------- 3 files changed, 93 insertions(+), 362 deletions(-) diff --git a/target/arm/neon-dp.decode b/target/arm/neon-dp.decode index 2f64841de5..686f9fbf46 100644 --- a/target/arm/neon-dp.decode +++ b/target/arm/neon-dp.decode @@ -489,7 +489,7 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm VNEG_F 1111 001 11 . 11 .. 01 .... 0 1111 . . 0 .... @2misc VSWP 1111 001 11 . 11 .. 10 .... 0 0000 . . 0 .... @2misc - + VTRN 1111 001 11 . 11 .. 10 .... 0 0001 . . 0 .... @2misc VUZP 1111 001 11 . 11 .. 10 .... 0 0010 . . 0 .... @2misc VZIP 1111 001 11 . 11 .. 10 .... 0 0011 . . 0 .... @2misc diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 01da7fad46..8cc7f5db54 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -3968,3 +3968,93 @@ static bool trans_VSWP(DisasContext *s, arg_2misc *a) return true; } +static void gen_neon_trn_u8(TCGv_i32 t0, TCGv_i32 t1) +{ + TCGv_i32 rd, tmp; + + rd = tcg_temp_new_i32(); + tmp = tcg_temp_new_i32(); + + tcg_gen_shli_i32(rd, t0, 8); + tcg_gen_andi_i32(rd, rd, 0xff00ff00); + tcg_gen_andi_i32(tmp, t1, 0x00ff00ff); + tcg_gen_or_i32(rd, rd, tmp); + + tcg_gen_shri_i32(t1, t1, 8); + tcg_gen_andi_i32(t1, t1, 0x00ff00ff); + tcg_gen_andi_i32(tmp, t0, 0xff00ff00); + tcg_gen_or_i32(t1, t1, tmp); + tcg_gen_mov_i32(t0, rd); + + tcg_temp_free_i32(tmp); + tcg_temp_free_i32(rd); +} + +static void gen_neon_trn_u16(TCGv_i32 t0, TCGv_i32 t1) +{ + TCGv_i32 rd, tmp; + + rd = tcg_temp_new_i32(); + tmp = tcg_temp_new_i32(); + + tcg_gen_shli_i32(rd, t0, 16); + tcg_gen_andi_i32(tmp, t1, 0xffff); + tcg_gen_or_i32(rd, rd, tmp); + tcg_gen_shri_i32(t1, t1, 16); + tcg_gen_andi_i32(tmp, t0, 0xffff0000); + tcg_gen_or_i32(t1, t1, tmp); + tcg_gen_mov_i32(t0, rd); + + tcg_temp_free_i32(tmp); + tcg_temp_free_i32(rd); +} + +static bool trans_VTRN(DisasContext *s, arg_2misc *a) +{ + TCGv_i32 tmp, tmp2; + int pass; + + if (!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->vd | a->vm) & 0x10)) { + return false; + } + + if ((a->vd | a->vm) & a->q) { + return false; + } + + if (a->size == 3) { + return false; + } + + if (!vfp_access_check(s)) { + return true; + } + + if (a->size == 2) { + for (pass = 0; pass < (a->q ? 4 : 2); pass += 2) { + tmp = neon_load_reg(a->vm, pass); + tmp2 = neon_load_reg(a->vd, pass + 1); + neon_store_reg(a->vm, pass, tmp2); + neon_store_reg(a->vd, pass + 1, tmp); + } + } else { + for (pass = 0; pass < (a->q ? 4 : 2); pass++) { + tmp = neon_load_reg(a->vm, pass); + tmp2 = neon_load_reg(a->vd, pass); + if (a->size == 0) { + gen_neon_trn_u8(tmp, tmp2); + } else { + gen_neon_trn_u16(tmp, tmp2); + } + neon_store_reg(a->vm, pass, tmp2); + neon_store_reg(a->vd, pass, tmp); + } + } + return true; +} diff --git a/target/arm/translate.c b/target/arm/translate.c index e8cd4a9c61..581b0b5cde 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -2934,183 +2934,6 @@ static void gen_exception_return(DisasContext *s, TCGv_i32 pc) gen_rfe(s, pc, load_cpu_field(spsr)); } -static void gen_neon_trn_u8(TCGv_i32 t0, TCGv_i32 t1) -{ - TCGv_i32 rd, tmp; - - rd = tcg_temp_new_i32(); - tmp = tcg_temp_new_i32(); - - tcg_gen_shli_i32(rd, t0, 8); - tcg_gen_andi_i32(rd, rd, 0xff00ff00); - tcg_gen_andi_i32(tmp, t1, 0x00ff00ff); - tcg_gen_or_i32(rd, rd, tmp); - - tcg_gen_shri_i32(t1, t1, 8); - tcg_gen_andi_i32(t1, t1, 0x00ff00ff); - tcg_gen_andi_i32(tmp, t0, 0xff00ff00); - tcg_gen_or_i32(t1, t1, tmp); - tcg_gen_mov_i32(t0, rd); - - tcg_temp_free_i32(tmp); - tcg_temp_free_i32(rd); -} - -static void gen_neon_trn_u16(TCGv_i32 t0, TCGv_i32 t1) -{ - TCGv_i32 rd, tmp; - - rd = tcg_temp_new_i32(); - tmp = tcg_temp_new_i32(); - - tcg_gen_shli_i32(rd, t0, 16); - tcg_gen_andi_i32(tmp, t1, 0xffff); - tcg_gen_or_i32(rd, rd, tmp); - tcg_gen_shri_i32(t1, t1, 16); - tcg_gen_andi_i32(tmp, t0, 0xffff0000); - tcg_gen_or_i32(t1, t1, tmp); - tcg_gen_mov_i32(t0, rd); - - tcg_temp_free_i32(tmp); - tcg_temp_free_i32(rd); -} - -/* Symbolic constants for op fields for Neon 2-register miscellaneous. - * The values correspond to bits [17:16,10:7]; see the ARM ARM DDI0406B - * table A7-13. - */ -#define NEON_2RM_VREV64 0 -#define NEON_2RM_VREV32 1 -#define NEON_2RM_VREV16 2 -#define NEON_2RM_VPADDL 4 -#define NEON_2RM_VPADDL_U 5 -#define NEON_2RM_AESE 6 /* Includes AESD */ -#define NEON_2RM_AESMC 7 /* Includes AESIMC */ -#define NEON_2RM_VCLS 8 -#define NEON_2RM_VCLZ 9 -#define NEON_2RM_VCNT 10 -#define NEON_2RM_VMVN 11 -#define NEON_2RM_VPADAL 12 -#define NEON_2RM_VPADAL_U 13 -#define NEON_2RM_VQABS 14 -#define NEON_2RM_VQNEG 15 -#define NEON_2RM_VCGT0 16 -#define NEON_2RM_VCGE0 17 -#define NEON_2RM_VCEQ0 18 -#define NEON_2RM_VCLE0 19 -#define NEON_2RM_VCLT0 20 -#define NEON_2RM_SHA1H 21 -#define NEON_2RM_VABS 22 -#define NEON_2RM_VNEG 23 -#define NEON_2RM_VCGT0_F 24 -#define NEON_2RM_VCGE0_F 25 -#define NEON_2RM_VCEQ0_F 26 -#define NEON_2RM_VCLE0_F 27 -#define NEON_2RM_VCLT0_F 28 -#define NEON_2RM_VABS_F 30 -#define NEON_2RM_VNEG_F 31 -#define NEON_2RM_VSWP 32 -#define NEON_2RM_VTRN 33 -#define NEON_2RM_VUZP 34 -#define NEON_2RM_VZIP 35 -#define NEON_2RM_VMOVN 36 /* Includes VQMOVN, VQMOVUN */ -#define NEON_2RM_VQMOVN 37 /* Includes VQMOVUN */ -#define NEON_2RM_VSHLL 38 -#define NEON_2RM_SHA1SU1 39 /* Includes SHA256SU0 */ -#define NEON_2RM_VRINTN 40 -#define NEON_2RM_VRINTX 41 -#define NEON_2RM_VRINTA 42 -#define NEON_2RM_VRINTZ 43 -#define NEON_2RM_VCVT_F16_F32 44 -#define NEON_2RM_VRINTM 45 -#define NEON_2RM_VCVT_F32_F16 46 -#define NEON_2RM_VRINTP 47 -#define NEON_2RM_VCVTAU 48 -#define NEON_2RM_VCVTAS 49 -#define NEON_2RM_VCVTNU 50 -#define NEON_2RM_VCVTNS 51 -#define NEON_2RM_VCVTPU 52 -#define NEON_2RM_VCVTPS 53 -#define NEON_2RM_VCVTMU 54 -#define NEON_2RM_VCVTMS 55 -#define NEON_2RM_VRECPE 56 -#define NEON_2RM_VRSQRTE 57 -#define NEON_2RM_VRECPE_F 58 -#define NEON_2RM_VRSQRTE_F 59 -#define NEON_2RM_VCVT_FS 60 -#define NEON_2RM_VCVT_FU 61 -#define NEON_2RM_VCVT_SF 62 -#define NEON_2RM_VCVT_UF 63 - -/* Each entry in this array has bit n set if the insn allows - * size value n (otherwise it will UNDEF). Since unallocated - * op values will have no bits set they always UNDEF. - */ -static const uint8_t neon_2rm_sizes[] = { - [NEON_2RM_VREV64] = 0x7, - [NEON_2RM_VREV32] = 0x3, - [NEON_2RM_VREV16] = 0x1, - [NEON_2RM_VPADDL] = 0x7, - [NEON_2RM_VPADDL_U] = 0x7, - [NEON_2RM_AESE] = 0x1, - [NEON_2RM_AESMC] = 0x1, - [NEON_2RM_VCLS] = 0x7, - [NEON_2RM_VCLZ] = 0x7, - [NEON_2RM_VCNT] = 0x1, - [NEON_2RM_VMVN] = 0x1, - [NEON_2RM_VPADAL] = 0x7, - [NEON_2RM_VPADAL_U] = 0x7, - [NEON_2RM_VQABS] = 0x7, - [NEON_2RM_VQNEG] = 0x7, - [NEON_2RM_VCGT0] = 0x7, - [NEON_2RM_VCGE0] = 0x7, - [NEON_2RM_VCEQ0] = 0x7, - [NEON_2RM_VCLE0] = 0x7, - [NEON_2RM_VCLT0] = 0x7, - [NEON_2RM_SHA1H] = 0x4, - [NEON_2RM_VABS] = 0x7, - [NEON_2RM_VNEG] = 0x7, - [NEON_2RM_VCGT0_F] = 0x4, - [NEON_2RM_VCGE0_F] = 0x4, - [NEON_2RM_VCEQ0_F] = 0x4, - [NEON_2RM_VCLE0_F] = 0x4, - [NEON_2RM_VCLT0_F] = 0x4, - [NEON_2RM_VABS_F] = 0x4, - [NEON_2RM_VNEG_F] = 0x4, - [NEON_2RM_VSWP] = 0x1, - [NEON_2RM_VTRN] = 0x7, - [NEON_2RM_VUZP] = 0x7, - [NEON_2RM_VZIP] = 0x7, - [NEON_2RM_VMOVN] = 0x7, - [NEON_2RM_VQMOVN] = 0x7, - [NEON_2RM_VSHLL] = 0x7, - [NEON_2RM_SHA1SU1] = 0x4, - [NEON_2RM_VRINTN] = 0x4, - [NEON_2RM_VRINTX] = 0x4, - [NEON_2RM_VRINTA] = 0x4, - [NEON_2RM_VRINTZ] = 0x4, - [NEON_2RM_VCVT_F16_F32] = 0x2, - [NEON_2RM_VRINTM] = 0x4, - [NEON_2RM_VCVT_F32_F16] = 0x2, - [NEON_2RM_VRINTP] = 0x4, - [NEON_2RM_VCVTAU] = 0x4, - [NEON_2RM_VCVTAS] = 0x4, - [NEON_2RM_VCVTNU] = 0x4, - [NEON_2RM_VCVTNS] = 0x4, - [NEON_2RM_VCVTPU] = 0x4, - [NEON_2RM_VCVTPS] = 0x4, - [NEON_2RM_VCVTMU] = 0x4, - [NEON_2RM_VCVTMS] = 0x4, - [NEON_2RM_VRECPE] = 0x4, - [NEON_2RM_VRSQRTE] = 0x4, - [NEON_2RM_VRECPE_F] = 0x4, - [NEON_2RM_VRSQRTE_F] = 0x4, - [NEON_2RM_VCVT_FS] = 0x4, - [NEON_2RM_VCVT_FU] = 0x4, - [NEON_2RM_VCVT_SF] = 0x4, - [NEON_2RM_VCVT_UF] = 0x4, -}; - static void gen_gvec_fn3_qc(uint32_t rd_ofs, uint32_t rn_ofs, uint32_t rm_ofs, uint32_t opr_sz, uint32_t max_sz, gen_helper_gvec_3_ptr *fn) @@ -4822,178 +4645,6 @@ void gen_gvec_uaba(unsigned vece, uint32_t rd_ofs, uint32_t rn_ofs, tcg_gen_gvec_3(rd_ofs, rn_ofs, rm_ofs, opr_sz, max_sz, &ops[vece]); } -/* Translate a NEON data processing instruction. Return nonzero if the - instruction is invalid. - We process data in a mixture of 32-bit and 64-bit chunks. - Mostly we use 32-bit chunks so we can use normal scalar instructions. */ - -static int disas_neon_data_insn(DisasContext *s, uint32_t insn) -{ - int op; - int q; - int rd, rm; - int size; - int pass; - int u; - TCGv_i32 tmp, tmp2; - - if (!arm_dc_feature(s, ARM_FEATURE_NEON)) { - return 1; - } - - /* FIXME: this access check should not take precedence over UNDEF - * for invalid encodings; we will generate incorrect syndrome information - * for attempts to execute invalid vfp/neon encodings with FP disabled. - */ - if (s->fp_excp_el) { - gen_exception_insn(s, s->pc_curr, EXCP_UDEF, - syn_simd_access_trap(1, 0xe, false), s->fp_excp_el); - return 0; - } - - if (!s->vfp_enabled) - return 1; - q = (insn & (1 << 6)) != 0; - u = (insn >> 24) & 1; - VFP_DREG_D(rd, insn); - VFP_DREG_M(rm, insn); - size = (insn >> 20) & 3; - - if ((insn & (1 << 23)) == 0) { - /* Three register same length: handled by decodetree */ - return 1; - } else if (insn & (1 << 4)) { - /* Two registers and shift or reg and imm: handled by decodetree */ - return 1; - } else { /* (insn & 0x00800010 == 0x00800000) */ - if (size != 3) { - /* - * Three registers of different lengths, or two registers and - * a scalar: handled by decodetree - */ - return 1; - } else { /* size == 3 */ - if (!u) { - /* Extract: handled by decodetree */ - return 1; - } else if ((insn & (1 << 11)) == 0) { - /* Two register misc. */ - op = ((insn >> 12) & 0x30) | ((insn >> 7) & 0xf); - size = (insn >> 18) & 3; - /* UNDEF for unknown op values and bad op-size combinations */ - if ((neon_2rm_sizes[op] & (1 << size)) == 0) { - return 1; - } - if (q && ((rm | rd) & 1)) { - return 1; - } - switch (op) { - case NEON_2RM_VREV64: - case NEON_2RM_VPADDL: case NEON_2RM_VPADDL_U: - case NEON_2RM_VPADAL: case NEON_2RM_VPADAL_U: - case NEON_2RM_VUZP: - case NEON_2RM_VZIP: - case NEON_2RM_VMOVN: case NEON_2RM_VQMOVN: - case NEON_2RM_VSHLL: - case NEON_2RM_VCVT_F16_F32: - case NEON_2RM_VCVT_F32_F16: - case NEON_2RM_VMVN: - case NEON_2RM_VNEG: - case NEON_2RM_VABS: - case NEON_2RM_VCEQ0: - case NEON_2RM_VCGT0: - case NEON_2RM_VCLE0: - case NEON_2RM_VCGE0: - case NEON_2RM_VCLT0: - case NEON_2RM_AESE: case NEON_2RM_AESMC: - case NEON_2RM_SHA1H: - case NEON_2RM_SHA1SU1: - case NEON_2RM_VREV32: - case NEON_2RM_VREV16: - case NEON_2RM_VCLS: - case NEON_2RM_VCLZ: - case NEON_2RM_VCNT: - case NEON_2RM_VABS_F: - case NEON_2RM_VNEG_F: - case NEON_2RM_VRECPE: - case NEON_2RM_VRSQRTE: - case NEON_2RM_VQABS: - case NEON_2RM_VQNEG: - case NEON_2RM_VRECPE_F: - case NEON_2RM_VRSQRTE_F: - case NEON_2RM_VCVT_FS: - case NEON_2RM_VCVT_FU: - case NEON_2RM_VCVT_SF: - case NEON_2RM_VCVT_UF: - case NEON_2RM_VRINTX: - case NEON_2RM_VCGT0_F: - case NEON_2RM_VCGE0_F: - case NEON_2RM_VCEQ0_F: - case NEON_2RM_VCLE0_F: - case NEON_2RM_VCLT0_F: - case NEON_2RM_VRINTN: - case NEON_2RM_VRINTA: - case NEON_2RM_VRINTM: - case NEON_2RM_VRINTP: - case NEON_2RM_VRINTZ: - case NEON_2RM_VCVTAU: - case NEON_2RM_VCVTAS: - case NEON_2RM_VCVTNU: - case NEON_2RM_VCVTNS: - case NEON_2RM_VCVTPU: - case NEON_2RM_VCVTPS: - case NEON_2RM_VCVTMU: - case NEON_2RM_VCVTMS: - case NEON_2RM_VSWP: - /* handled by decodetree */ - return 1; - case NEON_2RM_VTRN: - if (size == 2) { - int n; - for (n = 0; n < (q ? 4 : 2); n += 2) { - tmp = neon_load_reg(rm, n); - tmp2 = neon_load_reg(rd, n + 1); - neon_store_reg(rm, n, tmp2); - neon_store_reg(rd, n + 1, tmp); - } - } else { - goto elementwise; - } - break; - - default: - elementwise: - for (pass = 0; pass < (q ? 4 : 2); pass++) { - tmp = neon_load_reg(rm, pass); - switch (op) { - case NEON_2RM_VTRN: - tmp2 = neon_load_reg(rd, pass); - switch (size) { - case 0: gen_neon_trn_u8(tmp, tmp2); break; - case 1: gen_neon_trn_u16(tmp, tmp2); break; - default: abort(); - } - neon_store_reg(rm, pass, tmp2); - break; - default: - /* Reserved op values were caught by the - * neon_2rm_sizes[] check earlier. - */ - abort(); - } - neon_store_reg(rd, pass, tmp); - } - break; - } - } else { - /* VTBL, VTBX, VDUP: handled by decodetree */ - return 1; - } - } - } - return 0; -} - static int disas_coproc_insn(DisasContext *s, uint32_t insn) { int cpnum, is64, crn, crm, opc1, opc2, isread, rt, rt2; @@ -8694,13 +8345,6 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) } /* fall back to legacy decoder */ - if (((insn >> 25) & 7) == 1) { - /* NEON Data processing. */ - if (disas_neon_data_insn(s, insn)) { - goto illegal_op; - } - return; - } if ((insn & 0x0e000f00) == 0x0c000100) { if (arm_dc_feature(s, ARM_FEATURE_IWMMXT)) { /* iWMMXt register transfer. */ @@ -8888,11 +8532,8 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn) break; } if (((insn >> 24) & 3) == 3) { - /* Translate into the equivalent ARM encoding. */ - insn = (insn & 0xe2ffffff) | ((insn & (1 << 28)) >> 4) | (1 << 28); - if (disas_neon_data_insn(s, insn)) { - goto illegal_op; - } + /* Neon DP, but failed disas_neon_dp() */ + goto illegal_op; } else if (((insn >> 8) & 0xe) == 10) { /* VFP, but failed disas_vfp. */ goto illegal_op; From 6fb5787898aab6aa04887fed9cf3220dd4c3f36a Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 16 Jun 2020 18:08:44 +0100 Subject: [PATCH 23/42] target/arm: Move some functions used only in translate-neon.inc.c to that file The functions neon_element_offset(), neon_load_element(), neon_load_element64(), neon_store_element() and neon_store_element64() are used only in the translate-neon.inc.c file, so move their definitions there. Since the .inc.c file is #included in translate.c this doesn't make much difference currently, but it's a more logical place to put the functions and it might be helpful if we ever decide to try to make the .inc.c files genuinely separate compilation units. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20200616170844.13318-22-peter.maydell@linaro.org --- target/arm/translate-neon.inc.c | 101 ++++++++++++++++++++++++++++++++ target/arm/translate.c | 101 -------------------------------- 2 files changed, 101 insertions(+), 101 deletions(-) diff --git a/target/arm/translate-neon.inc.c b/target/arm/translate-neon.inc.c index 8cc7f5db54..f6cb921573 100644 --- a/target/arm/translate-neon.inc.c +++ b/target/arm/translate-neon.inc.c @@ -54,6 +54,107 @@ static inline int rsub_8(DisasContext *s, int x) #include "decode-neon-ls.inc.c" #include "decode-neon-shared.inc.c" +/* Return the offset of a 2**SIZE piece of a NEON register, at index ELE, + * where 0 is the least significant end of the register. + */ +static inline long +neon_element_offset(int reg, int element, MemOp size) +{ + int element_size = 1 << size; + int ofs = element * element_size; +#ifdef HOST_WORDS_BIGENDIAN + /* Calculate the offset assuming fully little-endian, + * then XOR to account for the order of the 8-byte units. + */ + if (element_size < 8) { + ofs ^= 8 - element_size; + } +#endif + return neon_reg_offset(reg, 0) + ofs; +} + +static void neon_load_element(TCGv_i32 var, int reg, int ele, MemOp mop) +{ + long offset = neon_element_offset(reg, ele, mop & MO_SIZE); + + switch (mop) { + case MO_UB: + tcg_gen_ld8u_i32(var, cpu_env, offset); + break; + case MO_UW: + tcg_gen_ld16u_i32(var, cpu_env, offset); + break; + case MO_UL: + tcg_gen_ld_i32(var, cpu_env, offset); + break; + default: + g_assert_not_reached(); + } +} + +static void neon_load_element64(TCGv_i64 var, int reg, int ele, MemOp mop) +{ + long offset = neon_element_offset(reg, ele, mop & MO_SIZE); + + switch (mop) { + case MO_UB: + tcg_gen_ld8u_i64(var, cpu_env, offset); + break; + case MO_UW: + tcg_gen_ld16u_i64(var, cpu_env, offset); + break; + case MO_UL: + tcg_gen_ld32u_i64(var, cpu_env, offset); + break; + case MO_Q: + tcg_gen_ld_i64(var, cpu_env, offset); + break; + default: + g_assert_not_reached(); + } +} + +static void neon_store_element(int reg, int ele, MemOp size, TCGv_i32 var) +{ + long offset = neon_element_offset(reg, ele, size); + + switch (size) { + case MO_8: + tcg_gen_st8_i32(var, cpu_env, offset); + break; + case MO_16: + tcg_gen_st16_i32(var, cpu_env, offset); + break; + case MO_32: + tcg_gen_st_i32(var, cpu_env, offset); + break; + default: + g_assert_not_reached(); + } +} + +static void neon_store_element64(int reg, int ele, MemOp size, TCGv_i64 var) +{ + long offset = neon_element_offset(reg, ele, size); + + switch (size) { + case MO_8: + tcg_gen_st8_i64(var, cpu_env, offset); + break; + case MO_16: + tcg_gen_st16_i64(var, cpu_env, offset); + break; + case MO_32: + tcg_gen_st32_i64(var, cpu_env, offset); + break; + case MO_64: + tcg_gen_st_i64(var, cpu_env, offset); + break; + default: + g_assert_not_reached(); + } +} + static bool trans_VCMLA(DisasContext *s, arg_VCMLA *a) { int opr_sz; diff --git a/target/arm/translate.c b/target/arm/translate.c index 581b0b5cde..408fb7a492 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -1133,25 +1133,6 @@ neon_reg_offset (int reg, int n) return vfp_reg_offset(0, sreg); } -/* Return the offset of a 2**SIZE piece of a NEON register, at index ELE, - * where 0 is the least significant end of the register. - */ -static inline long -neon_element_offset(int reg, int element, MemOp size) -{ - int element_size = 1 << size; - int ofs = element * element_size; -#ifdef HOST_WORDS_BIGENDIAN - /* Calculate the offset assuming fully little-endian, - * then XOR to account for the order of the 8-byte units. - */ - if (element_size < 8) { - ofs ^= 8 - element_size; - } -#endif - return neon_reg_offset(reg, 0) + ofs; -} - static TCGv_i32 neon_load_reg(int reg, int pass) { TCGv_i32 tmp = tcg_temp_new_i32(); @@ -1159,94 +1140,12 @@ static TCGv_i32 neon_load_reg(int reg, int pass) return tmp; } -static void neon_load_element(TCGv_i32 var, int reg, int ele, MemOp mop) -{ - long offset = neon_element_offset(reg, ele, mop & MO_SIZE); - - switch (mop) { - case MO_UB: - tcg_gen_ld8u_i32(var, cpu_env, offset); - break; - case MO_UW: - tcg_gen_ld16u_i32(var, cpu_env, offset); - break; - case MO_UL: - tcg_gen_ld_i32(var, cpu_env, offset); - break; - default: - g_assert_not_reached(); - } -} - -static void neon_load_element64(TCGv_i64 var, int reg, int ele, MemOp mop) -{ - long offset = neon_element_offset(reg, ele, mop & MO_SIZE); - - switch (mop) { - case MO_UB: - tcg_gen_ld8u_i64(var, cpu_env, offset); - break; - case MO_UW: - tcg_gen_ld16u_i64(var, cpu_env, offset); - break; - case MO_UL: - tcg_gen_ld32u_i64(var, cpu_env, offset); - break; - case MO_Q: - tcg_gen_ld_i64(var, cpu_env, offset); - break; - default: - g_assert_not_reached(); - } -} - static void neon_store_reg(int reg, int pass, TCGv_i32 var) { tcg_gen_st_i32(var, cpu_env, neon_reg_offset(reg, pass)); tcg_temp_free_i32(var); } -static void neon_store_element(int reg, int ele, MemOp size, TCGv_i32 var) -{ - long offset = neon_element_offset(reg, ele, size); - - switch (size) { - case MO_8: - tcg_gen_st8_i32(var, cpu_env, offset); - break; - case MO_16: - tcg_gen_st16_i32(var, cpu_env, offset); - break; - case MO_32: - tcg_gen_st_i32(var, cpu_env, offset); - break; - default: - g_assert_not_reached(); - } -} - -static void neon_store_element64(int reg, int ele, MemOp size, TCGv_i64 var) -{ - long offset = neon_element_offset(reg, ele, size); - - switch (size) { - case MO_8: - tcg_gen_st8_i64(var, cpu_env, offset); - break; - case MO_16: - tcg_gen_st16_i64(var, cpu_env, offset); - break; - case MO_32: - tcg_gen_st32_i64(var, cpu_env, offset); - break; - case MO_64: - tcg_gen_st_i64(var, cpu_env, offset); - break; - default: - g_assert_not_reached(); - } -} - static inline void neon_load_reg64(TCGv_i64 var, int reg) { tcg_gen_ld_i64(var, cpu_env, vfp_reg_offset(1, reg)); From 55c812b74289863c348449135812027d188f040a Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 19 Jun 2020 18:03:24 +0100 Subject: [PATCH 24/42] target/arm: Remove unnecessary gen_io_end() calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit ba3e7926691ed3 it has been unnecessary for target code to call gen_io_end() after an IO instruction in icount mode; it is sufficient to call gen_io_start() before it and to force the end of the TB. Many now-unnecessary calls to gen_io_end() were removed in commit 9e9b10c6491153b, but some were missed or accidentally added later. Remove unneeded calls from the arm target: * the call in the handling of exception-return-via-LDM is unnecessary, and the code is already forcing end-of-TB * the call in the VFP access check code is more complicated: we weren't ending the TB, so we need to add the code to force that by setting DISAS_UPDATE * the doc comment for ARM_CP_IO doesn't need to mention gen_io_end() any more Signed-off-by: Peter Maydell Reviewed-by: Alex Bennée Reviewed-by: Richard Henderson Reviewed-by: Pavel Dovgalyuk Message-id: 20200619170324.12093-1-peter.maydell@linaro.org --- target/arm/cpu.h | 2 +- target/arm/translate-vfp.inc.c | 7 +++---- target/arm/translate.c | 3 --- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 677584e5da..cf66b8c7fb 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -2334,7 +2334,7 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid) * migration or KVM state synchronization. (Typically this is for "registers" * which are actually used as instructions for cache maintenance and so on.) * IO indicates that this register does I/O and therefore its accesses - * need to be surrounded by gen_io_start()/gen_io_end(). In particular, + * need to be marked with gen_io_start() and also end the TB. In particular, * registers which implement clocks or timers require this. * RAISES_EXC is for when the read or write hook might raise an exception; * the generated code will synchronize the CPU state before calling the hook diff --git a/target/arm/translate-vfp.inc.c b/target/arm/translate-vfp.inc.c index e1a9017598..bf31b18657 100644 --- a/target/arm/translate-vfp.inc.c +++ b/target/arm/translate-vfp.inc.c @@ -119,15 +119,14 @@ static bool full_vfp_access_check(DisasContext *s, bool ignore_vfp_enabled) if (s->v7m_lspact) { /* * Lazy state saving affects external memory and also the NVIC, - * so we must mark it as an IO operation for icount. + * so we must mark it as an IO operation for icount (and cause + * this to be the last insn in the TB). */ if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { + s->base.is_jmp = DISAS_UPDATE; gen_io_start(); } gen_helper_v7m_preserve_fp_state(cpu_env); - if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); - } /* * If the preserve_fp_state helper doesn't throw an exception * then it will clear LSPACT; we don't need to repeat this for diff --git a/target/arm/translate.c b/target/arm/translate.c index 408fb7a492..795964da1f 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -7785,9 +7785,6 @@ static bool do_ldm(DisasContext *s, arg_ldst_block *a, int min_n) gen_io_start(); } gen_helper_cpsr_write_eret(cpu_env, tmp); - if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) { - gen_io_end(); - } tcg_temp_free_i32(tmp); /* Must exit loop to check un-masked IRQs */ s->base.is_jmp = DISAS_EXIT; From ced7e8edb282765685d2ba0206a11f8692d8ec1c Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 19 Jun 2020 18:15:47 +0100 Subject: [PATCH 25/42] target/arm: Remove dead code relating to SABA and UABA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In commit cfdb2c0c95ae9205b0 ("target/arm: Vectorize SABA/UABA") we replaced the old handling of SABA/UABA with a vectorized implementation which returns early rather than falling into the loop-ever-elements code. We forgot to delete the part of the old looping code that did the accumulate step, and Coverity correctly warns (CID 1428955) that this code is now dead. Delete it. Fixes: cfdb2c0c95ae9205b0 Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-id: 20200619171547.29780-1-peter.maydell@linaro.org --- target/arm/translate-a64.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 1204098498..4cef862c41 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -11370,18 +11370,6 @@ static void disas_simd_3same_int(DisasContext *s, uint32_t insn) genfn(tcg_res, tcg_op1, tcg_op2); } - if (opcode == 0xf) { - /* SABA, UABA: accumulating ops */ - static NeonGenTwoOpFn * const fns[3] = { - gen_helper_neon_add_u8, - gen_helper_neon_add_u16, - tcg_gen_add_i32, - }; - - read_vec_element_i32(s, tcg_op1, rd, pass, MO_32); - fns[size](tcg_res, tcg_op1, tcg_res); - } - write_vec_element_i32(s, tcg_res, rd, pass, MO_32); tcg_temp_free_i32(tcg_res); From 69ed08e4c5bb0b9d9ae55219ba5429064b0d272e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 17 Jun 2020 09:25:26 +0200 Subject: [PATCH 26/42] hw/watchdog/cmsdk-apb-watchdog: Add trace event for lock status MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a trace event to see when a guest disable/enable the watchdog. Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200617072539.32686-2-f4bug@amsat.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/watchdog/cmsdk-apb-watchdog.c | 1 + hw/watchdog/trace-events | 1 + 2 files changed, 2 insertions(+) diff --git a/hw/watchdog/cmsdk-apb-watchdog.c b/hw/watchdog/cmsdk-apb-watchdog.c index 1541365914..5bbadadfa6 100644 --- a/hw/watchdog/cmsdk-apb-watchdog.c +++ b/hw/watchdog/cmsdk-apb-watchdog.c @@ -225,6 +225,7 @@ static void cmsdk_apb_watchdog_write(void *opaque, hwaddr offset, break; case A_WDOGLOCK: s->lock = (value != WDOG_UNLOCK_VALUE); + trace_cmsdk_apb_watchdog_lock(s->lock); break; case A_WDOGITCR: if (s->is_luminary) { diff --git a/hw/watchdog/trace-events b/hw/watchdog/trace-events index ab94d7df50..3124ca1f1b 100644 --- a/hw/watchdog/trace-events +++ b/hw/watchdog/trace-events @@ -4,3 +4,4 @@ cmsdk_apb_watchdog_read(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB watchdog read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u" cmsdk_apb_watchdog_write(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB watchdog write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u" cmsdk_apb_watchdog_reset(void) "CMSDK APB watchdog: reset" +cmsdk_apb_watchdog_lock(uint32_t lock) "CMSDK APB watchdog: lock %" PRIu32 From faa1bdfa32547ea616ec554aa807b4e24e30acef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 17 Jun 2020 09:25:27 +0200 Subject: [PATCH 27/42] hw/i2c/versatile_i2c: Add definitions for register addresses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use self-explicit definitions instead of magic values. Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200617072539.32686-3-f4bug@amsat.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/i2c/versatile_i2c.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/hw/i2c/versatile_i2c.c b/hw/i2c/versatile_i2c.c index 1ac2a6f59a..040139d701 100644 --- a/hw/i2c/versatile_i2c.c +++ b/hw/i2c/versatile_i2c.c @@ -24,6 +24,7 @@ #include "qemu/osdep.h" #include "hw/sysbus.h" #include "hw/i2c/bitbang_i2c.h" +#include "hw/registerfields.h" #include "qemu/log.h" #include "qemu/module.h" @@ -40,14 +41,19 @@ typedef struct VersatileI2CState { int in; } VersatileI2CState; +REG32(CONTROL_GET, 0) +REG32(CONTROL_SET, 0) +REG32(CONTROL_CLR, 4) + static uint64_t versatile_i2c_read(void *opaque, hwaddr offset, unsigned size) { VersatileI2CState *s = (VersatileI2CState *)opaque; - if (offset == 0) { + switch (offset) { + case A_CONTROL_SET: return (s->out & 1) | (s->in << 1); - } else { + default: qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%x\n", __func__, (int)offset); return -1; @@ -60,10 +66,10 @@ static void versatile_i2c_write(void *opaque, hwaddr offset, VersatileI2CState *s = (VersatileI2CState *)opaque; switch (offset) { - case 0: + case A_CONTROL_SET: s->out |= value & 3; break; - case 4: + case A_CONTROL_CLR: s->out &= ~value; break; default: From cfcfbae0a1028383d7c084fc4cd3ee958ef78d71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 17 Jun 2020 09:25:28 +0200 Subject: [PATCH 28/42] hw/i2c/versatile_i2c: Add SCL/SDA definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use self-explicit definitions instead of magic values. Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200617072539.32686-4-f4bug@amsat.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/i2c/versatile_i2c.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/hw/i2c/versatile_i2c.c b/hw/i2c/versatile_i2c.c index 040139d701..0ce10a1bcc 100644 --- a/hw/i2c/versatile_i2c.c +++ b/hw/i2c/versatile_i2c.c @@ -45,6 +45,9 @@ REG32(CONTROL_GET, 0) REG32(CONTROL_SET, 0) REG32(CONTROL_CLR, 4) +#define SCL BIT(0) +#define SDA BIT(1) + static uint64_t versatile_i2c_read(void *opaque, hwaddr offset, unsigned size) { @@ -76,8 +79,8 @@ static void versatile_i2c_write(void *opaque, hwaddr offset, qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%x\n", __func__, (int)offset); } - bitbang_i2c_set(&s->bitbang, BITBANG_I2C_SCL, (s->out & 1) != 0); - s->in = bitbang_i2c_set(&s->bitbang, BITBANG_I2C_SDA, (s->out & 2) != 0); + bitbang_i2c_set(&s->bitbang, BITBANG_I2C_SCL, (s->out & SCL) != 0); + s->in = bitbang_i2c_set(&s->bitbang, BITBANG_I2C_SDA, (s->out & SDA) != 0); } static const MemoryRegionOps versatile_i2c_ops = { From f61c3fb56bfad1d76422fa80d18ae5e39a47d61d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 17 Jun 2020 09:25:29 +0200 Subject: [PATCH 29/42] hw/i2c: Add header for ARM SBCon two-wire serial bus interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 'ARM SBCon two-wire serial bus interface' is the official name describing the pair of registers used to bitbanging I2C in the Versatile boards. Make the private VersatileI2CState structure as public ArmSbconI2CState. Add the TYPE_ARM_SBCON_I2C, alias to our current TYPE_VERSATILE_I2C model. Rename the memory region description as 'arm_sbcon_i2c'. Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200617072539.32686-5-f4bug@amsat.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- MAINTAINERS | 1 + hw/i2c/versatile_i2c.c | 17 +++++------------ include/hw/i2c/arm_sbcon_i2c.h | 35 ++++++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 12 deletions(-) create mode 100644 include/hw/i2c/arm_sbcon_i2c.h diff --git a/MAINTAINERS b/MAINTAINERS index f0cb1fd337..f1a74b1dfe 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -842,6 +842,7 @@ M: Peter Maydell L: qemu-arm@nongnu.org S: Maintained F: hw/*/versatile* +F: include/hw/i2c/arm_sbcon_i2c.h F: hw/misc/arm_sysctl.c F: docs/system/arm/versatile.rst diff --git a/hw/i2c/versatile_i2c.c b/hw/i2c/versatile_i2c.c index 0ce10a1bcc..da8cda2ec1 100644 --- a/hw/i2c/versatile_i2c.c +++ b/hw/i2c/versatile_i2c.c @@ -1,5 +1,6 @@ /* - * ARM Versatile I2C controller + * ARM SBCon two-wire serial bus interface (I2C bitbang) + * a.k.a. ARM Versatile I2C controller * * Copyright (c) 2006-2007 CodeSourcery. * Copyright (c) 2012 Oskar Andero @@ -22,24 +23,16 @@ */ #include "qemu/osdep.h" -#include "hw/sysbus.h" -#include "hw/i2c/bitbang_i2c.h" +#include "hw/i2c/arm_sbcon_i2c.h" #include "hw/registerfields.h" #include "qemu/log.h" #include "qemu/module.h" -#define TYPE_VERSATILE_I2C "versatile_i2c" #define VERSATILE_I2C(obj) \ OBJECT_CHECK(VersatileI2CState, (obj), TYPE_VERSATILE_I2C) -typedef struct VersatileI2CState { - SysBusDevice parent_obj; +typedef ArmSbconI2CState VersatileI2CState; - MemoryRegion iomem; - bitbang_i2c_interface bitbang; - int out; - int in; -} VersatileI2CState; REG32(CONTROL_GET, 0) REG32(CONTROL_SET, 0) @@ -99,7 +92,7 @@ static void versatile_i2c_init(Object *obj) bus = i2c_init_bus(dev, "i2c"); bitbang_i2c_init(&s->bitbang, bus); memory_region_init_io(&s->iomem, obj, &versatile_i2c_ops, s, - "versatile_i2c", 0x1000); + "arm_sbcon_i2c", 0x1000); sysbus_init_mmio(sbd, &s->iomem); } diff --git a/include/hw/i2c/arm_sbcon_i2c.h b/include/hw/i2c/arm_sbcon_i2c.h new file mode 100644 index 0000000000..5d96507ab6 --- /dev/null +++ b/include/hw/i2c/arm_sbcon_i2c.h @@ -0,0 +1,35 @@ +/* + * ARM SBCon two-wire serial bus interface (I2C bitbang) + * a.k.a. + * ARM Versatile I2C controller + * + * Copyright (c) 2006-2007 CodeSourcery. + * Copyright (c) 2012 Oskar Andero + * Copyright (C) 2020 Philippe Mathieu-Daudé + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ +#ifndef HW_I2C_ARM_SBCON_H +#define HW_I2C_ARM_SBCON_H + +#include "hw/sysbus.h" +#include "hw/i2c/bitbang_i2c.h" + +#define TYPE_VERSATILE_I2C "versatile_i2c" +#define TYPE_ARM_SBCON_I2C TYPE_VERSATILE_I2C + +#define ARM_SBCON_I2C(obj) \ + OBJECT_CHECK(ArmSbconI2CState, (obj), TYPE_ARM_SBCON_I2C) + +typedef struct ArmSbconI2CState { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + + MemoryRegion iomem; + bitbang_i2c_interface bitbang; + int out; + int in; +} ArmSbconI2CState; + +#endif /* HW_I2C_ARM_SBCON_H */ From 440c9f959d20b83c20c589f614cb14fd0dce4546 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 17 Jun 2020 09:25:30 +0200 Subject: [PATCH 30/42] hw/arm: Use TYPE_VERSATILE_I2C instead of hardcoded string MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By using the TYPE_* definitions for devices, we can: - quickly find where devices are used with 'git-grep' - easily rename a device (one-line change). Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200617072539.32686-6-f4bug@amsat.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/realview.c | 3 ++- hw/arm/versatilepb.c | 3 ++- hw/arm/vexpress.c | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/hw/arm/realview.c b/hw/arm/realview.c index f3c00fe00c..b6c0a1adb9 100644 --- a/hw/arm/realview.c +++ b/hw/arm/realview.c @@ -26,6 +26,7 @@ #include "hw/cpu/a9mpcore.h" #include "hw/intc/realview_gic.h" #include "hw/irq.h" +#include "hw/i2c/arm_sbcon_i2c.h" #define SMP_BOOT_ADDR 0xe0000000 #define SMP_BOOTREG_ADDR 0x10000030 @@ -282,7 +283,7 @@ static void realview_init(MachineState *machine, } } - dev = sysbus_create_simple("versatile_i2c", 0x10002000, NULL); + dev = sysbus_create_simple(TYPE_VERSATILE_I2C, 0x10002000, NULL); i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c"); i2c_create_slave(i2c, "ds1338", 0x68); diff --git a/hw/arm/versatilepb.c b/hw/arm/versatilepb.c index 2ebdcbd8ac..e596b8170f 100644 --- a/hw/arm/versatilepb.c +++ b/hw/arm/versatilepb.c @@ -18,6 +18,7 @@ #include "sysemu/sysemu.h" #include "hw/pci/pci.h" #include "hw/i2c/i2c.h" +#include "hw/i2c/arm_sbcon_i2c.h" #include "hw/irq.h" #include "hw/boards.h" #include "exec/address-spaces.h" @@ -314,7 +315,7 @@ static void versatile_init(MachineState *machine, int board_id) /* Add PL031 Real Time Clock. */ sysbus_create_simple("pl031", 0x101e8000, pic[10]); - dev = sysbus_create_simple("versatile_i2c", 0x10002000, NULL); + dev = sysbus_create_simple(TYPE_VERSATILE_I2C, 0x10002000, NULL); i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c"); i2c_create_slave(i2c, "ds1338", 0x68); diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c index 7ca5d523a4..24d656e653 100644 --- a/hw/arm/vexpress.c +++ b/hw/arm/vexpress.c @@ -42,6 +42,7 @@ #include "hw/char/pl011.h" #include "hw/cpu/a9mpcore.h" #include "hw/cpu/a15mpcore.h" +#include "hw/i2c/arm_sbcon_i2c.h" #define VEXPRESS_BOARD_ID 0x8e0 #define VEXPRESS_FLASH_SIZE (64 * 1024 * 1024) @@ -640,7 +641,7 @@ static void vexpress_common_init(MachineState *machine) sysbus_create_simple("sp804", map[VE_TIMER01], pic[2]); sysbus_create_simple("sp804", map[VE_TIMER23], pic[3]); - dev = sysbus_create_simple("versatile_i2c", map[VE_SERIALDVI], NULL); + dev = sysbus_create_simple(TYPE_VERSATILE_I2C, map[VE_SERIALDVI], NULL); i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c"); i2c_create_slave(i2c, "sii9022", 0x39); From 75ca834136517a48f838537b10318e68abecaed5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 17 Jun 2020 09:25:31 +0200 Subject: [PATCH 31/42] hw/arm/mps2: Document CMSDK/FPGA APB subsystem sections MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200617072539.32686-7-f4bug@amsat.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/mps2.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c index daa55f730b..ee555f919d 100644 --- a/hw/arm/mps2.c +++ b/hw/arm/mps2.c @@ -65,7 +65,9 @@ typedef struct { MemoryRegion blockram_m2; MemoryRegion blockram_m3; MemoryRegion sram; + /* FPGA APB subsystem */ MPS2SCC scc; + /* CMSDK APB subsystem */ CMSDKAPBDualTimer dualtimer; } MPS2MachineState; @@ -299,9 +301,9 @@ static void mps2_common_init(MachineState *machine) g_assert_not_reached(); } + /* CMSDK APB subsystem */ cmsdk_apb_timer_create(0x40000000, qdev_get_gpio_in(armv7m, 8), SYSCLK_FRQ); cmsdk_apb_timer_create(0x40001000, qdev_get_gpio_in(armv7m, 9), SYSCLK_FRQ); - object_initialize_child(OBJECT(mms), "dualtimer", &mms->dualtimer, TYPE_CMSDK_APB_DUALTIMER); qdev_prop_set_uint32(DEVICE(&mms->dualtimer), "pclk-frq", SYSCLK_FRQ); @@ -310,6 +312,7 @@ static void mps2_common_init(MachineState *machine) qdev_get_gpio_in(armv7m, 10)); sysbus_mmio_map(SYS_BUS_DEVICE(&mms->dualtimer), 0, 0x40002000); + /* FPGA APB subsystem */ object_initialize_child(OBJECT(mms), "scc", &mms->scc, TYPE_MPS2_SCC); sccdev = DEVICE(&mms->scc); qdev_prop_set_uint32(sccdev, "scc-cfg4", 0x2); From 90b1b6eff423e1f6dc06b663528ab8d4423fa71f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 17 Jun 2020 09:25:32 +0200 Subject: [PATCH 32/42] hw/arm/mps2: Rename CMSDK AHB peripheral region MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To differenciate with the CMSDK APB peripheral region, rename this region 'CMSDK AHB peripheral region'. Reviewed-by: Peter Maydell Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200617072539.32686-8-f4bug@amsat.org Signed-off-by: Peter Maydell --- hw/arm/mps2.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c index ee555f919d..4fe5cc8622 100644 --- a/hw/arm/mps2.c +++ b/hw/arm/mps2.c @@ -212,10 +212,11 @@ static void mps2_common_init(MachineState *machine) */ create_unimplemented_device("CMSDK APB peripheral region @0x40000000", 0x40000000, 0x00010000); - create_unimplemented_device("CMSDK peripheral region @0x40010000", + create_unimplemented_device("CMSDK AHB peripheral region @0x40010000", 0x40010000, 0x00010000); create_unimplemented_device("Extra peripheral region @0x40020000", 0x40020000, 0x00010000); + create_unimplemented_device("RESERVED 4", 0x40030000, 0x001D0000); create_unimplemented_device("VGA", 0x41000000, 0x0200000); From ecbe51aff923b42b453b85471b000d4daa094fe3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 17 Jun 2020 09:25:33 +0200 Subject: [PATCH 33/42] hw/arm/mps2: Add CMSDK APB watchdog device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We already model the CMSDK APB watchdog device, let's use it! Suggested-by: Peter Maydell Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200617072539.32686-9-f4bug@amsat.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/Kconfig | 1 + hw/arm/mps2.c | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 9afa6eee79..5c8f689b3d 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -405,6 +405,7 @@ config MPS2 select PL080 # DMA controller select SPLIT_IRQ select UNIMP + select CMSDK_APB_WATCHDOG config FSL_IMX7 bool diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c index 4fe5cc8622..f7bef20b40 100644 --- a/hw/arm/mps2.c +++ b/hw/arm/mps2.c @@ -312,6 +312,13 @@ static void mps2_common_init(MachineState *machine) sysbus_connect_irq(SYS_BUS_DEVICE(&mms->dualtimer), 0, qdev_get_gpio_in(armv7m, 10)); sysbus_mmio_map(SYS_BUS_DEVICE(&mms->dualtimer), 0, 0x40002000); + object_initialize_child(OBJECT(mms), "watchdog", &mms->watchdog, + TYPE_CMSDK_APB_WATCHDOG); + qdev_prop_set_uint32(DEVICE(&mms->watchdog), "wdogclk-frq", SYSCLK_FRQ); + sysbus_realize(SYS_BUS_DEVICE(&mms->watchdog), &error_fatal); + sysbus_connect_irq(SYS_BUS_DEVICE(&mms->watchdog), 0, + qdev_get_gpio_in_named(armv7m, "NMI", 0)); + sysbus_mmio_map(SYS_BUS_DEVICE(&mms->watchdog), 0, 0x40008000); /* FPGA APB subsystem */ object_initialize_child(OBJECT(mms), "scc", &mms->scc, TYPE_MPS2_SCC); From bb8fba9c896dd889e36db8346cd90e17476fca02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 17 Jun 2020 09:25:34 +0200 Subject: [PATCH 34/42] hw/arm/mps2: Add CMSDK AHB GPIO peripherals as unimplemented devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Register the GPIO peripherals as unimplemented to better follow their accesses, for example booting Zephyr: ---------------- IN: arm_mps2_pinmux_init 0x00001160: f64f 0231 movw r2, #0xf831 0x00001164: 4b06 ldr r3, [pc, #0x18] 0x00001166: 2000 movs r0, #0 0x00001168: 619a str r2, [r3, #0x18] 0x0000116a: f24c 426f movw r2, #0xc46f 0x0000116e: f503 5380 add.w r3, r3, #0x1000 0x00001172: 619a str r2, [r3, #0x18] 0x00001174: f44f 529e mov.w r2, #0x13c0 0x00001178: f503 5380 add.w r3, r3, #0x1000 0x0000117c: 619a str r2, [r3, #0x18] 0x0000117e: 4770 bx lr cmsdk-ahb-gpio: unimplemented device write (size 4, value 0xf831, offset 0x18) cmsdk-ahb-gpio: unimplemented device write (size 4, value 0xc46f, offset 0x18) cmsdk-ahb-gpio: unimplemented device write (size 4, value 0x13c0, offset 0x18) Reviewed-by: Peter Maydell Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200617072539.32686-10-f4bug@amsat.org Signed-off-by: Peter Maydell --- hw/arm/mps2.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c index f7bef20b40..c66c595d4a 100644 --- a/hw/arm/mps2.c +++ b/hw/arm/mps2.c @@ -113,6 +113,7 @@ static void mps2_common_init(MachineState *machine) MemoryRegion *system_memory = get_system_memory(); MachineClass *mc = MACHINE_GET_CLASS(machine); DeviceState *armv7m, *sccdev; + int i; if (strcmp(machine->cpu_type, mc->default_cpu_type) != 0) { error_report("This board can only be used with CPU %s", @@ -228,7 +229,6 @@ static void mps2_common_init(MachineState *machine) */ Object *orgate; DeviceState *orgate_dev; - int i; orgate = object_new(TYPE_OR_IRQ); object_property_set_int(orgate, 6, "num-lines", &error_fatal); @@ -265,7 +265,6 @@ static void mps2_common_init(MachineState *machine) */ Object *orgate; DeviceState *orgate_dev; - int i; orgate = object_new(TYPE_OR_IRQ); object_property_set_int(orgate, 10, "num-lines", &error_fatal); @@ -301,6 +300,11 @@ static void mps2_common_init(MachineState *machine) default: g_assert_not_reached(); } + for (i = 0; i < 4; i++) { + static const hwaddr gpiobase[] = {0x40010000, 0x40011000, + 0x40012000, 0x40013000}; + create_unimplemented_device("cmsdk-ahb-gpio", gpiobase[i], 0x1000); + } /* CMSDK APB subsystem */ cmsdk_apb_timer_create(0x40000000, qdev_get_gpio_in(armv7m, 8), SYSCLK_FRQ); From adbb23b6a88341fa66a8cfaebedeeadd9a7ac891 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 17 Jun 2020 09:25:35 +0200 Subject: [PATCH 35/42] hw/arm/mps2: Map the FPGA I/O block MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200617072539.32686-11-f4bug@amsat.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/mps2.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c index c66c595d4a..e106123225 100644 --- a/hw/arm/mps2.c +++ b/hw/arm/mps2.c @@ -38,8 +38,10 @@ #include "hw/timer/cmsdk-apb-timer.h" #include "hw/timer/cmsdk-apb-dualtimer.h" #include "hw/misc/mps2-scc.h" +#include "hw/misc/mps2-fpgaio.h" #include "hw/net/lan9118.h" #include "net/net.h" +#include "hw/watchdog/cmsdk-apb-watchdog.h" typedef enum MPS2FPGAType { FPGA_AN385, @@ -67,8 +69,10 @@ typedef struct { MemoryRegion sram; /* FPGA APB subsystem */ MPS2SCC scc; + MPS2FPGAIO fpgaio; /* CMSDK APB subsystem */ CMSDKAPBDualTimer dualtimer; + CMSDKAPBWatchdog watchdog; } MPS2MachineState; #define TYPE_MPS2_MACHINE "mps2" @@ -332,6 +336,11 @@ static void mps2_common_init(MachineState *machine) qdev_prop_set_uint32(sccdev, "scc-id", mmc->scc_id); sysbus_realize(SYS_BUS_DEVICE(&mms->scc), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(sccdev), 0, 0x4002f000); + object_initialize_child(OBJECT(mms), "fpgaio", + &mms->fpgaio, TYPE_MPS2_FPGAIO); + qdev_prop_set_uint32(DEVICE(&mms->fpgaio), "prescale-clk", 25000000); + sysbus_realize(SYS_BUS_DEVICE(&mms->fpgaio), &error_fatal); + sysbus_mmio_map(SYS_BUS_DEVICE(&mms->fpgaio), 0, 0x40028000); /* In hardware this is a LAN9220; the LAN9118 is software compatible * except that it doesn't support the checksum-offload feature. From 58f7f3c4526ce90accc87006531e12971a366f67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 17 Jun 2020 09:25:36 +0200 Subject: [PATCH 36/42] hw/arm/mps2: Add SPI devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From 'Application Note AN385', chapter 3.9, SPI: The SMM implements five PL022 SPI modules. Two pairs of modules share the same OR-gated IRQ. Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200617072539.32686-12-f4bug@amsat.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/Kconfig | 6 +++--- hw/arm/mps2.c | 24 ++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 5c8f689b3d..90ed584e7a 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -59,7 +59,7 @@ config HIGHBANK select ARM_TIMER # sp804 select ARM_V7M select PL011 # UART - select PL022 # Serial port + select PL022 # SPI select PL031 # RTC select PL061 # GPIO select PL310 # cache controller @@ -222,7 +222,7 @@ config STELLARIS select CMSDK_APB_WATCHDOG select I2C select PL011 # UART - select PL022 # Serial port + select PL022 # SPI select PL061 # GPIO select SSD0303 # OLED display select SSD0323 # OLED display @@ -401,7 +401,7 @@ config MPS2 select MPS2_FPGAIO select MPS2_SCC select OR_IRQ - select PL022 # Serial port + select PL022 # SPI select PL080 # DMA controller select SPLIT_IRQ select UNIMP diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c index e106123225..daa26f68d7 100644 --- a/hw/arm/mps2.c +++ b/hw/arm/mps2.c @@ -39,6 +39,7 @@ #include "hw/timer/cmsdk-apb-dualtimer.h" #include "hw/misc/mps2-scc.h" #include "hw/misc/mps2-fpgaio.h" +#include "hw/ssi/pl022.h" #include "hw/net/lan9118.h" #include "net/net.h" #include "hw/watchdog/cmsdk-apb-watchdog.h" @@ -341,6 +342,29 @@ static void mps2_common_init(MachineState *machine) qdev_prop_set_uint32(DEVICE(&mms->fpgaio), "prescale-clk", 25000000); sysbus_realize(SYS_BUS_DEVICE(&mms->fpgaio), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(&mms->fpgaio), 0, 0x40028000); + sysbus_create_simple(TYPE_PL022, 0x40025000, /* External ADC */ + qdev_get_gpio_in(armv7m, 22)); + for (i = 0; i < 2; i++) { + static const int spi_irqno[] = {11, 24}; + static const hwaddr spibase[] = {0x40020000, /* APB */ + 0x40021000, /* LCD */ + 0x40026000, /* Shield0 */ + 0x40027000}; /* Shield1 */ + DeviceState *orgate_dev; + Object *orgate; + int j; + + orgate = object_new(TYPE_OR_IRQ); + object_property_set_int(orgate, 2, "num-lines", &error_fatal); + orgate_dev = DEVICE(orgate); + qdev_realize(orgate_dev, NULL, &error_fatal); + qdev_connect_gpio_out(orgate_dev, 0, + qdev_get_gpio_in(armv7m, spi_irqno[i])); + for (j = 0; j < 2; j++) { + sysbus_create_simple(TYPE_PL022, spibase[2 * i + j], + qdev_get_gpio_in(orgate_dev, j)); + } + } /* In hardware this is a LAN9220; the LAN9118 is software compatible * except that it doesn't support the checksum-offload feature. From ada45de9ea67b814a879a6151361c50122326e76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 17 Jun 2020 09:25:37 +0200 Subject: [PATCH 37/42] hw/arm/mps2: Add I2C devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From 'Application Note AN385', chapter 3.14: The SMM implements a simple SBCon interface based on I2C. There are 4 SBCon interfaces on the FPGA APB subsystem. Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200617072539.32686-13-f4bug@amsat.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/Kconfig | 1 + hw/arm/mps2.c | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 90ed584e7a..4a224a6351 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -406,6 +406,7 @@ config MPS2 select SPLIT_IRQ select UNIMP select CMSDK_APB_WATCHDOG + select VERSATILE_I2C config FSL_IMX7 bool diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c index daa26f68d7..2f6acbf2c2 100644 --- a/hw/arm/mps2.c +++ b/hw/arm/mps2.c @@ -40,6 +40,7 @@ #include "hw/misc/mps2-scc.h" #include "hw/misc/mps2-fpgaio.h" #include "hw/ssi/pl022.h" +#include "hw/i2c/arm_sbcon_i2c.h" #include "hw/net/lan9118.h" #include "net/net.h" #include "hw/watchdog/cmsdk-apb-watchdog.h" @@ -365,6 +366,13 @@ static void mps2_common_init(MachineState *machine) qdev_get_gpio_in(orgate_dev, j)); } } + for (i = 0; i < 4; i++) { + static const hwaddr i2cbase[] = {0x40022000, /* Touch */ + 0x40023000, /* Audio */ + 0x40029000, /* Shield0 */ + 0x4002a000}; /* Shield1 */ + sysbus_create_simple(TYPE_ARM_SBCON_I2C, i2cbase[i], NULL); + } /* In hardware this is a LAN9220; the LAN9118 is software compatible * except that it doesn't support the checksum-offload feature. From 7b465641ed6fd037f577666c0edd5d389ae39696 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 17 Jun 2020 09:25:38 +0200 Subject: [PATCH 38/42] hw/arm/mps2: Add audio I2S interface as unimplemented device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200617072539.32686-14-f4bug@amsat.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/mps2.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c index 2f6acbf2c2..d1653a7e6e 100644 --- a/hw/arm/mps2.c +++ b/hw/arm/mps2.c @@ -373,6 +373,7 @@ static void mps2_common_init(MachineState *machine) 0x4002a000}; /* Shield1 */ sysbus_create_simple(TYPE_ARM_SBCON_I2C, i2cbase[i], NULL); } + create_unimplemented_device("i2s", 0x40024000, 0x400); /* In hardware this is a LAN9220; the LAN9118 is software compatible * except that it doesn't support the checksum-offload feature. From 2e34818f08d28812e8efa319a4db36668348ac9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 17 Jun 2020 09:25:39 +0200 Subject: [PATCH 39/42] hw/arm/mps2-tz: Use the ARM SBCon two-wire serial bus interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From 'Application Note AN521', chapter 4.7: The SMM implements four SBCon serial modules: One SBCon module for use by the Color LCD touch interface. One SBCon module to configure the audio controller. Two general purpose SBCon modules, that connect to the Expansion headers J7 and J8, are intended for use with the V2C-Shield1 which provide an I2C interface on the headers. Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200617072539.32686-15-f4bug@amsat.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/mps2-tz.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c index 8155c35418..a4fd5ddede 100644 --- a/hw/arm/mps2-tz.c +++ b/hw/arm/mps2-tz.c @@ -58,6 +58,7 @@ #include "hw/arm/armsse.h" #include "hw/dma/pl080.h" #include "hw/ssi/pl022.h" +#include "hw/i2c/arm_sbcon_i2c.h" #include "hw/net/lan9118.h" #include "net/net.h" #include "hw/core/split-irq.h" @@ -87,7 +88,7 @@ typedef struct { TZPPC ppc[5]; TZMPC ssram_mpc[3]; PL022State spi[5]; - UnimplementedDeviceState i2c[4]; + ArmSbconI2CState i2c[4]; UnimplementedDeviceState i2s_audio; UnimplementedDeviceState gpio[4]; UnimplementedDeviceState gfx; @@ -365,6 +366,18 @@ static MemoryRegion *make_spi(MPS2TZMachineState *mms, void *opaque, return sysbus_mmio_get_region(s, 0); } +static MemoryRegion *make_i2c(MPS2TZMachineState *mms, void *opaque, + const char *name, hwaddr size) +{ + ArmSbconI2CState *i2c = opaque; + SysBusDevice *s; + + object_initialize_child(OBJECT(mms), name, i2c, TYPE_ARM_SBCON_I2C); + s = SYS_BUS_DEVICE(i2c); + sysbus_realize(s, &error_fatal); + return sysbus_mmio_get_region(s, 0); +} + static void mps2tz_common_init(MachineState *machine) { MPS2TZMachineState *mms = MPS2TZ_MACHINE(machine); @@ -499,10 +512,10 @@ static void mps2tz_common_init(MachineState *machine) { "uart2", make_uart, &mms->uart[2], 0x40202000, 0x1000 }, { "uart3", make_uart, &mms->uart[3], 0x40203000, 0x1000 }, { "uart4", make_uart, &mms->uart[4], 0x40204000, 0x1000 }, - { "i2c0", make_unimp_dev, &mms->i2c[0], 0x40207000, 0x1000 }, - { "i2c1", make_unimp_dev, &mms->i2c[1], 0x40208000, 0x1000 }, - { "i2c2", make_unimp_dev, &mms->i2c[2], 0x4020c000, 0x1000 }, - { "i2c3", make_unimp_dev, &mms->i2c[3], 0x4020d000, 0x1000 }, + { "i2c0", make_i2c, &mms->i2c[0], 0x40207000, 0x1000 }, + { "i2c1", make_i2c, &mms->i2c[1], 0x40208000, 0x1000 }, + { "i2c2", make_i2c, &mms->i2c[2], 0x4020c000, 0x1000 }, + { "i2c3", make_i2c, &mms->i2c[3], 0x4020d000, 0x1000 }, }, }, { .name = "apb_ppcexp2", From 7d20e6815bf5ab678a55673224340b39218be510 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 23 Jun 2020 11:06:22 +0200 Subject: [PATCH 40/42] target/arm: Check supported KVM features globally (not per vCPU) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit d70c996df23f, when enabling the PMU we get: $ qemu-system-aarch64 -cpu host,pmu=on -M virt,accel=kvm,gic-version=3 Segmentation fault (core dumped) Thread 1 "qemu-system-aar" received signal SIGSEGV, Segmentation fault. 0x0000aaaaaae356d0 in kvm_ioctl (s=0x0, type=44547) at accel/kvm/kvm-all.c:2588 2588 ret = ioctl(s->fd, type, arg); (gdb) bt #0 0x0000aaaaaae356d0 in kvm_ioctl (s=0x0, type=44547) at accel/kvm/kvm-all.c:2588 #1 0x0000aaaaaae31568 in kvm_check_extension (s=0x0, extension=126) at accel/kvm/kvm-all.c:916 #2 0x0000aaaaaafce254 in kvm_arm_pmu_supported (cpu=0xaaaaac214ab0) at target/arm/kvm.c:213 #3 0x0000aaaaaafc0f94 in arm_set_pmu (obj=0xaaaaac214ab0, value=true, errp=0xffffffffe438) at target/arm/cpu.c:1111 #4 0x0000aaaaab5533ac in property_set_bool (obj=0xaaaaac214ab0, v=0xaaaaac223a80, name=0xaaaaac11a970 "pmu", opaque=0xaaaaac222730, errp=0xffffffffe438) at qom/object.c:2170 #5 0x0000aaaaab5512f0 in object_property_set (obj=0xaaaaac214ab0, v=0xaaaaac223a80, name=0xaaaaac11a970 "pmu", errp=0xffffffffe438) at qom/object.c:1328 #6 0x0000aaaaab551e10 in object_property_parse (obj=0xaaaaac214ab0, string=0xaaaaac11b4c0 "on", name=0xaaaaac11a970 "pmu", errp=0xffffffffe438) at qom/object.c:1561 #7 0x0000aaaaab54ee8c in object_apply_global_props (obj=0xaaaaac214ab0, props=0xaaaaac018e20, errp=0xaaaaabd6fd88 ) at qom/object.c:407 #8 0x0000aaaaab1dd5a4 in qdev_prop_set_globals (dev=0xaaaaac214ab0) at hw/core/qdev-properties.c:1218 #9 0x0000aaaaab1d9fac in device_post_init (obj=0xaaaaac214ab0) at hw/core/qdev.c:1050 ... #15 0x0000aaaaab54f310 in object_initialize_with_type (obj=0xaaaaac214ab0, size=52208, type=0xaaaaabe237f0) at qom/object.c:512 #16 0x0000aaaaab54fa24 in object_new_with_type (type=0xaaaaabe237f0) at qom/object.c:687 #17 0x0000aaaaab54fa80 in object_new (typename=0xaaaaabe23970 "host-arm-cpu") at qom/object.c:702 #18 0x0000aaaaaaf04a74 in machvirt_init (machine=0xaaaaac0a8550) at hw/arm/virt.c:1770 #19 0x0000aaaaab1e8720 in machine_run_board_init (machine=0xaaaaac0a8550) at hw/core/machine.c:1138 #20 0x0000aaaaaaf95394 in qemu_init (argc=5, argv=0xffffffffea58, envp=0xffffffffea88) at softmmu/vl.c:4348 #21 0x0000aaaaaada3f74 in main (argc=, argv=, envp=) at softmmu/main.c:48 This is because in frame #2, cpu->kvm_state is still NULL (the vCPU is not yet realized). KVM has a hard requirement of all cores supporting the same feature set. We only need to check if the accelerator supports a feature, not each vCPU individually. Fix by removing the 'CPUState *cpu' argument from the kvm_arm__supported() functions. Fixes: d70c996df23f ('Use CPUState::kvm_state in kvm_arm_pmu_supported') Reported-by: Haibo Xu Reviewed-by: Andrew Jones Acked-by: Paolo Bonzini Signed-off-by: Philippe Mathieu-Daudé Suggested-by: Paolo Bonzini Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Peter Maydell --- target/arm/cpu.c | 2 +- target/arm/cpu64.c | 10 +++++----- target/arm/kvm.c | 4 ++-- target/arm/kvm64.c | 14 +++++--------- target/arm/kvm_arm.h | 21 +++++++++------------ 5 files changed, 22 insertions(+), 29 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 5b7a36b5d7..e44e18062c 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -1108,7 +1108,7 @@ static void arm_set_pmu(Object *obj, bool value, Error **errp) ARMCPU *cpu = ARM_CPU(obj); if (value) { - if (kvm_enabled() && !kvm_arm_pmu_supported(CPU(cpu))) { + if (kvm_enabled() && !kvm_arm_pmu_supported()) { error_setg(errp, "'pmu' feature not supported by KVM on this host"); return; } diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 778cecc2e6..a0c1d8894b 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -266,7 +266,7 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) /* Collect the set of vector lengths supported by KVM. */ bitmap_zero(kvm_supported, ARM_MAX_VQ); - if (kvm_enabled() && kvm_arm_sve_supported(CPU(cpu))) { + if (kvm_enabled() && kvm_arm_sve_supported()) { kvm_arm_sve_get_vls(CPU(cpu), kvm_supported); } else if (kvm_enabled()) { assert(!cpu_isar_feature(aa64_sve, cpu)); @@ -473,7 +473,7 @@ static void cpu_max_set_sve_max_vq(Object *obj, Visitor *v, const char *name, return; } - if (kvm_enabled() && !kvm_arm_sve_supported(CPU(cpu))) { + if (kvm_enabled() && !kvm_arm_sve_supported()) { error_setg(errp, "cannot set sve-max-vq"); error_append_hint(errp, "SVE not supported by KVM on this host\n"); return; @@ -519,7 +519,7 @@ static void cpu_arm_set_sve_vq(Object *obj, Visitor *v, const char *name, return; } - if (value && kvm_enabled() && !kvm_arm_sve_supported(CPU(cpu))) { + if (value && kvm_enabled() && !kvm_arm_sve_supported()) { error_setg(errp, "cannot enable %s", name); error_append_hint(errp, "SVE not supported by KVM on this host\n"); return; @@ -556,7 +556,7 @@ static void cpu_arm_set_sve(Object *obj, Visitor *v, const char *name, return; } - if (value && kvm_enabled() && !kvm_arm_sve_supported(CPU(cpu))) { + if (value && kvm_enabled() && !kvm_arm_sve_supported()) { error_setg(errp, "'sve' feature not supported by KVM on this host"); return; } @@ -751,7 +751,7 @@ static void aarch64_cpu_set_aarch64(Object *obj, bool value, Error **errp) * uniform execution state like do_interrupt. */ if (value == false) { - if (!kvm_enabled() || !kvm_arm_aarch32_supported(CPU(cpu))) { + if (!kvm_enabled() || !kvm_arm_aarch32_supported()) { error_setg(errp, "'aarch64' feature cannot be disabled " "unless KVM is enabled and 32-bit EL1 " "is supported"); diff --git a/target/arm/kvm.c b/target/arm/kvm.c index eef3bbd1cc..7c672c78b8 100644 --- a/target/arm/kvm.c +++ b/target/arm/kvm.c @@ -208,9 +208,9 @@ void kvm_arm_add_vcpu_properties(Object *obj) } } -bool kvm_arm_pmu_supported(CPUState *cpu) +bool kvm_arm_pmu_supported(void) { - return kvm_check_extension(cpu->kvm_state, KVM_CAP_ARM_PMU_V3); + return kvm_check_extension(kvm_state, KVM_CAP_ARM_PMU_V3); } int kvm_arm_get_max_vm_ipa_size(MachineState *ms) diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c index f09ed9f4df..3dc494aaa7 100644 --- a/target/arm/kvm64.c +++ b/target/arm/kvm64.c @@ -652,18 +652,14 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf) return true; } -bool kvm_arm_aarch32_supported(CPUState *cpu) +bool kvm_arm_aarch32_supported(void) { - KVMState *s = KVM_STATE(current_accel()); - - return kvm_check_extension(s, KVM_CAP_ARM_EL1_32BIT); + return kvm_check_extension(kvm_state, KVM_CAP_ARM_EL1_32BIT); } -bool kvm_arm_sve_supported(CPUState *cpu) +bool kvm_arm_sve_supported(void) { - KVMState *s = KVM_STATE(current_accel()); - - return kvm_check_extension(s, KVM_CAP_ARM_SVE); + return kvm_check_extension(kvm_state, KVM_CAP_ARM_SVE); } QEMU_BUILD_BUG_ON(KVM_ARM64_SVE_VQ_MIN != 1); @@ -798,7 +794,7 @@ int kvm_arch_init_vcpu(CPUState *cs) env->features &= ~(1ULL << ARM_FEATURE_PMU); } if (cpu_isar_feature(aa64_sve, cpu)) { - assert(kvm_arm_sve_supported(cs)); + assert(kvm_arm_sve_supported()); cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_SVE; } diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h index 48bf5e16d5..a4ce4fd93d 100644 --- a/target/arm/kvm_arm.h +++ b/target/arm/kvm_arm.h @@ -269,29 +269,26 @@ void kvm_arm_add_vcpu_properties(Object *obj); /** * kvm_arm_aarch32_supported: - * @cs: CPUState * - * Returns: true if the KVM VCPU can enable AArch32 mode + * Returns: true if KVM can enable AArch32 mode * and false otherwise. */ -bool kvm_arm_aarch32_supported(CPUState *cs); +bool kvm_arm_aarch32_supported(void); /** * kvm_arm_pmu_supported: - * @cs: CPUState * - * Returns: true if the KVM VCPU can enable its PMU + * Returns: true if KVM can enable the PMU * and false otherwise. */ -bool kvm_arm_pmu_supported(CPUState *cs); +bool kvm_arm_pmu_supported(void); /** * kvm_arm_sve_supported: - * @cs: CPUState * - * Returns true if the KVM VCPU can enable SVE and false otherwise. + * Returns true if KVM can enable SVE and false otherwise. */ -bool kvm_arm_sve_supported(CPUState *cs); +bool kvm_arm_sve_supported(void); /** * kvm_arm_get_max_vm_ipa_size: @@ -359,17 +356,17 @@ static inline void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu) static inline void kvm_arm_add_vcpu_properties(Object *obj) {} -static inline bool kvm_arm_aarch32_supported(CPUState *cs) +static inline bool kvm_arm_aarch32_supported(void) { return false; } -static inline bool kvm_arm_pmu_supported(CPUState *cs) +static inline bool kvm_arm_pmu_supported(void) { return false; } -static inline bool kvm_arm_sve_supported(CPUState *cs) +static inline bool kvm_arm_sve_supported(void) { return false; } From 92a70997ad6dcff865b0071475a878a4fa478da5 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 23 Jun 2020 11:06:21 +0200 Subject: [PATCH 41/42] tests/qtest/arm-cpu-features: Add feature setting tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some cpu features may be enabled and disabled for all configurations that support the feature. Let's test that. A recent regression[*] inspired adding these tests. [*] '-cpu host,pmu=on' caused a segfault Signed-off-by: Andrew Jones Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200623090622.30365-2-philmd@redhat.com Message-Id: <20200623082310.17577-1-drjones@redhat.com> Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- tests/qtest/arm-cpu-features.c | 38 ++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/tests/qtest/arm-cpu-features.c b/tests/qtest/arm-cpu-features.c index 4692173676..f7e062c189 100644 --- a/tests/qtest/arm-cpu-features.c +++ b/tests/qtest/arm-cpu-features.c @@ -159,16 +159,35 @@ static bool resp_get_feature(QDict *resp, const char *feature) qobject_unref(_resp); \ }) -#define assert_feature(qts, cpu_type, feature, expected_value) \ +#define resp_assert_feature(resp, feature, expected_value) \ ({ \ - QDict *_resp, *_props; \ + QDict *_props; \ \ - _resp = do_query_no_props(qts, cpu_type); \ g_assert(_resp); \ g_assert(resp_has_props(_resp)); \ _props = resp_get_props(_resp); \ g_assert(qdict_get(_props, feature)); \ g_assert(qdict_get_bool(_props, feature) == (expected_value)); \ +}) + +#define assert_feature(qts, cpu_type, feature, expected_value) \ +({ \ + QDict *_resp; \ + \ + _resp = do_query_no_props(qts, cpu_type); \ + g_assert(_resp); \ + resp_assert_feature(_resp, feature, expected_value); \ + qobject_unref(_resp); \ +}) + +#define assert_set_feature(qts, cpu_type, feature, value) \ +({ \ + const char *_fmt = (value) ? "{ %s: true }" : "{ %s: false }"; \ + QDict *_resp; \ + \ + _resp = do_query(qts, cpu_type, _fmt, feature); \ + g_assert(_resp); \ + resp_assert_feature(_resp, feature, value); \ qobject_unref(_resp); \ }) @@ -424,10 +443,14 @@ static void test_query_cpu_model_expansion(const void *data) assert_error(qts, "host", "The CPU type 'host' requires KVM", NULL); /* Test expected feature presence/absence for some cpu types */ - assert_has_feature_enabled(qts, "max", "pmu"); assert_has_feature_enabled(qts, "cortex-a15", "pmu"); assert_has_not_feature(qts, "cortex-a15", "aarch64"); + /* Enabling and disabling pmu should always work. */ + assert_has_feature_enabled(qts, "max", "pmu"); + assert_set_feature(qts, "max", "pmu", false); + assert_set_feature(qts, "max", "pmu", true); + assert_has_not_feature(qts, "max", "kvm-no-adjvtime"); if (g_str_equal(qtest_get_arch(), "aarch64")) { @@ -464,7 +487,10 @@ static void test_query_cpu_model_expansion_kvm(const void *data) return; } + /* Enabling and disabling kvm-no-adjvtime should always work. */ assert_has_feature_disabled(qts, "host", "kvm-no-adjvtime"); + assert_set_feature(qts, "host", "kvm-no-adjvtime", true); + assert_set_feature(qts, "host", "kvm-no-adjvtime", false); if (g_str_equal(qtest_get_arch(), "aarch64")) { bool kvm_supports_sve; @@ -475,7 +501,11 @@ static void test_query_cpu_model_expansion_kvm(const void *data) char *error; assert_has_feature_enabled(qts, "host", "aarch64"); + + /* Enabling and disabling pmu should always work. */ assert_has_feature_enabled(qts, "host", "pmu"); + assert_set_feature(qts, "host", "pmu", false); + assert_set_feature(qts, "host", "pmu", true); assert_error(qts, "cortex-a15", "We cannot guarantee the CPU type 'cortex-a15' works " From 539533b85fbd269f777bed931de8ccae1dd837e9 Mon Sep 17 00:00:00 2001 From: Shameer Kolothum Date: Mon, 22 Jun 2020 13:41:57 +0100 Subject: [PATCH 42/42] arm/virt: Add memory hot remove support This adds support for memory(pc-dimm) hot remove on arm/virt that uses acpi ged device. NVDIMM hot removal is not yet supported. Signed-off-by: Shameer Kolothum Message-id: 20200622124157.20360-1-shameerali.kolothum.thodi@huawei.com Reviewed-by: Eric Auger Tested-by: Eric Auger Signed-off-by: Peter Maydell --- hw/acpi/generic_event_device.c | 29 ++++++++++++++++ hw/arm/virt.c | 62 ++++++++++++++++++++++++++++++++-- 2 files changed, 89 insertions(+), 2 deletions(-) diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c index 1cb34111e5..b8abdefa1c 100644 --- a/hw/acpi/generic_event_device.c +++ b/hw/acpi/generic_event_device.c @@ -193,6 +193,33 @@ static void acpi_ged_device_plug_cb(HotplugHandler *hotplug_dev, } } +static void acpi_ged_unplug_request_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + AcpiGedState *s = ACPI_GED(hotplug_dev); + + if ((object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) && + !(object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)))) { + acpi_memory_unplug_request_cb(hotplug_dev, &s->memhp_state, dev, errp); + } else { + error_setg(errp, "acpi: device unplug request for unsupported device" + " type: %s", object_get_typename(OBJECT(dev))); + } +} + +static void acpi_ged_unplug_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + AcpiGedState *s = ACPI_GED(hotplug_dev); + + if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { + acpi_memory_unplug_cb(&s->memhp_state, dev, errp); + } else { + error_setg(errp, "acpi: device unplug for unsupported device" + " type: %s", object_get_typename(OBJECT(dev))); + } +} + static void acpi_ged_send_event(AcpiDeviceIf *adev, AcpiEventStatusBits ev) { AcpiGedState *s = ACPI_GED(adev); @@ -318,6 +345,8 @@ static void acpi_ged_class_init(ObjectClass *class, void *data) dc->vmsd = &vmstate_acpi_ged; hc->plug = acpi_ged_device_plug_cb; + hc->unplug_request = acpi_ged_unplug_request_cb; + hc->unplug = acpi_ged_unplug_cb; adevc->send_event = acpi_ged_send_event; } diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 8b6e6aa7b1..402c362c14 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -2177,11 +2177,68 @@ static void virt_machine_device_plug_cb(HotplugHandler *hotplug_dev, } } +static void virt_dimm_unplug_request(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + VirtMachineState *vms = VIRT_MACHINE(hotplug_dev); + Error *local_err = NULL; + + if (!vms->acpi_dev) { + error_setg(&local_err, + "memory hotplug is not enabled: missing acpi-ged device"); + goto out; + } + + if (object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)) { + error_setg(&local_err, + "nvdimm device hot unplug is not supported yet."); + goto out; + } + + hotplug_handler_unplug_request(HOTPLUG_HANDLER(vms->acpi_dev), dev, + &local_err); +out: + error_propagate(errp, local_err); +} + +static void virt_dimm_unplug(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + VirtMachineState *vms = VIRT_MACHINE(hotplug_dev); + Error *local_err = NULL; + + hotplug_handler_unplug(HOTPLUG_HANDLER(vms->acpi_dev), dev, &local_err); + if (local_err) { + goto out; + } + + pc_dimm_unplug(PC_DIMM(dev), MACHINE(vms)); + qdev_unrealize(dev); + +out: + error_propagate(errp, local_err); +} + static void virt_machine_device_unplug_request_cb(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { - error_setg(errp, "device unplug request for unsupported device" - " type: %s", object_get_typename(OBJECT(dev))); + if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { + virt_dimm_unplug_request(hotplug_dev, dev, errp); + } else { + error_setg(errp, "device unplug request for unsupported device" + " type: %s", object_get_typename(OBJECT(dev))); + } +} + +static void virt_machine_device_unplug_cb(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { + virt_dimm_unplug(hotplug_dev, dev, errp); + } else { + error_setg(errp, "virt: device unplug for unsupported device" + " type: %s", object_get_typename(OBJECT(dev))); + } } static HotplugHandler *virt_machine_get_hotplug_handler(MachineState *machine, @@ -2262,6 +2319,7 @@ static void virt_machine_class_init(ObjectClass *oc, void *data) hc->pre_plug = virt_machine_device_pre_plug_cb; hc->plug = virt_machine_device_plug_cb; hc->unplug_request = virt_machine_device_unplug_request_cb; + hc->unplug = virt_machine_device_unplug_cb; mc->numa_mem_supported = true; mc->nvdimm_supported = true; mc->auto_enable_numa_with_memhp = true;