|
|
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;
194:
195: if (currprefs.fpu_revision >= 0)
196: return currprefs.fpu_revision;
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];
353:
1.1.1.2 root 354: #if USE_LONG_DOUBLE
355: sprintf (str, "%.16Le", src);
356: #else
1.1 root 357: sprintf (str, "%.16e", src);
1.1.1.2 root 358: #endif
1.1 root 359: cp = str;
360: *wrd1 = *wrd2 = *wrd3 = 0;
361: if (*cp == '-') {
362: cp++;
363: *wrd1 = 0x80000000;
364: }
365: if (*cp == '+')
366: cp++;
367: *wrd1 |= (*cp++ - '0');
368: if (*cp == '.')
369: cp++;
370: for (i = 0; i < 8; i++) {
371: *wrd2 <<= 4;
372: if (*cp >= '0' && *cp <= '9')
373: *wrd2 |= *cp++ - '0';
374: }
375: for (i = 0; i < 8; i++) {
376: *wrd3 <<= 4;
377: if (*cp >= '0' && *cp <= '9')
378: *wrd3 |= *cp++ - '0';
379: }
380: if (*cp == 'e' || *cp == 'E') {
381: cp++;
382: if (*cp == '-') {
383: cp++;
384: *wrd1 |= 0x40000000;
385: }
386: if (*cp == '+')
387: cp++;
388: t = 0;
389: for (i = 0; i < 3; i++) {
390: if (*cp >= '0' && *cp <= '9')
391: t = (t << 4) | (*cp++ - '0');
392: }
393: *wrd1 |= t << 16;
394: }
395: }
396:
397: STATIC_INLINE int get_fp_value (uae_u32 opcode, uae_u16 extra, fptype *src)
398: {
399: uaecptr tmppc;
400: uae_u16 tmp;
401: int size, mode, reg;
402: uae_u32 ad = 0;
403: static const int sz1[8] = { 4, 4, 12, 12, 2, 8, 1, 0 };
404: static const int sz2[8] = { 4, 4, 12, 12, 2, 8, 2, 0 };
405:
406: if (!(extra & 0x4000)) {
407: *src = regs.fp[(extra >> 10) & 7];
408: return 1;
409: }
410: mode = (opcode >> 3) & 7;
411: reg = opcode & 7;
412: size = (extra >> 10) & 7;
413:
414: switch (mode) {
415: case 0:
416: switch (size) {
417: case 6:
418: *src = (fptype) (uae_s8) m68k_dreg (regs, reg);
419: break;
420: case 4:
421: *src = (fptype) (uae_s16) m68k_dreg (regs, reg);
422: break;
423: case 0:
424: *src = (fptype) (uae_s32) m68k_dreg (regs, reg);
425: break;
426: case 1:
427: *src = to_single (m68k_dreg (regs, reg));
428: break;
429: default:
430: return 0;
431: }
432: return 1;
433: case 1:
434: return 0;
435: case 2:
436: ad = m68k_areg (regs, reg);
437: break;
438: case 3:
439: ad = m68k_areg (regs, reg);
440: m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size];
441: break;
442: case 4:
443: m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size];
444: ad = m68k_areg (regs, reg);
445: break;
446: case 5:
447: ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) x_next_iword ();
448: break;
449: case 6:
450: ad = x_get_disp_ea_020 (m68k_areg (regs, reg), x_next_iword ());
451: break;
452: case 7:
453: switch (reg) {
454: case 0:
455: ad = (uae_s32) (uae_s16) x_next_iword ();
456: break;
457: case 1:
458: ad = x_next_ilong ();
459: break;
460: case 2:
461: ad = m68k_getpc ();
462: ad += (uae_s32) (uae_s16) x_next_iword ();
463: break;
464: case 3:
465: tmppc = m68k_getpc ();
466: tmp = x_next_iword ();
467: ad = x_get_disp_ea_020 (tmppc, tmp);
468: break;
469: case 4:
470: ad = m68k_getpc ();
471: m68k_setpc (ad + sz2[size]);
472: if (size == 6)
473: ad++;
474: break;
475: default:
476: return 0;
477: }
478: }
479: switch (size) {
480: case 0:
481: *src = (fptype) (uae_s32) x_get_long (ad);
482: break;
483: case 1:
484: *src = to_single (x_get_long (ad));
485: break;
486: case 2:{
487: uae_u32 wrd1, wrd2, wrd3;
488: wrd1 = x_get_long (ad);
489: ad += 4;
490: wrd2 = x_get_long (ad);
491: ad += 4;
492: wrd3 = x_get_long (ad);
493: *src = to_exten (wrd1, wrd2, wrd3);
494: }
495: break;
496: case 3:{
497: uae_u32 wrd1, wrd2, wrd3;
498: wrd1 = x_get_long (ad);
499: ad += 4;
500: wrd2 = x_get_long (ad);
501: ad += 4;
502: wrd3 = x_get_long (ad);
503: *src = to_pack (wrd1, wrd2, wrd3);
504: }
505: break;
506: case 4:
507: *src = (fptype) (uae_s16) x_get_word (ad);
508: break;
509: case 5:{
510: uae_u32 wrd1, wrd2;
511: wrd1 = x_get_long (ad);
512: ad += 4;
513: wrd2 = x_get_long (ad);
514: *src = to_double (wrd1, wrd2);
515: }
516: break;
517: case 6:
518: *src = (fptype) (uae_s8) x_get_byte (ad);
519: break;
520: default:
521: return 0;
522: }
523: return 1;
524: }
525:
526: STATIC_INLINE int put_fp_value (fptype value, uae_u32 opcode, uae_u16 extra)
527: {
528: uae_u16 tmp;
529: uaecptr tmppc;
530: int size, mode, reg;
531: uae_u32 ad;
532: static int sz1[8] = { 4, 4, 12, 12, 2, 8, 1, 0 };
533: static int sz2[8] = { 4, 4, 12, 12, 2, 8, 2, 0 };
534:
535: #if DEBUG_FPP
536: if (!isinrom ())
537: write_log ("PUTFP: %f %04X %04X\n", value, opcode, extra);
538: #endif
539: if (!(extra & 0x4000)) {
540: regs.fp[(extra >> 10) & 7] = value;
541: return 1;
542: }
543: reg = opcode & 7;
544: mode = (opcode >> 3) & 7;
545: size = (extra >> 10) & 7;
546: ad = -1;
547: switch (mode) {
548: case 0:
549: switch (size) {
550: case 6:
551: m68k_dreg (regs, reg) = (uae_u32)(((toint (value, -128.0, 127.0) & 0xff)
552: | (m68k_dreg (regs, reg) & ~0xff)));
553: break;
554: case 4:
555: m68k_dreg (regs, reg) = (uae_u32)(((toint (value, -32768.0, 32767.0) & 0xffff)
556: | (m68k_dreg (regs, reg) & ~0xffff)));
557: break;
558: case 0:
559: m68k_dreg (regs, reg) = (uae_u32)toint (value, -2147483648.0, 2147483647.0);
560: break;
561: case 1:
562: m68k_dreg (regs, reg) = from_single (value);
563: break;
564: default:
565: return 0;
566: }
567: return 1;
568: case 1:
569: return 0;
570: case 2:
571: ad = m68k_areg (regs, reg);
572: break;
573: case 3:
574: ad = m68k_areg (regs, reg);
575: m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size];
576: break;
577: case 4:
578: m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size];
579: ad = m68k_areg (regs, reg);
580: break;
581: case 5:
582: ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) x_next_iword ();
583: break;
584: case 6:
585: ad = x_get_disp_ea_020 (m68k_areg (regs, reg), x_next_iword ());
586: break;
587: case 7:
588: switch (reg) {
589: case 0:
590: ad = (uae_s32) (uae_s16) x_next_iword ();
591: break;
592: case 1:
593: ad = x_next_ilong ();
594: break;
595: case 2:
596: ad = m68k_getpc ();
597: ad += (uae_s32) (uae_s16) x_next_iword ();
598: break;
599: case 3:
600: tmppc = m68k_getpc ();
601: tmp = x_next_iword ();
602: ad = x_get_disp_ea_020 (tmppc, tmp);
603: break;
604: case 4:
605: ad = m68k_getpc ();
606: m68k_setpc (ad + sz2[size]);
607: break;
608: default:
609: return 0;
610: }
611: }
612: switch (size) {
613: case 0:
614: x_put_long (ad, (uae_u32)toint (value, -2147483648.0, 2147483647.0));
615: break;
616: case 1:
617: x_put_long (ad, from_single (value));
618: break;
619: case 2:
620: {
621: uae_u32 wrd1, wrd2, wrd3;
622: from_exten (value, &wrd1, &wrd2, &wrd3);
623: x_put_long (ad, wrd1);
624: ad += 4;
625: x_put_long (ad, wrd2);
626: ad += 4;
627: x_put_long (ad, wrd3);
628: }
629: break;
630: case 3:
631: {
632: uae_u32 wrd1, wrd2, wrd3;
633: from_pack (value, &wrd1, &wrd2, &wrd3);
634: x_put_long (ad, wrd1);
635: ad += 4;
636: x_put_long (ad, wrd2);
637: ad += 4;
638: x_put_long (ad, wrd3);
639: }
640: break;
641: case 4:
642: x_put_word (ad, (uae_s16) toint (value, -32768.0, 32767.0));
643: break;
644: case 5:{
645: uae_u32 wrd1, wrd2;
646: from_double (value, &wrd1, &wrd2);
647: x_put_long (ad, wrd1);
648: ad += 4;
649: x_put_long (ad, wrd2);
650: }
651: break;
652: case 6:
653: x_put_byte (ad, (uae_s8)toint (value, -128.0, 127.0));
654: break;
655: default:
656: return 0;
657: }
658: return 1;
659: }
660:
661: STATIC_INLINE int get_fp_ad (uae_u32 opcode, uae_u32 * ad)
662: {
663: uae_u16 tmp;
664: uaecptr tmppc;
665: int mode;
666: int reg;
667:
668: mode = (opcode >> 3) & 7;
669: reg = opcode & 7;
670: switch (mode) {
671: case 0:
672: case 1:
673: return 0;
674: case 2:
675: *ad = m68k_areg (regs, reg);
676: break;
677: case 3:
678: *ad = m68k_areg (regs, reg);
679: break;
680: case 4:
681: *ad = m68k_areg (regs, reg);
682: break;
683: case 5:
684: *ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) x_next_iword ();
685: break;
686: case 6:
687: *ad = x_get_disp_ea_020 (m68k_areg (regs, reg), x_next_iword ());
688: break;
689: case 7:
690: switch (reg) {
691: case 0:
692: *ad = (uae_s32) (uae_s16) x_next_iword ();
693: break;
694: case 1:
695: *ad = x_next_ilong ();
696: break;
697: case 2:
698: *ad = m68k_getpc ();
699: *ad += (uae_s32) (uae_s16) x_next_iword ();
700: break;
701: case 3:
702: tmppc = m68k_getpc ();
703: tmp = x_next_iword ();
704: *ad = x_get_disp_ea_020 (tmppc, tmp);
705: break;
706: default:
707: return 0;
708: }
709: }
710: return 1;
711: }
712:
713: STATIC_INLINE int fpp_cond (int condition)
714: {
715: int N = (regs.fp_result < 0.0);
716: int Z = (regs.fp_result == 0.0);
717: int NotANumber = 0;
718:
719: #ifdef HAVE_ISNAN
720: NotANumber = isnan (regs.fp_result);
721: #endif
722:
723: if (NotANumber)
724: N=Z=0;
725:
726: switch (condition) {
727: case 0x00:
728: return 0;
729: case 0x01:
730: return Z;
731: case 0x02:
732: return !(NotANumber || Z || N);
733: case 0x03:
734: return Z || !(NotANumber || N);
735: case 0x04:
736: return N && !(NotANumber || Z);
737: case 0x05:
738: return Z || (N && !NotANumber);
739: case 0x06:
740: return !(NotANumber || Z);
741: case 0x07:
742: return !NotANumber;
743: case 0x08:
744: return NotANumber;
745: case 0x09:
746: return NotANumber || Z;
747: case 0x0a:
748: return NotANumber || !(N || Z);
749: case 0x0b:
750: return NotANumber || Z || !N;
751: case 0x0c:
752: return NotANumber || (N && !Z);
753: case 0x0d:
754: return NotANumber || Z || N;
755: case 0x0e:
756: return !Z;
757: case 0x0f:
758: return 1;
759: case 0x10:
760: return 0;
761: case 0x11:
762: return Z;
763: case 0x12:
764: return !(NotANumber || Z || N);
765: case 0x13:
766: return Z || !(NotANumber || N);
767: case 0x14:
768: return N && !(NotANumber || Z);
769: case 0x15:
770: return Z || (N && !NotANumber);
771: case 0x16:
772: return !(NotANumber || Z);
773: case 0x17:
774: return !NotANumber;
775: case 0x18:
776: return NotANumber;
777: case 0x19:
778: return NotANumber || Z;
779: case 0x1a:
780: return NotANumber || !(N || Z);
781: case 0x1b:
782: return NotANumber || Z || !N;
783: case 0x1c:
784: return NotANumber || (N && !Z);
785: case 0x1d:
786: return NotANumber || Z || N;
787: case 0x1e:
788: return !Z;
789: case 0x1f:
790: return 1;
791: }
792: return -1;
793: }
794:
795: void fpuop_dbcc (uae_u32 opcode, uae_u16 extra)
796: {
797: uaecptr pc = (uae_u32) m68k_getpc ();
798: uae_s32 disp;
799: int cc;
800:
801: #if DEBUG_FPP
802: if (!isinrom ())
803: write_log ("fdbcc_opp at %08lx\n", m68k_getpc ());
804: #endif
805: if (fault_if_no_fpu (opcode, 4))
806: return;
807:
808: disp = (uae_s32) (uae_s16) x_next_iword ();
809: cc = fpp_cond (extra & 0x3f);
810: if (cc == -1) {
811: fpu_op_illg (opcode, 4);
812: } else if (!cc) {
813: int reg = opcode & 0x7;
814:
815: m68k_dreg (regs, reg) = ((m68k_dreg (regs, reg) & 0xffff0000)
816: | (((m68k_dreg (regs, reg) & 0xffff) - 1) & 0xffff));
817: if ((m68k_dreg (regs, reg) & 0xffff) != 0xffff)
818: m68k_setpc (pc + disp);
819: }
820: }
821:
822: void fpuop_scc (uae_u32 opcode, uae_u16 extra)
823: {
1.1.1.3 ! root 824: uae_u32 ad = 0;
1.1 root 825: int cc;
826:
827: #if DEBUG_FPP
828: if (!isinrom ())
829: write_log ("fscc_opp at %08lx\n", m68k_getpc ());
830: #endif
831: if (fault_if_no_fpu (opcode, 4))
832: return;
833:
834: cc = fpp_cond (extra & 0x3f);
835: if (cc == -1) {
836: fpu_op_illg (opcode, 4);
837: } else if ((opcode & 0x38) == 0) {
838: m68k_dreg (regs, opcode & 7) = (m68k_dreg (regs, opcode & 7) & ~0xff) | (cc ? 0xff : 0x00);
839: } else {
840: if (get_fp_ad (opcode, &ad) == 0) {
841: m68k_setpc (m68k_getpc () - 4);
842: op_illg (opcode);
843: } else
844: x_put_byte (ad, cc ? 0xff : 0x00);
845: }
846: }
847:
848: void fpuop_trapcc (uae_u32 opcode, uaecptr oldpc, uae_u16 extra)
849: {
850: int cc;
851:
852: #if DEBUG_FPP
853: if (!isinrom ())
854: write_log ("ftrapcc_opp at %08lx\n", m68k_getpc ());
855: #endif
856: if (fault_if_no_fpu (opcode, m68k_getpc() - oldpc))
857: return;
858:
859: cc = fpp_cond (extra & 0x3f);
860: if (cc == -1) {
861: fpu_op_illg (opcode, m68k_getpc () - oldpc);
862: }
863: if (cc)
864: Exception (7, oldpc - 2, M68000_EXC_SRC_CPU);
865: }
866:
867: void fpuop_bcc (uae_u32 opcode, uaecptr pc, uae_u32 extra)
868: {
869: int cc;
870:
871: #if DEBUG_FPP
872: if (!isinrom ())
873: write_log ("fbcc_opp at %08lx\n", m68k_getpc ());
874: #endif
875: if (fault_if_no_fpu (opcode, m68k_getpc () - pc))
876: return;
877:
878: cc = fpp_cond (opcode & 0x3f);
879: if (cc == -1) {
880: fpu_op_illg (opcode, m68k_getpc () - pc);
881: } else if (cc) {
882: if ((opcode & 0x40) == 0)
883: extra = (uae_s32) (uae_s16) extra;
884: m68k_setpc (pc + extra);
885: }
886: }
887:
888: void fpuop_save (uae_u32 opcode)
889: {
1.1.1.3 ! root 890: uae_u32 ad = 0;
1.1 root 891: int incr = (opcode & 0x38) == 0x20 ? -1 : 1;
892: int fpu_version = get_fpu_version();
893: int i;
894:
895: #if DEBUG_FPP
896: if (!isinrom ())
897: write_log ("fsave_opp at %08lx\n", m68k_getpc ());
898: #endif
899: if (fault_if_no_fpu (opcode, 2))
900: return;
901:
902: if (get_fp_ad (opcode, &ad) == 0) {
903: fpu_op_illg (opcode, 2);
904: return;
905: }
906:
907: if (currprefs.fpu_model == 68060) {
908: /* 12 byte 68060 IDLE frame. */
909: if (incr < 0) {
910: ad -= 4;
911: x_put_long (ad, 0x00000000);
912: ad -= 4;
913: x_put_long (ad, 0x00000000);
914: ad -= 4;
915: x_put_long (ad, 0x00006000);
916: } else {
917: x_put_long (ad, 0x00006000);
918: ad += 4;
919: x_put_long (ad, 0x00000000);
920: ad += 4;
921: x_put_long (ad, 0x00000000);
922: ad += 4;
923: }
924: } else if (currprefs.fpu_model == 68040) {
925: /* 4 byte 68040 IDLE frame. */
926: if (incr < 0) {
927: ad -= 4;
928: x_put_long (ad, fpu_version << 24);
929: } else {
930: x_put_long (ad, fpu_version << 24);
931: ad += 4;
932: }
933: } else { /* 68881/68882 */
934: int idle_size = currprefs.fpu_model == 68882 ? 0x38 : 0x18;
935: if (incr < 0) {
936: ad -= 4;
937: x_put_long (ad, 0x70000000);
938: for (i = 0; i < (idle_size - 1) / 4; i++) {
939: ad -= 4;
940: x_put_long (ad, 0x00000000);
941: }
942: ad -= 4;
943: x_put_long (ad, (fpu_version << 24) | (idle_size << 16));
944: } else {
945: x_put_long (ad, (fpu_version << 24) | (idle_size << 16));
946: ad += 4;
947: for (i = 0; i < (idle_size - 1) / 4; i++) {
948: x_put_long (ad, 0x00000000);
949: ad += 4;
950: }
951: x_put_long (ad, 0x70000000);
952: ad += 4;
953: }
954: }
955: if ((opcode & 0x38) == 0x18)
956: m68k_areg (regs, opcode & 7) = ad;
957: if ((opcode & 0x38) == 0x20)
958: m68k_areg (regs, opcode & 7) = ad;
959: }
960:
961: void fpuop_restore (uae_u32 opcode)
962: {
1.1.1.3 ! root 963: uae_u32 ad = 0;
1.1 root 964: uae_u32 d;
965: int incr = (opcode & 0x38) == 0x20 ? -1 : 1;
966:
967: #if DEBUG_FPP
968: if (!isinrom ())
969: write_log ("frestore_opp at %08lx\n", m68k_getpc ());
970: #endif
971: if (fault_if_no_fpu (opcode, 2))
972: return;
973:
974: if (get_fp_ad (opcode, &ad) == 0) {
975: fpu_op_illg (opcode, 2);
976: return;
977: }
978:
979: if (currprefs.fpu_model == 68060) {
980: /* all 68060 FPU frames are 12 bytes */
981: if (incr < 0) {
982: ad -= 4;
983: d = x_get_long (ad);
984: ad -= 8;
985: } else {
986: d = x_get_long (ad);
987: ad += 4;
988: ad += 8;
989: }
990:
991: } else if (currprefs.fpu_model == 68040) {
992: /* 68040 */
993: if (incr < 0) {
994: /* @@@ This may be wrong. */
995: ad -= 4;
996: d = x_get_long (ad);
997: if ((d & 0xff000000) != 0) { /* Not a NULL frame? */
998: if ((d & 0x00ff0000) == 0) { /* IDLE */
999: } else if ((d & 0x00ff0000) == 0x00300000) { /* UNIMP */
1000: ad -= 44;
1001: } else if ((d & 0x00ff0000) == 0x00600000) { /* BUSY */
1002: ad -= 92;
1003: }
1004: }
1005: } else {
1006: d = x_get_long (ad);
1007: ad += 4;
1008: if ((d & 0xff000000) != 0) { /* Not a NULL frame? */
1009: if ((d & 0x00ff0000) == 0) { /* IDLE */
1010: } else if ((d & 0x00ff0000) == 0x00300000) { /* UNIMP */
1011: ad += 44;
1012: } else if ((d & 0x00ff0000) == 0x00600000) { /* BUSY */
1013: ad += 92;
1014: }
1015: }
1016: }
1017: } else { /* 68881/68882 */
1018: if (incr < 0) {
1019: ad -= 4;
1020: d = x_get_long (ad);
1021: if ((d & 0xff000000) != 0) {
1022: if ((d & 0x00ff0000) == 0x00180000)
1023: ad -= 6 * 4;
1024: else if ((d & 0x00ff0000) == 0x00380000)
1025: ad -= 14 * 4;
1026: else if ((d & 0x00ff0000) == 0x00b40000)
1027: ad -= 45 * 4;
1028: }
1029: } else {
1030: d = x_get_long (ad);
1031: ad += 4;
1032: if ((d & 0xff000000) != 0) {
1033: if ((d & 0x00ff0000) == 0x00180000)
1034: ad += 6 * 4;
1035: else if ((d & 0x00ff0000) == 0x00380000)
1036: ad += 14 * 4;
1037: else if ((d & 0x00ff0000) == 0x00b40000)
1038: ad += 45 * 4;
1039: }
1040: }
1041: }
1042: if ((opcode & 0x38) == 0x18)
1043: m68k_areg (regs, opcode & 7) = ad;
1044: if ((opcode & 0x38) == 0x20)
1045: m68k_areg (regs, opcode & 7) = ad;
1046: }
1047:
1048: static void fround (int reg)
1049: {
1050: regs.fp[reg] = (float)regs.fp[reg];
1051: }
1052:
1053: void fpuop_arithmetic (uae_u32 opcode, uae_u16 extra)
1054: {
1055: int reg;
1056: fptype src;
1057:
1058: #if DEBUG_FPP
1059: if (!isinrom ())
1060: write_log ("FPP %04lx %04x at %08lx\n", opcode & 0xffff, extra, m68k_getpc () - 4);
1061: #endif
1062: if (fault_if_no_fpu (opcode, 4))
1063: return;
1064:
1065: switch ((extra >> 13) & 0x7) {
1066:
1067: case 3:
1068: if (put_fp_value (regs.fp[(extra >> 7) & 7], opcode, extra) == 0) {
1069: m68k_setpc (m68k_getpc () - 4);
1070: op_illg (opcode);
1071: }
1072: return;
1073:
1074: case 4:
1075: case 5:
1076: if ((opcode & 0x38) == 0) {
1077: if (extra & 0x2000) {
1078: if (extra & 0x1000)
1079: m68k_dreg (regs, opcode & 7) = regs.fpcr & 0xffff;
1080: if (extra & 0x0800)
1081: m68k_dreg (regs, opcode & 7) = get_fpsr ();
1082: if (extra & 0x0400)
1083: m68k_dreg (regs, opcode & 7) = regs.fpiar;
1084: } else {
1085: if (extra & 0x1000) {
1086: regs.fpcr = m68k_dreg (regs, opcode & 7);
1087: native_set_fpucw (regs.fpcr);
1088: }
1089: if (extra & 0x0800)
1090: set_fpsr (m68k_dreg (regs, opcode & 7));
1091: if (extra & 0x0400)
1092: regs.fpiar = m68k_dreg (regs, opcode & 7);
1093: }
1094: } else if ((opcode & 0x38) == 0x08) {
1095: if (extra & 0x2000) {
1096: if (extra & 0x1000)
1097: m68k_areg (regs, opcode & 7) = regs.fpcr & 0xffff;
1098: if (extra & 0x0800)
1099: m68k_areg (regs, opcode & 7) = get_fpsr ();
1100: if (extra & 0x0400)
1101: m68k_areg (regs, opcode & 7) = regs.fpiar;
1102: } else {
1103: if (extra & 0x1000) {
1104: regs.fpcr = m68k_areg (regs, opcode & 7);
1105: native_set_fpucw (regs.fpcr);
1106: }
1107: if (extra & 0x0800)
1108: set_fpsr (m68k_areg (regs, opcode & 7));
1109: if (extra & 0x0400)
1110: regs.fpiar = m68k_areg (regs, opcode & 7);
1111: }
1112: } else if ((opcode & 0x3f) == 0x3c) {
1113: if ((extra & 0x2000) == 0) {
1114: if (extra & 0x1000) {
1115: regs.fpcr = x_next_ilong ();
1116: native_set_fpucw (regs.fpcr);
1117: }
1118: if (extra & 0x0800)
1119: set_fpsr (x_next_ilong ());
1120: if (extra & 0x0400)
1121: regs.fpiar = x_next_ilong ();
1122: }
1123: } else if (extra & 0x2000) {
1124: /* FMOVEM FPP->memory */
1125: uae_u32 ad;
1126: int incr = 0;
1127:
1128: if (get_fp_ad (opcode, &ad) == 0) {
1129: m68k_setpc (m68k_getpc () - 4);
1130: op_illg (opcode);
1131: return;
1132: }
1133: if ((opcode & 0x38) == 0x20) {
1134: if (extra & 0x1000)
1135: incr += 4;
1136: if (extra & 0x0800)
1137: incr += 4;
1138: if (extra & 0x0400)
1139: incr += 4;
1140: }
1141: ad -= incr;
1142: if (extra & 0x1000) {
1143: x_put_long (ad, regs.fpcr & 0xffff);
1144: ad += 4;
1145: }
1146: if (extra & 0x0800) {
1147: x_put_long (ad, get_fpsr());
1148: ad += 4;
1149: }
1150: if (extra & 0x0400) {
1151: x_put_long (ad, regs.fpiar);
1152: ad += 4;
1153: }
1154: ad -= incr;
1155: if ((opcode & 0x38) == 0x18)
1156: m68k_areg (regs, opcode & 7) = ad;
1157: if ((opcode & 0x38) == 0x20)
1158: m68k_areg (regs, opcode & 7) = ad;
1159: } else {
1160: /* FMOVEM memory->FPP */
1161: uae_u32 ad;
1162: int incr = 0;
1163:
1164: if (get_fp_ad (opcode, &ad) == 0) {
1165: m68k_setpc (m68k_getpc () - 4);
1166: op_illg (opcode);
1167: return;
1168: }
1169: if((opcode & 0x38) == 0x20) {
1170: if (extra & 0x1000)
1171: incr += 4;
1172: if (extra & 0x0800)
1173: incr += 4;
1174: if (extra & 0x0400)
1175: incr += 4;
1176: ad = ad - incr;
1177: }
1178: if (extra & 0x1000) {
1179: regs.fpcr = x_get_long (ad);
1180: native_set_fpucw (regs.fpcr);
1181: ad += 4;
1182: }
1183: if (extra & 0x0800) {
1184: set_fpsr(x_get_long (ad));
1185: ad += 4;
1186: }
1187: if (extra & 0x0400) {
1188: regs.fpiar = x_get_long (ad);
1189: ad += 4;
1190: }
1191: if ((opcode & 0x38) == 0x18)
1192: m68k_areg (regs, opcode & 7) = ad;
1193: if ((opcode & 0x38) == 0x20)
1194: m68k_areg (regs, opcode & 7) = ad - incr;
1195: }
1196: return;
1197:
1198: case 6:
1199: case 7:
1200: {
1201: uae_u32 ad, list = 0;
1202: int incr = 0;
1203: if (extra & 0x2000) {
1204: /* FMOVEM FPP->memory */
1205: if (get_fp_ad (opcode, &ad) == 0) {
1206: m68k_setpc (m68k_getpc () - 4);
1207: op_illg (opcode);
1208: return;
1209: }
1210: switch ((extra >> 11) & 3) {
1211: case 0: /* static pred */
1212: list = extra & 0xff;
1213: incr = -1;
1214: break;
1215: case 1: /* dynamic pred */
1216: list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff;
1217: incr = -1;
1218: break;
1219: case 2: /* static postinc */
1220: list = extra & 0xff;
1221: incr = 1;
1222: break;
1223: case 3: /* dynamic postinc */
1224: list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff;
1225: incr = 1;
1226: break;
1227: }
1228: if (incr < 0) {
1229: for (reg = 7; reg >= 0; reg--) {
1230: uae_u32 wrd1, wrd2, wrd3;
1231: if (list & 0x80) {
1232: from_exten (regs.fp[reg], &wrd1, &wrd2, &wrd3);
1233: ad -= 4;
1234: x_put_long (ad, wrd3);
1235: ad -= 4;
1236: x_put_long (ad, wrd2);
1237: ad -= 4;
1238: x_put_long (ad, wrd1);
1239: }
1240: list <<= 1;
1241: }
1242: } else {
1243: for (reg = 0; reg <= 7; reg++) {
1244: uae_u32 wrd1, wrd2, wrd3;
1245: if (list & 0x80) {
1246: from_exten (regs.fp[reg], &wrd1, &wrd2, &wrd3);
1247: x_put_long (ad, wrd1);
1248: ad += 4;
1249: x_put_long (ad, wrd2);
1250: ad += 4;
1251: x_put_long (ad, wrd3);
1252: ad += 4;
1253: }
1254: list <<= 1;
1255: }
1256: }
1257: if ((opcode & 0x38) == 0x18)
1258: m68k_areg (regs, opcode & 7) = ad;
1259: if ((opcode & 0x38) == 0x20)
1260: m68k_areg (regs, opcode & 7) = ad;
1261: } else {
1262: /* FMOVEM memory->FPP */
1263: if (get_fp_ad (opcode, &ad) == 0) {
1264: m68k_setpc (m68k_getpc () - 4);
1265: op_illg (opcode);
1266: return;
1267: }
1268: switch ((extra >> 11) & 3) {
1269: case 0: /* static pred */
1270: list = extra & 0xff;
1271: incr = -1;
1272: break;
1273: case 1: /* dynamic pred */
1274: list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff;
1275: incr = -1;
1276: break;
1277: case 2: /* static postinc */
1278: list = extra & 0xff;
1279: incr = 1;
1280: break;
1281: case 3: /* dynamic postinc */
1282: list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff;
1283: incr = 1;
1284: break;
1285: }
1286: if (incr < 0) {
1287: for (reg = 7; reg >= 0; reg--) {
1288: uae_u32 wrd1, wrd2, wrd3;
1289: if (list & 0x80) {
1290: ad -= 4;
1291: wrd3 = x_get_long (ad);
1292: ad -= 4;
1293: wrd2 = x_get_long (ad);
1294: ad -= 4;
1295: wrd1 = x_get_long (ad);
1296: regs.fp[reg] = to_exten(wrd1, wrd2, wrd3);
1297: }
1298: list <<= 1;
1299: }
1300: } else {
1301: for (reg = 0; reg <= 7; reg++) {
1302: uae_u32 wrd1, wrd2, wrd3;
1303: if (list & 0x80) {
1304: wrd1 = x_get_long (ad);
1305: ad += 4;
1306: wrd2 = x_get_long (ad);
1307: ad += 4;
1308: wrd3 = x_get_long (ad);
1309: ad += 4;
1310: regs.fp[reg] = to_exten(wrd1, wrd2, wrd3);
1311: }
1312: list <<= 1;
1313: }
1314: }
1315: if ((opcode & 0x38) == 0x18)
1316: m68k_areg (regs, opcode & 7) = ad;
1317: if ((opcode & 0x38) == 0x20)
1318: m68k_areg (regs, opcode & 7) = ad;
1319: }
1320: }
1321: return;
1322:
1323: case 0:
1324: case 2: /* Extremely common */
1325: reg = (extra >> 7) & 7;
1326: if ((extra & 0xfc00) == 0x5c00) {
1327: switch (extra & 0x7f) {
1328: case 0x00:
1329: regs.fp[reg] = *fp_pi;
1330: break;
1331: case 0x0b:
1332: regs.fp[reg] = *fp_l10_2;
1333: break;
1334: case 0x0c:
1335: regs.fp[reg] = *fp_exp_1;
1336: break;
1337: case 0x0d:
1338: regs.fp[reg] = *fp_l2_e;
1339: break;
1340: case 0x0e:
1341: regs.fp[reg] = *fp_l10_e;
1342: break;
1343: case 0x0f:
1344: regs.fp[reg] = 0.0;
1345: break;
1346: case 0x30:
1347: regs.fp[reg] = *fp_ln_2;
1348: break;
1349: case 0x31:
1350: regs.fp[reg] = *fp_ln_10;
1351: break;
1352: case 0x32:
1353: regs.fp[reg] = (fptype)fp_1e0;
1354: break;
1355: case 0x33:
1356: regs.fp[reg] = (fptype)fp_1e1;
1357: break;
1358: case 0x34:
1359: regs.fp[reg] = (fptype)fp_1e2;
1360: break;
1361: case 0x35:
1362: regs.fp[reg] = (fptype)fp_1e4;
1363: break;
1364: case 0x36:
1365: regs.fp[reg] = (fptype)fp_1e8;
1366: break;
1367: case 0x37:
1368: regs.fp[reg] = *fp_1e16;
1369: break;
1370: case 0x38:
1371: regs.fp[reg] = *fp_1e32;
1372: break;
1373: case 0x39:
1374: regs.fp[reg] = *fp_1e64;
1375: break;
1376: case 0x3a:
1377: regs.fp[reg] = *fp_1e128;
1378: break;
1379: case 0x3b:
1380: regs.fp[reg] = *fp_1e256;
1381: break;
1382: case 0x3c:
1383: regs.fp[reg] = *fp_1e512;
1384: break;
1385: case 0x3d:
1386: regs.fp[reg] = *fp_1e1024;
1387: break;
1388: case 0x3e:
1389: regs.fp[reg] = *fp_1e2048;
1390: break;
1391: case 0x3f:
1392: regs.fp[reg] = *fp_1e4096;
1393: break;
1394: default:
1395: m68k_setpc (m68k_getpc () - 4);
1396: op_illg (opcode);
1397: return;
1398: }
1399: MAKE_FPSR (regs.fp[reg]);
1400: return;
1401: }
1402: if (get_fp_value (opcode, extra, &src) == 0) {
1403: m68k_setpc (m68k_getpc () - 4);
1404: op_illg (opcode);
1405: return;
1406: }
1407:
1408: switch (extra & 0x7f) {
1409:
1410: case 0x00: /* FMOVE */
1411: case 0x40: /* Explicit rounding. This is just a quick fix. */
1412: case 0x44: /* Same for all other cases that have three choices */
1413: regs.fp[reg] = src; /* Brian King was here. */
1414: /*<ea> to register needs FPSR updated. See Motorola 68K Manual. */
1415: if ((extra & 0x44) == 0x40)
1416: fround (reg);
1417: break;
1418: case 0x01: /* FINT */
1419: /* need to take the current rounding mode into account */
1420: #if defined(X86_MSVC_ASSEMBLY)
1421: {
1422: fptype tmp_fp;
1423:
1424: __asm {
1425: fld LDPTR src
1426: frndint
1427: fstp LDPTR tmp_fp
1428: }
1429: regs.fp[reg] = tmp_fp;
1430: }
1431: #else /* no X86_MSVC */
1432: switch ((regs.fpcr >> 4) & 3) {
1433: case 0: /* to nearest */
1434: regs.fp[reg] = floor (src + 0.5);
1435: break;
1436: case 1: /* to zero */
1437: if (src >= 0.0)
1438: regs.fp[reg] = floor (src);
1439: else
1440: regs.fp[reg] = ceil (src);
1441: break;
1442: case 2: /* down */
1443: regs.fp[reg] = floor (src);
1444: break;
1445: case 3: /* up */
1446: regs.fp[reg] = ceil (src);
1447: break;
1448: default: /* never reached */
1449: regs.fp[reg] = src;
1450: }
1451: #endif /* X86_MSVC */
1452: break;
1453: case 0x02: /* FSINH */
1454: regs.fp[reg] = sinh (src);
1455: break;
1456: case 0x03: /* FINTRZ */
1457: regs.fp[reg] = fp_round_to_zero(src);
1458: break;
1459: case 0x04: /* FSQRT */
1460: case 0x41:
1461: case 0x45:
1462: regs.fp[reg] = sqrt (src);
1463: if ((extra & 0x44) == 0x40)
1464: fround (reg);
1465: break;
1466: case 0x06: /* FLOGNP1 */
1467: regs.fp[reg] = log (src + 1.0);
1468: break;
1469: case 0x08: /* FETOXM1 */
1470: regs.fp[reg] = exp (src) - 1.0;
1471: break;
1472: case 0x09: /* FTANH */
1473: regs.fp[reg] = tanh (src);
1474: break;
1475: case 0x0a: /* FATAN */
1476: regs.fp[reg] = atan (src);
1477: break;
1478: case 0x0c: /* FASIN */
1479: regs.fp[reg] = asin (src);
1480: break;
1481: case 0x0d: /* FATANH */
1482: #if 1 /* The BeBox doesn't have atanh, and it isn't in the HPUX libm either */
1483: regs.fp[reg] = 0.5 * log ((1 + src) / (1 - src));
1484: #else
1485: regs.fp[reg] = atanh (src);
1486: #endif
1487: break;
1488: case 0x0e: /* FSIN */
1489: regs.fp[reg] = sin (src);
1490: break;
1491: case 0x0f: /* FTAN */
1492: regs.fp[reg] = tan (src);
1493: break;
1494: case 0x10: /* FETOX */
1495: regs.fp[reg] = exp (src);
1496: break;
1497: case 0x11: /* FTWOTOX */
1498: regs.fp[reg] = pow (2.0, src);
1499: break;
1500: case 0x12: /* FTENTOX */
1501: regs.fp[reg] = pow (10.0, src);
1502: break;
1503: case 0x14: /* FLOGN */
1504: regs.fp[reg] = log (src);
1505: break;
1506: case 0x15: /* FLOG10 */
1507: regs.fp[reg] = log10 (src);
1508: break;
1509: case 0x16: /* FLOG2 */
1510: regs.fp[reg] = *fp_l2_e * log (src);
1511: break;
1512: case 0x18: /* FABS */
1513: case 0x58:
1514: case 0x5c:
1515: regs.fp[reg] = src < 0 ? -src : src;
1516: if ((extra & 0x44) == 0x40)
1517: fround (reg);
1518: break;
1519: case 0x19: /* FCOSH */
1520: regs.fp[reg] = cosh (src);
1521: break;
1522: case 0x1a: /* FNEG */
1523: case 0x5a:
1524: case 0x5e:
1525: regs.fp[reg] = -src;
1526: if ((extra & 0x44) == 0x40)
1527: fround (reg);
1528: break;
1529: case 0x1c: /* FACOS */
1530: regs.fp[reg] = acos (src);
1531: break;
1532: case 0x1d: /* FCOS */
1533: regs.fp[reg] = cos (src);
1534: break;
1535: case 0x1e: /* FGETEXP */
1536: {
1537: if (src == 0) {
1538: regs.fp[reg] = 0;
1539: } else {
1540: int expon;
1541: frexp (src, &expon);
1542: regs.fp[reg] = (double) (expon - 1);
1543: }
1544: }
1545: break;
1546: case 0x1f: /* FGETMAN */
1547: {
1548: if (src == 0) {
1549: regs.fp[reg] = 0;
1550: } else {
1551: int expon;
1552: regs.fp[reg] = frexp (src, &expon) * 2.0;
1553: }
1554: }
1555: break;
1556: case 0x20: /* FDIV */
1557: case 0x60:
1558: case 0x64:
1559: regs.fp[reg] /= src;
1560: if ((extra & 0x44) == 0x40)
1561: fround (reg);
1562: break;
1563: case 0x21: /* FMOD */
1564: {
1565: fptype quot = fp_round_to_zero(regs.fp[reg] / src);
1566: regs.fp[reg] = regs.fp[reg] - quot * src;
1567: }
1568: break;
1569: case 0x22: /* FADD */
1570: case 0x62:
1571: case 0x66:
1572: regs.fp[reg] += src;
1573: if ((extra & 0x44) == 0x40)
1574: fround (reg);
1575: break;
1576: case 0x23: /* FMUL */
1577: case 0x63:
1578: case 0x67:
1579: regs.fp[reg] *= src;
1580: if ((extra & 0x44) == 0x40)
1581: fround (reg);
1582: break;
1583: case 0x24: /* FSGLDIV */
1584: regs.fp[reg] /= src;
1585: break;
1586: case 0x25: /* FREM */
1587: {
1588: fptype quot = fp_round_to_nearest(regs.fp[reg] / src);
1589: regs.fp[reg] = regs.fp[reg] - quot * src;
1590: }
1591: break;
1592: case 0x26: /* FSCALE */
1593: if (src != 0) {
1594: #ifdef ldexp
1595: regs.fp[reg] = ldexp (regs.fp[reg], (int) src);
1596: #else
1597: regs.fp[reg] *= exp (*fp_ln_2 * (int) src);
1598: #endif
1599: }
1600: break;
1601: case 0x27: /* FSGLMUL */
1602: regs.fp[reg] *= src;
1603: break;
1604: case 0x28: /* FSUB */
1605: case 0x68:
1606: case 0x6c:
1607: regs.fp[reg] -= src;
1608: if ((extra & 0x44) == 0x40)
1609: fround (reg);
1610: break;
1611: case 0x30: /* FSINCOS */
1612: case 0x31:
1613: case 0x32:
1614: case 0x33:
1615: case 0x34:
1616: case 0x35:
1617: case 0x36:
1618: case 0x37:
1619: regs.fp[extra & 7] = cos (src);
1620: regs.fp[reg] = sin (src);
1621: break;
1622: case 0x38: /* FCMP */
1623: {
1624: fptype tmp = regs.fp[reg] - src;
1625: regs.fpsr = 0;
1626: MAKE_FPSR (tmp);
1627: }
1628: return;
1629: case 0x3a: /* FTST */
1630: regs.fpsr = 0;
1631: MAKE_FPSR (src);
1632: return;
1633: default:
1634: m68k_setpc (m68k_getpc () - 4);
1635: op_illg (opcode);
1636: return;
1637: }
1638: MAKE_FPSR (regs.fp[reg]);
1639: return;
1640: }
1641: m68k_setpc (m68k_getpc () - 4);
1642: op_illg (opcode);
1643: }
1644:
1645: void fpu_reset (void)
1646: {
1647: regs.fpcr = regs.fpsr = regs.fpiar = 0;
1648: regs.fp_result = 1;
1649: fpux_restore (NULL);
1650: }
1651:
1652: uae_u8 *restore_fpu (uae_u8 *src)
1653: {
1654: int i;
1655: uae_u32 flags;
1656:
1657: changed_prefs.fpu_model = currprefs.fpu_model = restore_u32 ();
1658: flags = restore_u32 ();
1659: for (i = 0; i < 8; i++) {
1660: uae_u32 w1 = restore_u32 ();
1661: uae_u32 w2 = restore_u32 ();
1662: uae_u32 w3 = restore_u16 ();
1663: regs.fp[i] = to_exten (w1, w2, w3);
1664: }
1665: regs.fpcr = restore_u32 ();
1666: native_set_fpucw (regs.fpcr);
1667: regs.fpsr = restore_u32 ();
1668: regs.fpiar = restore_u32 ();
1669: if (flags & 0x80000000) {
1670: restore_u32();
1671: restore_u32();
1672: }
1673: write_log ("FPU: %d\n", currprefs.fpu_model);
1674: return src;
1675: }
1676:
1677: uae_u8 *save_fpu (int *len, uae_u8 *dstptr)
1678: {
1679: uae_u8 *dstbak,*dst;
1680: int i;
1681:
1682: *len = 0;
1683: if (currprefs.fpu_model == 0)
1684: return 0;
1685: if (dstptr)
1686: dstbak = dst = dstptr;
1687: else
1688: dstbak = dst = xmalloc (uae_u8, 4+4+8*10+4+4+4+4+4);
1689: save_u32 (currprefs.fpu_model);
1690: save_u32 (0x80000000);
1691: for (i = 0; i < 8; i++) {
1692: uae_u32 w1, w2, w3;
1693: from_exten (regs.fp[i], &w1, &w2, &w3);
1694: save_u32 (w1);
1695: save_u32 (w2);
1696: save_u16 (w3);
1697: }
1698: save_u32 (regs.fpcr);
1699: save_u32 (regs.fpsr);
1700: save_u32 (regs.fpiar);
1701: save_u32 (-1);
1702: save_u32 (0);
1703: *len = dst - dstbak;
1704: return dstbak;
1705: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.