|
|
1.1 ! root 1: /* ! 2: * UAE - The Un*x Amiga Emulator - CPU core ! 3: * ! 4: * MC68000 emulation ! 5: * ! 6: * (c) 1995 Bernd Schmidt ! 7: * ! 8: * Adaptation to Hatari by Thomas Huth ! 9: * ! 10: * This file is distributed under the GNU Public License, version 2 or at ! 11: * your option any later version. Read the file gpl.txt for details. ! 12: */ ! 13: ! 14: ! 15: /* 2007/11/12 [NP] Add HATARI_TRACE_CPU_DISASM. */ ! 16: /* 2007/11/15 [NP] In MakeFromSR, writes to m and t0 should be ignored and set to 0 if cpu < 68020 */ ! 17: /* 2007/11/26 [NP] We set BusErrorPC in m68k_run_1 instead of M68000_BusError, else the BusErrorPC */ ! 18: /* will not point to the opcode that generated the bus error. */ ! 19: /* Huge debug/work on Exceptions 2/3 stack frames, result is more accurate and */ ! 20: /* allow to pass the very tricky Transbeauce 2 Demo's protection. */ ! 21: /* 2007/11/28 [NP] Backport DIVS/DIVU cycles exact routines from WinUAE (original work by Jorge */ ! 22: /* Cwik, [email protected]). */ ! 23: /* 2007/12/06 [NP] The PC stored in the stack frame for the bus error is complex to emulate, */ ! 24: /* because it doesn't necessarily point to the next instruction after the one that */ ! 25: /* triggered the bus error. In the case of the Transbeauce 2 Demo, after */ ! 26: /* 'move.l $0.w,$24.w', PC is incremented of 4 bytes, not 6, and stored in the */ ! 27: /* stack. Special case to decrement PC of 2 bytes if opcode is '21f8'. */ ! 28: /* This should be fixed with a real model. */ ! 29: /* 2007/12/07 [NP] If Trace is enabled and a group 2 exception occurs (such as CHK), the trace */ ! 30: /* handler should be called after the group 2's handler. If a bus error, address */ ! 31: /* error or illegal occurs while Trace is enabled, the trace handler should not be */ ! 32: /* called after this instruction (Transbeauce 2 Demo, Phaleon Demo). */ ! 33: /* This means that if a CHK is executed while trace bit was set, we must set PC */ ! 34: /* to CHK handler, turn trace off in the internal SR, but we must still call the */ ! 35: /* trace handler one last time with the PC set to the CHK's handler (even if */ ! 36: /* trace mode is internally turned off while processing an exception). Once trace */ ! 37: /* handler is finished (RTE), we return to the CHK's handler. */ ! 38: /* This is true for DIV BY 0, CHK, TRAPV and TRAP. */ ! 39: /* Backport exception_trace() from WinUAE to handle this behaviour (used in */ ! 40: /* Transbeauce 2 demo). */ ! 41: /* 2007/12/09 [NP] 'dc.w $a' should not be used to call 'OpCode_SysInit' but should give an illegal*/ ! 42: /* instruction (Transbeauce 2 demo). */ ! 43: /* Instead of always replacing the illegal instructions $8, $a and $c by the */ ! 44: /* 3 functions required for HD emulation, we now do it in cart.c only if the */ ! 45: /* built-in cartridge image is loaded. */ ! 46: /* YEAH! Hatari is now the first emulator to pass the Transbeauce 2 protection :) */ ! 47: /* 2007/12/18 [NP] More precise timings for HBL, VBL and MFP interrupts. On ST, these interrupts */ ! 48: /* are taking 56 cycles instead of the 44 cycles in the 68000's documentation. */ ! 49: /* 2007/12/24 [NP] If an interrupt (HBL, VBL) is pending after intruction 'n' was processed, the */ ! 50: /* exception should be called before instr. 'n+1' is processed, not after (else the*/ ! 51: /* interrupt's handler is delayed by one 68000's instruction, which could break */ ! 52: /* some demos with too strict timings) (ACF's Demo Main Menu). */ ! 53: /* We call the interrupt if ( SPCFLAG_INT | SPCFLAG_DOINT ) is set, not only if */ ! 54: /* SPCFLAG_DOINT is set (as it was already the case when handling 'STOP'). */ ! 55: /* 2007/12/25 [NP] FIXME When handling exceptions' cycles, using nr >= 64 to determine if this is */ ! 56: /* an MFP exception could be wrong if the MFP VR was set to another value than the */ ! 57: /* default $40 (this could be a problem with programs requiring a precise cycles */ ! 58: /* calculation while changing VR, but no such programs were encountered so far). */ ! 59: /* -> FIXED, see 2008/10/05 */ ! 60: /* 2008/04/17 [NP] In m68k_run_1/m68k_run_2, add the wait state cycles before testing if content */ ! 61: /* of PendingInterruptCount is <= 0 (else the int could happen a few cycles earlier*/ ! 62: /* than expected in some rare cases (reading $fffa21 in BIG Demo Screen 1)). */ ! 63: /* 2008/09/14 [NP] Add the value of the new PC in the exception's log. */ ! 64: /* 2008/09/14 [NP] Correct cycles for TRAP are 34 not 38 (4 more cycles were counted because cpuemu*/ ! 65: /* returns 4 and Exception() adds 34) (Phaleon / Illusion Demo by Next). */ ! 66: /* FIXME : Others exception cycles may be wrong too. */ ! 67: /* 2008/10/05 [NP] Add a parameter 'ExceptionSource' to Exception(). This allows to know the source*/ ! 68: /* of the exception (video, mfp, cpu) and properly handle MFP interrupts. Since */ ! 69: /* it's possible to change the vector base in $fffa17, MFP int vectors can overlap */ ! 70: /* the 'normal' 68000 ones and the exception number is not enough to decide. */ ! 71: /* We need ExceptionSource to remove the ambiguity. */ ! 72: /* Fix High Fidelity Dreams by Aura which sets MFP vector base to $c0 instead of */ ! 73: /* $100. In that case, timer B int becomes exception nr 56 and conflicts with the */ ! 74: /* 'MMU config error' exception, which takes 4 cycles instead of 56 cycles for MFP.*/ ! 75: /* 2008/11/18 [NP] In 'do_specialties()', when the cpu is in the STOP state, we must test all */ ! 76: /* possible int handlers while PendingInterruptCount <= 0 without increasing the */ ! 77: /* cpu cycle counter. In the case where both an MFP int and an HBL occur at the */ ! 78: /* same time for example, the HBL was delayed by 4 cycles if no MFP exception */ ! 79: /* was triggered, which was wrong (this happened mainly with the TOS timer D that */ ! 80: /* expires very often). Such precision is required for very recent hardscroll */ ! 81: /* techniques that use 'stop' to stay in sync with the video shifter. */ ! 82: /* 2008/11/23 [NP] In 'do_specialties()', when in STOP state, we must first test for a pending */ ! 83: /* interrupt that would exit the STOP state immediatly, without doing a 'while' */ ! 84: /* loop until 'SPCFLAG_INT' or 'SPCFLAG_DOINT' are set. */ ! 85: /* 2008/11/29 [NP] Call 'InterruptAddJitter()' when a video interrupt happens to precisely emulate */ ! 86: /* the jitter happening on the Atari (see video.c for the jitter patterns). */ ! 87: /* FIXME : Pattern is not always correct when handling pending interrupt in STOP */ ! 88: /* state, but this should be harmless as no program has been found using this. */ ! 89: /* 2008/12/05 [NP] On Atari it takes 56 cycles to process an interrupt. During that time, a higher */ ! 90: /* level interrupt could happen and we must execute it before the previous int */ ! 91: /* (see m68k_run_1()). */ ! 92: /* This is the case for the VBL which can interrupt the last HBL of a screen */ ! 93: /* (end of line 312) at various point (from 0 to 8 cycles). */ ! 94: /* This fixes the fullscreen tunnel in Suretrip 49% by Checkpoint, which uses a */ ! 95: /* really buggy vbl/hbl combination, even on a real ST. Also fixes sample sound */ ! 96: /* in Swedish New Year's TCB screen. */ ! 97: /* 2008/12/11 [NP] Extract interrupt handling from do_specialties() in do_specialties_interrupt() */ ! 98: /* and factorize some code. In m68k_run_1 when testing for multiple interrupts at */ ! 99: /* the same time, call do_specialties_interrupt() to check only the special flags */ ! 100: /* related to interrupts (MFP and video) (else, this caused problem when the TRACE */ ! 101: /* flag was set). */ ! 102: /* 2008/12/14 [NP] In m68k_run_1(), we should check for simultaneous ints only if the cpu is not */ ! 103: /* in the STOP state after the last instruction was executed. Else, the call to */ ! 104: /* do_specialties_interrupt() could acknowledge the interrupt and we would never */ ! 105: /* exit the STOP state in do_specialties() just after (the problem can happen if */ ! 106: /* the TOS timer D expires just at the same time as the STOP instruction). */ ! 107: /* Fix regression since 2008/12/11 in the hidden screen from ULM in Oh Crickey... */ ! 108: /* 2008/12/20 [NP] In m68k_run_1(), when checking interrupts and STOP mode, we should test */ ! 109: /* PendingInterruptCount before regs.spcflags to have a faster evaluation of the */ ! 110: /* 'while' condition (PendingInterruptCount <= 0 is true less often than STOP==0) */ ! 111: ! 112: ! 113: const char NewCpu_fileid[] = "Hatari newcpu.c : " __DATE__ " " __TIME__; ! 114: ! 115: #include "sysdeps.h" ! 116: #include "hatari-glue.h" ! 117: #include "maccess.h" ! 118: #include "memory.h" ! 119: #include "newcpu.h" ! 120: #include "main.h" ! 121: #include "m68000.h" ! 122: #include "cycInt.h" ! 123: #include "mfp.h" ! 124: #include "cart.h" ! 125: #include "dialog.h" ! 126: #include "video.h" ! 127: #include "options.h" ! 128: #include "log.h" ! 129: #include "debugui.h" ! 130: #include "debugcpu.h" ! 131: ! 132: //#define DEBUG_PREFETCH ! 133: ! 134: struct flag_struct regflags; ! 135: ! 136: /* Opcode of faulting instruction */ ! 137: uae_u16 last_op_for_exception_3; ! 138: /* PC at fault time */ ! 139: uaecptr last_addr_for_exception_3; ! 140: /* Address that generated the exception */ ! 141: uaecptr last_fault_for_exception_3; ! 142: ! 143: const int areg_byteinc[] = { 1,1,1,1,1,1,1,2 }; ! 144: const int imm8_table[] = { 8,1,2,3,4,5,6,7 }; ! 145: ! 146: int movem_index1[256]; ! 147: int movem_index2[256]; ! 148: int movem_next[256]; ! 149: ! 150: int fpp_movem_index1[256]; ! 151: int fpp_movem_index2[256]; ! 152: int fpp_movem_next[256]; ! 153: ! 154: cpuop_func *cpufunctbl[65536]; ! 155: ! 156: int OpcodeFamily; ! 157: int BusCyclePenalty = 0; ! 158: ! 159: #define COUNT_INSTRS 0 ! 160: ! 161: #if COUNT_INSTRS ! 162: static unsigned long int instrcount[65536]; ! 163: static uae_u16 opcodenums[65536]; ! 164: ! 165: static int compfn (const void *el1, const void *el2) ! 166: { ! 167: return instrcount[*(const uae_u16 *)el1] < instrcount[*(const uae_u16 *)el2]; ! 168: } ! 169: ! 170: static char *icountfilename (void) ! 171: { ! 172: char *name = getenv ("INSNCOUNT"); ! 173: if (name) ! 174: return name; ! 175: return COUNT_INSTRS == 2 ? "frequent.68k" : "insncount"; ! 176: } ! 177: ! 178: void dump_counts (void) ! 179: { ! 180: FILE *f = fopen (icountfilename (), "w"); ! 181: unsigned long int total; ! 182: int i; ! 183: ! 184: write_log ("Writing instruction count file...\n"); ! 185: for (i = 0; i < 65536; i++) { ! 186: opcodenums[i] = i; ! 187: total += instrcount[i]; ! 188: } ! 189: qsort (opcodenums, 65536, sizeof(uae_u16), compfn); ! 190: ! 191: fprintf (f, "Total: %lu\n", total); ! 192: for (i=0; i < 65536; i++) { ! 193: unsigned long int cnt = instrcount[opcodenums[i]]; ! 194: struct instr *dp; ! 195: struct mnemolookup *lookup; ! 196: if (!cnt) ! 197: break; ! 198: dp = table68k + opcodenums[i]; ! 199: for (lookup = lookuptab;lookup->mnemo != dp->mnemo; lookup++) ! 200: ; ! 201: fprintf (f, "%04x: %lu %s\n", opcodenums[i], cnt, lookup->name); ! 202: } ! 203: fclose (f); ! 204: } ! 205: #else ! 206: void dump_counts (void) ! 207: { ! 208: } ! 209: #endif ! 210: ! 211: ! 212: static unsigned long op_illg_1 (uae_u32 opcode) REGPARAM; ! 213: ! 214: static unsigned long REGPARAM2 op_illg_1 (uae_u32 opcode) ! 215: { ! 216: op_illg (opcode); ! 217: return 4; ! 218: } ! 219: ! 220: ! 221: void build_cpufunctbl(void) ! 222: { ! 223: int i; ! 224: unsigned long opcode; ! 225: const struct cputbl *tbl = (currprefs.cpu_level == 4 ? op_smalltbl_0_ff ! 226: : currprefs.cpu_level == 3 ? op_smalltbl_1_ff ! 227: : currprefs.cpu_level == 2 ? op_smalltbl_2_ff ! 228: : currprefs.cpu_level == 1 ? op_smalltbl_3_ff ! 229: : ! currprefs.cpu_compatible ? op_smalltbl_4_ff ! 230: : op_smalltbl_5_ff); ! 231: ! 232: Log_Printf(LOG_DEBUG, "Building CPU function table (%d %d %d).\n", ! 233: currprefs.cpu_level, currprefs.cpu_compatible, currprefs.address_space_24); ! 234: ! 235: for (opcode = 0; opcode < 65536; opcode++) ! 236: cpufunctbl[opcode] = op_illg_1; ! 237: for (i = 0; tbl[i].handler != NULL; i++) { ! 238: if (! tbl[i].specific) ! 239: cpufunctbl[tbl[i].opcode] = tbl[i].handler; ! 240: } ! 241: for (opcode = 0; opcode < 65536; opcode++) { ! 242: cpuop_func *f; ! 243: ! 244: if (table68k[opcode].mnemo == i_ILLG || table68k[opcode].clev > currprefs.cpu_level) ! 245: continue; ! 246: ! 247: if (table68k[opcode].handler != -1) { ! 248: f = cpufunctbl[table68k[opcode].handler]; ! 249: if (f == op_illg_1) ! 250: abort(); ! 251: cpufunctbl[opcode] = f; ! 252: } ! 253: } ! 254: for (i = 0; tbl[i].handler != NULL; i++) { ! 255: if (tbl[i].specific) ! 256: cpufunctbl[tbl[i].opcode] = tbl[i].handler; ! 257: } ! 258: } ! 259: ! 260: ! 261: ! 262: void init_m68k (void) ! 263: { ! 264: int i; ! 265: ! 266: for (i = 0 ; i < 256 ; i++) { ! 267: int j; ! 268: for (j = 0 ; j < 8 ; j++) { ! 269: if (i & (1 << j)) break; ! 270: } ! 271: movem_index1[i] = j; ! 272: movem_index2[i] = 7-j; ! 273: movem_next[i] = i & (~(1 << j)); ! 274: } ! 275: for (i = 0 ; i < 256 ; i++) { ! 276: int j; ! 277: for (j = 7 ; j >= 0 ; j--) { ! 278: if (i & (1 << j)) break; ! 279: } ! 280: fpp_movem_index1[i] = 7-j; ! 281: fpp_movem_index2[i] = j; ! 282: fpp_movem_next[i] = i & (~(1 << j)); ! 283: } ! 284: #if COUNT_INSTRS ! 285: { ! 286: FILE *f = fopen (icountfilename (), "r"); ! 287: memset (instrcount, 0, sizeof instrcount); ! 288: if (f) { ! 289: uae_u32 opcode, count, total; ! 290: char name[20]; ! 291: write_log ("Reading instruction count file...\n"); ! 292: fscanf (f, "Total: %lu\n", &total); ! 293: while (fscanf (f, "%lx: %lu %s\n", &opcode, &count, name) == 3) { ! 294: instrcount[opcode] = count; ! 295: } ! 296: fclose(f); ! 297: } ! 298: } ! 299: #endif ! 300: write_log ("Building CPU table for configuration: 68"); ! 301: if (currprefs.address_space_24 && currprefs.cpu_level > 1) ! 302: write_log ("EC"); ! 303: switch (currprefs.cpu_level) { ! 304: case 1: ! 305: write_log ("010"); ! 306: break; ! 307: case 2: ! 308: write_log ("020"); ! 309: break; ! 310: case 3: ! 311: write_log ("020/881"); ! 312: break; ! 313: case 4: ! 314: /* Who is going to miss the MMU anyway...? :-) */ ! 315: write_log ("040"); ! 316: break; ! 317: default: ! 318: write_log ("000"); ! 319: break; ! 320: } ! 321: if (currprefs.cpu_compatible) ! 322: write_log (" (compatible mode)"); ! 323: write_log ("\n"); ! 324: ! 325: read_table68k (); ! 326: do_merges (); ! 327: ! 328: Log_Printf(LOG_DEBUG, "%d CPU functions\n", nr_cpuop_funcs); ! 329: ! 330: build_cpufunctbl (); ! 331: } ! 332: ! 333: ! 334: /* not used ATM: ! 335: static struct regstruct regs_backup[16]; ! 336: static int backup_pointer = 0; ! 337: struct regstruct lastint_regs; ! 338: int lastint_no; ! 339: */ ! 340: struct regstruct regs; ! 341: static long int m68kpc_offset; ! 342: ! 343: ! 344: #define get_ibyte_1(o) get_byte(regs.pc + (regs.pc_p - regs.pc_oldp) + (o) + 1) ! 345: #define get_iword_1(o) get_word(regs.pc + (regs.pc_p - regs.pc_oldp) + (o)) ! 346: #define get_ilong_1(o) get_long(regs.pc + (regs.pc_p - regs.pc_oldp) + (o)) ! 347: ! 348: uae_s32 ShowEA (FILE *f, int reg, amodes mode, wordsizes size, char *buf) ! 349: { ! 350: uae_u16 dp; ! 351: uae_s8 disp8; ! 352: uae_s16 disp16; ! 353: int r; ! 354: uae_u32 dispreg; ! 355: uaecptr addr; ! 356: uae_s32 offset = 0; ! 357: char buffer[80]; ! 358: ! 359: switch (mode){ ! 360: case Dreg: ! 361: sprintf (buffer,"D%d", reg); ! 362: break; ! 363: case Areg: ! 364: sprintf (buffer,"A%d", reg); ! 365: break; ! 366: case Aind: ! 367: sprintf (buffer,"(A%d)", reg); ! 368: break; ! 369: case Aipi: ! 370: sprintf (buffer,"(A%d)+", reg); ! 371: break; ! 372: case Apdi: ! 373: sprintf (buffer,"-(A%d)", reg); ! 374: break; ! 375: case Ad16: ! 376: disp16 = get_iword_1 (m68kpc_offset); m68kpc_offset += 2; ! 377: addr = m68k_areg(regs,reg) + (uae_s16)disp16; ! 378: sprintf (buffer,"(A%d,$%04x) == $%08lx", reg, disp16 & 0xffff, ! 379: (unsigned long)addr); ! 380: break; ! 381: case Ad8r: ! 382: dp = get_iword_1 (m68kpc_offset); m68kpc_offset += 2; ! 383: disp8 = dp & 0xFF; ! 384: r = (dp & 0x7000) >> 12; ! 385: dispreg = dp & 0x8000 ? m68k_areg(regs,r) : m68k_dreg(regs,r); ! 386: if (!(dp & 0x800)) dispreg = (uae_s32)(uae_s16)(dispreg); ! 387: dispreg <<= (dp >> 9) & 3; ! 388: ! 389: if (dp & 0x100) { ! 390: uae_s32 outer = 0, disp = 0; ! 391: uae_s32 base = m68k_areg(regs,reg); ! 392: char name[10]; ! 393: sprintf (name,"A%d, ",reg); ! 394: if (dp & 0x80) { base = 0; name[0] = 0; } ! 395: if (dp & 0x40) dispreg = 0; ! 396: if ((dp & 0x30) == 0x20) { disp = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; } ! 397: if ((dp & 0x30) == 0x30) { disp = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; } ! 398: base += disp; ! 399: ! 400: if ((dp & 0x3) == 0x2) { outer = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; } ! 401: if ((dp & 0x3) == 0x3) { outer = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; } ! 402: ! 403: if (!(dp & 4)) base += dispreg; ! 404: if (dp & 3) base = get_long (base); ! 405: if (dp & 4) base += dispreg; ! 406: ! 407: addr = base + outer; ! 408: sprintf (buffer,"(%s%c%d.%c*%d+%ld)+%ld == $%08lx", name, ! 409: dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W', ! 410: 1 << ((dp >> 9) & 3), ! 411: (long)disp, (long)outer, (unsigned long)addr); ! 412: } else { ! 413: addr = m68k_areg(regs,reg) + (uae_s32)((uae_s8)disp8) + dispreg; ! 414: sprintf (buffer,"(A%d, %c%d.%c*%d, $%02x) == $%08lx", reg, ! 415: dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W', ! 416: 1 << ((dp >> 9) & 3), disp8, ! 417: (unsigned long)addr); ! 418: } ! 419: break; ! 420: case PC16: ! 421: addr = m68k_getpc () + m68kpc_offset; ! 422: disp16 = get_iword_1 (m68kpc_offset); m68kpc_offset += 2; ! 423: addr += (uae_s16)disp16; ! 424: sprintf (buffer,"(PC,$%04x) == $%08lx", disp16 & 0xffff,(unsigned long)addr); ! 425: break; ! 426: case PC8r: ! 427: addr = m68k_getpc () + m68kpc_offset; ! 428: dp = get_iword_1 (m68kpc_offset); m68kpc_offset += 2; ! 429: disp8 = dp & 0xFF; ! 430: r = (dp & 0x7000) >> 12; ! 431: dispreg = dp & 0x8000 ? m68k_areg(regs,r) : m68k_dreg(regs,r); ! 432: if (!(dp & 0x800)) dispreg = (uae_s32)(uae_s16)(dispreg); ! 433: dispreg <<= (dp >> 9) & 3; ! 434: ! 435: if (dp & 0x100) { ! 436: uae_s32 outer = 0,disp = 0; ! 437: uae_s32 base = addr; ! 438: char name[10]; ! 439: sprintf (name,"PC, "); ! 440: if (dp & 0x80) { base = 0; name[0] = 0; } ! 441: if (dp & 0x40) dispreg = 0; ! 442: if ((dp & 0x30) == 0x20) { disp = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; } ! 443: if ((dp & 0x30) == 0x30) { disp = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; } ! 444: base += disp; ! 445: ! 446: if ((dp & 0x3) == 0x2) { outer = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; } ! 447: if ((dp & 0x3) == 0x3) { outer = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; } ! 448: ! 449: if (!(dp & 4)) base += dispreg; ! 450: if (dp & 3) base = get_long (base); ! 451: if (dp & 4) base += dispreg; ! 452: ! 453: addr = base + outer; ! 454: sprintf (buffer,"(%s%c%d.%c*%d+%ld)+%ld == $%08lx", name, ! 455: dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W', ! 456: 1 << ((dp >> 9) & 3), ! 457: (long)disp, (long)outer, (unsigned long)addr); ! 458: } else { ! 459: addr += (uae_s32)((uae_s8)disp8) + dispreg; ! 460: sprintf (buffer,"(PC, %c%d.%c*%d, $%02x) == $%08lx", dp & 0x8000 ? 'A' : 'D', ! 461: (int)r, dp & 0x800 ? 'L' : 'W', 1 << ((dp >> 9) & 3), ! 462: disp8, (unsigned long)addr); ! 463: } ! 464: break; ! 465: case absw: ! 466: sprintf (buffer,"$%08lx", (unsigned long)(uae_s32)(uae_s16)get_iword_1 (m68kpc_offset)); ! 467: m68kpc_offset += 2; ! 468: break; ! 469: case absl: ! 470: sprintf (buffer,"$%08lx", (unsigned long)get_ilong_1 (m68kpc_offset)); ! 471: m68kpc_offset += 4; ! 472: break; ! 473: case imm: ! 474: switch (size){ ! 475: case sz_byte: ! 476: sprintf (buffer,"#$%02x", (unsigned int)(get_iword_1 (m68kpc_offset) & 0xff)); ! 477: m68kpc_offset += 2; ! 478: break; ! 479: case sz_word: ! 480: sprintf (buffer,"#$%04x", (unsigned int)(get_iword_1 (m68kpc_offset) & 0xffff)); ! 481: m68kpc_offset += 2; ! 482: break; ! 483: case sz_long: ! 484: sprintf (buffer,"#$%08lx", (unsigned long)(get_ilong_1 (m68kpc_offset))); ! 485: m68kpc_offset += 4; ! 486: break; ! 487: default: ! 488: break; ! 489: } ! 490: break; ! 491: case imm0: ! 492: offset = (uae_s32)(uae_s8)get_iword_1 (m68kpc_offset); ! 493: m68kpc_offset += 2; ! 494: sprintf (buffer,"#$%02x", (unsigned int)(offset & 0xff)); ! 495: break; ! 496: case imm1: ! 497: offset = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); ! 498: m68kpc_offset += 2; ! 499: sprintf (buffer,"#$%04x", (unsigned int)(offset & 0xffff)); ! 500: break; ! 501: case imm2: ! 502: offset = (uae_s32)get_ilong_1 (m68kpc_offset); ! 503: m68kpc_offset += 4; ! 504: sprintf (buffer,"#$%08lx", (unsigned long)offset); ! 505: break; ! 506: case immi: ! 507: offset = (uae_s32)(uae_s8)(reg & 0xff); ! 508: sprintf (buffer,"#$%08lx", (unsigned long)offset); ! 509: break; ! 510: default: ! 511: break; ! 512: } ! 513: if (buf == 0) ! 514: fprintf (f, "%s", buffer); ! 515: else ! 516: strcat (buf, buffer); ! 517: return offset; ! 518: } ! 519: ! 520: ! 521: /* The plan is that this will take over the job of exception 3 handling - ! 522: * the CPU emulation functions will just do a longjmp to m68k_go whenever ! 523: * they hit an odd address. */ ! 524: #if 0 ! 525: static int verify_ea (int reg, amodes mode, wordsizes size, uae_u32 *val) ! 526: { ! 527: uae_u16 dp; ! 528: uae_s8 disp8; ! 529: uae_s16 disp16; ! 530: int r; ! 531: uae_u32 dispreg; ! 532: uaecptr addr; ! 533: /*uae_s32 offset = 0;*/ ! 534: ! 535: switch (mode){ ! 536: case Dreg: ! 537: *val = m68k_dreg (regs, reg); ! 538: return 1; ! 539: case Areg: ! 540: *val = m68k_areg (regs, reg); ! 541: return 1; ! 542: ! 543: case Aind: ! 544: case Aipi: ! 545: addr = m68k_areg (regs, reg); ! 546: break; ! 547: case Apdi: ! 548: addr = m68k_areg (regs, reg); ! 549: break; ! 550: case Ad16: ! 551: disp16 = get_iword_1 (m68kpc_offset); m68kpc_offset += 2; ! 552: addr = m68k_areg(regs,reg) + (uae_s16)disp16; ! 553: break; ! 554: case Ad8r: ! 555: addr = m68k_areg (regs, reg); ! 556: d8r_common: ! 557: dp = get_iword_1 (m68kpc_offset); m68kpc_offset += 2; ! 558: disp8 = dp & 0xFF; ! 559: r = (dp & 0x7000) >> 12; ! 560: dispreg = dp & 0x8000 ? m68k_areg(regs,r) : m68k_dreg(regs,r); ! 561: if (!(dp & 0x800)) dispreg = (uae_s32)(uae_s16)(dispreg); ! 562: dispreg <<= (dp >> 9) & 3; ! 563: ! 564: if (dp & 0x100) { ! 565: uae_s32 outer = 0, disp = 0; ! 566: uae_s32 base = addr; ! 567: if (dp & 0x80) base = 0; ! 568: if (dp & 0x40) dispreg = 0; ! 569: if ((dp & 0x30) == 0x20) { disp = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; } ! 570: if ((dp & 0x30) == 0x30) { disp = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; } ! 571: base += disp; ! 572: ! 573: if ((dp & 0x3) == 0x2) { outer = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; } ! 574: if ((dp & 0x3) == 0x3) { outer = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; } ! 575: ! 576: if (!(dp & 4)) base += dispreg; ! 577: if (dp & 3) base = get_long (base); ! 578: if (dp & 4) base += dispreg; ! 579: ! 580: addr = base + outer; ! 581: } else { ! 582: addr += (uae_s32)((uae_s8)disp8) + dispreg; ! 583: } ! 584: break; ! 585: case PC16: ! 586: addr = m68k_getpc () + m68kpc_offset; ! 587: disp16 = get_iword_1 (m68kpc_offset); m68kpc_offset += 2; ! 588: addr += (uae_s16)disp16; ! 589: break; ! 590: case PC8r: ! 591: addr = m68k_getpc () + m68kpc_offset; ! 592: goto d8r_common; ! 593: case absw: ! 594: addr = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); ! 595: m68kpc_offset += 2; ! 596: break; ! 597: case absl: ! 598: addr = get_ilong_1 (m68kpc_offset); ! 599: m68kpc_offset += 4; ! 600: break; ! 601: case imm: ! 602: switch (size){ ! 603: case sz_byte: ! 604: *val = get_iword_1 (m68kpc_offset) & 0xff; ! 605: m68kpc_offset += 2; ! 606: break; ! 607: case sz_word: ! 608: *val = get_iword_1 (m68kpc_offset) & 0xffff; ! 609: m68kpc_offset += 2; ! 610: break; ! 611: case sz_long: ! 612: *val = get_ilong_1 (m68kpc_offset); ! 613: m68kpc_offset += 4; ! 614: break; ! 615: default: ! 616: break; ! 617: } ! 618: return 1; ! 619: case imm0: ! 620: *val = (uae_s32)(uae_s8)get_iword_1 (m68kpc_offset); ! 621: m68kpc_offset += 2; ! 622: return 1; ! 623: case imm1: ! 624: *val = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); ! 625: m68kpc_offset += 2; ! 626: return 1; ! 627: case imm2: ! 628: *val = get_ilong_1 (m68kpc_offset); ! 629: m68kpc_offset += 4; ! 630: return 1; ! 631: case immi: ! 632: *val = (uae_s32)(uae_s8)(reg & 0xff); ! 633: return 1; ! 634: default: ! 635: addr = 0; ! 636: break; ! 637: } ! 638: if ((addr & 1) == 0) ! 639: return 1; ! 640: ! 641: last_addr_for_exception_3 = m68k_getpc () + m68kpc_offset; ! 642: last_fault_for_exception_3 = addr; ! 643: return 0; ! 644: } ! 645: #endif ! 646: ! 647: ! 648: uae_u32 get_disp_ea_020 (uae_u32 base, uae_u32 dp) ! 649: { ! 650: int reg = (dp >> 12) & 15; ! 651: uae_s32 regd = regs.regs[reg]; ! 652: if ((dp & 0x800) == 0) ! 653: regd = (uae_s32)(uae_s16)regd; ! 654: regd <<= (dp >> 9) & 3; ! 655: if (dp & 0x100) { ! 656: uae_s32 outer = 0; ! 657: if (dp & 0x80) base = 0; ! 658: if (dp & 0x40) regd = 0; ! 659: ! 660: if ((dp & 0x30) == 0x20) base += (uae_s32)(uae_s16)next_iword(); ! 661: if ((dp & 0x30) == 0x30) base += next_ilong(); ! 662: ! 663: if ((dp & 0x3) == 0x2) outer = (uae_s32)(uae_s16)next_iword(); ! 664: if ((dp & 0x3) == 0x3) outer = next_ilong(); ! 665: ! 666: if ((dp & 0x4) == 0) base += regd; ! 667: if (dp & 0x3) base = get_long (base); ! 668: if (dp & 0x4) base += regd; ! 669: ! 670: return base + outer; ! 671: } else { ! 672: return base + (uae_s32)((uae_s8)dp) + regd; ! 673: } ! 674: } ! 675: ! 676: uae_u32 get_disp_ea_000 (uae_u32 base, uae_u32 dp) ! 677: { ! 678: int reg = (dp >> 12) & 15; ! 679: uae_s32 regd = regs.regs[reg]; ! 680: #if 1 ! 681: if ((dp & 0x800) == 0) ! 682: regd = (uae_s32)(uae_s16)regd; ! 683: return base + (uae_s8)dp + regd; ! 684: #else ! 685: /* Branch-free code... benchmark this again now that ! 686: * things are no longer inline. */ ! 687: uae_s32 regd16; ! 688: uae_u32 mask; ! 689: mask = ((dp & 0x800) >> 11) - 1; ! 690: regd16 = (uae_s32)(uae_s16)regd; ! 691: regd16 &= mask; ! 692: mask = ~mask; ! 693: base += (uae_s8)dp; ! 694: regd &= mask; ! 695: regd |= regd16; ! 696: return base + regd; ! 697: #endif ! 698: } ! 699: ! 700: ! 701: /* Create the Status Register from the flags */ ! 702: void MakeSR (void) ! 703: { ! 704: #if 0 ! 705: assert((regs.t1 & 1) == regs.t1); ! 706: assert((regs.t0 & 1) == regs.t0); ! 707: assert((regs.s & 1) == regs.s); ! 708: assert((regs.m & 1) == regs.m); ! 709: assert((XFLG & 1) == XFLG); ! 710: assert((NFLG & 1) == NFLG); ! 711: assert((ZFLG & 1) == ZFLG); ! 712: assert((VFLG & 1) == VFLG); ! 713: assert((CFLG & 1) == CFLG); ! 714: #endif ! 715: regs.sr = ((regs.t1 << 15) | (regs.t0 << 14) ! 716: | (regs.s << 13) | (regs.m << 12) | (regs.intmask << 8) ! 717: | (GET_XFLG << 4) | (GET_NFLG << 3) | (GET_ZFLG << 2) | (GET_VFLG << 1) ! 718: | GET_CFLG); ! 719: } ! 720: ! 721: ! 722: /* Set up the flags from Status Register */ ! 723: void MakeFromSR (void) ! 724: { ! 725: int oldm = regs.m; ! 726: int olds = regs.s; ! 727: ! 728: regs.t1 = (regs.sr >> 15) & 1; ! 729: regs.t0 = (regs.sr >> 14) & 1; ! 730: regs.s = (regs.sr >> 13) & 1; ! 731: regs.m = (regs.sr >> 12) & 1; ! 732: regs.intmask = (regs.sr >> 8) & 7; ! 733: SET_XFLG ((regs.sr >> 4) & 1); ! 734: SET_NFLG ((regs.sr >> 3) & 1); ! 735: SET_ZFLG ((regs.sr >> 2) & 1); ! 736: SET_VFLG ((regs.sr >> 1) & 1); ! 737: SET_CFLG (regs.sr & 1); ! 738: if (currprefs.cpu_level >= 2) { ! 739: if (olds != regs.s) { ! 740: if (olds) { ! 741: if (oldm) ! 742: regs.msp = m68k_areg(regs, 7); ! 743: else ! 744: regs.isp = m68k_areg(regs, 7); ! 745: m68k_areg(regs, 7) = regs.usp; ! 746: } else { ! 747: regs.usp = m68k_areg(regs, 7); ! 748: m68k_areg(regs, 7) = regs.m ? regs.msp : regs.isp; ! 749: } ! 750: } else if (olds && oldm != regs.m) { ! 751: if (oldm) { ! 752: regs.msp = m68k_areg(regs, 7); ! 753: m68k_areg(regs, 7) = regs.isp; ! 754: } else { ! 755: regs.isp = m68k_areg(regs, 7); ! 756: m68k_areg(regs, 7) = regs.msp; ! 757: } ! 758: } ! 759: } else { ! 760: /* [NP] If cpu < 68020, m and t0 are ignored and should be set to 0 */ ! 761: regs.t0 = 0; ! 762: regs.m = 0; ! 763: ! 764: if (olds != regs.s) { ! 765: if (olds) { ! 766: regs.isp = m68k_areg(regs, 7); ! 767: m68k_areg(regs, 7) = regs.usp; ! 768: } else { ! 769: regs.usp = m68k_areg(regs, 7); ! 770: m68k_areg(regs, 7) = regs.isp; ! 771: } ! 772: } ! 773: } ! 774: ! 775: /* Pending interrupts can occur again after a write to the SR: */ ! 776: set_special (SPCFLAG_DOINT); ! 777: if (regs.t1 || regs.t0) ! 778: set_special (SPCFLAG_TRACE); ! 779: else ! 780: /* Keep SPCFLAG_DOTRACE, we still want a trace exception for ! 781: SR-modifying instructions (including STOP). */ ! 782: unset_special (SPCFLAG_TRACE); ! 783: } ! 784: ! 785: ! 786: static void exception_trace (int nr) ! 787: { ! 788: unset_special (SPCFLAG_TRACE | SPCFLAG_DOTRACE); ! 789: if (regs.t1 && !regs.t0) { ! 790: /* trace stays pending if exception is div by zero, chk, ! 791: * trapv or trap #x ! 792: */ ! 793: if (nr == 5 || nr == 6 || nr == 7 || (nr >= 32 && nr <= 47)) ! 794: set_special (SPCFLAG_DOTRACE); ! 795: } ! 796: regs.t1 = regs.t0 = regs.m = 0; ! 797: } ! 798: ! 799: ! 800: /* ! 801: * Compute the number of jitter cycles to add when a video interrupt occurs ! 802: * (this is specific to the Atari ST) ! 803: */ ! 804: static void InterruptAddJitter (int Level , int Pending) ! 805: { ! 806: } ! 807: ! 808: ! 809: /* Handle exceptions. We need a special case to handle MFP exceptions */ ! 810: /* on Atari ST, because it's possible to change the MFP's vector base */ ! 811: /* and get a conflict with 'normal' cpu exceptions. */ ! 812: void Exception(int nr, uaecptr oldpc, int ExceptionSource) ! 813: { ! 814: uae_u32 currpc = m68k_getpc (); ! 815: ! 816: /*if( nr>=2 && nr<10 ) fprintf(stderr,"Exception (-> %i bombs)!\n",nr);*/ ! 817: ! 818: ! 819: MakeSR(); ! 820: ! 821: /* Change to supervisor mode if necessary */ ! 822: if (!regs.s) { ! 823: regs.usp = m68k_areg(regs, 7); ! 824: if (currprefs.cpu_level >= 2) ! 825: m68k_areg(regs, 7) = regs.m ? regs.msp : regs.isp; ! 826: else ! 827: m68k_areg(regs, 7) = regs.isp; ! 828: regs.s = 1; ! 829: } ! 830: ! 831: /* Build additional exception stack frame for 68010 and higher */ ! 832: /* (special case for MFP) */ ! 833: if (currprefs.cpu_level > 0) { ! 834: if (nr == 2 || nr == 3) { ! 835: int i; ! 836: /* @@@ this is probably wrong (?) */ ! 837: for (i = 0 ; i < 12 ; i++) { ! 838: m68k_areg(regs, 7) -= 2; ! 839: put_word (m68k_areg(regs, 7), 0); ! 840: } ! 841: m68k_areg(regs, 7) -= 2; ! 842: put_word (m68k_areg(regs, 7), 0xa000 + nr * 4); ! 843: } else if (nr ==5 || nr == 6 || nr == 7 || nr == 9) { ! 844: m68k_areg(regs, 7) -= 4; ! 845: put_long (m68k_areg(regs, 7), oldpc); ! 846: m68k_areg(regs, 7) -= 2; ! 847: put_word (m68k_areg(regs, 7), 0x2000 + nr * 4); ! 848: } else if (regs.m && nr >= 24 && nr < 32) { ! 849: m68k_areg(regs, 7) -= 2; ! 850: put_word (m68k_areg(regs, 7), nr * 4); ! 851: m68k_areg(regs, 7) -= 4; ! 852: put_long (m68k_areg(regs, 7), currpc); ! 853: m68k_areg(regs, 7) -= 2; ! 854: put_word (m68k_areg(regs, 7), regs.sr); ! 855: regs.sr |= (1 << 13); ! 856: regs.msp = m68k_areg(regs, 7); ! 857: m68k_areg(regs, 7) = regs.isp; ! 858: m68k_areg(regs, 7) -= 2; ! 859: put_word (m68k_areg(regs, 7), 0x1000 + nr * 4); ! 860: } else { ! 861: m68k_areg(regs, 7) -= 2; ! 862: put_word (m68k_areg(regs, 7), nr * 4); ! 863: } ! 864: } ! 865: ! 866: /* Push PC on stack: */ ! 867: m68k_areg(regs, 7) -= 4; ! 868: put_long (m68k_areg(regs, 7), currpc); ! 869: /* Push SR on stack: */ ! 870: m68k_areg(regs, 7) -= 2; ! 871: put_word (m68k_areg(regs, 7), regs.sr); ! 872: ! 873: LOG_TRACE(TRACE_CPU_EXCEPTION, "cpu exception %d currpc %x buspc %x newpc %x fault_e3 %x op_e3 %hx addr_e3 %x\n", ! 874: nr, currpc, BusErrorPC, get_long (regs.vbr + 4*nr), last_fault_for_exception_3, last_op_for_exception_3, last_addr_for_exception_3); ! 875: ! 876: /* 68000 bus/address errors: */ ! 877: if (currprefs.cpu_level==0 && (nr==2 || nr==3) && ExceptionSource == M68000_EXC_SRC_CPU) { ! 878: uae_u16 specialstatus = 1; ! 879: ! 880: /* Special status word emulation isn't perfect yet... :-( */ ! 881: if (regs.sr & 0x2000) ! 882: specialstatus |= 0x4; ! 883: m68k_areg(regs, 7) -= 8; ! 884: if (nr == 3) { /* Address error */ ! 885: specialstatus |= ( last_op_for_exception_3 & (~0x1f) ); /* [NP] unused bits of specialstatus are those of the last opcode ! */ ! 886: put_word (m68k_areg(regs, 7), specialstatus); ! 887: put_long (m68k_areg(regs, 7)+2, last_fault_for_exception_3); ! 888: put_word (m68k_areg(regs, 7)+6, last_op_for_exception_3); ! 889: put_long (m68k_areg(regs, 7)+10, last_addr_for_exception_3); ! 890: if (bExceptionDebugging) { ! 891: fprintf(stderr,"Address Error at address $%x, PC=$%x\n",last_fault_for_exception_3,currpc); ! 892: DebugUI(); ! 893: } ! 894: } ! 895: else { /* Bus error */ ! 896: specialstatus |= ( get_word(BusErrorPC) & (~0x1f) ); /* [NP] unused bits of special status are those of the last opcode ! */ ! 897: if (bBusErrorReadWrite) ! 898: specialstatus |= 0x10; ! 899: put_word (m68k_areg(regs, 7), specialstatus); ! 900: put_long (m68k_areg(regs, 7)+2, BusErrorAddress); ! 901: put_word (m68k_areg(regs, 7)+6, get_word(BusErrorPC)); /* Opcode */ ! 902: ! 903: /* [NP] PC stored in the stack frame is not necessarily pointing to the next instruction ! */ ! 904: /* FIXME : we should have a proper model for this, in the meantime we handle specific cases */ ! 905: if ( get_word(BusErrorPC) == 0x21f8 ) /* move.l $0.w,$24.w (Transbeauce 2 loader) */ ! 906: put_long (m68k_areg(regs, 7)+10, currpc-2); /* correct PC is 2 bytes less than usual value */ ! 907: /* Check for double bus errors: */ ! 908: if (regs.spcflags & SPCFLAG_BUSERROR) { ! 909: fprintf(stderr, "Detected double bus error at address $%x, PC=$%lx => CPU halted!\n", ! 910: BusErrorAddress, (long)currpc); ! 911: unset_special(SPCFLAG_BUSERROR); ! 912: if (bExceptionDebugging) ! 913: DebugUI(); ! 914: else ! 915: DlgAlert_Notice("Detected double bus error => CPU halted!\nEmulation needs to be reseted.\n"); ! 916: regs.intmask = 7; ! 917: m68k_setstopped(true); ! 918: return; ! 919: } ! 920: if (bExceptionDebugging && BusErrorAddress!=0xff8a00) { ! 921: fprintf(stderr,"Bus Error at address $%x, PC=$%lx\n", BusErrorAddress, (long)currpc); ! 922: DebugUI(); ! 923: } ! 924: } ! 925: } ! 926: ! 927: /* Set PC and flags */ ! 928: if (bExceptionDebugging && get_long (regs.vbr + 4*nr) == 0) { ! 929: write_log("Uninitialized exception handler #%i!\n", nr); ! 930: DebugUI(); ! 931: } ! 932: m68k_setpc (get_long (regs.vbr + 4*nr)); ! 933: fill_prefetch_0 (); ! 934: /* Handle trace flags depending on current state */ ! 935: exception_trace (nr); ! 936: ! 937: /* Handle exception cycles (special case for MFP) */ ! 938: if (ExceptionSource == M68000_EXC_SRC_INT_MFP) ! 939: { ! 940: M68000_AddCycles(44+12); /* MFP interrupt, 'nr' can be in a different range depending on $fffa17 */ ! 941: } ! 942: else if (nr >= 24 && nr <= 31) ! 943: { ! 944: if ( nr == 26 ) /* HBL */ ! 945: { ! 946: /* store current cycle pos when then interrupt was received (see video.c) */ ! 947: // LastCycleHblException = Cycles_GetCounter(CYCLES_COUNTER_VIDEO); ! 948: M68000_AddCycles(44+12); /* Video Interrupt */ ! 949: } ! 950: else if ( nr == 28 ) /* VBL */ ! 951: M68000_AddCycles(44+12); /* Video Interrupt */ ! 952: else ! 953: M68000_AddCycles(44+4); /* Other Interrupts */ ! 954: } ! 955: else if(nr >= 32 && nr <= 47) ! 956: { ! 957: M68000_AddCycles(34-4); /* Trap (total is 34, but cpuemu.c already adds 4) */ ! 958: } ! 959: else switch(nr) ! 960: { ! 961: case 2: M68000_AddCycles(50); break; /* Bus error */ ! 962: case 3: M68000_AddCycles(50); break; /* Address error */ ! 963: case 4: M68000_AddCycles(34); break; /* Illegal instruction */ ! 964: case 5: M68000_AddCycles(38); break; /* Div by zero */ ! 965: case 6: M68000_AddCycles(40); break; /* CHK */ ! 966: case 7: M68000_AddCycles(34); break; /* TRAPV */ ! 967: case 8: M68000_AddCycles(34); break; /* Privilege violation */ ! 968: case 9: M68000_AddCycles(34); break; /* Trace */ ! 969: case 10: M68000_AddCycles(34); break; /* Line-A - probably wrong */ ! 970: case 11: M68000_AddCycles(34); break; /* Line-F - probably wrong */ ! 971: default: ! 972: /* FIXME: Add right cycles value for MFP interrupts and copro exceptions ... */ ! 973: if(nr < 64) ! 974: M68000_AddCycles(4); /* Coprocessor and unassigned exceptions (???) */ ! 975: else ! 976: M68000_AddCycles(44+12); /* Must be a MFP or DSP interrupt */ ! 977: break; ! 978: } ! 979: ! 980: } ! 981: ! 982: ! 983: static void Interrupt(int nr , int Pending) ! 984: { ! 985: assert(nr < 8 && nr >= 0); ! 986: /*lastint_regs = regs;*/ ! 987: /*lastint_no = nr;*/ ! 988: ! 989: /* On Hatari, only video ints are using SPCFLAG_INT (see m68000.c) */ ! 990: Exception(nr+24, 0, M68000_EXC_SRC_AUTOVEC); ! 991: ! 992: regs.intmask = nr; ! 993: set_special (SPCFLAG_INT); ! 994: ! 995: /* Handle Atari ST's specific jitter for hbl/vbl */ ! 996: InterruptAddJitter ( nr , Pending ); ! 997: } ! 998: ! 999: ! 1000: uae_u32 caar, cacr; ! 1001: static uae_u32 itt0, itt1, dtt0, dtt1, tc, mmusr, urp, srp; ! 1002: ! 1003: ! 1004: static int movec_illg (int regno) ! 1005: { ! 1006: int regno2 = regno & 0x7ff; ! 1007: if (currprefs.cpu_level == 1) { /* 68010 */ ! 1008: if (regno2 < 2) ! 1009: return 0; ! 1010: return 1; ! 1011: } ! 1012: if (currprefs.cpu_level == 2 || currprefs.cpu_level == 3) { /* 68020 */ ! 1013: if (regno == 3) return 1; /* 68040 only */ ! 1014: /* 4 is >=68040, but 0x804 is in 68020 */ ! 1015: if (regno2 < 4 || regno == 0x804) ! 1016: return 0; ! 1017: return 1; ! 1018: } ! 1019: if (currprefs.cpu_level >= 4) { /* 68040 */ ! 1020: if (regno == 0x802) return 1; /* 68020 only */ ! 1021: if (regno2 < 8) return 0; ! 1022: if (currprefs.cpu_level == 6 && regno2 == 8) /* 68060 only */ ! 1023: return 0; ! 1024: return 1; ! 1025: } ! 1026: return 1; ! 1027: } ! 1028: ! 1029: int m68k_move2c (int regno, uae_u32 *regp) ! 1030: { ! 1031: if (movec_illg (regno)) { ! 1032: op_illg (0x4E7B); ! 1033: return 0; ! 1034: } else { ! 1035: switch (regno) { ! 1036: case 0: regs.sfc = *regp & 7; break; ! 1037: case 1: regs.dfc = *regp & 7; break; ! 1038: case 2: ! 1039: { ! 1040: uae_u32 cacr_mask = 0; ! 1041: if (currprefs.cpu_level == 2) // 68020 ! 1042: cacr_mask = 0x0000000f; ! 1043: else if (currprefs.cpu_level == 3) // Fake 68030 ! 1044: cacr_mask = 0x00003f1f; ! 1045: else if (currprefs.cpu_level == 4) // 68040 ! 1046: cacr_mask = 0x80008000; ! 1047: cacr = *regp & cacr_mask; ! 1048: } ! 1049: case 3: tc = *regp & 0xc000; break; ! 1050: /* Mask out fields that should be zero. */ ! 1051: case 4: itt0 = *regp & 0xffffe364; break; ! 1052: case 5: itt1 = *regp & 0xffffe364; break; ! 1053: case 6: dtt0 = *regp & 0xffffe364; break; ! 1054: case 7: dtt1 = *regp & 0xffffe364; break; ! 1055: ! 1056: case 0x800: regs.usp = *regp; break; ! 1057: case 0x801: regs.vbr = *regp; break; ! 1058: case 0x802: caar = *regp & 0xfc; break; ! 1059: case 0x803: regs.msp = *regp; if (regs.m == 1) m68k_areg(regs, 7) = regs.msp; break; ! 1060: case 0x804: regs.isp = *regp; if (regs.m == 0) m68k_areg(regs, 7) = regs.isp; break; ! 1061: case 0x805: mmusr = *regp; break; ! 1062: case 0x806: urp = *regp; break; ! 1063: case 0x807: srp = *regp; break; ! 1064: default: ! 1065: op_illg (0x4E7B); ! 1066: return 0; ! 1067: } ! 1068: } ! 1069: return 1; ! 1070: } ! 1071: ! 1072: int m68k_movec2 (int regno, uae_u32 *regp) ! 1073: { ! 1074: if (movec_illg (regno)) { ! 1075: op_illg (0x4E7A); ! 1076: return 0; ! 1077: } else { ! 1078: switch (regno) { ! 1079: case 0: *regp = regs.sfc; break; ! 1080: case 1: *regp = regs.dfc; break; ! 1081: case 2: *regp = cacr; break; ! 1082: case 3: *regp = tc; break; ! 1083: case 4: *regp = itt0; break; ! 1084: case 5: *regp = itt1; break; ! 1085: case 6: *regp = dtt0; break; ! 1086: case 7: *regp = dtt1; break; ! 1087: case 0x800: *regp = regs.usp; break; ! 1088: case 0x801: *regp = regs.vbr; break; ! 1089: case 0x802: *regp = caar; break; ! 1090: case 0x803: *regp = regs.m == 1 ? m68k_areg(regs, 7) : regs.msp; break; ! 1091: case 0x804: *regp = regs.m == 0 ? m68k_areg(regs, 7) : regs.isp; break; ! 1092: case 0x805: *regp = mmusr; break; ! 1093: case 0x806: *regp = urp; break; ! 1094: case 0x807: *regp = srp; break; ! 1095: default: ! 1096: op_illg (0x4E7A); ! 1097: return 0; ! 1098: } ! 1099: } ! 1100: return 1; ! 1101: } ! 1102: ! 1103: STATIC_INLINE int ! 1104: div_unsigned(uae_u32 src_hi, uae_u32 src_lo, uae_u32 ndiv, uae_u32 *quot, uae_u32 *rem) ! 1105: { ! 1106: uae_u32 q = 0, cbit = 0; ! 1107: int i; ! 1108: ! 1109: if (ndiv <= src_hi) { ! 1110: return 1; ! 1111: } ! 1112: for (i = 0 ; i < 32 ; i++) { ! 1113: cbit = src_hi & 0x80000000ul; ! 1114: src_hi <<= 1; ! 1115: if (src_lo & 0x80000000ul) src_hi++; ! 1116: src_lo <<= 1; ! 1117: q = q << 1; ! 1118: if (cbit || ndiv <= src_hi) { ! 1119: q |= 1; ! 1120: src_hi -= ndiv; ! 1121: } ! 1122: } ! 1123: *quot = q; ! 1124: *rem = src_hi; ! 1125: return 0; ! 1126: } ! 1127: ! 1128: void m68k_divl (uae_u32 opcode, uae_u32 src, uae_u16 extra, uaecptr oldpc) ! 1129: { ! 1130: #if defined(uae_s64) ! 1131: if (src == 0) { ! 1132: Exception (5, oldpc,M68000_EXC_SRC_CPU); ! 1133: return; ! 1134: } ! 1135: if (extra & 0x800) { ! 1136: /* signed variant */ ! 1137: uae_s64 a = (uae_s64)(uae_s32)m68k_dreg(regs, (extra >> 12) & 7); ! 1138: uae_s64 quot, rem; ! 1139: ! 1140: if (extra & 0x400) { ! 1141: a &= 0xffffffffu; ! 1142: a |= (uae_s64)m68k_dreg(regs, extra & 7) << 32; ! 1143: } ! 1144: rem = a % (uae_s64)(uae_s32)src; ! 1145: quot = a / (uae_s64)(uae_s32)src; ! 1146: if ((quot & UVAL64(0xffffffff80000000)) != 0 ! 1147: && (quot & UVAL64(0xffffffff80000000)) != UVAL64(0xffffffff80000000)) ! 1148: { ! 1149: SET_VFLG (1); ! 1150: SET_NFLG (1); ! 1151: SET_CFLG (0); ! 1152: } else { ! 1153: if (((uae_s32)rem < 0) != ((uae_s64)a < 0)) rem = -rem; ! 1154: SET_VFLG (0); ! 1155: SET_CFLG (0); ! 1156: SET_ZFLG (((uae_s32)quot) == 0); ! 1157: SET_NFLG (((uae_s32)quot) < 0); ! 1158: m68k_dreg(regs, extra & 7) = rem; ! 1159: m68k_dreg(regs, (extra >> 12) & 7) = quot; ! 1160: } ! 1161: } else { ! 1162: /* unsigned */ ! 1163: uae_u64 a = (uae_u64)(uae_u32)m68k_dreg(regs, (extra >> 12) & 7); ! 1164: uae_u64 quot, rem; ! 1165: ! 1166: if (extra & 0x400) { ! 1167: a &= 0xffffffffu; ! 1168: a |= (uae_u64)m68k_dreg(regs, extra & 7) << 32; ! 1169: } ! 1170: rem = a % (uae_u64)src; ! 1171: quot = a / (uae_u64)src; ! 1172: if (quot > 0xffffffffu) { ! 1173: SET_VFLG (1); ! 1174: SET_NFLG (1); ! 1175: SET_CFLG (0); ! 1176: } else { ! 1177: SET_VFLG (0); ! 1178: SET_CFLG (0); ! 1179: SET_ZFLG (((uae_s32)quot) == 0); ! 1180: SET_NFLG (((uae_s32)quot) < 0); ! 1181: m68k_dreg(regs, extra & 7) = rem; ! 1182: m68k_dreg(regs, (extra >> 12) & 7) = quot; ! 1183: } ! 1184: } ! 1185: #else ! 1186: if (src == 0) { ! 1187: Exception (5, oldpc,M68000_EXC_SRC_CPU); ! 1188: return; ! 1189: } ! 1190: if (extra & 0x800) { ! 1191: /* signed variant */ ! 1192: uae_s32 lo = (uae_s32)m68k_dreg(regs, (extra >> 12) & 7); ! 1193: uae_s32 hi = lo < 0 ? -1 : 0; ! 1194: uae_s32 save_high; ! 1195: uae_u32 quot, rem; ! 1196: uae_u32 sign; ! 1197: ! 1198: if (extra & 0x400) { ! 1199: hi = (uae_s32)m68k_dreg(regs, extra & 7); ! 1200: } ! 1201: save_high = hi; ! 1202: sign = (hi ^ src); ! 1203: if (hi < 0) { ! 1204: hi = ~hi; ! 1205: lo = -lo; ! 1206: if (lo == 0) hi++; ! 1207: } ! 1208: if ((uae_s32)src < 0) src = -src; ! 1209: if (div_unsigned(hi, lo, src, ", &rem) || ! 1210: (sign & 0x80000000) ? quot > 0x80000000 : quot > 0x7fffffff) { ! 1211: SET_VFLG (1); ! 1212: SET_NFLG (1); ! 1213: SET_CFLG (0); ! 1214: } else { ! 1215: if (sign & 0x80000000) quot = -quot; ! 1216: if (((uae_s32)rem < 0) != (save_high < 0)) rem = -rem; ! 1217: SET_VFLG (0); ! 1218: SET_CFLG (0); ! 1219: SET_ZFLG (((uae_s32)quot) == 0); ! 1220: SET_NFLG (((uae_s32)quot) < 0); ! 1221: m68k_dreg(regs, extra & 7) = rem; ! 1222: m68k_dreg(regs, (extra >> 12) & 7) = quot; ! 1223: } ! 1224: } else { ! 1225: /* unsigned */ ! 1226: uae_u32 lo = (uae_u32)m68k_dreg(regs, (extra >> 12) & 7); ! 1227: uae_u32 hi = 0; ! 1228: uae_u32 quot, rem; ! 1229: ! 1230: if (extra & 0x400) { ! 1231: hi = (uae_u32)m68k_dreg(regs, extra & 7); ! 1232: } ! 1233: if (div_unsigned(hi, lo, src, ", &rem)) { ! 1234: SET_VFLG (1); ! 1235: SET_NFLG (1); ! 1236: SET_CFLG (0); ! 1237: } else { ! 1238: SET_VFLG (0); ! 1239: SET_CFLG (0); ! 1240: SET_ZFLG (((uae_s32)quot) == 0); ! 1241: SET_NFLG (((uae_s32)quot) < 0); ! 1242: m68k_dreg(regs, extra & 7) = rem; ! 1243: m68k_dreg(regs, (extra >> 12) & 7) = quot; ! 1244: } ! 1245: } ! 1246: #endif ! 1247: } ! 1248: ! 1249: STATIC_INLINE void ! 1250: mul_unsigned(uae_u32 src1, uae_u32 src2, uae_u32 *dst_hi, uae_u32 *dst_lo) ! 1251: { ! 1252: uae_u32 r0 = (src1 & 0xffff) * (src2 & 0xffff); ! 1253: uae_u32 r1 = ((src1 >> 16) & 0xffff) * (src2 & 0xffff); ! 1254: uae_u32 r2 = (src1 & 0xffff) * ((src2 >> 16) & 0xffff); ! 1255: uae_u32 r3 = ((src1 >> 16) & 0xffff) * ((src2 >> 16) & 0xffff); ! 1256: uae_u32 lo; ! 1257: ! 1258: lo = r0 + ((r1 << 16) & 0xffff0000ul); ! 1259: if (lo < r0) r3++; ! 1260: r0 = lo; ! 1261: lo = r0 + ((r2 << 16) & 0xffff0000ul); ! 1262: if (lo < r0) r3++; ! 1263: r3 += ((r1 >> 16) & 0xffff) + ((r2 >> 16) & 0xffff); ! 1264: *dst_lo = lo; ! 1265: *dst_hi = r3; ! 1266: } ! 1267: ! 1268: void m68k_mull (uae_u32 opcode, uae_u32 src, uae_u16 extra) ! 1269: { ! 1270: #if defined(uae_s64) ! 1271: if (extra & 0x800) { ! 1272: /* signed variant */ ! 1273: uae_s64 a = (uae_s64)(uae_s32)m68k_dreg(regs, (extra >> 12) & 7); ! 1274: ! 1275: a *= (uae_s64)(uae_s32)src; ! 1276: SET_VFLG (0); ! 1277: SET_CFLG (0); ! 1278: SET_ZFLG (a == 0); ! 1279: SET_NFLG (a < 0); ! 1280: if (extra & 0x400) ! 1281: m68k_dreg(regs, extra & 7) = a >> 32; ! 1282: else if ((a & UVAL64(0xffffffff80000000)) != 0 ! 1283: && (a & UVAL64(0xffffffff80000000)) != UVAL64(0xffffffff80000000)) ! 1284: { ! 1285: SET_VFLG (1); ! 1286: } ! 1287: m68k_dreg(regs, (extra >> 12) & 7) = (uae_u32)a; ! 1288: } else { ! 1289: /* unsigned */ ! 1290: uae_u64 a = (uae_u64)(uae_u32)m68k_dreg(regs, (extra >> 12) & 7); ! 1291: ! 1292: a *= (uae_u64)src; ! 1293: SET_VFLG (0); ! 1294: SET_CFLG (0); ! 1295: SET_ZFLG (a == 0); ! 1296: SET_NFLG (((uae_s64)a) < 0); ! 1297: if (extra & 0x400) ! 1298: m68k_dreg(regs, extra & 7) = a >> 32; ! 1299: else if ((a & UVAL64(0xffffffff00000000)) != 0) { ! 1300: SET_VFLG (1); ! 1301: } ! 1302: m68k_dreg(regs, (extra >> 12) & 7) = (uae_u32)a; ! 1303: } ! 1304: #else ! 1305: if (extra & 0x800) { ! 1306: /* signed variant */ ! 1307: uae_s32 src1,src2; ! 1308: uae_u32 dst_lo,dst_hi; ! 1309: uae_u32 sign; ! 1310: ! 1311: src1 = (uae_s32)src; ! 1312: src2 = (uae_s32)m68k_dreg(regs, (extra >> 12) & 7); ! 1313: sign = (src1 ^ src2); ! 1314: if (src1 < 0) src1 = -src1; ! 1315: if (src2 < 0) src2 = -src2; ! 1316: mul_unsigned((uae_u32)src1,(uae_u32)src2,&dst_hi,&dst_lo); ! 1317: if (sign & 0x80000000) { ! 1318: dst_hi = ~dst_hi; ! 1319: dst_lo = -dst_lo; ! 1320: if (dst_lo == 0) dst_hi++; ! 1321: } ! 1322: SET_VFLG (0); ! 1323: SET_CFLG (0); ! 1324: SET_ZFLG (dst_hi == 0 && dst_lo == 0); ! 1325: SET_NFLG (((uae_s32)dst_hi) < 0); ! 1326: if (extra & 0x400) ! 1327: m68k_dreg(regs, extra & 7) = dst_hi; ! 1328: else if ((dst_hi != 0 || (dst_lo & 0x80000000) != 0) ! 1329: && ((dst_hi & 0xffffffff) != 0xffffffff ! 1330: || (dst_lo & 0x80000000) != 0x80000000)) ! 1331: { ! 1332: SET_VFLG (1); ! 1333: } ! 1334: m68k_dreg(regs, (extra >> 12) & 7) = dst_lo; ! 1335: } else { ! 1336: /* unsigned */ ! 1337: uae_u32 dst_lo,dst_hi; ! 1338: ! 1339: mul_unsigned(src,(uae_u32)m68k_dreg(regs, (extra >> 12) & 7),&dst_hi,&dst_lo); ! 1340: ! 1341: SET_VFLG (0); ! 1342: SET_CFLG (0); ! 1343: SET_ZFLG (dst_hi == 0 && dst_lo == 0); ! 1344: SET_NFLG (((uae_s32)dst_hi) < 0); ! 1345: if (extra & 0x400) ! 1346: m68k_dreg(regs, extra & 7) = dst_hi; ! 1347: else if (dst_hi != 0) { ! 1348: SET_VFLG (1); ! 1349: } ! 1350: m68k_dreg(regs, (extra >> 12) & 7) = dst_lo; ! 1351: } ! 1352: #endif ! 1353: } ! 1354: ! 1355: ! 1356: void m68k_reset (void) ! 1357: { ! 1358: regs.s = 1; ! 1359: regs.m = 0; ! 1360: regs.stopped = 0; ! 1361: regs.t1 = 0; ! 1362: regs.t0 = 0; ! 1363: SET_ZFLG (0); ! 1364: SET_XFLG (0); ! 1365: SET_CFLG (0); ! 1366: SET_VFLG (0); ! 1367: SET_NFLG (0); ! 1368: regs.spcflags &= ( SPCFLAG_MODE_CHANGE | SPCFLAG_DEBUGGER ); /* Clear specialflags except mode-change and debugger */ ! 1369: regs.intmask = 7; ! 1370: regs.vbr = regs.sfc = regs.dfc = 0; ! 1371: regs.fpcr = regs.fpsr = regs.fpiar = 0; ! 1372: ! 1373: m68k_areg(regs, 7) = get_long(0); ! 1374: m68k_setpc(get_long(4)); ! 1375: refill_prefetch (m68k_getpc(), 0); ! 1376: } ! 1377: ! 1378: ! 1379: unsigned long REGPARAM2 op_illg (uae_u32 opcode) ! 1380: { ! 1381: #if 0 ! 1382: uaecptr pc = m68k_getpc (); ! 1383: #endif ! 1384: if ((opcode & 0xF000) == 0xF000) { ! 1385: Exception(0xB,0,M68000_EXC_SRC_CPU); ! 1386: return 4; ! 1387: } ! 1388: if ((opcode & 0xF000) == 0xA000) { ! 1389: Exception(0xA,0,M68000_EXC_SRC_CPU); ! 1390: return 4; ! 1391: } ! 1392: #if 0 ! 1393: write_log ("Illegal instruction: %04x at %08lx\n", opcode, (long)pc); ! 1394: #endif ! 1395: Exception (4,0,M68000_EXC_SRC_CPU); ! 1396: return 4; ! 1397: } ! 1398: ! 1399: ! 1400: void mmu_op(uae_u32 opcode, uae_u16 extra) ! 1401: { ! 1402: if ((opcode & 0xFE0) == 0x0500) { ! 1403: /* PFLUSH */ ! 1404: mmusr = 0; ! 1405: write_log ("PFLUSH\n"); ! 1406: } else if ((opcode & 0x0FD8) == 0x548) { ! 1407: /* PTEST */ ! 1408: write_log ("PTEST\n"); ! 1409: } else ! 1410: op_illg (opcode); ! 1411: } ! 1412: ! 1413: ! 1414: static uaecptr last_trace_ad = 0; ! 1415: ! 1416: static void do_trace (void) ! 1417: { ! 1418: if (regs.t0 && currprefs.cpu_level >= 2) { ! 1419: uae_u16 opcode; ! 1420: /* should also include TRAP, CHK, SR modification FPcc */ ! 1421: /* probably never used so why bother */ ! 1422: /* We can afford this to be inefficient... */ ! 1423: m68k_setpc (m68k_getpc ()); ! 1424: fill_prefetch_0 (); ! 1425: opcode = get_word (regs.pc); ! 1426: if (opcode == 0x4e72 /* RTE */ ! 1427: || opcode == 0x4e74 /* RTD */ ! 1428: || opcode == 0x4e75 /* RTS */ ! 1429: || opcode == 0x4e77 /* RTR */ ! 1430: || opcode == 0x4e76 /* TRAPV */ ! 1431: || (opcode & 0xffc0) == 0x4e80 /* JSR */ ! 1432: || (opcode & 0xffc0) == 0x4ec0 /* JMP */ ! 1433: || (opcode & 0xff00) == 0x6100 /* BSR */ ! 1434: || ((opcode & 0xf000) == 0x6000 /* Bcc */ ! 1435: && cctrue((opcode >> 8) & 0xf)) ! 1436: || ((opcode & 0xf0f0) == 0x5050 /* DBcc */ ! 1437: && !cctrue((opcode >> 8) & 0xf) ! 1438: && (uae_s16)m68k_dreg(regs, opcode & 7) != 0)) ! 1439: { ! 1440: last_trace_ad = m68k_getpc (); ! 1441: unset_special (SPCFLAG_TRACE); ! 1442: set_special (SPCFLAG_DOTRACE); ! 1443: } ! 1444: } else if (regs.t1) { ! 1445: last_trace_ad = m68k_getpc (); ! 1446: unset_special (SPCFLAG_TRACE); ! 1447: set_special (SPCFLAG_DOTRACE); ! 1448: } ! 1449: } ! 1450: ! 1451: ! 1452: /* ! 1453: * Handle special flags ! 1454: */ ! 1455: ! 1456: static bool do_specialties_interrupt (int Pending) ! 1457: { ! 1458: return false; /* no interrupt was found */ ! 1459: } ! 1460: ! 1461: ! 1462: static int do_specialties (void) ! 1463: { ! 1464: if(regs.spcflags & SPCFLAG_BUSERROR) { ! 1465: /* We can not execute bus errors directly in the memory handler ! 1466: * functions since the PC should point to the address of the next ! 1467: * instruction, so we're executing the bus errors here: */ ! 1468: unset_special(SPCFLAG_BUSERROR); ! 1469: Exception(2,0,M68000_EXC_SRC_CPU); ! 1470: } ! 1471: ! 1472: if(regs.spcflags & SPCFLAG_EXTRA_CYCLES) { ! 1473: /* Add some extra cycles to simulate a wait state */ ! 1474: unset_special(SPCFLAG_EXTRA_CYCLES); ! 1475: M68000_AddCycles(nWaitStateCycles); ! 1476: nWaitStateCycles = 0; ! 1477: } ! 1478: ! 1479: if (regs.spcflags & SPCFLAG_DOTRACE) { ! 1480: Exception (9,last_trace_ad,M68000_EXC_SRC_CPU); ! 1481: } ! 1482: ! 1483: ! 1484: /* Handle the STOP instruction */ ! 1485: if ( regs.spcflags & SPCFLAG_STOP ) { ! 1486: /* We first test if there's a pending interrupt that would */ ! 1487: /* allow to immediatly leave the STOP state */ ! 1488: if ( do_specialties_interrupt(true) ) { /* test if there's an interrupt and add pending jitter */ ! 1489: regs.stopped = 0; ! 1490: unset_special (SPCFLAG_STOP); ! 1491: } ! 1492: ! 1493: /* No pending int, we have to wait for the next matching int */ ! 1494: while (regs.spcflags & SPCFLAG_STOP) { ! 1495: ! 1496: /* Take care of quit event if needed */ ! 1497: if (regs.spcflags & SPCFLAG_BRK) ! 1498: return 1; ! 1499: ! 1500: M68000_AddCycles(4); ! 1501: ! 1502: /* It is possible one or more ints happen at the same time */ ! 1503: /* We must process them during the same cpu cycle until the special INT flag is set */ ! 1504: while (PendingInterruptCount<=0 && PendingInterruptFunction) { ! 1505: /* 1st, we call the interrupt handler */ ! 1506: CALL_VAR(PendingInterruptFunction); ! 1507: ! 1508: /* Then we check if this handler triggered an interrupt to process */ ! 1509: if ( do_specialties_interrupt(false) ) { /* test if there's an interrupt and add non pending jitter */ ! 1510: regs.stopped = 0; ! 1511: unset_special (SPCFLAG_STOP); ! 1512: break; ! 1513: } ! 1514: } ! 1515: } ! 1516: } ! 1517: ! 1518: ! 1519: if (regs.spcflags & SPCFLAG_TRACE) ! 1520: do_trace (); ! 1521: ! 1522: // if (regs.spcflags & SPCFLAG_DOINT) { ! 1523: /* [NP] pending int should be processed now, not after the current instr */ ! 1524: /* so we check for (SPCFLAG_INT | SPCFLAG_DOINT), not just for SPCFLAG_DOINT */ ! 1525: ! 1526: if ( do_specialties_interrupt(false) ) { /* test if there's an interrupt and add non pending jitter */ ! 1527: regs.stopped = 0; /* [NP] useless ? */ ! 1528: } ! 1529: if (regs.spcflags & SPCFLAG_INT) { ! 1530: unset_special (SPCFLAG_INT); ! 1531: set_special (SPCFLAG_DOINT); ! 1532: } ! 1533: ! 1534: if (regs.spcflags & SPCFLAG_DEBUGGER) ! 1535: DebugCpu_Check(); ! 1536: ! 1537: if (regs.spcflags & (SPCFLAG_BRK | SPCFLAG_MODE_CHANGE)) { ! 1538: unset_special(SPCFLAG_MODE_CHANGE); ! 1539: return 1; ! 1540: } ! 1541: ! 1542: return 0; ! 1543: } ! 1544: ! 1545: ! 1546: /* It's really sad to have two almost identical functions for this, but we ! 1547: do it all for performance... :( */ ! 1548: static void m68k_run_1 (void) ! 1549: { ! 1550: #ifdef DEBUG_PREFETCH ! 1551: uae_u8 saved_bytes[20]; ! 1552: uae_u16 *oldpcp; ! 1553: #endif ! 1554: ! 1555: for (;;) { ! 1556: int cycles; ! 1557: uae_u32 opcode = get_iword_prefetch (0); ! 1558: ! 1559: #ifdef DEBUG_PREFETCH ! 1560: if (get_ilong (0) != do_get_mem_long (®s.prefetch)) { ! 1561: fprintf (stderr, "Prefetch differs from memory.\n"); ! 1562: debugging = 1; ! 1563: return; ! 1564: } ! 1565: oldpcp = regs.pc_p; ! 1566: memcpy (saved_bytes, regs.pc_p, 20); ! 1567: #endif ! 1568: ! 1569: /*m68k_dumpstate(stderr, NULL);*/ ! 1570: if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM)) ! 1571: { ! 1572: int FrameCycles, HblCounterVideo, LineCycles; ! 1573: ! 1574: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles ); ! 1575: ! 1576: LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo ); ! 1577: m68k_disasm(stderr, m68k_getpc (), NULL, 1); ! 1578: } ! 1579: ! 1580: /* assert (!regs.stopped && !(regs.spcflags & SPCFLAG_STOP)); */ ! 1581: /* regs_backup[backup_pointer = (backup_pointer + 1) % 16] = regs;*/ ! 1582: #if COUNT_INSTRS == 2 ! 1583: if (table68k[opcode].handler != -1) ! 1584: instrcount[table68k[opcode].handler]++; ! 1585: #elif COUNT_INSTRS == 1 ! 1586: instrcount[opcode]++; ! 1587: #endif ! 1588: ! 1589: /* In case of a Bus Error, we need the PC of the instruction that caused */ ! 1590: /* the error to build the exception stack frame */ ! 1591: BusErrorPC = m68k_getpc(); ! 1592: ! 1593: cycles = (*cpufunctbl[opcode])(opcode); ! 1594: ! 1595: #ifdef DEBUG_PREFETCH ! 1596: if (memcmp (saved_bytes, oldpcp, 20) != 0) { ! 1597: fprintf (stderr, "Self-modifying code detected %x.\n" , m68k_getpc() ); ! 1598: set_special (SPCFLAG_BRK); ! 1599: debugging = 1; ! 1600: } ! 1601: #endif ! 1602: ! 1603: ! 1604: M68000_AddCyclesWithPairing(cycles); ! 1605: if (regs.spcflags & SPCFLAG_EXTRA_CYCLES) { ! 1606: /* Add some extra cycles to simulate a wait state */ ! 1607: unset_special(SPCFLAG_EXTRA_CYCLES); ! 1608: M68000_AddCycles(nWaitStateCycles); ! 1609: nWaitStateCycles = 0; ! 1610: } ! 1611: ! 1612: #if 0 ! 1613: while (PendingInterruptCount <= 0 && PendingInterruptFunction) ! 1614: CALL_VAR(PendingInterruptFunction); ! 1615: #else ! 1616: /* We can have several interrupts at the same time before the next CPU instruction */ ! 1617: /* We must check for pending interrupt and call do_specialties_interrupt() only */ ! 1618: /* if the cpu is not in the STOP state. Else, the int could be acknowledged now */ ! 1619: /* and prevent exiting the STOP state when calling do_specialties() after. */ ! 1620: /* For performance, we first test PendingInterruptCount, then regs.spcflags */ ! 1621: while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) && ( ( regs.spcflags & SPCFLAG_STOP ) == 0 ) ) ! 1622: { ! 1623: CALL_VAR(PendingInterruptFunction); /* call the interrupt handler */ ! 1624: do_specialties_interrupt(false); /* test if there's an mfp/video interrupt and add non pending jitter */ ! 1625: #if 0 ! 1626: if ( regs.spcflags & ( SPCFLAG_MFP | SPCFLAG_INT ) ) { /* only check mfp/video interrupts */ ! 1627: if (do_specialties ()) /* check if this latest int has higher priority */ ! 1628: return; ! 1629: } ! 1630: #endif ! 1631: } ! 1632: #endif ! 1633: ! 1634: if (regs.spcflags) { ! 1635: if (do_specialties ()) ! 1636: return; ! 1637: } ! 1638: ! 1639: } ! 1640: } ! 1641: ! 1642: ! 1643: /* Same thing, but don't use prefetch to get opcode. */ ! 1644: static void m68k_run_2 (void) ! 1645: { ! 1646: for (;;) { ! 1647: int cycles; ! 1648: uae_u32 opcode = get_iword (0); ! 1649: ! 1650: /*m68k_dumpstate(stderr, NULL);*/ ! 1651: if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM)) ! 1652: { ! 1653: int FrameCycles, HblCounterVideo, LineCycles; ! 1654: ! 1655: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles ); ! 1656: ! 1657: LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo ); ! 1658: m68k_disasm(stderr, m68k_getpc (), NULL, 1); ! 1659: } ! 1660: ! 1661: /* assert (!regs.stopped && !(regs.spcflags & SPCFLAG_STOP)); */ ! 1662: /* regs_backup[backup_pointer = (backup_pointer + 1) % 16] = regs;*/ ! 1663: #if COUNT_INSTRS == 2 ! 1664: if (table68k[opcode].handler != -1) ! 1665: instrcount[table68k[opcode].handler]++; ! 1666: #elif COUNT_INSTRS == 1 ! 1667: instrcount[opcode]++; ! 1668: #endif ! 1669: ! 1670: cycles = (*cpufunctbl[opcode])(opcode); ! 1671: ! 1672: ! 1673: M68000_AddCycles(cycles); ! 1674: if (regs.spcflags & SPCFLAG_EXTRA_CYCLES) { ! 1675: /* Add some extra cycles to simulate a wait state */ ! 1676: unset_special(SPCFLAG_EXTRA_CYCLES); ! 1677: M68000_AddCycles(nWaitStateCycles); ! 1678: nWaitStateCycles = 0; ! 1679: } ! 1680: ! 1681: while (PendingInterruptCount <= 0 && PendingInterruptFunction) ! 1682: CALL_VAR(PendingInterruptFunction); ! 1683: ! 1684: if (regs.spcflags) { ! 1685: if (do_specialties ()) ! 1686: return; ! 1687: } ! 1688: ! 1689: } ! 1690: } ! 1691: ! 1692: ! 1693: void m68k_go (int may_quit) ! 1694: { ! 1695: static int in_m68k_go = 0; ! 1696: ! 1697: if (in_m68k_go || !may_quit) { ! 1698: write_log ("Bug! m68k_go is not reentrant.\n"); ! 1699: abort (); ! 1700: } ! 1701: ! 1702: in_m68k_go++; ! 1703: while (!(regs.spcflags & SPCFLAG_BRK)) { ! 1704: if(currprefs.cpu_compatible) ! 1705: m68k_run_1(); ! 1706: else ! 1707: m68k_run_2(); ! 1708: } ! 1709: unset_special(SPCFLAG_BRK); ! 1710: in_m68k_go--; ! 1711: } ! 1712: ! 1713: ! 1714: /* ! 1715: static void m68k_verify (uaecptr addr, uaecptr *nextpc) ! 1716: { ! 1717: uae_u32 opcode, val; ! 1718: struct instr *dp; ! 1719: ! 1720: opcode = get_iword_1(0); ! 1721: last_op_for_exception_3 = opcode; ! 1722: m68kpc_offset = 2; ! 1723: ! 1724: if (cpufunctbl[opcode] == op_illg_1) { ! 1725: opcode = 0x4AFC; ! 1726: } ! 1727: dp = table68k + opcode; ! 1728: ! 1729: if (dp->suse) { ! 1730: if (!verify_ea (dp->sreg, dp->smode, dp->size, &val)) { ! 1731: Exception (3, 0,M68000_EXC_SRC_CPU); ! 1732: return; ! 1733: } ! 1734: } ! 1735: if (dp->duse) { ! 1736: if (!verify_ea (dp->dreg, dp->dmode, dp->size, &val)) { ! 1737: Exception (3, 0,M68000_EXC_SRC_CPU); ! 1738: return; ! 1739: } ! 1740: } ! 1741: } ! 1742: */ ! 1743: ! 1744: ! 1745: void m68k_disasm (FILE *f, uaecptr addr, uaecptr *nextpc, int cnt) ! 1746: { ! 1747: static const char * const ccnames[] = ! 1748: { "T ","F ","HI","LS","CC","CS","NE","EQ", ! 1749: "VC","VS","PL","MI","GE","LT","GT","LE" }; ! 1750: ! 1751: uaecptr newpc = 0; ! 1752: m68kpc_offset = addr - m68k_getpc (); ! 1753: while (cnt-- > 0) { ! 1754: char instrname[20],*ccpt; ! 1755: int opwords; ! 1756: uae_u32 opcode; ! 1757: const struct mnemolookup *lookup; ! 1758: struct instr *dp; ! 1759: fprintf (f, "%08lx: ", m68k_getpc () + m68kpc_offset); ! 1760: for (opwords = 0; opwords < 5; opwords++){ ! 1761: fprintf (f, "%04x ", get_iword_1 (m68kpc_offset + opwords*2)); ! 1762: } ! 1763: opcode = get_iword_1 (m68kpc_offset); ! 1764: m68kpc_offset += 2; ! 1765: if (cpufunctbl[opcode] == op_illg_1) { ! 1766: opcode = 0x4AFC; ! 1767: } ! 1768: dp = table68k + opcode; ! 1769: for (lookup = lookuptab;lookup->mnemo != dp->mnemo; lookup++) ! 1770: ; ! 1771: ! 1772: strcpy (instrname, lookup->name); ! 1773: ccpt = strstr (instrname, "cc"); ! 1774: if (ccpt != 0) { ! 1775: strncpy (ccpt, ccnames[dp->cc], 2); ! 1776: } ! 1777: fprintf (f, "%s", instrname); ! 1778: switch (dp->size){ ! 1779: case sz_byte: fprintf (f, ".B "); break; ! 1780: case sz_word: fprintf (f, ".W "); break; ! 1781: case sz_long: fprintf (f, ".L "); break; ! 1782: default: fprintf (f, " "); break; ! 1783: } ! 1784: ! 1785: if (dp->suse) { ! 1786: newpc = m68k_getpc () + m68kpc_offset; ! 1787: newpc += ShowEA (f, dp->sreg, dp->smode, dp->size, 0); ! 1788: } ! 1789: if (dp->suse && dp->duse) ! 1790: fprintf (f, ","); ! 1791: if (dp->duse) { ! 1792: newpc = m68k_getpc () + m68kpc_offset; ! 1793: newpc += ShowEA (f, dp->dreg, dp->dmode, dp->size, 0); ! 1794: } ! 1795: if (ccpt != 0) { ! 1796: if (cctrue(dp->cc)) ! 1797: fprintf (f, " == %08lx (TRUE)", (long)newpc); ! 1798: else ! 1799: fprintf (f, " == %08lx (FALSE)", (long)newpc); ! 1800: } else if ((opcode & 0xff00) == 0x6100) /* BSR */ ! 1801: fprintf (f, " == %08lx", (long)newpc); ! 1802: fprintf (f, "\n"); ! 1803: } ! 1804: if (nextpc) ! 1805: *nextpc = m68k_getpc () + m68kpc_offset; ! 1806: } ! 1807: ! 1808: void m68k_dumpstate (FILE *f, uaecptr *nextpc) ! 1809: { ! 1810: int i; ! 1811: for (i = 0; i < 8; i++){ ! 1812: fprintf (f, "D%d: %08lx ", i, (long)m68k_dreg(regs, i)); ! 1813: if ((i & 3) == 3) fprintf (f, "\n"); ! 1814: } ! 1815: for (i = 0; i < 8; i++){ ! 1816: fprintf (f, "A%d: %08lx ", i, (long)m68k_areg(regs, i)); ! 1817: if ((i & 3) == 3) fprintf (f, "\n"); ! 1818: } ! 1819: if (regs.s == 0) regs.usp = m68k_areg(regs, 7); ! 1820: if (regs.s && regs.m) regs.msp = m68k_areg(regs, 7); ! 1821: if (regs.s && regs.m == 0) regs.isp = m68k_areg(regs, 7); ! 1822: fprintf (f, "USP=%08lx ISP=%08lx MSP=%08lx VBR=%08lx\n", ! 1823: (long)regs.usp,(long)regs.isp,(long)regs.msp,(long)regs.vbr); ! 1824: fprintf (f, "T=%d%d S=%d M=%d X=%d N=%d Z=%d V=%d C=%d IMASK=%d\n", ! 1825: regs.t1, regs.t0, regs.s, regs.m, ! 1826: GET_XFLG, GET_NFLG, GET_ZFLG, GET_VFLG, GET_CFLG, regs.intmask); ! 1827: for (i = 0; i < 8; i++){ ! 1828: fprintf (f, "FP%d: %g ", i, regs.fp[i]); ! 1829: if ((i & 3) == 3) fprintf (f, "\n"); ! 1830: } ! 1831: fprintf (f, "N=%d Z=%d I=%d NAN=%d\n", ! 1832: (regs.fpsr & 0x8000000) != 0, ! 1833: (regs.fpsr & 0x4000000) != 0, ! 1834: (regs.fpsr & 0x2000000) != 0, ! 1835: (regs.fpsr & 0x1000000) != 0); ! 1836: if (currprefs.cpu_compatible) ! 1837: fprintf (f, "prefetch %08lx\n", (unsigned long)do_get_mem_long(®s.prefetch)); ! 1838: ! 1839: m68k_disasm (f, m68k_getpc (), nextpc, 1); ! 1840: if (nextpc) ! 1841: fprintf (f, "next PC: %08lx\n", (long)*nextpc); ! 1842: } ! 1843: ! 1844: ! 1845: /* ! 1846: ! 1847: The routines below take dividend and divisor as parameters. ! 1848: They return 0 if division by zero, or exact number of cycles otherwise. ! 1849: ! 1850: The number of cycles returned assumes a register operand. ! 1851: Effective address time must be added if memory operand. ! 1852: ! 1853: For 68000 only (not 68010, 68012, 68020, etc). ! 1854: Probably valid for 68008 after adding the extra prefetch cycle. ! 1855: ! 1856: ! 1857: Best and worst cases are for register operand: ! 1858: (Note the difference with the documented range.) ! 1859: ! 1860: ! 1861: DIVU: ! 1862: ! 1863: Overflow (always): 10 cycles. ! 1864: Worst case: 136 cycles. ! 1865: Best case: 76 cycles. ! 1866: ! 1867: ! 1868: DIVS: ! 1869: ! 1870: Absolute overflow: 16-18 cycles. ! 1871: Signed overflow is not detected prematurely. ! 1872: ! 1873: Worst case: 156 cycles. ! 1874: Best case without signed overflow: 122 cycles. ! 1875: Best case with signed overflow: 120 cycles ! 1876: ! 1877: ! 1878: */ ! 1879: ! 1880: ! 1881: // ! 1882: // DIVU ! 1883: // Unsigned division ! 1884: // ! 1885: ! 1886: STATIC_INLINE int getDivu68kCycles_2 (uae_u32 dividend, uae_u16 divisor) ! 1887: { ! 1888: int mcycles; ! 1889: uae_u32 hdivisor; ! 1890: int i; ! 1891: ! 1892: if (divisor == 0) ! 1893: return 0; ! 1894: ! 1895: // Overflow ! 1896: if ((dividend >> 16) >= divisor) ! 1897: return (mcycles = 5) * 2; ! 1898: ! 1899: mcycles = 38; ! 1900: hdivisor = divisor << 16; ! 1901: ! 1902: for (i = 0; i < 15; i++) { ! 1903: uae_u32 temp; ! 1904: temp = dividend; ! 1905: ! 1906: dividend <<= 1; ! 1907: ! 1908: // If carry from shift ! 1909: if ((uae_s32)temp < 0) ! 1910: dividend -= hdivisor; ! 1911: else { ! 1912: mcycles += 2; ! 1913: if (dividend >= hdivisor) { ! 1914: dividend -= hdivisor; ! 1915: mcycles--; ! 1916: } ! 1917: } ! 1918: } ! 1919: return mcycles * 2; ! 1920: } ! 1921: int getDivu68kCycles (uae_u32 dividend, uae_u16 divisor) ! 1922: { ! 1923: int v = getDivu68kCycles_2 (dividend, divisor) - 4; ! 1924: // write_log ("U%d ", v); ! 1925: return v; ! 1926: } ! 1927: ! 1928: // ! 1929: // DIVS ! 1930: // Signed division ! 1931: // ! 1932: ! 1933: STATIC_INLINE int getDivs68kCycles_2 (uae_s32 dividend, uae_s16 divisor) ! 1934: { ! 1935: int mcycles; ! 1936: uae_u32 aquot; ! 1937: int i; ! 1938: ! 1939: if (divisor == 0) ! 1940: return 0; ! 1941: ! 1942: mcycles = 6; ! 1943: ! 1944: if (dividend < 0) ! 1945: mcycles++; ! 1946: ! 1947: // Check for absolute overflow ! 1948: if (((uae_u32)abs (dividend) >> 16) >= (uae_u16)abs (divisor)) ! 1949: return (mcycles + 2) * 2; ! 1950: ! 1951: // Absolute quotient ! 1952: aquot = (uae_u32) abs (dividend) / (uae_u16)abs (divisor); ! 1953: ! 1954: mcycles += 55; ! 1955: ! 1956: if (divisor >= 0) { ! 1957: if (dividend >= 0) ! 1958: mcycles--; ! 1959: else ! 1960: mcycles++; ! 1961: } ! 1962: ! 1963: // Count 15 msbits in absolute of quotient ! 1964: ! 1965: for (i = 0; i < 15; i++) { ! 1966: if ((uae_s16)aquot >= 0) ! 1967: mcycles++; ! 1968: aquot <<= 1; ! 1969: } ! 1970: ! 1971: return mcycles * 2; ! 1972: } ! 1973: int getDivs68kCycles (uae_s32 dividend, uae_s16 divisor) ! 1974: { ! 1975: int v = getDivs68kCycles_2 (dividend, divisor) - 4; ! 1976: // write_log ("S%d ", v); ! 1977: return v; ! 1978: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.