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