diff --git a/target-mips/helper.h b/target-mips/helper.h index cee4eb47e7..3185c1d356 100644 --- a/target-mips/helper.h +++ b/target-mips/helper.h @@ -900,3 +900,15 @@ DEF_HELPER_5(msa_fsne_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_mulr_q_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_maddr_q_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_msubr_q_df, void, env, i32, i32, i32, i32) + +DEF_HELPER_4(msa_and_v, void, env, i32, i32, i32) +DEF_HELPER_4(msa_or_v, void, env, i32, i32, i32) +DEF_HELPER_4(msa_nor_v, void, env, i32, i32, i32) +DEF_HELPER_4(msa_xor_v, void, env, i32, i32, i32) +DEF_HELPER_4(msa_bmnz_v, void, env, i32, i32, i32) +DEF_HELPER_4(msa_bmz_v, void, env, i32, i32, i32) +DEF_HELPER_4(msa_bsel_v, void, env, i32, i32, i32) +DEF_HELPER_4(msa_fill_df, void, env, i32, i32, i32) +DEF_HELPER_4(msa_pcnt_df, void, env, i32, i32, i32) +DEF_HELPER_4(msa_nloc_df, void, env, i32, i32, i32) +DEF_HELPER_4(msa_nlzc_df, void, env, i32, i32, i32) diff --git a/target-mips/msa_helper.c b/target-mips/msa_helper.c index 3f3d9ebe5e..a96a64882f 100644 --- a/target-mips/msa_helper.c +++ b/target-mips/msa_helper.c @@ -114,6 +114,34 @@ void helper_msa_shf_df(CPUMIPSState *env, uint32_t df, uint32_t wd, msa_move_v(pwd, pwx); } +#define MSA_FN_VECTOR(FUNC, DEST, OPERATION) \ +void helper_msa_ ## FUNC(CPUMIPSState *env, uint32_t wd, uint32_t ws, \ + uint32_t wt) \ +{ \ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); \ + wr_t *pws = &(env->active_fpu.fpr[ws].wr); \ + wr_t *pwt = &(env->active_fpu.fpr[wt].wr); \ + uint32_t i; \ + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { \ + DEST = OPERATION; \ + } \ +} + +MSA_FN_VECTOR(and_v, pwd->d[i], pws->d[i] & pwt->d[i]) +MSA_FN_VECTOR(or_v, pwd->d[i], pws->d[i] | pwt->d[i]) +MSA_FN_VECTOR(nor_v, pwd->d[i], ~(pws->d[i] | pwt->d[i])) +MSA_FN_VECTOR(xor_v, pwd->d[i], pws->d[i] ^ pwt->d[i]) +MSA_FN_VECTOR(bmnz_v, pwd->d[i], + BIT_MOVE_IF_NOT_ZERO(pwd->d[i], pws->d[i], pwt->d[i], DF_DOUBLE)) +MSA_FN_VECTOR(bmz_v, pwd->d[i], + BIT_MOVE_IF_ZERO(pwd->d[i], pws->d[i], pwt->d[i], DF_DOUBLE)) +MSA_FN_VECTOR(bsel_v, pwd->d[i], + BIT_SELECT(pwd->d[i], pws->d[i], pwt->d[i], DF_DOUBLE)) +#undef BIT_MOVE_IF_NOT_ZERO +#undef BIT_MOVE_IF_ZERO +#undef BIT_SELECT +#undef MSA_FN_VECTOR + static inline int64_t msa_addv_df(uint32_t df, int64_t arg1, int64_t arg2) { return arg1 + arg2; @@ -1359,6 +1387,118 @@ void helper_msa_move_v(CPUMIPSState *env, uint32_t wd, uint32_t ws) msa_move_v(pwd, pws); } +static inline int64_t msa_pcnt_df(uint32_t df, int64_t arg) +{ + uint64_t x; + + x = UNSIGNED(arg, df); + + x = (x & 0x5555555555555555ULL) + ((x >> 1) & 0x5555555555555555ULL); + x = (x & 0x3333333333333333ULL) + ((x >> 2) & 0x3333333333333333ULL); + x = (x & 0x0F0F0F0F0F0F0F0FULL) + ((x >> 4) & 0x0F0F0F0F0F0F0F0FULL); + x = (x & 0x00FF00FF00FF00FFULL) + ((x >> 8) & 0x00FF00FF00FF00FFULL); + x = (x & 0x0000FFFF0000FFFFULL) + ((x >> 16) & 0x0000FFFF0000FFFFULL); + x = (x & 0x00000000FFFFFFFFULL) + ((x >> 32)); + + return x; +} + +static inline int64_t msa_nlzc_df(uint32_t df, int64_t arg) +{ + uint64_t x, y; + int n, c; + + x = UNSIGNED(arg, df); + n = DF_BITS(df); + c = DF_BITS(df) / 2; + + do { + y = x >> c; + if (y != 0) { + n = n - c; + x = y; + } + c = c >> 1; + } while (c != 0); + + return n - x; +} + +static inline int64_t msa_nloc_df(uint32_t df, int64_t arg) +{ + return msa_nlzc_df(df, UNSIGNED((~arg), df)); +} + +void helper_msa_fill_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t rs) +{ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); + uint32_t i; + + switch (df) { + case DF_BYTE: + for (i = 0; i < DF_ELEMENTS(DF_BYTE); i++) { + pwd->b[i] = (int8_t)env->active_tc.gpr[rs]; + } + break; + case DF_HALF: + for (i = 0; i < DF_ELEMENTS(DF_HALF); i++) { + pwd->h[i] = (int16_t)env->active_tc.gpr[rs]; + } + break; + case DF_WORD: + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { + pwd->w[i] = (int32_t)env->active_tc.gpr[rs]; + } + break; + case DF_DOUBLE: + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { + pwd->d[i] = (int64_t)env->active_tc.gpr[rs]; + } + break; + default: + assert(0); + } +} + +#define MSA_UNOP_DF(func) \ +void helper_msa_ ## func ## _df(CPUMIPSState *env, uint32_t df, \ + uint32_t wd, uint32_t ws) \ +{ \ + wr_t *pwd = &(env->active_fpu.fpr[wd].wr); \ + wr_t *pws = &(env->active_fpu.fpr[ws].wr); \ + uint32_t i; \ + \ + switch (df) { \ + case DF_BYTE: \ + for (i = 0; i < DF_ELEMENTS(DF_BYTE); i++) { \ + pwd->b[i] = msa_ ## func ## _df(df, pws->b[i]); \ + } \ + break; \ + case DF_HALF: \ + for (i = 0; i < DF_ELEMENTS(DF_HALF); i++) { \ + pwd->h[i] = msa_ ## func ## _df(df, pws->h[i]); \ + } \ + break; \ + case DF_WORD: \ + for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { \ + pwd->w[i] = msa_ ## func ## _df(df, pws->w[i]); \ + } \ + break; \ + case DF_DOUBLE: \ + for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { \ + pwd->d[i] = msa_ ## func ## _df(df, pws->d[i]); \ + } \ + break; \ + default: \ + assert(0); \ + } \ +} + +MSA_UNOP_DF(nlzc) +MSA_UNOP_DF(nloc) +MSA_UNOP_DF(pcnt) + #define FLOAT_ONE32 make_float32(0x3f8 << 20) #define FLOAT_ONE64 make_float64(0x3ffULL << 52) diff --git a/target-mips/translate.c b/target-mips/translate.c index aae023cc88..acaf5a32bc 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -18053,6 +18053,116 @@ static void gen_msa_3rf(CPUMIPSState *env, DisasContext *ctx) tcg_temp_free_i32(tdf); } +static void gen_msa_2r(CPUMIPSState *env, DisasContext *ctx) +{ +#define MASK_MSA_2R(op) (MASK_MSA_MINOR(op) | (op & (0x1f << 21)) | \ + (op & (0x7 << 18))) + uint8_t wt = (ctx->opcode >> 16) & 0x1f; + uint8_t ws = (ctx->opcode >> 11) & 0x1f; + uint8_t wd = (ctx->opcode >> 6) & 0x1f; + uint8_t df = (ctx->opcode >> 16) & 0x3; + TCGv_i32 twd = tcg_const_i32(wd); + TCGv_i32 tws = tcg_const_i32(ws); + TCGv_i32 twt = tcg_const_i32(wt); + TCGv_i32 tdf = tcg_const_i32(df); + + switch (MASK_MSA_2R(ctx->opcode)) { + case OPC_FILL_df: +#if !defined(TARGET_MIPS64) + /* Double format valid only for MIPS64 */ + if (df == DF_DOUBLE) { + generate_exception(ctx, EXCP_RI); + break; + } +#endif + gen_helper_msa_fill_df(cpu_env, tdf, twd, tws); /* trs */ + break; + case OPC_PCNT_df: + gen_helper_msa_pcnt_df(cpu_env, tdf, twd, tws); + break; + case OPC_NLOC_df: + gen_helper_msa_nloc_df(cpu_env, tdf, twd, tws); + break; + case OPC_NLZC_df: + gen_helper_msa_nlzc_df(cpu_env, tdf, twd, tws); + break; + default: + MIPS_INVAL("MSA instruction"); + generate_exception(ctx, EXCP_RI); + break; + } + + tcg_temp_free_i32(twd); + tcg_temp_free_i32(tws); + tcg_temp_free_i32(twt); + tcg_temp_free_i32(tdf); +} + +static void gen_msa_vec_v(CPUMIPSState *env, DisasContext *ctx) +{ +#define MASK_MSA_VEC(op) (MASK_MSA_MINOR(op) | (op & (0x1f << 21))) + uint8_t wt = (ctx->opcode >> 16) & 0x1f; + uint8_t ws = (ctx->opcode >> 11) & 0x1f; + uint8_t wd = (ctx->opcode >> 6) & 0x1f; + TCGv_i32 twd = tcg_const_i32(wd); + TCGv_i32 tws = tcg_const_i32(ws); + TCGv_i32 twt = tcg_const_i32(wt); + + switch (MASK_MSA_VEC(ctx->opcode)) { + case OPC_AND_V: + gen_helper_msa_and_v(cpu_env, twd, tws, twt); + break; + case OPC_OR_V: + gen_helper_msa_or_v(cpu_env, twd, tws, twt); + break; + case OPC_NOR_V: + gen_helper_msa_nor_v(cpu_env, twd, tws, twt); + break; + case OPC_XOR_V: + gen_helper_msa_xor_v(cpu_env, twd, tws, twt); + break; + case OPC_BMNZ_V: + gen_helper_msa_bmnz_v(cpu_env, twd, tws, twt); + break; + case OPC_BMZ_V: + gen_helper_msa_bmz_v(cpu_env, twd, tws, twt); + break; + case OPC_BSEL_V: + gen_helper_msa_bsel_v(cpu_env, twd, tws, twt); + break; + default: + MIPS_INVAL("MSA instruction"); + generate_exception(ctx, EXCP_RI); + break; + } + + tcg_temp_free_i32(twd); + tcg_temp_free_i32(tws); + tcg_temp_free_i32(twt); +} + +static void gen_msa_vec(CPUMIPSState *env, DisasContext *ctx) +{ + switch (MASK_MSA_VEC(ctx->opcode)) { + case OPC_AND_V: + case OPC_OR_V: + case OPC_NOR_V: + case OPC_XOR_V: + case OPC_BMNZ_V: + case OPC_BMZ_V: + case OPC_BSEL_V: + gen_msa_vec_v(env, ctx); + break; + case OPC_MSA_2R: + gen_msa_2r(env, ctx); + break; + default: + MIPS_INVAL("MSA instruction"); + generate_exception(ctx, EXCP_RI); + break; + } +} + static void gen_msa(CPUMIPSState *env, DisasContext *ctx) { uint32_t opcode = ctx->opcode; @@ -18092,6 +18202,9 @@ static void gen_msa(CPUMIPSState *env, DisasContext *ctx) case OPC_MSA_3RF_1C: gen_msa_3rf(env, ctx); break; + case OPC_MSA_VEC: + gen_msa_vec(env, ctx); + break; default: MIPS_INVAL("MSA instruction"); generate_exception(ctx, EXCP_RI);