mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2025-02-25 18:46:47 +00:00
target/arm: Convert the VSEL instructions to decodetree
Convert the VSEL instructions to decodetree. We leave trans_VSEL() in translate.c for now as this allows the patch to show just the changes from the old handle_vsel(). In the old code the check for "do D16-D31 exist" was hidden in the VFP_DREG macro, and assumed that VFPv3 always implied that D16-D31 exist. In the new code we do the correct ID register test. This gives identical behaviour for most of our CPUs, and fixes previously incorrect handling for Cortex-R5F, Cortex-M4 and Cortex-M33, which all implement VFPv3 or better with only 16 double-precision registers. Backports commit b3ff4b87b4ae08120a51fe12592725e1dca8a085 from qemu
This commit is contained in:
parent
93adaa7de2
commit
3994dfd079
|
@ -3328,6 +3328,12 @@ static inline bool isar_feature_aa32_fp16_arith(const ARMISARegisters *id)
|
|||
return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, FP) == 1;
|
||||
}
|
||||
|
||||
static inline bool isar_feature_aa32_fp_d32(const ARMISARegisters *id)
|
||||
{
|
||||
/* Return true if D16-D31 are implemented */
|
||||
return FIELD_EX64(id->mvfr0, MVFR0, SIMDREG) >= 2;
|
||||
}
|
||||
|
||||
/*
|
||||
* We always set the FP and SIMD FP16 fields to indicate identical
|
||||
* levels of support (assuming SIMD is implemented at all), so
|
||||
|
|
|
@ -131,3 +131,12 @@ static bool full_vfp_access_check(DisasContext *s, bool ignore_vfp_enabled)
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* The most usual kind of VFP access check, for everything except
|
||||
* FMXR/FMRX to the always-available special registers.
|
||||
*/
|
||||
static bool vfp_access_check(DisasContext *s)
|
||||
{
|
||||
return full_vfp_access_check(s, false);
|
||||
}
|
||||
|
|
|
@ -3177,11 +3177,28 @@ static void gen_neon_dup_high16(DisasContext *s, TCGv_i32 var)
|
|||
tcg_temp_free_i32(tcg_ctx, tmp);
|
||||
}
|
||||
|
||||
static int handle_vsel(DisasContext *s, uint32_t insn, uint32_t rd, uint32_t rn, uint32_t rm,
|
||||
uint32_t dp)
|
||||
static bool trans_VSEL(DisasContext *s, arg_VSEL *a)
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
uint32_t cc = extract32(insn, 20, 2);
|
||||
uint32_t rd, rn, rm;
|
||||
bool dp = a->dp;
|
||||
|
||||
if (!dc_isar_feature(aa32_vsel, s)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* UNDEF accesses to D16-D31 if they don't exist */
|
||||
if (dp && !dc_isar_feature(aa32_fp_d32, s) &&
|
||||
((a->vm | a->vn | a->vd) & 0x10)) {
|
||||
return false;
|
||||
}
|
||||
rd = a->vd;
|
||||
rn = a->vn;
|
||||
rm = a->vm;
|
||||
|
||||
if (!vfp_access_check(s)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (dp) {
|
||||
TCGv_i64 frn, frm, dest;
|
||||
|
@ -3203,7 +3220,7 @@ static int handle_vsel(DisasContext *s, uint32_t insn, uint32_t rd, uint32_t rn,
|
|||
|
||||
tcg_gen_ld_f64(tcg_ctx, frn, tcg_ctx->cpu_env, vfp_reg_offset(dp, rn));
|
||||
tcg_gen_ld_f64(tcg_ctx, frm, tcg_ctx->cpu_env, vfp_reg_offset(dp, rm));
|
||||
switch (cc) {
|
||||
switch (a->cc) {
|
||||
case 0: /* eq: Z */
|
||||
tcg_gen_movcond_i64(tcg_ctx, TCG_COND_EQ, dest, zf, zero,
|
||||
frn, frm);
|
||||
|
@ -3250,7 +3267,7 @@ static int handle_vsel(DisasContext *s, uint32_t insn, uint32_t rd, uint32_t rn,
|
|||
dest = tcg_temp_new_i32(tcg_ctx);
|
||||
tcg_gen_ld_f32(tcg_ctx, frn, tcg_ctx->cpu_env, vfp_reg_offset(dp, rn));
|
||||
tcg_gen_ld_f32(tcg_ctx, frm, tcg_ctx->cpu_env, vfp_reg_offset(dp, rm));
|
||||
switch (cc) {
|
||||
switch (a->cc) {
|
||||
case 0: /* eq: Z */
|
||||
tcg_gen_movcond_i32(tcg_ctx, TCG_COND_EQ, dest, tcg_ctx->cpu_ZF, zero,
|
||||
frn, frm);
|
||||
|
@ -3284,7 +3301,7 @@ static int handle_vsel(DisasContext *s, uint32_t insn, uint32_t rd, uint32_t rn,
|
|||
tcg_temp_free_i32(tcg_ctx, zero);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int handle_vminmaxnm(DisasContext *s, uint32_t insn, uint32_t rd, uint32_t rn,
|
||||
|
@ -3459,10 +3476,8 @@ static int disas_vfp_misc_insn(DisasContext *s, uint32_t insn)
|
|||
rm = VFP_SREG_M(insn);
|
||||
}
|
||||
|
||||
if ((insn & 0x0f800e50) == 0x0e000a00 && dc_isar_feature(aa32_vsel, s)) {
|
||||
return handle_vsel(s, insn, rd, rn, rm, dp);
|
||||
} else if ((insn & 0x0fb00e10) == 0x0e800a00 &&
|
||||
dc_isar_feature(aa32_vminmaxnm, s)) {
|
||||
if ((insn & 0x0fb00e10) == 0x0e800a00 &&
|
||||
dc_isar_feature(aa32_vminmaxnm, s)) {
|
||||
return handle_vminmaxnm(s, insn, rd, rn, rm, dp);
|
||||
} else if ((insn & 0x0fbc0ed0) == 0x0eb80a40 &&
|
||||
dc_isar_feature(aa32_vrint, s)) {
|
||||
|
|
|
@ -26,3 +26,22 @@
|
|||
# 1111 1110 .... .... .... 101. .... ....
|
||||
# (but those patterns might also cover some Neon instructions,
|
||||
# which do not live in this file.)
|
||||
|
||||
# VFP registers have an odd encoding with a four-bit field
|
||||
# and a one-bit field which are assembled in different orders
|
||||
# depending on whether the register is double or single precision.
|
||||
# Each individual instruction function must do the checks for
|
||||
# "double register selected but CPU does not have double support"
|
||||
# and "double register number has bit 4 set but CPU does not
|
||||
# support D16-D31" (which should UNDEF).
|
||||
%vm_dp 5:1 0:4
|
||||
%vm_sp 0:4 5:1
|
||||
%vn_dp 7:1 16:4
|
||||
%vn_sp 16:4 7:1
|
||||
%vd_dp 22:1 12:4
|
||||
%vd_sp 12:4 22:1
|
||||
|
||||
VSEL 1111 1110 0. cc:2 .... .... 1010 .0.0 .... \
|
||||
vm=%vm_sp vn=%vn_sp vd=%vd_sp dp=0
|
||||
VSEL 1111 1110 0. cc:2 .... .... 1011 .0.0 .... \
|
||||
vm=%vm_dp vn=%vn_dp vd=%vd_dp dp=1
|
||||
|
|
Loading…
Reference in a new issue