ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/uae_cpu/fpu/fpu_uae.cpp
Revision: 1.2
Committed: 2002-09-13T12:50:40Z (22 years ago) by gbeauche
Branch: MAIN
Changes since 1.1: +1658 -1587 lines
Log Message:
* Basilisk II JIT integration, phase 2:
- Add new FPU core architecture
- Clean fpu_x86_asm.h as it is no longer automatically generated

File Contents

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