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