|
|
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:
1.1.1.6 root 13: #define FPU_TEST 0
1.1.1.7 ! root 14: #define FPU_LOG 0
1.1.1.6 root 15:
1.1 root 16: #include <math.h>
17: #include <float.h>
1.1.1.4 root 18: #include <fenv.h>
19:
1.1 root 20: #include "sysconfig.h"
21: #include "sysdeps.h"
22:
1.1.1.7 ! root 23: #ifdef WINUAE_FOR_HATARI
! 24: #include "main.h"
! 25: #include "hatari-glue.h"
! 26: #include "log.h"
! 27: #endif
! 28:
1.1 root 29: #include "options_cpu.h"
30: #include "memory.h"
1.1.1.5 root 31: #include "uae/attributes.h"
32: #include "uae/vm.h"
1.1 root 33: #include "custom.h"
34: #include "events.h"
35: #include "newcpu.h"
1.1.1.6 root 36: #include "fpp.h"
1.1 root 37: #include "savestate.h"
38: #include "cpu_prefetch.h"
39: #include "cpummu.h"
1.1.1.4 root 40: #include "cpummu030.h"
1.1.1.7 ! root 41: #include "debug.h"
1.1.1.4 root 42:
1.1.1.6 root 43: #include "softfloat/softfloat.h"
44:
1.1.1.7 ! root 45: // global variable for JIT FPU
! 46: #ifdef USE_LONG_DOUBLE
! 47: bool use_long_double = true;
! 48: #else
! 49: bool use_long_double = false;
! 50: #endif
! 51:
! 52: static bool support_exceptions;
! 53: static bool support_denormals;
! 54:
1.1.1.6 root 55: FPP_PRINT fpp_print;
56:
57: FPP_IS fpp_unset_snan;
1.1.1.7 ! root 58: FPP_IS fpp_is_init;
! 59: FPP_IS fpp_is_snan;
1.1.1.6 root 60: FPP_IS fpp_is_nan;
61: FPP_IS fpp_is_infinity;
62: FPP_IS fpp_is_zero;
63: FPP_IS fpp_is_neg;
64: FPP_IS fpp_is_denormal;
65: FPP_IS fpp_is_unnormal;
1.1.1.7 ! root 66: FPP_A fpp_fix_infinity;
1.1.1.6 root 67:
68: FPP_GET_STATUS fpp_get_status;
69: FPP_CLEAR_STATUS fpp_clear_status;
70: FPP_SET_MODE fpp_set_mode;
1.1.1.7 ! root 71: FPP_SUPPORT_FLAGS fpp_get_support_flags;
1.1.1.6 root 72:
73: FPP_FROM_NATIVE fpp_from_native;
74: FPP_TO_NATIVE fpp_to_native;
75:
76: FPP_TO_INT fpp_to_int;
77: FPP_FROM_INT fpp_from_int;
78:
79: FPP_PACK fpp_to_pack;
80: FPP_PACK fpp_from_pack;
81:
82: FPP_TO_SINGLE fpp_to_single;
83: FPP_FROM_SINGLE fpp_from_single;
84: FPP_TO_DOUBLE fpp_to_double;
85: FPP_FROM_DOUBLE fpp_from_double;
86: FPP_TO_EXTEN fpp_to_exten;
87: FPP_FROM_EXTEN fpp_from_exten;
88: FPP_TO_EXTEN fpp_to_exten_fmovem;
89: FPP_FROM_EXTEN fpp_from_exten_fmovem;
90:
91: FPP_A fpp_normalize;
92: FPP_DENORMALIZE fpp_denormalize;
93: FPP_A fpp_get_internal_overflow;
94: FPP_A fpp_get_internal_underflow;
95: FPP_A fpp_get_internal_round_all;
96: FPP_A fpp_get_internal_round;
97: FPP_A fpp_get_internal_round_exten;
98: FPP_A fpp_get_internal;
99: FPP_GET32 fpp_get_internal_grs;
100:
101: FPP_A fpp_round_single;
102: FPP_A fpp_round_double;
103: FPP_A fpp_round32;
104: FPP_A fpp_round64;
105: FPP_AB fpp_int;
106: FPP_AB fpp_sinh;
107: FPP_AB fpp_intrz;
108: FPP_ABP fpp_sqrt;
109: FPP_AB fpp_lognp1;
110: FPP_AB fpp_etoxm1;
111: FPP_AB fpp_tanh;
112: FPP_AB fpp_atan;
113: FPP_AB fpp_atanh;
114: FPP_AB fpp_sin;
115: FPP_AB fpp_asin;
116: FPP_AB fpp_tan;
117: FPP_AB fpp_etox;
118: FPP_AB fpp_twotox;
119: FPP_AB fpp_tentox;
120: FPP_AB fpp_logn;
121: FPP_AB fpp_log10;
122: FPP_AB fpp_log2;
123: FPP_ABP fpp_abs;
124: FPP_AB fpp_cosh;
125: FPP_ABP fpp_neg;
126: FPP_AB fpp_acos;
127: FPP_AB fpp_cos;
128: FPP_AB fpp_getexp;
129: FPP_AB fpp_getman;
130: FPP_ABP fpp_div;
131: FPP_ABQS fpp_mod;
132: FPP_ABP fpp_add;
133: FPP_ABP fpp_mul;
134: FPP_ABQS fpp_rem;
135: FPP_AB fpp_scale;
136: FPP_ABP fpp_sub;
137: FPP_AB fpp_sgldiv;
138: FPP_AB fpp_sglmul;
139: FPP_AB fpp_cmp;
140: FPP_AB fpp_tst;
141: FPP_ABP fpp_move;
1.1.1.4 root 142:
1.1 root 143: #define DEBUG_FPP 0
1.1.1.6 root 144: #define EXCEPTION_FPP 0
1.1 root 145:
146: STATIC_INLINE int isinrom (void)
147: {
148: return (munge24 (m68k_getpc ()) & 0xFFF80000) == 0xF80000 && !currprefs.mmu_model;
149: }
150:
1.1.1.7 ! root 151: static bool jit_fpu(void)
! 152: {
! 153: return currprefs.cachesize && currprefs.compfpu;
! 154: }
! 155:
1.1.1.6 root 156: static int warned = 100;
157:
158: struct fpp_cr_entry {
159: uae_u32 val[3];
160: uae_u8 inexact;
161: uae_s8 rndoff[4];
162: };
163:
164: static const struct fpp_cr_entry fpp_cr[22] = {
165: { {0x40000000, 0xc90fdaa2, 0x2168c235}, 1, {0,-1,-1, 0} }, // 0 = pi
166: { {0x3ffd0000, 0x9a209a84, 0xfbcff798}, 1, {0, 0, 0, 1} }, // 1 = log10(2)
167: { {0x40000000, 0xadf85458, 0xa2bb4a9a}, 1, {0, 0, 0, 1} }, // 2 = e
168: { {0x3fff0000, 0xb8aa3b29, 0x5c17f0bc}, 1, {0,-1,-1, 0} }, // 3 = log2(e)
169: { {0x3ffd0000, 0xde5bd8a9, 0x37287195}, 0, {0, 0, 0, 0} }, // 4 = log10(e)
170: { {0x00000000, 0x00000000, 0x00000000}, 0, {0, 0, 0, 0} }, // 5 = 0.0
171: { {0x3ffe0000, 0xb17217f7, 0xd1cf79ac}, 1, {0,-1,-1, 0} }, // 6 = ln(2)
172: { {0x40000000, 0x935d8ddd, 0xaaa8ac17}, 1, {0,-1,-1, 0} }, // 7 = ln(10)
173: { {0x3fff0000, 0x80000000, 0x00000000}, 0, {0, 0, 0, 0} }, // 8 = 1e0
174: { {0x40020000, 0xa0000000, 0x00000000}, 0, {0, 0, 0, 0} }, // 9 = 1e1
175: { {0x40050000, 0xc8000000, 0x00000000}, 0, {0, 0, 0, 0} }, // 10 = 1e2
176: { {0x400c0000, 0x9c400000, 0x00000000}, 0, {0, 0, 0, 0} }, // 11 = 1e4
177: { {0x40190000, 0xbebc2000, 0x00000000}, 0, {0, 0, 0, 0} }, // 12 = 1e8
178: { {0x40340000, 0x8e1bc9bf, 0x04000000}, 0, {0, 0, 0, 0} }, // 13 = 1e16
179: { {0x40690000, 0x9dc5ada8, 0x2b70b59e}, 1, {0,-1,-1, 0} }, // 14 = 1e32
180: { {0x40d30000, 0xc2781f49, 0xffcfa6d5}, 1, {0, 0, 0, 1} }, // 15 = 1e64
181: { {0x41a80000, 0x93ba47c9, 0x80e98ce0}, 1, {0,-1,-1, 0} }, // 16 = 1e128
182: { {0x43510000, 0xaa7eebfb, 0x9df9de8e}, 1, {0,-1,-1, 0} }, // 17 = 1e256
183: { {0x46a30000, 0xe319a0ae, 0xa60e91c7}, 1, {0,-1,-1, 0} }, // 18 = 1e512
184: { {0x4d480000, 0xc9767586, 0x81750c17}, 1, {0, 0, 0, 1} }, // 19 = 1e1024
185: { {0x5a920000, 0x9e8b3b5d, 0xc53d5de5}, 1, {0,-1,-1, 0} }, // 20 = 1e2048
186: { {0x75250000, 0xc4605202, 0x8a20979b}, 1, {0,-1,-1, 0} } // 21 = 1e4094
187: };
188:
189: #define FPP_CR_PI 0
190: #define FPP_CR_LOG10_2 1
191: #define FPP_CR_E 2
192: #define FPP_CR_LOG2_E 3
193: #define FPP_CR_LOG10_E 4
194: #define FPP_CR_ZERO 5
195: #define FPP_CR_LN_2 6
196: #define FPP_CR_LN_10 7
197: #define FPP_CR_1E0 8
198: #define FPP_CR_1E1 9
199: #define FPP_CR_1E2 10
200: #define FPP_CR_1E4 11
201: #define FPP_CR_1E8 12
202: #define FPP_CR_1E16 13
203: #define FPP_CR_1E32 14
204: #define FPP_CR_1E64 15
205: #define FPP_CR_1E128 16
206: #define FPP_CR_1E256 17
207: #define FPP_CR_1E512 18
208: #define FPP_CR_1E1024 19
209: #define FPP_CR_1E2048 20
210: #define FPP_CR_1E4096 21
211:
212: struct fpp_cr_entry_undef {
213: uae_u32 val[3];
214: };
215:
216: #define FPP_CR_NUM_SPECIAL_UNDEFINED 10
217:
218: // 68881 and 68882 have identical undefined fields
219: static const struct fpp_cr_entry_undef fpp_cr_undef[] = {
220: { {0x40000000, 0x00000000, 0x00000000} },
221: { {0x40010000, 0xfe000682, 0x00000000} },
222: { {0x40010000, 0xffc00503, 0x80000000} },
223: { {0x20000000, 0x7fffffff, 0x00000000} },
224: { {0x00000000, 0xffffffff, 0xffffffff} },
225: { {0x3c000000, 0xffffffff, 0xfffff800} },
226: { {0x3f800000, 0xffffff00, 0x00000000} },
227: { {0x00010000, 0xf65d8d9c, 0x00000000} },
228: { {0x7fff0000, 0x001e0000, 0x00000000} },
229: { {0x43ff0000, 0x000e0000, 0x00000000} },
230: { {0x407f0000, 0x00060000, 0x00000000} }
231: };
232:
233: uae_u32 xhex_nan[] ={0x7fff0000, 0xffffffff, 0xffffffff};
234:
1.1.1.4 root 235: static bool fpu_mmu_fixup;
1.1 root 236:
1.1.1.6 root 237: /* Floating Point Control Register (FPCR)
238: *
239: * Exception Enable Byte
240: * x--- ---- ---- ---- bit 15: BSUN (branch/set on unordered)
241: * -x-- ---- ---- ---- bit 14: SNAN (signaling not a number)
242: * --x- ---- ---- ---- bit 13: OPERR (operand error)
243: * ---x ---- ---- ---- bit 12: OVFL (overflow)
244: * ---- x--- ---- ---- bit 11: UNFL (underflow)
245: * ---- -x-- ---- ---- bit 10: DZ (divide by zero)
246: * ---- --x- ---- ---- bit 9: INEX 2 (inexact operation)
247: * ---- ---x ---- ---- bit 8: INEX 1 (inexact decimal input)
248: *
249: * Mode Control Byte
250: * ---- ---- xx-- ---- bits 7 and 6: PREC (rounding precision)
251: * ---- ---- --xx ---- bits 5 and 4: RND (rounding mode)
252: * ---- ---- ---- xxxx bits 3 to 0: all 0
253: */
254:
255: #define FPCR_PREC 0x00C0
256: #define FPCR_RND 0x0030
257:
258: /* Floating Point Status Register (FPSR)
259: *
260: * Condition Code Byte
261: * xxxx ---- ---- ---- ---- ---- ---- ---- bits 31 to 28: all 0
262: * ---- x--- ---- ---- ---- ---- ---- ---- bit 27: N (negative)
263: * ---- -x-- ---- ---- ---- ---- ---- ---- bit 26: Z (zero)
264: * ---- --x- ---- ---- ---- ---- ---- ---- bit 25: I (infinity)
265: * ---- ---x ---- ---- ---- ---- ---- ---- bit 24: NAN (not a number or unordered)
266: *
267: * Quotient Byte (set and reset only by FMOD and FREM)
268: * ---- ---- x--- ---- ---- ---- ---- ---- bit 23: sign of quotient
269: * ---- ---- -xxx xxxx ---- ---- ---- ---- bits 22 to 16: 7 least significant bits of quotient
270: *
271: * Exception Status Byte
272: * ---- ---- ---- ---- x--- ---- ---- ---- bit 15: BSUN (branch/set on unordered)
273: * ---- ---- ---- ---- -x-- ---- ---- ---- bit 14: SNAN (signaling not a number)
274: * ---- ---- ---- ---- --x- ---- ---- ---- bit 13: OPERR (operand error)
275: * ---- ---- ---- ---- ---x ---- ---- ---- bit 12: OVFL (overflow)
276: * ---- ---- ---- ---- ---- x--- ---- ---- bit 11: UNFL (underflow)
277: * ---- ---- ---- ---- ---- -x-- ---- ---- bit 10: DZ (divide by zero)
278: * ---- ---- ---- ---- ---- --x- ---- ---- bit 9: INEX 2 (inexact operation)
279: * ---- ---- ---- ---- ---- ---x ---- ---- bit 8: INEX 1 (inexact decimal input)
280: *
281: * Accrued Exception Byte
282: * ---- ---- ---- ---- ---- ---- x--- ---- bit 7: IOP (invalid operation)
283: * ---- ---- ---- ---- ---- ---- -x-- ---- bit 6: OVFL (overflow)
284: * ---- ---- ---- ---- ---- ---- --x- ---- bit 5: UNFL (underflow)
285: * ---- ---- ---- ---- ---- ---- ---x ---- bit 4: DZ (divide by zero)
286: * ---- ---- ---- ---- ---- ---- ---- x--- bit 3: INEX (inexact)
287: * ---- ---- ---- ---- ---- ---- ---- -xxx bits 2 to 0: all 0
288: */
289:
290: #define FPSR_ZEROBITS 0xF0000007
291:
292: #define FPSR_CC_N 0x08000000
293: #define FPSR_CC_Z 0x04000000
294: #define FPSR_CC_I 0x02000000
295: #define FPSR_CC_NAN 0x01000000
296:
297: #define FPSR_QUOT_SIGN 0x00800000
298: #define FPSR_QUOT_LSB 0x007F0000
299:
300: #define FPSR_AE_IOP 0x00000080
301: #define FPSR_AE_OVFL 0x00000040
302: #define FPSR_AE_UNFL 0x00000020
303: #define FPSR_AE_DZ 0x00000010
304: #define FPSR_AE_INEX 0x00000008
305:
306: static struct {
307: // 6888x and 68060
308: uae_u32 ccr;
309: uae_u32 eo[3];
310: // 68060
311: uae_u32 v;
312: // 68040
313: uae_u32 fpiarcu;
314: uae_u32 cmdreg3b;
315: uae_u32 cmdreg1b;
316: uae_u32 stag, dtag;
317: uae_u32 e1, e3, t;
318: uae_u32 fpt[3];
319: uae_u32 et[3];
320: uae_u32 wbt[3];
321: uae_u32 grs;
322: uae_u32 wbte15;
323: uae_u32 wbtm66;
324: } fsave_data;
1.1.1.4 root 325:
1.1.1.6 root 326: static void reset_fsave_data(void)
1.1 root 327: {
1.1.1.6 root 328: int i;
329: for (i = 0; i < 3; i++) {
330: fsave_data.eo[i] = 0;
331: fsave_data.fpt[i] = 0;
332: fsave_data.et[i] = 0;
333: fsave_data.wbt[i] = 0;
334: }
335: fsave_data.ccr = 0;
336: fsave_data.v = 0;
337: fsave_data.fpiarcu = 0;
338: fsave_data.cmdreg1b = 0;
339: fsave_data.cmdreg3b = 0;
340: fsave_data.stag = 0;
341: fsave_data.dtag = 0;
342: fsave_data.e1 = 0;
343: fsave_data.e3 = 0;
344: fsave_data.t = 0;
345: fsave_data.wbte15 = 0;
346: fsave_data.wbtm66 = 0;
347: fsave_data.grs = 0;
348: }
349:
350: static uae_u32 get_ftag(fpdata *src, int size)
351: {
1.1.1.7 ! root 352: fpp_is_init(src);
1.1.1.6 root 353: if (fpp_is_zero(src)) {
354: return 1; // ZERO
355: } else if (fpp_is_unnormal(src) || fpp_is_denormal(src)) {
356: if (size == 1 || size == 5)
357: return 5; // Single/double DENORMAL
358: return 4; // Extended DENORMAL or UNNORMAL
359: } else if (fpp_is_nan(src)) {
360: return 3; // NAN
361: } else if (fpp_is_infinity(src)) {
362: return 2; // INF
363: }
364: return 0; // NORMAL
1.1.1.4 root 365: }
1.1 root 366:
1.1.1.6 root 367: STATIC_INLINE bool fp_is_dyadic(uae_u16 extra)
1.1.1.4 root 368: {
1.1.1.6 root 369: return ((extra & 0x30) == 0x20 || (extra & 0x7f) == 0x38);
1.1.1.4 root 370: }
371:
1.1.1.6 root 372: static bool fp_exception_pending(bool pre)
1.1.1.4 root 373: {
1.1.1.6 root 374: // first check for pending arithmetic exceptions
1.1.1.7 ! root 375: if (support_exceptions && !jit_fpu()) {
1.1.1.6 root 376: if (regs.fp_exp_pend) {
377: if (warned > 0) {
378: write_log (_T("FPU ARITHMETIC EXCEPTION (%d)\n"), regs.fp_exp_pend);
379: }
380: regs.fpu_exp_pre = pre;
381: Exception(regs.fp_exp_pend);
382: if (currprefs.fpu_model != 68882)
383: regs.fp_exp_pend = 0;
384: return true;
385: }
386: }
387: // no arithmetic exceptions pending, check for unimplemented datatype
388: if (regs.fp_unimp_pend) {
389: if (warned > 0) {
390: write_log (_T("FPU unimplemented datatype exception (%s)\n"), pre ? _T("pre") : _T("mid/post"));
391: }
392: regs.fpu_exp_pre = pre;
393: Exception(55);
394: regs.fp_unimp_pend = 0;
395:
396: return true;
397: }
398: return false;
1.1.1.4 root 399: }
1.1.1.6 root 400:
401: static void fp_unimp_instruction_exception_pending(void)
1.1.1.4 root 402: {
1.1.1.6 root 403: if (regs.fp_unimp_ins) {
404: if (warned > 0) {
405: write_log (_T("FPU UNIMPLEMENTED INSTRUCTION/FPU DISABLED EXCEPTION PC=%08x\n"), M68K_GETPC);
406: }
407: regs.fpu_exp_pre = true;
408: Exception(11);
409: regs.fp_unimp_ins = false;
410: regs.fp_unimp_pend = 0;
411: }
1.1.1.4 root 412: }
413:
1.1.1.6 root 414: void fpsr_set_exception(uae_u32 exception)
1.1.1.4 root 415: {
1.1.1.6 root 416: regs.fpsr |= exception;
1.1 root 417: }
418:
1.1.1.6 root 419: static uae_u32 fpsr_get_vector(uae_u32 exception)
1.1.1.4 root 420: {
1.1.1.6 root 421: static const int vtable[8] = { 49, 49, 50, 51, 53, 52, 54, 48 };
422: int i;
423: exception >>= 8;
424: for (i = 7; i >= 0; i--) {
425: if (exception & (1 << i)) {
426: return vtable[i];
427: }
428: }
429: return 0;
1.1.1.4 root 430: }
1.1.1.6 root 431:
432: static void fpsr_check_arithmetic_exception(uae_u32 mask, fpdata *src, uae_u32 opcode, uae_u16 extra, uae_u32 ea)
1.1.1.4 root 433: {
1.1.1.7 ! root 434: if (!support_exceptions || jit_fpu())
1.1.1.6 root 435: return;
436:
437: bool nonmaskable;
438: uae_u32 exception;
439: // Any exception status bit and matching exception enable bits set?
440: exception = regs.fpsr & regs.fpcr & 0xff00;
1.1.1.7 ! root 441: // Add 68040/68060 nonmaskable exceptions. Only if no unimplemented instruction emulation.
! 442: if (currprefs.cpu_model >= 68040 && currprefs.fpu_model && currprefs.fpu_no_unimplemented) {
1.1.1.6 root 443: exception |= regs.fpsr & (FPSR_OVFL | FPSR_UNFL | mask);
1.1.1.7 ! root 444: }
1.1.1.6 root 445:
446: if (exception) {
447: regs.fp_exp_pend = fpsr_get_vector(exception);
448: nonmaskable = (regs.fp_exp_pend != fpsr_get_vector(regs.fpsr & regs.fpcr));
449: if (warned > 0) {
450: write_log(_T("FPU %s arithmetic exception pending: FPSR: %08x, FPCR: %04x (vector: %d)!\n"),
451: nonmaskable ? _T("nonmaskable") : _T(""), regs.fpsr, regs.fpcr, regs.fp_exp_pend);
452: #if EXCEPTION_FPP == 0
453: warned--;
454: #endif
455: }
456:
1.1.1.7 ! root 457: if (!support_exceptions || jit_fpu()) {
1.1.1.6 root 458: // log message and exit
459: regs.fp_exp_pend = 0;
460: return;
461: }
462:
463: regs.fp_opword = opcode;
464: regs.fp_ea = ea;
465:
466: // data for FSAVE stack frame
467: fpdata eo;
468: uae_u32 opclass = (extra >> 13) & 7;
469:
470: reset_fsave_data();
471:
472: if (currprefs.fpu_model == 68881 || currprefs.fpu_model == 68882) {
473: // fsave data for 68881 and 68882
474:
475: if (opclass == 3) { // 011
476: fsave_data.ccr = ((uae_u32)extra << 16) | extra;
477: } else { // 000 or 010
478: fsave_data.ccr = ((uae_u32)(opcode | 0x0080) << 16) | extra;
479: }
480: if (regs.fp_exp_pend == 54 || regs.fp_exp_pend == 52 || regs.fp_exp_pend == 50) { // SNAN, OPERR, DZ
481: fpp_from_exten_fmovem(src, &fsave_data.eo[0], &fsave_data.eo[1], &fsave_data.eo[2]);
482: if (regs.fp_exp_pend == 52 && opclass == 3) { // OPERR from move to integer or packed
483: fsave_data.eo[0] &= 0x4fff0000;
484: fsave_data.eo[1] = fsave_data.eo[2] = 0;
485: }
486: } else if (regs.fp_exp_pend == 53) { // OVFL
487: fpp_get_internal_overflow(&eo);
488: fpp_from_exten_fmovem(&eo, &fsave_data.eo[0], &fsave_data.eo[1], &fsave_data.eo[2]);
489: } else if (regs.fp_exp_pend == 51) { // UNFL
490: fpp_get_internal_underflow(&eo);
491: fpp_from_exten_fmovem(&eo, &fsave_data.eo[0], &fsave_data.eo[1], &fsave_data.eo[2]);
492: } // else INEX1, INEX2: do nothing
493:
494: } else if (currprefs.cpu_model == 68060) {
495: // fsave data for 68060
496: regs.fpu_exp_state = 2; // 68060 EXCP frame
497: fsave_data.v = regs.fp_exp_pend & 7;
498: fpp_from_exten_fmovem(src, &fsave_data.eo[0], &fsave_data.eo[1], &fsave_data.eo[2]);
499: } else {
500: // fsave data for 68040
501: regs.fpu_exp_state = 1; // 68040 UNIMP frame
502:
503: uae_u32 reg = (extra >> 7) & 7;
504: int size = (extra >> 10) & 7;
505:
506: fsave_data.fpiarcu = regs.fpiar;
507:
508: if (regs.fp_exp_pend == 54) { // SNAN (undocumented)
509: fsave_data.wbte15 = 1;
510: fsave_data.grs = 7;
511: } else {
512: fsave_data.grs = 1;
513: }
514:
515: if (opclass == 3) { // OPCLASS 011
516: fsave_data.cmdreg1b = extra;
517: fsave_data.e1 = 1;
518: fsave_data.t = 1;
519: fsave_data.wbte15 = (regs.fp_exp_pend == 51 || regs.fp_exp_pend == 54) ? 1 : 0; // UNFL, SNAN
520:
1.1.1.7 ! root 521: fpp_is_init(src);
1.1.1.6 root 522: if (fpp_is_snan(src)) {
523: fpp_unset_snan(src);
524: }
525: fpp_from_exten_fmovem(src, &fsave_data.et[0], &fsave_data.et[1], &fsave_data.et[2]);
526: fsave_data.stag = get_ftag(src, -1);
527: } else { // OPCLASS 000 and 010
528: fsave_data.cmdreg1b = extra;
529: fsave_data.e1 = 1;
530: fsave_data.wbte15 = (regs.fp_exp_pend == 54) ? 1 : 0; // SNAN (undocumented)
531:
532: if (regs.fp_exp_pend == 51 || regs.fp_exp_pend == 53 || regs.fp_exp_pend == 49) { // UNFL, OVFL, INEX
533: if ((extra & 0x30) == 0x20 || (extra & 0x3f) == 0x04) { // FADD, FSUB, FMUL, FDIV, FSQRT
534: regs.fpu_exp_state = 2; // 68040 BUSY frame
535: fsave_data.e3 = 1;
536: fsave_data.e1 = 0;
537: fsave_data.cmdreg3b = (extra & 0x3C3) | ((extra & 0x038)>>1) | ((extra & 0x004)<<3);
538: if (regs.fp_exp_pend == 51) { // UNFL
539: fpp_get_internal(&eo);
540: } else { // OVFL, INEX
541: fpp_get_internal_round(&eo);
542: }
543: fsave_data.grs = fpp_get_internal_grs();
544: fpp_from_exten_fmovem(&eo, &fsave_data.wbt[0], &fsave_data.wbt[1], &fsave_data.wbt[2]);
545: fsave_data.wbte15 = (regs.fp_exp_pend == 51) ? 1 : 0; // UNFL
546: // src and dst is stored (undocumented)
547: fpp_from_exten_fmovem(src, &fsave_data.et[0], &fsave_data.et[1], &fsave_data.et[2]);
548: fsave_data.stag = get_ftag(src, (opclass == 0) ? -1 : size);
549: if (fp_is_dyadic(extra)) {
550: fpp_from_exten_fmovem(®s.fp[reg], &fsave_data.fpt[0], &fsave_data.fpt[1], &fsave_data.fpt[2]);
551: fsave_data.dtag = get_ftag(®s.fp[reg], -1);
552: }
553: } else { // FMOVE to register, FABS, FNEG
554: fpp_get_internal_round_exten(&eo);
555: fsave_data.grs = fpp_get_internal_grs();
556: fpp_from_exten_fmovem(&eo, &fsave_data.fpt[0], &fsave_data.fpt[1], &fsave_data.fpt[2]);
557: fpp_get_internal_round_all(&eo); // weird
558: fpp_from_exten_fmovem(&eo, &fsave_data.et[0], &fsave_data.et[1], &fsave_data.et[2]); // undocumented
559: fsave_data.stag = get_ftag(src, (opclass == 0) ? -1 : size);
560: }
561: } else { // SNAN, OPERR, DZ
562: fpp_from_exten_fmovem(src, &fsave_data.et[0], &fsave_data.et[1], &fsave_data.et[2]);
563: fsave_data.stag = get_ftag(src, (opclass == 0) ? -1 : size);
564: if (fp_is_dyadic(extra)) {
565: fpp_from_exten_fmovem(®s.fp[reg], &fsave_data.fpt[0], &fsave_data.fpt[1], &fsave_data.fpt[2]);
566: fsave_data.dtag = get_ftag(®s.fp[reg], -1);
567: }
568: }
569: }
570: }
571: }
1.1.1.4 root 572: }
1.1 root 573:
1.1.1.6 root 574: static void fpsr_set_result(fpdata *result)
1.1 root 575: {
1.1.1.6 root 576: #ifdef JIT
577: regs.fp_result = *result;
1.1 root 578: #endif
1.1.1.6 root 579: // condition code byte
580: regs.fpsr &= 0x00fffff8; // clear cc
1.1.1.7 ! root 581: fpp_is_init(result);
! 582: if (fpp_is_nan(result)) {
1.1.1.6 root 583: regs.fpsr |= FPSR_CC_NAN;
584: } else if (fpp_is_zero(result)) {
585: regs.fpsr |= FPSR_CC_Z;
1.1.1.7 ! root 586: } else if (fpp_is_infinity(result)) {
1.1.1.6 root 587: regs.fpsr |= FPSR_CC_I;
588: }
589: if (fpp_is_neg(result))
590: regs.fpsr |= FPSR_CC_N;
1.1.1.4 root 591: }
1.1.1.6 root 592: static void fpsr_clear_status(void)
1.1.1.4 root 593: {
1.1.1.6 root 594: // clear exception status byte only
595: regs.fpsr &= 0x0fff00f8;
596:
597: // clear external status
598: fpp_clear_status();
1.1.1.4 root 599: }
1.1.1.6 root 600:
601: static uae_u32 fpsr_make_status(void)
1.1.1.4 root 602: {
1.1.1.6 root 603: uae_u32 exception;
604:
605: // get external status
606: fpp_get_status(®s.fpsr);
607:
608: // update accrued exception byte
609: if (regs.fpsr & (FPSR_BSUN | FPSR_SNAN | FPSR_OPERR))
610: regs.fpsr |= FPSR_AE_IOP; // IOP = BSUN || SNAN || OPERR
611: if (regs.fpsr & FPSR_OVFL)
612: regs.fpsr |= FPSR_AE_OVFL; // OVFL = OVFL
613: if ((regs.fpsr & FPSR_UNFL) && (regs.fpsr & FPSR_INEX2))
614: regs.fpsr |= FPSR_AE_UNFL; // UNFL = UNFL && INEX2
615: if (regs.fpsr & FPSR_DZ)
616: regs.fpsr |= FPSR_AE_DZ; // DZ = DZ
617: if (regs.fpsr & (FPSR_OVFL | FPSR_INEX2 | FPSR_INEX1))
618: regs.fpsr |= FPSR_AE_INEX; // INEX = INEX1 || INEX2 || OVFL
619:
1.1.1.7 ! root 620: if (!support_exceptions || jit_fpu())
1.1.1.6 root 621: return 0;
622:
623: // return exceptions that interrupt calculation
624: exception = regs.fpsr & regs.fpcr & (FPSR_SNAN | FPSR_OPERR | FPSR_DZ);
1.1.1.7 ! root 625: if (currprefs.cpu_model >= 68040 && currprefs.fpu_model && currprefs.fpu_no_unimplemented)
1.1.1.6 root 626: exception |= regs.fpsr & (FPSR_OVFL | FPSR_UNFL);
627:
628: return exception;
1.1.1.4 root 629: }
1.1.1.6 root 630:
631: static int fpsr_set_bsun(void)
1.1.1.4 root 632: {
1.1.1.6 root 633: regs.fpsr |= FPSR_BSUN;
634: regs.fpsr |= FPSR_AE_IOP;
635:
636: if (regs.fpcr & FPSR_BSUN) {
637: // logging only so far
638: write_log (_T("FPU exception: BSUN! (FPSR: %08x, FPCR: %04x)\n"), regs.fpsr, regs.fpcr);
1.1.1.7 ! root 639: if (support_exceptions && !jit_fpu()) {
1.1.1.6 root 640: regs.fp_exp_pend = fpsr_get_vector(FPSR_BSUN);
641: fp_exception_pending(true);
642: return 1;
643: }
644: }
645: return 0;
1.1.1.4 root 646: }
1.1.1.6 root 647:
648: static void fpsr_set_quotient(uae_u64 quot, uae_u8 sign)
1.1.1.4 root 649: {
1.1.1.6 root 650: regs.fpsr &= 0x0f00fff8;
651: regs.fpsr |= (quot << 16) & FPSR_QUOT_LSB;
652: regs.fpsr |= sign ? FPSR_QUOT_SIGN : 0;
1.1.1.4 root 653: }
1.1.1.6 root 654: static void fpsr_get_quotient(uae_u64 *quot, uae_u8 *sign)
1.1.1.4 root 655: {
1.1.1.6 root 656: *quot = (regs.fpsr & FPSR_QUOT_LSB) >> 16;
657: *sign = (regs.fpsr & FPSR_QUOT_SIGN) ? 1 : 0;
1.1 root 658: }
659:
1.1.1.6 root 660: uae_u32 fpp_get_fpsr (void)
1.1 root 661: {
1.1.1.6 root 662: #ifdef JIT
663: if (currprefs.cachesize && currprefs.compfpu) {
664: regs.fpsr &= 0x00fffff8; // clear cc
1.1.1.7 ! root 665: fpp_is_init(®s.fp_result);
! 666: if (fpp_is_nan(®s.fp_result)) {
1.1.1.6 root 667: regs.fpsr |= FPSR_CC_NAN;
668: } else if (fpp_is_zero(®s.fp_result)) {
669: regs.fpsr |= FPSR_CC_Z;
1.1.1.7 ! root 670: } else if (fpp_is_infinity(®s.fp_result)) {
1.1.1.6 root 671: regs.fpsr |= FPSR_CC_I;
672: }
673: if (fpp_is_neg(®s.fp_result))
674: regs.fpsr |= FPSR_CC_N;
1.1 root 675: }
1.1.1.4 root 676: #endif
1.1.1.7 ! root 677: return regs.fpsr & 0x0ffffff8;
! 678: }
! 679:
! 680: static uae_u32 fpp_get_fpcr(void)
! 681: {
! 682: return regs.fpcr & (currprefs.fpu_model == 68040 ? 0xffff : 0xfff0);
1.1.1.6 root 683: }
1.1 root 684:
1.1.1.6 root 685: static void fpp_set_fpcr (uae_u32 val)
1.1 root 686: {
1.1.1.6 root 687: fpp_set_mode(val);
688: regs.fpcr = val & 0xffff;
1.1 root 689: }
690:
1.1.1.6 root 691: static void fpnan (fpdata *fpd)
1.1.1.4 root 692: {
1.1.1.6 root 693: fpp_to_exten(fpd, xhex_nan[0], xhex_nan[1], xhex_nan[2]);
1.1.1.4 root 694: }
695:
1.1.1.6 root 696: static void fpclear (fpdata *fpd)
1.1.1.4 root 697: {
1.1.1.6 root 698: fpp_from_int(fpd, 0);
1.1.1.4 root 699: }
1.1.1.6 root 700: static void fpset (fpdata *fpd, uae_s32 val)
1.1.1.5 root 701: {
1.1.1.6 root 702: fpp_from_int(fpd, val);
1.1.1.5 root 703: }
704:
1.1.1.6 root 705: static void fpp_set_fpsr (uae_u32 val)
1.1.1.5 root 706: {
1.1.1.6 root 707: regs.fpsr = val;
708:
709: #ifdef JIT
710: // check comment in fpp_cond
711: if (currprefs.cachesize && currprefs.compfpu) {
712: if (val & 0x01000000)
713: fpnan(®s.fp_result);
714: else if (val & 0x04000000)
715: fpset(®s.fp_result, 0);
716: else if (val & 0x08000000)
717: fpset(®s.fp_result, -1);
718: else
719: fpset(®s.fp_result, 1);
1.1.1.5 root 720: }
1.1.1.4 root 721: #endif
1.1.1.5 root 722: }
723:
1.1.1.6 root 724: bool fpu_get_constant(fpdata *fpd, int cr)
1.1.1.5 root 725: {
1.1.1.6 root 726: uae_u32 f[3] = { 0, 0, 0 };
727: int entry = 0;
728: bool round = true;
729: int mode = (regs.fpcr >> 4) & 3;
730: int prec = (regs.fpcr >> 6) & 3;
731:
732: switch (cr)
733: {
734: case 0x00: // pi
735: entry = FPP_CR_PI;
736: break;
737: case 0x0b: // log10(2)
738: entry = FPP_CR_LOG10_2;
739: break;
740: case 0x0c: // e
741: entry = FPP_CR_E;
742: break;
743: case 0x0d: // log2(e)
744: entry = FPP_CR_LOG2_E;
745: break;
746: case 0x0e: // log10(e)
747: entry = FPP_CR_LOG10_E;
748: break;
749: case 0x0f: // 0.0
750: entry = FPP_CR_ZERO;
751: break;
752: case 0x30: // ln(2)
753: entry = FPP_CR_LN_2;
754: break;
755: case 0x31: // ln(10)
756: entry = FPP_CR_LN_10;
757: break;
758: case 0x32: // 1e0
759: entry = FPP_CR_1E0;
760: break;
761: case 0x33: // 1e1
762: entry = FPP_CR_1E1;
763: break;
764: case 0x34: // 1e2
765: entry = FPP_CR_1E2;
766: break;
767: case 0x35: // 1e4
768: entry = FPP_CR_1E4;
769: break;
770: case 0x36: // 1e8
771: entry = FPP_CR_1E8;
772: break;
773: case 0x37: // 1e16
774: entry = FPP_CR_1E16;
775: break;
776: case 0x38: // 1e32
777: entry = FPP_CR_1E32;
778: break;
779: case 0x39: // 1e64
780: entry = FPP_CR_1E64;
781: break;
782: case 0x3a: // 1e128
783: entry = FPP_CR_1E128;
784: break;
785: case 0x3b: // 1e256
786: entry = FPP_CR_1E256;
787: break;
788: case 0x3c: // 1e512
789: entry = FPP_CR_1E512;
790: break;
791: case 0x3d: // 1e1024
792: entry = FPP_CR_1E1024;
793: break;
794: case 0x3e: // 1e2048
795: entry = FPP_CR_1E2048;
796: break;
797: case 0x3f: // 1e4096
798: entry = FPP_CR_1E4096;
799: break;
800: default: // undefined
801: {
802: bool check_f1_adjust = false;
803: int f1_adjust = 0;
804: uae_u32 sr = 0;
805:
806: if (cr > FPP_CR_NUM_SPECIAL_UNDEFINED) {
807: cr = 0; // Most undefined fields contain this
808: }
809: f[0] = fpp_cr_undef[cr].val[0];
810: f[1] = fpp_cr_undef[cr].val[1];
811: f[2] = fpp_cr_undef[cr].val[2];
812: // Rounding mode and precision works very strangely here..
813: switch (cr)
814: {
815: case 1:
816: check_f1_adjust = true;
817: break;
818: case 2:
819: if (prec == 1 && mode == 3)
820: f1_adjust = -1;
821: break;
822: case 3:
823: if (prec == 1 && (mode == 0 || mode == 3))
824: sr |= FPSR_CC_I;
825: else
826: sr |= FPSR_CC_NAN;
827: break;
828: case 7:
829: sr |= FPSR_CC_NAN;
830: check_f1_adjust = true;
831: break;
832: }
833: if (check_f1_adjust) {
834: if (prec == 1) {
835: if (mode == 0) {
836: f1_adjust = -1;
837: } else if (mode == 1 || mode == 2) {
838: f1_adjust = 1;
839: }
840: }
841: }
842: fpp_to_exten_fmovem(fpd, f[0], f[1], f[2]);
843: if (prec == 1)
844: fpp_round32(fpd);
845: if (prec >= 2)
846: fpp_round64(fpd);
847:
848: if (f1_adjust) {
849: fpp_from_exten_fmovem(fpd, &f[0], &f[1], &f[2]);
850: f[1] += f1_adjust * 0x80;
851: fpp_to_exten_fmovem(fpd, f[0], f[1], f[2]);
852: }
853:
854: fpsr_set_result(fpd);
855: regs.fpsr |= sr;
856: return false;
857: }
1.1.1.5 root 858: }
1.1 root 859:
1.1.1.6 root 860: f[0] = fpp_cr[entry].val[0];
861: f[1] = fpp_cr[entry].val[1];
862: f[2] = fpp_cr[entry].val[2];
863: // if constant is inexact, set inexact bit and round
864: // note: with valid constants, LSB never wraps
865: if (fpp_cr[entry].inexact) {
866: fpsr_set_exception(FPSR_INEX2);
867: f[2] += fpp_cr[entry].rndoff[mode];
868: }
1.1 root 869:
1.1.1.6 root 870: fpp_to_exten_fmovem(fpd, f[0], f[1], f[2]);
871:
872: if (prec == 1)
873: fpp_round32(fpd);
874: if (prec >= 2)
875: fpp_round64(fpd);
876:
877: fpsr_set_result(fpd);
878:
879: return true;
880: }
881:
882: #if 0
1.1.1.4 root 883: static void fpu_format_error (void)
1.1 root 884: {
1.1.1.4 root 885: uaecptr newpc;
886: regs.t0 = regs.t1 = 0;
887: MakeSR ();
888: if (!regs.s) {
889: regs.usp = m68k_areg (regs, 7);
890: m68k_areg (regs, 7) = regs.isp;
891: }
892: regs.s = 1;
893: m68k_areg (regs, 7) -= 2;
1.1.1.7 ! root 894: x_cp_put_long (m68k_areg (regs, 7), 0x0000 + 14 * 4);
1.1.1.4 root 895: m68k_areg (regs, 7) -= 4;
1.1.1.7 ! root 896: x_cp_put_long (m68k_areg (regs, 7), m68k_getpc ());
1.1.1.4 root 897: m68k_areg (regs, 7) -= 2;
1.1.1.7 ! root 898: x_cp_put_long (m68k_areg (regs, 7), regs.sr);
! 899: newpc = x_cp_get_long (regs.vbr + 14 * 4);
1.1.1.4 root 900: m68k_setpc (newpc);
901: #ifdef JIT
902: set_special (SPCFLAG_END_COMPILE);
1.1.1.2 root 903: #endif
1.1.1.4 root 904: regs.fp_exception = true;
1.1 root 905: }
1.1.1.6 root 906: #endif
1.1 root 907:
1.1.1.6 root 908: static void fp_unimp_instruction(uae_u16 opcode, uae_u16 extra, uae_u32 ea, uaecptr oldpc, fpdata *src, int reg, int size)
909: {
910: if ((extra & 0x7f) == 4) // FSQRT 4->5
911: extra |= 1;
1.1.1.4 root 912:
1.1.1.6 root 913: // data for fsave stack frame
914: regs.fpu_exp_state = 1; // 68060 IDLE frame, 68040 UNIMP frame
915:
916: if (currprefs.cpu_model == 68060) {
917: // fsave data for 68060
918: reset_fsave_data();
919: } else if(currprefs.cpu_model == 68040) {
920: // fsave data for 68040
921: fsave_data.fpiarcu = regs.fpiar;
922:
923: if (regs.fp_unimp_pend == 0) { // else data has been saved by fp_unimp_datatype
924: reset_fsave_data();
925: fsave_data.cmdreg3b = (extra & 0x3C3) | ((extra & 0x038) >> 1) | ((extra & 0x004) << 3);
926: fsave_data.cmdreg1b = extra;
927: fpp_from_exten_fmovem(src, &fsave_data.et[0], &fsave_data.et[1], &fsave_data.et[2]);
928: fsave_data.stag = get_ftag(src, size);
929: if (reg >= 0) {
930: fpp_from_exten_fmovem(®s.fp[reg], &fsave_data.fpt[0], &fsave_data.fpt[1], &fsave_data.fpt[2]);
931: fsave_data.dtag = get_ftag(®s.fp[reg], -1);
932: }
1.1.1.4 root 933: }
934: }
1.1.1.6 root 935: if (warned > 0) {
936: write_log (_T("FPU unimplemented instruction: OP=%04X-%04X SRC=%08X-%08X-%08X EA=%08X PC=%08X\n"),
937: opcode, extra, fsave_data.et[0],fsave_data.et[1],fsave_data.et[2], ea, oldpc);
938: #if EXCEPTION_FPP == 0
939: warned--;
940: #endif
941: }
942:
943: regs.fp_ea = ea;
944: regs.fp_unimp_ins = true;
945: fp_unimp_instruction_exception_pending();
946:
947: regs.fp_exception = true;
948:
949: }
950:
951: static void fp_unimp_datatype(uae_u16 opcode, uae_u16 extra, uae_u32 ea, uaecptr oldpc, fpdata *src, uae_u32 *packed)
952: {
953: uae_u32 reg = (extra >> 7) & 7;
954: uae_u32 size = (extra >> 10) & 7;
955: uae_u32 opclass = (extra >> 13) & 7;
956:
957: regs.fp_opword = opcode;
958: regs.fp_ea = ea;
959: regs.fp_unimp_pend = packed ? 2 : 1;
960:
961: if((extra & 0x7f) == 4) // FSQRT 4->5
962: extra |= 1;
963:
964: // data for fsave stack frame
965: reset_fsave_data();
966: regs.fpu_exp_state = 2; // 68060 EXCP frame, 68040 BUSY frame
967:
1.1.1.4 root 968: if (currprefs.cpu_model == 68060) {
1.1.1.6 root 969: // fsave data for 68060
970: if (packed) {
971: regs.fpu_exp_state = 1; // 68060 IDLE frame
972: } else {
973: fsave_data.v = 7; // vector & 0x7
974: fpp_from_exten_fmovem(src, &fsave_data.eo[0], &fsave_data.eo[1], &fsave_data.eo[2]);
1.1.1.4 root 975: }
976: } else if (currprefs.cpu_model == 68040) {
1.1.1.6 root 977: // fsave data for 68040
978: fsave_data.cmdreg1b = extra;
979: fsave_data.fpiarcu = regs.fpiar;
980: if (packed) {
981: fsave_data.e1 = 1; // used to distinguish packed operands
982: }
983: if (opclass == 3) { // OPCLASS 011
984: fsave_data.t = 1;
985: fpp_from_exten_fmovem(src, &fsave_data.et[0], &fsave_data.et[1], &fsave_data.et[2]);
986: fsave_data.stag = get_ftag(src, -1);
987: fpp_from_exten_fmovem(src, &fsave_data.fpt[0], &fsave_data.fpt[1], &fsave_data.fpt[2]); // undocumented
988: fsave_data.dtag = get_ftag(src, -1); // undocumented
989: } else { // OPCLASS 000 and 010
990: if (packed) {
991: fsave_data.fpt[2] = packed[0]; // yes, this is correct.
992: fsave_data.fpt[1] = packed[1]; // undocumented
993: fsave_data.et[1] = packed[1];
994: fsave_data.et[2] = packed[2];
995: fsave_data.stag = 7; // undocumented
996: } else {
997: fpp_from_exten_fmovem(src, &fsave_data.et[0], &fsave_data.et[1], &fsave_data.et[2]);
1.1.1.7 ! root 998: fsave_data.stag = get_ftag(src, (opclass == 0) ? -1U : size);
1.1.1.6 root 999: if (fsave_data.stag == 5) {
1000: fsave_data.et[0] = (size == 1) ? 0x3f800000 : 0x3c000000; // exponent for denormalized single and double
1001: }
1002: if (fp_is_dyadic(extra)) {
1003: fpp_from_exten_fmovem(®s.fp[reg], &fsave_data.fpt[0], &fsave_data.fpt[1], &fsave_data.fpt[2]);
1004: fsave_data.dtag = get_ftag(®s.fp[reg], -1);
1005: }
1006: }
1.1.1.4 root 1007: }
1008: }
1009: if (warned > 0) {
1.1.1.6 root 1010: write_log (_T("FPU unimplemented datatype (%s): OP=%04X-%04X SRC=%08X-%08X-%08X EA=%08X PC=%08X\n"),
1.1.1.7 ! root 1011: packed ? _T("packed") : _T("denormal"), opcode, extra,
1.1.1.6 root 1012: packed ? fsave_data.fpt[2] : fsave_data.et[0], fsave_data.et[1], fsave_data.et[2], ea, oldpc);
1.1.1.4 root 1013: #if EXCEPTION_FPP == 0
1014: warned--;
1015: #endif
1016: }
1017: regs.fp_exception = true;
1018: }
1019:
1.1.1.6 root 1020: static void fpu_op_illg(uae_u16 opcode, uae_u32 ea, uaecptr oldpc)
1.1.1.4 root 1021: {
1022: if ((currprefs.cpu_model == 68060 && (currprefs.fpu_model == 0 || (regs.pcr & 2)))
1023: || (currprefs.cpu_model == 68040 && currprefs.fpu_model == 0)) {
1.1.1.6 root 1024: regs.fp_unimp_ins = true;
1025: regs.fp_ea = ea;
1026: fp_unimp_instruction_exception_pending();
1.1.1.4 root 1027: return;
1028: }
1029: regs.fp_exception = true;
1030: m68k_setpc (oldpc);
1031: op_illg (opcode);
1032: }
1033:
1034: static void fpu_noinst (uae_u16 opcode, uaecptr pc)
1035: {
1036: #if EXCEPTION_FPP
1037: write_log (_T("Unknown FPU instruction %04X %08X\n"), opcode, pc);
1038: #endif
1039: regs.fp_exception = true;
1040: m68k_setpc (pc);
1041: op_illg (opcode);
1042: }
1043:
1.1.1.6 root 1044: static bool if_no_fpu(void)
1045: {
1046: return (regs.pcr & 2) || currprefs.fpu_model <= 0;
1047: }
1048:
1.1.1.4 root 1049: static bool fault_if_no_fpu (uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc)
1050: {
1.1.1.6 root 1051: if (if_no_fpu()) {
1.1.1.4 root 1052: #if EXCEPTION_FPP
1053: write_log (_T("no FPU: %04X-%04X PC=%08X\n"), opcode, extra, oldpc);
1054: #endif
1.1.1.6 root 1055: if (fpu_mmu_fixup) {
1056: m68k_areg (regs, mmufixup[0].reg) = mmufixup[0].value;
1057: mmufixup[0].reg = -1;
1058:
1059: }
1060: fpu_op_illg(opcode, ea, oldpc);
1.1.1.4 root 1061: return true;
1062: }
1063: return false;
1064: }
1065:
1066: static bool fault_if_unimplemented_680x0 (uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc, fpdata *src, int reg)
1067: {
1068: if (fault_if_no_fpu (opcode, extra, ea, oldpc))
1069: return true;
1070: if (currprefs.cpu_model >= 68040 && currprefs.fpu_model && currprefs.fpu_no_unimplemented) {
1071: if ((extra & (0x8000 | 0x2000)) != 0)
1072: return false;
1073: if ((extra & 0xfc00) == 0x5c00) {
1074: // FMOVECR
1.1.1.6 root 1075: fp_unimp_instruction(opcode, extra, ea, oldpc, src, reg, -1);
1.1.1.4 root 1076: return true;
1077: }
1078: uae_u16 v = extra & 0x7f;
1.1.1.6 root 1079: /* 68040/68060 only variants. 6888x = F-line exception. */
1.1.1.4 root 1080: switch (v)
1081: {
1.1.1.6 root 1082: case 0x00: /* FMOVE */
1083: case 0x40: /* FSMOVE */
1084: case 0x44: /* FDMOVE */
1085: case 0x04: /* FSQRT */
1086: case 0x41: /* FSSQRT */
1087: case 0x45: /* FDSQRT */
1088: case 0x18: /* FABS */
1089: case 0x58: /* FSABS */
1090: case 0x5c: /* FDABS */
1091: case 0x1a: /* FNEG */
1092: case 0x5a: /* FSNEG */
1093: case 0x5e: /* FDNEG */
1094: case 0x20: /* FDIV */
1095: case 0x60: /* FSDIV */
1096: case 0x64: /* FDDIV */
1097: case 0x22: /* FADD */
1098: case 0x62: /* FSADD */
1099: case 0x66: /* FDADD */
1100: case 0x23: /* FMUL */
1101: case 0x63: /* FSMUL */
1102: case 0x67: /* FDMUL */
1103: case 0x24: /* FSGLDIV */
1104: case 0x27: /* FSGLMUL */
1105: case 0x28: /* FSUB */
1106: case 0x68: /* FSSUB */
1107: case 0x6c: /* FDSUB */
1108: case 0x38: /* FCMP */
1109: case 0x3a: /* FTST */
1110: return false;
1.1.1.4 root 1111: case 0x01: /* FINT */
1112: case 0x03: /* FINTRZ */
1113: // Unimplemented only in 68040.
1.1.1.6 root 1114: if(currprefs.cpu_model != 68040) {
1115: return false;
1.1.1.4 root 1116: }
1.1.1.6 root 1117: default:
1118: fp_unimp_instruction(opcode, extra, ea, oldpc, src, reg, -1);
1119: return true;
1120: }
1121: }
1122: return false;
1123: }
1124:
1125: static bool fault_if_unimplemented_6888x (uae_u16 opcode, uae_u16 extra, uaecptr oldpc)
1126: {
1127: if ((currprefs.fpu_model == 68881 || currprefs.fpu_model == 68882) && currprefs.fpu_no_unimplemented) {
1128: uae_u16 v = extra & 0x7f;
1129: switch(v)
1130: {
1131: case 0x00: /* FMOVE */
1132: case 0x01: /* FINT */
1.1.1.4 root 1133: case 0x02: /* FSINH */
1.1.1.6 root 1134: case 0x03: /* FINTRZ */
1135: case 0x04: /* FSQRT */
1.1.1.4 root 1136: case 0x06: /* FLOGNP1 */
1137: case 0x08: /* FETOXM1 */
1138: case 0x09: /* FTANH */
1139: case 0x0a: /* FATAN */
1140: case 0x0c: /* FASIN */
1141: case 0x0d: /* FATANH */
1142: case 0x0e: /* FSIN */
1143: case 0x0f: /* FTAN */
1144: case 0x10: /* FETOX */
1145: case 0x11: /* FTWOTOX */
1146: case 0x12: /* FTENTOX */
1147: case 0x14: /* FLOGN */
1148: case 0x15: /* FLOG10 */
1149: case 0x16: /* FLOG2 */
1.1.1.6 root 1150: case 0x18: /* FABS */
1.1.1.4 root 1151: case 0x19: /* FCOSH */
1.1.1.6 root 1152: case 0x1a: /* FNEG */
1.1.1.4 root 1153: case 0x1c: /* FACOS */
1154: case 0x1d: /* FCOS */
1155: case 0x1e: /* FGETEXP */
1156: case 0x1f: /* FGETMAN */
1.1.1.6 root 1157: case 0x20: /* FDIV */
1158: case 0x21: /* FMOD */
1159: case 0x22: /* FADD */
1160: case 0x23: /* FMUL */
1161: case 0x24: /* FSGLDIV */
1162: case 0x25: /* FREM */
1163: case 0x26: /* FSCALE */
1164: case 0x27: /* FSGLMUL */
1165: case 0x28: /* FSUB */
1.1.1.4 root 1166: case 0x30: /* FSINCOS */
1167: case 0x31: /* FSINCOS */
1168: case 0x32: /* FSINCOS */
1169: case 0x33: /* FSINCOS */
1170: case 0x34: /* FSINCOS */
1171: case 0x35: /* FSINCOS */
1172: case 0x36: /* FSINCOS */
1173: case 0x37: /* FSINCOS */
1.1.1.6 root 1174: case 0x38: /* FCMP */
1175: case 0x3a: /* FTST */
1176: return false;
1177: default:
1178: fpu_noinst (opcode, oldpc);
1179: return true;
1.1.1.4 root 1180: }
1181: }
1182: return false;
1183: }
1184:
1.1.1.6 root 1185: static bool fault_if_60 (void)
1.1.1.4 root 1186: {
1187: if (currprefs.cpu_model == 68060 && currprefs.fpu_model && currprefs.fpu_no_unimplemented) {
1.1.1.6 root 1188: Exception(60);
1.1.1.4 root 1189: return true;
1190: }
1191: return false;
1192: }
1193:
1194: static bool fault_if_no_fpu_u (uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc)
1195: {
1196: if (fault_if_no_fpu (opcode, extra, ea, oldpc))
1197: return true;
1198: if (currprefs.cpu_model == 68060 && currprefs.fpu_model && currprefs.fpu_no_unimplemented) {
1199: // 68060 FTRAP, FDBcc or FScc are not implemented.
1.1.1.6 root 1200: regs.fp_unimp_ins = true;
1201: regs.fp_ea = ea;
1202: fp_unimp_instruction_exception_pending();
1.1.1.4 root 1203: return true;
1204: }
1205: return false;
1206: }
1207:
1208: static bool fault_if_no_6888x (uae_u16 opcode, uae_u16 extra, uaecptr oldpc)
1209: {
1210: if (currprefs.cpu_model < 68040 && currprefs.fpu_model <= 0) {
1211: #if EXCEPTION_FPP
1212: write_log (_T("6888x no FPU: %04X-%04X PC=%08X\n"), opcode, extra, oldpc);
1213: #endif
1214: m68k_setpc (oldpc);
1215: regs.fp_exception = true;
1216: op_illg (opcode);
1.1.1.6 root 1217: return true;
1218: }
1219: return false;
1.1.1.4 root 1220: }
1221:
1.1.1.6 root 1222: static int get_fpu_version (int model)
1.1.1.4 root 1223: {
1.1.1.6 root 1224: int v = 0;
1.1.1.4 root 1225:
1.1.1.6 root 1226: switch (model)
1227: {
1228: case 68881:
1229: case 68882:
1230: v = 0x1f;
1231: break;
1232: case 68040:
1233: if (currprefs.fpu_revision == 0x40)
1234: v = 0x40;
1235: else
1236: v = 0x41;
1237: break;
1.1.1.4 root 1238: }
1.1.1.6 root 1239: return v;
1240: }
1.1.1.4 root 1241:
1.1.1.6 root 1242: static void fpu_null (void)
1243: {
1244: regs.fpu_state = 0;
1245: regs.fpu_exp_state = 0;
1246: regs.fpcr = 0;
1247: regs.fpsr = 0;
1248: regs.fpiar = 0;
1.1.1.7 ! root 1249: for (int i = 0; i < 8; i++)
1.1.1.6 root 1250: fpnan (®s.fp[i]);
1251: }
1.1.1.4 root 1252:
1.1.1.6 root 1253: // 68040/060 does not support denormals
1254: static bool normalize_or_fault_if_no_denormal_support(uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc, fpdata *src)
1255: {
1.1.1.7 ! root 1256: if (!support_denormals)
1.1.1.6 root 1257: return false;
1.1.1.7 ! root 1258: fpp_is_init(src);
1.1.1.6 root 1259: if (fpp_is_unnormal(src) || fpp_is_denormal(src)) {
1260: if (currprefs.cpu_model >= 68040 && currprefs.fpu_model && currprefs.fpu_no_unimplemented) {
1261: if (fpp_is_zero(src)) {
1262: fpp_normalize(src); // 68040/060 can only fix unnormal zeros
1.1.1.4 root 1263: } else {
1.1.1.6 root 1264: fp_unimp_datatype(opcode, extra, ea, oldpc, src, NULL);
1265: return true;
1.1.1.4 root 1266: }
1.1.1.6 root 1267: } else {
1268: fpp_normalize(src);
1.1.1.4 root 1269: }
1270: }
1.1.1.6 root 1271: return false;
1272: }
1273: static bool normalize_or_fault_if_no_denormal_support_dst(uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc, fpdata *dst, fpdata *src)
1274: {
1.1.1.7 ! root 1275: if (!support_denormals)
1.1.1.6 root 1276: return false;
1.1.1.7 ! root 1277: fpp_is_init(dst);
1.1.1.6 root 1278: if (fpp_is_unnormal(dst) || fpp_is_denormal(dst)) {
1279: if (currprefs.cpu_model >= 68040 && currprefs.fpu_model && currprefs.fpu_no_unimplemented) {
1280: if (fpp_is_zero(dst)) {
1281: fpp_normalize(dst); // 68040/060 can only fix unnormal zeros
1282: } else {
1283: fp_unimp_datatype(opcode, extra, ea, oldpc, src, NULL);
1284: return true;
1285: }
1286: } else {
1287: fpp_normalize(dst);
1.1.1.4 root 1288: }
1289: }
1.1.1.6 root 1290: return false;
1.1.1.4 root 1291: }
1292:
1.1.1.6 root 1293: // 68040/060 does not support packed decimal format
1294: static bool fault_if_no_packed_support(uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc, fpdata *src, uae_u32 *packed)
1.1.1.4 root 1295: {
1.1.1.6 root 1296: if (currprefs.cpu_model >= 68040 && currprefs.fpu_model && currprefs.fpu_no_unimplemented) {
1297: fp_unimp_datatype(opcode, extra, ea, oldpc, src, packed);
1298: return true;
1.1.1.4 root 1299: }
1300: return false;
1.1.1.6 root 1301: }
1302:
1303: // 68040 does not support move to integer format
1304: static bool fault_if_68040_integer_nonmaskable(uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc, fpdata *src)
1.1.1.4 root 1305: {
1.1.1.7 ! root 1306: if (currprefs.cpu_model == 68040 && currprefs.fpu_model && currprefs.fpu_mode > 0) {
1.1.1.6 root 1307: fpsr_make_status();
1308: if (regs.fpsr & (FPSR_SNAN | FPSR_OPERR)) {
1309: fpsr_check_arithmetic_exception(FPSR_SNAN | FPSR_OPERR, src, opcode, extra, ea);
1310: fp_exception_pending(false); // post
1.1.1.4 root 1311: return true;
1.1 root 1312: }
1313: }
1.1.1.4 root 1314: return false;
1.1 root 1315: }
1316:
1.1.1.4 root 1317: static int get_fp_value (uae_u32 opcode, uae_u16 extra, fpdata *src, uaecptr oldpc, uae_u32 *adp)
1.1 root 1318: {
1319: int size, mode, reg;
1320: uae_u32 ad = 0;
1321: static const int sz1[8] = { 4, 4, 12, 12, 2, 8, 1, 0 };
1322: static const int sz2[8] = { 4, 4, 12, 12, 2, 8, 2, 0 };
1.1.1.5 root 1323: #ifndef WINUAE_FOR_HATARI
1.1.1.4 root 1324: uae_u32 exts[3];
1.1.1.5 root 1325: #else
1326: uae_u32 exts[3] = { 0 };
1327: #endif
1.1.1.4 root 1328: int doext = 0;
1.1 root 1329:
1330: if (!(extra & 0x4000)) {
1.1.1.4 root 1331: if (fault_if_no_fpu (opcode, extra, 0, oldpc))
1332: return -1;
1.1 root 1333: *src = regs.fp[(extra >> 10) & 7];
1.1.1.6 root 1334: normalize_or_fault_if_no_denormal_support(opcode, extra, 0, oldpc, src);
1.1 root 1335: return 1;
1336: }
1337: mode = (opcode >> 3) & 7;
1338: reg = opcode & 7;
1339: size = (extra >> 10) & 7;
1340:
1341: switch (mode) {
1.1.1.7 ! root 1342: case 0: // Dn
1.1.1.6 root 1343: if ((size == 0 || size == 1 ||size == 4 || size == 6) && fault_if_no_fpu (opcode, extra, 0, oldpc))
1344: return -1;
1.1.1.4 root 1345: switch (size)
1346: {
1347: case 6:
1348: fpset(src, (uae_s8) m68k_dreg (regs, reg));
1349: break;
1350: case 4:
1351: fpset(src, (uae_s16) m68k_dreg (regs, reg));
1352: break;
1353: case 0:
1354: fpset(src, (uae_s32) m68k_dreg (regs, reg));
1355: break;
1356: case 1:
1.1.1.6 root 1357: fpp_to_single (src, m68k_dreg (regs, reg));
1358: normalize_or_fault_if_no_denormal_support(opcode, extra, 0, oldpc, src);
1.1.1.4 root 1359: break;
1360: default:
1361: return 0;
1.1 root 1362: }
1363: return 1;
1.1.1.7 ! root 1364: case 1: // An
1.1 root 1365: return 0;
1.1.1.7 ! root 1366: case 2: // (An)
1.1 root 1367: ad = m68k_areg (regs, reg);
1368: break;
1.1.1.7 ! root 1369: case 3: // (An)+
1.1.1.6 root 1370: // Also needed by fault_if_no_fpu
1371: mmufixup[0].reg = reg;
1372: mmufixup[0].value = m68k_areg (regs, reg);
1373: fpu_mmu_fixup = true;
1.1 root 1374: ad = m68k_areg (regs, reg);
1375: m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size];
1376: break;
1.1.1.7 ! root 1377: case 4: // -(An)
1.1.1.6 root 1378: // Also needed by fault_if_no_fpu
1379: mmufixup[0].reg = reg;
1380: mmufixup[0].value = m68k_areg (regs, reg);
1381: fpu_mmu_fixup = true;
1.1 root 1382: m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size];
1383: ad = m68k_areg (regs, reg);
1.1.1.6 root 1384: // 68060 no fpu -(an): EA points to -4, not -12 if extended precision
1385: if (currprefs.cpu_model == 68060 && if_no_fpu() && sz1[size] == 12)
1386: ad += 8;
1.1 root 1387: break;
1.1.1.7 ! root 1388: case 5: // (d16,An)
1.1.1.4 root 1389: ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) x_cp_next_iword ();
1.1 root 1390: break;
1.1.1.7 ! root 1391: case 6: // (d8,An,Xn)+
1.1.1.4 root 1392: ad = x_cp_get_disp_ea_020 (m68k_areg (regs, reg), 0);
1.1 root 1393: break;
1394: case 7:
1.1.1.4 root 1395: switch (reg)
1396: {
1397: case 0: // (xxx).W
1398: ad = (uae_s32) (uae_s16) x_cp_next_iword ();
1399: break;
1400: case 1: // (xxx).L
1401: ad = x_cp_next_ilong ();
1402: break;
1403: case 2: // (d16,PC)
1404: ad = m68k_getpc ();
1405: ad += (uae_s32) (uae_s16) x_cp_next_iword ();
1406: break;
1407: case 3: // (d8,PC,Xn)+
1408: ad = x_cp_get_disp_ea_020 (m68k_getpc (), 0);
1409: break;
1410: case 4: // #imm
1411: doext = 1;
1412: switch (size)
1413: {
1414: case 0: // L
1415: case 1: // S
1416: exts[0] = x_cp_next_ilong ();
1417: break;
1418: case 2: // X
1419: case 3: // P
1420: // 68060 and immediate X or P: unimplemented effective address
1.1.1.6 root 1421: if (fault_if_60())
1.1.1.4 root 1422: return -1;
1423: exts[0] = x_cp_next_ilong ();
1424: exts[1] = x_cp_next_ilong ();
1425: exts[2] = x_cp_next_ilong ();
1426: break;
1427: case 4: // W
1428: exts[0] = x_cp_next_iword ();
1429: break;
1430: case 5: // D
1431: exts[0] = x_cp_next_ilong ();
1432: exts[1] = x_cp_next_ilong ();
1433: break;
1434: case 6: // B
1435: exts[0] = x_cp_next_iword ();
1436: break;
1437: }
1438: break;
1439: default:
1440: return 0;
1441: }
1442: }
1443:
1444:
1.1.1.6 root 1445: if (fault_if_no_fpu (opcode, extra, ad, oldpc))
1.1.1.4 root 1446: return -1;
1447:
1.1.1.6 root 1448: *adp = ad;
1449: uae_u32 adold = ad;
1450:
1451: if (currprefs.fpu_model == 68060) {
1452: // Skip if 68040 because FSAVE frame can store both src and dst
1453: if (fault_if_unimplemented_680x0(opcode, extra, ad, oldpc, src, -1)) {
1454: return -1;
1455: }
1456: }
1457:
1.1.1.4 root 1458: switch (size)
1459: {
1.1.1.7 ! root 1460: case 0: // L
1.1.1.4 root 1461: fpset(src, (uae_s32) (doext ? exts[0] : x_cp_get_long (ad)));
1.1 root 1462: break;
1.1.1.7 ! root 1463: case 1: // S
1.1.1.6 root 1464: fpp_to_single (src, (doext ? exts[0] : x_cp_get_long (ad)));
1465: normalize_or_fault_if_no_denormal_support(opcode, extra, adold, oldpc, src);
1.1 root 1466: break;
1.1.1.7 ! root 1467: case 2: // X
1.1.1.4 root 1468: {
1469: uae_u32 wrd1, wrd2, wrd3;
1470: wrd1 = (doext ? exts[0] : x_cp_get_long (ad));
1471: ad += 4;
1472: wrd2 = (doext ? exts[1] : x_cp_get_long (ad));
1473: ad += 4;
1474: wrd3 = (doext ? exts[2] : x_cp_get_long (ad));
1.1.1.6 root 1475: fpp_to_exten (src, wrd1, wrd2, wrd3);
1476: normalize_or_fault_if_no_denormal_support(opcode, extra, adold, oldpc, src);
1.1.1.4 root 1477: }
1.1 root 1478: break;
1.1.1.7 ! root 1479: case 3: // P
1.1.1.4 root 1480: {
1481: uae_u32 wrd[3];
1482: if (currprefs.cpu_model == 68060) {
1.1.1.6 root 1483: if (fault_if_no_packed_support (opcode, extra, adold, oldpc, NULL, wrd))
1484: return 1;
1.1.1.4 root 1485: }
1486: wrd[0] = (doext ? exts[0] : x_cp_get_long (ad));
1487: ad += 4;
1488: wrd[1] = (doext ? exts[1] : x_cp_get_long (ad));
1489: ad += 4;
1490: wrd[2] = (doext ? exts[2] : x_cp_get_long (ad));
1.1.1.6 root 1491: if (fault_if_no_packed_support (opcode, extra, adold, oldpc, NULL, wrd))
1492: return 1;
1493: fpp_to_pack (src, wrd, 0);
1494: fpp_normalize(src);
1.1.1.4 root 1495: return 1;
1496: }
1.1 root 1497: break;
1.1.1.7 ! root 1498: case 4: // W
1.1.1.4 root 1499: fpset(src, (uae_s16) (doext ? exts[0] : x_cp_get_word (ad)));
1.1 root 1500: break;
1.1.1.7 ! root 1501: case 5: // D
1.1.1.4 root 1502: {
1503: uae_u32 wrd1, wrd2;
1504: wrd1 = (doext ? exts[0] : x_cp_get_long (ad));
1505: ad += 4;
1506: wrd2 = (doext ? exts[1] : x_cp_get_long (ad));
1.1.1.6 root 1507: fpp_to_double (src, wrd1, wrd2);
1508: normalize_or_fault_if_no_denormal_support(opcode, extra, adold, oldpc, src);
1.1 root 1509: }
1510: break;
1.1.1.7 ! root 1511: case 6: // B
1.1.1.4 root 1512: fpset(src, (uae_s8) (doext ? exts[0] : x_cp_get_byte (ad)));
1.1 root 1513: break;
1514: default:
1515: return 0;
1516: }
1517: return 1;
1518: }
1519:
1.1.1.6 root 1520: static int put_fp_value (fpdata *value, uae_u32 opcode, uae_u16 extra, uaecptr oldpc, uae_u32 *adp)
1.1 root 1521: {
1522: int size, mode, reg;
1.1.1.4 root 1523: uae_u32 ad = 0;
1.1.1.6 root 1524: static const int sz1[8] = { 4, 4, 12, 12, 2, 8, 1, 0 };
1525: static const int sz2[8] = { 4, 4, 12, 12, 2, 8, 2, 0 };
1.1 root 1526:
1527: #if DEBUG_FPP
1528: if (!isinrom ())
1.1.1.6 root 1529: write_log (_T("PUTFP: %04X %04X\n"), opcode, extra);
1.1 root 1530: #endif
1.1.1.6 root 1531: #if 0
1.1 root 1532: if (!(extra & 0x4000)) {
1.1.1.4 root 1533: if (fault_if_no_fpu (opcode, extra, 0, oldpc))
1534: return 1;
1535: regs.fp[(extra >> 10) & 7] = *value;
1.1 root 1536: return 1;
1537: }
1.1.1.6 root 1538: #endif
1.1 root 1539: reg = opcode & 7;
1540: mode = (opcode >> 3) & 7;
1541: size = (extra >> 10) & 7;
1.1.1.4 root 1542: switch (mode)
1543: {
1.1.1.7 ! root 1544: case 0: // Dn
1.1.1.6 root 1545:
1546: if ((size == 0 || size == 1 ||size == 4 || size == 6) && fault_if_no_fpu (opcode, extra, 0, oldpc))
1547: return -1;
1.1.1.4 root 1548: switch (size)
1549: {
1.1.1.7 ! root 1550: case 6: // B
1.1.1.6 root 1551: if (normalize_or_fault_if_no_denormal_support(opcode, extra, 0, oldpc, value))
1552: return 1;
1553: m68k_dreg (regs, reg) = (uae_u32)(((fpp_to_int (value, 0) & 0xff)
1.1.1.4 root 1554: | (m68k_dreg (regs, reg) & ~0xff)));
1.1.1.6 root 1555: if (fault_if_68040_integer_nonmaskable(opcode, extra, ad, oldpc, value))
1556: return -1;
1.1.1.4 root 1557: break;
1.1.1.7 ! root 1558: case 4: // W
1.1.1.6 root 1559: if (normalize_or_fault_if_no_denormal_support(opcode, extra, 0, oldpc, value))
1560: return 1;
1561: m68k_dreg (regs, reg) = (uae_u32)(((fpp_to_int (value, 1) & 0xffff)
1.1.1.4 root 1562: | (m68k_dreg (regs, reg) & ~0xffff)));
1.1.1.6 root 1563: if (fault_if_68040_integer_nonmaskable(opcode, extra, ad, oldpc, value))
1564: return -1;
1.1.1.4 root 1565: break;
1.1.1.7 ! root 1566: case 0: // L
1.1.1.6 root 1567: if (normalize_or_fault_if_no_denormal_support(opcode, extra, 0, oldpc, value))
1568: return 1;
1569: m68k_dreg (regs, reg) = (uae_u32)fpp_to_int (value, 2);
1570: if (fault_if_68040_integer_nonmaskable(opcode, extra, ad, oldpc, value))
1571: return -1;
1.1.1.4 root 1572: break;
1.1.1.7 ! root 1573: case 1: // S
1.1.1.6 root 1574: if (normalize_or_fault_if_no_denormal_support(opcode, extra, 0, oldpc, value))
1575: return 1;
1576: m68k_dreg (regs, reg) = fpp_from_single (value);
1.1.1.4 root 1577: break;
1578: default:
1579: return 0;
1.1 root 1580: }
1581: return 1;
1.1.1.7 ! root 1582: case 1: // An
1.1 root 1583: return 0;
1.1.1.7 ! root 1584: case 2: // (An)
1.1 root 1585: ad = m68k_areg (regs, reg);
1586: break;
1.1.1.7 ! root 1587: case 3: // (An)+
1.1.1.6 root 1588: // Also needed by fault_if_no_fpu
1589: mmufixup[0].reg = reg;
1590: mmufixup[0].value = m68k_areg (regs, reg);
1591: fpu_mmu_fixup = true;
1.1 root 1592: ad = m68k_areg (regs, reg);
1593: m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size];
1594: break;
1.1.1.7 ! root 1595: case 4: // -(An)
1.1.1.6 root 1596: // Also needed by fault_if_no_fpu
1597: mmufixup[0].reg = reg;
1598: mmufixup[0].value = m68k_areg (regs, reg);
1599: fpu_mmu_fixup = true;
1.1 root 1600: m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size];
1601: ad = m68k_areg (regs, reg);
1.1.1.6 root 1602: // 68060 no fpu -(an): EA points to -4, not -12 if extended precision
1603: if (currprefs.cpu_model == 68060 && if_no_fpu() && sz1[size] == 12)
1604: ad += 8;
1.1 root 1605: break;
1.1.1.7 ! root 1606: case 5: // (d16,An)
1.1.1.4 root 1607: ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) x_cp_next_iword ();
1.1 root 1608: break;
1.1.1.7 ! root 1609: case 6: // (d8,An,Xn)+
1.1.1.4 root 1610: ad = x_cp_get_disp_ea_020 (m68k_areg (regs, reg), 0);
1.1 root 1611: break;
1612: case 7:
1.1.1.4 root 1613: switch (reg)
1614: {
1.1.1.7 ! root 1615: case 0: // (xxx).W
1.1.1.4 root 1616: ad = (uae_s32) (uae_s16) x_cp_next_iword ();
1617: break;
1.1.1.7 ! root 1618: case 1: // (xxx).L
1.1.1.4 root 1619: ad = x_cp_next_ilong ();
1620: break;
1.1.1.7 ! root 1621: // Immediate and PC-relative modes are not supported
1.1.1.4 root 1622: default:
1623: return 0;
1.1 root 1624: }
1625: }
1.1.1.4 root 1626:
1.1.1.6 root 1627: *adp = ad;
1628:
1.1.1.4 root 1629: if (fault_if_no_fpu (opcode, extra, ad, oldpc))
1.1.1.6 root 1630: return -1;
1.1.1.4 root 1631:
1632: switch (size)
1633: {
1.1.1.7 ! root 1634: case 0: // L
1.1.1.6 root 1635: if (normalize_or_fault_if_no_denormal_support(opcode, extra, ad, oldpc, value))
1.1.1.4 root 1636: return 1;
1.1.1.6 root 1637: x_cp_put_long(ad, (uae_u32)fpp_to_int(value, 2));
1638: if (fault_if_68040_integer_nonmaskable(opcode, extra, ad, oldpc, value))
1639: return -1;
1.1 root 1640: break;
1.1.1.7 ! root 1641: case 1: // S
1.1.1.6 root 1642: if (normalize_or_fault_if_no_denormal_support(opcode, extra, ad, oldpc, value))
1643: return 1;
1644: x_cp_put_long(ad, fpp_from_single(value));
1.1 root 1645: break;
1.1.1.7 ! root 1646: case 2: // X
1.1 root 1647: {
1.1.1.6 root 1648: if (normalize_or_fault_if_no_denormal_support(opcode, extra, ad, oldpc, value))
1.1.1.4 root 1649: return 1;
1.1.1.6 root 1650: uae_u32 wrd1, wrd2, wrd3;
1651: fpp_from_exten(value, &wrd1, &wrd2, &wrd3);
1.1.1.4 root 1652: x_cp_put_long (ad, wrd1);
1.1 root 1653: ad += 4;
1.1.1.4 root 1654: x_cp_put_long (ad, wrd2);
1.1 root 1655: ad += 4;
1.1.1.4 root 1656: x_cp_put_long (ad, wrd3);
1.1 root 1657: }
1658: break;
1.1.1.4 root 1659: case 3: // Packed-Decimal Real with Static k-Factor
1660: case 7: // Packed-Decimal Real with Dynamic k-Factor (P{Dn}) (reg to memory only)
1.1 root 1661: {
1.1.1.4 root 1662: uae_u32 wrd[3];
1663: int kfactor;
1.1.1.6 root 1664: if (fault_if_no_packed_support (opcode, extra, ad, oldpc, value, wrd))
1.1.1.4 root 1665: return 1;
1666: kfactor = size == 7 ? m68k_dreg (regs, (extra >> 4) & 7) : extra;
1667: kfactor &= 127;
1668: if (kfactor & 64)
1669: kfactor |= ~63;
1.1.1.6 root 1670: fpp_normalize(value);
1671: fpp_from_pack(value, wrd, kfactor);
1.1.1.4 root 1672: x_cp_put_long (ad, wrd[0]);
1.1 root 1673: ad += 4;
1.1.1.4 root 1674: x_cp_put_long (ad, wrd[1]);
1.1 root 1675: ad += 4;
1.1.1.4 root 1676: x_cp_put_long (ad, wrd[2]);
1.1 root 1677: }
1678: break;
1.1.1.7 ! root 1679: case 4: // W
1.1.1.6 root 1680: if (normalize_or_fault_if_no_denormal_support(opcode, extra, ad, oldpc, value))
1.1.1.4 root 1681: return 1;
1.1.1.6 root 1682: x_cp_put_word(ad, (uae_s16)fpp_to_int(value, 1));
1683: if (fault_if_68040_integer_nonmaskable(opcode, extra, ad, oldpc, value))
1684: return -1;
1.1.1.4 root 1685: break;
1.1.1.7 ! root 1686: case 5: // D
1.1.1.4 root 1687: {
1.1.1.6 root 1688: if (normalize_or_fault_if_no_denormal_support(opcode, extra, ad, oldpc, value))
1689: return 1;
1.1.1.4 root 1690: uae_u32 wrd1, wrd2;
1.1.1.6 root 1691: fpp_from_double(value, &wrd1, &wrd2);
1.1.1.4 root 1692: x_cp_put_long (ad, wrd1);
1693: ad += 4;
1694: x_cp_put_long (ad, wrd2);
1695: }
1.1 root 1696: break;
1.1.1.7 ! root 1697: case 6: // B
1.1.1.6 root 1698: if (normalize_or_fault_if_no_denormal_support(opcode, extra, ad, oldpc, value))
1.1.1.4 root 1699: return 1;
1.1.1.6 root 1700: x_cp_put_byte(ad, (uae_s8)fpp_to_int(value, 0));
1701: if (fault_if_68040_integer_nonmaskable(opcode, extra, ad, oldpc, value))
1702: return -1;
1.1 root 1703: break;
1704: default:
1705: return 0;
1706: }
1707: return 1;
1708: }
1709:
1.1.1.6 root 1710: static int get_fp_ad (uae_u32 opcode, uae_u32 * ad)
1.1 root 1711: {
1712: int mode;
1713: int reg;
1714:
1715: mode = (opcode >> 3) & 7;
1716: reg = opcode & 7;
1.1.1.4 root 1717: switch (mode)
1718: {
1.1.1.7 ! root 1719: case 0: // Dn
! 1720: case 1: // An
1.1 root 1721: return 0;
1.1.1.7 ! root 1722: case 2: // (An)
1.1 root 1723: *ad = m68k_areg (regs, reg);
1724: break;
1.1.1.7 ! root 1725: case 3: // (An)+
1.1 root 1726: *ad = m68k_areg (regs, reg);
1727: break;
1.1.1.7 ! root 1728: case 4: // -(An)
1.1 root 1729: *ad = m68k_areg (regs, reg);
1730: break;
1.1.1.7 ! root 1731: case 5: // (d16,An)
1.1.1.4 root 1732: *ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) x_cp_next_iword ();
1.1 root 1733: break;
1.1.1.7 ! root 1734: case 6: // (d8,An,Xn)+
1.1.1.4 root 1735: *ad = x_cp_get_disp_ea_020 (m68k_areg (regs, reg), 0);
1.1 root 1736: break;
1737: case 7:
1.1.1.4 root 1738: switch (reg)
1739: {
1.1.1.7 ! root 1740: case 0: // (xxx).W
1.1.1.4 root 1741: *ad = (uae_s32) (uae_s16) x_cp_next_iword ();
1742: break;
1.1.1.7 ! root 1743: case 1: // (xxx).L
1.1.1.4 root 1744: *ad = x_cp_next_ilong ();
1745: break;
1.1.1.7 ! root 1746: case 2: // (d16,PC)
1.1.1.4 root 1747: *ad = m68k_getpc ();
1748: *ad += (uae_s32) (uae_s16) x_cp_next_iword ();
1749: break;
1.1.1.7 ! root 1750: case 3: // (d8,PC,Xn)+
1.1.1.4 root 1751: *ad = x_cp_get_disp_ea_020 (m68k_getpc (), 0);
1752: break;
1753: default:
1754: return 0;
1.1 root 1755: }
1756: }
1757: return 1;
1758: }
1759:
1.1.1.4 root 1760: int fpp_cond (int condition)
1.1 root 1761: {
1.1.1.6 root 1762: int NotANumber, N, Z;
1.1 root 1763:
1.1.1.6 root 1764: #ifdef JIT
1765: if (currprefs.cachesize && currprefs.compfpu) {
1766: // JIT reads and writes regs.fpu_result
1.1.1.7 ! root 1767: fpp_is_init(®s.fp_result);
1.1.1.6 root 1768: NotANumber = fpp_is_nan(®s.fp_result);
1769: N = fpp_is_neg(®s.fp_result);
1770: Z = fpp_is_zero(®s.fp_result);
1771: } else
1772: #endif
1773: {
1774: NotANumber = (regs.fpsr & FPSR_CC_NAN) != 0;
1775: N = (regs.fpsr & FPSR_CC_N) != 0;
1776: Z = (regs.fpsr & FPSR_CC_Z) != 0;
1777: }
1.1 root 1778:
1.1.1.6 root 1779: if ((condition & 0x10) && NotANumber) {
1780: if (fpsr_set_bsun())
1781: return -2;
1782: }
1.1 root 1783:
1.1.1.4 root 1784: switch (condition)
1785: {
1.1 root 1786: case 0x00:
1787: return 0;
1788: case 0x01:
1789: return Z;
1790: case 0x02:
1791: return !(NotANumber || Z || N);
1792: case 0x03:
1793: return Z || !(NotANumber || N);
1794: case 0x04:
1795: return N && !(NotANumber || Z);
1796: case 0x05:
1797: return Z || (N && !NotANumber);
1798: case 0x06:
1799: return !(NotANumber || Z);
1800: case 0x07:
1801: return !NotANumber;
1802: case 0x08:
1803: return NotANumber;
1804: case 0x09:
1805: return NotANumber || Z;
1806: case 0x0a:
1807: return NotANumber || !(N || Z);
1808: case 0x0b:
1809: return NotANumber || Z || !N;
1810: case 0x0c:
1811: return NotANumber || (N && !Z);
1812: case 0x0d:
1813: return NotANumber || Z || N;
1814: case 0x0e:
1815: return !Z;
1816: case 0x0f:
1817: return 1;
1818: case 0x10:
1819: return 0;
1820: case 0x11:
1821: return Z;
1822: case 0x12:
1823: return !(NotANumber || Z || N);
1824: case 0x13:
1825: return Z || !(NotANumber || N);
1826: case 0x14:
1827: return N && !(NotANumber || Z);
1828: case 0x15:
1829: return Z || (N && !NotANumber);
1830: case 0x16:
1831: return !(NotANumber || Z);
1832: case 0x17:
1833: return !NotANumber;
1834: case 0x18:
1835: return NotANumber;
1836: case 0x19:
1837: return NotANumber || Z;
1838: case 0x1a:
1839: return NotANumber || !(N || Z);
1840: case 0x1b:
1841: return NotANumber || Z || !N;
1842: case 0x1c:
1843: return NotANumber || (N && !Z);
1844: case 0x1d:
1845: return NotANumber || Z || N;
1846: case 0x1e:
1847: return !Z;
1848: case 0x1f:
1849: return 1;
1850: }
1851: return -1;
1852: }
1853:
1.1.1.4 root 1854: static void maybe_idle_state (void)
1855: {
1856: // conditional floating point instruction does not change state
1857: // from null to idle on 68040/060.
1858: if (currprefs.fpu_model == 68881 || currprefs.fpu_model == 68882)
1859: regs.fpu_state = 1;
1860: }
1861:
1.1 root 1862: void fpuop_dbcc (uae_u32 opcode, uae_u16 extra)
1863: {
1.1.1.4 root 1864: uaecptr pc = m68k_getpc ();
1.1 root 1865: uae_s32 disp;
1866: int cc;
1867:
1.1.1.6 root 1868: if (fp_exception_pending(true))
1869: return;
1.1.1.4 root 1870: regs.fp_exception = false;
1.1.1.7 ! root 1871:
! 1872: #if FPU_LOG
! 1873: write_log(_T("FDBcc %04x %04x %08x\n"), opcode, extra, M68K_GETPC);
1.1 root 1874: #endif
1.1.1.7 ! root 1875:
1.1.1.4 root 1876: if (fault_if_no_6888x (opcode, extra, pc - 4))
1.1 root 1877: return;
1878:
1.1.1.4 root 1879: disp = (uae_s32) (uae_s16) x_cp_next_iword ();
1880: if (fault_if_no_fpu_u (opcode, extra, pc + disp, pc - 4))
1881: return;
1882: regs.fpiar = pc - 4;
1883: maybe_idle_state ();
1.1 root 1884: cc = fpp_cond (extra & 0x3f);
1.1.1.4 root 1885: if (cc < 0) {
1.1.1.6 root 1886: if (cc == -2)
1887: return; // BSUN
1888: fpu_op_illg (opcode, 0, regs.fpiar);
1.1 root 1889: } else if (!cc) {
1890: int reg = opcode & 0x7;
1891:
1892: m68k_dreg (regs, reg) = ((m68k_dreg (regs, reg) & 0xffff0000)
1893: | (((m68k_dreg (regs, reg) & 0xffff) - 1) & 0xffff));
1.1.1.4 root 1894: if ((m68k_dreg (regs, reg) & 0xffff) != 0xffff) {
1.1 root 1895: m68k_setpc (pc + disp);
1.1.1.4 root 1896: regs.fp_branch = true;
1897: }
1.1 root 1898: }
1899: }
1900:
1901: void fpuop_scc (uae_u32 opcode, uae_u16 extra)
1902: {
1.1.1.3 root 1903: uae_u32 ad = 0;
1.1 root 1904: int cc;
1.1.1.4 root 1905: uaecptr pc = m68k_getpc () - 4;
1.1 root 1906:
1.1.1.6 root 1907: if (fp_exception_pending(true))
1908: return;
1.1.1.4 root 1909: regs.fp_exception = false;
1.1.1.7 ! root 1910:
! 1911: #if FPU_LOG
! 1912: write_log(_T("FScc %04x %04x %08x\n"), opcode, extra, M68K_GETPC);
1.1 root 1913: #endif
1.1.1.4 root 1914:
1915: if (fault_if_no_6888x (opcode, extra, pc))
1916: return;
1917:
1918: if (opcode & 0x38) {
1919: if (get_fp_ad (opcode, &ad) == 0) {
1920: fpu_noinst (opcode, regs.fpiar);
1921: return;
1922: }
1923: }
1924:
1925: if (fault_if_no_fpu_u (opcode, extra, ad, pc))
1.1 root 1926: return;
1927:
1.1.1.4 root 1928: regs.fpiar = pc;
1929: maybe_idle_state ();
1.1 root 1930: cc = fpp_cond (extra & 0x3f);
1.1.1.4 root 1931: if (cc < 0) {
1.1.1.6 root 1932: if (cc == -2)
1933: return; // BSUN
1934: fpu_op_illg (opcode, 0, regs.fpiar);
1.1 root 1935: } else if ((opcode & 0x38) == 0) {
1936: m68k_dreg (regs, opcode & 7) = (m68k_dreg (regs, opcode & 7) & ~0xff) | (cc ? 0xff : 0x00);
1937: } else {
1.1.1.4 root 1938: x_cp_put_byte (ad, cc ? 0xff : 0x00);
1.1 root 1939: }
1940: }
1941:
1942: void fpuop_trapcc (uae_u32 opcode, uaecptr oldpc, uae_u16 extra)
1943: {
1944: int cc;
1945:
1.1.1.6 root 1946: if (fp_exception_pending(true))
1947: return;
1.1.1.4 root 1948: regs.fp_exception = false;
1.1.1.7 ! root 1949:
! 1950: #if FPU_LOG
! 1951: write_log(_T("FTRAPcc %04x %04x %08x\n"), opcode, extra, M68K_GETPC);
1.1 root 1952: #endif
1.1.1.7 ! root 1953:
1.1.1.4 root 1954: if (fault_if_no_fpu_u (opcode, extra, 0, oldpc))
1.1 root 1955: return;
1956:
1.1.1.4 root 1957: regs.fpiar = oldpc;
1958: maybe_idle_state ();
1.1 root 1959: cc = fpp_cond (extra & 0x3f);
1.1.1.4 root 1960: if (cc < 0) {
1.1.1.6 root 1961: if (cc == -2)
1962: return; // BSUN
1963: fpu_op_illg (opcode, 0, regs.fpiar);
1.1.1.4 root 1964: } else if (cc) {
1965: Exception (7);
1.1 root 1966: }
1967: }
1968:
1.1.1.4 root 1969: void fpuop_bcc (uae_u32 opcode, uaecptr oldpc, uae_u32 extra)
1.1 root 1970: {
1971: int cc;
1972:
1.1.1.6 root 1973: if (fp_exception_pending(true))
1974: return;
1.1.1.4 root 1975: regs.fp_exception = false;
1.1.1.7 ! root 1976:
! 1977: #if FPU_LOG
! 1978: write_log(_T("FBcc %04x %04x %08x\n"), opcode, extra, M68K_GETPC);
1.1 root 1979: #endif
1.1.1.7 ! root 1980:
1.1.1.4 root 1981: if (fault_if_no_fpu (opcode, extra, 0, oldpc - 2))
1.1 root 1982: return;
1983:
1.1.1.4 root 1984: regs.fpiar = oldpc - 2;
1985: maybe_idle_state ();
1.1 root 1986: cc = fpp_cond (opcode & 0x3f);
1.1.1.4 root 1987: if (cc < 0) {
1.1.1.6 root 1988: if (cc == -2)
1989: return; // BSUN
1990: fpu_op_illg (opcode, 0, regs.fpiar);
1.1 root 1991: } else if (cc) {
1992: if ((opcode & 0x40) == 0)
1993: extra = (uae_s32) (uae_s16) extra;
1.1.1.4 root 1994: m68k_setpc (oldpc + extra);
1995: regs.fp_branch = true;
1.1 root 1996: }
1997: }
1998:
1999: void fpuop_save (uae_u32 opcode)
2000: {
1.1.1.6 root 2001: uae_u32 ad, adp;
1.1 root 2002: int incr = (opcode & 0x38) == 0x20 ? -1 : 1;
1.1.1.6 root 2003: int fpu_version = get_fpu_version (currprefs.fpu_model);
1.1.1.4 root 2004: uaecptr pc = m68k_getpc () - 2;
1.1 root 2005: int i;
2006:
1.1.1.7 ! root 2007:
! 2008: #if FPU_LOG
! 2009: if (!isinrom())
! 2010: write_log(_T("FSAVE %04x %08x\n"), opcode, M68K_GETPC);
1.1 root 2011: #endif
1.1.1.4 root 2012:
1.1.1.7 ! root 2013: regs.fp_exception = false;
! 2014:
1.1.1.4 root 2015: if (fault_if_no_6888x (opcode, 0, pc))
1.1 root 2016: return;
2017:
2018: if (get_fp_ad (opcode, &ad) == 0) {
1.1.1.4 root 2019: fpu_op_illg (opcode, 0, pc);
1.1 root 2020: return;
2021: }
2022:
1.1.1.4 root 2023: if (fault_if_no_fpu (opcode, 0, ad, pc))
2024: return;
2025:
1.1.1.6 root 2026: // write_log(_T("FSAVE %08x %08x\n"), M68K_GETPC, ad);
2027:
1.1 root 2028: if (currprefs.fpu_model == 68060) {
1.1.1.6 root 2029:
1.1.1.4 root 2030: /* 12 byte 68060 NULL/IDLE/EXCP frame. */
2031: int frame_size = 12;
1.1.1.6 root 2032: uae_u32 frame_id;
1.1.1.4 root 2033:
2034: if (regs.fpu_exp_state > 1) {
1.1.1.6 root 2035: frame_id = 0x0000e000 | fsave_data.v;
1.1.1.4 root 2036:
1.1.1.6 root 2037: #if 0
2038: write_log(_T("68060 FSAVE EXCP %s\n"), fpp_print(&fsave_data.src));
1.1.1.4 root 2039: #endif
2040:
1.1 root 2041: } else {
1.1.1.4 root 2042: frame_id = regs.fpu_state == 0 ? 0x00000000 : 0x00006000;
1.1 root 2043: }
1.1.1.4 root 2044: if (incr < 0)
2045: ad -= frame_size;
1.1.1.6 root 2046: adp = ad;
1.1.1.7 ! root 2047: x_cp_put_long (ad, (fsave_data.eo[0] & 0xffff0000) | frame_id);
1.1.1.4 root 2048: ad += 4;
1.1.1.7 ! root 2049: x_cp_put_long (ad, fsave_data.eo[1]);
1.1.1.4 root 2050: ad += 4;
1.1.1.7 ! root 2051: x_cp_put_long (ad, fsave_data.eo[2]);
1.1.1.4 root 2052: ad += 4;
1.1.1.6 root 2053:
1.1 root 2054: } else if (currprefs.fpu_model == 68040) {
1.1.1.6 root 2055:
1.1.1.4 root 2056: if (!regs.fpu_exp_state) {
2057: /* 4 byte 68040 NULL/IDLE frame. */
2058: uae_u32 frame_id = regs.fpu_state == 0 ? 0 : fpu_version << 24;
1.1.1.6 root 2059: if (incr < 0)
1.1.1.4 root 2060: ad -= 4;
1.1.1.6 root 2061: adp = ad;
1.1.1.7 ! root 2062: x_cp_put_long (ad, frame_id);
1.1.1.6 root 2063: ad += 4;
1.1 root 2064: } else {
1.1.1.4 root 2065: /* 44 (rev $40) and 52 (rev $41) byte 68040 unimplemented instruction frame */
2066: /* 96 byte 68040 busy frame */
2067: int frame_size = regs.fpu_exp_state == 2 ? 0x64 : (fpu_version >= 0x41 ? 0x34 : 0x2c);
2068: uae_u32 frame_id = ((fpu_version << 8) | (frame_size - 4)) << 16;
2069:
1.1.1.6 root 2070: #if 0
2071: write_log(_T("68040 FSAVE %d (%d), CMDREG=%04X"), regs.fp_exp_pend, frame_size, extra);
2072: if (regs.fp_exp_pend == FPU_EXP_UNIMP_DATATYPE_PACKED_PRE) {
2073: write_log(_T(" PACKED %08x-%08x-%08x"), fsave_data.pack[0], fsave_data.pack[1], fsave_data.pack[2]);
2074: } else if (regs.fp_exp_pend == FPU_EXP_UNIMP_DATATYPE_PACKED_POST) {
2075: write_log(_T(" SRC=%s (%08x-%08x-%08x %d)"),
2076: fpp_print(&fsave_data.src), src1[0], src1[1], src1[2], stag);
2077: write_log(_T(" DST=%s (%08x-%08x-%08x %d)"),
2078: fpp_print(&fsave_data.dst), src2[0], src2[1], src2[2], dtag);
2079: }
1.1.1.4 root 2080: #endif
2081:
2082: if (incr < 0)
2083: ad -= frame_size;
1.1.1.6 root 2084: adp = ad;
1.1.1.7 ! root 2085: x_cp_put_long (ad, frame_id);
1.1 root 2086: ad += 4;
1.1.1.4 root 2087: if (regs.fpu_exp_state == 2) {
2088: /* BUSY frame */
1.1.1.7 ! root 2089: x_cp_put_long(ad, 0);
1.1.1.4 root 2090: ad += 4;
1.1.1.7 ! root 2091: x_cp_put_long(ad, 0); // CU_SAVEPC (Software shouldn't care)
1.1.1.4 root 2092: ad += 4;
1.1.1.7 ! root 2093: x_cp_put_long(ad, 0);
1.1.1.4 root 2094: ad += 4;
1.1.1.7 ! root 2095: x_cp_put_long(ad, 0);
1.1.1.4 root 2096: ad += 4;
1.1.1.7 ! root 2097: x_cp_put_long(ad, 0);
1.1.1.4 root 2098: ad += 4;
1.1.1.7 ! root 2099: x_cp_put_long(ad, fsave_data.wbt[0]); // WBTS/WBTE
1.1.1.4 root 2100: ad += 4;
1.1.1.7 ! root 2101: x_cp_put_long(ad, fsave_data.wbt[1]); // WBTM
1.1.1.4 root 2102: ad += 4;
1.1.1.7 ! root 2103: x_cp_put_long(ad, fsave_data.wbt[2]); // WBTM
1.1.1.4 root 2104: ad += 4;
1.1.1.7 ! root 2105: x_cp_put_long(ad, 0);
1.1.1.4 root 2106: ad += 4;
1.1.1.7 ! root 2107: x_cp_put_long(ad, fsave_data.fpiarcu); // FPIARCU (same as FPU PC or something else?)
1.1.1.4 root 2108: ad += 4;
1.1.1.7 ! root 2109: x_cp_put_long(ad, 0);
1.1.1.4 root 2110: ad += 4;
1.1.1.7 ! root 2111: x_cp_put_long(ad, 0);
1.1.1.4 root 2112: ad += 4;
2113: }
2114: if (fpu_version >= 0x41 || regs.fpu_exp_state == 2) {
1.1.1.7 ! root 2115: x_cp_put_long(ad, fsave_data.cmdreg3b << 16); // CMDREG3B
1.1.1.4 root 2116: ad += 4;
1.1.1.7 ! root 2117: x_cp_put_long (ad, 0);
1.1.1.4 root 2118: ad += 4;
2119: }
1.1.1.7 ! root 2120: x_cp_put_long (ad, (fsave_data.stag << 29) | (fsave_data.wbtm66 << 26) | (fsave_data.grs << 23)); // STAG
1.1.1.4 root 2121: ad += 4;
1.1.1.7 ! root 2122: x_cp_put_long (ad, fsave_data.cmdreg1b << 16); // CMDREG1B
1.1.1.4 root 2123: ad += 4;
1.1.1.7 ! root 2124: x_cp_put_long (ad, (fsave_data.dtag << 29) | (fsave_data.wbte15 << 20)); // DTAG
1.1.1.6 root 2125: ad += 4;
1.1.1.7 ! root 2126: x_cp_put_long (ad, (fsave_data.e1 << 26) | (fsave_data.e3 << 25) | (fsave_data.t << 20));
1.1.1.6 root 2127: ad += 4;
1.1.1.7 ! root 2128: x_cp_put_long(ad, fsave_data.fpt[0]); // FPTS/FPTE
1.1.1.6 root 2129: ad += 4;
1.1.1.7 ! root 2130: x_cp_put_long(ad, fsave_data.fpt[1]); // FPTM
1.1.1.6 root 2131: ad += 4;
1.1.1.7 ! root 2132: x_cp_put_long(ad, fsave_data.fpt[2]); // FPTM
1.1.1.6 root 2133: ad += 4;
1.1.1.7 ! root 2134: x_cp_put_long(ad, fsave_data.et[0]); // ETS/ETE
1.1.1.6 root 2135: ad += 4;
1.1.1.7 ! root 2136: x_cp_put_long(ad, fsave_data.et[1]); // ETM
1.1.1.6 root 2137: ad += 4;
1.1.1.7 ! root 2138: x_cp_put_long(ad, fsave_data.et[2]); // ETM
1.1.1.4 root 2139: ad += 4;
1.1 root 2140: }
2141: } else { /* 68881/68882 */
1.1.1.6 root 2142: uae_u32 biu_flags = 0x540effff;
2143: int frame_size = currprefs.fpu_model == 68882 ? 0x3c : 0x1c;
2144: uae_u32 frame_id = regs.fpu_state == 0 ? ((frame_size - 4) << 16) : (fpu_version << 24) | ((frame_size - 4) << 16);
1.1.1.5 root 2145:
1.1.1.6 root 2146: regs.fp_exp_pend = 0;
2147: if (regs.fpu_exp_state) {
2148: biu_flags |= 0x20000000;
2149: } else {
2150: biu_flags |= 0x08000000;
2151: }
2152: if (regs.fpu_state == 0)
2153: frame_size = 4;
2154:
1.1.1.4 root 2155: if (currprefs.mmu_model) {
1.1.1.6 root 2156: if (incr < 0)
2157: ad -= frame_size;
2158: adp = ad;
1.1.1.7 ! root 2159: x_cp_put_long(ad, frame_id); // frame id
1.1.1.6 root 2160: ad += 4;
2161: if (regs.fpu_state != 0) { // idle frame
1.1.1.7 ! root 2162: x_cp_put_long(ad, fsave_data.ccr); // command/condition register
1.1.1.6 root 2163: ad += 4;
2164: if (currprefs.fpu_model == 68882) {
1.1.1.7 ! root 2165: // don't write unused fields to save MMU state space.
! 2166: ad += 8 * 4;
1.1.1.4 root 2167: }
1.1.1.7 ! root 2168: x_cp_put_long(ad, fsave_data.eo[0]); // exceptional operand lo
1.1.1.6 root 2169: ad += 4;
1.1.1.7 ! root 2170: x_cp_put_long(ad, fsave_data.eo[1]); // exceptional operand mid
1.1.1.4 root 2171: ad += 4;
1.1.1.7 ! root 2172: x_cp_put_long(ad, fsave_data.eo[2]); // exceptional operand hi
1.1.1.6 root 2173: ad += 4;
1.1.1.7 ! root 2174: x_cp_put_long(ad, 0x00000000); // operand register
1.1.1.6 root 2175: ad += 4;
1.1.1.7 ! root 2176: x_cp_put_long(ad, biu_flags); // biu flags
1.1.1.6 root 2177: ad += 4;
1.1 root 2178: }
2179: } else {
1.1.1.6 root 2180: if (incr < 0)
2181: ad -= frame_size;
2182: adp = ad;
1.1.1.7 ! root 2183: x_cp_put_long(ad, frame_id); // frame id
1.1.1.6 root 2184: ad += 4;
2185: if (regs.fpu_state != 0) { // idle frame
1.1.1.7 ! root 2186: x_cp_put_long(ad, fsave_data.ccr); // command/condition register
1.1 root 2187: ad += 4;
1.1.1.6 root 2188: if(currprefs.fpu_model == 68882) {
2189: for(i = 0; i < 32; i += 4) {
1.1.1.7 ! root 2190: x_cp_put_long(ad, 0x00000000); // internal
1.1.1.6 root 2191: ad += 4;
2192: }
1.1.1.4 root 2193: }
1.1.1.7 ! root 2194: x_cp_put_long(ad, fsave_data.eo[0]); // exceptional operand hi
1.1.1.6 root 2195: ad += 4;
1.1.1.7 ! root 2196: x_cp_put_long(ad, fsave_data.eo[1]); // exceptional operand mid
1.1.1.6 root 2197: ad += 4;
1.1.1.7 ! root 2198: x_cp_put_long(ad, fsave_data.eo[2]); // exceptional operand lo
1.1.1.6 root 2199: ad += 4;
1.1.1.7 ! root 2200: x_cp_put_long(ad, 0x00000000); // operand register
1.1.1.6 root 2201: ad += 4;
1.1.1.7 ! root 2202: x_cp_put_long(ad, biu_flags); // biu flags
1.1.1.6 root 2203: ad += 4;
1.1 root 2204: }
2205: }
2206: }
1.1.1.4 root 2207:
1.1.1.6 root 2208: if ((opcode & 0x38) == 0x20) // predecrement
2209: m68k_areg (regs, opcode & 7) = adp;
1.1.1.4 root 2210: regs.fpu_exp_state = 0;
1.1 root 2211: }
2212:
1.1.1.6 root 2213: static bool fp_arithmetic(fpdata *src, fpdata *dst, int extra);
2214:
1.1 root 2215: void fpuop_restore (uae_u32 opcode)
2216: {
1.1.1.6 root 2217: int fpu_version;
2218: int frame_version;
2219: int fpu_model = currprefs.fpu_model;
1.1.1.4 root 2220: uaecptr pc = m68k_getpc () - 2;
1.1.1.6 root 2221: uae_u32 ad, ad_orig;
1.1 root 2222: uae_u32 d;
2223:
1.1.1.4 root 2224: regs.fp_exception = false;
1.1.1.6 root 2225:
1.1.1.7 ! root 2226: #if FPU_LOG
! 2227: if (!isinrom())
! 2228: write_log (_T("FRESTORE %04x %08x\n"), opcode, M68K_GETPC);
1.1 root 2229: #endif
1.1.1.4 root 2230:
2231: if (fault_if_no_6888x (opcode, 0, pc))
1.1 root 2232: return;
2233:
2234: if (get_fp_ad (opcode, &ad) == 0) {
1.1.1.4 root 2235: fpu_op_illg (opcode, 0, pc);
1.1 root 2236: return;
2237: }
2238:
1.1.1.4 root 2239: if (fault_if_no_fpu (opcode, 0, ad, pc))
2240: return;
1.1.1.6 root 2241: ad_orig = ad;
1.1.1.4 root 2242: regs.fpiar = pc;
2243:
1.1.1.6 root 2244: // write_log(_T("FRESTORE %08x %08x\n"), M68K_GETPC, ad);
1.1.1.4 root 2245:
1.1.1.6 root 2246: // FRESTORE does not support predecrement
2247:
1.1.1.7 ! root 2248: d = x_cp_get_long(ad);
1.1.1.6 root 2249:
2250: frame_version = (d >> 24) & 0xff;
2251:
2252: retry:
2253: ad = ad_orig + 4;
2254: fpu_version = get_fpu_version(fpu_model);
2255: if (fpu_model == 68060) {
1.1.1.4 root 2256: int ff = (d >> 8) & 0xff;
1.1.1.6 root 2257: uae_u32 v = d & 0x7;
2258: fsave_data.eo[0] = d & 0xffff0000;
2259:
1.1.1.7 ! root 2260: fsave_data.eo[1] = x_cp_get_long(ad);
1.1.1.6 root 2261: ad += 4;
1.1.1.7 ! root 2262: fsave_data.eo[2] = x_cp_get_long(ad);
1.1.1.6 root 2263: ad += 4;
1.1.1.4 root 2264:
2265: if (ff == 0x60) {
2266: regs.fpu_state = 1;
2267: regs.fpu_exp_state = 0;
2268: } else if (ff == 0xe0) {
1.1.1.6 root 2269: regs.fpu_state = 1;
2270: regs.fpu_exp_state = 2;
2271: if (v == 7) {
2272: regs.fp_unimp_pend = 1;
2273: } else {
2274: regs.fp_exp_pend = 48 + v;
2275: }
1.1.1.4 root 2276: } else if (ff) {
1.1.1.6 root 2277: write_log (_T("FRESTORE invalid frame format %02x %08x ADDR=%08x\n"), ff, d, ad_orig);
2278: Exception(14);
2279: return;
2280: } else {
2281: fpu_null();
2282: }
2283:
2284: } else if (fpu_model == 68040) {
2285:
2286: if (frame_version == fpu_version) { // not null frame
2287: uae_u32 frame_size = (d >> 16) & 0xff;
2288:
2289: if (frame_size == 0x60) { // busy
2290: fpdata src, dst;
2291: uae_u32 tmp, v, opclass, cmdreg1b, fpte15, et15, cusavepc;
2292:
2293: ad += 0x4; // offset to CU_SAVEPC field
1.1.1.7 ! root 2294: tmp = x_cp_get_long(ad);
1.1.1.6 root 2295: cusavepc = tmp >> 24;
2296: ad += 0x20; // offset to FPIARCU field
1.1.1.7 ! root 2297: regs.fpiar = x_cp_get_long(ad);
1.1.1.6 root 2298: ad += 0x14; // offset to ET15 field
1.1.1.7 ! root 2299: tmp = x_cp_get_long(ad);
1.1.1.6 root 2300: et15 = (tmp & 0x10000000) >> 28;
2301: ad += 0x4; // offset to CMDREG1B field
1.1.1.7 ! root 2302: fsave_data.cmdreg1b = x_cp_get_long(ad);
1.1.1.6 root 2303: fsave_data.cmdreg1b >>= 16;
2304: cmdreg1b = fsave_data.cmdreg1b;
2305: ad += 0x4; // offset to FPTE15 field
1.1.1.7 ! root 2306: tmp = x_cp_get_long(ad);
1.1.1.6 root 2307: fpte15 = (tmp & 0x10000000) >> 28;
2308: ad += 0x8; // offset to FPTE field
1.1.1.7 ! root 2309: fsave_data.fpt[0] = x_cp_get_long(ad);
1.1.1.6 root 2310: ad += 0x4;
1.1.1.7 ! root 2311: fsave_data.fpt[1] = x_cp_get_long(ad);
1.1.1.6 root 2312: ad += 0x4;
1.1.1.7 ! root 2313: fsave_data.fpt[2] = x_cp_get_long(ad);
1.1.1.6 root 2314: ad += 0x4; // offset to ET field
1.1.1.7 ! root 2315: fsave_data.et[0] = x_cp_get_long(ad);
1.1.1.6 root 2316: ad += 0x4;
1.1.1.7 ! root 2317: fsave_data.et[1] = x_cp_get_long(ad);
1.1.1.6 root 2318: ad += 0x4;
1.1.1.7 ! root 2319: fsave_data.et[2] = x_cp_get_long(ad);
1.1.1.6 root 2320: ad += 0x4;
2321:
2322: opclass = (cmdreg1b >> 13) & 0x7; // just to be sure
2323:
2324: if (cusavepc == 0xFE) {
2325: if (opclass == 0 || opclass == 2) {
2326: fpp_to_exten_fmovem(&dst, fsave_data.fpt[0], fsave_data.fpt[1], fsave_data.fpt[2]);
2327: fpp_denormalize(&dst, fpte15);
2328: fpp_to_exten_fmovem(&src, fsave_data.et[0], fsave_data.et[1], fsave_data.et[2]);
2329: fpp_denormalize(&src, et15);
2330: #if EXCEPTION_FPP
2331: uae_u32 tmpsrc[3], tmpdst[3];
2332: fpp_from_exten_fmovem(&src, &tmpsrc[0], &tmpsrc[1], &tmpsrc[2]);
2333: fpp_from_exten_fmovem(&dst, &tmpdst[0], &tmpdst[1], &tmpdst[2]);
2334: write_log (_T("FRESTORE src = %08X %08X %08X, dst = %08X %08X %08X, extra = %04X\n"),
2335: tmpsrc[0], tmpsrc[1], tmpsrc[2], tmpdst[0], tmpdst[1], tmpdst[2], cmdreg1b);
2336: #endif
2337: fpsr_clear_status();
2338:
2339: v = fp_arithmetic(&src, &dst, cmdreg1b);
2340:
2341: if (v)
2342: regs.fp[(cmdreg1b>>7)&7] = dst;
2343:
2344: fpsr_check_arithmetic_exception(0, &src, regs.fp_opword, cmdreg1b, regs.fp_ea);
2345: } else {
2346: write_log (_T("FRESTORE resume of opclass %d instruction not supported %08x\n"), opclass, ad_orig);
2347: }
2348: }
2349:
2350: } else if (frame_size == 0x30 || frame_size == 0x28) { // unimp
2351:
2352: // TODO: restore frame contents
2353: ad += frame_size;
2354:
2355: } else if (frame_size == 0x00) { // idle
2356: regs.fpu_state = 1;
2357: regs.fpu_exp_state = 0;
2358: } else {
2359: write_log (_T("FRESTORE invalid frame size %02x %08x %08x\n"), frame_size, d, ad_orig);
2360:
2361: Exception(14);
2362: return;
2363:
2364: }
2365: } else if (frame_version == 0x00) { // null frame
2366: fpu_null();
1.1.1.4 root 2367: } else {
1.1.1.6 root 2368: if (!currprefs.fpu_no_unimplemented && frame_version == 0x1f && currprefs.fpu_model == fpu_model) {
2369: // horrible hack to support on the fly 6888x <> 68040 FPU switching
2370: fpu_model = 68881;
2371: goto retry;
2372: }
2373: write_log (_T("FRESTORE 68040 (%d) invalid frame version %02x %08x %08x\n"), fpu_model, frame_version, d, ad_orig);
2374: Exception(14);
2375: return;
1.1.1.4 root 2376: }
1.1.1.6 root 2377:
1.1.1.4 root 2378: } else {
1.1.1.6 root 2379:
2380: // 6888x
2381: if (frame_version == fpu_version) { // not null frame
2382: uae_u32 biu_flags;
2383: uae_u32 frame_size = (d >> 16) & 0xff;
2384: uae_u32 biu_offset = frame_size - 4;
1.1.1.4 root 2385: regs.fpu_state = 1;
1.1.1.6 root 2386:
2387: if (frame_size == 0x18 || frame_size == 0x38) { // idle
1.1.1.7 ! root 2388:
! 2389: fsave_data.ccr = x_cp_get_long(ad);
1.1.1.6 root 2390: ad += 4;
2391: // 68882 internal registers (32 bytes, unused)
2392: ad += frame_size - 24;
1.1.1.7 ! root 2393: fsave_data.eo[0] = x_cp_get_long(ad);
1.1.1.6 root 2394: ad += 4;
1.1.1.7 ! root 2395: fsave_data.eo[1] = x_cp_get_long(ad);
1.1.1.6 root 2396: ad += 4;
1.1.1.7 ! root 2397: fsave_data.eo[2] = x_cp_get_long(ad);
1.1.1.6 root 2398: ad += 4;
2399: // operand register (unused)
2400: ad += 4;
1.1.1.7 ! root 2401: biu_flags = x_cp_get_long(ad);
1.1.1.6 root 2402: ad += 4;
2403:
2404: if ((biu_flags & 0x08000000) == 0x00000000) {
2405: regs.fpu_exp_state = 2;
2406: regs.fp_exp_pend = fpsr_get_vector(regs.fpsr & regs.fpcr & 0xff00);
2407: } else {
2408: regs.fpu_exp_state = 0;
2409: regs.fp_exp_pend = 0;
2410: }
2411: } else if (frame_size == 0xB4 || frame_size == 0xD4) {
2412: write_log (_T("FRESTORE of busy frame not supported %08x\n"), ad_orig);
2413: ad += frame_size;
2414: } else {
2415: write_log (_T("FRESTORE invalid frame size %02x %08x %08x\n"), frame_size, d, ad_orig);
2416: Exception(14);
2417: return;
2418: }
2419: } else if (frame_version == 0x00) { // null frame
2420: fpu_null();
1.1.1.4 root 2421: } else {
1.1.1.6 root 2422: if (!currprefs.fpu_no_unimplemented && (frame_version == 0x40 || frame_version == 0x41) && currprefs.fpu_model == fpu_model) {
2423: // horrible hack to support on the fly 6888x <> 68040 FPU switching
2424: fpu_model = 68040;
2425: goto retry;
2426: }
2427: write_log (_T("FRESTORE 6888x (%d) invalid frame version %02x %08x %08x\n"), fpu_model, frame_version, d, ad_orig);
2428: Exception(14);
2429: return;
1.1.1.4 root 2430: }
2431: }
1.1 root 2432:
1.1.1.6 root 2433: if ((opcode & 0x38) == 0x18) /// postincrement
1.1.1.4 root 2434: m68k_areg (regs, opcode & 7) = ad;
1.1.1.6 root 2435:
2436: fp_exception_pending(false);
1.1.1.4 root 2437: }
2438:
2439: static uaecptr fmovem2mem (uaecptr ad, uae_u32 list, int incr, int regdir)
2440: {
2441: int reg;
2442:
2443: // 68030 MMU state saving is annoying!
2444: if (currprefs.mmu_model == 68030) {
2445: int idx = 0;
2446: uae_u32 wrd[3];
2447: mmu030_state[1] |= MMU030_STATEFLAG1_MOVEM1;
1.1.1.7 ! root 2448: for (int r = 0; r < 8; r++) {
1.1.1.4 root 2449: if (regdir < 0)
2450: reg = 7 - r;
2451: else
2452: reg = r;
2453: if (list & 0x80) {
1.1.1.6 root 2454: fpp_from_exten_fmovem(®s.fp[reg], &wrd[0], &wrd[1], &wrd[2]);
1.1.1.4 root 2455: if (incr < 0)
2456: ad -= 3 * 4;
1.1.1.7 ! root 2457: for (int i = 0; i < 3; i++) {
1.1.1.4 root 2458: if (mmu030_state[0] == idx * 3 + i) {
2459: if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM2) {
2460: mmu030_state[1] &= ~MMU030_STATEFLAG1_MOVEM2;
1.1.1.7 ! root 2461: } else {
! 2462: mmu030_data_buffer_out = wrd[i];
1.1.1.4 root 2463: x_put_long(ad + i * 4, wrd[i]);
2464: }
2465: mmu030_state[0]++;
2466: }
1.1 root 2467: }
1.1.1.4 root 2468: if (incr > 0)
2469: ad += 3 * 4;
2470: idx++;
1.1 root 2471: }
1.1.1.4 root 2472: list <<= 1;
2473: }
2474: } else {
1.1.1.7 ! root 2475: for (int r = 0; r < 8; r++) {
1.1.1.4 root 2476: uae_u32 wrd1, wrd2, wrd3;
2477: if (regdir < 0)
2478: reg = 7 - r;
2479: else
2480: reg = r;
2481: if (list & 0x80) {
1.1.1.6 root 2482: fpp_from_exten_fmovem(®s.fp[reg], &wrd1, &wrd2, &wrd3);
1.1.1.4 root 2483: if (incr < 0)
2484: ad -= 3 * 4;
1.1.1.7 ! root 2485: x_cp_put_long(ad + 0, wrd1);
! 2486: x_cp_put_long(ad + 4, wrd2);
! 2487: x_cp_put_long(ad + 8, wrd3);
1.1.1.4 root 2488: if (incr > 0)
2489: ad += 3 * 4;
2490: }
2491: list <<= 1;
2492: }
2493: }
2494: return ad;
2495: }
2496:
2497: static uaecptr fmovem2fpp (uaecptr ad, uae_u32 list, int incr, int regdir)
2498: {
2499: int reg;
2500:
2501: if (currprefs.mmu_model == 68030) {
2502: uae_u32 wrd[3];
2503: int idx = 0;
2504: mmu030_state[1] |= MMU030_STATEFLAG1_MOVEM1 | MMU030_STATEFLAG1_FMOVEM;
1.1.1.7 ! root 2505: for (int r = 0; r < 8; r++) {
1.1.1.4 root 2506: if (regdir < 0)
2507: reg = 7 - r;
2508: else
2509: reg = r;
2510: if (list & 0x80) {
2511: if (incr < 0)
2512: ad -= 3 * 4;
1.1.1.7 ! root 2513: for (int i = 0; i < 3; i++) {
1.1.1.4 root 2514: if (mmu030_state[0] == idx * 3 + i) {
2515: if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM2) {
2516: mmu030_state[1] &= ~MMU030_STATEFLAG1_MOVEM2;
1.1.1.7 ! root 2517: wrd[i] = mmu030_data_buffer_out;
1.1.1.4 root 2518: } else {
2519: wrd[i] = x_get_long (ad + i * 4);
2520: }
2521: // save first two entries if 2nd or 3rd get_long() faults.
2522: if (i == 0 || i == 1)
2523: mmu030_fmovem_store[i] = wrd[i];
2524: mmu030_state[0]++;
2525: if (i == 2)
1.1.1.6 root 2526: fpp_to_exten (®s.fp[reg], mmu030_fmovem_store[0], mmu030_fmovem_store[1], wrd[2]);
1.1.1.4 root 2527: }
1.1 root 2528: }
1.1.1.4 root 2529: if (incr > 0)
2530: ad += 3 * 4;
2531: idx++;
1.1 root 2532: }
1.1.1.4 root 2533: list <<= 1;
1.1 root 2534: }
1.1.1.4 root 2535: } else {
1.1.1.7 ! root 2536: for (int r = 0; r < 8; r++) {
1.1.1.4 root 2537: uae_u32 wrd1, wrd2, wrd3;
2538: if (regdir < 0)
2539: reg = 7 - r;
2540: else
2541: reg = r;
2542: if (list & 0x80) {
2543: if (incr < 0)
2544: ad -= 3 * 4;
1.1.1.7 ! root 2545: wrd1 = x_cp_get_long (ad + 0);
! 2546: wrd2 = x_cp_get_long (ad + 4);
! 2547: wrd3 = x_cp_get_long (ad + 8);
1.1.1.4 root 2548: if (incr > 0)
2549: ad += 3 * 4;
1.1.1.6 root 2550: fpp_to_exten (®s.fp[reg], wrd1, wrd2, wrd3);
1.1 root 2551: }
1.1.1.4 root 2552: list <<= 1;
2553: }
2554: }
2555: return ad;
2556: }
2557:
1.1.1.6 root 2558: static bool fp_arithmetic(fpdata *src, fpdata *dst, int extra)
1.1.1.4 root 2559: {
1.1.1.6 root 2560: uae_u64 q = 0;
2561: uae_u8 s = 0;
1.1.1.4 root 2562:
2563: switch (extra & 0x7f)
2564: {
2565: case 0x00: /* FMOVE */
1.1.1.7 ! root 2566: fpp_move(dst, src, PREC_NORMAL);
1.1.1.6 root 2567: break;
2568: case 0x40: /* FSMOVE */
1.1.1.7 ! root 2569: fpp_move(dst, src, PREC_FLOAT);
1.1.1.6 root 2570: break;
2571: case 0x44: /* FDMOVE */
1.1.1.7 ! root 2572: fpp_move(dst, src, PREC_DOUBLE);
1.1.1.4 root 2573: break;
2574: case 0x01: /* FINT */
1.1.1.6 root 2575: fpp_int(dst, src);
1.1.1.4 root 2576: break;
2577: case 0x02: /* FSINH */
1.1.1.6 root 2578: fpp_sinh(dst, src);
1.1.1.4 root 2579: break;
2580: case 0x03: /* FINTRZ */
1.1.1.6 root 2581: fpp_intrz(dst, src);
1.1.1.4 root 2582: break;
2583: case 0x04: /* FSQRT */
1.1.1.7 ! root 2584: fpp_sqrt(dst, src, PREC_NORMAL);
1.1.1.6 root 2585: break;
1.1.1.4 root 2586: case 0x41: /* FSSQRT */
1.1.1.7 ! root 2587: fpp_sqrt(dst, src, PREC_FLOAT);
1.1.1.6 root 2588: break;
1.1.1.4 root 2589: case 0x45: /* FDSQRT */
1.1.1.7 ! root 2590: fpp_sqrt(dst, src, PREC_DOUBLE);
1.1.1.4 root 2591: break;
2592: case 0x06: /* FLOGNP1 */
1.1.1.6 root 2593: fpp_lognp1(dst, src);
1.1.1.4 root 2594: break;
2595: case 0x08: /* FETOXM1 */
1.1.1.6 root 2596: fpp_etoxm1(dst, src);
1.1.1.4 root 2597: break;
2598: case 0x09: /* FTANH */
1.1.1.6 root 2599: fpp_tanh(dst, src);
1.1.1.4 root 2600: break;
2601: case 0x0a: /* FATAN */
1.1.1.6 root 2602: fpp_atan(dst, src);
1.1.1.4 root 2603: break;
2604: case 0x0c: /* FASIN */
1.1.1.6 root 2605: fpp_asin(dst, src);
1.1.1.4 root 2606: break;
2607: case 0x0d: /* FATANH */
1.1.1.6 root 2608: fpp_atanh(dst, src);
1.1.1.4 root 2609: break;
2610: case 0x0e: /* FSIN */
1.1.1.6 root 2611: fpp_sin(dst, src);
1.1.1.4 root 2612: break;
2613: case 0x0f: /* FTAN */
1.1.1.6 root 2614: fpp_tan(dst, src);
1.1.1.4 root 2615: break;
2616: case 0x10: /* FETOX */
1.1.1.6 root 2617: fpp_etox(dst, src);
1.1.1.4 root 2618: break;
2619: case 0x11: /* FTWOTOX */
1.1.1.6 root 2620: fpp_twotox(dst, src);
1.1.1.4 root 2621: break;
2622: case 0x12: /* FTENTOX */
1.1.1.6 root 2623: fpp_tentox(dst, src);
1.1.1.4 root 2624: break;
2625: case 0x14: /* FLOGN */
1.1.1.6 root 2626: fpp_logn(dst, src);
1.1.1.4 root 2627: break;
2628: case 0x15: /* FLOG10 */
1.1.1.6 root 2629: fpp_log10(dst, src);
1.1.1.4 root 2630: break;
2631: case 0x16: /* FLOG2 */
1.1.1.6 root 2632: fpp_log2(dst, src);
1.1.1.4 root 2633: break;
2634: case 0x18: /* FABS */
1.1.1.7 ! root 2635: fpp_abs(dst, src, PREC_NORMAL);
1.1.1.6 root 2636: break;
1.1.1.4 root 2637: case 0x58: /* FSABS */
1.1.1.7 ! root 2638: fpp_abs(dst, src, PREC_FLOAT);
1.1.1.6 root 2639: break;
1.1.1.4 root 2640: case 0x5c: /* FDABS */
1.1.1.7 ! root 2641: fpp_abs(dst, src, PREC_DOUBLE);
1.1.1.4 root 2642: break;
2643: case 0x19: /* FCOSH */
1.1.1.6 root 2644: fpp_cosh(dst, src);
1.1.1.4 root 2645: break;
2646: case 0x1a: /* FNEG */
1.1.1.7 ! root 2647: fpp_neg(dst, src, PREC_NORMAL);
1.1.1.6 root 2648: break;
1.1.1.4 root 2649: case 0x5a: /* FSNEG */
1.1.1.7 ! root 2650: fpp_neg(dst, src, PREC_FLOAT);
1.1.1.6 root 2651: break;
1.1.1.4 root 2652: case 0x5e: /* FDNEG */
1.1.1.7 ! root 2653: fpp_neg(dst, src, PREC_DOUBLE);
1.1.1.4 root 2654: break;
2655: case 0x1c: /* FACOS */
1.1.1.6 root 2656: fpp_acos(dst, src);
1.1.1.4 root 2657: break;
2658: case 0x1d: /* FCOS */
1.1.1.6 root 2659: fpp_cos(dst, src);
1.1.1.4 root 2660: break;
2661: case 0x1e: /* FGETEXP */
1.1.1.6 root 2662: fpp_getexp(dst, src);
1.1.1.4 root 2663: break;
2664: case 0x1f: /* FGETMAN */
1.1.1.6 root 2665: fpp_getman(dst, src);
1.1.1.4 root 2666: break;
2667: case 0x20: /* FDIV */
1.1.1.7 ! root 2668: fpp_div(dst, src, PREC_NORMAL);
1.1.1.6 root 2669: break;
1.1.1.4 root 2670: case 0x60: /* FSDIV */
1.1.1.7 ! root 2671: fpp_div(dst, src, PREC_FLOAT);
1.1.1.6 root 2672: break;
1.1.1.4 root 2673: case 0x64: /* FDDIV */
1.1.1.7 ! root 2674: fpp_div(dst, src, PREC_DOUBLE);
1.1.1.4 root 2675: break;
2676: case 0x21: /* FMOD */
1.1.1.6 root 2677: fpsr_get_quotient(&q, &s);
2678: fpp_mod(dst, src, &q, &s);
2679: fpsr_set_quotient(q, s);
1.1.1.4 root 2680: break;
2681: case 0x22: /* FADD */
1.1.1.7 ! root 2682: fpp_add(dst, src, PREC_NORMAL);
1.1.1.6 root 2683: break;
1.1.1.4 root 2684: case 0x62: /* FSADD */
1.1.1.7 ! root 2685: fpp_add(dst, src, PREC_FLOAT);
1.1.1.6 root 2686: break;
1.1.1.4 root 2687: case 0x66: /* FDADD */
1.1.1.7 ! root 2688: fpp_add(dst, src, PREC_DOUBLE);
1.1.1.4 root 2689: break;
2690: case 0x23: /* FMUL */
1.1.1.7 ! root 2691: fpp_mul(dst, src, PREC_NORMAL);
1.1.1.6 root 2692: break;
1.1.1.4 root 2693: case 0x63: /* FSMUL */
1.1.1.7 ! root 2694: fpp_mul(dst, src, PREC_FLOAT);
1.1.1.6 root 2695: break;
1.1.1.4 root 2696: case 0x67: /* FDMUL */
1.1.1.7 ! root 2697: fpp_mul(dst, src, PREC_DOUBLE);
1.1.1.4 root 2698: break;
2699: case 0x24: /* FSGLDIV */
1.1.1.6 root 2700: fpp_sgldiv(dst, src);
1.1.1.4 root 2701: break;
2702: case 0x25: /* FREM */
1.1.1.6 root 2703: fpsr_get_quotient(&q, &s);
2704: fpp_rem(dst, src, &q, &s);
2705: fpsr_set_quotient(q, s);
1.1.1.4 root 2706: break;
2707: case 0x26: /* FSCALE */
1.1.1.6 root 2708: fpp_scale(dst, src);
1.1.1.4 root 2709: break;
2710: case 0x27: /* FSGLMUL */
1.1.1.6 root 2711: fpp_sglmul(dst, src);
1.1.1.4 root 2712: break;
2713: case 0x28: /* FSUB */
1.1.1.7 ! root 2714: fpp_sub(dst, src, PREC_NORMAL);
1.1.1.4 root 2715: break;
2716: case 0x68: /* FSSUB */
1.1.1.7 ! root 2717: fpp_sub(dst, src, PREC_FLOAT);
1.1.1.4 root 2718: break;
1.1.1.6 root 2719: case 0x6c: /* FDSUB */
1.1.1.7 ! root 2720: fpp_sub(dst, src, PREC_DOUBLE);
1.1.1.4 root 2721: break;
2722: case 0x30: /* FSINCOS */
2723: case 0x31: /* FSINCOS */
2724: case 0x32: /* FSINCOS */
2725: case 0x33: /* FSINCOS */
2726: case 0x34: /* FSINCOS */
2727: case 0x35: /* FSINCOS */
2728: case 0x36: /* FSINCOS */
2729: case 0x37: /* FSINCOS */
1.1.1.6 root 2730: fpp_cos(dst, src);
2731: regs.fp[extra & 7] = *dst;
2732: fpp_sin(dst, src);
1.1.1.4 root 2733: break;
1.1.1.6 root 2734: case 0x38: /* FCMP */
2735: {
2736: fpp_cmp(dst, src);
2737: fpsr_make_status();
2738: fpsr_set_result(dst);
2739: return false;
2740: }
2741: case 0x3a: /* FTST */
2742: {
2743: fpp_tst(dst, src);
2744: fpsr_make_status();
2745: fpsr_set_result(dst);
2746: return false;
2747: }
2748: default:
2749: write_log (_T("Unknown FPU arithmetic function (%02x)\n"), extra & 0x7f);
2750: return false;
1.1 root 2751: }
1.1.1.6 root 2752:
2753: fpsr_set_result(dst);
2754:
2755: if (fpsr_make_status())
2756: return false;
2757:
1.1.1.4 root 2758: return true;
1.1 root 2759: }
2760:
1.1.1.4 root 2761: static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra)
2762: {
2763: int reg = -1;
2764: int v;
1.1.1.6 root 2765: fpdata src, dst;
1.1.1.4 root 2766: uaecptr pc = m68k_getpc () - 4;
2767: uaecptr ad = 0;
1.1 root 2768:
2769: #if DEBUG_FPP
2770: if (!isinrom ())
1.1.1.4 root 2771: write_log (_T("FPP %04x %04x at %08x\n"), opcode & 0xffff, extra, pc);
1.1 root 2772: #endif
1.1.1.4 root 2773: if (fault_if_no_6888x (opcode, extra, pc))
1.1 root 2774: return;
2775:
1.1.1.4 root 2776: switch ((extra >> 13) & 0x7)
2777: {
1.1 root 2778: case 3:
1.1.1.7 ! root 2779: // FMOVE FPP->EA
1.1.1.6 root 2780: if (fp_exception_pending(true))
2781: return;
2782:
2783: regs.fpiar = pc;
2784: fpsr_clear_status();
2785: src = regs.fp[(extra >> 7) & 7];
2786: v = put_fp_value (&src, opcode, extra, pc, &ad);
2787: if (v <= 0) {
2788: if (v == 0)
2789: fpu_noinst (opcode, pc);
2790: return;
2791: }
2792: fpsr_make_status();
2793: fpsr_check_arithmetic_exception(0, &src, opcode, extra, ad);
2794: fp_exception_pending(false); // post/mid instruction
1.1 root 2795: return;
2796:
2797: case 4:
2798: case 5:
1.1.1.7 ! root 2799: // FMOVE Control Register <> Data or Address register
1.1 root 2800: if ((opcode & 0x38) == 0) {
1.1.1.7 ! root 2801: // Dn
1.1.1.4 root 2802: if (fault_if_no_fpu (opcode, extra, 0, pc))
2803: return;
1.1.1.7 ! root 2804: // Only single selected control register is allowed
! 2805: // All control register bits unset = FPIAR
! 2806: uae_u16 bits = extra & (0x1000 | 0x0800 | 0x0400);
! 2807: if (bits && bits != 0x1000 && bits != 0x0800 && bits != 0x400) {
! 2808: // 68060 does not generate f-line if multiple bits are set
! 2809: // but it also works unexpectedly, just do nothing for now.
! 2810: if (currprefs.fpu_model != 68060)
! 2811: fpu_noinst(opcode, pc);
! 2812: return;
! 2813: }
1.1 root 2814: if (extra & 0x2000) {
2815: if (extra & 0x1000)
1.1.1.7 ! root 2816: m68k_dreg (regs, opcode & 7) = fpp_get_fpcr();
1.1 root 2817: if (extra & 0x0800)
1.1.1.7 ! root 2818: m68k_dreg (regs, opcode & 7) = fpp_get_fpsr();
! 2819: if ((extra & 0x0400) || !bits)
1.1 root 2820: m68k_dreg (regs, opcode & 7) = regs.fpiar;
2821: } else {
1.1.1.6 root 2822: if (extra & 0x1000)
2823: fpp_set_fpcr(m68k_dreg (regs, opcode & 7));
1.1 root 2824: if (extra & 0x0800)
1.1.1.6 root 2825: fpp_set_fpsr(m68k_dreg (regs, opcode & 7));
1.1.1.7 ! root 2826: if ((extra & 0x0400) || !bits)
1.1 root 2827: regs.fpiar = m68k_dreg (regs, opcode & 7);
2828: }
2829: } else if ((opcode & 0x38) == 0x08) {
1.1.1.7 ! root 2830: // An
1.1.1.4 root 2831: if (fault_if_no_fpu (opcode, extra, 0, pc))
2832: return;
1.1.1.7 ! root 2833: // Only FPIAR can be moved to/from address register
! 2834: // All bits unset = FPIAR
! 2835: uae_u16 bits = extra & (0x1000 | 0x0800 | 0x0400);
! 2836: // 68060, An and all bits unset: f-line
! 2837: if ((bits && bits != 0x0400) || (!bits && currprefs.fpu_model == 68060)) {
! 2838: fpu_noinst(opcode, pc);
! 2839: return;
! 2840: }
1.1 root 2841: if (extra & 0x2000) {
1.1.1.7 ! root 2842: m68k_areg (regs, opcode & 7) = regs.fpiar;
1.1 root 2843: } else {
1.1.1.7 ! root 2844: regs.fpiar = m68k_areg (regs, opcode & 7);
1.1 root 2845: }
2846: } else if ((opcode & 0x3f) == 0x3c) {
2847: if ((extra & 0x2000) == 0) {
1.1.1.4 root 2848: uae_u32 ext[3];
2849: // 68060 FMOVEM.L #imm,more than 1 control register: unimplemented EA
2850: uae_u16 bits = extra & (0x1000 | 0x0800 | 0x0400);
2851: if (bits && bits != 0x1000 && bits != 0x0800 && bits != 0x400) {
1.1.1.6 root 2852: if (fault_if_60())
1.1.1.4 root 2853: return;
2854: }
2855: // fetch first, use only after all data has been fetched
2856: ext[0] = ext[1] = ext[2] = 0;
2857: if (extra & 0x1000)
2858: ext[0] = x_cp_next_ilong ();
2859: if (extra & 0x0800)
2860: ext[1] = x_cp_next_ilong ();
2861: if (extra & 0x0400)
2862: ext[2] = x_cp_next_ilong ();
1.1.1.6 root 2863: if (fault_if_no_fpu (opcode, extra, 0, pc))
2864: return;
2865: if (extra & 0x1000)
2866: fpp_set_fpcr(ext[0]);
1.1 root 2867: if (extra & 0x0800)
1.1.1.6 root 2868: fpp_set_fpsr(ext[1]);
1.1 root 2869: if (extra & 0x0400)
1.1.1.4 root 2870: regs.fpiar = ext[2];
1.1.1.6 root 2871: } else {
2872: // immediate as destination
2873: fpu_noinst (opcode, pc);
2874: return;
1.1 root 2875: }
2876: } else if (extra & 0x2000) {
1.1.1.7 ! root 2877: /* FMOVEM Control Register->Memory */
1.1 root 2878: uae_u32 ad;
2879: int incr = 0;
2880:
2881: if (get_fp_ad (opcode, &ad) == 0) {
1.1.1.4 root 2882: fpu_noinst (opcode, pc);
1.1 root 2883: return;
2884: }
1.1.1.4 root 2885: if (fault_if_no_fpu (opcode, extra, ad, pc))
2886: return;
1.1.1.7 ! root 2887: if ((opcode & 0x3f) >= 0x3a) {
! 2888: // PC relative modes not supported
! 2889: fpu_noinst(opcode, pc);
! 2890: return;
! 2891: }
1.1.1.4 root 2892:
1.1 root 2893: if ((opcode & 0x38) == 0x20) {
2894: if (extra & 0x1000)
2895: incr += 4;
2896: if (extra & 0x0800)
2897: incr += 4;
2898: if (extra & 0x0400)
2899: incr += 4;
2900: }
2901: ad -= incr;
2902: if (extra & 0x1000) {
1.1.1.7 ! root 2903: x_cp_put_long(ad, fpp_get_fpcr());
1.1 root 2904: ad += 4;
2905: }
2906: if (extra & 0x0800) {
1.1.1.7 ! root 2907: x_cp_put_long(ad, fpp_get_fpsr());
1.1 root 2908: ad += 4;
2909: }
2910: if (extra & 0x0400) {
1.1.1.7 ! root 2911: x_cp_put_long(ad, regs.fpiar);
1.1 root 2912: ad += 4;
2913: }
2914: ad -= incr;
2915: if ((opcode & 0x38) == 0x18)
2916: m68k_areg (regs, opcode & 7) = ad;
2917: if ((opcode & 0x38) == 0x20)
2918: m68k_areg (regs, opcode & 7) = ad;
2919: } else {
1.1.1.7 ! root 2920: /* FMOVEM Memory->Control Register */
1.1 root 2921: uae_u32 ad;
2922: int incr = 0;
2923:
2924: if (get_fp_ad (opcode, &ad) == 0) {
1.1.1.4 root 2925: fpu_noinst (opcode, pc);
1.1 root 2926: return;
2927: }
1.1.1.4 root 2928: if (fault_if_no_fpu (opcode, extra, ad, pc))
2929: return;
2930:
1.1 root 2931: if((opcode & 0x38) == 0x20) {
2932: if (extra & 0x1000)
2933: incr += 4;
2934: if (extra & 0x0800)
2935: incr += 4;
2936: if (extra & 0x0400)
2937: incr += 4;
2938: ad = ad - incr;
2939: }
2940: if (extra & 0x1000) {
1.1.1.6 root 2941: fpp_set_fpcr(x_cp_get_long (ad));
1.1 root 2942: ad += 4;
2943: }
2944: if (extra & 0x0800) {
1.1.1.6 root 2945: fpp_set_fpsr(x_cp_get_long (ad));
1.1 root 2946: ad += 4;
2947: }
2948: if (extra & 0x0400) {
1.1.1.4 root 2949: regs.fpiar = x_cp_get_long (ad);
1.1 root 2950: ad += 4;
2951: }
2952: if ((opcode & 0x38) == 0x18)
2953: m68k_areg (regs, opcode & 7) = ad;
2954: if ((opcode & 0x38) == 0x20)
2955: m68k_areg (regs, opcode & 7) = ad - incr;
2956: }
2957: return;
2958:
2959: case 6:
2960: case 7:
2961: {
1.1.1.7 ! root 2962: // FMOVEM FPP<>Memory
1.1 root 2963: uae_u32 ad, list = 0;
1.1.1.4 root 2964: int incr = 1;
2965: int regdir = 1;
2966: if (get_fp_ad (opcode, &ad) == 0) {
2967: fpu_noinst (opcode, pc);
2968: return;
2969: }
2970: if (fault_if_no_fpu (opcode, extra, ad, pc))
2971: return;
1.1.1.7 ! root 2972:
! 2973: if ((extra & 0x2000) && ((opcode & 0x38) == 0x18 || (opcode & 0x3f) >= 0x3a)) {
! 2974: // FMOVEM FPP->Memory: (An)+ and PC relative modes not supported
! 2975: fpu_noinst(opcode, pc);
! 2976: return;
! 2977: }
! 2978: if (!(extra & 0x2000) && (opcode & 0x38) == 0x20) {
! 2979: // FMOVEM Memory->FPP: -(An) not supported
! 2980: fpu_noinst(opcode, pc);
! 2981: return;
! 2982: }
! 2983:
1.1.1.4 root 2984: switch ((extra >> 11) & 3)
2985: {
2986: case 0: /* static pred */
2987: case 2: /* static postinc */
2988: list = extra & 0xff;
2989: break;
1.1.1.6 root 2990: case 1: /* dynamic pred */
1.1.1.4 root 2991: case 3: /* dynamic postinc */
1.1.1.6 root 2992: if (fault_if_60())
1.1.1.4 root 2993: return;
2994: list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff;
2995: break;
2996: }
1.1.1.6 root 2997: if ((opcode & 0x38) == 0x20) { // -(an)
1.1.1.4 root 2998: incr = -1;
1.1.1.6 root 2999: switch ((extra >> 11) & 3)
3000: {
3001: case 0: /* static pred */
3002: case 1: /* dynamic pred */
3003: regdir = -1;
3004: break;
3005: }
3006: }
1.1 root 3007: if (extra & 0x2000) {
1.1.1.7 ! root 3008: /* FMOVEM FPP->Memory */
1.1.1.4 root 3009: ad = fmovem2mem (ad, list, incr, regdir);
1.1 root 3010: } else {
1.1.1.7 ! root 3011: /* FMOVEM Memory->FPP */
1.1.1.4 root 3012: ad = fmovem2fpp (ad, list, incr, regdir);
1.1 root 3013: }
1.1.1.6 root 3014: if ((opcode & 0x38) == 0x18 || (opcode & 0x38) == 0x20) // (an)+ or -(an)
1.1.1.4 root 3015: m68k_areg (regs, opcode & 7) = ad;
1.1 root 3016: }
3017: return;
3018:
3019: case 0:
3020: case 2: /* Extremely common */
1.1.1.6 root 3021: if (fp_exception_pending(true))
3022: return;
3023:
1.1.1.4 root 3024: regs.fpiar = pc;
1.1 root 3025: reg = (extra >> 7) & 7;
3026: if ((extra & 0xfc00) == 0x5c00) {
1.1.1.6 root 3027: // FMOVECR
3028: if (fault_if_unimplemented_680x0 (opcode, extra, ad, pc, &src, reg))
1.1.1.4 root 3029: return;
1.1.1.6 root 3030: if (extra & 0x40) {
3031: // 6888x and ROM constant 0x40 - 0x7f: f-line
3032: fpu_noinst (opcode, pc);
1.1.1.4 root 3033: return;
1.1 root 3034: }
1.1.1.6 root 3035: fpsr_clear_status();
3036: fpu_get_constant(®s.fp[reg], extra & 0x7f);
3037: fpsr_make_status();
3038: fpsr_check_arithmetic_exception(0, &src, opcode, extra, ad);
1.1 root 3039: return;
3040: }
1.1.1.4 root 3041:
3042: // 6888x does not have special exceptions, check immediately
3043: if (fault_if_unimplemented_6888x (opcode, extra, pc))
3044: return;
3045:
1.1.1.6 root 3046: fpsr_clear_status();
3047:
3048: v = get_fp_value (opcode, extra, &src, pc, &ad);
1.1.1.4 root 3049: if (v <= 0) {
3050: if (v == 0)
3051: fpu_noinst (opcode, pc);
1.1 root 3052: return;
3053: }
3054:
1.1.1.6 root 3055: if (fault_if_no_fpu (opcode, extra, ad, pc))
1.1.1.4 root 3056: return;
1.1 root 3057:
1.1.1.6 root 3058: dst = regs.fp[reg];
3059:
3060: if (fp_is_dyadic(extra))
3061: normalize_or_fault_if_no_denormal_support_dst(opcode, extra, ad, pc, &dst, &src);
3062:
3063: // check for 680x0 unimplemented instruction
3064: if (fault_if_unimplemented_680x0 (opcode, extra, ad, pc, &src, reg))
3065: return;
3066:
3067: // unimplemented datatype was checked in get_fp_value
3068: if (regs.fp_unimp_pend) {
3069: fp_exception_pending(false); // simplification: always mid/post-instruction exception
3070: return;
3071: }
3072:
3073: v = fp_arithmetic(&src, &dst, extra);
3074:
3075: fpsr_check_arithmetic_exception(0, &src, opcode, extra, ad);
3076:
3077: if (v)
3078: regs.fp[reg] = dst;
1.1 root 3079:
3080: return;
3081: default:
1.1.1.4 root 3082: break;
3083: }
3084: fpu_noinst (opcode, pc);
3085: }
3086:
3087: void fpuop_arithmetic (uae_u32 opcode, uae_u16 extra)
3088: {
3089: regs.fpu_state = 1;
3090: regs.fp_exception = false;
3091: fpu_mmu_fixup = false;
1.1.1.7 ! root 3092: #if FPU_LOG
! 3093: write_log(_T("FPUOP %04x %04x PC=%08x\n"), opcode, extra, M68K_GETPC);
! 3094: #endif
1.1.1.4 root 3095: fpuop_arithmetic2 (opcode, extra);
3096: if (fpu_mmu_fixup) {
3097: mmufixup[0].reg = -1;
3098: }
1.1.1.6 root 3099: }
3100:
1.1.1.7 ! root 3101: static void get_features(void)
! 3102: {
! 3103: support_exceptions = (fpp_get_support_flags() & FPU_FEATURE_EXCEPTIONS) != 0;
! 3104: support_denormals = (fpp_get_support_flags() & FPU_FEATURE_DENORMALS) != 0;
! 3105: }
! 3106:
! 3107: void fpu_clearstatus(void)
! 3108: {
! 3109: fpp_clear_status();
! 3110: }
! 3111:
1.1.1.6 root 3112: void fpu_modechange(void)
3113: {
3114: uae_u32 temp_ext[8][3];
1.1.1.7 ! root 3115: //fprintf ( stderr , "fpu_modechange old %d new %d\n" , currprefs.fpu_mode , changed_prefs.fpu_mode );
1.1.1.6 root 3116:
1.1.1.7 ! root 3117: if (currprefs.fpu_mode == changed_prefs.fpu_mode)
1.1.1.6 root 3118: return;
1.1.1.7 ! root 3119: currprefs.fpu_mode = changed_prefs.fpu_mode;
1.1.1.6 root 3120:
1.1.1.7 ! root 3121: set_cpu_caches(true);
! 3122: for (int i = 0; i < 8; i++) {
1.1.1.6 root 3123: fpp_from_exten_fmovem(®s.fp[i], &temp_ext[i][0], &temp_ext[i][1], &temp_ext[i][2]);
3124: }
1.1.1.7 ! root 3125: if (currprefs.fpu_mode > 0) {
! 3126: fp_init_softfloat(currprefs.fpu_model);
! 3127: #ifdef MSVC_LONG_DOUBLE
! 3128: use_long_double = false;
! 3129: } else if (currprefs.fpu_mode < 0) {
! 3130: use_long_double = true;
! 3131: fp_init_native_80();
! 3132: #endif
1.1.1.6 root 3133: } else {
1.1.1.7 ! root 3134: #ifdef MSVC_LONG_DOUBLE
! 3135: use_long_double = false;
! 3136: #endif
1.1.1.6 root 3137: fp_init_native();
1.1 root 3138: }
1.1.1.7 ! root 3139: get_features();
! 3140: for (int i = 0; i < 8; i++) {
1.1.1.6 root 3141: fpp_to_exten_fmovem(®s.fp[i], temp_ext[i][0], temp_ext[i][1], temp_ext[i][2]);
3142: }
3143: }
3144:
3145: #if FPU_TEST
3146:
3147: static void fpu_test(void)
3148: {
3149: fpdata testp;
3150: uae_u32 packed[3];
3151:
3152: fpp_set_fpcr(0x30);
3153: fpp_to_exten_fmovem(&testp, 0xB4000000, 0x80000000, 0x000003fc);
3154: write_log(_T("INPUT: %s (%04x %16llx)\n"), fpp_print(&testp, -1), testp.fpx.high, testp.fpx.low);
3155: fpp_from_pack(&testp, packed, 17);
3156: fpp_to_pack(&testp, packed, 0);
1.1 root 3157: }
3158:
1.1.1.6 root 3159: #endif
3160:
1.1 root 3161: void fpu_reset (void)
3162: {
1.1.1.7 ! root 3163: currprefs.fpu_mode = changed_prefs.fpu_mode;
! 3164: //fprintf(stderr, "fpu_reset %d\n" , currprefs.fpu_mode );
! 3165: if (currprefs.fpu_mode > 0) {
! 3166: fp_init_softfloat(currprefs.fpu_model);
! 3167: #ifdef MSVC_LONG_DOUBLE
! 3168: use_long_double = false;
! 3169: } else if (currprefs.fpu_mode < 0) {
! 3170: use_long_double = true;
! 3171: fp_init_native_80();
! 3172: #endif
1.1.1.6 root 3173: } else {
1.1.1.7 ! root 3174: #ifdef MSVC_LONG_DOUBLE
! 3175: use_long_double = false;
! 3176: #endif
1.1.1.6 root 3177: fp_init_native();
3178: }
3179:
1.1.1.5 root 3180: #ifndef WINUAE_FOR_HATARI
3181: #if defined(CPU_i386) || defined(CPU_x86_64)
3182: init_fpucw_x87();
1.1.1.7 ! root 3183: #ifdef MSVC_LONG_DOUBLE
! 3184: init_fpucw_x87_80();
! 3185: #endif
1.1.1.5 root 3186: #endif
3187: #endif /* ! WINUAE_FOR_HATARI */
3188:
1.1.1.6 root 3189: regs.fpiar = 0;
1.1.1.4 root 3190: regs.fpu_exp_state = 0;
1.1.1.7 ! root 3191: get_features();
1.1.1.6 root 3192: fpp_set_fpcr (0);
3193: fpp_set_fpsr (0);
1.1 root 3194: fpux_restore (NULL);
1.1.1.6 root 3195: // reset precision
3196: fpp_set_mode(0x00000080 | 0x00000010);
3197: fpp_set_mode(0x00000000);
1.1.1.4 root 3198:
1.1.1.6 root 3199: #if FPU_TEST
3200: fpu_test();
1.1.1.4 root 3201: #endif
1.1.1.6 root 3202:
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 ();
1.1.1.6 root 3218: fpp_to_exten_fmovem(®s.fp[i], w1, w2, w3);
1.1 root 3219: }
3220: regs.fpcr = restore_u32 ();
3221: regs.fpsr = restore_u32 ();
3222: regs.fpiar = restore_u32 ();
1.1.1.6 root 3223: fpsr_make_status();
1.1 root 3224: if (flags & 0x80000000) {
1.1.1.4 root 3225: restore_u32 ();
3226: restore_u32 ();
1.1 root 3227: }
1.1.1.6 root 3228: if (flags & 0x20000000) {
3229: uae_u32 v = restore_u32();
3230: regs.fpu_state = (v >> 0) & 15;
3231: regs.fpu_exp_state = (v >> 4) & 15;
3232: regs.fp_unimp_pend = (v >> 8) & 15;
3233: regs.fp_exp_pend = (v >> 16) & 0xff;
3234: regs.fp_opword = restore_u16();
3235: regs.fp_ea = restore_u32();
3236: if (currprefs.fpu_model == 68060 || currprefs.fpu_model >= 68881) {
3237: fsave_data.ccr = restore_u32();
3238: fsave_data.eo[0] = restore_u32();
3239: fsave_data.eo[1] = restore_u32();
3240: fsave_data.eo[2] = restore_u32();
3241: }
3242: if (currprefs.fpu_model == 68060) {
3243: fsave_data.v = restore_u32();
3244: }
3245: if (currprefs.fpu_model == 68040) {
3246: fsave_data.fpiarcu = restore_u32();
3247: fsave_data.cmdreg3b = restore_u32();
3248: fsave_data.cmdreg1b = restore_u32();
3249: fsave_data.stag = restore_u32();
3250: fsave_data.dtag = restore_u32();
3251: fsave_data.e1 = restore_u32();
3252: fsave_data.e3 = restore_u32();
3253: fsave_data.t = restore_u32();
3254: fsave_data.fpt[0] = restore_u32();
3255: fsave_data.fpt[1] = restore_u32();
3256: fsave_data.fpt[2] = restore_u32();
3257: fsave_data.et[0] = restore_u32();
3258: fsave_data.et[1] = restore_u32();
3259: fsave_data.et[2] = restore_u32();
3260: fsave_data.wbt[0] = restore_u32();
3261: fsave_data.wbt[1] = restore_u32();
3262: fsave_data.wbt[2] = restore_u32();
3263: fsave_data.grs = restore_u32();
3264: fsave_data.wbte15 = restore_u32();
3265: fsave_data.wbtm66 = restore_u32();
3266: }
3267: }
1.1.1.4 root 3268: write_log(_T("FPU: %d\n"), currprefs.fpu_model);
1.1 root 3269: return src;
3270: }
3271:
3272: uae_u8 *save_fpu (int *len, uae_u8 *dstptr)
3273: {
1.1.1.6 root 3274: uae_u32 w1, w2, w3, v;
1.1.1.4 root 3275: uae_u8 *dstbak, *dst;
1.1 root 3276: int i;
3277:
3278: *len = 0;
1.1.1.4 root 3279: #ifndef WINUAE_FOR_HATARI
1.1.1.6 root 3280: /* Under Hatari, we save all FPU variables, even if fpu_model==0 */
1.1 root 3281: if (currprefs.fpu_model == 0)
3282: return 0;
1.1.1.4 root 3283: #endif
1.1 root 3284: if (dstptr)
3285: dstbak = dst = dstptr;
3286: else
1.1.1.4 root 3287: dstbak = dst = xmalloc (uae_u8, 4+4+8*10+4+4+4+4+4+2*10+3*(4+2));
1.1 root 3288: save_u32 (currprefs.fpu_model);
1.1.1.6 root 3289: save_u32 (0x80000000 | 0x20000000);
1.1 root 3290: for (i = 0; i < 8; i++) {
1.1.1.6 root 3291: fpp_from_exten_fmovem(®s.fp[i], &w1, &w2, &w3);
1.1.1.4 root 3292: save_u16 (w1 >> 16);
1.1 root 3293: save_u32 (w2);
1.1.1.4 root 3294: save_u32 (w3);
1.1 root 3295: }
3296: save_u32 (regs.fpcr);
3297: save_u32 (regs.fpsr);
3298: save_u32 (regs.fpiar);
1.1.1.4 root 3299:
1.1 root 3300: save_u32 (-1);
1.1.1.6 root 3301: save_u32 (1);
1.1.1.4 root 3302:
1.1.1.6 root 3303: v = regs.fpu_state;
3304: v |= regs.fpu_exp_state << 4;
3305: v |= regs.fp_unimp_pend << 8;
3306: v |= regs.fp_exp_pend << 16;
3307: save_u32(v);
3308: save_u16(regs.fp_opword);
3309: save_u32(regs.fp_ea);
3310:
3311: if (currprefs.fpu_model == 68060 || currprefs.fpu_model >= 68881) {
3312: save_u32(fsave_data.ccr);
3313: save_u32(fsave_data.eo[0]);
3314: save_u32(fsave_data.eo[1]);
3315: save_u32(fsave_data.eo[2]);
3316: }
3317: if (currprefs.fpu_model == 68060) {
3318: save_u32(fsave_data.v);
3319: }
3320: if (currprefs.fpu_model == 68040) {
3321: save_u32(fsave_data.fpiarcu);
3322: save_u32(fsave_data.cmdreg3b);
3323: save_u32(fsave_data.cmdreg1b);
3324: save_u32(fsave_data.stag);
3325: save_u32(fsave_data.dtag);
3326: save_u32(fsave_data.e1);
3327: save_u32(fsave_data.e3);
3328: save_u32(fsave_data.t);
3329: save_u32(fsave_data.fpt[0]);
3330: save_u32(fsave_data.fpt[1]);
3331: save_u32(fsave_data.fpt[2]);
3332: save_u32(fsave_data.et[0]);
3333: save_u32(fsave_data.et[1]);
3334: save_u32(fsave_data.et[2]);
3335: save_u32(fsave_data.wbt[0]);
3336: save_u32(fsave_data.wbt[1]);
3337: save_u32(fsave_data.wbt[2]);
3338: save_u32(fsave_data.grs);
3339: save_u32(fsave_data.wbte15);
3340: save_u32(fsave_data.wbtm66);
3341: }
1.1.1.4 root 3342:
1.1 root 3343: *len = dst - dstbak;
3344: return dstbak;
3345: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.