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