[parisc-linux-cvs] FPU emulation changes

Paul Bame bame@fc.hp.com
Fri, 16 Mar 2001 16:01:25 -0700


I'm not including the code copied from HP-UX in this diff, just the
more linux-related code.  You can read the other code in arch/parisc/math-emu

Index: arch/parisc/Makefile
===================================================================
RCS file: /home/cvs/parisc/linux/arch/parisc/Makefile,v
retrieving revision 1.23
retrieving revision 1.24
diff -u -u -r1.23 -r1.24
--- Makefile	2001/03/02 00:48:47	1.23
+++ Makefile	2001/03/16 22:51:08	1.24
@@ -76,10 +76,8 @@
 
 LIBS := `$(CC) -print-libgcc-file-name` $(TOPDIR)/arch/parisc/lib/lib.a $(LIBS) 
 
-ifdef CONFIG_MATH_EMULATION
 SUBDIRS := $(SUBDIRS) arch/parisc/math-emu
-DRIVERS := $(DRIVERS) arch/parisc/math-emu/math.a
-endif
+DRIVERS := $(DRIVERS) arch/parisc/math-emu/math.o
 
 ifdef CONFIG_KWDB
 SUBDIRS := $(SUBDIRS) arch/parisc/kdb
Index: arch/parisc/kernel/traps.c
===================================================================
RCS file: /home/cvs/parisc/linux/arch/parisc/kernel/traps.c,v
retrieving revision 1.44
retrieving revision 1.45
diff -u -u -r1.44 -r1.45
--- traps.c	2001/03/13 20:26:37	1.44
+++ traps.c	2001/03/16 22:51:09	1.45
@@ -32,6 +32,8 @@
 #include <asm/smp.h>
 #include <asm/pdc.h>
 
+#include "../math-emu/math-emu.h"	/* for handle_fpe() */
+
 #ifdef CONFIG_KWDB
 #include <kdb/break.h>		/* for BI2_KGDB_GDB */
 #include <kdb/kgdb_types.h>	/* for __() */
@@ -218,220 +220,6 @@
 	}
 }
 
