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