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