From: Leon Alrae Date: Fri, 27 Jun 2014 07:49:07 +0000 (+0100) Subject: target-mips: add new Floating Point instructions X-Git-Tag: TizenStudio_2.0_p2.3.2~208^2~519^2~12 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=e7f16abbc5b4058180e14c5912ef319f222b39fc;p=sdk%2Femulator%2Fqemu.git target-mips: add new Floating Point instructions In terms of encoding MIPS32R6 MIN.fmt, MAX.fmt, MINA.fmt, MAXA.fmt replaced MIPS-3D RECIP1, RECIP2, RSQRT1, RSQRT2 instructions. In R6 all Floating Point instructions are supposed to be IEEE-2008 compliant i.e. FIR.HAS2008 always 1. However, QEMU softfloat for MIPS has not been updated yet. Signed-off-by: Leon Alrae Reviewed-by: Yongbok Kim --- diff --git a/disas/mips.c b/disas/mips.c index 850cb65..fed2e5e 100644 --- a/disas/mips.c +++ b/disas/mips.c @@ -1263,6 +1263,28 @@ const struct mips_opcode mips_builtin_opcodes[] = {"cache", "k,o(b)", 0x7c000025, 0xfc00007f, RD_b, 0, I32R6}, {"seleqz", "d,v,t", 0x00000035, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6}, {"selnez", "d,v,t", 0x00000037, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6}, +{"maddf.s", "D,S,T", 0x46000018, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6}, +{"maddf.d", "D,S,T", 0x46200018, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I32R6}, +{"msubf.s", "D,S,T", 0x46000019, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6}, +{"msubf.d", "D,S,T", 0x46200019, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I32R6}, +{"max.s", "D,S,T", 0x4600001e, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6}, +{"max.d", "D,S,T", 0x4620001e, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I32R6}, +{"maxa.s", "D,S,T", 0x4600001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6}, +{"maxa.d", "D,S,T", 0x4620001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I32R6}, +{"rint.s", "D,S", 0x4600001a, 0xffff003f, WR_D|RD_S|FP_S, 0, I32R6}, +{"rint.d", "D,S", 0x4620001a, 0xffff003f, WR_D|RD_S|FP_D, 0, I32R6}, +{"class.s", "D,S", 0x4600001b, 0xffff003f, WR_D|RD_S|FP_S, 0, I32R6}, +{"class.d", "D,S", 0x4620001b, 0xffff003f, WR_D|RD_S|FP_D, 0, I32R6}, +{"min.s", "D,S,T", 0x4600001c, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6}, +{"min.d", "D,S,T", 0x4620001c, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I32R6}, +{"mina.s", "D,S,T", 0x4600001d, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6}, +{"mina.d", "D,S,T", 0x4620001d, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I32R6}, +{"sel.s", "D,S,T", 0x46000010, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6}, +{"sel.d", "D,S,T", 0x46200010, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I32R6}, +{"seleqz.s", "D,S,T", 0x46000014, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6}, +{"seleqz.d", "D,S,T", 0x46200014, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I32R6}, +{"selnez.s", "D,S,T", 0x46000017, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6}, +{"selnez.d", "D,S,T", 0x46200017, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I32R6}, {"align", "d,v,t", 0x7c000220, 0xfc00073f, WR_d|RD_s|RD_t, 0, I32R6}, {"dalign", "d,v,t", 0x7c000224, 0xfc00063f, WR_d|RD_s|RD_t, 0, I64R6}, {"bitswap", "d,w", 0x7c000020, 0xffe007ff, WR_d|RD_t, 0, I32R6}, diff --git a/target-mips/helper.h b/target-mips/helper.h index 5511dfc..9020c7b 100644 --- a/target-mips/helper.h +++ b/target-mips/helper.h @@ -202,6 +202,25 @@ DEF_HELPER_2(float_cvtw_d, i32, env, i64) DEF_HELPER_3(float_addr_ps, i64, env, i64, i64) DEF_HELPER_3(float_mulr_ps, i64, env, i64, i64) +DEF_HELPER_FLAGS_1(float_class_s, TCG_CALL_NO_RWG_SE, i32, i32) +DEF_HELPER_FLAGS_1(float_class_d, TCG_CALL_NO_RWG_SE, i64, i64) + +#define FOP_PROTO(op) \ +DEF_HELPER_4(float_ ## op ## _s, i32, env, i32, i32, i32) \ +DEF_HELPER_4(float_ ## op ## _d, i64, env, i64, i64, i64) +FOP_PROTO(maddf) +FOP_PROTO(msubf) +#undef FOP_PROTO + +#define FOP_PROTO(op) \ +DEF_HELPER_3(float_ ## op ## _s, i32, env, i32, i32) \ +DEF_HELPER_3(float_ ## op ## _d, i64, env, i64, i64) +FOP_PROTO(max) +FOP_PROTO(maxa) +FOP_PROTO(min) +FOP_PROTO(mina) +#undef FOP_PROTO + #define FOP_PROTO(op) \ DEF_HELPER_2(float_ ## op ## l_s, i64, env, i32) \ DEF_HELPER_2(float_ ## op ## l_d, i64, env, i64) \ @@ -219,6 +238,7 @@ DEF_HELPER_2(float_ ## op ## _d, i64, env, i64) FOP_PROTO(sqrt) FOP_PROTO(rsqrt) FOP_PROTO(recip) +FOP_PROTO(rint) #undef FOP_PROTO #define FOP_PROTO(op) \ diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index c9841e2..3f449ae 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -2809,6 +2809,110 @@ FLOAT_UNOP(abs) FLOAT_UNOP(chs) #undef FLOAT_UNOP +#define FLOAT_FMADDSUB(name, bits, muladd_arg) \ +uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env, \ + uint ## bits ## _t fs, \ + uint ## bits ## _t ft, \ + uint ## bits ## _t fd) \ +{ \ + uint ## bits ## _t fdret; \ + \ + fdret = float ## bits ## _muladd(fs, ft, fd, muladd_arg, \ + &env->active_fpu.fp_status); \ + update_fcr31(env, GETPC()); \ + return fdret; \ +} + +FLOAT_FMADDSUB(maddf_s, 32, 0) +FLOAT_FMADDSUB(maddf_d, 64, 0) +FLOAT_FMADDSUB(msubf_s, 32, float_muladd_negate_product) +FLOAT_FMADDSUB(msubf_d, 64, float_muladd_negate_product) +#undef FLOAT_FMADDSUB + +#define FLOAT_MINMAX(name, bits, minmaxfunc) \ +uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env, \ + uint ## bits ## _t fs, \ + uint ## bits ## _t ft) \ +{ \ + uint ## bits ## _t fdret; \ + \ + fdret = float ## bits ## _ ## minmaxfunc(fs, ft, \ + &env->active_fpu.fp_status); \ + update_fcr31(env, GETPC()); \ + return fdret; \ +} + +FLOAT_MINMAX(max_s, 32, maxnum) +FLOAT_MINMAX(max_d, 64, maxnum) +FLOAT_MINMAX(maxa_s, 32, maxnummag) +FLOAT_MINMAX(maxa_d, 64, maxnummag) + +FLOAT_MINMAX(min_s, 32, minnum) +FLOAT_MINMAX(min_d, 64, minnum) +FLOAT_MINMAX(mina_s, 32, minnummag) +FLOAT_MINMAX(mina_d, 64, minnummag) +#undef FLOAT_MINMAX + +#define FLOAT_RINT(name, bits) \ +uint ## bits ## _t helper_float_ ## name (CPUMIPSState *env, \ + uint ## bits ## _t fs) \ +{ \ + uint ## bits ## _t fdret; \ + \ + fdret = float ## bits ## _round_to_int(fs, &env->active_fpu.fp_status); \ + update_fcr31(env, GETPC()); \ + return fdret; \ +} + +FLOAT_RINT(rint_s, 32) +FLOAT_RINT(rint_d, 64) +#undef FLOAT_RINT + +#define FLOAT_CLASS_SIGNALING_NAN 0x001 +#define FLOAT_CLASS_QUIET_NAN 0x002 +#define FLOAT_CLASS_NEGATIVE_INFINITY 0x004 +#define FLOAT_CLASS_NEGATIVE_NORMAL 0x008 +#define FLOAT_CLASS_NEGATIVE_SUBNORMAL 0x010 +#define FLOAT_CLASS_NEGATIVE_ZERO 0x020 +#define FLOAT_CLASS_POSITIVE_INFINITY 0x040 +#define FLOAT_CLASS_POSITIVE_NORMAL 0x080 +#define FLOAT_CLASS_POSITIVE_SUBNORMAL 0x100 +#define FLOAT_CLASS_POSITIVE_ZERO 0x200 + +#define FLOAT_CLASS(name, bits) \ +uint ## bits ## _t helper_float_ ## name (uint ## bits ## _t arg) \ +{ \ + if (float ## bits ## _is_signaling_nan(arg)) { \ + return FLOAT_CLASS_SIGNALING_NAN; \ + } else if (float ## bits ## _is_quiet_nan(arg)) { \ + return FLOAT_CLASS_QUIET_NAN; \ + } else if (float ## bits ## _is_neg(arg)) { \ + if (float ## bits ## _is_infinity(arg)) { \ + return FLOAT_CLASS_NEGATIVE_INFINITY; \ + } else if (float ## bits ## _is_zero(arg)) { \ + return FLOAT_CLASS_NEGATIVE_ZERO; \ + } else if (float ## bits ## _is_zero_or_denormal(arg)) { \ + return FLOAT_CLASS_NEGATIVE_SUBNORMAL; \ + } else { \ + return FLOAT_CLASS_NEGATIVE_NORMAL; \ + } \ + } else { \ + if (float ## bits ## _is_infinity(arg)) { \ + return FLOAT_CLASS_POSITIVE_INFINITY; \ + } else if (float ## bits ## _is_zero(arg)) { \ + return FLOAT_CLASS_POSITIVE_ZERO; \ + } else if (float ## bits ## _is_zero_or_denormal(arg)) { \ + return FLOAT_CLASS_POSITIVE_SUBNORMAL; \ + } else { \ + return FLOAT_CLASS_POSITIVE_NORMAL; \ + } \ + } \ +} + +FLOAT_CLASS(class_s, 32) +FLOAT_CLASS(class_d, 64) +#undef FLOAT_CLASS + /* MIPS specific unary operations */ uint64_t helper_float_recip_d(CPUMIPSState *env, uint64_t fdt0) { diff --git a/target-mips/translate.c b/target-mips/translate.c index 45ff5fc..b6713b2 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -7647,14 +7647,25 @@ enum fopcode { OPC_TRUNC_W_S = FOP(13, FMT_S), OPC_CEIL_W_S = FOP(14, FMT_S), OPC_FLOOR_W_S = FOP(15, FMT_S), + OPC_SEL_S = FOP(16, FMT_S), OPC_MOVCF_S = FOP(17, FMT_S), OPC_MOVZ_S = FOP(18, FMT_S), OPC_MOVN_S = FOP(19, FMT_S), + OPC_SELEQZ_S = FOP(20, FMT_S), OPC_RECIP_S = FOP(21, FMT_S), OPC_RSQRT_S = FOP(22, FMT_S), + OPC_SELNEZ_S = FOP(23, FMT_S), + OPC_MADDF_S = FOP(24, FMT_S), + OPC_MSUBF_S = FOP(25, FMT_S), + OPC_RINT_S = FOP(26, FMT_S), + OPC_CLASS_S = FOP(27, FMT_S), + OPC_MIN_S = FOP(28, FMT_S), OPC_RECIP2_S = FOP(28, FMT_S), + OPC_MINA_S = FOP(29, FMT_S), OPC_RECIP1_S = FOP(29, FMT_S), + OPC_MAX_S = FOP(30, FMT_S), OPC_RSQRT1_S = FOP(30, FMT_S), + OPC_MAXA_S = FOP(31, FMT_S), OPC_RSQRT2_S = FOP(31, FMT_S), OPC_CVT_D_S = FOP(33, FMT_S), OPC_CVT_W_S = FOP(36, FMT_S), @@ -7693,14 +7704,25 @@ enum fopcode { OPC_TRUNC_W_D = FOP(13, FMT_D), OPC_CEIL_W_D = FOP(14, FMT_D), OPC_FLOOR_W_D = FOP(15, FMT_D), + OPC_SEL_D = FOP(16, FMT_D), OPC_MOVCF_D = FOP(17, FMT_D), OPC_MOVZ_D = FOP(18, FMT_D), OPC_MOVN_D = FOP(19, FMT_D), + OPC_SELEQZ_D = FOP(20, FMT_D), OPC_RECIP_D = FOP(21, FMT_D), OPC_RSQRT_D = FOP(22, FMT_D), + OPC_SELNEZ_D = FOP(23, FMT_D), + OPC_MADDF_D = FOP(24, FMT_D), + OPC_MSUBF_D = FOP(25, FMT_D), + OPC_RINT_D = FOP(26, FMT_D), + OPC_CLASS_D = FOP(27, FMT_D), + OPC_MIN_D = FOP(28, FMT_D), OPC_RECIP2_D = FOP(28, FMT_D), + OPC_MINA_D = FOP(29, FMT_D), OPC_RECIP1_D = FOP(29, FMT_D), + OPC_MAX_D = FOP(30, FMT_D), OPC_RSQRT1_D = FOP(30, FMT_D), + OPC_MAXA_D = FOP(31, FMT_D), OPC_RSQRT2_D = FOP(31, FMT_D), OPC_CVT_S_D = FOP(32, FMT_D), OPC_CVT_W_D = FOP(36, FMT_D), @@ -7956,6 +7978,79 @@ static inline void gen_movcf_ps(DisasContext *ctx, int fs, int fd, gen_set_label(l2); } +static void gen_sel_s(DisasContext *ctx, enum fopcode op1, int fd, int ft, + int fs) +{ + TCGv_i32 t1 = tcg_const_i32(0); + TCGv_i32 fp0 = tcg_temp_new_i32(); + TCGv_i32 fp1 = tcg_temp_new_i32(); + TCGv_i32 fp2 = tcg_temp_new_i32(); + gen_load_fpr32(fp0, fd); + gen_load_fpr32(fp1, ft); + gen_load_fpr32(fp2, fs); + + switch (op1) { + case OPC_SEL_S: + tcg_gen_andi_i32(fp0, fp0, 1); + tcg_gen_movcond_i32(TCG_COND_NE, fp0, fp0, t1, fp1, fp2); + break; + case OPC_SELEQZ_S: + tcg_gen_andi_i32(fp1, fp1, 1); + tcg_gen_movcond_i32(TCG_COND_EQ, fp0, fp1, t1, fp2, t1); + break; + case OPC_SELNEZ_S: + tcg_gen_andi_i32(fp1, fp1, 1); + tcg_gen_movcond_i32(TCG_COND_NE, fp0, fp1, t1, fp2, t1); + break; + default: + MIPS_INVAL("gen_sel_s"); + generate_exception (ctx, EXCP_RI); + break; + } + + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp2); + tcg_temp_free_i32(fp1); + tcg_temp_free_i32(fp0); + tcg_temp_free_i32(t1); +} + +static void gen_sel_d(DisasContext *ctx, enum fopcode op1, int fd, int ft, + int fs) +{ + TCGv_i64 t1 = tcg_const_i64(0); + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + TCGv_i64 fp2 = tcg_temp_new_i64(); + gen_load_fpr64(ctx, fp0, fd); + gen_load_fpr64(ctx, fp1, ft); + gen_load_fpr64(ctx, fp2, fs); + + switch (op1) { + case OPC_SEL_D: + tcg_gen_andi_i64(fp0, fp0, 1); + tcg_gen_movcond_i64(TCG_COND_NE, fp0, fp0, t1, fp1, fp2); + break; + case OPC_SELEQZ_D: + tcg_gen_andi_i64(fp1, fp1, 1); + tcg_gen_movcond_i64(TCG_COND_EQ, fp0, fp1, t1, fp2, t1); + break; + case OPC_SELNEZ_D: + tcg_gen_andi_i64(fp1, fp1, 1); + tcg_gen_movcond_i64(TCG_COND_NE, fp0, fp1, t1, fp2, t1); + break; + default: + MIPS_INVAL("gen_sel_d"); + generate_exception (ctx, EXCP_RI); + break; + } + + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp2); + tcg_temp_free_i64(fp1); + tcg_temp_free_i64(fp0); + tcg_temp_free_i64(t1); +} static void gen_farith (DisasContext *ctx, enum fopcode op1, int ft, int fs, int fd, int cc) @@ -8204,6 +8299,21 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, } opn = "floor.w.s"; break; + case OPC_SEL_S: + check_insn(ctx, ISA_MIPS32R6); + gen_sel_s(ctx, op1, fd, ft, fs); + opn = "sel.s"; + break; + case OPC_SELEQZ_S: + check_insn(ctx, ISA_MIPS32R6); + gen_sel_s(ctx, op1, fd, ft, fs); + opn = "seleqz.s"; + break; + case OPC_SELNEZ_S: + check_insn(ctx, ISA_MIPS32R6); + gen_sel_s(ctx, op1, fd, ft, fs); + opn = "selnez.s"; + break; case OPC_MOVCF_S: check_insn_opc_removed(ctx, ISA_MIPS32R6); gen_movcf_s(fs, fd, (ft >> 2) & 0x7, ft & 0x1); @@ -8267,59 +8377,175 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, } opn = "rsqrt.s"; break; - case OPC_RECIP2_S: - check_cp1_64bitmode(ctx); + case OPC_MADDF_S: + check_insn(ctx, ISA_MIPS32R6); { TCGv_i32 fp0 = tcg_temp_new_i32(); TCGv_i32 fp1 = tcg_temp_new_i32(); - + TCGv_i32 fp2 = tcg_temp_new_i32(); gen_load_fpr32(fp0, fs); gen_load_fpr32(fp1, ft); - gen_helper_float_recip2_s(fp0, cpu_env, fp0, fp1); + gen_load_fpr32(fp2, fd); + gen_helper_float_maddf_s(fp2, cpu_env, fp0, fp1, fp2); + gen_store_fpr32(fp2, fd); + tcg_temp_free_i32(fp2); tcg_temp_free_i32(fp1); - gen_store_fpr32(fp0, fd); tcg_temp_free_i32(fp0); + opn = "maddf.s"; } - opn = "recip2.s"; break; - case OPC_RECIP1_S: - check_cp1_64bitmode(ctx); + case OPC_MSUBF_S: + check_insn(ctx, ISA_MIPS32R6); { TCGv_i32 fp0 = tcg_temp_new_i32(); - + TCGv_i32 fp1 = tcg_temp_new_i32(); + TCGv_i32 fp2 = tcg_temp_new_i32(); gen_load_fpr32(fp0, fs); - gen_helper_float_recip1_s(fp0, cpu_env, fp0); - gen_store_fpr32(fp0, fd); + gen_load_fpr32(fp1, ft); + gen_load_fpr32(fp2, fd); + gen_helper_float_msubf_s(fp2, cpu_env, fp0, fp1, fp2); + gen_store_fpr32(fp2, fd); + tcg_temp_free_i32(fp2); + tcg_temp_free_i32(fp1); tcg_temp_free_i32(fp0); + opn = "msubf.s"; } - opn = "recip1.s"; break; - case OPC_RSQRT1_S: - check_cp1_64bitmode(ctx); + case OPC_RINT_S: + check_insn(ctx, ISA_MIPS32R6); { TCGv_i32 fp0 = tcg_temp_new_i32(); - gen_load_fpr32(fp0, fs); - gen_helper_float_rsqrt1_s(fp0, cpu_env, fp0); + gen_helper_float_rint_s(fp0, cpu_env, fp0); gen_store_fpr32(fp0, fd); tcg_temp_free_i32(fp0); + opn = "rint.s"; } - opn = "rsqrt1.s"; break; - case OPC_RSQRT2_S: - check_cp1_64bitmode(ctx); + case OPC_CLASS_S: + check_insn(ctx, ISA_MIPS32R6); { TCGv_i32 fp0 = tcg_temp_new_i32(); + gen_load_fpr32(fp0, fs); + gen_helper_float_class_s(fp0, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + opn = "class.s"; + } + break; + case OPC_MIN_S: /* OPC_RECIP2_S */ + if (ctx->insn_flags & ISA_MIPS32R6) { + /* OPC_MIN_S */ + TCGv_i32 fp0 = tcg_temp_new_i32(); + TCGv_i32 fp1 = tcg_temp_new_i32(); + TCGv_i32 fp2 = tcg_temp_new_i32(); + gen_load_fpr32(fp0, fs); + gen_load_fpr32(fp1, ft); + gen_helper_float_min_s(fp2, cpu_env, fp0, fp1); + gen_store_fpr32(fp2, fd); + tcg_temp_free_i32(fp2); + tcg_temp_free_i32(fp1); + tcg_temp_free_i32(fp0); + opn = "min.s"; + } else { + /* OPC_RECIP2_S */ + check_cp1_64bitmode(ctx); + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + TCGv_i32 fp1 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); + gen_load_fpr32(fp1, ft); + gen_helper_float_recip2_s(fp0, cpu_env, fp0, fp1); + tcg_temp_free_i32(fp1); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + } + opn = "recip2.s"; + } + break; + case OPC_MINA_S: /* OPC_RECIP1_S */ + if (ctx->insn_flags & ISA_MIPS32R6) { + /* OPC_MINA_S */ + TCGv_i32 fp0 = tcg_temp_new_i32(); TCGv_i32 fp1 = tcg_temp_new_i32(); + TCGv_i32 fp2 = tcg_temp_new_i32(); + gen_load_fpr32(fp0, fs); + gen_load_fpr32(fp1, ft); + gen_helper_float_mina_s(fp2, cpu_env, fp0, fp1); + gen_store_fpr32(fp2, fd); + tcg_temp_free_i32(fp2); + tcg_temp_free_i32(fp1); + tcg_temp_free_i32(fp0); + opn = "mina.s"; + } else { + /* OPC_RECIP1_S */ + check_cp1_64bitmode(ctx); + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + gen_load_fpr32(fp0, fs); + gen_helper_float_recip1_s(fp0, cpu_env, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + } + opn = "recip1.s"; + } + break; + case OPC_MAX_S: /* OPC_RSQRT1_S */ + if (ctx->insn_flags & ISA_MIPS32R6) { + /* OPC_MAX_S */ + TCGv_i32 fp0 = tcg_temp_new_i32(); + TCGv_i32 fp1 = tcg_temp_new_i32(); gen_load_fpr32(fp0, fs); gen_load_fpr32(fp1, ft); - gen_helper_float_rsqrt2_s(fp0, cpu_env, fp0, fp1); + gen_helper_float_max_s(fp1, cpu_env, fp0, fp1); + gen_store_fpr32(fp1, fd); + tcg_temp_free_i32(fp1); + tcg_temp_free_i32(fp0); + opn = "max.s"; + } else { + /* OPC_RSQRT1_S */ + check_cp1_64bitmode(ctx); + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); + gen_helper_float_rsqrt1_s(fp0, cpu_env, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + } + opn = "rsqrt1.s"; + } + break; + case OPC_MAXA_S: /* OPC_RSQRT2_S */ + if (ctx->insn_flags & ISA_MIPS32R6) { + /* OPC_MAXA_S */ + TCGv_i32 fp0 = tcg_temp_new_i32(); + TCGv_i32 fp1 = tcg_temp_new_i32(); + gen_load_fpr32(fp0, fs); + gen_load_fpr32(fp1, ft); + gen_helper_float_maxa_s(fp1, cpu_env, fp0, fp1); + gen_store_fpr32(fp1, fd); tcg_temp_free_i32(fp1); - gen_store_fpr32(fp0, fd); tcg_temp_free_i32(fp0); + opn = "maxa.s"; + } else { + /* OPC_RSQRT2_S */ + check_cp1_64bitmode(ctx); + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + TCGv_i32 fp1 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); + gen_load_fpr32(fp1, ft); + gen_helper_float_rsqrt2_s(fp0, cpu_env, fp0, fp1); + tcg_temp_free_i32(fp1); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + } + opn = "rsqrt2.s"; } - opn = "rsqrt2.s"; break; case OPC_CVT_D_S: check_cp1_registers(ctx, fd); @@ -8618,6 +8844,21 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, } opn = "floor.w.d"; break; + case OPC_SEL_D: + check_insn(ctx, ISA_MIPS32R6); + gen_sel_d(ctx, op1, fd, ft, fs); + opn = "sel.d"; + break; + case OPC_SELEQZ_D: + check_insn(ctx, ISA_MIPS32R6); + gen_sel_d(ctx, op1, fd, ft, fs); + opn = "seleqz.d"; + break; + case OPC_SELNEZ_D: + check_insn(ctx, ISA_MIPS32R6); + gen_sel_d(ctx, op1, fd, ft, fs); + opn = "selnez.d"; + break; case OPC_MOVCF_D: check_insn_opc_removed(ctx, ISA_MIPS32R6); gen_movcf_d(ctx, fs, fd, (ft >> 2) & 0x7, ft & 0x1); @@ -8681,59 +8922,171 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, } opn = "rsqrt.d"; break; - case OPC_RECIP2_D: - check_cp1_64bitmode(ctx); + case OPC_MADDF_D: + check_insn(ctx, ISA_MIPS32R6); { TCGv_i64 fp0 = tcg_temp_new_i64(); TCGv_i64 fp1 = tcg_temp_new_i64(); - + TCGv_i64 fp2 = tcg_temp_new_i64(); gen_load_fpr64(ctx, fp0, fs); gen_load_fpr64(ctx, fp1, ft); - gen_helper_float_recip2_d(fp0, cpu_env, fp0, fp1); + gen_load_fpr64(ctx, fp2, fd); + gen_helper_float_maddf_d(fp2, cpu_env, fp0, fp1, fp2); + gen_store_fpr64(ctx, fp2, fd); + tcg_temp_free_i64(fp2); tcg_temp_free_i64(fp1); - gen_store_fpr64(ctx, fp0, fd); tcg_temp_free_i64(fp0); + opn = "maddf.d"; } - opn = "recip2.d"; break; - case OPC_RECIP1_D: - check_cp1_64bitmode(ctx); + case OPC_MSUBF_D: + check_insn(ctx, ISA_MIPS32R6); { TCGv_i64 fp0 = tcg_temp_new_i64(); - + TCGv_i64 fp1 = tcg_temp_new_i64(); + TCGv_i64 fp2 = tcg_temp_new_i64(); gen_load_fpr64(ctx, fp0, fs); - gen_helper_float_recip1_d(fp0, cpu_env, fp0); - gen_store_fpr64(ctx, fp0, fd); + gen_load_fpr64(ctx, fp1, ft); + gen_load_fpr64(ctx, fp2, fd); + gen_helper_float_msubf_d(fp2, cpu_env, fp0, fp1, fp2); + gen_store_fpr64(ctx, fp2, fd); + tcg_temp_free_i64(fp2); + tcg_temp_free_i64(fp1); tcg_temp_free_i64(fp0); + opn = "msubf.d"; } - opn = "recip1.d"; break; - case OPC_RSQRT1_D: - check_cp1_64bitmode(ctx); + case OPC_RINT_D: + check_insn(ctx, ISA_MIPS32R6); { TCGv_i64 fp0 = tcg_temp_new_i64(); - gen_load_fpr64(ctx, fp0, fs); - gen_helper_float_rsqrt1_d(fp0, cpu_env, fp0); + gen_helper_float_rint_d(fp0, cpu_env, fp0); gen_store_fpr64(ctx, fp0, fd); tcg_temp_free_i64(fp0); + opn = "rint.d"; } - opn = "rsqrt1.d"; break; - case OPC_RSQRT2_D: - check_cp1_64bitmode(ctx); + case OPC_CLASS_D: + check_insn(ctx, ISA_MIPS32R6); { TCGv_i64 fp0 = tcg_temp_new_i64(); + gen_load_fpr64(ctx, fp0, fs); + gen_helper_float_class_d(fp0, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + opn = "class.d"; + } + break; + case OPC_MIN_D: /* OPC_RECIP2_D */ + if (ctx->insn_flags & ISA_MIPS32R6) { + /* OPC_MIN_D */ + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + gen_helper_float_min_d(fp1, cpu_env, fp0, fp1); + gen_store_fpr64(ctx, fp1, fd); + tcg_temp_free_i64(fp1); + tcg_temp_free_i64(fp0); + opn = "min.d"; + } else { + /* OPC_RECIP2_D */ + check_cp1_64bitmode(ctx); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + gen_helper_float_recip2_d(fp0, cpu_env, fp0, fp1); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } + opn = "recip2.d"; + } + break; + case OPC_MINA_D: /* OPC_RECIP1_D */ + if (ctx->insn_flags & ISA_MIPS32R6) { + /* OPC_MINA_D */ + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + gen_helper_float_mina_d(fp1, cpu_env, fp0, fp1); + gen_store_fpr64(ctx, fp1, fd); + tcg_temp_free_i64(fp1); + tcg_temp_free_i64(fp0); + opn = "mina.d"; + } else { + /* OPC_RECIP1_D */ + check_cp1_64bitmode(ctx); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_helper_float_recip1_d(fp0, cpu_env, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } + opn = "recip1.d"; + } + break; + case OPC_MAX_D: /* OPC_RSQRT1_D */ + if (ctx->insn_flags & ISA_MIPS32R6) { + /* OPC_MAX_D */ + TCGv_i64 fp0 = tcg_temp_new_i64(); TCGv_i64 fp1 = tcg_temp_new_i64(); + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + gen_helper_float_max_d(fp1, cpu_env, fp0, fp1); + gen_store_fpr64(ctx, fp1, fd); + tcg_temp_free_i64(fp1); + tcg_temp_free_i64(fp0); + opn = "max.d"; + } else { + /* OPC_RSQRT1_D */ + check_cp1_64bitmode(ctx); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + gen_load_fpr64(ctx, fp0, fs); + gen_helper_float_rsqrt1_d(fp0, cpu_env, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } + opn = "rsqrt1.d"; + } + break; + case OPC_MAXA_D: /* OPC_RSQRT2_D */ + if (ctx->insn_flags & ISA_MIPS32R6) { + /* OPC_MAXA_D */ + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); gen_load_fpr64(ctx, fp0, fs); gen_load_fpr64(ctx, fp1, ft); - gen_helper_float_rsqrt2_d(fp0, cpu_env, fp0, fp1); + gen_helper_float_maxa_d(fp1, cpu_env, fp0, fp1); + gen_store_fpr64(ctx, fp1, fd); tcg_temp_free_i64(fp1); - gen_store_fpr64(ctx, fp0, fd); tcg_temp_free_i64(fp0); + opn = "maxa.d"; + } else { + /* OPC_RSQRT2_D */ + check_cp1_64bitmode(ctx); + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + gen_helper_float_rsqrt2_d(fp0, cpu_env, fp0, fp1); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } + opn = "rsqrt2.d"; } - opn = "rsqrt2.d"; break; case OPC_CMP_F_D: case OPC_CMP_UN_D: