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 while ( 1 )
46 {
47 byte1 = get_fs_byte((unsigned char *) address);
48 if ( (byte1 & 0xf8) == 0xd8 ) break;
49 printk("[%02x]", byte1);
50 address++;
51 }
52 printk("%02x ", byte1);
53 FPU_modrm = get_fs_byte(1 + (unsigned char *) address);
54
55 if (FPU_modrm >= 0300)
56 printk("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7);
57 else
58 printk("/%d\n", (FPU_modrm >> 3) & 7);
59 RE_ENTRANT_CHECK_ON;
60
61 EXCEPTION(EX_Invalid);
62
63 }
64
65
66
67
68
69
70 void FPU_illegal(void)
71 {
72 math_abort(FPU_info,SIGILL);
73 }
74
75
76
77 void emu_printall()
78 {
79 int i;
80 static char *tag_desc[] = { "Valid", "Zero", "ERROR", "ERROR",
81 "DeNorm", "Inf", "NaN", "Empty" };
82 unsigned char byte1, FPU_modrm;
83 unsigned long address = FPU_ORIG_EIP;
84
85 RE_ENTRANT_CHECK_OFF;
86
87 printk("At %p:", (void *) address);
88 #define MAX_PRINTED_BYTES 20
89 for ( i = 0; i < MAX_PRINTED_BYTES; i++ )
90 {
91 byte1 = get_fs_byte((unsigned char *) address);
92 if ( (byte1 & 0xf8) == 0xd8 )
93 {
94 printk(" %02x", byte1);
95 break;
96 }
97 printk(" [%02x]", byte1);
98 address++;
99 }
100 if ( i == MAX_PRINTED_BYTES )
101 printk(" [more..]\n");
102 else
103 {
104 FPU_modrm = get_fs_byte(1 + (unsigned char *) address);
105
106 if (FPU_modrm >= 0300)
107 printk(" %02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7);
108 else
109 printk(" /%d, mod=%d rm=%d\n",
110 (FPU_modrm >> 3) & 7, (FPU_modrm >> 6) & 3, FPU_modrm & 7);
111 }
112
113 partial_status = status_word();
114
115 #ifdef DEBUGGING
116 if ( partial_status & SW_Backward ) printk("SW: backward compatibility\n");
117 if ( partial_status & SW_C3 ) printk("SW: condition bit 3\n");
118 if ( partial_status & SW_C2 ) printk("SW: condition bit 2\n");
119 if ( partial_status & SW_C1 ) printk("SW: condition bit 1\n");
120 if ( partial_status & SW_C0 ) printk("SW: condition bit 0\n");
121 if ( partial_status & SW_Summary ) printk("SW: exception summary\n");
122 if ( partial_status & SW_Stack_Fault ) printk("SW: stack fault\n");
123 if ( partial_status & SW_Precision ) printk("SW: loss of precision\n");
124 if ( partial_status & SW_Underflow ) printk("SW: underflow\n");
125 if ( partial_status & SW_Overflow ) printk("SW: overflow\n");
126 if ( partial_status & SW_Zero_Div ) printk("SW: divide by zero\n");
127 if ( partial_status & SW_Denorm_Op ) printk("SW: denormalized operand\n");
128 if ( partial_status & SW_Invalid ) printk("SW: invalid operation\n");
129 #endif DEBUGGING
130
131 printk(" SW: b=%d st=%ld es=%d sf=%d cc=%d%d%d%d ef=%d%d%d%d%d%d\n",
132 partial_status & 0x8000 ? 1 : 0,
133 (partial_status & 0x3800) >> 11,
134 partial_status & 0x80 ? 1 : 0,
135 partial_status & 0x40 ? 1 : 0,
136 partial_status & SW_C3?1:0, partial_status & SW_C2?1:0,
137 partial_status & SW_C1?1:0, partial_status & SW_C0?1:0,
138 partial_status & SW_Precision?1:0, partial_status & SW_Underflow?1:0,
139 partial_status & SW_Overflow?1:0, partial_status & SW_Zero_Div?1:0,
140 partial_status & SW_Denorm_Op?1:0, partial_status & SW_Invalid?1:0);
141
142 printk(" CW: ic=%d rc=%ld%ld pc=%ld%ld iem=%d ef=%d%d%d%d%d%d\n",
143 control_word & 0x1000 ? 1 : 0,
144 (control_word & 0x800) >> 11, (control_word & 0x400) >> 10,
145 (control_word & 0x200) >> 9, (control_word & 0x100) >> 8,
146 control_word & 0x80 ? 1 : 0,
147 control_word & SW_Precision?1:0, control_word & SW_Underflow?1:0,
148 control_word & SW_Overflow?1:0, control_word & SW_Zero_Div?1:0,
149 control_word & SW_Denorm_Op?1:0, control_word & SW_Invalid?1:0);
150
151 for ( i = 0; i < 8; i++ )
152 {
153 FPU_REG *r = &st(i);
154 switch (r->tag)
155 {
156 case TW_Empty:
157 continue;
158 break;
159 case TW_Zero:
160 #if 0
161 printk("st(%d) %c .0000 0000 0000 0000 ",
162 i, r->sign ? '-' : '+');
163 break;
164 #endif
165 case TW_Valid:
166 case TW_NaN:
167
168 case TW_Infinity:
169 printk("st(%d) %c .%04lx %04lx %04lx %04lx e%+-6ld ", i,
170 r->sign ? '-' : '+',
171 (long)(r->sigh >> 16),
172 (long)(r->sigh & 0xFFFF),
173 (long)(r->sigl >> 16),
174 (long)(r->sigl & 0xFFFF),
175 r->exp - EXP_BIAS + 1);
176 break;
177 default:
178 printk("Whoops! Error in errors.c ");
179 break;
180 }
181 printk("%s\n", tag_desc[(int) (unsigned) r->tag]);
182 }
183
184 printk("[data] %c .%04lx %04lx %04lx %04lx e%+-6ld ",
185 FPU_loaded_data.sign ? '-' : '+',
186 (long)(FPU_loaded_data.sigh >> 16),
187 (long)(FPU_loaded_data.sigh & 0xFFFF),
188 (long)(FPU_loaded_data.sigl >> 16),
189 (long)(FPU_loaded_data.sigl & 0xFFFF),
190 FPU_loaded_data.exp - EXP_BIAS + 1);
191 printk("%s\n", tag_desc[(int) (unsigned) FPU_loaded_data.tag]);
192 RE_ENTRANT_CHECK_ON;
193
194 }
195
196 static struct {
197 int type;
198 char *name;
199 } exception_names[] = {
200 { EX_StackOver, "stack overflow" },
201 { EX_StackUnder, "stack underflow" },
202 { EX_Precision, "loss of precision" },
203 { EX_Underflow, "underflow" },
204 { EX_Overflow, "overflow" },
205 { EX_ZeroDiv, "divide by zero" },
206 { EX_Denormal, "denormalized operand" },
207 { EX_Invalid, "invalid operation" },
208 { EX_INTERNAL, "INTERNAL BUG in "FPU_VERSION },
209 { 0, NULL }
210 };
211
212
213
214
215
216
217
218
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 void exception(int n)
276 {
277 int i, int_type;
278
279 int_type = 0;
280 if ( n & EX_INTERNAL )
281 {
282 int_type = n - EX_INTERNAL;
283 n = EX_INTERNAL;
284
285 partial_status |= (SW_Exc_Mask | SW_Summary | SW_Backward);
286 }
287 else
288 {
289
290 n &= (SW_Exc_Mask);
291
292 partial_status |= n;
293
294 if ( partial_status & ~control_word & CW_Exceptions )
295 partial_status |= (SW_Summary | SW_Backward);
296 if ( n & (SW_Stack_Fault | EX_Precision) )
297 {
298 if ( !(n & SW_C1) )
299
300
301 partial_status &= ~SW_C1;
302 }
303 }
304
305 RE_ENTRANT_CHECK_OFF;
306 if ( (~control_word & n & CW_Exceptions) || (n == EX_INTERNAL) )
307 {
308 #ifdef PRINT_MESSAGES
309
310 printk(FPU_VERSION" "__DATE__" (C) W. Metzenthen.\n");
311 #endif PRINT_MESSAGES
312
313
314 for (i=0; exception_names[i].type; i++)
315 if ( (exception_names[i].type & n) == exception_names[i].type )
316 break;
317
318 if (exception_names[i].type)
319 {
320 #ifdef PRINT_MESSAGES
321 printk("FP Exception: %s!\n", exception_names[i].name);
322 #endif PRINT_MESSAGES
323 }
324 else
325 printk("FPU emulator: Unknown Exception: 0x%04x!\n", n);
326
327 if ( n == EX_INTERNAL )
328 {
329 printk("FPU emulator: Internal error type 0x%04x\n", int_type);
330 emu_printall();
331 }
332 #ifdef PRINT_MESSAGES
333 else
334 emu_printall();
335 #endif PRINT_MESSAGES
336
337
338
339
340
341
342
343
344
345
346 }
347 RE_ENTRANT_CHECK_ON;
348
349 #ifdef __DEBUG__
350 math_abort(FPU_info,SIGFPE);
351 #endif __DEBUG__
352
353 }
354
355
356
357
358 asmlinkage int real_2op_NaN(FPU_REG const *a, FPU_REG const *b, FPU_REG *dest)
359 {
360 FPU_REG const *x;
361 int signalling;
362
363
364
365 x = a;
366 if (a->tag == TW_NaN)
367 {
368 if (b->tag == TW_NaN)
369 {
370 signalling = !(a->sigh & b->sigh & 0x40000000);
371
372 if ( significand(a) < significand(b) )
373 x = b;
374 }
375 else
376 {
377
378 signalling = !(a->sigh & 0x40000000);
379 }
380 }
381 else
382 #ifdef PARANOID
383 if (b->tag == TW_NaN)
384 #endif PARANOID
385 {
386 signalling = !(b->sigh & 0x40000000);
387 x = b;
388 }
389 #ifdef PARANOID
390 else
391 {
392 signalling = 0;
393 EXCEPTION(EX_INTERNAL|0x113);
394 x = &CONST_QNaN;
395 }
396 #endif PARANOID
397
398 if ( !signalling )
399 {
400 if ( !(x->sigh & 0x80000000) )
401 x = &CONST_QNaN;
402 reg_move(x, dest);
403 return 0;
404 }
405
406 if ( control_word & CW_Invalid )
407 {
408
409 if ( !(x->sigh & 0x80000000) )
410 x = &CONST_QNaN;
411 reg_move(x, dest);
412
413 dest->sigh |= 0x40000000;
414 }
415
416 EXCEPTION(EX_Invalid);
417
418 return !(control_word & CW_Invalid);
419 }
420
421
422
423
424 asmlinkage int arith_invalid(FPU_REG *dest)
425 {
426
427 EXCEPTION(EX_Invalid);
428
429 if ( control_word & CW_Invalid )
430 {
431
432 reg_move(&CONST_QNaN, dest);
433 }
434
435 return !(control_word & CW_Invalid);
436
437 }
438
439
440
441 asmlinkage int divide_by_zero(int sign, FPU_REG *dest)
442 {
443
444 if ( control_word & CW_ZeroDiv )
445 {
446
447 reg_move(&CONST_INF, dest);
448 dest->sign = (unsigned char)sign;
449 }
450
451 EXCEPTION(EX_ZeroDiv);
452
453 return !(control_word & CW_ZeroDiv);
454
455 }
456
457
458
459 int set_precision_flag(int flags)
460 {
461 if ( control_word & CW_Precision )
462 {
463 partial_status &= ~(SW_C1 & flags);
464 partial_status |= flags;
465 return 0;
466 }
467 else
468 {
469 exception(flags);
470 return 1;
471 }
472 }
473
474
475
476 asmlinkage void set_precision_flag_up(void)
477 {
478 if ( control_word & CW_Precision )
479 partial_status |= (SW_Precision | SW_C1);
480 else
481 exception(EX_Precision | SW_C1);
482
483 }
484
485
486
487 asmlinkage void set_precision_flag_down(void)
488 {
489 if ( control_word & CW_Precision )
490 {
491 partial_status &= ~SW_C1;
492 partial_status |= SW_Precision;
493 }
494 else
495 exception(EX_Precision);
496 }
497
498
499 asmlinkage int denormal_operand(void)
500 {
501 if ( control_word & CW_Denormal )
502 {
503 partial_status |= SW_Denorm_Op;
504 return 0;
505 }
506 else
507 {
508 exception(EX_Denormal);
509 return 1;
510 }
511 }
512
513
514 asmlinkage int arith_overflow(FPU_REG *dest)
515 {
516
517 if ( control_word & CW_Overflow )
518 {
519 char sign;
520
521
522 sign = dest->sign;
523 reg_move(&CONST_INF, dest);
524 dest->sign = sign;
525 }
526 else
527 {
528
529 dest->exp -= (3 * (1 << 13));
530 }
531
532 EXCEPTION(EX_Overflow);
533 if ( control_word & CW_Overflow )
534 {
535
536
537
538
539 EXCEPTION(EX_Precision | SW_C1);
540 return !(control_word & CW_Precision);
541 }
542
543 return !(control_word & CW_Overflow);
544
545 }
546
547
548 asmlinkage int arith_underflow(FPU_REG *dest)
549 {
550
551 if ( control_word & CW_Underflow )
552 {
553
554 if ( dest->exp <= EXP_UNDER - 63 )
555 {
556 reg_move(&CONST_Z, dest);
557 partial_status &= ~SW_C1;
558 }
559 }
560 else
561 {
562
563 dest->exp += (3 * (1 << 13));
564 }
565
566 EXCEPTION(EX_Underflow);
567 if ( control_word & CW_Underflow )
568 {
569
570 EXCEPTION(EX_Precision);
571 return !(control_word & CW_Precision);
572 }
573
574 return !(control_word & CW_Underflow);
575
576 }
577
578
579 void stack_overflow(void)
580 {
581
582 if ( control_word & CW_Invalid )
583 {
584
585 top--;
586 reg_move(&CONST_QNaN, FPU_st0_ptr = &st(0));
587 }
588
589 EXCEPTION(EX_StackOver);
590
591 return;
592
593 }
594
595
596 void stack_underflow(void)
597 {
598
599 if ( control_word & CW_Invalid )
600 {
601
602 reg_move(&CONST_QNaN, FPU_st0_ptr);
603 }
604
605 EXCEPTION(EX_StackUnder);
606
607 return;
608
609 }
610
611
612 void stack_underflow_i(int i)
613 {
614
615 if ( control_word & CW_Invalid )
616 {
617
618 reg_move(&CONST_QNaN, &(st(i)));
619 }
620
621 EXCEPTION(EX_StackUnder);
622
623 return;
624
625 }
626
627
628 void stack_underflow_pop(int i)
629 {
630
631 if ( control_word & CW_Invalid )
632 {
633
634 reg_move(&CONST_QNaN, &(st(i)));
635 pop();
636 }
637
638 EXCEPTION(EX_StackUnder);
639
640 return;
641
642 }
643