|
|
1.1 root 1: /*
2: * UAE - The Un*x Amiga Emulator
3: *
4: * MC68881 emulation
5: *
6: * Copyright 1996 Herman ten Brugge
7: * Modified 2005 Peter Keunecke
8: */
9:
10: #define __USE_ISOC9X /* We might be able to pick up a NaN */
11:
12: #include <math.h>
13: #include <float.h>
14:
15: #include "sysconfig.h"
16: #include "sysdeps.h"
17:
18: #include "options_cpu.h"
19: #include "memory.h"
20: #include "custom.h"
21: #include "events.h"
22: #include "newcpu.h"
23: //#include "ersatz.h"
24: #include "md-fpp.h"
25: #include "savestate.h"
26: #include "cpu_prefetch.h"
27: #include "main.h"
28: #include "cpummu.h"
29:
30: #define DEBUG_FPP 0
31: #define write_log printf
32:
33: STATIC_INLINE int isinrom (void)
34: {
35: return (munge24 (m68k_getpc ()) & 0xFFF80000) == 0xF80000 && !currprefs.mmu_model;
36: }
37:
38: static uae_u32 xhex_pi[] ={0x2168c235, 0xc90fdaa2, 0x4000};
39: uae_u32 xhex_exp_1[] ={0xa2bb4a9a, 0xadf85458, 0x4000};
40: static uae_u32 xhex_l2_e[] ={0x5c17f0bc, 0xb8aa3b29, 0x3fff};
41: static uae_u32 xhex_ln_2[] ={0xd1cf79ac, 0xb17217f7, 0x3ffe};
42: uae_u32 xhex_ln_10[] ={0xaaa8ac17, 0x935d8ddd, 0x4000};
43: uae_u32 xhex_l10_2[] ={0xfbcff798, 0x9a209a84, 0x3ffd};
44: uae_u32 xhex_l10_e[] ={0x37287195, 0xde5bd8a9, 0x3ffd};
45: uae_u32 xhex_1e16[] ={0x04000000, 0x8e1bc9bf, 0x4034};
46: uae_u32 xhex_1e32[] ={0x2b70b59e, 0x9dc5ada8, 0x4069};
47: uae_u32 xhex_1e64[] ={0xffcfa6d5, 0xc2781f49, 0x40d3};
48: uae_u32 xhex_1e128[] ={0x80e98ce0, 0x93ba47c9, 0x41a8};
49: uae_u32 xhex_1e256[] ={0x9df9de8e, 0xaa7eebfb, 0x4351};
50: uae_u32 xhex_1e512[] ={0xa60e91c7, 0xe319a0ae, 0x46a3};
51: uae_u32 xhex_1e1024[]={0x81750c17, 0xc9767586, 0x4d48};
52: uae_u32 xhex_1e2048[]={0xc53d5de5, 0x9e8b3b5d, 0x5a92};
53: uae_u32 xhex_1e4096[]={0x8a20979b, 0xc4605202, 0x7525};
54: static uae_u32 xhex_inf[] ={0x00000000, 0x00000000, 0x7fff};
55: static uae_u32 xhex_nan[] ={0xffffffff, 0xffffffff, 0x7fff};
56: #if USE_LONG_DOUBLE
57: static long double *fp_pi = (long double *)xhex_pi;
58: static long double *fp_exp_1 = (long double *)xhex_exp_1;
59: static long double *fp_l2_e = (long double *)xhex_l2_e;
60: static long double *fp_ln_2 = (long double *)xhex_ln_2;
61: static long double *fp_ln_10 = (long double *)xhex_ln_10;
62: static long double *fp_l10_2 = (long double *)xhex_l10_2;
63: static long double *fp_l10_e = (long double *)xhex_l10_e;
64: static long double *fp_1e16 = (long double *)xhex_1e16;
65: static long double *fp_1e32 = (long double *)xhex_1e32;
66: static long double *fp_1e64 = (long double *)xhex_1e64;
67: static long double *fp_1e128 = (long double *)xhex_1e128;
68: static long double *fp_1e256 = (long double *)xhex_1e256;
69: static long double *fp_1e512 = (long double *)xhex_1e512;
70: static long double *fp_1e1024 = (long double *)xhex_1e1024;
71: static long double *fp_1e2048 = (long double *)xhex_1e2048;
72: static long double *fp_1e4096 = (long double *)xhex_1e4096;
73: static long double *fp_inf = (long double *)xhex_inf;
74: static long double *fp_nan = (long double *)xhex_nan;
75: #else
76: static uae_u32 dhex_pi[] ={0x54442D18, 0x400921FB};
77: static uae_u32 dhex_exp_1[] ={0x8B145769, 0x4005BF0A};
78: static uae_u32 dhex_l2_e[] ={0x652B82FE, 0x3FF71547};
79: static uae_u32 dhex_ln_2[] ={0xFEFA39EF, 0x3FE62E42};
80: static uae_u32 dhex_ln_10[] ={0xBBB55516, 0x40026BB1};
81: static uae_u32 dhex_l10_2[] ={0x509F79FF, 0x3FD34413};
82: static uae_u32 dhex_l10_e[] ={0x1526E50E, 0x3FDBCB7B};
83: static uae_u32 dhex_1e16[] ={0x37E08000, 0x4341C379};
84: static uae_u32 dhex_1e32[] ={0xB5056E17, 0x4693B8B5};
85: static uae_u32 dhex_1e64[] ={0xE93FF9F5, 0x4D384F03};
86: static uae_u32 dhex_1e128[] ={0xF9301D32, 0x5A827748};
87: static uae_u32 dhex_1e256[] ={0x7F73BF3C, 0x75154FDD};
88: static uae_u32 dhex_inf[] ={0x00000000, 0x7ff00000};
89: static uae_u32 dhex_nan[] ={0xffffffff, 0x7fffffff};
90: static double *fp_pi = (double *)dhex_pi;
91: static double *fp_exp_1 = (double *)dhex_exp_1;
92: static double *fp_l2_e = (double *)dhex_l2_e;
93: static double *fp_ln_2 = (double *)dhex_ln_2;
94: static double *fp_ln_10 = (double *)dhex_ln_10;
95: static double *fp_l10_2 = (double *)dhex_l10_2;
96: static double *fp_l10_e = (double *)dhex_l10_e;
97: static double *fp_1e16 = (double *)dhex_1e16;
98: static double *fp_1e32 = (double *)dhex_1e32;
99: static double *fp_1e64 = (double *)dhex_1e64;
100: static double *fp_1e128 = (double *)dhex_1e128;
101: static double *fp_1e256 = (double *)dhex_1e256;
102: static double *fp_1e512 = (double *)dhex_inf;
103: static double *fp_1e1024 = (double *)dhex_inf;
104: static double *fp_1e2048 = (double *)dhex_inf;
105: static double *fp_1e4096 = (double *)dhex_inf;
106: static double *fp_inf = (double *)dhex_inf;
107: static double *fp_nan = (double *)dhex_nan;
108: #endif
109: double fp_1e8 = 1.0e8;
110: float fp_1e0 = 1, fp_1e1 = 10, fp_1e2 = 100, fp_1e4 = 10000;
111:
112: #define FFLAG_Z 0x4000
113: #define FFLAG_N 0x0100
114: #define FFLAG_NAN 0x0400
115:
116: #define MAKE_FPSR(r) (regs).fp_result=(r)
117:
118: static uae_u16 x87_cw_tab[] = {
119: 0x137f, 0x1f7f, 0x177f, 0x1b7f, /* Extended */
120: 0x107f, 0x1c7f, 0x147f, 0x187f, /* Single */
121: 0x127f, 0x1e7f, 0x167f, 0x1a7f, /* Double */
122: 0x137f, 0x1f7f, 0x177f, 0x1b7f /* undefined */
123: };
124: /* Nearest, toZero, Down, Up */
125: static __inline__ void native_set_fpucw (uae_u32 m68k_cw)
126: {
127: #if USE_X86_FPUCW
128: uae_u16 x87_cw = x87_cw_tab[(m68k_cw >> 4) & 0xf];
129:
130: #if defined(X86_MSVC_ASSEMBLY)
131: __asm {
132: fldcw word ptr x87_cw
133: }
134: #elif defined(X86_ASSEMBLY)
135: __asm__ ("fldcw %0" : : "m" (*&x87_cw));
136: #endif
137: #endif
138: }
139:
140: #if defined(uae_s64) /* Close enough for government work? */
141: typedef uae_s64 tointtype;
142: #else
143: typedef uae_s32 tointtype;
144: #endif
145:
146: static void fpu_op_illg (uae_u32 opcode, int pcoffset)
147: {
148: if ((currprefs.cpu_model == 68060 && (currprefs.fpu_model == 0 || (regs.pcr & 2)))
149: || (currprefs.cpu_model == 68040 && currprefs.fpu_model == 0)) {
150: /* 68040 unimplemented/68060 FPU disabled exception.
151: * Line F exception with different stack frame.. */
152: uaecptr newpc = m68k_getpc ();
153: uaecptr oldpc = newpc - pcoffset;
154: regs.t0 = regs.t1 = 0;
155: MakeSR ();
156: if (!regs.s) {
157: regs.usp = m68k_areg (regs, 7);
158: m68k_areg (regs, 7) = regs.isp;
159: }
160: regs.s = 1;
161: m68k_areg (regs, 7) -= 4;
162: x_put_long (m68k_areg (regs, 7), oldpc);
163: m68k_areg (regs, 7) -= 4;
164: x_put_long (m68k_areg (regs, 7), oldpc);
165: m68k_areg (regs, 7) -= 2;
166: x_put_word (m68k_areg (regs, 7), 0x4000 + 11 * 4);
167: m68k_areg (regs, 7) -= 4;
168: x_put_long (m68k_areg (regs, 7), newpc);
169: m68k_areg (regs, 7) -= 2;
170: x_put_word (m68k_areg (regs, 7), regs.sr);
171: write_log ("68040/060 FPU disabled exception PC=%x\n", newpc);
172: newpc = x_get_long (regs.vbr + 11 * 4);
173: m68k_setpc (newpc);
174: #ifdef JIT
175: set_special (SPCFLAG_END_COMPILE);
176: #endif
177: return;
178: }
179: op_illg (opcode);
180: }
181:
182: STATIC_INLINE int fault_if_no_fpu (uae_u32 opcode, int pcoffset)
183: {
184: if ((regs.pcr & 2) || currprefs.fpu_model <= 0) {
185: fpu_op_illg (opcode, pcoffset);
186: return 1;
187: }
188: return 0;
189: }
190:
191: static int get_fpu_version (void)
192: {
193: int v = 0;
1.1.1.2 ! root 194: /* removed for previous by andreas_g
1.1 root 195: if (currprefs.fpu_revision >= 0)
1.1.1.2 ! root 196: return currprefs.fpu_revision; */
1.1 root 197: switch (currprefs.fpu_model)
198: {
199: case 68881:
200: v = 0x1f;
201: break;
202: case 68882:
203: v = 0x20; /* ??? */
204: break;
205: case 68040:
206: v = 0x41;
207: break;
208: }
209: return v;
210: }
211:
212: #define fp_round_to_minus_infinity(x) fp_floor(x)
213: #define fp_round_to_plus_infinity(x) fp_ceil(x)
214: #define fp_round_to_zero(x) ((int)(x))
215: #define fp_round_to_nearest(x) ((int)((x) + 0.5))
216:
217: STATIC_INLINE tointtype toint (fptype src, fptype minval, fptype maxval)
218: {
219: if (src < minval)
220: src = minval;
221: if (src > maxval)
222: src = maxval;
223: #if defined(X86_MSVC_ASSEMBLY)
224: {
225: fptype tmp_fp;
226: __asm {
227: fld LDPTR src
228: frndint
229: fstp LDPTR tmp_fp
230: }
231: return (tointtype)tmp_fp;
232: }
233: #else /* no X86_MSVC */
234: {
235: int result = src;
236: #if 0
237: switch (get_fpcr () & 0x30) {
238: case FPCR_ROUND_ZERO:
239: result = fp_round_to_zero (src);
240: break;
241: case FPCR_ROUND_MINF:
242: result = fp_round_to_minus_infinity (src);
243: break;
244: case FPCR_ROUND_NEAR:
245: result = fp_round_to_nearest (src);
246: break;
247: case FPCR_ROUND_PINF:
248: result = fp_round_to_plus_infinity (src);
249: break;
250: default:
251: result = src; /* should never be reached */
252: break;
253: #endif
254: return result;
255: }
256: #endif
257: }
258:
259: /*extern int isinf (double x); //Not used */
260:
261: uae_u32 get_fpsr (void)
262: {
263: uae_u32 answer = regs.fpsr & 0x00ffffff;
264: #ifdef HAVE_ISNAN
265: if (isnan (regs.fp_result))
266: answer |= 0x01000000;
267: else
268: #endif
269: {
270: if (regs.fp_result == 0)
271: answer |= 0x04000000;
272: else if (regs.fp_result < 0)
273: answer |= 0x08000000;
274: #ifdef HAVE_ISINF
275: if (isinf (regs.fp_result))
276: answer |= 0x02000000;
277: #endif
278: }
279: return answer;
280: }
281:
282: STATIC_INLINE void set_fpsr (uae_u32 x)
283: {
284: regs.fpsr = x;
285:
286: if (x & 0x01000000) {
287: regs.fp_result = *fp_nan;
288: }
289: else if (x & 0x04000000)
290: regs.fp_result = 0;
291: else if (x & 0x08000000)
292: regs.fp_result = -1;
293: else
294: regs.fp_result = 1;
295: }
296:
297: /* single : S 8*E 23*F */
298: /* double : S 11*E 52*F */
299: /* extended : S 15*E 64*F */
300: /* E = 0 & F = 0 -> 0 */
301: /* E = MAX & F = 0 -> Infin */
302: /* E = MAX & F # 0 -> NotANumber */
303: /* E = biased by 127 (single) ,1023 (double) ,16383 (extended) */
304:
305: STATIC_INLINE fptype to_pack (uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3)
306: {
307: fptype d;
308: char *cp;
309: char str[100];
310:
311: cp = str;
312: if (wrd1 & 0x80000000)
313: *cp++ = '-';
314: *cp++ = (wrd1 & 0xf) + '0';
315: *cp++ = '.';
316: *cp++ = ((wrd2 >> 28) & 0xf) + '0';
317: *cp++ = ((wrd2 >> 24) & 0xf) + '0';
318: *cp++ = ((wrd2 >> 20) & 0xf) + '0';
319: *cp++ = ((wrd2 >> 16) & 0xf) + '0';
320: *cp++ = ((wrd2 >> 12) & 0xf) + '0';
321: *cp++ = ((wrd2 >> 8) & 0xf) + '0';
322: *cp++ = ((wrd2 >> 4) & 0xf) + '0';
323: *cp++ = ((wrd2 >> 0) & 0xf) + '0';
324: *cp++ = ((wrd3 >> 28) & 0xf) + '0';
325: *cp++ = ((wrd3 >> 24) & 0xf) + '0';
326: *cp++ = ((wrd3 >> 20) & 0xf) + '0';
327: *cp++ = ((wrd3 >> 16) & 0xf) + '0';
328: *cp++ = ((wrd3 >> 12) & 0xf) + '0';
329: *cp++ = ((wrd3 >> 8) & 0xf) + '0';
330: *cp++ = ((wrd3 >> 4) & 0xf) + '0';
331: *cp++ = ((wrd3 >> 0) & 0xf) + '0';
332: *cp++ = 'E';
333: if (wrd1 & 0x40000000)
334: *cp++ = '-';
335: *cp++ = ((wrd1 >> 24) & 0xf) + '0';
336: *cp++ = ((wrd1 >> 20) & 0xf) + '0';
337: *cp++ = ((wrd1 >> 16) & 0xf) + '0';
338: *cp = 0;
1.1.1.2 ! root 339: #if USE_LONG_DOUBLE
! 340: sscanf (str, "%Le", &d);
! 341: #else
1.1 root 342: sscanf (str, "%le", &d);
1.1.1.2 ! root 343: #endif
1.1 root 344: return d;
345: }
346:
347: STATIC_INLINE void from_pack (fptype src, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3)
348: {
349: int i;
350: int t;
351: char *cp;
352: char str[100];
1.1.1.2 ! root 353: #if USE_LONG_DOUBLE
! 354: sprintf (str, "%.16Le", src);
! 355: #else
1.1 root 356: sprintf (str, "%.16e", src);
1.1.1.2 ! root 357: #endif
1.1 root 358: cp = str;
359: *wrd1 = *wrd2 = *wrd3 = 0;
360: if (*cp == '-') {
361: cp++;
362: *wrd1 = 0x80000000;
363: }
364: if (*cp == '+')
365: cp++;
366: *wrd1 |= (*cp++ - '0');
367: if (*cp == '.')
368: cp++;
369: for (i = 0; i < 8; i++) {
370: *wrd2 <<= 4;
371: if (*cp >= '0' && *cp <= '9')
372: *wrd2 |= *cp++ - '0';
373: }
374: for (i = 0; i < 8; i++) {
375: *wrd3 <<= 4;
376: if (*cp >= '0' && *cp <= '9')
377: *wrd3 |= *cp++ - '0';
378: }
379: if (*cp == 'e' || *cp == 'E') {
380: cp++;
381: if (*cp == '-') {
382: cp++;
383: *wrd1 |= 0x40000000;
384: }
385: if (*cp == '+')
386: cp++;
387: t = 0;
388: for (i = 0; i < 3; i++) {
389: if (*cp >= '0' && *cp <= '9')
390: t = (t << 4) | (*cp++ - '0');
391: }
392: *wrd1 |= t << 16;
393: }
394: }
395:
396: STATIC_INLINE int get_fp_value (uae_u32 opcode, uae_u16 extra, fptype *src)
397: {
398: uaecptr tmppc;
399: uae_u16 tmp;
400: int size, mode, reg;
401: uae_u32 ad = 0;
402: static const int sz1[8] = { 4, 4, 12, 12, 2, 8, 1, 0 };
403: static const int sz2[8] = { 4, 4, 12, 12, 2, 8, 2, 0 };
404:
405: if (!(extra & 0x4000)) {
406: *src = regs.fp[(extra >> 10) & 7];
407: return 1;
408: }
409: mode = (opcode >> 3) & 7;
410: reg = opcode & 7;
411: size = (extra >> 10) & 7;
412:
413: switch (mode) {
414: case 0:
415: switch (size) {
416: case 6:
417: *src = (fptype) (uae_s8) m68k_dreg (regs, reg);
418: break;
419: case 4:
420: *src = (fptype) (uae_s16) m68k_dreg (regs, reg);
421: break;
422: case 0:
423: *src = (fptype) (uae_s32) m68k_dreg (regs, reg);
424: break;
425: case 1:
426: *src = to_single (m68k_dreg (regs, reg));
427: break;
428: default:
429: return 0;
430: }
431: return 1;
432: case 1:
433: return 0;
434: case 2:
435: ad = m68k_areg (regs, reg);
436: break;
437: case 3:
438: ad = m68k_areg (regs, reg);
439: m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size];
440: break;
441: case 4:
442: m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size];
443: ad = m68k_areg (regs, reg);
444: break;
445: case 5:
446: ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) x_next_iword ();
447: break;
448: case 6:
449: ad = x_get_disp_ea_020 (m68k_areg (regs, reg), x_next_iword ());
450: break;
451: case 7:
452: switch (reg) {
453: case 0:
454: ad = (uae_s32) (uae_s16) x_next_iword ();
455: break;
456: case 1:
457: ad = x_next_ilong ();
458: break;
459: case 2:
460: ad = m68k_getpc ();
461: ad += (uae_s32) (uae_s16) x_next_iword ();
462: break;
463: case 3:
464: tmppc = m68k_getpc ();
465: tmp = x_next_iword ();
466: ad = x_get_disp_ea_020 (tmppc, tmp);
467: break;
468: case 4:
469: ad = m68k_getpc ();
470: m68k_setpc (ad + sz2[size]);
471: if (size == 6)
472: ad++;
473: break;
474: default:
475: return 0;
476: }
477: }
478: switch (size) {
479: case 0:
480: *src = (fptype) (uae_s32) x_get_long (ad);
481: break;
482: case 1:
483: *src = to_single (x_get_long (ad));
484: break;
485: case 2:{
486: uae_u32 wrd1, wrd2, wrd3;
487: wrd1 = x_get_long (ad);
488: ad += 4;
489: wrd2 = x_get_long (ad);
490: ad += 4;
491: wrd3 = x_get_long (ad);
492: *src = to_exten (wrd1, wrd2, wrd3);
493: }
494: break;
495: case 3:{
496: uae_u32 wrd1, wrd2, wrd3;
497: wrd1 = x_get_long (ad);
498: ad += 4;
499: wrd2 = x_get_long (ad);
500: ad += 4;
501: wrd3 = x_get_long (ad);
502: *src = to_pack (wrd1, wrd2, wrd3);
503: }
504: break;
505: case 4:
506: *src = (fptype) (uae_s16) x_get_word (ad);
507: break;
508: case 5:{
509: uae_u32 wrd1, wrd2;
510: wrd1 = x_get_long (ad);
511: ad += 4;
512: wrd2 = x_get_long (ad);
513: *src = to_double (wrd1, wrd2);
514: }
515: break;
516: case 6:
517: *src = (fptype) (uae_s8) x_get_byte (ad);
518: break;
519: default:
520: return 0;
521: }
522: return 1;
523: }
524:
525: STATIC_INLINE int put_fp_value (fptype value, uae_u32 opcode, uae_u16 extra)
526: {
527: uae_u16 tmp;
528: uaecptr tmppc;
529: int size, mode, reg;
530: uae_u32 ad;
531: static int sz1[8] = { 4, 4, 12, 12, 2, 8, 1, 0 };
532: static int sz2[8] = { 4, 4, 12, 12, 2, 8, 2, 0 };
533:
534: #if DEBUG_FPP
535: if (!isinrom ())
536: write_log ("PUTFP: %f %04X %04X\n", value, opcode, extra);
537: #endif
538: if (!(extra & 0x4000)) {
539: regs.fp[(extra >> 10) & 7] = value;
540: return 1;
541: }
542: reg = opcode & 7;
543: mode = (opcode >> 3) & 7;
544: size = (extra >> 10) & 7;
545: ad = -1;
546: switch (mode) {
547: case 0:
548: switch (size) {
549: case 6:
550: m68k_dreg (regs, reg) = (uae_u32)(((toint (value, -128.0, 127.0) & 0xff)
551: | (m68k_dreg (regs, reg) & ~0xff)));
552: break;
553: case 4:
554: m68k_dreg (regs, reg) = (uae_u32)(((toint (value, -32768.0, 32767.0) & 0xffff)
555: | (m68k_dreg (regs, reg) & ~0xffff)));
556: break;
557: case 0:
558: m68k_dreg (regs, reg) = (uae_u32)toint (value, -2147483648.0, 2147483647.0);
559: break;
560: case 1:
561: m68k_dreg (regs, reg) = from_single (value);
562: break;
563: default:
564: return 0;
565: }
566: return 1;
567: case 1:
568: return 0;
569: case 2:
570: ad = m68k_areg (regs, reg);
571: break;
572: case 3:
573: ad = m68k_areg (regs, reg);
574: m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size];
575: break;
576: case 4:
577: m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size];
578: ad = m68k_areg (regs, reg);
579: break;
580: case 5:
581: ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) x_next_iword ();
582: break;
583: case 6:
584: ad = x_get_disp_ea_020 (m68k_areg (regs, reg), x_next_iword ());
585: break;
586: case 7:
587: switch (reg) {
588: case 0:
589: ad = (uae_s32) (uae_s16) x_next_iword ();
590: break;
591: case 1:
592: ad = x_next_ilong ();
593: break;
594: case 2:
595: ad = m68k_getpc ();
596: ad += (uae_s32) (uae_s16) x_next_iword ();
597: break;
598: case 3:
599: tmppc = m68k_getpc ();
600: tmp = x_next_iword ();
601: ad = x_get_disp_ea_020 (tmppc, tmp);
602: break;
603: case 4:
604: ad = m68k_getpc ();
605: m68k_setpc (ad + sz2[size]);
606: break;
607: default:
608: return 0;
609: }
610: }
611: switch (size) {
612: case 0:
613: x_put_long (ad, (uae_u32)toint (value, -2147483648.0, 2147483647.0));
614: break;
615: case 1:
616: x_put_long (ad, from_single (value));
617: break;
618: case 2:
619: {
620: uae_u32 wrd1, wrd2, wrd3;
621: from_exten (value, &wrd1, &wrd2, &wrd3);
622: x_put_long (ad, wrd1);
623: ad += 4;
624: x_put_long (ad, wrd2);
625: ad += 4;
626: x_put_long (ad, wrd3);
627: }
628: break;
629: case 3:
630: {
631: uae_u32 wrd1, wrd2, wrd3;
632: from_pack (value, &wrd1, &wrd2, &wrd3);
633: x_put_long (ad, wrd1);
634: ad += 4;
635: x_put_long (ad, wrd2);
636: ad += 4;
637: x_put_long (ad, wrd3);
638: }
639: break;
640: case 4:
641: x_put_word (ad, (uae_s16) toint (value, -32768.0, 32767.0));
642: break;
643: case 5:{
644: uae_u32 wrd1, wrd2;
645: from_double (value, &wrd1, &wrd2);
646: x_put_long (ad, wrd1);
647: ad += 4;
648: x_put_long (ad, wrd2);
649: }
650: break;
651: case 6:
652: x_put_byte (ad, (uae_s8)toint (value, -128.0, 127.0));
653: break;
654: default:
655: return 0;
656: }
657: return 1;
658: }
659:
660: STATIC_INLINE int get_fp_ad (uae_u32 opcode, uae_u32 * ad)
661: {
662: uae_u16 tmp;
663: uaecptr tmppc;
664: int mode;
665: int reg;
666:
667: mode = (opcode >> 3) & 7;
668: reg = opcode & 7;
669: switch (mode) {
670: case 0:
671: case 1:
672: return 0;
673: case 2:
674: *ad = m68k_areg (regs, reg);
675: break;
676: case 3:
677: *ad = m68k_areg (regs, reg);
678: break;
679: case 4:
680: *ad = m68k_areg (regs, reg);
681: break;
682: case 5:
683: *ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) x_next_iword ();
684: break;
685: case 6:
686: *ad = x_get_disp_ea_020 (m68k_areg (regs, reg), x_next_iword ());
687: break;
688: case 7:
689: switch (reg) {
690: case 0:
691: *ad = (uae_s32) (uae_s16) x_next_iword ();
692: break;
693: case 1:
694: *ad = x_next_ilong ();
695: break;
696: case 2:
697: *ad = m68k_getpc ();
698: *ad += (uae_s32) (uae_s16) x_next_iword ();
699: break;
700: case 3:
701: tmppc = m68k_getpc ();
702: tmp = x_next_iword ();
703: *ad = x_get_disp_ea_020 (tmppc, tmp);
704: break;
705: default:
706: return 0;
707: }
708: }
709: return 1;
710: }
711:
712: STATIC_INLINE int fpp_cond (int condition)
713: {
714: int N = (regs.fp_result < 0.0);
715: int Z = (regs.fp_result == 0.0);
716: int NotANumber = 0;
717:
718: #ifdef HAVE_ISNAN
719: NotANumber = isnan (regs.fp_result);
720: #endif
721:
722: if (NotANumber)
723: N=Z=0;
724:
725: switch (condition) {
726: case 0x00:
727: return 0;
728: case 0x01:
729: return Z;
730: case 0x02:
731: return !(NotANumber || Z || N);
732: case 0x03:
733: return Z || !(NotANumber || N);
734: case 0x04:
735: return N && !(NotANumber || Z);
736: case 0x05:
737: return Z || (N && !NotANumber);
738: case 0x06:
739: return !(NotANumber || Z);
740: case 0x07:
741: return !NotANumber;
742: case 0x08:
743: return NotANumber;
744: case 0x09:
745: return NotANumber || Z;
746: case 0x0a:
747: return NotANumber || !(N || Z);
748: case 0x0b:
749: return NotANumber || Z || !N;
750: case 0x0c:
751: return NotANumber || (N && !Z);
752: case 0x0d:
753: return NotANumber || Z || N;
754: case 0x0e:
755: return !Z;
756: case 0x0f:
757: return 1;
758: case 0x10:
759: return 0;
760: case 0x11:
761: return Z;
762: case 0x12:
763: return !(NotANumber || Z || N);
764: case 0x13:
765: return Z || !(NotANumber || N);
766: case 0x14:
767: return N && !(NotANumber || Z);
768: case 0x15:
769: return Z || (N && !NotANumber);
770: case 0x16:
771: return !(NotANumber || Z);
772: case 0x17:
773: return !NotANumber;
774: case 0x18:
775: return NotANumber;
776: case 0x19:
777: return NotANumber || Z;
778: case 0x1a:
779: return NotANumber || !(N || Z);
780: case 0x1b:
781: return NotANumber || Z || !N;
782: case 0x1c:
783: return NotANumber || (N && !Z);
784: case 0x1d:
785: return NotANumber || Z || N;
786: case 0x1e:
787: return !Z;
788: case 0x1f:
789: return 1;
790: }
791: return -1;
792: }
793:
794: void fpuop_dbcc (uae_u32 opcode, uae_u16 extra)
795: {
796: uaecptr pc = (uae_u32) m68k_getpc ();
797: uae_s32 disp;
798: int cc;
799:
800: #if DEBUG_FPP
801: if (!isinrom ())
802: write_log ("fdbcc_opp at %08lx\n", m68k_getpc ());
803: #endif
804: if (fault_if_no_fpu (opcode, 4))
805: return;
806:
807: disp = (uae_s32) (uae_s16) x_next_iword ();
808: cc = fpp_cond (extra & 0x3f);
809: if (cc == -1) {
810: fpu_op_illg (opcode, 4);
811: } else if (!cc) {
812: int reg = opcode & 0x7;
813:
814: m68k_dreg (regs, reg) = ((m68k_dreg (regs, reg) & 0xffff0000)
815: | (((m68k_dreg (regs, reg) & 0xffff) - 1) & 0xffff));
816: if ((m68k_dreg (regs, reg) & 0xffff) != 0xffff)
817: m68k_setpc (pc + disp);
818: }
819: }
820:
821: void fpuop_scc (uae_u32 opcode, uae_u16 extra)
822: {
823: uae_u32 ad;
824: int cc;
825:
826: #if DEBUG_FPP
827: if (!isinrom ())
828: write_log ("fscc_opp at %08lx\n", m68k_getpc ());
829: #endif
830: if (fault_if_no_fpu (opcode, 4))
831: return;
832:
833: cc = fpp_cond (extra & 0x3f);
834: if (cc == -1) {
835: fpu_op_illg (opcode, 4);
836: } else if ((opcode & 0x38) == 0) {
837: m68k_dreg (regs, opcode & 7) = (m68k_dreg (regs, opcode & 7) & ~0xff) | (cc ? 0xff : 0x00);
838: } else {
839: if (get_fp_ad (opcode, &ad) == 0) {
840: m68k_setpc (m68k_getpc () - 4);
841: op_illg (opcode);
842: } else
843: x_put_byte (ad, cc ? 0xff : 0x00);
844: }
845: }
846:
847: void fpuop_trapcc (uae_u32 opcode, uaecptr oldpc, uae_u16 extra)
848: {
849: int cc;
850:
851: #if DEBUG_FPP
852: if (!isinrom ())
853: write_log ("ftrapcc_opp at %08lx\n", m68k_getpc ());
854: #endif
855: if (fault_if_no_fpu (opcode, m68k_getpc() - oldpc))
856: return;
857:
858: cc = fpp_cond (extra & 0x3f);
859: if (cc == -1) {
860: fpu_op_illg (opcode, m68k_getpc () - oldpc);
861: }
862: if (cc)
863: Exception (7, oldpc - 2, M68000_EXC_SRC_CPU);
864: }
865:
866: void fpuop_bcc (uae_u32 opcode, uaecptr pc, uae_u32 extra)
867: {
868: int cc;
869:
870: #if DEBUG_FPP
871: if (!isinrom ())
872: write_log ("fbcc_opp at %08lx\n", m68k_getpc ());
873: #endif
874: if (fault_if_no_fpu (opcode, m68k_getpc () - pc))
875: return;
876:
877: cc = fpp_cond (opcode & 0x3f);
878: if (cc == -1) {
879: fpu_op_illg (opcode, m68k_getpc () - pc);
880: } else if (cc) {
881: if ((opcode & 0x40) == 0)
882: extra = (uae_s32) (uae_s16) extra;
883: m68k_setpc (pc + extra);
884: }
885: }
886:
887: void fpuop_save (uae_u32 opcode)
888: {
889: uae_u32 ad;
890: int incr = (opcode & 0x38) == 0x20 ? -1 : 1;
891: int fpu_version = get_fpu_version();
892: int i;
893:
894: #if DEBUG_FPP
895: if (!isinrom ())
896: write_log ("fsave_opp at %08lx\n", m68k_getpc ());
897: #endif
898: if (fault_if_no_fpu (opcode, 2))
899: return;
900:
901: if (get_fp_ad (opcode, &ad) == 0) {
902: fpu_op_illg (opcode, 2);
903: return;
904: }
905:
906: if (currprefs.fpu_model == 68060) {
907: /* 12 byte 68060 IDLE frame. */
908: if (incr < 0) {
909: ad -= 4;
910: x_put_long (ad, 0x00000000);
911: ad -= 4;
912: x_put_long (ad, 0x00000000);
913: ad -= 4;
914: x_put_long (ad, 0x00006000);
915: } else {
916: x_put_long (ad, 0x00006000);
917: ad += 4;
918: x_put_long (ad, 0x00000000);
919: ad += 4;
920: x_put_long (ad, 0x00000000);
921: ad += 4;
922: }
923: } else if (currprefs.fpu_model == 68040) {
924: /* 4 byte 68040 IDLE frame. */
925: if (incr < 0) {
926: ad -= 4;
927: x_put_long (ad, fpu_version << 24);
928: } else {
929: x_put_long (ad, fpu_version << 24);
930: ad += 4;
931: }
932: } else { /* 68881/68882 */
933: int idle_size = currprefs.fpu_model == 68882 ? 0x38 : 0x18;
934: if (incr < 0) {
935: ad -= 4;
936: x_put_long (ad, 0x70000000);
937: for (i = 0; i < (idle_size - 1) / 4; i++) {
938: ad -= 4;
939: x_put_long (ad, 0x00000000);
940: }
941: ad -= 4;
942: x_put_long (ad, (fpu_version << 24) | (idle_size << 16));
943: } else {
944: x_put_long (ad, (fpu_version << 24) | (idle_size << 16));
945: ad += 4;
946: for (i = 0; i < (idle_size - 1) / 4; i++) {
947: x_put_long (ad, 0x00000000);
948: ad += 4;
949: }
950: x_put_long (ad, 0x70000000);
951: ad += 4;
952: }
953: }
954: if ((opcode & 0x38) == 0x18)
955: m68k_areg (regs, opcode & 7) = ad;
956: if ((opcode & 0x38) == 0x20)
957: m68k_areg (regs, opcode & 7) = ad;
958: }
959:
960: void fpuop_restore (uae_u32 opcode)
961: {
962: uae_u32 ad;
963: uae_u32 d;
964: int incr = (opcode & 0x38) == 0x20 ? -1 : 1;
965:
966: #if DEBUG_FPP
967: if (!isinrom ())
968: write_log ("frestore_opp at %08lx\n", m68k_getpc ());
969: #endif
970: if (fault_if_no_fpu (opcode, 2))
971: return;
972:
973: if (get_fp_ad (opcode, &ad) == 0) {
974: fpu_op_illg (opcode, 2);
975: return;
976: }
977:
978: if (currprefs.fpu_model == 68060) {
979: /* all 68060 FPU frames are 12 bytes */
980: if (incr < 0) {
981: ad -= 4;
982: d = x_get_long (ad);
983: ad -= 8;
984: } else {
985: d = x_get_long (ad);
986: ad += 4;
987: ad += 8;
988: }
989:
990: } else if (currprefs.fpu_model == 68040) {
991: /* 68040 */
992: if (incr < 0) {
993: /* @@@ This may be wrong. */
994: ad -= 4;
995: d = x_get_long (ad);
996: if ((d & 0xff000000) != 0) { /* Not a NULL frame? */
997: if ((d & 0x00ff0000) == 0) { /* IDLE */
998: } else if ((d & 0x00ff0000) == 0x00300000) { /* UNIMP */
999: ad -= 44;
1000: } else if ((d & 0x00ff0000) == 0x00600000) { /* BUSY */
1001: ad -= 92;
1002: }
1003: }
1004: } else {
1005: d = x_get_long (ad);
1006: ad += 4;
1007: if ((d & 0xff000000) != 0) { /* Not a NULL frame? */
1008: if ((d & 0x00ff0000) == 0) { /* IDLE */
1009: } else if ((d & 0x00ff0000) == 0x00300000) { /* UNIMP */
1010: ad += 44;
1011: } else if ((d & 0x00ff0000) == 0x00600000) { /* BUSY */
1012: ad += 92;
1013: }
1014: }
1015: }
1016: } else { /* 68881/68882 */
1017: if (incr < 0) {
1018: ad -= 4;
1019: d = x_get_long (ad);
1020: if ((d & 0xff000000) != 0) {
1021: if ((d & 0x00ff0000) == 0x00180000)
1022: ad -= 6 * 4;
1023: else if ((d & 0x00ff0000) == 0x00380000)
1024: ad -= 14 * 4;
1025: else if ((d & 0x00ff0000) == 0x00b40000)
1026: ad -= 45 * 4;
1027: }
1028: } else {
1029: d = x_get_long (ad);
1030: ad += 4;
1031: if ((d & 0xff000000) != 0) {
1032: if ((d & 0x00ff0000) == 0x00180000)
1033: ad += 6 * 4;
1034: else if ((d & 0x00ff0000) == 0x00380000)
1035: ad += 14 * 4;
1036: else if ((d & 0x00ff0000) == 0x00b40000)
1037: ad += 45 * 4;
1038: }
1039: }
1040: }
1041: if ((opcode & 0x38) == 0x18)
1042: m68k_areg (regs, opcode & 7) = ad;
1043: if ((opcode & 0x38) == 0x20)
1044: m68k_areg (regs, opcode & 7) = ad;
1045: }
1046:
1047: static void fround (int reg)
1048: {
1049: regs.fp[reg] = (float)regs.fp[reg];
1050: }
1051:
1052: void fpuop_arithmetic (uae_u32 opcode, uae_u16 extra)
1053: {
1054: int reg;
1055: fptype src;
1056:
1057: #if DEBUG_FPP
1058: if (!isinrom ())
1059: write_log ("FPP %04lx %04x at %08lx\n", opcode & 0xffff, extra, m68k_getpc () - 4);
1060: #endif
1061: if (fault_if_no_fpu (opcode, 4))
1062: return;
1063:
1064: switch ((extra >> 13) & 0x7) {
1065:
1066: case 3:
1067: if (put_fp_value (regs.fp[(extra >> 7) & 7], opcode, extra) == 0) {
1068: m68k_setpc (m68k_getpc () - 4);
1069: op_illg (opcode);
1070: }
1071: return;
1072:
1073: case 4:
1074: case 5:
1075: if ((opcode & 0x38) == 0) {
1076: if (extra & 0x2000) {
1077: if (extra & 0x1000)
1078: m68k_dreg (regs, opcode & 7) = regs.fpcr & 0xffff;
1079: if (extra & 0x0800)
1080: m68k_dreg (regs, opcode & 7) = get_fpsr ();
1081: if (extra & 0x0400)
1082: m68k_dreg (regs, opcode & 7) = regs.fpiar;
1083: } else {
1084: if (extra & 0x1000) {
1085: regs.fpcr = m68k_dreg (regs, opcode & 7);
1086: native_set_fpucw (regs.fpcr);
1087: }
1088: if (extra & 0x0800)
1089: set_fpsr (m68k_dreg (regs, opcode & 7));
1090: if (extra & 0x0400)
1091: regs.fpiar = m68k_dreg (regs, opcode & 7);
1092: }
1093: } else if ((opcode & 0x38) == 0x08) {
1094: if (extra & 0x2000) {
1095: if (extra & 0x1000)
1096: m68k_areg (regs, opcode & 7) = regs.fpcr & 0xffff;
1097: if (extra & 0x0800)
1098: m68k_areg (regs, opcode & 7) = get_fpsr ();
1099: if (extra & 0x0400)
1100: m68k_areg (regs, opcode & 7) = regs.fpiar;
1101: } else {
1102: if (extra & 0x1000) {
1103: regs.fpcr = m68k_areg (regs, opcode & 7);
1104: native_set_fpucw (regs.fpcr);
1105: }
1106: if (extra & 0x0800)
1107: set_fpsr (m68k_areg (regs, opcode & 7));
1108: if (extra & 0x0400)
1109: regs.fpiar = m68k_areg (regs, opcode & 7);
1110: }
1111: } else if ((opcode & 0x3f) == 0x3c) {
1112: if ((extra & 0x2000) == 0) {
1113: if (extra & 0x1000) {
1114: regs.fpcr = x_next_ilong ();
1115: native_set_fpucw (regs.fpcr);
1116: }
1117: if (extra & 0x0800)
1118: set_fpsr (x_next_ilong ());
1119: if (extra & 0x0400)
1120: regs.fpiar = x_next_ilong ();
1121: }
1122: } else if (extra & 0x2000) {
1123: /* FMOVEM FPP->memory */
1124: uae_u32 ad;
1125: int incr = 0;
1126:
1127: if (get_fp_ad (opcode, &ad) == 0) {
1128: m68k_setpc (m68k_getpc () - 4);
1129: op_illg (opcode);
1130: return;
1131: }
1132: if ((opcode & 0x38) == 0x20) {
1133: if (extra & 0x1000)
1134: incr += 4;
1135: if (extra & 0x0800)
1136: incr += 4;
1137: if (extra & 0x0400)
1138: incr += 4;
1139: }
1140: ad -= incr;
1141: if (extra & 0x1000) {
1142: x_put_long (ad, regs.fpcr & 0xffff);
1143: ad += 4;
1144: }
1145: if (extra & 0x0800) {
1146: x_put_long (ad, get_fpsr());
1147: ad += 4;
1148: }
1149: if (extra & 0x0400) {
1150: x_put_long (ad, regs.fpiar);
1151: ad += 4;
1152: }
1153: ad -= incr;
1154: if ((opcode & 0x38) == 0x18)
1155: m68k_areg (regs, opcode & 7) = ad;
1156: if ((opcode & 0x38) == 0x20)
1157: m68k_areg (regs, opcode & 7) = ad;
1158: } else {
1159: /* FMOVEM memory->FPP */
1160: uae_u32 ad;
1161: int incr = 0;
1162:
1163: if (get_fp_ad (opcode, &ad) == 0) {
1164: m68k_setpc (m68k_getpc () - 4);
1165: op_illg (opcode);
1166: return;
1167: }
1168: if((opcode & 0x38) == 0x20) {
1169: if (extra & 0x1000)
1170: incr += 4;
1171: if (extra & 0x0800)
1172: incr += 4;
1173: if (extra & 0x0400)
1174: incr += 4;
1175: ad = ad - incr;
1176: }
1177: if (extra & 0x1000) {
1178: regs.fpcr = x_get_long (ad);
1179: native_set_fpucw (regs.fpcr);
1180: ad += 4;
1181: }
1182: if (extra & 0x0800) {
1183: set_fpsr(x_get_long (ad));
1184: ad += 4;
1185: }
1186: if (extra & 0x0400) {
1187: regs.fpiar = x_get_long (ad);
1188: ad += 4;
1189: }
1190: if ((opcode & 0x38) == 0x18)
1191: m68k_areg (regs, opcode & 7) = ad;
1192: if ((opcode & 0x38) == 0x20)
1193: m68k_areg (regs, opcode & 7) = ad - incr;
1194: }
1195: return;
1196:
1197: case 6:
1198: case 7:
1199: {
1200: uae_u32 ad, list = 0;
1201: int incr = 0;
1202: if (extra & 0x2000) {
1203: /* FMOVEM FPP->memory */
1204: if (get_fp_ad (opcode, &ad) == 0) {
1205: m68k_setpc (m68k_getpc () - 4);
1206: op_illg (opcode);
1207: return;
1208: }
1209: switch ((extra >> 11) & 3) {
1210: case 0: /* static pred */
1211: list = extra & 0xff;
1212: incr = -1;
1213: break;
1214: case 1: /* dynamic pred */
1215: list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff;
1216: incr = -1;
1217: break;
1218: case 2: /* static postinc */
1219: list = extra & 0xff;
1220: incr = 1;
1221: break;
1222: case 3: /* dynamic postinc */
1223: list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff;
1224: incr = 1;
1225: break;
1226: }
1227: if (incr < 0) {
1228: for (reg = 7; reg >= 0; reg--) {
1229: uae_u32 wrd1, wrd2, wrd3;
1230: if (list & 0x80) {
1231: from_exten (regs.fp[reg], &wrd1, &wrd2, &wrd3);
1232: ad -= 4;
1233: x_put_long (ad, wrd3);
1234: ad -= 4;
1235: x_put_long (ad, wrd2);
1236: ad -= 4;
1237: x_put_long (ad, wrd1);
1238: }
1239: list <<= 1;
1240: }
1241: } else {
1242: for (reg = 0; reg <= 7; reg++) {
1243: uae_u32 wrd1, wrd2, wrd3;
1244: if (list & 0x80) {
1245: from_exten (regs.fp[reg], &wrd1, &wrd2, &wrd3);
1246: x_put_long (ad, wrd1);
1247: ad += 4;
1248: x_put_long (ad, wrd2);
1249: ad += 4;
1250: x_put_long (ad, wrd3);
1251: ad += 4;
1252: }
1253: list <<= 1;
1254: }
1255: }
1256: if ((opcode & 0x38) == 0x18)
1257: m68k_areg (regs, opcode & 7) = ad;
1258: if ((opcode & 0x38) == 0x20)
1259: m68k_areg (regs, opcode & 7) = ad;
1260: } else {
1261: /* FMOVEM memory->FPP */
1262: if (get_fp_ad (opcode, &ad) == 0) {
1263: m68k_setpc (m68k_getpc () - 4);
1264: op_illg (opcode);
1265: return;
1266: }
1267: switch ((extra >> 11) & 3) {
1268: case 0: /* static pred */
1269: list = extra & 0xff;
1270: incr = -1;
1271: break;
1272: case 1: /* dynamic pred */
1273: list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff;
1274: incr = -1;
1275: break;
1276: case 2: /* static postinc */
1277: list = extra & 0xff;
1278: incr = 1;
1279: break;
1280: case 3: /* dynamic postinc */
1281: list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff;
1282: incr = 1;
1283: break;
1284: }
1285: if (incr < 0) {
1286: for (reg = 7; reg >= 0; reg--) {
1287: uae_u32 wrd1, wrd2, wrd3;
1288: if (list & 0x80) {
1289: ad -= 4;
1290: wrd3 = x_get_long (ad);
1291: ad -= 4;
1292: wrd2 = x_get_long (ad);
1293: ad -= 4;
1294: wrd1 = x_get_long (ad);
1295: regs.fp[reg] = to_exten(wrd1, wrd2, wrd3);
1296: }
1297: list <<= 1;
1298: }
1299: } else {
1300: for (reg = 0; reg <= 7; reg++) {
1301: uae_u32 wrd1, wrd2, wrd3;
1302: if (list & 0x80) {
1303: wrd1 = x_get_long (ad);
1304: ad += 4;
1305: wrd2 = x_get_long (ad);
1306: ad += 4;
1307: wrd3 = x_get_long (ad);
1308: ad += 4;
1309: regs.fp[reg] = to_exten(wrd1, wrd2, wrd3);
1310: }
1311: list <<= 1;
1312: }
1313: }
1314: if ((opcode & 0x38) == 0x18)
1315: m68k_areg (regs, opcode & 7) = ad;
1316: if ((opcode & 0x38) == 0x20)
1317: m68k_areg (regs, opcode & 7) = ad;
1318: }
1319: }
1320: return;
1321:
1322: case 0:
1323: case 2: /* Extremely common */
1324: reg = (extra >> 7) & 7;
1325: if ((extra & 0xfc00) == 0x5c00) {
1326: switch (extra & 0x7f) {
1327: case 0x00:
1328: regs.fp[reg] = *fp_pi;
1329: break;
1330: case 0x0b:
1331: regs.fp[reg] = *fp_l10_2;
1332: break;
1333: case 0x0c:
1334: regs.fp[reg] = *fp_exp_1;
1335: break;
1336: case 0x0d:
1337: regs.fp[reg] = *fp_l2_e;
1338: break;
1339: case 0x0e:
1340: regs.fp[reg] = *fp_l10_e;
1341: break;
1342: case 0x0f:
1343: regs.fp[reg] = 0.0;
1344: break;
1345: case 0x30:
1346: regs.fp[reg] = *fp_ln_2;
1347: break;
1348: case 0x31:
1349: regs.fp[reg] = *fp_ln_10;
1350: break;
1351: case 0x32:
1352: regs.fp[reg] = (fptype)fp_1e0;
1353: break;
1354: case 0x33:
1355: regs.fp[reg] = (fptype)fp_1e1;
1356: break;
1357: case 0x34:
1358: regs.fp[reg] = (fptype)fp_1e2;
1359: break;
1360: case 0x35:
1361: regs.fp[reg] = (fptype)fp_1e4;
1362: break;
1363: case 0x36:
1364: regs.fp[reg] = (fptype)fp_1e8;
1365: break;
1366: case 0x37:
1367: regs.fp[reg] = *fp_1e16;
1368: break;
1369: case 0x38:
1370: regs.fp[reg] = *fp_1e32;
1371: break;
1372: case 0x39:
1373: regs.fp[reg] = *fp_1e64;
1374: break;
1375: case 0x3a:
1376: regs.fp[reg] = *fp_1e128;
1377: break;
1378: case 0x3b:
1379: regs.fp[reg] = *fp_1e256;
1380: break;
1381: case 0x3c:
1382: regs.fp[reg] = *fp_1e512;
1383: break;
1384: case 0x3d:
1385: regs.fp[reg] = *fp_1e1024;
1386: break;
1387: case 0x3e:
1388: regs.fp[reg] = *fp_1e2048;
1389: break;
1390: case 0x3f:
1391: regs.fp[reg] = *fp_1e4096;
1392: break;
1393: default:
1394: m68k_setpc (m68k_getpc () - 4);
1395: op_illg (opcode);
1396: return;
1397: }
1398: MAKE_FPSR (regs.fp[reg]);
1399: return;
1400: }
1401: if (get_fp_value (opcode, extra, &src) == 0) {
1402: m68k_setpc (m68k_getpc () - 4);
1403: op_illg (opcode);
1404: return;
1405: }
1406:
1407: switch (extra & 0x7f) {
1408:
1409: case 0x00: /* FMOVE */
1410: case 0x40: /* Explicit rounding. This is just a quick fix. */
1411: case 0x44: /* Same for all other cases that have three choices */
1412: regs.fp[reg] = src; /* Brian King was here. */
1413: /*<ea> to register needs FPSR updated. See Motorola 68K Manual. */
1414: if ((extra & 0x44) == 0x40)
1415: fround (reg);
1416: break;
1417: case 0x01: /* FINT */
1418: /* need to take the current rounding mode into account */
1419: #if defined(X86_MSVC_ASSEMBLY)
1420: {
1421: fptype tmp_fp;
1422:
1423: __asm {
1424: fld LDPTR src
1425: frndint
1426: fstp LDPTR tmp_fp
1427: }
1428: regs.fp[reg] = tmp_fp;
1429: }
1430: #else /* no X86_MSVC */
1431: switch ((regs.fpcr >> 4) & 3) {
1432: case 0: /* to nearest */
1433: regs.fp[reg] = floor (src + 0.5);
1434: break;
1435: case 1: /* to zero */
1436: if (src >= 0.0)
1437: regs.fp[reg] = floor (src);
1438: else
1439: regs.fp[reg] = ceil (src);
1440: break;
1441: case 2: /* down */
1442: regs.fp[reg] = floor (src);
1443: break;
1444: case 3: /* up */
1445: regs.fp[reg] = ceil (src);
1446: break;
1447: default: /* never reached */
1448: regs.fp[reg] = src;
1449: }
1450: #endif /* X86_MSVC */
1451: break;
1452: case 0x02: /* FSINH */
1453: regs.fp[reg] = sinh (src);
1454: break;
1455: case 0x03: /* FINTRZ */
1456: regs.fp[reg] = fp_round_to_zero(src);
1457: break;
1458: case 0x04: /* FSQRT */
1459: case 0x41:
1460: case 0x45:
1461: regs.fp[reg] = sqrt (src);
1462: if ((extra & 0x44) == 0x40)
1463: fround (reg);
1464: break;
1465: case 0x06: /* FLOGNP1 */
1466: regs.fp[reg] = log (src + 1.0);
1467: break;
1468: case 0x08: /* FETOXM1 */
1469: regs.fp[reg] = exp (src) - 1.0;
1470: break;
1471: case 0x09: /* FTANH */
1472: regs.fp[reg] = tanh (src);
1473: break;
1474: case 0x0a: /* FATAN */
1475: regs.fp[reg] = atan (src);
1476: break;
1477: case 0x0c: /* FASIN */
1478: regs.fp[reg] = asin (src);
1479: break;
1480: case 0x0d: /* FATANH */
1481: #if 1 /* The BeBox doesn't have atanh, and it isn't in the HPUX libm either */
1482: regs.fp[reg] = 0.5 * log ((1 + src) / (1 - src));
1483: #else
1484: regs.fp[reg] = atanh (src);
1485: #endif
1486: break;
1487: case 0x0e: /* FSIN */
1488: regs.fp[reg] = sin (src);
1489: break;
1490: case 0x0f: /* FTAN */
1491: regs.fp[reg] = tan (src);
1492: break;
1493: case 0x10: /* FETOX */
1494: regs.fp[reg] = exp (src);
1495: break;
1496: case 0x11: /* FTWOTOX */
1497: regs.fp[reg] = pow (2.0, src);
1498: break;
1499: case 0x12: /* FTENTOX */
1500: regs.fp[reg] = pow (10.0, src);
1501: break;
1502: case 0x14: /* FLOGN */
1503: regs.fp[reg] = log (src);
1504: break;
1505: case 0x15: /* FLOG10 */
1506: regs.fp[reg] = log10 (src);
1507: break;
1508: case 0x16: /* FLOG2 */
1509: regs.fp[reg] = *fp_l2_e * log (src);
1510: break;
1511: case 0x18: /* FABS */
1512: case 0x58:
1513: case 0x5c:
1514: regs.fp[reg] = src < 0 ? -src : src;
1515: if ((extra & 0x44) == 0x40)
1516: fround (reg);
1517: break;
1518: case 0x19: /* FCOSH */
1519: regs.fp[reg] = cosh (src);
1520: break;
1521: case 0x1a: /* FNEG */
1522: case 0x5a:
1523: case 0x5e:
1524: regs.fp[reg] = -src;
1525: if ((extra & 0x44) == 0x40)
1526: fround (reg);
1527: break;
1528: case 0x1c: /* FACOS */
1529: regs.fp[reg] = acos (src);
1530: break;
1531: case 0x1d: /* FCOS */
1532: regs.fp[reg] = cos (src);
1533: break;
1534: case 0x1e: /* FGETEXP */
1535: {
1536: if (src == 0) {
1537: regs.fp[reg] = 0;
1538: } else {
1539: int expon;
1540: frexp (src, &expon);
1541: regs.fp[reg] = (double) (expon - 1);
1542: }
1543: }
1544: break;
1545: case 0x1f: /* FGETMAN */
1546: {
1547: if (src == 0) {
1548: regs.fp[reg] = 0;
1549: } else {
1550: int expon;
1551: regs.fp[reg] = frexp (src, &expon) * 2.0;
1552: }
1553: }
1554: break;
1555: case 0x20: /* FDIV */
1556: case 0x60:
1557: case 0x64:
1558: regs.fp[reg] /= src;
1559: if ((extra & 0x44) == 0x40)
1560: fround (reg);
1561: break;
1562: case 0x21: /* FMOD */
1563: {
1564: fptype quot = fp_round_to_zero(regs.fp[reg] / src);
1565: regs.fp[reg] = regs.fp[reg] - quot * src;
1566: }
1567: break;
1568: case 0x22: /* FADD */
1569: case 0x62:
1570: case 0x66:
1571: regs.fp[reg] += src;
1572: if ((extra & 0x44) == 0x40)
1573: fround (reg);
1574: break;
1575: case 0x23: /* FMUL */
1576: case 0x63:
1577: case 0x67:
1578: regs.fp[reg] *= src;
1579: if ((extra & 0x44) == 0x40)
1580: fround (reg);
1581: break;
1582: case 0x24: /* FSGLDIV */
1583: regs.fp[reg] /= src;
1584: break;
1585: case 0x25: /* FREM */
1586: {
1587: fptype quot = fp_round_to_nearest(regs.fp[reg] / src);
1588: regs.fp[reg] = regs.fp[reg] - quot * src;
1589: }
1590: break;
1591: case 0x26: /* FSCALE */
1592: if (src != 0) {
1593: #ifdef ldexp
1594: regs.fp[reg] = ldexp (regs.fp[reg], (int) src);
1595: #else
1596: regs.fp[reg] *= exp (*fp_ln_2 * (int) src);
1597: #endif
1598: }
1599: break;
1600: case 0x27: /* FSGLMUL */
1601: regs.fp[reg] *= src;
1602: break;
1603: case 0x28: /* FSUB */
1604: case 0x68:
1605: case 0x6c:
1606: regs.fp[reg] -= src;
1607: if ((extra & 0x44) == 0x40)
1608: fround (reg);
1609: break;
1610: case 0x30: /* FSINCOS */
1611: case 0x31:
1612: case 0x32:
1613: case 0x33:
1614: case 0x34:
1615: case 0x35:
1616: case 0x36:
1617: case 0x37:
1618: regs.fp[extra & 7] = cos (src);
1619: regs.fp[reg] = sin (src);
1620: break;
1621: case 0x38: /* FCMP */
1622: {
1623: fptype tmp = regs.fp[reg] - src;
1624: regs.fpsr = 0;
1625: MAKE_FPSR (tmp);
1626: }
1627: return;
1628: case 0x3a: /* FTST */
1629: regs.fpsr = 0;
1630: MAKE_FPSR (src);
1631: return;
1632: default:
1633: m68k_setpc (m68k_getpc () - 4);
1634: op_illg (opcode);
1635: return;
1636: }
1637: MAKE_FPSR (regs.fp[reg]);
1638: return;
1639: }
1640: m68k_setpc (m68k_getpc () - 4);
1641: op_illg (opcode);
1642: }
1643:
1644: void fpu_reset (void)
1645: {
1646: regs.fpcr = regs.fpsr = regs.fpiar = 0;
1647: regs.fp_result = 1;
1648: fpux_restore (NULL);
1649: }
1650:
1651: uae_u8 *restore_fpu (uae_u8 *src)
1652: {
1653: int i;
1654: uae_u32 flags;
1655:
1656: changed_prefs.fpu_model = currprefs.fpu_model = restore_u32 ();
1657: flags = restore_u32 ();
1658: for (i = 0; i < 8; i++) {
1659: uae_u32 w1 = restore_u32 ();
1660: uae_u32 w2 = restore_u32 ();
1661: uae_u32 w3 = restore_u16 ();
1662: regs.fp[i] = to_exten (w1, w2, w3);
1663: }
1664: regs.fpcr = restore_u32 ();
1665: native_set_fpucw (regs.fpcr);
1666: regs.fpsr = restore_u32 ();
1667: regs.fpiar = restore_u32 ();
1668: if (flags & 0x80000000) {
1669: restore_u32();
1670: restore_u32();
1671: }
1672: write_log ("FPU: %d\n", currprefs.fpu_model);
1673: return src;
1674: }
1675:
1676: uae_u8 *save_fpu (int *len, uae_u8 *dstptr)
1677: {
1678: uae_u8 *dstbak,*dst;
1679: int i;
1680:
1681: *len = 0;
1682: if (currprefs.fpu_model == 0)
1683: return 0;
1684: if (dstptr)
1685: dstbak = dst = dstptr;
1686: else
1687: dstbak = dst = xmalloc (uae_u8, 4+4+8*10+4+4+4+4+4);
1688: save_u32 (currprefs.fpu_model);
1689: save_u32 (0x80000000);
1690: for (i = 0; i < 8; i++) {
1691: uae_u32 w1, w2, w3;
1692: from_exten (regs.fp[i], &w1, &w2, &w3);
1693: save_u32 (w1);
1694: save_u32 (w2);
1695: save_u16 (w3);
1696: }
1697: save_u32 (regs.fpcr);
1698: save_u32 (regs.fpsr);
1699: save_u32 (regs.fpiar);
1700: save_u32 (-1);
1701: save_u32 (0);
1702: *len = dst - dstbak;
1703: return dstbak;
1704: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.