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