ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/uae_cpu/fpu/fpu_ieee.cpp
Revision: 1.7
Committed: 2002-11-16T15:28:25Z (21 years, 7 months ago) by gbeauche
Branch: MAIN
CVS Tags: nigel-build-12, nigel-build-13
Changes since 1.6: +1 -1 lines
Log Message:
Use old x87 FPU stack on x86-64 too because we now use long doubles there for
better accuracy. Aka. prefer compatibility over speed.

File Contents

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