ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/uae_cpu/fpu/fpu_ieee.cpp
Revision: 1.4
Committed: 2002-09-16T12:01:38Z (21 years, 9 months ago) by gbeauche
Branch: MAIN
Changes since 1.3: +1 -18 lines
Log Message:
- FP endianness is now testing at configure time
- Fix junk introduced in previous rev for extract_extended()

File Contents

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