patch-2.0.32 linux/arch/i386/math-emu/fpu_debug.c
Next file: linux/arch/i386/mm/fault.c
Previous file: linux/arch/i386/math-emu/Makefile
Back to the patch index
Back to the overall index
- Lines: 231
- Date:
Fri Nov 7 09:11:42 1997
- Orig file:
v2.0.31/linux/arch/i386/math-emu/fpu_debug.c
- Orig date:
Wed Dec 31 16:00:00 1969
diff -u --recursive --new-file v2.0.31/linux/arch/i386/math-emu/fpu_debug.c linux/arch/i386/math-emu/fpu_debug.c
@@ -0,0 +1,230 @@
+/* Interface with ptrace and core-dumping routines */
+
+
+#include "fpu_system.h"
+#include "exception.h"
+#include "reg_constant.h"
+#include "fpu_emu.h"
+#include "control_w.h"
+#include "status_w.h"
+
+
+#define EXTENDED_Ebias 0x3fff
+#define EXTENDED_Emin (-0x3ffe) /* smallest valid exponent */
+
+#define DOUBLE_Emax 1023 /* largest valid exponent */
+#define DOUBLE_Ebias 1023
+#define DOUBLE_Emin (-1022) /* smallest valid exponent */
+
+#define SINGLE_Emax 127 /* largest valid exponent */
+#define SINGLE_Ebias 127
+#define SINGLE_Emin (-126) /* smallest valid exponent */
+
+
+/* Copy and paste from round_to_int. Original comments maintained */
+/*===========================================================================*/
+
+/* r gets mangled such that sig is int, sign:
+ it is NOT normalized */
+/* The return value (in eax) is zero if the result is exact,
+ if bits are changed due to rounding, truncation, etc, then
+ a non-zero value is returned */
+/* Overflow is signalled by a non-zero return value (in eax).
+ In the case of overflow, the returned significand always has the
+ largest possible value */
+
+static int round_to_int_cwd(FPU_REG *r, long int user_control_word)
+{
+ char very_big;
+ unsigned eax;
+
+ if (r->tag == TW_Zero)
+ {
+ /* Make sure that zero is returned */
+ significand(r) = 0;
+ return 0; /* o.k. */
+ }
+
+ if (r->exp > EXP_BIAS + 63)
+ {
+ r->sigl = r->sigh = ~0; /* The largest representable number */
+ return 1; /* overflow */
+ }
+
+ eax = shrxs(&r->sigl, EXP_BIAS + 63 - r->exp);
+ very_big = !(~(r->sigh) | ~(r->sigl)); /* test for 0xfff...fff */
+#define half_or_more (eax & 0x80000000)
+#define frac_part (eax)
+#define more_than_half ((eax & 0x80000001) == 0x80000001)
+ switch (user_control_word & CW_RC)
+ {
+ case RC_RND:
+ if ( more_than_half /* nearest */
+ || (half_or_more && (r->sigl & 1)) ) /* odd -> even */
+ {
+ if ( very_big ) return 1; /* overflow */
+ significand(r) ++;
+ return PRECISION_LOST_UP;
+ }
+ break;
+ case RC_DOWN:
+ if (frac_part && r->sign)
+ {
+ if ( very_big ) return 1; /* overflow */
+ significand(r) ++;
+ return PRECISION_LOST_UP;
+ }
+ break;
+ case RC_UP:
+ if (frac_part && !r->sign)
+ {
+ if ( very_big ) return 1; /* overflow */
+ significand(r) ++;
+ return PRECISION_LOST_UP;
+ }
+ break;
+ case RC_CHOP:
+ break;
+ }
+
+ return eax ? PRECISION_LOST_DOWN : 0;
+
+}
+
+
+
+/* Conver a number in the emulator format to the
+ * hardware format.
+ * Taken from the emulator sources, function reg_load_extended
+ */
+
+/* Get a long double from the debugger */
+void hardreg_to_softreg(const char hardreg[10],
+ FPU_REG *soft_reg)
+
+{
+ unsigned long sigl, sigh, exp;
+
+ sigl = *((unsigned long *) hardreg);
+ sigh = *(1 + (unsigned long *) hardreg);
+ exp = *(4 + (unsigned short *) hardreg);
+
+ soft_reg->tag = TW_Valid; /* Default */
+ soft_reg->sigl = sigl;
+ soft_reg->sigh = sigh;
+ if (exp & 0x8000)
+ soft_reg->sign = SIGN_NEG;
+ else
+ soft_reg->sign = SIGN_POS;
+ exp &= 0x7fff;
+ soft_reg->exp = exp - EXTENDED_Ebias + EXP_BIAS;
+
+ if ( exp == 0 )
+ {
+ if ( !(sigh | sigl) )
+ {
+ soft_reg->tag = TW_Zero;
+ return;
+ }
+ /* The number is a de-normal or pseudodenormal. */
+ if (sigh & 0x80000000)
+ {
+ /* Is a pseudodenormal. */
+ /* Convert it for internal use. */
+ /* This is non-80486 behaviour because the number
+ loses its 'denormal' identity. */
+ soft_reg->exp++;
+ return;
+ }
+ else
+ {
+ /* Is a denormal. */
+ /* Convert it for internal use. */
+ soft_reg->exp++;
+ normalize_nuo(soft_reg);
+ return;
+ }
+ }
+ else if ( exp == 0x7fff )
+ {
+ if ( !((sigh ^ 0x80000000) | sigl) )
+ {
+ /* Matches the bit pattern for Infinity. */
+ soft_reg->exp = EXP_Infinity;
+ soft_reg->tag = TW_Infinity;
+ return;
+ }
+
+ soft_reg->exp = EXP_NaN;
+ soft_reg->tag = TW_NaN;
+ if ( !(sigh & 0x80000000) )
+ {
+ /* NaNs have the ms bit set to 1. */
+ /* This is therefore an Unsupported NaN data type. */
+ /* This is non 80486 behaviour */
+ /* This should generate an Invalid Operand exception
+ later, so we convert it to a SNaN */
+ soft_reg->sigh = 0x80000000;
+ soft_reg->sigl = 0x00000001;
+ soft_reg->sign = SIGN_NEG;
+ return;
+ }
+ return;
+ }
+
+ if ( !(sigh & 0x80000000) )
+ {
+ /* Unsupported data type. */
+ /* Valid numbers have the ms bit set to 1. */
+ /* Unnormal. */
+ /* Convert it for internal use. */
+ /* This is non-80486 behaviour */
+ /* This should generate an Invalid Operand exception
+ later, so we convert it to a SNaN */
+ soft_reg->sigh = 0x80000000;
+ soft_reg->sigl = 0x00000001;
+ soft_reg->sign = SIGN_NEG;
+ soft_reg->exp = EXP_NaN;
+ soft_reg->tag = TW_NaN;
+ return;
+ }
+ return;
+}
+
+/* Conver a number in the emulator format to the
+ * hardware format.
+ * Adapted from function write_to_extended
+ */
+
+
+void softreg_to_hardreg(const FPU_REG *rp, char d[10], long int user_control_word)
+{
+ long e;
+ FPU_REG tmp;
+ e = rp->exp - EXP_BIAS + EXTENDED_Ebias;
+
+ /*
+ All numbers except denormals are stored internally in a
+ format which is compatible with the extended real number
+ format.
+ */
+ if (e > 0) {
+ *(unsigned long *) d = rp->sigl;
+ *(unsigned long *) (d + 4) = rp->sigh;
+ } else {
+ /*
+ The number is a de-normal stored as a normal using our
+ extra exponent range, or is Zero.
+ Convert it back to a de-normal, or leave it as Zero.
+ */
+ reg_move(rp, &tmp);
+ tmp.exp += -EXTENDED_Emin + 63; /* largest exp to be 63 */
+ round_to_int_cwd(&tmp, user_control_word);
+ e = 0;
+ *(unsigned long *) d= tmp.sigl;
+ *(unsigned long *) (d + 4) = tmp.sigh;
+ }
+ e |= rp->sign == SIGN_POS ? 0 : 0x8000;
+ *(unsigned short *) (d + 8) = e;
+}
+
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov