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