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