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