target-arm: A64: Floating point <-> integer conv
This is kinda from suse patch 52 but I ended up rewriting
it pretty thoroughly and with a view to comments made on the mailing
list w.r.t the silliness of double stores to the fpu reg memory).
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Inspired-by: Alexander Graf <agraf@suse.de> aarch64 series 52/60
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 80bdada..da6c742 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -2856,10 +2856,107 @@
}
}
+/* 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
+ +--+---+---+-----------+------+---+-------+--------+-------------+----+-----+
+ |sf| 0 | S | 1 1 1 1 0 | type | 1 | rmode | opcode | 0 0 0 0 0 0 | Rn | Rd |
+ +--+---+---+-----------+------+---+-------+--------+-------------+----+-----+
+*/
+static void disas_fpintconv(DisasContext *s, uint32_t 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;
+
+ /* gpr to float, double, or top half of quad fp reg. */
+ 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;
+ }
+
+
+ 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;
+ }
+ }
+ } else {
+ /* actual FP conversions */
+ unsupported_encoding(s, insn);
+ }
+}
+
/* C3.6 Data processing - SIMD and floating point */
static void disas_data_proc_simd_fp(DisasContext *s, uint32_t insn)
{
- unsupported_encoding(s, insn);
+ // TODO proper decode skeleton here
+ if (extract32(insn, 30, 1) == 0 &&
+ extract32(insn, 24, 5) == 0x1e &&
+ extract32(insn, 21, 1) == 1 &&
+ extract32(insn, 10, 6) == 0) {
+ disas_fpintconv(s, insn);
+ } else {
+ unsupported_encoding(s, insn);
+ }
}
/* C3.1 A64 instruction index by encoding */