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