diff --git a/qemu/target/arm/translate.c b/qemu/target/arm/translate.c index 201b6a71..6aec2b6f 100644 --- a/qemu/target/arm/translate.c +++ b/qemu/target/arm/translate.c @@ -62,6 +62,10 @@ static const char *regnames[] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "pc" }; +/* Function prototypes for gen_ functions calling Neon helpers. */ +typedef void NeonGenThreeOpEnvFn(TCGContext *, TCGv_i32, TCGv_env, TCGv_i32, + TCGv_i32, TCGv_i32); + /* initialize TCG globals. */ void arm_translate_init(struct uc_struct *uc) { @@ -7141,11 +7145,45 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) } neon_store_reg64(tcg_ctx, tcg_ctx->cpu_V0, rd + pass); } - - break; - default: /* 14 and 15 are RESERVED */ - return 1; + case 14: /* VQRDMLAH scalar */ + case 15: /* VQRDMLSH scalar */ + { + NeonGenThreeOpEnvFn *fn; + + if (!arm_dc_feature(s, ARM_FEATURE_V8_RDM)) { + return 1; + } + if (u && ((rd | rn) & 1)) { + return 1; + } + if (op == 14) { + if (size == 1) { + fn = gen_helper_neon_qrdmlah_s16; + } else { + fn = gen_helper_neon_qrdmlah_s32; + } + } else { + if (size == 1) { + fn = gen_helper_neon_qrdmlsh_s16; + } else { + fn = gen_helper_neon_qrdmlsh_s32; + } + } + + tmp2 = neon_get_scalar(s, size, rm); + for (pass = 0; pass < (u ? 4 : 2); pass++) { + tmp = neon_load_reg(tcg_ctx, rn, pass); + tmp3 = neon_load_reg(tcg_ctx, rd, pass); + fn(tcg_ctx, tmp, tcg_ctx->cpu_env, tmp, tmp2, tmp3); + tcg_temp_free_i32(tcg_ctx, tmp3); + neon_store_reg(tcg_ctx, rd, pass, tmp); + } + tcg_temp_free_i32(tcg_ctx, tmp2); + } + break; + default: + g_assert_not_reached(); } } } else { /* size == 3 */