mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2025-07-09 06:30:40 +00:00
target/arm: Implement VFMAL and VFMSL for aarch32
Backports commit 87732318c5d68a366fc2d6fc394d9c20412099fa from qemu
This commit is contained in:
parent
625d3f3cfb
commit
4ae3ff8e61
|
@ -3277,6 +3277,11 @@ static inline bool isar_feature_aa32_dp(const ARMISARegisters *id)
|
||||||
return FIELD_EX32(id->id_isar6, ID_ISAR6, DP) != 0;
|
return FIELD_EX32(id->id_isar6, ID_ISAR6, DP) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool isar_feature_aa32_fhm(const ARMISARegisters *id)
|
||||||
|
{
|
||||||
|
return FIELD_EX32(id->id_isar6, ID_ISAR6, FHM) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool isar_feature_aa32_fp16_arith(const ARMISARegisters *id)
|
static inline bool isar_feature_aa32_fp16_arith(const ARMISARegisters *id)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -8546,15 +8546,9 @@ static int disas_neon_insn_3same_ext(DisasContext *s, uint32_t insn)
|
||||||
gen_helper_gvec_3_ptr *fn_gvec_ptr = NULL;
|
gen_helper_gvec_3_ptr *fn_gvec_ptr = NULL;
|
||||||
int rd, rn, rm, opr_sz;
|
int rd, rn, rm, opr_sz;
|
||||||
int data = 0;
|
int data = 0;
|
||||||
bool q;
|
int off_rn, off_rm;
|
||||||
|
bool is_long = false, q = extract32(insn, 6, 1);
|
||||||
q = extract32(insn, 6, 1);
|
bool ptr_is_env = false;
|
||||||
VFP_DREG_D(rd, insn);
|
|
||||||
VFP_DREG_N(rn, insn);
|
|
||||||
VFP_DREG_M(rm, insn);
|
|
||||||
if ((rd | rn | rm) & q) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((insn & 0xfe200f10) == 0xfc200800) {
|
if ((insn & 0xfe200f10) == 0xfc200800) {
|
||||||
/* VCMLA -- 1111 110R R.1S .... .... 1000 ...0 .... */
|
/* VCMLA -- 1111 110R R.1S .... .... 1000 ...0 .... */
|
||||||
|
@ -8581,10 +8575,39 @@ static int disas_neon_insn_3same_ext(DisasContext *s, uint32_t insn)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
fn_gvec = u ? gen_helper_gvec_udot_b : gen_helper_gvec_sdot_b;
|
fn_gvec = u ? gen_helper_gvec_udot_b : gen_helper_gvec_sdot_b;
|
||||||
|
} else if ((insn & 0xff300f10) == 0xfc200810) {
|
||||||
|
/* VFM[AS]L -- 1111 1100 S.10 .... .... 1000 .Q.1 .... */
|
||||||
|
int is_s = extract32(insn, 23, 1);
|
||||||
|
if (!dc_isar_feature(aa32_fhm, s)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
is_long = true;
|
||||||
|
data = is_s; /* is_2 == 0 */
|
||||||
|
fn_gvec_ptr = gen_helper_gvec_fmlal_a32;
|
||||||
|
ptr_is_env = true;
|
||||||
} else {
|
} else {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VFP_DREG_D(rd, insn);
|
||||||
|
if (rd & q) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (q || !is_long) {
|
||||||
|
VFP_DREG_N(rn, insn);
|
||||||
|
VFP_DREG_M(rm, insn);
|
||||||
|
if ((rn | rm) & q & !is_long) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
off_rn = vfp_reg_offset(1, rn);
|
||||||
|
off_rm = vfp_reg_offset(1, rm);
|
||||||
|
} else {
|
||||||
|
rn = VFP_SREG_N(insn);
|
||||||
|
rm = VFP_SREG_M(insn);
|
||||||
|
off_rn = vfp_reg_offset(0, rn);
|
||||||
|
off_rm = vfp_reg_offset(0, rm);
|
||||||
|
}
|
||||||
|
|
||||||
if (s->fp_excp_el) {
|
if (s->fp_excp_el) {
|
||||||
gen_exception_insn(s, 4, EXCP_UDEF,
|
gen_exception_insn(s, 4, EXCP_UDEF,
|
||||||
syn_simd_access_trap(1, 0xe, false), s->fp_excp_el);
|
syn_simd_access_trap(1, 0xe, false), s->fp_excp_el);
|
||||||
|
@ -8596,16 +8619,19 @@ static int disas_neon_insn_3same_ext(DisasContext *s, uint32_t insn)
|
||||||
|
|
||||||
opr_sz = (1 + q) * 8;
|
opr_sz = (1 + q) * 8;
|
||||||
if (fn_gvec_ptr) {
|
if (fn_gvec_ptr) {
|
||||||
TCGv_ptr fpst = get_fpstatus_ptr(s, 1);
|
TCGv_ptr ptr;
|
||||||
tcg_gen_gvec_3_ptr(tcg_ctx, vfp_reg_offset(1, rd),
|
if (ptr_is_env) {
|
||||||
vfp_reg_offset(1, rn),
|
ptr = tcg_ctx->cpu_env;
|
||||||
vfp_reg_offset(1, rm), fpst,
|
|
||||||
opr_sz, opr_sz, data, fn_gvec_ptr);
|
|
||||||
tcg_temp_free_ptr(tcg_ctx, fpst);
|
|
||||||
} else {
|
} else {
|
||||||
tcg_gen_gvec_3_ool(tcg_ctx, vfp_reg_offset(1, rd),
|
ptr = get_fpstatus_ptr(s, 1);
|
||||||
vfp_reg_offset(1, rn),
|
}
|
||||||
vfp_reg_offset(1, rm),
|
tcg_gen_gvec_3_ptr(tcg_ctx, vfp_reg_offset(1, rd), off_rn, off_rm, ptr,
|
||||||
|
opr_sz, opr_sz, data, fn_gvec_ptr);
|
||||||
|
if (!ptr_is_env) {
|
||||||
|
tcg_temp_free_ptr(tcg_ctx, ptr);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tcg_gen_gvec_3_ool(tcg_ctx, vfp_reg_offset(1, rd), off_rn, off_rm,
|
||||||
opr_sz, opr_sz, data, fn_gvec);
|
opr_sz, opr_sz, data, fn_gvec);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -8625,14 +8651,9 @@ static int disas_neon_insn_2reg_scalar_ext(DisasContext *s, uint32_t insn)
|
||||||
gen_helper_gvec_3 *fn_gvec = NULL;
|
gen_helper_gvec_3 *fn_gvec = NULL;
|
||||||
gen_helper_gvec_3_ptr *fn_gvec_ptr = NULL;
|
gen_helper_gvec_3_ptr *fn_gvec_ptr = NULL;
|
||||||
int rd, rn, rm, opr_sz, data;
|
int rd, rn, rm, opr_sz, data;
|
||||||
bool q;
|
int off_rn, off_rm;
|
||||||
|
bool is_long = false, q = extract32(insn, 6, 1);
|
||||||
q = extract32(insn, 6, 1);
|
bool ptr_is_env = false;
|
||||||
VFP_DREG_D(rd, insn);
|
|
||||||
VFP_DREG_N(rn, insn);
|
|
||||||
if ((rd | rn) & q) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((insn & 0xff000f10) == 0xfe000800) {
|
if ((insn & 0xff000f10) == 0xfe000800) {
|
||||||
/* VCMLA (indexed) -- 1111 1110 S.RR .... .... 1000 ...0 .... */
|
/* VCMLA (indexed) -- 1111 1110 S.RR .... .... 1000 ...0 .... */
|
||||||
|
@ -8661,6 +8682,7 @@ static int disas_neon_insn_2reg_scalar_ext(DisasContext *s, uint32_t insn)
|
||||||
} else if ((insn & 0xffb00f00) == 0xfe200d00) {
|
} else if ((insn & 0xffb00f00) == 0xfe200d00) {
|
||||||
/* V[US]DOT -- 1111 1110 0.10 .... .... 1101 .Q.U .... */
|
/* V[US]DOT -- 1111 1110 0.10 .... .... 1101 .Q.U .... */
|
||||||
int u = extract32(insn, 4, 1);
|
int u = extract32(insn, 4, 1);
|
||||||
|
|
||||||
if (!dc_isar_feature(aa32_dp, s)) {
|
if (!dc_isar_feature(aa32_dp, s)) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -8668,10 +8690,48 @@ static int disas_neon_insn_2reg_scalar_ext(DisasContext *s, uint32_t insn)
|
||||||
/* rm is just Vm, and index is M. */
|
/* rm is just Vm, and index is M. */
|
||||||
data = extract32(insn, 5, 1); /* index */
|
data = extract32(insn, 5, 1); /* index */
|
||||||
rm = extract32(insn, 0, 4);
|
rm = extract32(insn, 0, 4);
|
||||||
|
} else if ((insn & 0xffa00f10) == 0xfe000810) {
|
||||||
|
/* VFM[AS]L -- 1111 1110 0.0S .... .... 1000 .Q.1 .... */
|
||||||
|
int is_s = extract32(insn, 20, 1);
|
||||||
|
int vm20 = extract32(insn, 0, 3);
|
||||||
|
int vm3 = extract32(insn, 3, 1);
|
||||||
|
int m = extract32(insn, 5, 1);
|
||||||
|
int index;
|
||||||
|
|
||||||
|
if (!dc_isar_feature(aa32_fhm, s)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (q) {
|
||||||
|
rm = vm20;
|
||||||
|
index = m * 2 + vm3;
|
||||||
|
} else {
|
||||||
|
rm = vm20 * 2 + m;
|
||||||
|
index = vm3;
|
||||||
|
}
|
||||||
|
is_long = true;
|
||||||
|
data = (index << 2) | is_s; /* is_2 == 0 */
|
||||||
|
fn_gvec_ptr = gen_helper_gvec_fmlal_idx_a32;
|
||||||
|
ptr_is_env = true;
|
||||||
} else {
|
} else {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VFP_DREG_D(rd, insn);
|
||||||
|
if (rd & q) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (q || !is_long) {
|
||||||
|
VFP_DREG_N(rn, insn);
|
||||||
|
if (rn & q & !is_long) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
off_rn = vfp_reg_offset(1, rn);
|
||||||
|
off_rm = vfp_reg_offset(1, rm);
|
||||||
|
} else {
|
||||||
|
rn = VFP_SREG_N(insn);
|
||||||
|
off_rn = vfp_reg_offset(0, rn);
|
||||||
|
off_rm = vfp_reg_offset(0, rm);
|
||||||
|
}
|
||||||
if (s->fp_excp_el) {
|
if (s->fp_excp_el) {
|
||||||
gen_exception_insn(s, 4, EXCP_UDEF,
|
gen_exception_insn(s, 4, EXCP_UDEF,
|
||||||
syn_simd_access_trap(1, 0xe, false), s->fp_excp_el);
|
syn_simd_access_trap(1, 0xe, false), s->fp_excp_el);
|
||||||
|
@ -8683,16 +8743,19 @@ static int disas_neon_insn_2reg_scalar_ext(DisasContext *s, uint32_t insn)
|
||||||
|
|
||||||
opr_sz = (1 + q) * 8;
|
opr_sz = (1 + q) * 8;
|
||||||
if (fn_gvec_ptr) {
|
if (fn_gvec_ptr) {
|
||||||
TCGv_ptr fpst = get_fpstatus_ptr(s, 1);
|
TCGv_ptr ptr;
|
||||||
tcg_gen_gvec_3_ptr(tcg_ctx, vfp_reg_offset(1, rd),
|
if (ptr_is_env) {
|
||||||
vfp_reg_offset(1, rn),
|
ptr = tcg_ctx->cpu_env;
|
||||||
vfp_reg_offset(1, rm), fpst,
|
|
||||||
opr_sz, opr_sz, data, fn_gvec_ptr);
|
|
||||||
tcg_temp_free_ptr(tcg_ctx, fpst);
|
|
||||||
} else {
|
} else {
|
||||||
tcg_gen_gvec_3_ool(tcg_ctx, vfp_reg_offset(1, rd),
|
ptr = get_fpstatus_ptr(s, 1);
|
||||||
vfp_reg_offset(1, rn),
|
}
|
||||||
vfp_reg_offset(1, rm),
|
tcg_gen_gvec_3_ptr(tcg_ctx, vfp_reg_offset(1, rd), off_rn, off_rm, ptr,
|
||||||
|
opr_sz, opr_sz, data, fn_gvec_ptr);
|
||||||
|
if (!ptr_is_env) {
|
||||||
|
tcg_temp_free_ptr(tcg_ctx, ptr);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tcg_gen_gvec_3_ool(tcg_ctx, vfp_reg_offset(1, rd), off_rn, off_rm,
|
||||||
opr_sz, opr_sz, data, fn_gvec);
|
opr_sz, opr_sz, data, fn_gvec);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in a new issue