This source file includes following definitions.
- Un_impl
- emu_printall
- exception
- real_2op_NaN
- arith_invalid
- divide_by_zero
- 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 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
72 #ifdef DEBUGGING
73 if ( status_word & SW_Backward ) printk("SW: backward compatibility\n");
74 if ( status_word & SW_C3 ) printk("SW: condition bit 3\n");
75 if ( status_word & SW_C2 ) printk("SW: condition bit 2\n");
76 if ( status_word & SW_C1 ) printk("SW: condition bit 1\n");
77 if ( status_word & SW_C0 ) printk("SW: condition bit 0\n");
78 if ( status_word & SW_Summary ) printk("SW: exception summary\n");
79 if ( status_word & SW_Stack_Fault ) printk("SW: stack fault\n");
80 if ( status_word & SW_Precision ) printk("SW: loss of precision\n");
81 if ( status_word & SW_Underflow ) printk("SW: underflow\n");
82 if ( status_word & SW_Overflow ) printk("SW: overflow\n");
83 if ( status_word & SW_Zero_Div ) printk("SW: divide by zero\n");
84 if ( status_word & SW_Denorm_Op ) printk("SW: denormalized operand\n");
85 if ( status_word & SW_Invalid ) printk("SW: invalid operation\n");
86 #endif DEBUGGING
87
88 status_word = status_word & ~SW_Top;
89 status_word |= (top&7) << SW_Top_Shift;
90
91 printk("At %p: %02x ", 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=%d es=%d sf=%d cc=%d%d%d%d ef=%d%d%d%d%d%d\n",
99 status_word & 0x8000 ? 1 : 0,
100 (status_word & 0x3800) >> 11,
101 status_word & 0x80 ? 1 : 0,
102 status_word & 0x40 ? 1 : 0,
103 status_word & SW_C3?1:0, status_word & SW_C2?1:0,
104 status_word & SW_C1?1:0, status_word & SW_C0?1:0,
105 status_word & SW_Precision?1:0, status_word & SW_Underflow?1:0,
106 status_word & SW_Overflow?1:0, status_word & SW_Zero_Div?1:0,
107 status_word & SW_Denorm_Op?1:0, status_word & SW_Invalid?1:0);
108
109 printk(" CW: ic=%d rc=%d%d pc=%d%d 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 printk("st(%d) %c .0000 0000 0000 0000 ",
128 i, r->sign ? '-' : '+');
129 break;
130 case TW_Valid:
131 case TW_NaN:
132 case TW_Denormal:
133 case TW_Infinity:
134 printk("st(%d) %c .%04x %04x %04x %04x e%+-6d ", 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 .%04x %04x %04x %04x e%+-6d ",
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 void exception(int n)
229 {
230 int i, int_type;
231
232 int_type = 0;
233 if ( n & EX_INTERNAL )
234 {
235 int_type = n - EX_INTERNAL;
236 n = EX_INTERNAL;
237
238 status_word |= (SW_Exc_Mask | SW_Summary | FPU_BUSY);
239 }
240 else
241 {
242
243 n &= (SW_Exc_Mask);
244
245 status_word |= n;
246 if ( status_word & ~control_word & CW_Exceptions )
247 status_word |= SW_Summary;
248 if ( n & (SW_Stack_Fault | EX_Precision) )
249 {
250 if ( !(n & SW_C1) )
251
252
253 status_word &= ~SW_C1;
254 }
255 }
256
257 RE_ENTRANT_CHECK_OFF
258 if ( (~control_word & n & CW_Exceptions) || (n == EX_INTERNAL) )
259 {
260 #ifdef PRINT_MESSAGES
261
262 printk(FPU_VERSION" "__DATE__" (C) W. Metzenthen.\n");
263 #endif PRINT_MESSAGES
264
265
266 for (i=0; exception_names[i].type; i++)
267 if ( (exception_names[i].type & n) == exception_names[i].type )
268 break;
269
270 if (exception_names[i].type)
271 {
272 #ifdef PRINT_MESSAGES
273 printk("FP Exception: %s!\n", exception_names[i].name);
274 #endif PRINT_MESSAGES
275 }
276 else
277 printk("FP emulator: Unknown Exception: 0x%04x!\n", n);
278
279 if ( n == EX_INTERNAL )
280 {
281 printk("FP emulator: Internal error type 0x%04x\n", int_type);
282 emu_printall();
283 }
284 #ifdef PRINT_MESSAGES
285 else
286 emu_printall();
287 #endif PRINT_MESSAGES
288
289
290
291
292
293
294
295
296
297
298 }
299 RE_ENTRANT_CHECK_ON
300
301 #ifdef __DEBUG__
302 math_abort(FPU_info,SIGFPE);
303 #endif __DEBUG__
304
305 }
306
307
308
309 void real_2op_NaN(FPU_REG *a, FPU_REG *b, FPU_REG *dest)
310 {
311 FPU_REG *x;
312 int signalling;
313
314 x = a;
315 if (a->tag == TW_NaN)
316 {
317 if (b->tag == TW_NaN)
318 {
319 signalling = !(a->sigh & b->sigh & 0x40000000);
320
321 if ( *(long long *)&(a->sigl) < *(long long *)&(b->sigl) )
322 x = b;
323 }
324 else
325 {
326
327 signalling = !(a->sigh & 0x40000000);
328 }
329 }
330 else
331 #ifdef PARANOID
332 if (b->tag == TW_NaN)
333 #endif PARANOID
334 {
335 signalling = !(b->sigh & 0x40000000);
336 x = b;
337 }
338 #ifdef PARANOID
339 else
340 {
341 signalling = 0;
342 EXCEPTION(EX_INTERNAL|0x113);
343 x = &CONST_QNaN;
344 }
345 #endif PARANOID
346
347 if ( !signalling )
348 {
349 if ( !(x->sigh & 0x80000000) )
350 x = &CONST_QNaN;
351 reg_move(x, dest);
352 return;
353 }
354
355 if ( control_word & CW_Invalid )
356 {
357
358 if ( !(x->sigh & 0x80000000) )
359 x = &CONST_QNaN;
360 reg_move(x, dest);
361
362 dest->sigh |= 0x40000000;
363 }
364
365 EXCEPTION(EX_Invalid);
366
367 return;
368 }
369
370
371 void arith_invalid(FPU_REG *dest)
372 {
373
374 if ( control_word & CW_Invalid )
375 {
376
377 reg_move(&CONST_QNaN, dest);
378 }
379
380 EXCEPTION(EX_Invalid);
381
382 return;
383
384 }
385
386
387
388 void divide_by_zero(int sign, FPU_REG *dest)
389 {
390
391 if ( control_word & CW_ZeroDiv )
392 {
393
394 reg_move(&CONST_INF, dest);
395 dest->sign = (unsigned char)sign;
396 }
397
398 EXCEPTION(EX_ZeroDiv);
399
400 return;
401
402 }
403
404
405
406 void set_precision_flag_up(void)
407 {
408 if ( control_word & CW_Precision )
409 status_word |= (SW_Precision | SW_C1);
410 else
411 exception(EX_Precision | SW_C1);
412
413 }
414
415
416
417 void set_precision_flag_down(void)
418 {
419 if ( control_word & CW_Precision )
420 {
421 status_word &= ~SW_C1;
422 status_word |= SW_Precision;
423 }
424 else
425 exception(EX_Precision);
426 }
427
428
429 int denormal_operand(void)
430 {
431 if ( control_word & CW_Denormal )
432 {
433 status_word |= SW_Denorm_Op;
434 return 0;
435 }
436 else
437 {
438 exception(EX_Denormal);
439 return 1;
440 }
441 }
442
443
444 void arith_overflow(FPU_REG *dest)
445 {
446
447 if ( control_word & CW_Overflow )
448 {
449 char sign;
450
451
452 sign = dest->sign;
453 reg_move(&CONST_INF, dest);
454 dest->sign = sign;
455 }
456 else
457 {
458
459 dest->exp -= (3 * (1 << 13));
460 }
461
462
463
464 EXCEPTION(EX_Overflow | EX_Precision | SW_C1);
465
466 return;
467
468 }
469
470
471 void arith_underflow(FPU_REG *dest)
472 {
473
474 if ( control_word & CW_Underflow )
475 {
476
477 if ( dest->exp <= EXP_UNDER - 63 )
478 reg_move(&CONST_Z, dest);
479 }
480 else
481 {
482
483 dest->exp += (3 * (1 << 13));
484 }
485
486 EXCEPTION(EX_Underflow);
487
488 return;
489 }
490
491
492 void stack_overflow(void)
493 {
494
495 if ( control_word & CW_Invalid )
496 {
497
498 top--;
499 reg_move(&CONST_QNaN, FPU_st0_ptr = &st(0));
500 }
501
502 EXCEPTION(EX_StackOver);
503
504 return;
505
506 }
507
508
509 void stack_underflow(void)
510 {
511
512 if ( control_word & CW_Invalid )
513 {
514
515 reg_move(&CONST_QNaN, FPU_st0_ptr);
516 }
517
518 EXCEPTION(EX_StackUnder);
519
520 return;
521
522 }
523
524
525 void stack_underflow_i(int i)
526 {
527
528 if ( control_word & CW_Invalid )
529 {
530
531 reg_move(&CONST_QNaN, &(st(i)));
532 }
533
534 EXCEPTION(EX_StackUnder);
535
536 return;
537
538 }
539
540
541 void stack_underflow_pop(int i)
542 {
543
544 if ( control_word & CW_Invalid )
545 {
546
547 reg_move(&CONST_QNaN, &(st(i)));
548 pop();
549 }
550
551 EXCEPTION(EX_StackUnder);
552
553 return;
554
555 }
556