ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/uae_cpu/fpu/fpu_uae.cpp
Revision: 1.3
Committed: 2002-09-13T15:06:42Z (21 years, 9 months ago) by gbeauche
Branch: MAIN
CVS Tags: nigel-build-19, nigel-build-12, nigel-build-13, nigel-build-16, nigel-build-17, nigel-build-15
Changes since 1.2: +0 -2 lines
Log Message:
USE_LONG_DOUBLE guards

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