|
|
1.1 root 1: /*
2: * UAE - The Un*x Amiga Emulator
3: *
4: * MC68881 emulation
5: *
6: * Copyright 1996 Herman ten Brugge
7: * Adapted for JIT compilation (c) Bernd Meyer, 2000
8: * Modified 2005 Peter Keunecke
9: */
10:
11: #include <math.h>
12:
13: #include "sysconfig.h"
14: #include "sysdeps.h"
15:
16: #include "options.h"
17: #include "memory.h"
18: #include "custom.h"
19: #include "newcpu.h"
20: #include "ersatz.h"
21: #include "md-fpp.h"
22: #include "compemu.h"
23:
24: #if defined(JIT)
25: uae_u32 temp_fp[] = {0,0,0}; /* To convert between FP and <EA> */
26:
27: /* 128 words, indexed through the low byte of the 68k fpu control word */
28: static const uae_u16 x86_fpucw[]={
29: 0x137f, 0x137f, 0x137f, 0x137f, 0x137f, 0x137f, 0x137f, 0x137f, /* E-RN */
30: 0x1f7f, 0x1f7f, 0x1f7f, 0x1f7f, 0x1f7f, 0x1f7f, 0x1f7f, 0x1f7f, /* E-RZ */
31: 0x177f, 0x177f, 0x177f, 0x177f, 0x177f, 0x177f, 0x177f, 0x177f, /* E-RD */
32: 0x1b7f, 0x1b7f, 0x1b7f, 0x1b7f, 0x1b7f, 0x1b7f, 0x1b7f, 0x1b7f, /* E-RU */
33:
34: 0x107f, 0x107f, 0x107f, 0x107f, 0x107f, 0x107f, 0x107f, 0x107f, /* S-RN */
35: 0x1c7f, 0x1c7f, 0x1c7f, 0x1c7f, 0x1c7f, 0x1c7f, 0x1c7f, 0x1c7f, /* S-RZ */
36: 0x147f, 0x147f, 0x147f, 0x147f, 0x147f, 0x147f, 0x147f, 0x147f, /* S-RD */
37: 0x187f, 0x187f, 0x187f, 0x187f, 0x187f, 0x187f, 0x187f, 0x187f, /* S-RU */
38:
39: 0x127f, 0x127f, 0x127f, 0x127f, 0x127f, 0x127f, 0x127f, 0x127f, /* D-RN */
40: 0x1e7f, 0x1e7f, 0x1e7f, 0x1e7f, 0x1e7f, 0x1e7f, 0x1e7f, 0x1e7f, /* D-RZ */
41: 0x167f, 0x167f, 0x167f, 0x167f, 0x167f, 0x167f, 0x167f, 0x167f, /* D-RD */
42: 0x1a7f, 0x1a7f, 0x1a7f, 0x1a7f, 0x1a7f, 0x1a7f, 0x1a7f, 0x1a7f, /* D-RU */
43:
44: 0x137f, 0x137f, 0x137f, 0x137f, 0x137f, 0x137f, 0x137f, 0x137f, /* ?-RN */
45: 0x1f7f, 0x1f7f, 0x1f7f, 0x1f7f, 0x1f7f, 0x1f7f, 0x1f7f, 0x1f7f, /* ?-RZ */
46: 0x177f, 0x177f, 0x177f, 0x177f, 0x177f, 0x177f, 0x177f, 0x177f, /* ?-RD */
47: 0x1b7f, 0x1b7f, 0x1b7f, 0x1b7f, 0x1b7f, 0x1b7f, 0x1b7f, 0x1b7f /* ?-RU */
48: };
49: static const int sz1[8] = { 4, 4, 12, 12, 2, 8, 1, 0 };
50: static const int sz2[8] = { 4, 4, 12, 12, 2, 8, 2, 0 };
51:
52: static struct {
53: double b[2];
54: double w[2];
55: double l[2];
56: } clamp_bounds = {
57: { -128.0, 127.0 },
58: { -32768.0, 32767.0 },
59: { -2147483648.0, 2147483647.0 }
60: };
61:
62: /* return the required floating point precision or -1 for failure, 0=E, 1=S, 2=D */
63: STATIC_INLINE int comp_fp_get (uae_u32 opcode, uae_u16 extra, int treg)
64: {
65: int reg = opcode & 7;
66: int mode = (opcode >> 3) & 7;
67: int size = (extra >> 10) & 7;
68:
69: if (size == 3 || size == 7) /* 3 = packed decimal, 7 is not defined */
70: return -1;
71: switch (mode) {
72: case 0: /* Dn */
73: switch (size) {
74: case 0: /* Long */
75: mov_l_mr((uae_u32)temp_fp,reg);
76: fmovi_rm(treg,(uae_u32)temp_fp);
77: return 2;
78: case 1: /* Single */
79: mov_l_mr((uae_u32)temp_fp,reg);
80: fmovs_rm(treg,(uae_u32)temp_fp);
81: return 1;
82: case 4: /* Word */
83: sign_extend_16_rr(S1,reg);
84: mov_l_mr((uae_u32)temp_fp,S1);
85: fmovi_rm(treg,(uae_u32)temp_fp);
86: return 1;
87: case 6: /* Byte */
88: sign_extend_8_rr(S1,reg);
89: mov_l_mr((uae_u32)temp_fp,S1);
90: fmovi_rm(treg,(uae_u32)temp_fp);
91: return 1;
92: default:
93: return -1;
94: }
95: case 1: /* An, invalid mode */
96: return -1;
97: case 2: /* (An) */
98: mov_l_rr(S1,reg+8);
99: break;
100: case 3: /* (An)+ */
101: mov_l_rr(S1,reg+8);
102: lea_l_brr(reg+8,reg+8,(reg == 7?sz2[size]:sz1[size]));
103: break;
104: case 4: /* -(An) */
105: lea_l_brr(reg+8,reg+8,-(reg == 7?sz2[size]:sz1[size]));
106: mov_l_rr(S1,reg+8);
107: break;
108: case 5: /* (d16,An) */
109: {
110: uae_u32 off=(uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2);
111: mov_l_rr(S1,reg+8);
112: lea_l_brr(S1,S1,off);
113: break;
114: }
115: case 6: /* (d8,An,Xn) or (bd,An,Xn) or ([bd,An,Xn],od) or ([bd,An],Xn,od) */
116: {
117: uae_u32 dp=comp_get_iword((m68k_pc_offset+=2)-2);
118: calc_disp_ea_020(reg+8,dp,S1,S2);
119: break;
120: }
121: case 7:
122: switch (reg) {
123: case 0: /* (xxx).W */
124: {
125: uae_u32 off=(uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2);
126: mov_l_ri(S1,off);
127: break;
128: }
129: case 1: /* (xxx).L */
130: {
131: uae_u32 off=comp_get_ilong((m68k_pc_offset+=4)-4);
132: mov_l_ri(S1,off);
133: break;
134: }
135: case 2: /* (d16,PC) */
136: {
137: uae_u32 address=start_pc+((uae_char*)comp_pc_p-(uae_char*)start_pc_p)+
138: m68k_pc_offset;
139: uae_s32 PC16off =(uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2);
140: mov_l_ri(S1,address+PC16off);
141: break;
142: }
143: case 3: /* (d8,PC,Xn) or (bd,PC,Xn) or ([bd,PC,Xn],od) or ([bd,PC],Xn,od) */
144: return -1; /* rarely used, fallback to non-JIT */
145: case 4: /* # < data >; Constants should be converted just once by the JIT */
146: m68k_pc_offset+=sz2[size];
147: switch (size) {
148: case 0:
149: {
150: uae_s32 li = comp_get_ilong(m68k_pc_offset-4);
151: float si = (float) li;
152:
153: if (li == (int) si) {
154: //write_log (L"converted immediate LONG constant to SINGLE\n");
155: fmovs_ri(treg,*(uae_u32 *)&si);
156: return 1;
157: }
158: //write_log (L"immediate LONG constant\n");
159: fmovl_ri(treg,li);
160: return 2;
161: }
162: case 1:
163: //write_log (L"immediate SINGLE constant\n");
164: fmovs_ri(treg,comp_get_ilong(m68k_pc_offset-4));
165: return 1;
166: case 2:
167: //write_log (L"immediate LONG DOUBLE constant\n");
168: fmov_ext_ri(treg,comp_get_ilong(m68k_pc_offset-4),
169: comp_get_ilong(m68k_pc_offset-8),
170: (comp_get_ilong(m68k_pc_offset-12)>>16)&0xffff);
171: return 0;
172: case 4:
173: {
174: float si = (float)(uae_s16)comp_get_iword(m68k_pc_offset-2);
175:
176: //write_log (L"converted immediate WORD constant to SINGLE\n");
177: fmovs_ri(treg,*(uae_u32 *)&si);
178: return 1;
179: }
180: case 5:
181: {
182: uae_u32 longarray[] = {comp_get_ilong(m68k_pc_offset-4),
183: comp_get_ilong(m68k_pc_offset-8)};
184: float si = (float)*(double *)longarray;
185:
186: if (*(double *)longarray == (double)si) {
187: //write_log (L"SPEED GAIN: converted a DOUBLE constant to SINGLE\n");
188: fmovs_ri(treg,*(uae_u32 *)&si);
189: return 1;
190: }
191: //write_log (L"immediate DOUBLE constant\n");
192: fmov_ri(treg,longarray[0],longarray[1]);
193: return 2;
194: }
195: case 6:
196: {
197: float si = (float)(uae_s8)comp_get_ibyte(m68k_pc_offset-2);
198:
199: //write_log (L"immediate BYTE constant converted to SINGLE\n");
200: fmovs_ri(treg,*(uae_u32 *)&si);
201: return 1;
202: }
203: default: /* never reached */
204: return -1;
205: }
206: default: /* never reached */
207: return -1;
208: }
209: }
210:
211: switch (size) {
212: case 0: /* Long */
213: readlong(S1,S2,S3);
214: mov_l_mr((uae_u32)temp_fp,S2);
215: fmovi_rm(treg,(uae_u32)temp_fp);
216: return 2;
217: case 1: /* Single */
218: readlong(S1,S2,S3);
219: mov_l_mr((uae_u32)temp_fp,S2);
220: fmovs_rm(treg,(uae_u32)temp_fp);
221: return 1;
222: case 2: /* Long Double */
223: readword(S1,S2,S3);
224: mov_w_mr(((uae_u32)temp_fp)+8,S2);
225: add_l_ri(S1,4);
226: readlong(S1,S2,S3);
227: mov_l_mr((uae_u32)(temp_fp)+4,S2);
228: add_l_ri(S1,4);
229: readlong(S1,S2,S3);
230: mov_l_mr((uae_u32)(temp_fp),S2);
231: fmov_ext_rm(treg,(uae_u32)(temp_fp));
232: return 0;
233: case 4: /* Word */
234: readword(S1,S2,S3);
235: sign_extend_16_rr(S2,S2);
236: mov_l_mr((uae_u32)temp_fp,S2);
237: fmovi_rm(treg,(uae_u32)temp_fp);
238: return 1;
239: case 5: /* Double */
240: readlong(S1,S2,S3);
241: mov_l_mr(((uae_u32)temp_fp)+4,S2);
242: add_l_ri(S1,4);
243: readlong(S1,S2,S3);
244: mov_l_mr((uae_u32)(temp_fp),S2);
245: fmov_rm(treg,(uae_u32)(temp_fp));
246: return 2;
247: case 6: /* Byte */
248: readbyte(S1,S2,S3);
249: sign_extend_8_rr(S2,S2);
250: mov_l_mr((uae_u32)temp_fp,S2);
251: fmovi_rm(treg,(uae_u32)temp_fp);
252: return 1;
253: default:
254: return -1;
255: }
256: return -1;
257: }
258:
259: /* return of -1 means failure, >=0 means OK */
260: STATIC_INLINE int comp_fp_put (uae_u32 opcode, uae_u16 extra)
261: {
262: int reg = opcode & 7;
263: int sreg = (extra >> 7) &7;
264: int mode = (opcode >> 3) & 7;
265: int size = (extra >> 10) & 7;
266:
267: if (size == 3 || size == 7) /* 3 = packed decimal, 7 is not defined */
268: return -1;
269: switch (mode) {
270: case 0: /* Dn */
271: switch (size) {
272: case 0: /* FMOVE.L FPx, Dn */
273: #if USE_X86_FPUCW && 0
274: if (!(regs.fpcr & 0xf0)) { /* if extended round to nearest */
275: mov_l_ri(S1,0x10); /* use extended round to zero mode */
276: fldcw_m_indexed(S1,(uae_u32)x86_fpucw);
277: fmovi_mrb((uae_u32)temp_fp,sreg, clamp_bounds.l);
278: mov_l_rm(reg,(uae_u32)temp_fp);
279: mov_l_rm(S1,(uae_u32)®s.fpcr);
280: and_l_ri(S1,0xf0); /* restore control word */
281: fldcw_m_indexed(S1,(uae_u32)x86_fpucw);
282: return 0;
283: }
284: #endif
285: fmovi_mrb((uae_u32)temp_fp,sreg, clamp_bounds.l);
286: mov_l_rm(reg,(uae_u32)temp_fp);
287: return 0;
288: case 1: /* FMOVE.S FPx, Dn */
289: fmovs_mr((uae_u32)temp_fp,sreg);
290: mov_l_rm(reg,(uae_u32)temp_fp);
291: return 0;
292: case 4: /* FMOVE.W FPx, Dn */
293: #if USE_X86_FPUCW && 0
294: if (!(regs.fpcr & 0xf0)) { /* if extended round to nearest */
295: mov_l_ri(S1,0x10); /* use extended round to zero mode */
296: fldcw_m_indexed(S1,(uae_u32)x86_fpucw);
297: fmovi_mrb((uae_u32)temp_fp,sreg, clamp_bounds.w);
298: mov_w_rm(reg,(uae_u32)temp_fp);
299: mov_l_rm(S1,(uae_u32)®s.fpcr);
300: and_l_ri(S1,0xf0); /* restore control word */
301: fldcw_m_indexed(S1,(uae_u32)x86_fpucw);
302: return 0;
303: }
304: #endif
305: fmovi_mrb((uae_u32)temp_fp,sreg, clamp_bounds.w);
306: mov_w_rm(reg,(uae_u32)temp_fp);
307: return 0;
308: case 6: /* FMOVE.B FPx, Dn */
309: #if USE_X86_FPUCW && 0
310: if (!(regs.fpcr & 0xf0)) { /* if extended round to nearest */
311: mov_l_ri(S1,0x10); /* use extended round to zero mode */
312: fldcw_m_indexed(S1,(uae_u32)x86_fpucw);
313: fmovi_mrb((uae_u32)temp_fp,sreg, clamp_bounds.b);
314: mov_b_rm(reg,(uae_u32)temp_fp);
315: mov_l_rm(S1,(uae_u32)®s.fpcr);
316: and_l_ri(S1,0xf0); /* restore control word */
317: fldcw_m_indexed(S1,(uae_u32)x86_fpucw);
318: return 0;
319: }
320: #endif
321: fmovi_mrb((uae_u32)temp_fp,sreg, clamp_bounds.b);
322: mov_b_rm(reg,(uae_u32)temp_fp);
323: return 0;
324: default:
325: return -1;
326: }
327: case 1: /* An, invalid mode */
328: return -1;
329: case 2: /* (An) */
330: mov_l_rr(S1,reg+8);
331: break;
332: case 3: /* (An)+ */
333: mov_l_rr(S1,reg+8);
334: lea_l_brr(reg+8,reg+8,(reg == 7?sz2[size]:sz1[size]));
335: break;
336: case 4: /* -(An) */
337: lea_l_brr(reg+8,reg+8,-(reg == 7?sz2[size]:sz1[size]));
338: mov_l_rr(S1,reg+8);
339: break;
340: case 5: /* (d16,An) */
341: {
342: uae_u32 off=(uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2);
343: mov_l_rr(S1,reg+8);
344: add_l_ri(S1,off);
345: break;
346: }
347: case 6: /* (d8,An,Xn) or (bd,An,Xn) or ([bd,An,Xn],od) or ([bd,An],Xn,od) */
348: {
349: uae_u32 dp=comp_get_iword((m68k_pc_offset+=2)-2);
350: calc_disp_ea_020(reg+8,dp,S1,S2);
351: break;
352: }
353: case 7:
354: switch (reg) {
355: case 0: /* (xxx).W */
356: {
357: uae_u32 off=(uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2);
358: mov_l_ri(S1,off);
359: break;
360: }
361: case 1: /* (xxx).L */
362: {
363: uae_u32 off=comp_get_ilong((m68k_pc_offset+=4)-4);
364: mov_l_ri(S1,off);
365: break;
366: }
367: default: /* All other modes are not allowed for FPx to <EA> */
368: write_log (L"JIT FMOVE FPx,<EA> Mode is not allowed %04x %04x\n",opcode,extra);
369: return -1;
370: }
371: }
372: switch (size) {
373: case 0: /* Long */
374: fmovi_mrb((uae_u32)temp_fp,sreg, clamp_bounds.l);
375: mov_l_rm(S2,(uae_u32)temp_fp);
376: writelong_clobber(S1,S2,S3);
377: return 0;
378: case 1: /* Single */
379: fmovs_mr((uae_u32)temp_fp,sreg);
380: mov_l_rm(S2,(uae_u32)temp_fp);
381: writelong_clobber(S1,S2,S3);
382: return 0;
383: case 2:/* Long Double */
384: fmov_ext_mr((uae_u32)temp_fp,sreg);
385: mov_w_rm(S2,(uae_u32)temp_fp+8);
386: writeword_clobber(S1,S2,S3);
387: add_l_ri(S1,4);
388: mov_l_rm(S2,(uae_u32)temp_fp+4);
389: writelong_clobber(S1,S2,S3);
390: add_l_ri(S1,4);
391: mov_l_rm(S2,(uae_u32)temp_fp);
392: writelong_clobber(S1,S2,S3);
393: return 0;
394: case 4: /* Word */
395: fmovi_mrb((uae_u32)temp_fp,sreg, clamp_bounds.w);
396: mov_l_rm(S2,(uae_u32)temp_fp);
397: writeword_clobber(S1,S2,S3);
398: return 0;
399: case 5: /* Double */
400: fmov_mr((uae_u32)temp_fp,sreg);
401: mov_l_rm(S2,(uae_u32)temp_fp+4);
402: writelong_clobber(S1,S2,S3);
403: add_l_ri(S1,4);
404: mov_l_rm(S2,(uae_u32)temp_fp);
405: writelong_clobber(S1,S2,S3);
406: return 0;
407: case 6: /* Byte */
408: fmovi_mrb((uae_u32)temp_fp,sreg, clamp_bounds.b);
409: mov_l_rm(S2,(uae_u32)temp_fp);
410: writebyte(S1,S2,S3);
411: return 0;
412: default:
413: return -1;
414: }
415: return -1;
416: }
417:
418: /* return -1 for failure, or register number for success */
419: STATIC_INLINE int comp_fp_adr (uae_u32 opcode)
420: {
421: uae_s32 off;
422: int mode = (opcode >> 3) & 7;
423: int reg = opcode & 7;
424:
425: switch (mode) {
426: case 2:
427: case 3:
428: case 4:
429: mov_l_rr(S1,8+reg);
430: return S1;
431: case 5:
432: off=(uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2);
433: mov_l_rr(S1,8+reg);
434: add_l_ri(S1,off);
435: return S1;
436: case 7:
437: switch (reg) {
438: case 0:
439: off=(uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2);
440: mov_l_ri(S1,off);
441: return S1;
442: case 1:
443: off=comp_get_ilong((m68k_pc_offset+=4)-4);
444: mov_l_ri(S1,off);
445: return S1;
446: }
447: default:
448: return -1;
449: }
450: }
451:
452: void comp_fdbcc_opp (uae_u32 opcode, uae_u16 extra)
453: {
454: FAIL(1);
455: return;
456: }
457:
458: void comp_fscc_opp (uae_u32 opcode, uae_u16 extra)
459: {
460: uae_u32 ad;
461: int cc;
462: int reg;
463:
464: if (!currprefs.compfpu) {
465: FAIL(1);
466: return;
467: }
468:
469: #if DEBUG_FPP
470: write_log (L"JIT: fscc_opp at %08lx\n", M68K_GETPC);
471: #endif
472:
473: if (extra&0x20) { /* only cc from 00 to 1f are defined */
474: FAIL(1);
475: return;
476: }
477: if ((opcode & 0x38) != 0) { /* We can only do to integer register */
478: FAIL(1);
479: return;
480: }
481:
482: fflags_into_flags(S2);
483: reg=(opcode&7);
484:
485: mov_l_ri(S1,255);
486: mov_l_ri(S4,0);
487: switch(extra&0x0f) { /* according to fpp.c, the 0x10 bit is ignored */
488: case 0: break; /* set never */
489: case 1: mov_l_rr(S2,S4);
490: cmov_l_rr(S4,S1,4);
491: cmov_l_rr(S4,S2,10); break;
492: case 2: cmov_l_rr(S4,S1,7); break;
493: case 3: cmov_l_rr(S4,S1,3); break;
494: case 4: mov_l_rr(S2,S4);
495: cmov_l_rr(S4,S1,2);
496: cmov_l_rr(S4,S2,10); break;
497: case 5: mov_l_rr(S2,S4);
498: cmov_l_rr(S4,S1,6);
499: cmov_l_rr(S4,S2,10); break;
500: case 6: cmov_l_rr(S4,S1,5); break;
501: case 7: cmov_l_rr(S4,S1,11); break;
502: case 8: cmov_l_rr(S4,S1,10); break;
503: case 9: cmov_l_rr(S4,S1,4); break;
504: case 10: cmov_l_rr(S4,S1,10); cmov_l_rr(S4,S1,7); break;
505: case 11: cmov_l_rr(S4,S1,4); cmov_l_rr(S4,S1,3); break;
506: case 12: cmov_l_rr(S4,S1,2); break;
507: case 13: cmov_l_rr(S4,S1,6); break;
508: case 14: cmov_l_rr(S4,S1,5); cmov_l_rr(S4,S1,10); break;
509: case 15: mov_l_rr(S4,S1); break;
510: }
511:
512: if (!(opcode & 0x38))
513: mov_b_rr(reg,S4);
514: #if 0
515: else {
516: abort();
517: if (!comp_fp_adr (opcode)) {
518: m68k_setpc (m68k_getpc () - 4);
519: op_illg (opcode);
520: }
521: else
522: put_byte (ad, cc ? 0xff : 0x00);
523: }
524: #endif
525: }
526:
527: void comp_ftrapcc_opp (uae_u32 opcode, uaecptr oldpc)
528: {
529: FAIL(1);
530: return;
531: }
532:
533: extern unsigned long foink3, oink;
534:
535: void comp_fbcc_opp (uae_u32 opcode)
536: {
537: uae_u32 start_68k_offset=m68k_pc_offset;
538: uae_u32 off, v1, v2;
539: int cc;
540:
541: if (!currprefs.compfpu) {
542: FAIL(1);
543: return;
544: }
545:
546: if (opcode&0x20) { /* only cc from 00 to 1f are defined */
547: FAIL(1);
548: return;
549: }
550: if (!(opcode&0x40)) {
551: off=(uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2);
552: }
553: else {
554: off=comp_get_ilong((m68k_pc_offset+=4)-4);
555: }
556: mov_l_ri(S1,(uae_u32)
557: (comp_pc_p+off-(m68k_pc_offset-start_68k_offset)));
558: mov_l_ri(PC_P,(uae_u32)comp_pc_p);
559:
560: /* Now they are both constant. Might as well fold in m68k_pc_offset */
561: add_l_ri(S1,m68k_pc_offset);
562: add_l_ri(PC_P,m68k_pc_offset);
563: m68k_pc_offset=0;
564:
565: /* according to fpp.c, the 0x10 bit is ignored
566: (it handles exception handling, which we don't
567: do, anyway ;-) */
568: cc=opcode&0x0f;
569: v1=get_const(PC_P);
570: v2=get_const(S1);
571: fflags_into_flags(S2);
572:
573: // mov_l_mi((uae_u32)&foink3,cc);
574: switch(cc) {
575: case 0: break; /* jump never */
576: case 1:
577: mov_l_rr(S2,PC_P);
578: cmov_l_rr(PC_P,S1,4);
579: cmov_l_rr(PC_P,S2,10); break;
580: case 2: register_branch(v1,v2,7); break;
581: case 3: register_branch(v1,v2,3); break;
582: case 4:
583: mov_l_rr(S2,PC_P);
584: cmov_l_rr(PC_P,S1,2);
585: cmov_l_rr(PC_P,S2,10); break;
586: case 5:
587: mov_l_rr(S2,PC_P);
588: cmov_l_rr(PC_P,S1,6);
589: cmov_l_rr(PC_P,S2,10); break;
590: case 6: register_branch(v1,v2,5); break;
591: case 7: register_branch(v1,v2,11); break;
592: case 8: register_branch(v1,v2,10); break;
593: case 9: register_branch(v1,v2,4); break;
594: case 10:
595: cmov_l_rr(PC_P,S1,10);
596: cmov_l_rr(PC_P,S1,7); break;
597: case 11:
598: cmov_l_rr(PC_P,S1,4);
599: cmov_l_rr(PC_P,S1,3); break;
600: case 12: register_branch(v1,v2,2); break;
601: case 13: register_branch(v1,v2,6); break;
602: case 14:
603: cmov_l_rr(PC_P,S1,5);
604: cmov_l_rr(PC_P,S1,10); break;
605: case 15: mov_l_rr(PC_P,S1); break;
606: }
607: }
608:
609: /* Floating point conditions
610: The "NotANumber" part could be problematic; Howver, when NaN is
611: encountered, the ftst instruction sets bot N and Z to 1 on the x87,
612: so quite often things just fall into place. This is probably not
613: accurate wrt the 68k FPU, but it is *as* accurate as this was before.
614: However, some more thought should go into fixing this stuff up so
615: it accurately emulates the 68k FPU.
616: >=<U
617: 0000 0x00: 0 --- Never jump
618: 0101 0x01: Z --- jump if zero (x86: 4)
619: 1000 0x02: !(NotANumber || Z || N) --- Neither Z nor N set (x86: 7)
620: 1101 0x03: Z || !(NotANumber || N); --- Z or !N (x86: 4 and 3)
621: 0010 0x04: N && !(NotANumber || Z); --- N and !Z (x86: hard!)
622: 0111 0x05: Z || (N && !NotANumber); --- Z or N (x86: 6)
623: 1010 0x06: !(NotANumber || Z); --- not Z (x86: 5)
624: 1110 0x07: !NotANumber; --- not NaN (x86: 11, not parity)
625: 0001 0x08: NotANumber; --- NaN (x86: 10)
626: 0101 0x09: NotANumber || Z; --- Z (x86: 4)
627: 1001 0x0a: NotANumber || !(N || Z); --- NaN or neither N nor Z (x86: 10 and 7)
628: 1101 0x0b: NotANumber || Z || !N; --- Z or !N (x86: 4 and 3)
629: 0011 0x0c: NotANumber || (N && !Z); --- N (x86: 2)
630: 0111 0x0d: NotANumber || Z || N; --- Z or N (x86: 6)
631: 1010 0x0e: !Z; --- not Z (x86: 5)
632: 1111 0x0f: 1; --- always
633:
634: This is not how the 68k handles things, though --- it sets Z to 0 and N
635: to the NaN's sign.... ('o' and 'i' denote differences from the above
636: table)
637:
638: >=<U
639: 0000 0x00: 0 --- Never jump
640: 010o 0x01: Z --- jump if zero (x86: 4, not 10)
641: 1000 0x02: !(NotANumber || Z || N) --- Neither Z nor N set (x86: 7)
642: 110o 0x03: Z || !(NotANumber || N); --- Z or !N (x86: 3)
643: 0010 0x04: N && !(NotANumber || Z); --- N and !Z (x86: 2, not 10)
644: 011o 0x05: Z || (N && !NotANumber); --- Z or N (x86: 6, not 10)
645: 1010 0x06: !(NotANumber || Z); --- not Z (x86: 5)
646: 1110 0x07: !NotANumber; --- not NaN (x86: 11, not parity)
647: 0001 0x08: NotANumber; --- NaN (x86: 10)
648: 0101 0x09: NotANumber || Z; --- Z (x86: 4)
649: 1001 0x0a: NotANumber || !(N || Z); --- NaN or neither N nor Z (x86: 10 and 7)
650: 1101 0x0b: NotANumber || Z || !N; --- Z or !N (x86: 4 and 3)
651: 0011 0x0c: NotANumber || (N && !Z); --- N (x86: 2)
652: 0111 0x0d: NotANumber || Z || N; --- Z or N (x86: 6)
653: 101i 0x0e: !Z; --- not Z (x86: 5 and 10)
654: 1111 0x0f: 1; --- always
655:
656: Of course, this *still* doesn't mean that the x86 and 68k conditions are
657: equivalent --- the handling of infinities is different, for one thing.
658: On the 68k, +infinity minus +infinity is NotANumber (as it should be). On
659: the x86, it is +infinity, and some exception is raised (which I suspect
660: is promptly ignored) STUPID!
661: The more I learn about their CPUs, the more I detest Intel....
662:
663: You can see this in action if you have "Benoit" (see Aminet) and
664: set the exponent to 16. Wait for a long time, and marvel at the extra black
665: areas outside the center one. That's where Benoit expects NaN, and the x86
666: gives +infinity. [Ooops --- that must have been some kind of bug in my code.
667: it no longer happens, and the resulting graphic looks much better, too]
668:
669: x86 conditions
670: 0011 : 2
671: 1100 : 3
672: 0101 : 4
673: 1010 : 5
674: 0111 : 6
675: 1000 : 7
676: 0001 : 10
677: 1110 : 11
678: */
679: void comp_fsave_opp (uae_u32 opcode)
680: {
681: FAIL(1);
682: return;
683: }
684:
685: void comp_frestore_opp (uae_u32 opcode)
686: {
687: FAIL(1);
688: return;
689: }
690:
691: extern uae_u32 xhex_pi[], xhex_exp_1[], xhex_l2_e[], xhex_ln_2[], xhex_ln_10[];
692: extern uae_u32 xhex_l10_2[], xhex_l10_e[], xhex_1e16[], xhex_1e32[], xhex_1e64[];
693: extern uae_u32 xhex_1e128[], xhex_1e256[], xhex_1e512[], xhex_1e1024[];
694: extern uae_u32 xhex_1e2048[], xhex_1e4096[];
695: extern double fp_1e8;
696: extern float fp_1e1, fp_1e2, fp_1e4;
697:
698: void comp_fpp_opp (uae_u32 opcode, uae_u16 extra)
699: {
700: int reg;
701: int sreg, prec = 0;
702: int dreg = (extra >> 7) & 7;
703: int source = (extra >> 13) & 7;
704: int opmode = extra & 0x7f;
705:
706: if (!currprefs.compfpu) {
707: FAIL(1);
708: return;
709: }
710: switch (source) {
711: case 3: /* FMOVE FPx, <EA> */
712: if (comp_fp_put(opcode,extra) < 0)
713: FAIL(1);
714: return;
715: case 4: /* FMOVE.L <EA>, ControlReg */
716: if (!(opcode & 0x30)) { /* Dn or An */
717: if (extra & 0x1000) { /* FPCR */
718: mov_l_mr((uae_u32)®s.fpcr,opcode & 15);
719: #if USE_X86_FPUCW
720: mov_l_rr(S1,opcode & 15);
721: and_l_ri(S1,0xf0);
722: fldcw_m_indexed(S1,(uae_u32)x86_fpucw);
723: #endif
724: return;
725: }
726: if (extra & 0x0800) { /* FPSR */
727: FAIL(1);
728: return;
729: // set_fpsr(m68k_dreg (regs, opcode & 15));
730: }
731: if (extra & 0x0400) { /* FPIAR */
732: mov_l_mr((uae_u32)®s.fpiar,opcode & 15); return;
733: }
734: }
735: else if ((opcode & 0x3f) == 0x3c) {
736: if (extra & 0x1000) { /* FPCR */
737: uae_u32 val=comp_get_ilong((m68k_pc_offset+=4)-4);
738: mov_l_mi((uae_u32)®s.fpcr,val);
739: #if USE_X86_FPUCW
740: mov_l_ri(S1,val&0xf0);
741: fldcw_m_indexed(S1,(uae_u32)x86_fpucw);
742: #endif
743: return;
744: }
745: if (extra & 0x0800) { /* FPSR */
746: FAIL(1);
747: return;
748: }
749: if (extra & 0x0400) { /* FPIAR */
750: uae_u32 val=comp_get_ilong((m68k_pc_offset+=4)-4);
751: mov_l_mi((uae_u32)®s.fpiar,val);
752: return;
753: }
754: }
755: FAIL(1);
756: return;
757: case 5: /* FMOVE.L ControlReg, <EA> */
758: if (!(opcode & 0x30)) { /* Dn or An */
759: if (extra & 0x1000) { /* FPCR */
760: mov_l_rm(opcode & 15,(uae_u32)®s.fpcr); return;
761: }
762: if (extra & 0x0800) { /* FPSR */
763: FAIL(1);
764: return;
765: }
766: if (extra & 0x0400) { /* FPIAR */
767: mov_l_rm(opcode & 15,(uae_u32)®s.fpiar); return;
768: }
769: }
770: FAIL(1);
771: return;
772: case 6:
773: case 7:
774: {
775: uae_u32 list = 0;
776: int incr = 0;
777: if (extra & 0x2000) {
778: uae_u32 ad;
779:
780: /* FMOVEM FPP->memory */
781: switch ((extra >> 11) & 3) { /* Get out early if failure */
782: case 0:
783: case 2:
784: break;
785: case 1:
786: case 3:
787: default:
788: FAIL(1); return;
789: }
790: ad=comp_fp_adr (opcode);
791: if (ad<0) {
792: m68k_setpc (m68k_getpc () - 4);
793: op_illg (opcode);
794: return;
795: }
796: switch ((extra >> 11) & 3) {
797: case 0: /* static pred */
798: list = extra & 0xff;
799: incr = -1;
800: break;
801: case 2: /* static postinc */
802: list = extra & 0xff;
803: incr = 1;
804: break;
805: case 1: /* dynamic pred */
806: case 3: /* dynamic postinc */
807: abort();
808: }
809: if (incr < 0) { /* Predecrement */
810: for (reg = 7; reg >= 0; reg--) {
811: if (list & 0x80) {
812: fmov_ext_mr((uintptr)temp_fp,reg);
813: sub_l_ri(ad,4);
814: mov_l_rm(S2,(uintptr)temp_fp);
815: writelong_clobber(ad,S2,S3);
816: sub_l_ri(ad,4);
817: mov_l_rm(S2,(uintptr)temp_fp+4);
818: writelong_clobber(ad,S2,S3);
819: sub_l_ri(ad,4);
820: mov_w_rm(S2,(uintptr)temp_fp+8);
821: writeword_clobber(ad,S2,S3);
822: }
823: list <<= 1;
824: }
825: }
826: else { /* Postincrement */
827: for (reg = 0; reg <= 7; reg++) {
828: if (list & 0x80) {
829: fmov_ext_mr((uintptr)temp_fp,reg);
830: mov_w_rm(S2,(uintptr)temp_fp+8);
831: writeword_clobber(ad,S2,S3);
832: add_l_ri(ad,4);
833: mov_l_rm(S2,(uintptr)temp_fp+4);
834: writelong_clobber(ad,S2,S3);
835: add_l_ri(ad,4);
836: mov_l_rm(S2,(uintptr)temp_fp);
837: writelong_clobber(ad,S2,S3);
838: add_l_ri(ad,4);
839: }
840: list <<= 1;
841: }
842: }
843: if ((opcode & 0x38) == 0x18)
844: mov_l_rr((opcode & 7)+8,ad);
845: if ((opcode & 0x38) == 0x20)
846: mov_l_rr((opcode & 7)+8,ad);
847: } else {
848: /* FMOVEM memory->FPP */
849:
850: uae_u32 ad;
851: switch ((extra >> 11) & 3) { /* Get out early if failure */
852: case 0:
853: case 2:
854: break;
855: case 1:
856: case 3:
857: default:
858: FAIL(1); return;
859: }
860: ad=comp_fp_adr (opcode);
861: if (ad<0) {
862: m68k_setpc (m68k_getpc () - 4);
863: op_illg (opcode);
864: return;
865: }
866: switch ((extra >> 11) & 3) {
867: case 0: /* static pred */
868: list = extra & 0xff;
869: incr = -1;
870: break;
871: case 2: /* static postinc */
872: list = extra & 0xff;
873: incr = 1;
874: break;
875: case 1: /* dynamic pred */
876: case 3: /* dynamic postinc */
877: abort();
878: }
879:
880: if (incr < 0) {
881: // not reached
882: for (reg = 7; reg >= 0; reg--) {
883: if (list & 0x80) {
884: sub_l_ri(ad,4);
885: readlong(ad,S2,S3);
886: mov_l_mr((uintptr)(temp_fp),S2);
887: sub_l_ri(ad,4);
888: readlong(ad,S2,S3);
889: mov_l_mr((uintptr)(temp_fp)+4,S2);
890: sub_l_ri(ad,4);
891: readword(ad,S2,S3);
892: mov_w_mr(((uintptr)temp_fp)+8,S2);
893: fmov_ext_rm(reg,(uintptr)(temp_fp));
894: }
895: list <<= 1;
896: }
897: }
898: else {
899: for (reg = 0; reg <= 7; reg++) {
900: if (list & 0x80) {
901: readword(ad,S2,S3);
902: mov_w_mr(((uintptr)temp_fp)+8,S2);
903: add_l_ri(ad,4);
904: readlong(ad,S2,S3);
905: mov_l_mr((uintptr)(temp_fp)+4,S2);
906: add_l_ri(ad,4);
907: readlong(ad,S2,S3);
908: mov_l_mr((uintptr)(temp_fp),S2);
909: add_l_ri(ad,4);
910: fmov_ext_rm(reg,(uintptr)(temp_fp));
911: }
912: list <<= 1;
913: }
914: }
915: if ((opcode & 0x38) == 0x18)
916: mov_l_rr((opcode & 7)+8,ad);
917: if ((opcode & 0x38) == 0x20)
918: mov_l_rr((opcode & 7)+8,ad);
919: }
920: }
921: return;
922: #if 0
923: case 6: /* FMOVEM <EA>, FPx-FPz */
924: if (!(extra & 0x0800)) {
925: uae_u32 list = extra & 0xff;
926: int ad;
927: if ((ad = comp_fp_adr(opcode)) < 0) {FAIL(1);return;}
928: while (list) {
929: if (extra & 0x1000) { /* postincrement */
930: readword(ad,S2,S3);
931: mov_w_mr(((uae_u32)temp_fp)+8,S2);
932: add_l_ri(ad,4);
933: readlong(ad,S2,S3);
934: mov_l_mr((uae_u32)(temp_fp)+4,S2);
935: add_l_ri(ad,4);
936: readlong(ad,S2,S3);
937: mov_l_mr((uae_u32)(temp_fp),S2);
938: add_l_ri(ad,4);
939: fmov_ext_rm(fpp_movem_index1[list],(uae_u32)(temp_fp));
940: } else { /* predecrement */
941: sub_l_ri(ad,4);
942: readlong(ad,S2,S3);
943: mov_l_mr((uae_u32)(temp_fp),S2);
944: sub_l_ri(ad,4);
945: readlong(ad,S2,S3);
946: mov_l_mr((uae_u32)(temp_fp)+4,S2);
947: sub_l_ri(ad,4);
948: readword(ad,S2,S3);
949: mov_w_mr(((uae_u32)temp_fp)+8,S2);
950: fmov_ext_rm(fpp_movem_index2[list],(uae_u32)(temp_fp));
951: }
952: list = fpp_movem_next[list];
953: }
954: if ((opcode & 0x38) == 0x18)
955: mov_l_rr((opcode & 7)+8,ad);
956: return;
957: } /* no break for dynamic register list */
958: case 7: /* FMOVEM FPx-FPz, <EA> */
959: if (!(extra & 0x0800)) {
960: uae_u32 list = extra & 0xff;
961: int ad;
962: if ((ad = comp_fp_adr(opcode)) < 0) {FAIL(1);return;}
963: while (list) {
964: if (extra & 0x1000) { /* postincrement */
965: fmov_ext_mr((uae_u32)temp_fp,fpp_movem_index2[list]);
966: mov_w_rm(S2,(uae_u32)temp_fp+8);
967: writeword_clobber(ad,S2,S3);
968: add_l_ri(ad,4);
969: mov_l_rm(S2,(uae_u32)temp_fp+4);
970: writelong_clobber(ad,S2,S3);
971: add_l_ri(ad,4);
972: mov_l_rm(S2,(uae_u32)temp_fp);
973: writelong_clobber(ad,S2,S3);
974: add_l_ri(ad,4);
975: } else { /* predecrement */
976: fmov_ext_mr((uae_u32)temp_fp,fpp_movem_index2[list]);
977: sub_l_ri(ad,4);
978: mov_l_rm(S2,(uae_u32)temp_fp);
979: writelong_clobber(ad,S2,S3);
980: sub_l_ri(ad,4);
981: mov_l_rm(S2,(uae_u32)temp_fp+4);
982: writelong_clobber(ad,S2,S3);
983: sub_l_ri(ad,4);
984: mov_w_rm(S2,(uae_u32)temp_fp+8);
985: writeword_clobber(ad,S2,S3);
986: }
987: list = fpp_movem_next[list];
988: }
989: if ((opcode & 0x38) == 0x20)
990: mov_l_rr((opcode & 7)+8,ad);
991: return;
992: } /* no break */
993: write_log (L"fallback from JIT FMOVEM dynamic register list\n");
994: FAIL(1);
995: return;
996: #endif
997: case 2: /* from <EA> to FPx */
998: dont_care_fflags();
999: if ((extra & 0xfc00) == 0x5c00) { /* FMOVECR */
1000: //write_log (L"JIT FMOVECR %x\n", opmode);
1001: switch (opmode) {
1002: case 0x00:
1003: fmov_pi(dreg);
1004: break;
1005: case 0x0b:
1006: fmov_ext_rm(dreg,(uae_u32)&xhex_l10_2);
1007: break;
1008: case 0x0c:
1009: fmov_ext_rm(dreg,(uae_u32)&xhex_exp_1);
1010: break;
1011: case 0x0d:
1012: fmov_log2_e(dreg);
1013: break;
1014: case 0x0e:
1015: fmov_ext_rm(dreg,(uae_u32)&xhex_l10_e);
1016: break;
1017: case 0x0f:
1018: fmov_0(dreg);
1019: break;
1020: case 0x30:
1021: fmov_loge_2(dreg);
1022: break;
1023: case 0x31:
1024: fmov_ext_rm(dreg,(uae_u32)&xhex_ln_10);
1025: break;
1026: case 0x32:
1027: fmov_1(dreg);
1028: break;
1029: case 0x33:
1030: fmovs_rm(dreg,(uae_u32)&fp_1e1);
1031: break;
1032: case 0x34:
1033: fmovs_rm(dreg,(uae_u32)&fp_1e2);
1034: break;
1035: case 0x35:
1036: fmovs_rm(dreg,(uae_u32)&fp_1e4);
1037: break;
1038: case 0x36:
1039: fmov_rm(dreg,(uae_u32)&fp_1e8);
1040: break;
1041: case 0x37:
1042: fmov_ext_rm(dreg,(uae_u32)&xhex_1e16);
1043: break;
1044: case 0x38:
1045: fmov_ext_rm(dreg,(uae_u32)&xhex_1e32);
1046: break;
1047: case 0x39:
1048: fmov_ext_rm(dreg,(uae_u32)&xhex_1e64);
1049: break;
1050: case 0x3a:
1051: fmov_ext_rm(dreg,(uae_u32)&xhex_1e128);
1052: break;
1053: case 0x3b:
1054: fmov_ext_rm(dreg,(uae_u32)&xhex_1e256);
1055: break;
1056: case 0x3c:
1057: fmov_ext_rm(dreg,(uae_u32)&xhex_1e512);
1058: break;
1059: case 0x3d:
1060: fmov_ext_rm(dreg,(uae_u32)&xhex_1e1024);
1061: break;
1062: case 0x3e:
1063: fmov_ext_rm(dreg,(uae_u32)&xhex_1e2048);
1064: break;
1065: case 0x3f:
1066: fmov_ext_rm(dreg,(uae_u32)&xhex_1e4096);
1067: break;
1068: default:
1069: FAIL(1);
1070: return;
1071: }
1072: fmov_rr(FP_RESULT,dreg);
1073: return;
1074: }
1075: if (opmode & 0x20) /* two operands, so we need a scratch reg */
1076: sreg = FS1;
1077: else /* one operand only, thus we can load the argument into dreg */
1078: sreg = dreg;
1079: if ((prec = comp_fp_get(opcode,extra,sreg)) < 0) {
1080: FAIL(1);
1081: return;
1082: }
1083: if (!opmode) { /* FMOVE <EA>,FPx */
1084: fmov_rr(FP_RESULT,dreg);
1085: return;
1086: }
1087: /* no break here for <EA> to dreg */
1088: case 0: /* directly from sreg to dreg */
1089: if (!source) { /* no <EA> */
1090: dont_care_fflags();
1091: sreg = (extra >> 10) & 7;
1092: }
1093: switch (opmode) {
1094: case 0x00: /* FMOVE */
1095: fmov_rr(dreg,sreg);
1096: break;
1097: case 0x01: /* FINT */
1098: frndint_rr(dreg,sreg);
1099: break;
1100: case 0x02: /* FSINH */
1101: fsinh_rr(dreg,sreg);
1102: break;
1103: case 0x03: /* FINTRZ */
1104: #if USE_X86_FPUCW /* if we have control over the CW, we can do this */
1105: if (0 && (regs.fpcr & 0xf0) == 0x10) /* maybe unsafe, because this test is done */
1106: frndint_rr(dreg,sreg); /* during the JIT compilation and not at runtime */
1107: else {
1108: mov_l_ri(S1,0x10); /* extended round to zero */
1109: fldcw_m_indexed(S1,(uae_u32)x86_fpucw);
1110: frndint_rr(dreg,sreg);
1111: mov_l_rm(S1,(uae_u32)®s.fpcr);
1112: and_l_ri(S1,0xf0); /* restore control word */
1113: fldcw_m_indexed(S1,(uae_u32)x86_fpucw);
1114: }
1115: break;
1116: #endif
1117: FAIL(1);
1118: return;
1119: case 0x04: /* FSQRT */
1120: fsqrt_rr(dreg,sreg);
1121: break;
1122: case 0x06: /* FLOGNP1 */
1123: flogNP1_rr(dreg,sreg);
1124: break;
1125: case 0x08: /* FETOXM1 */
1126: fetoxM1_rr(dreg,sreg);
1127: break;
1128: case 0x09: /* FTANH */
1129: ftanh_rr(dreg,sreg);
1130: break;
1131: case 0x0a: /* FATAN */
1132: fatan_rr(dreg,sreg);
1133: break;
1134: case 0x0c: /* FASIN */
1135: fasin_rr(dreg,sreg);
1136: break;
1137: case 0x0d: /* FATANH */
1138: fatanh_rr(dreg,sreg);
1139: break;
1140: case 0x0e: /* FSIN */
1141: fsin_rr(dreg,sreg);
1142: break;
1143: case 0x0f: /* FTAN */
1144: ftan_rr(dreg,sreg);
1145: break;
1146: case 0x10: /* FETOX */
1147: fetox_rr(dreg,sreg);
1148: break;
1149: case 0x11: /* FTWOTOX */
1150: ftwotox_rr(dreg,sreg);
1151: break;
1152: case 0x12: /* FTENTOX */
1153: ftentox_rr(dreg,sreg);
1154: break;
1155: case 0x14: /* FLOGN */
1156: flogN_rr(dreg,sreg);
1157: break;
1158: case 0x15: /* FLOG10 */
1159: flog10_rr(dreg,sreg);
1160: break;
1161: case 0x16: /* FLOG2 */
1162: flog2_rr(dreg,sreg);
1163: break;
1164: case 0x18: /* FABS */
1165: fabs_rr(dreg,sreg);
1166: break;
1167: case 0x19: /* FCOSH */
1168: fcosh_rr(dreg,sreg);
1169: break;
1170: case 0x1a: /* FNEG */
1171: fneg_rr(dreg,sreg);
1172: break;
1173: case 0x1c: /* FACOS */
1174: #if USE_X86_FPUCW
1175: if ((regs.fpcr & 0x30) != 0x10) { /* use round to zero */
1176: mov_l_ri(S1,(regs.fpcr & 0xC0) | 0x10);
1177: fldcw_m_indexed(S1,(uae_u32)x86_fpucw);
1178: facos_rr(dreg,sreg);
1179: mov_l_rm(S1,(uae_u32)®s.fpcr);
1180: and_l_ri(S1,0xf0); /* restore control word */
1181: fldcw_m_indexed(S1,(uae_u32)x86_fpucw);
1182: break;
1183: }
1184: #endif
1185: facos_rr(dreg,sreg);
1186: break;
1187: case 0x1d: /* FCOS */
1188: fcos_rr(dreg,sreg);
1189: break;
1190: case 0x1e: /* FGETEXP */
1191: fgetexp_rr(dreg,sreg);
1192: break;
1193: case 0x1f: /* FGETMAN */
1194: fgetman_rr(dreg,sreg);
1195: break;
1196: case 0x20: /* FDIV */
1197: fdiv_rr(dreg,sreg);
1198: break;
1199: case 0x21: /* FMOD */
1200: frem_rr(dreg,sreg);
1201: break;
1202: case 0x22: /* FADD */
1203: fadd_rr(dreg,sreg);
1204: break;
1205: case 0x23: /* FMUL */
1206: fmul_rr(dreg,sreg);
1207: break;
1208: case 0x24: /* FSGLDIV is not exactly the same as FSDIV, */
1209: /* because both operands should be SINGLE precision, too */
1210: case 0x60: /* FSDIV */
1211: fdiv_rr(dreg,sreg);
1212: if (!currprefs.fpu_strict) /* faster, but less strict rounding */
1213: break;
1214: #if USE_X86_FPUCW
1215: if ((regs.fpcr & 0xC0) == 0x40) /* if SINGLE precision */
1216: break;
1217: #endif
1218: fcuts_r(dreg);
1219: break;
1220: case 0x25: /* FREM */
1221: frem1_rr(dreg,sreg);
1222: break;
1223: case 0x26: /* FSCALE */
1224: fscale_rr(dreg,sreg);
1225: break;
1226: case 0x27: /* FSGLMUL is not exactly the same as FSMUL, */
1227: /* because both operands should be SINGLE precision, too */
1228: case 0x63: /* FSMUL */
1229: fmul_rr(dreg,sreg);
1230: if (!currprefs.fpu_strict) /* faster, but less strict rounding */
1231: break;
1232: #if USE_X86_FPUCW
1233: if ((regs.fpcr & 0xC0) == 0x40) /* if SINGLE precision */
1234: break;
1235: #endif
1236: fcuts_r(dreg);
1237: break;
1238: case 0x28: /* FSUB */
1239: fsub_rr(dreg,sreg);
1240: break;
1241: case 0x30: /* FSINCOS */
1242: case 0x31:
1243: case 0x32:
1244: case 0x33:
1245: case 0x34:
1246: case 0x35:
1247: case 0x36:
1248: case 0x37:
1249: if (dreg == (extra & 7))
1250: fsin_rr(dreg, sreg);
1251: else
1252: fsincos_rr(dreg, extra & 7, sreg);
1253: break;
1254: case 0x38: /* FCMP */
1255: fmov_rr(FP_RESULT,dreg);
1256: fsub_rr(FP_RESULT,sreg);
1257: return;
1258: case 0x3a: /* FTST */
1259: fmov_rr(FP_RESULT,sreg);
1260: return;
1261: case 0x40: /* FSMOVE */
1262: if (prec == 1 || !currprefs.fpu_strict) {
1263: if (sreg != dreg) /* no <EA> */
1264: fmov_rr(dreg,sreg);
1265: } else {
1266: fmovs_mr((uae_u32)temp_fp,sreg);
1267: fmovs_rm(dreg,(uae_u32)temp_fp);
1268: }
1269: break;
1270: case 0x44: /* FDMOVE */
1271: if (prec || !currprefs.fpu_strict) {
1272: if (sreg != dreg) /* no <EA> */
1273: fmov_rr(dreg,sreg);
1274: } else {
1275: fmov_mr((uae_u32)temp_fp,sreg);
1276: fmov_rm(dreg,(uae_u32)temp_fp);
1277: }
1278: break;
1279: case 0x41: /* FSSQRT */
1280: fsqrt_rr(dreg,sreg);
1281: if (!currprefs.fpu_strict) /* faster, but less strict rounding */
1282: break;
1283: #if USE_X86_FPUCW
1284: if ((regs.fpcr & 0xC0) == 0x40) /* if SINGLE precision */
1285: break;
1286: #endif
1287: fcuts_r(dreg);
1288: break;
1289: case 0x45: /* FDSQRT */
1290: if (!currprefs.fpu_strict) { /* faster, but less strict rounding */
1291: fsqrt_rr(dreg,sreg);
1292: break;
1293: }
1294: #if USE_X86_FPUCW
1295: if (regs.fpcr & 0xC0) { /* if we don't have EXTENDED precision */
1296: if ((regs.fpcr & 0xC0) == 0x80) /* if we have DOUBLE */
1297: fsqrt_rr(dreg,sreg);
1298: else { /* if we have SINGLE presision, force DOUBLE */
1299: mov_l_ri(S1,(regs.fpcr & 0x30) | 0x80);
1300: fldcw_m_indexed(S1,(uae_u32)x86_fpucw);
1301: fsqrt_rr(dreg,sreg);
1302: mov_l_rm(S1,(uae_u32)®s.fpcr);
1303: and_l_ri(S1,0xf0); /* restore control word */
1304: fldcw_m_indexed(S1,(uae_u32)x86_fpucw);
1305: }
1306: break;
1307: }
1308: #endif /* in case of EXTENDED precision, just reduce the result to DOUBLE */
1309: fsqrt_rr(dreg,sreg);
1310: fcut_r(dreg);
1311: break;
1312: case 0x58: /* FSABS */
1313: fabs_rr(dreg,sreg);
1314: if (prec != 1 && currprefs.fpu_strict)
1315: fcuts_r(dreg);
1316: break;
1317: case 0x5a: /* FSNEG */
1318: fneg_rr(dreg,sreg);
1319: if (prec != 1 && currprefs.fpu_strict)
1320: fcuts_r(dreg);
1321: break;
1322: case 0x5c: /* FDABS */
1323: fabs_rr(dreg,sreg);
1324: if (!prec && currprefs.fpu_strict)
1325: fcut_r(dreg);
1326: break;
1327: case 0x5e: /* FDNEG */
1328: fneg_rr(dreg,sreg);
1329: if (!prec && currprefs.fpu_strict)
1330: fcut_r(dreg);
1331: break;
1332: case 0x62: /* FSADD */
1333: fadd_rr(dreg,sreg);
1334: if (!currprefs.fpu_strict) /* faster, but less strict rounding */
1335: break;
1336: #if USE_X86_FPUCW
1337: if ((regs.fpcr & 0xC0) == 0x40) /* if SINGLE precision */
1338: break;
1339: #endif
1340: fcuts_r(dreg);
1341: break;
1342: case 0x64: /* FDDIV */
1343: if (!currprefs.fpu_strict) { /* faster, but less strict rounding */
1344: fdiv_rr(dreg,sreg);
1345: break;
1346: }
1347: #if USE_X86_FPUCW
1348: if (regs.fpcr & 0xC0) { /* if we don't have EXTENDED precision */
1349: if ((regs.fpcr & 0xC0) == 0x80) /* if we have DOUBLE */
1350: fdiv_rr(dreg,sreg);
1351: else { /* if we have SINGLE presision, force DOUBLE */
1352: mov_l_ri(S1,(regs.fpcr & 0x30) | 0x80);
1353: fldcw_m_indexed(S1,(uae_u32)x86_fpucw);
1354: fdiv_rr(dreg,sreg);
1355: mov_l_rm(S1,(uae_u32)®s.fpcr);
1356: and_l_ri(S1,0xf0); /* restore control word */
1357: fldcw_m_indexed(S1,(uae_u32)x86_fpucw);
1358: }
1359: break;
1360: }
1361: #endif /* in case of EXTENDED precision, just reduce the result to DOUBLE */
1362: fdiv_rr(dreg,sreg);
1363: fcut_r(dreg);
1364: break;
1365: case 0x66: /* FDADD */
1366: if (!currprefs.fpu_strict) { /* faster, but less strict rounding */
1367: fadd_rr(dreg,sreg);
1368: break;
1369: }
1370: #if USE_X86_FPUCW
1371: if (regs.fpcr & 0xC0) { /* if we don't have EXTENDED precision */
1372: if ((regs.fpcr & 0xC0) == 0x80) /* if we have DOUBLE */
1373: fadd_rr(dreg,sreg);
1374: else { /* if we have SINGLE presision, force DOUBLE */
1375: mov_l_ri(S1,(regs.fpcr & 0x30) | 0x80);
1376: fldcw_m_indexed(S1,(uae_u32)x86_fpucw);
1377: fadd_rr(dreg,sreg);
1378: mov_l_rm(S1,(uae_u32)®s.fpcr);
1379: and_l_ri(S1,0xf0); /* restore control word */
1380: fldcw_m_indexed(S1,(uae_u32)x86_fpucw);
1381: }
1382: break;
1383: }
1384: #endif /* in case of EXTENDED precision, just reduce the result to DOUBLE */
1385: fadd_rr(dreg,sreg);
1386: fcut_r(dreg);
1387: break;
1388: case 0x67: /* FDMUL */
1389: if (!currprefs.fpu_strict) { /* faster, but less strict rounding */
1390: fmul_rr(dreg,sreg);
1391: break;
1392: }
1393: #if USE_X86_FPUCW
1394: if (regs.fpcr & 0xC0) { /* if we don't have EXTENDED precision */
1395: if ((regs.fpcr & 0xC0) == 0x80) /* if we have DOUBLE */
1396: fmul_rr(dreg,sreg);
1397: else { /* if we have SINGLE presision, force DOUBLE */
1398: mov_l_ri(S1,(regs.fpcr & 0x30) | 0x80);
1399: fldcw_m_indexed(S1,(uae_u32)x86_fpucw);
1400: fmul_rr(dreg,sreg);
1401: mov_l_rm(S1,(uae_u32)®s.fpcr);
1402: and_l_ri(S1,0xf0); /* restore control word */
1403: fldcw_m_indexed(S1,(uae_u32)x86_fpucw);
1404: }
1405: break;
1406: }
1407: #endif /* in case of EXTENDED precision, just reduce the result to DOUBLE */
1408: fmul_rr(dreg,sreg);
1409: fcut_r(dreg);
1410: break;
1411: case 0x68: /* FSSUB */
1412: fsub_rr(dreg,sreg);
1413: if (!currprefs.fpu_strict) /* faster, but less strict rounding */
1414: break;
1415: #if USE_X86_FPUCW
1416: if ((regs.fpcr & 0xC0) == 0x40) /* if SINGLE precision */
1417: break;
1418: #endif
1419: fcuts_r(dreg);
1420: break;
1421: case 0x6c: /* FDSUB */
1422: if (!currprefs.fpu_strict) { /* faster, but less strict rounding */
1423: fsub_rr(dreg,sreg);
1424: break;
1425: }
1426: #if USE_X86_FPUCW
1427: if (regs.fpcr & 0xC0) { /* if we don't have EXTENDED precision */
1428: if ((regs.fpcr & 0xC0) == 0x80) /* if we have DOUBLE */
1429: fsub_rr(dreg,sreg);
1430: else { /* if we have SINGLE presision, force DOUBLE */
1431: mov_l_ri(S1,(regs.fpcr & 0x30) | 0x80);
1432: fldcw_m_indexed(S1,(uae_u32)x86_fpucw);
1433: fsub_rr(dreg,sreg);
1434: mov_l_rm(S1,(uae_u32)®s.fpcr);
1435: and_l_ri(S1,0xf0); /* restore control word */
1436: fldcw_m_indexed(S1,(uae_u32)x86_fpucw);
1437: }
1438: break;
1439: }
1440: #endif /* in case of EXTENDED precision, just reduce the result to DOUBLE */
1441: fsub_rr(dreg,sreg);
1442: fcut_r(dreg);
1443: break;
1444: default:
1445: FAIL(1);
1446: return;
1447: }
1448: fmov_rr(FP_RESULT,dreg);
1449: return;
1450: default:
1451: write_log (L"Unsupported JIT-FPU instruction: 0x%04x %04x\n",opcode,extra);
1452: FAIL(1);
1453: return;
1454: }
1455: }
1456: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.