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