patch-2.1.73 linux/arch/i386/math-emu/errors.c

Next file: linux/arch/i386/math-emu/fpu_arith.c
Previous file: linux/arch/i386/math-emu/div_small.S
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.72/linux/arch/i386/math-emu/errors.c linux/arch/i386/math-emu/errors.c
@@ -21,9 +21,9 @@
 
 #include <asm/uaccess.h>
 
+#include "fpu_emu.h"
 #include "fpu_system.h"
 #include "exception.h"
-#include "fpu_emu.h"
 #include "status_w.h"
 #include "control_w.h"
 #include "reg_constant.h"
@@ -36,7 +36,7 @@
 
 void Un_impl(void)
 {
-  unsigned char byte1, FPU_modrm;
+  u_char byte1, FPU_modrm;
   unsigned long address = FPU_ORIG_EIP;
 
   RE_ENTRANT_CHECK_OFF;
@@ -46,13 +46,13 @@
     {
       while ( 1 )
 	{
-	  get_user(byte1, (unsigned char *) address);
+	  FPU_get_user(byte1, (u_char *) address);
 	  if ( (byte1 & 0xf8) == 0xd8 ) break;
 	  printk("[%02x]", byte1);
 	  address++;
 	}
       printk("%02x ", byte1);
-      get_user(FPU_modrm, 1 + (unsigned char *) address);
+      FPU_get_user(FPU_modrm, 1 + (u_char *) address);
       
       if (FPU_modrm >= 0300)
 	printk("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7);
@@ -82,12 +82,12 @@
 
 
 
-void emu_printall(void)
+void FPU_printall(void)
 {
   int i;
-  static const char *tag_desc[] = { "Valid", "Zero", "ERROR", "ERROR",
-                              "DeNorm", "Inf", "NaN", "Empty" };
-  unsigned char byte1, FPU_modrm;
+  static const char *tag_desc[] = { "Valid", "Zero", "ERROR", "Empty",
+                              "DeNorm", "Inf", "NaN" };
+  u_char byte1, FPU_modrm;
   unsigned long address = FPU_ORIG_EIP;
 
   RE_ENTRANT_CHECK_OFF;
@@ -98,7 +98,7 @@
 #define MAX_PRINTED_BYTES 20
       for ( i = 0; i < MAX_PRINTED_BYTES; i++ )
 	{
-	  get_user(byte1, (unsigned char *) address);
+	  FPU_get_user(byte1, (u_char *) address);
 	  if ( (byte1 & 0xf8) == 0xd8 )
 	    {
 	      printk(" %02x", byte1);
@@ -111,7 +111,7 @@
 	printk(" [more..]\n");
       else
 	{
-	  get_user(FPU_modrm, 1 + (unsigned char *) address);
+	  FPU_get_user(FPU_modrm, 1 + (u_char *) address);
 	  
 	  if (FPU_modrm >= 0300)
 	    printk(" %02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7);
@@ -166,29 +166,23 @@
   for ( i = 0; i < 8; i++ )
     {
       FPU_REG *r = &st(i);
-      char tagi = r->tag;
+      u_char tagi = FPU_gettagi(i);
       switch (tagi)
 	{
-	case TW_Empty:
+	case TAG_Empty:
 	  continue;
 	  break;
-	case TW_Zero:
-#if 0
-	  printk("st(%d)  %c .0000 0000 0000 0000         ",
-		 i, r->sign ? '-' : '+');
-	  break;
-#endif
-	case TW_Valid:
-	case TW_NaN:
-/*	case TW_Denormal: */
-	case TW_Infinity:
-	  printk("st(%d)  %c .%04lx %04lx %04lx %04lx e%+-6ld ", i,
-		 r->sign ? '-' : '+',
+	case TAG_Zero:
+	case TAG_Special:
+	  tagi = FPU_Special(r);
+	case TAG_Valid:
+	  printk("st(%d)  %c .%04lx %04lx %04lx %04lx e%+-6d ", i,
+		 getsign(r) ? '-' : '+',
 		 (long)(r->sigh >> 16),
 		 (long)(r->sigh & 0xFFFF),
 		 (long)(r->sigl >> 16),
 		 (long)(r->sigl & 0xFFFF),
-		 r->exp - EXP_BIAS + 1);
+		 exponent(r) - EXP_BIAS + 1);
 	  break;
 	default:
 	  printk("Whoops! Error in errors.c: tag%d is %d ", i, tagi);
@@ -262,6 +256,11 @@
 	      0x161  in reg_ld_str.c
 	      0x162  in reg_ld_str.c
 	      0x163  in reg_ld_str.c
+	      0x164  in reg_ld_str.c
+	      0x170  in fpu_tags.c
+	      0x171  in fpu_tags.c
+	      0x172  in fpu_tags.c
+	      0x180  in reg_convert.c
        0x2nn  in an *.S file:
               0x201  in reg_u_add.S
               0x202  in reg_u_div.S
@@ -347,11 +346,11 @@
       if ( n == EX_INTERNAL )
 	{
 	  printk("FPU emulator: Internal error type 0x%04x\n", int_type);
-	  emu_printall();
+	  FPU_printall();
 	}
 #ifdef PRINT_MESSAGES
       else
-	emu_printall();
+	FPU_printall();
 #endif PRINT_MESSAGES
 
       /*
@@ -369,24 +368,97 @@
 }
 
 
-/* Real operation attempted on two operands, one a NaN. */
-/* Returns nz if the exception is unmasked */
-asmlinkage int real_2op_NaN(FPU_REG const *a, FPU_REG const *b, FPU_REG *dest)
+/* Real operation attempted on a NaN. */
+/* Returns < 0 if the exception is unmasked */
+int real_1op_NaN(FPU_REG *a)
 {
-  FPU_REG const *x;
-  int signalling;
+  int signalling, isNaN;
+
+  isNaN = (exponent(a) == EXP_OVER) && (a->sigh & 0x80000000);
 
   /* The default result for the case of two "equal" NaNs (signs may
      differ) is chosen to reproduce 80486 behaviour */
-  x = a;
-  if (a->tag == TW_NaN)
+  signalling = isNaN && !(a->sigh & 0x40000000);
+
+  if ( !signalling )
     {
-      if (b->tag == TW_NaN)
+      if ( !isNaN )  /* pseudo-NaN, or other unsupported? */
+	{
+	  if ( control_word & CW_Invalid )
+	    {
+	      /* Masked response */
+	      reg_copy(&CONST_QNaN, a);
+	    }
+	  EXCEPTION(EX_Invalid);
+	  return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Special;
+	}
+      return TAG_Special;
+    }
+
+  if ( control_word & CW_Invalid )
+    {
+      /* The masked response */
+      if ( !(a->sigh & 0x80000000) )  /* pseudo-NaN ? */
+	{
+	  reg_copy(&CONST_QNaN, a);
+	}
+      /* ensure a Quiet NaN */
+      a->sigh |= 0x40000000;
+    }
+
+  EXCEPTION(EX_Invalid);
+
+  return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Special;
+}
+
+
+/* Real operation attempted on two operands, one a NaN. */
+/* Returns < 0 if the exception is unmasked */
+int real_2op_NaN(FPU_REG const *b, u_char tagb,
+		 int deststnr,
+		 FPU_REG const *defaultNaN)
+{
+  FPU_REG *dest = &st(deststnr);
+  FPU_REG const *a = dest;
+  u_char taga = FPU_gettagi(deststnr);
+  FPU_REG const *x;
+  int signalling, unsupported;
+
+  if ( taga == TAG_Special )
+    taga = FPU_Special(a);
+  if ( tagb == TAG_Special )
+    tagb = FPU_Special(b);
+
+  /* TW_NaN is also used for unsupported data types. */
+  unsupported = ((taga == TW_NaN)
+		 && !((exponent(a) == EXP_OVER) && (a->sigh & 0x80000000)))
+    || ((tagb == TW_NaN)
+	&& !((exponent(b) == EXP_OVER) && (b->sigh & 0x80000000)));
+  if ( unsupported )
+    {
+      if ( control_word & CW_Invalid )
+	{
+	  /* Masked response */
+	  FPU_copy_to_regi(&CONST_QNaN, TAG_Special, deststnr);
+	}
+      EXCEPTION(EX_Invalid);
+      return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Special;
+    }
+
+  if (taga == TW_NaN)
+    {
+      x = a;
+      if (tagb == TW_NaN)
 	{
 	  signalling = !(a->sigh & b->sigh & 0x40000000);
-	  /* find the "larger" */
-	  if ( significand(a) < significand(b) )
+	  if ( significand(b) > significand(a) )
 	    x = b;
+	  else if ( significand(b) == significand(a) )
+	    {
+	      /* The default result for the case of two "equal" NaNs (signs may
+		 differ) is chosen to reproduce 80486 behaviour */
+	      x = defaultNaN;
+	    }
 	}
       else
 	{
@@ -396,7 +468,7 @@
     }
   else
 #ifdef PARANOID
-    if (b->tag == TW_NaN)
+    if (tagb == TW_NaN)
 #endif PARANOID
     {
       signalling = !(b->sigh & 0x40000000);
@@ -411,33 +483,32 @@
     }
 #endif PARANOID
 
-  if ( !signalling )
+  if ( (!signalling) || (control_word & CW_Invalid) )
     {
-      if ( !(x->sigh & 0x80000000) )  /* pseudo-NaN ? */
-	x = &CONST_QNaN;
-      reg_move(x, dest);
-      return 0;
-    }
+      if ( ! x )
+	x = b;
 
-  if ( control_word & CW_Invalid )
-    {
-      /* The masked response */
       if ( !(x->sigh & 0x80000000) )  /* pseudo-NaN ? */
 	x = &CONST_QNaN;
-      reg_move(x, dest);
+
+      FPU_copy_to_regi(x, TAG_Special, deststnr);
+
+      if ( !signalling )
+	return TAG_Special;
+
       /* ensure a Quiet NaN */
       dest->sigh |= 0x40000000;
     }
 
   EXCEPTION(EX_Invalid);
-  
-  return !(control_word & CW_Invalid);
+
+  return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Special;
 }
 
 
 /* Invalid arith operation on Valid registers */
-/* Returns nz if the exception is unmasked */
-asmlinkage int arith_invalid(FPU_REG *dest)
+/* Returns < 0 if the exception is unmasked */
+asmlinkage int arith_invalid(int deststnr)
 {
 
   EXCEPTION(EX_Invalid);
@@ -445,28 +516,31 @@
   if ( control_word & CW_Invalid )
     {
       /* The masked response */
-      reg_move(&CONST_QNaN, dest);
+      FPU_copy_to_regi(&CONST_QNaN, TAG_Special, deststnr);
     }
   
-  return !(control_word & CW_Invalid);
+  return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Valid;
 
 }
 
 
 /* Divide a finite number by zero */
-asmlinkage int divide_by_zero(int sign, FPU_REG *dest)
+asmlinkage int FPU_divide_by_zero(int deststnr, u_char sign)
 {
+  FPU_REG *dest = &st(deststnr);
+  int tag = TAG_Valid;
 
   if ( control_word & CW_ZeroDiv )
     {
       /* The masked response */
-      reg_move(&CONST_INF, dest);
-      dest->sign = (unsigned char)sign;
+      FPU_copy_to_regi(&CONST_INF, TAG_Special, deststnr);
+      setsign(dest, sign);
+      tag = TAG_Special;
     }
  
   EXCEPTION(EX_ZeroDiv);
 
-  return !(control_word & CW_ZeroDiv);
+  return (!(control_word & CW_ZeroDiv) ? FPU_Exception : 0) | tag;
 
 }
 
@@ -495,7 +569,6 @@
     partial_status |= (SW_Precision | SW_C1);   /* The masked response */
   else
     EXCEPTION(EX_Precision | SW_C1);
-
 }
 
 
@@ -517,32 +590,31 @@
   if ( control_word & CW_Denormal )
     {   /* The masked response */
       partial_status |= SW_Denorm_Op;
-      return 0;
+      return TAG_Special;
     }
   else
     {
       EXCEPTION(EX_Denormal);
-      return 1;
+      return TAG_Special | FPU_Exception;
     }
 }
 
 
 asmlinkage int arith_overflow(FPU_REG *dest)
 {
+  int tag = TAG_Valid;
 
   if ( control_word & CW_Overflow )
     {
-      char sign;
       /* The masked response */
 /* ###### The response here depends upon the rounding mode */
-      sign = dest->sign;
-      reg_move(&CONST_INF, dest);
-      dest->sign = sign;
+      reg_copy(&CONST_INF, dest);
+      tag = TAG_Special;
     }
   else
     {
       /* Subtract the magic number from the exponent */
-      dest->exp -= (3 * (1 << 13));
+      addexponent(dest, (-3 * (1 << 13)));
     }
 
   EXCEPTION(EX_Overflow);
@@ -553,30 +625,36 @@
 	 The roundup bit (C1) is also set because we have
 	 "rounded" upwards to Infinity. */
       EXCEPTION(EX_Precision | SW_C1);
-      return !(control_word & CW_Precision);
+      return tag;
     }
 
-  return 0;
+  return tag;
 
 }
 
 
 asmlinkage int arith_underflow(FPU_REG *dest)
 {
+  int tag = TAG_Valid;
 
   if ( control_word & CW_Underflow )
     {
       /* The masked response */
-      if ( dest->exp <= EXP_UNDER - 63 )
+      if ( exponent16(dest) <= EXP_UNDER - 63 )
 	{
-	  reg_move(&CONST_Z, dest);
+	  reg_copy(&CONST_Z, dest);
 	  partial_status &= ~SW_C1;       /* Round down. */
+	  tag = TAG_Zero;
+	}
+      else
+	{
+	  stdexp(dest);
 	}
     }
   else
     {
       /* Add the magic number to the exponent. */
-      dest->exp += (3 * (1 << 13));
+      addexponent(dest, (3 * (1 << 13)) + EXTENDED_Ebias);
     }
 
   EXCEPTION(EX_Underflow);
@@ -584,22 +662,22 @@
     {
       /* The underflow exception is masked. */
       EXCEPTION(EX_Precision);
-      return !(control_word & CW_Precision);
+      return tag;
     }
 
-  return 0;
+  return tag;
 
 }
 
 
-void stack_overflow(void)
+void FPU_stack_overflow(void)
 {
 
  if ( control_word & CW_Invalid )
     {
       /* The masked response */
       top--;
-      reg_move(&CONST_QNaN, &st(0));
+      FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
     }
 
   EXCEPTION(EX_StackOver);
@@ -609,13 +687,13 @@
 }
 
 
-void stack_underflow(void)
+void FPU_stack_underflow(void)
 {
 
  if ( control_word & CW_Invalid )
     {
       /* The masked response */
-      reg_move(&CONST_QNaN, &st(0));
+      FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
     }
 
   EXCEPTION(EX_StackUnder);
@@ -625,13 +703,13 @@
 }
 
 
-void stack_underflow_i(int i)
+void FPU_stack_underflow_i(int i)
 {
 
  if ( control_word & CW_Invalid )
     {
       /* The masked response */
-      reg_move(&CONST_QNaN, &(st(i)));
+      FPU_copy_to_regi(&CONST_QNaN, TAG_Special, i);
     }
 
   EXCEPTION(EX_StackUnder);
@@ -641,14 +719,14 @@
 }
 
 
-void stack_underflow_pop(int i)
+void FPU_stack_underflow_pop(int i)
 {
 
  if ( control_word & CW_Invalid )
     {
       /* The masked response */
-      reg_move(&CONST_QNaN, &(st(i)));
-      pop();
+      FPU_copy_to_regi(&CONST_QNaN, TAG_Special, i);
+      FPU_pop();
     }
 
   EXCEPTION(EX_StackUnder);

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov