ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/uae_cpu/fpp.cpp
Revision: 1.6
Committed: 1999-10-31T23:18:38Z (24 years, 8 months ago) by cebix
Branch: MAIN
CVS Tags: snapshot-02111999
Changes since 1.5: +5 -0 lines
Log Message:
- removed MemoryDispatch() replacement; routine from ROM is now used if
  possible
- rom_patches.cpp: check for double PACK 4 resources; if only one is found,
  assume that the ROM requires an FPU and issue a warning if FPU emulation
  is turned off
- UAE CPU opcode routines no longer return the cycle count
- main_unix.cpp: pressing Ctrl-C dumps the UAE CPU state before entering mon
- sys_unix.cpp: under Linux, partition sizes are read with BLKGETSIZE instead
  of llseek()

File Contents

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