ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/uae_cpu/fpp.cpp
Revision: 1.5
Committed: 1999-10-28T15:33:18Z (24 years, 8 months ago) by cebix
Branch: MAIN
Changes since 1.4: +98 -55 lines
Log Message:
- added some 68040 instructions: CINV, CPUSH, MOVE16 (Ax)+,(Ay)+, MOVEC regs,
  and FPU state frames; enough to boot MacOS
- CPU type can be selected in GTK prefs editor

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     static int sz1[8] =
876     {4, 4, 12, 12, 2, 8, 1, 0};
877     static int sz2[8] =
878     {4, 4, 12, 12, 2, 8, 2, 0};
879    
880     // D(bug("put_fp_value(%.04f,%X,%X)\r\n",(float)value,(int)opcode,(int)extra));
881    
882     if ((extra & 0x4000) == 0) {
883     int dest_reg = (extra >> 10) & 7;
884     regs.fp[dest_reg] = value;
885     MAKE_FPSR(regs.fpsr,regs.fp[dest_reg]);
886     return 1;
887     }
888     mode = (opcode >> 3) & 7;
889     reg = opcode & 7;
890     size = (extra >> 10) & 7;
891     ad = 0xffffffff;
892     switch (mode) {
893 cebix 1.1 case 0:
894 cebix 1.2 switch (size) {
895     case 6:
896     m68k_dreg (regs, reg) = (((int) value & 0xff)
897 cebix 1.1 | (m68k_dreg (regs, reg) & ~0xff));
898 cebix 1.2 break;
899     case 4:
900     m68k_dreg (regs, reg) = (((int) value & 0xffff)
901 cebix 1.1 | (m68k_dreg (regs, reg) & ~0xffff));
902 cebix 1.2 break;
903     case 0:
904     m68k_dreg (regs, reg) = (int) value;
905     break;
906     case 1:
907     m68k_dreg (regs, reg) = from_single(value);
908     break;
909     default:
910     return 0;
911     }
912     return 1;
913     case 1:
914     return 0;
915 cebix 1.1 case 2:
916 cebix 1.2 ad = m68k_areg (regs, reg);
917     break;
918 cebix 1.1 case 3:
919 cebix 1.2 ad = m68k_areg (regs, reg);
920     m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size];
921     break;
922 cebix 1.1 case 4:
923 cebix 1.2 m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size];
924     ad = m68k_areg (regs, reg);
925     break;
926 cebix 1.1 case 5:
927 cebix 1.2 ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) next_iword();
928     break;
929 cebix 1.1 case 6:
930 cebix 1.2 ad = get_disp_ea_020 (m68k_areg (regs, reg), next_iword());
931     break;
932 cebix 1.1 case 7:
933 cebix 1.2 switch (reg) {
934     case 0:
935     ad = (uae_s32) (uae_s16) next_iword();
936     break;
937     case 1:
938     ad = next_ilong();
939     break;
940     case 2:
941     ad = m68k_getpc ();
942     ad += (uae_s32) (uae_s16) next_iword();
943     break;
944     case 3:
945     tmppc = m68k_getpc ();
946     tmp = (uae_u16)next_iword();
947     ad = get_disp_ea_020 (tmppc, tmp);
948     break;
949     case 4:
950     ad = m68k_getpc ();
951     m68k_setpc (ad + sz2[size]);
952     break;
953     default:
954     return 0;
955     }
956     }
957     switch (size) {
958 cebix 1.1 case 0:
959 cebix 1.2 put_long (ad, (uae_s32) value);
960     break;
961 cebix 1.1 case 1:
962 cebix 1.2 put_long (ad, from_single(value));
963     break;
964     case 2:
965     {
966     uae_u32 wrd1, wrd2, wrd3;
967     from_exten(value, &wrd1, &wrd2, &wrd3);
968     put_long (ad, wrd1);
969     ad += 4;
970     put_long (ad, wrd2);
971     ad += 4;
972     put_long (ad, wrd3);
973     }
974     break;
975 cebix 1.1 case 3:
976 cebix 1.2 {
977     uae_u32 wrd1, wrd2, wrd3;
978     from_pack(value, &wrd1, &wrd2, &wrd3);
979     put_long (ad, wrd1);
980     ad += 4;
981     put_long (ad, wrd2);
982     ad += 4;
983     put_long (ad, wrd3);
984     }
985     break;
986     case 4:
987     put_word(ad, (uae_s16) value);
988     break;
989 cebix 1.1 case 5:{
990     uae_u32 wrd1, wrd2;
991     from_double(value, &wrd1, &wrd2);
992     put_long (ad, wrd1);
993     ad += 4;
994     put_long (ad, wrd2);
995 cebix 1.2 }
996     break;
997 cebix 1.1 case 6:
998 cebix 1.2 put_byte(ad, (uae_s8) value);
999     break;
1000 cebix 1.1 default:
1001 cebix 1.2 return 0;
1002     }
1003     return 1;
1004 cebix 1.1 }
1005    
1006     static __inline__ int get_fp_ad(uae_u32 opcode, uae_u32 * ad)
1007     {
1008 cebix 1.2 uae_u16 tmp;
1009     uaecptr tmppc;
1010     int mode;
1011     int reg;
1012    
1013     mode = (opcode >> 3) & 7;
1014     reg = opcode & 7;
1015     switch (mode) {
1016 cebix 1.1 case 0:
1017     case 1:
1018 cebix 1.2 return 0;
1019 cebix 1.1 case 2:
1020 cebix 1.2 *ad = m68k_areg (regs, reg);
1021     break;
1022 cebix 1.1 case 3:
1023 cebix 1.2 *ad = m68k_areg (regs, reg);
1024     break;
1025 cebix 1.1 case 4:
1026 cebix 1.2 *ad = m68k_areg (regs, reg);
1027     break;
1028 cebix 1.1 case 5:
1029 cebix 1.2 *ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) next_iword();
1030     break;
1031 cebix 1.1 case 6:
1032 cebix 1.2 *ad = get_disp_ea_020 (m68k_areg (regs, reg), next_iword());
1033     break;
1034 cebix 1.1 case 7:
1035 cebix 1.2 switch (reg) {
1036     case 0:
1037     *ad = (uae_s32) (uae_s16) next_iword();
1038     break;
1039     case 1:
1040     *ad = next_ilong();
1041     break;
1042     case 2:
1043     *ad = m68k_getpc ();
1044     *ad += (uae_s32) (uae_s16) next_iword();
1045     break;
1046     case 3:
1047     tmppc = m68k_getpc ();
1048     tmp = (uae_u16)next_iword();
1049     *ad = get_disp_ea_020 (tmppc, tmp);
1050     break;
1051     default:
1052     return 0;
1053     }
1054     }
1055     return 1;
1056 cebix 1.1 }
1057    
1058     static __inline__ int fpp_cond(uae_u32 opcode, int contition)
1059     {
1060 cebix 1.2 int N = (regs.fpsr & 0x8000000) != 0;
1061     int Z = (regs.fpsr & 0x4000000) != 0;
1062     /* int I = (regs.fpsr & 0x2000000) != 0; */
1063     int NotANumber = (regs.fpsr & 0x1000000) != 0;
1064 cebix 1.1
1065 cebix 1.2 switch (contition) {
1066 cebix 1.1 case 0x00:
1067 cebix 1.2 CONDRET("False",0);
1068 cebix 1.1 case 0x01:
1069 cebix 1.2 CONDRET("Equal",Z);
1070 cebix 1.1 case 0x02:
1071 cebix 1.2 CONDRET("Ordered Greater Than",!(NotANumber || Z || N));
1072 cebix 1.1 case 0x03:
1073 cebix 1.2 CONDRET("Ordered Greater Than or Equal",Z || !(NotANumber || N));
1074 cebix 1.1 case 0x04:
1075 cebix 1.2 CONDRET("Ordered Less Than",N && !(NotANumber || Z));
1076 cebix 1.1 case 0x05:
1077 cebix 1.2 CONDRET("Ordered Less Than or Equal",Z || (N && !NotANumber));
1078 cebix 1.1 case 0x06:
1079 cebix 1.2 CONDRET("Ordered Greater or Less Than",!(NotANumber || Z));
1080 cebix 1.1 case 0x07:
1081 cebix 1.2 CONDRET("Ordered",!NotANumber);
1082 cebix 1.1 case 0x08:
1083 cebix 1.2 CONDRET("Unordered",NotANumber);
1084 cebix 1.1 case 0x09:
1085 cebix 1.2 CONDRET("Unordered or Equal",NotANumber || Z);
1086 cebix 1.1 case 0x0a:
1087 cebix 1.2 CONDRET("Unordered or Greater Than",NotANumber || !(N || Z));
1088 cebix 1.1 case 0x0b:
1089 cebix 1.2 CONDRET("Unordered or Greater or Equal",NotANumber || Z || !N);
1090 cebix 1.1 case 0x0c:
1091 cebix 1.2 CONDRET("Unordered or Less Than",NotANumber || (N && !Z));
1092 cebix 1.1 case 0x0d:
1093 cebix 1.2 CONDRET("Unordered or Less or Equal",NotANumber || Z || N);
1094 cebix 1.1 case 0x0e:
1095 cebix 1.2 CONDRET("Not Equal",!Z);
1096 cebix 1.1 case 0x0f:
1097 cebix 1.2 CONDRET("True",1);
1098 cebix 1.1 case 0x10:
1099 cebix 1.2 CONDRET("Signaling False",0);
1100 cebix 1.1 case 0x11:
1101 cebix 1.2 CONDRET("Signaling Equal",Z);
1102 cebix 1.1 case 0x12:
1103 cebix 1.2 CONDRET("Greater Than",!(NotANumber || Z || N));
1104 cebix 1.1 case 0x13:
1105 cebix 1.2 CONDRET("Greater Than or Equal",Z || !(NotANumber || N));
1106 cebix 1.1 case 0x14:
1107 cebix 1.2 CONDRET("Less Than",N && !(NotANumber || Z));
1108 cebix 1.1 case 0x15:
1109 cebix 1.2 CONDRET("Less Than or Equal",Z || (N && !NotANumber));
1110 cebix 1.1 case 0x16:
1111 cebix 1.2 CONDRET("Greater or Less Than",!(NotANumber || Z));
1112 cebix 1.1 case 0x17:
1113 cebix 1.2 CONDRET("Greater, Less or Equal",!NotANumber);
1114 cebix 1.1 case 0x18:
1115 cebix 1.2 CONDRET("Not Greater, Less or Equal",NotANumber);
1116 cebix 1.1 case 0x19:
1117 cebix 1.2 CONDRET("Not Greater or Less Than",NotANumber || Z);
1118 cebix 1.1 case 0x1a:
1119 cebix 1.2 CONDRET("Not Less Than or Equal",NotANumber || !(N || Z));
1120 cebix 1.1 case 0x1b:
1121 cebix 1.2 CONDRET("Not Less Than",NotANumber || Z || !N);
1122 cebix 1.1 case 0x1c:
1123 cebix 1.2 // CONDRET("Not Greater Than or Equal",NotANumber || (Z && N));
1124     CONDRET("Not Greater Than or Equal",!Z && (NotANumber || N));
1125 cebix 1.1 case 0x1d:
1126 cebix 1.2 CONDRET("Not Greater Than",NotANumber || Z || N);
1127 cebix 1.1 case 0x1e:
1128 cebix 1.2 CONDRET("Signaling Not Equal",!Z);
1129 cebix 1.1 case 0x1f:
1130 cebix 1.2 CONDRET("Signaling True",1);
1131     }
1132     CONDRET("",-1);
1133 cebix 1.1 }
1134    
1135     void fdbcc_opp(uae_u32 opcode, uae_u16 extra)
1136     {
1137 cebix 1.2 uaecptr pc = (uae_u32) m68k_getpc ();
1138     uae_s32 disp = (uae_s32) (uae_s16) next_iword();
1139     int cc;
1140    
1141     D(bug("fdbcc_opp %X, %X at %08lx\r\n", (uae_u32)opcode, (uae_u32)extra, m68k_getpc ()));
1142    
1143     cc = fpp_cond(opcode, extra & 0x3f);
1144     if (cc == -1) {
1145     m68k_setpc (pc - 4);
1146     op_illg (opcode);
1147     } else if (!cc) {
1148     int reg = opcode & 0x7;
1149 cebix 1.1
1150 cebix 1.2 // this may have leaked.
1151     /*
1152     m68k_dreg (regs, reg) = ((m68k_dreg (regs, reg) & ~0xffff)
1153 cebix 1.1 | ((m68k_dreg (regs, reg) - 1) & 0xffff));
1154 cebix 1.2 */
1155     m68k_dreg (regs, reg) = ((m68k_dreg (regs, reg) & 0xffff0000)
1156     | (((m68k_dreg (regs, reg) & 0xffff) - 1) & 0xffff));
1157    
1158    
1159     // condition reversed.
1160     // if ((m68k_dreg (regs, reg) & 0xffff) == 0xffff)
1161     if ((m68k_dreg (regs, reg) & 0xffff) != 0xffff)
1162 cebix 1.1 m68k_setpc (pc + disp);
1163 cebix 1.2 }
1164 cebix 1.1 }
1165    
1166     void fscc_opp(uae_u32 opcode, uae_u16 extra)
1167     {
1168 cebix 1.2 uae_u32 ad;
1169     int cc;
1170    
1171     D(bug("fscc_opp %X, %X at %08lx\r\n", (uae_u32)opcode, (uae_u32)extra, m68k_getpc ()));
1172 cebix 1.1
1173 cebix 1.2 cc = fpp_cond(opcode, extra & 0x3f);
1174     if (cc == -1) {
1175     m68k_setpc (m68k_getpc () - 4);
1176     op_illg (opcode);
1177     } else if ((opcode & 0x38) == 0) {
1178     m68k_dreg (regs, opcode & 7) = (m68k_dreg (regs, opcode & 7) & ~0xff) |
1179 cebix 1.1 (cc ? 0xff : 0x00);
1180 cebix 1.2 } else {
1181     if (get_fp_ad(opcode, &ad) == 0) {
1182 cebix 1.1 m68k_setpc (m68k_getpc () - 4);
1183     op_illg (opcode);
1184 cebix 1.2 } else
1185 cebix 1.1 put_byte(ad, cc ? 0xff : 0x00);
1186 cebix 1.2 }
1187 cebix 1.1 }
1188    
1189     void ftrapcc_opp(uae_u32 opcode, uaecptr oldpc)
1190     {
1191 cebix 1.2 int cc;
1192    
1193     D(bug("ftrapcc_opp %X at %08lx\r\n", (uae_u32)opcode, m68k_getpc ()));
1194 cebix 1.1
1195 cebix 1.2 cc = fpp_cond(opcode, opcode & 0x3f);
1196     if (cc == -1) {
1197     m68k_setpc (oldpc);
1198     op_illg (opcode);
1199     }
1200     if (cc)
1201     Exception(7, oldpc - 2);
1202 cebix 1.1 }
1203    
1204 cebix 1.2 // NOTE that we get here also when there is a FNOP (nontrapping false, displ 0)
1205 cebix 1.1 void fbcc_opp(uae_u32 opcode, uaecptr pc, uae_u32 extra)
1206     {
1207 cebix 1.2 int cc;
1208    
1209     D(bug("fbcc_opp %X, %X at %08lx, jumpto=%X\r\n", (uae_u32)opcode, (uae_u32)extra, m68k_getpc (), extra ));
1210 cebix 1.1
1211 cebix 1.2 cc = fpp_cond(opcode, opcode & 0x3f);
1212     if (cc == -1) {
1213     m68k_setpc (pc);
1214     op_illg (opcode);
1215     } else if (cc) {
1216     if ((opcode & 0x40) == 0)
1217 cebix 1.1 extra = (uae_s32) (uae_s16) extra;
1218 cebix 1.2 m68k_setpc (pc + extra);
1219     }
1220 cebix 1.1 }
1221    
1222 cebix 1.2 // FSAVE has no post-increment
1223     // 0x1f180000 == IDLE state frame, coprocessor version number 1F
1224 cebix 1.1 void fsave_opp(uae_u32 opcode)
1225     {
1226 cebix 1.2 uae_u32 ad;
1227     int incr = (opcode & 0x38) == 0x20 ? -1 : 1;
1228     int i;
1229    
1230     D(bug("fsave_opp at %08lx\r\n", m68k_getpc ()));
1231    
1232     if (get_fp_ad(opcode, &ad) == 0) {
1233     m68k_setpc (m68k_getpc () - 2);
1234     op_illg (opcode);
1235     return;
1236     }
1237    
1238 cebix 1.5 if (CPUType == 4) {
1239     // Put 4 byte 68040 IDLE frame.
1240     if (incr < 0) {
1241     ad -= 4;
1242     put_long (ad, 0x41000000);
1243     } else {
1244     put_long (ad, 0x41000000);
1245     ad += 4;
1246 cebix 1.2 }
1247 cebix 1.5 } else {
1248     // Put 28 byte 68881 IDLE frame.
1249     if (incr < 0) {
1250     D(bug("fsave_opp pre-decrement\r\n"));
1251     ad -= 4;
1252     // What's this? Some BIU flags, or (incorrectly placed) command/condition?
1253     put_long (ad, 0x70000000);
1254     for (i = 0; i < 5; i++) {
1255     ad -= 4;
1256     put_long (ad, 0x00000000);
1257     }
1258     ad -= 4;
1259     put_long (ad, 0x1f180000); // IDLE, vers 1f
1260     } else {
1261     put_long (ad, 0x1f180000); // IDLE, vers 1f
1262     ad += 4;
1263     for (i = 0; i < 5; i++) {
1264     put_long (ad, 0x00000000);
1265     ad += 4;
1266     }
1267     // What's this? Some BIU flags, or (incorrectly placed) command/condition?
1268     put_long (ad, 0x70000000);
1269     ad += 4;
1270     }
1271     }
1272 cebix 1.2 if ((opcode & 0x38) == 0x18) {
1273     m68k_areg (regs, opcode & 7) = ad; // Never executed on a 68881
1274     D(bug("PROBLEM: fsave_opp post-increment\r\n"));
1275     }
1276     if ((opcode & 0x38) == 0x20) {
1277     m68k_areg (regs, opcode & 7) = ad;
1278     D(bug("fsave_opp pre-decrement %X -> A%d\r\n",ad,opcode & 7));
1279 cebix 1.1 }
1280     }
1281    
1282 cebix 1.5 // FRESTORE has no pre-decrement
1283 cebix 1.1 void frestore_opp(uae_u32 opcode)
1284     {
1285 cebix 1.2 uae_u32 ad;
1286     uae_u32 d;
1287     int incr = (opcode & 0x38) == 0x20 ? -1 : 1;
1288    
1289     D(bug("frestore_opp at %08lx\r\n", m68k_getpc ()));
1290    
1291     if (get_fp_ad(opcode, &ad) == 0) {
1292     m68k_setpc (m68k_getpc () - 2);
1293     op_illg (opcode);
1294     return;
1295     }
1296    
1297 cebix 1.5 if (CPUType == 4) {
1298     // 68040
1299     if (incr < 0) {
1300     D(bug("PROBLEM: frestore_opp incr < 0\r\n"));
1301     // this may be wrong, but it's never called.
1302     ad -= 4;
1303     d = get_long (ad);
1304     if ((d & 0xff000000) != 0) { // Not a NULL frame?
1305     if ((d & 0x00ff0000) == 0) { // IDLE
1306     D(bug("frestore_opp found IDLE frame at %X\r\n",ad-4));
1307     } else if ((d & 0x00ff0000) == 0x00300000) { // UNIMP
1308     D(bug("PROBLEM: frestore_opp found UNIMP frame at %X\r\n",ad-4));
1309     ad -= 44;
1310     } else if ((d & 0x00ff0000) == 0x00600000) { // BUSY
1311     D(bug("PROBLEM: frestore_opp found BUSY frame at %X\r\n",ad-4));
1312     ad -= 92;
1313     }
1314     }
1315     } else {
1316     d = get_long (ad);
1317     D(bug("frestore_opp frame at %X = %X\r\n",ad,d));
1318     ad += 4;
1319     if ((d & 0xff000000) != 0) { // Not a NULL frame?
1320     if ((d & 0x00ff0000) == 0) { // IDLE
1321     D(bug("frestore_opp found IDLE frame at %X\r\n",ad-4));
1322     } else if ((d & 0x00ff0000) == 0x00300000) { // UNIMP
1323     D(bug("PROBLEM: frestore_opp found UNIMP frame at %X\r\n",ad-4));
1324     ad += 44;
1325     } else if ((d & 0x00ff0000) == 0x00600000) { // BUSY
1326     D(bug("PROBLEM: frestore_opp found BUSY frame at %X\r\n",ad-4));
1327     ad += 92;
1328     }
1329     }
1330 cebix 1.2 }
1331 cebix 1.5 } else {
1332     // 68881
1333     if (incr < 0) {
1334     D(bug("PROBLEM: frestore_opp incr < 0\r\n"));
1335     // this may be wrong, but it's never called.
1336     ad -= 4;
1337     d = get_long (ad);
1338     if ((d & 0xff000000) != 0) {
1339     if ((d & 0x00ff0000) == 0x00180000)
1340     ad -= 6 * 4;
1341     else if ((d & 0x00ff0000) == 0x00380000)
1342     ad -= 14 * 4;
1343     else if ((d & 0x00ff0000) == 0x00b40000)
1344     ad -= 45 * 4;
1345     }
1346     } else {
1347     d = get_long (ad);
1348     D(bug("frestore_opp frame at %X = %X\r\n",ad,d));
1349     ad += 4;
1350     if ((d & 0xff000000) != 0) { // Not a NULL frame?
1351     if ((d & 0x00ff0000) == 0x00180000) { // IDLE
1352     D(bug("frestore_opp found IDLE frame at %X\r\n",ad-4));
1353     ad += 6 * 4;
1354     } else if ((d & 0x00ff0000) == 0x00380000) {// UNIMP? shouldn't it be 3C?
1355     ad += 14 * 4;
1356     D(bug("PROBLEM: frestore_opp found UNIMP? frame at %X\r\n",ad-4));
1357     } else if ((d & 0x00ff0000) == 0x00b40000) {// BUSY
1358     D(bug("PROBLEM: frestore_opp found BUSY frame at %X\r\n",ad-4));
1359     ad += 45 * 4;
1360     }
1361 cebix 1.2 }
1362     }
1363     }
1364     if ((opcode & 0x38) == 0x18) {
1365     m68k_areg (regs, opcode & 7) = ad;
1366     D(bug("frestore_opp post-increment %X -> A%d\r\n",ad,opcode & 7));
1367 cebix 1.1 }
1368 cebix 1.2 if ((opcode & 0x38) == 0x20) {
1369     m68k_areg (regs, opcode & 7) = ad; // Never executed on a 68881
1370     D(bug("PROBLEM: frestore_opp pre-decrement\r\n"));
1371 cebix 1.1 }
1372     }
1373    
1374     void fpp_opp(uae_u32 opcode, uae_u16 extra)
1375     {
1376 cebix 1.2 int reg;
1377     double src;
1378 cebix 1.1
1379 cebix 1.2 D(bug("FPP %04lx %04x at %08lx\r\n", opcode & 0xffff, extra & 0xffff,
1380     m68k_getpc () - 4));
1381    
1382     dump_fp_regs( "START");
1383    
1384     switch ((extra >> 13) & 0x7) {
1385 cebix 1.1 case 3:
1386 cebix 1.2 D(bug("FMOVE -> <ea>\r\n"));
1387     if (put_fp_value (regs.fp[(extra >> 7) & 7], opcode, extra) == 0) {
1388     m68k_setpc (m68k_getpc () - 4);
1389     op_illg (opcode);
1390     }
1391     dump_fp_regs( "END ");
1392     return;
1393 cebix 1.1 case 4:
1394     case 5:
1395 cebix 1.2 if ((opcode & 0x38) == 0) {
1396     if (extra & 0x2000) { // dr bit
1397     if (extra & 0x1000) {
1398     // according to the manual, the msb bits are always zero.
1399     m68k_dreg (regs, opcode & 7) = regs.fpcr & 0xFFFF;
1400     D(bug("FMOVEM regs.fpcr (%X) -> D%d\r\n", regs.fpcr, opcode & 7));
1401     }
1402     if (extra & 0x0800) {
1403     m68k_dreg (regs, opcode & 7) = regs.fpsr;
1404     D(bug("FMOVEM regs.fpsr (%X) -> D%d\r\n", regs.fpsr, opcode & 7));
1405     }
1406     if (extra & 0x0400) {
1407     m68k_dreg (regs, opcode & 7) = regs.fpiar;
1408     D(bug("FMOVEM regs.fpiar (%X) -> D%d\r\n", regs.fpiar, opcode & 7));
1409     }
1410     } else {
1411     if (extra & 0x1000) {
1412     regs.fpcr = m68k_dreg (regs, opcode & 7);
1413     D(bug("FMOVEM D%d (%X) -> regs.fpcr\r\n", opcode & 7, regs.fpcr));
1414     }
1415     if (extra & 0x0800) {
1416     regs.fpsr = m68k_dreg (regs, opcode & 7);
1417     D(bug("FMOVEM D%d (%X) -> regs.fpsr\r\n", opcode & 7, regs.fpsr));
1418     }
1419     if (extra & 0x0400) {
1420     regs.fpiar = m68k_dreg (regs, opcode & 7);
1421     D(bug("FMOVEM D%d (%X) -> regs.fpiar\r\n", opcode & 7, regs.fpiar));
1422     }
1423     }
1424     // } else if ((opcode & 0x38) == 1) {
1425     } else if ((opcode & 0x38) == 8) {
1426     if (extra & 0x2000) { // dr bit
1427     if (extra & 0x1000) {
1428     // according to the manual, the msb bits are always zero.
1429     m68k_areg (regs, opcode & 7) = regs.fpcr & 0xFFFF;
1430     D(bug("FMOVEM regs.fpcr (%X) -> A%d\r\n", regs.fpcr, opcode & 7));
1431     }
1432     if (extra & 0x0800) {
1433     m68k_areg (regs, opcode & 7) = regs.fpsr;
1434     D(bug("FMOVEM regs.fpsr (%X) -> A%d\r\n", regs.fpsr, opcode & 7));
1435     }
1436     if (extra & 0x0400) {
1437     m68k_areg (regs, opcode & 7) = regs.fpiar;
1438     D(bug("FMOVEM regs.fpiar (%X) -> A%d\r\n", regs.fpiar, opcode & 7));
1439     }
1440     } else {
1441     if (extra & 0x1000) {
1442     regs.fpcr = m68k_areg (regs, opcode & 7);
1443     D(bug("FMOVEM A%d (%X) -> regs.fpcr\r\n", opcode & 7, regs.fpcr));
1444     }
1445     if (extra & 0x0800) {
1446     regs.fpsr = m68k_areg (regs, opcode & 7);
1447     D(bug("FMOVEM A%d (%X) -> regs.fpsr\r\n", opcode & 7, regs.fpsr));
1448     }
1449     if (extra & 0x0400) {
1450     regs.fpiar = m68k_areg (regs, opcode & 7);
1451     D(bug("FMOVEM A%d (%X) -> regs.fpiar\r\n", opcode & 7, regs.fpiar));
1452     }
1453     }
1454     } else if ((opcode & 0x3f) == 0x3c) {
1455     if ((extra & 0x2000) == 0) {
1456     if (extra & 0x1000) {
1457     regs.fpcr = next_ilong();
1458     D(bug("FMOVEM #<%X> -> regs.fpcr\r\n", regs.fpcr));
1459     }
1460     if (extra & 0x0800) {
1461     regs.fpsr = next_ilong();
1462     D(bug("FMOVEM #<%X> -> regs.fpsr\r\n", regs.fpsr));
1463     }
1464     if (extra & 0x0400) {
1465     regs.fpiar = next_ilong();
1466     D(bug("FMOVEM #<%X> -> regs.fpiar\r\n", regs.fpiar));
1467     }
1468     }
1469     } else if (extra & 0x2000) {
1470     /* FMOVEM FPP->memory */
1471    
1472     uae_u32 ad;
1473     int incr = 0;
1474    
1475     if (get_fp_ad(opcode, &ad) == 0) {
1476     m68k_setpc (m68k_getpc () - 4);
1477     op_illg (opcode);
1478     dump_fp_regs( "END ");
1479     return;
1480     }
1481     if ((opcode & 0x38) == 0x20) {
1482     if (extra & 0x1000)
1483     incr += 4;
1484     if (extra & 0x0800)
1485     incr += 4;
1486     if (extra & 0x0400)
1487     incr += 4;
1488     }
1489     ad -= incr;
1490     if (extra & 0x1000) {
1491     // according to the manual, the msb bits are always zero.
1492     put_long (ad, regs.fpcr & 0xFFFF);
1493     D(bug("FMOVEM regs.fpcr (%X) -> mem %X\r\n", regs.fpcr, ad ));
1494     ad += 4;
1495     }
1496     if (extra & 0x0800) {
1497     put_long (ad, regs.fpsr);
1498     D(bug("FMOVEM regs.fpsr (%X) -> mem %X\r\n", regs.fpsr, ad ));
1499     ad += 4;
1500     }
1501     if (extra & 0x0400) {
1502     put_long (ad, regs.fpiar);
1503     D(bug("FMOVEM regs.fpiar (%X) -> mem %X\r\n", regs.fpiar, ad ));
1504     ad += 4;
1505     }
1506     ad -= incr;
1507     if ((opcode & 0x38) == 0x18) // post-increment?
1508     m68k_areg (regs, opcode & 7) = ad;
1509     if ((opcode & 0x38) == 0x20) // pre-decrement?
1510     m68k_areg (regs, opcode & 7) = ad;
1511     } else {
1512     /* FMOVEM memory->FPP */
1513    
1514     uae_u32 ad;
1515    
1516     if (get_fp_ad(opcode, &ad) == 0) {
1517     m68k_setpc (m68k_getpc () - 4);
1518     op_illg (opcode);
1519     dump_fp_regs( "END ");
1520     return;
1521     }
1522    
1523     // ad = (opcode & 0x38) == 0x20 ? ad - 12 : ad;
1524     int incr = 0;
1525     if((opcode & 0x38) == 0x20) {
1526     if (extra & 0x1000)
1527     incr += 4;
1528     if (extra & 0x0800)
1529     incr += 4;
1530     if (extra & 0x0400)
1531     incr += 4;
1532     ad = ad - incr;
1533     }
1534    
1535     if (extra & 0x1000) {
1536     regs.fpcr = get_long (ad);
1537     D(bug("FMOVEM mem %X (%X) -> regs.fpcr\r\n", ad, regs.fpcr ));
1538     ad += 4;
1539     }
1540     if (extra & 0x0800) {
1541     regs.fpsr = get_long (ad);
1542     D(bug("FMOVEM mem %X (%X) -> regs.fpsr\r\n", ad, regs.fpsr ));
1543     ad += 4;
1544     }
1545     if (extra & 0x0400) {
1546     regs.fpiar = get_long (ad);
1547     D(bug("FMOVEM mem %X (%X) -> regs.fpiar\r\n", ad, regs.fpiar ));
1548     ad += 4;
1549     }
1550     if ((opcode & 0x38) == 0x18) // post-increment?
1551     m68k_areg (regs, opcode & 7) = ad;
1552     if ((opcode & 0x38) == 0x20) // pre-decrement?
1553     // m68k_areg (regs, opcode & 7) = ad - 12;
1554     m68k_areg (regs, opcode & 7) = ad - incr;
1555     }
1556     dump_fp_regs( "END ");
1557     return;
1558 cebix 1.1 case 6:
1559     case 7:
1560 cebix 1.2 {
1561 cebix 1.1 uae_u32 ad, list = 0;
1562     int incr = 0;
1563     if (extra & 0x2000) {
1564 cebix 1.2 /* FMOVEM FPP->memory */
1565    
1566     D(bug("FMOVEM FPP->memory\r\n"));
1567    
1568     if (get_fp_ad(opcode, &ad) == 0) {
1569     m68k_setpc (m68k_getpc () - 4);
1570     op_illg (opcode);
1571     dump_fp_regs( "END ");
1572     return;
1573     }
1574     switch ((extra >> 11) & 3) {
1575     case 0: /* static pred */
1576     list = extra & 0xff;
1577     incr = -1;
1578     break;
1579     case 1: /* dynamic pred */
1580     list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff;
1581     incr = -1;
1582     break;
1583     case 2: /* static postinc */
1584     list = extra & 0xff;
1585     incr = 1;
1586     break;
1587     case 3: /* dynamic postinc */
1588     list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff;
1589     incr = 1;
1590     break;
1591     }
1592    
1593     if (incr < 0) {
1594     for(reg=7; reg>=0; reg--) {
1595     uae_u32 wrd1, wrd2, wrd3;
1596     if( list & 0x80 ) {
1597     from_exten(regs.fp[reg],&wrd1, &wrd2, &wrd3);
1598     ad -= 4;
1599     put_long (ad, wrd3);
1600     ad -= 4;
1601     put_long (ad, wrd2);
1602     ad -= 4;
1603     put_long (ad, wrd1);
1604     }
1605     list <<= 1;
1606     }
1607     } else {
1608     for(reg=0; reg<8; reg++) {
1609     uae_u32 wrd1, wrd2, wrd3;
1610     if( list & 0x80 ) {
1611     from_exten(regs.fp[reg],&wrd1, &wrd2, &wrd3);
1612     put_long (ad, wrd3);
1613     ad += 4;
1614     put_long (ad, wrd2);
1615     ad += 4;
1616     put_long (ad, wrd1);
1617     ad += 4;
1618     }
1619     list <<= 1;
1620     }
1621     }
1622    
1623     /*
1624     while (list) {
1625     uae_u32 wrd1, wrd2, wrd3;
1626     if (incr < 0) {
1627     from_exten(regs.fp[fpp_movem_index2[list]],
1628     &wrd1, &wrd2, &wrd3);
1629     ad -= 4;
1630     put_long (ad, wrd3);
1631     ad -= 4;
1632     put_long (ad, wrd2);
1633     ad -= 4;
1634     put_long (ad, wrd1);
1635     } else {
1636     from_exten(regs.fp[fpp_movem_index1[list]],
1637     &wrd1, &wrd2, &wrd3);
1638     put_long (ad, wrd1);
1639     ad += 4;
1640     put_long (ad, wrd2);
1641     ad += 4;
1642     put_long (ad, wrd3);
1643     ad += 4;
1644     }
1645     list = fpp_movem_next[list];
1646     }
1647     */
1648     if ((opcode & 0x38) == 0x18) // post-increment?
1649     m68k_areg (regs, opcode & 7) = ad;
1650     if ((opcode & 0x38) == 0x20) // pre-decrement?
1651     m68k_areg (regs, opcode & 7) = ad;
1652     } else {
1653     /* FMOVEM memory->FPP */
1654    
1655     D(bug("FMOVEM memory->FPP\r\n"));
1656    
1657     if (get_fp_ad(opcode, &ad) == 0) {
1658     m68k_setpc (m68k_getpc () - 4);
1659     op_illg (opcode);
1660     dump_fp_regs( "END ");
1661     return;
1662     }
1663     switch ((extra >> 11) & 3) {
1664     case 0: /* static pred */
1665     D(bug("memory->FMOVEM FPP not legal mode.\r\n"));
1666     list = extra & 0xff;
1667     incr = -1;
1668     break;
1669     case 1: /* dynamic pred */
1670     D(bug("memory->FMOVEM FPP not legal mode.\r\n"));
1671     list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff;
1672     incr = -1;
1673     break;
1674     case 2: /* static postinc */
1675     list = extra & 0xff;
1676     incr = 1;
1677     break;
1678     case 3: /* dynamic postinc */
1679     list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff;
1680     incr = 1;
1681     break;
1682     }
1683    
1684     /**/
1685     if (incr < 0) {
1686     // not reached
1687     for(reg=7; reg>=0; reg--) {
1688     uae_u32 wrd1, wrd2, wrd3;
1689     if( list & 0x80 ) {
1690     wrd1 = get_long (ad);
1691     ad -= 4;
1692     wrd2 = get_long (ad);
1693     ad -= 4;
1694     wrd3 = get_long (ad);
1695     ad -= 4;
1696     regs.fp[reg] = to_exten (wrd1, wrd2, wrd3);
1697     }
1698     list <<= 1;
1699     }
1700     } else {
1701     for(reg=0; reg<8; reg++) {
1702     uae_u32 wrd1, wrd2, wrd3;
1703     if( list & 0x80 ) {
1704     wrd1 = get_long (ad);
1705     ad += 4;
1706     wrd2 = get_long (ad);
1707     ad += 4;
1708     wrd3 = get_long (ad);
1709     ad += 4;
1710     regs.fp[reg] = to_exten (wrd1, wrd2, wrd3);
1711     }
1712     list <<= 1;
1713     }
1714     }
1715     /**/
1716    
1717     /*
1718     while (list) {
1719     uae_u32 wrd1, wrd2, wrd3;
1720     if (incr < 0) {
1721     ad -= 4;
1722     wrd3 = get_long (ad);
1723     ad -= 4;
1724     wrd2 = get_long (ad);
1725     ad -= 4;
1726     wrd1 = get_long (ad);
1727     regs.fp[fpp_movem_index2[list]] = to_exten (wrd1, wrd2, wrd3);
1728     } else {
1729     wrd1 = get_long (ad);
1730     ad += 4;
1731     wrd2 = get_long (ad);
1732     ad += 4;
1733     wrd3 = get_long (ad);
1734     ad += 4;
1735     regs.fp[fpp_movem_index1[list]] = to_exten (wrd1, wrd2, wrd3);
1736     }
1737     list = fpp_movem_next[list];
1738     }
1739     */
1740     if ((opcode & 0x38) == 0x18) // post-increment?
1741     m68k_areg (regs, opcode & 7) = ad;
1742     if ((opcode & 0x38) == 0x20) // pre-decrement?
1743     m68k_areg (regs, opcode & 7) = ad;
1744 cebix 1.1 }
1745 cebix 1.2 }
1746     dump_fp_regs( "END ");
1747     return;
1748 cebix 1.1 case 0:
1749     case 2:
1750 cebix 1.2 reg = (extra >> 7) & 7;
1751     if ((extra & 0xfc00) == 0x5c00) {
1752     D(bug("FMOVECR memory->FPP\r\n"));
1753     switch (extra & 0x7f) {
1754     case 0x00:
1755     // regs.fp[reg] = 4.0 * atan(1.0);
1756     regs.fp[reg] = 3.1415926535897932384626433832795;
1757     D(bug("FP const: Pi\r\n"));
1758     break;
1759     case 0x0b:
1760     // regs.fp[reg] = log10 (2.0);
1761     regs.fp[reg] = 0.30102999566398119521373889472449;
1762     D(bug("FP const: Log 10 (2)\r\n"));
1763     break;
1764     case 0x0c:
1765     // regs.fp[reg] = exp (1.0);
1766     regs.fp[reg] = 2.7182818284590452353602874713527;
1767     D(bug("FP const: e\r\n"));
1768     break;
1769     case 0x0d:
1770     // regs.fp[reg] = log (exp (1.0)) / log (2.0);
1771     regs.fp[reg] = 1.4426950408889634073599246810019;
1772     D(bug("FP const: Log 2 (e)\r\n"));
1773     break;
1774     case 0x0e:
1775     // regs.fp[reg] = log (exp (1.0)) / log (10.0);
1776     regs.fp[reg] = 0.43429448190325182765112891891661;
1777     D(bug("FP const: Log 10 (e)\r\n"));
1778     break;
1779     case 0x0f:
1780     regs.fp[reg] = 0.0;
1781     D(bug("FP const: zero\r\n"));
1782     break;
1783     case 0x30:
1784     // regs.fp[reg] = log (2.0);
1785     regs.fp[reg] = 0.69314718055994530941723212145818;
1786     D(bug("FP const: ln(2)\r\n"));
1787     break;
1788     case 0x31:
1789     // regs.fp[reg] = log (10.0);
1790     regs.fp[reg] = 2.3025850929940456840179914546844;
1791     D(bug("FP const: ln(10)\r\n"));
1792     break;
1793     case 0x32:
1794     // ??
1795     regs.fp[reg] = 1.0e0;
1796     D(bug("FP const: 1.0e0\r\n"));
1797     break;
1798     case 0x33:
1799     regs.fp[reg] = 1.0e1;
1800     D(bug("FP const: 1.0e1\r\n"));
1801     break;
1802     case 0x34:
1803     regs.fp[reg] = 1.0e2;
1804     D(bug("FP const: 1.0e2\r\n"));
1805     break;
1806     case 0x35:
1807     regs.fp[reg] = 1.0e4;
1808     D(bug("FP const: 1.0e4\r\n"));
1809     break;
1810     case 0x36:
1811     regs.fp[reg] = 1.0e8;
1812     D(bug("FP const: 1.0e8\r\n"));
1813     break;
1814     case 0x37:
1815     regs.fp[reg] = 1.0e16;
1816     D(bug("FP const: 1.0e16\r\n"));
1817     break;
1818     case 0x38:
1819     regs.fp[reg] = 1.0e32;
1820     D(bug("FP const: 1.0e32\r\n"));
1821     break;
1822     case 0x39:
1823     regs.fp[reg] = 1.0e64;
1824     D(bug("FP const: 1.0e64\r\n"));
1825     break;
1826     case 0x3a:
1827     regs.fp[reg] = 1.0e128;
1828     D(bug("FP const: 1.0e128\r\n"));
1829     break;
1830     case 0x3b:
1831     regs.fp[reg] = 1.0e256;
1832     D(bug("FP const: 1.0e256\r\n"));
1833     break;
1834    
1835     // Valid for 64 bits only (see fpu.cpp)
1836 cebix 1.1 #if 0
1837 cebix 1.2 case 0x3c:
1838     regs.fp[reg] = 1.0e512;
1839     D(bug("FP const: 1.0e512\r\n"));
1840     break;
1841     case 0x3d:
1842     regs.fp[reg] = 1.0e1024;
1843     D(bug("FP const: 1.0e1024\r\n"));
1844     break;
1845     case 0x3e:
1846     regs.fp[reg] = 1.0e2048;
1847     D(bug("FP const: 1.0e2048\r\n"));
1848     break;
1849     case 0x3f:
1850     regs.fp[reg] = 1.0e4096;
1851     D(bug("FP const: 1.0e4096\r\n"));
1852     break;
1853 cebix 1.1 #endif
1854 cebix 1.2 default:
1855     m68k_setpc (m68k_getpc () - 4);
1856     op_illg (opcode);
1857     break;
1858     }
1859     // these *do* affect the status reg
1860     MAKE_FPSR(regs.fpsr,regs.fp[reg]);
1861     dump_fp_regs( "END ");
1862     return;
1863     }
1864     if (get_fp_value (opcode, extra, &src) == 0) {
1865     m68k_setpc (m68k_getpc () - 4);
1866     op_illg (opcode);
1867     dump_fp_regs( "END ");
1868     return;
1869     }
1870    
1871     switch (extra & 0x7f) {
1872     case 0x00: /* FMOVE */
1873     D(bug("FMOVE %.04f\r\n",(float)src));
1874     regs.fp[reg] = src;
1875     // <ea> -> reg DOES affect the status reg
1876     MAKE_FPSR(regs.fpsr,regs.fp[reg]);
1877     break;
1878     case 0x01: /* FINT */
1879     D(bug("FINT %.04f\r\n",(float)src));
1880     // regs.fp[reg] = (int) (src + 0.5);
1881     switch(regs.fpcr & 0x30) {
1882     case ROUND_TO_ZERO:
1883     regs.fp[reg] = round_to_zero(src);
1884     break;
1885     case ROUND_TO_NEGATIVE_INFINITY:
1886     regs.fp[reg] = floor(src);
1887     break;
1888     case ROUND_TO_NEAREST:
1889     regs.fp[reg] = round_to_nearest(src);
1890     break;
1891     case ROUND_TO_POSITIVE_INFINITY:
1892     regs.fp[reg] = ceil(src);
1893     break;
1894     }
1895     MAKE_FPSR(regs.fpsr,regs.fp[reg]);
1896     break;
1897     case 0x02: /* FSINH */
1898     D(bug("FSINH %.04f\r\n",(float)src));
1899     regs.fp[reg] = sinh (src);
1900     MAKE_FPSR(regs.fpsr,regs.fp[reg]);
1901     break;
1902     case 0x03: /* FINTRZ */
1903     D(bug("FINTRZ %.04f\r\n",(float)src));
1904     // regs.fp[reg] = (int) src;
1905     regs.fp[reg] = round_to_zero(src);
1906     MAKE_FPSR(regs.fpsr,regs.fp[reg]);
1907     break;
1908     case 0x04: /* FSQRT */
1909     D(bug("FSQRT %.04f\r\n",(float)src));
1910     regs.fp[reg] = sqrt (src);
1911     MAKE_FPSR(regs.fpsr,regs.fp[reg]);
1912     break;
1913     case 0x06: /* FLOGNP1 */
1914     D(bug("FLOGNP1 %.04f\r\n",(float)src));
1915     regs.fp[reg] = log (src + 1.0);
1916     MAKE_FPSR(regs.fpsr,regs.fp[reg]);
1917     break;
1918     case 0x08: /* FETOXM1 */
1919     D(bug("FETOXM1 %.04f\r\n",(float)src));
1920     regs.fp[reg] = exp (src) - 1.0;
1921     MAKE_FPSR(regs.fpsr,regs.fp[reg]);
1922     break;
1923     case 0x09: /* FTANH */
1924     D(bug("FTANH %.04f\r\n",(float)src));
1925     regs.fp[reg] = tanh (src);
1926     MAKE_FPSR(regs.fpsr,regs.fp[reg]);
1927     break;
1928     case 0x0a: /* FATAN */
1929     D(bug("FATAN %.04f\r\n",(float)src));
1930     regs.fp[reg] = atan (src);
1931     MAKE_FPSR(regs.fpsr,regs.fp[reg]);
1932     break;
1933     case 0x0c: /* FASIN */
1934     D(bug("FASIN %.04f\r\n",(float)src));
1935     regs.fp[reg] = asin (src);
1936     MAKE_FPSR(regs.fpsr,regs.fp[reg]);
1937     break;
1938     case 0x0d: /* FATANH */
1939     D(bug("FATANH %.04f\r\n",(float)src));
1940 cebix 1.1 #if 1 /* The BeBox doesn't have atanh, and it isn't in the HPUX libm either */
1941 cebix 1.2 regs.fp[reg] = log ((1 + src) / (1 - src)) / 2;
1942     #else
1943     regs.fp[reg] = atanh (src);
1944     #endif
1945     MAKE_FPSR(regs.fpsr,regs.fp[reg]);
1946     break;
1947     case 0x0e: /* FSIN */
1948     D(bug("FSIN %.04f\r\n",(float)src));
1949     regs.fp[reg] = sin (src);
1950     MAKE_FPSR(regs.fpsr,regs.fp[reg]);
1951     break;
1952     case 0x0f: /* FTAN */
1953     D(bug("FTAN %.04f\r\n",(float)src));
1954     regs.fp[reg] = tan (src);
1955     MAKE_FPSR(regs.fpsr,regs.fp[reg]);
1956     break;
1957     case 0x10: /* FETOX */
1958     D(bug("FETOX %.04f\r\n",(float)src));
1959     regs.fp[reg] = exp (src);
1960     MAKE_FPSR(regs.fpsr,regs.fp[reg]);
1961     break;
1962     case 0x11: /* FTWOTOX */
1963     D(bug("FTWOTOX %.04f\r\n",(float)src));
1964     regs.fp[reg] = pow(2.0, src);
1965     MAKE_FPSR(regs.fpsr,regs.fp[reg]);
1966     break;
1967     case 0x12: /* FTENTOX */
1968     D(bug("FTENTOX %.04f\r\n",(float)src));
1969     regs.fp[reg] = pow(10.0, src);
1970     MAKE_FPSR(regs.fpsr,regs.fp[reg]);
1971     break;
1972     case 0x14: /* FLOGN */
1973     D(bug("FLOGN %.04f\r\n",(float)src));
1974     regs.fp[reg] = log (src);
1975     MAKE_FPSR(regs.fpsr,regs.fp[reg]);
1976     break;
1977     case 0x15: /* FLOG10 */
1978     D(bug("FLOG10 %.04f\r\n",(float)src));
1979     regs.fp[reg] = log10 (src);
1980     MAKE_FPSR(regs.fpsr,regs.fp[reg]);
1981     break;
1982     case 0x16: /* FLOG2 */
1983     D(bug("FLOG2 %.04f\r\n",(float)src));
1984     regs.fp[reg] = log (src) / log (2.0);
1985     MAKE_FPSR(regs.fpsr,regs.fp[reg]);
1986     break;
1987     case 0x18: /* FABS */
1988     D(bug("FABS %.04f\r\n",(float)src));
1989     regs.fp[reg] = src < 0 ? -src : src;
1990     MAKE_FPSR(regs.fpsr,regs.fp[reg]);
1991     break;
1992     case 0x19: /* FCOSH */
1993     D(bug("FCOSH %.04f\r\n",(float)src));
1994     regs.fp[reg] = cosh(src);
1995     MAKE_FPSR(regs.fpsr,regs.fp[reg]);
1996     break;
1997     case 0x1a: /* FNEG */
1998     D(bug("FNEG %.04f\r\n",(float)src));
1999     regs.fp[reg] = -src;
2000     MAKE_FPSR(regs.fpsr,regs.fp[reg]);
2001     break;
2002     case 0x1c: /* FACOS */
2003     D(bug("FACOS %.04f\r\n",(float)src));
2004     regs.fp[reg] = acos(src);
2005     MAKE_FPSR(regs.fpsr,regs.fp[reg]);
2006     break;
2007     case 0x1d: /* FCOS */
2008     D(bug("FCOS %.04f\r\n",(float)src));
2009     regs.fp[reg] = cos(src);
2010     MAKE_FPSR(regs.fpsr,regs.fp[reg]);
2011     break;
2012     case 0x1e: /* FGETEXP */
2013     D(bug("FGETEXP %.04f\r\n",(float)src));
2014     #if HAVE_IEEE_DOUBLE
2015     if( IS_INFINITY((uae_u32 *)&src) ) {
2016     MAKE_NAN( (uae_u32 *)&regs.fp[reg] );
2017     } else {
2018     regs.fp[reg] = FAST_FGETEXP( (uae_u32 *)&src );
2019     }
2020 cebix 1.1 #else
2021 cebix 1.2 if(src == 0) {
2022     regs.fp[reg] = (double)0;
2023     } else {
2024     int expon;
2025     frexp (src, &expon);
2026     regs.fp[reg] = (double) (expon - 1);
2027     }
2028 cebix 1.1 #endif
2029 cebix 1.2 MAKE_FPSR(regs.fpsr,regs.fp[reg]);
2030     break;
2031     case 0x1f: /* FGETMAN */
2032     D(bug("FGETMAN %.04f\r\n",(float)src));
2033     #if HAVE_IEEE_DOUBLE
2034     if( src == 0 ) {
2035     regs.fp[reg] = 0;
2036     } else if( IS_INFINITY((uae_u32 *)&src) ) {
2037     MAKE_NAN( (uae_u32 *)&regs.fp[reg] );
2038     } else {
2039     regs.fp[reg] = src;
2040     FAST_REMOVE_EXPONENT( (uae_u32 *)&regs.fp[reg] );
2041     }
2042     #else
2043     {
2044     int expon;
2045     regs.fp[reg] = frexp (src, &expon) * 2.0;
2046     }
2047     #endif
2048     MAKE_FPSR(regs.fpsr,regs.fp[reg]);
2049     break;
2050     case 0x20: /* FDIV */
2051     D(bug("FDIV %.04f\r\n",(float)src));
2052     regs.fp[reg] /= src;
2053     MAKE_FPSR(regs.fpsr,regs.fp[reg]);
2054     break;
2055     case 0x21: /* FMOD */
2056     D(bug("FMOD %.04f\r\n",(float)src));
2057     // regs.fp[reg] = regs.fp[reg] - (double) ((int) (regs.fp[reg] / src)) * src;
2058     { double quot = round_to_zero(regs.fp[reg] / src);
2059     #if HAVE_IEEE_DOUBLE
2060     uae_u32 sign = GET_QUOTIENT_SIGN((uae_u32 *)&regs.fp[reg],(uae_u32 *)&src);
2061     #endif
2062     regs.fp[reg] = regs.fp[reg] - quot * src;
2063     MAKE_FPSR(regs.fpsr,regs.fp[reg]);
2064     #if HAVE_IEEE_DOUBLE
2065     regs.fpsr = MAKE_QUOTIENT(regs.fpsr,quot,sign);
2066     #endif
2067     }
2068     break;
2069     case 0x22: /* FADD */
2070     D(bug("FADD %.04f\r\n",(float)src));
2071     regs.fp[reg] += src;
2072     MAKE_FPSR(regs.fpsr,regs.fp[reg]);
2073     break;
2074     case 0x23: /* FMUL */
2075     D(bug("FMUL %.04f\r\n",(float)src));
2076     GET_DEST_FLAGS((uae_u32 *)&regs.fp[reg]);
2077     GET_SOURCE_FLAGS((uae_u32 *)&src);
2078     if(fl_dest.in_range && fl_source.in_range) {
2079     regs.fp[reg] *= src;
2080     } else if( fl_dest.nan || fl_source.nan ||
2081     fl_dest.zero && fl_source.infinity ||
2082     fl_dest.infinity && fl_source.zero )
2083     {
2084     MAKE_NAN( (uae_u32 *)&regs.fp[reg] );
2085     } else if( fl_dest.zero || fl_source.zero ) {
2086     if( fl_dest.negative && !fl_source.negative ||
2087     !fl_dest.negative && fl_source.negative)
2088     {
2089     MAKE_ZERO_NEGATIVE((uae_u32 *)&regs.fp[reg]);
2090     } else {
2091     MAKE_ZERO_POSITIVE((uae_u32 *)&regs.fp[reg]);
2092     }
2093     } else {
2094     if( fl_dest.negative && !fl_source.negative ||
2095     !fl_dest.negative && fl_source.negative)
2096     {
2097     MAKE_INF_NEGATIVE((uae_u32 *)&regs.fp[reg]);
2098     } else {
2099     MAKE_INF_POSITIVE((uae_u32 *)&regs.fp[reg]);
2100     }
2101     }
2102     MAKE_FPSR(regs.fpsr,regs.fp[reg]);
2103     break;
2104     case 0x24: /* FSGLDIV */
2105     D(bug("FSGLDIV %.04f\r\n",(float)src));
2106     // TODO: round to float.
2107     regs.fp[reg] /= src;
2108     MAKE_FPSR(regs.fpsr,regs.fp[reg]);
2109     break;
2110     case 0x25: /* FREM */
2111     D(bug("FREM %.04f\r\n",(float)src));
2112     // regs.fp[reg] = regs.fp[reg] - (double) ((int) (regs.fp[reg] / src + 0.5)) * src;
2113     { double quot = round_to_nearest(regs.fp[reg] / src);
2114     #if HAVE_IEEE_DOUBLE
2115     uae_u32 sign = GET_QUOTIENT_SIGN((uae_u32 *)&regs.fp[reg],(uae_u32 *)&src);
2116     #endif
2117     regs.fp[reg] = regs.fp[reg] - quot * src;
2118     MAKE_FPSR(regs.fpsr,regs.fp[reg]);
2119     #if HAVE_IEEE_DOUBLE
2120     regs.fpsr = MAKE_QUOTIENT(regs.fpsr,quot,sign);
2121     #endif
2122     }
2123     break;
2124    
2125     case 0x26: /* FSCALE */
2126     D(bug("FSCALE %.04f\r\n",(float)src));
2127    
2128     // TODO:
2129     // Overflow, underflow
2130 cebix 1.1
2131 cebix 1.2 #if HAVE_IEEE_DOUBLE
2132     if( IS_INFINITY((uae_u32 *)&regs.fp[reg]) ) {
2133     MAKE_NAN( (uae_u32 *)&regs.fp[reg] );
2134     } else {
2135     // When the absolute value of the source operand is >= 2^14,
2136     // an overflow or underflow always results.
2137     // Here (int) cast is okay.
2138     FAST_SCALE( (uae_u32 *)&regs.fp[reg], (int)round_to_zero(src) );
2139     }
2140     #else
2141     if(src != 0) { // Manual says: src==0 -> FPn
2142     regs.fp[reg] *= exp (log (2.0) * src);
2143     }
2144 cebix 1.1 #endif
2145 cebix 1.2 MAKE_FPSR(regs.fpsr,regs.fp[reg]);
2146     break;
2147     case 0x27: /* FSGLMUL */
2148     D(bug("FSGLMUL %.04f\r\n",(float)src));
2149     regs.fp[reg] *= src;
2150     MAKE_FPSR(regs.fpsr,regs.fp[reg]);
2151     break;
2152     case 0x28: /* FSUB */
2153     D(bug("FSUB %.04f\r\n",(float)src));
2154     regs.fp[reg] -= src;
2155     MAKE_FPSR(regs.fpsr,regs.fp[reg]);
2156     break;
2157     case 0x30: /* FSINCOS */
2158     case 0x31:
2159     case 0x32:
2160     case 0x33:
2161     case 0x34:
2162     case 0x35:
2163     case 0x36:
2164     case 0x37:
2165     D(bug("FSINCOS %.04f\r\n",(float)src));
2166     // Cosine must be calculated first if same register
2167     regs.fp[extra & 7] = cos(src);
2168     regs.fp[reg] = sin (src);
2169     // Set fpsr according to the sine result
2170     MAKE_FPSR(regs.fpsr,regs.fp[reg]);
2171     break;
2172     case 0x38: /* FCMP */
2173     D(bug("FCMP %.04f\r\n",(float)src));
2174    
2175     // The infinity bit is always cleared by the FCMP
2176     // instruction since it is not used by any of the
2177     // conditional predicate equations.
2178    
2179     #if HAVE_IEEE_DOUBLE
2180     if( IS_INFINITY((uae_u32 *)&src) ) {
2181     if( IS_NEGATIVE((uae_u32 *)&src) ) {
2182     // negative infinity
2183     if( IS_INFINITY((uae_u32 *)&regs.fp[reg]) && IS_NEGATIVE((uae_u32 *)&regs.fp[reg]) ) {
2184     // Zero, Negative
2185     regs.fpsr = (regs.fpsr & 0x00FFFFFF) | 0x4000000 | 0x8000000;
2186     D(bug("-INF cmp -INF -> NZ\r\n"));
2187     } else {
2188     // None
2189     regs.fpsr = (regs.fpsr & 0x00FFFFFF);
2190     D(bug("x cmp -INF -> None\r\n"));
2191     }
2192     } else {
2193     // positive infinity
2194     if( IS_INFINITY((uae_u32 *)&regs.fp[reg]) && !IS_NEGATIVE((uae_u32 *)&regs.fp[reg]) ) {
2195     // Zero
2196     regs.fpsr = (regs.fpsr & 0x00FFFFFF) | 0x4000000;
2197     D(bug("+INF cmp +INF -> Z\r\n"));
2198     } else {
2199     // Negative
2200     regs.fpsr = (regs.fpsr & 0x00FFFFFF) | 0x8000000;
2201     D(bug("X cmp +INF -> N\r\n"));
2202     }
2203     }
2204     } else {
2205     double tmp = regs.fp[reg] - src;
2206     regs.fpsr = (regs.fpsr & 0x00FFFFFF) | (tmp == 0 ? 0x4000000 : 0) | (tmp < 0 ? 0x8000000 : 0);
2207     }
2208     #else
2209     {
2210     double tmp = regs.fp[reg] - src;
2211     MAKE_FPSR(regs.fpsr,tmp);
2212     }
2213     #endif
2214     break;
2215     case 0x3a: /* FTST */
2216     D(bug("FTST %.04f\r\n",(float)src));
2217     // MAKE_FPSR(regs.fpsr,regs.fp[reg]);
2218     MAKE_FPSR(regs.fpsr,src);
2219     break;
2220     default:
2221     D(bug("ILLEGAL F OP %X\r\n",opcode));
2222     m68k_setpc (m68k_getpc () - 4);
2223     op_illg (opcode);
2224     break;
2225     }
2226     dump_fp_regs( "END ");
2227     return;
2228     }
2229     D(bug("ILLEGAL F OP 2 %X\r\n",opcode));
2230     m68k_setpc (m68k_getpc () - 4);
2231     op_illg (opcode);
2232     dump_fp_regs( "END ");
2233     }