ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/uae_cpu/fpp.cpp
Revision: 1.9
Committed: 2000-09-05T16:53:47Z (23 years, 10 months ago) by gbeauche
Branch: MAIN
CVS Tags: snapshot-17022001
Changes since 1.8: +25 -0 lines
Log Message:
- added FPU initialization routines

File Contents

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