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(®s.fp[reg], &fsave_data.fpt[0], &fsave_data.fpt[1], &fsave_data.fpt[2]);
551 fsave_data.dtag = get_ftag(®s.fp[reg], -1);
552 }
553 } else { // FMOVE to register, FABS, FNEG
554 fpp_get_internal_round_exten(&eo);
555 fsave_data.grs = fpp_get_internal_grs();
556 fpp_from_exten_fmovem(&eo, &fsave_data.fpt[0], &fsave_data.fpt[1], &fsave_data.fpt[2]);
557 fpp_get_internal_round_all(&eo); // weird
558 fpp_from_exten_fmovem(&eo, &fsave_data.et[0], &fsave_data.et[1], &fsave_data.et[2]); // undocumented
559 fsave_data.stag = get_ftag(src, (opclass == 0) ? -1 : size);
560 }
561 } else { // SNAN, OPERR, DZ
562 fpp_from_exten_fmovem(src, &fsave_data.et[0], &fsave_data.et[1], &fsave_data.et[2]);
563 fsave_data.stag = get_ftag(src, (opclass == 0) ? -1 : size);
564 if (fp_is_dyadic(extra)) {
565 fpp_from_exten_fmovem(®s.fp[reg], &fsave_data.fpt[0], &fsave_data.fpt[1], &fsave_data.fpt[2]);
566 fsave_data.dtag = get_ftag(®s.fp[reg], -1);
567 }
568 }
569 }
570 }
571 }
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(®s.fpsr);
607
608 // update accrued exception byte
609 if (regs.fpsr & (FPSR_BSUN | FPSR_SNAN | FPSR_OPERR))
610 regs.fpsr |= FPSR_AE_IOP; // IOP = BSUN || SNAN || OPERR
611 if (regs.fpsr & FPSR_OVFL)
612 regs.fpsr |= FPSR_AE_OVFL; // OVFL = OVFL
613 if ((regs.fpsr & FPSR_UNFL) && (regs.fpsr & FPSR_INEX2))
614 regs.fpsr |= FPSR_AE_UNFL; // UNFL = UNFL && INEX2
615 if (regs.fpsr & FPSR_DZ)
616 regs.fpsr |= FPSR_AE_DZ; // DZ = DZ
617 if (regs.fpsr & (FPSR_OVFL | FPSR_INEX2 | FPSR_INEX1))
618 regs.fpsr |= FPSR_AE_INEX; // INEX = INEX1 || INEX2 || OVFL
619
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(®s.fp_result);
666 if (fpp_is_nan(®s.fp_result)) {
667 regs.fpsr |= FPSR_CC_NAN;
668 } else if (fpp_is_zero(®s.fp_result)) {
669 regs.fpsr |= FPSR_CC_Z;
670 } else if (fpp_is_infinity(®s.fp_result)) {
671 regs.fpsr |= FPSR_CC_I;
672 }
673 if (fpp_is_neg(®s.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(®s.fp_result);
714 else if (val & 0x04000000)
715 fpset(®s.fp_result, 0);
716 else if (val & 0x08000000)
717 fpset(®s.fp_result, -1);
718 else
719 fpset(®s.fp_result, 1);
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(®s.fp[reg], &fsave_data.fpt[0], &fsave_data.fpt[1], &fsave_data.fpt[2]);
931 fsave_data.dtag = get_ftag(®s.fp[reg], -1);
932 }
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(®s.fp[reg], &fsave_data.fpt[0], &fsave_data.fpt[1], &fsave_data.fpt[2]);
1004 fsave_data.dtag = get_ftag(®s.fp[reg], -1);
1005 }
1006 }
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 (®s.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(®s.fp_result);
1768 NotANumber = fpp_is_nan(®s.fp_result);
1769 N = fpp_is_neg(®s.fp_result);
1770 Z = fpp_is_zero(®s.fp_result);
1771 } else
1772 #endif
1773 {
1774 NotANumber = (regs.fpsr & FPSR_CC_NAN) != 0;
1775 N = (regs.fpsr & FPSR_CC_N) != 0;
1776 Z = (regs.fpsr & FPSR_CC_Z) != 0;
1777 }
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(®s.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(®s.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 (®s.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 (®s.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(®s.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(®s.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(®s.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(®s.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(®s.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