ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/uae_cpu/fpu/fpu_uae.cpp
Revision: 1.4
Committed: 2012-03-30T01:45:08Z (12 years, 5 months ago) by asvitkine
Branch: MAIN
CVS Tags: HEAD
Changes since 1.3: +23 -3 lines
Error occurred while calculating annotation data.
Log Message:
Add correct GPUv2 attribution to fpu_ieee.cpp and fpu_uae.cpp files, to
match the other files under uae_cpu/fpu, which have the same history
according to CVS.

File Contents

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