ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/uae_cpu/compiler/compemu_fpp.cpp
Revision: 1.10
Committed: 2008-01-01T09:40:35Z (16 years, 11 months ago) by gbeauche
Branch: MAIN
CVS Tags: HEAD
Changes since 1.9: +1 -1 lines
Error occurred while calculating annotation data.
Log Message:
Happy New Year!

File Contents

# Content
1 /*
2 * compiler/compemu_fpp.cpp - Dynamic translation of FPU instructions
3 *
4 * Original 68040 JIT compiler for UAE, copyright 2000-2002 Bernd Meyer
5 *
6 * Adaptation for Basilisk II and improvements, copyright 2000-2005
7 * Gwenole Beauchesne
8 *
9 * Basilisk II (C) 1997-2008 Christian Bauer
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
26 /*
27 * UAE - The Un*x Amiga Emulator
28 *
29 * MC68881 emulation
30 *
31 * Copyright 1996 Herman ten Brugge
32 * Adapted for JIT compilation (c) Bernd Meyer, 2000
33 */
34
35 #include "sysdeps.h"
36
37 #include <math.h>
38 #include <stdio.h>
39
40 #include "memory.h"
41 #include "readcpu.h"
42 #include "newcpu.h"
43 #include "main.h"
44 #include "compiler/compemu.h"
45 #include "fpu/fpu.h"
46 #include "fpu/flags.h"
47 #include "fpu/exceptions.h"
48 #include "fpu/rounding.h"
49
50 #define DEBUG 0
51 #include "debug.h"
52
53 // gb-- WARNING: get_fpcr() and set_fpcr() support is experimental
54 #define HANDLE_FPCR 0
55
56 // - IEEE-based fpu core must be used
57 #if defined(FPU_IEEE)
58 # define CAN_HANDLE_FPCR
59 #endif
60
61 // - Generic rounding mode and precision modes are supported if set together
62 #if defined(FPU_USE_GENERIC_ROUNDING_MODE) && defined(FPU_USE_GENERIC_ROUNDING_PRECISION)
63 # define CAN_HANDLE_FPCR
64 #endif
65
66 // - X86 rounding mode and precision modes are *not* supported but might work (?!)
67 #if defined(FPU_USE_X86_ROUNDING_MODE) && defined(FPU_USE_X86_ROUNDING_PRECISION)
68 # define CAN_HANDLE_FPCR
69 #endif
70
71 #if HANDLE_FPCR && !defined(CAN_HANDLE_FPCR)
72 # warning "Can't handle FPCR, will FAIL(1) at runtime"
73 # undef HANDLE_FPCR
74 # define HANDLE_FPCR 0
75 #endif
76
77 #define STATIC_INLINE static inline
78 #define MAKE_FPSR(r) do { fmov_rr(FP_RESULT,r); } while (0)
79
80 #define delay nop() ;nop()
81 #define delay2 nop() ;nop()
82
83 #define UNKNOWN_EXTRA 0xFFFFFFFF
84 static void fpuop_illg(uae_u32 opcode, uae_u32 extra)
85 {
86 /*
87 if (extra == UNKNOWN_EXTRA)
88 printf("FPU opcode %x, extra UNKNOWN_EXTRA\n",opcode & 0xFFFF);
89 else
90 printf("FPU opcode %x, extra %x\n",opcode & 0xFFFF,extra & 0xFFFF);
91 */
92 op_illg(opcode);
93 }
94
95 static uae_s32 temp_fp[4]; /* To convert between FP/integer */
96
97 /* return register number, or -1 for failure */
98 STATIC_INLINE int get_fp_value (uae_u32 opcode, uae_u16 extra)
99 {
100 uaecptr tmppc;
101 uae_u16 tmp;
102 int size;
103 int mode;
104 int reg;
105 double* src;
106 uae_u32 ad = 0;
107 static int sz1[8] = { 4, 4, 12, 12, 2, 8, 1, 0 };
108 static int sz2[8] = { 4, 4, 12, 12, 2, 8, 2, 0 };
109
110 if ((extra & 0x4000) == 0) {
111 return ((extra >> 10) & 7);
112 }
113
114 mode = (opcode >> 3) & 7;
115 reg = opcode & 7;
116 size = (extra >> 10) & 7;
117 switch (mode) {
118 case 0:
119 switch (size) {
120 case 6:
121 sign_extend_8_rr(S1,reg);
122 mov_l_mr((uintptr)temp_fp,S1);
123 delay2;
124 fmovi_rm(FS1,(uintptr)temp_fp);
125 return FS1;
126 case 4:
127 sign_extend_16_rr(S1,reg);
128 mov_l_mr((uintptr)temp_fp,S1);
129 delay2;
130 fmovi_rm(FS1,(uintptr)temp_fp);
131 return FS1;
132 case 0:
133 mov_l_mr((uintptr)temp_fp,reg);
134 delay2;
135 fmovi_rm(FS1,(uintptr)temp_fp);
136 return FS1;
137 case 1:
138 mov_l_mr((uintptr)temp_fp,reg);
139 delay2;
140 fmovs_rm(FS1,(uintptr)temp_fp);
141 return FS1;
142 default:
143 return -1;
144 }
145 return -1; /* Should be unreachable */
146 case 1:
147 return -1; /* Genuine invalid instruction */
148 default:
149 break;
150 }
151 /* OK, we *will* have to load something from an address. Let's make
152 sure we know how to handle that, or quit early --- i.e. *before*
153 we do any postincrement/predecrement that we may regret */
154
155 switch (size) {
156 case 3:
157 return -1;
158 case 0:
159 case 1:
160 case 2:
161 case 4:
162 case 5:
163 case 6:
164 break;
165 default:
166 return -1;
167 }
168
169 switch (mode) {
170 case 2:
171 ad=S1; /* We will change it, anyway ;-) */
172 mov_l_rr(ad,reg+8);
173 break;
174 case 3:
175 ad=S1;
176 mov_l_rr(ad,reg+8);
177 lea_l_brr(reg+8,reg+8,(reg == 7?sz2[size]:sz1[size]));
178 break;
179 case 4:
180 ad=S1;
181
182 lea_l_brr(reg+8,reg+8,-(reg == 7?sz2[size]:sz1[size]));
183 mov_l_rr(ad,reg+8);
184 break;
185 case 5:
186 {
187 uae_u32 off=(uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2);
188 ad=S1;
189 mov_l_rr(ad,reg+8);
190 lea_l_brr(ad,ad,off);
191 break;
192 }
193 case 6:
194 {
195 uae_u32 dp=comp_get_iword((m68k_pc_offset+=2)-2);
196 ad=S1;
197 calc_disp_ea_020(reg+8,dp,ad,S2);
198 break;
199 }
200 case 7:
201 switch (reg) {
202 case 0:
203 {
204 uae_u32 off=(uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2);
205 ad=S1;
206 mov_l_ri(ad,off);
207 break;
208 }
209 case 1:
210 {
211 uae_u32 off=comp_get_ilong((m68k_pc_offset+=4)-4);
212 ad=S1;
213 mov_l_ri(ad,off);
214 break;
215 }
216 case 2:
217 {
218 uae_u32 address=start_pc+((char *)comp_pc_p-(char *)start_pc_p)+
219 m68k_pc_offset;
220 uae_s32 PC16off =(uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)
221 -2);
222 ad=S1;
223 mov_l_ri(ad,address+PC16off);
224 break;
225 }
226 case 3:
227 return -1;
228 tmppc = m68k_getpc ();
229 tmp = next_iword ();
230 ad = get_disp_ea_020 (tmppc, tmp);
231 break;
232 case 4:
233 {
234 uae_u32 address=start_pc+((char *)comp_pc_p-(char *)start_pc_p)+ m68k_pc_offset;
235 ad=S1;
236 // Immediate addressing mode && Operation Length == Byte ->
237 // Use the low-order byte of the extension word.
238 if (size == 6) address++;
239 mov_l_ri(ad,address);
240 m68k_pc_offset+=sz2[size];
241 break;
242 }
243 default:
244 return -1;
245 }
246 }
247
248 switch (size) {
249 case 0:
250 readlong(ad,S2,S3);
251 mov_l_mr((uintptr)temp_fp,S2);
252 delay2;
253 fmovi_rm(FS1,(uintptr)temp_fp);
254 break;
255 case 1:
256 readlong(ad,S2,S3);
257 mov_l_mr((uintptr)temp_fp,S2);
258 delay2;
259 fmovs_rm(FS1,(uintptr)temp_fp);
260 break;
261 case 2:
262 readword(ad,S2,S3);
263 mov_w_mr(((uintptr)temp_fp)+8,S2);
264 add_l_ri(ad,4);
265 readlong(ad,S2,S3);
266 mov_l_mr((uintptr)(temp_fp)+4,S2);
267 add_l_ri(ad,4);
268 readlong(ad,S2,S3);
269 mov_l_mr((uintptr)(temp_fp),S2);
270 delay2;
271 fmov_ext_rm(FS1,(uintptr)(temp_fp));
272 break;
273 case 3:
274 return -1; /* Some silly "packed" stuff */
275 case 4:
276 readword(ad,S2,S3);
277 sign_extend_16_rr(S2,S2);
278 mov_l_mr((uintptr)temp_fp,S2);
279 delay2;
280 fmovi_rm(FS1,(uintptr)temp_fp);
281 break;
282 case 5:
283 readlong(ad,S2,S3);
284 mov_l_mr(((uintptr)temp_fp)+4,S2);
285 add_l_ri(ad,4);
286 readlong(ad,S2,S3);
287 mov_l_mr((uintptr)(temp_fp),S2);
288 delay2;
289 fmov_rm(FS1,(uintptr)(temp_fp));
290 break;
291 case 6:
292 readbyte(ad,S2,S3);
293 sign_extend_8_rr(S2,S2);
294 mov_l_mr((uintptr)temp_fp,S2);
295 delay2;
296 fmovi_rm(FS1,(uintptr)temp_fp);
297 break;
298 default:
299 return -1;
300 }
301 return FS1;
302 }
303
304 /* return of -1 means failure, >=0 means OK */
305 STATIC_INLINE int put_fp_value (int val, uae_u32 opcode, uae_u16 extra)
306 {
307 uae_u16 tmp;
308 uaecptr tmppc;
309 int size;
310 int mode;
311 int reg;
312 uae_u32 ad;
313 static int sz1[8] = { 4, 4, 12, 12, 2, 8, 1, 0 };
314 static int sz2[8] = { 4, 4, 12, 12, 2, 8, 2, 0 };
315
316 if ((extra & 0x4000) == 0) {
317 const int dest_reg = (extra >> 10) & 7;
318 fmov_rr(dest_reg, val);
319 // gb-- status register is affected
320 MAKE_FPSR(dest_reg);
321 return 0;
322 }
323
324 mode = (opcode >> 3) & 7;
325 reg = opcode & 7;
326 size = (extra >> 10) & 7;
327 ad = (uae_u32)-1;
328 switch (mode) {
329 case 0:
330 switch (size) {
331 case 6:
332 fmovi_mr((uintptr)temp_fp,val);
333 delay;
334 mov_b_rm(reg,(uintptr)temp_fp);
335 return 0;
336 case 4:
337 fmovi_mr((uintptr)temp_fp,val);
338 delay;
339 mov_w_rm(reg,(uintptr)temp_fp);
340 return 0;
341 case 0:
342 fmovi_mr((uintptr)temp_fp,val);
343 delay;
344 mov_l_rm(reg,(uintptr)temp_fp);
345 return 0;
346 case 1:
347 fmovs_mr((uintptr)temp_fp,val);
348 delay;
349 mov_l_rm(reg,(uintptr)temp_fp);
350 return 0;
351 default:
352 return -1;
353 }
354 case 1:
355 return -1; /* genuine invalid instruction */
356 default: break;
357 }
358
359 /* Let's make sure we get out *before* doing something silly if
360 we can't handle the size */
361 switch (size) {
362 case 0:
363 case 4:
364 case 5:
365 case 6:
366 case 2:
367 case 1:
368 break;
369 case 3:
370 default:
371 return -1;
372 }
373
374 switch (mode) {
375 case 2:
376 ad=S1;
377 mov_l_rr(ad,reg+8);
378 break;
379 case 3:
380 ad=S1;
381 mov_l_rr(ad,reg+8);
382 lea_l_brr(reg+8,reg+8,(reg == 7?sz2[size]:sz1[size]));
383 break;
384 case 4:
385 ad=S1;
386 lea_l_brr(reg+8,reg+8,-(reg == 7?sz2[size]:sz1[size]));
387 mov_l_rr(ad,reg+8);
388 break;
389 case 5:
390 {
391 uae_u32 off=(uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2);
392 ad=S1;
393 mov_l_rr(ad,reg+8);
394 add_l_ri(ad,off);
395 break;
396 }
397 case 6:
398 {
399 uae_u32 dp=comp_get_iword((m68k_pc_offset+=2)-2);
400 ad=S1;
401 calc_disp_ea_020(reg+8,dp,ad,S2);
402 break;
403 }
404 case 7:
405 switch (reg) {
406 case 0:
407 {
408 uae_u32 off=(uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2);
409 ad=S1;
410 mov_l_ri(ad,off);
411 break;
412 }
413 case 1:
414 {
415 uae_u32 off=comp_get_ilong((m68k_pc_offset+=4)-4);
416 ad=S1;
417 mov_l_ri(ad,off);
418 break;
419 }
420 case 2:
421 {
422 uae_u32 address=start_pc+((char *)comp_pc_p-(char *)start_pc_p)+
423 m68k_pc_offset;
424 uae_s32 PC16off =(uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2);
425 ad=S1;
426 mov_l_ri(ad,address+PC16off);
427 break;
428 }
429 case 3:
430 return -1;
431 tmppc = m68k_getpc ();
432 tmp = next_iword ();
433 ad = get_disp_ea_020 (tmppc, tmp);
434 break;
435 case 4:
436 {
437 uae_u32 address=start_pc+((char *)comp_pc_p-(char *)start_pc_p)+
438 m68k_pc_offset;
439 ad=S1;
440 mov_l_ri(ad,address);
441 m68k_pc_offset+=sz2[size];
442 break;
443 }
444 default:
445 return -1;
446 }
447 }
448 switch (size) {
449 case 0:
450 fmovi_mr((uintptr)temp_fp,val);
451 delay;
452 mov_l_rm(S2,(uintptr)temp_fp);
453 writelong_clobber(ad,S2,S3);
454 break;
455 case 1:
456 fmovs_mr((uintptr)temp_fp,val);
457 delay;
458 mov_l_rm(S2,(uintptr)temp_fp);
459 writelong_clobber(ad,S2,S3);
460 break;
461 case 2:
462 fmov_ext_mr((uintptr)temp_fp,val);
463 delay;
464 mov_w_rm(S2,(uintptr)temp_fp+8);
465 writeword_clobber(ad,S2,S3);
466 add_l_ri(ad,4);
467 mov_l_rm(S2,(uintptr)temp_fp+4);
468 writelong_clobber(ad,S2,S3);
469 add_l_ri(ad,4);
470 mov_l_rm(S2,(uintptr)temp_fp);
471 writelong_clobber(ad,S2,S3);
472 break;
473 case 3: return -1; /* Packed */
474
475 case 4:
476 fmovi_mr((uintptr)temp_fp,val);
477 delay;
478 mov_l_rm(S2,(uintptr)temp_fp);
479 writeword_clobber(ad,S2,S3);
480 break;
481 case 5:
482 fmov_mr((uintptr)temp_fp,val);
483 delay;
484 mov_l_rm(S2,(uintptr)temp_fp+4);
485 writelong_clobber(ad,S2,S3);
486 add_l_ri(ad,4);
487 mov_l_rm(S2,(uintptr)temp_fp);
488 writelong_clobber(ad,S2,S3);
489 break;
490 case 6:
491 fmovi_mr((uintptr)temp_fp,val);
492 delay;
493 mov_l_rm(S2,(uintptr)temp_fp);
494 writebyte(ad,S2,S3);
495 break;
496 default:
497 return -1;
498 }
499 return 0;
500 }
501
502 /* return -1 for failure, or register number for success */
503 STATIC_INLINE int get_fp_ad (uae_u32 opcode, uae_u32 * ad)
504 {
505 uae_u16 tmp;
506 uaecptr tmppc;
507 int mode;
508 int reg;
509 uae_s32 off;
510
511 mode = (opcode >> 3) & 7;
512 reg = opcode & 7;
513 switch (mode) {
514 case 0:
515 case 1:
516 return -1;
517 case 2:
518 case 3:
519 case 4:
520 mov_l_rr(S1,8+reg);
521 return S1;
522 *ad = m68k_areg (regs, reg);
523 break;
524 case 5:
525 off=(uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2);
526
527 mov_l_rr(S1,8+reg);
528 add_l_ri(S1,off);
529 return S1;
530 case 6:
531 return -1;
532 break;
533 case 7:
534 switch (reg) {
535 case 0:
536 off=(uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2);
537 mov_l_ri(S1,off);
538 return S1;
539 case 1:
540 off=comp_get_ilong((m68k_pc_offset+=4)-4);
541 mov_l_ri(S1,off);
542 return S1;
543 case 2:
544 return -1;
545 // *ad = m68k_getpc ();
546 // *ad += (uae_s32) (uae_s16) next_iword ();
547 off=start_pc+((char *)comp_pc_p-(char *)start_pc_p)+m68k_pc_offset;
548 off+=(uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2);
549 mov_l_ri(S1,off);
550 return S1;
551 case 3:
552 return -1;
553 tmppc = m68k_getpc ();
554 tmp = next_iword ();
555 *ad = get_disp_ea_020 (tmppc, tmp);
556 break;
557 default:
558 return -1;
559 }
560 }
561 abort();
562 }
563
564 void comp_fdbcc_opp (uae_u32 opcode, uae_u16 extra)
565 {
566 FAIL(1);
567 return;
568 }
569
570 void comp_fscc_opp (uae_u32 opcode, uae_u16 extra)
571 {
572 uae_u32 ad;
573 int cc;
574 int reg;
575
576 #if DEBUG_FPP
577 printf ("fscc_opp at %08lx\n", m68k_getpc ());
578 fflush (stdout);
579 #endif
580
581
582 if (extra&0x20) { /* only cc from 00 to 1f are defined */
583 FAIL(1);
584 return;
585 }
586 if ((opcode & 0x38) != 0) { /* We can only do to integer register */
587 FAIL(1);
588 return;
589 }
590
591 fflags_into_flags(S2);
592 reg=(opcode&7);
593
594 mov_l_ri(S1,255);
595 mov_l_ri(S4,0);
596 switch(extra&0x0f) { /* according to fpp.c, the 0x10 bit is ignored
597 */
598 case 0: break; /* set never */
599 case 1: mov_l_rr(S2,S4);
600 cmov_l_rr(S4,S1,4);
601 cmov_l_rr(S4,S2,10); break;
602 case 2: cmov_l_rr(S4,S1,7); break;
603 case 3: cmov_l_rr(S4,S1,3); break;
604 case 4: mov_l_rr(S2,S4);
605 cmov_l_rr(S4,S1,2);
606 cmov_l_rr(S4,S2,10); break;
607 case 5: mov_l_rr(S2,S4);
608 cmov_l_rr(S4,S1,6);
609 cmov_l_rr(S4,S2,10); break;
610 case 6: cmov_l_rr(S4,S1,5); break;
611 case 7: cmov_l_rr(S4,S1,11); break;
612 case 8: cmov_l_rr(S4,S1,10); break;
613 case 9: cmov_l_rr(S4,S1,4); break;
614 case 10: cmov_l_rr(S4,S1,10); cmov_l_rr(S4,S1,7); break;
615 case 11: cmov_l_rr(S4,S1,4); cmov_l_rr(S4,S1,3); break;
616 case 12: cmov_l_rr(S4,S1,2); break;
617 case 13: cmov_l_rr(S4,S1,6); break;
618 case 14: cmov_l_rr(S4,S1,5); cmov_l_rr(S4,S1,10); break;
619 case 15: mov_l_rr(S4,S1); break;
620 }
621
622 if ((opcode & 0x38) == 0) {
623 mov_b_rr(reg,S4);
624 } else {
625 abort();
626 if (get_fp_ad (opcode, &ad) == 0) {
627 m68k_setpc (m68k_getpc () - 4);
628 fpuop_illg (opcode,extra);
629 } else
630 put_byte (ad, cc ? 0xff : 0x00);
631 }
632 }
633
634 void comp_ftrapcc_opp (uae_u32 opcode, uaecptr oldpc)
635 {
636 int cc;
637
638 FAIL(1);
639 return;
640 }
641
642 void comp_fbcc_opp (uae_u32 opcode)
643 {
644 uae_u32 start_68k_offset=m68k_pc_offset;
645 uae_u32 off;
646 uae_u32 v1;
647 uae_u32 v2;
648 uae_u32 nh;
649 int cc;
650
651 // comp_pc_p is expected to be bound to 32-bit addresses
652 assert((uintptr)comp_pc_p <= 0xffffffffUL);
653
654 if (opcode&0x20) { /* only cc from 00 to 1f are defined */
655 FAIL(1);
656 return;
657 }
658 if ((opcode&0x40)==0) {
659 off=(uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2);
660 }
661 else {
662 off=comp_get_ilong((m68k_pc_offset+=4)-4);
663 }
664 mov_l_ri(S1,(uintptr)
665 (comp_pc_p+off-(m68k_pc_offset-start_68k_offset)));
666 mov_l_ri(PC_P,(uintptr)comp_pc_p);
667
668 /* Now they are both constant. Might as well fold in m68k_pc_offset */
669 add_l_ri(S1,m68k_pc_offset);
670 add_l_ri(PC_P,m68k_pc_offset);
671 m68k_pc_offset=0;
672
673 /* according to fpp.c, the 0x10 bit is ignored
674 (it handles exception handling, which we don't
675 do, anyway ;-) */
676 cc=opcode&0x0f;
677 v1=get_const(PC_P);
678 v2=get_const(S1);
679 fflags_into_flags(S2);
680
681 switch(cc) {
682 case 0: break; /* jump never */
683 case 1:
684 mov_l_rr(S2,PC_P);
685 cmov_l_rr(PC_P,S1,4);
686 cmov_l_rr(PC_P,S2,10); break;
687 case 2: register_branch(v1,v2,7); break;
688 case 3: register_branch(v1,v2,3); break;
689 case 4:
690 mov_l_rr(S2,PC_P);
691 cmov_l_rr(PC_P,S1,2);
692 cmov_l_rr(PC_P,S2,10); break;
693 case 5:
694 mov_l_rr(S2,PC_P);
695 cmov_l_rr(PC_P,S1,6);
696 cmov_l_rr(PC_P,S2,10); break;
697 case 6: register_branch(v1,v2,5); break;
698 case 7: register_branch(v1,v2,11); break;
699 case 8: register_branch(v1,v2,10); break;
700 case 9: register_branch(v1,v2,4); break;
701 case 10:
702 cmov_l_rr(PC_P,S1,10);
703 cmov_l_rr(PC_P,S1,7); break;
704 case 11:
705 cmov_l_rr(PC_P,S1,4);
706 cmov_l_rr(PC_P,S1,3); break;
707 case 12: register_branch(v1,v2,2); break;
708 case 13: register_branch(v1,v2,6); break;
709 case 14:
710 cmov_l_rr(PC_P,S1,5);
711 cmov_l_rr(PC_P,S1,10); break;
712 case 15: mov_l_rr(PC_P,S1); break;
713 }
714 }
715
716 /* Floating point conditions
717 The "NotANumber" part could be problematic; Howver, when NaN is
718 encountered, the ftst instruction sets bot N and Z to 1 on the x87,
719 so quite often things just fall into place. This is probably not
720 accurate wrt the 68k FPU, but it is *as* accurate as this was before.
721 However, some more thought should go into fixing this stuff up so
722 it accurately emulates the 68k FPU.
723 >=<U
724 0000 0x00: 0 --- Never jump
725 0101 0x01: Z --- jump if zero (x86: 4)
726 1000 0x02: !(NotANumber || Z || N) --- Neither Z nor N set (x86: 7)
727 1101 0x03: Z || !(NotANumber || N); --- Z or !N (x86: 4 and 3)
728 0010 0x04: N && !(NotANumber || Z); --- N and !Z (x86: hard!)
729 0111 0x05: Z || (N && !NotANumber); --- Z or N (x86: 6)
730 1010 0x06: !(NotANumber || Z); --- not Z (x86: 5)
731 1110 0x07: !NotANumber; --- not NaN (x86: 11, not parity)
732 0001 0x08: NotANumber; --- NaN (x86: 10)
733 0101 0x09: NotANumber || Z; --- Z (x86: 4)
734 1001 0x0a: NotANumber || !(N || Z); --- NaN or neither N nor Z (x86: 10 and 7)
735 1101 0x0b: NotANumber || Z || !N; --- Z or !N (x86: 4 and 3)
736 0011 0x0c: NotANumber || (N && !Z); --- N (x86: 2)
737 0111 0x0d: NotANumber || Z || N; --- Z or N (x86: 6)
738 1010 0x0e: !Z; --- not Z (x86: 5)
739 1111 0x0f: 1; --- always
740
741 This is not how the 68k handles things, though --- it sets Z to 0 and N
742 to the NaN's sign.... ('o' and 'i' denote differences from the above
743 table)
744
745 >=<U
746 0000 0x00: 0 --- Never jump
747 010o 0x01: Z --- jump if zero (x86: 4, not 10)
748 1000 0x02: !(NotANumber || Z || N) --- Neither Z nor N set (x86: 7)
749 110o 0x03: Z || !(NotANumber || N); --- Z or !N (x86: 3)
750 0010 0x04: N && !(NotANumber || Z); --- N and !Z (x86: 2, not 10)
751 011o 0x05: Z || (N && !NotANumber); --- Z or N (x86: 6, not 10)
752 1010 0x06: !(NotANumber || Z); --- not Z (x86: 5)
753 1110 0x07: !NotANumber; --- not NaN (x86: 11, not parity)
754 0001 0x08: NotANumber; --- NaN (x86: 10)
755 0101 0x09: NotANumber || Z; --- Z (x86: 4)
756 1001 0x0a: NotANumber || !(N || Z); --- NaN or neither N nor Z (x86: 10 and 7)
757 1101 0x0b: NotANumber || Z || !N; --- Z or !N (x86: 4 and 3)
758 0011 0x0c: NotANumber || (N && !Z); --- N (x86: 2)
759 0111 0x0d: NotANumber || Z || N; --- Z or N (x86: 6)
760 101i 0x0e: !Z; --- not Z (x86: 5 and 10)
761 1111 0x0f: 1; --- always
762
763 Of course, this *still* doesn't mean that the x86 and 68k conditions are
764 equivalent --- the handling of infinities is different, for one thing.
765 On the 68k, +infinity minus +infinity is NotANumber (as it should be). On
766 the x86, it is +infinity, and some exception is raised (which I suspect
767 is promptly ignored) STUPID!
768 The more I learn about their CPUs, the more I detest Intel....
769
770 You can see this in action if you have "Benoit" (see Aminet) and
771 set the exponent to 16. Wait for a long time, and marvel at the extra black
772 areas outside the center one. That's where Benoit expects NaN, and the x86
773 gives +infinity. [Ooops --- that must have been some kind of bug in my code.
774 it no longer happens, and the resulting graphic looks much better, too]
775
776 x86 conditions
777 0011 : 2
778 1100 : 3
779 0101 : 4
780 1010 : 5
781 0111 : 6
782 1000 : 7
783 0001 : 10
784 1110 : 11
785 */
786 void comp_fsave_opp (uae_u32 opcode)
787 {
788 uae_u32 ad;
789 int incr = (opcode & 0x38) == 0x20 ? -1 : 1;
790 int i;
791
792 FAIL(1);
793 return;
794
795 #if DEBUG_FPP
796 printf ("fsave_opp at %08lx\n", m68k_getpc ());
797 fflush (stdout);
798 #endif
799 if (get_fp_ad (opcode, &ad) == 0) {
800 m68k_setpc (m68k_getpc () - 2);
801 fpuop_illg (opcode,UNKNOWN_EXTRA);
802 return;
803 }
804
805 if (CPUType == 4) {
806 /* 4 byte 68040 IDLE frame. */
807 if (incr < 0) {
808 ad -= 4;
809 put_long (ad, 0x41000000);
810 } else {
811 put_long (ad, 0x41000000);
812 ad += 4;
813 }
814 } else {
815 if (incr < 0) {
816 ad -= 4;
817 put_long (ad, 0x70000000);
818 for (i = 0; i < 5; i++) {
819 ad -= 4;
820 put_long (ad, 0x00000000);
821 }
822 ad -= 4;
823 put_long (ad, 0x1f180000);
824 } else {
825 put_long (ad, 0x1f180000);
826 ad += 4;
827 for (i = 0; i < 5; i++) {
828 put_long (ad, 0x00000000);
829 ad += 4;
830 }
831 put_long (ad, 0x70000000);
832 ad += 4;
833 }
834 }
835 if ((opcode & 0x38) == 0x18)
836 m68k_areg (regs, opcode & 7) = ad;
837 if ((opcode & 0x38) == 0x20)
838 m68k_areg (regs, opcode & 7) = ad;
839 }
840
841 void comp_frestore_opp (uae_u32 opcode)
842 {
843 uae_u32 ad;
844 uae_u32 d;
845 int incr = (opcode & 0x38) == 0x20 ? -1 : 1;
846
847 FAIL(1);
848 return;
849
850 #if DEBUG_FPP
851 printf ("frestore_opp at %08lx\n", m68k_getpc ());
852 fflush (stdout);
853 #endif
854 if (get_fp_ad (opcode, &ad) == 0) {
855 m68k_setpc (m68k_getpc () - 2);
856 fpuop_illg (opcode,UNKNOWN_EXTRA);
857 return;
858 }
859 if (CPUType == 4) {
860 /* 68040 */
861 if (incr < 0) {
862 /* @@@ This may be wrong. */
863 ad -= 4;
864 d = get_long (ad);
865 if ((d & 0xff000000) != 0) { /* Not a NULL frame? */
866 if ((d & 0x00ff0000) == 0) { /* IDLE */
867 } else if ((d & 0x00ff0000) == 0x00300000) { /* UNIMP */
868 ad -= 44;
869 } else if ((d & 0x00ff0000) == 0x00600000) { /* BUSY */
870 ad -= 92;
871 }
872 }
873 } else {
874 d = get_long (ad);
875 ad += 4;
876 if ((d & 0xff000000) != 0) { /* Not a NULL frame? */
877 if ((d & 0x00ff0000) == 0) { /* IDLE */
878 } else if ((d & 0x00ff0000) == 0x00300000) { /* UNIMP */
879 ad += 44;
880 } else if ((d & 0x00ff0000) == 0x00600000) { /* BUSY */
881 ad += 92;
882 }
883 }
884 }
885 } else {
886 if (incr < 0) {
887 ad -= 4;
888 d = get_long (ad);
889 if ((d & 0xff000000) != 0) {
890 if ((d & 0x00ff0000) == 0x00180000)
891 ad -= 6 * 4;
892 else if ((d & 0x00ff0000) == 0x00380000)
893 ad -= 14 * 4;
894 else if ((d & 0x00ff0000) == 0x00b40000)
895 ad -= 45 * 4;
896 }
897 } else {
898 d = get_long (ad);
899 ad += 4;
900 if ((d & 0xff000000) != 0) {
901 if ((d & 0x00ff0000) == 0x00180000)
902 ad += 6 * 4;
903 else if ((d & 0x00ff0000) == 0x00380000)
904 ad += 14 * 4;
905 else if ((d & 0x00ff0000) == 0x00b40000)
906 ad += 45 * 4;
907 }
908 }
909 }
910 if ((opcode & 0x38) == 0x18)
911 m68k_areg (regs, opcode & 7) = ad;
912 if ((opcode & 0x38) == 0x20)
913 m68k_areg (regs, opcode & 7) = ad;
914 }
915
916 #if USE_LONG_DOUBLE
917 static const fpu_register const_e = 2.7182818284590452353602874713526625L;
918 static const fpu_register const_log10_e = 0.4342944819032518276511289189166051L;
919 static const fpu_register const_loge_10 = 2.3025850929940456840179914546843642L;
920 #else
921 static const fpu_register const_e = 2.7182818284590452354;
922 static const fpu_register const_log10_e = 0.43429448190325182765;
923 static const fpu_register const_loge_10 = 2.30258509299404568402;
924 #endif
925
926 static const fpu_register power10[] = {
927 1e0, 1e1, 1e2, 1e4, 1e8, 1e16, 1e32, 1e64, 1e128, 1e256
928 #if USE_LONG_DOUBLE
929 , 1e512, 1e1024, 1e2048, 1e4096
930 #endif
931 };
932
933 /* 128 words, indexed through the low byte of the 68k fpu control word */
934 static uae_u16 x86_fpucw[]={
935 0x137f, 0x137f, 0x137f, 0x137f, 0x137f, 0x137f, 0x137f, 0x137f, /* p0r0 */
936 0x1f7f, 0x1f7f, 0x1f7f, 0x1f7f, 0x1f7f, 0x1f7f, 0x1f7f, 0x1f7f, /* p0r1 */
937 0x177f, 0x177f, 0x177f, 0x177f, 0x177f, 0x177f, 0x177f, 0x177f, /* p0r2 */
938 0x1b7f, 0x1b7f, 0x1b7f, 0x1b7f, 0x1b7f, 0x1b7f, 0x1b7f, 0x1b7f, /* p0r3 */
939
940 0x107f, 0x107f, 0x107f, 0x107f, 0x107f, 0x107f, 0x107f, 0x107f, /* p1r0 */
941 0x1c7f, 0x1c7f, 0x1c7f, 0x1c7f, 0x1c7f, 0x1c7f, 0x1c7f, 0x1c7f, /* p1r1 */
942 0x147f, 0x147f, 0x147f, 0x147f, 0x147f, 0x147f, 0x147f, 0x147f, /* p1r2 */
943 0x187f, 0x187f, 0x187f, 0x187f, 0x187f, 0x187f, 0x187f, 0x187f, /* p1r3 */
944
945 0x127f, 0x127f, 0x127f, 0x127f, 0x127f, 0x127f, 0x127f, 0x127f, /* p2r0 */
946 0x1e7f, 0x1e7f, 0x1e7f, 0x1e7f, 0x1e7f, 0x1e7f, 0x1e7f, 0x1e7f, /* p2r1 */
947 0x167f, 0x167f, 0x167f, 0x167f, 0x167f, 0x167f, 0x167f, 0x167f, /* p2r2 */
948 0x1a7f, 0x1a7f, 0x1a7f, 0x1a7f, 0x1a7f, 0x1a7f, 0x1a7f, 0x1a7f, /* p2r3 */
949
950 0x137f, 0x137f, 0x137f, 0x137f, 0x137f, 0x137f, 0x137f, 0x137f, /* p3r0 */
951 0x1f7f, 0x1f7f, 0x1f7f, 0x1f7f, 0x1f7f, 0x1f7f, 0x1f7f, 0x1f7f, /* p3r1 */
952 0x177f, 0x177f, 0x177f, 0x177f, 0x177f, 0x177f, 0x177f, 0x177f, /* p3r2 */
953 0x1b7f, 0x1b7f, 0x1b7f, 0x1b7f, 0x1b7f, 0x1b7f, 0x1b7f, 0x1b7f /* p3r3 */
954 };
955
956 void comp_fpp_opp (uae_u32 opcode, uae_u16 extra)
957 {
958 int reg;
959 int src;
960
961 switch ((extra >> 13) & 0x7) {
962 case 3: /* 2nd most common */
963 if (put_fp_value ((extra >> 7)&7 , opcode, extra) < 0) {
964 FAIL(1);
965 return;
966
967 }
968 return;
969 case 6:
970 case 7:
971 {
972 uae_u32 ad, list = 0;
973 int incr = 0;
974 if (extra & 0x2000) {
975 uae_u32 ad;
976
977 /* FMOVEM FPP->memory */
978 switch ((extra >> 11) & 3) { /* Get out early if failure */
979 case 0:
980 case 2:
981 break;
982 case 1:
983 case 3:
984 default:
985 FAIL(1); return;
986 }
987 ad=get_fp_ad (opcode, &ad);
988 if (ad<0) {
989 abort();
990 m68k_setpc (m68k_getpc () - 4);
991 fpuop_illg (opcode,extra);
992 return;
993 }
994 switch ((extra >> 11) & 3) {
995 case 0: /* static pred */
996 list = extra & 0xff;
997 incr = -1;
998 break;
999 case 2: /* static postinc */
1000 list = extra & 0xff;
1001 incr = 1;
1002 break;
1003 case 1: /* dynamic pred */
1004 case 3: /* dynamic postinc */
1005 abort();
1006 }
1007 if (incr < 0) { /* Predecrement */
1008 for (reg = 7; reg >= 0; reg--) {
1009 if (list & 0x80) {
1010 fmov_ext_mr((uintptr)temp_fp,reg);
1011 delay;
1012 sub_l_ri(ad,4);
1013 mov_l_rm(S2,(uintptr)temp_fp);
1014 writelong_clobber(ad,S2,S3);
1015 sub_l_ri(ad,4);
1016 mov_l_rm(S2,(uintptr)temp_fp+4);
1017 writelong_clobber(ad,S2,S3);
1018 sub_l_ri(ad,4);
1019 mov_w_rm(S2,(uintptr)temp_fp+8);
1020 writeword_clobber(ad,S2,S3);
1021 }
1022 list <<= 1;
1023 }
1024 }
1025 else { /* Postincrement */
1026 for (reg = 0; reg < 8; reg++) {
1027 if (list & 0x80) {
1028 fmov_ext_mr((uintptr)temp_fp,reg);
1029 delay;
1030 mov_w_rm(S2,(uintptr)temp_fp+8);
1031 writeword_clobber(ad,S2,S3);
1032 add_l_ri(ad,4);
1033 mov_l_rm(S2,(uintptr)temp_fp+4);
1034 writelong_clobber(ad,S2,S3);
1035 add_l_ri(ad,4);
1036 mov_l_rm(S2,(uintptr)temp_fp);
1037 writelong_clobber(ad,S2,S3);
1038 add_l_ri(ad,4);
1039 }
1040 list <<= 1;
1041 }
1042 }
1043 if ((opcode & 0x38) == 0x18)
1044 mov_l_rr((opcode & 7)+8,ad);
1045 if ((opcode & 0x38) == 0x20)
1046 mov_l_rr((opcode & 7)+8,ad);
1047 } else {
1048 /* FMOVEM memory->FPP */
1049
1050 uae_u32 ad;
1051 switch ((extra >> 11) & 3) { /* Get out early if failure */
1052 case 0:
1053 case 2:
1054 break;
1055 case 1:
1056 case 3:
1057 default:
1058 FAIL(1); return;
1059 }
1060 ad=get_fp_ad (opcode, &ad);
1061 if (ad<0) {
1062 abort();
1063 m68k_setpc (m68k_getpc () - 4);
1064 write_log("no ad\n");
1065 fpuop_illg (opcode,extra);
1066 return;
1067 }
1068 switch ((extra >> 11) & 3) {
1069 case 0: /* static pred */
1070 list = extra & 0xff;
1071 incr = -1;
1072 break;
1073 case 2: /* static postinc */
1074 list = extra & 0xff;
1075 incr = 1;
1076 break;
1077 case 1: /* dynamic pred */
1078 case 3: /* dynamic postinc */
1079 abort();
1080 }
1081
1082 if (incr < 0) {
1083 // not reached
1084 for (reg = 7; reg >= 0; reg--) {
1085 uae_u32 wrd1, wrd2, wrd3;
1086 if (list & 0x80) {
1087 sub_l_ri(ad,4);
1088 readlong(ad,S2,S3);
1089 mov_l_mr((uintptr)(temp_fp),S2);
1090 sub_l_ri(ad,4);
1091 readlong(ad,S2,S3);
1092 mov_l_mr((uintptr)(temp_fp)+4,S2);
1093 sub_l_ri(ad,4);
1094 readword(ad,S2,S3);
1095 mov_w_mr(((uintptr)temp_fp)+8,S2);
1096 delay2;
1097 fmov_ext_rm(reg,(uintptr)(temp_fp));
1098 }
1099 list <<= 1;
1100 }
1101 }
1102 else {
1103 for (reg = 0; reg < 8; reg++) {
1104 uae_u32 wrd1, wrd2, wrd3;
1105 if (list & 0x80) {
1106 readword(ad,S2,S3);
1107 mov_w_mr(((uintptr)temp_fp)+8,S2);
1108 add_l_ri(ad,4);
1109 readlong(ad,S2,S3);
1110 mov_l_mr((uintptr)(temp_fp)+4,S2);
1111 add_l_ri(ad,4);
1112 readlong(ad,S2,S3);
1113 mov_l_mr((uintptr)(temp_fp),S2);
1114 add_l_ri(ad,4);
1115 delay2;
1116 fmov_ext_rm(reg,(uintptr)(temp_fp));
1117 }
1118 list <<= 1;
1119 }
1120 }
1121 if ((opcode & 0x38) == 0x18)
1122 mov_l_rr((opcode & 7)+8,ad);
1123 if ((opcode & 0x38) == 0x20)
1124 mov_l_rr((opcode & 7)+8,ad);
1125 }
1126 }
1127 return;
1128
1129 case 4:
1130 case 5: /* rare */
1131 if ((opcode & 0x30) == 0) {
1132 if (extra & 0x2000) {
1133 if (extra & 0x1000) {
1134 #if HANDLE_FPCR
1135 mov_l_rm(opcode & 15, (uintptr)&fpu.fpcr.rounding_mode);
1136 or_l_rm(opcode & 15, (uintptr)&fpu.fpcr.rounding_precision);
1137 #else
1138 FAIL(1);
1139 return;
1140 #endif
1141 }
1142 if (extra & 0x0800) {
1143 FAIL(1);
1144 return;
1145 }
1146 if (extra & 0x0400) {
1147 mov_l_rm(opcode & 15,(uintptr)&fpu.instruction_address);
1148 return;
1149 }
1150 } else {
1151 // gb-- moved here so that we may FAIL() without generating any code
1152 if (extra & 0x0800) {
1153 // set_fpsr(m68k_dreg (regs, opcode & 15));
1154 FAIL(1);
1155 return;
1156 }
1157 if (extra & 0x1000) {
1158 #if HANDLE_FPCR
1159 #if defined(FPU_USE_X86_ROUNDING_MODE) && defined(FPU_USE_X86_ROUNDING_PRECISION)
1160 FAIL(1);
1161 return;
1162 #endif
1163 mov_l_rr(S1,opcode & 15);
1164 mov_l_rr(S2,opcode & 15);
1165 and_l_ri(S1,FPCR_ROUNDING_PRECISION);
1166 and_l_ri(S2,FPCR_ROUNDING_MODE);
1167 mov_l_mr((uintptr)&fpu.fpcr.rounding_precision,S1);
1168 mov_l_mr((uintptr)&fpu.fpcr.rounding_mode,S2);
1169 #else
1170 FAIL(1);
1171 return;
1172 #endif
1173 // return; gb-- FMOVEM could also operate on fpiar
1174 }
1175 if (extra & 0x0400) {
1176 mov_l_mr((uintptr)&fpu.instruction_address,opcode & 15);
1177 // return; gb-- we have to process all FMOVEM bits before returning
1178 }
1179 return;
1180 }
1181 } else if ((opcode & 0x3f) == 0x3c) {
1182 if ((extra & 0x2000) == 0) {
1183 // gb-- moved here so that we may FAIL() without generating any code
1184 if (extra & 0x0800) {
1185 FAIL(1);
1186 return;
1187 }
1188 if (extra & 0x1000) {
1189 uae_u32 val=comp_get_ilong((m68k_pc_offset+=4)-4);
1190 #if HANDLE_FPCR
1191 #if defined(FPU_USE_X86_ROUNDING_MODE) && defined(FPU_USE_X86_ROUNDING_PRECISION)
1192 FAIL(1);
1193 return;
1194 #endif
1195 // mov_l_mi((uintptr)&regs.fpcr,val);
1196 mov_l_ri(S1,val);
1197 mov_l_ri(S2,val);
1198 and_l_ri(S1,FPCR_ROUNDING_PRECISION);
1199 and_l_ri(S2,FPCR_ROUNDING_MODE);
1200 mov_l_mr((uintptr)&fpu.fpcr.rounding_precision,S1);
1201 mov_l_mr((uintptr)&fpu.fpcr.rounding_mode,S2);
1202 #else
1203 FAIL(1);
1204 return;
1205 #endif
1206 // return; gb-- FMOVEM could also operate on fpiar
1207 }
1208 if (extra & 0x0400) {
1209 uae_u32 val=comp_get_ilong((m68k_pc_offset+=4)-4);
1210 mov_l_mi((uintptr)&fpu.instruction_address,val);
1211 // return; gb-- we have to process all FMOVEM bits before returning
1212 }
1213 return;
1214 }
1215 FAIL(1);
1216 return;
1217 } else if (extra & 0x2000) {
1218 FAIL(1);
1219 return;
1220 } else {
1221 FAIL(1);
1222 return;
1223 }
1224 FAIL(1);
1225 return;
1226
1227 case 0:
1228 case 2: /* Extremely common */
1229 reg = (extra >> 7) & 7;
1230 if ((extra & 0xfc00) == 0x5c00) {
1231 switch (extra & 0x7f) {
1232 case 0x00:
1233 fmov_pi(reg);
1234 break;
1235 case 0x0b:
1236 fmov_log10_2(reg);
1237 break;
1238 case 0x0c:
1239 #if USE_LONG_DOUBLE
1240 fmov_ext_rm(reg,(uintptr)&const_e);
1241 #else
1242 fmov_rm(reg,(uintptr)&const_e);
1243 #endif
1244 break;
1245 case 0x0d:
1246 fmov_log2_e(reg);
1247 break;
1248 case 0x0e:
1249 #if USE_LONG_DOUBLE
1250 fmov_ext_rm(reg,(uintptr)&const_log10_e);
1251 #else
1252 fmov_rm(reg,(uintptr)&const_log10_e);
1253 #endif
1254 break;
1255 case 0x0f:
1256 fmov_0(reg);
1257 break;
1258 case 0x30:
1259 fmov_loge_2(reg);
1260 break;
1261 case 0x31:
1262 #if USE_LONG_DOUBLE
1263 fmov_ext_rm(reg,(uintptr)&const_loge_10);
1264 #else
1265 fmov_rm(reg,(uintptr)&const_loge_10);
1266 #endif
1267 break;
1268 case 0x32:
1269 fmov_1(reg);
1270 break;
1271 case 0x33:
1272 case 0x34:
1273 case 0x35:
1274 case 0x36:
1275 case 0x37:
1276 case 0x38:
1277 case 0x39:
1278 case 0x3a:
1279 case 0x3b:
1280 #if USE_LONG_DOUBLE
1281 case 0x3c:
1282 case 0x3d:
1283 case 0x3e:
1284 case 0x3f:
1285 fmov_ext_rm(reg,(uintptr)(power10+(extra & 0x7f)-0x32));
1286 #else
1287 fmov_rm(reg,(uintptr)(power10+(extra & 0x7f)-0x32));
1288 #endif
1289 break;
1290 default:
1291 /* This is not valid, so we fail */
1292 FAIL(1);
1293 return;
1294 }
1295 return;
1296 }
1297
1298 switch (extra & 0x7f) {
1299 case 0x00: /* FMOVE */
1300 case 0x40: /* Explicit rounding. This is just a quick fix. Same
1301 * for all other cases that have three choices */
1302 case 0x44:
1303 dont_care_fflags();
1304 src=get_fp_value (opcode, extra);
1305 if (src < 0) {
1306 FAIL(1); /* Illegal instruction */
1307 return;
1308 }
1309 fmov_rr(reg,src);
1310 MAKE_FPSR (src);
1311 break;
1312 case 0x01: /* FINT */
1313 FAIL(1);
1314 return;
1315 dont_care_fflags();
1316 case 0x02: /* FSINH */
1317 FAIL(1);
1318 return;
1319 dont_care_fflags();
1320 break;
1321 case 0x03: /* FINTRZ */
1322 #if USE_X86_FPUCW
1323 /* If we have control over the CW, we can do this */
1324 dont_care_fflags();
1325 src=get_fp_value (opcode, extra);
1326 if (src < 0) {
1327 FAIL(1); /* Illegal instruction */
1328 return;
1329 }
1330 mov_l_ri(S1,16); /* Switch to "round to zero" mode */
1331 fldcw_m_indexed(S1,(uae_u32)x86_fpucw);
1332
1333 frndint_rr(reg,src);
1334
1335 /* restore control word */
1336 mov_l_rm(S1,(uintptr)&regs.fpcr);
1337 and_l_ri(S1,0x000000f0);
1338 fldcw_m_indexed(S1,(uintptr)x86_fpucw);
1339
1340 MAKE_FPSR (reg);
1341 break;
1342 #endif
1343 FAIL(1);
1344 return;
1345 break;
1346 case 0x04: /* FSQRT */
1347 case 0x41:
1348 case 0x45:
1349 dont_care_fflags();
1350 src=get_fp_value (opcode, extra);
1351 if (src < 0) {
1352 FAIL(1); /* Illegal instruction */
1353 return;
1354 }
1355 fsqrt_rr(reg,src);
1356 MAKE_FPSR (reg);
1357 break;
1358 case 0x06: /* FLOGNP1 */
1359 FAIL(1);
1360 return;
1361 dont_care_fflags();
1362 break;
1363 case 0x08: /* FETOXM1 */
1364 FAIL(1);
1365 return;
1366 dont_care_fflags();
1367 break;
1368 case 0x09: /* FTANH */
1369 FAIL(1);
1370 return;
1371 dont_care_fflags();
1372 break;
1373 case 0x0a: /* FATAN */
1374 FAIL(1);
1375 return;
1376 dont_care_fflags();
1377 break;
1378 case 0x0c: /* FASIN */
1379 FAIL(1);
1380 return;
1381 dont_care_fflags();
1382 break;
1383 case 0x0d: /* FATANH */
1384 FAIL(1);
1385 return;
1386 dont_care_fflags();
1387 break;
1388 case 0x0e: /* FSIN */
1389 dont_care_fflags();
1390 src=get_fp_value (opcode, extra);
1391 if (src < 0) {
1392 FAIL(1); /* Illegal instruction */
1393 return;
1394 }
1395 fsin_rr(reg,src);
1396 MAKE_FPSR (reg);
1397 break;
1398 case 0x0f: /* FTAN */
1399 FAIL(1);
1400 return;
1401 dont_care_fflags();
1402 break;
1403 case 0x10: /* FETOX */
1404 dont_care_fflags();
1405 src=get_fp_value (opcode, extra);
1406 if (src < 0) {
1407 FAIL(1); /* Illegal instruction */
1408 return;
1409 }
1410 fetox_rr(reg,src);
1411 MAKE_FPSR (reg);
1412 break;
1413 case 0x11: /* FTWOTOX */
1414 dont_care_fflags();
1415 src=get_fp_value (opcode, extra);
1416 if (src < 0) {
1417 FAIL(1); /* Illegal instruction */
1418 return;
1419 }
1420 ftwotox_rr(reg,src);
1421 MAKE_FPSR (reg);
1422 break;
1423 case 0x12: /* FTENTOX */
1424 FAIL(1);
1425 return;
1426 dont_care_fflags();
1427 break;
1428 case 0x14: /* FLOGN */
1429 FAIL(1);
1430 return;
1431 dont_care_fflags();
1432 break;
1433 case 0x15: /* FLOG10 */
1434 FAIL(1);
1435 return;
1436 dont_care_fflags();
1437 break;
1438 case 0x16: /* FLOG2 */
1439 dont_care_fflags();
1440 src=get_fp_value (opcode, extra);
1441 if (src < 0) {
1442 FAIL(1); /* Illegal instruction */
1443 return;
1444 }
1445 flog2_rr(reg,src);
1446 MAKE_FPSR (reg);
1447 break;
1448 case 0x18: /* FABS */
1449 case 0x58:
1450 case 0x5c:
1451 dont_care_fflags();
1452 src=get_fp_value (opcode, extra);
1453 if (src < 0) {
1454 FAIL(1); /* Illegal instruction */
1455 return;
1456 }
1457 fabs_rr(reg,src);
1458 MAKE_FPSR (reg);
1459 break;
1460 case 0x19: /* FCOSH */
1461 FAIL(1);
1462 return;
1463 dont_care_fflags();
1464 break;
1465 case 0x1a: /* FNEG */
1466 case 0x5a:
1467 case 0x5e:
1468 dont_care_fflags();
1469 src=get_fp_value (opcode, extra);
1470 if (src < 0) {
1471 FAIL(1); /* Illegal instruction */
1472 return;
1473 }
1474 fneg_rr(reg,src);
1475 MAKE_FPSR (reg);
1476 break;
1477 case 0x1c: /* FACOS */
1478 FAIL(1);
1479 return;
1480 dont_care_fflags();
1481 break;
1482 case 0x1d: /* FCOS */
1483 dont_care_fflags();
1484 src=get_fp_value (opcode, extra);
1485 if (src < 0) {
1486 FAIL(1); /* Illegal instruction */
1487 return;
1488 }
1489 fcos_rr(reg,src);
1490 MAKE_FPSR (reg);
1491 break;
1492 case 0x1e: /* FGETEXP */
1493 FAIL(1);
1494 return;
1495 dont_care_fflags();
1496 break;
1497 case 0x1f: /* FGETMAN */
1498 FAIL(1);
1499 return;
1500 dont_care_fflags();
1501 break;
1502 case 0x20: /* FDIV */
1503 case 0x60:
1504 case 0x64:
1505 dont_care_fflags();
1506 src=get_fp_value (opcode, extra);
1507 if (src < 0) {
1508 FAIL(1); /* Illegal instruction */
1509 return;
1510 }
1511 fdiv_rr(reg,src);
1512 MAKE_FPSR (reg);
1513 break;
1514 case 0x21: /* FMOD */
1515 dont_care_fflags();
1516 src=get_fp_value (opcode, extra);
1517 if (src < 0) {
1518 FAIL(1); /* Illegal instruction */
1519 return;
1520 }
1521 frem_rr(reg,src);
1522 MAKE_FPSR (reg);
1523 break;
1524 case 0x22: /* FADD */
1525 case 0x62:
1526 case 0x66:
1527 dont_care_fflags();
1528 src=get_fp_value (opcode, extra);
1529 if (src < 0) {
1530 FAIL(1); /* Illegal instruction */
1531 return;
1532 }
1533 fadd_rr(reg,src);
1534 MAKE_FPSR (reg);
1535 break;
1536 case 0x23: /* FMUL */
1537 case 0x63:
1538 case 0x67:
1539 dont_care_fflags();
1540 src=get_fp_value (opcode, extra);
1541 if (src < 0) {
1542 FAIL(1); /* Illegal instruction */
1543 return;
1544 }
1545 fmul_rr(reg,src);
1546 MAKE_FPSR (reg);
1547 break;
1548 case 0x24: /* FSGLDIV */
1549 dont_care_fflags();
1550 src=get_fp_value (opcode, extra);
1551 if (src < 0) {
1552 FAIL(1); /* Illegal instruction */
1553 return;
1554 }
1555 fdiv_rr(reg,src);
1556 MAKE_FPSR (reg);
1557 break;
1558 case 0x25: /* FREM */
1559 // gb-- disabled because the quotient byte must be computed
1560 // otherwise, free rotation in ClarisWorks doesn't work.
1561 FAIL(1);
1562 return;
1563 dont_care_fflags();
1564 src=get_fp_value (opcode, extra);
1565 if (src < 0) {
1566 FAIL(1); /* Illegal instruction */
1567 return;
1568 }
1569 frem1_rr(reg,src);
1570 MAKE_FPSR (reg);
1571 break;
1572 case 0x26: /* FSCALE */
1573 dont_care_fflags();
1574 FAIL(1);
1575 return;
1576 break;
1577 case 0x27: /* FSGLMUL */
1578 dont_care_fflags();
1579 src=get_fp_value (opcode, extra);
1580 if (src < 0) {
1581 FAIL(1); /* Illegal instruction */
1582 return;
1583 }
1584 fmul_rr(reg,src);
1585 MAKE_FPSR (reg);
1586 break;
1587 case 0x28: /* FSUB */
1588 case 0x68:
1589 case 0x6c:
1590 dont_care_fflags();
1591 src=get_fp_value (opcode, extra);
1592 if (src < 0) {
1593 FAIL(1); /* Illegal instruction */
1594 return;
1595 }
1596 fsub_rr(reg,src);
1597 MAKE_FPSR (reg);
1598 break;
1599 case 0x30: /* FSINCOS */
1600 case 0x31:
1601 case 0x32:
1602 case 0x33:
1603 case 0x34:
1604 case 0x35:
1605 case 0x36:
1606 case 0x37:
1607 FAIL(1);
1608 return;
1609 dont_care_fflags();
1610 break;
1611 case 0x38: /* FCMP */
1612 src=get_fp_value (opcode, extra);
1613 if (src < 0) {
1614 FAIL(1); /* Illegal instruction */
1615 return;
1616 }
1617 fmov_rr(FP_RESULT,reg);
1618 fsub_rr(FP_RESULT,src); /* Right way? */
1619 break;
1620 case 0x3a: /* FTST */
1621 src=get_fp_value (opcode, extra);
1622 if (src < 0) {
1623 FAIL(1); /* Illegal instruction */
1624 return;
1625 }
1626 fmov_rr(FP_RESULT,src);
1627 break;
1628 default:
1629 FAIL(1);
1630 return;
1631 break;
1632 }
1633 return;
1634 }
1635 m68k_setpc (m68k_getpc () - 4);
1636 fpuop_illg (opcode,extra);
1637 }