On 2013-09-27 02:48:44 +0200, Alexander Graf wrote:
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 ag...@suse.de
---
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);
shift/fractional bits are encoded encoded as 64 - scale for fixed point
to float conversion
feel free to grab
http://git.jannau.net/qemu.git/commit/?h=aarch64-tcg-batch1-v3-fixesid=16ff73c6801c0c0b677216457dacb64a7d310ad1
+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;