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