|
|
1.1 root 1: /*
2: * UAE - The Un*x Amiga Emulator
3: *
4: * MC68881 emulation
5: *
6: * Copyright 1996 Herman ten Brugge
1.1.1.2 root 7: *
8: * Adaptation to Hatari by Thomas Huth
9: *
10: * This file is distributed under the GNU Public License, version 2 or at
11: * your option any later version. Read the file gpl.txt for details.
1.1 root 12: */
1.1.1.3 ! root 13: char FPP_rcsid[] = "Hatari $Id: fpp.c,v 1.3 2004/04/19 08:53:49 thothy Exp $";
1.1 root 14:
1.1.1.2 root 15:
16: #define __USE_ISOC9X /* We might be able to pick up a NaN */
1.1 root 17: #include <math.h>
18:
19: #include "sysdeps.h"
20: #include "hatari-glue.h"
21: #include "memory.h"
22: #include "newcpu.h"
23: #include "fpp-unknown.h"
24:
25:
26: #if 1
27:
28: #define DEBUG_FPP 0
29:
1.1.1.2 root 30: #define FFLAG_Z 0x4000
31: #define FFLAG_N 0x0100
32: #define FFLAG_NAN 0x0400
33:
34: #define MAKE_FPSR(r) regs.fp_result=(r)
35:
36: static __inline__ void native_set_fpucw (uae_u32 m68k_cw)
37: {
38: }
39:
40: #if defined(uae_s64) /* Close enough for government work? */
41: static __inline__ uae_s64 toint(fptype src)
42: #else
43: static __inline__ uae_s32 toint(fptype src)
44: #endif
45: {
46: switch ((regs.fpcr >> 4) & 0x3) {
47: case 0:
48: return (int) (src + 0.5);
49: case 1:
50: return (int) src;
51: case 2:
52: return floor (src);
53: case 3:
54: return ceil (src);
55: }
56: return src; /* Should never be reached */
57: }
58:
59: static uae_u32 get_fpsr (void)
60: {
61: uae_u32 answer = regs.fpsr & 0x00ffffff;
62: #ifdef HAVE_ISNAN
63: if (isnan (regs.fp_result))
64: answer |= 0x01000000;
65: else
66: #endif
67: {
68: if (regs.fp_result == 0)
69: answer |= 0x04000000;
70: else if (regs.fp_result < 0)
71: answer |= 0x08000000;
72: #ifdef HAVE_ISINF
73: if (isinf (regs.fp_result))
74: answer |= 0x02000000;
75: #endif
76: }
77: return answer;
78: }
79:
80: STATIC_INLINE void set_fpsr (uae_u32 x)
81: {
82: regs.fpsr = x;
83:
84: if (x & 0x01000000) {
85: #ifdef NAN
86: regs.fp_result = NAN;
87: #else
88: regs.fp_result = pow (1e100, 10) - pow(1e100, 10); /* Any better way? */
89: #endif
90: }
91: else if (x & 0x04000000)
92: regs.fp_result = 0;
93: else if (x & 0x08000000)
94: regs.fp_result = -1;
95: else
96: regs.fp_result = 1;
97: }
98:
1.1 root 99:
100: /* single : S 8*E 23*F */
101: /* double : S 11*E 52*F */
102: /* extended : S 15*E 64*F */
103: /* E = 0 & F = 0 -> 0 */
104: /* E = MAX & F = 0 -> Infin */
105: /* E = MAX & F # 0 -> NotANumber */
106: /* E = biased by 127 (single) ,1023 (double) ,16383 (extended) */
107:
1.1.1.2 root 108: STATIC_INLINE fptype to_pack (uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3)
1.1 root 109: {
1.1.1.2 root 110: fptype d;
1.1 root 111: char *cp;
112: char str[100];
113:
114: cp = str;
115: if (wrd1 & 0x80000000)
116: *cp++ = '-';
117: *cp++ = (wrd1 & 0xf) + '0';
118: *cp++ = '.';
119: *cp++ = ((wrd2 >> 28) & 0xf) + '0';
120: *cp++ = ((wrd2 >> 24) & 0xf) + '0';
121: *cp++ = ((wrd2 >> 20) & 0xf) + '0';
122: *cp++ = ((wrd2 >> 16) & 0xf) + '0';
123: *cp++ = ((wrd2 >> 12) & 0xf) + '0';
124: *cp++ = ((wrd2 >> 8) & 0xf) + '0';
125: *cp++ = ((wrd2 >> 4) & 0xf) + '0';
126: *cp++ = ((wrd2 >> 0) & 0xf) + '0';
127: *cp++ = ((wrd3 >> 28) & 0xf) + '0';
128: *cp++ = ((wrd3 >> 24) & 0xf) + '0';
129: *cp++ = ((wrd3 >> 20) & 0xf) + '0';
130: *cp++ = ((wrd3 >> 16) & 0xf) + '0';
131: *cp++ = ((wrd3 >> 12) & 0xf) + '0';
132: *cp++ = ((wrd3 >> 8) & 0xf) + '0';
133: *cp++ = ((wrd3 >> 4) & 0xf) + '0';
134: *cp++ = ((wrd3 >> 0) & 0xf) + '0';
135: *cp++ = 'E';
136: if (wrd1 & 0x40000000)
137: *cp++ = '-';
138: *cp++ = ((wrd1 >> 24) & 0xf) + '0';
139: *cp++ = ((wrd1 >> 20) & 0xf) + '0';
140: *cp++ = ((wrd1 >> 16) & 0xf) + '0';
141: *cp = 0;
142: sscanf (str, "%le", &d);
143: return d;
144: }
145:
1.1.1.2 root 146: STATIC_INLINE void from_pack (fptype src, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3)
1.1 root 147: {
148: int i;
149: int t;
150: char *cp;
151: char str[100];
152:
153: sprintf (str, "%.16e", src);
154: cp = str;
155: *wrd1 = *wrd2 = *wrd3 = 0;
156: if (*cp == '-') {
157: cp++;
158: *wrd1 = 0x80000000;
159: }
160: if (*cp == '+')
161: cp++;
162: *wrd1 |= (*cp++ - '0');
163: if (*cp == '.')
164: cp++;
165: for (i = 0; i < 8; i++) {
166: *wrd2 <<= 4;
167: if (*cp >= '0' && *cp <= '9')
168: *wrd2 |= *cp++ - '0';
169: }
170: for (i = 0; i < 8; i++) {
171: *wrd3 <<= 4;
172: if (*cp >= '0' && *cp <= '9')
173: *wrd3 |= *cp++ - '0';
174: }
175: if (*cp == 'e' || *cp == 'E') {
176: cp++;
177: if (*cp == '-') {
178: cp++;
179: *wrd1 |= 0x40000000;
180: }
181: if (*cp == '+')
182: cp++;
183: t = 0;
184: for (i = 0; i < 3; i++) {
185: if (*cp >= '0' && *cp <= '9')
186: t = (t << 4) | (*cp++ - '0');
187: }
188: *wrd1 |= t << 16;
189: }
190: }
191:
1.1.1.2 root 192: STATIC_INLINE int get_fp_value (uae_u32 opcode, uae_u16 extra, fptype *src)
1.1 root 193: {
194: uaecptr tmppc;
195: uae_u16 tmp;
196: int size;
197: int mode;
198: int reg;
199: uae_u32 ad = 0;
200: static int sz1[8] = { 4, 4, 12, 12, 2, 8, 1, 0 };
201: static int sz2[8] = { 4, 4, 12, 12, 2, 8, 2, 0 };
202:
203: if ((extra & 0x4000) == 0) {
204: *src = regs.fp[(extra >> 10) & 7];
205: return 1;
206: }
207: mode = (opcode >> 3) & 7;
208: reg = opcode & 7;
209: size = (extra >> 10) & 7;
210: switch (mode) {
211: case 0:
212: switch (size) {
213: case 6:
1.1.1.2 root 214: *src = (fptype) (uae_s8) m68k_dreg (regs, reg);
1.1 root 215: break;
216: case 4:
1.1.1.2 root 217: *src = (fptype) (uae_s16) m68k_dreg (regs, reg);
1.1 root 218: break;
219: case 0:
1.1.1.2 root 220: *src = (fptype) (uae_s32) m68k_dreg (regs, reg);
1.1 root 221: break;
222: case 1:
223: *src = to_single (m68k_dreg (regs, reg));
224: break;
225: default:
226: return 0;
227: }
228: return 1;
229: case 1:
230: return 0;
231: case 2:
232: ad = m68k_areg (regs, reg);
233: break;
234: case 3:
235: ad = m68k_areg (regs, reg);
236: m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size];
237: break;
238: case 4:
239: m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size];
240: ad = m68k_areg (regs, reg);
241: break;
242: case 5:
243: ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) next_iword ();
244: break;
245: case 6:
246: ad = get_disp_ea_020 (m68k_areg (regs, reg), next_iword ());
247: break;
248: case 7:
249: switch (reg) {
250: case 0:
251: ad = (uae_s32) (uae_s16) next_iword ();
252: break;
253: case 1:
254: ad = next_ilong ();
255: break;
256: case 2:
257: ad = m68k_getpc ();
258: ad += (uae_s32) (uae_s16) next_iword ();
259: break;
260: case 3:
261: tmppc = m68k_getpc ();
262: tmp = next_iword ();
263: ad = get_disp_ea_020 (tmppc, tmp);
264: break;
265: case 4:
266: ad = m68k_getpc ();
267: m68k_setpc (ad + sz2[size]);
268: break;
269: default:
270: return 0;
271: }
272: }
273: switch (size) {
274: case 0:
1.1.1.2 root 275: *src = (fptype) (uae_s32) get_long (ad);
1.1 root 276: break;
277: case 1:
278: *src = to_single (get_long (ad));
279: break;
280: case 2:{
281: uae_u32 wrd1, wrd2, wrd3;
282: wrd1 = get_long (ad);
283: ad += 4;
284: wrd2 = get_long (ad);
285: ad += 4;
286: wrd3 = get_long (ad);
287: *src = to_exten (wrd1, wrd2, wrd3);
288: }
289: break;
290: case 3:{
291: uae_u32 wrd1, wrd2, wrd3;
292: wrd1 = get_long (ad);
293: ad += 4;
294: wrd2 = get_long (ad);
295: ad += 4;
296: wrd3 = get_long (ad);
297: *src = to_pack (wrd1, wrd2, wrd3);
298: }
299: break;
300: case 4:
1.1.1.2 root 301: *src = (fptype) (uae_s16) get_word (ad);
1.1 root 302: break;
303: case 5:{
304: uae_u32 wrd1, wrd2;
305: wrd1 = get_long (ad);
306: ad += 4;
307: wrd2 = get_long (ad);
308: *src = to_double (wrd1, wrd2);
309: }
310: break;
311: case 6:
1.1.1.2 root 312: *src = (fptype) (uae_s8) get_byte (ad);
1.1 root 313: break;
314: default:
315: return 0;
316: }
317: return 1;
318: }
319:
1.1.1.2 root 320: STATIC_INLINE int put_fp_value (fptype value, uae_u32 opcode, uae_u16 extra)
1.1 root 321: {
322: uae_u16 tmp;
323: uaecptr tmppc;
324: int size;
325: int mode;
326: int reg;
327: uae_u32 ad;
328: static int sz1[8] = { 4, 4, 12, 12, 2, 8, 1, 0 };
329: static int sz2[8] = { 4, 4, 12, 12, 2, 8, 2, 0 };
330:
331: if ((extra & 0x4000) == 0) {
332: regs.fp[(extra >> 10) & 7] = value;
333: return 1;
334: }
335: mode = (opcode >> 3) & 7;
336: reg = opcode & 7;
337: size = (extra >> 10) & 7;
338: ad = -1;
1.1.1.2 root 339:
1.1 root 340: switch (mode) {
341: case 0:
342: switch (size) {
343: case 6:
1.1.1.2 root 344: m68k_dreg (regs, reg) = ((toint(value) & 0xff)
1.1 root 345: | (m68k_dreg (regs, reg) & ~0xff));
346: break;
347: case 4:
1.1.1.2 root 348: m68k_dreg (regs, reg) = ((toint(value) & 0xffff)
1.1 root 349: | (m68k_dreg (regs, reg) & ~0xffff));
350: break;
351: case 0:
1.1.1.2 root 352: m68k_dreg (regs, reg) = toint(value);
1.1 root 353: break;
354: case 1:
355: m68k_dreg (regs, reg) = from_single (value);
356: break;
357: default:
358: return 0;
359: }
360: return 1;
361: case 1:
362: return 0;
363: case 2:
364: ad = m68k_areg (regs, reg);
365: break;
366: case 3:
367: ad = m68k_areg (regs, reg);
368: m68k_areg (regs, reg) += reg == 7 ? sz2[size] : sz1[size];
369: break;
370: case 4:
371: m68k_areg (regs, reg) -= reg == 7 ? sz2[size] : sz1[size];
372: ad = m68k_areg (regs, reg);
373: break;
374: case 5:
375: ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) next_iword ();
376: break;
377: case 6:
378: ad = get_disp_ea_020 (m68k_areg (regs, reg), next_iword ());
379: break;
380: case 7:
381: switch (reg) {
382: case 0:
383: ad = (uae_s32) (uae_s16) next_iword ();
384: break;
385: case 1:
386: ad = next_ilong ();
387: break;
388: case 2:
389: ad = m68k_getpc ();
390: ad += (uae_s32) (uae_s16) next_iword ();
391: break;
392: case 3:
393: tmppc = m68k_getpc ();
394: tmp = next_iword ();
395: ad = get_disp_ea_020 (tmppc, tmp);
396: break;
397: case 4:
398: ad = m68k_getpc ();
399: m68k_setpc (ad + sz2[size]);
400: break;
401: default:
402: return 0;
403: }
404: }
405: switch (size) {
406: case 0:
1.1.1.2 root 407: put_long (ad,toint(value));
1.1 root 408: break;
409: case 1:
410: put_long (ad, from_single (value));
411: break;
412: case 2:
413: {
414: uae_u32 wrd1, wrd2, wrd3;
415: from_exten (value, &wrd1, &wrd2, &wrd3);
416: put_long (ad, wrd1);
417: ad += 4;
418: put_long (ad, wrd2);
419: ad += 4;
420: put_long (ad, wrd3);
421: }
422: break;
423: case 3:
424: {
425: uae_u32 wrd1, wrd2, wrd3;
426: from_pack (value, &wrd1, &wrd2, &wrd3);
427: put_long (ad, wrd1);
428: ad += 4;
429: put_long (ad, wrd2);
430: ad += 4;
431: put_long (ad, wrd3);
432: }
433: break;
434: case 4:
1.1.1.2 root 435: put_word (ad, (uae_s16) toint(value));
1.1 root 436: break;
437: case 5:{
438: uae_u32 wrd1, wrd2;
439: from_double (value, &wrd1, &wrd2);
440: put_long (ad, wrd1);
441: ad += 4;
442: put_long (ad, wrd2);
443: }
444: break;
445: case 6:
1.1.1.2 root 446: put_byte (ad, (uae_s8)toint(value));
1.1 root 447: break;
448: default:
449: return 0;
450: }
451: return 1;
452: }
453:
454: STATIC_INLINE int get_fp_ad (uae_u32 opcode, uae_u32 * ad)
455: {
456: uae_u16 tmp;
457: uaecptr tmppc;
458: int mode;
459: int reg;
460:
461: mode = (opcode >> 3) & 7;
462: reg = opcode & 7;
463: switch (mode) {
464: case 0:
465: case 1:
466: return 0;
467: case 2:
468: *ad = m68k_areg (regs, reg);
469: break;
470: case 3:
471: *ad = m68k_areg (regs, reg);
472: break;
473: case 4:
474: *ad = m68k_areg (regs, reg);
475: break;
476: case 5:
477: *ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) next_iword ();
478: break;
479: case 6:
480: *ad = get_disp_ea_020 (m68k_areg (regs, reg), next_iword ());
481: break;
482: case 7:
483: switch (reg) {
484: case 0:
485: *ad = (uae_s32) (uae_s16) next_iword ();
486: break;
487: case 1:
488: *ad = next_ilong ();
489: break;
490: case 2:
491: *ad = m68k_getpc ();
492: *ad += (uae_s32) (uae_s16) next_iword ();
493: break;
494: case 3:
495: tmppc = m68k_getpc ();
496: tmp = next_iword ();
497: *ad = get_disp_ea_020 (tmppc, tmp);
498: break;
499: default:
500: return 0;
501: }
502: }
503: return 1;
504: }
505:
506: STATIC_INLINE int fpp_cond (uae_u32 opcode, int contition)
507: {
1.1.1.2 root 508: int N = (regs.fp_result<0);
509: int Z = (regs.fp_result==0);
1.1 root 510: /* int I = (regs.fpsr & 0x2000000) != 0; */
1.1.1.2 root 511: int NotANumber = 0;
512:
513: #ifdef HAVE_ISNAN
514: NotANumber = isnan (regs.fp_result);
515: #endif
516:
517: if (NotANumber)
518: N=Z=0;
1.1 root 519:
520: switch (contition) {
521: case 0x00:
522: return 0;
523: case 0x01:
524: return Z;
525: case 0x02:
526: return !(NotANumber || Z || N);
527: case 0x03:
528: return Z || !(NotANumber || N);
529: case 0x04:
530: return N && !(NotANumber || Z);
531: case 0x05:
532: return Z || (N && !NotANumber);
533: case 0x06:
534: return !(NotANumber || Z);
535: case 0x07:
536: return !NotANumber;
537: case 0x08:
538: return NotANumber;
539: case 0x09:
540: return NotANumber || Z;
541: case 0x0a:
542: return NotANumber || !(N || Z);
543: case 0x0b:
544: return NotANumber || Z || !N;
545: case 0x0c:
546: return NotANumber || (N && !Z);
547: case 0x0d:
548: return NotANumber || Z || N;
549: case 0x0e:
550: return !Z;
551: case 0x0f:
552: return 1;
553: case 0x10:
554: return 0;
555: case 0x11:
556: return Z;
557: case 0x12:
558: return !(NotANumber || Z || N);
559: case 0x13:
560: return Z || !(NotANumber || N);
561: case 0x14:
562: return N && !(NotANumber || Z);
563: case 0x15:
564: return Z || (N && !NotANumber);
565: case 0x16:
566: return !(NotANumber || Z);
567: case 0x17:
568: return !NotANumber;
569: case 0x18:
570: return NotANumber;
571: case 0x19:
572: return NotANumber || Z;
573: case 0x1a:
574: return NotANumber || !(N || Z);
575: case 0x1b:
576: return NotANumber || Z || !N;
577: case 0x1c:
1.1.1.2 root 578: #if 0
579: return NotANumber || (Z && N); /* This is wrong, compare 0x0c */
580: #else
581: return NotANumber || (N && !Z);
582: #endif
1.1 root 583: case 0x1d:
584: return NotANumber || Z || N;
585: case 0x1e:
586: return !Z;
587: case 0x1f:
588: return 1;
589: }
590: return -1;
591: }
592:
593: void fdbcc_opp (uae_u32 opcode, uae_u16 extra)
594: {
595: uaecptr pc = (uae_u32) m68k_getpc ();
596: uae_s32 disp = (uae_s32) (uae_s16) next_iword ();
597: int cc;
598:
599: #if DEBUG_FPP
600: printf ("fdbcc_opp at %08lx\n", m68k_getpc ());
601: fflush (stdout);
602: #endif
603: cc = fpp_cond (opcode, extra & 0x3f);
604: if (cc == -1) {
605: m68k_setpc (pc - 4);
606: op_illg (opcode);
607: } else if (!cc) {
608: int reg = opcode & 0x7;
609:
610: m68k_dreg (regs, reg) = ((m68k_dreg (regs, reg) & ~0xffff)
611: | ((m68k_dreg (regs, reg) - 1) & 0xffff));
612: if ((m68k_dreg (regs, reg) & 0xffff) == 0xffff)
613: m68k_setpc (pc + disp);
614: }
615: }
616:
617: void fscc_opp (uae_u32 opcode, uae_u16 extra)
618: {
619: uae_u32 ad;
620: int cc;
621:
622: #if DEBUG_FPP
623: printf ("fscc_opp at %08lx\n", m68k_getpc ());
624: fflush (stdout);
625: #endif
626: cc = fpp_cond (opcode, extra & 0x3f);
627: if (cc == -1) {
628: m68k_setpc (m68k_getpc () - 4);
629: op_illg (opcode);
630: } else if ((opcode & 0x38) == 0) {
631: m68k_dreg (regs, opcode & 7) = (m68k_dreg (regs, opcode & 7) & ~0xff) | (cc ? 0xff : 0x00);
632: } else {
633: if (get_fp_ad (opcode, &ad) == 0) {
634: m68k_setpc (m68k_getpc () - 4);
635: op_illg (opcode);
636: } else
637: put_byte (ad, cc ? 0xff : 0x00);
638: }
639: }
640:
641: void ftrapcc_opp (uae_u32 opcode, uaecptr oldpc)
642: {
643: int cc;
644:
645: #if DEBUG_FPP
646: printf ("ftrapcc_opp at %08lx\n", m68k_getpc ());
647: fflush (stdout);
648: #endif
649: cc = fpp_cond (opcode, opcode & 0x3f);
650: if (cc == -1) {
651: m68k_setpc (oldpc);
652: op_illg (opcode);
653: }
654: if (cc)
655: Exception (7, oldpc - 2);
656: }
657:
658: void fbcc_opp (uae_u32 opcode, uaecptr pc, uae_u32 extra)
659: {
660: int cc;
661:
662: #if DEBUG_FPP
663: printf ("fbcc_opp at %08lx\n", m68k_getpc ());
664: fflush (stdout);
665: #endif
666: cc = fpp_cond (opcode, opcode & 0x3f);
667: if (cc == -1) {
668: m68k_setpc (pc);
669: op_illg (opcode);
670: } else if (cc) {
671: if ((opcode & 0x40) == 0)
672: extra = (uae_s32) (uae_s16) extra;
673: m68k_setpc (pc + extra);
674: }
675: }
676:
677: void fsave_opp (uae_u32 opcode)
678: {
679: uae_u32 ad;
680: int incr = (opcode & 0x38) == 0x20 ? -1 : 1;
681: int i;
682:
683: #if DEBUG_FPP
684: printf ("fsave_opp at %08lx\n", m68k_getpc ());
685: fflush (stdout);
686: #endif
687: if (get_fp_ad (opcode, &ad) == 0) {
688: m68k_setpc (m68k_getpc () - 2);
689: op_illg (opcode);
690: return;
691: }
692:
693: if (cpu_level == 4) {
694: /* 4 byte 68040 IDLE frame. */
695: if (incr < 0) {
696: ad -= 4;
697: put_long (ad, 0x41000000);
698: } else {
699: put_long (ad, 0x41000000);
700: ad += 4;
701: }
702: } else {
703: if (incr < 0) {
704: ad -= 4;
705: put_long (ad, 0x70000000);
706: for (i = 0; i < 5; i++) {
707: ad -= 4;
708: put_long (ad, 0x00000000);
709: }
710: ad -= 4;
711: put_long (ad, 0x1f180000);
712: } else {
713: put_long (ad, 0x1f180000);
714: ad += 4;
715: for (i = 0; i < 5; i++) {
716: put_long (ad, 0x00000000);
717: ad += 4;
718: }
719: put_long (ad, 0x70000000);
720: ad += 4;
721: }
722: }
723: if ((opcode & 0x38) == 0x18)
724: m68k_areg (regs, opcode & 7) = ad;
725: if ((opcode & 0x38) == 0x20)
726: m68k_areg (regs, opcode & 7) = ad;
727: }
728:
729: void frestore_opp (uae_u32 opcode)
730: {
731: uae_u32 ad;
732: uae_u32 d;
733: int incr = (opcode & 0x38) == 0x20 ? -1 : 1;
734:
735: #if DEBUG_FPP
736: printf ("frestore_opp at %08lx\n", m68k_getpc ());
737: fflush (stdout);
738: #endif
739: if (get_fp_ad (opcode, &ad) == 0) {
740: m68k_setpc (m68k_getpc () - 2);
741: op_illg (opcode);
742: return;
743: }
744: if (cpu_level == 4) {
745: /* 68040 */
746: if (incr < 0) {
747: /* @@@ This may be wrong. */
748: ad -= 4;
749: d = get_long (ad);
750: if ((d & 0xff000000) != 0) { /* Not a NULL frame? */
751: if ((d & 0x00ff0000) == 0) { /* IDLE */
752: } else if ((d & 0x00ff0000) == 0x00300000) { /* UNIMP */
753: ad -= 44;
754: } else if ((d & 0x00ff0000) == 0x00600000) { /* BUSY */
755: ad -= 92;
756: }
757: }
758: } else {
759: d = get_long (ad);
760: ad += 4;
761: if ((d & 0xff000000) != 0) { /* Not a NULL frame? */
762: if ((d & 0x00ff0000) == 0) { /* IDLE */
763: } else if ((d & 0x00ff0000) == 0x00300000) { /* UNIMP */
764: ad += 44;
765: } else if ((d & 0x00ff0000) == 0x00600000) { /* BUSY */
766: ad += 92;
767: }
768: }
769: }
770: } else {
771: if (incr < 0) {
772: ad -= 4;
773: d = get_long (ad);
774: if ((d & 0xff000000) != 0) {
775: if ((d & 0x00ff0000) == 0x00180000)
776: ad -= 6 * 4;
777: else if ((d & 0x00ff0000) == 0x00380000)
778: ad -= 14 * 4;
779: else if ((d & 0x00ff0000) == 0x00b40000)
780: ad -= 45 * 4;
781: }
782: } else {
783: d = get_long (ad);
784: ad += 4;
785: if ((d & 0xff000000) != 0) {
786: if ((d & 0x00ff0000) == 0x00180000)
787: ad += 6 * 4;
788: else if ((d & 0x00ff0000) == 0x00380000)
789: ad += 14 * 4;
790: else if ((d & 0x00ff0000) == 0x00b40000)
791: ad += 45 * 4;
792: }
793: }
794: }
795: if ((opcode & 0x38) == 0x18)
796: m68k_areg (regs, opcode & 7) = ad;
797: if ((opcode & 0x38) == 0x20)
798: m68k_areg (regs, opcode & 7) = ad;
799: }
800:
801: void fpp_opp (uae_u32 opcode, uae_u16 extra)
802: {
803: int reg;
1.1.1.2 root 804: fptype src;
1.1 root 805:
806: #if DEBUG_FPP
807: printf ("FPP %04lx %04x at %08lx\n", opcode & 0xffff, extra & 0xffff, m68k_getpc () - 4);
808: fflush (stdout);
809: #endif
810: switch ((extra >> 13) & 0x7) {
811: case 3:
812: if (put_fp_value (regs.fp[(extra >> 7) & 7], opcode, extra) == 0) {
813: m68k_setpc (m68k_getpc () - 4);
814: op_illg (opcode);
815: }
816: return;
817: case 4:
818: case 5:
819: if ((opcode & 0x38) == 0) {
820: if (extra & 0x2000) {
821: if (extra & 0x1000)
822: m68k_dreg (regs, opcode & 7) = regs.fpcr;
823: if (extra & 0x0800)
1.1.1.2 root 824: m68k_dreg (regs, opcode & 7) = get_fpsr ();
1.1 root 825: if (extra & 0x0400)
826: m68k_dreg (regs, opcode & 7) = regs.fpiar;
827: } else {
1.1.1.2 root 828: if (extra & 0x1000) {
1.1 root 829: regs.fpcr = m68k_dreg (regs, opcode & 7);
1.1.1.2 root 830: native_set_fpucw (regs.fpcr);
831: }
1.1 root 832: if (extra & 0x0800)
1.1.1.2 root 833: set_fpsr (m68k_dreg (regs, opcode & 7));
1.1 root 834: if (extra & 0x0400)
835: regs.fpiar = m68k_dreg (regs, opcode & 7);
836: }
1.1.1.2 root 837: } else if ((opcode & 0x38) == 0x08) {
1.1 root 838: if (extra & 0x2000) {
839: if (extra & 0x1000)
840: m68k_areg (regs, opcode & 7) = regs.fpcr;
841: if (extra & 0x0800)
1.1.1.2 root 842: m68k_areg (regs, opcode & 7) = get_fpsr ();
1.1 root 843: if (extra & 0x0400)
844: m68k_areg (regs, opcode & 7) = regs.fpiar;
845: } else {
1.1.1.2 root 846: if (extra & 0x1000) {
1.1 root 847: regs.fpcr = m68k_areg (regs, opcode & 7);
1.1.1.2 root 848: native_set_fpucw (regs.fpcr);
849: }
1.1 root 850: if (extra & 0x0800)
1.1.1.2 root 851: set_fpsr (m68k_areg (regs, opcode & 7));
1.1 root 852: if (extra & 0x0400)
853: regs.fpiar = m68k_areg (regs, opcode & 7);
854: }
855: } else if ((opcode & 0x3f) == 0x3c) {
856: if ((extra & 0x2000) == 0) {
1.1.1.2 root 857: if (extra & 0x1000) {
1.1 root 858: regs.fpcr = next_ilong ();
1.1.1.2 root 859: native_set_fpucw (regs.fpcr);
860: }
1.1 root 861: if (extra & 0x0800)
1.1.1.2 root 862: set_fpsr (next_ilong ());
1.1 root 863: if (extra & 0x0400)
864: regs.fpiar = next_ilong ();
865: }
866: } else if (extra & 0x2000) {
867: /* FMOVEM FPP->memory */
868: uae_u32 ad;
869: int incr = 0;
870:
871: if (get_fp_ad (opcode, &ad) == 0) {
872: m68k_setpc (m68k_getpc () - 4);
873: op_illg (opcode);
874: return;
875: }
876: if ((opcode & 0x38) == 0x20) {
877: if (extra & 0x1000)
878: incr += 4;
879: if (extra & 0x0800)
880: incr += 4;
881: if (extra & 0x0400)
882: incr += 4;
883: }
884: ad -= incr;
885: if (extra & 0x1000) {
886: put_long (ad, regs.fpcr);
887: ad += 4;
888: }
889: if (extra & 0x0800) {
1.1.1.2 root 890: put_long (ad, get_fpsr());
1.1 root 891: ad += 4;
892: }
893: if (extra & 0x0400) {
894: put_long (ad, regs.fpiar);
895: ad += 4;
896: }
897: ad -= incr;
898: if ((opcode & 0x38) == 0x18)
899: m68k_areg (regs, opcode & 7) = ad;
900: if ((opcode & 0x38) == 0x20)
901: m68k_areg (regs, opcode & 7) = ad;
902: } else {
903: /* FMOVEM memory->FPP */
904: uae_u32 ad;
905:
906: if (get_fp_ad (opcode, &ad) == 0) {
907: m68k_setpc (m68k_getpc () - 4);
908: op_illg (opcode);
909: return;
910: }
911: ad = (opcode & 0x38) == 0x20 ? ad - 12 : ad;
912: if (extra & 0x1000) {
913: regs.fpcr = get_long (ad);
1.1.1.2 root 914: native_set_fpucw(regs.fpcr);
1.1 root 915: ad += 4;
916: }
917: if (extra & 0x0800) {
1.1.1.2 root 918: set_fpsr(get_long (ad));
1.1 root 919: ad += 4;
920: }
921: if (extra & 0x0400) {
922: regs.fpiar = get_long (ad);
923: ad += 4;
924: }
925: if ((opcode & 0x38) == 0x18)
926: m68k_areg (regs, opcode & 7) = ad;
927: if ((opcode & 0x38) == 0x20)
928: m68k_areg (regs, opcode & 7) = ad - 12;
929: }
930: return;
931: case 6:
932: case 7:
1.1.1.2 root 933: {
934: uae_u32 ad, list = 0;
935: int incr = 0;
936: if (extra & 0x2000) {
937: /* FMOVEM FPP->memory */
938: if (get_fp_ad (opcode, &ad) == 0) {
939: m68k_setpc (m68k_getpc () - 4);
940: op_illg (opcode);
941: return;
942: }
943: switch ((extra >> 11) & 3) {
944: case 0: /* static pred */
945: list = extra & 0xff;
946: incr = -1;
947: break;
948: case 1: /* dynamic pred */
949: list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff;
950: incr = -1;
951: break;
952: case 2: /* static postinc */
953: list = extra & 0xff;
954: incr = 1;
955: break;
956: case 3: /* dynamic postinc */
957: list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff;
958: incr = 1;
959: break;
960: }
961: while (list) {
962: uae_u32 wrd1, wrd2, wrd3;
963: if (incr < 0) {
964: from_exten (regs.fp[fpp_movem_index2[list]], &wrd1, &wrd2, &wrd3);
965: ad -= 4;
966: put_long (ad, wrd3);
967: ad -= 4;
968: put_long (ad, wrd2);
969: ad -= 4;
970: put_long (ad, wrd1);
971: } else {
972: from_exten (regs.fp[fpp_movem_index1[list]], &wrd1, &wrd2, &wrd3);
973: put_long (ad, wrd1);
974: ad += 4;
975: put_long (ad, wrd2);
976: ad += 4;
977: put_long (ad, wrd3);
978: ad += 4;
1.1 root 979: }
1.1.1.2 root 980: list = fpp_movem_next[list];
981: }
982: if ((opcode & 0x38) == 0x18)
983: m68k_areg (regs, opcode & 7) = ad;
984: if ((opcode & 0x38) == 0x20)
985: m68k_areg (regs, opcode & 7) = ad;
986: } else {
987: /* FMOVEM memory->FPP */
988: if (get_fp_ad (opcode, &ad) == 0) {
989: m68k_setpc (m68k_getpc () - 4);
990: op_illg (opcode);
991: return;
992: }
993: switch ((extra >> 11) & 3) {
994: case 0: /* static pred */
995: list = extra & 0xff;
996: incr = -1;
997: break;
998: case 1: /* dynamic pred */
999: list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff;
1000: incr = -1;
1001: break;
1002: case 2: /* static postinc */
1003: list = extra & 0xff;
1004: incr = 1;
1005: break;
1006: case 3: /* dynamic postinc */
1007: list = m68k_dreg (regs, (extra >> 4) & 3) & 0xff;
1008: incr = 1;
1009: break;
1010: }
1011: while (list) {
1012: uae_u32 wrd1, wrd2, wrd3;
1013: if (incr < 0) {
1014: ad -= 4;
1015: wrd3 = get_long (ad);
1016: ad -= 4;
1017: wrd2 = get_long (ad);
1018: ad -= 4;
1019: wrd1 = get_long (ad);
1020: regs.fp[fpp_movem_index2[list]] = to_exten (wrd1, wrd2, wrd3);
1021: } else {
1022: wrd1 = get_long (ad);
1023: ad += 4;
1024: wrd2 = get_long (ad);
1025: ad += 4;
1026: wrd3 = get_long (ad);
1027: ad += 4;
1028: regs.fp[fpp_movem_index1[list]] = to_exten (wrd1, wrd2, wrd3);
1.1 root 1029: }
1.1.1.2 root 1030: list = fpp_movem_next[list];
1.1 root 1031: }
1.1.1.2 root 1032: if ((opcode & 0x38) == 0x18)
1033: m68k_areg (regs, opcode & 7) = ad;
1034: if ((opcode & 0x38) == 0x20)
1035: m68k_areg (regs, opcode & 7) = ad;
1.1 root 1036: }
1.1.1.2 root 1037: }
1038: return;
1.1 root 1039: case 0:
1.1.1.2 root 1040: case 2: /* Extremely common */
1.1 root 1041: reg = (extra >> 7) & 7;
1042: if ((extra & 0xfc00) == 0x5c00) {
1043: switch (extra & 0x7f) {
1044: case 0x00:
1045: regs.fp[reg] = 4.0 * atan (1.0);
1046: break;
1047: case 0x0b:
1048: regs.fp[reg] = log10 (2.0);
1049: break;
1050: case 0x0c:
1051: regs.fp[reg] = exp (1.0);
1052: break;
1053: case 0x0d:
1054: regs.fp[reg] = log (exp (1.0)) / log (2.0);
1055: break;
1056: case 0x0e:
1057: regs.fp[reg] = log (exp (1.0)) / log (10.0);
1058: break;
1059: case 0x0f:
1060: regs.fp[reg] = 0.0;
1061: break;
1062: case 0x30:
1063: regs.fp[reg] = log (2.0);
1064: break;
1065: case 0x31:
1066: regs.fp[reg] = log (10.0);
1067: break;
1068: case 0x32:
1069: regs.fp[reg] = 1.0e0;
1070: break;
1071: case 0x33:
1072: regs.fp[reg] = 1.0e1;
1073: break;
1074: case 0x34:
1075: regs.fp[reg] = 1.0e2;
1076: break;
1077: case 0x35:
1078: regs.fp[reg] = 1.0e4;
1079: break;
1080: case 0x36:
1081: regs.fp[reg] = 1.0e8;
1082: break;
1083: case 0x37:
1084: regs.fp[reg] = 1.0e16;
1085: break;
1086: case 0x38:
1087: regs.fp[reg] = 1.0e32;
1088: break;
1089: case 0x39:
1090: regs.fp[reg] = 1.0e64;
1091: break;
1092: case 0x3a:
1093: regs.fp[reg] = 1.0e128;
1094: break;
1095: case 0x3b:
1096: regs.fp[reg] = 1.0e256;
1097: break;
1098: #if 0
1099: case 0x3c:
1100: regs.fp[reg] = 1.0e512;
1101: break;
1102: case 0x3d:
1103: regs.fp[reg] = 1.0e1024;
1104: break;
1105: case 0x3e:
1106: regs.fp[reg] = 1.0e2048;
1107: break;
1108: case 0x3f:
1109: regs.fp[reg] = 1.0e4096;
1110: break;
1111: #endif
1112: default:
1113: m68k_setpc (m68k_getpc () - 4);
1114: op_illg (opcode);
1115: break;
1116: }
1117: return;
1118: }
1119: if (get_fp_value (opcode, extra, &src) == 0) {
1120: m68k_setpc (m68k_getpc () - 4);
1121: op_illg (opcode);
1122: return;
1123: }
1124: switch (extra & 0x7f) {
1125: case 0x00: /* FMOVE */
1.1.1.2 root 1126: case 0x40: /* Explicit rounding. This is just a quick fix. Same
1127: * for all other cases that have three choices */
1128: case 0x44:
1.1 root 1129: regs.fp[reg] = src;
1130: /* Brian King was here. <ea> to register needs FPSR updated.
1131: * See page 3-73 in Motorola 68K programmers reference manual.
1132: * %%%FPU */
1.1.1.2 root 1133: if ((extra & 0x44) == 0x40)
1134: regs.fp[reg] = (float)regs.fp[reg];
1135: MAKE_FPSR (regs.fp[reg]);
1.1 root 1136: break;
1137: case 0x01: /* FINT */
1138: /* need to take the current rounding mode into account */
1.1.1.2 root 1139: regs.fp[reg] = toint(src);
1.1 root 1140: break;
1141: case 0x02: /* FSINH */
1142: regs.fp[reg] = sinh (src);
1.1.1.2 root 1143: MAKE_FPSR (regs.fp[reg]);
1.1 root 1144: break;
1145: case 0x03: /* FINTRZ */
1146: regs.fp[reg] = (int) src;
1.1.1.2 root 1147: MAKE_FPSR (regs.fp[reg]);
1.1 root 1148: break;
1149: case 0x04: /* FSQRT */
1.1.1.2 root 1150: case 0x41:
1151: case 0x45:
1.1 root 1152: regs.fp[reg] = sqrt (src);
1.1.1.2 root 1153: if ((extra & 0x44) == 0x40)
1154: regs.fp[reg] = (float)regs.fp[reg];
1155: MAKE_FPSR (regs.fp[reg]);
1.1 root 1156: break;
1157: case 0x06: /* FLOGNP1 */
1158: regs.fp[reg] = log (src + 1.0);
1.1.1.2 root 1159: MAKE_FPSR (regs.fp[reg]);
1.1 root 1160: break;
1161: case 0x08: /* FETOXM1 */
1162: regs.fp[reg] = exp (src) - 1.0;
1.1.1.2 root 1163: MAKE_FPSR (regs.fp[reg]);
1.1 root 1164: break;
1165: case 0x09: /* FTANH */
1166: regs.fp[reg] = tanh (src);
1.1.1.2 root 1167: MAKE_FPSR (regs.fp[reg]);
1.1 root 1168: break;
1169: case 0x0a: /* FATAN */
1170: regs.fp[reg] = atan (src);
1.1.1.2 root 1171: MAKE_FPSR (regs.fp[reg]);
1.1 root 1172: break;
1173: case 0x0c: /* FASIN */
1174: regs.fp[reg] = asin (src);
1.1.1.2 root 1175: MAKE_FPSR (regs.fp[reg]);
1.1 root 1176: break;
1177: case 0x0d: /* FATANH */
1178: #if 1 /* The BeBox doesn't have atanh, and it isn't in the HPUX libm either */
1179: regs.fp[reg] = log ((1 + src) / (1 - src)) / 2;
1180: #else
1181: regs.fp[reg] = atanh (src);
1182: #endif
1.1.1.2 root 1183: MAKE_FPSR (regs.fp[reg]);
1.1 root 1184: break;
1185: case 0x0e: /* FSIN */
1186: regs.fp[reg] = sin (src);
1.1.1.2 root 1187: MAKE_FPSR (regs.fp[reg]);
1.1 root 1188: break;
1189: case 0x0f: /* FTAN */
1190: regs.fp[reg] = tan (src);
1.1.1.2 root 1191: MAKE_FPSR (regs.fp[reg]);
1.1 root 1192: break;
1193: case 0x10: /* FETOX */
1194: regs.fp[reg] = exp (src);
1.1.1.2 root 1195: MAKE_FPSR (regs.fp[reg]);
1.1 root 1196: break;
1197: case 0x11: /* FTWOTOX */
1198: regs.fp[reg] = pow (2.0, src);
1.1.1.2 root 1199: MAKE_FPSR (regs.fp[reg]);
1.1 root 1200: break;
1201: case 0x12: /* FTENTOX */
1202: regs.fp[reg] = pow (10.0, src);
1.1.1.2 root 1203: MAKE_FPSR (regs.fp[reg]);
1.1 root 1204: break;
1205: case 0x14: /* FLOGN */
1206: regs.fp[reg] = log (src);
1.1.1.2 root 1207: MAKE_FPSR (regs.fp[reg]);
1.1 root 1208: break;
1209: case 0x15: /* FLOG10 */
1210: regs.fp[reg] = log10 (src);
1.1.1.2 root 1211: MAKE_FPSR (regs.fp[reg]);
1.1 root 1212: break;
1213: case 0x16: /* FLOG2 */
1214: regs.fp[reg] = log (src) / log (2.0);
1.1.1.2 root 1215: MAKE_FPSR (regs.fp[reg]);
1.1 root 1216: break;
1217: case 0x18: /* FABS */
1.1.1.2 root 1218: case 0x58:
1219: case 0x5c:
1.1 root 1220: regs.fp[reg] = src < 0 ? -src : src;
1.1.1.2 root 1221: if ((extra & 0x44) == 0x40)
1222: regs.fp[reg] = (float)regs.fp[reg];
1223: MAKE_FPSR (regs.fp[reg]);
1.1 root 1224: break;
1225: case 0x19: /* FCOSH */
1226: regs.fp[reg] = cosh (src);
1.1.1.2 root 1227: MAKE_FPSR (regs.fp[reg]);
1.1 root 1228: break;
1229: case 0x1a: /* FNEG */
1.1.1.2 root 1230: case 0x5a:
1231: case 0x5e:
1.1 root 1232: regs.fp[reg] = -src;
1.1.1.2 root 1233: if ((extra & 0x44) == 0x40)
1234: regs.fp[reg] = (float)regs.fp[reg];
1235: MAKE_FPSR (regs.fp[reg]);
1.1 root 1236: break;
1237: case 0x1c: /* FACOS */
1238: regs.fp[reg] = acos (src);
1.1.1.2 root 1239: MAKE_FPSR (regs.fp[reg]);
1.1 root 1240: break;
1241: case 0x1d: /* FCOS */
1242: regs.fp[reg] = cos (src);
1.1.1.2 root 1243: MAKE_FPSR (regs.fp[reg]);
1.1 root 1244: break;
1245: case 0x1e: /* FGETEXP */
1.1.1.2 root 1246: {
1247: int expon;
1248: frexp (src, &expon);
1249: regs.fp[reg] = (double) (expon - 1);
1250: MAKE_FPSR (regs.fp[reg]);
1251: }
1252: break;
1.1 root 1253: case 0x1f: /* FGETMAN */
1.1.1.2 root 1254: {
1255: int expon;
1256: regs.fp[reg] = frexp (src, &expon) * 2.0;
1257: MAKE_FPSR (regs.fp[reg]);
1258: }
1259: break;
1.1 root 1260: case 0x20: /* FDIV */
1.1.1.2 root 1261: case 0x60:
1262: case 0x64:
1.1 root 1263: regs.fp[reg] /= src;
1.1.1.2 root 1264: if ((extra & 0x44) == 0x40)
1265: regs.fp[reg] = (float)regs.fp[reg];
1266: MAKE_FPSR (regs.fp[reg]);
1.1 root 1267: break;
1268: case 0x21: /* FMOD */
1269: regs.fp[reg] = regs.fp[reg] - (double) ((int) (regs.fp[reg] / src)) * src;
1.1.1.2 root 1270: MAKE_FPSR (regs.fp[reg]);
1.1 root 1271: break;
1272: case 0x22: /* FADD */
1.1.1.2 root 1273: case 0x62:
1274: case 0x66:
1.1 root 1275: regs.fp[reg] += src;
1.1.1.2 root 1276: if ((extra & 0x44) == 0x40)
1277: regs.fp[reg] = (float)regs.fp[reg];
1278: MAKE_FPSR (regs.fp[reg]);
1.1 root 1279: break;
1280: case 0x23: /* FMUL */
1.1.1.2 root 1281: case 0x63:
1282: case 0x67:
1.1 root 1283: regs.fp[reg] *= src;
1.1.1.2 root 1284: if ((extra & 0x44) == 0x40)
1285: regs.fp[reg] = (float)regs.fp[reg];
1286: MAKE_FPSR (regs.fp[reg]);
1.1 root 1287: break;
1288: case 0x24: /* FSGLDIV */
1289: regs.fp[reg] /= src;
1.1.1.2 root 1290: MAKE_FPSR (regs.fp[reg]);
1.1 root 1291: break;
1292: case 0x25: /* FREM */
1293: regs.fp[reg] = regs.fp[reg] - (double) ((int) (regs.fp[reg] / src + 0.5)) * src;
1.1.1.2 root 1294: MAKE_FPSR (regs.fp[reg]);
1.1 root 1295: break;
1296: case 0x26: /* FSCALE */
1297: regs.fp[reg] *= exp (log (2.0) * src);
1.1.1.2 root 1298: MAKE_FPSR (regs.fp[reg]);
1.1 root 1299: break;
1300: case 0x27: /* FSGLMUL */
1301: regs.fp[reg] *= src;
1.1.1.2 root 1302: MAKE_FPSR (regs.fp[reg]);
1.1 root 1303: break;
1304: case 0x28: /* FSUB */
1.1.1.2 root 1305: case 0x68:
1306: case 0x6c:
1.1 root 1307: regs.fp[reg] -= src;
1.1.1.2 root 1308: if ((extra & 0x44) == 0x40)
1309: regs.fp[reg] = (float)regs.fp[reg];
1310: MAKE_FPSR (regs.fp[reg]);
1.1 root 1311: break;
1312: case 0x30: /* FSINCOS */
1313: case 0x31:
1314: case 0x32:
1315: case 0x33:
1316: case 0x34:
1317: case 0x35:
1318: case 0x36:
1319: case 0x37:
1320: regs.fp[reg] = sin (src);
1321: regs.fp[extra & 7] = cos (src);
1.1.1.2 root 1322: MAKE_FPSR (regs.fp[reg]);
1.1 root 1323: break;
1324: case 0x38: /* FCMP */
1.1.1.2 root 1325: {
1326: fptype tmp = regs.fp[reg] - src;
1327: regs.fpsr = 0;
1328: MAKE_FPSR (tmp);
1329: }
1330: break;
1.1 root 1331: case 0x3a: /* FTST */
1.1.1.2 root 1332: regs.fpsr = 0;
1333: MAKE_FPSR (src);
1.1 root 1334: break;
1335: default:
1336: m68k_setpc (m68k_getpc () - 4);
1337: op_illg (opcode);
1338: break;
1339: }
1340: return;
1341: }
1342: m68k_setpc (m68k_getpc () - 4);
1343: op_illg (opcode);
1344: }
1345:
1346: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.