|
|
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.