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

File Contents

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