From: Alexander Graf <agraf@xxxxxxx> This patch adds emulation for the "Data-processing (3 source)" family of instructions, namely MADD, MSUB, SMADDL, SMSUBL, SMULH, UMADDL, UMSUBL, UMULH. Signed-off-by: Alexander Graf <agraf@xxxxxxx> Signed-off-by: Alex Bennée <alex.bennee@xxxxxxxxxx> Signed-off-by: Peter Maydell <peter.maydell@xxxxxxxxxx> --- target-arm/helper-a64.c | 14 ++++++++ target-arm/helper-a64.h | 2 ++ target-arm/translate-a64.c | 85 ++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 99 insertions(+), 2 deletions(-) diff --git a/target-arm/helper-a64.c b/target-arm/helper-a64.c index d3f7067..691d56b 100644 --- a/target-arm/helper-a64.c +++ b/target-arm/helper-a64.c @@ -77,3 +77,17 @@ uint64_t HELPER(rbit64)(uint64_t x) return x; } + +uint64_t HELPER(umulh)(uint64_t n, uint64_t m) +{ + uint64_t rl, rh; + mulu64(&rl, &rh, n, m); + return rh; +} + +uint64_t HELPER(smulh)(uint64_t n, uint64_t m) +{ + uint64_t rl, rh; + muls64(&rl, &rh, n, m); + return rh; +} diff --git a/target-arm/helper-a64.h b/target-arm/helper-a64.h index a163a94..275da96 100644 --- a/target-arm/helper-a64.h +++ b/target-arm/helper-a64.h @@ -22,3 +22,5 @@ DEF_HELPER_FLAGS_1(clz64, TCG_CALL_NO_RWG_SE, i64, i64) DEF_HELPER_FLAGS_1(cls64, TCG_CALL_NO_RWG_SE, i64, i64) DEF_HELPER_FLAGS_1(cls32, TCG_CALL_NO_RWG_SE, i32, i32) DEF_HELPER_FLAGS_1(rbit64, TCG_CALL_NO_RWG_SE, i64, i64) +DEF_HELPER_FLAGS_2(umulh, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_2(smulh, TCG_CALL_NO_RWG_SE, i64, i64, i64) diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c index 731e779..1ab264f 100644 --- a/target-arm/translate-a64.c +++ b/target-arm/translate-a64.c @@ -2261,10 +2261,91 @@ static void handle_add_sub_reg(DisasContext *s, uint32_t insn) tcg_temp_free_i64(tcg_result); } -/* Data-processing (3 source) */ +/* C3.5.9 Data-processing (3 source) + + 31 30 29 28 24 23 21 20 16 15 14 10 9 5 4 0 + +--+------+-----------+------+------+----+------+------+------+ + |sf| op54 | 1 1 0 1 1 | op31 | Rm | o0 | Ra | Rn | Rd | + +--+------+-----------+------+------+----+------+------+------+ + + */ static void disas_data_proc_3src(DisasContext *s, uint32_t insn) { - unsupported_encoding(s, insn); + int rd = extract32(insn, 0, 5); + int rn = extract32(insn, 5, 5); + int ra = extract32(insn, 10, 5); + int rm = extract32(insn, 16, 5); + int op_id = (extract32(insn, 29, 3) << 4) | + (extract32(insn, 21, 3) << 1) | + extract32(insn, 15, 1); + bool is_32bit = !extract32(insn, 31, 1); + bool is_sub = extract32(op_id, 0, 1); + bool is_high = extract32(op_id, 2, 1); + bool is_signed = false; + TCGv_i64 tcg_op1; + TCGv_i64 tcg_op2; + TCGv_i64 tcg_tmp; + + /* Note that op_id is sf:op54:op31:o0 so it includes the 32/64 size flag */ + switch (op_id) { + case 0x42: /* SMADDL */ + case 0x43: /* SMSUBL */ + case 0x44: /* SMULH */ + is_signed = true; + break; + case 0x0: /* MADD (32bit) */ + case 0x1: /* MSUB (32bit) */ + case 0x40: /* MADD (64bit) */ + case 0x41: /* MSUB (64bit) */ + case 0x4a: /* UMADDL */ + case 0x4b: /* UMSUBL */ + case 0x4c: /* UMULH */ + break; + default: + unallocated_encoding(s); + } + + if (is_high) { + /* SMULH and UMULH go via helpers for the 64x64->128 multiply */ + if (is_signed) { + gen_helper_smulh(cpu_reg(s, rd), cpu_reg(s, rn), cpu_reg(s, rm)); + } else { + gen_helper_umulh(cpu_reg(s, rd), cpu_reg(s, rn), cpu_reg(s, rm)); + } + return; + } + + tcg_op1 = tcg_temp_new_i64(); + tcg_op2 = tcg_temp_new_i64(); + tcg_tmp = tcg_temp_new_i64(); + + if (op_id < 0x42) { + tcg_gen_mov_i64(tcg_op1, cpu_reg(s, rn)); + tcg_gen_mov_i64(tcg_op2, cpu_reg(s, rm)); + } else { + if (is_signed) { + tcg_gen_ext32s_i64(tcg_op1, cpu_reg(s, rn)); + tcg_gen_ext32s_i64(tcg_op2, cpu_reg(s, rm)); + } else { + tcg_gen_ext32u_i64(tcg_op1, cpu_reg(s, rn)); + tcg_gen_ext32u_i64(tcg_op2, cpu_reg(s, rm)); + } + } + + tcg_gen_mul_i64(tcg_tmp, tcg_op1, tcg_op2); + if (is_sub) { + tcg_gen_sub_i64(cpu_reg(s, rd), cpu_reg(s, ra), tcg_tmp); + } else { + tcg_gen_add_i64(cpu_reg(s, rd), cpu_reg(s, ra), tcg_tmp); + } + + if (is_32bit) { + tcg_gen_ext32u_i64(cpu_reg(s, rd), cpu_reg(s, rd)); + } + + tcg_temp_free_i64(tcg_op1); + tcg_temp_free_i64(tcg_op2); + tcg_temp_free_i64(tcg_tmp); } /* Add/subtract (with carry) */ -- 1.8.5 _______________________________________________ kvmarm mailing list kvmarm@xxxxxxxxxxxxxxxxxxxxx https://lists.cs.columbia.edu/cucslists/listinfo/kvmarm