1 /*
2 * UAE - The Un*x Amiga Emulator
3 *
4 * MC68881/68882/68040/68060 FPU emulation
5 *
6 * Copyright 1996 Herman ten Brugge
7 * Modified 2005 Peter Keunecke
8 * 68040+ exceptions and more by Toni Wilen
9 */
10 
11 #define __USE_ISOC9X  /* We might be able to pick up a NaN */
12 
13 #define FPU_TEST 0
14 #define FPU_LOG 0
15 
16 #include <math.h>
17 #include <float.h>
18 #include <fenv.h>
19 
20 #include "sysconfig.h"
21 #include "sysdeps.h"
22 
23 #ifdef WINUAE_FOR_HATARI
24 #include "main.h"
25 #include "hatari-glue.h"
26 #include "log.h"
27 #endif
28 
29 #include "options_cpu.h"
30 #include "memory.h"
31 #include "uae/attributes.h"
32 #include "uae/vm.h"
33 #include "custom.h"
34 #include "events.h"
35 #include "newcpu.h"
36 #include "fpp.h"
37 #include "savestate.h"
38 #include "cpu_prefetch.h"
39 #include "cpummu.h"
40 #include "cpummu030.h"
41 #include "debug.h"
42 
43 #include "softfloat/softfloat.h"
44 
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 
55 FPP_PRINT fpp_print;
56 
57 FPP_IS fpp_unset_snan;
58 FPP_IS fpp_is_init;
59 FPP_IS fpp_is_snan;
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;
66 FPP_A fpp_fix_infinity;
67 
68 FPP_GET_STATUS fpp_get_status;
69 FPP_CLEAR_STATUS fpp_clear_status;
70 FPP_SET_MODE fpp_set_mode;
71 FPP_SUPPORT_FLAGS fpp_get_support_flags;
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;
142 
143 #define DEBUG_FPP 0
144 #define EXCEPTION_FPP 0
145 
isinrom(void)146 STATIC_INLINE int isinrom (void)
147 {
148 	return (munge24 (m68k_getpc ()) & 0xFFF80000) == 0xF80000 && !currprefs.mmu_model;
149 }
150 
jit_fpu(void)151 static bool jit_fpu(void)
152 {
153 	return currprefs.cachesize && currprefs.compfpu;
154 }
155 
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 
235 static bool fpu_mmu_fixup;
236 
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;
325 
reset_fsave_data(void)326 static void reset_fsave_data(void)
327 {
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 
get_ftag(fpdata * src,int size)350 static uae_u32 get_ftag(fpdata *src, int size)
351 {
352 	fpp_is_init(src);
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
365 }
366 
fp_is_dyadic(uae_u16 extra)367 STATIC_INLINE bool fp_is_dyadic(uae_u16 extra)
368 {
369 	return ((extra & 0x30) == 0x20 || (extra & 0x7f) == 0x38);
370 }
371 
fp_exception_pending(bool pre)372 static bool fp_exception_pending(bool pre)
373 {
374 	// first check for pending arithmetic exceptions
375 	if (support_exceptions && !jit_fpu()) {
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;
399 }
400 
fp_unimp_instruction_exception_pending(void)401 static void fp_unimp_instruction_exception_pending(void)
402 {
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 	}
412 }
413 
fpsr_set_exception(uae_u32 exception)414 void fpsr_set_exception(uae_u32 exception)
415 {
416 	regs.fpsr |= exception;
417 }
418 
fpsr_get_vector(uae_u32 exception)419 static uae_u32 fpsr_get_vector(uae_u32 exception)
420 {
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;
430 }
431 
fpsr_check_arithmetic_exception(uae_u32 mask,fpdata * src,uae_u32 opcode,uae_u16 extra,uae_u32 ea)432 static void fpsr_check_arithmetic_exception(uae_u32 mask, fpdata *src, uae_u32 opcode, uae_u16 extra, uae_u32 ea)
433 {
434 	if (!support_exceptions || jit_fpu())
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;
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) {
443 		exception |= regs.fpsr & (FPSR_OVFL | FPSR_UNFL | mask);
444 	}
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 
457 		if (!support_exceptions || jit_fpu()) {
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 
521 				fpp_is_init(src);
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(&regs.fp[reg], &fsave_data.fpt[0], &fsave_data.fpt[1], &fsave_data.fpt[2]);
551 							fsave_data.dtag = get_ftag(&regs.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(&regs.fp[reg], &fsave_data.fpt[0], &fsave_data.fpt[1], &fsave_data.fpt[2]);
566 						fsave_data.dtag = get_ftag(&regs.fp[reg], -1);
567 					}
568 				}
569 			}
570 		}
571 	}
572 }
573 
fpsr_set_result(fpdata * result)574 static void fpsr_set_result(fpdata *result)
575 {
576 #ifdef JIT
577 	regs.fp_result = *result;
578 #endif
579 	// condition code byte
580 	regs.fpsr &= 0x00fffff8; // clear cc
581 	fpp_is_init(result);
582 	if (fpp_is_nan(result)) {
583 		regs.fpsr |= FPSR_CC_NAN;
584 	} else if (fpp_is_zero(result)) {
585 		regs.fpsr |= FPSR_CC_Z;
586 	} else if (fpp_is_infinity(result)) {
587 		regs.fpsr |= FPSR_CC_I;
588 	}
589 	if (fpp_is_neg(result))
590 		regs.fpsr |= FPSR_CC_N;
591 }
fpsr_clear_status(void)592 static void fpsr_clear_status(void)
593 {
594 	// clear exception status byte only
595 	regs.fpsr &= 0x0fff00f8;
596 
597 	// clear external status
598 	fpp_clear_status();
599 }
600 
fpsr_make_status(void)601 static uae_u32 fpsr_make_status(void)
602 {
603 	uae_u32 exception;
604 
605 	// get external status
606 	fpp_get_status(&regs.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 
620 	if (!support_exceptions || jit_fpu())
621 		return 0;
622 
623 	// return exceptions that interrupt calculation
624 	exception = regs.fpsr & regs.fpcr & (FPSR_SNAN | FPSR_OPERR | FPSR_DZ);
625 	if (currprefs.cpu_model >= 68040 && currprefs.fpu_model && currprefs.fpu_no_unimplemented)
626 		exception |= regs.fpsr & (FPSR_OVFL | FPSR_UNFL);
627 
628 	return exception;
629 }
630 
fpsr_set_bsun(void)631 static int fpsr_set_bsun(void)
632 {
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);
639 		if (support_exceptions && !jit_fpu()) {
640 			regs.fp_exp_pend = fpsr_get_vector(FPSR_BSUN);
641 			fp_exception_pending(true);
642 			return 1;
643 		}
644 	}
645 	return 0;
646 }
647 
fpsr_set_quotient(uae_u64 quot,uae_u8 sign)648 static void fpsr_set_quotient(uae_u64 quot, uae_u8 sign)
649 {
650 	regs.fpsr &= 0x0f00fff8;
651 	regs.fpsr |= (quot << 16) & FPSR_QUOT_LSB;
652 	regs.fpsr |= sign ? FPSR_QUOT_SIGN : 0;
653 }
fpsr_get_quotient(uae_u64 * quot,uae_u8 * sign)654 static void fpsr_get_quotient(uae_u64 *quot, uae_u8 *sign)
655 {
656 	*quot = (regs.fpsr & FPSR_QUOT_LSB) >> 16;
657 	*sign = (regs.fpsr & FPSR_QUOT_SIGN) ? 1 : 0;
658 }
659 
fpp_get_fpsr(void)660 uae_u32 fpp_get_fpsr (void)
661 {
662 #ifdef JIT
663 	if (currprefs.cachesize && currprefs.compfpu) {
664 		regs.fpsr &= 0x00fffff8; // clear cc
665 		fpp_is_init(&regs.fp_result);
666 		if (fpp_is_nan(&regs.fp_result)) {
667 			regs.fpsr |= FPSR_CC_NAN;
668 		} else if (fpp_is_zero(&regs.fp_result)) {
669 			regs.fpsr |= FPSR_CC_Z;
670 		} else if (fpp_is_infinity(&regs.fp_result)) {
671 			regs.fpsr |= FPSR_CC_I;
672 		}
673 		if (fpp_is_neg(&regs.fp_result))
674 			regs.fpsr |= FPSR_CC_N;
675 	}
676 #endif
677 	return regs.fpsr & 0x0ffffff8;
678 }
679 
fpp_get_fpcr(void)680 static uae_u32 fpp_get_fpcr(void)
681 {
682 	return regs.fpcr & (currprefs.fpu_model == 68040 ? 0xffff : 0xfff0);
683 }
684 
fpp_set_fpcr(uae_u32 val)685 static void fpp_set_fpcr (uae_u32 val)
686 {
687 	fpp_set_mode(val);
688 	regs.fpcr = val & 0xffff;
689 }
690 
fpnan(fpdata * fpd)691 static void fpnan (fpdata *fpd)
692 {
693 	fpp_to_exten(fpd, xhex_nan[0], xhex_nan[1], xhex_nan[2]);
694 }
695 
fpclear(fpdata * fpd)696 static void fpclear (fpdata *fpd)
697 {
698 	fpp_from_int(fpd, 0);
699 }
fpset(fpdata * fpd,uae_s32 val)700 static void fpset (fpdata *fpd, uae_s32 val)
701 {
702 	fpp_from_int(fpd, val);
703 }
704 
fpp_set_fpsr(uae_u32 val)705 static void fpp_set_fpsr (uae_u32 val)
706 {
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(&regs.fp_result);
714 		else if (val & 0x04000000)
715 			fpset(&regs.fp_result, 0);
716 		else if (val & 0x08000000)
717 			fpset(&regs.fp_result, -1);
718 		else
719 			fpset(&regs.fp_result, 1);
720 	}
721 #endif
722 }
723 
fpu_get_constant(fpdata * fpd,int cr)724 bool fpu_get_constant(fpdata *fpd, int cr)
725 {
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 		}
858 	}
859 
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 	}
869 
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
883 static void fpu_format_error (void)
884 {
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;
894 	x_cp_put_long (m68k_areg (regs, 7), 0x0000 + 14 * 4);
895 	m68k_areg (regs, 7) -= 4;
896 	x_cp_put_long (m68k_areg (regs, 7), m68k_getpc ());
897 	m68k_areg (regs, 7) -= 2;
898 	x_cp_put_long (m68k_areg (regs, 7), regs.sr);
899 	newpc = x_cp_get_long (regs.vbr + 14 * 4);
900 	m68k_setpc (newpc);
901 #ifdef JIT
902 	set_special (SPCFLAG_END_COMPILE);
903 #endif
904 	regs.fp_exception = true;
905 }
906 #endif
907 
fp_unimp_instruction(uae_u16 opcode,uae_u16 extra,uae_u32 ea,uaecptr oldpc,fpdata * src,int reg,int size)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;
912 
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(&regs.fp[reg], &fsave_data.fpt[0], &fsave_data.fpt[1], &fsave_data.fpt[2]);
931 				fsave_data.dtag = get_ftag(&regs.fp[reg], -1);
932 			}
933 		}
934 	}
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 
fp_unimp_datatype(uae_u16 opcode,uae_u16 extra,uae_u32 ea,uaecptr oldpc,fpdata * src,uae_u32 * packed)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 
968 	if (currprefs.cpu_model == 68060) {
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]);
975 		}
976 	} else if (currprefs.cpu_model == 68040) {
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]);
998 				fsave_data.stag = get_ftag(src, (opclass == 0) ? -1U : size);
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(&regs.fp[reg], &fsave_data.fpt[0], &fsave_data.fpt[1], &fsave_data.fpt[2]);
1004 					fsave_data.dtag = get_ftag(&regs.fp[reg], -1);
1005 				}
1006 			}
1007 		}
1008 	}
1009 	if (warned > 0) {
1010 		write_log (_T("FPU unimplemented datatype (%s): OP=%04X-%04X SRC=%08X-%08X-%08X EA=%08X PC=%08X\n"),
1011 			packed ? _T("packed") : _T("denormal"), opcode, extra,
1012 			packed ? fsave_data.fpt[2] : fsave_data.et[0], fsave_data.et[1], fsave_data.et[2], ea, oldpc);
1013 #if EXCEPTION_FPP == 0
1014 		warned--;
1015 #endif
1016 	}
1017 	regs.fp_exception = true;
1018 }
1019 
fpu_op_illg(uae_u16 opcode,uae_u32 ea,uaecptr oldpc)1020 static void fpu_op_illg(uae_u16 opcode, uae_u32 ea, uaecptr oldpc)
1021 {
1022 	if ((currprefs.cpu_model == 68060 && (currprefs.fpu_model == 0 || (regs.pcr & 2)))
1023 		|| (currprefs.cpu_model == 68040 && currprefs.fpu_model == 0)) {
1024 			regs.fp_unimp_ins  = true;
1025 			regs.fp_ea = ea;
1026 			fp_unimp_instruction_exception_pending();
1027 			return;
1028 	}
1029 	regs.fp_exception = true;
1030 	m68k_setpc (oldpc);
1031 	op_illg (opcode);
1032 }
1033 
fpu_noinst(uae_u16 opcode,uaecptr pc)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 
if_no_fpu(void)1044 static bool if_no_fpu(void)
1045 {
1046 	return (regs.pcr & 2) || currprefs.fpu_model <= 0;
1047 }
1048 
fault_if_no_fpu(uae_u16 opcode,uae_u16 extra,uaecptr ea,uaecptr oldpc)1049 static bool fault_if_no_fpu (uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc)
1050 {
1051 	if (if_no_fpu()) {
1052 #if EXCEPTION_FPP
1053 		write_log (_T("no FPU: %04X-%04X PC=%08X\n"), opcode, extra, oldpc);
1054 #endif
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);
1061 		return true;
1062 	}
1063 	return false;
1064 }
1065 
fault_if_unimplemented_680x0(uae_u16 opcode,uae_u16 extra,uaecptr ea,uaecptr oldpc,fpdata * src,int reg)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
1075 			fp_unimp_instruction(opcode, extra, ea, oldpc, src, reg, -1);
1076 			return true;
1077 		}
1078 		uae_u16 v = extra & 0x7f;
1079 		/* 68040/68060 only variants. 6888x = F-line exception. */
1080 		switch (v)
1081 		{
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;
1111 			case 0x01: /* FINT */
1112 			case 0x03: /* FINTRZ */
1113 			// Unimplemented only in 68040.
1114 			if(currprefs.cpu_model != 68040) {
1115 				return false;
1116 			}
1117 			default:
1118 			fp_unimp_instruction(opcode, extra, ea, oldpc, src, reg, -1);
1119 			return true;
1120 		}
1121 	}
1122 	return false;
1123 }
1124 
fault_if_unimplemented_6888x(uae_u16 opcode,uae_u16 extra,uaecptr oldpc)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 */
1133 			case 0x02: /* FSINH */
1134 			case 0x03: /* FINTRZ */
1135 			case 0x04: /* FSQRT */
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 */
1150 			case 0x18: /* FABS */
1151 			case 0x19: /* FCOSH */
1152 			case 0x1a: /* FNEG */
1153 			case 0x1c: /* FACOS */
1154 			case 0x1d: /* FCOS */
1155 			case 0x1e: /* FGETEXP */
1156 			case 0x1f: /* FGETMAN */
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 */
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 */
1174 			case 0x38: /* FCMP */
1175 			case 0x3a: /* FTST */
1176 				return false;
1177 			default:
1178 				fpu_noinst (opcode, oldpc);
1179 				return true;
1180 		}
1181 	}
1182 	return false;
1183 }
1184 
fault_if_60(void)1185 static bool fault_if_60 (void)
1186 {
1187 	if (currprefs.cpu_model == 68060 && currprefs.fpu_model && currprefs.fpu_no_unimplemented) {
1188 		Exception(60);
1189 		return true;
1190 	}
1191 	return false;
1192 }
1193 
fault_if_no_fpu_u(uae_u16 opcode,uae_u16 extra,uaecptr ea,uaecptr oldpc)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.
1200 		regs.fp_unimp_ins = true;
1201 		regs.fp_ea = ea;
1202 		fp_unimp_instruction_exception_pending();
1203 		return true;
1204 	}
1205 	return false;
1206 }
1207 
fault_if_no_6888x(uae_u16 opcode,uae_u16 extra,uaecptr oldpc)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);
1217 		return true;
1218 	}
1219 	return false;
1220 }
1221 
get_fpu_version(int model)1222 static int get_fpu_version (int model)
1223 {
1224 	int v = 0;
1225 
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;
1238 	}
1239 	return v;
1240 }
1241 
fpu_null(void)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;
1249 	for (int i = 0; i < 8; i++)
1250 		fpnan (&regs.fp[i]);
1251 }
1252 
1253 // 68040/060 does not support denormals
normalize_or_fault_if_no_denormal_support(uae_u16 opcode,uae_u16 extra,uaecptr ea,uaecptr oldpc,fpdata * src)1254 static bool normalize_or_fault_if_no_denormal_support(uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc, fpdata *src)
1255 {
1256 	if (!support_denormals)
1257 		return false;
1258 	fpp_is_init(src);
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
1263 			} else {
1264 				fp_unimp_datatype(opcode, extra, ea, oldpc, src, NULL);
1265 				return true;
1266 			}
1267 		} else {
1268 			fpp_normalize(src);
1269 		}
1270 	}
1271 	return false;
1272 }
normalize_or_fault_if_no_denormal_support_dst(uae_u16 opcode,uae_u16 extra,uaecptr ea,uaecptr oldpc,fpdata * dst,fpdata * src)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 {
1275 	if (!support_denormals)
1276 		return false;
1277 	fpp_is_init(dst);
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);
1288 		}
1289 	}
1290 	return false;
1291 }
1292 
1293 // 68040/060 does not support packed decimal format
fault_if_no_packed_support(uae_u16 opcode,uae_u16 extra,uaecptr ea,uaecptr oldpc,fpdata * src,uae_u32 * packed)1294 static bool fault_if_no_packed_support(uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc, fpdata *src, uae_u32 *packed)
1295 {
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;
1299 	}
1300 	return false;
1301  }
1302 
1303 // 68040 does not support move to integer format
fault_if_68040_integer_nonmaskable(uae_u16 opcode,uae_u16 extra,uaecptr ea,uaecptr oldpc,fpdata * src)1304 static bool fault_if_68040_integer_nonmaskable(uae_u16 opcode, uae_u16 extra, uaecptr ea, uaecptr oldpc, fpdata *src)
1305 {
1306 	if (currprefs.cpu_model == 68040 && currprefs.fpu_model && currprefs.fpu_mode > 0) {
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
1311 			return true;
1312 		}
1313 	}
1314 	return false;
1315 }
1316 
get_fp_value(uae_u32 opcode,uae_u16 extra,fpdata * src,uaecptr oldpc,uae_u32 * adp)1317 static int get_fp_value (uae_u32 opcode, uae_u16 extra, fpdata *src, uaecptr oldpc, uae_u32 *adp)
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 };
1323 #ifndef WINUAE_FOR_HATARI
1324 	uae_u32 exts[3];
1325 #else
1326 	uae_u32 exts[3] = { 0 };
1327 #endif
1328 	int doext = 0;
1329 
1330 	if (!(extra & 0x4000)) {
1331 		if (fault_if_no_fpu (opcode, extra, 0, oldpc))
1332 			return -1;
1333 		*src = regs.fp[(extra >> 10) & 7];
1334 		normalize_or_fault_if_no_denormal_support(opcode, extra, 0, oldpc, src);
1335 		return 1;
1336 	}
1337 	mode = (opcode >> 3) & 7;
1338 	reg = opcode & 7;
1339 	size = (extra >> 10) & 7;
1340 
1341 	switch (mode) {
1342 		case 0: // Dn
1343 			if ((size == 0 || size == 1 ||size == 4 || size == 6) && fault_if_no_fpu (opcode, extra, 0, oldpc))
1344 				return -1;
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:
1357 					fpp_to_single (src, m68k_dreg (regs, reg));
1358 					normalize_or_fault_if_no_denormal_support(opcode, extra, 0, oldpc, src);
1359 					break;
1360 				default:
1361 					return 0;
1362 			}
1363 			return 1;
1364 		case 1: // An
1365 			return 0;
1366 		case 2: // (An)
1367 			ad = m68k_areg (regs, reg);
1368 			break;
1369 		case 3: // (An)+
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;
1374 			ad = m68k_areg (regs, reg);
1375 			m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size];
1376 			break;
1377 		case 4: // -(An)
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;
1382 			m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size];
1383 			ad = m68k_areg (regs, reg);
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;
1387 			break;
1388 		case 5: // (d16,An)
1389 			ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) x_cp_next_iword ();
1390 			break;
1391 		case 6: // (d8,An,Xn)+
1392 			ad = x_cp_get_disp_ea_020 (m68k_areg (regs, reg), 0);
1393 			break;
1394 		case 7:
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
1421 						if (fault_if_60())
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 
1445 	if (fault_if_no_fpu (opcode, extra, ad, oldpc))
1446 		return -1;
1447 
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 
1458 	switch (size)
1459 	{
1460 		case 0: // L
1461 			fpset(src, (uae_s32) (doext ? exts[0] : x_cp_get_long (ad)));
1462 			break;
1463 		case 1: // S
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);
1466 			break;
1467 		case 2: // X
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));
1475 				fpp_to_exten (src, wrd1, wrd2, wrd3);
1476 				normalize_or_fault_if_no_denormal_support(opcode, extra, adold, oldpc, src);
1477 			}
1478 			break;
1479 		case 3: // P
1480 			{
1481 				uae_u32 wrd[3];
1482 				if (currprefs.cpu_model == 68060) {
1483 					if (fault_if_no_packed_support (opcode, extra, adold, oldpc, NULL, wrd))
1484 						return 1;
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));
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);
1495 				return 1;
1496 			}
1497 			break;
1498 		case 4: // W
1499 			fpset(src, (uae_s16) (doext ? exts[0] : x_cp_get_word (ad)));
1500 			break;
1501 		case 5: // D
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));
1507 				fpp_to_double (src, wrd1, wrd2);
1508 				normalize_or_fault_if_no_denormal_support(opcode, extra, adold, oldpc, src);
1509 			}
1510 			break;
1511 		case 6: // B
1512 			fpset(src, (uae_s8) (doext ? exts[0] : x_cp_get_byte (ad)));
1513 			break;
1514 		default:
1515 			return 0;
1516 	}
1517 	return 1;
1518 }
1519 
put_fp_value(fpdata * value,uae_u32 opcode,uae_u16 extra,uaecptr oldpc,uae_u32 * adp)1520 static int put_fp_value (fpdata *value, uae_u32 opcode, uae_u16 extra, uaecptr oldpc, uae_u32 *adp)
1521 {
1522 	int size, mode, reg;
1523 	uae_u32 ad = 0;
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 };
1526 
1527 #if DEBUG_FPP
1528 	if (!isinrom ())
1529 		write_log (_T("PUTFP: %04X %04X\n"), opcode, extra);
1530 #endif
1531 #if 0
1532 	if (!(extra & 0x4000)) {
1533 		if (fault_if_no_fpu (opcode, extra, 0, oldpc))
1534 			return 1;
1535 		regs.fp[(extra >> 10) & 7] = *value;
1536 		return 1;
1537 	}
1538 #endif
1539 	reg = opcode & 7;
1540 	mode = (opcode >> 3) & 7;
1541 	size = (extra >> 10) & 7;
1542 	switch (mode)
1543 	{
1544 		case 0: // Dn
1545 
1546 			if ((size == 0 || size == 1 ||size == 4 || size == 6) && fault_if_no_fpu (opcode, extra, 0, oldpc))
1547 				return -1;
1548 			switch (size)
1549 			{
1550 				case 6: // B
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)
1554 						| (m68k_dreg (regs, reg) & ~0xff)));
1555 					if (fault_if_68040_integer_nonmaskable(opcode, extra, ad, oldpc, value))
1556 						return -1;
1557 					break;
1558 				case 4: // W
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)
1562 						| (m68k_dreg (regs, reg) & ~0xffff)));
1563 					if (fault_if_68040_integer_nonmaskable(opcode, extra, ad, oldpc, value))
1564 						return -1;
1565 					break;
1566 				case 0: // L
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;
1572 					break;
1573 				case 1: // S
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);
1577 					break;
1578 				default:
1579 					return 0;
1580 			}
1581 			return 1;
1582 		case 1: // An
1583 			return 0;
1584 		case 2: // (An)
1585 			ad = m68k_areg (regs, reg);
1586 			break;
1587 		case 3: // (An)+
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;
1592 			ad = m68k_areg (regs, reg);
1593 			m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size];
1594 			break;
1595 		case 4: // -(An)
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;
1600 			m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size];
1601 			ad = m68k_areg (regs, reg);
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;
1605 			break;
1606 		case 5: // (d16,An)
1607 			ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) x_cp_next_iword ();
1608 			break;
1609 		case 6: // (d8,An,Xn)+
1610 			ad = x_cp_get_disp_ea_020 (m68k_areg (regs, reg), 0);
1611 			break;
1612 		case 7:
1613 			switch (reg)
1614 			{
1615 				case 0: // (xxx).W
1616 					ad = (uae_s32) (uae_s16) x_cp_next_iword ();
1617 					break;
1618 				case 1: // (xxx).L
1619 					ad = x_cp_next_ilong ();
1620 					break;
1621 				// Immediate and PC-relative modes are not supported
1622 				default:
1623 					return 0;
1624 			}
1625 	}
1626 
1627 	*adp = ad;
1628 
1629 	if (fault_if_no_fpu (opcode, extra, ad, oldpc))
1630 		return -1;
1631 
1632 	switch (size)
1633 	{
1634 		case 0: // L
1635 			if (normalize_or_fault_if_no_denormal_support(opcode, extra, ad, oldpc, value))
1636 				return 1;
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;
1640 			break;
1641 		case 1: // S
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));
1645 			break;
1646 		case 2: // X
1647 			{
1648 				if (normalize_or_fault_if_no_denormal_support(opcode, extra, ad, oldpc, value))
1649 					return 1;
1650 				uae_u32 wrd1, wrd2, wrd3;
1651 				fpp_from_exten(value, &wrd1, &wrd2, &wrd3);
1652 				x_cp_put_long (ad, wrd1);
1653 				ad += 4;
1654 				x_cp_put_long (ad, wrd2);
1655 				ad += 4;
1656 				x_cp_put_long (ad, wrd3);
1657 			}
1658 			break;
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)
1661 			{
1662 				uae_u32 wrd[3];
1663 				int kfactor;
1664 				if (fault_if_no_packed_support (opcode, extra, ad, oldpc, value, wrd))
1665 					return 1;
1666 				kfactor = size == 7 ? m68k_dreg (regs, (extra >> 4) & 7) : extra;
1667 				kfactor &= 127;
1668 				if (kfactor & 64)
1669 					kfactor |= ~63;
1670 				fpp_normalize(value);
1671 				fpp_from_pack(value, wrd, kfactor);
1672 				x_cp_put_long (ad, wrd[0]);
1673 				ad += 4;
1674 				x_cp_put_long (ad, wrd[1]);
1675 				ad += 4;
1676 				x_cp_put_long (ad, wrd[2]);
1677 			}
1678 			break;
1679 		case 4: // W
1680 			if (normalize_or_fault_if_no_denormal_support(opcode, extra, ad, oldpc, value))
1681 				return 1;
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;
1685 			break;
1686 		case 5: // D
1687 			{
1688 				if (normalize_or_fault_if_no_denormal_support(opcode, extra, ad, oldpc, value))
1689 					return 1;
1690 				uae_u32 wrd1, wrd2;
1691 				fpp_from_double(value, &wrd1, &wrd2);
1692 				x_cp_put_long (ad, wrd1);
1693 				ad += 4;
1694 				x_cp_put_long (ad, wrd2);
1695 			}
1696 			break;
1697 		case 6: // B
1698 			if (normalize_or_fault_if_no_denormal_support(opcode, extra, ad, oldpc, value))
1699 				return 1;
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;
1703 			break;
1704 		default:
1705 			return 0;
1706 	}
1707 	return 1;
1708 }
1709 
get_fp_ad(uae_u32 opcode,uae_u32 * ad)1710 static int get_fp_ad (uae_u32 opcode, uae_u32 * ad)
1711 {
1712 	int mode;
1713 	int reg;
1714 
1715 	mode = (opcode >> 3) & 7;
1716 	reg = opcode & 7;
1717 	switch (mode)
1718 	{
1719 		case 0: // Dn
1720 		case 1: // An
1721 			return 0;
1722 		case 2: // (An)
1723 			*ad = m68k_areg (regs, reg);
1724 			break;
1725 		case 3: // (An)+
1726 			*ad = m68k_areg (regs, reg);
1727 			break;
1728 		case 4: // -(An)
1729 			*ad = m68k_areg (regs, reg);
1730 			break;
1731 		case 5: // (d16,An)
1732 			*ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) x_cp_next_iword ();
1733 			break;
1734 		case 6: // (d8,An,Xn)+
1735 			*ad = x_cp_get_disp_ea_020 (m68k_areg (regs, reg), 0);
1736 			break;
1737 		case 7:
1738 			switch (reg)
1739 			{
1740 				case 0: // (xxx).W
1741 					*ad = (uae_s32) (uae_s16) x_cp_next_iword ();
1742 					break;
1743 				case 1: // (xxx).L
1744 					*ad = x_cp_next_ilong ();
1745 					break;
1746 				case 2: // (d16,PC)
1747 					*ad = m68k_getpc ();
1748 					*ad += (uae_s32) (uae_s16) x_cp_next_iword ();
1749 					break;
1750 				case 3: // (d8,PC,Xn)+
1751 					*ad = x_cp_get_disp_ea_020 (m68k_getpc (), 0);
1752 					break;
1753 				default:
1754 					return 0;
1755 			}
1756 	}
1757 	return 1;
1758 }
1759 
fpp_cond(int condition)1760 int fpp_cond (int condition)
1761 {
1762 	int NotANumber, N, Z;
1763 
1764 #ifdef JIT
1765 	if (currprefs.cachesize && currprefs.compfpu) {
1766 		// JIT reads and writes regs.fpu_result
1767 		fpp_is_init(&regs.fp_result);
1768 		NotANumber = fpp_is_nan(&regs.fp_result);
1769 		N = fpp_is_neg(&regs.fp_result);
1770 		Z = fpp_is_zero(&regs.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 	}
1778 
1779 	if ((condition & 0x10) && NotANumber) {
1780 		if (fpsr_set_bsun())
1781 			return -2;
1782 	}
1783 
1784 	switch (condition)
1785 	{
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 
maybe_idle_state(void)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 
fpuop_dbcc(uae_u32 opcode,uae_u16 extra)1862 void fpuop_dbcc (uae_u32 opcode, uae_u16 extra)
1863 {
1864 	uaecptr pc = m68k_getpc ();
1865 	uae_s32 disp;
1866 	int cc;
1867 
1868 	if (fp_exception_pending(true))
1869 		return;
1870 	regs.fp_exception = false;
1871 
1872 #if FPU_LOG
1873 	write_log(_T("FDBcc %04x %04x %08x\n"), opcode, extra, M68K_GETPC);
1874 #endif
1875 
1876 	if (fault_if_no_6888x (opcode, extra, pc - 4))
1877 		return;
1878 
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 ();
1884 	cc = fpp_cond (extra & 0x3f);
1885 	if (cc < 0) {
1886 		if (cc == -2)
1887 			return; // BSUN
1888 		fpu_op_illg (opcode, 0, regs.fpiar);
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));
1894 		if ((m68k_dreg (regs, reg) & 0xffff) != 0xffff) {
1895 			m68k_setpc (pc + disp);
1896 			regs.fp_branch = true;
1897 		}
1898 	}
1899 }
1900 
fpuop_scc(uae_u32 opcode,uae_u16 extra)1901 void fpuop_scc (uae_u32 opcode, uae_u16 extra)
1902 {
1903 	uae_u32 ad = 0;
1904 	int cc;
1905 	uaecptr pc = m68k_getpc () - 4;
1906 
1907 	if (fp_exception_pending(true))
1908 		return;
1909 	regs.fp_exception = false;
1910 
1911 #if FPU_LOG
1912 	write_log(_T("FScc %04x %04x %08x\n"), opcode, extra, M68K_GETPC);
1913 #endif
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))
1926 		return;
1927 
1928 	regs.fpiar = pc;
1929 	maybe_idle_state ();
1930 	cc = fpp_cond (extra & 0x3f);
1931 	if (cc < 0) {
1932 		if (cc == -2)
1933 			return; // BSUN
1934 		fpu_op_illg (opcode, 0, regs.fpiar);
1935 	} else if ((opcode & 0x38) == 0) {
1936 		m68k_dreg (regs, opcode & 7) = (m68k_dreg (regs, opcode & 7) & ~0xff) | (cc ? 0xff : 0x00);
1937 	} else {
1938 		x_cp_put_byte (ad, cc ? 0xff : 0x00);
1939 	}
1940 }
1941 
fpuop_trapcc(uae_u32 opcode,uaecptr oldpc,uae_u16 extra)1942 void fpuop_trapcc (uae_u32 opcode, uaecptr oldpc, uae_u16 extra)
1943 {
1944 	int cc;
1945 
1946 	if (fp_exception_pending(true))
1947 		return;
1948 	regs.fp_exception = false;
1949 
1950 #if FPU_LOG
1951 	write_log(_T("FTRAPcc %04x %04x %08x\n"), opcode, extra, M68K_GETPC);
1952 #endif
1953 
1954 	if (fault_if_no_fpu_u (opcode, extra, 0, oldpc))
1955 		return;
1956 
1957 	regs.fpiar = oldpc;
1958 	maybe_idle_state ();
1959 	cc = fpp_cond (extra & 0x3f);
1960 	if (cc < 0) {
1961 		if (cc == -2)
1962 			return; // BSUN
1963 		fpu_op_illg (opcode, 0, regs.fpiar);
1964 	} else if (cc) {
1965 		Exception (7);
1966 	}
1967 }
1968 
fpuop_bcc(uae_u32 opcode,uaecptr oldpc,uae_u32 extra)1969 void fpuop_bcc (uae_u32 opcode, uaecptr oldpc, uae_u32 extra)
1970 {
1971 	int cc;
1972 
1973 	if (fp_exception_pending(true))
1974 		return;
1975 	regs.fp_exception = false;
1976 
1977 #if FPU_LOG
1978 	write_log(_T("FBcc %04x %04x %08x\n"), opcode, extra, M68K_GETPC);
1979 #endif
1980 
1981 	if (fault_if_no_fpu (opcode, extra, 0, oldpc - 2))
1982 		return;
1983 
1984 	regs.fpiar = oldpc - 2;
1985 	maybe_idle_state ();
1986 	cc = fpp_cond (opcode & 0x3f);
1987 	if (cc < 0) {
1988 		if (cc == -2)
1989 			return; // BSUN
1990 		fpu_op_illg (opcode, 0, regs.fpiar);
1991 	} else if (cc) {
1992 		if ((opcode & 0x40) == 0)
1993 			extra = (uae_s32) (uae_s16) extra;
1994 		m68k_setpc (oldpc + extra);
1995 		regs.fp_branch = true;
1996 	}
1997 }
1998 
fpuop_save(uae_u32 opcode)1999 void fpuop_save (uae_u32 opcode)
2000 {
2001 	uae_u32 ad, adp;
2002 	int incr = (opcode & 0x38) == 0x20 ? -1 : 1;
2003 	int fpu_version = get_fpu_version (currprefs.fpu_model);
2004 	uaecptr pc = m68k_getpc () - 2;
2005 	int i;
2006 
2007 
2008 #if FPU_LOG
2009 	if (!isinrom())
2010 		write_log(_T("FSAVE %04x %08x\n"), opcode, M68K_GETPC);
2011 #endif
2012 
2013 	regs.fp_exception = false;
2014 
2015 	if (fault_if_no_6888x (opcode, 0, pc))
2016 		return;
2017 
2018 	if (get_fp_ad (opcode, &ad) == 0) {
2019 		fpu_op_illg (opcode, 0, pc);
2020 		return;
2021 	}
2022 
2023 	if (fault_if_no_fpu (opcode, 0, ad, pc))
2024 		return;
2025 
2026 //	write_log(_T("FSAVE %08x %08x\n"), M68K_GETPC, ad);
2027 
2028 	if (currprefs.fpu_model == 68060) {
2029 
2030 		/* 12 byte 68060 NULL/IDLE/EXCP frame.  */
2031 		int frame_size = 12;
2032 		uae_u32 frame_id;
2033 
2034 		if (regs.fpu_exp_state > 1) {
2035 			frame_id = 0x0000e000 | fsave_data.v;
2036 
2037 #if 0
2038 			write_log(_T("68060 FSAVE EXCP %s\n"), fpp_print(&fsave_data.src));
2039 #endif
2040 
2041 		} else {
2042 			frame_id = regs.fpu_state == 0 ? 0x00000000 : 0x00006000;
2043 		}
2044 		if (incr < 0)
2045 			ad -= frame_size;
2046 		adp = ad;
2047 		x_cp_put_long (ad, (fsave_data.eo[0] & 0xffff0000) | frame_id);
2048 		ad += 4;
2049 		x_cp_put_long (ad, fsave_data.eo[1]);
2050 		ad += 4;
2051 		x_cp_put_long (ad, fsave_data.eo[2]);
2052 		ad += 4;
2053 
2054 	} else if (currprefs.fpu_model == 68040) {
2055 
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;
2059 			if (incr < 0)
2060 				ad -= 4;
2061 			adp = ad;
2062 			x_cp_put_long (ad, frame_id);
2063 			ad += 4;
2064 		} else {
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 
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 			 }
2080 #endif
2081 
2082 			if (incr < 0)
2083 				ad -= frame_size;
2084 			adp = ad;
2085 			x_cp_put_long (ad, frame_id);
2086 			ad += 4;
2087 			if (regs.fpu_exp_state == 2) {
2088 				/* BUSY frame */
2089 				x_cp_put_long(ad, 0);
2090 				ad += 4;
2091 				x_cp_put_long(ad, 0); // CU_SAVEPC (Software shouldn't care)
2092 				ad += 4;
2093 				x_cp_put_long(ad, 0);
2094 				ad += 4;
2095 				x_cp_put_long(ad, 0);
2096 				ad += 4;
2097 				x_cp_put_long(ad, 0);
2098 				ad += 4;
2099 				x_cp_put_long(ad, fsave_data.wbt[0]); // WBTS/WBTE
2100 				ad += 4;
2101 				x_cp_put_long(ad, fsave_data.wbt[1]); // WBTM
2102 				ad += 4;
2103 				x_cp_put_long(ad, fsave_data.wbt[2]); // WBTM
2104 				ad += 4;
2105 				x_cp_put_long(ad, 0);
2106 				ad += 4;
2107 				x_cp_put_long(ad, fsave_data.fpiarcu); // FPIARCU (same as FPU PC or something else?)
2108 				ad += 4;
2109 				x_cp_put_long(ad, 0);
2110 				ad += 4;
2111 				x_cp_put_long(ad, 0);
2112 				ad += 4;
2113 			}
2114 			if (fpu_version >= 0x41 || regs.fpu_exp_state == 2) {
2115 				x_cp_put_long(ad, fsave_data.cmdreg3b << 16); // CMDREG3B
2116 				ad += 4;
2117 				x_cp_put_long (ad, 0);
2118 				ad += 4;
2119 			}
2120 			x_cp_put_long (ad, (fsave_data.stag << 29) | (fsave_data.wbtm66 << 26) | (fsave_data.grs << 23)); // STAG
2121 			ad += 4;
2122 			x_cp_put_long (ad, fsave_data.cmdreg1b << 16); // CMDREG1B
2123 			ad += 4;
2124 			x_cp_put_long (ad, (fsave_data.dtag << 29) | (fsave_data.wbte15 << 20)); // DTAG
2125 			ad += 4;
2126 			x_cp_put_long (ad, (fsave_data.e1 << 26) | (fsave_data.e3 << 25) | (fsave_data.t << 20));
2127 			ad += 4;
2128 			x_cp_put_long(ad, fsave_data.fpt[0]); // FPTS/FPTE
2129 			ad += 4;
2130 			x_cp_put_long(ad, fsave_data.fpt[1]); // FPTM
2131 			ad += 4;
2132 			x_cp_put_long(ad, fsave_data.fpt[2]); // FPTM
2133 			ad += 4;
2134 			x_cp_put_long(ad, fsave_data.et[0]); // ETS/ETE
2135 			ad += 4;
2136 			x_cp_put_long(ad, fsave_data.et[1]); // ETM
2137 			ad += 4;
2138 			x_cp_put_long(ad, fsave_data.et[2]); // ETM
2139 			ad += 4;
2140 		}
2141 	} else { /* 68881/68882 */
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);
2145 
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 
2155 		if (currprefs.mmu_model) {
2156 			if (incr < 0)
2157 				ad -= frame_size;
2158 			adp = ad;
2159 			x_cp_put_long(ad, frame_id); // frame id
2160 			ad += 4;
2161 			if (regs.fpu_state != 0) { // idle frame
2162 				x_cp_put_long(ad, fsave_data.ccr); // command/condition register
2163 				ad += 4;
2164 				if (currprefs.fpu_model == 68882) {
2165 					// don't write unused fields to save MMU state space.
2166 					ad += 8 * 4;
2167 				}
2168 				x_cp_put_long(ad, fsave_data.eo[0]); // exceptional operand lo
2169 				ad += 4;
2170 				x_cp_put_long(ad, fsave_data.eo[1]); // exceptional operand mid
2171 				ad += 4;
2172 				x_cp_put_long(ad, fsave_data.eo[2]); // exceptional operand hi
2173 				ad += 4;
2174 				x_cp_put_long(ad, 0x00000000); // operand register
2175 				ad += 4;
2176 				x_cp_put_long(ad, biu_flags); // biu flags
2177 				ad += 4;
2178 			}
2179 		} else {
2180 			if (incr < 0)
2181 				ad -= frame_size;
2182 			adp = ad;
2183 			x_cp_put_long(ad, frame_id); // frame id
2184 			ad += 4;
2185 			if (regs.fpu_state != 0) { // idle frame
2186 				x_cp_put_long(ad, fsave_data.ccr); // command/condition register
2187 				ad += 4;
2188 				if(currprefs.fpu_model == 68882) {
2189 					for(i = 0; i < 32; i += 4) {
2190 						x_cp_put_long(ad, 0x00000000); // internal
2191 						ad += 4;
2192 					}
2193 				}
2194 				x_cp_put_long(ad, fsave_data.eo[0]); // exceptional operand hi
2195 				ad += 4;
2196 				x_cp_put_long(ad, fsave_data.eo[1]); // exceptional operand mid
2197 				ad += 4;
2198 				x_cp_put_long(ad, fsave_data.eo[2]); // exceptional operand lo
2199 				ad += 4;
2200 				x_cp_put_long(ad, 0x00000000); // operand register
2201 				ad += 4;
2202 				x_cp_put_long(ad, biu_flags); // biu flags
2203 				ad += 4;
2204 			}
2205 		}
2206 	}
2207 
2208 	if ((opcode & 0x38) == 0x20) // predecrement
2209 		m68k_areg (regs, opcode & 7) = adp;
2210 	regs.fpu_exp_state = 0;
2211 }
2212 
2213 static bool fp_arithmetic(fpdata *src, fpdata *dst, int extra);
2214 
fpuop_restore(uae_u32 opcode)2215 void fpuop_restore (uae_u32 opcode)
2216 {
2217 	int fpu_version;
2218 	int frame_version;
2219 	int fpu_model = currprefs.fpu_model;
2220 	uaecptr pc = m68k_getpc () - 2;
2221 	uae_u32 ad, ad_orig;
2222 	uae_u32 d;
2223 
2224 	regs.fp_exception = false;
2225 
2226 #if FPU_LOG
2227 	if (!isinrom())
2228 		write_log (_T("FRESTORE %04x %08x\n"), opcode, M68K_GETPC);
2229 #endif
2230 
2231 	if (fault_if_no_6888x (opcode, 0, pc))
2232 		return;
2233 
2234 	if (get_fp_ad (opcode, &ad) == 0) {
2235 		fpu_op_illg (opcode, 0, pc);
2236 		return;
2237 	}
2238 
2239 	if (fault_if_no_fpu (opcode, 0, ad, pc))
2240 		return;
2241 	ad_orig = ad;
2242 	regs.fpiar = pc;
2243 
2244 	// write_log(_T("FRESTORE %08x %08x\n"), M68K_GETPC, ad);
2245 
2246 	// FRESTORE does not support predecrement
2247 
2248 	d = x_cp_get_long(ad);
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) {
2256 		int ff = (d >> 8) & 0xff;
2257 		uae_u32 v = d & 0x7;
2258 		fsave_data.eo[0] = d & 0xffff0000;
2259 
2260 		fsave_data.eo[1] = x_cp_get_long(ad);
2261 		ad += 4;
2262 		fsave_data.eo[2] = x_cp_get_long(ad);
2263 		ad += 4;
2264 
2265 		if (ff == 0x60) {
2266 			regs.fpu_state = 1;
2267 			regs.fpu_exp_state = 0;
2268 		} else if (ff == 0xe0) {
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 			}
2276 		} else if (ff) {
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
2294 				tmp = x_cp_get_long(ad);
2295 				cusavepc = tmp >> 24;
2296 				ad += 0x20; // offset to FPIARCU field
2297 				regs.fpiar = x_cp_get_long(ad);
2298 				ad += 0x14; // offset to ET15 field
2299 				tmp = x_cp_get_long(ad);
2300 				et15 = (tmp & 0x10000000) >> 28;
2301 				ad += 0x4; // offset to CMDREG1B field
2302 				fsave_data.cmdreg1b = x_cp_get_long(ad);
2303 				fsave_data.cmdreg1b >>= 16;
2304 				cmdreg1b = fsave_data.cmdreg1b;
2305 				ad += 0x4; // offset to FPTE15 field
2306 				tmp = x_cp_get_long(ad);
2307 				fpte15 = (tmp & 0x10000000) >> 28;
2308 				ad += 0x8; // offset to FPTE field
2309 				fsave_data.fpt[0] = x_cp_get_long(ad);
2310 				ad += 0x4;
2311 				fsave_data.fpt[1] = x_cp_get_long(ad);
2312 				ad += 0x4;
2313 				fsave_data.fpt[2] = x_cp_get_long(ad);
2314 				ad += 0x4; // offset to ET field
2315 				fsave_data.et[0] = x_cp_get_long(ad);
2316 				ad += 0x4;
2317 				fsave_data.et[1] = x_cp_get_long(ad);
2318 				ad += 0x4;
2319 				fsave_data.et[2] = x_cp_get_long(ad);
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();
2367 		} else {
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;
2376 		}
2377 
2378 	} else {
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;
2385 			regs.fpu_state = 1;
2386 
2387 			if (frame_size == 0x18 || frame_size == 0x38) { // idle
2388 
2389 				fsave_data.ccr = x_cp_get_long(ad);
2390 				ad += 4;
2391 				// 68882 internal registers (32 bytes, unused)
2392 				ad += frame_size - 24;
2393 				fsave_data.eo[0] = x_cp_get_long(ad);
2394 				ad += 4;
2395 				fsave_data.eo[1] = x_cp_get_long(ad);
2396 				ad += 4;
2397 				fsave_data.eo[2] = x_cp_get_long(ad);
2398 				ad += 4;
2399 				// operand register (unused)
2400 				ad += 4;
2401 				biu_flags = x_cp_get_long(ad);
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();
2421 		} else {
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;
2430 		}
2431 	}
2432 
2433 	if ((opcode & 0x38) == 0x18) /// postincrement
2434 		m68k_areg (regs, opcode & 7) = ad;
2435 
2436 	fp_exception_pending(false);
2437 }
2438 
fmovem2mem(uaecptr ad,uae_u32 list,int incr,int regdir)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;
2448 		for (int r = 0; r < 8; r++) {
2449 			if (regdir < 0)
2450 				reg = 7 - r;
2451 			else
2452 				reg = r;
2453 			if (list & 0x80) {
2454 				fpp_from_exten_fmovem(&regs.fp[reg], &wrd[0], &wrd[1], &wrd[2]);
2455 				if (incr < 0)
2456 					ad -= 3 * 4;
2457 				for (int i = 0; i < 3; i++) {
2458 					if (mmu030_state[0] == idx * 3 + i) {
2459 						if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM2) {
2460 							mmu030_state[1] &= ~MMU030_STATEFLAG1_MOVEM2;
2461 						} else {
2462 							mmu030_data_buffer_out = wrd[i];
2463 							x_put_long(ad + i * 4, wrd[i]);
2464 						}
2465 						mmu030_state[0]++;
2466 					}
2467 				}
2468 				if (incr > 0)
2469 					ad += 3 * 4;
2470 				idx++;
2471 			}
2472 			list <<= 1;
2473 		}
2474 	} else {
2475 		for (int r = 0; r < 8; r++) {
2476 			uae_u32 wrd1, wrd2, wrd3;
2477 			if (regdir < 0)
2478 				reg = 7 - r;
2479 			else
2480 				reg = r;
2481 			if (list & 0x80) {
2482 				fpp_from_exten_fmovem(&regs.fp[reg], &wrd1, &wrd2, &wrd3);
2483 				if (incr < 0)
2484 					ad -= 3 * 4;
2485 				x_cp_put_long(ad + 0, wrd1);
2486 				x_cp_put_long(ad + 4, wrd2);
2487 				x_cp_put_long(ad + 8, wrd3);
2488 				if (incr > 0)
2489 					ad += 3 * 4;
2490 			}
2491 			list <<= 1;
2492 		}
2493 	}
2494 	return ad;
2495 }
2496 
fmovem2fpp(uaecptr ad,uae_u32 list,int incr,int regdir)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;
2505 		for (int r = 0; r < 8; r++) {
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;
2513 				for (int i = 0; i < 3; i++) {
2514 					if (mmu030_state[0] == idx * 3 + i) {
2515 						if (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM2) {
2516 							mmu030_state[1] &= ~MMU030_STATEFLAG1_MOVEM2;
2517 							wrd[i] = mmu030_data_buffer_out;
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)
2526 							fpp_to_exten (&regs.fp[reg], mmu030_fmovem_store[0], mmu030_fmovem_store[1], wrd[2]);
2527 					}
2528 				}
2529 				if (incr > 0)
2530 					ad += 3 * 4;
2531 				idx++;
2532 			}
2533 			list <<= 1;
2534 		}
2535 	} else {
2536 		for (int r = 0; r < 8; r++) {
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;
2545 				wrd1 = x_cp_get_long (ad + 0);
2546 				wrd2 = x_cp_get_long (ad + 4);
2547 				wrd3 = x_cp_get_long (ad + 8);
2548 				if (incr > 0)
2549 					ad += 3 * 4;
2550 				fpp_to_exten (&regs.fp[reg], wrd1, wrd2, wrd3);
2551 			}
2552 			list <<= 1;
2553 		}
2554 	}
2555 	return ad;
2556 }
2557 
fp_arithmetic(fpdata * src,fpdata * dst,int extra)2558 static bool fp_arithmetic(fpdata *src, fpdata *dst, int extra)
2559 {
2560 	uae_u64 q = 0;
2561 	uae_u8 s = 0;
2562 
2563 	switch (extra & 0x7f)
2564 	{
2565 		case 0x00: /* FMOVE */
2566 			fpp_move(dst, src, PREC_NORMAL);
2567 			break;
2568 		case 0x40: /* FSMOVE */
2569 			fpp_move(dst, src, PREC_FLOAT);
2570 			break;
2571 		case 0x44: /* FDMOVE */
2572 			fpp_move(dst, src, PREC_DOUBLE);
2573 			break;
2574 		case 0x01: /* FINT */
2575 			fpp_int(dst, src);
2576 			break;
2577 		case 0x02: /* FSINH */
2578 			fpp_sinh(dst, src);
2579 			break;
2580 		case 0x03: /* FINTRZ */
2581 			fpp_intrz(dst, src);
2582 			break;
2583 		case 0x04: /* FSQRT */
2584 			fpp_sqrt(dst, src, PREC_NORMAL);
2585 			break;
2586 		case 0x41: /* FSSQRT */
2587 			fpp_sqrt(dst, src, PREC_FLOAT);
2588 			break;
2589 		case 0x45: /* FDSQRT */
2590 			fpp_sqrt(dst, src, PREC_DOUBLE);
2591 			break;
2592 		case 0x06: /* FLOGNP1 */
2593 			fpp_lognp1(dst, src);
2594 			break;
2595 		case 0x08: /* FETOXM1 */
2596 			fpp_etoxm1(dst, src);
2597 			break;
2598 		case 0x09: /* FTANH */
2599 			fpp_tanh(dst, src);
2600 			break;
2601 		case 0x0a: /* FATAN */
2602 			fpp_atan(dst, src);
2603 			break;
2604 		case 0x0c: /* FASIN */
2605 			fpp_asin(dst, src);
2606 			break;
2607 		case 0x0d: /* FATANH */
2608 			fpp_atanh(dst, src);
2609 			break;
2610 		case 0x0e: /* FSIN */
2611 			fpp_sin(dst, src);
2612 			break;
2613 		case 0x0f: /* FTAN */
2614 			fpp_tan(dst, src);
2615 			break;
2616 		case 0x10: /* FETOX */
2617 			fpp_etox(dst, src);
2618 			break;
2619 		case 0x11: /* FTWOTOX */
2620 			fpp_twotox(dst, src);
2621 			break;
2622 		case 0x12: /* FTENTOX */
2623 			fpp_tentox(dst, src);
2624 			break;
2625 		case 0x14: /* FLOGN */
2626 			fpp_logn(dst, src);
2627 			break;
2628 		case 0x15: /* FLOG10 */
2629 			fpp_log10(dst, src);
2630 			break;
2631 		case 0x16: /* FLOG2 */
2632 			fpp_log2(dst, src);
2633 			break;
2634 		case 0x18: /* FABS */
2635 			fpp_abs(dst, src, PREC_NORMAL);
2636 			break;
2637 		case 0x58: /* FSABS */
2638 			fpp_abs(dst, src, PREC_FLOAT);
2639 			break;
2640 		case 0x5c: /* FDABS */
2641 			fpp_abs(dst, src, PREC_DOUBLE);
2642 			break;
2643 		case 0x19: /* FCOSH */
2644 			fpp_cosh(dst, src);
2645 			break;
2646 		case 0x1a: /* FNEG */
2647 			fpp_neg(dst, src, PREC_NORMAL);
2648 			break;
2649 		case 0x5a: /* FSNEG */
2650 			fpp_neg(dst, src, PREC_FLOAT);
2651 			break;
2652 		case 0x5e: /* FDNEG */
2653 			fpp_neg(dst, src, PREC_DOUBLE);
2654 			break;
2655 		case 0x1c: /* FACOS */
2656 			fpp_acos(dst, src);
2657 			break;
2658 		case 0x1d: /* FCOS */
2659 			fpp_cos(dst, src);
2660 			break;
2661 		case 0x1e: /* FGETEXP */
2662 			fpp_getexp(dst, src);
2663 			break;
2664 		case 0x1f: /* FGETMAN */
2665 			fpp_getman(dst, src);
2666 			break;
2667 		case 0x20: /* FDIV */
2668 			fpp_div(dst, src, PREC_NORMAL);
2669 			break;
2670 		case 0x60: /* FSDIV */
2671 			fpp_div(dst, src, PREC_FLOAT);
2672 			break;
2673 		case 0x64: /* FDDIV */
2674 			fpp_div(dst, src, PREC_DOUBLE);
2675 			break;
2676 		case 0x21: /* FMOD */
2677 			fpsr_get_quotient(&q, &s);
2678 			fpp_mod(dst, src, &q, &s);
2679 			fpsr_set_quotient(q, s);
2680 			break;
2681 		case 0x22: /* FADD */
2682 			fpp_add(dst, src, PREC_NORMAL);
2683 			break;
2684 		case 0x62: /* FSADD */
2685 			fpp_add(dst, src, PREC_FLOAT);
2686 			break;
2687 		case 0x66: /* FDADD */
2688 			fpp_add(dst, src, PREC_DOUBLE);
2689 			break;
2690 		case 0x23: /* FMUL */
2691 			fpp_mul(dst, src, PREC_NORMAL);
2692 			break;
2693 		case 0x63: /* FSMUL */
2694 			fpp_mul(dst, src, PREC_FLOAT);
2695 			break;
2696 		case 0x67: /* FDMUL */
2697 			fpp_mul(dst, src, PREC_DOUBLE);
2698 			break;
2699 		case 0x24: /* FSGLDIV */
2700 			fpp_sgldiv(dst, src);
2701 			break;
2702 		case 0x25: /* FREM */
2703 			fpsr_get_quotient(&q, &s);
2704 			fpp_rem(dst, src, &q, &s);
2705 			fpsr_set_quotient(q, s);
2706 			break;
2707 		case 0x26: /* FSCALE */
2708 			fpp_scale(dst, src);
2709 			break;
2710 		case 0x27: /* FSGLMUL */
2711 			fpp_sglmul(dst, src);
2712 			break;
2713 		case 0x28: /* FSUB */
2714 			fpp_sub(dst, src, PREC_NORMAL);
2715 			break;
2716 		case 0x68: /* FSSUB */
2717 			fpp_sub(dst, src, PREC_FLOAT);
2718 			break;
2719 		case 0x6c: /* FDSUB */
2720 			fpp_sub(dst, src, PREC_DOUBLE);
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 */
2730 			fpp_cos(dst, src);
2731 			regs.fp[extra & 7] = *dst;
2732 			fpp_sin(dst, src);
2733 			break;
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;
2751 	}
2752 
2753 	fpsr_set_result(dst);
2754 
2755 	if (fpsr_make_status())
2756 		return false;
2757 
2758 	return true;
2759 }
2760 
fpuop_arithmetic2(uae_u32 opcode,uae_u16 extra)2761 static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra)
2762 {
2763 	int reg = -1;
2764 	int v;
2765 	fpdata src, dst;
2766 	uaecptr pc = m68k_getpc () - 4;
2767 	uaecptr ad = 0;
2768 
2769 #if DEBUG_FPP
2770 	if (!isinrom ())
2771 		write_log (_T("FPP %04x %04x at %08x\n"), opcode & 0xffff, extra, pc);
2772 #endif
2773 	if (fault_if_no_6888x (opcode, extra, pc))
2774 		return;
2775 
2776 	switch ((extra >> 13) & 0x7)
2777 	{
2778 		case 3:
2779 			// FMOVE FPP->EA
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
2795 			return;
2796 
2797 		case 4:
2798 		case 5:
2799 			// FMOVE Control Register <> Data or Address register
2800 			if ((opcode & 0x38) == 0) {
2801 				// Dn
2802 				if (fault_if_no_fpu (opcode, extra, 0, pc))
2803 					return;
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 				}
2814 				if (extra & 0x2000) {
2815 					if (extra & 0x1000)
2816 						m68k_dreg (regs, opcode & 7) = fpp_get_fpcr();
2817 					if (extra & 0x0800)
2818 						m68k_dreg (regs, opcode & 7) = fpp_get_fpsr();
2819 					if ((extra & 0x0400) || !bits)
2820 						m68k_dreg (regs, opcode & 7) = regs.fpiar;
2821 				} else {
2822 					if (extra & 0x1000)
2823 						fpp_set_fpcr(m68k_dreg (regs, opcode & 7));
2824 					if (extra & 0x0800)
2825 						fpp_set_fpsr(m68k_dreg (regs, opcode & 7));
2826 					if ((extra & 0x0400) || !bits)
2827 						regs.fpiar = m68k_dreg (regs, opcode & 7);
2828 				}
2829 			} else if ((opcode & 0x38) == 0x08) {
2830 				// An
2831 				if (fault_if_no_fpu (opcode, extra, 0, pc))
2832 					return;
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 				}
2841 				if (extra & 0x2000) {
2842 					m68k_areg (regs, opcode & 7) = regs.fpiar;
2843 				} else {
2844 					regs.fpiar = m68k_areg (regs, opcode & 7);
2845 				}
2846 			} else if ((opcode & 0x3f) == 0x3c) {
2847 				if ((extra & 0x2000) == 0) {
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) {
2852 						if (fault_if_60())
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 ();
2863 					if (fault_if_no_fpu (opcode, extra, 0, pc))
2864 						return;
2865 					if (extra & 0x1000)
2866 						fpp_set_fpcr(ext[0]);
2867 					if (extra & 0x0800)
2868 						fpp_set_fpsr(ext[1]);
2869 					if (extra & 0x0400)
2870 						regs.fpiar = ext[2];
2871 				} else {
2872 					// immediate as destination
2873 					fpu_noinst (opcode, pc);
2874 					return;
2875 				}
2876 			} else if (extra & 0x2000) {
2877 				/* FMOVEM Control Register->Memory */
2878 				uae_u32 ad;
2879 				int incr = 0;
2880 
2881 				if (get_fp_ad (opcode, &ad) == 0) {
2882 					fpu_noinst (opcode, pc);
2883 					return;
2884 				}
2885 				if (fault_if_no_fpu (opcode, extra, ad, pc))
2886 					return;
2887 				if ((opcode & 0x3f) >= 0x3a) {
2888 					// PC relative modes not supported
2889 					fpu_noinst(opcode, pc);
2890 					return;
2891 				}
2892 
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) {
2903 					x_cp_put_long(ad, fpp_get_fpcr());
2904 					ad += 4;
2905 				}
2906 				if (extra & 0x0800) {
2907 					x_cp_put_long(ad, fpp_get_fpsr());
2908 					ad += 4;
2909 				}
2910 				if (extra & 0x0400) {
2911 					x_cp_put_long(ad, regs.fpiar);
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 {
2920 				/* FMOVEM Memory->Control Register */
2921 				uae_u32 ad;
2922 				int incr = 0;
2923 
2924 				if (get_fp_ad (opcode, &ad) == 0) {
2925 					fpu_noinst (opcode, pc);
2926 					return;
2927 				}
2928 				if (fault_if_no_fpu (opcode, extra, ad, pc))
2929 					return;
2930 
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) {
2941 					fpp_set_fpcr(x_cp_get_long (ad));
2942 					ad += 4;
2943 				}
2944 				if (extra & 0x0800) {
2945 					fpp_set_fpsr(x_cp_get_long (ad));
2946 					ad += 4;
2947 				}
2948 				if (extra & 0x0400) {
2949 					regs.fpiar = x_cp_get_long (ad);
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 			{
2962 				// FMOVEM FPP<>Memory
2963 				uae_u32 ad, list = 0;
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;
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 
2984 				switch ((extra >> 11) & 3)
2985 				{
2986 					case 0:	/* static pred */
2987 					case 2:	/* static postinc */
2988 						list = extra & 0xff;
2989 						break;
2990 					case 1:	/* dynamic pred */
2991 					case 3:	/* dynamic postinc */
2992 						if (fault_if_60())
2993 							return;
2994 						list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff;
2995 						break;
2996 				}
2997 				if ((opcode & 0x38) == 0x20) { // -(an)
2998 					incr = -1;
2999 					switch ((extra >> 11) & 3)
3000 					{
3001 						case 0:	/* static pred */
3002 						case 1:	/* dynamic pred */
3003 						regdir = -1;
3004 						break;
3005 					}
3006 				}
3007 				if (extra & 0x2000) {
3008 					/* FMOVEM FPP->Memory */
3009 					ad = fmovem2mem (ad, list, incr, regdir);
3010 				} else {
3011 					/* FMOVEM Memory->FPP */
3012 					ad = fmovem2fpp (ad, list, incr, regdir);
3013 				}
3014 				if ((opcode & 0x38) == 0x18 || (opcode & 0x38) == 0x20) // (an)+ or -(an)
3015 					m68k_areg (regs, opcode & 7) = ad;
3016 			}
3017 			return;
3018 
3019 		case 0:
3020 		case 2: /* Extremely common */
3021 			if (fp_exception_pending(true))
3022 				return;
3023 
3024 			regs.fpiar = pc;
3025 			reg = (extra >> 7) & 7;
3026 			if ((extra & 0xfc00) == 0x5c00) {
3027 				// FMOVECR
3028 				if (fault_if_unimplemented_680x0 (opcode, extra, ad, pc, &src, reg))
3029 					return;
3030 				if (extra & 0x40) {
3031 					// 6888x and ROM constant 0x40 - 0x7f: f-line
3032 					fpu_noinst (opcode, pc);
3033 					return;
3034 				}
3035 				fpsr_clear_status();
3036 				fpu_get_constant(&regs.fp[reg], extra & 0x7f);
3037 				fpsr_make_status();
3038 				fpsr_check_arithmetic_exception(0, &src, opcode, extra, ad);
3039 				return;
3040 			}
3041 
3042 			// 6888x does not have special exceptions, check immediately
3043 			if (fault_if_unimplemented_6888x (opcode, extra, pc))
3044 				return;
3045 
3046 			fpsr_clear_status();
3047 
3048 			v = get_fp_value (opcode, extra, &src, pc, &ad);
3049 			if (v <= 0) {
3050 				if (v == 0)
3051 					fpu_noinst (opcode, pc);
3052 				return;
3053 			}
3054 
3055 			if (fault_if_no_fpu (opcode, extra, ad, pc))
3056 				return;
3057 
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;
3079 
3080 			return;
3081 		default:
3082 		break;
3083 	}
3084 	fpu_noinst (opcode, pc);
3085 }
3086 
fpuop_arithmetic(uae_u32 opcode,uae_u16 extra)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;
3092 #if FPU_LOG
3093 	write_log(_T("FPUOP %04x %04x PC=%08x\n"), opcode, extra, M68K_GETPC);
3094 #endif
3095 	fpuop_arithmetic2 (opcode, extra);
3096 	if (fpu_mmu_fixup) {
3097 		mmufixup[0].reg = -1;
3098 	}
3099 }
3100 
get_features(void)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 
fpu_clearstatus(void)3107 void fpu_clearstatus(void)
3108 {
3109 	fpp_clear_status();
3110 }
3111 
fpu_modechange(void)3112 void fpu_modechange(void)
3113 {
3114 	uae_u32 temp_ext[8][3];
3115 //fprintf ( stderr , "fpu_modechange old %d new %d\n" , currprefs.fpu_mode , changed_prefs.fpu_mode );
3116 
3117 	if (currprefs.fpu_mode == changed_prefs.fpu_mode)
3118 		return;
3119 	currprefs.fpu_mode = changed_prefs.fpu_mode;
3120 
3121 	set_cpu_caches(true);
3122 	for (int i = 0; i < 8; i++) {
3123 		fpp_from_exten_fmovem(&regs.fp[i], &temp_ext[i][0], &temp_ext[i][1], &temp_ext[i][2]);
3124 	}
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
3133 	} else {
3134 #ifdef MSVC_LONG_DOUBLE
3135 		use_long_double = false;
3136 #endif
3137 		fp_init_native();
3138 	}
3139 	get_features();
3140 	for (int i = 0; i < 8; i++) {
3141 		fpp_to_exten_fmovem(&regs.fp[i], temp_ext[i][0], temp_ext[i][1], temp_ext[i][2]);
3142 	}
3143 }
3144 
3145 #if FPU_TEST
3146 
fpu_test(void)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);
3157 }
3158 
3159 #endif
3160 
fpu_reset(void)3161 void fpu_reset (void)
3162 {
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
3173 	} else {
3174 #ifdef MSVC_LONG_DOUBLE
3175 		use_long_double = false;
3176 #endif
3177 		fp_init_native();
3178 	}
3179 
3180 #ifndef WINUAE_FOR_HATARI
3181 #if defined(CPU_i386) || defined(CPU_x86_64)
3182 	init_fpucw_x87();
3183 #ifdef MSVC_LONG_DOUBLE
3184 	init_fpucw_x87_80();
3185 #endif
3186 #endif
3187 #endif /* ! WINUAE_FOR_HATARI */
3188 
3189 	regs.fpiar = 0;
3190 	regs.fpu_exp_state = 0;
3191 	get_features();
3192 	fpp_set_fpcr (0);
3193 	fpp_set_fpsr (0);
3194 	fpux_restore (NULL);
3195 	// reset precision
3196 	fpp_set_mode(0x00000080 | 0x00000010);
3197 	fpp_set_mode(0x00000000);
3198 
3199 #if FPU_TEST
3200 	fpu_test();
3201 #endif
3202 
3203 }
3204 
restore_fpu(uae_u8 * src)3205 uae_u8 *restore_fpu (uae_u8 *src)
3206 {
3207 	uae_u32 w1, w2, w3;
3208 	int i;
3209 	uae_u32 flags;
3210 
3211 	fpu_reset();
3212 	changed_prefs.fpu_model = currprefs.fpu_model = restore_u32 ();
3213 	flags = restore_u32 ();
3214 	for (i = 0; i < 8; i++) {
3215 		w1 = restore_u16 () << 16;
3216 		w2 = restore_u32 ();
3217 		w3 = restore_u32 ();
3218 		fpp_to_exten_fmovem(&regs.fp[i], w1, w2, w3);
3219 	}
3220 	regs.fpcr = restore_u32 ();
3221 	regs.fpsr = restore_u32 ();
3222 	regs.fpiar = restore_u32 ();
3223 	fpsr_make_status();
3224 	if (flags & 0x80000000) {
3225 		restore_u32 ();
3226 		restore_u32 ();
3227 	}
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 	}
3268 	write_log(_T("FPU: %d\n"), currprefs.fpu_model);
3269 	return src;
3270 }
3271 
save_fpu(int * len,uae_u8 * dstptr)3272 uae_u8 *save_fpu (int *len, uae_u8 *dstptr)
3273 {
3274 	uae_u32 w1, w2, w3, v;
3275 	uae_u8 *dstbak, *dst;
3276 	int i;
3277 
3278 	*len = 0;
3279 #ifndef WINUAE_FOR_HATARI
3280 	/* Under Hatari, we save all FPU variables, even if fpu_model==0 */
3281 	if (currprefs.fpu_model == 0)
3282 		return 0;
3283 #endif
3284 	if (dstptr)
3285 		dstbak = dst = dstptr;
3286 	else
3287 		dstbak = dst = xmalloc (uae_u8, 4+4+8*10+4+4+4+4+4+2*10+3*(4+2));
3288 	save_u32 (currprefs.fpu_model);
3289 	save_u32 (0x80000000 | 0x20000000);
3290 	for (i = 0; i < 8; i++) {
3291 		fpp_from_exten_fmovem(&regs.fp[i], &w1, &w2, &w3);
3292 		save_u16 (w1 >> 16);
3293 		save_u32 (w2);
3294 		save_u32 (w3);
3295 	}
3296 	save_u32 (regs.fpcr);
3297 	save_u32 (regs.fpsr);
3298 	save_u32 (regs.fpiar);
3299 
3300 	save_u32 (-1);
3301 	save_u32 (1);
3302 
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 	}
3342 
3343 	*len = dst - dstbak;
3344 	return dstbak;
3345 }
3346