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