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