[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 10/18] target-riscv: Add Single Precision Floating-P
From: |
Sagar Karandikar |
Subject: |
[Qemu-devel] [PATCH 10/18] target-riscv: Add Single Precision Floating-Point Instructions |
Date: |
Mon, 26 Sep 2016 03:56:40 -0700 |
Signed-off-by: Sagar Karandikar <address@hidden>
---
target-riscv/fpu_helper.c | 206 ++++++++++++++++++++++++++++++++++++++++++++++
target-riscv/helper.h | 28 +++++++
target-riscv/translate.c | 146 ++++++++++++++++++++++++++++++++
3 files changed, 380 insertions(+)
diff --git a/target-riscv/fpu_helper.c b/target-riscv/fpu_helper.c
index 9023d10..8d33fa1 100644
--- a/target-riscv/fpu_helper.c
+++ b/target-riscv/fpu_helper.c
@@ -149,3 +149,209 @@ uint64_t helper_fnmadd_d(CPURISCVState *env, uint64_t
frs1, uint64_t frs2,
set_fp_exceptions();
return frs1;
}
+
+uint64_t helper_fadd_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
+ uint64_t rm)
+{
+ set_float_rounding_mode(RM, &env->fp_status);
+ frs1 = float32_add(frs1, frs2, &env->fp_status);
+ set_fp_exceptions();
+ return frs1;
+}
+
+uint64_t helper_fsub_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
+ uint64_t rm)
+{
+ set_float_rounding_mode(RM, &env->fp_status);
+ frs1 = float32_sub(frs1, frs2, &env->fp_status);
+ set_fp_exceptions();
+ return frs1;
+}
+
+uint64_t helper_fmul_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
+ uint64_t rm)
+{
+ set_float_rounding_mode(RM, &env->fp_status);
+ frs1 = float32_mul(frs1, frs2, &env->fp_status);
+ set_fp_exceptions();
+ return frs1;
+}
+
+uint64_t helper_fdiv_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2,
+ uint64_t rm)
+{
+ set_float_rounding_mode(RM, &env->fp_status);
+ frs1 = float32_div(frs1, frs2, &env->fp_status);
+ set_fp_exceptions();
+ return frs1;
+}
+
+uint64_t helper_fsgnj_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+ frs1 = (frs1 & ~(uint32_t)INT32_MIN) | (frs2 & (uint32_t)INT32_MIN);
+ return frs1;
+}
+
+uint64_t helper_fsgnjn_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+ frs1 = (frs1 & ~(uint32_t)INT32_MIN) | ((~frs2) & (uint32_t)INT32_MIN);
+ return frs1;
+}
+
+uint64_t helper_fsgnjx_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+ frs1 = frs1 ^ (frs2 & (uint32_t)INT32_MIN);
+ return frs1;
+}
+
+uint64_t helper_fmin_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+ frs1 = float32_is_any_nan(frs2) ||
+ float32_lt_quiet(frs1, frs2, &env->fp_status) ? frs1 : frs2;
+ set_fp_exceptions();
+ return frs1;
+}
+
+uint64_t helper_fmax_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+ frs1 = float32_is_any_nan(frs2) ||
+ float32_le_quiet(frs2, frs1, &env->fp_status) ? frs1 : frs2;
+ set_fp_exceptions();
+ return frs1;
+}
+
+uint64_t helper_fsqrt_s(CPURISCVState *env, uint64_t frs1, uint64_t rm)
+{
+ set_float_rounding_mode(RM, &env->fp_status);
+ frs1 = float32_sqrt(frs1, &env->fp_status);
+ set_fp_exceptions();
+ return frs1;
+}
+
+target_ulong helper_fle_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+ frs1 = float32_le(frs1, frs2, &env->fp_status);
+ set_fp_exceptions();
+ return frs1;
+}
+
+target_ulong helper_flt_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+ frs1 = float32_lt(frs1, frs2, &env->fp_status);
+ set_fp_exceptions();
+ return frs1;
+}
+
+target_ulong helper_feq_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
+{
+ frs1 = float32_eq(frs1, frs2, &env->fp_status);
+ set_fp_exceptions();
+ return frs1;
+}
+
+target_ulong helper_fcvt_w_s(CPURISCVState *env, uint64_t frs1, uint64_t rm)
+{
+ set_float_rounding_mode(RM, &env->fp_status);
+ frs1 = (int64_t)((int32_t)float32_to_int32(frs1, &env->fp_status));
+ set_fp_exceptions();
+ return frs1;
+}
+
+target_ulong helper_fcvt_wu_s(CPURISCVState *env, uint64_t frs1, uint64_t rm)
+{
+ set_float_rounding_mode(RM, &env->fp_status);
+ frs1 = (int64_t)((int32_t)float32_to_uint32(frs1, &env->fp_status));
+ set_fp_exceptions();
+ return frs1;
+}
+
+#if defined(TARGET_RISCV64)
+uint64_t helper_fcvt_l_s(CPURISCVState *env, uint64_t frs1, uint64_t rm)
+{
+ set_float_rounding_mode(RM, &env->fp_status);
+ frs1 = float32_to_int64(frs1, &env->fp_status);
+ set_fp_exceptions();
+ return frs1;
+}
+
+uint64_t helper_fcvt_lu_s(CPURISCVState *env, uint64_t frs1, uint64_t rm)
+{
+ set_float_rounding_mode(RM, &env->fp_status);
+ frs1 = float32_to_uint64(frs1, &env->fp_status);
+ set_fp_exceptions();
+ return frs1;
+}
+#endif
+
+uint64_t helper_fcvt_s_w(CPURISCVState *env, target_ulong rs1, uint64_t rm)
+{
+ set_float_rounding_mode(RM, &env->fp_status);
+ rs1 = int32_to_float32((int32_t)rs1, &env->fp_status);
+ set_fp_exceptions();
+ return rs1;
+}
+
+uint64_t helper_fcvt_s_wu(CPURISCVState *env, target_ulong rs1, uint64_t rm)
+{
+ set_float_rounding_mode(RM, &env->fp_status);
+ rs1 = uint32_to_float32((uint32_t)rs1, &env->fp_status);
+ set_fp_exceptions();
+ return rs1;
+}
+
+#if defined(TARGET_RISCV64)
+uint64_t helper_fcvt_s_l(CPURISCVState *env, uint64_t rs1, uint64_t rm)
+{
+ set_float_rounding_mode(RM, &env->fp_status);
+ rs1 = int64_to_float32(rs1, &env->fp_status);
+ set_fp_exceptions();
+ return rs1;
+}
+
+uint64_t helper_fcvt_s_lu(CPURISCVState *env, uint64_t rs1, uint64_t rm)
+{
+ set_float_rounding_mode(RM, &env->fp_status);
+ rs1 = uint64_to_float32(rs1, &env->fp_status);
+ set_fp_exceptions();
+ return rs1;
+}
+#endif
+
+/* adapted from spike */
+#define isNaNF32UI(ui) (0xFF000000 < (uint32_t)((uint_fast32_t)ui << 1))
+#define signF32UI(a) ((bool)((uint32_t)a >> 31))
+#define expF32UI(a) ((int_fast16_t)(a >> 23) & 0xFF)
+#define fracF32UI(a) (a & 0x007FFFFF)
+
+union ui32_f32 { uint32_t ui; uint32_t f; };
+
+uint_fast16_t float32_classify(uint32_t a, float_status *status)
+{
+ union ui32_f32 uA;
+ uint_fast32_t uiA;
+
+ uA.f = a;
+ uiA = uA.ui;
+
+ uint_fast16_t infOrNaN = expF32UI(uiA) == 0xFF;
+ uint_fast16_t subnormalOrZero = expF32UI(uiA) == 0;
+ bool sign = signF32UI(uiA);
+
+ return
+ (sign && infOrNaN && fracF32UI(uiA) == 0) << 0 |
+ (sign && !infOrNaN && !subnormalOrZero) << 1 |
+ (sign && subnormalOrZero && fracF32UI(uiA)) << 2 |
+ (sign && subnormalOrZero && fracF32UI(uiA) == 0) << 3 |
+ (!sign && infOrNaN && fracF32UI(uiA) == 0) << 7 |
+ (!sign && !infOrNaN && !subnormalOrZero) << 6 |
+ (!sign && subnormalOrZero && fracF32UI(uiA)) << 5 |
+ (!sign && subnormalOrZero && fracF32UI(uiA) == 0) << 4 |
+ (isNaNF32UI(uiA) && float32_is_signaling_nan(uiA, status)) << 8 |
+ (isNaNF32UI(uiA) && !float32_is_signaling_nan(uiA, status)) << 9;
+}
+
+target_ulong helper_fclass_s(CPURISCVState *env, uint64_t frs1)
+{
+ frs1 = float32_classify(frs1, &env->fp_status);
+ return frs1;
+}
diff --git a/target-riscv/helper.h b/target-riscv/helper.h
index 586abae5..85b505a 100644
--- a/target-riscv/helper.h
+++ b/target-riscv/helper.h
@@ -16,3 +16,31 @@ 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)
+
+/* Floating Point - Single Precision */
+DEF_HELPER_FLAGS_4(fadd_s, TCG_CALL_NO_RWG, i64, env, i64, i64, i64)
+DEF_HELPER_FLAGS_4(fsub_s, TCG_CALL_NO_RWG, i64, env, i64, i64, i64)
+DEF_HELPER_FLAGS_4(fmul_s, TCG_CALL_NO_RWG, i64, env, i64, i64, i64)
+DEF_HELPER_FLAGS_4(fdiv_s, TCG_CALL_NO_RWG, i64, env, i64, i64, i64)
+DEF_HELPER_FLAGS_3(fsgnj_s, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(fsgnjn_s, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(fsgnjx_s, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(fmin_s, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(fmax_s, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(fsqrt_s, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(fle_s, TCG_CALL_NO_RWG, tl, env, i64, i64)
+DEF_HELPER_FLAGS_3(flt_s, TCG_CALL_NO_RWG, tl, env, i64, i64)
+DEF_HELPER_FLAGS_3(feq_s, TCG_CALL_NO_RWG, tl, env, i64, i64)
+DEF_HELPER_FLAGS_3(fcvt_w_s, TCG_CALL_NO_RWG, tl, env, i64, i64)
+DEF_HELPER_FLAGS_3(fcvt_wu_s, TCG_CALL_NO_RWG, tl, env, i64, i64)
+#if defined(TARGET_RISCV64)
+DEF_HELPER_FLAGS_3(fcvt_l_s, TCG_CALL_NO_RWG, i64, env, i64, i64)
+DEF_HELPER_FLAGS_3(fcvt_lu_s, TCG_CALL_NO_RWG, i64, env, i64, i64)
+#endif
+DEF_HELPER_FLAGS_3(fcvt_s_w, TCG_CALL_NO_RWG, i64, env, tl, i64)
+DEF_HELPER_FLAGS_3(fcvt_s_wu, TCG_CALL_NO_RWG, i64, env, tl, i64)
+#if defined(TARGET_RISCV64)
+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)
diff --git a/target-riscv/translate.c b/target-riscv/translate.c
index 07f24e8..4140769 100644
--- a/target-riscv/translate.c
+++ b/target-riscv/translate.c
@@ -881,6 +881,148 @@ static inline void gen_fp_fnmadd(DisasContext *ctx,
uint32_t opc, int rd,
tcg_temp_free_i64(rm_reg);
}
+static inline void gen_fp_arith(DisasContext *ctx, uint32_t opc, int rd,
+ int rs1, int rs2, int rm)
+{
+ TCGv_i64 rm_reg = tcg_temp_new_i64();
+ TCGv write_int_rd = tcg_temp_new();
+ tcg_gen_movi_i64(rm_reg, rm);
+
+ switch (opc) {
+ case OPC_RISC_FADD_S:
+ gen_helper_fadd_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2],
+ rm_reg);
+ break;
+ case OPC_RISC_FSUB_S:
+ gen_helper_fsub_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2],
+ rm_reg);
+ break;
+ case OPC_RISC_FMUL_S:
+ gen_helper_fmul_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2],
+ rm_reg);
+ break;
+ case OPC_RISC_FDIV_S:
+ gen_helper_fdiv_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], cpu_fpr[rs2],
+ rm_reg);
+ break;
+ case OPC_RISC_FSGNJ_S:
+ /* also handles: OPC_RISC_FSGNJN_S, OPC_RISC_FSGNJX_S */
+ if (rm == 0x0) {
+ gen_helper_fsgnj_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1],
+ cpu_fpr[rs2]);
+ } else if (rm == 0x1) {
+ gen_helper_fsgnjn_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1],
+ cpu_fpr[rs2]);
+ } else if (rm == 0x2) {
+ gen_helper_fsgnjx_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1],
+ cpu_fpr[rs2]);
+ } else {
+ kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+ }
+ break;
+ case OPC_RISC_FMIN_S:
+ /* also handles: OPC_RISC_FMAX_S */
+ if (rm == 0x0) {
+ gen_helper_fmin_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1],
cpu_fpr[rs2]);
+ } else if (rm == 0x1) {
+ gen_helper_fmax_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1],
cpu_fpr[rs2]);
+ } else {
+ kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+ }
+ break;
+ case OPC_RISC_FSQRT_S:
+ gen_helper_fsqrt_s(cpu_fpr[rd], cpu_env, cpu_fpr[rs1], rm_reg);
+ break;
+ case OPC_RISC_FEQ_S:
+ /* also handles: OPC_RISC_FLT_S, OPC_RISC_FLE_S */
+ if (rm == 0x0) {
+ gen_helper_fle_s(write_int_rd, cpu_env, cpu_fpr[rs1],
cpu_fpr[rs2]);
+ } else if (rm == 0x1) {
+ gen_helper_flt_s(write_int_rd, cpu_env, cpu_fpr[rs1],
cpu_fpr[rs2]);
+ } else if (rm == 0x2) {
+ gen_helper_feq_s(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_S:
+ /* also OPC_RISC_FCVT_WU_S, OPC_RISC_FCVT_L_S, OPC_RISC_FCVT_LU_S */
+ if (rs2 == 0x0) { /* FCVT_W_S */
+ gen_helper_fcvt_w_s(write_int_rd, cpu_env, cpu_fpr[rs1], rm_reg);
+ } else if (rs2 == 0x1) { /* FCVT_WU_S */
+ gen_helper_fcvt_wu_s(write_int_rd, cpu_env, cpu_fpr[rs1], rm_reg);
+ } else if (rs2 == 0x2) { /* FCVT_L_S */
+#if defined(TARGET_RISCV64)
+ gen_helper_fcvt_l_s(write_int_rd, cpu_env, cpu_fpr[rs1], rm_reg);
+#else
+ kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+#endif
+ } else if (rs2 == 0x3) { /* FCVT_LU_S */
+#if defined(TARGET_RISCV64)
+ gen_helper_fcvt_lu_s(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_S_W:
+ /* also OPC_RISC_FCVT_S_WU, OPC_RISC_FCVT_S_L, OPC_RISC_FCVT_S_LU */
+ gen_get_gpr(write_int_rd, rs1);
+ if (rs2 == 0) { /* FCVT_S_W */
+ gen_helper_fcvt_s_w(cpu_fpr[rd], cpu_env, write_int_rd, rm_reg);
+ } else if (rs2 == 0x1) { /* FCVT_S_WU */
+ gen_helper_fcvt_s_wu(cpu_fpr[rd], cpu_env, write_int_rd, rm_reg);
+ } else if (rs2 == 0x2) { /* FCVT_S_L */
+#if defined(TARGET_RISCV64)
+ gen_helper_fcvt_s_l(cpu_fpr[rd], cpu_env, write_int_rd, rm_reg);
+#else
+ kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+#endif
+ } else if (rs2 == 0x3) { /* FCVT_S_LU */
+#if defined(TARGET_RISCV64)
+ gen_helper_fcvt_s_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;
+ case OPC_RISC_FMV_X_S:
+ /* also OPC_RISC_FCLASS_S */
+ if (rm == 0x0) { /* FMV */
+#if defined(TARGET_RISCV64)
+ tcg_gen_ext32s_tl(write_int_rd, cpu_fpr[rs1]);
+#else
+ tcg_gen_extrl_i64_i32(write_int_rd, cpu_fpr[rs1]);
+#endif
+ } else if (rm == 0x1) {
+ gen_helper_fclass_s(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_S_X:
+ gen_get_gpr(write_int_rd, rs1);
+#if defined(TARGET_RISCV64)
+ tcg_gen_mov_tl(cpu_fpr[rd], write_int_rd);
+#else
+ tcg_gen_extu_i32_i64(cpu_fpr[rd], write_int_rd);
+#endif
+ break;
+ default:
+ kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
+ break;
+ }
+ tcg_temp_free_i64(rm_reg);
+ tcg_temp_free(write_int_rd);
+}
+
static void decode_opc(CPURISCVState *env, DisasContext *ctx)
{
int rs1;
@@ -1005,6 +1147,10 @@ static void decode_opc(CPURISCVState *env, DisasContext
*ctx)
gen_fp_fnmadd(ctx, MASK_OP_FP_FNMADD(ctx->opcode), rd, rs1, rs2,
GET_RS3(ctx->opcode), GET_RM(ctx->opcode));
break;
+ case OPC_RISC_FP_ARITH:
+ gen_fp_arith(ctx, MASK_OP_FP_ARITH(ctx->opcode), rd, rs1, rs2,
+ GET_RM(ctx->opcode));
+ break;
default:
kill_unknown(ctx, RISCV_EXCP_ILLEGAL_INST);
break;
--
2.9.3
- Re: [Qemu-devel] [PATCH 12/18] target-riscv: Add system instructions, (continued)
- [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, 2016/09/26
- [Qemu-devel] [PATCH 10/18] target-riscv: Add Single Precision Floating-Point Instructions,
Sagar Karandikar <=
- [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