errors.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:18k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

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