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