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