Skip to content

Commit

Permalink
target-arm: Implement ARMv8 VSEL instruction.
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Will Newton authored and pm215 committed Dec 10, 2013
1 parent 6a57f3e commit 04731fb
Showing 1 changed file with 134 additions and 1 deletion.
135 changes: 134 additions & 1 deletion target-arm/translate.c
Expand Up @@ -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)
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 04731fb

Please sign in to comment.