diff options
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 |
38 | void Un_impl(void) | 37 | void 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 | */ |
80 | void FPU_illegal(void) | 76 | void FPU_illegal(void) |
81 | { | 77 | { |
82 | math_abort(FPU_info,SIGILL); | 78 | math_abort(FPU_info, SIGILL); |
83 | } | 79 | } |
84 | 80 | ||
85 | |||
86 | |||
87 | void FPU_printall(void) | 81 | void 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 |
133 | if ( partial_status & SW_Backward ) printk("SW: backward compatibility\n"); | 124 | if (partial_status & SW_Backward) |
134 | if ( partial_status & SW_C3 ) printk("SW: condition bit 3\n"); | 125 | printk("SW: backward compatibility\n"); |
135 | if ( partial_status & SW_C2 ) printk("SW: condition bit 2\n"); | 126 | if (partial_status & SW_C3) |
136 | if ( partial_status & SW_C1 ) printk("SW: condition bit 1\n"); | 127 | printk("SW: condition bit 3\n"); |
137 | if ( partial_status & SW_C0 ) printk("SW: condition bit 0\n"); | 128 | if (partial_status & SW_C2) |
138 | if ( partial_status & SW_Summary ) printk("SW: exception summary\n"); | 129 | printk("SW: condition bit 2\n"); |
139 | if ( partial_status & SW_Stack_Fault ) printk("SW: stack fault\n"); | 130 | if (partial_status & SW_C1) |
140 | if ( partial_status & SW_Precision ) printk("SW: loss of precision\n"); | 131 | printk("SW: condition bit 1\n"); |
141 | if ( partial_status & SW_Underflow ) printk("SW: underflow\n"); | 132 | if (partial_status & SW_C0) |
142 | if ( partial_status & SW_Overflow ) printk("SW: overflow\n"); | 133 | printk("SW: condition bit 0\n"); |
143 | if ( partial_status & SW_Zero_Div ) printk("SW: divide by zero\n"); | 134 | if (partial_status & SW_Summary) |
144 | if ( partial_status & SW_Denorm_Op ) printk("SW: denormalized operand\n"); | 135 | printk("SW: exception summary\n"); |
145 | if ( 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, | |
159 | printk(" 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 | ||
201 | static struct { | 209 | static 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 | ||
296 | asmlinkage void FPU_exception(int n) | 305 | asmlinkage 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 */ |
375 | int real_1op_NaN(FPU_REG *a) | 377 | int 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 */ |
419 | int real_2op_NaN(FPU_REG const *b, u_char tagb, | 416 | int 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 */ |
513 | asmlinkage int arith_invalid(int deststnr) | 500 | asmlinkage 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 */ |
530 | asmlinkage int FPU_divide_by_zero(int deststnr, u_char sign) | 515 | asmlinkage 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 */ |
551 | int set_precision_flag(int flags) | 534 | int 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 */ |
568 | asmlinkage void set_precision_flag_up(void) | 547 | asmlinkage 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 */ |
578 | asmlinkage void set_precision_flag_down(void) | 556 | asmlinkage 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 | |||
590 | asmlinkage int denormal_operand(void) | 565 | asmlinkage 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 | 576 | asmlinkage int arith_overflow(FPU_REG * dest) | |
605 | asmlinkage 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 | ||
638 | asmlinkage int arith_underflow(FPU_REG *dest) | 602 | } |
639 | { | ||
640 | int tag = TAG_Valid; | ||
641 | 603 | ||
642 | if ( control_word & CW_Underflow ) | 604 | asmlinkage 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 | ||
675 | void FPU_stack_overflow(void) | 633 | void 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 | |||
692 | void FPU_stack_underflow(void) | 648 | void 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 | |||
708 | void FPU_stack_underflow_i(int i) | 662 | void 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 | |||
724 | void FPU_stack_underflow_pop(int i) | 676 | void 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 | |||
19 | void fadd__(void) | 18 | void 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 | |||
28 | void fmul__(void) | 26 | void 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 | |||
38 | void fsub__(void) | 34 | void 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 | |||
46 | void fsubr_(void) | 41 | void 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 | |||
54 | void fdiv__(void) | 48 | void 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 | |||
62 | void fdivr_(void) | 55 | void 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 | |||
71 | void fadd_i(void) | 62 | void 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 | |||
80 | void fmul_i(void) | 70 | void 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 | |||
88 | void fsubri(void) | 77 | void 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 | |||
96 | void fsub_i(void) | 84 | void 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 | |||
104 | void fdivri(void) | 91 | void 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 | |||
112 | void fdiv_i(void) | 98 | void 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 | |||
121 | void faddp_(void) | 105 | void 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 | |||
131 | void fmulp_(void) | 114 | void 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 | |||
141 | void fsubrp(void) | 122 | void 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 | |||
150 | void fsubp_(void) | 130 | void 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 | |||
159 | void fdivrp(void) | 138 | void 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 | |||
168 | void fdivp_(void) | 146 | void 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 | |||
20 | static void fnop(void) | 19 | static void fnop(void) |
21 | { | 20 | { |
22 | } | 21 | } |
23 | 22 | ||
24 | static void fclex(void) | 23 | static 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 */ |
33 | void finit(void) | 33 | void 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 | ||
56 | static FUNC const finit_table[] = { | 56 | static 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 | ||
61 | void finit_(void) | 61 | void finit_(void) |
62 | { | 62 | { |
63 | (finit_table[FPU_rm])(); | 63 | (finit_table[FPU_rm]) (); |
64 | } | 64 | } |
65 | 65 | ||
66 | |||
67 | static void fstsw_ax(void) | 66 | static 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 | ||
73 | static FUNC const fstsw_table[] = { | 72 | static 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 | ||
78 | void fstsw_(void) | 77 | void fstsw_(void) |
79 | { | 78 | { |
80 | (fstsw_table[FPU_rm])(); | 79 | (fstsw_table[FPU_rm]) (); |
81 | } | 80 | } |
82 | 81 | ||
83 | |||
84 | static FUNC const fp_nop_table[] = { | 82 | static 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 | ||
89 | void fp_nop(void) | 87 | void fp_nop(void) |
90 | { | 88 | { |
91 | (fp_nop_table[FPU_rm])(); | 89 | (fp_nop_table[FPU_rm]) (); |
92 | } | 90 | } |
93 | 91 | ||
94 | |||
95 | void fld_i_(void) | 92 | void 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 | ||
127 | void fxch_i(void) | 120 | void 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 | ||
176 | void ffree_(void) | 163 | void 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 | |||
183 | void ffreep(void) | 169 | void 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 | |||
191 | void fst_i_(void) | 176 | void 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 | |||
198 | void fstp_i(void) | 182 | void 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 | ||
114 | struct address { | 111 | struct 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 | }; |
120 | struct fpu__reg { | 117 | struct fpu__reg { |
121 | unsigned sigl; | 118 | unsigned sigl; |
122 | unsigned sigh; | 119 | unsigned sigh; |
123 | short exp; | 120 | short exp; |
124 | }; | 121 | }; |
125 | 122 | ||
126 | typedef void (*FUNC)(void); | 123 | typedef void (*FUNC) (void); |
127 | typedef struct fpu__reg FPU_REG; | 124 | typedef struct fpu__reg FPU_REG; |
128 | typedef void (*FUNC_ST0)(FPU_REG *st0_ptr, u_char st0_tag); | 125 | typedef void (*FUNC_ST0) (FPU_REG * st0_ptr, u_char st0_tag); |
129 | typedef struct { u_char address_size, operand_size, segment; } | 126 | typedef 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: */ |
132 | typedef struct { overrides override; | 130 | typedef 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 | ||
169 | static inline void reg_copy(FPU_REG const *x, FPU_REG *y) | 169 | static 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 | ||
191 | asmlinkage int FPU_normalize(FPU_REG *x); | 190 | asmlinkage int FPU_normalize(FPU_REG * x); |
192 | asmlinkage int FPU_normalize_nuo(FPU_REG *x); | 191 | asmlinkage int FPU_normalize_nuo(FPU_REG * x); |
193 | asmlinkage int FPU_u_sub(FPU_REG const *arg1, FPU_REG const *arg2, | 192 | asmlinkage 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); |
196 | asmlinkage int FPU_u_mul(FPU_REG const *arg1, FPU_REG const *arg2, | 195 | asmlinkage 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); |
199 | asmlinkage int FPU_u_div(FPU_REG const *arg1, FPU_REG const *arg2, | 198 | asmlinkage 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); |
201 | asmlinkage int FPU_u_add(FPU_REG const *arg1, FPU_REG const *arg2, | 200 | asmlinkage 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); |
204 | asmlinkage int wm_sqrt(FPU_REG *n, int dummy1, int dummy2, | 203 | asmlinkage 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); |
206 | asmlinkage unsigned FPU_shrx(void *l, unsigned x); | 205 | asmlinkage unsigned FPU_shrx(void *l, unsigned x); |
207 | asmlinkage unsigned FPU_shrxs(void *v, unsigned x); | 206 | asmlinkage unsigned FPU_shrxs(void *v, unsigned x); |
208 | asmlinkage unsigned long FPU_div_small(unsigned long long *x, unsigned long y); | 207 | asmlinkage unsigned long FPU_div_small(unsigned long long *x, unsigned long y); |
209 | asmlinkage int FPU_round(FPU_REG *arg, unsigned int extent, int dummy, | 208 | asmlinkage 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 | ||
58 | static FUNC const st_instr_table[64] = { | 58 | static 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 | ||
71 | static FUNC const st_instr_table[64] = { | 71 | static 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 | ||
100 | static u_char const type_table[64] = { | 99 | static 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 | ||
113 | static u_char const type_table[64] = { | 112 | static 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 |
128 | u_char emulating=0; | 126 | u_char emulating = 0; |
129 | #endif /* RE_ENTRANT_CHECKING */ | 127 | #endif /* RE_ENTRANT_CHECKING */ |
130 | 128 | ||
131 | static int valid_prefix(u_char *Byte, u_char __user **fpu_eip, | 129 | static int valid_prefix(u_char * Byte, u_char __user ** fpu_eip, |
132 | overrides *override); | 130 | overrides * override); |
133 | 131 | ||
134 | asmlinkage void math_emulate(long arg) | 132 | asmlinkage 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 | |||
230 | do_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 | ||
549 | FPU_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 | ||
556 | FPU_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. */ |
583 | static int valid_prefix(u_char *Byte, u_char __user **fpu_eip, | 583 | static 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 | 659 | void math_abort(struct info *info, unsigned int signal) | |
664 | void 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 | ||
683 | int restore_i387_soft(void *s387, struct _fpstate __user *buf) | 676 | int 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 | |||
729 | int save_i387_soft(void *s387, struct _fpstate __user * buf) | 722 | int 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 | 19 | static void fchs(FPU_REG * st0_ptr, u_char st0tag) | |
20 | static 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 | 28 | static void fabs(FPU_REG * st0_ptr, u_char st0tag) | |
32 | static 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 | 37 | static void ftst_(FPU_REG * st0_ptr, u_char st0tag) | |
44 | static 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 | 88 | static void fxam(FPU_REG * st0_ptr, u_char st0tag) | |
99 | static 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 | |||
135 | static FUNC_ST0 const fp_etc_table[] = { | 122 | static 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 | ||
140 | void FPU_etc(void) | 127 | void 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 @@ | |||
5 | extern void FPU_illegal(void); | 5 | extern void FPU_illegal(void); |
6 | extern void FPU_printall(void); | 6 | extern void FPU_printall(void); |
7 | asmlinkage void FPU_exception(int n); | 7 | asmlinkage void FPU_exception(int n); |
8 | extern int real_1op_NaN(FPU_REG *a); | 8 | extern int real_1op_NaN(FPU_REG * a); |
9 | extern int real_2op_NaN(FPU_REG const *b, u_char tagb, int deststnr, | 9 | extern int real_2op_NaN(FPU_REG const *b, u_char tagb, int deststnr, |
10 | FPU_REG const *defaultNaN); | 10 | FPU_REG const *defaultNaN); |
11 | asmlinkage int arith_invalid(int deststnr); | 11 | asmlinkage int arith_invalid(int deststnr); |
@@ -14,8 +14,8 @@ extern int set_precision_flag(int flags); | |||
14 | asmlinkage void set_precision_flag_up(void); | 14 | asmlinkage void set_precision_flag_up(void); |
15 | asmlinkage void set_precision_flag_down(void); | 15 | asmlinkage void set_precision_flag_down(void); |
16 | asmlinkage int denormal_operand(void); | 16 | asmlinkage int denormal_operand(void); |
17 | asmlinkage int arith_overflow(FPU_REG *dest); | 17 | asmlinkage int arith_overflow(FPU_REG * dest); |
18 | asmlinkage int arith_underflow(FPU_REG *dest); | 18 | asmlinkage int arith_underflow(FPU_REG * dest); |
19 | extern void FPU_stack_overflow(void); | 19 | extern void FPU_stack_overflow(void); |
20 | extern void FPU_stack_underflow(void); | 20 | extern void FPU_stack_underflow(void); |
21 | extern void FPU_stack_underflow_i(int i); | 21 | extern void FPU_stack_underflow_i(int i); |
@@ -66,7 +66,7 @@ extern int FPU_Special(FPU_REG const *ptr); | |||
66 | extern int isNaN(FPU_REG const *ptr); | 66 | extern int isNaN(FPU_REG const *ptr); |
67 | extern void FPU_pop(void); | 67 | extern void FPU_pop(void); |
68 | extern int FPU_empty_i(int stnr); | 68 | extern int FPU_empty_i(int stnr); |
69 | extern int FPU_stackoverflow(FPU_REG **st_new_ptr); | 69 | extern int FPU_stackoverflow(FPU_REG ** st_new_ptr); |
70 | extern void FPU_copy_to_regi(FPU_REG const *r, u_char tag, int stnr); | 70 | extern void FPU_copy_to_regi(FPU_REG const *r, u_char tag, int stnr); |
71 | extern void FPU_copy_to_reg1(FPU_REG const *r, u_char tag); | 71 | extern void FPU_copy_to_reg1(FPU_REG const *r, u_char tag); |
72 | extern void FPU_copy_to_reg0(FPU_REG const *r, u_char tag); | 72 | extern void FPU_copy_to_reg0(FPU_REG const *r, u_char tag); |
@@ -75,26 +75,28 @@ extern void FPU_triga(void); | |||
75 | extern void FPU_trigb(void); | 75 | extern void FPU_trigb(void); |
76 | /* get_address.c */ | 76 | /* get_address.c */ |
77 | extern void __user *FPU_get_address(u_char FPU_modrm, unsigned long *fpu_eip, | 77 | extern 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); | ||
79 | extern void __user *FPU_get_address_16(u_char FPU_modrm, unsigned long *fpu_eip, | 80 | extern 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 */ |
82 | extern int FPU_load_store(u_char type, fpu_addr_modes addr_modes, | 84 | extern 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 */ |
85 | extern int poly_2xm1(u_char sign, FPU_REG *arg, FPU_REG *result); | 87 | extern int poly_2xm1(u_char sign, FPU_REG * arg, FPU_REG * result); |
86 | /* poly_atan.c */ | 88 | /* poly_atan.c */ |
87 | extern void poly_atan(FPU_REG *st0_ptr, u_char st0_tag, FPU_REG *st1_ptr, | 89 | extern 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 */ |
90 | extern void poly_l2(FPU_REG *st0_ptr, FPU_REG *st1_ptr, u_char st1_sign); | 92 | extern void poly_l2(FPU_REG * st0_ptr, FPU_REG * st1_ptr, u_char st1_sign); |
91 | extern int poly_l2p1(u_char s0, u_char s1, FPU_REG *r0, FPU_REG *r1, | 93 | extern 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 */ |
94 | extern void poly_sine(FPU_REG *st0_ptr); | 96 | extern void poly_sine(FPU_REG * st0_ptr); |
95 | extern void poly_cos(FPU_REG *st0_ptr); | 97 | extern void poly_cos(FPU_REG * st0_ptr); |
96 | /* poly_tan.c */ | 98 | /* poly_tan.c */ |
97 | extern void poly_tan(FPU_REG *st0_ptr); | 99 | extern void poly_tan(FPU_REG * st0_ptr); |
98 | /* reg_add_sub.c */ | 100 | /* reg_add_sub.c */ |
99 | extern int FPU_add(FPU_REG const *b, u_char tagb, int destrnr, int control_w); | 101 | extern int FPU_add(FPU_REG const *b, u_char tagb, int destrnr, int control_w); |
100 | extern int FPU_sub(int flags, int rm, int control_w); | 102 | extern 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 */ |
110 | extern void fconst(void); | 112 | extern void fconst(void); |
111 | /* reg_ld_str.c */ | 113 | /* reg_ld_str.c */ |
112 | extern int FPU_load_extended(long double __user *s, int stnr); | 114 | extern int FPU_load_extended(long double __user * s, int stnr); |
113 | extern int FPU_load_double(double __user *dfloat, FPU_REG *loaded_data); | 115 | extern int FPU_load_double(double __user * dfloat, FPU_REG * loaded_data); |
114 | extern int FPU_load_single(float __user *single, FPU_REG *loaded_data); | 116 | extern int FPU_load_single(float __user * single, FPU_REG * loaded_data); |
115 | extern int FPU_load_int64(long long __user *_s); | 117 | extern int FPU_load_int64(long long __user * _s); |
116 | extern int FPU_load_int32(long __user *_s, FPU_REG *loaded_data); | 118 | extern int FPU_load_int32(long __user * _s, FPU_REG * loaded_data); |
117 | extern int FPU_load_int16(short __user *_s, FPU_REG *loaded_data); | 119 | extern int FPU_load_int16(short __user * _s, FPU_REG * loaded_data); |
118 | extern int FPU_load_bcd(u_char __user *s); | 120 | extern int FPU_load_bcd(u_char __user * s); |
119 | extern int FPU_store_extended(FPU_REG *st0_ptr, u_char st0_tag, | 121 | extern int FPU_store_extended(FPU_REG * st0_ptr, u_char st0_tag, |
120 | long double __user *d); | 122 | long double __user * d); |
121 | extern int FPU_store_double(FPU_REG *st0_ptr, u_char st0_tag, double __user *dfloat); | 123 | extern int FPU_store_double(FPU_REG * st0_ptr, u_char st0_tag, |
122 | extern int FPU_store_single(FPU_REG *st0_ptr, u_char st0_tag, float __user *single); | 124 | double __user * dfloat); |
123 | extern int FPU_store_int64(FPU_REG *st0_ptr, u_char st0_tag, long long __user *d); | 125 | extern int FPU_store_single(FPU_REG * st0_ptr, u_char st0_tag, |
124 | extern int FPU_store_int32(FPU_REG *st0_ptr, u_char st0_tag, long __user *d); | 126 | float __user * single); |
125 | extern int FPU_store_int16(FPU_REG *st0_ptr, u_char st0_tag, short __user *d); | 127 | extern int FPU_store_int64(FPU_REG * st0_ptr, u_char st0_tag, |
126 | extern int FPU_store_bcd(FPU_REG *st0_ptr, u_char st0_tag, u_char __user *d); | 128 | long long __user * d); |
127 | extern int FPU_round_to_int(FPU_REG *r, u_char tag); | 129 | extern int FPU_store_int32(FPU_REG * st0_ptr, u_char st0_tag, long __user * d); |
128 | extern u_char __user *fldenv(fpu_addr_modes addr_modes, u_char __user *s); | 130 | extern int FPU_store_int16(FPU_REG * st0_ptr, u_char st0_tag, short __user * d); |
129 | extern void frstor(fpu_addr_modes addr_modes, u_char __user *data_address); | 131 | extern int FPU_store_bcd(FPU_REG * st0_ptr, u_char st0_tag, u_char __user * d); |
130 | extern u_char __user *fstenv(fpu_addr_modes addr_modes, u_char __user *d); | 132 | extern int FPU_round_to_int(FPU_REG * r, u_char tag); |
131 | extern void fsave(fpu_addr_modes addr_modes, u_char __user *data_address); | 133 | extern u_char __user *fldenv(fpu_addr_modes addr_modes, u_char __user * s); |
132 | extern int FPU_tagof(FPU_REG *ptr); | 134 | extern void frstor(fpu_addr_modes addr_modes, u_char __user * data_address); |
135 | extern u_char __user *fstenv(fpu_addr_modes addr_modes, u_char __user * d); | ||
136 | extern void fsave(fpu_addr_modes addr_modes, u_char __user * data_address); | ||
137 | extern int FPU_tagof(FPU_REG * ptr); | ||
133 | /* reg_mul.c */ | 138 | /* reg_mul.c */ |
134 | extern int FPU_mul(FPU_REG const *b, u_char tagb, int deststnr, int control_w); | 139 | extern int FPU_mul(FPU_REG const *b, u_char tagb, int deststnr, int control_w); |
135 | 140 | ||
136 | extern int FPU_div(int flags, int regrm, int control_w); | 141 | extern int FPU_div(int flags, int regrm, int control_w); |
137 | /* reg_convert.c */ | 142 | /* reg_convert.c */ |
138 | extern int FPU_to_exp16(FPU_REG const *a, FPU_REG *x); | 143 | extern 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 | |||
18 | void FPU_pop(void) | 17 | void 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 | |||
25 | int FPU_gettag0(void) | 23 | int 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 | |||
31 | int FPU_gettagi(int stnr) | 28 | int 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 | |||
37 | int FPU_gettag(int regnr) | 33 | int 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 | |||
43 | void FPU_settag0(int tag) | 38 | void 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 | |||
52 | void FPU_settagi(int stnr, int tag) | 46 | void 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 | |||
61 | void FPU_settag(int regnr, int tag) | 54 | void 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 | |||
69 | int FPU_Special(FPU_REG const *ptr) | 61 | int 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 | |||
83 | int isNaN(FPU_REG const *ptr) | 74 | int 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 | |||
90 | int FPU_empty_i(int stnr) | 80 | int 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 | 87 | int FPU_stackoverflow(FPU_REG ** st_new_ptr) | |
98 | int 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 | |||
106 | void FPU_copy_to_regi(FPU_REG const *r, u_char tag, int stnr) | 94 | void 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 | ||
112 | void FPU_copy_to_reg1(FPU_REG const *r, u_char tag) | 100 | void 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 | ||
118 | void FPU_copy_to_reg0(FPU_REG const *r, u_char tag) | 106 | void 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 | ||
20 | static void rem_kernel(unsigned long long st0, unsigned long long *y, | 20 | static 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 */ |
34 | static int trig_arg(FPU_REG *st0_ptr, int even) | 33 | static 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 */ |
152 | static void convert_l2reg(long const *arg, int deststnr) | 151 | static 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 | ||
180 | static 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 | |||
179 | static 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 | 191 | static void single_arg_2_error(FPU_REG * st0_ptr, u_char st0_tag) | |
193 | static 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 | ||
242 | static void f2xm1(FPU_REG *st0_ptr, u_char tag) | 232 | static 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 | 275 | static void fptan(FPU_REG * st0_ptr, u_char st0_tag) | |
290 | static 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 | ||
378 | static void fxtract(FPU_REG *st0_ptr, u_char st0_tag) | 354 | static 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 | |||
470 | static void fdecstp(void) | 435 | static void fdecstp(void) |
471 | { | 436 | { |
472 | clear_C1(); | 437 | clear_C1(); |
473 | top--; | 438 | top--; |
474 | } | 439 | } |
475 | 440 | ||
476 | static void fincstp(void) | 441 | static void fincstp(void) |
477 | { | 442 | { |
478 | clear_C1(); | 443 | clear_C1(); |
479 | top++; | 444 | top++; |
480 | } | 445 | } |
481 | 446 | ||
482 | 447 | static void fsqrt_(FPU_REG * st0_ptr, u_char st0_tag) | |
483 | static 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 | ||
548 | static void frndint_(FPU_REG *st0_ptr, u_char st0_tag) | 503 | } |
504 | |||
505 | static 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 | ||
595 | static 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 | |||
549 | static 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 | ||
668 | static 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: | 610 | static 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 | ||
754 | static void fcos(FPU_REG *st0_ptr, u_char st0_tag) | 680 | static 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 | 685 | static void fsincos(FPU_REG * st0_ptr, u_char st0_tag) | |
760 | static 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 | */ |
828 | static void rem_kernel(unsigned long long st0, unsigned long long *y, | 745 | static 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. */ |
863 | static void do_fprem(FPU_REG *st0_ptr, u_char st0_tag, int round) | 778 | static 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 */ |
1125 | static void fyl2x(FPU_REG *st0_ptr, u_char st0_tag) | 1020 | static 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 | 1191 | static void fpatan(FPU_REG * st0_ptr, u_char st0_tag) | |
1330 | static 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 | 1301 | static void fprem(FPU_REG * st0_ptr, u_char st0_tag) | |
1461 | static 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 | 1306 | static void fprem1(FPU_REG * st0_ptr, u_char st0_tag) | |
1467 | static 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 | 1311 | static void fyl2xp1(FPU_REG * st0_ptr, u_char st0_tag) | |
1473 | static 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 | 1480 | static void fscale(FPU_REG * st0_ptr, u_char st0_tag) | |
1666 | static 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 | ||
1826 | static FUNC_ST0 const trig_table_a[] = { | 1626 | static 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 | ||
1831 | void FPU_triga(void) | 1631 | void 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 | 1636 | static FUNC_ST0 const trig_table_b[] = { | |
1837 | static 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 | ||
1842 | void FPU_trigb(void) | 1640 | void 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 | ||
33 | static int reg_offset[] = { | 31 | static 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 | ||
46 | static int reg_offset_vm86[] = { | 44 | static 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 | ||
62 | static int reg_offset_pm[] = { | 60 | static 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 */ |
77 | static int sib(int mod, unsigned long *fpu_eip) | 74 | static 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 | ||
135 | static unsigned long vm86_segment(u_char segment, | 125 | static 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. */ |
152 | static long pm_address(u_char FPU_modrm, u_char segment, | 139 | static 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 | ||
233 | void __user *FPU_get_address(u_char FPU_modrm, unsigned long *fpu_eip, | 213 | void __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 = ®_(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 | |||
298 | void __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 | ||
327 | void __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 | |||
38 | static u_char const type_table[32] = { | 36 | static 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 | ||
49 | u_char const data_sizes_16[32] = { | 47 | u_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 | ||
56 | static u_char const data_sizes_32[32] = { | 54 | static 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 | ||
63 | int FPU_load_store(u_char type, fpu_addr_modes addr_modes, | 61 | int 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 | */ |
23 | typedef struct { | 23 | typedef 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 | ||
29 | asmlinkage void mul64(unsigned long long const *a, unsigned long long const *b, | 29 | asmlinkage 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 | ||
34 | asmlinkage void mul32_Xsig(Xsig *, const unsigned long mult); | 34 | asmlinkage void mul32_Xsig(Xsig *, const unsigned long mult); |
35 | asmlinkage void mul64_Xsig(Xsig *, const unsigned long long *mult); | 35 | asmlinkage void mul64_Xsig(Xsig *, const unsigned long long *mult); |
36 | asmlinkage void mul_Xsig_Xsig(Xsig *dest, const Xsig *mult); | 36 | asmlinkage void mul_Xsig_Xsig(Xsig * dest, const Xsig * mult); |
37 | 37 | ||
38 | asmlinkage void shr_Xsig(Xsig *, const int n); | 38 | asmlinkage void shr_Xsig(Xsig *, const int n); |
39 | asmlinkage int round_Xsig(Xsig *); | 39 | asmlinkage int round_Xsig(Xsig *); |
40 | asmlinkage int norm_Xsig(Xsig *); | 40 | asmlinkage int norm_Xsig(Xsig *); |
41 | asmlinkage void div_Xsig(Xsig *x1, const Xsig *x2, const Xsig *dest); | 41 | asmlinkage 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); | |||
63 | static inline unsigned long mul_32_32(const unsigned long arg1, | 62 | static 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. */ |
76 | static inline void add_Xsig_Xsig(Xsig *dest, const Xsig *x2) | 73 | static 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! */ |
91 | static inline void add_two_Xsig(Xsig *dest, const Xsig *x2, long int *exp) | 87 | static 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. */ |
111 | static inline void negate_Xsig(Xsig *x) | 104 | static 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 |
22 | static const unsigned long long lterms[HIPOWER] = | 21 | static 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 | ||
37 | static const Xsig hiterm = MK_XSIG(0xb17217f7, 0xd1cf79ab, 0xc8a39194); | 35 | static const Xsig hiterm = MK_XSIG(0xb17217f7, 0xd1cf79ab, 0xc8a39194); |
@@ -45,112 +43,103 @@ static const Xsig shiftterm2 = MK_XSIG(0xb504f333, 0xf9de6484, 0x597d89b3); | |||
45 | static const Xsig shiftterm3 = MK_XSIG(0xd744fcca, 0xd69d6af4, 0x39a68bb9); | 43 | static const Xsig shiftterm3 = MK_XSIG(0xd744fcca, 0xd69d6af4, 0x39a68bb9); |
46 | 44 | ||
47 | static const Xsig *shiftterm[] = { &shiftterm0, &shiftterm1, | 45 | static 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 | +---------------------------------------------------------------------------*/ |
54 | int poly_2xm1(u_char sign, FPU_REG *arg, FPU_REG *result) | 52 | int 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 */ |
23 | static const unsigned long long oddnegterms[HIPOWERon] = | 22 | static 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 */ |
34 | static const unsigned long long oddplterms[HIPOWERop] = | 32 | static 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 | ||
45 | static const unsigned long long denomterm = 0xebd9b842c5c53a0eLL; | 42 | static const unsigned long long denomterm = 0xebd9b842c5c53a0eLL; |
@@ -48,182 +45,164 @@ static const Xsig fixedpterm = MK_XSIG(0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa); | |||
48 | 45 | ||
49 | static const Xsig pi_signif = MK_XSIG(0xc90fdaa2, 0x2168c234, 0xc4c6628b); | 46 | static const Xsig pi_signif = MK_XSIG(0xc90fdaa2, 0x2168c234, 0xc4c6628b); |
50 | 47 | ||
51 | |||
52 | /*--- poly_atan() -----------------------------------------------------------+ | 48 | /*--- poly_atan() -----------------------------------------------------------+ |
53 | | | | 49 | | | |
54 | +---------------------------------------------------------------------------*/ | 50 | +---------------------------------------------------------------------------*/ |
55 | void poly_atan(FPU_REG *st0_ptr, u_char st0_tag, | 51 | void 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 | |||
22 | static void log2_kernel(FPU_REG const *arg, u_char argsign, | 20 | static 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 | +---------------------------------------------------------------------------*/ |
29 | void poly_l2(FPU_REG *st0_ptr, FPU_REG *st1_ptr, u_char st1_sign) | 26 | void 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 | +---------------------------------------------------------------------------*/ |
119 | int poly_l2p1(u_char sign0, u_char sign1, | 105 | int 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 |
182 | static const unsigned long long logterms[HIPOWER] = | 162 | static 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 | ||
196 | static const unsigned long leadterm = 0xb8000000; | 175 | static 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 | +---------------------------------------------------------------------------*/ |
203 | static void log2_kernel(FPU_REG const *arg, u_char argsign, Xsig *accum_result, | 181 | static 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 | ||
26 | static const unsigned long long pos_terms_l[N_COEFF_P] = | 24 | static 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 | ||
34 | static const unsigned long long neg_terms_l[N_COEFF_N] = | 31 | static 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 |
46 | static const unsigned long long pos_terms_h[N_COEFF_PH] = | 40 | static 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 | ||
54 | static const unsigned long long neg_terms_h[N_COEFF_NH] = | 47 | static 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 | +---------------------------------------------------------------------------*/ |
66 | void poly_sine(FPU_REG *st0_ptr) | 57 | void 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 | +---------------------------------------------------------------------------*/ |
211 | void poly_cos(FPU_REG *st0_ptr) | 200 | void 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 */ |
22 | static const unsigned long long oddplterm[HiPOWERop] = | 21 | static 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 */ |
30 | static const unsigned long long oddnegterm[HiPOWERon] = | 28 | static 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 */ |
37 | static const unsigned long long evenplterm[HiPOWERep] = | 34 | static 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 */ |
44 | static const unsigned long long evennegterm[HiPOWERen] = | 40 | static const unsigned long long evennegterm[HiPOWERen] = { |
45 | { | 41 | 0xf1f0200fd51569ccLL, |
46 | 0xf1f0200fd51569ccLL, | 42 | 0x003afb46105c4432LL |
47 | 0x003afb46105c4432LL | ||
48 | }; | 43 | }; |
49 | 44 | ||
50 | static const unsigned long long twothirds = 0xaaaaaaaaaaaaaaabLL; | 45 | static const unsigned long long twothirds = 0xaaaaaaaaaaaaaaabLL; |
51 | 46 | ||
52 | |||
53 | /*--- poly_tan() ------------------------------------------------------------+ | 47 | /*--- poly_tan() ------------------------------------------------------------+ |
54 | | | | 48 | | | |
55 | +---------------------------------------------------------------------------*/ | 49 | +---------------------------------------------------------------------------*/ |
56 | void poly_tan(FPU_REG *st0_ptr) | 50 | void 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 @@ | |||
27 | static | 27 | static |
28 | int add_sub_specials(FPU_REG const *a, u_char taga, u_char signa, | 28 | int 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 | */ |
36 | int FPU_add(FPU_REG const *b, u_char tagb, int deststnr, int control_w) | 36 | int 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 */ |
138 | int FPU_sub(int flags, int rm, int control_w) | 128 | int 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 | ||
291 | static | 269 | static |
292 | int add_sub_specials(FPU_REG const *a, u_char taga, u_char signa, | 270 | int 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 | |||
24 | static int compare(FPU_REG const *b, int tagb) | 23 | static 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 */ |
175 | int FPU_compare_st_data(FPU_REG const *loaded_data, u_char loaded_tag) | 169 | int 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 | |||
217 | static int compare_st_st(int nr) | 206 | static 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 | |||
269 | static int compare_u_st_st(int nr) | 252 | static 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 | ||
327 | void fcom_st(void) | 304 | void 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 | |||
334 | void fcompst(void) | 310 | void 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 | |||
342 | void fcompp(void) | 317 | void 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 | |||
355 | void fucom_(void) | 328 | void 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 | |||
363 | void fucomp(void) | 335 | void 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 | |||
371 | void fucompp(void) | 342 | void 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 | ||
23 | FPU_REG const CONST_1 = MAKE_REG(POS, 0, 0x00000000, 0x80000000); | 22 | FPU_REG const CONST_1 = MAKE_REG(POS, 0, 0x00000000, 0x80000000); |
24 | #if 0 | 23 | #if 0 |
25 | FPU_REG const CONST_2 = MAKE_REG(POS, 1, 0x00000000, 0x80000000); | 24 | FPU_REG const CONST_2 = MAKE_REG(POS, 1, 0x00000000, 0x80000000); |
26 | FPU_REG const CONST_HALF = MAKE_REG(POS, -1, 0x00000000, 0x80000000); | 25 | FPU_REG const CONST_HALF = MAKE_REG(POS, -1, 0x00000000, 0x80000000); |
27 | #endif /* 0 */ | 26 | #endif /* 0 */ |
28 | static FPU_REG const CONST_L2T = MAKE_REG(POS, 1, 0xcd1b8afe, 0xd49a784b); | 27 | static FPU_REG const CONST_L2T = MAKE_REG(POS, 1, 0xcd1b8afe, 0xd49a784b); |
29 | static FPU_REG const CONST_L2E = MAKE_REG(POS, 0, 0x5c17f0bc, 0xb8aa3b29); | 28 | static FPU_REG const CONST_L2E = MAKE_REG(POS, 0, 0x5c17f0bc, 0xb8aa3b29); |
30 | FPU_REG const CONST_PI = MAKE_REG(POS, 1, 0x2168c235, 0xc90fdaa2); | 29 | FPU_REG const CONST_PI = MAKE_REG(POS, 1, 0x2168c235, 0xc90fdaa2); |
31 | FPU_REG const CONST_PI2 = MAKE_REG(POS, 0, 0x2168c235, 0xc90fdaa2); | 30 | FPU_REG const CONST_PI2 = MAKE_REG(POS, 0, 0x2168c235, 0xc90fdaa2); |
32 | FPU_REG const CONST_PI4 = MAKE_REG(POS, -1, 0x2168c235, 0xc90fdaa2); | 31 | FPU_REG const CONST_PI4 = MAKE_REG(POS, -1, 0x2168c235, 0xc90fdaa2); |
33 | static FPU_REG const CONST_LG2 = MAKE_REG(POS, -2, 0xfbcff799, 0x9a209a84); | 32 | static FPU_REG const CONST_LG2 = MAKE_REG(POS, -2, 0xfbcff799, 0x9a209a84); |
34 | static FPU_REG const CONST_LN2 = MAKE_REG(POS, -1, 0xd1cf79ac, 0xb17217f7); | 33 | static 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. */ |
37 | FPU_REG const CONST_PI2extra = MAKE_REG(NEG, -66, | 36 | FPU_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 */ |
41 | FPU_REG const CONST_Z = MAKE_REG(POS, EXP_UNDER, 0x0, 0x0); | 40 | FPU_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); | |||
48 | FPU_REG const CONST_QNaN = MAKE_REG(NEG, EXP_OVER, 0x00000000, 0xC0000000); | 47 | FPU_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 */ |
51 | FPU_REG const CONST_INF = MAKE_REG(POS, EXP_OVER, 0x00000000, 0x80000000); | 50 | FPU_REG const CONST_INF = MAKE_REG(POS, EXP_OVER, 0x00000000, 0x80000000); |
52 | |||
53 | 51 | ||
54 | static void fld_const(FPU_REG const *c, int adj, u_char tag) | 52 | static 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 | ||
76 | static void fld1(int rc) | 73 | static 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 | ||
81 | static void fldl2t(int rc) | 78 | static 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 | ||
86 | static void fldl2e(int rc) | 83 | static 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 | ||
91 | static void fldpi(int rc) | 88 | static 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 | ||
96 | static void fldlg2(int rc) | 93 | static 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 | ||
101 | static void fldln2(int rc) | 98 | static 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 | ||
106 | static void fldz(int rc) | 103 | static 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 | ||
111 | typedef void (*FUNC_RC)(int); | 108 | typedef void (*FUNC_RC) (int); |
112 | 109 | ||
113 | static FUNC_RC constants_table[] = { | 110 | static 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 | ||
117 | void fconst(void) | 114 | void 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 | 16 | int FPU_to_exp16(FPU_REG const *a, FPU_REG * x) | |
17 | int 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 | */ |
27 | int FPU_div(int flags, int rm, int control_w) | 27 | int 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 | ||
40 | static u_char normalize_no_excep(FPU_REG *r, int exp, int sign) | 38 | static 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 | 52 | int FPU_tagof(FPU_REG * ptr) | |
55 | int 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 */ |
89 | int FPU_load_extended(long double __user *s, int stnr) | 81 | int 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 */ |
103 | int FPU_load_double(double __user *dfloat, FPU_REG *loaded_data) | 94 | int 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 */ |
175 | int FPU_load_single(float __user *single, FPU_REG *loaded_data) | 155 | int 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 */ |
239 | int FPU_load_int64(long long __user *_s) | 209 | int 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 */ |
272 | int FPU_load_int32(long __user *_s, FPU_REG *loaded_data) | 239 | int 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 */ |
301 | int FPU_load_int16(short __user *_s, FPU_REG *loaded_data) | 268 | int 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 */ |
330 | int FPU_load_bcd(u_char __user *s) | 297 | int 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 */ |
373 | int FPU_store_extended(FPU_REG *st0_ptr, u_char st0_tag, long double __user *d) | 336 | int 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 */ |
415 | int FPU_store_double(FPU_REG *st0_ptr, u_char st0_tag, double __user *dfloat) | 378 | int 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 */ |
634 | int FPU_store_single(FPU_REG *st0_ptr, u_char st0_tag, float __user *single) | 568 | int 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 */ |
858 | int FPU_store_int64(FPU_REG *st0_ptr, u_char st0_tag, long long __user *d) | 757 | int 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 */ |
920 | int FPU_store_int32(FPU_REG *st0_ptr, u_char st0_tag, long __user *d) | 807 | int 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 */ |
977 | int FPU_store_int16(FPU_REG *st0_ptr, u_char st0_tag, short __user *d) | 853 | int 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 */ |
1034 | int FPU_store_bcd(FPU_REG *st0_ptr, u_char st0_tag, u_char __user *d) | 899 | int 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 */ |
1120 | int FPU_round_to_int(FPU_REG *r, u_char tag) | 974 | int 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 | ||
1180 | u_char __user *fldenv(fpu_addr_modes addr_modes, u_char __user *s) | 1031 | u_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 | ||
1271 | void frstor(fpu_addr_modes addr_modes, u_char __user *data_address) | 1124 | void 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 | 1147 | u_char __user *fstenv(fpu_addr_modes addr_modes, u_char __user * d) | |
1296 | u_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 | ||
1354 | void fsave(fpu_addr_modes addr_modes, u_char __user *data_address) | 1203 | void 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 */ |
30 | int FPU_mul(FPU_REG const *b, u_char tagb, int deststnr, int control_w) | 29 | int 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)) |
51 | static inline void setcc(int cc) | 51 | static 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 |