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