ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/uae_cpu/fpp.cpp
Revision: 1.7
Committed: 1999-11-03T10:56:38Z (25 years ago) by cebix
Branch: MAIN
CVS Tags: snapshot-22121999, release-0_8-1, snapshot-13072000
Changes since 1.6: +2 -4 lines
Log Message:
- imported UAE CPU 0.8.10 changes
- new utility functions Mac_memset, Mac2Host_memcpy, Host2Mac_memcpu and
  Mac2Mac_memcpy
- extfs.cpp: fixed bug in fs_rename() and fs_cat_move() (auxiliary IOParam
  block was not in Mac address space)
- some provisions for using UAE CPU compiler (doesn't work yet)

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