target-mips: add MSA 3R format instructions

add MSA 3R format instructions

Signed-off-by: Yongbok Kim <yongbok.kim@imgtec.com>
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
This commit is contained in:
Yongbok Kim 2014-11-01 05:28:46 +00:00 committed by Leon Alrae
parent d4cf28dec2
commit 28f99f08cf
3 changed files with 963 additions and 0 deletions

View File

@ -784,3 +784,67 @@ DEF_HELPER_5(msa_sat_s_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_sat_u_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_srari_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_srlri_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_sll_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_sra_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_srl_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_bclr_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_bset_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_bneg_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_binsl_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_binsr_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_addv_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_subv_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_max_s_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_max_u_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_min_s_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_min_u_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_max_a_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_min_a_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_ceq_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_clt_s_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_clt_u_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_cle_s_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_cle_u_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_add_a_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_adds_a_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_adds_s_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_adds_u_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_ave_s_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_ave_u_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_aver_s_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_aver_u_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_subs_s_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_subs_u_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_subsus_u_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_subsuu_s_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_asub_s_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_asub_u_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_mulv_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_maddv_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_msubv_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_div_s_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_div_u_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_mod_s_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_mod_u_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_dotp_s_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_dotp_u_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_dpadd_s_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_dpadd_u_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_dpsub_s_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_dpsub_u_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_sld_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_splat_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_pckev_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_pckod_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_ilvl_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_ilvr_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_ilvev_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_ilvod_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_vshf_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_srar_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_srlr_df, void, env, i32, 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)
DEF_HELPER_5(msa_hsub_u_df, void, env, i32, i32, i32, i32)

View File

