ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/uae_cpu/fpu/fpu_ieee.cpp
Revision: 1.4
Committed: 2002-09-16T12:01:38Z (21 years, 9 months ago) by gbeauche
Branch: MAIN
Changes since 1.3: +1 -18 lines
Log Message:
- FP endianness is now testing at configure time
- Fix junk introduced in previous rev for extract_extended()

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