diff --git a/qemu/target/arm/neon-dp.decode b/qemu/target/arm/neon-dp.decode index 4f0aaaf6..1da492df 100644 --- a/qemu/target/arm/neon-dp.decode +++ b/qemu/target/arm/neon-dp.decode @@ -450,5 +450,14 @@ Vimm_1r 1111 001 . 1 . 000 ... .... cmode:4 0 . op:1 1 .... @1reg_imm VABDL_S_3d 1111 001 0 1 . .. .... .... 0111 . 0 . 0 .... @3diff VABDL_U_3d 1111 001 1 1 . .. .... .... 0111 . 0 . 0 .... @3diff + + VMLAL_S_3d 1111 001 0 1 . .. .... .... 1000 . 0 . 0 .... @3diff + VMLAL_U_3d 1111 001 1 1 . .. .... .... 1000 . 0 . 0 .... @3diff + + VMLSL_S_3d 1111 001 0 1 . .. .... .... 1010 . 0 . 0 .... @3diff + VMLSL_U_3d 1111 001 1 1 . .. .... .... 1010 . 0 . 0 .... @3diff + + VMULL_S_3d 1111 001 0 1 . .. .... .... 1100 . 0 . 0 .... @3diff + VMULL_U_3d 1111 001 1 1 . .. .... .... 1100 . 0 . 0 .... @3diff ] } diff --git a/qemu/target/arm/translate-neon.inc.c b/qemu/target/arm/translate-neon.inc.c index a1a0622d..d6b73a53 100644 --- a/qemu/target/arm/translate-neon.inc.c +++ b/qemu/target/arm/translate-neon.inc.c @@ -2178,3 +2178,74 @@ static bool trans_VABAL_U_3d(DisasContext *s, arg_3diff *a) return do_long_3d(s, a, opfn[a->size], addfn[a->size]); } + +static void gen_mull_s32(TCGContext *s, TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm) +{ + TCGv_i32 lo = tcg_temp_new_i32(s); + TCGv_i32 hi = tcg_temp_new_i32(s); + + tcg_gen_muls2_i32(s, lo, hi, rn, rm); + tcg_gen_concat_i32_i64(s, rd, lo, hi); + + tcg_temp_free_i32(s, lo); + tcg_temp_free_i32(s, hi); +} + +static void gen_mull_u32(TCGContext *s, TCGv_i64 rd, TCGv_i32 rn, TCGv_i32 rm) +{ + TCGv_i32 lo = tcg_temp_new_i32(s); + TCGv_i32 hi = tcg_temp_new_i32(s); + + tcg_gen_mulu2_i32(s, lo, hi, rn, rm); + tcg_gen_concat_i32_i64(s, rd, lo, hi); + + tcg_temp_free_i32(s, lo); + tcg_temp_free_i32(s, hi); +} + +static bool trans_VMULL_S_3d(DisasContext *s, arg_3diff *a) +{ + static NeonGenTwoOpWidenFn * const opfn[] = { + gen_helper_neon_mull_s8, + gen_helper_neon_mull_s16, + gen_mull_s32, + NULL, + }; + + return do_long_3d(s, a, opfn[a->size], NULL); +} + +static bool trans_VMULL_U_3d(DisasContext *s, arg_3diff *a) +{ + static NeonGenTwoOpWidenFn * const opfn[] = { + gen_helper_neon_mull_u8, + gen_helper_neon_mull_u16, + gen_mull_u32, + NULL, + }; + + return do_long_3d(s, a, opfn[a->size], NULL); +} + +#define DO_VMLAL(INSN,MULL,ACC) \ + static bool trans_##INSN##_3d(DisasContext *s, arg_3diff *a) \ + { \ + static NeonGenTwoOpWidenFn * const opfn[] = { \ + gen_helper_neon_##MULL##8, \ + gen_helper_neon_##MULL##16, \ + gen_##MULL##32, \ + NULL, \ + }; \ + static NeonGenTwo64OpFn * const accfn[] = { \ + gen_helper_neon_##ACC##l_u16, \ + gen_helper_neon_##ACC##l_u32, \ + tcg_gen_##ACC##_i64, \ + NULL, \ + }; \ + return do_long_3d(s, a, opfn[a->size], accfn[a->size]); \ + } + +DO_VMLAL(VMLAL_S,mull_s,add) +DO_VMLAL(VMLAL_U,mull_u,add) +DO_VMLAL(VMLSL_S,mull_s,sub) +DO_VMLAL(VMLSL_U,mull_u,sub) diff --git a/qemu/target/arm/translate.c b/qemu/target/arm/translate.c index 384730cb..35406334 100644 --- a/qemu/target/arm/translate.c +++ b/qemu/target/arm/translate.c @@ -5370,11 +5370,11 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) {0, 0, 0, 7}, /* VABAL */ {0, 0, 0, 7}, /* VSUBHN: handled by decodetree */ {0, 0, 0, 7}, /* VABDL */ - {0, 0, 0, 0}, /* VMLAL */ + {0, 0, 0, 7}, /* VMLAL */ {0, 0, 0, 9}, /* VQDMLAL */ - {0, 0, 0, 0}, /* VMLSL */ + {0, 0, 0, 7}, /* VMLSL */ {0, 0, 0, 9}, /* VQDMLSL */ - {0, 0, 0, 0}, /* Integer VMULL */ + {0, 0, 0, 7}, /* Integer VMULL */ {0, 0, 0, 9}, /* VQDMULL */ {0, 0, 0, 0xa}, /* Polynomial VMULL */ {0, 0, 0, 7}, /* Reserved: always UNDEF */ @@ -5430,8 +5430,8 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) tmp2 = neon_load_reg(s, rm, pass); } switch (op) { - case 8: case 9: case 10: case 11: case 12: case 13: - /* VMLAL, VQDMLAL, VMLSL, VQDMLSL, VMULL, VQDMULL */ + case 9: case 11: case 13: + /* VQDMLAL, VQDMLSL, VQDMULL */ gen_neon_mull(s, s->V0, tmp, tmp2, size, u); break; default: /* 15 is RESERVED: caught earlier */ @@ -5441,16 +5441,10 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) /* VQDMULL */ gen_neon_addl_saturate(s, s->V0, s->V0, size); neon_store_reg64(s, s->V0, rd + pass); - } else if (op == 5 || (op >= 8 && op <= 11)) { + } else { /* Accumulate. */ neon_load_reg64(s, s->V1, rd + pass); switch (op) { - case 10: /* VMLSL */ - gen_neon_negl(s, s->V0, size); - /* Fall through */ - case 8: /* VABAL, VMLAL */ - gen_neon_addl(s, size); - break; case 9: case 11: /* VQDMLAL, VQDMLSL */ gen_neon_addl_saturate(s, s->V0, s->V0, size); if (op == 11) { @@ -5462,9 +5456,6 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) abort(); } neon_store_reg64(s, s->V0, rd + pass); - } else { - /* Write back the result. */ - neon_store_reg64(s, s->V0, rd + pass); } } } else {