@ -451,3 +451,660 @@ void helper_msa_ ## helper ## _df(CPUMIPSState *env, uint32_t df, \
MSA_TEROP_IMMU_DF(binsli, binsl)
MSA_TEROP_IMMU_DF(binsri, binsr)
#undef MSA_TEROP_IMMU_DF
static inline int64_t msa_max_a_df(uint32_t df, int64_t arg1, int64_t arg2)
{
uint64_t abs_arg1 = arg1 >= 0 ? arg1 : -arg1;
uint64_t abs_arg2 = arg2 >= 0 ? arg2 : -arg2;
return abs_arg1 > abs_arg2 ? arg1 : arg2;
}
static inline int64_t msa_min_a_df(uint32_t df, int64_t arg1, int64_t arg2)
{
uint64_t abs_arg1 = arg1 >= 0 ? arg1 : -arg1;
uint64_t abs_arg2 = arg2 >= 0 ? arg2 : -arg2;
return abs_arg1 < abs_arg2 ? arg1 : arg2;
}
static inline int64_t msa_add_a_df(uint32_t df, int64_t arg1, int64_t arg2)
{
uint64_t abs_arg1 = arg1 >= 0 ? arg1 : -arg1;
uint64_t abs_arg2 = arg2 >= 0 ? arg2 : -arg2;
return abs_arg1 + abs_arg2;
}
static inline int64_t msa_adds_a_df(uint32_t df, int64_t arg1, int64_t arg2)
{
uint64_t max_int = (uint64_t)DF_MAX_INT(df);
uint64_t abs_arg1 = arg1 >= 0 ? arg1 : -arg1;
uint64_t abs_arg2 = arg2 >= 0 ? arg2 : -arg2;
if (abs_arg1 > max_int || abs_arg2 > max_int) {
return (int64_t)max_int;
} else {
return (abs_arg1 < max_int - abs_arg2) ? abs_arg1 + abs_arg2 : max_int;
}
}
static inline int64_t msa_adds_s_df(uint32_t df, int64_t arg1, int64_t arg2)
{
int64_t max_int = DF_MAX_INT(df);
int64_t min_int = DF_MIN_INT(df);
if (arg1 < 0) {
return (min_int - arg1 < arg2) ? arg1 + arg2 : min_int;
} else {
return (arg2 < max_int - arg1) ? arg1 + arg2 : max_int;
}
}
static inline uint64_t msa_adds_u_df(uint32_t df, uint64_t arg1, uint64_t arg2)
{
uint64_t max_uint = DF_MAX_UINT(df);
uint64_t u_arg1 = UNSIGNED(arg1, df);
uint64_t u_arg2 = UNSIGNED(arg2, df);
return (u_arg1 < max_uint - u_arg2) ? u_arg1 + u_arg2 : max_uint;
}
static inline int64_t msa_ave_s_df(uint32_t df, int64_t arg1, int64_t arg2)
{
/* signed shift */
return (arg1 >> 1) + (arg2 >> 1) + (arg1 & arg2 & 1);
}
static inline uint64_t msa_ave_u_df(uint32_t df, uint64_t arg1, uint64_t arg2)
{
uint64_t u_arg1 = UNSIGNED(arg1, df);
uint64_t u_arg2 = UNSIGNED(arg2, df);
/* unsigned shift */
return (u_arg1 >> 1) + (u_arg2 >> 1) + (u_arg1 & u_arg2 & 1);
}
static inline int64_t msa_aver_s_df(uint32_t df, int64_t arg1, int64_t arg2)
{
/* signed shift */
return (arg1 >> 1) + (arg2 >> 1) + ((arg1 | arg2) & 1);
}
static inline uint64_t msa_aver_u_df(uint32_t df, uint64_t arg1, uint64_t arg2)
{
uint64_t u_arg1 = UNSIGNED(arg1, df);
uint64_t u_arg2 = UNSIGNED(arg2, df);
/* unsigned shift */
return (u_arg1 >> 1) + (u_arg2 >> 1) + ((u_arg1 | u_arg2) & 1);
}
static inline int64_t msa_subs_s_df(uint32_t df, int64_t arg1, int64_t arg2)
{
int64_t max_int = DF_MAX_INT(df);
int64_t min_int = DF_MIN_INT(df);
if (arg2 > 0) {
return (min_int + arg2 < arg1) ? arg1 - arg2 : min_int;
} else {
return (arg1 < max_int + arg2) ? arg1 - arg2 : max_int;
}
}
static inline int64_t msa_subs_u_df(uint32_t df, int64_t arg1, int64_t arg2)
{
uint64_t u_arg1 = UNSIGNED(arg1, df);
uint64_t u_arg2 = UNSIGNED(arg2, df);
return (u_arg1 > u_arg2) ? u_arg1 - u_arg2 : 0;
}
static inline int64_t msa_subsus_u_df(uint32_t df, int64_t arg1, int64_t arg2)
{
uint64_t u_arg1 = UNSIGNED(arg1, df);
uint64_t max_uint = DF_MAX_UINT(df);
if (arg2 >= 0) {
uint64_t u_arg2 = (uint64_t)arg2;
return (u_arg1 > u_arg2) ?
(int64_t)(u_arg1 - u_arg2) :
0;
} else {
uint64_t u_arg2 = (uint64_t)(-arg2);
return (u_arg1 < max_uint - u_arg2) ?
(int64_t)(u_arg1 + u_arg2) :
(int64_t)max_uint;
}
}
static inline int64_t msa_subsuu_s_df(uint32_t df, int64_t arg1, int64_t arg2)
{
uint64_t u_arg1 = UNSIGNED(arg1, df);
uint64_t u_arg2 = UNSIGNED(arg2, df);
int64_t max_int = DF_MAX_INT(df);
int64_t min_int = DF_MIN_INT(df);
if (u_arg1 > u_arg2) {
return u_arg1 - u_arg2 < (uint64_t)max_int ?
(int64_t)(u_arg1 - u_arg2) :
max_int;
} else {
return u_arg2 - u_arg1 < (uint64_t)(-min_int) ?
(int64_t)(u_arg1 - u_arg2) :
min_int;
}
}
static inline int64_t msa_asub_s_df(uint32_t df, int64_t arg1, int64_t arg2)
{
/* signed compare */
return (arg1 < arg2) ?
(uint64_t)(arg2 - arg1) : (uint64_t)(arg1 - arg2);
}
static inline uint64_t msa_asub_u_df(uint32_t df, uint64_t arg1, uint64_t arg2)
{
uint64_t u_arg1 = UNSIGNED(arg1, df);
uint64_t u_arg2 = UNSIGNED(arg2, df);
/* unsigned compare */
return (u_arg1 < u_arg2) ?
(uint64_t)(u_arg2 - u_arg1) : (uint64_t)(u_arg1 - u_arg2);
}
static inline int64_t msa_mulv_df(uint32_t df, int64_t arg1, int64_t arg2)
{
return arg1 * arg2;
}
static inline int64_t msa_div_s_df(uint32_t df, int64_t arg1, int64_t arg2)
{
if (arg1 == DF_MIN_INT(df) && arg2 == -1) {
return DF_MIN_INT(df);
}
return arg2 ? arg1 / arg2 : 0;
}
static inline int64_t msa_div_u_df(uint32_t df, int64_t arg1, int64_t arg2)
{
uint64_t u_arg1 = UNSIGNED(arg1, df);
uint64_t u_arg2 = UNSIGNED(arg2, df);
return u_arg2 ? u_arg1 / u_arg2 : 0;
}
static inline int64_t msa_mod_s_df(uint32_t df, int64_t arg1, int64_t arg2)
{
if (arg1 == DF_MIN_INT(df) && arg2 == -1) {
return 0;
}
return arg2 ? arg1 % arg2 : 0;
}
static inline int64_t msa_mod_u_df(uint32_t df, int64_t arg1, int64_t arg2)
{
uint64_t u_arg1 = UNSIGNED(arg1, df);
uint64_t u_arg2 = UNSIGNED(arg2, df);
return u_arg2 ? u_arg1 % u_arg2 : 0;
}
#define SIGNED_EVEN(a, df) \
((((int64_t)(a)) << (64 - DF_BITS(df)/2)) >> (64 - DF_BITS(df)/2))
#define UNSIGNED_EVEN(a, df) \
((((uint64_t)(a)) << (64 - DF_BITS(df)/2)) >> (64 - DF_BITS(df)/2))
#define SIGNED_ODD(a, df) \
((((int64_t)(a)) << (64 - DF_BITS(df))) >> (64 - DF_BITS(df)/2))
#define UNSIGNED_ODD(a, df) \
((((uint64_t)(a)) << (64 - DF_BITS(df))) >> (64 - DF_BITS(df)/2))
#define SIGNED_EXTRACT(e, o, a, df) \
do { \
e = SIGNED_EVEN(a, df); \
o = SIGNED_ODD(a, df); \
} while (0);
#define UNSIGNED_EXTRACT(e, o, a, df) \
do { \
e = UNSIGNED_EVEN(a, df); \
o = UNSIGNED_ODD(a, df); \
} while (0);
static inline int64_t msa_dotp_s_df(uint32_t df, int64_t arg1, int64_t arg2)
{
int64_t even_arg1;
int64_t even_arg2;
int64_t odd_arg1;
int64_t odd_arg2;
SIGNED_EXTRACT(even_arg1, odd_arg1, arg1, df);
SIGNED_EXTRACT(even_arg2, odd_arg2, arg2, df);
return (even_arg1 * even_arg2) + (odd_arg1 * odd_arg2);
}
static inline int64_t msa_dotp_u_df(uint32_t df, int64_t arg1, int64_t arg2)
{
int64_t even_arg1;
int64_t even_arg2;
int64_t odd_arg1;
int64_t odd_arg2;
UNSIGNED_EXTRACT(even_arg1, odd_arg1, arg1, df);
UNSIGNED_EXTRACT(even_arg2, odd_arg2, arg2, df);
return (even_arg1 * even_arg2) + (odd_arg1 * odd_arg2);
}
#define CONCATENATE_AND_SLIDE(s, k) \
do { \
for (i = 0; i < s; i++) { \
v[i] = pws->b[s * k + i]; \
v[i + s] = pwd->b[s * k + i]; \
} \
for (i = 0; i < s; i++) { \
pwd->b[s * k + i] = v[i + n]; \
} \
} while (0)
static inline void msa_sld_df(uint32_t df, wr_t *pwd,
wr_t *pws, target_ulong rt)
{
uint32_t n = rt % DF_ELEMENTS(df);
uint8_t v[64];
uint32_t i, k;
switch (df) {
case DF_BYTE:
CONCATENATE_AND_SLIDE(DF_ELEMENTS(DF_BYTE), 0);
break;
case DF_HALF:
for (k = 0; k < 2; k++) {
CONCATENATE_AND_SLIDE(DF_ELEMENTS(DF_HALF), k);
}
break;
case DF_WORD:
for (k = 0; k < 4; k++) {
CONCATENATE_AND_SLIDE(DF_ELEMENTS(DF_WORD), k);
}
break;
case DF_DOUBLE:
for (k = 0; k < 8; k++) {
CONCATENATE_AND_SLIDE(DF_ELEMENTS(DF_DOUBLE), k);
}
break;
default:
assert(0);
}
}
static inline int64_t msa_hadd_s_df(uint32_t df, int64_t arg1, int64_t arg2)
{
return SIGNED_ODD(arg1, df) + SIGNED_EVEN(arg2, df);
}
static inline int64_t msa_hadd_u_df(uint32_t df, int64_t arg1, int64_t arg2)
{
return UNSIGNED_ODD(arg1, df) + UNSIGNED_EVEN(arg2, df);
}
static inline int64_t msa_hsub_s_df(uint32_t df, int64_t arg1, int64_t arg2)
{
return SIGNED_ODD(arg1, df) - SIGNED_EVEN(arg2, df);
}
static inline int64_t msa_hsub_u_df(uint32_t df, int64_t arg1, int64_t arg2)
{
return UNSIGNED_ODD(arg1, df) - UNSIGNED_EVEN(arg2, df);
}
#define MSA_BINOP_DF(func) \
void helper_msa_ ## func ## _df(CPUMIPSState *env, uint32_t df, \
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; \
\
switch (df) { \
case DF_BYTE: \
for (i = 0; i < DF_ELEMENTS(DF_BYTE); i++) { \
pwd->b[i] = msa_ ## func ## _df(df, pws->b[i], pwt->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], pwt->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], pwt->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], pwt->d[i]); \
} \
break; \
default: \
assert(0); \
} \
}
MSA_BINOP_DF(sll)
MSA_BINOP_DF(sra)
MSA_BINOP_DF(srl)
MSA_BINOP_DF(bclr)
MSA_BINOP_DF(bset)
MSA_BINOP_DF(bneg)
MSA_BINOP_DF(addv)
MSA_BINOP_DF(subv)
MSA_BINOP_DF(max_s)
MSA_BINOP_DF(max_u)
MSA_BINOP_DF(min_s)
MSA_BINOP_DF(min_u)
MSA_BINOP_DF(max_a)
MSA_BINOP_DF(min_a)
MSA_BINOP_DF(ceq)
MSA_BINOP_DF(clt_s)
MSA_BINOP_DF(clt_u)
MSA_BINOP_DF(cle_s)
MSA_BINOP_DF(cle_u)
MSA_BINOP_DF(add_a)
MSA_BINOP_DF(adds_a)
MSA_BINOP_DF(adds_s)
MSA_BINOP_DF(adds_u)
MSA_BINOP_DF(ave_s)
MSA_BINOP_DF(ave_u)
MSA_BINOP_DF(aver_s)
MSA_BINOP_DF(aver_u)
MSA_BINOP_DF(subs_s)
MSA_BINOP_DF(subs_u)
MSA_BINOP_DF(subsus_u)
MSA_BINOP_DF(subsuu_s)
MSA_BINOP_DF(asub_s)
MSA_BINOP_DF(asub_u)
MSA_BINOP_DF(mulv)
MSA_BINOP_DF(div_s)
MSA_BINOP_DF(div_u)
MSA_BINOP_DF(mod_s)
MSA_BINOP_DF(mod_u)
MSA_BINOP_DF(dotp_s)
MSA_BINOP_DF(dotp_u)
MSA_BINOP_DF(srar)
MSA_BINOP_DF(srlr)
MSA_BINOP_DF(hadd_s)
MSA_BINOP_DF(hadd_u)
MSA_BINOP_DF(hsub_s)
MSA_BINOP_DF(hsub_u)
#undef MSA_BINOP_DF
void helper_msa_sld_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
uint32_t ws, uint32_t rt)
{
wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
wr_t *pws = &(env->active_fpu.fpr[ws].wr);
msa_sld_df(df, pwd, pws, env->active_tc.gpr[rt]);
}
static inline int64_t msa_maddv_df(uint32_t df, int64_t dest, int64_t arg1,
int64_t arg2)
{
return dest + arg1 * arg2;
}
static inline int64_t msa_msubv_df(uint32_t df, int64_t dest, int64_t arg1,
int64_t arg2)
{
return dest - arg1 * arg2;
}
static inline int64_t msa_dpadd_s_df(uint32_t df, int64_t dest, int64_t arg1,
int64_t arg2)
{
int64_t even_arg1;
int64_t even_arg2;
int64_t odd_arg1;
int64_t odd_arg2;
SIGNED_EXTRACT(even_arg1, odd_arg1, arg1, df);
SIGNED_EXTRACT(even_arg2, odd_arg2, arg2, df);
return dest + (even_arg1 * even_arg2) + (odd_arg1 * odd_arg2);
}
static inline int64_t msa_dpadd_u_df(uint32_t df, int64_t dest, int64_t arg1,
int64_t arg2)
{
int64_t even_arg1;
int64_t even_arg2;
int64_t odd_arg1;
int64_t odd_arg2;
UNSIGNED_EXTRACT(even_arg1, odd_arg1, arg1, df);
UNSIGNED_EXTRACT(even_arg2, odd_arg2, arg2, df);
return dest + (even_arg1 * even_arg2) + (odd_arg1 * odd_arg2);
}
static inline int64_t msa_dpsub_s_df(uint32_t df, int64_t dest, int64_t arg1,
int64_t arg2)
{
int64_t even_arg1;
int64_t even_arg2;
int64_t odd_arg1;
int64_t odd_arg2;
SIGNED_EXTRACT(even_arg1, odd_arg1, arg1, df);
SIGNED_EXTRACT(even_arg2, odd_arg2, arg2, df);
return dest - ((even_arg1 * even_arg2) + (odd_arg1 * odd_arg2));
}
static inline int64_t msa_dpsub_u_df(uint32_t df, int64_t dest, int64_t arg1,
int64_t arg2)
{
int64_t even_arg1;
int64_t even_arg2;
int64_t odd_arg1;
int64_t odd_arg2;
UNSIGNED_EXTRACT(even_arg1, odd_arg1, arg1, df);
UNSIGNED_EXTRACT(even_arg2, odd_arg2, arg2, df);
return dest - ((even_arg1 * even_arg2) + (odd_arg1 * odd_arg2));
}
#define MSA_TEROP_DF(func) \
void helper_msa_ ## func ## _df(CPUMIPSState *env, uint32_t df, 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; \
\
switch (df) { \
case DF_BYTE: \
for (i = 0; i < DF_ELEMENTS(DF_BYTE); i++) { \
pwd->b[i] = msa_ ## func ## _df(df, pwd->b[i], pws->b[i], \
pwt->b[i]); \
} \
break; \
case DF_HALF: \
for (i = 0; i < DF_ELEMENTS(DF_HALF); i++) { \
pwd->h[i] = msa_ ## func ## _df(df, pwd->h[i], pws->h[i], \
pwt->h[i]); \
} \
break; \
case DF_WORD: \
for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { \
pwd->w[i] = msa_ ## func ## _df(df, pwd->w[i], pws->w[i], \
pwt->w[i]); \
} \
break; \
case DF_DOUBLE: \
for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { \
pwd->d[i] = msa_ ## func ## _df(df, pwd->d[i], pws->d[i], \
pwt->d[i]); \
} \
break; \
default: \
assert(0); \
} \
}
MSA_TEROP_DF(maddv)
MSA_TEROP_DF(msubv)
MSA_TEROP_DF(dpadd_s)
MSA_TEROP_DF(dpadd_u)
MSA_TEROP_DF(dpsub_s)
MSA_TEROP_DF(dpsub_u)
MSA_TEROP_DF(binsl)
MSA_TEROP_DF(binsr)
#undef MSA_TEROP_DF
static inline void msa_splat_df(uint32_t df, wr_t *pwd,
wr_t *pws, target_ulong rt)
{
uint32_t n = rt % DF_ELEMENTS(df);
uint32_t i;
switch (df) {
case DF_BYTE:
for (i = 0; i < DF_ELEMENTS(DF_BYTE); i++) {
pwd->b[i] = pws->b[n];
}
break;
case DF_HALF:
for (i = 0; i < DF_ELEMENTS(DF_HALF); i++) {
pwd->h[i] = pws->h[n];
}
break;
case DF_WORD:
for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) {
pwd->w[i] = pws->w[n];
}
break;
case DF_DOUBLE:
for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) {
pwd->d[i] = pws->d[n];
}
break;
default:
assert(0);
}
}
void helper_msa_splat_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
uint32_t ws, uint32_t rt)
{
wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
wr_t *pws = &(env->active_fpu.fpr[ws].wr);
msa_splat_df(df, pwd, pws, env->active_tc.gpr[rt]);
}
#define MSA_DO_B MSA_DO(b)
#define MSA_DO_H MSA_DO(h)
#define MSA_DO_W MSA_DO(w)
#define MSA_DO_D MSA_DO(d)
#define MSA_LOOP_B MSA_LOOP(B)
#define MSA_LOOP_H MSA_LOOP(H)
#define MSA_LOOP_W MSA_LOOP(W)
#define MSA_LOOP_D MSA_LOOP(D)
#define MSA_LOOP_COND_B MSA_LOOP_COND(DF_BYTE)
#define MSA_LOOP_COND_H MSA_LOOP_COND(DF_HALF)
#define MSA_LOOP_COND_W MSA_LOOP_COND(DF_WORD)
#define MSA_LOOP_COND_D MSA_LOOP_COND(DF_DOUBLE)
#define MSA_LOOP(DF) \
for (i = 0; i < (MSA_LOOP_COND_ ## DF) ; i++) { \
MSA_DO_ ## DF \
}
#define MSA_FN_DF(FUNC) \
void helper_msa_##FUNC(CPUMIPSState *env, uint32_t df, 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); \
wr_t wx, *pwx = &wx; \
uint32_t i; \
switch (df) { \
case DF_BYTE: \
MSA_LOOP_B \
break; \
case DF_HALF: \
MSA_LOOP_H \
break; \
case DF_WORD: \
MSA_LOOP_W \
break; \
case DF_DOUBLE: \
MSA_LOOP_D \
break; \
default: \
assert(0); \
} \
msa_move_v(pwd, pwx); \
}
#define MSA_LOOP_COND(DF) \
(DF_ELEMENTS(DF) / 2)
#define Rb(pwr, i) (pwr->b[i])
#define Lb(pwr, i) (pwr->b[i + DF_ELEMENTS(DF_BYTE)/2])
#define Rh(pwr, i) (pwr->h[i])
#define Lh(pwr, i) (pwr->h[i + DF_ELEMENTS(DF_HALF)/2])
#define Rw(pwr, i) (pwr->w[i])
#define Lw(pwr, i) (pwr->w[i + DF_ELEMENTS(DF_WORD)/2])
#define Rd(pwr, i) (pwr->d[i])
#define Ld(pwr, i) (pwr->d[i + DF_ELEMENTS(DF_DOUBLE)/2])
#define MSA_DO(DF) \
do { \
R##DF(pwx, i) = pwt->DF[2*i]; \
L##DF(pwx, i) = pws->DF[2*i]; \
} while (0);
MSA_FN_DF(pckev_df)
#undef MSA_DO
#define MSA_DO(DF) \
do { \
R##DF(pwx, i) = pwt->DF[2*i+1]; \
L##DF(pwx, i) = pws->DF[2*i+1]; \
} while (0);
MSA_FN_DF(pckod_df)
#undef MSA_DO
#define MSA_DO(DF) \
do { \
pwx->DF[2*i] = L##DF(pwt, i); \
pwx->DF[2*i+1] = L##DF(pws, i); \
} while (0);
MSA_FN_DF(ilvl_df)
#undef MSA_DO
#define MSA_DO(DF) \
do { \
pwx->DF[2*i] = R##DF(pwt, i); \
pwx->DF[2*i+1] = R##DF(pws, i); \
} while (0);
MSA_FN_DF(ilvr_df)
#undef MSA_DO
#define MSA_DO(DF) \
do { \
pwx->DF[2*i] = pwt->DF[2*i]; \
pwx->DF[2*i+1] = pws->DF[2*i]; \
} while (0);
MSA_FN_DF(ilvev_df)
#undef MSA_DO
#define MSA_DO(DF) \
do { \
pwx->DF[2*i] = pwt->DF[2*i+1]; \
pwx->DF[2*i+1] = pws->DF[2*i+1]; \
} while (0);
MSA_FN_DF(ilvod_df)
#undef MSA_DO
#undef MSA_LOOP_COND
#define MSA_LOOP_COND(DF) \
(DF_ELEMENTS(DF))
#define MSA_DO(DF) \
do { \
uint32_t n = DF_ELEMENTS(df); \
uint32_t k = (pwd->DF[i] & 0x3f) % (2 * n); \
pwx->DF[i] = \
(pwd->DF[i] & 0xc0) ? 0 : k < n ? pwt->DF[k] : pws->DF[k - n]; \
} while (0);
MSA_FN_DF(vshf_df)
#undef MSA_DO
#undef MSA_LOOP_COND
#undef MSA_FN_DF

