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