qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 50/60] AArch64: Add "Floating-point<->fixed-point


From: Alexander Graf
Subject: [Qemu-devel] [PATCH 50/60] AArch64: Add "Floating-point<->fixed-point
Date: Fri, 27 Sep 2013 02:48:44 +0200

This patch adds emulation for the instruction group labeled
"Floating-point <-> fixed-point conversions" in the ARM ARM.

Namely this includes the instructions SCVTF, UCVTF, FCVTZS, FCVTZU
(scalar, fixed-point).

Signed-off-by: Alexander Graf <address@hidden>
---
 target-arm/helper-a64.c    |  22 ++++++
 target-arm/helper-a64.h    |   1 +
 target-arm/translate-a64.c | 173 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 196 insertions(+)

diff --git a/target-arm/helper-a64.c b/target-arm/helper-a64.c
index a46b00e..0b7aee1 100644
--- a/target-arm/helper-a64.c
+++ b/target-arm/helper-a64.c
@@ -275,3 +275,25 @@ uint64_t HELPER(smulh)(uint64_t n, uint64_t m)
     muls64(&rl, &rh, n, m);
     return rh;
 }
+
+void HELPER(set_rmode)(uint32_t rmode, void *fp_status)
+{
+    switch (rmode) {
+    case ROUND_MODE_TIEEVEN:
+    default:
+        rmode = float_round_nearest_even;
+        break;
+    case ROUND_MODE_UP:
+        rmode = float_round_up;
+        break;
+    case ROUND_MODE_DOWN:
+        rmode = float_round_down;
+        break;
+    case ROUND_MODE_ZERO:
+        rmode = float_round_to_zero;
+        break;
+    /* XXX add fpcr rounding (exact and not exact) */
+    }
+
+    set_float_rounding_mode(rmode, fp_status);
+}
diff --git a/target-arm/helper-a64.h b/target-arm/helper-a64.h
index 41dedd7..f42edf8 100644
--- a/target-arm/helper-a64.h
+++ b/target-arm/helper-a64.h
@@ -30,3 +30,4 @@ DEF_HELPER_FLAGS_1(rbit64, TCG_CALL_NO_RWG_SE, i64, i64)
 DEF_HELPER_FLAGS_1(clz64, TCG_CALL_NO_RWG_SE, i64, i64)
 DEF_HELPER_FLAGS_2(umulh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
 DEF_HELPER_FLAGS_2(smulh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
+DEF_HELPER_2(set_rmode, void, i32, ptr)
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 5985c01..654e011 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -183,6 +183,17 @@ static void clear_fpreg(int dest)
     tcg_gen_st_i64(tcg_zero, cpu_env, freg_offs + sizeof(float64));
 }
 
+static TCGv_ptr get_fpstatus_ptr(void)
+{
+    TCGv_ptr statusptr = tcg_temp_new_ptr();
+    int offset;
+
+    offset = offsetof(CPUARMState, vfp.standard_fp_status);
+    tcg_gen_addi_ptr(statusptr, cpu_env, offset);
+
+    return statusptr;
+}
+
 static inline void gen_goto_tb(DisasContext *s, int n, uint64_t dest)
 {
     TranslationBlock *tb;
@@ -1718,6 +1729,161 @@ static void handle_dp3s(DisasContext *s, uint32_t insn)
     tcg_temp_free_i64(tcg_tmp);
 }
 
+static void handle_fpfpcvt(DisasContext *s, uint32_t insn, bool direction,
+                           int rmode)
+{
+    int rd = get_reg(insn);
+    int rn = get_bits(insn, 5, 5);
+    int scale = get_bits(insn, 10, 6);
+    int opcode = get_bits(insn, 16, 3);
+    int type = get_bits(insn, 22, 2);
+    bool is_32bit = !get_bits(insn, 31, 1);
+    bool is_double = get_bits(type, 0, 1);
+    bool is_signed = !get_bits(opcode, 0, 1);
+    int freg_offs;
+    int fp_reg;
+    TCGv_i64 tcg_int;
+    TCGv_i64 tcg_single;
+    TCGv_i64 tcg_double;
+    TCGv_i64 tcg_fpstatus = get_fpstatus_ptr();
+    TCGv_i32 tcg_shift = tcg_const_i32(scale);
+    TCGv_i32 tcg_rmode = tcg_const_i32(rmode);
+    TCGv_i64 tcg_tmp;
+
+    if (direction) {
+        fp_reg = rn;
+        tcg_int = cpu_reg(rd);
+    } else {
+        fp_reg = rd;
+        tcg_int = cpu_reg(rn);
+    }
+    freg_offs = offsetof(CPUARMState, vfp.regs[fp_reg * 2]);
+
+    if (!direction) {
+        clear_fpreg(fp_reg);
+    }
+
+    if (is_32bit && !direction) {
+        tcg_tmp = tcg_temp_new_i64();
+        if (is_signed) {
+            tcg_gen_ext32s_i64(tcg_tmp, tcg_int);
+        } else {
+            tcg_gen_ext32u_i64(tcg_tmp, tcg_int);
+        }
+        tcg_int = tcg_tmp;
+    }
+
+    gen_helper_set_rmode(tcg_rmode, tcg_fpstatus);
+
+    switch ((direction ? 0x10 : 0)|
+            (is_double ? 0x1 : 0) |
+            (is_signed ? 0x2 : 0)) {
+    case 0x0: /* unsigned scalar->single */
+        tcg_single = tcg_temp_new_i32();
+        tcg_tmp = tcg_temp_new_i64();
+        gen_helper_vfp_uqtos(tcg_single, tcg_int, tcg_shift, tcg_fpstatus);
+        tcg_gen_extu_i32_i64(tcg_tmp, tcg_single);
+        tcg_gen_st32_i64(tcg_tmp, cpu_env, freg_offs);
+        tcg_temp_free_i32(tcg_single);
+        tcg_temp_free_i64(tcg_tmp);
+        break;
+    case 0x1: /* unsigned scalar->double */
+        tcg_double = tcg_temp_new_i64();
+        gen_helper_vfp_uqtod(tcg_double, tcg_int, tcg_shift, tcg_fpstatus);
+        tcg_gen_st_i64(tcg_double, cpu_env, freg_offs);
+        tcg_temp_free_i64(tcg_double);
+        break;
+    case 0x2: /* signed scalar->single */
+        tcg_single = tcg_temp_new_i32();
+        tcg_tmp = tcg_temp_new_i64();
+        gen_helper_vfp_sqtos(tcg_single, tcg_int, tcg_shift, tcg_fpstatus);
+        tcg_gen_extu_i32_i64(tcg_tmp, tcg_single);
+        tcg_gen_st32_i64(tcg_tmp, cpu_env, freg_offs);
+        tcg_temp_free_i32(tcg_single);
+        tcg_temp_free_i64(tcg_tmp);
+        break;
+    case 0x3: /* signed scalar->double */
+        tcg_double = tcg_temp_new_i64();
+        gen_helper_vfp_sqtod(tcg_double, tcg_int, tcg_shift, tcg_fpstatus);
+        tcg_gen_st_i64(tcg_double, cpu_env, freg_offs);
+        tcg_temp_free_i64(tcg_double);
+        break;
+    case 0x10: /* unsigned single->scalar */
+        tcg_single = tcg_temp_new_i32();
+        tcg_tmp = tcg_temp_new_i64();
+        tcg_gen_ld32u_i64(tcg_tmp, cpu_env, freg_offs);
+        tcg_gen_trunc_i64_i32(tcg_single, tcg_tmp);
+        gen_helper_vfp_touqs(tcg_int, tcg_single, tcg_shift, tcg_fpstatus);
+        tcg_temp_free_i32(tcg_single);
+        tcg_temp_free_i64(tcg_tmp);
+        break;
+    case 0x11: /* unsigned single->double */
+        tcg_double = tcg_temp_new_i64();
+        tcg_gen_ld_i64(tcg_double, cpu_env, freg_offs);
+        gen_helper_vfp_touqd(tcg_int, tcg_double, tcg_shift, tcg_fpstatus);
+        tcg_temp_free_i64(tcg_double);
+        break;
+    case 0x12: /* signed single->scalar */
+        tcg_single = tcg_temp_new_i32();
+        tcg_tmp = tcg_temp_new_i64();
+        tcg_gen_ld32u_i64(tcg_tmp, cpu_env, freg_offs);
+        tcg_gen_trunc_i64_i32(tcg_single, tcg_tmp);
+        gen_helper_vfp_tosqs(tcg_int, tcg_single, tcg_shift, tcg_fpstatus);
+        tcg_temp_free_i32(tcg_single);
+        tcg_temp_free_i64(tcg_tmp);
+        break;
+    case 0x13: /* signed single->double */
+        tcg_double = tcg_temp_new_i64();
+        tcg_gen_ld_i64(tcg_double, cpu_env, freg_offs);
+        gen_helper_vfp_tosqd(tcg_int, tcg_double, tcg_shift, tcg_fpstatus);
+        tcg_temp_free_i64(tcg_double);
+        break;
+    default:
+        unallocated_encoding(s);
+    }
+
+    /* XXX use fpcr */
+    tcg_gen_movi_i32(tcg_rmode, -1);
+    gen_helper_set_rmode(tcg_rmode, tcg_fpstatus);
+
+    if (is_32bit && direction) {
+        tcg_gen_ext32u_i64(tcg_int, tcg_int);
+    }
+
+    tcg_temp_free_i64(tcg_fpstatus);
+    tcg_temp_free_i32(tcg_shift);
+    tcg_temp_free_i32(tcg_rmode);
+}
+
+/* fixed <-> floating conversion */
+static void handle_fpfpconv(DisasContext *s, uint32_t insn)
+{
+    int opcode = get_bits(insn, 16, 3);
+    int rmode = get_bits(insn, 20, 2);
+    int type = get_bits(insn, 22, 2);
+    bool is_s = get_bits(insn, 29, 1);
+    bool direction;
+
+    if (is_s || (type > 1) || (opcode > 1)) {
+        unallocated_encoding(s);
+        return;
+    }
+
+    switch (rmode) {
+    case 0x1: /* [S|U]CVTF (scalar->float) */
+        direction = 0;
+        break;
+    case 0x3: /* FCVTZ[S|U] (float->scalar) */
+        direction = 1;
+        break;
+    default:
+        unallocated_encoding(s);
+        return;
+    }
+
+    handle_fpfpcvt(s, insn, direction, ROUND_MODE_ZERO);
+}
+
 /* SIMD ORR */
 static void handle_simdorr(DisasContext *s, uint32_t insn)
 {
@@ -2297,6 +2463,13 @@ void disas_a64_insn(CPUARMState *env, DisasContext *s)
     case 0x1b:
         handle_dp3s(s, insn);
         break;
+    case 0x1e:
+        if (!get_bits(insn, 21, 1) && !get_bits(insn, 30, 1)) {
+            handle_fpfpconv(s, insn);
+        } else {
+            unallocated_encoding(s);
+        }
+        break;
     default:
         unallocated_encoding(s);
         break;
-- 
1.7.12.4




reply via email to

[Prev in Thread] Current Thread [Next in Thread]