ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/uae_cpu/fpu/fpu_ieee.cpp
Revision: 1.2
Committed: 2002-09-13T15:06:42Z (21 years, 9 months ago) by gbeauche
Branch: MAIN
Changes since 1.1: +2 -0 lines
Log Message:
USE_LONG_DOUBLE guards

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