~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/x86/math-emu/errors.c

Version: ~ [ linux-5.13-rc1 ] ~ [ linux-5.12.2 ] ~ [ linux-5.11.19 ] ~ [ linux-5.10.35 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.117 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.190 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.232 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.268 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.268 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp