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

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