This source file includes following definitions.
- Un_impl
- FPU_illegal
- emu_printall
- exception
- real_2op_NaN
- arith_invalid
- divide_by_zero
- set_precision_flag
- set_precision_flag_up
- set_precision_flag_down
- denormal_operand
- arith_overflow
- arith_underflow
- stack_overflow
- stack_underflow
- stack_underflow_i
- stack_underflow_pop
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
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
76
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
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,
148 (partial_status & 0x3800) >> 11,
149 partial_status & 0x80 ? 1 : 0,
150 partial_status & 0x40 ? 1 : 0,
151 partial_status & SW_C3?1:0, partial_status & SW_C2?1:0,
152 partial_status & SW_C1?1:0, partial_status & SW_C0?1:0,
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
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
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303 void exception(int n)
304 {
305 int i, int_type;
306
307 int_type = 0;
308 if ( n & EX_INTERNAL )
309 {
310 int_type = n - EX_INTERNAL;
311 n = EX_INTERNAL;
312
313 partial_status |= (SW_Exc_Mask | SW_Summary | SW_Backward);
314 }
315 else
316 {
317
318 n &= (SW_Exc_Mask);
319
320 partial_status |= n;
321
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
328
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
338 printk(FPU_VERSION" "__DATE__" (C) W. Metzenthen.\n");
339 #endif PRINT_MESSAGES
340
341
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
367
368
369
370
371
372
373
374 }
375 RE_ENTRANT_CHECK_ON;
376
377 #ifdef __DEBUG__
378 math_abort(FPU_info,SIGFPE);
379 #endif __DEBUG__
380
381 }
382
383
384
385
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
392
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
400 if ( significand(a) < significand(b) )
401 x = b;
402 }
403 else
404 {
405
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) )
429 x = &CONST_QNaN;
430 reg_move(x, dest);
431 return 0;
432 }
433
434 if ( control_word & CW_Invalid )
435 {
436
437 if ( !(x->sigh & 0x80000000) )
438 x = &CONST_QNaN;
439 reg_move(x, dest);
440
441 dest->sigh |= 0x40000000;
442 }
443
444 EXCEPTION(EX_Invalid);
445
446 return !(control_word & CW_Invalid);
447 }
448
449
450
451
452 asmlinkage int arith_invalid(FPU_REG *dest)
453 {
454
455 EXCEPTION(EX_Invalid);
456
457 if ( control_word & CW_Invalid )
458 {
459
460 reg_move(&CONST_QNaN, dest);
461 }
462
463 return !(control_word & CW_Invalid);
464
465 }
466
467
468
469 asmlinkage int divide_by_zero(int sign, FPU_REG *dest)
470 {
471
472 if ( control_word & CW_ZeroDiv )
473 {
474
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
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;
493 return 0;
494 }
495 else
496 {
497 exception(flags);
498 return 1;
499 }
500 }
501
502
503
504 asmlinkage void set_precision_flag_up(void)
505 {
506 if ( control_word & CW_Precision )
507 partial_status |= (SW_Precision | SW_C1);
508 else
509 exception(EX_Precision | SW_C1);
510
511 }
512
513
514
515 asmlinkage void set_precision_flag_down(void)
516 {
517 if ( control_word & CW_Precision )
518 {
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 {
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
549
550 sign = dest->sign;
551 reg_move(&CONST_INF, dest);
552 dest->sign = sign;
553 }
554 else
555 {
556
557 dest->exp -= (3 * (1 << 13));
558 }
559
560 EXCEPTION(EX_Overflow);
561 if ( control_word & CW_Overflow )
562 {
563
564
565
566
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
582 if ( dest->exp <= EXP_UNDER - 63 )
583 {
584 reg_move(&CONST_Z, dest);
585 partial_status &= ~SW_C1;
586 }
587 }
588 else
589 {
590
591 dest->exp += (3 * (1 << 13));
592 }
593
594 EXCEPTION(EX_Underflow);
595 if ( control_word & CW_Underflow )
596 {
597
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
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
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
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
662 reg_move(&CONST_QNaN, &(st(i)));
663 pop();
664 }
665
666 EXCEPTION(EX_StackUnder);
667
668 return;
669
670 }
671