This covers all the floating point convert operations.
Signed-off-by: Alex Bennée
---
target/arm/helper-a64.c| 32 +
target/arm/helper-a64.h| 2 ++
target/arm/translate-a64.c | 85 +-
3 files changed, 118 insertions(+), 1 deletion(-)
diff --git a/target/arm/helper-a64.c b/target/arm/helper-a64.c
index 919b073635..76f3289e37 100644
--- a/target/arm/helper-a64.c
+++ b/target/arm/helper-a64.c
@@ -772,3 +772,35 @@ float16 HELPER(advsimd_rinth)(float16 x, void *fp_status)
return ret;
}
+
+/*
+ * Half-precision floating point conversion functions
+ *
+ * There are a multitude of conversion functions with various
+ * different rounding modes. This is dealt with by the calling code
+ * setting the mode appropriately before calling the helper.
+ */
+
+uint32_t HELPER(advsimd_f16tosinth)(float16 a, void *fpstp)
+{
+float_status *fpst = fpstp;
+
+/* Invalid if we are passed a NaN */
+if (float16_is_any_nan(a)) {
+float_raise(float_flag_invalid, fpst);
+return 0;
+}
+return float16_to_int16(a, fpst);
+}
+
+uint32_t HELPER(advsimd_f16touinth)(float16 a, void *fpstp)
+{
+float_status *fpst = fpstp;
+
+/* Invalid if we are passed a NaN */
+if (float16_is_any_nan(a)) {
+float_raise(float_flag_invalid, fpst);
+return 0;
+}
+return float16_to_uint16(a, fpst);
+}
diff --git a/target/arm/helper-a64.h b/target/arm/helper-a64.h
index b583bc0dd8..453753f4e7 100644
--- a/target/arm/helper-a64.h
+++ b/target/arm/helper-a64.h
@@ -78,3 +78,5 @@ DEF_HELPER_3(advsimd_acge_f16, i32, f16, f16, ptr)
DEF_HELPER_3(advsimd_acgt_f16, i32, f16, f16, ptr)
DEF_HELPER_2(advsimd_rinth_exact, f16, f16, ptr)
DEF_HELPER_2(advsimd_rinth, f16, f16, ptr)
+DEF_HELPER_2(advsimd_f16tosinth, i32, f16, ptr)
+DEF_HELPER_2(advsimd_f16touinth, i32, f16, ptr)
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
index a0506f094f..0049111e6d 100644
--- a/target/arm/translate-a64.c
+++ b/target/arm/translate-a64.c
@@ -10797,6 +10797,46 @@ static void disas_simd_two_reg_misc_fp16(DisasContext
*s, uint32_t insn)
only_in_vector = true;
/* current rounding mode */
break;
+case 0x1a: /* FCVTNS */
+need_rmode = true;
+rmode = FPROUNDING_TIEEVEN;
+break;
+case 0x1b: /* FCVTMS */
+need_rmode = true;
+rmode = FPROUNDING_NEGINF;
+break;
+case 0x1c: /* FCVTAS */
+need_rmode = true;
+rmode = FPROUNDING_TIEAWAY;
+break;
+case 0x3a: /* FCVTPS */
+need_rmode = true;
+rmode = FPROUNDING_POSINF;
+break;
+case 0x3b: /* FCVTZS */
+need_rmode = true;
+rmode = FPROUNDING_ZERO;
+break;
+case 0x5a: /* FCVTNU */
+need_rmode = true;
+rmode = FPROUNDING_TIEEVEN;
+break;
+case 0x5b: /* FCVTMU */
+need_rmode = true;
+rmode = FPROUNDING_NEGINF;
+break;
+case 0x5c: /* FCVTAU */
+need_rmode = true;
+rmode = FPROUNDING_TIEAWAY;
+break;
+case 0x7a: /* FCVTPU */
+need_rmode = true;
+rmode = FPROUNDING_POSINF;
+break;
+case 0x7b: /* FCVTZU */
+need_rmode = true;
+rmode = FPROUNDING_ZERO;
+break;
default:
fprintf(stderr, "%s: insn %#04x fpop %#2x\n", __func__, insn, fpop);
g_assert_not_reached();
@@ -10830,7 +10870,36 @@ static void disas_simd_two_reg_misc_fp16(DisasContext
*s, uint32_t insn)
}
if (is_scalar) {
-/* no operations yet */
+TCGv_i32 tcg_op = tcg_temp_new_i32();
+TCGv_i32 tcg_res = tcg_temp_new_i32();
+
+read_vec_element_i32(s, tcg_op, rn, 0, MO_16);
+
+switch (fpop) {
+case 0x1a: /* FCVTNS */
+case 0x1b: /* FCVTMS */
+case 0x1c: /* FCVTAS */
+case 0x3a: /* FCVTPS */
+case 0x3b: /* FCVTZS */
+gen_helper_advsimd_f16tosinth(tcg_res, tcg_op, tcg_fpstatus);
+break;
+case 0x5a: /* FCVTNU */
+case 0x5b: /* FCVTMU */
+case 0x5c: /* FCVTAU */
+case 0x7a: /* FCVTPU */
+case 0x7b: /* FCVTZU */
+gen_helper_advsimd_f16touinth(tcg_res, tcg_op, tcg_fpstatus);
+break;
+default:
+g_assert_not_reached();
+}
+
+/* limit any sign extension going on */
+tcg_gen_andi_i32(tcg_res, tcg_res, 0x);
+write_fp_sreg(s, rd, tcg_res);
+
+tcg_temp_free_i32(tcg_res);
+tcg_temp_free_i32(tcg_op);
} else {
for (pass = 0; pass < (is_q ? 8 : 4); pass++) {
TCGv_i32 tcg_op = tcg_temp_new_i32();
@@ -10839,6 +10908,20 @@ static void disas_simd_two_reg_misc_fp16(DisasContext
*s, uint32_t insn)
read_vec_element_i32(s, tcg_op, rn, pass, MO_16);
switch (fpop) {
+case 0x1a: /* FCVTNS */
+case 0x1b: /* FCVTMS */
+