|
|
1.1.1.4 root 1: /*
2: * UAE - The Un*x Amiga Emulator
3: *
4: * MC68000 emulation
5: *
6: * (c) 1995 Bernd Schmidt
7: */
8:
9: #define MMUOP_DEBUG 2
10: #define DEBUG_CD32CDTVIO 0
1.1.1.7 root 11: #define EXCEPTION3_DEBUGGER 0
12: #define CPUTRACE_DEBUG 0
13:
1.1.1.9 root 14: #define VALIDATE_68030_DATACACHE 0
15: #define VALIDATE_68040_DATACACHE 0
16: #define DISABLE_68040_COPYBACK 0
17:
1.1.1.7 root 18: #define MORE_ACCURATE_68020_PIPELINE 1
1.1.1.4 root 19:
1.1.1.8 root 20: #include <inttypes.h> /* Needed for PRIX64 */
21:
1.1.1.5 root 22: #include "main.h"
1.1.1.4 root 23: #include "compat.h"
1.1.1.7 root 24:
1.1.1.4 root 25: #include "sysconfig.h"
26: #include "sysdeps.h"
1.1.1.7 root 27:
1.1.1.4 root 28: #include "hatari-glue.h"
1.1.1.7 root 29:
1.1.1.4 root 30: #include "options_cpu.h"
31: #include "events.h"
32: #include "memory.h"
1.1.1.7 root 33: #include "custom.h"
1.1.1.4 root 34: #include "newcpu.h"
35: #include "cpummu.h"
1.1.1.5 root 36: #include "cpummu030.h"
1.1.1.4 root 37: #include "cpu_prefetch.h"
1.1.1.10! root 38: #include "debugmem.h"
1.1.1.7 root 39: #include "savestate.h"
1.1.1.9 root 40: #include "fpp.h"
1.1.1.10! root 41:
1.1.1.7 root 42: #ifdef WINUAE_FOR_HATARI
43: #include "debug.h"
44: #include "m68000.h"
1.1.1.4 root 45: #include "reset.h"
46: #include "cycInt.h"
47: #include "mfp.h"
48: #include "tos.h"
49: #include "vdi.h"
50: #include "cart.h"
51: #include "dialog.h"
52: #include "bios.h"
53: #include "xbios.h"
54: #include "screen.h"
55: #include "video.h"
56: #include "options.h"
57: #include "dsp.h"
58: #include "log.h"
59: #include "debugui.h"
60: #include "debugcpu.h"
1.1.1.5 root 61: #include "stMemory.h"
1.1.1.9 root 62: #include "blitter.h"
1.1.1.10! root 63: #endif
1.1.1.4 root 64:
65:
66: #ifdef JIT
67: #include "jit/compemu.h"
68: #include <signal.h>
69: #else
70: /* Need to have these somewhere */
1.1.1.8 root 71: //#ifndef WINUAE_FOR_HATARI
72: bool check_prefs_changed_comp (bool checkonly) { return false; }
73: //#endif
1.1.1.7 root 74: #endif
1.1.1.4 root 75:
76: /* Opcode of faulting instruction */
77: static uae_u16 last_op_for_exception_3;
78: /* PC at fault time */
79: static uaecptr last_addr_for_exception_3;
80: /* Address that generated the exception */
81: static uaecptr last_fault_for_exception_3;
82: /* read (0) or write (1) access */
1.1.1.7 root 83: static bool last_writeaccess_for_exception_3;
1.1.1.4 root 84: /* instruction (1) or data (0) access */
1.1.1.7 root 85: static bool last_instructionaccess_for_exception_3;
86: /* not instruction */
87: static bool last_notinstruction_for_exception_3;
88: /* set when writing exception stack frame */
89: static int exception_in_exception;
90:
1.1.1.4 root 91: int mmu_enabled, mmu_triggered;
92: int cpu_cycles;
1.1.1.7 root 93: int bus_error_offset;
94: #ifndef WINUAE_FOR_HATARI
1.1.1.4 root 95: static int baseclock;
1.1.1.7 root 96: #endif
97: int m68k_pc_indirect;
98: bool m68k_interrupt_delay;
99: static bool m68k_reset_delay;
1.1.1.9 root 100:
1.1.1.10! root 101: #ifndef WINUAE_FOR_HATARI
! 102: static volatile uae_atomic uae_interrupt;
! 103: static volatile uae_atomic uae_interrupts2[IRQ_SOURCE_MAX];
! 104: static volatile uae_atomic uae_interrupts6[IRQ_SOURCE_MAX];
! 105: #endif
! 106:
1.1.1.9 root 107: static int cacheisets04060, cacheisets04060mask, cacheitag04060mask;
108: static int cachedsets04060, cachedsets04060mask, cachedtag04060mask;
109:
1.1.1.7 root 110: static int cpu_prefs_changed_flag;
111:
1.1.1.4 root 112: int cpucycleunit;
1.1.1.7 root 113: int cpu_tracer;
1.1.1.4 root 114:
115: const int areg_byteinc[] = { 1, 1, 1, 1, 1, 1, 1, 2 };
116: const int imm8_table[] = { 8, 1, 2, 3, 4, 5, 6, 7 };
117:
118: int movem_index1[256];
119: int movem_index2[256];
120: int movem_next[256];
121:
122: cpuop_func *cpufunctbl[65536];
123:
1.1.1.7 root 124: struct cputbl_data
125: {
126: uae_s16 length;
127: uae_s8 disp020[2];
128: uae_u8 branch;
129: };
130: static struct cputbl_data cpudatatbl[65536];
1.1.1.5 root 131:
1.1.1.4 root 132: struct mmufixup mmufixup[2];
133:
134: #define COUNT_INSTRS 0
135: #define MC68060_PCR 0x04300000
136: #define MC68EC060_PCR 0x04310000
137:
1.1.1.7 root 138: static uae_u64 fake_srp_030, fake_crp_030;
139: static uae_u32 fake_tt0_030, fake_tt1_030, fake_tc_030;
140: static uae_u16 fake_mmusr_030;
1.1.1.4 root 141:
142: static struct cache020 caches020[CACHELINES020];
143: static struct cache030 icaches030[CACHELINES030];
144: static struct cache030 dcaches030[CACHELINES030];
1.1.1.9 root 145: static int icachelinecnt, icachehalfline;
146: static int dcachelinecnt;
147: static struct cache040 icaches040[CACHESETS060];
148: static struct cache040 dcaches040[CACHESETS060];
149: static int cache_lastline;
1.1.1.7 root 150:
1.1.1.8 root 151: static int fallback_cpu_model, fallback_mmu_model, fallback_fpu_model;
1.1.1.9 root 152: static bool fallback_cpu_compatible, fallback_cpu_address_space_24;
1.1.1.8 root 153: static struct regstruct fallback_regs;
154: static int fallback_new_cpu_model;
1.1.1.7 root 155:
156: #ifdef WINUAE_FOR_HATARI
157: int OpcodeFamily;
158: int BusCyclePenalty = 0;
1.1.1.4 root 159:
1.1.1.7 root 160: FILE *console_out_FILE = NULL;
1.1.1.9 root 161:
1.1.1.10! root 162: int quit_program = 0; /* from main.cpp */
1.1.1.7 root 163: #endif
1.1.1.4 root 164:
165:
166: #if COUNT_INSTRS
167: static unsigned long int instrcount[65536];
168: static uae_u16 opcodenums[65536];
169:
170: static int compfn (const void *el1, const void *el2)
171: {
172: return instrcount[*(const uae_u16 *)el1] < instrcount[*(const uae_u16 *)el2];
173: }
174:
175: static TCHAR *icountfilename (void)
176: {
177: TCHAR *name = getenv ("INSNCOUNT");
178: if (name)
179: return name;
180: return COUNT_INSTRS == 2 ? "frequent.68k" : "insncount";
181: }
182:
183: void dump_counts (void)
184: {
185: FILE *f = fopen (icountfilename (), "w");
186: unsigned long int total;
187: int i;
188:
1.1.1.7 root 189: write_log (_T("Writing instruction count file...\n"));
1.1.1.4 root 190: for (i = 0; i < 65536; i++) {
191: opcodenums[i] = i;
192: total += instrcount[i];
193: }
194: qsort (opcodenums, 65536, sizeof (uae_u16), compfn);
195:
196: fprintf (f, "Total: %lu\n", total);
197: for (i=0; i < 65536; i++) {
198: unsigned long int cnt = instrcount[opcodenums[i]];
199: struct instr *dp;
200: struct mnemolookup *lookup;
201: if (!cnt)
202: break;
203: dp = table68k + opcodenums[i];
204: for (lookup = lookuptab;lookup->mnemo != dp->mnemo; lookup++)
205: ;
206: fprintf (f, "%04x: %lu %s\n", opcodenums[i], cnt, lookup->name);
207: }
208: fclose (f);
209: }
210: #else
211: void dump_counts (void)
212: {
213: }
214: #endif
215:
1.1.1.7 root 216: /*
217:
218: ok, all this to "record" current instruction state
219: for later 100% cycle-exact restoring
220:
221: */
222:
223: static uae_u32 (*x2_prefetch)(int);
224: static uae_u32 (*x2_prefetch_long)(int);
225: static uae_u32 (*x2_next_iword)(void);
226: static uae_u32 (*x2_next_ilong)(void);
227: static uae_u32 (*x2_get_ilong)(int);
228: static uae_u32 (*x2_get_iword)(int);
229: static uae_u32 (*x2_get_ibyte)(int);
230: static uae_u32 (*x2_get_long)(uaecptr);
231: static uae_u32 (*x2_get_word)(uaecptr);
232: static uae_u32 (*x2_get_byte)(uaecptr);
233: static void (*x2_put_long)(uaecptr,uae_u32);
234: static void (*x2_put_word)(uaecptr,uae_u32);
235: static void (*x2_put_byte)(uaecptr,uae_u32);
236: static void (*x2_do_cycles)(unsigned long);
237: static void (*x2_do_cycles_pre)(unsigned long);
238: static void (*x2_do_cycles_post)(unsigned long, uae_u32);
1.1.1.4 root 239:
240: uae_u32 (*x_prefetch)(int);
241: uae_u32 (*x_next_iword)(void);
242: uae_u32 (*x_next_ilong)(void);
1.1.1.7 root 243: uae_u32 (*x_get_ilong)(int);
244: uae_u32 (*x_get_iword)(int);
245: uae_u32 (*x_get_ibyte)(int);
1.1.1.4 root 246: uae_u32 (*x_get_long)(uaecptr);
247: uae_u32 (*x_get_word)(uaecptr);
248: uae_u32 (*x_get_byte)(uaecptr);
249: void (*x_put_long)(uaecptr,uae_u32);
250: void (*x_put_word)(uaecptr,uae_u32);
251: void (*x_put_byte)(uaecptr,uae_u32);
252:
1.1.1.7 root 253: uae_u32 (*x_cp_next_iword)(void);
254: uae_u32 (*x_cp_next_ilong)(void);
255: uae_u32 (*x_cp_get_long)(uaecptr);
256: uae_u32 (*x_cp_get_word)(uaecptr);
257: uae_u32 (*x_cp_get_byte)(uaecptr);
258: void (*x_cp_put_long)(uaecptr,uae_u32);
259: void (*x_cp_put_word)(uaecptr,uae_u32);
260: void (*x_cp_put_byte)(uaecptr,uae_u32);
261: uae_u32 (REGPARAM3 *x_cp_get_disp_ea_020)(uae_u32 base, int idx) REGPARAM;
262:
263: void (*x_do_cycles)(unsigned long);
264: void (*x_do_cycles_pre)(unsigned long);
265: void (*x_do_cycles_post)(unsigned long, uae_u32);
266:
267: uae_u32(*x_phys_get_iword)(uaecptr);
268: uae_u32(*x_phys_get_ilong)(uaecptr);
269: uae_u32(*x_phys_get_byte)(uaecptr);
270: uae_u32(*x_phys_get_word)(uaecptr);
271: uae_u32(*x_phys_get_long)(uaecptr);
272: void(*x_phys_put_byte)(uaecptr, uae_u32);
273: void(*x_phys_put_word)(uaecptr, uae_u32);
274: void(*x_phys_put_long)(uaecptr, uae_u32);
275:
276: static void set_x_cp_funcs(void)
277: {
278: x_cp_put_long = x_put_long;
279: x_cp_put_word = x_put_word;
280: x_cp_put_byte = x_put_byte;
281: x_cp_get_long = x_get_long;
282: x_cp_get_word = x_get_word;
283: x_cp_get_byte = x_get_byte;
284: x_cp_next_iword = x_next_iword;
285: x_cp_next_ilong = x_next_ilong;
286: x_cp_get_disp_ea_020 = x_get_disp_ea_020;
287:
288: if (currprefs.mmu_model == 68030) {
1.1.1.9 root 289: if (currprefs.cpu_compatible) {
290: x_cp_put_long = put_long_mmu030c_state;
291: x_cp_put_word = put_word_mmu030c_state;
292: x_cp_put_byte = put_byte_mmu030c_state;
293: x_cp_get_long = get_long_mmu030c_state;
294: x_cp_get_word = get_word_mmu030c_state;
295: x_cp_get_byte = get_byte_mmu030c_state;
296: x_cp_next_iword = next_iword_mmu030c_state;
297: x_cp_next_ilong = next_ilong_mmu030c_state;
298: x_cp_get_disp_ea_020 = get_disp_ea_020_mmu030c;
299: } else {
300: x_cp_put_long = put_long_mmu030_state;
301: x_cp_put_word = put_word_mmu030_state;
302: x_cp_put_byte = put_byte_mmu030_state;
303: x_cp_get_long = get_long_mmu030_state;
304: x_cp_get_word = get_word_mmu030_state;
305: x_cp_get_byte = get_byte_mmu030_state;
306: x_cp_next_iword = next_iword_mmu030_state;
307: x_cp_next_ilong = next_ilong_mmu030_state;
308: x_cp_get_disp_ea_020 = get_disp_ea_020_mmu030;
309: }
1.1.1.7 root 310: }
311: }
312:
313: static struct cputracestruct cputrace;
314:
315: #if CPUTRACE_DEBUG
316: static void validate_trace (void)
317: {
318: for (int i = 0; i < cputrace.memoryoffset; i++) {
319: struct cputracememory *ctm = &cputrace.ctm[i];
320: if (ctm->data == 0xdeadf00d) {
321: write_log (_T("unfinished write operation %d %08x\n"), i, ctm->addr);
322: }
323: }
324: }
325: #endif
326:
327: static void debug_trace (void)
328: {
329: if (cputrace.writecounter > 10000 || cputrace.readcounter > 10000)
330: write_log (_T("cputrace.readcounter=%d cputrace.writecounter=%d\n"), cputrace.readcounter, cputrace.writecounter);
331: }
332:
333: STATIC_INLINE void clear_trace (void)
334: {
335: #if CPUTRACE_DEBUG
336: validate_trace ();
337: #endif
1.1.1.9 root 338: if (cputrace.memoryoffset == MAX_CPUTRACESIZE)
339: return;
1.1.1.7 root 340: struct cputracememory *ctm = &cputrace.ctm[cputrace.memoryoffset++];
1.1.1.9 root 341: if (cputrace.memoryoffset == MAX_CPUTRACESIZE) {
342: write_log(_T("CPUTRACE overflow, stopping tracing.\n"));
343: return;
344: }
1.1.1.7 root 345: ctm->mode = 0;
346: cputrace.cyclecounter = 0;
347: cputrace.cyclecounter_pre = cputrace.cyclecounter_post = 0;
348: }
349: static void set_trace (uaecptr addr, int accessmode, int size)
350: {
351: #if CPUTRACE_DEBUG
352: validate_trace ();
353: #endif
1.1.1.9 root 354: if (cputrace.memoryoffset == MAX_CPUTRACESIZE)
355: return;
1.1.1.7 root 356: struct cputracememory *ctm = &cputrace.ctm[cputrace.memoryoffset++];
1.1.1.9 root 357: if (cputrace.memoryoffset == MAX_CPUTRACESIZE) {
358: write_log(_T("CPUTRACE overflow, stopping tracing.\n"));
359: return;
360: }
1.1.1.7 root 361: ctm->addr = addr;
362: ctm->data = 0xdeadf00d;
363: ctm->mode = accessmode | (size << 4);
364: cputrace.cyclecounter_pre = -1;
365: if (accessmode == 1)
366: cputrace.writecounter++;
367: else
368: cputrace.readcounter++;
369: debug_trace ();
370: }
371: static void add_trace (uaecptr addr, uae_u32 val, int accessmode, int size)
372: {
373: if (cputrace.memoryoffset < 1) {
374: #if CPUTRACE_DEBUG
375: write_log (_T("add_trace memoryoffset=%d!\n"), cputrace.memoryoffset);
376: #endif
377: return;
378: }
379: int mode = accessmode | (size << 4);
380: struct cputracememory *ctm = &cputrace.ctm[cputrace.memoryoffset - 1];
381: ctm->addr = addr;
382: ctm->data = val;
383: if (!ctm->mode) {
384: ctm->mode = mode;
385: if (accessmode == 1)
386: cputrace.writecounter++;
387: else
388: cputrace.readcounter++;
389: }
390: debug_trace ();
391: cputrace.cyclecounter_pre = cputrace.cyclecounter_post = 0;
392: }
393:
394:
395: static void check_trace2 (void)
396: {
397: if (cputrace.readcounter || cputrace.writecounter ||
398: cputrace.cyclecounter || cputrace.cyclecounter_pre || cputrace.cyclecounter_post)
399: write_log (_T("CPU tracer invalid state during playback!\n"));
400: }
401:
402: static bool check_trace (void)
403: {
404: if (!cpu_tracer)
405: return true;
406: if (!cputrace.readcounter && !cputrace.writecounter && !cputrace.cyclecounter) {
407: if (cpu_tracer != -2) {
408: write_log (_T("CPU trace: dma_cycle() enabled. %08x %08x NOW=%08lx\n"),
409: cputrace.cyclecounter_pre, cputrace.cyclecounter_post, get_cycles ());
410: cpu_tracer = -2; // dma_cycle() allowed to work now
411: }
412: }
413: if (cputrace.readcounter || cputrace.writecounter ||
414: cputrace.cyclecounter || cputrace.cyclecounter_pre || cputrace.cyclecounter_post)
415: return false;
416: x_prefetch = x2_prefetch;
417: x_get_ilong = x2_get_ilong;
418: x_get_iword = x2_get_iword;
419: x_get_ibyte = x2_get_ibyte;
420: x_next_iword = x2_next_iword;
421: x_next_ilong = x2_next_ilong;
422: x_put_long = x2_put_long;
423: x_put_word = x2_put_word;
424: x_put_byte = x2_put_byte;
425: x_get_long = x2_get_long;
426: x_get_word = x2_get_word;
427: x_get_byte = x2_get_byte;
428: x_do_cycles = x2_do_cycles;
429: x_do_cycles_pre = x2_do_cycles_pre;
430: x_do_cycles_post = x2_do_cycles_post;
431: set_x_cp_funcs();
432: write_log (_T("CPU tracer playback complete. STARTCYCLES=%08x NOWCYCLES=%08lx\n"), cputrace.startcycles, get_cycles ());
433: cputrace.needendcycles = 1;
434: cpu_tracer = 0;
435: return true;
436: }
437:
438: static bool get_trace (uaecptr addr, int accessmode, int size, uae_u32 *data)
439: {
440: int mode = accessmode | (size << 4);
1.1.1.10! root 441: for (int i = 0; i < cputrace.memoryoffset; i++) {
1.1.1.7 root 442: struct cputracememory *ctm = &cputrace.ctm[i];
443: if (ctm->addr == addr && ctm->mode == mode) {
444: ctm->mode = 0;
445: write_log (_T("CPU trace: GET %d: PC=%08x %08x=%08x %d %d %08x/%08x/%08x %d/%d (%08lx)\n"),
446: i, cputrace.pc, addr, ctm->data, accessmode, size,
447: cputrace.cyclecounter, cputrace.cyclecounter_pre, cputrace.cyclecounter_post,
448: cputrace.readcounter, cputrace.writecounter, get_cycles ());
449: if (accessmode == 1)
450: cputrace.writecounter--;
451: else
452: cputrace.readcounter--;
453: if (cputrace.writecounter == 0 && cputrace.readcounter == 0) {
454: if (cputrace.cyclecounter_post) {
455: int c = cputrace.cyclecounter_post;
456: cputrace.cyclecounter_post = 0;
457: x_do_cycles (c);
458: } else if (cputrace.cyclecounter_pre) {
459: check_trace ();
460: *data = ctm->data;
461: return true; // argh, need to rerun the memory access..
462: }
463: }
464: check_trace ();
465: *data = ctm->data;
466: return false;
467: }
468: }
469: if (cputrace.cyclecounter_post) {
470: int c = cputrace.cyclecounter_post;
471: cputrace.cyclecounter_post = 0;
472: check_trace ();
473: check_trace2 ();
474: x_do_cycles (c);
475: return false;
476: }
477: gui_message (_T("CPU trace: GET %08x %d %d NOT FOUND!\n"), addr, accessmode, size);
478: check_trace ();
479: *data = 0;
480: return false;
481: }
482:
483: static uae_u32 cputracefunc_x_prefetch (int o)
484: {
485: uae_u32 pc = m68k_getpc ();
486: set_trace (pc + o, 2, 2);
487: uae_u32 v = x2_prefetch (o);
488: add_trace (pc + o, v, 2, 2);
489: return v;
490: }
491: static uae_u32 cputracefunc2_x_prefetch (int o)
492: {
493: uae_u32 v;
494: if (get_trace (m68k_getpc () + o, 2, 2, &v)) {
495: v = x2_prefetch (o);
496: check_trace2 ();
497: }
498: return v;
499: }
500:
501: static uae_u32 cputracefunc_x_next_iword (void)
502: {
503: uae_u32 pc = m68k_getpc ();
504: set_trace (pc, 2, 2);
505: uae_u32 v = x2_next_iword ();
506: add_trace (pc, v, 2, 2);
507: return v;
508: }
509: static uae_u32 cputracefunc_x_next_ilong (void)
510: {
511: uae_u32 pc = m68k_getpc ();
512: set_trace (pc, 2, 4);
513: uae_u32 v = x2_next_ilong ();
514: add_trace (pc, v, 2, 4);
515: return v;
516: }
517: static uae_u32 cputracefunc2_x_next_iword (void)
518: {
519: uae_u32 v;
520: if (get_trace (m68k_getpc (), 2, 2, &v)) {
521: v = x2_next_iword ();
522: check_trace2 ();
523: }
524: return v;
525: }
526: static uae_u32 cputracefunc2_x_next_ilong (void)
527: {
528: uae_u32 v;
529: if (get_trace (m68k_getpc (), 2, 4, &v)) {
530: v = x2_next_ilong ();
531: check_trace2 ();
532: }
533: return v;
534: }
535:
536: static uae_u32 cputracefunc_x_get_ilong (int o)
537: {
538: uae_u32 pc = m68k_getpc ();
539: set_trace (pc + o, 2, 4);
540: uae_u32 v = x2_get_ilong (o);
541: add_trace (pc + o, v, 2, 4);
542: return v;
543: }
544: static uae_u32 cputracefunc_x_get_iword (int o)
545: {
546: uae_u32 pc = m68k_getpc ();
547: set_trace (pc + o, 2, 2);
548: uae_u32 v = x2_get_iword (o);
549: add_trace (pc + o, v, 2, 2);
550: return v;
551: }
552: static uae_u32 cputracefunc_x_get_ibyte (int o)
553: {
554: uae_u32 pc = m68k_getpc ();
555: set_trace (pc + o, 2, 1);
556: uae_u32 v = x2_get_ibyte (o);
557: add_trace (pc + o, v, 2, 1);
558: return v;
559: }
560: static uae_u32 cputracefunc2_x_get_ilong (int o)
561: {
562: uae_u32 v;
563: if (get_trace (m68k_getpc () + o, 2, 4, &v)) {
564: v = x2_get_ilong (o);
565: check_trace2 ();
566: }
567: return v;
568: }
569: static uae_u32 cputracefunc2_x_get_iword (int o)
570: {
571: uae_u32 v;
572: if (get_trace (m68k_getpc () + o, 2, 2, &v)) {
573: v = x2_get_iword (o);
574: check_trace2 ();
575: }
576: return v;
577: }
578: static uae_u32 cputracefunc2_x_get_ibyte (int o)
579: {
580: uae_u32 v;
581: if (get_trace (m68k_getpc () + o, 2, 1, &v)) {
582: v = x2_get_ibyte (o);
583: check_trace2 ();
584: }
585: return v;
586: }
587:
588: static uae_u32 cputracefunc_x_get_long (uaecptr o)
589: {
590: set_trace (o, 0, 4);
591: uae_u32 v = x2_get_long (o);
592: add_trace (o, v, 0, 4);
593: return v;
594: }
595: static uae_u32 cputracefunc_x_get_word (uaecptr o)
596: {
597: set_trace (o, 0, 2);
598: uae_u32 v = x2_get_word (o);
599: add_trace (o, v, 0, 2);
600: return v;
601: }
602: static uae_u32 cputracefunc_x_get_byte (uaecptr o)
603: {
604: set_trace (o, 0, 1);
605: uae_u32 v = x2_get_byte (o);
606: add_trace (o, v, 0, 1);
607: return v;
608: }
609: static uae_u32 cputracefunc2_x_get_long (uaecptr o)
610: {
611: uae_u32 v;
612: if (get_trace (o, 0, 4, &v)) {
613: v = x2_get_long (o);
614: check_trace2 ();
615: }
616: return v;
617: }
618: static uae_u32 cputracefunc2_x_get_word (uaecptr o)
619: {
620: uae_u32 v;
621: if (get_trace (o, 0, 2, &v)) {
622: v = x2_get_word (o);
623: check_trace2 ();
624: }
625: return v;
626: }
627: static uae_u32 cputracefunc2_x_get_byte (uaecptr o)
628: {
629: uae_u32 v;
630: if (get_trace (o, 0, 1, &v)) {
631: v = x2_get_byte (o);
632: check_trace2 ();
633: }
634: return v;
635: }
636:
637: static void cputracefunc_x_put_long (uaecptr o, uae_u32 val)
638: {
639: clear_trace ();
640: add_trace (o, val, 1, 4);
641: x2_put_long (o, val);
642: }
643: static void cputracefunc_x_put_word (uaecptr o, uae_u32 val)
644: {
645: clear_trace ();
646: add_trace (o, val, 1, 2);
647: x2_put_word (o, val);
648: }
649: static void cputracefunc_x_put_byte (uaecptr o, uae_u32 val)
650: {
651: clear_trace ();
652: add_trace (o, val, 1, 1);
653: x2_put_byte (o, val);
654: }
655: static void cputracefunc2_x_put_long (uaecptr o, uae_u32 val)
656: {
657: uae_u32 v;
658: if (get_trace (o, 1, 4, &v)) {
659: x2_put_long (o, val);
660: check_trace2 ();
661: }
662: if (v != val)
663: write_log (_T("cputracefunc2_x_put_long %d <> %d\n"), v, val);
664: }
665: static void cputracefunc2_x_put_word (uaecptr o, uae_u32 val)
666: {
667: uae_u32 v;
668: if (get_trace (o, 1, 2, &v)) {
669: x2_put_word (o, val);
670: check_trace2 ();
671: }
672: if (v != val)
673: write_log (_T("cputracefunc2_x_put_word %d <> %d\n"), v, val);
674: }
675: static void cputracefunc2_x_put_byte (uaecptr o, uae_u32 val)
676: {
677: uae_u32 v;
678: if (get_trace (o, 1, 1, &v)) {
679: x2_put_byte (o, val);
680: check_trace2 ();
681: }
682: if (v != val)
683: write_log (_T("cputracefunc2_x_put_byte %d <> %d\n"), v, val);
684: }
685:
686: static void cputracefunc_x_do_cycles (unsigned long cycles)
687: {
688: while (cycles >= CYCLE_UNIT) {
689: cputrace.cyclecounter += CYCLE_UNIT;
690: cycles -= CYCLE_UNIT;
691: x2_do_cycles (CYCLE_UNIT);
692: }
693: if (cycles > 0) {
694: cputrace.cyclecounter += cycles;
695: x2_do_cycles (cycles);
696: }
697: }
698:
699: static void cputracefunc2_x_do_cycles (unsigned long cycles)
700: {
701: if (cputrace.cyclecounter > (long)cycles) {
702: cputrace.cyclecounter -= cycles;
703: return;
704: }
705: cycles -= cputrace.cyclecounter;
706: cputrace.cyclecounter = 0;
707: check_trace ();
708: x_do_cycles = x2_do_cycles;
709: if (cycles > 0)
710: x_do_cycles (cycles);
711: }
712:
713: static void cputracefunc_x_do_cycles_pre (unsigned long cycles)
714: {
715: cputrace.cyclecounter_post = 0;
716: cputrace.cyclecounter_pre = 0;
717: while (cycles >= CYCLE_UNIT) {
718: cycles -= CYCLE_UNIT;
719: cputrace.cyclecounter_pre += CYCLE_UNIT;
720: x2_do_cycles (CYCLE_UNIT);
721: }
722: if (cycles > 0) {
723: x2_do_cycles (cycles);
724: cputrace.cyclecounter_pre += cycles;
725: }
726: cputrace.cyclecounter_pre = 0;
727: }
728: // cyclecounter_pre = how many cycles we need to SWALLOW
729: // -1 = rerun whole access
730: static void cputracefunc2_x_do_cycles_pre (unsigned long cycles)
731: {
732: if (cputrace.cyclecounter_pre == -1) {
733: cputrace.cyclecounter_pre = 0;
734: check_trace ();
735: check_trace2 ();
736: x_do_cycles (cycles);
737: return;
738: }
739: if (cputrace.cyclecounter_pre > (long)cycles) {
740: cputrace.cyclecounter_pre -= cycles;
741: return;
742: }
743: cycles -= cputrace.cyclecounter_pre;
744: cputrace.cyclecounter_pre = 0;
745: check_trace ();
746: if (cycles > 0)
747: x_do_cycles (cycles);
748: }
749:
750: static void cputracefunc_x_do_cycles_post (unsigned long cycles, uae_u32 v)
751: {
752: if (cputrace.memoryoffset < 1) {
753: #if CPUTRACE_DEBUG
754: write_log (_T("cputracefunc_x_do_cycles_post memoryoffset=%d!\n"), cputrace.memoryoffset);
755: #endif
756: return;
757: }
758: struct cputracememory *ctm = &cputrace.ctm[cputrace.memoryoffset - 1];
759: ctm->data = v;
760: cputrace.cyclecounter_post = cycles;
761: cputrace.cyclecounter_pre = 0;
762: while (cycles >= CYCLE_UNIT) {
763: cycles -= CYCLE_UNIT;
764: cputrace.cyclecounter_post -= CYCLE_UNIT;
765: x2_do_cycles (CYCLE_UNIT);
766: }
767: if (cycles > 0) {
768: cputrace.cyclecounter_post -= cycles;
769: x2_do_cycles (cycles);
770: }
771: cputrace.cyclecounter_post = 0;
772: }
773: // cyclecounter_post = how many cycles we need to WAIT
774: static void cputracefunc2_x_do_cycles_post (unsigned long cycles, uae_u32 v)
775: {
776: uae_u32 c;
777: if (cputrace.cyclecounter_post) {
778: c = cputrace.cyclecounter_post;
779: cputrace.cyclecounter_post = 0;
780: } else {
781: c = cycles;
782: }
783: check_trace ();
784: if (c > 0)
785: x_do_cycles (c);
786: }
787:
788: static void do_cycles_post (unsigned long cycles, uae_u32 v)
789: {
790: do_cycles (cycles);
791: }
792: static void do_cycles_ce_post (unsigned long cycles, uae_u32 v)
793: {
794: do_cycles_ce (cycles);
795: }
796: static void do_cycles_ce020_post (unsigned long cycles, uae_u32 v)
797: {
798: #ifndef WINUAE_FOR_HATARI
799: do_cycles_ce020 (cycles);
800: #else
801: do_cycles_ce020_long (cycles);
802: #endif
803: }
804:
1.1.1.9 root 805: static uae_u8 dcache_check_nommu(uaecptr addr, bool write, uae_u32 size)
806: {
807: return ce_cachable[addr >> 16];
808: }
809:
810: static void mem_access_delay_long_write_ce030_cicheck(uaecptr addr, uae_u32 v)
811: {
812: mem_access_delay_long_write_ce020(addr, v);
813: mmu030_cache_state = ce_cachable[addr >> 16];
814: }
815: static void mem_access_delay_word_write_ce030_cicheck(uaecptr addr, uae_u32 v)
816: {
817: mem_access_delay_word_write_ce020(addr, v);
818: mmu030_cache_state = ce_cachable[addr >> 16];
819: }
820: static void mem_access_delay_byte_write_ce030_cicheck(uaecptr addr, uae_u32 v)
821: {
822: mem_access_delay_byte_write_ce020(addr, v);
823: mmu030_cache_state = ce_cachable[addr >> 16];
824: }
825:
826: static void put_long030_cicheck(uaecptr addr, uae_u32 v)
827: {
828: put_long(addr, v);
829: mmu030_cache_state = ce_cachable[addr >> 16];
830: }
831: static void put_word030_cicheck(uaecptr addr, uae_u32 v)
832: {
833: put_word(addr, v);
834: mmu030_cache_state = ce_cachable[addr >> 16];
835: }
836: static void put_byte030_cicheck(uaecptr addr, uae_u32 v)
837: {
838: put_byte(addr, v);
839: mmu030_cache_state = ce_cachable[addr >> 16];
840: }
841:
842: static uae_u32 (*icache_fetch)(uaecptr);
843: static uae_u32 (*dcache_lget)(uaecptr);
844: static uae_u32 (*dcache_wget)(uaecptr);
845: static uae_u32 (*dcache_bget)(uaecptr);
846: static uae_u8 (*dcache_check)(uaecptr, bool, uae_u32);
847: static void (*dcache_lput)(uaecptr, uae_u32);
848: static void (*dcache_wput)(uaecptr, uae_u32);
849: static void (*dcache_bput)(uaecptr, uae_u32);
850:
851: uae_u32(*read_data_030_bget)(uaecptr);
852: uae_u32(*read_data_030_wget)(uaecptr);
853: uae_u32(*read_data_030_lget)(uaecptr);
854: void(*write_data_030_bput)(uaecptr,uae_u32);
855: void(*write_data_030_wput)(uaecptr,uae_u32);
856: void(*write_data_030_lput)(uaecptr,uae_u32);
857:
858: uae_u32(*read_data_030_fc_bget)(uaecptr, uae_u32);
859: uae_u32(*read_data_030_fc_wget)(uaecptr, uae_u32);
860: uae_u32(*read_data_030_fc_lget)(uaecptr, uae_u32);
861: void(*write_data_030_fc_bput)(uaecptr, uae_u32, uae_u32);
862: void(*write_data_030_fc_wput)(uaecptr, uae_u32, uae_u32);
863: void(*write_data_030_fc_lput)(uaecptr, uae_u32, uae_u32);
864:
865:
866: static void set_x_ifetches(void)
1.1.1.7 root 867: {
868: if (m68k_pc_indirect) {
869: if (currprefs.cachesize) {
870: // indirect via addrbank
871: x_get_ilong = get_iilong_jit;
872: x_get_iword = get_iiword_jit;
873: x_get_ibyte = get_iibyte_jit;
874: x_next_iword = next_iiword_jit;
875: x_next_ilong = next_iilong_jit;
876: } else {
877: // indirect via addrbank
878: x_get_ilong = get_iilong;
879: x_get_iword = get_iiword;
880: x_get_ibyte = get_iibyte;
881: x_next_iword = next_iiword;
882: x_next_ilong = next_iilong;
883: }
884: } else {
885: // direct to memory
886: x_get_ilong = get_dilong;
887: x_get_iword = get_diword;
888: x_get_ibyte = get_dibyte;
889: x_next_iword = next_diword;
890: x_next_ilong = next_dilong;
891: }
892: }
893:
1.1.1.9 root 894:
895: #ifdef WINUAE_FOR_HATARI
896:
897: void (*x_do_cycles_hatari_blitter_save)(unsigned long);
898: void (*x_do_cycles_pre_hatari_blitter_save)(unsigned long);
899: void (*x_do_cycles_post_hatari_blitter_save)(unsigned long, uae_u32);
900:
901: static void do_cycles_ce_post_hatari_blitter (unsigned long cycles, uae_u32 v)
902: {
903: do_cycles_ce_hatari_blitter (cycles);
904: }
905:
906: void set_x_funcs_hatari_blitter (int flag)
907: {
908: if ( flag == 0 )
909: {
910: //fprintf ( stderr , "restore blitter x_funcs\n" );
911: /* disable blitter, restore functions if needed */
912: if ( x_do_cycles_hatari_blitter_save )
913: {
914: x_do_cycles = x_do_cycles_hatari_blitter_save;
915: x_do_cycles_pre = x_do_cycles_pre_hatari_blitter_save;
916: x_do_cycles_post = x_do_cycles_post_hatari_blitter_save;
917: }
918: }
919: else
920: {
921: //fprintf ( stderr , "save/set blitter x_funcs\n" );
922: /* save current functions */
923: x_do_cycles_hatari_blitter_save = x_do_cycles;
924: x_do_cycles_pre_hatari_blitter_save = x_do_cycles_pre;
925: x_do_cycles_post_hatari_blitter_save = x_do_cycles_post;
926:
927: /* set blitter specific functions */
928: x_do_cycles = do_cycles_ce_hatari_blitter;
929: x_do_cycles_pre = do_cycles_ce_hatari_blitter;
930: x_do_cycles_post = do_cycles_ce_post_hatari_blitter;
931: }
932: }
933:
934: #endif
935:
1.1.1.7 root 936: // indirect memory access functions
1.1.1.4 root 937: static void set_x_funcs (void)
938: {
1.1.1.7 root 939: if (currprefs.mmu_model) {
940: if (currprefs.cpu_model == 68060) {
1.1.1.9 root 941:
1.1.1.7 root 942: x_prefetch = get_iword_mmu060;
943: x_get_ilong = get_ilong_mmu060;
944: x_get_iword = get_iword_mmu060;
945: x_get_ibyte = get_ibyte_mmu060;
946: x_next_iword = next_iword_mmu060;
947: x_next_ilong = next_ilong_mmu060;
948: x_put_long = put_long_mmu060;
949: x_put_word = put_word_mmu060;
950: x_put_byte = put_byte_mmu060;
951: x_get_long = get_long_mmu060;
952: x_get_word = get_word_mmu060;
953: x_get_byte = get_byte_mmu060;
1.1.1.9 root 954:
1.1.1.7 root 955: } else if (currprefs.cpu_model == 68040) {
1.1.1.9 root 956:
1.1.1.7 root 957: x_prefetch = get_iword_mmu040;
958: x_get_ilong = get_ilong_mmu040;
959: x_get_iword = get_iword_mmu040;
960: x_get_ibyte = get_ibyte_mmu040;
961: x_next_iword = next_iword_mmu040;
962: x_next_ilong = next_ilong_mmu040;
963: x_put_long = put_long_mmu040;
964: x_put_word = put_word_mmu040;
965: x_put_byte = put_byte_mmu040;
966: x_get_long = get_long_mmu040;
967: x_get_word = get_word_mmu040;
968: x_get_byte = get_byte_mmu040;
1.1.1.9 root 969:
1.1.1.7 root 970: } else {
1.1.1.9 root 971:
972: if (currprefs.cpu_memory_cycle_exact) {
973: x_prefetch = get_iword_mmu030c_state;
974: x_get_ilong = get_ilong_mmu030c_state;
975: x_get_iword = get_iword_mmu030c_state;
976: x_get_ibyte = NULL;
977: x_next_iword = next_iword_mmu030c_state;
978: x_next_ilong = next_ilong_mmu030c_state;
979: x_do_cycles = do_cycles;
980: x_do_cycles_pre = do_cycles;
981: x_do_cycles_post = do_cycles_post;
982: } else if (currprefs.cpu_compatible) {
983: x_prefetch = get_iword_mmu030c_state;
984: x_get_ilong = get_ilong_mmu030c_state;
985: x_get_iword = get_iword_mmu030c_state;
986: x_get_ibyte = NULL;
987: x_next_iword = next_iword_mmu030c_state;
988: x_next_ilong = next_ilong_mmu030c_state;
989: x_do_cycles = do_cycles;
990: x_do_cycles_pre = do_cycles;
991: x_do_cycles_post = do_cycles_post;
992: } else {
993: x_prefetch = get_iword_mmu030;
994: x_get_ilong = get_ilong_mmu030;
995: x_get_iword = get_iword_mmu030;
996: x_get_ibyte = get_ibyte_mmu030;
997: x_next_iword = next_iword_mmu030;
998: x_next_ilong = next_ilong_mmu030;
999: }
1.1.1.7 root 1000: x_put_long = put_long_mmu030;
1001: x_put_word = put_word_mmu030;
1002: x_put_byte = put_byte_mmu030;
1003: x_get_long = get_long_mmu030;
1004: x_get_word = get_word_mmu030;
1005: x_get_byte = get_byte_mmu030;
1.1.1.9 root 1006: if (currprefs.cpu_data_cache) {
1007: x_put_long = put_long_dc030;
1008: x_put_word = put_word_dc030;
1009: x_put_byte = put_byte_dc030;
1010: x_get_long = get_long_dc030;
1011: x_get_word = get_word_dc030;
1012: x_get_byte = get_byte_dc030;
1013: }
1014:
1.1.1.7 root 1015: }
1016: x_do_cycles = do_cycles;
1017: x_do_cycles_pre = do_cycles;
1018: x_do_cycles_post = do_cycles_post;
1.1.1.4 root 1019: } else if (currprefs.cpu_model < 68020) {
1.1.1.7 root 1020: // 68000/010
1021: if (currprefs.cpu_cycle_exact) {
1022: x_prefetch = get_word_ce000_prefetch;
1023: x_get_ilong = NULL;
1024: x_get_iword = get_wordi_ce000;
1025: x_get_ibyte = NULL;
1026: x_next_iword = NULL;
1027: x_next_ilong = NULL;
1028: x_put_long = put_long_ce000;
1029: x_put_word = put_word_ce000;
1030: x_put_byte = put_byte_ce000;
1031: x_get_long = get_long_ce000;
1032: x_get_word = get_word_ce000;
1033: x_get_byte = get_byte_ce000;
1034: x_do_cycles = do_cycles_ce;
1035: x_do_cycles_pre = do_cycles_ce;
1036: x_do_cycles_post = do_cycles_ce_post;
1.1.1.8 root 1037: } else if (currprefs.cpu_memory_cycle_exact) {
1038: // cpu_memory_cycle_exact + cpu_compatible
1039: x_prefetch = get_word_000_prefetch;
1040: x_get_ilong = NULL;
1041: x_get_iword = get_iiword;
1042: x_get_ibyte = get_iibyte;
1043: x_next_iword = NULL;
1044: x_next_ilong = NULL;
1045: x_put_long = put_long_ce000;
1046: x_put_word = put_word_ce000;
1047: x_put_byte = put_byte_ce000;
1048: x_get_long = get_long_ce000;
1049: x_get_word = get_word_ce000;
1050: x_get_byte = get_byte_ce000;
1051: x_do_cycles = do_cycles;
1052: x_do_cycles_pre = do_cycles;
1053: x_do_cycles_post = do_cycles_post;
1.1.1.7 root 1054: } else if (currprefs.cpu_compatible) {
1.1.1.8 root 1055: // cpu_compatible only
1056: x_prefetch = get_word_000_prefetch;
1.1.1.7 root 1057: x_get_ilong = NULL;
1058: x_get_iword = get_iiword;
1059: x_get_ibyte = get_iibyte;
1060: x_next_iword = NULL;
1061: x_next_ilong = NULL;
1062: x_put_long = put_long;
1063: x_put_word = put_word;
1064: x_put_byte = put_byte;
1065: x_get_long = get_long;
1066: x_get_word = get_word;
1067: x_get_byte = get_byte;
1068: x_do_cycles = do_cycles;
1069: x_do_cycles_pre = do_cycles;
1070: x_do_cycles_post = do_cycles_post;
1071: } else {
1072: x_prefetch = NULL;
1073: x_get_ilong = get_dilong;
1074: x_get_iword = get_diword;
1075: x_get_ibyte = get_dibyte;
1076: x_next_iword = next_diword;
1077: x_next_ilong = next_dilong;
1078: x_put_long = put_long;
1079: x_put_word = put_word;
1080: x_put_byte = put_byte;
1081: x_get_long = get_long;
1082: x_get_word = get_word;
1083: x_get_byte = get_byte;
1084: x_do_cycles = do_cycles;
1085: x_do_cycles_pre = do_cycles;
1086: x_do_cycles_post = do_cycles_post;
1087: }
1088: } else if (!currprefs.cpu_cycle_exact) {
1089: // 68020+ no ce
1.1.1.8 root 1090: if (currprefs.cpu_memory_cycle_exact) {
1091: // cpu_memory_cycle_exact + cpu_compatible
1092: if (currprefs.cpu_model == 68020 && !currprefs.cachesize) {
1093: x_prefetch = get_word_020_prefetch;
1094: x_get_ilong = get_long_020_prefetch;
1095: x_get_iword = get_word_020_prefetch;
1096: x_get_ibyte = NULL;
1097: x_next_iword = next_iword_020_prefetch;
1098: x_next_ilong = next_ilong_020_prefetch;
1099: x_put_long = put_long_ce020;
1100: x_put_word = put_word_ce020;
1101: x_put_byte = put_byte_ce020;
1102: x_get_long = get_long_ce020;
1103: x_get_word = get_word_ce020;
1104: x_get_byte = get_byte_ce020;
1105: x_do_cycles = do_cycles;
1106: x_do_cycles_pre = do_cycles;
1107: x_do_cycles_post = do_cycles_post;
1108: } else if (currprefs.cpu_model == 68030 && !currprefs.cachesize) {
1109: x_prefetch = get_word_030_prefetch;
1110: x_get_ilong = get_long_030_prefetch;
1111: x_get_iword = get_word_030_prefetch;
1112: x_get_ibyte = NULL;
1113: x_next_iword = next_iword_030_prefetch;
1114: x_next_ilong = next_ilong_030_prefetch;
1115: x_put_long = put_long_ce030;
1116: x_put_word = put_word_ce030;
1117: x_put_byte = put_byte_ce030;
1118: x_get_long = get_long_ce030;
1119: x_get_word = get_word_ce030;
1120: x_get_byte = get_byte_ce030;
1121: x_do_cycles = do_cycles;
1122: x_do_cycles_pre = do_cycles;
1123: x_do_cycles_post = do_cycles_post;
1124: } else if (currprefs.cpu_model < 68040) {
1125: // JIT or 68030+ does not have real prefetch only emulation
1126: x_prefetch = NULL;
1127: set_x_ifetches();
1128: x_put_long = put_long;
1129: x_put_word = put_word;
1130: x_put_byte = put_byte;
1131: x_get_long = get_long;
1132: x_get_word = get_word;
1133: x_get_byte = get_byte;
1134: x_do_cycles = do_cycles;
1135: x_do_cycles_pre = do_cycles;
1136: x_do_cycles_post = do_cycles_post;
1137: } else {
1138: // 68040+ (same as below)
1139: x_prefetch = NULL;
1140: x_get_ilong = get_ilong_cache_040;
1141: x_get_iword = get_iword_cache_040;
1142: x_get_ibyte = NULL;
1143: x_next_iword = next_iword_cache040;
1144: x_next_ilong = next_ilong_cache040;
1.1.1.9 root 1145: if (currprefs.cpu_data_cache) {
1146: x_put_long = put_long_cache_040;
1147: x_put_word = put_word_cache_040;
1148: x_put_byte = put_byte_cache_040;
1149: x_get_long = get_long_cache_040;
1150: x_get_word = get_word_cache_040;
1151: x_get_byte = get_byte_cache_040;
1152: } else {
1153: x_get_byte = mem_access_delay_byte_read_c040;
1154: x_get_word = mem_access_delay_word_read_c040;
1155: x_get_long = mem_access_delay_long_read_c040;
1156: x_put_byte = mem_access_delay_byte_write_c040;
1157: x_put_word = mem_access_delay_word_write_c040;
1158: x_put_long = mem_access_delay_long_write_c040;
1159: }
1.1.1.8 root 1160: x_do_cycles = do_cycles;
1161: x_do_cycles_pre = do_cycles;
1162: x_do_cycles_post = do_cycles_post;
1163: }
1164: } else if (currprefs.cpu_compatible) {
1165: // cpu_compatible only
1.1.1.7 root 1166: if (currprefs.cpu_model == 68020 && !currprefs.cachesize) {
1.1.1.8 root 1167: x_prefetch = get_word_020_prefetch;
1.1.1.7 root 1168: x_get_ilong = get_long_020_prefetch;
1169: x_get_iword = get_word_020_prefetch;
1170: x_get_ibyte = NULL;
1171: x_next_iword = next_iword_020_prefetch;
1172: x_next_ilong = next_ilong_020_prefetch;
1173: x_put_long = put_long;
1174: x_put_word = put_word;
1175: x_put_byte = put_byte;
1176: x_get_long = get_long;
1177: x_get_word = get_word;
1178: x_get_byte = get_byte;
1179: x_do_cycles = do_cycles;
1180: x_do_cycles_pre = do_cycles;
1181: x_do_cycles_post = do_cycles_post;
1182: } else if (currprefs.cpu_model == 68030 && !currprefs.cachesize) {
1.1.1.9 root 1183: x_prefetch = get_word_030_prefetch;
1.1.1.7 root 1184: x_get_ilong = get_long_030_prefetch;
1185: x_get_iword = get_word_030_prefetch;
1186: x_get_ibyte = NULL;
1187: x_next_iword = next_iword_030_prefetch;
1188: x_next_ilong = next_ilong_030_prefetch;
1.1.1.9 root 1189: x_put_long = put_long_030;
1190: x_put_word = put_word_030;
1191: x_put_byte = put_byte_030;
1192: x_get_long = get_long_030;
1193: x_get_word = get_word_030;
1194: x_get_byte = get_byte_030;
1.1.1.7 root 1195: x_do_cycles = do_cycles;
1196: x_do_cycles_pre = do_cycles;
1197: x_do_cycles_post = do_cycles_post;
1198: } else if (currprefs.cpu_model < 68040) {
1199: // JIT or 68030+ does not have real prefetch only emulation
1200: x_prefetch = NULL;
1201: set_x_ifetches();
1202: x_put_long = put_long;
1203: x_put_word = put_word;
1204: x_put_byte = put_byte;
1205: x_get_long = get_long;
1206: x_get_word = get_word;
1207: x_get_byte = get_byte;
1208: x_do_cycles = do_cycles;
1209: x_do_cycles_pre = do_cycles;
1210: x_do_cycles_post = do_cycles_post;
1211: } else {
1212: x_prefetch = NULL;
1213: x_get_ilong = get_ilong_cache_040;
1214: x_get_iword = get_iword_cache_040;
1215: x_get_ibyte = NULL;
1216: x_next_iword = next_iword_cache040;
1217: x_next_ilong = next_ilong_cache040;
1.1.1.9 root 1218: if (currprefs.cpu_data_cache) {
1219: x_put_long = put_long_cache_040;
1220: x_put_word = put_word_cache_040;
1221: x_put_byte = put_byte_cache_040;
1222: x_get_long = get_long_cache_040;
1223: x_get_word = get_word_cache_040;
1224: x_get_byte = get_byte_cache_040;
1225: } else {
1226: x_put_long = put_long;
1227: x_put_word = put_word;
1228: x_put_byte = put_byte;
1229: x_get_long = get_long;
1230: x_get_word = get_word;
1231: x_get_byte = get_byte;
1232: }
1.1.1.7 root 1233: x_do_cycles = do_cycles;
1234: x_do_cycles_pre = do_cycles;
1235: x_do_cycles_post = do_cycles_post;
1236: }
1237: } else {
1238: x_prefetch = NULL;
1239: set_x_ifetches();
1.1.1.8 root 1240: if (currprefs.cachesize) {
1241: x_put_long = put_long_jit;
1242: x_put_word = put_word_jit;
1243: x_put_byte = put_byte_jit;
1244: x_get_long = get_long_jit;
1245: x_get_word = get_word_jit;
1246: x_get_byte = get_byte_jit;
1247: } else {
1248: x_put_long = put_long;
1249: x_put_word = put_word;
1250: x_put_byte = put_byte;
1251: x_get_long = get_long;
1252: x_get_word = get_word;
1253: x_get_byte = get_byte;
1254: }
1.1.1.7 root 1255: x_do_cycles = do_cycles;
1256: x_do_cycles_pre = do_cycles;
1257: x_do_cycles_post = do_cycles_post;
1258: }
1259: // 68020+ cycle exact
1.1.1.4 root 1260: } else if (currprefs.cpu_model == 68020) {
1261: x_prefetch = get_word_ce020_prefetch;
1.1.1.7 root 1262: x_get_ilong = get_long_ce020_prefetch;
1263: x_get_iword = get_word_ce020_prefetch;
1264: x_get_ibyte = NULL;
1.1.1.4 root 1265: x_next_iword = next_iword_020ce;
1266: x_next_ilong = next_ilong_020ce;
1267: x_put_long = put_long_ce020;
1268: x_put_word = put_word_ce020;
1269: x_put_byte = put_byte_ce020;
1270: x_get_long = get_long_ce020;
1271: x_get_word = get_word_ce020;
1272: x_get_byte = get_byte_ce020;
1.1.1.7 root 1273: #ifndef WINUAE_FOR_HATARI
1274: x_do_cycles = do_cycles_ce020;
1275: x_do_cycles_pre = do_cycles_ce020;
1276: x_do_cycles_post = do_cycles_ce020_post;
1277: #else
1278: x_do_cycles = do_cycles_ce020_long;
1279: x_do_cycles_pre = do_cycles_ce020_long;
1280: x_do_cycles_post = do_cycles_ce020_post;
1281: #endif
1282: } else if (currprefs.cpu_model == 68030) {
1.1.1.4 root 1283: x_prefetch = get_word_ce030_prefetch;
1.1.1.7 root 1284: x_get_ilong = get_long_ce030_prefetch;
1285: x_get_iword = get_word_ce030_prefetch;
1286: x_get_ibyte = NULL;
1.1.1.4 root 1287: x_next_iword = next_iword_030ce;
1288: x_next_ilong = next_ilong_030ce;
1.1.1.9 root 1289: if (currprefs.cpu_data_cache) {
1290: x_put_long = put_long_dc030;
1291: x_put_word = put_word_dc030;
1292: x_put_byte = put_byte_dc030;
1293: x_get_long = get_long_dc030;
1294: x_get_word = get_word_dc030;
1295: x_get_byte = get_byte_dc030;
1296: } else {
1297: x_put_long = put_long_ce030;
1298: x_put_word = put_word_ce030;
1299: x_put_byte = put_byte_ce030;
1300: x_get_long = get_long_ce030;
1301: x_get_word = get_word_ce030;
1302: x_get_byte = get_byte_ce030;
1303: }
1.1.1.7 root 1304: #ifndef WINUAE_FOR_HATARI
1305: x_do_cycles = do_cycles_ce020;
1306: x_do_cycles_pre = do_cycles_ce020;
1307: x_do_cycles_post = do_cycles_ce020_post;
1308: #else
1309: x_do_cycles = do_cycles_ce020_long;
1310: x_do_cycles_pre = do_cycles_ce020_long;
1311: x_do_cycles_post = do_cycles_ce020_post;
1312: #endif
1313: } else if (currprefs.cpu_model >= 68040) {
1314: x_prefetch = NULL;
1315: x_get_ilong = get_ilong_cache_040;
1316: x_get_iword = get_iword_cache_040;
1317: x_get_ibyte = NULL;
1318: x_next_iword = next_iword_cache040;
1319: x_next_ilong = next_ilong_cache040;
1.1.1.9 root 1320: if (currprefs.cpu_data_cache) {
1321: x_put_long = put_long_cache_040;
1322: x_put_word = put_word_cache_040;
1323: x_put_byte = put_byte_cache_040;
1324: x_get_long = get_long_cache_040;
1325: x_get_word = get_word_cache_040;
1326: x_get_byte = get_byte_cache_040;
1327: } else {
1328: x_get_byte = mem_access_delay_byte_read_c040;
1329: x_get_word = mem_access_delay_word_read_c040;
1330: x_get_long = mem_access_delay_long_read_c040;
1331: x_put_byte = mem_access_delay_byte_write_c040;
1332: x_put_word = mem_access_delay_word_write_c040;
1333: x_put_long = mem_access_delay_long_write_c040;
1334: }
1.1.1.7 root 1335: #ifndef WINUAE_FOR_HATARI
1336: x_do_cycles = do_cycles_ce020;
1337: x_do_cycles_pre = do_cycles_ce020;
1338: x_do_cycles_post = do_cycles_ce020_post;
1339: #else
1340: x_do_cycles = do_cycles_ce020_long;
1341: x_do_cycles_pre = do_cycles_ce020_long;
1342: x_do_cycles_post = do_cycles_ce020_post;
1343: #endif
1344: }
1345: x2_prefetch = x_prefetch;
1346: x2_get_ilong = x_get_ilong;
1347: x2_get_iword = x_get_iword;
1348: x2_get_ibyte = x_get_ibyte;
1349: x2_next_iword = x_next_iword;
1350: x2_next_ilong = x_next_ilong;
1351: x2_put_long = x_put_long;
1352: x2_put_word = x_put_word;
1353: x2_put_byte = x_put_byte;
1354: x2_get_long = x_get_long;
1355: x2_get_word = x_get_word;
1356: x2_get_byte = x_get_byte;
1357: x2_do_cycles = x_do_cycles;
1358: x2_do_cycles_pre = x_do_cycles_pre;
1359: x2_do_cycles_post = x_do_cycles_post;
1360:
1361: if (cpu_tracer > 0) {
1362: x_prefetch = cputracefunc_x_prefetch;
1363: x_get_ilong = cputracefunc_x_get_ilong;
1364: x_get_iword = cputracefunc_x_get_iword;
1365: x_get_ibyte = cputracefunc_x_get_ibyte;
1366: x_next_iword = cputracefunc_x_next_iword;
1367: x_next_ilong = cputracefunc_x_next_ilong;
1368: x_put_long = cputracefunc_x_put_long;
1369: x_put_word = cputracefunc_x_put_word;
1370: x_put_byte = cputracefunc_x_put_byte;
1371: x_get_long = cputracefunc_x_get_long;
1372: x_get_word = cputracefunc_x_get_word;
1373: x_get_byte = cputracefunc_x_get_byte;
1374: x_do_cycles = cputracefunc_x_do_cycles;
1375: x_do_cycles_pre = cputracefunc_x_do_cycles_pre;
1376: x_do_cycles_post = cputracefunc_x_do_cycles_post;
1377: } else if (cpu_tracer < 0) {
1378: if (!check_trace ()) {
1379: x_prefetch = cputracefunc2_x_prefetch;
1380: x_get_ilong = cputracefunc2_x_get_ilong;
1381: x_get_iword = cputracefunc2_x_get_iword;
1382: x_get_ibyte = cputracefunc2_x_get_ibyte;
1383: x_next_iword = cputracefunc2_x_next_iword;
1384: x_next_ilong = cputracefunc2_x_next_ilong;
1385: x_put_long = cputracefunc2_x_put_long;
1386: x_put_word = cputracefunc2_x_put_word;
1387: x_put_byte = cputracefunc2_x_put_byte;
1388: x_get_long = cputracefunc2_x_get_long;
1389: x_get_word = cputracefunc2_x_get_word;
1390: x_get_byte = cputracefunc2_x_get_byte;
1391: x_do_cycles = cputracefunc2_x_do_cycles;
1392: x_do_cycles_pre = cputracefunc2_x_do_cycles_pre;
1393: x_do_cycles_post = cputracefunc2_x_do_cycles_post;
1394: }
1395: }
1396:
1397: set_x_cp_funcs();
1398: mmu_set_funcs();
1399: mmu030_set_funcs();
1400:
1.1.1.9 root 1401: dcache_lput = put_long;
1402: dcache_wput = put_word;
1403: dcache_bput = put_byte;
1404: dcache_lget = get_long;
1405: dcache_wget = get_word;
1406: dcache_bget = get_byte;
1407: dcache_check = dcache_check_nommu;
1408:
1409: icache_fetch = get_longi;
1410: if (currprefs.cpu_cycle_exact) {
1411: icache_fetch = mem_access_delay_longi_read_ce020;
1412: }
1413: if (currprefs.cpu_model >= 68040 && currprefs.cpu_memory_cycle_exact) {
1414: icache_fetch = mem_access_delay_longi_read_c040;
1415: dcache_bget = mem_access_delay_byte_read_c040;
1416: dcache_wget = mem_access_delay_word_read_c040;
1417: dcache_lget = mem_access_delay_long_read_c040;
1418: dcache_bput = mem_access_delay_byte_write_c040;
1419: dcache_wput = mem_access_delay_word_write_c040;
1420: dcache_lput = mem_access_delay_long_write_c040;
1421: }
1422:
1423: if (currprefs.cpu_model == 68030) {
1424:
1425: if (currprefs.cpu_data_cache) {
1426: read_data_030_bget = read_dcache030_mmu_bget;
1427: read_data_030_wget = read_dcache030_mmu_wget;
1428: read_data_030_lget = read_dcache030_mmu_lget;
1429: write_data_030_bput = write_dcache030_mmu_bput;
1430: write_data_030_wput = write_dcache030_mmu_wput;
1431: write_data_030_lput = write_dcache030_mmu_lput;
1432:
1433: read_data_030_fc_bget = read_dcache030_bget;
1434: read_data_030_fc_wget = read_dcache030_wget;
1435: read_data_030_fc_lget = read_dcache030_lget;
1436: write_data_030_fc_bput = write_dcache030_bput;
1437: write_data_030_fc_wput = write_dcache030_wput;
1438: write_data_030_fc_lput = write_dcache030_lput;
1439: } else {
1440: read_data_030_bget = dcache_bget;
1441: read_data_030_wget = dcache_wget;
1442: read_data_030_lget = dcache_lget;
1443: write_data_030_bput = dcache_bput;
1444: write_data_030_wput = dcache_wput;
1445: write_data_030_lput = dcache_lput;
1446:
1447: read_data_030_fc_bget = mmu030_get_fc_byte;
1448: read_data_030_fc_wget = mmu030_get_fc_word;
1449: read_data_030_fc_lget = mmu030_get_fc_long;
1450: write_data_030_fc_bput = mmu030_put_fc_byte;
1451: write_data_030_fc_wput = mmu030_put_fc_word;
1452: write_data_030_fc_lput = mmu030_put_fc_long;
1453: }
1454:
1455: if (currprefs.mmu_model) {
1456: if (currprefs.cpu_compatible) {
1457: icache_fetch = uae_mmu030_get_ilong_fc;
1458: } else {
1459: icache_fetch = uae_mmu030_get_ilong;
1460: }
1.1.1.10! root 1461: dcache_lput = uae_mmu030_put_long_fc;
! 1462: dcache_wput = uae_mmu030_put_word_fc;
! 1463: dcache_bput = uae_mmu030_put_byte_fc;
! 1464: dcache_lget = uae_mmu030_get_long_fc;
! 1465: dcache_wget = uae_mmu030_get_word_fc;
! 1466: dcache_bget = uae_mmu030_get_byte_fc;
1.1.1.9 root 1467: if (currprefs.cpu_data_cache) {
1468: read_data_030_bget = read_dcache030_mmu_bget;
1469: read_data_030_wget = read_dcache030_mmu_wget;
1470: read_data_030_lget = read_dcache030_mmu_lget;
1471: write_data_030_bput = write_dcache030_mmu_bput;
1472: write_data_030_wput = write_dcache030_mmu_wput;
1473: write_data_030_lput = write_dcache030_mmu_lput;
1474: dcache_check = uae_mmu030_check_fc;
1475: } else {
1476: read_data_030_bget = uae_mmu030_get_byte;
1477: read_data_030_wget = uae_mmu030_get_word;
1478: read_data_030_lget = uae_mmu030_get_long;
1479: write_data_030_bput = uae_mmu030_put_byte;
1480: write_data_030_wput = uae_mmu030_put_word;
1481: write_data_030_lput = uae_mmu030_put_long;
1482: }
1483: } else if (currprefs.cpu_memory_cycle_exact) {
1484: icache_fetch = mem_access_delay_longi_read_ce020;
1485: dcache_lget = mem_access_delay_long_read_ce020;
1486: dcache_wget = mem_access_delay_word_read_ce020;
1487: dcache_bget = mem_access_delay_byte_read_ce020;
1488: if (currprefs.cpu_data_cache) {
1489: dcache_lput = mem_access_delay_long_write_ce030_cicheck;
1490: dcache_wput = mem_access_delay_word_write_ce030_cicheck;
1491: dcache_bput = mem_access_delay_byte_write_ce030_cicheck;
1492: } else {
1493: dcache_lput = mem_access_delay_long_write_ce020;
1494: dcache_wput = mem_access_delay_word_write_ce020;
1495: dcache_bput = mem_access_delay_byte_write_ce020;
1496: }
1497: } else if (currprefs.cpu_data_cache) {
1498: dcache_lput = put_long030_cicheck;
1499: dcache_wput = put_word030_cicheck;
1500: dcache_bput = put_byte030_cicheck;
1501: if (currprefs.cpu_data_cache) {
1502: dcache_lput = mem_access_delay_long_write_ce030_cicheck;
1503: dcache_wput = mem_access_delay_word_write_ce030_cicheck;
1504: dcache_bput = mem_access_delay_byte_write_ce030_cicheck;
1505: } else {
1506: dcache_lput = mem_access_delay_long_write_ce020;
1507: dcache_wput = mem_access_delay_word_write_ce020;
1508: dcache_bput = mem_access_delay_byte_write_ce020;
1509: }
1510: } else if (currprefs.cpu_data_cache) {
1511: dcache_lput = put_long030_cicheck;
1512: dcache_wput = put_word030_cicheck;
1513: dcache_bput = put_byte030_cicheck;
1514: }
1515: }
1.1.1.7 root 1516: }
1517:
1518: bool can_cpu_tracer (void)
1519: {
1.1.1.8 root 1520: return (currprefs.cpu_model == 68000 || currprefs.cpu_model == 68020) && currprefs.cpu_memory_cycle_exact;
1.1.1.7 root 1521: }
1522:
1523: bool is_cpu_tracer (void)
1524: {
1525: return cpu_tracer > 0;
1526: }
1527: bool set_cpu_tracer (bool state)
1528: {
1529: if (cpu_tracer < 0)
1530: return false;
1531: int old = cpu_tracer;
1532: #ifndef WINUAE_FOR_HATARI
1533: if (input_record)
1534: state = true;
1535: #endif
1536: cpu_tracer = 0;
1537: if (state && can_cpu_tracer ()) {
1538: cpu_tracer = 1;
1539: set_x_funcs ();
1540: if (old != cpu_tracer)
1541: write_log (_T("CPU tracer enabled\n"));
1.1.1.4 root 1542: }
1.1.1.7 root 1543: if (old > 0 && state == false) {
1544: set_x_funcs ();
1545: write_log (_T("CPU tracer disabled\n"));
1546: }
1547: return is_cpu_tracer ();
1.1.1.4 root 1548: }
1549:
1.1.1.9 root 1550: void invalidate_cpu_data_caches(void)
1551: {
1552: if (currprefs.cpu_model == 68030) {
1.1.1.10! root 1553: for (int i = 0; i < CACHELINES030; i++) {
1.1.1.9 root 1554: dcaches030[i].valid[0] = 0;
1555: dcaches030[i].valid[1] = 0;
1556: dcaches030[i].valid[2] = 0;
1557: dcaches030[i].valid[3] = 0;
1558: }
1559: } else if (currprefs.cpu_model >= 68040) {
1560: dcachelinecnt = 0;
1.1.1.10! root 1561: for (int i = 0; i < CACHESETS060; i++) {
! 1562: for (int j = 0; j < CACHELINES040; j++) {
1.1.1.9 root 1563: dcaches040[i].valid[j] = false;
1564: }
1565: }
1566: }
1567: }
1568:
1.1.1.7 root 1569: void flush_cpu_caches(bool force)
1.1.1.4 root 1570: {
1.1.1.8 root 1571: bool doflush = currprefs.cpu_compatible || currprefs.cpu_memory_cycle_exact;
1.1.1.4 root 1572:
1573: if (currprefs.cpu_model == 68020) {
1.1.1.9 root 1574: if ((regs.cacr & 0x08) || force) { // clear instr cache
1.1.1.10! root 1575: for (int i = 0; i < CACHELINES020; i++)
1.1.1.4 root 1576: caches020[i].valid = 0;
1.1.1.7 root 1577: regs.cacr &= ~0x08;
1.1.1.4 root 1578: }
1579: if (regs.cacr & 0x04) { // clear entry in instr cache
1.1.1.7 root 1580: caches020[(regs.caar >> 2) & (CACHELINES020 - 1)].valid = 0;
1.1.1.4 root 1581: regs.cacr &= ~0x04;
1582: }
1583: } else if (currprefs.cpu_model == 68030) {
1.1.1.9 root 1584: if ((regs.cacr & 0x08) || force) { // clear instr cache
1.1.1.7 root 1585: if (doflush) {
1.1.1.10! root 1586: for (int i = 0; i < CACHELINES030; i++) {
1.1.1.7 root 1587: icaches030[i].valid[0] = 0;
1588: icaches030[i].valid[1] = 0;
1589: icaches030[i].valid[2] = 0;
1590: icaches030[i].valid[3] = 0;
1591: }
1.1.1.4 root 1592: }
1.1.1.7 root 1593: regs.cacr &= ~0x08;
1.1.1.4 root 1594: }
1595: if (regs.cacr & 0x04) { // clear entry in instr cache
1.1.1.7 root 1596: icaches030[(regs.caar >> 4) & (CACHELINES030 - 1)].valid[(regs.caar >> 2) & 3] = 0;
1.1.1.4 root 1597: regs.cacr &= ~0x04;
1598: }
1.1.1.9 root 1599: if ((regs.cacr & 0x800) || force) { // clear data cache
1.1.1.7 root 1600: if (doflush) {
1.1.1.10! root 1601: for (int i = 0; i < CACHELINES030; i++) {
1.1.1.7 root 1602: dcaches030[i].valid[0] = 0;
1603: dcaches030[i].valid[1] = 0;
1604: dcaches030[i].valid[2] = 0;
1605: dcaches030[i].valid[3] = 0;
1606: }
1.1.1.4 root 1607: }
1608: regs.cacr &= ~0x800;
1609: }
1610: if (regs.cacr & 0x400) { // clear entry in data cache
1.1.1.7 root 1611: dcaches030[(regs.caar >> 4) & (CACHELINES030 - 1)].valid[(regs.caar >> 2) & 3] = 0;
1.1.1.4 root 1612: regs.cacr &= ~0x400;
1613: }
1.1.1.7 root 1614: } else if (currprefs.cpu_model >= 68040) {
1.1.1.9 root 1615: if (doflush && force) {
1616: mmu_flush_cache();
1617: icachelinecnt = 0;
1618: icachehalfline = 0;
1.1.1.10! root 1619: for (int i = 0; i < CACHESETS060; i++) {
! 1620: for (int j = 0; j < CACHELINES040; j++) {
1.1.1.9 root 1621: icaches040[i].valid[j] = false;
1622: }
1623: }
1624: }
1625: }
1626: }
1627:
1628: #if VALIDATE_68040_DATACACHE > 1
1629: static void validate_dcache040(void)
1630: {
1.1.1.10! root 1631: for (int i = 0; i < cachedsets04060; i++) {
1.1.1.9 root 1632: struct cache040 *c = &dcaches040[i];
1.1.1.10! root 1633: for (int j = 0; j < CACHELINES040; j++) {
1.1.1.9 root 1634: if (c->valid[j]) {
1635: uae_u32 addr = (c->tag[j] & cachedtag04060mask) | (i << 4);
1636: if (addr < 0x200000 || (addr >= 0xd80000 && addr < 0xe00000) || (addr >= 0xe80000 && addr < 0xf00000) || (addr >= 0xa00000 && addr < 0xc00000)) {
1637: write_log(_T("Chip RAM or IO address cached! %08x\n"), addr);
1638: }
1.1.1.10! root 1639: for (int k = 0; k < 4; k++) {
1.1.1.9 root 1640: if (!c->dirty[j][k]) {
1641: uae_u32 v = get_long(addr + k * 4);
1642: if (v != c->data[j][k]) {
1643: write_log(_T("Address %08x data cache mismatch %08x != %08x\n"), addr, v, c->data[j][k]);
1644: }
1645: }
1646: }
1647: }
1648: }
1649: }
1650: }
1651: #endif
1652:
1653: static void dcache040_push_line(int index, int line, bool writethrough, bool invalidate)
1654: {
1655: struct cache040 *c = &dcaches040[index];
1656: #if VALIDATE_68040_DATACACHE
1657: if (!c->valid[line]) {
1658: write_log("dcache040_push_line pushing invalid line!\n");
1659: }
1660: #endif
1661: if (c->gdirty[line]) {
1662: uae_u32 addr = (c->tag[line] & cachedtag04060mask) | (index << 4);
1.1.1.10! root 1663: for (int i = 0; i < 4; i++) {
1.1.1.9 root 1664: if (c->dirty[line][i] || (!writethrough && currprefs.cpu_model == 68060)) {
1665: dcache_lput(addr + i * 4, c->data[line][i]);
1666: c->dirty[line][i] = false;
1.1.1.4 root 1667: }
1668: }
1.1.1.9 root 1669: c->gdirty[line] = false;
1.1.1.4 root 1670: }
1.1.1.9 root 1671: if (invalidate)
1672: c->valid[line] = false;
1673:
1674: #if VALIDATE_68040_DATACACHE > 1
1675: validate_dcache040();
1676: #endif
1.1.1.4 root 1677: }
1678:
1.1.1.10! root 1679: static void flush_cpu_caches_040_2(int cache, int scope, uaecptr addr, bool push, bool pushinv)
1.1.1.4 root 1680: {
1.1.1.9 root 1681:
1682: #if VALIDATE_68040_DATACACHE
1683: write_log(_T("push %d %d %d %08x %d %d\n"), cache, scope, areg, addr, push, pushinv);
1684: #endif
1685:
1686: if (cache & 2)
1687: regs.prefetch020addr = 0xffffffff;
1.1.1.10! root 1688: for (int k = 0; k < 2; k++) {
1.1.1.9 root 1689: if (cache & (1 << k)) {
1690: if (scope == 3) {
1691: // all
1692: if (!k) {
1693: // data
1.1.1.10! root 1694: for (int i = 0; i < cachedsets04060; i++) {
1.1.1.9 root 1695: struct cache040 *c = &dcaches040[i];
1.1.1.10! root 1696: for (int j = 0; j < CACHELINES040; j++) {
1.1.1.9 root 1697: if (c->valid[j]) {
1698: if (push) {
1699: dcache040_push_line(i, j, false, pushinv);
1700: } else {
1701: c->valid[j] = false;
1702: }
1703: }
1704: }
1705: }
1706: dcachelinecnt = 0;
1707: } else {
1708: // instruction
1709: flush_cpu_caches(true);
1710: }
1711: } else {
1712: uae_u32 pagesize;
1713: if (scope == 2) {
1714: // page
1715: pagesize = mmu_pagesize_8k ? 8192 : 4096;
1716: } else {
1717: // line
1718: pagesize = 16;
1719: }
1720: addr &= ~(pagesize - 1);
1.1.1.10! root 1721: uae_u32 j;
1.1.1.9 root 1722: for (j = 0; j < pagesize; j += 16, addr += 16) {
1723: int index;
1724: uae_u32 tag;
1725: uae_u32 tagmask;
1726: struct cache040 *c;
1727: if (k) {
1728: tagmask = cacheitag04060mask;
1729: index = (addr >> 4) & cacheisets04060mask;
1730: c = &icaches040[index];
1731: } else {
1732: tagmask = cachedtag04060mask;
1733: index = (addr >> 4) & cachedsets04060mask;
1734: c = &dcaches040[index];
1735: }
1736: tag = addr & tagmask;
1.1.1.10! root 1737: for (int i = 0; i < CACHELINES040; i++) {
1.1.1.9 root 1738: if (c->valid[i] && c->tag[i] == tag) {
1739: if (push) {
1740: dcache040_push_line(index, i, false, pushinv);
1741: } else {
1742: c->valid[i] = false;
1743: }
1744: }
1745: }
1746: }
1747: }
1748: }
1749: }
1.1.1.10! root 1750: }
! 1751:
! 1752: void flush_cpu_caches_040(uae_u16 opcode)
! 1753: {
! 1754: // 0 (1) = data, 1 (2) = instruction
! 1755: int cache = (opcode >> 6) & 3;
! 1756: int scope = (opcode >> 3) & 3;
! 1757: int areg = opcode & 7;
! 1758: uaecptr addr = m68k_areg(regs, areg);
! 1759: bool push = (opcode & 0x20) != 0;
! 1760: bool pushinv = (regs.cacr & 0x01000000) == 0; // 68060 DPI
! 1761:
! 1762: flush_cpu_caches_040_2(cache, scope, addr, push, pushinv);
1.1.1.9 root 1763: mmu_flush_cache();
1.1.1.4 root 1764: }
1765:
1.1.1.10! root 1766: void cpu_invalidate_cache(uaecptr addr, int size)
! 1767: {
! 1768: if (!currprefs.cpu_data_cache)
! 1769: return;
! 1770: if (currprefs.cpu_model == 68030) {
! 1771: uaecptr end = addr + size;
! 1772: addr &= ~3;
! 1773: while (addr < end) {
! 1774: dcaches030[(addr >> 4) & (CACHELINES030 - 1)].valid[(addr >> 2) & 3] = 0;
! 1775: addr += 4;
! 1776: }
! 1777: } else if (currprefs.cpu_model >= 68040) {
! 1778: uaecptr end = addr + size;
! 1779: while (addr < end) {
! 1780: flush_cpu_caches_040_2(0, 1, addr, true, true);
! 1781: addr += 16;
! 1782: }
! 1783: }
! 1784: }
! 1785:
! 1786:
1.1.1.7 root 1787: void set_cpu_caches (bool flush)
1.1.1.4 root 1788: {
1.1.1.7 root 1789: regs.prefetch020addr = 0xffffffff;
1790: regs.cacheholdingaddr020 = 0xffffffff;
1.1.1.9 root 1791: cache_default_data &= ~CACHE_DISABLE_ALLOCATE;
1792:
1793: // 68060 FIC 1/2 instruction cache
1794: cacheisets04060 = currprefs.cpu_model == 68060 && !(regs.cacr & 0x00002000) ? CACHESETS060 : CACHESETS040;
1795: cacheisets04060mask = cacheisets04060 - 1;
1796: cacheitag04060mask = ~((cacheisets04060 << 4) - 1);
1797: // 68060 FOC 1/2 data cache
1798: cachedsets04060 = currprefs.cpu_model == 68060 && !(regs.cacr & 0x08000000) ? CACHESETS060 : CACHESETS040;
1799: cachedsets04060mask = cachedsets04060 - 1;
1800: cachedtag04060mask = ~((cachedsets04060 << 4) - 1);
1801: cache_lastline = 0;
1.1.1.4 root 1802:
1.1.1.7 root 1803: #ifdef JIT
1804: if (currprefs.cachesize) {
1805: if (currprefs.cpu_model < 68040) {
1806: set_cache_state (regs.cacr & 1);
1807: if (regs.cacr & 0x08) {
1.1.1.9 root 1808: flush_icache (3);
1.1.1.7 root 1809: }
1810: } else {
1811: set_cache_state ((regs.cacr & 0x8000) ? 1 : 0);
1812: }
1813: }
1814: #endif
1815: flush_cpu_caches(flush);
1816: }
1817:
1818: STATIC_INLINE void count_instr (unsigned int opcode)
1819: {
1820: }
1821:
1822: static uae_u32 REGPARAM2 op_illg_1 (uae_u32 opcode)
1823: {
1824: op_illg (opcode);
1825: return 4;
1826: }
1827: static uae_u32 REGPARAM2 op_unimpl_1 (uae_u32 opcode)
1828: {
1829: if ((opcode & 0xf000) == 0xf000 || currprefs.cpu_model < 68060)
1830: op_illg (opcode);
1831: else
1832: op_unimpl (opcode);
1833: return 4;
1834: }
1835:
1.1.1.9 root 1836: // generic+direct, generic+direct+jit, generic+indirect, more compatible, cycle-exact, mmu, mmu+more compatible, mmu+mc+ce
1837: static const struct cputbl *cputbls[6][8] =
1.1.1.7 root 1838: {
1839: // 68000
1.1.1.9 root 1840: { op_smalltbl_5_ff, op_smalltbl_45_ff, op_smalltbl_55_ff, op_smalltbl_12_ff, op_smalltbl_14_ff, NULL, NULL, NULL },
1.1.1.7 root 1841: // 68010
1.1.1.9 root 1842: { op_smalltbl_4_ff, op_smalltbl_44_ff, op_smalltbl_54_ff, op_smalltbl_11_ff, op_smalltbl_13_ff, NULL, NULL, NULL },
1.1.1.7 root 1843: // 68020
1.1.1.9 root 1844: { op_smalltbl_3_ff, op_smalltbl_43_ff, op_smalltbl_53_ff, op_smalltbl_20_ff, op_smalltbl_21_ff, NULL, NULL, NULL },
1.1.1.7 root 1845: // 68030
1.1.1.9 root 1846: { op_smalltbl_2_ff, op_smalltbl_42_ff, op_smalltbl_52_ff, op_smalltbl_22_ff, op_smalltbl_23_ff, op_smalltbl_32_ff, op_smalltbl_34_ff, op_smalltbl_35_ff },
1.1.1.7 root 1847: // 68040
1.1.1.9 root 1848: { op_smalltbl_1_ff, op_smalltbl_41_ff, op_smalltbl_51_ff, op_smalltbl_25_ff, op_smalltbl_25_ff, op_smalltbl_31_ff, op_smalltbl_31_ff, op_smalltbl_31_ff },
1.1.1.7 root 1849: // 68060
1.1.1.9 root 1850: { op_smalltbl_0_ff, op_smalltbl_40_ff, op_smalltbl_50_ff, op_smalltbl_24_ff, op_smalltbl_24_ff, op_smalltbl_33_ff, op_smalltbl_33_ff, op_smalltbl_33_ff }
1.1.1.7 root 1851: };
1852:
1853: static void build_cpufunctbl (void)
1.1.1.4 root 1854: {
1855: int i, opcnt;
1856: unsigned long opcode;
1857: const struct cputbl *tbl = 0;
1.1.1.7 root 1858: int lvl, mode;
1.1.1.4 root 1859:
1.1.1.7 root 1860: if (!currprefs.cachesize) {
1.1.1.9 root 1861: if (currprefs.mmu_model) {
1862: if (currprefs.cpu_cycle_exact)
1863: mode = 7;
1864: else if (currprefs.cpu_compatible)
1865: mode = 6;
1866: else
1867: mode = 5;
1868: } else if (currprefs.cpu_cycle_exact) {
1.1.1.8 root 1869: mode = 4;
1.1.1.9 root 1870: } else if (currprefs.cpu_compatible) {
1.1.1.8 root 1871: mode = 3;
1.1.1.9 root 1872: } else {
1.1.1.7 root 1873: mode = 0;
1.1.1.9 root 1874: }
1.1.1.7 root 1875: m68k_pc_indirect = mode != 0 ? 1 : 0;
1876: } else {
1.1.1.8 root 1877: mode = 1;
1.1.1.7 root 1878: m68k_pc_indirect = 0;
1879: if (currprefs.comptrustbyte) {
1.1.1.8 root 1880: mode = 2;
1.1.1.7 root 1881: m68k_pc_indirect = -1;
1882: }
1.1.1.4 root 1883: }
1.1.1.7 root 1884: lvl = (currprefs.cpu_model - 68000) / 10;
1885: if (lvl == 6)
1886: lvl = 5;
1887: tbl = cputbls[lvl][mode];
1.1.1.4 root 1888:
1.1.1.7 root 1889: if (tbl == NULL) {
1890: write_log (_T("no CPU emulation cores available CPU=%d!"), currprefs.cpu_model);
1.1.1.4 root 1891: abort ();
1892: }
1893:
1894: for (opcode = 0; opcode < 65536; opcode++)
1895: cpufunctbl[opcode] = op_illg_1;
1896: for (i = 0; tbl[i].handler != NULL; i++) {
1897: opcode = tbl[i].opcode;
1898: cpufunctbl[opcode] = tbl[i].handler;
1.1.1.7 root 1899: cpudatatbl[opcode].length = tbl[i].length;
1900: cpudatatbl[opcode].disp020[0] = tbl[i].disp020[0];
1901: cpudatatbl[opcode].disp020[1] = tbl[i].disp020[1];
1902: cpudatatbl[opcode].branch = tbl[i].branch;
1.1.1.4 root 1903: }
1904:
1905: /* hack fpu to 68000/68010 mode */
1906: if (currprefs.fpu_model && currprefs.cpu_model < 68020) {
1907: tbl = op_smalltbl_3_ff;
1908: for (i = 0; tbl[i].handler != NULL; i++) {
1.1.1.7 root 1909: if ((tbl[i].opcode & 0xfe00) == 0xf200) {
1.1.1.4 root 1910: cpufunctbl[tbl[i].opcode] = tbl[i].handler;
1.1.1.7 root 1911: cpudatatbl[tbl[i].opcode].length = tbl[i].length;
1912: cpudatatbl[tbl[i].opcode].disp020[0] = tbl[i].disp020[0];
1913: cpudatatbl[tbl[i].opcode].disp020[1] = tbl[i].disp020[1];
1914: cpudatatbl[tbl[i].opcode].branch = tbl[i].branch;
1915: }
1.1.1.4 root 1916: }
1917: }
1.1.1.7 root 1918:
1.1.1.4 root 1919: opcnt = 0;
1920: for (opcode = 0; opcode < 65536; opcode++) {
1921: cpuop_func *f;
1.1.1.7 root 1922: struct instr *table = &table68k[opcode];
1923:
1924: if (table->mnemo == i_ILLG)
1925: continue;
1926:
1927: /* unimplemented opcode? */
1928: if (table->unimpclev > 0 && lvl >= table->unimpclev) {
1.1.1.8 root 1929: if (currprefs.cpu_model == 68060) {
1930: // remove unimplemented integer instructions
1931: // unimpclev == 5: not implemented in 68060,
1932: // generates unimplemented instruction exception.
1933: if (currprefs.int_no_unimplemented && table->unimpclev == 5) {
1934: cpufunctbl[opcode] = op_unimpl_1;
1935: continue;
1936: }
1937: // remove unimplemented instruction that were removed in previous models,
1938: // generates normal illegal instruction exception.
1939: // unimplclev < 5: instruction was removed in 68040 or previous model.
1940: // clev=4: implemented in 68040 or later. unimpclev=5: not in 68060
1941: if (table->unimpclev < 5 || (table->clev == 4 && table->unimpclev == 5)) {
1.1.1.7 root 1942: cpufunctbl[opcode] = op_illg_1;
1943: continue;
1944: }
1.1.1.8 root 1945: } else {
1946: cpufunctbl[opcode] = op_illg_1;
1947: continue;
1.1.1.7 root 1948: }
1949: }
1.1.1.4 root 1950:
1951: if (currprefs.fpu_model && currprefs.cpu_model < 68020) {
1952: /* more hack fpu to 68000/68010 mode */
1.1.1.7 root 1953: if (table->clev > lvl && (opcode & 0xfe00) != 0xf200)
1.1.1.4 root 1954: continue;
1.1.1.7 root 1955: } else if (table->clev > lvl) {
1.1.1.4 root 1956: continue;
1957: }
1958:
1.1.1.7 root 1959: if (table->handler != -1) {
1960: int idx = table->handler;
1.1.1.4 root 1961: f = cpufunctbl[idx];
1962: if (f == op_illg_1)
1963: abort ();
1964: cpufunctbl[opcode] = f;
1.1.1.7 root 1965: memcpy(&cpudatatbl[opcode], &cpudatatbl[idx], sizeof(struct cputbl_data));
1.1.1.4 root 1966: opcnt++;
1967: }
1968: }
1.1.1.7 root 1969: write_log (_T("Building CPU, %d opcodes (%d %d %d)\n"),
1.1.1.4 root 1970: opcnt, lvl,
1.1.1.8 root 1971: currprefs.cpu_cycle_exact ? -2 : currprefs.cpu_memory_cycle_exact ? -1 : currprefs.cpu_compatible ? 1 : 0, currprefs.address_space_24);
1.1.1.4 root 1972: #ifdef JIT
1.1.1.8 root 1973: write_log(_T("JIT: &countdown = %p\n"), &countdown);
1974: write_log(_T("JIT: &build_comp = %p\n"), &build_comp);
1.1.1.4 root 1975: build_comp ();
1976: #endif
1.1.1.7 root 1977:
1.1.1.9 root 1978: write_log(_T("CPU=%d, FPU=%d%s, MMU=%d, JIT%s=%d."),
1979: currprefs.cpu_model,
1.1.1.10! root 1980: currprefs.fpu_model, currprefs.fpu_model ? (currprefs.fpu_mode > 0 ? _T(" (softfloat)") : (currprefs.fpu_mode < 0 ? _T(" (host 80b)") : _T(" (host 64b)"))) : _T(""),
1.1.1.9 root 1981: currprefs.mmu_model,
1982: currprefs.cachesize ? (currprefs.compfpu ? _T("=CPU/FPU") : _T("=CPU")) : _T(""),
1983: currprefs.cachesize);
1.1.1.7 root 1984:
1985: regs.address_space_mask = 0xffffffff;
1986: #ifndef WINUAE_FOR_HATARI
1987: if (currprefs.cpu_compatible) {
1988: if (currprefs.address_space_24 && currprefs.cpu_model >= 68040)
1989: currprefs.address_space_24 = false;
1990: }
1991: #else
1992: /* Hatari : don't force address_space_24=0 for 68030, as the Falcon has a 68030 LC with only 24 bits */
1993: /* TODO ? Force address_space_24=0 for 68040 ? */
1994: #endif
1995: m68k_interrupt_delay = false;
1996: if (currprefs.cpu_cycle_exact) {
1997: if (tbl == op_smalltbl_14_ff || tbl == op_smalltbl_13_ff || tbl == op_smalltbl_21_ff || tbl == op_smalltbl_23_ff)
1998: m68k_interrupt_delay = true;
1999: }
2000:
2001: if (currprefs.cpu_cycle_exact) {
2002: if (currprefs.cpu_model == 68000)
2003: write_log(_T(" prefetch and cycle-exact"));
2004: else
2005: write_log(_T(" ~cycle-exact"));
1.1.1.8 root 2006: } else if (currprefs.cpu_memory_cycle_exact) {
2007: write_log(_T(" ~memory-cycle-exact"));
1.1.1.7 root 2008: } else if (currprefs.cpu_compatible) {
2009: if (currprefs.cpu_model <= 68020) {
2010: write_log(_T(" prefetch"));
2011: } else {
2012: write_log(_T(" fake prefetch"));
1.1.1.5 root 2013: }
1.1.1.4 root 2014: }
1.1.1.7 root 2015: if (currprefs.m68k_speed < 0)
2016: write_log(_T(" fast"));
2017: if (currprefs.int_no_unimplemented && currprefs.cpu_model == 68060) {
2018: write_log(_T(" no unimplemented integer instructions"));
2019: }
2020: if (currprefs.fpu_no_unimplemented && currprefs.fpu_model) {
2021: write_log(_T(" no unimplemented floating point instructions"));
2022: }
2023: if (currprefs.address_space_24) {
2024: regs.address_space_mask = 0x00ffffff;
2025: write_log(_T(" 24-bit"));
2026: }
2027: write_log(_T("\n"));
1.1.1.4 root 2028:
1.1.1.7 root 2029: set_cpu_caches (true);
1.1.1.10! root 2030: #ifndef WINUAE_FOR_HATARI
! 2031: target_cpu_speed();
! 2032: #endif
1.1.1.4 root 2033: }
2034:
1.1.1.7 root 2035: #define CYCLES_DIV 8192
2036: static unsigned long cycles_mult;
1.1.1.4 root 2037:
2038: static void update_68k_cycles (void)
2039: {
1.1.1.7 root 2040: cycles_mult = 0;
1.1.1.9 root 2041: #ifdef WINUAE_FOR_HATARI
2042: Log_Printf(LOG_DEBUG, "update cyc speed %d throttle %f clock_mult %d\n", currprefs.m68k_speed, currprefs.m68k_speed_throttle, changed_prefs.cpu_clock_multiplier);
2043: #else /* Don't adjust cycles_mult in Hatari and ignore m68k_speed (forced to 0) */
1.1.1.7 root 2044: if (currprefs.m68k_speed >= 0 && !currprefs.cpu_cycle_exact) {
2045: if (currprefs.m68k_speed_throttle < 0) {
2046: cycles_mult = (unsigned long)(CYCLES_DIV * 1000 / (1000 + currprefs.m68k_speed_throttle));
2047: } else if (currprefs.m68k_speed_throttle > 0) {
2048: cycles_mult = (unsigned long)(CYCLES_DIV * 1000 / (1000 + currprefs.m68k_speed_throttle));
2049: }
2050: }
2051: if (currprefs.m68k_speed == 0) {
2052: if (currprefs.cpu_model >= 68040) {
2053: if (!cycles_mult)
2054: cycles_mult = CYCLES_DIV / 8;
2055: else
2056: cycles_mult /= 8;
2057: } else if (currprefs.cpu_model >= 68020) {
2058: if (!cycles_mult)
2059: cycles_mult = CYCLES_DIV / 4;
2060: else
2061: cycles_mult /= 4;
2062: }
1.1.1.4 root 2063: }
1.1.1.7 root 2064: #endif
2065:
1.1.1.4 root 2066: currprefs.cpu_clock_multiplier = changed_prefs.cpu_clock_multiplier;
2067: currprefs.cpu_frequency = changed_prefs.cpu_frequency;
2068:
1.1.1.7 root 2069: #ifndef WINUAE_FOR_HATARI
2070: baseclock = (currprefs.ntscmode ? CHIPSET_CLOCK_NTSC : CHIPSET_CLOCK_PAL) * 8;
2071: #endif
1.1.1.4 root 2072: cpucycleunit = CYCLE_UNIT / 2;
2073: if (currprefs.cpu_clock_multiplier) {
2074: if (currprefs.cpu_clock_multiplier >= 256) {
2075: cpucycleunit = CYCLE_UNIT / (currprefs.cpu_clock_multiplier >> 8);
2076: } else {
2077: cpucycleunit = CYCLE_UNIT * currprefs.cpu_clock_multiplier;
2078: }
1.1.1.7 root 2079: if (currprefs.cpu_model >= 68040)
2080: cpucycleunit /= 2;
2081: #ifndef WINUAE_FOR_HATARI /* [NP] TODO : handle any cpu frequency, not just mulltiplier ? */
1.1.1.4 root 2082: } else if (currprefs.cpu_frequency) {
2083: cpucycleunit = CYCLE_UNIT * baseclock / currprefs.cpu_frequency;
1.1.1.7 root 2084: #endif
2085: } else if (currprefs.cpu_cycle_exact && currprefs.cpu_clock_multiplier == 0) {
2086: if (currprefs.cpu_model >= 68040) {
2087: cpucycleunit = CYCLE_UNIT / 16;
2088: } if (currprefs.cpu_model == 68030) {
2089: cpucycleunit = CYCLE_UNIT / 8;
2090: } else if (currprefs.cpu_model == 68020) {
2091: cpucycleunit = CYCLE_UNIT / 4;
2092: } else {
2093: cpucycleunit = CYCLE_UNIT / 2;
2094: }
1.1.1.4 root 2095: }
2096: if (cpucycleunit < 1)
2097: cpucycleunit = 1;
2098: if (currprefs.cpu_cycle_exact)
1.1.1.7 root 2099: write_log (_T("CPU cycleunit: %d (%.3f)\n"), cpucycleunit, (float)cpucycleunit / CYCLE_UNIT);
2100: write_log (_T("CPU cycleunit: %d (%.3f)\n"), cpucycleunit, (float)cpucycleunit / CYCLE_UNIT);
2101: #ifndef WINUAE_FOR_HATARI
2102: set_config_changed ();
2103: #endif
1.1.1.4 root 2104: }
2105:
2106: static void prefs_changed_cpu (void)
2107: {
2108: fixup_cpu (&changed_prefs);
1.1.1.8 root 2109: check_prefs_changed_comp(false);
1.1.1.4 root 2110: currprefs.cpu_model = changed_prefs.cpu_model;
2111: currprefs.fpu_model = changed_prefs.fpu_model;
1.1.1.9 root 2112: if (currprefs.mmu_model != changed_prefs.mmu_model) {
2113: int oldmmu = currprefs.mmu_model;
2114: currprefs.mmu_model = changed_prefs.mmu_model;
2115: if (currprefs.mmu_model >= 68040) {
2116: uae_u32 tcr = regs.tcr;
2117: mmu_reset();
2118: mmu_set_tc(tcr);
2119: mmu_set_super(regs.s != 0);
2120: mmu_tt_modified();
2121: } else if (currprefs.mmu_model == 68030) {
2122: mmu030_reset(-1);
2123: mmu030_flush_atc_all();
2124: tc_030 = fake_tc_030;
2125: tt0_030 = fake_tt0_030;
2126: tt1_030 = fake_tt1_030;
2127: srp_030 = fake_srp_030;
2128: crp_030 = fake_crp_030;
2129: mmu030_decode_tc(tc_030, false);
2130: } else if (oldmmu == 68030) {
2131: fake_tc_030 = tc_030;
2132: fake_tt0_030 = tt0_030;
2133: fake_tt1_030 = tt1_030;
2134: fake_srp_030 = srp_030;
2135: fake_crp_030 = crp_030;
2136: }
2137: }
2138: currprefs.mmu_ec = changed_prefs.mmu_ec;
2139: if (currprefs.cpu_compatible != changed_prefs.cpu_compatible) {
2140: currprefs.cpu_compatible = changed_prefs.cpu_compatible;
2141: flush_cpu_caches(true);
2142: invalidate_cpu_data_caches();
2143: }
2144: if (currprefs.cpu_data_cache != changed_prefs.cpu_data_cache) {
2145: currprefs.cpu_data_cache = changed_prefs.cpu_data_cache;
2146: invalidate_cpu_data_caches();
2147: }
1.1.1.8 root 2148: currprefs.address_space_24 = changed_prefs.address_space_24;
1.1.1.4 root 2149: currprefs.cpu_cycle_exact = changed_prefs.cpu_cycle_exact;
1.1.1.8 root 2150: currprefs.cpu_memory_cycle_exact = changed_prefs.cpu_memory_cycle_exact;
1.1.1.7 root 2151: currprefs.int_no_unimplemented = changed_prefs.int_no_unimplemented;
2152: currprefs.fpu_no_unimplemented = changed_prefs.fpu_no_unimplemented;
2153: currprefs.blitter_cycle_exact = changed_prefs.blitter_cycle_exact;
1.1.1.4 root 2154: }
2155:
1.1.1.7 root 2156: static int check_prefs_changed_cpu2(void)
1.1.1.4 root 2157: {
1.1.1.7 root 2158: int changed = 0;
1.1.1.4 root 2159:
2160: #ifdef JIT
1.1.1.8 root 2161: changed = check_prefs_changed_comp(true) ? 1 : 0;
1.1.1.4 root 2162: #endif
2163: if (changed
2164: || currprefs.cpu_model != changed_prefs.cpu_model
2165: || currprefs.fpu_model != changed_prefs.fpu_model
2166: || currprefs.mmu_model != changed_prefs.mmu_model
1.1.1.9 root 2167: || currprefs.mmu_ec != changed_prefs.mmu_ec
2168: || currprefs.cpu_data_cache != changed_prefs.cpu_data_cache
1.1.1.8 root 2169: || currprefs.address_space_24 != changed_prefs.address_space_24 /* WINUAE_FOR_HATARI */
1.1.1.7 root 2170: || currprefs.int_no_unimplemented != changed_prefs.int_no_unimplemented
2171: || currprefs.fpu_no_unimplemented != changed_prefs.fpu_no_unimplemented
1.1.1.4 root 2172: || currprefs.cpu_compatible != changed_prefs.cpu_compatible
1.1.1.8 root 2173: || currprefs.cpu_cycle_exact != changed_prefs.cpu_cycle_exact
1.1.1.9 root 2174: || currprefs.cpu_memory_cycle_exact != changed_prefs.cpu_memory_cycle_exact
1.1.1.10! root 2175: || currprefs.fpu_mode != changed_prefs.fpu_mode) {
1.1.1.7 root 2176: cpu_prefs_changed_flag |= 1;
1.1.1.4 root 2177: }
2178: if (changed
2179: || currprefs.m68k_speed != changed_prefs.m68k_speed
1.1.1.7 root 2180: || currprefs.m68k_speed_throttle != changed_prefs.m68k_speed_throttle
1.1.1.4 root 2181: || currprefs.cpu_clock_multiplier != changed_prefs.cpu_clock_multiplier
1.1.1.7 root 2182: || currprefs.reset_delay != changed_prefs.reset_delay
1.1.1.4 root 2183: || currprefs.cpu_frequency != changed_prefs.cpu_frequency) {
1.1.1.7 root 2184: cpu_prefs_changed_flag |= 2;
1.1.1.4 root 2185: }
1.1.1.7 root 2186: return cpu_prefs_changed_flag;
2187: }
1.1.1.4 root 2188:
1.1.1.7 root 2189: void check_prefs_changed_cpu(void)
2190: {
1.1.1.8 root 2191: #ifndef WINUAE_FOR_HATARI /* [NP] TODO : handle cpu change on the fly ? */
1.1.1.7 root 2192: if (!config_changed)
2193: return;
1.1.1.8 root 2194: #endif
1.1.1.4 root 2195:
1.1.1.7 root 2196: currprefs.cpu_idle = changed_prefs.cpu_idle;
2197: currprefs.ppc_cpu_idle = changed_prefs.ppc_cpu_idle;
2198: currprefs.reset_delay = changed_prefs.reset_delay;
2199:
2200: if (check_prefs_changed_cpu2()) {
2201: set_special(SPCFLAG_MODE_CHANGE);
2202: reset_frame_rate_hack();
2203: }
1.1.1.4 root 2204: }
2205:
2206: void init_m68k (void)
2207: {
2208: prefs_changed_cpu ();
2209: update_68k_cycles ();
2210:
1.1.1.10! root 2211: for (int i = 0 ; i < 256 ; i++) {
1.1.1.4 root 2212: int j;
2213: for (j = 0 ; j < 8 ; j++) {
2214: if (i & (1 << j)) break;
2215: }
2216: movem_index1[i] = j;
1.1.1.7 root 2217: movem_index2[i] = 7 - j;
1.1.1.4 root 2218: movem_next[i] = i & (~(1 << j));
2219: }
2220:
2221: #if COUNT_INSTRS
2222: {
2223: FILE *f = fopen (icountfilename (), "r");
2224: memset (instrcount, 0, sizeof instrcount);
2225: if (f) {
2226: uae_u32 opcode, count, total;
2227: TCHAR name[20];
1.1.1.7 root 2228: write_log (_T("Reading instruction count file...\n"));
1.1.1.4 root 2229: fscanf (f, "Total: %lu\n", &total);
1.1.1.7 root 2230: while (fscanf (f, "%x: %lu %s\n", &opcode, &count, name) == 3) {
1.1.1.4 root 2231: instrcount[opcode] = count;
2232: }
2233: fclose (f);
2234: }
2235: }
2236: #endif
2237:
2238: read_table68k ();
2239: do_merges ();
2240:
1.1.1.7 root 2241: write_log (_T("%d CPU functions\n"), nr_cpuop_funcs);
1.1.1.4 root 2242: }
2243:
2244: struct regstruct regs, mmu_backup_regs;
2245: struct flag_struct regflags;
1.1.1.7 root 2246: static int m68kpc_offset;
1.1.1.4 root 2247:
1.1.1.9 root 2248: static const TCHAR *fpsizes[] = {
2249: _T("L"),
2250: _T("S"),
2251: _T("X"),
2252: _T("P"),
2253: _T("W"),
2254: _T("D"),
2255: _T("B"),
2256: _T("P")
2257: };
2258: static const int fpsizeconv[] = {
2259: sz_long,
2260: sz_single,
2261: sz_extended,
2262: sz_packed,
2263: sz_word,
2264: sz_double,
2265: sz_byte,
2266: sz_packed
2267: };
2268: static const int datasizes[] = {
2269: 1,
2270: 2,
2271: 4,
2272: 4,
2273: 8,
2274: 12,
2275: 12
2276: };
2277:
2278: static void showea_val(TCHAR *buffer, uae_u16 opcode, uaecptr addr, int size)
2279: {
2280: struct mnemolookup *lookup;
2281: struct instr *table = &table68k[opcode];
2282:
1.1.1.10! root 2283:
! 2284: #ifndef WINUAE_FOR_HATARI
! 2285: if (addr >= 0xe90000 && addr < 0xf00000)
! 2286: goto skip;
! 2287: if (addr >= 0xdff000 && addr < 0xe00000)
! 2288: goto skip;
! 2289: #endif
! 2290:
1.1.1.9 root 2291: for (lookup = lookuptab; lookup->mnemo != table->mnemo; lookup++)
2292: ;
2293: if (!(lookup->flags & 1))
1.1.1.10! root 2294: goto skip;
1.1.1.9 root 2295: buffer += _tcslen(buffer);
2296: if (debug_safe_addr(addr, datasizes[size])) {
2297: bool cached = false;
2298: switch (size)
2299: {
2300: case sz_byte:
2301: {
2302: uae_u8 v = get_byte_cache_debug(addr, &cached);
2303: uae_u8 v2 = v;
2304: if (cached)
2305: v2 = get_byte_debug(addr);
2306: if (v != v2) {
2307: _stprintf(buffer, _T(" [%02x:%02x]"), v, v2);
2308: } else {
2309: _stprintf(buffer, _T(" [%s%02x]"), cached ? _T("*") : _T(""), v);
2310: }
2311: }
2312: break;
2313: case sz_word:
2314: {
2315: uae_u16 v = get_word_cache_debug(addr, &cached);
2316: uae_u16 v2 = v;
2317: if (cached)
2318: v2 = get_word_debug(addr);
2319: if (v != v2) {
2320: _stprintf(buffer, _T(" [%04x:%04x]"), v, v2);
2321: } else {
2322: _stprintf(buffer, _T(" [%s%04x]"), cached ? _T("*") : _T(""), v);
2323: }
2324: }
2325: break;
2326: case sz_long:
2327: {
2328: uae_u32 v = get_long_cache_debug(addr, &cached);
2329: uae_u32 v2 = v;
2330: if (cached)
2331: v2 = get_long_debug(addr);
2332: if (v != v2) {
2333: _stprintf(buffer, _T(" [%08x:%08x]"), v, v2);
2334: } else {
2335: _stprintf(buffer, _T(" [%s%08x]"), cached ? _T("*") : _T(""), v);
2336: }
2337: }
2338: break;
2339: case sz_single:
2340: {
2341: fpdata fp;
2342: fpp_to_single(&fp, get_long_debug(addr));
2343: _stprintf(buffer, _T("[%s]"), fpp_print(&fp, 0));
2344: }
2345: break;
2346: case sz_double:
2347: {
2348: fpdata fp;
2349: fpp_to_double(&fp, get_long_debug(addr), get_long_debug(addr + 4));
2350: _stprintf(buffer, _T("[%s]"), fpp_print(&fp, 0));
2351: }
2352: break;
2353: case sz_extended:
2354: {
2355: fpdata fp;
2356: fpp_to_exten(&fp, get_long_debug(addr), get_long_debug(addr + 4), get_long_debug(addr + 8));
2357: _stprintf(buffer, _T("[%s]"), fpp_print(&fp, 0));
2358: break;
2359: }
2360: case sz_packed:
2361: _stprintf(buffer, _T("[%08x%08x%08x]"), get_long_debug(addr), get_long_debug(addr + 4), get_long_debug(addr + 8));
2362: break;
2363: }
2364: }
1.1.1.10! root 2365: skip:
! 2366: #ifndef WINUAE_FOR_HATARI
! 2367: for (int i = 0; i < size; i++) {
! 2368: TCHAR name[256];
! 2369: if (debugmem_get_symbol(addr + i, name, sizeof(name) / sizeof(TCHAR))) {
! 2370: _stprintf(buffer + _tcslen(buffer), _T(" %s"), name);
! 2371: }
! 2372: }
! 2373: #else
! 2374: return;
! 2375: #endif
1.1.1.9 root 2376: }
1.1.1.4 root 2377:
1.1.1.10! root 2378: static uaecptr ShowEA_disp(uaecptr *pcp, uaecptr base, TCHAR *buffer, const TCHAR *name)
1.1.1.4 root 2379: {
1.1.1.10! root 2380: uaecptr addr;
1.1.1.4 root 2381: uae_u16 dp;
2382: int r;
2383: uae_u32 dispreg;
1.1.1.10! root 2384: uaecptr pc = *pcp;
! 2385: TCHAR mult[20];
! 2386:
! 2387: dp = get_iword_debug(pc);
! 2388: pc += 2;
! 2389:
! 2390: r = (dp & 0x7000) >> 12; // REGISTER
! 2391:
! 2392: dispreg = dp & 0x8000 ? m68k_areg(regs, r) : m68k_dreg(regs, r);
! 2393: if (!(dp & 0x800)) { // W/L
! 2394: dispreg = (uae_s32)(uae_s16)(dispreg);
! 2395: }
! 2396:
! 2397: if (currprefs.cpu_model >= 68020) {
! 2398: dispreg <<= (dp >> 9) & 3; // SCALE
! 2399: }
! 2400:
! 2401: int m = 1 << ((dp >> 9) & 3);
! 2402: mult[0] = 0;
! 2403: if (m > 1) {
! 2404: _stprintf(mult, _T("*%d"), m);
! 2405: }
! 2406:
! 2407: buffer[0] = 0;
! 2408: if ((dp & 0x100) && currprefs.cpu_model >= 68020) {
! 2409: TCHAR dr[20];
! 2410: // Full format extension (68020+)
! 2411: uae_s32 outer = 0, disp = 0;
! 2412: if (dp & 0x80) { // BS (base register suppress)
! 2413: base = 0;
! 2414: name = NULL;
! 2415: }
! 2416: _stprintf(dr, _T("%c%d.%c"), dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W');
! 2417: if (dp & 0x40) {
! 2418: dispreg = 0;
! 2419: dr[0] = 0;
! 2420: }
! 2421:
! 2422: _tcscpy(buffer, _T("("));
! 2423: TCHAR *p = buffer + _tcslen(buffer);
! 2424:
! 2425: if (dp & 3) {
! 2426: _stprintf(p, _T("["));
! 2427: p += _tcslen(p);
! 2428: }
! 2429:
! 2430: if ((dp & 0x30) == 0x20) { // BD SIZE = 2 (WORD)
! 2431: disp = (uae_s32)(uae_s16)get_iword_debug(pc);
! 2432: _stprintf(p, _T("$%04x,"), (uae_s16)disp);
! 2433: p += _tcslen(p);
! 2434: pc += 2;
! 2435: base += disp;
! 2436: } else if ((dp & 0x30) == 0x30) { // BD SIZE = 3 (LONG)
! 2437: disp = get_ilong_debug(pc);
! 2438: _stprintf(p, _T("$%08x,"), disp);
! 2439: p += _tcslen(p);
! 2440: pc += 4;
! 2441: base += disp;
! 2442: }
! 2443:
! 2444: if ((dp & 0x04) == 0x00 && name) {
! 2445: _stprintf(p, _T("%s,"), name);
! 2446: p += _tcslen(p);
! 2447: }
! 2448:
! 2449: if (dr[0] && (dp & 0x04) == 0) {
! 2450: _stprintf(p, _T("%s%s,"), dr, mult);
! 2451: p += _tcslen(p);
! 2452: }
! 2453:
! 2454: if (dp & 3) {
! 2455: if (p[-1] == ',')
! 2456: p--;
! 2457: _stprintf(p, _T("],"));
! 2458: p += _tcslen(p);
! 2459: }
! 2460:
! 2461: if (dr[0] && (dp & 0x04) != 0) {
! 2462: _stprintf(p, _T("%s%s,"), dr, mult);
! 2463: p += _tcslen(p);
! 2464: }
! 2465:
! 2466: if ((dp & 0x03) == 0x02) {
! 2467: outer = (uae_s32)(uae_s16)get_iword_debug(pc);
! 2468: _stprintf(p, _T("$%04x,"), (uae_s16)outer);
! 2469: p += _tcslen(p);
! 2470: pc += 2;
! 2471: } else if ((dp & 0x03) == 0x03) {
! 2472: outer = get_ilong_debug(pc);
! 2473: _stprintf(p, _T("$%08x,"), outer);
! 2474: p += _tcslen(p);
! 2475: pc += 4;
! 2476: }
! 2477:
! 2478: if (p[-1] == ',')
! 2479: p--;
! 2480: _stprintf(p, _T(")"));
! 2481: p += _tcslen(p);
! 2482:
! 2483: if ((dp & 0x4) == 0)
! 2484: base += dispreg;
! 2485: if (dp & 0x3)
! 2486: base = get_long_debug(base);
! 2487: if (dp & 0x4)
! 2488: base += dispreg;
! 2489:
! 2490: addr = base + outer;
! 2491:
! 2492: _stprintf(p, _T(" == $%08x"), addr);
! 2493: p += _tcslen(p);
! 2494:
! 2495: } else {
! 2496: // Brief format extension
! 2497: TCHAR regstr[20];
! 2498: uae_s8 disp8 = dp & 0xFF;
! 2499:
! 2500: regstr[0] = 0;
! 2501: _stprintf(regstr, _T(",%c%d.%c"), dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W');
! 2502: addr = base + (uae_s32)((uae_s8)disp8) + dispreg;
! 2503: _stprintf(buffer, _T("(%s%s%s,$%02x) == $%08x"), name, regstr, mult, disp8, addr);
! 2504: if (dp & 0x100) {
! 2505: _tcscat(buffer, _T(" (68020+)"));
! 2506: }
! 2507: }
! 2508:
! 2509: *pcp = pc;
! 2510: return addr;
! 2511: }
! 2512:
! 2513: static uaecptr ShowEA (void *f, uaecptr pc, uae_u16 opcode, int reg, amodes mode, wordsizes size, TCHAR *buf, uae_u32 *eaddr, int safemode)
! 2514: {
1.1.1.7 root 2515: uaecptr addr = pc;
1.1.1.10! root 2516: uae_s16 disp16;
1.1.1.4 root 2517: uae_s32 offset = 0;
2518: TCHAR buffer[80];
2519:
2520: switch (mode){
2521: case Dreg:
1.1.1.7 root 2522: _stprintf (buffer, _T("D%d"), reg);
1.1.1.4 root 2523: break;
2524: case Areg:
1.1.1.7 root 2525: _stprintf (buffer, _T("A%d"), reg);
1.1.1.4 root 2526: break;
2527: case Aind:
1.1.1.7 root 2528: _stprintf (buffer, _T("(A%d)"), reg);
1.1.1.4 root 2529: addr = regs.regs[reg + 8];
1.1.1.9 root 2530: showea_val(buffer, opcode, addr, size);
1.1.1.4 root 2531: break;
2532: case Aipi:
1.1.1.7 root 2533: _stprintf (buffer, _T("(A%d)+"), reg);
1.1.1.4 root 2534: addr = regs.regs[reg + 8];
1.1.1.9 root 2535: showea_val(buffer, opcode, addr, size);
1.1.1.4 root 2536: break;
2537: case Apdi:
1.1.1.7 root 2538: _stprintf (buffer, _T("-(A%d)"), reg);
1.1.1.4 root 2539: addr = regs.regs[reg + 8];
1.1.1.9 root 2540: showea_val(buffer, opcode, addr - datasizes[size], size);
1.1.1.4 root 2541: break;
2542: case Ad16:
2543: {
1.1.1.10! root 2544: TCHAR offtxt[8];
1.1.1.7 root 2545: disp16 = get_iword_debug (pc); pc += 2;
1.1.1.4 root 2546: if (disp16 < 0)
1.1.1.7 root 2547: _stprintf (offtxt, _T("-$%04x"), -disp16);
1.1.1.4 root 2548: else
1.1.1.7 root 2549: _stprintf (offtxt, _T("$%04x"), disp16);
1.1.1.4 root 2550: addr = m68k_areg (regs, reg) + disp16;
1.1.1.10! root 2551: _stprintf (buffer, _T("(A%d,%s) == $%08x"), reg, offtxt, addr);
1.1.1.9 root 2552: showea_val(buffer, opcode, addr, size);
1.1.1.4 root 2553: }
2554: break;
2555: case Ad8r:
1.1.1.10! root 2556: {
1.1.1.4 root 2557: TCHAR name[10];
1.1.1.10! root 2558: _stprintf(name, _T("A%d"), reg);
! 2559: addr = ShowEA_disp(&pc, m68k_areg(regs, reg), buffer, name);
! 2560: showea_val(buffer, opcode, addr, size);
1.1.1.4 root 2561: }
2562: break;
2563: case PC16:
1.1.1.7 root 2564: disp16 = get_iword_debug (pc); pc += 2;
1.1.1.4 root 2565: addr += (uae_s16)disp16;
1.1.1.7 root 2566: _stprintf (buffer, _T("(PC,$%04x) == $%08x"), disp16 & 0xffff, addr);
1.1.1.9 root 2567: showea_val(buffer, opcode, addr, size);
1.1.1.4 root 2568: break;
2569: case PC8r:
1.1.1.10! root 2570: {
! 2571: addr = ShowEA_disp(&pc, addr, buffer, _T("PC"));
! 2572: showea_val(buffer, opcode, addr, size);
1.1.1.4 root 2573: }
2574: break;
2575: case absw:
1.1.1.7 root 2576: addr = (uae_s32)(uae_s16)get_iword_debug (pc);
1.1.1.9 root 2577: _stprintf (buffer, _T("$%04x"), (uae_u16)addr);
1.1.1.7 root 2578: pc += 2;
1.1.1.9 root 2579: showea_val(buffer, opcode, addr, size);
1.1.1.4 root 2580: break;
2581: case absl:
1.1.1.7 root 2582: addr = get_ilong_debug (pc);
2583: _stprintf (buffer, _T("$%08x"), addr);
2584: pc += 4;
1.1.1.9 root 2585: showea_val(buffer, opcode, addr, size);
1.1.1.4 root 2586: break;
2587: case imm:
2588: switch (size){
2589: case sz_byte:
1.1.1.7 root 2590: _stprintf (buffer, _T("#$%02x"), (get_iword_debug (pc) & 0xff));
2591: pc += 2;
1.1.1.4 root 2592: break;
2593: case sz_word:
1.1.1.7 root 2594: _stprintf (buffer, _T("#$%04x"), (get_iword_debug (pc) & 0xffff));
2595: pc += 2;
1.1.1.4 root 2596: break;
2597: case sz_long:
1.1.1.7 root 2598: _stprintf(buffer, _T("#$%08x"), (get_ilong_debug(pc)));
2599: pc += 4;
2600: break;
2601: case sz_single:
2602: {
2603: fpdata fp;
1.1.1.9 root 2604: fpp_to_single(&fp, get_ilong_debug(pc));
2605: _stprintf(buffer, _T("#%s"), fpp_print(&fp, 0));
1.1.1.7 root 2606: pc += 4;
2607: }
2608: break;
2609: case sz_double:
2610: {
2611: fpdata fp;
1.1.1.9 root 2612: fpp_to_double(&fp, get_ilong_debug(pc), get_ilong_debug(pc + 4));
2613: _stprintf(buffer, _T("#%s"), fpp_print(&fp, 0));
1.1.1.7 root 2614: pc += 8;
2615: }
2616: break;
2617: case sz_extended:
2618: {
2619: fpdata fp;
1.1.1.9 root 2620: fpp_to_exten(&fp, get_ilong_debug(pc), get_ilong_debug(pc + 4), get_ilong_debug(pc + 8));
2621: _stprintf(buffer, _T("#%s"), fpp_print(&fp, 0));
1.1.1.7 root 2622: pc += 12;
2623: break;
2624: }
2625: case sz_packed:
2626: _stprintf(buffer, _T("#$%08x%08x%08x"), get_ilong_debug(pc), get_ilong_debug(pc + 4), get_ilong_debug(pc + 8));
2627: pc += 12;
1.1.1.4 root 2628: break;
2629: default:
2630: break;
2631: }
2632: break;
2633: case imm0:
1.1.1.7 root 2634: offset = (uae_s32)(uae_s8)get_iword_debug (pc);
2635: _stprintf (buffer, _T("#$%02x"), (uae_u32)(offset & 0xff));
2636: addr = pc + 2 + offset;
1.1.1.10! root 2637: if ((opcode & 0xf000) == 0x6000) {
! 2638: showea_val(buffer, opcode, addr, 1);
! 2639: }
1.1.1.7 root 2640: pc += 2;
1.1.1.4 root 2641: break;
2642: case imm1:
1.1.1.7 root 2643: offset = (uae_s32)(uae_s16)get_iword_debug (pc);
1.1.1.4 root 2644: buffer[0] = 0;
1.1.1.7 root 2645: _stprintf (buffer, _T("#$%04x"), (uae_u32)(offset & 0xffff));
2646: addr = pc + offset;
1.1.1.10! root 2647: if ((opcode & 0xf000) == 0x6000) {
! 2648: showea_val(buffer, opcode, addr, 2);
! 2649: }
1.1.1.7 root 2650: pc += 2;
1.1.1.4 root 2651: break;
2652: case imm2:
1.1.1.7 root 2653: offset = (uae_s32)get_ilong_debug (pc);
2654: _stprintf (buffer, _T("#$%08x"), (uae_u32)offset);
2655: addr = pc + offset;
1.1.1.10! root 2656: if ((opcode & 0xf000) == 0x6000) {
! 2657: showea_val(buffer, opcode, addr, 4);
! 2658: }
1.1.1.7 root 2659: pc += 4;
1.1.1.4 root 2660: break;
2661: case immi:
2662: offset = (uae_s32)(uae_s8)(reg & 0xff);
1.1.1.9 root 2663: _stprintf (buffer, _T("#$%02x"), (uae_u8)offset);
1.1.1.7 root 2664: addr = pc + offset;
1.1.1.4 root 2665: break;
2666: default:
2667: break;
2668: }
1.1.1.10! root 2669: if (buf == NULL)
1.1.1.7 root 2670: f_out (f, _T("%s"), buffer);
1.1.1.4 root 2671: else
2672: _tcscat (buf, buffer);
2673: if (eaddr)
2674: *eaddr = addr;
1.1.1.7 root 2675: return pc;
1.1.1.4 root 2676: }
2677:
2678: #if 0
2679: /* The plan is that this will take over the job of exception 3 handling -
2680: * the CPU emulation functions will just do a longjmp to m68k_go whenever
2681: * they hit an odd address. */
2682: static int verify_ea (int reg, amodes mode, wordsizes size, uae_u32 *val)
2683: {
2684: uae_u16 dp;
2685: uae_s8 disp8;
2686: uae_s16 disp16;
2687: int r;
2688: uae_u32 dispreg;
2689: uaecptr addr;
2690: uae_s32 offset = 0;
2691:
2692: switch (mode){
2693: case Dreg:
2694: *val = m68k_dreg (regs, reg);
2695: return 1;
2696: case Areg:
2697: *val = m68k_areg (regs, reg);
2698: return 1;
2699:
2700: case Aind:
2701: case Aipi:
2702: addr = m68k_areg (regs, reg);
2703: break;
2704: case Apdi:
2705: addr = m68k_areg (regs, reg);
2706: break;
2707: case Ad16:
2708: disp16 = get_iword_1 (m68kpc_offset); m68kpc_offset += 2;
2709: addr = m68k_areg (regs, reg) + (uae_s16)disp16;
2710: break;
2711: case Ad8r:
2712: addr = m68k_areg (regs, reg);
2713: d8r_common:
2714: dp = get_iword_1 (m68kpc_offset); m68kpc_offset += 2;
2715: disp8 = dp & 0xFF;
2716: r = (dp & 0x7000) >> 12;
2717: dispreg = dp & 0x8000 ? m68k_areg (regs, r) : m68k_dreg (regs, r);
2718: if (!(dp & 0x800)) dispreg = (uae_s32)(uae_s16)(dispreg);
2719: dispreg <<= (dp >> 9) & 3;
2720:
2721: if (dp & 0x100) {
2722: uae_s32 outer = 0, disp = 0;
2723: uae_s32 base = addr;
2724: if (dp & 0x80) base = 0;
2725: if (dp & 0x40) dispreg = 0;
2726: if ((dp & 0x30) == 0x20) { disp = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; }
2727: if ((dp & 0x30) == 0x30) { disp = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; }
2728: base += disp;
2729:
2730: if ((dp & 0x3) == 0x2) { outer = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; }
2731: if ((dp & 0x3) == 0x3) { outer = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; }
2732:
2733: if (!(dp & 4)) base += dispreg;
2734: if (dp & 3) base = get_long (base);
2735: if (dp & 4) base += dispreg;
2736:
2737: addr = base + outer;
2738: } else {
2739: addr += (uae_s32)((uae_s8)disp8) + dispreg;
2740: }
2741: break;
2742: case PC16:
2743: addr = m68k_getpc () + m68kpc_offset;
2744: disp16 = get_iword_1 (m68kpc_offset); m68kpc_offset += 2;
2745: addr += (uae_s16)disp16;
2746: break;
2747: case PC8r:
2748: addr = m68k_getpc () + m68kpc_offset;
2749: goto d8r_common;
2750: case absw:
2751: addr = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset);
2752: m68kpc_offset += 2;
2753: break;
2754: case absl:
2755: addr = get_ilong_1 (m68kpc_offset);
2756: m68kpc_offset += 4;
2757: break;
2758: case imm:
2759: switch (size){
2760: case sz_byte:
2761: *val = get_iword_1 (m68kpc_offset) & 0xff;
2762: m68kpc_offset += 2;
2763: break;
2764: case sz_word:
2765: *val = get_iword_1 (m68kpc_offset) & 0xffff;
2766: m68kpc_offset += 2;
2767: break;
2768: case sz_long:
2769: *val = get_ilong_1 (m68kpc_offset);
2770: m68kpc_offset += 4;
2771: break;
2772: default:
2773: break;
2774: }
2775: return 1;
2776: case imm0:
2777: *val = (uae_s32)(uae_s8)get_iword_1 (m68kpc_offset);
2778: m68kpc_offset += 2;
2779: return 1;
2780: case imm1:
2781: *val = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset);
2782: m68kpc_offset += 2;
2783: return 1;
2784: case imm2:
2785: *val = get_ilong_1 (m68kpc_offset);
2786: m68kpc_offset += 4;
2787: return 1;
2788: case immi:
2789: *val = (uae_s32)(uae_s8)(reg & 0xff);
2790: return 1;
2791: default:
2792: addr = 0;
2793: break;
2794: }
2795: if ((addr & 1) == 0)
2796: return 1;
2797:
2798: last_addr_for_exception_3 = m68k_getpc () + m68kpc_offset;
2799: last_fault_for_exception_3 = addr;
2800: last_writeaccess_for_exception_3 = 0;
2801: last_instructionaccess_for_exception_3 = 0;
2802: return 0;
2803: }
2804: #endif
2805:
2806: int get_cpu_model (void)
2807: {
2808: return currprefs.cpu_model;
2809: }
2810:
1.1.1.7 root 2811: #ifndef WINUAE_FOR_HATARI
2812: STATIC_INLINE int in_rom (uaecptr pc)
1.1.1.4 root 2813: {
1.1.1.7 root 2814: return (munge24 (pc) & 0xFFF80000) == 0xF80000;
1.1.1.4 root 2815: }
2816:
1.1.1.7 root 2817: STATIC_INLINE int in_rtarea (uaecptr pc)
1.1.1.4 root 2818: {
1.1.1.9 root 2819: return (munge24 (pc) & 0xFFFF0000) == rtarea_base && (uae_boot_rom_type || currprefs.uaeboard > 0);
1.1.1.4 root 2820: }
1.1.1.7 root 2821: #endif
1.1.1.4 root 2822:
1.1.1.7 root 2823: STATIC_INLINE void wait_memory_cycles (void)
1.1.1.4 root 2824: {
1.1.1.7 root 2825: if (regs.memory_waitstate_cycles) {
2826: x_do_cycles(regs.memory_waitstate_cycles);
2827: regs.memory_waitstate_cycles = 0;
1.1.1.4 root 2828: }
1.1.1.7 root 2829: if (regs.ce020extracycles >= 16) {
2830: regs.ce020extracycles = 0;
2831: x_do_cycles(4 * CYCLE_UNIT);
1.1.1.4 root 2832: }
2833: }
2834:
1.1.1.7 root 2835: STATIC_INLINE int adjust_cycles (int cycles)
1.1.1.4 root 2836: {
1.1.1.7 root 2837: int mc = regs.memory_waitstate_cycles;
2838: regs.memory_waitstate_cycles = 0;
2839: if (currprefs.m68k_speed < 0 || cycles_mult == 0)
2840: return cycles + mc;
2841: cycles *= cycles_mult;
2842: cycles /= CYCLES_DIV;
2843: return cycles + mc;
1.1.1.4 root 2844: }
2845:
1.1.1.9 root 2846: void m68k_cancel_idle(void)
2847: {
2848: #ifndef WINUAE_FOR_HATARI
2849: cpu_last_stop_vpos = -1;
2850: #endif
2851: }
2852:
1.1.1.8 root 2853: static void m68k_set_stop(void)
2854: {
2855: if (regs.stopped)
2856: return;
2857: regs.stopped = 1;
2858: set_special(SPCFLAG_STOP);
2859: #ifndef WINUAE_FOR_HATARI
1.1.1.9 root 2860: if (cpu_last_stop_vpos >= 0) {
2861: cpu_last_stop_vpos = vpos;
2862: }
1.1.1.8 root 2863: #endif
2864: }
2865:
2866: static void m68k_unset_stop(void)
2867: {
2868: regs.stopped = 0;
2869: unset_special(SPCFLAG_STOP);
2870: #ifndef WINUAE_FOR_HATARI
1.1.1.9 root 2871: if (cpu_last_stop_vpos >= 0) {
2872: cpu_stopped_lines += vpos - cpu_last_stop_vpos;
2873: cpu_last_stop_vpos = vpos;
2874: }
1.1.1.8 root 2875: #endif
2876: }
2877:
1.1.1.9 root 2878: static void activate_trace(void)
2879: {
2880: unset_special (SPCFLAG_TRACE);
2881: set_special (SPCFLAG_DOTRACE);
2882: }
2883:
1.1.1.10! root 2884: // make sure interrupt is checked immediately after current instruction
! 2885: static void doint_imm(void)
! 2886: {
! 2887: doint();
! 2888: if (!currprefs.cachesize && !(regs.spcflags & SPCFLAG_INT) && (regs.spcflags & SPCFLAG_DOINT))
! 2889: set_special(SPCFLAG_INT);
! 2890: }
! 2891:
1.1.1.9 root 2892: void REGPARAM2 MakeSR (void)
1.1.1.4 root 2893: {
2894: regs.sr = ((regs.t1 << 15) | (regs.t0 << 14)
2895: | (regs.s << 13) | (regs.m << 12) | (regs.intmask << 8)
2896: | (GET_XFLG () << 4) | (GET_NFLG () << 3)
2897: | (GET_ZFLG () << 2) | (GET_VFLG () << 1)
2898: | GET_CFLG ());
2899: }
2900:
1.1.1.8 root 2901: static void SetSR (uae_u16 sr)
1.1.1.4 root 2902: {
1.1.1.7 root 2903: regs.sr &= 0xff00;
2904: regs.sr |= sr;
1.1.1.4 root 2905:
2906: SET_XFLG ((regs.sr >> 4) & 1);
2907: SET_NFLG ((regs.sr >> 3) & 1);
2908: SET_ZFLG ((regs.sr >> 2) & 1);
2909: SET_VFLG ((regs.sr >> 1) & 1);
2910: SET_CFLG (regs.sr & 1);
1.1.1.7 root 2911: }
2912:
1.1.1.9 root 2913: static void MakeFromSR_x(int t0trace)
1.1.1.7 root 2914: {
2915: int oldm = regs.m;
2916: int olds = regs.s;
1.1.1.9 root 2917: int oldt0 = regs.t0;
2918: int oldt1 = regs.t1;
1.1.1.7 root 2919:
2920: SET_XFLG ((regs.sr >> 4) & 1);
2921: SET_NFLG ((regs.sr >> 3) & 1);
2922: SET_ZFLG ((regs.sr >> 2) & 1);
2923: SET_VFLG ((regs.sr >> 1) & 1);
2924: SET_CFLG (regs.sr & 1);
2925: if (regs.t1 == ((regs.sr >> 15) & 1) &&
2926: regs.t0 == ((regs.sr >> 14) & 1) &&
2927: regs.s == ((regs.sr >> 13) & 1) &&
1.1.1.4 root 2928: regs.m == ((regs.sr >> 12) & 1) &&
2929: regs.intmask == ((regs.sr >> 8) & 7))
2930: return;
2931: regs.t1 = (regs.sr >> 15) & 1;
2932: regs.t0 = (regs.sr >> 14) & 1;
2933: regs.s = (regs.sr >> 13) & 1;
2934: regs.m = (regs.sr >> 12) & 1;
2935: regs.intmask = (regs.sr >> 8) & 7;
2936: if (currprefs.cpu_model >= 68020) {
2937: /* 68060 does not have MSP but does have M-bit.. */
2938: if (currprefs.cpu_model >= 68060)
2939: regs.msp = regs.isp;
2940: if (olds != regs.s) {
2941: if (olds) {
2942: if (oldm)
2943: regs.msp = m68k_areg (regs, 7);
2944: else
2945: regs.isp = m68k_areg (regs, 7);
2946: m68k_areg (regs, 7) = regs.usp;
2947: } else {
2948: regs.usp = m68k_areg (regs, 7);
2949: m68k_areg (regs, 7) = regs.m ? regs.msp : regs.isp;
2950: }
2951: } else if (olds && oldm != regs.m) {
2952: if (oldm) {
2953: regs.msp = m68k_areg (regs, 7);
2954: m68k_areg (regs, 7) = regs.isp;
2955: } else {
2956: regs.isp = m68k_areg (regs, 7);
2957: m68k_areg (regs, 7) = regs.msp;
2958: }
2959: }
2960: if (currprefs.cpu_model >= 68060)
2961: regs.t0 = 0;
2962: } else {
2963: regs.t0 = regs.m = 0;
2964: if (olds != regs.s) {
2965: if (olds) {
2966: regs.isp = m68k_areg (regs, 7);
2967: m68k_areg (regs, 7) = regs.usp;
2968: } else {
2969: regs.usp = m68k_areg (regs, 7);
2970: m68k_areg (regs, 7) = regs.isp;
2971: }
2972: }
2973: }
2974: if (currprefs.mmu_model)
2975: mmu_set_super (regs.s != 0);
2976:
1.1.1.10! root 2977: doint_imm();
1.1.1.9 root 2978: if (regs.t1 || regs.t0) {
1.1.1.4 root 2979: set_special (SPCFLAG_TRACE);
1.1.1.9 root 2980: } else {
1.1.1.4 root 2981: /* Keep SPCFLAG_DOTRACE, we still want a trace exception for
2982: SR-modifying instructions (including STOP). */
2983: unset_special (SPCFLAG_TRACE);
1.1.1.9 root 2984: }
2985: // Stop SR-modification does not generate T0
2986: // If this SR modification set Tx bit, no trace until next instruction.
2987: if ((oldt0 && t0trace && currprefs.cpu_model >= 68020) || oldt1) {
2988: // Always trace if Tx bits were already set, even if this SR modification cleared them.
2989: activate_trace();
2990: }
2991: }
2992:
2993: void REGPARAM2 MakeFromSR_T0(void)
2994: {
2995: MakeFromSR_x(1);
2996: }
2997: void REGPARAM2 MakeFromSR(void)
2998: {
2999: MakeFromSR_x(0);
1.1.1.4 root 3000: }
3001:
1.1.1.8 root 3002: static void exception_check_trace (int nr)
1.1.1.4 root 3003: {
3004: unset_special (SPCFLAG_TRACE | SPCFLAG_DOTRACE);
3005: if (regs.t1 && !regs.t0) {
3006: /* trace stays pending if exception is div by zero, chk,
3007: * trapv or trap #x
3008: */
3009: if (nr == 5 || nr == 6 || nr == 7 || (nr >= 32 && nr <= 47))
3010: set_special (SPCFLAG_DOTRACE);
3011: }
1.1.1.8 root 3012: regs.t1 = regs.t0 = 0;
1.1.1.4 root 3013: }
3014:
3015: static void exception_debug (int nr)
3016: {
1.1.1.7 root 3017: #ifdef WINUAE_FOR_HATARI
1.1.1.8 root 3018: if (unlikely(ExceptionDebugMask & EXCEPT_NOHANDLER) && STMemory_ReadLong(regs.vbr + 4*nr) == 0) {
1.1.1.10! root 3019: fprintf(stderr,"Uninitialized exception handler #%i!\n", nr);
1.1.1.8 root 3020: DebugUI(REASON_CPU_EXCEPTION);
3021: } else {
3022: DebugUI_Exceptions(nr, M68K_GETPC);
3023: }
1.1.1.9 root 3024: #else
3025: #ifdef DEBUGGER
3026: if (!exception_debugging)
3027: return;
3028: console_out_f (_T("Exception %d, PC=%08X\n"), nr, M68K_GETPC);
3029: #endif
1.1.1.7 root 3030: #endif
1.1.1.4 root 3031: }
3032:
1.1.1.7 root 3033: #ifdef CPUEMU_13
1.1.1.4 root 3034:
3035: /* cycle-exact exception handler, 68000 only */
3036:
3037: /*
3038:
3039: Address/Bus Error:
3040:
1.1.1.7 root 3041: - 8 idle cycles
1.1.1.4 root 3042: - write PC low word
3043: - write SR
3044: - write PC high word
3045: - write instruction word
3046: - write fault address low word
3047: - write status code
3048: - write fault address high word
3049: - 2 idle cycles
3050: - read exception address high word
3051: - read exception address low word
3052: - prefetch
3053: - 2 idle cycles
3054: - prefetch
3055:
3056: Division by Zero:
3057:
1.1.1.7 root 3058: - 8 idle cycles
1.1.1.4 root 3059: - write PC low word
3060: - write SR
3061: - write PC high word
3062: - read exception address high word
3063: - read exception address low word
3064: - prefetch
3065: - 2 idle cycles
3066: - prefetch
3067:
3068: Traps:
3069:
1.1.1.7 root 3070: - 4 idle cycles
1.1.1.4 root 3071: - write PC low word
3072: - write SR
3073: - write PC high word
3074: - read exception address high word
3075: - read exception address low word
3076: - prefetch
3077: - 2 idle cycles
3078: - prefetch
3079:
3080: TrapV:
3081:
1.1.1.7 root 3082: (- normal prefetch done by TRAPV)
1.1.1.4 root 3083: - write PC low word
3084: - write SR
3085: - write PC high word
3086: - read exception address high word
3087: - read exception address low word
3088: - prefetch
3089: - 2 idle cycles
3090: - prefetch
3091:
3092: CHK:
3093:
1.1.1.7 root 3094: - 8 idle cycles
1.1.1.4 root 3095: - write PC low word
3096: - write SR
3097: - write PC high word
3098: - read exception address high word
3099: - read exception address low word
3100: - prefetch
3101: - 2 idle cycles
3102: - prefetch
3103:
3104: Illegal Instruction:
1.1.1.7 root 3105: Privilege violation:
1.1.1.8 root 3106: Trace:
1.1.1.7 root 3107: Line A:
3108: Line F:
1.1.1.4 root 3109:
1.1.1.7 root 3110: - 4 idle cycles
1.1.1.4 root 3111: - write PC low word
3112: - write SR
3113: - write PC high word
3114: - read exception address high word
3115: - read exception address low word
3116: - prefetch
3117: - 2 idle cycles
3118: - prefetch
3119:
1.1.1.7 root 3120: Interrupt:
1.1.1.4 root 3121:
3122: - 6 idle cycles
3123: - write PC low word
3124: - read exception number byte from (0xfffff1 | (interrupt number << 1))
3125: - 4 idle cycles
3126: - write SR
3127: - write PC high word
3128: - read exception address high word
3129: - read exception address low word
3130: - prefetch
3131: - 2 idle cycles
3132: - prefetch
3133:
3134: */
3135:
1.1.1.7 root 3136: static int iack_cycle(int nr)
3137: {
3138: int vector;
3139:
3140: #ifndef WINUAE_FOR_HATARI
3141: if (1) {
3142: // non-autovectored
3143: vector = x_get_byte(0x00fffff1 | ((nr - 24) << 1));
3144: if (currprefs.cpu_cycle_exact)
3145: x_do_cycles(4 * cpucycleunit);
3146: } else {
3147: // autovectored
3148:
3149: }
3150: #else
3151: int iack_start = CPU_IACK_CYCLES_START;
3152: int e_cycles;
1.1.1.8 root 3153: int cycle_exact = currprefs.cpu_cycle_exact && !currprefs.mmu_model;
1.1.1.7 root 3154:
3155: /* In cycle exact mode, the cycles before reaching IACK are already counted */
1.1.1.8 root 3156: if (cycle_exact)
1.1.1.7 root 3157: iack_start = 0;
3158:
3159: /* Pending bits / vector number can change before the end of the IACK sequence. */
3160: /* We need to handle MFP/DSP and HBL/VBL cases for this. */
3161: /* - Level 6 (MFP/DSP) use vectored interrupts */
3162: /* - Level 2 (HBL) and 4 (VBL) use auto-vectored interrupts and require sync with E-clock */
3163: vector = nr;
3164: if ( nr == 30 ) /* MFP or DSP */
3165: {
3166: vector = -1;
3167: if (bDspEnabled) /* Check DSP first */
3168: {
3169: /* TODO : For DSP, we just get the vector, we don't add IACK cycles */
3170: vector = DSP_ProcessIACK ();
3171: }
3172:
3173: if ( vector < 0 ) /* No DSP, check MFP */
3174: {
1.1.1.8 root 3175: if (cycle_exact)
3176: {
3177: x_do_cycles ( ( iack_start + CPU_IACK_CYCLES_MFP ) * cpucycleunit );
3178: /* Flush all CE cycles so far to update PendingInterruptCount */
3179: M68000_AddCycles_CE ( currcycle * 2 / CYCLE_UNIT );
3180: currcycle=0;
3181: }
3182: else
3183: M68000_AddCycles ( iack_start + CPU_IACK_CYCLES_MFP );
3184:
1.1.1.7 root 3185: CPU_IACK = true;
3186: while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) )
3187: CALL_VAR(PendingInterruptFunction);
3188: vector = MFP_ProcessIACK ( nr );
3189: CPU_IACK = false;
3190: }
1.1.1.8 root 3191:
3192: if ( vector >= 0 ) /* We have a valid vector for level 6 */
3193: {
3194: /* If a DSP IRQ is pending, we don't clear level 6 pending bit, else the DSP IRQ */
3195: /* will never be processed. If there's no DSP IRQ, we clear level 6 pending bit now */
3196: /* and if there's a lower MFP pending int, level 6 will be set again at the next instruction */
3197: if ( DSP_GetHREQ() == 0 )
3198: pendingInterrupts &= ~( 1 << 6 );
3199: }
1.1.1.7 root 3200: }
3201: else if ( ( nr == 26 ) || ( nr == 28 ) ) /* HBL / VBL */
3202: {
1.1.1.8 root 3203: if (cycle_exact)
3204: {
3205: /* In CE mode, iack_start = 0, no need to call x_do_cycles() */
3206: //x_do_cycles ( ( iack_start + CPU_IACK_CYCLES_VIDEO_CE + e_cycles ) * cpucycleunit );
3207: /* Flush all CE cycles so far before calling M68000_WaitEClock() */
3208: M68000_AddCycles_CE ( currcycle * 2 / CYCLE_UNIT );
3209: currcycle = 0;
3210: }
3211: else
3212: M68000_AddCycles ( iack_start );
3213:
1.1.1.7 root 3214: e_cycles = M68000_WaitEClock ();
1.1.1.8 root 3215: // fprintf ( stderr , "wait e clock %d\n" , e_cycles);
3216:
3217: if (cycle_exact)
3218: {
3219: x_do_cycles ( ( e_cycles + CPU_IACK_CYCLES_VIDEO_CE ) * cpucycleunit );
3220: /* Flush all CE cycles so far to update PendingInterruptCount */
3221: M68000_AddCycles_CE ( currcycle * 2 / CYCLE_UNIT );
3222: currcycle = 0;
3223: }
3224: else
3225: M68000_AddCycles ( e_cycles + CPU_IACK_CYCLES_VIDEO_CE );
1.1.1.7 root 3226:
3227: CPU_IACK = true;
3228: while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) )
3229: CALL_VAR(PendingInterruptFunction);
3230: if ( MFP_UpdateNeeded == true )
3231: MFP_UpdateIRQ ( 0 ); /* update MFP's state if some internal timers related to MFP expired */
1.1.1.8 root 3232: pendingInterrupts &= ~( 1 << ( nr - 24 ) ); /* clear HBL or VBL pending bit (even if an MFP timer occurred during IACK) */
1.1.1.7 root 3233: CPU_IACK = false;
3234: }
3235:
3236: /* TODO If there was no DSP and no MFP IRQ, then we have a spurious interrupt */
3237: /* In that case, we use vector 24 and we jump to $60 */
3238: if ( vector < 0 )
3239: {
3240: }
1.1.1.8 root 3241:
3242: /* Add 4 idle cycles for CE mode. For non-CE mode, this will be counted in add_approximate_exception_cycles() */
3243: if (cycle_exact)
3244: x_do_cycles( 4 * cpucycleunit );
1.1.1.7 root 3245: #endif
3246: return vector;
3247: }
3248:
3249: static void Exception_ce000 (int nr)
1.1.1.4 root 3250: {
3251: uae_u32 currpc = m68k_getpc (), newpc;
3252: int sv = regs.s;
1.1.1.7 root 3253: int start, interrupt;
3254: int vector_nr = nr;
1.1.1.4 root 3255:
1.1.1.8 root 3256: //fprintf ( stderr , "ex in %d %ld %ld\n" , nr , currcycle , CyclesGlobalClockCounter );
1.1.1.7 root 3257: start = 6;
1.1.1.4 root 3258: interrupt = nr >= 24 && nr < 24 + 8;
1.1.1.7 root 3259: if (!interrupt) {
3260: start = 8;
3261: if (nr == 7) // TRAPV
3262: start = 0;
3263: else if (nr >= 32 && nr < 32 + 16) // TRAP #x
3264: start = 4;
1.1.1.8 root 3265: else if (nr == 4 || nr == 8 || nr == 9 || nr == 10 || nr == 11) // ILLG, PRIV, TRACE, LINEA, LINEF
1.1.1.7 root 3266: start = 4;
3267: }
1.1.1.4 root 3268:
3269: if (start)
1.1.1.7 root 3270: x_do_cycles (start * cpucycleunit);
1.1.1.4 root 3271:
1.1.1.7 root 3272: #ifdef WINUAE_FOR_HATARI
3273: LOG_TRACE(TRACE_CPU_EXCEPTION, "cpu exception %d currpc %x buspc %x newpc %x fault_e3 %x op_e3 %hx addr_e3 %x SR %x\n",
3274: nr, currpc, regs.instruction_pc, STMemory_ReadLong (regs.vbr + 4*nr), last_fault_for_exception_3, last_op_for_exception_3, last_addr_for_exception_3, regs.sr);
3275: #endif
1.1.1.4 root 3276: exception_debug (nr);
3277: MakeSR ();
3278:
3279: if (!regs.s) {
3280: regs.usp = m68k_areg (regs, 7);
3281: m68k_areg (regs, 7) = regs.isp;
3282: regs.s = 1;
3283: }
3284: if (nr == 2 || nr == 3) { /* 2=bus error, 3=address error */
1.1.1.7 root 3285: if ((m68k_areg(regs, 7) & 1) || exception_in_exception < 0) {
1.1.1.8 root 3286: cpu_halt (CPU_HALT_DOUBLE_FAULT);
1.1.1.7 root 3287: return;
3288: }
1.1.1.4 root 3289: uae_u16 mode = (sv ? 4 : 0) | (last_instructionaccess_for_exception_3 ? 2 : 1);
3290: mode |= last_writeaccess_for_exception_3 ? 0 : 16;
1.1.1.7 root 3291: mode |= last_notinstruction_for_exception_3 ? 8 : 0;
3292: // undocumented bits seem to contain opcode
3293: mode |= last_op_for_exception_3 & ~31;
1.1.1.4 root 3294: m68k_areg (regs, 7) -= 14;
1.1.1.7 root 3295: exception_in_exception = -1;
3296: x_put_word (m68k_areg (regs, 7) + 12, last_addr_for_exception_3);
3297: x_put_word (m68k_areg (regs, 7) + 8, regs.sr);
3298: x_put_word (m68k_areg (regs, 7) + 10, last_addr_for_exception_3 >> 16);
3299: x_put_word (m68k_areg (regs, 7) + 6, last_op_for_exception_3);
3300: x_put_word (m68k_areg (regs, 7) + 4, last_fault_for_exception_3);
3301: x_put_word (m68k_areg (regs, 7) + 0, mode);
3302: x_put_word (m68k_areg (regs, 7) + 2, last_fault_for_exception_3 >> 16);
3303: x_do_cycles (2 * cpucycleunit);
1.1.1.8 root 3304: #ifndef WINUAE_FOR_HATARI
1.1.1.7 root 3305: write_log (_T("Exception %d (%04x %x) at %x -> %x!\n"),
3306: nr, last_op_for_exception_3, last_addr_for_exception_3, currpc, get_long_debug (4 * nr));
1.1.1.8 root 3307: #else
1.1.1.10! root 3308: if (nr != 2 || M68000_IsVerboseBusError(currpc, last_fault_for_exception_3))
! 3309: Log_Printf(LOG_WARN, "%s Error %s at address $%x, PC=$%x addr_e3=%x op_e3=%x\n",
! 3310: nr == 2 ? "Bus" : "Address",
! 3311: last_writeaccess_for_exception_3 ? "writing" : "reading",
! 3312: last_fault_for_exception_3, currpc,
! 3313: last_addr_for_exception_3 , last_op_for_exception_3);
1.1.1.7 root 3314: #endif
1.1.1.4 root 3315: goto kludge_me_do;
3316: }
1.1.1.7 root 3317: if (currprefs.cpu_model == 68010) {
3318: // 68010 creates only format 0 and 8 stack frames
3319: m68k_areg (regs, 7) -= 8;
3320: if (m68k_areg(regs, 7) & 1) {
3321: exception3_notinstruction(regs.ir, m68k_areg(regs, 7) + 4);
3322: return;
3323: }
3324: exception_in_exception = 1;
3325: x_put_word (m68k_areg (regs, 7) + 4, currpc); // write low address
3326: if (interrupt)
3327: vector_nr = iack_cycle(nr);
3328: x_put_word (m68k_areg (regs, 7) + 0, regs.sr); // write SR
3329: x_put_word (m68k_areg (regs, 7) + 2, currpc >> 16); // write high address
3330: x_put_word (m68k_areg (regs, 7) + 6, vector_nr * 4);
3331: } else {
3332: m68k_areg (regs, 7) -= 6;
3333: if (m68k_areg(regs, 7) & 1) {
3334: exception3_notinstruction(regs.ir, m68k_areg(regs, 7) + 4);
3335: return;
3336: }
3337: exception_in_exception = 1;
3338: x_put_word (m68k_areg (regs, 7) + 4, currpc); // write low address
1.1.1.8 root 3339: //fprintf ( stderr , "ex iack1 %d %ld\n" , nr , currcycle );
1.1.1.7 root 3340: if (interrupt)
3341: vector_nr = iack_cycle(nr);
1.1.1.8 root 3342: //fprintf ( stderr , "ex iack2 %d %ld\n" , nr , currcycle );
1.1.1.7 root 3343: x_put_word (m68k_areg (regs, 7) + 0, regs.sr); // write SR
3344: x_put_word (m68k_areg (regs, 7) + 2, currpc >> 16); // write high address
1.1.1.4 root 3345: }
3346: kludge_me_do:
1.1.1.7 root 3347: newpc = x_get_word (regs.vbr + 4 * vector_nr) << 16; // read high address
3348: newpc |= x_get_word (regs.vbr + 4 * vector_nr + 2); // read low address
3349: exception_in_exception = 0;
1.1.1.4 root 3350: if (newpc & 1) {
3351: if (nr == 2 || nr == 3)
1.1.1.8 root 3352: cpu_halt (CPU_HALT_DOUBLE_FAULT);
1.1.1.4 root 3353: else
1.1.1.7 root 3354: exception3_notinstruction(regs.ir, newpc);
1.1.1.4 root 3355: return;
3356: }
3357: m68k_setpc (newpc);
1.1.1.10! root 3358: if (interrupt)
! 3359: regs.intmask = nr - 24;
! 3360: branch_stack_push(currpc, currpc);
1.1.1.7 root 3361: regs.ir = x_get_word (m68k_getpc ()); // prefetch 1
3362: x_do_cycles (2 * cpucycleunit);
1.1.1.8 root 3363: #ifdef WINUAE_FOR_HATARI
3364: /* [NP] IPL should be updated just before the last x_get_word for irc */
3365: /* (4 cycles before end of exception), so we need to add 2 cycles now */
3366: /* to be aligned on 4 cycles (else the 2 cycles will be added in x_get_word */
3367: /* and IPL will be updated 2 cycles too soon) */
3368: x_do_cycles (2 * cpucycleunit);
3369: /* Add all cycles needed for the exception so far */
3370: M68000_AddCycles_CE ( currcycle * 2 / CYCLE_UNIT );
3371: currcycle = 0;
3372: /* Update IPL / interrupts state, in case a new interrupt happened during this exception */
3373: while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) )
3374: CALL_VAR(PendingInterruptFunction);
3375: #endif
3376: regs.ipl_pin = intlev();
3377: ipl_fetch();
1.1.1.7 root 3378: regs.irc = x_get_word (m68k_getpc () + 2); // prefetch 2
1.1.1.4 root 3379: #ifdef JIT
3380: set_special (SPCFLAG_END_COMPILE);
3381: #endif
1.1.1.8 root 3382: exception_check_trace (nr);
1.1.1.7 root 3383:
3384: //fprintf ( stderr , "ex out %d %ld\n" , nr , currcycle );
3385: #ifdef WINUAE_FOR_HATARI
1.1.1.8 root 3386: /* Add all cycles needed for the exception */
3387: M68000_AddCycles_CE ( currcycle * 2 / CYCLE_UNIT );
3388: currcycle = 0;
1.1.1.7 root 3389: #endif
3390: }
3391: #endif
3392:
3393: static uae_u32 exception_pc (int nr)
3394: {
3395: // bus error, address error, illegal instruction, privilege violation, a-line, f-line
3396: if (nr == 2 || nr == 3 || nr == 4 || nr == 8 || nr == 10 || nr == 11)
3397: return regs.instruction_pc;
3398: return m68k_getpc ();
3399: }
3400:
3401: static void Exception_build_stack_frame (uae_u32 oldpc, uae_u32 currpc, uae_u32 ssw, int nr, int format)
3402: {
3403: int i;
3404:
3405: #if 0
3406: if (nr < 24 || nr > 31) { // do not print debugging for interrupts
3407: write_log(_T("Building exception stack frame (format %X)\n"), format);
3408: }
3409: #endif
3410:
1.1.1.9 root 3411: switch (format) {
1.1.1.7 root 3412: case 0x0: // four word stack frame
3413: case 0x1: // throwaway four word stack frame
3414: break;
3415: case 0x2: // six word stack frame
3416: m68k_areg (regs, 7) -= 4;
3417: x_put_long (m68k_areg (regs, 7), oldpc);
3418: break;
1.1.1.9 root 3419: case 0x3: // floating point post-instruction stack frame (68040)
3420: m68k_areg (regs, 7) -= 4;
3421: x_put_long (m68k_areg (regs, 7), regs.fp_ea);
3422: break;
3423: case 0x7: // access error stack frame (68040)
1.1.1.7 root 3424:
3425: for (i = 3; i >= 0; i--) {
3426: // WB1D/PD0,PD1,PD2,PD3
3427: m68k_areg (regs, 7) -= 4;
3428: x_put_long (m68k_areg (regs, 7), mmu040_move16[i]);
3429: }
3430:
3431: m68k_areg (regs, 7) -= 4;
3432: x_put_long (m68k_areg (regs, 7), 0); // WB1A
3433: m68k_areg (regs, 7) -= 4;
3434: x_put_long (m68k_areg (regs, 7), 0); // WB2D
3435: m68k_areg (regs, 7) -= 4;
3436: x_put_long (m68k_areg (regs, 7), regs.wb2_address); // WB2A
3437: m68k_areg (regs, 7) -= 4;
3438: x_put_long (m68k_areg (regs, 7), regs.wb3_data); // WB3D
3439: m68k_areg (regs, 7) -= 4;
3440: x_put_long (m68k_areg (regs, 7), regs.mmu_fault_addr); // WB3A
3441:
3442: m68k_areg (regs, 7) -= 4;
3443: x_put_long (m68k_areg (regs, 7), regs.mmu_fault_addr); // FA
3444:
3445: m68k_areg (regs, 7) -= 2;
3446: x_put_word (m68k_areg (regs, 7), 0);
3447: m68k_areg (regs, 7) -= 2;
3448: x_put_word (m68k_areg (regs, 7), regs.wb2_status);
3449: regs.wb2_status = 0;
3450: m68k_areg (regs, 7) -= 2;
3451: x_put_word (m68k_areg (regs, 7), regs.wb3_status);
3452: regs.wb3_status = 0;
3453:
3454: m68k_areg (regs, 7) -= 2;
3455: x_put_word (m68k_areg (regs, 7), ssw);
3456: m68k_areg (regs, 7) -= 4;
3457: x_put_long (m68k_areg (regs, 7), regs.mmu_effective_addr);
3458: break;
3459: case 0x9: // coprocessor mid-instruction stack frame (68020, 68030)
3460: m68k_areg (regs, 7) -= 4;
1.1.1.9 root 3461: x_put_long (m68k_areg (regs, 7), regs.fp_ea);
1.1.1.7 root 3462: m68k_areg (regs, 7) -= 4;
1.1.1.9 root 3463: x_put_long (m68k_areg (regs, 7), regs.fp_opword);
3464: m68k_areg (regs, 7) -= 4;
1.1.1.7 root 3465: x_put_long (m68k_areg (regs, 7), oldpc);
3466: break;
3467: case 0x8: // bus and address error stack frame (68010)
3468: write_log(_T("Exception stack frame format %X not implemented\n"), format);
3469: return;
3470: case 0x4: // floating point unimplemented stack frame (68LC040, 68EC040)
1.1.1.9 root 3471: // or 68060 bus access fault stack frame
1.1.1.7 root 3472: m68k_areg (regs, 7) -= 4;
1.1.1.9 root 3473: x_put_long (m68k_areg (regs, 7), ssw);
1.1.1.7 root 3474: m68k_areg (regs, 7) -= 4;
1.1.1.9 root 3475: x_put_long (m68k_areg (regs, 7), oldpc);
1.1.1.7 root 3476: break;
3477: case 0xB: // long bus cycle fault stack frame (68020, 68030)
3478: // We always use B frame because it is easier to emulate,
3479: // our PC always points at start of instruction but A frame assumes
3480: // it is + 2 and handling this properly is not easy.
3481: // Store state information to internal register space
1.1.1.10! root 3482: #if MMU030_DEBUG
! 3483: if (mmu030_idx >= MAX_MMU030_ACCESS) {
! 3484: write_log(_T("mmu030_idx out of bounds! %d >= %d\n"), mmu030_idx, MAX_MMU030_ACCESS);
! 3485: }
! 3486: #endif
! 3487: if (!(ssw & MMU030_SSW_RW)) {
! 3488: mmu030_ad[mmu030_idx].val = regs.wb3_data;
! 3489: }
1.1.1.7 root 3490: for (i = 0; i < mmu030_idx + 1; i++) {
3491: m68k_areg (regs, 7) -= 4;
3492: x_put_long (m68k_areg (regs, 7), mmu030_ad[i].val);
3493: }
1.1.1.10! root 3494: while (i < MAX_MMU030_ACCESS) {
1.1.1.7 root 3495: uae_u32 v = 0;
3496: m68k_areg (regs, 7) -= 4;
3497: // mmu030_idx is always small enough if instruction is FMOVEM.
3498: if (mmu030_state[1] & MMU030_STATEFLAG1_FMOVEM) {
1.1.1.10! root 3499: #if MMU030_DEBUG
! 3500: if (mmu030_idx >= MAX_MMU030_ACCESS - 2) {
! 3501: write_log(_T("mmu030_idx (FMOVEM) out of bounds! %d >= %d\n"), mmu030_idx, MAX_MMU030_ACCESS - 2);
! 3502: }
! 3503: #endif
! 3504: if (i == MAX_MMU030_ACCESS - 2)
1.1.1.7 root 3505: v = mmu030_fmovem_store[0];
1.1.1.10! root 3506: else if (i == MAX_MMU030_ACCESS - 1)
1.1.1.7 root 3507: v = mmu030_fmovem_store[1];
3508: }
3509: x_put_long (m68k_areg (regs, 7), v);
3510: i++;
3511: }
3512: // version & internal information (We store index here)
3513: m68k_areg (regs, 7) -= 2;
3514: x_put_word (m68k_areg (regs, 7), mmu030_idx);
3515: // 3* internal registers
3516: m68k_areg (regs, 7) -= 2;
3517: x_put_word (m68k_areg (regs, 7), mmu030_state[2]);
3518: m68k_areg (regs, 7) -= 2;
1.1.1.10! root 3519: x_put_word (m68k_areg(regs, 7), regs.wb2_address); // = mmu030_state[1]
1.1.1.7 root 3520: m68k_areg (regs, 7) -= 2;
3521: x_put_word (m68k_areg (regs, 7), mmu030_state[0]);
3522: // data input buffer = fault address
3523: m68k_areg (regs, 7) -= 4;
3524: x_put_long (m68k_areg (regs, 7), regs.mmu_fault_addr);
3525: // 2xinternal
1.1.1.9 root 3526: {
3527: uae_u32 ps = (regs.prefetch020_valid[0] ? 1 : 0) | (regs.prefetch020_valid[1] ? 2 : 0) | (regs.prefetch020_valid[2] ? 4 : 0);
3528: ps |= ((regs.pipeline_r8[0] & 7) << 8);
3529: ps |= ((regs.pipeline_r8[1] & 7) << 11);
3530: ps |= ((regs.pipeline_pos & 15) << 16);
3531: ps |= ((regs.pipeline_stop & 15) << 20);
3532: if (mmu030_opcode == -1)
3533: ps |= 1 << 31;
3534: m68k_areg (regs, 7) -= 4;
3535: x_put_long (m68k_areg (regs, 7), ps);
3536: }
1.1.1.7 root 3537: // stage b address
3538: m68k_areg (regs, 7) -= 4;
3539: x_put_long (m68k_areg (regs, 7), mm030_stageb_address);
3540: // 2xinternal
3541: m68k_areg (regs, 7) -= 4;
3542: x_put_long (m68k_areg (regs, 7), mmu030_disp_store[1]);
3543: /* fall through */
3544: case 0xA: // short bus cycle fault stack frame (68020, 68030)
3545: m68k_areg (regs, 7) -= 4;
3546: x_put_long (m68k_areg (regs, 7), mmu030_disp_store[0]);
3547: m68k_areg (regs, 7) -= 4;
1.1.1.10! root 3548: // Data output buffer = value that was going to be written
! 3549: x_put_long (m68k_areg (regs, 7), regs.wb3_data);
1.1.1.7 root 3550: m68k_areg (regs, 7) -= 4;
1.1.1.9 root 3551: x_put_long (m68k_areg (regs, 7), (mmu030_opcode & 0xffff) | (regs.prefetch020[0] << 16)); // Internal register (opcode storage)
1.1.1.7 root 3552: m68k_areg (regs, 7) -= 4;
3553: x_put_long (m68k_areg (regs, 7), regs.mmu_fault_addr); // data cycle fault address
3554: m68k_areg (regs, 7) -= 2;
1.1.1.9 root 3555: x_put_word (m68k_areg (regs, 7), regs.prefetch020[2]); // Instr. pipe stage B
1.1.1.7 root 3556: m68k_areg (regs, 7) -= 2;
1.1.1.9 root 3557: x_put_word (m68k_areg (regs, 7), regs.prefetch020[1]); // Instr. pipe stage C
1.1.1.7 root 3558: m68k_areg (regs, 7) -= 2;
3559: x_put_word (m68k_areg (regs, 7), ssw);
3560: m68k_areg (regs, 7) -= 2;
3561: x_put_word (m68k_areg (regs, 7), 0); // Internal register
3562: break;
3563: default:
3564: write_log(_T("Unknown exception stack frame format: %X\n"), format);
3565: return;
3566: }
3567: m68k_areg (regs, 7) -= 2;
3568: x_put_word (m68k_areg (regs, 7), (format << 12) | (nr * 4));
3569: m68k_areg (regs, 7) -= 4;
3570: x_put_long (m68k_areg (regs, 7), currpc);
3571: m68k_areg (regs, 7) -= 2;
3572: x_put_word (m68k_areg (regs, 7), regs.sr);
1.1.1.4 root 3573: }
1.1.1.7 root 3574:
1.1.1.9 root 3575: static void Exception_build_stack_frame_common (uae_u32 oldpc, uae_u32 currpc, uae_u32 ssw, int nr)
3576: {
3577: if (nr == 5 || nr == 6 || nr == 7 || nr == 9) {
3578: Exception_build_stack_frame(oldpc, currpc, regs.mmu_ssw, nr, 0x2);
3579: } else if (nr == 60 || nr == 61) {
3580: Exception_build_stack_frame(oldpc, regs.instruction_pc, regs.mmu_ssw, nr, 0x0);
3581: } else if (nr >= 48 && nr <= 55) {
3582: if (regs.fpu_exp_pre) {
3583: if (currprefs.cpu_model == 68060 && nr == 55 && regs.fp_unimp_pend == 2) { // packed decimal real
3584: Exception_build_stack_frame(regs.fp_ea, regs.instruction_pc, 0, nr, 0x2);
3585: } else {
3586: Exception_build_stack_frame(oldpc, regs.instruction_pc, 0, nr, 0x0);
3587: }
3588: } else { /* post-instruction */
3589: if (currprefs.cpu_model == 68060 && nr == 55 && regs.fp_unimp_pend == 2) { // packed decimal real
3590: Exception_build_stack_frame(regs.fp_ea, currpc, 0, nr, 0x2);
3591: } else {
3592: Exception_build_stack_frame(oldpc, currpc, 0, nr, 0x3);
3593: }
3594: }
3595: } else if (nr == 11 && regs.fp_unimp_ins) {
3596: regs.fp_unimp_ins = false;
3597: if ((currprefs.cpu_model == 68060 && (currprefs.fpu_model == 0 || (regs.pcr & 2))) ||
3598: (currprefs.cpu_model == 68040 && currprefs.fpu_model == 0)) {
3599: Exception_build_stack_frame(regs.fp_ea, currpc, regs.instruction_pc, nr, 0x4);
3600: } else {
3601: Exception_build_stack_frame(regs.fp_ea, currpc, regs.mmu_ssw, nr, 0x2);
3602: }
3603: } else {
3604: Exception_build_stack_frame(oldpc, currpc, regs.mmu_ssw, nr, 0x0);
3605: }
3606: }
1.1.1.7 root 3607:
3608: // 68030 MMU
3609: static void Exception_mmu030 (int nr, uaecptr oldpc)
3610: {
3611: uae_u32 currpc = m68k_getpc (), newpc;
3612: int interrupt;
3613:
3614: interrupt = nr >= 24 && nr < 24 + 8;
1.1.1.4 root 3615:
1.1.1.7 root 3616: #ifdef WINUAE_FOR_HATARI
3617: if (interrupt)
3618: nr = iack_cycle(nr);
3619: #endif
3620:
3621: #ifdef WINUAE_FOR_HATARI
3622: LOG_TRACE(TRACE_CPU_EXCEPTION, "cpu exception %d currpc %x buspc %x newpc %x fault_e3 %x op_e3 %hx addr_e3 %x SR %x\n",
3623: nr, currpc, regs.instruction_pc, STMemory_ReadLong (regs.vbr + 4*nr), last_fault_for_exception_3, last_op_for_exception_3, last_addr_for_exception_3, regs.sr);
3624: #endif
3625: exception_debug (nr);
3626: MakeSR ();
3627:
3628: if (!regs.s) {
3629: regs.usp = m68k_areg (regs, 7);
3630: m68k_areg(regs, 7) = regs.m ? regs.msp : regs.isp;
3631: regs.s = 1;
3632: mmu_set_super (1);
3633: }
3634:
3635: #if 0
3636: if (nr < 24 || nr > 31) { // do not print debugging for interrupts
3637: write_log (_T("Exception_mmu030: Exception %i: %08x %08x %08x\n"),
3638: nr, currpc, oldpc, regs.mmu_fault_addr);
3639: }
3640: #endif
3641:
1.1.1.9 root 3642: newpc = x_get_long (regs.vbr + 4 * nr);
3643:
1.1.1.7 root 3644: #if 0
1.1.1.9 root 3645: write_log (_T("Exception %d -> %08x\n"), nr, newpc);
1.1.1.7 root 3646: #endif
3647:
3648: if (regs.m && interrupt) { /* M + Interrupt */
3649: Exception_build_stack_frame (oldpc, currpc, regs.mmu_ssw, nr, 0x0);
3650: MakeSR ();
3651: regs.m = 0;
3652: regs.msp = m68k_areg (regs, 7);
3653: m68k_areg (regs, 7) = regs.isp;
3654: Exception_build_stack_frame (oldpc, currpc, regs.mmu_ssw, nr, 0x1);
3655: } else if (nr == 2) {
3656: Exception_build_stack_frame (oldpc, currpc, regs.mmu_ssw, nr, 0xB);
3657: } else if (nr == 3) {
3658: regs.mmu_fault_addr = last_fault_for_exception_3;
3659: mmu030_state[0] = mmu030_state[1] = 0;
1.1.1.10! root 3660: mmu030_data_buffer_out = 0;
1.1.1.7 root 3661: Exception_build_stack_frame (last_fault_for_exception_3, currpc, MMU030_SSW_RW | MMU030_SSW_SIZE_W | (regs.s ? 6 : 2), nr, 0xA);
1.1.1.9 root 3662: } else {
3663: Exception_build_stack_frame_common(oldpc, currpc, regs.mmu_ssw, nr);
3664: }
3665:
1.1.1.7 root 3666: if (newpc & 1) {
3667: if (nr == 2 || nr == 3)
1.1.1.8 root 3668: cpu_halt (CPU_HALT_DOUBLE_FAULT);
1.1.1.7 root 3669: else
3670: exception3_read(regs.ir, newpc);
3671: return;
3672: }
1.1.1.10! root 3673: if (interrupt)
! 3674: regs.intmask = nr - 24;
1.1.1.7 root 3675: m68k_setpci (newpc);
3676: fill_prefetch ();
1.1.1.8 root 3677: exception_check_trace (nr);
1.1.1.7 root 3678: }
3679:
3680: // 68040/060 MMU
1.1.1.4 root 3681: static void Exception_mmu (int nr, uaecptr oldpc)
3682: {
3683: uae_u32 currpc = m68k_getpc (), newpc;
1.1.1.7 root 3684: int interrupt;
1.1.1.4 root 3685:
1.1.1.7 root 3686: interrupt = nr >= 24 && nr < 24 + 8;
3687:
1.1.1.9 root 3688: // exception vector fetch and exception stack frame
3689: // operations don't allocate new cachelines
3690: cache_default_data |= CACHE_DISABLE_ALLOCATE;
3691:
1.1.1.7 root 3692: #ifdef WINUAE_FOR_HATARI
3693: if (interrupt)
3694: nr = iack_cycle(nr);
3695: #endif
3696:
3697: #ifdef WINUAE_FOR_HATARI
3698: LOG_TRACE(TRACE_CPU_EXCEPTION, "cpu exception %d currpc %x buspc %x newpc %x fault_e3 %x op_e3 %hx addr_e3 %x SR %x\n",
3699: nr, currpc, regs.instruction_pc, STMemory_ReadLong (regs.vbr + 4*nr), last_fault_for_exception_3, last_op_for_exception_3, last_addr_for_exception_3, regs.sr);
3700: #endif
1.1.1.4 root 3701: exception_debug (nr);
3702: MakeSR ();
3703:
3704: if (!regs.s) {
3705: regs.usp = m68k_areg (regs, 7);
1.1.1.8 root 3706: if (currprefs.cpu_model >= 68020 && currprefs.cpu_model < 68060) {
1.1.1.4 root 3707: m68k_areg (regs, 7) = regs.m ? regs.msp : regs.isp;
1.1.1.7 root 3708: } else {
1.1.1.4 root 3709: m68k_areg (regs, 7) = regs.isp;
1.1.1.7 root 3710: }
1.1.1.4 root 3711: regs.s = 1;
3712: mmu_set_super (1);
3713: }
1.1.1.8 root 3714:
1.1.1.7 root 3715: newpc = x_get_long (regs.vbr + 4 * nr);
3716: #if 0
3717: write_log (_T("Exception %d: %08x -> %08x\n"), nr, currpc, newpc);
3718: #endif
1.1.1.5 root 3719:
1.1.1.7 root 3720: if (nr == 2) { // bus error
3721: //write_log (_T("Exception_mmu %08x %08x %08x\n"), currpc, oldpc, regs.mmu_fault_addr);
3722: if (currprefs.mmu_model == 68040)
3723: Exception_build_stack_frame(oldpc, currpc, regs.mmu_ssw, nr, 0x7);
3724: else
1.1.1.9 root 3725: Exception_build_stack_frame(regs.mmu_fault_addr, currpc, regs.mmu_fslw, nr, 0x4);
1.1.1.7 root 3726: } else if (nr == 3) { // address error
3727: Exception_build_stack_frame(last_fault_for_exception_3, currpc, 0, nr, 0x2);
3728: write_log (_T("Exception %d (%x) at %x -> %x!\n"), nr, last_fault_for_exception_3, currpc, get_long_debug (regs.vbr + 4 * nr));
3729: } else if (regs.m && interrupt) { /* M + Interrupt */
1.1.1.8 root 3730: Exception_build_stack_frame(oldpc, currpc, regs.mmu_ssw, nr, 0x0);
3731: MakeSR();
3732: regs.m = 0;
3733: if (currprefs.cpu_model < 68060) {
3734: regs.msp = m68k_areg(regs, 7);
3735: Exception_build_stack_frame(oldpc, currpc, regs.mmu_ssw, nr, 0x1);
3736: }
1.1.1.4 root 3737: } else {
1.1.1.9 root 3738: Exception_build_stack_frame_common(oldpc, currpc, regs.mmu_ssw, nr);
1.1.1.4 root 3739: }
1.1.1.7 root 3740:
1.1.1.4 root 3741: if (newpc & 1) {
3742: if (nr == 2 || nr == 3)
1.1.1.8 root 3743: cpu_halt (CPU_HALT_DOUBLE_FAULT);
1.1.1.4 root 3744: else
1.1.1.7 root 3745: exception3_read(regs.ir, newpc);
1.1.1.4 root 3746: return;
3747: }
1.1.1.9 root 3748:
3749: cache_default_data &= ~CACHE_DISABLE_ALLOCATE;
3750:
1.1.1.7 root 3751: m68k_setpci (newpc);
1.1.1.10! root 3752: if (interrupt)
! 3753: regs.intmask = nr - 24;
1.1.1.7 root 3754: fill_prefetch ();
1.1.1.8 root 3755: exception_check_trace (nr);
1.1.1.4 root 3756: }
3757:
1.1.1.7 root 3758: static void add_approximate_exception_cycles(int nr)
1.1.1.4 root 3759: {
1.1.1.7 root 3760: int cycles;
3761:
3762: if (currprefs.cpu_model > 68000)
3763: return;
3764: #ifndef WINUAE_FOR_HATARI
3765: if (nr >= 24 && nr <= 31) {
3766: /* Interrupts */
3767: cycles = 44 + 4;
3768: #else
3769: if ( nr >= 24 && nr <= 31 ) {
1.1.1.8 root 3770: /* Atari's specific interrupts take 56 cycles instead of 44 due to iack sequence */
3771: /* We must subtract CPU_IACK_CYCLES_START cycles already counted into iack_cycle() */
1.1.1.7 root 3772: if ( nr == 30 ) /* MFP/DSP */
1.1.1.8 root 3773: cycles = 44-CPU_IACK_CYCLES_START;
1.1.1.7 root 3774: else if ( nr == 28 ) /* VBL */
1.1.1.8 root 3775: cycles = 44-CPU_IACK_CYCLES_START;
1.1.1.7 root 3776: else if ( nr == 26 ) /* HBL */
1.1.1.8 root 3777: cycles = 44-CPU_IACK_CYCLES_START;
1.1.1.7 root 3778: else
1.1.1.8 root 3779: cycles = 44+4; /* Other interrupts (not used in Atari machines) */
1.1.1.7 root 3780: #endif
3781: } else if (nr >= 32 && nr <= 47) {
3782: /* Trap (total is 34, but cpuemux.c already adds 4) */
3783: cycles = 34 -4;
3784: } else {
3785: switch (nr)
3786: {
3787: case 2: cycles = 50; break; /* Bus error */
3788: case 3: cycles = 50; break; /* Address error */
3789: case 4: cycles = 34; break; /* Illegal instruction */
3790: case 5: cycles = 38; break; /* Division by zero */
3791: case 6: cycles = 40; break; /* CHK */
3792: case 7: cycles = 34; break; /* TRAPV */
3793: case 8: cycles = 34; break; /* Privilege violation */
3794: case 9: cycles = 34; break; /* Trace */
3795: case 10: cycles = 34; break; /* Line-A */
3796: case 11: cycles = 34; break; /* Line-F */
3797: default:
3798: cycles = 4;
3799: break;
3800: }
3801: }
3802: #ifdef WINUAE_FOR_HATARI
3803: M68000_AddCycles ( cycles );
3804: #endif
3805: cycles = adjust_cycles(cycles * CYCLE_UNIT / 2);
3806: x_do_cycles(cycles);
3807: }
3808:
3809: static void Exception_normal (int nr)
3810: {
1.1.1.9 root 3811: uae_u32 newpc;
3812: uae_u32 currpc = m68k_getpc();
3813: uae_u32 nextpc;
1.1.1.4 root 3814: int sv = regs.s;
1.1.1.7 root 3815: int interrupt;
3816: int vector_nr = nr;
3817:
1.1.1.9 root 3818: cache_default_data |= CACHE_DISABLE_ALLOCATE;
3819:
1.1.1.7 root 3820: interrupt = nr >= 24 && nr < 24 + 8;
1.1.1.4 root 3821:
1.1.1.7 root 3822: #ifndef WINUAE_FOR_HATARI
3823: if (interrupt && currprefs.cpu_model <= 68010)
3824: #else
3825: if (interrupt)
1.1.1.4 root 3826: #endif
1.1.1.7 root 3827: vector_nr = iack_cycle(nr);
1.1.1.4 root 3828:
3829: exception_debug (nr);
3830: MakeSR ();
3831:
3832: if (!regs.s) {
3833: regs.usp = m68k_areg (regs, 7);
1.1.1.8 root 3834: if (currprefs.cpu_model >= 68020 && currprefs.cpu_model < 68060) {
1.1.1.4 root 3835: m68k_areg (regs, 7) = regs.m ? regs.msp : regs.isp;
1.1.1.7 root 3836: } else {
1.1.1.4 root 3837: m68k_areg (regs, 7) = regs.isp;
1.1.1.7 root 3838: }
1.1.1.4 root 3839: regs.s = 1;
3840: if (currprefs.mmu_model)
3841: mmu_set_super (regs.s != 0);
3842: }
1.1.1.7 root 3843:
1.1.1.8 root 3844: if ((m68k_areg(regs, 7) & 1) && currprefs.cpu_model < 68020) {
1.1.1.7 root 3845: if (nr == 2 || nr == 3)
1.1.1.8 root 3846: cpu_halt (CPU_HALT_DOUBLE_FAULT);
1.1.1.7 root 3847: else
3848: exception3_notinstruction(regs.ir, m68k_areg(regs, 7));
3849: return;
3850: }
3851: if ((nr == 2 || nr == 3) && exception_in_exception < 0) {
1.1.1.8 root 3852: cpu_halt (CPU_HALT_DOUBLE_FAULT);
1.1.1.7 root 3853: return;
3854: }
3855:
1.1.1.8 root 3856: #ifndef WINUAE_FOR_HATARI
3857: if (!currprefs.cpu_compatible) {
3858: addrbank *ab = &get_mem_bank(m68k_areg(regs, 7) - 4);
3859: // Not plain RAM check because some CPU type tests that
3860: // don't need to return set stack to ROM..
3861: if (!ab || ab == &dummy_bank || (ab->flags & ABFLAG_IO)) {
3862: cpu_halt(CPU_HALT_SSP_IN_NON_EXISTING_ADDRESS);
3863: return;
3864: }
3865: }
3866: #endif
3867:
1.1.1.9 root 3868: bool used_exception_build_stack_frame = false;
3869:
1.1.1.7 root 3870: if (currprefs.cpu_model > 68000) {
1.1.1.9 root 3871: uae_u32 oldpc = regs.instruction_pc;
3872: nextpc = exception_pc (nr);
1.1.1.7 root 3873: #ifdef WINUAE_FOR_HATARI
3874: LOG_TRACE(TRACE_CPU_EXCEPTION, "cpu exception %d vector %x currpc %x buspc %x newpc %x fault_e3 %x op_e3 %hx addr_e3 %x SR %x\n",
3875: nr, 4*vector_nr , currpc, regs.instruction_pc, STMemory_ReadLong (regs.vbr + 4*vector_nr), last_fault_for_exception_3, last_op_for_exception_3, last_addr_for_exception_3, regs.sr);
3876: #endif
3877: if (nr == 2 || nr == 3) {
3878: int i;
1.1.1.4 root 3879: if (currprefs.cpu_model >= 68040) {
3880: if (nr == 2) {
3881: if (currprefs.mmu_model) {
1.1.1.7 root 3882: // 68040 mmu bus error
1.1.1.4 root 3883: for (i = 0 ; i < 7 ; i++) {
3884: m68k_areg (regs, 7) -= 4;
3885: x_put_long (m68k_areg (regs, 7), 0);
3886: }
3887: m68k_areg (regs, 7) -= 4;
3888: x_put_long (m68k_areg (regs, 7), regs.wb3_data);
3889: m68k_areg (regs, 7) -= 4;
3890: x_put_long (m68k_areg (regs, 7), regs.mmu_fault_addr);
3891: m68k_areg (regs, 7) -= 4;
3892: x_put_long (m68k_areg (regs, 7), regs.mmu_fault_addr);
3893: m68k_areg (regs, 7) -= 2;
3894: x_put_word (m68k_areg (regs, 7), 0);
3895: m68k_areg (regs, 7) -= 2;
3896: x_put_word (m68k_areg (regs, 7), 0);
3897: m68k_areg (regs, 7) -= 2;
3898: x_put_word (m68k_areg (regs, 7), regs.wb3_status);
3899: regs.wb3_status = 0;
3900: m68k_areg (regs, 7) -= 2;
3901: x_put_word (m68k_areg (regs, 7), regs.mmu_ssw);
3902: m68k_areg (regs, 7) -= 4;
3903: x_put_long (m68k_areg (regs, 7), regs.mmu_fault_addr);
3904:
3905: m68k_areg (regs, 7) -= 2;
1.1.1.7 root 3906: x_put_word (m68k_areg (regs, 7), 0x7000 + vector_nr * 4);
1.1.1.4 root 3907: m68k_areg (regs, 7) -= 4;
1.1.1.7 root 3908: x_put_long (m68k_areg (regs, 7), regs.instruction_pc);
1.1.1.4 root 3909: m68k_areg (regs, 7) -= 2;
3910: x_put_word (m68k_areg (regs, 7), regs.sr);
1.1.1.7 root 3911: newpc = x_get_long (regs.vbr + 4 * vector_nr);
1.1.1.4 root 3912: if (newpc & 1) {
3913: if (nr == 2 || nr == 3)
1.1.1.8 root 3914: cpu_halt (CPU_HALT_DOUBLE_FAULT);
1.1.1.4 root 3915: else
1.1.1.7 root 3916: exception3_read(regs.ir, newpc);
1.1.1.4 root 3917: return;
3918: }
3919: m68k_setpc (newpc);
3920: #ifdef JIT
3921: set_special (SPCFLAG_END_COMPILE);
3922: #endif
1.1.1.8 root 3923: exception_check_trace (nr);
1.1.1.4 root 3924: return;
3925:
3926: } else {
3927:
1.1.1.7 root 3928: // 68040 bus error (not really, some garbage?)
1.1.1.4 root 3929: for (i = 0 ; i < 18 ; i++) {
3930: m68k_areg (regs, 7) -= 2;
3931: x_put_word (m68k_areg (regs, 7), 0);
3932: }
3933: m68k_areg (regs, 7) -= 4;
3934: x_put_long (m68k_areg (regs, 7), last_fault_for_exception_3);
3935: m68k_areg (regs, 7) -= 2;
3936: x_put_word (m68k_areg (regs, 7), 0);
3937: m68k_areg (regs, 7) -= 2;
3938: x_put_word (m68k_areg (regs, 7), 0);
3939: m68k_areg (regs, 7) -= 2;
3940: x_put_word (m68k_areg (regs, 7), 0);
3941: m68k_areg (regs, 7) -= 2;
3942: x_put_word (m68k_areg (regs, 7), 0x0140 | (sv ? 6 : 2)); /* SSW */
3943: m68k_areg (regs, 7) -= 4;
3944: x_put_long (m68k_areg (regs, 7), last_addr_for_exception_3);
3945: m68k_areg (regs, 7) -= 2;
1.1.1.7 root 3946: x_put_word (m68k_areg (regs, 7), 0x7000 + vector_nr * 4);
1.1.1.4 root 3947: m68k_areg (regs, 7) -= 4;
1.1.1.7 root 3948: x_put_long (m68k_areg (regs, 7), regs.instruction_pc);
1.1.1.4 root 3949: m68k_areg (regs, 7) -= 2;
3950: x_put_word (m68k_areg (regs, 7), regs.sr);
3951: goto kludge_me_do;
3952:
3953: }
3954:
3955: } else {
3956: m68k_areg (regs, 7) -= 4;
3957: x_put_long (m68k_areg (regs, 7), last_fault_for_exception_3);
3958: m68k_areg (regs, 7) -= 2;
1.1.1.7 root 3959: x_put_word (m68k_areg (regs, 7), 0x2000 + vector_nr * 4);
1.1.1.4 root 3960: }
3961: } else {
1.1.1.7 root 3962: // 68020 address error
1.1.1.4 root 3963: uae_u16 ssw = (sv ? 4 : 0) | (last_instructionaccess_for_exception_3 ? 2 : 1);
3964: ssw |= last_writeaccess_for_exception_3 ? 0 : 0x40;
3965: ssw |= 0x20;
3966: for (i = 0 ; i < 36; i++) {
3967: m68k_areg (regs, 7) -= 2;
3968: x_put_word (m68k_areg (regs, 7), 0);
3969: }
3970: m68k_areg (regs, 7) -= 4;
3971: x_put_long (m68k_areg (regs, 7), last_fault_for_exception_3);
3972: m68k_areg (regs, 7) -= 2;
3973: x_put_word (m68k_areg (regs, 7), 0);
3974: m68k_areg (regs, 7) -= 2;
3975: x_put_word (m68k_areg (regs, 7), 0);
3976: m68k_areg (regs, 7) -= 2;
3977: x_put_word (m68k_areg (regs, 7), 0);
3978: m68k_areg (regs, 7) -= 2;
3979: x_put_word (m68k_areg (regs, 7), ssw);
3980: m68k_areg (regs, 7) -= 2;
1.1.1.7 root 3981: x_put_word (m68k_areg (regs, 7), 0xb000 + vector_nr * 4);
1.1.1.4 root 3982: }
1.1.1.10! root 3983: #ifndef WINUAE_FOR_HATARI
1.1.1.7 root 3984: write_log (_T("Exception %d (%x) at %x -> %x!\n"), nr, regs.instruction_pc, currpc, get_long_debug (regs.vbr + 4 * vector_nr));
1.1.1.10! root 3985: #else
! 3986: if (nr != 2 || M68000_IsVerboseBusError(currpc, last_fault_for_exception_3))
! 3987: Log_Printf(LOG_WARN, "%s Error %s at address $%x, PC=$%x addr_e3=%x op_e3=%x\n",
! 3988: nr == 2 ? "Bus" : "Address",
! 3989: last_writeaccess_for_exception_3 ? "writing" : "reading",
! 3990: last_fault_for_exception_3, currpc,
! 3991: last_addr_for_exception_3, last_op_for_exception_3);
! 3992: #endif
1.1.1.7 root 3993: } else if (regs.m && interrupt) { /* M + Interrupt */
1.1.1.4 root 3994: m68k_areg (regs, 7) -= 2;
1.1.1.7 root 3995: x_put_word (m68k_areg (regs, 7), vector_nr * 4);
1.1.1.8 root 3996: if (currprefs.cpu_model < 68060) {
3997: m68k_areg (regs, 7) -= 4;
3998: x_put_long (m68k_areg (regs, 7), currpc);
3999: m68k_areg (regs, 7) -= 2;
4000: x_put_word (m68k_areg (regs, 7), regs.sr);
4001: regs.sr |= (1 << 13);
4002: regs.msp = m68k_areg(regs, 7);
4003: regs.m = 0;
4004: m68k_areg(regs, 7) = regs.isp;
4005: m68k_areg (regs, 7) -= 2;
4006: x_put_word (m68k_areg (regs, 7), 0x1000 + vector_nr * 4);
4007: }
1.1.1.4 root 4008: } else {
1.1.1.9 root 4009: Exception_build_stack_frame_common(oldpc, currpc, regs.mmu_ssw, nr);
4010: used_exception_build_stack_frame = true;
1.1.1.7 root 4011: }
1.1.1.9 root 4012: } else {
1.1.1.7 root 4013: add_approximate_exception_cycles(nr);
1.1.1.9 root 4014: nextpc = m68k_getpc ();
1.1.1.7 root 4015: #ifdef WINUAE_FOR_HATARI
4016: LOG_TRACE(TRACE_CPU_EXCEPTION, "cpu exception %d vector %x currpc %x buspc %x newpc %x fault_e3 %x op_e3 %hx addr_e3 %x SR %x\n",
4017: nr, 4*vector_nr , currpc, regs.instruction_pc, STMemory_ReadLong (regs.vbr + 4*vector_nr), last_fault_for_exception_3, last_op_for_exception_3, last_addr_for_exception_3, regs.sr);
4018: #endif
4019: if (nr == 2 || nr == 3) {
4020: // 68000 address error
4021: uae_u16 mode = (sv ? 4 : 0) | (last_instructionaccess_for_exception_3 ? 2 : 1);
4022: mode |= last_writeaccess_for_exception_3 ? 0 : 16;
4023: mode |= last_notinstruction_for_exception_3 ? 8 : 0;
4024: // undocumented bits seem to contain opcode
4025: mode |= last_op_for_exception_3 & ~31;
4026: m68k_areg (regs, 7) -= 14;
4027: exception_in_exception = -1;
4028: x_put_word (m68k_areg (regs, 7) + 0, mode);
4029: x_put_long (m68k_areg (regs, 7) + 2, last_fault_for_exception_3);
4030: x_put_word (m68k_areg (regs, 7) + 6, last_op_for_exception_3);
4031: x_put_word (m68k_areg (regs, 7) + 8, regs.sr);
4032: x_put_long (m68k_areg (regs, 7) + 10, last_addr_for_exception_3);
1.1.1.8 root 4033: #ifndef WINUAE_FOR_HATARI
1.1.1.7 root 4034: write_log (_T("Exception %d (%x) at %x -> %x!\n"), nr, last_fault_for_exception_3, currpc, get_long_debug (regs.vbr + 4 * vector_nr));
1.1.1.8 root 4035: #else
1.1.1.10! root 4036: if (nr != 2 || M68000_IsVerboseBusError(currpc, last_fault_for_exception_3))
! 4037: Log_Printf(LOG_WARN, "%s Error %s at address $%x, PC=$%x addr_e3=%x op_e3=%x\n",
! 4038: nr == 2 ? "Bus" : "Address",
! 4039: last_writeaccess_for_exception_3 ? "writing" : "reading",
! 4040: last_fault_for_exception_3, currpc,
! 4041: last_addr_for_exception_3, last_op_for_exception_3);
1.1.1.7 root 4042: #endif
4043: goto kludge_me_do;
1.1.1.4 root 4044: }
4045: }
1.1.1.9 root 4046: if (!used_exception_build_stack_frame) {
4047: m68k_areg (regs, 7) -= 4;
4048: x_put_long (m68k_areg (regs, 7), nextpc);
4049: m68k_areg (regs, 7) -= 2;
4050: x_put_word (m68k_areg (regs, 7), regs.sr);
4051: }
1.1.1.8 root 4052: if (currprefs.cpu_model == 68060 && interrupt) {
4053: regs.m = 0;
4054: }
1.1.1.4 root 4055: kludge_me_do:
1.1.1.7 root 4056: newpc = x_get_long (regs.vbr + 4 * vector_nr);
4057: exception_in_exception = 0;
1.1.1.4 root 4058: if (newpc & 1) {
4059: if (nr == 2 || nr == 3)
1.1.1.8 root 4060: cpu_halt (CPU_HALT_DOUBLE_FAULT);
1.1.1.4 root 4061: else
1.1.1.7 root 4062: exception3_notinstruction(regs.ir, newpc);
1.1.1.4 root 4063: return;
4064: }
1.1.1.10! root 4065: if (interrupt)
! 4066: regs.intmask = nr - 24;
1.1.1.4 root 4067: m68k_setpc (newpc);
1.1.1.9 root 4068: cache_default_data &= ~CACHE_DISABLE_ALLOCATE;
1.1.1.8 root 4069: #ifdef WINUAE_FOR_HATARI
4070: /* Update IPL / interrupts state, in case a new interrupt happened during this exception */
4071: while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) )
4072: CALL_VAR(PendingInterruptFunction);
4073: #endif
1.1.1.4 root 4074: #ifdef JIT
4075: set_special (SPCFLAG_END_COMPILE);
4076: #endif
1.1.1.10! root 4077: branch_stack_push(currpc, nextpc);
1.1.1.7 root 4078: fill_prefetch ();
1.1.1.8 root 4079: exception_check_trace (nr);
1.1.1.4 root 4080: }
4081:
1.1.1.7 root 4082: // address = format $2 stack frame address field
4083: static void ExceptionX (int nr, uaecptr address)
1.1.1.4 root 4084: {
1.1.1.10! root 4085: uaecptr pc = m68k_getpc();
1.1.1.7 root 4086: regs.exception = nr;
4087: if (cpu_tracer) {
4088: cputrace.state = nr;
1.1.1.6 root 4089: }
1.1.1.10! root 4090: if (!regs.s) {
! 4091: regs.instruction_pc_user_exception = pc;
! 4092: }
1.1.1.6 root 4093:
1.1.1.8 root 4094: #ifdef WINUAE_FOR_HATARI
4095: /* Handle Hatari GEM and BIOS traps */
4096: if (nr == 0x22) {
4097: /* Intercept VDI & AES exceptions (Trap #2) */
4098: if (bVdiAesIntercept && VDI_AES_Entry()) {
4099: /* Set 'PC' to address of 'VDI_OPCODE' illegal instruction.
4100: * This will call OpCode_VDI() after completion of Trap call!
4101: * Used to modify specific VDI return vectors contents. */
4102: VDI_OldPC = m68k_getpc();
4103: m68k_setpc(CART_VDI_OPCODE_ADDR);
4104: }
4105: }
4106: else if (nr == 0x2d) {
4107: /* Intercept BIOS (Trap #13) calls */
4108: if (Bios()) {
4109: fill_prefetch ();
4110: regs.exception = 0;
4111: return;
4112: }
4113: }
4114: else if (nr == 0x2e) {
4115: /* Intercept XBIOS (Trap #14) calls */
4116: if (XBios()) {
4117: fill_prefetch ();
4118: regs.exception = 0;
4119: return;
4120: }
4121: }
4122: #endif
4123:
1.1.1.7 root 4124: #ifdef JIT
4125: if (currprefs.cachesize)
1.1.1.10! root 4126: regs.instruction_pc = address == -1 ? pc : address;
! 4127: #endif
! 4128:
! 4129: #ifndef WINUAE_FOR_HATARI
! 4130: if (debug_illegal && !in_rom(pc)) {
! 4131: if (nr <= 63 && (debug_illegal_mask & ((uae_u64)1 << nr))) {
! 4132: write_log(_T("Exception %d breakpoint\n"), nr);
! 4133: activate_debugger();
! 4134: }
! 4135: }
1.1.1.7 root 4136: #endif
1.1.1.10! root 4137:
1.1.1.7 root 4138: #ifdef CPUEMU_13
4139: if (currprefs.cpu_cycle_exact && currprefs.cpu_model <= 68010)
4140: Exception_ce000 (nr);
1.1.1.4 root 4141: else
4142: #endif
1.1.1.7 root 4143: if (currprefs.mmu_model) {
4144: if (currprefs.cpu_model == 68030)
4145: Exception_mmu030 (nr, m68k_getpc ());
4146: else
4147: Exception_mmu (nr, m68k_getpc ());
4148: } else {
4149: Exception_normal (nr);
4150: }
1.1.1.4 root 4151:
1.1.1.7 root 4152: regs.exception = 0;
4153: if (cpu_tracer) {
4154: cputrace.state = 0;
4155: }
4156: }
4157:
1.1.1.9 root 4158: void REGPARAM2 Exception_cpu(int nr)
4159: {
4160: bool t0 = currprefs.cpu_model >= 68020 && regs.t0;
4161: ExceptionX (nr, -1);
4162: // check T0 trace
4163: if (t0) {
4164: activate_trace();
4165: }
4166: }
1.1.1.7 root 4167: void REGPARAM2 Exception (int nr)
4168: {
4169: ExceptionX (nr, -1);
4170: }
4171: void REGPARAM2 ExceptionL (int nr, uaecptr address)
4172: {
4173: ExceptionX (nr, address);
1.1.1.4 root 4174: }
4175:
1.1.1.9 root 4176: static void bus_error(void)
4177: {
4178: TRY (prb2) {
4179: Exception (2);
4180: } CATCH (prb2) {
4181: cpu_halt (CPU_HALT_BUS_ERROR_DOUBLE_FAULT);
4182: } ENDTRY
4183: }
4184:
1.1.1.7 root 4185: static void do_interrupt (int nr)
1.1.1.4 root 4186: {
1.1.1.7 root 4187: #ifndef WINUAE_FOR_HATARI
1.1.1.4 root 4188: if (debug_dma)
4189: record_dma_event (DMA_EVENT_CPUIRQ, current_hpos (), vpos);
1.1.1.7 root 4190:
4191: if (inputrecord_debug & 2) {
4192: if (input_record > 0)
4193: inprec_recorddebug_cpu (2);
4194: else if (input_play > 0)
4195: inprec_playdebug_cpu (2);
4196: }
1.1.1.4 root 4197: #endif
4198:
1.1.1.8 root 4199: m68k_unset_stop();
1.1.1.4 root 4200: assert (nr < 8 && nr >= 0);
4201:
1.1.1.8 root 4202: for (;;) {
4203: Exception (nr + 24);
4204: if (!currprefs.cpu_compatible || currprefs.cpu_model == 68060)
4205: break;
4206: if (m68k_interrupt_delay)
4207: nr = regs.ipl;
4208: else
4209: nr = intlev();
4210: if (nr <= 0 || regs.intmask >= nr)
4211: break;
4212: }
1.1.1.4 root 4213:
4214: doint ();
4215: }
4216:
4217: void NMI (void)
4218: {
1.1.1.7 root 4219: do_interrupt (7);
1.1.1.4 root 4220: }
4221:
1.1.1.7 root 4222: static void m68k_reset_sr(void)
1.1.1.4 root 4223: {
1.1.1.7 root 4224: SET_XFLG ((regs.sr >> 4) & 1);
4225: SET_NFLG ((regs.sr >> 3) & 1);
4226: SET_ZFLG ((regs.sr >> 2) & 1);
4227: SET_VFLG ((regs.sr >> 1) & 1);
4228: SET_CFLG (regs.sr & 1);
4229: regs.t1 = (regs.sr >> 15) & 1;
4230: regs.t0 = (regs.sr >> 14) & 1;
4231: regs.s = (regs.sr >> 13) & 1;
4232: regs.m = (regs.sr >> 12) & 1;
4233: regs.intmask = (regs.sr >> 8) & 7;
4234: /* set stack pointer */
4235: if (regs.s)
4236: m68k_areg (regs, 7) = regs.isp;
4237: else
4238: m68k_areg (regs, 7) = regs.usp;
1.1.1.4 root 4239: }
4240:
1.1.1.7 root 4241: static void m68k_reset2(bool hardreset)
1.1.1.4 root 4242: {
1.1.1.7 root 4243: uae_u32 v;
1.1.1.4 root 4244:
1.1.1.10! root 4245: //fprintf ( stderr,"m68k_reset2 hard=%d in pc=%x\n" , hardreset , regs.pc );
1.1.1.7 root 4246: regs.halted = 0;
4247: #ifndef WINUAE_FOR_HATARI
4248: gui_data.cpu_halted = 0;
4249: gui_led (LED_CPU, 0, -1);
1.1.1.4 root 4250: #endif
4251:
1.1.1.7 root 4252: regs.spcflags = 0;
4253: m68k_reset_delay = 0;
4254: regs.ipl = regs.ipl_pin = 0;
1.1.1.10! root 4255: #ifndef WINUAE_FOR_HATARI
! 4256: for (int i = 0; i < IRQ_SOURCE_MAX; i++) {
! 4257: uae_interrupts2[i] = 0;
! 4258: uae_interrupts6[i] = 0;
! 4259: uae_interrupt = 0;
! 4260: }
! 4261: #endif
1.1.1.4 root 4262:
1.1.1.7 root 4263: #ifdef SAVESTATE
4264: if (isrestore ()) {
4265: m68k_reset_sr();
4266: m68k_setpc_normal (regs.pc);
1.1.1.4 root 4267: return;
4268: } else {
1.1.1.7 root 4269: m68k_reset_delay = currprefs.reset_delay;
4270: set_special(SPCFLAG_CHECK);
1.1.1.4 root 4271: }
4272: #endif
1.1.1.7 root 4273: regs.s = 1;
4274: #ifndef WINUAE_FOR_HATARI
4275: if (currprefs.cpuboard_type) {
1.1.1.8 root 4276: uaecptr stack;
1.1.1.7 root 4277: v = cpuboard_get_reset_pc(&stack);
4278: m68k_areg (regs, 7) = stack;
1.1.1.4 root 4279: } else {
1.1.1.7 root 4280: v = get_long (4);
4281: m68k_areg (regs, 7) = get_long (0);
1.1.1.8 root 4282: }
1.1.1.4 root 4283: #else
1.1.1.7 root 4284: v = get_long (4);
4285: m68k_areg (regs, 7) = get_long (0);
1.1.1.4 root 4286: #endif
1.1.1.8 root 4287:
1.1.1.7 root 4288: m68k_setpc_normal(v);
1.1.1.4 root 4289: regs.m = 0;
4290: regs.stopped = 0;
4291: regs.t1 = 0;
4292: regs.t0 = 0;
4293: SET_ZFLG (0);
4294: SET_XFLG (0);
4295: SET_CFLG (0);
4296: SET_VFLG (0);
4297: SET_NFLG (0);
4298: regs.intmask = 7;
4299: regs.vbr = regs.sfc = regs.dfc = 0;
4300: regs.irc = 0xffff;
4301: #ifdef FPUEMU
4302: fpu_reset ();
4303: #endif
4304: regs.caar = regs.cacr = 0;
4305: regs.itt0 = regs.itt1 = regs.dtt0 = regs.dtt1 = 0;
4306: regs.tcr = regs.mmusr = regs.urp = regs.srp = regs.buscr = 0;
1.1.1.7 root 4307: mmu_tt_modified ();
1.1.1.4 root 4308: if (currprefs.cpu_model == 68020) {
4309: regs.cacr |= 8;
1.1.1.7 root 4310: set_cpu_caches (false);
1.1.1.4 root 4311: }
4312:
4313: mmufixup[0].reg = -1;
4314: mmufixup[1].reg = -1;
1.1.1.9 root 4315: mmu030_cache_state = CACHE_ENABLE_ALL;
4316: mmu_cache_state = CACHE_ENABLE_ALL;
4317: if (currprefs.cpu_model >= 68040) {
4318: set_cpu_caches(false);
4319: }
1.1.1.7 root 4320: if (currprefs.mmu_model >= 68040) {
4321: mmu_reset ();
4322: mmu_set_tc (regs.tcr);
4323: mmu_set_super (regs.s != 0);
4324: } else if (currprefs.mmu_model == 68030) {
4325: mmu030_reset (hardreset || regs.halted);
4326: } else {
4327: #ifndef WINUAE_FOR_HATARI
4328: a3000_fakekick (0);
4329: #endif
4330: /* only (E)nable bit is zeroed when CPU is reset, A3000 SuperKickstart expects this */
4331: fake_tc_030 &= ~0x80000000;
4332: fake_tt0_030 &= ~0x80000000;
4333: fake_tt1_030 &= ~0x80000000;
4334: if (hardreset || regs.halted) {
4335: fake_srp_030 = fake_crp_030 = 0;
4336: fake_tt0_030 = fake_tt1_030 = fake_tc_030 = 0;
1.1.1.5 root 4337: }
1.1.1.7 root 4338: fake_mmusr_030 = 0;
1.1.1.4 root 4339: }
4340:
4341: /* 68060 FPU is not compatible with 68040,
4342: * 68060 accelerators' boot ROM disables the FPU
4343: */
4344: regs.pcr = 0;
4345: if (currprefs.cpu_model == 68060) {
4346: regs.pcr = currprefs.fpu_model == 68060 ? MC68060_PCR : MC68EC060_PCR;
4347: regs.pcr |= (currprefs.cpu060_revision & 0xff) << 8;
1.1.1.7 root 4348: #ifndef WINUAE_FOR_HATARI
1.1.1.10! root 4349: if (currprefs.fpu_model == 0 || (currprefs.cpuboard_type == 0 && rtarea_base != 0xf00000)) {
! 4350: /* disable FPU if no accelerator board and no $f0 ROM */
! 4351: regs.pcr |= 2;
! 4352: }
1.1.1.7 root 4353: #endif
4354: }
1.1.1.9 root 4355: // regs.ce020memcycles = 0;
4356: regs.ce020startcycle = regs.ce020endcycle = 0;
1.1.1.7 root 4357: fill_prefetch ();
1.1.1.10! root 4358: //fprintf ( stderr,"m68k_reset2 out pc=%x\n" , regs.pc );
1.1.1.7 root 4359: }
1.1.1.8 root 4360:
1.1.1.7 root 4361: void m68k_reset(void)
4362: {
4363: m68k_reset2(false);
4364: }
4365:
1.1.1.8 root 4366: #ifndef WINUAE_FOR_HATARI
4367: void cpu_change(int newmodel)
4368: {
4369: if (newmodel == currprefs.cpu_model)
4370: return;
4371: fallback_new_cpu_model = newmodel;
4372: cpu_halt(CPU_HALT_ACCELERATOR_CPU_FALLBACK);
4373: }
1.1.1.7 root 4374:
1.1.1.8 root 4375: void cpu_fallback(int mode)
1.1.1.7 root 4376: {
1.1.1.8 root 4377: int fallbackmodel;
4378: if (currprefs.chipset_mask & CSMASK_AGA) {
4379: fallbackmodel = 68020;
4380: } else {
4381: fallbackmodel = 68000;
4382: }
4383: if (mode < 0) {
4384: if (currprefs.cpu_model > fallbackmodel) {
4385: cpu_change(fallbackmodel);
4386: } else if (fallback_new_cpu_model) {
4387: cpu_change(fallback_new_cpu_model);
4388: }
4389: } else if (mode == 0) {
4390: cpu_change(fallbackmodel);
4391: } else if (mode) {
4392: if (fallback_cpu_model) {
4393: cpu_change(fallback_cpu_model);
4394: }
1.1.1.4 root 4395: }
1.1.1.8 root 4396: }
4397:
4398: static void cpu_do_fallback(void)
4399: {
4400: bool fallbackmode = false;
4401: if ((fallback_new_cpu_model < 68020 && !(currprefs.chipset_mask & CSMASK_AGA)) || (fallback_new_cpu_model == 68020 && (currprefs.chipset_mask & CSMASK_AGA))) {
4402: // -> 68000/68010 or 68EC020
4403: fallback_cpu_model = currprefs.cpu_model;
4404: fallback_fpu_model = currprefs.fpu_model;
4405: fallback_mmu_model = currprefs.mmu_model;
4406: fallback_cpu_compatible = currprefs.cpu_compatible;
4407: fallback_cpu_address_space_24 = currprefs.address_space_24;
4408: changed_prefs.cpu_model = currprefs.cpu_model_fallback && fallback_new_cpu_model <= 68020 ? currprefs.cpu_model_fallback : fallback_new_cpu_model;
4409: changed_prefs.fpu_model = 0;
4410: changed_prefs.mmu_model = 0;
4411: changed_prefs.cpu_compatible = true;
4412: changed_prefs.address_space_24 = true;
4413: memcpy(&fallback_regs, ®s, sizeof(struct regstruct));
4414: fallback_regs.pc = M68K_GETPC;
4415: fallbackmode = true;
4416: } else {
4417: // -> 68020+
4418: changed_prefs.cpu_model = fallback_cpu_model;
4419: changed_prefs.fpu_model = fallback_fpu_model;
4420: changed_prefs.mmu_model = fallback_mmu_model;
4421: changed_prefs.cpu_compatible = fallback_cpu_compatible;
4422: changed_prefs.address_space_24 = fallback_cpu_address_space_24;
4423: fallback_cpu_model = 0;
4424: }
4425: init_m68k();
4426: m68k_reset2(false);
4427: if (!fallbackmode) {
4428: // restore original 68020+
4429: memcpy(®s, &fallback_regs, sizeof(regs));
4430: restore_banks();
4431: memory_restore();
4432: memory_map_dump();
4433: m68k_setpc(fallback_regs.pc);
4434: } else {
1.1.1.9 root 4435: // 68000/010/EC020
1.1.1.8 root 4436: memory_restore();
4437: expansion_cpu_fallback();
4438: memory_map_dump();
4439: }
4440: }
1.1.1.10! root 4441: #endif
1.1.1.8 root 4442:
4443: static void m68k_reset_restore(void)
4444: {
1.1.1.10! root 4445: #ifndef WINUAE_FOR_HATARI
1.1.1.8 root 4446: // hardreset and 68000/68020 fallback mode? Restore original mode.
4447: if (fallback_cpu_model) {
4448: fallback_new_cpu_model = fallback_cpu_model;
4449: fallback_regs.pc = 0;
4450: cpu_do_fallback();
4451: }
4452: #endif
1.1.1.10! root 4453: }
! 4454:
1.1.1.8 root 4455: void REGPARAM2 op_unimpl (uae_u16 opcode)
4456: {
4457: static int warned;
4458: if (warned < 20) {
4459: write_log (_T("68060 unimplemented opcode %04X, PC=%08x\n"), opcode, regs.instruction_pc);
4460: warned++;
4461: }
4462: ExceptionL (61, regs.instruction_pc);
1.1.1.4 root 4463: }
4464:
1.1.1.7 root 4465: uae_u32 REGPARAM2 op_illg (uae_u32 opcode)
1.1.1.4 root 4466: {
4467: uaecptr pc = m68k_getpc ();
4468: static int warned;
4469:
1.1.1.7 root 4470: #ifndef WINUAE_FOR_HATARI
1.1.1.4 root 4471: int inrom = in_rom (pc);
4472: int inrt = in_rtarea (pc);
4473:
1.1.1.9 root 4474: if ((opcode == 0x4afc || opcode == 0xfc4a) && !valid_address(pc, 4) && valid_address(pc - 4, 4)) {
4475: // PC fell off the end of RAM
4476: bus_error();
4477: return 4;
4478: }
4479:
1.1.1.10! root 4480: if (debugmem_illg(opcode)) {
! 4481: m68k_incpc_normal(2);
! 4482: return 4;
! 4483: }
! 4484:
1.1.1.4 root 4485: if (cloanto_rom && (opcode & 0xF100) == 0x7100) {
4486: m68k_dreg (regs, (opcode >> 9) & 7) = (uae_s8)(opcode & 0xFF);
1.1.1.7 root 4487: m68k_incpc_normal (2);
4488: fill_prefetch ();
1.1.1.4 root 4489: return 4;
4490: }
4491:
1.1.1.7 root 4492: if (opcode == 0x4E7B && inrom) {
4493: if (get_long (0x10) == 0) {
4494: notify_user (NUMSG_KS68020);
4495: uae_restart (-1, NULL);
1.1.1.8 root 4496: m68k_setstopped();
4497: return 4;
1.1.1.7 root 4498: }
1.1.1.4 root 4499: }
4500:
4501: #ifdef AUTOCONFIG
1.1.1.7 root 4502: if (opcode == 0xFF0D && inrt) {
4503: /* User-mode STOP replacement */
4504: m68k_setstopped ();
4505: return 4;
1.1.1.4 root 4506: }
4507:
4508: if ((opcode & 0xF000) == 0xA000 && inrt) {
4509: /* Calltrap. */
1.1.1.7 root 4510: m68k_incpc_normal (2);
4511: m68k_handle_trap(opcode & 0xFFF);
4512: fill_prefetch ();
1.1.1.4 root 4513: return 4;
4514: }
4515: #endif
1.1.1.7 root 4516: #endif
1.1.1.4 root 4517:
4518: if ((opcode & 0xF000) == 0xF000) {
1.1.1.7 root 4519: #ifndef WINUAE_FOR_HATARI
1.1.1.4 root 4520: if (warned < 20) {
1.1.1.7 root 4521: write_log(_T("B-Trap %04X at %08X -> %08X\n"), opcode, pc, get_long_debug(regs.vbr + 0x2c));
1.1.1.4 root 4522: warned++;
4523: }
1.1.1.7 root 4524: #endif
4525: Exception (0xB);
1.1.1.10! root 4526: //activate_debugger_new();
1.1.1.4 root 4527: return 4;
4528: }
4529: if ((opcode & 0xF000) == 0xA000) {
1.1.1.7 root 4530: #ifndef WINUAE_FOR_HATARI
1.1.1.4 root 4531: if (warned < 20) {
1.1.1.7 root 4532: write_log(_T("A-Trap %04X at %08X -> %08X\n"), opcode, pc, get_long_debug(regs.vbr + 0x28));
1.1.1.4 root 4533: warned++;
4534: }
1.1.1.7 root 4535: #endif
4536: Exception (0xA);
1.1.1.10! root 4537: //activate_debugger_new();
1.1.1.4 root 4538: return 4;
4539: }
4540: if (warned < 20) {
1.1.1.7 root 4541: write_log (_T("Illegal instruction: %04x at %08X -> %08X\n"), opcode, pc, get_long_debug(regs.vbr + 0x10));
1.1.1.4 root 4542: warned++;
1.1.1.10! root 4543: //activate_debugger_new();
1.1.1.4 root 4544: }
4545:
1.1.1.7 root 4546: Exception (4);
1.1.1.4 root 4547: return 4;
4548: }
4549:
4550: #ifdef CPUEMU_0
4551:
1.1.1.9 root 4552: static bool mmu_op30_invea(uae_u32 opcode)
1.1.1.4 root 4553: {
1.1.1.9 root 4554: int eamode = (opcode >> 3) & 7;
1.1.1.7 root 4555: int rreg = opcode & 7;
1.1.1.9 root 4556:
4557: // Dn, An, (An)+, -(An), immediate and PC-relative not allowed
1.1.1.10! root 4558: if (eamode == 0 || eamode == 1 || eamode == 3 || eamode == 4 || (eamode == 7 && rreg > 1))
1.1.1.9 root 4559: return true;
4560: return false;
4561: }
4562:
4563: static bool mmu_op30fake_pmove (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra)
4564: {
1.1.1.7 root 4565: int preg = (next >> 10) & 31;
4566: int rw = (next >> 9) & 1;
4567: int fd = (next >> 8) & 1;
1.1.1.9 root 4568: int unused = (next & 0xff);
1.1.1.7 root 4569: const TCHAR *reg = NULL;
1.1.1.8 root 4570: #ifndef WINUAE_FOR_HATARI
1.1.1.7 root 4571: uae_u32 otc = fake_tc_030;
1.1.1.8 root 4572: #endif
1.1.1.7 root 4573: int siz;
4574:
1.1.1.9 root 4575: if (mmu_op30_invea(opcode))
4576: return true;
4577: // unused low 8 bits must be zeroed
4578: if (unused)
4579: return true;
4580: // read and fd set?
4581: if (rw && fd)
1.1.1.7 root 4582: return true;
1.1.1.5 root 4583:
1.1.1.7 root 4584: switch (preg)
4585: {
4586: case 0x10: // TC
4587: reg = _T("TC");
4588: siz = 4;
4589: if (rw)
4590: x_put_long (extra, fake_tc_030);
4591: else
4592: fake_tc_030 = x_get_long (extra);
4593: break;
4594: case 0x12: // SRP
4595: reg = _T("SRP");
4596: siz = 8;
4597: if (rw) {
4598: x_put_long (extra, fake_srp_030 >> 32);
4599: x_put_long (extra + 4, (uae_u32)fake_srp_030);
4600: } else {
4601: fake_srp_030 = (uae_u64)x_get_long (extra) << 32;
4602: fake_srp_030 |= x_get_long (extra + 4);
4603: }
4604: break;
4605: case 0x13: // CRP
4606: reg = _T("CRP");
4607: siz = 8;
4608: if (rw) {
4609: x_put_long (extra, fake_crp_030 >> 32);
4610: x_put_long (extra + 4, (uae_u32)fake_crp_030);
4611: } else {
4612: fake_crp_030 = (uae_u64)x_get_long (extra) << 32;
4613: fake_crp_030 |= x_get_long (extra + 4);
4614: }
4615: break;
4616: case 0x18: // MMUSR
1.1.1.9 root 4617: if (fd) {
4618: // FD must be always zero when MMUSR read or write
4619: return true;
4620: }
1.1.1.7 root 4621: reg = _T("MMUSR");
4622: siz = 2;
4623: if (rw)
4624: x_put_word (extra, fake_mmusr_030);
4625: else
4626: fake_mmusr_030 = x_get_word (extra);
4627: break;
4628: case 0x02: // TT0
4629: reg = _T("TT0");
4630: siz = 4;
4631: if (rw)
4632: x_put_long (extra, fake_tt0_030);
4633: else
4634: fake_tt0_030 = x_get_long (extra);
4635: break;
4636: case 0x03: // TT1
4637: reg = _T("TT1");
4638: siz = 4;
4639: if (rw)
4640: x_put_long (extra, fake_tt1_030);
4641: else
4642: fake_tt1_030 = x_get_long (extra);
4643: break;
4644: }
1.1.1.4 root 4645:
1.1.1.9 root 4646: if (!reg)
1.1.1.7 root 4647: return true;
1.1.1.9 root 4648:
1.1.1.4 root 4649: #if MMUOP_DEBUG > 0
1.1.1.7 root 4650: {
4651: uae_u32 val;
4652: if (siz == 8) {
4653: uae_u32 val2 = x_get_long (extra);
4654: val = x_get_long (extra + 4);
4655: if (rw)
4656: write_log (_T("PMOVE %s,%08X%08X"), reg, val2, val);
4657: else
4658: write_log (_T("PMOVE %08X%08X,%s"), val2, val, reg);
4659: } else {
4660: if (siz == 4)
4661: val = x_get_long (extra);
4662: else
4663: val = x_get_word (extra);
4664: if (rw)
4665: write_log (_T("PMOVE %s,%08X"), reg, val);
4666: else
4667: write_log (_T("PMOVE %08X,%s"), val, reg);
1.1.1.4 root 4668: }
1.1.1.7 root 4669: write_log (_T(" PC=%08X\n"), pc);
4670: }
1.1.1.4 root 4671: #endif
1.1.1.7 root 4672: #ifndef WINUAE_FOR_HATARI
4673: if ((currprefs.cs_mbdmac & 1) && currprefs.mbresmem_low_size > 0) {
4674: if (otc != fake_tc_030) {
4675: a3000_fakekick (fake_tc_030 & 0x80000000);
1.1.1.4 root 4676: }
4677: }
4678: #endif
1.1.1.7 root 4679: return false;
1.1.1.4 root 4680: }
4681:
1.1.1.7 root 4682: static bool mmu_op30fake_ptest (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra)
4683: {
1.1.1.9 root 4684: int eamode = (opcode >> 3) & 7;
4685: int rreg = opcode & 7;
4686: int level = (next&0x1C00)>>10;
4687: int a = (next >> 8) & 1;
4688:
4689: if (mmu_op30_invea(opcode))
4690: return true;
4691: if (!level && a)
4692: return true;
4693:
1.1.1.7 root 4694: #if MMUOP_DEBUG > 0
4695: TCHAR tmp[10];
4696:
4697: tmp[0] = 0;
4698: if ((next >> 8) & 1)
4699: _stprintf (tmp, _T(",A%d"), (next >> 4) & 15);
4700: write_log (_T("PTEST%c %02X,%08X,#%X%s PC=%08X\n"),
4701: ((next >> 9) & 1) ? 'W' : 'R', (next & 15), extra, (next >> 10) & 7, tmp, pc);
1.1.1.4 root 4702: #endif
1.1.1.7 root 4703: fake_mmusr_030 = 0;
4704: return false;
4705: }
1.1.1.4 root 4706:
1.1.1.9 root 4707: static bool mmu_op30fake_pload (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra)
4708: {
4709: int unused = (next & (0x100 | 0x80 | 0x40 | 0x20));
4710:
4711: if (mmu_op30_invea(opcode))
4712: return true;
4713: if (unused)
4714: return true;
4715: write_log(_T("PLOAD\n"));
4716: return false;
4717: }
4718:
1.1.1.7 root 4719: static bool mmu_op30fake_pflush (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra)
4720: {
1.1.1.9 root 4721: int flushmode = (next >> 8) & 31;
1.1.1.7 root 4722: int fc = next & 31;
4723: int mask = (next >> 5) & 3;
1.1.1.9 root 4724: int fc_bits = next & 0x7f;
1.1.1.7 root 4725: TCHAR fname[100];
4726:
4727: switch (flushmode)
4728: {
1.1.1.9 root 4729: case 0x00:
1.1.1.10! root 4730: case 0x02:
1.1.1.9 root 4731: return mmu_op30fake_pload(pc, opcode, next, extra);
4732: case 0x18:
4733: if (mmu_op30_invea(opcode))
1.1.1.7 root 4734: return true;
4735: _stprintf (fname, _T("FC=%x MASK=%x EA=%08x"), fc, mask, 0);
4736: break;
1.1.1.9 root 4737: case 0x10:
1.1.1.7 root 4738: _stprintf (fname, _T("FC=%x MASK=%x"), fc, mask);
4739: break;
1.1.1.9 root 4740: case 0x04:
4741: if (fc_bits)
4742: return true;
1.1.1.7 root 4743: _tcscpy (fname, _T("ALL"));
4744: break;
4745: default:
4746: return true;
4747: }
4748: #if MMUOP_DEBUG > 0
4749: write_log (_T("PFLUSH %s PC=%08X\n"), fname, pc);
4750: #endif
4751: return false;
4752: }
4753:
4754: // 68030 (68851) MMU instructions only
4755: bool mmu_op30 (uaecptr pc, uae_u32 opcode, uae_u16 extra, uaecptr extraa)
4756: {
4757: int type = extra >> 13;
1.1.1.9 root 4758: bool fline = false;
1.1.1.7 root 4759:
4760: switch (type)
4761: {
4762: case 0:
4763: case 2:
4764: case 3:
1.1.1.9 root 4765: if (currprefs.mmu_model)
4766: fline = mmu_op30_pmove (pc, opcode, extra, extraa);
4767: else
4768: fline = mmu_op30fake_pmove (pc, opcode, extra, extraa);
1.1.1.7 root 4769: break;
4770: case 1:
1.1.1.9 root 4771: if (currprefs.mmu_model)
4772: fline = mmu_op30_pflush (pc, opcode, extra, extraa);
4773: else
4774: fline = mmu_op30fake_pflush (pc, opcode, extra, extraa);
1.1.1.7 root 4775: break;
4776: case 4:
1.1.1.9 root 4777: if (currprefs.mmu_model)
4778: fline = mmu_op30_ptest (pc, opcode, extra, extraa);
4779: else
4780: fline = mmu_op30fake_ptest (pc, opcode, extra, extraa);
1.1.1.7 root 4781: break;
4782: }
1.1.1.9 root 4783: if (fline) {
4784: m68k_setpc(pc);
4785: op_illg(opcode);
4786: }
4787: return fline;
4788: }
4789:
4790: /* check if an address matches a ttr */
4791: static int fake_mmu_do_match_ttr(uae_u32 ttr, uaecptr addr, bool super)
4792: {
4793: if (ttr & MMU_TTR_BIT_ENABLED) { /* TTR enabled */
4794: uae_u8 msb, mask;
4795:
4796: msb = ((addr ^ ttr) & MMU_TTR_LOGICAL_BASE) >> 24;
4797: mask = (ttr & MMU_TTR_LOGICAL_MASK) >> 16;
4798:
4799: if (!(msb & ~mask)) {
4800:
4801: if ((ttr & MMU_TTR_BIT_SFIELD_ENABLED) == 0) {
4802: if (((ttr & MMU_TTR_BIT_SFIELD_SUPER) == 0) != (super == 0)) {
4803: return TTR_NO_MATCH;
4804: }
4805: }
4806:
4807: return (ttr & MMU_TTR_BIT_WRITE_PROTECT) ? TTR_NO_WRITE : TTR_OK_MATCH;
4808: }
4809: }
4810: return TTR_NO_MATCH;
4811: }
4812:
4813: static int fake_mmu_match_ttr(uaecptr addr, bool super, bool data)
4814: {
4815: int res;
4816:
4817: if (data) {
4818: res = fake_mmu_do_match_ttr(regs.dtt0, addr, super);
4819: if (res == TTR_NO_MATCH)
4820: res = fake_mmu_do_match_ttr(regs.dtt1, addr, super);
4821: } else {
4822: res = fake_mmu_do_match_ttr(regs.itt0, addr, super);
4823: if (res == TTR_NO_MATCH)
4824: res = fake_mmu_do_match_ttr(regs.itt1, addr, super);
4825: }
4826: return res;
1.1.1.7 root 4827: }
4828:
4829: // 68040+ MMU instructions only
4830: void mmu_op (uae_u32 opcode, uae_u32 extra)
4831: {
4832: if (currprefs.mmu_model) {
4833: mmu_op_real (opcode, extra);
4834: return;
4835: }
4836: #if MMUOP_DEBUG > 1
4837: write_log (_T("mmu_op %04X PC=%08X\n"), opcode, m68k_getpc ());
4838: #endif
4839: if ((opcode & 0xFE0) == 0x0500) {
4840: /* PFLUSH */
4841: regs.mmusr = 0;
4842: #if MMUOP_DEBUG > 0
4843: write_log (_T("PFLUSH\n"));
4844: #endif
4845: return;
1.1.1.9 root 4846: } else if ((opcode & 0x0FD8) == 0x0548) {
1.1.1.7 root 4847: if (currprefs.cpu_model < 68060) { /* PTEST not in 68060 */
4848: /* PTEST */
1.1.1.9 root 4849: int regno = opcode & 7;
4850: uae_u32 addr = m68k_areg(regs, regno);
4851: bool write = (opcode & 32) == 0;
4852: bool super = (regs.dfc & 4) != 0;
4853: bool data = (regs.dfc & 3) != 2;
4854:
4855: regs.mmusr = 0;
4856: if (fake_mmu_match_ttr(addr, super, data) != TTR_NO_MATCH) {
4857: regs.mmusr = MMU_MMUSR_T | MMU_MMUSR_R;
4858: }
4859: regs.mmusr |= addr & 0xfffff000;
1.1.1.7 root 4860: #if MMUOP_DEBUG > 0
1.1.1.9 root 4861: write_log (_T("PTEST%c %08x\n"), write ? 'W' : 'R', addr);
1.1.1.7 root 4862: #endif
4863: return;
4864: }
1.1.1.9 root 4865: } else if ((opcode & 0x0FB8) == 0x0588) {
1.1.1.7 root 4866: /* PLPA */
4867: if (currprefs.cpu_model == 68060) {
1.1.1.9 root 4868: int regno = opcode & 7;
4869: uae_u32 addr = m68k_areg (regs, regno);
4870: int write = (opcode & 0x40) == 0;
4871: bool data = (regs.dfc & 3) != 2;
4872: bool super = (regs.dfc & 4) != 0;
4873:
4874: if (fake_mmu_match_ttr(addr, super, data) == TTR_NO_MATCH) {
4875: m68k_areg (regs, regno) = addr;
4876: }
1.1.1.7 root 4877: #if MMUOP_DEBUG > 0
4878: write_log (_T("PLPA\n"));
4879: #endif
4880: return;
4881: }
4882: }
4883: #if MMUOP_DEBUG > 0
4884: write_log (_T("Unknown MMU OP %04X\n"), opcode);
4885: #endif
4886: m68k_setpc_normal (m68k_getpc () - 2);
4887: op_illg (opcode);
4888: }
4889:
4890: #endif
4891:
1.1.1.4 root 4892: static void do_trace (void)
4893: {
4894: if (regs.t0 && currprefs.cpu_model >= 68020) {
1.1.1.9 root 4895: // this is obsolete
4896: return;
4897: }
4898: if (regs.t1) {
4899: activate_trace();
1.1.1.4 root 4900: }
4901: }
4902:
1.1.1.8 root 4903: #ifndef WINUAE_FOR_HATARI
1.1.1.7 root 4904: static void check_uae_int_request(void)
4905: {
1.1.1.10! root 4906: bool irq2 = false;
! 4907: bool irq6 = false;
! 4908: if (atomic_and(&uae_interrupt, 0)) {
! 4909: for (int i = 0; i < IRQ_SOURCE_MAX; i++) {
! 4910: if (!irq2 && uae_interrupts2[i]) {
! 4911: uae_atomic v = atomic_and(&uae_interrupts2[i], 0);
! 4912: if (v) {
! 4913: INTREQ_f(0x8000 | 0x0008);
! 4914: irq2 = true;
! 4915: }
! 4916: }
! 4917: if (!irq6 && uae_interrupts6[i]) {
! 4918: uae_atomic v = atomic_and(&uae_interrupts6[i], 0);
! 4919: if (v) {
! 4920: INTREQ_f(0x8000 | 0x2000);
! 4921: irq6 = true;
! 4922: }
! 4923: }
! 4924: }
! 4925: }
1.1.1.8 root 4926: if (uae_int_requested) {
1.1.1.10! root 4927: if (!irq2 && (uae_int_requested & 0x00ff)) {
1.1.1.7 root 4928: INTREQ_f(0x8000 | 0x0008);
1.1.1.10! root 4929: irq2 = true;
1.1.1.8 root 4930: }
1.1.1.10! root 4931: if (!irq6 && (uae_int_requested & 0xff00)) {
1.1.1.7 root 4932: INTREQ_f(0x8000 | 0x2000);
1.1.1.10! root 4933: irq6 = true;
1.1.1.8 root 4934: }
4935: if (uae_int_requested & 0xff0000) {
1.1.1.10! root 4936: if (!cpuboard_is_ppcboard_irq()) {
1.1.1.8 root 4937: atomic_and(&uae_int_requested, ~0x010000);
1.1.1.10! root 4938: }
1.1.1.8 root 4939: }
1.1.1.10! root 4940: }
! 4941: if (irq2 || irq6) {
! 4942: doint();
1.1.1.7 root 4943: }
1.1.1.8 root 4944: }
4945:
1.1.1.10! root 4946: void safe_interrupt_set(int num, int id, bool i6)
1.1.1.8 root 4947: {
1.1.1.10! root 4948: if (!is_mainthread()) {
! 4949: set_special_exter(SPCFLAG_UAEINT);
! 4950: volatile uae_atomic *p;
! 4951: if (i6)
! 4952: p = &uae_interrupts6[num];
! 4953: else
! 4954: p = &uae_interrupts2[num];
! 4955: atomic_or(p, 1 << id);
! 4956: atomic_or(&uae_interrupt, 1);
! 4957: } else {
! 4958: uae_u16 v = i6 ? 0x2000 : 0x0008;
! 4959: if (currprefs.cpu_cycle_exact || (!(intreq & v) && !currprefs.cpu_cycle_exact)) {
! 4960: INTREQ_0(0x8000 | v);
! 4961: }
! 4962: }
1.1.1.7 root 4963: }
1.1.1.8 root 4964: #endif
4965:
4966: int cpu_sleep_millis(int ms)
4967: {
4968: int ret = 0;
1.1.1.7 root 4969: #ifdef WITH_PPC
4970: int state = ppc_state;
4971: if (state)
4972: uae_ppc_spinlock_release();
4973: #endif
1.1.1.8 root 4974: #ifdef WITH_X86
1.1.1.10! root 4975: // if (x86_turbo_on) {
! 4976: // execute_other_cpu(read_processor_time() + vsynctimebase / 20);
! 4977: // } else {
1.1.1.8 root 4978: ret = sleep_millis_main(ms);
1.1.1.10! root 4979: // }
1.1.1.8 root 4980: #endif
1.1.1.7 root 4981: #ifdef WITH_PPC
4982: if (state)
4983: uae_ppc_spinlock_get();
4984: #endif
1.1.1.8 root 4985: return ret;
1.1.1.7 root 4986: }
4987:
4988: #define PPC_HALTLOOP_SCANLINES 25
4989: // ppc_cpu_idle
4990: // 0 = busy
4991: // 1-9 = wait, levels
4992: // 10 = max wait
4993:
1.1.1.8 root 4994: #ifndef WINUAE_FOR_HATARI
4995: static bool haltloop_do(int vsynctimeline, int rpt_end, int lines)
4996: {
4997: int ovpos = vpos;
4998: while (lines-- >= 0) {
4999: ovpos = vpos;
5000: while (ovpos == vpos) {
5001: x_do_cycles(8 * CYCLE_UNIT);
5002: unset_special(SPCFLAG_UAEINT);
5003: check_uae_int_request();
5004: #ifdef WITH_PPC
5005: ppc_interrupt(intlev());
5006: uae_ppc_execute_check();
5007: #endif
5008: if (regs.spcflags & SPCFLAG_COPPER)
5009: do_copper();
5010: if (regs.spcflags & (SPCFLAG_BRK | SPCFLAG_MODE_CHANGE)) {
5011: if (regs.spcflags & SPCFLAG_BRK) {
5012: unset_special(SPCFLAG_BRK);
5013: #ifdef DEBUGGER
5014: if (debugging)
5015: debug();
5016: #endif
5017: }
5018: return true;
5019: }
5020: }
5021:
5022: // sync chipset with real time
5023: for (;;) {
5024: check_uae_int_request();
5025: #ifdef WITH_PPC
5026: ppc_interrupt(intlev());
5027: uae_ppc_execute_check();
5028: #endif
5029: if (event_wait)
5030: break;
5031: int d = read_processor_time() - rpt_end;
5032: if (d < -2 * vsynctimeline || d >= 0)
5033: break;
5034: }
5035: }
5036: return false;
5037: }
5038: #endif
5039:
1.1.1.7 root 5040: static bool haltloop(void)
5041: {
5042: #ifndef WINUAE_FOR_HATARI
5043: #ifdef WITH_PPC
5044: if (regs.halted < 0) {
5045: int rpt_end = 0;
5046: int ovpos = vpos;
5047:
5048: while (regs.halted) {
5049: int vsynctimeline = vsynctimebase / (maxvpos_display + 1);
5050: int lines;
5051: int rpt_scanline = read_processor_time();
5052: int rpt_end = rpt_scanline + vsynctimeline;
5053:
5054: // See expansion handling.
5055: // Dialog must be opened from main thread.
5056: if (regs.halted == -2) {
5057: regs.halted = -1;
5058: notify_user (NUMSG_UAEBOOTROM_PPC);
5059: }
5060:
5061: if (currprefs.ppc_cpu_idle) {
5062:
5063: int maxlines = 100 - (currprefs.ppc_cpu_idle - 1) * 10;
5064: int i;
5065:
5066: event_wait = false;
5067: for (i = 0; i < ev_max; i++) {
5068: if (i == ev_hsync)
5069: continue;
5070: if (i == ev_audio)
5071: continue;
5072: if (!eventtab[i].active)
5073: continue;
5074: if (eventtab[i].evtime - currcycle < maxlines * maxhpos * CYCLE_UNIT)
5075: break;
5076: }
5077: if (currprefs.ppc_cpu_idle >= 10 || (i == ev_max && vpos > 0 && vpos < maxvpos - maxlines)) {
5078: cpu_sleep_millis(1);
5079: }
5080: check_uae_int_request();
5081: uae_ppc_execute_check();
5082:
5083: lines = (read_processor_time() - rpt_scanline) / vsynctimeline + 1;
5084:
5085: } else {
5086:
5087: event_wait = true;
5088: lines = 0;
5089:
5090: }
5091:
5092: if (lines > maxvpos / 2)
5093: lines = maxvpos / 2;
5094:
1.1.1.8 root 5095: if (haltloop_do(vsynctimeline, rpt_end, lines))
5096: return true;
1.1.1.7 root 5097:
1.1.1.4 root 5098: }
1.1.1.7 root 5099:
5100: } else {
1.1.1.4 root 5101: #endif
1.1.1.7 root 5102: while (regs.halted) {
5103: static int prevvpos;
5104: if (vpos == 0 && prevvpos) {
5105: prevvpos = 0;
5106: cpu_sleep_millis(8);
5107: }
5108: if (vpos)
5109: prevvpos = 1;
5110: x_do_cycles(8 * CYCLE_UNIT);
5111:
5112: if (regs.spcflags & SPCFLAG_COPPER)
5113: do_copper();
5114:
5115: if (regs.spcflags) {
5116: if ((regs.spcflags & (SPCFLAG_BRK | SPCFLAG_MODE_CHANGE)))
5117: return true;
5118: }
5119: }
5120: #ifdef WITH_PPC
1.1.1.4 root 5121: }
1.1.1.7 root 5122: #endif
5123:
5124: return false;
5125: #else
5126: /* In Hatari, we don't use the halt state, we do a reset */
5127: return false;
5128: #endif
1.1.1.4 root 5129: }
5130:
1.1.1.7 root 5131: #ifdef WITH_PPC
5132: static bool uae_ppc_poll_check_halt(void)
1.1.1.4 root 5133: {
1.1.1.7 root 5134: if (regs.halted) {
5135: if (haltloop())
5136: return true;
1.1.1.4 root 5137: }
1.1.1.7 root 5138: return false;
1.1.1.4 root 5139: }
1.1.1.7 root 5140: #endif
1.1.1.4 root 5141:
5142:
1.1.1.7 root 5143: // handle interrupt delay (few cycles)
5144: STATIC_INLINE bool time_for_interrupt (void)
1.1.1.4 root 5145: {
1.1.1.7 root 5146: return regs.ipl > regs.intmask || regs.ipl == 7;
5147: }
1.1.1.4 root 5148:
1.1.1.7 root 5149: void doint (void)
5150: {
5151: #ifdef WITH_PPC
5152: if (ppc_state) {
5153: if (!ppc_interrupt(intlev()))
5154: return;
1.1.1.4 root 5155: }
1.1.1.7 root 5156: #endif
1.1.1.8 root 5157: //fprintf ( stderr , "doint1 %d ipl=%x ipl_pin=%x intmask=%x spcflags=%x\n" , m68k_interrupt_delay,regs.ipl, regs.ipl_pin , regs.intmask, regs.spcflags );
1.1.1.7 root 5158: if (m68k_interrupt_delay) {
5159: regs.ipl_pin = intlev ();
5160: unset_special (SPCFLAG_INT);
1.1.1.8 root 5161: //fprintf ( stderr , "doint2 %d ipl=%x ipl_pin=%x intmask=%x spcflags=%x\n" , m68k_interrupt_delay,regs.ipl, regs.ipl_pin , regs.intmask, regs.spcflags );
1.1.1.7 root 5162: return;
1.1.1.4 root 5163: }
1.1.1.7 root 5164: if (currprefs.cpu_compatible && currprefs.cpu_model < 68020)
5165: set_special (SPCFLAG_INT);
5166: else
5167: set_special (SPCFLAG_DOINT);
1.1.1.4 root 5168: }
5169:
5170:
1.1.1.7 root 5171: #ifdef WINUAE_FOR_HATARI
1.1.1.4 root 5172: /*
5173: * Handle special flags
5174: */
5175:
5176: static bool do_specialties_interrupt (int Pending)
5177: {
1.1.1.5 root 5178: #if ENABLE_DSP_EMU
5179: /* Check for DSP int first (if enabled) (level 6) */
5180: if (regs.spcflags & SPCFLAG_DSP) {
5181: if (DSP_ProcessIRQ() == true)
5182: return true;
5183: }
5184: #endif
5185:
5186: /* Check for MFP ints (level 6) */
1.1.1.4 root 5187: if (regs.spcflags & SPCFLAG_MFP) {
1.1.1.5 root 5188: if (MFP_ProcessIRQ() == true)
1.1.1.4 root 5189: return true; /* MFP exception was generated, no higher interrupt can happen */
5190: }
5191:
5192: /* No MFP int, check for VBL/HBL ints (levels 4/2) */
5193: if (regs.spcflags & (SPCFLAG_INT | SPCFLAG_DOINT)) {
5194: int intr = intlev ();
5195: /* SPCFLAG_DOINT will be enabled again in MakeFromSR to handle pending interrupts! */
5196: // unset_special (SPCFLAG_DOINT);
5197: unset_special (SPCFLAG_INT | SPCFLAG_DOINT);
5198: if (intr != -1 && intr > regs.intmask) {
1.1.1.7 root 5199: do_interrupt (intr); /* process the interrupt */
1.1.1.4 root 5200: return true;
5201: }
5202: }
5203:
5204: return false; /* no interrupt was found */
5205: }
1.1.1.7 root 5206: #endif
1.1.1.4 root 5207:
1.1.1.7 root 5208: static int do_specialties (int cycles)
1.1.1.4 root 5209: {
1.1.1.10! root 5210: bool stopped_debug = false;
! 5211:
1.1.1.7 root 5212: if (regs.spcflags & SPCFLAG_MODE_CHANGE)
5213: return 1;
5214:
5215: #ifndef WINUAE_FOR_HATARI
5216: if (regs.spcflags & SPCFLAG_CHECK) {
5217: if (regs.halted) {
1.1.1.8 root 5218: if (regs.halted == CPU_HALT_ACCELERATOR_CPU_FALLBACK) {
5219: return 1;
5220: }
5221: unset_special(SPCFLAG_CHECK);
1.1.1.7 root 5222: if (haltloop())
5223: return 1;
5224: }
5225: if (m68k_reset_delay) {
5226: int vsynccnt = 60;
5227: int vsyncstate = -1;
5228: while (vsynccnt > 0 && !quit_program) {
5229: x_do_cycles(8 * CYCLE_UNIT);
5230: if (regs.spcflags & SPCFLAG_COPPER)
5231: do_copper();
5232: if (timeframes != vsyncstate) {
5233: vsyncstate = timeframes;
5234: vsynccnt--;
5235: }
5236: }
5237: }
5238: m68k_reset_delay = 0;
5239: unset_special(SPCFLAG_CHECK);
5240: }
5241: #endif
5242:
5243: #ifdef ACTION_REPLAY
5244: #ifdef ACTION_REPLAY_HRTMON
5245: if ((regs.spcflags & SPCFLAG_ACTION_REPLAY) && hrtmon_flag != ACTION_REPLAY_INACTIVE) {
5246: int isinhrt = (m68k_getpc () >= hrtmem_start && m68k_getpc () < hrtmem_start + hrtmem_size);
5247: /* exit from HRTMon? */
5248: if (hrtmon_flag == ACTION_REPLAY_ACTIVE && !isinhrt)
5249: hrtmon_hide ();
5250: /* HRTMon breakpoint? (not via IRQ7) */
5251: if (hrtmon_flag == ACTION_REPLAY_IDLE && isinhrt)
5252: hrtmon_breakenter ();
5253: if (hrtmon_flag == ACTION_REPLAY_ACTIVATE)
5254: hrtmon_enter ();
5255: }
5256: #endif
5257: if ((regs.spcflags & SPCFLAG_ACTION_REPLAY) && action_replay_flag != ACTION_REPLAY_INACTIVE) {
5258: /*if (action_replay_flag == ACTION_REPLAY_ACTIVE && !is_ar_pc_in_rom ())*/
5259: /* write_log (_T("PC:%p\n"), m68k_getpc ());*/
5260:
5261: if (action_replay_flag == ACTION_REPLAY_ACTIVATE || action_replay_flag == ACTION_REPLAY_DORESET)
5262: action_replay_enter ();
5263: if ((action_replay_flag == ACTION_REPLAY_HIDE || action_replay_flag == ACTION_REPLAY_ACTIVE) && !is_ar_pc_in_rom ()) {
5264: action_replay_hide ();
5265: unset_special (SPCFLAG_ACTION_REPLAY);
5266: }
5267: if (action_replay_flag == ACTION_REPLAY_WAIT_PC) {
5268: /*write_log (_T("Waiting for PC: %p, current PC= %p\n"), wait_for_pc, m68k_getpc ());*/
5269: if (m68k_getpc () == wait_for_pc) {
5270: action_replay_flag = ACTION_REPLAY_ACTIVATE; /* Activate after next instruction. */
5271: }
5272: }
5273: }
5274: #endif
5275:
5276: #ifndef WINUAE_FOR_HATARI
5277: if (regs.spcflags & SPCFLAG_COPPER)
5278: do_copper ();
5279: #endif
5280:
1.1.1.4 root 5281: #ifdef JIT
5282: unset_special (SPCFLAG_END_COMPILE); /* has done its job */
5283: #endif
5284:
1.1.1.7 root 5285: #ifndef WINUAE_FOR_HATARI
1.1.1.9 root 5286: while ((regs.spcflags & SPCFLAG_BLTNASTY) && dmaen (DMA_BLITTER) && cycles > 0 && ((currprefs.waiting_blits && currprefs.cpu_model >= 68020) || !currprefs.blitter_cycle_exact)) {
1.1.1.4 root 5287: int c = blitnasty ();
1.1.1.7 root 5288: if (c < 0) {
5289: break;
5290: } else if (c > 0) {
1.1.1.4 root 5291: cycles -= c * CYCLE_UNIT * 2;
5292: if (cycles < CYCLE_UNIT)
5293: cycles = 0;
1.1.1.7 root 5294: } else {
1.1.1.4 root 5295: c = 4;
1.1.1.7 root 5296: }
5297: x_do_cycles (c * CYCLE_UNIT);
1.1.1.4 root 5298: if (regs.spcflags & SPCFLAG_COPPER)
5299: do_copper ();
1.1.1.7 root 5300: #ifdef WITH_PPC
5301: if (ppc_state) {
5302: if (uae_ppc_poll_check_halt())
5303: return true;
5304: uae_ppc_execute_check();
5305: }
5306: #endif
1.1.1.4 root 5307: }
5308: #endif
5309:
1.1.1.7 root 5310: #ifdef WINUAE_FOR_HATARI
1.1.1.4 root 5311: if (regs.spcflags & SPCFLAG_BUSERROR) {
5312: /* We can not execute bus errors directly in the memory handler
5313: * functions since the PC should point to the address of the next
5314: * instruction, so we're executing the bus errors here: */
5315: unset_special(SPCFLAG_BUSERROR);
1.1.1.7 root 5316: Exception(2);
1.1.1.4 root 5317: }
1.1.1.7 root 5318: #endif
1.1.1.4 root 5319:
5320: if (regs.spcflags & SPCFLAG_DOTRACE)
1.1.1.7 root 5321: Exception (9);
1.1.1.4 root 5322:
1.1.1.7 root 5323: #ifndef WINUAE_FOR_HATARI
1.1.1.4 root 5324: if (regs.spcflags & SPCFLAG_TRAP) {
5325: unset_special (SPCFLAG_TRAP);
1.1.1.7 root 5326: Exception (3);
1.1.1.4 root 5327: }
1.1.1.7 root 5328: #endif
1.1.1.9 root 5329: if ((regs.spcflags & SPCFLAG_STOP) && regs.s == 0 && currprefs.cpu_model <= 68010) {
5330: // 68000/68010 undocumented special case:
5331: // if STOP clears S-bit and T was not set:
5332: // cause privilege violation exception, PC pointing to following instruction.
5333: // If T was set before STOP: STOP works as documented.
5334: m68k_unset_stop();
5335: Exception(8);
5336: }
5337:
1.1.1.7 root 5338: bool first = true;
5339: while ((regs.spcflags & SPCFLAG_STOP) && !(regs.spcflags & SPCFLAG_BRK)) {
1.1.1.8 root 5340: //fprintf ( stderr , "stop wait %d %ld %ld\n" , currcycle , CyclesGlobalClockCounter );
5341: isstopped:
1.1.1.9 root 5342: #ifndef WINUAE_FOR_HATARI
1.1.1.7 root 5343: check_uae_int_request();
5344: {
5345: if (bsd_int_requested)
5346: bsdsock_fake_int_handler ();
5347: }
5348: #endif
5349:
5350: if (cpu_tracer > 0) {
5351: cputrace.stopped = regs.stopped;
5352: cputrace.intmask = regs.intmask;
5353: cputrace.sr = regs.sr;
5354: cputrace.state = 1;
5355: cputrace.pc = m68k_getpc ();
5356: cputrace.memoryoffset = 0;
5357: cputrace.cyclecounter = cputrace.cyclecounter_pre = cputrace.cyclecounter_post = 0;
5358: cputrace.readcounter = cputrace.writecounter = 0;
5359: }
5360: if (!first)
5361: x_do_cycles (currprefs.cpu_cycle_exact ? 2 * CYCLE_UNIT : 4 * CYCLE_UNIT);
1.1.1.4 root 5362:
1.1.1.7 root 5363: #ifdef WINUAE_FOR_HATARI
5364: if (!first)
5365: {
1.1.1.8 root 5366: if (currprefs.cpu_cycle_exact && !currprefs.mmu_model)
5367: {
5368: /* Flush all CE cycles so far to update PendingInterruptCount */
5369: M68000_AddCycles_CE ( currcycle * 2 / CYCLE_UNIT );
5370: currcycle = 0;
5371: }
5372: else
1.1.1.7 root 5373: M68000_AddCycles(4);
5374: }
1.1.1.4 root 5375:
5376: /* It is possible one or more ints happen at the same time */
1.1.1.5 root 5377: /* We must process them during the same cpu cycle then choose the highest priority one */
5378: while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) )
1.1.1.7 root 5379: CALL_VAR(PendingInterruptFunction);
1.1.1.5 root 5380: if ( MFP_UpdateNeeded == true )
1.1.1.7 root 5381: MFP_UpdateIRQ ( 0 );
1.1.1.4 root 5382:
1.1.1.5 root 5383: /* Check is there's an interrupt to process (could be a delayed MFP interrupt) */
1.1.1.7 root 5384: if (regs.spcflags & SPCFLAG_MFP) {
5385: MFP_DelayIRQ (); /* Handle IRQ propagation */
5386: M68000_Update_intlev (); /* Refresh the list of pending interrupts */
1.1.1.5 root 5387: }
1.1.1.7 root 5388: #endif
5389: first = false;
5390: #ifndef WINUAE_FOR_HATARI
1.1.1.5 root 5391: if (regs.spcflags & SPCFLAG_COPPER)
5392: do_copper ();
1.1.1.4 root 5393: #endif
5394:
1.1.1.7 root 5395: if (m68k_interrupt_delay) {
1.1.1.5 root 5396: ipl_fetch ();
5397: if (time_for_interrupt ()) {
1.1.1.7 root 5398: do_interrupt (regs.ipl);
1.1.1.5 root 5399: }
5400: } else {
1.1.1.7 root 5401: if (regs.spcflags & (SPCFLAG_INT | SPCFLAG_DOINT)) {
5402: int intr = intlev ();
5403: unset_special (SPCFLAG_INT | SPCFLAG_DOINT);
5404: #ifdef WITH_PPC
5405: bool m68kint = true;
5406: if (ppc_state) {
5407: m68kint = ppc_interrupt(intr);
5408: }
5409: if (m68kint) {
1.1.1.4 root 5410: #endif
1.1.1.7 root 5411: if (intr > 0 && intr > regs.intmask)
5412: do_interrupt (intr);
5413: #ifdef WITH_PPC
5414: }
5415: #endif
5416: }
1.1.1.5 root 5417: }
1.1.1.7 root 5418:
5419: if (regs.spcflags & SPCFLAG_MODE_CHANGE) {
5420: m68k_resumestopped();
1.1.1.5 root 5421: return 1;
5422: }
1.1.1.4 root 5423:
1.1.1.7 root 5424: #ifdef WITH_PPC
5425: if (ppc_state) {
5426: uae_ppc_execute_check();
5427: uae_ppc_poll_check_halt();
1.1.1.4 root 5428: }
1.1.1.7 root 5429: #endif
5430:
1.1.1.4 root 5431: }
5432:
5433: if (regs.spcflags & SPCFLAG_TRACE)
5434: do_trace ();
5435:
1.1.1.8 root 5436: #ifndef WINUAE_FOR_HATARI
5437: if (regs.spcflags & SPCFLAG_UAEINT) {
5438: check_uae_int_request();
5439: unset_special(SPCFLAG_UAEINT);
5440: }
5441: #endif
5442:
1.1.1.7 root 5443: #ifdef WINUAE_FOR_HATARI
5444: if (regs.spcflags & SPCFLAG_MFP) {
5445: MFP_DelayIRQ (); /* Handle IRQ propagation */
5446: M68000_Update_intlev (); /* Refresh the list of pending interrupts */
5447: }
5448: #endif
5449:
1.1.1.8 root 5450: //fprintf ( stderr , "dospec1 %d %d spcflags=%x ipl=%x ipl_pin=%x intmask=%x\n" , m68k_interrupt_delay,time_for_interrupt() , regs.spcflags , regs.ipl , regs.ipl_pin, regs.intmask );
1.1.1.7 root 5451: if (m68k_interrupt_delay) {
1.1.1.4 root 5452: if (time_for_interrupt ()) {
1.1.1.7 root 5453: do_interrupt (regs.ipl);
1.1.1.4 root 5454: }
5455: } else {
5456: if (regs.spcflags & SPCFLAG_INT) {
5457: int intr = intlev ();
5458: unset_special (SPCFLAG_INT | SPCFLAG_DOINT);
5459: if (intr > 0 && (intr > regs.intmask || intr == 7))
1.1.1.7 root 5460: do_interrupt (intr);
1.1.1.4 root 5461: }
5462: }
5463:
1.1.1.8 root 5464: //fprintf ( stderr , "dospec2 %d %d spcflags=%x ipl=%x ipl_pin=%x intmask=%x\n" , m68k_interrupt_delay,time_for_interrupt() , regs.spcflags , regs.ipl , regs.ipl_pin, regs.intmask );
1.1.1.4 root 5465: if (regs.spcflags & SPCFLAG_DOINT) {
5466: unset_special (SPCFLAG_DOINT);
5467: set_special (SPCFLAG_INT);
5468: }
1.1.1.8 root 5469: //fprintf ( stderr , "dospec3 %d %d spcflags=%x ipl=%x ipl_pin=%x intmask=%x\n" , m68k_interrupt_delay,time_for_interrupt() , regs.spcflags , regs.ipl , regs.ipl_pin, regs.intmask );
1.1.1.4 root 5470:
1.1.1.7 root 5471: #ifdef WINUAE_FOR_HATARI
1.1.1.8 root 5472: if (regs.spcflags & SPCFLAG_DEBUGGER)
1.1.1.4 root 5473: DebugCpu_Check();
1.1.1.7 root 5474: #endif
1.1.1.4 root 5475:
1.1.1.10! root 5476: if ((regs.spcflags & SPCFLAG_BRK) || stopped_debug) {
1.1.1.7 root 5477: unset_special(SPCFLAG_BRK);
5478: #ifdef DEBUGGER
1.1.1.10! root 5479: if (stopped_debug && !regs.stopped) {
! 5480: if (debugging) {
! 5481: debugger_active = 1;
! 5482: stopped_debug = false;
! 5483: }
! 5484: }
1.1.1.7 root 5485: if (debugging) {
1.1.1.10! root 5486: if (!stopped_debug)
! 5487: debug();
! 5488: if (regs.stopped) {
! 5489: stopped_debug = true;
! 5490: if (debugging) {
! 5491: debugger_active = 0;
! 5492: }
1.1.1.7 root 5493: goto isstopped;
1.1.1.10! root 5494: }
1.1.1.7 root 5495: }
5496: #endif
5497: #ifdef WINUAE_FOR_HATARI
5498: return 1; /* Exit the upper run_xxx() function */
5499: #endif
1.1.1.4 root 5500: }
1.1.1.7 root 5501:
1.1.1.4 root 5502: return 0;
5503: }
5504:
5505: //static uae_u32 pcs[1000];
5506:
1.1.1.7 root 5507: #ifndef WINUAE_FOR_HATARI
1.1.1.4 root 5508: #if DEBUG_CD32CDTVIO
5509:
5510: static uae_u32 cd32nextpc, cd32request;
5511:
5512: static void out_cd32io2 (void)
5513: {
5514: uae_u32 request = cd32request;
1.1.1.7 root 5515: write_log (_T("%08x returned\n"), request);
5516: //write_log (_T("ACTUAL=%d ERROR=%d\n"), get_long (request + 32), get_byte (request + 31));
1.1.1.4 root 5517: cd32nextpc = 0;
5518: cd32request = 0;
5519: }
5520:
5521: static void out_cd32io (uae_u32 pc)
5522: {
5523: TCHAR out[100];
5524: int ioreq = 0;
5525: uae_u32 request = m68k_areg (regs, 1);
5526:
5527: if (pc == cd32nextpc) {
5528: out_cd32io2 ();
5529: return;
5530: }
5531: out[0] = 0;
5532: switch (pc)
5533: {
5534: case 0xe57cc0:
5535: case 0xf04c34:
1.1.1.7 root 5536: _stprintf (out, _T("opendevice"));
1.1.1.4 root 5537: break;
5538: case 0xe57ce6:
5539: case 0xf04c56:
1.1.1.7 root 5540: _stprintf (out, _T("closedevice"));
1.1.1.4 root 5541: break;
5542: case 0xe57e44:
5543: case 0xf04f2c:
1.1.1.7 root 5544: _stprintf (out, _T("beginio"));
1.1.1.4 root 5545: ioreq = 1;
5546: break;
5547: case 0xe57ef2:
5548: case 0xf0500e:
1.1.1.7 root 5549: _stprintf (out, _T("abortio"));
1.1.1.4 root 5550: ioreq = -1;
5551: break;
5552: }
5553: if (out[0] == 0)
5554: return;
5555: if (cd32request)
1.1.1.7 root 5556: write_log (_T("old request still not returned!\n"));
1.1.1.4 root 5557: cd32request = request;
5558: cd32nextpc = get_long (m68k_areg (regs, 7));
1.1.1.7 root 5559: write_log (_T("%s A1=%08X\n"), out, request);
1.1.1.4 root 5560: if (ioreq) {
5561: static int cnt = 0;
5562: int cmd = get_word (request + 28);
5563: #if 0
1.1.1.7 root 5564: if (cmd == 33) {
5565: uaecptr data = get_long (request + 40);
5566: write_log (_T("CD_CONFIG:\n"));
5567: for (int i = 0; i < 16; i++) {
5568: write_log (_T("%08X=%08X\n"), get_long (data), get_long (data + 4));
5569: data += 8;
5570: }
5571: }
5572: #endif
5573: #if 0
1.1.1.4 root 5574: if (cmd == 37) {
5575: cnt--;
5576: if (cnt <= 0)
5577: activate_debugger ();
5578: }
5579: #endif
1.1.1.7 root 5580: write_log (_T("CMD=%d DATA=%08X LEN=%d %OFF=%d PC=%x\n"),
5581: cmd, get_long (request + 40),
5582: get_long (request + 36), get_long (request + 44), M68K_GETPC);
1.1.1.4 root 5583: }
5584: if (ioreq < 0)
5585: ;//activate_debugger ();
5586: }
5587:
1.1.1.7 root 5588: #endif
5589: #endif
5590:
1.1.1.4 root 5591: #ifndef CPUEMU_11
5592:
5593: static void m68k_run_1 (void)
5594: {
5595: }
5596:
5597: #else
5598:
5599: /* It's really sad to have two almost identical functions for this, but we
5600: do it all for performance... :(
5601: This version emulates 68000's prefetch "cache" */
5602: static void m68k_run_1 (void)
5603: {
5604: struct regstruct *r = ®s;
1.1.1.7 root 5605: bool exit = false;
1.1.1.8 root 5606:
5607: Log_Printf(LOG_DEBUG, "m68k_run_1\n");
1.1.1.4 root 5608:
1.1.1.7 root 5609: while (!exit) {
5610: TRY (prb) {
5611: while (!exit) {
5612: r->opcode = r->ir;
5613:
5614: count_instr (r->opcode);
5615:
5616: #ifdef WINUAE_FOR_HATARI
1.1.1.10! root 5617: //m68k_dumpstate_file(stderr, NULL, 0xffffffff);
1.1.1.7 root 5618: if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM))
5619: {
5620: int FrameCycles, HblCounterVideo, LineCycles;
1.1.1.4 root 5621:
1.1.1.7 root 5622: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
1.1.1.4 root 5623:
1.1.1.7 root 5624: LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo );
1.1.1.10! root 5625: m68k_disasm_file(stderr, m68k_getpc (), NULL, m68k_getpc (), 1);
1.1.1.7 root 5626: }
5627: #endif
1.1.1.4 root 5628:
1.1.1.7 root 5629: #ifndef WINUAE_FOR_HATARI
1.1.1.4 root 5630: #if DEBUG_CD32CDTVIO
1.1.1.7 root 5631: out_cd32io (m68k_getpc ());
5632: #endif
1.1.1.4 root 5633: #endif
5634:
5635: #if 0
1.1.1.7 root 5636: int pc = m68k_getpc ();
5637: if (pc == 0xdff002)
5638: write_log (_T("hip\n"));
5639: if (pc != pcs[0] && (pc < 0xd00000 || pc > 0x1000000)) {
5640: memmove (pcs + 1, pcs, 998 * 4);
5641: pcs[0] = pc;
5642: //write_log (_T("%08X-%04X "), pc, r->opcode);
5643: }
1.1.1.4 root 5644: #endif
1.1.1.7 root 5645: do_cycles (cpu_cycles);
5646: r->instruction_pc = m68k_getpc ();
5647: cpu_cycles = (*cpufunctbl[r->opcode])(r->opcode);
5648: cpu_cycles = adjust_cycles (cpu_cycles);
5649:
5650: #ifdef WINUAE_FOR_HATARI
1.1.1.8 root 5651: /* Also add some extra cycles to simulate some wait state */
5652: /* TODO [NP] do this in all m68k_run_xx() */
5653: M68000_AddCyclesWithPairing(cpu_cycles * 2 / CYCLE_UNIT + WaitStateCycles);
5654: WaitStateCycles = 0;
1.1.1.5 root 5655:
1.1.1.7 root 5656: /* We can have several interrupts at the same time before the next CPU instruction */
5657: /* We must check for pending interrupt and call do_specialties_interrupt() only */
5658: /* if the cpu is not in the STOP state. Else, the int could be acknowledged now */
5659: /* and prevent exiting the STOP state when calling do_specialties() after. */
5660: /* For performance, we first test PendingInterruptCount, then regs.spcflags */
5661: while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) && ( ( regs.spcflags & SPCFLAG_STOP ) == 0 ) )
5662: CALL_VAR(PendingInterruptFunction); /* call the interrupt handler */
5663: if ( MFP_UpdateNeeded == true )
5664: MFP_UpdateIRQ ( 0 );
5665: #endif
1.1.1.4 root 5666:
1.1.1.7 root 5667: if (r->spcflags) {
5668: if (do_specialties (cpu_cycles))
5669: exit = true;
5670: }
5671: regs.ipl = regs.ipl_pin;
1.1.1.10! root 5672:
! 5673: #ifdef WINUAE_FOR_HATARI
! 5674: if ( savestate_state == STATE_SAVE )
! 5675: save_state ( NULL , NULL );
! 5676: #endif
! 5677:
1.1.1.7 root 5678: if (!currprefs.cpu_compatible || (currprefs.cpu_cycle_exact && currprefs.cpu_model <= 68010))
5679: exit = true;
5680: }
5681: } CATCH (prb) {
5682: bus_error();
5683: if (r->spcflags) {
5684: if (do_specialties(cpu_cycles))
5685: exit = true;
5686: }
5687: regs.ipl = regs.ipl_pin;
5688: } ENDTRY
5689: }
5690: }
1.1.1.4 root 5691:
5692: #endif /* CPUEMU_11 */
5693:
1.1.1.7 root 5694: #ifndef CPUEMU_13
1.1.1.4 root 5695:
5696: static void m68k_run_1_ce (void)
5697: {
5698: }
5699:
5700: #else
5701:
5702: /* cycle-exact m68k_run () */
5703:
5704: static void m68k_run_1_ce (void)
5705: {
5706: struct regstruct *r = ®s;
1.1.1.7 root 5707: bool first = true;
5708: bool exit = false;
1.1.1.8 root 5709:
5710: Log_Printf(LOG_DEBUG, "m68k_run_1_ce\n");
1.1.1.7 root 5711:
5712: while (!exit) {
5713: TRY (prb) {
5714: if (first) {
5715: if (cpu_tracer < 0) {
5716: memcpy (&r->regs, &cputrace.regs, 16 * sizeof (uae_u32));
5717: r->ir = cputrace.ir;
5718: r->irc = cputrace.irc;
5719: r->sr = cputrace.sr;
5720: r->usp = cputrace.usp;
5721: r->isp = cputrace.isp;
5722: r->intmask = cputrace.intmask;
5723: r->stopped = cputrace.stopped;
5724: m68k_setpc (cputrace.pc);
5725: if (!r->stopped) {
5726: if (cputrace.state > 1) {
5727: write_log (_T("CPU TRACE: EXCEPTION %d\n"), cputrace.state);
5728: Exception (cputrace.state);
5729: } else if (cputrace.state == 1) {
5730: write_log (_T("CPU TRACE: %04X\n"), cputrace.opcode);
5731: (*cpufunctbl[cputrace.opcode])(cputrace.opcode);
5732: }
5733: } else {
5734: write_log (_T("CPU TRACE: STOPPED\n"));
5735: }
5736: if (r->stopped)
5737: set_special (SPCFLAG_STOP);
5738: set_cpu_tracer (false);
5739: goto cont;
5740: }
5741: set_cpu_tracer (false);
5742: first = false;
5743: }
1.1.1.4 root 5744:
1.1.1.7 root 5745: while (!exit) {
5746: r->opcode = r->ir;
1.1.1.4 root 5747:
1.1.1.7 root 5748: #ifdef WINUAE_FOR_HATARI
1.1.1.10! root 5749: //m68k_dumpstate_file(stderr, NULL, 0xffffffff);
1.1.1.7 root 5750: if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM))
5751: {
5752: int FrameCycles, HblCounterVideo, LineCycles;
1.1.1.4 root 5753:
1.1.1.7 root 5754: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
1.1.1.4 root 5755:
1.1.1.8 root 5756: //fprintf ( stderr , "clock %ld\n" , CyclesGlobalClockCounter );
1.1.1.7 root 5757: LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo );
1.1.1.10! root 5758: m68k_disasm_file(stderr, m68k_getpc (), NULL, m68k_getpc (), 1);
1.1.1.7 root 5759: }
5760: #endif
5761:
5762: #ifndef WINUAE_FOR_HATARI
5763: #if DEBUG_CD32CDTVIO
5764: out_cd32io (m68k_getpc ());
5765: #endif
5766: #endif
5767: if (cpu_tracer) {
5768: memcpy (&cputrace.regs, &r->regs, 16 * sizeof (uae_u32));
5769: cputrace.opcode = r->opcode;
5770: cputrace.ir = r->ir;
5771: cputrace.irc = r->irc;
5772: cputrace.sr = r->sr;
5773: cputrace.usp = r->usp;
5774: cputrace.isp = r->isp;
5775: cputrace.intmask = r->intmask;
5776: cputrace.stopped = r->stopped;
5777: cputrace.state = 1;
5778: cputrace.pc = m68k_getpc ();
5779: cputrace.startcycles = get_cycles ();
5780: cputrace.memoryoffset = 0;
5781: cputrace.cyclecounter = cputrace.cyclecounter_pre = cputrace.cyclecounter_post = 0;
5782: cputrace.readcounter = cputrace.writecounter = 0;
5783: }
5784:
5785: #ifndef WINUAE_FOR_HATARI
5786: if (inputrecord_debug & 4) {
5787: if (input_record > 0)
5788: inprec_recorddebug_cpu (1);
5789: else if (input_play > 0)
5790: inprec_playdebug_cpu (1);
5791: }
5792: #endif
5793:
5794: #ifdef WINUAE_FOR_HATARI
5795: currcycle = 0;
5796: #endif
5797:
5798: r->instruction_pc = m68k_getpc ();
5799: (*cpufunctbl[r->opcode])(r->opcode);
5800: wait_memory_cycles(); // TODO NP : ici, ou plus bas ?
5801: #ifdef WINUAE_FOR_HATARI
5802: //fprintf ( stderr, "cyc_1ce %d\n" , currcycle );
1.1.1.8 root 5803: /* Flush all CE cycles so far to update PendingInterruptCount */
5804: M68000_AddCycles_CE ( currcycle * 2 / CYCLE_UNIT );
5805: currcycle = 0;
1.1.1.7 root 5806:
5807: while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) && ( ( regs.spcflags & SPCFLAG_STOP ) == 0 ) )
5808: CALL_VAR(PendingInterruptFunction); /* call the interrupt handler */
5809: if ( MFP_UpdateNeeded == true )
5810: MFP_UpdateIRQ ( 0 );
5811: #endif
5812:
5813: if (cpu_tracer) {
5814: cputrace.state = 0;
5815: }
5816: cont:
5817: if (cputrace.needendcycles) {
5818: cputrace.needendcycles = 0;
5819: write_log (_T("STARTCYCLES=%08x ENDCYCLES=%08lx\n"), cputrace.startcycles, get_cycles ());
5820: #ifndef WINUAE_FOR_HATARI
5821: log_dma_record ();
5822: #endif
5823: }
5824:
5825: if (r->spcflags || time_for_interrupt ()) {
5826: if (do_specialties (0))
5827: exit = true;
5828: }
5829:
1.1.1.10! root 5830: #ifdef WINUAE_FOR_HATARI
! 5831: if ( savestate_state == STATE_SAVE )
! 5832: save_state ( NULL , NULL );
! 5833: #endif
! 5834:
1.1.1.7 root 5835: if (!currprefs.cpu_cycle_exact || currprefs.cpu_model > 68010)
5836: exit = true;
5837: }
5838: } CATCH (prb) {
5839: bus_error();
5840: if (r->spcflags || time_for_interrupt()) {
5841: if (do_specialties(0))
5842: exit = true;
5843: }
5844: } ENDTRY
5845: }
5846: }
5847:
5848: #endif
5849:
1.1.1.8 root 5850: #if defined(CPUEMU_20) && defined(JIT)
1.1.1.7 root 5851: // emulate simple prefetch
5852: static uae_u16 get_word_020_prefetchf (uae_u32 pc)
5853: {
5854: if (pc == regs.prefetch020addr) {
5855: uae_u16 v = regs.prefetch020[0];
5856: regs.prefetch020[0] = regs.prefetch020[1];
5857: regs.prefetch020[1] = regs.prefetch020[2];
5858: regs.prefetch020[2] = x_get_word (pc + 6);
5859: regs.prefetch020addr += 2;
5860: return v;
5861: } else if (pc == regs.prefetch020addr + 2) {
5862: uae_u16 v = regs.prefetch020[1];
5863: regs.prefetch020[0] = regs.prefetch020[2];
5864: regs.prefetch020[1] = x_get_word (pc + 4);
5865: regs.prefetch020[2] = x_get_word (pc + 6);
5866: regs.prefetch020addr = pc + 2;
5867: return v;
5868: } else if (pc == regs.prefetch020addr + 4) {
5869: uae_u16 v = regs.prefetch020[2];
5870: regs.prefetch020[0] = x_get_word (pc + 2);
5871: regs.prefetch020[1] = x_get_word (pc + 4);
5872: regs.prefetch020[2] = x_get_word (pc + 6);
5873: regs.prefetch020addr = pc + 2;
5874: return v;
5875: } else {
5876: regs.prefetch020addr = pc + 2;
5877: regs.prefetch020[0] = x_get_word (pc + 2);
5878: regs.prefetch020[1] = x_get_word (pc + 4);
5879: regs.prefetch020[2] = x_get_word (pc + 6);
5880: return x_get_word (pc);
1.1.1.4 root 5881: }
5882: }
5883: #endif
5884:
1.1.1.8 root 5885: #ifdef WITH_THREADED_CPU
5886: static volatile int cpu_thread_active;
1.1.1.10! root 5887: static uae_sem_t cpu_in_sema, cpu_out_sema, cpu_wakeup_sema;
! 5888:
! 5889: static volatile int cpu_thread_ilvl;
! 5890: static volatile uae_u32 cpu_thread_indirect_mode;
! 5891: static volatile uae_u32 cpu_thread_indirect_addr;
! 5892: static volatile uae_u32 cpu_thread_indirect_val;
! 5893: static volatile uae_u32 cpu_thread_indirect_size;
! 5894: static volatile uae_u32 cpu_thread_reset;
! 5895: static uae_thread_id cpu_thread_tid;
1.1.1.8 root 5896:
5897: static bool m68k_cs_initialized;
5898:
5899: static int do_specialties_thread(void)
5900: {
5901: if (regs.spcflags & SPCFLAG_MODE_CHANGE)
5902: return 1;
5903:
5904: #ifdef JIT
5905: unset_special(SPCFLAG_END_COMPILE); /* has done its job */
5906: #endif
5907:
5908: if (regs.spcflags & SPCFLAG_DOTRACE)
5909: Exception(9);
5910:
5911: if (regs.spcflags & SPCFLAG_TRAP) {
5912: unset_special(SPCFLAG_TRAP);
5913: Exception(3);
5914: }
5915:
5916: if (regs.spcflags & SPCFLAG_TRACE)
5917: do_trace();
5918:
1.1.1.10! root 5919: for (;;) {
1.1.1.8 root 5920:
1.1.1.10! root 5921: if (regs.spcflags & (SPCFLAG_BRK | SPCFLAG_MODE_CHANGE)) {
! 5922: return 1;
! 5923: }
1.1.1.8 root 5924:
1.1.1.10! root 5925: int ilvl = cpu_thread_ilvl;
! 5926: if (ilvl > 0 && (ilvl > regs.intmask || ilvl == 7)) {
! 5927: do_interrupt(ilvl);
! 5928: }
! 5929:
! 5930: if (!(regs.spcflags & SPCFLAG_STOP))
! 5931: break;
! 5932:
! 5933: uae_sem_wait(&cpu_wakeup_sema);
1.1.1.8 root 5934: }
5935:
5936: return 0;
5937: }
5938:
1.1.1.10! root 5939: static void init_cpu_thread(void)
1.1.1.8 root 5940: {
5941: if (!currprefs.cpu_thread)
5942: return;
1.1.1.10! root 5943: if (m68k_cs_initialized)
1.1.1.8 root 5944: return;
1.1.1.10! root 5945: uae_sem_init(&cpu_in_sema, 0, 0);
! 5946: uae_sem_init(&cpu_out_sema, 0, 0);
! 5947: uae_sem_init(&cpu_wakeup_sema, 0, 0);
! 5948: m68k_cs_initialized = true;
1.1.1.8 root 5949: }
1.1.1.10! root 5950:
! 5951: extern addrbank *thread_mem_banks[MEMORY_BANKS];
! 5952:
! 5953: uae_u32 process_cpu_indirect_memory_read(uae_u32 addr, int size)
1.1.1.8 root 5954: {
1.1.1.10! root 5955: // Do direct access if call is from filesystem etc thread
! 5956: if (cpu_thread_tid != uae_thread_get_id()) {
! 5957: uae_u32 data = 0;
! 5958: addrbank *ab = thread_mem_banks[bankindex(addr)];
! 5959: switch (size)
! 5960: {
! 5961: case 0:
! 5962: data = ab->bget(addr) & 0xff;
! 5963: break;
! 5964: case 1:
! 5965: data = ab->wget(addr) & 0xffff;
! 5966: break;
! 5967: case 2:
! 5968: data = ab->lget(addr);
! 5969: break;
! 5970: }
! 5971: return data;
1.1.1.8 root 5972: }
1.1.1.10! root 5973:
! 5974: cpu_thread_indirect_mode = 2;
! 5975: cpu_thread_indirect_addr = addr;
! 5976: cpu_thread_indirect_size = size;
! 5977: uae_sem_post(&cpu_out_sema);
! 5978: uae_sem_wait(&cpu_in_sema);
! 5979: cpu_thread_indirect_mode = 0xfe;
! 5980: return cpu_thread_indirect_val;
1.1.1.8 root 5981: }
5982:
1.1.1.10! root 5983: void process_cpu_indirect_memory_write(uae_u32 addr, uae_u32 data, int size)
1.1.1.8 root 5984: {
1.1.1.10! root 5985: if (cpu_thread_tid != uae_thread_get_id()) {
! 5986: addrbank *ab = thread_mem_banks[bankindex(addr)];
! 5987: switch (size)
! 5988: {
! 5989: case 0:
! 5990: ab->bput(addr, data & 0xff);
! 5991: break;
! 5992: case 1:
! 5993: ab->wput(addr, data & 0xffff);
! 5994: break;
! 5995: case 2:
! 5996: ab->lput(addr, data);
! 5997: break;
! 5998: }
1.1.1.8 root 5999: return;
6000: }
1.1.1.10! root 6001: cpu_thread_indirect_mode = 1;
! 6002: cpu_thread_indirect_addr = addr;
! 6003: cpu_thread_indirect_size = size;
! 6004: cpu_thread_indirect_val = data;
! 6005: uae_sem_post(&cpu_out_sema);
! 6006: uae_sem_wait(&cpu_in_sema);
! 6007: cpu_thread_indirect_mode = 0xff;
1.1.1.8 root 6008: }
6009:
6010: static void run_cpu_thread(void *(*f)(void *))
6011: {
1.1.1.10! root 6012: int framecnt = -1;
! 6013: int vp = 0;
! 6014: int intlev_prev = 0;
! 6015:
1.1.1.8 root 6016: cpu_thread_active = 0;
1.1.1.10! root 6017: uae_sem_init(&cpu_in_sema, 0, 0);
! 6018: uae_sem_init(&cpu_out_sema, 0, 0);
! 6019: uae_sem_init(&cpu_wakeup_sema, 0, 0);
! 6020:
! 6021: if (!uae_start_thread(_T("cpu"), f, NULL, NULL))
! 6022: return;
! 6023: while (!cpu_thread_active) {
! 6024: sleep_millis(1);
! 6025: }
! 6026:
! 6027: while (!(regs.spcflags & SPCFLAG_MODE_CHANGE)) {
! 6028: int maxperloop = 10;
! 6029:
! 6030: while (!uae_sem_trywait(&cpu_out_sema)) {
! 6031: uae_u32 cmd, addr, data, size, mode;
! 6032:
! 6033: addr = cpu_thread_indirect_addr;
! 6034: data = cpu_thread_indirect_val;
! 6035: size = cpu_thread_indirect_size;
! 6036: mode = cpu_thread_indirect_mode;
! 6037:
! 6038: switch(mode)
! 6039: {
! 6040: case 1:
! 6041: {
! 6042: addrbank *ab = thread_mem_banks[bankindex(addr)];
! 6043: switch (size)
! 6044: {
! 6045: case 0:
! 6046: ab->bput(addr, data & 0xff);
! 6047: break;
! 6048: case 1:
! 6049: ab->wput(addr, data & 0xffff);
! 6050: break;
! 6051: case 2:
! 6052: ab->lput(addr, data);
! 6053: break;
1.1.1.8 root 6054: }
1.1.1.10! root 6055: uae_sem_post(&cpu_in_sema);
! 6056: break;
1.1.1.8 root 6057: }
1.1.1.10! root 6058: case 2:
! 6059: {
! 6060: addrbank *ab = thread_mem_banks[bankindex(addr)];
! 6061: switch (size)
! 6062: {
! 6063: case 0:
! 6064: data = ab->bget(addr) & 0xff;
! 6065: break;
! 6066: case 1:
! 6067: data = ab->wget(addr) & 0xffff;
! 6068: break;
! 6069: case 2:
! 6070: data = ab->lget(addr);
! 6071: break;
1.1.1.8 root 6072: }
1.1.1.10! root 6073: cpu_thread_indirect_val = data;
! 6074: uae_sem_post(&cpu_in_sema);
! 6075: break;
1.1.1.8 root 6076: }
1.1.1.10! root 6077: default:
! 6078: write_log(_T("cpu_thread_indirect_mode=%08x!\n"), mode);
! 6079: break;
1.1.1.8 root 6080: }
6081:
1.1.1.10! root 6082: if (maxperloop-- < 0)
! 6083: break;
! 6084: }
! 6085:
! 6086: if (framecnt != timeframes) {
! 6087: framecnt = timeframes;
! 6088: }
! 6089:
! 6090: if (cpu_thread_reset) {
! 6091: bool hardreset = cpu_thread_reset & 2;
! 6092: bool keyboardreset = cpu_thread_reset & 4;
! 6093: custom_reset(hardreset, keyboardreset);
! 6094: cpu_thread_reset = 0;
! 6095: uae_sem_post(&cpu_in_sema);
! 6096: }
! 6097:
! 6098: if (regs.spcflags & SPCFLAG_BRK) {
1.1.1.8 root 6099: unset_special(SPCFLAG_BRK);
6100: #ifdef DEBUGGER
6101: if (debugging) {
6102: debug();
6103: }
6104: #endif
6105: }
1.1.1.10! root 6106:
! 6107: if (vp == vpos) {
! 6108:
! 6109: do_cycles((maxhpos / 2) * CYCLE_UNIT);
! 6110:
! 6111: if (regs.spcflags & SPCFLAG_COPPER) {
! 6112: do_copper();
! 6113: }
! 6114:
! 6115: check_uae_int_request();
! 6116: if (regs.spcflags & (SPCFLAG_INT | SPCFLAG_DOINT)) {
! 6117: int intr = intlev();
! 6118: unset_special(SPCFLAG_INT | SPCFLAG_DOINT);
! 6119: if (intr > 0) {
! 6120: cpu_thread_ilvl = intr;
! 6121: cycles_do_special();
! 6122: uae_sem_post(&cpu_wakeup_sema);
! 6123: } else {
! 6124: cpu_thread_ilvl = 0;
! 6125: }
! 6126: }
! 6127: continue;
! 6128: }
! 6129:
! 6130: frame_time_t next = vsyncmintimepre + (vsynctimebase * vpos / (maxvpos + 1));
! 6131: frame_time_t c = read_processor_time();
! 6132: if ((int)next - (int)c > 0 && (int)next - (int)c < vsyncmaxtime * 2)
! 6133: continue;
! 6134:
! 6135: vp = vpos;
! 6136:
! 6137: }
! 6138:
! 6139: while (cpu_thread_active) {
! 6140: uae_sem_post(&cpu_in_sema);
! 6141: uae_sem_post(&cpu_wakeup_sema);
! 6142: sleep_millis(1);
1.1.1.8 root 6143: }
1.1.1.10! root 6144:
! 6145: }
! 6146:
! 6147: #endif
! 6148:
! 6149: #ifndef WINUAE_FOR_HATARI
! 6150: void custom_reset_cpu(bool hardreset, bool keyboardreset)
! 6151: {
! 6152: #ifdef WITH_THREADED_CPU
! 6153: if (cpu_thread_tid != uae_thread_get_id()) {
! 6154: custom_reset(hardreset, keyboardreset);
! 6155: return;
! 6156: }
! 6157: cpu_thread_reset = 1 | (hardreset ? 2 : 0) | (keyboardreset ? 4 : 0);
! 6158: uae_sem_post(&cpu_wakeup_sema);
! 6159: uae_sem_wait(&cpu_in_sema);
! 6160: #else
! 6161: custom_reset(hardreset, keyboardreset);
! 6162: #endif
1.1.1.8 root 6163: }
6164: #endif
6165:
1.1.1.4 root 6166: #ifdef JIT /* Completely different run_2 replacement */
6167:
6168: void do_nothing (void)
6169: {
1.1.1.8 root 6170: if (!currprefs.cpu_thread) {
6171: /* What did you expect this to do? */
6172: do_cycles (0);
6173: /* I bet you didn't expect *that* ;-) */
6174: }
1.1.1.4 root 6175: }
6176:
6177: void exec_nostats (void)
6178: {
6179: struct regstruct *r = ®s;
6180:
6181: for (;;)
6182: {
1.1.1.7 root 6183: if (currprefs.cpu_compatible) {
6184: r->opcode = get_word_020_prefetchf(m68k_getpc());
6185: } else {
6186: r->opcode = x_get_iword(0);
6187: }
6188: cpu_cycles = (*cpufunctbl[r->opcode])(r->opcode);
6189: cpu_cycles = adjust_cycles (cpu_cycles);
1.1.1.8 root 6190:
6191: if (!currprefs.cpu_thread) {
6192: do_cycles (cpu_cycles);
1.1.1.4 root 6193:
1.1.1.7 root 6194: #ifdef WITH_PPC
1.1.1.8 root 6195: if (ppc_state)
6196: ppc_interrupt(intlev());
1.1.1.7 root 6197: #endif
1.1.1.8 root 6198: }
1.1.1.7 root 6199: #ifdef WINUAE_FOR_HATARI
6200: if (end_block(r->opcode) || r->spcflags)
6201: #else
6202:
1.1.1.8 root 6203: if (end_block(r->opcode) || r->spcflags || uae_int_requested)
1.1.1.7 root 6204: #endif
1.1.1.4 root 6205: return; /* We will deal with the spcflags in the caller */
6206: }
6207: }
6208:
6209: void execute_normal (void)
6210: {
6211: struct regstruct *r = ®s;
6212: int blocklen;
6213: cpu_history pc_hist[MAXRUN];
6214: int total_cycles;
6215:
6216: if (check_for_cache_miss ())
6217: return;
6218:
6219: total_cycles = 0;
6220: blocklen = 0;
6221: start_pc_p = r->pc_oldp;
6222: start_pc = r->pc;
6223: for (;;) {
6224: /* Take note: This is the do-it-normal loop */
1.1.1.7 root 6225: regs.instruction_pc = m68k_getpc ();
6226: if (currprefs.cpu_compatible) {
6227: r->opcode = get_word_020_prefetchf (regs.instruction_pc);
6228: } else {
6229: r->opcode = x_get_iword(0);
6230: }
1.1.1.4 root 6231:
6232: special_mem = DISTRUST_CONSISTENT_MEM;
6233: pc_hist[blocklen].location = (uae_u16*)r->pc_p;
6234:
1.1.1.7 root 6235: cpu_cycles = (*cpufunctbl[r->opcode])(r->opcode);
1.1.1.8 root 6236: cpu_cycles = adjust_cycles(cpu_cycles);
6237: if (!currprefs.cpu_thread) {
6238: do_cycles (cpu_cycles);
6239: }
1.1.1.4 root 6240: total_cycles += cpu_cycles;
6241: pc_hist[blocklen].specmem = special_mem;
6242: blocklen++;
1.1.1.7 root 6243: #ifdef WINUAE_FOR_HATARI
6244: if (end_block (r->opcode) || blocklen >= MAXRUN || r->spcflags) {
6245: #else
1.1.1.8 root 6246: if (end_block (r->opcode) || blocklen >= MAXRUN || r->spcflags || uae_int_requested) {
1.1.1.7 root 6247: #endif
1.1.1.4 root 6248: compile_block (pc_hist, blocklen, total_cycles);
6249: return; /* We will deal with the spcflags in the caller */
6250: }
6251: /* No need to check regs.spcflags, because if they were set,
6252: we'd have ended up inside that "if" */
1.1.1.7 root 6253:
6254: #ifdef WITH_PPC
6255: if (ppc_state)
6256: ppc_interrupt(intlev());
6257: #endif
1.1.1.4 root 6258: }
6259: }
6260:
6261: typedef void compiled_handler (void);
6262:
1.1.1.8 root 6263: #ifdef WITH_THREADED_CPU
6264: static void *cpu_thread_run_jit(void *v)
1.1.1.4 root 6265: {
1.1.1.10! root 6266: cpu_thread_tid = uae_thread_get_id();
1.1.1.8 root 6267: cpu_thread_active = 1;
1.1.1.10! root 6268: #ifdef USE_STRUCTURED_EXCEPTION_HANDLING
! 6269: __try
! 6270: #endif
! 6271: {
! 6272: for (;;) {
! 6273: ((compiled_handler*)(pushall_call_handler))();
! 6274: /* Whenever we return from that, we should check spcflags */
! 6275: if (regs.spcflags || cpu_thread_ilvl > 0) {
! 6276: if (do_specialties_thread()) {
! 6277: break;
! 6278: }
1.1.1.8 root 6279: }
6280: }
6281: }
1.1.1.10! root 6282: #ifdef USE_STRUCTURED_EXCEPTION_HANDLING
! 6283: #ifdef JIT
! 6284: __except (EvalException(GetExceptionInformation()))
! 6285: #else
! 6286: __except (DummyException(GetExceptionInformation(), GetExceptionCode()))
! 6287: #endif
! 6288: {
! 6289: // EvalException does the good stuff...
! 6290: }
! 6291: #endif
1.1.1.8 root 6292: cpu_thread_active = 0;
6293: return 0;
6294: }
6295: #endif
6296:
6297: static void m68k_run_jit(void)
6298: {
6299: Log_Printf(LOG_DEBUG, "m68k_run_jit\n");
6300: #ifdef WITH_THREADED_CPU
6301: if (currprefs.cpu_thread) {
6302: run_cpu_thread(cpu_thread_run_jit);
6303: return;
6304: }
6305: #endif
6306:
1.1.1.4 root 6307: for (;;) {
1.1.1.10! root 6308: #ifdef USE_STRUCTURED_EXCEPTION_HANDLING
! 6309: __try {
! 6310: #endif
! 6311: for (;;) {
1.1.1.7 root 6312: #ifdef WINUAE_FOR_HATARI
1.1.1.10! root 6313: //m68k_dumpstate_file(stderr, NULL, 0xffffffff);
! 6314: if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM))
! 6315: {
! 6316: int FrameCycles, HblCounterVideo, LineCycles;
! 6317: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
! 6318: LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo );
! 6319: m68k_disasm_file(stderr, m68k_getpc (), NULL, m68k_getpc (), 1);
! 6320: }
1.1.1.7 root 6321: #endif
1.1.1.4 root 6322:
1.1.1.10! root 6323: ((compiled_handler*)(pushall_call_handler))();
! 6324: /* Whenever we return from that, we should check spcflags */
! 6325: check_uae_int_request();
! 6326: if (regs.spcflags) {
! 6327: if (do_specialties(0)) {
! 6328: return;
! 6329: }
! 6330: }
1.1.1.4 root 6331: }
1.1.1.10! root 6332:
! 6333: #ifdef USE_STRUCTURED_EXCEPTION_HANDLING
! 6334: } __except (EvalException(GetExceptionInformation())) {
! 6335: // Something very bad happened, generate fake bus error exception
! 6336: // Either emulation continues normally or crashes.
! 6337: // Without this it would have crashed in any case..
! 6338: uaecptr pc = M68K_GETPC;
! 6339: write_log(_T("Unhandled JIT exception! PC=%08x\n"), pc);
! 6340: if (pc & 1)
! 6341: Exception(3);
! 6342: else
! 6343: Exception(2);
1.1.1.4 root 6344: }
1.1.1.10! root 6345: #endif
1.1.1.4 root 6346: }
1.1.1.10! root 6347:
1.1.1.4 root 6348: }
6349: #endif /* JIT */
6350:
6351: #ifndef CPUEMU_0
6352:
6353: static void m68k_run_2 (void)
6354: {
6355: }
6356:
6357: #else
6358:
1.1.1.7 root 6359: static void opcodedebug (uae_u32 pc, uae_u16 opcode, bool full)
1.1.1.4 root 6360: {
6361: struct mnemolookup *lookup;
6362: struct instr *dp;
6363: uae_u32 addr;
6364: int fault;
6365:
6366: if (cpufunctbl[opcode] == op_illg_1)
6367: opcode = 0x4AFC;
6368: dp = table68k + opcode;
6369: for (lookup = lookuptab;lookup->mnemo != dp->mnemo; lookup++)
6370: ;
6371: fault = 0;
6372: TRY(prb) {
1.1.1.9 root 6373: addr = mmu_translate (pc, 0, (regs.mmu_ssw & 4) ? 1 : 0, 0, 0, sz_word);
1.1.1.4 root 6374: } CATCH (prb) {
6375: fault = 1;
6376: } ENDTRY
6377: if (!fault) {
1.1.1.7 root 6378: TCHAR buf[100];
6379: if (full)
6380: write_log (_T("mmufixup=%d %04x %04x\n"), mmufixup[0].reg, regs.wb3_status, regs.mmu_ssw);
1.1.1.10! root 6381: m68k_disasm_2 (buf, sizeof buf / sizeof (TCHAR), addr, NULL, 1, NULL, NULL, 0xffffffff, 0);
1.1.1.7 root 6382: write_log (_T("%s\n"), buf);
6383: if (full)
1.1.1.10! root 6384: m68k_dumpstate(NULL, 0xffffffff);
1.1.1.7 root 6385: }
6386: }
6387:
1.1.1.9 root 6388: static void check_halt(void)
6389: {
6390: if (regs.halted)
6391: do_specialties (0);
6392: }
6393:
1.1.1.7 root 6394: void cpu_halt (int id)
6395: {
6396: #ifndef WINUAE_FOR_HATARI
6397: // id < 0: m68k halted, PPC active.
6398: // id > 0: emulation halted.
6399: if (!regs.halted) {
6400: write_log (_T("CPU halted: reason = %d PC=%08x\n"), id, M68K_GETPC);
6401: regs.halted = id;
6402: gui_data.cpu_halted = id;
6403: gui_led(LED_CPU, 0, -1);
6404: if (id >= 0) {
6405: regs.intmask = 7;
6406: MakeSR ();
6407: audio_deactivate ();
6408: }
6409: }
1.1.1.9 root 6410: set_special(SPCFLAG_CHECK);
1.1.1.7 root 6411: #else
6412: Dialog_HaltDlg();
6413: #endif
6414: }
6415:
6416: #ifdef CPUEMU_33
6417: /* [NP] TODO : use 68060 in Hatari ? with DSP ? */
6418: /* MMU 68060 */
6419: static void m68k_run_mmu060 (void)
6420: {
6421: struct flag_struct f;
6422: int halt = 0;
1.1.1.8 root 6423:
1.1.1.9 root 6424: check_halt();
1.1.1.8 root 6425: #ifdef WINUAE_FOR_HATARI
6426: Log_Printf(LOG_DEBUG, "m68k_run_mmu060\n");
6427: #endif
1.1.1.7 root 6428:
6429: while (!halt) {
6430: TRY (prb) {
6431: for (;;) {
1.1.1.8 root 6432: #ifdef WINUAE_FOR_HATARI
1.1.1.10! root 6433: //m68k_dumpstate_file(stderr, NULL, 0xffffffff);
1.1.1.8 root 6434: if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM))
6435: {
6436: int FrameCycles, HblCounterVideo, LineCycles;
6437: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
6438: LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo );
1.1.1.10! root 6439: m68k_disasm_file(stderr, m68k_getpc (), NULL, m68k_getpc (), 1);
1.1.1.8 root 6440: }
6441: #endif
1.1.1.7 root 6442: f.cznv = regflags.cznv;
6443: f.x = regflags.x;
6444: regs.instruction_pc = m68k_getpc ();
6445:
6446: do_cycles (cpu_cycles);
6447:
6448: mmu_opcode = -1;
6449: mmu060_state = 0;
6450: mmu_opcode = regs.opcode = x_prefetch (0);
6451: mmu060_state = 1;
6452:
6453: count_instr (regs.opcode);
6454: cpu_cycles = (*cpufunctbl[regs.opcode])(regs.opcode);
6455:
6456: cpu_cycles = adjust_cycles (cpu_cycles);
1.1.1.8 root 6457: #ifdef WINUAE_FOR_HATARI
6458: M68000_AddCycles(cpu_cycles * 2 / CYCLE_UNIT);
1.1.1.7 root 6459:
1.1.1.8 root 6460: if ( WaitStateCycles ) {
6461: /* Add some extra cycles to simulate a wait state */
6462: M68000_AddCycles(WaitStateCycles);
6463: WaitStateCycles = 0;
6464: }
6465:
6466: while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) && ( ( regs.spcflags & SPCFLAG_STOP ) == 0 ) )
6467: CALL_VAR(PendingInterruptFunction); /* call the interrupt handler */
6468: if ( MFP_UpdateNeeded == true )
6469: MFP_UpdateIRQ ( 0 );
6470: #endif
1.1.1.7 root 6471: if (regs.spcflags) {
6472: if (do_specialties (cpu_cycles))
6473: return;
6474: }
1.1.1.8 root 6475: #ifdef WINUAE_FOR_HATARI
6476: /* Run DSP 56k code if necessary */
6477: if (bDspEnabled) {
6478: DSP_Run(2 * cpu_cycles * 2 / CYCLE_UNIT);
6479: // DSP_Run ( DSP_CPU_FREQ_RATIO * ( CyclesGlobalClockCounter - DSP_CyclesGlobalClockCounter ) );
6480: }
1.1.1.10! root 6481:
! 6482: if ( savestate_state == STATE_SAVE )
! 6483: save_state ( NULL , NULL );
1.1.1.8 root 6484: #endif
1.1.1.7 root 6485: }
6486: } CATCH (prb) {
6487:
6488: m68k_setpci (regs.instruction_pc);
6489: regflags.cznv = f.cznv;
6490: regflags.x = f.x;
6491:
6492: if (mmufixup[0].reg >= 0) {
6493: m68k_areg (regs, mmufixup[0].reg) = mmufixup[0].value;
6494: mmufixup[0].reg = -1;
6495: }
6496: if (mmufixup[1].reg >= 0) {
6497: m68k_areg (regs, mmufixup[1].reg) = mmufixup[1].value;
6498: mmufixup[1].reg = -1;
6499: }
6500:
6501: TRY (prb2) {
6502: Exception (prb);
6503: } CATCH (prb2) {
6504: halt = 1;
6505: } ENDTRY
6506: } ENDTRY
1.1.1.4 root 6507: }
1.1.1.7 root 6508: cpu_halt(halt);
1.1.1.4 root 6509: }
1.1.1.7 root 6510:
1.1.1.4 root 6511: #endif
6512:
1.1.1.7 root 6513: #ifdef CPUEMU_31
1.1.1.4 root 6514:
6515: /* Aranym MMU 68040 */
6516: static void m68k_run_mmu040 (void)
6517: {
1.1.1.7 root 6518: struct flag_struct f;
6519: int halt = 0;
1.1.1.8 root 6520:
1.1.1.9 root 6521: check_halt();
1.1.1.8 root 6522: #ifdef WINUAE_FOR_HATARI
6523: Log_Printf(LOG_DEBUG, "m68k_run_mmu040\n");
6524: #endif
1.1.1.7 root 6525:
6526: while (!halt) {
6527: TRY (prb) {
6528: for (;;) {
6529: #ifdef WINUAE_FOR_HATARI
1.1.1.10! root 6530: //m68k_dumpstate_file(stderr, NULL, 0xffffffff);
1.1.1.7 root 6531: if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM))
6532: {
6533: int FrameCycles, HblCounterVideo, LineCycles;
6534: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
6535: LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo );
1.1.1.10! root 6536: m68k_disasm_file(stderr, m68k_getpc (), NULL, m68k_getpc (), 1);
1.1.1.7 root 6537: }
6538: #endif
6539: f.cznv = regflags.cznv;
6540: f.x = regflags.x;
6541: mmu_restart = true;
6542: regs.instruction_pc = m68k_getpc ();
6543:
6544: do_cycles (cpu_cycles);
6545:
6546: mmu_opcode = -1;
6547: mmu_opcode = regs.opcode = x_prefetch (0);
6548: count_instr (regs.opcode);
6549: cpu_cycles = (*cpufunctbl[regs.opcode])(regs.opcode);
6550: cpu_cycles = adjust_cycles (cpu_cycles);
6551:
6552: #ifdef WINUAE_FOR_HATARI
6553: M68000_AddCycles(cpu_cycles * 2 / CYCLE_UNIT);
6554:
1.1.1.8 root 6555: if ( WaitStateCycles ) {
1.1.1.7 root 6556: /* Add some extra cycles to simulate a wait state */
1.1.1.8 root 6557: M68000_AddCycles(WaitStateCycles);
6558: WaitStateCycles = 0;
1.1.1.7 root 6559: }
1.1.1.4 root 6560:
1.1.1.7 root 6561: /* We can have several interrupts at the same time before the next CPU instruction */
6562: /* We must check for pending interrupt and call do_specialties_interrupt() only */
6563: /* if the cpu is not in the STOP state. Else, the int could be acknowledged now */
6564: /* and prevent exiting the STOP state when calling do_specialties() after. */
6565: /* For performance, we first test PendingInterruptCount, then regs.spcflags */
6566: while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) && ( ( regs.spcflags & SPCFLAG_STOP ) == 0 ) )
6567: CALL_VAR(PendingInterruptFunction); /* call the interrupt handler */
6568: if ( MFP_UpdateNeeded == true )
6569: MFP_UpdateIRQ ( 0 );
6570: #endif
1.1.1.4 root 6571:
1.1.1.7 root 6572: if (regs.spcflags) {
6573: if (do_specialties (cpu_cycles))
6574: return;
1.1.1.4 root 6575: }
1.1.1.7 root 6576:
6577: #ifdef WINUAE_FOR_HATARI
6578: /* Run DSP 56k code if necessary */
6579: if (bDspEnabled) {
6580: DSP_Run(2 * cpu_cycles * 2 / CYCLE_UNIT);
1.1.1.8 root 6581: // DSP_Run ( DSP_CPU_FREQ_RATIO * ( CyclesGlobalClockCounter - DSP_CyclesGlobalClockCounter ) );
1.1.1.7 root 6582: }
1.1.1.10! root 6583:
! 6584: if ( savestate_state == STATE_SAVE )
! 6585: save_state ( NULL , NULL );
1.1.1.7 root 6586: #endif
1.1.1.4 root 6587: }
1.1.1.7 root 6588: } CATCH (prb) {
6589:
6590: if (mmu_restart) {
6591: /* restore state if instruction restart */
6592: regflags.cznv = f.cznv;
6593: regflags.x = f.x;
6594: m68k_setpci (regs.instruction_pc);
1.1.1.4 root 6595: }
1.1.1.7 root 6596:
6597: if (mmufixup[0].reg >= 0) {
6598: m68k_areg (regs, mmufixup[0].reg) = mmufixup[0].value;
6599: mmufixup[0].reg = -1;
1.1.1.4 root 6600: }
1.1.1.7 root 6601:
6602: TRY (prb2) {
6603: Exception (prb);
6604: } CATCH (prb2) {
6605: halt = 1;
6606: } ENDTRY
6607: } ENDTRY
6608: }
6609: cpu_halt(halt);
6610: }
6611:
6612: #endif
6613:
6614: #ifdef CPUEMU_32
6615:
6616: // Previous MMU 68030
6617: static void m68k_run_mmu030 (void)
6618: {
6619: struct flag_struct f;
6620: int halt = 0;
1.1.1.8 root 6621:
6622: #ifdef WINUAE_FOR_HATARI
6623: Log_Printf(LOG_DEBUG, "m68k_run_mmu030\n");
6624: #endif
1.1.1.7 root 6625:
6626: mmu030_opcode_stageb = -1;
6627: mmu030_fake_prefetch = -1;
1.1.1.9 root 6628: check_halt();
1.1.1.7 root 6629: while(!halt) {
6630: TRY (prb) {
6631: for (;;) {
6632: int cnt;
6633: insretry:
6634: regs.instruction_pc = m68k_getpc ();
6635: f.cznv = regflags.cznv;
6636: f.x = regflags.x;
6637:
6638: mmu030_state[0] = mmu030_state[1] = mmu030_state[2] = 0;
6639: mmu030_opcode = -1;
6640: if (mmu030_fake_prefetch >= 0) {
6641: // use fake prefetch opcode only if mapping changed
6642: uaecptr new_addr = mmu030_translate(regs.instruction_pc, regs.s != 0, false, false);
6643: if (mmu030_fake_prefetch_addr != new_addr) {
6644: regs.opcode = mmu030_fake_prefetch;
1.1.1.8 root 6645: write_log(_T("MMU030 fake prefetch remap: %04x, %08x -> %08x\n"), mmu030_fake_prefetch, mmu030_fake_prefetch_addr, new_addr);
1.1.1.7 root 6646: } else {
6647: if (mmu030_opcode_stageb < 0) {
6648: regs.opcode = x_prefetch (0);
6649: } else {
6650: regs.opcode = mmu030_opcode_stageb;
6651: mmu030_opcode_stageb = -1;
6652: }
6653: }
6654: mmu030_fake_prefetch = -1;
6655: } else if (mmu030_opcode_stageb < 0) {
1.1.1.9 root 6656: if (currprefs.cpu_compatible)
6657: regs.opcode = regs.irc;
6658: else
6659: regs.opcode = x_prefetch (0);
1.1.1.7 root 6660: } else {
6661: regs.opcode = mmu030_opcode_stageb;
6662: mmu030_opcode_stageb = -1;
6663: }
6664:
6665: mmu030_opcode = regs.opcode;
6666: mmu030_ad[0].done = false;
6667:
6668: cnt = 50;
6669: for (;;) {
1.1.1.10! root 6670: #ifdef WINUAE_FOR_HATARI
! 6671: //m68k_dumpstate_file(stderr, NULL, 0xffffffff);
! 6672: if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM))
! 6673: {
! 6674: int FrameCycles, HblCounterVideo, LineCycles;
! 6675: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
! 6676: LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo );
! 6677: m68k_disasm_file(stderr, m68k_getpc (), NULL, m68k_getpc (), 1);
! 6678: }
! 6679: #endif
1.1.1.9 root 6680: regs.opcode = regs.irc = mmu030_opcode;
1.1.1.7 root 6681: mmu030_idx = 0;
1.1.1.9 root 6682:
1.1.1.7 root 6683: mmu030_retry = false;
6684:
1.1.1.9 root 6685: if (!currprefs.cpu_cycle_exact) {
6686:
6687: count_instr (regs.opcode);
6688: do_cycles (cpu_cycles);
6689:
6690: cpu_cycles = (*cpufunctbl[regs.opcode])(regs.opcode);
6691:
6692: } else {
6693: #ifdef WINUAE_FOR_HATARI
6694: currcycle = 0;
6695: #endif
6696: (*cpufunctbl[regs.opcode])(regs.opcode);
6697:
6698: wait_memory_cycles();
6699: }
6700:
1.1.1.7 root 6701: cnt--; // so that we don't get in infinite loop if things go horribly wrong
6702: if (!mmu030_retry)
6703: break;
6704: if (cnt < 0) {
1.1.1.8 root 6705: cpu_halt (CPU_HALT_CPU_STUCK);
1.1.1.7 root 6706: break;
6707: }
6708: if (mmu030_retry && mmu030_opcode == -1)
6709: goto insretry; // urgh
6710: }
1.1.1.4 root 6711:
1.1.1.7 root 6712: mmu030_opcode = -1;
1.1.1.4 root 6713:
1.1.1.9 root 6714: if (!currprefs.cpu_cycle_exact) {
1.1.1.4 root 6715:
1.1.1.9 root 6716: cpu_cycles = adjust_cycles (cpu_cycles);
1.1.1.7 root 6717: #ifdef WINUAE_FOR_HATARI
1.1.1.9 root 6718: M68000_AddCycles(cpu_cycles * 2 / CYCLE_UNIT);
1.1.1.4 root 6719:
1.1.1.9 root 6720: if ( WaitStateCycles ) {
6721: /* Add some extra cycles to simulate a wait state */
6722: M68000_AddCycles(WaitStateCycles);
6723: WaitStateCycles = 0;
6724: }
1.1.1.7 root 6725:
1.1.1.9 root 6726: /* We can have several interrupts at the same time before the next CPU instruction */
6727: /* We must check for pending interrupt and call do_specialties_interrupt() only */
6728: /* if the cpu is not in the STOP state. Else, the int could be acknowledged now */
6729: /* and prevent exiting the STOP state when calling do_specialties() after. */
6730: /* For performance, we first test PendingInterruptCount, then regs.spcflags */
6731: while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) && ( ( regs.spcflags & SPCFLAG_STOP ) == 0 ) )
6732: CALL_VAR(PendingInterruptFunction); /* call the interrupt handler */
6733: if ( MFP_UpdateNeeded == true )
6734: MFP_UpdateIRQ ( 0 );
1.1.1.7 root 6735: #endif
1.1.1.9 root 6736: if (regs.spcflags) {
6737: if (do_specialties (cpu_cycles))
6738: return;
6739: }
1.1.1.7 root 6740: #ifdef WINUAE_FOR_HATARI
1.1.1.10! root 6741: /* Run DSP 56k code if necessary */
! 6742: if (bDspEnabled) {
! 6743: DSP_Run(2 * cpu_cycles * 2 / CYCLE_UNIT);
! 6744: // DSP_Run ( DSP_CPU_FREQ_RATIO * ( CyclesGlobalClockCounter - DSP_CyclesGlobalClockCounter ) );
! 6745: }
1.1.1.7 root 6746: #endif
6747:
1.1.1.9 root 6748: } else {
6749:
6750: #ifdef WINUAE_FOR_HATARI
6751: //fprintf ( stderr, "cyc_2ce %d\n" , currcycle );
6752: /* Flush all CE cycles so far to update PendingInterruptCount */
6753: M68000_AddCycles_CE ( currcycle * 2 / CYCLE_UNIT );
6754: // currcycle = 0; // FIXME : uncomment this when using DSP_CyclesGlobalClockCounter in DSP_Run
6755:
6756: /* We can have several interrupts at the same time before the next CPU instruction */
6757: /* We must check for pending interrupt and call do_specialties_interrupt() only */
6758: /* if the cpu is not in the STOP state. Else, the int could be acknowledged now */
6759: /* and prevent exiting the STOP state when calling do_specialties() after. */
6760: /* For performance, we first test PendingInterruptCount, then regs.spcflags */
6761: while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) && ( ( regs.spcflags & SPCFLAG_STOP ) == 0 ) )
6762: CALL_VAR(PendingInterruptFunction); /* call the interrupt handler */
6763: if ( MFP_UpdateNeeded == true )
6764: MFP_UpdateIRQ ( 0 );
6765: #endif
6766:
6767: if (regs.spcflags || time_for_interrupt ()) {
6768: if (do_specialties (0))
6769: return;
6770: }
6771:
6772: #ifdef WINUAE_FOR_HATARI
6773: /* Run DSP 56k code if necessary */
6774: if (bDspEnabled) {
6775: //fprintf ( stderr, "dsp cyc_2ce %d\n" , currcycle );
6776: DSP_Run(2 * currcycle * 2 / CYCLE_UNIT);
6777: //fprintf ( stderr, "dsp cyc_2ce %d - %d\n" , currcycle * 2 / CYCLE_UNIT , (CyclesGlobalClockCounter - DSP_CyclesGlobalClockCounter) );
6778: // DSP_Run ( DSP_CPU_FREQ_RATIO * ( CyclesGlobalClockCounter - DSP_CyclesGlobalClockCounter ) );
6779: }
6780: #endif
6781:
6782: regs.ipl = regs.ipl_pin;
6783:
6784: }
6785:
1.1.1.10! root 6786: #ifdef WINUAE_FOR_HATARI
! 6787: if ( savestate_state == STATE_SAVE )
! 6788: save_state ( NULL , NULL );
! 6789: #endif
1.1.1.9 root 6790: }
6791:
6792: } CATCH (prb) {
6793:
6794: if (mmu030_opcode == -1 && currprefs.cpu_compatible) {
6795: // full prefetch fill access fault
6796: // TODO: this should create shorter A-frame
6797: mmufixup[0].reg = -1;
6798: mmufixup[1].reg = -1;
1.1.1.10! root 6799: } else if (!(mmu030_state[1] & MMU030_STATEFLAG1_LASTWRITE)) {
1.1.1.9 root 6800: regflags.cznv = f.cznv;
6801: regflags.x = f.x;
6802:
6803: if (mmufixup[0].reg >= 0) {
1.1.1.10! root 6804: m68k_areg(regs, mmufixup[0].reg) = mmufixup[0].value;
1.1.1.9 root 6805: mmufixup[0].reg = -1;
6806: }
6807: if (mmufixup[1].reg >= 0) {
1.1.1.10! root 6808: m68k_areg(regs, mmufixup[1].reg) = mmufixup[1].value;
1.1.1.9 root 6809: mmufixup[1].reg = -1;
6810: }
6811: }
6812:
6813: m68k_setpci (regs.instruction_pc);
6814:
6815: TRY (prb2) {
6816: Exception (prb);
6817: } CATCH (prb2) {
6818: halt = 1;
6819: } ENDTRY
6820: } ENDTRY
6821: }
6822: cpu_halt (halt);
6823: }
1.1.1.7 root 6824:
6825: #endif
6826:
6827:
6828: /* "cycle exact" 68040/060 */
6829:
6830: static void m68k_run_3ce (void)
6831: {
6832: struct regstruct *r = ®s;
6833: bool exit = false;
1.1.1.10! root 6834: int extracycles = 0;
1.1.1.8 root 6835:
6836: Log_Printf(LOG_DEBUG, "m68k_run_3ce\n");
1.1.1.7 root 6837:
6838: while (!exit) {
6839: TRY(prb) {
6840: while (!exit) {
6841: #ifdef WINUAE_FOR_HATARI
1.1.1.10! root 6842: //m68k_dumpstate_file(stderr, NULL, 0xffffffff);
1.1.1.7 root 6843: if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM))
6844: {
6845: int FrameCycles, HblCounterVideo, LineCycles;
6846: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
6847: LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo );
1.1.1.10! root 6848: m68k_disasm_file(stderr, m68k_getpc (), NULL, m68k_getpc (), 1);
1.1.1.7 root 6849: }
1.1.1.8 root 6850: currcycle = CYCLE_UNIT / 2; /* Assume at least 1 cycle per instruction */
1.1.1.7 root 6851: #endif
6852: r->instruction_pc = m68k_getpc();
6853: r->opcode = get_iword_cache_040(0);
6854: // "prefetch"
6855: if (regs.cacr & 0x8000)
6856: fill_icache040(r->instruction_pc + 16);
6857:
6858: (*cpufunctbl[r->opcode])(r->opcode);
6859:
6860: #ifdef WINUAE_FOR_HATARI
1.1.1.8 root 6861: //fprintf ( stderr, "cyc_3ce %ld\n" , currcycle );
6862: /* Flush all CE cycles so far to update PendingInterruptCount */
6863: M68000_AddCycles_CE ( currcycle * 2 / CYCLE_UNIT );
6864: // currcycle = 0; // FIXME : uncomment this when using DSP_CyclesGlobalClockCounter in DSP_Run
1.1.1.7 root 6865:
6866: /* We can have several interrupts at the same time before the next CPU instruction */
6867: /* We must check for pending interrupt and call do_specialties_interrupt() only */
6868: /* if the cpu is not in the STOP state. Else, the int could be acknowledged now */
6869: /* and prevent exiting the STOP state when calling do_specialties() after. */
6870: /* For performance, we first test PendingInterruptCount, then regs.spcflags */
6871: while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) && ( ( regs.spcflags & SPCFLAG_STOP ) == 0 ) )
6872: CALL_VAR(PendingInterruptFunction); /* call the interrupt handler */
6873: if ( MFP_UpdateNeeded == true )
6874: MFP_UpdateIRQ ( 0 );
6875: #endif
6876: if (r->spcflags) {
6877: if (do_specialties (0))
6878: exit = true;
6879: }
6880:
1.1.1.10! root 6881: // workaround for situation when all accesses are cached
! 6882: extracycles++;
! 6883: if (extracycles >= 8) {
! 6884: extracycles = 0;
! 6885: #ifdef WINUAE_FOR_HATARI
! 6886: x_do_cycles(CYCLE_UNIT);
! 6887: #else
! 6888: M68000_AddCycles_CE ( 2 );
! 6889: #endif
! 6890: }
! 6891:
1.1.1.7 root 6892: #ifdef WINUAE_FOR_HATARI
6893: /* Run DSP 56k code if necessary */
6894: if (bDspEnabled) {
6895: DSP_Run(2 * currcycle * 2 / CYCLE_UNIT);
1.1.1.8 root 6896: // DSP_Run ( DSP_CPU_FREQ_RATIO * ( CyclesGlobalClockCounter - DSP_CyclesGlobalClockCounter ) );
1.1.1.4 root 6897: }
1.1.1.10! root 6898:
! 6899: if ( savestate_state == STATE_SAVE )
! 6900: save_state ( NULL , NULL );
1.1.1.7 root 6901: #endif
1.1.1.4 root 6902: }
1.1.1.7 root 6903: } CATCH(prb) {
6904: bus_error();
6905: if (r->spcflags) {
6906: if (do_specialties(0))
6907: exit = true;
6908: }
6909: } ENDTRY
6910: }
6911: }
1.1.1.4 root 6912:
1.1.1.7 root 6913: /* "prefetch" 68040/060 */
1.1.1.4 root 6914:
1.1.1.7 root 6915: static void m68k_run_3p(void)
6916: {
6917: struct regstruct *r = ®s;
6918: bool exit = false;
6919: int cycles;
1.1.1.8 root 6920:
6921: Log_Printf(LOG_DEBUG, "m68k_run_3p\n");
1.1.1.7 root 6922:
6923: while (!exit) {
6924: TRY(prb) {
6925: while (!exit) {
6926: #ifdef WINUAE_FOR_HATARI
1.1.1.10! root 6927: //m68k_dumpstate_file(stderr, NULL, 0xffffffff);
1.1.1.7 root 6928: if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM))
6929: {
6930: int FrameCycles, HblCounterVideo, LineCycles;
6931: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
6932: LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo );
1.1.1.10! root 6933: m68k_disasm_file(stderr, m68k_getpc (), NULL, m68k_getpc (), 1);
1.1.1.7 root 6934: }
6935: #endif
6936: r->instruction_pc = m68k_getpc();
6937: r->opcode = get_iword_cache_040(0);
6938: // "prefetch"
6939: if (regs.cacr & 0x8000)
6940: fill_icache040(r->instruction_pc + 16);
6941:
6942: (*cpufunctbl[r->opcode])(r->opcode);
6943:
1.1.1.8 root 6944: #ifndef WINUAE_FOR_HATARI
1.1.1.7 root 6945: cpu_cycles = 1 * CYCLE_UNIT;
6946: cycles = adjust_cycles(cpu_cycles);
6947: do_cycles(cycles);
1.1.1.8 root 6948: #else
6949: cycles = cpu_cycles = CYCLE_UNIT / 2;
6950: M68000_AddCycles_CE(cycles * 2 / CYCLE_UNIT);
1.1.1.7 root 6951:
1.1.1.8 root 6952: if ( WaitStateCycles ) {
1.1.1.7 root 6953: /* Add some extra cycles to simulate a wait state */
1.1.1.8 root 6954: M68000_AddCycles(WaitStateCycles);
6955: WaitStateCycles = 0;
1.1.1.7 root 6956: }
1.1.1.4 root 6957:
1.1.1.7 root 6958: /* We can have several interrupts at the same time before the next CPU instruction */
6959: /* We must check for pending interrupt and call do_specialties_interrupt() only */
6960: /* if the cpu is not in the STOP state. Else, the int could be acknowledged now */
6961: /* and prevent exiting the STOP state when calling do_specialties() after. */
6962: /* For performance, we first test PendingInterruptCount, then regs.spcflags */
6963: while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) && ( ( regs.spcflags & SPCFLAG_STOP ) == 0 ) )
6964: CALL_VAR(PendingInterruptFunction); /* call the interrupt handler */
6965: if ( MFP_UpdateNeeded == true )
6966: MFP_UpdateIRQ ( 0 );
6967: #endif
6968:
6969: if (r->spcflags) {
6970: if (do_specialties(0))
6971: exit = true;
6972: }
6973:
6974: #ifdef WINUAE_FOR_HATARI
6975: /* Run DSP 56k code if necessary */
6976: if (bDspEnabled) {
6977: DSP_Run(2 * cycles * 2 / CYCLE_UNIT);
1.1.1.8 root 6978: // DSP_Run ( DSP_CPU_FREQ_RATIO * ( CyclesGlobalClockCounter - DSP_CyclesGlobalClockCounter ) );
1.1.1.7 root 6979: }
1.1.1.10! root 6980:
! 6981: if ( savestate_state == STATE_SAVE )
! 6982: save_state ( NULL , NULL );
1.1.1.7 root 6983: #endif
6984: }
6985: } CATCH(prb) {
6986: bus_error();
6987: if (r->spcflags) {
6988: if (do_specialties(0))
6989: exit = true;
6990: }
6991: } ENDTRY
6992: }
1.1.1.4 root 6993: }
6994:
6995: /* "cycle exact" 68020/030 */
1.1.1.7 root 6996:
6997: STATIC_INLINE struct cache030 *getcache030 (struct cache030 *cp, uaecptr addr, uae_u32 *tagp, int *lwsp);
1.1.1.4 root 6998: static void m68k_run_2ce (void)
6999: {
7000: struct regstruct *r = ®s;
1.1.1.7 root 7001: bool exit = false;
7002: bool first = true;
1.1.1.8 root 7003:
7004: Log_Printf(LOG_DEBUG, "m68k_run_2ce\n");
1.1.1.7 root 7005:
7006: while (!exit) {
7007: TRY(prb) {
7008: if (first) {
7009: if (cpu_tracer < 0) {
7010: memcpy (&r->regs, &cputrace.regs, 16 * sizeof (uae_u32));
7011: r->ir = cputrace.ir;
7012: r->irc = cputrace.irc;
7013: r->sr = cputrace.sr;
7014: r->usp = cputrace.usp;
7015: r->isp = cputrace.isp;
7016: r->intmask = cputrace.intmask;
7017: r->stopped = cputrace.stopped;
7018:
7019: r->msp = cputrace.msp;
7020: r->vbr = cputrace.vbr;
7021: r->caar = cputrace.caar;
7022: r->cacr = cputrace.cacr;
7023: r->cacheholdingdata020 = cputrace.cacheholdingdata020;
7024: r->cacheholdingaddr020 = cputrace.cacheholdingaddr020;
7025: r->prefetch020addr = cputrace.prefetch020addr;
1.1.1.9 root 7026: memcpy(&r->prefetch020, &cputrace.prefetch020, CPU_PIPELINE_MAX * sizeof(uae_u16));
7027: memcpy(&r->prefetch020_valid, &cputrace.prefetch020_valid, CPU_PIPELINE_MAX * sizeof(uae_u8));
7028: memcpy(&caches020, &cputrace.caches020, sizeof caches020);
1.1.1.7 root 7029:
7030: m68k_setpc (cputrace.pc);
7031: if (!r->stopped) {
7032: if (cputrace.state > 1)
7033: Exception (cputrace.state);
7034: else if (cputrace.state == 1)
7035: (*cpufunctbl[cputrace.opcode])(cputrace.opcode);
7036: }
7037: if (regs.stopped)
7038: set_special (SPCFLAG_STOP);
7039: set_cpu_tracer (false);
7040: goto cont;
7041: }
7042: set_cpu_tracer (false);
7043: first = false;
7044: }
1.1.1.4 root 7045:
1.1.1.7 root 7046: while (!exit) {
1.1.1.8 root 7047: #if 0
1.1.1.7 root 7048: static int prevopcode;
1.1.1.8 root 7049: #endif
1.1.1.7 root 7050: #ifdef WINUAE_FOR_HATARI
1.1.1.10! root 7051: //m68k_dumpstate_file(stderr, NULL, 0xffffffff);
1.1.1.7 root 7052: if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM))
7053: {
7054: int FrameCycles, HblCounterVideo, LineCycles;
7055: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
7056: LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo );
1.1.1.10! root 7057: m68k_disasm_file(stderr, m68k_getpc (), NULL, m68k_getpc (), 1);
1.1.1.7 root 7058: #if 0
7059: // logs to debug data cache issues
7060: struct cache030 *c1 ,*c2;
7061: int lws1, lws2;
7062: uae_u32 tag1, tag2;
7063: c1 = getcache030 (dcaches030, (uaecptr)0x27ece, &tag1, &lws1);
7064: c2 = getcache030 (dcaches030, (uaecptr)0x7f8192+4, &tag2, &lws2);
7065: fprintf ( stderr , "cache valid %d tag1 %x lws1 %x ctag %x data %x mem=%x\n" , c1->valid[lws1] , tag1 , lws1 , c1->tag , c1->data[lws1] , get_long(0x27ece) );
7066: //fprintf ( stderr , "cache valid %d tag2 %x lws2 %x ctag %x data %x mem=%x\n" , c2->valid[lws2] , tag2 , lws2 , c2->tag , c2->data[lws2] , get_long(0x7f8192+4) );
7067: #endif
7068: }
1.1.1.4 root 7069:
1.1.1.7 root 7070: currcycle = 0;
7071: #endif
7072: r->instruction_pc = m68k_getpc ();
1.1.1.4 root 7073:
1.1.1.8 root 7074: #if 0
1.1.1.7 root 7075: if (regs.irc == 0xfffb) {
7076: gui_message (_T("OPCODE %04X HAS FAULTY PREFETCH! PC=%08X"), prevopcode, r->instruction_pc);
7077: }
1.1.1.8 root 7078: #endif
1.1.1.4 root 7079:
1.1.1.7 root 7080: //write_log (_T("%x %04x\n"), r->instruction_pc, regs.irc);
1.1.1.4 root 7081:
1.1.1.7 root 7082: r->opcode = regs.irc;
1.1.1.8 root 7083: #if 0
1.1.1.7 root 7084: prevopcode = r->opcode;
7085: regs.irc = 0xfffb;
1.1.1.8 root 7086: #endif
1.1.1.7 root 7087: //write_log (_T("%08x %04x\n"), r->instruction_pc, opcode);
1.1.1.5 root 7088:
1.1.1.7 root 7089: #ifndef WINUAE_FOR_HATARI
7090: #if DEBUG_CD32CDTVIO
7091: out_cd32io (r->instruction_pc);
7092: #endif
7093: #endif
1.1.1.4 root 7094:
1.1.1.7 root 7095: if (cpu_tracer) {
1.1.1.4 root 7096:
1.1.1.7 root 7097: #if CPUTRACE_DEBUG
7098: validate_trace ();
7099: #endif
7100: memcpy (&cputrace.regs, &r->regs, 16 * sizeof (uae_u32));
7101: cputrace.opcode = r->opcode;
7102: cputrace.ir = r->ir;
7103: cputrace.irc = r->irc;
7104: cputrace.sr = r->sr;
7105: cputrace.usp = r->usp;
7106: cputrace.isp = r->isp;
7107: cputrace.intmask = r->intmask;
7108: cputrace.stopped = r->stopped;
7109: cputrace.state = 1;
7110: cputrace.pc = m68k_getpc ();
7111:
7112: cputrace.msp = r->msp;
7113: cputrace.vbr = r->vbr;
7114: cputrace.caar = r->caar;
7115: cputrace.cacr = r->cacr;
7116: cputrace.cacheholdingdata020 = r->cacheholdingdata020;
7117: cputrace.cacheholdingaddr020 = r->cacheholdingaddr020;
7118: cputrace.prefetch020addr = r->prefetch020addr;
1.1.1.9 root 7119: memcpy(&cputrace.prefetch020, &r->prefetch020, CPU_PIPELINE_MAX * sizeof (uae_u16));
7120: memcpy(&cputrace.prefetch020_valid, &r->prefetch020_valid, CPU_PIPELINE_MAX * sizeof(uae_u8));
7121: memcpy(&cputrace.caches020, &caches020, sizeof caches020);
1.1.1.7 root 7122:
7123: cputrace.memoryoffset = 0;
7124: cputrace.cyclecounter = cputrace.cyclecounter_pre = cputrace.cyclecounter_post = 0;
7125: cputrace.readcounter = cputrace.writecounter = 0;
7126: }
1.1.1.4 root 7127:
1.1.1.7 root 7128: #ifndef WINUAE_FOR_HATARI
7129: if (inputrecord_debug & 4) {
7130: if (input_record > 0)
7131: inprec_recorddebug_cpu (1);
7132: else if (input_play > 0)
7133: inprec_playdebug_cpu (1);
7134: }
7135: #endif
1.1.1.4 root 7136:
1.1.1.7 root 7137: (*cpufunctbl[r->opcode])(r->opcode);
7138:
7139: wait_memory_cycles();
7140:
1.1.1.8 root 7141: #ifdef WINUAE_FOR_HATARI
7142: //fprintf ( stderr, "cyc_2ce %d\n" , currcycle );
7143: /* Flush all CE cycles so far to update PendingInterruptCount */
7144: M68000_AddCycles_CE ( currcycle * 2 / CYCLE_UNIT );
7145: // currcycle = 0; // FIXME : uncomment this when using DSP_CyclesGlobalClockCounter in DSP_Run
1.1.1.4 root 7146:
1.1.1.7 root 7147: /* We can have several interrupts at the same time before the next CPU instruction */
7148: /* We must check for pending interrupt and call do_specialties_interrupt() only */
7149: /* if the cpu is not in the STOP state. Else, the int could be acknowledged now */
7150: /* and prevent exiting the STOP state when calling do_specialties() after. */
7151: /* For performance, we first test PendingInterruptCount, then regs.spcflags */
7152: while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) && ( ( regs.spcflags & SPCFLAG_STOP ) == 0 ) )
7153: CALL_VAR(PendingInterruptFunction); /* call the interrupt handler */
7154: if ( MFP_UpdateNeeded == true )
7155: MFP_UpdateIRQ ( 0 );
7156: #endif
1.1.1.4 root 7157:
1.1.1.9 root 7158: cont:
1.1.1.7 root 7159: if (r->spcflags || time_for_interrupt ()) {
7160: if (do_specialties (0))
7161: exit = true;
7162: }
1.1.1.4 root 7163:
1.1.1.10! root 7164: regs.ipl = regs.ipl_pin;
1.1.1.7 root 7165: #ifdef WINUAE_FOR_HATARI
7166: /* Run DSP 56k code if necessary */
7167: if (bDspEnabled) {
7168: //fprintf ( stderr, "dsp cyc_2ce %d\n" , currcycle );
7169: DSP_Run(2 * currcycle * 2 / CYCLE_UNIT);
1.1.1.8 root 7170: //fprintf ( stderr, "dsp cyc_2ce %d - %d\n" , currcycle * 2 / CYCLE_UNIT , (CyclesGlobalClockCounter - DSP_CyclesGlobalClockCounter) );
7171: // DSP_Run ( DSP_CPU_FREQ_RATIO * ( CyclesGlobalClockCounter - DSP_CyclesGlobalClockCounter ) );
1.1.1.7 root 7172: }
1.1.1.4 root 7173:
1.1.1.10! root 7174: if ( savestate_state == STATE_SAVE )
! 7175: save_state ( NULL , NULL );
! 7176: #endif
1.1.1.4 root 7177:
1.1.1.7 root 7178: }
7179: } CATCH(prb) {
7180: bus_error();
7181: if (r->spcflags || time_for_interrupt()) {
1.1.1.9 root 7182: if (do_specialties(0))
1.1.1.7 root 7183: exit = true;
7184: }
1.1.1.9 root 7185: regs.ipl = regs.ipl_pin;
1.1.1.7 root 7186: } ENDTRY
1.1.1.4 root 7187: }
7188: }
7189:
1.1.1.7 root 7190: #ifdef CPUEMU_20
7191:
7192: // full prefetch 020 (more compatible)
1.1.1.4 root 7193: static void m68k_run_2p (void)
7194: {
7195: struct regstruct *r = ®s;
1.1.1.7 root 7196: bool exit = false;
1.1.1.8 root 7197: bool first = true;
7198:
7199: Log_Printf(LOG_DEBUG, "m68k_run_2p\n");
1.1.1.4 root 7200:
1.1.1.7 root 7201: while (!exit) {
7202: TRY(prb) {
1.1.1.8 root 7203:
7204: if (first) {
7205: if (cpu_tracer < 0) {
7206: memcpy (&r->regs, &cputrace.regs, 16 * sizeof (uae_u32));
7207: r->ir = cputrace.ir;
7208: r->irc = cputrace.irc;
7209: r->sr = cputrace.sr;
7210: r->usp = cputrace.usp;
7211: r->isp = cputrace.isp;
7212: r->intmask = cputrace.intmask;
7213: r->stopped = cputrace.stopped;
7214:
7215: r->msp = cputrace.msp;
7216: r->vbr = cputrace.vbr;
7217: r->caar = cputrace.caar;
7218: r->cacr = cputrace.cacr;
7219: r->cacheholdingdata020 = cputrace.cacheholdingdata020;
7220: r->cacheholdingaddr020 = cputrace.cacheholdingaddr020;
7221: r->prefetch020addr = cputrace.prefetch020addr;
1.1.1.9 root 7222: memcpy(&r->prefetch020, &cputrace.prefetch020, CPU_PIPELINE_MAX * sizeof(uae_u16));
7223: memcpy(&r->prefetch020_valid, &cputrace.prefetch020_valid, CPU_PIPELINE_MAX * sizeof(uae_u8));
7224: memcpy(&caches020, &cputrace.caches020, sizeof caches020);
1.1.1.8 root 7225:
7226: m68k_setpc (cputrace.pc);
7227: if (!r->stopped) {
7228: if (cputrace.state > 1)
7229: Exception (cputrace.state);
7230: else if (cputrace.state == 1)
7231: (*cpufunctbl[cputrace.opcode])(cputrace.opcode);
7232: }
7233: if (regs.stopped)
7234: set_special (SPCFLAG_STOP);
7235: set_cpu_tracer (false);
7236: goto cont;
7237: }
7238: set_cpu_tracer (false);
7239: first = false;
7240: }
7241:
1.1.1.7 root 7242: while (!exit) {
7243: #ifdef WINUAE_FOR_HATARI
1.1.1.10! root 7244: //m68k_dumpstate_file(stderr, NULL, 0xffffffff);
1.1.1.7 root 7245: if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM))
7246: {
7247: int FrameCycles, HblCounterVideo, LineCycles;
7248: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
7249: LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo );
1.1.1.10! root 7250: m68k_disasm_file(stderr, m68k_getpc (), NULL, m68k_getpc (), 1);
1.1.1.7 root 7251: }
7252: #endif
7253: r->instruction_pc = m68k_getpc ();
1.1.1.8 root 7254: r->opcode = regs.irc;
1.1.1.4 root 7255:
1.1.1.7 root 7256: #ifndef WINUAE_FOR_HATARI
1.1.1.4 root 7257: #if DEBUG_CD32CDTVIO
1.1.1.7 root 7258: out_cd32io (m68k_getpc ());
7259: #endif
1.1.1.4 root 7260: #endif
7261:
1.1.1.8 root 7262: if (cpu_tracer) {
1.1.1.4 root 7263:
1.1.1.8 root 7264: #if CPUTRACE_DEBUG
7265: validate_trace ();
7266: #endif
7267: memcpy (&cputrace.regs, &r->regs, 16 * sizeof (uae_u32));
7268: cputrace.opcode = r->opcode;
7269: cputrace.ir = r->ir;
7270: cputrace.irc = r->irc;
7271: cputrace.sr = r->sr;
7272: cputrace.usp = r->usp;
7273: cputrace.isp = r->isp;
7274: cputrace.intmask = r->intmask;
7275: cputrace.stopped = r->stopped;
7276: cputrace.state = 1;
7277: cputrace.pc = m68k_getpc ();
7278:
7279: cputrace.msp = r->msp;
7280: cputrace.vbr = r->vbr;
7281: cputrace.caar = r->caar;
7282: cputrace.cacr = r->cacr;
7283: cputrace.cacheholdingdata020 = r->cacheholdingdata020;
7284: cputrace.cacheholdingaddr020 = r->cacheholdingaddr020;
7285: cputrace.prefetch020addr = r->prefetch020addr;
1.1.1.9 root 7286: memcpy(&cputrace.prefetch020, &r->prefetch020, CPU_PIPELINE_MAX * sizeof(uae_u16));
7287: memcpy(&cputrace.prefetch020_valid, &r->prefetch020_valid, CPU_PIPELINE_MAX * sizeof(uae_u8));
7288: memcpy(&cputrace.caches020, &caches020, sizeof caches020);
1.1.1.8 root 7289:
7290: cputrace.memoryoffset = 0;
7291: cputrace.cyclecounter = cputrace.cyclecounter_pre = cputrace.cyclecounter_post = 0;
7292: cputrace.readcounter = cputrace.writecounter = 0;
7293: }
7294:
7295: #ifndef WINUAE_FOR_HATARI
7296: if (inputrecord_debug & 4) {
7297: if (input_record > 0)
7298: inprec_recorddebug_cpu (1);
7299: else if (input_play > 0)
7300: inprec_playdebug_cpu (1);
7301: }
7302: #endif
1.1.1.10! root 7303: if (cpu_cycles > 0)
! 7304: x_do_cycles(cpu_cycles);
! 7305:
1.1.1.9 root 7306: if (currprefs.cpu_memory_cycle_exact) {
1.1.1.8 root 7307:
1.1.1.9 root 7308: (*cpufunctbl[r->opcode])(r->opcode);
1.1.1.10! root 7309: // 0% = no extra cycles
! 7310: cpu_cycles = 4 * CYCLE_UNIT * cycles_mult;
! 7311: cpu_cycles /= CYCLES_DIV;
! 7312: cpu_cycles -= CYCLE_UNIT;
! 7313: if (cpu_cycles <= 0)
! 7314: cpu_cycles = cpucycleunit;
1.1.1.4 root 7315:
1.1.1.9 root 7316: } else {
7317:
7318: cpu_cycles = (*cpufunctbl[r->opcode])(r->opcode);
7319: cpu_cycles = adjust_cycles (cpu_cycles);
7320:
7321: }
1.1.1.8 root 7322: cont:
1.1.1.7 root 7323: #ifdef WINUAE_FOR_HATARI
1.1.1.8 root 7324: //fprintf ( stderr , "waits %d %d %ld\n" , cpu_cycles*2/CYCLE_UNIT , WaitStateCycles , CyclesGlobalClockCounter );
1.1.1.7 root 7325: M68000_AddCycles(cpu_cycles * 2 / CYCLE_UNIT);
1.1.1.4 root 7326:
1.1.1.8 root 7327: //fprintf ( stderr , "waits %d %d %ld\n" , cpu_cycles*2/CYCLE_UNIT , WaitStateCycles , CyclesGlobalClockCounter );
1.1.1.10! root 7328: if ( WaitStateCycles ) {
1.1.1.7 root 7329: /* Add some extra cycles to simulate a wait state */
1.1.1.8 root 7330: M68000_AddCycles(WaitStateCycles);
7331: WaitStateCycles = 0;
1.1.1.7 root 7332: }
1.1.1.8 root 7333: //fprintf ( stderr , "waits %d %d %ld\n" , cpu_cycles*2/CYCLE_UNIT , WaitStateCycles , CyclesGlobalClockCounter );
1.1.1.4 root 7334:
1.1.1.7 root 7335: /* We can have several interrupts at the same time before the next CPU instruction */
7336: /* We must check for pending interrupt and call do_specialties_interrupt() only */
7337: /* if the cpu is not in the STOP state. Else, the int could be acknowledged now */
7338: /* and prevent exiting the STOP state when calling do_specialties() after. */
7339: /* For performance, we first test PendingInterruptCount, then regs.spcflags */
7340: while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) && ( ( regs.spcflags & SPCFLAG_STOP ) == 0 ) )
7341: CALL_VAR(PendingInterruptFunction); /* call the interrupt handler */
7342: if ( MFP_UpdateNeeded == true )
7343: MFP_UpdateIRQ ( 0 );
7344: #endif
1.1.1.4 root 7345:
1.1.1.7 root 7346: if (r->spcflags) {
7347: if (do_specialties (cpu_cycles))
7348: exit = true;
7349: }
1.1.1.10! root 7350: ipl_fetch ();
1.1.1.7 root 7351:
7352: #ifdef WINUAE_FOR_HATARI
7353: /* Run DSP 56k code if necessary */
7354: if (bDspEnabled) {
1.1.1.8 root 7355: //if ( DSP_CPU_FREQ_RATIO * ( (CyclesGlobalClockCounter - DSP_CyclesGlobalClockCounter) << nCpuFreqShift ) - 2 * cpu_cycles * 2 / CYCLE_UNIT >= 8 )
7356: //fprintf ( stderr , "dsp %d %d\n" , 2 * cpu_cycles * 2 / CYCLE_UNIT , DSP_CPU_FREQ_RATIO * ( (CyclesGlobalClockCounter - DSP_CyclesGlobalClockCounter) << nCpuFreqShift ) );
1.1.1.7 root 7357: DSP_Run(2 * cpu_cycles * 2 / CYCLE_UNIT);
1.1.1.8 root 7358: // DSP_Run ( DSP_CPU_FREQ_RATIO * ( CyclesGlobalClockCounter - DSP_CyclesGlobalClockCounter ) );
1.1.1.7 root 7359: }
7360:
1.1.1.10! root 7361: if ( savestate_state == STATE_SAVE )
! 7362: save_state ( NULL , NULL );
! 7363: #endif
1.1.1.7 root 7364: }
7365: } CATCH(prb) {
7366: bus_error();
7367: if (r->spcflags) {
7368: if (do_specialties(cpu_cycles))
1.1.1.8 root 7369: exit = true;
1.1.1.7 root 7370: }
7371: ipl_fetch();
7372: } ENDTRY
1.1.1.4 root 7373: }
7374: }
7375:
1.1.1.7 root 7376: #endif
1.1.1.4 root 7377:
1.1.1.8 root 7378: #ifdef WITH_THREADED_CPU
7379: static void *cpu_thread_run_2(void *v)
7380: {
7381: bool exit = false;
7382: struct regstruct *r = ®s;
7383:
1.1.1.10! root 7384: cpu_thread_tid = uae_thread_get_id();
! 7385:
1.1.1.8 root 7386: cpu_thread_active = 1;
7387: while (!exit) {
7388: TRY(prb)
7389: {
7390: while (!exit) {
7391: r->instruction_pc = m68k_getpc();
7392:
7393: r->opcode = x_get_iword(0);
7394:
7395: (*cpufunctbl[r->opcode])(r->opcode);
7396:
1.1.1.10! root 7397: if (regs.spcflags || cpu_thread_ilvl > 0) {
1.1.1.8 root 7398: if (do_specialties_thread())
7399: exit = true;
7400: }
1.1.1.10! root 7401:
1.1.1.8 root 7402: }
7403: } CATCH(prb)
7404: {
7405: bus_error();
7406: if (r->spcflags) {
7407: if (do_specialties_thread())
7408: exit = true;
7409: }
7410: } ENDTRY
7411: }
7412: cpu_thread_active = 0;
7413: return 0;
7414: }
7415: #endif
1.1.1.4 root 7416:
7417: /* Same thing, but don't use prefetch to get opcode. */
7418: static void m68k_run_2 (void)
7419: {
1.1.1.8 root 7420: #ifdef WITH_THREADED_CPU
7421: if (currprefs.cpu_thread) {
7422: run_cpu_thread(cpu_thread_run_2);
7423: return;
7424: }
7425: #endif
7426:
1.1.1.4 root 7427: struct regstruct *r = ®s;
1.1.1.7 root 7428: bool exit = false;
1.1.1.8 root 7429:
7430: Log_Printf(LOG_DEBUG, "m68k_run_2\n");
1.1.1.4 root 7431:
1.1.1.7 root 7432: while (!exit) {
7433: TRY(prb) {
7434: while (!exit) {
7435: #ifdef WINUAE_FOR_HATARI
1.1.1.10! root 7436: //m68k_dumpstate_file(stderr, NULL, 0xffffffff);
1.1.1.7 root 7437: if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM))
7438: {
7439: int FrameCycles, HblCounterVideo, LineCycles;
7440: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
7441: LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo );
1.1.1.10! root 7442: m68k_disasm_file(stderr, m68k_getpc (), NULL, m68k_getpc (), 1);
1.1.1.7 root 7443: }
7444: #endif
7445: r->instruction_pc = m68k_getpc ();
1.1.1.4 root 7446:
1.1.1.7 root 7447: r->opcode = x_get_iword(0);
7448: count_instr (r->opcode);
1.1.1.4 root 7449:
1.1.1.7 root 7450: do_cycles (cpu_cycles);
1.1.1.5 root 7451:
1.1.1.7 root 7452: cpu_cycles = (*cpufunctbl[r->opcode])(r->opcode);
7453: cpu_cycles = adjust_cycles (cpu_cycles);
7454: #ifdef WINUAE_FOR_HATARI
7455: //fprintf ( stderr , "cyc_2 %d\n" , cpu_cycles );
7456: M68000_AddCyclesWithPairing(cpu_cycles * 2 / CYCLE_UNIT);
7457:
1.1.1.8 root 7458: if ( WaitStateCycles ) {
1.1.1.7 root 7459: /* Add some extra cycles to simulate a wait state */
1.1.1.8 root 7460: M68000_AddCycles(WaitStateCycles);
7461: WaitStateCycles = 0;
1.1.1.7 root 7462: }
1.1.1.4 root 7463:
1.1.1.7 root 7464: /* We can have several interrupts at the same time before the next CPU instruction */
7465: /* We must check for pending interrupt and call do_specialties_interrupt() only */
7466: /* if the cpu is not in the STOP state. Else, the int could be acknowledged now */
7467: /* and prevent exiting the STOP state when calling do_specialties() after. */
7468: /* For performance, we first test PendingInterruptCount, then regs.spcflags */
7469: while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) && ( ( regs.spcflags & SPCFLAG_STOP ) == 0 ) )
7470: CALL_VAR(PendingInterruptFunction); /* call the interrupt handler */
7471: if ( MFP_UpdateNeeded == true )
7472: MFP_UpdateIRQ ( 0 );
7473: #endif
1.1.1.4 root 7474:
1.1.1.7 root 7475: if (r->spcflags) {
7476: if (do_specialties (cpu_cycles))
7477: exit = true;
7478: }
7479:
7480: #ifdef WINUAE_FOR_HATARI
7481: /* Run DSP 56k code if necessary */
7482: if (bDspEnabled) {
7483: DSP_Run(2 * cpu_cycles * 2 / CYCLE_UNIT);
1.1.1.8 root 7484: // DSP_Run ( DSP_CPU_FREQ_RATIO * ( CyclesGlobalClockCounter - DSP_CyclesGlobalClockCounter ) );
1.1.1.7 root 7485: }
1.1.1.10! root 7486:
! 7487: if ( savestate_state == STATE_SAVE )
! 7488: save_state ( NULL , NULL );
1.1.1.7 root 7489: #endif
7490: }
7491: } CATCH(prb) {
7492: bus_error();
7493: if (r->spcflags) {
7494: if (do_specialties(cpu_cycles))
7495: exit = true;
7496: }
7497: } ENDTRY
1.1.1.4 root 7498: }
7499: }
7500:
7501: /* fake MMU 68k */
1.1.1.8 root 7502: #if 0
1.1.1.4 root 7503: static void m68k_run_mmu (void)
7504: {
7505: for (;;) {
1.1.1.7 root 7506: #ifdef WINUAE_FOR_HATARI
1.1.1.10! root 7507: //m68k_dumpstate_file(stderr, NULL, 0xffffffff);
1.1.1.4 root 7508: if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM))
7509: {
7510: int FrameCycles, HblCounterVideo, LineCycles;
7511: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
7512: LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo );
1.1.1.10! root 7513: m68k_disasm_file(stderr, m68k_getpc (), NULL, m68k_getpc (), 1);
1.1.1.4 root 7514: }
1.1.1.7 root 7515: #endif
7516: regs.opcode = get_iiword (0);
1.1.1.4 root 7517: do_cycles (cpu_cycles);
7518: mmu_backup_regs = regs;
1.1.1.7 root 7519: cpu_cycles = (*cpufunctbl[regs.opcode])(regs.opcode);
7520: cpu_cycles = adjust_cycles (cpu_cycles);
1.1.1.4 root 7521: if (mmu_triggered)
7522: mmu_do_hit ();
7523: if (regs.spcflags) {
7524: if (do_specialties (cpu_cycles))
7525: return;
7526: }
7527: }
7528: }
1.1.1.8 root 7529: #endif
1.1.1.4 root 7530:
7531: #endif /* CPUEMU_0 */
7532:
7533: int in_m68k_go = 0;
7534:
1.1.1.8 root 7535: #if 0
1.1.1.4 root 7536: static void exception2_handle (uaecptr addr, uaecptr fault)
7537: {
7538: last_addr_for_exception_3 = addr;
7539: last_fault_for_exception_3 = fault;
7540: last_writeaccess_for_exception_3 = 0;
7541: last_instructionaccess_for_exception_3 = 0;
1.1.1.7 root 7542: Exception (2);
7543: }
1.1.1.8 root 7544: #endif
1.1.1.7 root 7545:
7546: static bool cpu_hardreset, cpu_keyboardreset;
7547:
7548: bool is_hardreset(void)
7549: {
7550: return cpu_hardreset;
7551: }
7552: bool is_keyboardreset(void)
7553: {
7554: return cpu_keyboardreset;
1.1.1.4 root 7555: }
7556:
7557: void m68k_go (int may_quit)
7558: {
1.1.1.7 root 7559: int hardboot = 1;
7560: int startup = 1;
7561:
1.1.1.8 root 7562: #ifdef WITH_THREADED_CPU
7563: init_cpu_thread();
7564: #endif
1.1.1.4 root 7565: if (in_m68k_go || !may_quit) {
1.1.1.7 root 7566: write_log (_T("Bug! m68k_go is not reentrant.\n"));
1.1.1.4 root 7567: abort ();
7568: }
7569:
7570: reset_frame_rate_hack ();
7571: update_68k_cycles ();
1.1.1.7 root 7572: #ifndef WINUAE_FOR_HATARI
7573: start_cycles = 0;
7574: #endif
7575:
7576: set_cpu_tracer (false);
1.1.1.4 root 7577:
1.1.1.7 root 7578: cpu_prefs_changed_flag = 0;
1.1.1.4 root 7579: in_m68k_go++;
7580: for (;;) {
7581: void (*run_func)(void);
7582:
1.1.1.7 root 7583: #ifdef WINUAE_FOR_HATARI
1.1.1.4 root 7584: /* Exit hatari ? */
7585: if (bQuitProgram == true)
7586: break;
1.1.1.7 root 7587: #endif
7588:
7589: cputrace.state = -1;
7590:
7591: #ifndef WINUAE_FOR_HATARI
1.1.1.8 root 7592: if (regs.halted == CPU_HALT_ACCELERATOR_CPU_FALLBACK) {
7593: regs.halted = 0;
7594: cpu_do_fallback();
7595: }
7596:
1.1.1.7 root 7597: if (currprefs.inprecfile[0] && input_play) {
7598: inprec_open (currprefs.inprecfile, NULL);
7599: changed_prefs.inprecfile[0] = currprefs.inprecfile[0] = 0;
7600: quit_program = UAE_RESET;
7601: }
7602: if (input_play || input_record)
7603: inprec_startup ();
1.1.1.10! root 7604: #endif
1.1.1.7 root 7605:
7606: if (quit_program > 0) {
7607: int restored = 0;
7608: cpu_keyboardreset = quit_program == UAE_RESET_KEYBOARD;
7609: cpu_hardreset = ((quit_program == UAE_RESET_HARD ? 1 : 0) | hardboot) != 0;
7610:
7611: if (quit_program == UAE_QUIT)
7612: break;
7613:
7614: hsync_counter = 0;
7615: vsync_counter = 0;
7616: quit_program = 0;
7617: hardboot = 0;
7618:
7619: #ifdef SAVESTATE
7620: if (savestate_state == STATE_DORESTORE)
7621: savestate_state = STATE_RESTORE;
7622: if (savestate_state == STATE_RESTORE)
7623: restore_state (savestate_fname);
1.1.1.10! root 7624: #ifndef WINUAE_FOR_HATARI
1.1.1.7 root 7625: else if (savestate_state == STATE_REWIND)
7626: savestate_rewind ();
7627: #endif
1.1.1.10! root 7628: #endif
1.1.1.8 root 7629: if (cpu_hardreset)
7630: m68k_reset_restore();
7631: prefs_changed_cpu();
1.1.1.9 root 7632: build_cpufunctbl();
7633: set_x_funcs();
1.1.1.10! root 7634: #ifndef WINUAE_FOR_HATARI
1.1.1.9 root 7635: set_cycles (start_cycles);
1.1.1.10! root 7636: #endif
1.1.1.7 root 7637: custom_reset (cpu_hardreset != 0, cpu_keyboardreset);
7638: m68k_reset2 (cpu_hardreset != 0);
7639: if (cpu_hardreset) {
7640: memory_clear ();
7641: write_log (_T("hardreset, memory cleared\n"));
7642: }
7643: cpu_hardreset = false;
7644: #ifdef SAVESTATE
7645: /* We may have been restoring state, but we're done now. */
7646: if (isrestore ()) {
1.1.1.10! root 7647: #ifndef WINUAE_FOR_HATARI
1.1.1.7 root 7648: if (debug_dma) {
7649: record_dma_reset ();
7650: record_dma_reset ();
7651: }
1.1.1.10! root 7652: #endif
1.1.1.7 root 7653: savestate_restore_finish ();
1.1.1.10! root 7654: #ifndef WINUAE_FOR_HATARI
1.1.1.7 root 7655: memory_map_dump ();
1.1.1.10! root 7656: #endif
1.1.1.7 root 7657: if (currprefs.mmu_model == 68030) {
1.1.1.9 root 7658: mmu030_decode_tc (tc_030, true);
1.1.1.7 root 7659: } else if (currprefs.mmu_model >= 68040) {
7660: mmu_set_tc (regs.tcr);
7661: }
7662: startup = 1;
7663: restored = 1;
7664: }
7665: #endif
1.1.1.10! root 7666: #ifndef WINUAE_FOR_HATARI
1.1.1.7 root 7667: if (currprefs.produce_sound == 0)
7668: eventtab[ev_audio].active = 0;
7669: m68k_setpc_normal (regs.pc);
7670: check_prefs_changed_audio ();
7671:
7672: if (!restored || hsync_counter == 0)
7673: savestate_check ();
7674: if (input_record == INPREC_RECORD_START)
7675: input_record = INPREC_RECORD_NORMAL;
7676: statusline_clear();
1.1.1.10! root 7677: #else
! 7678: m68k_setpc_normal (regs.pc);
! 7679: #endif
1.1.1.7 root 7680: } else {
1.1.1.10! root 7681: #ifndef WINUAE_FOR_HATARI
1.1.1.7 root 7682: if (input_record == INPREC_RECORD_START) {
7683: input_record = INPREC_RECORD_NORMAL;
7684: savestate_init ();
7685: hsync_counter = 0;
7686: vsync_counter = 0;
7687: savestate_check ();
7688: }
1.1.1.10! root 7689: #endif
1.1.1.7 root 7690: }
7691:
1.1.1.10! root 7692: #ifndef WINUAE_FOR_HATARI
1.1.1.7 root 7693: if (changed_prefs.inprecfile[0] && input_record)
7694: inprec_prepare_record (savestate_fname[0] ? savestate_fname : NULL);
7695: #endif
7696:
7697: set_cpu_tracer (false);
1.1.1.4 root 7698:
7699: #ifdef DEBUGGER
7700: if (debugging)
7701: debug ();
7702: #endif
1.1.1.7 root 7703: if (regs.spcflags & SPCFLAG_MODE_CHANGE) {
7704: if (cpu_prefs_changed_flag & 1) {
7705: uaecptr pc = m68k_getpc();
7706: prefs_changed_cpu();
1.1.1.9 root 7707: fpu_modechange();
1.1.1.10! root 7708: #ifndef WINUAE_FOR_HATARI
! 7709: custom_cpuchange();
! 7710: #endif
1.1.1.7 root 7711: build_cpufunctbl();
7712: m68k_setpc_normal(pc);
7713: fill_prefetch();
7714: }
7715: if (cpu_prefs_changed_flag & 2) {
7716: fixup_cpu(&changed_prefs);
7717: currprefs.m68k_speed = changed_prefs.m68k_speed;
7718: currprefs.m68k_speed_throttle = changed_prefs.m68k_speed_throttle;
7719: update_68k_cycles();
1.1.1.10! root 7720: #ifndef WINUAE_FOR_HATARI
! 7721: target_cpu_speed();
! 7722: #endif
1.1.1.7 root 7723: }
7724: cpu_prefs_changed_flag = 0;
7725: }
1.1.1.4 root 7726:
1.1.1.7 root 7727: set_x_funcs();
7728: #ifndef WINUAE_FOR_HATARI
7729: if (startup) {
7730: custom_prepare ();
7731: protect_roms (true);
1.1.1.4 root 7732: }
1.1.1.7 root 7733: startup = 0;
7734: event_wait = true;
1.1.1.4 root 7735: #endif
1.1.1.7 root 7736: unset_special(SPCFLAG_MODE_CHANGE);
1.1.1.4 root 7737:
1.1.1.9 root 7738: if (!regs.halted) {
7739: // check that PC points to something that looks like memory.
7740: uaecptr pc = m68k_getpc();
7741: #ifndef WINUAE_FOR_HATARI
7742: addrbank *ab = get_mem_bank_real(pc);
7743: #else
7744: addrbank *ab = &get_mem_bank(pc);
7745: #endif
7746: if (ab == NULL || ab == &dummy_bank || (!currprefs.cpu_compatible && !valid_address(pc, 2)) || (pc & 1)) {
7747: cpu_halt(CPU_HALT_INVALID_START_ADDRESS);
7748: }
7749: }
1.1.1.7 root 7750: if (regs.halted) {
7751: cpu_halt (regs.halted);
7752: if (regs.halted < 0) {
7753: haltloop();
7754: continue;
7755: }
7756: }
7757:
1.1.1.10! root 7758: #ifdef WINUAE_FOR_HATARI
! 7759: /* Apply patches for gemdos HD if needed (we need to do it after */
! 7760: /* cpu tables for all opcodes were rebuilt in build_cpufunctbl() ) */
! 7761: Cart_PatchCpuTables();
! 7762:
! 7763: /* Restore debugger state (breakpoints) after a reset */
! 7764: M68000_RestoreDebugger();
! 7765: #endif
! 7766:
1.1.1.7 root 7767: #if 0
1.1.1.4 root 7768: if (mmu_enabled && !currprefs.cachesize) {
7769: run_func = m68k_run_mmu;
7770: } else {
1.1.1.7 root 7771: #endif
7772: run_func = currprefs.cpu_cycle_exact && currprefs.cpu_model <= 68010 ? m68k_run_1_ce :
7773: currprefs.cpu_compatible && currprefs.cpu_model <= 68010 ? m68k_run_1 :
1.1.1.4 root 7774: #ifdef JIT
7775: currprefs.cpu_model >= 68020 && currprefs.cachesize ? m68k_run_jit :
7776: #endif
1.1.1.7 root 7777: currprefs.cpu_model == 68030 && currprefs.mmu_model ? m68k_run_mmu030 :
7778: currprefs.cpu_model == 68040 && currprefs.mmu_model ? m68k_run_mmu040 :
7779: currprefs.cpu_model == 68060 && currprefs.mmu_model ? m68k_run_mmu060 :
7780:
7781: currprefs.cpu_model >= 68040 && currprefs.cpu_cycle_exact ? m68k_run_3ce :
1.1.1.4 root 7782: currprefs.cpu_model >= 68020 && currprefs.cpu_cycle_exact ? m68k_run_2ce :
1.1.1.7 root 7783:
7784: currprefs.cpu_model <= 68020 && currprefs.cpu_compatible ? m68k_run_2p :
7785: currprefs.cpu_model == 68030 && currprefs.cpu_compatible ? m68k_run_2p :
7786: currprefs.cpu_model >= 68040 && currprefs.cpu_compatible ? m68k_run_3p :
7787:
7788: m68k_run_2;
7789: #if 0
1.1.1.4 root 7790: }
1.1.1.7 root 7791: #endif
7792: run_func();
1.1.1.8 root 7793: Log_Printf(LOG_DEBUG, "exit m68k_run\n");
1.1.1.4 root 7794: }
1.1.1.7 root 7795: #ifndef WINUAE_FOR_HATARI
7796: protect_roms (false);
7797: #endif
1.1.1.4 root 7798: in_m68k_go--;
7799: }
7800:
7801: #if 0
7802: static void m68k_verify (uaecptr addr, uaecptr *nextpc)
7803: {
1.1.1.7 root 7804: uae_u16 opcode, val;
1.1.1.4 root 7805: struct instr *dp;
7806:
7807: opcode = get_iword_1 (0);
7808: last_op_for_exception_3 = opcode;
7809: m68kpc_offset = 2;
7810:
7811: if (cpufunctbl[opcode] == op_illg_1) {
7812: opcode = 0x4AFC;
7813: }
7814: dp = table68k + opcode;
7815:
7816: if (dp->suse) {
7817: if (!verify_ea (dp->sreg, dp->smode, dp->size, &val)) {
7818: Exception (3, 0);
7819: return;
7820: }
7821: }
7822: if (dp->duse) {
7823: if (!verify_ea (dp->dreg, dp->dmode, dp->size, &val)) {
7824: Exception (3, 0);
7825: return;
7826: }
7827: }
7828: }
7829: #endif
7830:
7831: static const TCHAR *ccnames[] =
1.1.1.7 root 7832: {
7833: _T("T "),_T("F "),_T("HI"),_T("LS"),_T("CC"),_T("CS"),_T("NE"),_T("EQ"),
7834: _T("VC"),_T("VS"),_T("PL"),_T("MI"),_T("GE"),_T("LT"),_T("GT"),_T("LE")
7835: };
7836: static const TCHAR *fpccnames[] =
7837: {
7838: _T("F"),
7839: _T("EQ"),
7840: _T("OGT"),
7841: _T("OGE"),
7842: _T("OLT"),
7843: _T("OLE"),
7844: _T("OGL"),
7845: _T("OR"),
7846: _T("UN"),
7847: _T("UEQ"),
7848: _T("UGT"),
7849: _T("UGE"),
7850: _T("ULT"),
7851: _T("ULE"),
7852: _T("NE"),
7853: _T("T"),
7854: _T("SF"),
7855: _T("SEQ"),
7856: _T("GT"),
7857: _T("GE"),
7858: _T("LT"),
7859: _T("LE"),
7860: _T("GL"),
7861: _T("GLE"),
7862: _T("NGLE"),
7863: _T("NGL"),
7864: _T("NLE"),
7865: _T("NLT"),
7866: _T("NGE"),
7867: _T("NGT"),
7868: _T("SNE"),
7869: _T("ST")
7870: };
7871: static const TCHAR *fpuopcodes[] =
7872: {
7873: _T("FMOVE"),
7874: _T("FINT"),
7875: _T("FSINH"),
7876: _T("FINTRZ"),
7877: _T("FSQRT"),
7878: NULL,
7879: _T("FLOGNP1"),
7880: NULL,
7881: _T("FETOXM1"),
7882: _T("FTANH"),
7883: _T("FATAN"),
7884: NULL,
7885: _T("FASIN"),
7886: _T("FATANH"),
7887: _T("FSIN"),
7888: _T("FTAN"),
7889: _T("FETOX"), // 0x10
7890: _T("FTWOTOX"),
7891: _T("FTENTOX"),
7892: NULL,
7893: _T("FLOGN"),
7894: _T("FLOG10"),
7895: _T("FLOG2"),
7896: NULL,
7897: _T("FABS"),
7898: _T("FCOSH"),
7899: _T("FNEG"),
7900: NULL,
7901: _T("FACOS"),
7902: _T("FCOS"),
7903: _T("FGETEXP"),
7904: _T("FGETMAN"),
7905: _T("FDIV"), // 0x20
7906: _T("FMOD"),
7907: _T("FADD"),
7908: _T("FMUL"),
7909: _T("FSGLDIV"),
7910: _T("FREM"),
7911: _T("FSCALE"),
7912: _T("FSGLMUL"),
7913: _T("FSUB"),
7914: NULL,
7915: NULL,
7916: NULL,
7917: NULL,
7918: NULL,
7919: NULL,
7920: NULL,
7921: _T("FSINCOS"), // 0x30
7922: _T("FSINCOS"),
7923: _T("FSINCOS"),
7924: _T("FSINCOS"),
7925: _T("FSINCOS"),
7926: _T("FSINCOS"),
7927: _T("FSINCOS"),
7928: _T("FSINCOS"),
7929: _T("FCMP"),
7930: NULL,
7931: _T("FTST"),
7932: NULL,
7933: NULL,
7934: NULL,
7935: NULL,
7936: NULL
7937: };
7938:
7939: static const TCHAR *movemregs[] =
7940: {
7941: _T("D0"),
7942: _T("D1"),
7943: _T("D2"),
7944: _T("D3"),
7945: _T("D4"),
7946: _T("D5"),
7947: _T("D6"),
7948: _T("D7"),
7949: _T("A0"),
7950: _T("A1"),
7951: _T("A2"),
7952: _T("A3"),
7953: _T("A4"),
7954: _T("A5"),
7955: _T("A6"),
7956: _T("A7"),
7957: _T("FP0"),
7958: _T("FP1"),
7959: _T("FP2"),
7960: _T("FP3"),
7961: _T("FP4"),
7962: _T("FP5"),
7963: _T("FP6"),
7964: _T("FP7"),
1.1.1.8 root 7965: _T("FPIAR"),
1.1.1.7 root 7966: _T("FPSR"),
1.1.1.8 root 7967: _T("FPCR")
1.1.1.7 root 7968: };
1.1.1.4 root 7969:
1.1.1.7 root 7970: static void addmovemreg (TCHAR *out, int *prevreg, int *lastreg, int *first, int reg, int fpmode)
1.1.1.4 root 7971: {
7972: TCHAR *p = out + _tcslen (out);
7973: if (*prevreg < 0) {
7974: *prevreg = reg;
7975: *lastreg = reg;
7976: return;
7977: }
1.1.1.7 root 7978: if (reg < 0 || fpmode == 2 || (*prevreg) + 1 != reg || (reg & 8) != ((*prevreg & 8))) {
7979: _stprintf (p, _T("%s%s"), (*first) ? _T("") : _T("/"), movemregs[*lastreg]);
1.1.1.4 root 7980: p = p + _tcslen (p);
1.1.1.8 root 7981: if (*lastreg != *prevreg) {
7982: if ((*lastreg) + 2 == reg) {
7983: _stprintf(p, _T("/%s"), movemregs[*prevreg]);
7984: } else if ((*lastreg) != (*prevreg)) {
7985: _stprintf(p, _T("-%s"), movemregs[*prevreg]);
7986: }
1.1.1.4 root 7987: }
7988: *lastreg = reg;
7989: *first = 0;
7990: }
7991: *prevreg = reg;
7992: }
7993:
1.1.1.10! root 7994: static bool movemout (TCHAR *out, uae_u16 mask, int mode, int fpmode, bool dst)
1.1.1.4 root 7995: {
7996: unsigned int dmask, amask;
7997: int prevreg = -1, lastreg = -1, first = 1;
7998:
1.1.1.7 root 7999: if (mode == Apdi && !fpmode) {
8000: uae_u8 dmask2;
8001: uae_u8 amask2;
8002:
8003: amask2 = mask & 0xff;
8004: dmask2 = (mask >> 8) & 0xff;
1.1.1.4 root 8005: dmask = 0;
8006: amask = 0;
1.1.1.10! root 8007: for (int i = 0; i < 8; i++) {
1.1.1.4 root 8008: if (dmask2 & (1 << i))
8009: dmask |= 1 << (7 - i);
8010: if (amask2 & (1 << i))
8011: amask |= 1 << (7 - i);
8012: }
8013: } else {
8014: dmask = mask & 0xff;
8015: amask = (mask >> 8) & 0xff;
1.1.1.7 root 8016: if (fpmode == 1 && mode != Apdi) {
8017: uae_u8 dmask2 = dmask;
8018: dmask = 0;
1.1.1.10! root 8019: for (int i = 0; i < 8; i++) {
1.1.1.7 root 8020: if (dmask2 & (1 << i))
8021: dmask |= 1 << (7 - i);
8022: }
8023: }
8024: }
1.1.1.10! root 8025: bool dataout = dmask != 0 || amask != 0;
! 8026: if (dst && dataout)
! 8027: _tcscat(out, _T(","));
1.1.1.7 root 8028: if (fpmode) {
8029: while (dmask) { addmovemreg(out, &prevreg, &lastreg, &first, movem_index1[dmask] + (fpmode == 2 ? 24 : 16), fpmode); dmask = movem_next[dmask]; }
8030: } else {
8031: while (dmask) { addmovemreg (out, &prevreg, &lastreg, &first, movem_index1[dmask], fpmode); dmask = movem_next[dmask]; }
8032: while (amask) { addmovemreg (out, &prevreg, &lastreg, &first, movem_index1[amask] + 8, fpmode); amask = movem_next[amask]; }
1.1.1.4 root 8033: }
1.1.1.7 root 8034: addmovemreg(out, &prevreg, &lastreg, &first, -1, fpmode);
1.1.1.10! root 8035: return dataout;
1.1.1.4 root 8036: }
8037:
8038: static void disasm_size (TCHAR *instrname, struct instr *dp)
8039: {
1.1.1.7 root 8040: if (dp->unsized) {
8041: _tcscat(instrname, _T(" "));
8042: return;
1.1.1.4 root 8043: }
8044: switch (dp->size)
8045: {
8046: case sz_byte:
1.1.1.7 root 8047: _tcscat (instrname, _T(".B "));
1.1.1.4 root 8048: break;
8049: case sz_word:
1.1.1.7 root 8050: _tcscat (instrname, _T(".W "));
1.1.1.4 root 8051: break;
8052: case sz_long:
1.1.1.7 root 8053: _tcscat (instrname, _T(".L "));
1.1.1.4 root 8054: break;
8055: default:
1.1.1.7 root 8056: _tcscat (instrname, _T(" "));
1.1.1.4 root 8057: break;
8058: }
8059: }
8060:
1.1.1.9 root 8061: static void asm_add_extensions(uae_u16 *data, int *dcntp, int mode, uae_u32 v, uae_u16 *ext, uaecptr pc, int size)
8062: {
8063: int dcnt = *dcntp;
8064: if (mode < 0)
8065: return;
8066: if (mode == Ad16) {
8067: data[dcnt++] = v;
8068: }
8069: if (mode == PC16) {
8070: data[dcnt++] = v - (pc + 2);
8071: }
8072: if (mode == Ad8r || mode == PC8r) {
8073: data[dcnt++] = ext[0];
8074: }
8075: if (mode == absw) {
8076: data[dcnt++] = (uae_u16)v;
8077: }
8078: if (mode == absl) {
8079: data[dcnt++] = (uae_u16)(v >> 16);
8080: data[dcnt++] = (uae_u16)v;
8081: }
8082: if ((mode == imm && size == 0) || mode == imm0) {
8083: data[dcnt++] = (uae_u8)v;
8084: }
8085: if ((mode == imm && size == 1) || mode == imm1) {
8086: data[dcnt++] = (uae_u16)v;
8087: }
8088: if ((mode == imm && size == 2) || mode == imm2) {
8089: data[dcnt++] = (uae_u16)(v >> 16);
8090: data[dcnt++] = (uae_u16)v;
8091: }
8092: *dcntp = dcnt;
8093: }
8094:
8095: static int asm_isdreg(const TCHAR *s)
8096: {
8097: if (s[0] == 'D' && s[1] >= '0' && s[1] <= '7')
8098: return s[1] - '0';
8099: return -1;
8100: }
8101: static int asm_isareg(const TCHAR *s)
8102: {
8103: if (s[0] == 'A' && s[1] >= '0' && s[1] <= '7')
8104: return s[1] - '0';
1.1.1.10! root 8105: if (s[0] == 'S' && s[1] == 'P')
! 8106: return 7;
1.1.1.9 root 8107: return -1;
8108: }
8109: static int asm_ispc(const TCHAR *s)
8110: {
8111: if (s[0] == 'P' && s[1] == 'C')
8112: return 1;
8113: return 0;
8114: }
8115:
1.1.1.10! root 8116: static uae_u32 asmgetval(const TCHAR *s)
! 8117: {
! 8118: TCHAR *endptr;
! 8119: if (s[0] == '-')
! 8120: return _tcstol(s, &endptr, 16);
! 8121: return _tcstoul(s, &endptr, 16);
! 8122: }
! 8123:
1.1.1.9 root 8124: static int asm_parse_mode(TCHAR *s, uae_u8 *reg, uae_u32 *v, uae_u16 *ext)
8125: {
8126: TCHAR *ss = s;
8127: *reg = -1;
8128: *v = 0;
8129: *ext = 0;
8130: if (s[0] == 0)
8131: return -1;
8132: // Dn
8133: if (asm_isdreg(s) >= 0 && s[2] == 0) {
8134: *reg = asm_isdreg(s);
8135: return Dreg;
8136: }
8137: // An
8138: if (asm_isareg(s) >= 0 && s[2] == 0) {
8139: *reg = asm_isareg(s);
8140: return Areg;
8141: }
8142: // (An) and (An)+
8143: if (s[0] == '(' && asm_isareg(s + 1) >= 0 && s[3] == ')') {
8144: *reg = asm_isareg(s + 1);
8145: if (s[4] == '+' && s[5] == 0)
8146: return Aipi;
8147: if (s[4] == 0)
8148: return Aind;
8149: return -1;
8150: }
8151: // -(An)
8152: if (s[0] == '-' && s[1] == '(' && asm_isareg(s + 2) >= 0 && s[4] == ')' && s[5] == 0) {
8153: *reg = asm_isareg(s + 2);
8154: return Apdi;
8155: }
8156: // Immediate
8157: if (s[0] == '#') {
8158: if (s[1] == '!') {
8159: *v = _tstol(s + 2);
8160: } else {
1.1.1.10! root 8161: *v = asmgetval(s + 1);
1.1.1.9 root 8162: }
8163: return imm;
8164: }
8165: // Value
8166: if (s[0] == '!') {
8167: *v = _tstol(s + 1);
8168: } else {
1.1.1.10! root 8169: *v = asmgetval(s);
1.1.1.9 root 8170: }
8171: int dots = 0;
8172: unsigned int i;
8173: for (i = 0; i < _tcslen(s); i++) {
8174: if (s[i] == ',')
8175: dots++;
8176: }
8177: while (*s != 0) {
8178: // d16(An)
8179: if (dots == 0 && s[0] == '(' && asm_isareg(s + 1) >= 0 && s[3] == ')' && s[4] == 0) {
8180: *reg = asm_isareg(s + 1);
8181: return Ad16;
8182: }
8183: // d16(PC)
8184: if (dots == 0 && s[0] == '(' && asm_ispc(s + 1) && s[3] == ')' && s[4] == 0) {
8185: *reg = 2;
8186: return PC16;
8187: }
8188: // (d16,An) / (d16,PC)
8189: if (dots == 1 && s[0] == '(' && !asm_ispc(s + 1) && asm_isareg(s + 1) < 0 && asm_isdreg(s + 1) < 0) {
8190: TCHAR *startptr, *endptr;
8191: if (s[1] == '!') {
8192: startptr = s + 2;
8193: *v = _tcstol(startptr, &endptr, 10);
8194: } else {
8195: startptr = s + 1;
8196: *v = _tcstol(startptr, &endptr, 16);
8197: }
8198: if (endptr == startptr || endptr[0] != ',')
8199: return -1;
8200: if (asm_ispc(endptr + 1) && endptr[3] == ')') {
8201: *reg = 2;
8202: return PC16;
8203: }
8204: if (asm_isareg(endptr + 1) >= 0 && endptr[3] == ')') {
8205: *reg = asm_isareg(endptr + 1);
8206: return Ad16;
8207: }
8208: return -1;
8209: }
8210: // Ad8r PC8r
8211: if (s[0] == '(') {
8212: TCHAR *s2 = s;
8213: if (!asm_ispc(s + 1) && asm_isareg(s + 1) < 0 && asm_isdreg(s + 1) < 0) {
8214: if (dots != 2)
8215: return -1;
8216: TCHAR *startptr, *endptr;
8217: if (s[1] == '!') {
8218: startptr = s + 2;
8219: *v = _tcstol(startptr, &endptr, 10);
8220: } else {
8221: startptr = s + 1;
8222: *v = _tcstol(startptr, &endptr, 16);
8223: }
8224: if (endptr == startptr || endptr[0] != ',')
8225: return -1;
8226: s2 = endptr + 1;
8227: } else if (((asm_isareg(s + 1) >= 0 || asm_ispc(s + 1)) && s[3] == ',') || (asm_isdreg(s + 4) >= 0 || asm_isareg(s + 4) >= 0)) {
8228: if (dots != 1)
8229: return -1;
8230: s2 = s + 1;
8231: } else {
8232: return -1;
8233: }
8234: uae_u8 reg2;
8235: bool ispc = asm_ispc(s2);
8236: if (ispc) {
8237: *reg = 3;
8238: } else {
8239: *reg = asm_isareg(s2);
8240: }
8241: s2 += 2;
8242: if (*s2 != ',')
8243: return -1;
8244: s2++;
8245: if (asm_isdreg(s2) >= 0) {
8246: reg2 = asm_isdreg(s2);
8247: } else {
8248: reg2 = asm_isareg(s2);
8249: *ext |= 1 << 15;
8250: }
8251: s2 += 2;
8252: *ext |= reg2 << 12;
8253: *ext |= (*v) & 0xff;
8254: if (s2[0] == '.' && s2[1] == 'W') {
8255: s2 += 2;
8256: } else if (s2[0] == '.' && s2[1] == 'L') {
8257: *ext |= 1 << 11;
8258: s2 += 2;
8259: }
8260: if (s2[0] == '*') {
8261: TCHAR scale = s2[1];
8262: if (scale == '2')
8263: *ext |= 1 << 9;
8264: else if (scale == '4')
8265: *ext |= 2 << 9;
8266: else if (scale == '8')
8267: *ext |= 3 << 9;
8268: else
8269: return -1;
8270: s2 += 2;
8271: }
8272: if (s2[0] == ')' && s2[1] == 0) {
8273: return ispc ? PC8r : Ad8r;
8274: }
8275: return -1;
8276: }
8277: s++;
8278: }
8279: // abs.w
8280: if (s - ss > 2 && s[-2] == '.' && s[-1] == 'W') {
8281: *reg = 0;
8282: return absw;
8283: }
8284: // abs.l
8285: *reg = 1;
8286: return absl;
8287: }
8288:
8289: static TCHAR *asm_parse_parm(TCHAR *parm, TCHAR *out)
8290: {
8291: TCHAR *p = parm;
8292: bool quote = false;
8293:
8294: for (;;) {
8295: if (*p == '(') {
8296: quote = true;
8297: }
8298: if (*p == ')') {
8299: if (!quote)
8300: return NULL;
8301: quote = false;
8302: }
8303: if ((*p == ',' || *p == 0) && !quote) {
8304: TCHAR c = *p;
8305: p[0] = 0;
8306: _tcscpy(out, parm);
8307: my_trim(out);
8308: if (c)
8309: p++;
8310: return p;
8311: }
8312: p++;
8313: }
8314: }
8315:
8316: static bool m68k_asm_parse_movec(TCHAR *s, TCHAR *d)
8317: {
1.1.1.10! root 8318: for (int i = 0; m2cregs[i].regname; i++) {
1.1.1.9 root 8319: if (!_tcscmp(s, m2cregs[i].regname)) {
8320: uae_u16 v = m2cregs[i].regno;
8321: if (asm_isareg(d) >= 0)
8322: v |= 0x8000 | (asm_isareg(d) << 12);
8323: else if (asm_isdreg(d) >= 0)
8324: v |= (asm_isdreg(d) << 12);
8325: else
8326: return false;
8327: _stprintf(s, _T("#%X"), v);
8328: return true;
8329: }
8330: }
8331: return false;
8332: }
8333:
8334: static bool m68k_asm_parse_movem(TCHAR *s, int dir)
8335: {
8336: TCHAR *d = s;
8337: uae_u16 regmask = 0;
8338: uae_u16 mask = dir ? 0x8000 : 0x0001;
8339: bool ret = false;
8340: while(*s) {
8341: int dreg = asm_isdreg(s);
8342: int areg = asm_isareg(s);
8343: if (dreg < 0 && areg < 0)
8344: break;
8345: int reg = dreg >= 0 ? dreg : areg + 8;
8346: regmask |= dir ? (mask >> reg) : (mask << reg);
8347: s += 2;
8348: if (*s == 0) {
8349: ret = true;
8350: break;
8351: } else if (*s == '/') {
8352: s++;
8353: continue;
8354: } else if (*s == '-') {
8355: s++;
8356: int dreg2 = asm_isdreg(s);
8357: int areg2 = asm_isareg(s);
8358: if (dreg2 < 0 && areg2 < 0)
8359: break;
8360: int reg2 = dreg2 >= 0 ? dreg2 : areg2 + 8;
8361: if (reg2 < reg)
8362: break;
8363: while (reg2 >= reg) {
8364: regmask |= dir ? (mask >> reg) : (mask << reg);
8365: reg++;
8366: }
8367: s += 2;
8368: if (*s == 0) {
8369: ret = true;
8370: break;
8371: }
8372: } else {
8373: break;
8374: }
8375: }
8376: if (ret)
8377: _stprintf(d, _T("#%X"), regmask);
8378: return ret;
8379: }
8380:
8381: int m68k_asm(TCHAR *sline, uae_u16 *out, uaecptr pc)
8382: {
8383: TCHAR *p;
8384: const TCHAR *cp1;
8385: TCHAR ins[256], parms[256];
8386: TCHAR line[256];
8387: TCHAR srcea[256], dstea[256];
8388: uae_u16 data[16], sexts[8], dexts[8];
8389: int dcnt = 0;
8390: int cc = -1;
8391: int quick = 0;
8392: bool immrelpc = false;
8393:
8394: if (_tcslen(sline) > 100)
8395: return -1;
8396:
8397: srcea[0] = dstea[0] = 0;
8398: parms[0] = 0;
8399:
8400: // strip all white space except first space
8401: p = line;
8402: bool firstsp = true;
1.1.1.10! root 8403: for (int i = 0; sline[i]; i++) {
1.1.1.9 root 8404: TCHAR c = sline[i];
8405: if (c == 32 && firstsp) {
8406: firstsp = false;
8407: *p++ = 32;
8408: }
8409: if (c <= 32)
8410: continue;
8411: *p++ = c;
8412: }
8413: *p = 0;
8414:
8415: to_upper(line, _tcslen(line));
8416:
8417: p = line;
8418: while (*p && *p != ' ')
8419: p++;
8420: if (*p == ' ') {
8421: *p = 0;
8422: _tcscpy(parms, p + 1);
8423: my_trim(parms);
8424: }
8425: _tcscpy(ins, line);
8426:
8427: if (_tcslen(ins) == 0)
8428: return 0;
8429:
8430: int size = 1;
8431: int inssize = -1;
8432: cp1 = _tcschr(line, '.');
8433: if (cp1) {
8434: size = cp1[1];
8435: if (size == 'W')
8436: size = 1;
8437: else if (size == 'L')
8438: size = 2;
8439: else if (size == 'B')
8440: size = 0;
8441: else
8442: return 0;
8443: inssize = size;
8444: line[cp1 - line] = 0;
8445: _tcscpy(ins, line);
8446: }
8447:
8448: TCHAR *parmp = parms;
8449: parmp = asm_parse_parm(parmp, srcea);
8450: if (!parmp)
8451: return 0;
8452: if (srcea[0]) {
8453: parmp = asm_parse_parm(parmp, dstea);
8454: if (!parmp)
8455: return 0;
8456: }
8457:
8458: int smode = -1;
8459: int dmode = -1;
8460: uae_u8 sreg = -1;
8461: uae_u8 dreg = -1;
8462: uae_u32 sval = 0;
8463: uae_u32 dval = 0;
8464: int ssize = -1;
8465: int dsize = -1;
8466:
8467: dmode = asm_parse_mode(dstea, &dreg, &dval, dexts);
8468:
8469:
8470: // Common alias
8471: if (!_tcscmp(ins, _T("BRA"))) {
8472: _tcscpy(ins, _T("BT"));
8473: } else if (!_tcscmp(ins, _T("BSR"))) {
8474: immrelpc = true;
8475: } else if (!_tcscmp(ins, _T("MOVEM"))) {
8476: if (dmode >= Aind && _tcschr(dstea, '-') == NULL && _tcschr(dstea, '/') == NULL) {
8477: _tcscpy(ins, _T("MVMLE"));
8478: if (!m68k_asm_parse_movem(srcea, dmode == Apdi))
8479: return -1;
8480: } else {
8481: TCHAR tmp[256];
8482: _tcscpy(ins, _T("MVMEL"));
8483: _tcscpy(tmp, srcea);
8484: _tcscpy(srcea, dstea);
8485: _tcscpy(dstea, tmp);
8486: if (!m68k_asm_parse_movem(srcea, 0))
8487: return -1;
8488: dmode = asm_parse_mode(dstea, &dreg, &dval, dexts);
8489: }
8490: } else if (!_tcscmp(ins, _T("MOVEC"))) {
8491: if (dmode == Dreg || dmode == Areg) {
8492: _tcscpy(ins, _T("MOVEC2"));
8493: if (!m68k_asm_parse_movec(srcea, dstea))
8494: return -1;
8495: } else {
8496: TCHAR tmp[256];
8497: _tcscpy(ins, _T("MOVE2C"));
8498: _tcscpy(tmp, srcea);
8499: _tcscpy(srcea, dstea);
8500: dstea[0] = 0;
8501: if (!m68k_asm_parse_movec(srcea, tmp))
8502: return -1;
8503: }
8504: dmode = -1;
8505: }
8506:
8507: if (dmode == Areg) {
8508: int l = _tcslen(ins);
8509: if (l <= 2)
8510: return -1;
8511: TCHAR last = ins[l- 1];
8512: if (last == 'Q') {
8513: last = ins[l - 2];
8514: if (last != 'A') {
8515: ins[l - 1] = 'A';
8516: ins[l] = 'Q';
8517: ins[l + 1] = 0;
8518: }
8519: } else if (last != 'A') {
8520: _tcscat(ins, _T("A"));
8521: }
8522: }
8523:
1.1.1.10! root 8524: bool fp = ins[0] == 'F';
! 8525:
! 8526: if (ins[_tcslen(ins) - 1] == 'Q' && _tcslen(ins) > 3 && !fp) {
1.1.1.9 root 8527: quick = 1;
8528: ins[_tcslen(ins) - 1] = 0;
8529: }
8530:
8531: struct mnemolookup *lookup;
8532: for (lookup = lookuptab; lookup->name; lookup++) {
8533: if (!_tcscmp(ins, lookup->name))
8534: break;
8535: }
8536: if (!lookup->name) {
8537: // Check cc variants
8538: for (lookup = lookuptab; lookup->name; lookup++) {
8539: const TCHAR *ccp = _tcsstr(lookup->name, _T("cc"));
8540: if (ccp) {
8541: TCHAR tmp[256];
1.1.1.10! root 8542: for (int i = 0; i < (fp ? 32 : 16); i++) {
1.1.1.9 root 8543: const TCHAR *ccname = fp ? fpccnames[i] : ccnames[i];
8544: _tcscpy(tmp, lookup->name);
8545: _tcscpy(tmp + (ccp - lookup->name), ccname);
8546: if (tmp[_tcslen(tmp) - 1] == ' ')
8547: tmp[_tcslen(tmp) - 1] = 0;
8548: if (!_tcscmp(tmp, ins)) {
8549: _tcscpy(ins, lookup->name);
8550: cc = i;
1.1.1.10! root 8551: if (lookup->mnemo == i_DBcc || lookup->mnemo == i_Bcc) {
! 8552: // Bcc.B uses same encoding mode as MOVEQ
! 8553: immrelpc = true;
! 8554: }
1.1.1.9 root 8555: if (size == 0) {
8556: quick = 2;
8557: }
8558: break;
8559: }
8560: }
8561: }
8562: if (cc >= 0)
8563: break;
8564: }
8565: }
8566:
8567: if (!lookup->name)
8568: return 0;
8569:
8570: int mnemo = lookup->mnemo;
8571:
8572: int found = 0;
8573: int sizemask = 0;
8574: int tsize = size;
8575: int unsized = 0;
8576:
1.1.1.10! root 8577: for (int round = 0; round < 9; round++) {
1.1.1.9 root 8578:
8579: if (!found && round == 8)
8580: return 0;
8581:
8582: if (round == 3) {
8583: // Q is always LONG sized
8584: if (quick == 1) {
8585: tsize = 2;
8586: }
8587: bool isimm = srcea[0] == '#';
8588: if (immrelpc && !isimm) {
8589: TCHAR tmp[256];
8590: _tcscpy(tmp, srcea);
8591: srcea[0] = '#';
8592: _tcscpy(srcea + 1, tmp);
8593: }
8594: smode = asm_parse_mode(srcea, &sreg, &sval, sexts);
8595: if (immrelpc && !isimm) {
8596: sval = sval - (pc + 2);
8597: }
8598: if (quick) {
8599: smode = immi;
8600: sreg = sval & 0xff;
8601: }
8602: }
8603:
8604: if (round == 1) {
8605: if (!quick && (sizemask == 1 || sizemask == 2 || sizemask == 4)) {
8606: tsize = 0;
8607: if (sizemask == 2)
8608: tsize = 1;
8609: else if (sizemask == 4)
8610: tsize = 2;
8611: } else {
8612: continue;
8613: }
8614: }
8615: if (round == 2 && !found) {
8616: unsized = 1;
8617: }
8618:
8619: if (round == 4 && smode == imm) {
8620: smode = imm0;
8621: } else if (round == 5 && smode == imm0) {
8622: smode = imm1;
8623: } else if (round == 6 && smode == imm1) {
8624: smode = imm2;
8625: } else if (round == 7 && smode == imm2) {
8626: smode = immi;
8627: sreg = sval & 0xff;
8628: } else if (round == 4) {
8629: round += 5 - 1;
8630: }
8631:
1.1.1.10! root 8632: for (int opcode = 0; opcode < 65536; opcode++) {
1.1.1.9 root 8633: struct instr *table = &table68k[opcode];
8634: if (table->mnemo != mnemo)
8635: continue;
8636: if (cc >= 0 && table->cc != cc)
8637: continue;
8638:
8639: #if 0
8640: if (round == 0) {
8641: console_out_f(_T("%s OP=%04x S=%d SR=%d SM=%d SU=%d SP=%d DR=%d DM=%d DU=%d DP=%d SDU=%d\n"), lookup->name, opcode, table->size,
8642: table->sreg, table->smode, table->suse, table->spos,
8643: table->dreg, table->dmode, table->duse, table->dpos,
8644: table->sduse);
8645: }
8646: #endif
8647:
8648: if (table->duse && !(table->dmode == dmode || (dmode >= imm && dmode <= imm2 && table->dmode >= imm && table->dmode <= imm2)))
8649: continue;
8650: if (round == 0) {
8651: sizemask |= 1 << table->size;
8652: }
8653: if (unsized > 0 && !table->unsized) {
8654: continue;
8655: }
8656:
8657: found++;
8658:
8659: if (round >= 3) {
8660:
8661: if (
8662: ((table->size == tsize || table->unsized)) &&
8663: ((!table->suse && smode < 0) || (table->suse && table->smode == smode)) &&
8664: ((!table->duse && dmode < 0) || (table->duse && (table->dmode == dmode || (dmode == imm && (table->dmode >= imm && table->dmode <= imm2))))) &&
8665: ((table->sreg == sreg || (table->smode >= absw && table->smode != immi))) &&
8666: ((table->dreg == dreg || table->dmode >= absw))
8667: )
8668: {
8669: if (inssize >= 0 && tsize != inssize)
8670: continue;
8671:
8672:
8673: data[dcnt++] = opcode;
8674: asm_add_extensions(data, &dcnt, smode, sval, sexts, pc, tsize);
8675: if (smode >= 0)
8676: asm_add_extensions(data, &dcnt, dmode, dval, dexts, pc, tsize);
1.1.1.10! root 8677: for (int i = 0; i < dcnt; i++) {
1.1.1.9 root 8678: out[i] = data[i];
8679: }
8680: return dcnt;
8681: }
8682:
8683: }
8684: }
8685: }
8686:
8687: return 0;
8688: }
8689:
1.1.1.10! root 8690: static void resolve_if_jmp(TCHAR *s, uae_u32 addr)
! 8691: {
! 8692: uae_u16 opcode = get_word_debug(addr);
! 8693: if (opcode == 0x4ef9) { // JMP x.l
! 8694: TCHAR *p = s + _tcslen(s);
! 8695: uae_u32 addr2 = get_long_debug(addr + 2);
! 8696: _stprintf(p, _T(" == $%08x "), addr2);
! 8697: showea_val(p + _tcslen(p), opcode, addr2, 4);
! 8698: TCHAR txt[256];
! 8699: bool ext;
! 8700: if (debugmem_get_segment(addr2, NULL, &ext, NULL, txt)) {
! 8701: if (ext) {
! 8702: _tcscat(p, _T(" "));
! 8703: _tcscat(p, txt);
! 8704: }
! 8705: }
! 8706: }
! 8707: }
! 8708:
! 8709:
! 8710: void m68k_disasm_2 (TCHAR *buf, int bufsize, uaecptr pc, uaecptr *nextpc, int cnt, uae_u32 *seaddr, uae_u32 *deaddr, uaecptr lastpc, int safemode)
1.1.1.4 root 8711: {
1.1.1.7 root 8712: uae_u32 seaddr2;
8713: uae_u32 deaddr2;
1.1.1.4 root 8714:
8715: if (!table68k)
8716: return;
8717: while (cnt-- > 0) {
1.1.1.10! root 8718: TCHAR instrname[256], *ccpt;
! 8719: TCHAR segout[256], segname[256];
1.1.1.4 root 8720: int i;
8721: uae_u32 opcode;
1.1.1.7 root 8722: uae_u16 extra;
1.1.1.4 root 8723: struct mnemolookup *lookup;
8724: struct instr *dp;
1.1.1.7 root 8725: uaecptr oldpc;
8726: uaecptr m68kpc_illg = 0;
8727: bool illegal = false;
1.1.1.10! root 8728: int segid, lastsegid;
! 8729: TCHAR *symbolpos;
1.1.1.7 root 8730:
8731: seaddr2 = deaddr2 = 0;
8732: oldpc = pc;
8733: opcode = get_word_debug (pc);
8734: extra = get_word_debug (pc + 2);
8735: if (cpufunctbl[opcode] == op_illg_1 || cpufunctbl[opcode] == op_unimpl_1) {
8736: m68kpc_illg = pc + 2;
8737: illegal = TRUE;
8738: }
1.1.1.4 root 8739:
1.1.1.7 root 8740: dp = table68k + opcode;
8741: if (dp->mnemo == i_ILLG) {
8742: illegal = FALSE;
1.1.1.4 root 8743: opcode = 0x4AFC;
1.1.1.7 root 8744: dp = table68k + opcode;
1.1.1.4 root 8745: }
8746: for (lookup = lookuptab;lookup->mnemo != dp->mnemo; lookup++)
8747: ;
8748:
1.1.1.10! root 8749: lastsegid = -1;
! 8750: bool exact = false;
! 8751: if (lastpc != 0xffffffff) {
! 8752: lastsegid = debugmem_get_segment(lastpc, NULL, NULL, NULL, NULL);
! 8753: }
! 8754: segid = debugmem_get_segment(pc, &exact, NULL, segout, segname);
! 8755: if (segid && (lastsegid != -1 || exact) && (segid != lastsegid || pc == lastpc || exact)) {
! 8756: buf = buf_out(buf, &bufsize, _T("%s\n"), segname);
! 8757: }
! 8758: symbolpos = buf;
! 8759:
1.1.1.7 root 8760: buf = buf_out (buf, &bufsize, _T("%08X "), pc);
1.1.1.4 root 8761:
1.1.1.10! root 8762: if (segid) {
! 8763: buf = buf_out(buf, &bufsize, _T("%s "), segout);
! 8764: }
! 8765:
1.1.1.7 root 8766: pc += 2;
8767:
8768: if (lookup->friendlyname)
1.1.1.4 root 8769: _tcscpy (instrname, lookup->friendlyname);
8770: else
8771: _tcscpy (instrname, lookup->name);
1.1.1.7 root 8772: ccpt = _tcsstr (instrname, _T("cc"));
1.1.1.4 root 8773: if (ccpt != 0) {
1.1.1.7 root 8774: if ((opcode & 0xf000) == 0xf000)
8775: _tcscpy (ccpt, fpccnames[extra & 0x1f]);
8776: else
8777: _tcsncpy (ccpt, ccnames[dp->cc], 2);
1.1.1.4 root 8778: }
8779: disasm_size (instrname, dp);
8780:
8781: if (lookup->mnemo == i_MOVEC2 || lookup->mnemo == i_MOVE2C) {
1.1.1.7 root 8782: uae_u16 imm = extra;
1.1.1.4 root 8783: uae_u16 creg = imm & 0x0fff;
8784: uae_u16 r = imm >> 12;
8785: TCHAR regs[16];
1.1.1.7 root 8786: const TCHAR *cname = _T("?");
1.1.1.10! root 8787: int j;
! 8788: for (j = 0; m2cregs[j].regname; j++) {
! 8789: if (m2cregs[j].regno == creg)
1.1.1.4 root 8790: break;
8791: }
1.1.1.7 root 8792: _stprintf (regs, _T("%c%d"), r >= 8 ? 'A' : 'D', r >= 8 ? r - 8 : r);
1.1.1.10! root 8793: if (m2cregs[j].regname)
! 8794: cname = m2cregs[j].regname;
1.1.1.4 root 8795: if (lookup->mnemo == i_MOVE2C) {
8796: _tcscat (instrname, regs);
1.1.1.7 root 8797: _tcscat (instrname, _T(","));
1.1.1.4 root 8798: _tcscat (instrname, cname);
8799: } else {
8800: _tcscat (instrname, cname);
1.1.1.7 root 8801: _tcscat (instrname, _T(","));
1.1.1.4 root 8802: _tcscat (instrname, regs);
8803: }
1.1.1.7 root 8804: pc += 2;
1.1.1.4 root 8805: } else if (lookup->mnemo == i_MVMEL) {
1.1.1.7 root 8806: uae_u16 mask = extra;
8807: pc += 2;
8808: pc = ShowEA (0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, deaddr, safemode);
1.1.1.10! root 8809: movemout (instrname, mask, dp->dmode, 0, true);
1.1.1.4 root 8810: } else if (lookup->mnemo == i_MVMLE) {
1.1.1.7 root 8811: uae_u16 mask = extra;
8812: pc += 2;
1.1.1.10! root 8813: if (movemout(instrname, mask, dp->dmode, 0, false))
! 8814: _tcscat(instrname, _T(","));
1.1.1.7 root 8815: pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, deaddr, safemode);
8816: } else if (lookup->mnemo == i_DIVL || lookup->mnemo == i_MULL) {
8817: TCHAR *p;
8818: pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &seaddr2, safemode);
8819: extra = get_word_debug(pc);
8820: pc += 2;
8821: p = instrname + _tcslen(instrname);
8822: if (extra & 0x0400)
8823: _stprintf(p, _T(",D%d:D%d"), extra & 7, (extra >> 12) & 7);
8824: else
8825: _stprintf(p, _T(",D%d"), (extra >> 12) & 7);
8826: } else if (lookup->mnemo == i_MOVES) {
8827: TCHAR *p;
8828: pc += 2;
1.1.1.9 root 8829: if (!(extra & 0x0800)) {
1.1.1.7 root 8830: pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &seaddr2, safemode);
8831: p = instrname + _tcslen(instrname);
8832: _stprintf(p, _T(",%c%d"), (extra & 0x8000) ? 'A' : 'D', (extra >> 12) & 7);
8833: } else {
8834: p = instrname + _tcslen(instrname);
8835: _stprintf(p, _T("%c%d,"), (extra & 0x8000) ? 'A' : 'D', (extra >> 12) & 7);
8836: pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &seaddr2, safemode);
8837: }
8838: } else if (lookup->mnemo == i_BFEXTS || lookup->mnemo == i_BFEXTU ||
8839: lookup->mnemo == i_BFCHG || lookup->mnemo == i_BFCLR ||
8840: lookup->mnemo == i_BFFFO || lookup->mnemo == i_BFINS ||
8841: lookup->mnemo == i_BFSET || lookup->mnemo == i_BFTST) {
8842: TCHAR *p;
8843: int reg = -1;
8844:
8845: pc += 2;
8846: p = instrname + _tcslen(instrname);
8847: if (lookup->mnemo == i_BFEXTS || lookup->mnemo == i_BFEXTU || lookup->mnemo == i_BFFFO || lookup->mnemo == i_BFINS)
8848: reg = (extra >> 12) & 7;
8849: if (lookup->mnemo == i_BFINS)
8850: _stprintf(p, _T("D%d,"), reg);
8851: pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &seaddr2, safemode);
8852: _tcscat(instrname, _T(" {"));
8853: p = instrname + _tcslen(instrname);
8854: if (extra & 0x0800)
8855: _stprintf(p, _T("D%d"), (extra >> 6) & 7);
8856: else
8857: _stprintf(p, _T("%d"), (extra >> 6) & 31);
8858: _tcscat(instrname, _T(":"));
8859: p = instrname + _tcslen(instrname);
8860: if (extra & 0x0020)
8861: _stprintf(p, _T("D%d"), extra & 7);
8862: else
8863: _stprintf(p, _T("%d"), extra & 31);
8864: _tcscat(instrname, _T("}"));
8865: p = instrname + _tcslen(instrname);
8866: if (lookup->mnemo == i_BFFFO || lookup->mnemo == i_BFEXTS || lookup->mnemo == i_BFEXTU)
8867: _stprintf(p, _T(",D%d"), reg);
8868: } else if (lookup->mnemo == i_CPUSHA || lookup->mnemo == i_CPUSHL || lookup->mnemo == i_CPUSHP ||
8869: lookup->mnemo == i_CINVA || lookup->mnemo == i_CINVL || lookup->mnemo == i_CINVP) {
8870: if ((opcode & 0xc0) == 0xc0)
8871: _tcscat(instrname, _T("BC"));
8872: else if (opcode & 0x80)
8873: _tcscat(instrname, _T("IC"));
8874: else if (opcode & 0x40)
8875: _tcscat(instrname, _T("DC"));
8876: else
8877: _tcscat(instrname, _T("?"));
8878: if (lookup->mnemo == i_CPUSHL || lookup->mnemo == i_CPUSHP || lookup->mnemo == i_CINVL || lookup->mnemo == i_CINVP) {
8879: TCHAR *p = instrname + _tcslen(instrname);
8880: _stprintf(p, _T(",(A%d)"), opcode & 7);
8881: }
1.1.1.10! root 8882: } else if (lookup->mnemo == i_MOVE16) {
! 8883: TCHAR *p = instrname + _tcslen(instrname);
! 8884: if (opcode & 0x20) {
! 8885: _stprintf(p, _T("(A%d)+,(A%d)+"), opcode & 7, (extra >> 12) & 7);
! 8886: pc += 2;
! 8887: } else {
! 8888: uae_u32 addr = get_long_debug(pc + 2);
! 8889: int ay = opcode & 7;
! 8890: pc += 4;
! 8891: switch ((opcode >> 3) & 3)
! 8892: {
! 8893: case 0:
! 8894: _stprintf(p, _T("(A%d)+,$%08x"), ay, addr);
! 8895: break;
! 8896: case 1:
! 8897: _stprintf(p, _T("$%08x,(A%d)+"), addr, ay);
! 8898: break;
! 8899: case 2:
! 8900: _stprintf(p, _T("(A%d),$%08x"), ay, addr);
! 8901: break;
! 8902: case 3:
! 8903: _stprintf(p, _T("$%08x,(A%d)"), addr, ay);
! 8904: break;
! 8905: }
! 8906: }
1.1.1.7 root 8907: } else if (lookup->mnemo == i_FPP) {
8908: TCHAR *p;
8909: int ins = extra & 0x3f;
8910: int size = (extra >> 10) & 7;
8911:
8912: pc += 2;
8913: if ((extra & 0xfc00) == 0x5c00) { // FMOVECR (=i_FPP with source specifier = 7)
8914: fpdata fp;
1.1.1.9 root 8915: fpu_get_constant(&fp, extra);
8916: _stprintf(instrname, _T("FMOVECR.X #0x%02x [%s],FP%d"), extra & 0x7f, fpp_print(&fp, 0), (extra >> 7) & 7);
1.1.1.7 root 8917: } else if ((extra & 0x8000) == 0x8000) { // FMOVEM
8918: int dr = (extra >> 13) & 1;
8919: int mode;
8920: int dreg = (extra >> 4) & 7;
8921: int regmask, fpmode;
8922:
8923: if (extra & 0x4000) {
8924: mode = (extra >> 11) & 3;
8925: regmask = extra & 0xff; // FMOVEM FPx
8926: fpmode = 1;
8927: _tcscpy(instrname, _T("FMOVEM.X "));
8928: } else {
8929: mode = 0;
8930: regmask = (extra >> 10) & 7; // FMOVEM control
8931: fpmode = 2;
8932: _tcscpy(instrname, _T("FMOVEM.L "));
8933: if (regmask == 1 || regmask == 2 || regmask == 4)
8934: _tcscpy(instrname, _T("FMOVE.L "));
8935: }
8936: p = instrname + _tcslen(instrname);
8937: if (dr) {
8938: if (mode & 1)
8939: _stprintf(instrname, _T("D%d"), dreg);
8940: else
1.1.1.10! root 8941: movemout(instrname, regmask, dp->dmode, fpmode, false);
1.1.1.7 root 8942: _tcscat(instrname, _T(","));
8943: pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, deaddr, safemode);
8944: } else {
8945: pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, deaddr, safemode);
8946: p = instrname + _tcslen(instrname);
8947: if (mode & 1)
1.1.1.10! root 8948: _stprintf(p, _T(",D%d"), dreg);
1.1.1.7 root 8949: else
1.1.1.10! root 8950: movemout(p, regmask, dp->dmode, fpmode, true);
1.1.1.7 root 8951: }
8952: } else {
8953: if (fpuopcodes[ins])
8954: _tcscpy(instrname, fpuopcodes[ins]);
8955: else
8956: _tcscpy(instrname, _T("F?"));
8957:
8958: if ((extra & 0xe000) == 0x6000) { // FMOVE to memory
8959: int kfactor = extra & 0x7f;
8960: _tcscpy(instrname, _T("FMOVE."));
8961: _tcscat(instrname, fpsizes[size]);
8962: _tcscat(instrname, _T(" "));
8963: p = instrname + _tcslen(instrname);
8964: _stprintf(p, _T("FP%d,"), (extra >> 7) & 7);
8965: pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, fpsizeconv[size], instrname, &deaddr2, safemode);
8966: p = instrname + _tcslen(instrname);
8967: if (size == 7) {
8968: _stprintf(p, _T(" {D%d}"), (kfactor >> 4));
8969: } else if (kfactor) {
8970: if (kfactor & 0x40)
8971: kfactor |= ~0x3f;
8972: _stprintf(p, _T(" {%d}"), kfactor);
8973: }
8974: } else {
8975: if (extra & 0x4000) { // source is EA
8976: _tcscat(instrname, _T("."));
8977: _tcscat(instrname, fpsizes[size]);
8978: _tcscat(instrname, _T(" "));
8979: pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, fpsizeconv[size], instrname, &seaddr2, safemode);
8980: } else { // source is FPx
8981: p = instrname + _tcslen(instrname);
8982: _stprintf(p, _T(".X FP%d"), (extra >> 10) & 7);
8983: }
8984: p = instrname + _tcslen(instrname);
8985: if ((extra & 0x4000) || (((extra >> 7) & 7) != ((extra >> 10) & 7)))
8986: _stprintf(p, _T(",FP%d"), (extra >> 7) & 7);
8987: if (ins >= 0x30 && ins < 0x38) { // FSINCOS
8988: p = instrname + _tcslen(instrname);
8989: _stprintf(p, _T(",FP%d"), extra & 7);
8990: }
8991: }
8992: }
8993: } else if ((opcode & 0xf000) == 0xa000) {
8994: _tcscpy(instrname, _T("A-LINE"));
1.1.1.4 root 8995: } else {
8996: if (dp->suse) {
1.1.1.7 root 8997: pc = ShowEA (0, pc, opcode, dp->sreg, dp->smode, dp->size, instrname, &seaddr2, safemode);
1.1.1.10! root 8998:
! 8999: // JSR x(a6) / JMP x(a6)
! 9000: if (opcode == 0x4ea8 + 6 || opcode == 0x4ee8 + 6) {
! 9001: TCHAR sname[256];
! 9002: if (debugger_get_library_symbol(m68k_areg(regs, 6), 0xffff0000 | extra, sname)) {
! 9003: TCHAR *p = instrname + _tcslen(instrname);
! 9004: _stprintf(p, _T(" %s"), sname);
! 9005: resolve_if_jmp(instrname, m68k_areg(regs, 6) + (uae_s16)extra);
! 9006: }
! 9007: }
! 9008: // show target address if JSR x(pc) + JMP xxxx combination
! 9009: if (opcode == 0x4eba && seaddr2 && instrname[0]) { // JSR x(pc)
! 9010: resolve_if_jmp(instrname, seaddr2);
! 9011: }
1.1.1.4 root 9012: }
9013: if (dp->suse && dp->duse)
1.1.1.7 root 9014: _tcscat (instrname, _T(","));
1.1.1.4 root 9015: if (dp->duse) {
1.1.1.7 root 9016: pc = ShowEA (0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &deaddr2, safemode);
1.1.1.4 root 9017: }
9018: }
9019:
1.1.1.7 root 9020: for (i = 0; i < (int)(pc - oldpc) / 2 && i < 5; i++) {
9021: buf = buf_out (buf, &bufsize, _T("%04x "), get_word_debug (oldpc + i * 2));
1.1.1.4 root 9022: }
9023: while (i++ < 5)
1.1.1.7 root 9024: buf = buf_out (buf, &bufsize, _T(" "));
1.1.1.4 root 9025:
1.1.1.7 root 9026: if (illegal)
9027: buf = buf_out (buf, &bufsize, _T("[ "));
9028: buf = buf_out (buf, &bufsize, instrname);
9029: if (illegal)
9030: buf = buf_out (buf, &bufsize, _T(" ]"));
1.1.1.4 root 9031:
9032: if (ccpt != 0) {
1.1.1.7 root 9033: uaecptr addr2 = deaddr2 ? deaddr2 : seaddr2;
1.1.1.4 root 9034: if (deaddr)
1.1.1.7 root 9035: *deaddr = pc;
9036: if ((opcode & 0xf000) == 0xf000) {
9037: if (fpp_cond(dp->cc)) {
9038: buf = buf_out(buf, &bufsize, _T(" == $%08x (T)"), addr2);
9039: } else {
9040: buf = buf_out(buf, &bufsize, _T(" == $%08x (F)"), addr2);
9041: }
9042: } else {
1.1.1.10! root 9043: if (dp->mnemo == i_Bcc || dp->mnemo == i_DBcc) {
! 9044: if (cctrue(dp->cc)) {
! 9045: buf = buf_out(buf, &bufsize, _T(" == $%08x (T)"), addr2);
! 9046: } else {
! 9047: buf = buf_out(buf, &bufsize, _T(" == $%08x (F)"), addr2);
! 9048: }
1.1.1.7 root 9049: } else {
1.1.1.10! root 9050: if (cctrue(dp->cc)) {
! 9051: buf = buf_out(buf, &bufsize, _T(" (T)"));
! 9052: } else {
! 9053: buf = buf_out(buf, &bufsize, _T(" (F)"));
! 9054: }
1.1.1.7 root 9055: }
9056: }
1.1.1.4 root 9057: } else if ((opcode & 0xff00) == 0x6100) { /* BSR */
9058: if (deaddr)
1.1.1.7 root 9059: *deaddr = pc;
9060: buf = buf_out (buf, &bufsize, _T(" == $%08x"), seaddr2);
1.1.1.4 root 9061: }
1.1.1.7 root 9062: buf = buf_out (buf, &bufsize, _T("\n"));
9063:
1.1.1.10! root 9064: for (uaecptr segpc = oldpc; segpc < pc; segpc++) {
! 9065: TCHAR segout[256];
! 9066: if (debugmem_get_symbol(segpc, segout, sizeof(segout) / sizeof(TCHAR))) {
! 9067: _tcscat(segout, _T(":\n"));
! 9068: if (bufsize > _tcslen(segout)) {
! 9069: memmove(symbolpos + _tcslen(segout), symbolpos, (_tcslen(symbolpos) + 1) * sizeof(TCHAR));
! 9070: memcpy(symbolpos, segout, _tcslen(segout) * sizeof(TCHAR));
! 9071: bufsize -= _tcslen(segout);
! 9072: buf += _tcslen(segout);
! 9073: symbolpos += _tcslen(segout);
! 9074: }
! 9075: }
! 9076: }
! 9077:
! 9078: int srcline = -1;
! 9079: for (uaecptr segpc = oldpc; segpc < pc; segpc++) {
! 9080: TCHAR sourceout[256];
! 9081: int line = debugmem_get_sourceline(segpc, sourceout, sizeof(sourceout) / sizeof(TCHAR));
! 9082: if (line < 0)
! 9083: break;
! 9084: if (srcline != line) {
! 9085: if (srcline < 0)
! 9086: buf = buf_out(buf, &bufsize, _T("\n"));
! 9087: buf = buf_out(buf, &bufsize, sourceout);
! 9088: srcline = line;
! 9089: }
! 9090: }
! 9091: if (srcline >= 0) {
! 9092: buf = buf_out(buf, &bufsize, _T("\n"));
! 9093: }
! 9094:
1.1.1.7 root 9095: if (illegal)
9096: pc = m68kpc_illg;
1.1.1.4 root 9097: }
9098: if (nextpc)
1.1.1.7 root 9099: *nextpc = pc;
9100: if (seaddr)
9101: *seaddr = seaddr2;
9102: if (deaddr)
9103: *deaddr = deaddr2;
1.1.1.4 root 9104: }
9105:
1.1.1.10! root 9106: void m68k_disasm_ea (uaecptr addr, uaecptr *nextpc, int cnt, uae_u32 *seaddr, uae_u32 *deaddr, uaecptr lastpc)
1.1.1.7 root 9107: {
9108: TCHAR *buf;
9109:
1.1.1.10! root 9110: buf = xcalloc (TCHAR, (MAX_LINEWIDTH + 1) * cnt);
1.1.1.7 root 9111: if (!buf)
9112: return;
1.1.1.10! root 9113: m68k_disasm_2 (buf, MAX_LINEWIDTH * cnt, addr, nextpc, cnt, seaddr, deaddr, lastpc, 1);
1.1.1.7 root 9114: xfree (buf);
9115: }
1.1.1.10! root 9116: void m68k_disasm (uaecptr addr, uaecptr *nextpc, uaecptr lastpc, int cnt)
1.1.1.4 root 9117: {
1.1.1.7 root 9118: TCHAR *buf;
9119:
1.1.1.10! root 9120: buf = xcalloc (TCHAR, (MAX_LINEWIDTH + 1) * cnt);
1.1.1.7 root 9121: if (!buf)
9122: return;
1.1.1.10! root 9123: m68k_disasm_2 (buf, MAX_LINEWIDTH * cnt, addr, nextpc, cnt, NULL, NULL, lastpc, 0);
1.1.1.7 root 9124: console_out_f (_T("%s"), buf);
9125: xfree (buf);
1.1.1.4 root 9126: }
1.1.1.10! root 9127: void m68k_disasm_file (FILE *f, uaecptr addr, uaecptr *nextpc, uaecptr lastpc, int cnt)
1.1.1.4 root 9128: {
1.1.1.7 root 9129: TCHAR *buf;
9130:
9131: buf = xmalloc (TCHAR, (MAX_LINEWIDTH + 1) * cnt);
9132: if (!buf)
9133: return;
9134: console_out_FILE = f;
1.1.1.10! root 9135: m68k_disasm_2 (buf, MAX_LINEWIDTH * cnt, addr, nextpc, cnt, NULL, NULL, lastpc, 0);
1.1.1.7 root 9136: f_out (f, _T("%s"), buf);
9137: xfree (buf);
9138: console_out_FILE = NULL;
1.1.1.4 root 9139: }
9140:
9141: /*************************************************************
9142: Disasm the m68kcode at the given address into instrname
9143: and instrcode
9144: *************************************************************/
1.1.1.10! root 9145: void sm68k_disasm (TCHAR *instrname, TCHAR *instrcode, uaecptr addr, uaecptr *nextpc, uaecptr lastpc)
1.1.1.4 root 9146: {
9147: TCHAR *ccpt;
9148: uae_u32 opcode;
9149: struct mnemolookup *lookup;
9150: struct instr *dp;
1.1.1.7 root 9151: uaecptr pc, oldpc;
1.1.1.4 root 9152:
1.1.1.7 root 9153: pc = oldpc = addr;
9154: opcode = get_word_debug (pc);
1.1.1.4 root 9155: if (cpufunctbl[opcode] == op_illg_1) {
9156: opcode = 0x4AFC;
9157: }
9158: dp = table68k + opcode;
9159: for (lookup = lookuptab;lookup->mnemo != dp->mnemo; lookup++);
9160:
1.1.1.7 root 9161: pc += 2;
1.1.1.4 root 9162:
9163: _tcscpy (instrname, lookup->name);
1.1.1.7 root 9164: ccpt = _tcsstr (instrname, _T("cc"));
1.1.1.4 root 9165: if (ccpt != 0) {
9166: _tcsncpy (ccpt, ccnames[dp->cc], 2);
9167: }
9168: switch (dp->size){
1.1.1.7 root 9169: case sz_byte: _tcscat (instrname, _T(".B ")); break;
9170: case sz_word: _tcscat (instrname, _T(".W ")); break;
9171: case sz_long: _tcscat (instrname, _T(".L ")); break;
9172: default: _tcscat (instrname, _T(" ")); break;
1.1.1.4 root 9173: }
9174:
9175: if (dp->suse) {
1.1.1.7 root 9176: pc = ShowEA (0, pc, opcode, dp->sreg, dp->smode, dp->size, instrname, NULL, 0);
1.1.1.4 root 9177: }
9178: if (dp->suse && dp->duse)
1.1.1.7 root 9179: _tcscat (instrname, _T(","));
1.1.1.4 root 9180: if (dp->duse) {
1.1.1.7 root 9181: pc = ShowEA (0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, NULL, 0);
1.1.1.4 root 9182: }
9183: if (instrcode)
9184: {
9185: int i;
1.1.1.10! root 9186: for (i = 0; i < (pc - oldpc) / 2; i++)
1.1.1.4 root 9187: {
1.1.1.7 root 9188: _stprintf (instrcode, _T("%04x "), get_iword_debug (oldpc + i * 2));
1.1.1.4 root 9189: instrcode += _tcslen (instrcode);
9190: }
9191: }
9192: if (nextpc)
1.1.1.7 root 9193: *nextpc = pc;
1.1.1.4 root 9194: }
9195:
9196: struct cpum2c m2cregs[] = {
1.1.1.7 root 9197: { 0, _T("SFC") },
9198: { 1, _T("DFC") },
9199: { 2, _T("CACR") },
9200: { 3, _T("TC") },
9201: { 4, _T("ITT0") },
9202: { 5, _T("ITT1") },
9203: { 6, _T("DTT0") },
9204: { 7, _T("DTT1") },
9205: { 8, _T("BUSC") },
9206: { 0x800, _T("USP") },
9207: { 0x801, _T("VBR") },
9208: { 0x802, _T("CAAR") },
9209: { 0x803, _T("MSP") },
9210: { 0x804, _T("ISP") },
9211: { 0x805, _T("MMUS") },
9212: { 0x806, _T("URP") },
9213: { 0x807, _T("SRP") },
9214: { 0x808, _T("PCR") },
9215: { -1, NULL }
1.1.1.4 root 9216: };
9217:
1.1.1.10! root 9218: void m68k_dumpstate(uaecptr *nextpc, uaecptr prevpc)
1.1.1.4 root 9219: {
9220: int i, j;
1.1.1.10! root 9221: uaecptr pc = M68K_GETPC;
1.1.1.4 root 9222:
9223: for (i = 0; i < 8; i++){
1.1.1.7 root 9224: console_out_f (_T(" D%d %08X "), i, m68k_dreg (regs, i));
9225: if ((i & 3) == 3) console_out_f (_T("\n"));
1.1.1.4 root 9226: }
9227: for (i = 0; i < 8; i++){
1.1.1.7 root 9228: console_out_f (_T(" A%d %08X "), i, m68k_areg (regs, i));
9229: if ((i & 3) == 3) console_out_f (_T("\n"));
1.1.1.4 root 9230: }
9231: if (regs.s == 0)
9232: regs.usp = m68k_areg (regs, 7);
9233: if (regs.s && regs.m)
9234: regs.msp = m68k_areg (regs, 7);
9235: if (regs.s && regs.m == 0)
9236: regs.isp = m68k_areg (regs, 7);
9237: j = 2;
1.1.1.7 root 9238: console_out_f (_T("USP %08X ISP %08X "), regs.usp, regs.isp);
1.1.1.4 root 9239: for (i = 0; m2cregs[i].regno>= 0; i++) {
9240: if (!movec_illg (m2cregs[i].regno)) {
1.1.1.7 root 9241: if (!_tcscmp (m2cregs[i].regname, _T("USP")) || !_tcscmp (m2cregs[i].regname, _T("ISP")))
1.1.1.4 root 9242: continue;
9243: if (j > 0 && (j % 4) == 0)
1.1.1.7 root 9244: console_out_f (_T("\n"));
9245: console_out_f (_T("%-4s %08X "), m2cregs[i].regname, val_move2c (m2cregs[i].regno));
1.1.1.4 root 9246: j++;
9247: }
9248: }
9249: if (j > 0)
1.1.1.7 root 9250: console_out_f (_T("\n"));
9251: console_out_f (_T("T=%d%d S=%d M=%d X=%d N=%d Z=%d V=%d C=%d IMASK=%d STP=%d\n"),
1.1.1.4 root 9252: regs.t1, regs.t0, regs.s, regs.m,
9253: GET_XFLG (), GET_NFLG (), GET_ZFLG (),
9254: GET_VFLG (), GET_CFLG (),
9255: regs.intmask, regs.stopped);
9256: #ifdef FPUEMU
9257: if (currprefs.fpu_model) {
9258: uae_u32 fpsr;
1.1.1.9 root 9259: for (i = 0; i < 8; i++) {
9260: if (!(i & 1))
9261: console_out_f(_T("%d: "), i);
9262: console_out_f (_T("%s "), fpp_print(®s.fp[i], -1));
9263: console_out_f (_T("%s "), fpp_print(®s.fp[i], 0));
9264: if (i & 1)
1.1.1.7 root 9265: console_out_f (_T("\n"));
1.1.1.4 root 9266: }
1.1.1.7 root 9267: fpsr = fpp_get_fpsr ();
1.1.1.9 root 9268: console_out_f (_T("FPSR: %08X FPCR: %08x FPIAR: %08x N=%d Z=%d I=%d NAN=%d\n"),
1.1.1.7 root 9269: fpsr, regs.fpcr, regs.fpiar,
1.1.1.4 root 9270: (fpsr & 0x8000000) != 0,
9271: (fpsr & 0x4000000) != 0,
9272: (fpsr & 0x2000000) != 0,
9273: (fpsr & 0x1000000) != 0);
9274: }
9275: #endif
1.1.1.7 root 9276: if (currprefs.mmu_model == 68030) {
9277: #ifndef WINUAE_FOR_HATARI
9278: console_out_f (_T("SRP: %llX CRP: %llX\n"), srp_030, crp_030);
1.1.1.8 root 9279: #else /* Use PRIX64 since MinGW on Windows does not know about %llx (?) */
9280: console_out_f (_T("SRP: %"PRIX64" CRP: %"PRIX64"\n"), (uint64_t)srp_030, (uint64_t)crp_030);
1.1.1.7 root 9281: #endif
9282: console_out_f (_T("TT0: %08X TT1: %08X TC: %08X\n"), tt0_030, tt1_030, tc_030);
9283: }
1.1.1.9 root 9284: if (currprefs.cpu_compatible) {
9285: if (currprefs.cpu_model == 68000) {
9286: struct instr *dp;
9287: struct mnemolookup *lookup1, *lookup2;
9288: dp = table68k + regs.irc;
9289: for (lookup1 = lookuptab; lookup1->mnemo != dp->mnemo; lookup1++)
9290: ;
9291: dp = table68k + regs.ir;
9292: for (lookup2 = lookuptab; lookup2->mnemo != dp->mnemo; lookup2++)
9293: ;
9294: console_out_f (_T("Prefetch %04x (%s) %04x (%s) Chip latch %08X\n"), regs.irc, lookup1->name, regs.ir, lookup2->name, regs.chipset_latch_rw);
9295: } else if (currprefs.cpu_model == 68020 || currprefs.cpu_model == 68030) {
9296: console_out_f (_T("Prefetch %08x %08x (%d) %04x (%d) %04x (%d) %04x (%d)\n"),
9297: regs.cacheholdingaddr020, regs.cacheholdingdata020, regs.cacheholdingdata_valid,
9298: regs.prefetch020[0], regs.prefetch020_valid[0],
9299: regs.prefetch020[1], regs.prefetch020_valid[1],
9300: regs.prefetch020[2], regs.prefetch020_valid[2]);
9301: }
1.1.1.4 root 9302: }
1.1.1.10! root 9303: if (prevpc != 0xffffffff && pc - prevpc < 100) {
! 9304: while (prevpc < pc) {
! 9305: m68k_disasm(prevpc, &prevpc, 0xffffffff, 1);
! 9306: }
1.1.1.7 root 9307: }
1.1.1.10! root 9308: m68k_disasm (pc, nextpc, pc, 1);
! 9309: if (nextpc)
! 9310: console_out_f (_T("Next PC: %08x\n"), *nextpc);
1.1.1.7 root 9311: }
9312: #ifdef WINUAE_FOR_HATARI
1.1.1.10! root 9313: void m68k_dumpstate_file (FILE *f, uaecptr *nextpc, uaecptr prevpc)
1.1.1.7 root 9314: {
9315: console_out_FILE = f;
1.1.1.10! root 9316: m68k_dumpstate(nextpc, prevpc);
1.1.1.7 root 9317: console_out_FILE = NULL;
9318: }
9319: #endif
1.1.1.9 root 9320: void m68k_dumpcache (bool dc)
1.1.1.7 root 9321: {
9322: if (!currprefs.cpu_compatible)
9323: return;
9324: if (currprefs.cpu_model == 68020) {
1.1.1.10! root 9325: for (int i = 0; i < CACHELINES020; i += 4) {
! 9326: for (int j = 0; j < 4; j++) {
1.1.1.7 root 9327: int s = i + j;
9328: uaecptr addr;
1.1.1.9 root 9329: int fc;
1.1.1.7 root 9330: struct cache020 *c = &caches020[s];
1.1.1.9 root 9331: fc = c->tag & 1;
1.1.1.7 root 9332: addr = c->tag & ~1;
9333: addr |= s << 2;
1.1.1.9 root 9334: console_out_f (_T("%08X%c:%08X%c"), addr, fc ? 'S' : 'U', c->data, c->valid ? '*' : ' ');
1.1.1.7 root 9335: }
9336: console_out_f (_T("\n"));
9337: }
9338: } else if (currprefs.cpu_model == 68030) {
1.1.1.10! root 9339: for (int i = 0; i < CACHELINES030; i++) {
1.1.1.9 root 9340: struct cache030 *c = dc ? &dcaches030[i] : &icaches030[i];
9341: int fc;
1.1.1.7 root 9342: uaecptr addr;
1.1.1.9 root 9343: if (!dc) {
9344: fc = (c->tag & 1) ? 6 : 2;
9345: } else {
9346: fc = c->fc;
9347: }
1.1.1.7 root 9348: addr = c->tag & ~1;
9349: addr |= i << 4;
1.1.1.9 root 9350: console_out_f (_T("%08X %d: "), addr, fc);
1.1.1.10! root 9351: for (int j = 0; j < 4; j++) {
1.1.1.7 root 9352: console_out_f (_T("%08X%c "), c->data[j], c->valid[j] ? '*' : ' ');
9353: }
9354: console_out_f (_T("\n"));
9355: }
1.1.1.9 root 9356: } else if (currprefs.cpu_model >= 68040) {
9357: uae_u32 tagmask = dc ? cachedtag04060mask : cacheitag04060mask;
1.1.1.10! root 9358: for (int i = 0; i < cachedsets04060; i++) {
1.1.1.9 root 9359: struct cache040 *c = dc ? &dcaches040[i] : &icaches040[i];
1.1.1.10! root 9360: for (int j = 0; j < CACHELINES040; j++) {
1.1.1.9 root 9361: if (c->valid[j]) {
9362: uae_u32 addr = (c->tag[j] & tagmask) | (i << 4);
9363: write_log(_T("%02d:%d %08x = %08x%c %08x%c %08x%c %08x%c\n"),
9364: i, j, addr,
9365: c->data[j][0], c->dirty[j][0] ? '*' : ' ',
9366: c->data[j][1], c->dirty[j][1] ? '*' : ' ',
9367: c->data[j][2], c->dirty[j][2] ? '*' : ' ',
9368: c->data[j][3], c->dirty[j][3] ? '*' : ' ');
9369: }
9370: }
9371: }
1.1.1.7 root 9372: }
1.1.1.4 root 9373: }
9374:
9375: #ifdef SAVESTATE
9376:
9377: /* CPU save/restore code */
9378:
9379: #define CPUTYPE_EC 1
9380: #define CPUMODE_HALT 1
9381:
9382: uae_u8 *restore_cpu (uae_u8 *src)
9383: {
1.1.1.10! root 9384: int flags, model;
1.1.1.4 root 9385: uae_u32 l;
9386:
1.1.1.7 root 9387: currprefs.cpu_model = changed_prefs.cpu_model = model = restore_u32 ();
1.1.1.4 root 9388: flags = restore_u32 ();
9389: changed_prefs.address_space_24 = 0;
9390: if (flags & CPUTYPE_EC)
9391: changed_prefs.address_space_24 = 1;
9392: currprefs.address_space_24 = changed_prefs.address_space_24;
9393: currprefs.cpu_compatible = changed_prefs.cpu_compatible;
9394: currprefs.cpu_cycle_exact = changed_prefs.cpu_cycle_exact;
1.1.1.8 root 9395: currprefs.cpu_memory_cycle_exact = changed_prefs.cpu_memory_cycle_exact;
1.1.1.4 root 9396: currprefs.blitter_cycle_exact = changed_prefs.blitter_cycle_exact;
9397: currprefs.cpu_frequency = changed_prefs.cpu_frequency = 0;
9398: currprefs.cpu_clock_multiplier = changed_prefs.cpu_clock_multiplier = 0;
1.1.1.10! root 9399: for (int i = 0; i < 15; i++)
1.1.1.4 root 9400: regs.regs[i] = restore_u32 ();
9401: regs.pc = restore_u32 ();
9402: regs.irc = restore_u16 ();
9403: regs.ir = restore_u16 ();
9404: regs.usp = restore_u32 ();
9405: regs.isp = restore_u32 ();
9406: regs.sr = restore_u16 ();
9407: l = restore_u32 ();
9408: if (l & CPUMODE_HALT) {
9409: regs.stopped = 1;
9410: } else {
9411: regs.stopped = 0;
9412: }
9413: if (model >= 68010) {
9414: regs.dfc = restore_u32 ();
9415: regs.sfc = restore_u32 ();
9416: regs.vbr = restore_u32 ();
9417: }
9418: if (model >= 68020) {
9419: regs.caar = restore_u32 ();
9420: regs.cacr = restore_u32 ();
9421: regs.msp = restore_u32 ();
9422: }
9423: if (model >= 68030) {
1.1.1.7 root 9424: crp_030 = fake_crp_030 = restore_u64 ();
9425: srp_030 = fake_srp_030 = restore_u64 ();
9426: tt0_030 = fake_tt0_030 = restore_u32 ();
9427: tt1_030 = fake_tt1_030 = restore_u32 ();
9428: tc_030 = fake_tc_030 = restore_u32 ();
9429: mmusr_030 = fake_mmusr_030 = restore_u16 ();
1.1.1.4 root 9430: }
9431: if (model >= 68040) {
9432: regs.itt0 = restore_u32 ();
9433: regs.itt1 = restore_u32 ();
9434: regs.dtt0 = restore_u32 ();
9435: regs.dtt1 = restore_u32 ();
9436: regs.tcr = restore_u32 ();
9437: regs.urp = restore_u32 ();
9438: regs.srp = restore_u32 ();
9439: }
9440: if (model >= 68060) {
9441: regs.buscr = restore_u32 ();
9442: regs.pcr = restore_u32 ();
9443: }
9444: if (flags & 0x80000000) {
9445: int khz = restore_u32 ();
9446: restore_u32 ();
9447: if (khz > 0 && khz < 800000)
9448: currprefs.m68k_speed = changed_prefs.m68k_speed = 0;
9449: }
1.1.1.7 root 9450: set_cpu_caches (true);
9451: if (flags & 0x40000000) {
9452: if (model == 68020) {
1.1.1.10! root 9453: for (int i = 0; i < CACHELINES020; i++) {
1.1.1.7 root 9454: caches020[i].data = restore_u32 ();
9455: caches020[i].tag = restore_u32 ();
9456: caches020[i].valid = restore_u8 () != 0;
9457: }
9458: regs.prefetch020addr = restore_u32 ();
9459: regs.cacheholdingaddr020 = restore_u32 ();
9460: regs.cacheholdingdata020 = restore_u32 ();
9461: if (flags & 0x20000000) {
1.1.1.9 root 9462: if (flags & 0x4000000) {
9463: // 3.6 new (back to 16 bits)
1.1.1.10! root 9464: for (int i = 0; i < CPU_PIPELINE_MAX; i++) {
1.1.1.9 root 9465: uae_u32 v = restore_u32();
9466: regs.prefetch020[i] = v >> 16;
9467: regs.prefetch020_valid[i] = (v & 1) != 0;
9468: }
9469: } else {
9470: // old
9471: uae_u32 v = restore_u32();
9472: regs.prefetch020[0] = v >> 16;
9473: regs.prefetch020[1] = (uae_u16)v;
9474: v = restore_u32();
9475: regs.prefetch020[2] = v >> 16;
9476: regs.prefetch020[3] = (uae_u16)v;
9477: restore_u32();
9478: restore_u32();
9479: regs.prefetch020_valid[0] = true;
9480: regs.prefetch020_valid[1] = true;
9481: regs.prefetch020_valid[2] = true;
9482: regs.prefetch020_valid[3] = true;
9483: }
1.1.1.7 root 9484: }
9485: } else if (model == 68030) {
1.1.1.10! root 9486: for (int i = 0; i < CACHELINES030; i++) {
! 9487: for (int j = 0; j < 4; j++) {
1.1.1.7 root 9488: icaches030[i].data[j] = restore_u32 ();
9489: icaches030[i].valid[j] = restore_u8 () != 0;
9490: }
9491: icaches030[i].tag = restore_u32 ();
9492: }
1.1.1.10! root 9493: for (int i = 0; i < CACHELINES030; i++) {
! 9494: for (int j = 0; j < 4; j++) {
1.1.1.7 root 9495: dcaches030[i].data[j] = restore_u32 ();
9496: dcaches030[i].valid[j] = restore_u8 () != 0;
9497: }
9498: dcaches030[i].tag = restore_u32 ();
9499: }
9500: regs.prefetch020addr = restore_u32 ();
9501: regs.cacheholdingaddr020 = restore_u32 ();
9502: regs.cacheholdingdata020 = restore_u32 ();
1.1.1.9 root 9503: if (flags & 0x4000000) {
1.1.1.10! root 9504: for (int i = 0; i < CPU_PIPELINE_MAX; i++) {
1.1.1.9 root 9505: uae_u32 v = restore_u32();
9506: regs.prefetch020[i] = v >> 16;
9507: regs.prefetch020_valid[i] = (v & 1) != 0;
9508: }
9509: } else {
1.1.1.10! root 9510: for (int i = 0; i < CPU_PIPELINE_MAX; i++) {
1.1.1.9 root 9511: regs.prefetch020[i] = restore_u32 ();
9512: regs.prefetch020_valid[i] = false;
9513: }
9514: }
9515: } else if (model == 68040) {
1.1.1.7 root 9516: if (flags & 0x8000000) {
1.1.1.10! root 9517: for (int i = 0; i < ((model == 68060 && (flags & 0x4000000)) ? CACHESETS060 : CACHESETS040); i++) {
! 9518: for (int j = 0; j < CACHELINES040; j++) {
1.1.1.9 root 9519: struct cache040 *c = &icaches040[i];
9520: c->data[j][0] = restore_u32();
9521: c->data[j][1] = restore_u32();
9522: c->data[j][2] = restore_u32();
9523: c->data[j][3] = restore_u32();
9524: c->tag[j] = restore_u32();
9525: c->valid[j] = restore_u16() & 1;
1.1.1.7 root 9526: }
9527: }
9528: regs.prefetch020addr = restore_u32();
9529: regs.cacheholdingaddr020 = restore_u32();
9530: regs.cacheholdingdata020 = restore_u32();
1.1.1.10! root 9531: for (int i = 0; i < CPU_PIPELINE_MAX; i++)
1.1.1.9 root 9532: regs.prefetch040[i] = restore_u32();
9533: if (flags & 0x4000000) {
1.1.1.10! root 9534: for (int i = 0; i < (model == 68060 ? CACHESETS060 : CACHESETS040); i++) {
! 9535: for (int j = 0; j < CACHELINES040; j++) {
1.1.1.9 root 9536: struct cache040 *c = &dcaches040[i];
9537: c->data[j][0] = restore_u32();
9538: c->data[j][1] = restore_u32();
9539: c->data[j][2] = restore_u32();
9540: c->data[j][3] = restore_u32();
9541: c->tag[j] = restore_u32();
9542: uae_u16 v = restore_u16();
9543: c->valid[j] = (v & 1) != 0;
9544: c->dirty[j][0] = (v & 0x10) != 0;
9545: c->dirty[j][1] = (v & 0x20) != 0;
9546: c->dirty[j][2] = (v & 0x40) != 0;
9547: c->dirty[j][3] = (v & 0x80) != 0;
9548: c->gdirty[j] = c->dirty[j][0] || c->dirty[j][1] || c->dirty[j][2] || c->dirty[j][3];
9549: }
9550: }
9551: }
1.1.1.7 root 9552: }
9553: }
9554: if (model >= 68020) {
1.1.1.9 root 9555: restore_u32 (); // regs.ce020memcycles
9556: regs.ce020startcycle = regs.ce020endcycle = 0;
1.1.1.7 root 9557: restore_u32 ();
9558: }
9559: }
9560: if (flags & 0x10000000) {
9561: regs.chipset_latch_rw = restore_u32 ();
9562: regs.chipset_latch_read = restore_u32 ();
9563: regs.chipset_latch_write = restore_u32 ();
9564: }
9565:
1.1.1.9 root 9566: regs.pipeline_pos = -1;
9567: regs.pipeline_stop = 0;
9568: if (flags & 0x4000000 && currprefs.cpu_model == 68020) {
9569: regs.pipeline_pos = restore_u16();
9570: regs.pipeline_r8[0] = restore_u16();
9571: regs.pipeline_r8[1] = restore_u16();
9572: regs.pipeline_stop = restore_u16();
9573: }
9574:
1.1.1.7 root 9575: m68k_reset_sr();
9576:
9577: write_log (_T("CPU: %d%s%03d, PC=%08X\n"),
9578: model / 1000, flags & 1 ? _T("EC") : _T(""), model % 1000, regs.pc);
1.1.1.4 root 9579:
9580: return src;
9581: }
9582:
1.1.1.7 root 9583: static void fill_prefetch_quick (void)
9584: {
9585: if (currprefs.cpu_model >= 68020) {
9586: fill_prefetch ();
9587: return;
9588: }
9589: // old statefile compatibility, this needs to done,
9590: // even in 68000 cycle-exact mode
9591: regs.ir = get_word (m68k_getpc ());
9592: regs.irc = get_word (m68k_getpc () + 2);
9593: }
9594:
1.1.1.4 root 9595: void restore_cpu_finish (void)
9596: {
1.1.1.10! root 9597: if (!currprefs.fpu_model)
! 9598: fpu_reset();
1.1.1.4 root 9599: init_m68k ();
1.1.1.7 root 9600: m68k_setpc_normal (regs.pc);
1.1.1.4 root 9601: doint ();
1.1.1.7 root 9602: fill_prefetch_quick ();
9603: #ifndef WINUAE_FOR_HATARI
9604: set_cycles (start_cycles);
9605: events_schedule ();
9606: #endif
1.1.1.4 root 9607: if (regs.stopped)
9608: set_special (SPCFLAG_STOP);
9609: //activate_debugger ();
9610: }
9611:
1.1.1.7 root 9612: uae_u8 *save_cpu_trace (int *len, uae_u8 *dstptr)
1.1.1.4 root 9613: {
1.1.1.7 root 9614: uae_u8 *dstbak, *dst;
1.1.1.4 root 9615:
1.1.1.7 root 9616: if (cputrace.state <= 0)
9617: return NULL;
1.1.1.4 root 9618:
1.1.1.7 root 9619: if (dstptr)
9620: dstbak = dst = dstptr;
9621: else
1.1.1.8 root 9622: dstbak = dst = xmalloc (uae_u8, 10000);
1.1.1.7 root 9623:
1.1.1.9 root 9624: save_u32 (2 | 4 | 16 | 32);
1.1.1.7 root 9625: save_u16 (cputrace.opcode);
1.1.1.10! root 9626: for (int i = 0; i < 16; i++)
1.1.1.7 root 9627: save_u32 (cputrace.regs[i]);
9628: save_u32 (cputrace.pc);
9629: save_u16 (cputrace.irc);
9630: save_u16 (cputrace.ir);
9631: save_u32 (cputrace.usp);
9632: save_u32 (cputrace.isp);
9633: save_u16 (cputrace.sr);
9634: save_u16 (cputrace.intmask);
9635: save_u16 ((cputrace.stopped ? 1 : 0) | (regs.stopped ? 2 : 0));
9636: save_u16 (cputrace.state);
9637: save_u32 (cputrace.cyclecounter);
9638: save_u32 (cputrace.cyclecounter_pre);
9639: save_u32 (cputrace.cyclecounter_post);
9640: save_u32 (cputrace.readcounter);
9641: save_u32 (cputrace.writecounter);
9642: save_u32 (cputrace.memoryoffset);
9643: write_log (_T("CPUT SAVE: PC=%08x C=%08X %08x %08x %08x %d %d %d\n"),
9644: cputrace.pc, cputrace.startcycles,
9645: cputrace.cyclecounter, cputrace.cyclecounter_pre, cputrace.cyclecounter_post,
9646: cputrace.readcounter, cputrace.writecounter, cputrace.memoryoffset);
1.1.1.10! root 9647: for (int i = 0; i < cputrace.memoryoffset; i++) {
1.1.1.7 root 9648: save_u32 (cputrace.ctm[i].addr);
9649: save_u32 (cputrace.ctm[i].data);
9650: save_u32 (cputrace.ctm[i].mode);
9651: write_log (_T("CPUT%d: %08x %08x %08x\n"), i, cputrace.ctm[i].addr, cputrace.ctm[i].data, cputrace.ctm[i].mode);
9652: }
9653: save_u32 (cputrace.startcycles);
9654:
9655: if (currprefs.cpu_model == 68020) {
1.1.1.10! root 9656: for (int i = 0; i < CACHELINES020; i++) {
1.1.1.7 root 9657: save_u32 (cputrace.caches020[i].data);
9658: save_u32 (cputrace.caches020[i].tag);
9659: save_u8 (cputrace.caches020[i].valid ? 1 : 0);
9660: }
9661: save_u32 (cputrace.prefetch020addr);
9662: save_u32 (cputrace.cacheholdingaddr020);
9663: save_u32 (cputrace.cacheholdingdata020);
1.1.1.10! root 9664: for (int i = 0; i < CPU_PIPELINE_MAX; i++) {
1.1.1.7 root 9665: save_u16 (cputrace.prefetch020[i]);
1.1.1.9 root 9666: }
1.1.1.10! root 9667: for (int i = 0; i < CPU_PIPELINE_MAX; i++) {
1.1.1.7 root 9668: save_u32 (cputrace.prefetch020[i]);
1.1.1.9 root 9669: }
1.1.1.10! root 9670: for (int i = 0; i < CPU_PIPELINE_MAX; i++) {
1.1.1.9 root 9671: save_u8 (cputrace.prefetch020_valid[i]);
9672: }
9673: save_u16(cputrace.pipeline_pos);
9674: save_u16(cputrace.pipeline_r8[0]);
9675: save_u16(cputrace.pipeline_r8[1]);
9676: save_u16(cputrace.pipeline_stop);
1.1.1.7 root 9677: }
9678:
9679: *len = dst - dstbak;
9680: cputrace.needendcycles = 1;
9681: return dstbak;
9682: }
9683:
9684: uae_u8 *restore_cpu_trace (uae_u8 *src)
9685: {
9686: cpu_tracer = 0;
9687: cputrace.state = 0;
9688: uae_u32 v = restore_u32 ();
9689: if (!(v & 2))
9690: return src;
9691: cputrace.opcode = restore_u16 ();
1.1.1.10! root 9692: for (int i = 0; i < 16; i++)
1.1.1.7 root 9693: cputrace.regs[i] = restore_u32 ();
9694: cputrace.pc = restore_u32 ();
9695: cputrace.irc = restore_u16 ();
9696: cputrace.ir = restore_u16 ();
9697: cputrace.usp = restore_u32 ();
9698: cputrace.isp = restore_u32 ();
9699: cputrace.sr = restore_u16 ();
9700: cputrace.intmask = restore_u16 ();
9701: cputrace.stopped = restore_u16 ();
9702: cputrace.state = restore_u16 ();
9703: cputrace.cyclecounter = restore_u32 ();
9704: cputrace.cyclecounter_pre = restore_u32 ();
9705: cputrace.cyclecounter_post = restore_u32 ();
9706: cputrace.readcounter = restore_u32 ();
9707: cputrace.writecounter = restore_u32 ();
9708: cputrace.memoryoffset = restore_u32 ();
1.1.1.10! root 9709: for (int i = 0; i < cputrace.memoryoffset; i++) {
1.1.1.7 root 9710: cputrace.ctm[i].addr = restore_u32 ();
9711: cputrace.ctm[i].data = restore_u32 ();
9712: cputrace.ctm[i].mode = restore_u32 ();
9713: }
9714: cputrace.startcycles = restore_u32 ();
9715:
9716: if (v & 4) {
9717: if (currprefs.cpu_model == 68020) {
1.1.1.10! root 9718: for (int i = 0; i < CACHELINES020; i++) {
1.1.1.7 root 9719: cputrace.caches020[i].data = restore_u32 ();
9720: cputrace.caches020[i].tag = restore_u32 ();
9721: cputrace.caches020[i].valid = restore_u8 () != 0;
9722: }
9723: cputrace.prefetch020addr = restore_u32 ();
9724: cputrace.cacheholdingaddr020 = restore_u32 ();
9725: cputrace.cacheholdingdata020 = restore_u32 ();
1.1.1.10! root 9726: for (int i = 0; i < CPU_PIPELINE_MAX; i++) {
1.1.1.7 root 9727: cputrace.prefetch020[i] = restore_u16 ();
1.1.1.9 root 9728: }
1.1.1.7 root 9729: if (v & 8) {
1.1.1.9 root 9730: // backwards compatibility
1.1.1.10! root 9731: uae_u32 v2 = restore_u32();
! 9732: cputrace.prefetch020[0] = v2 >> 16;
! 9733: cputrace.prefetch020[1] = (uae_u16)v2;
! 9734: v2 = restore_u32();
! 9735: cputrace.prefetch020[2] = v2 >> 16;
! 9736: cputrace.prefetch020[3] = (uae_u16)v2;
1.1.1.9 root 9737: restore_u32();
9738: restore_u32();
9739: cputrace.prefetch020_valid[0] = true;
9740: cputrace.prefetch020_valid[1] = true;
9741: cputrace.prefetch020_valid[2] = true;
9742: cputrace.prefetch020_valid[3] = true;
9743:
9744: cputrace.prefetch020[0] = cputrace.prefetch020[1];
9745: cputrace.prefetch020[1] = cputrace.prefetch020[2];
9746: cputrace.prefetch020[2] = cputrace.prefetch020[3];
9747: cputrace.prefetch020_valid[3] = false;
9748: }
9749: if (v & 16) {
1.1.1.10! root 9750: if ((v & 32) && !(v & 8)) {
! 9751: restore_u32();
! 9752: restore_u32();
! 9753: restore_u32();
! 9754: restore_u32();
! 9755: }
! 9756: for (int i = 0; i < CPU_PIPELINE_MAX; i++) {
1.1.1.9 root 9757: cputrace.prefetch020_valid[i] = restore_u8() != 0;
9758: }
9759: }
9760: if (v & 32) {
9761: cputrace.pipeline_pos = restore_u16();
9762: cputrace.pipeline_r8[0] = restore_u16();
9763: cputrace.pipeline_r8[1] = restore_u16();
9764: cputrace.pipeline_stop = restore_u16();
1.1.1.7 root 9765: }
9766: }
9767: }
9768:
9769: cputrace.needendcycles = 1;
9770: if (v && cputrace.state) {
9771: if (currprefs.cpu_model > 68000) {
9772: if (v & 4)
9773: cpu_tracer = -1;
9774: // old format?
1.1.1.10! root 9775: if ((v & (4 | 8)) != (4 | 8) && (v & (32 | 16 | 8 | 4)) != (32 | 16 | 4))
1.1.1.7 root 9776: cpu_tracer = 0;
9777: } else {
9778: cpu_tracer = -1;
9779: }
9780: }
9781:
9782: return src;
9783: }
9784:
9785: uae_u8 *restore_cpu_extra (uae_u8 *src)
9786: {
9787: restore_u32 ();
9788: uae_u32 flags = restore_u32 ();
9789:
9790: currprefs.cpu_cycle_exact = changed_prefs.cpu_cycle_exact = (flags & 1) ? true : false;
1.1.1.8 root 9791: currprefs.cpu_memory_cycle_exact = changed_prefs.cpu_memory_cycle_exact = currprefs.cpu_cycle_exact;
9792: if ((flags & 32) && !(flags & 1))
9793: currprefs.cpu_memory_cycle_exact = changed_prefs.cpu_memory_cycle_exact = true;
1.1.1.7 root 9794: currprefs.blitter_cycle_exact = changed_prefs.blitter_cycle_exact = currprefs.cpu_cycle_exact;
9795: currprefs.cpu_compatible = changed_prefs.cpu_compatible = (flags & 2) ? true : false;
9796: currprefs.cpu_frequency = changed_prefs.cpu_frequency = restore_u32 ();
9797: currprefs.cpu_clock_multiplier = changed_prefs.cpu_clock_multiplier = restore_u32 ();
9798: //currprefs.cachesize = changed_prefs.cachesize = (flags & 8) ? 8192 : 0;
9799:
9800: currprefs.m68k_speed = changed_prefs.m68k_speed = 0;
9801: if (flags & 4)
1.1.1.4 root 9802: currprefs.m68k_speed = changed_prefs.m68k_speed = -1;
1.1.1.7 root 9803: if (flags & 16)
9804: currprefs.m68k_speed = changed_prefs.m68k_speed = (flags >> 24) * CYCLE_UNIT;
1.1.1.4 root 9805:
9806: currprefs.cpu060_revision = changed_prefs.cpu060_revision = restore_u8 ();
9807: currprefs.fpu_revision = changed_prefs.fpu_revision = restore_u8 ();
9808:
9809: return src;
9810: }
9811:
9812: uae_u8 *save_cpu_extra (int *len, uae_u8 *dstptr)
9813: {
9814: uae_u8 *dstbak, *dst;
9815: uae_u32 flags;
9816:
9817: if (dstptr)
9818: dstbak = dst = dstptr;
9819: else
9820: dstbak = dst = xmalloc (uae_u8, 1000);
9821: save_u32 (0); // version
9822: flags = 0;
9823: flags |= currprefs.cpu_cycle_exact ? 1 : 0;
9824: flags |= currprefs.cpu_compatible ? 2 : 0;
9825: flags |= currprefs.m68k_speed < 0 ? 4 : 0;
9826: flags |= currprefs.cachesize > 0 ? 8 : 0;
1.1.1.7 root 9827: flags |= currprefs.m68k_speed > 0 ? 16 : 0;
1.1.1.8 root 9828: flags |= currprefs.cpu_memory_cycle_exact ? 32 : 0;
1.1.1.7 root 9829: if (currprefs.m68k_speed > 0)
9830: flags |= (currprefs.m68k_speed / CYCLE_UNIT) << 24;
1.1.1.4 root 9831: save_u32 (flags);
9832: save_u32 (currprefs.cpu_frequency);
9833: save_u32 (currprefs.cpu_clock_multiplier);
9834: save_u8 (currprefs.cpu060_revision);
9835: save_u8 (currprefs.fpu_revision);
9836: *len = dst - dstbak;
9837: return dstbak;
9838: }
9839:
9840: uae_u8 *save_cpu (int *len, uae_u8 *dstptr)
9841: {
9842: uae_u8 *dstbak, *dst;
1.1.1.10! root 9843: int model, khz;
1.1.1.4 root 9844:
9845: if (dstptr)
9846: dstbak = dst = dstptr;
9847: else
1.1.1.10! root 9848: dstbak = dst = xmalloc (uae_u8, 1000 + 30000);
1.1.1.4 root 9849: model = currprefs.cpu_model;
9850: save_u32 (model); /* MODEL */
1.1.1.9 root 9851: save_u32(0x80000000 | 0x40000000 | 0x20000000 | 0x10000000 | 0x8000000 | 0x4000000 | (currprefs.address_space_24 ? 1 : 0)); /* FLAGS */
1.1.1.10! root 9852: for (int i = 0;i < 15; i++)
1.1.1.4 root 9853: save_u32 (regs.regs[i]); /* D0-D7 A0-A6 */
9854: save_u32 (m68k_getpc ()); /* PC */
9855: save_u16 (regs.irc); /* prefetch */
9856: save_u16 (regs.ir); /* instruction prefetch */
9857: MakeSR ();
9858: save_u32 (!regs.s ? regs.regs[15] : regs.usp); /* USP */
9859: save_u32 (regs.s ? regs.regs[15] : regs.isp); /* ISP */
9860: save_u16 (regs.sr); /* SR/CCR */
9861: save_u32 (regs.stopped ? CPUMODE_HALT : 0); /* flags */
9862: if (model >= 68010) {
9863: save_u32 (regs.dfc); /* DFC */
9864: save_u32 (regs.sfc); /* SFC */
9865: save_u32 (regs.vbr); /* VBR */
9866: }
9867: if (model >= 68020) {
9868: save_u32 (regs.caar); /* CAAR */
9869: save_u32 (regs.cacr); /* CACR */
9870: save_u32 (regs.msp); /* MSP */
9871: }
9872: if (model >= 68030) {
1.1.1.7 root 9873: if (currprefs.mmu_model) {
9874: save_u64 (crp_030); /* CRP */
9875: save_u64 (srp_030); /* SRP */
9876: save_u32 (tt0_030); /* TT0/AC0 */
9877: save_u32 (tt1_030); /* TT1/AC1 */
9878: save_u32 (tc_030); /* TCR */
9879: save_u16 (mmusr_030); /* MMUSR/ACUSR */
9880: } else {
9881: save_u64 (fake_crp_030); /* CRP */
9882: save_u64 (fake_srp_030); /* SRP */
9883: save_u32 (fake_tt0_030); /* TT0/AC0 */
9884: save_u32 (fake_tt1_030); /* TT1/AC1 */
9885: save_u32 (fake_tc_030); /* TCR */
9886: save_u16 (fake_mmusr_030); /* MMUSR/ACUSR */
9887: }
1.1.1.4 root 9888: }
9889: if (model >= 68040) {
9890: save_u32 (regs.itt0); /* ITT0 */
9891: save_u32 (regs.itt1); /* ITT1 */
9892: save_u32 (regs.dtt0); /* DTT0 */
9893: save_u32 (regs.dtt1); /* DTT1 */
9894: save_u32 (regs.tcr); /* TCR */
9895: save_u32 (regs.urp); /* URP */
9896: save_u32 (regs.srp); /* SRP */
9897: }
9898: if (model >= 68060) {
9899: save_u32 (regs.buscr); /* BUSCR */
9900: save_u32 (regs.pcr); /* PCR */
9901: }
9902: khz = -1;
9903: if (currprefs.m68k_speed == 0) {
9904: khz = currprefs.ntscmode ? 715909 : 709379;
9905: if (currprefs.cpu_model >= 68020)
9906: khz *= 2;
9907: }
9908: save_u32 (khz); // clock rate in KHz: -1 = fastest possible
9909: save_u32 (0); // spare
1.1.1.7 root 9910: if (model == 68020) {
1.1.1.10! root 9911: for (int i = 0; i < CACHELINES020; i++) {
1.1.1.7 root 9912: save_u32 (caches020[i].data);
9913: save_u32 (caches020[i].tag);
9914: save_u8 (caches020[i].valid ? 1 : 0);
9915: }
9916: save_u32 (regs.prefetch020addr);
9917: save_u32 (regs.cacheholdingaddr020);
9918: save_u32 (regs.cacheholdingdata020);
1.1.1.10! root 9919: for (int i = 0; i < CPU_PIPELINE_MAX; i++)
1.1.1.9 root 9920: save_u32 ((regs.prefetch020[i] << 16) | (regs.prefetch020_valid[i] ? 1 : 0));
1.1.1.7 root 9921: } else if (model == 68030) {
1.1.1.10! root 9922: for (int i = 0; i < CACHELINES030; i++) {
! 9923: for (int j = 0; j < 4; j++) {
1.1.1.7 root 9924: save_u32 (icaches030[i].data[j]);
9925: save_u8 (icaches030[i].valid[j] ? 1 : 0);
9926: }
9927: save_u32 (icaches030[i].tag);
9928: }
1.1.1.10! root 9929: for (int i = 0; i < CACHELINES030; i++) {
! 9930: for (int j = 0; j < 4; j++) {
1.1.1.7 root 9931: save_u32 (dcaches030[i].data[j]);
9932: save_u8 (dcaches030[i].valid[j] ? 1 : 0);
9933: }
9934: save_u32 (dcaches030[i].tag);
9935: }
9936: save_u32 (regs.prefetch020addr);
9937: save_u32 (regs.cacheholdingaddr020);
9938: save_u32 (regs.cacheholdingdata020);
1.1.1.10! root 9939: for (int i = 0; i < CPU_PIPELINE_MAX; i++)
1.1.1.7 root 9940: save_u32 (regs.prefetch020[i]);
9941: } else if (model >= 68040) {
1.1.1.10! root 9942: for (int i = 0; i < (model == 68060 ? CACHESETS060 : CACHESETS040); i++) {
! 9943: for (int j = 0; j < CACHELINES040; j++) {
1.1.1.9 root 9944: struct cache040 *c = &icaches040[i];
9945: save_u32(c->data[j][0]);
9946: save_u32(c->data[j][1]);
9947: save_u32(c->data[j][2]);
9948: save_u32(c->data[j][3]);
9949: save_u32(c->tag[j]);
9950: save_u16(c->valid[j] ? 1 : 0);
1.1.1.7 root 9951: }
9952: }
9953: save_u32(regs.prefetch020addr);
9954: save_u32(regs.cacheholdingaddr020);
9955: save_u32(regs.cacheholdingdata020);
1.1.1.10! root 9956: for (int i = 0; i < CPU_PIPELINE_MAX; i++) {
1.1.1.9 root 9957: save_u32(regs.prefetch040[i]);
9958: }
1.1.1.10! root 9959: for (int i = 0; i < (model == 68060 ? CACHESETS060 : CACHESETS040); i++) {
! 9960: for (int j = 0; j < CACHELINES040; j++) {
1.1.1.9 root 9961: struct cache040 *c = &dcaches040[i];
9962: save_u32(c->data[j][0]);
9963: save_u32(c->data[j][1]);
9964: save_u32(c->data[j][2]);
9965: save_u32(c->data[j][3]);
9966: save_u32(c->tag[j]);
9967: uae_u16 v = c->valid[j] ? 1 : 0;
9968: v |= c->dirty[j][0] ? 0x10 : 0;
9969: v |= c->dirty[j][1] ? 0x20 : 0;
9970: v |= c->dirty[j][2] ? 0x40 : 0;
9971: v |= c->dirty[j][3] ? 0x80 : 0;
9972: save_u16(v);
9973: }
9974: }
1.1.1.7 root 9975: }
9976: if (currprefs.cpu_model >= 68020) {
1.1.1.9 root 9977: save_u32 (0); //save_u32 (regs.ce020memcycles);
1.1.1.7 root 9978: save_u32 (0);
9979: }
9980: save_u32 (regs.chipset_latch_rw);
9981: save_u32 (regs.chipset_latch_read);
9982: save_u32 (regs.chipset_latch_write);
1.1.1.9 root 9983: if (currprefs.cpu_model == 68020) {
9984: save_u16(regs.pipeline_pos);
9985: save_u16(regs.pipeline_r8[0]);
9986: save_u16(regs.pipeline_r8[1]);
9987: save_u16(regs.pipeline_stop);
9988: }
1.1.1.4 root 9989: *len = dst - dstbak;
9990: return dstbak;
9991: }
9992:
9993: uae_u8 *save_mmu (int *len, uae_u8 *dstptr)
9994: {
9995: uae_u8 *dstbak, *dst;
9996: int model;
9997:
9998: model = currprefs.mmu_model;
1.1.1.7 root 9999: #ifndef WINUAE_FOR_HATARI
1.1.1.8 root 10000: /* Under Hatari, we save all MMU variables, even if mmu_model==0 */
1.1.1.7 root 10001: if (model != 68030 && model != 68040 && model != 68060)
1.1.1.4 root 10002: return NULL;
1.1.1.7 root 10003: #endif
1.1.1.4 root 10004: if (dstptr)
10005: dstbak = dst = dstptr;
10006: else
10007: dstbak = dst = xmalloc (uae_u8, 1000);
10008: save_u32 (model); /* MODEL */
1.1.1.7 root 10009: save_u32 (0); /* FLAGS */
1.1.1.4 root 10010: *len = dst - dstbak;
10011: return dstbak;
10012: }
10013:
10014: uae_u8 *restore_mmu (uae_u8 *src)
10015: {
10016: int flags, model;
10017:
10018: changed_prefs.mmu_model = model = restore_u32 ();
10019: flags = restore_u32 ();
1.1.1.7 root 10020: write_log (_T("MMU: %d\n"), model);
1.1.1.4 root 10021: return src;
10022: }
10023:
10024: #endif /* SAVESTATE */
10025:
1.1.1.7 root 10026: static void exception3f (uae_u32 opcode, uaecptr addr, bool writeaccess, bool instructionaccess, bool notinstruction, uaecptr pc, bool plus2)
1.1.1.4 root 10027: {
10028: if (currprefs.cpu_model >= 68040)
10029: addr &= ~1;
1.1.1.7 root 10030: if (currprefs.cpu_model >= 68020) {
10031: if (pc == 0xffffffff)
10032: last_addr_for_exception_3 = regs.instruction_pc;
10033: else
10034: last_addr_for_exception_3 = pc;
10035: } else if (pc == 0xffffffff) {
10036: last_addr_for_exception_3 = m68k_getpc ();
10037: if (plus2)
10038: last_addr_for_exception_3 += 2;
10039: } else {
10040: last_addr_for_exception_3 = pc;
10041: }
10042: last_fault_for_exception_3 = addr;
1.1.1.4 root 10043: last_op_for_exception_3 = opcode;
10044: last_writeaccess_for_exception_3 = writeaccess;
10045: last_instructionaccess_for_exception_3 = instructionaccess;
1.1.1.7 root 10046: last_notinstruction_for_exception_3 = notinstruction;
10047: Exception (3);
10048: #if EXCEPTION3_DEBUGGER
10049: activate_debugger();
10050: #endif
1.1.1.4 root 10051: }
10052:
1.1.1.7 root 10053: void exception3_notinstruction(uae_u32 opcode, uaecptr addr)
1.1.1.4 root 10054: {
1.1.1.7 root 10055: exception3f (opcode, addr, true, false, true, 0xffffffff, false);
1.1.1.4 root 10056: }
1.1.1.7 root 10057: void exception3_read(uae_u32 opcode, uaecptr addr)
10058: {
10059: exception3f (opcode, addr, false, 0, false, 0xffffffff, false);
10060: }
10061: void exception3_write(uae_u32 opcode, uaecptr addr)
10062: {
10063: exception3f (opcode, addr, true, 0, false, 0xffffffff, false);
10064: }
10065: void exception3i (uae_u32 opcode, uaecptr addr)
10066: {
10067: exception3f (opcode, addr, 0, 1, false, 0xffffffff, true);
10068: }
10069: void exception3b (uae_u32 opcode, uaecptr addr, bool w, bool i, uaecptr pc)
1.1.1.4 root 10070: {
1.1.1.7 root 10071: exception3f (opcode, addr, w, i, false, pc, true);
1.1.1.4 root 10072: }
10073:
1.1.1.10! root 10074: void exception2_setup(uaecptr addr, bool read, int size, uae_u32 fc)
! 10075: {
! 10076: last_addr_for_exception_3 = m68k_getpc() + bus_error_offset;
! 10077: last_fault_for_exception_3 = addr;
! 10078: last_writeaccess_for_exception_3 = read == 0;
! 10079: last_instructionaccess_for_exception_3 = (fc & 1) == 0;
! 10080: last_op_for_exception_3 = regs.opcode;
! 10081: last_notinstruction_for_exception_3 = exception_in_exception != 0;
! 10082: }
! 10083:
1.1.1.7 root 10084: void exception2 (uaecptr addr, bool read, int size, uae_u32 fc)
1.1.1.4 root 10085: {
1.1.1.7 root 10086: if (currprefs.mmu_model) {
10087: if (currprefs.mmu_model == 68030) {
10088: uae_u32 flags = size == 1 ? MMU030_SSW_SIZE_B : (size == 2 ? MMU030_SSW_SIZE_W : MMU030_SSW_SIZE_L);
10089: mmu030_page_fault (addr, read, flags, fc);
10090: } else {
1.1.1.9 root 10091: mmu_bus_error (addr, 0, fc, read == false, size, 0, true);
1.1.1.7 root 10092: }
10093: } else {
1.1.1.10! root 10094: exception2_setup(addr, read, size, fc);
1.1.1.7 root 10095: THROW(2);
10096: }
1.1.1.4 root 10097: }
10098:
10099: void cpureset (void)
10100: {
1.1.1.7 root 10101: /* RESET hasn't increased PC yet, 1 word offset */
1.1.1.4 root 10102: uaecptr pc;
1.1.1.7 root 10103: #ifndef WINUAE_FOR_HATARI
10104: uaecptr ksboot = 0xf80002 - 2;
1.1.1.4 root 10105: uae_u16 ins;
1.1.1.7 root 10106: #endif
10107: addrbank *ab;
1.1.1.4 root 10108:
1.1.1.10! root 10109: #ifndef WINUAE_FOR_HATARI
! 10110: if (currprefs.cpu_model == 68060 && currprefs.cpuboard_type == 0 && rtarea_base != 0xf00000) {
! 10111: // disable FPU at reset if no accelerator board and no $f0 ROM.
! 10112: regs.pcr |= 2;
! 10113: }
! 10114: #endif
1.1.1.7 root 10115: m68k_reset_delay = currprefs.reset_delay;
10116: set_special(SPCFLAG_CHECK);
10117: #ifndef WINUAE_FOR_HATARI
10118: send_internalevent(INTERNALEVENT_CPURESET);
1.1.1.8 root 10119: if ((currprefs.cpu_compatible || currprefs.cpu_memory_cycle_exact) && currprefs.cpu_model <= 68020) {
1.1.1.10! root 10120: custom_reset_cpu (false, false);
1.1.1.4 root 10121: return;
10122: }
1.1.1.7 root 10123: #endif
10124: pc = m68k_getpc () + 2;
10125: ab = &get_mem_bank (pc);
10126: if (ab->check (pc, 2)) {
10127: write_log (_T("CPU reset PC=%x (%s)..\n"), pc - 2, ab->name);
10128: #ifndef WINUAE_FOR_HATARI
10129: ins = get_word (pc);
1.1.1.10! root 10130: custom_reset_cpu(false, false);
1.1.1.7 root 10131: // did memory disappear under us?
10132: if (ab == &get_mem_bank (pc))
10133: return;
10134: // it did
10135: if ((ins & ~7) == 0x4ed0) {
10136: int reg = ins & 7;
10137: uae_u32 addr = m68k_areg (regs, reg);
10138: if (addr < 0x80000)
10139: addr += 0xf80000;
10140: write_log (_T("reset/jmp (ax) combination at %08x emulated -> %x\n"), pc, addr);
10141: m68k_setpc_normal (addr - 2);
1.1.1.4 root 10142: return;
10143: }
1.1.1.7 root 10144: #else
10145: customreset (); /* From hatari-glue.c */
10146: return;
10147: #endif
10148: }
10149: // the best we can do, jump directly to ROM entrypoint
10150: // (which is probably what program wanted anyway)
10151: #ifndef WINUAE_FOR_HATARI
10152: write_log (_T("CPU Reset PC=%x (%s), invalid memory -> %x.\n"), pc, ab->name, ksboot + 2);
1.1.1.10! root 10153: custom_reset_cpu (false, false);
1.1.1.7 root 10154: m68k_setpc_normal (ksboot);
10155: #else
10156: write_log (_T("CPU Reset PC=%x (%s), invalid memory\n"), pc, ab->name);
10157: customreset (); /* From hatari-glue.c */
10158: #endif
1.1.1.4 root 10159: }
10160:
10161:
10162: void m68k_setstopped (void)
10163: {
10164: /* A traced STOP instruction drops through immediately without
10165: actually stopping. */
1.1.1.8 root 10166: if ((regs.spcflags & SPCFLAG_DOTRACE) == 0) {
10167: m68k_set_stop();
10168: } else {
1.1.1.4 root 10169: m68k_resumestopped ();
1.1.1.8 root 10170: }
1.1.1.4 root 10171: }
10172:
10173: void m68k_resumestopped (void)
10174: {
10175: if (!regs.stopped)
10176: return;
1.1.1.8 root 10177: if (currprefs.cpu_cycle_exact && currprefs.cpu_model == 68000) {
10178: x_do_cycles (6 * cpucycleunit);
1.1.1.4 root 10179: }
1.1.1.7 root 10180: fill_prefetch ();
1.1.1.8 root 10181: m68k_unset_stop();
10182: }
10183:
10184:
10185: uae_u32 mem_access_delay_word_read (uaecptr addr)
10186: {
10187: uae_u32 v;
10188: //#ifndef WINUAE_FOR_HATARI
1.1.1.9 root 10189: if ( BlitterPhase ) Blitter_HOG_CPU_mem_access_before ( 1 ); // WINUAE_FOR_HATARI
1.1.1.8 root 10190: #if 1
10191: switch (ce_banktype[addr >> 16])
10192: {
10193: case CE_MEMBANK_CHIP16:
10194: case CE_MEMBANK_CHIP32:
10195: v = wait_cpu_cycle_read (addr, 1);
10196: break;
10197: case CE_MEMBANK_FAST16:
10198: case CE_MEMBANK_FAST32:
10199: v = get_word (addr);
10200: x_do_cycles_post (4 * cpucycleunit, v);
10201: break;
10202: default:
10203: v = get_word (addr);
10204: break;
10205: }
10206: #else
10207: //fprintf ( stderr , "word read mis %lu %lu\n" , currcycle / cpucycleunit , currcycle );
10208: v = get_word (addr);
10209: x_do_cycles_post (4 * cpucycleunit, v);
10210: #endif
10211: regs.db = v;
1.1.1.9 root 10212: if ( BlitterPhase ) Blitter_HOG_CPU_mem_access_after ( 1 ); // WINUAE_FOR_HATARI
1.1.1.8 root 10213: return v;
10214: }
10215: uae_u32 mem_access_delay_wordi_read (uaecptr addr)
10216: {
10217: uae_u32 v;
10218: //#ifndef WINUAE_FOR_HATARI
1.1.1.9 root 10219: if ( BlitterPhase ) Blitter_HOG_CPU_mem_access_before ( 1 ); // WINUAE_FOR_HATARI
1.1.1.8 root 10220: #if 1
10221: switch (ce_banktype[addr >> 16])
10222: {
10223: case CE_MEMBANK_CHIP16:
10224: case CE_MEMBANK_CHIP32:
10225: v = wait_cpu_cycle_read (addr, 2);
10226: break;
10227: case CE_MEMBANK_FAST16:
10228: case CE_MEMBANK_FAST32:
10229: v = get_wordi (addr);
10230: x_do_cycles_post (4 * cpucycleunit, v);
10231: break;
10232: default:
10233: v = get_wordi (addr);
10234: break;
10235: }
10236: #else
10237: //fprintf ( stderr , "wordi read mis %lu %lu\n" , currcycle / cpucycleunit , currcycle );
10238: v = get_wordi (addr);
10239: x_do_cycles_post (4 * cpucycleunit, v);
10240: #endif
10241: regs.db = v;
1.1.1.9 root 10242: if ( BlitterPhase ) Blitter_HOG_CPU_mem_access_after ( 1 ); // WINUAE_FOR_HATARI
1.1.1.8 root 10243: return v;
10244: }
10245:
10246: uae_u32 mem_access_delay_byte_read (uaecptr addr)
10247: {
10248: uae_u32 v;
10249: //#ifndef WINUAE_FOR_HATARI
1.1.1.9 root 10250: if ( BlitterPhase ) Blitter_HOG_CPU_mem_access_before ( 1 ); // WINUAE_FOR_HATARI
1.1.1.8 root 10251: #if 1
10252: switch (ce_banktype[addr >> 16])
10253: {
10254: case CE_MEMBANK_CHIP16:
10255: case CE_MEMBANK_CHIP32:
10256: v = wait_cpu_cycle_read (addr, 0);
10257: break;
10258: case CE_MEMBANK_FAST16:
10259: case CE_MEMBANK_FAST32:
10260: v = get_byte (addr);
10261: x_do_cycles_post (4 * cpucycleunit, v);
10262: break;
10263: default:
10264: v = get_byte (addr);
10265: break;
10266: }
10267: #else
10268: //fprintf ( stderr , "byte read mis %lu %lu\n" , currcycle / cpucycleunit , currcycle );
10269: v = get_byte (addr);
10270: x_do_cycles_post (4 * cpucycleunit, v);
10271: #endif
10272: regs.db = (v << 8) | v;
1.1.1.9 root 10273: if ( BlitterPhase ) Blitter_HOG_CPU_mem_access_after ( 1 ); // WINUAE_FOR_HATARI
1.1.1.8 root 10274: return v;
10275: }
10276: void mem_access_delay_byte_write (uaecptr addr, uae_u32 v)
10277: {
10278: regs.db = (v << 8) | v;
10279: //#ifndef WINUAE_FOR_HATARI
1.1.1.9 root 10280: if ( BlitterPhase ) Blitter_HOG_CPU_mem_access_before ( 1 ); // WINUAE_FOR_HATARI
1.1.1.8 root 10281: #if 1
10282: switch (ce_banktype[addr >> 16])
10283: {
10284: case CE_MEMBANK_CHIP16:
10285: case CE_MEMBANK_CHIP32:
10286: wait_cpu_cycle_write (addr, 0, v);
1.1.1.9 root 10287: if ( BlitterPhase ) Blitter_HOG_CPU_mem_access_after ( 1 ); // WINUAE_FOR_HATARI
1.1.1.8 root 10288: return;
10289: case CE_MEMBANK_FAST16:
10290: case CE_MEMBANK_FAST32:
10291: put_byte (addr, v);
10292: x_do_cycles_post (4 * cpucycleunit, v);
1.1.1.9 root 10293: if ( BlitterPhase ) Blitter_HOG_CPU_mem_access_after ( 1 ); // WINUAE_FOR_HATARI
1.1.1.8 root 10294: return;
10295: }
10296: put_byte (addr, v);
10297: #else
10298: put_byte (addr, v);
10299: x_do_cycles_post (4 * cpucycleunit, v);
10300: #endif
10301: }
10302: void mem_access_delay_word_write (uaecptr addr, uae_u32 v)
10303: {
10304: //#ifndef WINUAE_FOR_HATARI
1.1.1.9 root 10305: if ( BlitterPhase ) Blitter_HOG_CPU_mem_access_before ( 1 ); // WINUAE_FOR_HATARI
1.1.1.8 root 10306: #if 1
10307: regs.db = v;
10308: switch (ce_banktype[addr >> 16])
10309: {
10310: case CE_MEMBANK_CHIP16:
10311: case CE_MEMBANK_CHIP32:
10312: wait_cpu_cycle_write (addr, 1, v);
1.1.1.9 root 10313: if ( BlitterPhase ) Blitter_HOG_CPU_mem_access_after ( 1 ); // WINUAE_FOR_HATARI
1.1.1.8 root 10314: return;
10315: case CE_MEMBANK_FAST16:
10316: case CE_MEMBANK_FAST32:
10317: put_word (addr, v);
10318: x_do_cycles_post (4 * cpucycleunit, v);
1.1.1.9 root 10319: if ( BlitterPhase ) Blitter_HOG_CPU_mem_access_after ( 1 ); // WINUAE_FOR_HATARI
1.1.1.8 root 10320: return;
10321: }
10322: put_word (addr, v);
10323: #else
10324: put_word (addr, v);
10325: x_do_cycles_post (4 * cpucycleunit, v);
10326: #endif
1.1.1.4 root 10327: }
10328:
1.1.1.9 root 10329: static void start_020_cycle(void)
10330: {
10331: regs.ce020startcycle = get_cycles();
10332: }
10333:
10334: static void start_020_cycle_prefetch(bool opcode)
10335: {
10336: regs.ce020startcycle = get_cycles();
10337: // back to back prefetch cycles require 2 extra cycles (maybe)
10338: if (opcode && regs.ce020startcycle == regs.ce020prefetchendcycle && currprefs.cpu_cycle_exact) {
10339: x_do_cycles(2 * cpucycleunit);
10340: regs.ce020startcycle = get_cycles();
10341: }
10342: }
10343: static void end_020_cycle(void)
10344: {
10345: regs.ce020endcycle = get_cycles();
10346: }
10347: static void end_020_cycle_prefetch(bool opcode)
10348: {
10349: regs.ce020endcycle = get_cycles();
10350: if (opcode) {
10351: regs.ce020prefetchendcycle = regs.ce020endcycle;
10352: } else {
10353: regs.ce020prefetchendcycle = regs.ce020startcycle;
10354: }
10355: }
1.1.1.8 root 10356:
1.1.1.4 root 10357: // this one is really simple and easy
1.1.1.9 root 10358: static void fill_icache020 (uae_u32 addr, bool opcode)
1.1.1.4 root 10359: {
10360: int index;
10361: uae_u32 tag;
10362: uae_u32 data;
10363: struct cache020 *c;
10364:
1.1.1.9 root 10365: regs.fc030 = (regs.s ? 4 : 0) | 2;
1.1.1.4 root 10366: addr &= ~3;
1.1.1.7 root 10367: if (regs.cacheholdingaddr020 == addr)
10368: return;
1.1.1.4 root 10369: index = (addr >> 2) & (CACHELINES020 - 1);
10370: tag = regs.s | (addr & ~((CACHELINES020 << 2) - 1));
10371: c = &caches020[index];
1.1.1.9 root 10372: if ((regs.cacr & 1) && c->valid && c->tag == tag) {
1.1.1.4 root 10373: // cache hit
1.1.1.7 root 10374: regs.cacheholdingaddr020 = addr;
10375: regs.cacheholdingdata020 = c->data;
1.1.1.9 root 10376: regs.cacheholdingdata_valid = true;
1.1.1.7 root 10377: #ifdef WINUAE_FOR_HATARI
10378: CpuInstruction.I_Cache_hit++;
10379: #endif
1.1.1.4 root 10380: return;
10381: }
1.1.1.9 root 10382:
1.1.1.4 root 10383: // cache miss
1.1.1.9 root 10384: #if 0
1.1.1.7 root 10385: // Prefetch apparently can be queued by bus controller
10386: // even if bus controller is currently processing
10387: // previous data access.
10388: // Other combinations are not possible.
1.1.1.9 root 10389: if (!regs.ce020memcycle_data) {
10390: if (regs.ce020memcycles > 0)
10391: x_do_cycles (regs.ce020memcycles);
1.1.1.7 root 10392: regs.ce020memcycles = 0;
1.1.1.9 root 10393: }
10394: #endif
10395:
10396: start_020_cycle_prefetch(opcode);
10397: data = icache_fetch(addr);
10398: end_020_cycle_prefetch(opcode);
10399:
10400: // enabled and not frozen
10401: if ((regs.cacr & 1) && !(regs.cacr & 2)) {
1.1.1.4 root 10402: c->tag = tag;
1.1.1.9 root 10403: c->valid = true;
1.1.1.4 root 10404: c->data = data;
10405: }
1.1.1.7 root 10406: regs.cacheholdingaddr020 = addr;
10407: regs.cacheholdingdata020 = data;
1.1.1.9 root 10408: regs.cacheholdingdata_valid = true;
1.1.1.7 root 10409: #ifdef WINUAE_FOR_HATARI
10410: CpuInstruction.I_Cache_miss++;
10411: #endif
1.1.1.4 root 10412: }
10413:
1.1.1.7 root 10414: #if MORE_ACCURATE_68020_PIPELINE
10415: #define PIPELINE_DEBUG 0
10416: #if PIPELINE_DEBUG
10417: static uae_u16 pipeline_opcode;
10418: #endif
1.1.1.9 root 10419: static void pipeline_020(uaecptr pc)
1.1.1.4 root 10420: {
1.1.1.9 root 10421: uae_u16 w = regs.prefetch020[1];
10422: if (regs.prefetch020_valid[1] == 0) {
10423: regs.pipeline_stop = -1;
10424: return;
10425: }
1.1.1.7 root 10426: if (regs.pipeline_pos < 0)
10427: return;
10428: if (regs.pipeline_pos > 0) {
10429: // handle annoying 68020+ addressing modes
10430: if (regs.pipeline_pos == regs.pipeline_r8[0]) {
10431: regs.pipeline_r8[0] = 0;
10432: if (w & 0x100) {
10433: int extra = 0;
10434: if ((w & 0x30) == 0x20)
10435: extra += 2;
10436: if ((w & 0x30) == 0x30)
10437: extra += 4;
10438: if ((w & 0x03) == 0x02)
10439: extra += 2;
10440: if ((w & 0x03) == 0x03)
10441: extra += 4;
10442: regs.pipeline_pos += extra;
10443: }
10444: return;
10445: }
10446: if (regs.pipeline_pos == regs.pipeline_r8[1]) {
10447: regs.pipeline_r8[1] = 0;
10448: if (w & 0x100) {
10449: int extra = 0;
10450: if ((w & 0x30) == 0x20)
10451: extra += 2;
10452: if ((w & 0x30) == 0x30)
10453: extra += 4;
10454: if ((w & 0x03) == 0x02)
10455: extra += 2;
10456: if ((w & 0x03) == 0x03)
10457: extra += 4;
10458: regs.pipeline_pos += extra;
1.1.1.4 root 10459: }
1.1.1.7 root 10460: return;
10461: }
10462: }
10463: if (regs.pipeline_pos > 2) {
10464: regs.pipeline_pos -= 2;
10465: // If stop set, prefetches stop 1 word early.
10466: if (regs.pipeline_stop > 0 && regs.pipeline_pos == 2)
10467: regs.pipeline_stop = -1;
10468: return;
10469: }
10470: if (regs.pipeline_stop) {
10471: regs.pipeline_stop = -1;
10472: return;
10473: }
10474: #if PIPELINE_DEBUG
10475: pipeline_opcode = w;
10476: #endif
10477: regs.pipeline_r8[0] = cpudatatbl[w].disp020[0];
10478: regs.pipeline_r8[1] = cpudatatbl[w].disp020[1];
10479: regs.pipeline_pos = cpudatatbl[w].length;
10480: #if PIPELINE_DEBUG
10481: if (!regs.pipeline_pos) {
10482: write_log(_T("Opcode %04x has no size PC=%08x!\n"), w, pc);
10483: }
10484: #endif
1.1.1.8 root 10485: // illegal instructions, TRAP, TRAPV, A-line, F-line don't stop prefetches
1.1.1.7 root 10486: int branch = cpudatatbl[w].branch;
10487: if (regs.pipeline_pos > 0 && branch) {
10488: // Short branches (Bcc.s) still do one more prefetch.
10489: #if 0
10490: // RTS and other unconditional single opcode instruction stop immediately.
10491: if (branch == 2) {
10492: // Immediate stop
10493: regs.pipeline_stop = -1;
10494: } else {
10495: // Stop 1 word early than normally
10496: regs.pipeline_stop = 1;
1.1.1.4 root 10497: }
1.1.1.7 root 10498: #else
10499: regs.pipeline_stop = 1;
10500: #endif
1.1.1.4 root 10501: }
10502: }
10503:
1.1.1.7 root 10504: #endif
1.1.1.4 root 10505:
1.1.1.9 root 10506: static uae_u32 get_word_ce020_prefetch_2 (int o, bool opcode)
1.1.1.4 root 10507: {
1.1.1.7 root 10508: uae_u32 pc = m68k_getpc () + o;
10509: uae_u32 v;
1.1.1.4 root 10510:
1.1.1.9 root 10511: v = regs.prefetch020[0];
10512: regs.prefetch020[0] = regs.prefetch020[1];
10513: regs.prefetch020[1] = regs.prefetch020[2];
1.1.1.7 root 10514: #if MORE_ACCURATE_68020_PIPELINE
1.1.1.9 root 10515: pipeline_020(pc);
1.1.1.7 root 10516: #endif
1.1.1.9 root 10517: if (pc & 2) {
1.1.1.7 root 10518: // branch instruction detected in pipeline: stop fetches until branch executed.
10519: if (!MORE_ACCURATE_68020_PIPELINE || regs.pipeline_stop >= 0) {
1.1.1.9 root 10520: fill_icache020 (pc + 2 + 4, opcode);
1.1.1.4 root 10521: }
1.1.1.9 root 10522: regs.prefetch020[2] = regs.cacheholdingdata020 >> 16;
1.1.1.7 root 10523: } else {
1.1.1.9 root 10524: regs.prefetch020[2] = (uae_u16)regs.cacheholdingdata020;
1.1.1.4 root 10525: }
1.1.1.7 root 10526: do_cycles_ce020_internal (2);
1.1.1.9 root 10527: regs.db = regs.prefetch020[0];
1.1.1.7 root 10528: return v;
1.1.1.4 root 10529: }
10530:
1.1.1.9 root 10531: uae_u32 get_word_ce020_prefetch (int o)
10532: {
10533: return get_word_ce020_prefetch_2(o, false);
10534: }
10535:
10536: uae_u32 get_word_ce020_prefetch_opcode (int o)
10537: {
10538: return get_word_ce020_prefetch_2(o, true);
10539: }
10540:
1.1.1.7 root 10541: uae_u32 get_word_020_prefetch (int o)
1.1.1.4 root 10542: {
1.1.1.7 root 10543: uae_u32 pc = m68k_getpc () + o;
10544: uae_u32 v;
1.1.1.4 root 10545:
1.1.1.9 root 10546: v = regs.prefetch020[0];
10547: regs.prefetch020[0] = regs.prefetch020[1];
10548: regs.prefetch020[1] = regs.prefetch020[2];
1.1.1.7 root 10549: #if MORE_ACCURATE_68020_PIPELINE
1.1.1.9 root 10550: pipeline_020(pc);
1.1.1.7 root 10551: #endif
1.1.1.9 root 10552: if (pc & 2) {
10553: // branch instruction detected in pipeline: stop fetches until branch executed.
1.1.1.7 root 10554: if (!MORE_ACCURATE_68020_PIPELINE || regs.pipeline_stop >= 0) {
1.1.1.9 root 10555: fill_icache020 (pc + 2 + 4, false);
1.1.1.7 root 10556: }
1.1.1.9 root 10557: regs.prefetch020[2] = regs.cacheholdingdata020 >> 16;
1.1.1.7 root 10558: } else {
1.1.1.9 root 10559: regs.prefetch020[2] = (uae_u16)regs.cacheholdingdata020;
1.1.1.7 root 10560: }
1.1.1.9 root 10561: regs.db = regs.prefetch020[0];
1.1.1.7 root 10562: //if ( ( v & 0xffff ) != ( get_word(pc) & 0xffff ) )
10563: // fprintf ( stderr , "prefetch mismatch pc=%x prefetch=%x != mem=%x, i-cache error ?\n" , pc , v&0xffff , get_word(pc)&0xffff );
10564: return v;
10565: }
1.1.1.4 root 10566:
1.1.1.7 root 10567: // these are also used by 68030.
1.1.1.4 root 10568:
1.1.1.9 root 10569: #if 0
1.1.1.7 root 10570: #define RESET_CE020_CYCLES \
10571: regs.ce020memcycles = 0; \
10572: regs.ce020memcycle_data = true;
10573: #define STORE_CE020_CYCLES \
10574: unsigned long cycs = get_cycles ()
10575: #define ADD_CE020_CYCLES \
10576: regs.ce020memcycles += get_cycles () - cycs
1.1.1.9 root 10577: #endif
1.1.1.4 root 10578:
1.1.1.7 root 10579: uae_u32 mem_access_delay_long_read_ce020 (uaecptr addr)
10580: {
10581: uae_u32 v;
1.1.1.9 root 10582: //fprintf ( stderr , "long read ce020 %lu %lu\n" , currcycle / cpucycleunit , currcycle );
10583: start_020_cycle();
1.1.1.7 root 10584: switch (ce_banktype[addr >> 16])
10585: {
10586: case CE_MEMBANK_CHIP16:
10587: v = wait_cpu_cycle_read_ce020 (addr + 0, 1) << 16;
10588: v |= wait_cpu_cycle_read_ce020 (addr + 2, 1) << 0;
10589: break;
10590: case CE_MEMBANK_CHIP32:
10591: if ((addr & 3) != 0) {
10592: v = wait_cpu_cycle_read_ce020 (addr + 0, 1) << 16;
10593: v |= wait_cpu_cycle_read_ce020 (addr + 2, 1) << 0;
10594: } else {
10595: v = wait_cpu_cycle_read_ce020 (addr, -1);
10596: }
10597: break;
10598: case CE_MEMBANK_FAST32:
10599: v = get_long (addr);
10600: if ((addr & 3) != 0)
10601: do_cycles_ce020_mem (2 * CPU020_MEM_CYCLE, v);
10602: else
10603: do_cycles_ce020_mem (1 * CPU020_MEM_CYCLE, v);
10604: break;
10605: case CE_MEMBANK_FAST16:
10606: v = get_long (addr);
10607: do_cycles_ce020_mem (2 * CPU020_MEM_CYCLE, v);
10608: break;
10609: default:
10610: v = get_long (addr);
10611: break;
10612: }
1.1.1.9 root 10613: //fprintf ( stderr , "long read2 ce020 %lu %lu\n" , currcycle / cpucycleunit , currcycle );
10614: end_020_cycle();
10615: //fprintf ( stderr , "long read3 ce020 %lu %lu\n" , currcycle / cpucycleunit , currcycle );
1.1.1.7 root 10616: return v;
10617: }
10618:
10619: uae_u32 mem_access_delay_longi_read_ce020 (uaecptr addr)
10620: {
10621: uae_u32 v;
10622: switch (ce_banktype[addr >> 16])
10623: {
10624: case CE_MEMBANK_CHIP16:
1.1.1.8 root 10625: v = wait_cpu_cycle_read_ce020 (addr + 0, 2) << 16;
10626: v |= wait_cpu_cycle_read_ce020 (addr + 2, 2) << 0;
1.1.1.7 root 10627: break;
10628: case CE_MEMBANK_CHIP32:
10629: if ((addr & 3) != 0) {
1.1.1.8 root 10630: v = wait_cpu_cycle_read_ce020 (addr + 0, 2) << 16;
10631: v |= wait_cpu_cycle_read_ce020 (addr + 2, 2) << 0;
1.1.1.7 root 10632: } else {
1.1.1.8 root 10633: v = wait_cpu_cycle_read_ce020 (addr, -2);
1.1.1.7 root 10634: }
10635: break;
10636: case CE_MEMBANK_FAST32:
10637: v = get_longi (addr);
10638: if ((addr & 3) != 0)
10639: do_cycles_ce020_mem (2 * CPU020_MEM_CYCLE, v);
10640: else
10641: do_cycles_ce020_mem (1 * CPU020_MEM_CYCLE, v);
10642: break;
10643: case CE_MEMBANK_FAST16:
10644: v = get_longi (addr);
10645: do_cycles_ce020_mem (2 * CPU020_MEM_CYCLE, v);
10646: break;
10647: default:
10648: v = get_longi (addr);
10649: break;
10650: }
10651: return v;
10652: }
10653:
1.1.1.9 root 10654: uae_u32 mem_access_delay_wordi_read_ce020 (uaecptr addr)
10655: {
10656: uae_u32 v;
10657: start_020_cycle();
10658: switch (ce_banktype[addr >> 16])
10659: {
10660: case CE_MEMBANK_CHIP16:
10661: case CE_MEMBANK_CHIP32:
10662: if ((addr & 3) == 3) {
10663: v = wait_cpu_cycle_read_ce020 (addr + 0, 0) << 8;
10664: v |= wait_cpu_cycle_read_ce020 (addr + 1, 0) << 0;
10665: } else {
10666: v = wait_cpu_cycle_read_ce020 (addr, 1);
10667: }
10668: break;
10669: case CE_MEMBANK_FAST16:
10670: case CE_MEMBANK_FAST32:
10671: v = get_wordi (addr);
10672: if ((addr & 3) == 3)
10673: do_cycles_ce020_mem (2 * CPU020_MEM_CYCLE, v);
10674: else
10675: do_cycles_ce020_mem (1 * CPU020_MEM_CYCLE, v);
10676: break;
10677: default:
10678: v = get_wordi (addr);
10679: break;
10680: }
10681: end_020_cycle();
10682: return v;
10683: }
10684:
1.1.1.7 root 10685: uae_u32 mem_access_delay_word_read_ce020 (uaecptr addr)
10686: {
10687: uae_u32 v;
1.1.1.9 root 10688: start_020_cycle();
1.1.1.7 root 10689: switch (ce_banktype[addr >> 16])
10690: {
10691: case CE_MEMBANK_CHIP16:
10692: case CE_MEMBANK_CHIP32:
10693: if ((addr & 3) == 3) {
10694: v = wait_cpu_cycle_read_ce020 (addr + 0, 0) << 8;
10695: v |= wait_cpu_cycle_read_ce020 (addr + 1, 0) << 0;
10696: } else {
10697: v = wait_cpu_cycle_read_ce020 (addr, 1);
10698: }
10699: break;
10700: case CE_MEMBANK_FAST16:
10701: case CE_MEMBANK_FAST32:
10702: v = get_word (addr);
10703: if ((addr & 3) == 3)
10704: do_cycles_ce020_mem (2 * CPU020_MEM_CYCLE, v);
10705: else
10706: do_cycles_ce020_mem (1 * CPU020_MEM_CYCLE, v);
10707: break;
10708: default:
10709: v = get_word (addr);
10710: break;
10711: }
1.1.1.9 root 10712: end_020_cycle();
1.1.1.7 root 10713: return v;
10714: }
10715:
10716: uae_u32 mem_access_delay_byte_read_ce020 (uaecptr addr)
10717: {
10718: uae_u32 v;
1.1.1.9 root 10719: start_020_cycle();
1.1.1.7 root 10720: switch (ce_banktype[addr >> 16])
10721: {
10722: case CE_MEMBANK_CHIP16:
10723: case CE_MEMBANK_CHIP32:
10724: v = wait_cpu_cycle_read_ce020 (addr, 0);
10725: break;
10726: case CE_MEMBANK_FAST16:
10727: case CE_MEMBANK_FAST32:
10728: v = get_byte (addr);
10729: do_cycles_ce020_mem (1 * CPU020_MEM_CYCLE, v);
10730: break;
10731: default:
10732: v = get_byte (addr);
10733: break;
10734: }
1.1.1.9 root 10735: end_020_cycle();
1.1.1.7 root 10736: return v;
10737: }
10738:
10739: void mem_access_delay_byte_write_ce020 (uaecptr addr, uae_u32 v)
10740: {
1.1.1.9 root 10741: start_020_cycle();
1.1.1.7 root 10742: switch (ce_banktype[addr >> 16])
10743: {
10744: case CE_MEMBANK_CHIP16:
10745: case CE_MEMBANK_CHIP32:
10746: wait_cpu_cycle_write_ce020 (addr, 0, v);
10747: break;
10748: case CE_MEMBANK_FAST16:
10749: case CE_MEMBANK_FAST32:
10750: put_byte (addr, v);
10751: do_cycles_ce020_mem (1 * CPU020_MEM_CYCLE, v);
10752: break;
10753: default:
10754: put_byte (addr, v);
10755: break;
1.1.1.4 root 10756: }
1.1.1.9 root 10757: end_020_cycle();
1.1.1.7 root 10758: }
10759:
10760: void mem_access_delay_word_write_ce020 (uaecptr addr, uae_u32 v)
10761: {
1.1.1.9 root 10762: start_020_cycle();
1.1.1.7 root 10763: switch (ce_banktype[addr >> 16])
10764: {
10765: case CE_MEMBANK_CHIP16:
10766: case CE_MEMBANK_CHIP32:
10767: if ((addr & 3) == 3) {
10768: wait_cpu_cycle_write_ce020 (addr + 0, 0, (v >> 8) & 0xff);
10769: wait_cpu_cycle_write_ce020 (addr + 1, 0, (v >> 0) & 0xff);
10770: } else {
10771: wait_cpu_cycle_write_ce020 (addr + 0, 1, v);
10772: }
10773: break;
10774: case CE_MEMBANK_FAST16:
10775: case CE_MEMBANK_FAST32:
10776: put_word (addr, v);
10777: if ((addr & 3) == 3)
10778: do_cycles_ce020_mem (2 * CPU020_MEM_CYCLE, v);
10779: else
10780: do_cycles_ce020_mem (1 * CPU020_MEM_CYCLE, v);
10781: break;
10782: default:
10783: put_word (addr, v);
10784: break;
10785: }
1.1.1.9 root 10786: end_020_cycle();
1.1.1.7 root 10787: }
10788:
10789: void mem_access_delay_long_write_ce020 (uaecptr addr, uae_u32 v)
10790: {
1.1.1.9 root 10791: start_020_cycle();
1.1.1.7 root 10792: switch (ce_banktype[addr >> 16])
10793: {
10794: case CE_MEMBANK_CHIP16:
10795: wait_cpu_cycle_write_ce020 (addr + 0, 1, (v >> 16) & 0xffff);
10796: wait_cpu_cycle_write_ce020 (addr + 2, 1, (v >> 0) & 0xffff);
10797: break;
10798: case CE_MEMBANK_CHIP32:
10799: if ((addr & 3) == 3) {
10800: wait_cpu_cycle_write_ce020 (addr + 0, 1, (v >> 16) & 0xffff);
10801: wait_cpu_cycle_write_ce020 (addr + 2, 1, (v >> 0) & 0xffff);
10802: } else {
10803: wait_cpu_cycle_write_ce020 (addr + 0, -1, v);
10804: }
10805: break;
10806: case CE_MEMBANK_FAST32:
10807: put_long (addr, v);
10808: if ((addr & 3) != 0)
10809: do_cycles_ce020_mem (2 * CPU020_MEM_CYCLE, v);
10810: else
10811: do_cycles_ce020_mem (1 * CPU020_MEM_CYCLE, v);
10812: break;
10813: case CE_MEMBANK_FAST16:
10814: put_long (addr, v);
10815: do_cycles_ce020_mem (2 * CPU020_MEM_CYCLE, v);
10816: break;
10817: default:
10818: put_long (addr, v);
10819: break;
10820: }
1.1.1.9 root 10821: end_020_cycle();
1.1.1.7 root 10822: }
10823:
10824:
10825: // 68030 caches aren't so simple as 68020 cache..
1.1.1.10! root 10826:
1.1.1.9 root 10827: STATIC_INLINE struct cache030 *geticache030 (struct cache030 *cp, uaecptr addr, uae_u32 *tagp, int *lwsp)
1.1.1.7 root 10828: {
10829: int index, lws;
10830: uae_u32 tag;
10831: struct cache030 *c;
10832:
10833: addr &= ~3;
10834: index = (addr >> 4) & (CACHELINES030 - 1);
10835: tag = regs.s | (addr & ~((CACHELINES030 << 4) - 1));
10836: lws = (addr >> 2) & 3;
10837: c = &cp[index];
10838: *tagp = tag;
10839: *lwsp = lws;
1.1.1.9 root 10840: //fprintf ( stderr , "getcache addr=%x index=%x tag=%x lws=%x\n" , addr , index , tag , lws );
10841: return c;
10842: }
10843:
10844: STATIC_INLINE void update_icache030 (struct cache030 *c, uae_u32 val, uae_u32 tag, int lws)
10845: {
10846: if (c->tag != tag)
10847: c->valid[0] = c->valid[1] = c->valid[2] = c->valid[3] = false;
10848: c->tag = tag;
10849: c->valid[lws] = true;
10850: c->data[lws] = val;
10851: }
10852:
10853: STATIC_INLINE struct cache030 *getdcache030 (struct cache030 *cp, uaecptr addr, uae_u32 *tagp, int *lwsp)
10854: {
10855: int index, lws;
10856: uae_u32 tag;
10857: struct cache030 *c;
10858:
10859: addr &= ~3;
10860: index = (addr >> 4) & (CACHELINES030 - 1);
10861: tag = addr & ~((CACHELINES030 << 4) - 1);
10862: lws = (addr >> 2) & 3;
10863: c = &cp[index];
10864: *tagp = tag;
10865: *lwsp = lws;
1.1.1.7 root 10866: return c;
10867: }
10868:
1.1.1.9 root 10869: STATIC_INLINE void update_dcache030 (struct cache030 *c, uae_u32 val, uae_u32 tag, uae_u8 fc, int lws)
1.1.1.7 root 10870: {
10871: if (c->tag != tag)
10872: c->valid[0] = c->valid[1] = c->valid[2] = c->valid[3] = false;
10873: c->tag = tag;
1.1.1.9 root 10874: c->fc = fc;
1.1.1.7 root 10875: c->valid[lws] = true;
10876: c->data[lws] = val;
10877: }
10878:
10879: static void fill_icache030 (uae_u32 addr)
10880: {
10881: int lws;
10882: uae_u32 tag;
10883: uae_u32 data;
10884: struct cache030 *c;
1.1.1.9 root 10885: //fprintf ( stderr , "fill icache030 %x %x %x\n" , addr , regs.cacr , regs.cacheholdingaddr020 );
1.1.1.7 root 10886:
1.1.1.9 root 10887: regs.fc030 = (regs.s ? 4 : 0) | 2;
1.1.1.7 root 10888: addr &= ~3;
1.1.1.9 root 10889: if (regs.cacheholdingaddr020 == addr || regs.cacheholdingdata_valid == 0)
1.1.1.7 root 10890: return;
1.1.1.9 root 10891: c = geticache030 (icaches030, addr, &tag, &lws);
10892: if ((regs.cacr & 1) && c->valid[lws] && c->tag == tag) {
1.1.1.7 root 10893: // cache hit
10894: regs.cacheholdingaddr020 = addr;
10895: regs.cacheholdingdata020 = c->data[lws];
1.1.1.9 root 10896: //fprintf ( stderr , "fill ica %x -> hit %x %x\n" , addr , regs.cacheholdingdata020 , regs.cacr );
1.1.1.7 root 10897: #ifdef WINUAE_FOR_HATARI
10898: CpuInstruction.I_Cache_hit++;
1.1.1.4 root 10899: #endif
1.1.1.7 root 10900: return;
10901: }
10902:
1.1.1.9 root 10903: TRY (prb2) {
10904: // cache miss
10905: if (currprefs.cpu_cycle_exact) {
10906: regs.ce020memcycle_data = false;
10907: start_020_cycle_prefetch(false);
10908: data = icache_fetch(addr);
10909: end_020_cycle_prefetch(false);
10910: } else {
10911: data = icache_fetch(addr);
10912: }
10913: } CATCH (prb2) {
10914: // Bus error/MMU access fault: Delayed exception.
10915: regs.cacheholdingdata_valid = 0;
10916: regs.cacheholdingaddr020 = 0xffffffff;
10917: regs.cacheholdingdata020 = 0xffffffff;
10918: end_020_cycle_prefetch(false);
1.1.1.10! root 10919: STOPTRY;
1.1.1.9 root 10920: return;
10921: } ENDTRY
10922:
10923: if (mmu030_cache_state & CACHE_ENABLE_INS) {
10924: if ((regs.cacr & 0x03) == 0x01) {
10925: // instruction cache not frozen and enabled
1.1.1.7 root 10926: //fprintf ( stderr , "fill ica %x -> update %x\n" , addr , data );
1.1.1.9 root 10927: update_icache030 (c, data, tag, lws);
10928: }
10929: if ((mmu030_cache_state & CACHE_ENABLE_INS_BURST) && (regs.cacr & 0x11) == 0x11 && (c->valid[0] + c->valid[1] + c->valid[2] + c->valid[3] == 1)) {
1.1.1.7 root 10930: //fprintf ( stderr , "fill ica %x -> burst %x\n" , addr , data );
1.1.1.9 root 10931: // do burst fetch if cache enabled, not frozen, all slots invalid, no chip ram
10932: int i;
10933: for (i = 0; i < 4; i++) {
10934: if (c->valid[i])
10935: break;
10936: }
10937: uaecptr baddr = addr & ~15;
10938: if (currprefs.mmu_model) {
10939: TRY (prb) {
10940: if (currprefs.cpu_cycle_exact)
10941: #ifndef WINUAE_FOR_HATARI
10942: do_cycles_ce020(3 * (CPU020_MEM_CYCLE - 1));
10943: #else
10944: do_cycles_ce020_long(3 * (CPU020_MEM_CYCLE - 1));
10945: #endif
1.1.1.10! root 10946: for (int j = 0; j < 3; j++) {
1.1.1.9 root 10947: i++;
10948: i &= 3;
10949: c->data[i] = icache_fetch(baddr + i * 4);
10950: c->valid[i] = true;
10951: }
10952: } CATCH (prb) {
10953: ; // abort burst fetch if bus error, do not report it.
10954: } ENDTRY
10955: } else {
1.1.1.10! root 10956: for (int j = 0; j < 3; j++) {
1.1.1.9 root 10957: i++;
10958: i &= 3;
10959: c->data[i] = icache_fetch(baddr + i * 4);
10960: c->valid[i] = true;
10961: }
10962: if (currprefs.cpu_cycle_exact)
10963: do_cycles_ce020_mem (3 * (CPU020_MEM_CYCLE - 1), c->data[3]);
10964: }
10965: }
1.1.1.7 root 10966: }
10967: regs.cacheholdingaddr020 = addr;
10968: regs.cacheholdingdata020 = data;
10969: //fprintf ( stderr , "fill ica %x -> miss %x\n" , addr , regs.cacheholdingdata020 );
10970: #ifdef WINUAE_FOR_HATARI
10971: CpuInstruction.I_Cache_miss++;
10972: #endif
10973: }
10974:
1.1.1.9 root 10975: #if VALIDATE_68030_DATACACHE
10976: static void validate_dcache030(void)
1.1.1.7 root 10977: {
1.1.1.10! root 10978: for (int i = 0; i < CACHELINES030; i++) {
1.1.1.9 root 10979: struct cache030 *c = &dcaches030[i];
10980: uae_u32 addr = c->tag & ~((CACHELINES030 << 4) - 1);
10981: addr |= i << 4;
1.1.1.10! root 10982: for (int j = 0; j < 4; j++) {
1.1.1.9 root 10983: if (c->valid[j]) {
10984: uae_u32 v = get_long(addr);
10985: if (v != c->data[j]) {
10986: write_log(_T("Address %08x data cache mismatch %08x != %08x\n"), addr, v, c->data[j]);
10987: }
10988: }
10989: addr += 4;
10990: }
10991: }
1.1.1.7 root 10992: }
10993:
1.1.1.9 root 10994: static void validate_dcache030_read(uae_u32 addr, uae_u32 ov, int size)
1.1.1.7 root 10995: {
1.1.1.9 root 10996: uae_u32 ov2;
10997: if (size == 2) {
10998: ov2 = get_long(addr);
10999: } else if (size == 1) {
11000: ov2 = get_word(addr);
11001: ov &= 0xffff;
11002: } else {
11003: ov2 = get_byte(addr);
11004: ov &= 0xff;
1.1.1.4 root 11005: }
1.1.1.9 root 11006: if (ov2 != ov) {
11007: write_log(_T("Address read %08x data cache mismatch %08x != %08x\n"), addr, ov2, ov);
11008: }
11009: }
11010: #endif
1.1.1.7 root 11011:
1.1.1.9 root 11012: // and finally the worst part, 68030 data cache..
11013: static void write_dcache030x(uaecptr addr, uae_u32 val, uae_u32 size, uae_u32 fc)
11014: {
11015: if (regs.cacr & 0x100) {
11016: static const uae_u32 mask[3] = { 0xff000000, 0xffff0000, 0xffffffff };
11017: struct cache030 *c1, *c2;
11018: int lws1, lws2;
11019: uae_u32 tag1, tag2;
11020: int aligned = addr & 3;
11021: int wa = regs.cacr & 0x2000;
11022: int width = 8 << size;
11023: int offset = 8 * aligned;
11024: int hit;
11025:
11026: c1 = getdcache030(dcaches030, addr, &tag1, &lws1);
11027: hit = c1->tag == tag1 && c1->fc == fc && c1->valid[lws1];
11028:
11029: // Write-allocate can create new valid cache entry if
11030: // long aligned long write and MMU CI is not active.
11031: // All writes ignore external CIIN signal.
11032: // CACHE_DISABLE_ALLOCATE = emulation only method to disable WA caching completely.
11033:
11034: if (width == 32 && offset == 0 && wa) {
11035: if (!(mmu030_cache_state & CACHE_DISABLE_MMU) && !(mmu030_cache_state & CACHE_DISABLE_ALLOCATE)) {
11036: update_dcache030(c1, val, tag1, fc, lws1);
11037: //fprintf ( stderr , "write cache1 %x %x %d tag1 %x lws1 %x tag2 %x lws2 %x ctag %x data %x\n", addr, val, size, tag1, lws1, tag2, lws2, c1->tag , c1->data[lws1] );
11038: #if VALIDATE_68030_DATACACHE
11039: validate_dcache030();
11040: #endif
11041: } else if (hit) {
11042: // Does real 68030 do this if MMU cache inhibited?
1.1.1.7 root 11043: c1->valid[lws1] = false;
1.1.1.9 root 11044: }
11045: return;
11046: }
11047:
11048: if (hit || wa) {
1.1.1.7 root 11049: if (hit) {
1.1.1.9 root 11050: uae_u32 val_left_aligned = val << (32 - width);
11051: c1->data[lws1] &= ~(mask[size] >> offset);
11052: c1->data[lws1] |= val_left_aligned >> offset;
11053: } else {
1.1.1.7 root 11054: c1->valid[lws1] = false;
1.1.1.9 root 11055: }
11056: }
11057:
11058: // do we need to update a 2nd cache entry ?
11059: if (width + offset > 32) {
11060: c2 = getdcache030(dcaches030, addr + 4, &tag2, &lws2);
11061: hit = c2->tag == tag2 && c2->fc == fc && c2->valid[lws2];
11062: if (hit || wa) {
11063: if (hit) {
11064: c2->data[lws2] &= 0xffffffff >> (width + offset - 32);
11065: c2->data[lws2] |= val << (32 - (width + offset - 32));
11066: } else {
11067: c2->valid[lws2] = false;
11068: }
11069: }
1.1.1.7 root 11070: }
1.1.1.9 root 11071: #if VALIDATE_68030_DATACACHE
11072: validate_dcache030();
11073: #endif
1.1.1.7 root 11074: }
1.1.1.9 root 11075: }
1.1.1.7 root 11076:
1.1.1.9 root 11077: void write_dcache030_bput(uaecptr addr, uae_u32 v,uae_u32 fc)
11078: {
11079: //fprintf ( stderr , "write dcache %x %x %d\n" , addr , v , size );
11080: regs.fc030 = fc;
11081: dcache_bput(addr, v);
11082: write_dcache030x(addr, v, 0, fc);
11083: }
11084: void write_dcache030_wput(uaecptr addr, uae_u32 v,uae_u32 fc)
11085: {
11086: regs.fc030 = fc;
11087: dcache_wput(addr, v);
11088: write_dcache030x(addr, v, 1, fc);
11089: }
11090: void write_dcache030_lput(uaecptr addr, uae_u32 v,uae_u32 fc)
11091: {
11092: regs.fc030 = fc;
11093: dcache_lput(addr, v);
11094: write_dcache030x(addr, v, 2, fc);
11095: }
1.1.1.7 root 11096:
1.1.1.10! root 11097: // 68030 MMU bus fault retry case, direct write, store to cache if enabled
! 11098: void write_dcache030_retry(uaecptr addr, uae_u32 v, uae_u32 fc, int size, int flags)
! 11099: {
! 11100: regs.fc030 = fc;
! 11101: mmu030_put_generic(addr, v, fc, size, flags);
! 11102: write_dcache030x(addr, v, size, fc);
! 11103: }
! 11104:
1.1.1.9 root 11105: static void dcache030_maybe_burst(uaecptr addr, struct cache030 *c, int lws)
11106: {
11107: if ((c->valid[0] + c->valid[1] + c->valid[2] + c->valid[3] == 1) && ce_banktype[addr >> 16] == CE_MEMBANK_FAST32) {
11108: // do burst fetch if cache enabled, not frozen, all slots invalid, no chip ram
11109: int i;
11110: uaecptr baddr = addr & ~15;
11111: for (i = 0; i < 4; i++) {
11112: if (c->valid[i])
11113: break;
1.1.1.4 root 11114: }
1.1.1.9 root 11115: if (currprefs.mmu_model) {
11116: TRY (prb) {
11117: if (currprefs.cpu_cycle_exact)
11118: #ifndef WINUAE_FOR_HATARI
11119: do_cycles_ce020(3 * (CPU020_MEM_CYCLE - 1));
11120: #else
11121: do_cycles_ce020_long(3 * (CPU020_MEM_CYCLE - 1));
11122: #endif
1.1.1.10! root 11123: for (int j = 0; j < 3; j++) {
1.1.1.9 root 11124: i++;
11125: i &= 3;
11126: c->data[i] = dcache_lget (baddr + i * 4);
11127: c->valid[i] = true;
11128: }
11129: } CATCH (prb) {
11130: ; // abort burst fetch if bus error
11131: } ENDTRY
11132: } else {
1.1.1.10! root 11133: for (int j = 0; j < 3; j++) {
1.1.1.9 root 11134: i++;
11135: i &= 3;
11136: c->data[i] = dcache_lget (baddr + i * 4);
11137: c->valid[i] = true;
11138: }
11139: if (currprefs.cpu_cycle_exact)
11140: do_cycles_ce020_mem (3 * (CPU020_MEM_CYCLE - 1), c->data[i]);
11141: }
11142: #if VALIDATE_68030_DATACACHE
11143: validate_dcache030();
11144: #endif
1.1.1.4 root 11145: }
11146: }
11147:
1.1.1.9 root 11148: static uae_u32 read_dcache030_debug(uaecptr addr, uae_u32 size, uae_u32 fc, bool *cached)
1.1.1.7 root 11149: {
1.1.1.9 root 11150: static const uae_u32 mask[3] = { 0x000000ff, 0x0000ffff, 0xffffffff };
11151: struct cache030 *c1, *c2;
11152: int lws1, lws2;
11153: uae_u32 tag1, tag2;
11154: int aligned = addr & 3;
11155: uae_u32 v1, v2;
11156: int width = 8 << size;
11157: int offset = 8 * aligned;
11158: uae_u32 out;
11159:
11160: *cached = false;
11161: if (!currprefs.cpu_data_cache) {
11162: if (size == 0)
11163: return get_byte_debug(addr);
11164: if (size == 1)
11165: return get_word_debug(addr);
11166: return get_long_debug(addr);
11167: }
11168:
11169: c1 = getdcache030(dcaches030, addr, &tag1, &lws1);
11170: addr &= ~3;
11171: if (!c1->valid[lws1] || c1->tag != tag1 || c1->fc != fc) {
11172: v1 = get_long_debug(addr);
1.1.1.7 root 11173: } else {
1.1.1.9 root 11174: // Cache hit, inhibited caching do not prevent read hits.
11175: v1 = c1->data[lws1];
11176: *cached = true;
11177: }
11178:
11179: // only one long fetch needed?
11180: if (width + offset <= 32) {
11181: out = v1 >> (32 - (offset + width));
11182: out &= mask[size];
11183: return out;
11184: }
11185:
11186: // no, need another one
11187: addr += 4;
11188: c2 = getdcache030(dcaches030, addr, &tag2, &lws2);
11189: if (!c2->valid[lws2] || c2->tag != tag2 || c2->fc != fc) {
11190: v2 = get_long_debug(addr);
11191: } else {
11192: v2 = c2->data[lws2];
11193: *cached = true;
1.1.1.7 root 11194: }
1.1.1.9 root 11195:
11196: uae_u64 v64 = ((uae_u64)v1 << 32) | v2;
11197: out = (uae_u32)(v64 >> (64 - (offset + width)));
11198: out &= mask[size];
11199: return out;
1.1.1.7 root 11200: }
11201:
11202: // [HATARI] Define next line to check for 68030 data cache mismatch after every write
11203: //#define WINUAE_FOR_HATARI_DEBUG_CACHE
11204: #ifdef WINUAE_FOR_HATARI_DEBUG_CACHE
1.1.1.10! root 11205: bool read_dcache030_2_real (uaecptr addr, uae_u32 size, uae_u32 *valp);
! 11206: static bool read_dcache030_2 (uaecptr addr, uae_u32 size, uae_u32 *valp)
1.1.1.7 root 11207: {
1.1.1.10! root 11208: bool b;
1.1.1.7 root 11209:
1.1.1.10! root 11210: b = read_dcache030_2_real ( addr , size , valp );
! 11211: if ( b==false)
! 11212: return false;
! 11213:
! 11214: if ( ( ( size==2 ) && ( *valp != get_long ( addr ) ) )
! 11215: || ( ( size==1 ) && ( (*valp&0xffff) != (get_word ( addr ) & 0xffff) ) )
! 11216: || ( ( size==0 ) && ( (*valp&0xff) != (get_byte ( addr ) & 0xff ) ) ) )
! 11217: fprintf ( stderr , "d-cache mismatch pc=%x addr=%x size=%d cache=%x != mem=%x, d-cache error ?\n" , m68k_getpc(), addr, size, *valp , get_long(addr) );
! 11218: return true;
1.1.1.7 root 11219: }
1.1.1.10! root 11220: bool read_dcache030_2_real(uaecptr addr, uae_u32 size, uae_u32 *valp)
1.1.1.7 root 11221: #else
1.1.1.10! root 11222: static bool read_dcache030_2(uaecptr addr, uae_u32 size, uae_u32 *valp)
1.1.1.7 root 11223: #endif
1.1.1.4 root 11224: {
1.1.1.10! root 11225: // data cache enabled?
! 11226: if (!(regs.cacr & 0x100))
! 11227: return false;
! 11228:
1.1.1.9 root 11229: uae_u32 addr_o = addr;
1.1.1.10! root 11230: uae_u32 fc = regs.fc030;
! 11231: static const uae_u32 mask[3] = { 0x000000ff, 0x0000ffff, 0xffffffff };
! 11232: struct cache030 *c1, *c2;
! 11233: int lws1, lws2;
! 11234: uae_u32 tag1, tag2;
! 11235: int aligned = addr & 3;
! 11236: uae_u32 v1, v2;
! 11237: int width = 8 << size;
! 11238: int offset = 8 * aligned;
! 11239: uae_u32 out;
1.1.1.9 root 11240:
1.1.1.10! root 11241: c1 = getdcache030(dcaches030, addr, &tag1, &lws1);
! 11242: addr &= ~3;
! 11243: if (!c1->valid[lws1] || c1->tag != tag1 || c1->fc != fc) {
! 11244: // MMU validate address, returns zero if valid but uncacheable
! 11245: // throws bus error if invalid
! 11246: uae_u8 cs = dcache_check(addr_o, false, size);
! 11247: if (!(cs & CACHE_ENABLE_DATA))
! 11248: return false;
! 11249: v1 = dcache_lget(addr);
! 11250: update_dcache030(c1, v1, tag1, fc, lws1);
! 11251: if ((cs & CACHE_ENABLE_DATA_BURST) && (regs.cacr & 0x1100) == 0x1100)
! 11252: dcache030_maybe_burst(addr, c1, lws1);
1.1.1.9 root 11253: #if VALIDATE_68030_DATACACHE
1.1.1.10! root 11254: validate_dcache030();
1.1.1.9 root 11255: #endif
11256: //fprintf ( stderr , "read cache %x %x %d tag1 %x lws1 %x tag2 %x lws2 %x ref %x\n", addr, v1, size, tag1, lws1, tag2, lws2 , get_long (0x1f81ec) );
11257: #ifdef WINUAE_FOR_HATARI
11258: CpuInstruction.D_Cache_miss++;
11259: #endif
1.1.1.10! root 11260: } else {
! 11261: // Cache hit, inhibited caching do not prevent read hits.
! 11262: v1 = c1->data[lws1];
1.1.1.7 root 11263: #ifdef WINUAE_FOR_HATARI
11264: CpuInstruction.D_Cache_hit++;
11265: #endif
1.1.1.10! root 11266: }
1.1.1.9 root 11267:
1.1.1.10! root 11268: // only one long fetch needed?
! 11269: if (width + offset <= 32) {
! 11270: out = v1 >> (32 - (offset + width));
! 11271: out &= mask[size];
1.1.1.9 root 11272: #if VALIDATE_68030_DATACACHE
1.1.1.10! root 11273: validate_dcache030_read(addr_o, out, size);
1.1.1.9 root 11274: #endif
1.1.1.10! root 11275: *valp = out;
! 11276: return true;
! 11277: }
1.1.1.9 root 11278:
1.1.1.10! root 11279: // no, need another one
! 11280: addr += 4;
! 11281: c2 = getdcache030(dcaches030, addr, &tag2, &lws2);
! 11282: if (!c2->valid[lws2] || c2->tag != tag2 || c2->fc != fc) {
! 11283: uae_u8 cs = dcache_check(addr, false, 2);
! 11284: if (!(cs & CACHE_ENABLE_DATA))
! 11285: return false;
! 11286: v2 = dcache_lget(addr);
! 11287: update_dcache030(c2, v2, tag2, fc, lws2);
! 11288: if ((cs & CACHE_ENABLE_DATA_BURST) && (regs.cacr & 0x1100) == 0x1100)
! 11289: dcache030_maybe_burst(addr, c2, lws2);
1.1.1.9 root 11290: #if VALIDATE_68030_DATACACHE
1.1.1.10! root 11291: validate_dcache030();
1.1.1.9 root 11292: #endif
1.1.1.7 root 11293: //fprintf ( stderr , "read cache %x %x %d tag1 %x lws1 %x tag2 %x lws2 %x\n", addr, v1, size, tag1, lws1, tag2, lws2 );
11294: #ifdef WINUAE_FOR_HATARI
11295: CpuInstruction.D_Cache_miss++;
11296: #endif
1.1.1.10! root 11297: } else {
! 11298: v2 = c2->data[lws2];
1.1.1.9 root 11299: #ifdef WINUAE_FOR_HATARI
1.1.1.7 root 11300: CpuInstruction.D_Cache_hit++;
11301: #endif
1.1.1.10! root 11302: }
1.1.1.9 root 11303:
1.1.1.10! root 11304: uae_u64 v64 = ((uae_u64)v1 << 32) | v2;
! 11305: out = (uae_u32)(v64 >> (64 - (offset + width)));
! 11306: out &= mask[size];
1.1.1.9 root 11307:
11308: #if VALIDATE_68030_DATACACHE
1.1.1.10! root 11309: validate_dcache030_read(addr_o, out, size);
1.1.1.9 root 11310: #endif
1.1.1.10! root 11311: *valp = out;
! 11312: return true;
! 11313: }
! 11314:
! 11315: static uae_u32 read_dcache030 (uaecptr addr, uae_u32 size, uae_u32 fc)
! 11316: {
! 11317: uae_u32 val;
! 11318: regs.fc030 = fc;
1.1.1.9 root 11319:
1.1.1.10! root 11320: if (!read_dcache030_2(addr, size, &val)) {
! 11321: // read from memory, data cache is disabled or inhibited.
! 11322: if (size == 2)
! 11323: return dcache_lget(addr);
! 11324: else if (size == 1)
! 11325: return dcache_wget(addr);
! 11326: else
! 11327: return dcache_bget(addr);
1.1.1.9 root 11328: }
1.1.1.10! root 11329: return val;
! 11330: }
! 11331:
! 11332: // 68030 MMU bus fault retry case, either read from cache or use direct reads
! 11333: uae_u32 read_dcache030_retry(uaecptr addr, uae_u32 fc, int size, int flags)
! 11334: {
! 11335: uae_u32 val;
! 11336: regs.fc030 = fc;
! 11337:
! 11338: if (!read_dcache030_2(addr, size, &val)) {
! 11339: return mmu030_get_generic(addr, fc, size, flags);
! 11340: }
! 11341: return val;
1.1.1.9 root 11342: }
1.1.1.10! root 11343:
1.1.1.9 root 11344: uae_u32 read_dcache030_bget(uaecptr addr, uae_u32 fc)
11345: {
11346: return read_dcache030(addr, 0, fc);
11347: }
11348: uae_u32 read_dcache030_wget(uaecptr addr, uae_u32 fc)
11349: {
11350: return read_dcache030(addr, 1, fc);
11351: }
11352: uae_u32 read_dcache030_lget(uaecptr addr, uae_u32 fc)
11353: {
11354: return read_dcache030(addr, 2, fc);
11355: }
1.1.1.7 root 11356:
1.1.1.9 root 11357: uae_u32 read_dcache030_mmu_bget(uaecptr addr)
11358: {
11359: return read_dcache030_bget(addr, (regs.s ? 4 : 0) | 1);
11360: }
11361: uae_u32 read_dcache030_mmu_wget(uaecptr addr)
11362: {
11363: return read_dcache030_wget(addr, (regs.s ? 4 : 0) | 1);
11364: }
11365: uae_u32 read_dcache030_mmu_lget(uaecptr addr)
11366: {
11367: return read_dcache030_lget(addr, (regs.s ? 4 : 0) | 1);
11368: }
11369: void write_dcache030_mmu_bput(uaecptr addr, uae_u32 val)
11370: {
11371: write_dcache030_bput(addr, val, (regs.s ? 4 : 0) | 1);
11372: }
11373: void write_dcache030_mmu_wput(uaecptr addr, uae_u32 val)
11374: {
11375: write_dcache030_wput(addr, val, (regs.s ? 4 : 0) | 1);
11376: }
11377: void write_dcache030_mmu_lput(uaecptr addr, uae_u32 val)
11378: {
11379: write_dcache030_lput(addr, val, (regs.s ? 4 : 0) | 1);
11380: }
1.1.1.4 root 11381:
1.1.1.10! root 11382: uae_u32 read_dcache030_lrmw_mmu_fcx(uaecptr addr, uae_u32 size, int fc)
1.1.1.9 root 11383: {
11384: if (currprefs.cpu_data_cache) {
11385: mmu030_cache_state = CACHE_DISABLE_MMU;
11386: if (size == 0)
1.1.1.10! root 11387: return read_dcache030_bget(addr, fc);
1.1.1.9 root 11388: if (size == 1)
1.1.1.10! root 11389: return read_dcache030_wget(addr, fc);
! 11390: return read_dcache030_lget(addr, fc);
1.1.1.9 root 11391: } else {
11392: if (size == 0)
11393: return read_data_030_bget(addr);
11394: if (size == 1)
11395: return read_data_030_wget(addr);
11396: return read_data_030_lget(addr);
11397: }
11398: }
1.1.1.10! root 11399: uae_u32 read_dcache030_lrmw_mmu(uaecptr addr, uae_u32 size)
! 11400: {
! 11401: return read_dcache030_lrmw_mmu_fcx(addr, size, (regs.s ? 4 : 0) | 1);
! 11402: }
! 11403: void write_dcache030_lrmw_mmu_fcx(uaecptr addr, uae_u32 val, uae_u32 size, int fc)
1.1.1.9 root 11404: {
11405: if (currprefs.cpu_data_cache) {
11406: mmu030_cache_state = CACHE_DISABLE_MMU;
11407: if (size == 0)
1.1.1.10! root 11408: write_dcache030_bput(addr, val, fc);
1.1.1.9 root 11409: else if (size == 1)
1.1.1.10! root 11410: write_dcache030_wput(addr, val, fc);
1.1.1.9 root 11411: else
1.1.1.10! root 11412: write_dcache030_lput(addr, val, fc);
1.1.1.9 root 11413: } else {
11414: if (size == 0)
11415: write_data_030_bput(addr, val);
11416: else if (size == 1)
11417: write_data_030_wput(addr, val);
11418: else
11419: write_data_030_lput(addr, val);
11420: }
1.1.1.4 root 11421: }
1.1.1.10! root 11422: void write_dcache030_lrmw_mmu(uaecptr addr, uae_u32 val, uae_u32 size)
! 11423: {
! 11424: write_dcache030_lrmw_mmu_fcx(addr, val, size, (regs.s ? 4 : 0) | 1);
! 11425: }
1.1.1.4 root 11426:
1.1.1.9 root 11427: static void do_access_or_bus_error(uaecptr pc, uaecptr pcnow)
11428: {
11429: // TODO: handle external bus errors
11430: if (!currprefs.mmu_model)
11431: return;
11432: if (pc != 0xffffffff)
11433: regs.instruction_pc = pc;
11434: mmu030_opcode = -1;
11435: mmu030_page_fault(pcnow, true, -1, 0);
11436: }
11437:
11438: static uae_u32 get_word_ce030_prefetch_2 (int o)
1.1.1.4 root 11439: {
11440: uae_u32 pc = m68k_getpc () + o;
1.1.1.7 root 11441: uae_u32 v;
1.1.1.4 root 11442:
1.1.1.9 root 11443: //fprintf ( stderr , "get_word_ce030_prefetch_2 %d pc=%x\n" , currcycle , pc);
11444: v = regs.prefetch020[0];
11445: regs.prefetch020[0] = regs.prefetch020[1];
11446: regs.prefetch020[1] = regs.prefetch020[2];
1.1.1.7 root 11447: #if MORE_ACCURATE_68020_PIPELINE
1.1.1.9 root 11448: pipeline_020(pc);
1.1.1.7 root 11449: #endif
1.1.1.9 root 11450: if (pc & 2) {
1.1.1.7 root 11451: // branch instruction detected in pipeline: stop fetches until branch executed.
11452: if (!MORE_ACCURATE_68020_PIPELINE || regs.pipeline_stop >= 0) {
11453: fill_icache030 (pc + 2 + 4);
1.1.1.9 root 11454: } else {
11455: if (regs.cacheholdingdata_valid > 0)
11456: regs.cacheholdingdata_valid++;
1.1.1.7 root 11457: }
1.1.1.9 root 11458: regs.prefetch020[2] = regs.cacheholdingdata020 >> 16;
1.1.1.7 root 11459: } else {
1.1.1.9 root 11460: pc += 4;
11461: // cacheholdingdata020 may be invalid if RTE from bus error
11462: if ((!MORE_ACCURATE_68020_PIPELINE || regs.pipeline_stop >= 0) && regs.cacheholdingaddr020 != pc) {
11463: fill_icache030 (pc);
11464: }
11465: regs.prefetch020[2] = (uae_u16)regs.cacheholdingdata020;
1.1.1.7 root 11466: }
1.1.1.9 root 11467: regs.db = regs.prefetch020[0];
1.1.1.7 root 11468: do_cycles_ce020_internal (2);
11469: return v;
11470: }
11471:
1.1.1.9 root 11472: uae_u32 get_word_ce030_prefetch (int o)
11473: {
11474: return get_word_ce030_prefetch_2(o);
11475: }
11476: uae_u32 get_word_ce030_prefetch_opcode (int o)
11477: {
11478: return get_word_ce030_prefetch_2(o);
11479: }
11480:
11481: uae_u32 get_word_030_prefetch (int o)
1.1.1.7 root 11482: {
1.1.1.9 root 11483: uae_u32 pc = m68k_getpc () + o;
1.1.1.7 root 11484: uae_u32 v;
11485:
1.1.1.9 root 11486: v = regs.prefetch020[0];
11487: regs.prefetch020[0] = regs.prefetch020[1];
11488: regs.prefetch020[1] = regs.prefetch020[2];
11489: regs.prefetch020_valid[0] = regs.prefetch020_valid[1];
11490: regs.prefetch020_valid[1] = regs.prefetch020_valid[2];
11491: regs.prefetch020_valid[2] = false;
11492: if (!regs.prefetch020_valid[1]) {
11493: do_access_or_bus_error(0xffffffff, pc + 4);
11494: }
1.1.1.7 root 11495: #if MORE_ACCURATE_68020_PIPELINE
1.1.1.9 root 11496: pipeline_020(pc);
1.1.1.7 root 11497: #endif
1.1.1.9 root 11498: if (pc & 2) {
1.1.1.7 root 11499: // branch instruction detected in pipeline: stop fetches until branch executed.
11500: if (!MORE_ACCURATE_68020_PIPELINE || regs.pipeline_stop >= 0) {
1.1.1.9 root 11501: fill_icache030 (pc + 2 + 4);
11502: } else {
11503: if (regs.cacheholdingdata_valid > 0)
11504: regs.cacheholdingdata_valid++;
1.1.1.7 root 11505: }
1.1.1.9 root 11506: regs.prefetch020[2] = regs.cacheholdingdata020 >> 16;
1.1.1.7 root 11507: } else {
1.1.1.9 root 11508: pc += 4;
11509: // cacheholdingdata020 may be invalid if RTE from bus error
11510: if ((!MORE_ACCURATE_68020_PIPELINE || regs.pipeline_stop >= 0) && regs.cacheholdingaddr020 != pc) {
11511: fill_icache030 (pc);
11512: }
11513: regs.prefetch020[2] = (uae_u16)regs.cacheholdingdata020;
1.1.1.7 root 11514: }
1.1.1.9 root 11515: regs.prefetch020_valid[2] = regs.cacheholdingdata_valid;
11516: regs.db = regs.prefetch020[0];
11517: //if ( ( v & 0xffff ) != ( get_word(pc) & 0xffff ) )
11518: // fprintf ( stderr , "prefetch mismatch pc=%x prefetch=%x != mem=%x, i-cache error ?\n" , pc , v&0xffff , get_word(pc)&0xffff );
1.1.1.7 root 11519: return v;
11520: }
11521:
11522: uae_u32 get_word_icache030(uaecptr addr)
11523: {
11524: fill_icache030(addr);
11525: return regs.cacheholdingdata020 >> ((addr & 2) ? 0 : 16);
11526: }
11527: uae_u32 get_long_icache030(uaecptr addr)
11528: {
11529: uae_u32 v;
11530: fill_icache030(addr);
11531: if ((addr & 2) == 0)
11532: return regs.cacheholdingdata020;
11533: v = regs.cacheholdingdata020 << 16;
11534: fill_icache030(addr + 4);
11535: v |= regs.cacheholdingdata020 >> 16;
11536: return v;
11537: }
11538:
1.1.1.9 root 11539: uae_u32 fill_icache040(uae_u32 addr)
11540: {
11541: int index, lws;
11542: uae_u32 tag, addr2;
11543: struct cache040 *c;
11544: int line;
11545:
11546: addr2 = addr & ~15;
11547: lws = (addr >> 2) & 3;
11548:
11549: if (regs.prefetch020addr == addr2) {
11550: return regs.prefetch040[lws];
11551: }
11552:
11553: if (regs.cacr & 0x8000) {
11554: uae_u8 cs = mmu_cache_state;
11555:
11556: if (!(ce_cachable[addr >> 16] & CACHE_ENABLE_INS))
11557: cs = CACHE_DISABLE_MMU;
11558:
11559: index = (addr >> 4) & cacheisets04060mask;
11560: tag = addr & cacheitag04060mask;
11561: c = &icaches040[index];
1.1.1.10! root 11562: for (int i = 0; i < CACHELINES040; i++) {
1.1.1.9 root 11563: if (c->valid[cache_lastline] && c->tag[cache_lastline] == tag) {
11564: // cache hit
11565: if (!(cs & CACHE_ENABLE_INS) || (cs & CACHE_DISABLE_MMU)) {
11566: c->valid[cache_lastline] = false;
11567: goto end;
11568: }
11569: if ((lws & 1) != icachehalfline) {
11570: icachehalfline ^= 1;
11571: icachelinecnt++;
11572: #ifdef WINUAE_FOR_HATARI
11573: CpuInstruction.I_Cache_hit++;
11574: #endif
11575: }
11576: return c->data[cache_lastline][lws];
11577: }
11578: cache_lastline++;
11579: cache_lastline &= (CACHELINES040 - 1);
11580: }
11581: // cache miss
11582: regs.prefetch020addr = 0xffffffff;
11583: regs.prefetch040[0] = icache_fetch(addr2 + 0);
11584: regs.prefetch040[1] = icache_fetch(addr2 + 4);
11585: regs.prefetch040[2] = icache_fetch(addr2 + 8);
11586: regs.prefetch040[3] = icache_fetch(addr2 + 12);
11587: regs.prefetch020addr = addr2;
11588: if (!(cs & CACHE_ENABLE_INS) || (cs & CACHE_DISABLE_MMU))
11589: goto end;
11590: if (regs.cacr & 0x00004000) // 68060 NAI
11591: goto end;
11592: if (c->valid[0] && c->valid[1] && c->valid[2] && c->valid[3]) {
11593: line = icachelinecnt & (CACHELINES040 - 1);
11594: icachehalfline = (lws & 1) ? 0 : 1;
11595: } else {
11596: for (line = 0; line < CACHELINES040; line++) {
11597: if (c->valid[line] == false)
11598: break;
11599: }
11600: }
11601: c->tag[line] = tag;
11602: c->valid[line] = true;
11603: c->data[line][0] = regs.prefetch040[0];
11604: c->data[line][1] = regs.prefetch040[1];
11605: c->data[line][2] = regs.prefetch040[2];
11606: c->data[line][3] = regs.prefetch040[3];
11607: if ((lws & 1) != icachehalfline) {
11608: icachehalfline ^= 1;
11609: icachelinecnt++;
11610: }
11611: #ifdef WINUAE_FOR_HATARI
11612: CpuInstruction.I_Cache_miss++;
11613: #endif
11614: return c->data[line][lws];
11615:
11616: }
11617:
11618: end:
11619: if (regs.prefetch020addr == addr2)
11620: return regs.prefetch040[lws];
11621: regs.prefetch020addr = addr2;
11622: regs.prefetch040[0] = icache_fetch(addr2 + 0);
11623: regs.prefetch040[1] = icache_fetch(addr2 + 4);
11624: regs.prefetch040[2] = icache_fetch(addr2 + 8);
11625: regs.prefetch040[3] = icache_fetch(addr2 + 12);
11626: return regs.prefetch040[lws];
11627: }
11628:
11629: STATIC_INLINE void do_cycles_c040_mem (int clocks, uae_u32 val)
11630: {
11631: x_do_cycles_post (clocks * cpucycleunit, val);
11632: }
11633:
11634: uae_u32 mem_access_delay_longi_read_c040 (uaecptr addr)
11635: {
11636: uae_u32 v;
11637: switch (ce_banktype[addr >> 16])
11638: {
11639: case CE_MEMBANK_CHIP16:
11640: v = wait_cpu_cycle_read_ce020 (addr + 0, 1) << 16;
11641: v |= wait_cpu_cycle_read_ce020 (addr + 2, 1) << 0;
11642: break;
11643: case CE_MEMBANK_CHIP32:
11644: if ((addr & 3) != 0) {
11645: v = wait_cpu_cycle_read_ce020 (addr + 0, 1) << 16;
11646: v |= wait_cpu_cycle_read_ce020 (addr + 2, 1) << 0;
11647: } else {
11648: v = wait_cpu_cycle_read_ce020 (addr, -1);
11649: }
11650: break;
11651: case CE_MEMBANK_FAST16:
11652: v = get_longi (addr);
11653: do_cycles_c040_mem(1, v);
11654: break;
11655: case CE_MEMBANK_FAST32:
11656: v = get_longi (addr);
11657: break;
11658: default:
11659: v = get_longi (addr);
11660: break;
11661: }
11662: return v;
11663: }
11664: uae_u32 mem_access_delay_long_read_c040 (uaecptr addr)
11665: {
11666: uae_u32 v;
11667: switch (ce_banktype[addr >> 16])
11668: {
11669: case CE_MEMBANK_CHIP16:
11670: v = wait_cpu_cycle_read_ce020 (addr + 0, 1) << 16;
11671: v |= wait_cpu_cycle_read_ce020 (addr + 2, 1) << 0;
11672: break;
11673: case CE_MEMBANK_CHIP32:
11674: if ((addr & 3) != 0) {
11675: v = wait_cpu_cycle_read_ce020 (addr + 0, 1) << 16;
11676: v |= wait_cpu_cycle_read_ce020 (addr + 2, 1) << 0;
11677: } else {
11678: v = wait_cpu_cycle_read_ce020 (addr, -1);
11679: }
11680: break;
11681: case CE_MEMBANK_FAST16:
11682: v = get_long (addr);
11683: do_cycles_c040_mem(1, v);
11684: break;
11685: case CE_MEMBANK_FAST32:
11686: v = get_long (addr);
11687: break;
11688: default:
11689: v = get_long (addr);
11690: break;
11691: }
11692: return v;
11693: }
11694:
11695: uae_u32 mem_access_delay_word_read_c040 (uaecptr addr)
11696: {
11697: uae_u32 v;
11698: switch (ce_banktype[addr >> 16])
11699: {
11700: case CE_MEMBANK_CHIP16:
11701: case CE_MEMBANK_CHIP32:
11702: if ((addr & 3) == 3) {
11703: v = wait_cpu_cycle_read_ce020 (addr + 0, 0) << 8;
11704: v |= wait_cpu_cycle_read_ce020 (addr + 1, 0) << 0;
11705: } else {
11706: v = wait_cpu_cycle_read_ce020 (addr, 1);
11707: }
11708: break;
11709: case CE_MEMBANK_FAST16:
11710: v = get_word (addr);
11711: do_cycles_c040_mem (2, v);
11712: break;
11713: case CE_MEMBANK_FAST32:
11714: v = get_word (addr);
11715: break;
11716: default:
11717: v = get_word (addr);
11718: break;
11719: }
11720: return v;
11721: }
11722:
11723: uae_u32 mem_access_delay_byte_read_c040 (uaecptr addr)
11724: {
11725: uae_u32 v;
11726: switch (ce_banktype[addr >> 16])
11727: {
11728: case CE_MEMBANK_CHIP16:
11729: case CE_MEMBANK_CHIP32:
11730: v = wait_cpu_cycle_read_ce020 (addr, 0);
11731: break;
11732: case CE_MEMBANK_FAST16:
11733: v = get_byte (addr);
11734: do_cycles_c040_mem (1, v);
11735: break;
11736: case CE_MEMBANK_FAST32:
11737: v = get_byte (addr);
11738: break;
11739: default:
11740: v = get_byte (addr);
11741: break;
11742: }
11743: return v;
11744: }
11745:
11746: void mem_access_delay_byte_write_c040 (uaecptr addr, uae_u32 v)
11747: {
11748: switch (ce_banktype[addr >> 16])
11749: {
11750: case CE_MEMBANK_CHIP16:
11751: case CE_MEMBANK_CHIP32:
11752: wait_cpu_cycle_write_ce020 (addr, 0, v);
11753: break;
11754: case CE_MEMBANK_FAST16:
11755: put_byte (addr, v);
11756: do_cycles_c040_mem (1, v);
11757: break;
11758: case CE_MEMBANK_FAST32:
11759: put_byte (addr, v);
11760: break;
11761: default:
11762: put_byte (addr, v);
11763: break;
11764: }
11765: }
11766:
11767: void mem_access_delay_word_write_c040 (uaecptr addr, uae_u32 v)
11768: {
11769: switch (ce_banktype[addr >> 16])
11770: {
11771: case CE_MEMBANK_CHIP16:
11772: case CE_MEMBANK_CHIP32:
11773: if ((addr & 3) == 3) {
11774: wait_cpu_cycle_write_ce020 (addr + 0, 0, (v >> 8) & 0xff);
11775: wait_cpu_cycle_write_ce020 (addr + 1, 0, (v >> 0) & 0xff);
11776: } else {
11777: wait_cpu_cycle_write_ce020 (addr + 0, 1, v);
11778: }
11779: break;
11780: case CE_MEMBANK_FAST16:
11781: put_word (addr, v);
11782: if ((addr & 3) == 3)
11783: do_cycles_c040_mem(2, v);
11784: else
11785: do_cycles_c040_mem(1, v);
11786: break;
11787: case CE_MEMBANK_FAST32:
11788: put_word (addr, v);
11789: break;
11790: default:
11791: put_word (addr, v);
11792: break;
11793: }
11794: }
11795:
11796: void mem_access_delay_long_write_c040 (uaecptr addr, uae_u32 v)
11797: {
11798: switch (ce_banktype[addr >> 16])
11799: {
11800: case CE_MEMBANK_CHIP16:
11801: wait_cpu_cycle_write_ce020 (addr + 0, 1, (v >> 16) & 0xffff);
11802: wait_cpu_cycle_write_ce020 (addr + 2, 1, (v >> 0) & 0xffff);
11803: break;
11804: case CE_MEMBANK_CHIP32:
11805: if ((addr & 3) == 3) {
11806: wait_cpu_cycle_write_ce020 (addr + 0, 1, (v >> 16) & 0xffff);
11807: wait_cpu_cycle_write_ce020 (addr + 2, 1, (v >> 0) & 0xffff);
11808: } else {
11809: wait_cpu_cycle_write_ce020 (addr + 0, -1, v);
11810: }
11811: break;
11812: case CE_MEMBANK_FAST16:
11813: put_long (addr, v);
11814: do_cycles_ce020_mem (2 * CPU020_MEM_CYCLE, v);
11815: break;
11816: case CE_MEMBANK_FAST32:
11817: put_long (addr, v);
11818: break;
11819: default:
11820: put_long (addr, v);
11821: break;
11822: }
11823: }
11824:
11825: static uae_u32 dcache040_get_data(uaecptr addr, struct cache040 *c, int line, int size)
1.1.1.7 root 11826: {
1.1.1.9 root 11827: static const uae_u32 mask[3] = { 0x000000ff, 0x0000ffff, 0xffffffff };
11828: int offset = (addr & 15) * 8;
11829: int offset32 = offset & 31;
11830: int slot = offset / 32;
11831: int width = 8 << size;
11832: uae_u32 vv;
11833:
11834: if (offset32 + width <= 32) {
11835: uae_u32 v = c->data[line][slot];
11836: v >>= 32 - (offset32 + width);
11837: v &= mask[size];
11838: vv = v;
11839: } else {
11840: #if VALIDATE_68040_DATACACHE
11841: if (slot >= 3) {
11842: write_log(_T("invalid dcache040_get_data!\n"));
11843: return 0;
1.1.1.7 root 11844: }
1.1.1.9 root 11845: #endif
11846: uae_u64 v = c->data[line][slot];
11847: v <<= 32;
11848: v |= c->data[line][slot + 1];
11849: v >>= 64 - (offset32 + width);
11850: vv = v & mask[size];
1.1.1.7 root 11851: }
1.1.1.9 root 11852: return vv;
11853: }
1.1.1.7 root 11854:
1.1.1.9 root 11855: static void dcache040_update(uaecptr addr, struct cache040 *c, int line, uae_u32 val, int size)
11856: {
11857: static const uae_u64 mask64[3] = { 0xff, 0xffff, 0xffffffff };
11858: static const uae_u32 mask32[3] = { 0xff, 0xffff, 0xffffffff };
11859: int offset = (addr & 15) * 8;
11860: int offset32 = offset & 31;
11861: int slot = offset / 32;
11862: int width = 8 << size;
11863:
11864: #if VALIDATE_68040_DATACACHE > 1
11865: validate_dcache040();
1.1.1.7 root 11866: #endif
1.1.1.9 root 11867:
11868: if (offset32 + width <= 32) {
11869: int shift = 32 - (offset32 + width);
11870: uae_u32 v = c->data[line][slot];
11871: v &= ~(mask32[size] << shift);
11872: v |= val << shift;
11873: c->data[line][slot] = v;
11874: c->dirty[line][slot] = true;
11875: } else {
11876: #if VALIDATE_68040_DATACACHE
11877: if (slot >= 3) {
11878: write_log(_T("invalid dcache040_update!\n"));
11879: return;
1.1.1.7 root 11880: }
1.1.1.9 root 11881: #endif
11882: int shift = 64 - (offset32 + width);
11883: uae_u64 v = c->data[line][slot];
11884: v <<= 32;
11885: v |= c->data[line][slot + 1];
11886: v &= ~(mask64[size] << shift);
11887: v |= ((uae_u64)val) << shift;
11888: c->data[line][slot] = v >> 32;
11889: c->dirty[line][slot] = true;
11890: c->data[line][slot + 1] = (uae_u32)v;
11891: c->dirty[line][slot + 1] = true;
1.1.1.7 root 11892: }
1.1.1.9 root 11893: c->gdirty[line] = true;
11894: }
11895:
11896: static int dcache040_fill_line(int index, uae_u32 tag, uaecptr addr)
11897: {
1.1.1.7 root 11898: // cache miss
1.1.1.9 root 11899: struct cache040 *c = &dcaches040[index];
11900: int line;
1.1.1.7 root 11901: if (c->valid[0] && c->valid[1] && c->valid[2] && c->valid[3]) {
1.1.1.9 root 11902: // all lines allocated, choose one, push and invalidate.
11903: line = dcachelinecnt & (CACHELINES040 - 1);
11904: dcachelinecnt++;
11905: dcache040_push_line(index, line, false, true);
11906: } else {
11907: // at least one invalid
1.1.1.7 root 11908: for (line = 0; line < CACHELINES040; line++) {
11909: if (c->valid[line] == false)
11910: break;
11911: }
11912: }
11913: c->tag[line] = tag;
1.1.1.9 root 11914: c->dirty[line][0] = false;
11915: c->dirty[line][1] = false;
11916: c->dirty[line][2] = false;
11917: c->dirty[line][3] = false;
11918: c->gdirty[line] = false;
11919: c->data[line][0] = dcache_lget(addr + 0);
11920: c->data[line][1] = dcache_lget(addr + 4);
11921: c->data[line][2] = dcache_lget(addr + 8);
11922: c->data[line][3] = dcache_lget(addr + 12);
1.1.1.7 root 11923: c->valid[line] = true;
1.1.1.9 root 11924: return line;
1.1.1.7 root 11925: }
11926:
1.1.1.9 root 11927: static uae_u32 read_dcache040_debug(uae_u32 addr, int size, bool *cached)
1.1.1.7 root 11928: {
1.1.1.9 root 11929: int index;
1.1.1.7 root 11930: uae_u32 tag;
11931: struct cache040 *c;
1.1.1.9 root 11932: int line;
11933: uae_u32 addr_o = addr;
11934: uae_u8 cs = mmu_cache_state;
11935:
11936: *cached = false;
11937: if (!currprefs.cpu_data_cache)
11938: goto nocache;
11939: if (!(regs.cacr & 0x80000000))
11940: goto nocache;
1.1.1.7 root 11941:
11942: addr &= ~15;
1.1.1.9 root 11943: index = (addr >> 4) & cachedsets04060mask;
11944: tag = addr & cachedtag04060mask;
1.1.1.7 root 11945: c = &dcaches040[index];
1.1.1.9 root 11946: for (line = 0; line < CACHELINES040; line++) {
11947: if (c->valid[line] && c->tag[line] == tag) {
11948: // cache hit
11949: return dcache040_get_data(addr_o, c, line, size);
1.1.1.7 root 11950: }
11951: }
1.1.1.9 root 11952: nocache:
11953: if (size == 0)
11954: return get_byte_debug(addr);
11955: if (size == 1)
11956: return get_word_debug(addr);
11957: return get_long_debug(addr);
1.1.1.7 root 11958: }
11959:
1.1.1.9 root 11960: static uae_u32 read_dcache040(uae_u32 addr, int size, uae_u32 (*fetch)(uaecptr))
1.1.1.7 root 11961: {
1.1.1.9 root 11962: int index;
1.1.1.7 root 11963: uae_u32 tag;
11964: struct cache040 *c;
11965: int line;
1.1.1.9 root 11966: uae_u32 addr_o = addr;
11967: uae_u8 cs = mmu_cache_state;
11968:
11969: if (!(regs.cacr & 0x80000000))
11970: goto nocache;
11971:
11972: #if VALIDATE_68040_DATACACHE > 1
11973: validate_dcache040();
11974: #endif
11975:
11976: // Simple because 68040+ caches physical addresses (68030 caches logical addresses)
11977: if (!(ce_cachable[addr >> 16] & CACHE_ENABLE_DATA))
11978: cs = CACHE_DISABLE_MMU;
1.1.1.7 root 11979:
11980: addr &= ~15;
1.1.1.9 root 11981: index = (addr >> 4) & cachedsets04060mask;
11982: tag = addr & cachedtag04060mask;
1.1.1.7 root 11983: c = &dcaches040[index];
1.1.1.9 root 11984: for (line = 0; line < CACHELINES040; line++) {
11985: if (c->valid[line] && c->tag[line] == tag) {
1.1.1.7 root 11986: // cache hit
11987: dcachelinecnt++;
1.1.1.9 root 11988: // Cache hit but MMU disabled: do not cache, push and invalidate possible existing line
11989: if (cs & CACHE_DISABLE_MMU) {
11990: dcache040_push_line(index, line, false, true);
11991: goto nocache;
1.1.1.7 root 11992: }
1.1.1.9 root 11993: return dcache040_get_data(addr_o, c, line, size);
1.1.1.7 root 11994: }
11995: }
1.1.1.9 root 11996: // Cache miss
11997: // 040+ always caches whole line
1.1.1.10! root 11998: if ((cs & CACHE_DISABLE_MMU) || !(cs & CACHE_ENABLE_DATA) || (cs & CACHE_DISABLE_ALLOCATE) || (regs.cacr & 0x40000000)) {
1.1.1.9 root 11999: nocache:
12000: return fetch(addr_o);
1.1.1.7 root 12001: }
1.1.1.9 root 12002: // Allocate new cache line, return requested data.
12003: line = dcache040_fill_line(index, tag, addr);
12004: return dcache040_get_data(addr_o, c, line, size);
1.1.1.7 root 12005: }
12006:
1.1.1.9 root 12007: static void write_dcache040(uae_u32 addr, uae_u32 val, int size, void (*store)(uaecptr, uae_u32))
1.1.1.7 root 12008: {
1.1.1.9 root 12009: static const uae_u32 mask[3] = { 0x000000ff, 0x0000ffff, 0xffffffff };
12010: int index;
1.1.1.7 root 12011: uae_u32 tag;
12012: struct cache040 *c;
12013: int line;
1.1.1.9 root 12014: uae_u32 addr_o = addr;
12015: uae_u8 cs = mmu_cache_state;
12016:
12017: val &= mask[size];
12018:
12019: if (!(regs.cacr & 0x80000000))
12020: goto nocache;
12021:
12022: if (!(ce_cachable[addr >> 16] & CACHE_ENABLE_DATA))
12023: cs = CACHE_DISABLE_MMU;
1.1.1.7 root 12024:
12025: addr &= ~15;
1.1.1.9 root 12026: index = (addr >> 4) & cachedsets04060mask;
12027: tag = addr & cachedtag04060mask;
1.1.1.7 root 12028: c = &dcaches040[index];
1.1.1.9 root 12029: for (line = 0; line < CACHELINES040; line++) {
12030: if (c->valid[line] && c->tag[line] == tag) {
1.1.1.7 root 12031: // cache hit
12032: dcachelinecnt++;
1.1.1.9 root 12033: // Cache hit but MMU disabled: do not cache, push and invalidate possible existing line
12034: if (cs & CACHE_DISABLE_MMU) {
12035: dcache040_push_line(index, line, false, true);
12036: goto nocache;
12037: }
12038: dcache040_update(addr_o, c, line, val, size);
12039: // If not copyback mode: push modifications immediately (write-through)
12040: if (!(cs & CACHE_ENABLE_COPYBACK) || DISABLE_68040_COPYBACK) {
12041: dcache040_push_line(index, line, true, false);
1.1.1.4 root 12042: }
1.1.1.9 root 12043: return;
1.1.1.4 root 12044: }
12045: }
1.1.1.9 root 12046: // Cache miss
12047: // 040+ always caches whole line
12048: // Writes misses in write-through mode don't allocate new cache lines
12049: if (!(cs & CACHE_ENABLE_DATA) || (cs & CACHE_DISABLE_MMU) || (cs & CACHE_DISABLE_ALLOCATE) || !(cs & CACHE_ENABLE_COPYBACK) || (regs.cacr & 0x400000000)) {
12050: nocache:
12051: store(addr_o, val);
12052: return;
12053: }
12054: // Allocate new cache line and update it with new data.
12055: line = dcache040_fill_line(index, tag, addr);
12056: dcache040_update(addr_o, c, line, val, size);
12057: if (DISABLE_68040_COPYBACK) {
12058: dcache040_push_line(index, line, true, false);
1.1.1.7 root 12059: }
12060: }
12061:
12062: // really unoptimized
12063: uae_u32 get_word_icache040(uaecptr addr)
12064: {
12065: uae_u32 v = fill_icache040(addr);
12066: return v >> ((addr & 2) ? 0 : 16);
12067: }
12068: uae_u32 get_long_icache040(uaecptr addr)
12069: {
12070: uae_u32 v1, v2;
12071: v1 = fill_icache040(addr);
12072: if ((addr & 2) == 0)
12073: return v1;
12074: v2 = fill_icache040(addr + 4);
12075: return (v2 >> 16) | (v1 << 16);
12076: }
12077: uae_u32 get_ilong_cache_040(int o)
12078: {
12079: return get_long_icache040(m68k_getpci() + o);
12080: }
12081: uae_u32 get_iword_cache_040(int o)
12082: {
12083: return get_word_icache040(m68k_getpci() + o);
12084: }
12085:
12086: void put_long_cache_040(uaecptr addr, uae_u32 v)
12087: {
1.1.1.9 root 12088: int offset = addr & 15;
12089: // access must not cross cachelines
12090: if (offset < 13) {
12091: write_dcache040(addr, v, 2, dcache_lput);
12092: } else if (offset == 13 || offset == 15) {
12093: write_dcache040(addr + 0, v >> 24, 0, dcache_bput);
12094: write_dcache040(addr + 1, v >> 8, 1, dcache_wput);
12095: write_dcache040(addr + 3, v >> 0, 0, dcache_bput);
12096: } else if (offset == 14) {
12097: write_dcache040(addr + 0, v >> 16, 1, dcache_wput);
12098: write_dcache040(addr + 2, v >> 0, 1, dcache_wput);
1.1.1.7 root 12099: }
12100: }
12101: void put_word_cache_040(uaecptr addr, uae_u32 v)
12102: {
1.1.1.9 root 12103: int offset = addr & 15;
12104: if (offset < 15) {
12105: write_dcache040(addr, v, 1, dcache_wput);
1.1.1.7 root 12106: } else {
1.1.1.9 root 12107: write_dcache040(addr + 0, v >> 8, 0, dcache_bput);
12108: write_dcache040(addr + 1, v >> 0, 0, dcache_bput);
1.1.1.7 root 12109: }
12110: }
12111: void put_byte_cache_040(uaecptr addr, uae_u32 v)
12112: {
1.1.1.9 root 12113: return write_dcache040(addr, v, 0, dcache_bput);
1.1.1.4 root 12114: }
12115:
1.1.1.7 root 12116: uae_u32 get_long_cache_040(uaecptr addr)
12117: {
1.1.1.9 root 12118: uae_u32 v;
12119: int offset = addr & 15;
12120: if (offset < 13) {
12121: v = read_dcache040(addr, 2, dcache_lget);
12122: } else if (offset == 13 || offset == 15) {
12123: v = read_dcache040(addr + 0, 0, dcache_bget) << 24;
12124: v |= read_dcache040(addr + 1, 1, dcache_wget) << 8;
12125: v |= read_dcache040(addr + 3, 0, dcache_bget) << 0;
1.1.1.10! root 12126: } else /* if (offset == 14) */ {
1.1.1.9 root 12127: v = read_dcache040(addr + 0, 1, dcache_wget) << 16;
12128: v |= read_dcache040(addr + 2, 1, dcache_wget) << 0;
12129: }
12130: return v;
1.1.1.7 root 12131: }
12132: uae_u32 get_word_cache_040(uaecptr addr)
12133: {
1.1.1.9 root 12134: uae_u32 v;
12135: int offset = addr & 15;
12136: if (offset < 15) {
12137: v = read_dcache040(addr, 1, dcache_wget);
12138: } else {
12139: v = read_dcache040(addr + 0, 0, dcache_bget) << 8;
12140: v |= read_dcache040(addr + 1, 0, dcache_bget) << 0;
12141: }
12142: return v;
1.1.1.7 root 12143: }
12144: uae_u32 get_byte_cache_040(uaecptr addr)
12145: {
1.1.1.9 root 12146: return read_dcache040(addr, 0, dcache_bget);
1.1.1.7 root 12147: }
12148: uae_u32 next_iword_cache040(void)
12149: {
12150: uae_u32 r = get_word_icache040(m68k_getpci());
12151: m68k_incpci(2);
12152: return r;
12153: }
12154: uae_u32 next_ilong_cache040(void)
12155: {
12156: uae_u32 r = get_long_icache040(m68k_getpci());
12157: m68k_incpci(4);
12158: return r;
12159: }
1.1.1.4 root 12160:
1.1.1.9 root 12161: uae_u32 get_byte_cache_debug(uaecptr addr, bool *cached)
1.1.1.4 root 12162: {
1.1.1.9 root 12163: *cached = false;
12164: if (currprefs.cpu_model == 68030) {
12165: return read_dcache030_debug(addr, 0, regs.s ? 5 : 1, cached);
12166: } else if (currprefs.cpu_model >= 68040) {
12167: return read_dcache040_debug(addr, 0, cached);
12168: }
12169: return get_byte_debug(addr);
12170: }
12171: uae_u32 get_word_cache_debug(uaecptr addr, bool *cached)
12172: {
12173: *cached = false;
12174: if (currprefs.cpu_model == 68030) {
12175: return read_dcache030_debug(addr, 1, regs.s ? 5 : 1, cached);
12176: } else if (currprefs.cpu_model >= 68040) {
12177: return read_dcache040_debug(addr, 1, cached);
1.1.1.4 root 12178: }
1.1.1.9 root 12179: return get_word_debug(addr);
1.1.1.4 root 12180: }
12181:
1.1.1.9 root 12182: uae_u32 get_long_cache_debug(uaecptr addr, bool *cached)
1.1.1.4 root 12183: {
1.1.1.9 root 12184: *cached = false;
12185: if (currprefs.cpu_model == 68030) {
12186: return read_dcache030_debug(addr, 2, regs.s ? 5 : 1, cached);
12187: } else if (currprefs.cpu_model >= 68040) {
12188: return read_dcache040_debug(addr, 2, cached);
1.1.1.7 root 12189: }
1.1.1.9 root 12190: return get_long_debug(addr);
12191: }
12192:
12193: void check_t0_trace(void)
12194: {
12195: if (regs.t0 && currprefs.cpu_model >= 68020) {
12196: unset_special (SPCFLAG_TRACE);
12197: set_special (SPCFLAG_DOTRACE);
1.1.1.7 root 12198: }
1.1.1.9 root 12199: }
12200:
12201: static void reset_pipeline_state(void)
12202: {
12203: #if MORE_ACCURATE_68020_PIPELINE
12204: regs.pipeline_pos = 0;
12205: regs.pipeline_stop = 0;
12206: regs.pipeline_r8[0] = regs.pipeline_r8[1] = -1;
12207: #endif
12208: }
12209:
12210: static int add_prefetch_030(int idx, uae_u16 w, uaecptr pc)
12211: {
12212: regs.prefetch020[0] = regs.prefetch020[1];
12213: regs.prefetch020_valid[0] = regs.prefetch020_valid[1];
12214: regs.prefetch020[1] = regs.prefetch020[2];
12215: regs.prefetch020_valid[1] = regs.prefetch020_valid[2];
12216: regs.prefetch020[2] = w;
12217: regs.prefetch020_valid[2] = regs.cacheholdingdata_valid;
12218:
12219: #if MORE_ACCURATE_68020_PIPELINE
12220: if (idx >= 1) {
12221: pipeline_020(pc);
12222: }
12223: #endif
12224:
12225: if (!regs.prefetch020_valid[2]) {
12226: if (idx == 0 || !regs.pipeline_stop) {
12227: // Pipeline refill and first opcode word is invalid?
12228: // Generate previously detected bus error/MMU fault
12229: do_access_or_bus_error(pc, pc + idx * 2);
1.1.1.7 root 12230: }
12231: }
1.1.1.9 root 12232: return idx + 1;
1.1.1.4 root 12233: }
12234:
1.1.1.9 root 12235: void fill_prefetch_030_ntx(void)
1.1.1.4 root 12236: {
1.1.1.9 root 12237: //fprintf ( stderr , "fill_prefetch_030_ntx %d\n" , currcycle);
1.1.1.7 root 12238: uaecptr pc = m68k_getpc ();
12239: uaecptr pc2 = pc;
1.1.1.9 root 12240: int idx = 0;
12241:
1.1.1.7 root 12242: pc &= ~3;
1.1.1.9 root 12243: mmu030_idx = 0;
12244: reset_pipeline_state();
12245: regs.cacheholdingdata_valid = 1;
12246: regs.cacheholdingaddr020 = 0xffffffff;
12247: regs.prefetch020_valid[0] = regs.prefetch020_valid[1] = regs.prefetch020_valid[2] = 0;
1.1.1.4 root 12248:
1.1.1.9 root 12249: fill_icache030(pc);
1.1.1.7 root 12250: if (currprefs.cpu_cycle_exact)
12251: do_cycles_ce020_internal(2);
1.1.1.9 root 12252: if (pc2 & 2) {
12253: idx = add_prefetch_030(idx, regs.cacheholdingdata020, pc2);
12254: } else {
12255: idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc2);
12256: idx = add_prefetch_030(idx, regs.cacheholdingdata020, pc2);
12257: }
1.1.1.7 root 12258:
1.1.1.9 root 12259: fill_icache030(pc + 4);
1.1.1.7 root 12260: if (currprefs.cpu_cycle_exact)
12261: do_cycles_ce020_internal(2);
12262: if (pc2 & 2) {
1.1.1.9 root 12263: idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc2);
12264: idx = add_prefetch_030(idx, regs.cacheholdingdata020, pc2);
1.1.1.7 root 12265: } else {
1.1.1.9 root 12266: idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc2);
1.1.1.4 root 12267: }
1.1.1.9 root 12268:
12269: if (currprefs.cpu_cycle_exact)
12270: regs.irc = get_word_ce030_prefetch_opcode (0);
12271: else
12272: regs.irc = get_word_030_prefetch (0);
12273: }
12274:
12275: void fill_prefetch_030_ntx_continue (void)
12276: {
12277: uaecptr pc = m68k_getpc ();
12278: uaecptr pc_orig = pc;
12279: int idx = 0;
12280:
12281: mmu030_idx = 0;
12282: reset_pipeline_state();
12283: regs.cacheholdingdata_valid = 1;
12284: regs.cacheholdingaddr020 = 0xffffffff;
12285:
1.1.1.10! root 12286: for (int i = 2; i >= 0; i--) {
1.1.1.9 root 12287: if (!regs.prefetch020_valid[i])
12288: break;
12289: #if MORE_ACCURATE_68020_PIPELINE
12290: if (idx >= 1) {
12291: pipeline_020(pc);
12292: }
1.1.1.7 root 12293: #endif
1.1.1.9 root 12294: pc += 2;
12295: idx++;
12296: }
12297:
12298: if (idx < 3 && !regs.pipeline_stop) {
12299: uaecptr pc2 = pc;
12300: pc &= ~3;
12301:
12302: fill_icache030(pc);
12303: if (currprefs.cpu_cycle_exact)
12304: do_cycles_ce020_internal(2);
12305: if (pc2 & 2) {
12306: idx = add_prefetch_030(idx, regs.cacheholdingdata020, pc_orig);
12307: } else {
12308: idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc_orig);
12309: if (idx < 3)
12310: idx = add_prefetch_030(idx, regs.cacheholdingdata020, pc_orig);
12311: }
12312:
12313: if (idx < 3) {
12314: fill_icache030(pc + 4);
12315: if (currprefs.cpu_cycle_exact)
12316: do_cycles_ce020_internal(2);
12317: if (pc2 & 2) {
12318: idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc_orig);
12319: if (idx < 3)
12320: idx = add_prefetch_030(idx, regs.cacheholdingdata020, pc_orig);
12321: } else {
12322: idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc_orig);
12323: }
12324: }
12325: }
1.1.1.4 root 12326:
1.1.1.7 root 12327: if (currprefs.cpu_cycle_exact)
1.1.1.9 root 12328: regs.irc = get_word_ce030_prefetch_opcode (0);
1.1.1.7 root 12329: else
1.1.1.9 root 12330: regs.irc = get_word_030_prefetch (0);
12331: //fprintf ( stderr , "fill_prefetch_030_ntx4 %d\n" , currcycle);
1.1.1.4 root 12332: }
12333:
1.1.1.9 root 12334: void fill_prefetch_020_ntx(void)
1.1.1.4 root 12335: {
1.1.1.7 root 12336: uaecptr pc = m68k_getpc ();
12337: uaecptr pc2 = pc;
1.1.1.9 root 12338: int idx = 0;
12339:
1.1.1.7 root 12340: pc &= ~3;
1.1.1.9 root 12341: reset_pipeline_state();
1.1.1.7 root 12342:
1.1.1.9 root 12343: fill_icache020 (pc, true);
1.1.1.7 root 12344: if (currprefs.cpu_cycle_exact)
12345: do_cycles_ce020_internal(2);
1.1.1.9 root 12346: if (pc2 & 2) {
12347: idx = add_prefetch_030(idx, regs.cacheholdingdata020, pc);
12348: } else {
12349: idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc);
12350: idx = add_prefetch_030(idx, regs.cacheholdingdata020, pc);
12351: }
1.1.1.7 root 12352:
1.1.1.9 root 12353: fill_icache020 (pc + 4, true);
1.1.1.7 root 12354: if (currprefs.cpu_cycle_exact)
12355: do_cycles_ce020_internal(2);
12356: if (pc2 & 2) {
1.1.1.9 root 12357: idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc);
12358: idx = add_prefetch_030(idx, regs.cacheholdingdata020, pc);
1.1.1.7 root 12359: } else {
1.1.1.9 root 12360: idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc);
1.1.1.7 root 12361: }
12362:
12363: if (currprefs.cpu_cycle_exact)
1.1.1.9 root 12364: regs.irc = get_word_ce020_prefetch_opcode (0);
1.1.1.7 root 12365: else
12366: regs.irc = get_word_020_prefetch (0);
1.1.1.4 root 12367: }
12368:
1.1.1.9 root 12369: // Not exactly right, requires logic analyzer checks.
12370: void continue_ce020_prefetch(void)
12371: {
12372: fill_prefetch_020_ntx();
12373: }
12374: void continue_020_prefetch(void)
12375: {
12376: fill_prefetch_020_ntx();
12377: }
12378:
12379: void continue_ce030_prefetch(void)
12380: {
12381: fill_prefetch_030_ntx();
12382: }
12383: void continue_030_prefetch(void)
12384: {
12385: fill_prefetch_030_ntx();
12386: }
12387:
12388: void fill_prefetch_020(void)
12389: {
12390: fill_prefetch_020_ntx();
12391: check_t0_trace();
12392: }
12393:
12394: void fill_prefetch_030(void)
12395: {
12396: fill_prefetch_030_ntx();
12397: check_t0_trace();
12398: }
12399:
12400:
1.1.1.7 root 12401: void fill_prefetch (void)
1.1.1.4 root 12402: {
1.1.1.9 root 12403: reset_pipeline_state();
1.1.1.7 root 12404: if (currprefs.cachesize)
12405: return;
12406: if (!currprefs.cpu_compatible)
12407: return;
12408: if (currprefs.cpu_model >= 68040) {
1.1.1.8 root 12409: if (currprefs.cpu_compatible || currprefs.cpu_memory_cycle_exact) {
1.1.1.7 root 12410: fill_icache040(m68k_getpc() + 16);
12411: fill_icache040(m68k_getpc());
12412: }
12413: } else if (currprefs.cpu_model == 68020) {
12414: fill_prefetch_020 ();
12415: } else if (currprefs.cpu_model == 68030) {
12416: fill_prefetch_030 ();
12417: } else if (currprefs.cpu_model <= 68010) {
12418: uaecptr pc = m68k_getpc ();
12419: regs.ir = x_get_word (pc);
12420: regs.irc = x_get_word (pc + 2);
12421: }
1.1.1.4 root 12422: }
1.1.1.10! root 12423:
! 12424: #ifndef WINUAE_FOR_HATARI
! 12425: extern bool cpuboard_fc_check(uaecptr addr, uae_u32 *v, int size, bool write);
! 12426: #else
! 12427: STATIC_INLINE bool cpuboard_fc_check(uaecptr addr, uae_u32 *v, int size, bool write)
! 12428: {
! 12429: return false;
! 12430: }
! 12431: #endif
! 12432:
! 12433: uae_u32 sfc_nommu_get_byte(uaecptr addr)
! 12434: {
! 12435: uae_u32 v;
! 12436: if (!cpuboard_fc_check(addr, &v, 0, false))
! 12437: v = x_get_byte(addr);
! 12438: return v;
! 12439: }
! 12440: uae_u32 sfc_nommu_get_word(uaecptr addr)
! 12441: {
! 12442: uae_u32 v;
! 12443: if (!cpuboard_fc_check(addr, &v, 1, false))
! 12444: v = x_get_word(addr);
! 12445: return v;
! 12446: }
! 12447: uae_u32 sfc_nommu_get_long(uaecptr addr)
! 12448: {
! 12449: uae_u32 v;
! 12450: if (!cpuboard_fc_check(addr, &v, 2, false))
! 12451: v = x_get_long(addr);
! 12452: return v;
! 12453: }
! 12454: void dfc_nommu_put_byte(uaecptr addr, uae_u32 v)
! 12455: {
! 12456: if (!cpuboard_fc_check(addr, &v, 0, true))
! 12457: x_put_byte(addr, v);
! 12458: }
! 12459: void dfc_nommu_put_word(uaecptr addr, uae_u32 v)
! 12460: {
! 12461: if (!cpuboard_fc_check(addr, &v, 1, true))
! 12462: x_put_word(addr, v);
! 12463: }
! 12464: void dfc_nommu_put_long(uaecptr addr, uae_u32 v)
! 12465: {
! 12466: if (!cpuboard_fc_check(addr, &v, 2, true))
! 12467: x_put_long(addr, v);
! 12468: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.