ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/uae_cpu/fpu/fpu_ieee.cpp
Revision: 1.9
Committed: 2003-05-28T10:17:43Z (21 years, 3 months ago) by gbeauche
Branch: MAIN
CVS Tags: nigel-build-19, nigel-build-16, nigel-build-17, nigel-build-15
Changes since 1.8: +1 -1 lines
Log Message:
workaround a compiler bug on SPARC (Milan)

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