X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/8908f4d1850dbfd0de442e8deaed2f41821cdb89..e508a92b621c7160122e99d3754e568f2b8e255e:/target-arm/translate-a64.c diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c index bcf32a12b4..f6500e5181 100644 --- a/target-arm/translate-a64.c +++ b/target-arm/translate-a64.c @@ -1177,7 +1177,12 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread, crn, crm, op0, op1, op2)); if (!ri) { - /* Unknown register */ + /* Unknown register; this might be a guest error or a QEMU + * unimplemented feature. + */ + qemu_log_mask(LOG_UNIMP, "%s access to unsupported AArch64 " + "system register op0:%d op1:%d crn:%d crm:%d op2:%d\n", + isread ? "read" : "write", op0, op1, crn, crm, op2); unallocated_encoding(s); return; } @@ -6045,18 +6050,33 @@ static void handle_3same_float(DisasContext *s, int size, int elements, read_vec_element(s, tcg_op2, rm, pass, MO_64); switch (fpopcode) { + case 0x39: /* FMLS */ + /* As usual for ARM, separate negation for fused multiply-add */ + gen_helper_vfp_negd(tcg_op1, tcg_op1); + /* fall through */ + case 0x19: /* FMLA */ + read_vec_element(s, tcg_res, rd, pass, MO_64); + gen_helper_vfp_muladdd(tcg_res, tcg_op1, tcg_op2, + tcg_res, fpst); + break; case 0x18: /* FMAXNM */ gen_helper_vfp_maxnumd(tcg_res, tcg_op1, tcg_op2, fpst); break; case 0x1a: /* FADD */ gen_helper_vfp_addd(tcg_res, tcg_op1, tcg_op2, fpst); break; + case 0x1b: /* FMULX */ + gen_helper_vfp_mulxd(tcg_res, tcg_op1, tcg_op2, fpst); + break; case 0x1c: /* FCMEQ */ gen_helper_neon_ceq_f64(tcg_res, tcg_op1, tcg_op2, fpst); break; case 0x1e: /* FMAX */ gen_helper_vfp_maxd(tcg_res, tcg_op1, tcg_op2, fpst); break; + case 0x1f: /* FRECPS */ + gen_helper_recpsf_f64(tcg_res, tcg_op1, tcg_op2, fpst); + break; case 0x38: /* FMINNM */ gen_helper_vfp_minnumd(tcg_res, tcg_op1, tcg_op2, fpst); break; @@ -6066,12 +6086,18 @@ static void handle_3same_float(DisasContext *s, int size, int elements, case 0x3e: /* FMIN */ gen_helper_vfp_mind(tcg_res, tcg_op1, tcg_op2, fpst); break; + case 0x3f: /* FRSQRTS */ + gen_helper_rsqrtsf_f64(tcg_res, tcg_op1, tcg_op2, fpst); + break; case 0x5b: /* FMUL */ gen_helper_vfp_muld(tcg_res, tcg_op1, tcg_op2, fpst); break; case 0x5c: /* FCMGE */ gen_helper_neon_cge_f64(tcg_res, tcg_op1, tcg_op2, fpst); break; + case 0x5d: /* FACGE */ + gen_helper_neon_acge_f64(tcg_res, tcg_op1, tcg_op2, fpst); + break; case 0x5f: /* FDIV */ gen_helper_vfp_divd(tcg_res, tcg_op1, tcg_op2, fpst); break; @@ -6082,6 +6108,9 @@ static void handle_3same_float(DisasContext *s, int size, int elements, case 0x7c: /* FCMGT */ gen_helper_neon_cgt_f64(tcg_res, tcg_op1, tcg_op2, fpst); break; + case 0x7d: /* FACGT */ + gen_helper_neon_acgt_f64(tcg_res, tcg_op1, tcg_op2, fpst); + break; default: g_assert_not_reached(); } @@ -6101,15 +6130,30 @@ static void handle_3same_float(DisasContext *s, int size, int elements, read_vec_element_i32(s, tcg_op2, rm, pass, MO_32); switch (fpopcode) { + case 0x39: /* FMLS */ + /* As usual for ARM, separate negation for fused multiply-add */ + gen_helper_vfp_negs(tcg_op1, tcg_op1); + /* fall through */ + case 0x19: /* FMLA */ + read_vec_element_i32(s, tcg_res, rd, pass, MO_32); + gen_helper_vfp_muladds(tcg_res, tcg_op1, tcg_op2, + tcg_res, fpst); + break; case 0x1a: /* FADD */ gen_helper_vfp_adds(tcg_res, tcg_op1, tcg_op2, fpst); break; + case 0x1b: /* FMULX */ + gen_helper_vfp_mulxs(tcg_res, tcg_op1, tcg_op2, fpst); + break; case 0x1c: /* FCMEQ */ gen_helper_neon_ceq_f32(tcg_res, tcg_op1, tcg_op2, fpst); break; case 0x1e: /* FMAX */ gen_helper_vfp_maxs(tcg_res, tcg_op1, tcg_op2, fpst); break; + case 0x1f: /* FRECPS */ + gen_helper_recpsf_f32(tcg_res, tcg_op1, tcg_op2, fpst); + break; case 0x18: /* FMAXNM */ gen_helper_vfp_maxnums(tcg_res, tcg_op1, tcg_op2, fpst); break; @@ -6122,12 +6166,18 @@ static void handle_3same_float(DisasContext *s, int size, int elements, case 0x3e: /* FMIN */ gen_helper_vfp_mins(tcg_res, tcg_op1, tcg_op2, fpst); break; + case 0x3f: /* FRSQRTS */ + gen_helper_rsqrtsf_f32(tcg_res, tcg_op1, tcg_op2, fpst); + break; case 0x5b: /* FMUL */ gen_helper_vfp_muls(tcg_res, tcg_op1, tcg_op2, fpst); break; case 0x5c: /* FCMGE */ gen_helper_neon_cge_f32(tcg_res, tcg_op1, tcg_op2, fpst); break; + case 0x5d: /* FACGE */ + gen_helper_neon_acge_f32(tcg_res, tcg_op1, tcg_op2, fpst); + break; case 0x5f: /* FDIV */ gen_helper_vfp_divs(tcg_res, tcg_op1, tcg_op2, fpst); break; @@ -6138,6 +6188,9 @@ static void handle_3same_float(DisasContext *s, int size, int elements, case 0x7c: /* FCMGT */ gen_helper_neon_cgt_f32(tcg_res, tcg_op1, tcg_op2, fpst); break; + case 0x7d: /* FACGT */ + gen_helper_neon_acgt_f32(tcg_res, tcg_op1, tcg_op2, fpst); + break; default: g_assert_not_reached(); } @@ -6192,8 +6245,6 @@ static void disas_simd_scalar_three_reg_same(DisasContext *s, uint32_t insn) case 0x3f: /* FRSQRTS */ case 0x5d: /* FACGE */ case 0x7d: /* FACGT */ - unsupported_encoding(s, insn); - return; case 0x1c: /* FCMEQ */ case 0x5c: /* FCMGE */ case 0x7c: /* FCMGT */ @@ -7105,39 +7156,22 @@ static void gen_min_u32(TCGv_i32 res, TCGv_i32 op1, TCGv_i32 op2) tcg_gen_movcond_i32(TCG_COND_LEU, res, op1, op2, op1, op2); } -/* Pairwise op subgroup of C3.6.16. */ -static void disas_simd_3same_pair(DisasContext *s, uint32_t insn) +/* Pairwise op subgroup of C3.6.16. + * + * This is called directly or via the handle_3same_float for float pairwise + * operations where the opcode and size are calculated differently. + */ +static void handle_simd_3same_pair(DisasContext *s, int is_q, int u, int opcode, + int size, int rn, int rm, int rd) { - int is_q = extract32(insn, 30, 1); - int u = extract32(insn, 29, 1); - int size = extract32(insn, 22, 2); - int opcode = extract32(insn, 11, 5); - int rm = extract32(insn, 16, 5); - int rn = extract32(insn, 5, 5); - int rd = extract32(insn, 0, 5); + TCGv_ptr fpst; int pass; - if (size == 3 && !is_q) { - unallocated_encoding(s); - return; - } - - switch (opcode) { - case 0x14: /* SMAXP, UMAXP */ - case 0x15: /* SMINP, UMINP */ - if (size == 3) { - unallocated_encoding(s); - return; - } - break; - case 0x17: - if (u) { - unallocated_encoding(s); - return; - } - break; - default: - g_assert_not_reached(); + /* Floating point operations need fpst */ + if (opcode >= 0x58) { + fpst = get_fpstatus_ptr(); + } else { + TCGV_UNUSED_PTR(fpst); } /* These operations work on the concatenated rm:rn, with each pair of @@ -7155,9 +7189,28 @@ static void disas_simd_3same_pair(DisasContext *s, uint32_t insn) read_vec_element(s, tcg_op2, passreg, 1, MO_64); tcg_res[pass] = tcg_temp_new_i64(); - /* The only 64 bit pairwise integer op is ADDP */ - assert(opcode == 0x17); - tcg_gen_add_i64(tcg_res[pass], tcg_op1, tcg_op2); + switch (opcode) { + case 0x17: /* ADDP */ + tcg_gen_add_i64(tcg_res[pass], tcg_op1, tcg_op2); + break; + case 0x58: /* FMAXNMP */ + gen_helper_vfp_maxnumd(tcg_res[pass], tcg_op1, tcg_op2, fpst); + break; + case 0x5a: /* FADDP */ + gen_helper_vfp_addd(tcg_res[pass], tcg_op1, tcg_op2, fpst); + break; + case 0x5e: /* FMAXP */ + gen_helper_vfp_maxd(tcg_res[pass], tcg_op1, tcg_op2, fpst); + break; + case 0x78: /* FMINNMP */ + gen_helper_vfp_minnumd(tcg_res[pass], tcg_op1, tcg_op2, fpst); + break; + case 0x7e: /* FMINP */ + gen_helper_vfp_mind(tcg_res[pass], tcg_op1, tcg_op2, fpst); + break; + default: + g_assert_not_reached(); + } tcg_temp_free_i64(tcg_op1); tcg_temp_free_i64(tcg_op2); @@ -7174,7 +7227,7 @@ static void disas_simd_3same_pair(DisasContext *s, uint32_t insn) for (pass = 0; pass < maxpass; pass++) { TCGv_i32 tcg_op1 = tcg_temp_new_i32(); TCGv_i32 tcg_op2 = tcg_temp_new_i32(); - NeonGenTwoOpFn *genfn; + NeonGenTwoOpFn *genfn = NULL; int passreg = pass < (maxpass / 2) ? rn : rm; int passelt = (is_q && (pass & 1)) ? 2 : 0; @@ -7213,11 +7266,30 @@ static void disas_simd_3same_pair(DisasContext *s, uint32_t insn) genfn = fns[size][u]; break; } + /* The FP operations are all on single floats (32 bit) */ + case 0x58: /* FMAXNMP */ + gen_helper_vfp_maxnums(tcg_res[pass], tcg_op1, tcg_op2, fpst); + break; + case 0x5a: /* FADDP */ + gen_helper_vfp_adds(tcg_res[pass], tcg_op1, tcg_op2, fpst); + break; + case 0x5e: /* FMAXP */ + gen_helper_vfp_maxs(tcg_res[pass], tcg_op1, tcg_op2, fpst); + break; + case 0x78: /* FMINNMP */ + gen_helper_vfp_minnums(tcg_res[pass], tcg_op1, tcg_op2, fpst); + break; + case 0x7e: /* FMINP */ + gen_helper_vfp_mins(tcg_res[pass], tcg_op1, tcg_op2, fpst); + break; default: g_assert_not_reached(); } - genfn(tcg_res[pass], tcg_op1, tcg_op2); + /* FP ops called directly, otherwise call now */ + if (genfn) { + genfn(tcg_res[pass], tcg_op1, tcg_op2); + } tcg_temp_free_i32(tcg_op1); tcg_temp_free_i32(tcg_op2); @@ -7231,6 +7303,10 @@ static void disas_simd_3same_pair(DisasContext *s, uint32_t insn) clear_vec_high(s, rd); } } + + if (!TCGV_IS_UNUSED_PTR(fpst)) { + tcg_temp_free_ptr(fpst); + } } /* Floating point op subgroup of C3.6.16. */ @@ -7264,8 +7340,12 @@ static void disas_simd_3same_float(DisasContext *s, uint32_t insn) case 0x5e: /* FMAXP */ case 0x78: /* FMINNMP */ case 0x7e: /* FMINP */ - /* pairwise ops */ - unsupported_encoding(s, insn); + if (size && !is_q) { + unallocated_encoding(s); + return; + } + handle_simd_3same_pair(s, is_q, 0, fpopcode, size ? MO_64 : MO_32, + rn, rm, rd); return; case 0x1b: /* FMULX */ case 0x1f: /* FRECPS */ @@ -7274,8 +7354,6 @@ static void disas_simd_3same_float(DisasContext *s, uint32_t insn) case 0x7d: /* FACGT */ case 0x19: /* FMLA */ case 0x39: /* FMLS */ - unsupported_encoding(s, insn); - return; case 0x18: /* FMAXNM */ case 0x1a: /* FADD */ case 0x1c: /* FCMEQ */ @@ -7615,9 +7693,28 @@ static void disas_simd_three_reg_same(DisasContext *s, uint32_t insn) case 0x17: /* ADDP */ case 0x14: /* SMAXP, UMAXP */ case 0x15: /* SMINP, UMINP */ + { /* Pairwise operations */ - disas_simd_3same_pair(s, insn); + int is_q = extract32(insn, 30, 1); + int u = extract32(insn, 29, 1); + int size = extract32(insn, 22, 2); + int rm = extract32(insn, 16, 5); + int rn = extract32(insn, 5, 5); + int rd = extract32(insn, 0, 5); + if (opcode == 0x17) { + if (u || (size == 3 && !is_q)) { + unallocated_encoding(s); + return; + } + } else { + if (size == 3) { + unallocated_encoding(s); + return; + } + } + handle_simd_3same_pair(s, is_q, u, opcode, size, rn, rm, rd); break; + } case 0x18 ... 0x31: /* floating point ops, sz[1] and U are part of opcode */ disas_simd_3same_float(s, insn);