ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/uae_cpu/fpp.cpp
Revision: 1.1
Committed: 1999-10-03T14:16:26Z (24 years, 9 months ago) by cebix
Branch: MAIN
Branch point for: cebix
Log Message:
Initial revision

File Contents

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