summaryrefslogtreecommitdiffstats
path: root/arch/sparc/math-emu
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-06-13 16:29:25 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-06-13 16:29:25 +0000
commitdb7d4daea91e105e3859cf461d7e53b9b77454b2 (patch)
tree9bb65b95440af09e8aca63abe56970dd3360cc57 /arch/sparc/math-emu
parent9c1c01ead627bdda9211c9abd5b758d6c687d8ac (diff)
Merge with Linux 2.2.8.
Diffstat (limited to 'arch/sparc/math-emu')
-rw-r--r--arch/sparc/math-emu/fabss.c2
-rw-r--r--arch/sparc/math-emu/fcmpd.c2
-rw-r--r--arch/sparc/math-emu/fcmped.c2
-rw-r--r--arch/sparc/math-emu/fcmpeq.c2
-rw-r--r--arch/sparc/math-emu/fcmpes.c2
-rw-r--r--arch/sparc/math-emu/fcmpq.c2
-rw-r--r--arch/sparc/math-emu/fcmps.c2
-rw-r--r--arch/sparc/math-emu/fdmulq.c3
-rw-r--r--arch/sparc/math-emu/fdtoq.c3
-rw-r--r--arch/sparc/math-emu/fdtos.c3
-rw-r--r--arch/sparc/math-emu/fnegs.c2
-rw-r--r--arch/sparc/math-emu/fqtod.c3
-rw-r--r--arch/sparc/math-emu/fqtos.c3
-rw-r--r--arch/sparc/math-emu/fsmuld.c3
-rw-r--r--arch/sparc/math-emu/fstod.c3
-rw-r--r--arch/sparc/math-emu/fstoq.c3
-rw-r--r--arch/sparc/math-emu/math.c91
-rw-r--r--arch/sparc/math-emu/sfp-machine.h133
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)