[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 11/18] target-riscv: Add Double Precision Floating-P
From: |
Sagar Karandikar |
Subject: |
[Qemu-devel] [PATCH 11/18] target-riscv: Add Double Precision Floating-Point Instructions |
Date: |
Mon, 26 Sep 2016 03:56:41 -0700 |
Signed-off-by: Sagar Karandikar <address@hidden>
---
target-riscv/fpu_helper.c | 225 ++++++++++++++++++++++++++++++++++++++++++++++
target-riscv/helper.h | 30 +++++++
target-riscv/translate.c | 135 ++++++++++++++++++++++++++++
3 files changed, 390 insertions(+)
diff --git a/target-riscv/fpu_helper.c b/target-riscv/fpu_helper.c
index 8d33fa1..b3d443e 100644
--- a/target-riscv/fpu_helper.c
+++ b/target-riscv/fpu_helper.c
@@ -355,3 +355,228 @@ target_ulong helper_fclass_s(CPURISCVState *env, uint64_t
frs1)
frs1 = float32_classify(frs1, &env->fp_status);
return frs1;
}
+
+uint64_t helper_fadd_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
+ uint64_t rm)
+{
+ set_float_rounding_mode(RM, &env->fp_status);
+ frs1 = float64_add(frs1, frs2, &env->fp_status);
+ set_fp_exceptions();
+ return frs1;
+}
+
+uint64_t helper_fsub_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
+ uint64_t rm)
+{
+ set_float_rounding_mode(RM, &env->fp_status);
+ frs1 = float64_sub(frs1, frs2, &env->fp_status);
+ set_fp_exceptions();
+ return frs1;
+}
+
+uint64_t helper_fmul_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
+ uint64_t rm)
+{
+ set_float_rounding_mode(RM, &env->fp_status);
+ frs1 = float64_mul(frs1, frs2, &env->fp_status);
+ set_fp_exceptions();
+ return frs1;
+}
+
+uint64_t helper_fdiv_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
+ uint64_t rm)
+{
+ set_float_rounding_mode(RM, &env->fp_status);
+ frs1 = float64_div(frs1, frs2, &env->fp_status);
+ set_fp_exceptions();
+ return frs1;
+}
+
+uint64_t helper_fsgnj_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+ frs1 = (frs1 & ~INT64_MIN) | (frs2 & INT64_MIN);
+ return frs1;
+}
+
+uint64_t helper_fsgnjn_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+ frs1 = (frs1 & ~INT64_MIN) | ((~frs2) & INT64_MIN);
+ return frs1;
+}
+
+uint64_t helper_fsgnjx_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+ frs1 = frs1 ^ (frs2 & INT64_MIN);
+ return frs1;
+}
+
+uint64_t helper_fmin_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+ frs1 = float64_is_any_nan(frs2) ||
+ float64_lt_quiet(frs1, frs2, &env->fp_status) ? frs1 : frs2;
+ set_fp_exceptions();
+ return frs1;
+}
+
+uint64_t helper_fmax_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+ frs1 = float64_is_any_nan(frs2) ||
+ float64_le_quiet(frs2, frs1, &env->fp_status) ? frs1 : frs2;
+ set_fp_exceptions();
+ return frs1;
+}
+
+uint64_t helper_fcvt_s_d(CPURISCVState *env, uint64_t rs1, uint64_t rm)
+{
+ set_float_rounding_mode(RM, &env->fp_status);
+ rs1 = float64_to_float32(rs1, &env->fp_status);
+ set_fp_exceptions();
+ return rs1;
+}
+
+uint64_t helper_fcvt_d_s(CPURISCVState *env, uint64_t rs1, uint64_t rm)
+{
+ set_float_rounding_mode(RM, &env->fp_status);
+ rs1 = float32_to_float64(rs1, &env->fp_status);
+ set_fp_exceptions();
+ return rs1;
+}
+
+uint64_t helper_fsqrt_d(CPURISCVState *env, uint64_t frs1, uint64_t rm)
+{
+ set_float_rounding_mode(RM, &env->fp_status);
+ frs1 = float64_sqrt(frs1, &env->fp_status);
+ set_fp_exceptions();
+ return frs1;
+}
+
+target_ulong helper_fle_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+ frs1 = float64_le(frs1, frs2, &env->fp_status);
+ set_fp_exceptions();
+ return frs1;
+}
+
+target_ulong helper_flt_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+ frs1 = float64_lt(frs1, frs2, &env->fp_status);
+ set_fp_exceptions();
+ return frs1;
+}
+
+target_ulong helper_feq_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+ frs1 = float64_eq(frs1, frs2, &env->fp_status);
+ set_fp_exceptions();
+ return frs1;
+}
+
+target_ulong helper_fcvt_w_d(CPURISCVState *env, uint64_t frs1, uint64_t rm)
+{
+ set_float_rounding_mode(RM, &env->fp_status);
+ frs1 = (int64_t)((int32_t)float64_to_int32(frs1, &env->fp_status));
+ set_fp_exceptions();
+ return frs1;
+}
+
+target_ulong helper_fcvt_wu_d(CPURISCVState *env, uint64_t frs1, uint64_t rm)
+{
+ set_float_rounding_mode(RM, &env->fp_status);
+ frs1 = (int64_t)((int32_t)float64_to_uint32(frs1, &env->fp_status));
+ set_fp_exceptions();
+ return frs1;
+}
+
+#if defined(TARGET_RISCV64)
+uint64_t helper_fcvt_l_d(CPURISCVState *env, uint64_t frs1, uint64_t rm)
+{
+ set_float_rounding_mode(RM, &env->fp_status);
+ frs1 = float64_to_int64(frs1, &env->fp_status);
+ set_fp_exceptions();
+ return frs1;
+}
+
+uint64_t helper_fcvt_lu_d(CPURISCVState *env, uint64_t frs1, uint64_t rm)
+{
+ set_float_rounding_mode(RM, &env->fp_status);
+ frs1 = float64_to_uint64(frs1, &env->fp_status);
+ set_fp_exceptions();
+ return frs1;
+}
+#endif
+
+uint64_t helper_fcvt_d_w(CPURISCVState *env, target_ulong rs1, uint64_t rm)
+{
+ uint64_t res;
+ set_float_rounding_mode(RM, &env->fp_status);
+ res = int32_to_float64((int32_t)rs1, &env->fp_status);
+ set_fp_exceptions();
+ return res;
+}
+
+uint64_t helper_fcvt_d_wu(CPURISCVState *env, target_ulong rs1, uint64_t rm)
+{
+ uint64_t res;
+ set_float_rounding_mode(RM, &env->fp_status);
+ res = uint32_to_float64((uint32_t)rs1, &env->fp_status);
+ set_fp_exceptions();
+ return res;
+}
+
+#if defined(TARGET_RISCV64)
+uint64_t helper_fcvt_d_l(CPURISCVState *env, uint64_t rs1, uint64_t rm)
+{
+ set_float_rounding_mode(RM, &env->fp_status);
+ rs1 = int64_to_float64(rs1, &env->fp_status);
+ set_fp_exceptions();
+ return rs1;
+}
+
+uint64_t helper_fcvt_d_lu(CPURISCVState *env, uint64_t rs1, uint64_t rm)
+{
+ set_float_rounding_mode(RM, &env->fp_status);
+ rs1 = uint64_to_float64(rs1, &env->fp_status);
+ set_fp_exceptions();
+ return rs1;
+}
+#endif
+
+/* adapted from spike */
+#define isNaNF64UI(ui) (UINT64_C(0xFFE0000000000000) \
+ < (uint64_t)((uint_fast64_t)ui << 1))
+#define signF64UI(a) ((bool)((uint64_t) a >> 63))
+#define expF64UI(a) ((int_fast16_t)(a >> 52) & 0x7FF)
+#define fracF64UI(a) (a & UINT64_C(0x000FFFFFFFFFFFFF))
+
+union ui64_f64 { uint64_t ui; uint64_t f; };
+
+uint_fast16_t float64_classify(uint64_t a, float_status *status)
+{
+ union ui64_f64 uA;
+ uint_fast64_t uiA;
+
+ uA.f = a;
+ uiA = uA.ui;
+
+ uint_fast16_t infOrNaN = expF64UI(uiA) == 0x7FF;
+ uint_fast16_t subnormalOrZero = expF64UI(uiA) == 0;
+ bool sign = signF64UI(uiA);
+
+ return
+ (sign && infOrNaN && fracF64UI(uiA) == 0) << 0 |
+ (sign && !infOrNaN && !subnormalOrZero) << 1 |
+ (sign && subnormalOrZero && fracF64UI(uiA)) << 2 |
+ (sign && subnormalOrZero && fracF64UI(uiA) == 0) << 3 |
+ (!sign && infOrNaN && fracF64UI(uiA) == 0) << 7 |
+ (!sign && !infOrNaN && !subnormalOrZero) << 6 |
+ (!sign && subnormalOrZero && fracF64UI(uiA)) << 5 |
+ (!sign && subnormalOrZero && fracF64UI(uiA) == 0) << 4 |
+ (isNaNF64UI(uiA) && float64_is_signaling_nan(uiA, status)) << 8 |
+ (isNaNF64UI(uiA) && !float64_is_signaling_nan(uiA, status)) << 9;
+}
+
+target_ulong helper_fclass_d(CPURISCVState *env, uint64_t frs1)
+{
+ frs1 = float64_classify(frs1, &env->fp_status);
+ return frs1;
+}
diff --git a/target-riscv/helper.h b/target-riscv/helper.h
index 85b505a..eeb1caf 100644
--- a/target-riscv/helper.h
+++ b/target-riscv/helper.h
@@ -44,3 +44,33 @@ DEF_HELPER_FLAGS_3(fcvt_s_l, TCG_CALL_NO_RWG, i64, env, i64,
i64)
DEF_HELPER_FLAGS_3(fcvt_s_lu, TCG_CALL_NO_RWG, i64, env, i64, i64)
#endif
DEF_HELPER_FLAGS_2(fclass_s, TCG_CALL_NO_RWG, tl, env, i64)
+
+/* Floating Point - Double Precision */
+DEF_HELPER_FLAGS_4(fadd_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64)
+DEF_HELPER_FLAGS_4(fsub_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64)
+DEF_HELPER_FLAGS_4(fmul_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64)
+DEF_HELPER_FLAGS_4(fdiv_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64)
+DEF_HELPER_FLAGS_3(fsgnj_d, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(fsgnjn_d, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(fsgnjx_d, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(fmin_d, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(fmax_d, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(fcvt_s_d, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(fcvt_d_s, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(fsqrt_d, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(fle_d, TCG_CALL_NO_RWG, tl, env, i64, i64)
+DEF_HELPER_FLAGS_3(flt_d, TCG_CALL_NO_RWG, tl, env, i64, i64)
+DEF_HELPER_FLAGS_3(feq_d, TCG_CALL_NO_RWG, tl, env, i64, i64)
+DEF_HELPER_FLAGS_3(fcvt_w_d, TCG_CALL_NO_RWG, tl, env, i64, i64)
+DEF_HELPER_FLAGS_3(fcvt_wu_d, TCG_CALL_NO_RWG, tl, env, i64, i64)
+#if defined(TARGET_RISCV64)
+DEF_HELPER_FLAGS_3(fcvt_l_d, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(fcvt_lu_d, TCG_CALL_NO_RWG, i64, env, i64, i64)
+#endif
+DEF_HELPER_FLAGS_3(fcvt_d_w, TCG_CALL_NO_RWG, i64, env, tl, i64)
+DEF_HELPER_FLAGS_3(fcvt_d_wu, TCG_CALL_NO_RWG, i64, env, tl, i64)
+#if defined(TARGET_RISCV64)
+DEF_HELPER_FLAGS_3(fcvt_d_l, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(fcvt_d_lu, TCG_CALL_NO_RWG, i64, env, i64, i64)
+#endif
+DEF_HELPER_FLAGS_2(fclass_d, TCG_CALL_NO_RWG, tl, env, i64)
diff --git a/target-riscv/translate.c b/target-riscv/translate.c
index 4140769..de39276 100644
--- a/target-riscv/translate.c
+++ b/target-riscv/translate.c
@@ -1015,6 +1015,141 @@ static inline void gen_fp_arith(DisasContext *ctx,
uint32_t opc, int rd,
tcg_gen_extu_i32_i64(cpu_fpr[rd], write_int_rd);
#endif
break;
+ /* double */
+ case OPC_RISC_FADD_D:
+ gen_helper_fadd_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2],
+ rm_reg);
+ break;
+ case OPC_RISC_FSUB_D:
+ gen_helper_fsub_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2],
+ rm_reg);
+ break;
+ case OPC_RISC_FMUL_D:
+ gen_helper_fmul_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2],
+ rm_reg);
+ break;
+ case OPC_RISC_FDIV_D:
+ gen_helper_fdiv_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2],
+ rm_reg);
+ break;
+ case OPC_RISC_FSGNJ_D:
+ /* also OPC_RISC_FSGNJN_D, OPC_RISC_FSGNJX_D */
+ if (rm == 0x0) {
+ gen_helper_fsgnj_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1],
+ cpu_fpr[rs2]);
+ } else if (rm == 0x1) {
+ gen_helper_fsgnjn_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1],
+ cpu_fpr[rs2]);
+ } else if (rm == 0x2) {
+ gen_helper_fsgnjx_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1],
+ cpu_fpr[rs2]);
+ } else {
+ kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+ }
+ break;
+ case OPC_RISC_FMIN_D:
+ /* also OPC_RISC_FMAX_D */
+ if (rm == 0x0) {
+ gen_helper_fmin_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1],
cpu_fpr[rs2]);
+ } else if (rm == 0x1) {
+ gen_helper_fmax_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1],
cpu_fpr[rs2]);
+ } else {
+ kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+ }
+ break;
+ case OPC_RISC_FCVT_S_D:
+ if (rs2 == 0x1) {
+ gen_helper_fcvt_s_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], rm_reg);
+ } else {
+ kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+ }
+ break;
+ case OPC_RISC_FCVT_D_S:
+ if (rs2 == 0x0) {
+ gen_helper_fcvt_d_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], rm_reg);
+ } else {
+ kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+ }
+ break;
+ case OPC_RISC_FSQRT_D:
+ gen_helper_fsqrt_d(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], rm_reg);
+ break;
+ case OPC_RISC_FEQ_D:
+ /* also OPC_RISC_FLT_D, OPC_RISC_FLE_D */
+ if (rm == 0x0) {
+ gen_helper_fle_d(write_int_rd, cpu_env, cpu_fpr[rs1],
cpu_fpr[rs2]);
+ } else if (rm == 0x1) {
+ gen_helper_flt_d(write_int_rd, cpu_env, cpu_fpr[rs1],
cpu_fpr[rs2]);
+ } else if (rm == 0x2) {
+ gen_helper_feq_d(write_int_rd, cpu_env, cpu_fpr[rs1],
cpu_fpr[rs2]);
+ } else {
+ kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+ }
+ gen_set_gpr(rd, write_int_rd);
+ break;
+ case OPC_RISC_FCVT_W_D:
+ /* also OPC_RISC_FCVT_WU_D, OPC_RISC_FCVT_L_D, OPC_RISC_FCVT_LU_D */
+ if (rs2 == 0x0) {
+ gen_helper_fcvt_w_d(write_int_rd, cpu_env, cpu_fpr[rs1], rm_reg);
+ } else if (rs2 == 0x1) {
+ gen_helper_fcvt_wu_d(write_int_rd, cpu_env, cpu_fpr[rs1], rm_reg);
+ } else if (rs2 == 0x2) {
+#if defined(TARGET_RISCV64)
+ gen_helper_fcvt_l_d(write_int_rd, cpu_env, cpu_fpr[rs1], rm_reg);
+#else
+ kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+#endif
+ } else if (rs2 == 0x3) {
+#if defined(TARGET_RISCV64)
+ gen_helper_fcvt_lu_d(write_int_rd, cpu_env, cpu_fpr[rs1], rm_reg);
+#else
+ kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+#endif
+ } else {
+ kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+ }
+ gen_set_gpr(rd, write_int_rd);
+ break;
+ case OPC_RISC_FCVT_D_W:
+ /* also OPC_RISC_FCVT_D_WU, OPC_RISC_FCVT_D_L, OPC_RISC_FCVT_D_LU */
+ gen_get_gpr(write_int_rd, rs1);
+ if (rs2 == 0x0) {
+ gen_helper_fcvt_d_w(cpu_fpr[rd], cpu_env, write_int_rd, rm_reg);
+ } else if (rs2 == 0x1) {
+ gen_helper_fcvt_d_wu(cpu_fpr[rd], cpu_env, write_int_rd, rm_reg);
+ } else if (rs2 == 0x2) {
+#if defined(TARGET_RISCV64)
+ gen_helper_fcvt_d_l(cpu_fpr[rd], cpu_env, write_int_rd, rm_reg);
+#else
+ kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+#endif
+ } else if (rs2 == 0x3) {
+#if defined(TARGET_RISCV64)
+ gen_helper_fcvt_d_lu(cpu_fpr[rd], cpu_env, write_int_rd, rm_reg);
+#else
+ kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+#endif
+ } else {
+ kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+ }
+ break;
+#if defined(TARGET_RISCV64)
+ case OPC_RISC_FMV_X_D:
+ /* also OPC_RISC_FCLASS_D */
+ if (rm == 0x0) { /* FMV */
+ tcg_gen_mov_tl(write_int_rd, cpu_fpr[rs1]);
+ } else if (rm == 0x1) {
+ gen_helper_fclass_d(write_int_rd, cpu_env, cpu_fpr[rs1]);
+ } else {
+ kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+ }
+ gen_set_gpr(rd, write_int_rd);
+ break;
+ case OPC_RISC_FMV_D_X:
+ gen_get_gpr(write_int_rd, rs1);
+ tcg_gen_mov_tl(cpu_fpr[rd], write_int_rd);
+ break;
+#endif
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, 2016/09/26
[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 <=
[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
[Qemu-devel] [PATCH 02/18] target-riscv: Add RISC-V Target stubs inside target-riscv/, Sagar Karandikar, 2016/09/26
[Qemu-devel] [PATCH 17/18] target-riscv: Add support for Host-Target Interface (HTIF) Devices, Sagar Karandikar, 2016/09/26
Re: [Qemu-devel] [PATCH 00/18] target-riscv: Add full-system emulation support for the RISC-V Instruction Set Architecture (RV64G, RV32G), Paolo Bonzini, 2016/09/26