View File

@ -17549,6 +17549,237 @@ static void gen_msa_bit(CPUMIPSState *env, DisasContext *ctx)
tcg_temp_free_i32(tws);
}
static void gen_msa_3r(CPUMIPSState *env, DisasContext *ctx)
{
#define MASK_MSA_3R(op) (MASK_MSA_MINOR(op) | (op & (0x7 << 23)))
uint8_t df = (ctx->opcode >> 21) & 0x3;
uint8_t wt = (ctx->opcode >> 16) & 0x1f;
uint8_t ws = (ctx->opcode >> 11) & 0x1f;
uint8_t wd = (ctx->opcode >> 6) & 0x1f;
TCGv_i32 tdf = tcg_const_i32(df);
TCGv_i32 twd = tcg_const_i32(wd);
TCGv_i32 tws = tcg_const_i32(ws);
TCGv_i32 twt = tcg_const_i32(wt);
switch (MASK_MSA_3R(ctx->opcode)) {
case OPC_SLL_df:
gen_helper_msa_sll_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_ADDV_df:
gen_helper_msa_addv_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_CEQ_df:
gen_helper_msa_ceq_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_ADD_A_df:
gen_helper_msa_add_a_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_SUBS_S_df:
gen_helper_msa_subs_s_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_MULV_df:
gen_helper_msa_mulv_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_SLD_df:
gen_helper_msa_sld_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_VSHF_df:
gen_helper_msa_vshf_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_SRA_df:
gen_helper_msa_sra_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_SUBV_df:
gen_helper_msa_subv_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_ADDS_A_df:
gen_helper_msa_adds_a_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_SUBS_U_df:
gen_helper_msa_subs_u_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_MADDV_df:
gen_helper_msa_maddv_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_SPLAT_df:
gen_helper_msa_splat_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_SRAR_df:
gen_helper_msa_srar_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_SRL_df:
gen_helper_msa_srl_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_MAX_S_df:
gen_helper_msa_max_s_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_CLT_S_df:
gen_helper_msa_clt_s_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_ADDS_S_df:
gen_helper_msa_adds_s_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_SUBSUS_U_df:
gen_helper_msa_subsus_u_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_MSUBV_df:
gen_helper_msa_msubv_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_PCKEV_df:
gen_helper_msa_pckev_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_SRLR_df:
gen_helper_msa_srlr_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_BCLR_df:
gen_helper_msa_bclr_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_MAX_U_df:
gen_helper_msa_max_u_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_CLT_U_df:
gen_helper_msa_clt_u_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_ADDS_U_df:
gen_helper_msa_adds_u_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_SUBSUU_S_df:
gen_helper_msa_subsuu_s_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_PCKOD_df:
gen_helper_msa_pckod_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_BSET_df:
gen_helper_msa_bset_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_MIN_S_df:
gen_helper_msa_min_s_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_CLE_S_df:
gen_helper_msa_cle_s_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_AVE_S_df:
gen_helper_msa_ave_s_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_ASUB_S_df:
gen_helper_msa_asub_s_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_DIV_S_df:
gen_helper_msa_div_s_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_ILVL_df:
gen_helper_msa_ilvl_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_BNEG_df:
gen_helper_msa_bneg_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_MIN_U_df:
gen_helper_msa_min_u_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_CLE_U_df:
gen_helper_msa_cle_u_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_AVE_U_df:
gen_helper_msa_ave_u_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_ASUB_U_df:
gen_helper_msa_asub_u_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_DIV_U_df:
gen_helper_msa_div_u_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_ILVR_df:
gen_helper_msa_ilvr_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_BINSL_df:
gen_helper_msa_binsl_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_MAX_A_df:
gen_helper_msa_max_a_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_AVER_S_df:
gen_helper_msa_aver_s_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_MOD_S_df:
gen_helper_msa_mod_s_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_ILVEV_df:
gen_helper_msa_ilvev_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_BINSR_df:
gen_helper_msa_binsr_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_MIN_A_df:
gen_helper_msa_min_a_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_AVER_U_df:
gen_helper_msa_aver_u_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_MOD_U_df:
gen_helper_msa_mod_u_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_ILVOD_df:
gen_helper_msa_ilvod_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_DOTP_S_df:
case OPC_DOTP_U_df:
case OPC_DPADD_S_df:
case OPC_DPADD_U_df:
case OPC_DPSUB_S_df:
case OPC_HADD_S_df:
case OPC_DPSUB_U_df:
case OPC_HADD_U_df:
case OPC_HSUB_S_df:
case OPC_HSUB_U_df:
if (df == DF_BYTE) {
generate_exception(ctx, EXCP_RI);
}
switch (MASK_MSA_3R(ctx->opcode)) {
case OPC_DOTP_S_df:
gen_helper_msa_dotp_s_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_DOTP_U_df:
gen_helper_msa_dotp_u_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_DPADD_S_df:
gen_helper_msa_dpadd_s_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_DPADD_U_df:
gen_helper_msa_dpadd_u_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_DPSUB_S_df:
gen_helper_msa_dpsub_s_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_HADD_S_df:
gen_helper_msa_hadd_s_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_DPSUB_U_df:
gen_helper_msa_dpsub_u_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_HADD_U_df:
gen_helper_msa_hadd_u_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_HSUB_S_df:
gen_helper_msa_hsub_s_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_HSUB_U_df:
gen_helper_msa_hsub_u_df(cpu_env, tdf, twd, tws, twt);
break;
}
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(CPUMIPSState *env, DisasContext *ctx)
{
uint32_t opcode = ctx->opcode;
@ -17569,6 +17800,17 @@ static void gen_msa(CPUMIPSState *env, DisasContext *ctx)
case OPC_MSA_BIT_0A:
gen_msa_bit(env, ctx);
break;
case OPC_MSA_3R_0D:
case OPC_MSA_3R_0E:
case OPC_MSA_3R_0F:
case OPC_MSA_3R_10:
case OPC_MSA_3R_11:
case OPC_MSA_3R_12:
case OPC_MSA_3R_13:
case OPC_MSA_3R_14:
case OPC_MSA_3R_15:
gen_msa_3r(env, ctx);
break;
default:
MIPS_INVAL("MSA instruction");
generate_exception(ctx, EXCP_RI);