|
|
1.1 ! root 1: /* ! 2: Hatari ! 3: ! 4: M68000 - CPU. This handles exception handling as well as a few OpCode's such as Line-F and Line-A. ! 5: We also have a function to save off the last 'x' instruction ran which is very handy for debugging ! 6: as we can see what code was run before a crash etc... ! 7: (Other CPU functions can be found in 'decode.asm/.inc') ! 8: */ ! 9: ! 10: #include "main.h" ! 11: #include "bios.h" ! 12: #include "cart.h" ! 13: #include "debug.h" ! 14: #include "decode.h" ! 15: #include "disass.h" ! 16: #include "fdc.h" ! 17: #include "gemdos.h" ! 18: #include "ikbd.h" ! 19: #include "int.h" ! 20: #include "m68000.h" ! 21: #include "memAlloc.h" ! 22: #include "memorySnapShot.h" ! 23: #include "mfp.h" ! 24: #include "misc.h" ! 25: #include "psg.h" ! 26: #include "screen.h" ! 27: #include "stMemory.h" ! 28: #include "tos.h" ! 29: #include "vdi.h" ! 30: #include "view.h" ! 31: #include "xbios.h" ! 32: ! 33: ! 34: /* Taken from Decode.asm - Thothy */ ! 35: /* These should be replaced with UAE's CPU core equivalents one day */ ! 36: unsigned short SR_Before; ! 37: unsigned long ExceptionVector; ! 38: short int PendingInterruptFlag; ! 39: void *PendingInterruptFunction; ! 40: short int PendingInterruptCount; ! 41: int SoundCycles; ! 42: BOOL bInSuperMode; ! 43: unsigned long EmuCCode; ! 44: unsigned long BusAddressLocation; ! 45: ! 46: ! 47: /* Use these if want to bring up any bus/address error, else uses 68000 vector handler */ ! 48: #ifndef FINAL_VERSION ! 49: // #define TRAP_BUSERROR_HISTORY // Output history on true Bus Error(bombs display) ! 50: // #define TRAP_ADDRESSERROR_HISTORY // Or Address Error ! 51: // #define TRAP_ILLEGALINSTRUCTIONERROR_HISTORY // Or Illegal Instruction ! 52: #endif ! 53: ! 54: BOOL bDoTraceException; /* Do TRACE? */ ! 55: ! 56: ! 57: //----------------------------------------------------------------------- ! 58: /* ! 59: Reset CPU 68000 variables ! 60: */ ! 61: void M68000_Reset(BOOL bCold) ! 62: { ! 63: int i; ! 64: ! 65: // Clear registers, set PC, SR and stack pointers ! 66: if (bCold) { ! 67: for(i=0; i<(16+1); i++) ! 68: Regs[i] = 0; ! 69: } ! 70: PC = TOSAddress; /* Start of TOS image, 0xfc0000 or 0xe00000 */ ! 71: SR = 0x2700; /* Starting status register */ ! 72: bDoTraceException = FALSE; /* No TRACE exceptions */ ! 73: bInSuperMode = TRUE; /* We begin in supervisor mode */ ! 74: Regs[REG_A7] = Regs[REG_A8] = 0x0000f000; /* Stack default */ ! 75: Reg_SuperSP = (unsigned long)&Regs[REG_A7]; /* So use this register as our stack */ ! 76: Reg_UserSP = (unsigned long)&Regs[REG_A8]; ! 77: PendingInterruptFlag = 0; // Clear pending flag ! 78: ! 79: // Read Supervisor Stack/PC for warm reset ! 80: if (!bCold) { ! 81: Regs[REG_A8] = STMemory_ReadLong(0x00000000); ! 82: PC = STMemory_ReadLong(0x00000004); ! 83: } ! 84: ! 85: // Hold display for extended VDI resolutions(under init our VDI) ! 86: bHoldScreenDisplay = TRUE; ! 87: } ! 88: ! 89: //----------------------------------------------------------------------- ! 90: /* ! 91: Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type) ! 92: */ ! 93: void M68000_MemorySnapShot_Capture(BOOL bSave) ! 94: { ! 95: // Save/Restore details ! 96: MemorySnapShot_Store(&bDoTraceException,sizeof(bDoTraceException)); ! 97: } ! 98: ! 99: //----------------------------------------------------------------------- ! 100: /* ! 101: Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type) ! 102: This is for 'decode.asm' variables - as cannot use 'decode.c' as will overwrite assembler .obj file! ! 103: */ ! 104: void M68000_Decode_MemorySnapShot_Capture(BOOL bSave) ! 105: { ! 106: int ID; ! 107: ! 108: // Save/Restore details ! 109: MemorySnapShot_Store(Regs,sizeof(Regs)); ! 110: MemorySnapShot_Store(&STRamEnd,sizeof(STRamEnd)); ! 111: MemorySnapShot_Store(&STRamEnd_BusErr,sizeof(STRamEnd_BusErr)); ! 112: MemorySnapShot_Store(&PendingInterruptCount,sizeof(PendingInterruptCount)); ! 113: MemorySnapShot_Store(&PendingInterruptFlag,sizeof(PendingInterruptFlag)); ! 114: if (bSave) { ! 115: // Convert function to ID ! 116: ID = Int_HandlerFunctionToID(PendingInterruptFunction); ! 117: MemorySnapShot_Store(&ID,sizeof(int)); ! 118: } ! 119: else { ! 120: // Convert ID to function ! 121: MemorySnapShot_Store(&ID,sizeof(int)); ! 122: PendingInterruptFunction = Int_IDToHandlerFunction(ID); ! 123: } ! 124: MemorySnapShot_Store(&PC,sizeof(PC)); ! 125: MemorySnapShot_Store(&SR,sizeof(SR)); ! 126: MemorySnapShot_Store(&SR_Before,sizeof(SR_Before)); ! 127: MemorySnapShot_Store(&bInSuperMode,sizeof(bInSuperMode)); ! 128: MemorySnapShot_Store(&Reg_SuperSP,sizeof(Reg_SuperSP)); ! 129: MemorySnapShot_Store(&Reg_UserSP,sizeof(Reg_UserSP)); ! 130: MemorySnapShot_Store(&EmuCCode,sizeof(EmuCCode)); ! 131: MemorySnapShot_Store(&ExceptionVector,sizeof(ExceptionVector)); ! 132: } ! 133: ! 134: //----------------------------------------------------------------------- ! 135: /* ! 136: ILLEGAL - Unknown 68000 OpCode ! 137: */ ! 138: void M68000_IllegalInstruction(void) ! 139: { ! 140: fprintf(stderr, "M68000_IllegalInstruction\n"); ! 141: ADD_CYCLES(34,4,3); ! 142: ExceptionVector = EXCEPTION_ILLEGALINS; /* Illegal vector */ ! 143: M68000_Exception(); /* Cause trap */ ! 144: // RET; ! 145: } ! 146: ! 147: //----------------------------------------------------------------------- ! 148: /* ! 149: BUSERROR - Access outside valid memory range ! 150: */ ! 151: void M68000_BusError(unsigned long addr) ! 152: { ! 153: /* Reset PC's stack to normal(as may have done many calls) so return to ! 154: correct level after exception. ! 155: Enter here with 'ebp' as address we tried to access */ ! 156: fprintf(stderr, "M68000_BusError at address $%lx\n", (long)addr); ! 157: BusAddressLocation=addr; /* Store for exception frame */ ! 158: ExceptionVector = EXCEPTION_BUSERROR; /* Handler */ ! 159: M68000_Exception(); /* Cause trap */ ! 160: /* ! 161: asm(" mov [BusAddressLocation],ebp\n" // Store for exception frame ! 162: " mov esp,[StackSave]\n" // Restore stack ! 163: " mov [ExceptionVector],EXCEPTION_BUSERROR\n"); // Handler ! 164: SAVE_ASSEM_REGS(); // Save assembly registers ! 165: asm(" call M68000_Exception\n"); // Cause trap ! 166: RESTORE_ASSEM_REGS(); // Restore assembly registers ! 167: RET; // Start decoding ! 168: */ ! 169: } ! 170: ! 171: //----------------------------------------------------------------------- ! 172: /* ! 173: ADDRESSERROR - Access incorrect memory boundary, eg byte offset for a word access ! 174: */ ! 175: void M68000_AddressError(unsigned long addr) ! 176: { ! 177: fprintf(stderr, "M68000_AddressError at address $%lx\n", (long)addr); ! 178: BusAddressLocation=addr; /* Store for exception frame */ ! 179: ExceptionVector=EXCEPTION_ADDRERROR; /* Handler */ ! 180: M68000_Exception(); /* Cause trap */ ! 181: /* ! 182: // Reset PC's stack to normal(as may have done many calls) so return to correct level after exception ! 183: __asm { ! 184: // Enter here with 'ebp' as address we tried to access ! 185: mov [BusAddressLocation],ebp // Store for exception frame ! 186: mov esp,[StackSave] // Restore stack ! 187: mov [ExceptionVector],EXCEPTION_ADDRERROR // Handler ! 188: SAVE_ASSEM_REGS // Save assembly registers ! 189: call M68000_Exception // Cause trap ! 190: RESTORE_ASSEM_REGS // Restore assembly registers ! 191: } ! 192: RET // Start decoding ! 193: */ ! 194: } ! 195: ! 196: //----------------------------------------------------------------------- ! 197: /* ! 198: See if in user/super mode and if need to swap SP ! 199: */ ! 200: void M68000_CheckUserSuperToggle(void) ! 201: { ! 202: unsigned long *TempReg; ! 203: unsigned long TempSP; ! 204: ! 205: // Have we swapped mode? ! 206: if ( (SR_Before&SR_SUPERMODE)!=(SR&SR_SUPERMODE) ) { ! 207: // Yes, swap to ST's REG_A8! ! 208: TempSP = Regs[REG_A7]; ! 209: Regs[REG_A7] = Regs[REG_A8]; ! 210: Regs[REG_A8] = TempSP; ! 211: ! 212: // And keep track of which of our registers is the supermode stack pointer ! 213: TempReg = (unsigned long *)Reg_SuperSP; ! 214: Reg_SuperSP = Reg_UserSP; ! 215: Reg_UserSP = (unsigned long)TempReg; ! 216: ! 217: // Swap super flag ! 218: bInSuperMode^=TRUE; ! 219: } ! 220: ! 221: // Set/Clear trace mode ! 222: if (SR&SR_TRACEMODE) { ! 223: // Have we set the TRACE bit for the FIRST time? Don't let exception occur until NEXT instruction ! 224: // NOTE Sometimes the TRACE bit can be set many times, so only skip exception on FIRST one ! 225: if ((PendingInterruptFlag&PENDING_INTERRUPT_FLAG_TRACE)==0) { ! 226: PendingInterruptFlag |= PENDING_INTERRUPT_FLAG_TRACE; ! 227: bDoTraceException = FALSE; ! 228: } ! 229: } ! 230: else ! 231: PendingInterruptFlag &= CLEAR_PENDING_INTERRUPT_FLAG_TRACE; ! 232: } ! 233: ! 234: //----------------------------------------------------------------------- ! 235: /* ! 236: Called when TRACE bit is set. This causes 'exception' after each instruction, BUT ! 237: it does not execute after the FIRST 'move SR,xxxx' to set the bit ! 238: */ ! 239: void M68000_TraceModeTriggered(void) ! 240: { ! 241: /* FIXME */ ! 242: /* ! 243: __asm { ! 244: cmp [bDoTraceException],FALSE // First time around? Skip exception ! 245: je dont_need_expection ! 246: ! 247: mov [ExceptionVector],EXCEPTION_TRACE // Handler ! 248: SAVE_ASSEM_REGS // Save assembly registers ! 249: call M68000_Exception // Cause trap ! 250: RESTORE_ASSEM_REGS // Restore assembly registers ! 251: ! 252: dont_need_expection:; ! 253: mov [bDoTraceException],TRUE // Do TRACE exception next time around ! 254: ret ! 255: } ! 256: */ ! 257: } ! 258: ! 259: //----------------------------------------------------------------------- ! 260: /* ! 261: Exception handler ! 262: */ ! 263: void M68000_Exception(void) ! 264: { ! 265: unsigned long Vector,MFPBaseVector; ! 266: BOOL bRet=FALSE; ! 267: ! 268: /* At the moment, this functions ist just a wrapper to Exception() of the UAE CPU - Thothy */ ! 269: Exception(ExceptionVector/4, m68k_getpc()); ! 270: return; ! 271: ! 272: #if 0 ! 273: // Was the CPU stopped, ie by a STOP instruction? ! 274: /* FIXME: */ ! 275: /* ! 276: if (CPUStopped) { ! 277: PC += 4; // Skip after the STOP instruction as CPU is now to resume! ! 278: CPUStopped = FALSE; // All is go,go,go! ! 279: } ! 280: */ ! 281: /* Find exception vector, keep 32-bit address as top byte is used by TOS */ ! 282: /* exception vectors as an ID! */ ! 283: Vector = STMemory_ReadLong(ExceptionVector); ! 284: ! 285: /* Check for intercept - The game 'Operation Wolf' re-directs traps, */ ! 286: /* so double check is a TOS trap and not software! (ie Vector is >0xE00000) */ ! 287: if ((Vector&0xffffff)>=0xE00000) { ! 288: if (ExceptionVector==EXCEPTION_TRAP13) ! 289: bRet = Bios(); ! 290: else if (ExceptionVector==EXCEPTION_TRAP14) ! 291: bRet = XBios(); ! 292: else if (ExceptionVector==EXCEPTION_TRAP1) ! 293: bRet = GemDOS(); ! 294: else if (ExceptionVector==EXCEPTION_TRAP2) { ! 295: bRet = VDI(); ! 296: if (!bRet) { ! 297: // Set 'PC' as address of 'VDI_OPCODE' illegal instruction ! 298: // This will call VDI_OpCode after completion of Trap call! ! 299: // Use to modify return structure from VDI ! 300: if (bUseVDIRes) { ! 301: VDI_OldPC = PC; ! 302: PC = CART_VDI_OPCODE_ADDR; ! 303: } ! 304: } ! 305: } ! 306: ! 307: // Do handly bit of debugging to trap bus/address errors, before goes to TOS handler ! 308: #ifdef TRAP_BUSERROR_HISTORY ! 309: if (ExceptionVector==EXCEPTION_BUSERROR) { ! 310: MessageBox(NULL,"TRAP BUS ERROR",PROG_NAME,MB_OK | MB_ICONSTOP); ! 311: Debug_File("TRAP BUS ERROR\n"); ! 312: M68000_OutputHistory(); ! 313: exit(0); ! 314: } ! 315: #endif ! 316: #ifdef TRAP_ADDRESSERROR_HISTORY ! 317: if (ExceptionVector==EXCEPTION_ADDRERROR) { ! 318: MessageBox(NULL,"TRAP ADDRESS ERROR",PROG_NAME,MB_OK | MB_ICONSTOP); ! 319: Debug_File("TRAP ADDRESS ERROR\n"); ! 320: M68000_OutputHistory(); ! 321: exit(0); ! 322: } ! 323: #endif ! 324: #ifdef TRAP_ILLEGALINSTRUCTIONERROR_HISTORY ! 325: if (ExceptionVector==EXCEPTION_ILLEGALINS) { ! 326: MessageBox(NULL,"TRAP ILLEGAL INSTRUCTION ERROR",PROG_NAME,MB_OK | MB_ICONSTOP); ! 327: Debug_File("TRAP ILLEGAL INSTRUCTION ERROR\n"); ! 328: M68000_OutputHistory(); ! 329: exit(0); ! 330: } ! 331: #endif ! 332: } ! 333: ! 334: // Did we re-direct call? No, so let's call it! ! 335: if (!bRet) { ! 336: // Save PC and SR to supervisor stack ! 337: /* FIXME */ ! 338: /* ! 339: __asm { ! 340: push ebp ! 341: ! 342: mov edx,[Reg_SuperSP] ! 343: ! 344: sub DWORD PTR [edx],SIZE_LONG ! 345: mov ebp,[edx] // Stack pointer ! 346: and ebp,0xffffff // as 24-bit address in PC memory(note _C) ! 347: mov ecx,[PC] // Save PC ! 348: SWAP_ENDIAN_LONG_ECX ! 349: mov DWORD PTR STRam[ebp],ecx ! 350: ! 351: sub DWORD PTR [edx],SIZE_WORD ! 352: mov ebp,[edx] // Stack pointer ! 353: and ebp,0xffffff // as 24-bit address in PC memory(note _C) ! 354: mov cx,WORD PTR [SR] ! 355: and ecx,SR_MASK // Remove condition codes ! 356: mov eax,[EmuCCode] ! 357: shr eax,4 // Emulation codes in correct bits ! 358: and eax,SR_CCODE_MASK ! 359: or eax,ecx // Or in current condition codes ! 360: SWAP_ENDIAN_WORD_AX ! 361: mov WORD PTR STRam[ebp],ax ! 362: ! 363: pop ebp ! 364: } ! 365: */ ! 366: // Exception frame, total 14 bytes (6 already put on stack, ie PC and SR) ! 367: // 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00 ! 368: // SSP->| |RW|IN|Func.cod| Higher ! 369: // address ! 370: // |High word access address | ! 371: // |Low word access address | ! 372: // |Instruction register | ! 373: // |Status register | ! 374: // |High word program counter | ! 375: // |Low word program counter | Lower address ! 376: // ! 377: // RW: Write=0, Read=1 ! 378: // IN: Instruction=0, Not=1 ! 379: if ( (ExceptionVector==EXCEPTION_BUSERROR) || (ExceptionVector==EXCEPTION_ADDRERROR) ) { ! 380: /* FIXME */ ! 381: /* ! 382: __asm { ! 383: push ebp ! 384: ! 385: mov ebp,[InsPC] // Get PC of instruction last ran ! 386: mov cx,WORD PTR [ebp] // 'Opcode' in 68000 endian ! 387: mov edx,[Reg_SuperSP] ! 388: sub DWORD PTR [edx],SIZE_WORD ! 389: mov ebp,[edx] // Stack pointer ! 390: and ebp,0xffffff // as 24-bit address in PC memory(note _C) ! 391: mov WORD PTR STRam[ebp],cx // Store 'Instruction Register' ! 392: ! 393: sub DWORD PTR [edx],SIZE_LONG ! 394: mov ebp,[edx] // Stack pointer ! 395: and ebp,0xffffff // as 24-bit address in PC memory(note _C) ! 396: mov ecx,[BusAddressLocation] // Address which caused fault ! 397: SWAP_ENDIAN_LONG_ECX ! 398: mov DWORD PTR STRam[ebp],ecx ! 399: ! 400: sub DWORD PTR [edx],SIZE_WORD ! 401: mov ebp,[edx] // Stack pointer ! 402: and ebp,0xffffff // as 24-bit address in PC memory(note _C) ! 403: xor ecx,ecx ! 404: mov WORD PTR STRam[ebp],cx // '0' for now ! 405: ! 406: pop ebp ! 407: } ! 408: */ ! 409: } ! 410: ! 411: SR_Before = SR; ! 412: SR &= SR_CLEAR_TRACEMODE; // Clear trace mode (bit 15) ! 413: SR |= SR_SUPERMODE; // Set super mode (bit 13) ! 414: M68000_CheckUserSuperToggle(); // Check if swapped mode ! 415: ! 416: // Do call to vector ! 417: // char szString[256]; ! 418: // sprintf(szString,"0x%X (0x%X)",Vector,ExceptionVector); ! 419: // debug << szString << endl; ! 420: PC = Vector; ! 421: // Set Status Register so interrupt can ONLY be stopped by another interrupt of higher priority! ! 422: if (ExceptionVector==EXCEPTION_VBLANK) ! 423: SR = (SR&SR_CLEAR_IPL)|0x0400; // VBL, level 4 ! 424: else if (ExceptionVector==EXCEPTION_HBLANK) ! 425: SR = (SR&SR_CLEAR_IPL)|0x0200; // HBL, level 2 ! 426: else { ! 427: MFPBaseVector = (unsigned int)(MFP_VR&0xf0)<<2; ! 428: if ( (ExceptionVector>=MFPBaseVector) && (ExceptionVector<=(MFPBaseVector+0x34)) ) ! 429: SR = (SR&SR_CLEAR_IPL)|0x0600; // MFP, level 6 ! 430: } ! 431: } ! 432: #endif ! 433: } ! 434: ! 435: //----------------------------------------------------------------------- ! 436: /* ! 437: Handle Line-A OpCode exception(Top 4-bit in opcode are 0xA) ! 438: */ ! 439: /* ! 440: void M68000_Line_A_OpCode_Execute(void) ! 441: { ! 442: PC -= SIZE_WORD; // PC needs to be at address of Line-A instruction ! 443: ExceptionVector = EXCEPTION_LINE_A; ! 444: M68000_Exception(); ! 445: } ! 446: ! 447: void M68000_Line_A_OpCode(void) ! 448: { ! 449: //FIXME SAVE_ASSEM_REGS(); // Save assembly registers ! 450: M68000_Line_A_OpCode_Execute(); ! 451: // RESTORE_ASSEM_REGS(); // Restore assembly registers ! 452: // RET; ! 453: } ! 454: */ ! 455: ! 456: //----------------------------------------------------------------------- ! 457: /* ! 458: During init do 0xA000, followed by 0xA0FF - we use this to get pointer to Line-A structure details(to fix for extended VDI res) ! 459: */ ! 460: void M68000_Line_A_Trap(void) ! 461: { ! 462: /* FIXME */ ! 463: /* ! 464: ! 465: PUSH_ALL ! 466: __asm { ! 467: mov edx,DWORD PTR Regs[REG_D0*4] ! 468: mov [LineABase],edx ! 469: mov edx,DWORD PTR Regs[REG_A1*4] ! 470: mov [FontBase],edx ! 471: call VDI_LineA // Modify Line-A structure ! 472: } ! 473: POP_ALL ! 474: RET ! 475: */ ! 476: } ! 477: ! 478: //----------------------------------------------------------------------- ! 479: /* ! 480: Handle Line-F OpCode exception(Top 4-bit in opcode are 0xF) ! 481: */ ! 482: /* ! 483: void M68000_Line_F_OpCode_Execute(void) ! 484: { ! 485: PC -= SIZE_WORD; // PC needs to be at address of Line-F instruction ! 486: ExceptionVector = EXCEPTION_LINE_F; ! 487: M68000_Exception(); ! 488: } ! 489: ! 490: void M68000_Line_F_OpCode(void) ! 491: { ! 492: //FIXME SAVE_ASSEM_REGS(); // Save assembly registers ! 493: M68000_Line_F_OpCode_Execute(); ! 494: // RESTORE_ASSEM_REGS(); // Restore assembly registers ! 495: // RET; ! 496: } ! 497: */ ! 498: ! 499: //----------------------------------------------------------------------- ! 500: /* ! 501: Use 'InsPC' to find how many cycles last instruction took to execute ! 502: */ ! 503: int M68000_FindLastInstructionCycles(void) ! 504: { ! 505: unsigned short int OpCode; ! 506: ! 507: //FIXME OpCode = *(unsigned short int *)InsPC; // Read 'opcode' ! 508: //FIXME return( DecodeTable[(OpCode*SIZEOF_DECODE)+(DECODE_CYCLES/sizeof(long))] ); ! 509: return 4; /* Ouargs ... this is an uggly hack */ ! 510: } ! 511: ! 512: //----------------------------------------------------------------------- ! 513: /* ! 514: Output CPU instruction history(last 'x' instructions) for debugging ! 515: */ ! 516: void M68000_OutputHistory(void) ! 517: { ! 518: #ifndef FINAL_VERSION ! 519: unsigned long StartPC; ! 520: int i; ! 521: ! 522: /* First, Return back into a Window */ ! 523: Screen_ReturnFromFullScreen(); ! 524: View_ToggleWindowsMouse(MOUSE_WINDOWS); ! 525: ! 526: Debug_File("HISTORY\n"); ! 527: ! 528: for(i=0; i<(INSTRUCTION_HISTORY_SIZE-1); i++) { ! 529: StartPC = DisPC = InstructionHistory[(InstructionHistoryIndex+i+1)&INSTRUCTION_HISTORY_MASK]; ! 530: Disass_DiassembleLine(); // Disassemble instruction ! 531: ! 532: Debug_File("%8.8X\t%s\n",StartPC,szOpString); ! 533: } ! 534: #endif ! 535: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.