home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.2 / LINUX-1.2 / LINUX-1 / linux / arch / i386 / math-emu / errors.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-01  |  16.7 KB  |  672 lines

  1. /*---------------------------------------------------------------------------+
  2.  |  errors.c                                                                 |
  3.  |                                                                           |
  4.  |  The error handling functions for wm-FPU-emu                              |
  5.  |                                                                           |
  6.  | Copyright (C) 1992,1993,1994                                              |
  7.  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
  8.  |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  9.  |                                                                           |
  10.  |                                                                           |
  11.  +---------------------------------------------------------------------------*/
  12.  
  13. /*---------------------------------------------------------------------------+
  14.  | Note:                                                                     |
  15.  |    The file contains code which accesses user memory.                     |
  16.  |    Emulator static data may change when user memory is accessed, due to   |
  17.  |    other processes using the emulator while swapping is in progress.      |
  18.  +---------------------------------------------------------------------------*/
  19.  
  20. #include <linux/signal.h>
  21.  
  22. #include <asm/segment.h>
  23.  
  24. #include "fpu_system.h"
  25. #include "exception.h"
  26. #include "fpu_emu.h"
  27. #include "status_w.h"
  28. #include "control_w.h"
  29. #include "reg_constant.h"
  30. #include "version.h"
  31.  
  32. /* */
  33. #undef PRINT_MESSAGES
  34. /* */
  35.  
  36.  
  37. void Un_impl(void)
  38. {
  39.   unsigned char byte1, FPU_modrm;
  40.   unsigned long address = FPU_ORIG_EIP;
  41.  
  42.   RE_ENTRANT_CHECK_OFF;
  43.   /* No need to verify_area(), we have previously fetched these bytes. */
  44.   printk("Unimplemented FPU Opcode at eip=%p : ", (void *) address);
  45.   if ( FPU_CS == USER_CS )
  46.     {
  47.       while ( 1 )
  48.     {
  49.       byte1 = get_fs_byte((unsigned char *) address);
  50.       if ( (byte1 & 0xf8) == 0xd8 ) break;
  51.       printk("[%02x]", byte1);
  52.       address++;
  53.     }
  54.       printk("%02x ", byte1);
  55.       FPU_modrm = get_fs_byte(1 + (unsigned char *) address);
  56.       
  57.       if (FPU_modrm >= 0300)
  58.     printk("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7);
  59.       else
  60.     printk("/%d\n", (FPU_modrm >> 3) & 7);
  61.     }
  62.   else
  63.     {
  64.       printk("cs selector = %04x\n", FPU_CS);
  65.     }
  66.  
  67.   RE_ENTRANT_CHECK_ON;
  68.  
  69.   EXCEPTION(EX_Invalid);
  70.  
  71. }
  72.  
  73.  
  74. /*
  75.    Called for opcodes which are illegal and which are known to result in a
  76.    SIGILL with a real 80486.
  77.    */
  78. void FPU_illegal(void)
  79. {
  80.   math_abort(FPU_info,SIGILL);
  81. }
  82.  
  83.  
  84.  
  85. void emu_printall()
  86. {
  87.   int i;
  88.   static char *tag_desc[] = { "Valid", "Zero", "ERROR", "ERROR",
  89.                               "DeNorm", "Inf", "NaN", "Empty" };
  90.   unsigned char byte1, FPU_modrm;
  91.   unsigned long address = FPU_ORIG_EIP;
  92.  
  93.   RE_ENTRANT_CHECK_OFF;
  94.   /* No need to verify_area(), we have previously fetched these bytes. */
  95.   printk("At %p:", (void *) address);
  96.   if ( FPU_CS == USER_CS )
  97.     {
  98. #define MAX_PRINTED_BYTES 20
  99.       for ( i = 0; i < MAX_PRINTED_BYTES; i++ )
  100.     {
  101.       byte1 = get_fs_byte((unsigned char *) address);
  102.       if ( (byte1 & 0xf8) == 0xd8 )
  103.         {
  104.           printk(" %02x", byte1);
  105.           break;
  106.         }
  107.       printk(" [%02x]", byte1);
  108.       address++;
  109.     }
  110.       if ( i == MAX_PRINTED_BYTES )
  111.     printk(" [more..]\n");
  112.       else
  113.     {
  114.       FPU_modrm = get_fs_byte(1 + (unsigned char *) address);
  115.       
  116.       if (FPU_modrm >= 0300)
  117.         printk(" %02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7);
  118.       else
  119.         printk(" /%d, mod=%d rm=%d\n",
  120.            (FPU_modrm >> 3) & 7, (FPU_modrm >> 6) & 3, FPU_modrm & 7);
  121.     }
  122.     }
  123.   else
  124.     {
  125.       printk("%04x\n", FPU_CS);
  126.     }
  127.  
  128.   partial_status = status_word();
  129.  
  130. #ifdef DEBUGGING
  131. if ( partial_status & SW_Backward )    printk("SW: backward compatibility\n");
  132. if ( partial_status & SW_C3 )          printk("SW: condition bit 3\n");
  133. if ( partial_status & SW_C2 )          printk("SW: condition bit 2\n");
  134. if ( partial_status & SW_C1 )          printk("SW: condition bit 1\n");
  135. if ( partial_status & SW_C0 )          printk("SW: condition bit 0\n");
  136. if ( partial_status & SW_Summary )     printk("SW: exception summary\n");
  137. if ( partial_status & SW_Stack_Fault ) printk("SW: stack fault\n");
  138. if ( partial_status & SW_Precision )   printk("SW: loss of precision\n");
  139. if ( partial_status & SW_Underflow )   printk("SW: underflow\n");
  140. if ( partial_status & SW_Overflow )    printk("SW: overflow\n");
  141. if ( partial_status & SW_Zero_Div )    printk("SW: divide by zero\n");
  142. if ( partial_status & SW_Denorm_Op )   printk("SW: denormalized operand\n");
  143. if ( partial_status & SW_Invalid )     printk("SW: invalid operation\n");
  144. #endif DEBUGGING
  145.  
  146.   printk(" SW: b=%d st=%ld es=%d sf=%d cc=%d%d%d%d ef=%d%d%d%d%d%d\n",
  147.      partial_status & 0x8000 ? 1 : 0,   /* busy */
  148.      (partial_status & 0x3800) >> 11,   /* stack top pointer */
  149.      partial_status & 0x80 ? 1 : 0,     /* Error summary status */
  150.      partial_status & 0x40 ? 1 : 0,     /* Stack flag */
  151.      partial_status & SW_C3?1:0, partial_status & SW_C2?1:0, /* cc */
  152.      partial_status & SW_C1?1:0, partial_status & SW_C0?1:0, /* cc */
  153.      partial_status & SW_Precision?1:0, partial_status & SW_Underflow?1:0,
  154.      partial_status & SW_Overflow?1:0, partial_status & SW_Zero_Div?1:0,
  155.      partial_status & SW_Denorm_Op?1:0, partial_status & SW_Invalid?1:0);
  156.   
  157. printk(" CW: ic=%d rc=%ld%ld pc=%ld%ld iem=%d     ef=%d%d%d%d%d%d\n",
  158.      control_word & 0x1000 ? 1 : 0,
  159.      (control_word & 0x800) >> 11, (control_word & 0x400) >> 10,
  160.      (control_word & 0x200) >> 9, (control_word & 0x100) >> 8,
  161.      control_word & 0x80 ? 1 : 0,
  162.      control_word & SW_Precision?1:0, control_word & SW_Underflow?1:0,
  163.      control_word & SW_Overflow?1:0, control_word & SW_Zero_Div?1:0,
  164.      control_word & SW_Denorm_Op?1:0, control_word & SW_Invalid?1:0);
  165.  
  166.   for ( i = 0; i < 8; i++ )
  167.     {
  168.       FPU_REG *r = &st(i);
  169.       switch (r->tag)
  170.     {
  171.     case TW_Empty:
  172.       continue;
  173.       break;
  174.     case TW_Zero:
  175. #if 0
  176.       printk("st(%d)  %c .0000 0000 0000 0000         ",
  177.          i, r->sign ? '-' : '+');
  178.       break;
  179. #endif
  180.     case TW_Valid:
  181.     case TW_NaN:
  182. /*    case TW_Denormal: */
  183.     case TW_Infinity:
  184.       printk("st(%d)  %c .%04lx %04lx %04lx %04lx e%+-6ld ", i,
  185.          r->sign ? '-' : '+',
  186.          (long)(r->sigh >> 16),
  187.          (long)(r->sigh & 0xFFFF),
  188.          (long)(r->sigl >> 16),
  189.          (long)(r->sigl & 0xFFFF),
  190.          r->exp - EXP_BIAS + 1);
  191.       break;
  192.     default:
  193.       printk("Whoops! Error in errors.c      ");
  194.       break;
  195.     }
  196.       printk("%s\n", tag_desc[(int) (unsigned) r->tag]);
  197.     }
  198.  
  199. #ifdef OBSOLETE
  200.   printk("[data] %c .%04lx %04lx %04lx %04lx e%+-6ld ",
  201.      FPU_loaded_data.sign ? '-' : '+',
  202.      (long)(FPU_loaded_data.sigh >> 16),
  203.      (long)(FPU_loaded_data.sigh & 0xFFFF),
  204.      (long)(FPU_loaded_data.sigl >> 16),
  205.      (long)(FPU_loaded_data.sigl & 0xFFFF),
  206.      FPU_loaded_data.exp - EXP_BIAS + 1);
  207.   printk("%s\n", tag_desc[(int) (unsigned) FPU_loaded_data.tag]);
  208. #endif OBSOLETE
  209.   RE_ENTRANT_CHECK_ON;
  210.  
  211. }
  212.  
  213. static struct {
  214.   int type;
  215.   char *name;
  216. } exception_names[] = {
  217.   { EX_StackOver, "stack overflow" },
  218.   { EX_StackUnder, "stack underflow" },
  219.   { EX_Precision, "loss of precision" },
  220.   { EX_Underflow, "underflow" },
  221.   { EX_Overflow, "overflow" },
  222.   { EX_ZeroDiv, "divide by zero" },
  223.   { EX_Denormal, "denormalized operand" },
  224.   { EX_Invalid, "invalid operation" },
  225.   { EX_INTERNAL, "INTERNAL BUG in "FPU_VERSION },
  226.   { 0, NULL }
  227. };
  228.  
  229. /*
  230.  EX_INTERNAL is always given with a code which indicates where the
  231.  error was detected.
  232.  
  233.  Internal error types:
  234.        0x14   in fpu_etc.c
  235.        0x1nn  in a *.c file:
  236.               0x101  in reg_add_sub.c
  237.               0x102  in reg_mul.c
  238.               0x104  in poly_atan.c
  239.               0x105  in reg_mul.c
  240.               0x107  in fpu_trig.c
  241.           0x108  in reg_compare.c
  242.           0x109  in reg_compare.c
  243.           0x110  in reg_add_sub.c
  244.           0x111  in fpe_entry.c
  245.           0x112  in fpu_trig.c
  246.           0x113  in errors.c
  247.           0x115  in fpu_trig.c
  248.           0x116  in fpu_trig.c
  249.           0x117  in fpu_trig.c
  250.           0x118  in fpu_trig.c
  251.           0x119  in fpu_trig.c
  252.           0x120  in poly_atan.c
  253.           0x121  in reg_compare.c
  254.           0x122  in reg_compare.c
  255.           0x123  in reg_compare.c
  256.           0x125  in fpu_trig.c
  257.           0x126  in fpu_entry.c
  258.           0x127  in poly_2xm1.c
  259.           0x128  in fpu_entry.c
  260.           0x129  in fpu_entry.c
  261.           0x130  in get_address.c
  262.           0x131  in get_address.c
  263.           0x132  in get_address.c
  264.           0x133  in get_address.c
  265.           0x140  in load_store.c
  266.           0x141  in load_store.c
  267.               0x150  in poly_sin.c
  268.               0x151  in poly_sin.c
  269.           0x160  in reg_ld_str.c
  270.           0x161  in reg_ld_str.c
  271.           0x162  in reg_ld_str.c
  272.           0x163  in reg_ld_str.c
  273.        0x2nn  in an *.S file:
  274.               0x201  in reg_u_add.S
  275.               0x202  in reg_u_div.S
  276.               0x203  in reg_u_div.S
  277.               0x204  in reg_u_div.S
  278.               0x205  in reg_u_mul.S
  279.               0x206  in reg_u_sub.S
  280.               0x207  in wm_sqrt.S
  281.           0x208  in reg_div.S
  282.               0x209  in reg_u_sub.S
  283.               0x210  in reg_u_sub.S
  284.               0x211  in reg_u_sub.S
  285.               0x212  in reg_u_sub.S
  286.           0x213  in wm_sqrt.S
  287.           0x214  in wm_sqrt.S
  288.           0x215  in wm_sqrt.S
  289.           0x220  in reg_norm.S
  290.           0x221  in reg_norm.S
  291.           0x230  in reg_round.S
  292.           0x231  in reg_round.S
  293.           0x232  in reg_round.S
  294.           0x233  in reg_round.S
  295.           0x234  in reg_round.S
  296.           0x235  in reg_round.S
  297.           0x236  in reg_round.S
  298.           0x240  in div_Xsig.S
  299.           0x241  in div_Xsig.S
  300.           0x242  in div_Xsig.S
  301.  */
  302.  
  303. void exception(int n)
  304. {
  305.   int i, int_type;
  306.  
  307.   int_type = 0;         /* Needed only to stop compiler warnings */
  308.   if ( n & EX_INTERNAL )
  309.     {
  310.       int_type = n - EX_INTERNAL;
  311.       n = EX_INTERNAL;
  312.       /* Set lots of exception bits! */
  313.       partial_status |= (SW_Exc_Mask | SW_Summary | SW_Backward);
  314.     }
  315.   else
  316.     {
  317.       /* Extract only the bits which we use to set the status word */
  318.       n &= (SW_Exc_Mask);
  319.       /* Set the corresponding exception bit */
  320.       partial_status |= n;
  321.       /* Set summary bits iff exception isn't masked */
  322.       if ( partial_status & ~control_word & CW_Exceptions )
  323.     partial_status |= (SW_Summary | SW_Backward);
  324.       if ( n & (SW_Stack_Fault | EX_Precision) )
  325.     {
  326.       if ( !(n & SW_C1) )
  327.         /* This bit distinguishes over- from underflow for a stack fault,
  328.            and roundup from round-down for precision loss. */
  329.         partial_status &= ~SW_C1;
  330.     }
  331.     }
  332.  
  333.   RE_ENTRANT_CHECK_OFF;
  334.   if ( (~control_word & n & CW_Exceptions) || (n == EX_INTERNAL) )
  335.     {
  336. #ifdef PRINT_MESSAGES
  337.       /* My message from the sponsor */
  338.       printk(FPU_VERSION" "__DATE__" (C) W. Metzenthen.\n");
  339. #endif PRINT_MESSAGES
  340.       
  341.       /* Get a name string for error reporting */
  342.       for (i=0; exception_names[i].type; i++)
  343.     if ( (exception_names[i].type & n) == exception_names[i].type )
  344.       break;
  345.       
  346.       if (exception_names[i].type)
  347.     {
  348. #ifdef PRINT_MESSAGES
  349.       printk("FP Exception: %s!\n", exception_names[i].name);
  350. #endif PRINT_MESSAGES
  351.     }
  352.       else
  353.     printk("FPU emulator: Unknown Exception: 0x%04x!\n", n);
  354.       
  355.       if ( n == EX_INTERNAL )
  356.     {
  357.       printk("FPU emulator: Internal error type 0x%04x\n", int_type);
  358.       emu_printall();
  359.     }
  360. #ifdef PRINT_MESSAGES
  361.       else
  362.     emu_printall();
  363. #endif PRINT_MESSAGES
  364.  
  365.       /*
  366.        * The 80486 generates an interrupt on the next non-control FPU
  367.        * instruction. So we need some means of flagging it.
  368.        * We use the ES (Error Summary) bit for this, assuming that
  369.        * this is the way a real FPU does it (until I can check it out),
  370.        * if not, then some method such as the following kludge might
  371.        * be needed.
  372.        */
  373. /*      regs[0].tag |= TW_FPU_Interrupt; */
  374.     }
  375.   RE_ENTRANT_CHECK_ON;
  376.  
  377. #ifdef __DEBUG__
  378.   math_abort(FPU_info,SIGFPE);
  379. #endif __DEBUG__
  380.  
  381. }
  382.  
  383.  
  384. /* Real operation attempted on two operands, one a NaN. */
  385. /* Returns nz if the exception is unmasked */
  386. asmlinkage int real_2op_NaN(FPU_REG const *a, FPU_REG const *b, FPU_REG *dest)
  387. {
  388.   FPU_REG const *x;
  389.   int signalling;
  390.  
  391.   /* The default result for the case of two "equal" NaNs (signs may
  392.      differ) is chosen to reproduce 80486 behaviour */
  393.   x = a;
  394.   if (a->tag == TW_NaN)
  395.     {
  396.       if (b->tag == TW_NaN)
  397.     {
  398.       signalling = !(a->sigh & b->sigh & 0x40000000);
  399.       /* find the "larger" */
  400.       if ( significand(a) < significand(b) )
  401.         x = b;
  402.     }
  403.       else
  404.     {
  405.       /* return the quiet version of the NaN in a */
  406.       signalling = !(a->sigh & 0x40000000);
  407.     }
  408.     }
  409.   else
  410. #ifdef PARANOID
  411.     if (b->tag == TW_NaN)
  412. #endif PARANOID
  413.     {
  414.       signalling = !(b->sigh & 0x40000000);
  415.       x = b;
  416.     }
  417. #ifdef PARANOID
  418.   else
  419.     {
  420.       signalling = 0;
  421.       EXCEPTION(EX_INTERNAL|0x113);
  422.       x = &CONST_QNaN;
  423.     }
  424. #endif PARANOID
  425.  
  426.   if ( !signalling )
  427.     {
  428.       if ( !(x->sigh & 0x80000000) )  /* pseudo-NaN ? */
  429.     x = &CONST_QNaN;
  430.       reg_move(x, dest);
  431.       return 0;
  432.     }
  433.  
  434.   if ( control_word & CW_Invalid )
  435.     {
  436.       /* The masked response */
  437.       if ( !(x->sigh & 0x80000000) )  /* pseudo-NaN ? */
  438.     x = &CONST_QNaN;
  439.       reg_move(x, dest);
  440.       /* ensure a Quiet NaN */
  441.       dest->sigh |= 0x40000000;
  442.     }
  443.  
  444.   EXCEPTION(EX_Invalid);
  445.   
  446.   return !(control_word & CW_Invalid);
  447. }
  448.  
  449.  
  450. /* Invalid arith operation on Valid registers */
  451. /* Returns nz if the exception is unmasked */
  452. asmlinkage int arith_invalid(FPU_REG *dest)
  453. {
  454.  
  455.   EXCEPTION(EX_Invalid);
  456.   
  457.   if ( control_word & CW_Invalid )
  458.     {
  459.       /* The masked response */
  460.       reg_move(&CONST_QNaN, dest);
  461.     }
  462.   
  463.   return !(control_word & CW_Invalid);
  464.  
  465. }
  466.  
  467.  
  468. /* Divide a finite number by zero */
  469. asmlinkage int divide_by_zero(int sign, FPU_REG *dest)
  470. {
  471.  
  472.   if ( control_word & CW_ZeroDiv )
  473.     {
  474.       /* The masked response */
  475.       reg_move(&CONST_INF, dest);
  476.       dest->sign = (unsigned char)sign;
  477.     }
  478.  
  479.   EXCEPTION(EX_ZeroDiv);
  480.  
  481.   return !(control_word & CW_ZeroDiv);
  482.  
  483. }
  484.  
  485.  
  486. /* This may be called often, so keep it lean */
  487. int set_precision_flag(int flags)
  488. {
  489.   if ( control_word & CW_Precision )
  490.     {
  491.       partial_status &= ~(SW_C1 & flags);
  492.       partial_status |= flags;   /* The masked response */
  493.       return 0;
  494.     }
  495.   else
  496.     {
  497.       exception(flags);
  498.       return 1;
  499.     }
  500. }
  501.  
  502.  
  503. /* This may be called often, so keep it lean */
  504. asmlinkage void set_precision_flag_up(void)
  505. {
  506.   if ( control_word & CW_Precision )
  507.     partial_status |= (SW_Precision | SW_C1);   /* The masked response */
  508.   else
  509.     exception(EX_Precision | SW_C1);
  510.  
  511. }
  512.  
  513.  
  514. /* This may be called often, so keep it lean */
  515. asmlinkage void set_precision_flag_down(void)
  516. {
  517.   if ( control_word & CW_Precision )
  518.     {   /* The masked response */
  519.       partial_status &= ~SW_C1;
  520.       partial_status |= SW_Precision;
  521.     }
  522.   else
  523.     exception(EX_Precision);
  524. }
  525.  
  526.  
  527. asmlinkage int denormal_operand(void)
  528. {
  529.   if ( control_word & CW_Denormal )
  530.     {   /* The masked response */
  531.       partial_status |= SW_Denorm_Op;
  532.       return 0;
  533.     }
  534.   else
  535.     {
  536.       exception(EX_Denormal);
  537.       return 1;
  538.     }
  539. }
  540.  
  541.  
  542. asmlinkage int arith_overflow(FPU_REG *dest)
  543. {
  544.  
  545.   if ( control_word & CW_Overflow )
  546.     {
  547.       char sign;
  548.       /* The masked response */
  549. /* ###### The response here depends upon the rounding mode */
  550.       sign = dest->sign;
  551.       reg_move(&CONST_INF, dest);
  552.       dest->sign = sign;
  553.     }
  554.   else
  555.     {
  556.       /* Subtract the magic number from the exponent */
  557.       dest->exp -= (3 * (1 << 13));
  558.     }
  559.  
  560.   EXCEPTION(EX_Overflow);
  561.   if ( control_word & CW_Overflow )
  562.     {
  563.       /* The overflow exception is masked. */
  564.       /* By definition, precision is lost.
  565.      The roundup bit (C1) is also set because we have
  566.      "rounded" upwards to Infinity. */
  567.       EXCEPTION(EX_Precision | SW_C1);
  568.       return !(control_word & CW_Precision);
  569.     }
  570.  
  571.   return !(control_word & CW_Overflow);
  572.  
  573. }
  574.  
  575.  
  576. asmlinkage int arith_underflow(FPU_REG *dest)
  577. {
  578.  
  579.   if ( control_word & CW_Underflow )
  580.     {
  581.       /* The masked response */
  582.       if ( dest->exp <= EXP_UNDER - 63 )
  583.     {
  584.       reg_move(&CONST_Z, dest);
  585.       partial_status &= ~SW_C1;       /* Round down. */
  586.     }
  587.     }
  588.   else
  589.     {
  590.       /* Add the magic number to the exponent. */
  591.       dest->exp += (3 * (1 << 13));
  592.     }
  593.  
  594.   EXCEPTION(EX_Underflow);
  595.   if ( control_word & CW_Underflow )
  596.     {
  597.       /* The underflow exception is masked. */
  598.       EXCEPTION(EX_Precision);
  599.       return !(control_word & CW_Precision);
  600.     }
  601.  
  602.   return !(control_word & CW_Underflow);
  603.  
  604. }
  605.  
  606.  
  607. void stack_overflow(void)
  608. {
  609.  
  610.  if ( control_word & CW_Invalid )
  611.     {
  612.       /* The masked response */
  613.       top--;
  614.       reg_move(&CONST_QNaN, &st(0));
  615.     }
  616.  
  617.   EXCEPTION(EX_StackOver);
  618.  
  619.   return;
  620.  
  621. }
  622.  
  623.  
  624. void stack_underflow(void)
  625. {
  626.  
  627.  if ( control_word & CW_Invalid )
  628.     {
  629.       /* The masked response */
  630.       reg_move(&CONST_QNaN, &st(0));
  631.     }
  632.  
  633.   EXCEPTION(EX_StackUnder);
  634.  
  635.   return;
  636.  
  637. }
  638.  
  639.  
  640. void stack_underflow_i(int i)
  641. {
  642.  
  643.  if ( control_word & CW_Invalid )
  644.     {
  645.       /* The masked response */
  646.       reg_move(&CONST_QNaN, &(st(i)));
  647.     }
  648.  
  649.   EXCEPTION(EX_StackUnder);
  650.  
  651.   return;
  652.  
  653. }
  654.  
  655.  
  656. void stack_underflow_pop(int i)
  657. {
  658.  
  659.  if ( control_word & CW_Invalid )
  660.     {
  661.       /* The masked response */
  662.       reg_move(&CONST_QNaN, &(st(i)));
  663.       pop();
  664.     }
  665.  
  666.   EXCEPTION(EX_StackUnder);
  667.  
  668.   return;
  669.  
  670. }
  671.  
  672.