ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/uae_cpu/fpu/fpu_ieee.cpp
Revision: 1.10
Committed: 2012-03-30T01:45:08Z (12 years, 2 months ago) by asvitkine
Branch: MAIN
CVS Tags: HEAD
Changes since 1.9: +23 -3 lines
Log Message:
Add correct GPUv2 attribution to fpu_ieee.cpp and fpu_uae.cpp files, to
match the other files under uae_cpu/fpu, which have the same history
according to CVS.

File Contents

# Content
1 /*
2 * fpu/fpu_ieee.cpp
3 *
4 * Basilisk II (C) 1997-2008 Christian Bauer
5 *
6 * MC68881/68040 fpu emulation
7 *
8 * Original UAE FPU, copyright 1996 Herman ten Brugge
9 * Rewrite for x86, copyright 1999-2000 Lauri Pesonen
10 * New framework, copyright 2000 Gwenole Beauchesne
11 * Adapted for JIT compilation (c) Bernd Meyer, 2000
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 */
27
28 /*
29 * Following fixes by Lauri Pesonen, July 1999:
30 *
31 * FMOVEM list handling:
32 * The lookup tables did not work correctly, rewritten.
33 * FINT:
34 * (int) cast does not work, fixed.
35 * Further, now honors the FPU fpcr rounding modes.
36 * FINTRZ:
37 * (int) cast cannot be used, fixed.
38 * FGETEXP:
39 * Input argument value 0 returned erroneous value.
40 * FMOD:
41 * (int) cast cannot be used. Replaced by proper rounding.
42 * Quotient byte handling was missing.
43 * FREM:
44 * (int) cast cannot be used. Replaced by proper rounding.
45 * Quotient byte handling was missing.
46 * FSCALE:
47 * Input argument value 0 was not handled correctly.
48 * FMOVEM Control Registers to/from address FPU registers An:
49 * A bug caused the code never been called.
50 * FMOVEM Control Registers pre-decrement:
51 * Moving of control regs from memory to FPP was not handled properly,
52 * if not all of the three FPU registers were moved.
53 * Condition code "Not Greater Than or Equal":
54 * Returned erroneous value.
55 * FSINCOS:
56 * Cosine must be loaded first if same register.
57 * FMOVECR:
58 * Status register was not updated (yes, this affects it).
59 * FMOVE <ea> -> reg:
60 * Status register was not updated (yes, this affects it).
61 * FMOVE reg -> reg:
62 * Status register was not updated.
63 * FDBcc:
64 * The loop termination condition was wrong.
65 * Possible leak from int16 to int32 fixed.
66 * get_fp_value:
67 * Immediate addressing mode && Operation Length == Byte ->
68 * Use the low-order byte of the extension word.
69 * Now FPU fpcr high 16 bits are always read as zeroes, no matter what was
70 * written to them.
71 *
72 * Other:
73 * - Optimized single/double/extended to/from conversion functions.
74 * Huge speed boost, but not (necessarily) portable to other systems.
75 * Enabled/disabled by #define FPU_HAVE_IEEE_DOUBLE 1
76 * - Optimized versions of FSCALE, FGETEXP, FGETMAN
77 * - Conversion routines now handle NaN and infinity better.
78 * - Some constants precalculated. Not all compilers can optimize the
79 * expressions previously used.
80 *
81 * TODO:
82 * - Floating point exceptions.
83 * - More Infinity/NaN/overflow/underflow checking.
84 * - FPU instruction_address (only needed when exceptions are implemented)
85 * - Should be written in assembly to support long doubles.
86 * - Precision rounding single/double
87 */
88
89 #include "sysdeps.h"
90 #include <stdio.h>
91 #include "memory.h"
92 #include "readcpu.h"
93 #include "newcpu.h"
94 #include "main.h"
95 #define FPU_IMPLEMENTATION
96 #include "fpu/fpu.h"
97 #include "fpu/fpu_ieee.h"
98
99 /* Global FPU context */
100 fpu_t fpu;
101
102 /* -------------------------------------------------------------------------- */
103 /* --- Scopes Definition --- */
104 /* -------------------------------------------------------------------------- */
105
106 #undef PUBLIC
107 #define PUBLIC /**/
108
109 #undef PRIVATE
110 #define PRIVATE static
111
112 #undef FFPU
113 #define FFPU /**/
114
115 #undef FPU
116 #define FPU fpu.
117
118 /* -------------------------------------------------------------------------- */
119 /* --- Native Support --- */
120 /* -------------------------------------------------------------------------- */
121
122 #include "fpu/mathlib.h"
123 #include "fpu/flags.h"
124 #include "fpu/exceptions.h"
125 #include "fpu/rounding.h"
126 #include "fpu/impl.h"
127
128 #include "fpu/mathlib.cpp"
129 #include "fpu/flags.cpp"
130 #include "fpu/exceptions.cpp"
131 #include "fpu/rounding.cpp"
132
133 /* -------------------------------------------------------------------------- */
134 /* --- Debugging --- */
135 /* -------------------------------------------------------------------------- */
136
137 PUBLIC void FFPU fpu_dump_registers(void)
138 {
139 for (int i = 0; i < 8; i++){
140 printf ("FP%d: %g ", i, fpu_get_register(i));
141 if ((i & 3) == 3)
142 printf ("\n");
143 }
144 }
145
146 PUBLIC void FFPU fpu_dump_flags(void)
147 {
148 printf ("N=%d Z=%d I=%d NAN=%d\n",
149 (get_fpsr() & FPSR_CCB_NEGATIVE) != 0,
150 (get_fpsr() & FPSR_CCB_ZERO)!= 0,
151 (get_fpsr() & FPSR_CCB_INFINITY) != 0,
152 (get_fpsr() & FPSR_CCB_NAN) != 0);
153 }
154
155 PRIVATE void FFPU dump_registers(const char * str)
156 {
157 #if FPU_DEBUG && FPU_DUMP_REGISTERS
158 char temp_str[512];
159
160 sprintf(temp_str, "%s: %.04f, %.04f, %.04f, %.04f, %.04f, %.04f, %.04f, %.04f\n",
161 str,
162 fpu_get_register(0), fpu_get_register(1), fpu_get_register(2),
163 fpu_get_register(3), fpu_get_register(4), fpu_get_register(5),
164 fpu_get_register(6), fpu_get_register(7) );
165
166 fpu_debug((temp_str));
167 #endif
168 }
169
170 PRIVATE void FFPU dump_first_bytes(uae_u8 * buffer, uae_s32 actual)
171 {
172 #if FPU_DEBUG && FPU_DUMP_FIRST_BYTES
173 char temp_buf1[256], temp_buf2[10];
174 int bytes = sizeof(temp_buf1)/3-1-3;
175 if (actual < bytes)
176 bytes = actual;
177
178 temp_buf1[0] = 0;
179 for (int i = 0; i < bytes; i++) {
180 sprintf(temp_buf2, "%02x ", (uae_u32)buffer[i]);
181 strcat(temp_buf1, temp_buf2);
182 }
183
184 strcat(temp_buf1, "\n");
185 fpu_debug((temp_buf1));
186 #endif
187 }
188
189 // Quotient Byte is loaded with the sign and least significant
190 // seven bits of the quotient.
191 PRIVATE inline void FFPU make_quotient(fpu_register const & quotient, uae_u32 sign)
192 {
193 uae_u32 lsb = (uae_u32)fp_fabs(quotient) & 0x7f;
194 FPU fpsr.quotient = sign | (lsb << 16);
195 }
196
197 // to_single
198 PRIVATE inline fpu_register FFPU make_single(uae_u32 value)
199 {
200 #if 1
201 // Use a single, otherwise some checks for NaN, Inf, Zero would have to
202 // be performed
203 fpu_single result = 0; // = 0 to workaround a compiler bug on SPARC
204 fp_declare_init_shape(srp, result, single);
205 srp->ieee.negative = (value >> 31) & 1;
206 srp->ieee.exponent = (value >> 23) & FP_SINGLE_EXP_MAX;
207 srp->ieee.mantissa = value & 0x007fffff;
208 fpu_debug(("make_single (%X) = %.04f\n",value,(double)result));
209 return result;
210 #elif 0 /* Original code */
211 if ((value & 0x7fffffff) == 0)
212 return (0.0);
213
214 fpu_register result;
215 uae_u32 * p = (uae_u32 *)&result;
216
217 uae_u32 sign = (value & 0x80000000);
218 uae_u32 exp = ((value & 0x7F800000) >> 23) + 1023 - 127;
219
220 p[FLO] = value << 29;
221 p[FHI] = sign | (exp << 20) | ((value & 0x007FFFFF) >> 3);
222
223 fpu_debug(("make_single (%X) = %.04f\n",value,(double)result));
224
225 return(result);
226 #endif
227 }
228
229 // from_single
230 PRIVATE inline uae_u32 FFPU extract_single(fpu_register const & src)
231 {
232 #if 1
233 fpu_single input = (fpu_single) src;
234 fp_declare_init_shape(sip, input, single);
235 uae_u32 result = (sip->ieee.negative << 31)
236 | (sip->ieee.exponent << 23)
237 | sip->ieee.mantissa;
238 fpu_debug(("extract_single (%.04f) = %X\n",(double)src,result));
239 return result;
240 #elif 0 /* Original code */
241 if (src == 0.0)
242 return 0;
243
244 uae_u32 result;
245 uae_u32 *p = (uae_u32 *)&src;
246
247 uae_u32 sign = (p[FHI] & 0x80000000);
248 uae_u32 exp = (p[FHI] & 0x7FF00000) >> 20;
249
250 if(exp + 127 < 1023) {
251 exp = 0;
252 } else if(exp > 1023 + 127) {
253 exp = 255;
254 } else {
255 exp = exp + 127 - 1023;
256 }
257
258 result = sign | (exp << 23) | ((p[FHI] & 0x000FFFFF) << 3) | (p[FLO] >> 29);
259
260 fpu_debug(("extract_single (%.04f) = %X\n",(double)src,result));
261
262 return (result);
263 #endif
264 }
265
266 // to_exten
267 PRIVATE inline fpu_register FFPU make_extended(uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3)
268 {
269 // is it zero?
270 if ((wrd1 & 0x7fff0000) == 0 && wrd2 == 0 && wrd3 == 0)
271 return 0.0;
272
273 fpu_register result;
274 #if USE_QUAD_DOUBLE
275 // is it NaN?
276 if ((wrd1 & 0x7fff0000) == 0x7fff0000 && wrd2 != 0 && wrd3 != 0) {
277 make_nan(result);
278 return result;
279 }
280 // is it inf?
281 if ((wrd1 & 0x7ffff000) == 0x7fff0000 && wrd2 == 0 && wrd3 == 0) {
282 if ((wrd1 & 0x80000000) == 0)
283 make_inf_positive(result);
284 else
285 make_inf_negative(result);
286 return result;
287 }
288 fp_declare_init_shape(srp, result, extended);
289 srp->ieee.negative = (wrd1 >> 31) & 1;
290 srp->ieee.exponent = (wrd1 >> 16) & FP_EXTENDED_EXP_MAX;
291 srp->ieee.mantissa0 = (wrd2 >> 16) & 0xffff;
292 srp->ieee.mantissa1 = ((wrd2 & 0xffff) << 16) | ((wrd3 >> 16) & 0xffff);
293 srp->ieee.mantissa2 = (wrd3 & 0xffff) << 16;
294 srp->ieee.mantissa3 = 0;
295 #elif USE_LONG_DOUBLE
296 fp_declare_init_shape(srp, result, extended);
297 srp->ieee.negative = (wrd1 >> 31) & 1;
298 srp->ieee.exponent = (wrd1 >> 16) & FP_EXTENDED_EXP_MAX;
299 srp->ieee.mantissa0 = wrd2;
300 srp->ieee.mantissa1 = wrd3;
301 #else
302 uae_u32 sgn = (wrd1 >> 31) & 1;
303 uae_u32 exp = (wrd1 >> 16) & 0x7fff;
304
305 // the explicit integer bit is not set, must normalize
306 if ((wrd2 & 0x80000000) == 0) {
307 fpu_debug(("make_extended denormalized mantissa (%X,%X,%X)\n",wrd1,wrd2,wrd3));
308 if (wrd2 | wrd3) {
309 // mantissa, not fraction.
310 uae_u64 man = ((uae_u64)wrd2 << 32) | wrd3;
311 while (exp > 0 && (man & UVAL64(0x8000000000000000)) == 0) {
312 man <<= 1;
313 exp--;
314 }
315 wrd2 = (uae_u32)(man >> 32);
316 wrd3 = (uae_u32)(man & 0xFFFFFFFF);
317 }
318 else if (exp != 0x7fff) // zero
319 exp = FP_EXTENDED_EXP_BIAS - FP_DOUBLE_EXP_BIAS;
320 }
321
322 if (exp < FP_EXTENDED_EXP_BIAS - FP_DOUBLE_EXP_BIAS)
323 exp = 0;
324 else if (exp > FP_EXTENDED_EXP_BIAS + FP_DOUBLE_EXP_BIAS)
325 exp = FP_DOUBLE_EXP_MAX;
326 else
327 exp += FP_DOUBLE_EXP_BIAS - FP_EXTENDED_EXP_BIAS;
328
329 fp_declare_init_shape(srp, result, double);
330 srp->ieee.negative = sgn;
331 srp->ieee.exponent = exp;
332 // drop the explicit integer bit
333 srp->ieee.mantissa0 = (wrd2 & 0x7fffffff) >> 11;
334 srp->ieee.mantissa1 = (wrd2 << 21) | (wrd3 >> 11);
335 #endif
336 fpu_debug(("make_extended (%X,%X,%X) = %.04f\n",wrd1,wrd2,wrd3,(double)result));
337 return result;
338 }
339
340 /*
341 Would be so much easier with full size floats :(
342 ... this is so vague.
343 */
344 // make_extended_no_normalize
345 PRIVATE inline void FFPU make_extended_no_normalize(
346 uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3, fpu_register & result
347 )
348 {
349 // is it zero?
350 if ((wrd1 && 0x7fff0000) == 0 && wrd2 == 0 && wrd3 == 0) {
351 make_zero_positive(result);
352 return;
353 }
354 // is it NaN?
355 if ((wrd1 & 0x7fff0000) == 0x7fff0000 && wrd2 != 0 && wrd3 != 0) {
356 make_nan(result);
357 return;
358 }
359 #if USE_QUAD_DOUBLE
360 // is it inf?
361 if ((wrd1 & 0x7ffff000) == 0x7fff0000 && wrd2 == 0 && wrd3 == 0) {
362 if ((wrd1 & 0x80000000) == 0)
363 make_inf_positive(result);
364 else
365 make_inf_negative(result);
366 return;
367 }
368 fp_declare_init_shape(srp, result, extended);
369 srp->ieee.negative = (wrd1 >> 31) & 1;
370 srp->ieee.exponent = (wrd1 >> 16) & FP_EXTENDED_EXP_MAX;
371 srp->ieee.mantissa0 = (wrd2 >> 16) & 0xffff;
372 srp->ieee.mantissa1 = ((wrd2 & 0xffff) << 16) | ((wrd3 >> 16) & 0xffff);
373 srp->ieee.mantissa2 = (wrd3 & 0xffff) << 16;
374 srp->ieee.mantissa3 = 0;
375 #elif USE_LONG_DOUBLE
376 fp_declare_init_shape(srp, result, extended);
377 srp->ieee.negative = (wrd1 >> 31) & 1;
378 srp->ieee.exponent = (wrd1 >> 16) & FP_EXTENDED_EXP_MAX;
379 srp->ieee.mantissa0 = wrd2;
380 srp->ieee.mantissa1 = wrd3;
381 #else
382 uae_u32 exp = (wrd1 >> 16) & 0x7fff;
383 if (exp < FP_EXTENDED_EXP_BIAS - FP_DOUBLE_EXP_BIAS)
384 exp = 0;
385 else if (exp > FP_EXTENDED_EXP_BIAS + FP_DOUBLE_EXP_BIAS)
386 exp = FP_DOUBLE_EXP_MAX;
387 else
388 exp += FP_DOUBLE_EXP_BIAS - FP_EXTENDED_EXP_BIAS;
389
390 fp_declare_init_shape(srp, result, double);
391 srp->ieee.negative = (wrd1 >> 31) & 1;
392 srp->ieee.exponent = exp;
393 // drop the explicit integer bit
394 srp->ieee.mantissa0 = (wrd2 & 0x7fffffff) >> 11;
395 srp->ieee.mantissa1 = (wrd2 << 21) | (wrd3 >> 11);
396 #endif
397 fpu_debug(("make_extended (%X,%X,%X) = %.04f\n",wrd1,wrd2,wrd3,(double)result));
398 }
399
400 // from_exten
401 PRIVATE inline void FFPU extract_extended(fpu_register const & src,
402 uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3
403 )
404 {
405 if (src == 0.0) {
406 *wrd1 = *wrd2 = *wrd3 = 0;
407 return;
408 }
409 #if USE_QUAD_DOUBLE
410 // FIXME: deal with denormals?
411 fp_declare_init_shape(srp, src, extended);
412 *wrd1 = (srp->ieee.negative << 31) | (srp->ieee.exponent << 16);
413 // always set the explicit integer bit.
414 *wrd2 = 0x80000000 | (srp->ieee.mantissa0 << 15) | ((srp->ieee.mantissa1 & 0xfffe0000) >> 17);
415 *wrd3 = (srp->ieee.mantissa1 << 15) | ((srp->ieee.mantissa2 & 0xfffe0000) >> 17);
416 #elif USE_LONG_DOUBLE
417 uae_u32 *p = (uae_u32 *)&src;
418 #ifdef WORDS_BIGENDIAN
419 *wrd1 = p[0];
420 *wrd2 = p[1];
421 *wrd3 = p[2];
422 #else
423 *wrd3 = p[0];
424 *wrd2 = p[1];
425 *wrd1 = ( (uae_u32)*((uae_u16 *)&p[2]) ) << 16;
426 #endif
427 #else
428 fp_declare_init_shape(srp, src, double);
429 fpu_debug(("extract_extended (%d,%d,%X,%X)\n",
430 srp->ieee.negative , srp->ieee.exponent,
431 srp->ieee.mantissa0, srp->ieee.mantissa1));
432
433 uae_u32 exp = srp->ieee.exponent;
434
435 if (exp == FP_DOUBLE_EXP_MAX)
436 exp = FP_EXTENDED_EXP_MAX;
437 else
438 exp += FP_EXTENDED_EXP_BIAS - FP_DOUBLE_EXP_BIAS;
439
440 *wrd1 = (srp->ieee.negative << 31) | (exp << 16);
441 // always set the explicit integer bit.
442 *wrd2 = 0x80000000 | (srp->ieee.mantissa0 << 11) | ((srp->ieee.mantissa1 & 0xffe00000) >> 21);
443 *wrd3 = srp->ieee.mantissa1 << 11;
444 #endif
445 fpu_debug(("extract_extended (%.04f) = %X,%X,%X\n",(double)src,*wrd1,*wrd2,*wrd3));
446 }
447
448 // to_double
449 PRIVATE inline fpu_register FFPU make_double(uae_u32 wrd1, uae_u32 wrd2)
450 {
451 union {
452 fpu_double value;
453 uae_u32 parts[2];
454 } dest;
455 #ifdef WORDS_BIGENDIAN
456 dest.parts[0] = wrd1;
457 dest.parts[1] = wrd2;
458 #else
459 dest.parts[0] = wrd2;
460 dest.parts[1] = wrd1;
461 #endif
462 fpu_debug(("make_double (%X,%X) = %.04f\n",wrd1,wrd2,dest.value));
463 return (fpu_register)(dest.value);
464 }
465
466 // from_double
467 PRIVATE inline void FFPU extract_double(fpu_register const & src,
468 uae_u32 * wrd1, uae_u32 * wrd2
469 )
470 {
471 union {
472 fpu_double value;
473 uae_u32 parts[2];
474 } dest;
475 dest.value = (fpu_double)src;
476 #ifdef WORDS_BIGENDIAN
477 *wrd1 = dest.parts[0];
478 *wrd2 = dest.parts[1];
479 #else
480 *wrd2 = dest.parts[0];
481 *wrd1 = dest.parts[1];
482 #endif
483 fpu_debug(("extract_double (%.04f) = %X,%X\n",(double)src,*wrd1,*wrd2));
484 }
485
486 // to_pack
487 PRIVATE inline fpu_register FFPU make_packed(uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3)
488 {
489 fpu_double d;
490 char *cp;
491 char str[100];
492
493 cp = str;
494 if (wrd1 & 0x80000000)
495 *cp++ = '-';
496 *cp++ = (char)((wrd1 & 0xf) + '0');
497 *cp++ = '.';
498 *cp++ = (char)(((wrd2 >> 28) & 0xf) + '0');
499 *cp++ = (char)(((wrd2 >> 24) & 0xf) + '0');
500 *cp++ = (char)(((wrd2 >> 20) & 0xf) + '0');
501 *cp++ = (char)(((wrd2 >> 16) & 0xf) + '0');
502 *cp++ = (char)(((wrd2 >> 12) & 0xf) + '0');
503 *cp++ = (char)(((wrd2 >> 8) & 0xf) + '0');
504 *cp++ = (char)(((wrd2 >> 4) & 0xf) + '0');
505 *cp++ = (char)(((wrd2 >> 0) & 0xf) + '0');
506 *cp++ = (char)(((wrd3 >> 28) & 0xf) + '0');
507 *cp++ = (char)(((wrd3 >> 24) & 0xf) + '0');
508 *cp++ = (char)(((wrd3 >> 20) & 0xf) + '0');
509 *cp++ = (char)(((wrd3 >> 16) & 0xf) + '0');
510 *cp++ = (char)(((wrd3 >> 12) & 0xf) + '0');
511 *cp++ = (char)(((wrd3 >> 8) & 0xf) + '0');
512 *cp++ = (char)(((wrd3 >> 4) & 0xf) + '0');
513 *cp++ = (char)(((wrd3 >> 0) & 0xf) + '0');
514 *cp++ = 'E';
515 if (wrd1 & 0x40000000)
516 *cp++ = '-';
517 *cp++ = (char)(((wrd1 >> 24) & 0xf) + '0');
518 *cp++ = (char)(((wrd1 >> 20) & 0xf) + '0');
519 *cp++ = (char)(((wrd1 >> 16) & 0xf) + '0');
520 *cp = 0;
521 sscanf(str, "%le", &d);
522
523 fpu_debug(("make_packed str = %s\n",str));
524
525 fpu_debug(("make_packed(%X,%X,%X) = %.04f\n",wrd1,wrd2,wrd3,(double)d));
526 return d;
527 }
528
529 // from_pack
530 PRIVATE inline void FFPU extract_packed(fpu_register const & src, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3)
531 {
532 int i;
533 int t;
534 char *cp;
535 char str[100];
536
537 sprintf(str, "%.16e", src);
538
539 fpu_debug(("extract_packed(%.04f,%s)\n",(double)src,str));
540
541 cp = str;
542 *wrd1 = *wrd2 = *wrd3 = 0;
543 if (*cp == '-') {
544 cp++;
545 *wrd1 = 0x80000000;
546 }
547 if (*cp == '+')
548 cp++;
549 *wrd1 |= (*cp++ - '0');
550 if (*cp == '.')
551 cp++;
552 for (i = 0; i < 8; i++) {
553 *wrd2 <<= 4;
554 if (*cp >= '0' && *cp <= '9')
555 *wrd2 |= *cp++ - '0';
556 }
557 for (i = 0; i < 8; i++) {
558 *wrd3 <<= 4;
559 if (*cp >= '0' && *cp <= '9')
560 *wrd3 |= *cp++ - '0';
561 }
562 if (*cp == 'e' || *cp == 'E') {
563 cp++;
564 if (*cp == '-') {
565 cp++;
566 *wrd1 |= 0x40000000;
567 }
568 if (*cp == '+')
569 cp++;
570 t = 0;
571 for (i = 0; i < 3; i++) {
572 if (*cp >= '0' && *cp <= '9')
573 t = (t << 4) | (*cp++ - '0');
574 }
575 *wrd1 |= t << 16;
576 }
577
578 fpu_debug(("extract_packed(%.04f) = %X,%X,%X\n",(double)src,*wrd1,*wrd2,*wrd3));
579 }
580
581 PRIVATE inline int FFPU get_fp_value (uae_u32 opcode, uae_u16 extra, fpu_register & src)
582 {
583 uaecptr tmppc;
584 uae_u16 tmp;
585 int size;
586 int mode;
587 int reg;
588 uae_u32 ad = 0;
589 static int sz1[8] = {4, 4, 12, 12, 2, 8, 1, 0};
590 static int sz2[8] = {4, 4, 12, 12, 2, 8, 2, 0};
591
592 // fpu_debug(("get_fp_value(%X,%X)\n",(int)opcode,(int)extra));
593 // dump_first_bytes( regs.pc_p-4, 16 );
594
595 if ((extra & 0x4000) == 0) {
596 src = FPU registers[(extra >> 10) & 7];
597 return 1;
598 }
599 mode = (opcode >> 3) & 7;
600 reg = opcode & 7;
601 size = (extra >> 10) & 7;
602
603 fpu_debug(("get_fp_value mode=%d, reg=%d, size=%d\n",(int)mode,(int)reg,(int)size));
604
605 switch (mode) {
606 case 0:
607 switch (size) {
608 case 6:
609 src = (fpu_register) (uae_s8) m68k_dreg (regs, reg);
610 break;
611 case 4:
612 src = (fpu_register) (uae_s16) m68k_dreg (regs, reg);
613 break;
614 case 0:
615 src = (fpu_register) (uae_s32) m68k_dreg (regs, reg);
616 break;
617 case 1:
618 src = make_single(m68k_dreg (regs, reg));
619 break;
620 default:
621 return 0;
622 }
623 return 1;
624 case 1:
625 return 0;
626 case 2:
627 ad = m68k_areg (regs, reg);
628 break;
629 case 3:
630 ad = m68k_areg (regs, reg);
631 m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size];
632 break;
633 case 4:
634 m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size];
635 ad = m68k_areg (regs, reg);
636 break;
637 case 5:
638 ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) next_iword();
639 break;
640 case 6:
641 ad = get_disp_ea_020 (m68k_areg (regs, reg), next_iword());
642 break;
643 case 7:
644 switch (reg) {
645 case 0:
646 ad = (uae_s32) (uae_s16) next_iword();
647 break;
648 case 1:
649 ad = next_ilong();
650 break;
651 case 2:
652 ad = m68k_getpc ();
653 ad += (uae_s32) (uae_s16) next_iword();
654 fpu_debug(("get_fp_value next_iword()=%X\n",ad-m68k_getpc()-2));
655 break;
656 case 3:
657 tmppc = m68k_getpc ();
658 tmp = (uae_u16)next_iword();
659 ad = get_disp_ea_020 (tmppc, tmp);
660 break;
661 case 4:
662 ad = m68k_getpc ();
663 m68k_setpc (ad + sz2[size]);
664 // Immediate addressing mode && Operation Length == Byte ->
665 // Use the low-order byte of the extension word.
666 if(size == 6) ad++;
667 break;
668 default:
669 return 0;
670 }
671 }
672
673 fpu_debug(("get_fp_value m68k_getpc()=%X\n",m68k_getpc()));
674 fpu_debug(("get_fp_value ad=%X\n",ad));
675 fpu_debug(("get_fp_value get_long (ad)=%X\n",get_long (ad)));
676 dump_first_bytes( get_real_address(ad)-64, 64 );
677 dump_first_bytes( get_real_address(ad), 64 );
678
679 switch (size) {
680 case 0:
681 src = (fpu_register) (uae_s32) get_long (ad);
682 break;
683 case 1:
684 src = make_single(get_long (ad));
685 break;
686 case 2: {
687 uae_u32 wrd1, wrd2, wrd3;
688 wrd1 = get_long (ad);
689 ad += 4;
690 wrd2 = get_long (ad);
691 ad += 4;
692 wrd3 = get_long (ad);
693 src = make_extended(wrd1, wrd2, wrd3);
694 break;
695 }
696 case 3: {
697 uae_u32 wrd1, wrd2, wrd3;
698 wrd1 = get_long (ad);
699 ad += 4;
700 wrd2 = get_long (ad);
701 ad += 4;
702 wrd3 = get_long (ad);
703 src = make_packed(wrd1, wrd2, wrd3);
704 break;
705 }
706 case 4:
707 src = (fpu_register) (uae_s16) get_word(ad);
708 break;
709 case 5: {
710 uae_u32 wrd1, wrd2;
711 wrd1 = get_long (ad);
712 ad += 4;
713 wrd2 = get_long (ad);
714 src = make_double(wrd1, wrd2);
715 break;
716 }
717 case 6:
718 src = (fpu_register) (uae_s8) get_byte(ad);
719 break;
720 default:
721 return 0;
722 }
723
724 // fpu_debug(("get_fp_value result = %.04f\n",(float)src));
725 return 1;
726 }
727
728 /* Convert the FP value to integer according to the current m68k rounding mode */
729 PRIVATE inline uae_s32 FFPU toint(fpu_register const & src)
730 {
731 fpu_register result;
732 switch (get_fpcr() & 0x30) {
733 case FPCR_ROUND_ZERO:
734 result = fp_round_to_zero(src);
735 break;
736 case FPCR_ROUND_MINF:
737 result = fp_round_to_minus_infinity(src);
738 break;
739 case FPCR_ROUND_NEAR:
740 result = fp_round_to_nearest(src);
741 break;
742 case FPCR_ROUND_PINF:
743 result = fp_round_to_plus_infinity(src);
744 break;
745 default:
746 result = src; /* should never be reached */
747 break;
748 }
749 return (uae_s32)result;
750 }
751
752 PRIVATE inline int FFPU put_fp_value (uae_u32 opcode, uae_u16 extra, fpu_register const & value)
753 {
754 uae_u16 tmp;
755 uaecptr tmppc;
756 int size;
757 int mode;
758 int reg;
759 uae_u32 ad;
760 static int sz1[8] = {4, 4, 12, 12, 2, 8, 1, 0};
761 static int sz2[8] = {4, 4, 12, 12, 2, 8, 2, 0};
762
763 // fpu_debug(("put_fp_value(%.04f,%X,%X)\n",(float)value,(int)opcode,(int)extra));
764
765 if ((extra & 0x4000) == 0) {
766 int dest_reg = (extra >> 10) & 7;
767 FPU registers[dest_reg] = value;
768 make_fpsr(FPU registers[dest_reg]);
769 return 1;
770 }
771 mode = (opcode >> 3) & 7;
772 reg = opcode & 7;
773 size = (extra >> 10) & 7;
774 ad = 0xffffffff;
775 switch (mode) {
776 case 0:
777 switch (size) {
778 case 6:
779 m68k_dreg (regs, reg) = ((toint(value) & 0xff)
780 | (m68k_dreg (regs, reg) & ~0xff));
781 break;
782 case 4:
783 m68k_dreg (regs, reg) = ((toint(value) & 0xffff)
784 | (m68k_dreg (regs, reg) & ~0xffff));
785 break;
786 case 0:
787 m68k_dreg (regs, reg) = toint(value);
788 break;
789 case 1:
790 m68k_dreg (regs, reg) = extract_single(value);
791 break;
792 default:
793 return 0;
794 }
795 return 1;
796 case 1:
797 return 0;
798 case 2:
799 ad = m68k_areg (regs, reg);
800 break;
801 case 3:
802 ad = m68k_areg (regs, reg);
803 m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size];
804 break;
805 case 4:
806 m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size];
807 ad = m68k_areg (regs, reg);
808 break;
809 case 5:
810 ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) next_iword();
811 break;
812 case 6:
813 ad = get_disp_ea_020 (m68k_areg (regs, reg), next_iword());
814 break;
815 case 7:
816 switch (reg) {
817 case 0:
818 ad = (uae_s32) (uae_s16) next_iword();
819 break;
820 case 1:
821 ad = next_ilong();
822 break;
823 case 2:
824 ad = m68k_getpc ();
825 ad += (uae_s32) (uae_s16) next_iword();
826 break;
827 case 3:
828 tmppc = m68k_getpc ();
829 tmp = (uae_u16)next_iword();
830 ad = get_disp_ea_020 (tmppc, tmp);
831 break;
832 case 4:
833 ad = m68k_getpc ();
834 m68k_setpc (ad + sz2[size]);
835 break;
836 default:
837 return 0;
838 }
839 }
840 switch (size) {
841 case 0:
842 put_long (ad, toint(value));
843 break;
844 case 1:
845 put_long (ad, extract_single(value));
846 break;
847 case 2: {
848 uae_u32 wrd1, wrd2, wrd3;
849 extract_extended(value, &wrd1, &wrd2, &wrd3);
850 put_long (ad, wrd1);
851 ad += 4;
852 put_long (ad, wrd2);
853 ad += 4;
854 put_long (ad, wrd3);
855 break;
856 }
857 case 3: {
858 uae_u32 wrd1, wrd2, wrd3;
859 extract_packed(value, &wrd1, &wrd2, &wrd3);
860 put_long (ad, wrd1);
861 ad += 4;
862 put_long (ad, wrd2);
863 ad += 4;
864 put_long (ad, wrd3);
865 break;
866 }
867 case 4:
868 put_word(ad, (uae_s16) toint(value));
869 break;
870 case 5: {
871 uae_u32 wrd1, wrd2;
872 extract_double(value, &wrd1, &wrd2);
873 put_long (ad, wrd1);
874 ad += 4;
875 put_long (ad, wrd2);
876 break;
877 }
878 case 6:
879 put_byte(ad, (uae_s8) toint(value));
880 break;
881 default:
882 return 0;
883 }
884 return 1;
885 }
886
887 PRIVATE inline int FFPU get_fp_ad(uae_u32 opcode, uae_u32 * ad)
888 {
889 uae_u16 tmp;
890 uaecptr tmppc;
891 int mode;
892 int reg;
893
894 mode = (opcode >> 3) & 7;
895 reg = opcode & 7;
896 switch (mode) {
897 case 0:
898 case 1:
899 return 0;
900 case 2:
901 *ad = m68k_areg (regs, reg);
902 break;
903 case 3:
904 *ad = m68k_areg (regs, reg);
905 break;
906 case 4:
907 *ad = m68k_areg (regs, reg);
908 break;
909 case 5:
910 *ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) next_iword();
911 break;
912 case 6:
913 *ad = get_disp_ea_020 (m68k_areg (regs, reg), next_iword());
914 break;
915 case 7:
916 switch (reg) {
917 case 0:
918 *ad = (uae_s32) (uae_s16) next_iword();
919 break;
920 case 1:
921 *ad = next_ilong();
922 break;
923 case 2:
924 *ad = m68k_getpc ();
925 *ad += (uae_s32) (uae_s16) next_iword();
926 break;
927 case 3:
928 tmppc = m68k_getpc ();
929 tmp = (uae_u16)next_iword();
930 *ad = get_disp_ea_020 (tmppc, tmp);
931 break;
932 default:
933 return 0;
934 }
935 }
936 return 1;
937 }
938
939 #if FPU_DEBUG
940 # define CONDRET(s,x) fpu_debug(("fpp_cond %s = %d\n",s,(uint32)(x))); return (x)
941 #else
942 # define CONDRET(s,x) return (x)
943 #endif
944
945 PRIVATE inline int FFPU fpp_cond(int condition)
946 {
947 int N = (FPU result < 0.0);
948 int Z = (FPU result == 0.0);
949 int NaN = isnan(FPU result);
950
951 if (NaN)
952 N = Z = 0;
953
954 switch (condition) {
955 case 0x00: CONDRET("False",0);
956 case 0x01: CONDRET("Equal",Z);
957 case 0x02: CONDRET("Ordered Greater Than",!(NaN || Z || N));
958 case 0x03: CONDRET("Ordered Greater Than or Equal",Z || !(NaN || N));
959 case 0x04: CONDRET("Ordered Less Than",N && !(NaN || Z));
960 case 0x05: CONDRET("Ordered Less Than or Equal",Z || (N && !NaN));
961 case 0x06: CONDRET("Ordered Greater or Less Than",!(NaN || Z));
962 case 0x07: CONDRET("Ordered",!NaN);
963 case 0x08: CONDRET("Unordered",NaN);
964 case 0x09: CONDRET("Unordered or Equal",NaN || Z);
965 case 0x0a: CONDRET("Unordered or Greater Than",NaN || !(N || Z));
966 case 0x0b: CONDRET("Unordered or Greater or Equal",NaN || Z || !N);
967 case 0x0c: CONDRET("Unordered or Less Than",NaN || (N && !Z));
968 case 0x0d: CONDRET("Unordered or Less or Equal",NaN || Z || N);
969 case 0x0e: CONDRET("Not Equal",!Z);
970 case 0x0f: CONDRET("True",1);
971 case 0x10: CONDRET("Signaling False",0);
972 case 0x11: CONDRET("Signaling Equal",Z);
973 case 0x12: CONDRET("Greater Than",!(NaN || Z || N));
974 case 0x13: CONDRET("Greater Than or Equal",Z || !(NaN || N));
975 case 0x14: CONDRET("Less Than",N && !(NaN || Z));
976 case 0x15: CONDRET("Less Than or Equal",Z || (N && !NaN));
977 case 0x16: CONDRET("Greater or Less Than",!(NaN || Z));
978 case 0x17: CONDRET("Greater, Less or Equal",!NaN);
979 case 0x18: CONDRET("Not Greater, Less or Equal",NaN);
980 case 0x19: CONDRET("Not Greater or Less Than",NaN || Z);
981 case 0x1a: CONDRET("Not Less Than or Equal",NaN || !(N || Z));
982 case 0x1b: CONDRET("Not Less Than",NaN || Z || !N);
983 case 0x1c: CONDRET("Not Greater Than or Equal", NaN || (N && !Z));
984 case 0x1d: CONDRET("Not Greater Than",NaN || Z || N);
985 case 0x1e: CONDRET("Signaling Not Equal",!Z);
986 case 0x1f: CONDRET("Signaling True",1);
987 default: CONDRET("",-1);
988 }
989 }
990
991 void FFPU fpuop_dbcc(uae_u32 opcode, uae_u32 extra)
992 {
993 fpu_debug(("fdbcc_opp %X, %X at %08lx\n", (uae_u32)opcode, (uae_u32)extra, m68k_getpc ()));
994
995 uaecptr pc = (uae_u32) m68k_getpc ();
996 uae_s32 disp = (uae_s32) (uae_s16) next_iword();
997 int cc = fpp_cond(extra & 0x3f);
998 if (cc == -1) {
999 m68k_setpc (pc - 4);
1000 op_illg (opcode);
1001 } else if (!cc) {
1002 int reg = opcode & 0x7;
1003
1004 // this may have leaked.
1005 /*
1006 m68k_dreg (regs, reg) = ((m68k_dreg (regs, reg) & ~0xffff)
1007 | ((m68k_dreg (regs, reg) - 1) & 0xffff));
1008 */
1009 m68k_dreg (regs, reg) = ((m68k_dreg (regs, reg) & 0xffff0000)
1010 | (((m68k_dreg (regs, reg) & 0xffff) - 1) & 0xffff));
1011
1012
1013 // condition reversed.
1014 // if ((m68k_dreg (regs, reg) & 0xffff) == 0xffff)
1015 if ((m68k_dreg (regs, reg) & 0xffff) != 0xffff)
1016 m68k_setpc (pc + disp);
1017 }
1018 }
1019
1020 void FFPU fpuop_scc(uae_u32 opcode, uae_u32 extra)
1021 {
1022 fpu_debug(("fscc_opp %X, %X at %08lx\n", (uae_u32)opcode, (uae_u32)extra, m68k_getpc ()));
1023
1024 uae_u32 ad;
1025 int cc = fpp_cond(extra & 0x3f);
1026 if (cc == -1) {
1027 m68k_setpc (m68k_getpc () - 4);
1028 op_illg (opcode);
1029 }
1030 else if ((opcode & 0x38) == 0) {
1031 m68k_dreg (regs, opcode & 7) = (m68k_dreg (regs, opcode & 7) & ~0xff) |
1032 (cc ? 0xff : 0x00);
1033 }
1034 else if (get_fp_ad(opcode, &ad) == 0) {
1035 m68k_setpc (m68k_getpc () - 4);
1036 op_illg (opcode);
1037 }
1038 else
1039 put_byte(ad, cc ? 0xff : 0x00);
1040 }
1041
1042 void FFPU fpuop_trapcc(uae_u32 opcode, uaecptr oldpc)
1043 {
1044 fpu_debug(("ftrapcc_opp %X at %08lx\n", (uae_u32)opcode, m68k_getpc ()));
1045
1046 int cc = fpp_cond(opcode & 0x3f);
1047 if (cc == -1) {
1048 m68k_setpc (oldpc);
1049 op_illg (opcode);
1050 }
1051 if (cc)
1052 Exception(7, oldpc - 2);
1053 }
1054
1055 // NOTE that we get here also when there is a FNOP (nontrapping false, displ 0)
1056 void FFPU fpuop_bcc(uae_u32 opcode, uaecptr pc, uae_u32 extra)
1057 {
1058 fpu_debug(("fbcc_opp %X, %X at %08lx, jumpto=%X\n", (uae_u32)opcode, (uae_u32)extra, m68k_getpc (), extra ));
1059
1060 int cc = fpp_cond(opcode & 0x3f);
1061 if (cc == -1) {
1062 m68k_setpc (pc);
1063 op_illg (opcode);
1064 }
1065 else if (cc) {
1066 if ((opcode & 0x40) == 0)
1067 extra = (uae_s32) (uae_s16) extra;
1068 m68k_setpc (pc + extra);
1069 }
1070 }
1071
1072 // FSAVE has no post-increment
1073 // 0x1f180000 == IDLE state frame, coprocessor version number 1F
1074 void FFPU fpuop_save(uae_u32 opcode)
1075 {
1076 fpu_debug(("fsave_opp at %08lx\n", m68k_getpc ()));
1077
1078 uae_u32 ad;
1079 int incr = (opcode & 0x38) == 0x20 ? -1 : 1;
1080 int i;
1081
1082 if (get_fp_ad(opcode, &ad) == 0) {
1083 m68k_setpc (m68k_getpc () - 2);
1084 op_illg (opcode);
1085 return;
1086 }
1087
1088 if (CPUType == 4) {
1089 // Put 4 byte 68040 IDLE frame.
1090 if (incr < 0) {
1091 ad -= 4;
1092 put_long (ad, 0x41000000);
1093 }
1094 else {
1095 put_long (ad, 0x41000000);
1096 ad += 4;
1097 }
1098 } else {
1099 // Put 28 byte 68881 IDLE frame.
1100 if (incr < 0) {
1101 fpu_debug(("fsave_opp pre-decrement\n"));
1102 ad -= 4;
1103 // What's this? Some BIU flags, or (incorrectly placed) command/condition?
1104 put_long (ad, 0x70000000);
1105 for (i = 0; i < 5; i++) {
1106 ad -= 4;
1107 put_long (ad, 0x00000000);
1108 }
1109 ad -= 4;
1110 put_long (ad, 0x1f180000); // IDLE, vers 1f
1111 }
1112 else {
1113 put_long (ad, 0x1f180000); // IDLE, vers 1f
1114 ad += 4;
1115 for (i = 0; i < 5; i++) {
1116 put_long (ad, 0x00000000);
1117 ad += 4;
1118 }
1119 // What's this? Some BIU flags, or (incorrectly placed) command/condition?
1120 put_long (ad, 0x70000000);
1121 ad += 4;
1122 }
1123 }
1124 if ((opcode & 0x38) == 0x18) {
1125 m68k_areg (regs, opcode & 7) = ad; // Never executed on a 68881
1126 fpu_debug(("PROBLEM: fsave_opp post-increment\n"));
1127 }
1128 if ((opcode & 0x38) == 0x20) {
1129 m68k_areg (regs, opcode & 7) = ad;
1130 fpu_debug(("fsave_opp pre-decrement %X -> A%d\n",ad,opcode & 7));
1131 }
1132 }
1133
1134 // FRESTORE has no pre-decrement
1135 void FFPU fpuop_restore(uae_u32 opcode)
1136 {
1137 fpu_debug(("frestore_opp at %08lx\n", m68k_getpc ()));
1138
1139 uae_u32 ad;
1140 uae_u32 d;
1141 int incr = (opcode & 0x38) == 0x20 ? -1 : 1;
1142
1143 if (get_fp_ad(opcode, &ad) == 0) {
1144 m68k_setpc (m68k_getpc () - 2);
1145 op_illg (opcode);
1146 return;
1147 }
1148
1149 if (CPUType == 4) {
1150 // 68040
1151 if (incr < 0) {
1152 fpu_debug(("PROBLEM: frestore_opp incr < 0\n"));
1153 // this may be wrong, but it's never called.
1154 ad -= 4;
1155 d = get_long (ad);
1156 if ((d & 0xff000000) != 0) { // Not a NULL frame?
1157 if ((d & 0x00ff0000) == 0) { // IDLE
1158 fpu_debug(("frestore_opp found IDLE frame at %X\n",ad-4));
1159 }
1160 else if ((d & 0x00ff0000) == 0x00300000) { // UNIMP
1161 fpu_debug(("PROBLEM: frestore_opp found UNIMP frame at %X\n",ad-4));
1162 ad -= 44;
1163 }
1164 else if ((d & 0x00ff0000) == 0x00600000) { // BUSY
1165 fpu_debug(("PROBLEM: frestore_opp found BUSY frame at %X\n",ad-4));
1166 ad -= 92;
1167 }
1168 }
1169 }
1170 else {
1171 d = get_long (ad);
1172 fpu_debug(("frestore_opp frame at %X = %X\n",ad,d));
1173 ad += 4;
1174 if ((d & 0xff000000) != 0) { // Not a NULL frame?
1175 if ((d & 0x00ff0000) == 0) { // IDLE
1176 fpu_debug(("frestore_opp found IDLE frame at %X\n",ad-4));
1177 }
1178 else if ((d & 0x00ff0000) == 0x00300000) { // UNIMP
1179 fpu_debug(("PROBLEM: frestore_opp found UNIMP frame at %X\n",ad-4));
1180 ad += 44;
1181 }
1182 else if ((d & 0x00ff0000) == 0x00600000) { // BUSY
1183 fpu_debug(("PROBLEM: frestore_opp found BUSY frame at %X\n",ad-4));
1184 ad += 92;
1185 }
1186 }
1187 }
1188 }
1189 else {
1190 // 68881
1191 if (incr < 0) {
1192 fpu_debug(("PROBLEM: frestore_opp incr < 0\n"));
1193 // this may be wrong, but it's never called.
1194 ad -= 4;
1195 d = get_long (ad);
1196 if ((d & 0xff000000) != 0) {
1197 if ((d & 0x00ff0000) == 0x00180000)
1198 ad -= 6 * 4;
1199 else if ((d & 0x00ff0000) == 0x00380000)
1200 ad -= 14 * 4;
1201 else if ((d & 0x00ff0000) == 0x00b40000)
1202 ad -= 45 * 4;
1203 }
1204 }
1205 else {
1206 d = get_long (ad);
1207 fpu_debug(("frestore_opp frame at %X = %X\n",ad,d));
1208 ad += 4;
1209 if ((d & 0xff000000) != 0) { // Not a NULL frame?
1210 if ((d & 0x00ff0000) == 0x00180000) { // IDLE
1211 fpu_debug(("frestore_opp found IDLE frame at %X\n",ad-4));
1212 ad += 6 * 4;
1213 }
1214 else if ((d & 0x00ff0000) == 0x00380000) {// UNIMP? shouldn't it be 3C?
1215 ad += 14 * 4;
1216 fpu_debug(("PROBLEM: frestore_opp found UNIMP? frame at %X\n",ad-4));
1217 }
1218 else if ((d & 0x00ff0000) == 0x00b40000) {// BUSY
1219 fpu_debug(("PROBLEM: frestore_opp found BUSY frame at %X\n",ad-4));
1220 ad += 45 * 4;
1221 }
1222 }
1223 }
1224 }
1225 if ((opcode & 0x38) == 0x18) {
1226 m68k_areg (regs, opcode & 7) = ad;
1227 fpu_debug(("frestore_opp post-increment %X -> A%d\n",ad,opcode & 7));
1228 }
1229 if ((opcode & 0x38) == 0x20) {
1230 m68k_areg (regs, opcode & 7) = ad; // Never executed on a 68881
1231 fpu_debug(("PROBLEM: frestore_opp pre-decrement\n"));
1232 }
1233 }
1234
1235 void FFPU fpuop_arithmetic(uae_u32 opcode, uae_u32 extra)
1236 {
1237 int reg;
1238 fpu_register src;
1239
1240 fpu_debug(("FPP %04lx %04x at %08lx\n", opcode & 0xffff, extra & 0xffff,
1241 m68k_getpc () - 4));
1242
1243 dump_registers( "START");
1244
1245 switch ((extra >> 13) & 0x7) {
1246 case 3:
1247 fpu_debug(("FMOVE -> <ea>\n"));
1248 if (put_fp_value (opcode, extra, FPU registers[(extra >> 7) & 7]) == 0) {
1249 m68k_setpc (m68k_getpc () - 4);
1250 op_illg (opcode);
1251 }
1252 dump_registers( "END ");
1253 return;
1254 case 4:
1255 case 5:
1256 if ((opcode & 0x38) == 0) {
1257 if (extra & 0x2000) { // dr bit
1258 if (extra & 0x1000) {
1259 // according to the manual, the msb bits are always zero.
1260 m68k_dreg (regs, opcode & 7) = get_fpcr() & 0xFFFF;
1261 fpu_debug(("FMOVEM FPU fpcr (%X) -> D%d\n", get_fpcr(), opcode & 7));
1262 }
1263 if (extra & 0x0800) {
1264 m68k_dreg (regs, opcode & 7) = get_fpsr();
1265 fpu_debug(("FMOVEM FPU fpsr (%X) -> D%d\n", get_fpsr(), opcode & 7));
1266 }
1267 if (extra & 0x0400) {
1268 m68k_dreg (regs, opcode & 7) = FPU instruction_address;
1269 fpu_debug(("FMOVEM FPU instruction_address (%X) -> D%d\n", FPU instruction_address, opcode & 7));
1270 }
1271 }
1272 else {
1273 if (extra & 0x1000) {
1274 set_fpcr( m68k_dreg (regs, opcode & 7) );
1275 fpu_debug(("FMOVEM D%d (%X) -> FPU fpcr\n", opcode & 7, get_fpcr()));
1276 }
1277 if (extra & 0x0800) {
1278 set_fpsr( m68k_dreg (regs, opcode & 7) );
1279 fpu_debug(("FMOVEM D%d (%X) -> FPU fpsr\n", opcode & 7, get_fpsr()));
1280 }
1281 if (extra & 0x0400) {
1282 FPU instruction_address = m68k_dreg (regs, opcode & 7);
1283 fpu_debug(("FMOVEM D%d (%X) -> FPU instruction_address\n", opcode & 7, FPU instruction_address));
1284 }
1285 }
1286 // } else if ((opcode & 0x38) == 1) {
1287 }
1288 else if ((opcode & 0x38) == 8) {
1289 if (extra & 0x2000) { // dr bit
1290 if (extra & 0x1000) {
1291 // according to the manual, the msb bits are always zero.
1292 m68k_areg (regs, opcode & 7) = get_fpcr() & 0xFFFF;
1293 fpu_debug(("FMOVEM FPU fpcr (%X) -> A%d\n", get_fpcr(), opcode & 7));
1294 }
1295 if (extra & 0x0800) {
1296 m68k_areg (regs, opcode & 7) = get_fpsr();
1297 fpu_debug(("FMOVEM FPU fpsr (%X) -> A%d\n", get_fpsr(), opcode & 7));
1298 }
1299 if (extra & 0x0400) {
1300 m68k_areg (regs, opcode & 7) = FPU instruction_address;
1301 fpu_debug(("FMOVEM FPU instruction_address (%X) -> A%d\n", FPU instruction_address, opcode & 7));
1302 }
1303 } else {
1304 if (extra & 0x1000) {
1305 set_fpcr( m68k_areg (regs, opcode & 7) );
1306 fpu_debug(("FMOVEM A%d (%X) -> FPU fpcr\n", opcode & 7, get_fpcr()));
1307 }
1308 if (extra & 0x0800) {
1309 set_fpsr( m68k_areg (regs, opcode & 7) );
1310 fpu_debug(("FMOVEM A%d (%X) -> FPU fpsr\n", opcode & 7, get_fpsr()));
1311 }
1312 if (extra & 0x0400) {
1313 FPU instruction_address = m68k_areg (regs, opcode & 7);
1314 fpu_debug(("FMOVEM A%d (%X) -> FPU instruction_address\n", opcode & 7, FPU instruction_address));
1315 }
1316 }
1317 }
1318 else if ((opcode & 0x3f) == 0x3c) {
1319 if ((extra & 0x2000) == 0) {
1320 if (extra & 0x1000) {
1321 set_fpcr( next_ilong() );
1322 fpu_debug(("FMOVEM #<%X> -> FPU fpcr\n", get_fpcr()));
1323 }
1324 if (extra & 0x0800) {
1325 set_fpsr( next_ilong() );
1326 fpu_debug(("FMOVEM #<%X> -> FPU fpsr\n", get_fpsr()));
1327 }
1328 if (extra & 0x0400) {
1329 FPU instruction_address = next_ilong();
1330 fpu_debug(("FMOVEM #<%X> -> FPU instruction_address\n", FPU instruction_address));
1331 }
1332 }
1333 }
1334 else if (extra & 0x2000) {
1335 /* FMOVEM FPP->memory */
1336 uae_u32 ad;
1337 int incr = 0;
1338
1339 if (get_fp_ad(opcode, &ad) == 0) {
1340 m68k_setpc (m68k_getpc () - 4);
1341 op_illg (opcode);
1342 dump_registers( "END ");
1343 return;
1344 }
1345 if ((opcode & 0x38) == 0x20) {
1346 if (extra & 0x1000)
1347 incr += 4;
1348 if (extra & 0x0800)
1349 incr += 4;
1350 if (extra & 0x0400)
1351 incr += 4;
1352 }
1353 ad -= incr;
1354 if (extra & 0x1000) {
1355 // according to the manual, the msb bits are always zero.
1356 put_long (ad, get_fpcr() & 0xFFFF);
1357 fpu_debug(("FMOVEM FPU fpcr (%X) -> mem %X\n", get_fpcr(), ad ));
1358 ad += 4;
1359 }
1360 if (extra & 0x0800) {
1361 put_long (ad, get_fpsr());
1362 fpu_debug(("FMOVEM FPU fpsr (%X) -> mem %X\n", get_fpsr(), ad ));
1363 ad += 4;
1364 }
1365 if (extra & 0x0400) {
1366 put_long (ad, FPU instruction_address);
1367 fpu_debug(("FMOVEM FPU instruction_address (%X) -> mem %X\n", FPU instruction_address, ad ));
1368 ad += 4;
1369 }
1370 ad -= incr;
1371 if ((opcode & 0x38) == 0x18) // post-increment?
1372 m68k_areg (regs, opcode & 7) = ad;
1373 if ((opcode & 0x38) == 0x20) // pre-decrement?
1374 m68k_areg (regs, opcode & 7) = ad;
1375 }
1376 else {
1377 /* FMOVEM memory->FPP */
1378 uae_u32 ad;
1379
1380 if (get_fp_ad(opcode, &ad) == 0) {
1381 m68k_setpc (m68k_getpc () - 4);
1382 op_illg (opcode);
1383 dump_registers( "END ");
1384 return;
1385 }
1386
1387 // ad = (opcode & 0x38) == 0x20 ? ad - 12 : ad;
1388 int incr = 0;
1389 if((opcode & 0x38) == 0x20) {
1390 if (extra & 0x1000)
1391 incr += 4;
1392 if (extra & 0x0800)
1393 incr += 4;
1394 if (extra & 0x0400)
1395 incr += 4;
1396 ad = ad - incr;
1397 }
1398
1399 if (extra & 0x1000) {
1400 set_fpcr( get_long (ad) );
1401 fpu_debug(("FMOVEM mem %X (%X) -> FPU fpcr\n", ad, get_fpcr() ));
1402 ad += 4;
1403 }
1404 if (extra & 0x0800) {
1405 set_fpsr( get_long (ad) );
1406 fpu_debug(("FMOVEM mem %X (%X) -> FPU fpsr\n", ad, get_fpsr() ));
1407 ad += 4;
1408 }
1409 if (extra & 0x0400) {
1410 FPU instruction_address = get_long (ad);
1411 fpu_debug(("FMOVEM mem %X (%X) -> FPU instruction_address\n", ad, FPU instruction_address ));
1412 ad += 4;
1413 }
1414 if ((opcode & 0x38) == 0x18) // post-increment?
1415 m68k_areg (regs, opcode & 7) = ad;
1416 if ((opcode & 0x38) == 0x20) // pre-decrement?
1417 // m68k_areg (regs, opcode & 7) = ad - 12;
1418 m68k_areg (regs, opcode & 7) = ad - incr;
1419 }
1420 dump_registers( "END ");
1421 return;
1422 case 6:
1423 case 7: {
1424 uae_u32 ad, list = 0;
1425 int incr = 0;
1426 if (extra & 0x2000) {
1427 /* FMOVEM FPP->memory */
1428 fpu_debug(("FMOVEM FPP->memory\n"));
1429
1430 if (get_fp_ad(opcode, &ad) == 0) {
1431 m68k_setpc (m68k_getpc () - 4);
1432 op_illg (opcode);
1433 dump_registers( "END ");
1434 return;
1435 }
1436 switch ((extra >> 11) & 3) {
1437 case 0: /* static pred */
1438 list = extra & 0xff;
1439 incr = -1;
1440 break;
1441 case 1: /* dynamic pred */
1442 list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff;
1443 incr = -1;
1444 break;
1445 case 2: /* static postinc */
1446 list = extra & 0xff;
1447 incr = 1;
1448 break;
1449 case 3: /* dynamic postinc */
1450 list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff;
1451 incr = 1;
1452 break;
1453 }
1454
1455 if (incr < 0) {
1456 for(reg=7; reg>=0; reg--) {
1457 uae_u32 wrd1, wrd2, wrd3;
1458 if( list & 0x80 ) {
1459 extract_extended(FPU registers[reg],&wrd1, &wrd2, &wrd3);
1460 ad -= 4;
1461 put_long (ad, wrd3);
1462 ad -= 4;
1463 put_long (ad, wrd2);
1464 ad -= 4;
1465 put_long (ad, wrd1);
1466 }
1467 list <<= 1;
1468 }
1469 }
1470 else {
1471 for(reg=0; reg<8; reg++) {
1472 uae_u32 wrd1, wrd2, wrd3;
1473 if( list & 0x80 ) {
1474 extract_extended(FPU registers[reg],&wrd1, &wrd2, &wrd3);
1475 put_long (ad, wrd1);
1476 ad += 4;
1477 put_long (ad, wrd2);
1478 ad += 4;
1479 put_long (ad, wrd3);
1480 ad += 4;
1481 }
1482 list <<= 1;
1483 }
1484 }
1485 if ((opcode & 0x38) == 0x18) // post-increment?
1486 m68k_areg (regs, opcode & 7) = ad;
1487 if ((opcode & 0x38) == 0x20) // pre-decrement?
1488 m68k_areg (regs, opcode & 7) = ad;
1489 }
1490 else {
1491 /* FMOVEM memory->FPP */
1492 fpu_debug(("FMOVEM memory->FPP\n"));
1493
1494 if (get_fp_ad(opcode, &ad) == 0) {
1495 m68k_setpc (m68k_getpc () - 4);
1496 op_illg (opcode);
1497 dump_registers( "END ");
1498 return;
1499 }
1500 switch ((extra >> 11) & 3) {
1501 case 0: /* static pred */
1502 fpu_debug(("memory->FMOVEM FPP not legal mode.\n"));
1503 list = extra & 0xff;
1504 incr = -1;
1505 break;
1506 case 1: /* dynamic pred */
1507 fpu_debug(("memory->FMOVEM FPP not legal mode.\n"));
1508 list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff;
1509 incr = -1;
1510 break;
1511 case 2: /* static postinc */
1512 list = extra & 0xff;
1513 incr = 1;
1514 break;
1515 case 3: /* dynamic postinc */
1516 list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff;
1517 incr = 1;
1518 break;
1519 }
1520
1521 /**/
1522 if (incr < 0) {
1523 // not reached
1524 for(reg=7; reg>=0; reg--) {
1525 uae_u32 wrd1, wrd2, wrd3;
1526 if( list & 0x80 ) {
1527 ad -= 4;
1528 wrd3 = get_long (ad);
1529 ad -= 4;
1530 wrd2 = get_long (ad);
1531 ad -= 4;
1532 wrd1 = get_long (ad);
1533 // FPU registers[reg] = make_extended(wrd1, wrd2, wrd3);
1534 make_extended_no_normalize (wrd1, wrd2, wrd3, FPU registers[reg]);
1535 }
1536 list <<= 1;
1537 }
1538 }
1539 else {
1540 for(reg=0; reg<8; reg++) {
1541 uae_u32 wrd1, wrd2, wrd3;
1542 if( list & 0x80 ) {
1543 wrd1 = get_long (ad);
1544 ad += 4;
1545 wrd2 = get_long (ad);
1546 ad += 4;
1547 wrd3 = get_long (ad);
1548 ad += 4;
1549 // FPU registers[reg] = make_extended(wrd1, wrd2, wrd3);
1550 make_extended_no_normalize (wrd1, wrd2, wrd3, FPU registers[reg]);
1551 }
1552 list <<= 1;
1553 }
1554 }
1555 if ((opcode & 0x38) == 0x18) // post-increment?
1556 m68k_areg (regs, opcode & 7) = ad;
1557 if ((opcode & 0x38) == 0x20) // pre-decrement?
1558 m68k_areg (regs, opcode & 7) = ad;
1559 }
1560 dump_registers( "END ");
1561 return;
1562 }
1563 case 0:
1564 case 2:
1565 reg = (extra >> 7) & 7;
1566 if ((extra & 0xfc00) == 0x5c00) {
1567 fpu_debug(("FMOVECR memory->FPP\n"));
1568 switch (extra & 0x7f) {
1569 case 0x00:
1570 // FPU registers[reg] = 4.0 * atan(1.0);
1571 FPU registers[reg] = 3.1415926535897932384626433832795;
1572 fpu_debug(("FP const: Pi\n"));
1573 break;
1574 case 0x0b:
1575 // FPU registers[reg] = log10 (2.0);
1576 FPU registers[reg] = 0.30102999566398119521373889472449;
1577 fpu_debug(("FP const: Log 10 (2)\n"));
1578 break;
1579 case 0x0c:
1580 // FPU registers[reg] = exp (1.0);
1581 FPU registers[reg] = 2.7182818284590452353602874713527;
1582 fpu_debug(("FP const: e\n"));
1583 break;
1584 case 0x0d:
1585 // FPU registers[reg] = log (exp (1.0)) / log (2.0);
1586 FPU registers[reg] = 1.4426950408889634073599246810019;
1587 fpu_debug(("FP const: Log 2 (e)\n"));
1588 break;
1589 case 0x0e:
1590 // FPU registers[reg] = log (exp (1.0)) / log (10.0);
1591 FPU registers[reg] = 0.43429448190325182765112891891661;
1592 fpu_debug(("FP const: Log 10 (e)\n"));
1593 break;
1594 case 0x0f:
1595 FPU registers[reg] = 0.0;
1596 fpu_debug(("FP const: zero\n"));
1597 break;
1598 case 0x30:
1599 // FPU registers[reg] = log (2.0);
1600 FPU registers[reg] = 0.69314718055994530941723212145818;
1601 fpu_debug(("FP const: ln(2)\n"));
1602 break;
1603 case 0x31:
1604 // FPU registers[reg] = log (10.0);
1605 FPU registers[reg] = 2.3025850929940456840179914546844;
1606 fpu_debug(("FP const: ln(10)\n"));
1607 break;
1608 case 0x32:
1609 // ??
1610 FPU registers[reg] = 1.0e0;
1611 fpu_debug(("FP const: 1.0e0\n"));
1612 break;
1613 case 0x33:
1614 FPU registers[reg] = 1.0e1;
1615 fpu_debug(("FP const: 1.0e1\n"));
1616 break;
1617 case 0x34:
1618 FPU registers[reg] = 1.0e2;
1619 fpu_debug(("FP const: 1.0e2\n"));
1620 break;
1621 case 0x35:
1622 FPU registers[reg] = 1.0e4;
1623 fpu_debug(("FP const: 1.0e4\n"));
1624 break;
1625 case 0x36:
1626 FPU registers[reg] = 1.0e8;
1627 fpu_debug(("FP const: 1.0e8\n"));
1628 break;
1629 case 0x37:
1630 FPU registers[reg] = 1.0e16;
1631 fpu_debug(("FP const: 1.0e16\n"));
1632 break;
1633 case 0x38:
1634 FPU registers[reg] = 1.0e32;
1635 fpu_debug(("FP const: 1.0e32\n"));
1636 break;
1637 case 0x39:
1638 FPU registers[reg] = 1.0e64;
1639 fpu_debug(("FP const: 1.0e64\n"));
1640 break;
1641 case 0x3a:
1642 FPU registers[reg] = 1.0e128;
1643 fpu_debug(("FP const: 1.0e128\n"));
1644 break;
1645 case 0x3b:
1646 FPU registers[reg] = 1.0e256;
1647 fpu_debug(("FP const: 1.0e256\n"));
1648 break;
1649 #if USE_LONG_DOUBLE || USE_QUAD_DOUBLE
1650 case 0x3c:
1651 FPU registers[reg] = 1.0e512L;
1652 fpu_debug(("FP const: 1.0e512\n"));
1653 break;
1654 case 0x3d:
1655 FPU registers[reg] = 1.0e1024L;
1656 fpu_debug(("FP const: 1.0e1024\n"));
1657 break;
1658 case 0x3e:
1659 FPU registers[reg] = 1.0e2048L;
1660 fpu_debug(("FP const: 1.0e2048\n"));
1661 break;
1662 case 0x3f:
1663 FPU registers[reg] = 1.0e4096L;
1664 fpu_debug(("FP const: 1.0e4096\n"));
1665 #endif
1666 break;
1667 default:
1668 m68k_setpc (m68k_getpc () - 4);
1669 op_illg (opcode);
1670 break;
1671 }
1672 // these *do* affect the status reg
1673 make_fpsr(FPU registers[reg]);
1674 dump_registers( "END ");
1675 return;
1676 }
1677
1678 if (get_fp_value (opcode, extra, src) == 0) {
1679 m68k_setpc (m68k_getpc () - 4);
1680 op_illg (opcode);
1681 dump_registers( "END ");
1682 return;
1683 }
1684 fpu_debug(("returned from get_fp_value m68k_getpc()=%X\n",m68k_getpc()));
1685
1686 if (FPU is_integral) {
1687 // 68040-specific operations
1688 switch (extra & 0x7f) {
1689 case 0x40: /* FSMOVE */
1690 fpu_debug(("FSMOVE %.04f\n",(double)src));
1691 FPU registers[reg] = (float)src;
1692 make_fpsr(FPU registers[reg]);
1693 break;
1694 case 0x44: /* FDMOVE */
1695 fpu_debug(("FDMOVE %.04f\n",(double)src));
1696 FPU registers[reg] = (double)src;
1697 make_fpsr(FPU registers[reg]);
1698 break;
1699 case 0x41: /* FSSQRT */
1700 fpu_debug(("FSQRT %.04f\n",(double)src));
1701 FPU registers[reg] = (float)fp_sqrt (src);
1702 make_fpsr(FPU registers[reg]);
1703 break;
1704 case 0x45: /* FDSQRT */
1705 fpu_debug(("FSQRT %.04f\n",(double)src));
1706 FPU registers[reg] = (double)fp_sqrt (src);
1707 make_fpsr(FPU registers[reg]);
1708 break;
1709 case 0x58: /* FSABS */
1710 fpu_debug(("FSABS %.04f\n",(double)src));
1711 FPU registers[reg] = (float)fp_fabs(src);
1712 make_fpsr(FPU registers[reg]);
1713 break;
1714 case 0x5c: /* FDABS */
1715 fpu_debug(("FDABS %.04f\n",(double)src));
1716 FPU registers[reg] = (double)fp_fabs(src);
1717 make_fpsr(FPU registers[reg]);
1718 break;
1719 case 0x5a: /* FSNEG */
1720 fpu_debug(("FSNEG %.04f\n",(double)src));
1721 FPU registers[reg] = (float)-src;
1722 make_fpsr(FPU registers[reg]);
1723 break;
1724 case 0x5e: /* FDNEG */
1725 fpu_debug(("FDNEG %.04f\n",(double)src));
1726 FPU registers[reg] = (double)-src;
1727 make_fpsr(FPU registers[reg]);
1728 break;
1729 case 0x60: /* FSDIV */
1730 fpu_debug(("FSDIV %.04f\n",(double)src));
1731 FPU registers[reg] = (float)(FPU registers[reg] / src);
1732 make_fpsr(FPU registers[reg]);
1733 break;
1734 case 0x64: /* FDDIV */
1735 fpu_debug(("FDDIV %.04f\n",(double)src));
1736 FPU registers[reg] = (double)(FPU registers[reg] / src);
1737 make_fpsr(FPU registers[reg]);
1738 break;
1739 case 0x62: /* FSADD */
1740 fpu_debug(("FSADD %.04f\n",(double)src));
1741 FPU registers[reg] = (float)(FPU registers[reg] + src);
1742 make_fpsr(FPU registers[reg]);
1743 break;
1744 case 0x66: /* FDADD */
1745 fpu_debug(("FDADD %.04f\n",(double)src));
1746 FPU registers[reg] = (double)(FPU registers[reg] + src);
1747 make_fpsr(FPU registers[reg]);
1748 break;
1749 case 0x68: /* FSSUB */
1750 fpu_debug(("FSSUB %.04f\n",(double)src));
1751 FPU registers[reg] = (float)(FPU registers[reg] - src);
1752 make_fpsr(FPU registers[reg]);
1753 break;
1754 case 0x6c: /* FDSUB */
1755 fpu_debug(("FDSUB %.04f\n",(double)src));
1756 FPU registers[reg] = (double)(FPU registers[reg] - src);
1757 make_fpsr(FPU registers[reg]);
1758 break;
1759 case 0x63: /* FSMUL */
1760 case 0x67: /* FDMUL */
1761 fpu_debug(("FMUL %.04f\n",(double)src));
1762 get_dest_flags(FPU registers[reg]);
1763 get_source_flags(src);
1764 if(fl_dest.in_range && fl_source.in_range) {
1765 if ((extra & 0x7f) == 0x63)
1766 FPU registers[reg] = (float)(FPU registers[reg] * src);
1767 else
1768 FPU registers[reg] = (double)(FPU registers[reg] * src);
1769 }
1770 else if (fl_dest.nan || fl_source.nan ||
1771 fl_dest.zero && fl_source.infinity ||
1772 fl_dest.infinity && fl_source.zero ) {
1773 make_nan( FPU registers[reg] );
1774 }
1775 else if (fl_dest.zero || fl_source.zero ) {
1776 if (fl_dest.negative && !fl_source.negative ||
1777 !fl_dest.negative && fl_source.negative) {
1778 make_zero_negative(FPU registers[reg]);
1779 }
1780 else {
1781 make_zero_positive(FPU registers[reg]);
1782 }
1783 }
1784 else {
1785 if( fl_dest.negative && !fl_source.negative ||
1786 !fl_dest.negative && fl_source.negative) {
1787 make_inf_negative(FPU registers[reg]);
1788 }
1789 else {
1790 make_inf_positive(FPU registers[reg]);
1791 }
1792 }
1793 make_fpsr(FPU registers[reg]);
1794 break;
1795 default:
1796 // Continue decode-execute 6888x instructions below
1797 goto process_6888x_instructions;
1798 }
1799 fpu_debug(("END m68k_getpc()=%X\n",m68k_getpc()));
1800 dump_registers( "END ");
1801 return;
1802 }
1803
1804 process_6888x_instructions:
1805 switch (extra & 0x7f) {
1806 case 0x00: /* FMOVE */
1807 fpu_debug(("FMOVE %.04f\n",(double)src));
1808 FPU registers[reg] = src;
1809 make_fpsr(FPU registers[reg]);
1810 break;
1811 case 0x01: /* FINT */
1812 fpu_debug(("FINT %.04f\n",(double)src));
1813 FPU registers[reg] = toint(src);
1814 make_fpsr(FPU registers[reg]);
1815 break;
1816 case 0x02: /* FSINH */
1817 fpu_debug(("FSINH %.04f\n",(double)src));
1818 FPU registers[reg] = fp_sinh (src);
1819 make_fpsr(FPU registers[reg]);
1820 break;
1821 case 0x03: /* FINTRZ */
1822 fpu_debug(("FINTRZ %.04f\n",(double)src));
1823 FPU registers[reg] = fp_round_to_zero(src);
1824 make_fpsr(FPU registers[reg]);
1825 break;
1826 case 0x04: /* FSQRT */
1827 fpu_debug(("FSQRT %.04f\n",(double)src));
1828 FPU registers[reg] = fp_sqrt (src);
1829 make_fpsr(FPU registers[reg]);
1830 break;
1831 case 0x06: /* FLOGNP1 */
1832 fpu_debug(("FLOGNP1 %.04f\n",(double)src));
1833 FPU registers[reg] = fp_log (src + 1.0);
1834 make_fpsr(FPU registers[reg]);
1835 break;
1836 case 0x08: /* FETOXM1 */
1837 fpu_debug(("FETOXM1 %.04f\n",(double)src));
1838 FPU registers[reg] = fp_exp (src) - 1.0;
1839 make_fpsr(FPU registers[reg]);
1840 break;
1841 case 0x09: /* FTANH */
1842 fpu_debug(("FTANH %.04f\n",(double)src));
1843 FPU registers[reg] = fp_tanh (src);
1844 make_fpsr(FPU registers[reg]);
1845 break;
1846 case 0x0a: /* FATAN */
1847 fpu_debug(("FATAN %.04f\n",(double)src));
1848 FPU registers[reg] = fp_atan (src);
1849 make_fpsr(FPU registers[reg]);
1850 break;
1851 case 0x0c: /* FASIN */
1852 fpu_debug(("FASIN %.04f\n",(double)src));
1853 FPU registers[reg] = fp_asin (src);
1854 make_fpsr(FPU registers[reg]);
1855 break;
1856 case 0x0d: /* FATANH */
1857 fpu_debug(("FATANH %.04f\n",(double)src));
1858 FPU registers[reg] = fp_atanh (src);
1859 make_fpsr(FPU registers[reg]);
1860 break;
1861 case 0x0e: /* FSIN */
1862 fpu_debug(("FSIN %.04f\n",(double)src));
1863 FPU registers[reg] = fp_sin (src);
1864 make_fpsr(FPU registers[reg]);
1865 break;
1866 case 0x0f: /* FTAN */
1867 fpu_debug(("FTAN %.04f\n",(double)src));
1868 FPU registers[reg] = fp_tan (src);
1869 make_fpsr(FPU registers[reg]);
1870 break;
1871 case 0x10: /* FETOX */
1872 fpu_debug(("FETOX %.04f\n",(double)src));
1873 FPU registers[reg] = fp_exp (src);
1874 make_fpsr(FPU registers[reg]);
1875 break;
1876 case 0x11: /* FTWOTOX */
1877 fpu_debug(("FTWOTOX %.04f\n",(double)src));
1878 FPU registers[reg] = fp_pow(2.0, src);
1879 make_fpsr(FPU registers[reg]);
1880 break;
1881 case 0x12: /* FTENTOX */
1882 fpu_debug(("FTENTOX %.04f\n",(double)src));
1883 FPU registers[reg] = fp_pow(10.0, src);
1884 make_fpsr(FPU registers[reg]);
1885 break;
1886 case 0x14: /* FLOGN */
1887 fpu_debug(("FLOGN %.04f\n",(double)src));
1888 FPU registers[reg] = fp_log (src);
1889 make_fpsr(FPU registers[reg]);
1890 break;
1891 case 0x15: /* FLOG10 */
1892 fpu_debug(("FLOG10 %.04f\n",(double)src));
1893 FPU registers[reg] = fp_log10 (src);
1894 make_fpsr(FPU registers[reg]);
1895 break;
1896 case 0x16: /* FLOG2 */
1897 fpu_debug(("FLOG2 %.04f\n",(double)src));
1898 FPU registers[reg] = fp_log (src) / fp_log (2.0);
1899 make_fpsr(FPU registers[reg]);
1900 break;
1901 case 0x18: /* FABS */
1902 fpu_debug(("FABS %.04f\n",(double)src));
1903 FPU registers[reg] = fp_fabs(src);
1904 make_fpsr(FPU registers[reg]);
1905 break;
1906 case 0x19: /* FCOSH */
1907 fpu_debug(("FCOSH %.04f\n",(double)src));
1908 FPU registers[reg] = fp_cosh(src);
1909 make_fpsr(FPU registers[reg]);
1910 break;
1911 case 0x1a: /* FNEG */
1912 fpu_debug(("FNEG %.04f\n",(double)src));
1913 FPU registers[reg] = -src;
1914 make_fpsr(FPU registers[reg]);
1915 break;
1916 case 0x1c: /* FACOS */
1917 fpu_debug(("FACOS %.04f\n",(double)src));
1918 FPU registers[reg] = fp_acos(src);
1919 make_fpsr(FPU registers[reg]);
1920 break;
1921 case 0x1d: /* FCOS */
1922 fpu_debug(("FCOS %.04f\n",(double)src));
1923 FPU registers[reg] = fp_cos(src);
1924 make_fpsr(FPU registers[reg]);
1925 break;
1926 case 0x1e: /* FGETEXP */
1927 fpu_debug(("FGETEXP %.04f\n",(double)src));
1928 if( isinf(src) ) {
1929 make_nan( FPU registers[reg] );
1930 }
1931 else {
1932 FPU registers[reg] = fast_fgetexp( src );
1933 }
1934 make_fpsr(FPU registers[reg]);
1935 break;
1936 case 0x1f: /* FGETMAN */
1937 fpu_debug(("FGETMAN %.04f\n",(double)src));
1938 if( src == 0 ) {
1939 FPU registers[reg] = 0;
1940 }
1941 else if( isinf(src) ) {
1942 make_nan( FPU registers[reg] );
1943 }
1944 else {
1945 FPU registers[reg] = src;
1946 fast_remove_exponent( FPU registers[reg] );
1947 }
1948 make_fpsr(FPU registers[reg]);
1949 break;
1950 case 0x20: /* FDIV */
1951 fpu_debug(("FDIV %.04f\n",(double)src));
1952 FPU registers[reg] /= src;
1953 make_fpsr(FPU registers[reg]);
1954 break;
1955 case 0x21: /* FMOD */
1956 fpu_debug(("FMOD %.04f\n",(double)src));
1957 // FPU registers[reg] = FPU registers[reg] - (fpu_register) ((int) (FPU registers[reg] / src)) * src;
1958 {
1959 fpu_register quot = fp_round_to_zero(FPU registers[reg] / src);
1960 uae_u32 sign = get_quotient_sign(FPU registers[reg],src);
1961 FPU registers[reg] = FPU registers[reg] - quot * src;
1962 make_fpsr(FPU registers[reg]);
1963 make_quotient(quot, sign);
1964 }
1965 break;
1966 case 0x23: /* FMUL */
1967 fpu_debug(("FMUL %.04f\n",(double)src));
1968 get_dest_flags(FPU registers[reg]);
1969 get_source_flags(src);
1970 if(fl_dest.in_range && fl_source.in_range) {
1971 FPU registers[reg] *= src;
1972 }
1973 else if (fl_dest.nan || fl_source.nan ||
1974 fl_dest.zero && fl_source.infinity ||
1975 fl_dest.infinity && fl_source.zero ) {
1976 make_nan( FPU registers[reg] );
1977 }
1978 else if (fl_dest.zero || fl_source.zero ) {
1979 if (fl_dest.negative && !fl_source.negative ||
1980 !fl_dest.negative && fl_source.negative) {
1981 make_zero_negative(FPU registers[reg]);
1982 }
1983 else {
1984 make_zero_positive(FPU registers[reg]);
1985 }
1986 }
1987 else {
1988 if( fl_dest.negative && !fl_source.negative ||
1989 !fl_dest.negative && fl_source.negative) {
1990 make_inf_negative(FPU registers[reg]);
1991 }
1992 else {
1993 make_inf_positive(FPU registers[reg]);
1994 }
1995 }
1996 make_fpsr(FPU registers[reg]);
1997 break;
1998 case 0x24: /* FSGLDIV */
1999 fpu_debug(("FSGLDIV %.04f\n",(double)src));
2000 FPU registers[reg] = (float)(FPU registers[reg] / src);
2001 make_fpsr(FPU registers[reg]);
2002 break;
2003 case 0x25: /* FREM */
2004 fpu_debug(("FREM %.04f\n",(double)src));
2005 // FPU registers[reg] = FPU registers[reg] - (double) ((int) (FPU registers[reg] / src + 0.5)) * src;
2006 {
2007 fpu_register quot = fp_round_to_nearest(FPU registers[reg] / src);
2008 uae_u32 sign = get_quotient_sign(FPU registers[reg],src);
2009 FPU registers[reg] = FPU registers[reg] - quot * src;
2010 make_fpsr(FPU registers[reg]);
2011 make_quotient(quot,sign);
2012 }
2013 break;
2014
2015 case 0x26: /* FSCALE */
2016 fpu_debug(("FSCALE %.04f\n",(double)src));
2017 // TODO: overflow flags
2018 get_dest_flags(FPU registers[reg]);
2019 get_source_flags(src);
2020 if (fl_source.in_range && fl_dest.in_range) {
2021 // When the absolute value of the source operand is >= 2^14,
2022 // an overflow or underflow always results.
2023 // Here (int) cast is okay.
2024 int scale_factor = (int)fp_round_to_zero(src);
2025 #if USE_LONG_DOUBLE || USE_QUAD_DOUBLE
2026 fp_declare_init_shape(sxp, FPU registers[reg], extended);
2027 sxp->ieee.exponent += scale_factor;
2028 #else
2029 fp_declare_init_shape(sxp, FPU registers[reg], double);
2030 uae_u32 exp = sxp->ieee.exponent + scale_factor;
2031 if (exp < FP_EXTENDED_EXP_BIAS - FP_DOUBLE_EXP_BIAS)
2032 exp = 0;
2033 else if (exp > FP_EXTENDED_EXP_BIAS + FP_DOUBLE_EXP_BIAS)
2034 exp = FP_DOUBLE_EXP_MAX;
2035 else
2036 exp += FP_DOUBLE_EXP_BIAS - FP_EXTENDED_EXP_BIAS;
2037 sxp->ieee.exponent = exp;
2038 #endif
2039 }
2040 else if (fl_source.infinity) {
2041 // Returns NaN for any Infinity source
2042 make_nan( FPU registers[reg] );
2043 }
2044 make_fpsr(FPU registers[reg]);
2045 break;
2046 case 0x27: /* FSGLMUL */
2047 fpu_debug(("FSGLMUL %.04f\n",(double)src));
2048 FPU registers[reg] = (float)(FPU registers[reg] * src);
2049 make_fpsr(FPU registers[reg]);
2050 break;
2051 case 0x28: /* FSUB */
2052 fpu_debug(("FSUB %.04f\n",(double)src));
2053 FPU registers[reg] -= src;
2054 make_fpsr(FPU registers[reg]);
2055 break;
2056 case 0x22: /* FADD */
2057 fpu_debug(("FADD %.04f\n",(double)src));
2058 FPU registers[reg] += src;
2059 make_fpsr(FPU registers[reg]);
2060 break;
2061 case 0x30: /* FSINCOS */
2062 case 0x31:
2063 case 0x32:
2064 case 0x33:
2065 case 0x34:
2066 case 0x35:
2067 case 0x36:
2068 case 0x37:
2069 fpu_debug(("FSINCOS %.04f\n",(double)src));
2070 // Cosine must be calculated first if same register
2071 FPU registers[extra & 7] = fp_cos(src);
2072 FPU registers[reg] = fp_sin (src);
2073 // Set FPU fpsr according to the sine result
2074 make_fpsr(FPU registers[reg]);
2075 break;
2076 case 0x38: /* FCMP */
2077 fpu_debug(("FCMP %.04f\n",(double)src));
2078 set_fpsr(0);
2079 make_fpsr(FPU registers[reg] - src);
2080 break;
2081 case 0x3a: /* FTST */
2082 fpu_debug(("FTST %.04f\n",(double)src));
2083 set_fpsr(0);
2084 make_fpsr(src);
2085 break;
2086 default:
2087 fpu_debug(("ILLEGAL F OP %X\n",opcode));
2088 m68k_setpc (m68k_getpc () - 4);
2089 op_illg (opcode);
2090 break;
2091 }
2092 fpu_debug(("END m68k_getpc()=%X\n",m68k_getpc()));
2093 dump_registers( "END ");
2094 return;
2095 }
2096
2097 fpu_debug(("ILLEGAL F OP 2 %X\n",opcode));
2098 m68k_setpc (m68k_getpc () - 4);
2099 op_illg (opcode);
2100 dump_registers( "END ");
2101 }
2102
2103 /* -------------------------- Initialization -------------------------- */
2104
2105 PRIVATE uae_u8 m_fpu_state_original[108]; // 90/94/108
2106
2107 PUBLIC void FFPU fpu_init (bool integral_68040)
2108 {
2109 fpu_debug(("fpu_init\n"));
2110
2111 static bool initialized_lookup_tables = false;
2112 if (!initialized_lookup_tables) {
2113 fpu_init_native_fflags();
2114 fpu_init_native_exceptions();
2115 fpu_init_native_accrued_exceptions();
2116 initialized_lookup_tables = true;
2117 }
2118
2119 FPU is_integral = integral_68040;
2120 FPU instruction_address = 0;
2121 FPU fpsr.quotient = 0;
2122 set_fpcr(0);
2123 set_fpsr(0);
2124
2125 #if defined(FPU_USE_X86_ROUNDING)
2126 // Initial state after boot, reset and frestore(null frame)
2127 x86_control_word = CW_INITIAL;
2128 #elif defined(USE_X87_ASSEMBLY)
2129 volatile unsigned short int cw;
2130 __asm__ __volatile__("fnstcw %0" : "=m" (cw));
2131 cw &= ~0x0300; cw |= 0x0300; // CW_PC_EXTENDED
2132 cw &= ~0x0C00; cw |= 0x0000; // CW_RC_NEAR
2133 __asm__ __volatile__("fldcw %0" : : "m" (cw));
2134 #endif
2135
2136 FPU result = 1;
2137
2138 for (int i = 0; i < 8; i++)
2139 make_nan(FPU registers[i]);
2140 }
2141
2142 PUBLIC void FFPU fpu_exit (void)
2143 {
2144 fpu_debug(("fpu_exit\n"));
2145 }
2146
2147 PUBLIC void FFPU fpu_reset (void)
2148 {
2149 fpu_debug(("fpu_reset\n"));
2150 fpu_exit();
2151 fpu_init(FPU is_integral);
2152 }