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