staticunsignedlong insn_type(unsignedlong speinsn)
{ unsignedlong ret = NOTYPE;
switch (speinsn & 0x7ff) { case EFSABS: ret = XA; break; case EFSADD: ret = AB; break; case EFSCFD: ret = XB; break; case EFSCMPEQ: ret = XCR; break; case EFSCMPGT: ret = XCR; break; case EFSCMPLT: ret = XCR; break; case EFSCTSF: ret = XB; break; case EFSCTSI: ret = XB; break; case EFSCTSIZ: ret = XB; break; case EFSCTUF: ret = XB; break; case EFSCTUI: ret = XB; break; case EFSCTUIZ: ret = XB; break; case EFSDIV: ret = AB; break; case EFSMUL: ret = AB; break; case EFSNABS: ret = XA; break; case EFSNEG: ret = XA; break; case EFSSUB: ret = AB; break; case EFSCFSI: ret = XB; break;
case EVFSABS: ret = XA; break; case EVFSADD: ret = AB; break; case EVFSCMPEQ: ret = XCR; break; case EVFSCMPGT: ret = XCR; break; case EVFSCMPLT: ret = XCR; break; case EVFSCTSF: ret = XB; break; case EVFSCTSI: ret = XB; break; case EVFSCTSIZ: ret = XB; break; case EVFSCTUF: ret = XB; break; case EVFSCTUI: ret = XB; break; case EVFSCTUIZ: ret = XB; break; case EVFSDIV: ret = AB; break; case EVFSMUL: ret = AB; break; case EVFSNABS: ret = XA; break; case EVFSNEG: ret = XA; break; case EVFSSUB: ret = AB; break;
case EFDABS: ret = XA; break; case EFDADD: ret = AB; break; case EFDCFS: ret = XB; break; case EFDCMPEQ: ret = XCR; break; case EFDCMPGT: ret = XCR; break; case EFDCMPLT: ret = XCR; break; case EFDCTSF: ret = XB; break; case EFDCTSI: ret = XB; break; case EFDCTSIDZ: ret = XB; break; case EFDCTSIZ: ret = XB; break; case EFDCTUF: ret = XB; break; case EFDCTUI: ret = XB; break; case EFDCTUIDZ: ret = XB; break; case EFDCTUIZ: ret = XB; break; case EFDDIV: ret = AB; break; case EFDMUL: ret = AB; break; case EFDNABS: ret = XA; break; case EFDNEG: ret = XA; break; case EFDSUB: ret = AB; break;
}
return ret;
}
int do_spe_mathemu(struct pt_regs *regs)
{
FP_DECL_EX; int IR, cmp;
unsignedlong type, func, fc, fa, fb, src, speinsn; union dw_union vc, va, vb;
if (get_user(speinsn, (unsignedint __user *) regs->nip)) return -EFAULT; if ((speinsn >> 26) != EFAPU) return -EINVAL; /* not an spe instruction */
type = insn_type(speinsn); if (type == NOTYPE) goto illegal;
cmp_s:
FP_CMP_S(IR, SA, SB, 3); if (IR == 3 && (FP_ISSIGNAN_S(SA) || FP_ISSIGNAN_S(SB)))
FP_SET_EXCEPTION(FP_EX_INVALID); if (IR == cmp) {
IR = 0x4;
} else {
IR = 0;
} goto update_ccr;
}
case DPFP: {
FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
switch (type) { case AB: case XCR:
FP_UNPACK_DP(DA, va.dp);
fallthrough; case XB:
FP_UNPACK_DP(DB, vb.dp); break; case XA:
FP_UNPACK_DP(DA, va.dp); break;
}
cmp_d:
FP_CMP_D(IR, DA, DB, 3); if (IR == 3 && (FP_ISSIGNAN_D(DA) || FP_ISSIGNAN_D(DB)))
FP_SET_EXCEPTION(FP_EX_INVALID); if (IR == cmp) {
IR = 0x4;
} else {
IR = 0;
} goto update_ccr;
}
case VCT: {
FP_DECL_S(SA0); FP_DECL_S(SB0); FP_DECL_S(SR0);
FP_DECL_S(SA1); FP_DECL_S(SB1); FP_DECL_S(SR1); int IR0, IR1;
switch (type) { case AB: case XCR:
FP_UNPACK_SP(SA0, va.wp);
FP_UNPACK_SP(SA1, va.wp + 1);
fallthrough; case XB:
FP_UNPACK_SP(SB0, vb.wp);
FP_UNPACK_SP(SB1, vb.wp + 1); break; case XA:
FP_UNPACK_SP(SA0, va.wp);
FP_UNPACK_SP(SA1, va.wp + 1); break;
}
update_regs: /* * If the "invalid" exception sticky bit was set by the * processor for non-finite input, but was not set before the * instruction being emulated, clear it. Likewise for the * "underflow" bit, which may have been set by the processor * for exact underflow, not just inexact underflow when the * flag should be set for IEEE 754 semantics. Other sticky * exceptions will only be set by the processor when they are * correct according to IEEE 754 semantics, and we must not * clear sticky bits that were already set before the emulated * instruction as they represent the user-visible sticky * exception status. "inexact" traps to kernel are not * required for IEEE semantics and are not enabled by default, * so the "inexact" sticky bit may have been set by a previous * instruction without the kernel being aware of it.
*/
__FPU_FPSCR
&= ~(FP_EX_INVALID | FP_EX_UNDERFLOW) | current->thread.spefscr_last;
__FPU_FPSCR |= (FP_CUR_EXCEPTIONS & FP_EX_MASK);
mtspr(SPRN_SPEFSCR, __FPU_FPSCR);
current->thread.spefscr_last = __FPU_FPSCR;
int speround_handler(struct pt_regs *regs)
{ union dw_union fgpr; int s_lo, s_hi; int lo_inexact, hi_inexact; int fp_result; unsignedlong speinsn, type, fb, fc, fptype, func;
if (get_user(speinsn, (unsignedint __user *) regs->nip)) return -EFAULT; if ((speinsn >> 26) != 4) return -EINVAL; /* not an spe instruction */
func = speinsn & 0x7ff;
type = insn_type(func); if (type == XCR) return -ENOSYS;
/* No need to round if the result is exact */
lo_inexact = __FPU_FPSCR & (SPEFSCR_FG | SPEFSCR_FX);
hi_inexact = __FPU_FPSCR & (SPEFSCR_FGH | SPEFSCR_FXH); if (!(lo_inexact || (hi_inexact && fptype == VCT))) return 0;
fb = (speinsn >> 11) & 0x1f; switch (func) { case EFSCTUIZ: case EFSCTSIZ: case EVFSCTUIZ: case EVFSCTSIZ: case EFDCTUIDZ: case EFDCTSIDZ: case EFDCTUIZ: case EFDCTSIZ: /* * These instructions always round to zero, * independent of the rounding mode.
*/ return 0;
case EFSCTUI: case EFSCTUF: case EVFSCTUI: case EVFSCTUF: case EFDCTUI: case EFDCTUF:
fp_result = 0;
s_lo = 0;
s_hi = 0; break;
case EFSCTSI: case EFSCTSF:
fp_result = 0; /* Recover the sign of a zero result if possible. */ if (fgpr.wp[1] == 0)
s_lo = regs->gpr[fb] & SIGN_BIT_S; break;
case EVFSCTSI: case EVFSCTSF:
fp_result = 0; /* Recover the sign of a zero result if possible. */ if (fgpr.wp[1] == 0)
s_lo = regs->gpr[fb] & SIGN_BIT_S; if (fgpr.wp[0] == 0)
s_hi = current->thread.evr[fb] & SIGN_BIT_S; break;
case EFDCTSI: case EFDCTSF:
fp_result = 0;
s_hi = s_lo; /* Recover the sign of a zero result if possible. */ if (fgpr.wp[1] == 0)
s_hi = current->thread.evr[fb] & SIGN_BIT_S; break;
switch (fptype) { /* Since SPE instructions on E500 core can handle round to nearest * and round toward zero with IEEE-754 complied, we just need * to handle round toward +Inf and round toward -Inf by software.
*/ case SPFP: if ((FP_ROUNDMODE) == FP_RND_PINF) { if (!s_lo) fgpr.wp[1]++; /* Z > 0, choose Z1 */
} else { /* round to -Inf */ if (s_lo) { if (fp_result)
fgpr.wp[1]++; /* Z < 0, choose Z2 */ else
fgpr.wp[1]--; /* Z < 0, choose Z2 */
}
} break;
case DPFP: if (FP_ROUNDMODE == FP_RND_PINF) { if (!s_hi) { if (fp_result)
fgpr.dp[0]++; /* Z > 0, choose Z1 */ else
fgpr.wp[1]++; /* Z > 0, choose Z1 */
}
} else { /* round to -Inf */ if (s_hi) { if (fp_result)
fgpr.dp[0]++; /* Z < 0, choose Z2 */ else
fgpr.wp[1]--; /* Z < 0, choose Z2 */
}
} break;
case VCT: if (FP_ROUNDMODE == FP_RND_PINF) { if (lo_inexact && !s_lo)
fgpr.wp[1]++; /* Z_low > 0, choose Z1 */ if (hi_inexact && !s_hi)
fgpr.wp[0]++; /* Z_high word > 0, choose Z1 */
} else { /* round to -Inf */ if (lo_inexact && s_lo) { if (fp_result)
fgpr.wp[1]++; /* Z_low < 0, choose Z2 */ else
fgpr.wp[1]--; /* Z_low < 0, choose Z2 */
} if (hi_inexact && s_hi) { if (fp_result)
fgpr.wp[0]++; /* Z_high < 0, choose Z2 */ else
fgpr.wp[0]--; /* Z_high < 0, choose Z2 */
}
} break;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.