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

# Content
1 /*
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
68 #include <math.h>
69 #include <stdio.h>
70
71 #include "memory.h"
72 #include "readcpu.h"
73 #include "newcpu.h"
74
75 #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
82 #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 // 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
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
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 if( (p[FHI] & 0x7FF00000) == 0x7FF00000 ) {
185 // logical or is faster here.
186 if( (p[FHI] & 0x000FFFFF) || p[FLO] ) {
187 return(1);
188 }
189 }
190 return(0);
191 }
192
193 static __inline__ uae_u32 IS_INFINITY(uae_u32 *p)
194 {
195 if( ((p[FHI] & 0x7FF00000) == 0x7FF00000) && p[FLO] == 0 ) {
196 return(1);
197 }
198 return(0);
199 }
200
201 static __inline__ uae_u32 IS_NEGATIVE(uae_u32 *p)
202 {
203 return( (p[FHI] & 0x80000000) != 0 );
204 }
205
206 static __inline__ uae_u32 IS_ZERO(uae_u32 *p)
207 {
208 return( ((p[FHI] & 0x7FF00000) == 0) && p[FLO] == 0 );
209 }
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 p[FLO] = 0xFFFFFFFF;
248 p[FHI] = 0x7FFFFFFF;
249 }
250
251 static __inline__ void MAKE_ZERO_POSITIVE(uae_u32 *p)
252 {
253 p[FLO] = p[FHI] = 0;
254 }
255
256 static __inline__ void MAKE_ZERO_NEGATIVE(uae_u32 *p)
257 {
258 p[FLO] = 0;
259 p[FHI] = 0x80000000;
260 }
261
262 static __inline__ void MAKE_INF_POSITIVE(uae_u32 *p)
263 {
264 p[FLO] = 0;
265 p[FHI] = 0x7FF00000;
266 }
267
268 static __inline__ void MAKE_INF_NEGATIVE(uae_u32 *p)
269 {
270 p[FLO] = 0;
271 p[FHI] = 0xFFF00000;
272 }
273
274 static __inline__ void FAST_SCALE(uae_u32 *p, int add)
275 {
276 int exp;
277
278 exp = (p[FHI] & 0x7FF00000) >> 20;
279 // 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 p[FHI] &= 0x80000000;
286 } else {
287 p[FHI] = (p[FHI] & 0x800FFFFF) | ((uae_u32)exp << 20);
288 }
289 }
290
291 static __inline__ double FAST_FGETEXP(uae_u32 *p)
292 {
293 int exp = (p[FHI] & 0x7FF00000) >> 20;
294 return( exp - 1023 );
295 }
296
297 // Normalize to range 1..2
298 static __inline__ void FAST_REMOVE_EXPONENT(uae_u32 *p)
299 {
300 p[FHI] = (p[FHI] & 0x800FFFFF) | 0x3FF00000;
301 }
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 return( ((a[FHI] ^ b[FHI]) & 0x80000000) ? 0x800000 : 0);
308 }
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 static __inline__ double to_single (uae_u32 value)
319 {
320 double result;
321 uae_u32 *p;
322
323 if ((value & 0x7fffffff) == 0) return (0.0);
324
325 p = (uae_u32 *)&result;
326
327 uae_u32 sign = (value & 0x80000000);
328 uae_u32 exp = ((value & 0x7F800000) >> 23) + 1023 - 127;
329
330 p[FLO] = value << 29;
331 p[FHI] = sign | (exp << 20) | ((value & 0x007FFFFF) >> 3);
332
333 D(bug("to_single (%X) = %.04f\r\n",value,(float)result));
334
335 return(result);
336 }
337
338 static __inline__ uae_u32 from_single (double src)
339 {
340 uae_u32 result;
341 uae_u32 *p = (uae_u32 *)&src;
342
343 if (src == 0.0) return 0;
344
345 uae_u32 sign = (p[FHI] & 0x80000000);
346 uae_u32 exp = (p[FHI] & 0x7FF00000) >> 20;
347
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 result = sign | (exp << 23) | ((p[FHI] & 0x000FFFFF) << 3) | (p[FLO] >> 29);
357
358 D(bug("from_single (%.04f) = %X\r\n",(float)src,result));
359
360 return (result);
361 }
362
363 static __inline__ double to_exten(uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3)
364 {
365 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 while( (man & UVAL64(0x8000000000000000)) == 0 ) {
380 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
395 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 p[FLO] = (wrd2 << 21) | (wrd3 >> 11);
407 p[FHI] = sign | (exp << 20) | ((wrd2 & 0x7FFFFFFF) >> 11);
408
409 D(bug("to_exten (%X,%X,%X) = %.04f\r\n",wrd1,wrd2,wrd3,(float)result));
410
411 return(result);
412 }
413
414 static __inline__ void from_exten(double src, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3)
415 {
416 uae_u32 *p = (uae_u32 *)&src;
417
418 if (src == 0.0) {
419 *wrd1 = *wrd2 = *wrd3 = 0;
420 return;
421 }
422
423 D(bug("from_exten (%X,%X)\r\n",p[FLO],p[FHI]));
424
425 uae_u32 sign = p[FHI] & 0x80000000;
426
427 uae_u32 exp = ((p[FHI] >> 20) & 0x7ff);
428 // 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 *wrd2 = 0x80000000 | ((p[FHI] & 0x000FFFFF) << 11) | ((p[FLO] & 0xFFE00000) >> 21);
438 *wrd3 = p[FLO] << 11;
439
440 D(bug("from_exten (%.04f) = %X,%X,%X\r\n",(float)src,*wrd1,*wrd2,*wrd3));
441 }
442
443 static __inline__ double to_double(uae_u32 wrd1, uae_u32 wrd2)
444 {
445 double result;
446 uae_u32 *p;
447
448 if ((wrd1 & 0x7fffffff) == 0 && wrd2 == 0) return 0.0;
449
450 p = (uae_u32 *)&result;
451 p[FLO] = wrd2;
452 p[FHI] = wrd1;
453
454 D(bug("to_double (%X,%X) = %.04f\r\n",wrd1,wrd2,(float)result));
455
456 return(result);
457 }
458
459 static __inline__ void from_double(double src, uae_u32 * wrd1, uae_u32 * wrd2)
460 {
461 if (src == 0.0) {
462 *wrd1 = *wrd2 = 0;
463 return;
464 }
465 uae_u32 *p = (uae_u32 *)&src;
466 *wrd2 = p[FLO];
467 *wrd1 = p[FHI];
468
469 D(bug("from_double (%.04f) = %X,%X\r\n",(float)src,*wrd1,*wrd2));
470 }
471
472
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 static __inline__ double to_pack(uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3)
628 {
629 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 }
668
669 static __inline__ void from_pack(double src, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3)
670 {
671 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 *wrd2 |= *cp++ - '0';
695 }
696 for (i = 0; i < 8; i++) {
697 *wrd3 <<= 4;
698 if (*cp >= '0' && *cp <= '9')
699 *wrd3 |= *cp++ - '0';
700 }
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 }
719
720 static __inline__ int get_fp_value (uae_u32 opcode, uae_u16 extra, double *src)
721 {
722 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 case 0:
746 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 case 1:
764 return 0;
765 case 2:
766 ad = m68k_areg (regs, reg);
767 break;
768 case 3:
769 ad = m68k_areg (regs, reg);
770 m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size];
771 break;
772 case 4:
773 m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size];
774 ad = m68k_areg (regs, reg);
775 break;
776 case 5:
777 ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) next_iword();
778 break;
779 case 6:
780 ad = get_disp_ea_020 (m68k_areg (regs, reg), next_iword());
781 break;
782 case 7:
783 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 case 0:
817 *src = (double) (uae_s32) get_long (ad);
818 break;
819 case 1:
820 *src = to_single(get_long (ad));
821 break;
822
823 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 }
832 break;
833 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 }
842 break;
843 case 4:
844 *src = (double) (uae_s16) get_word(ad);
845 break;
846 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 }
853 break;
854 case 6:
855 *src = (double) (uae_s8) get_byte(ad);
856 break;
857 default:
858 return 0;
859 }
860
861 // D(bug("get_fp_value result = %.04f\r\n",(float)*src));
862
863 return 1;
864 }
865
866 static __inline__ int put_fp_value (double value, uae_u32 opcode, uae_u16 extra)
867 {
868 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 case 0:
893 switch (size) {
894 case 6:
895 m68k_dreg (regs, reg) = (((int) value & 0xff)
896 | (m68k_dreg (regs, reg) & ~0xff));
897 break;
898 case 4:
899 m68k_dreg (regs, reg) = (((int) value & 0xffff)
900 | (m68k_dreg (regs, reg) & ~0xffff));
901 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 case 2:
915 ad = m68k_areg (regs, reg);
916 break;
917 case 3:
918 ad = m68k_areg (regs, reg);
919 m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size];
920 break;
921 case 4:
922 m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size];
923 ad = m68k_areg (regs, reg);
924 break;
925 case 5:
926 ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) next_iword();
927 break;
928 case 6:
929 ad = get_disp_ea_020 (m68k_areg (regs, reg), next_iword());
930 break;
931 case 7:
932 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 case 0:
958 put_long (ad, (uae_s32) value);
959 break;
960 case 1:
961 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 case 3:
975 {
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 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 }
995 break;
996 case 6:
997 put_byte(ad, (uae_s8) value);
998 break;
999 default:
1000 return 0;
1001 }
1002 return 1;
1003 }
1004
1005 static __inline__ int get_fp_ad(uae_u32 opcode, uae_u32 * ad)
1006 {
1007 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 case 0:
1016 case 1:
1017 return 0;
1018 case 2:
1019 *ad = m68k_areg (regs, reg);
1020 break;
1021 case 3:
1022 *ad = m68k_areg (regs, reg);
1023 break;
1024 case 4:
1025 *ad = m68k_areg (regs, reg);
1026 break;
1027 case 5:
1028 *ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) next_iword();
1029 break;
1030 case 6:
1031 *ad = get_disp_ea_020 (m68k_areg (regs, reg), next_iword());
1032 break;
1033 case 7:
1034 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 }
1056
1057 static __inline__ int fpp_cond(uae_u32 opcode, int contition)
1058 {
1059 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
1064 switch (contition) {
1065 case 0x00:
1066 CONDRET("False",0);
1067 case 0x01:
1068 CONDRET("Equal",Z);
1069 case 0x02:
1070 CONDRET("Ordered Greater Than",!(NotANumber || Z || N));
1071 case 0x03:
1072 CONDRET("Ordered Greater Than or Equal",Z || !(NotANumber || N));
1073 case 0x04:
1074 CONDRET("Ordered Less Than",N && !(NotANumber || Z));
1075 case 0x05:
1076 CONDRET("Ordered Less Than or Equal",Z || (N && !NotANumber));
1077 case 0x06:
1078 CONDRET("Ordered Greater or Less Than",!(NotANumber || Z));
1079 case 0x07:
1080 CONDRET("Ordered",!NotANumber);
1081 case 0x08:
1082 CONDRET("Unordered",NotANumber);
1083 case 0x09:
1084 CONDRET("Unordered or Equal",NotANumber || Z);
1085 case 0x0a:
1086 CONDRET("Unordered or Greater Than",NotANumber || !(N || Z));
1087 case 0x0b:
1088 CONDRET("Unordered or Greater or Equal",NotANumber || Z || !N);
1089 case 0x0c:
1090 CONDRET("Unordered or Less Than",NotANumber || (N && !Z));
1091 case 0x0d:
1092 CONDRET("Unordered or Less or Equal",NotANumber || Z || N);
1093 case 0x0e:
1094 CONDRET("Not Equal",!Z);
1095 case 0x0f:
1096 CONDRET("True",1);
1097 case 0x10:
1098 CONDRET("Signaling False",0);
1099 case 0x11:
1100 CONDRET("Signaling Equal",Z);
1101 case 0x12:
1102 CONDRET("Greater Than",!(NotANumber || Z || N));
1103 case 0x13:
1104 CONDRET("Greater Than or Equal",Z || !(NotANumber || N));
1105 case 0x14:
1106 CONDRET("Less Than",N && !(NotANumber || Z));
1107 case 0x15:
1108 CONDRET("Less Than or Equal",Z || (N && !NotANumber));
1109 case 0x16:
1110 CONDRET("Greater or Less Than",!(NotANumber || Z));
1111 case 0x17:
1112 CONDRET("Greater, Less or Equal",!NotANumber);
1113 case 0x18:
1114 CONDRET("Not Greater, Less or Equal",NotANumber);
1115 case 0x19:
1116 CONDRET("Not Greater or Less Than",NotANumber || Z);
1117 case 0x1a:
1118 CONDRET("Not Less Than or Equal",NotANumber || !(N || Z));
1119 case 0x1b:
1120 CONDRET("Not Less Than",NotANumber || Z || !N);
1121 case 0x1c:
1122 // CONDRET("Not Greater Than or Equal",NotANumber || (Z && N));
1123 CONDRET("Not Greater Than or Equal",!Z && (NotANumber || N));
1124 case 0x1d:
1125 CONDRET("Not Greater Than",NotANumber || Z || N);
1126 case 0x1e:
1127 CONDRET("Signaling Not Equal",!Z);
1128 case 0x1f:
1129 CONDRET("Signaling True",1);
1130 }
1131 CONDRET("",-1);
1132 }
1133
1134 void fdbcc_opp(uae_u32 opcode, uae_u16 extra)
1135 {
1136 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
1149 // this may have leaked.
1150 /*
1151 m68k_dreg (regs, reg) = ((m68k_dreg (regs, reg) & ~0xffff)
1152 | ((m68k_dreg (regs, reg) - 1) & 0xffff));
1153 */
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 m68k_setpc (pc + disp);
1162 }
1163 }
1164
1165 void fscc_opp(uae_u32 opcode, uae_u16 extra)
1166 {
1167 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
1172 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 (cc ? 0xff : 0x00);
1179 } else {
1180 if (get_fp_ad(opcode, &ad) == 0) {
1181 m68k_setpc (m68k_getpc () - 4);
1182 op_illg (opcode);
1183 } else
1184 put_byte(ad, cc ? 0xff : 0x00);
1185 }
1186 }
1187
1188 void ftrapcc_opp(uae_u32 opcode, uaecptr oldpc)
1189 {
1190 int cc;
1191
1192 D(bug("ftrapcc_opp %X at %08lx\r\n", (uae_u32)opcode, m68k_getpc ()));
1193
1194 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 }
1202
1203 // NOTE that we get here also when there is a FNOP (nontrapping false, displ 0)
1204 void fbcc_opp(uae_u32 opcode, uaecptr pc, uae_u32 extra)
1205 {
1206 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
1210 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 extra = (uae_s32) (uae_s16) extra;
1217 m68k_setpc (pc + extra);
1218 }
1219 }
1220
1221 // FSAVE has no post-increment
1222 // 0x1f180000 == IDLE state frame, coprocessor version number 1F
1223 void fsave_opp(uae_u32 opcode)
1224 {
1225 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 ad -= 4;
1247 put_long (ad, 0x00000000);
1248 }
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 put_long (ad, 0x00000000);
1256 ad += 4;
1257 }
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 }
1270 }
1271
1272 // FSAVE has no pre-decrement
1273 void frestore_opp(uae_u32 opcode)
1274 {
1275 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 if ((d & 0x00ff0000) == 0x00180000)
1296 ad -= 6 * 4;
1297 else if ((d & 0x00ff0000) == 0x00380000)
1298 ad -= 14 * 4;
1299 else if ((d & 0x00ff0000) == 0x00b40000)
1300 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 }
1325 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 }
1329 }
1330
1331 void fpp_opp(uae_u32 opcode, uae_u16 extra)
1332 {
1333 int reg;
1334 double src;
1335
1336 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 case 3:
1343 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 case 4:
1351 case 5:
1352 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 case 6:
1516 case 7:
1517 {
1518 uae_u32 ad, list = 0;
1519 int incr = 0;
1520 if (extra & 0x2000) {
1521 /* 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 }
1702 }
1703 dump_fp_regs( "END ");
1704 return;
1705 case 0:
1706 case 2:
1707 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 #if 0
1794 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 #endif
1811 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 #if 1 /* The BeBox doesn't have atanh, and it isn't in the HPUX libm either */
1898 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 #else
1978 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 #endif
1986 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
2088 #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 #endif
2102 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 }