ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/uae_cpu/fpp.cpp
Revision: 1.8
Committed: 2000-07-14T21:29:16Z (24 years, 4 months ago) by cebix
Branch: MAIN
Changes since 1.7: +92 -73 lines
Log Message:
- AmigaOS bug fixes by J.Lachmann (floppy, 2060scsi.device, "Add Volume" in
  prefs editor)
- imported some changes from the Windows source (1Hz interrupt, FPU fixes)

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