patch-2.2.4 linux/arch/sparc/math-emu/math.c

Next file: linux/arch/sparc/math-emu/sfp-machine.h
Previous file: linux/arch/sparc/math-emu/fstoq.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.2.3/linux/arch/sparc/math-emu/math.c linux/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(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 @@
          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 @@
     * (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 @@
 #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);
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)