diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2013-12-23 23:27:31 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2013-12-23 23:27:31 +0000 |
commit | ce5458e82e250c66fe31c716d0e44fac5b1bc349 (patch) | |
tree | 42fa4b45ae42362df7c0511ea647b1554ad07e1e | |
parent | faa0ba465b772200e9775c1f5af886cfc83d0da6 (diff) | |
download | qemu-ce5458e82e250c66fe31c716d0e44fac5b1bc349.zip qemu-ce5458e82e250c66fe31c716d0e44fac5b1bc349.tar.gz qemu-ce5458e82e250c66fe31c716d0e44fac5b1bc349.tar.bz2 |
target-arm: A64: implement FMOV
Implement FMOV, ie non-converting moves between general purpose
registers and floating point registers. This is a subtype of
the floating point <-> integer instruction class.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
-rw-r--r-- | target-arm/translate-a64.c | 86 |
1 files changed, 85 insertions, 1 deletions
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c index 079c2f7..7d98337 100644 --- a/target-arm/translate-a64.c +++ b/target-arm/translate-a64.c @@ -2758,6 +2758,63 @@ static void disas_fp_fixed_conv(DisasContext *s, uint32_t insn) unsupported_encoding(s, insn); } +static void handle_fmov(DisasContext *s, int rd, int rn, int type, bool itof) +{ + /* FMOV: gpr to or from float, double, or top half of quad fp reg, + * without conversion. + */ + + if (itof) { + int freg_offs = offsetof(CPUARMState, vfp.regs[rd * 2]); + TCGv_i64 tcg_rn = cpu_reg(s, rn); + + switch (type) { + case 0: + { + /* 32 bit */ + TCGv_i64 tmp = tcg_temp_new_i64(); + tcg_gen_ext32u_i64(tmp, tcg_rn); + tcg_gen_st_i64(tmp, cpu_env, freg_offs); + tcg_gen_movi_i64(tmp, 0); + tcg_gen_st_i64(tmp, cpu_env, freg_offs + sizeof(float64)); + tcg_temp_free_i64(tmp); + break; + } + case 1: + { + /* 64 bit */ + TCGv_i64 tmp = tcg_const_i64(0); + tcg_gen_st_i64(tcg_rn, cpu_env, freg_offs); + tcg_gen_st_i64(tmp, cpu_env, freg_offs + sizeof(float64)); + tcg_temp_free_i64(tmp); + break; + } + case 2: + /* 64 bit to top half. */ + tcg_gen_st_i64(tcg_rn, cpu_env, freg_offs + sizeof(float64)); + break; + } + } else { + int freg_offs = offsetof(CPUARMState, vfp.regs[rn * 2]); + TCGv_i64 tcg_rd = cpu_reg(s, rd); + + switch (type) { + case 0: + /* 32 bit */ + tcg_gen_ld32u_i64(tcg_rd, cpu_env, freg_offs); + break; + case 2: + /* 64 bits from top half */ + freg_offs += sizeof(float64); + /* fall through */ + case 1: + /* 64 bit */ + tcg_gen_ld_i64(tcg_rd, cpu_env, freg_offs); + break; + } + } +} + /* C3.6.30 Floating point <-> integer conversions * 31 30 29 28 24 23 22 21 20 19 18 16 15 10 9 5 4 0 * +----+---+---+-----------+------+---+-------+-----+-------------+----+----+ @@ -2766,7 +2823,34 @@ static void disas_fp_fixed_conv(DisasContext *s, uint32_t insn) */ static void disas_fp_int_conv(DisasContext *s, uint32_t insn) { - unsupported_encoding(s, insn); + int rd = extract32(insn, 0, 5); + int rn = extract32(insn, 5, 5); + int opcode = extract32(insn, 16, 3); + int rmode = extract32(insn, 19, 2); + int type = extract32(insn, 22, 2); + bool sbit = extract32(insn, 29, 1); + bool sf = extract32(insn, 31, 1); + + if (!sbit && (rmode < 2) && (opcode > 5)) { + /* FMOV */ + bool itof = opcode & 1; + + switch (sf << 3 | type << 1 | rmode) { + case 0x0: /* 32 bit */ + case 0xa: /* 64 bit */ + case 0xd: /* 64 bit to top half of quad */ + break; + default: + /* all other sf/type/rmode combinations are invalid */ + unallocated_encoding(s); + break; + } + + handle_fmov(s, rd, rn, type, itof); + } else { + /* actual FP conversions */ + unsupported_encoding(s, insn); + } } /* FP-specific subcases of table C3-6 (SIMD and FP data processing) |