|
|
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 );
103:
104: PairingArray[ i_MULU ][ i_MOVEA] = 1;
105: PairingArray[ i_MULS ][ i_MOVEA] = 1;
106: PairingArray[ i_MULU ][ i_MOVE ] = 1;
107: PairingArray[ i_MULS ][ i_MOVE ] = 1;
108:
109: PairingArray[ i_MULU ][ i_DIVU ] = 1;
110: PairingArray[ i_MULU ][ i_DIVS ] = 1;
111: PairingArray[ i_MULS ][ i_DIVU ] = 1;
112: PairingArray[ i_MULS ][ i_DIVS ] = 1;
113:
114: PairingArray[ i_BTST ][ i_Bcc ] = 1;
115:
116: M68000_InitPairing_BitShift ( i_ADD );
117: M68000_InitPairing_BitShift ( i_SUB );
118: M68000_InitPairing_BitShift ( i_OR );
119: M68000_InitPairing_BitShift ( i_AND );
120: M68000_InitPairing_BitShift ( i_EOR );
121: M68000_InitPairing_BitShift ( i_NOT );
122: M68000_InitPairing_BitShift ( i_CLR );
123: M68000_InitPairing_BitShift ( i_NEG );
124: M68000_InitPairing_BitShift ( i_ADDX );
125: M68000_InitPairing_BitShift ( i_SUBX );
126: M68000_InitPairing_BitShift ( i_ABCD );
127: M68000_InitPairing_BitShift ( i_SBCD );
128:
129: PairingArray[ i_ADD ][ i_MOVE ] = 1; /* when using xx(an,dn) addr mode */
130: PairingArray[ i_SUB ][ i_MOVE ] = 1;
131: }
132:
133:
134: /**
135: * One-time CPU initialization.
136: */
137: void M68000_Init(void)
138: {
139: /* Init UAE CPU core */
140: Init680x0();
141:
142: /* Init the pairing matrix */
143: M68000_InitPairing();
144: }
145:
146:
147: /*-----------------------------------------------------------------------*/
148: /**
149: * Reset CPU 68000 variables
150: */
151: void M68000_Reset(bool bCold)
152: {
153: /* Clear registers */
154: if (bCold)
155: {
156: memset(®s, 0, sizeof(regs));
157: }
158:
159: /* Now directly reset the UAE CPU core: */
160: m68k_reset();
161:
162: BusMode = BUS_MODE_CPU;
163: }
164:
165:
166: /*-----------------------------------------------------------------------*/
167: /**
168: * Start 680x0 emulation
169: */
170: void M68000_Start(void)
171: {
172: /* Load initial memory snapshot */
173: if (bLoadMemorySave)
174: {
175: MemorySnapShot_Restore(ConfigureParams.Memory.szMemoryCaptureFileName, false);
176: }
177: else if (bLoadAutoSave)
178: {
179: MemorySnapShot_Restore(ConfigureParams.Memory.szAutoSaveFileName, false);
180: }
181:
182: m68k_go(true);
183: }
184:
185:
186: /*-----------------------------------------------------------------------*/
187: /**
188: * Check wether the CPU mode has been changed.
189: */
190: void M68000_CheckCpuLevel(void)
191: {
192: changed_prefs.cpu_level = ConfigureParams.System.nCpuLevel;
193: changed_prefs.cpu_compatible = ConfigureParams.System.bCompatibleCpu;
194: #ifndef UAE_NEWCPU_H
195: changed_prefs.cpu_cycle_exact = 0; // TODO
196: #endif
197: if (table68k)
198: check_prefs_changed_cpu();
199: }
200:
201:
202: /*-----------------------------------------------------------------------*/
203: /**
204: * Save/Restore snapshot of CPU variables ('MemorySnapShot_Store' handles type)
205: */
206: void M68000_MemorySnapShot_Capture(bool bSave)
207: {
208: Uint32 savepc;
209:
210: /* For the UAE CPU core: */
211: MemorySnapShot_Store(&currprefs.address_space_24,
212: sizeof(currprefs.address_space_24));
213: MemorySnapShot_Store(®s.regs[0], sizeof(regs.regs)); /* D0-D7 A0-A6 */
214:
215: if (bSave)
216: {
217: savepc = M68000_GetPC();
218: MemorySnapShot_Store(&savepc, sizeof(savepc)); /* PC */
219: }
220: else
221: {
222: MemorySnapShot_Store(&savepc, sizeof(savepc)); /* PC */
223: regs.pc = savepc;
224: #ifdef UAE_NEWCPU_H
225: regs.prefetch_pc = regs.pc + 128;
226: #endif
227: }
228:
229: #ifdef UAE_NEWCPU_H
230: MemorySnapShot_Store(®s.prefetch, sizeof(regs.prefetch)); /* prefetch */
231: #else
232: uae_u32 prefetch_dummy;
233: MemorySnapShot_Store(&prefetch_dummy, sizeof(prefetch_dummy));
234: #endif
235:
236: if (bSave)
237: {
238: #ifdef UAE_NEWCPU_H
239: MakeSR();
240: #else
241: MakeSR(®s);
242: #endif
243: if (regs.s)
244: {
245: MemorySnapShot_Store(®s.usp, sizeof(regs.usp)); /* USP */
246: MemorySnapShot_Store(®s.regs[15], sizeof(regs.regs[15])); /* ISP */
247: }
248: else
249: {
250: MemorySnapShot_Store(®s.regs[15], sizeof(regs.regs[15])); /* USP */
251: MemorySnapShot_Store(®s.isp, sizeof(regs.isp)); /* ISP */
252: }
253: MemorySnapShot_Store(®s.sr, sizeof(regs.sr)); /* SR/CCR */
254: }
255: else
256: {
257: MemorySnapShot_Store(®s.usp, sizeof(regs.usp));
258: MemorySnapShot_Store(®s.isp, sizeof(regs.isp));
259: MemorySnapShot_Store(®s.sr, sizeof(regs.sr));
260: }
261: MemorySnapShot_Store(®s.stopped, sizeof(regs.stopped));
262: MemorySnapShot_Store(®s.dfc, sizeof(regs.dfc)); /* DFC */
263: MemorySnapShot_Store(®s.sfc, sizeof(regs.sfc)); /* SFC */
264: MemorySnapShot_Store(®s.vbr, sizeof(regs.vbr)); /* VBR */
265: MemorySnapShot_Store(&caar, sizeof(caar)); /* CAAR */
266: MemorySnapShot_Store(&cacr, sizeof(cacr)); /* CACR */
267: MemorySnapShot_Store(®s.msp, sizeof(regs.msp)); /* MSP */
268:
269: if (!bSave)
270: {
271: M68000_SetPC(regs.pc);
272: /* MakeFromSR() must not swap stack pointer */
273: regs.s = (regs.sr >> 13) & 1;
274: #ifdef UAE_NEWCPU_H
275: MakeFromSR();
276: /* set stack pointer */
277: if (regs.s)
278: m68k_areg(regs, 7) = regs.isp;
279: else
280: m68k_areg(regs, 7) = regs.usp;
281: #else
282: MakeFromSR(®s);
283: /* set stack pointer */
284: if (regs.s)
285: m68k_areg(®s, 7) = regs.isp;
286: else
287: m68k_areg(®s, 7) = regs.usp;
288: #endif
289: }
290:
291: if (bSave)
292: save_fpu();
293: else
294: restore_fpu();
295: }
296:
297:
298: /*-----------------------------------------------------------------------*/
299: /**
300: * BUSERROR - Access outside valid memory range.
301: * Use bReadWrite = 0 for write errors and bReadWrite = 1 for read errors!
302: */
303: void M68000_BusError(Uint32 addr, bool bReadWrite)
304: {
305: /* FIXME: In prefetch mode, m68k_getpc() seems already to point to the next instruction */
306: // BusErrorPC = M68000_GetPC(); /* [NP] We set BusErrorPC in m68k_run_1 */
307:
308: fprintf(stderr, "M68000 Bus Error at address $%x.\n", addr);
309:
310: if ((regs.spcflags & SPCFLAG_BUSERROR) == 0) /* [NP] Check that the opcode has not already generated a read bus error */
311: {
312: BusErrorAddress = addr; /* Store for exception frame */
313: bBusErrorReadWrite = bReadWrite;
314: M68000_SetSpecial(SPCFLAG_BUSERROR); /* The exception will be done in newcpu.c */
315: }
316: }
317:
318:
319: /*-----------------------------------------------------------------------*/
320: /**
321: * Exception handler
322: */
323: void M68000_Exception(Uint32 ExceptionVector , int ExceptionSource)
324: {
325: int exceptionNr = ExceptionVector/4;
326:
327: if ((ExceptionSource == M68000_EXC_SRC_AUTOVEC)
328: && (exceptionNr>24 && exceptionNr<32)) /* 68k autovector interrupt? */
329: {
330: /* Handle autovector interrupts the UAE's way
331: * (see intlev() and do_specialties() in UAE CPU core) */
332: /* In our case, this part is only called for HBL and VBL interrupts */
333: int intnr = exceptionNr - 24;
334: pendingInterrupts |= (1 << intnr);
335: M68000_SetSpecial(SPCFLAG_INT);
336: }
337:
338: else /* MFP or direct CPU exceptions */
339: {
340: Uint16 SR;
341:
342: /* Was the CPU stopped, i.e. by a STOP instruction? */
343: if (regs.spcflags & SPCFLAG_STOP)
344: {
345: regs.stopped = 0;
346: M68000_UnsetSpecial(SPCFLAG_STOP); /* All is go,go,go! */
347: }
348:
349: /* 68k exceptions are handled by Exception() of the UAE CPU core */
350: #ifdef UAE_NEWCPU_H
351: Exception(exceptionNr, m68k_getpc(), ExceptionSource);
352: #else
353: Exception(exceptionNr, ®s, m68k_getpc(®s));
354: #endif
355:
356: SR = M68000_GetSR();
357:
358: /* Set Status Register so interrupt can ONLY be stopped by another interrupt
359: * of higher priority! */
360: SR = (SR&SR_CLEAR_IPL)|0x0600; /* DSP, level 6 */
361:
362: M68000_SetSR(SR);
363: }
364: }
365:
366:
367: /*-----------------------------------------------------------------------*/
368: /**
369: * There seem to be wait states when a program accesses certain hardware
370: * registers on the ST. Use this function to simulate these wait states.
371: * [NP] with some instructions like CLR, we have a read then a write at the
372: * same location, so we may have 2 wait states (read and write) to add
373: * (nWaitStateCycles should be reset to 0 after the cycles were added).
374: */
375: void M68000_WaitState(int nCycles)
376: {
377: M68000_SetSpecial(SPCFLAG_EXTRA_CYCLES);
378:
379: nWaitStateCycles += nCycles; /* add all the wait states for this instruction */
380: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.