|
|
1.1 root 1: /*
1.1.1.6 root 2: Hatari - m68000.c
1.1 root 3:
1.1.1.20 root 4: This file is distributed under the GNU General Public License, version 2
5: or at your option any later version. Read the file gpl.txt for details.
1.1.1.6 root 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.16 root 54: /* 2010/05/07 [NP] Add pairing for ADD/MOVE ; such pairing should only be possible when combined */
55: /* with d8(an,ix) address mode (eg: add.l (a5,d1.w),d0 + move.b 7(a5,d1.w),d5) */
56: /* (fixes Sommarhack 2010 Invitation by DHS). */
1.1.1.17 root 57: /* 2010/11/07 [NP] Add pairing between bit shift instr and JMP (fixes lsl.w #2,d0 + jmp 2(pc,d0) */
58: /* used in Fullparts by Hemoroids). */
1.1.1.18 root 59: /* 2011/12/11 [NP] Add pairing between MUL and JSR (fixes muls #52,d2 + jsr 0(a1,d2.w) used in */
1.1.1.21 root 60: /* Lemmings Compilation 40's Intro). */
61: /* 2014/05/07 [NP] In M68000_WaitEClock, use CyclesGlobalClockCounter instead of the VBL video */
62: /* counter (else for a given position in a VBL we would always get the same value */
63: /* for the E clock). */
1.1.1.22! root 64: /* 2015/02/01 [NP] When using the new WinUAE's cpu, don't handle MFP/DSP interrupts by calling */
! 65: /* directly Exception(), we must set bit 6 in pendingInterrupts and use the IACK */
! 66: /* sequence to get the exception's vector number. */
! 67: /* 2015/02/05 [NP] For the new WinUAE's cpu, don't use ExceptionSource anymore when calling */
! 68: /* Exception(). */
! 69: /* 2015/02/11 [NP] Replace BusErrorPC by regs.instruction_pc, to get similar code to WinUAE's cpu */
! 70:
1.1.1.12 root 71:
1.1.1.14 root 72: const char M68000_fileid[] = "Hatari m68000.c : " __DATE__ " " __TIME__;
1.1 root 73:
74: #include "main.h"
1.1.1.12 root 75: #include "configuration.h"
1.1 root 76: #include "gemdos.h"
1.1.1.6 root 77: #include "hatari-glue.h"
1.1.1.16 root 78: #include "cycInt.h"
1.1 root 79: #include "m68000.h"
80: #include "memorySnapShot.h"
81: #include "mfp.h"
1.1.1.12 root 82: #include "options.h"
83: #include "savestate.h"
1.1 root 84: #include "stMemory.h"
85: #include "tos.h"
86:
1.1.1.22! root 87: #if ENABLE_DSP_EMU
! 88: #include "dsp.h"
! 89: #endif
! 90:
1.1.1.20 root 91: #if ENABLE_WINUAE_CPU
92: #include "mmu_common.h"
93: #endif
94:
95: /* information about current CPU instruction */
96: cpu_instruction_t CpuInstruction;
1.1 root 97:
1.1.1.12 root 98: Uint32 BusErrorAddress; /* Stores the offending address for bus-/address errors */
1.1.1.13 root 99: bool bBusErrorReadWrite; /* 0 for write error, 1 for read error */
1.1.1.12 root 100: int nCpuFreqShift; /* Used to emulate higher CPU frequencies: 0=8MHz, 1=16MHz, 2=32Mhz */
101: int nWaitStateCycles; /* Used to emulate the wait state cycles of certain IO registers */
1.1.1.14 root 102: int BusMode = BUS_MODE_CPU; /* Used to tell which part is owning the bus (cpu, blitter, ...) */
1.1.1.20 root 103: bool CPU_IACK = false; /* Set to true during an exception when getting the interrupt's vector number */
1.1.1.12 root 104:
1.1.1.16 root 105: int LastOpcodeFamily = i_NOP; /* see the enum in readcpu.h i_XXX */
106: int LastInstrCycles = 0; /* number of cycles for previous instr. (not rounded to 4) */
107: int Pairing = 0; /* set to 1 if the latest 2 intr paired */
1.1.1.12 root 108: char PairingArray[ MAX_OPCODE_FAMILY ][ MAX_OPCODE_FAMILY ];
109:
110:
111: /* to convert the enum from OpcodeFamily to a readable value for pairing's debug */
112: const char *OpcodeName[] = { "ILLG",
113: "OR","AND","EOR","ORSR","ANDSR","EORSR",
114: "SUB","SUBA","SUBX","SBCD",
115: "ADD","ADDA","ADDX","ABCD",
116: "NEG","NEGX","NBCD","CLR","NOT","TST",
117: "BTST","BCHG","BCLR","BSET",
118: "CMP","CMPM","CMPA",
119: "MVPRM","MVPMR","MOVE","MOVEA","MVSR2","MV2SR",
120: "SWAP","EXG","EXT","MVMEL","MVMLE",
121: "TRAP","MVR2USP","MVUSP2R","RESET","NOP","STOP","RTE","RTD",
122: "LINK","UNLK",
123: "RTS","TRAPV","RTR",
124: "JSR","JMP","BSR","Bcc",
125: "LEA","PEA","DBcc","Scc",
126: "DIVU","DIVS","MULU","MULS",
127: "ASR","ASL","LSR","LSL","ROL","ROR","ROXL","ROXR",
128: "ASRW","ASLW","LSRW","LSLW","ROLW","RORW","ROXLW","ROXRW",
129: "CHK","CHK2",
130: "MOVEC2","MOVE2C","CAS","CAS2","DIVL","MULL",
131: "BFTST","BFEXTU","BFCHG","BFEXTS","BFCLR","BFFFO","BFSET","BFINS",
132: "PACK","UNPK","TAS","BKPT","CALLM","RTM","TRAPcc","MOVES",
133: "FPP","FDBcc","FScc","FTRAPcc","FBcc","FSAVE","FRESTORE",
134: "CINVL","CINVP","CINVA","CPUSHL","CPUSHP","CPUSHA","MOVE16",
135: "MMUOP"
136: };
1.1.1.8 root 137:
1.1.1.12 root 138:
139: /*-----------------------------------------------------------------------*/
140: /**
1.1.1.13 root 141: * Add pairing between all the bit shifting instructions and a given Opcode
142: */
143:
144: static void M68000_InitPairing_BitShift ( int OpCode )
145: {
146: PairingArray[ i_ASR ][ OpCode ] = 1;
147: PairingArray[ i_ASL ][ OpCode ] = 1;
148: PairingArray[ i_LSR ][ OpCode ] = 1;
149: PairingArray[ i_LSL ][ OpCode ] = 1;
150: PairingArray[ i_ROL ][ OpCode ] = 1;
151: PairingArray[ i_ROR ][ OpCode ] = 1;
152: PairingArray[ i_ROXR ][ OpCode ] = 1;
153: PairingArray[ i_ROXL ][ OpCode ] = 1;
154: }
155:
156:
157: /**
1.1.1.12 root 158: * Init the pairing matrix
159: * Two instructions can pair if PairingArray[ LastOpcodeFamily ][ OpcodeFamily ] == 1
160: */
1.1.1.16 root 161: static void M68000_InitPairing(void)
1.1.1.12 root 162: {
163: /* First, clear the matrix (pairing is false) */
164: memset(PairingArray , 0 , MAX_OPCODE_FAMILY * MAX_OPCODE_FAMILY);
165:
166: /* Set all valid pairing combinations to 1 */
167: PairingArray[ i_EXG ][ i_DBcc ] = 1;
1.1.1.13 root 168: PairingArray[ i_EXG ][ i_MOVE ] = 1;
169: PairingArray[ i_EXG ][ i_MOVEA] = 1;
170:
1.1.1.12 root 171: PairingArray[ i_CMPA ][ i_Bcc ] = 1;
172: PairingArray[ i_CMP ][ i_Bcc ] = 1;
1.1.1.13 root 173:
174: M68000_InitPairing_BitShift ( i_DBcc );
175: M68000_InitPairing_BitShift ( i_MOVE );
176: M68000_InitPairing_BitShift ( i_MOVEA );
177: M68000_InitPairing_BitShift ( i_LEA );
1.1.1.17 root 178: M68000_InitPairing_BitShift ( i_JMP );
1.1.1.13 root 179:
1.1.1.12 root 180: PairingArray[ i_MULU ][ i_MOVEA] = 1;
181: PairingArray[ i_MULS ][ i_MOVEA] = 1;
182: PairingArray[ i_MULU ][ i_MOVE ] = 1;
183: PairingArray[ i_MULS ][ i_MOVE ] = 1;
1.1.1.13 root 184:
185: PairingArray[ i_MULU ][ i_DIVU ] = 1;
186: PairingArray[ i_MULU ][ i_DIVS ] = 1;
187: PairingArray[ i_MULS ][ i_DIVU ] = 1;
188: PairingArray[ i_MULS ][ i_DIVS ] = 1;
189:
1.1.1.18 root 190: PairingArray[ i_MULU ][ i_JSR ] = 1;
191: PairingArray[ i_MULS ][ i_JSR ] = 1;
192:
1.1.1.13 root 193: PairingArray[ i_BTST ][ i_Bcc ] = 1;
194:
195: M68000_InitPairing_BitShift ( i_ADD );
196: M68000_InitPairing_BitShift ( i_SUB );
197: M68000_InitPairing_BitShift ( i_OR );
198: M68000_InitPairing_BitShift ( i_AND );
199: M68000_InitPairing_BitShift ( i_EOR );
200: M68000_InitPairing_BitShift ( i_NOT );
201: M68000_InitPairing_BitShift ( i_CLR );
202: M68000_InitPairing_BitShift ( i_NEG );
203: M68000_InitPairing_BitShift ( i_ADDX );
204: M68000_InitPairing_BitShift ( i_SUBX );
205: M68000_InitPairing_BitShift ( i_ABCD );
206: M68000_InitPairing_BitShift ( i_SBCD );
1.1.1.16 root 207:
208: PairingArray[ i_ADD ][ i_MOVE ] = 1; /* when using xx(an,dn) addr mode */
209: PairingArray[ i_SUB ][ i_MOVE ] = 1;
1.1.1.22! root 210:
! 211: PairingArray[ i_ABCD ][ i_DBcc ] = 1;
! 212: PairingArray[ i_SBCD ][ i_DBcc ] = 1;
1.1.1.16 root 213: }
214:
215:
216: /**
217: * One-time CPU initialization.
218: */
219: void M68000_Init(void)
220: {
221: /* Init UAE CPU core */
222: Init680x0();
223:
224: /* Init the pairing matrix */
225: M68000_InitPairing();
1.1.1.12 root 226: }
1.1 root 227:
228:
1.1.1.3 root 229: /*-----------------------------------------------------------------------*/
1.1.1.12 root 230: /**
231: * Reset CPU 68000 variables
232: */
1.1.1.13 root 233: void M68000_Reset(bool bCold)
1.1 root 234: {
1.1.1.19 root 235: #if ENABLE_WINUAE_CPU
1.1.1.22! root 236: int spcFlags = regs.spcflags & (SPCFLAG_MODE_CHANGE | SPCFLAG_BRK);
1.1.1.12 root 237: if (bCold)
238: {
1.1.1.16 root 239: memset(®s, 0, sizeof(regs));
1.1.1.12 root 240: }
1.1.1.19 root 241: /* Now reset the WINUAE CPU core */
1.1.1.22! root 242: m68k_reset();
! 243:
! 244: /* On Hatari, when we change cpu settings, we call m68k_reset() during m68k_run_xx(), */
! 245: /* so we must keep the value of bits SPCFLAG_MODE_CHANGE and SPCFLAG_BRK to exit m68k_run_xx() */
! 246: /* and choose a new m68k_run_xx() function */
! 247: /* [NP] TODO : don't force a reset when changing cpu settings and use common code with WinUAE ? */
! 248: regs.spcflags |= spcFlags;
! 249:
1.1.1.19 root 250: #else /* UAE CPU core */
251: if (bCold)
252: {
253: /* Clear registers */
254: memset(®s, 0, sizeof(regs));
255: }
256: /* Now reset the UAE CPU core */
1.1.1.12 root 257: m68k_reset();
1.1.1.17 root 258: #endif
1.1.1.14 root 259: BusMode = BUS_MODE_CPU;
1.1.1.20 root 260: CPU_IACK = false;
1.1.1.12 root 261: }
262:
263:
264: /*-----------------------------------------------------------------------*/
265: /**
1.1.1.16 root 266: * Start 680x0 emulation
1.1.1.12 root 267: */
268: void M68000_Start(void)
269: {
270: /* Load initial memory snapshot */
271: if (bLoadMemorySave)
272: {
1.1.1.15 root 273: MemorySnapShot_Restore(ConfigureParams.Memory.szMemoryCaptureFileName, false);
1.1.1.12 root 274: }
275: else if (bLoadAutoSave)
276: {
1.1.1.15 root 277: MemorySnapShot_Restore(ConfigureParams.Memory.szAutoSaveFileName, false);
1.1.1.12 root 278: }
1.1.1.7 root 279:
1.1.1.15 root 280: m68k_go(true);
1.1 root 281: }
282:
1.1.1.3 root 283:
284: /*-----------------------------------------------------------------------*/
1.1.1.12 root 285: /**
1.1.1.17 root 286: * Check whether CPU settings have been changed.
1.1.1.22! root 287: * Possible values for WinUAE :
! 288: * cpu_model : 68000 , 68010, 68020, 68030, 68040, 68060
! 289: * cpu_level : not used anymore
! 290: * cpu_compatible : 0/false (no prefetch for 68000/20/30) 1/true (prefetch opcode for 68000/20/30)
! 291: * cpu_cycle_exact : 0/false 1/true (most accurate, implies cpu_compatible)
! 292: * address_space_24 : 1 (68000/10 and 68030 LC for Falcon), 0 (68020/30/40/60)
! 293: * fpu_model : 0, 68881 (external), 68882 (external), 68040 (cpu) , 68060 (cpu)
! 294: * fpu_strict : true/false (more accurate rounding)
! 295: * mmu_model : 0, 68030, 68040, 68060
! 296: *
! 297: * m68k_speed : -1=don't adjust cycle >=0 use m68k_speed_throttle to precisely adjust cycles
! 298: * m68k_speed_throttle : if not 0, used to set cycles_mult. In Hatari, set it to 0
! 299: * cpu_frequency : in CE mode, fine control of cpu freq, set it to freq/2. Not used in Hatari, set it to 0.
! 300: * cpu_clock_multiplier : used to speed up/slow down clock by multiple of 2 in CE mode. In Hatari
! 301: * we use nCpuFreqShift, so this should always be set to 2<<8 = 512 to get the same
! 302: * cpucycleunit as in non CE mode.
1.1.1.12 root 303: */
1.1.1.17 root 304: void M68000_CheckCpuSettings(void)
1.1.1.12 root 305: {
1.1.1.17 root 306: if (ConfigureParams.System.nCpuFreq < 12)
307: {
308: ConfigureParams.System.nCpuFreq = 8;
309: nCpuFreqShift = 0;
310: }
311: else if (ConfigureParams.System.nCpuFreq > 26)
312: {
313: ConfigureParams.System.nCpuFreq = 32;
314: nCpuFreqShift = 2;
315: }
316: else
317: {
318: ConfigureParams.System.nCpuFreq = 16;
319: nCpuFreqShift = 1;
320: }
1.1.1.12 root 321: changed_prefs.cpu_level = ConfigureParams.System.nCpuLevel;
322: changed_prefs.cpu_compatible = ConfigureParams.System.bCompatibleCpu;
1.1.1.17 root 323:
324: #if ENABLE_WINUAE_CPU
1.1.1.19 root 325: /* WinUAE core uses cpu_model instead of cpu_level, so we've got to
326: * convert these values here: */
1.1.1.17 root 327: switch (changed_prefs.cpu_level) {
328: case 0 : changed_prefs.cpu_model = 68000; break;
329: case 1 : changed_prefs.cpu_model = 68010; break;
330: case 2 : changed_prefs.cpu_model = 68020; break;
331: case 3 : changed_prefs.cpu_model = 68030; break;
332: case 4 : changed_prefs.cpu_model = 68040; break;
333: case 5 : changed_prefs.cpu_model = 68060; break;
334: default: fprintf (stderr, "Init680x0() : Error, cpu_level unknown\n");
335: }
1.1.1.19 root 336: currprefs.cpu_level = changed_prefs.cpu_level;
1.1.1.17 root 337:
338: changed_prefs.address_space_24 = ConfigureParams.System.bAddressSpace24;
339: changed_prefs.cpu_cycle_exact = ConfigureParams.System.bCycleExactCpu;
340: changed_prefs.fpu_model = ConfigureParams.System.n_FPUType;
341: changed_prefs.fpu_strict = ConfigureParams.System.bCompatibleFPU;
1.1.1.22! root 342:
! 343: /* Update the MMU model by taking the same value as CPU model */
! 344: /* MMU is only supported for CPU >=68030, this is later checked in custom.c fixup_cpu() */
! 345: if ( !ConfigureParams.System.bMMU )
! 346: changed_prefs.mmu_model = 0; /* MMU disabled */
! 347: else
! 348: changed_prefs.mmu_model = changed_prefs.cpu_model; /* MMU enabled */
! 349:
! 350: /* Set cpu speed to default values (only use in WinUAE, not in Hatari) */
! 351: currprefs.m68k_speed = changed_prefs.m68k_speed = 0;
! 352: currprefs.cpu_clock_multiplier = changed_prefs.cpu_clock_multiplier = 2 << 8;
! 353:
! 354: #else
! 355: changed_prefs.cpu_cycle_exact = 0; /* With old UAE CPU, cycle_exact is always false */
1.1.1.12 root 356: #endif
1.1.1.22! root 357:
1.1.1.12 root 358: if (table68k)
359: check_prefs_changed_cpu();
360: }
361:
362:
363: /*-----------------------------------------------------------------------*/
364: /**
365: * Save/Restore snapshot of CPU variables ('MemorySnapShot_Store' handles type)
366: */
1.1.1.13 root 367: void M68000_MemorySnapShot_Capture(bool bSave)
1.1 root 368: {
1.1.1.17 root 369: #if ENABLE_WINUAE_CPU
370: int len;
1.1.1.22! root 371: uae_u8 chunk[ 1000 ];
! 372:
! 373: if (bSave)
! 374: {
! 375: //m68k_dumpstate_file(stderr, NULL);
! 376: save_cpu (&len,chunk);
! 377: //printf ( "save cpu done\n" );
! 378: save_cpu_extra (&len,chunk);
! 379: //printf ( "save cpux done\n" );
! 380: save_fpu (&len,chunk);
! 381: //printf ( "save fpu done\n" );
! 382: save_mmu (&len,chunk);
! 383: //printf ( "save mmu done\n" );
! 384: //m68k_dumpstate_file(stderr, NULL);
! 385: }
! 386: else
! 387: {
! 388: //m68k_dumpstate_file(stderr, NULL);
! 389: restore_cpu (chunk);
! 390: //printf ( "restore cpu done\n" );
! 391: restore_cpu_extra (chunk);
! 392: //printf ( "restore cpux done\n" );
! 393: restore_fpu (chunk);
! 394: //printf ( "restore fpu done\n" );
! 395: restore_mmu (chunk);
! 396: //printf ( "restore mmu done\n" );
! 397:
! 398: restore_cpu_finish ();
! 399: if ( regs.s ) regs.regs[15] = regs.isp;
! 400: else regs.regs[15] = regs.usp;
! 401: //m68k_dumpstate_file(stderr, NULL);
! 402: }
! 403:
! 404: #else /* UAE CPU core */
! 405: Uint32 savepc;
1.1 root 406:
1.1.1.12 root 407: /* For the UAE CPU core: */
408: MemorySnapShot_Store(&currprefs.address_space_24,
409: sizeof(currprefs.address_space_24));
410: MemorySnapShot_Store(®s.regs[0], sizeof(regs.regs)); /* D0-D7 A0-A6 */
411:
412: if (bSave)
413: {
414: savepc = M68000_GetPC();
415: MemorySnapShot_Store(&savepc, sizeof(savepc)); /* PC */
416: }
417: else
418: {
419: MemorySnapShot_Store(&savepc, sizeof(savepc)); /* PC */
420: regs.pc = savepc;
421: regs.prefetch_pc = regs.pc + 128;
422: }
1.1.1.8 root 423:
1.1.1.12 root 424: MemorySnapShot_Store(®s.prefetch, sizeof(regs.prefetch)); /* prefetch */
425:
426: if (bSave)
427: {
428: MakeSR();
429: if (regs.s)
430: {
431: MemorySnapShot_Store(®s.usp, sizeof(regs.usp)); /* USP */
432: MemorySnapShot_Store(®s.regs[15], sizeof(regs.regs[15])); /* ISP */
433: }
434: else
435: {
436: MemorySnapShot_Store(®s.regs[15], sizeof(regs.regs[15])); /* USP */
437: MemorySnapShot_Store(®s.isp, sizeof(regs.isp)); /* ISP */
438: }
439: MemorySnapShot_Store(®s.sr, sizeof(regs.sr)); /* SR/CCR */
440: }
441: else
442: {
443: MemorySnapShot_Store(®s.usp, sizeof(regs.usp));
444: MemorySnapShot_Store(®s.isp, sizeof(regs.isp));
445: MemorySnapShot_Store(®s.sr, sizeof(regs.sr));
446: }
1.1.1.22! root 447: MemorySnapShot_Store(®s.opcode, sizeof(regs.opcode));
! 448: MemorySnapShot_Store(®s.instruction_pc, sizeof(regs.instruction_pc));
1.1.1.12 root 449: MemorySnapShot_Store(®s.stopped, sizeof(regs.stopped));
450: MemorySnapShot_Store(®s.dfc, sizeof(regs.dfc)); /* DFC */
451: MemorySnapShot_Store(®s.sfc, sizeof(regs.sfc)); /* SFC */
452: MemorySnapShot_Store(®s.vbr, sizeof(regs.vbr)); /* VBR */
453: MemorySnapShot_Store(&caar, sizeof(caar)); /* CAAR */
454: MemorySnapShot_Store(&cacr, sizeof(cacr)); /* CACR */
455: MemorySnapShot_Store(®s.msp, sizeof(regs.msp)); /* MSP */
456:
457: if (!bSave)
458: {
459: M68000_SetPC(regs.pc);
460: /* MakeFromSR() must not swap stack pointer */
461: regs.s = (regs.sr >> 13) & 1;
462: MakeFromSR();
463: /* set stack pointer */
464: if (regs.s)
465: m68k_areg(regs, 7) = regs.isp;
466: else
467: m68k_areg(regs, 7) = regs.usp;
468: }
469:
470: if (bSave)
471: save_fpu();
472: else
473: restore_fpu();
1.1.1.17 root 474: #endif
1.1 root 475: }
476:
477:
1.1.1.3 root 478: /*-----------------------------------------------------------------------*/
1.1.1.12 root 479: /**
480: * BUSERROR - Access outside valid memory range.
1.1.1.17 root 481: * Use bRead = 0 for write errors and bRead = 1 for read errors!
1.1.1.12 root 482: */
1.1.1.22! root 483: void M68000_BusError ( Uint32 addr , int ReadWrite , int Size , int AccessType )
1.1 root 484: {
1.1.1.22! root 485: Uint32 InstrPC = M68000_InstrPC;
1.1.1.7 root 486:
1.1.1.15 root 487: /* Do not print message when TOS is testing for available HW or
488: * when a program just checks for the floating point co-processor. */
1.1.1.22! root 489: if ((InstrPC < TosAddress || InstrPC > TosAddress + TosSize)
1.1.1.15 root 490: && addr != 0xfffa42)
1.1.1.12 root 491: {
1.1.1.15 root 492: /* Print bus error message */
1.1.1.22! root 493: fprintf(stderr, "M68000 Bus Error %s at address $%x PC=$%x.\n",
! 494: ReadWrite ? "reading" : "writing", addr, InstrPC);
1.1.1.12 root 495: }
496:
1.1.1.22! root 497: #ifndef ENABLE_WINUAE_CPU
! 498: if ((regs.spcflags & SPCFLAG_BUSERROR) == 0) /* [NP] Check that the opcode has not already generated a read bus error */
1.1.1.12 root 499: {
500: BusErrorAddress = addr; /* Store for exception frame */
1.1.1.22! root 501: bBusErrorReadWrite = ReadWrite;
1.1.1.12 root 502: M68000_SetSpecial(SPCFLAG_BUSERROR); /* The exception will be done in newcpu.c */
503: }
1.1.1.22! root 504:
! 505: #else
! 506: /* With WinUAE's cpu, on a bus error instruction will be correctly aborted before completing, */
! 507: /* so we don't need to check if the opcode already generated a bus error or not */
! 508: exception2 ( addr , ReadWrite , Size , AccessType );
! 509: #endif
1.1 root 510: }
511:
1.1.1.3 root 512:
513: /*-----------------------------------------------------------------------*/
1.1.1.12 root 514: /**
515: * Exception handler
516: */
1.1.1.22! root 517: void M68000_Exception(Uint32 ExceptionNr , int ExceptionSource)
1.1.1.12 root 518: {
1.1.1.22! root 519: #ifndef WINUAE_FOR_HATARI
1.1.1.16 root 520: if ((ExceptionSource == M68000_EXC_SRC_AUTOVEC)
1.1.1.22! root 521: && (ExceptionNr>24 && ExceptionNr<32)) /* 68k autovector interrupt? */
1.1.1.12 root 522: {
523: /* Handle autovector interrupts the UAE's way
524: * (see intlev() and do_specialties() in UAE CPU core) */
525: /* In our case, this part is only called for HBL and VBL interrupts */
1.1.1.22! root 526: int intnr = ExceptionNr - 24;
1.1.1.12 root 527: pendingInterrupts |= (1 << intnr);
528: M68000_SetSpecial(SPCFLAG_INT);
529: }
1.1.1.13 root 530:
531: else /* MFP or direct CPU exceptions */
1.1.1.12 root 532: {
533: Uint16 SR;
534:
535: /* Was the CPU stopped, i.e. by a STOP instruction? */
536: if (regs.spcflags & SPCFLAG_STOP)
537: {
538: regs.stopped = 0;
539: M68000_UnsetSpecial(SPCFLAG_STOP); /* All is go,go,go! */
540: }
541:
542: /* 68k exceptions are handled by Exception() of the UAE CPU core */
1.1.1.22! root 543: Exception(ExceptionNr, m68k_getpc(), ExceptionSource);
1.1.1.12 root 544:
545: /* Set Status Register so interrupt can ONLY be stopped by another interrupt
1.1.1.22! root 546: * of higher priority */
! 547: if ( (ExceptionSource == M68000_EXC_SRC_INT_MFP)
! 548: || (ExceptionSource == M68000_EXC_SRC_INT_DSP) )
1.1.1.12 root 549: {
1.1.1.22! root 550: SR = M68000_GetSR();
! 551: SR = (SR&SR_CLEAR_IPL)|0x0600; /* MFP or DSP, level 6 */
! 552: M68000_SetSR(SR);
1.1.1.16 root 553: }
1.1.1.22! root 554: }
! 555:
! 556: #else
! 557: if ( ExceptionNr > 24 && ExceptionNr < 32 ) /* Level 1-7 interrupts */
! 558: {
! 559: /* In our case, this part is called for HBL, VBL and MFP/DSP interrupts */
! 560: /* (see intlev() and do_specialties() in UAE CPU core) */
! 561: int intnr = ExceptionNr - 24;
! 562: pendingInterrupts |= (1 << intnr);
! 563: doint();
! 564: }
1.1.1.12 root 565:
1.1.1.22! root 566: else /* direct CPU exceptions */
! 567: {
! 568: Exception(ExceptionNr);
1.1.1.12 root 569: }
1.1.1.22! root 570: #endif
1.1 root 571: }
572:
1.1.1.8 root 573:
1.1.1.22! root 574:
! 575:
! 576: /*-----------------------------------------------------------------------*/
! 577: /**
! 578: * Update the list of pending interrupts.
! 579: * Level 2 (HBL) and 4 (VBL) are only cleared when the interrupt is processed,
! 580: * but level 6 is shared between MFP and DSP and can be cleared by MFP or DSP
! 581: * before being processed.
! 582: * So, we need to check which IRQ are set/cleared at the same time
! 583: * and update level 6 accordingly : level 6 = MFP_IRQ OR DSP_IRQ
! 584: *
! 585: * [NP] NOTE : temporary case for interrupts with WinUAE CPU in cycle exact mode
! 586: * In CE mode, interrupt state should be updated on each subcycle of every opcode
! 587: * then ipl_fetch() is called in each opcode.
! 588: * For now, Hatari with WinUAE CPU in CE mode only evaluates the interrupt state
! 589: * after the end of each opcode. So we need to call ipl_fetch() ourselves at the moment.
! 590: */
! 591: void M68000_Update_intlev ( void )
! 592: {
! 593: #ifdef WINUAE_FOR_HATARI
! 594: Uint8 Level6_IRQ;
! 595:
! 596: #if ENABLE_DSP_EMU
! 597: Level6_IRQ = MFP_GetIRQ_CPU() | DSP_GetHREQ();
! 598: #else
! 599: Level6_IRQ = MFP_GetIRQ_CPU();
! 600: #endif
! 601: if ( Level6_IRQ == 1 )
! 602: pendingInterrupts |= (1 << 6);
! 603: else
! 604: pendingInterrupts &= ~(1 << 6);
! 605:
! 606: if ( pendingInterrupts )
! 607: doint();
! 608: else
! 609: M68000_UnsetSpecial ( SPCFLAG_INT | SPCFLAG_DOINT );
! 610:
! 611: /* Temporary case for WinUAE CPU in CE mode */
! 612: /* doint() will update regs.ipl_pin, so copy it into regs.ipl */
! 613: if ( ConfigureParams.System.bCycleExactCpu )
! 614: regs.ipl = regs.ipl_pin; /* See ipl_fetch() in cpu/cpu_prefetch.h */
! 615: #endif
! 616: }
! 617:
! 618:
! 619:
! 620:
1.1.1.8 root 621: /*-----------------------------------------------------------------------*/
1.1.1.12 root 622: /**
623: * There seem to be wait states when a program accesses certain hardware
624: * registers on the ST. Use this function to simulate these wait states.
625: * [NP] with some instructions like CLR, we have a read then a write at the
626: * same location, so we may have 2 wait states (read and write) to add
627: * (nWaitStateCycles should be reset to 0 after the cycles were added).
628: */
1.1.1.11 root 629: void M68000_WaitState(int nCycles)
1.1.1.8 root 630: {
1.1.1.12 root 631: M68000_SetSpecial(SPCFLAG_EXTRA_CYCLES);
1.1.1.11 root 632:
1.1.1.12 root 633: nWaitStateCycles += nCycles; /* add all the wait states for this instruction */
1.1.1.8 root 634: }
1.1.1.20 root 635:
636:
637:
638: /*-----------------------------------------------------------------------*/
639: /**
640: * Some components (HBL/VBL interrupts, access to the ACIA) require an
641: * extra delay to be synchronized with the E Clock.
642: * E Clock's frequency is 1/10th of the CPU, ie 0.8 MHz in an STF/STE
643: * This delay is a multiple of 2 and will follow the pattern [ 0 8 6 4 2 ]
644: */
645: int M68000_WaitEClock ( void )
646: {
647: int CyclesToNextE;
648:
649: /* We must wait for the next multiple of 10 cycles to be synchronised with E Clock */
1.1.1.21 root 650: CyclesToNextE = 10 - CyclesGlobalClockCounter % 10;
1.1.1.20 root 651: if ( CyclesToNextE == 10 ) /* we're already synchronised with E Clock */
652: CyclesToNextE = 0;
653: return CyclesToNextE;
654: }
655:
656:
657:
1.1.1.22! root 658:
! 659: /*-----------------------------------------------------------------------*/
! 660: /**
! 661: * In case we modified the memory by accessing it directly (and bypassing
! 662: * the CPU's cache mechanism), we need to flush the instruction and data
! 663: * caches to force an update of the caches on the next accesses.
! 664: *
! 665: * [NP] NOTE : for now, flush_instr_caches and flush_dcache flush
! 666: * the whole caches, not just 'addr'
! 667: */
! 668: void M68000_Flush_All_Caches ( uaecptr addr , int size )
! 669: {
! 670: #ifdef WINUAE_FOR_HATARI
! 671: M68000_Flush_Instr_Cache ( addr , size );
! 672: M68000_Flush_Data_Cache ( addr , size );
! 673: #endif
! 674: }
! 675:
! 676:
! 677: void M68000_Flush_Instr_Cache ( uaecptr addr , int size )
! 678: {
! 679: #ifdef WINUAE_FOR_HATARI
! 680: /* Instruction cache for cpu >= 68020 */
! 681: flush_instr_cache ( addr , size );
! 682: #endif
! 683: }
! 684:
! 685:
! 686: void M68000_Flush_Data_Cache ( uaecptr addr , int size )
! 687: {
! 688: #ifdef WINUAE_FOR_HATARI
! 689: /* Data cache for cpu >= 68030 is only emulated with WinUAE */
! 690: flush_dcache ( addr , size );
! 691: #endif
! 692: }
! 693:
! 694:
! 695:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.