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