mirror of
https://github.com/xemu-project/xemu.git
synced 2024-11-23 19:49:43 +00:00
target-arm: Implement ARMv8 VSEL instruction.
This adds support for the VSEL floating point selection instruction which was added in ARMv8. Signed-off-by: Will Newton <will.newton@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Message-id: 1386158099-9239-3-git-send-email-will.newton@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
parent
6a57f3ebba
commit
04731fb5f3
@ -2614,6 +2614,139 @@ static TCGv_i32 gen_load_and_replicate(DisasContext *s, TCGv_i32 addr, int size)
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static int handle_vsel(uint32_t insn, uint32_t rd, uint32_t rn, uint32_t rm,
|
||||
uint32_t dp)
|
||||
{
|
||||
uint32_t cc = extract32(insn, 20, 2);
|
||||
|
||||
if (dp) {
|
||||
TCGv_i64 frn, frm, dest;
|
||||
TCGv_i64 tmp, zero, zf, nf, vf;
|
||||
|
||||
zero = tcg_const_i64(0);
|
||||
|
||||
frn = tcg_temp_new_i64();
|
||||
frm = tcg_temp_new_i64();
|
||||
dest = tcg_temp_new_i64();
|
||||
|
||||
zf = tcg_temp_new_i64();
|
||||
nf = tcg_temp_new_i64();
|
||||
vf = tcg_temp_new_i64();
|
||||
|
||||
tcg_gen_extu_i32_i64(zf, cpu_ZF);
|
||||
tcg_gen_ext_i32_i64(nf, cpu_NF);
|
||||
tcg_gen_ext_i32_i64(vf, cpu_VF);
|
||||
|
||||
tcg_gen_ld_f64(frn, cpu_env, vfp_reg_offset(dp, rn));
|
||||
tcg_gen_ld_f64(frm, cpu_env, vfp_reg_offset(dp, rm));
|
||||
switch (cc) {
|
||||
case 0: /* eq: Z */
|
||||
tcg_gen_movcond_i64(TCG_COND_EQ, dest, zf, zero,
|
||||
frn, frm);
|
||||
break;
|
||||
case 1: /* vs: V */
|
||||
tcg_gen_movcond_i64(TCG_COND_LT, dest, vf, zero,
|
||||
frn, frm);
|
||||
break;
|
||||
case 2: /* ge: N == V -> N ^ V == 0 */
|
||||
tmp = tcg_temp_new_i64();
|
||||
tcg_gen_xor_i64(tmp, vf, nf);
|
||||
tcg_gen_movcond_i64(TCG_COND_GE, dest, tmp, zero,
|
||||
frn, frm);
|
||||
tcg_temp_free_i64(tmp);
|
||||
break;
|
||||
case 3: /* gt: !Z && N == V */
|
||||
tcg_gen_movcond_i64(TCG_COND_NE, dest, zf, zero,
|
||||
frn, frm);
|
||||
tmp = tcg_temp_new_i64();
|
||||
tcg_gen_xor_i64(tmp, vf, nf);
|
||||
tcg_gen_movcond_i64(TCG_COND_GE, dest, tmp, zero,
|
||||
dest, frm);
|
||||
tcg_temp_free_i64(tmp);
|
||||
break;
|
||||
}
|
||||
tcg_gen_st_f64(dest, cpu_env, vfp_reg_offset(dp, rd));
|
||||
tcg_temp_free_i64(frn);
|
||||
tcg_temp_free_i64(frm);
|
||||
tcg_temp_free_i64(dest);
|
||||
|
||||
tcg_temp_free_i64(zf);
|
||||
tcg_temp_free_i64(nf);
|
||||
tcg_temp_free_i64(vf);
|
||||
|
||||
tcg_temp_free_i64(zero);
|
||||
} else {
|
||||
TCGv_i32 frn, frm, dest;
|
||||
TCGv_i32 tmp, zero;
|
||||
|
||||
zero = tcg_const_i32(0);
|
||||
|
||||
frn = tcg_temp_new_i32();
|
||||
frm = tcg_temp_new_i32();
|
||||
dest = tcg_temp_new_i32();
|
||||
tcg_gen_ld_f32(frn, cpu_env, vfp_reg_offset(dp, rn));
|
||||
tcg_gen_ld_f32(frm, cpu_env, vfp_reg_offset(dp, rm));
|
||||
switch (cc) {
|
||||
case 0: /* eq: Z */
|
||||
tcg_gen_movcond_i32(TCG_COND_EQ, dest, cpu_ZF, zero,
|
||||
frn, frm);
|
||||
break;
|
||||
case 1: /* vs: V */
|
||||
tcg_gen_movcond_i32(TCG_COND_LT, dest, cpu_VF, zero,
|
||||
frn, frm);
|
||||
break;
|
||||
case 2: /* ge: N == V -> N ^ V == 0 */
|
||||
tmp = tcg_temp_new_i32();
|
||||
tcg_gen_xor_i32(tmp, cpu_VF, cpu_NF);
|
||||
tcg_gen_movcond_i32(TCG_COND_GE, dest, tmp, zero,
|
||||
frn, frm);
|
||||
tcg_temp_free_i32(tmp);
|
||||
break;
|
||||
case 3: /* gt: !Z && N == V */
|
||||
tcg_gen_movcond_i32(TCG_COND_NE, dest, cpu_ZF, zero,
|
||||
frn, frm);
|
||||
tmp = tcg_temp_new_i32();
|
||||
tcg_gen_xor_i32(tmp, cpu_VF, cpu_NF);
|
||||
tcg_gen_movcond_i32(TCG_COND_GE, dest, tmp, zero,
|
||||
dest, frm);
|
||||
tcg_temp_free_i32(tmp);
|
||||
break;
|
||||
}
|
||||
tcg_gen_st_f32(dest, cpu_env, vfp_reg_offset(dp, rd));
|
||||
tcg_temp_free_i32(frn);
|
||||
tcg_temp_free_i32(frm);
|
||||
tcg_temp_free_i32(dest);
|
||||
|
||||
tcg_temp_free_i32(zero);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int disas_vfp_v8_insn(CPUARMState *env, DisasContext *s, uint32_t insn)
|
||||
{
|
||||
uint32_t rd, rn, rm, dp = extract32(insn, 8, 1);
|
||||
|
||||
if (!arm_feature(env, ARM_FEATURE_V8)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (dp) {
|
||||
VFP_DREG_D(rd, insn);
|
||||
VFP_DREG_N(rn, insn);
|
||||
VFP_DREG_M(rm, insn);
|
||||
} else {
|
||||
rd = VFP_SREG_D(insn);
|
||||
rn = VFP_SREG_N(insn);
|
||||
rm = VFP_SREG_M(insn);
|
||||
}
|
||||
|
||||
if ((insn & 0x0f800e50) == 0x0e000a00) {
|
||||
return handle_vsel(insn, rd, rn, rm, dp);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Disassemble a VFP instruction. Returns nonzero if an error occurred
|
||||
(ie. an undefined instruction). */
|
||||
static int disas_vfp_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
|
||||
@ -2641,7 +2774,7 @@ static int disas_vfp_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
|
||||
/* Encodings with T=1 (Thumb) or unconditional (ARM):
|
||||
* only used in v8 and above.
|
||||
*/
|
||||
return 1;
|
||||
return disas_vfp_v8_insn(env, s, insn);
|
||||
}
|
||||
|
||||
dp = ((insn & 0xf00) == 0xb00);
|
||||
|
Loading…
Reference in New Issue
Block a user