-/* Format of the floating-point exception registers. */
-struct exc_reg {
-	unsigned int exception : 6;
-	unsigned int ei : 26;
-};
-
-/* Macros for grabbing bits of the instruction format from the 'ei'
-   field above. */
-/* Major opcode 0c and 0e */
-#define FP0CE_UID(i) (((i) >> 6) & 3)
-#define FP0CE_CLASS(i) (((i) >> 9) & 3)
-#define FP0CE_SUBOP(i) (((i) >> 13) & 7)
-#define FP0CE_SUBOP1(i) (((i) >> 15) & 7) /* Class 1 subopcode */
-#define FP0C_FORMAT(i) (((i) >> 11) & 3)
-#define FP0E_FORMAT(i) (((i) >> 11) & 1)
-
-/* Major opcode 0c, uid 2 (performance monitoring) */
-#define FPPM_SUBOP(i) (((i) >> 9) & 0x1f)
-
-/* Major opcode 2e (fused operations).   */
-#define FP2E_SUBOP(i)  (((i) >> 5) & 1)
-#define FP2E_FORMAT(i) (((i) >> 11) & 1)
-
-/* Major opcode 26 (FMPYSUB) */
-/* Major opcode 06 (FMPYADD) */
-#define FPx6_FORMAT(i) ((i) & 0x1f)
-
-/* Flags and enable bits of the status word. */
-#define FPSW_FLAGS(w) ((w) >> 27)
-#define FPSW_ENABLE(w) ((w) & 0x1f)
-#define FPSW_V (1<<4)
-#define FPSW_Z (1<<3)
-#define FPSW_O (1<<2)
-#define FPSW_U (1<<1)
-#define FPSW_I (1<<0)
-
-/* Emulate a floating point instruction if necessary and possible
-   (this will be moved elsewhere eventually).  Return zero if
-   successful or if emulation was not required, -1 if the instruction
-   is actually illegal or unimplemented.  The status word passed as
-   the first parameter will be modified to signal exceptions, if
-   any. */
-
-/* FIXME!!!  This is really incomplete and, at the moment, most
-   illegal FP instructions will simply act as no-ops.  Obviously that
-   is *not* what we want.  Also we don't even try to handle exception
-   types other than the 'unimplemented' ones. */
-int
-fp_emul_insn(u32 *sw, struct exc_reg exc, struct pt_regs *regs)
-{
-	switch (exc.exception) {
-	case 0x3:  /* Unimplemented, opcode 06 */
-		break;
-	case 0x9:  /* Unimplemented, opcode 0c */
-		/* We do not support quadword operations, end of
-                   story.  There's no support for them in GCC. */
-		if (FP0C_FORMAT(exc.ei) == 3)
-			return -1; /* SIGILL */
-		/* Fall through. */
-	case 0xa:  /* Unimplemented, opcode 0e */
-		if (FP0CE_CLASS(exc.ei) == 1) {
-			/* FCNV instructions of various sorts. */
-		} else {
-			if (FP0CE_CLASS(exc.ei == 0)
-			    && FP0CE_SUBOP(exc.ei == 5)) {
-				/* FRND instructions should be
-                                   emulated, at some point, I
-                                   guess. */
-				return -1; /* SIGILL */
-			}
-		}
-		break;
-	case 0x23: /* Unimplemented, opcode 26 */
-		break;
-	case 0x2b: /* Unimplemented, opcode 2e */
-		break;
-	case 0x1:  /* Unimplemented, opcode 0e/0c */
-		/* FIXME: How the hell are we supposed to tell which
-                   opcode it is? */
-		break;
-	default:
-		return -1; /* Punt */
-	}
-
-	printk("FP emulation: exception 0x%03lx:%06lx\n", exc.exception, exc.ei);
-	return 0;
-}
-
-/* Handle a floating point exception.  Return zero if the faulting
-   instruction can be completed successfully. */
-int
-handle_fpe(struct pt_regs *regs)
-{
-	struct siginfo si;
-	union {
-		struct fpsw {
-			/* flag bits */
-			unsigned int fv : 1;
-			unsigned int fz : 1;
-			unsigned int fo : 1;
-			unsigned int fu : 1;
-			unsigned int fi : 1;
-
-			unsigned int c : 1;
-			unsigned int pad1 : 4;
-			unsigned int cq : 11;
-			unsigned int rm : 2;
-			unsigned int pad2 : 2;
-			unsigned int t : 1;
-			unsigned int d : 1;
-
-			/* enable bits */
-			unsigned int ev : 1;
-			unsigned int ez : 1;
-			unsigned int eo : 1;
-			unsigned int eu : 1;
-			unsigned int ei : 1;
-		} status;
-		u32 word;
-	} sw;
-	struct exc_reg excepts[7];
-	unsigned int code = 0;
-	unsigned int throw;
-
-	/* Status word = FR0L. */
-	memcpy(&sw, regs->fr, sizeof(sw));
-	/* Exception words = FR0R-FR3R. */
-	memcpy(excepts, ((char *) regs->fr) + 4, sizeof(excepts));
-
-	/* This is all CPU dependent.  Since there is no public
-           documentation on the PA2.0 processors we will just assume
-           everything is like the 7100/7100LC/7300LC for now.
-
-	   Specifically: All exceptions are marked as "unimplemented"
-	   in the exception word, and the only exception word used is
-	   excepts[1]. */
-
-	/* Try to emulate the instruction.  Also determine if it is
-           really an illegal instruction in the process.
-
-	   FIXME: fp_emul_insn() only checks for the "unimplemented"
-	   exceptions at the moment.  So this may break horribly on
-	   PA2.0, where we may want to also check to see if we should
-	   just send SIGFPE (or maybe not, let's see the documentation
-	   first...) */
-	if (fp_emul_insn(&sw.word, excepts[1], regs) == -1)
-		goto send_sigill;
-
-	/* Take the intersection of the flag bits in the FPSW and the
-           enable bits in the FPSW. */
-	throw = FPSW_FLAGS(sw.word) & FPSW_ENABLE(sw.word);
-
-	/* Concoct an appropriate si_code.  Of course we don't know
-           what to do if multiple exceptions were enabled and multiple
-           flags were set.  Maybe that's why HP/UX doesn't implement
-           feenableexcept(). */
-
-	if (throw == 0)
-		goto success; /* Duh. */
-	else if (throw & FPSW_V)
-		code = FPE_FLTINV;
-	else if (throw & FPSW_Z)
-		code = FPE_FLTDIV;
-	else if (throw & FPSW_O)
-		code = FPE_FLTOVF;
-	else if (throw & FPSW_U)
-		code = FPE_FLTUND;
-	else if (throw & FPSW_I)
-		code = FPE_FLTRES;
-
-#if 1 /* Debugging... */
-	printk("Unemulated floating point exception, pid=%d (%s)\n",
-	       current->pid, current->comm);
-	show_regs(regs);
-	{
-		int i;
-		printk("FP Status: %08x\n", sw.word);
-		printk("FP Exceptions:\n");
-		for (i = 0; i < 7; i++) {
-			printk("\tExcept%d: exception %03x insn %06x\n",
-			       i, excepts[i].exception, excepts[i].ei);
-		}
-	}
-#endif
-
-	/* FIXME: Should we clear the flag bits, T bit, and exception
-           registers here? */
-
-	si.si_signo = SIGFPE;
-	si.si_errno = 0;
-	si.si_code = code;
-	si.si_addr = (void *) regs->iaoq[0];
-	force_sig_info(SIGFPE, &si, current);
-	return -1;
-
- send_sigill:
-	si.si_signo = SIGILL;
-	si.si_errno = 0;
-	si.si_code = ILL_COPROC;
-	si.si_addr = (void *) regs->iaoq[0];
-	force_sig_info(SIGILL, &si, current);
-	return -1;
-
- success:
-	/* We absolutely have to clear the T bit and exception
-           registers to allow the process to recover.  Otherwise every
-           subsequent floating point instruction will trap. */
-	sw.status.t = 0;
-	memset(excepts, 0, sizeof(excepts));
-
-	memcpy(regs->fr, &sw, sizeof(sw));
-	memcpy(((char *) regs->fr) + 4,excepts , sizeof(excepts));
-	return 0;
-}
 
 int handle_toc(void)
 {
Index: arch/parisc/math-emu/Makefile
===================================================================
RCS file: Makefile
diff -N Makefile
--- /dev/null	Tue May  5 14:32:27 1998
+++ /tmp/cvs09130eaa	Fri Mar 16 15:54:50 2001
@@ -0,0 +1,19 @@
+#
+# Makefile for the linux parisc-specific parts of the memory manager.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definition is now in the main makefile...
+
+O_TARGET := math.o
+obj-y	 := frnd.o driver.o
+
+ifdef CONFIG_MATH_EMULATION
+# Math emulation code beyond the FRND is required for 712/80i and
+# other very old or stripped-down PA-RISC CPUs -- not currently supported
+obj-y	+= unimplemented-math-emulation.o
+endif
+
+include $(TOPDIR)/Rules.make
Index: arch/parisc/math-emu/README
===================================================================
RCS file: README
diff -N README
--- /dev/null	Tue May  5 14:32:27 1998
+++ /tmp/cvs09130faa	Fri Mar 16 15:54:50 2001
@@ -0,0 +1,11 @@
+All files except driver.c are snapshots from the HP-UX kernel.  They've
+been modified as little as possible.  Even though they don't fit the
+Linux coding style, please leave them in their funny format just in case
+someone in the future, with access to HP-UX source code, is generous
+enough to update our copies with later changes from HP-UX -- it'll
+make their 'diff' job easier if our code is relatively unmodified.
+
+Required Disclaimer: Hewlett-Packard makes no implied or expressed
+warranties about this code nor any promises to maintain or test it
+in any way.  This copy of this snapshot is no longer the property
+of Hewlett-Packard.
Index: arch/parisc/math-emu/driver.c
===================================================================
RCS file: driver.c
diff -N driver.c
--- /dev/null	Tue May  5 14:32:27 1998
+++ /tmp/cvs09130gaa	Fri Mar 16 15:54:50 2001
@@ -0,0 +1,335 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2, or (at your option)
+ *    any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ *  linux/arch/math-emu/driver.c.c
+ *
+ *	decodes and dispatches unimplemented FPU instructions
+ *
+ *  Copyright (C) 1999, 2000  Philipp Rumpf <prumpf@tux.org>
+ *  Copyright (C) 2001	      Hewlett-Packard <bame@debian.org>
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include "float.h"
+#include "math-emu.h"
+
+
+#define fptpos 31
+#define fpr1pos 10
+#define extru(r,pos,len) (((r) >> (31-(pos))) & (( 1 << (len)) - 1))
+
+/* Format of the floating-point exception registers. */
+struct exc_reg {
+	unsigned int exception : 6;
+	unsigned int ei : 26;
+};
+
+/* Macros for grabbing bits of the instruction format from the 'ei'
+   field above. */
+/* Major opcode 0c and 0e */
+#define FP0CE_UID(i) (((i) >> 6) & 3)
+#define FP0CE_CLASS(i) (((i) >> 9) & 3)
+#define FP0CE_SUBOP(i) (((i) >> 13) & 7)
+#define FP0CE_SUBOP1(i) (((i) >> 15) & 7) /* Class 1 subopcode */
+#define FP0C_FORMAT(i) (((i) >> 11) & 3)
+#define FP0E_FORMAT(i) (((i) >> 11) & 1)
+
+/* Major opcode 0c, uid 2 (performance monitoring) */
+#define FPPM_SUBOP(i) (((i) >> 9) & 0x1f)
+
+/* Major opcode 2e (fused operations).   */
+#define FP2E_SUBOP(i)  (((i) >> 5) & 1)
+#define FP2E_FORMAT(i) (((i) >> 11) & 1)
+
+/* Major opcode 26 (FMPYSUB) */
+/* Major opcode 06 (FMPYADD) */
+#define FPx6_FORMAT(i) ((i) & 0x1f)
+
+/* Flags and enable bits of the status word. */
+#define FPSW_FLAGS(w) ((w) >> 27)
+#define FPSW_ENABLE(w) ((w) & 0x1f)
+#define FPSW_V (1<<4)
+#define FPSW_Z (1<<3)
+#define FPSW_O (1<<2)
+#define FPSW_U (1<<1)
+#define FPSW_I (1<<0)
+
+/* return -1 if unemulatable otherwise 0 */
+static int frnd(u32 *sw, struct exc_reg exc, struct pt_regs *regs)
+{
+	int r = 0;
+	int srcreg, destreg;
+	__u64 *srcp, *destp;
+	__u64 fpzeroreg = 0;
+	extern int sgl_frnd(sgl_floating_point *srcptr,
+				unsigned int *nullptr,
+				sgl_floating_point *dstptr,
+			        unsigned int *status);
+	extern int dbl_frnd(dbl_floating_point *srcptr,
+				unsigned int *nullptr,
+				dbl_floating_point *dstptr,
+			        unsigned int *status);
+
+	/* source register */
+	srcreg = extru(exc.ei,fpr1pos,5);
+        if (srcreg == 0)            /* map fr0 source to constant zero */
+                srcp = &fpzeroreg;
+	else
+		srcp = &regs->fr[srcreg];
+
+        destreg = extru(exc.ei,fptpos,5);
+        if (destreg == 0)       /* fr0 as destination -- a NO-OP */
+		return 0;
+
+	destp = &regs->fr[destreg];
+
+	switch(FP0C_FORMAT(exc.ei)) {
+	case 0:		/* single-precision */
+		sgl_frnd((sgl_floating_point *)srcp, 0,
+			(sgl_floating_point *)destp, sw);
+		break;
+	case 1:		/* double-precision */
+		dbl_frnd((dbl_floating_point *)srcp, 0,
+			(dbl_floating_point *)destp, sw);
+		break;
+	default:	/* quad precision unimplemented */
+		r = -1;
+		break;
+	}
+
+	return r;
+}
+
+/* Decode the floating-point exception and if it's from an unimplemented
+ * FRND instruction, emulate it.  Return 0 if the instruction was successfully
+ * emulated, or if the exception code indicates the floating-point status
+ * register is sufficient to enable the caller, handle_fpe(), to do the
+ * right thing.  Return -1 to signal an illegal or unemulatable instruction
+ * or a "reserved" exception code value.  May modify the status word.
+ */
+static int
+fp_emul_insn(u32 *sw, struct exc_reg exc, struct pt_regs *regs)
+{
+	int r = -1;
+
+#if 0	/* Debug */
+	printk("@@ FP emulation: exception 0x%02x:%06x fmt %d class %d subop %d\n",
+		exc.exception,
+		exc.ei,
+		FP0C_FORMAT(exc.ei),
+		FP0CE_CLASS(exc.ei),
+		FP0CE_SUBOP(exc.ei)
+	);
+	show_regs(regs);
+#endif
+
+	switch (exc.exception & 0x0f) {
+	case 0x04:	/* Underflow */
+	case 0x06:	/* Inexact & Underflow */
+		r = 0;
+		break;
+	default:
+	    switch (exc.exception) {
+	    case 0x01:  /* Unimplemented, opcode 0C/0E */
+	    case 0x09:  /* Unimplemented, opcode 0C */
+	    case 0x0b:  /* Unimplemented, opcode 0E */
+		    /* All we need to decode is FRND instructions. */
+		    if (FP0CE_CLASS(exc.ei) == 0 && FP0CE_SUBOP(exc.ei) == 5) {
+			    r = frnd(sw, exc, regs);
+		    }
+		    break;
+	    /* can't emulate any of these (yet) */
+	    case 0x03:		/* Unimplemented, opcode 06 */
+	    case 0x23:		/* Unimplemented, opcode 26 */
+	    case 0x2b:		/* Unimplemented, opcode 2e */
+		    break;
+	    /* non-unimplemented exception codes.  Maybe these should be
+	     * handled elsewhere.  For now, return "success" and let the
+	     * fp status decode handle returning the proper signal.  This
+	     * is also how the "Underflow" cases in the outer switch work.
+	     */
+	    case 0x00:		/* No exception, probably a bug */
+		    BUG();
+	    case 0x20:		/* Invalid operation */
+	    case 0x10:		/* Divide by zero */
+	    case 0x08:		/* Overflow */
+	    case 0x02:		/* Inexact */
+	    case 0x0a:		/* Inexact & Overflow */
+		    r = 0;
+		    break;
+	    default:		/* Reserved exception values */
+		    break;
+	    }
+	}
+
+	if (r == -1)
+	{
+		printk("%d(%s): Unemulated floating instruction: exception 0x%02x:%06x fmt %d class %d subop %d\n",
+		    current->pid,
+		    current->comm,
+		    exc.exception,
+		    exc.ei,
+		    FP0C_FORMAT(exc.ei),
+		    FP0CE_CLASS(exc.ei),
+		    FP0CE_SUBOP(exc.ei)
+		);
+		show_regs(regs);
+	}
+
+	return 0;
+}
+
+/* Handle a floating point exception.  Return zero if the faulting
+   instruction can be completed successfully. */
+int
+handle_fpe(struct pt_regs *regs)
+{
+	struct siginfo si;
+	int i, ereg;
+	union {
+		struct fpsw {
+			/* flag bits */
+			unsigned int fv : 1;
+			unsigned int fz : 1;
+			unsigned int fo : 1;
+			unsigned int fu : 1;
+			unsigned int fi : 1;
+
+			unsigned int c : 1;
+			unsigned int pad1 : 4;
+			unsigned int cq : 11;
+			unsigned int rm : 2;
+			unsigned int pad2 : 2;
+			unsigned int t : 1;
+			unsigned int d : 1;
+
+			/* enable bits */
+			unsigned int ev : 1;
+			unsigned int ez : 1;
+			unsigned int eo : 1;
+			unsigned int eu : 1;
+			unsigned int ei : 1;
+		} status;
+		u32 word;
+	} sw;
+	struct exc_reg excepts[7];
+	unsigned int code = 0;
+	unsigned int throw;
+
+	/* Status word = FR0L. */
+	memcpy(&sw, regs->fr, sizeof(sw));
+	/* Exception words = FR0R-FR3R. */
+	memcpy(excepts, ((char *) regs->fr) + 4, sizeof(excepts));
+
+	/* This is all CPU dependent.  Since there is no public
+           documentation on the PA2.0 processors we will just assume
+           everything is like the 7100/7100LC/7300LC for now.
+
+	   Specifically: All exceptions are marked as "unimplemented"
+	   in the exception word, and the only exception word used is
+	   excepts[1]. */
+
+	/* Try to emulate the instruction.  Also determine if it is
+           really an illegal instruction in the process.
+
+	   FIXME: fp_emul_insn() only checks for the "unimplemented"
+	   exceptions at the moment.  So this may break horribly on
+	   PA2.0, where we may want to also check to see if we should
+	   just send SIGFPE (or maybe not, let's see the documentation
+	   first...) */
+
+	/* process the first-found exception */
+	for (ereg = 0; ereg < 7; ereg++) {
+		if (excepts[ereg].exception != 0) {
+		    i = fp_emul_insn(&sw.word, excepts[ereg], regs);
+		    if (i == -1)
+			    goto send_sigill;
+		    break;
+		}
+	}
+
+	/* Take the intersection of the flag bits in the FPSW and the
+           enable bits in the FPSW. */
+	throw = FPSW_FLAGS(sw.word) & FPSW_ENABLE(sw.word);
+
+	/* Concoct an appropriate si_code.  Of course we don't know
+           what to do if multiple exceptions were enabled and multiple
+           flags were set.  Maybe that's why HP/UX doesn't implement
+           feenableexcept(). */
+
+	if (throw == 0)
+		goto success; /* Duh. */
+	else if (throw & FPSW_V)
+		code = FPE_FLTINV;
+	else if (throw & FPSW_Z)
+		code = FPE_FLTDIV;
+	else if (throw & FPSW_O)
+		code = FPE_FLTOVF;
+	else if (throw & FPSW_U)
+		code = FPE_FLTUND;
+	else if (throw & FPSW_I)
+		code = FPE_FLTRES;
+
+#if 1 /* Debugging... */
+	printk("Unemulated floating point exception, pid=%d (%s)\n",
+	       current->pid, current->comm);
+	show_regs(regs);
+	{
+		int i;
+		printk("FP Status: %08x\n", sw.word);
+		printk("FP Exceptions:\n");
+		for (i = 0; i < 7; i++) {
+			printk("\tExcept%d: exception %03x insn %06x\n",
+			       i, excepts[i].exception, excepts[i].ei);
+		}
+	}
+#endif
+
+	/* FIXME: Should we clear the flag bits, T bit, and exception
+           registers here? */
+
+	si.si_signo = SIGFPE;
+	si.si_errno = 0;
+	si.si_code = code;
+	si.si_addr = (void *) regs->iaoq[0];
+	force_sig_info(SIGFPE, &si, current);
+	return -1;
+
+ send_sigill:
+	si.si_signo = SIGILL;
+	si.si_errno = 0;
+	si.si_code = ILL_COPROC;
+	si.si_addr = (void *) regs->iaoq[0];
+	force_sig_info(SIGILL, &si, current);
+	return -1;
+
+ success:
+	/* We absolutely have to clear the T bit and exception
+           registers to allow the process to recover.  Otherwise every
+           subsequent floating point instruction will trap. */
+	sw.status.t = 0;
+	memset(excepts, 0, sizeof(excepts));
+
+	memcpy(regs->fr, &sw, sizeof(sw));
+	memcpy(((char *) regs->fr) + 4,excepts , sizeof(excepts));
+	return 0;
+}
Index: arch/parisc/math-emu/math-emu.h
===================================================================
RCS file: math-emu.h
diff -N math-emu.h
--- /dev/null	Tue May  5 14:32:27 1998
+++ /tmp/cvs09130haa	Fri Mar 16 15:54:50 2001
@@ -0,0 +1,7 @@
+#ifndef _PARISC_MATH_EMU_H
+#define _PARISC_MATH_EMU_H
+
+#include <asm/ptrace.h>
+extern int handle_fpe(struct pt_regs *regs);
+
+#endif