|
|
1.1 root 1: /*---------------------------------------------------------------------------+
2: | errors.c |
3: | |
4: | The error handling functions for wm-FPU-emu |
5: | |
6: | Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
7: | Australia. E-mail [email protected] |
8: | |
9: | |
10: +---------------------------------------------------------------------------*/
11:
12: /*---------------------------------------------------------------------------+
13: | Note: |
14: | The file contains code which accesses user memory. |
15: | Emulator static data may change when user memory is accessed, due to |
16: | other processes using the emulator while swapping is in progress. |
17: +---------------------------------------------------------------------------*/
18:
19: #include <linux/signal.h>
20:
21: #include <asm/segment.h>
22:
23: #include "fpu_system.h"
24: #include "exception.h"
25: #include "fpu_emu.h"
26: #include "status_w.h"
27: #include "control_w.h"
28: #include "reg_constant.h"
29: #include "version.h"
30:
31: /* */
32: #undef PRINT_MESSAGES
33: /* */
34:
35: void Un_impl(void)
36: {
37: unsigned char byte1, FPU_modrm;
38:
39: RE_ENTRANT_CHECK_OFF
40: byte1 = get_fs_byte((unsigned char *) FPU_ORIG_EIP);
41: FPU_modrm = get_fs_byte(1 + (unsigned char *) FPU_ORIG_EIP);
42:
43: printf("Unimplemented FPU Opcode at eip=%p : %02x ",
44: FPU_ORIG_EIP, byte1);
45:
46: if (FPU_modrm >= 0300)
47: printf("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7);
48: else
49: printf("/%d\n", (FPU_modrm >> 3) & 7);
50: RE_ENTRANT_CHECK_ON
51:
52: EXCEPTION(EX_Invalid);
53:
54: }
55:
56:
57:
58:
59: void emu_printall()
60: {
61: int i;
62: static char *tag_desc[] = { "Valid", "Zero", "ERROR", "ERROR",
63: "DeNorm", "Inf", "NaN", "Empty" };
64: unsigned char byte1, FPU_modrm;
65:
66: RE_ENTRANT_CHECK_OFF
67: byte1 = get_fs_byte((unsigned char *) FPU_ORIG_EIP);
68: FPU_modrm = get_fs_byte(1 + (unsigned char *) FPU_ORIG_EIP);
69:
70: #ifdef DEBUGGING
71: if ( status_word & SW_B ) printf("SW: backward compatibility (=ES)\n");
72: if ( status_word & SW_C3 ) printf("SW: condition bit 3\n");
73: if ( status_word & SW_C2 ) printf("SW: condition bit 2\n");
74: if ( status_word & SW_C1 ) printf("SW: condition bit 1\n");
75: if ( status_word & SW_C0 ) printf("SW: condition bit 0\n");
76: if ( status_word & SW_ES ) printf("SW: exception summary\n");
77: if ( status_word & SW_SF ) printf("SW: stack fault\n");
78: if ( status_word & SW_PE ) printf("SW: loss of precision\n");
79: if ( status_word & SW_UE ) printf("SW: underflow\n");
80: if ( status_word & SW_OE ) printf("SW: overflow\n");
81: if ( status_word & SW_ZE ) printf("SW: divide by zero\n");
82: if ( status_word & SW_DE ) printf("SW: denormalized operand\n");
83: if ( status_word & SW_IE ) printf("SW: invalid operation\n");
84: #endif DEBUGGING
85:
86: status_word = status_word & ~SW_TOP;
87: status_word |= (top&7) << SW_TOPS;
88:
89: printf("At %p: %02x ", FPU_ORIG_EIP, byte1);
90: if (FPU_modrm >= 0300)
91: printf("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7);
92: else
93: printf("/%d, mod=%d rm=%d\n",
94: (FPU_modrm >> 3) & 7, (FPU_modrm >> 6) & 3, FPU_modrm & 7);
95:
96: printf(" SW: b=%d st=%d es=%d sf=%d cc=%d%d%d%d ef=%d%d%d%d%d%d\n",
97: status_word & 0x8000 ? 1 : 0, /* busy */
98: (status_word & 0x3800) >> 11, /* stack top pointer */
99: status_word & 0x80 ? 1 : 0, /* Error summary status */
100: status_word & 0x40 ? 1 : 0, /* Stack flag */
101: status_word & SW_C3?1:0, status_word & SW_C2?1:0, /* cc */
102: status_word & SW_C1?1:0, status_word & SW_C0?1:0, /* cc */
103: status_word & SW_PE?1:0, status_word & SW_UE?1:0, /* exception fl */
104: status_word & SW_OE?1:0, status_word & SW_ZE?1:0, /* exception fl */
105: status_word & SW_DE?1:0, status_word & SW_IE?1:0); /* exception fl */
106:
107: printf(" CW: ic=%d rc=%d%d pc=%d%d 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_PE?1:0, control_word & SW_UE?1:0, /* exception */
113: control_word & SW_OE?1:0, control_word & SW_ZE?1:0, /* exception */
114: control_word & SW_DE?1:0, control_word & SW_IE?1:0); /* exception */
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: printf("st(%d) %c .0000 0000 0000 0000 ",
126: i, r->sign ? '-' : '+');
127: break;
128: case TW_Valid:
129: case TW_NaN:
130: case TW_Denormal:
131: case TW_Infinity:
132: printf("st(%d) %c .%04x %04x %04x %04x e%+-6d ", i,
133: r->sign ? '-' : '+',
134: (long)(r->sigh >> 16),
135: (long)(r->sigh & 0xFFFF),
136: (long)(r->sigl >> 16),
137: (long)(r->sigl & 0xFFFF),
138: r->exp - EXP_BIAS + 1);
139: break;
140: default:
141: printf("Whoops! Error in errors.c ");
142: break;
143: }
144: printf("%s\n", tag_desc[(int) (unsigned) r->tag]);
145: }
146:
147: printf("[data] %c .%04x %04x %04x %04x e%+-6d ",
148: FPU_loaded_data.sign ? '-' : '+',
149: (long)(FPU_loaded_data.sigh >> 16),
150: (long)(FPU_loaded_data.sigh & 0xFFFF),
151: (long)(FPU_loaded_data.sigl >> 16),
152: (long)(FPU_loaded_data.sigl & 0xFFFF),
153: FPU_loaded_data.exp - EXP_BIAS + 1);
154: printf("%s\n", tag_desc[(int) (unsigned) FPU_loaded_data.tag]);
155: RE_ENTRANT_CHECK_ON
156:
157: }
158:
159: static struct {
160: int type;
161: char *name;
162: } exception_names[] = {
163: { EX_StackOver, "stack overflow" },
164: { EX_StackUnder, "stack underflow" },
165: { EX_Precision, "loss of precision" },
166: { EX_Underflow, "underflow" },
167: { EX_Overflow, "overflow" },
168: { EX_ZeroDiv, "divide by zero" },
169: { EX_Denormal, "denormalized operand" },
170: { EX_Invalid, "invalid operation" },
171: { EX_INTERNAL, "INTERNAL BUG in "FPU_VERSION },
172: { 0, NULL }
173: };
174:
175: /*
176: EX_INTERNAL is always given with a code which indicates where the
177: error was detected.
178:
179: Internal error types:
180: 0x14 in e14.c
181: 0x1nn in a *.c file:
182: 0x101 in reg_add_sub.c
183: 0x102 in reg_mul.c
184: 0x103 in poly_sin.c
185: 0x104 in poly_tan.c
186: 0x105 in reg_mul.c
187: 0x106 in reg_mov.c
188: 0x107 in fpu_trig.c
189: 0x108 in reg_compare.c
190: 0x109 in reg_compare.c
191: 0x110 in reg_add_sub.c
192: 0x111 in interface.c
193: 0x112 in fpu_trig.c
194: 0x113 in reg_add_sub.c
195: 0x114 in reg_ld_str.c
196: 0x115 in fpu_trig.c
197: 0x116 in fpu_trig.c
198: 0x117 in fpu_trig.c
199: 0x118 in fpu_trig.c
200: 0x119 in fpu_trig.c
201: 0x120 in poly_atan.c
202: 0x121 in reg_compare.c
203: 0x122 in reg_compare.c
204: 0x123 in reg_compare.c
205: 0x2nn in an *.s file:
206: 0x201 in reg_u_add.S
207: 0x202 in reg_u_div.S
208: 0x203 in reg_u_div.S
209: 0x204 in reg_u_div.S
210: 0x205 in reg_u_mul.S
211: 0x206 in reg_u_sub.S
212: 0x207 in wm_sqrt.S
213: 0x208 in reg_div.S
214: 0x209 in reg_u_sub.S
215: 0x210 in reg_u_sub.S
216: 0x211 in reg_u_sub.S
217: 0x212 in reg_u_sub.S
218: */
219:
220: void exception(int n)
221: {
222: int i, int_type;
223:
224: int_type = 0;
225: if ( n & EX_INTERNAL )
226: {
227: int_type = n - EX_INTERNAL;
228: n = EX_INTERNAL;
229: /* Set lots of exception bits! */
230: status_word |= (0x3f | EX_ErrorSummary | FPU_BUSY);
231: }
232: else
233: {
234: /* Set the corresponding exception bit */
235: status_word |= (n | EX_ErrorSummary | FPU_BUSY);
236: if (n == EX_StackUnder) /* Stack underflow */
237: /* This bit distinguishes over- from underflow */
238: status_word &= ~SW_C1;
239: }
240:
241: RE_ENTRANT_CHECK_OFF
242: if ( (~control_word & n & CW_EXM) || (n == EX_INTERNAL) )
243: {
244: #ifdef PRINT_MESSAGES
245: /* My message from the sponsor */
246: printf(FPU_VERSION" "__DATE__" (C) W. Metzenthen.\r\n");
247: #endif PRINT_MESSAGES
248:
249: /* Get a name string for error reporting */
250: for (i=0; exception_names[i].type; i++)
251: if (exception_names[i].type == n)
252: break;
253:
254: if (exception_names[i].type)
255: {
256: #ifdef PRINT_MESSAGES
257: printf("FP Exception: %s!\n", exception_names[i].name);
258: #endif PRINT_MESSAGES
259: }
260: else
261: printf("FP emulator: Unknown Exception: 0x%04x!\n", n);
262:
263: if ( n == EX_INTERNAL )
264: {
265: printf("FP emulator: Internal error type 0x%04x\n", int_type);
266: emu_printall();
267: }
268: #ifdef PRINT_MESSAGES
269: else
270: emu_printall();
271: #endif PRINT_MESSAGES
272: emSendsig(SIGFPE, emCurrent, 1);
273: }
274: RE_ENTRANT_CHECK_ON
275:
276: #ifdef __DEBUG__
277: math_abort(FPU_info,SIGFPE);
278: #endif __DEBUG__
279:
280: /* Cause the look-ahead mechanism to terminate */
281: FPU_lookahead = 0;
282: }
283:
284:
285: /* Real operation attempted on two operands, one a NaN */
286: void real_2op_NaN(FPU_REG *a, FPU_REG *b, FPU_REG *dest)
287: {
288: FPU_REG *x;
289:
290: x = a;
291: if (a->tag == TW_NaN)
292: {
293: if (b->tag == TW_NaN)
294: {
295: /* find the "larger" */
296: if ( *(long long *)&(a->sigl) < *(long long *)&(b->sigl) )
297: x = b;
298: }
299: /* else return the quiet version of the NaN in a */
300: }
301: else if (b->tag == TW_NaN)
302: {
303: x = b;
304: }
305: #ifdef PARANOID
306: else
307: {
308: EXCEPTION(EX_INTERNAL|0x113);
309: x = &CONST_QNaN;
310: }
311: #endif PARANOID
312:
313: if ( control_word & EX_Invalid )
314: {
315: /* The masked response */
316: reg_move(x, dest);
317: /* ensure a Quiet NaN */
318: dest->sigh |= 0x40000000;
319: }
320:
321: EXCEPTION(EX_Invalid);
322:
323: return;
324: }
325:
326: /* Invalid arith operation on valid registers */
327: void arith_invalid(FPU_REG *dest)
328: {
329:
330: if ( control_word & EX_Invalid )
331: {
332: /* The masked response */
333: reg_move(&CONST_QNaN, dest);
334: }
335:
336: EXCEPTION(EX_Invalid);
337:
338: return;
339:
340: }
341:
342:
343: /* Divide a finite number by zero */
344: void divide_by_zero(int sign, FPU_REG *dest)
345: {
346:
347: if ( control_word & EX_ZeroDiv )
348: {
349: /* The masked response */
350: reg_move(&CONST_INF, dest);
351: dest->sign = (unsigned char)sign;
352: }
353:
354: EXCEPTION(EX_ZeroDiv);
355:
356: return;
357:
358: }
359:
360:
361: void arith_overflow(FPU_REG *dest)
362: {
363:
364: if ( control_word & EX_Overflow )
365: {
366: char sign;
367: /* The masked response */
368: sign = dest->sign;
369: reg_move(&CONST_INF, dest);
370: dest->sign = sign;
371: }
372: else
373: {
374: /* Subtract the magic number from the exponent */
375: dest->exp -= (3 * (1 << 13));
376: }
377:
378: EXCEPTION(EX_Overflow);
379:
380: return;
381:
382: }
383:
384:
385: void arith_underflow(FPU_REG *dest)
386: {
387:
388: if ( control_word & EX_Underflow )
389: {
390: /* The masked response */
391: if ( dest->exp <= EXP_UNDER - 63 )
392: reg_move(&CONST_Z, dest);
393: }
394: else
395: {
396: /* Add the magic number to the exponent */
397: dest->exp += (3 * (1 << 13));
398: }
399:
400: EXCEPTION(EX_Underflow);
401:
402: return;
403: }
404:
405:
406: void stack_overflow(void)
407: {
408:
409: if ( control_word & EX_Invalid )
410: {
411: /* The masked response */
412: top--;
413: reg_move(&CONST_QNaN, FPU_st0_ptr = &st(0));
414: }
415:
416: EXCEPTION(EX_StackOver);
417:
418: return;
419:
420: }
421:
422:
423: void stack_underflow(void)
424: {
425:
426: if ( control_word & EX_Invalid )
427: {
428: /* The masked response */
429: reg_move(&CONST_QNaN, FPU_st0_ptr);
430: }
431:
432: EXCEPTION(EX_StackUnder);
433:
434: return;
435:
436: }
437:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.