break;
case mfhc_op:
- if (!cpu_has_mips_r2)
+ if (!cpu_has_mips_r2_r6)
goto sigill;
/* copregister rd -> gpr[rt] */
break;
case mthc_op:
- if (!cpu_has_mips_r2)
+ if (!cpu_has_mips_r2_r6)
goto sigill;
/* copregister rd <- gpr[rt] */
}
break;
+ case bc1eqz_op:
+ case bc1nez_op:
+ if (!cpu_has_mips_r6 || delay_slot(xcp))
+ return SIGILL;
+
+ cond = likely = 0;
+ switch (MIPSInst_RS(ir)) {
+ case bc1eqz_op:
+ if (get_fpr32(¤t->thread.fpu.fpr[MIPSInst_RT(ir)], 0) & 0x1)
+ cond = 1;
+ break;
+ case bc1nez_op:
+ if (!(get_fpr32(¤t->thread.fpu.fpr[MIPSInst_RT(ir)], 0) & 0x1))
+ cond = 1;
+ break;
+ }
+ goto branch_common;
+
case bc_op:
if (delay_slot(xcp))
return SIGILL;
case bct_op:
break;
}
-
+branch_common:
set_delay_slot(xcp);
if (cond) {
/*
IEEE754_CLT | IEEE754_CEQ | IEEE754_CUN, /* cmp_ule (sig) cmp_ngt */
};
+static const unsigned char negative_cmptab[8] = {
+ 0, /* Reserved */
+ IEEE754_CLT | IEEE754_CGT | IEEE754_CEQ,
+ IEEE754_CLT | IEEE754_CGT | IEEE754_CUN,
+ IEEE754_CLT | IEEE754_CGT,
+ /* Reserved */
+};
+
/*
* Additional MIPS4 instructions
SPFROMREG(rv.s, MIPSInst_FS(ir));
break;
+ case fseleqz_op:
+ if (!cpu_has_mips_r6)
+ return SIGILL;
+
+ SPFROMREG(rv.s, MIPSInst_FT(ir));
+ if (rv.w & 0x1)
+ rv.w = 0;
+ else
+ SPFROMREG(rv.s, MIPSInst_FS(ir));
+ break;
+
+ case fselnez_op:
+ if (!cpu_has_mips_r6)
+ return SIGILL;
+
+ SPFROMREG(rv.s, MIPSInst_FT(ir));
+ if (rv.w & 0x1)
+ SPFROMREG(rv.s, MIPSInst_FS(ir));
+ else
+ rv.w = 0;
+ break;
+
+ case fmaddf_op: {
+ union ieee754sp ft, fs, fd;
+
+ if (!cpu_has_mips_r6)
+ return SIGILL;
+
+ SPFROMREG(ft, MIPSInst_FT(ir));
+ SPFROMREG(fs, MIPSInst_FS(ir));
+ SPFROMREG(fd, MIPSInst_FD(ir));
+ rv.s = ieee754sp_maddf(fd, fs, ft);
+ break;
+ }
+
case fabs_op:
handler.u = ieee754sp_abs;
goto scopuop;
goto copcsr;
default:
- if (MIPSInst_FUNC(ir) >= fcmp_op) {
+ if (!NO_R6EMU && MIPSInst_FUNC(ir) >= fcmp_op) {
unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op;
union ieee754sp fs, ft;
return 0;
DPFROMREG(rv.d, MIPSInst_FS(ir));
break;
+
+ case fseleqz_op:
+ if (!cpu_has_mips_r6)
+ return SIGILL;
+
+ DPFROMREG(rv.d, MIPSInst_FT(ir));
+ if (rv.l & 0x1)
+ rv.l = 0;
+ else
+ DPFROMREG(rv.d, MIPSInst_FS(ir));
+ break;
+
+ case fselnez_op:
+ if (!cpu_has_mips_r6)
+ return SIGILL;
+
+ DPFROMREG(rv.d, MIPSInst_FT(ir));
+ if (rv.l & 0x1)
+ DPFROMREG(rv.d, MIPSInst_FS(ir));
+ else
+ rv.l = 0;
+ break;
+
+ case fmaddf_op: {
+ union ieee754dp ft, fs, fd;
+
+ if (!cpu_has_mips_r6)
+ return SIGILL;
+
+ DPFROMREG(ft, MIPSInst_FT(ir));
+ DPFROMREG(fs, MIPSInst_FS(ir));
+ DPFROMREG(fd, MIPSInst_FD(ir));
+ rv.d = ieee754dp_maddf(fd, fs, ft);
+ break;
+ }
+
case fabs_op:
handler.u = ieee754dp_abs;
goto dcopuop;
goto copcsr;
default:
- if (MIPSInst_FUNC(ir) >= fcmp_op) {
+ if (!NO_R6EMU && MIPSInst_FUNC(ir) >= fcmp_op) {
unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op;
union ieee754dp fs, ft;
break;
}
break;
+ }
+
+ case w_fmt: {
+ union ieee754dp fs;
- case w_fmt:
switch (MIPSInst_FUNC(ir)) {
case fcvts_op:
/* convert word to single precision real */
rv.d = ieee754dp_fint(fs.bits);
rfmt = d_fmt;
goto copcsr;
- default:
- return SIGILL;
+ default: {
+ /* Emulating the new CMP.condn.fmt R6 instruction */
+#define CMPOP_MASK 0x7
+#define SIGN_BIT (0x1 << 3)
+#define PREDICATE_BIT (0x1 << 4)
+
+ int cmpop = MIPSInst_FUNC(ir) & CMPOP_MASK;
+ int sig = MIPSInst_FUNC(ir) & SIGN_BIT;
+ union ieee754sp fs, ft;
+
+ /* This is an R6 only instruction */
+ if (!cpu_has_mips_r6 ||
+ (MIPSInst_FUNC(ir) & 0x20))
+ return SIGILL;
+
+ /* fmt is w_fmt for single precision so fix it */
+ rfmt = s_fmt;
+ /* default to false */
+ rv.w = 0;
+
+ /* CMP.condn.S */
+ SPFROMREG(fs, MIPSInst_FS(ir));
+ SPFROMREG(ft, MIPSInst_FT(ir));
+
+ /* positive predicates */
+ if (!(MIPSInst_FUNC(ir) & PREDICATE_BIT)) {
+ if (ieee754sp_cmp(fs, ft, cmptab[cmpop],
+ sig))
+ rv.w = -1; /* true, all 1s */
+ if ((sig) &&
+ ieee754_cxtest(IEEE754_INVALID_OPERATION))
+ rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S;
+ else
+ goto copcsr;
+ } else {
+ /* negative predicates */
+ switch (cmpop) {
+ case 1:
+ case 2:
+ case 3:
+ if (ieee754sp_cmp(fs, ft,
+ negative_cmptab[cmpop],
+ sig))
+ rv.w = -1; /* true, all 1s */
+ if (sig &&
+ ieee754_cxtest(IEEE754_INVALID_OPERATION))
+ rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S;
+ else
+ goto copcsr;
+ break;
+ default:
+ /* Reserved R6 ops */
+ pr_err("Reserved MIPS R6 CMP.condn.S operation\n");
+ return SIGILL;
+ }
+ }
+ break;
+ }
}
- break;
}
case l_fmt:
rv.d = ieee754dp_flong(bits);
rfmt = d_fmt;
goto copcsr;
- default:
- return SIGILL;
- }
- break;
+ default: {
+ /* Emulating the new CMP.condn.fmt R6 instruction */
+ int cmpop = MIPSInst_FUNC(ir) & CMPOP_MASK;
+ int sig = MIPSInst_FUNC(ir) & SIGN_BIT;
+ union ieee754dp fs, ft;
+
+ if (!cpu_has_mips_r6 ||
+ (MIPSInst_FUNC(ir) & 0x20))
+ return SIGILL;
+
+ /* fmt is l_fmt for double precision so fix it */
+ rfmt = d_fmt;
+ /* default to false */
+ rv.l = 0;
+
+ /* CMP.condn.D */
+ DPFROMREG(fs, MIPSInst_FS(ir));
+ DPFROMREG(ft, MIPSInst_FT(ir));
+ /* positive predicates */
+ if (!(MIPSInst_FUNC(ir) & PREDICATE_BIT)) {
+ if (ieee754dp_cmp(fs, ft,
+ cmptab[cmpop], sig))
+ rv.l = -1LL; /* true, all 1s */
+ if (sig &&
+ ieee754_cxtest(IEEE754_INVALID_OPERATION))
+ rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S;
+ else
+ goto copcsr;
+ } else {
+ /* negative predicates */
+ switch (cmpop) {
+ case 1:
+ case 2:
+ case 3:
+ if (ieee754dp_cmp(fs, ft,
+ negative_cmptab[cmpop],
+ sig))
+ rv.l = -1LL; /* true, all 1s */
+ if (sig &&
+ ieee754_cxtest(IEEE754_INVALID_OPERATION))
+ rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S;
+ else
+ goto copcsr;
+ break;
+ default:
+ /* Reserved R6 ops */
+ pr_err("Reserved MIPS R6 CMP.condn.D operation\n");
+ return SIGILL;
+ }
+ }
+ break;
+ }
+ }
default:
return SIGILL;
}