|
|
1.1 root 1: /*
2: Hatari - m68000.c
3:
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: */
8:
9:
10: const char M68000_fileid[] = "Hatari m68000.c : " __DATE__ " " __TIME__;
11:
12: #include "main.h"
13: #include "configuration.h"
14: #include "hatari-glue.h"
15: #include "cycInt.h"
16: #include "m68000.h"
17: #include "memorySnapShot.h"
18: #include "options.h"
19: #include "savestate.h"
20: #include "nextMemory.h"
21:
1.1.1.3 root 22: #include "mmu_common.h"
1.1 root 23:
24: Uint32 BusErrorAddress; /* Stores the offending address for bus-/address errors */
25: Uint32 BusErrorPC; /* Value of the PC when bus error occurs */
26: bool bBusErrorReadWrite; /* 0 for write error, 1 for read error */
27: int nCpuFreqShift; /* Used to emulate higher CPU frequencies: 0=8MHz, 1=16MHz, 2=32Mhz */
1.1.1.4 ! root 28: int nCpuFreqDivider; /* Used to emulate higher CPU frequencies: 1=8MHz, 2=16MHz, 4=32Mhz */
1.1 root 29: int nWaitStateCycles; /* Used to emulate the wait state cycles of certain IO registers */
30: int BusMode = BUS_MODE_CPU; /* Used to tell which part is owning the bus (cpu, blitter, ...) */
31:
32: int LastOpcodeFamily = i_NOP; /* see the enum in readcpu.h i_XXX */
33: int LastInstrCycles = 0; /* number of cycles for previous instr. (not rounded to 4) */
34: int Pairing = 0; /* set to 1 if the latest 2 intr paired */
35: char PairingArray[ MAX_OPCODE_FAMILY ][ MAX_OPCODE_FAMILY ];
36:
37:
38: /* to convert the enum from OpcodeFamily to a readable value for pairing's debug */
39: const char *OpcodeName[] = { "ILLG",
40: "OR","AND","EOR","ORSR","ANDSR","EORSR",
41: "SUB","SUBA","SUBX","SBCD",
42: "ADD","ADDA","ADDX","ABCD",
43: "NEG","NEGX","NBCD","CLR","NOT","TST",
44: "BTST","BCHG","BCLR","BSET",
45: "CMP","CMPM","CMPA",
46: "MVPRM","MVPMR","MOVE","MOVEA","MVSR2","MV2SR",
47: "SWAP","EXG","EXT","MVMEL","MVMLE",
48: "TRAP","MVR2USP","MVUSP2R","RESET","NOP","STOP","RTE","RTD",
49: "LINK","UNLK",
50: "RTS","TRAPV","RTR",
51: "JSR","JMP","BSR","Bcc",
52: "LEA","PEA","DBcc","Scc",
53: "DIVU","DIVS","MULU","MULS",
54: "ASR","ASL","LSR","LSL","ROL","ROR","ROXL","ROXR",
55: "ASRW","ASLW","LSRW","LSLW","ROLW","RORW","ROXLW","ROXRW",
56: "CHK","CHK2",
57: "MOVEC2","MOVE2C","CAS","CAS2","DIVL","MULL",
58: "BFTST","BFEXTU","BFCHG","BFEXTS","BFCLR","BFFFO","BFSET","BFINS",
59: "PACK","UNPK","TAS","BKPT","CALLM","RTM","TRAPcc","MOVES",
60: "FPP","FDBcc","FScc","FTRAPcc","FBcc","FSAVE","FRESTORE",
61: "CINVL","CINVP","CINVA","CPUSHL","CPUSHP","CPUSHA","MOVE16",
62: "MMUOP"
63: };
64:
65:
66: /*-----------------------------------------------------------------------*/
67: /**
68: * Add pairing between all the bit shifting instructions and a given Opcode
69: */
70:
71: static void M68000_InitPairing_BitShift ( int OpCode )
72: {
73: PairingArray[ i_ASR ][ OpCode ] = 1;
74: PairingArray[ i_ASL ][ OpCode ] = 1;
75: PairingArray[ i_LSR ][ OpCode ] = 1;
76: PairingArray[ i_LSL ][ OpCode ] = 1;
77: PairingArray[ i_ROL ][ OpCode ] = 1;
78: PairingArray[ i_ROR ][ OpCode ] = 1;
79: PairingArray[ i_ROXR ][ OpCode ] = 1;
80: PairingArray[ i_ROXL ][ OpCode ] = 1;
81: }
82:
83:
84: /**
85: * Init the pairing matrix
86: * Two instructions can pair if PairingArray[ LastOpcodeFamily ][ OpcodeFamily ] == 1
87: */
88: static void M68000_InitPairing(void)
89: {
90: /* First, clear the matrix (pairing is false) */
91: memset(PairingArray , 0 , MAX_OPCODE_FAMILY * MAX_OPCODE_FAMILY);
92:
93: /* Set all valid pairing combinations to 1 */
94: PairingArray[ i_EXG ][ i_DBcc ] = 1;
95: PairingArray[ i_EXG ][ i_MOVE ] = 1;
96: PairingArray[ i_EXG ][ i_MOVEA] = 1;
97:
98: PairingArray[ i_CMPA ][ i_Bcc ] = 1;
99: PairingArray[ i_CMP ][ i_Bcc ] = 1;
100:
101: M68000_InitPairing_BitShift ( i_DBcc );
102: M68000_InitPairing_BitShift ( i_MOVE );
103: M68000_InitPairing_BitShift ( i_MOVEA );
104: M68000_InitPairing_BitShift ( i_LEA );
1.1.1.2 root 105: M68000_InitPairing_BitShift ( i_JMP );
1.1 root 106:
107: PairingArray[ i_MULU ][ i_MOVEA] = 1;
108: PairingArray[ i_MULS ][ i_MOVEA] = 1;
109: PairingArray[ i_MULU ][ i_MOVE ] = 1;
110: PairingArray[ i_MULS ][ i_MOVE ] = 1;
111:
112: PairingArray[ i_MULU ][ i_DIVU ] = 1;
113: PairingArray[ i_MULU ][ i_DIVS ] = 1;
114: PairingArray[ i_MULS ][ i_DIVU ] = 1;
115: PairingArray[ i_MULS ][ i_DIVS ] = 1;
116:
117: PairingArray[ i_BTST ][ i_Bcc ] = 1;
118:
119: M68000_InitPairing_BitShift ( i_ADD );
120: M68000_InitPairing_BitShift ( i_SUB );
121: M68000_InitPairing_BitShift ( i_OR );
122: M68000_InitPairing_BitShift ( i_AND );
123: M68000_InitPairing_BitShift ( i_EOR );
124: M68000_InitPairing_BitShift ( i_NOT );
125: M68000_InitPairing_BitShift ( i_CLR );
126: M68000_InitPairing_BitShift ( i_NEG );
127: M68000_InitPairing_BitShift ( i_ADDX );
128: M68000_InitPairing_BitShift ( i_SUBX );
129: M68000_InitPairing_BitShift ( i_ABCD );
130: M68000_InitPairing_BitShift ( i_SBCD );
131:
132: PairingArray[ i_ADD ][ i_MOVE ] = 1; /* when using xx(an,dn) addr mode */
133: PairingArray[ i_SUB ][ i_MOVE ] = 1;
134: }
135:
136:
137: /**
138: * One-time CPU initialization.
139: */
140: void M68000_Init(void)
141: {
142: /* Init UAE CPU core */
143: Init680x0();
144:
145: /* Init the pairing matrix */
146: M68000_InitPairing();
147: }
148:
149:
150: /*-----------------------------------------------------------------------*/
151: /**
152: * Reset CPU 68000 variables
153: */
154: void M68000_Reset(bool bCold)
155: {
1.1.1.3 root 156: if (bCold)
157: {
158: /* Clear registers, but we need to keep SPCFLAG_MODE_CHANGE and SPCFLAG_BRK unchanged */
159: int spcFlags = regs.spcflags & (SPCFLAG_MODE_CHANGE | SPCFLAG_BRK);
160: memset(®s, 0, sizeof(regs));
161: regs.spcflags = spcFlags;
162: }
163: /* Now reset the WINUAE CPU core */
164: m68k_reset(bCold);
165: BusMode = BUS_MODE_CPU;
1.1 root 166: }
167:
168:
169: /*-----------------------------------------------------------------------*/
170: /**
1.1.1.4 ! root 171: * Stop 680x0 emulation
! 172: */
! 173: void M68000_Stop(void)
! 174: {
! 175: M68000_SetSpecial(SPCFLAG_BRK);
! 176: }
! 177:
! 178:
! 179: /*-----------------------------------------------------------------------*/
! 180: /**
1.1 root 181: * Start 680x0 emulation
182: */
183: void M68000_Start(void)
184: {
185: /* Load initial memory snapshot */
186: if (bLoadMemorySave)
187: {
188: MemorySnapShot_Restore(ConfigureParams.Memory.szMemoryCaptureFileName, false);
189: }
190: else if (bLoadAutoSave)
191: {
192: MemorySnapShot_Restore(ConfigureParams.Memory.szAutoSaveFileName, false);
193: }
194:
195: m68k_go(true);
196: }
197:
198:
199: /*-----------------------------------------------------------------------*/
200: /**
1.1.1.2 root 201: * Check whether CPU settings have been changed.
1.1 root 202: */
1.1.1.2 root 203: void M68000_CheckCpuSettings(void)
1.1 root 204: {
1.1.1.4 ! root 205: #if USE_FREQ_DIVIDER
! 206: if (ConfigureParams.System.nCpuFreq < 20)
! 207: {
! 208: ConfigureParams.System.nCpuFreq = 16;
! 209: nCpuFreqDivider = 2;
! 210: }
! 211: else if (ConfigureParams.System.nCpuFreq < 24)
! 212: {
! 213: ConfigureParams.System.nCpuFreq = 20;
! 214: nCpuFreqDivider = 3;
! 215: }
! 216: else if (ConfigureParams.System.nCpuFreq < 32)
! 217: {
! 218: ConfigureParams.System.nCpuFreq = 25;
! 219: nCpuFreqDivider = 3;
! 220: }
! 221: else if (ConfigureParams.System.nCpuFreq < 40)
! 222: {
! 223: ConfigureParams.System.nCpuFreq = 33;
! 224: nCpuFreqDivider = 4;
! 225: } else {
! 226: if (ConfigureParams.System.bTurbo) {
! 227: ConfigureParams.System.nCpuFreq = 40;
! 228: nCpuFreqDivider = 5;
! 229: } else {
! 230: ConfigureParams.System.nCpuFreq = 33;
! 231: nCpuFreqDivider = 4;
! 232: }
! 233: }
! 234: #else
1.1.1.2 root 235: if (ConfigureParams.System.nCpuFreq < 12)
236: {
237: ConfigureParams.System.nCpuFreq = 8;
238: nCpuFreqShift = 0;
239: }
240: else if (ConfigureParams.System.nCpuFreq > 26)
241: {
242: ConfigureParams.System.nCpuFreq = 32;
243: nCpuFreqShift = 2;
244: }
245: else
246: {
247: ConfigureParams.System.nCpuFreq = 16;
248: nCpuFreqShift = 1;
249: }
1.1.1.4 ! root 250: #endif
1.1 root 251: changed_prefs.cpu_level = ConfigureParams.System.nCpuLevel;
252: changed_prefs.cpu_compatible = ConfigureParams.System.bCompatibleCpu;
1.1.1.2 root 253:
254: switch (changed_prefs.cpu_level) {
255: case 0 : changed_prefs.cpu_model = 68000; break;
256: case 1 : changed_prefs.cpu_model = 68010; break;
257: case 2 : changed_prefs.cpu_model = 68020; break;
258: case 3 : changed_prefs.cpu_model = 68030; break;
259: case 4 : changed_prefs.cpu_model = 68040; break;
260: case 5 : changed_prefs.cpu_model = 68060; break;
261: default: fprintf (stderr, "Init680x0() : Error, cpu_level unknown\n");
262: }
263:
1.1.1.4 ! root 264: changed_prefs.fpu_model = ConfigureParams.System.n_FPUType;
! 265: switch (changed_prefs.fpu_model) {
! 266: case 68881: changed_prefs.fpu_revision = 0x1f; break;
! 267: case 68882: changed_prefs.fpu_revision = 0x20; break;
! 268: case 68040:
! 269: if (ConfigureParams.System.bTurbo)
! 270: changed_prefs.fpu_revision = 0x41;
! 271: else
! 272: changed_prefs.fpu_revision = 0x40;
! 273: break;
! 274: default: fprintf (stderr, "Init680x0() : Error, fpu_model unknown\n");
! 275: }
! 276:
1.1.1.2 root 277: changed_prefs.address_space_24 = ConfigureParams.System.bAddressSpace24;
278: changed_prefs.cpu_cycle_exact = ConfigureParams.System.bCycleExactCpu;
279: changed_prefs.fpu_strict = ConfigureParams.System.bCompatibleFPU;
1.1.1.4 ! root 280: changed_prefs.mmu_model = ConfigureParams.System.bMMU?changed_prefs.cpu_model:0;
! 281:
1.1 root 282: if (table68k)
283: check_prefs_changed_cpu();
284: }
285:
286:
287: /*-----------------------------------------------------------------------*/
288: /**
289: * Save/Restore snapshot of CPU variables ('MemorySnapShot_Store' handles type)
290: */
291: void M68000_MemorySnapShot_Capture(bool bSave)
292: {
293: Uint32 savepc;
1.1.1.2 root 294: int len;
295: uae_u8 *chunk = 0;
1.1 root 296:
297: /* For the UAE CPU core: */
298: MemorySnapShot_Store(&currprefs.address_space_24,
299: sizeof(currprefs.address_space_24));
300: MemorySnapShot_Store(®s.regs[0], sizeof(regs.regs)); /* D0-D7 A0-A6 */
301:
302: if (bSave)
303: {
304: savepc = M68000_GetPC();
305: MemorySnapShot_Store(&savepc, sizeof(savepc)); /* PC */
306: }
307: else
308: {
309: MemorySnapShot_Store(&savepc, sizeof(savepc)); /* PC */
310: regs.pc = savepc;
311: #ifdef UAE_NEWCPU_H
312: regs.prefetch_pc = regs.pc + 128;
313: #endif
314: }
315:
316: #ifdef UAE_NEWCPU_H
317: MemorySnapShot_Store(®s.prefetch, sizeof(regs.prefetch)); /* prefetch */
318: #else
319: uae_u32 prefetch_dummy;
320: MemorySnapShot_Store(&prefetch_dummy, sizeof(prefetch_dummy));
321: #endif
322:
323: if (bSave)
324: {
325: MakeSR();
326: if (regs.s)
327: {
328: MemorySnapShot_Store(®s.usp, sizeof(regs.usp)); /* USP */
329: MemorySnapShot_Store(®s.regs[15], sizeof(regs.regs[15])); /* ISP */
330: }
331: else
332: {
333: MemorySnapShot_Store(®s.regs[15], sizeof(regs.regs[15])); /* USP */
334: MemorySnapShot_Store(®s.isp, sizeof(regs.isp)); /* ISP */
335: }
336: MemorySnapShot_Store(®s.sr, sizeof(regs.sr)); /* SR/CCR */
337: }
338: else
339: {
340: MemorySnapShot_Store(®s.usp, sizeof(regs.usp));
341: MemorySnapShot_Store(®s.isp, sizeof(regs.isp));
342: MemorySnapShot_Store(®s.sr, sizeof(regs.sr));
343: }
344: MemorySnapShot_Store(®s.stopped, sizeof(regs.stopped));
345: MemorySnapShot_Store(®s.dfc, sizeof(regs.dfc)); /* DFC */
346: MemorySnapShot_Store(®s.sfc, sizeof(regs.sfc)); /* SFC */
347: MemorySnapShot_Store(®s.vbr, sizeof(regs.vbr)); /* VBR */
1.1.1.2 root 348: MemorySnapShot_Store(®s.caar, sizeof(regs.caar)); /* CAAR */
349: MemorySnapShot_Store(®s.cacr, sizeof(regs.cacr)); /* CACR */
1.1 root 350: MemorySnapShot_Store(®s.msp, sizeof(regs.msp)); /* MSP */
351:
352: if (!bSave)
353: {
354: M68000_SetPC(regs.pc);
355: /* MakeFromSR() must not swap stack pointer */
356: regs.s = (regs.sr >> 13) & 1;
357: MakeFromSR();
358: /* set stack pointer */
359: if (regs.s)
360: m68k_areg(regs, 7) = regs.isp;
361: else
362: m68k_areg(regs, 7) = regs.usp;
363: }
364:
1.1.1.2 root 365: if (bSave)
366: save_fpu(&len,0);
367: else
368: restore_fpu(chunk);
1.1 root 369: }
370:
371:
372: /*-----------------------------------------------------------------------*/
373: /**
374: * BUSERROR - Access outside valid memory range.
1.1.1.2 root 375: * Use bRead = 0 for write errors and bRead = 1 for read errors!
1.1 root 376: */
1.1.1.2 root 377: void M68000_BusError(Uint32 addr, bool bRead)
1.1 root 378: {
1.1.1.4 ! root 379: exception2 (addr, bRead, 0, regs.s ? 5 : 1); /* assumes data access,
! 380: size not set */
! 381: }
! 382: #if 0
! 383: void M68000_BusError(Uint32 addr, bool bRead)
! 384: {
1.1 root 385: /* FIXME: In prefetch mode, m68k_getpc() seems already to point to the next instruction */
386: // BusErrorPC = M68000_GetPC(); /* [NP] We set BusErrorPC in m68k_run_1 */
387:
1.1.1.2 root 388:
1.1 root 389: if ((regs.spcflags & SPCFLAG_BUSERROR) == 0) /* [NP] Check that the opcode has not already generated a read bus error */
390: {
1.1.1.3 root 391: regs.mmu_fault_addr = addr;
1.1 root 392: BusErrorAddress = addr; /* Store for exception frame */
1.1.1.2 root 393: bBusErrorReadWrite = bRead;
1.1.1.4 ! root 394:
1.1.1.3 root 395: if (currprefs.mmu_model) {
1.1.1.4 ! root 396: /* This is a hack for the special status word, this needs to be corrected later */
! 397: if (ConfigureParams.System.nCpuLevel==3) { /* CPU 68030 */
! 398: int fc = 5; /* hack */
! 399: regs.mmu_ssw = (fc&1) ? MMU030_SSW_DF : (MMU030_SSW_FB|MMU030_SSW_RB);
! 400: regs.mmu_ssw |= bRead ? MMU030_SSW_RW : 0;
! 401: regs.mmu_ssw |= fc&MMU030_SSW_FC_MASK;
! 402: /*switch (size) {
! 403: case 4: regs.mmu_ssw |= MMU030_SSW_SIZE_L; break;
! 404: case 2: regs.mmu_ssw |= MMU030_SSW_SIZE_W; break;
! 405: case 1: regs.mmu_ssw |= MMU030_SSW_SIZE_B; break;
! 406: default: break;
! 407: }*/
! 408: printf("Bus Error: Warning! Using hacked SSW (%04X)!\n", regs.mmu_ssw);
! 409: }
1.1.1.3 root 410: THROW(2);
411: return;
412: }
1.1.1.4 ! root 413:
1.1 root 414: M68000_SetSpecial(SPCFLAG_BUSERROR); /* The exception will be done in newcpu.c */
415: }
416: }
1.1.1.4 ! root 417: #endif
1.1 root 418:
419: /*-----------------------------------------------------------------------*/
420: /**
421: * Exception handler
422: */
423: void M68000_Exception(Uint32 ExceptionVector , int ExceptionSource)
424: {
425: int exceptionNr = ExceptionVector/4;
426:
427: if ((ExceptionSource == M68000_EXC_SRC_AUTOVEC)
428: && (exceptionNr>24 && exceptionNr<32)) /* 68k autovector interrupt? */
429: {
430: /* Handle autovector interrupts the UAE's way
431: * (see intlev() and do_specialties() in UAE CPU core) */
432: /* In our case, this part is only called for HBL and VBL interrupts */
433: int intnr = exceptionNr - 24;
434: pendingInterrupts |= (1 << intnr);
435: M68000_SetSpecial(SPCFLAG_INT);
436: }
437:
438: else /* MFP or direct CPU exceptions */
439: {
440: Uint16 SR;
441:
442: /* Was the CPU stopped, i.e. by a STOP instruction? */
443: if (regs.spcflags & SPCFLAG_STOP)
444: {
445: regs.stopped = 0;
446: M68000_UnsetSpecial(SPCFLAG_STOP); /* All is go,go,go! */
447: }
448:
449: /* 68k exceptions are handled by Exception() of the UAE CPU core */
1.1.1.4 ! root 450: Exception(exceptionNr/*, m68k_getpc(), ExceptionSource*/);
! 451:
1.1 root 452: SR = M68000_GetSR();
453:
454: /* Set Status Register so interrupt can ONLY be stopped by another interrupt
455: * of higher priority! */
1.1.1.2 root 456:
1.1 root 457: SR = (SR&SR_CLEAR_IPL)|0x0600; /* DSP, level 6 */
1.1.1.2 root 458:
459: M68000_SetSR(SR);
1.1 root 460: }
461: }
462:
463:
464: /*-----------------------------------------------------------------------*/
465: /**
466: * There seem to be wait states when a program accesses certain hardware
467: * registers on the ST. Use this function to simulate these wait states.
468: * [NP] with some instructions like CLR, we have a read then a write at the
469: * same location, so we may have 2 wait states (read and write) to add
470: * (nWaitStateCycles should be reset to 0 after the cycles were added).
471: */
472: void M68000_WaitState(int nCycles)
473: {
474: M68000_SetSpecial(SPCFLAG_EXTRA_CYCLES);
475:
476: nWaitStateCycles += nCycles; /* add all the wait states for this instruction */
477: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.