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/uaccess.h>
23
24#include "fpu_emu.h"
25#include "fpu_system.h"
26#include "exception.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#if 0
37void Un_impl(void)
38{
39 u_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 __user *)address);
45 if (FPU_CS == __USER_CS) {
46 while (1) {
47 FPU_get_user(byte1, (u_char __user *) address);
48 if ((byte1 & 0xf8) == 0xd8)
49 break;
50 printk("[%02x]", byte1);
51 address++;
52 }
53 printk("%02x ", byte1);
54 FPU_get_user(FPU_modrm, 1 + (u_char __user *) address);
55
56 if (FPU_modrm >= 0300)
57 printk("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8,
58 FPU_modrm & 7);
59 else
60 printk("/%d\n", (FPU_modrm >> 3) & 7);
61 } else {
62 printk("cs selector = %04x\n", FPU_CS);
63 }
64
65 RE_ENTRANT_CHECK_ON;
66
67 EXCEPTION(EX_Invalid);
68
69}
70#endif
71
72
73
74
75
76void FPU_illegal(void)
77{
78 math_abort(FPU_info, SIGILL);
79}
80
81void FPU_printall(void)
82{
83 int i;
84 static const char *tag_desc[] = { "Valid", "Zero", "ERROR", "Empty",
85 "DeNorm", "Inf", "NaN"
86 };
87 u_char byte1, FPU_modrm;
88 unsigned long address = FPU_ORIG_EIP;
89
90 RE_ENTRANT_CHECK_OFF;
91
92 printk("At %p:", (void *)address);
93 if (FPU_CS == __USER_CS) {
94#define MAX_PRINTED_BYTES 20
95 for (i = 0; i < MAX_PRINTED_BYTES; i++) {
96 FPU_get_user(byte1, (u_char __user *) address);
97 if ((byte1 & 0xf8) == 0xd8) {
98 printk(" %02x", byte1);
99 break;
100 }
101 printk(" [%02x]", byte1);
102 address++;
103 }
104 if (i == MAX_PRINTED_BYTES)
105 printk(" [more..]\n");
106 else {
107 FPU_get_user(FPU_modrm, 1 + (u_char __user *) address);
108
109 if (FPU_modrm >= 0300)
110 printk(" %02x (%02x+%d)\n", FPU_modrm,
111 FPU_modrm & 0xf8, FPU_modrm & 7);
112 else
113 printk(" /%d, mod=%d rm=%d\n",
114 (FPU_modrm >> 3) & 7,
115 (FPU_modrm >> 6) & 3, FPU_modrm & 7);
116 }
117 } else {
118 printk("%04x\n", FPU_CS);
119 }
120
121 partial_status = status_word();
122
123#ifdef DEBUGGING
124 if (partial_status & SW_Backward)
125 printk("SW: backward compatibility\n");
126 if (partial_status & SW_C3)
127 printk("SW: condition bit 3\n");
128 if (partial_status & SW_C2)
129 printk("SW: condition bit 2\n");
130 if (partial_status & SW_C1)
131 printk("SW: condition bit 1\n");
132 if (partial_status & SW_C0)
133 printk("SW: condition bit 0\n");
134 if (partial_status & SW_Summary)
135 printk("SW: exception summary\n");
136 if (partial_status & SW_Stack_Fault)
137 printk("SW: stack fault\n");
138 if (partial_status & SW_Precision)
139 printk("SW: loss of precision\n");
140 if (partial_status & SW_Underflow)
141 printk("SW: underflow\n");
142 if (partial_status & SW_Overflow)
143 printk("SW: overflow\n");
144 if (partial_status & SW_Zero_Div)
145 printk("SW: divide by zero\n");
146 if (partial_status & SW_Denorm_Op)
147 printk("SW: denormalized operand\n");
148 if (partial_status & SW_Invalid)
149 printk("SW: invalid operation\n");
150#endif
151
152 printk(" SW: b=%d st=%d es=%d sf=%d cc=%d%d%d%d ef=%d%d%d%d%d%d\n", partial_status & 0x8000 ? 1 : 0,
153 (partial_status & 0x3800) >> 11,
154 partial_status & 0x80 ? 1 : 0,
155 partial_status & 0x40 ? 1 : 0,
156 partial_status & SW_C3 ? 1 : 0, partial_status & SW_C2 ? 1 : 0,
157 partial_status & SW_C1 ? 1 : 0, partial_status & SW_C0 ? 1 : 0,
158 partial_status & SW_Precision ? 1 : 0,
159 partial_status & SW_Underflow ? 1 : 0,
160 partial_status & SW_Overflow ? 1 : 0,
161 partial_status & SW_Zero_Div ? 1 : 0,
162 partial_status & SW_Denorm_Op ? 1 : 0,
163 partial_status & SW_Invalid ? 1 : 0);
164
165 printk(" CW: ic=%d rc=%d%d pc=%d%d iem=%d ef=%d%d%d%d%d%d\n",
166 control_word & 0x1000 ? 1 : 0,
167 (control_word & 0x800) >> 11, (control_word & 0x400) >> 10,
168 (control_word & 0x200) >> 9, (control_word & 0x100) >> 8,
169 control_word & 0x80 ? 1 : 0,
170 control_word & SW_Precision ? 1 : 0,
171 control_word & SW_Underflow ? 1 : 0,
172 control_word & SW_Overflow ? 1 : 0,
173 control_word & SW_Zero_Div ? 1 : 0,
174 control_word & SW_Denorm_Op ? 1 : 0,
175 control_word & SW_Invalid ? 1 : 0);
176
177 for (i = 0; i < 8; i++) {
178 FPU_REG *r = &st(i);
179 u_char tagi = FPU_gettagi(i);
180 switch (tagi) {
181 case TAG_Empty:
182 continue;
183 break;
184 case TAG_Zero:
185 case TAG_Special:
186 tagi = FPU_Special(r);
187 case TAG_Valid:
188 printk("st(%d) %c .%04lx %04lx %04lx %04lx e%+-6d ", i,
189 getsign(r) ? '-' : '+',
190 (long)(r->sigh >> 16),
191 (long)(r->sigh & 0xFFFF),
192 (long)(r->sigl >> 16),
193 (long)(r->sigl & 0xFFFF),
194 exponent(r) - EXP_BIAS + 1);
195 break;
196 default:
197 printk("Whoops! Error in errors.c: tag%d is %d ", i,
198 tagi);
199 continue;
200 break;
201 }
202 printk("%s\n", tag_desc[(int)(unsigned)tagi]);
203 }
204
205 RE_ENTRANT_CHECK_ON;
206
207}
208
209static struct {
210 int type;
211 const char *name;
212} exception_names[] = {
213 {
214 EX_StackOver, "stack overflow"}, {
215 EX_StackUnder, "stack underflow"}, {
216 EX_Precision, "loss of precision"}, {
217 EX_Underflow, "underflow"}, {
218 EX_Overflow, "overflow"}, {
219 EX_ZeroDiv, "divide by zero"}, {
220 EX_Denormal, "denormalized operand"}, {
221 EX_Invalid, "invalid operation"}, {
222 EX_INTERNAL, "INTERNAL BUG in " FPU_VERSION}, {
223 0, NULL}
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
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305asmlinkage void FPU_exception(int n)
306{
307 int i, int_type;
308
309 int_type = 0;
310 if (n & EX_INTERNAL) {
311 int_type = n - EX_INTERNAL;
312 n = EX_INTERNAL;
313
314 partial_status |= (SW_Exc_Mask | SW_Summary | SW_Backward);
315 } else {
316
317 n &= (SW_Exc_Mask);
318
319 partial_status |= n;
320
321 if (partial_status & ~control_word & CW_Exceptions)
322 partial_status |= (SW_Summary | SW_Backward);
323 if (n & (SW_Stack_Fault | EX_Precision)) {
324 if (!(n & SW_C1))
325
326
327 partial_status &= ~SW_C1;
328 }
329 }
330
331 RE_ENTRANT_CHECK_OFF;
332 if ((~control_word & n & CW_Exceptions) || (n == EX_INTERNAL)) {
333#ifdef PRINT_MESSAGES
334
335 printk(FPU_VERSION " " __DATE__ " (C) W. Metzenthen.\n");
336#endif
337
338
339 for (i = 0; exception_names[i].type; i++)
340 if ((exception_names[i].type & n) ==
341 exception_names[i].type)
342 break;
343
344 if (exception_names[i].type) {
345#ifdef PRINT_MESSAGES
346 printk("FP Exception: %s!\n", exception_names[i].name);
347#endif
348 } else
349 printk("FPU emulator: Unknown Exception: 0x%04x!\n", n);
350
351 if (n == EX_INTERNAL) {
352 printk("FPU emulator: Internal error type 0x%04x\n",
353 int_type);
354 FPU_printall();
355 }
356#ifdef PRINT_MESSAGES
357 else
358 FPU_printall();
359#endif
360
361
362
363
364
365
366 }
367 RE_ENTRANT_CHECK_ON;
368
369#ifdef __DEBUG__
370 math_abort(FPU_info, SIGFPE);
371#endif
372
373}
374
375
376
377int real_1op_NaN(FPU_REG *a)
378{
379 int signalling, isNaN;
380
381 isNaN = (exponent(a) == EXP_OVER) && (a->sigh & 0x80000000);
382
383
384
385 signalling = isNaN && !(a->sigh & 0x40000000);
386
387 if (!signalling) {
388 if (!isNaN) {
389 if (control_word & CW_Invalid) {
390
391 reg_copy(&CONST_QNaN, a);
392 }
393 EXCEPTION(EX_Invalid);
394 return (!(control_word & CW_Invalid) ? FPU_Exception :
395 0) | TAG_Special;
396 }
397 return TAG_Special;
398 }
399
400 if (control_word & CW_Invalid) {
401
402 if (!(a->sigh & 0x80000000)) {
403 reg_copy(&CONST_QNaN, a);
404 }
405
406 a->sigh |= 0x40000000;
407 }
408
409 EXCEPTION(EX_Invalid);
410
411 return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Special;
412}
413
414
415
416int real_2op_NaN(FPU_REG const *b, u_char tagb,
417 int deststnr, FPU_REG const *defaultNaN)
418{
419 FPU_REG *dest = &st(deststnr);
420 FPU_REG const *a = dest;
421 u_char taga = FPU_gettagi(deststnr);
422 FPU_REG const *x;
423 int signalling, unsupported;
424
425 if (taga == TAG_Special)
426 taga = FPU_Special(a);
427 if (tagb == TAG_Special)
428 tagb = FPU_Special(b);
429
430
431 unsupported = ((taga == TW_NaN)
432 && !((exponent(a) == EXP_OVER)
433 && (a->sigh & 0x80000000)))
434 || ((tagb == TW_NaN)
435 && !((exponent(b) == EXP_OVER) && (b->sigh & 0x80000000)));
436 if (unsupported) {
437 if (control_word & CW_Invalid) {
438
439 FPU_copy_to_regi(&CONST_QNaN, TAG_Special, deststnr);
440 }
441 EXCEPTION(EX_Invalid);
442 return (!(control_word & CW_Invalid) ? FPU_Exception : 0) |
443 TAG_Special;
444 }
445
446 if (taga == TW_NaN) {
447 x = a;
448 if (tagb == TW_NaN) {
449 signalling = !(a->sigh & b->sigh & 0x40000000);
450 if (significand(b) > significand(a))
451 x = b;
452 else if (significand(b) == significand(a)) {
453
454
455 x = defaultNaN;
456 }
457 } else {
458
459 signalling = !(a->sigh & 0x40000000);
460 }
461 } else
462#ifdef PARANOID
463 if (tagb == TW_NaN)
464#endif
465 {
466 signalling = !(b->sigh & 0x40000000);
467 x = b;
468 }
469#ifdef PARANOID
470 else {
471 signalling = 0;
472 EXCEPTION(EX_INTERNAL | 0x113);
473 x = &CONST_QNaN;
474 }
475#endif
476
477 if ((!signalling) || (control_word & CW_Invalid)) {
478 if (!x)
479 x = b;
480
481 if (!(x->sigh & 0x80000000))
482 x = &CONST_QNaN;
483
484 FPU_copy_to_regi(x, TAG_Special, deststnr);
485
486 if (!signalling)
487 return TAG_Special;
488
489
490 dest->sigh |= 0x40000000;
491 }
492
493 EXCEPTION(EX_Invalid);
494
495 return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Special;
496}
497
498
499
500asmlinkage int arith_invalid(int deststnr)
501{
502
503 EXCEPTION(EX_Invalid);
504
505 if (control_word & CW_Invalid) {
506
507 FPU_copy_to_regi(&CONST_QNaN, TAG_Special, deststnr);
508 }
509
510 return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Valid;
511
512}
513
514
515asmlinkage int FPU_divide_by_zero(int deststnr, u_char sign)
516{
517 FPU_REG *dest = &st(deststnr);
518 int tag = TAG_Valid;
519
520 if (control_word & CW_ZeroDiv) {
521
522 FPU_copy_to_regi(&CONST_INF, TAG_Special, deststnr);
523 setsign(dest, sign);
524 tag = TAG_Special;
525 }
526
527 EXCEPTION(EX_ZeroDiv);
528
529 return (!(control_word & CW_ZeroDiv) ? FPU_Exception : 0) | tag;
530
531}
532
533
534int set_precision_flag(int flags)
535{
536 if (control_word & CW_Precision) {
537 partial_status &= ~(SW_C1 & flags);
538 partial_status |= flags;
539 return 0;
540 } else {
541 EXCEPTION(flags);
542 return 1;
543 }
544}
545
546
547asmlinkage void set_precision_flag_up(void)
548{
549 if (control_word & CW_Precision)
550 partial_status |= (SW_Precision | SW_C1);
551 else
552 EXCEPTION(EX_Precision | SW_C1);
553}
554
555
556asmlinkage void set_precision_flag_down(void)
557{
558 if (control_word & CW_Precision) {
559 partial_status &= ~SW_C1;
560 partial_status |= SW_Precision;
561 } else
562 EXCEPTION(EX_Precision);
563}
564
565asmlinkage int denormal_operand(void)
566{
567 if (control_word & CW_Denormal) {
568 partial_status |= SW_Denorm_Op;
569 return TAG_Special;
570 } else {
571 EXCEPTION(EX_Denormal);
572 return TAG_Special | FPU_Exception;
573 }
574}
575
576asmlinkage int arith_overflow(FPU_REG *dest)
577{
578 int tag = TAG_Valid;
579
580 if (control_word & CW_Overflow) {
581
582
583 reg_copy(&CONST_INF, dest);
584 tag = TAG_Special;
585 } else {
586
587 addexponent(dest, (-3 * (1 << 13)));
588 }
589
590 EXCEPTION(EX_Overflow);
591 if (control_word & CW_Overflow) {
592
593
594
595
596 EXCEPTION(EX_Precision | SW_C1);
597 return tag;
598 }
599
600 return tag;
601
602}
603
604asmlinkage int arith_underflow(FPU_REG *dest)
605{
606 int tag = TAG_Valid;
607
608 if (control_word & CW_Underflow) {
609
610 if (exponent16(dest) <= EXP_UNDER - 63) {
611 reg_copy(&CONST_Z, dest);
612 partial_status &= ~SW_C1;
613 tag = TAG_Zero;
614 } else {
615 stdexp(dest);
616 }
617 } else {
618
619 addexponent(dest, (3 * (1 << 13)) + EXTENDED_Ebias);
620 }
621
622 EXCEPTION(EX_Underflow);
623 if (control_word & CW_Underflow) {
624
625 EXCEPTION(EX_Precision);
626 return tag;
627 }
628
629 return tag;
630
631}
632
633void FPU_stack_overflow(void)
634{
635
636 if (control_word & CW_Invalid) {
637
638 top--;
639 FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
640 }
641
642 EXCEPTION(EX_StackOver);
643
644 return;
645
646}
647
648void FPU_stack_underflow(void)
649{
650
651 if (control_word & CW_Invalid) {
652
653 FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
654 }
655
656 EXCEPTION(EX_StackUnder);
657
658 return;
659
660}
661
662void FPU_stack_underflow_i(int i)
663{
664
665 if (control_word & CW_Invalid) {
666
667 FPU_copy_to_regi(&CONST_QNaN, TAG_Special, i);
668 }
669
670 EXCEPTION(EX_StackUnder);
671
672 return;
673
674}
675
676void FPU_stack_underflow_pop(int i)
677{
678
679 if (control_word & CW_Invalid) {
680
681 FPU_copy_to_regi(&CONST_QNaN, TAG_Special, i);
682 FPU_pop();
683 }
684
685 EXCEPTION(EX_StackUnder);
686
687 return;
688
689}
690