diff options
Diffstat (limited to 'arch/sparc64/math-emu')
40 files changed, 274 insertions, 141 deletions
diff --git a/arch/sparc64/math-emu/fabsq.c b/arch/sparc64/math-emu/fabsq.c index e01b02046..62a7e1839 100644 --- a/arch/sparc64/math-emu/fabsq.c +++ b/arch/sparc64/math-emu/fabsq.c @@ -2,5 +2,5 @@ int FABSQ(unsigned long *rd, unsigned long *rs2) { rd[0] = rs2[0] & 0x7fffffffffffffffUL; rd[1] = rs2[1]; - return 1; + return 0; } diff --git a/arch/sparc64/math-emu/faddd.c b/arch/sparc64/math-emu/faddd.c index 69b9f7c24..7c755b872 100644 --- a/arch/sparc64/math-emu/faddd.c +++ b/arch/sparc64/math-emu/faddd.c @@ -8,6 +8,5 @@ int FADDD(void *rd, void *rs2, void *rs1) __FP_UNPACK_D(A, rs1); __FP_UNPACK_D(B, rs2); FP_ADD_D(R, A, B); - __FP_PACK_D(rd, R); - return 1; + return __FP_PACK_D(rd, R); } diff --git a/arch/sparc64/math-emu/faddq.c b/arch/sparc64/math-emu/faddq.c index 07245eb95..052c6c9cd 100644 --- a/arch/sparc64/math-emu/faddq.c +++ b/arch/sparc64/math-emu/faddq.c @@ -8,6 +8,5 @@ int FADDQ(void *rd, void *rs2, void *rs1) __FP_UNPACK_Q(A, rs1); __FP_UNPACK_Q(B, rs2); FP_ADD_Q(R, A, B); - __FP_PACK_Q(rd, R); - return 1; + return __FP_PACK_Q(rd, R); } diff --git a/arch/sparc64/math-emu/fadds.c b/arch/sparc64/math-emu/fadds.c index 71295ae47..35bb2030e 100644 --- a/arch/sparc64/math-emu/fadds.c +++ b/arch/sparc64/math-emu/fadds.c @@ -8,6 +8,5 @@ int FADDS(void *rd, void *rs2, void *rs1) __FP_UNPACK_S(A, rs1); __FP_UNPACK_S(B, rs2); FP_ADD_S(R, A, B); - __FP_PACK_S(rd, R); - return 1; + return __FP_PACK_S(rd, R); } diff --git a/arch/sparc64/math-emu/fcmpeq.c b/arch/sparc64/math-emu/fcmpeq.c index e74b1b06b..e99864f55 100644 --- a/arch/sparc64/math-emu/fcmpeq.c +++ b/arch/sparc64/math-emu/fcmpeq.c @@ -21,5 +21,5 @@ int FCMPEQ(void *rd, void *rs2, void *rs1) case 3: fsr &= ~0x3000000000UL; fsr |= (ret << 36); break; } *(unsigned long *)rd = fsr; - return 1; + return 0; } diff --git a/arch/sparc64/math-emu/fcmpq.c b/arch/sparc64/math-emu/fcmpq.c index 9effefb1f..54ec4492f 100644 --- a/arch/sparc64/math-emu/fcmpq.c +++ b/arch/sparc64/math-emu/fcmpq.c @@ -21,5 +21,5 @@ int FCMPQ(void *rd, void *rs2, void *rs1) case 3: fsr &= ~0x3000000000UL; fsr |= (ret << 36); break; } *(unsigned long *)rd = fsr; - return 1; + return 0; } diff --git a/arch/sparc64/math-emu/fdivd.c b/arch/sparc64/math-emu/fdivd.c index 2984290fc..a19dbdd78 100644 --- a/arch/sparc64/math-emu/fdivd.c +++ b/arch/sparc64/math-emu/fdivd.c @@ -4,10 +4,16 @@ int FDIVD(void *rd, void *rs2, void *rs1) { FP_DECL_D(A); FP_DECL_D(B); FP_DECL_D(R); + int ret = 0; __FP_UNPACK_D(A, rs1); __FP_UNPACK_D(B, rs2); + if(B_c == FP_CLS_ZERO && + A_c != FP_CLS_ZERO) { + ret |= EFLAG_DIVZERO; + if(__FPU_TRAP_P(EFLAG_DIVZERO)) + return ret; + } FP_DIV_D(R, A, B); - __FP_PACK_D(rd, R); - return 1; + return (ret | __FP_PACK_D(rd, R)); } diff --git a/arch/sparc64/math-emu/fdivq.c b/arch/sparc64/math-emu/fdivq.c index e5858c0af..9bc0987f5 100644 --- a/arch/sparc64/math-emu/fdivq.c +++ b/arch/sparc64/math-emu/fdivq.c @@ -4,10 +4,16 @@ int FDIVQ(void *rd, void *rs2, void *rs1) { FP_DECL_Q(A); FP_DECL_Q(B); FP_DECL_Q(R); + int ret; __FP_UNPACK_Q(A, rs1); __FP_UNPACK_Q(B, rs2); + if(B_c == FP_CLS_ZERO && + A_c != FP_CLS_ZERO) { + ret |= EFLAG_DIVZERO; + if(__FPU_TRAP_P(EFLAG_DIVZERO)) + return ret; + } FP_DIV_Q(R, A, B); - __FP_PACK_Q(rd, R); - return 1; + return (ret | __FP_PACK_Q(rd, R)); } diff --git a/arch/sparc64/math-emu/fdivs.c b/arch/sparc64/math-emu/fdivs.c index 704f218c9..41095dc4c 100644 --- a/arch/sparc64/math-emu/fdivs.c +++ b/arch/sparc64/math-emu/fdivs.c @@ -4,10 +4,17 @@ int FDIVS(void *rd, void *rs2, void *rs1) { FP_DECL_S(A); FP_DECL_S(B); FP_DECL_S(R); + int ret = 0; __FP_UNPACK_S(A, rs1); __FP_UNPACK_S(B, rs2); + if(B_c == FP_CLS_ZERO && + A_c != FP_CLS_ZERO) { + ret |= EFLAG_DIVZERO; + if(__FPU_TRAP_P(EFLAG_DIVZERO)) + return ret; + } FP_DIV_S(R, A, B); - __FP_PACK_S(rd, R); - return 1; + return (ret | __FP_PACK_S(rd, R)); } + diff --git a/arch/sparc64/math-emu/fdmulq.c b/arch/sparc64/math-emu/fdmulq.c index 7862a0039..4d4b5916a 100644 --- a/arch/sparc64/math-emu/fdmulq.c +++ b/arch/sparc64/math-emu/fdmulq.c @@ -11,6 +11,5 @@ int FDMULQ(void *rd, void *rs2, void *rs1) __FP_UNPACK_D(IN, rs2); FP_CONV(Q,D,2,1,B,IN); FP_MUL_Q(R, A, B); - __FP_PACK_Q(rd, R); - return 1; + return __FP_PACK_Q(rd, R); } diff --git a/arch/sparc64/math-emu/fdtoi.c b/arch/sparc64/math-emu/fdtoi.c index f7ba0f1f2..1b12a6395 100644 --- a/arch/sparc64/math-emu/fdtoi.c +++ b/arch/sparc64/math-emu/fdtoi.c @@ -9,5 +9,5 @@ int FDTOI(unsigned *rd, void *rs2) __FP_UNPACK_D(A, rs2); FP_TO_INT_D(r, A, 32, 1); *rd = r; - return 1; + return 0; } diff --git a/arch/sparc64/math-emu/fdtoq.c b/arch/sparc64/math-emu/fdtoq.c index 42e4009c6..b37b31198 100644 --- a/arch/sparc64/math-emu/fdtoq.c +++ b/arch/sparc64/math-emu/fdtoq.c @@ -8,6 +8,5 @@ int FDTOQ(void *rd, void *rs2) __FP_UNPACK_D(A, rs2); FP_CONV(Q,D,2,1,R,A); - __FP_PACK_Q(rd, R); - return 1; + return __FP_PACK_Q(rd, R); } diff --git a/arch/sparc64/math-emu/fdtos.c b/arch/sparc64/math-emu/fdtos.c index fb7fede54..ae9f382ed 100644 --- a/arch/sparc64/math-emu/fdtos.c +++ b/arch/sparc64/math-emu/fdtos.c @@ -8,6 +8,5 @@ int FDTOS(void *rd, void *rs2) __FP_UNPACK_D(A, rs2); FP_CONV(S,D,1,1,R,A); - __FP_PACK_S(rd, R); - return 1; + return __FP_PACK_S(rd, R); } diff --git a/arch/sparc64/math-emu/fdtox.c b/arch/sparc64/math-emu/fdtox.c index 1a93b585c..062651a47 100644 --- a/arch/sparc64/math-emu/fdtox.c +++ b/arch/sparc64/math-emu/fdtox.c @@ -9,5 +9,5 @@ int FDTOX(unsigned long *rd, void *rs2) __FP_UNPACK_D(A, rs2); FP_TO_INT_D(r, A, 64, 1); *rd = r; - return 1; + return 0; } diff --git a/arch/sparc64/math-emu/fitoq.c b/arch/sparc64/math-emu/fitoq.c index 5d08bbe18..68ba2839b 100644 --- a/arch/sparc64/math-emu/fitoq.c +++ b/arch/sparc64/math-emu/fitoq.c @@ -7,6 +7,5 @@ int FITOQ(void *rd, void *rs2) int a = *(int *)rs2; FP_FROM_INT_Q(R, a, 32, int); - __FP_PACK_Q(rd, R); - return 1; + return __FP_PACK_Q(rd, R); } diff --git a/arch/sparc64/math-emu/fmuld.c b/arch/sparc64/math-emu/fmuld.c index 04d1f38df..707bb45c1 100644 --- a/arch/sparc64/math-emu/fmuld.c +++ b/arch/sparc64/math-emu/fmuld.c @@ -8,6 +8,5 @@ int FMULD(void *rd, void *rs2, void *rs1) __FP_UNPACK_D(A, rs1); __FP_UNPACK_D(B, rs2); FP_MUL_D(R, A, B); - __FP_PACK_D(rd, R); - return 1; + return __FP_PACK_D(rd, R); } diff --git a/arch/sparc64/math-emu/fmulq.c b/arch/sparc64/math-emu/fmulq.c index 4d099be6f..94400d023 100644 --- a/arch/sparc64/math-emu/fmulq.c +++ b/arch/sparc64/math-emu/fmulq.c @@ -8,6 +8,5 @@ int FMULQ(void *rd, void *rs2, void *rs1) __FP_UNPACK_Q(A, rs1); __FP_UNPACK_Q(B, rs2); FP_MUL_Q(R, A, B); - __FP_PACK_Q(rd, R); - return 1; + return __FP_PACK_Q(rd, R); } diff --git a/arch/sparc64/math-emu/fmuls.c b/arch/sparc64/math-emu/fmuls.c index 8a358d030..b16509964 100644 --- a/arch/sparc64/math-emu/fmuls.c +++ b/arch/sparc64/math-emu/fmuls.c @@ -8,6 +8,5 @@ int FMULS(void *rd, void *rs2, void *rs1) __FP_UNPACK_S(A, rs1); __FP_UNPACK_S(B, rs2); FP_MUL_S(R, A, B); - __FP_PACK_S(rd, R); - return 1; + return __FP_PACK_S(rd, R); } diff --git a/arch/sparc64/math-emu/fnegq.c b/arch/sparc64/math-emu/fnegq.c index 2251e3308..745020ee3 100644 --- a/arch/sparc64/math-emu/fnegq.c +++ b/arch/sparc64/math-emu/fnegq.c @@ -2,6 +2,6 @@ int FNEGQ(unsigned long *rd, unsigned long *rs2) { rd[0] = rs2[0] ^ 0x8000000000000000UL; rd[1] = rs2[1]; - return 1; + return 0; } diff --git a/arch/sparc64/math-emu/fqtod.c b/arch/sparc64/math-emu/fqtod.c index 1f9161999..29e41cf6a 100644 --- a/arch/sparc64/math-emu/fqtod.c +++ b/arch/sparc64/math-emu/fqtod.c @@ -8,6 +8,5 @@ int FQTOD(void *rd, void *rs2) __FP_UNPACK_Q(A, rs2); FP_CONV(D,Q,1,2,R,A); - __FP_PACK_D(rd, R); - return 1; + return __FP_PACK_D(rd, R); } diff --git a/arch/sparc64/math-emu/fqtoi.c b/arch/sparc64/math-emu/fqtoi.c index 06d67ff81..1bb213f19 100644 --- a/arch/sparc64/math-emu/fqtoi.c +++ b/arch/sparc64/math-emu/fqtoi.c @@ -9,5 +9,5 @@ int FQTOI(unsigned *rd, void *rs2) __FP_UNPACK_Q(A, rs2); FP_TO_INT_Q(r, A, 32, 1); *rd = r; - return 1; + return 0; } diff --git a/arch/sparc64/math-emu/fqtos.c b/arch/sparc64/math-emu/fqtos.c index 833f10618..382912d11 100644 --- a/arch/sparc64/math-emu/fqtos.c +++ b/arch/sparc64/math-emu/fqtos.c @@ -8,6 +8,5 @@ int FQTOS(void *rd, void *rs2) __FP_UNPACK_Q(A, rs2); FP_CONV(S,Q,1,2,R,A); - __FP_PACK_S(rd, R); - return 1; + return __FP_PACK_S(rd, R); } diff --git a/arch/sparc64/math-emu/fqtox.c b/arch/sparc64/math-emu/fqtox.c index 6cdabc8cd..484ca6900 100644 --- a/arch/sparc64/math-emu/fqtox.c +++ b/arch/sparc64/math-emu/fqtox.c @@ -9,5 +9,5 @@ int FQTOX(unsigned long *rd, void *rs2) __FP_UNPACK_Q(A, rs2); FP_TO_INT_Q(r, A, 64, 1); *rd = r; - return 1; + return 0; } diff --git a/arch/sparc64/math-emu/fsmuld.c b/arch/sparc64/math-emu/fsmuld.c index 1a0eefd06..b6bf61b0f 100644 --- a/arch/sparc64/math-emu/fsmuld.c +++ b/arch/sparc64/math-emu/fsmuld.c @@ -11,6 +11,5 @@ int FSMULD(void *rd, void *rs2, void *rs1) __FP_UNPACK_S(IN, rs2); FP_CONV(D,S,1,1,B,IN); FP_MUL_D(R, A, B); - __FP_PACK_D(rd, R); - return 1; + return __FP_PACK_D(rd, R); } diff --git a/arch/sparc64/math-emu/fsqrtd.c b/arch/sparc64/math-emu/fsqrtd.c index 59f5e3bf3..b022f7d37 100644 --- a/arch/sparc64/math-emu/fsqrtd.c +++ b/arch/sparc64/math-emu/fsqrtd.c @@ -7,6 +7,5 @@ int FSQRTD(void *rd, void *rs2) __FP_UNPACK_D(A, rs2); FP_SQRT_D(R, A); - __FP_PACK_D(rd, R); - return 1; + return __FP_PACK_D(rd, R); } diff --git a/arch/sparc64/math-emu/fsqrtq.c b/arch/sparc64/math-emu/fsqrtq.c index 8f84aa850..7e620079f 100644 --- a/arch/sparc64/math-emu/fsqrtq.c +++ b/arch/sparc64/math-emu/fsqrtq.c @@ -7,6 +7,5 @@ int FSQRTQ(void *rd, void *rs2) __FP_UNPACK_Q(A, rs2); FP_SQRT_Q(R, A); - __FP_PACK_Q(rd, R); - return 1; + return __FP_PACK_Q(rd, R); } diff --git a/arch/sparc64/math-emu/fsqrts.c b/arch/sparc64/math-emu/fsqrts.c index d57cdc98e..62ff0b782 100644 --- a/arch/sparc64/math-emu/fsqrts.c +++ b/arch/sparc64/math-emu/fsqrts.c @@ -7,6 +7,5 @@ int FSQRTS(void *rd, void *rs2) __FP_UNPACK_S(A, rs2); FP_SQRT_S(R, A); - __FP_PACK_S(rd, R); - return 1; + return __FP_PACK_S(rd, R); } diff --git a/arch/sparc64/math-emu/fstod.c b/arch/sparc64/math-emu/fstod.c index 60f1bc8a4..91935f78e 100644 --- a/arch/sparc64/math-emu/fstod.c +++ b/arch/sparc64/math-emu/fstod.c @@ -8,6 +8,5 @@ int FSTOD(void *rd, void *rs2) __FP_UNPACK_S(A, rs2); FP_CONV(D,S,1,1,R,A); - __FP_PACK_D(rd, R); - return 1; + return __FP_PACK_D(rd, R); } diff --git a/arch/sparc64/math-emu/fstoi.c b/arch/sparc64/math-emu/fstoi.c index 4adc7d170..5ff3854cc 100644 --- a/arch/sparc64/math-emu/fstoi.c +++ b/arch/sparc64/math-emu/fstoi.c @@ -9,5 +9,5 @@ int FSTOI(unsigned *rd, void *rs2) __FP_UNPACK_S(A, rs2); FP_TO_INT_S(r, A, 32, 1); *rd = r; - return 1; + return 0; } diff --git a/arch/sparc64/math-emu/fstoq.c b/arch/sparc64/math-emu/fstoq.c index 06313a77f..1a56e0055 100644 --- a/arch/sparc64/math-emu/fstoq.c +++ b/arch/sparc64/math-emu/fstoq.c @@ -8,6 +8,5 @@ int FSTOQ(void *rd, void *rs2) __FP_UNPACK_S(A, rs2); FP_CONV(Q,S,2,1,R,A); - __FP_PACK_Q(rd, R); - return 1; + return __FP_PACK_Q(rd, R); } diff --git a/arch/sparc64/math-emu/fstox.c b/arch/sparc64/math-emu/fstox.c index 555fba2ee..fa2135f8b 100644 --- a/arch/sparc64/math-emu/fstox.c +++ b/arch/sparc64/math-emu/fstox.c @@ -9,5 +9,5 @@ int FSTOX(unsigned long *rd, void *rs2) __FP_UNPACK_S(A, rs2); FP_TO_INT_S(r, A, 64, 1); *rd = r; - return 1; + return 0; } diff --git a/arch/sparc64/math-emu/fsubd.c b/arch/sparc64/math-emu/fsubd.c index b0f451b32..bbd11c611 100644 --- a/arch/sparc64/math-emu/fsubd.c +++ b/arch/sparc64/math-emu/fsubd.c @@ -10,6 +10,5 @@ int FSUBD(void *rd, void *rs2, void *rs1) if (B_c != FP_CLS_NAN) B_s ^= 1; FP_ADD_D(R, A, B); - __FP_PACK_D(rd, R); - return 1; + return __FP_PACK_D(rd, R); } diff --git a/arch/sparc64/math-emu/fsubq.c b/arch/sparc64/math-emu/fsubq.c index ef006a540..d5cc260cf 100644 --- a/arch/sparc64/math-emu/fsubq.c +++ b/arch/sparc64/math-emu/fsubq.c @@ -10,6 +10,5 @@ int FSUBQ(void *rd, void *rs2, void *rs1) if (B_c != FP_CLS_NAN) B_s ^= 1; FP_ADD_Q(R, A, B); - __FP_PACK_Q(rd, R); - return 1; + return __FP_PACK_Q(rd, R); } diff --git a/arch/sparc64/math-emu/fsubs.c b/arch/sparc64/math-emu/fsubs.c index d060f095a..ff8fa12b1 100644 --- a/arch/sparc64/math-emu/fsubs.c +++ b/arch/sparc64/math-emu/fsubs.c @@ -10,6 +10,5 @@ int FSUBS(void *rd, void *rs2, void *rs1) if (B_c != FP_CLS_NAN) B_s ^= 1; FP_ADD_S(R, A, B); - __FP_PACK_S(rd, R); - return 1; + return __FP_PACK_S(rd, R); } diff --git a/arch/sparc64/math-emu/fxtoq.c b/arch/sparc64/math-emu/fxtoq.c index 7c2f7df48..411e51571 100644 --- a/arch/sparc64/math-emu/fxtoq.c +++ b/arch/sparc64/math-emu/fxtoq.c @@ -7,6 +7,5 @@ int FXTOQ(void *rd, void *rs2) long a = *(long *)rs2; FP_FROM_INT_Q(R, a, 64, long); - __FP_PACK_Q(rd, R); - return 1; + return __FP_PACK_Q(rd, R); } diff --git a/arch/sparc64/math-emu/math.c b/arch/sparc64/math-emu/math.c index 5a71804b9..f4493e224 100644 --- a/arch/sparc64/math-emu/math.c +++ b/arch/sparc64/math-emu/math.c @@ -1,7 +1,8 @@ -/* $Id: math.c,v 1.5 1998/06/12 14:54:27 jj Exp $ +/* $Id: math.c,v 1.7 1999/02/10 14:16:26 davem Exp $ * arch/sparc64/math-emu/math.c * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1999 David S. Miller (davem@redhat.com) * * Emulation routines originate from soft-fp package, which is part * of glibc and has appropriate copyrights in it. @@ -14,6 +15,8 @@ #include <asm/ptrace.h> #include <asm/uaccess.h> +#include "soft-fp.h" + #define FLOATFUNC(x) extern int x(void *,void *,void *); FLOATFUNC(FMOVQ) @@ -54,6 +57,91 @@ FLOATFUNC(FSTOD) FLOATFUNC(FSTOI) FLOATFUNC(FDTOI) +#define FSR_TEM_SHIFT 23UL +#define FSR_TEM_MASK (0x1fUL << FSR_TEM_SHIFT) +#define FSR_AEXC_SHIFT 5UL +#define FSR_AEXC_MASK (0x1fUL << FSR_AEXC_SHIFT) +#define FSR_CEXC_SHIFT 0UL +#define FSR_CEXC_MASK (0x1fUL << FSR_CEXC_SHIFT) + +/* All routines returning an exception to raise should detect + * such exceptions _before_ rounding to be consistant with + * the behavior of the hardware in the implemented cases + * (and thus with the recommendations in the V9 architecture + * manual). + * + * We return 0 if a SIGFPE should be sent, 1 otherwise. + */ +static int record_exception(struct pt_regs *regs, int eflag) +{ + u64 fsr = current->tss.xfsr[0]; + int would_trap; + + /* Determine if this exception would have generated a trap. */ + would_trap = (fsr & ((long)eflag << FSR_TEM_SHIFT)) != 0UL; + + /* If trapping, we only want to signal one bit. */ + if(would_trap != 0) { + eflag &= ((fsr & FSR_TEM_MASK) >> FSR_TEM_SHIFT); + if((eflag & (eflag - 1)) != 0) { + if(eflag & EFLAG_INVALID) + eflag = EFLAG_INVALID; + else if(eflag & EFLAG_DIVZERO) + eflag = EFLAG_DIVZERO; + else if(eflag & EFLAG_INEXACT) + eflag = EFLAG_INEXACT; + } + } + + /* Set CEXC, here are the rules: + * + * 1) In general all FPU ops will set one and only one + * bit in the CEXC field, this is always the case + * when the IEEE exception trap is enabled in TEM. + * + * 2) As a special case, if an overflow or underflow + * is being signalled, AND the trap is not enabled + * in TEM, then the inexact field shall also be set. + */ + fsr &= ~(FSR_CEXC_MASK); + if(would_trap || + (eflag & (EFLAG_OVERFLOW | EFLAG_UNDERFLOW)) == 0) { + fsr |= ((long)eflag << FSR_CEXC_SHIFT); + } else { + fsr |= (((long)eflag << FSR_CEXC_SHIFT) | + (EFLAG_INEXACT << FSR_CEXC_SHIFT)); + } + + /* Set the AEXC field, rules are: + * + * 1) If a trap would not be generated, the + * CEXC just generated is OR'd into the + * existing value of AEXC. + * + * 2) When a trap is generated, AEXC is cleared. + */ + if(would_trap == 0) + fsr |= ((long)eflag << FSR_AEXC_SHIFT); + else + fsr &= ~(FSR_AEXC_MASK); + + /* If trapping, indicate fault trap type IEEE. */ + if(would_trap != 0) + fsr |= (1UL << 14); + + current->tss.xfsr[0] = fsr; + + /* If we will not trap, advance the program counter over + * the instruction being handled. + */ + if(would_trap == 0) { + regs->tpc = regs->tnpc; + regs->tnpc += 4; + } + + return (would_trap ? 0 : 1); +} + int do_mathemu(struct pt_regs *regs, struct fpustate *f) { unsigned long pc = regs->tpc; @@ -175,7 +263,12 @@ int do_mathemu(struct pt_regs *regs, struct fpustate *f) current->tss.fpsaved[0] |= flags; break; } - func(rd, rs2, rs1); + flags = func(rd, rs2, rs1); + if(flags != 0) + return record_exception(regs, flags); + + /* Success and no exceptions detected. */ + current->tss.xfsr[0] &= ~(FSR_CEXC_MASK); regs->tpc = regs->tnpc; regs->tnpc += 4; return 1; diff --git a/arch/sparc64/math-emu/op-2.h b/arch/sparc64/math-emu/op-2.h index 5999cfc3b..8ac63188c 100644 --- a/arch/sparc64/math-emu/op-2.h +++ b/arch/sparc64/math-emu/op-2.h @@ -190,14 +190,14 @@ \ __FP_FRAC_ADD_4(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \ _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0), \ + 0, _b_f1, _b_f0, 0, \ _FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \ - _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0), \ - 0, _b_f1, _b_f0, 0); \ + _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0)); \ __FP_FRAC_ADD_4(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \ _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0), \ + 0, _c_f1, _c_f0, 0, \ _FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \ - _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0), \ - 0, _c_f1, _c_f0, 0); \ + _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0)); \ \ /* Normalize since we know where the msb of the multiplicands \ were (bit B), we know that the msb of the of the product is \ diff --git a/arch/sparc64/math-emu/op-common.h b/arch/sparc64/math-emu/op-common.h index ac49cd6c2..6090e0213 100644 --- a/arch/sparc64/math-emu/op-common.h +++ b/arch/sparc64/math-emu/op-common.h @@ -53,14 +53,14 @@ do { \ */ #define _FP_PACK_CANONICAL(fs, wc, X) \ -do { \ +({int __ret = 0; \ switch (X##_c) \ { \ case FP_CLS_NORMAL: \ X##_e += _FP_EXPBIAS_##fs; \ if (X##_e > 0) \ { \ - _FP_ROUND(wc, X); \ + __ret |= _FP_ROUND(wc, X); \ if (_FP_FRAC_OVERP_##wc(fs, X)) \ { \ _FP_FRAC_SRL_##wc(X, (_FP_WORKBITS+1)); \ @@ -73,6 +73,7 @@ do { \ /* overflow to infinity */ \ X##_e = _FP_EXPMAX_##fs; \ _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ + __ret |= EFLAG_OVERFLOW; \ } \ } \ else \ @@ -82,7 +83,7 @@ do { \ if (X##_e <= _FP_WFRACBITS_##fs) \ { \ _FP_FRAC_SRS_##wc(X, X##_e, _FP_WFRACBITS_##fs); \ - _FP_ROUND(wc, X); \ + __ret |= _FP_ROUND(wc, X); \ _FP_FRAC_SLL_##wc(X, 1); \ if (_FP_FRAC_OVERP_##wc(fs, X)) \ { \ @@ -93,6 +94,7 @@ do { \ { \ X##_e = 0; \ _FP_FRAC_SRL_##wc(X, _FP_WORKBITS+1); \ + __ret |= EFLAG_UNDERFLOW; \ } \ } \ else \ @@ -100,6 +102,7 @@ do { \ /* underflow to zero */ \ X##_e = 0; \ _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ + __ret |= EFLAG_UNDERFLOW; \ } \ } \ break; \ @@ -125,7 +128,8 @@ do { \ _FP_FRAC_HIGH_##wc(X) |= _FP_QNANBIT_##fs; \ break; \ } \ -} while (0) + __ret; \ +}) /* @@ -424,11 +428,19 @@ do { \ } \ else \ { \ - /* Force -0 -> +0 */ \ - if (!X##_e && _FP_FRAC_ZEROP_##wc(X)) X##_s = 0; \ - if (!Y##_e && _FP_FRAC_ZEROP_##wc(Y)) X##_s = 0; \ + int __is_zero_x; \ + int __is_zero_y; \ + \ + __is_zero_x = (!X##_e && _FP_FRAC_ZEROP_##wc(X)) ? 1 : 0; \ + __is_zero_y = (!Y##_e && _FP_FRAC_ZEROP_##wc(Y)) ? 1 : 0; \ \ - if (X##_s != Y##_s) \ + if (__is_zero_x && __is_zero_y) \ + ret = 0; \ + else if (__is_zero_x) \ + ret = Y##_s ? 1 : -1; \ + else if (__is_zero_y) \ + ret = X##_s ? -1 : 1; \ + else if (X##_s != Y##_s) \ ret = X##_s ? -1 : 1; \ else if (X##_e > Y##_e) \ ret = X##_s ? -1 : 1; \ diff --git a/arch/sparc64/math-emu/sfp-machine.h b/arch/sparc64/math-emu/sfp-machine.h index f15a5ea4a..3846ac4f9 100644 --- a/arch/sparc64/math-emu/sfp-machine.h +++ b/arch/sparc64/math-emu/sfp-machine.h @@ -52,16 +52,6 @@ X##_s = _flo->bits.sign; \ } while (0) -#define __FP_PACK_RAW_1(fs, val, X) \ - do { \ - union _FP_UNION_##fs *_flo = \ - (union _FP_UNION_##fs *)val; \ - \ - _flo->bits.frac = X##_f; \ - _flo->bits.exp = X##_e; \ - _flo->bits.sign = X##_s; \ - } while (0) - #define __FP_UNPACK_RAW_2(fs, X, val) \ do { \ union _FP_UNION_##fs *_flo = \ @@ -73,53 +63,80 @@ X##_s = _flo->bits.sign; \ } while (0) -#define __FP_PACK_RAW_2(fs, val, X) \ - do { \ - union _FP_UNION_##fs *_flo = \ - (union _FP_UNION_##fs *)val; \ - \ - _flo->bits.frac0 = X##_f0; \ - _flo->bits.frac1 = X##_f1; \ - _flo->bits.exp = X##_e; \ - _flo->bits.sign = X##_s; \ - } while (0) - #define __FP_UNPACK_S(X,val) \ do { \ __FP_UNPACK_RAW_1(S,X,val); \ _FP_UNPACK_CANONICAL(S,1,X); \ } while (0) -#define __FP_PACK_S(val,X) \ - do { \ - _FP_PACK_CANONICAL(S,1,X); \ - __FP_PACK_RAW_1(S,val,X); \ - } while (0) - #define __FP_UNPACK_D(X,val) \ do { \ __FP_UNPACK_RAW_1(D,X,val); \ _FP_UNPACK_CANONICAL(D,1,X); \ } while (0) -#define __FP_PACK_D(val,X) \ - do { \ - _FP_PACK_CANONICAL(D,1,X); \ - __FP_PACK_RAW_1(D,val,X); \ - } while (0) - #define __FP_UNPACK_Q(X,val) \ do { \ __FP_UNPACK_RAW_2(Q,X,val); \ _FP_UNPACK_CANONICAL(Q,2,X); \ } while (0) -#define __FP_PACK_Q(val,X) \ - do { \ - _FP_PACK_CANONICAL(Q,2,X); \ - __FP_PACK_RAW_2(Q,val,X); \ +#define __FP_PACK_RAW_1(fs, val, X) \ + do { \ + union _FP_UNION_##fs *_flo = \ + (union _FP_UNION_##fs *)val; \ + \ + _flo->bits.frac = X##_f; \ + _flo->bits.exp = X##_e; \ + _flo->bits.sign = X##_s; \ + } while (0) + +#define __FP_PACK_RAW_2(fs, val, X) \ + do { \ + union _FP_UNION_##fs *_flo = \ + (union _FP_UNION_##fs *)val; \ + \ + _flo->bits.frac0 = X##_f0; \ + _flo->bits.frac1 = X##_f1; \ + _flo->bits.exp = X##_e; \ + _flo->bits.sign = X##_s; \ } while (0) +#include <linux/kernel.h> +#include <linux/sched.h> + +/* We only actually write to the destination register + * if exceptions signalled (if any) will not trap. + */ +#define __FPU_TEM \ + (((current->tss.xfsr[0])>>23)&0x1f) +#define __FPU_TRAP_P(bits) \ + ((__FPU_TEM & (bits)) != 0) + +#define __FP_PACK_S(val,X) \ +({ int __exc = _FP_PACK_CANONICAL(S,1,X); \ + if(!__exc || !__FPU_TRAP_P(__exc)) \ + __FP_PACK_RAW_1(S,val,X); \ + __exc; \ +}) + +#define __FP_PACK_D(val,X) \ +({ int __exc = _FP_PACK_CANONICAL(D,1,X); \ + if(!__exc || !__FPU_TRAP_P(__exc)) \ + __FP_PACK_RAW_1(D,val,X); \ + __exc; \ +}) + +#define __FP_PACK_Q(val,X) \ +({ int __exc = _FP_PACK_CANONICAL(Q,2,X); \ + if(!__exc || !__FPU_TRAP_P(__exc)) \ + __FP_PACK_RAW_2(Q,val,X); \ + __exc; \ +}) + +/* Obtain the current rounding mode. */ +#define FP_ROUNDMODE ((current->tss.xfsr[0] >> 30) & 0x3) + #include <linux/types.h> #include <asm/byteorder.h> @@ -153,28 +170,24 @@ #define umul_ppmm(wh, wl, u, v) \ do { \ - long tmp1 = 0, tmp2 = 0, tmp3 = 0; \ __asm__ ("mulx %2,%3,%1 - srlx %2,32,%4 - srl %3,0,%5 - mulx %4,%5,%6 - srlx %3,32,%4 - srl %2,0,%5 - mulx %4,%5,%5 - srlx %2,32,%4 - add %5,%6,%6 - srlx %3,32,%5 - mulx %4,%5,%4 - srlx %6,32,%5 - add %4,%5,%0" \ + srlx %2,32,%%g1 + srl %3,0,%%g2 + mulx %%g1,%%g2,%%g3 + srlx %3,32,%%g1 + srl %2,0,%%g2 + mulx %%g1,%%g2,%%g2 + srlx %2,32,%%g1 + add %%g2,%%g3,%%g3 + srlx %3,32,%%g2 + mulx %%g1,%%g2,%%g1 + srlx %%g3,32,%%g2 + add %%g1,%%g2,%0" \ : "=r" ((UDItype)(wh)), \ "=&r" ((UDItype)(wl)) \ : "r" ((UDItype)(u)), \ - "r" ((UDItype)(v)), \ - "r" ((UDItype)(tmp1)), \ - "r" ((UDItype)(tmp2)), \ - "r" ((UDItype)(tmp3)) \ - : "cc"); \ + "r" ((UDItype)(v)) \ + : "g1", "g2", "g3", "cc"); \ } while (0) #define udiv_qrnnd(q, r, n1, n0, d) \ @@ -223,3 +236,10 @@ #else #define __BYTE_ORDER __LITTLE_ENDIAN #endif + +/* Exception flags. */ +#define EFLAG_INVALID (1 << 4) +#define EFLAG_OVERFLOW (1 << 3) +#define EFLAG_UNDERFLOW (1 << 2) +#define EFLAG_DIVZERO (1 << 1) +#define EFLAG_INEXACT (1 << 0) diff --git a/arch/sparc64/math-emu/soft-fp.h b/arch/sparc64/math-emu/soft-fp.h index a4f72e78f..b54f86217 100644 --- a/arch/sparc64/math-emu/soft-fp.h +++ b/arch/sparc64/math-emu/soft-fp.h @@ -14,45 +14,56 @@ # define FP_RND_ZERO 1 # define FP_RND_PINF 2 # define FP_RND_MINF 3 +#ifndef FP_ROUNDMODE # define FP_ROUNDMODE FP_RND_NEAREST #endif +#endif #define _FP_ROUND_NEAREST(wc, X) \ - do { \ +({ int __ret = EFLAG_INEXACT; \ if ((_FP_FRAC_LOW_##wc(X) & 15) != _FP_WORK_ROUND) \ _FP_FRAC_ADDI_##wc(X, _FP_WORK_ROUND); \ - } while(0) + else __ret = 0; \ + __ret; \ +}) -#define _FP_ROUND_ZERO(wc, X) +#define _FP_ROUND_ZERO(wc, X) 0 /* XXX */ #define _FP_ROUND_PINF(wc, X) \ - do { \ +({ int __ret = EFLAG_INEXACT; \ if (!X##_s && (_FP_FRAC_LOW_##wc(X) & 7)) \ _FP_FRAC_ADDI_##wc(X, _FP_WORK_LSB); \ - } while (0) + else __ret = 0; \ + __ret; \ +}) #define _FP_ROUND_MINF(wc, X) \ - do { \ +({ int __ret = EFLAG_INEXACT; \ if (X##_s && (_FP_FRAC_LOW_##wc(X) & 7)) \ _FP_FRAC_ADDI_##wc(X, _FP_WORK_LSB); \ - } while (0) + else __ret = 0; \ + __ret; \ +}) #define _FP_ROUND(wc, X) \ +({ int __ret = 0; \ switch (FP_ROUNDMODE) \ { \ case FP_RND_NEAREST: \ - _FP_ROUND_NEAREST(wc,X); \ + __ret |= _FP_ROUND_NEAREST(wc,X); \ break; \ case FP_RND_ZERO: \ - _FP_ROUND_ZERO(wc,X); \ + __ret |= _FP_ROUND_ZERO(wc,X); \ break; \ case FP_RND_PINF: \ - _FP_ROUND_PINF(wc,X); \ + __ret |= _FP_ROUND_PINF(wc,X); \ break; \ case FP_RND_MINF: \ - _FP_ROUND_MINF(wc,X); \ + __ret |= _FP_ROUND_MINF(wc,X); \ break; \ - } + }; \ + __ret; \ +}) #define FP_CLS_NORMAL 0 #define FP_CLS_ZERO 1 |