ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/uae_cpu/fpp.cpp
Revision: 1.2
Committed: 1999-10-27T16:59:54Z (24 years, 8 months ago) by cebix
Branch: MAIN
Changes since 1.1: +1948 -1101 lines
Log Message:
- imported fixed UAE FPU from Lauri
- extfs.cpp: fixed bug with fsResolveWDCB in fs_get_wd_info()
- ExtFS: MAX_PATH_LENGTH is global, removed third parameter to
  add_path_component()
- rom_patches.cpp: added print_rom_info()
- Unix: added "-rominfo" command line argument
- extfs_unix.cpp: supports finder info and resource forks
- prefs_editor_gtk.cpp: tab widget is no longer scrollable

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