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