|
|
1.1 ! root 1: ! 2: ! 3: #include "sysconfig.h" ! 4: #include "sysdeps.h" ! 5: ! 6: #define MOVEC_DEBUG 0 ! 7: ! 8: #include "options_cpu.h" ! 9: #include "memory.h" ! 10: #include "newcpu.h" ! 11: #include "cpummu.h" ! 12: #include "cpummu030.h" ! 13: #include "cpu_prefetch.h" ! 14: ! 15: #include "log.h" ! 16: ! 17: void val_move2c2 (int regno, uae_u32 val) ! 18: { ! 19: switch (regno) { ! 20: case 0: regs.sfc = val; break; ! 21: case 1: regs.dfc = val; break; ! 22: case 2: regs.cacr = val; break; ! 23: case 3: regs.tcr = val; break; ! 24: case 4: regs.itt0 = val; break; ! 25: case 5: regs.itt1 = val; break; ! 26: case 6: regs.dtt0 = val; break; ! 27: case 7: regs.dtt1 = val; break; ! 28: case 8: regs.buscr = val; break; ! 29: case 0x800: regs.usp = val; break; ! 30: case 0x801: regs.vbr = val; break; ! 31: case 0x802: regs.caar = val; break; ! 32: case 0x803: regs.msp = val; break; ! 33: case 0x804: regs.isp = val; break; ! 34: case 0x805: regs.mmusr = val; break; ! 35: case 0x806: regs.urp = val; break; ! 36: case 0x807: regs.srp = val; break; ! 37: case 0x808: regs.pcr = val; break; ! 38: } ! 39: } ! 40: ! 41: uae_u32 val_move2c (int regno) ! 42: { ! 43: switch (regno) { ! 44: case 0: return regs.sfc; ! 45: case 1: return regs.dfc; ! 46: case 2: return regs.cacr; ! 47: case 3: return regs.tcr; ! 48: case 4: return regs.itt0; ! 49: case 5: return regs.itt1; ! 50: case 6: return regs.dtt0; ! 51: case 7: return regs.dtt1; ! 52: case 8: return regs.buscr; ! 53: case 0x800: return regs.usp; ! 54: case 0x801: return regs.vbr; ! 55: case 0x802: return regs.caar; ! 56: case 0x803: return regs.msp; ! 57: case 0x804: return regs.isp; ! 58: case 0x805: return regs.mmusr; ! 59: case 0x806: return regs.urp; ! 60: case 0x807: return regs.srp; ! 61: case 0x808: return regs.pcr; ! 62: default: return 0; ! 63: } ! 64: } ! 65: ! 66: ! 67: #ifndef CPUEMU_68000_ONLY ! 68: ! 69: int movec_illg (int regno) ! 70: { ! 71: int regno2 = regno & 0x7ff; ! 72: ! 73: if (currprefs.cpu_model == 68060) { ! 74: if (regno <= 8) ! 75: return 0; ! 76: if (regno == 0x800 || regno == 0x801 || ! 77: regno == 0x806 || regno == 0x807 || regno == 0x808) ! 78: return 0; ! 79: return 1; ! 80: } else if (currprefs.cpu_model == 68010) { ! 81: if (regno2 < 2) ! 82: return 0; ! 83: return 1; ! 84: } else if (currprefs.cpu_model == 68020) { ! 85: if (regno == 3) ! 86: return 1; /* 68040/060 only */ ! 87: /* 4 is >=68040, but 0x804 is in 68020 */ ! 88: if (regno2 < 4 || regno == 0x804) ! 89: return 0; ! 90: return 1; ! 91: } else if (currprefs.cpu_model == 68030) { ! 92: if (regno2 <= 2) ! 93: return 0; ! 94: if (regno == 0x803 || regno == 0x804) ! 95: return 0; ! 96: return 1; ! 97: } else if (currprefs.cpu_model == 68040) { ! 98: if (regno == 0x802) ! 99: return 1; /* 68020/030 only */ ! 100: if (regno2 < 8) return 0; ! 101: return 1; ! 102: } ! 103: return 1; ! 104: } ! 105: ! 106: int m68k_move2c (int regno, uae_u32 *regp) ! 107: { ! 108: #if MOVEC_DEBUG > 0 ! 109: write_log (_T("move2c %04X <- %08X PC=%x\n"), regno, *regp, M68K_GETPC); ! 110: #endif ! 111: if (movec_illg (regno)) { ! 112: op_illg (0x4E7B); ! 113: return 0; ! 114: } else { ! 115: switch (regno) { ! 116: case 0: regs.sfc = *regp & 7; break; ! 117: case 1: regs.dfc = *regp & 7; break; ! 118: case 2: ! 119: { ! 120: uae_u32 cacr_mask = 0; ! 121: if (currprefs.cpu_model == 68020) ! 122: cacr_mask = 0x0000000f; ! 123: else if (currprefs.cpu_model == 68030) ! 124: cacr_mask = 0x00003f1f; ! 125: else if (currprefs.cpu_model == 68040) ! 126: cacr_mask = 0x80008000; ! 127: else if (currprefs.cpu_model == 68060) ! 128: cacr_mask = 0xf8e0e000; ! 129: regs.cacr = *regp & cacr_mask; ! 130: set_cpu_caches (false); ! 131: } ! 132: break; ! 133: /* 68040/060 only */ ! 134: case 3: ! 135: regs.tcr = *regp & (currprefs.cpu_model == 68060 ? 0xfffe : 0xc000); ! 136: if (currprefs.mmu_model) ! 137: mmu_set_tc (regs.tcr); ! 138: break; ! 139: ! 140: /* no differences between 68040 and 68060 */ ! 141: case 4: regs.itt0 = *regp & 0xffffe364; mmu_tt_modified (); break; ! 142: case 5: regs.itt1 = *regp & 0xffffe364; mmu_tt_modified (); break; ! 143: case 6: regs.dtt0 = *regp & 0xffffe364; mmu_tt_modified (); break; ! 144: case 7: regs.dtt1 = *regp & 0xffffe364; mmu_tt_modified (); break; ! 145: /* 68060 only */ ! 146: case 8: regs.buscr = *regp & 0xf0000000; break; ! 147: ! 148: case 0x800: regs.usp = *regp; break; ! 149: case 0x801: regs.vbr = *regp; break; ! 150: case 0x802: regs.caar = *regp; break; ! 151: case 0x803: regs.msp = *regp; if (regs.m == 1) m68k_areg (regs, 7) = regs.msp; break; ! 152: case 0x804: regs.isp = *regp; if (regs.m == 0) m68k_areg (regs, 7) = regs.isp; break; ! 153: /* 68040 only */ ! 154: case 0x805: regs.mmusr = *regp; break; ! 155: /* 68040/060 */ ! 156: case 0x806: regs.urp = *regp & 0xfffffe00; break; ! 157: case 0x807: regs.srp = *regp & 0xfffffe00; break; ! 158: /* 68060 only */ ! 159: case 0x808: ! 160: { ! 161: uae_u32 opcr = regs.pcr; ! 162: regs.pcr &= ~(0x40 | 2 | 1); ! 163: regs.pcr |= (*regp) & (0x40 | 2 | 1); ! 164: if (currprefs.fpu_model <= 0) ! 165: regs.pcr |= 2; ! 166: if (((opcr ^ regs.pcr) & 2) == 2) { ! 167: //write_log (_T("68060 FPU state: %s\n"), regs.pcr & 2 ? _T("disabled") : _T("enabled")); ! 168: /* flush possible already translated FPU instructions */ ! 169: flush_icache (0, 3); ! 170: } ! 171: } ! 172: break; ! 173: default: ! 174: op_illg (0x4E7B); ! 175: return 0; ! 176: } ! 177: } ! 178: return 1; ! 179: } ! 180: ! 181: int m68k_movec2 (int regno, uae_u32 *regp) ! 182: { ! 183: #if MOVEC_DEBUG > 0 ! 184: write_log (_T("movec2 %04X PC=%x\n"), regno, M68K_GETPC); ! 185: #endif ! 186: if (movec_illg (regno)) { ! 187: op_illg (0x4E7A); ! 188: return 0; ! 189: } else { ! 190: switch (regno) { ! 191: case 0: *regp = regs.sfc; break; ! 192: case 1: *regp = regs.dfc; break; ! 193: case 2: ! 194: { ! 195: uae_u32 v = regs.cacr; ! 196: uae_u32 cacr_mask = 0; ! 197: if (currprefs.cpu_model == 68020) ! 198: cacr_mask = 0x00000003; ! 199: else if (currprefs.cpu_model == 68030) ! 200: cacr_mask = 0x00003313; ! 201: else if (currprefs.cpu_model == 68040) ! 202: cacr_mask = 0x80008000; ! 203: else if (currprefs.cpu_model == 68060) ! 204: cacr_mask = 0xf880e000; ! 205: *regp = v & cacr_mask; ! 206: } ! 207: break; ! 208: case 3: *regp = regs.tcr; break; ! 209: case 4: *regp = regs.itt0; break; ! 210: case 5: *regp = regs.itt1; break; ! 211: case 6: *regp = regs.dtt0; break; ! 212: case 7: *regp = regs.dtt1; break; ! 213: case 8: *regp = regs.buscr; break; ! 214: ! 215: case 0x800: *regp = regs.usp; break; ! 216: case 0x801: *regp = regs.vbr; break; ! 217: case 0x802: *regp = regs.caar; break; ! 218: case 0x803: *regp = regs.m == 1 ? m68k_areg (regs, 7) : regs.msp; break; ! 219: case 0x804: *regp = regs.m == 0 ? m68k_areg (regs, 7) : regs.isp; break; ! 220: case 0x805: *regp = regs.mmusr; break; ! 221: case 0x806: *regp = regs.urp; break; ! 222: case 0x807: *regp = regs.srp; break; ! 223: case 0x808: *regp = regs.pcr; break; ! 224: ! 225: default: ! 226: op_illg (0x4E7A); ! 227: return 0; ! 228: } ! 229: } ! 230: #if MOVEC_DEBUG > 0 ! 231: write_log (_T("-> %08X\n"), *regp); ! 232: #endif ! 233: return 1; ! 234: } ! 235: ! 236: #endif ! 237: ! 238: /* ! 239: * extract bitfield data from memory and return it in the MSBs ! 240: * bdata caches the unmodified data for put_bitfield() ! 241: */ ! 242: uae_u32 REGPARAM2 get_bitfield (uae_u32 src, uae_u32 bdata[2], uae_s32 offset, int width) ! 243: { ! 244: uae_u32 tmp, res, mask; ! 245: ! 246: offset &= 7; ! 247: mask = 0xffffffffu << (32 - width); ! 248: switch ((offset + width + 7) >> 3) { ! 249: case 1: ! 250: tmp = get_byte (src); ! 251: res = tmp << (24 + offset); ! 252: bdata[0] = tmp & ~(mask >> (24 + offset)); ! 253: break; ! 254: case 2: ! 255: tmp = get_word (src); ! 256: res = tmp << (16 + offset); ! 257: bdata[0] = tmp & ~(mask >> (16 + offset)); ! 258: break; ! 259: case 3: ! 260: tmp = get_word (src); ! 261: res = tmp << (16 + offset); ! 262: bdata[0] = tmp & ~(mask >> (16 + offset)); ! 263: tmp = get_byte (src + 2); ! 264: res |= tmp << (8 + offset); ! 265: bdata[1] = tmp & ~(mask >> (8 + offset)); ! 266: break; ! 267: case 4: ! 268: tmp = get_long (src); ! 269: res = tmp << offset; ! 270: bdata[0] = tmp & ~(mask >> offset); ! 271: break; ! 272: case 5: ! 273: tmp = get_long (src); ! 274: res = tmp << offset; ! 275: bdata[0] = tmp & ~(mask >> offset); ! 276: tmp = get_byte (src + 4); ! 277: res |= tmp >> (8 - offset); ! 278: bdata[1] = tmp & ~(mask << (8 - offset)); ! 279: break; ! 280: default: ! 281: /* Panic? */ ! 282: //write_log (_T("get_bitfield() can't happen %d\n"), (offset + width + 7) >> 3); ! 283: res = 0; ! 284: break; ! 285: } ! 286: return res; ! 287: } ! 288: /* ! 289: * write bitfield data (in the LSBs) back to memory, upper bits ! 290: * must be cleared already. ! 291: */ ! 292: void REGPARAM2 put_bitfield (uae_u32 dst, uae_u32 bdata[2], uae_u32 val, uae_s32 offset, int width) ! 293: { ! 294: offset = (offset & 7) + width; ! 295: switch ((offset + 7) >> 3) { ! 296: case 1: ! 297: put_byte (dst, bdata[0] | (val << (8 - offset))); ! 298: break; ! 299: case 2: ! 300: put_word (dst, bdata[0] | (val << (16 - offset))); ! 301: break; ! 302: case 3: ! 303: put_word (dst, bdata[0] | (val >> (offset - 16))); ! 304: put_byte (dst + 2, bdata[1] | (val << (24 - offset))); ! 305: break; ! 306: case 4: ! 307: put_long (dst, bdata[0] | (val << (32 - offset))); ! 308: break; ! 309: case 5: ! 310: put_long (dst, bdata[0] | (val >> (offset - 32))); ! 311: put_byte (dst + 4, bdata[1] | (val << (40 - offset))); ! 312: break; ! 313: default: ! 314: //write_log (_T("put_bitfield() can't happen %d\n"), (offset + 7) >> 3); ! 315: break; ! 316: } ! 317: } ! 318: ! 319: uae_u32 REGPARAM2 x_get_bitfield (uae_u32 src, uae_u32 bdata[2], uae_s32 offset, int width) ! 320: { ! 321: uae_u32 tmp1, tmp2, res, mask; ! 322: ! 323: offset &= 7; ! 324: mask = 0xffffffffu << (32 - width); ! 325: switch ((offset + width + 7) >> 3) { ! 326: case 1: ! 327: tmp1 = x_cp_get_byte (src); ! 328: res = tmp1 << (24 + offset); ! 329: bdata[0] = tmp1 & ~(mask >> (24 + offset)); ! 330: break; ! 331: case 2: ! 332: tmp1 = x_cp_get_word (src); ! 333: res = tmp1 << (16 + offset); ! 334: bdata[0] = tmp1 & ~(mask >> (16 + offset)); ! 335: break; ! 336: case 3: ! 337: tmp1 = x_cp_get_word (src); ! 338: tmp2 = x_cp_get_byte (src + 2); ! 339: res = tmp1 << (16 + offset); ! 340: bdata[0] = tmp1 & ~(mask >> (16 + offset)); ! 341: res |= tmp2 << (8 + offset); ! 342: bdata[1] = tmp2 & ~(mask >> (8 + offset)); ! 343: break; ! 344: case 4: ! 345: tmp1 = x_cp_get_long (src); ! 346: res = tmp1 << offset; ! 347: bdata[0] = tmp1 & ~(mask >> offset); ! 348: break; ! 349: case 5: ! 350: tmp1 = x_cp_get_long (src); ! 351: tmp2 = x_cp_get_byte (src + 4); ! 352: res = tmp1 << offset; ! 353: bdata[0] = tmp1 & ~(mask >> offset); ! 354: res |= tmp2 >> (8 - offset); ! 355: bdata[1] = tmp2 & ~(mask << (8 - offset)); ! 356: break; ! 357: default: ! 358: /* Panic? */ ! 359: //write_log (_T("x_get_bitfield() can't happen %d\n"), (offset + width + 7) >> 3); ! 360: res = 0; ! 361: break; ! 362: } ! 363: return res; ! 364: } ! 365: ! 366: void REGPARAM2 x_put_bitfield (uae_u32 dst, uae_u32 bdata[2], uae_u32 val, uae_s32 offset, int width) ! 367: { ! 368: offset = (offset & 7) + width; ! 369: switch ((offset + 7) >> 3) { ! 370: case 1: ! 371: x_cp_put_byte (dst, bdata[0] | (val << (8 - offset))); ! 372: break; ! 373: case 2: ! 374: x_cp_put_word (dst, bdata[0] | (val << (16 - offset))); ! 375: break; ! 376: case 3: ! 377: x_cp_put_word (dst, bdata[0] | (val >> (offset - 16))); ! 378: x_cp_put_byte (dst + 2, bdata[1] | (val << (24 - offset))); ! 379: break; ! 380: case 4: ! 381: x_cp_put_long (dst, bdata[0] | (val << (32 - offset))); ! 382: break; ! 383: case 5: ! 384: x_cp_put_long (dst, bdata[0] | (val >> (offset - 32))); ! 385: x_cp_put_byte (dst + 4, bdata[1] | (val << (40 - offset))); ! 386: break; ! 387: default: ! 388: //write_log (_T("x_put_bitfield() can't happen %d\n"), (offset + 7) >> 3); ! 389: break; ! 390: } ! 391: } ! 392: ! 393: uae_u32 REGPARAM2 get_disp_ea_020 (uae_u32 base, int idx) ! 394: { ! 395: uae_u16 dp = next_iword (); ! 396: int reg = (dp >> 12) & 15; ! 397: uae_s32 regd = regs.regs[reg]; ! 398: if ((dp & 0x800) == 0) ! 399: regd = (uae_s32)(uae_s16)regd; ! 400: regd <<= (dp >> 9) & 3; ! 401: if (dp & 0x100) { ! 402: uae_s32 outer = 0; ! 403: if (dp & 0x80) base = 0; ! 404: if (dp & 0x40) regd = 0; ! 405: ! 406: if ((dp & 0x30) == 0x20) ! 407: base += (uae_s32)(uae_s16) next_iword (); ! 408: if ((dp & 0x30) == 0x30) ! 409: base += next_ilong (); ! 410: ! 411: if ((dp & 0x3) == 0x2) ! 412: outer = (uae_s32)(uae_s16) next_iword (); ! 413: if ((dp & 0x3) == 0x3) ! 414: outer = next_ilong (); ! 415: ! 416: if ((dp & 0x4) == 0) ! 417: base += regd; ! 418: if (dp & 0x3) ! 419: base = get_long (base); ! 420: if (dp & 0x4) ! 421: base += regd; ! 422: ! 423: return base + outer; ! 424: } else { ! 425: return base + (uae_s32)((uae_s8)dp) + regd; ! 426: } ! 427: } ! 428: ! 429: uae_u32 REGPARAM2 x_get_disp_ea_020 (uae_u32 base, int idx) ! 430: { ! 431: uae_u16 dp = x_next_iword (); ! 432: int reg = (dp >> 12) & 15; ! 433: int cycles = 0; ! 434: uae_u32 v; ! 435: ! 436: uae_s32 regd = regs.regs[reg]; ! 437: if ((dp & 0x800) == 0) ! 438: regd = (uae_s32)(uae_s16)regd; ! 439: regd <<= (dp >> 9) & 3; ! 440: if (dp & 0x100) { ! 441: uae_s32 outer = 0; ! 442: if (dp & 0x80) ! 443: base = 0; ! 444: if (dp & 0x40) ! 445: regd = 0; ! 446: ! 447: if ((dp & 0x30) == 0x20) { ! 448: base += (uae_s32)(uae_s16) x_next_iword (); ! 449: cycles++; ! 450: } ! 451: if ((dp & 0x30) == 0x30) { ! 452: base += x_next_ilong (); ! 453: cycles++; ! 454: } ! 455: ! 456: if ((dp & 0x3) == 0x2) { ! 457: outer = (uae_s32)(uae_s16) x_next_iword (); ! 458: cycles++; ! 459: } ! 460: if ((dp & 0x3) == 0x3) { ! 461: outer = x_next_ilong (); ! 462: cycles++; ! 463: } ! 464: ! 465: if ((dp & 0x4) == 0) { ! 466: base += regd; ! 467: cycles++; ! 468: } ! 469: if (dp & 0x3) { ! 470: base = x_get_long (base); ! 471: cycles++; ! 472: } ! 473: if (dp & 0x4) { ! 474: base += regd; ! 475: cycles++; ! 476: } ! 477: v = base + outer; ! 478: } else { ! 479: v = base + (uae_s32)((uae_s8)dp) + regd; ! 480: } ! 481: // if (cycles && currprefs.cpu_cycle_exact) ! 482: // x_do_cycles (cycles * cpucycleunit); ! 483: return v; ! 484: } ! 485: ! 486: uae_u32 REGPARAM2 x_get_disp_ea_ce030 (uae_u32 base, int idx) ! 487: { ! 488: uae_u16 dp = next_iword_030ce (); ! 489: int reg = (dp >> 12) & 15; ! 490: uae_u32 v; ! 491: ! 492: uae_s32 regd = regs.regs[reg]; ! 493: if ((dp & 0x800) == 0) ! 494: regd = (uae_s32)(uae_s16)regd; ! 495: regd <<= (dp >> 9) & 3; ! 496: if (dp & 0x100) { ! 497: uae_s32 outer = 0; ! 498: if (dp & 0x80) ! 499: base = 0; ! 500: if (dp & 0x40) ! 501: regd = 0; ! 502: ! 503: if ((dp & 0x30) == 0x20) { ! 504: base += (uae_s32)(uae_s16) next_iword_030ce (); ! 505: } ! 506: if ((dp & 0x30) == 0x30) { ! 507: base += next_ilong_030ce (); ! 508: } ! 509: ! 510: if ((dp & 0x3) == 0x2) { ! 511: outer = (uae_s32)(uae_s16) next_iword_030ce (); ! 512: } ! 513: if ((dp & 0x3) == 0x3) { ! 514: outer = next_ilong_030ce (); ! 515: } ! 516: ! 517: if ((dp & 0x4) == 0) { ! 518: base += regd; ! 519: } ! 520: if (dp & 0x3) { ! 521: base = x_get_long (base); ! 522: } ! 523: if (dp & 0x4) { ! 524: base += regd; ! 525: } ! 526: v = base + outer; ! 527: } else { ! 528: v = base + (uae_s32)((uae_s8)dp) + regd; ! 529: } ! 530: return v; ! 531: } ! 532: ! 533: uae_u32 REGPARAM2 x_get_disp_ea_ce020 (uae_u32 base, int idx) ! 534: { ! 535: uae_u16 dp = next_iword_020ce (); ! 536: int reg = (dp >> 12) & 15; ! 537: uae_u32 v; ! 538: ! 539: uae_s32 regd = regs.regs[reg]; ! 540: if ((dp & 0x800) == 0) ! 541: regd = (uae_s32)(uae_s16)regd; ! 542: regd <<= (dp >> 9) & 3; ! 543: if (dp & 0x100) { ! 544: uae_s32 outer = 0; ! 545: if (dp & 0x80) ! 546: base = 0; ! 547: if (dp & 0x40) ! 548: regd = 0; ! 549: ! 550: if ((dp & 0x30) == 0x20) { ! 551: base += (uae_s32)(uae_s16) next_iword_020ce (); ! 552: } ! 553: if ((dp & 0x30) == 0x30) { ! 554: base += next_ilong_020ce (); ! 555: } ! 556: ! 557: if ((dp & 0x3) == 0x2) { ! 558: outer = (uae_s32)(uae_s16) next_iword_020ce (); ! 559: } ! 560: if ((dp & 0x3) == 0x3) { ! 561: outer = next_ilong_020ce (); ! 562: } ! 563: ! 564: if ((dp & 0x4) == 0) { ! 565: base += regd; ! 566: } ! 567: if (dp & 0x3) { ! 568: base = x_get_long (base); ! 569: } ! 570: if (dp & 0x4) { ! 571: base += regd; ! 572: } ! 573: v = base + outer; ! 574: } else { ! 575: v = base + (uae_s32)((uae_s8)dp) + regd; ! 576: } ! 577: return v; ! 578: } ! 579: ! 580: ! 581: /* ! 582: * Compute exact number of CPU cycles taken ! 583: * by DIVU and DIVS on a 68000 processor. ! 584: * ! 585: * Copyright (c) 2005 by Jorge Cwik, [email protected] ! 586: * ! 587: * This is free software; you can redistribute it and/or modify ! 588: * it under the terms of the GNU General Public License as published by ! 589: * the Free Software Foundation; either version 2 of the License, or ! 590: * (at your option) any later version. ! 591: * ! 592: * This software is distributed in the hope that it will be useful, ! 593: * but WITHOUT ANY WARRANTY; without even the implied warranty of ! 594: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 595: * GNU General Public License for more details. ! 596: * ! 597: * You should have received a copy of the GNU General Public License ! 598: * along with this software; if not, write to the Free Software ! 599: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ! 600: * ! 601: */ ! 602: ! 603: ! 604: /* ! 605: ! 606: The routines below take dividend and divisor as parameters. ! 607: They return 0 if division by zero, or exact number of cycles otherwise. ! 608: ! 609: The number of cycles returned assumes a register operand. ! 610: Effective address time must be added if memory operand. ! 611: ! 612: For 68000 only (not 68010, 68012, 68020, etc). ! 613: Probably valid for 68008 after adding the extra prefetch cycle. ! 614: ! 615: ! 616: Best and worst cases for register operand: ! 617: (Note the difference with the documented range.) ! 618: ! 619: ! 620: DIVU: ! 621: ! 622: Overflow (always): 10 cycles. ! 623: Worst case: 136 cycles. ! 624: Best case: 76 cycles. ! 625: ! 626: ! 627: DIVS: ! 628: ! 629: Absolute overflow: 16-18 cycles. ! 630: Signed overflow is not detected prematurely. ! 631: ! 632: Worst case: 156 cycles. ! 633: Best case without signed overflow: 122 cycles. ! 634: Best case with signed overflow: 120 cycles ! 635: ! 636: ! 637: */ ! 638: ! 639: int getDivu68kCycles (uae_u32 dividend, uae_u16 divisor) ! 640: { ! 641: int mcycles; ! 642: uae_u32 hdivisor; ! 643: int i; ! 644: ! 645: if (divisor == 0) ! 646: return 0; ! 647: ! 648: // Overflow ! 649: if ((dividend >> 16) >= divisor) ! 650: return (mcycles = 5) * 2; ! 651: ! 652: mcycles = 38; ! 653: hdivisor = divisor << 16; ! 654: ! 655: for (i = 0; i < 15; i++) { ! 656: uae_u32 temp; ! 657: temp = dividend; ! 658: ! 659: dividend <<= 1; ! 660: ! 661: // If carry from shift ! 662: if ((uae_s32)temp < 0) ! 663: dividend -= hdivisor; ! 664: else { ! 665: mcycles += 2; ! 666: if (dividend >= hdivisor) { ! 667: dividend -= hdivisor; ! 668: mcycles--; ! 669: } ! 670: } ! 671: } ! 672: return mcycles * 2; ! 673: } ! 674: ! 675: int getDivs68kCycles (uae_s32 dividend, uae_s16 divisor) ! 676: { ! 677: int mcycles; ! 678: uae_u32 aquot; ! 679: int i; ! 680: ! 681: if (divisor == 0) ! 682: return 0; ! 683: ! 684: mcycles = 6; ! 685: ! 686: if (dividend < 0) ! 687: mcycles++; ! 688: ! 689: // Check for absolute overflow ! 690: if (((uae_u32)abs (dividend) >> 16) >= (uae_u16)abs (divisor)) ! 691: return (mcycles + 2) * 2; ! 692: ! 693: // Absolute quotient ! 694: aquot = (uae_u32) abs (dividend) / (uae_u16)abs (divisor); ! 695: ! 696: mcycles += 55; ! 697: ! 698: if (divisor >= 0) { ! 699: if (dividend >= 0) ! 700: mcycles--; ! 701: else ! 702: mcycles++; ! 703: } ! 704: ! 705: // Count 15 msbits in absolute of quotient ! 706: ! 707: for (i = 0; i < 15; i++) { ! 708: if ((uae_s16)aquot >= 0) ! 709: mcycles++; ! 710: aquot <<= 1; ! 711: } ! 712: ! 713: return mcycles * 2; ! 714: } ! 715: ! 716: /* 68000 Z=1. NVC=0 ! 717: * 68020 and 68030: Signed: Z=1 NVC=0. Unsigned: V=1, N<dst, Z=!N, C=0. ! 718: * 68040/68060 C=0. ! 719: */ ! 720: void divbyzero_special (bool issigned, uae_s32 dst) ! 721: { ! 722: if (currprefs.cpu_model == 68020 || currprefs.cpu_model == 68030) { ! 723: CLEAR_CZNV (); ! 724: if (issigned == false) { ! 725: if (dst < 0) ! 726: SET_NFLG (1); ! 727: SET_ZFLG (!GET_NFLG ()); ! 728: SET_VFLG (1); ! 729: } else { ! 730: SET_ZFLG (1); ! 731: } ! 732: } else if (currprefs.cpu_model >= 68040) { ! 733: SET_CFLG (0); ! 734: } else { ! 735: // 68000/010 ! 736: CLEAR_CZNV (); ! 737: } ! 738: } ! 739: ! 740: #ifndef CPUEMU_68000_ONLY ! 741: ! 742: STATIC_INLINE int div_unsigned (uae_u32 src_hi, uae_u32 src_lo, uae_u32 div, uae_u32 *quot, uae_u32 *rem) ! 743: { ! 744: uae_u32 q = 0, cbit = 0; ! 745: int i; ! 746: ! 747: if (div <= src_hi) { ! 748: return 1; ! 749: } ! 750: for (i = 0 ; i < 32 ; i++) { ! 751: cbit = src_hi & 0x80000000ul; ! 752: src_hi <<= 1; ! 753: if (src_lo & 0x80000000ul) src_hi++; ! 754: src_lo <<= 1; ! 755: q = q << 1; ! 756: if (cbit || div <= src_hi) { ! 757: q |= 1; ! 758: src_hi -= div; ! 759: } ! 760: } ! 761: *quot = q; ! 762: *rem = src_hi; ! 763: return 0; ! 764: } ! 765: ! 766: bool m68k_divl (uae_u32 opcode, uae_u32 src, uae_u16 extra) ! 767: { ! 768: if ((extra & 0x400) && currprefs.int_no_unimplemented && currprefs.cpu_model == 68060) { ! 769: op_unimpl (opcode); ! 770: return false; ! 771: } ! 772: if (src == 0) { ! 773: Exception (5); ! 774: return false; ! 775: } ! 776: #if defined (uae_s64) ! 777: if (extra & 0x800) { ! 778: /* signed variant */ ! 779: uae_s64 a = (uae_s64)(uae_s32)m68k_dreg (regs, (extra >> 12) & 7); ! 780: uae_s64 quot, rem; ! 781: ! 782: if (extra & 0x400) { ! 783: a &= 0xffffffffu; ! 784: a |= (uae_s64)m68k_dreg (regs, extra & 7) << 32; ! 785: } ! 786: ! 787: if (a == 0x8000000000000000 && src == -1) { ! 788: SET_VFLG (1); ! 789: SET_NFLG (1); ! 790: SET_CFLG (0); ! 791: } else { ! 792: rem = a % (uae_s64)(uae_s32)src; ! 793: quot = a / (uae_s64)(uae_s32)src; ! 794: if ((quot & UVAL64 (0xffffffff80000000)) != 0 ! 795: && (quot & UVAL64 (0xffffffff80000000)) != UVAL64 (0xffffffff80000000)) ! 796: { ! 797: SET_VFLG (1); ! 798: SET_NFLG (1); ! 799: SET_CFLG (0); ! 800: } else { ! 801: if (((uae_s32)rem < 0) != ((uae_s64)a < 0)) rem = -rem; ! 802: SET_VFLG (0); ! 803: SET_CFLG (0); ! 804: SET_ZFLG (((uae_s32)quot) == 0); ! 805: SET_NFLG (((uae_s32)quot) < 0); ! 806: m68k_dreg (regs, extra & 7) = (uae_u32)rem; ! 807: m68k_dreg (regs, (extra >> 12) & 7) = (uae_u32)quot; ! 808: } ! 809: } ! 810: } else { ! 811: /* unsigned */ ! 812: uae_u64 a = (uae_u64)(uae_u32)m68k_dreg (regs, (extra >> 12) & 7); ! 813: uae_u64 quot, rem; ! 814: ! 815: if (extra & 0x400) { ! 816: a &= 0xffffffffu; ! 817: a |= (uae_u64)m68k_dreg (regs, extra & 7) << 32; ! 818: } ! 819: rem = a % (uae_u64)src; ! 820: quot = a / (uae_u64)src; ! 821: if (quot > 0xffffffffu) { ! 822: SET_VFLG (1); ! 823: SET_NFLG (1); ! 824: SET_CFLG (0); ! 825: } else { ! 826: SET_VFLG (0); ! 827: SET_CFLG (0); ! 828: SET_ZFLG (((uae_s32)quot) == 0); ! 829: SET_NFLG (((uae_s32)quot) < 0); ! 830: m68k_dreg (regs, extra & 7) = (uae_u32)rem; ! 831: m68k_dreg (regs, (extra >> 12) & 7) = (uae_u32)quot; ! 832: } ! 833: } ! 834: #else ! 835: if (extra & 0x800) { ! 836: /* signed variant */ ! 837: uae_s32 lo = (uae_s32)m68k_dreg (regs, (extra >> 12) & 7); ! 838: uae_s32 hi = lo < 0 ? -1 : 0; ! 839: uae_s32 save_high; ! 840: uae_u32 quot, rem; ! 841: uae_u32 sign; ! 842: ! 843: if (extra & 0x400) { ! 844: hi = (uae_s32)m68k_dreg (regs, extra & 7); ! 845: } ! 846: save_high = hi; ! 847: sign = (hi ^ src); ! 848: if (hi < 0) { ! 849: hi = ~hi; ! 850: lo = -lo; ! 851: if (lo == 0) hi++; ! 852: } ! 853: if ((uae_s32)src < 0) src = -src; ! 854: if (div_unsigned (hi, lo, src, ", &rem) || ! 855: (sign & 0x80000000) ? quot > 0x80000000 : quot > 0x7fffffff) { ! 856: SET_VFLG (1); ! 857: SET_NFLG (1); ! 858: SET_CFLG (0); ! 859: } else { ! 860: if (sign & 0x80000000) quot = -quot; ! 861: if (((uae_s32)rem < 0) != (save_high < 0)) rem = -rem; ! 862: SET_VFLG (0); ! 863: SET_CFLG (0); ! 864: SET_ZFLG (((uae_s32)quot) == 0); ! 865: SET_NFLG (((uae_s32)quot) < 0); ! 866: m68k_dreg (regs, extra & 7) = rem; ! 867: m68k_dreg (regs, (extra >> 12) & 7) = quot; ! 868: } ! 869: } else { ! 870: /* unsigned */ ! 871: uae_u32 lo = (uae_u32)m68k_dreg (regs, (extra >> 12) & 7); ! 872: uae_u32 hi = 0; ! 873: uae_u32 quot, rem; ! 874: ! 875: if (extra & 0x400) { ! 876: hi = (uae_u32)m68k_dreg (regs, extra & 7); ! 877: } ! 878: if (div_unsigned (hi, lo, src, ", &rem)) { ! 879: SET_VFLG (1); ! 880: SET_NFLG (1); ! 881: SET_CFLG (0); ! 882: } else { ! 883: SET_VFLG (0); ! 884: SET_CFLG (0); ! 885: SET_ZFLG (((uae_s32)quot) == 0); ! 886: SET_NFLG (((uae_s32)quot) < 0); ! 887: m68k_dreg (regs, extra & 7) = rem; ! 888: m68k_dreg (regs, (extra >> 12) & 7) = quot; ! 889: } ! 890: } ! 891: #endif ! 892: return true; ! 893: } ! 894: ! 895: STATIC_INLINE void mul_unsigned (uae_u32 src1, uae_u32 src2, uae_u32 *dst_hi, uae_u32 *dst_lo) ! 896: { ! 897: uae_u32 r0 = (src1 & 0xffff) * (src2 & 0xffff); ! 898: uae_u32 r1 = ((src1 >> 16) & 0xffff) * (src2 & 0xffff); ! 899: uae_u32 r2 = (src1 & 0xffff) * ((src2 >> 16) & 0xffff); ! 900: uae_u32 r3 = ((src1 >> 16) & 0xffff) * ((src2 >> 16) & 0xffff); ! 901: uae_u32 lo; ! 902: ! 903: lo = r0 + ((r1 << 16) & 0xffff0000ul); ! 904: if (lo < r0) r3++; ! 905: r0 = lo; ! 906: lo = r0 + ((r2 << 16) & 0xffff0000ul); ! 907: if (lo < r0) r3++; ! 908: r3 += ((r1 >> 16) & 0xffff) + ((r2 >> 16) & 0xffff); ! 909: *dst_lo = lo; ! 910: *dst_hi = r3; ! 911: } ! 912: ! 913: bool m68k_mull (uae_u32 opcode, uae_u32 src, uae_u16 extra) ! 914: { ! 915: if ((extra & 0x400) && currprefs.int_no_unimplemented && currprefs.cpu_model == 68060) { ! 916: op_unimpl (opcode); ! 917: return false; ! 918: } ! 919: #if defined (uae_s64) ! 920: if (extra & 0x800) { ! 921: /* signed variant */ ! 922: uae_s64 a = (uae_s64)(uae_s32)m68k_dreg (regs, (extra >> 12) & 7); ! 923: ! 924: a *= (uae_s64)(uae_s32)src; ! 925: SET_VFLG (0); ! 926: SET_CFLG (0); ! 927: SET_ZFLG (a == 0); ! 928: SET_NFLG (a < 0); ! 929: if (extra & 0x400) ! 930: m68k_dreg (regs, extra & 7) = (uae_u32)(a >> 32); ! 931: else if ((a & UVAL64 (0xffffffff80000000)) != 0 ! 932: && (a & UVAL64 (0xffffffff80000000)) != UVAL64 (0xffffffff80000000)) ! 933: { ! 934: SET_VFLG (1); ! 935: } ! 936: m68k_dreg (regs, (extra >> 12) & 7) = (uae_u32)a; ! 937: } else { ! 938: /* unsigned */ ! 939: uae_u64 a = (uae_u64)(uae_u32)m68k_dreg (regs, (extra >> 12) & 7); ! 940: ! 941: a *= (uae_u64)src; ! 942: SET_VFLG (0); ! 943: SET_CFLG (0); ! 944: SET_ZFLG (a == 0); ! 945: SET_NFLG (((uae_s64)a) < 0); ! 946: if (extra & 0x400) ! 947: m68k_dreg (regs, extra & 7) = (uae_u32)(a >> 32); ! 948: else if ((a & UVAL64 (0xffffffff00000000)) != 0) { ! 949: SET_VFLG (1); ! 950: } ! 951: m68k_dreg (regs, (extra >> 12) & 7) = (uae_u32)a; ! 952: } ! 953: #else ! 954: if (extra & 0x800) { ! 955: /* signed variant */ ! 956: uae_s32 src1, src2; ! 957: uae_u32 dst_lo, dst_hi; ! 958: uae_u32 sign; ! 959: ! 960: src1 = (uae_s32)src; ! 961: src2 = (uae_s32)m68k_dreg (regs, (extra >> 12) & 7); ! 962: sign = (src1 ^ src2); ! 963: if (src1 < 0) src1 = -src1; ! 964: if (src2 < 0) src2 = -src2; ! 965: mul_unsigned ((uae_u32)src1, (uae_u32)src2, &dst_hi, &dst_lo); ! 966: if (sign & 0x80000000) { ! 967: dst_hi = ~dst_hi; ! 968: dst_lo = -dst_lo; ! 969: if (dst_lo == 0) dst_hi++; ! 970: } ! 971: SET_VFLG (0); ! 972: SET_CFLG (0); ! 973: SET_ZFLG (dst_hi == 0 && dst_lo == 0); ! 974: SET_NFLG (((uae_s32)dst_hi) < 0); ! 975: if (extra & 0x400) ! 976: m68k_dreg (regs, extra & 7) = dst_hi; ! 977: else if ((dst_hi != 0 || (dst_lo & 0x80000000) != 0) ! 978: && ((dst_hi & 0xffffffff) != 0xffffffff ! 979: || (dst_lo & 0x80000000) != 0x80000000)) ! 980: { ! 981: SET_VFLG (1); ! 982: } ! 983: m68k_dreg (regs, (extra >> 12) & 7) = dst_lo; ! 984: } else { ! 985: /* unsigned */ ! 986: uae_u32 dst_lo, dst_hi; ! 987: ! 988: mul_unsigned (src, (uae_u32)m68k_dreg (regs, (extra >> 12) & 7), &dst_hi, &dst_lo); ! 989: ! 990: SET_VFLG (0); ! 991: SET_CFLG (0); ! 992: SET_ZFLG (dst_hi == 0 && dst_lo == 0); ! 993: SET_NFLG (((uae_s32)dst_hi) < 0); ! 994: if (extra & 0x400) ! 995: m68k_dreg (regs, extra & 7) = dst_hi; ! 996: else if (dst_hi != 0) { ! 997: SET_VFLG (1); ! 998: } ! 999: m68k_dreg (regs, (extra >> 12) & 7) = dst_lo; ! 1000: } ! 1001: #endif ! 1002: return true; ! 1003: } ! 1004: ! 1005: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.