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