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