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