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

File Contents

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