diff mbox

target-arm: Implement ARMv8 VSEL instruction.

Message ID 524D3FAF.7020701@linaro.org
State Superseded
Headers show

Commit Message

Will Newton Oct. 3, 2013, 9:58 a.m. UTC
This adds support for the VSEL floating point selection instruction
which was added in ARMv8. It is based on the previous patch[1] from
Mans Rullgard, but attempts to addres the feedback given on that patch.

[1] http://lists.nongnu.org/archive/html/qemu-devel/2013-06/msg03117.html

Signed-off-by: Will Newton <will.newton@linaro.org>
---
 target-arm/translate.c | 121 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 121 insertions(+)

Comments

Alex Bennée Oct. 3, 2013, 11:31 a.m. UTC | #1
will.newton@linaro.org writes:

<snip>
> @@ -6756,6 +6864,13 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
>                  goto illegal_op;
>              return;
>          }
> +	if ((insn & 0x0f800e50) == 0x0e000a00) {
> +	    /* ARMv8 VFP.  */
> +	    ARCH(8);
> +
> +	    if (disas_v8vfp_insn(env, s, insn))
> +		goto illegal_op;
> +	}
>          if (((insn & 0x0f30f000) == 0x0510f000) ||
>              ((insn & 0x0f30f010) == 0x0710f000)) {
>              if ((insn & (1 << 22)) == 0) {
> @@ -8768,6 +8883,12 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
>              insn = (insn & 0xe2ffffff) | ((insn & (1 << 28)) >> 4) | (1 << 28);
>              if (disas_neon_data_insn(env, s, insn))
>                  goto illegal_op;
> +	} else if ((insn & 0x0f800e50) == 0x0e000a00) {
> +	    /* ARMv8 VFP.  */
> +	    ARCH(8);
> +
> +	    if (disas_v8vfp_insn(env, s, insn))
> +		goto illegal_op;
>          } else {
>              if (insn & (1 << 28))
>                  goto illegal_op;

I wonder is there a better way to deal with these masks for checking
instruction type? I only mention it because the same constant is used
twice and should it ever be changed there is a risk of one being missed
(although conceivably thumb encoding could be different?).

I appreciate the disassembler code is already a mass of magic constants
so it's not a major thing for me.

Cheers,
Peter Maydell Oct. 3, 2013, 12:11 p.m. UTC | #2
On 3 October 2013 20:31, Alex Bennée <alex.bennee@linaro.org> wrote:
>
> will.newton@linaro.org writes:
>
> <snip>
>> @@ -6756,6 +6864,13 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
>>                  goto illegal_op;
>>              return;
>>          }
>> +     if ((insn & 0x0f800e50) == 0x0e000a00) {
>> +         /* ARMv8 VFP.  */
>> +         ARCH(8);
>> +
>> +         if (disas_v8vfp_insn(env, s, insn))
>> +             goto illegal_op;
>> +     }
>>          if (((insn & 0x0f30f000) == 0x0510f000) ||
>>              ((insn & 0x0f30f010) == 0x0710f000)) {
>>              if ((insn & (1 << 22)) == 0) {
>> @@ -8768,6 +8883,12 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
>>              insn = (insn & 0xe2ffffff) | ((insn & (1 << 28)) >> 4) | (1 << 28);
>>              if (disas_neon_data_insn(env, s, insn))
>>                  goto illegal_op;
>> +     } else if ((insn & 0x0f800e50) == 0x0e000a00) {
>> +         /* ARMv8 VFP.  */
>> +         ARCH(8);
>> +
>> +         if (disas_v8vfp_insn(env, s, insn))
>> +             goto illegal_op;
>>          } else {
>>              if (insn & (1 << 28))
>>                  goto illegal_op;
>
> I wonder is there a better way to deal with these masks for checking
> instruction type? I only mention it because the same constant is used
> twice and should it ever be changed there is a risk of one being missed
> (although conceivably thumb encoding could be different?).

The v8 ARM ARM actually integrates this new instruction into the
decode tables for the existing VFP insns (it's an entry in table F5-16
'three register data floating point instructions'), which makes me wonder
if we should put the decode into the existing disas_vfp_insn()...

-- PMM
diff mbox

Patch

diff --git a/target-arm/translate.c b/target-arm/translate.c
index 998bde2..7bfd606 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -2617,6 +2617,114 @@  static TCGv_i32 gen_load_and_replicate(DisasContext *s, TCGv_i32 addr, int size)
     return tmp;
 }

+static int disas_v8vfp_insn(CPUARMState *env, DisasContext *s, uint32_t insn)
+{
+    uint32_t rd, rn, rm, dp = (insn >> 8) & 1;
+
+    if (!s->vfp_enabled)
+      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 >> 23) & 1) == 0) {
+        /* vsel */
+        uint32_t cc = (insn >> 20) & 3;
+	TCGv_i32 tmp, zero;
+
+	zero = tcg_const_tl(0);
+
+	if (dp) {
+	    TCGv_i64 ftmp1, ftmp2, ftmp3;
+
+	    ftmp1 = tcg_temp_new_i64();
+	    ftmp2 = tcg_temp_new_i64();
+	    ftmp3 = tcg_temp_new_i64();
+	    tcg_gen_ld_f64(ftmp1, cpu_env, vfp_reg_offset(dp, rn));
+	    tcg_gen_ld_f64(ftmp2, cpu_env, vfp_reg_offset(dp, rm));
+	    switch (cc) {
+	    case 0: /* eq: Z */
+		tcg_gen_movcond_i64(TCG_COND_EQ, ftmp3, cpu_ZF, zero,
+				    ftmp1, ftmp2);
+		break;
+	    case 1: /* vs: V */
+		tcg_gen_movcond_i64(TCG_COND_LT, ftmp3, cpu_VF, zero,
+				    ftmp1, ftmp2);
+		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_i64(TCG_COND_GE, ftmp3, tmp, zero,
+				    ftmp1, ftmp2);
+		tcg_temp_free_i32(tmp);
+		break;
+	    case 3: /* gt: !Z && N == V */
+		tcg_gen_movcond_i64(TCG_COND_NE, ftmp3, cpu_ZF, zero,
+				    ftmp1, ftmp2);
+		tmp = tcg_temp_new_i32();
+		tcg_gen_xor_i32(tmp, cpu_VF, cpu_NF);
+		tcg_gen_movcond_i64(TCG_COND_GE, ftmp3, tmp, zero,
+				    ftmp3, ftmp2);
+		tcg_temp_free_i32(tmp);
+		break;
+	    }
+	    tcg_gen_st_f64(ftmp3, cpu_env, vfp_reg_offset(dp, rd));
+	    tcg_temp_free_i64(ftmp1);
+	    tcg_temp_free_i64(ftmp2);
+	    tcg_temp_free_i64(ftmp3);
+	} else {
+	    TCGv_i32 ftmp1, ftmp2, ftmp3;
+
+	    ftmp1 = tcg_temp_new_i32();
+	    ftmp2 = tcg_temp_new_i32();
+	    ftmp3 = tcg_temp_new_i32();
+	    tcg_gen_ld_f32(ftmp1, cpu_env, vfp_reg_offset(dp, rn));
+	    tcg_gen_ld_f32(ftmp2, cpu_env, vfp_reg_offset(dp, rm));
+	    switch (cc) {
+	    case 0: /* eq: Z */
+		tcg_gen_movcond_i32(TCG_COND_EQ, ftmp3, cpu_ZF, zero,
+				    ftmp1, ftmp2);
+		break;
+	    case 1: /* vs: V */
+		tcg_gen_movcond_i32(TCG_COND_LT, ftmp3, cpu_VF, zero,
+				    ftmp1, ftmp2);
+		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, ftmp3, tmp, zero,
+				    ftmp1, ftmp2);
+		tcg_temp_free_i32(tmp);
+		break;
+	    case 3: /* gt: !Z && N == V */
+		tcg_gen_movcond_i32(TCG_COND_NE, ftmp3, cpu_ZF, zero,
+				    ftmp1, ftmp2);
+		tmp = tcg_temp_new_i32();
+		tcg_gen_xor_i32(tmp, cpu_VF, cpu_NF);
+		tcg_gen_movcond_i32(TCG_COND_GE, ftmp3, tmp, zero,
+				    ftmp3, ftmp2);
+		tcg_temp_free_i32(tmp);
+		break;
+	    }
+	    tcg_gen_st_f32(ftmp3, cpu_env, vfp_reg_offset(dp, rd));
+	    tcg_temp_free_i32(ftmp1);
+	    tcg_temp_free_i32(ftmp2);
+	    tcg_temp_free_i32(ftmp3);
+	}
+
+        return 0;
+    }
+
+    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)
@@ -6756,6 +6864,13 @@  static void disas_arm_insn(CPUARMState * env, DisasContext *s)
                 goto illegal_op;
             return;
         }
+	if ((insn & 0x0f800e50) == 0x0e000a00) {
+	    /* ARMv8 VFP.  */
+	    ARCH(8);
+
+	    if (disas_v8vfp_insn(env, s, insn))
+		goto illegal_op;
+	}
         if (((insn & 0x0f30f000) == 0x0510f000) ||
             ((insn & 0x0f30f010) == 0x0710f000)) {
             if ((insn & (1 << 22)) == 0) {
@@ -8768,6 +8883,12 @@  static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
             insn = (insn & 0xe2ffffff) | ((insn & (1 << 28)) >> 4) | (1 << 28);
             if (disas_neon_data_insn(env, s, insn))
                 goto illegal_op;
+	} else if ((insn & 0x0f800e50) == 0x0e000a00) {
+	    /* ARMv8 VFP.  */
+	    ARCH(8);
+
+	    if (disas_v8vfp_insn(env, s, insn))
+		goto illegal_op;
         } else {
             if (insn & (1 << 28))
                 goto illegal_op;