ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/uae_cpu/fpu/fpu_ieee.cpp
Revision: 1.10
Committed: 2012-03-30T01:45:08Z (12 years, 3 months ago) by asvitkine
Branch: MAIN
CVS Tags: HEAD
Changes since 1.9: +23 -3 lines
Log Message:
Add correct GPUv2 attribution to fpu_ieee.cpp and fpu_uae.cpp files, to
match the other files under uae_cpu/fpu, which have the same history
according to CVS.

File Contents

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