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