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