|
|
1.1 ! root 1: /* ! 2: * UAE - The Un*x Amiga Emulator ! 3: * ! 4: * MC68000 emulation ! 5: * ! 6: * (c) 1995 Bernd Schmidt ! 7: */ ! 8: ! 9: #include "sysdeps.h" ! 10: #include "hatari-glue.h" ! 11: #include "maccess.h" ! 12: #include "memory.h" ! 13: #include "newcpu.h" ! 14: #include "compiler.h" ! 15: #include "events.h" ! 16: #include "../includes/tos.h" ! 17: /* ! 18: #include "sysconfig.h" ! 19: #include "config.h" ! 20: #include "options.h" ! 21: #include "uae.h" ! 22: #include "autoconf.h" ! 23: #include "debug.h" ! 24: */ ! 25: ! 26: /*int crashtrace=0;*/ ! 27: ! 28: int quit_program = 0; ! 29: int debugging = 0; ! 30: struct flag_struct regflags; ! 31: ! 32: /* Opcode of faulting instruction */ ! 33: uae_u16 last_op_for_exception_3; ! 34: /* PC at fault time */ ! 35: uaecptr last_addr_for_exception_3; ! 36: /* Address that generated the exception */ ! 37: uaecptr last_fault_for_exception_3; ! 38: ! 39: int areg_byteinc[] = { 1,1,1,1,1,1,1,2 }; ! 40: int imm8_table[] = { 8,1,2,3,4,5,6,7 }; ! 41: ! 42: int movem_index1[256]; ! 43: int movem_index2[256]; ! 44: int movem_next[256]; ! 45: ! 46: int fpp_movem_index1[256]; ! 47: int fpp_movem_index2[256]; ! 48: int fpp_movem_next[256]; ! 49: ! 50: cpuop_func *cpufunctbl[65536]; ! 51: ! 52: #define COUNT_INSTRS 0 ! 53: ! 54: #if COUNT_INSTRS ! 55: static unsigned long int instrcount[65536]; ! 56: static uae_u16 opcodenums[65536]; ! 57: ! 58: static int compfn (const void *el1, const void *el2) ! 59: { ! 60: return instrcount[*(const uae_u16 *)el1] < instrcount[*(const uae_u16 *)el2]; ! 61: } ! 62: ! 63: static char *icountfilename (void) ! 64: { ! 65: char *name = getenv ("INSNCOUNT"); ! 66: if (name) ! 67: return name; ! 68: return COUNT_INSTRS == 2 ? "frequent.68k" : "insncount"; ! 69: } ! 70: ! 71: void dump_counts (void) ! 72: { ! 73: FILE *f = fopen (icountfilename (), "w"); ! 74: unsigned long int total; ! 75: int i; ! 76: ! 77: write_log ("Writing instruction count file...\n"); ! 78: for (i = 0; i < 65536; i++) { ! 79: opcodenums[i] = i; ! 80: total += instrcount[i]; ! 81: } ! 82: qsort (opcodenums, 65536, sizeof(uae_u16), compfn); ! 83: ! 84: fprintf (f, "Total: %lu\n", total); ! 85: for (i=0; i < 65536; i++) { ! 86: unsigned long int cnt = instrcount[opcodenums[i]]; ! 87: struct instr *dp; ! 88: struct mnemolookup *lookup; ! 89: if (!cnt) ! 90: break; ! 91: dp = table68k + opcodenums[i]; ! 92: for (lookup = lookuptab;lookup->mnemo != dp->mnemo; lookup++) ! 93: ; ! 94: fprintf (f, "%04x: %lu %s\n", opcodenums[i], cnt, lookup->name); ! 95: } ! 96: fclose (f); ! 97: } ! 98: #else ! 99: void dump_counts (void) ! 100: { ! 101: } ! 102: #endif ! 103: ! 104: int broken_in; ! 105: ! 106: static __inline__ unsigned int cft_map (unsigned int f) ! 107: { ! 108: #ifndef HAVE_GET_WORD_UNSWAPPED ! 109: return f; ! 110: #else ! 111: return ((f >> 8) & 255) | ((f & 255) << 8); ! 112: #endif ! 113: } ! 114: ! 115: static unsigned long op_illg_1 (uae_u32 opcode) REGPARAM; ! 116: ! 117: static unsigned long REGPARAM2 op_illg_1 (uae_u32 opcode) ! 118: { ! 119: op_illg (cft_map (opcode)); ! 120: return 4; ! 121: } ! 122: ! 123: static void build_cpufunctbl (void) ! 124: { ! 125: int i; ! 126: unsigned long opcode; ! 127: struct cputbl *tbl = (cpu_level == 4 ? op_smalltbl_0_ff ! 128: : cpu_level == 3 ? op_smalltbl_1_ff ! 129: : cpu_level == 2 ? op_smalltbl_2_ff ! 130: : cpu_level == 1 ? op_smalltbl_3_ff ! 131: : ! cpu_compatible ? op_smalltbl_4_ff ! 132: : op_smalltbl_5_ff); ! 133: ! 134: write_log ("Building CPU function table (%d %d %d).\n", ! 135: cpu_level, cpu_compatible, address_space_24); ! 136: ! 137: for (opcode = 0; opcode < 65536; opcode++) ! 138: cpufunctbl[cft_map(opcode)] = op_illg_1; ! 139: for (i = 0; tbl[i].handler != NULL; i++) { ! 140: if (! tbl[i].specific) ! 141: cpufunctbl[cft_map (tbl[i].opcode)] = tbl[i].handler; ! 142: } ! 143: for (opcode = 0; opcode < 65536; opcode++) { ! 144: cpuop_func *f; ! 145: ! 146: if (table68k[opcode].mnemo == i_ILLG || table68k[opcode].clev > cpu_level) ! 147: continue; ! 148: ! 149: if (table68k[opcode].handler != -1) { ! 150: f = cpufunctbl[cft_map (table68k[opcode].handler)]; ! 151: if (f == op_illg_1) ! 152: abort(); ! 153: cpufunctbl[cft_map(opcode)] = f; ! 154: } ! 155: } ! 156: for (i = 0; tbl[i].handler != NULL; i++) { ! 157: if (tbl[i].specific) ! 158: cpufunctbl[cft_map(tbl[i].opcode)] = tbl[i].handler; ! 159: } ! 160: ! 161: /* Hataris illegal opcodes: */ ! 162: cpufunctbl[cft_map(CONDRV_OPCODE)] = OpCode_ConnectedDrive; ! 163: cpufunctbl[cft_map(TIMERD_OPCODE)] = OpCode_TimerD; ! 164: } ! 165: ! 166: unsigned long cycles_mask, cycles_val; ! 167: ! 168: static void update_68k_cycles (void) ! 169: { ! 170: cycles_mask = 0; ! 171: cycles_val = m68k_speed; ! 172: if (m68k_speed < 1) { ! 173: cycles_mask = 0xFFFFFFFF; ! 174: cycles_val = 0; ! 175: } ! 176: } ! 177: ! 178: /* ! 179: void check_prefs_changed_cpu (void) ! 180: { ! 181: if (currprefs.cpu_level != changed_prefs.cpu_level ! 182: || currprefs.cpu_compatible != changed_prefs.cpu_compatible) { ! 183: currprefs.cpu_level = changed_prefs.cpu_level; ! 184: currprefs.cpu_compatible = changed_prefs.cpu_compatible; ! 185: build_cpufunctbl (); ! 186: } ! 187: if (currprefs.m68k_speed != changed_prefs.m68k_speed) { ! 188: currprefs.m68k_speed = changed_prefs.m68k_speed; ! 189: reset_frame_rate_hack (); ! 190: update_68k_cycles (); ! 191: } ! 192: } ! 193: */ ! 194: ! 195: void init_m68k (void) ! 196: { ! 197: int i; ! 198: ! 199: update_68k_cycles (); ! 200: ! 201: for (i = 0 ; i < 256 ; i++) { ! 202: int j; ! 203: for (j = 0 ; j < 8 ; j++) { ! 204: if (i & (1 << j)) break; ! 205: } ! 206: movem_index1[i] = j; ! 207: movem_index2[i] = 7-j; ! 208: movem_next[i] = i & (~(1 << j)); ! 209: } ! 210: for (i = 0 ; i < 256 ; i++) { ! 211: int j; ! 212: for (j = 7 ; j >= 0 ; j--) { ! 213: if (i & (1 << j)) break; ! 214: } ! 215: fpp_movem_index1[i] = 7-j; ! 216: fpp_movem_index2[i] = j; ! 217: fpp_movem_next[i] = i & (~(1 << j)); ! 218: } ! 219: #if COUNT_INSTRS ! 220: { ! 221: FILE *f = fopen (icountfilename (), "r"); ! 222: memset (instrcount, 0, sizeof instrcount); ! 223: if (f) { ! 224: uae_u32 opcode, count, total; ! 225: char name[20]; ! 226: write_log ("Reading instruction count file...\n"); ! 227: fscanf (f, "Total: %lu\n", &total); ! 228: while (fscanf (f, "%lx: %lu %s\n", &opcode, &count, name) == 3) { ! 229: instrcount[opcode] = count; ! 230: } ! 231: fclose(f); ! 232: } ! 233: } ! 234: #endif ! 235: write_log ("Building CPU table for configuration: 68"); ! 236: if (address_space_24 && cpu_level > 1) ! 237: write_log ("EC"); ! 238: switch (cpu_level) { ! 239: case 1: ! 240: write_log ("010"); ! 241: break; ! 242: case 2: ! 243: write_log ("020"); ! 244: break; ! 245: case 3: ! 246: write_log ("020/881"); ! 247: break; ! 248: case 4: ! 249: /* Who is going to miss the MMU anyway...? :-) */ ! 250: write_log ("040"); ! 251: break; ! 252: default: ! 253: write_log ("000"); ! 254: break; ! 255: } ! 256: if (cpu_compatible) ! 257: write_log (" (compatible mode)"); ! 258: write_log ("\n"); ! 259: ! 260: read_table68k (); ! 261: do_merges (); ! 262: ! 263: write_log ("%d CPU functions\n", nr_cpuop_funcs); ! 264: ! 265: build_cpufunctbl (); ! 266: } ! 267: ! 268: struct regstruct regs, lastint_regs; ! 269: static struct regstruct regs_backup[16]; ! 270: static int backup_pointer = 0; ! 271: static long int m68kpc_offset; ! 272: int lastint_no; ! 273: ! 274: #define get_ibyte_1(o) get_byte(regs.pc + (regs.pc_p - regs.pc_oldp) + (o) + 1) ! 275: #define get_iword_1(o) get_word(regs.pc + (regs.pc_p - regs.pc_oldp) + (o)) ! 276: #define get_ilong_1(o) get_long(regs.pc + (regs.pc_p - regs.pc_oldp) + (o)) ! 277: ! 278: uae_s32 ShowEA (FILE *f, int reg, amodes mode, wordsizes size, char *buf) ! 279: { ! 280: uae_u16 dp; ! 281: uae_s8 disp8; ! 282: uae_s16 disp16; ! 283: int r; ! 284: uae_u32 dispreg; ! 285: uaecptr addr; ! 286: uae_s32 offset = 0; ! 287: char buffer[80]; ! 288: ! 289: switch (mode){ ! 290: case Dreg: ! 291: sprintf (buffer,"D%d", reg); ! 292: break; ! 293: case Areg: ! 294: sprintf (buffer,"A%d", reg); ! 295: break; ! 296: case Aind: ! 297: sprintf (buffer,"(A%d)", reg); ! 298: break; ! 299: case Aipi: ! 300: sprintf (buffer,"(A%d)+", reg); ! 301: break; ! 302: case Apdi: ! 303: sprintf (buffer,"-(A%d)", reg); ! 304: break; ! 305: case Ad16: ! 306: disp16 = get_iword_1 (m68kpc_offset); m68kpc_offset += 2; ! 307: addr = m68k_areg(regs,reg) + (uae_s16)disp16; ! 308: sprintf (buffer,"(A%d,$%04x) == $%08lx", reg, disp16 & 0xffff, ! 309: (unsigned long)addr); ! 310: break; ! 311: case Ad8r: ! 312: dp = get_iword_1 (m68kpc_offset); m68kpc_offset += 2; ! 313: disp8 = dp & 0xFF; ! 314: r = (dp & 0x7000) >> 12; ! 315: dispreg = dp & 0x8000 ? m68k_areg(regs,r) : m68k_dreg(regs,r); ! 316: if (!(dp & 0x800)) dispreg = (uae_s32)(uae_s16)(dispreg); ! 317: dispreg <<= (dp >> 9) & 3; ! 318: ! 319: if (dp & 0x100) { ! 320: uae_s32 outer = 0, disp = 0; ! 321: uae_s32 base = m68k_areg(regs,reg); ! 322: char name[10]; ! 323: sprintf (name,"A%d, ",reg); ! 324: if (dp & 0x80) { base = 0; name[0] = 0; } ! 325: if (dp & 0x40) dispreg = 0; ! 326: if ((dp & 0x30) == 0x20) { disp = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; } ! 327: if ((dp & 0x30) == 0x30) { disp = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; } ! 328: base += disp; ! 329: ! 330: if ((dp & 0x3) == 0x2) { outer = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; } ! 331: if ((dp & 0x3) == 0x3) { outer = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; } ! 332: ! 333: if (!(dp & 4)) base += dispreg; ! 334: if (dp & 3) base = get_long (base); ! 335: if (dp & 4) base += dispreg; ! 336: ! 337: addr = base + outer; ! 338: sprintf (buffer,"(%s%c%d.%c*%d+%ld)+%ld == $%08lx", name, ! 339: dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W', ! 340: 1 << ((dp >> 9) & 3), ! 341: disp,outer, ! 342: (unsigned long)addr); ! 343: } else { ! 344: addr = m68k_areg(regs,reg) + (uae_s32)((uae_s8)disp8) + dispreg; ! 345: sprintf (buffer,"(A%d, %c%d.%c*%d, $%02x) == $%08lx", reg, ! 346: dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W', ! 347: 1 << ((dp >> 9) & 3), disp8, ! 348: (unsigned long)addr); ! 349: } ! 350: break; ! 351: case PC16: ! 352: addr = m68k_getpc () + m68kpc_offset; ! 353: disp16 = get_iword_1 (m68kpc_offset); m68kpc_offset += 2; ! 354: addr += (uae_s16)disp16; ! 355: sprintf (buffer,"(PC,$%04x) == $%08lx", disp16 & 0xffff,(unsigned long)addr); ! 356: break; ! 357: case PC8r: ! 358: addr = m68k_getpc () + m68kpc_offset; ! 359: dp = get_iword_1 (m68kpc_offset); m68kpc_offset += 2; ! 360: disp8 = dp & 0xFF; ! 361: r = (dp & 0x7000) >> 12; ! 362: dispreg = dp & 0x8000 ? m68k_areg(regs,r) : m68k_dreg(regs,r); ! 363: if (!(dp & 0x800)) dispreg = (uae_s32)(uae_s16)(dispreg); ! 364: dispreg <<= (dp >> 9) & 3; ! 365: ! 366: if (dp & 0x100) { ! 367: uae_s32 outer = 0,disp = 0; ! 368: uae_s32 base = addr; ! 369: char name[10]; ! 370: sprintf (name,"PC, "); ! 371: if (dp & 0x80) { base = 0; name[0] = 0; } ! 372: if (dp & 0x40) dispreg = 0; ! 373: if ((dp & 0x30) == 0x20) { disp = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; } ! 374: if ((dp & 0x30) == 0x30) { disp = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; } ! 375: base += disp; ! 376: ! 377: if ((dp & 0x3) == 0x2) { outer = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; } ! 378: if ((dp & 0x3) == 0x3) { outer = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; } ! 379: ! 380: if (!(dp & 4)) base += dispreg; ! 381: if (dp & 3) base = get_long (base); ! 382: if (dp & 4) base += dispreg; ! 383: ! 384: addr = base + outer; ! 385: sprintf (buffer,"(%s%c%d.%c*%d+%ld)+%ld == $%08lx", name, ! 386: dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W', ! 387: 1 << ((dp >> 9) & 3), ! 388: disp,outer, ! 389: (unsigned long)addr); ! 390: } else { ! 391: addr += (uae_s32)((uae_s8)disp8) + dispreg; ! 392: sprintf (buffer,"(PC, %c%d.%c*%d, $%02x) == $%08lx", dp & 0x8000 ? 'A' : 'D', ! 393: (int)r, dp & 0x800 ? 'L' : 'W', 1 << ((dp >> 9) & 3), ! 394: disp8, (unsigned long)addr); ! 395: } ! 396: break; ! 397: case absw: ! 398: sprintf (buffer,"$%08lx", (unsigned long)(uae_s32)(uae_s16)get_iword_1 (m68kpc_offset)); ! 399: m68kpc_offset += 2; ! 400: break; ! 401: case absl: ! 402: sprintf (buffer,"$%08lx", (unsigned long)get_ilong_1 (m68kpc_offset)); ! 403: m68kpc_offset += 4; ! 404: break; ! 405: case imm: ! 406: switch (size){ ! 407: case sz_byte: ! 408: sprintf (buffer,"#$%02x", (unsigned int)(get_iword_1 (m68kpc_offset) & 0xff)); ! 409: m68kpc_offset += 2; ! 410: break; ! 411: case sz_word: ! 412: sprintf (buffer,"#$%04x", (unsigned int)(get_iword_1 (m68kpc_offset) & 0xffff)); ! 413: m68kpc_offset += 2; ! 414: break; ! 415: case sz_long: ! 416: sprintf (buffer,"#$%08lx", (unsigned long)(get_ilong_1 (m68kpc_offset))); ! 417: m68kpc_offset += 4; ! 418: break; ! 419: default: ! 420: break; ! 421: } ! 422: break; ! 423: case imm0: ! 424: offset = (uae_s32)(uae_s8)get_iword_1 (m68kpc_offset); ! 425: m68kpc_offset += 2; ! 426: sprintf (buffer,"#$%02x", (unsigned int)(offset & 0xff)); ! 427: break; ! 428: case imm1: ! 429: offset = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); ! 430: m68kpc_offset += 2; ! 431: sprintf (buffer,"#$%04x", (unsigned int)(offset & 0xffff)); ! 432: break; ! 433: case imm2: ! 434: offset = (uae_s32)get_ilong_1 (m68kpc_offset); ! 435: m68kpc_offset += 4; ! 436: sprintf (buffer,"#$%08lx", (unsigned long)offset); ! 437: break; ! 438: case immi: ! 439: offset = (uae_s32)(uae_s8)(reg & 0xff); ! 440: sprintf (buffer,"#$%08lx", (unsigned long)offset); ! 441: break; ! 442: default: ! 443: break; ! 444: } ! 445: if (buf == 0) ! 446: fprintf (f, "%s", buffer); ! 447: else ! 448: strcat (buf, buffer); ! 449: return offset; ! 450: } ! 451: ! 452: /* The plan is that this will take over the job of exception 3 handling - ! 453: * the CPU emulation functions will just do a longjmp to m68k_go whenever ! 454: * they hit an odd address. */ ! 455: static int verify_ea (int reg, amodes mode, wordsizes size, uae_u32 *val) ! 456: { ! 457: uae_u16 dp; ! 458: uae_s8 disp8; ! 459: uae_s16 disp16; ! 460: int r; ! 461: uae_u32 dispreg; ! 462: uaecptr addr; ! 463: uae_s32 offset = 0; ! 464: ! 465: switch (mode){ ! 466: case Dreg: ! 467: *val = m68k_dreg (regs, reg); ! 468: return 1; ! 469: case Areg: ! 470: *val = m68k_areg (regs, reg); ! 471: return 1; ! 472: ! 473: case Aind: ! 474: case Aipi: ! 475: addr = m68k_areg (regs, reg); ! 476: break; ! 477: case Apdi: ! 478: addr = m68k_areg (regs, reg); ! 479: break; ! 480: case Ad16: ! 481: disp16 = get_iword_1 (m68kpc_offset); m68kpc_offset += 2; ! 482: addr = m68k_areg(regs,reg) + (uae_s16)disp16; ! 483: break; ! 484: case Ad8r: ! 485: addr = m68k_areg (regs, reg); ! 486: d8r_common: ! 487: dp = get_iword_1 (m68kpc_offset); m68kpc_offset += 2; ! 488: disp8 = dp & 0xFF; ! 489: r = (dp & 0x7000) >> 12; ! 490: dispreg = dp & 0x8000 ? m68k_areg(regs,r) : m68k_dreg(regs,r); ! 491: if (!(dp & 0x800)) dispreg = (uae_s32)(uae_s16)(dispreg); ! 492: dispreg <<= (dp >> 9) & 3; ! 493: ! 494: if (dp & 0x100) { ! 495: uae_s32 outer = 0, disp = 0; ! 496: uae_s32 base = addr; ! 497: if (dp & 0x80) base = 0; ! 498: if (dp & 0x40) dispreg = 0; ! 499: if ((dp & 0x30) == 0x20) { disp = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; } ! 500: if ((dp & 0x30) == 0x30) { disp = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; } ! 501: base += disp; ! 502: ! 503: if ((dp & 0x3) == 0x2) { outer = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; } ! 504: if ((dp & 0x3) == 0x3) { outer = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; } ! 505: ! 506: if (!(dp & 4)) base += dispreg; ! 507: if (dp & 3) base = get_long (base); ! 508: if (dp & 4) base += dispreg; ! 509: ! 510: addr = base + outer; ! 511: } else { ! 512: addr += (uae_s32)((uae_s8)disp8) + dispreg; ! 513: } ! 514: break; ! 515: case PC16: ! 516: addr = m68k_getpc () + m68kpc_offset; ! 517: disp16 = get_iword_1 (m68kpc_offset); m68kpc_offset += 2; ! 518: addr += (uae_s16)disp16; ! 519: break; ! 520: case PC8r: ! 521: addr = m68k_getpc () + m68kpc_offset; ! 522: goto d8r_common; ! 523: case absw: ! 524: addr = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); ! 525: m68kpc_offset += 2; ! 526: break; ! 527: case absl: ! 528: addr = get_ilong_1 (m68kpc_offset); ! 529: m68kpc_offset += 4; ! 530: break; ! 531: case imm: ! 532: switch (size){ ! 533: case sz_byte: ! 534: *val = get_iword_1 (m68kpc_offset) & 0xff; ! 535: m68kpc_offset += 2; ! 536: break; ! 537: case sz_word: ! 538: *val = get_iword_1 (m68kpc_offset) & 0xffff; ! 539: m68kpc_offset += 2; ! 540: break; ! 541: case sz_long: ! 542: *val = get_ilong_1 (m68kpc_offset); ! 543: m68kpc_offset += 4; ! 544: break; ! 545: default: ! 546: break; ! 547: } ! 548: return 1; ! 549: case imm0: ! 550: *val = (uae_s32)(uae_s8)get_iword_1 (m68kpc_offset); ! 551: m68kpc_offset += 2; ! 552: return 1; ! 553: case imm1: ! 554: *val = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); ! 555: m68kpc_offset += 2; ! 556: return 1; ! 557: case imm2: ! 558: *val = get_ilong_1 (m68kpc_offset); ! 559: m68kpc_offset += 4; ! 560: return 1; ! 561: case immi: ! 562: *val = (uae_s32)(uae_s8)(reg & 0xff); ! 563: return 1; ! 564: default: ! 565: addr = 0; ! 566: break; ! 567: } ! 568: if ((addr & 1) == 0) ! 569: return 1; ! 570: ! 571: last_addr_for_exception_3 = m68k_getpc () + m68kpc_offset; ! 572: last_fault_for_exception_3 = addr; ! 573: return 0; ! 574: } ! 575: ! 576: uae_u32 get_disp_ea_020 (uae_u32 base, uae_u32 dp) ! 577: { ! 578: int reg = (dp >> 12) & 15; ! 579: uae_s32 regd = regs.regs[reg]; ! 580: if ((dp & 0x800) == 0) ! 581: regd = (uae_s32)(uae_s16)regd; ! 582: regd <<= (dp >> 9) & 3; ! 583: if (dp & 0x100) { ! 584: uae_s32 outer = 0; ! 585: if (dp & 0x80) base = 0; ! 586: if (dp & 0x40) regd = 0; ! 587: ! 588: if ((dp & 0x30) == 0x20) base += (uae_s32)(uae_s16)next_iword(); ! 589: if ((dp & 0x30) == 0x30) base += next_ilong(); ! 590: ! 591: if ((dp & 0x3) == 0x2) outer = (uae_s32)(uae_s16)next_iword(); ! 592: if ((dp & 0x3) == 0x3) outer = next_ilong(); ! 593: ! 594: if ((dp & 0x4) == 0) base += regd; ! 595: if (dp & 0x3) base = get_long (base); ! 596: if (dp & 0x4) base += regd; ! 597: ! 598: return base + outer; ! 599: } else { ! 600: return base + (uae_s32)((uae_s8)dp) + regd; ! 601: } ! 602: } ! 603: ! 604: uae_u32 get_disp_ea_000 (uae_u32 base, uae_u32 dp) ! 605: { ! 606: int reg = (dp >> 12) & 15; ! 607: uae_s32 regd = regs.regs[reg]; ! 608: #if 1 ! 609: if ((dp & 0x800) == 0) ! 610: regd = (uae_s32)(uae_s16)regd; ! 611: return base + (uae_s8)dp + regd; ! 612: #else ! 613: /* Branch-free code... benchmark this again now that ! 614: * things are no longer inline. */ ! 615: uae_s32 regd16; ! 616: uae_u32 mask; ! 617: mask = ((dp & 0x800) >> 11) - 1; ! 618: regd16 = (uae_s32)(uae_s16)regd; ! 619: regd16 &= mask; ! 620: mask = ~mask; ! 621: base += (uae_s8)dp; ! 622: regd &= mask; ! 623: regd |= regd16; ! 624: return base + regd; ! 625: #endif ! 626: } ! 627: ! 628: void MakeSR (void) ! 629: { ! 630: #if 0 ! 631: assert((regs.t1 & 1) == regs.t1); ! 632: assert((regs.t0 & 1) == regs.t0); ! 633: assert((regs.s & 1) == regs.s); ! 634: assert((regs.m & 1) == regs.m); ! 635: assert((XFLG & 1) == XFLG); ! 636: assert((NFLG & 1) == NFLG); ! 637: assert((ZFLG & 1) == ZFLG); ! 638: assert((VFLG & 1) == VFLG); ! 639: assert((CFLG & 1) == CFLG); ! 640: #endif ! 641: regs.sr = ((regs.t1 << 15) | (regs.t0 << 14) ! 642: | (regs.s << 13) | (regs.m << 12) | (regs.intmask << 8) ! 643: | (GET_XFLG << 4) | (GET_NFLG << 3) | (GET_ZFLG << 2) | (GET_VFLG << 1) ! 644: | GET_CFLG); ! 645: } ! 646: ! 647: void MakeFromSR (void) ! 648: { ! 649: int oldm = regs.m; ! 650: int olds = regs.s; ! 651: ! 652: regs.t1 = (regs.sr >> 15) & 1; ! 653: regs.t0 = (regs.sr >> 14) & 1; ! 654: regs.s = (regs.sr >> 13) & 1; ! 655: regs.m = (regs.sr >> 12) & 1; ! 656: regs.intmask = (regs.sr >> 8) & 7; ! 657: SET_XFLG ((regs.sr >> 4) & 1); ! 658: SET_NFLG ((regs.sr >> 3) & 1); ! 659: SET_ZFLG ((regs.sr >> 2) & 1); ! 660: SET_VFLG ((regs.sr >> 1) & 1); ! 661: SET_CFLG (regs.sr & 1); ! 662: if (cpu_level >= 2) { ! 663: if (olds != regs.s) { ! 664: if (olds) { ! 665: if (oldm) ! 666: regs.msp = m68k_areg(regs, 7); ! 667: else ! 668: regs.isp = m68k_areg(regs, 7); ! 669: m68k_areg(regs, 7) = regs.usp; ! 670: } else { ! 671: regs.usp = m68k_areg(regs, 7); ! 672: m68k_areg(regs, 7) = regs.m ? regs.msp : regs.isp; ! 673: } ! 674: } else if (olds && oldm != regs.m) { ! 675: if (oldm) { ! 676: regs.msp = m68k_areg(regs, 7); ! 677: m68k_areg(regs, 7) = regs.isp; ! 678: } else { ! 679: regs.isp = m68k_areg(regs, 7); ! 680: m68k_areg(regs, 7) = regs.msp; ! 681: } ! 682: } ! 683: } else { ! 684: if (olds != regs.s) { ! 685: if (olds) { ! 686: regs.isp = m68k_areg(regs, 7); ! 687: m68k_areg(regs, 7) = regs.usp; ! 688: } else { ! 689: regs.usp = m68k_areg(regs, 7); ! 690: m68k_areg(regs, 7) = regs.isp; ! 691: } ! 692: } ! 693: } ! 694: ! 695: set_special (SPCFLAG_INT); ! 696: if (regs.t1 || regs.t0) ! 697: set_special (SPCFLAG_TRACE); ! 698: else ! 699: unset_special (SPCFLAG_TRACE | SPCFLAG_DOTRACE); ! 700: } ! 701: ! 702: void Exception(int nr, uaecptr oldpc) ! 703: { ! 704: uae_u32 currpc = m68k_getpc (); ! 705: ! 706: if( nr>=2 && nr<10 ) ! 707: fprintf(stderr,"Exception (-> %i bombs)!\n",nr); ! 708: ! 709: compiler_flush_jsr_stack(); ! 710: MakeSR(); ! 711: ! 712: if (!regs.s) { ! 713: regs.usp = m68k_areg(regs, 7); ! 714: if (cpu_level >= 2) ! 715: m68k_areg(regs, 7) = regs.m ? regs.msp : regs.isp; ! 716: else ! 717: m68k_areg(regs, 7) = regs.isp; ! 718: regs.s = 1; ! 719: } ! 720: if (cpu_level > 0) { ! 721: if (nr == 2 || nr == 3) { ! 722: int i; ! 723: /* @@@ this is probably wrong (?) */ ! 724: for (i = 0 ; i < 12 ; i++) { ! 725: m68k_areg(regs, 7) -= 2; ! 726: put_word (m68k_areg(regs, 7), 0); ! 727: } ! 728: m68k_areg(regs, 7) -= 2; ! 729: put_word (m68k_areg(regs, 7), 0xa000 + nr * 4); ! 730: } else if (nr ==5 || nr == 6 || nr == 7 || nr == 9) { ! 731: m68k_areg(regs, 7) -= 4; ! 732: put_long (m68k_areg(regs, 7), oldpc); ! 733: m68k_areg(regs, 7) -= 2; ! 734: put_word (m68k_areg(regs, 7), 0x2000 + nr * 4); ! 735: } else if (regs.m && nr >= 24 && nr < 32) { ! 736: m68k_areg(regs, 7) -= 2; ! 737: put_word (m68k_areg(regs, 7), nr * 4); ! 738: m68k_areg(regs, 7) -= 4; ! 739: put_long (m68k_areg(regs, 7), currpc); ! 740: m68k_areg(regs, 7) -= 2; ! 741: put_word (m68k_areg(regs, 7), regs.sr); ! 742: regs.sr |= (1 << 13); ! 743: regs.msp = m68k_areg(regs, 7); ! 744: m68k_areg(regs, 7) = regs.isp; ! 745: m68k_areg(regs, 7) -= 2; ! 746: put_word (m68k_areg(regs, 7), 0x1000 + nr * 4); ! 747: } else { ! 748: m68k_areg(regs, 7) -= 2; ! 749: put_word (m68k_areg(regs, 7), nr * 4); ! 750: } ! 751: } else { ! 752: if (nr == 2 || nr == 3) { ! 753: /*crashtrace=4;*/ ! 754: /*sleep(1);*/ ! 755: m68k_areg(regs, 7) -= 12; ! 756: /* ??????? */ ! 757: if (nr == 3) { ! 758: put_long (m68k_areg(regs, 7), last_fault_for_exception_3); ! 759: put_word (m68k_areg(regs, 7)+4, last_op_for_exception_3); ! 760: put_long (m68k_areg(regs, 7)+8, last_addr_for_exception_3); ! 761: } ! 762: /*write_log ("UAE CPU Exception.\n");*/ ! 763: goto kludge_me_do; ! 764: } ! 765: } ! 766: m68k_areg(regs, 7) -= 4; ! 767: put_long (m68k_areg(regs, 7), currpc); ! 768: kludge_me_do: ! 769: m68k_areg(regs, 7) -= 2; ! 770: put_word (m68k_areg(regs, 7), regs.sr); ! 771: m68k_setpc (get_long (regs.vbr + 4*nr)); ! 772: fill_prefetch_0 (); ! 773: regs.t1 = regs.t0 = regs.m = 0; ! 774: unset_special (SPCFLAG_TRACE | SPCFLAG_DOTRACE); ! 775: } ! 776: ! 777: static void Interrupt(int nr) ! 778: { ! 779: assert(nr < 8 && nr >= 0); ! 780: lastint_regs = regs; ! 781: lastint_no = nr; ! 782: Exception(nr+24, 0); ! 783: ! 784: regs.intmask = nr; ! 785: set_special (SPCFLAG_INT); ! 786: } ! 787: ! 788: static uae_u32 caar, cacr, itt0, itt1, dtt0, dtt1, tc, mmusr; ! 789: ! 790: int m68k_move2c (int regno, uae_u32 *regp) ! 791: { ! 792: if ((cpu_level == 1 && (regno & 0x7FF) > 1) ! 793: || (cpu_level < 4 && (regno & 0x7FF) > 2) ! 794: || (cpu_level == 4 && regno == 0x802)) ! 795: { ! 796: op_illg (0x4E7B); ! 797: return 0; ! 798: } else { ! 799: switch (regno) { ! 800: case 0: regs.sfc = *regp & 7; break; ! 801: case 1: regs.dfc = *regp & 7; break; ! 802: case 2: cacr = *regp & (cpu_level < 4 ? 0x3 : 0x80008000); break; ! 803: case 3: tc = *regp & 0xc000; break; ! 804: /* Mask out fields that should be zero. */ ! 805: case 4: itt0 = *regp & 0xffffe364; break; ! 806: case 5: itt1 = *regp & 0xffffe364; break; ! 807: case 6: dtt0 = *regp & 0xffffe364; break; ! 808: case 7: dtt1 = *regp & 0xffffe364; break; ! 809: ! 810: case 0x800: regs.usp = *regp; break; ! 811: case 0x801: regs.vbr = *regp; break; ! 812: case 0x802: caar = *regp & 0xfc; break; ! 813: case 0x803: regs.msp = *regp; if (regs.m == 1) m68k_areg(regs, 7) = regs.msp; break; ! 814: case 0x804: regs.isp = *regp; if (regs.m == 0) m68k_areg(regs, 7) = regs.isp; break; ! 815: default: ! 816: op_illg (0x4E7B); ! 817: return 0; ! 818: } ! 819: } ! 820: return 1; ! 821: } ! 822: ! 823: int m68k_movec2 (int regno, uae_u32 *regp) ! 824: { ! 825: if ((cpu_level == 1 && (regno & 0x7FF) > 1) ! 826: || (cpu_level < 4 && (regno & 0x7FF) > 2) ! 827: || (cpu_level == 4 && regno == 0x802)) ! 828: { ! 829: op_illg (0x4E7A); ! 830: return 0; ! 831: } else { ! 832: switch (regno) { ! 833: case 0: *regp = regs.sfc; break; ! 834: case 1: *regp = regs.dfc; break; ! 835: case 2: *regp = cacr; break; ! 836: case 3: *regp = tc; break; ! 837: case 4: *regp = itt0; break; ! 838: case 5: *regp = itt1; break; ! 839: case 6: *regp = dtt0; break; ! 840: case 7: *regp = dtt1; break; ! 841: case 0x800: *regp = regs.usp; break; ! 842: case 0x801: *regp = regs.vbr; break; ! 843: case 0x802: *regp = caar; break; ! 844: case 0x803: *regp = regs.m == 1 ? m68k_areg(regs, 7) : regs.msp; break; ! 845: case 0x804: *regp = regs.m == 0 ? m68k_areg(regs, 7) : regs.isp; break; ! 846: case 0x805: *regp = mmusr; break; ! 847: default: ! 848: op_illg (0x4E7A); ! 849: return 0; ! 850: } ! 851: } ! 852: return 1; ! 853: } ! 854: ! 855: STATIC_INLINE int ! 856: div_unsigned(uae_u32 src_hi, uae_u32 src_lo, uae_u32 div, uae_u32 *quot, uae_u32 *rem) ! 857: { ! 858: uae_u32 q = 0, cbit = 0; ! 859: int i; ! 860: ! 861: if (div <= src_hi) { ! 862: return 1; ! 863: } ! 864: for (i = 0 ; i < 32 ; i++) { ! 865: cbit = src_hi & 0x80000000ul; ! 866: src_hi <<= 1; ! 867: if (src_lo & 0x80000000ul) src_hi++; ! 868: src_lo <<= 1; ! 869: q = q << 1; ! 870: if (cbit || div <= src_hi) { ! 871: q |= 1; ! 872: src_hi -= div; ! 873: } ! 874: } ! 875: *quot = q; ! 876: *rem = src_hi; ! 877: return 0; ! 878: } ! 879: ! 880: void m68k_divl (uae_u32 opcode, uae_u32 src, uae_u16 extra, uaecptr oldpc) ! 881: { ! 882: #if defined(uae_s64) ! 883: if (src == 0) { ! 884: Exception (5, oldpc); ! 885: return; ! 886: } ! 887: if (extra & 0x800) { ! 888: /* signed variant */ ! 889: uae_s64 a = (uae_s64)(uae_s32)m68k_dreg(regs, (extra >> 12) & 7); ! 890: uae_s64 quot, rem; ! 891: ! 892: if (extra & 0x400) { ! 893: a &= 0xffffffffu; ! 894: a |= (uae_s64)m68k_dreg(regs, extra & 7) << 32; ! 895: } ! 896: rem = a % (uae_s64)(uae_s32)src; ! 897: quot = a / (uae_s64)(uae_s32)src; ! 898: if ((quot & UVAL64(0xffffffff80000000)) != 0 ! 899: && (quot & UVAL64(0xffffffff80000000)) != UVAL64(0xffffffff80000000)) ! 900: { ! 901: SET_VFLG (1); ! 902: SET_NFLG (1); ! 903: SET_CFLG (0); ! 904: } else { ! 905: if (((uae_s32)rem < 0) != ((uae_s64)a < 0)) rem = -rem; ! 906: SET_VFLG (0); ! 907: SET_CFLG (0); ! 908: SET_ZFLG (((uae_s32)quot) == 0); ! 909: SET_NFLG (((uae_s32)quot) < 0); ! 910: m68k_dreg(regs, extra & 7) = rem; ! 911: m68k_dreg(regs, (extra >> 12) & 7) = quot; ! 912: } ! 913: } else { ! 914: /* unsigned */ ! 915: uae_u64 a = (uae_u64)(uae_u32)m68k_dreg(regs, (extra >> 12) & 7); ! 916: uae_u64 quot, rem; ! 917: ! 918: if (extra & 0x400) { ! 919: a &= 0xffffffffu; ! 920: a |= (uae_u64)m68k_dreg(regs, extra & 7) << 32; ! 921: } ! 922: rem = a % (uae_u64)src; ! 923: quot = a / (uae_u64)src; ! 924: if (quot > 0xffffffffu) { ! 925: SET_VFLG (1); ! 926: SET_NFLG (1); ! 927: SET_CFLG (0); ! 928: } else { ! 929: SET_VFLG (0); ! 930: SET_CFLG (0); ! 931: SET_ZFLG (((uae_s32)quot) == 0); ! 932: SET_NFLG (((uae_s32)quot) < 0); ! 933: m68k_dreg(regs, extra & 7) = rem; ! 934: m68k_dreg(regs, (extra >> 12) & 7) = quot; ! 935: } ! 936: } ! 937: #else ! 938: if (src == 0) { ! 939: Exception (5, oldpc); ! 940: return; ! 941: } ! 942: if (extra & 0x800) { ! 943: /* signed variant */ ! 944: uae_s32 lo = (uae_s32)m68k_dreg(regs, (extra >> 12) & 7); ! 945: uae_s32 hi = lo < 0 ? -1 : 0; ! 946: uae_s32 save_high; ! 947: uae_u32 quot, rem; ! 948: uae_u32 sign; ! 949: ! 950: if (extra & 0x400) { ! 951: hi = (uae_s32)m68k_dreg(regs, extra & 7); ! 952: } ! 953: save_high = hi; ! 954: sign = (hi ^ src); ! 955: if (hi < 0) { ! 956: hi = ~hi; ! 957: lo = -lo; ! 958: if (lo == 0) hi++; ! 959: } ! 960: if ((uae_s32)src < 0) src = -src; ! 961: if (div_unsigned(hi, lo, src, ", &rem) || ! 962: (sign & 0x80000000) ? quot > 0x80000000 : quot > 0x7fffffff) { ! 963: SET_VFLG (1); ! 964: SET_NFLG (1); ! 965: SET_CFLG (0); ! 966: } else { ! 967: if (sign & 0x80000000) quot = -quot; ! 968: if (((uae_s32)rem < 0) != (save_high < 0)) rem = -rem; ! 969: SET_VFLG (0); ! 970: SET_CFLG (0); ! 971: SET_ZFLG (((uae_s32)quot) == 0); ! 972: SET_NFLG (((uae_s32)quot) < 0); ! 973: m68k_dreg(regs, extra & 7) = rem; ! 974: m68k_dreg(regs, (extra >> 12) & 7) = quot; ! 975: } ! 976: } else { ! 977: /* unsigned */ ! 978: uae_u32 lo = (uae_u32)m68k_dreg(regs, (extra >> 12) & 7); ! 979: uae_u32 hi = 0; ! 980: uae_u32 quot, rem; ! 981: ! 982: if (extra & 0x400) { ! 983: hi = (uae_u32)m68k_dreg(regs, extra & 7); ! 984: } ! 985: if (div_unsigned(hi, lo, src, ", &rem)) { ! 986: SET_VFLG (1); ! 987: SET_NFLG (1); ! 988: SET_CFLG (0); ! 989: } else { ! 990: SET_VFLG (0); ! 991: SET_CFLG (0); ! 992: SET_ZFLG (((uae_s32)quot) == 0); ! 993: SET_NFLG (((uae_s32)quot) < 0); ! 994: m68k_dreg(regs, extra & 7) = rem; ! 995: m68k_dreg(regs, (extra >> 12) & 7) = quot; ! 996: } ! 997: } ! 998: #endif ! 999: } ! 1000: ! 1001: STATIC_INLINE void ! 1002: mul_unsigned(uae_u32 src1, uae_u32 src2, uae_u32 *dst_hi, uae_u32 *dst_lo) ! 1003: { ! 1004: uae_u32 r0 = (src1 & 0xffff) * (src2 & 0xffff); ! 1005: uae_u32 r1 = ((src1 >> 16) & 0xffff) * (src2 & 0xffff); ! 1006: uae_u32 r2 = (src1 & 0xffff) * ((src2 >> 16) & 0xffff); ! 1007: uae_u32 r3 = ((src1 >> 16) & 0xffff) * ((src2 >> 16) & 0xffff); ! 1008: uae_u32 lo; ! 1009: ! 1010: lo = r0 + ((r1 << 16) & 0xffff0000ul); ! 1011: if (lo < r0) r3++; ! 1012: r0 = lo; ! 1013: lo = r0 + ((r2 << 16) & 0xffff0000ul); ! 1014: if (lo < r0) r3++; ! 1015: r3 += ((r1 >> 16) & 0xffff) + ((r2 >> 16) & 0xffff); ! 1016: *dst_lo = lo; ! 1017: *dst_hi = r3; ! 1018: } ! 1019: ! 1020: void m68k_mull (uae_u32 opcode, uae_u32 src, uae_u16 extra) ! 1021: { ! 1022: #if defined(uae_s64) ! 1023: if (extra & 0x800) { ! 1024: /* signed variant */ ! 1025: uae_s64 a = (uae_s64)(uae_s32)m68k_dreg(regs, (extra >> 12) & 7); ! 1026: ! 1027: a *= (uae_s64)(uae_s32)src; ! 1028: SET_VFLG (0); ! 1029: SET_CFLG (0); ! 1030: SET_ZFLG (a == 0); ! 1031: SET_NFLG (a < 0); ! 1032: if (extra & 0x400) ! 1033: m68k_dreg(regs, extra & 7) = a >> 32; ! 1034: else if ((a & UVAL64(0xffffffff80000000)) != 0 ! 1035: && (a & UVAL64(0xffffffff80000000)) != UVAL64(0xffffffff80000000)) ! 1036: { ! 1037: SET_VFLG (1); ! 1038: } ! 1039: m68k_dreg(regs, (extra >> 12) & 7) = (uae_u32)a; ! 1040: } else { ! 1041: /* unsigned */ ! 1042: uae_u64 a = (uae_u64)(uae_u32)m68k_dreg(regs, (extra >> 12) & 7); ! 1043: ! 1044: a *= (uae_u64)src; ! 1045: SET_VFLG (0); ! 1046: SET_CFLG (0); ! 1047: SET_ZFLG (a == 0); ! 1048: SET_NFLG (((uae_s64)a) < 0); ! 1049: if (extra & 0x400) ! 1050: m68k_dreg(regs, extra & 7) = a >> 32; ! 1051: else if ((a & UVAL64(0xffffffff00000000)) != 0) { ! 1052: SET_VFLG (1); ! 1053: } ! 1054: m68k_dreg(regs, (extra >> 12) & 7) = (uae_u32)a; ! 1055: } ! 1056: #else ! 1057: if (extra & 0x800) { ! 1058: /* signed variant */ ! 1059: uae_s32 src1,src2; ! 1060: uae_u32 dst_lo,dst_hi; ! 1061: uae_u32 sign; ! 1062: ! 1063: src1 = (uae_s32)src; ! 1064: src2 = (uae_s32)m68k_dreg(regs, (extra >> 12) & 7); ! 1065: sign = (src1 ^ src2); ! 1066: if (src1 < 0) src1 = -src1; ! 1067: if (src2 < 0) src2 = -src2; ! 1068: mul_unsigned((uae_u32)src1,(uae_u32)src2,&dst_hi,&dst_lo); ! 1069: if (sign & 0x80000000) { ! 1070: dst_hi = ~dst_hi; ! 1071: dst_lo = -dst_lo; ! 1072: if (dst_lo == 0) dst_hi++; ! 1073: } ! 1074: SET_VFLG (0); ! 1075: SET_CFLG (0); ! 1076: SET_ZFLG (dst_hi == 0 && dst_lo == 0); ! 1077: SET_NFLG (((uae_s32)dst_hi) < 0); ! 1078: if (extra & 0x400) ! 1079: m68k_dreg(regs, extra & 7) = dst_hi; ! 1080: else if ((dst_hi != 0 || (dst_lo & 0x80000000) != 0) ! 1081: && ((dst_hi & 0xffffffff) != 0xffffffff ! 1082: || (dst_lo & 0x80000000) != 0x80000000)) ! 1083: { ! 1084: SET_VFLG (1); ! 1085: } ! 1086: m68k_dreg(regs, (extra >> 12) & 7) = dst_lo; ! 1087: } else { ! 1088: /* unsigned */ ! 1089: uae_u32 dst_lo,dst_hi; ! 1090: ! 1091: mul_unsigned(src,(uae_u32)m68k_dreg(regs, (extra >> 12) & 7),&dst_hi,&dst_lo); ! 1092: ! 1093: SET_VFLG (0); ! 1094: SET_CFLG (0); ! 1095: SET_ZFLG (dst_hi == 0 && dst_lo == 0); ! 1096: SET_NFLG (((uae_s32)dst_hi) < 0); ! 1097: if (extra & 0x400) ! 1098: m68k_dreg(regs, extra & 7) = dst_hi; ! 1099: else if (dst_hi != 0) { ! 1100: SET_VFLG (1); ! 1101: } ! 1102: m68k_dreg(regs, (extra >> 12) & 7) = dst_lo; ! 1103: } ! 1104: #endif ! 1105: } ! 1106: static char* ccnames[] = ! 1107: { "T ","F ","HI","LS","CC","CS","NE","EQ", ! 1108: "VC","VS","PL","MI","GE","LT","GT","LE" }; ! 1109: ! 1110: void m68k_reset (void) ! 1111: { ! 1112: m68k_areg (regs, 7) = get_long (ROMmem_start); ! 1113: m68k_setpc (get_long (ROMmem_start+4)); ! 1114: fill_prefetch_0 (); ! 1115: regs.kick_mask = 0xF80000; ! 1116: regs.s = 1; ! 1117: regs.m = 0; ! 1118: regs.stopped = 0; ! 1119: regs.t1 = 0; ! 1120: regs.t0 = 0; ! 1121: SET_ZFLG (0); ! 1122: SET_XFLG (0); ! 1123: SET_CFLG (0); ! 1124: SET_VFLG (0); ! 1125: SET_NFLG (0); ! 1126: regs.spcflags = 0; ! 1127: regs.intmask = 7; ! 1128: regs.vbr = regs.sfc = regs.dfc = 0; ! 1129: regs.fpcr = regs.fpsr = regs.fpiar = 0; ! 1130: } ! 1131: ! 1132: unsigned long REGPARAM2 op_illg (uae_u32 opcode) ! 1133: { ! 1134: uaecptr pc = m68k_getpc (); ! 1135: /* ! 1136: if (cloanto_rom && (opcode & 0xF100) == 0x7100) { ! 1137: m68k_dreg (regs, (opcode >> 9) & 7) = (uae_s8)(opcode & 0xFF); ! 1138: m68k_incpc (2); ! 1139: fill_prefetch_0 (); ! 1140: return 4; ! 1141: } ! 1142: */ ! 1143: compiler_flush_jsr_stack (); ! 1144: if (opcode == 0x4E7B && get_long (0x10) == 0 ) ! 1145: { ! 1146: write_log ("This program requires a 68020 CPU!\n"); ! 1147: broken_in = 1; ! 1148: set_special (SPCFLAG_BRK); ! 1149: quit_program = 1; ! 1150: } ! 1151: /* ! 1152: if (opcode == 0xFF0D) { ! 1153: if ((pc & 0xF80000) == 0xF80000) { ! 1154: // This is from the dummy Kickstart replacement ! 1155: uae_u16 arg = get_iword (2); ! 1156: m68k_incpc (4); ! 1157: ersatz_perform (arg); ! 1158: fill_prefetch_0 (); ! 1159: return 4; ! 1160: } else if ((pc & 0xF80000) == 0xF00000) { ! 1161: // User-mode STOP replacement ! 1162: m68k_setstopped (1); ! 1163: return 4; ! 1164: } ! 1165: } ! 1166: */ ! 1167: /* ! 1168: if ((opcode & 0xF000) == 0xA000 && (pc & 0xF80000) == 0xF00000) { ! 1169: // Calltrap. ! 1170: m68k_incpc(2); ! 1171: call_calltrap (opcode & 0xFFF); ! 1172: fill_prefetch_0 (); ! 1173: return 4; ! 1174: } ! 1175: */ ! 1176: if ((opcode & 0xF000) == 0xF000) ! 1177: { ! 1178: Exception(0xB,0); ! 1179: return 4; ! 1180: } ! 1181: if ((opcode & 0xF000) == 0xA000) ! 1182: { ! 1183: /* ! 1184: if ((pc & 0xF80000) == 0xF00000) { ! 1185: // Calltrap. ! 1186: call_calltrap (opcode & 0xFFF); ! 1187: } ! 1188: */ ! 1189: Exception(0xA,0); ! 1190: return 4; ! 1191: } ! 1192: ! 1193: #if 1 ! 1194: write_log ("Illegal instruction: %04x at %08lx\n", opcode, pc); ! 1195: #endif ! 1196: Exception (4,0); ! 1197: return 4; ! 1198: } ! 1199: ! 1200: void mmu_op(uae_u32 opcode, uae_u16 extra) ! 1201: { ! 1202: if ((opcode & 0xFE0) == 0x0500) { ! 1203: /* PFLUSH */ ! 1204: mmusr = 0; ! 1205: write_log ("PFLUSH\n"); ! 1206: } else if ((opcode & 0x0FD8) == 0x548) { ! 1207: /* PTEST */ ! 1208: write_log ("PTEST\n"); ! 1209: } else ! 1210: op_illg (opcode); ! 1211: } ! 1212: ! 1213: static int n_insns = 0, n_spcinsns = 0; ! 1214: ! 1215: static uaecptr last_trace_ad = 0; ! 1216: ! 1217: static void do_trace (void) ! 1218: { ! 1219: if (regs.t0 && cpu_level >= 2) { ! 1220: uae_u16 opcode; ! 1221: /* should also include TRAP, CHK, SR modification FPcc */ ! 1222: /* probably never used so why bother */ ! 1223: /* We can afford this to be inefficient... */ ! 1224: m68k_setpc (m68k_getpc ()); ! 1225: fill_prefetch_0 (); ! 1226: opcode = get_word (regs.pc); ! 1227: if (opcode == 0x4e72 /* RTE */ ! 1228: || opcode == 0x4e74 /* RTD */ ! 1229: || opcode == 0x4e75 /* RTS */ ! 1230: || opcode == 0x4e77 /* RTR */ ! 1231: || opcode == 0x4e76 /* TRAPV */ ! 1232: || (opcode & 0xffc0) == 0x4e80 /* JSR */ ! 1233: || (opcode & 0xffc0) == 0x4ec0 /* JMP */ ! 1234: || (opcode & 0xff00) == 0x6100 /* BSR */ ! 1235: || ((opcode & 0xf000) == 0x6000 /* Bcc */ ! 1236: && cctrue((opcode >> 8) & 0xf)) ! 1237: || ((opcode & 0xf0f0) == 0x5050 /* DBcc */ ! 1238: && !cctrue((opcode >> 8) & 0xf) ! 1239: && (uae_s16)m68k_dreg(regs, opcode & 7) != 0)) ! 1240: { ! 1241: last_trace_ad = m68k_getpc (); ! 1242: unset_special (SPCFLAG_TRACE); ! 1243: set_special (SPCFLAG_DOTRACE); ! 1244: } ! 1245: } else if (regs.t1) { ! 1246: last_trace_ad = m68k_getpc (); ! 1247: unset_special (SPCFLAG_TRACE); ! 1248: set_special (SPCFLAG_DOTRACE); ! 1249: } ! 1250: } ! 1251: ! 1252: ! 1253: static int do_specialties (void) ! 1254: { ! 1255: /* ! 1256: if (regs.spcflags & SPCFLAG_COPPER) ! 1257: do_copper (); ! 1258: ! 1259: //n_spcinsns++; ! 1260: while (regs.spcflags & SPCFLAG_BLTNASTY) { ! 1261: do_cycles (4); ! 1262: if (regs.spcflags & SPCFLAG_COPPER) ! 1263: do_copper (); ! 1264: } ! 1265: */ ! 1266: run_compiled_code(); ! 1267: if (regs.spcflags & SPCFLAG_DOTRACE) { ! 1268: Exception (9,last_trace_ad); ! 1269: } ! 1270: while (regs.spcflags & SPCFLAG_STOP) { ! 1271: do_cycles (4); ! 1272: /*if (regs.spcflags & SPCFLAG_COPPER) ! 1273: do_copper ();*/ ! 1274: if (regs.spcflags & (SPCFLAG_INT | SPCFLAG_DOINT)){ ! 1275: int intr = intlev (); ! 1276: unset_special (SPCFLAG_INT | SPCFLAG_DOINT); ! 1277: if (intr != -1 && intr > regs.intmask) { ! 1278: Interrupt (intr); ! 1279: regs.stopped = 0; ! 1280: unset_special (SPCFLAG_STOP); ! 1281: } ! 1282: } ! 1283: } ! 1284: if (regs.spcflags & SPCFLAG_TRACE) ! 1285: do_trace (); ! 1286: ! 1287: if (regs.spcflags & SPCFLAG_DOINT) { ! 1288: int intr = intlev (); ! 1289: unset_special (SPCFLAG_DOINT); ! 1290: if (intr != -1 && intr > regs.intmask) { ! 1291: Interrupt (intr); ! 1292: regs.stopped = 0; ! 1293: } ! 1294: } ! 1295: if (regs.spcflags & SPCFLAG_INT) { ! 1296: unset_special (SPCFLAG_INT); ! 1297: set_special (SPCFLAG_DOINT); ! 1298: } ! 1299: if (regs.spcflags & (SPCFLAG_BRK | SPCFLAG_MODE_CHANGE)) { ! 1300: unset_special (SPCFLAG_BRK | SPCFLAG_MODE_CHANGE); ! 1301: return 1; ! 1302: } ! 1303: return 0; ! 1304: } ! 1305: ! 1306: /* It's really sad to have two almost identical functions for this, but we ! 1307: do it all for performance... :( */ ! 1308: static void m68k_run_1 (void) ! 1309: { ! 1310: #ifdef DEBUG_PREFETCH ! 1311: uae_u8 saved_bytes[20]; ! 1312: uae_u16 *oldpcp; ! 1313: #endif ! 1314: while(!quit_program) { ! 1315: int cycles; ! 1316: uae_u32 opcode = get_iword_prefetch (0); ! 1317: #ifdef DEBUG_PREFETCH ! 1318: if (get_ilong (0) != do_get_mem_long (®s.prefetch)) { ! 1319: fprintf (stderr, "Prefetch differs from memory.\n"); ! 1320: debugging = 1; ! 1321: return; ! 1322: } ! 1323: oldpcp = regs.pc_p; ! 1324: memcpy (saved_bytes, regs.pc_p, 20); ! 1325: #endif ! 1326: ! 1327: /*m68k_dumpstate(stderr, NULL);*/ ! 1328: m68k_disasm(stderr, m68k_getpc (), NULL, 1); ! 1329: /*if( opcode == 0 ) sleep(1);*/ ! 1330: ! 1331: /* assert (!regs.stopped && !(regs.spcflags & SPCFLAG_STOP)); */ ! 1332: /* regs_backup[backup_pointer = (backup_pointer + 1) % 16] = regs;*/ ! 1333: #if COUNT_INSTRS == 2 ! 1334: if (table68k[opcode].handler != -1) ! 1335: instrcount[table68k[opcode].handler]++; ! 1336: #elif COUNT_INSTRS == 1 ! 1337: instrcount[opcode]++; ! 1338: #endif ! 1339: #if defined X86_ASSEMBLY ! 1340: __asm__ __volatile__("\tcall *%%ebx" ! 1341: : "=&a" (cycles) : "b" (cpufunctbl[cft_map(opcode)]), "0" (opcode) ! 1342: : "%edx", "%ecx", ! 1343: "%esi", "%edi", "%ebp", "memory", "cc"); ! 1344: #else ! 1345: cycles = (*cpufunctbl[cft_map(opcode)])(opcode); ! 1346: #endif ! 1347: #ifdef DEBUG_PREFETCH ! 1348: if (memcmp (saved_bytes, oldpcp, 20) != 0) { ! 1349: fprintf (stderr, "Self-modifying code detected.\n"); ! 1350: set_special (SPCFLAG_BRK); ! 1351: debugging = 1; ! 1352: } ! 1353: #endif ! 1354: /*n_insns++;*/ ! 1355: /*cycles &= cycles_mask; ! 1356: cycles |= cycles_val;*/ ! 1357: do_cycles (cycles); ! 1358: if (regs.spcflags) { ! 1359: if (do_specialties ()) ! 1360: return; ! 1361: } ! 1362: } ! 1363: } ! 1364: ! 1365: #define DEBUG_PREFETCH ! 1366: ! 1367: /* Same thing, but don't use prefetch to get opcode. */ ! 1368: static void m68k_run_2 (void) ! 1369: { ! 1370: while(!quit_program) { ! 1371: int cycles; ! 1372: #ifdef HAVE_GET_WORD_UNSWAPPED ! 1373: uae_u32 opcode = do_get_mem_word_unswapped (regs.pc_p); ! 1374: #else ! 1375: uae_u32 opcode = get_iword (0); ! 1376: #endif ! 1377: ! 1378: /*m68k_dumpstate(stderr, NULL);*/ ! 1379: /*if(crashtrace) ! 1380: { --crashtrace ; m68k_disasm(stderr, m68k_getpc (), NULL, 1); }*/ ! 1381: /*if( opcode == 0 ) sleep(1); */ ! 1382: ! 1383: /* assert (!regs.stopped && !(regs.spcflags & SPCFLAG_STOP)); */ ! 1384: /* regs_backup[backup_pointer = (backup_pointer + 1) % 16] = regs;*/ ! 1385: #if COUNT_INSTRS == 2 ! 1386: if (table68k[opcode].handler != -1) ! 1387: instrcount[table68k[opcode].handler]++; ! 1388: #elif COUNT_INSTRS == 1 ! 1389: instrcount[opcode]++; ! 1390: #endif ! 1391: #if defined X86_ASSEMBLY ! 1392: __asm__ __volatile__("\tcall *%%ebx" ! 1393: : "=&a" (cycles) : "b" (cpufunctbl[cft_map(opcode)]), "0" (opcode) ! 1394: : "%edx", "%ecx", ! 1395: "%esi", "%edi", "%ebp", "memory", "cc"); ! 1396: #else ! 1397: cycles = (*cpufunctbl[cft_map(opcode)])(opcode); ! 1398: #endif ! 1399: ! 1400: /*n_insns++;*/ ! 1401: /*cycles &= cycles_mask; ! 1402: cycles |= cycles_val;*/ ! 1403: do_cycles (cycles); ! 1404: if (regs.spcflags) { ! 1405: if (do_specialties ()) ! 1406: return; ! 1407: } ! 1408: } ! 1409: } ! 1410: ! 1411: #ifdef X86_ASSEMBLY ! 1412: STATIC_INLINE void m68k_run1 (void (*func)(void)) ! 1413: { ! 1414: /* Work around compiler bug: GCC doesn't push %ebp in m68k_run_1. */ ! 1415: __asm__ __volatile__ ("pushl %%ebp\n\tcall *%0\n\tpopl %%ebp" ! 1416: : : "r" (func) : "%eax", "%edx", "%ecx", "memory", "cc"); ! 1417: } ! 1418: #else ! 1419: #define m68k_run1(F) F() ! 1420: #endif ! 1421: ! 1422: int in_m68k_go = 0; ! 1423: ! 1424: void m68k_go (int may_quit) ! 1425: { ! 1426: if (in_m68k_go || !may_quit) { ! 1427: write_log ("Bug! m68k_go is not reentrant.\n"); ! 1428: abort (); ! 1429: } ! 1430: ! 1431: /*reset_frame_rate_hack ();*/ ! 1432: update_68k_cycles (); ! 1433: ! 1434: in_m68k_go++; ! 1435: while(!quit_program) { ! 1436: /* ! 1437: if (quit_program > 0) { ! 1438: if (quit_program == 1) ! 1439: break; ! 1440: quit_program = 0; ! 1441: m68k_reset (); ! 1442: //reset_all_systems (); ! 1443: customreset (); ! 1444: } ! 1445: */ ! 1446: /* ! 1447: if (debugging) ! 1448: debug (); ! 1449: */ ! 1450: m68k_run1 (cpu_compatible ? m68k_run_1 : m68k_run_2); ! 1451: } ! 1452: in_m68k_go--; ! 1453: } ! 1454: ! 1455: static void m68k_verify (uaecptr addr, uaecptr *nextpc) ! 1456: { ! 1457: uae_u32 opcode, val; ! 1458: struct instr *dp; ! 1459: ! 1460: opcode = get_iword_1(0); ! 1461: last_op_for_exception_3 = opcode; ! 1462: m68kpc_offset = 2; ! 1463: ! 1464: if (cpufunctbl[cft_map(opcode)] == op_illg_1) { ! 1465: opcode = 0x4AFC; ! 1466: } ! 1467: dp = table68k + opcode; ! 1468: ! 1469: if (dp->suse) { ! 1470: if (!verify_ea (dp->sreg, dp->smode, dp->size, &val)) { ! 1471: Exception (3, 0); ! 1472: return; ! 1473: } ! 1474: } ! 1475: if (dp->duse) { ! 1476: if (!verify_ea (dp->dreg, dp->dmode, dp->size, &val)) { ! 1477: Exception (3, 0); ! 1478: return; ! 1479: } ! 1480: } ! 1481: } ! 1482: ! 1483: void m68k_disasm (FILE *f, uaecptr addr, uaecptr *nextpc, int cnt) ! 1484: { ! 1485: uaecptr newpc = 0; ! 1486: m68kpc_offset = addr - m68k_getpc (); ! 1487: while (cnt-- > 0) { ! 1488: char instrname[20],*ccpt; ! 1489: int opwords; ! 1490: uae_u32 opcode; ! 1491: struct mnemolookup *lookup; ! 1492: struct instr *dp; ! 1493: fprintf (f, "%08lx: ", m68k_getpc () + m68kpc_offset); ! 1494: for (opwords = 0; opwords < 5; opwords++){ ! 1495: fprintf (f, "%04x ", get_iword_1 (m68kpc_offset + opwords*2)); ! 1496: } ! 1497: opcode = get_iword_1 (m68kpc_offset); ! 1498: m68kpc_offset += 2; ! 1499: if (cpufunctbl[cft_map(opcode)] == op_illg_1) { ! 1500: opcode = 0x4AFC; ! 1501: } ! 1502: dp = table68k + opcode; ! 1503: for (lookup = lookuptab;lookup->mnemo != dp->mnemo; lookup++) ! 1504: ; ! 1505: ! 1506: strcpy (instrname, lookup->name); ! 1507: ccpt = strstr (instrname, "cc"); ! 1508: if (ccpt != 0) { ! 1509: strncpy (ccpt, ccnames[dp->cc], 2); ! 1510: } ! 1511: fprintf (f, "%s", instrname); ! 1512: switch (dp->size){ ! 1513: case sz_byte: fprintf (f, ".B "); break; ! 1514: case sz_word: fprintf (f, ".W "); break; ! 1515: case sz_long: fprintf (f, ".L "); break; ! 1516: default: fprintf (f, " "); break; ! 1517: } ! 1518: ! 1519: if (dp->suse) { ! 1520: newpc = m68k_getpc () + m68kpc_offset; ! 1521: newpc += ShowEA (f, dp->sreg, dp->smode, dp->size, 0); ! 1522: } ! 1523: if (dp->suse && dp->duse) ! 1524: fprintf (f, ","); ! 1525: if (dp->duse) { ! 1526: newpc = m68k_getpc () + m68kpc_offset; ! 1527: newpc += ShowEA (f, dp->dreg, dp->dmode, dp->size, 0); ! 1528: } ! 1529: if (ccpt != 0) { ! 1530: if (cctrue(dp->cc)) ! 1531: fprintf (f, " == %08lx (TRUE)", newpc); ! 1532: else ! 1533: fprintf (f, " == %08lx (FALSE)", newpc); ! 1534: } else if ((opcode & 0xff00) == 0x6100) /* BSR */ ! 1535: fprintf (f, " == %08lx", newpc); ! 1536: fprintf (f, "\n"); ! 1537: } ! 1538: if (nextpc) ! 1539: *nextpc = m68k_getpc () + m68kpc_offset; ! 1540: } ! 1541: ! 1542: void m68k_dumpstate (FILE *f, uaecptr *nextpc) ! 1543: { ! 1544: int i; ! 1545: for (i = 0; i < 8; i++){ ! 1546: fprintf (f, "D%d: %08lx ", i, m68k_dreg(regs, i)); ! 1547: if ((i & 3) == 3) fprintf (f, "\n"); ! 1548: } ! 1549: for (i = 0; i < 8; i++){ ! 1550: fprintf (f, "A%d: %08lx ", i, m68k_areg(regs, i)); ! 1551: if ((i & 3) == 3) fprintf (f, "\n"); ! 1552: } ! 1553: if (regs.s == 0) regs.usp = m68k_areg(regs, 7); ! 1554: if (regs.s && regs.m) regs.msp = m68k_areg(regs, 7); ! 1555: if (regs.s && regs.m == 0) regs.isp = m68k_areg(regs, 7); ! 1556: fprintf (f, "USP=%08lx ISP=%08lx MSP=%08lx VBR=%08lx\n", ! 1557: regs.usp,regs.isp,regs.msp,regs.vbr); ! 1558: fprintf (f, "T=%d%d S=%d M=%d X=%d N=%d Z=%d V=%d C=%d IMASK=%d\n", ! 1559: regs.t1, regs.t0, regs.s, regs.m, ! 1560: GET_XFLG, GET_NFLG, GET_ZFLG, GET_VFLG, GET_CFLG, regs.intmask); ! 1561: for (i = 0; i < 8; i++){ ! 1562: fprintf (f, "FP%d: %g ", i, regs.fp[i]); ! 1563: if ((i & 3) == 3) fprintf (f, "\n"); ! 1564: } ! 1565: fprintf (f, "N=%d Z=%d I=%d NAN=%d\n", ! 1566: (regs.fpsr & 0x8000000) != 0, ! 1567: (regs.fpsr & 0x4000000) != 0, ! 1568: (regs.fpsr & 0x2000000) != 0, ! 1569: (regs.fpsr & 0x1000000) != 0); ! 1570: if (cpu_compatible) ! 1571: fprintf (f, "prefetch %08lx\n", (unsigned long)do_get_mem_long(®s.prefetch)); ! 1572: ! 1573: m68k_disasm (f, m68k_getpc (), nextpc, 1); ! 1574: if (nextpc) ! 1575: fprintf (f, "next PC: %08lx\n", *nextpc); ! 1576: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.