add MSA 2RF format instructions Signed-off-by: Yongbok Kim <yongbok....@imgtec.com> --- target-mips/helper.h | 16 ++ target-mips/msa_helper.c | 656 ++++++++++++++++++++++++++++++++++++++++++++++ target-mips/translate.c | 76 ++++++ 3 files changed, 748 insertions(+), 0 deletions(-)
diff --git a/target-mips/helper.h b/target-mips/helper.h index b87bb50..c86bd36 100644 --- a/target-mips/helper.h +++ b/target-mips/helper.h @@ -747,6 +747,7 @@ DEF_HELPER_5(msa_dpsub_u_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_fadd_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_fcaf_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_fceq_df, void, env, i32, i32, i32, i32) +DEF_HELPER_4(msa_fclass_df, void, env, i32, i32, i32) DEF_HELPER_5(msa_fcle_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_fclt_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_fcne_df, void, env, i32, i32, i32, i32) @@ -759,7 +760,14 @@ DEF_HELPER_5(msa_fcune_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_fdiv_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_fexdo_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_fexp2_df, void, env, i32, i32, i32, i32) +DEF_HELPER_4(msa_fexupl_df, void, env, i32, i32, i32) +DEF_HELPER_4(msa_fexupr_df, void, env, i32, i32, i32) +DEF_HELPER_4(msa_ffint_s_df, void, env, i32, i32, i32) +DEF_HELPER_4(msa_ffint_u_df, void, env, i32, i32, i32) +DEF_HELPER_4(msa_ffql_df, void, env, i32, i32, i32) +DEF_HELPER_4(msa_ffqr_df, void, env, i32, i32, i32) DEF_HELPER_4(msa_fill_df, void, env, i32, i32, i32) +DEF_HELPER_4(msa_flog2_df, void, env, i32, i32, i32) DEF_HELPER_5(msa_fmadd_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_fmax_a_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_fmax_df, void, env, i32, i32, i32, i32) @@ -767,19 +775,27 @@ DEF_HELPER_5(msa_fmin_a_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_fmin_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_fmsub_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_fmul_df, void, env, i32, i32, i32, i32) +DEF_HELPER_4(msa_frcp_df, void, env, i32, i32, i32) +DEF_HELPER_4(msa_frint_df, void, env, i32, i32, i32) +DEF_HELPER_4(msa_frsqrt_df, void, env, i32, i32, i32) DEF_HELPER_5(msa_fsaf_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_fseq_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_fsle_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_fslt_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_fsne_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_fsor_df, void, env, i32, i32, i32, i32) +DEF_HELPER_4(msa_fsqrt_df, void, env, i32, i32, i32) DEF_HELPER_5(msa_fsub_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_fsueq_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_fsule_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_fsult_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_fsun_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_fsune_df, void, env, i32, i32, i32, i32) +DEF_HELPER_4(msa_ftint_s_df, void, env, i32, i32, i32) +DEF_HELPER_4(msa_ftint_u_df, void, env, i32, i32, i32) DEF_HELPER_5(msa_ftq_df, void, env, i32, i32, i32, i32) +DEF_HELPER_4(msa_ftrunc_s_df, void, env, i32, i32, i32) +DEF_HELPER_4(msa_ftrunc_u_df, void, env, i32, i32, i32) DEF_HELPER_5(msa_hadd_s_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_hadd_u_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_hsub_s_df, void, env, i32, i32, i32, i32) diff --git a/target-mips/msa_helper.c b/target-mips/msa_helper.c index aa165ac..d152953 100644 --- a/target-mips/msa_helper.c +++ b/target-mips/msa_helper.c @@ -3240,6 +3240,9 @@ void helper_msa_msubr_q_df(CPUMIPSState *env, uint32_t df, uint32_t wd, } } +#define FLOAT_ONE32 make_float32(0x3f8 << 20) +#define FLOAT_ONE64 make_float64(0x3ffULL << 52) + #define FLOAT_SNAN16 (float16_default_nan ^ 0x0220) /* 0x7c20 */ #define FLOAT_SNAN32 (float32_default_nan ^ 0x00400020) @@ -3352,6 +3355,28 @@ static inline int update_msacsr(CPUMIPSState *env, int action, int denormal) (!float ## BITS ## _is_zero(ARG) \ && float ## BITS ## _is_zero_or_denormal(ARG)) +#define MSA_FLOAT_UNOP0(DEST, OP, ARG, BITS) \ + do { \ + int c; \ + int cause; \ + int enable; \ + \ + set_float_exception_flags(0, &env->active_msa.fp_status); \ + DEST = float ## BITS ## _ ## OP(ARG, &env->active_msa.fp_status); \ + c = update_msacsr(env, CLEAR_FS_UNDERFLOW, 0); \ + enable = GET_FP_ENABLE(env->active_msa.msacsr) | FP_UNIMPLEMENTED; \ + cause = c & enable; \ + \ + if (cause) { \ + DEST = ((FLOAT_SNAN ## BITS >> 6) << 6) | c; \ + } \ + else { \ + if (float ## BITS ## _is_any_nan(ARG)) { \ + DEST = 0; \ + } \ + } \ + } while (0) + #define MSA_FLOAT_UNOP_XD(DEST, OP, ARG, BITS, XBITS) \ do { \ int c; \ @@ -3386,6 +3411,37 @@ static inline int update_msacsr(CPUMIPSState *env, int action, int denormal) } \ } while (0) +#define MSA_FLOAT_LOGB(DEST, ARG, BITS) \ + do { \ + int c; \ + int cause; \ + int enable; \ + \ + set_float_exception_flags(0, &env->active_msa.fp_status); \ + set_float_rounding_mode(float_round_down, \ + &env->active_msa.fp_status); \ + DEST = float ## BITS ## _ ## log2(ARG, \ + &env->active_msa.fp_status); \ + DEST = float ## BITS ## _ ## round_to_int(DEST, \ + &env->active_msa.fp_status); \ + set_float_rounding_mode(ieee_rm[(env->active_msa.msacsr & \ + MSACSR_RM_MASK) >> MSACSR_RM_POS], \ + &env->active_msa.fp_status); \ + \ + set_float_exception_flags( \ + get_float_exception_flags(&env->active_msa.fp_status) \ + & (~float_flag_inexact), \ + &env->active_msa.fp_status); \ + \ + c = update_msacsr(env, 0, IS_DENORMAL(DEST, BITS)); \ + enable = GET_FP_ENABLE(env->active_msa.msacsr) | FP_UNIMPLEMENTED; \ + cause = c & enable; \ + \ + if (cause) { \ + DEST = ((FLOAT_SNAN ## BITS >> 6) << 6) | c; \ + } \ + } while (0) + #define MSA_FLOAT_BINOP(DEST, OP, ARG1, ARG2, BITS) \ do { \ int c; \ @@ -3422,6 +3478,27 @@ static inline int update_msacsr(CPUMIPSState *env, int action, int denormal) } \ } while (0) +#define MSA_FLOAT_RECIPROCAL(DEST, ARG, BITS) \ + do { \ + int c; \ + int cause; \ + int enable; \ + \ + set_float_exception_flags(0, &env->active_msa.fp_status); \ + DEST = float ## BITS ## _ ## div(FLOAT_ONE ## BITS, ARG, \ + &env->active_msa.fp_status); \ + c = update_msacsr(env, float ## BITS ## _is_infinity(ARG) || \ + float ## BITS ## _is_quiet_nan(DEST) ? \ + 0 : RECIPROCAL_INEXACT, \ + IS_DENORMAL(DEST, BITS)); \ + enable = GET_FP_ENABLE(env->active_msa.msacsr) | FP_UNIMPLEMENTED; \ + cause = c & enable; \ + \ + if (cause) { \ + DEST = ((FLOAT_SNAN ## BITS >> 6) << 6) | c; \ + } \ + } while (0) + #define MSA_FLOAT_MULADD(DEST, ARG1, ARG2, ARG3, NEGATE, BITS) \ do { \ int c; \ @@ -3566,6 +3643,36 @@ void helper_msa_fdiv_df(CPUMIPSState *env, uint32_t df, uint32_t wd, msa_move_v(pwd, pwx); } +void helper_msa_fsqrt_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws) +{ + wr_t wx, *pwx = &wx; + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + ALL_W_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_UNOP(W(pwx, i), sqrt, W(pws, i), 32); + } DONE_ALL_ELEMENTS; + break; + case DF_DOUBLE: + ALL_D_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_UNOP(D(pwx, i), sqrt, D(pws, i), 64); + } DONE_ALL_ELEMENTS; + break; + default: + /* shouldn't get here */ + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + void helper_msa_fexp2_df(CPUMIPSState *env, uint32_t df, uint32_t wd, uint32_t ws, uint32_t wt) { @@ -3603,6 +3710,36 @@ void helper_msa_fexp2_df(CPUMIPSState *env, uint32_t df, uint32_t wd, msa_move_v(pwd, pwx); } +void helper_msa_flog2_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws) +{ + wr_t wx, *pwx = &wx; + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + ALL_W_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_LOGB(W(pwx, i), W(pws, i), 32); + } DONE_ALL_ELEMENTS; + break; + case DF_DOUBLE: + ALL_D_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_LOGB(D(pwx, i), D(pws, i), 64); + } DONE_ALL_ELEMENTS; + break; + default: + /* shouldn't get here */ + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + void helper_msa_fmadd_df(CPUMIPSState *env, uint32_t df, uint32_t wd, uint32_t ws, uint32_t wt) { @@ -4417,6 +4554,89 @@ void helper_msa_fsor_df(CPUMIPSState *env, uint32_t df, uint32_t wd, compare_or(env, pwd, pws, pwt, df, 0); } +#define MSA_FLOAT_CLASS_SIGNALING_NAN 0x001 +#define MSA_FLOAT_CLASS_QUIET_NAN 0x002 + +#define MSA_FLOAT_CLASS_NEGATIVE_INFINITY 0x004 +#define MSA_FLOAT_CLASS_NEGATIVE_NORMAL 0x008 +#define MSA_FLOAT_CLASS_NEGATIVE_SUBNORMAL 0x010 +#define MSA_FLOAT_CLASS_NEGATIVE_ZERO 0x020 + +#define MSA_FLOAT_CLASS_POSITIVE_INFINITY 0x040 +#define MSA_FLOAT_CLASS_POSITIVE_NORMAL 0x080 +#define MSA_FLOAT_CLASS_POSITIVE_SUBNORMAL 0x100 +#define MSA_FLOAT_CLASS_POSITIVE_ZERO 0x200 + +#define MSA_FLOAT_CLASS(ARG, BITS) \ + do { \ + int mask; \ + int snan, qnan, inf, neg, zero, dnmz; \ + \ + snan = float ## BITS ## _is_signaling_nan(ARG); \ + qnan = float ## BITS ## _is_quiet_nan(ARG); \ + inf = float ## BITS ## _is_infinity(ARG); \ + neg = float ## BITS ## _is_neg(ARG); \ + zero = float ## BITS ## _is_zero(ARG); \ + dnmz = float ## BITS ## _is_zero_or_denormal(ARG); \ + \ + mask = 0; \ + if (snan) { \ + mask |= MSA_FLOAT_CLASS_SIGNALING_NAN; \ + } \ + else if (qnan) { \ + mask |= MSA_FLOAT_CLASS_QUIET_NAN; \ + } else if (neg) { \ + if (inf) { \ + mask |= MSA_FLOAT_CLASS_NEGATIVE_INFINITY; \ + } else if (zero) { \ + mask |= MSA_FLOAT_CLASS_NEGATIVE_ZERO; \ + } else if (dnmz) { \ + mask |= MSA_FLOAT_CLASS_NEGATIVE_SUBNORMAL; \ + } \ + else { \ + mask |= MSA_FLOAT_CLASS_NEGATIVE_NORMAL; \ + } \ + } else { \ + if (inf) { \ + mask |= MSA_FLOAT_CLASS_POSITIVE_INFINITY; \ + } else if (zero) { \ + mask |= MSA_FLOAT_CLASS_POSITIVE_ZERO; \ + } else if (dnmz) { \ + mask |= MSA_FLOAT_CLASS_POSITIVE_SUBNORMAL; \ + } else { \ + mask |= MSA_FLOAT_CLASS_POSITIVE_NORMAL; \ + } \ + } \ + return mask; \ + } while (0) + +static inline int64_t msa_fclass_df(CPUMIPSState *env, uint32_t df, int64_t arg) +{ + if (df == DF_WORD) { + MSA_FLOAT_CLASS(arg, 32); + } else { + MSA_FLOAT_CLASS(arg, 64); + } +} + +void helper_msa_fclass_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws) +{ + uint64_t td, ts; + int i; + int df_bits = 8 * (1 << df); + + for (i = 0; i < MSA_WRLEN / df_bits; i++) { + ts = msa_load_wr_elem_s64(env, ws, df, i); + td = msa_fclass_df(env, df, ts); + msa_store_wr_elem(env, td, wd, df, i); + } + + if (env->active_msa.msair & MSAIR_WRP_BIT) { + env->active_msa.msamodify |= (1 << wd); + } +} + static inline float16 float16_from_float32(int32 a, flag ieee STATUS_PARAM) { float16 f_val; @@ -4437,6 +4657,26 @@ static inline float32 float32_from_float64(int64 a STATUS_PARAM) return a < 0 ? (f_val | (1 << 31)) : f_val; } +static inline float32 float32_from_float16(int16_t a, flag ieee STATUS_PARAM) +{ + float32 f_val; + + f_val = float16_to_float32((float16)a, ieee STATUS_VAR); + f_val = float32_maybe_silence_nan(f_val); + + return a < 0 ? (f_val | (1 << 31)) : f_val; +} + +static inline float64 float64_from_float32(int32 a STATUS_PARAM) +{ + float64 f_val; + + f_val = float32_to_float64((float64)a STATUS_VAR); + f_val = float64_maybe_silence_nan(f_val); + + return a < 0 ? (f_val | (1ULL << 63)) : f_val; +} + void helper_msa_fexdo_df(CPUMIPSState *env, uint32_t df, uint32_t wd, uint32_t ws, uint32_t wt) { @@ -4472,6 +4712,308 @@ void helper_msa_fexdo_df(CPUMIPSState *env, uint32_t df, uint32_t wd, msa_move_v(pwd, pwx); } +void helper_msa_fexupl_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws) +{ + wr_t wx, *pwx = &wx; + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + + switch (df) { + case DF_WORD: + ALL_W_ELEMENTS(i, MSA_WRLEN) { + /* Half precision floats come in two formats: standard + IEEE and "ARM" format. The latter gains extra exponent + range by omitting the NaN/Inf encodings. */ + flag ieee = 1; + + MSA_FLOAT_BINOP(W(pwx, i), from_float16, HL(pws, i), ieee, 32); + } DONE_ALL_ELEMENTS; + break; + case DF_DOUBLE: + ALL_D_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_UNOP(D(pwx, i), from_float32, WL(pws, i), 64); + } DONE_ALL_ELEMENTS; + break; + default: + /* shouldn't get here */ + assert(0); + } + + check_msacsr_cause(env); + msa_move_v(pwd, pwx); +} + +void helper_msa_fexupr_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws) +{ + wr_t wx, *pwx = &wx; + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + + switch (df) { + case DF_WORD: + ALL_W_ELEMENTS(i, MSA_WRLEN) { + /* Half precision floats come in two formats: standard + IEEE and "ARM" format. The latter gains extra exponent + range by omitting the NaN/Inf encodings. */ + flag ieee = 1; + + MSA_FLOAT_BINOP(W(pwx, i), from_float16, HR(pws, i), ieee, 32); + } DONE_ALL_ELEMENTS; + break; + case DF_DOUBLE: + ALL_D_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_UNOP(D(pwx, i), from_float32, WR(pws, i), 64); + } DONE_ALL_ELEMENTS; + break; + default: + /* shouldn't get here */ + assert(0); + } + + check_msacsr_cause(env); + msa_move_v(pwd, pwx); +} + +#define float32_from_int32 int32_to_float32 +#define float32_from_uint32 uint32_to_float32 + +#define float64_from_int64 int64_to_float64 +#define float64_from_uint64 uint64_to_float64 + +void helper_msa_ffint_s_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws) +{ + wr_t wx, *pwx = &wx; + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + ALL_W_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_UNOP(W(pwx, i), from_int32, W(pws, i), 32); + } DONE_ALL_ELEMENTS; + break; + case DF_DOUBLE: + ALL_D_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_UNOP(D(pwx, i), from_int64, D(pws, i), 64); + } DONE_ALL_ELEMENTS; + break; + default: + /* shouldn't get here */ + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +void helper_msa_ffint_u_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws) +{ + wr_t wx, *pwx = &wx; + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + ALL_W_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_UNOP(W(pwx, i), from_uint32, W(pws, i), 32); + } DONE_ALL_ELEMENTS; + break; + case DF_DOUBLE: + ALL_D_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_UNOP(D(pwx, i), from_uint64, D(pws, i), 64); + } DONE_ALL_ELEMENTS; + break; + default: + /* shouldn't get here */ + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +void helper_msa_ftint_s_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws) +{ + wr_t wx, *pwx = &wx; + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + ALL_W_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_UNOP0(W(pwx, i), to_int32, W(pws, i), 32); + } DONE_ALL_ELEMENTS; + break; + case DF_DOUBLE: + ALL_D_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_UNOP0(D(pwx, i), to_int64, D(pws, i), 64); + } DONE_ALL_ELEMENTS; + break; + default: + /* shouldn't get here */ + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +void helper_msa_ftint_u_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws) +{ + wr_t wx, *pwx = &wx; + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + ALL_W_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_UNOP0(W(pwx, i), to_uint32, W(pws, i), 32); + } DONE_ALL_ELEMENTS; + break; + case DF_DOUBLE: + ALL_D_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_UNOP0(D(pwx, i), to_uint64, D(pws, i), 64); + } DONE_ALL_ELEMENTS; + break; + default: + /* shouldn't get here */ + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +void helper_msa_ftrunc_s_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws) +{ + wr_t wx, *pwx = &wx; + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + ALL_W_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_UNOP0(W(pwx, i), to_int32_round_to_zero, W(pws, i), 32); + } DONE_ALL_ELEMENTS; + break; + case DF_DOUBLE: + ALL_D_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_UNOP0(D(pwx, i), to_int64_round_to_zero, D(pws, i), 64); + } DONE_ALL_ELEMENTS; + break; + default: + /* shouldn't get here */ + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +void helper_msa_ftrunc_u_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws) +{ + wr_t wx, *pwx = &wx; + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + ALL_W_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_UNOP0(W(pwx, i), to_uint32_round_to_zero, W(pws, i), 32); + } DONE_ALL_ELEMENTS; + break; + case DF_DOUBLE: + ALL_D_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_UNOP0(D(pwx, i), to_uint64_round_to_zero, D(pws, i), 64); + } DONE_ALL_ELEMENTS; + break; + default: + /* shouldn't get here */ + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +void helper_msa_frint_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws) +{ + wr_t wx, *pwx = &wx; + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + ALL_W_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_UNOP(W(pwx, i), round_to_int, W(pws, i), 32); + } DONE_ALL_ELEMENTS; + break; + case DF_DOUBLE: + ALL_D_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_UNOP(D(pwx, i), round_to_int, D(pws, i), 64); + } DONE_ALL_ELEMENTS; + break; + default: + /* shouldn't get here */ + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +static inline float32 float32_from_q16(int16_t a STATUS_PARAM) +{ + float32 f_val; + + /* conversion as integer and scaling */ + f_val = int32_to_float32(a STATUS_VAR); + f_val = float32_scalbn(f_val, -15 STATUS_VAR); + + return f_val; +} + +static inline float64 float64_from_q32(int32 a STATUS_PARAM) +{ + float64 f_val; + + /* conversion as integer and scaling */ + f_val = int32_to_float64(a STATUS_VAR); + f_val = float64_scalbn(f_val, -31 STATUS_VAR); + + return f_val; +} + static inline int16_t float32_to_q16(float32 a STATUS_PARAM) { int32 q_val; @@ -4576,6 +5118,58 @@ static inline int32 float64_to_q32(float64 a STATUS_PARAM) return (int32)q_val; } +void helper_msa_ffql_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws) +{ + wr_t wx, *pwx = &wx; + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + + switch (df) { + case DF_WORD: + ALL_W_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_UNOP(W(pwx, i), from_q16, HL(pws, i), 32); + } DONE_ALL_ELEMENTS; + break; + case DF_DOUBLE: + ALL_D_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_UNOP(D(pwx, i), from_q32, WL(pws, i), 64); + } DONE_ALL_ELEMENTS; + break; + default: + /* shouldn't get here */ + assert(0); + } + + msa_move_v(pwd, pwx); +} + +void helper_msa_ffqr_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws) +{ + wr_t wx, *pwx = &wx; + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + + switch (df) { + case DF_WORD: + ALL_W_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_UNOP(W(pwx, i), from_q16, HR(pws, i), 32); + } DONE_ALL_ELEMENTS; + break; + case DF_DOUBLE: + ALL_D_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_UNOP(D(pwx, i), from_q32, WR(pws, i), 64); + } DONE_ALL_ELEMENTS; + break; + default: + /* shouldn't get here */ + assert(0); + } + + msa_move_v(pwd, pwx); +} + void helper_msa_ftq_df(CPUMIPSState *env, uint32_t df, uint32_t wd, uint32_t ws, uint32_t wt) { @@ -4608,6 +5202,68 @@ void helper_msa_ftq_df(CPUMIPSState *env, uint32_t df, uint32_t wd, msa_move_v(pwd, pwx); } +void helper_msa_frcp_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws) +{ + wr_t wx, *pwx = &wx; + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + ALL_W_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_RECIPROCAL(W(pwx, i), W(pws, i), 32); + } DONE_ALL_ELEMENTS; + break; + case DF_DOUBLE: + ALL_D_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_RECIPROCAL(D(pwx, i), D(pws, i), 64); + } DONE_ALL_ELEMENTS; + break; + default: + /* shouldn't get here */ + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +void helper_msa_frsqrt_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws) +{ + wr_t wx, *pwx = &wx; + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + ALL_W_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_RECIPROCAL(W(pwx, i), float32_sqrt(W(pws, i), + &env->active_msa.fp_status), 32); + } DONE_ALL_ELEMENTS; + break; + case DF_DOUBLE: + ALL_D_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_RECIPROCAL(D(pwx, i), float64_sqrt(D(pws, i), + &env->active_msa.fp_status), 64); + } DONE_ALL_ELEMENTS; + break; + default: + /* shouldn't get here */ + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + target_ulong helper_msa_cfcmsa(CPUMIPSState *env, uint32_t cs) { diff --git a/target-mips/translate.c b/target-mips/translate.c index 4185019..dcfe830 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -15737,6 +15737,82 @@ static void gen_msa_vec(CPUMIPSState *env, DisasContext *ctx) } break; case OPC_MSA_2RF: + { + uint8_t df = (ctx->opcode >> 16) & 0x1 /* df [16:16] */; + /* adjust df value for floating-point instruction */ + df = df + 2; + TCGv_i32 tdf = tcg_const_i32(df); + + switch (MASK_MSA_2RF(opcode)) { + case OPC_MSA_FCLASS_df: + check_msa_access(env, ctx, -1, ws, wd); + gen_helper_msa_fclass_df(cpu_env, tdf, twd, tws); + break; + case OPC_MSA_FTRUNC_S_df: + check_msa_access(env, ctx, -1, ws, wd); + gen_helper_msa_ftrunc_s_df(cpu_env, tdf, twd, tws); + break; + case OPC_MSA_FTRUNC_U_df: + check_msa_access(env, ctx, -1, ws, wd); + gen_helper_msa_ftrunc_u_df(cpu_env, tdf, twd, tws); + break; + case OPC_MSA_FSQRT_df: + check_msa_access(env, ctx, -1, ws, wd); + gen_helper_msa_fsqrt_df(cpu_env, tdf, twd, tws); + break; + case OPC_MSA_FRSQRT_df: + check_msa_access(env, ctx, -1, ws, wd); + gen_helper_msa_frsqrt_df(cpu_env, tdf, twd, tws); + break; + case OPC_MSA_FRCP_df: + check_msa_access(env, ctx, -1, ws, wd); + gen_helper_msa_frcp_df(cpu_env, tdf, twd, tws); + break; + case OPC_MSA_FRINT_df: + check_msa_access(env, ctx, -1, ws, wd); + gen_helper_msa_frint_df(cpu_env, tdf, twd, tws); + break; + case OPC_MSA_FRLOG2_df: + check_msa_access(env, ctx, -1, ws, wd); + gen_helper_msa_flog2_df(cpu_env, tdf, twd, tws); + break; + case OPC_MSA_FEXUPL_df: + check_msa_access(env, ctx, -1, ws, wd); + gen_helper_msa_fexupl_df(cpu_env, tdf, twd, tws); + break; + case OPC_MSA_FEXUPR_df: + check_msa_access(env, ctx, -1, ws, wd); + gen_helper_msa_fexupr_df(cpu_env, tdf, twd, tws); + break; + case OPC_MSA_FFQL_df: + check_msa_access(env, ctx, -1, ws, wd); + gen_helper_msa_ffql_df(cpu_env, tdf, twd, tws); + break; + case OPC_MSA_FFQR_df: + check_msa_access(env, ctx, -1, ws, wd); + gen_helper_msa_ffqr_df(cpu_env, tdf, twd, tws); + break; + case OPC_MSA_FINT_S_df: + check_msa_access(env, ctx, -1, ws, wd); + gen_helper_msa_ftint_s_df(cpu_env, tdf, twd, tws); + break; + case OPC_MSA_FINT_U_df: + check_msa_access(env, ctx, -1, ws, wd); + gen_helper_msa_ftint_u_df(cpu_env, tdf, twd, tws); + break; + case OPC_MSA_FFINT_S_df: + check_msa_access(env, ctx, -1, ws, wd); + gen_helper_msa_ffint_s_df(cpu_env, tdf, twd, tws); + break; + case OPC_MSA_FFINT_U_df: + check_msa_access(env, ctx, -1, ws, wd); + gen_helper_msa_ffint_u_df(cpu_env, tdf, twd, tws); + break; + } + + tcg_temp_free_i32(tdf); + } + break; default: break; } -- 1.7.4