ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/uae_cpu/fpu/fpu_ieee.cpp
Revision: 1.3
Committed: 2002-09-15T18:21:13Z (22 years ago) by gbeauche
Branch: MAIN
Changes since 1.2: +117 -116 lines
Log Message:
Fix "ieee" FPU core on big endian and without long double > double support
- Handle conversions to/from host double for m68k long doubles formats
- Make mathlib aware of sizeof(long double) == sizeof(double) arches
- Attempt to fix FSCALE implementation

File Contents

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