[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 09/18] target-riscv: Add FMADD, FMSUB, FNMADD, FNMSU
From: |
Sagar Karandikar |
Subject: |
[Qemu-devel] [PATCH 09/18] target-riscv: Add FMADD, FMSUB, FNMADD, FNMSUB Instructions, |
Date: |
Mon, 26 Sep 2016 03:56:39 -0700 |
Along with FP helper infrastructure, changes to softfloat-specialize
Signed-off-by: Sagar Karandikar <address@hidden>
---
fpu/softfloat-specialize.h | 7 ++-
target-riscv/Makefile.objs | 2 +-
target-riscv/fpu_helper.c | 151 +++++++++++++++++++++++++++++++++++++++++++++
target-riscv/helper.h | 10 +++
target-riscv/translate.c | 105 +++++++++++++++++++++++++++++++
5 files changed, 271 insertions(+), 4 deletions(-)
create mode 100644 target-riscv/fpu_helper.c
diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h
index f5aed72..fa5986d 100644
--- a/fpu/softfloat-specialize.h
+++ b/fpu/softfloat-specialize.h
@@ -114,7 +114,8 @@ float32 float32_default_nan(float_status *status)
#if defined(TARGET_SPARC)
return const_float32(0x7FFFFFFF);
#elif defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA) || \
- defined(TARGET_XTENSA) || defined(TARGET_S390X) ||
defined(TARGET_TRICORE)
+ defined(TARGET_XTENSA) || defined(TARGET_S390X) || \
+ defined(TARGET_TRICORE) || defined(TARGET_RISCV)
return const_float32(0x7FC00000);
#else
if (status->snan_bit_is_one) {
@@ -137,7 +138,7 @@ float64 float64_default_nan(float_status *status)
#if defined(TARGET_SPARC)
return const_float64(LIT64(0x7FFFFFFFFFFFFFFF));
#elif defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA) || \
- defined(TARGET_S390X)
+ defined(TARGET_S390X) || defined(TARGET_RISCV)
return const_float64(LIT64(0x7FF8000000000000));
#else
if (status->snan_bit_is_one) {
@@ -181,7 +182,7 @@ float128 float128_default_nan(float_status *status)
r.high = LIT64(0x7FFF7FFFFFFFFFFF);
} else {
r.low = LIT64(0x0000000000000000);
-#if defined(TARGET_S390X)
+#if defined(TARGET_S390X) || defined(TARGET_RISCV)
r.high = LIT64(0x7FFF800000000000);
#else
r.high = LIT64(0xFFFF800000000000);
diff --git a/target-riscv/Makefile.objs b/target-riscv/Makefile.objs
index cb448a8..0149732 100644
--- a/target-riscv/Makefile.objs
+++ b/target-riscv/Makefile.objs
@@ -1 +1 @@
-obj-y += translate.o op_helper.o helper.o cpu.o
+obj-y += translate.o op_helper.o helper.o cpu.o fpu_helper.o
diff --git a/target-riscv/fpu_helper.c b/target-riscv/fpu_helper.c
new file mode 100644
index 0000000..9023d10
--- /dev/null
+++ b/target-riscv/fpu_helper.c
@@ -0,0 +1,151 @@
+/*
+ * RISC-V FPU Emulation Helpers for QEMU.
+ *
+ * Author: Sagar Karandikar, address@hidden
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include <stdlib.h>
+#include "cpu.h"
+#include "qemu/host-utils.h"
+#include "exec/helper-proto.h"
+
+/* convert RISC-V rounding mode to IEEE library numbers */
+unsigned int ieee_rm[] = {
+ float_round_nearest_even,
+ float_round_to_zero,
+ float_round_down,
+ float_round_up,
+ float_round_ties_away
+};
+
+/* obtain rm value to use in computation
+ * as the last step, convert rm codes to what the softfloat library expects
+ * Adapted from Spike's decode.h:RM
+ */
+#define RM ({ \
+if (rm == 7) { \
+ rm = env->csr[CSR_FRM]; \
+} \
+if (rm > 4) { \
+ helper_raise_exception(env, RISCV_EXCP_ILLEGAL_INST); \
+} \
+ieee_rm[rm]; })
+
+/* convert softfloat library flag numbers to RISC-V */
+unsigned int softfloat_flags_to_riscv(unsigned int flag)
+{
+ switch (flag) {
+ case float_flag_inexact:
+ return 1;
+ case float_flag_underflow:
+ return 2;
+ case float_flag_overflow:
+ return 4;
+ case float_flag_divbyzero:
+ return 8;
+ case float_flag_invalid:
+ return 16;
+ default:
+ return 0;
+ }
+}
+
+/* adapted from Spike's decode.h:set_fp_exceptions */
+#define set_fp_exceptions() do { \
+ env->csr[CSR_FFLAGS] |=
softfloat_flags_to_riscv(get_float_exception_flags(\
+ &env->fp_status)); \
+ set_float_exception_flags(0, &env->fp_status); \
+} while (0)
+
+uint64_t helper_fmadd_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
+ uint64_t frs3, uint64_t rm)
+{
+ set_float_rounding_mode(RM, &env->fp_status);
+ frs1 = float32_muladd(frs1, frs2, frs3, 0, &env->fp_status);
+ set_fp_exceptions();
+ return frs1;
+}
+
+uint64_t helper_fmadd_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
+ uint64_t frs3, uint64_t rm)
+{
+ set_float_rounding_mode(RM, &env->fp_status);
+ frs1 = float64_muladd(frs1, frs2, frs3, 0, &env->fp_status);
+ set_fp_exceptions();
+ return frs1;
+}
+
+uint64_t helper_fmsub_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
+ uint64_t frs3, uint64_t rm)
+{
+ set_float_rounding_mode(RM, &env->fp_status);
+ frs1 = float32_muladd(frs1, frs2, frs3 ^ (uint32_t)INT32_MIN, 0,
+ &env->fp_status);
+ set_fp_exceptions();
+ return frs1;
+}
+
+uint64_t helper_fmsub_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
+ uint64_t frs3, uint64_t rm)
+{
+ set_float_rounding_mode(RM, &env->fp_status);
+ frs1 = float64_muladd(frs1, frs2, frs3 ^ (uint64_t)INT64_MIN, 0,
+ &env->fp_status);
+ set_fp_exceptions();
+ return frs1;
+}
+
+uint64_t helper_fnmsub_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
+ uint64_t frs3, uint64_t rm)
+{
+ set_float_rounding_mode(RM, &env->fp_status);
+ frs1 = float32_muladd(frs1 ^ (uint32_t)INT32_MIN, frs2, frs3, 0,
+ &env->fp_status);
+ set_fp_exceptions();
+ return frs1;
+}
+
+uint64_t helper_fnmsub_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
+ uint64_t frs3, uint64_t rm)
+{
+ set_float_rounding_mode(RM, &env->fp_status);
+ frs1 = float64_muladd(frs1 ^ (uint64_t)INT64_MIN, frs2, frs3, 0,
+ &env->fp_status);
+ set_fp_exceptions();
+ return frs1;
+}
+
+uint64_t helper_fnmadd_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
+ uint64_t frs3, uint64_t rm)
+{
+ set_float_rounding_mode(RM, &env->fp_status);
+ frs1 = float32_muladd(frs1 ^ (uint32_t)INT32_MIN, frs2,
+ frs3 ^ (uint32_t)INT32_MIN, 0, &env->fp_status);
+ set_fp_exceptions();
+ return frs1;
+}
+
+uint64_t helper_fnmadd_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
+ uint64_t frs3, uint64_t rm)
+{
+ set_float_rounding_mode(RM, &env->fp_status);
+ frs1 = float64_muladd(frs1 ^ (uint64_t)INT64_MIN, frs2,
+ frs3 ^ (uint64_t)INT64_MIN, 0, &env->fp_status);
+ set_fp_exceptions();
+ return frs1;
+}
diff --git a/target-riscv/helper.h b/target-riscv/helper.h
index c489222..586abae5 100644
--- a/target-riscv/helper.h
+++ b/target-riscv/helper.h
@@ -6,3 +6,13 @@ DEF_HELPER_3(raise_exception_mbadaddr, noreturn, env, i32, tl)
#if defined(TARGET_RISCV64)
DEF_HELPER_FLAGS_3(mulhsu, TCG_CALL_NO_RWG_SE, tl, env, tl, tl)
#endif
+
+/* Floating Point - fused */
+DEF_HELPER_FLAGS_5(fmadd_s, TCG_CALL_NO_RWG, i64, env, i64, i64, i64, i64)
+DEF_HELPER_FLAGS_5(fmadd_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64, i64)
+DEF_HELPER_FLAGS_5(fmsub_s, TCG_CALL_NO_RWG, i64, env, i64, i64, i64, i64)
+DEF_HELPER_FLAGS_5(fmsub_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64, i64)
+DEF_HELPER_FLAGS_5(fnmsub_s, TCG_CALL_NO_RWG, i64, env, i64, i64, i64, i64)
+DEF_HELPER_FLAGS_5(fnmsub_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64, i64)
+DEF_HELPER_FLAGS_5(fnmadd_s, TCG_CALL_NO_RWG, i64, env, i64, i64, i64, i64)
+DEF_HELPER_FLAGS_5(fnmadd_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64, i64)
diff --git a/target-riscv/translate.c b/target-riscv/translate.c
index af82eab..07f24e8 100644
--- a/target-riscv/translate.c
+++ b/target-riscv/translate.c
@@ -792,6 +792,95 @@ static inline void gen_atomic(DisasContext *ctx, uint32_t
opc,
tcg_temp_free(dat);
}
+static inline void gen_fp_fmadd(DisasContext *ctx, uint32_t opc, int rd,
+ int rs1, int rs2, int rs3, int rm)
+{
+ TCGv_i64 rm_reg = tcg_temp_new_i64();
+ tcg_gen_movi_i64(rm_reg, rm);
+
+ switch (opc) {
+ case OPC_RISC_FMADD_S:
+ gen_helper_fmadd_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2],
+ cpu_fpr[rs3], rm_reg);
+ break;
+ case OPC_RISC_FMADD_D:
+ gen_helper_fmadd_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2],
+ cpu_fpr[rs3], rm_reg);
+ break;
+ default:
+ kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+ break;
+ }
+ tcg_temp_free_i64(rm_reg);
+
+}
+
+static inline void gen_fp_fmsub(DisasContext *ctx, uint32_t opc, int rd,
+ int rs1, int rs2, int rs3, int rm)
+{
+ TCGv_i64 rm_reg = tcg_temp_new_i64();
+ tcg_gen_movi_i64(rm_reg, rm);
+
+ switch (opc) {
+ case OPC_RISC_FMSUB_S:
+ gen_helper_fmsub_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2],
+ cpu_fpr[rs3], rm_reg);
+ break;
+ case OPC_RISC_FMSUB_D:
+ gen_helper_fmsub_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2],
+ cpu_fpr[rs3], rm_reg);
+ break;
+ default:
+ kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+ break;
+ }
+ tcg_temp_free_i64(rm_reg);
+}
+
+static inline void gen_fp_fnmsub(DisasContext *ctx, uint32_t opc, int rd,
+ int rs1, int rs2, int rs3, int rm)
+{
+ TCGv_i64 rm_reg = tcg_temp_new_i64();
+ tcg_gen_movi_i64(rm_reg, rm);
+
+ switch (opc) {
+ case OPC_RISC_FNMSUB_S:
+ gen_helper_fnmsub_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2],
+ cpu_fpr[rs3], rm_reg);
+ break;
+ case OPC_RISC_FNMSUB_D:
+ gen_helper_fnmsub_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2],
+ cpu_fpr[rs3], rm_reg);
+ break;
+ default:
+ kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+ break;
+ }
+ tcg_temp_free_i64(rm_reg);
+}
+
+static inline void gen_fp_fnmadd(DisasContext *ctx, uint32_t opc, int rd,
+ int rs1, int rs2, int rs3, int rm)
+{
+ TCGv_i64 rm_reg = tcg_temp_new_i64();
+ tcg_gen_movi_i64(rm_reg, rm);
+
+ switch (opc) {
+ case OPC_RISC_FNMADD_S:
+ gen_helper_fnmadd_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2],
+ cpu_fpr[rs3], rm_reg);
+ break;
+ case OPC_RISC_FNMADD_D:
+ gen_helper_fnmadd_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2],
+ cpu_fpr[rs3], rm_reg);
+ break;
+ default:
+ kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+ break;
+ }
+ tcg_temp_free_i64(rm_reg);
+}
+
static void decode_opc(CPURISCVState *env, DisasContext *ctx)
{
int rs1;
@@ -900,6 +989,22 @@ static void decode_opc(CPURISCVState *env, DisasContext
*ctx)
case OPC_RISC_ATOMIC:
gen_atomic(ctx, MASK_OP_ATOMIC(ctx->opcode), rd, rs1, rs2);
break;
+ case OPC_RISC_FMADD:
+ gen_fp_fmadd(ctx, MASK_OP_FP_FMADD(ctx->opcode), rd, rs1, rs2,
+ GET_RS3(ctx->opcode), GET_RM(ctx->opcode));
+ break;
+ case OPC_RISC_FMSUB:
+ gen_fp_fmsub(ctx, MASK_OP_FP_FMSUB(ctx->opcode), rd, rs1, rs2,
+ GET_RS3(ctx->opcode), GET_RM(ctx->opcode));
+ break;
+ case OPC_RISC_FNMSUB:
+ gen_fp_fnmsub(ctx, MASK_OP_FP_FNMSUB(ctx->opcode), rd, rs1, rs2,
+ GET_RS3(ctx->opcode), GET_RM(ctx->opcode));
+ break;
+ case OPC_RISC_FNMADD:
+ gen_fp_fnmadd(ctx, MASK_OP_FP_FNMADD(ctx->opcode), rd, rs1, rs2,
+ GET_RS3(ctx->opcode), GET_RM(ctx->opcode));
+ break;
default:
kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
break;
--
2.9.3
[Qemu-devel] [PATCH 13/18] target-riscv: Add CSR read/write helpers, Sagar Karandikar, 2016/09/26
[Qemu-devel] [PATCH 09/18] target-riscv: Add FMADD, FMSUB, FNMADD, FNMSUB Instructions,,
Sagar Karandikar <=
- Re: [Qemu-devel] [PATCH 09/18] target-riscv: Add FMADD, FMSUB, FNMADD, FNMSUB Instructions,, Richard Henderson, 2016/09/26
- Re: [Qemu-devel] [PATCH 09/18] target-riscv: Add FMADD, FMSUB, FNMADD, FNMSUB Instructions,, Richard Henderson, 2016/09/27
[Qemu-devel] [PATCH 05/18] target-riscv: Add Arithmetic instructions, Sagar Karandikar, 2016/09/26
[Qemu-devel] [PATCH 18/18] target-riscv: Add generic test board, activate target, Sagar Karandikar, 2016/09/26
[Qemu-devel] [PATCH 11/18] target-riscv: Add Double Precision Floating-Point Instructions, Sagar Karandikar, 2016/09/26
[Qemu-devel] [PATCH 10/18] target-riscv: Add Single Precision Floating-Point Instructions, Sagar Karandikar, 2016/09/26
[Qemu-devel] [PATCH 04/18] target-riscv: Add framework for instruction decode, Sagar Karandikar, 2016/09/26