|
|
1.1 root 1: /*
2: * UAE - The Un*x Amiga Emulator
3: *
1.1.1.4 root 4: * MC68881/68882/68040/68060 FPU emulation
1.1 root 5: *
6: * Copyright 1996 Herman ten Brugge
7: * Modified 2005 Peter Keunecke
1.1.1.4 root 8: * 68040+ exceptions and more by Toni Wilen
1.1 root 9: */
10:
11: #define __USE_ISOC9X /* We might be able to pick up a NaN */
12:
13: #include <math.h>
14: #include <float.h>
1.1.1.4 root 15: #include <fenv.h>
16:
17: #include "main.h"
18: #include "hatari-glue.h"
19:
1.1 root 20:
21: #include "sysconfig.h"
22: #include "sysdeps.h"
23:
1.1.1.4 root 24: #ifdef _MSC_VER
25: #pragma fenv_access(on)
26: #endif
27:
1.1 root 28: #include "options_cpu.h"
29: #include "memory.h"
1.1.1.5 ! root 30: #include "uae/attributes.h"
! 31: #include "uae/vm.h"
1.1 root 32: #include "custom.h"
33: #include "events.h"
34: #include "newcpu.h"
35: #include "md-fpp.h"
36: #include "savestate.h"
37: #include "cpu_prefetch.h"
38: #include "cpummu.h"
1.1.1.4 root 39: #include "cpummu030.h"
40: //#include "debug.h"
41:
42: #ifdef WITH_SOFTFLOAT
43: #include "softfloatx80.h"
44: #endif
45:
1.1 root 46: #define DEBUG_FPP 0
1.1.1.4 root 47: #define EXCEPTION_FPP 1
1.1 root 48:
49: STATIC_INLINE int isinrom (void)
50: {
51: return (munge24 (m68k_getpc ()) & 0xFFF80000) == 0xF80000 && !currprefs.mmu_model;
52: }
53:
1.1.1.4 root 54: #ifdef WITH_SOFTFLOAT
1.1 root 55: static uae_u32 xhex_pi[] ={0x2168c235, 0xc90fdaa2, 0x4000};
56: uae_u32 xhex_exp_1[] ={0xa2bb4a9a, 0xadf85458, 0x4000};
57: static uae_u32 xhex_l2_e[] ={0x5c17f0bc, 0xb8aa3b29, 0x3fff};
58: static uae_u32 xhex_ln_2[] ={0xd1cf79ac, 0xb17217f7, 0x3ffe};
59: uae_u32 xhex_ln_10[] ={0xaaa8ac17, 0x935d8ddd, 0x4000};
60: uae_u32 xhex_l10_2[] ={0xfbcff798, 0x9a209a84, 0x3ffd};
61: uae_u32 xhex_l10_e[] ={0x37287195, 0xde5bd8a9, 0x3ffd};
62: uae_u32 xhex_1e16[] ={0x04000000, 0x8e1bc9bf, 0x4034};
63: uae_u32 xhex_1e32[] ={0x2b70b59e, 0x9dc5ada8, 0x4069};
64: uae_u32 xhex_1e64[] ={0xffcfa6d5, 0xc2781f49, 0x40d3};
65: uae_u32 xhex_1e128[] ={0x80e98ce0, 0x93ba47c9, 0x41a8};
66: uae_u32 xhex_1e256[] ={0x9df9de8e, 0xaa7eebfb, 0x4351};
67: uae_u32 xhex_1e512[] ={0xa60e91c7, 0xe319a0ae, 0x46a3};
68: uae_u32 xhex_1e1024[]={0x81750c17, 0xc9767586, 0x4d48};
69: uae_u32 xhex_1e2048[]={0xc53d5de5, 0x9e8b3b5d, 0x5a92};
70: uae_u32 xhex_1e4096[]={0x8a20979b, 0xc4605202, 0x7525};
71: static uae_u32 xhex_inf[] ={0x00000000, 0x00000000, 0x7fff};
72: static uae_u32 xhex_nan[] ={0xffffffff, 0xffffffff, 0x7fff};
1.1.1.4 root 73: static uae_u32 xhex_snan[] ={0xffffffff, 0xbfffffff, 0x7fff};
74: #endif
75:
1.1 root 76: #if USE_LONG_DOUBLE
77: static long double *fp_pi = (long double *)xhex_pi;
78: static long double *fp_exp_1 = (long double *)xhex_exp_1;
79: static long double *fp_l2_e = (long double *)xhex_l2_e;
80: static long double *fp_ln_2 = (long double *)xhex_ln_2;
81: static long double *fp_ln_10 = (long double *)xhex_ln_10;
82: static long double *fp_l10_2 = (long double *)xhex_l10_2;
83: static long double *fp_l10_e = (long double *)xhex_l10_e;
84: static long double *fp_1e16 = (long double *)xhex_1e16;
85: static long double *fp_1e32 = (long double *)xhex_1e32;
86: static long double *fp_1e64 = (long double *)xhex_1e64;
87: static long double *fp_1e128 = (long double *)xhex_1e128;
88: static long double *fp_1e256 = (long double *)xhex_1e256;
89: static long double *fp_1e512 = (long double *)xhex_1e512;
90: static long double *fp_1e1024 = (long double *)xhex_1e1024;
91: static long double *fp_1e2048 = (long double *)xhex_1e2048;
92: static long double *fp_1e4096 = (long double *)xhex_1e4096;
1.1.1.4 root 93: //static long double *fp_inf = (long double *)xhex_inf;
1.1 root 94: static long double *fp_nan = (long double *)xhex_nan;
95: #else
96: static uae_u32 dhex_pi[] ={0x54442D18, 0x400921FB};
97: static uae_u32 dhex_exp_1[] ={0x8B145769, 0x4005BF0A};
98: static uae_u32 dhex_l2_e[] ={0x652B82FE, 0x3FF71547};
99: static uae_u32 dhex_ln_2[] ={0xFEFA39EF, 0x3FE62E42};
100: static uae_u32 dhex_ln_10[] ={0xBBB55516, 0x40026BB1};
101: static uae_u32 dhex_l10_2[] ={0x509F79FF, 0x3FD34413};
102: static uae_u32 dhex_l10_e[] ={0x1526E50E, 0x3FDBCB7B};
103: static uae_u32 dhex_1e16[] ={0x37E08000, 0x4341C379};
104: static uae_u32 dhex_1e32[] ={0xB5056E17, 0x4693B8B5};
105: static uae_u32 dhex_1e64[] ={0xE93FF9F5, 0x4D384F03};
106: static uae_u32 dhex_1e128[] ={0xF9301D32, 0x5A827748};
107: static uae_u32 dhex_1e256[] ={0x7F73BF3C, 0x75154FDD};
108: static uae_u32 dhex_inf[] ={0x00000000, 0x7ff00000};
109: static uae_u32 dhex_nan[] ={0xffffffff, 0x7fffffff};
110: static double *fp_pi = (double *)dhex_pi;
111: static double *fp_exp_1 = (double *)dhex_exp_1;
112: static double *fp_l2_e = (double *)dhex_l2_e;
113: static double *fp_ln_2 = (double *)dhex_ln_2;
114: static double *fp_ln_10 = (double *)dhex_ln_10;
115: static double *fp_l10_2 = (double *)dhex_l10_2;
116: static double *fp_l10_e = (double *)dhex_l10_e;
117: static double *fp_1e16 = (double *)dhex_1e16;
118: static double *fp_1e32 = (double *)dhex_1e32;
119: static double *fp_1e64 = (double *)dhex_1e64;
120: static double *fp_1e128 = (double *)dhex_1e128;
121: static double *fp_1e256 = (double *)dhex_1e256;
122: static double *fp_1e512 = (double *)dhex_inf;
123: static double *fp_1e1024 = (double *)dhex_inf;
124: static double *fp_1e2048 = (double *)dhex_inf;
125: static double *fp_1e4096 = (double *)dhex_inf;
1.1.1.4 root 126: //static double *fp_inf = (double *)dhex_inf;
1.1 root 127: static double *fp_nan = (double *)dhex_nan;
128: #endif
129: double fp_1e8 = 1.0e8;
130: float fp_1e0 = 1, fp_1e1 = 10, fp_1e2 = 100, fp_1e4 = 10000;
1.1.1.4 root 131: static bool fpu_mmu_fixup;
1.1 root 132:
133: #define FFLAG_Z 0x4000
134: #define FFLAG_N 0x0100
135: #define FFLAG_NAN 0x0400
136:
137:
1.1.1.4 root 138: #ifdef WITH_SOFTFLOAT
139: static floatx80 fxsizes[6] = { 0 };
140: static floatx80 fxzero;
141: static floatx80 fx_1e0, fx_1e1, fx_1e2, fx_1e4, fx_1e8;
142: struct float_status_t fxstatus;
143: #endif
1.1.1.5 ! root 144: static const fptype fsizes[] = { -128.0, 127.0, -32768.0, 32767.0, -2147483648.0, 2147483647.0 };
1.1.1.4 root 145:
146: #define FP_INEXACT (1 << 9)
147: #define FP_DIVBYZERO (1 << 10)
148: #define FP_UNDERFLOW (1 << 11)
149: #define FP_OVERFLOW (1 << 12)
150: #define FP_OPERAND (1 << 13)
1.1.1.5 ! root 151: #ifndef WINUAE_FOR_HATARI
1.1.1.4 root 152: #define FP_SNAN (1 << 14)
1.1.1.5 ! root 153: #endif
1.1.1.4 root 154: #define FP_BSUN (1 << 15)
155:
156: STATIC_INLINE void MAKE_FPSR (fptype *fp)
1.1 root 157: {
1.1.1.4 root 158: #ifdef WITH_SOFTFLOAT
159: if (currprefs.fpu_softfloat)
160: return;
161: #endif
162: int status = fetestexcept (FE_ALL_EXCEPT);
163: if (status) {
164: if (status & FE_INEXACT)
165: regs.fp_result_status |= FP_INEXACT;
166: if (status & FE_DIVBYZERO)
167: regs.fp_result_status |= FP_DIVBYZERO;
168: if (status & FE_UNDERFLOW)
169: regs.fp_result_status |= FP_UNDERFLOW;
170: if (status & FE_OVERFLOW)
171: regs.fp_result_status |= FP_OVERFLOW;
172: if (status & FE_INVALID)
173: regs.fp_result_status |= FP_OPERAND;
174: }
175: regs.fp_result.fp = *fp;
176: }
177:
178: #ifdef WITH_SOFTFLOAT
179: STATIC_INLINE void MAKE_FPSR_SOFTFLOAT(floatx80 fx)
180: {
181: if (fxstatus.float_exception_flags & float_flag_invalid)
182: regs.fp_result_status |= FP_OPERAND;
183: if (fxstatus.float_exception_flags & float_flag_divbyzero)
184: regs.fp_result_status |= FP_DIVBYZERO;
185: if (fxstatus.float_exception_flags & float_flag_overflow)
186: regs.fp_result_status |= FP_OVERFLOW;
187: if (fxstatus.float_exception_flags & float_flag_underflow)
188: regs.fp_result_status |= FP_UNDERFLOW;
189: if (fxstatus.float_exception_flags & float_flag_inexact)
190: regs.fp_result_status |= FP_INEXACT;
191: regs.fp_result.fpx = fx;
192: }
193: #endif
1.1 root 194:
1.1.1.4 root 195: STATIC_INLINE void CLEAR_STATUS (void)
196: {
197: #ifdef WITH_SOFTFLOAT
198: if (currprefs.fpu_softfloat)
199: return;
200: #endif
201: feclearexcept (FE_ALL_EXCEPT);
202: }
203:
204: #ifdef WITH_SOFTFLOAT
205: static void softfloat_set(floatx80 *fx, uae_u32 *f)
206: {
207: fx->exp = (uae_u16)f[2];
208: fx->fraction = ((uae_u64)f[1] << 32) | f[0];
209: }
210: static void softfloat_get(floatx80 *fx, uae_u32 *f)
211: {
212: f[2] = fx->exp;
213: f[1] = fx->fraction >> 32;
214: f[0] = (uae_u32)fx->fraction;
215: }
1.1 root 216: #endif
1.1.1.4 root 217:
218: static void fpnan (fpdata *fpd)
219: {
220: fpd->fp = *fp_nan;
221: #ifdef WITH_SOFTFLOAT
222: softfloat_set(&fpd->fpx, xhex_nan);
1.1 root 223: #endif
224: }
225:
1.1.1.4 root 226: static void fpclear (fpdata *fpd)
227: {
228: fpd->fp = 0;
229: #ifdef WITH_SOFTFLOAT
230: fpd->fpx = int32_to_floatx80(0);
231: #endif
232: }
233: static void fpset (fpdata *fpd, uae_s32 val)
234: {
235: fpd->fp = (fptype)val;
236: #ifdef WITH_SOFTFLOAT
237: fpd->fpx = int32_to_floatx80(val);
1.1 root 238: #endif
1.1.1.4 root 239: }
1.1 root 240:
1.1.1.4 root 241: void to_single(fpdata *fpd, uae_u32 value)
1.1 root 242: {
1.1.1.4 root 243: #ifdef WITH_SOFTFLOAT
244: if (currprefs.fpu_softfloat) {
245: float32 f = value;
246: fpd->fpx = float32_to_floatx80(f, fxstatus);
247: } else
1.1 root 248: #endif
1.1.1.4 root 249: fpd->fp = to_single_x(value);
250: }
251: static uae_u32 from_single(fpdata *fpd)
252: {
253: #ifdef WITH_SOFTFLOAT
254: if (currprefs.fpu_softfloat) {
255: float32 f = floatx80_to_float32(fpd->fpx, fxstatus);
256: return f;
257: } else
258: #endif
259: return from_single_x(fpd->fp);
260: }
261: void to_double(fpdata *fpd, uae_u32 wrd1, uae_u32 wrd2)
262: {
263: #ifdef WITH_SOFTFLOAT
264: if (currprefs.fpu_softfloat) {
265: float64 f = ((float64)wrd1 << 32) | wrd2;
266: fpd->fpx = float64_to_floatx80(f, fxstatus);
267: } else
268: #endif
269: fpd->fp = to_double_x(wrd1, wrd2);
270: }
271: static void from_double(fpdata *fpd, uae_u32 *wrd1, uae_u32 *wrd2)
272: {
273: #ifdef WITH_SOFTFLOAT
274: if (currprefs.fpu_softfloat) {
275: float64 f = floatx80_to_float64(fpd->fpx, fxstatus);
276: *wrd1 = f >> 32;
277: *wrd2 = (uae_u32)f;
278: return;
279: } else
280: #endif
281: return from_double_x(fpd->fp, wrd1, wrd2);
282: }
283: void to_exten(fpdata *fpd, uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3)
284: {
285: #ifdef WITH_SOFTFLOAT
286: if (currprefs.fpu_softfloat) {
287: fpd->fpx.exp = wrd1 >> 16;
288: fpd->fpx.fraction = ((uae_u64)wrd2 << 32) | wrd3;
289: #if 0
290: if ((currprefs.fpu_model == 68881 || currprefs.fpu_model == 68882) || currprefs.fpu_no_unimplemented) {
291: // automatically fix denormals if 6888x or no implemented emulation
292: Bit64u Sig = extractFloatx80Frac(fpd->fpx);
293: Bit32s Exp = extractFloatx80Exp(fpd->fpx);
294: if (Exp == 0 && Sig != 0)
295: normalizeFloatx80Subnormal(Sig, &Exp, &Sig);
296: }
297: #endif
298: } else
299: #endif
300: to_exten_x(&fpd->fp, wrd1, wrd2, wrd3);
301: }
302: static void from_exten(fpdata *fpd, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3)
303: {
304: #ifdef WITH_SOFTFLOAT
305: if (currprefs.fpu_softfloat) {
306: *wrd1 = fpd->fpx.exp << 16;
307: *wrd2 = fpd->fpx.fraction >> 32;
308: *wrd3 = (uae_u32)fpd->fpx.fraction;
309: } else
310: #endif
311: from_exten_x(fpd->fp, wrd1, wrd2, wrd3);
1.1 root 312: }
313:
1.1.1.4 root 314:
315: #if 0
316: static void normalize(uae_u32 *pwrd1, uae_u32 *pwrd2, uae_u32 *pwrd3)
1.1 root 317: {
1.1.1.4 root 318: uae_u32 wrd1 = *pwrd1;
319: uae_u32 wrd2 = *pwrd2;
320: uae_u32 wrd3 = *pwrd3;
321: int exp = (wrd1 >> 16) & 0x7fff;
322: // Normalize if unnormal.
323: if (exp != 0 && exp != 0x7fff && !(wrd2 & 0x80000000)) {
324: while (!(wrd2 & 0x80000000) && (wrd2 || wrd3)) {
325: wrd2 <<= 1;
326: if (wrd3 & 0x80000000)
327: wrd2 |= 1;
328: wrd3 <<= 1;
329: exp--;
330: }
331: if (exp < 0)
332: exp = 0;
333: if (!wrd2 && !wrd3)
334: exp = 0;
335: *pwrd1 = (wrd1 & 0x80000000) | (exp << 16);
336: *pwrd2 = wrd2;
337: *pwrd3 = wrd3;
1.1 root 338: }
339: }
1.1.1.4 root 340: #endif
1.1 root 341:
1.1.1.4 root 342: static bool fpu_get_constant_fp(fpdata *fp, int cr)
1.1 root 343: {
1.1.1.4 root 344: fptype f;
345: switch (cr & 0x7f)
1.1 root 346: {
1.1.1.4 root 347: case 0x00:
348: f = *fp_pi;
1.1 root 349: break;
1.1.1.4 root 350: case 0x0b:
351: f = *fp_l10_2;
1.1 root 352: break;
1.1.1.4 root 353: case 0x0c:
354: f = *fp_exp_1;
355: break;
356: case 0x0d:
357: f = *fp_l2_e;
358: break;
359: case 0x0e:
360: f = *fp_l10_e;
361: break;
362: case 0x0f:
363: f = 0.0;
364: break;
365: case 0x30:
366: f = *fp_ln_2;
367: break;
368: case 0x31:
369: f = *fp_ln_10;
370: break;
371: case 0x32:
372: f = (fptype)fp_1e0;
373: break;
374: case 0x33:
375: f = (fptype)fp_1e1;
376: break;
377: case 0x34:
378: f = (fptype)fp_1e2;
379: break;
380: case 0x35:
381: f = (fptype)fp_1e4;
382: break;
383: case 0x36:
384: f = (fptype)fp_1e8;
385: break;
386: case 0x37:
387: f = *fp_1e16;
388: break;
389: case 0x38:
390: f = *fp_1e32;
391: break;
392: case 0x39:
393: f = *fp_1e64;
394: break;
395: case 0x3a:
396: f = *fp_1e128;
397: break;
398: case 0x3b:
399: f = *fp_1e256;
400: break;
401: case 0x3c:
402: f = *fp_1e512;
403: break;
404: case 0x3d:
405: f = *fp_1e1024;
406: break;
407: case 0x3e:
408: f = *fp_1e2048;
409: break;
410: case 0x3f:
411: f = *fp_1e4096;
1.1 root 412: break;
1.1.1.4 root 413: default:
414: return false;
1.1 root 415: }
1.1.1.4 root 416: fp->fp = f;
417: return true;
1.1 root 418: }
419:
1.1.1.4 root 420: #ifdef WITH_SOFTFLOAT
421: static bool fpu_get_constant_softfloat(fpdata *fp, int cr)
422: {
423: uae_u32 *f = NULL;
424: floatx80 fx;
425:
426: switch (cr & 0x7f)
1.1 root 427: {
1.1.1.4 root 428: case 0x00:
429: f = xhex_pi;
430: break;
431: case 0x0b:
432: f = xhex_l10_2;
433: break;
434: case 0x0c:
435: f = xhex_exp_1;
436: break;
437: case 0x0d:
438: f = xhex_l2_e;
439: break;
440: case 0x0e:
441: f = xhex_l10_e;
442: break;
443: case 0x0f:
444: fx = fxzero;
445: break;
446: case 0x30:
447: f = xhex_ln_2;
448: break;
449: case 0x31:
450: f = xhex_ln_10;
451: break;
452: case 0x32:
453: fx = fx_1e0;
454: break;
455: case 0x33:
456: fx = fx_1e1;
457: break;
458: case 0x34:
459: fx = fx_1e2;
460: break;
461: case 0x35:
462: fx = fx_1e4;
463: break;
464: case 0x36:
465: fx = fx_1e8;
466: break;
467: case 0x37:
468: f = xhex_1e16;
469: break;
470: case 0x38:
471: f = xhex_1e32;
472: break;
473: case 0x39:
474: f = xhex_1e64;
475: break;
476: case 0x3a:
477: f = xhex_1e128;
478: break;
479: case 0x3b:
480: f = xhex_1e256;
481: break;
482: case 0x3c:
483: f = xhex_1e512;
484: break;
485: case 0x3d:
486: f = xhex_1e1024;
487: break;
488: case 0x3e:
489: f = xhex_1e2048;
490: break;
491: case 0x3f:
492: f = xhex_1e4096;
493: break;
494: default:
495: return false;
1.1 root 496: }
1.1.1.4 root 497: if (f)
498: softfloat_set(&fp->fpx, f);
499: else
500: fp->fpx = fx;
501: return true;
502: }
503: #endif
504:
505: bool fpu_get_constant(fpdata *fp, int cr)
506: {
507: #ifdef WITH_SOFTFLOAT
508: if (currprefs.fpu_softfloat)
509: return fpu_get_constant_softfloat(fp, cr);
510: #endif
511: return fpu_get_constant_fp(fp, cr);
512: }
513:
514: #ifdef WITH_SOFTFLOAT
1.1.1.5 ! root 515:
! 516: static inline void set_fpucw_softfloat(uae_u32 m68k_cw)
! 517: {
! 518: switch((m68k_cw >> 6) & 3) {
! 519: case 0: // X
! 520: default: // undefined
! 521: fxstatus.float_rounding_precision = 80;
! 522: break;
! 523: case 1: // S
! 524: fxstatus.float_rounding_precision = 32;
! 525: break;
! 526: case 2: // D
! 527: fxstatus.float_rounding_precision = 64;
! 528: break;
! 529: }
! 530: switch((m68k_cw >> 4) & 3) {
! 531: case 0: // to neareset
! 532: fxstatus.float_rounding_precision = float_round_nearest_even;
! 533: break;
! 534: case 1: // to zero
! 535: fxstatus.float_rounding_mode = float_round_to_zero;
! 536: break;
! 537: case 2: // to minus
! 538: fxstatus.float_rounding_mode = float_round_down;
! 539: break;
! 540: case 3: // to plus
! 541: fxstatus.float_rounding_mode = float_round_up;
! 542: break;
! 543: }
! 544: return;
! 545: }
! 546:
! 547: #endif /* WITH_SOFTFLOAT */
! 548:
! 549: #ifndef WINUAE_FOR_HATARI
! 550: // TODO [NP] enable this part later for faster fpu (need vm.cpp and mmap.cpp too)
! 551: #if defined(CPU_i386) || defined(CPU_x86_64)
! 552:
! 553: /* The main motivation for dynamically creating an x86(-64) function in
! 554: * memory is because MSVC (x64) does not allow you to use inline assembly,
! 555: * and the x86-64 versions of _control87/_controlfp functions only modifies
! 556: * SSE2 registers. */
! 557:
! 558: static uae_u16 x87_cw = 0;
! 559: static uae_u8 *x87_fldcw_code = NULL;
! 560: typedef void (uae_cdecl *x87_fldcw_function)(void);
! 561:
! 562: static void init_fpucw_x87(void)
! 563: {
! 564: if (x87_fldcw_code) {
! 565: return;
! 566: }
! 567: x87_fldcw_code = (uae_u8 *) uae_vm_alloc(
! 568: uae_vm_page_size(), UAE_VM_32BIT, UAE_VM_READ_WRITE_EXECUTE);
! 569: uae_u8 *c = x87_fldcw_code;
! 570: /* mov eax,0x0 */
! 571: *(c++) = 0xb8;
! 572: *(c++) = 0x00;
! 573: *(c++) = 0x00;
! 574: *(c++) = 0x00;
! 575: *(c++) = 0x00;
! 576: #ifdef CPU_x86_64
! 577: /* Address override prefix */
! 578: *(c++) = 0x67;
! 579: #endif
! 580: /* fldcw WORD PTR [eax+addr] */
! 581: *(c++) = 0xd9;
! 582: *(c++) = 0xa8;
! 583: *(c++) = (((uintptr_t) &x87_cw) ) & 0xff;
! 584: *(c++) = (((uintptr_t) &x87_cw) >> 8) & 0xff;
! 585: *(c++) = (((uintptr_t) &x87_cw) >> 16) & 0xff;
! 586: *(c++) = (((uintptr_t) &x87_cw) >> 24) & 0xff;
! 587: /* ret */
! 588: *(c++) = 0xc3;
! 589: /* Write-protect the function */
! 590: uae_vm_protect(x87_fldcw_code, uae_vm_page_size(), UAE_VM_READ_EXECUTE);
! 591: }
! 592:
! 593: static inline void set_fpucw_x87(uae_u32 m68k_cw)
! 594: {
! 595: #ifdef _MSC_VER
! 596: static int ex = 0;
! 597: // RN, RZ, RM, RP
! 598: static const unsigned int fp87_round[4] = { _RC_NEAR, _RC_CHOP, _RC_DOWN, _RC_UP };
! 599: // Extend X, Single S, Double D, Undefined
! 600: static const unsigned int fp87_prec[4] = { _PC_64, _PC_24, _PC_53, 0 };
! 601: int round = (m68k_cw >> 4) & 3;
1.1.1.4 root 602: #ifdef WIN64
1.1.1.5 ! root 603: // x64 only sets SSE2, must also call x87_fldcw_code() to set FPU rounding mode.
! 604: _controlfp(ex | fp87_round[round], _MCW_RC);
1.1.1.4 root 605: #else
1.1.1.5 ! root 606: int prec = (m68k_cw >> 6) & 3;
! 607: // x86 sets both FPU and SSE2 rounding mode, don't need x87_fldcw_code()
! 608: _control87(ex | fp87_round[round] | fp87_prec[prec], _MCW_RC | _MCW_PC);
! 609: return;
! 610: #endif
1.1 root 611: #endif
1.1.1.4 root 612: static const uae_u16 x87_cw_tab[] = {
613: 0x137f, 0x1f7f, 0x177f, 0x1b7f, /* Extended */
614: 0x107f, 0x1c7f, 0x147f, 0x187f, /* Single */
615: 0x127f, 0x1e7f, 0x167f, 0x1a7f, /* Double */
616: 0x137f, 0x1f7f, 0x177f, 0x1b7f /* undefined */
617: };
1.1.1.5 ! root 618: x87_cw = x87_cw_tab[(m68k_cw >> 4) & 0xf];
! 619: #if defined(X86_MSVC_ASSEMBLY) && 0
! 620: __asm { fldcw word ptr x87_cw }
! 621: #elif defined(__GNUC__) && 0
! 622: __asm__("fldcw %0" : : "m" (*&x87_cw));
! 623: #else
! 624: ((x87_fldcw_function) x87_fldcw_code)();
1.1.1.4 root 625: #endif
1.1.1.5 ! root 626: }
! 627:
! 628: #endif /* defined(CPU_i386) || defined(CPU_x86_64) */
! 629: #endif /* ! WINUAE_FOR_HATARI */
! 630:
! 631: static void native_set_fpucw(uae_u32 m68k_cw)
! 632: {
! 633: #ifdef WITH_SOFTFLOAT
! 634: if (currprefs.fpu_softfloat) {
! 635: set_fpucw_softfloat(m68k_cw);
! 636: }
1.1 root 637: #endif
1.1.1.5 ! root 638: #ifndef WINUAE_FOR_HATARI
! 639: #if defined(CPU_i386) || defined(CPU_x86_64)
! 640: set_fpucw_x87(m68k_cw);
1.1 root 641: #endif
1.1.1.5 ! root 642: #endif /* ! WINUAE_FOR_HATARI */
1.1 root 643: }
644:
1.1.1.4 root 645: typedef uae_s64 tointtype;
1.1 root 646:
1.1.1.4 root 647: /*
648: static void fpu_format_error (void)
1.1 root 649: {
1.1.1.4 root 650: uaecptr newpc;
651: regs.t0 = regs.t1 = 0;
652: MakeSR ();
653: if (!regs.s) {
654: regs.usp = m68k_areg (regs, 7);
655: m68k_areg (regs, 7) = regs.isp;
656: }
657: regs.s = 1;
658: m68k_areg (regs, 7) -= 2;
659: x_put_long (m68k_areg (regs, 7), 0x0000 + 14 * 4);
660: m68k_areg (regs, 7) -= 4;
661: x_put_long (m68k_areg (regs, 7), m68k_getpc ());
662: m68k_areg (regs, 7) -= 2;
663: x_put_long (m68k_areg (regs, 7), regs.sr);
664: newpc = x_get_long (regs.vbr + 14 * 4);
665: m68k_setpc (newpc);
666: #ifdef JIT
667: set_special (SPCFLAG_END_COMPILE);
1.1.1.2 root 668: #endif
1.1.1.4 root 669: regs.fp_exception = true;
1.1 root 670: }
1.1.1.4 root 671: */
1.1 root 672:
1.1.1.4 root 673: #define FPU_EXP_UNIMP_INS 0
674: #define FPU_EXP_DISABLED 1
675: #define FPU_EXP_UNIMP_DATATYPE_PRE 2
676: #define FPU_EXP_UNIMP_DATATYPE_POST 3
677: #define FPU_EXP_UNIMP_DATATYPE_PACKED_PRE 4
678: #define FPU_EXP_UNIMP_DATATYPE_PACKED_POST 5
679: #define FPU_EXP_UNIMP_EA 6
680:
681:
682: static void fpu_op_unimp (uae_u16 opcode, uae_u16 extra, uae_u32 ea, uaecptr oldpc, int type, fpdata *src, int reg, int size)
683: {
684: /* 68040 unimplemented/68060 FPU disabled exception.
685: * Line F exception with different stack frame.. */
686: int vector = 11;
687: uaecptr newpc = m68k_getpc (); // next instruction
688: static int warned = 20;
689:
690: regs.t0 = regs.t1 = 0;
691: MakeSR ();
692: if (!regs.s) {
693: regs.usp = m68k_areg (regs, 7);
694: if (currprefs.cpu_model == 68060) {
695: m68k_areg (regs, 7) = regs.isp;
696: } else if (currprefs.cpu_model >= 68020) {
697: m68k_areg (regs, 7) = regs.m ? regs.msp : regs.isp;
698: } else {
699: m68k_areg (regs, 7) = regs.isp;
700: }
701: regs.s = 1;
702: if (currprefs.mmu_model)
703: mmu_set_super (regs.s != 0);
704: }
705: regs.fpu_exp_state = 1;
706: if (currprefs.cpu_model == 68060) {
707: regs.fpiar = oldpc;
708: regs.exp_extra = extra;
709: regs.exp_opcode = opcode;
710: regs.exp_size = size;
711: if (src)
712: regs.exp_src1 = *src;
713: regs.exp_type = type;
714: if (type == FPU_EXP_DISABLED) {
715: // current PC
716: newpc = oldpc;
717: m68k_areg (regs, 7) -= 4;
718: x_put_long (m68k_areg (regs, 7), oldpc);
719: m68k_areg (regs, 7) -= 4;
720: x_put_long (m68k_areg (regs, 7), ea);
721: m68k_areg (regs, 7) -= 2;
722: x_put_word (m68k_areg (regs, 7), 0x4000 + vector * 4);
723: } else if (type == FPU_EXP_UNIMP_INS) {
724: // PC = next instruction
725: m68k_areg (regs, 7) -= 4;
726: x_put_long (m68k_areg (regs, 7), ea);
727: m68k_areg (regs, 7) -= 2;
728: x_put_word (m68k_areg (regs, 7), 0x2000 + vector * 4);
729: } else if (type == FPU_EXP_UNIMP_DATATYPE_PACKED_PRE || type == FPU_EXP_UNIMP_DATATYPE_PACKED_POST || type == FPU_EXP_UNIMP_DATATYPE_PRE || type == FPU_EXP_UNIMP_DATATYPE_POST) {
730: regs.fpu_exp_state = 2; // EXC frame
731: // PC = next instruction
732: vector = 55;
733: m68k_areg (regs, 7) -= 4;
734: x_put_long (m68k_areg (regs, 7), ea);
735: m68k_areg (regs, 7) -= 2;
736: x_put_word (m68k_areg (regs, 7), 0x2000 + vector * 4);
737: } else { // FPU_EXP_UNIMP_EA
738: // current PC
739: newpc = oldpc;
740: vector = 60;
741: m68k_areg (regs, 7) -= 2;
742: x_put_word (m68k_areg (regs, 7), 0x0000 + vector * 4);
743: }
744: } else if (currprefs.cpu_model == 68040) {
745: regs.fpiar = oldpc;
746: regs.exp_extra = extra;
747: regs.exp_opcode = opcode;
748: regs.exp_size = size;
749: if (src)
750: regs.exp_src1 = *src;
751: regs.exp_type = type;
752: if (reg >= 0)
753: regs.exp_src2 = regs.fp[reg];
754: else
755: fpclear (®s.exp_src2);
756: if (type == FPU_EXP_UNIMP_INS || type == FPU_EXP_DISABLED) {
757: // PC = next instruction
758: m68k_areg (regs, 7) -= 4;
759: x_put_long (m68k_areg (regs, 7), ea);
760: m68k_areg (regs, 7) -= 2;
761: x_put_word (m68k_areg (regs, 7), 0x2000 + vector * 4);
762: } else if (type == FPU_EXP_UNIMP_DATATYPE_PACKED_PRE || type == FPU_EXP_UNIMP_DATATYPE_PACKED_POST || type == FPU_EXP_UNIMP_DATATYPE_PRE || type == FPU_EXP_UNIMP_DATATYPE_POST) {
763: // PC = next instruction
764: vector = 55;
765: m68k_areg (regs, 7) -= 4;
766: x_put_long (m68k_areg (regs, 7), ea);
767: m68k_areg (regs, 7) -= 2;
768: x_put_word (m68k_areg (regs, 7), 0x2000 + vector * 4);
769: regs.fpu_exp_state = 2; // BUSY frame
770: }
771: }
772: oldpc = newpc;
773: m68k_areg (regs, 7) -= 4;
774: x_put_long (m68k_areg (regs, 7), newpc);
775: m68k_areg (regs, 7) -= 2;
776: x_put_word (m68k_areg (regs, 7), regs.sr);
777: newpc = x_get_long (regs.vbr + vector * 4);
778: if (warned > 0) {
779: write_log (_T("FPU EXCEPTION %d OP=%04X-%04X EA=%08X PC=%08X -> %08X\n"), type, opcode, extra, ea, oldpc, newpc);
780: #if EXCEPTION_FPP == 0
781: warned--;
782: #endif
783: }
784: regs.fp_exception = true;
785: m68k_setpc (newpc);
786: #ifdef JIT
787: set_special (SPCFLAG_END_COMPILE);
788: #endif
789: }
790:
791: static void fpu_op_illg2 (uae_u16 opcode, uae_u16 extra, uae_u32 ea, uaecptr oldpc)
792: {
793: if ((currprefs.cpu_model == 68060 && (currprefs.fpu_model == 0 || (regs.pcr & 2)))
794: || (currprefs.cpu_model == 68040 && currprefs.fpu_model == 0)) {
795: fpu_op_unimp (opcode, extra, ea, oldpc, FPU_EXP_DISABLED, NULL, -1, -1);
796: return;
797: }
798: regs.fp_exception = true;
799: m68k_setpc (oldpc);
800: op_illg (opcode);
801: }
802:
803: static void fpu_op_illg (uae_u16 opcode, uae_u16 extra, uaecptr oldpc)
804: {
805: fpu_op_illg2 (opcode, extra, 0, oldpc);
806: }
807:
808:
809: static void fpu_noinst (uae_u16 opcode, uaecptr pc)
810: {
811: #if EXCEPTION_FPP
812: write_log (_T("Unknown FPU instruction %04X %08X\n"), opcode, pc);
813: #endif
814: regs.fp_exception = true;
815: m68k_setpc (pc);
816: op_illg (opcode);
817: }
818:
819: static bool fault_if_no_fpu (uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc)
820: {
821: if ((regs.pcr & 2) || currprefs.fpu_model <= 0) {
822: #if EXCEPTION_FPP
823: write_log (_T("no FPU: %04X-%04X PC=%08X\n"), opcode, extra, oldpc);
824: #endif
825: fpu_op_illg2 (opcode, extra, ea, oldpc);
826: return true;
827: }
828: return false;
829: }
830:
831: static bool fault_if_unimplemented_680x0 (uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc, fpdata *src, int reg)
832: {
833: if (fault_if_no_fpu (opcode, extra, ea, oldpc))
834: return true;
835: if (currprefs.cpu_model >= 68040 && currprefs.fpu_model && currprefs.fpu_no_unimplemented) {
836: if ((extra & (0x8000 | 0x2000)) != 0)
837: return false;
838: if ((extra & 0xfc00) == 0x5c00) {
839: // FMOVECR
840: fpu_op_unimp (opcode, extra, ea, oldpc, FPU_EXP_UNIMP_INS, src, reg, -1);
841: return true;
842: }
843: uae_u16 v = extra & 0x7f;
844: switch (v)
845: {
846: case 0x01: /* FINT */
847: case 0x03: /* FINTRZ */
848: // Unimplemented only in 68040.
849: if (currprefs.cpu_model == 68040) {
850: fpu_op_unimp (opcode, extra, ea, oldpc, FPU_EXP_UNIMP_INS, src, reg, -1);
851: return true;
852: }
853: return false;
854: case 0x02: /* FSINH */
855: case 0x06: /* FLOGNP1 */
856: case 0x08: /* FETOXM1 */
857: case 0x09: /* FTANH */
858: case 0x0a: /* FATAN */
859: case 0x0c: /* FASIN */
860: case 0x0d: /* FATANH */
861: case 0x0e: /* FSIN */
862: case 0x0f: /* FTAN */
863: case 0x10: /* FETOX */
864: case 0x11: /* FTWOTOX */
865: case 0x12: /* FTENTOX */
866: case 0x14: /* FLOGN */
867: case 0x15: /* FLOG10 */
868: case 0x16: /* FLOG2 */
869: case 0x19: /* FCOSH */
870: case 0x1c: /* FACOS */
871: case 0x1d: /* FCOS */
872: case 0x1e: /* FGETEXP */
873: case 0x1f: /* FGETMAN */
874: case 0x30: /* FSINCOS */
875: case 0x31: /* FSINCOS */
876: case 0x32: /* FSINCOS */
877: case 0x33: /* FSINCOS */
878: case 0x34: /* FSINCOS */
879: case 0x35: /* FSINCOS */
880: case 0x36: /* FSINCOS */
881: case 0x37: /* FSINCOS */
882: case 0x21: /* FMOD */
883: case 0x25: /* FREM */
884: case 0x26: /* FSCALE */
885: fpu_op_unimp (opcode, extra, ea, oldpc, FPU_EXP_UNIMP_INS, src, reg, -1);
886: return true;
887: }
888: }
889: return false;
890: }
891:
892: static bool fault_if_unimplemented_6888x (uae_u16 opcode, uae_u16 extra, uaecptr oldpc)
893: {
894: if ((currprefs.fpu_model == 68881 || currprefs.fpu_model == 68882) && currprefs.fpu_no_unimplemented) {
895: uae_u16 v = extra & 0x7f;
896: /* 68040/68060 only variants. 6888x = F-line exception. */
897: switch (v)
898: {
899: case 0x62: /* FSADD */
900: case 0x66: /* FDADD */
901: case 0x68: /* FSSUB */
902: case 0x6c: /* FDSUB */
903: case 0x5a: /* FSNEG */
904: case 0x5e: /* FDNEG */
905: case 0x58: /* FSABS */
906: case 0x5c: /* FDABS */
907: case 0x63: /* FSMUL */
908: case 0x67: /* FDMUL */
909: case 0x41: /* FSSQRT */
910: case 0x45: /* FDSQRT */
911: fpu_noinst (opcode, oldpc);
912: return true;
913: }
914: }
915: return false;
916: }
917:
918: static bool fault_if_60 (uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc, int type)
919: {
920: if (currprefs.cpu_model == 68060 && currprefs.fpu_model && currprefs.fpu_no_unimplemented) {
921: fpu_op_unimp (opcode, extra, ea, oldpc, type, NULL, -1, -1);
922: return true;
923: }
924: return false;
925: }
926:
927: static bool fault_if_4060 (uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc, int type, fpdata *src, uae_u32 *pack)
928: {
929: if (currprefs.cpu_model >= 68040 && currprefs.fpu_model && currprefs.fpu_no_unimplemented) {
930: if (pack) {
931: regs.exp_pack[0] = pack[0];
932: regs.exp_pack[1] = pack[1];
933: regs.exp_pack[2] = pack[2];
934: }
935: fpu_op_unimp (opcode, extra, ea, oldpc, type, src, -1, -1);
936: return true;
937: }
938: return false;
939: }
940:
941: static bool fault_if_no_fpu_u (uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc)
942: {
943: if (fault_if_no_fpu (opcode, extra, ea, oldpc))
944: return true;
945: if (currprefs.cpu_model == 68060 && currprefs.fpu_model && currprefs.fpu_no_unimplemented) {
946: // 68060 FTRAP, FDBcc or FScc are not implemented.
947: fpu_op_unimp (opcode, extra, ea, oldpc, FPU_EXP_UNIMP_INS, NULL, -1, -1);
948: return true;
949: }
950: return false;
951: }
952:
953: static bool fault_if_no_6888x (uae_u16 opcode, uae_u16 extra, uaecptr oldpc)
954: {
955: if (currprefs.cpu_model < 68040 && currprefs.fpu_model <= 0) {
956: #if EXCEPTION_FPP
957: write_log (_T("6888x no FPU: %04X-%04X PC=%08X\n"), opcode, extra, oldpc);
958: #endif
959: m68k_setpc (oldpc);
960: regs.fp_exception = true;
961: op_illg (opcode);
962: return true;
963: }
964: return false;
965: }
966:
967: static int get_fpu_version (void)
968: {
969: int v = 0;
970:
971: switch (currprefs.fpu_model)
972: {
973: case 68881:
974: case 68882:
975: v = 0x1f;
976: break;
977: case 68040:
978: if (currprefs.fpu_revision == 0x40)
979: v = 0x40;
980: else
981: v = 0x41;
982: break;
983: }
984: return v;
985: }
986:
987: static void fpu_null (void)
1.1 root 988: {
989: int i;
1.1.1.4 root 990: regs.fpu_state = 0;
991: regs.fpu_exp_state = 0;
992: regs.fpcr = 0;
993: regs.fpsr = 0;
994: regs.fpiar = 0;
995: fpclear (®s.fp_result);
996: for (i = 0; i < 8; i++)
997: fpnan (®s.fp[i]);
998: }
999:
1000: #define fp_round_to_minus_infinity(x) floor(x)
1001: #define fp_round_to_plus_infinity(x) ceil(x)
1002: #define fp_round_to_zero(x) ((x) >= 0.0 ? floor(x) : ceil(x))
1003: #define fp_round_to_nearest(x) ((x) >= 0.0 ? (int)((x) + 0.5) : (int)((x) - 0.5))
1004:
1005: static tointtype toint(fpdata *src, int size)
1006: {
1007: #ifdef WITH_SOFTFLOAT
1008: if (currprefs.fpu_softfloat) {
1009: if (floatx80_compare(src->fpx, fxsizes[size * 2 + 0], fxstatus) == float_relation_greater)
1.1.1.5 ! root 1010: return floatx80_to_int32(fxsizes[size * 2 + 0], fxstatus);
1.1.1.4 root 1011: if (floatx80_compare(src->fpx, fxsizes[size * 2 + 1], fxstatus) == float_relation_less)
1012: return floatx80_to_int32(fxsizes[size * 2 + 1], fxstatus);
1013: return floatx80_to_int32(src->fpx, fxstatus);
1014: } else
1015: #endif
1016: {
1017: fptype fp = src->fp;
1018: if (fp < fsizes[size * 2 + 0])
1019: fp = fsizes[size * 2 + 0];
1020: if (fp > fsizes[size * 2 + 1])
1021: fp = fsizes[size * 2 + 1];
1022: #if defined(X86_MSVC_ASSEMBLY_FPU)
1023: {
1024: fptype tmp_fp;
1025: __asm {
1026: fld LDPTR fp
1027: frndint
1028: fstp LDPTR tmp_fp
1029: }
1030: return (tointtype)tmp_fp;
1031: }
1032: #else /* no X86_MSVC */
1033: {
1034: int result = (int)fp;
1035: switch (regs.fpcr & 0x30)
1036: {
1037: case FPCR_ROUND_ZERO:
1.1.1.5 ! root 1038: result = fp_round_to_zero (fp);
1.1.1.4 root 1039: break;
1040: case FPCR_ROUND_MINF:
1.1.1.5 ! root 1041: result = fp_round_to_minus_infinity (fp);
1.1.1.4 root 1042: break;
1043: case FPCR_ROUND_NEAR:
1044: result = fp_round_to_nearest (fp);
1045: break;
1046: case FPCR_ROUND_PINF:
1.1.1.5 ! root 1047: result = fp_round_to_plus_infinity (fp);
1.1.1.4 root 1048: break;
1049: }
1050: return result;
1051: }
1052: #endif
1053: }
1054: }
1055:
1056: static bool fp_is_snan(fpdata *fpd)
1057: {
1058: #ifdef WITH_SOFTFLOAT
1059: if (currprefs.fpu_softfloat)
1060: return floatx80_is_signaling_nan(fpd->fpx) != 0;
1061: #endif
1062: return false;
1063: }
1064: static bool fp_is_nan (fpdata *fpd)
1065: {
1066: #ifdef WITH_SOFTFLOAT
1067: if (currprefs.fpu_softfloat)
1068: return floatx80_is_nan(fpd->fpx) != 0;
1069: #endif
1070: #ifdef HAVE_ISNAN
1071: return isnan(fpd->fp) != 0;
1072: #else
1073: return false;
1074: #endif
1075: }
1076: static bool fp_is_infinity (fpdata *fpd)
1077: {
1078: #ifdef WITH_SOFTFLOAT
1079: if (currprefs.fpu_softfloat) {
1080: float_class_t fc = floatx80_class(fpd->fpx);
1081: return fc == float_negative_inf || fc == float_positive_inf;
1082: }
1083: #endif
1084: #ifdef _MSC_VER
1085: return !_finite (fpd->fp);
1086: #elif defined(HAVE_ISINF)
1.1.1.5 ! root 1087: return isinf(fpd->fp);
1.1.1.4 root 1088: #else
1089: return false;
1090: #endif
1091: }
1092: static bool fp_is_zero(fpdata *fpd)
1093: {
1094: #ifdef WITH_SOFTFLOAT
1095: if (currprefs.fpu_softfloat)
1096: return floatx80_compare_quiet(fpd->fpx, fxzero, fxstatus) == float_relation_equal;
1097: #endif
1098: return fpd->fp == 0.0;
1099: }
1100: static bool fp_is_neg(fpdata *fpd)
1101: {
1102: #ifdef WITH_SOFTFLOAT
1103: if (currprefs.fpu_softfloat)
1104: return extractFloatx80Sign(fpd->fpx) != 0;
1105: #endif
1106: return fpd->fp < 0.0;
1107: }
1108:
1109: uae_u32 fpp_get_fpsr (void)
1110: {
1111: uae_u32 answer = regs.fpsr & 0x00ff00f8;
1112:
1113: // exception status byte
1114: answer |= regs.fp_result_status;
1115: if (fp_is_snan(®s.fp_result))
1116: answer |= 1 << 14;
1117:
1118: // accrued exception byte
1119: if (answer & ((1 << 14) | (1 << 13)))
1120: answer |= 0x80; // IOP = SNAN | OPERR
1121: if (answer & (1 << 12))
1122: answer |= 0x40; // OVFL = OVFL
1123: if (answer & ((1 << 11) | (1 << 9)))
1124: answer |= 0x20; // UNFL = UNFL | INEX2
1125: if (answer & (1 << 10))
1126: answer |= 0x10; // DZ = DZ
1127: if (answer & ((1 << 12) | (1 << 9) | (1 << 8)))
1.1.1.5 ! root 1128: answer |= 0x08; // INEX = INEX1 | INEX2 | OVFL
1.1.1.4 root 1129:
1130: regs.fpsr = answer;
1131:
1132: // condition code byte
1133: if (fp_is_nan (®s.fp_result)) {
1134: answer |= 1 << 24;
1135: } else {
1136: if (fp_is_zero(®s.fp_result))
1137: answer |= 1 << 26;
1138: if (fp_is_infinity (®s.fp_result))
1139: answer |= 1 << 25;
1140: }
1141: if (fp_is_neg(®s.fp_result))
1142: answer |= 1 << 27;
1143: return answer;
1144: }
1145:
1146: static void update_fpsr (uae_u32 v)
1147: {
1148: regs.fp_result_status = v;
1149: fpp_get_fpsr ();
1150: }
1151:
1152: STATIC_INLINE void set_fpsr (uae_u32 x)
1153: {
1154: regs.fpsr = x;
1155: regs.fp_result_status = 0;
1156:
1157: if (x & 0x01000000)
1158: fpnan (®s.fp_result);
1159: else if (x & 0x04000000)
1160: fpset (®s.fp_result, 0);
1161: else if (x & 0x08000000)
1162: fpset (®s.fp_result, -1);
1163: else
1164: fpset (®s.fp_result, 1);
1165: }
1166:
1167: static uae_u32 get_ftag (uae_u32 w1, uae_u32 w2, uae_u32 w3, int size)
1168: {
1169: int exp = (w1 >> 16) & 0x7fff;
1170:
1171: if (exp == 0) {
1172: if (!w2 && !w3)
1173: return 1; // ZERO
1174: if (size == 0 || size == 1)
1175: return 5; // Single/double DENORMAL
1176: return 4; // Extended DENORMAL or UNNORMAL
1177: } else if (exp == 0x7fff) {
1178: int s = w2 >> 30;
1179: int z = (w2 & 0x3fffffff) == 0 && w3 == 0;
1180: if ((s == 0 && !z) || (s == 2 && !z))
1181: return 2; // INF
1182: return 3; // NAN
1183: } else {
1184: if (!(w2 & 0x80000000))
1185: return 4; // Extended UNNORMAL
1186: return 0; // NORMAL
1187: }
1188: }
1189:
1190: /* single : S 8*E 23*F */
1191: /* double : S 11*E 52*F */
1192: /* extended : S 15*E 64*F */
1193: /* E = 0 & F = 0 -> 0 */
1194: /* E = MAX & F = 0 -> Infin */
1195: /* E = MAX & F # 0 -> NotANumber */
1196: /* E = biased by 127 (single) ,1023 (double) ,16383 (extended) */
1197:
1198: static void to_pack (fpdata *fpd, uae_u32 *wrd)
1199: {
1200: fptype d;
1.1 root 1201: char *cp;
1202: char str[100];
1203:
1.1.1.4 root 1204: cp = str;
1205: if (wrd[0] & 0x80000000)
1206: *cp++ = '-';
1207: *cp++ = (wrd[0] & 0xf) + '0';
1208: *cp++ = '.';
1209: *cp++ = ((wrd[1] >> 28) & 0xf) + '0';
1210: *cp++ = ((wrd[1] >> 24) & 0xf) + '0';
1211: *cp++ = ((wrd[1] >> 20) & 0xf) + '0';
1212: *cp++ = ((wrd[1] >> 16) & 0xf) + '0';
1213: *cp++ = ((wrd[1] >> 12) & 0xf) + '0';
1214: *cp++ = ((wrd[1] >> 8) & 0xf) + '0';
1215: *cp++ = ((wrd[1] >> 4) & 0xf) + '0';
1216: *cp++ = ((wrd[1] >> 0) & 0xf) + '0';
1217: *cp++ = ((wrd[2] >> 28) & 0xf) + '0';
1218: *cp++ = ((wrd[2] >> 24) & 0xf) + '0';
1219: *cp++ = ((wrd[2] >> 20) & 0xf) + '0';
1220: *cp++ = ((wrd[2] >> 16) & 0xf) + '0';
1221: *cp++ = ((wrd[2] >> 12) & 0xf) + '0';
1222: *cp++ = ((wrd[2] >> 8) & 0xf) + '0';
1223: *cp++ = ((wrd[2] >> 4) & 0xf) + '0';
1224: *cp++ = ((wrd[2] >> 0) & 0xf) + '0';
1225: *cp++ = 'E';
1226: if (wrd[0] & 0x40000000)
1227: *cp++ = '-';
1228: *cp++ = ((wrd[0] >> 24) & 0xf) + '0';
1229: *cp++ = ((wrd[0] >> 20) & 0xf) + '0';
1230: *cp++ = ((wrd[0] >> 16) & 0xf) + '0';
1231: *cp = 0;
1232: #if USE_LONG_DOUBLE
1233: sscanf (str, "%Le", &d);
1234: #else
1235: sscanf (str, "%le", &d);
1236: #endif
1237: #ifdef WITH_SOFTFLOAT
1238: if (currprefs.fpu_softfloat) {
1239: uae_u32 wrd[3];
1240: from_exten_x(d, &wrd[0], &wrd[1], &wrd[2]);
1241: softfloat_set(&fpd->fpx, wrd);
1242: } else
1243: #endif
1244: fpd->fp = d;
1245: }
1246:
1247: static void from_pack (fpdata *src, uae_u32 *wrd, int kfactor)
1248: {
1249: int i, j, t;
1250: int exp;
1251: int ndigits;
1252: char *cp, *strp;
1253: char str[100];
1254: fptype fp;
1255:
1256: wrd[0] = wrd[1] = wrd[2] = 0;
1257:
1258: if (fp_is_nan (src) || fp_is_infinity (src)) {
1259: wrd[0] |= (1 << 30) | (1 << 29) | (1 << 30); // YY=1
1260: wrd[0] |= 0xfff << 16; // Exponent=FFF
1261: // TODO: mantissa should be set if NAN
1262: return;
1263: }
1264:
1265: #ifdef WITH_SOFTFLOAT
1266: if (currprefs.fpu_softfloat) {
1267: uae_u32 out[3];
1268: softfloat_get(&src->fpx, out);
1269: to_exten_x(&fp, out[0], out[1], out[2]);
1270: } else
1271: #endif
1272: fp = src->fp;
1273:
1.1.1.2 root 1274: #if USE_LONG_DOUBLE
1.1.1.4 root 1275: sprintf (str, "%#.17Le", fp);
1.1.1.2 root 1276: #else
1.1.1.4 root 1277: sprintf (str, "%#.17e", fp);
1.1.1.2 root 1278: #endif
1.1.1.4 root 1279:
1280: // get exponent
1.1 root 1281: cp = str;
1.1.1.4 root 1282: while (*cp++ != 'e');
1283: if (*cp == '+')
1284: cp++;
1285: exp = atoi (cp);
1286:
1287: // remove trailing zeros
1288: cp = str;
1289: while (*cp != 'e')
1.1 root 1290: cp++;
1.1.1.4 root 1291: cp[0] = 0;
1292: cp--;
1293: while (cp > str && *cp == '0') {
1294: *cp = 0;
1295: cp--;
1.1 root 1296: }
1.1.1.4 root 1297:
1298: cp = str;
1299: // get sign
1300: if (*cp == '-') {
1.1 root 1301: cp++;
1.1.1.4 root 1302: wrd[0] = 0x80000000;
1303: } else if (*cp == '+') {
1.1 root 1304: cp++;
1305: }
1.1.1.4 root 1306: strp = cp;
1307:
1308: if (kfactor <= 0) {
1309: ndigits = abs (exp) + (-kfactor) + 1;
1310: } else {
1311: if (kfactor > 17) {
1312: kfactor = 17;
1313: update_fpsr (FE_INVALID);
1314: }
1315: ndigits = kfactor;
1.1 root 1316: }
1.1.1.4 root 1317:
1318: if (ndigits < 0)
1319: ndigits = 0;
1320: if (ndigits > 16)
1321: ndigits = 16;
1322:
1323: // remove decimal point
1324: strp[1] = strp[0];
1325: strp++;
1326: // add trailing zeros
1327: i = strlen (strp);
1328: cp = strp + i;
1329: while (i < ndigits) {
1330: *cp++ = '0';
1331: i++;
1332: }
1333: i = ndigits + 1;
1334: while (i < 17) {
1335: strp[i] = 0;
1336: i++;
1337: }
1338: *cp = 0;
1339: i = ndigits - 1;
1340: // need to round?
1341: if (i >= 0 && strp[i + 1] >= '5') {
1342: while (i >= 0) {
1343: strp[i]++;
1344: if (strp[i] <= '9')
1345: break;
1346: if (i == 0) {
1347: strp[i] = '1';
1348: exp++;
1349: } else {
1350: strp[i] = '0';
1351: }
1352: i--;
1353: }
1354: }
1355: strp[ndigits] = 0;
1356:
1357: // store first digit of mantissa
1358: cp = strp;
1359: wrd[0] |= *cp++ - '0';
1360:
1361: // store rest of mantissa
1362: for (j = 1; j < 3; j++) {
1363: for (i = 0; i < 8; i++) {
1364: wrd[j] <<= 4;
1.1 root 1365: if (*cp >= '0' && *cp <= '9')
1.1.1.4 root 1366: wrd[j] |= *cp++ - '0';
1367: }
1368: }
1369:
1370: // exponent
1371: if (exp < 0) {
1372: wrd[0] |= 0x40000000;
1373: exp = -exp;
1374: }
1375: if (exp > 9999) // ??
1376: exp = 9999;
1377: if (exp > 999) {
1378: int d = exp / 1000;
1379: wrd[0] |= d << 12;
1380: exp -= d * 1000;
1381: update_fpsr (FE_INVALID);
1382: }
1383: i = 100;
1384: t = 0;
1385: while (i >= 1) {
1386: int d = exp / i;
1387: t <<= 4;
1388: t |= d;
1389: exp -= d * i;
1390: i /= 10;
1391: }
1392: wrd[0] |= t << 16;
1393: }
1394:
1395: // 68040/060 does not support denormals
1396: static bool fault_if_no_denormal_support_pre(uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc, fpdata *fpd, int size)
1397: {
1398: #ifdef WITH_SOFTFLOAT
1399: if (currprefs.cpu_model >= 68040 && currprefs.fpu_model && currprefs.fpu_no_unimplemented && currprefs.fpu_softfloat) {
1400: Bit64u Sig = extractFloatx80Frac(fpd->fpx);
1401: Bit32s Exp = extractFloatx80Exp(fpd->fpx);
1402: if (Exp == 0 && Sig != 0) {
1403: fpu_op_unimp(opcode, extra, ea, oldpc, FPU_EXP_UNIMP_DATATYPE_PRE, fpd, -1, size);
1404: return true;
1405: }
1406: }
1407: #endif
1408: return false;
1409: }
1410: static bool fault_if_no_denormal_support_post(uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc, fpdata *fpd, int size)
1411: {
1412: #ifdef WITH_SOFTFLOAT
1413: if (currprefs.fpu_softfloat && currprefs.cpu_model >= 68040 && currprefs.fpu_model && currprefs.fpu_no_unimplemented) {
1414: Bit64u Sig = extractFloatx80Frac(fpd->fpx);
1415: Bit32s Exp = extractFloatx80Exp(fpd->fpx);
1416: if (Exp == 0 && Sig != 0) {
1417: fpu_op_unimp(opcode, extra, ea, oldpc, FPU_EXP_UNIMP_DATATYPE_POST, fpd, -1, size);
1418: return true;
1.1 root 1419: }
1420: }
1.1.1.4 root 1421: #endif
1422: return false;
1.1 root 1423: }
1424:
1.1.1.4 root 1425: static int get_fp_value (uae_u32 opcode, uae_u16 extra, fpdata *src, uaecptr oldpc, uae_u32 *adp)
1.1 root 1426: {
1427: int size, mode, reg;
1428: uae_u32 ad = 0;
1429: static const int sz1[8] = { 4, 4, 12, 12, 2, 8, 1, 0 };
1430: static const int sz2[8] = { 4, 4, 12, 12, 2, 8, 2, 0 };
1.1.1.5 ! root 1431: #ifndef WINUAE_FOR_HATARI
1.1.1.4 root 1432: uae_u32 exts[3];
1.1.1.5 ! root 1433: #else
! 1434: uae_u32 exts[3] = { 0 };
! 1435: #endif
1.1.1.4 root 1436: int doext = 0;
1.1 root 1437:
1438: if (!(extra & 0x4000)) {
1.1.1.4 root 1439: if (fault_if_no_fpu (opcode, extra, 0, oldpc))
1440: return -1;
1.1 root 1441: *src = regs.fp[(extra >> 10) & 7];
1.1.1.4 root 1442: if (fault_if_no_denormal_support_pre(opcode, extra, 0, oldpc, src, 2))
1443: return -1;
1.1 root 1444: return 1;
1445: }
1446: mode = (opcode >> 3) & 7;
1447: reg = opcode & 7;
1448: size = (extra >> 10) & 7;
1449:
1450: switch (mode) {
1451: case 0:
1.1.1.4 root 1452: switch (size)
1453: {
1454: case 6:
1455: fpset(src, (uae_s8) m68k_dreg (regs, reg));
1456: break;
1457: case 4:
1458: fpset(src, (uae_s16) m68k_dreg (regs, reg));
1459: break;
1460: case 0:
1461: fpset(src, (uae_s32) m68k_dreg (regs, reg));
1462: break;
1463: case 1:
1464: to_single (src, m68k_dreg (regs, reg));
1465: if (fault_if_no_denormal_support_pre(opcode, extra, 0, oldpc, src, 0))
1466: return -1;
1467: break;
1468: default:
1469: return 0;
1.1 root 1470: }
1471: return 1;
1472: case 1:
1473: return 0;
1474: case 2:
1475: ad = m68k_areg (regs, reg);
1476: break;
1477: case 3:
1.1.1.4 root 1478: if (currprefs.mmu_model) {
1479: mmufixup[0].reg = reg;
1480: mmufixup[0].value = m68k_areg (regs, reg);
1481: fpu_mmu_fixup = true;
1482: }
1.1 root 1483: ad = m68k_areg (regs, reg);
1484: m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size];
1485: break;
1486: case 4:
1.1.1.4 root 1487: if (currprefs.mmu_model) {
1488: mmufixup[0].reg = reg;
1489: mmufixup[0].value = m68k_areg (regs, reg);
1490: fpu_mmu_fixup = true;
1491: }
1.1 root 1492: m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size];
1493: ad = m68k_areg (regs, reg);
1494: break;
1495: case 5:
1.1.1.4 root 1496: ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) x_cp_next_iword ();
1.1 root 1497: break;
1498: case 6:
1.1.1.4 root 1499: ad = x_cp_get_disp_ea_020 (m68k_areg (regs, reg), 0);
1.1 root 1500: break;
1501: case 7:
1.1.1.4 root 1502: switch (reg)
1503: {
1504: case 0: // (xxx).W
1505: ad = (uae_s32) (uae_s16) x_cp_next_iword ();
1506: break;
1507: case 1: // (xxx).L
1508: ad = x_cp_next_ilong ();
1509: break;
1510: case 2: // (d16,PC)
1511: ad = m68k_getpc ();
1512: ad += (uae_s32) (uae_s16) x_cp_next_iword ();
1513: break;
1514: case 3: // (d8,PC,Xn)+
1515: ad = x_cp_get_disp_ea_020 (m68k_getpc (), 0);
1516: break;
1517: case 4: // #imm
1518: doext = 1;
1519: switch (size)
1520: {
1521: case 0: // L
1522: case 1: // S
1523: exts[0] = x_cp_next_ilong ();
1524: break;
1525: case 2: // X
1526: case 3: // P
1527: // 68060 and immediate X or P: unimplemented effective address
1528: if (fault_if_60 (opcode, extra, ad, oldpc, FPU_EXP_UNIMP_EA))
1529: return -1;
1530: exts[0] = x_cp_next_ilong ();
1531: exts[1] = x_cp_next_ilong ();
1532: exts[2] = x_cp_next_ilong ();
1533: break;
1534: case 4: // W
1535: exts[0] = x_cp_next_iword ();
1536: break;
1537: case 5: // D
1538: exts[0] = x_cp_next_ilong ();
1539: exts[1] = x_cp_next_ilong ();
1540: break;
1541: case 6: // B
1542: exts[0] = x_cp_next_iword ();
1543: break;
1544: }
1545: break;
1546: default:
1547: return 0;
1548: }
1549: }
1550:
1551: *adp = ad;
1552:
1553: if (currprefs.fpu_model == 68060 && fault_if_unimplemented_680x0 (opcode, extra, ad, oldpc, src, -1))
1554: return -1;
1555:
1556: switch (size)
1557: {
1.1 root 1558: case 0:
1.1.1.4 root 1559: fpset(src, (uae_s32) (doext ? exts[0] : x_cp_get_long (ad)));
1.1 root 1560: break;
1561: case 1:
1.1.1.4 root 1562: to_single (src, (doext ? exts[0] : x_cp_get_long (ad)));
1563: if (fault_if_no_denormal_support_pre(opcode, extra, 0, oldpc, src, 0))
1564: return -1;
1.1 root 1565: break;
1566: case 2:
1.1.1.4 root 1567: {
1568: uae_u32 wrd1, wrd2, wrd3;
1569: wrd1 = (doext ? exts[0] : x_cp_get_long (ad));
1570: ad += 4;
1571: wrd2 = (doext ? exts[1] : x_cp_get_long (ad));
1572: ad += 4;
1573: wrd3 = (doext ? exts[2] : x_cp_get_long (ad));
1574: to_exten (src, wrd1, wrd2, wrd3);
1575: if (fault_if_no_denormal_support_pre(opcode, extra, 0, oldpc, src, 2))
1576: return -1;
1577: }
1.1 root 1578: break;
1579: case 3:
1.1.1.4 root 1580: {
1581: uae_u32 wrd[3];
1582: uae_u32 adold = ad;
1583: if (currprefs.cpu_model == 68060) {
1584: if (fault_if_4060 (opcode, extra, adold, oldpc, FPU_EXP_UNIMP_DATATYPE_PACKED_PRE, NULL, wrd))
1585: return -1;
1586: }
1587: wrd[0] = (doext ? exts[0] : x_cp_get_long (ad));
1588: ad += 4;
1589: wrd[1] = (doext ? exts[1] : x_cp_get_long (ad));
1590: ad += 4;
1591: wrd[2] = (doext ? exts[2] : x_cp_get_long (ad));
1592: if (fault_if_4060 (opcode, extra, adold, oldpc, FPU_EXP_UNIMP_DATATYPE_PACKED_PRE, NULL, wrd))
1593: return -1;
1594: to_pack (src, wrd);
1595: return 1;
1596: }
1.1 root 1597: break;
1598: case 4:
1.1.1.4 root 1599: fpset(src, (uae_s16) (doext ? exts[0] : x_cp_get_word (ad)));
1.1 root 1600: break;
1.1.1.4 root 1601: case 5:
1602: {
1603: uae_u32 wrd1, wrd2;
1604: wrd1 = (doext ? exts[0] : x_cp_get_long (ad));
1605: ad += 4;
1606: wrd2 = (doext ? exts[1] : x_cp_get_long (ad));
1607: to_double (src, wrd1, wrd2);
1608: if (fault_if_no_denormal_support_pre(opcode, extra, 0, oldpc, src, 1))
1609: return -1;
1.1 root 1610: }
1611: break;
1.1.1.4 root 1612: case 6:
1613: fpset(src, (uae_s8) (doext ? exts[0] : x_cp_get_byte (ad)));
1.1 root 1614: break;
1615: default:
1616: return 0;
1617: }
1618: return 1;
1619: }
1620:
1.1.1.4 root 1621: static int put_fp_value (fpdata *value, uae_u32 opcode, uae_u16 extra, uaecptr oldpc)
1.1 root 1622: {
1623: int size, mode, reg;
1.1.1.4 root 1624: uae_u32 ad = 0;
1.1 root 1625: static int sz1[8] = { 4, 4, 12, 12, 2, 8, 1, 0 };
1626: static int sz2[8] = { 4, 4, 12, 12, 2, 8, 2, 0 };
1627:
1628: #if DEBUG_FPP
1629: if (!isinrom ())
1.1.1.4 root 1630: write_log (_T("PUTFP: %f %04X %04X\n"), value, opcode, extra);
1.1 root 1631: #endif
1632: if (!(extra & 0x4000)) {
1.1.1.4 root 1633: if (fault_if_no_fpu (opcode, extra, 0, oldpc))
1634: return 1;
1635: regs.fp[(extra >> 10) & 7] = *value;
1.1 root 1636: return 1;
1637: }
1638: reg = opcode & 7;
1639: mode = (opcode >> 3) & 7;
1640: size = (extra >> 10) & 7;
1641: ad = -1;
1.1.1.4 root 1642: switch (mode)
1643: {
1.1 root 1644: case 0:
1.1.1.4 root 1645: switch (size)
1646: {
1647: case 6:
1648: m68k_dreg (regs, reg) = (uae_u32)(((toint (value, 0) & 0xff)
1649: | (m68k_dreg (regs, reg) & ~0xff)));
1650: break;
1651: case 4:
1652: m68k_dreg (regs, reg) = (uae_u32)(((toint (value, 1) & 0xffff)
1653: | (m68k_dreg (regs, reg) & ~0xffff)));
1654: break;
1655: case 0:
1656: m68k_dreg (regs, reg) = (uae_u32)toint (value, 2);
1657: break;
1658: case 1:
1659: m68k_dreg (regs, reg) = from_single (value);
1660: break;
1661: default:
1662: return 0;
1.1 root 1663: }
1664: return 1;
1665: case 1:
1666: return 0;
1667: case 2:
1668: ad = m68k_areg (regs, reg);
1669: break;
1670: case 3:
1.1.1.4 root 1671: if (currprefs.mmu_model) {
1672: mmufixup[0].reg = reg;
1673: mmufixup[0].value = m68k_areg (regs, reg);
1674: fpu_mmu_fixup = true;
1675: }
1.1 root 1676: ad = m68k_areg (regs, reg);
1677: m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size];
1678: break;
1679: case 4:
1.1.1.4 root 1680: if (currprefs.mmu_model) {
1681: mmufixup[0].reg = reg;
1682: mmufixup[0].value = m68k_areg (regs, reg);
1683: fpu_mmu_fixup = true;
1684: }
1.1 root 1685: m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size];
1686: ad = m68k_areg (regs, reg);
1687: break;
1688: case 5:
1.1.1.4 root 1689: ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) x_cp_next_iword ();
1.1 root 1690: break;
1691: case 6:
1.1.1.4 root 1692: ad = x_cp_get_disp_ea_020 (m68k_areg (regs, reg), 0);
1.1 root 1693: break;
1694: case 7:
1.1.1.4 root 1695: switch (reg)
1696: {
1697: case 0:
1698: ad = (uae_s32) (uae_s16) x_cp_next_iword ();
1699: break;
1700: case 1:
1701: ad = x_cp_next_ilong ();
1702: break;
1703: case 2:
1704: ad = m68k_getpc ();
1705: ad += (uae_s32) (uae_s16) x_cp_next_iword ();
1706: break;
1707: case 3:
1708: ad = x_cp_get_disp_ea_020 (m68k_getpc (), 0);
1709: break;
1710: default:
1711: return 0;
1.1 root 1712: }
1713: }
1.1.1.4 root 1714:
1715: if (fault_if_no_fpu (opcode, extra, ad, oldpc))
1716: return 1;
1717:
1718: switch (size)
1719: {
1.1 root 1720: case 0:
1.1.1.4 root 1721: if (fault_if_no_denormal_support_post(opcode, extra, ad, oldpc, value, 2))
1722: return 1;
1723: x_cp_put_long(ad, (uae_u32)toint(value, 2));
1.1 root 1724: break;
1725: case 1:
1.1.1.4 root 1726: if (fault_if_no_denormal_support_post(opcode, extra, ad, oldpc, value, 2))
1727: return -1;
1728: x_cp_put_long(ad, from_single(value));
1.1 root 1729: break;
1730: case 2:
1731: {
1732: uae_u32 wrd1, wrd2, wrd3;
1.1.1.4 root 1733: if (fault_if_no_denormal_support_post(opcode, extra, ad, oldpc, value, 2))
1734: return 1;
1735: from_exten(value, &wrd1, &wrd2, &wrd3);
1736: x_cp_put_long (ad, wrd1);
1.1 root 1737: ad += 4;
1.1.1.4 root 1738: x_cp_put_long (ad, wrd2);
1.1 root 1739: ad += 4;
1.1.1.4 root 1740: x_cp_put_long (ad, wrd3);
1.1 root 1741: }
1742: break;
1.1.1.4 root 1743: case 3: // Packed-Decimal Real with Static k-Factor
1744: case 7: // Packed-Decimal Real with Dynamic k-Factor (P{Dn}) (reg to memory only)
1.1 root 1745: {
1.1.1.4 root 1746: uae_u32 wrd[3];
1747: int kfactor;
1748: if (fault_if_4060 (opcode, extra, ad, oldpc, FPU_EXP_UNIMP_DATATYPE_PACKED_POST, value, NULL))
1749: return 1;
1750: kfactor = size == 7 ? m68k_dreg (regs, (extra >> 4) & 7) : extra;
1751: kfactor &= 127;
1752: if (kfactor & 64)
1753: kfactor |= ~63;
1754: from_pack (value, wrd, kfactor);
1755: x_cp_put_long (ad, wrd[0]);
1.1 root 1756: ad += 4;
1.1.1.4 root 1757: x_cp_put_long (ad, wrd[1]);
1.1 root 1758: ad += 4;
1.1.1.4 root 1759: x_cp_put_long (ad, wrd[2]);
1.1 root 1760: }
1761: break;
1762: case 4:
1.1.1.4 root 1763: if (fault_if_no_denormal_support_post(opcode, extra, ad, oldpc, value, 2))
1764: return 1;
1765: x_cp_put_word(ad, (uae_s16)toint(value, 1));
1766: break;
1767: case 5:
1768: {
1769: uae_u32 wrd1, wrd2;
1770: if (fault_if_no_denormal_support_post(opcode, extra, ad, oldpc, value, 1))
1771: return -1;
1772: from_double(value, &wrd1, &wrd2);
1773: x_cp_put_long (ad, wrd1);
1774: ad += 4;
1775: x_cp_put_long (ad, wrd2);
1776: }
1.1 root 1777: break;
1778: case 6:
1.1.1.4 root 1779: if (fault_if_no_denormal_support_post(opcode, extra, ad, oldpc, value, 2))
1780: return 1;
1781: x_cp_put_byte(ad, (uae_s8)toint(value, 0));
1.1 root 1782: break;
1783: default:
1784: return 0;
1785: }
1786: return 1;
1787: }
1788:
1789: STATIC_INLINE int get_fp_ad (uae_u32 opcode, uae_u32 * ad)
1790: {
1791: int mode;
1792: int reg;
1793:
1794: mode = (opcode >> 3) & 7;
1795: reg = opcode & 7;
1.1.1.4 root 1796: switch (mode)
1797: {
1.1 root 1798: case 0:
1799: case 1:
1800: return 0;
1801: case 2:
1802: *ad = m68k_areg (regs, reg);
1803: break;
1804: case 3:
1805: *ad = m68k_areg (regs, reg);
1806: break;
1807: case 4:
1808: *ad = m68k_areg (regs, reg);
1809: break;
1810: case 5:
1.1.1.4 root 1811: *ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) x_cp_next_iword ();
1.1 root 1812: break;
1813: case 6:
1.1.1.4 root 1814: *ad = x_cp_get_disp_ea_020 (m68k_areg (regs, reg), 0);
1.1 root 1815: break;
1816: case 7:
1.1.1.4 root 1817: switch (reg)
1818: {
1819: case 0:
1820: *ad = (uae_s32) (uae_s16) x_cp_next_iword ();
1821: break;
1822: case 1:
1823: *ad = x_cp_next_ilong ();
1824: break;
1825: case 2:
1826: *ad = m68k_getpc ();
1827: *ad += (uae_s32) (uae_s16) x_cp_next_iword ();
1828: break;
1829: case 3:
1830: *ad = x_cp_get_disp_ea_020 (m68k_getpc (), 0);
1831: break;
1832: default:
1833: return 0;
1.1 root 1834: }
1835: }
1836: return 1;
1837: }
1838:
1.1.1.4 root 1839: int fpp_cond (int condition)
1.1 root 1840: {
1.1.1.4 root 1841: int NotANumber, Z, N;
1.1 root 1842:
1.1.1.4 root 1843: NotANumber = fp_is_nan(®s.fp_result);
1844: N = fp_is_neg(®s.fp_result);
1845: Z = fp_is_zero(®s.fp_result);
1.1 root 1846:
1.1.1.4 root 1847: if ((condition & 0x10) && NotANumber)
1848: regs.fp_result_status |= FP_BSUN;
1.1 root 1849:
1.1.1.4 root 1850: switch (condition)
1851: {
1.1 root 1852: case 0x00:
1853: return 0;
1854: case 0x01:
1855: return Z;
1856: case 0x02:
1857: return !(NotANumber || Z || N);
1858: case 0x03:
1859: return Z || !(NotANumber || N);
1860: case 0x04:
1861: return N && !(NotANumber || Z);
1862: case 0x05:
1863: return Z || (N && !NotANumber);
1864: case 0x06:
1865: return !(NotANumber || Z);
1866: case 0x07:
1867: return !NotANumber;
1868: case 0x08:
1869: return NotANumber;
1870: case 0x09:
1871: return NotANumber || Z;
1872: case 0x0a:
1873: return NotANumber || !(N || Z);
1874: case 0x0b:
1875: return NotANumber || Z || !N;
1876: case 0x0c:
1877: return NotANumber || (N && !Z);
1878: case 0x0d:
1879: return NotANumber || Z || N;
1880: case 0x0e:
1881: return !Z;
1882: case 0x0f:
1883: return 1;
1884: case 0x10:
1885: return 0;
1886: case 0x11:
1887: return Z;
1888: case 0x12:
1889: return !(NotANumber || Z || N);
1890: case 0x13:
1891: return Z || !(NotANumber || N);
1892: case 0x14:
1893: return N && !(NotANumber || Z);
1894: case 0x15:
1895: return Z || (N && !NotANumber);
1896: case 0x16:
1897: return !(NotANumber || Z);
1898: case 0x17:
1899: return !NotANumber;
1900: case 0x18:
1901: return NotANumber;
1902: case 0x19:
1903: return NotANumber || Z;
1904: case 0x1a:
1905: return NotANumber || !(N || Z);
1906: case 0x1b:
1907: return NotANumber || Z || !N;
1908: case 0x1c:
1909: return NotANumber || (N && !Z);
1910: case 0x1d:
1911: return NotANumber || Z || N;
1912: case 0x1e:
1913: return !Z;
1914: case 0x1f:
1915: return 1;
1916: }
1917: return -1;
1918: }
1919:
1.1.1.4 root 1920: static void maybe_idle_state (void)
1921: {
1922: // conditional floating point instruction does not change state
1923: // from null to idle on 68040/060.
1924: if (currprefs.fpu_model == 68881 || currprefs.fpu_model == 68882)
1925: regs.fpu_state = 1;
1926: }
1927:
1.1 root 1928: void fpuop_dbcc (uae_u32 opcode, uae_u16 extra)
1929: {
1.1.1.4 root 1930: uaecptr pc = m68k_getpc ();
1.1 root 1931: uae_s32 disp;
1932: int cc;
1933:
1.1.1.4 root 1934: regs.fp_exception = false;
1.1 root 1935: #if DEBUG_FPP
1936: if (!isinrom ())
1.1.1.4 root 1937: write_log (_T("fdbcc_opp at %08x\n"), m68k_getpc ());
1.1 root 1938: #endif
1.1.1.4 root 1939: if (fault_if_no_6888x (opcode, extra, pc - 4))
1.1 root 1940: return;
1941:
1.1.1.4 root 1942: disp = (uae_s32) (uae_s16) x_cp_next_iword ();
1943: if (fault_if_no_fpu_u (opcode, extra, pc + disp, pc - 4))
1944: return;
1945: regs.fpiar = pc - 4;
1946: maybe_idle_state ();
1.1 root 1947: cc = fpp_cond (extra & 0x3f);
1.1.1.4 root 1948: if (cc < 0) {
1949: fpu_op_illg (opcode, extra, regs.fpiar);
1.1 root 1950: } else if (!cc) {
1951: int reg = opcode & 0x7;
1952:
1953: m68k_dreg (regs, reg) = ((m68k_dreg (regs, reg) & 0xffff0000)
1954: | (((m68k_dreg (regs, reg) & 0xffff) - 1) & 0xffff));
1.1.1.4 root 1955: if ((m68k_dreg (regs, reg) & 0xffff) != 0xffff) {
1.1 root 1956: m68k_setpc (pc + disp);
1.1.1.4 root 1957: regs.fp_branch = true;
1958: }
1.1 root 1959: }
1960: }
1961:
1962: void fpuop_scc (uae_u32 opcode, uae_u16 extra)
1963: {
1.1.1.3 root 1964: uae_u32 ad = 0;
1.1 root 1965: int cc;
1.1.1.4 root 1966: uaecptr pc = m68k_getpc () - 4;
1.1 root 1967:
1.1.1.4 root 1968: regs.fp_exception = false;
1.1 root 1969: #if DEBUG_FPP
1970: if (!isinrom ())
1.1.1.4 root 1971: write_log (_T("fscc_opp at %08x\n"), m68k_getpc ());
1.1 root 1972: #endif
1.1.1.4 root 1973:
1974: if (fault_if_no_6888x (opcode, extra, pc))
1975: return;
1976:
1977: if (opcode & 0x38) {
1978: if (get_fp_ad (opcode, &ad) == 0) {
1979: fpu_noinst (opcode, regs.fpiar);
1980: return;
1981: }
1982: }
1983:
1984: if (fault_if_no_fpu_u (opcode, extra, ad, pc))
1.1 root 1985: return;
1986:
1.1.1.4 root 1987: regs.fpiar = pc;
1988: maybe_idle_state ();
1.1 root 1989: cc = fpp_cond (extra & 0x3f);
1.1.1.4 root 1990: if (cc < 0) {
1991: fpu_op_illg (opcode, extra, regs.fpiar);
1.1 root 1992: } else if ((opcode & 0x38) == 0) {
1993: m68k_dreg (regs, opcode & 7) = (m68k_dreg (regs, opcode & 7) & ~0xff) | (cc ? 0xff : 0x00);
1994: } else {
1.1.1.4 root 1995: x_cp_put_byte (ad, cc ? 0xff : 0x00);
1.1 root 1996: }
1997: }
1998:
1999: void fpuop_trapcc (uae_u32 opcode, uaecptr oldpc, uae_u16 extra)
2000: {
2001: int cc;
2002:
1.1.1.4 root 2003: regs.fp_exception = false;
1.1 root 2004: #if DEBUG_FPP
2005: if (!isinrom ())
1.1.1.4 root 2006: write_log (_T("ftrapcc_opp at %08x\n"), m68k_getpc ());
1.1 root 2007: #endif
1.1.1.4 root 2008: if (fault_if_no_fpu_u (opcode, extra, 0, oldpc))
1.1 root 2009: return;
2010:
1.1.1.4 root 2011: regs.fpiar = oldpc;
2012: maybe_idle_state ();
1.1 root 2013: cc = fpp_cond (extra & 0x3f);
1.1.1.4 root 2014: if (cc < 0) {
2015: fpu_op_illg (opcode, extra, oldpc);
2016: } else if (cc) {
2017: Exception (7);
1.1 root 2018: }
2019: }
2020:
1.1.1.4 root 2021: void fpuop_bcc (uae_u32 opcode, uaecptr oldpc, uae_u32 extra)
1.1 root 2022: {
2023: int cc;
2024:
1.1.1.4 root 2025: regs.fp_exception = false;
1.1 root 2026: #if DEBUG_FPP
2027: if (!isinrom ())
1.1.1.4 root 2028: write_log (_T("fbcc_opp at %08x\n"), m68k_getpc ());
1.1 root 2029: #endif
1.1.1.4 root 2030: if (fault_if_no_fpu (opcode, extra, 0, oldpc - 2))
1.1 root 2031: return;
2032:
1.1.1.4 root 2033: regs.fpiar = oldpc - 2;
2034: maybe_idle_state ();
1.1 root 2035: cc = fpp_cond (opcode & 0x3f);
1.1.1.4 root 2036: if (cc < 0) {
2037: fpu_op_illg (opcode, extra, oldpc - 2);
1.1 root 2038: } else if (cc) {
2039: if ((opcode & 0x40) == 0)
2040: extra = (uae_s32) (uae_s16) extra;
1.1.1.4 root 2041: m68k_setpc (oldpc + extra);
2042: regs.fp_branch = true;
1.1 root 2043: }
2044: }
2045:
2046: void fpuop_save (uae_u32 opcode)
2047: {
1.1.1.4 root 2048: uae_u32 ad;
1.1 root 2049: int incr = (opcode & 0x38) == 0x20 ? -1 : 1;
1.1.1.4 root 2050: int fpu_version = get_fpu_version ();
2051: uaecptr pc = m68k_getpc () - 2;
1.1 root 2052: int i;
2053:
1.1.1.4 root 2054: regs.fp_exception = false;
1.1 root 2055: #if DEBUG_FPP
2056: if (!isinrom ())
1.1.1.4 root 2057: write_log (_T("fsave_opp at %08x\n"), m68k_getpc ());
1.1 root 2058: #endif
1.1.1.4 root 2059:
2060: if (fault_if_no_6888x (opcode, 0, pc))
1.1 root 2061: return;
2062:
2063: if (get_fp_ad (opcode, &ad) == 0) {
1.1.1.4 root 2064: fpu_op_illg (opcode, 0, pc);
1.1 root 2065: return;
2066: }
2067:
1.1.1.4 root 2068: if (fault_if_no_fpu (opcode, 0, ad, pc))
2069: return;
2070:
1.1 root 2071: if (currprefs.fpu_model == 68060) {
1.1.1.4 root 2072: /* 12 byte 68060 NULL/IDLE/EXCP frame. */
2073: int frame_size = 12;
2074: uae_u32 frame_id, frame_v1, frame_v2;
2075:
2076: if (regs.fpu_exp_state > 1) {
2077: uae_u32 src1[3];
2078: from_exten (®s.exp_src1, &src1[0], &src1[1], &src1[2]);
2079: frame_id = 0x0000e000 | src1[0];
2080: frame_v1 = src1[1];
2081: frame_v2 = src1[2];
2082:
2083: #if EXCEPTION_FPP
2084: #if USE_LONG_DOUBLE
2085: write_log(_T("68060 FSAVE EXCP %Le\n"), regs.exp_src1.fp);
2086: #else
2087: write_log(_T("68060 FSAVE EXCP %e\n"), regs.exp_src1.fp);
2088: #endif
2089: #endif
2090:
1.1 root 2091: } else {
1.1.1.4 root 2092: frame_id = regs.fpu_state == 0 ? 0x00000000 : 0x00006000;
2093: frame_v1 = 0;
2094: frame_v2 = 0;
1.1 root 2095: }
1.1.1.4 root 2096: if (incr < 0)
2097: ad -= frame_size;
2098: x_put_long (ad, frame_id);
2099: ad += 4;
2100: x_put_long (ad, frame_v1);
2101: ad += 4;
2102: x_put_long (ad, frame_v2);
2103: ad += 4;
2104: if (incr < 0)
2105: ad -= frame_size;
1.1 root 2106: } else if (currprefs.fpu_model == 68040) {
1.1.1.4 root 2107: if (!regs.fpu_exp_state) {
2108: /* 4 byte 68040 NULL/IDLE frame. */
2109: uae_u32 frame_id = regs.fpu_state == 0 ? 0 : fpu_version << 24;
2110: if (incr < 0) {
2111: ad -= 4;
2112: x_put_long (ad, frame_id);
2113: } else {
2114: x_put_long (ad, frame_id);
2115: ad += 4;
2116: }
1.1 root 2117: } else {
1.1.1.4 root 2118: /* 44 (rev $40) and 52 (rev $41) byte 68040 unimplemented instruction frame */
2119: /* 96 byte 68040 busy frame */
2120: int frame_size = regs.fpu_exp_state == 2 ? 0x64 : (fpu_version >= 0x41 ? 0x34 : 0x2c);
2121: uae_u32 frame_id = ((fpu_version << 8) | (frame_size - 4)) << 16;
2122: uae_u32 src1[3], src2[3];
2123: uae_u32 stag, dtag;
2124: uae_u32 extra = regs.exp_extra;
2125:
2126: from_exten(®s.exp_src1, &src1[0], &src1[1], &src1[2]);
2127: from_exten(®s.exp_src2, &src2[0], &src2[1], &src2[2]);
2128: stag = get_ftag(src1[0], src1[1], src1[2], regs.exp_size);
2129: dtag = get_ftag(src2[0], src2[1], src2[2], -1);
2130: if ((extra & 0x7f) == 4) // FSQRT 4->5
2131: extra |= 1;
2132:
2133: #if EXCEPTION_FPP
2134: write_log(_T("68040 FSAVE %d (%d), CMDREG=%04X"), regs.exp_type, frame_size, extra);
2135: if (regs.exp_type == FPU_EXP_UNIMP_DATATYPE_PACKED_PRE) {
2136: write_log(_T(" PACKED %08x-%08x-%08x"), regs.exp_pack[0], regs.exp_pack[1], regs.exp_pack[2]);
2137: } else if (regs.exp_type == FPU_EXP_UNIMP_DATATYPE_PACKED_POST) {
2138: #if USE_LONG_DOUBLE
2139: write_log(_T(" SRC=%Le (%08x-%08x-%08x %d), DST=%Le (%08x-%08x-%08x %d)"), regs.exp_src1.fp, src1[0], src1[1], src1[2], stag, regs.exp_src2.fp, src2[0], src2[1], src2[2], dtag);
2140: #else
2141: write_log(_T(" SRC=%e (%08x-%08x-%08x %d), DST=%e (%08x-%08x-%08x %d)"), regs.exp_src1.fp, src1[0], src1[1], src1[2], stag, regs.exp_src2.fp, src2[0], src2[1], src2[2], dtag);
2142: #endif
2143: }
2144: write_log(_T("\n"));
2145: #endif
2146:
2147: if (incr < 0)
2148: ad -= frame_size;
2149: x_put_long (ad, frame_id);
1.1 root 2150: ad += 4;
1.1.1.4 root 2151: if (regs.fpu_exp_state == 2) {
2152: /* BUSY frame */
2153: x_put_long(ad, 0);
2154: ad += 4;
2155: x_put_long(ad, 0); // CU_SAVEPC (Software shouldn't care)
2156: ad += 4;
2157: x_put_long(ad, 0);
2158: ad += 4;
2159: x_put_long(ad, 0);
2160: ad += 4;
2161: x_put_long(ad, 0);
2162: ad += 4;
2163: x_put_long(ad, 0); // WBTS/WBTE (No E3 emulated yet)
2164: ad += 4;
2165: x_put_long(ad, 0); // WBTM
2166: ad += 4;
2167: x_put_long(ad, 0); // WBTM
2168: ad += 4;
2169: x_put_long(ad, 0);
2170: ad += 4;
2171: x_put_long(ad, regs.fpiar); // FPIARCU (same as FPU PC or something else?)
2172: ad += 4;
2173: x_put_long(ad, 0);
2174: ad += 4;
2175: x_put_long(ad, 0);
2176: ad += 4;
2177: }
2178: if (fpu_version >= 0x41 || regs.fpu_exp_state == 2) {
2179: x_put_long (ad, ((extra & (0x200 | 0x100 | 0x80)) | (extra & (0x40 | 0x02 | 0x01)) | ((extra >> 1) & (0x04 | 0x08 | 0x10)) | ((extra & 0x04) ? 0x20 : 0x00)) << 16); // CMDREG3B
2180: ad += 4;
2181: x_put_long (ad, 0);
2182: ad += 4;
2183: }
2184: x_put_long (ad, stag << 29); // STAG
2185: ad += 4;
2186: x_put_long (ad, extra << 16); // CMDREG1B
2187: ad += 4;
2188: x_put_long (ad, dtag << 29); // DTAG
2189: ad += 4;
2190: if (fpu_version >= 0x41 || regs.fpu_exp_state == 2) {
2191: x_put_long(ad, (regs.exp_type == FPU_EXP_UNIMP_DATATYPE_PACKED_PRE ? 1 << 26 : 0) | (regs.exp_type == FPU_EXP_UNIMP_DATATYPE_PACKED_POST ? 1 << 20 : 0)); // E1 and T
2192: ad += 4;
2193: } else {
2194: x_put_long(ad, (regs.exp_type == FPU_EXP_UNIMP_DATATYPE_PACKED_PRE || regs.exp_type == FPU_EXP_UNIMP_DATATYPE_PACKED_POST) ? 1 << 26 : 0); // E1
2195: ad += 4;
2196: }
2197: if (regs.exp_type == FPU_EXP_UNIMP_DATATYPE_PACKED_PRE) {
2198: x_put_long (ad, 0); // FPTS/FPTE
2199: ad += 4;
2200: x_put_long (ad, 0); // FPTM
2201: ad += 4;
2202: x_put_long (ad, regs.exp_pack[0]); // FPTM
2203: ad += 4;
2204: x_put_long (ad, 0); // ETS/ETE
2205: ad += 4;
2206: x_put_long (ad, regs.exp_pack[1]); // ETM
2207: ad += 4;
2208: x_put_long (ad, regs.exp_pack[2]); // ETM
2209: ad += 4;
2210: } else {
2211: x_put_long (ad, src2[0]); // FPTS/FPTE
2212: ad += 4;
2213: x_put_long (ad, src2[1]); // FPTM
2214: ad += 4;
2215: x_put_long (ad, src2[2]); // FPTM
2216: ad += 4;
2217: x_put_long (ad, src1[0]); // ETS/ETE
2218: ad += 4;
2219: x_put_long (ad, src1[1]); // ETM
2220: ad += 4;
2221: x_put_long (ad, src1[2]); // ETM
2222: ad += 4;
2223: }
2224: if (incr < 0)
2225: ad -= frame_size;
1.1 root 2226: }
2227: } else { /* 68881/68882 */
1.1.1.4 root 2228: int frame_size_real = currprefs.fpu_model == 68882 ? 0x3c : 0x1c;;
2229: int frame_size = regs.fpu_state == 0 ? 0 : frame_size_real;
2230: uae_u32 frame_id = regs.fpu_state == 0 ? ((frame_size_real - 4) << 16) : (fpu_version << 24) | ((frame_size_real - 4) << 16);
1.1.1.5 ! root 2231:
1.1.1.4 root 2232: if (currprefs.mmu_model) {
2233: if (incr < 0) {
2234: for (i = 0; i < (frame_size / 4) - 1; i++) {
2235: ad -= 4;
2236: if (mmu030_state[0] == i) {
2237: x_put_long (ad, i == 0 ? 0x70000000 : 0x00000000);
2238: mmu030_state[0]++;
2239: }
2240: }
1.1 root 2241: ad -= 4;
1.1.1.4 root 2242: if (mmu030_state[0] == (frame_size / 4) - 1 || (mmu030_state[0] == 0 && frame_size == 0)) {
2243: x_put_long (ad, frame_id);
2244: mmu030_state[0]++;
2245: }
2246: } else {
2247: if (mmu030_state[0] == 0) {
2248: x_put_long (ad, frame_id);
2249: mmu030_state[0]++;
2250: }
2251: ad += 4;
2252: for (i = 0; i < (frame_size / 4) - 1; i++) {
2253: if (mmu030_state[0] == i + 1) {
2254: x_put_long (ad, i == (frame_size / 4) - 2 ? 0x70000000 : 0x00000000);
2255: mmu030_state[0]++;
2256: }
2257: ad += 4;
2258: }
1.1 root 2259: }
2260: } else {
1.1.1.4 root 2261: if (incr < 0) {
2262: for (i = 0; i < (frame_size / 4) - 1; i++) {
2263: ad -= 4;
2264: x_put_long (ad, i == 0 ? 0x70000000 : 0x00000000);
2265: }
2266: ad -= 4;
2267: x_put_long (ad, frame_id);
2268: } else {
2269: x_put_long (ad, frame_id);
1.1 root 2270: ad += 4;
1.1.1.4 root 2271: for (i = 0; i < (frame_size / 4) - 1; i++) {
2272: x_put_long (ad, i == (frame_size / 4) - 2 ? 0x70000000 : 0x00000000);
2273: ad += 4;
2274: }
1.1 root 2275: }
2276: }
2277: }
1.1.1.4 root 2278:
1.1 root 2279: if ((opcode & 0x38) == 0x18)
2280: m68k_areg (regs, opcode & 7) = ad;
2281: if ((opcode & 0x38) == 0x20)
2282: m68k_areg (regs, opcode & 7) = ad;
1.1.1.4 root 2283: regs.fpu_exp_state = 0;
1.1 root 2284: }
2285:
2286: void fpuop_restore (uae_u32 opcode)
2287: {
1.1.1.4 root 2288: #ifndef WINUAE_FOR_HATARI
2289: int fpu_version = get_fpu_version (); // TODO: check version of stack frame
2290: #endif
2291: uaecptr pc = m68k_getpc () - 2;
2292: uae_u32 ad;
1.1 root 2293: uae_u32 d;
2294: int incr = (opcode & 0x38) == 0x20 ? -1 : 1;
2295:
1.1.1.4 root 2296: regs.fp_exception = false;
1.1 root 2297: #if DEBUG_FPP
2298: if (!isinrom ())
1.1.1.4 root 2299: write_log (_T("frestore_opp at %08x\n"), m68k_getpc ());
1.1 root 2300: #endif
1.1.1.4 root 2301:
2302: if (fault_if_no_6888x (opcode, 0, pc))
1.1 root 2303: return;
2304:
2305: if (get_fp_ad (opcode, &ad) == 0) {
1.1.1.4 root 2306: fpu_op_illg (opcode, 0, pc);
1.1 root 2307: return;
2308: }
2309:
1.1.1.4 root 2310: if (fault_if_no_fpu (opcode, 0, ad, pc))
2311: return;
2312: regs.fpiar = pc;
2313:
2314: if (incr < 0) {
2315: ad -= 4;
2316: d = x_get_long (ad);
2317: } else {
2318: d = x_get_long (ad);
2319: ad += 4;
2320: }
2321:
1.1 root 2322: if (currprefs.fpu_model == 68060) {
1.1.1.4 root 2323: int ff = (d >> 8) & 0xff;
2324: uae_u32 v1, v2;
2325:
1.1 root 2326: if (incr < 0) {
2327: ad -= 4;
1.1.1.4 root 2328: v1 = x_get_long (ad);
2329: ad -= 4;
2330: v2 = x_get_long (ad);
1.1 root 2331: } else {
1.1.1.4 root 2332: v1 = x_get_long (ad);
2333: ad += 4;
2334: v2 = x_get_long (ad);
1.1 root 2335: ad += 4;
2336: }
1.1.1.4 root 2337: if (ff == 0x60) {
2338: regs.fpu_state = 1;
2339: regs.fpu_exp_state = 0;
2340: } else if (ff == 0xe0) {
2341: regs.fpu_exp_state = 1;
2342: to_exten (®s.exp_src1, d & 0xffff0000, v1, v2);
2343: } else if (ff) {
2344: write_log (_T("FRESTORE invalid frame format %X!\n"), (d >> 8) & 0xff);
2345: } else {
2346: fpu_null ();
2347: }
2348: } else {
2349: if ((d & 0xff000000) != 0) {
2350: regs.fpu_state = 1;
2351: if (incr < 0)
2352: ad -= (d >> 16) & 0xff;
2353: else
2354: ad += (d >> 16) & 0xff;
2355: } else {
2356: fpu_null ();
2357: }
2358: }
1.1 root 2359:
1.1.1.4 root 2360: if ((opcode & 0x38) == 0x18)
2361: m68k_areg (regs, opcode & 7) = ad;
2362: if ((opcode & 0x38) == 0x20)
2363: m68k_areg (regs, opcode & 7) = ad;
2364: }
2365:
2366: static uaecptr fmovem2mem (uaecptr ad, uae_u32 list, int incr, int regdir)
2367: {
2368: int reg;
2369:
2370: // 68030 MMU state saving is annoying!
2371: if (currprefs.mmu_model == 68030) {
2372: int idx = 0;
2373: int r;
2374: int i;
2375: uae_u32 wrd[3];
2376: mmu030_state[1] |= MMU030_STATEFLAG1_MOVEM1;
2377: for (r = 0; r < 8; r++) {
2378: if (regdir < 0)
2379: reg = 7 - r;
2380: else
2381: reg = r;
2382: if (list & 0x80) {
2383: from_exten(®s.fp[reg], &wrd[0], &wrd[1], &wrd[2]);
2384: if (incr < 0)
2385: ad -= 3 * 4;
2386: for (i = 0; i < 3; i++) {
2387: if (mmu030_state[0] == idx * 3 + i) {
2388: if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM2) {
2389: mmu030_state[1] &= ~MMU030_STATEFLAG1_MOVEM2;
2390: }
2391: else {
2392: mmu030_data_buffer = wrd[i];
2393: x_put_long(ad + i * 4, wrd[i]);
2394: }
2395: mmu030_state[0]++;
2396: }
1.1 root 2397: }
1.1.1.4 root 2398: if (incr > 0)
2399: ad += 3 * 4;
2400: idx++;
1.1 root 2401: }
1.1.1.4 root 2402: list <<= 1;
2403: }
2404: } else {
2405: int r;
2406: for (r = 0; r < 8; r++) {
2407: uae_u32 wrd1, wrd2, wrd3;
2408: if (regdir < 0)
2409: reg = 7 - r;
2410: else
2411: reg = r;
2412: if (list & 0x80) {
2413: from_exten(®s.fp[reg], &wrd1, &wrd2, &wrd3);
2414: if (incr < 0)
2415: ad -= 3 * 4;
2416: x_put_long(ad + 0, wrd1);
2417: x_put_long(ad + 4, wrd2);
2418: x_put_long(ad + 8, wrd3);
2419: if (incr > 0)
2420: ad += 3 * 4;
2421: }
2422: list <<= 1;
2423: }
2424: }
2425: return ad;
2426: }
2427:
2428: static uaecptr fmovem2fpp (uaecptr ad, uae_u32 list, int incr, int regdir)
2429: {
2430: int reg;
2431:
2432: if (currprefs.mmu_model == 68030) {
2433: uae_u32 wrd[3];
2434: int idx = 0;
2435: int r;
2436: int i;
2437: mmu030_state[1] |= MMU030_STATEFLAG1_MOVEM1 | MMU030_STATEFLAG1_FMOVEM;
2438: if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM2)
2439: ad = mmu030_ad[mmu030_idx].val;
2440: else
2441: mmu030_ad[mmu030_idx].val = ad;
2442: for (r = 0; r < 8; r++) {
2443: if (regdir < 0)
2444: reg = 7 - r;
2445: else
2446: reg = r;
2447: if (list & 0x80) {
2448: if (incr < 0)
2449: ad -= 3 * 4;
2450: for (i = 0; i < 3; i++) {
2451: if (mmu030_state[0] == idx * 3 + i) {
2452: if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM2) {
2453: mmu030_state[1] &= ~MMU030_STATEFLAG1_MOVEM2;
2454: wrd[i] = mmu030_data_buffer;
2455: } else {
2456: wrd[i] = x_get_long (ad + i * 4);
2457: }
2458: // save first two entries if 2nd or 3rd get_long() faults.
2459: if (i == 0 || i == 1)
2460: mmu030_fmovem_store[i] = wrd[i];
2461: mmu030_state[0]++;
2462: if (i == 2)
2463: to_exten (®s.fp[reg], mmu030_fmovem_store[0], mmu030_fmovem_store[1], wrd[2]);
2464: }
1.1 root 2465: }
1.1.1.4 root 2466: if (incr > 0)
2467: ad += 3 * 4;
2468: idx++;
1.1 root 2469: }
1.1.1.4 root 2470: list <<= 1;
1.1 root 2471: }
1.1.1.4 root 2472: } else {
2473: int r;
2474: for (r = 0; r < 8; r++) {
2475: uae_u32 wrd1, wrd2, wrd3;
2476: if (regdir < 0)
2477: reg = 7 - r;
2478: else
2479: reg = r;
2480: if (list & 0x80) {
2481: if (incr < 0)
2482: ad -= 3 * 4;
2483: wrd1 = x_get_long (ad + 0);
2484: wrd2 = x_get_long (ad + 4);
2485: wrd3 = x_get_long (ad + 8);
2486: if (incr > 0)
2487: ad += 3 * 4;
2488: to_exten (®s.fp[reg], wrd1, wrd2, wrd3);
1.1 root 2489: }
1.1.1.4 root 2490: list <<= 1;
2491: }
2492: }
2493: return ad;
2494: }
2495:
2496: // round to float
2497: static void fround (int reg)
2498: {
2499: #ifdef WITH_SOFTFLOAT
2500: if (currprefs.fpu_softfloat) {
2501: float32 f = floatx80_to_float32(regs.fp[reg].fpx, fxstatus);
2502: regs.fp[reg].fpx = float32_to_floatx80(f, fxstatus);
2503: } else
2504: #endif
2505: regs.fp[reg].fp = (float)regs.fp[reg].fp;
2506: }
2507:
2508: static bool arithmetic_fp(fptype src, int reg, int extra)
2509: {
2510: bool sgl = false;
2511: switch (extra & 0x7f)
2512: {
2513: case 0x00: /* FMOVE */
2514: case 0x40: /* Explicit rounding. This is just a quick fix. */
2515: case 0x44: /* Same for all other cases that have three choices */
2516: regs.fp[reg].fp = src; /* Brian King was here. */
2517: /*<ea> to register needs FPSR updated. See Motorola 68K Manual. */
2518: break;
2519: case 0x01: /* FINT */
2520: /* need to take the current rounding mode into account */
2521: #if defined(X86_MSVC_ASSEMBLY_FPU)
2522: {
2523: fptype tmp_fp;
2524: __asm {
2525: fld LDPTR src
2526: frndint
2527: fstp LDPTR tmp_fp
2528: }
2529: regs.fp[reg].fp = tmp_fp;
2530: }
2531: #else /* no X86_MSVC */
2532: switch (regs.fpcr & 0x30)
2533: {
2534: case FPCR_ROUND_NEAR:
2535: regs.fp[reg].fp = fp_round_to_nearest(src);
2536: break;
2537: case FPCR_ROUND_ZERO:
2538: regs.fp[reg].fp = fp_round_to_zero(src);
2539: break;
2540: case FPCR_ROUND_MINF:
2541: regs.fp[reg].fp = fp_round_to_minus_infinity(src);
2542: break;
2543: case FPCR_ROUND_PINF:
2544: regs.fp[reg].fp = fp_round_to_plus_infinity(src);
2545: break;
2546: default: /* never reached */
2547: regs.fp[reg].fp = src;
2548: break;
2549: }
2550: #endif /* X86_MSVC */
2551: break;
2552: case 0x02: /* FSINH */
2553: regs.fp[reg].fp = sinh (src);
2554: break;
2555: case 0x03: /* FINTRZ */
2556: regs.fp[reg].fp = fp_round_to_zero (src);
2557: break;
2558: case 0x04: /* FSQRT */
2559: case 0x41: /* FSSQRT */
2560: case 0x45: /* FDSQRT */
2561: regs.fp[reg].fp = sqrt (src);
2562: break;
2563: case 0x06: /* FLOGNP1 */
2564: regs.fp[reg].fp = log (src + 1.0);
2565: break;
2566: case 0x08: /* FETOXM1 */
2567: regs.fp[reg].fp = exp (src) - 1.0;
2568: break;
2569: case 0x09: /* FTANH */
2570: regs.fp[reg].fp = tanh (src);
2571: break;
2572: case 0x0a: /* FATAN */
2573: regs.fp[reg].fp = atan (src);
2574: break;
2575: case 0x0c: /* FASIN */
2576: regs.fp[reg].fp = asin (src);
2577: break;
2578: case 0x0d: /* FATANH */
2579: regs.fp[reg].fp = atanh (src);
2580: break;
2581: case 0x0e: /* FSIN */
2582: regs.fp[reg].fp = sin (src);
2583: break;
2584: case 0x0f: /* FTAN */
2585: regs.fp[reg].fp = tan (src);
2586: break;
2587: case 0x10: /* FETOX */
2588: regs.fp[reg].fp = exp (src);
2589: break;
2590: case 0x11: /* FTWOTOX */
2591: regs.fp[reg].fp = pow (2.0, src);
2592: break;
2593: case 0x12: /* FTENTOX */
2594: regs.fp[reg].fp = pow (10.0, src);
2595: break;
2596: case 0x14: /* FLOGN */
2597: regs.fp[reg].fp = log (src);
2598: break;
2599: case 0x15: /* FLOG10 */
2600: regs.fp[reg].fp = log10 (src);
2601: break;
2602: case 0x16: /* FLOG2 */
2603: regs.fp[reg].fp = *fp_l2_e * log (src);
2604: break;
2605: case 0x18: /* FABS */
2606: case 0x58: /* FSABS */
2607: case 0x5c: /* FDABS */
2608: regs.fp[reg].fp = src < 0 ? -src : src;
2609: break;
2610: case 0x19: /* FCOSH */
2611: regs.fp[reg].fp = cosh (src);
2612: break;
2613: case 0x1a: /* FNEG */
2614: case 0x5a: /* FSNEG */
2615: case 0x5e: /* FDNEG */
2616: regs.fp[reg].fp = -src;
2617: break;
2618: case 0x1c: /* FACOS */
2619: regs.fp[reg].fp = acos (src);
2620: break;
2621: case 0x1d: /* FCOS */
2622: regs.fp[reg].fp = cos (src);
2623: break;
2624: case 0x1e: /* FGETEXP */
2625: {
2626: if (src == 0) {
2627: regs.fp[reg].fp = 0;
2628: } else {
2629: int expon;
2630: frexp (src, &expon);
2631: regs.fp[reg].fp = (double) (expon - 1);
2632: }
2633: }
2634: break;
2635: case 0x1f: /* FGETMAN */
2636: {
2637: if (src == 0) {
2638: regs.fp[reg].fp = 0;
2639: } else {
2640: int expon;
2641: regs.fp[reg].fp = frexp (src, &expon) * 2.0;
2642: }
2643: }
2644: break;
2645: case 0x20: /* FDIV */
2646: case 0x60: /* FSDIV */
2647: case 0x64: /* FDDIV */
2648: regs.fp[reg].fp /= src;
2649: break;
2650: case 0x21: /* FMOD */
2651: {
2652: fptype quot = fp_round_to_zero(regs.fp[reg].fp / src);
2653: regs.fp[reg].fp = regs.fp[reg].fp - quot * src;
2654: }
2655: break;
2656: case 0x22: /* FADD */
2657: case 0x62: /* FSADD */
2658: case 0x66: /* FDADD */
2659: regs.fp[reg].fp += src;
2660: break;
2661: case 0x23: /* FMUL */
2662: case 0x63: /* FSMUL */
2663: case 0x67: /* FDMUL */
2664: regs.fp[reg].fp *= src;
2665: break;
2666: case 0x24: /* FSGLDIV */
2667: regs.fp[reg].fp /= src;
2668: sgl = true;
2669: break;
2670: case 0x25: /* FREM */
2671: {
2672: fptype quot = fp_round_to_nearest(regs.fp[reg].fp / src);
2673: regs.fp[reg].fp = regs.fp[reg].fp - quot * src;
2674: }
2675: break;
2676: case 0x26: /* FSCALE */
2677: if (src != 0) {
2678: #ifdef ldexp
2679: regs.fp[reg] = ldexp (regs.fp[reg], (int) src);
2680: #else
2681: regs.fp[reg].fp *= exp (*fp_ln_2 * (int) src);
2682: #endif
2683: }
2684: break;
2685: case 0x27: /* FSGLMUL */
2686: regs.fp[reg].fp *= src;
2687: sgl = true;
2688: break;
2689: case 0x28: /* FSUB */
2690: case 0x68: /* FSSUB */
2691: case 0x6c: /* FDSUB */
2692: regs.fp[reg].fp -= src;
2693: break;
2694: case 0x30: /* FSINCOS */
2695: case 0x31:
2696: case 0x32:
2697: case 0x33:
2698: case 0x34:
2699: case 0x35:
2700: case 0x36:
2701: case 0x37:
2702: regs.fp[extra & 7].fp = cos (src);
2703: regs.fp[reg].fp = sin (src);
2704: break;
2705: case 0x38: /* FCMP */
2706: {
2707: fptype tmp = regs.fp[reg].fp - src;
2708: regs.fpsr = 0;
2709: MAKE_FPSR (&tmp);
2710: }
2711: return true;
2712: case 0x3a: /* FTST */
2713: regs.fpsr = 0;
2714: MAKE_FPSR (&src);
2715: return true;
2716: default:
2717: return false;
2718: }
2719: // round to float?
1.1.1.5 ! root 2720: if (sgl || (extra & 0x44) == 0x40 || ((regs.fpcr >> 6) & 3) == 1)
1.1.1.4 root 2721: fround (reg);
2722: MAKE_FPSR (®s.fp[reg].fp);
2723: return true;
2724: }
2725:
2726: #ifdef WITH_SOFTFLOAT
2727: static bool arithmetic_softfloat(floatx80 *srcd, int reg, int extra)
2728: {
2729: floatx80 fx = *srcd;
2730: floatx80 f = regs.fp[reg].fpx;
2731: int float_rounding_mode;
2732: bool sgl = false;
2733: Bit64u q;
2734:
2735: // SNAN -> QNAN if SNAN interrupt is not enabled
2736: if (floatx80_is_signaling_nan(fx) && !(regs.fpcr & 0x4000)) {
2737: fx.fraction |= 0x40000000;
2738: }
2739:
2740: switch (extra & 0x7f)
2741: {
2742: case 0x00: /* FMOVE */
2743: case 0x40:
2744: case 0x44:
2745: regs.fp[reg].fpx = fx;
2746: break;
2747: case 0x01: /* FINT */
2748: regs.fp[reg].fpx = floatx80_round_to_int(fx, fxstatus);
2749: break;
2750: case 0x03: /* FINTRZ */
2751: float_rounding_mode = fxstatus.float_rounding_mode;
2752: fxstatus.float_rounding_mode = float_round_to_zero;
2753: regs.fp[reg].fpx = floatx80_round_to_int(fx, fxstatus);
2754: float_rounding_mode = fxstatus.float_rounding_mode;
2755: break;
2756: case 0x04: /* FSQRT */
2757: case 0x41: /* FSSQRT */
2758: case 0x45: /* FDSQRT */
2759: regs.fp[reg].fpx = floatx80_sqrt(fx, fxstatus);
2760: break;
2761: case 0x18: /* FABS */
2762: case 0x58: /* FSABS */
2763: case 0x5c: /* FDABS */
2764: regs.fp[reg].fpx = floatx80_abs(fx);
2765: break;
2766: case 0x1a: /* FNEG */
2767: case 0x5a: /* FSNEG */
2768: case 0x5e: /* FDNEG */
2769: // same here..
2770: regs.fp[reg].fpx = floatx80_chs(fx);
2771: break;
2772: case 0x20: /* FDIV */
2773: case 0x60: /* FSDIV */
2774: case 0x64: /* FDDIV */
2775: regs.fp[reg].fpx = floatx80_div(f, fx, fxstatus);
2776: break;
2777: case 0x22: /* FADD */
2778: case 0x62: /* FSADD */
2779: case 0x66: /* FDADD */
2780: regs.fp[reg].fpx = floatx80_add(f, fx, fxstatus);
2781: break;
2782: case 0x23: /* FMUL */
2783: case 0x63: /* FSMUL */
2784: case 0x67: /* FDMUL */
2785: regs.fp[reg].fpx = floatx80_mul(f, fx, fxstatus);
2786: break;
2787: case 0x24: /* FSGLDIV */
2788: regs.fp[reg].fpx = floatx80_div(f, fx, fxstatus);
2789: sgl = true;
2790: break;
2791: case 0x25: /* FREM */
2792: floatx80_ieee754_remainder(f, fx, regs.fp[reg].fpx, q, fxstatus);
2793: break;
2794: case 0x27: /* FSGLMUL */
2795: regs.fp[reg].fpx = floatx80_mul(f, fx, fxstatus);
2796: sgl = true;
2797: break;
2798: case 0x28: /* FSUB */
2799: case 0x68: /* FSSUB */
2800: case 0x6c: /* FDSUB */
2801: regs.fp[reg].fpx = floatx80_sub(f, fx, fxstatus);
2802: break;
2803: case 0x38: /* FCMP */
2804: f = floatx80_sub(f, fx, fxstatus);
2805: regs.fpsr = 0;
2806: MAKE_FPSR_SOFTFLOAT(f);
2807: return true;
2808: case 0x3a: /* FTST */
2809: regs.fpsr = 0;
2810: MAKE_FPSR_SOFTFLOAT(f);
2811: return true;
2812:
2813: case 0x1d: /* FCOS */
2814: fcos(f, fxstatus);
2815: regs.fp[reg].fpx = f;
2816: break;
2817: case 0x0e: /* FSIN */
2818: fsin(f, fxstatus);
2819: regs.fp[reg].fpx = f;
2820: break;
2821: case 0x0f: /* FTAN */
2822: ftan(f, fxstatus);
2823: regs.fp[reg].fpx = f;
2824: break;
2825: case 0x30: /* FSINCOS */
2826: case 0x31: /* FSINCOS */
2827: case 0x32: /* FSINCOS */
2828: case 0x33: /* FSINCOS */
2829: case 0x34: /* FSINCOS */
2830: case 0x35: /* FSINCOS */
2831: case 0x36: /* FSINCOS */
2832: case 0x37: /* FSINCOS */
2833: fsincos(f, ®s.fp[extra & 7].fpx, ®s.fp[reg].fpx, fxstatus);
2834: break;
2835:
2836: // some of following are supported by softfloat, later..
2837: case 0x06: /* FLOGNP1 */
2838: case 0x08: /* FETOXM1 */
2839: case 0x09: /* FTANH */
2840: case 0x0a: /* FATAN */
2841: case 0x0c: /* FASIN */
2842: case 0x0d: /* FATANH */
2843: case 0x10: /* FETOX */
2844: case 0x11: /* FTWOTOX */
2845: case 0x12: /* FTENTOX */
2846: case 0x14: /* FLOGN */
2847: case 0x15: /* FLOG10 */
2848: case 0x16: /* FLOG2 */
2849: case 0x19: /* FCOSH */
2850: case 0x1c: /* FACOS */
2851: case 0x1e: /* FGETEXP */
2852: case 0x1f: /* FGETMAN */
2853: {
2854: // This is horribly ineffective..
2855: fptype fp;
2856: uae_u32 out[3];
2857: // convert softfloat to raw words
2858: softfloat_get(&fx, out);
2859: // convert to double/long double
2860: to_exten_x(&fp, out[0], out[1], out[2]);
2861: // emulate instruction using normal fpu code
2862: if (!arithmetic_fp(fp, reg, extra))
2863: return false;
2864: // convert back to raw
2865: from_exten_x(regs.fp[reg].fp, &out[0], &out[1], &out[2]);
2866: // convert to softfloat internal format
2867: softfloat_set(®s.fp[reg].fpx, out);
2868: MAKE_FPSR_SOFTFLOAT(regs.fp[reg].fpx);
1.1 root 2869: }
1.1.1.4 root 2870: break;
1.1 root 2871: }
1.1.1.4 root 2872: return true;
1.1 root 2873: }
1.1.1.4 root 2874: #endif
1.1 root 2875:
1.1.1.4 root 2876: static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra)
2877: {
2878: int reg = -1;
2879: int v;
2880: fpdata srcd;
2881: uaecptr pc = m68k_getpc () - 4;
2882: uaecptr ad = 0;
1.1 root 2883:
2884: #if DEBUG_FPP
2885: if (!isinrom ())
1.1.1.4 root 2886: write_log (_T("FPP %04x %04x at %08x\n"), opcode & 0xffff, extra, pc);
1.1 root 2887: #endif
1.1.1.4 root 2888: if (fault_if_no_6888x (opcode, extra, pc))
1.1 root 2889: return;
2890:
1.1.1.4 root 2891: switch ((extra >> 13) & 0x7)
2892: {
1.1 root 2893: case 3:
1.1.1.4 root 2894: if (put_fp_value (®s.fp[(extra >> 7) & 7], opcode, extra, pc) == 0)
2895: fpu_noinst (opcode, pc);
1.1 root 2896: return;
2897:
2898: case 4:
2899: case 5:
2900: if ((opcode & 0x38) == 0) {
1.1.1.4 root 2901: if (fault_if_no_fpu (opcode, extra, 0, pc))
2902: return;
1.1 root 2903: if (extra & 0x2000) {
2904: if (extra & 0x1000)
2905: m68k_dreg (regs, opcode & 7) = regs.fpcr & 0xffff;
2906: if (extra & 0x0800)
1.1.1.4 root 2907: m68k_dreg (regs, opcode & 7) = fpp_get_fpsr ();
1.1 root 2908: if (extra & 0x0400)
2909: m68k_dreg (regs, opcode & 7) = regs.fpiar;
2910: } else {
2911: if (extra & 0x1000) {
2912: regs.fpcr = m68k_dreg (regs, opcode & 7);
2913: native_set_fpucw (regs.fpcr);
2914: }
2915: if (extra & 0x0800)
2916: set_fpsr (m68k_dreg (regs, opcode & 7));
2917: if (extra & 0x0400)
2918: regs.fpiar = m68k_dreg (regs, opcode & 7);
2919: }
2920: } else if ((opcode & 0x38) == 0x08) {
1.1.1.4 root 2921: if (fault_if_no_fpu (opcode, extra, 0, pc))
2922: return;
1.1 root 2923: if (extra & 0x2000) {
2924: if (extra & 0x1000)
2925: m68k_areg (regs, opcode & 7) = regs.fpcr & 0xffff;
2926: if (extra & 0x0800)
1.1.1.4 root 2927: m68k_areg (regs, opcode & 7) = fpp_get_fpsr ();
1.1 root 2928: if (extra & 0x0400)
2929: m68k_areg (regs, opcode & 7) = regs.fpiar;
2930: } else {
2931: if (extra & 0x1000) {
2932: regs.fpcr = m68k_areg (regs, opcode & 7);
2933: native_set_fpucw (regs.fpcr);
2934: }
2935: if (extra & 0x0800)
2936: set_fpsr (m68k_areg (regs, opcode & 7));
2937: if (extra & 0x0400)
2938: regs.fpiar = m68k_areg (regs, opcode & 7);
2939: }
2940: } else if ((opcode & 0x3f) == 0x3c) {
1.1.1.4 root 2941: if (fault_if_no_fpu (opcode, extra, 0, pc))
2942: return;
1.1 root 2943: if ((extra & 0x2000) == 0) {
1.1.1.4 root 2944: uae_u32 ext[3];
2945: // 68060 FMOVEM.L #imm,more than 1 control register: unimplemented EA
2946: uae_u16 bits = extra & (0x1000 | 0x0800 | 0x0400);
2947: if (bits && bits != 0x1000 && bits != 0x0800 && bits != 0x400) {
2948: if (fault_if_60 (opcode, extra, ad, pc, FPU_EXP_UNIMP_EA))
2949: return;
2950: }
2951: // fetch first, use only after all data has been fetched
2952: ext[0] = ext[1] = ext[2] = 0;
2953: if (extra & 0x1000)
2954: ext[0] = x_cp_next_ilong ();
2955: if (extra & 0x0800)
2956: ext[1] = x_cp_next_ilong ();
2957: if (extra & 0x0400)
2958: ext[2] = x_cp_next_ilong ();
1.1 root 2959: if (extra & 0x1000) {
1.1.1.4 root 2960: regs.fpcr = ext[0];
1.1 root 2961: native_set_fpucw (regs.fpcr);
2962: }
2963: if (extra & 0x0800)
1.1.1.4 root 2964: set_fpsr (ext[1]);
1.1 root 2965: if (extra & 0x0400)
1.1.1.4 root 2966: regs.fpiar = ext[2];
1.1 root 2967: }
2968: } else if (extra & 0x2000) {
2969: /* FMOVEM FPP->memory */
2970: uae_u32 ad;
2971: int incr = 0;
2972:
2973: if (get_fp_ad (opcode, &ad) == 0) {
1.1.1.4 root 2974: fpu_noinst (opcode, pc);
1.1 root 2975: return;
2976: }
1.1.1.4 root 2977: if (fault_if_no_fpu (opcode, extra, ad, pc))
2978: return;
2979:
1.1 root 2980: if ((opcode & 0x38) == 0x20) {
2981: if (extra & 0x1000)
2982: incr += 4;
2983: if (extra & 0x0800)
2984: incr += 4;
2985: if (extra & 0x0400)
2986: incr += 4;
2987: }
2988: ad -= incr;
2989: if (extra & 0x1000) {
1.1.1.4 root 2990: x_cp_put_long (ad, regs.fpcr & 0xffff);
1.1 root 2991: ad += 4;
2992: }
2993: if (extra & 0x0800) {
1.1.1.4 root 2994: x_cp_put_long (ad, fpp_get_fpsr ());
1.1 root 2995: ad += 4;
2996: }
2997: if (extra & 0x0400) {
1.1.1.4 root 2998: x_cp_put_long (ad, regs.fpiar);
1.1 root 2999: ad += 4;
3000: }
3001: ad -= incr;
3002: if ((opcode & 0x38) == 0x18)
3003: m68k_areg (regs, opcode & 7) = ad;
3004: if ((opcode & 0x38) == 0x20)
3005: m68k_areg (regs, opcode & 7) = ad;
3006: } else {
3007: /* FMOVEM memory->FPP */
3008: uae_u32 ad;
3009: int incr = 0;
3010:
3011: if (get_fp_ad (opcode, &ad) == 0) {
1.1.1.4 root 3012: fpu_noinst (opcode, pc);
1.1 root 3013: return;
3014: }
1.1.1.4 root 3015: if (fault_if_no_fpu (opcode, extra, ad, pc))
3016: return;
3017:
1.1 root 3018: if((opcode & 0x38) == 0x20) {
3019: if (extra & 0x1000)
3020: incr += 4;
3021: if (extra & 0x0800)
3022: incr += 4;
3023: if (extra & 0x0400)
3024: incr += 4;
3025: ad = ad - incr;
3026: }
3027: if (extra & 0x1000) {
1.1.1.4 root 3028: regs.fpcr = x_cp_get_long (ad);
1.1 root 3029: native_set_fpucw (regs.fpcr);
3030: ad += 4;
3031: }
3032: if (extra & 0x0800) {
1.1.1.4 root 3033: set_fpsr (x_cp_get_long (ad));
1.1 root 3034: ad += 4;
3035: }
3036: if (extra & 0x0400) {
1.1.1.4 root 3037: regs.fpiar = x_cp_get_long (ad);
1.1 root 3038: ad += 4;
3039: }
3040: if ((opcode & 0x38) == 0x18)
3041: m68k_areg (regs, opcode & 7) = ad;
3042: if ((opcode & 0x38) == 0x20)
3043: m68k_areg (regs, opcode & 7) = ad - incr;
3044: }
3045: return;
3046:
3047: case 6:
3048: case 7:
3049: {
3050: uae_u32 ad, list = 0;
1.1.1.4 root 3051: int incr = 1;
3052: int regdir = 1;
3053: if (get_fp_ad (opcode, &ad) == 0) {
3054: fpu_noinst (opcode, pc);
3055: return;
3056: }
3057: if (fault_if_no_fpu (opcode, extra, ad, pc))
3058: return;
3059: switch ((extra >> 11) & 3)
3060: {
3061: case 0: /* static pred */
3062: list = extra & 0xff;
3063: regdir = -1;
3064: break;
3065: case 1: /* dynamic pred */
3066: if (fault_if_60 (opcode, extra, ad, pc, FPU_EXP_UNIMP_EA))
3067: return;
3068: list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff;
3069: regdir = -1;
3070: break;
3071: case 2: /* static postinc */
3072: list = extra & 0xff;
3073: break;
3074: case 3: /* dynamic postinc */
3075: if (fault_if_60 (opcode, extra, ad, pc, FPU_EXP_UNIMP_EA))
3076: return;
3077: list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff;
3078: break;
3079: }
3080: if ((opcode & 0x38) == 0x20) // -(an)
3081: incr = -1;
1.1 root 3082: if (extra & 0x2000) {
3083: /* FMOVEM FPP->memory */
1.1.1.4 root 3084: ad = fmovem2mem (ad, list, incr, regdir);
1.1 root 3085: } else {
3086: /* FMOVEM memory->FPP */
1.1.1.4 root 3087: ad = fmovem2fpp (ad, list, incr, regdir);
1.1 root 3088: }
1.1.1.4 root 3089: if ((opcode & 0x38) == 0x18 || (opcode & 0x38) == 0x20)
3090: m68k_areg (regs, opcode & 7) = ad;
1.1 root 3091: }
3092: return;
3093:
3094: case 0:
3095: case 2: /* Extremely common */
1.1.1.4 root 3096: regs.fpiar = pc;
1.1 root 3097: reg = (extra >> 7) & 7;
3098: if ((extra & 0xfc00) == 0x5c00) {
1.1.1.4 root 3099: if (fault_if_no_fpu (opcode, extra, 0, pc))
3100: return;
3101: if (fault_if_unimplemented_680x0 (opcode, extra, ad, pc, &srcd, reg))
3102: return;
3103: CLEAR_STATUS ();
3104: if (!fpu_get_constant(®s.fp[reg], extra)) {
3105: fpu_noinst(opcode, pc);
3106: return;
1.1 root 3107: }
1.1.1.4 root 3108: MAKE_FPSR (®s.fp[reg].fp);
1.1 root 3109: return;
3110: }
1.1.1.4 root 3111:
3112: // 6888x does not have special exceptions, check immediately
3113: if (fault_if_unimplemented_6888x (opcode, extra, pc))
3114: return;
3115:
3116: v = get_fp_value (opcode, extra, &srcd, pc, &ad);
3117: if (v <= 0) {
3118: if (v == 0)
3119: fpu_noinst (opcode, pc);
1.1 root 3120: return;
3121: }
3122:
1.1.1.4 root 3123: // get_fp_value() checked this, but only if EA was nonzero (non-register)
3124: if (fault_if_unimplemented_680x0 (opcode, extra, ad, pc, &srcd, reg))
3125: return;
1.1 root 3126:
1.1.1.4 root 3127: regs.fpiar = pc;
1.1 root 3128:
1.1.1.4 root 3129: CLEAR_STATUS ();
3130: #ifdef WITH_SOFTFLOAT
3131: if (currprefs.fpu_softfloat)
3132: v = arithmetic_softfloat(&srcd.fpx, reg, extra);
1.1 root 3133: else
3134: #endif
1.1.1.4 root 3135: v = arithmetic_fp(srcd.fp, reg, extra);
3136: if (!v)
3137: fpu_noinst (opcode, pc);
1.1 root 3138: return;
3139: default:
1.1.1.4 root 3140: break;
3141: }
3142: fpu_noinst (opcode, pc);
3143: }
3144:
3145: void fpuop_arithmetic (uae_u32 opcode, uae_u16 extra)
3146: {
3147: regs.fpu_state = 1;
3148: regs.fp_exception = false;
3149: fpu_mmu_fixup = false;
3150: fpuop_arithmetic2 (opcode, extra);
3151: if (fpu_mmu_fixup) {
3152: mmufixup[0].reg = -1;
3153: }
3154: #ifdef WITH_SOFTFLOAT
3155: if (currprefs.fpu_softfloat) {
3156: // Any exception status bit and matching exception enable bits set?
3157: if ((regs.fpcr >> 8) & (regs.fpsr >> 8)) {
3158: uae_u32 mask = regs.fpcr >> 8;
3159: int vector = 0;
3160: for (int i = 7; i >= 0; i--) {
3161: if (mask & (1 << i)) {
3162: if (i > 0)
3163: i--;
3164: vector = i + 48;
3165: break;
3166: }
1.1 root 3167: }
1.1.1.4 root 3168: // logging only so far
3169: write_log (_T("FPU exception: %08x %d!\n"), regs.fpsr, vector);
3170: }
1.1 root 3171: }
1.1.1.4 root 3172: #endif
1.1 root 3173: }
3174:
3175: void fpu_reset (void)
3176: {
1.1.1.5 ! root 3177: #ifndef WINUAE_FOR_HATARI
! 3178: #if defined(CPU_i386) || defined(CPU_x86_64)
! 3179: init_fpucw_x87();
! 3180: #endif
! 3181: #endif /* ! WINUAE_FOR_HATARI */
! 3182:
1.1 root 3183: regs.fpcr = regs.fpsr = regs.fpiar = 0;
1.1.1.4 root 3184: regs.fpu_exp_state = 0;
3185: fpset (®s.fp_result, 1);
3186: native_set_fpucw (regs.fpcr);
1.1 root 3187: fpux_restore (NULL);
1.1.1.4 root 3188:
3189: #ifdef WITH_SOFTFLOAT
3190: fxsizes[0] = int32_to_floatx80(-128);
3191: fxsizes[1] = int32_to_floatx80(127);
3192: fxsizes[2] = int32_to_floatx80(-32768);
3193: fxsizes[3] = int32_to_floatx80(32767);
3194: fxsizes[4] = int32_to_floatx80(-2147483648);
3195: fxsizes[5] = int32_to_floatx80(2147483647);
3196: fxzero = int32_to_floatx80(0);
3197: fx_1e0 = int32_to_floatx80(1);
3198: fx_1e1 = int32_to_floatx80(10);
3199: fx_1e2 = int32_to_floatx80(100);
3200: fx_1e4 = int32_to_floatx80(10000);
3201: fx_1e8 = int32_to_floatx80(100000000);
3202: #endif
1.1 root 3203: }
3204:
3205: uae_u8 *restore_fpu (uae_u8 *src)
3206: {
1.1.1.4 root 3207: uae_u32 w1, w2, w3;
1.1 root 3208: int i;
3209: uae_u32 flags;
3210:
1.1.1.5 ! root 3211: fpu_reset();
1.1 root 3212: changed_prefs.fpu_model = currprefs.fpu_model = restore_u32 ();
3213: flags = restore_u32 ();
3214: for (i = 0; i < 8; i++) {
1.1.1.4 root 3215: w1 = restore_u16 () << 16;
3216: w2 = restore_u32 ();
3217: w3 = restore_u32 ();
3218: to_exten (®s.fp[i], w1, w2, w3);
1.1 root 3219: }
3220: regs.fpcr = restore_u32 ();
3221: native_set_fpucw (regs.fpcr);
3222: regs.fpsr = restore_u32 ();
3223: regs.fpiar = restore_u32 ();
3224: if (flags & 0x80000000) {
1.1.1.4 root 3225: restore_u32 ();
3226: restore_u32 ();
1.1 root 3227: }
1.1.1.4 root 3228: if (flags & 0x40000000) {
3229: w1 = restore_u16() << 16;
3230: w2 = restore_u32();
3231: w3 = restore_u32();
3232: to_exten(®s.exp_src1, w1, w2, w3);
3233: w1 = restore_u16() << 16;
3234: w2 = restore_u32();
3235: w3 = restore_u32();
3236: to_exten(®s.exp_src2, w1, w2, w3);
3237: regs.exp_pack[0] = restore_u32();
3238: regs.exp_pack[1] = restore_u32();
3239: regs.exp_pack[2] = restore_u32();
3240: regs.exp_opcode = restore_u16();
3241: regs.exp_extra = restore_u16();
3242: regs.exp_type = restore_u16();
3243: }
3244: regs.fpu_state = (flags & 1) ? 0 : 1;
3245: regs.fpu_exp_state = (flags & 2) ? 1 : 0;
3246: if (flags & 4)
3247: regs.fpu_exp_state = 2;
3248: write_log(_T("FPU: %d\n"), currprefs.fpu_model);
1.1 root 3249: return src;
3250: }
3251:
3252: uae_u8 *save_fpu (int *len, uae_u8 *dstptr)
3253: {
1.1.1.4 root 3254: uae_u32 w1, w2, w3;
3255: uae_u8 *dstbak, *dst;
1.1 root 3256: int i;
3257:
3258: *len = 0;
1.1.1.4 root 3259: #ifndef WINUAE_FOR_HATARI
3260: /* Under Hatari, we save all FPU variables, even if fpu_model==0 */
1.1 root 3261: if (currprefs.fpu_model == 0)
3262: return 0;
1.1.1.4 root 3263: #endif
1.1 root 3264: if (dstptr)
3265: dstbak = dst = dstptr;
3266: else
1.1.1.4 root 3267: dstbak = dst = xmalloc (uae_u8, 4+4+8*10+4+4+4+4+4+2*10+3*(4+2));
1.1 root 3268: save_u32 (currprefs.fpu_model);
1.1.1.4 root 3269: save_u32 (0x80000000 | 0x40000000 | (regs.fpu_state == 0 ? 1 : 0) | (regs.fpu_exp_state ? 2 : 0) | (regs.fpu_exp_state > 1 ? 4 : 0));
1.1 root 3270: for (i = 0; i < 8; i++) {
1.1.1.4 root 3271: from_exten (®s.fp[i], &w1, &w2, &w3);
3272: save_u16 (w1 >> 16);
1.1 root 3273: save_u32 (w2);
1.1.1.4 root 3274: save_u32 (w3);
1.1 root 3275: }
3276: save_u32 (regs.fpcr);
3277: save_u32 (regs.fpsr);
3278: save_u32 (regs.fpiar);
1.1.1.4 root 3279:
1.1 root 3280: save_u32 (-1);
3281: save_u32 (0);
1.1.1.4 root 3282:
3283: from_exten(®s.exp_src1, &w1, &w2, &w3);
3284: save_u16(w1 >> 16);
3285: save_u32(w2);
3286: save_u32(w3);
3287: from_exten(®s.exp_src2, &w1, &w2, &w3);
3288: save_u16(w1 >> 16);
3289: save_u32(w2);
3290: save_u32(w3);
3291: save_u32(regs.exp_pack[0]);
3292: save_u32(regs.exp_pack[1]);
3293: save_u32(regs.exp_pack[2]);
3294: save_u16(regs.exp_opcode);
3295: save_u16(regs.exp_extra);
3296: save_u16(regs.exp_type);
3297:
1.1 root 3298: *len = dst - dstbak;
3299: return dstbak;
3300: }
1.1.1.4 root 3301:
3302: #ifdef _MSC_VER
3303: #pragma fenv_access(off)
3304: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.