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(void)
86 {
87 int i;
88 static const 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 char tagi = r->tag;
170 switch (tagi)
171 {
172 case TW_Empty:
173 continue;
174 break;
175 case TW_Zero:
176 #if 0
177 printk("st(%d) %c .0000 0000 0000 0000 ",
178 i, r->sign ? '-' : '+');
179 break;
180 #endif
181 case TW_Valid:
182 case TW_NaN:
183
184 case TW_Infinity:
185 printk("st(%d) %c .%04lx %04lx %04lx %04lx e%+-6ld ", i,
186 r->sign ? '-' : '+',
187 (long)(r->sigh >> 16),
188 (long)(r->sigh & 0xFFFF),
189 (long)(r->sigl >> 16),
190 (long)(r->sigl & 0xFFFF),
191 r->exp - EXP_BIAS + 1);
192 break;
193 default:
194 printk("Whoops! Error in errors.c: tag%d is %d ", i, tagi);
195 continue;
196 break;
197 }
198 printk("%s\n", tag_desc[(int) (unsigned) tagi]);
199 }
200
201 RE_ENTRANT_CHECK_ON;
202
203 }
204
205 static struct {
206 int type;
207 const char *name;
208 } exception_names[] = {
209 { EX_StackOver, "stack overflow" },
210 { EX_StackUnder, "stack underflow" },
211 { EX_Precision, "loss of precision" },
212 { EX_Underflow, "underflow" },
213 { EX_Overflow, "overflow" },
214 { EX_ZeroDiv, "divide by zero" },
215 { EX_Denormal, "denormalized operand" },
216 { EX_Invalid, "invalid operation" },
217 { EX_INTERNAL, "INTERNAL BUG in "FPU_VERSION },
218 { 0, NULL }
219 };
220
221
222
223
224
225
226
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 void exception(int n)
296 {
297 int i, int_type;
298
299 int_type = 0;
300 if ( n & EX_INTERNAL )
301 {
302 int_type = n - EX_INTERNAL;
303 n = EX_INTERNAL;
304
305 partial_status |= (SW_Exc_Mask | SW_Summary | SW_Backward);
306 }
307 else
308 {
309
310 n &= (SW_Exc_Mask);
311
312 partial_status |= n;
313
314 if ( partial_status & ~control_word & CW_Exceptions )
315 partial_status |= (SW_Summary | SW_Backward);
316 if ( n & (SW_Stack_Fault | EX_Precision) )
317 {
318 if ( !(n & SW_C1) )
319
320
321 partial_status &= ~SW_C1;
322 }
323 }
324
325 RE_ENTRANT_CHECK_OFF;
326 if ( (~control_word & n & CW_Exceptions) || (n == EX_INTERNAL) )
327 {
328 #ifdef PRINT_MESSAGES
329
330 printk(FPU_VERSION" "__DATE__" (C) W. Metzenthen.\n");
331 #endif PRINT_MESSAGES
332
333
334 for (i=0; exception_names[i].type; i++)
335 if ( (exception_names[i].type & n) == exception_names[i].type )
336 break;
337
338 if (exception_names[i].type)
339 {
340 #ifdef PRINT_MESSAGES
341 printk("FP Exception: %s!\n", exception_names[i].name);
342 #endif PRINT_MESSAGES
343 }
344 else
345 printk("FPU emulator: Unknown Exception: 0x%04x!\n", n);
346
347 if ( n == EX_INTERNAL )
348 {
349 printk("FPU emulator: Internal error type 0x%04x\n", int_type);
350 emu_printall();
351 }
352 #ifdef PRINT_MESSAGES
353 else
354 emu_printall();
355 #endif PRINT_MESSAGES
356
357
358
359
360
361
362 }
363 RE_ENTRANT_CHECK_ON;
364
365 #ifdef __DEBUG__
366 math_abort(FPU_info,SIGFPE);
367 #endif __DEBUG__
368
369 }
370
371
372
373
374 asmlinkage int real_2op_NaN(FPU_REG const *a, FPU_REG const *b, FPU_REG *dest)
375 {
376 FPU_REG const *x;
377 int signalling;
378
379
380
381 x = a;
382 if (a->tag == TW_NaN)
383 {
384 if (b->tag == TW_NaN)
385 {
386 signalling = !(a->sigh & b->sigh & 0x40000000);
387
388 if ( significand(a) < significand(b) )
389 x = b;
390 }
391 else
392 {
393
394 signalling = !(a->sigh & 0x40000000);
395 }
396 }
397 else
398 #ifdef PARANOID
399 if (b->tag == TW_NaN)
400 #endif PARANOID
401 {
402 signalling = !(b->sigh & 0x40000000);
403 x = b;
404 }
405 #ifdef PARANOID
406 else
407 {
408 signalling = 0;
409 EXCEPTION(EX_INTERNAL|0x113);
410 x = &CONST_QNaN;
411 }
412 #endif PARANOID
413
414 if ( !signalling )
415 {
416 if ( !(x->sigh & 0x80000000) )
417 x = &CONST_QNaN;
418 reg_move(x, dest);
419 return 0;
420 }
421
422 if ( control_word & CW_Invalid )
423 {
424
425 if ( !(x->sigh & 0x80000000) )
426 x = &CONST_QNaN;
427 reg_move(x, dest);
428
429 dest->sigh |= 0x40000000;
430 }
431
432 EXCEPTION(EX_Invalid);
433
434 return !(control_word & CW_Invalid);
435 }
436
437
438
439
440 asmlinkage int arith_invalid(FPU_REG *dest)
441 {
442
443 EXCEPTION(EX_Invalid);
444
445 if ( control_word & CW_Invalid )
446 {
447
448 reg_move(&CONST_QNaN, dest);
449 }
450
451 return !(control_word & CW_Invalid);
452
453 }
454
455
456
457 asmlinkage int divide_by_zero(int sign, FPU_REG *dest)
458 {
459
460 if ( control_word & CW_ZeroDiv )
461 {
462
463 reg_move(&CONST_INF, dest);
464 dest->sign = (unsigned char)sign;
465 }
466
467 EXCEPTION(EX_ZeroDiv);
468
469 return !(control_word & CW_ZeroDiv);
470
471 }
472
473
474
475 int set_precision_flag(int flags)
476 {
477 if ( control_word & CW_Precision )
478 {
479 partial_status &= ~(SW_C1 & flags);
480 partial_status |= flags;
481 return 0;
482 }
483 else
484 {
485 exception(flags);
486 return 1;
487 }
488 }
489
490
491
492 asmlinkage void set_precision_flag_up(void)
493 {
494 if ( control_word & CW_Precision )
495 partial_status |= (SW_Precision | SW_C1);
496 else
497 exception(EX_Precision | SW_C1);
498
499 }
500
501
502
503 asmlinkage void set_precision_flag_down(void)
504 {
505 if ( control_word & CW_Precision )
506 {
507 partial_status &= ~SW_C1;
508 partial_status |= SW_Precision;
509 }
510 else
511 exception(EX_Precision);
512 }
513
514
515 asmlinkage int denormal_operand(void)
516 {
517 if ( control_word & CW_Denormal )
518 {
519 partial_status |= SW_Denorm_Op;
520 return 0;
521 }
522 else
523 {
524 exception(EX_Denormal);
525 return 1;
526 }
527 }
528
529
530 asmlinkage int arith_overflow(FPU_REG *dest)
531 {
532
533 if ( control_word & CW_Overflow )
534 {
535 char sign;
536
537
538 sign = dest->sign;
539 reg_move(&CONST_INF, dest);
540 dest->sign = sign;
541 }
542 else
543 {
544
545 dest->exp -= (3 * (1 << 13));
546 }
547
548 EXCEPTION(EX_Overflow);
549 if ( control_word & CW_Overflow )
550 {
551
552
553
554
555 EXCEPTION(EX_Precision | SW_C1);
556 return !(control_word & CW_Precision);
557 }
558
559 return 0;
560
561 }
562
563
564 asmlinkage int arith_underflow(FPU_REG *dest)
565 {
566
567 if ( control_word & CW_Underflow )
568 {
569
570 if ( dest->exp <= EXP_UNDER - 63 )
571 {
572 reg_move(&CONST_Z, dest);
573 partial_status &= ~SW_C1;
574 }
575 }
576 else
577 {
578
579 dest->exp += (3 * (1 << 13));
580 }
581
582 EXCEPTION(EX_Underflow);
583 if ( control_word & CW_Underflow )
584 {
585
586 EXCEPTION(EX_Precision);
587 return !(control_word & CW_Precision);
588 }
589
590 return 0;
591
592 }
593
594
595 void stack_overflow(void)
596 {
597
598 if ( control_word & CW_Invalid )
599 {
600
601 top--;
602 reg_move(&CONST_QNaN, &st(0));
603 }
604
605 EXCEPTION(EX_StackOver);
606
607 return;
608
609 }
610
611
612 void stack_underflow(void)
613 {
614
615 if ( control_word & CW_Invalid )
616 {
617
618 reg_move(&CONST_QNaN, &st(0));
619 }
620
621 EXCEPTION(EX_StackUnder);
622
623 return;
624
625 }
626
627
628 void stack_underflow_i(int i)
629 {
630
631 if ( control_word & CW_Invalid )
632 {
633
634 reg_move(&CONST_QNaN, &(st(i)));
635 }
636
637 EXCEPTION(EX_StackUnder);
638
639 return;
640
641 }
642
643
644 void stack_underflow_pop(int i)
645 {
646
647 if ( control_word & CW_Invalid )
648 {
649
650 reg_move(&CONST_QNaN, &(st(i)));
651 pop();
652 }
653
654 EXCEPTION(EX_StackUnder);
655
656 return;
657
658 }
659