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