aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/math-emu/errors.c888
-rw-r--r--arch/x86/math-emu/exception.h9
-rw-r--r--arch/x86/math-emu/fpu_arith.c150
-rw-r--r--arch/x86/math-emu/fpu_asm.h1
-rw-r--r--arch/x86/math-emu/fpu_aux.c211
-rw-r--r--arch/x86/math-emu/fpu_emu.h77
-rw-r--r--arch/x86/math-emu/fpu_entry.c1220
-rw-r--r--arch/x86/math-emu/fpu_etc.c193
-rw-r--r--arch/x86/math-emu/fpu_proto.h80
-rw-r--r--arch/x86/math-emu/fpu_tags.c94
-rw-r--r--arch/x86/math-emu/fpu_trig.c2922
-rw-r--r--arch/x86/math-emu/get_address.c650
-rw-r--r--arch/x86/math-emu/load_store.c448
-rw-r--r--arch/x86/math-emu/poly.h79
-rw-r--r--arch/x86/math-emu/poly_2xm1.c199
-rw-r--r--arch/x86/math-emu/poly_atan.c353
-rw-r--r--arch/x86/math-emu/poly_l2.c378
-rw-r--r--arch/x86/math-emu/poly_sin.c599
-rw-r--r--arch/x86/math-emu/poly_tan.c338
-rw-r--r--arch/x86/math-emu/reg_add_sub.c563
-rw-r--r--arch/x86/math-emu/reg_compare.c567
-rw-r--r--arch/x86/math-emu/reg_constant.c73
-rw-r--r--arch/x86/math-emu/reg_convert.c59
-rw-r--r--arch/x86/math-emu/reg_divide.c301
-rw-r--r--arch/x86/math-emu/reg_ld_str.c2187
-rw-r--r--arch/x86/math-emu/reg_mul.c163
-rw-r--r--arch/x86/math-emu/status_w.h8
27 files changed, 6046 insertions, 6764 deletions
diff --git a/arch/x86/math-emu/errors.c b/arch/x86/math-emu/errors.c
index a1b0d22f6978..7cb5bf3495b2 100644
--- a/arch/x86/math-emu/errors.c
+++ b/arch/x86/math-emu/errors.c
@@ -33,45 +33,41 @@
33#undef PRINT_MESSAGES 33#undef PRINT_MESSAGES
34/* */ 34/* */
35 35
36
37#if 0 36#if 0
38void Un_impl(void) 37void Un_impl(void)
39{ 38{
40 u_char byte1, FPU_modrm; 39 u_char byte1, FPU_modrm;
41 unsigned long address = FPU_ORIG_EIP; 40 unsigned long address = FPU_ORIG_EIP;
42 41
43 RE_ENTRANT_CHECK_OFF; 42 RE_ENTRANT_CHECK_OFF;
44 /* No need to check access_ok(), we have previously fetched these bytes. */ 43 /* No need to check access_ok(), we have previously fetched these bytes. */
45 printk("Unimplemented FPU Opcode at eip=%p : ", (void __user *) address); 44 printk("Unimplemented FPU Opcode at eip=%p : ", (void __user *)address);
46 if ( FPU_CS == __USER_CS ) 45 if (FPU_CS == __USER_CS) {
47 { 46 while (1) {
48 while ( 1 ) 47 FPU_get_user(byte1, (u_char __user *) address);
49 { 48 if ((byte1 & 0xf8) == 0xd8)
50 FPU_get_user(byte1, (u_char __user *) address); 49 break;
51 if ( (byte1 & 0xf8) == 0xd8 ) break; 50 printk("[%02x]", byte1);
52 printk("[%02x]", byte1); 51 address++;
53 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);
54 } 63 }
55 printk("%02x ", byte1);
56 FPU_get_user(FPU_modrm, 1 + (u_char __user *) address);
57
58 if (FPU_modrm >= 0300)
59 printk("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7);
60 else
61 printk("/%d\n", (FPU_modrm >> 3) & 7);
62 }
63 else
64 {
65 printk("cs selector = %04x\n", FPU_CS);
66 }
67
68 RE_ENTRANT_CHECK_ON;
69
70 EXCEPTION(EX_Invalid);
71 64
72} 65 RE_ENTRANT_CHECK_ON;
73#endif /* 0 */
74 66
67 EXCEPTION(EX_Invalid);
68
69}
70#endif /* 0 */
75 71
76/* 72/*
77 Called for opcodes which are illegal and which are known to result in a 73 Called for opcodes which are illegal and which are known to result in a
@@ -79,139 +75,152 @@ void Un_impl(void)
79 */ 75 */
80void FPU_illegal(void) 76void FPU_illegal(void)
81{ 77{
82 math_abort(FPU_info,SIGILL); 78 math_abort(FPU_info, SIGILL);
83} 79}
84 80
85
86
87void FPU_printall(void) 81void FPU_printall(void)
88{ 82{
89 int i; 83 int i;
90 static const char *tag_desc[] = { "Valid", "Zero", "ERROR", "Empty", 84 static const char *tag_desc[] = { "Valid", "Zero", "ERROR", "Empty",
91 "DeNorm", "Inf", "NaN" }; 85 "DeNorm", "Inf", "NaN"
92 u_char byte1, FPU_modrm; 86 };
93 unsigned long address = FPU_ORIG_EIP; 87 u_char byte1, FPU_modrm;
94 88 unsigned long address = FPU_ORIG_EIP;
95 RE_ENTRANT_CHECK_OFF; 89
96 /* No need to check access_ok(), we have previously fetched these bytes. */ 90 RE_ENTRANT_CHECK_OFF;
97 printk("At %p:", (void *) address); 91 /* No need to check access_ok(), we have previously fetched these bytes. */
98 if ( FPU_CS == __USER_CS ) 92 printk("At %p:", (void *)address);
99 { 93 if (FPU_CS == __USER_CS) {
100#define MAX_PRINTED_BYTES 20 94#define MAX_PRINTED_BYTES 20
101 for ( i = 0; i < MAX_PRINTED_BYTES; i++ ) 95 for (i = 0; i < MAX_PRINTED_BYTES; i++) {
102 { 96 FPU_get_user(byte1, (u_char __user *) address);
103 FPU_get_user(byte1, (u_char __user *) address); 97 if ((byte1 & 0xf8) == 0xd8) {
104 if ( (byte1 & 0xf8) == 0xd8 ) 98 printk(" %02x", byte1);
105 { 99 break;
106 printk(" %02x", byte1); 100 }
107 break; 101 printk(" [%02x]", byte1);
108 } 102 address++;
109 printk(" [%02x]", byte1); 103 }
110 address++; 104 if (i == MAX_PRINTED_BYTES)
111 } 105 printk(" [more..]\n");
112 if ( i == MAX_PRINTED_BYTES ) 106 else {
113 printk(" [more..]\n"); 107 FPU_get_user(FPU_modrm, 1 + (u_char __user *) address);
114 else 108
115 { 109 if (FPU_modrm >= 0300)
116 FPU_get_user(FPU_modrm, 1 + (u_char __user *) address); 110 printk(" %02x (%02x+%d)\n", FPU_modrm,
117 111 FPU_modrm & 0xf8, FPU_modrm & 7);
118 if (FPU_modrm >= 0300) 112 else
119 printk(" %02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7); 113 printk(" /%d, mod=%d rm=%d\n",
120 else 114 (FPU_modrm >> 3) & 7,
121 printk(" /%d, mod=%d rm=%d\n", 115 (FPU_modrm >> 6) & 3, FPU_modrm & 7);
122 (FPU_modrm >> 3) & 7, (FPU_modrm >> 6) & 3, FPU_modrm & 7); 116 }
117 } else {
118 printk("%04x\n", FPU_CS);
123 } 119 }
124 }
125 else
126 {
127 printk("%04x\n", FPU_CS);
128 }
129 120
130 partial_status = status_word(); 121 partial_status = status_word();
131 122
132#ifdef DEBUGGING 123#ifdef DEBUGGING
133if ( partial_status & SW_Backward ) printk("SW: backward compatibility\n"); 124 if (partial_status & SW_Backward)
134if ( partial_status & SW_C3 ) printk("SW: condition bit 3\n"); 125 printk("SW: backward compatibility\n");
135if ( partial_status & SW_C2 ) printk("SW: condition bit 2\n"); 126 if (partial_status & SW_C3)
136if ( partial_status & SW_C1 ) printk("SW: condition bit 1\n"); 127 printk("SW: condition bit 3\n");
137if ( partial_status & SW_C0 ) printk("SW: condition bit 0\n"); 128 if (partial_status & SW_C2)
138if ( partial_status & SW_Summary ) printk("SW: exception summary\n"); 129 printk("SW: condition bit 2\n");
139if ( partial_status & SW_Stack_Fault ) printk("SW: stack fault\n"); 130 if (partial_status & SW_C1)
140if ( partial_status & SW_Precision ) printk("SW: loss of precision\n"); 131 printk("SW: condition bit 1\n");
141if ( partial_status & SW_Underflow ) printk("SW: underflow\n"); 132 if (partial_status & SW_C0)
142if ( partial_status & SW_Overflow ) printk("SW: overflow\n"); 133 printk("SW: condition bit 0\n");
143if ( partial_status & SW_Zero_Div ) printk("SW: divide by zero\n"); 134 if (partial_status & SW_Summary)
144if ( partial_status & SW_Denorm_Op ) printk("SW: denormalized operand\n"); 135 printk("SW: exception summary\n");
145if ( partial_status & SW_Invalid ) printk("SW: invalid operation\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");
146#endif /* DEBUGGING */ 150#endif /* DEBUGGING */
147 151
148 printk(" SW: b=%d st=%ld es=%d sf=%d cc=%d%d%d%d ef=%d%d%d%d%d%d\n", 152 printk(" SW: b=%d st=%ld es=%d sf=%d cc=%d%d%d%d ef=%d%d%d%d%d%d\n", partial_status & 0x8000 ? 1 : 0, /* busy */
149 partial_status & 0x8000 ? 1 : 0, /* busy */ 153 (partial_status & 0x3800) >> 11, /* stack top pointer */
150 (partial_status & 0x3800) >> 11, /* stack top pointer */ 154 partial_status & 0x80 ? 1 : 0, /* Error summary status */
151 partial_status & 0x80 ? 1 : 0, /* Error summary status */ 155 partial_status & 0x40 ? 1 : 0, /* Stack flag */
152 partial_status & 0x40 ? 1 : 0, /* Stack flag */ 156 partial_status & SW_C3 ? 1 : 0, partial_status & SW_C2 ? 1 : 0, /* cc */
153 partial_status & SW_C3?1:0, partial_status & SW_C2?1:0, /* cc */ 157 partial_status & SW_C1 ? 1 : 0, partial_status & SW_C0 ? 1 : 0, /* cc */
154 partial_status & SW_C1?1:0, partial_status & SW_C0?1:0, /* cc */ 158 partial_status & SW_Precision ? 1 : 0,
155 partial_status & SW_Precision?1:0, partial_status & SW_Underflow?1:0, 159 partial_status & SW_Underflow ? 1 : 0,
156 partial_status & SW_Overflow?1:0, partial_status & SW_Zero_Div?1:0, 160 partial_status & SW_Overflow ? 1 : 0,
157 partial_status & SW_Denorm_Op?1:0, partial_status & SW_Invalid?1:0); 161 partial_status & SW_Zero_Div ? 1 : 0,
158 162 partial_status & SW_Denorm_Op ? 1 : 0,
159printk(" CW: ic=%d rc=%ld%ld pc=%ld%ld iem=%d ef=%d%d%d%d%d%d\n", 163 partial_status & SW_Invalid ? 1 : 0);
160 control_word & 0x1000 ? 1 : 0, 164
161 (control_word & 0x800) >> 11, (control_word & 0x400) >> 10, 165 printk(" CW: ic=%d rc=%ld%ld pc=%ld%ld iem=%d ef=%d%d%d%d%d%d\n",
162 (control_word & 0x200) >> 9, (control_word & 0x100) >> 8, 166 control_word & 0x1000 ? 1 : 0,
163 control_word & 0x80 ? 1 : 0, 167 (control_word & 0x800) >> 11, (control_word & 0x400) >> 10,
164 control_word & SW_Precision?1:0, control_word & SW_Underflow?1:0, 168 (control_word & 0x200) >> 9, (control_word & 0x100) >> 8,
165 control_word & SW_Overflow?1:0, control_word & SW_Zero_Div?1:0, 169 control_word & 0x80 ? 1 : 0,
166 control_word & SW_Denorm_Op?1:0, control_word & SW_Invalid?1:0); 170 control_word & SW_Precision ? 1 : 0,
167 171 control_word & SW_Underflow ? 1 : 0,
168 for ( i = 0; i < 8; i++ ) 172 control_word & SW_Overflow ? 1 : 0,
169 { 173 control_word & SW_Zero_Div ? 1 : 0,
170 FPU_REG *r = &st(i); 174 control_word & SW_Denorm_Op ? 1 : 0,
171 u_char tagi = FPU_gettagi(i); 175 control_word & SW_Invalid ? 1 : 0);
172 switch (tagi) 176
173 { 177 for (i = 0; i < 8; i++) {
174 case TAG_Empty: 178 FPU_REG *r = &st(i);
175 continue; 179 u_char tagi = FPU_gettagi(i);
176 break; 180 switch (tagi) {
177 case TAG_Zero: 181 case TAG_Empty:
178 case TAG_Special: 182 continue;
179 tagi = FPU_Special(r); 183 break;
180 case TAG_Valid: 184 case TAG_Zero:
181 printk("st(%d) %c .%04lx %04lx %04lx %04lx e%+-6d ", i, 185 case TAG_Special:
182 getsign(r) ? '-' : '+', 186 tagi = FPU_Special(r);
183 (long)(r->sigh >> 16), 187 case TAG_Valid:
184 (long)(r->sigh & 0xFFFF), 188 printk("st(%d) %c .%04lx %04lx %04lx %04lx e%+-6d ", i,
185 (long)(r->sigl >> 16), 189 getsign(r) ? '-' : '+',
186 (long)(r->sigl & 0xFFFF), 190 (long)(r->sigh >> 16),
187 exponent(r) - EXP_BIAS + 1); 191 (long)(r->sigh & 0xFFFF),
188 break; 192 (long)(r->sigl >> 16),
189 default: 193 (long)(r->sigl & 0xFFFF),
190 printk("Whoops! Error in errors.c: tag%d is %d ", i, tagi); 194 exponent(r) - EXP_BIAS + 1);
191 continue; 195 break;
192 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]);
193 } 203 }
194 printk("%s\n", tag_desc[(int) (unsigned) tagi]);
195 }
196 204
197 RE_ENTRANT_CHECK_ON; 205 RE_ENTRANT_CHECK_ON;
198 206
199} 207}
200 208
201static struct { 209static struct {
202 int type; 210 int type;
203 const char *name; 211 const char *name;
204} exception_names[] = { 212} exception_names[] = {
205 { EX_StackOver, "stack overflow" }, 213 {
206 { EX_StackUnder, "stack underflow" }, 214 EX_StackOver, "stack overflow"}, {
207 { EX_Precision, "loss of precision" }, 215 EX_StackUnder, "stack underflow"}, {
208 { EX_Underflow, "underflow" }, 216 EX_Precision, "loss of precision"}, {
209 { EX_Overflow, "overflow" }, 217 EX_Underflow, "underflow"}, {
210 { EX_ZeroDiv, "divide by zero" }, 218 EX_Overflow, "overflow"}, {
211 { EX_Denormal, "denormalized operand" }, 219 EX_ZeroDiv, "divide by zero"}, {
212 { EX_Invalid, "invalid operation" }, 220 EX_Denormal, "denormalized operand"}, {
213 { EX_INTERNAL, "INTERNAL BUG in "FPU_VERSION }, 221 EX_Invalid, "invalid operation"}, {
214 { 0, NULL } 222 EX_INTERNAL, "INTERNAL BUG in " FPU_VERSION}, {
223 0, NULL}
215}; 224};
216 225
217/* 226/*
@@ -295,445 +304,386 @@ static struct {
295 304
296asmlinkage void FPU_exception(int n) 305asmlinkage void FPU_exception(int n)
297{ 306{
298 int i, int_type; 307 int i, int_type;
299 308
300 int_type = 0; /* Needed only to stop compiler warnings */ 309 int_type = 0; /* Needed only to stop compiler warnings */
301 if ( n & EX_INTERNAL ) 310 if (n & EX_INTERNAL) {
302 { 311 int_type = n - EX_INTERNAL;
303 int_type = n - EX_INTERNAL; 312 n = EX_INTERNAL;
304 n = EX_INTERNAL; 313 /* Set lots of exception bits! */
305 /* Set lots of exception bits! */ 314 partial_status |= (SW_Exc_Mask | SW_Summary | SW_Backward);
306 partial_status |= (SW_Exc_Mask | SW_Summary | SW_Backward); 315 } else {
307 } 316 /* Extract only the bits which we use to set the status word */
308 else 317 n &= (SW_Exc_Mask);
309 { 318 /* Set the corresponding exception bit */
310 /* Extract only the bits which we use to set the status word */ 319 partial_status |= n;
311 n &= (SW_Exc_Mask); 320 /* Set summary bits iff exception isn't masked */
312 /* Set the corresponding exception bit */ 321 if (partial_status & ~control_word & CW_Exceptions)
313 partial_status |= n; 322 partial_status |= (SW_Summary | SW_Backward);
314 /* Set summary bits iff exception isn't masked */ 323 if (n & (SW_Stack_Fault | EX_Precision)) {
315 if ( partial_status & ~control_word & CW_Exceptions ) 324 if (!(n & SW_C1))
316 partial_status |= (SW_Summary | SW_Backward); 325 /* This bit distinguishes over- from underflow for a stack fault,
317 if ( n & (SW_Stack_Fault | EX_Precision) ) 326 and roundup from round-down for precision loss. */
318 { 327 partial_status &= ~SW_C1;
319 if ( !(n & SW_C1) ) 328 }
320 /* This bit distinguishes over- from underflow for a stack fault,
321 and roundup from round-down for precision loss. */
322 partial_status &= ~SW_C1;
323 } 329 }
324 }
325 330
326 RE_ENTRANT_CHECK_OFF; 331 RE_ENTRANT_CHECK_OFF;
327 if ( (~control_word & n & CW_Exceptions) || (n == EX_INTERNAL) ) 332 if ((~control_word & n & CW_Exceptions) || (n == EX_INTERNAL)) {
328 {
329#ifdef PRINT_MESSAGES 333#ifdef PRINT_MESSAGES
330 /* My message from the sponsor */ 334 /* My message from the sponsor */
331 printk(FPU_VERSION" "__DATE__" (C) W. Metzenthen.\n"); 335 printk(FPU_VERSION " " __DATE__ " (C) W. Metzenthen.\n");
332#endif /* PRINT_MESSAGES */ 336#endif /* PRINT_MESSAGES */
333 337
334 /* Get a name string for error reporting */ 338 /* Get a name string for error reporting */
335 for (i=0; exception_names[i].type; i++) 339 for (i = 0; exception_names[i].type; i++)
336 if ( (exception_names[i].type & n) == exception_names[i].type ) 340 if ((exception_names[i].type & n) ==
337 break; 341 exception_names[i].type)
338 342 break;
339 if (exception_names[i].type) 343
340 { 344 if (exception_names[i].type) {
341#ifdef PRINT_MESSAGES 345#ifdef PRINT_MESSAGES
342 printk("FP Exception: %s!\n", exception_names[i].name); 346 printk("FP Exception: %s!\n", exception_names[i].name);
343#endif /* PRINT_MESSAGES */ 347#endif /* PRINT_MESSAGES */
344 } 348 } else
345 else 349 printk("FPU emulator: Unknown Exception: 0x%04x!\n", n);
346 printk("FPU emulator: Unknown Exception: 0x%04x!\n", n); 350
347 351 if (n == EX_INTERNAL) {
348 if ( n == EX_INTERNAL ) 352 printk("FPU emulator: Internal error type 0x%04x\n",
349 { 353 int_type);
350 printk("FPU emulator: Internal error type 0x%04x\n", int_type); 354 FPU_printall();
351 FPU_printall(); 355 }
352 }
353#ifdef PRINT_MESSAGES 356#ifdef PRINT_MESSAGES
354 else 357 else
355 FPU_printall(); 358 FPU_printall();
356#endif /* PRINT_MESSAGES */ 359#endif /* PRINT_MESSAGES */
357 360
358 /* 361 /*
359 * The 80486 generates an interrupt on the next non-control FPU 362 * The 80486 generates an interrupt on the next non-control FPU
360 * instruction. So we need some means of flagging it. 363 * instruction. So we need some means of flagging it.
361 * We use the ES (Error Summary) bit for this. 364 * We use the ES (Error Summary) bit for this.
362 */ 365 */
363 } 366 }
364 RE_ENTRANT_CHECK_ON; 367 RE_ENTRANT_CHECK_ON;
365 368
366#ifdef __DEBUG__ 369#ifdef __DEBUG__
367 math_abort(FPU_info,SIGFPE); 370 math_abort(FPU_info, SIGFPE);
368#endif /* __DEBUG__ */ 371#endif /* __DEBUG__ */
369 372
370} 373}
371 374
372
373/* Real operation attempted on a NaN. */ 375/* Real operation attempted on a NaN. */
374/* Returns < 0 if the exception is unmasked */ 376/* Returns < 0 if the exception is unmasked */
375int real_1op_NaN(FPU_REG *a) 377int real_1op_NaN(FPU_REG * a)
376{ 378{
377 int signalling, isNaN; 379 int signalling, isNaN;
378 380
379 isNaN = (exponent(a) == EXP_OVER) && (a->sigh & 0x80000000); 381 isNaN = (exponent(a) == EXP_OVER) && (a->sigh & 0x80000000);
380 382
381 /* The default result for the case of two "equal" NaNs (signs may 383 /* The default result for the case of two "equal" NaNs (signs may
382 differ) is chosen to reproduce 80486 behaviour */ 384 differ) is chosen to reproduce 80486 behaviour */
383 signalling = isNaN && !(a->sigh & 0x40000000); 385 signalling = isNaN && !(a->sigh & 0x40000000);
384 386
385 if ( !signalling ) 387 if (!signalling) {
386 { 388 if (!isNaN) { /* pseudo-NaN, or other unsupported? */
387 if ( !isNaN ) /* pseudo-NaN, or other unsupported? */ 389 if (control_word & CW_Invalid) {
388 { 390 /* Masked response */
389 if ( control_word & CW_Invalid ) 391 reg_copy(&CONST_QNaN, a);
390 { 392 }
391 /* Masked response */ 393 EXCEPTION(EX_Invalid);
392 reg_copy(&CONST_QNaN, a); 394 return (!(control_word & CW_Invalid) ? FPU_Exception :
393 } 395 0) | TAG_Special;
394 EXCEPTION(EX_Invalid); 396 }
395 return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Special; 397 return TAG_Special;
396 } 398 }
397 return TAG_Special;
398 }
399 399
400 if ( control_word & CW_Invalid ) 400 if (control_word & CW_Invalid) {
401 { 401 /* The masked response */
402 /* The masked response */ 402 if (!(a->sigh & 0x80000000)) { /* pseudo-NaN ? */
403 if ( !(a->sigh & 0x80000000) ) /* pseudo-NaN ? */ 403 reg_copy(&CONST_QNaN, a);
404 { 404 }
405 reg_copy(&CONST_QNaN, a); 405 /* ensure a Quiet NaN */
406 a->sigh |= 0x40000000;
406 } 407 }
407 /* ensure a Quiet NaN */
408 a->sigh |= 0x40000000;
409 }
410 408
411 EXCEPTION(EX_Invalid); 409 EXCEPTION(EX_Invalid);
412 410
413 return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Special; 411 return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Special;
414} 412}
415 413
416
417/* Real operation attempted on two operands, one a NaN. */ 414/* Real operation attempted on two operands, one a NaN. */
418/* Returns < 0 if the exception is unmasked */ 415/* Returns < 0 if the exception is unmasked */
419int real_2op_NaN(FPU_REG const *b, u_char tagb, 416int real_2op_NaN(FPU_REG const *b, u_char tagb,
420 int deststnr, 417 int deststnr, FPU_REG const *defaultNaN)
421 FPU_REG const *defaultNaN)
422{ 418{
423 FPU_REG *dest = &st(deststnr); 419 FPU_REG *dest = &st(deststnr);
424 FPU_REG const *a = dest; 420 FPU_REG const *a = dest;
425 u_char taga = FPU_gettagi(deststnr); 421 u_char taga = FPU_gettagi(deststnr);
426 FPU_REG const *x; 422 FPU_REG const *x;
427 int signalling, unsupported; 423 int signalling, unsupported;
428 424
429 if ( taga == TAG_Special ) 425 if (taga == TAG_Special)
430 taga = FPU_Special(a); 426 taga = FPU_Special(a);
431 if ( tagb == TAG_Special ) 427 if (tagb == TAG_Special)
432 tagb = FPU_Special(b); 428 tagb = FPU_Special(b);
433 429
434 /* TW_NaN is also used for unsupported data types. */ 430 /* TW_NaN is also used for unsupported data types. */
435 unsupported = ((taga == TW_NaN) 431 unsupported = ((taga == TW_NaN)
436 && !((exponent(a) == EXP_OVER) && (a->sigh & 0x80000000))) 432 && !((exponent(a) == EXP_OVER)
437 || ((tagb == TW_NaN) 433 && (a->sigh & 0x80000000)))
438 && !((exponent(b) == EXP_OVER) && (b->sigh & 0x80000000))); 434 || ((tagb == TW_NaN)
439 if ( unsupported ) 435 && !((exponent(b) == EXP_OVER) && (b->sigh & 0x80000000)));
440 { 436 if (unsupported) {
441 if ( control_word & CW_Invalid ) 437 if (control_word & CW_Invalid) {
442 { 438 /* Masked response */
443 /* Masked response */ 439 FPU_copy_to_regi(&CONST_QNaN, TAG_Special, deststnr);
444 FPU_copy_to_regi(&CONST_QNaN, TAG_Special, deststnr); 440 }
445 } 441 EXCEPTION(EX_Invalid);
446 EXCEPTION(EX_Invalid); 442 return (!(control_word & CW_Invalid) ? FPU_Exception : 0) |
447 return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Special; 443 TAG_Special;
448 }
449
450 if (taga == TW_NaN)
451 {
452 x = a;
453 if (tagb == TW_NaN)
454 {
455 signalling = !(a->sigh & b->sigh & 0x40000000);
456 if ( significand(b) > significand(a) )
457 x = b;
458 else if ( significand(b) == significand(a) )
459 {
460 /* The default result for the case of two "equal" NaNs (signs may
461 differ) is chosen to reproduce 80486 behaviour */
462 x = defaultNaN;
463 }
464 }
465 else
466 {
467 /* return the quiet version of the NaN in a */
468 signalling = !(a->sigh & 0x40000000);
469 } 444 }
470 } 445
471 else 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 /* The default result for the case of two "equal" NaNs (signs may
454 differ) is chosen to reproduce 80486 behaviour */
455 x = defaultNaN;
456 }
457 } else {
458 /* return the quiet version of the NaN in a */
459 signalling = !(a->sigh & 0x40000000);
460 }
461 } else
472#ifdef PARANOID 462#ifdef PARANOID
473 if (tagb == TW_NaN) 463 if (tagb == TW_NaN)
474#endif /* PARANOID */ 464#endif /* PARANOID */
475 { 465 {
476 signalling = !(b->sigh & 0x40000000); 466 signalling = !(b->sigh & 0x40000000);
477 x = b; 467 x = b;
478 } 468 }
479#ifdef PARANOID 469#ifdef PARANOID
480 else 470 else {
481 { 471 signalling = 0;
482 signalling = 0; 472 EXCEPTION(EX_INTERNAL | 0x113);
483 EXCEPTION(EX_INTERNAL|0x113); 473 x = &CONST_QNaN;
484 x = &CONST_QNaN; 474 }
485 }
486#endif /* PARANOID */ 475#endif /* PARANOID */
487 476
488 if ( (!signalling) || (control_word & CW_Invalid) ) 477 if ((!signalling) || (control_word & CW_Invalid)) {
489 { 478 if (!x)
490 if ( ! x ) 479 x = b;
491 x = b;
492 480
493 if ( !(x->sigh & 0x80000000) ) /* pseudo-NaN ? */ 481 if (!(x->sigh & 0x80000000)) /* pseudo-NaN ? */
494 x = &CONST_QNaN; 482 x = &CONST_QNaN;
495 483
496 FPU_copy_to_regi(x, TAG_Special, deststnr); 484 FPU_copy_to_regi(x, TAG_Special, deststnr);
497 485
498 if ( !signalling ) 486 if (!signalling)
499 return TAG_Special; 487 return TAG_Special;
500 488
501 /* ensure a Quiet NaN */ 489 /* ensure a Quiet NaN */
502 dest->sigh |= 0x40000000; 490 dest->sigh |= 0x40000000;
503 } 491 }
504 492
505 EXCEPTION(EX_Invalid); 493 EXCEPTION(EX_Invalid);
506 494
507 return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Special; 495 return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Special;
508} 496}
509 497
510
511/* Invalid arith operation on Valid registers */ 498/* Invalid arith operation on Valid registers */
512/* Returns < 0 if the exception is unmasked */ 499/* Returns < 0 if the exception is unmasked */
513asmlinkage int arith_invalid(int deststnr) 500asmlinkage int arith_invalid(int deststnr)
514{ 501{
515 502
516 EXCEPTION(EX_Invalid); 503 EXCEPTION(EX_Invalid);
517
518 if ( control_word & CW_Invalid )
519 {
520 /* The masked response */
521 FPU_copy_to_regi(&CONST_QNaN, TAG_Special, deststnr);
522 }
523
524 return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Valid;
525 504
526} 505 if (control_word & CW_Invalid) {
506 /* The masked response */
507 FPU_copy_to_regi(&CONST_QNaN, TAG_Special, deststnr);
508 }
527 509
510 return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Valid;
511
512}
528 513
529/* Divide a finite number by zero */ 514/* Divide a finite number by zero */
530asmlinkage int FPU_divide_by_zero(int deststnr, u_char sign) 515asmlinkage int FPU_divide_by_zero(int deststnr, u_char sign)
531{ 516{
532 FPU_REG *dest = &st(deststnr); 517 FPU_REG *dest = &st(deststnr);
533 int tag = TAG_Valid; 518 int tag = TAG_Valid;
519
520 if (control_word & CW_ZeroDiv) {
521 /* The masked response */
522 FPU_copy_to_regi(&CONST_INF, TAG_Special, deststnr);
523 setsign(dest, sign);
524 tag = TAG_Special;
525 }
534 526
535 if ( control_word & CW_ZeroDiv ) 527 EXCEPTION(EX_ZeroDiv);
536 {
537 /* The masked response */
538 FPU_copy_to_regi(&CONST_INF, TAG_Special, deststnr);
539 setsign(dest, sign);
540 tag = TAG_Special;
541 }
542
543 EXCEPTION(EX_ZeroDiv);
544 528
545 return (!(control_word & CW_ZeroDiv) ? FPU_Exception : 0) | tag; 529 return (!(control_word & CW_ZeroDiv) ? FPU_Exception : 0) | tag;
546 530
547} 531}
548 532
549
550/* This may be called often, so keep it lean */ 533/* This may be called often, so keep it lean */
551int set_precision_flag(int flags) 534int set_precision_flag(int flags)
552{ 535{
553 if ( control_word & CW_Precision ) 536 if (control_word & CW_Precision) {
554 { 537 partial_status &= ~(SW_C1 & flags);
555 partial_status &= ~(SW_C1 & flags); 538 partial_status |= flags; /* The masked response */
556 partial_status |= flags; /* The masked response */ 539 return 0;
557 return 0; 540 } else {
558 } 541 EXCEPTION(flags);
559 else 542 return 1;
560 { 543 }
561 EXCEPTION(flags);
562 return 1;
563 }
564} 544}
565 545
566
567/* This may be called often, so keep it lean */ 546/* This may be called often, so keep it lean */
568asmlinkage void set_precision_flag_up(void) 547asmlinkage void set_precision_flag_up(void)
569{ 548{
570 if ( control_word & CW_Precision ) 549 if (control_word & CW_Precision)
571 partial_status |= (SW_Precision | SW_C1); /* The masked response */ 550 partial_status |= (SW_Precision | SW_C1); /* The masked response */
572 else 551 else
573 EXCEPTION(EX_Precision | SW_C1); 552 EXCEPTION(EX_Precision | SW_C1);
574} 553}
575 554
576
577/* This may be called often, so keep it lean */ 555/* This may be called often, so keep it lean */
578asmlinkage void set_precision_flag_down(void) 556asmlinkage void set_precision_flag_down(void)
579{ 557{
580 if ( control_word & CW_Precision ) 558 if (control_word & CW_Precision) { /* The masked response */
581 { /* The masked response */ 559 partial_status &= ~SW_C1;
582 partial_status &= ~SW_C1; 560 partial_status |= SW_Precision;
583 partial_status |= SW_Precision; 561 } else
584 } 562 EXCEPTION(EX_Precision);
585 else
586 EXCEPTION(EX_Precision);
587} 563}
588 564
589
590asmlinkage int denormal_operand(void) 565asmlinkage int denormal_operand(void)
591{ 566{
592 if ( control_word & CW_Denormal ) 567 if (control_word & CW_Denormal) { /* The masked response */
593 { /* The masked response */ 568 partial_status |= SW_Denorm_Op;
594 partial_status |= SW_Denorm_Op; 569 return TAG_Special;
595 return TAG_Special; 570 } else {
596 } 571 EXCEPTION(EX_Denormal);
597 else 572 return TAG_Special | FPU_Exception;
598 { 573 }
599 EXCEPTION(EX_Denormal);
600 return TAG_Special | FPU_Exception;
601 }
602} 574}
603 575
604 576asmlinkage int arith_overflow(FPU_REG * dest)
605asmlinkage int arith_overflow(FPU_REG *dest)
606{ 577{
607 int tag = TAG_Valid; 578 int tag = TAG_Valid;
608 579
609 if ( control_word & CW_Overflow ) 580 if (control_word & CW_Overflow) {
610 { 581 /* The masked response */
611 /* The masked response */
612/* ###### The response here depends upon the rounding mode */ 582/* ###### The response here depends upon the rounding mode */
613 reg_copy(&CONST_INF, dest); 583 reg_copy(&CONST_INF, dest);
614 tag = TAG_Special; 584 tag = TAG_Special;
615 } 585 } else {
616 else 586 /* Subtract the magic number from the exponent */
617 { 587 addexponent(dest, (-3 * (1 << 13)));
618 /* Subtract the magic number from the exponent */ 588 }
619 addexponent(dest, (-3 * (1 << 13)));
620 }
621
622 EXCEPTION(EX_Overflow);
623 if ( control_word & CW_Overflow )
624 {
625 /* The overflow exception is masked. */
626 /* By definition, precision is lost.
627 The roundup bit (C1) is also set because we have
628 "rounded" upwards to Infinity. */
629 EXCEPTION(EX_Precision | SW_C1);
630 return tag;
631 }
632
633 return tag;
634 589
635} 590 EXCEPTION(EX_Overflow);
591 if (control_word & CW_Overflow) {
592 /* The overflow exception is masked. */
593 /* By definition, precision is lost.
594 The roundup bit (C1) is also set because we have
595 "rounded" upwards to Infinity. */
596 EXCEPTION(EX_Precision | SW_C1);
597 return tag;
598 }
636 599
600 return tag;
637 601
638asmlinkage int arith_underflow(FPU_REG *dest) 602}
639{
640 int tag = TAG_Valid;
641 603
642 if ( control_word & CW_Underflow ) 604asmlinkage int arith_underflow(FPU_REG * dest)
643 { 605{
644 /* The masked response */ 606 int tag = TAG_Valid;
645 if ( exponent16(dest) <= EXP_UNDER - 63 ) 607
646 { 608 if (control_word & CW_Underflow) {
647 reg_copy(&CONST_Z, dest); 609 /* The masked response */
648 partial_status &= ~SW_C1; /* Round down. */ 610 if (exponent16(dest) <= EXP_UNDER - 63) {
649 tag = TAG_Zero; 611 reg_copy(&CONST_Z, dest);
612 partial_status &= ~SW_C1; /* Round down. */
613 tag = TAG_Zero;
614 } else {
615 stdexp(dest);
616 }
617 } else {
618 /* Add the magic number to the exponent. */
619 addexponent(dest, (3 * (1 << 13)) + EXTENDED_Ebias);
650 } 620 }
651 else 621
652 { 622 EXCEPTION(EX_Underflow);
653 stdexp(dest); 623 if (control_word & CW_Underflow) {
624 /* The underflow exception is masked. */
625 EXCEPTION(EX_Precision);
626 return tag;
654 } 627 }
655 }
656 else
657 {
658 /* Add the magic number to the exponent. */
659 addexponent(dest, (3 * (1 << 13)) + EXTENDED_Ebias);
660 }
661
662 EXCEPTION(EX_Underflow);
663 if ( control_word & CW_Underflow )
664 {
665 /* The underflow exception is masked. */
666 EXCEPTION(EX_Precision);
667 return tag;
668 }
669
670 return tag;
671 628
672} 629 return tag;
673 630
631}
674 632
675void FPU_stack_overflow(void) 633void FPU_stack_overflow(void)
676{ 634{
677 635
678 if ( control_word & CW_Invalid ) 636 if (control_word & CW_Invalid) {
679 { 637 /* The masked response */
680 /* The masked response */ 638 top--;
681 top--; 639 FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
682 FPU_copy_to_reg0(&CONST_QNaN, TAG_Special); 640 }
683 }
684 641
685 EXCEPTION(EX_StackOver); 642 EXCEPTION(EX_StackOver);
686 643
687 return; 644 return;
688 645
689} 646}
690 647
691
692void FPU_stack_underflow(void) 648void FPU_stack_underflow(void)
693{ 649{
694 650
695 if ( control_word & CW_Invalid ) 651 if (control_word & CW_Invalid) {
696 { 652 /* The masked response */
697 /* The masked response */ 653 FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
698 FPU_copy_to_reg0(&CONST_QNaN, TAG_Special); 654 }
699 }
700 655
701 EXCEPTION(EX_StackUnder); 656 EXCEPTION(EX_StackUnder);
702 657
703 return; 658 return;
704 659
705} 660}
706 661
707
708void FPU_stack_underflow_i(int i) 662void FPU_stack_underflow_i(int i)
709{ 663{
710 664
711 if ( control_word & CW_Invalid ) 665 if (control_word & CW_Invalid) {
712 { 666 /* The masked response */
713 /* The masked response */ 667 FPU_copy_to_regi(&CONST_QNaN, TAG_Special, i);
714 FPU_copy_to_regi(&CONST_QNaN, TAG_Special, i); 668 }
715 }
716 669
717 EXCEPTION(EX_StackUnder); 670 EXCEPTION(EX_StackUnder);
718 671
719 return; 672 return;
720 673
721} 674}
722 675
723
724void FPU_stack_underflow_pop(int i) 676void FPU_stack_underflow_pop(int i)
725{ 677{
726 678
727 if ( control_word & CW_Invalid ) 679 if (control_word & CW_Invalid) {
728 { 680 /* The masked response */
729 /* The masked response */ 681 FPU_copy_to_regi(&CONST_QNaN, TAG_Special, i);
730 FPU_copy_to_regi(&CONST_QNaN, TAG_Special, i); 682 FPU_pop();
731 FPU_pop(); 683 }
732 }
733 684
734 EXCEPTION(EX_StackUnder); 685 EXCEPTION(EX_StackUnder);
735 686
736 return; 687 return;
737 688
738} 689}
739
diff --git a/arch/x86/math-emu/exception.h b/arch/x86/math-emu/exception.h
index b463f21a811e..67f43a4683d5 100644
--- a/arch/x86/math-emu/exception.h
+++ b/arch/x86/math-emu/exception.h
@@ -9,7 +9,6 @@
9#ifndef _EXCEPTION_H_ 9#ifndef _EXCEPTION_H_
10#define _EXCEPTION_H_ 10#define _EXCEPTION_H_
11 11
12
13#ifdef __ASSEMBLY__ 12#ifdef __ASSEMBLY__
14#define Const_(x) $##x 13#define Const_(x) $##x
15#else 14#else
@@ -20,8 +19,8 @@
20#include "fpu_emu.h" 19#include "fpu_emu.h"
21#endif /* SW_C1 */ 20#endif /* SW_C1 */
22 21
23#define FPU_BUSY Const_(0x8000) /* FPU busy bit (8087 compatibility) */ 22#define FPU_BUSY Const_(0x8000) /* FPU busy bit (8087 compatibility) */
24#define EX_ErrorSummary Const_(0x0080) /* Error summary status */ 23#define EX_ErrorSummary Const_(0x0080) /* Error summary status */
25/* Special exceptions: */ 24/* Special exceptions: */
26#define EX_INTERNAL Const_(0x8000) /* Internal error in wm-FPU-emu */ 25#define EX_INTERNAL Const_(0x8000) /* Internal error in wm-FPU-emu */
27#define EX_StackOver Const_(0x0041|SW_C1) /* stack overflow */ 26#define EX_StackOver Const_(0x0041|SW_C1) /* stack overflow */
@@ -34,11 +33,9 @@
34#define EX_Denormal Const_(0x0002) /* denormalized operand */ 33#define EX_Denormal Const_(0x0002) /* denormalized operand */
35#define EX_Invalid Const_(0x0001) /* invalid operation */ 34#define EX_Invalid Const_(0x0001) /* invalid operation */
36 35
37
38#define PRECISION_LOST_UP Const_((EX_Precision | SW_C1)) 36#define PRECISION_LOST_UP Const_((EX_Precision | SW_C1))
39#define PRECISION_LOST_DOWN Const_(EX_Precision) 37#define PRECISION_LOST_DOWN Const_(EX_Precision)
40 38
41
42#ifndef __ASSEMBLY__ 39#ifndef __ASSEMBLY__
43 40
44#ifdef DEBUG 41#ifdef DEBUG
@@ -48,6 +45,6 @@
48#define EXCEPTION(x) FPU_exception(x) 45#define EXCEPTION(x) FPU_exception(x)
49#endif 46#endif
50 47
51#endif /* __ASSEMBLY__ */ 48#endif /* __ASSEMBLY__ */
52 49
53#endif /* _EXCEPTION_H_ */ 50#endif /* _EXCEPTION_H_ */
diff --git a/arch/x86/math-emu/fpu_arith.c b/arch/x86/math-emu/fpu_arith.c
index 6972dec01af6..aeab24e083c4 100644
--- a/arch/x86/math-emu/fpu_arith.c
+++ b/arch/x86/math-emu/fpu_arith.c
@@ -15,160 +15,138 @@
15#include "control_w.h" 15#include "control_w.h"
16#include "status_w.h" 16#include "status_w.h"
17 17
18
19void fadd__(void) 18void fadd__(void)
20{ 19{
21 /* fadd st,st(i) */ 20 /* fadd st,st(i) */
22 int i = FPU_rm; 21 int i = FPU_rm;
23 clear_C1(); 22 clear_C1();
24 FPU_add(&st(i), FPU_gettagi(i), 0, control_word); 23 FPU_add(&st(i), FPU_gettagi(i), 0, control_word);
25} 24}
26 25
27
28void fmul__(void) 26void fmul__(void)
29{ 27{
30 /* fmul st,st(i) */ 28 /* fmul st,st(i) */
31 int i = FPU_rm; 29 int i = FPU_rm;
32 clear_C1(); 30 clear_C1();
33 FPU_mul(&st(i), FPU_gettagi(i), 0, control_word); 31 FPU_mul(&st(i), FPU_gettagi(i), 0, control_word);
34} 32}
35 33
36
37
38void fsub__(void) 34void fsub__(void)
39{ 35{
40 /* fsub st,st(i) */ 36 /* fsub st,st(i) */
41 clear_C1(); 37 clear_C1();
42 FPU_sub(0, FPU_rm, control_word); 38 FPU_sub(0, FPU_rm, control_word);
43} 39}
44 40
45
46void fsubr_(void) 41void fsubr_(void)
47{ 42{
48 /* fsubr st,st(i) */ 43 /* fsubr st,st(i) */
49 clear_C1(); 44 clear_C1();
50 FPU_sub(REV, FPU_rm, control_word); 45 FPU_sub(REV, FPU_rm, control_word);
51} 46}
52 47
53
54void fdiv__(void) 48void fdiv__(void)
55{ 49{
56 /* fdiv st,st(i) */ 50 /* fdiv st,st(i) */
57 clear_C1(); 51 clear_C1();
58 FPU_div(0, FPU_rm, control_word); 52 FPU_div(0, FPU_rm, control_word);
59} 53}
60 54
61
62void fdivr_(void) 55void fdivr_(void)
63{ 56{
64 /* fdivr st,st(i) */ 57 /* fdivr st,st(i) */
65 clear_C1(); 58 clear_C1();
66 FPU_div(REV, FPU_rm, control_word); 59 FPU_div(REV, FPU_rm, control_word);
67} 60}
68 61
69
70
71void fadd_i(void) 62void fadd_i(void)
72{ 63{
73 /* fadd st(i),st */ 64 /* fadd st(i),st */
74 int i = FPU_rm; 65 int i = FPU_rm;
75 clear_C1(); 66 clear_C1();
76 FPU_add(&st(i), FPU_gettagi(i), i, control_word); 67 FPU_add(&st(i), FPU_gettagi(i), i, control_word);
77} 68}
78 69
79
80void fmul_i(void) 70void fmul_i(void)
81{ 71{
82 /* fmul st(i),st */ 72 /* fmul st(i),st */
83 clear_C1(); 73 clear_C1();
84 FPU_mul(&st(0), FPU_gettag0(), FPU_rm, control_word); 74 FPU_mul(&st(0), FPU_gettag0(), FPU_rm, control_word);
85} 75}
86 76
87
88void fsubri(void) 77void fsubri(void)
89{ 78{
90 /* fsubr st(i),st */ 79 /* fsubr st(i),st */
91 clear_C1(); 80 clear_C1();
92 FPU_sub(DEST_RM, FPU_rm, control_word); 81 FPU_sub(DEST_RM, FPU_rm, control_word);
93} 82}
94 83
95
96void fsub_i(void) 84void fsub_i(void)
97{ 85{
98 /* fsub st(i),st */ 86 /* fsub st(i),st */
99 clear_C1(); 87 clear_C1();
100 FPU_sub(REV|DEST_RM, FPU_rm, control_word); 88 FPU_sub(REV | DEST_RM, FPU_rm, control_word);
101} 89}
102 90
103
104void fdivri(void) 91void fdivri(void)
105{ 92{
106 /* fdivr st(i),st */ 93 /* fdivr st(i),st */
107 clear_C1(); 94 clear_C1();
108 FPU_div(DEST_RM, FPU_rm, control_word); 95 FPU_div(DEST_RM, FPU_rm, control_word);
109} 96}
110 97
111
112void fdiv_i(void) 98void fdiv_i(void)
113{ 99{
114 /* fdiv st(i),st */ 100 /* fdiv st(i),st */
115 clear_C1(); 101 clear_C1();
116 FPU_div(REV|DEST_RM, FPU_rm, control_word); 102 FPU_div(REV | DEST_RM, FPU_rm, control_word);
117} 103}
118 104
119
120
121void faddp_(void) 105void faddp_(void)
122{ 106{
123 /* faddp st(i),st */ 107 /* faddp st(i),st */
124 int i = FPU_rm; 108 int i = FPU_rm;
125 clear_C1(); 109 clear_C1();
126 if ( FPU_add(&st(i), FPU_gettagi(i), i, control_word) >= 0 ) 110 if (FPU_add(&st(i), FPU_gettagi(i), i, control_word) >= 0)
127 FPU_pop(); 111 FPU_pop();
128} 112}
129 113
130
131void fmulp_(void) 114void fmulp_(void)
132{ 115{
133 /* fmulp st(i),st */ 116 /* fmulp st(i),st */
134 clear_C1(); 117 clear_C1();
135 if ( FPU_mul(&st(0), FPU_gettag0(), FPU_rm, control_word) >= 0 ) 118 if (FPU_mul(&st(0), FPU_gettag0(), FPU_rm, control_word) >= 0)
136 FPU_pop(); 119 FPU_pop();
137} 120}
138 121
139
140
141void fsubrp(void) 122void fsubrp(void)
142{ 123{
143 /* fsubrp st(i),st */ 124 /* fsubrp st(i),st */
144 clear_C1(); 125 clear_C1();
145 if ( FPU_sub(DEST_RM, FPU_rm, control_word) >= 0 ) 126 if (FPU_sub(DEST_RM, FPU_rm, control_word) >= 0)
146 FPU_pop(); 127 FPU_pop();
147} 128}
148 129
149
150void fsubp_(void) 130void fsubp_(void)
151{ 131{
152 /* fsubp st(i),st */ 132 /* fsubp st(i),st */
153 clear_C1(); 133 clear_C1();
154 if ( FPU_sub(REV|DEST_RM, FPU_rm, control_word) >= 0 ) 134 if (FPU_sub(REV | DEST_RM, FPU_rm, control_word) >= 0)
155 FPU_pop(); 135 FPU_pop();
156} 136}
157 137
158
159void fdivrp(void) 138void fdivrp(void)
160{ 139{
161 /* fdivrp st(i),st */ 140 /* fdivrp st(i),st */
162 clear_C1(); 141 clear_C1();
163 if ( FPU_div(DEST_RM, FPU_rm, control_word) >= 0 ) 142 if (FPU_div(DEST_RM, FPU_rm, control_word) >= 0)
164 FPU_pop(); 143 FPU_pop();
165} 144}
166 145
167
168void fdivp_(void) 146void fdivp_(void)
169{ 147{
170 /* fdivp st(i),st */ 148 /* fdivp st(i),st */
171 clear_C1(); 149 clear_C1();
172 if ( FPU_div(REV|DEST_RM, FPU_rm, control_word) >= 0 ) 150 if (FPU_div(REV | DEST_RM, FPU_rm, control_word) >= 0)
173 FPU_pop(); 151 FPU_pop();
174} 152}
diff --git a/arch/x86/math-emu/fpu_asm.h b/arch/x86/math-emu/fpu_asm.h
index 9ba12416df12..955b932735a4 100644
--- a/arch/x86/math-emu/fpu_asm.h
+++ b/arch/x86/math-emu/fpu_asm.h
@@ -14,7 +14,6 @@
14 14
15#define EXCEPTION FPU_exception 15#define EXCEPTION FPU_exception
16 16
17
18#define PARAM1 8(%ebp) 17#define PARAM1 8(%ebp)
19#define PARAM2 12(%ebp) 18#define PARAM2 12(%ebp)
20#define PARAM3 16(%ebp) 19#define PARAM3 16(%ebp)
diff --git a/arch/x86/math-emu/fpu_aux.c b/arch/x86/math-emu/fpu_aux.c
index 20886cfb9f76..491e737ce547 100644
--- a/arch/x86/math-emu/fpu_aux.c
+++ b/arch/x86/math-emu/fpu_aux.c
@@ -16,34 +16,34 @@
16#include "status_w.h" 16#include "status_w.h"
17#include "control_w.h" 17#include "control_w.h"
18 18
19
20static void fnop(void) 19static void fnop(void)
21{ 20{
22} 21}
23 22
24static void fclex(void) 23static void fclex(void)
25{ 24{
26 partial_status &= ~(SW_Backward|SW_Summary|SW_Stack_Fault|SW_Precision| 25 partial_status &=
27 SW_Underflow|SW_Overflow|SW_Zero_Div|SW_Denorm_Op| 26 ~(SW_Backward | SW_Summary | SW_Stack_Fault | SW_Precision |
28 SW_Invalid); 27 SW_Underflow | SW_Overflow | SW_Zero_Div | SW_Denorm_Op |
29 no_ip_update = 1; 28 SW_Invalid);
29 no_ip_update = 1;
30} 30}
31 31
32/* Needs to be externally visible */ 32/* Needs to be externally visible */
33void finit(void) 33void finit(void)
34{ 34{
35 control_word = 0x037f; 35 control_word = 0x037f;
36 partial_status = 0; 36 partial_status = 0;
37 top = 0; /* We don't keep top in the status word internally. */ 37 top = 0; /* We don't keep top in the status word internally. */
38 fpu_tag_word = 0xffff; 38 fpu_tag_word = 0xffff;
39 /* The behaviour is different from that detailed in 39 /* The behaviour is different from that detailed in
40 Section 15.1.6 of the Intel manual */ 40 Section 15.1.6 of the Intel manual */
41 operand_address.offset = 0; 41 operand_address.offset = 0;
42 operand_address.selector = 0; 42 operand_address.selector = 0;
43 instruction_address.offset = 0; 43 instruction_address.offset = 0;
44 instruction_address.selector = 0; 44 instruction_address.selector = 0;
45 instruction_address.opcode = 0; 45 instruction_address.opcode = 0;
46 no_ip_update = 1; 46 no_ip_update = 1;
47} 47}
48 48
49/* 49/*
@@ -54,151 +54,134 @@ void finit(void)
54#define fsetpm fnop 54#define fsetpm fnop
55 55
56static FUNC const finit_table[] = { 56static FUNC const finit_table[] = {
57 feni, fdisi, fclex, finit, 57 feni, fdisi, fclex, finit,
58 fsetpm, FPU_illegal, FPU_illegal, FPU_illegal 58 fsetpm, FPU_illegal, FPU_illegal, FPU_illegal
59}; 59};
60 60
61void finit_(void) 61void finit_(void)
62{ 62{
63 (finit_table[FPU_rm])(); 63 (finit_table[FPU_rm]) ();
64} 64}
65 65
66
67static void fstsw_ax(void) 66static void fstsw_ax(void)
68{ 67{
69 *(short *) &FPU_EAX = status_word(); 68 *(short *)&FPU_EAX = status_word();
70 no_ip_update = 1; 69 no_ip_update = 1;
71} 70}
72 71
73static FUNC const fstsw_table[] = { 72static FUNC const fstsw_table[] = {
74 fstsw_ax, FPU_illegal, FPU_illegal, FPU_illegal, 73 fstsw_ax, FPU_illegal, FPU_illegal, FPU_illegal,
75 FPU_illegal, FPU_illegal, FPU_illegal, FPU_illegal 74 FPU_illegal, FPU_illegal, FPU_illegal, FPU_illegal
76}; 75};
77 76
78void fstsw_(void) 77void fstsw_(void)
79{ 78{
80 (fstsw_table[FPU_rm])(); 79 (fstsw_table[FPU_rm]) ();
81} 80}
82 81
83
84static FUNC const fp_nop_table[] = { 82static FUNC const fp_nop_table[] = {
85 fnop, FPU_illegal, FPU_illegal, FPU_illegal, 83 fnop, FPU_illegal, FPU_illegal, FPU_illegal,
86 FPU_illegal, FPU_illegal, FPU_illegal, FPU_illegal 84 FPU_illegal, FPU_illegal, FPU_illegal, FPU_illegal
87}; 85};
88 86
89void fp_nop(void) 87void fp_nop(void)
90{ 88{
91 (fp_nop_table[FPU_rm])(); 89 (fp_nop_table[FPU_rm]) ();
92} 90}
93 91
94
95void fld_i_(void) 92void fld_i_(void)
96{ 93{
97 FPU_REG *st_new_ptr; 94 FPU_REG *st_new_ptr;
98 int i; 95 int i;
99 u_char tag; 96 u_char tag;
100 97
101 if ( STACK_OVERFLOW ) 98 if (STACK_OVERFLOW) {
102 { FPU_stack_overflow(); return; } 99 FPU_stack_overflow();
103 100 return;
104 /* fld st(i) */
105 i = FPU_rm;
106 if ( NOT_EMPTY(i) )
107 {
108 reg_copy(&st(i), st_new_ptr);
109 tag = FPU_gettagi(i);
110 push();
111 FPU_settag0(tag);
112 }
113 else
114 {
115 if ( control_word & CW_Invalid )
116 {
117 /* The masked response */
118 FPU_stack_underflow();
119 } 101 }
120 else
121 EXCEPTION(EX_StackUnder);
122 }
123 102
124} 103 /* fld st(i) */
104 i = FPU_rm;
105 if (NOT_EMPTY(i)) {
106 reg_copy(&st(i), st_new_ptr);
107 tag = FPU_gettagi(i);
108 push();
109 FPU_settag0(tag);
110 } else {
111 if (control_word & CW_Invalid) {
112 /* The masked response */
113 FPU_stack_underflow();
114 } else
115 EXCEPTION(EX_StackUnder);
116 }
125 117
118}
126 119
127void fxch_i(void) 120void fxch_i(void)
128{ 121{
129 /* fxch st(i) */ 122 /* fxch st(i) */
130 FPU_REG t; 123 FPU_REG t;
131 int i = FPU_rm; 124 int i = FPU_rm;
132 FPU_REG *st0_ptr = &st(0), *sti_ptr = &st(i); 125 FPU_REG *st0_ptr = &st(0), *sti_ptr = &st(i);
133 long tag_word = fpu_tag_word; 126 long tag_word = fpu_tag_word;
134 int regnr = top & 7, regnri = ((regnr + i) & 7); 127 int regnr = top & 7, regnri = ((regnr + i) & 7);
135 u_char st0_tag = (tag_word >> (regnr*2)) & 3; 128 u_char st0_tag = (tag_word >> (regnr * 2)) & 3;
136 u_char sti_tag = (tag_word >> (regnri*2)) & 3; 129 u_char sti_tag = (tag_word >> (regnri * 2)) & 3;
137 130
138 if ( st0_tag == TAG_Empty ) 131 if (st0_tag == TAG_Empty) {
139 { 132 if (sti_tag == TAG_Empty) {
140 if ( sti_tag == TAG_Empty ) 133 FPU_stack_underflow();
141 { 134 FPU_stack_underflow_i(i);
142 FPU_stack_underflow(); 135 return;
143 FPU_stack_underflow_i(i); 136 }
144 return; 137 if (control_word & CW_Invalid) {
138 /* Masked response */
139 FPU_copy_to_reg0(sti_ptr, sti_tag);
140 }
141 FPU_stack_underflow_i(i);
142 return;
145 } 143 }
146 if ( control_word & CW_Invalid ) 144 if (sti_tag == TAG_Empty) {
147 { 145 if (control_word & CW_Invalid) {
148 /* Masked response */ 146 /* Masked response */
149 FPU_copy_to_reg0(sti_ptr, sti_tag); 147 FPU_copy_to_regi(st0_ptr, st0_tag, i);
148 }
149 FPU_stack_underflow();
150 return;
150 } 151 }
151 FPU_stack_underflow_i(i); 152 clear_C1();
152 return;
153 }
154 if ( sti_tag == TAG_Empty )
155 {
156 if ( control_word & CW_Invalid )
157 {
158 /* Masked response */
159 FPU_copy_to_regi(st0_ptr, st0_tag, i);
160 }
161 FPU_stack_underflow();
162 return;
163 }
164 clear_C1();
165
166 reg_copy(st0_ptr, &t);
167 reg_copy(sti_ptr, st0_ptr);
168 reg_copy(&t, sti_ptr);
169
170 tag_word &= ~(3 << (regnr*2)) & ~(3 << (regnri*2));
171 tag_word |= (sti_tag << (regnr*2)) | (st0_tag << (regnri*2));
172 fpu_tag_word = tag_word;
173}
174 153
154 reg_copy(st0_ptr, &t);
155 reg_copy(sti_ptr, st0_ptr);
156 reg_copy(&t, sti_ptr);
157
158 tag_word &= ~(3 << (regnr * 2)) & ~(3 << (regnri * 2));
159 tag_word |= (sti_tag << (regnr * 2)) | (st0_tag << (regnri * 2));
160 fpu_tag_word = tag_word;
161}
175 162
176void ffree_(void) 163void ffree_(void)
177{ 164{
178 /* ffree st(i) */ 165 /* ffree st(i) */
179 FPU_settagi(FPU_rm, TAG_Empty); 166 FPU_settagi(FPU_rm, TAG_Empty);
180} 167}
181 168
182
183void ffreep(void) 169void ffreep(void)
184{ 170{
185 /* ffree st(i) + pop - unofficial code */ 171 /* ffree st(i) + pop - unofficial code */
186 FPU_settagi(FPU_rm, TAG_Empty); 172 FPU_settagi(FPU_rm, TAG_Empty);
187 FPU_pop(); 173 FPU_pop();
188} 174}
189 175
190
191void fst_i_(void) 176void fst_i_(void)
192{ 177{
193 /* fst st(i) */ 178 /* fst st(i) */
194 FPU_copy_to_regi(&st(0), FPU_gettag0(), FPU_rm); 179 FPU_copy_to_regi(&st(0), FPU_gettag0(), FPU_rm);
195} 180}
196 181
197
198void fstp_i(void) 182void fstp_i(void)
199{ 183{
200 /* fstp st(i) */ 184 /* fstp st(i) */
201 FPU_copy_to_regi(&st(0), FPU_gettag0(), FPU_rm); 185 FPU_copy_to_regi(&st(0), FPU_gettag0(), FPU_rm);
202 FPU_pop(); 186 FPU_pop();
203} 187}
204
diff --git a/arch/x86/math-emu/fpu_emu.h b/arch/x86/math-emu/fpu_emu.h
index 65120f523853..656dd4c04b1b 100644
--- a/arch/x86/math-emu/fpu_emu.h
+++ b/arch/x86/math-emu/fpu_emu.h
@@ -7,7 +7,6 @@
7 | | 7 | |
8 +---------------------------------------------------------------------------*/ 8 +---------------------------------------------------------------------------*/
9 9
10
11#ifndef _FPU_EMU_H_ 10#ifndef _FPU_EMU_H_
12#define _FPU_EMU_H_ 11#define _FPU_EMU_H_
13 12
@@ -28,15 +27,15 @@
28#endif 27#endif
29 28
30#define EXP_BIAS Const(0) 29#define EXP_BIAS Const(0)
31#define EXP_OVER Const(0x4000) /* smallest invalid large exponent */ 30#define EXP_OVER Const(0x4000) /* smallest invalid large exponent */
32#define EXP_UNDER Const(-0x3fff) /* largest invalid small exponent */ 31#define EXP_UNDER Const(-0x3fff) /* largest invalid small exponent */
33#define EXP_WAY_UNDER Const(-0x6000) /* Below the smallest denormal, but 32#define EXP_WAY_UNDER Const(-0x6000) /* Below the smallest denormal, but
34 still a 16 bit nr. */ 33 still a 16 bit nr. */
35#define EXP_Infinity EXP_OVER 34#define EXP_Infinity EXP_OVER
36#define EXP_NaN EXP_OVER 35#define EXP_NaN EXP_OVER
37 36
38#define EXTENDED_Ebias Const(0x3fff) 37#define EXTENDED_Ebias Const(0x3fff)
39#define EXTENDED_Emin (-0x3ffe) /* smallest valid exponent */ 38#define EXTENDED_Emin (-0x3ffe) /* smallest valid exponent */
40 39
41#define SIGN_POS Const(0) 40#define SIGN_POS Const(0)
42#define SIGN_NEG Const(0x80) 41#define SIGN_NEG Const(0x80)
@@ -44,10 +43,9 @@
44#define SIGN_Positive Const(0) 43#define SIGN_Positive Const(0)
45#define SIGN_Negative Const(0x8000) 44#define SIGN_Negative Const(0x8000)
46 45
47
48/* Keep the order TAG_Valid, TAG_Zero, TW_Denormal */ 46/* Keep the order TAG_Valid, TAG_Zero, TW_Denormal */
49/* The following fold to 2 (Special) in the Tag Word */ 47/* The following fold to 2 (Special) in the Tag Word */
50#define TW_Denormal Const(4) /* De-normal */ 48#define TW_Denormal Const(4) /* De-normal */
51#define TW_Infinity Const(5) /* + or - infinity */ 49#define TW_Infinity Const(5) /* + or - infinity */
52#define TW_NaN Const(6) /* Not a Number */ 50#define TW_NaN Const(6) /* Not a Number */
53#define TW_Unsupported Const(7) /* Not supported by an 80486 */ 51#define TW_Unsupported Const(7) /* Not supported by an 80486 */
@@ -67,14 +65,13 @@
67#define DEST_RM 0x20 65#define DEST_RM 0x20
68#define LOADED 0x40 66#define LOADED 0x40
69 67
70#define FPU_Exception Const(0x80000000) /* Added to tag returns. */ 68#define FPU_Exception Const(0x80000000) /* Added to tag returns. */
71
72 69
73#ifndef __ASSEMBLY__ 70#ifndef __ASSEMBLY__
74 71
75#include "fpu_system.h" 72#include "fpu_system.h"
76 73
77#include <asm/sigcontext.h> /* for struct _fpstate */ 74#include <asm/sigcontext.h> /* for struct _fpstate */
78#include <asm/math_emu.h> 75#include <asm/math_emu.h>
79#include <linux/linkage.h> 76#include <linux/linkage.h>
80 77
@@ -112,30 +109,33 @@ extern u_char emulating;
112#define PREFIX_DEFAULT 7 109#define PREFIX_DEFAULT 7
113 110
114struct address { 111struct address {
115 unsigned int offset; 112 unsigned int offset;
116 unsigned int selector:16; 113 unsigned int selector:16;
117 unsigned int opcode:11; 114 unsigned int opcode:11;
118 unsigned int empty:5; 115 unsigned int empty:5;
119}; 116};
120struct fpu__reg { 117struct fpu__reg {
121 unsigned sigl; 118 unsigned sigl;
122 unsigned sigh; 119 unsigned sigh;
123 short exp; 120 short exp;
124}; 121};
125 122
126typedef void (*FUNC)(void); 123typedef void (*FUNC) (void);
127typedef struct fpu__reg FPU_REG; 124typedef struct fpu__reg FPU_REG;
128typedef void (*FUNC_ST0)(FPU_REG *st0_ptr, u_char st0_tag); 125typedef void (*FUNC_ST0) (FPU_REG * st0_ptr, u_char st0_tag);
129typedef struct { u_char address_size, operand_size, segment; } 126typedef struct {
130 overrides; 127 u_char address_size, operand_size, segment;
128} overrides;
131/* This structure is 32 bits: */ 129/* This structure is 32 bits: */
132typedef struct { overrides override; 130typedef struct {
133 u_char default_mode; } fpu_addr_modes; 131 overrides override;
132 u_char default_mode;
133} fpu_addr_modes;
134/* PROTECTED has a restricted meaning in the emulator; it is used 134/* PROTECTED has a restricted meaning in the emulator; it is used
135 to signal that the emulator needs to do special things to ensure 135 to signal that the emulator needs to do special things to ensure
136 that protection is respected in a segmented model. */ 136 that protection is respected in a segmented model. */
137#define PROTECTED 4 137#define PROTECTED 4
138#define SIXTEEN 1 /* We rely upon this being 1 (true) */ 138#define SIXTEEN 1 /* We rely upon this being 1 (true) */
139#define VM86 SIXTEEN 139#define VM86 SIXTEEN
140#define PM16 (SIXTEEN | PROTECTED) 140#define PM16 (SIXTEEN | PROTECTED)
141#define SEG32 PROTECTED 141#define SEG32 PROTECTED
@@ -166,10 +166,10 @@ extern u_char const data_sizes_16[32];
166#define signpositive(a) ( (signbyte(a) & 0x80) == 0 ) 166#define signpositive(a) ( (signbyte(a) & 0x80) == 0 )
167#define signnegative(a) (signbyte(a) & 0x80) 167#define signnegative(a) (signbyte(a) & 0x80)
168 168
169static inline void reg_copy(FPU_REG const *x, FPU_REG *y) 169static inline void reg_copy(FPU_REG const *x, FPU_REG * y)
170{ 170{
171 *(short *)&(y->exp) = *(const short *)&(x->exp); 171 *(short *)&(y->exp) = *(const short *)&(x->exp);
172 *(long long *)&(y->sigl) = *(const long long *)&(x->sigl); 172 *(long long *)&(y->sigl) = *(const long long *)&(x->sigl);
173} 173}
174 174
175#define exponent(x) (((*(short *)&((x)->exp)) & 0x7fff) - EXTENDED_Ebias) 175#define exponent(x) (((*(short *)&((x)->exp)) & 0x7fff) - EXTENDED_Ebias)
@@ -184,29 +184,28 @@ static inline void reg_copy(FPU_REG const *x, FPU_REG *y)
184 184
185#define significand(x) ( ((unsigned long long *)&((x)->sigl))[0] ) 185#define significand(x) ( ((unsigned long long *)&((x)->sigl))[0] )
186 186
187
188/*----- Prototypes for functions written in assembler -----*/ 187/*----- Prototypes for functions written in assembler -----*/
189/* extern void reg_move(FPU_REG *a, FPU_REG *b); */ 188/* extern void reg_move(FPU_REG *a, FPU_REG *b); */
190 189
191asmlinkage int FPU_normalize(FPU_REG *x); 190asmlinkage int FPU_normalize(FPU_REG * x);
192asmlinkage int FPU_normalize_nuo(FPU_REG *x); 191asmlinkage int FPU_normalize_nuo(FPU_REG * x);
193asmlinkage int FPU_u_sub(FPU_REG const *arg1, FPU_REG const *arg2, 192asmlinkage int FPU_u_sub(FPU_REG const *arg1, FPU_REG const *arg2,
194 FPU_REG *answ, unsigned int control_w, u_char sign, 193 FPU_REG * answ, unsigned int control_w, u_char sign,
195 int expa, int expb); 194 int expa, int expb);
196asmlinkage int FPU_u_mul(FPU_REG const *arg1, FPU_REG const *arg2, 195asmlinkage int FPU_u_mul(FPU_REG const *arg1, FPU_REG const *arg2,
197 FPU_REG *answ, unsigned int control_w, u_char sign, 196 FPU_REG * answ, unsigned int control_w, u_char sign,
198 int expon); 197 int expon);
199asmlinkage int FPU_u_div(FPU_REG const *arg1, FPU_REG const *arg2, 198asmlinkage int FPU_u_div(FPU_REG const *arg1, FPU_REG const *arg2,
200 FPU_REG *answ, unsigned int control_w, u_char sign); 199 FPU_REG * answ, unsigned int control_w, u_char sign);
201asmlinkage int FPU_u_add(FPU_REG const *arg1, FPU_REG const *arg2, 200asmlinkage int FPU_u_add(FPU_REG const *arg1, FPU_REG const *arg2,
202 FPU_REG *answ, unsigned int control_w, u_char sign, 201 FPU_REG * answ, unsigned int control_w, u_char sign,
203 int expa, int expb); 202 int expa, int expb);
204asmlinkage int wm_sqrt(FPU_REG *n, int dummy1, int dummy2, 203asmlinkage int wm_sqrt(FPU_REG * n, int dummy1, int dummy2,
205 unsigned int control_w, u_char sign); 204 unsigned int control_w, u_char sign);
206asmlinkage unsigned FPU_shrx(void *l, unsigned x); 205asmlinkage unsigned FPU_shrx(void *l, unsigned x);
207asmlinkage unsigned FPU_shrxs(void *v, unsigned x); 206asmlinkage unsigned FPU_shrxs(void *v, unsigned x);
208asmlinkage unsigned long FPU_div_small(unsigned long long *x, unsigned long y); 207asmlinkage unsigned long FPU_div_small(unsigned long long *x, unsigned long y);
209asmlinkage int FPU_round(FPU_REG *arg, unsigned int extent, int dummy, 208asmlinkage int FPU_round(FPU_REG * arg, unsigned int extent, int dummy,
210 unsigned int control_w, u_char sign); 209 unsigned int control_w, u_char sign);
211 210
212#ifndef MAKING_PROTO 211#ifndef MAKING_PROTO
diff --git a/arch/x86/math-emu/fpu_entry.c b/arch/x86/math-emu/fpu_entry.c
index 1853524c8b57..cbb8717f09fd 100644
--- a/arch/x86/math-emu/fpu_entry.c
+++ b/arch/x86/math-emu/fpu_entry.c
@@ -36,726 +36,720 @@
36#include "control_w.h" 36#include "control_w.h"
37#include "status_w.h" 37#include "status_w.h"
38 38
39#define __BAD__ FPU_illegal /* Illegal on an 80486, causes SIGILL */ 39#define __BAD__ FPU_illegal /* Illegal on an 80486, causes SIGILL */
40 40
41#ifndef NO_UNDOC_CODE /* Un-documented FPU op-codes supported by default. */ 41#ifndef NO_UNDOC_CODE /* Un-documented FPU op-codes supported by default. */
42 42
43/* WARNING: These codes are not documented by Intel in their 80486 manual 43/* WARNING: These codes are not documented by Intel in their 80486 manual
44 and may not work on FPU clones or later Intel FPUs. */ 44 and may not work on FPU clones or later Intel FPUs. */
45 45
46/* Changes to support the un-doc codes provided by Linus Torvalds. */ 46/* Changes to support the un-doc codes provided by Linus Torvalds. */
47 47
48#define _d9_d8_ fstp_i /* unofficial code (19) */ 48#define _d9_d8_ fstp_i /* unofficial code (19) */
49#define _dc_d0_ fcom_st /* unofficial code (14) */ 49#define _dc_d0_ fcom_st /* unofficial code (14) */
50#define _dc_d8_ fcompst /* unofficial code (1c) */ 50#define _dc_d8_ fcompst /* unofficial code (1c) */
51#define _dd_c8_ fxch_i /* unofficial code (0d) */ 51#define _dd_c8_ fxch_i /* unofficial code (0d) */
52#define _de_d0_ fcompst /* unofficial code (16) */ 52#define _de_d0_ fcompst /* unofficial code (16) */
53#define _df_c0_ ffreep /* unofficial code (07) ffree + pop */ 53#define _df_c0_ ffreep /* unofficial code (07) ffree + pop */
54#define _df_c8_ fxch_i /* unofficial code (0f) */ 54#define _df_c8_ fxch_i /* unofficial code (0f) */
55#define _df_d0_ fstp_i /* unofficial code (17) */ 55#define _df_d0_ fstp_i /* unofficial code (17) */
56#define _df_d8_ fstp_i /* unofficial code (1f) */ 56#define _df_d8_ fstp_i /* unofficial code (1f) */
57 57
58static FUNC const st_instr_table[64] = { 58static FUNC const st_instr_table[64] = {
59 fadd__, fld_i_, __BAD__, __BAD__, fadd_i, ffree_, faddp_, _df_c0_, 59 fadd__, fld_i_, __BAD__, __BAD__, fadd_i, ffree_, faddp_, _df_c0_,
60 fmul__, fxch_i, __BAD__, __BAD__, fmul_i, _dd_c8_, fmulp_, _df_c8_, 60 fmul__, fxch_i, __BAD__, __BAD__, fmul_i, _dd_c8_, fmulp_, _df_c8_,
61 fcom_st, fp_nop, __BAD__, __BAD__, _dc_d0_, fst_i_, _de_d0_, _df_d0_, 61 fcom_st, fp_nop, __BAD__, __BAD__, _dc_d0_, fst_i_, _de_d0_, _df_d0_,
62 fcompst, _d9_d8_, __BAD__, __BAD__, _dc_d8_, fstp_i, fcompp, _df_d8_, 62 fcompst, _d9_d8_, __BAD__, __BAD__, _dc_d8_, fstp_i, fcompp, _df_d8_,
63 fsub__, FPU_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_, 63 fsub__, FPU_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_,
64 fsubr_, fconst, fucompp, __BAD__, fsub_i, fucomp, fsubp_, __BAD__, 64 fsubr_, fconst, fucompp, __BAD__, fsub_i, fucomp, fsubp_, __BAD__,
65 fdiv__, FPU_triga, __BAD__, __BAD__, fdivri, __BAD__, fdivrp, __BAD__, 65 fdiv__, FPU_triga, __BAD__, __BAD__, fdivri, __BAD__, fdivrp, __BAD__,
66 fdivr_, FPU_trigb, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__, 66 fdivr_, FPU_trigb, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__,
67}; 67};
68 68
69#else /* Support only documented FPU op-codes */ 69#else /* Support only documented FPU op-codes */
70 70
71static FUNC const st_instr_table[64] = { 71static FUNC const st_instr_table[64] = {
72 fadd__, fld_i_, __BAD__, __BAD__, fadd_i, ffree_, faddp_, __BAD__, 72 fadd__, fld_i_, __BAD__, __BAD__, fadd_i, ffree_, faddp_, __BAD__,
73 fmul__, fxch_i, __BAD__, __BAD__, fmul_i, __BAD__, fmulp_, __BAD__, 73 fmul__, fxch_i, __BAD__, __BAD__, fmul_i, __BAD__, fmulp_, __BAD__,
74 fcom_st, fp_nop, __BAD__, __BAD__, __BAD__, fst_i_, __BAD__, __BAD__, 74 fcom_st, fp_nop, __BAD__, __BAD__, __BAD__, fst_i_, __BAD__, __BAD__,
75 fcompst, __BAD__, __BAD__, __BAD__, __BAD__, fstp_i, fcompp, __BAD__, 75 fcompst, __BAD__, __BAD__, __BAD__, __BAD__, fstp_i, fcompp, __BAD__,
76 fsub__, FPU_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_, 76 fsub__, FPU_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_,
77 fsubr_, fconst, fucompp, __BAD__, fsub_i, fucomp, fsubp_, __BAD__, 77 fsubr_, fconst, fucompp, __BAD__, fsub_i, fucomp, fsubp_, __BAD__,
78 fdiv__, FPU_triga, __BAD__, __BAD__, fdivri, __BAD__, fdivrp, __BAD__, 78 fdiv__, FPU_triga, __BAD__, __BAD__, fdivri, __BAD__, fdivrp, __BAD__,
79 fdivr_, FPU_trigb, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__, 79 fdivr_, FPU_trigb, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__,
80}; 80};
81 81
82#endif /* NO_UNDOC_CODE */ 82#endif /* NO_UNDOC_CODE */
83 83
84 84#define _NONE_ 0 /* Take no special action */
85#define _NONE_ 0 /* Take no special action */ 85#define _REG0_ 1 /* Need to check for not empty st(0) */
86#define _REG0_ 1 /* Need to check for not empty st(0) */ 86#define _REGI_ 2 /* Need to check for not empty st(0) and st(rm) */
87#define _REGI_ 2 /* Need to check for not empty st(0) and st(rm) */ 87#define _REGi_ 0 /* Uses st(rm) */
88#define _REGi_ 0 /* Uses st(rm) */ 88#define _PUSH_ 3 /* Need to check for space to push onto stack */
89#define _PUSH_ 3 /* Need to check for space to push onto stack */ 89#define _null_ 4 /* Function illegal or not implemented */
90#define _null_ 4 /* Function illegal or not implemented */ 90#define _REGIi 5 /* Uses st(0) and st(rm), result to st(rm) */
91#define _REGIi 5 /* Uses st(0) and st(rm), result to st(rm) */ 91#define _REGIp 6 /* Uses st(0) and st(rm), result to st(rm) then pop */
92#define _REGIp 6 /* Uses st(0) and st(rm), result to st(rm) then pop */ 92#define _REGIc 0 /* Compare st(0) and st(rm) */
93#define _REGIc 0 /* Compare st(0) and st(rm) */ 93#define _REGIn 0 /* Uses st(0) and st(rm), but handle checks later */
94#define _REGIn 0 /* Uses st(0) and st(rm), but handle checks later */
95 94
96#ifndef NO_UNDOC_CODE 95#ifndef NO_UNDOC_CODE
97 96
98/* Un-documented FPU op-codes supported by default. (see above) */ 97/* Un-documented FPU op-codes supported by default. (see above) */
99 98
100static u_char const type_table[64] = { 99static u_char const type_table[64] = {
101 _REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _REGi_, 100 _REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _REGi_,
102 _REGI_, _REGIn, _null_, _null_, _REGIi, _REGI_, _REGIp, _REGI_, 101 _REGI_, _REGIn, _null_, _null_, _REGIi, _REGI_, _REGIp, _REGI_,
103 _REGIc, _NONE_, _null_, _null_, _REGIc, _REG0_, _REGIc, _REG0_, 102 _REGIc, _NONE_, _null_, _null_, _REGIc, _REG0_, _REGIc, _REG0_,
104 _REGIc, _REG0_, _null_, _null_, _REGIc, _REG0_, _REGIc, _REG0_, 103 _REGIc, _REG0_, _null_, _null_, _REGIc, _REG0_, _REGIc, _REG0_,
105 _REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_, 104 _REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_,
106 _REGI_, _NONE_, _REGIc, _null_, _REGIi, _REGIc, _REGIp, _null_, 105 _REGI_, _NONE_, _REGIc, _null_, _REGIi, _REGIc, _REGIp, _null_,
107 _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_, 106 _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
108 _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_ 107 _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_
109}; 108};
110 109
111#else /* Support only documented FPU op-codes */ 110#else /* Support only documented FPU op-codes */
112 111
113static u_char const type_table[64] = { 112static u_char const type_table[64] = {
114 _REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _null_, 113 _REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _null_,
115 _REGI_, _REGIn, _null_, _null_, _REGIi, _null_, _REGIp, _null_, 114 _REGI_, _REGIn, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
116 _REGIc, _NONE_, _null_, _null_, _null_, _REG0_, _null_, _null_, 115 _REGIc, _NONE_, _null_, _null_, _null_, _REG0_, _null_, _null_,
117 _REGIc, _null_, _null_, _null_, _null_, _REG0_, _REGIc, _null_, 116 _REGIc, _null_, _null_, _null_, _null_, _REG0_, _REGIc, _null_,
118 _REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_, 117 _REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_,
119 _REGI_, _NONE_, _REGIc, _null_, _REGIi, _REGIc, _REGIp, _null_, 118 _REGI_, _NONE_, _REGIc, _null_, _REGIi, _REGIc, _REGIp, _null_,
120 _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_, 119 _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
121 _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_ 120 _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_
122}; 121};
123 122
124#endif /* NO_UNDOC_CODE */ 123#endif /* NO_UNDOC_CODE */
125 124
126
127#ifdef RE_ENTRANT_CHECKING 125#ifdef RE_ENTRANT_CHECKING
128u_char emulating=0; 126u_char emulating = 0;
129#endif /* RE_ENTRANT_CHECKING */ 127#endif /* RE_ENTRANT_CHECKING */
130 128
131static int valid_prefix(u_char *Byte, u_char __user **fpu_eip, 129static int valid_prefix(u_char * Byte, u_char __user ** fpu_eip,
132 overrides *override); 130 overrides * override);
133 131
134asmlinkage void math_emulate(long arg) 132asmlinkage void math_emulate(long arg)
135{ 133{
136 u_char FPU_modrm, byte1; 134 u_char FPU_modrm, byte1;
137 unsigned short code; 135 unsigned short code;
138 fpu_addr_modes addr_modes; 136 fpu_addr_modes addr_modes;
139 int unmasked; 137 int unmasked;
140 FPU_REG loaded_data; 138 FPU_REG loaded_data;
141 FPU_REG *st0_ptr; 139 FPU_REG *st0_ptr;
142 u_char loaded_tag, st0_tag; 140 u_char loaded_tag, st0_tag;
143 void __user *data_address; 141 void __user *data_address;
144 struct address data_sel_off; 142 struct address data_sel_off;
145 struct address entry_sel_off; 143 struct address entry_sel_off;
146 unsigned long code_base = 0; 144 unsigned long code_base = 0;
147 unsigned long code_limit = 0; /* Initialized to stop compiler warnings */ 145 unsigned long code_limit = 0; /* Initialized to stop compiler warnings */
148 struct desc_struct code_descriptor; 146 struct desc_struct code_descriptor;
149 147
150#ifdef RE_ENTRANT_CHECKING 148#ifdef RE_ENTRANT_CHECKING
151 if ( emulating ) 149 if (emulating) {
152 { 150 printk("ERROR: wm-FPU-emu is not RE-ENTRANT!\n");
153 printk("ERROR: wm-FPU-emu is not RE-ENTRANT!\n"); 151 }
154 } 152 RE_ENTRANT_CHECK_ON;
155 RE_ENTRANT_CHECK_ON;
156#endif /* RE_ENTRANT_CHECKING */ 153#endif /* RE_ENTRANT_CHECKING */
157 154
158 if (!used_math()) 155 if (!used_math()) {
159 { 156 finit();
160 finit(); 157 set_used_math();
161 set_used_math();
162 }
163
164 SETUP_DATA_AREA(arg);
165
166 FPU_ORIG_EIP = FPU_EIP;
167
168 if ( (FPU_EFLAGS & 0x00020000) != 0 )
169 {
170 /* Virtual 8086 mode */
171 addr_modes.default_mode = VM86;
172 FPU_EIP += code_base = FPU_CS << 4;
173 code_limit = code_base + 0xffff; /* Assumes code_base <= 0xffff0000 */
174 }
175 else if ( FPU_CS == __USER_CS && FPU_DS == __USER_DS )
176 {
177 addr_modes.default_mode = 0;
178 }
179 else if ( FPU_CS == __KERNEL_CS )
180 {
181 printk("math_emulate: %04x:%08lx\n",FPU_CS,FPU_EIP);
182 panic("Math emulation needed in kernel");
183 }
184 else
185 {
186
187 if ( (FPU_CS & 4) != 4 ) /* Must be in the LDT */
188 {
189 /* Can only handle segmented addressing via the LDT
190 for now, and it must be 16 bit */
191 printk("FPU emulator: Unsupported addressing mode\n");
192 math_abort(FPU_info, SIGILL);
193 } 158 }
194 159
195 code_descriptor = LDT_DESCRIPTOR(FPU_CS); 160 SETUP_DATA_AREA(arg);
196 if ( SEG_D_SIZE(code_descriptor) ) 161
197 { 162 FPU_ORIG_EIP = FPU_EIP;
198 /* The above test may be wrong, the book is not clear */ 163
199 /* Segmented 32 bit protected mode */ 164 if ((FPU_EFLAGS & 0x00020000) != 0) {
200 addr_modes.default_mode = SEG32; 165 /* Virtual 8086 mode */
166 addr_modes.default_mode = VM86;
167 FPU_EIP += code_base = FPU_CS << 4;
168 code_limit = code_base + 0xffff; /* Assumes code_base <= 0xffff0000 */
169 } else if (FPU_CS == __USER_CS && FPU_DS == __USER_DS) {
170 addr_modes.default_mode = 0;
171 } else if (FPU_CS == __KERNEL_CS) {
172 printk("math_emulate: %04x:%08lx\n", FPU_CS, FPU_EIP);
173 panic("Math emulation needed in kernel");
174 } else {
175
176 if ((FPU_CS & 4) != 4) { /* Must be in the LDT */
177 /* Can only handle segmented addressing via the LDT
178 for now, and it must be 16 bit */
179 printk("FPU emulator: Unsupported addressing mode\n");
180 math_abort(FPU_info, SIGILL);
181 }
182
183 code_descriptor = LDT_DESCRIPTOR(FPU_CS);
184 if (SEG_D_SIZE(code_descriptor)) {
185 /* The above test may be wrong, the book is not clear */
186 /* Segmented 32 bit protected mode */
187 addr_modes.default_mode = SEG32;
188 } else {
189 /* 16 bit protected mode */
190 addr_modes.default_mode = PM16;
191 }
192 FPU_EIP += code_base = SEG_BASE_ADDR(code_descriptor);
193 code_limit = code_base
194 + (SEG_LIMIT(code_descriptor) +
195 1) * SEG_GRANULARITY(code_descriptor)
196 - 1;
197 if (code_limit < code_base)
198 code_limit = 0xffffffff;
201 } 199 }
202 else 200
203 { 201 FPU_lookahead = 1;
204 /* 16 bit protected mode */ 202 if (current->ptrace & PT_PTRACED)
205 addr_modes.default_mode = PM16; 203 FPU_lookahead = 0;
204
205 if (!valid_prefix(&byte1, (u_char __user **) & FPU_EIP,
206 &addr_modes.override)) {
207 RE_ENTRANT_CHECK_OFF;
208 printk
209 ("FPU emulator: Unknown prefix byte 0x%02x, probably due to\n"
210 "FPU emulator: self-modifying code! (emulation impossible)\n",
211 byte1);
212 RE_ENTRANT_CHECK_ON;
213 EXCEPTION(EX_INTERNAL | 0x126);
214 math_abort(FPU_info, SIGILL);
206 } 215 }
207 FPU_EIP += code_base = SEG_BASE_ADDR(code_descriptor); 216
208 code_limit = code_base 217 do_another_FPU_instruction:
209 + (SEG_LIMIT(code_descriptor)+1) * SEG_GRANULARITY(code_descriptor) 218
210 - 1; 219 no_ip_update = 0;
211 if ( code_limit < code_base ) code_limit = 0xffffffff; 220
212 } 221 FPU_EIP++; /* We have fetched the prefix and first code bytes. */
213 222
214 FPU_lookahead = 1; 223 if (addr_modes.default_mode) {
215 if (current->ptrace & PT_PTRACED) 224 /* This checks for the minimum instruction bytes.
216 FPU_lookahead = 0; 225 We also need to check any extra (address mode) code access. */
217 226 if (FPU_EIP > code_limit)
218 if ( !valid_prefix(&byte1, (u_char __user **)&FPU_EIP, 227 math_abort(FPU_info, SIGSEGV);
219 &addr_modes.override) )
220 {
221 RE_ENTRANT_CHECK_OFF;
222 printk("FPU emulator: Unknown prefix byte 0x%02x, probably due to\n"
223 "FPU emulator: self-modifying code! (emulation impossible)\n",
224 byte1);
225 RE_ENTRANT_CHECK_ON;
226 EXCEPTION(EX_INTERNAL|0x126);
227 math_abort(FPU_info,SIGILL);
228 }
229
230do_another_FPU_instruction:
231
232 no_ip_update = 0;
233
234 FPU_EIP++; /* We have fetched the prefix and first code bytes. */
235
236 if ( addr_modes.default_mode )
237 {
238 /* This checks for the minimum instruction bytes.
239 We also need to check any extra (address mode) code access. */
240 if ( FPU_EIP > code_limit )
241 math_abort(FPU_info,SIGSEGV);
242 }
243
244 if ( (byte1 & 0xf8) != 0xd8 )
245 {
246 if ( byte1 == FWAIT_OPCODE )
247 {
248 if (partial_status & SW_Summary)
249 goto do_the_FPU_interrupt;
250 else
251 goto FPU_fwait_done;
252 } 228 }
229
230 if ((byte1 & 0xf8) != 0xd8) {
231 if (byte1 == FWAIT_OPCODE) {
232 if (partial_status & SW_Summary)
233 goto do_the_FPU_interrupt;
234 else
235 goto FPU_fwait_done;
236 }
253#ifdef PARANOID 237#ifdef PARANOID
254 EXCEPTION(EX_INTERNAL|0x128); 238 EXCEPTION(EX_INTERNAL | 0x128);
255 math_abort(FPU_info,SIGILL); 239 math_abort(FPU_info, SIGILL);
256#endif /* PARANOID */ 240#endif /* PARANOID */
257 }
258
259 RE_ENTRANT_CHECK_OFF;
260 FPU_code_access_ok(1);
261 FPU_get_user(FPU_modrm, (u_char __user *) FPU_EIP);
262 RE_ENTRANT_CHECK_ON;
263 FPU_EIP++;
264
265 if (partial_status & SW_Summary)
266 {
267 /* Ignore the error for now if the current instruction is a no-wait
268 control instruction */
269 /* The 80486 manual contradicts itself on this topic,
270 but a real 80486 uses the following instructions:
271 fninit, fnstenv, fnsave, fnstsw, fnstenv, fnclex.
272 */
273 code = (FPU_modrm << 8) | byte1;
274 if ( ! ( (((code & 0xf803) == 0xe003) || /* fnclex, fninit, fnstsw */
275 (((code & 0x3003) == 0x3001) && /* fnsave, fnstcw, fnstenv,
276 fnstsw */
277 ((code & 0xc000) != 0xc000))) ) )
278 {
279 /*
280 * We need to simulate the action of the kernel to FPU
281 * interrupts here.
282 */
283 do_the_FPU_interrupt:
284
285 FPU_EIP = FPU_ORIG_EIP; /* Point to current FPU instruction. */
286
287 RE_ENTRANT_CHECK_OFF;
288 current->thread.trap_no = 16;
289 current->thread.error_code = 0;
290 send_sig(SIGFPE, current, 1);
291 return;
292 }
293 }
294
295 entry_sel_off.offset = FPU_ORIG_EIP;
296 entry_sel_off.selector = FPU_CS;
297 entry_sel_off.opcode = (byte1 << 8) | FPU_modrm;
298
299 FPU_rm = FPU_modrm & 7;
300
301 if ( FPU_modrm < 0300 )
302 {
303 /* All of these instructions use the mod/rm byte to get a data address */
304
305 if ( (addr_modes.default_mode & SIXTEEN)
306 ^ (addr_modes.override.address_size == ADDR_SIZE_PREFIX) )
307 data_address = FPU_get_address_16(FPU_modrm, &FPU_EIP, &data_sel_off,
308 addr_modes);
309 else
310 data_address = FPU_get_address(FPU_modrm, &FPU_EIP, &data_sel_off,
311 addr_modes);
312
313 if ( addr_modes.default_mode )
314 {
315 if ( FPU_EIP-1 > code_limit )
316 math_abort(FPU_info,SIGSEGV);
317 } 241 }
318 242
319 if ( !(byte1 & 1) ) 243 RE_ENTRANT_CHECK_OFF;
320 { 244 FPU_code_access_ok(1);
321 unsigned short status1 = partial_status; 245 FPU_get_user(FPU_modrm, (u_char __user *) FPU_EIP);
322 246 RE_ENTRANT_CHECK_ON;
323 st0_ptr = &st(0); 247 FPU_EIP++;
324 st0_tag = FPU_gettag0(); 248
325 249 if (partial_status & SW_Summary) {
326 /* Stack underflow has priority */ 250 /* Ignore the error for now if the current instruction is a no-wait
327 if ( NOT_EMPTY_ST0 ) 251 control instruction */
328 { 252 /* The 80486 manual contradicts itself on this topic,
329 if ( addr_modes.default_mode & PROTECTED ) 253 but a real 80486 uses the following instructions:
330 { 254 fninit, fnstenv, fnsave, fnstsw, fnstenv, fnclex.
331 /* This table works for 16 and 32 bit protected mode */ 255 */
332 if ( access_limit < data_sizes_16[(byte1 >> 1) & 3] ) 256 code = (FPU_modrm << 8) | byte1;
333 math_abort(FPU_info,SIGSEGV); 257 if (!((((code & 0xf803) == 0xe003) || /* fnclex, fninit, fnstsw */
258 (((code & 0x3003) == 0x3001) && /* fnsave, fnstcw, fnstenv,
259 fnstsw */
260 ((code & 0xc000) != 0xc000))))) {
261 /*
262 * We need to simulate the action of the kernel to FPU
263 * interrupts here.
264 */
265 do_the_FPU_interrupt:
266
267 FPU_EIP = FPU_ORIG_EIP; /* Point to current FPU instruction. */
268
269 RE_ENTRANT_CHECK_OFF;
270 current->thread.trap_no = 16;
271 current->thread.error_code = 0;
272 send_sig(SIGFPE, current, 1);
273 return;
334 } 274 }
275 }
335 276
336 unmasked = 0; /* Do this here to stop compiler warnings. */ 277 entry_sel_off.offset = FPU_ORIG_EIP;
337 switch ( (byte1 >> 1) & 3 ) 278 entry_sel_off.selector = FPU_CS;
338 { 279 entry_sel_off.opcode = (byte1 << 8) | FPU_modrm;
339 case 0:
340 unmasked = FPU_load_single((float __user *)data_address,
341 &loaded_data);
342 loaded_tag = unmasked & 0xff;
343 unmasked &= ~0xff;
344 break;
345 case 1:
346 loaded_tag = FPU_load_int32((long __user *)data_address, &loaded_data);
347 break;
348 case 2:
349 unmasked = FPU_load_double((double __user *)data_address,
350 &loaded_data);
351 loaded_tag = unmasked & 0xff;
352 unmasked &= ~0xff;
353 break;
354 case 3:
355 default: /* Used here to suppress gcc warnings. */
356 loaded_tag = FPU_load_int16((short __user *)data_address, &loaded_data);
357 break;
358 }
359 280
360 /* No more access to user memory, it is safe 281 FPU_rm = FPU_modrm & 7;
361 to use static data now */
362
363 /* NaN operands have the next priority. */
364 /* We have to delay looking at st(0) until after
365 loading the data, because that data might contain an SNaN */
366 if ( ((st0_tag == TAG_Special) && isNaN(st0_ptr)) ||
367 ((loaded_tag == TAG_Special) && isNaN(&loaded_data)) )
368 {
369 /* Restore the status word; we might have loaded a
370 denormal. */
371 partial_status = status1;
372 if ( (FPU_modrm & 0x30) == 0x10 )
373 {
374 /* fcom or fcomp */
375 EXCEPTION(EX_Invalid);
376 setcc(SW_C3 | SW_C2 | SW_C0);
377 if ( (FPU_modrm & 0x08) && (control_word & CW_Invalid) )
378 FPU_pop(); /* fcomp, masked, so we pop. */
379 }
380 else
381 {
382 if ( loaded_tag == TAG_Special )
383 loaded_tag = FPU_Special(&loaded_data);
384#ifdef PECULIAR_486
385 /* This is not really needed, but gives behaviour
386 identical to an 80486 */
387 if ( (FPU_modrm & 0x28) == 0x20 )
388 /* fdiv or fsub */
389 real_2op_NaN(&loaded_data, loaded_tag, 0, &loaded_data);
390 else
391#endif /* PECULIAR_486 */
392 /* fadd, fdivr, fmul, or fsubr */
393 real_2op_NaN(&loaded_data, loaded_tag, 0, st0_ptr);
394 }
395 goto reg_mem_instr_done;
396 }
397 282
398 if ( unmasked && !((FPU_modrm & 0x30) == 0x10) ) 283 if (FPU_modrm < 0300) {
399 { 284 /* All of these instructions use the mod/rm byte to get a data address */
400 /* Is not a comparison instruction. */
401 if ( (FPU_modrm & 0x38) == 0x38 )
402 {
403 /* fdivr */
404 if ( (st0_tag == TAG_Zero) &&
405 ((loaded_tag == TAG_Valid)
406 || (loaded_tag == TAG_Special
407 && isdenormal(&loaded_data))) )
408 {
409 if ( FPU_divide_by_zero(0, getsign(&loaded_data))
410 < 0 )
411 {
412 /* We use the fact here that the unmasked
413 exception in the loaded data was for a
414 denormal operand */
415 /* Restore the state of the denormal op bit */
416 partial_status &= ~SW_Denorm_Op;
417 partial_status |= status1 & SW_Denorm_Op;
418 }
419 else
420 setsign(st0_ptr, getsign(&loaded_data));
421 }
422 }
423 goto reg_mem_instr_done;
424 }
425 285
426 switch ( (FPU_modrm >> 3) & 7 ) 286 if ((addr_modes.default_mode & SIXTEEN)
427 { 287 ^ (addr_modes.override.address_size == ADDR_SIZE_PREFIX))
428 case 0: /* fadd */ 288 data_address =
429 clear_C1(); 289 FPU_get_address_16(FPU_modrm, &FPU_EIP,
430 FPU_add(&loaded_data, loaded_tag, 0, control_word); 290 &data_sel_off, addr_modes);
431 break; 291 else
432 case 1: /* fmul */ 292 data_address =
433 clear_C1(); 293 FPU_get_address(FPU_modrm, &FPU_EIP, &data_sel_off,
434 FPU_mul(&loaded_data, loaded_tag, 0, control_word); 294 addr_modes);
435 break; 295
436 case 2: /* fcom */ 296 if (addr_modes.default_mode) {
437 FPU_compare_st_data(&loaded_data, loaded_tag); 297 if (FPU_EIP - 1 > code_limit)
438 break; 298 math_abort(FPU_info, SIGSEGV);
439 case 3: /* fcomp */
440 if ( !FPU_compare_st_data(&loaded_data, loaded_tag)
441 && !unmasked )
442 FPU_pop();
443 break;
444 case 4: /* fsub */
445 clear_C1();
446 FPU_sub(LOADED|loaded_tag, (int)&loaded_data, control_word);
447 break;
448 case 5: /* fsubr */
449 clear_C1();
450 FPU_sub(REV|LOADED|loaded_tag, (int)&loaded_data, control_word);
451 break;
452 case 6: /* fdiv */
453 clear_C1();
454 FPU_div(LOADED|loaded_tag, (int)&loaded_data, control_word);
455 break;
456 case 7: /* fdivr */
457 clear_C1();
458 if ( st0_tag == TAG_Zero )
459 partial_status = status1; /* Undo any denorm tag,
460 zero-divide has priority. */
461 FPU_div(REV|LOADED|loaded_tag, (int)&loaded_data, control_word);
462 break;
463 } 299 }
464 } 300
465 else 301 if (!(byte1 & 1)) {
466 { 302 unsigned short status1 = partial_status;
467 if ( (FPU_modrm & 0x30) == 0x10 ) 303
468 { 304 st0_ptr = &st(0);
469 /* The instruction is fcom or fcomp */ 305 st0_tag = FPU_gettag0();
470 EXCEPTION(EX_StackUnder); 306
471 setcc(SW_C3 | SW_C2 | SW_C0); 307 /* Stack underflow has priority */
472 if ( (FPU_modrm & 0x08) && (control_word & CW_Invalid) ) 308 if (NOT_EMPTY_ST0) {
473 FPU_pop(); /* fcomp */ 309 if (addr_modes.default_mode & PROTECTED) {
310 /* This table works for 16 and 32 bit protected mode */
311 if (access_limit <
312 data_sizes_16[(byte1 >> 1) & 3])
313 math_abort(FPU_info, SIGSEGV);
314 }
315
316 unmasked = 0; /* Do this here to stop compiler warnings. */
317 switch ((byte1 >> 1) & 3) {
318 case 0:
319 unmasked =
320 FPU_load_single((float __user *)
321 data_address,
322 &loaded_data);
323 loaded_tag = unmasked & 0xff;
324 unmasked &= ~0xff;
325 break;
326 case 1:
327 loaded_tag =
328 FPU_load_int32((long __user *)
329 data_address,
330 &loaded_data);
331 break;
332 case 2:
333 unmasked =
334 FPU_load_double((double __user *)
335 data_address,
336 &loaded_data);
337 loaded_tag = unmasked & 0xff;
338 unmasked &= ~0xff;
339 break;
340 case 3:
341 default: /* Used here to suppress gcc warnings. */
342 loaded_tag =
343 FPU_load_int16((short __user *)
344 data_address,
345 &loaded_data);
346 break;
347 }
348
349 /* No more access to user memory, it is safe
350 to use static data now */
351
352 /* NaN operands have the next priority. */
353 /* We have to delay looking at st(0) until after
354 loading the data, because that data might contain an SNaN */
355 if (((st0_tag == TAG_Special) && isNaN(st0_ptr))
356 || ((loaded_tag == TAG_Special)
357 && isNaN(&loaded_data))) {
358 /* Restore the status word; we might have loaded a
359 denormal. */
360 partial_status = status1;
361 if ((FPU_modrm & 0x30) == 0x10) {
362 /* fcom or fcomp */
363 EXCEPTION(EX_Invalid);
364 setcc(SW_C3 | SW_C2 | SW_C0);
365 if ((FPU_modrm & 0x08)
366 && (control_word &
367 CW_Invalid))
368 FPU_pop(); /* fcomp, masked, so we pop. */
369 } else {
370 if (loaded_tag == TAG_Special)
371 loaded_tag =
372 FPU_Special
373 (&loaded_data);
374#ifdef PECULIAR_486
375 /* This is not really needed, but gives behaviour
376 identical to an 80486 */
377 if ((FPU_modrm & 0x28) == 0x20)
378 /* fdiv or fsub */
379 real_2op_NaN
380 (&loaded_data,
381 loaded_tag, 0,
382 &loaded_data);
383 else
384#endif /* PECULIAR_486 */
385 /* fadd, fdivr, fmul, or fsubr */
386 real_2op_NaN
387 (&loaded_data,
388 loaded_tag, 0,
389 st0_ptr);
390 }
391 goto reg_mem_instr_done;
392 }
393
394 if (unmasked && !((FPU_modrm & 0x30) == 0x10)) {
395 /* Is not a comparison instruction. */
396 if ((FPU_modrm & 0x38) == 0x38) {
397 /* fdivr */
398 if ((st0_tag == TAG_Zero) &&
399 ((loaded_tag == TAG_Valid)
400 || (loaded_tag ==
401 TAG_Special
402 &&
403 isdenormal
404 (&loaded_data)))) {
405 if (FPU_divide_by_zero
406 (0,
407 getsign
408 (&loaded_data))
409 < 0) {
410 /* We use the fact here that the unmasked
411 exception in the loaded data was for a
412 denormal operand */
413 /* Restore the state of the denormal op bit */
414 partial_status
415 &=
416 ~SW_Denorm_Op;
417 partial_status
418 |=
419 status1 &
420 SW_Denorm_Op;
421 } else
422 setsign(st0_ptr,
423 getsign
424 (&loaded_data));
425 }
426 }
427 goto reg_mem_instr_done;
428 }
429
430 switch ((FPU_modrm >> 3) & 7) {
431 case 0: /* fadd */
432 clear_C1();
433 FPU_add(&loaded_data, loaded_tag, 0,
434 control_word);
435 break;
436 case 1: /* fmul */
437 clear_C1();
438 FPU_mul(&loaded_data, loaded_tag, 0,
439 control_word);
440 break;
441 case 2: /* fcom */
442 FPU_compare_st_data(&loaded_data,
443 loaded_tag);
444 break;
445 case 3: /* fcomp */
446 if (!FPU_compare_st_data
447 (&loaded_data, loaded_tag)
448 && !unmasked)
449 FPU_pop();
450 break;
451 case 4: /* fsub */
452 clear_C1();
453 FPU_sub(LOADED | loaded_tag,
454 (int)&loaded_data,
455 control_word);
456 break;
457 case 5: /* fsubr */
458 clear_C1();
459 FPU_sub(REV | LOADED | loaded_tag,
460 (int)&loaded_data,
461 control_word);
462 break;
463 case 6: /* fdiv */
464 clear_C1();
465 FPU_div(LOADED | loaded_tag,
466 (int)&loaded_data,
467 control_word);
468 break;
469 case 7: /* fdivr */
470 clear_C1();
471 if (st0_tag == TAG_Zero)
472 partial_status = status1; /* Undo any denorm tag,
473 zero-divide has priority. */
474 FPU_div(REV | LOADED | loaded_tag,
475 (int)&loaded_data,
476 control_word);
477 break;
478 }
479 } else {
480 if ((FPU_modrm & 0x30) == 0x10) {
481 /* The instruction is fcom or fcomp */
482 EXCEPTION(EX_StackUnder);
483 setcc(SW_C3 | SW_C2 | SW_C0);
484 if ((FPU_modrm & 0x08)
485 && (control_word & CW_Invalid))
486 FPU_pop(); /* fcomp */
487 } else
488 FPU_stack_underflow();
489 }
490 reg_mem_instr_done:
491 operand_address = data_sel_off;
492 } else {
493 if (!(no_ip_update =
494 FPU_load_store(((FPU_modrm & 0x38) | (byte1 & 6))
495 >> 1, addr_modes, data_address))) {
496 operand_address = data_sel_off;
497 }
474 } 498 }
475 else
476 FPU_stack_underflow();
477 }
478 reg_mem_instr_done:
479 operand_address = data_sel_off;
480 }
481 else
482 {
483 if ( !(no_ip_update =
484 FPU_load_store(((FPU_modrm & 0x38) | (byte1 & 6)) >> 1,
485 addr_modes, data_address)) )
486 {
487 operand_address = data_sel_off;
488 }
489 }
490 499
491 } 500 } else {
492 else 501 /* None of these instructions access user memory */
493 { 502 u_char instr_index = (FPU_modrm & 0x38) | (byte1 & 7);
494 /* None of these instructions access user memory */
495 u_char instr_index = (FPU_modrm & 0x38) | (byte1 & 7);
496 503
497#ifdef PECULIAR_486 504#ifdef PECULIAR_486
498 /* This is supposed to be undefined, but a real 80486 seems 505 /* This is supposed to be undefined, but a real 80486 seems
499 to do this: */ 506 to do this: */
500 operand_address.offset = 0; 507 operand_address.offset = 0;
501 operand_address.selector = FPU_DS; 508 operand_address.selector = FPU_DS;
502#endif /* PECULIAR_486 */ 509#endif /* PECULIAR_486 */
503 510
504 st0_ptr = &st(0); 511 st0_ptr = &st(0);
505 st0_tag = FPU_gettag0(); 512 st0_tag = FPU_gettag0();
506 switch ( type_table[(int) instr_index] ) 513 switch (type_table[(int)instr_index]) {
507 { 514 case _NONE_: /* also _REGIc: _REGIn */
508 case _NONE_: /* also _REGIc: _REGIn */ 515 break;
509 break; 516 case _REG0_:
510 case _REG0_: 517 if (!NOT_EMPTY_ST0) {
511 if ( !NOT_EMPTY_ST0 ) 518 FPU_stack_underflow();
512 { 519 goto FPU_instruction_done;
513 FPU_stack_underflow(); 520 }
514 goto FPU_instruction_done; 521 break;
515 } 522 case _REGIi:
516 break; 523 if (!NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm)) {
517 case _REGIi: 524 FPU_stack_underflow_i(FPU_rm);
518 if ( !NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm) ) 525 goto FPU_instruction_done;
519 { 526 }
520 FPU_stack_underflow_i(FPU_rm); 527 break;
521 goto FPU_instruction_done; 528 case _REGIp:
522 } 529 if (!NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm)) {
523 break; 530 FPU_stack_underflow_pop(FPU_rm);
524 case _REGIp: 531 goto FPU_instruction_done;
525 if ( !NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm) ) 532 }
526 { 533 break;
527 FPU_stack_underflow_pop(FPU_rm); 534 case _REGI_:
528 goto FPU_instruction_done; 535 if (!NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm)) {
529 } 536 FPU_stack_underflow();
530 break; 537 goto FPU_instruction_done;
531 case _REGI_: 538 }
532 if ( !NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm) ) 539 break;
533 { 540 case _PUSH_: /* Only used by the fld st(i) instruction */
534 FPU_stack_underflow(); 541 break;
535 goto FPU_instruction_done; 542 case _null_:
536 } 543 FPU_illegal();
537 break; 544 goto FPU_instruction_done;
538 case _PUSH_: /* Only used by the fld st(i) instruction */ 545 default:
539 break; 546 EXCEPTION(EX_INTERNAL | 0x111);
540 case _null_: 547 goto FPU_instruction_done;
541 FPU_illegal(); 548 }
542 goto FPU_instruction_done; 549 (*st_instr_table[(int)instr_index]) ();
543 default:
544 EXCEPTION(EX_INTERNAL|0x111);
545 goto FPU_instruction_done;
546 }
547 (*st_instr_table[(int) instr_index])();
548 550
549FPU_instruction_done: 551 FPU_instruction_done:
550 ; 552 ;
551 } 553 }
552 554
553 if ( ! no_ip_update ) 555 if (!no_ip_update)
554 instruction_address = entry_sel_off; 556 instruction_address = entry_sel_off;
555 557
556FPU_fwait_done: 558 FPU_fwait_done:
557 559
558#ifdef DEBUG 560#ifdef DEBUG
559 RE_ENTRANT_CHECK_OFF; 561 RE_ENTRANT_CHECK_OFF;
560 FPU_printall(); 562 FPU_printall();
561 RE_ENTRANT_CHECK_ON; 563 RE_ENTRANT_CHECK_ON;
562#endif /* DEBUG */ 564#endif /* DEBUG */
563 565
564 if (FPU_lookahead && !need_resched()) 566 if (FPU_lookahead && !need_resched()) {
565 { 567 FPU_ORIG_EIP = FPU_EIP - code_base;
566 FPU_ORIG_EIP = FPU_EIP - code_base; 568 if (valid_prefix(&byte1, (u_char __user **) & FPU_EIP,
567 if ( valid_prefix(&byte1, (u_char __user **)&FPU_EIP, 569 &addr_modes.override))
568 &addr_modes.override) ) 570 goto do_another_FPU_instruction;
569 goto do_another_FPU_instruction; 571 }
570 }
571 572
572 if ( addr_modes.default_mode ) 573 if (addr_modes.default_mode)
573 FPU_EIP -= code_base; 574 FPU_EIP -= code_base;
574 575
575 RE_ENTRANT_CHECK_OFF; 576 RE_ENTRANT_CHECK_OFF;
576} 577}
577 578
578
579/* Support for prefix bytes is not yet complete. To properly handle 579/* Support for prefix bytes is not yet complete. To properly handle
580 all prefix bytes, further changes are needed in the emulator code 580 all prefix bytes, further changes are needed in the emulator code
581 which accesses user address space. Access to separate segments is 581 which accesses user address space. Access to separate segments is
582 important for msdos emulation. */ 582 important for msdos emulation. */
583static int valid_prefix(u_char *Byte, u_char __user **fpu_eip, 583static int valid_prefix(u_char * Byte, u_char __user ** fpu_eip,
584 overrides *override) 584 overrides * override)
585{ 585{
586 u_char byte; 586 u_char byte;
587 u_char __user *ip = *fpu_eip; 587 u_char __user *ip = *fpu_eip;
588 588
589 *override = (overrides) { 0, 0, PREFIX_DEFAULT }; /* defaults */ 589 *override = (overrides) {
590 590 0, 0, PREFIX_DEFAULT}; /* defaults */
591 RE_ENTRANT_CHECK_OFF; 591
592 FPU_code_access_ok(1); 592 RE_ENTRANT_CHECK_OFF;
593 FPU_get_user(byte, ip); 593 FPU_code_access_ok(1);
594 RE_ENTRANT_CHECK_ON; 594 FPU_get_user(byte, ip);
595 595 RE_ENTRANT_CHECK_ON;
596 while ( 1 ) 596
597 { 597 while (1) {
598 switch ( byte ) 598 switch (byte) {
599 { 599 case ADDR_SIZE_PREFIX:
600 case ADDR_SIZE_PREFIX: 600 override->address_size = ADDR_SIZE_PREFIX;
601 override->address_size = ADDR_SIZE_PREFIX; 601 goto do_next_byte;
602 goto do_next_byte; 602
603 603 case OP_SIZE_PREFIX:
604 case OP_SIZE_PREFIX: 604 override->operand_size = OP_SIZE_PREFIX;
605 override->operand_size = OP_SIZE_PREFIX; 605 goto do_next_byte;
606 goto do_next_byte; 606
607 607 case PREFIX_CS:
608 case PREFIX_CS: 608 override->segment = PREFIX_CS_;
609 override->segment = PREFIX_CS_; 609 goto do_next_byte;
610 goto do_next_byte; 610 case PREFIX_ES:
611 case PREFIX_ES: 611 override->segment = PREFIX_ES_;
612 override->segment = PREFIX_ES_; 612 goto do_next_byte;
613 goto do_next_byte; 613 case PREFIX_SS:
614 case PREFIX_SS: 614 override->segment = PREFIX_SS_;
615 override->segment = PREFIX_SS_; 615 goto do_next_byte;
616 goto do_next_byte; 616 case PREFIX_FS:
617 case PREFIX_FS: 617 override->segment = PREFIX_FS_;
618 override->segment = PREFIX_FS_; 618 goto do_next_byte;
619 goto do_next_byte; 619 case PREFIX_GS:
620 case PREFIX_GS: 620 override->segment = PREFIX_GS_;
621 override->segment = PREFIX_GS_; 621 goto do_next_byte;
622 goto do_next_byte; 622 case PREFIX_DS:
623 case PREFIX_DS: 623 override->segment = PREFIX_DS_;
624 override->segment = PREFIX_DS_; 624 goto do_next_byte;
625 goto do_next_byte;
626 625
627/* lock is not a valid prefix for FPU instructions, 626/* lock is not a valid prefix for FPU instructions,
628 let the cpu handle it to generate a SIGILL. */ 627 let the cpu handle it to generate a SIGILL. */
629/* case PREFIX_LOCK: */ 628/* case PREFIX_LOCK: */
630 629
631 /* rep.. prefixes have no meaning for FPU instructions */ 630 /* rep.. prefixes have no meaning for FPU instructions */
632 case PREFIX_REPE: 631 case PREFIX_REPE:
633 case PREFIX_REPNE: 632 case PREFIX_REPNE:
634 633
635 do_next_byte: 634 do_next_byte:
636 ip++; 635 ip++;
637 RE_ENTRANT_CHECK_OFF; 636 RE_ENTRANT_CHECK_OFF;
638 FPU_code_access_ok(1); 637 FPU_code_access_ok(1);
639 FPU_get_user(byte, ip); 638 FPU_get_user(byte, ip);
640 RE_ENTRANT_CHECK_ON; 639 RE_ENTRANT_CHECK_ON;
641 break; 640 break;
642 case FWAIT_OPCODE: 641 case FWAIT_OPCODE:
643 *Byte = byte; 642 *Byte = byte;
644 return 1; 643 return 1;
645 default: 644 default:
646 if ( (byte & 0xf8) == 0xd8 ) 645 if ((byte & 0xf8) == 0xd8) {
647 { 646 *Byte = byte;
648 *Byte = byte; 647 *fpu_eip = ip;
649 *fpu_eip = ip; 648 return 1;
650 return 1; 649 } else {
651 } 650 /* Not a valid sequence of prefix bytes followed by
652 else 651 an FPU instruction. */
653 { 652 *Byte = byte; /* Needed for error message. */
654 /* Not a valid sequence of prefix bytes followed by 653 return 0;
655 an FPU instruction. */ 654 }
656 *Byte = byte; /* Needed for error message. */ 655 }
657 return 0;
658 }
659 } 656 }
660 }
661} 657}
662 658
663 659void math_abort(struct info *info, unsigned int signal)
664void math_abort(struct info * info, unsigned int signal)
665{ 660{
666 FPU_EIP = FPU_ORIG_EIP; 661 FPU_EIP = FPU_ORIG_EIP;
667 current->thread.trap_no = 16; 662 current->thread.trap_no = 16;
668 current->thread.error_code = 0; 663 current->thread.error_code = 0;
669 send_sig(signal,current,1); 664 send_sig(signal, current, 1);
670 RE_ENTRANT_CHECK_OFF; 665 RE_ENTRANT_CHECK_OFF;
671 __asm__("movl %0,%%esp ; ret": :"g" (((long) info)-4)); 666 __asm__("movl %0,%%esp ; ret": :"g"(((long)info) - 4));
672#ifdef PARANOID 667#ifdef PARANOID
673 printk("ERROR: wm-FPU-emu math_abort failed!\n"); 668 printk("ERROR: wm-FPU-emu math_abort failed!\n");
674#endif /* PARANOID */ 669#endif /* PARANOID */
675} 670}
676 671
677
678
679#define S387 ((struct i387_soft_struct *)s387) 672#define S387 ((struct i387_soft_struct *)s387)
680#define sstatus_word() \ 673#define sstatus_word() \
681 ((S387->swd & ~SW_Top & 0xffff) | ((S387->ftop << SW_Top_Shift) & SW_Top)) 674 ((S387->swd & ~SW_Top & 0xffff) | ((S387->ftop << SW_Top_Shift) & SW_Top))
682 675
683int restore_i387_soft(void *s387, struct _fpstate __user *buf) 676int restore_i387_soft(void *s387, struct _fpstate __user * buf)
684{ 677{
685 u_char __user *d = (u_char __user *)buf; 678 u_char __user *d = (u_char __user *) buf;
686 int offset, other, i, tags, regnr, tag, newtop; 679 int offset, other, i, tags, regnr, tag, newtop;
687 680
688 RE_ENTRANT_CHECK_OFF; 681 RE_ENTRANT_CHECK_OFF;
689 FPU_access_ok(VERIFY_READ, d, 7*4 + 8*10); 682 FPU_access_ok(VERIFY_READ, d, 7 * 4 + 8 * 10);
690 if (__copy_from_user(&S387->cwd, d, 7*4)) 683 if (__copy_from_user(&S387->cwd, d, 7 * 4))
691 return -1; 684 return -1;
692 RE_ENTRANT_CHECK_ON; 685 RE_ENTRANT_CHECK_ON;
693 686
694 d += 7*4; 687 d += 7 * 4;
695 688
696 S387->ftop = (S387->swd >> SW_Top_Shift) & 7; 689 S387->ftop = (S387->swd >> SW_Top_Shift) & 7;
697 offset = (S387->ftop & 7) * 10; 690 offset = (S387->ftop & 7) * 10;
698 other = 80 - offset; 691 other = 80 - offset;
699 692
700 RE_ENTRANT_CHECK_OFF; 693 RE_ENTRANT_CHECK_OFF;
701 /* Copy all registers in stack order. */ 694 /* Copy all registers in stack order. */
702 if (__copy_from_user(((u_char *)&S387->st_space)+offset, d, other)) 695 if (__copy_from_user(((u_char *) & S387->st_space) + offset, d, other))
703 return -1; 696 return -1;
704 if ( offset ) 697 if (offset)
705 if (__copy_from_user((u_char *)&S387->st_space, d+other, offset)) 698 if (__copy_from_user
706 return -1; 699 ((u_char *) & S387->st_space, d + other, offset))
707 RE_ENTRANT_CHECK_ON; 700 return -1;
708 701 RE_ENTRANT_CHECK_ON;
709 /* The tags may need to be corrected now. */ 702
710 tags = S387->twd; 703 /* The tags may need to be corrected now. */
711 newtop = S387->ftop; 704 tags = S387->twd;
712 for ( i = 0; i < 8; i++ ) 705 newtop = S387->ftop;
713 { 706 for (i = 0; i < 8; i++) {
714 regnr = (i+newtop) & 7; 707 regnr = (i + newtop) & 7;
715 if ( ((tags >> ((regnr & 7)*2)) & 3) != TAG_Empty ) 708 if (((tags >> ((regnr & 7) * 2)) & 3) != TAG_Empty) {
716 { 709 /* The loaded data over-rides all other cases. */
717 /* The loaded data over-rides all other cases. */ 710 tag =
718 tag = FPU_tagof((FPU_REG *)((u_char *)S387->st_space + 10*regnr)); 711 FPU_tagof((FPU_REG *) ((u_char *) S387->st_space +
719 tags &= ~(3 << (regnr*2)); 712 10 * regnr));
720 tags |= (tag & 3) << (regnr*2); 713 tags &= ~(3 << (regnr * 2));
714 tags |= (tag & 3) << (regnr * 2);
715 }
721 } 716 }
722 } 717 S387->twd = tags;
723 S387->twd = tags;
724 718
725 return 0; 719 return 0;
726} 720}
727 721
728
729int save_i387_soft(void *s387, struct _fpstate __user * buf) 722int save_i387_soft(void *s387, struct _fpstate __user * buf)
730{ 723{
731 u_char __user *d = (u_char __user *)buf; 724 u_char __user *d = (u_char __user *) buf;
732 int offset = (S387->ftop & 7) * 10, other = 80 - offset; 725 int offset = (S387->ftop & 7) * 10, other = 80 - offset;
733 726
734 RE_ENTRANT_CHECK_OFF; 727 RE_ENTRANT_CHECK_OFF;
735 FPU_access_ok(VERIFY_WRITE, d, 7*4 + 8*10); 728 FPU_access_ok(VERIFY_WRITE, d, 7 * 4 + 8 * 10);
736#ifdef PECULIAR_486 729#ifdef PECULIAR_486
737 S387->cwd &= ~0xe080; 730 S387->cwd &= ~0xe080;
738 /* An 80486 sets nearly all of the reserved bits to 1. */ 731 /* An 80486 sets nearly all of the reserved bits to 1. */
739 S387->cwd |= 0xffff0040; 732 S387->cwd |= 0xffff0040;
740 S387->swd = sstatus_word() | 0xffff0000; 733 S387->swd = sstatus_word() | 0xffff0000;
741 S387->twd |= 0xffff0000; 734 S387->twd |= 0xffff0000;
742 S387->fcs &= ~0xf8000000; 735 S387->fcs &= ~0xf8000000;
743 S387->fos |= 0xffff0000; 736 S387->fos |= 0xffff0000;
744#endif /* PECULIAR_486 */ 737#endif /* PECULIAR_486 */
745 if (__copy_to_user(d, &S387->cwd, 7*4)) 738 if (__copy_to_user(d, &S387->cwd, 7 * 4))
746 return -1; 739 return -1;
747 RE_ENTRANT_CHECK_ON; 740 RE_ENTRANT_CHECK_ON;
748 741
749 d += 7*4; 742 d += 7 * 4;
750 743
751 RE_ENTRANT_CHECK_OFF; 744 RE_ENTRANT_CHECK_OFF;
752 /* Copy all registers in stack order. */ 745 /* Copy all registers in stack order. */
753 if (__copy_to_user(d, ((u_char *)&S387->st_space)+offset, other)) 746 if (__copy_to_user(d, ((u_char *) & S387->st_space) + offset, other))
754 return -1; 747 return -1;
755 if ( offset ) 748 if (offset)
756 if (__copy_to_user(d+other, (u_char *)&S387->st_space, offset)) 749 if (__copy_to_user
757 return -1; 750 (d + other, (u_char *) & S387->st_space, offset))
758 RE_ENTRANT_CHECK_ON; 751 return -1;
759 752 RE_ENTRANT_CHECK_ON;
760 return 1; 753
754 return 1;
761} 755}
diff --git a/arch/x86/math-emu/fpu_etc.c b/arch/x86/math-emu/fpu_etc.c
index e3b5d465587f..e73631e0cde9 100644
--- a/arch/x86/math-emu/fpu_etc.c
+++ b/arch/x86/math-emu/fpu_etc.c
@@ -16,128 +16,115 @@
16#include "status_w.h" 16#include "status_w.h"
17#include "reg_constant.h" 17#include "reg_constant.h"
18 18
19 19static void fchs(FPU_REG * st0_ptr, u_char st0tag)
20static void fchs(FPU_REG *st0_ptr, u_char st0tag)
21{ 20{
22 if ( st0tag ^ TAG_Empty ) 21 if (st0tag ^ TAG_Empty) {
23 { 22 signbyte(st0_ptr) ^= SIGN_NEG;
24 signbyte(st0_ptr) ^= SIGN_NEG; 23 clear_C1();
25 clear_C1(); 24 } else
26 } 25 FPU_stack_underflow();
27 else
28 FPU_stack_underflow();
29} 26}
30 27
31 28static void fabs(FPU_REG * st0_ptr, u_char st0tag)
32static void fabs(FPU_REG *st0_ptr, u_char st0tag)
33{ 29{
34 if ( st0tag ^ TAG_Empty ) 30 if (st0tag ^ TAG_Empty) {
35 { 31 setpositive(st0_ptr);
36 setpositive(st0_ptr); 32 clear_C1();
37 clear_C1(); 33 } else
38 } 34 FPU_stack_underflow();
39 else
40 FPU_stack_underflow();
41} 35}
42 36
43 37static void ftst_(FPU_REG * st0_ptr, u_char st0tag)
44static void ftst_(FPU_REG *st0_ptr, u_char st0tag)
45{ 38{
46 switch (st0tag) 39 switch (st0tag) {
47 { 40 case TAG_Zero:
48 case TAG_Zero:
49 setcc(SW_C3);
50 break;
51 case TAG_Valid:
52 if (getsign(st0_ptr) == SIGN_POS)
53 setcc(0);
54 else
55 setcc(SW_C0);
56 break;
57 case TAG_Special:
58 switch ( FPU_Special(st0_ptr) )
59 {
60 case TW_Denormal:
61 if (getsign(st0_ptr) == SIGN_POS)
62 setcc(0);
63 else
64 setcc(SW_C0);
65 if ( denormal_operand() < 0 )
66 {
67#ifdef PECULIAR_486
68 /* This is weird! */
69 if (getsign(st0_ptr) == SIGN_POS)
70 setcc(SW_C3); 41 setcc(SW_C3);
42 break;
43 case TAG_Valid:
44 if (getsign(st0_ptr) == SIGN_POS)
45 setcc(0);
46 else
47 setcc(SW_C0);
48 break;
49 case TAG_Special:
50 switch (FPU_Special(st0_ptr)) {
51 case TW_Denormal:
52 if (getsign(st0_ptr) == SIGN_POS)
53 setcc(0);
54 else
55 setcc(SW_C0);
56 if (denormal_operand() < 0) {
57#ifdef PECULIAR_486
58 /* This is weird! */
59 if (getsign(st0_ptr) == SIGN_POS)
60 setcc(SW_C3);
71#endif /* PECULIAR_486 */ 61#endif /* PECULIAR_486 */
72 return; 62 return;
73 } 63 }
74 break; 64 break;
75 case TW_NaN: 65 case TW_NaN:
76 setcc(SW_C0|SW_C2|SW_C3); /* Operand is not comparable */ 66 setcc(SW_C0 | SW_C2 | SW_C3); /* Operand is not comparable */
77 EXCEPTION(EX_Invalid); 67 EXCEPTION(EX_Invalid);
78 break; 68 break;
79 case TW_Infinity: 69 case TW_Infinity:
80 if (getsign(st0_ptr) == SIGN_POS) 70 if (getsign(st0_ptr) == SIGN_POS)
81 setcc(0); 71 setcc(0);
82 else 72 else
83 setcc(SW_C0); 73 setcc(SW_C0);
84 break; 74 break;
85 default: 75 default:
86 setcc(SW_C0|SW_C2|SW_C3); /* Operand is not comparable */ 76 setcc(SW_C0 | SW_C2 | SW_C3); /* Operand is not comparable */
87 EXCEPTION(EX_INTERNAL|0x14); 77 EXCEPTION(EX_INTERNAL | 0x14);
88 break; 78 break;
79 }
80 break;
81 case TAG_Empty:
82 setcc(SW_C0 | SW_C2 | SW_C3);
83 EXCEPTION(EX_StackUnder);
84 break;
89 } 85 }
90 break;
91 case TAG_Empty:
92 setcc(SW_C0|SW_C2|SW_C3);
93 EXCEPTION(EX_StackUnder);
94 break;
95 }
96} 86}
97 87
98 88static void fxam(FPU_REG * st0_ptr, u_char st0tag)
99static void fxam(FPU_REG *st0_ptr, u_char st0tag)
100{ 89{
101 int c = 0; 90 int c = 0;
102 switch (st0tag) 91 switch (st0tag) {
103 { 92 case TAG_Empty:
104 case TAG_Empty: 93 c = SW_C3 | SW_C0;
105 c = SW_C3|SW_C0; 94 break;
106 break; 95 case TAG_Zero:
107 case TAG_Zero: 96 c = SW_C3;
108 c = SW_C3; 97 break;
109 break; 98 case TAG_Valid:
110 case TAG_Valid: 99 c = SW_C2;
111 c = SW_C2; 100 break;
112 break; 101 case TAG_Special:
113 case TAG_Special: 102 switch (FPU_Special(st0_ptr)) {
114 switch ( FPU_Special(st0_ptr) ) 103 case TW_Denormal:
115 { 104 c = SW_C2 | SW_C3; /* Denormal */
116 case TW_Denormal: 105 break;
117 c = SW_C2|SW_C3; /* Denormal */ 106 case TW_NaN:
118 break; 107 /* We also use NaN for unsupported types. */
119 case TW_NaN: 108 if ((st0_ptr->sigh & 0x80000000)
120 /* We also use NaN for unsupported types. */ 109 && (exponent(st0_ptr) == EXP_OVER))
121 if ( (st0_ptr->sigh & 0x80000000) && (exponent(st0_ptr) == EXP_OVER) ) 110 c = SW_C0;
122 c = SW_C0; 111 break;
123 break; 112 case TW_Infinity:
124 case TW_Infinity: 113 c = SW_C2 | SW_C0;
125 c = SW_C2|SW_C0; 114 break;
126 break; 115 }
127 } 116 }
128 } 117 if (getsign(st0_ptr) == SIGN_NEG)
129 if ( getsign(st0_ptr) == SIGN_NEG ) 118 c |= SW_C1;
130 c |= SW_C1; 119 setcc(c);
131 setcc(c);
132} 120}
133 121
134
135static FUNC_ST0 const fp_etc_table[] = { 122static FUNC_ST0 const fp_etc_table[] = {
136 fchs, fabs, (FUNC_ST0)FPU_illegal, (FUNC_ST0)FPU_illegal, 123 fchs, fabs, (FUNC_ST0) FPU_illegal, (FUNC_ST0) FPU_illegal,
137 ftst_, fxam, (FUNC_ST0)FPU_illegal, (FUNC_ST0)FPU_illegal 124 ftst_, fxam, (FUNC_ST0) FPU_illegal, (FUNC_ST0) FPU_illegal
138}; 125};
139 126
140void FPU_etc(void) 127void FPU_etc(void)
141{ 128{
142 (fp_etc_table[FPU_rm])(&st(0), FPU_gettag0()); 129 (fp_etc_table[FPU_rm]) (&st(0), FPU_gettag0());
143} 130}
diff --git a/arch/x86/math-emu/fpu_proto.h b/arch/x86/math-emu/fpu_proto.h
index 37a8a7fe7e2b..0f6384102afd 100644
--- a/arch/x86/math-emu/fpu_proto.h
+++ b/arch/x86/math-emu/fpu_proto.h
@@ -5,7 +5,7 @@
5extern void FPU_illegal(void); 5extern void FPU_illegal(void);
6extern void FPU_printall(void); 6extern void FPU_printall(void);
7asmlinkage void FPU_exception(int n); 7asmlinkage void FPU_exception(int n);
8extern int real_1op_NaN(FPU_REG *a); 8extern int real_1op_NaN(FPU_REG * a);
9extern int real_2op_NaN(FPU_REG const *b, u_char tagb, int deststnr, 9extern int real_2op_NaN(FPU_REG const *b, u_char tagb, int deststnr,
10 FPU_REG const *defaultNaN); 10 FPU_REG const *defaultNaN);
11asmlinkage int arith_invalid(int deststnr); 11asmlinkage int arith_invalid(int deststnr);
@@ -14,8 +14,8 @@ extern int set_precision_flag(int flags);
14asmlinkage void set_precision_flag_up(void); 14asmlinkage void set_precision_flag_up(void);
15asmlinkage void set_precision_flag_down(void); 15asmlinkage void set_precision_flag_down(void);
16asmlinkage int denormal_operand(void); 16asmlinkage int denormal_operand(void);
17asmlinkage int arith_overflow(FPU_REG *dest); 17asmlinkage int arith_overflow(FPU_REG * dest);
18asmlinkage int arith_underflow(FPU_REG *dest); 18asmlinkage int arith_underflow(FPU_REG * dest);
19extern void FPU_stack_overflow(void); 19extern void FPU_stack_overflow(void);
20extern void FPU_stack_underflow(void); 20extern void FPU_stack_underflow(void);
21extern void FPU_stack_underflow_i(int i); 21extern void FPU_stack_underflow_i(int i);
@@ -66,7 +66,7 @@ extern int FPU_Special(FPU_REG const *ptr);
66extern int isNaN(FPU_REG const *ptr); 66extern int isNaN(FPU_REG const *ptr);
67extern void FPU_pop(void); 67extern void FPU_pop(void);
68extern int FPU_empty_i(int stnr); 68extern int FPU_empty_i(int stnr);
69extern int FPU_stackoverflow(FPU_REG **st_new_ptr); 69extern int FPU_stackoverflow(FPU_REG ** st_new_ptr);
70extern void FPU_copy_to_regi(FPU_REG const *r, u_char tag, int stnr); 70extern void FPU_copy_to_regi(FPU_REG const *r, u_char tag, int stnr);
71extern void FPU_copy_to_reg1(FPU_REG const *r, u_char tag); 71extern void FPU_copy_to_reg1(FPU_REG const *r, u_char tag);
72extern void FPU_copy_to_reg0(FPU_REG const *r, u_char tag); 72extern void FPU_copy_to_reg0(FPU_REG const *r, u_char tag);
@@ -75,26 +75,28 @@ extern void FPU_triga(void);
75extern void FPU_trigb(void); 75extern void FPU_trigb(void);
76/* get_address.c */ 76/* get_address.c */
77extern void __user *FPU_get_address(u_char FPU_modrm, unsigned long *fpu_eip, 77extern void __user *FPU_get_address(u_char FPU_modrm, unsigned long *fpu_eip,
78 struct address *addr, fpu_addr_modes addr_modes); 78 struct address *addr,
79 fpu_addr_modes addr_modes);
79extern void __user *FPU_get_address_16(u_char FPU_modrm, unsigned long *fpu_eip, 80extern void __user *FPU_get_address_16(u_char FPU_modrm, unsigned long *fpu_eip,
80 struct address *addr, fpu_addr_modes addr_modes); 81 struct address *addr,
82 fpu_addr_modes addr_modes);
81/* load_store.c */ 83/* load_store.c */
82extern int FPU_load_store(u_char type, fpu_addr_modes addr_modes, 84extern int FPU_load_store(u_char type, fpu_addr_modes addr_modes,
83 void __user *data_address); 85 void __user * data_address);
84/* poly_2xm1.c */ 86/* poly_2xm1.c */
85extern int poly_2xm1(u_char sign, FPU_REG *arg, FPU_REG *result); 87extern int poly_2xm1(u_char sign, FPU_REG * arg, FPU_REG * result);
86/* poly_atan.c */ 88/* poly_atan.c */
87extern void poly_atan(FPU_REG *st0_ptr, u_char st0_tag, FPU_REG *st1_ptr, 89extern void poly_atan(FPU_REG * st0_ptr, u_char st0_tag, FPU_REG * st1_ptr,
88 u_char st1_tag); 90 u_char st1_tag);
89/* poly_l2.c */ 91/* poly_l2.c */
90extern void poly_l2(FPU_REG *st0_ptr, FPU_REG *st1_ptr, u_char st1_sign); 92extern void poly_l2(FPU_REG * st0_ptr, FPU_REG * st1_ptr, u_char st1_sign);
91extern int poly_l2p1(u_char s0, u_char s1, FPU_REG *r0, FPU_REG *r1, 93extern int poly_l2p1(u_char s0, u_char s1, FPU_REG * r0, FPU_REG * r1,
92 FPU_REG *d); 94 FPU_REG * d);
93/* poly_sin.c */ 95/* poly_sin.c */
94extern void poly_sine(FPU_REG *st0_ptr); 96extern void poly_sine(FPU_REG * st0_ptr);
95extern void poly_cos(FPU_REG *st0_ptr); 97extern void poly_cos(FPU_REG * st0_ptr);
96/* poly_tan.c */ 98/* poly_tan.c */
97extern void poly_tan(FPU_REG *st0_ptr); 99extern void poly_tan(FPU_REG * st0_ptr);
98/* reg_add_sub.c */ 100/* reg_add_sub.c */
99extern int FPU_add(FPU_REG const *b, u_char tagb, int destrnr, int control_w); 101extern int FPU_add(FPU_REG const *b, u_char tagb, int destrnr, int control_w);
100extern int FPU_sub(int flags, int rm, int control_w); 102extern int FPU_sub(int flags, int rm, int control_w);
@@ -109,32 +111,34 @@ extern void fucompp(void);
109/* reg_constant.c */ 111/* reg_constant.c */
110extern void fconst(void); 112extern void fconst(void);
111/* reg_ld_str.c */ 113/* reg_ld_str.c */
112extern int FPU_load_extended(long double __user *s, int stnr); 114extern int FPU_load_extended(long double __user * s, int stnr);
113extern int FPU_load_double(double __user *dfloat, FPU_REG *loaded_data); 115extern int FPU_load_double(double __user * dfloat, FPU_REG * loaded_data);
114extern int FPU_load_single(float __user *single, FPU_REG *loaded_data); 116extern int FPU_load_single(float __user * single, FPU_REG * loaded_data);
115extern int FPU_load_int64(long long __user *_s); 117extern int FPU_load_int64(long long __user * _s);
116extern int FPU_load_int32(long __user *_s, FPU_REG *loaded_data); 118extern int FPU_load_int32(long __user * _s, FPU_REG * loaded_data);
117extern int FPU_load_int16(short __user *_s, FPU_REG *loaded_data); 119extern int FPU_load_int16(short __user * _s, FPU_REG * loaded_data);
118extern int FPU_load_bcd(u_char __user *s); 120extern int FPU_load_bcd(u_char __user * s);
119extern int FPU_store_extended(FPU_REG *st0_ptr, u_char st0_tag, 121extern int FPU_store_extended(FPU_REG * st0_ptr, u_char st0_tag,
120 long double __user *d); 122 long double __user * d);
121extern int FPU_store_double(FPU_REG *st0_ptr, u_char st0_tag, double __user *dfloat); 123extern int FPU_store_double(FPU_REG * st0_ptr, u_char st0_tag,
122extern int FPU_store_single(FPU_REG *st0_ptr, u_char st0_tag, float __user *single); 124 double __user * dfloat);
123extern int FPU_store_int64(FPU_REG *st0_ptr, u_char st0_tag, long long __user *d); 125extern int FPU_store_single(FPU_REG * st0_ptr, u_char st0_tag,
124extern int FPU_store_int32(FPU_REG *st0_ptr, u_char st0_tag, long __user *d); 126 float __user * single);
125extern int FPU_store_int16(FPU_REG *st0_ptr, u_char st0_tag, short __user *d); 127extern int FPU_store_int64(FPU_REG * st0_ptr, u_char st0_tag,
126extern int FPU_store_bcd(FPU_REG *st0_ptr, u_char st0_tag, u_char __user *d); 128 long long __user * d);
127extern int FPU_round_to_int(FPU_REG *r, u_char tag); 129extern int FPU_store_int32(FPU_REG * st0_ptr, u_char st0_tag, long __user * d);
128extern u_char __user *fldenv(fpu_addr_modes addr_modes, u_char __user *s); 130extern int FPU_store_int16(FPU_REG * st0_ptr, u_char st0_tag, short __user * d);
129extern void frstor(fpu_addr_modes addr_modes, u_char __user *data_address); 131extern int FPU_store_bcd(FPU_REG * st0_ptr, u_char st0_tag, u_char __user * d);
130extern u_char __user *fstenv(fpu_addr_modes addr_modes, u_char __user *d); 132extern int FPU_round_to_int(FPU_REG * r, u_char tag);
131extern void fsave(fpu_addr_modes addr_modes, u_char __user *data_address); 133extern u_char __user *fldenv(fpu_addr_modes addr_modes, u_char __user * s);
132extern int FPU_tagof(FPU_REG *ptr); 134extern void frstor(fpu_addr_modes addr_modes, u_char __user * data_address);
135extern u_char __user *fstenv(fpu_addr_modes addr_modes, u_char __user * d);
136extern void fsave(fpu_addr_modes addr_modes, u_char __user * data_address);
137extern int FPU_tagof(FPU_REG * ptr);
133/* reg_mul.c */ 138/* reg_mul.c */
134extern int FPU_mul(FPU_REG const *b, u_char tagb, int deststnr, int control_w); 139extern int FPU_mul(FPU_REG const *b, u_char tagb, int deststnr, int control_w);
135 140
136extern int FPU_div(int flags, int regrm, int control_w); 141extern int FPU_div(int flags, int regrm, int control_w);
137/* reg_convert.c */ 142/* reg_convert.c */
138extern int FPU_to_exp16(FPU_REG const *a, FPU_REG *x); 143extern int FPU_to_exp16(FPU_REG const *a, FPU_REG * x);
139#endif /* _FPU_PROTO_H */ 144#endif /* _FPU_PROTO_H */
140
diff --git a/arch/x86/math-emu/fpu_tags.c b/arch/x86/math-emu/fpu_tags.c
index cb436fe20e4c..d9c657cd7746 100644
--- a/arch/x86/math-emu/fpu_tags.c
+++ b/arch/x86/math-emu/fpu_tags.c
@@ -14,114 +14,102 @@
14#include "fpu_system.h" 14#include "fpu_system.h"
15#include "exception.h" 15#include "exception.h"
16 16
17
18void FPU_pop(void) 17void FPU_pop(void)
19{ 18{
20 fpu_tag_word |= 3 << ((top & 7)*2); 19 fpu_tag_word |= 3 << ((top & 7) * 2);
21 top++; 20 top++;
22} 21}
23 22
24
25int FPU_gettag0(void) 23int FPU_gettag0(void)
26{ 24{
27 return (fpu_tag_word >> ((top & 7)*2)) & 3; 25 return (fpu_tag_word >> ((top & 7) * 2)) & 3;
28} 26}
29 27
30
31int FPU_gettagi(int stnr) 28int FPU_gettagi(int stnr)
32{ 29{
33 return (fpu_tag_word >> (((top+stnr) & 7)*2)) & 3; 30 return (fpu_tag_word >> (((top + stnr) & 7) * 2)) & 3;
34} 31}
35 32
36
37int FPU_gettag(int regnr) 33int FPU_gettag(int regnr)
38{ 34{
39 return (fpu_tag_word >> ((regnr & 7)*2)) & 3; 35 return (fpu_tag_word >> ((regnr & 7) * 2)) & 3;
40} 36}
41 37
42
43void FPU_settag0(int tag) 38void FPU_settag0(int tag)
44{ 39{
45 int regnr = top; 40 int regnr = top;
46 regnr &= 7; 41 regnr &= 7;
47 fpu_tag_word &= ~(3 << (regnr*2)); 42 fpu_tag_word &= ~(3 << (regnr * 2));
48 fpu_tag_word |= (tag & 3) << (regnr*2); 43 fpu_tag_word |= (tag & 3) << (regnr * 2);
49} 44}
50 45
51
52void FPU_settagi(int stnr, int tag) 46void FPU_settagi(int stnr, int tag)
53{ 47{
54 int regnr = stnr+top; 48 int regnr = stnr + top;
55 regnr &= 7; 49 regnr &= 7;
56 fpu_tag_word &= ~(3 << (regnr*2)); 50 fpu_tag_word &= ~(3 << (regnr * 2));
57 fpu_tag_word |= (tag & 3) << (regnr*2); 51 fpu_tag_word |= (tag & 3) << (regnr * 2);
58} 52}
59 53
60
61void FPU_settag(int regnr, int tag) 54void FPU_settag(int regnr, int tag)
62{ 55{
63 regnr &= 7; 56 regnr &= 7;
64 fpu_tag_word &= ~(3 << (regnr*2)); 57 fpu_tag_word &= ~(3 << (regnr * 2));
65 fpu_tag_word |= (tag & 3) << (regnr*2); 58 fpu_tag_word |= (tag & 3) << (regnr * 2);
66} 59}
67 60
68
69int FPU_Special(FPU_REG const *ptr) 61int FPU_Special(FPU_REG const *ptr)
70{ 62{
71 int exp = exponent(ptr); 63 int exp = exponent(ptr);
72 64
73 if ( exp == EXP_BIAS+EXP_UNDER ) 65 if (exp == EXP_BIAS + EXP_UNDER)
74 return TW_Denormal; 66 return TW_Denormal;
75 else if ( exp != EXP_BIAS+EXP_OVER ) 67 else if (exp != EXP_BIAS + EXP_OVER)
76 return TW_NaN; 68 return TW_NaN;
77 else if ( (ptr->sigh == 0x80000000) && (ptr->sigl == 0) ) 69 else if ((ptr->sigh == 0x80000000) && (ptr->sigl == 0))
78 return TW_Infinity; 70 return TW_Infinity;
79 return TW_NaN; 71 return TW_NaN;
80} 72}
81 73
82
83int isNaN(FPU_REG const *ptr) 74int isNaN(FPU_REG const *ptr)
84{ 75{
85 return ( (exponent(ptr) == EXP_BIAS+EXP_OVER) 76 return ((exponent(ptr) == EXP_BIAS + EXP_OVER)
86 && !((ptr->sigh == 0x80000000) && (ptr->sigl == 0)) ); 77 && !((ptr->sigh == 0x80000000) && (ptr->sigl == 0)));
87} 78}
88 79
89
90int FPU_empty_i(int stnr) 80int FPU_empty_i(int stnr)
91{ 81{
92 int regnr = (top+stnr) & 7; 82 int regnr = (top + stnr) & 7;
93 83
94 return ((fpu_tag_word >> (regnr*2)) & 3) == TAG_Empty; 84 return ((fpu_tag_word >> (regnr * 2)) & 3) == TAG_Empty;
95} 85}
96 86
97 87int FPU_stackoverflow(FPU_REG ** st_new_ptr)
98int FPU_stackoverflow(FPU_REG **st_new_ptr)
99{ 88{
100 *st_new_ptr = &st(-1); 89 *st_new_ptr = &st(-1);
101 90
102 return ((fpu_tag_word >> (((top - 1) & 7)*2)) & 3) != TAG_Empty; 91 return ((fpu_tag_word >> (((top - 1) & 7) * 2)) & 3) != TAG_Empty;
103} 92}
104 93
105
106void FPU_copy_to_regi(FPU_REG const *r, u_char tag, int stnr) 94void FPU_copy_to_regi(FPU_REG const *r, u_char tag, int stnr)
107{ 95{
108 reg_copy(r, &st(stnr)); 96 reg_copy(r, &st(stnr));
109 FPU_settagi(stnr, tag); 97 FPU_settagi(stnr, tag);
110} 98}
111 99
112void FPU_copy_to_reg1(FPU_REG const *r, u_char tag) 100void FPU_copy_to_reg1(FPU_REG const *r, u_char tag)
113{ 101{
114 reg_copy(r, &st(1)); 102 reg_copy(r, &st(1));
115 FPU_settagi(1, tag); 103 FPU_settagi(1, tag);
116} 104}
117 105
118void FPU_copy_to_reg0(FPU_REG const *r, u_char tag) 106void FPU_copy_to_reg0(FPU_REG const *r, u_char tag)
119{ 107{
120 int regnr = top; 108 int regnr = top;
121 regnr &= 7; 109 regnr &= 7;
122 110
123 reg_copy(r, &st(0)); 111 reg_copy(r, &st(0));
124 112
125 fpu_tag_word &= ~(3 << (regnr*2)); 113 fpu_tag_word &= ~(3 << (regnr * 2));
126 fpu_tag_word |= (tag & 3) << (regnr*2); 114 fpu_tag_word |= (tag & 3) << (regnr * 2);
127} 115}
diff --git a/arch/x86/math-emu/fpu_trig.c b/arch/x86/math-emu/fpu_trig.c
index 403cbde1d425..e5316a288a6e 100644
--- a/arch/x86/math-emu/fpu_trig.c
+++ b/arch/x86/math-emu/fpu_trig.c
@@ -15,11 +15,10 @@
15#include "fpu_emu.h" 15#include "fpu_emu.h"
16#include "status_w.h" 16#include "status_w.h"
17#include "control_w.h" 17#include "control_w.h"
18#include "reg_constant.h" 18#include "reg_constant.h"
19 19
20static void rem_kernel(unsigned long long st0, unsigned long long *y, 20static void rem_kernel(unsigned long long st0, unsigned long long *y,
21 unsigned long long st1, 21 unsigned long long st1, unsigned long long q, int n);
22 unsigned long long q, int n);
23 22
24#define BETTER_THAN_486 23#define BETTER_THAN_486
25 24
@@ -31,790 +30,708 @@ static void rem_kernel(unsigned long long st0, unsigned long long *y,
31/* Limited measurements show no results worse than 64 bit precision 30/* Limited measurements show no results worse than 64 bit precision
32 except for the results for arguments close to 2^63, where the 31 except for the results for arguments close to 2^63, where the
33 precision of the result sometimes degrades to about 63.9 bits */ 32 precision of the result sometimes degrades to about 63.9 bits */
34static int trig_arg(FPU_REG *st0_ptr, int even) 33static int trig_arg(FPU_REG * st0_ptr, int even)
35{ 34{
36 FPU_REG tmp; 35 FPU_REG tmp;
37 u_char tmptag; 36 u_char tmptag;
38 unsigned long long q; 37 unsigned long long q;
39 int old_cw = control_word, saved_status = partial_status; 38 int old_cw = control_word, saved_status = partial_status;
40 int tag, st0_tag = TAG_Valid; 39 int tag, st0_tag = TAG_Valid;
41 40
42 if ( exponent(st0_ptr) >= 63 ) 41 if (exponent(st0_ptr) >= 63) {
43 { 42 partial_status |= SW_C2; /* Reduction incomplete. */
44 partial_status |= SW_C2; /* Reduction incomplete. */ 43 return -1;
45 return -1; 44 }
46 }
47
48 control_word &= ~CW_RC;
49 control_word |= RC_CHOP;
50
51 setpositive(st0_ptr);
52 tag = FPU_u_div(st0_ptr, &CONST_PI2, &tmp, PR_64_BITS | RC_CHOP | 0x3f,
53 SIGN_POS);
54
55 FPU_round_to_int(&tmp, tag); /* Fortunately, this can't overflow
56 to 2^64 */
57 q = significand(&tmp);
58 if ( q )
59 {
60 rem_kernel(significand(st0_ptr),
61 &significand(&tmp),
62 significand(&CONST_PI2),
63 q, exponent(st0_ptr) - exponent(&CONST_PI2));
64 setexponent16(&tmp, exponent(&CONST_PI2));
65 st0_tag = FPU_normalize(&tmp);
66 FPU_copy_to_reg0(&tmp, st0_tag);
67 }
68
69 if ( (even && !(q & 1)) || (!even && (q & 1)) )
70 {
71 st0_tag = FPU_sub(REV|LOADED|TAG_Valid, (int)&CONST_PI2, FULL_PRECISION);
72 45
73#ifdef BETTER_THAN_486 46 control_word &= ~CW_RC;
74 /* So far, the results are exact but based upon a 64 bit 47 control_word |= RC_CHOP;
75 precision approximation to pi/2. The technique used 48
76 now is equivalent to using an approximation to pi/2 which 49 setpositive(st0_ptr);
77 is accurate to about 128 bits. */ 50 tag = FPU_u_div(st0_ptr, &CONST_PI2, &tmp, PR_64_BITS | RC_CHOP | 0x3f,
78 if ( (exponent(st0_ptr) <= exponent(&CONST_PI2extra) + 64) || (q > 1) ) 51 SIGN_POS);
79 { 52
80 /* This code gives the effect of having pi/2 to better than 53 FPU_round_to_int(&tmp, tag); /* Fortunately, this can't overflow
81 128 bits precision. */ 54 to 2^64 */
82 55 q = significand(&tmp);
83 significand(&tmp) = q + 1; 56 if (q) {
84 setexponent16(&tmp, 63); 57 rem_kernel(significand(st0_ptr),
85 FPU_normalize(&tmp); 58 &significand(&tmp),
86 tmptag = 59 significand(&CONST_PI2),
87 FPU_u_mul(&CONST_PI2extra, &tmp, &tmp, FULL_PRECISION, SIGN_POS, 60 q, exponent(st0_ptr) - exponent(&CONST_PI2));
88 exponent(&CONST_PI2extra) + exponent(&tmp)); 61 setexponent16(&tmp, exponent(&CONST_PI2));
89 setsign(&tmp, getsign(&CONST_PI2extra)); 62 st0_tag = FPU_normalize(&tmp);
90 st0_tag = FPU_add(&tmp, tmptag, 0, FULL_PRECISION); 63 FPU_copy_to_reg0(&tmp, st0_tag);
91 if ( signnegative(st0_ptr) )
92 {
93 /* CONST_PI2extra is negative, so the result of the addition
94 can be negative. This means that the argument is actually
95 in a different quadrant. The correction is always < pi/2,
96 so it can't overflow into yet another quadrant. */
97 setpositive(st0_ptr);
98 q++;
99 }
100 } 64 }
65
66 if ((even && !(q & 1)) || (!even && (q & 1))) {
67 st0_tag =
68 FPU_sub(REV | LOADED | TAG_Valid, (int)&CONST_PI2,
69 FULL_PRECISION);
70
71#ifdef BETTER_THAN_486
72 /* So far, the results are exact but based upon a 64 bit
73 precision approximation to pi/2. The technique used
74 now is equivalent to using an approximation to pi/2 which
75 is accurate to about 128 bits. */
76 if ((exponent(st0_ptr) <= exponent(&CONST_PI2extra) + 64)
77 || (q > 1)) {
78 /* This code gives the effect of having pi/2 to better than
79 128 bits precision. */
80
81 significand(&tmp) = q + 1;
82 setexponent16(&tmp, 63);
83 FPU_normalize(&tmp);
84 tmptag =
85 FPU_u_mul(&CONST_PI2extra, &tmp, &tmp,
86 FULL_PRECISION, SIGN_POS,
87 exponent(&CONST_PI2extra) +
88 exponent(&tmp));
89 setsign(&tmp, getsign(&CONST_PI2extra));
90 st0_tag = FPU_add(&tmp, tmptag, 0, FULL_PRECISION);
91 if (signnegative(st0_ptr)) {
92 /* CONST_PI2extra is negative, so the result of the addition
93 can be negative. This means that the argument is actually
94 in a different quadrant. The correction is always < pi/2,
95 so it can't overflow into yet another quadrant. */
96 setpositive(st0_ptr);
97 q++;
98 }
99 }
101#endif /* BETTER_THAN_486 */ 100#endif /* BETTER_THAN_486 */
102 } 101 }
103#ifdef BETTER_THAN_486 102#ifdef BETTER_THAN_486
104 else 103 else {
105 { 104 /* So far, the results are exact but based upon a 64 bit
106 /* So far, the results are exact but based upon a 64 bit 105 precision approximation to pi/2. The technique used
107 precision approximation to pi/2. The technique used 106 now is equivalent to using an approximation to pi/2 which
108 now is equivalent to using an approximation to pi/2 which 107 is accurate to about 128 bits. */
109 is accurate to about 128 bits. */ 108 if (((q > 0)
110 if ( ((q > 0) && (exponent(st0_ptr) <= exponent(&CONST_PI2extra) + 64)) 109 && (exponent(st0_ptr) <= exponent(&CONST_PI2extra) + 64))
111 || (q > 1) ) 110 || (q > 1)) {
112 { 111 /* This code gives the effect of having p/2 to better than
113 /* This code gives the effect of having p/2 to better than 112 128 bits precision. */
114 128 bits precision. */ 113
115 114 significand(&tmp) = q;
116 significand(&tmp) = q; 115 setexponent16(&tmp, 63);
117 setexponent16(&tmp, 63); 116 FPU_normalize(&tmp); /* This must return TAG_Valid */
118 FPU_normalize(&tmp); /* This must return TAG_Valid */ 117 tmptag =
119 tmptag = FPU_u_mul(&CONST_PI2extra, &tmp, &tmp, FULL_PRECISION, 118 FPU_u_mul(&CONST_PI2extra, &tmp, &tmp,
120 SIGN_POS, 119 FULL_PRECISION, SIGN_POS,
121 exponent(&CONST_PI2extra) + exponent(&tmp)); 120 exponent(&CONST_PI2extra) +
122 setsign(&tmp, getsign(&CONST_PI2extra)); 121 exponent(&tmp));
123 st0_tag = FPU_sub(LOADED|(tmptag & 0x0f), (int)&tmp, 122 setsign(&tmp, getsign(&CONST_PI2extra));
124 FULL_PRECISION); 123 st0_tag = FPU_sub(LOADED | (tmptag & 0x0f), (int)&tmp,
125 if ( (exponent(st0_ptr) == exponent(&CONST_PI2)) && 124 FULL_PRECISION);
126 ((st0_ptr->sigh > CONST_PI2.sigh) 125 if ((exponent(st0_ptr) == exponent(&CONST_PI2)) &&
127 || ((st0_ptr->sigh == CONST_PI2.sigh) 126 ((st0_ptr->sigh > CONST_PI2.sigh)
128 && (st0_ptr->sigl > CONST_PI2.sigl))) ) 127 || ((st0_ptr->sigh == CONST_PI2.sigh)
129 { 128 && (st0_ptr->sigl > CONST_PI2.sigl)))) {
130 /* CONST_PI2extra is negative, so the result of the 129 /* CONST_PI2extra is negative, so the result of the
131 subtraction can be larger than pi/2. This means 130 subtraction can be larger than pi/2. This means
132 that the argument is actually in a different quadrant. 131 that the argument is actually in a different quadrant.
133 The correction is always < pi/2, so it can't overflow 132 The correction is always < pi/2, so it can't overflow
134 into yet another quadrant. */ 133 into yet another quadrant. */
135 st0_tag = FPU_sub(REV|LOADED|TAG_Valid, (int)&CONST_PI2, 134 st0_tag =
136 FULL_PRECISION); 135 FPU_sub(REV | LOADED | TAG_Valid,
137 q++; 136 (int)&CONST_PI2, FULL_PRECISION);
138 } 137 q++;
138 }
139 }
139 } 140 }
140 }
141#endif /* BETTER_THAN_486 */ 141#endif /* BETTER_THAN_486 */
142 142
143 FPU_settag0(st0_tag); 143 FPU_settag0(st0_tag);
144 control_word = old_cw; 144 control_word = old_cw;
145 partial_status = saved_status & ~SW_C2; /* Reduction complete. */ 145 partial_status = saved_status & ~SW_C2; /* Reduction complete. */
146 146
147 return (q & 3) | even; 147 return (q & 3) | even;
148} 148}
149 149
150
151/* Convert a long to register */ 150/* Convert a long to register */
152static void convert_l2reg(long const *arg, int deststnr) 151static void convert_l2reg(long const *arg, int deststnr)
153{ 152{
154 int tag; 153 int tag;
155 long num = *arg; 154 long num = *arg;
156 u_char sign; 155 u_char sign;
157 FPU_REG *dest = &st(deststnr); 156 FPU_REG *dest = &st(deststnr);
158
159 if (num == 0)
160 {
161 FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
162 return;
163 }
164
165 if (num > 0)
166 { sign = SIGN_POS; }
167 else
168 { num = -num; sign = SIGN_NEG; }
169
170 dest->sigh = num;
171 dest->sigl = 0;
172 setexponent16(dest, 31);
173 tag = FPU_normalize(dest);
174 FPU_settagi(deststnr, tag);
175 setsign(dest, sign);
176 return;
177}
178 157
158 if (num == 0) {
159 FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
160 return;
161 }
162
163 if (num > 0) {
164 sign = SIGN_POS;
165 } else {
166 num = -num;
167 sign = SIGN_NEG;
168 }
179 169
180static void single_arg_error(FPU_REG *st0_ptr, u_char st0_tag) 170 dest->sigh = num;
171 dest->sigl = 0;
172 setexponent16(dest, 31);
173 tag = FPU_normalize(dest);
174 FPU_settagi(deststnr, tag);
175 setsign(dest, sign);
176 return;
177}
178
179static void single_arg_error(FPU_REG * st0_ptr, u_char st0_tag)
181{ 180{
182 if ( st0_tag == TAG_Empty ) 181 if (st0_tag == TAG_Empty)
183 FPU_stack_underflow(); /* Puts a QNaN in st(0) */ 182 FPU_stack_underflow(); /* Puts a QNaN in st(0) */
184 else if ( st0_tag == TW_NaN ) 183 else if (st0_tag == TW_NaN)
185 real_1op_NaN(st0_ptr); /* return with a NaN in st(0) */ 184 real_1op_NaN(st0_ptr); /* return with a NaN in st(0) */
186#ifdef PARANOID 185#ifdef PARANOID
187 else 186 else
188 EXCEPTION(EX_INTERNAL|0x0112); 187 EXCEPTION(EX_INTERNAL | 0x0112);
189#endif /* PARANOID */ 188#endif /* PARANOID */
190} 189}
191 190
192 191static void single_arg_2_error(FPU_REG * st0_ptr, u_char st0_tag)
193static void single_arg_2_error(FPU_REG *st0_ptr, u_char st0_tag)
194{ 192{
195 int isNaN; 193 int isNaN;
196 194
197 switch ( st0_tag ) 195 switch (st0_tag) {
198 { 196 case TW_NaN:
199 case TW_NaN: 197 isNaN = (exponent(st0_ptr) == EXP_OVER)
200 isNaN = (exponent(st0_ptr) == EXP_OVER) && (st0_ptr->sigh & 0x80000000); 198 && (st0_ptr->sigh & 0x80000000);
201 if ( isNaN && !(st0_ptr->sigh & 0x40000000) ) /* Signaling ? */ 199 if (isNaN && !(st0_ptr->sigh & 0x40000000)) { /* Signaling ? */
202 { 200 EXCEPTION(EX_Invalid);
203 EXCEPTION(EX_Invalid); 201 if (control_word & CW_Invalid) {
204 if ( control_word & CW_Invalid ) 202 /* The masked response */
205 { 203 /* Convert to a QNaN */
206 /* The masked response */ 204 st0_ptr->sigh |= 0x40000000;
207 /* Convert to a QNaN */ 205 push();
208 st0_ptr->sigh |= 0x40000000; 206 FPU_copy_to_reg0(st0_ptr, TAG_Special);
209 push(); 207 }
210 FPU_copy_to_reg0(st0_ptr, TAG_Special); 208 } else if (isNaN) {
211 } 209 /* A QNaN */
212 } 210 push();
213 else if ( isNaN ) 211 FPU_copy_to_reg0(st0_ptr, TAG_Special);
214 { 212 } else {
215 /* A QNaN */ 213 /* pseudoNaN or other unsupported */
216 push(); 214 EXCEPTION(EX_Invalid);
217 FPU_copy_to_reg0(st0_ptr, TAG_Special); 215 if (control_word & CW_Invalid) {
218 } 216 /* The masked response */
219 else 217 FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
220 { 218 push();
221 /* pseudoNaN or other unsupported */ 219 FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
222 EXCEPTION(EX_Invalid); 220 }
223 if ( control_word & CW_Invalid ) 221 }
224 { 222 break; /* return with a NaN in st(0) */
225 /* The masked response */
226 FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
227 push();
228 FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
229 }
230 }
231 break; /* return with a NaN in st(0) */
232#ifdef PARANOID 223#ifdef PARANOID
233 default: 224 default:
234 EXCEPTION(EX_INTERNAL|0x0112); 225 EXCEPTION(EX_INTERNAL | 0x0112);
235#endif /* PARANOID */ 226#endif /* PARANOID */
236 } 227 }
237} 228}
238 229
239
240/*---------------------------------------------------------------------------*/ 230/*---------------------------------------------------------------------------*/
241 231
242static void f2xm1(FPU_REG *st0_ptr, u_char tag) 232static void f2xm1(FPU_REG * st0_ptr, u_char tag)
243{ 233{
244 FPU_REG a; 234 FPU_REG a;
245 235
246 clear_C1(); 236 clear_C1();
247 237
248 if ( tag == TAG_Valid ) 238 if (tag == TAG_Valid) {
249 { 239 /* For an 80486 FPU, the result is undefined if the arg is >= 1.0 */
250 /* For an 80486 FPU, the result is undefined if the arg is >= 1.0 */ 240 if (exponent(st0_ptr) < 0) {
251 if ( exponent(st0_ptr) < 0 ) 241 denormal_arg:
252 {
253 denormal_arg:
254 242
255 FPU_to_exp16(st0_ptr, &a); 243 FPU_to_exp16(st0_ptr, &a);
256 244
257 /* poly_2xm1(x) requires 0 < st(0) < 1. */ 245 /* poly_2xm1(x) requires 0 < st(0) < 1. */
258 poly_2xm1(getsign(st0_ptr), &a, st0_ptr); 246 poly_2xm1(getsign(st0_ptr), &a, st0_ptr);
247 }
248 set_precision_flag_up(); /* 80486 appears to always do this */
249 return;
259 } 250 }
260 set_precision_flag_up(); /* 80486 appears to always do this */
261 return;
262 }
263 251
264 if ( tag == TAG_Zero ) 252 if (tag == TAG_Zero)
265 return; 253 return;
266 254
267 if ( tag == TAG_Special ) 255 if (tag == TAG_Special)
268 tag = FPU_Special(st0_ptr); 256 tag = FPU_Special(st0_ptr);
269 257
270 switch ( tag ) 258 switch (tag) {
271 { 259 case TW_Denormal:
272 case TW_Denormal: 260 if (denormal_operand() < 0)
273 if ( denormal_operand() < 0 ) 261 return;
274 return; 262 goto denormal_arg;
275 goto denormal_arg; 263 case TW_Infinity:
276 case TW_Infinity: 264 if (signnegative(st0_ptr)) {
277 if ( signnegative(st0_ptr) ) 265 /* -infinity gives -1 (p16-10) */
278 { 266 FPU_copy_to_reg0(&CONST_1, TAG_Valid);
279 /* -infinity gives -1 (p16-10) */ 267 setnegative(st0_ptr);
280 FPU_copy_to_reg0(&CONST_1, TAG_Valid); 268 }
281 setnegative(st0_ptr); 269 return;
270 default:
271 single_arg_error(st0_ptr, tag);
282 } 272 }
283 return;
284 default:
285 single_arg_error(st0_ptr, tag);
286 }
287} 273}
288 274
289 275static void fptan(FPU_REG * st0_ptr, u_char st0_tag)
290static void fptan(FPU_REG *st0_ptr, u_char st0_tag)
291{ 276{
292 FPU_REG *st_new_ptr; 277 FPU_REG *st_new_ptr;
293 int q; 278 int q;
294 u_char arg_sign = getsign(st0_ptr); 279 u_char arg_sign = getsign(st0_ptr);
295 280
296 /* Stack underflow has higher priority */ 281 /* Stack underflow has higher priority */
297 if ( st0_tag == TAG_Empty ) 282 if (st0_tag == TAG_Empty) {
298 { 283 FPU_stack_underflow(); /* Puts a QNaN in st(0) */
299 FPU_stack_underflow(); /* Puts a QNaN in st(0) */ 284 if (control_word & CW_Invalid) {
300 if ( control_word & CW_Invalid ) 285 st_new_ptr = &st(-1);
301 { 286 push();
302 st_new_ptr = &st(-1); 287 FPU_stack_underflow(); /* Puts a QNaN in the new st(0) */
303 push(); 288 }
304 FPU_stack_underflow(); /* Puts a QNaN in the new st(0) */ 289 return;
305 } 290 }
306 return; 291
307 } 292 if (STACK_OVERFLOW) {
308 293 FPU_stack_overflow();
309 if ( STACK_OVERFLOW ) 294 return;
310 { FPU_stack_overflow(); return; }
311
312 if ( st0_tag == TAG_Valid )
313 {
314 if ( exponent(st0_ptr) > -40 )
315 {
316 if ( (q = trig_arg(st0_ptr, 0)) == -1 )
317 {
318 /* Operand is out of range */
319 return;
320 }
321
322 poly_tan(st0_ptr);
323 setsign(st0_ptr, (q & 1) ^ (arg_sign != 0));
324 set_precision_flag_up(); /* We do not really know if up or down */
325 } 295 }
326 else
327 {
328 /* For a small arg, the result == the argument */
329 /* Underflow may happen */
330 296
331 denormal_arg: 297 if (st0_tag == TAG_Valid) {
298 if (exponent(st0_ptr) > -40) {
299 if ((q = trig_arg(st0_ptr, 0)) == -1) {
300 /* Operand is out of range */
301 return;
302 }
303
304 poly_tan(st0_ptr);
305 setsign(st0_ptr, (q & 1) ^ (arg_sign != 0));
306 set_precision_flag_up(); /* We do not really know if up or down */
307 } else {
308 /* For a small arg, the result == the argument */
309 /* Underflow may happen */
310
311 denormal_arg:
312
313 FPU_to_exp16(st0_ptr, st0_ptr);
332 314
333 FPU_to_exp16(st0_ptr, st0_ptr); 315 st0_tag =
334 316 FPU_round(st0_ptr, 1, 0, FULL_PRECISION, arg_sign);
335 st0_tag = FPU_round(st0_ptr, 1, 0, FULL_PRECISION, arg_sign); 317 FPU_settag0(st0_tag);
336 FPU_settag0(st0_tag); 318 }
319 push();
320 FPU_copy_to_reg0(&CONST_1, TAG_Valid);
321 return;
337 } 322 }
338 push();
339 FPU_copy_to_reg0(&CONST_1, TAG_Valid);
340 return;
341 }
342
343 if ( st0_tag == TAG_Zero )
344 {
345 push();
346 FPU_copy_to_reg0(&CONST_1, TAG_Valid);
347 setcc(0);
348 return;
349 }
350
351 if ( st0_tag == TAG_Special )
352 st0_tag = FPU_Special(st0_ptr);
353
354 if ( st0_tag == TW_Denormal )
355 {
356 if ( denormal_operand() < 0 )
357 return;
358 323
359 goto denormal_arg; 324 if (st0_tag == TAG_Zero) {
360 } 325 push();
361 326 FPU_copy_to_reg0(&CONST_1, TAG_Valid);
362 if ( st0_tag == TW_Infinity ) 327 setcc(0);
363 { 328 return;
364 /* The 80486 treats infinity as an invalid operand */ 329 }
365 if ( arith_invalid(0) >= 0 ) 330
366 { 331 if (st0_tag == TAG_Special)
367 st_new_ptr = &st(-1); 332 st0_tag = FPU_Special(st0_ptr);
368 push(); 333
369 arith_invalid(0); 334 if (st0_tag == TW_Denormal) {
335 if (denormal_operand() < 0)
336 return;
337
338 goto denormal_arg;
370 } 339 }
371 return;
372 }
373 340
374 single_arg_2_error(st0_ptr, st0_tag); 341 if (st0_tag == TW_Infinity) {
375} 342 /* The 80486 treats infinity as an invalid operand */
343 if (arith_invalid(0) >= 0) {
344 st_new_ptr = &st(-1);
345 push();
346 arith_invalid(0);
347 }
348 return;
349 }
376 350
351 single_arg_2_error(st0_ptr, st0_tag);
352}
377 353
378static void fxtract(FPU_REG *st0_ptr, u_char st0_tag) 354static void fxtract(FPU_REG * st0_ptr, u_char st0_tag)
379{ 355{
380 FPU_REG *st_new_ptr; 356 FPU_REG *st_new_ptr;
381 u_char sign; 357 u_char sign;
382 register FPU_REG *st1_ptr = st0_ptr; /* anticipate */ 358 register FPU_REG *st1_ptr = st0_ptr; /* anticipate */
383
384 if ( STACK_OVERFLOW )
385 { FPU_stack_overflow(); return; }
386
387 clear_C1();
388
389 if ( st0_tag == TAG_Valid )
390 {
391 long e;
392
393 push();
394 sign = getsign(st1_ptr);
395 reg_copy(st1_ptr, st_new_ptr);
396 setexponent16(st_new_ptr, exponent(st_new_ptr));
397
398 denormal_arg:
399
400 e = exponent16(st_new_ptr);
401 convert_l2reg(&e, 1);
402 setexponentpos(st_new_ptr, 0);
403 setsign(st_new_ptr, sign);
404 FPU_settag0(TAG_Valid); /* Needed if arg was a denormal */
405 return;
406 }
407 else if ( st0_tag == TAG_Zero )
408 {
409 sign = getsign(st0_ptr);
410
411 if ( FPU_divide_by_zero(0, SIGN_NEG) < 0 )
412 return;
413 359
414 push(); 360 if (STACK_OVERFLOW) {
415 FPU_copy_to_reg0(&CONST_Z, TAG_Zero); 361 FPU_stack_overflow();
416 setsign(st_new_ptr, sign); 362 return;
417 return; 363 }
418 }
419 364
420 if ( st0_tag == TAG_Special ) 365 clear_C1();
421 st0_tag = FPU_Special(st0_ptr);
422 366
423 if ( st0_tag == TW_Denormal ) 367 if (st0_tag == TAG_Valid) {
424 { 368 long e;
425 if (denormal_operand() < 0 )
426 return;
427 369
428 push(); 370 push();
429 sign = getsign(st1_ptr); 371 sign = getsign(st1_ptr);
430 FPU_to_exp16(st1_ptr, st_new_ptr); 372 reg_copy(st1_ptr, st_new_ptr);
431 goto denormal_arg; 373 setexponent16(st_new_ptr, exponent(st_new_ptr));
432 } 374
433 else if ( st0_tag == TW_Infinity ) 375 denormal_arg:
434 { 376
435 sign = getsign(st0_ptr); 377 e = exponent16(st_new_ptr);
436 setpositive(st0_ptr); 378 convert_l2reg(&e, 1);
437 push(); 379 setexponentpos(st_new_ptr, 0);
438 FPU_copy_to_reg0(&CONST_INF, TAG_Special); 380 setsign(st_new_ptr, sign);
439 setsign(st_new_ptr, sign); 381 FPU_settag0(TAG_Valid); /* Needed if arg was a denormal */
440 return; 382 return;
441 } 383 } else if (st0_tag == TAG_Zero) {
442 else if ( st0_tag == TW_NaN ) 384 sign = getsign(st0_ptr);
443 { 385
444 if ( real_1op_NaN(st0_ptr) < 0 ) 386 if (FPU_divide_by_zero(0, SIGN_NEG) < 0)
445 return; 387 return;
446 388
447 push(); 389 push();
448 FPU_copy_to_reg0(st0_ptr, TAG_Special); 390 FPU_copy_to_reg0(&CONST_Z, TAG_Zero);
449 return; 391 setsign(st_new_ptr, sign);
450 } 392 return;
451 else if ( st0_tag == TAG_Empty ) 393 }
452 { 394
453 /* Is this the correct behaviour? */ 395 if (st0_tag == TAG_Special)
454 if ( control_word & EX_Invalid ) 396 st0_tag = FPU_Special(st0_ptr);
455 { 397
456 FPU_stack_underflow(); 398 if (st0_tag == TW_Denormal) {
457 push(); 399 if (denormal_operand() < 0)
458 FPU_stack_underflow(); 400 return;
401
402 push();
403 sign = getsign(st1_ptr);
404 FPU_to_exp16(st1_ptr, st_new_ptr);
405 goto denormal_arg;
406 } else if (st0_tag == TW_Infinity) {
407 sign = getsign(st0_ptr);
408 setpositive(st0_ptr);
409 push();
410 FPU_copy_to_reg0(&CONST_INF, TAG_Special);
411 setsign(st_new_ptr, sign);
412 return;
413 } else if (st0_tag == TW_NaN) {
414 if (real_1op_NaN(st0_ptr) < 0)
415 return;
416
417 push();
418 FPU_copy_to_reg0(st0_ptr, TAG_Special);
419 return;
420 } else if (st0_tag == TAG_Empty) {
421 /* Is this the correct behaviour? */
422 if (control_word & EX_Invalid) {
423 FPU_stack_underflow();
424 push();
425 FPU_stack_underflow();
426 } else
427 EXCEPTION(EX_StackUnder);
459 } 428 }
460 else
461 EXCEPTION(EX_StackUnder);
462 }
463#ifdef PARANOID 429#ifdef PARANOID
464 else 430 else
465 EXCEPTION(EX_INTERNAL | 0x119); 431 EXCEPTION(EX_INTERNAL | 0x119);
466#endif /* PARANOID */ 432#endif /* PARANOID */
467} 433}
468 434
469
470static void fdecstp(void) 435static void fdecstp(void)
471{ 436{
472 clear_C1(); 437 clear_C1();
473 top--; 438 top--;
474} 439}
475 440
476static void fincstp(void) 441static void fincstp(void)
477{ 442{
478 clear_C1(); 443 clear_C1();
479 top++; 444 top++;
480} 445}
481 446
482 447static void fsqrt_(FPU_REG * st0_ptr, u_char st0_tag)
483static void fsqrt_(FPU_REG *st0_ptr, u_char st0_tag)
484{ 448{
485 int expon; 449 int expon;
486 450
487 clear_C1(); 451 clear_C1();
488
489 if ( st0_tag == TAG_Valid )
490 {
491 u_char tag;
492
493 if (signnegative(st0_ptr))
494 {
495 arith_invalid(0); /* sqrt(negative) is invalid */
496 return;
497 }
498 452
499 /* make st(0) in [1.0 .. 4.0) */ 453 if (st0_tag == TAG_Valid) {
500 expon = exponent(st0_ptr); 454 u_char tag;
501 455
502 denormal_arg: 456 if (signnegative(st0_ptr)) {
503 457 arith_invalid(0); /* sqrt(negative) is invalid */
504 setexponent16(st0_ptr, (expon & 1)); 458 return;
505 459 }
506 /* Do the computation, the sign of the result will be positive. */ 460
507 tag = wm_sqrt(st0_ptr, 0, 0, control_word, SIGN_POS); 461 /* make st(0) in [1.0 .. 4.0) */
508 addexponent(st0_ptr, expon >> 1); 462 expon = exponent(st0_ptr);
509 FPU_settag0(tag); 463
510 return; 464 denormal_arg:
511 } 465
512 466 setexponent16(st0_ptr, (expon & 1));
513 if ( st0_tag == TAG_Zero ) 467
514 return; 468 /* Do the computation, the sign of the result will be positive. */
515 469 tag = wm_sqrt(st0_ptr, 0, 0, control_word, SIGN_POS);
516 if ( st0_tag == TAG_Special ) 470 addexponent(st0_ptr, expon >> 1);
517 st0_tag = FPU_Special(st0_ptr); 471 FPU_settag0(tag);
518 472 return;
519 if ( st0_tag == TW_Infinity )
520 {
521 if ( signnegative(st0_ptr) )
522 arith_invalid(0); /* sqrt(-Infinity) is invalid */
523 return;
524 }
525 else if ( st0_tag == TW_Denormal )
526 {
527 if (signnegative(st0_ptr))
528 {
529 arith_invalid(0); /* sqrt(negative) is invalid */
530 return;
531 } 473 }
532 474
533 if ( denormal_operand() < 0 ) 475 if (st0_tag == TAG_Zero)
534 return; 476 return;
535 477
536 FPU_to_exp16(st0_ptr, st0_ptr); 478 if (st0_tag == TAG_Special)
479 st0_tag = FPU_Special(st0_ptr);
537 480
538 expon = exponent16(st0_ptr); 481 if (st0_tag == TW_Infinity) {
482 if (signnegative(st0_ptr))
483 arith_invalid(0); /* sqrt(-Infinity) is invalid */
484 return;
485 } else if (st0_tag == TW_Denormal) {
486 if (signnegative(st0_ptr)) {
487 arith_invalid(0); /* sqrt(negative) is invalid */
488 return;
489 }
539 490
540 goto denormal_arg; 491 if (denormal_operand() < 0)
541 } 492 return;
542 493
543 single_arg_error(st0_ptr, st0_tag); 494 FPU_to_exp16(st0_ptr, st0_ptr);
544 495
545} 496 expon = exponent16(st0_ptr);
497
498 goto denormal_arg;
499 }
546 500
501 single_arg_error(st0_ptr, st0_tag);
547 502
548static void frndint_(FPU_REG *st0_ptr, u_char st0_tag) 503}
504
505static void frndint_(FPU_REG * st0_ptr, u_char st0_tag)
549{ 506{
550 int flags, tag; 507 int flags, tag;
551 508
552 if ( st0_tag == TAG_Valid ) 509 if (st0_tag == TAG_Valid) {
553 { 510 u_char sign;
554 u_char sign;
555 511
556 denormal_arg: 512 denormal_arg:
557 513
558 sign = getsign(st0_ptr); 514 sign = getsign(st0_ptr);
559 515
560 if (exponent(st0_ptr) > 63) 516 if (exponent(st0_ptr) > 63)
561 return; 517 return;
518
519 if (st0_tag == TW_Denormal) {
520 if (denormal_operand() < 0)
521 return;
522 }
523
524 /* Fortunately, this can't overflow to 2^64 */
525 if ((flags = FPU_round_to_int(st0_ptr, st0_tag)))
526 set_precision_flag(flags);
562 527
563 if ( st0_tag == TW_Denormal ) 528 setexponent16(st0_ptr, 63);
564 { 529 tag = FPU_normalize(st0_ptr);
565 if (denormal_operand() < 0 ) 530 setsign(st0_ptr, sign);
566 return; 531 FPU_settag0(tag);
532 return;
567 } 533 }
568 534
569 /* Fortunately, this can't overflow to 2^64 */ 535 if (st0_tag == TAG_Zero)
570 if ( (flags = FPU_round_to_int(st0_ptr, st0_tag)) ) 536 return;
571 set_precision_flag(flags);
572
573 setexponent16(st0_ptr, 63);
574 tag = FPU_normalize(st0_ptr);
575 setsign(st0_ptr, sign);
576 FPU_settag0(tag);
577 return;
578 }
579
580 if ( st0_tag == TAG_Zero )
581 return;
582
583 if ( st0_tag == TAG_Special )
584 st0_tag = FPU_Special(st0_ptr);
585
586 if ( st0_tag == TW_Denormal )
587 goto denormal_arg;
588 else if ( st0_tag == TW_Infinity )
589 return;
590 else
591 single_arg_error(st0_ptr, st0_tag);
592}
593 537
538 if (st0_tag == TAG_Special)
539 st0_tag = FPU_Special(st0_ptr);
594 540
595static int fsin(FPU_REG *st0_ptr, u_char tag) 541 if (st0_tag == TW_Denormal)
542 goto denormal_arg;
543 else if (st0_tag == TW_Infinity)
544 return;
545 else
546 single_arg_error(st0_ptr, st0_tag);
547}
548
549static int fsin(FPU_REG * st0_ptr, u_char tag)
596{ 550{
597 u_char arg_sign = getsign(st0_ptr); 551 u_char arg_sign = getsign(st0_ptr);
598 552
599 if ( tag == TAG_Valid ) 553 if (tag == TAG_Valid) {
600 { 554 int q;
601 int q; 555
602 556 if (exponent(st0_ptr) > -40) {
603 if ( exponent(st0_ptr) > -40 ) 557 if ((q = trig_arg(st0_ptr, 0)) == -1) {
604 { 558 /* Operand is out of range */
605 if ( (q = trig_arg(st0_ptr, 0)) == -1 ) 559 return 1;
606 { 560 }
607 /* Operand is out of range */ 561
608 return 1; 562 poly_sine(st0_ptr);
609 } 563
610 564 if (q & 2)
611 poly_sine(st0_ptr); 565 changesign(st0_ptr);
612 566
613 if (q & 2) 567 setsign(st0_ptr, getsign(st0_ptr) ^ arg_sign);
614 changesign(st0_ptr); 568
615 569 /* We do not really know if up or down */
616 setsign(st0_ptr, getsign(st0_ptr) ^ arg_sign); 570 set_precision_flag_up();
617 571 return 0;
618 /* We do not really know if up or down */ 572 } else {
619 set_precision_flag_up(); 573 /* For a small arg, the result == the argument */
620 return 0; 574 set_precision_flag_up(); /* Must be up. */
575 return 0;
576 }
621 } 577 }
622 else 578
623 { 579 if (tag == TAG_Zero) {
624 /* For a small arg, the result == the argument */ 580 setcc(0);
625 set_precision_flag_up(); /* Must be up. */ 581 return 0;
626 return 0;
627 } 582 }
628 }
629
630 if ( tag == TAG_Zero )
631 {
632 setcc(0);
633 return 0;
634 }
635
636 if ( tag == TAG_Special )
637 tag = FPU_Special(st0_ptr);
638
639 if ( tag == TW_Denormal )
640 {
641 if ( denormal_operand() < 0 )
642 return 1;
643
644 /* For a small arg, the result == the argument */
645 /* Underflow may happen */
646 FPU_to_exp16(st0_ptr, st0_ptr);
647
648 tag = FPU_round(st0_ptr, 1, 0, FULL_PRECISION, arg_sign);
649
650 FPU_settag0(tag);
651
652 return 0;
653 }
654 else if ( tag == TW_Infinity )
655 {
656 /* The 80486 treats infinity as an invalid operand */
657 arith_invalid(0);
658 return 1;
659 }
660 else
661 {
662 single_arg_error(st0_ptr, tag);
663 return 1;
664 }
665}
666 583
584 if (tag == TAG_Special)
585 tag = FPU_Special(st0_ptr);
667 586
668static int f_cos(FPU_REG *st0_ptr, u_char tag) 587 if (tag == TW_Denormal) {
669{ 588 if (denormal_operand() < 0)
670 u_char st0_sign; 589 return 1;
671 590
672 st0_sign = getsign(st0_ptr); 591 /* For a small arg, the result == the argument */
673 592 /* Underflow may happen */
674 if ( tag == TAG_Valid ) 593 FPU_to_exp16(st0_ptr, st0_ptr);
675 { 594
676 int q; 595 tag = FPU_round(st0_ptr, 1, 0, FULL_PRECISION, arg_sign);
677 596
678 if ( exponent(st0_ptr) > -40 ) 597 FPU_settag0(tag);
679 { 598
680 if ( (exponent(st0_ptr) < 0) 599 return 0;
681 || ((exponent(st0_ptr) == 0) 600 } else if (tag == TW_Infinity) {
682 && (significand(st0_ptr) <= 0xc90fdaa22168c234LL)) ) 601 /* The 80486 treats infinity as an invalid operand */
683 { 602 arith_invalid(0);
684 poly_cos(st0_ptr); 603 return 1;
685 604 } else {
686 /* We do not really know if up or down */ 605 single_arg_error(st0_ptr, tag);
687 set_precision_flag_down(); 606 return 1;
688
689 return 0;
690 }
691 else if ( (q = trig_arg(st0_ptr, FCOS)) != -1 )
692 {
693 poly_sine(st0_ptr);
694
695 if ((q+1) & 2)
696 changesign(st0_ptr);
697
698 /* We do not really know if up or down */
699 set_precision_flag_down();
700
701 return 0;
702 }
703 else
704 {
705 /* Operand is out of range */
706 return 1;
707 }
708 } 607 }
709 else 608}
710 { 609
711 denormal_arg: 610static int f_cos(FPU_REG * st0_ptr, u_char tag)
611{
612 u_char st0_sign;
613
614 st0_sign = getsign(st0_ptr);
712 615
713 setcc(0); 616 if (tag == TAG_Valid) {
714 FPU_copy_to_reg0(&CONST_1, TAG_Valid); 617 int q;
618
619 if (exponent(st0_ptr) > -40) {
620 if ((exponent(st0_ptr) < 0)
621 || ((exponent(st0_ptr) == 0)
622 && (significand(st0_ptr) <=
623 0xc90fdaa22168c234LL))) {
624 poly_cos(st0_ptr);
625
626 /* We do not really know if up or down */
627 set_precision_flag_down();
628
629 return 0;
630 } else if ((q = trig_arg(st0_ptr, FCOS)) != -1) {
631 poly_sine(st0_ptr);
632
633 if ((q + 1) & 2)
634 changesign(st0_ptr);
635
636 /* We do not really know if up or down */
637 set_precision_flag_down();
638
639 return 0;
640 } else {
641 /* Operand is out of range */
642 return 1;
643 }
644 } else {
645 denormal_arg:
646
647 setcc(0);
648 FPU_copy_to_reg0(&CONST_1, TAG_Valid);
715#ifdef PECULIAR_486 649#ifdef PECULIAR_486
716 set_precision_flag_down(); /* 80486 appears to do this. */ 650 set_precision_flag_down(); /* 80486 appears to do this. */
717#else 651#else
718 set_precision_flag_up(); /* Must be up. */ 652 set_precision_flag_up(); /* Must be up. */
719#endif /* PECULIAR_486 */ 653#endif /* PECULIAR_486 */
720 return 0; 654 return 0;
655 }
656 } else if (tag == TAG_Zero) {
657 FPU_copy_to_reg0(&CONST_1, TAG_Valid);
658 setcc(0);
659 return 0;
721 } 660 }
722 }
723 else if ( tag == TAG_Zero )
724 {
725 FPU_copy_to_reg0(&CONST_1, TAG_Valid);
726 setcc(0);
727 return 0;
728 }
729
730 if ( tag == TAG_Special )
731 tag = FPU_Special(st0_ptr);
732
733 if ( tag == TW_Denormal )
734 {
735 if ( denormal_operand() < 0 )
736 return 1;
737
738 goto denormal_arg;
739 }
740 else if ( tag == TW_Infinity )
741 {
742 /* The 80486 treats infinity as an invalid operand */
743 arith_invalid(0);
744 return 1;
745 }
746 else
747 {
748 single_arg_error(st0_ptr, tag); /* requires st0_ptr == &st(0) */
749 return 1;
750 }
751}
752 661
662 if (tag == TAG_Special)
663 tag = FPU_Special(st0_ptr);
664
665 if (tag == TW_Denormal) {
666 if (denormal_operand() < 0)
667 return 1;
668
669 goto denormal_arg;
670 } else if (tag == TW_Infinity) {
671 /* The 80486 treats infinity as an invalid operand */
672 arith_invalid(0);
673 return 1;
674 } else {
675 single_arg_error(st0_ptr, tag); /* requires st0_ptr == &st(0) */
676 return 1;
677 }
678}
753 679
754static void fcos(FPU_REG *st0_ptr, u_char st0_tag) 680static void fcos(FPU_REG * st0_ptr, u_char st0_tag)
755{ 681{
756 f_cos(st0_ptr, st0_tag); 682 f_cos(st0_ptr, st0_tag);
757} 683}
758 684
759 685static void fsincos(FPU_REG * st0_ptr, u_char st0_tag)
760static void fsincos(FPU_REG *st0_ptr, u_char st0_tag)
761{ 686{
762 FPU_REG *st_new_ptr; 687 FPU_REG *st_new_ptr;
763 FPU_REG arg; 688 FPU_REG arg;
764 u_char tag; 689 u_char tag;
765 690
766 /* Stack underflow has higher priority */ 691 /* Stack underflow has higher priority */
767 if ( st0_tag == TAG_Empty ) 692 if (st0_tag == TAG_Empty) {
768 { 693 FPU_stack_underflow(); /* Puts a QNaN in st(0) */
769 FPU_stack_underflow(); /* Puts a QNaN in st(0) */ 694 if (control_word & CW_Invalid) {
770 if ( control_word & CW_Invalid ) 695 st_new_ptr = &st(-1);
771 { 696 push();
772 st_new_ptr = &st(-1); 697 FPU_stack_underflow(); /* Puts a QNaN in the new st(0) */
773 push(); 698 }
774 FPU_stack_underflow(); /* Puts a QNaN in the new st(0) */ 699 return;
775 } 700 }
776 return; 701
777 } 702 if (STACK_OVERFLOW) {
778 703 FPU_stack_overflow();
779 if ( STACK_OVERFLOW ) 704 return;
780 { FPU_stack_overflow(); return; }
781
782 if ( st0_tag == TAG_Special )
783 tag = FPU_Special(st0_ptr);
784 else
785 tag = st0_tag;
786
787 if ( tag == TW_NaN )
788 {
789 single_arg_2_error(st0_ptr, TW_NaN);
790 return;
791 }
792 else if ( tag == TW_Infinity )
793 {
794 /* The 80486 treats infinity as an invalid operand */
795 if ( arith_invalid(0) >= 0 )
796 {
797 /* Masked response */
798 push();
799 arith_invalid(0);
800 } 705 }
801 return;
802 }
803
804 reg_copy(st0_ptr, &arg);
805 if ( !fsin(st0_ptr, st0_tag) )
806 {
807 push();
808 FPU_copy_to_reg0(&arg, st0_tag);
809 f_cos(&st(0), st0_tag);
810 }
811 else
812 {
813 /* An error, so restore st(0) */
814 FPU_copy_to_reg0(&arg, st0_tag);
815 }
816}
817 706
707 if (st0_tag == TAG_Special)
708 tag = FPU_Special(st0_ptr);
709 else
710 tag = st0_tag;
711
712 if (tag == TW_NaN) {
713 single_arg_2_error(st0_ptr, TW_NaN);
714 return;
715 } else if (tag == TW_Infinity) {
716 /* The 80486 treats infinity as an invalid operand */
717 if (arith_invalid(0) >= 0) {
718 /* Masked response */
719 push();
720 arith_invalid(0);
721 }
722 return;
723 }
724
725 reg_copy(st0_ptr, &arg);
726 if (!fsin(st0_ptr, st0_tag)) {
727 push();
728 FPU_copy_to_reg0(&arg, st0_tag);
729 f_cos(&st(0), st0_tag);
730 } else {
731 /* An error, so restore st(0) */
732 FPU_copy_to_reg0(&arg, st0_tag);
733 }
734}
818 735
819/*---------------------------------------------------------------------------*/ 736/*---------------------------------------------------------------------------*/
820/* The following all require two arguments: st(0) and st(1) */ 737/* The following all require two arguments: st(0) and st(1) */
@@ -826,1020 +743,901 @@ static void fsincos(FPU_REG *st0_ptr, u_char st0_tag)
826 result must be zero. 743 result must be zero.
827 */ 744 */
828static void rem_kernel(unsigned long long st0, unsigned long long *y, 745static void rem_kernel(unsigned long long st0, unsigned long long *y,
829 unsigned long long st1, 746 unsigned long long st1, unsigned long long q, int n)
830 unsigned long long q, int n)
831{ 747{
832 int dummy; 748 int dummy;
833 unsigned long long x; 749 unsigned long long x;
834 750
835 x = st0 << n; 751 x = st0 << n;
836 752
837 /* Do the required multiplication and subtraction in the one operation */ 753 /* Do the required multiplication and subtraction in the one operation */
838 754
839 /* lsw x -= lsw st1 * lsw q */ 755 /* lsw x -= lsw st1 * lsw q */
840 asm volatile ("mull %4; subl %%eax,%0; sbbl %%edx,%1" 756 asm volatile ("mull %4; subl %%eax,%0; sbbl %%edx,%1":"=m"
841 :"=m" (((unsigned *)&x)[0]), "=m" (((unsigned *)&x)[1]), 757 (((unsigned *)&x)[0]), "=m"(((unsigned *)&x)[1]),
842 "=a" (dummy) 758 "=a"(dummy)
843 :"2" (((unsigned *)&st1)[0]), "m" (((unsigned *)&q)[0]) 759 :"2"(((unsigned *)&st1)[0]), "m"(((unsigned *)&q)[0])
844 :"%dx"); 760 :"%dx");
845 /* msw x -= msw st1 * lsw q */ 761 /* msw x -= msw st1 * lsw q */
846 asm volatile ("mull %3; subl %%eax,%0" 762 asm volatile ("mull %3; subl %%eax,%0":"=m" (((unsigned *)&x)[1]),
847 :"=m" (((unsigned *)&x)[1]), "=a" (dummy) 763 "=a"(dummy)
848 :"1" (((unsigned *)&st1)[1]), "m" (((unsigned *)&q)[0]) 764 :"1"(((unsigned *)&st1)[1]), "m"(((unsigned *)&q)[0])
849 :"%dx"); 765 :"%dx");
850 /* msw x -= lsw st1 * msw q */ 766 /* msw x -= lsw st1 * msw q */
851 asm volatile ("mull %3; subl %%eax,%0" 767 asm volatile ("mull %3; subl %%eax,%0":"=m" (((unsigned *)&x)[1]),
852 :"=m" (((unsigned *)&x)[1]), "=a" (dummy) 768 "=a"(dummy)
853 :"1" (((unsigned *)&st1)[0]), "m" (((unsigned *)&q)[1]) 769 :"1"(((unsigned *)&st1)[0]), "m"(((unsigned *)&q)[1])
854 :"%dx"); 770 :"%dx");
855 771
856 *y = x; 772 *y = x;
857} 773}
858 774
859
860/* Remainder of st(0) / st(1) */ 775/* Remainder of st(0) / st(1) */
861/* This routine produces exact results, i.e. there is never any 776/* This routine produces exact results, i.e. there is never any
862 rounding or truncation, etc of the result. */ 777 rounding or truncation, etc of the result. */
863static void do_fprem(FPU_REG *st0_ptr, u_char st0_tag, int round) 778static void do_fprem(FPU_REG * st0_ptr, u_char st0_tag, int round)
864{ 779{
865 FPU_REG *st1_ptr = &st(1); 780 FPU_REG *st1_ptr = &st(1);
866 u_char st1_tag = FPU_gettagi(1); 781 u_char st1_tag = FPU_gettagi(1);
867 782
868 if ( !((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid)) ) 783 if (!((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid))) {
869 { 784 FPU_REG tmp, st0, st1;
870 FPU_REG tmp, st0, st1; 785 u_char st0_sign, st1_sign;
871 u_char st0_sign, st1_sign; 786 u_char tmptag;
872 u_char tmptag; 787 int tag;
873 int tag; 788 int old_cw;
874 int old_cw; 789 int expdif;
875 int expdif; 790 long long q;
876 long long q; 791 unsigned short saved_status;
877 unsigned short saved_status; 792 int cc;
878 int cc; 793
879 794 fprem_valid:
880 fprem_valid: 795 /* Convert registers for internal use. */
881 /* Convert registers for internal use. */ 796 st0_sign = FPU_to_exp16(st0_ptr, &st0);
882 st0_sign = FPU_to_exp16(st0_ptr, &st0); 797 st1_sign = FPU_to_exp16(st1_ptr, &st1);
883 st1_sign = FPU_to_exp16(st1_ptr, &st1); 798 expdif = exponent16(&st0) - exponent16(&st1);
884 expdif = exponent16(&st0) - exponent16(&st1); 799
885 800 old_cw = control_word;
886 old_cw = control_word; 801 cc = 0;
887 cc = 0; 802
888 803 /* We want the status following the denorm tests, but don't want
889 /* We want the status following the denorm tests, but don't want 804 the status changed by the arithmetic operations. */
890 the status changed by the arithmetic operations. */ 805 saved_status = partial_status;
891 saved_status = partial_status; 806 control_word &= ~CW_RC;
892 control_word &= ~CW_RC; 807 control_word |= RC_CHOP;
893 control_word |= RC_CHOP; 808
894 809 if (expdif < 64) {
895 if ( expdif < 64 ) 810 /* This should be the most common case */
896 { 811
897 /* This should be the most common case */ 812 if (expdif > -2) {
898 813 u_char sign = st0_sign ^ st1_sign;
899 if ( expdif > -2 ) 814 tag = FPU_u_div(&st0, &st1, &tmp,
900 { 815 PR_64_BITS | RC_CHOP | 0x3f,
901 u_char sign = st0_sign ^ st1_sign; 816 sign);
902 tag = FPU_u_div(&st0, &st1, &tmp, 817 setsign(&tmp, sign);
903 PR_64_BITS | RC_CHOP | 0x3f, 818
904 sign); 819 if (exponent(&tmp) >= 0) {
905 setsign(&tmp, sign); 820 FPU_round_to_int(&tmp, tag); /* Fortunately, this can't
906 821 overflow to 2^64 */
907 if ( exponent(&tmp) >= 0 ) 822 q = significand(&tmp);
908 { 823
909 FPU_round_to_int(&tmp, tag); /* Fortunately, this can't 824 rem_kernel(significand(&st0),
910 overflow to 2^64 */ 825 &significand(&tmp),
911 q = significand(&tmp); 826 significand(&st1),
912 827 q, expdif);
913 rem_kernel(significand(&st0), 828
914 &significand(&tmp), 829 setexponent16(&tmp, exponent16(&st1));
915 significand(&st1), 830 } else {
916 q, expdif); 831 reg_copy(&st0, &tmp);
917 832 q = 0;
918 setexponent16(&tmp, exponent16(&st1)); 833 }
919 } 834
920 else 835 if ((round == RC_RND)
921 { 836 && (tmp.sigh & 0xc0000000)) {
922 reg_copy(&st0, &tmp); 837 /* We may need to subtract st(1) once more,
923 q = 0; 838 to get a result <= 1/2 of st(1). */
924 } 839 unsigned long long x;
925 840 expdif =
926 if ( (round == RC_RND) && (tmp.sigh & 0xc0000000) ) 841 exponent16(&st1) - exponent16(&tmp);
927 { 842 if (expdif <= 1) {
928 /* We may need to subtract st(1) once more, 843 if (expdif == 0)
929 to get a result <= 1/2 of st(1). */ 844 x = significand(&st1) -
930 unsigned long long x; 845 significand(&tmp);
931 expdif = exponent16(&st1) - exponent16(&tmp); 846 else /* expdif is 1 */
932 if ( expdif <= 1 ) 847 x = (significand(&st1)
933 { 848 << 1) -
934 if ( expdif == 0 ) 849 significand(&tmp);
935 x = significand(&st1) - significand(&tmp); 850 if ((x < significand(&tmp)) ||
936 else /* expdif is 1 */ 851 /* or equi-distant (from 0 & st(1)) and q is odd */
937 x = (significand(&st1) << 1) - significand(&tmp); 852 ((x == significand(&tmp))
938 if ( (x < significand(&tmp)) || 853 && (q & 1))) {
939 /* or equi-distant (from 0 & st(1)) and q is odd */ 854 st0_sign = !st0_sign;
940 ((x == significand(&tmp)) && (q & 1) ) ) 855 significand(&tmp) = x;
941 { 856 q++;
942 st0_sign = ! st0_sign; 857 }
943 significand(&tmp) = x; 858 }
944 q++; 859 }
860
861 if (q & 4)
862 cc |= SW_C0;
863 if (q & 2)
864 cc |= SW_C3;
865 if (q & 1)
866 cc |= SW_C1;
867 } else {
868 control_word = old_cw;
869 setcc(0);
870 return;
945 } 871 }
946 } 872 } else {
947 } 873 /* There is a large exponent difference ( >= 64 ) */
948 874 /* To make much sense, the code in this section should
949 if (q & 4) cc |= SW_C0; 875 be done at high precision. */
950 if (q & 2) cc |= SW_C3; 876 int exp_1, N;
951 if (q & 1) cc |= SW_C1; 877 u_char sign;
952 } 878
953 else 879 /* prevent overflow here */
954 { 880 /* N is 'a number between 32 and 63' (p26-113) */
955 control_word = old_cw; 881 reg_copy(&st0, &tmp);
956 setcc(0); 882 tmptag = st0_tag;
957 return; 883 N = (expdif & 0x0000001f) + 32; /* This choice gives results
958 } 884 identical to an AMD 486 */
959 } 885 setexponent16(&tmp, N);
960 else 886 exp_1 = exponent16(&st1);
961 { 887 setexponent16(&st1, 0);
962 /* There is a large exponent difference ( >= 64 ) */ 888 expdif -= N;
963 /* To make much sense, the code in this section should 889
964 be done at high precision. */ 890 sign = getsign(&tmp) ^ st1_sign;
965 int exp_1, N; 891 tag =
966 u_char sign; 892 FPU_u_div(&tmp, &st1, &tmp,
967 893 PR_64_BITS | RC_CHOP | 0x3f, sign);
968 /* prevent overflow here */ 894 setsign(&tmp, sign);
969 /* N is 'a number between 32 and 63' (p26-113) */ 895
970 reg_copy(&st0, &tmp); 896 FPU_round_to_int(&tmp, tag); /* Fortunately, this can't
971 tmptag = st0_tag; 897 overflow to 2^64 */
972 N = (expdif & 0x0000001f) + 32; /* This choice gives results 898
973 identical to an AMD 486 */ 899 rem_kernel(significand(&st0),
974 setexponent16(&tmp, N); 900 &significand(&tmp),
975 exp_1 = exponent16(&st1); 901 significand(&st1),
976 setexponent16(&st1, 0); 902 significand(&tmp), exponent(&tmp)
977 expdif -= N; 903 );
978 904 setexponent16(&tmp, exp_1 + expdif);
979 sign = getsign(&tmp) ^ st1_sign; 905
980 tag = FPU_u_div(&tmp, &st1, &tmp, PR_64_BITS | RC_CHOP | 0x3f, 906 /* It is possible for the operation to be complete here.
981 sign); 907 What does the IEEE standard say? The Intel 80486 manual
982 setsign(&tmp, sign); 908 implies that the operation will never be completed at this
983 909 point, and the behaviour of a real 80486 confirms this.
984 FPU_round_to_int(&tmp, tag); /* Fortunately, this can't 910 */
985 overflow to 2^64 */ 911 if (!(tmp.sigh | tmp.sigl)) {
986 912 /* The result is zero */
987 rem_kernel(significand(&st0), 913 control_word = old_cw;
988 &significand(&tmp), 914 partial_status = saved_status;
989 significand(&st1), 915 FPU_copy_to_reg0(&CONST_Z, TAG_Zero);
990 significand(&tmp), 916 setsign(&st0, st0_sign);
991 exponent(&tmp)
992 );
993 setexponent16(&tmp, exp_1 + expdif);
994
995 /* It is possible for the operation to be complete here.
996 What does the IEEE standard say? The Intel 80486 manual
997 implies that the operation will never be completed at this
998 point, and the behaviour of a real 80486 confirms this.
999 */
1000 if ( !(tmp.sigh | tmp.sigl) )
1001 {
1002 /* The result is zero */
1003 control_word = old_cw;
1004 partial_status = saved_status;
1005 FPU_copy_to_reg0(&CONST_Z, TAG_Zero);
1006 setsign(&st0, st0_sign);
1007#ifdef PECULIAR_486 917#ifdef PECULIAR_486
1008 setcc(SW_C2); 918 setcc(SW_C2);
1009#else 919#else
1010 setcc(0); 920 setcc(0);
1011#endif /* PECULIAR_486 */ 921#endif /* PECULIAR_486 */
1012 return; 922 return;
1013 } 923 }
1014 cc = SW_C2; 924 cc = SW_C2;
1015 } 925 }
1016 926
1017 control_word = old_cw; 927 control_word = old_cw;
1018 partial_status = saved_status; 928 partial_status = saved_status;
1019 tag = FPU_normalize_nuo(&tmp); 929 tag = FPU_normalize_nuo(&tmp);
1020 reg_copy(&tmp, st0_ptr); 930 reg_copy(&tmp, st0_ptr);
1021 931
1022 /* The only condition to be looked for is underflow, 932 /* The only condition to be looked for is underflow,
1023 and it can occur here only if underflow is unmasked. */ 933 and it can occur here only if underflow is unmasked. */
1024 if ( (exponent16(&tmp) <= EXP_UNDER) && (tag != TAG_Zero) 934 if ((exponent16(&tmp) <= EXP_UNDER) && (tag != TAG_Zero)
1025 && !(control_word & CW_Underflow) ) 935 && !(control_word & CW_Underflow)) {
1026 { 936 setcc(cc);
1027 setcc(cc); 937 tag = arith_underflow(st0_ptr);
1028 tag = arith_underflow(st0_ptr); 938 setsign(st0_ptr, st0_sign);
1029 setsign(st0_ptr, st0_sign); 939 FPU_settag0(tag);
1030 FPU_settag0(tag); 940 return;
1031 return; 941 } else if ((exponent16(&tmp) > EXP_UNDER) || (tag == TAG_Zero)) {
1032 } 942 stdexp(st0_ptr);
1033 else if ( (exponent16(&tmp) > EXP_UNDER) || (tag == TAG_Zero) ) 943 setsign(st0_ptr, st0_sign);
1034 { 944 } else {
1035 stdexp(st0_ptr); 945 tag =
1036 setsign(st0_ptr, st0_sign); 946 FPU_round(st0_ptr, 0, 0, FULL_PRECISION, st0_sign);
1037 } 947 }
1038 else 948 FPU_settag0(tag);
1039 { 949 setcc(cc);
1040 tag = FPU_round(st0_ptr, 0, 0, FULL_PRECISION, st0_sign);
1041 }
1042 FPU_settag0(tag);
1043 setcc(cc);
1044 950
1045 return; 951 return;
1046 } 952 }
1047 953
1048 if ( st0_tag == TAG_Special ) 954 if (st0_tag == TAG_Special)
1049 st0_tag = FPU_Special(st0_ptr); 955 st0_tag = FPU_Special(st0_ptr);
1050 if ( st1_tag == TAG_Special ) 956 if (st1_tag == TAG_Special)
1051 st1_tag = FPU_Special(st1_ptr); 957 st1_tag = FPU_Special(st1_ptr);
1052 958
1053 if ( ((st0_tag == TAG_Valid) && (st1_tag == TW_Denormal)) 959 if (((st0_tag == TAG_Valid) && (st1_tag == TW_Denormal))
1054 || ((st0_tag == TW_Denormal) && (st1_tag == TAG_Valid)) 960 || ((st0_tag == TW_Denormal) && (st1_tag == TAG_Valid))
1055 || ((st0_tag == TW_Denormal) && (st1_tag == TW_Denormal)) ) 961 || ((st0_tag == TW_Denormal) && (st1_tag == TW_Denormal))) {
1056 { 962 if (denormal_operand() < 0)
1057 if ( denormal_operand() < 0 ) 963 return;
1058 return; 964 goto fprem_valid;
1059 goto fprem_valid; 965 } else if ((st0_tag == TAG_Empty) || (st1_tag == TAG_Empty)) {
1060 } 966 FPU_stack_underflow();
1061 else if ( (st0_tag == TAG_Empty) || (st1_tag == TAG_Empty) ) 967 return;
1062 { 968 } else if (st0_tag == TAG_Zero) {
1063 FPU_stack_underflow(); 969 if (st1_tag == TAG_Valid) {
1064 return; 970 setcc(0);
1065 } 971 return;
1066 else if ( st0_tag == TAG_Zero ) 972 } else if (st1_tag == TW_Denormal) {
1067 { 973 if (denormal_operand() < 0)
1068 if ( st1_tag == TAG_Valid ) 974 return;
1069 { 975 setcc(0);
1070 setcc(0); return; 976 return;
1071 } 977 } else if (st1_tag == TAG_Zero) {
1072 else if ( st1_tag == TW_Denormal ) 978 arith_invalid(0);
1073 { 979 return;
1074 if ( denormal_operand() < 0 ) 980 } /* fprem(?,0) always invalid */
1075 return; 981 else if (st1_tag == TW_Infinity) {
1076 setcc(0); return; 982 setcc(0);
1077 } 983 return;
1078 else if ( st1_tag == TAG_Zero ) 984 }
1079 { arith_invalid(0); return; } /* fprem(?,0) always invalid */ 985 } else if ((st0_tag == TAG_Valid) || (st0_tag == TW_Denormal)) {
1080 else if ( st1_tag == TW_Infinity ) 986 if (st1_tag == TAG_Zero) {
1081 { setcc(0); return; } 987 arith_invalid(0); /* fprem(Valid,Zero) is invalid */
1082 } 988 return;
1083 else if ( (st0_tag == TAG_Valid) || (st0_tag == TW_Denormal) ) 989 } else if (st1_tag != TW_NaN) {
1084 { 990 if (((st0_tag == TW_Denormal)
1085 if ( st1_tag == TAG_Zero ) 991 || (st1_tag == TW_Denormal))
1086 { 992 && (denormal_operand() < 0))
1087 arith_invalid(0); /* fprem(Valid,Zero) is invalid */ 993 return;
1088 return; 994
1089 } 995 if (st1_tag == TW_Infinity) {
1090 else if ( st1_tag != TW_NaN ) 996 /* fprem(Valid,Infinity) is o.k. */
1091 { 997 setcc(0);
1092 if ( ((st0_tag == TW_Denormal) || (st1_tag == TW_Denormal)) 998 return;
1093 && (denormal_operand() < 0) ) 999 }
1094 return; 1000 }
1095 1001 } else if (st0_tag == TW_Infinity) {
1096 if ( st1_tag == TW_Infinity ) 1002 if (st1_tag != TW_NaN) {
1097 { 1003 arith_invalid(0); /* fprem(Infinity,?) is invalid */
1098 /* fprem(Valid,Infinity) is o.k. */ 1004 return;
1099 setcc(0); return; 1005 }
1100 }
1101 }
1102 }
1103 else if ( st0_tag == TW_Infinity )
1104 {
1105 if ( st1_tag != TW_NaN )
1106 {
1107 arith_invalid(0); /* fprem(Infinity,?) is invalid */
1108 return;
1109 } 1006 }
1110 }
1111 1007
1112 /* One of the registers must contain a NaN if we got here. */ 1008 /* One of the registers must contain a NaN if we got here. */
1113 1009
1114#ifdef PARANOID 1010#ifdef PARANOID
1115 if ( (st0_tag != TW_NaN) && (st1_tag != TW_NaN) ) 1011 if ((st0_tag != TW_NaN) && (st1_tag != TW_NaN))
1116 EXCEPTION(EX_INTERNAL | 0x118); 1012 EXCEPTION(EX_INTERNAL | 0x118);
1117#endif /* PARANOID */ 1013#endif /* PARANOID */
1118 1014
1119 real_2op_NaN(st1_ptr, st1_tag, 0, st1_ptr); 1015 real_2op_NaN(st1_ptr, st1_tag, 0, st1_ptr);
1120 1016
1121} 1017}
1122 1018
1123
1124/* ST(1) <- ST(1) * log ST; pop ST */ 1019/* ST(1) <- ST(1) * log ST; pop ST */
1125static void fyl2x(FPU_REG *st0_ptr, u_char st0_tag) 1020static void fyl2x(FPU_REG * st0_ptr, u_char st0_tag)
1126{ 1021{
1127 FPU_REG *st1_ptr = &st(1), exponent; 1022 FPU_REG *st1_ptr = &st(1), exponent;
1128 u_char st1_tag = FPU_gettagi(1); 1023 u_char st1_tag = FPU_gettagi(1);
1129 u_char sign; 1024 u_char sign;
1130 int e, tag; 1025 int e, tag;
1131 1026
1132 clear_C1(); 1027 clear_C1();
1133 1028
1134 if ( (st0_tag == TAG_Valid) && (st1_tag == TAG_Valid) ) 1029 if ((st0_tag == TAG_Valid) && (st1_tag == TAG_Valid)) {
1135 { 1030 both_valid:
1136 both_valid: 1031 /* Both regs are Valid or Denormal */
1137 /* Both regs are Valid or Denormal */ 1032 if (signpositive(st0_ptr)) {
1138 if ( signpositive(st0_ptr) ) 1033 if (st0_tag == TW_Denormal)
1139 { 1034 FPU_to_exp16(st0_ptr, st0_ptr);
1140 if ( st0_tag == TW_Denormal ) 1035 else
1141 FPU_to_exp16(st0_ptr, st0_ptr); 1036 /* Convert st(0) for internal use. */
1142 else 1037 setexponent16(st0_ptr, exponent(st0_ptr));
1143 /* Convert st(0) for internal use. */ 1038
1144 setexponent16(st0_ptr, exponent(st0_ptr)); 1039 if ((st0_ptr->sigh == 0x80000000)
1145 1040 && (st0_ptr->sigl == 0)) {
1146 if ( (st0_ptr->sigh == 0x80000000) && (st0_ptr->sigl == 0) ) 1041 /* Special case. The result can be precise. */
1147 { 1042 u_char esign;
1148 /* Special case. The result can be precise. */ 1043 e = exponent16(st0_ptr);
1149 u_char esign; 1044 if (e >= 0) {
1150 e = exponent16(st0_ptr); 1045 exponent.sigh = e;
1151 if ( e >= 0 ) 1046 esign = SIGN_POS;
1152 { 1047 } else {
1153 exponent.sigh = e; 1048 exponent.sigh = -e;
1154 esign = SIGN_POS; 1049 esign = SIGN_NEG;
1155 } 1050 }
1156 else 1051 exponent.sigl = 0;
1157 { 1052 setexponent16(&exponent, 31);
1158 exponent.sigh = -e; 1053 tag = FPU_normalize_nuo(&exponent);
1159 esign = SIGN_NEG; 1054 stdexp(&exponent);
1055 setsign(&exponent, esign);
1056 tag =
1057 FPU_mul(&exponent, tag, 1, FULL_PRECISION);
1058 if (tag >= 0)
1059 FPU_settagi(1, tag);
1060 } else {
1061 /* The usual case */
1062 sign = getsign(st1_ptr);
1063 if (st1_tag == TW_Denormal)
1064 FPU_to_exp16(st1_ptr, st1_ptr);
1065 else
1066 /* Convert st(1) for internal use. */
1067 setexponent16(st1_ptr,
1068 exponent(st1_ptr));
1069 poly_l2(st0_ptr, st1_ptr, sign);
1070 }
1071 } else {
1072 /* negative */
1073 if (arith_invalid(1) < 0)
1074 return;
1160 } 1075 }
1161 exponent.sigl = 0;
1162 setexponent16(&exponent, 31);
1163 tag = FPU_normalize_nuo(&exponent);
1164 stdexp(&exponent);
1165 setsign(&exponent, esign);
1166 tag = FPU_mul(&exponent, tag, 1, FULL_PRECISION);
1167 if ( tag >= 0 )
1168 FPU_settagi(1, tag);
1169 }
1170 else
1171 {
1172 /* The usual case */
1173 sign = getsign(st1_ptr);
1174 if ( st1_tag == TW_Denormal )
1175 FPU_to_exp16(st1_ptr, st1_ptr);
1176 else
1177 /* Convert st(1) for internal use. */
1178 setexponent16(st1_ptr, exponent(st1_ptr));
1179 poly_l2(st0_ptr, st1_ptr, sign);
1180 }
1181 }
1182 else
1183 {
1184 /* negative */
1185 if ( arith_invalid(1) < 0 )
1186 return;
1187 }
1188 1076
1189 FPU_pop(); 1077 FPU_pop();
1190
1191 return;
1192 }
1193
1194 if ( st0_tag == TAG_Special )
1195 st0_tag = FPU_Special(st0_ptr);
1196 if ( st1_tag == TAG_Special )
1197 st1_tag = FPU_Special(st1_ptr);
1198
1199 if ( (st0_tag == TAG_Empty) || (st1_tag == TAG_Empty) )
1200 {
1201 FPU_stack_underflow_pop(1);
1202 return;
1203 }
1204 else if ( (st0_tag <= TW_Denormal) && (st1_tag <= TW_Denormal) )
1205 {
1206 if ( st0_tag == TAG_Zero )
1207 {
1208 if ( st1_tag == TAG_Zero )
1209 {
1210 /* Both args zero is invalid */
1211 if ( arith_invalid(1) < 0 )
1212 return;
1213 }
1214 else
1215 {
1216 u_char sign;
1217 sign = getsign(st1_ptr)^SIGN_NEG;
1218 if ( FPU_divide_by_zero(1, sign) < 0 )
1219 return;
1220 1078
1221 setsign(st1_ptr, sign);
1222 }
1223 }
1224 else if ( st1_tag == TAG_Zero )
1225 {
1226 /* st(1) contains zero, st(0) valid <> 0 */
1227 /* Zero is the valid answer */
1228 sign = getsign(st1_ptr);
1229
1230 if ( signnegative(st0_ptr) )
1231 {
1232 /* log(negative) */
1233 if ( arith_invalid(1) < 0 )
1234 return; 1079 return;
1235 }
1236 else if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) )
1237 return;
1238 else
1239 {
1240 if ( exponent(st0_ptr) < 0 )
1241 sign ^= SIGN_NEG;
1242
1243 FPU_copy_to_reg1(&CONST_Z, TAG_Zero);
1244 setsign(st1_ptr, sign);
1245 }
1246 } 1080 }
1247 else
1248 {
1249 /* One or both operands are denormals. */
1250 if ( denormal_operand() < 0 )
1251 return;
1252 goto both_valid;
1253 }
1254 }
1255 else if ( (st0_tag == TW_NaN) || (st1_tag == TW_NaN) )
1256 {
1257 if ( real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0 )
1258 return;
1259 }
1260 /* One or both arg must be an infinity */
1261 else if ( st0_tag == TW_Infinity )
1262 {
1263 if ( (signnegative(st0_ptr)) || (st1_tag == TAG_Zero) )
1264 {
1265 /* log(-infinity) or 0*log(infinity) */
1266 if ( arith_invalid(1) < 0 )
1267 return;
1268 }
1269 else
1270 {
1271 u_char sign = getsign(st1_ptr);
1272 1081
1273 if ( (st1_tag == TW_Denormal) && (denormal_operand() < 0) ) 1082 if (st0_tag == TAG_Special)
1274 return; 1083 st0_tag = FPU_Special(st0_ptr);
1084 if (st1_tag == TAG_Special)
1085 st1_tag = FPU_Special(st1_ptr);
1275 1086
1276 FPU_copy_to_reg1(&CONST_INF, TAG_Special); 1087 if ((st0_tag == TAG_Empty) || (st1_tag == TAG_Empty)) {
1277 setsign(st1_ptr, sign); 1088 FPU_stack_underflow_pop(1);
1278 }
1279 }
1280 /* st(1) must be infinity here */
1281 else if ( ((st0_tag == TAG_Valid) || (st0_tag == TW_Denormal))
1282 && ( signpositive(st0_ptr) ) )
1283 {
1284 if ( exponent(st0_ptr) >= 0 )
1285 {
1286 if ( (exponent(st0_ptr) == 0) &&
1287 (st0_ptr->sigh == 0x80000000) &&
1288 (st0_ptr->sigl == 0) )
1289 {
1290 /* st(0) holds 1.0 */
1291 /* infinity*log(1) */
1292 if ( arith_invalid(1) < 0 )
1293 return; 1089 return;
1294 } 1090 } else if ((st0_tag <= TW_Denormal) && (st1_tag <= TW_Denormal)) {
1295 /* else st(0) is positive and > 1.0 */ 1091 if (st0_tag == TAG_Zero) {
1092 if (st1_tag == TAG_Zero) {
1093 /* Both args zero is invalid */
1094 if (arith_invalid(1) < 0)
1095 return;
1096 } else {
1097 u_char sign;
1098 sign = getsign(st1_ptr) ^ SIGN_NEG;
1099 if (FPU_divide_by_zero(1, sign) < 0)
1100 return;
1101
1102 setsign(st1_ptr, sign);
1103 }
1104 } else if (st1_tag == TAG_Zero) {
1105 /* st(1) contains zero, st(0) valid <> 0 */
1106 /* Zero is the valid answer */
1107 sign = getsign(st1_ptr);
1108
1109 if (signnegative(st0_ptr)) {
1110 /* log(negative) */
1111 if (arith_invalid(1) < 0)
1112 return;
1113 } else if ((st0_tag == TW_Denormal)
1114 && (denormal_operand() < 0))
1115 return;
1116 else {
1117 if (exponent(st0_ptr) < 0)
1118 sign ^= SIGN_NEG;
1119
1120 FPU_copy_to_reg1(&CONST_Z, TAG_Zero);
1121 setsign(st1_ptr, sign);
1122 }
1123 } else {
1124 /* One or both operands are denormals. */
1125 if (denormal_operand() < 0)
1126 return;
1127 goto both_valid;
1128 }
1129 } else if ((st0_tag == TW_NaN) || (st1_tag == TW_NaN)) {
1130 if (real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0)
1131 return;
1132 }
1133 /* One or both arg must be an infinity */
1134 else if (st0_tag == TW_Infinity) {
1135 if ((signnegative(st0_ptr)) || (st1_tag == TAG_Zero)) {
1136 /* log(-infinity) or 0*log(infinity) */
1137 if (arith_invalid(1) < 0)
1138 return;
1139 } else {
1140 u_char sign = getsign(st1_ptr);
1141
1142 if ((st1_tag == TW_Denormal)
1143 && (denormal_operand() < 0))
1144 return;
1145
1146 FPU_copy_to_reg1(&CONST_INF, TAG_Special);
1147 setsign(st1_ptr, sign);
1148 }
1296 } 1149 }
1297 else 1150 /* st(1) must be infinity here */
1298 { 1151 else if (((st0_tag == TAG_Valid) || (st0_tag == TW_Denormal))
1299 /* st(0) is positive and < 1.0 */ 1152 && (signpositive(st0_ptr))) {
1153 if (exponent(st0_ptr) >= 0) {
1154 if ((exponent(st0_ptr) == 0) &&
1155 (st0_ptr->sigh == 0x80000000) &&
1156 (st0_ptr->sigl == 0)) {
1157 /* st(0) holds 1.0 */
1158 /* infinity*log(1) */
1159 if (arith_invalid(1) < 0)
1160 return;
1161 }
1162 /* else st(0) is positive and > 1.0 */
1163 } else {
1164 /* st(0) is positive and < 1.0 */
1300 1165
1301 if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) ) 1166 if ((st0_tag == TW_Denormal)
1302 return; 1167 && (denormal_operand() < 0))
1168 return;
1303 1169
1304 changesign(st1_ptr); 1170 changesign(st1_ptr);
1305 } 1171 }
1306 } 1172 } else {
1307 else 1173 /* st(0) must be zero or negative */
1308 { 1174 if (st0_tag == TAG_Zero) {
1309 /* st(0) must be zero or negative */ 1175 /* This should be invalid, but a real 80486 is happy with it. */
1310 if ( st0_tag == TAG_Zero )
1311 {
1312 /* This should be invalid, but a real 80486 is happy with it. */
1313 1176
1314#ifndef PECULIAR_486 1177#ifndef PECULIAR_486
1315 sign = getsign(st1_ptr); 1178 sign = getsign(st1_ptr);
1316 if ( FPU_divide_by_zero(1, sign) < 0 ) 1179 if (FPU_divide_by_zero(1, sign) < 0)
1317 return; 1180 return;
1318#endif /* PECULIAR_486 */ 1181#endif /* PECULIAR_486 */
1319 1182
1320 changesign(st1_ptr); 1183 changesign(st1_ptr);
1184 } else if (arith_invalid(1) < 0) /* log(negative) */
1185 return;
1321 } 1186 }
1322 else if ( arith_invalid(1) < 0 ) /* log(negative) */
1323 return;
1324 }
1325 1187
1326 FPU_pop(); 1188 FPU_pop();
1327} 1189}
1328 1190
1329 1191static void fpatan(FPU_REG * st0_ptr, u_char st0_tag)
1330static void fpatan(FPU_REG *st0_ptr, u_char st0_tag)
1331{ 1192{
1332 FPU_REG *st1_ptr = &st(1); 1193 FPU_REG *st1_ptr = &st(1);
1333 u_char st1_tag = FPU_gettagi(1); 1194 u_char st1_tag = FPU_gettagi(1);
1334 int tag; 1195 int tag;
1335 1196
1336 clear_C1(); 1197 clear_C1();
1337 if ( !((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid)) ) 1198 if (!((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid))) {
1338 { 1199 valid_atan:
1339 valid_atan:
1340 1200
1341 poly_atan(st0_ptr, st0_tag, st1_ptr, st1_tag); 1201 poly_atan(st0_ptr, st0_tag, st1_ptr, st1_tag);
1342 1202
1343 FPU_pop(); 1203 FPU_pop();
1344 1204
1345 return; 1205 return;
1346 } 1206 }
1347 1207
1348 if ( st0_tag == TAG_Special ) 1208 if (st0_tag == TAG_Special)
1349 st0_tag = FPU_Special(st0_ptr); 1209 st0_tag = FPU_Special(st0_ptr);
1350 if ( st1_tag == TAG_Special ) 1210 if (st1_tag == TAG_Special)
1351 st1_tag = FPU_Special(st1_ptr); 1211 st1_tag = FPU_Special(st1_ptr);
1352 1212
1353 if ( ((st0_tag == TAG_Valid) && (st1_tag == TW_Denormal)) 1213 if (((st0_tag == TAG_Valid) && (st1_tag == TW_Denormal))
1354 || ((st0_tag == TW_Denormal) && (st1_tag == TAG_Valid)) 1214 || ((st0_tag == TW_Denormal) && (st1_tag == TAG_Valid))
1355 || ((st0_tag == TW_Denormal) && (st1_tag == TW_Denormal)) ) 1215 || ((st0_tag == TW_Denormal) && (st1_tag == TW_Denormal))) {
1356 { 1216 if (denormal_operand() < 0)
1357 if ( denormal_operand() < 0 ) 1217 return;
1358 return;
1359 1218
1360 goto valid_atan; 1219 goto valid_atan;
1361 } 1220 } else if ((st0_tag == TAG_Empty) || (st1_tag == TAG_Empty)) {
1362 else if ( (st0_tag == TAG_Empty) || (st1_tag == TAG_Empty) ) 1221 FPU_stack_underflow_pop(1);
1363 { 1222 return;
1364 FPU_stack_underflow_pop(1); 1223 } else if ((st0_tag == TW_NaN) || (st1_tag == TW_NaN)) {
1365 return; 1224 if (real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) >= 0)
1366 } 1225 FPU_pop();
1367 else if ( (st0_tag == TW_NaN) || (st1_tag == TW_NaN) )
1368 {
1369 if ( real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) >= 0 )
1370 FPU_pop();
1371 return;
1372 }
1373 else if ( (st0_tag == TW_Infinity) || (st1_tag == TW_Infinity) )
1374 {
1375 u_char sign = getsign(st1_ptr);
1376 if ( st0_tag == TW_Infinity )
1377 {
1378 if ( st1_tag == TW_Infinity )
1379 {
1380 if ( signpositive(st0_ptr) )
1381 {
1382 FPU_copy_to_reg1(&CONST_PI4, TAG_Valid);
1383 }
1384 else
1385 {
1386 setpositive(st1_ptr);
1387 tag = FPU_u_add(&CONST_PI4, &CONST_PI2, st1_ptr,
1388 FULL_PRECISION, SIGN_POS,
1389 exponent(&CONST_PI4), exponent(&CONST_PI2));
1390 if ( tag >= 0 )
1391 FPU_settagi(1, tag);
1392 }
1393 }
1394 else
1395 {
1396 if ( (st1_tag == TW_Denormal) && (denormal_operand() < 0) )
1397 return; 1226 return;
1227 } else if ((st0_tag == TW_Infinity) || (st1_tag == TW_Infinity)) {
1228 u_char sign = getsign(st1_ptr);
1229 if (st0_tag == TW_Infinity) {
1230 if (st1_tag == TW_Infinity) {
1231 if (signpositive(st0_ptr)) {
1232 FPU_copy_to_reg1(&CONST_PI4, TAG_Valid);
1233 } else {
1234 setpositive(st1_ptr);
1235 tag =
1236 FPU_u_add(&CONST_PI4, &CONST_PI2,
1237 st1_ptr, FULL_PRECISION,
1238 SIGN_POS,
1239 exponent(&CONST_PI4),
1240 exponent(&CONST_PI2));
1241 if (tag >= 0)
1242 FPU_settagi(1, tag);
1243 }
1244 } else {
1245 if ((st1_tag == TW_Denormal)
1246 && (denormal_operand() < 0))
1247 return;
1248
1249 if (signpositive(st0_ptr)) {
1250 FPU_copy_to_reg1(&CONST_Z, TAG_Zero);
1251 setsign(st1_ptr, sign); /* An 80486 preserves the sign */
1252 FPU_pop();
1253 return;
1254 } else {
1255 FPU_copy_to_reg1(&CONST_PI, TAG_Valid);
1256 }
1257 }
1258 } else {
1259 /* st(1) is infinity, st(0) not infinity */
1260 if ((st0_tag == TW_Denormal)
1261 && (denormal_operand() < 0))
1262 return;
1398 1263
1399 if ( signpositive(st0_ptr) ) 1264 FPU_copy_to_reg1(&CONST_PI2, TAG_Valid);
1400 {
1401 FPU_copy_to_reg1(&CONST_Z, TAG_Zero);
1402 setsign(st1_ptr, sign); /* An 80486 preserves the sign */
1403 FPU_pop();
1404 return;
1405 } 1265 }
1406 else 1266 setsign(st1_ptr, sign);
1407 { 1267 } else if (st1_tag == TAG_Zero) {
1408 FPU_copy_to_reg1(&CONST_PI, TAG_Valid); 1268 /* st(0) must be valid or zero */
1269 u_char sign = getsign(st1_ptr);
1270
1271 if ((st0_tag == TW_Denormal) && (denormal_operand() < 0))
1272 return;
1273
1274 if (signpositive(st0_ptr)) {
1275 /* An 80486 preserves the sign */
1276 FPU_pop();
1277 return;
1409 } 1278 }
1410 }
1411 }
1412 else
1413 {
1414 /* st(1) is infinity, st(0) not infinity */
1415 if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) )
1416 return;
1417 1279
1418 FPU_copy_to_reg1(&CONST_PI2, TAG_Valid); 1280 FPU_copy_to_reg1(&CONST_PI, TAG_Valid);
1419 } 1281 setsign(st1_ptr, sign);
1420 setsign(st1_ptr, sign); 1282 } else if (st0_tag == TAG_Zero) {
1421 } 1283 /* st(1) must be TAG_Valid here */
1422 else if ( st1_tag == TAG_Zero ) 1284 u_char sign = getsign(st1_ptr);
1423 {
1424 /* st(0) must be valid or zero */
1425 u_char sign = getsign(st1_ptr);
1426
1427 if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) )
1428 return;
1429 1285
1430 if ( signpositive(st0_ptr) ) 1286 if ((st1_tag == TW_Denormal) && (denormal_operand() < 0))
1431 { 1287 return;
1432 /* An 80486 preserves the sign */
1433 FPU_pop();
1434 return;
1435 }
1436 1288
1437 FPU_copy_to_reg1(&CONST_PI, TAG_Valid); 1289 FPU_copy_to_reg1(&CONST_PI2, TAG_Valid);
1438 setsign(st1_ptr, sign); 1290 setsign(st1_ptr, sign);
1439 } 1291 }
1440 else if ( st0_tag == TAG_Zero )
1441 {
1442 /* st(1) must be TAG_Valid here */
1443 u_char sign = getsign(st1_ptr);
1444
1445 if ( (st1_tag == TW_Denormal) && (denormal_operand() < 0) )
1446 return;
1447
1448 FPU_copy_to_reg1(&CONST_PI2, TAG_Valid);
1449 setsign(st1_ptr, sign);
1450 }
1451#ifdef PARANOID 1292#ifdef PARANOID
1452 else 1293 else
1453 EXCEPTION(EX_INTERNAL | 0x125); 1294 EXCEPTION(EX_INTERNAL | 0x125);
1454#endif /* PARANOID */ 1295#endif /* PARANOID */
1455 1296
1456 FPU_pop(); 1297 FPU_pop();
1457 set_precision_flag_up(); /* We do not really know if up or down */ 1298 set_precision_flag_up(); /* We do not really know if up or down */
1458} 1299}
1459 1300
1460 1301static void fprem(FPU_REG * st0_ptr, u_char st0_tag)
1461static void fprem(FPU_REG *st0_ptr, u_char st0_tag)
1462{ 1302{
1463 do_fprem(st0_ptr, st0_tag, RC_CHOP); 1303 do_fprem(st0_ptr, st0_tag, RC_CHOP);
1464} 1304}
1465 1305
1466 1306static void fprem1(FPU_REG * st0_ptr, u_char st0_tag)
1467static void fprem1(FPU_REG *st0_ptr, u_char st0_tag)
1468{ 1307{
1469 do_fprem(st0_ptr, st0_tag, RC_RND); 1308 do_fprem(st0_ptr, st0_tag, RC_RND);
1470} 1309}
1471 1310
1472 1311static void fyl2xp1(FPU_REG * st0_ptr, u_char st0_tag)
1473static void fyl2xp1(FPU_REG *st0_ptr, u_char st0_tag)
1474{ 1312{
1475 u_char sign, sign1; 1313 u_char sign, sign1;
1476 FPU_REG *st1_ptr = &st(1), a, b; 1314 FPU_REG *st1_ptr = &st(1), a, b;
1477 u_char st1_tag = FPU_gettagi(1); 1315 u_char st1_tag = FPU_gettagi(1);
1478 1316
1479 clear_C1(); 1317 clear_C1();
1480 if ( !((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid)) ) 1318 if (!((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid))) {
1481 { 1319 valid_yl2xp1:
1482 valid_yl2xp1:
1483 1320
1484 sign = getsign(st0_ptr); 1321 sign = getsign(st0_ptr);
1485 sign1 = getsign(st1_ptr); 1322 sign1 = getsign(st1_ptr);
1486 1323
1487 FPU_to_exp16(st0_ptr, &a); 1324 FPU_to_exp16(st0_ptr, &a);
1488 FPU_to_exp16(st1_ptr, &b); 1325 FPU_to_exp16(st1_ptr, &b);
1489 1326
1490 if ( poly_l2p1(sign, sign1, &a, &b, st1_ptr) ) 1327 if (poly_l2p1(sign, sign1, &a, &b, st1_ptr))
1491 return; 1328 return;
1492 1329
1493 FPU_pop(); 1330 FPU_pop();
1494 return; 1331 return;
1495 } 1332 }
1496 1333
1497 if ( st0_tag == TAG_Special ) 1334 if (st0_tag == TAG_Special)
1498 st0_tag = FPU_Special(st0_ptr); 1335 st0_tag = FPU_Special(st0_ptr);
1499 if ( st1_tag == TAG_Special ) 1336 if (st1_tag == TAG_Special)
1500 st1_tag = FPU_Special(st1_ptr); 1337 st1_tag = FPU_Special(st1_ptr);
1501 1338
1502 if ( ((st0_tag == TAG_Valid) && (st1_tag == TW_Denormal)) 1339 if (((st0_tag == TAG_Valid) && (st1_tag == TW_Denormal))
1503 || ((st0_tag == TW_Denormal) && (st1_tag == TAG_Valid)) 1340 || ((st0_tag == TW_Denormal) && (st1_tag == TAG_Valid))
1504 || ((st0_tag == TW_Denormal) && (st1_tag == TW_Denormal)) ) 1341 || ((st0_tag == TW_Denormal) && (st1_tag == TW_Denormal))) {
1505 { 1342 if (denormal_operand() < 0)
1506 if ( denormal_operand() < 0 ) 1343 return;
1507 return;
1508
1509 goto valid_yl2xp1;
1510 }
1511 else if ( (st0_tag == TAG_Empty) | (st1_tag == TAG_Empty) )
1512 {
1513 FPU_stack_underflow_pop(1);
1514 return;
1515 }
1516 else if ( st0_tag == TAG_Zero )
1517 {
1518 switch ( st1_tag )
1519 {
1520 case TW_Denormal:
1521 if ( denormal_operand() < 0 )
1522 return;
1523
1524 case TAG_Zero:
1525 case TAG_Valid:
1526 setsign(st0_ptr, getsign(st0_ptr) ^ getsign(st1_ptr));
1527 FPU_copy_to_reg1(st0_ptr, st0_tag);
1528 break;
1529
1530 case TW_Infinity:
1531 /* Infinity*log(1) */
1532 if ( arith_invalid(1) < 0 )
1533 return;
1534 break;
1535 1344
1536 case TW_NaN: 1345 goto valid_yl2xp1;
1537 if ( real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0 ) 1346 } else if ((st0_tag == TAG_Empty) | (st1_tag == TAG_Empty)) {
1538 return; 1347 FPU_stack_underflow_pop(1);
1539 break; 1348 return;
1540 1349 } else if (st0_tag == TAG_Zero) {
1541 default: 1350 switch (st1_tag) {
1351 case TW_Denormal:
1352 if (denormal_operand() < 0)
1353 return;
1354
1355 case TAG_Zero:
1356 case TAG_Valid:
1357 setsign(st0_ptr, getsign(st0_ptr) ^ getsign(st1_ptr));
1358 FPU_copy_to_reg1(st0_ptr, st0_tag);
1359 break;
1360
1361 case TW_Infinity:
1362 /* Infinity*log(1) */
1363 if (arith_invalid(1) < 0)
1364 return;
1365 break;
1366
1367 case TW_NaN:
1368 if (real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0)
1369 return;
1370 break;
1371
1372 default:
1542#ifdef PARANOID 1373#ifdef PARANOID
1543 EXCEPTION(EX_INTERNAL | 0x116); 1374 EXCEPTION(EX_INTERNAL | 0x116);
1544 return; 1375 return;
1545#endif /* PARANOID */ 1376#endif /* PARANOID */
1546 break; 1377 break;
1547 } 1378 }
1548 } 1379 } else if ((st0_tag == TAG_Valid) || (st0_tag == TW_Denormal)) {
1549 else if ( (st0_tag == TAG_Valid) || (st0_tag == TW_Denormal) ) 1380 switch (st1_tag) {
1550 { 1381 case TAG_Zero:
1551 switch ( st1_tag ) 1382 if (signnegative(st0_ptr)) {
1552 { 1383 if (exponent(st0_ptr) >= 0) {
1553 case TAG_Zero: 1384 /* st(0) holds <= -1.0 */
1554 if ( signnegative(st0_ptr) ) 1385#ifdef PECULIAR_486 /* Stupid 80486 doesn't worry about log(negative). */
1555 { 1386 changesign(st1_ptr);
1556 if ( exponent(st0_ptr) >= 0 )
1557 {
1558 /* st(0) holds <= -1.0 */
1559#ifdef PECULIAR_486 /* Stupid 80486 doesn't worry about log(negative). */
1560 changesign(st1_ptr);
1561#else 1387#else
1562 if ( arith_invalid(1) < 0 ) 1388 if (arith_invalid(1) < 0)
1563 return; 1389 return;
1564#endif /* PECULIAR_486 */ 1390#endif /* PECULIAR_486 */
1565 } 1391 } else if ((st0_tag == TW_Denormal)
1566 else if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) ) 1392 && (denormal_operand() < 0))
1567 return; 1393 return;
1568 else 1394 else
1569 changesign(st1_ptr); 1395 changesign(st1_ptr);
1570 } 1396 } else if ((st0_tag == TW_Denormal)
1571 else if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) ) 1397 && (denormal_operand() < 0))
1572 return; 1398 return;
1573 break; 1399 break;
1574 1400
1575 case TW_Infinity: 1401 case TW_Infinity:
1576 if ( signnegative(st0_ptr) ) 1402 if (signnegative(st0_ptr)) {
1577 { 1403 if ((exponent(st0_ptr) >= 0) &&
1578 if ( (exponent(st0_ptr) >= 0) && 1404 !((st0_ptr->sigh == 0x80000000) &&
1579 !((st0_ptr->sigh == 0x80000000) && 1405 (st0_ptr->sigl == 0))) {
1580 (st0_ptr->sigl == 0)) ) 1406 /* st(0) holds < -1.0 */
1581 { 1407#ifdef PECULIAR_486 /* Stupid 80486 doesn't worry about log(negative). */
1582 /* st(0) holds < -1.0 */ 1408 changesign(st1_ptr);
1583#ifdef PECULIAR_486 /* Stupid 80486 doesn't worry about log(negative). */
1584 changesign(st1_ptr);
1585#else 1409#else
1586 if ( arith_invalid(1) < 0 ) return; 1410 if (arith_invalid(1) < 0)
1411 return;
1587#endif /* PECULIAR_486 */ 1412#endif /* PECULIAR_486 */
1413 } else if ((st0_tag == TW_Denormal)
1414 && (denormal_operand() < 0))
1415 return;
1416 else
1417 changesign(st1_ptr);
1418 } else if ((st0_tag == TW_Denormal)
1419 && (denormal_operand() < 0))
1420 return;
1421 break;
1422
1423 case TW_NaN:
1424 if (real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0)
1425 return;
1588 } 1426 }
1589 else if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) )
1590 return;
1591 else
1592 changesign(st1_ptr);
1593 }
1594 else if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) )
1595 return;
1596 break;
1597
1598 case TW_NaN:
1599 if ( real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0 )
1600 return;
1601 }
1602 1427
1603 } 1428 } else if (st0_tag == TW_NaN) {
1604 else if ( st0_tag == TW_NaN ) 1429 if (real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0)
1605 { 1430 return;
1606 if ( real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0 ) 1431 } else if (st0_tag == TW_Infinity) {
1607 return; 1432 if (st1_tag == TW_NaN) {
1608 } 1433 if (real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0)
1609 else if ( st0_tag == TW_Infinity ) 1434 return;
1610 { 1435 } else if (signnegative(st0_ptr)) {
1611 if ( st1_tag == TW_NaN )
1612 {
1613 if ( real_2op_NaN(st0_ptr, st0_tag, 1, st0_ptr) < 0 )
1614 return;
1615 }
1616 else if ( signnegative(st0_ptr) )
1617 {
1618#ifndef PECULIAR_486 1436#ifndef PECULIAR_486
1619 /* This should have higher priority than denormals, but... */ 1437 /* This should have higher priority than denormals, but... */
1620 if ( arith_invalid(1) < 0 ) /* log(-infinity) */ 1438 if (arith_invalid(1) < 0) /* log(-infinity) */
1621 return; 1439 return;
1622#endif /* PECULIAR_486 */ 1440#endif /* PECULIAR_486 */
1623 if ( (st1_tag == TW_Denormal) && (denormal_operand() < 0) ) 1441 if ((st1_tag == TW_Denormal)
1624 return; 1442 && (denormal_operand() < 0))
1443 return;
1625#ifdef PECULIAR_486 1444#ifdef PECULIAR_486
1626 /* Denormal operands actually get higher priority */ 1445 /* Denormal operands actually get higher priority */
1627 if ( arith_invalid(1) < 0 ) /* log(-infinity) */ 1446 if (arith_invalid(1) < 0) /* log(-infinity) */
1628 return; 1447 return;
1629#endif /* PECULIAR_486 */ 1448#endif /* PECULIAR_486 */
1630 } 1449 } else if (st1_tag == TAG_Zero) {
1631 else if ( st1_tag == TAG_Zero ) 1450 /* log(infinity) */
1632 { 1451 if (arith_invalid(1) < 0)
1633 /* log(infinity) */ 1452 return;
1634 if ( arith_invalid(1) < 0 ) 1453 }
1635 return;
1636 }
1637
1638 /* st(1) must be valid here. */
1639 1454
1640 else if ( (st1_tag == TW_Denormal) && (denormal_operand() < 0) ) 1455 /* st(1) must be valid here. */
1641 return; 1456
1457 else if ((st1_tag == TW_Denormal) && (denormal_operand() < 0))
1458 return;
1642 1459
1643 /* The Manual says that log(Infinity) is invalid, but a real 1460 /* The Manual says that log(Infinity) is invalid, but a real
1644 80486 sensibly says that it is o.k. */ 1461 80486 sensibly says that it is o.k. */
1645 else 1462 else {
1646 { 1463 u_char sign = getsign(st1_ptr);
1647 u_char sign = getsign(st1_ptr); 1464 FPU_copy_to_reg1(&CONST_INF, TAG_Special);
1648 FPU_copy_to_reg1(&CONST_INF, TAG_Special); 1465 setsign(st1_ptr, sign);
1649 setsign(st1_ptr, sign); 1466 }
1650 } 1467 }
1651 }
1652#ifdef PARANOID 1468#ifdef PARANOID
1653 else 1469 else {
1654 { 1470 EXCEPTION(EX_INTERNAL | 0x117);
1655 EXCEPTION(EX_INTERNAL | 0x117); 1471 return;
1656 return; 1472 }
1657 }
1658#endif /* PARANOID */ 1473#endif /* PARANOID */
1659 1474
1660 FPU_pop(); 1475 FPU_pop();
1661 return; 1476 return;
1662 1477
1663} 1478}
1664 1479
1665 1480static void fscale(FPU_REG * st0_ptr, u_char st0_tag)
1666static void fscale(FPU_REG *st0_ptr, u_char st0_tag)
1667{ 1481{
1668 FPU_REG *st1_ptr = &st(1); 1482 FPU_REG *st1_ptr = &st(1);
1669 u_char st1_tag = FPU_gettagi(1); 1483 u_char st1_tag = FPU_gettagi(1);
1670 int old_cw = control_word; 1484 int old_cw = control_word;
1671 u_char sign = getsign(st0_ptr); 1485 u_char sign = getsign(st0_ptr);
1672 1486
1673 clear_C1(); 1487 clear_C1();
1674 if ( !((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid)) ) 1488 if (!((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid))) {
1675 { 1489 long scale;
1676 long scale; 1490 FPU_REG tmp;
1677 FPU_REG tmp; 1491
1678 1492 /* Convert register for internal use. */
1679 /* Convert register for internal use. */ 1493 setexponent16(st0_ptr, exponent(st0_ptr));
1680 setexponent16(st0_ptr, exponent(st0_ptr)); 1494
1681 1495 valid_scale:
1682 valid_scale: 1496
1683 1497 if (exponent(st1_ptr) > 30) {
1684 if ( exponent(st1_ptr) > 30 ) 1498 /* 2^31 is far too large, would require 2^(2^30) or 2^(-2^30) */
1685 { 1499
1686 /* 2^31 is far too large, would require 2^(2^30) or 2^(-2^30) */ 1500 if (signpositive(st1_ptr)) {
1687 1501 EXCEPTION(EX_Overflow);
1688 if ( signpositive(st1_ptr) ) 1502 FPU_copy_to_reg0(&CONST_INF, TAG_Special);
1689 { 1503 } else {
1690 EXCEPTION(EX_Overflow); 1504 EXCEPTION(EX_Underflow);
1691 FPU_copy_to_reg0(&CONST_INF, TAG_Special); 1505 FPU_copy_to_reg0(&CONST_Z, TAG_Zero);
1692 } 1506 }
1693 else 1507 setsign(st0_ptr, sign);
1694 { 1508 return;
1695 EXCEPTION(EX_Underflow); 1509 }
1696 FPU_copy_to_reg0(&CONST_Z, TAG_Zero);
1697 }
1698 setsign(st0_ptr, sign);
1699 return;
1700 }
1701
1702 control_word &= ~CW_RC;
1703 control_word |= RC_CHOP;
1704 reg_copy(st1_ptr, &tmp);
1705 FPU_round_to_int(&tmp, st1_tag); /* This can never overflow here */
1706 control_word = old_cw;
1707 scale = signnegative(st1_ptr) ? -tmp.sigl : tmp.sigl;
1708 scale += exponent16(st0_ptr);
1709
1710 setexponent16(st0_ptr, scale);
1711
1712 /* Use FPU_round() to properly detect under/overflow etc */
1713 FPU_round(st0_ptr, 0, 0, control_word, sign);
1714
1715 return;
1716 }
1717
1718 if ( st0_tag == TAG_Special )
1719 st0_tag = FPU_Special(st0_ptr);
1720 if ( st1_tag == TAG_Special )
1721 st1_tag = FPU_Special(st1_ptr);
1722
1723 if ( (st0_tag == TAG_Valid) || (st0_tag == TW_Denormal) )
1724 {
1725 switch ( st1_tag )
1726 {
1727 case TAG_Valid:
1728 /* st(0) must be a denormal */
1729 if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) )
1730 return;
1731
1732 FPU_to_exp16(st0_ptr, st0_ptr); /* Will not be left on stack */
1733 goto valid_scale;
1734
1735 case TAG_Zero:
1736 if ( st0_tag == TW_Denormal )
1737 denormal_operand();
1738 return;
1739
1740 case TW_Denormal:
1741 denormal_operand();
1742 return;
1743
1744 case TW_Infinity:
1745 if ( (st0_tag == TW_Denormal) && (denormal_operand() < 0) )
1746 return;
1747
1748 if ( signpositive(st1_ptr) )
1749 FPU_copy_to_reg0(&CONST_INF, TAG_Special);
1750 else
1751 FPU_copy_to_reg0(&CONST_Z, TAG_Zero);
1752 setsign(st0_ptr, sign);
1753 return;
1754 1510
1755 case TW_NaN: 1511 control_word &= ~CW_RC;
1756 real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr); 1512 control_word |= RC_CHOP;
1757 return; 1513 reg_copy(st1_ptr, &tmp);
1758 } 1514 FPU_round_to_int(&tmp, st1_tag); /* This can never overflow here */
1759 } 1515 control_word = old_cw;
1760 else if ( st0_tag == TAG_Zero ) 1516 scale = signnegative(st1_ptr) ? -tmp.sigl : tmp.sigl;
1761 { 1517 scale += exponent16(st0_ptr);
1762 switch ( st1_tag )
1763 {
1764 case TAG_Valid:
1765 case TAG_Zero:
1766 return;
1767 1518
1768 case TW_Denormal: 1519 setexponent16(st0_ptr, scale);
1769 denormal_operand();
1770 return;
1771 1520
1772 case TW_Infinity: 1521 /* Use FPU_round() to properly detect under/overflow etc */
1773 if ( signpositive(st1_ptr) ) 1522 FPU_round(st0_ptr, 0, 0, control_word, sign);
1774 arith_invalid(0); /* Zero scaled by +Infinity */
1775 return;
1776 1523
1777 case TW_NaN: 1524 return;
1778 real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr);
1779 return;
1780 } 1525 }
1781 }
1782 else if ( st0_tag == TW_Infinity )
1783 {
1784 switch ( st1_tag )
1785 {
1786 case TAG_Valid:
1787 case TAG_Zero:
1788 return;
1789
1790 case TW_Denormal:
1791 denormal_operand();
1792 return;
1793 1526
1794 case TW_Infinity: 1527 if (st0_tag == TAG_Special)
1795 if ( signnegative(st1_ptr) ) 1528 st0_tag = FPU_Special(st0_ptr);
1796 arith_invalid(0); /* Infinity scaled by -Infinity */ 1529 if (st1_tag == TAG_Special)
1797 return; 1530 st1_tag = FPU_Special(st1_ptr);
1798 1531
1799 case TW_NaN: 1532 if ((st0_tag == TAG_Valid) || (st0_tag == TW_Denormal)) {
1800 real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr); 1533 switch (st1_tag) {
1801 return; 1534 case TAG_Valid:
1535 /* st(0) must be a denormal */
1536 if ((st0_tag == TW_Denormal)
1537 && (denormal_operand() < 0))
1538 return;
1539
1540 FPU_to_exp16(st0_ptr, st0_ptr); /* Will not be left on stack */
1541 goto valid_scale;
1542
1543 case TAG_Zero:
1544 if (st0_tag == TW_Denormal)
1545 denormal_operand();
1546 return;
1547
1548 case TW_Denormal:
1549 denormal_operand();
1550 return;
1551
1552 case TW_Infinity:
1553 if ((st0_tag == TW_Denormal)
1554 && (denormal_operand() < 0))
1555 return;
1556
1557 if (signpositive(st1_ptr))
1558 FPU_copy_to_reg0(&CONST_INF, TAG_Special);
1559 else
1560 FPU_copy_to_reg0(&CONST_Z, TAG_Zero);
1561 setsign(st0_ptr, sign);
1562 return;
1563
1564 case TW_NaN:
1565 real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr);
1566 return;
1567 }
1568 } else if (st0_tag == TAG_Zero) {
1569 switch (st1_tag) {
1570 case TAG_Valid:
1571 case TAG_Zero:
1572 return;
1573
1574 case TW_Denormal:
1575 denormal_operand();
1576 return;
1577
1578 case TW_Infinity:
1579 if (signpositive(st1_ptr))
1580 arith_invalid(0); /* Zero scaled by +Infinity */
1581 return;
1582
1583 case TW_NaN:
1584 real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr);
1585 return;
1586 }
1587 } else if (st0_tag == TW_Infinity) {
1588 switch (st1_tag) {
1589 case TAG_Valid:
1590 case TAG_Zero:
1591 return;
1592
1593 case TW_Denormal:
1594 denormal_operand();
1595 return;
1596
1597 case TW_Infinity:
1598 if (signnegative(st1_ptr))
1599 arith_invalid(0); /* Infinity scaled by -Infinity */
1600 return;
1601
1602 case TW_NaN:
1603 real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr);
1604 return;
1605 }
1606 } else if (st0_tag == TW_NaN) {
1607 if (st1_tag != TAG_Empty) {
1608 real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr);
1609 return;
1610 }
1802 } 1611 }
1803 }
1804 else if ( st0_tag == TW_NaN )
1805 {
1806 if ( st1_tag != TAG_Empty )
1807 { real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr); return; }
1808 }
1809
1810#ifdef PARANOID 1612#ifdef PARANOID
1811 if ( !((st0_tag == TAG_Empty) || (st1_tag == TAG_Empty)) ) 1613 if (!((st0_tag == TAG_Empty) || (st1_tag == TAG_Empty))) {
1812 { 1614 EXCEPTION(EX_INTERNAL | 0x115);
1813 EXCEPTION(EX_INTERNAL | 0x115); 1615 return;
1814 return; 1616 }
1815 }
1816#endif 1617#endif
1817 1618
1818 /* At least one of st(0), st(1) must be empty */ 1619 /* At least one of st(0), st(1) must be empty */
1819 FPU_stack_underflow(); 1620 FPU_stack_underflow();
1820 1621
1821} 1622}
1822 1623
1823
1824/*---------------------------------------------------------------------------*/ 1624/*---------------------------------------------------------------------------*/
1825 1625
1826static FUNC_ST0 const trig_table_a[] = { 1626static FUNC_ST0 const trig_table_a[] = {
1827 f2xm1, fyl2x, fptan, fpatan, 1627 f2xm1, fyl2x, fptan, fpatan,
1828 fxtract, fprem1, (FUNC_ST0)fdecstp, (FUNC_ST0)fincstp 1628 fxtract, fprem1, (FUNC_ST0) fdecstp, (FUNC_ST0) fincstp
1829}; 1629};
1830 1630
1831void FPU_triga(void) 1631void FPU_triga(void)
1832{ 1632{
1833 (trig_table_a[FPU_rm])(&st(0), FPU_gettag0()); 1633 (trig_table_a[FPU_rm]) (&st(0), FPU_gettag0());
1834} 1634}
1835 1635
1836 1636static FUNC_ST0 const trig_table_b[] = {
1837static FUNC_ST0 const trig_table_b[] = 1637 fprem, fyl2xp1, fsqrt_, fsincos, frndint_, fscale, (FUNC_ST0) fsin, fcos
1838 { 1638};
1839 fprem, fyl2xp1, fsqrt_, fsincos, frndint_, fscale, (FUNC_ST0)fsin, fcos
1840 };
1841 1639
1842void FPU_trigb(void) 1640void FPU_trigb(void)
1843{ 1641{
1844 (trig_table_b[FPU_rm])(&st(0), FPU_gettag0()); 1642 (trig_table_b[FPU_rm]) (&st(0), FPU_gettag0());
1845} 1643}
diff --git a/arch/x86/math-emu/get_address.c b/arch/x86/math-emu/get_address.c
index 2e2c51a8bd3a..d701e2b39e44 100644
--- a/arch/x86/math-emu/get_address.c
+++ b/arch/x86/math-emu/get_address.c
@@ -17,7 +17,6 @@
17 | other processes using the emulator while swapping is in progress. | 17 | other processes using the emulator while swapping is in progress. |
18 +---------------------------------------------------------------------------*/ 18 +---------------------------------------------------------------------------*/
19 19
20
21#include <linux/stddef.h> 20#include <linux/stddef.h>
22 21
23#include <asm/uaccess.h> 22#include <asm/uaccess.h>
@@ -27,31 +26,30 @@
27#include "exception.h" 26#include "exception.h"
28#include "fpu_emu.h" 27#include "fpu_emu.h"
29 28
30
31#define FPU_WRITE_BIT 0x10 29#define FPU_WRITE_BIT 0x10
32 30
33static int reg_offset[] = { 31static int reg_offset[] = {
34 offsetof(struct info,___eax), 32 offsetof(struct info, ___eax),
35 offsetof(struct info,___ecx), 33 offsetof(struct info, ___ecx),
36 offsetof(struct info,___edx), 34 offsetof(struct info, ___edx),
37 offsetof(struct info,___ebx), 35 offsetof(struct info, ___ebx),
38 offsetof(struct info,___esp), 36 offsetof(struct info, ___esp),
39 offsetof(struct info,___ebp), 37 offsetof(struct info, ___ebp),
40 offsetof(struct info,___esi), 38 offsetof(struct info, ___esi),
41 offsetof(struct info,___edi) 39 offsetof(struct info, ___edi)
42}; 40};
43 41
44#define REG_(x) (*(long *)(reg_offset[(x)]+(u_char *) FPU_info)) 42#define REG_(x) (*(long *)(reg_offset[(x)]+(u_char *) FPU_info))
45 43
46static int reg_offset_vm86[] = { 44static int reg_offset_vm86[] = {
47 offsetof(struct info,___cs), 45 offsetof(struct info, ___cs),
48 offsetof(struct info,___vm86_ds), 46 offsetof(struct info, ___vm86_ds),
49 offsetof(struct info,___vm86_es), 47 offsetof(struct info, ___vm86_es),
50 offsetof(struct info,___vm86_fs), 48 offsetof(struct info, ___vm86_fs),
51 offsetof(struct info,___vm86_gs), 49 offsetof(struct info, ___vm86_gs),
52 offsetof(struct info,___ss), 50 offsetof(struct info, ___ss),
53 offsetof(struct info,___vm86_ds) 51 offsetof(struct info, ___vm86_ds)
54 }; 52};
55 53
56#define VM86_REG_(x) (*(unsigned short *) \ 54#define VM86_REG_(x) (*(unsigned short *) \
57 (reg_offset_vm86[((unsigned)x)]+(u_char *) FPU_info)) 55 (reg_offset_vm86[((unsigned)x)]+(u_char *) FPU_info))
@@ -60,158 +58,141 @@ static int reg_offset_vm86[] = {
60#define ___GS ___ds 58#define ___GS ___ds
61 59
62static int reg_offset_pm[] = { 60static int reg_offset_pm[] = {
63 offsetof(struct info,___cs), 61 offsetof(struct info, ___cs),
64 offsetof(struct info,___ds), 62 offsetof(struct info, ___ds),
65 offsetof(struct info,___es), 63 offsetof(struct info, ___es),
66 offsetof(struct info,___fs), 64 offsetof(struct info, ___fs),
67 offsetof(struct info,___GS), 65 offsetof(struct info, ___GS),
68 offsetof(struct info,___ss), 66 offsetof(struct info, ___ss),
69 offsetof(struct info,___ds) 67 offsetof(struct info, ___ds)
70 }; 68};
71 69
72#define PM_REG_(x) (*(unsigned short *) \ 70#define PM_REG_(x) (*(unsigned short *) \
73 (reg_offset_pm[((unsigned)x)]+(u_char *) FPU_info)) 71 (reg_offset_pm[((unsigned)x)]+(u_char *) FPU_info))
74 72
75
76/* Decode the SIB byte. This function assumes mod != 0 */ 73/* Decode the SIB byte. This function assumes mod != 0 */
77static int sib(int mod, unsigned long *fpu_eip) 74static int sib(int mod, unsigned long *fpu_eip)
78{ 75{
79 u_char ss,index,base; 76 u_char ss, index, base;
80 long offset; 77 long offset;
81 78
82 RE_ENTRANT_CHECK_OFF; 79 RE_ENTRANT_CHECK_OFF;
83 FPU_code_access_ok(1); 80 FPU_code_access_ok(1);
84 FPU_get_user(base, (u_char __user *) (*fpu_eip)); /* The SIB byte */ 81 FPU_get_user(base, (u_char __user *) (*fpu_eip)); /* The SIB byte */
85 RE_ENTRANT_CHECK_ON; 82 RE_ENTRANT_CHECK_ON;
86 (*fpu_eip)++; 83 (*fpu_eip)++;
87 ss = base >> 6; 84 ss = base >> 6;
88 index = (base >> 3) & 7; 85 index = (base >> 3) & 7;
89 base &= 7; 86 base &= 7;
90 87
91 if ((mod == 0) && (base == 5)) 88 if ((mod == 0) && (base == 5))
92 offset = 0; /* No base register */ 89 offset = 0; /* No base register */
93 else 90 else
94 offset = REG_(base); 91 offset = REG_(base);
95 92
96 if (index == 4) 93 if (index == 4) {
97 { 94 /* No index register */
98 /* No index register */ 95 /* A non-zero ss is illegal */
99 /* A non-zero ss is illegal */ 96 if (ss)
100 if ( ss ) 97 EXCEPTION(EX_Invalid);
101 EXCEPTION(EX_Invalid); 98 } else {
102 } 99 offset += (REG_(index)) << ss;
103 else 100 }
104 { 101
105 offset += (REG_(index)) << ss; 102 if (mod == 1) {
106 } 103 /* 8 bit signed displacement */
107 104 long displacement;
108 if (mod == 1) 105 RE_ENTRANT_CHECK_OFF;
109 { 106 FPU_code_access_ok(1);
110 /* 8 bit signed displacement */ 107 FPU_get_user(displacement, (signed char __user *)(*fpu_eip));
111 long displacement; 108 offset += displacement;
112 RE_ENTRANT_CHECK_OFF; 109 RE_ENTRANT_CHECK_ON;
113 FPU_code_access_ok(1); 110 (*fpu_eip)++;
114 FPU_get_user(displacement, (signed char __user *) (*fpu_eip)); 111 } else if (mod == 2 || base == 5) { /* The second condition also has mod==0 */
115 offset += displacement; 112 /* 32 bit displacement */
116 RE_ENTRANT_CHECK_ON; 113 long displacement;
117 (*fpu_eip)++; 114 RE_ENTRANT_CHECK_OFF;
118 } 115 FPU_code_access_ok(4);
119 else if (mod == 2 || base == 5) /* The second condition also has mod==0 */ 116 FPU_get_user(displacement, (long __user *)(*fpu_eip));
120 { 117 offset += displacement;
121 /* 32 bit displacement */ 118 RE_ENTRANT_CHECK_ON;
122 long displacement; 119 (*fpu_eip) += 4;
123 RE_ENTRANT_CHECK_OFF; 120 }
124 FPU_code_access_ok(4);
125 FPU_get_user(displacement, (long __user *) (*fpu_eip));
126 offset += displacement;
127 RE_ENTRANT_CHECK_ON;
128 (*fpu_eip) += 4;
129 }
130
131 return offset;
132}
133 121
122 return offset;
123}
134 124
135static unsigned long vm86_segment(u_char segment, 125static unsigned long vm86_segment(u_char segment, struct address *addr)
136 struct address *addr)
137{ 126{
138 segment--; 127 segment--;
139#ifdef PARANOID 128#ifdef PARANOID
140 if ( segment > PREFIX_SS_ ) 129 if (segment > PREFIX_SS_) {
141 { 130 EXCEPTION(EX_INTERNAL | 0x130);
142 EXCEPTION(EX_INTERNAL|0x130); 131 math_abort(FPU_info, SIGSEGV);
143 math_abort(FPU_info,SIGSEGV); 132 }
144 }
145#endif /* PARANOID */ 133#endif /* PARANOID */
146 addr->selector = VM86_REG_(segment); 134 addr->selector = VM86_REG_(segment);
147 return (unsigned long)VM86_REG_(segment) << 4; 135 return (unsigned long)VM86_REG_(segment) << 4;
148} 136}
149 137
150
151/* This should work for 16 and 32 bit protected mode. */ 138/* This should work for 16 and 32 bit protected mode. */
152static long pm_address(u_char FPU_modrm, u_char segment, 139static long pm_address(u_char FPU_modrm, u_char segment,
153 struct address *addr, long offset) 140 struct address *addr, long offset)
154{ 141{
155 struct desc_struct descriptor; 142 struct desc_struct descriptor;
156 unsigned long base_address, limit, address, seg_top; 143 unsigned long base_address, limit, address, seg_top;
157 144
158 segment--; 145 segment--;
159 146
160#ifdef PARANOID 147#ifdef PARANOID
161 /* segment is unsigned, so this also detects if segment was 0: */ 148 /* segment is unsigned, so this also detects if segment was 0: */
162 if ( segment > PREFIX_SS_ ) 149 if (segment > PREFIX_SS_) {
163 { 150 EXCEPTION(EX_INTERNAL | 0x132);
164 EXCEPTION(EX_INTERNAL|0x132); 151 math_abort(FPU_info, SIGSEGV);
165 math_abort(FPU_info,SIGSEGV); 152 }
166 }
167#endif /* PARANOID */ 153#endif /* PARANOID */
168 154
169 switch ( segment ) 155 switch (segment) {
170 { 156 /* gs isn't used by the kernel, so it still has its
171 /* gs isn't used by the kernel, so it still has its 157 user-space value. */
172 user-space value. */ 158 case PREFIX_GS_ - 1:
173 case PREFIX_GS_-1: 159 /* N.B. - movl %seg, mem is a 2 byte write regardless of prefix */
174 /* N.B. - movl %seg, mem is a 2 byte write regardless of prefix */ 160 savesegment(gs, addr->selector);
175 savesegment(gs, addr->selector); 161 break;
176 break; 162 default:
177 default: 163 addr->selector = PM_REG_(segment);
178 addr->selector = PM_REG_(segment);
179 }
180
181 descriptor = LDT_DESCRIPTOR(PM_REG_(segment));
182 base_address = SEG_BASE_ADDR(descriptor);
183 address = base_address + offset;
184 limit = base_address
185 + (SEG_LIMIT(descriptor)+1) * SEG_GRANULARITY(descriptor) - 1;
186 if ( limit < base_address ) limit = 0xffffffff;
187
188 if ( SEG_EXPAND_DOWN(descriptor) )
189 {
190 if ( SEG_G_BIT(descriptor) )
191 seg_top = 0xffffffff;
192 else
193 {
194 seg_top = base_address + (1 << 20);
195 if ( seg_top < base_address ) seg_top = 0xffffffff;
196 } 164 }
197 access_limit =
198 (address <= limit) || (address >= seg_top) ? 0 :
199 ((seg_top-address) >= 255 ? 255 : seg_top-address);
200 }
201 else
202 {
203 access_limit =
204 (address > limit) || (address < base_address) ? 0 :
205 ((limit-address) >= 254 ? 255 : limit-address+1);
206 }
207 if ( SEG_EXECUTE_ONLY(descriptor) ||
208 (!SEG_WRITE_PERM(descriptor) && (FPU_modrm & FPU_WRITE_BIT)) )
209 {
210 access_limit = 0;
211 }
212 return address;
213}
214 165
166 descriptor = LDT_DESCRIPTOR(PM_REG_(segment));
167 base_address = SEG_BASE_ADDR(descriptor);
168 address = base_address + offset;
169 limit = base_address
170 + (SEG_LIMIT(descriptor) + 1) * SEG_GRANULARITY(descriptor) - 1;
171 if (limit < base_address)
172 limit = 0xffffffff;
173
174 if (SEG_EXPAND_DOWN(descriptor)) {
175 if (SEG_G_BIT(descriptor))
176 seg_top = 0xffffffff;
177 else {
178 seg_top = base_address + (1 << 20);
179 if (seg_top < base_address)
180 seg_top = 0xffffffff;
181 }
182 access_limit =
183 (address <= limit) || (address >= seg_top) ? 0 :
184 ((seg_top - address) >= 255 ? 255 : seg_top - address);
185 } else {
186 access_limit =
187 (address > limit) || (address < base_address) ? 0 :
188 ((limit - address) >= 254 ? 255 : limit - address + 1);
189 }
190 if (SEG_EXECUTE_ONLY(descriptor) ||
191 (!SEG_WRITE_PERM(descriptor) && (FPU_modrm & FPU_WRITE_BIT))) {
192 access_limit = 0;
193 }
194 return address;
195}
215 196
216/* 197/*
217 MOD R/M byte: MOD == 3 has a special use for the FPU 198 MOD R/M byte: MOD == 3 has a special use for the FPU
@@ -221,7 +202,6 @@ static long pm_address(u_char FPU_modrm, u_char segment,
221 ..... ......... ......... 202 ..... ......... .........
222 MOD OPCODE(2) R/M 203 MOD OPCODE(2) R/M
223 204
224
225 SIB byte 205 SIB byte
226 206
227 7 6 5 4 3 2 1 0 207 7 6 5 4 3 2 1 0
@@ -231,208 +211,194 @@ static long pm_address(u_char FPU_modrm, u_char segment,
231*/ 211*/
232 212
233void __user *FPU_get_address(u_char FPU_modrm, unsigned long *fpu_eip, 213void __user *FPU_get_address(u_char FPU_modrm, unsigned long *fpu_eip,
234 struct address *addr, 214 struct address *addr, fpu_addr_modes addr_modes)
235 fpu_addr_modes addr_modes) 215{
216 u_char mod;
217 unsigned rm = FPU_modrm & 7;
218 long *cpu_reg_ptr;
219 int address = 0; /* Initialized just to stop compiler warnings. */
220
221 /* Memory accessed via the cs selector is write protected
222 in `non-segmented' 32 bit protected mode. */
223 if (!addr_modes.default_mode && (FPU_modrm & FPU_WRITE_BIT)
224 && (addr_modes.override.segment == PREFIX_CS_)) {
225 math_abort(FPU_info, SIGSEGV);
226 }
227
228 addr->selector = FPU_DS; /* Default, for 32 bit non-segmented mode. */
229
230 mod = (FPU_modrm >> 6) & 3;
231
232 if (rm == 4 && mod != 3) {
233 address = sib(mod, fpu_eip);
234 } else {
235 cpu_reg_ptr = &REG_(rm);
236 switch (mod) {
237 case 0:
238 if (rm == 5) {
239 /* Special case: disp32 */
240 RE_ENTRANT_CHECK_OFF;
241 FPU_code_access_ok(4);
242 FPU_get_user(address,
243 (unsigned long __user
244 *)(*fpu_eip));
245 (*fpu_eip) += 4;
246 RE_ENTRANT_CHECK_ON;
247 addr->offset = address;
248 return (void __user *)address;
249 } else {
250 address = *cpu_reg_ptr; /* Just return the contents
251 of the cpu register */
252 addr->offset = address;
253 return (void __user *)address;
254 }
255 case 1:
256 /* 8 bit signed displacement */
257 RE_ENTRANT_CHECK_OFF;
258 FPU_code_access_ok(1);
259 FPU_get_user(address, (signed char __user *)(*fpu_eip));
260 RE_ENTRANT_CHECK_ON;
261 (*fpu_eip)++;
262 break;
263 case 2:
264 /* 32 bit displacement */
265 RE_ENTRANT_CHECK_OFF;
266 FPU_code_access_ok(4);
267 FPU_get_user(address, (long __user *)(*fpu_eip));
268 (*fpu_eip) += 4;
269 RE_ENTRANT_CHECK_ON;
270 break;
271 case 3:
272 /* Not legal for the FPU */
273 EXCEPTION(EX_Invalid);
274 }
275 address += *cpu_reg_ptr;
276 }
277
278 addr->offset = address;
279
280 switch (addr_modes.default_mode) {
281 case 0:
282 break;
283 case VM86:
284 address += vm86_segment(addr_modes.override.segment, addr);
285 break;
286 case PM16:
287 case SEG32:
288 address = pm_address(FPU_modrm, addr_modes.override.segment,
289 addr, address);
290 break;
291 default:
292 EXCEPTION(EX_INTERNAL | 0x133);
293 }
294
295 return (void __user *)address;
296}
297
298void __user *FPU_get_address_16(u_char FPU_modrm, unsigned long *fpu_eip,
299 struct address *addr, fpu_addr_modes addr_modes)
236{ 300{
237 u_char mod; 301 u_char mod;
238 unsigned rm = FPU_modrm & 7; 302 unsigned rm = FPU_modrm & 7;
239 long *cpu_reg_ptr; 303 int address = 0; /* Default used for mod == 0 */
240 int address = 0; /* Initialized just to stop compiler warnings. */ 304
241 305 /* Memory accessed via the cs selector is write protected
242 /* Memory accessed via the cs selector is write protected 306 in `non-segmented' 32 bit protected mode. */
243 in `non-segmented' 32 bit protected mode. */ 307 if (!addr_modes.default_mode && (FPU_modrm & FPU_WRITE_BIT)
244 if ( !addr_modes.default_mode && (FPU_modrm & FPU_WRITE_BIT) 308 && (addr_modes.override.segment == PREFIX_CS_)) {
245 && (addr_modes.override.segment == PREFIX_CS_) ) 309 math_abort(FPU_info, SIGSEGV);
246 { 310 }
247 math_abort(FPU_info,SIGSEGV); 311
248 } 312 addr->selector = FPU_DS; /* Default, for 32 bit non-segmented mode. */
249 313
250 addr->selector = FPU_DS; /* Default, for 32 bit non-segmented mode. */ 314 mod = (FPU_modrm >> 6) & 3;
251 315
252 mod = (FPU_modrm >> 6) & 3; 316 switch (mod) {
253
254 if (rm == 4 && mod != 3)
255 {
256 address = sib(mod, fpu_eip);
257 }
258 else
259 {
260 cpu_reg_ptr = & REG_(rm);
261 switch (mod)
262 {
263 case 0: 317 case 0:
264 if (rm == 5) 318 if (rm == 6) {
265 { 319 /* Special case: disp16 */
266 /* Special case: disp32 */ 320 RE_ENTRANT_CHECK_OFF;
267 RE_ENTRANT_CHECK_OFF; 321 FPU_code_access_ok(2);
268 FPU_code_access_ok(4); 322 FPU_get_user(address,
269 FPU_get_user(address, (unsigned long __user *) (*fpu_eip)); 323 (unsigned short __user *)(*fpu_eip));
270 (*fpu_eip) += 4; 324 (*fpu_eip) += 2;
271 RE_ENTRANT_CHECK_ON; 325 RE_ENTRANT_CHECK_ON;
272 addr->offset = address; 326 goto add_segment;
273 return (void __user *) address; 327 }
274 } 328 break;
275 else
276 {
277 address = *cpu_reg_ptr; /* Just return the contents
278 of the cpu register */
279 addr->offset = address;
280 return (void __user *) address;
281 }
282 case 1: 329 case 1:
283 /* 8 bit signed displacement */ 330 /* 8 bit signed displacement */
284 RE_ENTRANT_CHECK_OFF; 331 RE_ENTRANT_CHECK_OFF;
285 FPU_code_access_ok(1); 332 FPU_code_access_ok(1);
286 FPU_get_user(address, (signed char __user *) (*fpu_eip)); 333 FPU_get_user(address, (signed char __user *)(*fpu_eip));
287 RE_ENTRANT_CHECK_ON; 334 RE_ENTRANT_CHECK_ON;
288 (*fpu_eip)++; 335 (*fpu_eip)++;
289 break; 336 break;
290 case 2: 337 case 2:
291 /* 32 bit displacement */ 338 /* 16 bit displacement */
292 RE_ENTRANT_CHECK_OFF; 339 RE_ENTRANT_CHECK_OFF;
293 FPU_code_access_ok(4); 340 FPU_code_access_ok(2);
294 FPU_get_user(address, (long __user *) (*fpu_eip)); 341 FPU_get_user(address, (unsigned short __user *)(*fpu_eip));
295 (*fpu_eip) += 4; 342 (*fpu_eip) += 2;
296 RE_ENTRANT_CHECK_ON; 343 RE_ENTRANT_CHECK_ON;
297 break; 344 break;
298 case 3: 345 case 3:
299 /* Not legal for the FPU */ 346 /* Not legal for the FPU */
300 EXCEPTION(EX_Invalid); 347 EXCEPTION(EX_Invalid);
348 break;
349 }
350 switch (rm) {
351 case 0:
352 address += FPU_info->___ebx + FPU_info->___esi;
353 break;
354 case 1:
355 address += FPU_info->___ebx + FPU_info->___edi;
356 break;
357 case 2:
358 address += FPU_info->___ebp + FPU_info->___esi;
359 if (addr_modes.override.segment == PREFIX_DEFAULT)
360 addr_modes.override.segment = PREFIX_SS_;
361 break;
362 case 3:
363 address += FPU_info->___ebp + FPU_info->___edi;
364 if (addr_modes.override.segment == PREFIX_DEFAULT)
365 addr_modes.override.segment = PREFIX_SS_;
366 break;
367 case 4:
368 address += FPU_info->___esi;
369 break;
370 case 5:
371 address += FPU_info->___edi;
372 break;
373 case 6:
374 address += FPU_info->___ebp;
375 if (addr_modes.override.segment == PREFIX_DEFAULT)
376 addr_modes.override.segment = PREFIX_SS_;
377 break;
378 case 7:
379 address += FPU_info->___ebx;
380 break;
301 } 381 }
302 address += *cpu_reg_ptr;
303 }
304
305 addr->offset = address;
306
307 switch ( addr_modes.default_mode )
308 {
309 case 0:
310 break;
311 case VM86:
312 address += vm86_segment(addr_modes.override.segment, addr);
313 break;
314 case PM16:
315 case SEG32:
316 address = pm_address(FPU_modrm, addr_modes.override.segment,
317 addr, address);
318 break;
319 default:
320 EXCEPTION(EX_INTERNAL|0x133);
321 }
322
323 return (void __user *)address;
324}
325 382
383 add_segment:
384 address &= 0xffff;
326 385
327void __user *FPU_get_address_16(u_char FPU_modrm, unsigned long *fpu_eip, 386 addr->offset = address;
328 struct address *addr, 387
329 fpu_addr_modes addr_modes) 388 switch (addr_modes.default_mode) {
330{ 389 case 0:
331 u_char mod; 390 break;
332 unsigned rm = FPU_modrm & 7; 391 case VM86:
333 int address = 0; /* Default used for mod == 0 */ 392 address += vm86_segment(addr_modes.override.segment, addr);
334 393 break;
335 /* Memory accessed via the cs selector is write protected 394 case PM16:
336 in `non-segmented' 32 bit protected mode. */ 395 case SEG32:
337 if ( !addr_modes.default_mode && (FPU_modrm & FPU_WRITE_BIT) 396 address = pm_address(FPU_modrm, addr_modes.override.segment,
338 && (addr_modes.override.segment == PREFIX_CS_) ) 397 addr, address);
339 { 398 break;
340 math_abort(FPU_info,SIGSEGV); 399 default:
341 } 400 EXCEPTION(EX_INTERNAL | 0x131);
342
343 addr->selector = FPU_DS; /* Default, for 32 bit non-segmented mode. */
344
345 mod = (FPU_modrm >> 6) & 3;
346
347 switch (mod)
348 {
349 case 0:
350 if (rm == 6)
351 {
352 /* Special case: disp16 */
353 RE_ENTRANT_CHECK_OFF;
354 FPU_code_access_ok(2);
355 FPU_get_user(address, (unsigned short __user *) (*fpu_eip));
356 (*fpu_eip) += 2;
357 RE_ENTRANT_CHECK_ON;
358 goto add_segment;
359 } 401 }
360 break; 402
361 case 1: 403 return (void __user *)address;
362 /* 8 bit signed displacement */
363 RE_ENTRANT_CHECK_OFF;
364 FPU_code_access_ok(1);
365 FPU_get_user(address, (signed char __user *) (*fpu_eip));
366 RE_ENTRANT_CHECK_ON;
367 (*fpu_eip)++;
368 break;
369 case 2:
370 /* 16 bit displacement */
371 RE_ENTRANT_CHECK_OFF;
372 FPU_code_access_ok(2);
373 FPU_get_user(address, (unsigned short __user *) (*fpu_eip));
374 (*fpu_eip) += 2;
375 RE_ENTRANT_CHECK_ON;
376 break;
377 case 3:
378 /* Not legal for the FPU */
379 EXCEPTION(EX_Invalid);
380 break;
381 }
382 switch ( rm )
383 {
384 case 0:
385 address += FPU_info->___ebx + FPU_info->___esi;
386 break;
387 case 1:
388 address += FPU_info->___ebx + FPU_info->___edi;
389 break;
390 case 2:
391 address += FPU_info->___ebp + FPU_info->___esi;
392 if ( addr_modes.override.segment == PREFIX_DEFAULT )
393 addr_modes.override.segment = PREFIX_SS_;
394 break;
395 case 3:
396 address += FPU_info->___ebp + FPU_info->___edi;
397 if ( addr_modes.override.segment == PREFIX_DEFAULT )
398 addr_modes.override.segment = PREFIX_SS_;
399 break;
400 case 4:
401 address += FPU_info->___esi;
402 break;
403 case 5:
404 address += FPU_info->___edi;
405 break;
406 case 6:
407 address += FPU_info->___ebp;
408 if ( addr_modes.override.segment == PREFIX_DEFAULT )
409 addr_modes.override.segment = PREFIX_SS_;
410 break;
411 case 7:
412 address += FPU_info->___ebx;
413 break;
414 }
415
416 add_segment:
417 address &= 0xffff;
418
419 addr->offset = address;
420
421 switch ( addr_modes.default_mode )
422 {
423 case 0:
424 break;
425 case VM86:
426 address += vm86_segment(addr_modes.override.segment, addr);
427 break;
428 case PM16:
429 case SEG32:
430 address = pm_address(FPU_modrm, addr_modes.override.segment,
431 addr, address);
432 break;
433 default:
434 EXCEPTION(EX_INTERNAL|0x131);
435 }
436
437 return (void __user *)address ;
438} 404}
diff --git a/arch/x86/math-emu/load_store.c b/arch/x86/math-emu/load_store.c
index eebd6fb1c8a8..2931ff355218 100644
--- a/arch/x86/math-emu/load_store.c
+++ b/arch/x86/math-emu/load_store.c
@@ -26,247 +26,257 @@
26#include "status_w.h" 26#include "status_w.h"
27#include "control_w.h" 27#include "control_w.h"
28 28
29 29#define _NONE_ 0 /* st0_ptr etc not needed */
30#define _NONE_ 0 /* st0_ptr etc not needed */ 30#define _REG0_ 1 /* Will be storing st(0) */
31#define _REG0_ 1 /* Will be storing st(0) */ 31#define _PUSH_ 3 /* Need to check for space to push onto stack */
32#define _PUSH_ 3 /* Need to check for space to push onto stack */ 32#define _null_ 4 /* Function illegal or not implemented */
33#define _null_ 4 /* Function illegal or not implemented */
34 33
35#define pop_0() { FPU_settag0(TAG_Empty); top++; } 34#define pop_0() { FPU_settag0(TAG_Empty); top++; }
36 35
37
38static u_char const type_table[32] = { 36static u_char const type_table[32] = {
39 _PUSH_, _PUSH_, _PUSH_, _PUSH_, 37 _PUSH_, _PUSH_, _PUSH_, _PUSH_,
40 _null_, _null_, _null_, _null_, 38 _null_, _null_, _null_, _null_,
41 _REG0_, _REG0_, _REG0_, _REG0_, 39 _REG0_, _REG0_, _REG0_, _REG0_,
42 _REG0_, _REG0_, _REG0_, _REG0_, 40 _REG0_, _REG0_, _REG0_, _REG0_,
43 _NONE_, _null_, _NONE_, _PUSH_, 41 _NONE_, _null_, _NONE_, _PUSH_,
44 _NONE_, _PUSH_, _null_, _PUSH_, 42 _NONE_, _PUSH_, _null_, _PUSH_,
45 _NONE_, _null_, _NONE_, _REG0_, 43 _NONE_, _null_, _NONE_, _REG0_,
46 _NONE_, _REG0_, _NONE_, _REG0_ 44 _NONE_, _REG0_, _NONE_, _REG0_
47 }; 45};
48 46
49u_char const data_sizes_16[32] = { 47u_char const data_sizes_16[32] = {
50 4, 4, 8, 2, 0, 0, 0, 0, 48 4, 4, 8, 2, 0, 0, 0, 0,
51 4, 4, 8, 2, 4, 4, 8, 2, 49 4, 4, 8, 2, 4, 4, 8, 2,
52 14, 0, 94, 10, 2, 10, 0, 8, 50 14, 0, 94, 10, 2, 10, 0, 8,
53 14, 0, 94, 10, 2, 10, 2, 8 51 14, 0, 94, 10, 2, 10, 2, 8
54}; 52};
55 53
56static u_char const data_sizes_32[32] = { 54static u_char const data_sizes_32[32] = {
57 4, 4, 8, 2, 0, 0, 0, 0, 55 4, 4, 8, 2, 0, 0, 0, 0,
58 4, 4, 8, 2, 4, 4, 8, 2, 56 4, 4, 8, 2, 4, 4, 8, 2,
59 28, 0,108, 10, 2, 10, 0, 8, 57 28, 0, 108, 10, 2, 10, 0, 8,
60 28, 0,108, 10, 2, 10, 2, 8 58 28, 0, 108, 10, 2, 10, 2, 8
61}; 59};
62 60
63int FPU_load_store(u_char type, fpu_addr_modes addr_modes, 61int FPU_load_store(u_char type, fpu_addr_modes addr_modes,
64 void __user *data_address) 62 void __user * data_address)
65{ 63{
66 FPU_REG loaded_data; 64 FPU_REG loaded_data;
67 FPU_REG *st0_ptr; 65 FPU_REG *st0_ptr;
68 u_char st0_tag = TAG_Empty; /* This is just to stop a gcc warning. */ 66 u_char st0_tag = TAG_Empty; /* This is just to stop a gcc warning. */
69 u_char loaded_tag; 67 u_char loaded_tag;
70 68
71 st0_ptr = NULL; /* Initialized just to stop compiler warnings. */ 69 st0_ptr = NULL; /* Initialized just to stop compiler warnings. */
72 70
73 if ( addr_modes.default_mode & PROTECTED ) 71 if (addr_modes.default_mode & PROTECTED) {
74 { 72 if (addr_modes.default_mode == SEG32) {
75 if ( addr_modes.default_mode == SEG32 ) 73 if (access_limit < data_sizes_32[type])
76 { 74 math_abort(FPU_info, SIGSEGV);
77 if ( access_limit < data_sizes_32[type] ) 75 } else if (addr_modes.default_mode == PM16) {
78 math_abort(FPU_info,SIGSEGV); 76 if (access_limit < data_sizes_16[type])
79 } 77 math_abort(FPU_info, SIGSEGV);
80 else if ( addr_modes.default_mode == PM16 ) 78 }
81 {
82 if ( access_limit < data_sizes_16[type] )
83 math_abort(FPU_info,SIGSEGV);
84 }
85#ifdef PARANOID 79#ifdef PARANOID
86 else 80 else
87 EXCEPTION(EX_INTERNAL|0x140); 81 EXCEPTION(EX_INTERNAL | 0x140);
88#endif /* PARANOID */ 82#endif /* PARANOID */
89 } 83 }
90 84
91 switch ( type_table[type] ) 85 switch (type_table[type]) {
92 { 86 case _NONE_:
93 case _NONE_: 87 break;
94 break; 88 case _REG0_:
95 case _REG0_: 89 st0_ptr = &st(0); /* Some of these instructions pop after
96 st0_ptr = &st(0); /* Some of these instructions pop after 90 storing */
97 storing */ 91 st0_tag = FPU_gettag0();
98 st0_tag = FPU_gettag0(); 92 break;
99 break; 93 case _PUSH_:
100 case _PUSH_: 94 {
101 { 95 if (FPU_gettagi(-1) != TAG_Empty) {
102 if ( FPU_gettagi(-1) != TAG_Empty ) 96 FPU_stack_overflow();
103 { FPU_stack_overflow(); return 0; } 97 return 0;
104 top--; 98 }
105 st0_ptr = &st(0); 99 top--;
106 } 100 st0_ptr = &st(0);
107 break; 101 }
108 case _null_: 102 break;
109 FPU_illegal(); 103 case _null_:
110 return 0; 104 FPU_illegal();
105 return 0;
111#ifdef PARANOID 106#ifdef PARANOID
112 default: 107 default:
113 EXCEPTION(EX_INTERNAL|0x141); 108 EXCEPTION(EX_INTERNAL | 0x141);
114 return 0; 109 return 0;
115#endif /* PARANOID */ 110#endif /* PARANOID */
116 }
117
118 switch ( type )
119 {
120 case 000: /* fld m32real */
121 clear_C1();
122 loaded_tag = FPU_load_single((float __user *)data_address, &loaded_data);
123 if ( (loaded_tag == TAG_Special)
124 && isNaN(&loaded_data)
125 && (real_1op_NaN(&loaded_data) < 0) )
126 {
127 top++;
128 break;
129 }
130 FPU_copy_to_reg0(&loaded_data, loaded_tag);
131 break;
132 case 001: /* fild m32int */
133 clear_C1();
134 loaded_tag = FPU_load_int32((long __user *)data_address, &loaded_data);
135 FPU_copy_to_reg0(&loaded_data, loaded_tag);
136 break;
137 case 002: /* fld m64real */
138 clear_C1();
139 loaded_tag = FPU_load_double((double __user *)data_address, &loaded_data);
140 if ( (loaded_tag == TAG_Special)
141 && isNaN(&loaded_data)
142 && (real_1op_NaN(&loaded_data) < 0) )
143 {
144 top++;
145 break;
146 } 111 }
147 FPU_copy_to_reg0(&loaded_data, loaded_tag); 112
148 break; 113 switch (type) {
149 case 003: /* fild m16int */ 114 case 000: /* fld m32real */
150 clear_C1(); 115 clear_C1();
151 loaded_tag = FPU_load_int16((short __user *)data_address, &loaded_data); 116 loaded_tag =
152 FPU_copy_to_reg0(&loaded_data, loaded_tag); 117 FPU_load_single((float __user *)data_address, &loaded_data);
153 break; 118 if ((loaded_tag == TAG_Special)
154 case 010: /* fst m32real */ 119 && isNaN(&loaded_data)
155 clear_C1(); 120 && (real_1op_NaN(&loaded_data) < 0)) {
156 FPU_store_single(st0_ptr, st0_tag, (float __user *)data_address); 121 top++;
157 break; 122 break;
158 case 011: /* fist m32int */ 123 }
159 clear_C1(); 124 FPU_copy_to_reg0(&loaded_data, loaded_tag);
160 FPU_store_int32(st0_ptr, st0_tag, (long __user *)data_address); 125 break;
161 break; 126 case 001: /* fild m32int */
162 case 012: /* fst m64real */ 127 clear_C1();
163 clear_C1(); 128 loaded_tag =
164 FPU_store_double(st0_ptr, st0_tag, (double __user *)data_address); 129 FPU_load_int32((long __user *)data_address, &loaded_data);
165 break; 130 FPU_copy_to_reg0(&loaded_data, loaded_tag);
166 case 013: /* fist m16int */ 131 break;
167 clear_C1(); 132 case 002: /* fld m64real */
168 FPU_store_int16(st0_ptr, st0_tag, (short __user *)data_address); 133 clear_C1();
169 break; 134 loaded_tag =
170 case 014: /* fstp m32real */ 135 FPU_load_double((double __user *)data_address,
171 clear_C1(); 136 &loaded_data);
172 if ( FPU_store_single(st0_ptr, st0_tag, (float __user *)data_address) ) 137 if ((loaded_tag == TAG_Special)
173 pop_0(); /* pop only if the number was actually stored 138 && isNaN(&loaded_data)
174 (see the 80486 manual p16-28) */ 139 && (real_1op_NaN(&loaded_data) < 0)) {
175 break; 140 top++;
176 case 015: /* fistp m32int */ 141 break;
177 clear_C1(); 142 }
178 if ( FPU_store_int32(st0_ptr, st0_tag, (long __user *)data_address) ) 143 FPU_copy_to_reg0(&loaded_data, loaded_tag);
179 pop_0(); /* pop only if the number was actually stored 144 break;
180 (see the 80486 manual p16-28) */ 145 case 003: /* fild m16int */
181 break; 146 clear_C1();
182 case 016: /* fstp m64real */ 147 loaded_tag =
183 clear_C1(); 148 FPU_load_int16((short __user *)data_address, &loaded_data);
184 if ( FPU_store_double(st0_ptr, st0_tag, (double __user *)data_address) ) 149 FPU_copy_to_reg0(&loaded_data, loaded_tag);
185 pop_0(); /* pop only if the number was actually stored 150 break;
186 (see the 80486 manual p16-28) */ 151 case 010: /* fst m32real */
187 break; 152 clear_C1();
188 case 017: /* fistp m16int */ 153 FPU_store_single(st0_ptr, st0_tag,
189 clear_C1(); 154 (float __user *)data_address);
190 if ( FPU_store_int16(st0_ptr, st0_tag, (short __user *)data_address) ) 155 break;
191 pop_0(); /* pop only if the number was actually stored 156 case 011: /* fist m32int */
192 (see the 80486 manual p16-28) */ 157 clear_C1();
193 break; 158 FPU_store_int32(st0_ptr, st0_tag, (long __user *)data_address);
194 case 020: /* fldenv m14/28byte */ 159 break;
195 fldenv(addr_modes, (u_char __user *)data_address); 160 case 012: /* fst m64real */
196 /* Ensure that the values just loaded are not changed by 161 clear_C1();
197 fix-up operations. */ 162 FPU_store_double(st0_ptr, st0_tag,
198 return 1; 163 (double __user *)data_address);
199 case 022: /* frstor m94/108byte */ 164 break;
200 frstor(addr_modes, (u_char __user *)data_address); 165 case 013: /* fist m16int */
201 /* Ensure that the values just loaded are not changed by 166 clear_C1();
202 fix-up operations. */ 167 FPU_store_int16(st0_ptr, st0_tag, (short __user *)data_address);
203 return 1; 168 break;
204 case 023: /* fbld m80dec */ 169 case 014: /* fstp m32real */
205 clear_C1(); 170 clear_C1();
206 loaded_tag = FPU_load_bcd((u_char __user *)data_address); 171 if (FPU_store_single
207 FPU_settag0(loaded_tag); 172 (st0_ptr, st0_tag, (float __user *)data_address))
208 break; 173 pop_0(); /* pop only if the number was actually stored
209 case 024: /* fldcw */ 174 (see the 80486 manual p16-28) */
210 RE_ENTRANT_CHECK_OFF; 175 break;
211 FPU_access_ok(VERIFY_READ, data_address, 2); 176 case 015: /* fistp m32int */
212 FPU_get_user(control_word, (unsigned short __user *) data_address); 177 clear_C1();
213 RE_ENTRANT_CHECK_ON; 178 if (FPU_store_int32
214 if ( partial_status & ~control_word & CW_Exceptions ) 179 (st0_ptr, st0_tag, (long __user *)data_address))
215 partial_status |= (SW_Summary | SW_Backward); 180 pop_0(); /* pop only if the number was actually stored
216 else 181 (see the 80486 manual p16-28) */
217 partial_status &= ~(SW_Summary | SW_Backward); 182 break;
183 case 016: /* fstp m64real */
184 clear_C1();
185 if (FPU_store_double
186 (st0_ptr, st0_tag, (double __user *)data_address))
187 pop_0(); /* pop only if the number was actually stored
188 (see the 80486 manual p16-28) */
189 break;
190 case 017: /* fistp m16int */
191 clear_C1();
192 if (FPU_store_int16
193 (st0_ptr, st0_tag, (short __user *)data_address))
194 pop_0(); /* pop only if the number was actually stored
195 (see the 80486 manual p16-28) */
196 break;
197 case 020: /* fldenv m14/28byte */
198 fldenv(addr_modes, (u_char __user *) data_address);
199 /* Ensure that the values just loaded are not changed by
200 fix-up operations. */
201 return 1;
202 case 022: /* frstor m94/108byte */
203 frstor(addr_modes, (u_char __user *) data_address);
204 /* Ensure that the values just loaded are not changed by
205 fix-up operations. */
206 return 1;
207 case 023: /* fbld m80dec */
208 clear_C1();
209 loaded_tag = FPU_load_bcd((u_char __user *) data_address);
210 FPU_settag0(loaded_tag);
211 break;
212 case 024: /* fldcw */
213 RE_ENTRANT_CHECK_OFF;
214 FPU_access_ok(VERIFY_READ, data_address, 2);
215 FPU_get_user(control_word,
216 (unsigned short __user *)data_address);
217 RE_ENTRANT_CHECK_ON;
218 if (partial_status & ~control_word & CW_Exceptions)
219 partial_status |= (SW_Summary | SW_Backward);
220 else
221 partial_status &= ~(SW_Summary | SW_Backward);
218#ifdef PECULIAR_486 222#ifdef PECULIAR_486
219 control_word |= 0x40; /* An 80486 appears to always set this bit */ 223 control_word |= 0x40; /* An 80486 appears to always set this bit */
220#endif /* PECULIAR_486 */ 224#endif /* PECULIAR_486 */
221 return 1; 225 return 1;
222 case 025: /* fld m80real */ 226 case 025: /* fld m80real */
223 clear_C1(); 227 clear_C1();
224 loaded_tag = FPU_load_extended((long double __user *)data_address, 0); 228 loaded_tag =
225 FPU_settag0(loaded_tag); 229 FPU_load_extended((long double __user *)data_address, 0);
226 break; 230 FPU_settag0(loaded_tag);
227 case 027: /* fild m64int */ 231 break;
228 clear_C1(); 232 case 027: /* fild m64int */
229 loaded_tag = FPU_load_int64((long long __user *)data_address); 233 clear_C1();
230 if (loaded_tag == TAG_Error) 234 loaded_tag = FPU_load_int64((long long __user *)data_address);
235 if (loaded_tag == TAG_Error)
236 return 0;
237 FPU_settag0(loaded_tag);
238 break;
239 case 030: /* fstenv m14/28byte */
240 fstenv(addr_modes, (u_char __user *) data_address);
241 return 1;
242 case 032: /* fsave */
243 fsave(addr_modes, (u_char __user *) data_address);
244 return 1;
245 case 033: /* fbstp m80dec */
246 clear_C1();
247 if (FPU_store_bcd
248 (st0_ptr, st0_tag, (u_char __user *) data_address))
249 pop_0(); /* pop only if the number was actually stored
250 (see the 80486 manual p16-28) */
251 break;
252 case 034: /* fstcw m16int */
253 RE_ENTRANT_CHECK_OFF;
254 FPU_access_ok(VERIFY_WRITE, data_address, 2);
255 FPU_put_user(control_word,
256 (unsigned short __user *)data_address);
257 RE_ENTRANT_CHECK_ON;
258 return 1;
259 case 035: /* fstp m80real */
260 clear_C1();
261 if (FPU_store_extended
262 (st0_ptr, st0_tag, (long double __user *)data_address))
263 pop_0(); /* pop only if the number was actually stored
264 (see the 80486 manual p16-28) */
265 break;
266 case 036: /* fstsw m2byte */
267 RE_ENTRANT_CHECK_OFF;
268 FPU_access_ok(VERIFY_WRITE, data_address, 2);
269 FPU_put_user(status_word(),
270 (unsigned short __user *)data_address);
271 RE_ENTRANT_CHECK_ON;
272 return 1;
273 case 037: /* fistp m64int */
274 clear_C1();
275 if (FPU_store_int64
276 (st0_ptr, st0_tag, (long long __user *)data_address))
277 pop_0(); /* pop only if the number was actually stored
278 (see the 80486 manual p16-28) */
279 break;
280 }
231 return 0; 281 return 0;
232 FPU_settag0(loaded_tag);
233 break;
234 case 030: /* fstenv m14/28byte */
235 fstenv(addr_modes, (u_char __user *)data_address);
236 return 1;
237 case 032: /* fsave */
238 fsave(addr_modes, (u_char __user *)data_address);
239 return 1;
240 case 033: /* fbstp m80dec */
241 clear_C1();
242 if ( FPU_store_bcd(st0_ptr, st0_tag, (u_char __user *)data_address) )
243 pop_0(); /* pop only if the number was actually stored
244 (see the 80486 manual p16-28) */
245 break;
246 case 034: /* fstcw m16int */
247 RE_ENTRANT_CHECK_OFF;
248 FPU_access_ok(VERIFY_WRITE,data_address,2);
249 FPU_put_user(control_word, (unsigned short __user *) data_address);
250 RE_ENTRANT_CHECK_ON;
251 return 1;
252 case 035: /* fstp m80real */
253 clear_C1();
254 if ( FPU_store_extended(st0_ptr, st0_tag, (long double __user *)data_address) )
255 pop_0(); /* pop only if the number was actually stored
256 (see the 80486 manual p16-28) */
257 break;
258 case 036: /* fstsw m2byte */
259 RE_ENTRANT_CHECK_OFF;
260 FPU_access_ok(VERIFY_WRITE,data_address,2);
261 FPU_put_user(status_word(),(unsigned short __user *) data_address);
262 RE_ENTRANT_CHECK_ON;
263 return 1;
264 case 037: /* fistp m64int */
265 clear_C1();
266 if ( FPU_store_int64(st0_ptr, st0_tag, (long long __user *)data_address) )
267 pop_0(); /* pop only if the number was actually stored
268 (see the 80486 manual p16-28) */
269 break;
270 }
271 return 0;
272} 282}
diff --git a/arch/x86/math-emu/poly.h b/arch/x86/math-emu/poly.h
index 4db798114923..f317de7d8864 100644
--- a/arch/x86/math-emu/poly.h
+++ b/arch/x86/math-emu/poly.h
@@ -21,9 +21,9 @@
21 allows. 9-byte would probably be sufficient. 21 allows. 9-byte would probably be sufficient.
22 */ 22 */
23typedef struct { 23typedef struct {
24 unsigned long lsw; 24 unsigned long lsw;
25 unsigned long midw; 25 unsigned long midw;
26 unsigned long msw; 26 unsigned long msw;
27} Xsig; 27} Xsig;
28 28
29asmlinkage void mul64(unsigned long long const *a, unsigned long long const *b, 29asmlinkage void mul64(unsigned long long const *a, unsigned long long const *b,
@@ -33,12 +33,12 @@ asmlinkage void polynomial_Xsig(Xsig *, const unsigned long long *x,
33 33
34asmlinkage void mul32_Xsig(Xsig *, const unsigned long mult); 34asmlinkage void mul32_Xsig(Xsig *, const unsigned long mult);
35asmlinkage void mul64_Xsig(Xsig *, const unsigned long long *mult); 35asmlinkage void mul64_Xsig(Xsig *, const unsigned long long *mult);
36asmlinkage void mul_Xsig_Xsig(Xsig *dest, const Xsig *mult); 36asmlinkage void mul_Xsig_Xsig(Xsig * dest, const Xsig * mult);
37 37
38asmlinkage void shr_Xsig(Xsig *, const int n); 38asmlinkage void shr_Xsig(Xsig *, const int n);
39asmlinkage int round_Xsig(Xsig *); 39asmlinkage int round_Xsig(Xsig *);
40asmlinkage int norm_Xsig(Xsig *); 40asmlinkage int norm_Xsig(Xsig *);
41asmlinkage void div_Xsig(Xsig *x1, const Xsig *x2, const Xsig *dest); 41asmlinkage void div_Xsig(Xsig * x1, const Xsig * x2, const Xsig * dest);
42 42
43/* Macro to extract the most significant 32 bits from a long long */ 43/* Macro to extract the most significant 32 bits from a long long */
44#define LL_MSW(x) (((unsigned long *)&x)[1]) 44#define LL_MSW(x) (((unsigned long *)&x)[1])
@@ -49,7 +49,6 @@ asmlinkage void div_Xsig(Xsig *x1, const Xsig *x2, const Xsig *dest);
49/* Macro to access the 8 ms bytes of an Xsig as a long long */ 49/* Macro to access the 8 ms bytes of an Xsig as a long long */
50#define XSIG_LL(x) (*(unsigned long long *)&x.midw) 50#define XSIG_LL(x) (*(unsigned long long *)&x.midw)
51 51
52
53/* 52/*
54 Need to run gcc with optimizations on to get these to 53 Need to run gcc with optimizations on to get these to
55 actually be in-line. 54 actually be in-line.
@@ -63,59 +62,53 @@ asmlinkage void div_Xsig(Xsig *x1, const Xsig *x2, const Xsig *dest);
63static inline unsigned long mul_32_32(const unsigned long arg1, 62static inline unsigned long mul_32_32(const unsigned long arg1,
64 const unsigned long arg2) 63 const unsigned long arg2)
65{ 64{
66 int retval; 65 int retval;
67 asm volatile ("mull %2; movl %%edx,%%eax" \ 66 asm volatile ("mull %2; movl %%edx,%%eax":"=a" (retval)
68 :"=a" (retval) \ 67 :"0"(arg1), "g"(arg2)
69 :"0" (arg1), "g" (arg2) \ 68 :"dx");
70 :"dx"); 69 return retval;
71 return retval;
72} 70}
73 71
74
75/* Add the 12 byte Xsig x2 to Xsig dest, with no checks for overflow. */ 72/* Add the 12 byte Xsig x2 to Xsig dest, with no checks for overflow. */
76static inline void add_Xsig_Xsig(Xsig *dest, const Xsig *x2) 73static inline void add_Xsig_Xsig(Xsig * dest, const Xsig * x2)
77{ 74{
78 asm volatile ("movl %1,%%edi; movl %2,%%esi;\n" 75 asm volatile ("movl %1,%%edi; movl %2,%%esi;\n"
79 "movl (%%esi),%%eax; addl %%eax,(%%edi);\n" 76 "movl (%%esi),%%eax; addl %%eax,(%%edi);\n"
80 "movl 4(%%esi),%%eax; adcl %%eax,4(%%edi);\n" 77 "movl 4(%%esi),%%eax; adcl %%eax,4(%%edi);\n"
81 "movl 8(%%esi),%%eax; adcl %%eax,8(%%edi);\n" 78 "movl 8(%%esi),%%eax; adcl %%eax,8(%%edi);\n":"=g"
82 :"=g" (*dest):"g" (dest), "g" (x2) 79 (*dest):"g"(dest), "g"(x2)
83 :"ax","si","di"); 80 :"ax", "si", "di");
84} 81}
85 82
86
87/* Add the 12 byte Xsig x2 to Xsig dest, adjust exp if overflow occurs. */ 83/* Add the 12 byte Xsig x2 to Xsig dest, adjust exp if overflow occurs. */
88/* Note: the constraints in the asm statement didn't always work properly 84/* Note: the constraints in the asm statement didn't always work properly
89 with gcc 2.5.8. Changing from using edi to using ecx got around the 85 with gcc 2.5.8. Changing from using edi to using ecx got around the
90 problem, but keep fingers crossed! */ 86 problem, but keep fingers crossed! */
91static inline void add_two_Xsig(Xsig *dest, const Xsig *x2, long int *exp) 87static inline void add_two_Xsig(Xsig * dest, const Xsig * x2, long int *exp)
92{ 88{
93 asm volatile ("movl %2,%%ecx; movl %3,%%esi;\n" 89 asm volatile ("movl %2,%%ecx; movl %3,%%esi;\n"
94 "movl (%%esi),%%eax; addl %%eax,(%%ecx);\n" 90 "movl (%%esi),%%eax; addl %%eax,(%%ecx);\n"
95 "movl 4(%%esi),%%eax; adcl %%eax,4(%%ecx);\n" 91 "movl 4(%%esi),%%eax; adcl %%eax,4(%%ecx);\n"
96 "movl 8(%%esi),%%eax; adcl %%eax,8(%%ecx);\n" 92 "movl 8(%%esi),%%eax; adcl %%eax,8(%%ecx);\n"
97 "jnc 0f;\n" 93 "jnc 0f;\n"
98 "rcrl 8(%%ecx); rcrl 4(%%ecx); rcrl (%%ecx)\n" 94 "rcrl 8(%%ecx); rcrl 4(%%ecx); rcrl (%%ecx)\n"
99 "movl %4,%%ecx; incl (%%ecx)\n" 95 "movl %4,%%ecx; incl (%%ecx)\n"
100 "movl $1,%%eax; jmp 1f;\n" 96 "movl $1,%%eax; jmp 1f;\n"
101 "0: xorl %%eax,%%eax;\n" 97 "0: xorl %%eax,%%eax;\n" "1:\n":"=g" (*exp), "=g"(*dest)
102 "1:\n" 98 :"g"(dest), "g"(x2), "g"(exp)
103 :"=g" (*exp), "=g" (*dest) 99 :"cx", "si", "ax");
104 :"g" (dest), "g" (x2), "g" (exp)
105 :"cx","si","ax");
106} 100}
107 101
108
109/* Negate (subtract from 1.0) the 12 byte Xsig */ 102/* Negate (subtract from 1.0) the 12 byte Xsig */
110/* This is faster in a loop on my 386 than using the "neg" instruction. */ 103/* This is faster in a loop on my 386 than using the "neg" instruction. */
111static inline void negate_Xsig(Xsig *x) 104static inline void negate_Xsig(Xsig * x)
112{ 105{
113 asm volatile("movl %1,%%esi;\n" 106 asm volatile ("movl %1,%%esi;\n"
114 "xorl %%ecx,%%ecx;\n" 107 "xorl %%ecx,%%ecx;\n"
115 "movl %%ecx,%%eax; subl (%%esi),%%eax; movl %%eax,(%%esi);\n" 108 "movl %%ecx,%%eax; subl (%%esi),%%eax; movl %%eax,(%%esi);\n"
116 "movl %%ecx,%%eax; sbbl 4(%%esi),%%eax; movl %%eax,4(%%esi);\n" 109 "movl %%ecx,%%eax; sbbl 4(%%esi),%%eax; movl %%eax,4(%%esi);\n"
117 "movl %%ecx,%%eax; sbbl 8(%%esi),%%eax; movl %%eax,8(%%esi);\n" 110 "movl %%ecx,%%eax; sbbl 8(%%esi),%%eax; movl %%eax,8(%%esi);\n":"=g"
118 :"=g" (*x):"g" (x):"si","ax","cx"); 111 (*x):"g"(x):"si", "ax", "cx");
119} 112}
120 113
121#endif /* _POLY_H */ 114#endif /* _POLY_H */
diff --git a/arch/x86/math-emu/poly_2xm1.c b/arch/x86/math-emu/poly_2xm1.c
index 9766ad5e9743..d8f2be3c8383 100644
--- a/arch/x86/math-emu/poly_2xm1.c
+++ b/arch/x86/math-emu/poly_2xm1.c
@@ -17,21 +17,19 @@
17#include "control_w.h" 17#include "control_w.h"
18#include "poly.h" 18#include "poly.h"
19 19
20
21#define HIPOWER 11 20#define HIPOWER 11
22static const unsigned long long lterms[HIPOWER] = 21static const unsigned long long lterms[HIPOWER] = {
23{ 22 0x0000000000000000LL, /* This term done separately as 12 bytes */
24 0x0000000000000000LL, /* This term done separately as 12 bytes */ 23 0xf5fdeffc162c7543LL,
25 0xf5fdeffc162c7543LL, 24 0x1c6b08d704a0bfa6LL,
26 0x1c6b08d704a0bfa6LL, 25 0x0276556df749cc21LL,
27 0x0276556df749cc21LL, 26 0x002bb0ffcf14f6b8LL,
28 0x002bb0ffcf14f6b8LL, 27 0x0002861225ef751cLL,
29 0x0002861225ef751cLL, 28 0x00001ffcbfcd5422LL,
30 0x00001ffcbfcd5422LL, 29 0x00000162c005d5f1LL,
31 0x00000162c005d5f1LL, 30 0x0000000da96ccb1bLL,
32 0x0000000da96ccb1bLL, 31 0x0000000078d1b897LL,
33 0x0000000078d1b897LL, 32 0x000000000422b029LL
34 0x000000000422b029LL
35}; 33};
36 34
37static const Xsig hiterm = MK_XSIG(0xb17217f7, 0xd1cf79ab, 0xc8a39194); 35static const Xsig hiterm = MK_XSIG(0xb17217f7, 0xd1cf79ab, 0xc8a39194);
@@ -45,112 +43,103 @@ static const Xsig shiftterm2 = MK_XSIG(0xb504f333, 0xf9de6484, 0x597d89b3);
45static const Xsig shiftterm3 = MK_XSIG(0xd744fcca, 0xd69d6af4, 0x39a68bb9); 43static const Xsig shiftterm3 = MK_XSIG(0xd744fcca, 0xd69d6af4, 0x39a68bb9);
46 44
47static const Xsig *shiftterm[] = { &shiftterm0, &shiftterm1, 45static const Xsig *shiftterm[] = { &shiftterm0, &shiftterm1,
48 &shiftterm2, &shiftterm3 }; 46 &shiftterm2, &shiftterm3
49 47};
50 48
51/*--- poly_2xm1() -----------------------------------------------------------+ 49/*--- poly_2xm1() -----------------------------------------------------------+
52 | Requires st(0) which is TAG_Valid and < 1. | 50 | Requires st(0) which is TAG_Valid and < 1. |
53 +---------------------------------------------------------------------------*/ 51 +---------------------------------------------------------------------------*/
54int poly_2xm1(u_char sign, FPU_REG *arg, FPU_REG *result) 52int poly_2xm1(u_char sign, FPU_REG * arg, FPU_REG * result)
55{ 53{
56 long int exponent, shift; 54 long int exponent, shift;
57 unsigned long long Xll; 55 unsigned long long Xll;
58 Xsig accumulator, Denom, argSignif; 56 Xsig accumulator, Denom, argSignif;
59 u_char tag; 57 u_char tag;
60 58
61 exponent = exponent16(arg); 59 exponent = exponent16(arg);
62 60
63#ifdef PARANOID 61#ifdef PARANOID
64 if ( exponent >= 0 ) /* Don't want a |number| >= 1.0 */ 62 if (exponent >= 0) { /* Don't want a |number| >= 1.0 */
65 { 63 /* Number negative, too large, or not Valid. */
66 /* Number negative, too large, or not Valid. */ 64 EXCEPTION(EX_INTERNAL | 0x127);
67 EXCEPTION(EX_INTERNAL|0x127); 65 return 1;
68 return 1; 66 }
69 }
70#endif /* PARANOID */ 67#endif /* PARANOID */
71 68
72 argSignif.lsw = 0; 69 argSignif.lsw = 0;
73 XSIG_LL(argSignif) = Xll = significand(arg); 70 XSIG_LL(argSignif) = Xll = significand(arg);
74 71
75 if ( exponent == -1 ) 72 if (exponent == -1) {
76 { 73 shift = (argSignif.msw & 0x40000000) ? 3 : 2;
77 shift = (argSignif.msw & 0x40000000) ? 3 : 2; 74 /* subtract 0.5 or 0.75 */
78 /* subtract 0.5 or 0.75 */ 75 exponent -= 2;
79 exponent -= 2; 76 XSIG_LL(argSignif) <<= 2;
80 XSIG_LL(argSignif) <<= 2; 77 Xll <<= 2;
81 Xll <<= 2; 78 } else if (exponent == -2) {
82 } 79 shift = 1;
83 else if ( exponent == -2 ) 80 /* subtract 0.25 */
84 { 81 exponent--;
85 shift = 1; 82 XSIG_LL(argSignif) <<= 1;
86 /* subtract 0.25 */ 83 Xll <<= 1;
87 exponent--; 84 } else
88 XSIG_LL(argSignif) <<= 1; 85 shift = 0;
89 Xll <<= 1; 86
90 } 87 if (exponent < -2) {
91 else 88 /* Shift the argument right by the required places. */
92 shift = 0; 89 if (FPU_shrx(&Xll, -2 - exponent) >= 0x80000000U)
93 90 Xll++; /* round up */
94 if ( exponent < -2 ) 91 }
95 { 92
96 /* Shift the argument right by the required places. */ 93 accumulator.lsw = accumulator.midw = accumulator.msw = 0;
97 if ( FPU_shrx(&Xll, -2-exponent) >= 0x80000000U ) 94 polynomial_Xsig(&accumulator, &Xll, lterms, HIPOWER - 1);
98 Xll++; /* round up */ 95 mul_Xsig_Xsig(&accumulator, &argSignif);
99 } 96 shr_Xsig(&accumulator, 3);
100 97
101 accumulator.lsw = accumulator.midw = accumulator.msw = 0; 98 mul_Xsig_Xsig(&argSignif, &hiterm); /* The leading term */
102 polynomial_Xsig(&accumulator, &Xll, lterms, HIPOWER-1); 99 add_two_Xsig(&accumulator, &argSignif, &exponent);
103 mul_Xsig_Xsig(&accumulator, &argSignif); 100
104 shr_Xsig(&accumulator, 3); 101 if (shift) {
105 102 /* The argument is large, use the identity:
106 mul_Xsig_Xsig(&argSignif, &hiterm); /* The leading term */ 103 f(x+a) = f(a) * (f(x) + 1) - 1;
107 add_two_Xsig(&accumulator, &argSignif, &exponent); 104 */
108 105 shr_Xsig(&accumulator, -exponent);
109 if ( shift ) 106 accumulator.msw |= 0x80000000; /* add 1.0 */
110 { 107 mul_Xsig_Xsig(&accumulator, shiftterm[shift]);
111 /* The argument is large, use the identity: 108 accumulator.msw &= 0x3fffffff; /* subtract 1.0 */
112 f(x+a) = f(a) * (f(x) + 1) - 1; 109 exponent = 1;
113 */ 110 }
114 shr_Xsig(&accumulator, - exponent); 111
115 accumulator.msw |= 0x80000000; /* add 1.0 */ 112 if (sign != SIGN_POS) {
116 mul_Xsig_Xsig(&accumulator, shiftterm[shift]); 113 /* The argument is negative, use the identity:
117 accumulator.msw &= 0x3fffffff; /* subtract 1.0 */ 114 f(-x) = -f(x) / (1 + f(x))
118 exponent = 1; 115 */
119 } 116 Denom.lsw = accumulator.lsw;
120 117 XSIG_LL(Denom) = XSIG_LL(accumulator);
121 if ( sign != SIGN_POS ) 118 if (exponent < 0)
122 { 119 shr_Xsig(&Denom, -exponent);
123 /* The argument is negative, use the identity: 120 else if (exponent > 0) {
124 f(-x) = -f(x) / (1 + f(x)) 121 /* exponent must be 1 here */
125 */ 122 XSIG_LL(Denom) <<= 1;
126 Denom.lsw = accumulator.lsw; 123 if (Denom.lsw & 0x80000000)
127 XSIG_LL(Denom) = XSIG_LL(accumulator); 124 XSIG_LL(Denom) |= 1;
128 if ( exponent < 0 ) 125 (Denom.lsw) <<= 1;
129 shr_Xsig(&Denom, - exponent); 126 }
130 else if ( exponent > 0 ) 127 Denom.msw |= 0x80000000; /* add 1.0 */
131 { 128 div_Xsig(&accumulator, &Denom, &accumulator);
132 /* exponent must be 1 here */
133 XSIG_LL(Denom) <<= 1;
134 if ( Denom.lsw & 0x80000000 )
135 XSIG_LL(Denom) |= 1;
136 (Denom.lsw) <<= 1;
137 } 129 }
138 Denom.msw |= 0x80000000; /* add 1.0 */
139 div_Xsig(&accumulator, &Denom, &accumulator);
140 }
141 130
142 /* Convert to 64 bit signed-compatible */ 131 /* Convert to 64 bit signed-compatible */
143 exponent += round_Xsig(&accumulator); 132 exponent += round_Xsig(&accumulator);
144 133
145 result = &st(0); 134 result = &st(0);
146 significand(result) = XSIG_LL(accumulator); 135 significand(result) = XSIG_LL(accumulator);
147 setexponent16(result, exponent); 136 setexponent16(result, exponent);
148 137
149 tag = FPU_round(result, 1, 0, FULL_PRECISION, sign); 138 tag = FPU_round(result, 1, 0, FULL_PRECISION, sign);
150 139
151 setsign(result, sign); 140 setsign(result, sign);
152 FPU_settag0(tag); 141 FPU_settag0(tag);
153 142
154 return 0; 143 return 0;
155 144
156} 145}
diff --git a/arch/x86/math-emu/poly_atan.c b/arch/x86/math-emu/poly_atan.c
index 82f702952f69..2f4ac8143fc3 100644
--- a/arch/x86/math-emu/poly_atan.c
+++ b/arch/x86/math-emu/poly_atan.c
@@ -18,28 +18,25 @@
18#include "control_w.h" 18#include "control_w.h"
19#include "poly.h" 19#include "poly.h"
20 20
21
22#define HIPOWERon 6 /* odd poly, negative terms */ 21#define HIPOWERon 6 /* odd poly, negative terms */
23static const unsigned long long oddnegterms[HIPOWERon] = 22static const unsigned long long oddnegterms[HIPOWERon] = {
24{ 23 0x0000000000000000LL, /* Dummy (not for - 1.0) */
25 0x0000000000000000LL, /* Dummy (not for - 1.0) */ 24 0x015328437f756467LL,
26 0x015328437f756467LL, 25 0x0005dda27b73dec6LL,
27 0x0005dda27b73dec6LL, 26 0x0000226bf2bfb91aLL,
28 0x0000226bf2bfb91aLL, 27 0x000000ccc439c5f7LL,
29 0x000000ccc439c5f7LL, 28 0x0000000355438407LL
30 0x0000000355438407LL 29};
31} ;
32 30
33#define HIPOWERop 6 /* odd poly, positive terms */ 31#define HIPOWERop 6 /* odd poly, positive terms */
34static const unsigned long long oddplterms[HIPOWERop] = 32static const unsigned long long oddplterms[HIPOWERop] = {
35{
36/* 0xaaaaaaaaaaaaaaabLL, transferred to fixedpterm[] */ 33/* 0xaaaaaaaaaaaaaaabLL, transferred to fixedpterm[] */
37 0x0db55a71875c9ac2LL, 34 0x0db55a71875c9ac2LL,
38 0x0029fce2d67880b0LL, 35 0x0029fce2d67880b0LL,
39 0x0000dfd3908b4596LL, 36 0x0000dfd3908b4596LL,
40 0x00000550fd61dab4LL, 37 0x00000550fd61dab4LL,
41 0x0000001c9422b3f9LL, 38 0x0000001c9422b3f9LL,
42 0x000000003e3301e1LL 39 0x000000003e3301e1LL
43}; 40};
44 41
45static const unsigned long long denomterm = 0xebd9b842c5c53a0eLL; 42static const unsigned long long denomterm = 0xebd9b842c5c53a0eLL;
@@ -48,182 +45,164 @@ static const Xsig fixedpterm = MK_XSIG(0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa);
48 45
49static const Xsig pi_signif = MK_XSIG(0xc90fdaa2, 0x2168c234, 0xc4c6628b); 46static const Xsig pi_signif = MK_XSIG(0xc90fdaa2, 0x2168c234, 0xc4c6628b);
50 47
51
52/*--- poly_atan() -----------------------------------------------------------+ 48/*--- poly_atan() -----------------------------------------------------------+
53 | | 49 | |
54 +---------------------------------------------------------------------------*/ 50 +---------------------------------------------------------------------------*/
55void poly_atan(FPU_REG *st0_ptr, u_char st0_tag, 51void poly_atan(FPU_REG * st0_ptr, u_char st0_tag,
56 FPU_REG *st1_ptr, u_char st1_tag) 52 FPU_REG * st1_ptr, u_char st1_tag)
57{ 53{
58 u_char transformed, inverted, 54 u_char transformed, inverted, sign1, sign2;
59 sign1, sign2; 55 int exponent;
60 int exponent; 56 long int dummy_exp;
61 long int dummy_exp; 57 Xsig accumulator, Numer, Denom, accumulatore, argSignif, argSq, argSqSq;
62 Xsig accumulator, Numer, Denom, accumulatore, argSignif, 58 u_char tag;
63 argSq, argSqSq; 59
64 u_char tag; 60 sign1 = getsign(st0_ptr);
65 61 sign2 = getsign(st1_ptr);
66 sign1 = getsign(st0_ptr); 62 if (st0_tag == TAG_Valid) {
67 sign2 = getsign(st1_ptr); 63 exponent = exponent(st0_ptr);
68 if ( st0_tag == TAG_Valid ) 64 } else {
69 { 65 /* This gives non-compatible stack contents... */
70 exponent = exponent(st0_ptr); 66 FPU_to_exp16(st0_ptr, st0_ptr);
71 } 67 exponent = exponent16(st0_ptr);
72 else 68 }
73 { 69 if (st1_tag == TAG_Valid) {
74 /* This gives non-compatible stack contents... */ 70 exponent -= exponent(st1_ptr);
75 FPU_to_exp16(st0_ptr, st0_ptr); 71 } else {
76 exponent = exponent16(st0_ptr); 72 /* This gives non-compatible stack contents... */
77 } 73 FPU_to_exp16(st1_ptr, st1_ptr);
78 if ( st1_tag == TAG_Valid ) 74 exponent -= exponent16(st1_ptr);
79 { 75 }
80 exponent -= exponent(st1_ptr); 76
81 } 77 if ((exponent < 0) || ((exponent == 0) &&
82 else 78 ((st0_ptr->sigh < st1_ptr->sigh) ||
83 { 79 ((st0_ptr->sigh == st1_ptr->sigh) &&
84 /* This gives non-compatible stack contents... */ 80 (st0_ptr->sigl < st1_ptr->sigl))))) {
85 FPU_to_exp16(st1_ptr, st1_ptr); 81 inverted = 1;
86 exponent -= exponent16(st1_ptr); 82 Numer.lsw = Denom.lsw = 0;
87 } 83 XSIG_LL(Numer) = significand(st0_ptr);
88 84 XSIG_LL(Denom) = significand(st1_ptr);
89 if ( (exponent < 0) || ((exponent == 0) && 85 } else {
90 ((st0_ptr->sigh < st1_ptr->sigh) || 86 inverted = 0;
91 ((st0_ptr->sigh == st1_ptr->sigh) && 87 exponent = -exponent;
92 (st0_ptr->sigl < st1_ptr->sigl))) ) ) 88 Numer.lsw = Denom.lsw = 0;
93 { 89 XSIG_LL(Numer) = significand(st1_ptr);
94 inverted = 1; 90 XSIG_LL(Denom) = significand(st0_ptr);
95 Numer.lsw = Denom.lsw = 0; 91 }
96 XSIG_LL(Numer) = significand(st0_ptr); 92 div_Xsig(&Numer, &Denom, &argSignif);
97 XSIG_LL(Denom) = significand(st1_ptr); 93 exponent += norm_Xsig(&argSignif);
98 } 94
99 else 95 if ((exponent >= -1)
100 { 96 || ((exponent == -2) && (argSignif.msw > 0xd413ccd0))) {
101 inverted = 0; 97 /* The argument is greater than sqrt(2)-1 (=0.414213562...) */
102 exponent = -exponent; 98 /* Convert the argument by an identity for atan */
103 Numer.lsw = Denom.lsw = 0; 99 transformed = 1;
104 XSIG_LL(Numer) = significand(st1_ptr); 100
105 XSIG_LL(Denom) = significand(st0_ptr); 101 if (exponent >= 0) {
106 }
107 div_Xsig(&Numer, &Denom, &argSignif);
108 exponent += norm_Xsig(&argSignif);
109
110 if ( (exponent >= -1)
111 || ((exponent == -2) && (argSignif.msw > 0xd413ccd0)) )
112 {
113 /* The argument is greater than sqrt(2)-1 (=0.414213562...) */
114 /* Convert the argument by an identity for atan */
115 transformed = 1;
116
117 if ( exponent >= 0 )
118 {
119#ifdef PARANOID 102#ifdef PARANOID
120 if ( !( (exponent == 0) && 103 if (!((exponent == 0) &&
121 (argSignif.lsw == 0) && (argSignif.midw == 0) && 104 (argSignif.lsw == 0) && (argSignif.midw == 0) &&
122 (argSignif.msw == 0x80000000) ) ) 105 (argSignif.msw == 0x80000000))) {
123 { 106 EXCEPTION(EX_INTERNAL | 0x104); /* There must be a logic error */
124 EXCEPTION(EX_INTERNAL|0x104); /* There must be a logic error */ 107 return;
125 return; 108 }
126 }
127#endif /* PARANOID */ 109#endif /* PARANOID */
128 argSignif.msw = 0; /* Make the transformed arg -> 0.0 */ 110 argSignif.msw = 0; /* Make the transformed arg -> 0.0 */
111 } else {
112 Numer.lsw = Denom.lsw = argSignif.lsw;
113 XSIG_LL(Numer) = XSIG_LL(Denom) = XSIG_LL(argSignif);
114
115 if (exponent < -1)
116 shr_Xsig(&Numer, -1 - exponent);
117 negate_Xsig(&Numer);
118
119 shr_Xsig(&Denom, -exponent);
120 Denom.msw |= 0x80000000;
121
122 div_Xsig(&Numer, &Denom, &argSignif);
123
124 exponent = -1 + norm_Xsig(&argSignif);
125 }
126 } else {
127 transformed = 0;
128 }
129
130 argSq.lsw = argSignif.lsw;
131 argSq.midw = argSignif.midw;
132 argSq.msw = argSignif.msw;
133 mul_Xsig_Xsig(&argSq, &argSq);
134
135 argSqSq.lsw = argSq.lsw;
136 argSqSq.midw = argSq.midw;
137 argSqSq.msw = argSq.msw;
138 mul_Xsig_Xsig(&argSqSq, &argSqSq);
139
140 accumulatore.lsw = argSq.lsw;
141 XSIG_LL(accumulatore) = XSIG_LL(argSq);
142
143 shr_Xsig(&argSq, 2 * (-1 - exponent - 1));
144 shr_Xsig(&argSqSq, 4 * (-1 - exponent - 1));
145
146 /* Now have argSq etc with binary point at the left
147 .1xxxxxxxx */
148
149 /* Do the basic fixed point polynomial evaluation */
150 accumulator.msw = accumulator.midw = accumulator.lsw = 0;
151 polynomial_Xsig(&accumulator, &XSIG_LL(argSqSq),
152 oddplterms, HIPOWERop - 1);
153 mul64_Xsig(&accumulator, &XSIG_LL(argSq));
154 negate_Xsig(&accumulator);
155 polynomial_Xsig(&accumulator, &XSIG_LL(argSqSq), oddnegterms,
156 HIPOWERon - 1);
157 negate_Xsig(&accumulator);
158 add_two_Xsig(&accumulator, &fixedpterm, &dummy_exp);
159
160 mul64_Xsig(&accumulatore, &denomterm);
161 shr_Xsig(&accumulatore, 1 + 2 * (-1 - exponent));
162 accumulatore.msw |= 0x80000000;
163
164 div_Xsig(&accumulator, &accumulatore, &accumulator);
165
166 mul_Xsig_Xsig(&accumulator, &argSignif);
167 mul_Xsig_Xsig(&accumulator, &argSq);
168
169 shr_Xsig(&accumulator, 3);
170 negate_Xsig(&accumulator);
171 add_Xsig_Xsig(&accumulator, &argSignif);
172
173 if (transformed) {
174 /* compute pi/4 - accumulator */
175 shr_Xsig(&accumulator, -1 - exponent);
176 negate_Xsig(&accumulator);
177 add_Xsig_Xsig(&accumulator, &pi_signif);
178 exponent = -1;
179 }
180
181 if (inverted) {
182 /* compute pi/2 - accumulator */
183 shr_Xsig(&accumulator, -exponent);
184 negate_Xsig(&accumulator);
185 add_Xsig_Xsig(&accumulator, &pi_signif);
186 exponent = 0;
129 } 187 }
130 else 188
131 { 189 if (sign1) {
132 Numer.lsw = Denom.lsw = argSignif.lsw; 190 /* compute pi - accumulator */
133 XSIG_LL(Numer) = XSIG_LL(Denom) = XSIG_LL(argSignif); 191 shr_Xsig(&accumulator, 1 - exponent);
134 192 negate_Xsig(&accumulator);
135 if ( exponent < -1 ) 193 add_Xsig_Xsig(&accumulator, &pi_signif);
136 shr_Xsig(&Numer, -1-exponent); 194 exponent = 1;
137 negate_Xsig(&Numer);
138
139 shr_Xsig(&Denom, -exponent);
140 Denom.msw |= 0x80000000;
141
142 div_Xsig(&Numer, &Denom, &argSignif);
143
144 exponent = -1 + norm_Xsig(&argSignif);
145 } 195 }
146 } 196
147 else 197 exponent += round_Xsig(&accumulator);
148 { 198
149 transformed = 0; 199 significand(st1_ptr) = XSIG_LL(accumulator);
150 } 200 setexponent16(st1_ptr, exponent);
151 201
152 argSq.lsw = argSignif.lsw; argSq.midw = argSignif.midw; 202 tag = FPU_round(st1_ptr, 1, 0, FULL_PRECISION, sign2);
153 argSq.msw = argSignif.msw; 203 FPU_settagi(1, tag);
154 mul_Xsig_Xsig(&argSq, &argSq); 204
155 205 set_precision_flag_up(); /* We do not really know if up or down,
156 argSqSq.lsw = argSq.lsw; argSqSq.midw = argSq.midw; argSqSq.msw = argSq.msw; 206 use this as the default. */
157 mul_Xsig_Xsig(&argSqSq, &argSqSq);
158
159 accumulatore.lsw = argSq.lsw;
160 XSIG_LL(accumulatore) = XSIG_LL(argSq);
161
162 shr_Xsig(&argSq, 2*(-1-exponent-1));
163 shr_Xsig(&argSqSq, 4*(-1-exponent-1));
164
165 /* Now have argSq etc with binary point at the left
166 .1xxxxxxxx */
167
168 /* Do the basic fixed point polynomial evaluation */
169 accumulator.msw = accumulator.midw = accumulator.lsw = 0;
170 polynomial_Xsig(&accumulator, &XSIG_LL(argSqSq),
171 oddplterms, HIPOWERop-1);
172 mul64_Xsig(&accumulator, &XSIG_LL(argSq));
173 negate_Xsig(&accumulator);
174 polynomial_Xsig(&accumulator, &XSIG_LL(argSqSq), oddnegterms, HIPOWERon-1);
175 negate_Xsig(&accumulator);
176 add_two_Xsig(&accumulator, &fixedpterm, &dummy_exp);
177
178 mul64_Xsig(&accumulatore, &denomterm);
179 shr_Xsig(&accumulatore, 1 + 2*(-1-exponent));
180 accumulatore.msw |= 0x80000000;
181
182 div_Xsig(&accumulator, &accumulatore, &accumulator);
183
184 mul_Xsig_Xsig(&accumulator, &argSignif);
185 mul_Xsig_Xsig(&accumulator, &argSq);
186
187 shr_Xsig(&accumulator, 3);
188 negate_Xsig(&accumulator);
189 add_Xsig_Xsig(&accumulator, &argSignif);
190
191 if ( transformed )
192 {
193 /* compute pi/4 - accumulator */
194 shr_Xsig(&accumulator, -1-exponent);
195 negate_Xsig(&accumulator);
196 add_Xsig_Xsig(&accumulator, &pi_signif);
197 exponent = -1;
198 }
199
200 if ( inverted )
201 {
202 /* compute pi/2 - accumulator */
203 shr_Xsig(&accumulator, -exponent);
204 negate_Xsig(&accumulator);
205 add_Xsig_Xsig(&accumulator, &pi_signif);
206 exponent = 0;
207 }
208
209 if ( sign1 )
210 {
211 /* compute pi - accumulator */
212 shr_Xsig(&accumulator, 1 - exponent);
213 negate_Xsig(&accumulator);
214 add_Xsig_Xsig(&accumulator, &pi_signif);
215 exponent = 1;
216 }
217
218 exponent += round_Xsig(&accumulator);
219
220 significand(st1_ptr) = XSIG_LL(accumulator);
221 setexponent16(st1_ptr, exponent);
222
223 tag = FPU_round(st1_ptr, 1, 0, FULL_PRECISION, sign2);
224 FPU_settagi(1, tag);
225
226 set_precision_flag_up(); /* We do not really know if up or down,
227 use this as the default. */
228 207
229} 208}
diff --git a/arch/x86/math-emu/poly_l2.c b/arch/x86/math-emu/poly_l2.c
index dd00e1d5b074..c0102ae87511 100644
--- a/arch/x86/math-emu/poly_l2.c
+++ b/arch/x86/math-emu/poly_l2.c
@@ -10,7 +10,6 @@
10 | | 10 | |
11 +---------------------------------------------------------------------------*/ 11 +---------------------------------------------------------------------------*/
12 12
13
14#include "exception.h" 13#include "exception.h"
15#include "reg_constant.h" 14#include "reg_constant.h"
16#include "fpu_emu.h" 15#include "fpu_emu.h"
@@ -18,255 +17,228 @@
18#include "control_w.h" 17#include "control_w.h"
19#include "poly.h" 18#include "poly.h"
20 19
21
22static void log2_kernel(FPU_REG const *arg, u_char argsign, 20static void log2_kernel(FPU_REG const *arg, u_char argsign,
23 Xsig *accum_result, long int *expon); 21 Xsig * accum_result, long int *expon);
24
25 22
26/*--- poly_l2() -------------------------------------------------------------+ 23/*--- poly_l2() -------------------------------------------------------------+
27 | Base 2 logarithm by a polynomial approximation. | 24 | Base 2 logarithm by a polynomial approximation. |
28 +---------------------------------------------------------------------------*/ 25 +---------------------------------------------------------------------------*/
29void poly_l2(FPU_REG *st0_ptr, FPU_REG *st1_ptr, u_char st1_sign) 26void poly_l2(FPU_REG * st0_ptr, FPU_REG * st1_ptr, u_char st1_sign)
30{ 27{
31 long int exponent, expon, expon_expon; 28 long int exponent, expon, expon_expon;
32 Xsig accumulator, expon_accum, yaccum; 29 Xsig accumulator, expon_accum, yaccum;
33 u_char sign, argsign; 30 u_char sign, argsign;
34 FPU_REG x; 31 FPU_REG x;
35 int tag; 32 int tag;
36 33
37 exponent = exponent16(st0_ptr); 34 exponent = exponent16(st0_ptr);
38 35
39 /* From st0_ptr, make a number > sqrt(2)/2 and < sqrt(2) */ 36 /* From st0_ptr, make a number > sqrt(2)/2 and < sqrt(2) */
40 if ( st0_ptr->sigh > (unsigned)0xb504f334 ) 37 if (st0_ptr->sigh > (unsigned)0xb504f334) {
41 { 38 /* Treat as sqrt(2)/2 < st0_ptr < 1 */
42 /* Treat as sqrt(2)/2 < st0_ptr < 1 */ 39 significand(&x) = -significand(st0_ptr);
43 significand(&x) = - significand(st0_ptr); 40 setexponent16(&x, -1);
44 setexponent16(&x, -1); 41 exponent++;
45 exponent++; 42 argsign = SIGN_NEG;
46 argsign = SIGN_NEG; 43 } else {
47 } 44 /* Treat as 1 <= st0_ptr < sqrt(2) */
48 else 45 x.sigh = st0_ptr->sigh - 0x80000000;
49 { 46 x.sigl = st0_ptr->sigl;
50 /* Treat as 1 <= st0_ptr < sqrt(2) */ 47 setexponent16(&x, 0);
51 x.sigh = st0_ptr->sigh - 0x80000000; 48 argsign = SIGN_POS;
52 x.sigl = st0_ptr->sigl; 49 }
53 setexponent16(&x, 0); 50 tag = FPU_normalize_nuo(&x);
54 argsign = SIGN_POS;
55 }
56 tag = FPU_normalize_nuo(&x);
57
58 if ( tag == TAG_Zero )
59 {
60 expon = 0;
61 accumulator.msw = accumulator.midw = accumulator.lsw = 0;
62 }
63 else
64 {
65 log2_kernel(&x, argsign, &accumulator, &expon);
66 }
67
68 if ( exponent < 0 )
69 {
70 sign = SIGN_NEG;
71 exponent = -exponent;
72 }
73 else
74 sign = SIGN_POS;
75 expon_accum.msw = exponent; expon_accum.midw = expon_accum.lsw = 0;
76 if ( exponent )
77 {
78 expon_expon = 31 + norm_Xsig(&expon_accum);
79 shr_Xsig(&accumulator, expon_expon - expon);
80
81 if ( sign ^ argsign )
82 negate_Xsig(&accumulator);
83 add_Xsig_Xsig(&accumulator, &expon_accum);
84 }
85 else
86 {
87 expon_expon = expon;
88 sign = argsign;
89 }
90
91 yaccum.lsw = 0; XSIG_LL(yaccum) = significand(st1_ptr);
92 mul_Xsig_Xsig(&accumulator, &yaccum);
93
94 expon_expon += round_Xsig(&accumulator);
95
96 if ( accumulator.msw == 0 )
97 {
98 FPU_copy_to_reg1(&CONST_Z, TAG_Zero);
99 return;
100 }
101
102 significand(st1_ptr) = XSIG_LL(accumulator);
103 setexponent16(st1_ptr, expon_expon + exponent16(st1_ptr) + 1);
104
105 tag = FPU_round(st1_ptr, 1, 0, FULL_PRECISION, sign ^ st1_sign);
106 FPU_settagi(1, tag);
107
108 set_precision_flag_up(); /* 80486 appears to always do this */
109
110 return;
111 51
112} 52 if (tag == TAG_Zero) {
53 expon = 0;
54 accumulator.msw = accumulator.midw = accumulator.lsw = 0;
55 } else {
56 log2_kernel(&x, argsign, &accumulator, &expon);
57 }
58
59 if (exponent < 0) {
60 sign = SIGN_NEG;
61 exponent = -exponent;
62 } else
63 sign = SIGN_POS;
64 expon_accum.msw = exponent;
65 expon_accum.midw = expon_accum.lsw = 0;
66 if (exponent) {
67 expon_expon = 31 + norm_Xsig(&expon_accum);
68 shr_Xsig(&accumulator, expon_expon - expon);
69
70 if (sign ^ argsign)
71 negate_Xsig(&accumulator);
72 add_Xsig_Xsig(&accumulator, &expon_accum);
73 } else {
74 expon_expon = expon;
75 sign = argsign;
76 }
77
78 yaccum.lsw = 0;
79 XSIG_LL(yaccum) = significand(st1_ptr);
80 mul_Xsig_Xsig(&accumulator, &yaccum);
81
82 expon_expon += round_Xsig(&accumulator);
83
84 if (accumulator.msw == 0) {
85 FPU_copy_to_reg1(&CONST_Z, TAG_Zero);
86 return;
87 }
88
89 significand(st1_ptr) = XSIG_LL(accumulator);
90 setexponent16(st1_ptr, expon_expon + exponent16(st1_ptr) + 1);
113 91
92 tag = FPU_round(st1_ptr, 1, 0, FULL_PRECISION, sign ^ st1_sign);
93 FPU_settagi(1, tag);
94
95 set_precision_flag_up(); /* 80486 appears to always do this */
96
97 return;
98
99}
114 100
115/*--- poly_l2p1() -----------------------------------------------------------+ 101/*--- poly_l2p1() -----------------------------------------------------------+
116 | Base 2 logarithm by a polynomial approximation. | 102 | Base 2 logarithm by a polynomial approximation. |
117 | log2(x+1) | 103 | log2(x+1) |
118 +---------------------------------------------------------------------------*/ 104 +---------------------------------------------------------------------------*/
119int poly_l2p1(u_char sign0, u_char sign1, 105int poly_l2p1(u_char sign0, u_char sign1,
120 FPU_REG *st0_ptr, FPU_REG *st1_ptr, FPU_REG *dest) 106 FPU_REG * st0_ptr, FPU_REG * st1_ptr, FPU_REG * dest)
121{ 107{
122 u_char tag; 108 u_char tag;
123 long int exponent; 109 long int exponent;
124 Xsig accumulator, yaccum; 110 Xsig accumulator, yaccum;
125 111
126 if ( exponent16(st0_ptr) < 0 ) 112 if (exponent16(st0_ptr) < 0) {
127 { 113 log2_kernel(st0_ptr, sign0, &accumulator, &exponent);
128 log2_kernel(st0_ptr, sign0, &accumulator, &exponent);
129 114
130 yaccum.lsw = 0; 115 yaccum.lsw = 0;
131 XSIG_LL(yaccum) = significand(st1_ptr); 116 XSIG_LL(yaccum) = significand(st1_ptr);
132 mul_Xsig_Xsig(&accumulator, &yaccum); 117 mul_Xsig_Xsig(&accumulator, &yaccum);
133 118
134 exponent += round_Xsig(&accumulator); 119 exponent += round_Xsig(&accumulator);
135 120
136 exponent += exponent16(st1_ptr) + 1; 121 exponent += exponent16(st1_ptr) + 1;
137 if ( exponent < EXP_WAY_UNDER ) exponent = EXP_WAY_UNDER; 122 if (exponent < EXP_WAY_UNDER)
123 exponent = EXP_WAY_UNDER;
138 124
139 significand(dest) = XSIG_LL(accumulator); 125 significand(dest) = XSIG_LL(accumulator);
140 setexponent16(dest, exponent); 126 setexponent16(dest, exponent);
141 127
142 tag = FPU_round(dest, 1, 0, FULL_PRECISION, sign0 ^ sign1); 128 tag = FPU_round(dest, 1, 0, FULL_PRECISION, sign0 ^ sign1);
143 FPU_settagi(1, tag); 129 FPU_settagi(1, tag);
144 130
145 if ( tag == TAG_Valid ) 131 if (tag == TAG_Valid)
146 set_precision_flag_up(); /* 80486 appears to always do this */ 132 set_precision_flag_up(); /* 80486 appears to always do this */
147 } 133 } else {
148 else 134 /* The magnitude of st0_ptr is far too large. */
149 {
150 /* The magnitude of st0_ptr is far too large. */
151 135
152 if ( sign0 != SIGN_POS ) 136 if (sign0 != SIGN_POS) {
153 { 137 /* Trying to get the log of a negative number. */
154 /* Trying to get the log of a negative number. */ 138#ifdef PECULIAR_486 /* Stupid 80486 doesn't worry about log(negative). */
155#ifdef PECULIAR_486 /* Stupid 80486 doesn't worry about log(negative). */ 139 changesign(st1_ptr);
156 changesign(st1_ptr);
157#else 140#else
158 if ( arith_invalid(1) < 0 ) 141 if (arith_invalid(1) < 0)
159 return 1; 142 return 1;
160#endif /* PECULIAR_486 */ 143#endif /* PECULIAR_486 */
161 } 144 }
162 145
163 /* 80486 appears to do this */ 146 /* 80486 appears to do this */
164 if ( sign0 == SIGN_NEG ) 147 if (sign0 == SIGN_NEG)
165 set_precision_flag_down(); 148 set_precision_flag_down();
166 else 149 else
167 set_precision_flag_up(); 150 set_precision_flag_up();
168 } 151 }
169 152
170 if ( exponent(dest) <= EXP_UNDER ) 153 if (exponent(dest) <= EXP_UNDER)
171 EXCEPTION(EX_Underflow); 154 EXCEPTION(EX_Underflow);
172 155
173 return 0; 156 return 0;
174 157
175} 158}
176 159
177
178
179
180#undef HIPOWER 160#undef HIPOWER
181#define HIPOWER 10 161#define HIPOWER 10
182static const unsigned long long logterms[HIPOWER] = 162static const unsigned long long logterms[HIPOWER] = {
183{ 163 0x2a8eca5705fc2ef0LL,
184 0x2a8eca5705fc2ef0LL, 164 0xf6384ee1d01febceLL,
185 0xf6384ee1d01febceLL, 165 0x093bb62877cdf642LL,
186 0x093bb62877cdf642LL, 166 0x006985d8a9ec439bLL,
187 0x006985d8a9ec439bLL, 167 0x0005212c4f55a9c8LL,
188 0x0005212c4f55a9c8LL, 168 0x00004326a16927f0LL,
189 0x00004326a16927f0LL, 169 0x0000038d1d80a0e7LL,
190 0x0000038d1d80a0e7LL, 170 0x0000003141cc80c6LL,
191 0x0000003141cc80c6LL, 171 0x00000002b1668c9fLL,
192 0x00000002b1668c9fLL, 172 0x000000002c7a46aaLL
193 0x000000002c7a46aaLL
194}; 173};
195 174
196static const unsigned long leadterm = 0xb8000000; 175static const unsigned long leadterm = 0xb8000000;
197 176
198
199/*--- log2_kernel() ---------------------------------------------------------+ 177/*--- log2_kernel() ---------------------------------------------------------+
200 | Base 2 logarithm by a polynomial approximation. | 178 | Base 2 logarithm by a polynomial approximation. |
201 | log2(x+1) | 179 | log2(x+1) |
202 +---------------------------------------------------------------------------*/ 180 +---------------------------------------------------------------------------*/
203static void log2_kernel(FPU_REG const *arg, u_char argsign, Xsig *accum_result, 181static void log2_kernel(FPU_REG const *arg, u_char argsign, Xsig * accum_result,
204 long int *expon) 182 long int *expon)
205{ 183{
206 long int exponent, adj; 184 long int exponent, adj;
207 unsigned long long Xsq; 185 unsigned long long Xsq;
208 Xsig accumulator, Numer, Denom, argSignif, arg_signif; 186 Xsig accumulator, Numer, Denom, argSignif, arg_signif;
209 187
210 exponent = exponent16(arg); 188 exponent = exponent16(arg);
211 Numer.lsw = Denom.lsw = 0; 189 Numer.lsw = Denom.lsw = 0;
212 XSIG_LL(Numer) = XSIG_LL(Denom) = significand(arg); 190 XSIG_LL(Numer) = XSIG_LL(Denom) = significand(arg);
213 if ( argsign == SIGN_POS ) 191 if (argsign == SIGN_POS) {
214 { 192 shr_Xsig(&Denom, 2 - (1 + exponent));
215 shr_Xsig(&Denom, 2 - (1 + exponent)); 193 Denom.msw |= 0x80000000;
216 Denom.msw |= 0x80000000; 194 div_Xsig(&Numer, &Denom, &argSignif);
217 div_Xsig(&Numer, &Denom, &argSignif); 195 } else {
218 } 196 shr_Xsig(&Denom, 1 - (1 + exponent));
219 else 197 negate_Xsig(&Denom);
220 { 198 if (Denom.msw & 0x80000000) {
221 shr_Xsig(&Denom, 1 - (1 + exponent)); 199 div_Xsig(&Numer, &Denom, &argSignif);
222 negate_Xsig(&Denom); 200 exponent++;
223 if ( Denom.msw & 0x80000000 ) 201 } else {
224 { 202 /* Denom must be 1.0 */
225 div_Xsig(&Numer, &Denom, &argSignif); 203 argSignif.lsw = Numer.lsw;
226 exponent ++; 204 argSignif.midw = Numer.midw;
227 } 205 argSignif.msw = Numer.msw;
228 else 206 }
229 {
230 /* Denom must be 1.0 */
231 argSignif.lsw = Numer.lsw; argSignif.midw = Numer.midw;
232 argSignif.msw = Numer.msw;
233 } 207 }
234 }
235 208
236#ifndef PECULIAR_486 209#ifndef PECULIAR_486
237 /* Should check here that |local_arg| is within the valid range */ 210 /* Should check here that |local_arg| is within the valid range */
238 if ( exponent >= -2 ) 211 if (exponent >= -2) {
239 { 212 if ((exponent > -2) || (argSignif.msw > (unsigned)0xafb0ccc0)) {
240 if ( (exponent > -2) || 213 /* The argument is too large */
241 (argSignif.msw > (unsigned)0xafb0ccc0) ) 214 }
242 {
243 /* The argument is too large */
244 } 215 }
245 }
246#endif /* PECULIAR_486 */ 216#endif /* PECULIAR_486 */
247 217
248 arg_signif.lsw = argSignif.lsw; XSIG_LL(arg_signif) = XSIG_LL(argSignif); 218 arg_signif.lsw = argSignif.lsw;
249 adj = norm_Xsig(&argSignif); 219 XSIG_LL(arg_signif) = XSIG_LL(argSignif);
250 accumulator.lsw = argSignif.lsw; XSIG_LL(accumulator) = XSIG_LL(argSignif); 220 adj = norm_Xsig(&argSignif);
251 mul_Xsig_Xsig(&accumulator, &accumulator); 221 accumulator.lsw = argSignif.lsw;
252 shr_Xsig(&accumulator, 2*(-1 - (1 + exponent + adj))); 222 XSIG_LL(accumulator) = XSIG_LL(argSignif);
253 Xsq = XSIG_LL(accumulator); 223 mul_Xsig_Xsig(&accumulator, &accumulator);
254 if ( accumulator.lsw & 0x80000000 ) 224 shr_Xsig(&accumulator, 2 * (-1 - (1 + exponent + adj)));
255 Xsq++; 225 Xsq = XSIG_LL(accumulator);
256 226 if (accumulator.lsw & 0x80000000)
257 accumulator.msw = accumulator.midw = accumulator.lsw = 0; 227 Xsq++;
258 /* Do the basic fixed point polynomial evaluation */ 228
259 polynomial_Xsig(&accumulator, &Xsq, logterms, HIPOWER-1); 229 accumulator.msw = accumulator.midw = accumulator.lsw = 0;
260 230 /* Do the basic fixed point polynomial evaluation */
261 mul_Xsig_Xsig(&accumulator, &argSignif); 231 polynomial_Xsig(&accumulator, &Xsq, logterms, HIPOWER - 1);
262 shr_Xsig(&accumulator, 6 - adj); 232
263 233 mul_Xsig_Xsig(&accumulator, &argSignif);
264 mul32_Xsig(&arg_signif, leadterm); 234 shr_Xsig(&accumulator, 6 - adj);
265 add_two_Xsig(&accumulator, &arg_signif, &exponent); 235
266 236 mul32_Xsig(&arg_signif, leadterm);
267 *expon = exponent + 1; 237 add_two_Xsig(&accumulator, &arg_signif, &exponent);
268 accum_result->lsw = accumulator.lsw; 238
269 accum_result->midw = accumulator.midw; 239 *expon = exponent + 1;
270 accum_result->msw = accumulator.msw; 240 accum_result->lsw = accumulator.lsw;
241 accum_result->midw = accumulator.midw;
242 accum_result->msw = accumulator.msw;
271 243
272} 244}
diff --git a/arch/x86/math-emu/poly_sin.c b/arch/x86/math-emu/poly_sin.c
index a36313fb06f1..7273ae0c7692 100644
--- a/arch/x86/math-emu/poly_sin.c
+++ b/arch/x86/math-emu/poly_sin.c
@@ -11,7 +11,6 @@
11 | | 11 | |
12 +---------------------------------------------------------------------------*/ 12 +---------------------------------------------------------------------------*/
13 13
14
15#include "exception.h" 14#include "exception.h"
16#include "reg_constant.h" 15#include "reg_constant.h"
17#include "fpu_emu.h" 16#include "fpu_emu.h"
@@ -19,379 +18,361 @@
19#include "control_w.h" 18#include "control_w.h"
20#include "poly.h" 19#include "poly.h"
21 20
22
23#define N_COEFF_P 4 21#define N_COEFF_P 4
24#define N_COEFF_N 4 22#define N_COEFF_N 4
25 23
26static const unsigned long long pos_terms_l[N_COEFF_P] = 24static const unsigned long long pos_terms_l[N_COEFF_P] = {
27{ 25 0xaaaaaaaaaaaaaaabLL,
28 0xaaaaaaaaaaaaaaabLL, 26 0x00d00d00d00cf906LL,
29 0x00d00d00d00cf906LL, 27 0x000006b99159a8bbLL,
30 0x000006b99159a8bbLL, 28 0x000000000d7392e6LL
31 0x000000000d7392e6LL
32}; 29};
33 30
34static const unsigned long long neg_terms_l[N_COEFF_N] = 31static const unsigned long long neg_terms_l[N_COEFF_N] = {
35{ 32 0x2222222222222167LL,
36 0x2222222222222167LL, 33 0x0002e3bc74aab624LL,
37 0x0002e3bc74aab624LL, 34 0x0000000b09229062LL,
38 0x0000000b09229062LL, 35 0x00000000000c7973LL
39 0x00000000000c7973LL
40}; 36};
41 37
42
43
44#define N_COEFF_PH 4 38#define N_COEFF_PH 4
45#define N_COEFF_NH 4 39#define N_COEFF_NH 4
46static const unsigned long long pos_terms_h[N_COEFF_PH] = 40static const unsigned long long pos_terms_h[N_COEFF_PH] = {
47{ 41 0x0000000000000000LL,
48 0x0000000000000000LL, 42 0x05b05b05b05b0406LL,
49 0x05b05b05b05b0406LL, 43 0x000049f93edd91a9LL,
50 0x000049f93edd91a9LL, 44 0x00000000c9c9ed62LL
51 0x00000000c9c9ed62LL
52}; 45};
53 46
54static const unsigned long long neg_terms_h[N_COEFF_NH] = 47static const unsigned long long neg_terms_h[N_COEFF_NH] = {
55{ 48 0xaaaaaaaaaaaaaa98LL,
56 0xaaaaaaaaaaaaaa98LL, 49 0x001a01a01a019064LL,
57 0x001a01a01a019064LL, 50 0x0000008f76c68a77LL,
58 0x0000008f76c68a77LL, 51 0x0000000000d58f5eLL
59 0x0000000000d58f5eLL
60}; 52};
61 53
62
63/*--- poly_sine() -----------------------------------------------------------+ 54/*--- poly_sine() -----------------------------------------------------------+
64 | | 55 | |
65 +---------------------------------------------------------------------------*/ 56 +---------------------------------------------------------------------------*/
66void poly_sine(FPU_REG *st0_ptr) 57void poly_sine(FPU_REG * st0_ptr)
67{ 58{
68 int exponent, echange; 59 int exponent, echange;
69 Xsig accumulator, argSqrd, argTo4; 60 Xsig accumulator, argSqrd, argTo4;
70 unsigned long fix_up, adj; 61 unsigned long fix_up, adj;
71 unsigned long long fixed_arg; 62 unsigned long long fixed_arg;
72 FPU_REG result; 63 FPU_REG result;
73 64
74 exponent = exponent(st0_ptr); 65 exponent = exponent(st0_ptr);
75 66
76 accumulator.lsw = accumulator.midw = accumulator.msw = 0; 67 accumulator.lsw = accumulator.midw = accumulator.msw = 0;
77 68
78 /* Split into two ranges, for arguments below and above 1.0 */ 69 /* Split into two ranges, for arguments below and above 1.0 */
79 /* The boundary between upper and lower is approx 0.88309101259 */ 70 /* The boundary between upper and lower is approx 0.88309101259 */
80 if ( (exponent < -1) || ((exponent == -1) && (st0_ptr->sigh <= 0xe21240aa)) ) 71 if ((exponent < -1)
81 { 72 || ((exponent == -1) && (st0_ptr->sigh <= 0xe21240aa))) {
82 /* The argument is <= 0.88309101259 */ 73 /* The argument is <= 0.88309101259 */
74
75 argSqrd.msw = st0_ptr->sigh;
76 argSqrd.midw = st0_ptr->sigl;
77 argSqrd.lsw = 0;
78 mul64_Xsig(&argSqrd, &significand(st0_ptr));
79 shr_Xsig(&argSqrd, 2 * (-1 - exponent));
80 argTo4.msw = argSqrd.msw;
81 argTo4.midw = argSqrd.midw;
82 argTo4.lsw = argSqrd.lsw;
83 mul_Xsig_Xsig(&argTo4, &argTo4);
83 84
84 argSqrd.msw = st0_ptr->sigh; argSqrd.midw = st0_ptr->sigl; argSqrd.lsw = 0; 85 polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), neg_terms_l,
85 mul64_Xsig(&argSqrd, &significand(st0_ptr)); 86 N_COEFF_N - 1);
86 shr_Xsig(&argSqrd, 2*(-1-exponent)); 87 mul_Xsig_Xsig(&accumulator, &argSqrd);
87 argTo4.msw = argSqrd.msw; argTo4.midw = argSqrd.midw; 88 negate_Xsig(&accumulator);
88 argTo4.lsw = argSqrd.lsw;
89 mul_Xsig_Xsig(&argTo4, &argTo4);
90 89
91 polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), neg_terms_l, 90 polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), pos_terms_l,
92 N_COEFF_N-1); 91 N_COEFF_P - 1);
93 mul_Xsig_Xsig(&accumulator, &argSqrd);
94 negate_Xsig(&accumulator);
95 92
96 polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), pos_terms_l, 93 shr_Xsig(&accumulator, 2); /* Divide by four */
97 N_COEFF_P-1); 94 accumulator.msw |= 0x80000000; /* Add 1.0 */
98 95
99 shr_Xsig(&accumulator, 2); /* Divide by four */ 96 mul64_Xsig(&accumulator, &significand(st0_ptr));
100 accumulator.msw |= 0x80000000; /* Add 1.0 */ 97 mul64_Xsig(&accumulator, &significand(st0_ptr));
98 mul64_Xsig(&accumulator, &significand(st0_ptr));
101 99
102 mul64_Xsig(&accumulator, &significand(st0_ptr)); 100 /* Divide by four, FPU_REG compatible, etc */
103 mul64_Xsig(&accumulator, &significand(st0_ptr)); 101 exponent = 3 * exponent;
104 mul64_Xsig(&accumulator, &significand(st0_ptr));
105 102
106 /* Divide by four, FPU_REG compatible, etc */ 103 /* The minimum exponent difference is 3 */
107 exponent = 3*exponent; 104 shr_Xsig(&accumulator, exponent(st0_ptr) - exponent);
108 105
109 /* The minimum exponent difference is 3 */ 106 negate_Xsig(&accumulator);
110 shr_Xsig(&accumulator, exponent(st0_ptr) - exponent); 107 XSIG_LL(accumulator) += significand(st0_ptr);
111 108
112 negate_Xsig(&accumulator); 109 echange = round_Xsig(&accumulator);
113 XSIG_LL(accumulator) += significand(st0_ptr);
114 110
115 echange = round_Xsig(&accumulator); 111 setexponentpos(&result, exponent(st0_ptr) + echange);
112 } else {
113 /* The argument is > 0.88309101259 */
114 /* We use sin(st(0)) = cos(pi/2-st(0)) */
116 115
117 setexponentpos(&result, exponent(st0_ptr) + echange); 116 fixed_arg = significand(st0_ptr);
118 }
119 else
120 {
121 /* The argument is > 0.88309101259 */
122 /* We use sin(st(0)) = cos(pi/2-st(0)) */
123 117
124 fixed_arg = significand(st0_ptr); 118 if (exponent == 0) {
119 /* The argument is >= 1.0 */
125 120
126 if ( exponent == 0 ) 121 /* Put the binary point at the left. */
127 { 122 fixed_arg <<= 1;
128 /* The argument is >= 1.0 */ 123 }
124 /* pi/2 in hex is: 1.921fb54442d18469 898CC51701B839A2 52049C1 */
125 fixed_arg = 0x921fb54442d18469LL - fixed_arg;
126 /* There is a special case which arises due to rounding, to fix here. */
127 if (fixed_arg == 0xffffffffffffffffLL)
128 fixed_arg = 0;
129 129
130 /* Put the binary point at the left. */ 130 XSIG_LL(argSqrd) = fixed_arg;
131 fixed_arg <<= 1; 131 argSqrd.lsw = 0;
132 } 132 mul64_Xsig(&argSqrd, &fixed_arg);
133 /* pi/2 in hex is: 1.921fb54442d18469 898CC51701B839A2 52049C1 */
134 fixed_arg = 0x921fb54442d18469LL - fixed_arg;
135 /* There is a special case which arises due to rounding, to fix here. */
136 if ( fixed_arg == 0xffffffffffffffffLL )
137 fixed_arg = 0;
138 133
139 XSIG_LL(argSqrd) = fixed_arg; argSqrd.lsw = 0; 134 XSIG_LL(argTo4) = XSIG_LL(argSqrd);
140 mul64_Xsig(&argSqrd, &fixed_arg); 135 argTo4.lsw = argSqrd.lsw;
136 mul_Xsig_Xsig(&argTo4, &argTo4);
141 137
142 XSIG_LL(argTo4) = XSIG_LL(argSqrd); argTo4.lsw = argSqrd.lsw; 138 polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), neg_terms_h,
143 mul_Xsig_Xsig(&argTo4, &argTo4); 139 N_COEFF_NH - 1);
140 mul_Xsig_Xsig(&accumulator, &argSqrd);
141 negate_Xsig(&accumulator);
144 142
145 polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), neg_terms_h, 143 polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), pos_terms_h,
146 N_COEFF_NH-1); 144 N_COEFF_PH - 1);
147 mul_Xsig_Xsig(&accumulator, &argSqrd); 145 negate_Xsig(&accumulator);
148 negate_Xsig(&accumulator);
149 146
150 polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), pos_terms_h, 147 mul64_Xsig(&accumulator, &fixed_arg);
151 N_COEFF_PH-1); 148 mul64_Xsig(&accumulator, &fixed_arg);
152 negate_Xsig(&accumulator);
153 149
154 mul64_Xsig(&accumulator, &fixed_arg); 150 shr_Xsig(&accumulator, 3);
155 mul64_Xsig(&accumulator, &fixed_arg); 151 negate_Xsig(&accumulator);
156 152
157 shr_Xsig(&accumulator, 3); 153 add_Xsig_Xsig(&accumulator, &argSqrd);
158 negate_Xsig(&accumulator);
159 154
160 add_Xsig_Xsig(&accumulator, &argSqrd); 155 shr_Xsig(&accumulator, 1);
161 156
162 shr_Xsig(&accumulator, 1); 157 accumulator.lsw |= 1; /* A zero accumulator here would cause problems */
158 negate_Xsig(&accumulator);
163 159
164 accumulator.lsw |= 1; /* A zero accumulator here would cause problems */ 160 /* The basic computation is complete. Now fix the answer to
165 negate_Xsig(&accumulator); 161 compensate for the error due to the approximation used for
162 pi/2
163 */
166 164
167 /* The basic computation is complete. Now fix the answer to 165 /* This has an exponent of -65 */
168 compensate for the error due to the approximation used for 166 fix_up = 0x898cc517;
169 pi/2 167 /* The fix-up needs to be improved for larger args */
170 */ 168 if (argSqrd.msw & 0xffc00000) {
169 /* Get about 32 bit precision in these: */
170 fix_up -= mul_32_32(0x898cc517, argSqrd.msw) / 6;
171 }
172 fix_up = mul_32_32(fix_up, LL_MSW(fixed_arg));
171 173
172 /* This has an exponent of -65 */ 174 adj = accumulator.lsw; /* temp save */
173 fix_up = 0x898cc517; 175 accumulator.lsw -= fix_up;
174 /* The fix-up needs to be improved for larger args */ 176 if (accumulator.lsw > adj)
175 if ( argSqrd.msw & 0xffc00000 ) 177 XSIG_LL(accumulator)--;
176 {
177 /* Get about 32 bit precision in these: */
178 fix_up -= mul_32_32(0x898cc517, argSqrd.msw) / 6;
179 }
180 fix_up = mul_32_32(fix_up, LL_MSW(fixed_arg));
181 178
182 adj = accumulator.lsw; /* temp save */ 179 echange = round_Xsig(&accumulator);
183 accumulator.lsw -= fix_up;
184 if ( accumulator.lsw > adj )
185 XSIG_LL(accumulator) --;
186 180
187 echange = round_Xsig(&accumulator); 181 setexponentpos(&result, echange - 1);
188 182 }
189 setexponentpos(&result, echange - 1);
190 }
191 183
192 significand(&result) = XSIG_LL(accumulator); 184 significand(&result) = XSIG_LL(accumulator);
193 setsign(&result, getsign(st0_ptr)); 185 setsign(&result, getsign(st0_ptr));
194 FPU_copy_to_reg0(&result, TAG_Valid); 186 FPU_copy_to_reg0(&result, TAG_Valid);
195 187
196#ifdef PARANOID 188#ifdef PARANOID
197 if ( (exponent(&result) >= 0) 189 if ((exponent(&result) >= 0)
198 && (significand(&result) > 0x8000000000000000LL) ) 190 && (significand(&result) > 0x8000000000000000LL)) {
199 { 191 EXCEPTION(EX_INTERNAL | 0x150);
200 EXCEPTION(EX_INTERNAL|0x150); 192 }
201 }
202#endif /* PARANOID */ 193#endif /* PARANOID */
203 194
204} 195}
205 196
206
207
208/*--- poly_cos() ------------------------------------------------------------+ 197/*--- poly_cos() ------------------------------------------------------------+
209 | | 198 | |
210 +---------------------------------------------------------------------------*/ 199 +---------------------------------------------------------------------------*/
211void poly_cos(FPU_REG *st0_ptr) 200void poly_cos(FPU_REG * st0_ptr)
212{ 201{
213 FPU_REG result; 202 FPU_REG result;
214 long int exponent, exp2, echange; 203 long int exponent, exp2, echange;
215 Xsig accumulator, argSqrd, fix_up, argTo4; 204 Xsig accumulator, argSqrd, fix_up, argTo4;
216 unsigned long long fixed_arg; 205 unsigned long long fixed_arg;
217 206
218#ifdef PARANOID 207#ifdef PARANOID
219 if ( (exponent(st0_ptr) > 0) 208 if ((exponent(st0_ptr) > 0)
220 || ((exponent(st0_ptr) == 0) 209 || ((exponent(st0_ptr) == 0)
221 && (significand(st0_ptr) > 0xc90fdaa22168c234LL)) ) 210 && (significand(st0_ptr) > 0xc90fdaa22168c234LL))) {
222 { 211 EXCEPTION(EX_Invalid);
223 EXCEPTION(EX_Invalid); 212 FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
224 FPU_copy_to_reg0(&CONST_QNaN, TAG_Special); 213 return;
225 return;
226 }
227#endif /* PARANOID */
228
229 exponent = exponent(st0_ptr);
230
231 accumulator.lsw = accumulator.midw = accumulator.msw = 0;
232
233 if ( (exponent < -1) || ((exponent == -1) && (st0_ptr->sigh <= 0xb00d6f54)) )
234 {
235 /* arg is < 0.687705 */
236
237 argSqrd.msw = st0_ptr->sigh; argSqrd.midw = st0_ptr->sigl;
238 argSqrd.lsw = 0;
239 mul64_Xsig(&argSqrd, &significand(st0_ptr));
240
241 if ( exponent < -1 )
242 {
243 /* shift the argument right by the required places */
244 shr_Xsig(&argSqrd, 2*(-1-exponent));
245 }
246
247 argTo4.msw = argSqrd.msw; argTo4.midw = argSqrd.midw;
248 argTo4.lsw = argSqrd.lsw;
249 mul_Xsig_Xsig(&argTo4, &argTo4);
250
251 polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), neg_terms_h,
252 N_COEFF_NH-1);
253 mul_Xsig_Xsig(&accumulator, &argSqrd);
254 negate_Xsig(&accumulator);
255
256 polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), pos_terms_h,
257 N_COEFF_PH-1);
258 negate_Xsig(&accumulator);
259
260 mul64_Xsig(&accumulator, &significand(st0_ptr));
261 mul64_Xsig(&accumulator, &significand(st0_ptr));
262 shr_Xsig(&accumulator, -2*(1+exponent));
263
264 shr_Xsig(&accumulator, 3);
265 negate_Xsig(&accumulator);
266
267 add_Xsig_Xsig(&accumulator, &argSqrd);
268
269 shr_Xsig(&accumulator, 1);
270
271 /* It doesn't matter if accumulator is all zero here, the
272 following code will work ok */
273 negate_Xsig(&accumulator);
274
275 if ( accumulator.lsw & 0x80000000 )
276 XSIG_LL(accumulator) ++;
277 if ( accumulator.msw == 0 )
278 {
279 /* The result is 1.0 */
280 FPU_copy_to_reg0(&CONST_1, TAG_Valid);
281 return;
282 }
283 else
284 {
285 significand(&result) = XSIG_LL(accumulator);
286
287 /* will be a valid positive nr with expon = -1 */
288 setexponentpos(&result, -1);
289 }
290 }
291 else
292 {
293 fixed_arg = significand(st0_ptr);
294
295 if ( exponent == 0 )
296 {
297 /* The argument is >= 1.0 */
298
299 /* Put the binary point at the left. */
300 fixed_arg <<= 1;
301 }
302 /* pi/2 in hex is: 1.921fb54442d18469 898CC51701B839A2 52049C1 */
303 fixed_arg = 0x921fb54442d18469LL - fixed_arg;
304 /* There is a special case which arises due to rounding, to fix here. */
305 if ( fixed_arg == 0xffffffffffffffffLL )
306 fixed_arg = 0;
307
308 exponent = -1;
309 exp2 = -1;
310
311 /* A shift is needed here only for a narrow range of arguments,
312 i.e. for fixed_arg approx 2^-32, but we pick up more... */
313 if ( !(LL_MSW(fixed_arg) & 0xffff0000) )
314 {
315 fixed_arg <<= 16;
316 exponent -= 16;
317 exp2 -= 16;
318 } 214 }
215#endif /* PARANOID */
319 216
320 XSIG_LL(argSqrd) = fixed_arg; argSqrd.lsw = 0; 217 exponent = exponent(st0_ptr);
321 mul64_Xsig(&argSqrd, &fixed_arg); 218
322 219 accumulator.lsw = accumulator.midw = accumulator.msw = 0;
323 if ( exponent < -1 ) 220
324 { 221 if ((exponent < -1)
325 /* shift the argument right by the required places */ 222 || ((exponent == -1) && (st0_ptr->sigh <= 0xb00d6f54))) {
326 shr_Xsig(&argSqrd, 2*(-1-exponent)); 223 /* arg is < 0.687705 */
327 } 224
328 225 argSqrd.msw = st0_ptr->sigh;
329 argTo4.msw = argSqrd.msw; argTo4.midw = argSqrd.midw; 226 argSqrd.midw = st0_ptr->sigl;
330 argTo4.lsw = argSqrd.lsw; 227 argSqrd.lsw = 0;
331 mul_Xsig_Xsig(&argTo4, &argTo4); 228 mul64_Xsig(&argSqrd, &significand(st0_ptr));
332 229
333 polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), neg_terms_l, 230 if (exponent < -1) {
334 N_COEFF_N-1); 231 /* shift the argument right by the required places */
335 mul_Xsig_Xsig(&accumulator, &argSqrd); 232 shr_Xsig(&argSqrd, 2 * (-1 - exponent));
336 negate_Xsig(&accumulator); 233 }
337 234
338 polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), pos_terms_l, 235 argTo4.msw = argSqrd.msw;
339 N_COEFF_P-1); 236 argTo4.midw = argSqrd.midw;
340 237 argTo4.lsw = argSqrd.lsw;
341 shr_Xsig(&accumulator, 2); /* Divide by four */ 238 mul_Xsig_Xsig(&argTo4, &argTo4);
342 accumulator.msw |= 0x80000000; /* Add 1.0 */ 239
343 240 polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), neg_terms_h,
344 mul64_Xsig(&accumulator, &fixed_arg); 241 N_COEFF_NH - 1);
345 mul64_Xsig(&accumulator, &fixed_arg); 242 mul_Xsig_Xsig(&accumulator, &argSqrd);
346 mul64_Xsig(&accumulator, &fixed_arg); 243 negate_Xsig(&accumulator);
347 244
348 /* Divide by four, FPU_REG compatible, etc */ 245 polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), pos_terms_h,
349 exponent = 3*exponent; 246 N_COEFF_PH - 1);
350 247 negate_Xsig(&accumulator);
351 /* The minimum exponent difference is 3 */ 248
352 shr_Xsig(&accumulator, exp2 - exponent); 249 mul64_Xsig(&accumulator, &significand(st0_ptr));
353 250 mul64_Xsig(&accumulator, &significand(st0_ptr));
354 negate_Xsig(&accumulator); 251 shr_Xsig(&accumulator, -2 * (1 + exponent));
355 XSIG_LL(accumulator) += fixed_arg; 252
356 253 shr_Xsig(&accumulator, 3);
357 /* The basic computation is complete. Now fix the answer to 254 negate_Xsig(&accumulator);
358 compensate for the error due to the approximation used for 255
359 pi/2 256 add_Xsig_Xsig(&accumulator, &argSqrd);
360 */ 257
361 258 shr_Xsig(&accumulator, 1);
362 /* This has an exponent of -65 */ 259
363 XSIG_LL(fix_up) = 0x898cc51701b839a2ll; 260 /* It doesn't matter if accumulator is all zero here, the
364 fix_up.lsw = 0; 261 following code will work ok */
365 262 negate_Xsig(&accumulator);
366 /* The fix-up needs to be improved for larger args */ 263
367 if ( argSqrd.msw & 0xffc00000 ) 264 if (accumulator.lsw & 0x80000000)
368 { 265 XSIG_LL(accumulator)++;
369 /* Get about 32 bit precision in these: */ 266 if (accumulator.msw == 0) {
370 fix_up.msw -= mul_32_32(0x898cc517, argSqrd.msw) / 2; 267 /* The result is 1.0 */
371 fix_up.msw += mul_32_32(0x898cc517, argTo4.msw) / 24; 268 FPU_copy_to_reg0(&CONST_1, TAG_Valid);
269 return;
270 } else {
271 significand(&result) = XSIG_LL(accumulator);
272
273 /* will be a valid positive nr with expon = -1 */
274 setexponentpos(&result, -1);
275 }
276 } else {
277 fixed_arg = significand(st0_ptr);
278
279 if (exponent == 0) {
280 /* The argument is >= 1.0 */
281
282 /* Put the binary point at the left. */
283 fixed_arg <<= 1;
284 }
285 /* pi/2 in hex is: 1.921fb54442d18469 898CC51701B839A2 52049C1 */
286 fixed_arg = 0x921fb54442d18469LL - fixed_arg;
287 /* There is a special case which arises due to rounding, to fix here. */
288 if (fixed_arg == 0xffffffffffffffffLL)
289 fixed_arg = 0;
290
291 exponent = -1;
292 exp2 = -1;
293
294 /* A shift is needed here only for a narrow range of arguments,
295 i.e. for fixed_arg approx 2^-32, but we pick up more... */
296 if (!(LL_MSW(fixed_arg) & 0xffff0000)) {
297 fixed_arg <<= 16;
298 exponent -= 16;
299 exp2 -= 16;
300 }
301
302 XSIG_LL(argSqrd) = fixed_arg;
303 argSqrd.lsw = 0;
304 mul64_Xsig(&argSqrd, &fixed_arg);
305
306 if (exponent < -1) {
307 /* shift the argument right by the required places */
308 shr_Xsig(&argSqrd, 2 * (-1 - exponent));
309 }
310
311 argTo4.msw = argSqrd.msw;
312 argTo4.midw = argSqrd.midw;
313 argTo4.lsw = argSqrd.lsw;
314 mul_Xsig_Xsig(&argTo4, &argTo4);
315
316 polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), neg_terms_l,
317 N_COEFF_N - 1);
318 mul_Xsig_Xsig(&accumulator, &argSqrd);
319 negate_Xsig(&accumulator);
320
321 polynomial_Xsig(&accumulator, &XSIG_LL(argTo4), pos_terms_l,
322 N_COEFF_P - 1);
323
324 shr_Xsig(&accumulator, 2); /* Divide by four */
325 accumulator.msw |= 0x80000000; /* Add 1.0 */
326
327 mul64_Xsig(&accumulator, &fixed_arg);
328 mul64_Xsig(&accumulator, &fixed_arg);
329 mul64_Xsig(&accumulator, &fixed_arg);
330
331 /* Divide by four, FPU_REG compatible, etc */
332 exponent = 3 * exponent;
333
334 /* The minimum exponent difference is 3 */
335 shr_Xsig(&accumulator, exp2 - exponent);
336
337 negate_Xsig(&accumulator);
338 XSIG_LL(accumulator) += fixed_arg;
339
340 /* The basic computation is complete. Now fix the answer to
341 compensate for the error due to the approximation used for
342 pi/2
343 */
344
345 /* This has an exponent of -65 */
346 XSIG_LL(fix_up) = 0x898cc51701b839a2ll;
347 fix_up.lsw = 0;
348
349 /* The fix-up needs to be improved for larger args */
350 if (argSqrd.msw & 0xffc00000) {
351 /* Get about 32 bit precision in these: */
352 fix_up.msw -= mul_32_32(0x898cc517, argSqrd.msw) / 2;
353 fix_up.msw += mul_32_32(0x898cc517, argTo4.msw) / 24;
354 }
355
356 exp2 += norm_Xsig(&accumulator);
357 shr_Xsig(&accumulator, 1); /* Prevent overflow */
358 exp2++;
359 shr_Xsig(&fix_up, 65 + exp2);
360
361 add_Xsig_Xsig(&accumulator, &fix_up);
362
363 echange = round_Xsig(&accumulator);
364
365 setexponentpos(&result, exp2 + echange);
366 significand(&result) = XSIG_LL(accumulator);
372 } 367 }
373 368
374 exp2 += norm_Xsig(&accumulator); 369 FPU_copy_to_reg0(&result, TAG_Valid);
375 shr_Xsig(&accumulator, 1); /* Prevent overflow */
376 exp2++;
377 shr_Xsig(&fix_up, 65 + exp2);
378
379 add_Xsig_Xsig(&accumulator, &fix_up);
380
381 echange = round_Xsig(&accumulator);
382
383 setexponentpos(&result, exp2 + echange);
384 significand(&result) = XSIG_LL(accumulator);
385 }
386
387 FPU_copy_to_reg0(&result, TAG_Valid);
388 370
389#ifdef PARANOID 371#ifdef PARANOID
390 if ( (exponent(&result) >= 0) 372 if ((exponent(&result) >= 0)
391 && (significand(&result) > 0x8000000000000000LL) ) 373 && (significand(&result) > 0x8000000000000000LL)) {
392 { 374 EXCEPTION(EX_INTERNAL | 0x151);
393 EXCEPTION(EX_INTERNAL|0x151); 375 }
394 }
395#endif /* PARANOID */ 376#endif /* PARANOID */
396 377
397} 378}
diff --git a/arch/x86/math-emu/poly_tan.c b/arch/x86/math-emu/poly_tan.c
index 8df3e03b6e6f..c0d181e39229 100644
--- a/arch/x86/math-emu/poly_tan.c
+++ b/arch/x86/math-emu/poly_tan.c
@@ -17,206 +17,196 @@
17#include "control_w.h" 17#include "control_w.h"
18#include "poly.h" 18#include "poly.h"
19 19
20
21#define HiPOWERop 3 /* odd poly, positive terms */ 20#define HiPOWERop 3 /* odd poly, positive terms */
22static const unsigned long long oddplterm[HiPOWERop] = 21static const unsigned long long oddplterm[HiPOWERop] = {
23{ 22 0x0000000000000000LL,
24 0x0000000000000000LL, 23 0x0051a1cf08fca228LL,
25 0x0051a1cf08fca228LL, 24 0x0000000071284ff7LL
26 0x0000000071284ff7LL
27}; 25};
28 26
29#define HiPOWERon 2 /* odd poly, negative terms */ 27#define HiPOWERon 2 /* odd poly, negative terms */
30static const unsigned long long oddnegterm[HiPOWERon] = 28static const unsigned long long oddnegterm[HiPOWERon] = {
31{ 29 0x1291a9a184244e80LL,
32 0x1291a9a184244e80LL, 30 0x0000583245819c21LL
33 0x0000583245819c21LL
34}; 31};
35 32
36#define HiPOWERep 2 /* even poly, positive terms */ 33#define HiPOWERep 2 /* even poly, positive terms */
37static const unsigned long long evenplterm[HiPOWERep] = 34static const unsigned long long evenplterm[HiPOWERep] = {
38{ 35 0x0e848884b539e888LL,
39 0x0e848884b539e888LL, 36 0x00003c7f18b887daLL
40 0x00003c7f18b887daLL
41}; 37};
42 38
43#define HiPOWERen 2 /* even poly, negative terms */ 39#define HiPOWERen 2 /* even poly, negative terms */
44static const unsigned long long evennegterm[HiPOWERen] = 40static const unsigned long long evennegterm[HiPOWERen] = {
45{ 41 0xf1f0200fd51569ccLL,
46 0xf1f0200fd51569ccLL, 42 0x003afb46105c4432LL
47 0x003afb46105c4432LL
48}; 43};
49 44
50static const unsigned long long twothirds = 0xaaaaaaaaaaaaaaabLL; 45static const unsigned long long twothirds = 0xaaaaaaaaaaaaaaabLL;
51 46
52
53/*--- poly_tan() ------------------------------------------------------------+ 47/*--- poly_tan() ------------------------------------------------------------+
54 | | 48 | |
55 +---------------------------------------------------------------------------*/ 49 +---------------------------------------------------------------------------*/
56void poly_tan(FPU_REG *st0_ptr) 50void poly_tan(FPU_REG * st0_ptr)
57{ 51{
58 long int exponent; 52 long int exponent;
59 int invert; 53 int invert;
60 Xsig argSq, argSqSq, accumulatoro, accumulatore, accum, 54 Xsig argSq, argSqSq, accumulatoro, accumulatore, accum,
61 argSignif, fix_up; 55 argSignif, fix_up;
62 unsigned long adj; 56 unsigned long adj;
63 57
64 exponent = exponent(st0_ptr); 58 exponent = exponent(st0_ptr);
65 59
66#ifdef PARANOID 60#ifdef PARANOID
67 if ( signnegative(st0_ptr) ) /* Can't hack a number < 0.0 */ 61 if (signnegative(st0_ptr)) { /* Can't hack a number < 0.0 */
68 { arith_invalid(0); return; } /* Need a positive number */ 62 arith_invalid(0);
63 return;
64 } /* Need a positive number */
69#endif /* PARANOID */ 65#endif /* PARANOID */
70 66
71 /* Split the problem into two domains, smaller and larger than pi/4 */ 67 /* Split the problem into two domains, smaller and larger than pi/4 */
72 if ( (exponent == 0) || ((exponent == -1) && (st0_ptr->sigh > 0xc90fdaa2)) ) 68 if ((exponent == 0)
73 { 69 || ((exponent == -1) && (st0_ptr->sigh > 0xc90fdaa2))) {
74 /* The argument is greater than (approx) pi/4 */ 70 /* The argument is greater than (approx) pi/4 */
75 invert = 1; 71 invert = 1;
76 accum.lsw = 0; 72 accum.lsw = 0;
77 XSIG_LL(accum) = significand(st0_ptr); 73 XSIG_LL(accum) = significand(st0_ptr);
78 74
79 if ( exponent == 0 ) 75 if (exponent == 0) {
80 { 76 /* The argument is >= 1.0 */
81 /* The argument is >= 1.0 */ 77 /* Put the binary point at the left. */
82 /* Put the binary point at the left. */ 78 XSIG_LL(accum) <<= 1;
83 XSIG_LL(accum) <<= 1; 79 }
84 } 80 /* pi/2 in hex is: 1.921fb54442d18469 898CC51701B839A2 52049C1 */
85 /* pi/2 in hex is: 1.921fb54442d18469 898CC51701B839A2 52049C1 */ 81 XSIG_LL(accum) = 0x921fb54442d18469LL - XSIG_LL(accum);
86 XSIG_LL(accum) = 0x921fb54442d18469LL - XSIG_LL(accum); 82 /* This is a special case which arises due to rounding. */
87 /* This is a special case which arises due to rounding. */ 83 if (XSIG_LL(accum) == 0xffffffffffffffffLL) {
88 if ( XSIG_LL(accum) == 0xffffffffffffffffLL ) 84 FPU_settag0(TAG_Valid);
89 { 85 significand(st0_ptr) = 0x8a51e04daabda360LL;
90 FPU_settag0(TAG_Valid); 86 setexponent16(st0_ptr,
91 significand(st0_ptr) = 0x8a51e04daabda360LL; 87 (0x41 + EXTENDED_Ebias) | SIGN_Negative);
92 setexponent16(st0_ptr, (0x41 + EXTENDED_Ebias) | SIGN_Negative); 88 return;
93 return; 89 }
90
91 argSignif.lsw = accum.lsw;
92 XSIG_LL(argSignif) = XSIG_LL(accum);
93 exponent = -1 + norm_Xsig(&argSignif);
94 } else {
95 invert = 0;
96 argSignif.lsw = 0;
97 XSIG_LL(accum) = XSIG_LL(argSignif) = significand(st0_ptr);
98
99 if (exponent < -1) {
100 /* shift the argument right by the required places */
101 if (FPU_shrx(&XSIG_LL(accum), -1 - exponent) >=
102 0x80000000U)
103 XSIG_LL(accum)++; /* round up */
104 }
94 } 105 }
95 106
96 argSignif.lsw = accum.lsw; 107 XSIG_LL(argSq) = XSIG_LL(accum);
97 XSIG_LL(argSignif) = XSIG_LL(accum); 108 argSq.lsw = accum.lsw;
98 exponent = -1 + norm_Xsig(&argSignif); 109 mul_Xsig_Xsig(&argSq, &argSq);
99 } 110 XSIG_LL(argSqSq) = XSIG_LL(argSq);
100 else 111 argSqSq.lsw = argSq.lsw;
101 { 112 mul_Xsig_Xsig(&argSqSq, &argSqSq);
102 invert = 0; 113
103 argSignif.lsw = 0; 114 /* Compute the negative terms for the numerator polynomial */
104 XSIG_LL(accum) = XSIG_LL(argSignif) = significand(st0_ptr); 115 accumulatoro.msw = accumulatoro.midw = accumulatoro.lsw = 0;
105 116 polynomial_Xsig(&accumulatoro, &XSIG_LL(argSqSq), oddnegterm,
106 if ( exponent < -1 ) 117 HiPOWERon - 1);
107 { 118 mul_Xsig_Xsig(&accumulatoro, &argSq);
108 /* shift the argument right by the required places */ 119 negate_Xsig(&accumulatoro);
109 if ( FPU_shrx(&XSIG_LL(accum), -1-exponent) >= 0x80000000U ) 120 /* Add the positive terms */
110 XSIG_LL(accum) ++; /* round up */ 121 polynomial_Xsig(&accumulatoro, &XSIG_LL(argSqSq), oddplterm,
111 } 122 HiPOWERop - 1);
112 } 123
113 124 /* Compute the positive terms for the denominator polynomial */
114 XSIG_LL(argSq) = XSIG_LL(accum); argSq.lsw = accum.lsw; 125 accumulatore.msw = accumulatore.midw = accumulatore.lsw = 0;
115 mul_Xsig_Xsig(&argSq, &argSq); 126 polynomial_Xsig(&accumulatore, &XSIG_LL(argSqSq), evenplterm,
116 XSIG_LL(argSqSq) = XSIG_LL(argSq); argSqSq.lsw = argSq.lsw; 127 HiPOWERep - 1);
117 mul_Xsig_Xsig(&argSqSq, &argSqSq); 128 mul_Xsig_Xsig(&accumulatore, &argSq);
118 129 negate_Xsig(&accumulatore);
119 /* Compute the negative terms for the numerator polynomial */ 130 /* Add the negative terms */
120 accumulatoro.msw = accumulatoro.midw = accumulatoro.lsw = 0; 131 polynomial_Xsig(&accumulatore, &XSIG_LL(argSqSq), evennegterm,
121 polynomial_Xsig(&accumulatoro, &XSIG_LL(argSqSq), oddnegterm, HiPOWERon-1); 132 HiPOWERen - 1);
122 mul_Xsig_Xsig(&accumulatoro, &argSq); 133 /* Multiply by arg^2 */
123 negate_Xsig(&accumulatoro); 134 mul64_Xsig(&accumulatore, &XSIG_LL(argSignif));
124 /* Add the positive terms */ 135 mul64_Xsig(&accumulatore, &XSIG_LL(argSignif));
125 polynomial_Xsig(&accumulatoro, &XSIG_LL(argSqSq), oddplterm, HiPOWERop-1); 136 /* de-normalize and divide by 2 */
126 137 shr_Xsig(&accumulatore, -2 * (1 + exponent) + 1);
127 138 negate_Xsig(&accumulatore); /* This does 1 - accumulator */
128 /* Compute the positive terms for the denominator polynomial */ 139
129 accumulatore.msw = accumulatore.midw = accumulatore.lsw = 0; 140 /* Now find the ratio. */
130 polynomial_Xsig(&accumulatore, &XSIG_LL(argSqSq), evenplterm, HiPOWERep-1); 141 if (accumulatore.msw == 0) {
131 mul_Xsig_Xsig(&accumulatore, &argSq); 142 /* accumulatoro must contain 1.0 here, (actually, 0) but it
132 negate_Xsig(&accumulatore); 143 really doesn't matter what value we use because it will
133 /* Add the negative terms */ 144 have negligible effect in later calculations
134 polynomial_Xsig(&accumulatore, &XSIG_LL(argSqSq), evennegterm, HiPOWERen-1); 145 */
135 /* Multiply by arg^2 */ 146 XSIG_LL(accum) = 0x8000000000000000LL;
136 mul64_Xsig(&accumulatore, &XSIG_LL(argSignif)); 147 accum.lsw = 0;
137 mul64_Xsig(&accumulatore, &XSIG_LL(argSignif)); 148 } else {
138 /* de-normalize and divide by 2 */ 149 div_Xsig(&accumulatoro, &accumulatore, &accum);
139 shr_Xsig(&accumulatore, -2*(1+exponent) + 1);
140 negate_Xsig(&accumulatore); /* This does 1 - accumulator */
141
142 /* Now find the ratio. */
143 if ( accumulatore.msw == 0 )
144 {
145 /* accumulatoro must contain 1.0 here, (actually, 0) but it
146 really doesn't matter what value we use because it will
147 have negligible effect in later calculations
148 */
149 XSIG_LL(accum) = 0x8000000000000000LL;
150 accum.lsw = 0;
151 }
152 else
153 {
154 div_Xsig(&accumulatoro, &accumulatore, &accum);
155 }
156
157 /* Multiply by 1/3 * arg^3 */
158 mul64_Xsig(&accum, &XSIG_LL(argSignif));
159 mul64_Xsig(&accum, &XSIG_LL(argSignif));
160 mul64_Xsig(&accum, &XSIG_LL(argSignif));
161 mul64_Xsig(&accum, &twothirds);
162 shr_Xsig(&accum, -2*(exponent+1));
163
164 /* tan(arg) = arg + accum */
165 add_two_Xsig(&accum, &argSignif, &exponent);
166
167 if ( invert )
168 {
169 /* We now have the value of tan(pi_2 - arg) where pi_2 is an
170 approximation for pi/2
171 */
172 /* The next step is to fix the answer to compensate for the
173 error due to the approximation used for pi/2
174 */
175
176 /* This is (approx) delta, the error in our approx for pi/2
177 (see above). It has an exponent of -65
178 */
179 XSIG_LL(fix_up) = 0x898cc51701b839a2LL;
180 fix_up.lsw = 0;
181
182 if ( exponent == 0 )
183 adj = 0xffffffff; /* We want approx 1.0 here, but
184 this is close enough. */
185 else if ( exponent > -30 )
186 {
187 adj = accum.msw >> -(exponent+1); /* tan */
188 adj = mul_32_32(adj, adj); /* tan^2 */
189 } 150 }
190 else 151
191 adj = 0; 152 /* Multiply by 1/3 * arg^3 */
192 adj = mul_32_32(0x898cc517, adj); /* delta * tan^2 */ 153 mul64_Xsig(&accum, &XSIG_LL(argSignif));
193 154 mul64_Xsig(&accum, &XSIG_LL(argSignif));
194 fix_up.msw += adj; 155 mul64_Xsig(&accum, &XSIG_LL(argSignif));
195 if ( !(fix_up.msw & 0x80000000) ) /* did fix_up overflow ? */ 156 mul64_Xsig(&accum, &twothirds);
196 { 157 shr_Xsig(&accum, -2 * (exponent + 1));
197 /* Yes, we need to add an msb */ 158
198 shr_Xsig(&fix_up, 1); 159 /* tan(arg) = arg + accum */
199 fix_up.msw |= 0x80000000; 160 add_two_Xsig(&accum, &argSignif, &exponent);
200 shr_Xsig(&fix_up, 64 + exponent); 161
162 if (invert) {
163 /* We now have the value of tan(pi_2 - arg) where pi_2 is an
164 approximation for pi/2
165 */
166 /* The next step is to fix the answer to compensate for the
167 error due to the approximation used for pi/2
168 */
169
170 /* This is (approx) delta, the error in our approx for pi/2
171 (see above). It has an exponent of -65
172 */
173 XSIG_LL(fix_up) = 0x898cc51701b839a2LL;
174 fix_up.lsw = 0;
175
176 if (exponent == 0)
177 adj = 0xffffffff; /* We want approx 1.0 here, but
178 this is close enough. */
179 else if (exponent > -30) {
180 adj = accum.msw >> -(exponent + 1); /* tan */
181 adj = mul_32_32(adj, adj); /* tan^2 */
182 } else
183 adj = 0;
184 adj = mul_32_32(0x898cc517, adj); /* delta * tan^2 */
185
186 fix_up.msw += adj;
187 if (!(fix_up.msw & 0x80000000)) { /* did fix_up overflow ? */
188 /* Yes, we need to add an msb */
189 shr_Xsig(&fix_up, 1);
190 fix_up.msw |= 0x80000000;
191 shr_Xsig(&fix_up, 64 + exponent);
192 } else
193 shr_Xsig(&fix_up, 65 + exponent);
194
195 add_two_Xsig(&accum, &fix_up, &exponent);
196
197 /* accum now contains tan(pi/2 - arg).
198 Use tan(arg) = 1.0 / tan(pi/2 - arg)
199 */
200 accumulatoro.lsw = accumulatoro.midw = 0;
201 accumulatoro.msw = 0x80000000;
202 div_Xsig(&accumulatoro, &accum, &accum);
203 exponent = -exponent - 1;
201 } 204 }
202 else 205
203 shr_Xsig(&fix_up, 65 + exponent); 206 /* Transfer the result */
204 207 round_Xsig(&accum);
205 add_two_Xsig(&accum, &fix_up, &exponent); 208 FPU_settag0(TAG_Valid);
206 209 significand(st0_ptr) = XSIG_LL(accum);
207 /* accum now contains tan(pi/2 - arg). 210 setexponent16(st0_ptr, exponent + EXTENDED_Ebias); /* Result is positive. */
208 Use tan(arg) = 1.0 / tan(pi/2 - arg)
209 */
210 accumulatoro.lsw = accumulatoro.midw = 0;
211 accumulatoro.msw = 0x80000000;
212 div_Xsig(&accumulatoro, &accum, &accum);
213 exponent = - exponent - 1;
214 }
215
216 /* Transfer the result */
217 round_Xsig(&accum);
218 FPU_settag0(TAG_Valid);
219 significand(st0_ptr) = XSIG_LL(accum);
220 setexponent16(st0_ptr, exponent + EXTENDED_Ebias); /* Result is positive. */
221 211
222} 212}
diff --git a/arch/x86/math-emu/reg_add_sub.c b/arch/x86/math-emu/reg_add_sub.c
index 7cd3b37ac084..deea48b9f13a 100644
--- a/arch/x86/math-emu/reg_add_sub.c
+++ b/arch/x86/math-emu/reg_add_sub.c
@@ -27,7 +27,7 @@
27static 27static
28int add_sub_specials(FPU_REG const *a, u_char taga, u_char signa, 28int add_sub_specials(FPU_REG const *a, u_char taga, u_char signa,
29 FPU_REG const *b, u_char tagb, u_char signb, 29 FPU_REG const *b, u_char tagb, u_char signb,
30 FPU_REG *dest, int deststnr, int control_w); 30 FPU_REG * dest, int deststnr, int control_w);
31 31
32/* 32/*
33 Operates on st(0) and st(n), or on st(0) and temporary data. 33 Operates on st(0) and st(n), or on st(0) and temporary data.
@@ -35,340 +35,299 @@ int add_sub_specials(FPU_REG const *a, u_char taga, u_char signa,
35 */ 35 */
36int FPU_add(FPU_REG const *b, u_char tagb, int deststnr, int control_w) 36int FPU_add(FPU_REG const *b, u_char tagb, int deststnr, int control_w)
37{ 37{
38 FPU_REG *a = &st(0); 38 FPU_REG *a = &st(0);
39 FPU_REG *dest = &st(deststnr); 39 FPU_REG *dest = &st(deststnr);
40 u_char signb = getsign(b); 40 u_char signb = getsign(b);
41 u_char taga = FPU_gettag0(); 41 u_char taga = FPU_gettag0();
42 u_char signa = getsign(a); 42 u_char signa = getsign(a);
43 u_char saved_sign = getsign(dest); 43 u_char saved_sign = getsign(dest);
44 int diff, tag, expa, expb; 44 int diff, tag, expa, expb;
45 45
46 if ( !(taga | tagb) ) 46 if (!(taga | tagb)) {
47 { 47 expa = exponent(a);
48 expa = exponent(a); 48 expb = exponent(b);
49 expb = exponent(b); 49
50 50 valid_add:
51 valid_add: 51 /* Both registers are valid */
52 /* Both registers are valid */ 52 if (!(signa ^ signb)) {
53 if (!(signa ^ signb)) 53 /* signs are the same */
54 { 54 tag =
55 /* signs are the same */ 55 FPU_u_add(a, b, dest, control_w, signa, expa, expb);
56 tag = FPU_u_add(a, b, dest, control_w, signa, expa, expb); 56 } else {
57 } 57 /* The signs are different, so do a subtraction */
58 else 58 diff = expa - expb;
59 { 59 if (!diff) {
60 /* The signs are different, so do a subtraction */ 60 diff = a->sigh - b->sigh; /* This works only if the ms bits
61 diff = expa - expb; 61 are identical. */
62 if (!diff) 62 if (!diff) {
63 { 63 diff = a->sigl > b->sigl;
64 diff = a->sigh - b->sigh; /* This works only if the ms bits 64 if (!diff)
65 are identical. */ 65 diff = -(a->sigl < b->sigl);
66 if (!diff) 66 }
67 { 67 }
68 diff = a->sigl > b->sigl; 68
69 if (!diff) 69 if (diff > 0) {
70 diff = -(a->sigl < b->sigl); 70 tag =
71 FPU_u_sub(a, b, dest, control_w, signa,
72 expa, expb);
73 } else if (diff < 0) {
74 tag =
75 FPU_u_sub(b, a, dest, control_w, signb,
76 expb, expa);
77 } else {
78 FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
79 /* sign depends upon rounding mode */
80 setsign(dest, ((control_w & CW_RC) != RC_DOWN)
81 ? SIGN_POS : SIGN_NEG);
82 return TAG_Zero;
83 }
71 } 84 }
72 }
73
74 if (diff > 0)
75 {
76 tag = FPU_u_sub(a, b, dest, control_w, signa, expa, expb);
77 }
78 else if ( diff < 0 )
79 {
80 tag = FPU_u_sub(b, a, dest, control_w, signb, expb, expa);
81 }
82 else
83 {
84 FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
85 /* sign depends upon rounding mode */
86 setsign(dest, ((control_w & CW_RC) != RC_DOWN)
87 ? SIGN_POS : SIGN_NEG);
88 return TAG_Zero;
89 }
90 }
91 85
92 if ( tag < 0 ) 86 if (tag < 0) {
93 { 87 setsign(dest, saved_sign);
94 setsign(dest, saved_sign); 88 return tag;
95 return tag; 89 }
90 FPU_settagi(deststnr, tag);
91 return tag;
96 } 92 }
97 FPU_settagi(deststnr, tag);
98 return tag;
99 }
100 93
101 if ( taga == TAG_Special ) 94 if (taga == TAG_Special)
102 taga = FPU_Special(a); 95 taga = FPU_Special(a);
103 if ( tagb == TAG_Special ) 96 if (tagb == TAG_Special)
104 tagb = FPU_Special(b); 97 tagb = FPU_Special(b);
105 98
106 if ( ((taga == TAG_Valid) && (tagb == TW_Denormal)) 99 if (((taga == TAG_Valid) && (tagb == TW_Denormal))
107 || ((taga == TW_Denormal) && (tagb == TAG_Valid)) 100 || ((taga == TW_Denormal) && (tagb == TAG_Valid))
108 || ((taga == TW_Denormal) && (tagb == TW_Denormal)) ) 101 || ((taga == TW_Denormal) && (tagb == TW_Denormal))) {
109 { 102 FPU_REG x, y;
110 FPU_REG x, y; 103
104 if (denormal_operand() < 0)
105 return FPU_Exception;
106
107 FPU_to_exp16(a, &x);
108 FPU_to_exp16(b, &y);
109 a = &x;
110 b = &y;
111 expa = exponent16(a);
112 expb = exponent16(b);
113 goto valid_add;
114 }
111 115
112 if ( denormal_operand() < 0 ) 116 if ((taga == TW_NaN) || (tagb == TW_NaN)) {
113 return FPU_Exception; 117 if (deststnr == 0)
118 return real_2op_NaN(b, tagb, deststnr, a);
119 else
120 return real_2op_NaN(a, taga, deststnr, a);
121 }
114 122
115 FPU_to_exp16(a, &x); 123 return add_sub_specials(a, taga, signa, b, tagb, signb,
116 FPU_to_exp16(b, &y); 124 dest, deststnr, control_w);
117 a = &x;
118 b = &y;
119 expa = exponent16(a);
120 expb = exponent16(b);
121 goto valid_add;
122 }
123
124 if ( (taga == TW_NaN) || (tagb == TW_NaN) )
125 {
126 if ( deststnr == 0 )
127 return real_2op_NaN(b, tagb, deststnr, a);
128 else
129 return real_2op_NaN(a, taga, deststnr, a);
130 }
131
132 return add_sub_specials(a, taga, signa, b, tagb, signb,
133 dest, deststnr, control_w);
134} 125}
135 126
136
137/* Subtract b from a. (a-b) -> dest */ 127/* Subtract b from a. (a-b) -> dest */
138int FPU_sub(int flags, int rm, int control_w) 128int FPU_sub(int flags, int rm, int control_w)
139{ 129{
140 FPU_REG const *a, *b; 130 FPU_REG const *a, *b;
141 FPU_REG *dest; 131 FPU_REG *dest;
142 u_char taga, tagb, signa, signb, saved_sign, sign; 132 u_char taga, tagb, signa, signb, saved_sign, sign;
143 int diff, tag = 0, expa, expb, deststnr; 133 int diff, tag = 0, expa, expb, deststnr;
144 134
145 a = &st(0); 135 a = &st(0);
146 taga = FPU_gettag0(); 136 taga = FPU_gettag0();
147 137
148 deststnr = 0; 138 deststnr = 0;
149 if ( flags & LOADED ) 139 if (flags & LOADED) {
150 { 140 b = (FPU_REG *) rm;
151 b = (FPU_REG *)rm; 141 tagb = flags & 0x0f;
152 tagb = flags & 0x0f; 142 } else {
153 } 143 b = &st(rm);
154 else 144 tagb = FPU_gettagi(rm);
155 { 145
156 b = &st(rm); 146 if (flags & DEST_RM)
157 tagb = FPU_gettagi(rm); 147 deststnr = rm;
158
159 if ( flags & DEST_RM )
160 deststnr = rm;
161 }
162
163 signa = getsign(a);
164 signb = getsign(b);
165
166 if ( flags & REV )
167 {
168 signa ^= SIGN_NEG;
169 signb ^= SIGN_NEG;
170 }
171
172 dest = &st(deststnr);
173 saved_sign = getsign(dest);
174
175 if ( !(taga | tagb) )
176 {
177 expa = exponent(a);
178 expb = exponent(b);
179
180 valid_subtract:
181 /* Both registers are valid */
182
183 diff = expa - expb;
184
185 if (!diff)
186 {
187 diff = a->sigh - b->sigh; /* Works only if ms bits are identical */
188 if (!diff)
189 {
190 diff = a->sigl > b->sigl;
191 if (!diff)
192 diff = -(a->sigl < b->sigl);
193 }
194 } 148 }
195 149
196 switch ( (((int)signa)*2 + signb) / SIGN_NEG ) 150 signa = getsign(a);
197 { 151 signb = getsign(b);
198 case 0: /* P - P */ 152
199 case 3: /* N - N */ 153 if (flags & REV) {
200 if (diff > 0) 154 signa ^= SIGN_NEG;
201 { 155 signb ^= SIGN_NEG;
202 /* |a| > |b| */ 156 }
203 tag = FPU_u_sub(a, b, dest, control_w, signa, expa, expb); 157
204 } 158 dest = &st(deststnr);
205 else if ( diff == 0 ) 159 saved_sign = getsign(dest);
206 { 160
207 FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr); 161 if (!(taga | tagb)) {
208 162 expa = exponent(a);
209 /* sign depends upon rounding mode */ 163 expb = exponent(b);
210 setsign(dest, ((control_w & CW_RC) != RC_DOWN) 164
211 ? SIGN_POS : SIGN_NEG); 165 valid_subtract:
212 return TAG_Zero; 166 /* Both registers are valid */
213 } 167
214 else 168 diff = expa - expb;
215 { 169
216 sign = signa ^ SIGN_NEG; 170 if (!diff) {
217 tag = FPU_u_sub(b, a, dest, control_w, sign, expb, expa); 171 diff = a->sigh - b->sigh; /* Works only if ms bits are identical */
218 } 172 if (!diff) {
219 break; 173 diff = a->sigl > b->sigl;
220 case 1: /* P - N */ 174 if (!diff)
221 tag = FPU_u_add(a, b, dest, control_w, SIGN_POS, expa, expb); 175 diff = -(a->sigl < b->sigl);
222 break; 176 }
223 case 2: /* N - P */ 177 }
224 tag = FPU_u_add(a, b, dest, control_w, SIGN_NEG, expa, expb); 178
225 break; 179 switch ((((int)signa) * 2 + signb) / SIGN_NEG) {
180 case 0: /* P - P */
181 case 3: /* N - N */
182 if (diff > 0) {
183 /* |a| > |b| */
184 tag =
185 FPU_u_sub(a, b, dest, control_w, signa,
186 expa, expb);
187 } else if (diff == 0) {
188 FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
189
190 /* sign depends upon rounding mode */
191 setsign(dest, ((control_w & CW_RC) != RC_DOWN)
192 ? SIGN_POS : SIGN_NEG);
193 return TAG_Zero;
194 } else {
195 sign = signa ^ SIGN_NEG;
196 tag =
197 FPU_u_sub(b, a, dest, control_w, sign, expb,
198 expa);
199 }
200 break;
201 case 1: /* P - N */
202 tag =
203 FPU_u_add(a, b, dest, control_w, SIGN_POS, expa,
204 expb);
205 break;
206 case 2: /* N - P */
207 tag =
208 FPU_u_add(a, b, dest, control_w, SIGN_NEG, expa,
209 expb);
210 break;
226#ifdef PARANOID 211#ifdef PARANOID
227 default: 212 default:
228 EXCEPTION(EX_INTERNAL|0x111); 213 EXCEPTION(EX_INTERNAL | 0x111);
229 return -1; 214 return -1;
230#endif 215#endif
216 }
217 if (tag < 0) {
218 setsign(dest, saved_sign);
219 return tag;
220 }
221 FPU_settagi(deststnr, tag);
222 return tag;
231 } 223 }
232 if ( tag < 0 )
233 {
234 setsign(dest, saved_sign);
235 return tag;
236 }
237 FPU_settagi(deststnr, tag);
238 return tag;
239 }
240 224
241 if ( taga == TAG_Special ) 225 if (taga == TAG_Special)
242 taga = FPU_Special(a); 226 taga = FPU_Special(a);
243 if ( tagb == TAG_Special ) 227 if (tagb == TAG_Special)
244 tagb = FPU_Special(b); 228 tagb = FPU_Special(b);
245 229
246 if ( ((taga == TAG_Valid) && (tagb == TW_Denormal)) 230 if (((taga == TAG_Valid) && (tagb == TW_Denormal))
247 || ((taga == TW_Denormal) && (tagb == TAG_Valid)) 231 || ((taga == TW_Denormal) && (tagb == TAG_Valid))
248 || ((taga == TW_Denormal) && (tagb == TW_Denormal)) ) 232 || ((taga == TW_Denormal) && (tagb == TW_Denormal))) {
249 { 233 FPU_REG x, y;
250 FPU_REG x, y;
251 234
252 if ( denormal_operand() < 0 ) 235 if (denormal_operand() < 0)
253 return FPU_Exception; 236 return FPU_Exception;
237
238 FPU_to_exp16(a, &x);
239 FPU_to_exp16(b, &y);
240 a = &x;
241 b = &y;
242 expa = exponent16(a);
243 expb = exponent16(b);
254 244
255 FPU_to_exp16(a, &x); 245 goto valid_subtract;
256 FPU_to_exp16(b, &y);
257 a = &x;
258 b = &y;
259 expa = exponent16(a);
260 expb = exponent16(b);
261
262 goto valid_subtract;
263 }
264
265 if ( (taga == TW_NaN) || (tagb == TW_NaN) )
266 {
267 FPU_REG const *d1, *d2;
268 if ( flags & REV )
269 {
270 d1 = b;
271 d2 = a;
272 } 246 }
273 else 247
274 { 248 if ((taga == TW_NaN) || (tagb == TW_NaN)) {
275 d1 = a; 249 FPU_REG const *d1, *d2;
276 d2 = b; 250 if (flags & REV) {
251 d1 = b;
252 d2 = a;
253 } else {
254 d1 = a;
255 d2 = b;
256 }
257 if (flags & LOADED)
258 return real_2op_NaN(b, tagb, deststnr, d1);
259 if (flags & DEST_RM)
260 return real_2op_NaN(a, taga, deststnr, d2);
261 else
262 return real_2op_NaN(b, tagb, deststnr, d2);
277 } 263 }
278 if ( flags & LOADED )
279 return real_2op_NaN(b, tagb, deststnr, d1);
280 if ( flags & DEST_RM )
281 return real_2op_NaN(a, taga, deststnr, d2);
282 else
283 return real_2op_NaN(b, tagb, deststnr, d2);
284 }
285
286 return add_sub_specials(a, taga, signa, b, tagb, signb ^ SIGN_NEG,
287 dest, deststnr, control_w);
288}
289 264
265 return add_sub_specials(a, taga, signa, b, tagb, signb ^ SIGN_NEG,
266 dest, deststnr, control_w);
267}
290 268
291static 269static
292int add_sub_specials(FPU_REG const *a, u_char taga, u_char signa, 270int add_sub_specials(FPU_REG const *a, u_char taga, u_char signa,
293 FPU_REG const *b, u_char tagb, u_char signb, 271 FPU_REG const *b, u_char tagb, u_char signb,
294 FPU_REG *dest, int deststnr, int control_w) 272 FPU_REG * dest, int deststnr, int control_w)
295{ 273{
296 if ( ((taga == TW_Denormal) || (tagb == TW_Denormal)) 274 if (((taga == TW_Denormal) || (tagb == TW_Denormal))
297 && (denormal_operand() < 0) ) 275 && (denormal_operand() < 0))
298 return FPU_Exception; 276 return FPU_Exception;
299 277
300 if (taga == TAG_Zero) 278 if (taga == TAG_Zero) {
301 { 279 if (tagb == TAG_Zero) {
302 if (tagb == TAG_Zero) 280 /* Both are zero, result will be zero. */
303 { 281 u_char different_signs = signa ^ signb;
304 /* Both are zero, result will be zero. */ 282
305 u_char different_signs = signa ^ signb; 283 FPU_copy_to_regi(a, TAG_Zero, deststnr);
306 284 if (different_signs) {
307 FPU_copy_to_regi(a, TAG_Zero, deststnr); 285 /* Signs are different. */
308 if ( different_signs ) 286 /* Sign of answer depends upon rounding mode. */
309 { 287 setsign(dest, ((control_w & CW_RC) != RC_DOWN)
310 /* Signs are different. */ 288 ? SIGN_POS : SIGN_NEG);
311 /* Sign of answer depends upon rounding mode. */ 289 } else
312 setsign(dest, ((control_w & CW_RC) != RC_DOWN) 290 setsign(dest, signa); /* signa may differ from the sign of a. */
313 ? SIGN_POS : SIGN_NEG); 291 return TAG_Zero;
314 } 292 } else {
315 else 293 reg_copy(b, dest);
316 setsign(dest, signa); /* signa may differ from the sign of a. */ 294 if ((tagb == TW_Denormal) && (b->sigh & 0x80000000)) {
317 return TAG_Zero; 295 /* A pseudoDenormal, convert it. */
318 } 296 addexponent(dest, 1);
319 else 297 tagb = TAG_Valid;
320 { 298 } else if (tagb > TAG_Empty)
321 reg_copy(b, dest); 299 tagb = TAG_Special;
322 if ( (tagb == TW_Denormal) && (b->sigh & 0x80000000) ) 300 setsign(dest, signb); /* signb may differ from the sign of b. */
323 { 301 FPU_settagi(deststnr, tagb);
324 /* A pseudoDenormal, convert it. */ 302 return tagb;
325 addexponent(dest, 1); 303 }
326 tagb = TAG_Valid; 304 } else if (tagb == TAG_Zero) {
327 } 305 reg_copy(a, dest);
328 else if ( tagb > TAG_Empty ) 306 if ((taga == TW_Denormal) && (a->sigh & 0x80000000)) {
329 tagb = TAG_Special; 307 /* A pseudoDenormal */
330 setsign(dest, signb); /* signb may differ from the sign of b. */ 308 addexponent(dest, 1);
331 FPU_settagi(deststnr, tagb); 309 taga = TAG_Valid;
332 return tagb; 310 } else if (taga > TAG_Empty)
333 } 311 taga = TAG_Special;
334 } 312 setsign(dest, signa); /* signa may differ from the sign of a. */
335 else if (tagb == TAG_Zero) 313 FPU_settagi(deststnr, taga);
336 { 314 return taga;
337 reg_copy(a, dest); 315 } else if (taga == TW_Infinity) {
338 if ( (taga == TW_Denormal) && (a->sigh & 0x80000000) ) 316 if ((tagb != TW_Infinity) || (signa == signb)) {
339 { 317 FPU_copy_to_regi(a, TAG_Special, deststnr);
340 /* A pseudoDenormal */ 318 setsign(dest, signa); /* signa may differ from the sign of a. */
341 addexponent(dest, 1); 319 return taga;
342 taga = TAG_Valid; 320 }
343 } 321 /* Infinity-Infinity is undefined. */
344 else if ( taga > TAG_Empty ) 322 return arith_invalid(deststnr);
345 taga = TAG_Special; 323 } else if (tagb == TW_Infinity) {
346 setsign(dest, signa); /* signa may differ from the sign of a. */ 324 FPU_copy_to_regi(b, TAG_Special, deststnr);
347 FPU_settagi(deststnr, taga); 325 setsign(dest, signb); /* signb may differ from the sign of b. */
348 return taga; 326 return tagb;
349 }
350 else if (taga == TW_Infinity)
351 {
352 if ( (tagb != TW_Infinity) || (signa == signb) )
353 {
354 FPU_copy_to_regi(a, TAG_Special, deststnr);
355 setsign(dest, signa); /* signa may differ from the sign of a. */
356 return taga;
357 } 327 }
358 /* Infinity-Infinity is undefined. */
359 return arith_invalid(deststnr);
360 }
361 else if (tagb == TW_Infinity)
362 {
363 FPU_copy_to_regi(b, TAG_Special, deststnr);
364 setsign(dest, signb); /* signb may differ from the sign of b. */
365 return tagb;
366 }
367
368#ifdef PARANOID 328#ifdef PARANOID
369 EXCEPTION(EX_INTERNAL|0x101); 329 EXCEPTION(EX_INTERNAL | 0x101);
370#endif 330#endif
371 331
372 return FPU_Exception; 332 return FPU_Exception;
373} 333}
374
diff --git a/arch/x86/math-emu/reg_compare.c b/arch/x86/math-emu/reg_compare.c
index f37c5b5a35ad..ecce55fc2e2e 100644
--- a/arch/x86/math-emu/reg_compare.c
+++ b/arch/x86/math-emu/reg_compare.c
@@ -20,362 +20,331 @@
20#include "control_w.h" 20#include "control_w.h"
21#include "status_w.h" 21#include "status_w.h"
22 22
23
24static int compare(FPU_REG const *b, int tagb) 23static int compare(FPU_REG const *b, int tagb)
25{ 24{
26 int diff, exp0, expb; 25 int diff, exp0, expb;
27 u_char st0_tag; 26 u_char st0_tag;
28 FPU_REG *st0_ptr; 27 FPU_REG *st0_ptr;
29 FPU_REG x, y; 28 FPU_REG x, y;
30 u_char st0_sign, signb = getsign(b); 29 u_char st0_sign, signb = getsign(b);
31 30
32 st0_ptr = &st(0); 31 st0_ptr = &st(0);
33 st0_tag = FPU_gettag0(); 32 st0_tag = FPU_gettag0();
34 st0_sign = getsign(st0_ptr); 33 st0_sign = getsign(st0_ptr);
35 34
36 if ( tagb == TAG_Special ) 35 if (tagb == TAG_Special)
37 tagb = FPU_Special(b); 36 tagb = FPU_Special(b);
38 if ( st0_tag == TAG_Special ) 37 if (st0_tag == TAG_Special)
39 st0_tag = FPU_Special(st0_ptr); 38 st0_tag = FPU_Special(st0_ptr);
40 39
41 if ( ((st0_tag != TAG_Valid) && (st0_tag != TW_Denormal)) 40 if (((st0_tag != TAG_Valid) && (st0_tag != TW_Denormal))
42 || ((tagb != TAG_Valid) && (tagb != TW_Denormal)) ) 41 || ((tagb != TAG_Valid) && (tagb != TW_Denormal))) {
43 { 42 if (st0_tag == TAG_Zero) {
44 if ( st0_tag == TAG_Zero ) 43 if (tagb == TAG_Zero)
45 { 44 return COMP_A_eq_B;
46 if ( tagb == TAG_Zero ) return COMP_A_eq_B; 45 if (tagb == TAG_Valid)
47 if ( tagb == TAG_Valid ) 46 return ((signb ==
48 return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B); 47 SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B);
49 if ( tagb == TW_Denormal ) 48 if (tagb == TW_Denormal)
50 return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B) 49 return ((signb ==
51 | COMP_Denormal; 50 SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
52 } 51 | COMP_Denormal;
53 else if ( tagb == TAG_Zero ) 52 } else if (tagb == TAG_Zero) {
54 { 53 if (st0_tag == TAG_Valid)
55 if ( st0_tag == TAG_Valid ) 54 return ((st0_sign ==
56 return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B); 55 SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
57 if ( st0_tag == TW_Denormal ) 56 if (st0_tag == TW_Denormal)
58 return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B) 57 return ((st0_sign ==
59 | COMP_Denormal; 58 SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
59 | COMP_Denormal;
60 }
61
62 if (st0_tag == TW_Infinity) {
63 if ((tagb == TAG_Valid) || (tagb == TAG_Zero))
64 return ((st0_sign ==
65 SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
66 else if (tagb == TW_Denormal)
67 return ((st0_sign ==
68 SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
69 | COMP_Denormal;
70 else if (tagb == TW_Infinity) {
71 /* The 80486 book says that infinities can be equal! */
72 return (st0_sign == signb) ? COMP_A_eq_B :
73 ((st0_sign ==
74 SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
75 }
76 /* Fall through to the NaN code */
77 } else if (tagb == TW_Infinity) {
78 if ((st0_tag == TAG_Valid) || (st0_tag == TAG_Zero))
79 return ((signb ==
80 SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B);
81 if (st0_tag == TW_Denormal)
82 return ((signb ==
83 SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
84 | COMP_Denormal;
85 /* Fall through to the NaN code */
86 }
87
88 /* The only possibility now should be that one of the arguments
89 is a NaN */
90 if ((st0_tag == TW_NaN) || (tagb == TW_NaN)) {
91 int signalling = 0, unsupported = 0;
92 if (st0_tag == TW_NaN) {
93 signalling =
94 (st0_ptr->sigh & 0xc0000000) == 0x80000000;
95 unsupported = !((exponent(st0_ptr) == EXP_OVER)
96 && (st0_ptr->
97 sigh & 0x80000000));
98 }
99 if (tagb == TW_NaN) {
100 signalling |=
101 (b->sigh & 0xc0000000) == 0x80000000;
102 unsupported |= !((exponent(b) == EXP_OVER)
103 && (b->sigh & 0x80000000));
104 }
105 if (signalling || unsupported)
106 return COMP_No_Comp | COMP_SNaN | COMP_NaN;
107 else
108 /* Neither is a signaling NaN */
109 return COMP_No_Comp | COMP_NaN;
110 }
111
112 EXCEPTION(EX_Invalid);
60 } 113 }
61 114
62 if ( st0_tag == TW_Infinity ) 115 if (st0_sign != signb) {
63 { 116 return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
64 if ( (tagb == TAG_Valid) || (tagb == TAG_Zero) ) 117 | (((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
65 return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B); 118 COMP_Denormal : 0);
66 else if ( tagb == TW_Denormal )
67 return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
68 | COMP_Denormal;
69 else if ( tagb == TW_Infinity )
70 {
71 /* The 80486 book says that infinities can be equal! */
72 return (st0_sign == signb) ? COMP_A_eq_B :
73 ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
74 }
75 /* Fall through to the NaN code */
76 }
77 else if ( tagb == TW_Infinity )
78 {
79 if ( (st0_tag == TAG_Valid) || (st0_tag == TAG_Zero) )
80 return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B);
81 if ( st0_tag == TW_Denormal )
82 return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
83 | COMP_Denormal;
84 /* Fall through to the NaN code */
85 } 119 }
86 120
87 /* The only possibility now should be that one of the arguments 121 if ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) {
88 is a NaN */ 122 FPU_to_exp16(st0_ptr, &x);
89 if ( (st0_tag == TW_NaN) || (tagb == TW_NaN) ) 123 FPU_to_exp16(b, &y);
90 { 124 st0_ptr = &x;
91 int signalling = 0, unsupported = 0; 125 b = &y;
92 if ( st0_tag == TW_NaN ) 126 exp0 = exponent16(st0_ptr);
93 { 127 expb = exponent16(b);
94 signalling = (st0_ptr->sigh & 0xc0000000) == 0x80000000; 128 } else {
95 unsupported = !((exponent(st0_ptr) == EXP_OVER) 129 exp0 = exponent(st0_ptr);
96 && (st0_ptr->sigh & 0x80000000)); 130 expb = exponent(b);
97 }
98 if ( tagb == TW_NaN )
99 {
100 signalling |= (b->sigh & 0xc0000000) == 0x80000000;
101 unsupported |= !((exponent(b) == EXP_OVER)
102 && (b->sigh & 0x80000000));
103 }
104 if ( signalling || unsupported )
105 return COMP_No_Comp | COMP_SNaN | COMP_NaN;
106 else
107 /* Neither is a signaling NaN */
108 return COMP_No_Comp | COMP_NaN;
109 } 131 }
110
111 EXCEPTION(EX_Invalid);
112 }
113
114 if (st0_sign != signb)
115 {
116 return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
117 | ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
118 COMP_Denormal : 0);
119 }
120
121 if ( (st0_tag == TW_Denormal) || (tagb == TW_Denormal) )
122 {
123 FPU_to_exp16(st0_ptr, &x);
124 FPU_to_exp16(b, &y);
125 st0_ptr = &x;
126 b = &y;
127 exp0 = exponent16(st0_ptr);
128 expb = exponent16(b);
129 }
130 else
131 {
132 exp0 = exponent(st0_ptr);
133 expb = exponent(b);
134 }
135 132
136#ifdef PARANOID 133#ifdef PARANOID
137 if (!(st0_ptr->sigh & 0x80000000)) EXCEPTION(EX_Invalid); 134 if (!(st0_ptr->sigh & 0x80000000))
138 if (!(b->sigh & 0x80000000)) EXCEPTION(EX_Invalid); 135 EXCEPTION(EX_Invalid);
136 if (!(b->sigh & 0x80000000))
137 EXCEPTION(EX_Invalid);
139#endif /* PARANOID */ 138#endif /* PARANOID */
140 139
141 diff = exp0 - expb; 140 diff = exp0 - expb;
142 if ( diff == 0 ) 141 if (diff == 0) {
143 { 142 diff = st0_ptr->sigh - b->sigh; /* Works only if ms bits are
144 diff = st0_ptr->sigh - b->sigh; /* Works only if ms bits are 143 identical */
145 identical */ 144 if (diff == 0) {
146 if ( diff == 0 ) 145 diff = st0_ptr->sigl > b->sigl;
147 { 146 if (diff == 0)
148 diff = st0_ptr->sigl > b->sigl; 147 diff = -(st0_ptr->sigl < b->sigl);
149 if ( diff == 0 ) 148 }
150 diff = -(st0_ptr->sigl < b->sigl);
151 } 149 }
152 }
153
154 if ( diff > 0 )
155 {
156 return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
157 | ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
158 COMP_Denormal : 0);
159 }
160 if ( diff < 0 )
161 {
162 return ((st0_sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
163 | ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
164 COMP_Denormal : 0);
165 }
166
167 return COMP_A_eq_B
168 | ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
169 COMP_Denormal : 0);
170 150
171} 151 if (diff > 0) {
152 return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
153 | (((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
154 COMP_Denormal : 0);
155 }
156 if (diff < 0) {
157 return ((st0_sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
158 | (((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
159 COMP_Denormal : 0);
160 }
172 161
162 return COMP_A_eq_B
163 | (((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
164 COMP_Denormal : 0);
165
166}
173 167
174/* This function requires that st(0) is not empty */ 168/* This function requires that st(0) is not empty */
175int FPU_compare_st_data(FPU_REG const *loaded_data, u_char loaded_tag) 169int FPU_compare_st_data(FPU_REG const *loaded_data, u_char loaded_tag)
176{ 170{
177 int f = 0, c; 171 int f = 0, c;
178 172
179 c = compare(loaded_data, loaded_tag); 173 c = compare(loaded_data, loaded_tag);
180 174
181 if (c & COMP_NaN) 175 if (c & COMP_NaN) {
182 { 176 EXCEPTION(EX_Invalid);
183 EXCEPTION(EX_Invalid); 177 f = SW_C3 | SW_C2 | SW_C0;
184 f = SW_C3 | SW_C2 | SW_C0; 178 } else
185 } 179 switch (c & 7) {
186 else 180 case COMP_A_lt_B:
187 switch (c & 7) 181 f = SW_C0;
188 { 182 break;
189 case COMP_A_lt_B: 183 case COMP_A_eq_B:
190 f = SW_C0; 184 f = SW_C3;
191 break; 185 break;
192 case COMP_A_eq_B: 186 case COMP_A_gt_B:
193 f = SW_C3; 187 f = 0;
194 break; 188 break;
195 case COMP_A_gt_B: 189 case COMP_No_Comp:
196 f = 0; 190 f = SW_C3 | SW_C2 | SW_C0;
197 break; 191 break;
198 case COMP_No_Comp:
199 f = SW_C3 | SW_C2 | SW_C0;
200 break;
201#ifdef PARANOID 192#ifdef PARANOID
202 default: 193 default:
203 EXCEPTION(EX_INTERNAL|0x121); 194 EXCEPTION(EX_INTERNAL | 0x121);
204 f = SW_C3 | SW_C2 | SW_C0; 195 f = SW_C3 | SW_C2 | SW_C0;
205 break; 196 break;
206#endif /* PARANOID */ 197#endif /* PARANOID */
207 } 198 }
208 setcc(f); 199 setcc(f);
209 if (c & COMP_Denormal) 200 if (c & COMP_Denormal) {
210 { 201 return denormal_operand() < 0;
211 return denormal_operand() < 0; 202 }
212 } 203 return 0;
213 return 0;
214} 204}
215 205
216
217static int compare_st_st(int nr) 206static int compare_st_st(int nr)
218{ 207{
219 int f = 0, c; 208 int f = 0, c;
220 FPU_REG *st_ptr; 209 FPU_REG *st_ptr;
221 210
222 if ( !NOT_EMPTY(0) || !NOT_EMPTY(nr) ) 211 if (!NOT_EMPTY(0) || !NOT_EMPTY(nr)) {
223 { 212 setcc(SW_C3 | SW_C2 | SW_C0);
224 setcc(SW_C3 | SW_C2 | SW_C0); 213 /* Stack fault */
225 /* Stack fault */ 214 EXCEPTION(EX_StackUnder);
226 EXCEPTION(EX_StackUnder); 215 return !(control_word & CW_Invalid);
227 return !(control_word & CW_Invalid); 216 }
228 } 217
229 218 st_ptr = &st(nr);
230 st_ptr = &st(nr); 219 c = compare(st_ptr, FPU_gettagi(nr));
231 c = compare(st_ptr, FPU_gettagi(nr)); 220 if (c & COMP_NaN) {
232 if (c & COMP_NaN) 221 setcc(SW_C3 | SW_C2 | SW_C0);
233 { 222 EXCEPTION(EX_Invalid);
234 setcc(SW_C3 | SW_C2 | SW_C0); 223 return !(control_word & CW_Invalid);
235 EXCEPTION(EX_Invalid); 224 } else
236 return !(control_word & CW_Invalid); 225 switch (c & 7) {
237 } 226 case COMP_A_lt_B:
238 else 227 f = SW_C0;
239 switch (c & 7) 228 break;
240 { 229 case COMP_A_eq_B:
241 case COMP_A_lt_B: 230 f = SW_C3;
242 f = SW_C0; 231 break;
243 break; 232 case COMP_A_gt_B:
244 case COMP_A_eq_B: 233 f = 0;
245 f = SW_C3; 234 break;
246 break; 235 case COMP_No_Comp:
247 case COMP_A_gt_B: 236 f = SW_C3 | SW_C2 | SW_C0;
248 f = 0; 237 break;
249 break;
250 case COMP_No_Comp:
251 f = SW_C3 | SW_C2 | SW_C0;
252 break;
253#ifdef PARANOID 238#ifdef PARANOID
254 default: 239 default:
255 EXCEPTION(EX_INTERNAL|0x122); 240 EXCEPTION(EX_INTERNAL | 0x122);
256 f = SW_C3 | SW_C2 | SW_C0; 241 f = SW_C3 | SW_C2 | SW_C0;
257 break; 242 break;
258#endif /* PARANOID */ 243#endif /* PARANOID */
259 } 244 }
260 setcc(f); 245 setcc(f);
261 if (c & COMP_Denormal) 246 if (c & COMP_Denormal) {
262 { 247 return denormal_operand() < 0;
263 return denormal_operand() < 0; 248 }
264 } 249 return 0;
265 return 0;
266} 250}
267 251
268
269static int compare_u_st_st(int nr) 252static int compare_u_st_st(int nr)
270{ 253{
271 int f = 0, c; 254 int f = 0, c;
272 FPU_REG *st_ptr; 255 FPU_REG *st_ptr;
273 256
274 if ( !NOT_EMPTY(0) || !NOT_EMPTY(nr) ) 257 if (!NOT_EMPTY(0) || !NOT_EMPTY(nr)) {
275 { 258 setcc(SW_C3 | SW_C2 | SW_C0);
276 setcc(SW_C3 | SW_C2 | SW_C0); 259 /* Stack fault */
277 /* Stack fault */ 260 EXCEPTION(EX_StackUnder);
278 EXCEPTION(EX_StackUnder); 261 return !(control_word & CW_Invalid);
279 return !(control_word & CW_Invalid);
280 }
281
282 st_ptr = &st(nr);
283 c = compare(st_ptr, FPU_gettagi(nr));
284 if (c & COMP_NaN)
285 {
286 setcc(SW_C3 | SW_C2 | SW_C0);
287 if (c & COMP_SNaN) /* This is the only difference between
288 un-ordered and ordinary comparisons */
289 {
290 EXCEPTION(EX_Invalid);
291 return !(control_word & CW_Invalid);
292 } 262 }
293 return 0; 263
294 } 264 st_ptr = &st(nr);
295 else 265 c = compare(st_ptr, FPU_gettagi(nr));
296 switch (c & 7) 266 if (c & COMP_NaN) {
297 { 267 setcc(SW_C3 | SW_C2 | SW_C0);
298 case COMP_A_lt_B: 268 if (c & COMP_SNaN) { /* This is the only difference between
299 f = SW_C0; 269 un-ordered and ordinary comparisons */
300 break; 270 EXCEPTION(EX_Invalid);
301 case COMP_A_eq_B: 271 return !(control_word & CW_Invalid);
302 f = SW_C3; 272 }
303 break; 273 return 0;
304 case COMP_A_gt_B: 274 } else
305 f = 0; 275 switch (c & 7) {
306 break; 276 case COMP_A_lt_B:
307 case COMP_No_Comp: 277 f = SW_C0;
308 f = SW_C3 | SW_C2 | SW_C0; 278 break;
309 break; 279 case COMP_A_eq_B:
280 f = SW_C3;
281 break;
282 case COMP_A_gt_B:
283 f = 0;
284 break;
285 case COMP_No_Comp:
286 f = SW_C3 | SW_C2 | SW_C0;
287 break;
310#ifdef PARANOID 288#ifdef PARANOID
311 default: 289 default:
312 EXCEPTION(EX_INTERNAL|0x123); 290 EXCEPTION(EX_INTERNAL | 0x123);
313 f = SW_C3 | SW_C2 | SW_C0; 291 f = SW_C3 | SW_C2 | SW_C0;
314 break; 292 break;
315#endif /* PARANOID */ 293#endif /* PARANOID */
316 } 294 }
317 setcc(f); 295 setcc(f);
318 if (c & COMP_Denormal) 296 if (c & COMP_Denormal) {
319 { 297 return denormal_operand() < 0;
320 return denormal_operand() < 0; 298 }
321 } 299 return 0;
322 return 0;
323} 300}
324 301
325/*---------------------------------------------------------------------------*/ 302/*---------------------------------------------------------------------------*/
326 303
327void fcom_st(void) 304void fcom_st(void)
328{ 305{
329 /* fcom st(i) */ 306 /* fcom st(i) */
330 compare_st_st(FPU_rm); 307 compare_st_st(FPU_rm);
331} 308}
332 309
333
334void fcompst(void) 310void fcompst(void)
335{ 311{
336 /* fcomp st(i) */ 312 /* fcomp st(i) */
337 if ( !compare_st_st(FPU_rm) ) 313 if (!compare_st_st(FPU_rm))
338 FPU_pop(); 314 FPU_pop();
339} 315}
340 316
341
342void fcompp(void) 317void fcompp(void)
343{ 318{
344 /* fcompp */ 319 /* fcompp */
345 if (FPU_rm != 1) 320 if (FPU_rm != 1) {
346 { 321 FPU_illegal();
347 FPU_illegal(); 322 return;
348 return; 323 }
349 } 324 if (!compare_st_st(1))
350 if ( !compare_st_st(1) ) 325 poppop();
351 poppop();
352} 326}
353 327
354
355void fucom_(void) 328void fucom_(void)
356{ 329{
357 /* fucom st(i) */ 330 /* fucom st(i) */
358 compare_u_st_st(FPU_rm); 331 compare_u_st_st(FPU_rm);
359 332
360} 333}
361 334
362
363void fucomp(void) 335void fucomp(void)
364{ 336{
365 /* fucomp st(i) */ 337 /* fucomp st(i) */
366 if ( !compare_u_st_st(FPU_rm) ) 338 if (!compare_u_st_st(FPU_rm))
367 FPU_pop(); 339 FPU_pop();
368} 340}
369 341
370
371void fucompp(void) 342void fucompp(void)
372{ 343{
373 /* fucompp */ 344 /* fucompp */
374 if (FPU_rm == 1) 345 if (FPU_rm == 1) {
375 { 346 if (!compare_u_st_st(1))
376 if ( !compare_u_st_st(1) ) 347 poppop();
377 poppop(); 348 } else
378 } 349 FPU_illegal();
379 else
380 FPU_illegal();
381} 350}
diff --git a/arch/x86/math-emu/reg_constant.c b/arch/x86/math-emu/reg_constant.c
index a85015801969..04869e64b18e 100644
--- a/arch/x86/math-emu/reg_constant.c
+++ b/arch/x86/math-emu/reg_constant.c
@@ -16,29 +16,28 @@
16#include "reg_constant.h" 16#include "reg_constant.h"
17#include "control_w.h" 17#include "control_w.h"
18 18
19
20#define MAKE_REG(s,e,l,h) { l, h, \ 19#define MAKE_REG(s,e,l,h) { l, h, \
21 ((EXTENDED_Ebias+(e)) | ((SIGN_##s != 0)*0x8000)) } 20 ((EXTENDED_Ebias+(e)) | ((SIGN_##s != 0)*0x8000)) }
22 21
23FPU_REG const CONST_1 = MAKE_REG(POS, 0, 0x00000000, 0x80000000); 22FPU_REG const CONST_1 = MAKE_REG(POS, 0, 0x00000000, 0x80000000);
24#if 0 23#if 0
25FPU_REG const CONST_2 = MAKE_REG(POS, 1, 0x00000000, 0x80000000); 24FPU_REG const CONST_2 = MAKE_REG(POS, 1, 0x00000000, 0x80000000);
26FPU_REG const CONST_HALF = MAKE_REG(POS, -1, 0x00000000, 0x80000000); 25FPU_REG const CONST_HALF = MAKE_REG(POS, -1, 0x00000000, 0x80000000);
27#endif /* 0 */ 26#endif /* 0 */
28static FPU_REG const CONST_L2T = MAKE_REG(POS, 1, 0xcd1b8afe, 0xd49a784b); 27static FPU_REG const CONST_L2T = MAKE_REG(POS, 1, 0xcd1b8afe, 0xd49a784b);
29static FPU_REG const CONST_L2E = MAKE_REG(POS, 0, 0x5c17f0bc, 0xb8aa3b29); 28static FPU_REG const CONST_L2E = MAKE_REG(POS, 0, 0x5c17f0bc, 0xb8aa3b29);
30FPU_REG const CONST_PI = MAKE_REG(POS, 1, 0x2168c235, 0xc90fdaa2); 29FPU_REG const CONST_PI = MAKE_REG(POS, 1, 0x2168c235, 0xc90fdaa2);
31FPU_REG const CONST_PI2 = MAKE_REG(POS, 0, 0x2168c235, 0xc90fdaa2); 30FPU_REG const CONST_PI2 = MAKE_REG(POS, 0, 0x2168c235, 0xc90fdaa2);
32FPU_REG const CONST_PI4 = MAKE_REG(POS, -1, 0x2168c235, 0xc90fdaa2); 31FPU_REG const CONST_PI4 = MAKE_REG(POS, -1, 0x2168c235, 0xc90fdaa2);
33static FPU_REG const CONST_LG2 = MAKE_REG(POS, -2, 0xfbcff799, 0x9a209a84); 32static FPU_REG const CONST_LG2 = MAKE_REG(POS, -2, 0xfbcff799, 0x9a209a84);
34static FPU_REG const CONST_LN2 = MAKE_REG(POS, -1, 0xd1cf79ac, 0xb17217f7); 33static FPU_REG const CONST_LN2 = MAKE_REG(POS, -1, 0xd1cf79ac, 0xb17217f7);
35 34
36/* Extra bits to take pi/2 to more than 128 bits precision. */ 35/* Extra bits to take pi/2 to more than 128 bits precision. */
37FPU_REG const CONST_PI2extra = MAKE_REG(NEG, -66, 36FPU_REG const CONST_PI2extra = MAKE_REG(NEG, -66,
38 0xfc8f8cbb, 0xece675d1); 37 0xfc8f8cbb, 0xece675d1);
39 38
40/* Only the sign (and tag) is used in internal zeroes */ 39/* Only the sign (and tag) is used in internal zeroes */
41FPU_REG const CONST_Z = MAKE_REG(POS, EXP_UNDER, 0x0, 0x0); 40FPU_REG const CONST_Z = MAKE_REG(POS, EXP_UNDER, 0x0, 0x0);
42 41
43/* Only the sign and significand (and tag) are used in internal NaNs */ 42/* Only the sign and significand (and tag) are used in internal NaNs */
44/* The 80486 never generates one of these 43/* The 80486 never generates one of these
@@ -48,24 +47,22 @@ FPU_REG const CONST_SNAN = MAKE_REG(POS, EXP_OVER, 0x00000001, 0x80000000);
48FPU_REG const CONST_QNaN = MAKE_REG(NEG, EXP_OVER, 0x00000000, 0xC0000000); 47FPU_REG const CONST_QNaN = MAKE_REG(NEG, EXP_OVER, 0x00000000, 0xC0000000);
49 48
50/* Only the sign (and tag) is used in internal infinities */ 49/* Only the sign (and tag) is used in internal infinities */
51FPU_REG const CONST_INF = MAKE_REG(POS, EXP_OVER, 0x00000000, 0x80000000); 50FPU_REG const CONST_INF = MAKE_REG(POS, EXP_OVER, 0x00000000, 0x80000000);
52
53 51
54static void fld_const(FPU_REG const *c, int adj, u_char tag) 52static void fld_const(FPU_REG const *c, int adj, u_char tag)
55{ 53{
56 FPU_REG *st_new_ptr; 54 FPU_REG *st_new_ptr;
57 55
58 if ( STACK_OVERFLOW ) 56 if (STACK_OVERFLOW) {
59 { 57 FPU_stack_overflow();
60 FPU_stack_overflow(); 58 return;
61 return; 59 }
62 } 60 push();
63 push(); 61 reg_copy(c, st_new_ptr);
64 reg_copy(c, st_new_ptr); 62 st_new_ptr->sigl += adj; /* For all our fldxxx constants, we don't need to
65 st_new_ptr->sigl += adj; /* For all our fldxxx constants, we don't need to 63 borrow or carry. */
66 borrow or carry. */ 64 FPU_settag0(tag);
67 FPU_settag0(tag); 65 clear_C1();
68 clear_C1();
69} 66}
70 67
71/* A fast way to find out whether x is one of RC_DOWN or RC_CHOP 68/* A fast way to find out whether x is one of RC_DOWN or RC_CHOP
@@ -75,46 +72,46 @@ static void fld_const(FPU_REG const *c, int adj, u_char tag)
75 72
76static void fld1(int rc) 73static void fld1(int rc)
77{ 74{
78 fld_const(&CONST_1, 0, TAG_Valid); 75 fld_const(&CONST_1, 0, TAG_Valid);
79} 76}
80 77
81static void fldl2t(int rc) 78static void fldl2t(int rc)
82{ 79{
83 fld_const(&CONST_L2T, (rc == RC_UP) ? 1 : 0, TAG_Valid); 80 fld_const(&CONST_L2T, (rc == RC_UP) ? 1 : 0, TAG_Valid);
84} 81}
85 82
86static void fldl2e(int rc) 83static void fldl2e(int rc)
87{ 84{
88 fld_const(&CONST_L2E, DOWN_OR_CHOP(rc) ? -1 : 0, TAG_Valid); 85 fld_const(&CONST_L2E, DOWN_OR_CHOP(rc) ? -1 : 0, TAG_Valid);
89} 86}
90 87
91static void fldpi(int rc) 88static void fldpi(int rc)
92{ 89{
93 fld_const(&CONST_PI, DOWN_OR_CHOP(rc) ? -1 : 0, TAG_Valid); 90 fld_const(&CONST_PI, DOWN_OR_CHOP(rc) ? -1 : 0, TAG_Valid);
94} 91}
95 92
96static void fldlg2(int rc) 93static void fldlg2(int rc)
97{ 94{
98 fld_const(&CONST_LG2, DOWN_OR_CHOP(rc) ? -1 : 0, TAG_Valid); 95 fld_const(&CONST_LG2, DOWN_OR_CHOP(rc) ? -1 : 0, TAG_Valid);
99} 96}
100 97
101static void fldln2(int rc) 98static void fldln2(int rc)
102{ 99{
103 fld_const(&CONST_LN2, DOWN_OR_CHOP(rc) ? -1 : 0, TAG_Valid); 100 fld_const(&CONST_LN2, DOWN_OR_CHOP(rc) ? -1 : 0, TAG_Valid);
104} 101}
105 102
106static void fldz(int rc) 103static void fldz(int rc)
107{ 104{
108 fld_const(&CONST_Z, 0, TAG_Zero); 105 fld_const(&CONST_Z, 0, TAG_Zero);
109} 106}
110 107
111typedef void (*FUNC_RC)(int); 108typedef void (*FUNC_RC) (int);
112 109
113static FUNC_RC constants_table[] = { 110static FUNC_RC constants_table[] = {
114 fld1, fldl2t, fldl2e, fldpi, fldlg2, fldln2, fldz, (FUNC_RC)FPU_illegal 111 fld1, fldl2t, fldl2e, fldpi, fldlg2, fldln2, fldz, (FUNC_RC) FPU_illegal
115}; 112};
116 113
117void fconst(void) 114void fconst(void)
118{ 115{
119 (constants_table[FPU_rm])(control_word & CW_RC); 116 (constants_table[FPU_rm]) (control_word & CW_RC);
120} 117}
diff --git a/arch/x86/math-emu/reg_convert.c b/arch/x86/math-emu/reg_convert.c
index 45a258752703..afd31b31000d 100644
--- a/arch/x86/math-emu/reg_convert.c
+++ b/arch/x86/math-emu/reg_convert.c
@@ -13,41 +13,34 @@
13#include "exception.h" 13#include "exception.h"
14#include "fpu_emu.h" 14#include "fpu_emu.h"
15 15
16 16int FPU_to_exp16(FPU_REG const *a, FPU_REG * x)
17int FPU_to_exp16(FPU_REG const *a, FPU_REG *x)
18{ 17{
19 int sign = getsign(a); 18 int sign = getsign(a);
20 19
21 *(long long *)&(x->sigl) = *(const long long *)&(a->sigl); 20 *(long long *)&(x->sigl) = *(const long long *)&(a->sigl);
22 21
23 /* Set up the exponent as a 16 bit quantity. */ 22 /* Set up the exponent as a 16 bit quantity. */
24 setexponent16(x, exponent(a)); 23 setexponent16(x, exponent(a));
25 24
26 if ( exponent16(x) == EXP_UNDER ) 25 if (exponent16(x) == EXP_UNDER) {
27 { 26 /* The number is a de-normal or pseudodenormal. */
28 /* The number is a de-normal or pseudodenormal. */ 27 /* We only deal with the significand and exponent. */
29 /* We only deal with the significand and exponent. */ 28
30 29 if (x->sigh & 0x80000000) {
31 if (x->sigh & 0x80000000) 30 /* Is a pseudodenormal. */
32 { 31 /* This is non-80486 behaviour because the number
33 /* Is a pseudodenormal. */ 32 loses its 'denormal' identity. */
34 /* This is non-80486 behaviour because the number 33 addexponent(x, 1);
35 loses its 'denormal' identity. */ 34 } else {
36 addexponent(x, 1); 35 /* Is a denormal. */
37 } 36 addexponent(x, 1);
38 else 37 FPU_normalize_nuo(x);
39 { 38 }
40 /* Is a denormal. */
41 addexponent(x, 1);
42 FPU_normalize_nuo(x);
43 } 39 }
44 }
45 40
46 if ( !(x->sigh & 0x80000000) ) 41 if (!(x->sigh & 0x80000000)) {
47 { 42 EXCEPTION(EX_INTERNAL | 0x180);
48 EXCEPTION(EX_INTERNAL | 0x180); 43 }
49 }
50 44
51 return sign; 45 return sign;
52} 46}
53
diff --git a/arch/x86/math-emu/reg_divide.c b/arch/x86/math-emu/reg_divide.c
index 5cee7ff920d9..6827012db341 100644
--- a/arch/x86/math-emu/reg_divide.c
+++ b/arch/x86/math-emu/reg_divide.c
@@ -26,182 +26,157 @@
26 */ 26 */
27int FPU_div(int flags, int rm, int control_w) 27int FPU_div(int flags, int rm, int control_w)
28{ 28{
29 FPU_REG x, y; 29 FPU_REG x, y;
30 FPU_REG const *a, *b, *st0_ptr, *st_ptr; 30 FPU_REG const *a, *b, *st0_ptr, *st_ptr;
31 FPU_REG *dest; 31 FPU_REG *dest;
32 u_char taga, tagb, signa, signb, sign, saved_sign; 32 u_char taga, tagb, signa, signb, sign, saved_sign;
33 int tag, deststnr; 33 int tag, deststnr;
34 34
35 if ( flags & DEST_RM ) 35 if (flags & DEST_RM)
36 deststnr = rm; 36 deststnr = rm;
37 else 37 else
38 deststnr = 0; 38 deststnr = 0;
39 39
40 if ( flags & REV ) 40 if (flags & REV) {
41 { 41 b = &st(0);
42 b = &st(0); 42 st0_ptr = b;
43 st0_ptr = b; 43 tagb = FPU_gettag0();
44 tagb = FPU_gettag0(); 44 if (flags & LOADED) {
45 if ( flags & LOADED ) 45 a = (FPU_REG *) rm;
46 { 46 taga = flags & 0x0f;
47 a = (FPU_REG *)rm; 47 } else {
48 taga = flags & 0x0f; 48 a = &st(rm);
49 st_ptr = a;
50 taga = FPU_gettagi(rm);
51 }
52 } else {
53 a = &st(0);
54 st0_ptr = a;
55 taga = FPU_gettag0();
56 if (flags & LOADED) {
57 b = (FPU_REG *) rm;
58 tagb = flags & 0x0f;
59 } else {
60 b = &st(rm);
61 st_ptr = b;
62 tagb = FPU_gettagi(rm);
63 }
49 } 64 }
50 else
51 {
52 a = &st(rm);
53 st_ptr = a;
54 taga = FPU_gettagi(rm);
55 }
56 }
57 else
58 {
59 a = &st(0);
60 st0_ptr = a;
61 taga = FPU_gettag0();
62 if ( flags & LOADED )
63 {
64 b = (FPU_REG *)rm;
65 tagb = flags & 0x0f;
66 }
67 else
68 {
69 b = &st(rm);
70 st_ptr = b;
71 tagb = FPU_gettagi(rm);
72 }
73 }
74 65
75 signa = getsign(a); 66 signa = getsign(a);
76 signb = getsign(b); 67 signb = getsign(b);
77 68
78 sign = signa ^ signb; 69 sign = signa ^ signb;
79 70
80 dest = &st(deststnr); 71 dest = &st(deststnr);
81 saved_sign = getsign(dest); 72 saved_sign = getsign(dest);
82 73
83 if ( !(taga | tagb) ) 74 if (!(taga | tagb)) {
84 { 75 /* Both regs Valid, this should be the most common case. */
85 /* Both regs Valid, this should be the most common case. */ 76 reg_copy(a, &x);
86 reg_copy(a, &x); 77 reg_copy(b, &y);
87 reg_copy(b, &y); 78 setpositive(&x);
88 setpositive(&x); 79 setpositive(&y);
89 setpositive(&y); 80 tag = FPU_u_div(&x, &y, dest, control_w, sign);
90 tag = FPU_u_div(&x, &y, dest, control_w, sign);
91 81
92 if ( tag < 0 ) 82 if (tag < 0)
93 return tag; 83 return tag;
94 84
95 FPU_settagi(deststnr, tag); 85 FPU_settagi(deststnr, tag);
96 return tag; 86 return tag;
97 } 87 }
98 88
99 if ( taga == TAG_Special ) 89 if (taga == TAG_Special)
100 taga = FPU_Special(a); 90 taga = FPU_Special(a);
101 if ( tagb == TAG_Special ) 91 if (tagb == TAG_Special)
102 tagb = FPU_Special(b); 92 tagb = FPU_Special(b);
103 93
104 if ( ((taga == TAG_Valid) && (tagb == TW_Denormal)) 94 if (((taga == TAG_Valid) && (tagb == TW_Denormal))
105 || ((taga == TW_Denormal) && (tagb == TAG_Valid)) 95 || ((taga == TW_Denormal) && (tagb == TAG_Valid))
106 || ((taga == TW_Denormal) && (tagb == TW_Denormal)) ) 96 || ((taga == TW_Denormal) && (tagb == TW_Denormal))) {
107 { 97 if (denormal_operand() < 0)
108 if ( denormal_operand() < 0 ) 98 return FPU_Exception;
109 return FPU_Exception; 99
110 100 FPU_to_exp16(a, &x);
111 FPU_to_exp16(a, &x); 101 FPU_to_exp16(b, &y);
112 FPU_to_exp16(b, &y); 102 tag = FPU_u_div(&x, &y, dest, control_w, sign);
113 tag = FPU_u_div(&x, &y, dest, control_w, sign); 103 if (tag < 0)
114 if ( tag < 0 ) 104 return tag;
115 return tag; 105
116 106 FPU_settagi(deststnr, tag);
117 FPU_settagi(deststnr, tag); 107 return tag;
118 return tag; 108 } else if ((taga <= TW_Denormal) && (tagb <= TW_Denormal)) {
119 } 109 if (tagb != TAG_Zero) {
120 else if ( (taga <= TW_Denormal) && (tagb <= TW_Denormal) ) 110 /* Want to find Zero/Valid */
121 { 111 if (tagb == TW_Denormal) {
122 if ( tagb != TAG_Zero ) 112 if (denormal_operand() < 0)
123 { 113 return FPU_Exception;
124 /* Want to find Zero/Valid */ 114 }
125 if ( tagb == TW_Denormal ) 115
126 { 116 /* The result is zero. */
127 if ( denormal_operand() < 0 ) 117 FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
128 return FPU_Exception; 118 setsign(dest, sign);
129 } 119 return TAG_Zero;
130 120 }
131 /* The result is zero. */ 121 /* We have an exception condition, either 0/0 or Valid/Zero. */
132 FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr); 122 if (taga == TAG_Zero) {
133 setsign(dest, sign); 123 /* 0/0 */
134 return TAG_Zero; 124 return arith_invalid(deststnr);
125 }
126 /* Valid/Zero */
127 return FPU_divide_by_zero(deststnr, sign);
135 } 128 }
136 /* We have an exception condition, either 0/0 or Valid/Zero. */ 129 /* Must have infinities, NaNs, etc */
137 if ( taga == TAG_Zero ) 130 else if ((taga == TW_NaN) || (tagb == TW_NaN)) {
138 { 131 if (flags & LOADED)
139 /* 0/0 */ 132 return real_2op_NaN((FPU_REG *) rm, flags & 0x0f, 0,
140 return arith_invalid(deststnr); 133 st0_ptr);
134
135 if (flags & DEST_RM) {
136 int tag;
137 tag = FPU_gettag0();
138 if (tag == TAG_Special)
139 tag = FPU_Special(st0_ptr);
140 return real_2op_NaN(st0_ptr, tag, rm,
141 (flags & REV) ? st0_ptr : &st(rm));
142 } else {
143 int tag;
144 tag = FPU_gettagi(rm);
145 if (tag == TAG_Special)
146 tag = FPU_Special(&st(rm));
147 return real_2op_NaN(&st(rm), tag, 0,
148 (flags & REV) ? st0_ptr : &st(rm));
149 }
150 } else if (taga == TW_Infinity) {
151 if (tagb == TW_Infinity) {
152 /* infinity/infinity */
153 return arith_invalid(deststnr);
154 } else {
155 /* tagb must be Valid or Zero */
156 if ((tagb == TW_Denormal) && (denormal_operand() < 0))
157 return FPU_Exception;
158
159 /* Infinity divided by Zero or Valid does
160 not raise and exception, but returns Infinity */
161 FPU_copy_to_regi(a, TAG_Special, deststnr);
162 setsign(dest, sign);
163 return taga;
164 }
165 } else if (tagb == TW_Infinity) {
166 if ((taga == TW_Denormal) && (denormal_operand() < 0))
167 return FPU_Exception;
168
169 /* The result is zero. */
170 FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
171 setsign(dest, sign);
172 return TAG_Zero;
141 } 173 }
142 /* Valid/Zero */
143 return FPU_divide_by_zero(deststnr, sign);
144 }
145 /* Must have infinities, NaNs, etc */
146 else if ( (taga == TW_NaN) || (tagb == TW_NaN) )
147 {
148 if ( flags & LOADED )
149 return real_2op_NaN((FPU_REG *)rm, flags & 0x0f, 0, st0_ptr);
150
151 if ( flags & DEST_RM )
152 {
153 int tag;
154 tag = FPU_gettag0();
155 if ( tag == TAG_Special )
156 tag = FPU_Special(st0_ptr);
157 return real_2op_NaN(st0_ptr, tag, rm, (flags & REV) ? st0_ptr : &st(rm));
158 }
159 else
160 {
161 int tag;
162 tag = FPU_gettagi(rm);
163 if ( tag == TAG_Special )
164 tag = FPU_Special(&st(rm));
165 return real_2op_NaN(&st(rm), tag, 0, (flags & REV) ? st0_ptr : &st(rm));
166 }
167 }
168 else if (taga == TW_Infinity)
169 {
170 if (tagb == TW_Infinity)
171 {
172 /* infinity/infinity */
173 return arith_invalid(deststnr);
174 }
175 else
176 {
177 /* tagb must be Valid or Zero */
178 if ( (tagb == TW_Denormal) && (denormal_operand() < 0) )
179 return FPU_Exception;
180
181 /* Infinity divided by Zero or Valid does
182 not raise and exception, but returns Infinity */
183 FPU_copy_to_regi(a, TAG_Special, deststnr);
184 setsign(dest, sign);
185 return taga;
186 }
187 }
188 else if (tagb == TW_Infinity)
189 {
190 if ( (taga == TW_Denormal) && (denormal_operand() < 0) )
191 return FPU_Exception;
192
193 /* The result is zero. */
194 FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
195 setsign(dest, sign);
196 return TAG_Zero;
197 }
198#ifdef PARANOID 174#ifdef PARANOID
199 else 175 else {
200 { 176 EXCEPTION(EX_INTERNAL | 0x102);
201 EXCEPTION(EX_INTERNAL|0x102); 177 return FPU_Exception;
202 return FPU_Exception; 178 }
203 } 179#endif /* PARANOID */
204#endif /* PARANOID */
205 180
206 return 0; 181 return 0;
207} 182}
diff --git a/arch/x86/math-emu/reg_ld_str.c b/arch/x86/math-emu/reg_ld_str.c
index e976caef6498..0b2ca8dc2988 100644
--- a/arch/x86/math-emu/reg_ld_str.c
+++ b/arch/x86/math-emu/reg_ld_str.c
@@ -27,1084 +27,938 @@
27#include "control_w.h" 27#include "control_w.h"
28#include "status_w.h" 28#include "status_w.h"
29 29
30 30#define DOUBLE_Emax 1023 /* largest valid exponent */
31#define DOUBLE_Emax 1023 /* largest valid exponent */
32#define DOUBLE_Ebias 1023 31#define DOUBLE_Ebias 1023
33#define DOUBLE_Emin (-1022) /* smallest valid exponent */ 32#define DOUBLE_Emin (-1022) /* smallest valid exponent */
34 33
35#define SINGLE_Emax 127 /* largest valid exponent */ 34#define SINGLE_Emax 127 /* largest valid exponent */
36#define SINGLE_Ebias 127 35#define SINGLE_Ebias 127
37#define SINGLE_Emin (-126) /* smallest valid exponent */ 36#define SINGLE_Emin (-126) /* smallest valid exponent */
38
39 37
40static u_char normalize_no_excep(FPU_REG *r, int exp, int sign) 38static u_char normalize_no_excep(FPU_REG * r, int exp, int sign)
41{ 39{
42 u_char tag; 40 u_char tag;
43 41
44 setexponent16(r, exp); 42 setexponent16(r, exp);
45 43
46 tag = FPU_normalize_nuo(r); 44 tag = FPU_normalize_nuo(r);
47 stdexp(r); 45 stdexp(r);
48 if ( sign ) 46 if (sign)
49 setnegative(r); 47 setnegative(r);
50 48
51 return tag; 49 return tag;
52} 50}
53 51
54 52int FPU_tagof(FPU_REG * ptr)
55int FPU_tagof(FPU_REG *ptr)
56{ 53{
57 int exp; 54 int exp;
58 55
59 exp = exponent16(ptr) & 0x7fff; 56 exp = exponent16(ptr) & 0x7fff;
60 if ( exp == 0 ) 57 if (exp == 0) {
61 { 58 if (!(ptr->sigh | ptr->sigl)) {
62 if ( !(ptr->sigh | ptr->sigl) ) 59 return TAG_Zero;
63 { 60 }
64 return TAG_Zero; 61 /* The number is a de-normal or pseudodenormal. */
62 return TAG_Special;
63 }
64
65 if (exp == 0x7fff) {
66 /* Is an Infinity, a NaN, or an unsupported data type. */
67 return TAG_Special;
65 } 68 }
66 /* The number is a de-normal or pseudodenormal. */
67 return TAG_Special;
68 }
69
70 if ( exp == 0x7fff )
71 {
72 /* Is an Infinity, a NaN, or an unsupported data type. */
73 return TAG_Special;
74 }
75
76 if ( !(ptr->sigh & 0x80000000) )
77 {
78 /* Unsupported data type. */
79 /* Valid numbers have the ms bit set to 1. */
80 /* Unnormal. */
81 return TAG_Special;
82 }
83
84 return TAG_Valid;
85}
86 69
70 if (!(ptr->sigh & 0x80000000)) {
71 /* Unsupported data type. */
72 /* Valid numbers have the ms bit set to 1. */
73 /* Unnormal. */
74 return TAG_Special;
75 }
76
77 return TAG_Valid;
78}
87 79
88/* Get a long double from user memory */ 80/* Get a long double from user memory */
89int FPU_load_extended(long double __user *s, int stnr) 81int FPU_load_extended(long double __user * s, int stnr)
90{ 82{
91 FPU_REG *sti_ptr = &st(stnr); 83 FPU_REG *sti_ptr = &st(stnr);
92 84
93 RE_ENTRANT_CHECK_OFF; 85 RE_ENTRANT_CHECK_OFF;
94 FPU_access_ok(VERIFY_READ, s, 10); 86 FPU_access_ok(VERIFY_READ, s, 10);
95 __copy_from_user(sti_ptr, s, 10); 87 __copy_from_user(sti_ptr, s, 10);
96 RE_ENTRANT_CHECK_ON; 88 RE_ENTRANT_CHECK_ON;
97 89
98 return FPU_tagof(sti_ptr); 90 return FPU_tagof(sti_ptr);
99} 91}
100 92
101
102/* Get a double from user memory */ 93/* Get a double from user memory */
103int FPU_load_double(double __user *dfloat, FPU_REG *loaded_data) 94int FPU_load_double(double __user * dfloat, FPU_REG * loaded_data)
104{ 95{
105 int exp, tag, negative; 96 int exp, tag, negative;
106 unsigned m64, l64; 97 unsigned m64, l64;
107 98
108 RE_ENTRANT_CHECK_OFF; 99 RE_ENTRANT_CHECK_OFF;
109 FPU_access_ok(VERIFY_READ, dfloat, 8); 100 FPU_access_ok(VERIFY_READ, dfloat, 8);
110 FPU_get_user(m64, 1 + (unsigned long __user *) dfloat); 101 FPU_get_user(m64, 1 + (unsigned long __user *)dfloat);
111 FPU_get_user(l64, (unsigned long __user *) dfloat); 102 FPU_get_user(l64, (unsigned long __user *)dfloat);
112 RE_ENTRANT_CHECK_ON; 103 RE_ENTRANT_CHECK_ON;
113 104
114 negative = (m64 & 0x80000000) ? SIGN_Negative : SIGN_Positive; 105 negative = (m64 & 0x80000000) ? SIGN_Negative : SIGN_Positive;
115 exp = ((m64 & 0x7ff00000) >> 20) - DOUBLE_Ebias + EXTENDED_Ebias; 106 exp = ((m64 & 0x7ff00000) >> 20) - DOUBLE_Ebias + EXTENDED_Ebias;
116 m64 &= 0xfffff; 107 m64 &= 0xfffff;
117 if ( exp > DOUBLE_Emax + EXTENDED_Ebias ) 108 if (exp > DOUBLE_Emax + EXTENDED_Ebias) {
118 { 109 /* Infinity or NaN */
119 /* Infinity or NaN */ 110 if ((m64 == 0) && (l64 == 0)) {
120 if ((m64 == 0) && (l64 == 0)) 111 /* +- infinity */
121 { 112 loaded_data->sigh = 0x80000000;
122 /* +- infinity */ 113 loaded_data->sigl = 0x00000000;
123 loaded_data->sigh = 0x80000000; 114 exp = EXP_Infinity + EXTENDED_Ebias;
124 loaded_data->sigl = 0x00000000; 115 tag = TAG_Special;
125 exp = EXP_Infinity + EXTENDED_Ebias; 116 } else {
126 tag = TAG_Special; 117 /* Must be a signaling or quiet NaN */
127 } 118 exp = EXP_NaN + EXTENDED_Ebias;
128 else 119 loaded_data->sigh = (m64 << 11) | 0x80000000;
129 { 120 loaded_data->sigh |= l64 >> 21;
130 /* Must be a signaling or quiet NaN */ 121 loaded_data->sigl = l64 << 11;
131 exp = EXP_NaN + EXTENDED_Ebias; 122 tag = TAG_Special; /* The calling function must look for NaNs */
132 loaded_data->sigh = (m64 << 11) | 0x80000000; 123 }
133 loaded_data->sigh |= l64 >> 21; 124 } else if (exp < DOUBLE_Emin + EXTENDED_Ebias) {
134 loaded_data->sigl = l64 << 11; 125 /* Zero or de-normal */
135 tag = TAG_Special; /* The calling function must look for NaNs */ 126 if ((m64 == 0) && (l64 == 0)) {
136 } 127 /* Zero */
137 } 128 reg_copy(&CONST_Z, loaded_data);
138 else if ( exp < DOUBLE_Emin + EXTENDED_Ebias ) 129 exp = 0;
139 { 130 tag = TAG_Zero;
140 /* Zero or de-normal */ 131 } else {
141 if ((m64 == 0) && (l64 == 0)) 132 /* De-normal */
142 { 133 loaded_data->sigh = m64 << 11;
143 /* Zero */ 134 loaded_data->sigh |= l64 >> 21;
144 reg_copy(&CONST_Z, loaded_data); 135 loaded_data->sigl = l64 << 11;
145 exp = 0; 136
146 tag = TAG_Zero; 137 return normalize_no_excep(loaded_data, DOUBLE_Emin,
147 } 138 negative)
148 else 139 | (denormal_operand() < 0 ? FPU_Exception : 0);
149 { 140 }
150 /* De-normal */ 141 } else {
151 loaded_data->sigh = m64 << 11; 142 loaded_data->sigh = (m64 << 11) | 0x80000000;
152 loaded_data->sigh |= l64 >> 21; 143 loaded_data->sigh |= l64 >> 21;
153 loaded_data->sigl = l64 << 11; 144 loaded_data->sigl = l64 << 11;
154
155 return normalize_no_excep(loaded_data, DOUBLE_Emin, negative)
156 | (denormal_operand() < 0 ? FPU_Exception : 0);
157 }
158 }
159 else
160 {
161 loaded_data->sigh = (m64 << 11) | 0x80000000;
162 loaded_data->sigh |= l64 >> 21;
163 loaded_data->sigl = l64 << 11;
164 145
165 tag = TAG_Valid; 146 tag = TAG_Valid;
166 } 147 }
167 148
168 setexponent16(loaded_data, exp | negative); 149 setexponent16(loaded_data, exp | negative);
169 150
170 return tag; 151 return tag;
171} 152}
172 153
173
174/* Get a float from user memory */ 154/* Get a float from user memory */
175int FPU_load_single(float __user *single, FPU_REG *loaded_data) 155int FPU_load_single(float __user * single, FPU_REG * loaded_data)
176{ 156{
177 unsigned m32; 157 unsigned m32;
178 int exp, tag, negative; 158 int exp, tag, negative;
179 159
180 RE_ENTRANT_CHECK_OFF; 160 RE_ENTRANT_CHECK_OFF;
181 FPU_access_ok(VERIFY_READ, single, 4); 161 FPU_access_ok(VERIFY_READ, single, 4);
182 FPU_get_user(m32, (unsigned long __user *) single); 162 FPU_get_user(m32, (unsigned long __user *)single);
183 RE_ENTRANT_CHECK_ON; 163 RE_ENTRANT_CHECK_ON;
184 164
185 negative = (m32 & 0x80000000) ? SIGN_Negative : SIGN_Positive; 165 negative = (m32 & 0x80000000) ? SIGN_Negative : SIGN_Positive;
186 166
187 if (!(m32 & 0x7fffffff)) 167 if (!(m32 & 0x7fffffff)) {
188 { 168 /* Zero */
189 /* Zero */ 169 reg_copy(&CONST_Z, loaded_data);
190 reg_copy(&CONST_Z, loaded_data); 170 addexponent(loaded_data, negative);
191 addexponent(loaded_data, negative); 171 return TAG_Zero;
192 return TAG_Zero;
193 }
194 exp = ((m32 & 0x7f800000) >> 23) - SINGLE_Ebias + EXTENDED_Ebias;
195 m32 = (m32 & 0x7fffff) << 8;
196 if ( exp < SINGLE_Emin + EXTENDED_Ebias )
197 {
198 /* De-normals */
199 loaded_data->sigh = m32;
200 loaded_data->sigl = 0;
201
202 return normalize_no_excep(loaded_data, SINGLE_Emin, negative)
203 | (denormal_operand() < 0 ? FPU_Exception : 0);
204 }
205 else if ( exp > SINGLE_Emax + EXTENDED_Ebias )
206 {
207 /* Infinity or NaN */
208 if ( m32 == 0 )
209 {
210 /* +- infinity */
211 loaded_data->sigh = 0x80000000;
212 loaded_data->sigl = 0x00000000;
213 exp = EXP_Infinity + EXTENDED_Ebias;
214 tag = TAG_Special;
215 } 172 }
216 else 173 exp = ((m32 & 0x7f800000) >> 23) - SINGLE_Ebias + EXTENDED_Ebias;
217 { 174 m32 = (m32 & 0x7fffff) << 8;
218 /* Must be a signaling or quiet NaN */ 175 if (exp < SINGLE_Emin + EXTENDED_Ebias) {
219 exp = EXP_NaN + EXTENDED_Ebias; 176 /* De-normals */
220 loaded_data->sigh = m32 | 0x80000000; 177 loaded_data->sigh = m32;
221 loaded_data->sigl = 0; 178 loaded_data->sigl = 0;
222 tag = TAG_Special; /* The calling function must look for NaNs */ 179
180 return normalize_no_excep(loaded_data, SINGLE_Emin, negative)
181 | (denormal_operand() < 0 ? FPU_Exception : 0);
182 } else if (exp > SINGLE_Emax + EXTENDED_Ebias) {
183 /* Infinity or NaN */
184 if (m32 == 0) {
185 /* +- infinity */
186 loaded_data->sigh = 0x80000000;
187 loaded_data->sigl = 0x00000000;
188 exp = EXP_Infinity + EXTENDED_Ebias;
189 tag = TAG_Special;
190 } else {
191 /* Must be a signaling or quiet NaN */
192 exp = EXP_NaN + EXTENDED_Ebias;
193 loaded_data->sigh = m32 | 0x80000000;
194 loaded_data->sigl = 0;
195 tag = TAG_Special; /* The calling function must look for NaNs */
196 }
197 } else {
198 loaded_data->sigh = m32 | 0x80000000;
199 loaded_data->sigl = 0;
200 tag = TAG_Valid;
223 } 201 }
224 }
225 else
226 {
227 loaded_data->sigh = m32 | 0x80000000;
228 loaded_data->sigl = 0;
229 tag = TAG_Valid;
230 }
231 202
232 setexponent16(loaded_data, exp | negative); /* Set the sign. */ 203 setexponent16(loaded_data, exp | negative); /* Set the sign. */
233 204
234 return tag; 205 return tag;
235} 206}
236 207
237
238/* Get a long long from user memory */ 208/* Get a long long from user memory */
239int FPU_load_int64(long long __user *_s) 209int FPU_load_int64(long long __user * _s)
240{ 210{
241 long long s; 211 long long s;
242 int sign; 212 int sign;
243 FPU_REG *st0_ptr = &st(0); 213 FPU_REG *st0_ptr = &st(0);
244 214
245 RE_ENTRANT_CHECK_OFF; 215 RE_ENTRANT_CHECK_OFF;
246 FPU_access_ok(VERIFY_READ, _s, 8); 216 FPU_access_ok(VERIFY_READ, _s, 8);
247 if (copy_from_user(&s,_s,8)) 217 if (copy_from_user(&s, _s, 8))
248 FPU_abort; 218 FPU_abort;
249 RE_ENTRANT_CHECK_ON; 219 RE_ENTRANT_CHECK_ON;
250 220
251 if (s == 0) 221 if (s == 0) {
252 { 222 reg_copy(&CONST_Z, st0_ptr);
253 reg_copy(&CONST_Z, st0_ptr); 223 return TAG_Zero;
254 return TAG_Zero; 224 }
255 } 225
256 226 if (s > 0)
257 if (s > 0) 227 sign = SIGN_Positive;
258 sign = SIGN_Positive; 228 else {
259 else 229 s = -s;
260 { 230 sign = SIGN_Negative;
261 s = -s; 231 }
262 sign = SIGN_Negative;
263 }
264
265 significand(st0_ptr) = s;
266
267 return normalize_no_excep(st0_ptr, 63, sign);
268}
269 232
233 significand(st0_ptr) = s;
234
235 return normalize_no_excep(st0_ptr, 63, sign);
236}
270 237
271/* Get a long from user memory */ 238/* Get a long from user memory */
272int FPU_load_int32(long __user *_s, FPU_REG *loaded_data) 239int FPU_load_int32(long __user * _s, FPU_REG * loaded_data)
273{ 240{
274 long s; 241 long s;
275 int negative; 242 int negative;
276 243
277 RE_ENTRANT_CHECK_OFF; 244 RE_ENTRANT_CHECK_OFF;
278 FPU_access_ok(VERIFY_READ, _s, 4); 245 FPU_access_ok(VERIFY_READ, _s, 4);
279 FPU_get_user(s, _s); 246 FPU_get_user(s, _s);
280 RE_ENTRANT_CHECK_ON; 247 RE_ENTRANT_CHECK_ON;
281 248
282 if (s == 0) 249 if (s == 0) {
283 { reg_copy(&CONST_Z, loaded_data); return TAG_Zero; } 250 reg_copy(&CONST_Z, loaded_data);
251 return TAG_Zero;
252 }
284 253
285 if (s > 0) 254 if (s > 0)
286 negative = SIGN_Positive; 255 negative = SIGN_Positive;
287 else 256 else {
288 { 257 s = -s;
289 s = -s; 258 negative = SIGN_Negative;
290 negative = SIGN_Negative; 259 }
291 }
292 260
293 loaded_data->sigh = s; 261 loaded_data->sigh = s;
294 loaded_data->sigl = 0; 262 loaded_data->sigl = 0;
295 263
296 return normalize_no_excep(loaded_data, 31, negative); 264 return normalize_no_excep(loaded_data, 31, negative);
297} 265}
298 266
299
300/* Get a short from user memory */ 267/* Get a short from user memory */
301int FPU_load_int16(short __user *_s, FPU_REG *loaded_data) 268int FPU_load_int16(short __user * _s, FPU_REG * loaded_data)
302{ 269{
303 int s, negative; 270 int s, negative;
304 271
305 RE_ENTRANT_CHECK_OFF; 272 RE_ENTRANT_CHECK_OFF;
306 FPU_access_ok(VERIFY_READ, _s, 2); 273 FPU_access_ok(VERIFY_READ, _s, 2);
307 /* Cast as short to get the sign extended. */ 274 /* Cast as short to get the sign extended. */
308 FPU_get_user(s, _s); 275 FPU_get_user(s, _s);
309 RE_ENTRANT_CHECK_ON; 276 RE_ENTRANT_CHECK_ON;
310 277
311 if (s == 0) 278 if (s == 0) {
312 { reg_copy(&CONST_Z, loaded_data); return TAG_Zero; } 279 reg_copy(&CONST_Z, loaded_data);
280 return TAG_Zero;
281 }
313 282
314 if (s > 0) 283 if (s > 0)
315 negative = SIGN_Positive; 284 negative = SIGN_Positive;
316 else 285 else {
317 { 286 s = -s;
318 s = -s; 287 negative = SIGN_Negative;
319 negative = SIGN_Negative; 288 }
320 }
321 289
322 loaded_data->sigh = s << 16; 290 loaded_data->sigh = s << 16;
323 loaded_data->sigl = 0; 291 loaded_data->sigl = 0;
324 292
325 return normalize_no_excep(loaded_data, 15, negative); 293 return normalize_no_excep(loaded_data, 15, negative);
326} 294}
327 295
328
329/* Get a packed bcd array from user memory */ 296/* Get a packed bcd array from user memory */
330int FPU_load_bcd(u_char __user *s) 297int FPU_load_bcd(u_char __user * s)
331{ 298{
332 FPU_REG *st0_ptr = &st(0); 299 FPU_REG *st0_ptr = &st(0);
333 int pos; 300 int pos;
334 u_char bcd; 301 u_char bcd;
335 long long l=0; 302 long long l = 0;
336 int sign; 303 int sign;
337 304
338 RE_ENTRANT_CHECK_OFF; 305 RE_ENTRANT_CHECK_OFF;
339 FPU_access_ok(VERIFY_READ, s, 10); 306 FPU_access_ok(VERIFY_READ, s, 10);
340 RE_ENTRANT_CHECK_ON; 307 RE_ENTRANT_CHECK_ON;
341 for ( pos = 8; pos >= 0; pos--) 308 for (pos = 8; pos >= 0; pos--) {
342 { 309 l *= 10;
343 l *= 10; 310 RE_ENTRANT_CHECK_OFF;
344 RE_ENTRANT_CHECK_OFF; 311 FPU_get_user(bcd, s + pos);
345 FPU_get_user(bcd, s+pos); 312 RE_ENTRANT_CHECK_ON;
346 RE_ENTRANT_CHECK_ON; 313 l += bcd >> 4;
347 l += bcd >> 4; 314 l *= 10;
348 l *= 10; 315 l += bcd & 0x0f;
349 l += bcd & 0x0f; 316 }
350 } 317
351 318 RE_ENTRANT_CHECK_OFF;
352 RE_ENTRANT_CHECK_OFF; 319 FPU_get_user(sign, s + 9);
353 FPU_get_user(sign, s+9); 320 sign = sign & 0x80 ? SIGN_Negative : SIGN_Positive;
354 sign = sign & 0x80 ? SIGN_Negative : SIGN_Positive; 321 RE_ENTRANT_CHECK_ON;
355 RE_ENTRANT_CHECK_ON; 322
356 323 if (l == 0) {
357 if ( l == 0 ) 324 reg_copy(&CONST_Z, st0_ptr);
358 { 325 addexponent(st0_ptr, sign); /* Set the sign. */
359 reg_copy(&CONST_Z, st0_ptr); 326 return TAG_Zero;
360 addexponent(st0_ptr, sign); /* Set the sign. */ 327 } else {
361 return TAG_Zero; 328 significand(st0_ptr) = l;
362 } 329 return normalize_no_excep(st0_ptr, 63, sign);
363 else 330 }
364 {
365 significand(st0_ptr) = l;
366 return normalize_no_excep(st0_ptr, 63, sign);
367 }
368} 331}
369 332
370/*===========================================================================*/ 333/*===========================================================================*/
371 334
372/* Put a long double into user memory */ 335/* Put a long double into user memory */
373int FPU_store_extended(FPU_REG *st0_ptr, u_char st0_tag, long double __user *d) 336int FPU_store_extended(FPU_REG * st0_ptr, u_char st0_tag,
337 long double __user * d)
374{ 338{
375 /* 339 /*
376 The only exception raised by an attempt to store to an 340 The only exception raised by an attempt to store to an
377 extended format is the Invalid Stack exception, i.e. 341 extended format is the Invalid Stack exception, i.e.
378 attempting to store from an empty register. 342 attempting to store from an empty register.
379 */ 343 */
380 344
381 if ( st0_tag != TAG_Empty ) 345 if (st0_tag != TAG_Empty) {
382 { 346 RE_ENTRANT_CHECK_OFF;
383 RE_ENTRANT_CHECK_OFF; 347 FPU_access_ok(VERIFY_WRITE, d, 10);
384 FPU_access_ok(VERIFY_WRITE, d, 10); 348
385 349 FPU_put_user(st0_ptr->sigl, (unsigned long __user *)d);
386 FPU_put_user(st0_ptr->sigl, (unsigned long __user *) d); 350 FPU_put_user(st0_ptr->sigh,
387 FPU_put_user(st0_ptr->sigh, (unsigned long __user *) ((u_char __user *)d + 4)); 351 (unsigned long __user *)((u_char __user *) d + 4));
388 FPU_put_user(exponent16(st0_ptr), (unsigned short __user *) ((u_char __user *)d + 8)); 352 FPU_put_user(exponent16(st0_ptr),
389 RE_ENTRANT_CHECK_ON; 353 (unsigned short __user *)((u_char __user *) d +
390 354 8));
391 return 1; 355 RE_ENTRANT_CHECK_ON;
392 } 356
393 357 return 1;
394 /* Empty register (stack underflow) */ 358 }
395 EXCEPTION(EX_StackUnder);
396 if ( control_word & CW_Invalid )
397 {
398 /* The masked response */
399 /* Put out the QNaN indefinite */
400 RE_ENTRANT_CHECK_OFF;
401 FPU_access_ok(VERIFY_WRITE,d,10);
402 FPU_put_user(0, (unsigned long __user *) d);
403 FPU_put_user(0xc0000000, 1 + (unsigned long __user *) d);
404 FPU_put_user(0xffff, 4 + (short __user *) d);
405 RE_ENTRANT_CHECK_ON;
406 return 1;
407 }
408 else
409 return 0;
410 359
411} 360 /* Empty register (stack underflow) */
361 EXCEPTION(EX_StackUnder);
362 if (control_word & CW_Invalid) {
363 /* The masked response */
364 /* Put out the QNaN indefinite */
365 RE_ENTRANT_CHECK_OFF;
366 FPU_access_ok(VERIFY_WRITE, d, 10);
367 FPU_put_user(0, (unsigned long __user *)d);
368 FPU_put_user(0xc0000000, 1 + (unsigned long __user *)d);
369 FPU_put_user(0xffff, 4 + (short __user *)d);
370 RE_ENTRANT_CHECK_ON;
371 return 1;
372 } else
373 return 0;
412 374
375}
413 376
414/* Put a double into user memory */ 377/* Put a double into user memory */
415int FPU_store_double(FPU_REG *st0_ptr, u_char st0_tag, double __user *dfloat) 378int FPU_store_double(FPU_REG * st0_ptr, u_char st0_tag, double __user * dfloat)
416{ 379{
417 unsigned long l[2]; 380 unsigned long l[2];
418 unsigned long increment = 0; /* avoid gcc warnings */ 381 unsigned long increment = 0; /* avoid gcc warnings */
419 int precision_loss; 382 int precision_loss;
420 int exp; 383 int exp;
421 FPU_REG tmp; 384 FPU_REG tmp;
422 385
423 if ( st0_tag == TAG_Valid ) 386 if (st0_tag == TAG_Valid) {
424 { 387 reg_copy(st0_ptr, &tmp);
425 reg_copy(st0_ptr, &tmp); 388 exp = exponent(&tmp);
426 exp = exponent(&tmp);
427 389
428 if ( exp < DOUBLE_Emin ) /* It may be a denormal */ 390 if (exp < DOUBLE_Emin) { /* It may be a denormal */
429 { 391 addexponent(&tmp, -DOUBLE_Emin + 52); /* largest exp to be 51 */
430 addexponent(&tmp, -DOUBLE_Emin + 52); /* largest exp to be 51 */
431 392
432 denormal_arg: 393 denormal_arg:
433 394
434 if ( (precision_loss = FPU_round_to_int(&tmp, st0_tag)) ) 395 if ((precision_loss = FPU_round_to_int(&tmp, st0_tag))) {
435 {
436#ifdef PECULIAR_486 396#ifdef PECULIAR_486
437 /* Did it round to a non-denormal ? */ 397 /* Did it round to a non-denormal ? */
438 /* This behaviour might be regarded as peculiar, it appears 398 /* This behaviour might be regarded as peculiar, it appears
439 that the 80486 rounds to the dest precision, then 399 that the 80486 rounds to the dest precision, then
440 converts to decide underflow. */ 400 converts to decide underflow. */
441 if ( !((tmp.sigh == 0x00100000) && (tmp.sigl == 0) && 401 if (!
442 (st0_ptr->sigl & 0x000007ff)) ) 402 ((tmp.sigh == 0x00100000) && (tmp.sigl == 0)
403 && (st0_ptr->sigl & 0x000007ff)))
443#endif /* PECULIAR_486 */ 404#endif /* PECULIAR_486 */
444 { 405 {
445 EXCEPTION(EX_Underflow); 406 EXCEPTION(EX_Underflow);
446 /* This is a special case: see sec 16.2.5.1 of 407 /* This is a special case: see sec 16.2.5.1 of
447 the 80486 book */ 408 the 80486 book */
448 if ( !(control_word & CW_Underflow) ) 409 if (!(control_word & CW_Underflow))
449 return 0; 410 return 0;
450 } 411 }
451 EXCEPTION(precision_loss); 412 EXCEPTION(precision_loss);
452 if ( !(control_word & CW_Precision) ) 413 if (!(control_word & CW_Precision))
453 return 0; 414 return 0;
454 }
455 l[0] = tmp.sigl;
456 l[1] = tmp.sigh;
457 }
458 else
459 {
460 if ( tmp.sigl & 0x000007ff )
461 {
462 precision_loss = 1;
463 switch (control_word & CW_RC)
464 {
465 case RC_RND:
466 /* Rounding can get a little messy.. */
467 increment = ((tmp.sigl & 0x7ff) > 0x400) | /* nearest */
468 ((tmp.sigl & 0xc00) == 0xc00); /* odd -> even */
469 break;
470 case RC_DOWN: /* towards -infinity */
471 increment = signpositive(&tmp) ? 0 : tmp.sigl & 0x7ff;
472 break;
473 case RC_UP: /* towards +infinity */
474 increment = signpositive(&tmp) ? tmp.sigl & 0x7ff : 0;
475 break;
476 case RC_CHOP:
477 increment = 0;
478 break;
479 }
480
481 /* Truncate the mantissa */
482 tmp.sigl &= 0xfffff800;
483
484 if ( increment )
485 {
486 if ( tmp.sigl >= 0xfffff800 )
487 {
488 /* the sigl part overflows */
489 if ( tmp.sigh == 0xffffffff )
490 {
491 /* The sigh part overflows */
492 tmp.sigh = 0x80000000;
493 exp++;
494 if (exp >= EXP_OVER)
495 goto overflow;
496 } 415 }
497 else 416 l[0] = tmp.sigl;
498 { 417 l[1] = tmp.sigh;
499 tmp.sigh ++; 418 } else {
419 if (tmp.sigl & 0x000007ff) {
420 precision_loss = 1;
421 switch (control_word & CW_RC) {
422 case RC_RND:
423 /* Rounding can get a little messy.. */
424 increment = ((tmp.sigl & 0x7ff) > 0x400) | /* nearest */
425 ((tmp.sigl & 0xc00) == 0xc00); /* odd -> even */
426 break;
427 case RC_DOWN: /* towards -infinity */
428 increment =
429 signpositive(&tmp) ? 0 : tmp.
430 sigl & 0x7ff;
431 break;
432 case RC_UP: /* towards +infinity */
433 increment =
434 signpositive(&tmp) ? tmp.
435 sigl & 0x7ff : 0;
436 break;
437 case RC_CHOP:
438 increment = 0;
439 break;
440 }
441
442 /* Truncate the mantissa */
443 tmp.sigl &= 0xfffff800;
444
445 if (increment) {
446 if (tmp.sigl >= 0xfffff800) {
447 /* the sigl part overflows */
448 if (tmp.sigh == 0xffffffff) {
449 /* The sigh part overflows */
450 tmp.sigh = 0x80000000;
451 exp++;
452 if (exp >= EXP_OVER)
453 goto overflow;
454 } else {
455 tmp.sigh++;
456 }
457 tmp.sigl = 0x00000000;
458 } else {
459 /* We only need to increment sigl */
460 tmp.sigl += 0x00000800;
461 }
462 }
463 } else
464 precision_loss = 0;
465
466 l[0] = (tmp.sigl >> 11) | (tmp.sigh << 21);
467 l[1] = ((tmp.sigh >> 11) & 0xfffff);
468
469 if (exp > DOUBLE_Emax) {
470 overflow:
471 EXCEPTION(EX_Overflow);
472 if (!(control_word & CW_Overflow))
473 return 0;
474 set_precision_flag_up();
475 if (!(control_word & CW_Precision))
476 return 0;
477
478 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
479 /* Overflow to infinity */
480 l[0] = 0x00000000; /* Set to */
481 l[1] = 0x7ff00000; /* + INF */
482 } else {
483 if (precision_loss) {
484 if (increment)
485 set_precision_flag_up();
486 else
487 set_precision_flag_down();
488 }
489 /* Add the exponent */
490 l[1] |= (((exp + DOUBLE_Ebias) & 0x7ff) << 20);
500 } 491 }
501 tmp.sigl = 0x00000000;
502 }
503 else
504 {
505 /* We only need to increment sigl */
506 tmp.sigl += 0x00000800;
507 }
508 }
509 }
510 else
511 precision_loss = 0;
512
513 l[0] = (tmp.sigl >> 11) | (tmp.sigh << 21);
514 l[1] = ((tmp.sigh >> 11) & 0xfffff);
515
516 if ( exp > DOUBLE_Emax )
517 {
518 overflow:
519 EXCEPTION(EX_Overflow);
520 if ( !(control_word & CW_Overflow) )
521 return 0;
522 set_precision_flag_up();
523 if ( !(control_word & CW_Precision) )
524 return 0;
525
526 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
527 /* Overflow to infinity */
528 l[0] = 0x00000000; /* Set to */
529 l[1] = 0x7ff00000; /* + INF */
530 }
531 else
532 {
533 if ( precision_loss )
534 {
535 if ( increment )
536 set_precision_flag_up();
537 else
538 set_precision_flag_down();
539 } 492 }
540 /* Add the exponent */ 493 } else if (st0_tag == TAG_Zero) {
541 l[1] |= (((exp+DOUBLE_Ebias) & 0x7ff) << 20); 494 /* Number is zero */
542 } 495 l[0] = 0;
543 } 496 l[1] = 0;
544 } 497 } else if (st0_tag == TAG_Special) {
545 else if (st0_tag == TAG_Zero) 498 st0_tag = FPU_Special(st0_ptr);
546 { 499 if (st0_tag == TW_Denormal) {
547 /* Number is zero */ 500 /* A denormal will always underflow. */
548 l[0] = 0;
549 l[1] = 0;
550 }
551 else if ( st0_tag == TAG_Special )
552 {
553 st0_tag = FPU_Special(st0_ptr);
554 if ( st0_tag == TW_Denormal )
555 {
556 /* A denormal will always underflow. */
557#ifndef PECULIAR_486 501#ifndef PECULIAR_486
558 /* An 80486 is supposed to be able to generate 502 /* An 80486 is supposed to be able to generate
559 a denormal exception here, but... */ 503 a denormal exception here, but... */
560 /* Underflow has priority. */ 504 /* Underflow has priority. */
561 if ( control_word & CW_Underflow ) 505 if (control_word & CW_Underflow)
562 denormal_operand(); 506 denormal_operand();
563#endif /* PECULIAR_486 */ 507#endif /* PECULIAR_486 */
564 reg_copy(st0_ptr, &tmp); 508 reg_copy(st0_ptr, &tmp);
565 goto denormal_arg; 509 goto denormal_arg;
566 } 510 } else if (st0_tag == TW_Infinity) {
567 else if (st0_tag == TW_Infinity) 511 l[0] = 0;
568 { 512 l[1] = 0x7ff00000;
569 l[0] = 0; 513 } else if (st0_tag == TW_NaN) {
570 l[1] = 0x7ff00000; 514 /* Is it really a NaN ? */
571 } 515 if ((exponent(st0_ptr) == EXP_OVER)
572 else if (st0_tag == TW_NaN) 516 && (st0_ptr->sigh & 0x80000000)) {
573 { 517 /* See if we can get a valid NaN from the FPU_REG */
574 /* Is it really a NaN ? */ 518 l[0] =
575 if ( (exponent(st0_ptr) == EXP_OVER) 519 (st0_ptr->sigl >> 11) | (st0_ptr->
576 && (st0_ptr->sigh & 0x80000000) ) 520 sigh << 21);
577 { 521 l[1] = ((st0_ptr->sigh >> 11) & 0xfffff);
578 /* See if we can get a valid NaN from the FPU_REG */ 522 if (!(st0_ptr->sigh & 0x40000000)) {
579 l[0] = (st0_ptr->sigl >> 11) | (st0_ptr->sigh << 21); 523 /* It is a signalling NaN */
580 l[1] = ((st0_ptr->sigh >> 11) & 0xfffff); 524 EXCEPTION(EX_Invalid);
581 if ( !(st0_ptr->sigh & 0x40000000) ) 525 if (!(control_word & CW_Invalid))
582 { 526 return 0;
583 /* It is a signalling NaN */ 527 l[1] |= (0x40000000 >> 11);
584 EXCEPTION(EX_Invalid); 528 }
585 if ( !(control_word & CW_Invalid) ) 529 l[1] |= 0x7ff00000;
586 return 0; 530 } else {
587 l[1] |= (0x40000000 >> 11); 531 /* It is an unsupported data type */
532 EXCEPTION(EX_Invalid);
533 if (!(control_word & CW_Invalid))
534 return 0;
535 l[0] = 0;
536 l[1] = 0xfff80000;
537 }
588 } 538 }
589 l[1] |= 0x7ff00000; 539 } else if (st0_tag == TAG_Empty) {
590 } 540 /* Empty register (stack underflow) */
591 else 541 EXCEPTION(EX_StackUnder);
592 { 542 if (control_word & CW_Invalid) {
593 /* It is an unsupported data type */ 543 /* The masked response */
594 EXCEPTION(EX_Invalid); 544 /* Put out the QNaN indefinite */
595 if ( !(control_word & CW_Invalid) ) 545 RE_ENTRANT_CHECK_OFF;
596 return 0; 546 FPU_access_ok(VERIFY_WRITE, dfloat, 8);
597 l[0] = 0; 547 FPU_put_user(0, (unsigned long __user *)dfloat);
598 l[1] = 0xfff80000; 548 FPU_put_user(0xfff80000,
599 } 549 1 + (unsigned long __user *)dfloat);
550 RE_ENTRANT_CHECK_ON;
551 return 1;
552 } else
553 return 0;
600 } 554 }
601 } 555 if (getsign(st0_ptr))
602 else if ( st0_tag == TAG_Empty ) 556 l[1] |= 0x80000000;
603 {
604 /* Empty register (stack underflow) */
605 EXCEPTION(EX_StackUnder);
606 if ( control_word & CW_Invalid )
607 {
608 /* The masked response */
609 /* Put out the QNaN indefinite */
610 RE_ENTRANT_CHECK_OFF;
611 FPU_access_ok(VERIFY_WRITE,dfloat,8);
612 FPU_put_user(0, (unsigned long __user *) dfloat);
613 FPU_put_user(0xfff80000, 1 + (unsigned long __user *) dfloat);
614 RE_ENTRANT_CHECK_ON;
615 return 1;
616 }
617 else
618 return 0;
619 }
620 if ( getsign(st0_ptr) )
621 l[1] |= 0x80000000;
622
623 RE_ENTRANT_CHECK_OFF;
624 FPU_access_ok(VERIFY_WRITE,dfloat,8);
625 FPU_put_user(l[0], (unsigned long __user *)dfloat);
626 FPU_put_user(l[1], 1 + (unsigned long __user *)dfloat);
627 RE_ENTRANT_CHECK_ON;
628
629 return 1;
630}
631 557
558 RE_ENTRANT_CHECK_OFF;
559 FPU_access_ok(VERIFY_WRITE, dfloat, 8);
560 FPU_put_user(l[0], (unsigned long __user *)dfloat);
561 FPU_put_user(l[1], 1 + (unsigned long __user *)dfloat);
562 RE_ENTRANT_CHECK_ON;
563
564 return 1;
565}
632 566
633/* Put a float into user memory */ 567/* Put a float into user memory */
634int FPU_store_single(FPU_REG *st0_ptr, u_char st0_tag, float __user *single) 568int FPU_store_single(FPU_REG * st0_ptr, u_char st0_tag, float __user * single)
635{ 569{
636 long templ = 0; 570 long templ = 0;
637 unsigned long increment = 0; /* avoid gcc warnings */ 571 unsigned long increment = 0; /* avoid gcc warnings */
638 int precision_loss; 572 int precision_loss;
639 int exp; 573 int exp;
640 FPU_REG tmp; 574 FPU_REG tmp;
641 575
642 if ( st0_tag == TAG_Valid ) 576 if (st0_tag == TAG_Valid) {
643 {
644 577
645 reg_copy(st0_ptr, &tmp); 578 reg_copy(st0_ptr, &tmp);
646 exp = exponent(&tmp); 579 exp = exponent(&tmp);
647 580
648 if ( exp < SINGLE_Emin ) 581 if (exp < SINGLE_Emin) {
649 { 582 addexponent(&tmp, -SINGLE_Emin + 23); /* largest exp to be 22 */
650 addexponent(&tmp, -SINGLE_Emin + 23); /* largest exp to be 22 */
651 583
652 denormal_arg: 584 denormal_arg:
653 585
654 if ( (precision_loss = FPU_round_to_int(&tmp, st0_tag)) ) 586 if ((precision_loss = FPU_round_to_int(&tmp, st0_tag))) {
655 {
656#ifdef PECULIAR_486 587#ifdef PECULIAR_486
657 /* Did it round to a non-denormal ? */ 588 /* Did it round to a non-denormal ? */
658 /* This behaviour might be regarded as peculiar, it appears 589 /* This behaviour might be regarded as peculiar, it appears
659 that the 80486 rounds to the dest precision, then 590 that the 80486 rounds to the dest precision, then
660 converts to decide underflow. */ 591 converts to decide underflow. */
661 if ( !((tmp.sigl == 0x00800000) && 592 if (!((tmp.sigl == 0x00800000) &&
662 ((st0_ptr->sigh & 0x000000ff) || st0_ptr->sigl)) ) 593 ((st0_ptr->sigh & 0x000000ff)
594 || st0_ptr->sigl)))
663#endif /* PECULIAR_486 */ 595#endif /* PECULIAR_486 */
664 { 596 {
665 EXCEPTION(EX_Underflow); 597 EXCEPTION(EX_Underflow);
666 /* This is a special case: see sec 16.2.5.1 of 598 /* This is a special case: see sec 16.2.5.1 of
667 the 80486 book */ 599 the 80486 book */
668 if ( !(control_word & CW_Underflow) ) 600 if (!(control_word & CW_Underflow))
669 return 0; 601 return 0;
670 } 602 }
671 EXCEPTION(precision_loss); 603 EXCEPTION(precision_loss);
672 if ( !(control_word & CW_Precision) ) 604 if (!(control_word & CW_Precision))
673 return 0; 605 return 0;
674 } 606 }
675 templ = tmp.sigl; 607 templ = tmp.sigl;
676 } 608 } else {
677 else 609 if (tmp.sigl | (tmp.sigh & 0x000000ff)) {
678 { 610 unsigned long sigh = tmp.sigh;
679 if ( tmp.sigl | (tmp.sigh & 0x000000ff) ) 611 unsigned long sigl = tmp.sigl;
680 { 612
681 unsigned long sigh = tmp.sigh; 613 precision_loss = 1;
682 unsigned long sigl = tmp.sigl; 614 switch (control_word & CW_RC) {
683 615 case RC_RND:
684 precision_loss = 1; 616 increment = ((sigh & 0xff) > 0x80) /* more than half */
685 switch (control_word & CW_RC) 617 ||(((sigh & 0xff) == 0x80) && sigl) /* more than half */
686 { 618 ||((sigh & 0x180) == 0x180); /* round to even */
687 case RC_RND: 619 break;
688 increment = ((sigh & 0xff) > 0x80) /* more than half */ 620 case RC_DOWN: /* towards -infinity */
689 || (((sigh & 0xff) == 0x80) && sigl) /* more than half */ 621 increment = signpositive(&tmp)
690 || ((sigh & 0x180) == 0x180); /* round to even */ 622 ? 0 : (sigl | (sigh & 0xff));
691 break; 623 break;
692 case RC_DOWN: /* towards -infinity */ 624 case RC_UP: /* towards +infinity */
693 increment = signpositive(&tmp) 625 increment = signpositive(&tmp)
694 ? 0 : (sigl | (sigh & 0xff)); 626 ? (sigl | (sigh & 0xff)) : 0;
695 break; 627 break;
696 case RC_UP: /* towards +infinity */ 628 case RC_CHOP:
697 increment = signpositive(&tmp) 629 increment = 0;
698 ? (sigl | (sigh & 0xff)) : 0; 630 break;
699 break; 631 }
700 case RC_CHOP: 632
701 increment = 0; 633 /* Truncate part of the mantissa */
702 break; 634 tmp.sigl = 0;
703 } 635
704 636 if (increment) {
705 /* Truncate part of the mantissa */ 637 if (sigh >= 0xffffff00) {
706 tmp.sigl = 0; 638 /* The sigh part overflows */
707 639 tmp.sigh = 0x80000000;
708 if (increment) 640 exp++;
709 { 641 if (exp >= EXP_OVER)
710 if ( sigh >= 0xffffff00 ) 642 goto overflow;
711 { 643 } else {
712 /* The sigh part overflows */ 644 tmp.sigh &= 0xffffff00;
713 tmp.sigh = 0x80000000; 645 tmp.sigh += 0x100;
714 exp++; 646 }
715 if ( exp >= EXP_OVER ) 647 } else {
716 goto overflow; 648 tmp.sigh &= 0xffffff00; /* Finish the truncation */
717 } 649 }
718 else 650 } else
719 { 651 precision_loss = 0;
720 tmp.sigh &= 0xffffff00; 652
721 tmp.sigh += 0x100; 653 templ = (tmp.sigh >> 8) & 0x007fffff;
722 } 654
723 } 655 if (exp > SINGLE_Emax) {
724 else 656 overflow:
725 { 657 EXCEPTION(EX_Overflow);
726 tmp.sigh &= 0xffffff00; /* Finish the truncation */ 658 if (!(control_word & CW_Overflow))
727 } 659 return 0;
728 } 660 set_precision_flag_up();
729 else 661 if (!(control_word & CW_Precision))
730 precision_loss = 0; 662 return 0;
731 663
732 templ = (tmp.sigh >> 8) & 0x007fffff; 664 /* This is a special case: see sec 16.2.5.1 of the 80486 book. */
733 665 /* Masked response is overflow to infinity. */
734 if ( exp > SINGLE_Emax ) 666 templ = 0x7f800000;
735 { 667 } else {
736 overflow: 668 if (precision_loss) {
737 EXCEPTION(EX_Overflow); 669 if (increment)
738 if ( !(control_word & CW_Overflow) ) 670 set_precision_flag_up();
739 return 0; 671 else
740 set_precision_flag_up(); 672 set_precision_flag_down();
741 if ( !(control_word & CW_Precision) ) 673 }
742 return 0; 674 /* Add the exponent */
743 675 templ |= ((exp + SINGLE_Ebias) & 0xff) << 23;
744 /* This is a special case: see sec 16.2.5.1 of the 80486 book. */ 676 }
745 /* Masked response is overflow to infinity. */
746 templ = 0x7f800000;
747 }
748 else
749 {
750 if ( precision_loss )
751 {
752 if ( increment )
753 set_precision_flag_up();
754 else
755 set_precision_flag_down();
756 } 677 }
757 /* Add the exponent */ 678 } else if (st0_tag == TAG_Zero) {
758 templ |= ((exp+SINGLE_Ebias) & 0xff) << 23; 679 templ = 0;
759 } 680 } else if (st0_tag == TAG_Special) {
760 } 681 st0_tag = FPU_Special(st0_ptr);
761 } 682 if (st0_tag == TW_Denormal) {
762 else if (st0_tag == TAG_Zero) 683 reg_copy(st0_ptr, &tmp);
763 { 684
764 templ = 0; 685 /* A denormal will always underflow. */
765 }
766 else if ( st0_tag == TAG_Special )
767 {
768 st0_tag = FPU_Special(st0_ptr);
769 if (st0_tag == TW_Denormal)
770 {
771 reg_copy(st0_ptr, &tmp);
772
773 /* A denormal will always underflow. */
774#ifndef PECULIAR_486 686#ifndef PECULIAR_486
775 /* An 80486 is supposed to be able to generate 687 /* An 80486 is supposed to be able to generate
776 a denormal exception here, but... */ 688 a denormal exception here, but... */
777 /* Underflow has priority. */ 689 /* Underflow has priority. */
778 if ( control_word & CW_Underflow ) 690 if (control_word & CW_Underflow)
779 denormal_operand(); 691 denormal_operand();
780#endif /* PECULIAR_486 */ 692#endif /* PECULIAR_486 */
781 goto denormal_arg; 693 goto denormal_arg;
782 } 694 } else if (st0_tag == TW_Infinity) {
783 else if (st0_tag == TW_Infinity) 695 templ = 0x7f800000;
784 { 696 } else if (st0_tag == TW_NaN) {
785 templ = 0x7f800000; 697 /* Is it really a NaN ? */
786 } 698 if ((exponent(st0_ptr) == EXP_OVER)
787 else if (st0_tag == TW_NaN) 699 && (st0_ptr->sigh & 0x80000000)) {
788 { 700 /* See if we can get a valid NaN from the FPU_REG */
789 /* Is it really a NaN ? */ 701 templ = st0_ptr->sigh >> 8;
790 if ( (exponent(st0_ptr) == EXP_OVER) && (st0_ptr->sigh & 0x80000000) ) 702 if (!(st0_ptr->sigh & 0x40000000)) {
791 { 703 /* It is a signalling NaN */
792 /* See if we can get a valid NaN from the FPU_REG */ 704 EXCEPTION(EX_Invalid);
793 templ = st0_ptr->sigh >> 8; 705 if (!(control_word & CW_Invalid))
794 if ( !(st0_ptr->sigh & 0x40000000) ) 706 return 0;
795 { 707 templ |= (0x40000000 >> 8);
796 /* It is a signalling NaN */ 708 }
797 EXCEPTION(EX_Invalid); 709 templ |= 0x7f800000;
798 if ( !(control_word & CW_Invalid) ) 710 } else {
799 return 0; 711 /* It is an unsupported data type */
800 templ |= (0x40000000 >> 8); 712 EXCEPTION(EX_Invalid);
713 if (!(control_word & CW_Invalid))
714 return 0;
715 templ = 0xffc00000;
716 }
801 } 717 }
802 templ |= 0x7f800000;
803 }
804 else
805 {
806 /* It is an unsupported data type */
807 EXCEPTION(EX_Invalid);
808 if ( !(control_word & CW_Invalid) )
809 return 0;
810 templ = 0xffc00000;
811 }
812 }
813#ifdef PARANOID 718#ifdef PARANOID
814 else 719 else {
815 { 720 EXCEPTION(EX_INTERNAL | 0x164);
816 EXCEPTION(EX_INTERNAL|0x164); 721 return 0;
817 return 0; 722 }
818 }
819#endif 723#endif
820 } 724 } else if (st0_tag == TAG_Empty) {
821 else if ( st0_tag == TAG_Empty ) 725 /* Empty register (stack underflow) */
822 { 726 EXCEPTION(EX_StackUnder);
823 /* Empty register (stack underflow) */ 727 if (control_word & EX_Invalid) {
824 EXCEPTION(EX_StackUnder); 728 /* The masked response */
825 if ( control_word & EX_Invalid ) 729 /* Put out the QNaN indefinite */
826 { 730 RE_ENTRANT_CHECK_OFF;
827 /* The masked response */ 731 FPU_access_ok(VERIFY_WRITE, single, 4);
828 /* Put out the QNaN indefinite */ 732 FPU_put_user(0xffc00000,
829 RE_ENTRANT_CHECK_OFF; 733 (unsigned long __user *)single);
830 FPU_access_ok(VERIFY_WRITE,single,4); 734 RE_ENTRANT_CHECK_ON;
831 FPU_put_user(0xffc00000, (unsigned long __user *) single); 735 return 1;
832 RE_ENTRANT_CHECK_ON; 736 } else
833 return 1; 737 return 0;
834 } 738 }
835 else
836 return 0;
837 }
838#ifdef PARANOID 739#ifdef PARANOID
839 else 740 else {
840 { 741 EXCEPTION(EX_INTERNAL | 0x163);
841 EXCEPTION(EX_INTERNAL|0x163); 742 return 0;
842 return 0; 743 }
843 }
844#endif 744#endif
845 if ( getsign(st0_ptr) ) 745 if (getsign(st0_ptr))
846 templ |= 0x80000000; 746 templ |= 0x80000000;
847 747
848 RE_ENTRANT_CHECK_OFF; 748 RE_ENTRANT_CHECK_OFF;
849 FPU_access_ok(VERIFY_WRITE,single,4); 749 FPU_access_ok(VERIFY_WRITE, single, 4);
850 FPU_put_user(templ,(unsigned long __user *) single); 750 FPU_put_user(templ, (unsigned long __user *)single);
851 RE_ENTRANT_CHECK_ON; 751 RE_ENTRANT_CHECK_ON;
852 752
853 return 1; 753 return 1;
854} 754}
855 755
856
857/* Put a long long into user memory */ 756/* Put a long long into user memory */
858int FPU_store_int64(FPU_REG *st0_ptr, u_char st0_tag, long long __user *d) 757int FPU_store_int64(FPU_REG * st0_ptr, u_char st0_tag, long long __user * d)
859{ 758{
860 FPU_REG t; 759 FPU_REG t;
861 long long tll; 760 long long tll;
862 int precision_loss; 761 int precision_loss;
863 762
864 if ( st0_tag == TAG_Empty ) 763 if (st0_tag == TAG_Empty) {
865 { 764 /* Empty register (stack underflow) */
866 /* Empty register (stack underflow) */ 765 EXCEPTION(EX_StackUnder);
867 EXCEPTION(EX_StackUnder); 766 goto invalid_operand;
868 goto invalid_operand; 767 } else if (st0_tag == TAG_Special) {
869 } 768 st0_tag = FPU_Special(st0_ptr);
870 else if ( st0_tag == TAG_Special ) 769 if ((st0_tag == TW_Infinity) || (st0_tag == TW_NaN)) {
871 { 770 EXCEPTION(EX_Invalid);
872 st0_tag = FPU_Special(st0_ptr); 771 goto invalid_operand;
873 if ( (st0_tag == TW_Infinity) || 772 }
874 (st0_tag == TW_NaN) )
875 {
876 EXCEPTION(EX_Invalid);
877 goto invalid_operand;
878 } 773 }
879 } 774
880 775 reg_copy(st0_ptr, &t);
881 reg_copy(st0_ptr, &t); 776 precision_loss = FPU_round_to_int(&t, st0_tag);
882 precision_loss = FPU_round_to_int(&t, st0_tag); 777 ((long *)&tll)[0] = t.sigl;
883 ((long *)&tll)[0] = t.sigl; 778 ((long *)&tll)[1] = t.sigh;
884 ((long *)&tll)[1] = t.sigh; 779 if ((precision_loss == 1) ||
885 if ( (precision_loss == 1) || 780 ((t.sigh & 0x80000000) &&
886 ((t.sigh & 0x80000000) && 781 !((t.sigh == 0x80000000) && (t.sigl == 0) && signnegative(&t)))) {
887 !((t.sigh == 0x80000000) && (t.sigl == 0) && 782 EXCEPTION(EX_Invalid);
888 signnegative(&t))) ) 783 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
889 { 784 invalid_operand:
890 EXCEPTION(EX_Invalid); 785 if (control_word & EX_Invalid) {
891 /* This is a special case: see sec 16.2.5.1 of the 80486 book */ 786 /* Produce something like QNaN "indefinite" */
892 invalid_operand: 787 tll = 0x8000000000000000LL;
893 if ( control_word & EX_Invalid ) 788 } else
894 { 789 return 0;
895 /* Produce something like QNaN "indefinite" */ 790 } else {
896 tll = 0x8000000000000000LL; 791 if (precision_loss)
792 set_precision_flag(precision_loss);
793 if (signnegative(&t))
794 tll = -tll;
897 } 795 }
898 else
899 return 0;
900 }
901 else
902 {
903 if ( precision_loss )
904 set_precision_flag(precision_loss);
905 if ( signnegative(&t) )
906 tll = - tll;
907 }
908
909 RE_ENTRANT_CHECK_OFF;
910 FPU_access_ok(VERIFY_WRITE,d,8);
911 if (copy_to_user(d, &tll, 8))
912 FPU_abort;
913 RE_ENTRANT_CHECK_ON;
914
915 return 1;
916}
917 796
797 RE_ENTRANT_CHECK_OFF;
798 FPU_access_ok(VERIFY_WRITE, d, 8);
799 if (copy_to_user(d, &tll, 8))
800 FPU_abort;
801 RE_ENTRANT_CHECK_ON;
802
803 return 1;
804}
918 805
919/* Put a long into user memory */ 806/* Put a long into user memory */
920int FPU_store_int32(FPU_REG *st0_ptr, u_char st0_tag, long __user *d) 807int FPU_store_int32(FPU_REG * st0_ptr, u_char st0_tag, long __user * d)
921{ 808{
922 FPU_REG t; 809 FPU_REG t;
923 int precision_loss; 810 int precision_loss;
924 811
925 if ( st0_tag == TAG_Empty ) 812 if (st0_tag == TAG_Empty) {
926 { 813 /* Empty register (stack underflow) */
927 /* Empty register (stack underflow) */ 814 EXCEPTION(EX_StackUnder);
928 EXCEPTION(EX_StackUnder); 815 goto invalid_operand;
929 goto invalid_operand; 816 } else if (st0_tag == TAG_Special) {
930 } 817 st0_tag = FPU_Special(st0_ptr);
931 else if ( st0_tag == TAG_Special ) 818 if ((st0_tag == TW_Infinity) || (st0_tag == TW_NaN)) {
932 { 819 EXCEPTION(EX_Invalid);
933 st0_tag = FPU_Special(st0_ptr); 820 goto invalid_operand;
934 if ( (st0_tag == TW_Infinity) || 821 }
935 (st0_tag == TW_NaN) )
936 {
937 EXCEPTION(EX_Invalid);
938 goto invalid_operand;
939 } 822 }
940 } 823
941 824 reg_copy(st0_ptr, &t);
942 reg_copy(st0_ptr, &t); 825 precision_loss = FPU_round_to_int(&t, st0_tag);
943 precision_loss = FPU_round_to_int(&t, st0_tag); 826 if (t.sigh ||
944 if (t.sigh || 827 ((t.sigl & 0x80000000) &&
945 ((t.sigl & 0x80000000) && 828 !((t.sigl == 0x80000000) && signnegative(&t)))) {
946 !((t.sigl == 0x80000000) && signnegative(&t))) ) 829 EXCEPTION(EX_Invalid);
947 { 830 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
948 EXCEPTION(EX_Invalid); 831 invalid_operand:
949 /* This is a special case: see sec 16.2.5.1 of the 80486 book */ 832 if (control_word & EX_Invalid) {
950 invalid_operand: 833 /* Produce something like QNaN "indefinite" */
951 if ( control_word & EX_Invalid ) 834 t.sigl = 0x80000000;
952 { 835 } else
953 /* Produce something like QNaN "indefinite" */ 836 return 0;
954 t.sigl = 0x80000000; 837 } else {
838 if (precision_loss)
839 set_precision_flag(precision_loss);
840 if (signnegative(&t))
841 t.sigl = -(long)t.sigl;
955 } 842 }
956 else
957 return 0;
958 }
959 else
960 {
961 if ( precision_loss )
962 set_precision_flag(precision_loss);
963 if ( signnegative(&t) )
964 t.sigl = -(long)t.sigl;
965 }
966
967 RE_ENTRANT_CHECK_OFF;
968 FPU_access_ok(VERIFY_WRITE,d,4);
969 FPU_put_user(t.sigl, (unsigned long __user *) d);
970 RE_ENTRANT_CHECK_ON;
971
972 return 1;
973}
974 843
844 RE_ENTRANT_CHECK_OFF;
845 FPU_access_ok(VERIFY_WRITE, d, 4);
846 FPU_put_user(t.sigl, (unsigned long __user *)d);
847 RE_ENTRANT_CHECK_ON;
848
849 return 1;
850}
975 851
976/* Put a short into user memory */ 852/* Put a short into user memory */
977int FPU_store_int16(FPU_REG *st0_ptr, u_char st0_tag, short __user *d) 853int FPU_store_int16(FPU_REG * st0_ptr, u_char st0_tag, short __user * d)
978{ 854{
979 FPU_REG t; 855 FPU_REG t;
980 int precision_loss; 856 int precision_loss;
981 857
982 if ( st0_tag == TAG_Empty ) 858 if (st0_tag == TAG_Empty) {
983 { 859 /* Empty register (stack underflow) */
984 /* Empty register (stack underflow) */ 860 EXCEPTION(EX_StackUnder);
985 EXCEPTION(EX_StackUnder); 861 goto invalid_operand;
986 goto invalid_operand; 862 } else if (st0_tag == TAG_Special) {
987 } 863 st0_tag = FPU_Special(st0_ptr);
988 else if ( st0_tag == TAG_Special ) 864 if ((st0_tag == TW_Infinity) || (st0_tag == TW_NaN)) {
989 { 865 EXCEPTION(EX_Invalid);
990 st0_tag = FPU_Special(st0_ptr); 866 goto invalid_operand;
991 if ( (st0_tag == TW_Infinity) || 867 }
992 (st0_tag == TW_NaN) )
993 {
994 EXCEPTION(EX_Invalid);
995 goto invalid_operand;
996 } 868 }
997 } 869
998 870 reg_copy(st0_ptr, &t);
999 reg_copy(st0_ptr, &t); 871 precision_loss = FPU_round_to_int(&t, st0_tag);
1000 precision_loss = FPU_round_to_int(&t, st0_tag); 872 if (t.sigh ||
1001 if (t.sigh || 873 ((t.sigl & 0xffff8000) &&
1002 ((t.sigl & 0xffff8000) && 874 !((t.sigl == 0x8000) && signnegative(&t)))) {
1003 !((t.sigl == 0x8000) && signnegative(&t))) ) 875 EXCEPTION(EX_Invalid);
1004 { 876 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
1005 EXCEPTION(EX_Invalid); 877 invalid_operand:
1006 /* This is a special case: see sec 16.2.5.1 of the 80486 book */ 878 if (control_word & EX_Invalid) {
1007 invalid_operand: 879 /* Produce something like QNaN "indefinite" */
1008 if ( control_word & EX_Invalid ) 880 t.sigl = 0x8000;
1009 { 881 } else
1010 /* Produce something like QNaN "indefinite" */ 882 return 0;
1011 t.sigl = 0x8000; 883 } else {
884 if (precision_loss)
885 set_precision_flag(precision_loss);
886 if (signnegative(&t))
887 t.sigl = -t.sigl;
1012 } 888 }
1013 else
1014 return 0;
1015 }
1016 else
1017 {
1018 if ( precision_loss )
1019 set_precision_flag(precision_loss);
1020 if ( signnegative(&t) )
1021 t.sigl = -t.sigl;
1022 }
1023
1024 RE_ENTRANT_CHECK_OFF;
1025 FPU_access_ok(VERIFY_WRITE,d,2);
1026 FPU_put_user((short)t.sigl, d);
1027 RE_ENTRANT_CHECK_ON;
1028
1029 return 1;
1030}
1031 889
890 RE_ENTRANT_CHECK_OFF;
891 FPU_access_ok(VERIFY_WRITE, d, 2);
892 FPU_put_user((short)t.sigl, d);
893 RE_ENTRANT_CHECK_ON;
894
895 return 1;
896}
1032 897
1033/* Put a packed bcd array into user memory */ 898/* Put a packed bcd array into user memory */
1034int FPU_store_bcd(FPU_REG *st0_ptr, u_char st0_tag, u_char __user *d) 899int FPU_store_bcd(FPU_REG * st0_ptr, u_char st0_tag, u_char __user * d)
1035{ 900{
1036 FPU_REG t; 901 FPU_REG t;
1037 unsigned long long ll; 902 unsigned long long ll;
1038 u_char b; 903 u_char b;
1039 int i, precision_loss; 904 int i, precision_loss;
1040 u_char sign = (getsign(st0_ptr) == SIGN_NEG) ? 0x80 : 0; 905 u_char sign = (getsign(st0_ptr) == SIGN_NEG) ? 0x80 : 0;
1041 906
1042 if ( st0_tag == TAG_Empty ) 907 if (st0_tag == TAG_Empty) {
1043 { 908 /* Empty register (stack underflow) */
1044 /* Empty register (stack underflow) */ 909 EXCEPTION(EX_StackUnder);
1045 EXCEPTION(EX_StackUnder); 910 goto invalid_operand;
1046 goto invalid_operand; 911 } else if (st0_tag == TAG_Special) {
1047 } 912 st0_tag = FPU_Special(st0_ptr);
1048 else if ( st0_tag == TAG_Special ) 913 if ((st0_tag == TW_Infinity) || (st0_tag == TW_NaN)) {
1049 { 914 EXCEPTION(EX_Invalid);
1050 st0_tag = FPU_Special(st0_ptr); 915 goto invalid_operand;
1051 if ( (st0_tag == TW_Infinity) || 916 }
1052 (st0_tag == TW_NaN) ) 917 }
1053 { 918
1054 EXCEPTION(EX_Invalid); 919 reg_copy(st0_ptr, &t);
1055 goto invalid_operand; 920 precision_loss = FPU_round_to_int(&t, st0_tag);
921 ll = significand(&t);
922
923 /* Check for overflow, by comparing with 999999999999999999 decimal. */
924 if ((t.sigh > 0x0de0b6b3) ||
925 ((t.sigh == 0x0de0b6b3) && (t.sigl > 0xa763ffff))) {
926 EXCEPTION(EX_Invalid);
927 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
928 invalid_operand:
929 if (control_word & CW_Invalid) {
930 /* Produce the QNaN "indefinite" */
931 RE_ENTRANT_CHECK_OFF;
932 FPU_access_ok(VERIFY_WRITE, d, 10);
933 for (i = 0; i < 7; i++)
934 FPU_put_user(0, d + i); /* These bytes "undefined" */
935 FPU_put_user(0xc0, d + 7); /* This byte "undefined" */
936 FPU_put_user(0xff, d + 8);
937 FPU_put_user(0xff, d + 9);
938 RE_ENTRANT_CHECK_ON;
939 return 1;
940 } else
941 return 0;
942 } else if (precision_loss) {
943 /* Precision loss doesn't stop the data transfer */
944 set_precision_flag(precision_loss);
1056 } 945 }
1057 } 946
1058 947 RE_ENTRANT_CHECK_OFF;
1059 reg_copy(st0_ptr, &t); 948 FPU_access_ok(VERIFY_WRITE, d, 10);
1060 precision_loss = FPU_round_to_int(&t, st0_tag); 949 RE_ENTRANT_CHECK_ON;
1061 ll = significand(&t); 950 for (i = 0; i < 9; i++) {
1062 951 b = FPU_div_small(&ll, 10);
1063 /* Check for overflow, by comparing with 999999999999999999 decimal. */ 952 b |= (FPU_div_small(&ll, 10)) << 4;
1064 if ( (t.sigh > 0x0de0b6b3) || 953 RE_ENTRANT_CHECK_OFF;
1065 ((t.sigh == 0x0de0b6b3) && (t.sigl > 0xa763ffff)) ) 954 FPU_put_user(b, d + i);
1066 { 955 RE_ENTRANT_CHECK_ON;
1067 EXCEPTION(EX_Invalid);
1068 /* This is a special case: see sec 16.2.5.1 of the 80486 book */
1069 invalid_operand:
1070 if ( control_word & CW_Invalid )
1071 {
1072 /* Produce the QNaN "indefinite" */
1073 RE_ENTRANT_CHECK_OFF;
1074 FPU_access_ok(VERIFY_WRITE,d,10);
1075 for ( i = 0; i < 7; i++)
1076 FPU_put_user(0, d+i); /* These bytes "undefined" */
1077 FPU_put_user(0xc0, d+7); /* This byte "undefined" */
1078 FPU_put_user(0xff, d+8);
1079 FPU_put_user(0xff, d+9);
1080 RE_ENTRANT_CHECK_ON;
1081 return 1;
1082 } 956 }
1083 else 957 RE_ENTRANT_CHECK_OFF;
1084 return 0; 958 FPU_put_user(sign, d + 9);
1085 } 959 RE_ENTRANT_CHECK_ON;
1086 else if ( precision_loss ) 960
1087 { 961 return 1;
1088 /* Precision loss doesn't stop the data transfer */
1089 set_precision_flag(precision_loss);
1090 }
1091
1092 RE_ENTRANT_CHECK_OFF;
1093 FPU_access_ok(VERIFY_WRITE,d,10);
1094 RE_ENTRANT_CHECK_ON;
1095 for ( i = 0; i < 9; i++)
1096 {
1097 b = FPU_div_small(&ll, 10);
1098 b |= (FPU_div_small(&ll, 10)) << 4;
1099 RE_ENTRANT_CHECK_OFF;
1100 FPU_put_user(b, d+i);
1101 RE_ENTRANT_CHECK_ON;
1102 }
1103 RE_ENTRANT_CHECK_OFF;
1104 FPU_put_user(sign, d+9);
1105 RE_ENTRANT_CHECK_ON;
1106
1107 return 1;
1108} 962}
1109 963
1110/*===========================================================================*/ 964/*===========================================================================*/
@@ -1117,259 +971,254 @@ int FPU_store_bcd(FPU_REG *st0_ptr, u_char st0_tag, u_char __user *d)
1117/* Overflow is signalled by a non-zero return value (in eax). 971/* Overflow is signalled by a non-zero return value (in eax).
1118 In the case of overflow, the returned significand always has the 972 In the case of overflow, the returned significand always has the
1119 largest possible value */ 973 largest possible value */
1120int FPU_round_to_int(FPU_REG *r, u_char tag) 974int FPU_round_to_int(FPU_REG * r, u_char tag)
1121{ 975{
1122 u_char very_big; 976 u_char very_big;
1123 unsigned eax; 977 unsigned eax;
1124 978
1125 if (tag == TAG_Zero) 979 if (tag == TAG_Zero) {
1126 { 980 /* Make sure that zero is returned */
1127 /* Make sure that zero is returned */ 981 significand(r) = 0;
1128 significand(r) = 0; 982 return 0; /* o.k. */
1129 return 0; /* o.k. */ 983 }
1130 } 984
1131 985 if (exponent(r) > 63) {
1132 if (exponent(r) > 63) 986 r->sigl = r->sigh = ~0; /* The largest representable number */
1133 { 987 return 1; /* overflow */
1134 r->sigl = r->sigh = ~0; /* The largest representable number */ 988 }
1135 return 1; /* overflow */ 989
1136 } 990 eax = FPU_shrxs(&r->sigl, 63 - exponent(r));
1137 991 very_big = !(~(r->sigh) | ~(r->sigl)); /* test for 0xfff...fff */
1138 eax = FPU_shrxs(&r->sigl, 63 - exponent(r));
1139 very_big = !(~(r->sigh) | ~(r->sigl)); /* test for 0xfff...fff */
1140#define half_or_more (eax & 0x80000000) 992#define half_or_more (eax & 0x80000000)
1141#define frac_part (eax) 993#define frac_part (eax)
1142#define more_than_half ((eax & 0x80000001) == 0x80000001) 994#define more_than_half ((eax & 0x80000001) == 0x80000001)
1143 switch (control_word & CW_RC) 995 switch (control_word & CW_RC) {
1144 { 996 case RC_RND:
1145 case RC_RND: 997 if (more_than_half /* nearest */
1146 if ( more_than_half /* nearest */ 998 || (half_or_more && (r->sigl & 1))) { /* odd -> even */
1147 || (half_or_more && (r->sigl & 1)) ) /* odd -> even */ 999 if (very_big)
1148 { 1000 return 1; /* overflow */
1149 if ( very_big ) return 1; /* overflow */ 1001 significand(r)++;
1150 significand(r) ++; 1002 return PRECISION_LOST_UP;
1151 return PRECISION_LOST_UP; 1003 }
1152 } 1004 break;
1153 break; 1005 case RC_DOWN:
1154 case RC_DOWN: 1006 if (frac_part && getsign(r)) {
1155 if (frac_part && getsign(r)) 1007 if (very_big)
1156 { 1008 return 1; /* overflow */
1157 if ( very_big ) return 1; /* overflow */ 1009 significand(r)++;
1158 significand(r) ++; 1010 return PRECISION_LOST_UP;
1159 return PRECISION_LOST_UP; 1011 }
1160 } 1012 break;
1161 break; 1013 case RC_UP:
1162 case RC_UP: 1014 if (frac_part && !getsign(r)) {
1163 if (frac_part && !getsign(r)) 1015 if (very_big)
1164 { 1016 return 1; /* overflow */
1165 if ( very_big ) return 1; /* overflow */ 1017 significand(r)++;
1166 significand(r) ++; 1018 return PRECISION_LOST_UP;
1167 return PRECISION_LOST_UP; 1019 }
1020 break;
1021 case RC_CHOP:
1022 break;
1168 } 1023 }
1169 break;
1170 case RC_CHOP:
1171 break;
1172 }
1173 1024
1174 return eax ? PRECISION_LOST_DOWN : 0; 1025 return eax ? PRECISION_LOST_DOWN : 0;
1175 1026
1176} 1027}
1177 1028
1178/*===========================================================================*/ 1029/*===========================================================================*/
1179 1030
1180u_char __user *fldenv(fpu_addr_modes addr_modes, u_char __user *s) 1031u_char __user *fldenv(fpu_addr_modes addr_modes, u_char __user * s)
1181{ 1032{
1182 unsigned short tag_word = 0; 1033 unsigned short tag_word = 0;
1183 u_char tag; 1034 u_char tag;
1184 int i; 1035 int i;
1185 1036
1186 if ( (addr_modes.default_mode == VM86) || 1037 if ((addr_modes.default_mode == VM86) ||
1187 ((addr_modes.default_mode == PM16) 1038 ((addr_modes.default_mode == PM16)
1188 ^ (addr_modes.override.operand_size == OP_SIZE_PREFIX)) ) 1039 ^ (addr_modes.override.operand_size == OP_SIZE_PREFIX))) {
1189 { 1040 RE_ENTRANT_CHECK_OFF;
1190 RE_ENTRANT_CHECK_OFF; 1041 FPU_access_ok(VERIFY_READ, s, 0x0e);
1191 FPU_access_ok(VERIFY_READ, s, 0x0e); 1042 FPU_get_user(control_word, (unsigned short __user *)s);
1192 FPU_get_user(control_word, (unsigned short __user *) s); 1043 FPU_get_user(partial_status, (unsigned short __user *)(s + 2));
1193 FPU_get_user(partial_status, (unsigned short __user *) (s+2)); 1044 FPU_get_user(tag_word, (unsigned short __user *)(s + 4));
1194 FPU_get_user(tag_word, (unsigned short __user *) (s+4)); 1045 FPU_get_user(instruction_address.offset,
1195 FPU_get_user(instruction_address.offset, (unsigned short __user *) (s+6)); 1046 (unsigned short __user *)(s + 6));
1196 FPU_get_user(instruction_address.selector, (unsigned short __user *) (s+8)); 1047 FPU_get_user(instruction_address.selector,
1197 FPU_get_user(operand_address.offset, (unsigned short __user *) (s+0x0a)); 1048 (unsigned short __user *)(s + 8));
1198 FPU_get_user(operand_address.selector, (unsigned short __user *) (s+0x0c)); 1049 FPU_get_user(operand_address.offset,
1199 RE_ENTRANT_CHECK_ON; 1050 (unsigned short __user *)(s + 0x0a));
1200 s += 0x0e; 1051 FPU_get_user(operand_address.selector,
1201 if ( addr_modes.default_mode == VM86 ) 1052 (unsigned short __user *)(s + 0x0c));
1202 { 1053 RE_ENTRANT_CHECK_ON;
1203 instruction_address.offset 1054 s += 0x0e;
1204 += (instruction_address.selector & 0xf000) << 4; 1055 if (addr_modes.default_mode == VM86) {
1205 operand_address.offset += (operand_address.selector & 0xf000) << 4; 1056 instruction_address.offset
1057 += (instruction_address.selector & 0xf000) << 4;
1058 operand_address.offset +=
1059 (operand_address.selector & 0xf000) << 4;
1060 }
1061 } else {
1062 RE_ENTRANT_CHECK_OFF;
1063 FPU_access_ok(VERIFY_READ, s, 0x1c);
1064 FPU_get_user(control_word, (unsigned short __user *)s);
1065 FPU_get_user(partial_status, (unsigned short __user *)(s + 4));
1066 FPU_get_user(tag_word, (unsigned short __user *)(s + 8));
1067 FPU_get_user(instruction_address.offset,
1068 (unsigned long __user *)(s + 0x0c));
1069 FPU_get_user(instruction_address.selector,
1070 (unsigned short __user *)(s + 0x10));
1071 FPU_get_user(instruction_address.opcode,
1072 (unsigned short __user *)(s + 0x12));
1073 FPU_get_user(operand_address.offset,
1074 (unsigned long __user *)(s + 0x14));
1075 FPU_get_user(operand_address.selector,
1076 (unsigned long __user *)(s + 0x18));
1077 RE_ENTRANT_CHECK_ON;
1078 s += 0x1c;
1206 } 1079 }
1207 }
1208 else
1209 {
1210 RE_ENTRANT_CHECK_OFF;
1211 FPU_access_ok(VERIFY_READ, s, 0x1c);
1212 FPU_get_user(control_word, (unsigned short __user *) s);
1213 FPU_get_user(partial_status, (unsigned short __user *) (s+4));
1214 FPU_get_user(tag_word, (unsigned short __user *) (s+8));
1215 FPU_get_user(instruction_address.offset, (unsigned long __user *) (s+0x0c));
1216 FPU_get_user(instruction_address.selector, (unsigned short __user *) (s+0x10));
1217 FPU_get_user(instruction_address.opcode, (unsigned short __user *) (s+0x12));
1218 FPU_get_user(operand_address.offset, (unsigned long __user *) (s+0x14));
1219 FPU_get_user(operand_address.selector, (unsigned long __user *) (s+0x18));
1220 RE_ENTRANT_CHECK_ON;
1221 s += 0x1c;
1222 }
1223 1080
1224#ifdef PECULIAR_486 1081#ifdef PECULIAR_486
1225 control_word &= ~0xe080; 1082 control_word &= ~0xe080;
1226#endif /* PECULIAR_486 */ 1083#endif /* PECULIAR_486 */
1227 1084
1228 top = (partial_status >> SW_Top_Shift) & 7; 1085 top = (partial_status >> SW_Top_Shift) & 7;
1229 1086
1230 if ( partial_status & ~control_word & CW_Exceptions ) 1087 if (partial_status & ~control_word & CW_Exceptions)
1231 partial_status |= (SW_Summary | SW_Backward); 1088 partial_status |= (SW_Summary | SW_Backward);
1232 else 1089 else
1233 partial_status &= ~(SW_Summary | SW_Backward); 1090 partial_status &= ~(SW_Summary | SW_Backward);
1234 1091
1235 for ( i = 0; i < 8; i++ ) 1092 for (i = 0; i < 8; i++) {
1236 { 1093 tag = tag_word & 3;
1237 tag = tag_word & 3; 1094 tag_word >>= 2;
1238 tag_word >>= 2; 1095
1239 1096 if (tag == TAG_Empty)
1240 if ( tag == TAG_Empty ) 1097 /* New tag is empty. Accept it */
1241 /* New tag is empty. Accept it */ 1098 FPU_settag(i, TAG_Empty);
1242 FPU_settag(i, TAG_Empty); 1099 else if (FPU_gettag(i) == TAG_Empty) {
1243 else if ( FPU_gettag(i) == TAG_Empty ) 1100 /* Old tag is empty and new tag is not empty. New tag is determined
1244 { 1101 by old reg contents */
1245 /* Old tag is empty and new tag is not empty. New tag is determined 1102 if (exponent(&fpu_register(i)) == -EXTENDED_Ebias) {
1246 by old reg contents */ 1103 if (!
1247 if ( exponent(&fpu_register(i)) == - EXTENDED_Ebias ) 1104 (fpu_register(i).sigl | fpu_register(i).
1248 { 1105 sigh))
1249 if ( !(fpu_register(i).sigl | fpu_register(i).sigh) ) 1106 FPU_settag(i, TAG_Zero);
1250 FPU_settag(i, TAG_Zero); 1107 else
1251 else 1108 FPU_settag(i, TAG_Special);
1252 FPU_settag(i, TAG_Special); 1109 } else if (exponent(&fpu_register(i)) ==
1253 } 1110 0x7fff - EXTENDED_Ebias) {
1254 else if ( exponent(&fpu_register(i)) == 0x7fff - EXTENDED_Ebias ) 1111 FPU_settag(i, TAG_Special);
1255 { 1112 } else if (fpu_register(i).sigh & 0x80000000)
1256 FPU_settag(i, TAG_Special); 1113 FPU_settag(i, TAG_Valid);
1257 } 1114 else
1258 else if ( fpu_register(i).sigh & 0x80000000 ) 1115 FPU_settag(i, TAG_Special); /* An Un-normal */
1259 FPU_settag(i, TAG_Valid); 1116 }
1260 else 1117 /* Else old tag is not empty and new tag is not empty. Old tag
1261 FPU_settag(i, TAG_Special); /* An Un-normal */ 1118 remains correct */
1262 } 1119 }
1263 /* Else old tag is not empty and new tag is not empty. Old tag
1264 remains correct */
1265 }
1266
1267 return s;
1268}
1269 1120
1121 return s;
1122}
1270 1123
1271void frstor(fpu_addr_modes addr_modes, u_char __user *data_address) 1124void frstor(fpu_addr_modes addr_modes, u_char __user * data_address)
1272{ 1125{
1273 int i, regnr; 1126 int i, regnr;
1274 u_char __user *s = fldenv(addr_modes, data_address); 1127 u_char __user *s = fldenv(addr_modes, data_address);
1275 int offset = (top & 7) * 10, other = 80 - offset; 1128 int offset = (top & 7) * 10, other = 80 - offset;
1276 1129
1277 /* Copy all registers in stack order. */ 1130 /* Copy all registers in stack order. */
1278 RE_ENTRANT_CHECK_OFF; 1131 RE_ENTRANT_CHECK_OFF;
1279 FPU_access_ok(VERIFY_READ,s,80); 1132 FPU_access_ok(VERIFY_READ, s, 80);
1280 __copy_from_user(register_base+offset, s, other); 1133 __copy_from_user(register_base + offset, s, other);
1281 if ( offset ) 1134 if (offset)
1282 __copy_from_user(register_base, s+other, offset); 1135 __copy_from_user(register_base, s + other, offset);
1283 RE_ENTRANT_CHECK_ON; 1136 RE_ENTRANT_CHECK_ON;
1284 1137
1285 for ( i = 0; i < 8; i++ ) 1138 for (i = 0; i < 8; i++) {
1286 { 1139 regnr = (i + top) & 7;
1287 regnr = (i+top) & 7; 1140 if (FPU_gettag(regnr) != TAG_Empty)
1288 if ( FPU_gettag(regnr) != TAG_Empty ) 1141 /* The loaded data over-rides all other cases. */
1289 /* The loaded data over-rides all other cases. */ 1142 FPU_settag(regnr, FPU_tagof(&st(i)));
1290 FPU_settag(regnr, FPU_tagof(&st(i))); 1143 }
1291 }
1292 1144
1293} 1145}
1294 1146
1295 1147u_char __user *fstenv(fpu_addr_modes addr_modes, u_char __user * d)
1296u_char __user *fstenv(fpu_addr_modes addr_modes, u_char __user *d)
1297{ 1148{
1298 if ( (addr_modes.default_mode == VM86) || 1149 if ((addr_modes.default_mode == VM86) ||
1299 ((addr_modes.default_mode == PM16) 1150 ((addr_modes.default_mode == PM16)
1300 ^ (addr_modes.override.operand_size == OP_SIZE_PREFIX)) ) 1151 ^ (addr_modes.override.operand_size == OP_SIZE_PREFIX))) {
1301 { 1152 RE_ENTRANT_CHECK_OFF;
1302 RE_ENTRANT_CHECK_OFF; 1153 FPU_access_ok(VERIFY_WRITE, d, 14);
1303 FPU_access_ok(VERIFY_WRITE,d,14);
1304#ifdef PECULIAR_486 1154#ifdef PECULIAR_486
1305 FPU_put_user(control_word & ~0xe080, (unsigned long __user *) d); 1155 FPU_put_user(control_word & ~0xe080, (unsigned long __user *)d);
1306#else 1156#else
1307 FPU_put_user(control_word, (unsigned short __user *) d); 1157 FPU_put_user(control_word, (unsigned short __user *)d);
1308#endif /* PECULIAR_486 */ 1158#endif /* PECULIAR_486 */
1309 FPU_put_user(status_word(), (unsigned short __user *) (d+2)); 1159 FPU_put_user(status_word(), (unsigned short __user *)(d + 2));
1310 FPU_put_user(fpu_tag_word, (unsigned short __user *) (d+4)); 1160 FPU_put_user(fpu_tag_word, (unsigned short __user *)(d + 4));
1311 FPU_put_user(instruction_address.offset, (unsigned short __user *) (d+6)); 1161 FPU_put_user(instruction_address.offset,
1312 FPU_put_user(operand_address.offset, (unsigned short __user *) (d+0x0a)); 1162 (unsigned short __user *)(d + 6));
1313 if ( addr_modes.default_mode == VM86 ) 1163 FPU_put_user(operand_address.offset,
1314 { 1164 (unsigned short __user *)(d + 0x0a));
1315 FPU_put_user((instruction_address.offset & 0xf0000) >> 4, 1165 if (addr_modes.default_mode == VM86) {
1316 (unsigned short __user *) (d+8)); 1166 FPU_put_user((instruction_address.
1317 FPU_put_user((operand_address.offset & 0xf0000) >> 4, 1167 offset & 0xf0000) >> 4,
1318 (unsigned short __user *) (d+0x0c)); 1168 (unsigned short __user *)(d + 8));
1319 } 1169 FPU_put_user((operand_address.offset & 0xf0000) >> 4,
1320 else 1170 (unsigned short __user *)(d + 0x0c));
1321 { 1171 } else {
1322 FPU_put_user(instruction_address.selector, (unsigned short __user *) (d+8)); 1172 FPU_put_user(instruction_address.selector,
1323 FPU_put_user(operand_address.selector, (unsigned short __user *) (d+0x0c)); 1173 (unsigned short __user *)(d + 8));
1324 } 1174 FPU_put_user(operand_address.selector,
1325 RE_ENTRANT_CHECK_ON; 1175 (unsigned short __user *)(d + 0x0c));
1326 d += 0x0e; 1176 }
1327 } 1177 RE_ENTRANT_CHECK_ON;
1328 else 1178 d += 0x0e;
1329 { 1179 } else {
1330 RE_ENTRANT_CHECK_OFF; 1180 RE_ENTRANT_CHECK_OFF;
1331 FPU_access_ok(VERIFY_WRITE, d, 7*4); 1181 FPU_access_ok(VERIFY_WRITE, d, 7 * 4);
1332#ifdef PECULIAR_486 1182#ifdef PECULIAR_486
1333 control_word &= ~0xe080; 1183 control_word &= ~0xe080;
1334 /* An 80486 sets nearly all of the reserved bits to 1. */ 1184 /* An 80486 sets nearly all of the reserved bits to 1. */
1335 control_word |= 0xffff0040; 1185 control_word |= 0xffff0040;
1336 partial_status = status_word() | 0xffff0000; 1186 partial_status = status_word() | 0xffff0000;
1337 fpu_tag_word |= 0xffff0000; 1187 fpu_tag_word |= 0xffff0000;
1338 I387.soft.fcs &= ~0xf8000000; 1188 I387.soft.fcs &= ~0xf8000000;
1339 I387.soft.fos |= 0xffff0000; 1189 I387.soft.fos |= 0xffff0000;
1340#endif /* PECULIAR_486 */ 1190#endif /* PECULIAR_486 */
1341 if (__copy_to_user(d, &control_word, 7*4)) 1191 if (__copy_to_user(d, &control_word, 7 * 4))
1342 FPU_abort; 1192 FPU_abort;
1343 RE_ENTRANT_CHECK_ON; 1193 RE_ENTRANT_CHECK_ON;
1344 d += 0x1c; 1194 d += 0x1c;
1345 } 1195 }
1346
1347 control_word |= CW_Exceptions;
1348 partial_status &= ~(SW_Summary | SW_Backward);
1349
1350 return d;
1351}
1352 1196
1197 control_word |= CW_Exceptions;
1198 partial_status &= ~(SW_Summary | SW_Backward);
1199
1200 return d;
1201}
1353 1202
1354void fsave(fpu_addr_modes addr_modes, u_char __user *data_address) 1203void fsave(fpu_addr_modes addr_modes, u_char __user * data_address)
1355{ 1204{
1356 u_char __user *d; 1205 u_char __user *d;
1357 int offset = (top & 7) * 10, other = 80 - offset; 1206 int offset = (top & 7) * 10, other = 80 - offset;
1358 1207
1359 d = fstenv(addr_modes, data_address); 1208 d = fstenv(addr_modes, data_address);
1360 1209
1361 RE_ENTRANT_CHECK_OFF; 1210 RE_ENTRANT_CHECK_OFF;
1362 FPU_access_ok(VERIFY_WRITE,d,80); 1211 FPU_access_ok(VERIFY_WRITE, d, 80);
1363 1212
1364 /* Copy all registers in stack order. */ 1213 /* Copy all registers in stack order. */
1365 if (__copy_to_user(d, register_base+offset, other)) 1214 if (__copy_to_user(d, register_base + offset, other))
1366 FPU_abort; 1215 FPU_abort;
1367 if ( offset ) 1216 if (offset)
1368 if (__copy_to_user(d+other, register_base, offset)) 1217 if (__copy_to_user(d + other, register_base, offset))
1369 FPU_abort; 1218 FPU_abort;
1370 RE_ENTRANT_CHECK_ON; 1219 RE_ENTRANT_CHECK_ON;
1371 1220
1372 finit(); 1221 finit();
1373} 1222}
1374 1223
1375/*===========================================================================*/ 1224/*===========================================================================*/
diff --git a/arch/x86/math-emu/reg_mul.c b/arch/x86/math-emu/reg_mul.c
index 40f50b61bc67..36c37f71f713 100644
--- a/arch/x86/math-emu/reg_mul.c
+++ b/arch/x86/math-emu/reg_mul.c
@@ -20,7 +20,6 @@
20#include "reg_constant.h" 20#include "reg_constant.h"
21#include "fpu_system.h" 21#include "fpu_system.h"
22 22
23
24/* 23/*
25 Multiply two registers to give a register result. 24 Multiply two registers to give a register result.
26 The sources are st(deststnr) and (b,tagb,signb). 25 The sources are st(deststnr) and (b,tagb,signb).
@@ -29,104 +28,88 @@
29/* This routine must be called with non-empty source registers */ 28/* This routine must be called with non-empty source registers */
30int FPU_mul(FPU_REG const *b, u_char tagb, int deststnr, int control_w) 29int FPU_mul(FPU_REG const *b, u_char tagb, int deststnr, int control_w)
31{ 30{
32 FPU_REG *a = &st(deststnr); 31 FPU_REG *a = &st(deststnr);
33 FPU_REG *dest = a; 32 FPU_REG *dest = a;
34 u_char taga = FPU_gettagi(deststnr); 33 u_char taga = FPU_gettagi(deststnr);
35 u_char saved_sign = getsign(dest); 34 u_char saved_sign = getsign(dest);
36 u_char sign = (getsign(a) ^ getsign(b)); 35 u_char sign = (getsign(a) ^ getsign(b));
37 int tag; 36 int tag;
38
39 37
40 if ( !(taga | tagb) ) 38 if (!(taga | tagb)) {
41 { 39 /* Both regs Valid, this should be the most common case. */
42 /* Both regs Valid, this should be the most common case. */
43 40
44 tag = FPU_u_mul(a, b, dest, control_w, sign, exponent(a) + exponent(b)); 41 tag =
45 if ( tag < 0 ) 42 FPU_u_mul(a, b, dest, control_w, sign,
46 { 43 exponent(a) + exponent(b));
47 setsign(dest, saved_sign); 44 if (tag < 0) {
48 return tag; 45 setsign(dest, saved_sign);
46 return tag;
47 }
48 FPU_settagi(deststnr, tag);
49 return tag;
49 } 50 }
50 FPU_settagi(deststnr, tag);
51 return tag;
52 }
53 51
54 if ( taga == TAG_Special ) 52 if (taga == TAG_Special)
55 taga = FPU_Special(a); 53 taga = FPU_Special(a);
56 if ( tagb == TAG_Special ) 54 if (tagb == TAG_Special)
57 tagb = FPU_Special(b); 55 tagb = FPU_Special(b);
58 56
59 if ( ((taga == TAG_Valid) && (tagb == TW_Denormal)) 57 if (((taga == TAG_Valid) && (tagb == TW_Denormal))
60 || ((taga == TW_Denormal) && (tagb == TAG_Valid)) 58 || ((taga == TW_Denormal) && (tagb == TAG_Valid))
61 || ((taga == TW_Denormal) && (tagb == TW_Denormal)) ) 59 || ((taga == TW_Denormal) && (tagb == TW_Denormal))) {
62 { 60 FPU_REG x, y;
63 FPU_REG x, y; 61 if (denormal_operand() < 0)
64 if ( denormal_operand() < 0 ) 62 return FPU_Exception;
65 return FPU_Exception;
66
67 FPU_to_exp16(a, &x);
68 FPU_to_exp16(b, &y);
69 tag = FPU_u_mul(&x, &y, dest, control_w, sign,
70 exponent16(&x) + exponent16(&y));
71 if ( tag < 0 )
72 {
73 setsign(dest, saved_sign);
74 return tag;
75 }
76 FPU_settagi(deststnr, tag);
77 return tag;
78 }
79 else if ( (taga <= TW_Denormal) && (tagb <= TW_Denormal) )
80 {
81 if ( ((tagb == TW_Denormal) || (taga == TW_Denormal))
82 && (denormal_operand() < 0) )
83 return FPU_Exception;
84 63
85 /* Must have either both arguments == zero, or 64 FPU_to_exp16(a, &x);
86 one valid and the other zero. 65 FPU_to_exp16(b, &y);
87 The result is therefore zero. */ 66 tag = FPU_u_mul(&x, &y, dest, control_w, sign,
88 FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr); 67 exponent16(&x) + exponent16(&y));
89 /* The 80486 book says that the answer is +0, but a real 68 if (tag < 0) {
90 80486 behaves this way. 69 setsign(dest, saved_sign);
91 IEEE-754 apparently says it should be this way. */ 70 return tag;
92 setsign(dest, sign); 71 }
93 return TAG_Zero; 72 FPU_settagi(deststnr, tag);
94 } 73 return tag;
95 /* Must have infinities, NaNs, etc */ 74 } else if ((taga <= TW_Denormal) && (tagb <= TW_Denormal)) {
96 else if ( (taga == TW_NaN) || (tagb == TW_NaN) ) 75 if (((tagb == TW_Denormal) || (taga == TW_Denormal))
97 { 76 && (denormal_operand() < 0))
98 return real_2op_NaN(b, tagb, deststnr, &st(0)); 77 return FPU_Exception;
99 }
100 else if ( ((taga == TW_Infinity) && (tagb == TAG_Zero))
101 || ((tagb == TW_Infinity) && (taga == TAG_Zero)) )
102 {
103 return arith_invalid(deststnr); /* Zero*Infinity is invalid */
104 }
105 else if ( ((taga == TW_Denormal) || (tagb == TW_Denormal))
106 && (denormal_operand() < 0) )
107 {
108 return FPU_Exception;
109 }
110 else if (taga == TW_Infinity)
111 {
112 FPU_copy_to_regi(a, TAG_Special, deststnr);
113 setsign(dest, sign);
114 return TAG_Special;
115 }
116 else if (tagb == TW_Infinity)
117 {
118 FPU_copy_to_regi(b, TAG_Special, deststnr);
119 setsign(dest, sign);
120 return TAG_Special;
121 }
122 78
79 /* Must have either both arguments == zero, or
80 one valid and the other zero.
81 The result is therefore zero. */
82 FPU_copy_to_regi(&CONST_Z, TAG_Zero, deststnr);
83 /* The 80486 book says that the answer is +0, but a real
84 80486 behaves this way.
85 IEEE-754 apparently says it should be this way. */
86 setsign(dest, sign);
87 return TAG_Zero;
88 }
89 /* Must have infinities, NaNs, etc */
90 else if ((taga == TW_NaN) || (tagb == TW_NaN)) {
91 return real_2op_NaN(b, tagb, deststnr, &st(0));
92 } else if (((taga == TW_Infinity) && (tagb == TAG_Zero))
93 || ((tagb == TW_Infinity) && (taga == TAG_Zero))) {
94 return arith_invalid(deststnr); /* Zero*Infinity is invalid */
95 } else if (((taga == TW_Denormal) || (tagb == TW_Denormal))
96 && (denormal_operand() < 0)) {
97 return FPU_Exception;
98 } else if (taga == TW_Infinity) {
99 FPU_copy_to_regi(a, TAG_Special, deststnr);
100 setsign(dest, sign);
101 return TAG_Special;
102 } else if (tagb == TW_Infinity) {
103 FPU_copy_to_regi(b, TAG_Special, deststnr);
104 setsign(dest, sign);
105 return TAG_Special;
106 }
123#ifdef PARANOID 107#ifdef PARANOID
124 else 108 else {
125 { 109 EXCEPTION(EX_INTERNAL | 0x102);
126 EXCEPTION(EX_INTERNAL|0x102); 110 return FPU_Exception;
127 return FPU_Exception; 111 }
128 } 112#endif /* PARANOID */
129#endif /* PARANOID */
130 113
131 return 0; 114 return 0;
132} 115}
diff --git a/arch/x86/math-emu/status_w.h b/arch/x86/math-emu/status_w.h
index 59e73302aa60..54a3f226982d 100644
--- a/arch/x86/math-emu/status_w.h
+++ b/arch/x86/math-emu/status_w.h
@@ -10,7 +10,7 @@
10#ifndef _STATUS_H_ 10#ifndef _STATUS_H_
11#define _STATUS_H_ 11#define _STATUS_H_
12 12
13#include "fpu_emu.h" /* for definition of PECULIAR_486 */ 13#include "fpu_emu.h" /* for definition of PECULIAR_486 */
14 14
15#ifdef __ASSEMBLY__ 15#ifdef __ASSEMBLY__
16#define Const__(x) $##x 16#define Const__(x) $##x
@@ -34,7 +34,7 @@
34#define SW_Denorm_Op Const__(0x0002) /* denormalized operand */ 34#define SW_Denorm_Op Const__(0x0002) /* denormalized operand */
35#define SW_Invalid Const__(0x0001) /* invalid operation */ 35#define SW_Invalid Const__(0x0001) /* invalid operation */
36 36
37#define SW_Exc_Mask Const__(0x27f) /* Status word exception bit mask */ 37#define SW_Exc_Mask Const__(0x27f) /* Status word exception bit mask */
38 38
39#ifndef __ASSEMBLY__ 39#ifndef __ASSEMBLY__
40 40
@@ -50,8 +50,8 @@
50 ((partial_status & ~SW_Top & 0xffff) | ((top << SW_Top_Shift) & SW_Top)) 50 ((partial_status & ~SW_Top & 0xffff) | ((top << SW_Top_Shift) & SW_Top))
51static inline void setcc(int cc) 51static inline void setcc(int cc)
52{ 52{
53 partial_status &= ~(SW_C0|SW_C1|SW_C2|SW_C3); 53 partial_status &= ~(SW_C0 | SW_C1 | SW_C2 | SW_C3);
54 partial_status |= (cc) & (SW_C0|SW_C1|SW_C2|SW_C3); 54 partial_status |= (cc) & (SW_C0 | SW_C1 | SW_C2 | SW_C3);
55} 55}
56 56
57#ifdef PECULIAR_486 57#ifdef PECULIAR_486