diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1999-06-13 16:29:25 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1999-06-13 16:29:25 +0000 |
commit | db7d4daea91e105e3859cf461d7e53b9b77454b2 (patch) | |
tree | 9bb65b95440af09e8aca63abe56970dd3360cc57 /arch/sparc/math-emu | |
parent | 9c1c01ead627bdda9211c9abd5b758d6c687d8ac (diff) |
Merge with Linux 2.2.8.
Diffstat (limited to 'arch/sparc/math-emu')
-rw-r--r-- | arch/sparc/math-emu/fabss.c | 2 | ||||
-rw-r--r-- | arch/sparc/math-emu/fcmpd.c | 2 | ||||
-rw-r--r-- | arch/sparc/math-emu/fcmped.c | 2 | ||||
-rw-r--r-- | arch/sparc/math-emu/fcmpeq.c | 2 | ||||
-rw-r--r-- | arch/sparc/math-emu/fcmpes.c | 2 | ||||
-rw-r--r-- | arch/sparc/math-emu/fcmpq.c | 2 | ||||
-rw-r--r-- | arch/sparc/math-emu/fcmps.c | 2 | ||||
-rw-r--r-- | arch/sparc/math-emu/fdmulq.c | 3 | ||||
-rw-r--r-- | arch/sparc/math-emu/fdtoq.c | 3 | ||||
-rw-r--r-- | arch/sparc/math-emu/fdtos.c | 3 | ||||
-rw-r--r-- | arch/sparc/math-emu/fnegs.c | 2 | ||||
-rw-r--r-- | arch/sparc/math-emu/fqtod.c | 3 | ||||
-rw-r--r-- | arch/sparc/math-emu/fqtos.c | 3 | ||||
-rw-r--r-- | arch/sparc/math-emu/fsmuld.c | 3 | ||||
-rw-r--r-- | arch/sparc/math-emu/fstod.c | 3 | ||||
-rw-r--r-- | arch/sparc/math-emu/fstoq.c | 3 | ||||
-rw-r--r-- | arch/sparc/math-emu/math.c | 91 | ||||
-rw-r--r-- | arch/sparc/math-emu/sfp-machine.h | 133 |
18 files changed, 186 insertions, 78 deletions
diff --git a/arch/sparc/math-emu/fabss.c b/arch/sparc/math-emu/fabss.c index accfd4f59..5429cc733 100644 --- a/arch/sparc/math-emu/fabss.c +++ b/arch/sparc/math-emu/fabss.c @@ -2,5 +2,5 @@ int FABSS(unsigned long *rd, unsigned long *rs2) { /* Clear the sign bit (high bit of word 0) */ rd[0] = rs2[0] & 0x7fffffffUL; - return 1; + return 0; } diff --git a/arch/sparc/math-emu/fcmpd.c b/arch/sparc/math-emu/fcmpd.c index 3a9926575..8adb30d88 100644 --- a/arch/sparc/math-emu/fcmpd.c +++ b/arch/sparc/math-emu/fcmpd.c @@ -14,5 +14,5 @@ int FCMPD(void *rd, void *rs2, void *rs1) ret = 2; *fsr = (*fsr & ~0xc00) | (ret << 10); - return 1; + return 0; } diff --git a/arch/sparc/math-emu/fcmped.c b/arch/sparc/math-emu/fcmped.c index a8c188042..2033b1dc8 100644 --- a/arch/sparc/math-emu/fcmped.c +++ b/arch/sparc/math-emu/fcmped.c @@ -14,5 +14,5 @@ int FCMPED(void *rd, void *rs2, void *rs1) ret = 2; *fsr = (*fsr & ~0xc00) | (ret << 10); - return 1; + return 0; } diff --git a/arch/sparc/math-emu/fcmpeq.c b/arch/sparc/math-emu/fcmpeq.c index c109c51ce..de99bf343 100644 --- a/arch/sparc/math-emu/fcmpeq.c +++ b/arch/sparc/math-emu/fcmpeq.c @@ -14,5 +14,5 @@ int FCMPEQ(void *rd, void *rs2, void *rs1) fsr = *(unsigned long *)rd; fsr &= ~0xc00; fsr |= (ret << 10); *(unsigned long *)rd = fsr; - return 1; + return 0; } diff --git a/arch/sparc/math-emu/fcmpes.c b/arch/sparc/math-emu/fcmpes.c index e20884cfd..a078a1243 100644 --- a/arch/sparc/math-emu/fcmpes.c +++ b/arch/sparc/math-emu/fcmpes.c @@ -14,5 +14,5 @@ int FCMPES(void *rd, void *rs2, void *rs1) ret = 2; *fsr = (*fsr & ~0xc00) | (ret << 10); - return 1; + return 0; } diff --git a/arch/sparc/math-emu/fcmpq.c b/arch/sparc/math-emu/fcmpq.c index 549f02cae..f3d1b1233 100644 --- a/arch/sparc/math-emu/fcmpq.c +++ b/arch/sparc/math-emu/fcmpq.c @@ -14,5 +14,5 @@ int FCMPQ(void *rd, void *rs2, void *rs1) fsr = *(unsigned long *)rd; fsr &= ~0xc00; fsr |= (ret << 10); *(unsigned long *)rd = fsr; - return 1; + return 0; } diff --git a/arch/sparc/math-emu/fcmps.c b/arch/sparc/math-emu/fcmps.c index 1b53312ae..7e273320f 100644 --- a/arch/sparc/math-emu/fcmps.c +++ b/arch/sparc/math-emu/fcmps.c @@ -14,5 +14,5 @@ int FCMPS(void *rd, void *rs2, void *rs1) ret = 2; *fsr = (*fsr & ~0xc00) | (ret << 10); - return 1; + return 0; } diff --git a/arch/sparc/math-emu/fdmulq.c b/arch/sparc/math-emu/fdmulq.c index 1d5bc5053..dd9c7953c 100644 --- a/arch/sparc/math-emu/fdmulq.c +++ b/arch/sparc/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,4,2,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/sparc/math-emu/fdtoq.c b/arch/sparc/math-emu/fdtoq.c index 84ebcf4a2..7b7746821 100644 --- a/arch/sparc/math-emu/fdtoq.c +++ b/arch/sparc/math-emu/fdtoq.c @@ -8,6 +8,5 @@ int FDTOQ(void *rd, void *rs2) __FP_UNPACK_D(A, rs2); FP_CONV(Q,D,4,2,R,A); - __FP_PACK_Q(rd, R); - return 1; + return __FP_PACK_Q(rd, R); } diff --git a/arch/sparc/math-emu/fdtos.c b/arch/sparc/math-emu/fdtos.c index 83b8a14ed..612434c40 100644 --- a/arch/sparc/math-emu/fdtos.c +++ b/arch/sparc/math-emu/fdtos.c @@ -8,6 +8,5 @@ int FDTOS(void *rd, void *rs2) __FP_UNPACK_D(A, rs2); FP_CONV(S,D,1,2,R,A); - __FP_PACK_S(rd, R); - return 1; + return __FP_PACK_S(rd, R); } diff --git a/arch/sparc/math-emu/fnegs.c b/arch/sparc/math-emu/fnegs.c index 1c662f201..26a90d778 100644 --- a/arch/sparc/math-emu/fnegs.c +++ b/arch/sparc/math-emu/fnegs.c @@ -2,5 +2,5 @@ int FNEGS(unsigned long *rd, unsigned long *rs2) { /* just change the sign bit */ rd[0] = rs2[0] ^ 0x80000000UL; - return 1; + return 0; } diff --git a/arch/sparc/math-emu/fqtod.c b/arch/sparc/math-emu/fqtod.c index dc5b6f9aa..62a437e31 100644 --- a/arch/sparc/math-emu/fqtod.c +++ b/arch/sparc/math-emu/fqtod.c @@ -8,6 +8,5 @@ int FQTOD(void *rd, void *rs2) __FP_UNPACK_Q(A, rs2); FP_CONV(D,Q,2,4,R,A); - __FP_PACK_D(rd, R); - return 1; + return __FP_PACK_D(rd, R); } diff --git a/arch/sparc/math-emu/fqtos.c b/arch/sparc/math-emu/fqtos.c index 608f57be0..2520affbf 100644 --- a/arch/sparc/math-emu/fqtos.c +++ b/arch/sparc/math-emu/fqtos.c @@ -8,6 +8,5 @@ int FQTOS(void *rd, void *rs2) __FP_UNPACK_Q(A, rs2); FP_CONV(S,Q,1,4,R,A); - __FP_PACK_S(rd, R); - return 1; + return __FP_PACK_S(rd, R); } diff --git a/arch/sparc/math-emu/fsmuld.c b/arch/sparc/math-emu/fsmuld.c index dead5a042..b7b992818 100644 --- a/arch/sparc/math-emu/fsmuld.c +++ b/arch/sparc/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,2,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/sparc/math-emu/fstod.c b/arch/sparc/math-emu/fstod.c index cb34329c9..ea73660d8 100644 --- a/arch/sparc/math-emu/fstod.c +++ b/arch/sparc/math-emu/fstod.c @@ -8,6 +8,5 @@ int FSTOD(void *rd, void *rs2) __FP_UNPACK_S(A, rs2); FP_CONV(D,S,2,1,R,A); - __FP_PACK_D(rd, R); - return 1; + return __FP_PACK_D(rd, R); } diff --git a/arch/sparc/math-emu/fstoq.c b/arch/sparc/math-emu/fstoq.c index 081c4d4d0..7d201310c 100644 --- a/arch/sparc/math-emu/fstoq.c +++ b/arch/sparc/math-emu/fstoq.c @@ -8,6 +8,5 @@ int FSTOQ(void *rd, void *rs2) __FP_UNPACK_S(A, rs2); FP_CONV(Q,S,4,1,R,A); - __FP_PACK_Q(rd, R); - return 1; + return __FP_PACK_Q(rd, R); } diff --git a/arch/sparc/math-emu/math.c b/arch/sparc/math-emu/math.c index df5c879c5..68ccb932a 100644 --- a/arch/sparc/math-emu/math.c +++ b/arch/sparc/math-emu/math.c @@ -124,6 +124,7 @@ #include <linux/mm.h> #include <asm/uaccess.h> +#include "soft-fp.h" #define FLOATFUNC(x) extern int x(void *,void *,void *) @@ -189,6 +190,13 @@ FLOATFUNC(FNEGS); /* v6 */ FLOATFUNC(FITOS); /* v6 */ FLOATFUNC(FITOD); /* v6 */ +#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) + static int do_one_mathemu(u32 insn, unsigned long *fsr, unsigned long *fregs); /* Unlike the Sparc64 version (which has a struct fpustate), we @@ -254,12 +262,85 @@ int do_mathemu(struct pt_regs *regs, struct task_struct *fpt) break; } /* Now empty the queue and clear the queue_not_empty flag */ - fpt->tss.fsr &= ~0x3000; + if(retcode) + fpt->tss.fsr &= ~(0x3000 | FSR_CEXC_MASK); + else + fpt->tss.fsr &= ~0x3000; fpt->tss.fpqdepth = 0; return retcode; } +/* 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(unsigned long *pfsr, int eflag) +{ + unsigned long fsr = *pfsr; + 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); + + *pfsr = fsr; + + return (would_trap ? 0 : 1); +} + static int do_one_mathemu(u32 insn, unsigned long *fsr, unsigned long *fregs) { /* Emulate the given insn, updating fsr and fregs appropriately. */ @@ -270,7 +351,7 @@ static int do_one_mathemu(u32 insn, unsigned long *fsr, unsigned long *fregs) * (this field not used on sparc32 code, as we can't * extract trap type info for ops on the FP queue) */ - int freg; + int freg, eflag; int (*func)(void *,void *,void *) = NULL; void *rs1 = NULL, *rs2 = NULL, *rd = NULL; @@ -411,6 +492,8 @@ static int do_one_mathemu(u32 insn, unsigned long *fsr, unsigned long *fregs) #ifdef DEBUG_MATHEMU printk("executing insn...\n"); #endif - func(rd, rs2, rs1); /* do the Right Thing */ - return 1; /* success! */ + eflag = func(rd, rs2, rs1); /* do the Right Thing */ + if(eflag == 0) + return 1; /* success! */ + return record_exception(fsr, eflag); } diff --git a/arch/sparc/math-emu/sfp-machine.h b/arch/sparc/math-emu/sfp-machine.h index eafad4273..67a74580c 100644 --- a/arch/sparc/math-emu/sfp-machine.h +++ b/arch/sparc/math-emu/sfp-machine.h @@ -115,16 +115,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 = \ @@ -136,17 +126,6 @@ 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_RAW_4(fs, X, val) \ do { \ union _FP_UNION_##fs *_flo = \ @@ -160,55 +139,103 @@ X##_s = _flo->bits.sign; \ } while (0) -#define __FP_PACK_RAW_4(fs, val, X) \ - do { \ - union _FP_UNION_##fs *_flo = \ - (union _FP_UNION_##fs *)val; \ - \ - _flo->bits.frac0 = X##_f[0]; \ - _flo->bits.frac1 = X##_f[1]; \ - _flo->bits.frac2 = X##_f[2]; \ - _flo->bits.frac3 = X##_f[3]; \ - _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_2(D,X,val); \ _FP_UNPACK_CANONICAL(D,2,X); \ } while (0) -#define __FP_PACK_D(val,X) \ - do { \ - _FP_PACK_CANONICAL(D,2,X); \ - __FP_PACK_RAW_2(D,val,X); \ - } while (0) - #define __FP_UNPACK_Q(X,val) \ do { \ __FP_UNPACK_RAW_4(Q,X,val); \ _FP_UNPACK_CANONICAL(Q,4,X); \ } while (0) -#define __FP_PACK_Q(val,X) \ - do { \ - _FP_PACK_CANONICAL(Q,4,X); \ - __FP_PACK_RAW_4(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) +#define __FP_PACK_RAW_4(fs, val, X) \ + do { \ + union _FP_UNION_##fs *_flo = \ + (union _FP_UNION_##fs *)val; \ + \ + _flo->bits.frac0 = X##_f[0]; \ + _flo->bits.frac1 = X##_f[1]; \ + _flo->bits.frac2 = X##_f[2]; \ + _flo->bits.frac3 = X##_f[3]; \ + _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. + */ +#ifdef __SMP__ +#define __FPU_TEM \ + (((current->tss.fsr)>>23)&0x1f) +#else +extern struct task_struct *last_task_used_math; +#define __FPU_TEM \ + (((last_task_used_math->tss.fsr)>>23)&0x1f) +#endif +#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,2,X); \ + if(!__exc || !__FPU_TRAP_P(__exc)) \ + __FP_PACK_RAW_2(D,val,X); \ + __exc; \ +}) + +#define __FP_PACK_Q(val,X) \ +({ int __exc = _FP_PACK_CANONICAL(Q,4,X); \ + if(!__exc || !__FPU_TRAP_P(__exc)) \ + __FP_PACK_RAW_4(Q,val,X); \ + __exc; \ +}) + +/* Obtain the current rounding mode. */ +#ifdef __SMP__ +#define FP_ROUNDMODE ((current->tss.fsr >> 30) & 0x3) +#else +#define FP_ROUNDMODE ((last_task_used_math->tss.fsr >> 30) & 0x3) +#endif + /* the asm fragments go here: all these are taken from glibc-2.0.5's stdlib/longlong.h */ #include <linux/types.h> @@ -361,3 +388,9 @@ #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) |