|
|
1.1 root 1: /*
1.1.1.6 root 2: Hatari - m68000.c
1.1 root 3:
1.1.1.6 root 4: This file is distributed under the GNU Public License, version 2 or at
5: your option any later version. Read the file gpl.txt for details.
6:
7: These routines originally (in WinSTon) handled exceptions as well as some
1.1.1.5 root 8: few OpCode's such as Line-F and Line-A. In Hatari it has mainly become a
9: wrapper between the WinSTon sources and the UAE CPU code.
1.1 root 10: */
1.1.1.12 root 11:
12: /* 2007/03/xx [NP] Possibility to add several wait states for the same instruction in */
13: /* M68000_WaitState (e.g. clr.b $fa1b.w in Decade Demo Menu). */
14: /* 2007/04/14 [NP] Add support for instruction pairing in M68000_AddCycles, using OpcodeFamily and */
15: /* LastOpcodeFamily (No Cooper Loader, Oh Crickey ... Hidden Screen). */
16: /* 2007/04/24 [NP] Add pairing for BCLR/Bcc. */
17: /* 2007/09/29 [NP] Use the new int.c and INT_CONVERT_TO_INTERNAL. */
18: /* 2007/11/26 [NP] We set BusErrorPC in m68k_run_1 instead of M68000_BusError, else the BusErrorPC */
19: /* will not point to the opcode that generated the bus error. */
20: /* In M68000_BusError, if we have 'move.l $0,$24', we need to generate a bus error */
21: /* for the read, not for the write that should occur after (TransBeauce 2 Demo). */
22: /* 2008/01/07 [NP] Function 'M68000_InitPairing' and 'PairingArray' as a lookup table for fast */
23: /* determination of valid pairing combinations (replace lots of 'if' tests in */
24: /* m68000.h). */
25: /* 2008/01/25 [NP] Add pairing for LSR/MOVE (and all other bit shifting instr) (Anomaly Demo Intro)*/
26: /* 2008/02/02 [NP] Add pairing for CMP/Bcc (Level 16 Fullscreen (1988)). */
27: /* 2008/02/08 [NP] Add pairing for LSL/LEA (and all other bit shifting instr) (TVI 2 - The Year */
28: /* After Demo). */
29: /* 2008/02/11 [NP] Add pairing for MULS/MOVEA (Delirious Demo IV Loader). */
30: /* 2008/01/25 [NP] Add pairing for LSR/MOVEA (and all other bit shifting instr) (Decade Demo Reset)*/
1.1.1.13! root 31: /* 2008/02/16 [NP] Add pairing for MULS/DIVS (fixes e605 demo part 3). */
1.1.1.12 root 32: /* 2008/03/08 [NP] In M68000_Exception, we need to know if the exception was triggered by an MFP */
33: /* interrupt or by a video interrupt. In the case MFP vector base was changed in */
34: /* fffa17 to an other value than the default $40, testing exceptionNr is not enough*/
35: /* to correctly process the exception. For example, if vector base is set to $10 */
36: /* then MFP Timer A will call vector stored at address $74, which would be wrongly */
37: /* interpreted as a level 5 int (which doesn't exist on Atari and will cause an */
1.1.1.13! root 38: /* assert to fail in intlevel()). We use InterruptSource to correctly recognize the*/
1.1.1.12 root 39: /* MFP interrupts (fix 'Toki' end part fullscreen which sets vector base to $10). */
1.1.1.13! root 40: /* 2008/04/14 [NP] Add pairing for BTST/Bcc (eg btst #7,d0 + bne.s label (with branch taken)). */
! 41: /* 2008/04/15 [NP] As tested on a real STF : */
! 42: /* - MUL/DIV can pair (but DIV/MUL can't) */
! 43: /* (eg mulu d0,d0 + divs d1,d1 with d0=0 and d1=1) */
! 44: /* - MUL/MOVE can pair, but not DIV/MOVE */
! 45: /* - EXG/MOVE can pair (eg exg d3,d4 + move.l 0(a3,d1.w),a4) */
! 46: /* - MOVE/DBcc can't pair */
! 47: /* 2008/04/16 [NP] Functions 'M68000_InitPairing_BitShift' to ease code maintenance. */
! 48: /* Tested on STF : add pairing between bit shift instr and ADD/SUB/OR/AND/EOR/NOT */
! 49: /* CLR/NEG (certainly some more possible, haven't tested everything) */
! 50: /* (fixes lsr.w #4,d4 + add.b $f0(a4,d4),d7 used in Zoolook part of ULM New Year). */
! 51: /* 2008/07/08 [NP] Add pairing between bit shift instr and ADDX/SUBX/ABCD/SBCD (fixes lsl.l #1,d0 */
! 52: /* + abcd d1,d1 used in Dragonnels - Rainbow Wall). */
! 53: /* 2008/10/05 [NP] Pass the 'ExceptionSource' parameter to Exception() in uae-cpu/newcpu.c */
1.1.1.12 root 54:
55:
56:
1.1.1.13! root 57: const char M68000_rcsid[] = "Hatari $Id: m68000.c,v 1.61 2008/10/05 17:55:31 npomarede Exp $";
1.1 root 58:
59: #include "main.h"
1.1.1.12 root 60: #include "configuration.h"
1.1 root 61: #include "gemdos.h"
1.1.1.6 root 62: #include "hatari-glue.h"
1.1 root 63: #include "int.h"
64: #include "m68000.h"
65: #include "memorySnapShot.h"
66: #include "mfp.h"
1.1.1.12 root 67: #include "options.h"
68: #include "savestate.h"
1.1 root 69: #include "stMemory.h"
70: #include "tos.h"
71:
72:
1.1.1.12 root 73: Uint32 BusErrorAddress; /* Stores the offending address for bus-/address errors */
74: Uint32 BusErrorPC; /* Value of the PC when bus error occurs */
1.1.1.13! root 75: bool bBusErrorReadWrite; /* 0 for write error, 1 for read error */
1.1.1.12 root 76: int nCpuFreqShift; /* Used to emulate higher CPU frequencies: 0=8MHz, 1=16MHz, 2=32Mhz */
77: int nWaitStateCycles; /* Used to emulate the wait state cycles of certain IO registers */
78:
79: int LastOpcodeFamily = -1; /* see the enum in readcpu.h i_XXX */
80: int LastInstrCycles = -1; /* number of cycles for previous instr. (not rounded to 4) */
81: int Pairing = 0; /* set to 1 if the latest 2 intr paired */
82: char PairingArray[ MAX_OPCODE_FAMILY ][ MAX_OPCODE_FAMILY ];
83:
84:
85: /* to convert the enum from OpcodeFamily to a readable value for pairing's debug */
86: const char *OpcodeName[] = { "ILLG",
87: "OR","AND","EOR","ORSR","ANDSR","EORSR",
88: "SUB","SUBA","SUBX","SBCD",
89: "ADD","ADDA","ADDX","ABCD",
90: "NEG","NEGX","NBCD","CLR","NOT","TST",
91: "BTST","BCHG","BCLR","BSET",
92: "CMP","CMPM","CMPA",
93: "MVPRM","MVPMR","MOVE","MOVEA","MVSR2","MV2SR",
94: "SWAP","EXG","EXT","MVMEL","MVMLE",
95: "TRAP","MVR2USP","MVUSP2R","RESET","NOP","STOP","RTE","RTD",
96: "LINK","UNLK",
97: "RTS","TRAPV","RTR",
98: "JSR","JMP","BSR","Bcc",
99: "LEA","PEA","DBcc","Scc",
100: "DIVU","DIVS","MULU","MULS",
101: "ASR","ASL","LSR","LSL","ROL","ROR","ROXL","ROXR",
102: "ASRW","ASLW","LSRW","LSLW","ROLW","RORW","ROXLW","ROXRW",
103: "CHK","CHK2",
104: "MOVEC2","MOVE2C","CAS","CAS2","DIVL","MULL",
105: "BFTST","BFEXTU","BFCHG","BFEXTS","BFCLR","BFFFO","BFSET","BFINS",
106: "PACK","UNPK","TAS","BKPT","CALLM","RTM","TRAPcc","MOVES",
107: "FPP","FDBcc","FScc","FTRAPcc","FBcc","FSAVE","FRESTORE",
108: "CINVL","CINVP","CINVA","CPUSHL","CPUSHP","CPUSHA","MOVE16",
109: "MMUOP"
110: };
1.1.1.8 root 111:
1.1.1.12 root 112:
113: /*-----------------------------------------------------------------------*/
114: /**
1.1.1.13! root 115: * Add pairing between all the bit shifting instructions and a given Opcode
! 116: */
! 117:
! 118: static void M68000_InitPairing_BitShift ( int OpCode )
! 119: {
! 120: PairingArray[ i_ASR ][ OpCode ] = 1;
! 121: PairingArray[ i_ASL ][ OpCode ] = 1;
! 122: PairingArray[ i_LSR ][ OpCode ] = 1;
! 123: PairingArray[ i_LSL ][ OpCode ] = 1;
! 124: PairingArray[ i_ROL ][ OpCode ] = 1;
! 125: PairingArray[ i_ROR ][ OpCode ] = 1;
! 126: PairingArray[ i_ROXR ][ OpCode ] = 1;
! 127: PairingArray[ i_ROXL ][ OpCode ] = 1;
! 128: }
! 129:
! 130:
! 131: /*-----------------------------------------------------------------------*/
! 132: /**
1.1.1.12 root 133: * Init the pairing matrix
134: * Two instructions can pair if PairingArray[ LastOpcodeFamily ][ OpcodeFamily ] == 1
135: */
136: void M68000_InitPairing(void)
137: {
138: /* First, clear the matrix (pairing is false) */
139: memset(PairingArray , 0 , MAX_OPCODE_FAMILY * MAX_OPCODE_FAMILY);
140:
141: /* Set all valid pairing combinations to 1 */
142: PairingArray[ i_EXG ][ i_DBcc ] = 1;
1.1.1.13! root 143: PairingArray[ i_EXG ][ i_MOVE ] = 1;
! 144: PairingArray[ i_EXG ][ i_MOVEA] = 1;
! 145:
1.1.1.12 root 146: PairingArray[ i_CMPA ][ i_Bcc ] = 1;
147: PairingArray[ i_CMP ][ i_Bcc ] = 1;
1.1.1.13! root 148:
! 149: M68000_InitPairing_BitShift ( i_DBcc );
! 150: M68000_InitPairing_BitShift ( i_MOVE );
! 151: M68000_InitPairing_BitShift ( i_MOVEA );
! 152: M68000_InitPairing_BitShift ( i_LEA );
! 153:
1.1.1.12 root 154: PairingArray[ i_MULU ][ i_MOVEA] = 1;
155: PairingArray[ i_MULS ][ i_MOVEA] = 1;
156: PairingArray[ i_MULU ][ i_MOVE ] = 1;
157: PairingArray[ i_MULS ][ i_MOVE ] = 1;
1.1.1.13! root 158:
! 159: PairingArray[ i_MULU ][ i_DIVU ] = 1;
! 160: PairingArray[ i_MULU ][ i_DIVS ] = 1;
! 161: PairingArray[ i_MULS ][ i_DIVU ] = 1;
! 162: PairingArray[ i_MULS ][ i_DIVS ] = 1;
! 163:
! 164: PairingArray[ i_BTST ][ i_Bcc ] = 1;
! 165:
! 166: M68000_InitPairing_BitShift ( i_ADD );
! 167: M68000_InitPairing_BitShift ( i_SUB );
! 168: M68000_InitPairing_BitShift ( i_OR );
! 169: M68000_InitPairing_BitShift ( i_AND );
! 170: M68000_InitPairing_BitShift ( i_EOR );
! 171: M68000_InitPairing_BitShift ( i_NOT );
! 172: M68000_InitPairing_BitShift ( i_CLR );
! 173: M68000_InitPairing_BitShift ( i_NEG );
! 174: M68000_InitPairing_BitShift ( i_ADDX );
! 175: M68000_InitPairing_BitShift ( i_SUBX );
! 176: M68000_InitPairing_BitShift ( i_ABCD );
! 177: M68000_InitPairing_BitShift ( i_SBCD );
1.1.1.12 root 178: }
1.1 root 179:
180:
1.1.1.3 root 181: /*-----------------------------------------------------------------------*/
1.1.1.12 root 182: /**
183: * Reset CPU 68000 variables
184: */
1.1.1.13! root 185: void M68000_Reset(bool bCold)
1.1 root 186: {
1.1.1.12 root 187: int i;
188:
189: /* Clear registers */
190: if (bCold)
191: {
192: for (i=0; i<(16+1); i++)
193: Regs[i] = 0;
194: }
195:
196: /* Now directly reset the UAE CPU core: */
197: m68k_reset();
198:
199: /* Init the pairing matrix */
200: M68000_InitPairing();
201: }
202:
203:
204: /*-----------------------------------------------------------------------*/
205: /**
206: * Reset and start 680x0 emulation
207: */
208: void M68000_Start(void)
209: {
210: m68k_reset();
1.1 root 211:
1.1.1.12 root 212: /* Load initial memory snapshot */
213: if (bLoadMemorySave)
214: {
215: MemorySnapShot_Restore(ConfigureParams.Memory.szMemoryCaptureFileName, FALSE);
216: }
217: else if (bLoadAutoSave)
218: {
219: MemorySnapShot_Restore(ConfigureParams.Memory.szAutoSaveFileName, FALSE);
220: }
1.1.1.7 root 221:
1.1.1.12 root 222: m68k_go(TRUE);
1.1 root 223: }
224:
1.1.1.3 root 225:
226: /*-----------------------------------------------------------------------*/
1.1.1.12 root 227: /**
228: * Check wether the CPU mode has been changed.
229: */
230: void M68000_CheckCpuLevel(void)
231: {
232: changed_prefs.cpu_level = ConfigureParams.System.nCpuLevel;
233: changed_prefs.cpu_compatible = ConfigureParams.System.bCompatibleCpu;
234: #ifndef UAE_NEWCPU_H
235: changed_prefs.cpu_cycle_exact = 0; // TODO
236: #endif
237: if (table68k)
238: check_prefs_changed_cpu();
239: }
240:
241:
242: /*-----------------------------------------------------------------------*/
243: /**
244: * Save/Restore snapshot of CPU variables ('MemorySnapShot_Store' handles type)
245: */
1.1.1.13! root 246: void M68000_MemorySnapShot_Capture(bool bSave)
1.1 root 247: {
1.1.1.12 root 248: Uint32 savepc;
1.1 root 249:
1.1.1.12 root 250: /* Save/Restore details */
251: MemorySnapShot_Store(Regs,sizeof(Regs));
252: MemorySnapShot_Store(&STRamEnd,sizeof(STRamEnd));
253:
254: /* For the UAE CPU core: */
255: MemorySnapShot_Store(&currprefs.address_space_24,
256: sizeof(currprefs.address_space_24));
257: MemorySnapShot_Store(®s.regs[0], sizeof(regs.regs)); /* D0-D7 A0-A6 */
258:
259: if (bSave)
260: {
261: savepc = M68000_GetPC();
262: MemorySnapShot_Store(&savepc, sizeof(savepc)); /* PC */
263: }
264: else
265: {
266: MemorySnapShot_Store(&savepc, sizeof(savepc)); /* PC */
267: regs.pc = savepc;
268: #ifdef UAE_NEWCPU_H
269: regs.prefetch_pc = regs.pc + 128;
270: #endif
271: }
1.1.1.8 root 272:
1.1.1.12 root 273: #ifdef UAE_NEWCPU_H
274: MemorySnapShot_Store(®s.prefetch, sizeof(regs.prefetch)); /* prefetch */
275: #else
276: uae_u32 prefetch_dummy;
277: MemorySnapShot_Store(&prefetch_dummy, sizeof(prefetch_dummy));
278: #endif
279:
280: if (bSave)
281: {
282: #ifdef UAE_NEWCPU_H
283: MakeSR();
284: #else
285: MakeSR(®s);
286: #endif
287: if (regs.s)
288: {
289: MemorySnapShot_Store(®s.usp, sizeof(regs.usp)); /* USP */
290: MemorySnapShot_Store(®s.regs[15], sizeof(regs.regs[15])); /* ISP */
291: }
292: else
293: {
294: MemorySnapShot_Store(®s.regs[15], sizeof(regs.regs[15])); /* USP */
295: MemorySnapShot_Store(®s.isp, sizeof(regs.isp)); /* ISP */
296: }
297: MemorySnapShot_Store(®s.sr, sizeof(regs.sr)); /* SR/CCR */
298: }
299: else
300: {
301: MemorySnapShot_Store(®s.usp, sizeof(regs.usp));
302: MemorySnapShot_Store(®s.isp, sizeof(regs.isp));
303: MemorySnapShot_Store(®s.sr, sizeof(regs.sr));
304: }
305: MemorySnapShot_Store(®s.stopped, sizeof(regs.stopped));
306: MemorySnapShot_Store(®s.dfc, sizeof(regs.dfc)); /* DFC */
307: MemorySnapShot_Store(®s.sfc, sizeof(regs.sfc)); /* SFC */
308: MemorySnapShot_Store(®s.vbr, sizeof(regs.vbr)); /* VBR */
309: MemorySnapShot_Store(&caar, sizeof(caar)); /* CAAR */
310: MemorySnapShot_Store(&cacr, sizeof(cacr)); /* CACR */
311: MemorySnapShot_Store(®s.msp, sizeof(regs.msp)); /* MSP */
312:
313: if (!bSave)
314: {
315: M68000_SetPC(regs.pc);
316: /* MakeFromSR() must not swap stack pointer */
317: regs.s = (regs.sr >> 13) & 1;
318: #ifdef UAE_NEWCPU_H
319: MakeFromSR();
320: /* set stack pointer */
321: if (regs.s)
322: m68k_areg(regs, 7) = regs.isp;
323: else
324: m68k_areg(regs, 7) = regs.usp;
325: #else
326: MakeFromSR(®s);
327: /* set stack pointer */
328: if (regs.s)
329: m68k_areg(®s, 7) = regs.isp;
330: else
331: m68k_areg(®s, 7) = regs.usp;
332: #endif
333: }
334:
335: if (bSave)
336: save_fpu();
337: else
338: restore_fpu();
1.1 root 339: }
340:
341:
1.1.1.3 root 342: /*-----------------------------------------------------------------------*/
1.1.1.12 root 343: /**
344: * BUSERROR - Access outside valid memory range.
345: * Use bReadWrite = 0 for write errors and bReadWrite = 1 for read errors!
346: */
1.1.1.13! root 347: void M68000_BusError(Uint32 addr, bool bReadWrite)
1.1 root 348: {
1.1.1.12 root 349: /* FIXME: In prefetch mode, m68k_getpc() seems already to point to the next instruction */
350: // BusErrorPC = M68000_GetPC(); /* [NP] We set BusErrorPC in m68k_run_1 */
1.1.1.7 root 351:
1.1.1.12 root 352: if (BusErrorPC < TosAddress || BusErrorPC > TosAddress + TosSize)
353: {
354: /* Print bus errors (except for TOS' hardware tests) */
355: fprintf(stderr, "M68000_BusError at address $%lx\n", (long)addr);
356: }
357:
358: if ((regs.spcflags & SPCFLAG_BUSERROR) == 0) /* [NP] Check that the opcode has not already generated a read bus error */
359: {
360: BusErrorAddress = addr; /* Store for exception frame */
361: bBusErrorReadWrite = bReadWrite;
362: M68000_SetSpecial(SPCFLAG_BUSERROR); /* The exception will be done in newcpu.c */
363: }
1.1 root 364: }
365:
1.1.1.3 root 366:
367: /*-----------------------------------------------------------------------*/
1.1.1.12 root 368: /**
369: * Exception handler
370: */
1.1.1.13! root 371: void M68000_Exception(Uint32 ExceptionVector , int ExceptionSource)
1.1.1.12 root 372: {
373: int exceptionNr = ExceptionVector/4;
374:
1.1.1.13! root 375: if ( ( ExceptionSource == M68000_EXCEPTION_SRC_INT_VIDEO )
1.1.1.12 root 376: && (exceptionNr>24 && exceptionNr<32) ) /* 68k autovector interrupt? */
377: {
378: /* Handle autovector interrupts the UAE's way
379: * (see intlev() and do_specialties() in UAE CPU core) */
380: /* In our case, this part is only called for HBL and VBL interrupts */
381: int intnr = exceptionNr - 24;
382: pendingInterrupts |= (1 << intnr);
383: M68000_SetSpecial(SPCFLAG_INT);
384: }
1.1.1.13! root 385:
! 386: else /* MFP or direct CPU exceptions */
1.1.1.12 root 387: {
388: Uint16 SR;
389:
390: /* Was the CPU stopped, i.e. by a STOP instruction? */
391: if (regs.spcflags & SPCFLAG_STOP)
392: {
393: regs.stopped = 0;
394: M68000_UnsetSpecial(SPCFLAG_STOP); /* All is go,go,go! */
395: }
396:
397: /* 68k exceptions are handled by Exception() of the UAE CPU core */
398: #ifdef UAE_NEWCPU_H
1.1.1.13! root 399: Exception(exceptionNr, m68k_getpc(), ExceptionSource);
1.1.1.12 root 400: #else
401: Exception(exceptionNr, ®s, m68k_getpc(®s));
402: #endif
403:
404: SR = M68000_GetSR();
405:
406: /* Set Status Register so interrupt can ONLY be stopped by another interrupt
407: * of higher priority! */
1.1.1.6 root 408: #if 0 /* VBL and HBL are handled in the UAE CPU core (see above). */
1.1.1.12 root 409: if (ExceptionVector == EXCEPTION_VBLANK)
410: SR = (SR&SR_CLEAR_IPL)|0x0400; /* VBL, level 4 */
411: else if (ExceptionVector == EXCEPTION_HBLANK)
412: SR = (SR&SR_CLEAR_IPL)|0x0200; /* HBL, level 2 */
413: else
414: #endif
415: {
416: Uint32 MFPBaseVector = (unsigned int)(MFP_VR&0xf0)<<2;
417: if ( (ExceptionVector>=MFPBaseVector) && (ExceptionVector<=(MFPBaseVector+0x3c)) )
418: SR = (SR&SR_CLEAR_IPL)|0x0600; /* MFP, level 6 */
419: }
420:
421: M68000_SetSR(SR);
422: }
1.1 root 423: }
424:
1.1.1.8 root 425:
426: /*-----------------------------------------------------------------------*/
1.1.1.12 root 427: /**
428: * There seem to be wait states when a program accesses certain hardware
429: * registers on the ST. Use this function to simulate these wait states.
430: * [NP] with some instructions like CLR, we have a read then a write at the
431: * same location, so we may have 2 wait states (read and write) to add
432: * (nWaitStateCycles should be reset to 0 after the cycles were added).
433: */
1.1.1.11 root 434: void M68000_WaitState(int nCycles)
1.1.1.8 root 435: {
1.1.1.12 root 436: M68000_SetSpecial(SPCFLAG_EXTRA_CYCLES);
1.1.1.11 root 437:
1.1.1.12 root 438: nWaitStateCycles += nCycles; /* add all the wait states for this instruction */
1.1.1.8 root 439: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.