|
|
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.7 root 38: #include "savestate.h"
1.1.1.9 ! root 39: #include "fpp.h"
1.1.1.7 root 40: #ifdef WINUAE_FOR_HATARI
41: #include "debug.h"
42: #endif
43:
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.4 root 63:
64:
65: #ifdef JIT
66: #include "jit/compemu.h"
67: #include <signal.h>
68: #else
69: /* Need to have these somewhere */
1.1.1.8 root 70: //#ifndef WINUAE_FOR_HATARI
71: bool check_prefs_changed_comp (bool checkonly) { return false; }
72: //#endif
1.1.1.7 root 73: #endif
1.1.1.4 root 74:
75: /* Opcode of faulting instruction */
76: static uae_u16 last_op_for_exception_3;
77: /* PC at fault time */
78: static uaecptr last_addr_for_exception_3;
79: /* Address that generated the exception */
80: static uaecptr last_fault_for_exception_3;
81: /* read (0) or write (1) access */
1.1.1.7 root 82: static bool last_writeaccess_for_exception_3;
1.1.1.4 root 83: /* instruction (1) or data (0) access */
1.1.1.7 root 84: static bool last_instructionaccess_for_exception_3;
85: /* not instruction */
86: static bool last_notinstruction_for_exception_3;
87: /* set when writing exception stack frame */
88: static int exception_in_exception;
89:
1.1.1.4 root 90: int mmu_enabled, mmu_triggered;
91: int cpu_cycles;
1.1.1.7 root 92: int bus_error_offset;
93: #ifndef WINUAE_FOR_HATARI
1.1.1.4 root 94: static int baseclock;
1.1.1.7 root 95: #endif
96: int m68k_pc_indirect;
97: bool m68k_interrupt_delay;
98: static bool m68k_reset_delay;
1.1.1.9 ! root 99:
! 100: static int cacheisets04060, cacheisets04060mask, cacheitag04060mask;
! 101: static int cachedsets04060, cachedsets04060mask, cachedtag04060mask;
! 102:
1.1.1.7 root 103: static int cpu_prefs_changed_flag;
104:
1.1.1.4 root 105: int cpucycleunit;
1.1.1.7 root 106: int cpu_tracer;
1.1.1.4 root 107:
108: const int areg_byteinc[] = { 1, 1, 1, 1, 1, 1, 1, 2 };
109: const int imm8_table[] = { 8, 1, 2, 3, 4, 5, 6, 7 };
110:
111: int movem_index1[256];
112: int movem_index2[256];
113: int movem_next[256];
114:
115: cpuop_func *cpufunctbl[65536];
116:
1.1.1.7 root 117: struct cputbl_data
118: {
119: uae_s16 length;
120: uae_s8 disp020[2];
121: uae_u8 branch;
122: };
123: static struct cputbl_data cpudatatbl[65536];
1.1.1.5 root 124:
1.1.1.4 root 125: struct mmufixup mmufixup[2];
126:
127: #define COUNT_INSTRS 0
128: #define MC68060_PCR 0x04300000
129: #define MC68EC060_PCR 0x04310000
130:
1.1.1.7 root 131: static uae_u64 fake_srp_030, fake_crp_030;
132: static uae_u32 fake_tt0_030, fake_tt1_030, fake_tc_030;
133: static uae_u16 fake_mmusr_030;
1.1.1.4 root 134:
135: static struct cache020 caches020[CACHELINES020];
136: static struct cache030 icaches030[CACHELINES030];
137: static struct cache030 dcaches030[CACHELINES030];
1.1.1.9 ! root 138: static int icachelinecnt, icachehalfline;
! 139: static int dcachelinecnt;
! 140: static struct cache040 icaches040[CACHESETS060];
! 141: static struct cache040 dcaches040[CACHESETS060];
! 142: static int cache_lastline;
1.1.1.7 root 143:
1.1.1.8 root 144: static int fallback_cpu_model, fallback_mmu_model, fallback_fpu_model;
1.1.1.9 ! root 145: static bool fallback_cpu_compatible, fallback_cpu_address_space_24;
1.1.1.8 root 146: static struct regstruct fallback_regs;
147: static int fallback_new_cpu_model;
1.1.1.7 root 148:
149: #ifdef WINUAE_FOR_HATARI
150: int OpcodeFamily;
151: int BusCyclePenalty = 0;
1.1.1.4 root 152:
1.1.1.7 root 153: FILE *console_out_FILE = NULL;
1.1.1.9 ! root 154:
! 155: int uae_quit_program = 0; /* from main.cpp */
1.1.1.7 root 156: #endif
1.1.1.4 root 157:
158:
159: #if COUNT_INSTRS
160: static unsigned long int instrcount[65536];
161: static uae_u16 opcodenums[65536];
162:
163: static int compfn (const void *el1, const void *el2)
164: {
165: return instrcount[*(const uae_u16 *)el1] < instrcount[*(const uae_u16 *)el2];
166: }
167:
168: static TCHAR *icountfilename (void)
169: {
170: TCHAR *name = getenv ("INSNCOUNT");
171: if (name)
172: return name;
173: return COUNT_INSTRS == 2 ? "frequent.68k" : "insncount";
174: }
175:
176: void dump_counts (void)
177: {
178: FILE *f = fopen (icountfilename (), "w");
179: unsigned long int total;
180: int i;
181:
1.1.1.7 root 182: write_log (_T("Writing instruction count file...\n"));
1.1.1.4 root 183: for (i = 0; i < 65536; i++) {
184: opcodenums[i] = i;
185: total += instrcount[i];
186: }
187: qsort (opcodenums, 65536, sizeof (uae_u16), compfn);
188:
189: fprintf (f, "Total: %lu\n", total);
190: for (i=0; i < 65536; i++) {
191: unsigned long int cnt = instrcount[opcodenums[i]];
192: struct instr *dp;
193: struct mnemolookup *lookup;
194: if (!cnt)
195: break;
196: dp = table68k + opcodenums[i];
197: for (lookup = lookuptab;lookup->mnemo != dp->mnemo; lookup++)
198: ;
199: fprintf (f, "%04x: %lu %s\n", opcodenums[i], cnt, lookup->name);
200: }
201: fclose (f);
202: }
203: #else
204: void dump_counts (void)
205: {
206: }
207: #endif
208:
1.1.1.7 root 209: /*
210:
211: ok, all this to "record" current instruction state
212: for later 100% cycle-exact restoring
213:
214: */
215:
216: static uae_u32 (*x2_prefetch)(int);
217: static uae_u32 (*x2_prefetch_long)(int);
218: static uae_u32 (*x2_next_iword)(void);
219: static uae_u32 (*x2_next_ilong)(void);
220: static uae_u32 (*x2_get_ilong)(int);
221: static uae_u32 (*x2_get_iword)(int);
222: static uae_u32 (*x2_get_ibyte)(int);
223: static uae_u32 (*x2_get_long)(uaecptr);
224: static uae_u32 (*x2_get_word)(uaecptr);
225: static uae_u32 (*x2_get_byte)(uaecptr);
226: static void (*x2_put_long)(uaecptr,uae_u32);
227: static void (*x2_put_word)(uaecptr,uae_u32);
228: static void (*x2_put_byte)(uaecptr,uae_u32);
229: static void (*x2_do_cycles)(unsigned long);
230: static void (*x2_do_cycles_pre)(unsigned long);
231: static void (*x2_do_cycles_post)(unsigned long, uae_u32);
1.1.1.4 root 232:
233: uae_u32 (*x_prefetch)(int);
234: uae_u32 (*x_next_iword)(void);
235: uae_u32 (*x_next_ilong)(void);
1.1.1.7 root 236: uae_u32 (*x_get_ilong)(int);
237: uae_u32 (*x_get_iword)(int);
238: uae_u32 (*x_get_ibyte)(int);
1.1.1.4 root 239: uae_u32 (*x_get_long)(uaecptr);
240: uae_u32 (*x_get_word)(uaecptr);
241: uae_u32 (*x_get_byte)(uaecptr);
242: void (*x_put_long)(uaecptr,uae_u32);
243: void (*x_put_word)(uaecptr,uae_u32);
244: void (*x_put_byte)(uaecptr,uae_u32);
245:
1.1.1.7 root 246: uae_u32 (*x_cp_next_iword)(void);
247: uae_u32 (*x_cp_next_ilong)(void);
248: uae_u32 (*x_cp_get_long)(uaecptr);
249: uae_u32 (*x_cp_get_word)(uaecptr);
250: uae_u32 (*x_cp_get_byte)(uaecptr);
251: void (*x_cp_put_long)(uaecptr,uae_u32);
252: void (*x_cp_put_word)(uaecptr,uae_u32);
253: void (*x_cp_put_byte)(uaecptr,uae_u32);
254: uae_u32 (REGPARAM3 *x_cp_get_disp_ea_020)(uae_u32 base, int idx) REGPARAM;
255:
256: void (*x_do_cycles)(unsigned long);
257: void (*x_do_cycles_pre)(unsigned long);
258: void (*x_do_cycles_post)(unsigned long, uae_u32);
259:
260: uae_u32(*x_phys_get_iword)(uaecptr);
261: uae_u32(*x_phys_get_ilong)(uaecptr);
262: uae_u32(*x_phys_get_byte)(uaecptr);
263: uae_u32(*x_phys_get_word)(uaecptr);
264: uae_u32(*x_phys_get_long)(uaecptr);
265: void(*x_phys_put_byte)(uaecptr, uae_u32);
266: void(*x_phys_put_word)(uaecptr, uae_u32);
267: void(*x_phys_put_long)(uaecptr, uae_u32);
268:
269: static void set_x_cp_funcs(void)
270: {
271: x_cp_put_long = x_put_long;
272: x_cp_put_word = x_put_word;
273: x_cp_put_byte = x_put_byte;
274: x_cp_get_long = x_get_long;
275: x_cp_get_word = x_get_word;
276: x_cp_get_byte = x_get_byte;
277: x_cp_next_iword = x_next_iword;
278: x_cp_next_ilong = x_next_ilong;
279: x_cp_get_disp_ea_020 = x_get_disp_ea_020;
280:
281: if (currprefs.mmu_model == 68030) {
1.1.1.9 ! root 282: if (currprefs.cpu_compatible) {
! 283: x_cp_put_long = put_long_mmu030c_state;
! 284: x_cp_put_word = put_word_mmu030c_state;
! 285: x_cp_put_byte = put_byte_mmu030c_state;
! 286: x_cp_get_long = get_long_mmu030c_state;
! 287: x_cp_get_word = get_word_mmu030c_state;
! 288: x_cp_get_byte = get_byte_mmu030c_state;
! 289: x_cp_next_iword = next_iword_mmu030c_state;
! 290: x_cp_next_ilong = next_ilong_mmu030c_state;
! 291: x_cp_get_disp_ea_020 = get_disp_ea_020_mmu030c;
! 292: } else {
! 293: x_cp_put_long = put_long_mmu030_state;
! 294: x_cp_put_word = put_word_mmu030_state;
! 295: x_cp_put_byte = put_byte_mmu030_state;
! 296: x_cp_get_long = get_long_mmu030_state;
! 297: x_cp_get_word = get_word_mmu030_state;
! 298: x_cp_get_byte = get_byte_mmu030_state;
! 299: x_cp_next_iword = next_iword_mmu030_state;
! 300: x_cp_next_ilong = next_ilong_mmu030_state;
! 301: x_cp_get_disp_ea_020 = get_disp_ea_020_mmu030;
! 302: }
1.1.1.7 root 303: }
304: }
305:
306: static struct cputracestruct cputrace;
307:
308: #if CPUTRACE_DEBUG
309: static void validate_trace (void)
310: {
311: for (int i = 0; i < cputrace.memoryoffset; i++) {
312: struct cputracememory *ctm = &cputrace.ctm[i];
313: if (ctm->data == 0xdeadf00d) {
314: write_log (_T("unfinished write operation %d %08x\n"), i, ctm->addr);
315: }
316: }
317: }
318: #endif
319:
320: static void debug_trace (void)
321: {
322: if (cputrace.writecounter > 10000 || cputrace.readcounter > 10000)
323: write_log (_T("cputrace.readcounter=%d cputrace.writecounter=%d\n"), cputrace.readcounter, cputrace.writecounter);
324: }
325:
326: STATIC_INLINE void clear_trace (void)
327: {
328: #if CPUTRACE_DEBUG
329: validate_trace ();
330: #endif
1.1.1.9 ! root 331: if (cputrace.memoryoffset == MAX_CPUTRACESIZE)
! 332: return;
1.1.1.7 root 333: struct cputracememory *ctm = &cputrace.ctm[cputrace.memoryoffset++];
1.1.1.9 ! root 334: if (cputrace.memoryoffset == MAX_CPUTRACESIZE) {
! 335: write_log(_T("CPUTRACE overflow, stopping tracing.\n"));
! 336: return;
! 337: }
1.1.1.7 root 338: ctm->mode = 0;
339: cputrace.cyclecounter = 0;
340: cputrace.cyclecounter_pre = cputrace.cyclecounter_post = 0;
341: }
342: static void set_trace (uaecptr addr, int accessmode, int size)
343: {
344: #if CPUTRACE_DEBUG
345: validate_trace ();
346: #endif
1.1.1.9 ! root 347: if (cputrace.memoryoffset == MAX_CPUTRACESIZE)
! 348: return;
1.1.1.7 root 349: struct cputracememory *ctm = &cputrace.ctm[cputrace.memoryoffset++];
1.1.1.9 ! root 350: if (cputrace.memoryoffset == MAX_CPUTRACESIZE) {
! 351: write_log(_T("CPUTRACE overflow, stopping tracing.\n"));
! 352: return;
! 353: }
1.1.1.7 root 354: ctm->addr = addr;
355: ctm->data = 0xdeadf00d;
356: ctm->mode = accessmode | (size << 4);
357: cputrace.cyclecounter_pre = -1;
358: if (accessmode == 1)
359: cputrace.writecounter++;
360: else
361: cputrace.readcounter++;
362: debug_trace ();
363: }
364: static void add_trace (uaecptr addr, uae_u32 val, int accessmode, int size)
365: {
366: if (cputrace.memoryoffset < 1) {
367: #if CPUTRACE_DEBUG
368: write_log (_T("add_trace memoryoffset=%d!\n"), cputrace.memoryoffset);
369: #endif
370: return;
371: }
372: int mode = accessmode | (size << 4);
373: struct cputracememory *ctm = &cputrace.ctm[cputrace.memoryoffset - 1];
374: ctm->addr = addr;
375: ctm->data = val;
376: if (!ctm->mode) {
377: ctm->mode = mode;
378: if (accessmode == 1)
379: cputrace.writecounter++;
380: else
381: cputrace.readcounter++;
382: }
383: debug_trace ();
384: cputrace.cyclecounter_pre = cputrace.cyclecounter_post = 0;
385: }
386:
387:
388: static void check_trace2 (void)
389: {
390: if (cputrace.readcounter || cputrace.writecounter ||
391: cputrace.cyclecounter || cputrace.cyclecounter_pre || cputrace.cyclecounter_post)
392: write_log (_T("CPU tracer invalid state during playback!\n"));
393: }
394:
395: static bool check_trace (void)
396: {
397: if (!cpu_tracer)
398: return true;
399: if (!cputrace.readcounter && !cputrace.writecounter && !cputrace.cyclecounter) {
400: if (cpu_tracer != -2) {
401: write_log (_T("CPU trace: dma_cycle() enabled. %08x %08x NOW=%08lx\n"),
402: cputrace.cyclecounter_pre, cputrace.cyclecounter_post, get_cycles ());
403: cpu_tracer = -2; // dma_cycle() allowed to work now
404: }
405: }
406: if (cputrace.readcounter || cputrace.writecounter ||
407: cputrace.cyclecounter || cputrace.cyclecounter_pre || cputrace.cyclecounter_post)
408: return false;
409: x_prefetch = x2_prefetch;
410: x_get_ilong = x2_get_ilong;
411: x_get_iword = x2_get_iword;
412: x_get_ibyte = x2_get_ibyte;
413: x_next_iword = x2_next_iword;
414: x_next_ilong = x2_next_ilong;
415: x_put_long = x2_put_long;
416: x_put_word = x2_put_word;
417: x_put_byte = x2_put_byte;
418: x_get_long = x2_get_long;
419: x_get_word = x2_get_word;
420: x_get_byte = x2_get_byte;
421: x_do_cycles = x2_do_cycles;
422: x_do_cycles_pre = x2_do_cycles_pre;
423: x_do_cycles_post = x2_do_cycles_post;
424: set_x_cp_funcs();
425: write_log (_T("CPU tracer playback complete. STARTCYCLES=%08x NOWCYCLES=%08lx\n"), cputrace.startcycles, get_cycles ());
426: cputrace.needendcycles = 1;
427: cpu_tracer = 0;
428: return true;
429: }
430:
431: static bool get_trace (uaecptr addr, int accessmode, int size, uae_u32 *data)
432: {
433: int mode = accessmode | (size << 4);
434: int i;
435: for (i = 0; i < cputrace.memoryoffset; i++) {
436: struct cputracememory *ctm = &cputrace.ctm[i];
437: if (ctm->addr == addr && ctm->mode == mode) {
438: ctm->mode = 0;
439: write_log (_T("CPU trace: GET %d: PC=%08x %08x=%08x %d %d %08x/%08x/%08x %d/%d (%08lx)\n"),
440: i, cputrace.pc, addr, ctm->data, accessmode, size,
441: cputrace.cyclecounter, cputrace.cyclecounter_pre, cputrace.cyclecounter_post,
442: cputrace.readcounter, cputrace.writecounter, get_cycles ());
443: if (accessmode == 1)
444: cputrace.writecounter--;
445: else
446: cputrace.readcounter--;
447: if (cputrace.writecounter == 0 && cputrace.readcounter == 0) {
448: if (cputrace.cyclecounter_post) {
449: int c = cputrace.cyclecounter_post;
450: cputrace.cyclecounter_post = 0;
451: x_do_cycles (c);
452: } else if (cputrace.cyclecounter_pre) {
453: check_trace ();
454: *data = ctm->data;
455: return true; // argh, need to rerun the memory access..
456: }
457: }
458: check_trace ();
459: *data = ctm->data;
460: return false;
461: }
462: }
463: if (cputrace.cyclecounter_post) {
464: int c = cputrace.cyclecounter_post;
465: cputrace.cyclecounter_post = 0;
466: check_trace ();
467: check_trace2 ();
468: x_do_cycles (c);
469: return false;
470: }
471: gui_message (_T("CPU trace: GET %08x %d %d NOT FOUND!\n"), addr, accessmode, size);
472: check_trace ();
473: *data = 0;
474: return false;
475: }
476:
477: static uae_u32 cputracefunc_x_prefetch (int o)
478: {
479: uae_u32 pc = m68k_getpc ();
480: set_trace (pc + o, 2, 2);
481: uae_u32 v = x2_prefetch (o);
482: add_trace (pc + o, v, 2, 2);
483: return v;
484: }
485: static uae_u32 cputracefunc2_x_prefetch (int o)
486: {
487: uae_u32 v;
488: if (get_trace (m68k_getpc () + o, 2, 2, &v)) {
489: v = x2_prefetch (o);
490: check_trace2 ();
491: }
492: return v;
493: }
494:
495: static uae_u32 cputracefunc_x_next_iword (void)
496: {
497: uae_u32 pc = m68k_getpc ();
498: set_trace (pc, 2, 2);
499: uae_u32 v = x2_next_iword ();
500: add_trace (pc, v, 2, 2);
501: return v;
502: }
503: static uae_u32 cputracefunc_x_next_ilong (void)
504: {
505: uae_u32 pc = m68k_getpc ();
506: set_trace (pc, 2, 4);
507: uae_u32 v = x2_next_ilong ();
508: add_trace (pc, v, 2, 4);
509: return v;
510: }
511: static uae_u32 cputracefunc2_x_next_iword (void)
512: {
513: uae_u32 v;
514: if (get_trace (m68k_getpc (), 2, 2, &v)) {
515: v = x2_next_iword ();
516: check_trace2 ();
517: }
518: return v;
519: }
520: static uae_u32 cputracefunc2_x_next_ilong (void)
521: {
522: uae_u32 v;
523: if (get_trace (m68k_getpc (), 2, 4, &v)) {
524: v = x2_next_ilong ();
525: check_trace2 ();
526: }
527: return v;
528: }
529:
530: static uae_u32 cputracefunc_x_get_ilong (int o)
531: {
532: uae_u32 pc = m68k_getpc ();
533: set_trace (pc + o, 2, 4);
534: uae_u32 v = x2_get_ilong (o);
535: add_trace (pc + o, v, 2, 4);
536: return v;
537: }
538: static uae_u32 cputracefunc_x_get_iword (int o)
539: {
540: uae_u32 pc = m68k_getpc ();
541: set_trace (pc + o, 2, 2);
542: uae_u32 v = x2_get_iword (o);
543: add_trace (pc + o, v, 2, 2);
544: return v;
545: }
546: static uae_u32 cputracefunc_x_get_ibyte (int o)
547: {
548: uae_u32 pc = m68k_getpc ();
549: set_trace (pc + o, 2, 1);
550: uae_u32 v = x2_get_ibyte (o);
551: add_trace (pc + o, v, 2, 1);
552: return v;
553: }
554: static uae_u32 cputracefunc2_x_get_ilong (int o)
555: {
556: uae_u32 v;
557: if (get_trace (m68k_getpc () + o, 2, 4, &v)) {
558: v = x2_get_ilong (o);
559: check_trace2 ();
560: }
561: return v;
562: }
563: static uae_u32 cputracefunc2_x_get_iword (int o)
564: {
565: uae_u32 v;
566: if (get_trace (m68k_getpc () + o, 2, 2, &v)) {
567: v = x2_get_iword (o);
568: check_trace2 ();
569: }
570: return v;
571: }
572: static uae_u32 cputracefunc2_x_get_ibyte (int o)
573: {
574: uae_u32 v;
575: if (get_trace (m68k_getpc () + o, 2, 1, &v)) {
576: v = x2_get_ibyte (o);
577: check_trace2 ();
578: }
579: return v;
580: }
581:
582: static uae_u32 cputracefunc_x_get_long (uaecptr o)
583: {
584: set_trace (o, 0, 4);
585: uae_u32 v = x2_get_long (o);
586: add_trace (o, v, 0, 4);
587: return v;
588: }
589: static uae_u32 cputracefunc_x_get_word (uaecptr o)
590: {
591: set_trace (o, 0, 2);
592: uae_u32 v = x2_get_word (o);
593: add_trace (o, v, 0, 2);
594: return v;
595: }
596: static uae_u32 cputracefunc_x_get_byte (uaecptr o)
597: {
598: set_trace (o, 0, 1);
599: uae_u32 v = x2_get_byte (o);
600: add_trace (o, v, 0, 1);
601: return v;
602: }
603: static uae_u32 cputracefunc2_x_get_long (uaecptr o)
604: {
605: uae_u32 v;
606: if (get_trace (o, 0, 4, &v)) {
607: v = x2_get_long (o);
608: check_trace2 ();
609: }
610: return v;
611: }
612: static uae_u32 cputracefunc2_x_get_word (uaecptr o)
613: {
614: uae_u32 v;
615: if (get_trace (o, 0, 2, &v)) {
616: v = x2_get_word (o);
617: check_trace2 ();
618: }
619: return v;
620: }
621: static uae_u32 cputracefunc2_x_get_byte (uaecptr o)
622: {
623: uae_u32 v;
624: if (get_trace (o, 0, 1, &v)) {
625: v = x2_get_byte (o);
626: check_trace2 ();
627: }
628: return v;
629: }
630:
631: static void cputracefunc_x_put_long (uaecptr o, uae_u32 val)
632: {
633: clear_trace ();
634: add_trace (o, val, 1, 4);
635: x2_put_long (o, val);
636: }
637: static void cputracefunc_x_put_word (uaecptr o, uae_u32 val)
638: {
639: clear_trace ();
640: add_trace (o, val, 1, 2);
641: x2_put_word (o, val);
642: }
643: static void cputracefunc_x_put_byte (uaecptr o, uae_u32 val)
644: {
645: clear_trace ();
646: add_trace (o, val, 1, 1);
647: x2_put_byte (o, val);
648: }
649: static void cputracefunc2_x_put_long (uaecptr o, uae_u32 val)
650: {
651: uae_u32 v;
652: if (get_trace (o, 1, 4, &v)) {
653: x2_put_long (o, val);
654: check_trace2 ();
655: }
656: if (v != val)
657: write_log (_T("cputracefunc2_x_put_long %d <> %d\n"), v, val);
658: }
659: static void cputracefunc2_x_put_word (uaecptr o, uae_u32 val)
660: {
661: uae_u32 v;
662: if (get_trace (o, 1, 2, &v)) {
663: x2_put_word (o, val);
664: check_trace2 ();
665: }
666: if (v != val)
667: write_log (_T("cputracefunc2_x_put_word %d <> %d\n"), v, val);
668: }
669: static void cputracefunc2_x_put_byte (uaecptr o, uae_u32 val)
670: {
671: uae_u32 v;
672: if (get_trace (o, 1, 1, &v)) {
673: x2_put_byte (o, val);
674: check_trace2 ();
675: }
676: if (v != val)
677: write_log (_T("cputracefunc2_x_put_byte %d <> %d\n"), v, val);
678: }
679:
680: static void cputracefunc_x_do_cycles (unsigned long cycles)
681: {
682: while (cycles >= CYCLE_UNIT) {
683: cputrace.cyclecounter += CYCLE_UNIT;
684: cycles -= CYCLE_UNIT;
685: x2_do_cycles (CYCLE_UNIT);
686: }
687: if (cycles > 0) {
688: cputrace.cyclecounter += cycles;
689: x2_do_cycles (cycles);
690: }
691: }
692:
693: static void cputracefunc2_x_do_cycles (unsigned long cycles)
694: {
695: if (cputrace.cyclecounter > (long)cycles) {
696: cputrace.cyclecounter -= cycles;
697: return;
698: }
699: cycles -= cputrace.cyclecounter;
700: cputrace.cyclecounter = 0;
701: check_trace ();
702: x_do_cycles = x2_do_cycles;
703: if (cycles > 0)
704: x_do_cycles (cycles);
705: }
706:
707: static void cputracefunc_x_do_cycles_pre (unsigned long cycles)
708: {
709: cputrace.cyclecounter_post = 0;
710: cputrace.cyclecounter_pre = 0;
711: while (cycles >= CYCLE_UNIT) {
712: cycles -= CYCLE_UNIT;
713: cputrace.cyclecounter_pre += CYCLE_UNIT;
714: x2_do_cycles (CYCLE_UNIT);
715: }
716: if (cycles > 0) {
717: x2_do_cycles (cycles);
718: cputrace.cyclecounter_pre += cycles;
719: }
720: cputrace.cyclecounter_pre = 0;
721: }
722: // cyclecounter_pre = how many cycles we need to SWALLOW
723: // -1 = rerun whole access
724: static void cputracefunc2_x_do_cycles_pre (unsigned long cycles)
725: {
726: if (cputrace.cyclecounter_pre == -1) {
727: cputrace.cyclecounter_pre = 0;
728: check_trace ();
729: check_trace2 ();
730: x_do_cycles (cycles);
731: return;
732: }
733: if (cputrace.cyclecounter_pre > (long)cycles) {
734: cputrace.cyclecounter_pre -= cycles;
735: return;
736: }
737: cycles -= cputrace.cyclecounter_pre;
738: cputrace.cyclecounter_pre = 0;
739: check_trace ();
740: if (cycles > 0)
741: x_do_cycles (cycles);
742: }
743:
744: static void cputracefunc_x_do_cycles_post (unsigned long cycles, uae_u32 v)
745: {
746: if (cputrace.memoryoffset < 1) {
747: #if CPUTRACE_DEBUG
748: write_log (_T("cputracefunc_x_do_cycles_post memoryoffset=%d!\n"), cputrace.memoryoffset);
749: #endif
750: return;
751: }
752: struct cputracememory *ctm = &cputrace.ctm[cputrace.memoryoffset - 1];
753: ctm->data = v;
754: cputrace.cyclecounter_post = cycles;
755: cputrace.cyclecounter_pre = 0;
756: while (cycles >= CYCLE_UNIT) {
757: cycles -= CYCLE_UNIT;
758: cputrace.cyclecounter_post -= CYCLE_UNIT;
759: x2_do_cycles (CYCLE_UNIT);
760: }
761: if (cycles > 0) {
762: cputrace.cyclecounter_post -= cycles;
763: x2_do_cycles (cycles);
764: }
765: cputrace.cyclecounter_post = 0;
766: }
767: // cyclecounter_post = how many cycles we need to WAIT
768: static void cputracefunc2_x_do_cycles_post (unsigned long cycles, uae_u32 v)
769: {
770: uae_u32 c;
771: if (cputrace.cyclecounter_post) {
772: c = cputrace.cyclecounter_post;
773: cputrace.cyclecounter_post = 0;
774: } else {
775: c = cycles;
776: }
777: check_trace ();
778: if (c > 0)
779: x_do_cycles (c);
780: }
781:
782: static void do_cycles_post (unsigned long cycles, uae_u32 v)
783: {
784: do_cycles (cycles);
785: }
786: static void do_cycles_ce_post (unsigned long cycles, uae_u32 v)
787: {
788: do_cycles_ce (cycles);
789: }
790: static void do_cycles_ce020_post (unsigned long cycles, uae_u32 v)
791: {
792: #ifndef WINUAE_FOR_HATARI
793: do_cycles_ce020 (cycles);
794: #else
795: do_cycles_ce020_long (cycles);
796: #endif
797: }
798:
1.1.1.9 ! root 799: static uae_u8 dcache_check_nommu(uaecptr addr, bool write, uae_u32 size)
! 800: {
! 801: return ce_cachable[addr >> 16];
! 802: }
! 803:
! 804: static void mem_access_delay_long_write_ce030_cicheck(uaecptr addr, uae_u32 v)
! 805: {
! 806: mem_access_delay_long_write_ce020(addr, v);
! 807: mmu030_cache_state = ce_cachable[addr >> 16];
! 808: }
! 809: static void mem_access_delay_word_write_ce030_cicheck(uaecptr addr, uae_u32 v)
! 810: {
! 811: mem_access_delay_word_write_ce020(addr, v);
! 812: mmu030_cache_state = ce_cachable[addr >> 16];
! 813: }
! 814: static void mem_access_delay_byte_write_ce030_cicheck(uaecptr addr, uae_u32 v)
! 815: {
! 816: mem_access_delay_byte_write_ce020(addr, v);
! 817: mmu030_cache_state = ce_cachable[addr >> 16];
! 818: }
! 819:
! 820: static void put_long030_cicheck(uaecptr addr, uae_u32 v)
! 821: {
! 822: put_long(addr, v);
! 823: mmu030_cache_state = ce_cachable[addr >> 16];
! 824: }
! 825: static void put_word030_cicheck(uaecptr addr, uae_u32 v)
! 826: {
! 827: put_word(addr, v);
! 828: mmu030_cache_state = ce_cachable[addr >> 16];
! 829: }
! 830: static void put_byte030_cicheck(uaecptr addr, uae_u32 v)
! 831: {
! 832: put_byte(addr, v);
! 833: mmu030_cache_state = ce_cachable[addr >> 16];
! 834: }
! 835:
! 836: static uae_u32 (*icache_fetch)(uaecptr);
! 837: static uae_u32 (*dcache_lget)(uaecptr);
! 838: static uae_u32 (*dcache_wget)(uaecptr);
! 839: static uae_u32 (*dcache_bget)(uaecptr);
! 840: static uae_u8 (*dcache_check)(uaecptr, bool, uae_u32);
! 841: static void (*dcache_lput)(uaecptr, uae_u32);
! 842: static void (*dcache_wput)(uaecptr, uae_u32);
! 843: static void (*dcache_bput)(uaecptr, uae_u32);
! 844:
! 845: uae_u32(*read_data_030_bget)(uaecptr);
! 846: uae_u32(*read_data_030_wget)(uaecptr);
! 847: uae_u32(*read_data_030_lget)(uaecptr);
! 848: void(*write_data_030_bput)(uaecptr,uae_u32);
! 849: void(*write_data_030_wput)(uaecptr,uae_u32);
! 850: void(*write_data_030_lput)(uaecptr,uae_u32);
! 851:
! 852: uae_u32(*read_data_030_fc_bget)(uaecptr, uae_u32);
! 853: uae_u32(*read_data_030_fc_wget)(uaecptr, uae_u32);
! 854: uae_u32(*read_data_030_fc_lget)(uaecptr, uae_u32);
! 855: void(*write_data_030_fc_bput)(uaecptr, uae_u32, uae_u32);
! 856: void(*write_data_030_fc_wput)(uaecptr, uae_u32, uae_u32);
! 857: void(*write_data_030_fc_lput)(uaecptr, uae_u32, uae_u32);
! 858:
! 859:
! 860: static void set_x_ifetches(void)
1.1.1.7 root 861: {
862: if (m68k_pc_indirect) {
863: if (currprefs.cachesize) {
864: // indirect via addrbank
865: x_get_ilong = get_iilong_jit;
866: x_get_iword = get_iiword_jit;
867: x_get_ibyte = get_iibyte_jit;
868: x_next_iword = next_iiword_jit;
869: x_next_ilong = next_iilong_jit;
870: } else {
871: // indirect via addrbank
872: x_get_ilong = get_iilong;
873: x_get_iword = get_iiword;
874: x_get_ibyte = get_iibyte;
875: x_next_iword = next_iiword;
876: x_next_ilong = next_iilong;
877: }
878: } else {
879: // direct to memory
880: x_get_ilong = get_dilong;
881: x_get_iword = get_diword;
882: x_get_ibyte = get_dibyte;
883: x_next_iword = next_diword;
884: x_next_ilong = next_dilong;
885: }
886: }
887:
1.1.1.9 ! root 888:
! 889: #ifdef WINUAE_FOR_HATARI
! 890:
! 891: void (*x_do_cycles_hatari_blitter_save)(unsigned long);
! 892: void (*x_do_cycles_pre_hatari_blitter_save)(unsigned long);
! 893: void (*x_do_cycles_post_hatari_blitter_save)(unsigned long, uae_u32);
! 894:
! 895: static void do_cycles_ce_post_hatari_blitter (unsigned long cycles, uae_u32 v)
! 896: {
! 897: do_cycles_ce_hatari_blitter (cycles);
! 898: }
! 899:
! 900: void set_x_funcs_hatari_blitter (int flag)
! 901: {
! 902: if ( flag == 0 )
! 903: {
! 904: //fprintf ( stderr , "restore blitter x_funcs\n" );
! 905: /* disable blitter, restore functions if needed */
! 906: if ( x_do_cycles_hatari_blitter_save )
! 907: {
! 908: x_do_cycles = x_do_cycles_hatari_blitter_save;
! 909: x_do_cycles_pre = x_do_cycles_pre_hatari_blitter_save;
! 910: x_do_cycles_post = x_do_cycles_post_hatari_blitter_save;
! 911: }
! 912: }
! 913: else
! 914: {
! 915: //fprintf ( stderr , "save/set blitter x_funcs\n" );
! 916: /* save current functions */
! 917: x_do_cycles_hatari_blitter_save = x_do_cycles;
! 918: x_do_cycles_pre_hatari_blitter_save = x_do_cycles_pre;
! 919: x_do_cycles_post_hatari_blitter_save = x_do_cycles_post;
! 920:
! 921: /* set blitter specific functions */
! 922: x_do_cycles = do_cycles_ce_hatari_blitter;
! 923: x_do_cycles_pre = do_cycles_ce_hatari_blitter;
! 924: x_do_cycles_post = do_cycles_ce_post_hatari_blitter;
! 925: }
! 926: }
! 927:
! 928: #endif
! 929:
1.1.1.7 root 930: // indirect memory access functions
1.1.1.4 root 931: static void set_x_funcs (void)
932: {
1.1.1.7 root 933: if (currprefs.mmu_model) {
934: if (currprefs.cpu_model == 68060) {
1.1.1.9 ! root 935:
1.1.1.7 root 936: x_prefetch = get_iword_mmu060;
937: x_get_ilong = get_ilong_mmu060;
938: x_get_iword = get_iword_mmu060;
939: x_get_ibyte = get_ibyte_mmu060;
940: x_next_iword = next_iword_mmu060;
941: x_next_ilong = next_ilong_mmu060;
942: x_put_long = put_long_mmu060;
943: x_put_word = put_word_mmu060;
944: x_put_byte = put_byte_mmu060;
945: x_get_long = get_long_mmu060;
946: x_get_word = get_word_mmu060;
947: x_get_byte = get_byte_mmu060;
1.1.1.9 ! root 948:
1.1.1.7 root 949: } else if (currprefs.cpu_model == 68040) {
1.1.1.9 ! root 950:
1.1.1.7 root 951: x_prefetch = get_iword_mmu040;
952: x_get_ilong = get_ilong_mmu040;
953: x_get_iword = get_iword_mmu040;
954: x_get_ibyte = get_ibyte_mmu040;
955: x_next_iword = next_iword_mmu040;
956: x_next_ilong = next_ilong_mmu040;
957: x_put_long = put_long_mmu040;
958: x_put_word = put_word_mmu040;
959: x_put_byte = put_byte_mmu040;
960: x_get_long = get_long_mmu040;
961: x_get_word = get_word_mmu040;
962: x_get_byte = get_byte_mmu040;
1.1.1.9 ! root 963:
1.1.1.7 root 964: } else {
1.1.1.9 ! root 965:
! 966: if (currprefs.cpu_memory_cycle_exact) {
! 967: x_prefetch = get_iword_mmu030c_state;
! 968: x_get_ilong = get_ilong_mmu030c_state;
! 969: x_get_iword = get_iword_mmu030c_state;
! 970: x_get_ibyte = NULL;
! 971: x_next_iword = next_iword_mmu030c_state;
! 972: x_next_ilong = next_ilong_mmu030c_state;
! 973: x_do_cycles = do_cycles;
! 974: x_do_cycles_pre = do_cycles;
! 975: x_do_cycles_post = do_cycles_post;
! 976: } else if (currprefs.cpu_compatible) {
! 977: x_prefetch = get_iword_mmu030c_state;
! 978: x_get_ilong = get_ilong_mmu030c_state;
! 979: x_get_iword = get_iword_mmu030c_state;
! 980: x_get_ibyte = NULL;
! 981: x_next_iword = next_iword_mmu030c_state;
! 982: x_next_ilong = next_ilong_mmu030c_state;
! 983: x_do_cycles = do_cycles;
! 984: x_do_cycles_pre = do_cycles;
! 985: x_do_cycles_post = do_cycles_post;
! 986: } else {
! 987: x_prefetch = get_iword_mmu030;
! 988: x_get_ilong = get_ilong_mmu030;
! 989: x_get_iword = get_iword_mmu030;
! 990: x_get_ibyte = get_ibyte_mmu030;
! 991: x_next_iword = next_iword_mmu030;
! 992: x_next_ilong = next_ilong_mmu030;
! 993: }
1.1.1.7 root 994: x_put_long = put_long_mmu030;
995: x_put_word = put_word_mmu030;
996: x_put_byte = put_byte_mmu030;
997: x_get_long = get_long_mmu030;
998: x_get_word = get_word_mmu030;
999: x_get_byte = get_byte_mmu030;
1.1.1.9 ! root 1000: if (currprefs.cpu_data_cache) {
! 1001: x_put_long = put_long_dc030;
! 1002: x_put_word = put_word_dc030;
! 1003: x_put_byte = put_byte_dc030;
! 1004: x_get_long = get_long_dc030;
! 1005: x_get_word = get_word_dc030;
! 1006: x_get_byte = get_byte_dc030;
! 1007: }
! 1008:
1.1.1.7 root 1009: }
1010: x_do_cycles = do_cycles;
1011: x_do_cycles_pre = do_cycles;
1012: x_do_cycles_post = do_cycles_post;
1.1.1.4 root 1013: } else if (currprefs.cpu_model < 68020) {
1.1.1.7 root 1014: // 68000/010
1015: if (currprefs.cpu_cycle_exact) {
1016: x_prefetch = get_word_ce000_prefetch;
1017: x_get_ilong = NULL;
1018: x_get_iword = get_wordi_ce000;
1019: x_get_ibyte = NULL;
1020: x_next_iword = NULL;
1021: x_next_ilong = NULL;
1022: x_put_long = put_long_ce000;
1023: x_put_word = put_word_ce000;
1024: x_put_byte = put_byte_ce000;
1025: x_get_long = get_long_ce000;
1026: x_get_word = get_word_ce000;
1027: x_get_byte = get_byte_ce000;
1028: x_do_cycles = do_cycles_ce;
1029: x_do_cycles_pre = do_cycles_ce;
1030: x_do_cycles_post = do_cycles_ce_post;
1.1.1.8 root 1031: } else if (currprefs.cpu_memory_cycle_exact) {
1032: // cpu_memory_cycle_exact + cpu_compatible
1033: x_prefetch = get_word_000_prefetch;
1034: x_get_ilong = NULL;
1035: x_get_iword = get_iiword;
1036: x_get_ibyte = get_iibyte;
1037: x_next_iword = NULL;
1038: x_next_ilong = NULL;
1039: x_put_long = put_long_ce000;
1040: x_put_word = put_word_ce000;
1041: x_put_byte = put_byte_ce000;
1042: x_get_long = get_long_ce000;
1043: x_get_word = get_word_ce000;
1044: x_get_byte = get_byte_ce000;
1045: x_do_cycles = do_cycles;
1046: x_do_cycles_pre = do_cycles;
1047: x_do_cycles_post = do_cycles_post;
1.1.1.7 root 1048: } else if (currprefs.cpu_compatible) {
1.1.1.8 root 1049: // cpu_compatible only
1050: x_prefetch = get_word_000_prefetch;
1.1.1.7 root 1051: x_get_ilong = NULL;
1052: x_get_iword = get_iiword;
1053: x_get_ibyte = get_iibyte;
1054: x_next_iword = NULL;
1055: x_next_ilong = NULL;
1056: x_put_long = put_long;
1057: x_put_word = put_word;
1058: x_put_byte = put_byte;
1059: x_get_long = get_long;
1060: x_get_word = get_word;
1061: x_get_byte = get_byte;
1062: x_do_cycles = do_cycles;
1063: x_do_cycles_pre = do_cycles;
1064: x_do_cycles_post = do_cycles_post;
1065: } else {
1066: x_prefetch = NULL;
1067: x_get_ilong = get_dilong;
1068: x_get_iword = get_diword;
1069: x_get_ibyte = get_dibyte;
1070: x_next_iword = next_diword;
1071: x_next_ilong = next_dilong;
1072: x_put_long = put_long;
1073: x_put_word = put_word;
1074: x_put_byte = put_byte;
1075: x_get_long = get_long;
1076: x_get_word = get_word;
1077: x_get_byte = get_byte;
1078: x_do_cycles = do_cycles;
1079: x_do_cycles_pre = do_cycles;
1080: x_do_cycles_post = do_cycles_post;
1081: }
1082: } else if (!currprefs.cpu_cycle_exact) {
1083: // 68020+ no ce
1.1.1.8 root 1084: if (currprefs.cpu_memory_cycle_exact) {
1085: // cpu_memory_cycle_exact + cpu_compatible
1086: if (currprefs.cpu_model == 68020 && !currprefs.cachesize) {
1087: x_prefetch = get_word_020_prefetch;
1088: x_get_ilong = get_long_020_prefetch;
1089: x_get_iword = get_word_020_prefetch;
1090: x_get_ibyte = NULL;
1091: x_next_iword = next_iword_020_prefetch;
1092: x_next_ilong = next_ilong_020_prefetch;
1093: x_put_long = put_long_ce020;
1094: x_put_word = put_word_ce020;
1095: x_put_byte = put_byte_ce020;
1096: x_get_long = get_long_ce020;
1097: x_get_word = get_word_ce020;
1098: x_get_byte = get_byte_ce020;
1099: x_do_cycles = do_cycles;
1100: x_do_cycles_pre = do_cycles;
1101: x_do_cycles_post = do_cycles_post;
1102: } else if (currprefs.cpu_model == 68030 && !currprefs.cachesize) {
1103: x_prefetch = get_word_030_prefetch;
1104: x_get_ilong = get_long_030_prefetch;
1105: x_get_iword = get_word_030_prefetch;
1106: x_get_ibyte = NULL;
1107: x_next_iword = next_iword_030_prefetch;
1108: x_next_ilong = next_ilong_030_prefetch;
1109: x_put_long = put_long_ce030;
1110: x_put_word = put_word_ce030;
1111: x_put_byte = put_byte_ce030;
1112: x_get_long = get_long_ce030;
1113: x_get_word = get_word_ce030;
1114: x_get_byte = get_byte_ce030;
1115: x_do_cycles = do_cycles;
1116: x_do_cycles_pre = do_cycles;
1117: x_do_cycles_post = do_cycles_post;
1118: } else if (currprefs.cpu_model < 68040) {
1119: // JIT or 68030+ does not have real prefetch only emulation
1120: x_prefetch = NULL;
1121: set_x_ifetches();
1122: x_put_long = put_long;
1123: x_put_word = put_word;
1124: x_put_byte = put_byte;
1125: x_get_long = get_long;
1126: x_get_word = get_word;
1127: x_get_byte = get_byte;
1128: x_do_cycles = do_cycles;
1129: x_do_cycles_pre = do_cycles;
1130: x_do_cycles_post = do_cycles_post;
1131: } else {
1132: // 68040+ (same as below)
1133: x_prefetch = NULL;
1134: x_get_ilong = get_ilong_cache_040;
1135: x_get_iword = get_iword_cache_040;
1136: x_get_ibyte = NULL;
1137: x_next_iword = next_iword_cache040;
1138: x_next_ilong = next_ilong_cache040;
1.1.1.9 ! root 1139: if (currprefs.cpu_data_cache) {
! 1140: x_put_long = put_long_cache_040;
! 1141: x_put_word = put_word_cache_040;
! 1142: x_put_byte = put_byte_cache_040;
! 1143: x_get_long = get_long_cache_040;
! 1144: x_get_word = get_word_cache_040;
! 1145: x_get_byte = get_byte_cache_040;
! 1146: } else {
! 1147: x_get_byte = mem_access_delay_byte_read_c040;
! 1148: x_get_word = mem_access_delay_word_read_c040;
! 1149: x_get_long = mem_access_delay_long_read_c040;
! 1150: x_put_byte = mem_access_delay_byte_write_c040;
! 1151: x_put_word = mem_access_delay_word_write_c040;
! 1152: x_put_long = mem_access_delay_long_write_c040;
! 1153: }
1.1.1.8 root 1154: x_do_cycles = do_cycles;
1155: x_do_cycles_pre = do_cycles;
1156: x_do_cycles_post = do_cycles_post;
1157: }
1158: } else if (currprefs.cpu_compatible) {
1159: // cpu_compatible only
1.1.1.7 root 1160: if (currprefs.cpu_model == 68020 && !currprefs.cachesize) {
1.1.1.8 root 1161: x_prefetch = get_word_020_prefetch;
1.1.1.7 root 1162: x_get_ilong = get_long_020_prefetch;
1163: x_get_iword = get_word_020_prefetch;
1164: x_get_ibyte = NULL;
1165: x_next_iword = next_iword_020_prefetch;
1166: x_next_ilong = next_ilong_020_prefetch;
1167: x_put_long = put_long;
1168: x_put_word = put_word;
1169: x_put_byte = put_byte;
1170: x_get_long = get_long;
1171: x_get_word = get_word;
1172: x_get_byte = get_byte;
1173: x_do_cycles = do_cycles;
1174: x_do_cycles_pre = do_cycles;
1175: x_do_cycles_post = do_cycles_post;
1176: } else if (currprefs.cpu_model == 68030 && !currprefs.cachesize) {
1.1.1.9 ! root 1177: x_prefetch = get_word_030_prefetch;
1.1.1.7 root 1178: x_get_ilong = get_long_030_prefetch;
1179: x_get_iword = get_word_030_prefetch;
1180: x_get_ibyte = NULL;
1181: x_next_iword = next_iword_030_prefetch;
1182: x_next_ilong = next_ilong_030_prefetch;
1.1.1.9 ! root 1183: x_put_long = put_long_030;
! 1184: x_put_word = put_word_030;
! 1185: x_put_byte = put_byte_030;
! 1186: x_get_long = get_long_030;
! 1187: x_get_word = get_word_030;
! 1188: x_get_byte = get_byte_030;
1.1.1.7 root 1189: x_do_cycles = do_cycles;
1190: x_do_cycles_pre = do_cycles;
1191: x_do_cycles_post = do_cycles_post;
1192: } else if (currprefs.cpu_model < 68040) {
1193: // JIT or 68030+ does not have real prefetch only emulation
1194: x_prefetch = NULL;
1195: set_x_ifetches();
1196: x_put_long = put_long;
1197: x_put_word = put_word;
1198: x_put_byte = put_byte;
1199: x_get_long = get_long;
1200: x_get_word = get_word;
1201: x_get_byte = get_byte;
1202: x_do_cycles = do_cycles;
1203: x_do_cycles_pre = do_cycles;
1204: x_do_cycles_post = do_cycles_post;
1205: } else {
1206: x_prefetch = NULL;
1207: x_get_ilong = get_ilong_cache_040;
1208: x_get_iword = get_iword_cache_040;
1209: x_get_ibyte = NULL;
1210: x_next_iword = next_iword_cache040;
1211: x_next_ilong = next_ilong_cache040;
1.1.1.9 ! root 1212: if (currprefs.cpu_data_cache) {
! 1213: x_put_long = put_long_cache_040;
! 1214: x_put_word = put_word_cache_040;
! 1215: x_put_byte = put_byte_cache_040;
! 1216: x_get_long = get_long_cache_040;
! 1217: x_get_word = get_word_cache_040;
! 1218: x_get_byte = get_byte_cache_040;
! 1219: } else {
! 1220: x_put_long = put_long;
! 1221: x_put_word = put_word;
! 1222: x_put_byte = put_byte;
! 1223: x_get_long = get_long;
! 1224: x_get_word = get_word;
! 1225: x_get_byte = get_byte;
! 1226: }
1.1.1.7 root 1227: x_do_cycles = do_cycles;
1228: x_do_cycles_pre = do_cycles;
1229: x_do_cycles_post = do_cycles_post;
1230: }
1231: } else {
1232: x_prefetch = NULL;
1233: set_x_ifetches();
1.1.1.8 root 1234: if (currprefs.cachesize) {
1235: x_put_long = put_long_jit;
1236: x_put_word = put_word_jit;
1237: x_put_byte = put_byte_jit;
1238: x_get_long = get_long_jit;
1239: x_get_word = get_word_jit;
1240: x_get_byte = get_byte_jit;
1241: } else {
1242: x_put_long = put_long;
1243: x_put_word = put_word;
1244: x_put_byte = put_byte;
1245: x_get_long = get_long;
1246: x_get_word = get_word;
1247: x_get_byte = get_byte;
1248: }
1.1.1.7 root 1249: x_do_cycles = do_cycles;
1250: x_do_cycles_pre = do_cycles;
1251: x_do_cycles_post = do_cycles_post;
1252: }
1253: // 68020+ cycle exact
1.1.1.4 root 1254: } else if (currprefs.cpu_model == 68020) {
1255: x_prefetch = get_word_ce020_prefetch;
1.1.1.7 root 1256: x_get_ilong = get_long_ce020_prefetch;
1257: x_get_iword = get_word_ce020_prefetch;
1258: x_get_ibyte = NULL;
1.1.1.4 root 1259: x_next_iword = next_iword_020ce;
1260: x_next_ilong = next_ilong_020ce;
1261: x_put_long = put_long_ce020;
1262: x_put_word = put_word_ce020;
1263: x_put_byte = put_byte_ce020;
1264: x_get_long = get_long_ce020;
1265: x_get_word = get_word_ce020;
1266: x_get_byte = get_byte_ce020;
1.1.1.7 root 1267: #ifndef WINUAE_FOR_HATARI
1268: x_do_cycles = do_cycles_ce020;
1269: x_do_cycles_pre = do_cycles_ce020;
1270: x_do_cycles_post = do_cycles_ce020_post;
1271: #else
1272: x_do_cycles = do_cycles_ce020_long;
1273: x_do_cycles_pre = do_cycles_ce020_long;
1274: x_do_cycles_post = do_cycles_ce020_post;
1275: #endif
1276: } else if (currprefs.cpu_model == 68030) {
1.1.1.4 root 1277: x_prefetch = get_word_ce030_prefetch;
1.1.1.7 root 1278: x_get_ilong = get_long_ce030_prefetch;
1279: x_get_iword = get_word_ce030_prefetch;
1280: x_get_ibyte = NULL;
1.1.1.4 root 1281: x_next_iword = next_iword_030ce;
1282: x_next_ilong = next_ilong_030ce;
1.1.1.9 ! root 1283: if (currprefs.cpu_data_cache) {
! 1284: x_put_long = put_long_dc030;
! 1285: x_put_word = put_word_dc030;
! 1286: x_put_byte = put_byte_dc030;
! 1287: x_get_long = get_long_dc030;
! 1288: x_get_word = get_word_dc030;
! 1289: x_get_byte = get_byte_dc030;
! 1290: } else {
! 1291: x_put_long = put_long_ce030;
! 1292: x_put_word = put_word_ce030;
! 1293: x_put_byte = put_byte_ce030;
! 1294: x_get_long = get_long_ce030;
! 1295: x_get_word = get_word_ce030;
! 1296: x_get_byte = get_byte_ce030;
! 1297: }
1.1.1.7 root 1298: #ifndef WINUAE_FOR_HATARI
1299: x_do_cycles = do_cycles_ce020;
1300: x_do_cycles_pre = do_cycles_ce020;
1301: x_do_cycles_post = do_cycles_ce020_post;
1302: #else
1303: x_do_cycles = do_cycles_ce020_long;
1304: x_do_cycles_pre = do_cycles_ce020_long;
1305: x_do_cycles_post = do_cycles_ce020_post;
1306: #endif
1307: } else if (currprefs.cpu_model >= 68040) {
1308: x_prefetch = NULL;
1309: x_get_ilong = get_ilong_cache_040;
1310: x_get_iword = get_iword_cache_040;
1311: x_get_ibyte = NULL;
1312: x_next_iword = next_iword_cache040;
1313: x_next_ilong = next_ilong_cache040;
1.1.1.9 ! root 1314: if (currprefs.cpu_data_cache) {
! 1315: x_put_long = put_long_cache_040;
! 1316: x_put_word = put_word_cache_040;
! 1317: x_put_byte = put_byte_cache_040;
! 1318: x_get_long = get_long_cache_040;
! 1319: x_get_word = get_word_cache_040;
! 1320: x_get_byte = get_byte_cache_040;
! 1321: } else {
! 1322: x_get_byte = mem_access_delay_byte_read_c040;
! 1323: x_get_word = mem_access_delay_word_read_c040;
! 1324: x_get_long = mem_access_delay_long_read_c040;
! 1325: x_put_byte = mem_access_delay_byte_write_c040;
! 1326: x_put_word = mem_access_delay_word_write_c040;
! 1327: x_put_long = mem_access_delay_long_write_c040;
! 1328: }
1.1.1.7 root 1329: #ifndef WINUAE_FOR_HATARI
1330: x_do_cycles = do_cycles_ce020;
1331: x_do_cycles_pre = do_cycles_ce020;
1332: x_do_cycles_post = do_cycles_ce020_post;
1333: #else
1334: x_do_cycles = do_cycles_ce020_long;
1335: x_do_cycles_pre = do_cycles_ce020_long;
1336: x_do_cycles_post = do_cycles_ce020_post;
1337: #endif
1338: }
1339: x2_prefetch = x_prefetch;
1340: x2_get_ilong = x_get_ilong;
1341: x2_get_iword = x_get_iword;
1342: x2_get_ibyte = x_get_ibyte;
1343: x2_next_iword = x_next_iword;
1344: x2_next_ilong = x_next_ilong;
1345: x2_put_long = x_put_long;
1346: x2_put_word = x_put_word;
1347: x2_put_byte = x_put_byte;
1348: x2_get_long = x_get_long;
1349: x2_get_word = x_get_word;
1350: x2_get_byte = x_get_byte;
1351: x2_do_cycles = x_do_cycles;
1352: x2_do_cycles_pre = x_do_cycles_pre;
1353: x2_do_cycles_post = x_do_cycles_post;
1354:
1355: if (cpu_tracer > 0) {
1356: x_prefetch = cputracefunc_x_prefetch;
1357: x_get_ilong = cputracefunc_x_get_ilong;
1358: x_get_iword = cputracefunc_x_get_iword;
1359: x_get_ibyte = cputracefunc_x_get_ibyte;
1360: x_next_iword = cputracefunc_x_next_iword;
1361: x_next_ilong = cputracefunc_x_next_ilong;
1362: x_put_long = cputracefunc_x_put_long;
1363: x_put_word = cputracefunc_x_put_word;
1364: x_put_byte = cputracefunc_x_put_byte;
1365: x_get_long = cputracefunc_x_get_long;
1366: x_get_word = cputracefunc_x_get_word;
1367: x_get_byte = cputracefunc_x_get_byte;
1368: x_do_cycles = cputracefunc_x_do_cycles;
1369: x_do_cycles_pre = cputracefunc_x_do_cycles_pre;
1370: x_do_cycles_post = cputracefunc_x_do_cycles_post;
1371: } else if (cpu_tracer < 0) {
1372: if (!check_trace ()) {
1373: x_prefetch = cputracefunc2_x_prefetch;
1374: x_get_ilong = cputracefunc2_x_get_ilong;
1375: x_get_iword = cputracefunc2_x_get_iword;
1376: x_get_ibyte = cputracefunc2_x_get_ibyte;
1377: x_next_iword = cputracefunc2_x_next_iword;
1378: x_next_ilong = cputracefunc2_x_next_ilong;
1379: x_put_long = cputracefunc2_x_put_long;
1380: x_put_word = cputracefunc2_x_put_word;
1381: x_put_byte = cputracefunc2_x_put_byte;
1382: x_get_long = cputracefunc2_x_get_long;
1383: x_get_word = cputracefunc2_x_get_word;
1384: x_get_byte = cputracefunc2_x_get_byte;
1385: x_do_cycles = cputracefunc2_x_do_cycles;
1386: x_do_cycles_pre = cputracefunc2_x_do_cycles_pre;
1387: x_do_cycles_post = cputracefunc2_x_do_cycles_post;
1388: }
1389: }
1390:
1391: set_x_cp_funcs();
1392: mmu_set_funcs();
1393: mmu030_set_funcs();
1394:
1.1.1.9 ! root 1395: dcache_lput = put_long;
! 1396: dcache_wput = put_word;
! 1397: dcache_bput = put_byte;
! 1398: dcache_lget = get_long;
! 1399: dcache_wget = get_word;
! 1400: dcache_bget = get_byte;
! 1401: dcache_check = dcache_check_nommu;
! 1402:
! 1403: icache_fetch = get_longi;
! 1404: if (currprefs.cpu_cycle_exact) {
! 1405: icache_fetch = mem_access_delay_longi_read_ce020;
! 1406: }
! 1407: if (currprefs.cpu_model >= 68040 && currprefs.cpu_memory_cycle_exact) {
! 1408: icache_fetch = mem_access_delay_longi_read_c040;
! 1409: dcache_bget = mem_access_delay_byte_read_c040;
! 1410: dcache_wget = mem_access_delay_word_read_c040;
! 1411: dcache_lget = mem_access_delay_long_read_c040;
! 1412: dcache_bput = mem_access_delay_byte_write_c040;
! 1413: dcache_wput = mem_access_delay_word_write_c040;
! 1414: dcache_lput = mem_access_delay_long_write_c040;
! 1415: }
! 1416:
! 1417: if (currprefs.cpu_model == 68030) {
! 1418:
! 1419: if (currprefs.cpu_data_cache) {
! 1420: read_data_030_bget = read_dcache030_mmu_bget;
! 1421: read_data_030_wget = read_dcache030_mmu_wget;
! 1422: read_data_030_lget = read_dcache030_mmu_lget;
! 1423: write_data_030_bput = write_dcache030_mmu_bput;
! 1424: write_data_030_wput = write_dcache030_mmu_wput;
! 1425: write_data_030_lput = write_dcache030_mmu_lput;
! 1426:
! 1427: read_data_030_fc_bget = read_dcache030_bget;
! 1428: read_data_030_fc_wget = read_dcache030_wget;
! 1429: read_data_030_fc_lget = read_dcache030_lget;
! 1430: write_data_030_fc_bput = write_dcache030_bput;
! 1431: write_data_030_fc_wput = write_dcache030_wput;
! 1432: write_data_030_fc_lput = write_dcache030_lput;
! 1433: } else {
! 1434: read_data_030_bget = dcache_bget;
! 1435: read_data_030_wget = dcache_wget;
! 1436: read_data_030_lget = dcache_lget;
! 1437: write_data_030_bput = dcache_bput;
! 1438: write_data_030_wput = dcache_wput;
! 1439: write_data_030_lput = dcache_lput;
! 1440:
! 1441: read_data_030_fc_bget = mmu030_get_fc_byte;
! 1442: read_data_030_fc_wget = mmu030_get_fc_word;
! 1443: read_data_030_fc_lget = mmu030_get_fc_long;
! 1444: write_data_030_fc_bput = mmu030_put_fc_byte;
! 1445: write_data_030_fc_wput = mmu030_put_fc_word;
! 1446: write_data_030_fc_lput = mmu030_put_fc_long;
! 1447: }
! 1448:
! 1449: if (currprefs.mmu_model) {
! 1450: if (currprefs.cpu_compatible) {
! 1451: icache_fetch = uae_mmu030_get_ilong_fc;
! 1452: } else {
! 1453: icache_fetch = uae_mmu030_get_ilong;
! 1454: }
! 1455: dcache_lput = uae_mmu030_put_long;
! 1456: dcache_wput = uae_mmu030_put_word;
! 1457: dcache_bput = uae_mmu030_put_byte;
! 1458: dcache_lget = uae_mmu030_get_long;
! 1459: dcache_wget = uae_mmu030_get_word;
! 1460: dcache_bget = uae_mmu030_get_byte;
! 1461: if (currprefs.cpu_data_cache) {
! 1462: read_data_030_bget = read_dcache030_mmu_bget;
! 1463: read_data_030_wget = read_dcache030_mmu_wget;
! 1464: read_data_030_lget = read_dcache030_mmu_lget;
! 1465: write_data_030_bput = write_dcache030_mmu_bput;
! 1466: write_data_030_wput = write_dcache030_mmu_wput;
! 1467: write_data_030_lput = write_dcache030_mmu_lput;
! 1468: dcache_lput = uae_mmu030_put_long_fc;
! 1469: dcache_wput = uae_mmu030_put_word_fc;
! 1470: dcache_bput = uae_mmu030_put_byte_fc;
! 1471: dcache_lget = uae_mmu030_get_long_fc;
! 1472: dcache_wget = uae_mmu030_get_word_fc;
! 1473: dcache_bget = uae_mmu030_get_byte_fc;
! 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: int i,j;
! 1553:
! 1554: if (currprefs.cpu_model == 68030) {
! 1555: for (i = 0; i < CACHELINES030; i++) {
! 1556: dcaches030[i].valid[0] = 0;
! 1557: dcaches030[i].valid[1] = 0;
! 1558: dcaches030[i].valid[2] = 0;
! 1559: dcaches030[i].valid[3] = 0;
! 1560: }
! 1561: } else if (currprefs.cpu_model >= 68040) {
! 1562: dcachelinecnt = 0;
! 1563: for (i = 0; i < CACHESETS060; i++) {
! 1564: for (j = 0; j < CACHELINES040; j++) {
! 1565: dcaches040[i].valid[j] = false;
! 1566: }
! 1567: }
! 1568: }
! 1569: }
! 1570:
1.1.1.7 root 1571: void flush_cpu_caches(bool force)
1.1.1.4 root 1572: {
1.1.1.8 root 1573: bool doflush = currprefs.cpu_compatible || currprefs.cpu_memory_cycle_exact;
1.1.1.9 ! root 1574: int i,j;
1.1.1.4 root 1575:
1576: if (currprefs.cpu_model == 68020) {
1.1.1.9 ! root 1577: if ((regs.cacr & 0x08) || force) { // clear instr cache
1.1.1.4 root 1578: for (i = 0; i < CACHELINES020; i++)
1579: caches020[i].valid = 0;
1.1.1.7 root 1580: regs.cacr &= ~0x08;
1.1.1.4 root 1581: }
1582: if (regs.cacr & 0x04) { // clear entry in instr cache
1.1.1.7 root 1583: caches020[(regs.caar >> 2) & (CACHELINES020 - 1)].valid = 0;
1.1.1.4 root 1584: regs.cacr &= ~0x04;
1585: }
1586: } else if (currprefs.cpu_model == 68030) {
1.1.1.9 ! root 1587: if ((regs.cacr & 0x08) || force) { // clear instr cache
1.1.1.7 root 1588: if (doflush) {
1589: for (i = 0; i < CACHELINES030; i++) {
1590: icaches030[i].valid[0] = 0;
1591: icaches030[i].valid[1] = 0;
1592: icaches030[i].valid[2] = 0;
1593: icaches030[i].valid[3] = 0;
1594: }
1.1.1.4 root 1595: }
1.1.1.7 root 1596: regs.cacr &= ~0x08;
1.1.1.4 root 1597: }
1598: if (regs.cacr & 0x04) { // clear entry in instr cache
1.1.1.7 root 1599: icaches030[(regs.caar >> 4) & (CACHELINES030 - 1)].valid[(regs.caar >> 2) & 3] = 0;
1.1.1.4 root 1600: regs.cacr &= ~0x04;
1601: }
1.1.1.9 ! root 1602: if ((regs.cacr & 0x800) || force) { // clear data cache
1.1.1.7 root 1603: if (doflush) {
1604: for (i = 0; i < CACHELINES030; i++) {
1605: dcaches030[i].valid[0] = 0;
1606: dcaches030[i].valid[1] = 0;
1607: dcaches030[i].valid[2] = 0;
1608: dcaches030[i].valid[3] = 0;
1609: }
1.1.1.4 root 1610: }
1611: regs.cacr &= ~0x800;
1612: }
1613: if (regs.cacr & 0x400) { // clear entry in data cache
1.1.1.7 root 1614: dcaches030[(regs.caar >> 4) & (CACHELINES030 - 1)].valid[(regs.caar >> 2) & 3] = 0;
1.1.1.4 root 1615: regs.cacr &= ~0x400;
1616: }
1.1.1.7 root 1617: } else if (currprefs.cpu_model >= 68040) {
1.1.1.9 ! root 1618: if (doflush && force) {
! 1619: mmu_flush_cache();
! 1620: icachelinecnt = 0;
! 1621: icachehalfline = 0;
! 1622: for (i = 0; i < CACHESETS060; i++) {
! 1623: for (j = 0; j < CACHELINES040; j++) {
! 1624: icaches040[i].valid[j] = false;
! 1625: }
! 1626: }
! 1627: }
! 1628: }
! 1629: }
! 1630:
! 1631: #if VALIDATE_68040_DATACACHE > 1
! 1632: static void validate_dcache040(void)
! 1633: {
! 1634: int i,j,k;
! 1635:
! 1636: for (i = 0; i < cachedsets04060; i++) {
! 1637: struct cache040 *c = &dcaches040[i];
! 1638: for (j = 0; j < CACHELINES040; j++) {
! 1639: if (c->valid[j]) {
! 1640: uae_u32 addr = (c->tag[j] & cachedtag04060mask) | (i << 4);
! 1641: if (addr < 0x200000 || (addr >= 0xd80000 && addr < 0xe00000) || (addr >= 0xe80000 && addr < 0xf00000) || (addr >= 0xa00000 && addr < 0xc00000)) {
! 1642: write_log(_T("Chip RAM or IO address cached! %08x\n"), addr);
! 1643: }
! 1644: for (k = 0; k < 4; k++) {
! 1645: if (!c->dirty[j][k]) {
! 1646: uae_u32 v = get_long(addr + k * 4);
! 1647: if (v != c->data[j][k]) {
! 1648: write_log(_T("Address %08x data cache mismatch %08x != %08x\n"), addr, v, c->data[j][k]);
! 1649: }
! 1650: }
! 1651: }
! 1652: }
! 1653: }
! 1654: }
! 1655: }
! 1656: #endif
! 1657:
! 1658: static void dcache040_push_line(int index, int line, bool writethrough, bool invalidate)
! 1659: {
! 1660: struct cache040 *c = &dcaches040[index];
! 1661: int i;
! 1662:
! 1663: #if VALIDATE_68040_DATACACHE
! 1664: if (!c->valid[line]) {
! 1665: write_log("dcache040_push_line pushing invalid line!\n");
! 1666: }
! 1667: #endif
! 1668: if (c->gdirty[line]) {
! 1669: uae_u32 addr = (c->tag[line] & cachedtag04060mask) | (index << 4);
! 1670: for (i = 0; i < 4; i++) {
! 1671: if (c->dirty[line][i] || (!writethrough && currprefs.cpu_model == 68060)) {
! 1672: dcache_lput(addr + i * 4, c->data[line][i]);
! 1673: c->dirty[line][i] = false;
1.1.1.4 root 1674: }
1675: }
1.1.1.9 ! root 1676: c->gdirty[line] = false;
1.1.1.4 root 1677: }
1.1.1.9 ! root 1678: if (invalidate)
! 1679: c->valid[line] = false;
! 1680:
! 1681: #if VALIDATE_68040_DATACACHE > 1
! 1682: validate_dcache040();
! 1683: #endif
1.1.1.4 root 1684: }
1685:
1.1.1.7 root 1686: void flush_cpu_caches_040(uae_u16 opcode)
1.1.1.4 root 1687: {
1.1.1.9 ! root 1688: // 0 (1) = data, 1 (2) = instruction
1.1.1.7 root 1689: int cache = (opcode >> 6) & 3;
1.1.1.9 ! root 1690: int scope = (opcode >> 3) & 3;
! 1691: int areg = opcode & 7;
! 1692: uaecptr addr = m68k_areg(regs, areg);
! 1693: bool push = (opcode & 0x20) != 0;
! 1694: bool pushinv = (regs.cacr & 0x01000000) == 0; // 68060 DPI
! 1695: int i;
! 1696: uae_u32 k, j;
! 1697:
! 1698: #if VALIDATE_68040_DATACACHE
! 1699: write_log(_T("push %d %d %d %08x %d %d\n"), cache, scope, areg, addr, push, pushinv);
! 1700: #endif
! 1701:
! 1702: if (cache & 2)
! 1703: regs.prefetch020addr = 0xffffffff;
! 1704: for (k = 0; k < 2; k++) {
! 1705: if (cache & (1 << k)) {
! 1706: if (scope == 3) {
! 1707: // all
! 1708: if (!k) {
! 1709: // data
! 1710: for (i = 0; i < cachedsets04060; i++) {
! 1711: struct cache040 *c = &dcaches040[i];
! 1712: for (j = 0; j < CACHELINES040; j++) {
! 1713: if (c->valid[j]) {
! 1714: if (push) {
! 1715: dcache040_push_line(i, j, false, pushinv);
! 1716: } else {
! 1717: c->valid[j] = false;
! 1718: }
! 1719: }
! 1720: }
! 1721: }
! 1722: dcachelinecnt = 0;
! 1723: } else {
! 1724: // instruction
! 1725: flush_cpu_caches(true);
! 1726: }
! 1727: } else {
! 1728: uae_u32 pagesize;
! 1729: if (scope == 2) {
! 1730: // page
! 1731: pagesize = mmu_pagesize_8k ? 8192 : 4096;
! 1732: } else {
! 1733: // line
! 1734: pagesize = 16;
! 1735: }
! 1736: addr &= ~(pagesize - 1);
! 1737: for (j = 0; j < pagesize; j += 16, addr += 16) {
! 1738: int index;
! 1739: uae_u32 tag;
! 1740: uae_u32 tagmask;
! 1741: struct cache040 *c;
! 1742: if (k) {
! 1743: tagmask = cacheitag04060mask;
! 1744: index = (addr >> 4) & cacheisets04060mask;
! 1745: c = &icaches040[index];
! 1746: } else {
! 1747: tagmask = cachedtag04060mask;
! 1748: index = (addr >> 4) & cachedsets04060mask;
! 1749: c = &dcaches040[index];
! 1750: }
! 1751: tag = addr & tagmask;
! 1752: for (i = 0; i < CACHELINES040; i++) {
! 1753: if (c->valid[i] && c->tag[i] == tag) {
! 1754: if (push) {
! 1755: dcache040_push_line(index, i, false, pushinv);
! 1756: } else {
! 1757: c->valid[i] = false;
! 1758: }
! 1759: }
! 1760: }
! 1761: }
! 1762: }
! 1763: }
! 1764: }
! 1765: mmu_flush_cache();
1.1.1.4 root 1766: }
1767:
1.1.1.7 root 1768: void set_cpu_caches (bool flush)
1.1.1.4 root 1769: {
1.1.1.7 root 1770: regs.prefetch020addr = 0xffffffff;
1771: regs.cacheholdingaddr020 = 0xffffffff;
1.1.1.9 ! root 1772: cache_default_data &= ~CACHE_DISABLE_ALLOCATE;
! 1773:
! 1774: // 68060 FIC 1/2 instruction cache
! 1775: cacheisets04060 = currprefs.cpu_model == 68060 && !(regs.cacr & 0x00002000) ? CACHESETS060 : CACHESETS040;
! 1776: cacheisets04060mask = cacheisets04060 - 1;
! 1777: cacheitag04060mask = ~((cacheisets04060 << 4) - 1);
! 1778: // 68060 FOC 1/2 data cache
! 1779: cachedsets04060 = currprefs.cpu_model == 68060 && !(regs.cacr & 0x08000000) ? CACHESETS060 : CACHESETS040;
! 1780: cachedsets04060mask = cachedsets04060 - 1;
! 1781: cachedtag04060mask = ~((cachedsets04060 << 4) - 1);
! 1782: cache_lastline = 0;
1.1.1.4 root 1783:
1.1.1.7 root 1784: #ifdef JIT
1785: if (currprefs.cachesize) {
1786: if (currprefs.cpu_model < 68040) {
1787: set_cache_state (regs.cacr & 1);
1788: if (regs.cacr & 0x08) {
1.1.1.9 ! root 1789: flush_icache (3);
1.1.1.7 root 1790: }
1791: } else {
1792: set_cache_state ((regs.cacr & 0x8000) ? 1 : 0);
1793: }
1794: }
1795: #endif
1796: flush_cpu_caches(flush);
1797: }
1798:
1799: STATIC_INLINE void count_instr (unsigned int opcode)
1800: {
1801: }
1802:
1803: static uae_u32 REGPARAM2 op_illg_1 (uae_u32 opcode)
1804: {
1805: op_illg (opcode);
1806: return 4;
1807: }
1808: static uae_u32 REGPARAM2 op_unimpl_1 (uae_u32 opcode)
1809: {
1810: if ((opcode & 0xf000) == 0xf000 || currprefs.cpu_model < 68060)
1811: op_illg (opcode);
1812: else
1813: op_unimpl (opcode);
1814: return 4;
1815: }
1816:
1.1.1.9 ! root 1817: // generic+direct, generic+direct+jit, generic+indirect, more compatible, cycle-exact, mmu, mmu+more compatible, mmu+mc+ce
! 1818: static const struct cputbl *cputbls[6][8] =
1.1.1.7 root 1819: {
1820: // 68000
1.1.1.9 ! root 1821: { 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 1822: // 68010
1.1.1.9 ! root 1823: { 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 1824: // 68020
1.1.1.9 ! root 1825: { 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 1826: // 68030
1.1.1.9 ! root 1827: { 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 1828: // 68040
1.1.1.9 ! root 1829: { 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 1830: // 68060
1.1.1.9 ! root 1831: { 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 1832: };
1833:
1834: static void build_cpufunctbl (void)
1.1.1.4 root 1835: {
1836: int i, opcnt;
1837: unsigned long opcode;
1838: const struct cputbl *tbl = 0;
1.1.1.7 root 1839: int lvl, mode;
1.1.1.4 root 1840:
1.1.1.7 root 1841: if (!currprefs.cachesize) {
1.1.1.9 ! root 1842: if (currprefs.mmu_model) {
! 1843: if (currprefs.cpu_cycle_exact)
! 1844: mode = 7;
! 1845: else if (currprefs.cpu_compatible)
! 1846: mode = 6;
! 1847: else
! 1848: mode = 5;
! 1849: } else if (currprefs.cpu_cycle_exact) {
1.1.1.8 root 1850: mode = 4;
1.1.1.9 ! root 1851: } else if (currprefs.cpu_compatible) {
1.1.1.8 root 1852: mode = 3;
1.1.1.9 ! root 1853: } else {
1.1.1.7 root 1854: mode = 0;
1.1.1.9 ! root 1855: }
1.1.1.7 root 1856: m68k_pc_indirect = mode != 0 ? 1 : 0;
1857: } else {
1.1.1.8 root 1858: mode = 1;
1.1.1.7 root 1859: m68k_pc_indirect = 0;
1860: if (currprefs.comptrustbyte) {
1.1.1.8 root 1861: mode = 2;
1.1.1.7 root 1862: m68k_pc_indirect = -1;
1863: }
1.1.1.4 root 1864: }
1.1.1.7 root 1865: lvl = (currprefs.cpu_model - 68000) / 10;
1866: if (lvl == 6)
1867: lvl = 5;
1.1.1.9 ! root 1868: fprintf ( stderr , "cpu table lvl=%d , mode=%d\n" , lvl , mode );
1.1.1.7 root 1869: tbl = cputbls[lvl][mode];
1.1.1.4 root 1870:
1.1.1.7 root 1871: if (tbl == NULL) {
1872: write_log (_T("no CPU emulation cores available CPU=%d!"), currprefs.cpu_model);
1.1.1.4 root 1873: abort ();
1874: }
1875:
1876: for (opcode = 0; opcode < 65536; opcode++)
1877: cpufunctbl[opcode] = op_illg_1;
1878: for (i = 0; tbl[i].handler != NULL; i++) {
1879: opcode = tbl[i].opcode;
1880: cpufunctbl[opcode] = tbl[i].handler;
1.1.1.7 root 1881: cpudatatbl[opcode].length = tbl[i].length;
1882: cpudatatbl[opcode].disp020[0] = tbl[i].disp020[0];
1883: cpudatatbl[opcode].disp020[1] = tbl[i].disp020[1];
1884: cpudatatbl[opcode].branch = tbl[i].branch;
1.1.1.4 root 1885: }
1886:
1887: /* hack fpu to 68000/68010 mode */
1888: if (currprefs.fpu_model && currprefs.cpu_model < 68020) {
1889: tbl = op_smalltbl_3_ff;
1890: for (i = 0; tbl[i].handler != NULL; i++) {
1.1.1.7 root 1891: if ((tbl[i].opcode & 0xfe00) == 0xf200) {
1.1.1.4 root 1892: cpufunctbl[tbl[i].opcode] = tbl[i].handler;
1.1.1.7 root 1893: cpudatatbl[tbl[i].opcode].length = tbl[i].length;
1894: cpudatatbl[tbl[i].opcode].disp020[0] = tbl[i].disp020[0];
1895: cpudatatbl[tbl[i].opcode].disp020[1] = tbl[i].disp020[1];
1896: cpudatatbl[tbl[i].opcode].branch = tbl[i].branch;
1897: }
1.1.1.4 root 1898: }
1899: }
1.1.1.7 root 1900:
1.1.1.4 root 1901: opcnt = 0;
1902: for (opcode = 0; opcode < 65536; opcode++) {
1903: cpuop_func *f;
1.1.1.7 root 1904: struct instr *table = &table68k[opcode];
1905:
1906: if (table->mnemo == i_ILLG)
1907: continue;
1908:
1909: /* unimplemented opcode? */
1910: if (table->unimpclev > 0 && lvl >= table->unimpclev) {
1.1.1.8 root 1911: if (currprefs.cpu_model == 68060) {
1912: // remove unimplemented integer instructions
1913: // unimpclev == 5: not implemented in 68060,
1914: // generates unimplemented instruction exception.
1915: if (currprefs.int_no_unimplemented && table->unimpclev == 5) {
1916: cpufunctbl[opcode] = op_unimpl_1;
1917: continue;
1918: }
1919: // remove unimplemented instruction that were removed in previous models,
1920: // generates normal illegal instruction exception.
1921: // unimplclev < 5: instruction was removed in 68040 or previous model.
1922: // clev=4: implemented in 68040 or later. unimpclev=5: not in 68060
1923: if (table->unimpclev < 5 || (table->clev == 4 && table->unimpclev == 5)) {
1.1.1.7 root 1924: cpufunctbl[opcode] = op_illg_1;
1925: continue;
1926: }
1.1.1.8 root 1927: } else {
1928: cpufunctbl[opcode] = op_illg_1;
1929: continue;
1.1.1.7 root 1930: }
1931: }
1.1.1.4 root 1932:
1933: if (currprefs.fpu_model && currprefs.cpu_model < 68020) {
1934: /* more hack fpu to 68000/68010 mode */
1.1.1.7 root 1935: if (table->clev > lvl && (opcode & 0xfe00) != 0xf200)
1.1.1.4 root 1936: continue;
1.1.1.7 root 1937: } else if (table->clev > lvl) {
1.1.1.4 root 1938: continue;
1939: }
1940:
1.1.1.7 root 1941: if (table->handler != -1) {
1942: int idx = table->handler;
1.1.1.4 root 1943: f = cpufunctbl[idx];
1944: if (f == op_illg_1)
1945: abort ();
1946: cpufunctbl[opcode] = f;
1.1.1.7 root 1947: memcpy(&cpudatatbl[opcode], &cpudatatbl[idx], sizeof(struct cputbl_data));
1.1.1.4 root 1948: opcnt++;
1949: }
1950: }
1.1.1.7 root 1951: write_log (_T("Building CPU, %d opcodes (%d %d %d)\n"),
1.1.1.4 root 1952: opcnt, lvl,
1.1.1.8 root 1953: 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 1954: #ifdef JIT
1.1.1.8 root 1955: write_log(_T("JIT: &countdown = %p\n"), &countdown);
1956: write_log(_T("JIT: &build_comp = %p\n"), &build_comp);
1.1.1.4 root 1957: build_comp ();
1958: #endif
1.1.1.7 root 1959:
1.1.1.9 ! root 1960: write_log(_T("CPU=%d, FPU=%d%s, MMU=%d, JIT%s=%d."),
! 1961: currprefs.cpu_model,
! 1962: currprefs.fpu_model, currprefs.fpu_model ? (currprefs.fpu_softfloat ? _T(" (softfloat)") : _T(" (host)")) : _T(""),
! 1963: currprefs.mmu_model,
! 1964: currprefs.cachesize ? (currprefs.compfpu ? _T("=CPU/FPU") : _T("=CPU")) : _T(""),
! 1965: currprefs.cachesize);
1.1.1.7 root 1966:
1967: regs.address_space_mask = 0xffffffff;
1968: #ifndef WINUAE_FOR_HATARI
1969: if (currprefs.cpu_compatible) {
1970: if (currprefs.address_space_24 && currprefs.cpu_model >= 68040)
1971: currprefs.address_space_24 = false;
1972: }
1973: #else
1974: /* Hatari : don't force address_space_24=0 for 68030, as the Falcon has a 68030 LC with only 24 bits */
1975: /* TODO ? Force address_space_24=0 for 68040 ? */
1976: #endif
1977: m68k_interrupt_delay = false;
1978: if (currprefs.cpu_cycle_exact) {
1979: if (tbl == op_smalltbl_14_ff || tbl == op_smalltbl_13_ff || tbl == op_smalltbl_21_ff || tbl == op_smalltbl_23_ff)
1980: m68k_interrupt_delay = true;
1981: }
1982:
1983: if (currprefs.cpu_cycle_exact) {
1984: if (currprefs.cpu_model == 68000)
1985: write_log(_T(" prefetch and cycle-exact"));
1986: else
1987: write_log(_T(" ~cycle-exact"));
1.1.1.8 root 1988: } else if (currprefs.cpu_memory_cycle_exact) {
1989: write_log(_T(" ~memory-cycle-exact"));
1.1.1.7 root 1990: } else if (currprefs.cpu_compatible) {
1991: if (currprefs.cpu_model <= 68020) {
1992: write_log(_T(" prefetch"));
1993: } else {
1994: write_log(_T(" fake prefetch"));
1.1.1.5 root 1995: }
1.1.1.4 root 1996: }
1.1.1.7 root 1997: if (currprefs.m68k_speed < 0)
1998: write_log(_T(" fast"));
1999: if (currprefs.int_no_unimplemented && currprefs.cpu_model == 68060) {
2000: write_log(_T(" no unimplemented integer instructions"));
2001: }
2002: if (currprefs.fpu_no_unimplemented && currprefs.fpu_model) {
2003: write_log(_T(" no unimplemented floating point instructions"));
2004: }
2005: if (currprefs.address_space_24) {
2006: regs.address_space_mask = 0x00ffffff;
2007: write_log(_T(" 24-bit"));
2008: }
2009: write_log(_T("\n"));
1.1.1.4 root 2010:
1.1.1.7 root 2011: set_cpu_caches (true);
1.1.1.4 root 2012: }
2013:
1.1.1.7 root 2014: #define CYCLES_DIV 8192
2015: static unsigned long cycles_mult;
1.1.1.4 root 2016:
2017: static void update_68k_cycles (void)
2018: {
1.1.1.7 root 2019: cycles_mult = 0;
1.1.1.9 ! root 2020: #ifdef WINUAE_FOR_HATARI
! 2021: 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);
! 2022: #else /* Don't adjust cycles_mult in Hatari and ignore m68k_speed (forced to 0) */
1.1.1.7 root 2023: if (currprefs.m68k_speed >= 0 && !currprefs.cpu_cycle_exact) {
2024: if (currprefs.m68k_speed_throttle < 0) {
2025: cycles_mult = (unsigned long)(CYCLES_DIV * 1000 / (1000 + currprefs.m68k_speed_throttle));
2026: } else if (currprefs.m68k_speed_throttle > 0) {
2027: cycles_mult = (unsigned long)(CYCLES_DIV * 1000 / (1000 + currprefs.m68k_speed_throttle));
2028: }
2029: }
2030: if (currprefs.m68k_speed == 0) {
2031: if (currprefs.cpu_model >= 68040) {
2032: if (!cycles_mult)
2033: cycles_mult = CYCLES_DIV / 8;
2034: else
2035: cycles_mult /= 8;
2036: } else if (currprefs.cpu_model >= 68020) {
2037: if (!cycles_mult)
2038: cycles_mult = CYCLES_DIV / 4;
2039: else
2040: cycles_mult /= 4;
2041: }
1.1.1.4 root 2042: }
1.1.1.7 root 2043: #endif
2044:
1.1.1.4 root 2045: currprefs.cpu_clock_multiplier = changed_prefs.cpu_clock_multiplier;
2046: currprefs.cpu_frequency = changed_prefs.cpu_frequency;
2047:
1.1.1.7 root 2048: #ifndef WINUAE_FOR_HATARI
2049: baseclock = (currprefs.ntscmode ? CHIPSET_CLOCK_NTSC : CHIPSET_CLOCK_PAL) * 8;
2050: #endif
1.1.1.4 root 2051: cpucycleunit = CYCLE_UNIT / 2;
2052: if (currprefs.cpu_clock_multiplier) {
2053: if (currprefs.cpu_clock_multiplier >= 256) {
2054: cpucycleunit = CYCLE_UNIT / (currprefs.cpu_clock_multiplier >> 8);
2055: } else {
2056: cpucycleunit = CYCLE_UNIT * currprefs.cpu_clock_multiplier;
2057: }
1.1.1.7 root 2058: if (currprefs.cpu_model >= 68040)
2059: cpucycleunit /= 2;
2060: #ifndef WINUAE_FOR_HATARI /* [NP] TODO : handle any cpu frequency, not just mulltiplier ? */
1.1.1.4 root 2061: } else if (currprefs.cpu_frequency) {
2062: cpucycleunit = CYCLE_UNIT * baseclock / currprefs.cpu_frequency;
1.1.1.7 root 2063: #endif
2064: } else if (currprefs.cpu_cycle_exact && currprefs.cpu_clock_multiplier == 0) {
2065: if (currprefs.cpu_model >= 68040) {
2066: cpucycleunit = CYCLE_UNIT / 16;
2067: } if (currprefs.cpu_model == 68030) {
2068: cpucycleunit = CYCLE_UNIT / 8;
2069: } else if (currprefs.cpu_model == 68020) {
2070: cpucycleunit = CYCLE_UNIT / 4;
2071: } else {
2072: cpucycleunit = CYCLE_UNIT / 2;
2073: }
1.1.1.4 root 2074: }
2075: if (cpucycleunit < 1)
2076: cpucycleunit = 1;
2077: if (currprefs.cpu_cycle_exact)
1.1.1.7 root 2078: write_log (_T("CPU cycleunit: %d (%.3f)\n"), cpucycleunit, (float)cpucycleunit / CYCLE_UNIT);
2079: write_log (_T("CPU cycleunit: %d (%.3f)\n"), cpucycleunit, (float)cpucycleunit / CYCLE_UNIT);
2080: #ifndef WINUAE_FOR_HATARI
2081: set_config_changed ();
2082: #endif
1.1.1.4 root 2083: }
2084:
2085: static void prefs_changed_cpu (void)
2086: {
2087: fixup_cpu (&changed_prefs);
1.1.1.8 root 2088: check_prefs_changed_comp(false);
1.1.1.4 root 2089: currprefs.cpu_model = changed_prefs.cpu_model;
2090: currprefs.fpu_model = changed_prefs.fpu_model;
1.1.1.9 ! root 2091: if (currprefs.mmu_model != changed_prefs.mmu_model) {
! 2092: int oldmmu = currprefs.mmu_model;
! 2093: currprefs.mmu_model = changed_prefs.mmu_model;
! 2094: if (currprefs.mmu_model >= 68040) {
! 2095: uae_u32 tcr = regs.tcr;
! 2096: mmu_reset();
! 2097: mmu_set_tc(tcr);
! 2098: mmu_set_super(regs.s != 0);
! 2099: mmu_tt_modified();
! 2100: } else if (currprefs.mmu_model == 68030) {
! 2101: mmu030_reset(-1);
! 2102: mmu030_flush_atc_all();
! 2103: tc_030 = fake_tc_030;
! 2104: tt0_030 = fake_tt0_030;
! 2105: tt1_030 = fake_tt1_030;
! 2106: srp_030 = fake_srp_030;
! 2107: crp_030 = fake_crp_030;
! 2108: mmu030_decode_tc(tc_030, false);
! 2109: } else if (oldmmu == 68030) {
! 2110: fake_tc_030 = tc_030;
! 2111: fake_tt0_030 = tt0_030;
! 2112: fake_tt1_030 = tt1_030;
! 2113: fake_srp_030 = srp_030;
! 2114: fake_crp_030 = crp_030;
! 2115: }
! 2116: }
! 2117: currprefs.mmu_ec = changed_prefs.mmu_ec;
! 2118: if (currprefs.cpu_compatible != changed_prefs.cpu_compatible) {
! 2119: currprefs.cpu_compatible = changed_prefs.cpu_compatible;
! 2120: flush_cpu_caches(true);
! 2121: invalidate_cpu_data_caches();
! 2122: }
! 2123: if (currprefs.cpu_data_cache != changed_prefs.cpu_data_cache) {
! 2124: currprefs.cpu_data_cache = changed_prefs.cpu_data_cache;
! 2125: invalidate_cpu_data_caches();
! 2126: }
1.1.1.8 root 2127: currprefs.address_space_24 = changed_prefs.address_space_24;
1.1.1.4 root 2128: currprefs.cpu_cycle_exact = changed_prefs.cpu_cycle_exact;
1.1.1.8 root 2129: currprefs.cpu_memory_cycle_exact = changed_prefs.cpu_memory_cycle_exact;
1.1.1.7 root 2130: currprefs.int_no_unimplemented = changed_prefs.int_no_unimplemented;
2131: currprefs.fpu_no_unimplemented = changed_prefs.fpu_no_unimplemented;
1.1.1.9 ! root 2132: currprefs.fpu_softfloat = changed_prefs.fpu_softfloat;
1.1.1.7 root 2133: currprefs.blitter_cycle_exact = changed_prefs.blitter_cycle_exact;
1.1.1.4 root 2134: }
2135:
1.1.1.7 root 2136: static int check_prefs_changed_cpu2(void)
1.1.1.4 root 2137: {
1.1.1.7 root 2138: int changed = 0;
1.1.1.4 root 2139:
2140: #ifdef JIT
1.1.1.8 root 2141: changed = check_prefs_changed_comp(true) ? 1 : 0;
1.1.1.4 root 2142: #endif
2143: if (changed
2144: || currprefs.cpu_model != changed_prefs.cpu_model
2145: || currprefs.fpu_model != changed_prefs.fpu_model
2146: || currprefs.mmu_model != changed_prefs.mmu_model
1.1.1.9 ! root 2147: || currprefs.mmu_ec != changed_prefs.mmu_ec
! 2148: || currprefs.cpu_data_cache != changed_prefs.cpu_data_cache
1.1.1.8 root 2149: || currprefs.address_space_24 != changed_prefs.address_space_24 /* WINUAE_FOR_HATARI */
1.1.1.7 root 2150: || currprefs.int_no_unimplemented != changed_prefs.int_no_unimplemented
2151: || currprefs.fpu_no_unimplemented != changed_prefs.fpu_no_unimplemented
1.1.1.4 root 2152: || currprefs.cpu_compatible != changed_prefs.cpu_compatible
1.1.1.8 root 2153: || currprefs.cpu_cycle_exact != changed_prefs.cpu_cycle_exact
1.1.1.9 ! root 2154: || currprefs.cpu_memory_cycle_exact != changed_prefs.cpu_memory_cycle_exact
! 2155: || currprefs.fpu_softfloat != changed_prefs.fpu_softfloat) {
1.1.1.7 root 2156: cpu_prefs_changed_flag |= 1;
2157: #ifdef WINUAE_FOR_HATARI
2158: /* When changing CPU prefs in Hatari we reset the emulation, */
2159: /* so new cpu table should be built now, not in m68k_go() */
2160: // uaecptr pc = m68k_getpc();
2161: prefs_changed_cpu();
2162: build_cpufunctbl();
1.1.1.9 ! root 2163: set_x_funcs(); // [NP] TODO : really handle cpu change in m68k_go(), not during cpu instruction, too risky to keep a consistent state !!
1.1.1.7 root 2164: // done in m68k_go :
2165: // m68k_setpc_normal(pc);
2166: // fill_prefetch();
2167: #endif
1.1.1.4 root 2168: }
2169: if (changed
2170: || currprefs.m68k_speed != changed_prefs.m68k_speed
1.1.1.7 root 2171: || currprefs.m68k_speed_throttle != changed_prefs.m68k_speed_throttle
1.1.1.4 root 2172: || currprefs.cpu_clock_multiplier != changed_prefs.cpu_clock_multiplier
1.1.1.7 root 2173: || currprefs.reset_delay != changed_prefs.reset_delay
1.1.1.4 root 2174: || currprefs.cpu_frequency != changed_prefs.cpu_frequency) {
1.1.1.7 root 2175: cpu_prefs_changed_flag |= 2;
1.1.1.4 root 2176: }
1.1.1.7 root 2177: return cpu_prefs_changed_flag;
2178: }
1.1.1.4 root 2179:
1.1.1.7 root 2180: void check_prefs_changed_cpu(void)
2181: {
1.1.1.8 root 2182: #ifndef WINUAE_FOR_HATARI /* [NP] TODO : handle cpu change on the fly ? */
1.1.1.7 root 2183: if (!config_changed)
2184: return;
1.1.1.8 root 2185: #endif
1.1.1.4 root 2186:
1.1.1.7 root 2187: currprefs.cpu_idle = changed_prefs.cpu_idle;
2188: currprefs.ppc_cpu_idle = changed_prefs.ppc_cpu_idle;
2189: currprefs.reset_delay = changed_prefs.reset_delay;
2190:
2191: if (check_prefs_changed_cpu2()) {
2192: set_special(SPCFLAG_MODE_CHANGE);
2193: reset_frame_rate_hack();
2194: }
1.1.1.4 root 2195: }
2196:
2197: void init_m68k (void)
2198: {
2199: int i;
2200:
2201: prefs_changed_cpu ();
2202: update_68k_cycles ();
2203:
2204: for (i = 0 ; i < 256 ; i++) {
2205: int j;
2206: for (j = 0 ; j < 8 ; j++) {
2207: if (i & (1 << j)) break;
2208: }
2209: movem_index1[i] = j;
1.1.1.7 root 2210: movem_index2[i] = 7 - j;
1.1.1.4 root 2211: movem_next[i] = i & (~(1 << j));
2212: }
2213:
2214: #if COUNT_INSTRS
2215: {
2216: FILE *f = fopen (icountfilename (), "r");
2217: memset (instrcount, 0, sizeof instrcount);
2218: if (f) {
2219: uae_u32 opcode, count, total;
2220: TCHAR name[20];
1.1.1.7 root 2221: write_log (_T("Reading instruction count file...\n"));
1.1.1.4 root 2222: fscanf (f, "Total: %lu\n", &total);
1.1.1.7 root 2223: while (fscanf (f, "%x: %lu %s\n", &opcode, &count, name) == 3) {
1.1.1.4 root 2224: instrcount[opcode] = count;
2225: }
2226: fclose (f);
2227: }
2228: }
2229: #endif
2230:
2231: read_table68k ();
2232: do_merges ();
2233:
1.1.1.7 root 2234: write_log (_T("%d CPU functions\n"), nr_cpuop_funcs);
1.1.1.4 root 2235:
1.1.1.9 ! root 2236: #ifdef WINUAE_FOR_HATARI
! 2237: /* Hatari : TODO remove these 2 lines as in winuae 3.4.0 */
! 2238: /* and do it only in m68k_go by setting uae_quit_program=UAE_RESET */
1.1.1.4 root 2239: build_cpufunctbl ();
2240: set_x_funcs ();
2241: #endif
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:
! 2283: for (lookup = lookuptab; lookup->mnemo != table->mnemo; lookup++)
! 2284: ;
! 2285: if (!(lookup->flags & 1))
! 2286: return;
! 2287: buffer += _tcslen(buffer);
! 2288: if (debug_safe_addr(addr, datasizes[size])) {
! 2289: bool cached = false;
! 2290: switch (size)
! 2291: {
! 2292: case sz_byte:
! 2293: {
! 2294: uae_u8 v = get_byte_cache_debug(addr, &cached);
! 2295: uae_u8 v2 = v;
! 2296: if (cached)
! 2297: v2 = get_byte_debug(addr);
! 2298: if (v != v2) {
! 2299: _stprintf(buffer, _T(" [%02x:%02x]"), v, v2);
! 2300: } else {
! 2301: _stprintf(buffer, _T(" [%s%02x]"), cached ? _T("*") : _T(""), v);
! 2302: }
! 2303: }
! 2304: break;
! 2305: case sz_word:
! 2306: {
! 2307: uae_u16 v = get_word_cache_debug(addr, &cached);
! 2308: uae_u16 v2 = v;
! 2309: if (cached)
! 2310: v2 = get_word_debug(addr);
! 2311: if (v != v2) {
! 2312: _stprintf(buffer, _T(" [%04x:%04x]"), v, v2);
! 2313: } else {
! 2314: _stprintf(buffer, _T(" [%s%04x]"), cached ? _T("*") : _T(""), v);
! 2315: }
! 2316: }
! 2317: break;
! 2318: case sz_long:
! 2319: {
! 2320: uae_u32 v = get_long_cache_debug(addr, &cached);
! 2321: uae_u32 v2 = v;
! 2322: if (cached)
! 2323: v2 = get_long_debug(addr);
! 2324: if (v != v2) {
! 2325: _stprintf(buffer, _T(" [%08x:%08x]"), v, v2);
! 2326: } else {
! 2327: _stprintf(buffer, _T(" [%s%08x]"), cached ? _T("*") : _T(""), v);
! 2328: }
! 2329: }
! 2330: break;
! 2331: case sz_single:
! 2332: {
! 2333: fpdata fp;
! 2334: fpp_to_single(&fp, get_long_debug(addr));
! 2335: _stprintf(buffer, _T("[%s]"), fpp_print(&fp, 0));
! 2336: }
! 2337: break;
! 2338: case sz_double:
! 2339: {
! 2340: fpdata fp;
! 2341: fpp_to_double(&fp, get_long_debug(addr), get_long_debug(addr + 4));
! 2342: _stprintf(buffer, _T("[%s]"), fpp_print(&fp, 0));
! 2343: }
! 2344: break;
! 2345: case sz_extended:
! 2346: {
! 2347: fpdata fp;
! 2348: fpp_to_exten(&fp, get_long_debug(addr), get_long_debug(addr + 4), get_long_debug(addr + 8));
! 2349: _stprintf(buffer, _T("[%s]"), fpp_print(&fp, 0));
! 2350: break;
! 2351: }
! 2352: case sz_packed:
! 2353: _stprintf(buffer, _T("[%08x%08x%08x]"), get_long_debug(addr), get_long_debug(addr + 4), get_long_debug(addr + 8));
! 2354: break;
! 2355: }
! 2356: }
! 2357: }
1.1.1.4 root 2358:
1.1.1.7 root 2359: static uaecptr ShowEA (void *f, uaecptr pc, uae_u16 opcode, int reg, amodes mode, wordsizes size, TCHAR *buf, uae_u32 *eaddr, int safemode)
1.1.1.4 root 2360: {
2361: uae_u16 dp;
2362: uae_s8 disp8;
2363: uae_s16 disp16;
2364: int r;
2365: uae_u32 dispreg;
1.1.1.7 root 2366: uaecptr addr = pc;
1.1.1.4 root 2367: uae_s32 offset = 0;
2368: TCHAR buffer[80];
2369:
2370: switch (mode){
2371: case Dreg:
1.1.1.7 root 2372: _stprintf (buffer, _T("D%d"), reg);
1.1.1.4 root 2373: break;
2374: case Areg:
1.1.1.7 root 2375: _stprintf (buffer, _T("A%d"), reg);
1.1.1.4 root 2376: break;
2377: case Aind:
1.1.1.7 root 2378: _stprintf (buffer, _T("(A%d)"), reg);
1.1.1.4 root 2379: addr = regs.regs[reg + 8];
1.1.1.9 ! root 2380: showea_val(buffer, opcode, addr, size);
1.1.1.4 root 2381: break;
2382: case Aipi:
1.1.1.7 root 2383: _stprintf (buffer, _T("(A%d)+"), reg);
1.1.1.4 root 2384: addr = regs.regs[reg + 8];
1.1.1.9 ! root 2385: showea_val(buffer, opcode, addr, size);
1.1.1.4 root 2386: break;
2387: case Apdi:
1.1.1.7 root 2388: _stprintf (buffer, _T("-(A%d)"), reg);
1.1.1.4 root 2389: addr = regs.regs[reg + 8];
1.1.1.9 ! root 2390: showea_val(buffer, opcode, addr - datasizes[size], size);
1.1.1.4 root 2391: break;
2392: case Ad16:
2393: {
2394: TCHAR offtxt[80];
1.1.1.7 root 2395: disp16 = get_iword_debug (pc); pc += 2;
1.1.1.4 root 2396: if (disp16 < 0)
1.1.1.7 root 2397: _stprintf (offtxt, _T("-$%04x"), -disp16);
1.1.1.4 root 2398: else
1.1.1.7 root 2399: _stprintf (offtxt, _T("$%04x"), disp16);
1.1.1.4 root 2400: addr = m68k_areg (regs, reg) + disp16;
1.1.1.7 root 2401: _stprintf (buffer, _T("(A%d, %s) == $%08x"), reg, offtxt, addr);
1.1.1.9 ! root 2402: showea_val(buffer, opcode, addr, size);
1.1.1.4 root 2403: }
2404: break;
2405: case Ad8r:
1.1.1.7 root 2406: dp = get_iword_debug (pc); pc += 2;
1.1.1.4 root 2407: disp8 = dp & 0xFF;
2408: r = (dp & 0x7000) >> 12;
2409: dispreg = dp & 0x8000 ? m68k_areg (regs, r) : m68k_dreg (regs, r);
2410: if (!(dp & 0x800)) dispreg = (uae_s32)(uae_s16)(dispreg);
2411: dispreg <<= (dp >> 9) & 3;
2412:
2413: if (dp & 0x100) {
2414: uae_s32 outer = 0, disp = 0;
2415: uae_s32 base = m68k_areg (regs, reg);
2416: TCHAR name[10];
1.1.1.7 root 2417: _stprintf (name, _T("A%d, "), reg);
1.1.1.4 root 2418: if (dp & 0x80) { base = 0; name[0] = 0; }
2419: if (dp & 0x40) dispreg = 0;
1.1.1.7 root 2420: if ((dp & 0x30) == 0x20) { disp = (uae_s32)(uae_s16)get_iword_debug (pc); pc += 2; }
2421: if ((dp & 0x30) == 0x30) { disp = get_ilong_debug (pc); pc += 4; }
1.1.1.4 root 2422: base += disp;
2423:
1.1.1.7 root 2424: if ((dp & 0x3) == 0x2) { outer = (uae_s32)(uae_s16)get_iword_debug (pc); pc += 2; }
2425: if ((dp & 0x3) == 0x3) { outer = get_ilong_debug (pc); pc += 4; }
1.1.1.4 root 2426:
2427: if (!(dp & 4)) base += dispreg;
1.1.1.7 root 2428: if ((dp & 3) && !safemode) base = get_ilong_debug (base);
1.1.1.4 root 2429: if (dp & 4) base += dispreg;
2430:
2431: addr = base + outer;
1.1.1.7 root 2432: _stprintf (buffer, _T("(%s%c%d.%c*%d+%d)+%d == $%08x"), name,
1.1.1.4 root 2433: dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W',
2434: 1 << ((dp >> 9) & 3),
1.1.1.7 root 2435: disp, outer, addr);
1.1.1.4 root 2436: } else {
2437: addr = m68k_areg (regs, reg) + (uae_s32)((uae_s8)disp8) + dispreg;
1.1.1.7 root 2438: _stprintf (buffer, _T("(A%d, %c%d.%c*%d, $%02x) == $%08x"), reg,
1.1.1.4 root 2439: dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W',
1.1.1.7 root 2440: 1 << ((dp >> 9) & 3), disp8, addr);
1.1.1.4 root 2441: }
1.1.1.9 ! root 2442: showea_val(buffer, opcode, addr, size);
1.1.1.4 root 2443: break;
2444: case PC16:
1.1.1.7 root 2445: disp16 = get_iword_debug (pc); pc += 2;
1.1.1.4 root 2446: addr += (uae_s16)disp16;
1.1.1.7 root 2447: _stprintf (buffer, _T("(PC,$%04x) == $%08x"), disp16 & 0xffff, addr);
1.1.1.9 ! root 2448: showea_val(buffer, opcode, addr, size);
1.1.1.4 root 2449: break;
2450: case PC8r:
1.1.1.7 root 2451: dp = get_iword_debug (pc); pc += 2;
1.1.1.4 root 2452: disp8 = dp & 0xFF;
2453: r = (dp & 0x7000) >> 12;
2454: dispreg = dp & 0x8000 ? m68k_areg (regs, r) : m68k_dreg (regs, r);
2455: if (!(dp & 0x800)) dispreg = (uae_s32)(uae_s16)(dispreg);
2456: dispreg <<= (dp >> 9) & 3;
2457:
2458: if (dp & 0x100) {
2459: uae_s32 outer = 0, disp = 0;
2460: uae_s32 base = addr;
2461: TCHAR name[10];
1.1.1.7 root 2462: _stprintf (name, _T("PC, "));
1.1.1.4 root 2463: if (dp & 0x80) { base = 0; name[0] = 0; }
2464: if (dp & 0x40) dispreg = 0;
1.1.1.7 root 2465: if ((dp & 0x30) == 0x20) { disp = (uae_s32)(uae_s16)get_iword_debug (pc); pc += 2; }
2466: if ((dp & 0x30) == 0x30) { disp = get_ilong_debug (pc); pc += 4; }
1.1.1.4 root 2467: base += disp;
2468:
1.1.1.7 root 2469: if ((dp & 0x3) == 0x2) { outer = (uae_s32)(uae_s16)get_iword_debug (pc); pc += 2; }
2470: if ((dp & 0x3) == 0x3) { outer = get_ilong_debug (pc); pc += 4; }
1.1.1.4 root 2471:
2472: if (!(dp & 4)) base += dispreg;
1.1.1.7 root 2473: if ((dp & 3) && !safemode) base = get_ilong_debug (base);
1.1.1.4 root 2474: if (dp & 4) base += dispreg;
2475:
2476: addr = base + outer;
1.1.1.7 root 2477: _stprintf (buffer, _T("(%s%c%d.%c*%d+%d)+%d == $%08x"), name,
1.1.1.4 root 2478: dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W',
2479: 1 << ((dp >> 9) & 3),
1.1.1.7 root 2480: disp, outer, addr);
1.1.1.4 root 2481: } else {
2482: addr += (uae_s32)((uae_s8)disp8) + dispreg;
1.1.1.7 root 2483: _stprintf (buffer, _T("(PC, %c%d.%c*%d, $%02x) == $%08x"), dp & 0x8000 ? 'A' : 'D',
1.1.1.4 root 2484: (int)r, dp & 0x800 ? 'L' : 'W', 1 << ((dp >> 9) & 3),
1.1.1.7 root 2485: disp8, addr);
1.1.1.4 root 2486: }
1.1.1.9 ! root 2487: showea_val(buffer, opcode, addr, size);
1.1.1.4 root 2488: break;
2489: case absw:
1.1.1.7 root 2490: addr = (uae_s32)(uae_s16)get_iword_debug (pc);
1.1.1.9 ! root 2491: _stprintf (buffer, _T("$%04x"), (uae_u16)addr);
1.1.1.7 root 2492: pc += 2;
1.1.1.9 ! root 2493: showea_val(buffer, opcode, addr, size);
1.1.1.4 root 2494: break;
2495: case absl:
1.1.1.7 root 2496: addr = get_ilong_debug (pc);
2497: _stprintf (buffer, _T("$%08x"), addr);
2498: pc += 4;
1.1.1.9 ! root 2499: showea_val(buffer, opcode, addr, size);
1.1.1.4 root 2500: break;
2501: case imm:
2502: switch (size){
2503: case sz_byte:
1.1.1.7 root 2504: _stprintf (buffer, _T("#$%02x"), (get_iword_debug (pc) & 0xff));
2505: pc += 2;
1.1.1.4 root 2506: break;
2507: case sz_word:
1.1.1.7 root 2508: _stprintf (buffer, _T("#$%04x"), (get_iword_debug (pc) & 0xffff));
2509: pc += 2;
1.1.1.4 root 2510: break;
2511: case sz_long:
1.1.1.7 root 2512: _stprintf(buffer, _T("#$%08x"), (get_ilong_debug(pc)));
2513: pc += 4;
2514: break;
2515: case sz_single:
2516: {
2517: fpdata fp;
1.1.1.9 ! root 2518: fpp_to_single(&fp, get_ilong_debug(pc));
! 2519: _stprintf(buffer, _T("#%s"), fpp_print(&fp, 0));
1.1.1.7 root 2520: pc += 4;
2521: }
2522: break;
2523: case sz_double:
2524: {
2525: fpdata fp;
1.1.1.9 ! root 2526: fpp_to_double(&fp, get_ilong_debug(pc), get_ilong_debug(pc + 4));
! 2527: _stprintf(buffer, _T("#%s"), fpp_print(&fp, 0));
1.1.1.7 root 2528: pc += 8;
2529: }
2530: break;
2531: case sz_extended:
2532: {
2533: fpdata fp;
1.1.1.9 ! root 2534: fpp_to_exten(&fp, get_ilong_debug(pc), get_ilong_debug(pc + 4), get_ilong_debug(pc + 8));
! 2535: _stprintf(buffer, _T("#%s"), fpp_print(&fp, 0));
1.1.1.7 root 2536: pc += 12;
2537: break;
2538: }
2539: case sz_packed:
2540: _stprintf(buffer, _T("#$%08x%08x%08x"), get_ilong_debug(pc), get_ilong_debug(pc + 4), get_ilong_debug(pc + 8));
2541: pc += 12;
1.1.1.4 root 2542: break;
2543: default:
2544: break;
2545: }
2546: break;
2547: case imm0:
1.1.1.7 root 2548: offset = (uae_s32)(uae_s8)get_iword_debug (pc);
2549: _stprintf (buffer, _T("#$%02x"), (uae_u32)(offset & 0xff));
2550: addr = pc + 2 + offset;
2551: pc += 2;
1.1.1.4 root 2552: break;
2553: case imm1:
1.1.1.7 root 2554: offset = (uae_s32)(uae_s16)get_iword_debug (pc);
1.1.1.4 root 2555: buffer[0] = 0;
1.1.1.7 root 2556: _stprintf (buffer, _T("#$%04x"), (uae_u32)(offset & 0xffff));
2557: addr = pc + offset;
2558: pc += 2;
1.1.1.4 root 2559: break;
2560: case imm2:
1.1.1.7 root 2561: offset = (uae_s32)get_ilong_debug (pc);
2562: _stprintf (buffer, _T("#$%08x"), (uae_u32)offset);
2563: addr = pc + offset;
2564: pc += 4;
1.1.1.4 root 2565: break;
2566: case immi:
2567: offset = (uae_s32)(uae_s8)(reg & 0xff);
1.1.1.9 ! root 2568: _stprintf (buffer, _T("#$%02x"), (uae_u8)offset);
1.1.1.7 root 2569: addr = pc + offset;
1.1.1.4 root 2570: break;
2571: default:
2572: break;
2573: }
2574: if (buf == 0)
1.1.1.7 root 2575: f_out (f, _T("%s"), buffer);
1.1.1.4 root 2576: else
2577: _tcscat (buf, buffer);
2578: if (eaddr)
2579: *eaddr = addr;
1.1.1.7 root 2580: return pc;
1.1.1.4 root 2581: }
2582:
2583: #if 0
2584: /* The plan is that this will take over the job of exception 3 handling -
2585: * the CPU emulation functions will just do a longjmp to m68k_go whenever
2586: * they hit an odd address. */
2587: static int verify_ea (int reg, amodes mode, wordsizes size, uae_u32 *val)
2588: {
2589: uae_u16 dp;
2590: uae_s8 disp8;
2591: uae_s16 disp16;
2592: int r;
2593: uae_u32 dispreg;
2594: uaecptr addr;
2595: uae_s32 offset = 0;
2596:
2597: switch (mode){
2598: case Dreg:
2599: *val = m68k_dreg (regs, reg);
2600: return 1;
2601: case Areg:
2602: *val = m68k_areg (regs, reg);
2603: return 1;
2604:
2605: case Aind:
2606: case Aipi:
2607: addr = m68k_areg (regs, reg);
2608: break;
2609: case Apdi:
2610: addr = m68k_areg (regs, reg);
2611: break;
2612: case Ad16:
2613: disp16 = get_iword_1 (m68kpc_offset); m68kpc_offset += 2;
2614: addr = m68k_areg (regs, reg) + (uae_s16)disp16;
2615: break;
2616: case Ad8r:
2617: addr = m68k_areg (regs, reg);
2618: d8r_common:
2619: dp = get_iword_1 (m68kpc_offset); m68kpc_offset += 2;
2620: disp8 = dp & 0xFF;
2621: r = (dp & 0x7000) >> 12;
2622: dispreg = dp & 0x8000 ? m68k_areg (regs, r) : m68k_dreg (regs, r);
2623: if (!(dp & 0x800)) dispreg = (uae_s32)(uae_s16)(dispreg);
2624: dispreg <<= (dp >> 9) & 3;
2625:
2626: if (dp & 0x100) {
2627: uae_s32 outer = 0, disp = 0;
2628: uae_s32 base = addr;
2629: if (dp & 0x80) base = 0;
2630: if (dp & 0x40) dispreg = 0;
2631: if ((dp & 0x30) == 0x20) { disp = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; }
2632: if ((dp & 0x30) == 0x30) { disp = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; }
2633: base += disp;
2634:
2635: if ((dp & 0x3) == 0x2) { outer = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; }
2636: if ((dp & 0x3) == 0x3) { outer = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; }
2637:
2638: if (!(dp & 4)) base += dispreg;
2639: if (dp & 3) base = get_long (base);
2640: if (dp & 4) base += dispreg;
2641:
2642: addr = base + outer;
2643: } else {
2644: addr += (uae_s32)((uae_s8)disp8) + dispreg;
2645: }
2646: break;
2647: case PC16:
2648: addr = m68k_getpc () + m68kpc_offset;
2649: disp16 = get_iword_1 (m68kpc_offset); m68kpc_offset += 2;
2650: addr += (uae_s16)disp16;
2651: break;
2652: case PC8r:
2653: addr = m68k_getpc () + m68kpc_offset;
2654: goto d8r_common;
2655: case absw:
2656: addr = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset);
2657: m68kpc_offset += 2;
2658: break;
2659: case absl:
2660: addr = get_ilong_1 (m68kpc_offset);
2661: m68kpc_offset += 4;
2662: break;
2663: case imm:
2664: switch (size){
2665: case sz_byte:
2666: *val = get_iword_1 (m68kpc_offset) & 0xff;
2667: m68kpc_offset += 2;
2668: break;
2669: case sz_word:
2670: *val = get_iword_1 (m68kpc_offset) & 0xffff;
2671: m68kpc_offset += 2;
2672: break;
2673: case sz_long:
2674: *val = get_ilong_1 (m68kpc_offset);
2675: m68kpc_offset += 4;
2676: break;
2677: default:
2678: break;
2679: }
2680: return 1;
2681: case imm0:
2682: *val = (uae_s32)(uae_s8)get_iword_1 (m68kpc_offset);
2683: m68kpc_offset += 2;
2684: return 1;
2685: case imm1:
2686: *val = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset);
2687: m68kpc_offset += 2;
2688: return 1;
2689: case imm2:
2690: *val = get_ilong_1 (m68kpc_offset);
2691: m68kpc_offset += 4;
2692: return 1;
2693: case immi:
2694: *val = (uae_s32)(uae_s8)(reg & 0xff);
2695: return 1;
2696: default:
2697: addr = 0;
2698: break;
2699: }
2700: if ((addr & 1) == 0)
2701: return 1;
2702:
2703: last_addr_for_exception_3 = m68k_getpc () + m68kpc_offset;
2704: last_fault_for_exception_3 = addr;
2705: last_writeaccess_for_exception_3 = 0;
2706: last_instructionaccess_for_exception_3 = 0;
2707: return 0;
2708: }
2709: #endif
2710:
2711: int get_cpu_model (void)
2712: {
2713: return currprefs.cpu_model;
2714: }
2715:
1.1.1.7 root 2716: #ifndef WINUAE_FOR_HATARI
2717: STATIC_INLINE int in_rom (uaecptr pc)
1.1.1.4 root 2718: {
1.1.1.7 root 2719: return (munge24 (pc) & 0xFFF80000) == 0xF80000;
1.1.1.4 root 2720: }
2721:
1.1.1.7 root 2722: STATIC_INLINE int in_rtarea (uaecptr pc)
1.1.1.4 root 2723: {
1.1.1.9 ! root 2724: return (munge24 (pc) & 0xFFFF0000) == rtarea_base && (uae_boot_rom_type || currprefs.uaeboard > 0);
1.1.1.4 root 2725: }
1.1.1.7 root 2726: #endif
1.1.1.4 root 2727:
1.1.1.7 root 2728: STATIC_INLINE void wait_memory_cycles (void)
1.1.1.4 root 2729: {
1.1.1.7 root 2730: if (regs.memory_waitstate_cycles) {
2731: x_do_cycles(regs.memory_waitstate_cycles);
2732: regs.memory_waitstate_cycles = 0;
1.1.1.4 root 2733: }
1.1.1.7 root 2734: if (regs.ce020extracycles >= 16) {
2735: regs.ce020extracycles = 0;
2736: x_do_cycles(4 * CYCLE_UNIT);
1.1.1.4 root 2737: }
2738: }
2739:
1.1.1.7 root 2740: STATIC_INLINE int adjust_cycles (int cycles)
1.1.1.4 root 2741: {
1.1.1.7 root 2742: int mc = regs.memory_waitstate_cycles;
2743: regs.memory_waitstate_cycles = 0;
2744: if (currprefs.m68k_speed < 0 || cycles_mult == 0)
2745: return cycles + mc;
2746: cycles *= cycles_mult;
2747: cycles /= CYCLES_DIV;
2748: return cycles + mc;
1.1.1.4 root 2749: }
2750:
1.1.1.9 ! root 2751: void m68k_cancel_idle(void)
! 2752: {
! 2753: #ifndef WINUAE_FOR_HATARI
! 2754: cpu_last_stop_vpos = -1;
! 2755: #endif
! 2756: }
! 2757:
1.1.1.8 root 2758: static void m68k_set_stop(void)
2759: {
2760: if (regs.stopped)
2761: return;
2762: regs.stopped = 1;
2763: set_special(SPCFLAG_STOP);
2764: #ifndef WINUAE_FOR_HATARI
1.1.1.9 ! root 2765: if (cpu_last_stop_vpos >= 0) {
! 2766: cpu_last_stop_vpos = vpos;
! 2767: }
1.1.1.8 root 2768: #endif
2769: }
2770:
2771: static void m68k_unset_stop(void)
2772: {
2773: regs.stopped = 0;
2774: unset_special(SPCFLAG_STOP);
2775: #ifndef WINUAE_FOR_HATARI
1.1.1.9 ! root 2776: if (cpu_last_stop_vpos >= 0) {
! 2777: cpu_stopped_lines += vpos - cpu_last_stop_vpos;
! 2778: cpu_last_stop_vpos = vpos;
! 2779: }
1.1.1.8 root 2780: #endif
2781: }
2782:
1.1.1.9 ! root 2783: static void activate_trace(void)
! 2784: {
! 2785: unset_special (SPCFLAG_TRACE);
! 2786: set_special (SPCFLAG_DOTRACE);
! 2787: }
! 2788:
! 2789: void REGPARAM2 MakeSR (void)
1.1.1.4 root 2790: {
2791: regs.sr = ((regs.t1 << 15) | (regs.t0 << 14)
2792: | (regs.s << 13) | (regs.m << 12) | (regs.intmask << 8)
2793: | (GET_XFLG () << 4) | (GET_NFLG () << 3)
2794: | (GET_ZFLG () << 2) | (GET_VFLG () << 1)
2795: | GET_CFLG ());
2796: }
2797:
1.1.1.8 root 2798: static void SetSR (uae_u16 sr)
1.1.1.4 root 2799: {
1.1.1.7 root 2800: regs.sr &= 0xff00;
2801: regs.sr |= sr;
1.1.1.4 root 2802:
2803: SET_XFLG ((regs.sr >> 4) & 1);
2804: SET_NFLG ((regs.sr >> 3) & 1);
2805: SET_ZFLG ((regs.sr >> 2) & 1);
2806: SET_VFLG ((regs.sr >> 1) & 1);
2807: SET_CFLG (regs.sr & 1);
1.1.1.7 root 2808: }
2809:
1.1.1.9 ! root 2810: static void MakeFromSR_x(int t0trace)
1.1.1.7 root 2811: {
2812: int oldm = regs.m;
2813: int olds = regs.s;
1.1.1.9 ! root 2814: int oldt0 = regs.t0;
! 2815: int oldt1 = regs.t1;
1.1.1.7 root 2816:
2817: SET_XFLG ((regs.sr >> 4) & 1);
2818: SET_NFLG ((regs.sr >> 3) & 1);
2819: SET_ZFLG ((regs.sr >> 2) & 1);
2820: SET_VFLG ((regs.sr >> 1) & 1);
2821: SET_CFLG (regs.sr & 1);
2822: if (regs.t1 == ((regs.sr >> 15) & 1) &&
2823: regs.t0 == ((regs.sr >> 14) & 1) &&
2824: regs.s == ((regs.sr >> 13) & 1) &&
1.1.1.4 root 2825: regs.m == ((regs.sr >> 12) & 1) &&
2826: regs.intmask == ((regs.sr >> 8) & 7))
2827: return;
2828: regs.t1 = (regs.sr >> 15) & 1;
2829: regs.t0 = (regs.sr >> 14) & 1;
2830: regs.s = (regs.sr >> 13) & 1;
2831: regs.m = (regs.sr >> 12) & 1;
2832: regs.intmask = (regs.sr >> 8) & 7;
2833: if (currprefs.cpu_model >= 68020) {
2834: /* 68060 does not have MSP but does have M-bit.. */
2835: if (currprefs.cpu_model >= 68060)
2836: regs.msp = regs.isp;
2837: if (olds != regs.s) {
2838: if (olds) {
2839: if (oldm)
2840: regs.msp = m68k_areg (regs, 7);
2841: else
2842: regs.isp = m68k_areg (regs, 7);
2843: m68k_areg (regs, 7) = regs.usp;
2844: } else {
2845: regs.usp = m68k_areg (regs, 7);
2846: m68k_areg (regs, 7) = regs.m ? regs.msp : regs.isp;
2847: }
2848: } else if (olds && oldm != regs.m) {
2849: if (oldm) {
2850: regs.msp = m68k_areg (regs, 7);
2851: m68k_areg (regs, 7) = regs.isp;
2852: } else {
2853: regs.isp = m68k_areg (regs, 7);
2854: m68k_areg (regs, 7) = regs.msp;
2855: }
2856: }
2857: if (currprefs.cpu_model >= 68060)
2858: regs.t0 = 0;
2859: } else {
2860: regs.t0 = regs.m = 0;
2861: if (olds != regs.s) {
2862: if (olds) {
2863: regs.isp = m68k_areg (regs, 7);
2864: m68k_areg (regs, 7) = regs.usp;
2865: } else {
2866: regs.usp = m68k_areg (regs, 7);
2867: m68k_areg (regs, 7) = regs.isp;
2868: }
2869: }
2870: }
2871: if (currprefs.mmu_model)
2872: mmu_set_super (regs.s != 0);
2873:
2874: doint ();
1.1.1.9 ! root 2875: if (regs.t1 || regs.t0) {
1.1.1.4 root 2876: set_special (SPCFLAG_TRACE);
1.1.1.9 ! root 2877: } else {
1.1.1.4 root 2878: /* Keep SPCFLAG_DOTRACE, we still want a trace exception for
2879: SR-modifying instructions (including STOP). */
2880: unset_special (SPCFLAG_TRACE);
1.1.1.9 ! root 2881: }
! 2882: // Stop SR-modification does not generate T0
! 2883: // If this SR modification set Tx bit, no trace until next instruction.
! 2884: if ((oldt0 && t0trace && currprefs.cpu_model >= 68020) || oldt1) {
! 2885: // Always trace if Tx bits were already set, even if this SR modification cleared them.
! 2886: activate_trace();
! 2887: }
! 2888: }
! 2889:
! 2890: void REGPARAM2 MakeFromSR_T0(void)
! 2891: {
! 2892: MakeFromSR_x(1);
! 2893: }
! 2894: void REGPARAM2 MakeFromSR(void)
! 2895: {
! 2896: MakeFromSR_x(0);
1.1.1.4 root 2897: }
2898:
1.1.1.8 root 2899: static void exception_check_trace (int nr)
1.1.1.4 root 2900: {
2901: unset_special (SPCFLAG_TRACE | SPCFLAG_DOTRACE);
2902: if (regs.t1 && !regs.t0) {
2903: /* trace stays pending if exception is div by zero, chk,
2904: * trapv or trap #x
2905: */
2906: if (nr == 5 || nr == 6 || nr == 7 || (nr >= 32 && nr <= 47))
2907: set_special (SPCFLAG_DOTRACE);
2908: }
1.1.1.8 root 2909: regs.t1 = regs.t0 = 0;
1.1.1.4 root 2910: }
2911:
2912: static void exception_debug (int nr)
2913: {
1.1.1.7 root 2914: #ifdef WINUAE_FOR_HATARI
1.1.1.8 root 2915: if (unlikely(ExceptionDebugMask & EXCEPT_NOHANDLER) && STMemory_ReadLong(regs.vbr + 4*nr) == 0) {
2916: fprintf(stderr,"Uninitialized exception handler #%i!\n", nr);
2917: DebugUI(REASON_CPU_EXCEPTION);
2918: } else {
2919: DebugUI_Exceptions(nr, M68K_GETPC);
2920: }
1.1.1.9 ! root 2921: #else
! 2922: #ifdef DEBUGGER
! 2923: if (!exception_debugging)
! 2924: return;
! 2925: console_out_f (_T("Exception %d, PC=%08X\n"), nr, M68K_GETPC);
! 2926: #endif
1.1.1.7 root 2927: #endif
1.1.1.4 root 2928: }
2929:
1.1.1.7 root 2930: #ifdef CPUEMU_13
1.1.1.4 root 2931:
2932: /* cycle-exact exception handler, 68000 only */
2933:
2934: /*
2935:
2936: Address/Bus Error:
2937:
1.1.1.7 root 2938: - 8 idle cycles
1.1.1.4 root 2939: - write PC low word
2940: - write SR
2941: - write PC high word
2942: - write instruction word
2943: - write fault address low word
2944: - write status code
2945: - write fault address high word
2946: - 2 idle cycles
2947: - read exception address high word
2948: - read exception address low word
2949: - prefetch
2950: - 2 idle cycles
2951: - prefetch
2952:
2953: Division by Zero:
2954:
1.1.1.7 root 2955: - 8 idle cycles
1.1.1.4 root 2956: - write PC low word
2957: - write SR
2958: - write PC high word
2959: - read exception address high word
2960: - read exception address low word
2961: - prefetch
2962: - 2 idle cycles
2963: - prefetch
2964:
2965: Traps:
2966:
1.1.1.7 root 2967: - 4 idle cycles
1.1.1.4 root 2968: - write PC low word
2969: - write SR
2970: - write PC high word
2971: - read exception address high word
2972: - read exception address low word
2973: - prefetch
2974: - 2 idle cycles
2975: - prefetch
2976:
2977: TrapV:
2978:
1.1.1.7 root 2979: (- normal prefetch done by TRAPV)
1.1.1.4 root 2980: - write PC low word
2981: - write SR
2982: - write PC high word
2983: - read exception address high word
2984: - read exception address low word
2985: - prefetch
2986: - 2 idle cycles
2987: - prefetch
2988:
2989: CHK:
2990:
1.1.1.7 root 2991: - 8 idle cycles
1.1.1.4 root 2992: - write PC low word
2993: - write SR
2994: - write PC high word
2995: - read exception address high word
2996: - read exception address low word
2997: - prefetch
2998: - 2 idle cycles
2999: - prefetch
3000:
3001: Illegal Instruction:
1.1.1.7 root 3002: Privilege violation:
1.1.1.8 root 3003: Trace:
1.1.1.7 root 3004: Line A:
3005: Line F:
1.1.1.4 root 3006:
1.1.1.7 root 3007: - 4 idle cycles
1.1.1.4 root 3008: - write PC low word
3009: - write SR
3010: - write PC high word
3011: - read exception address high word
3012: - read exception address low word
3013: - prefetch
3014: - 2 idle cycles
3015: - prefetch
3016:
1.1.1.7 root 3017: Interrupt:
1.1.1.4 root 3018:
3019: - 6 idle cycles
3020: - write PC low word
3021: - read exception number byte from (0xfffff1 | (interrupt number << 1))
3022: - 4 idle cycles
3023: - write SR
3024: - write PC high word
3025: - read exception address high word
3026: - read exception address low word
3027: - prefetch
3028: - 2 idle cycles
3029: - prefetch
3030:
3031: */
3032:
1.1.1.7 root 3033: static int iack_cycle(int nr)
3034: {
3035: int vector;
3036:
3037: #ifndef WINUAE_FOR_HATARI
3038: if (1) {
3039: // non-autovectored
3040: vector = x_get_byte(0x00fffff1 | ((nr - 24) << 1));
3041: if (currprefs.cpu_cycle_exact)
3042: x_do_cycles(4 * cpucycleunit);
3043: } else {
3044: // autovectored
3045:
3046: }
3047: #else
3048: int iack_start = CPU_IACK_CYCLES_START;
3049: int e_cycles;
1.1.1.8 root 3050: int cycle_exact = currprefs.cpu_cycle_exact && !currprefs.mmu_model;
1.1.1.7 root 3051:
3052: /* In cycle exact mode, the cycles before reaching IACK are already counted */
1.1.1.8 root 3053: if (cycle_exact)
1.1.1.7 root 3054: iack_start = 0;
3055:
3056: /* Pending bits / vector number can change before the end of the IACK sequence. */
3057: /* We need to handle MFP/DSP and HBL/VBL cases for this. */
3058: /* - Level 6 (MFP/DSP) use vectored interrupts */
3059: /* - Level 2 (HBL) and 4 (VBL) use auto-vectored interrupts and require sync with E-clock */
3060: vector = nr;
3061: if ( nr == 30 ) /* MFP or DSP */
3062: {
3063: vector = -1;
3064: if (bDspEnabled) /* Check DSP first */
3065: {
3066: /* TODO : For DSP, we just get the vector, we don't add IACK cycles */
3067: vector = DSP_ProcessIACK ();
3068: }
3069:
3070: if ( vector < 0 ) /* No DSP, check MFP */
3071: {
1.1.1.8 root 3072: if (cycle_exact)
3073: {
3074: x_do_cycles ( ( iack_start + CPU_IACK_CYCLES_MFP ) * cpucycleunit );
3075: /* Flush all CE cycles so far to update PendingInterruptCount */
3076: M68000_AddCycles_CE ( currcycle * 2 / CYCLE_UNIT );
3077: currcycle=0;
3078: }
3079: else
3080: M68000_AddCycles ( iack_start + CPU_IACK_CYCLES_MFP );
3081:
1.1.1.7 root 3082: CPU_IACK = true;
3083: while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) )
3084: CALL_VAR(PendingInterruptFunction);
3085: vector = MFP_ProcessIACK ( nr );
3086: CPU_IACK = false;
3087: }
1.1.1.8 root 3088:
3089: if ( vector >= 0 ) /* We have a valid vector for level 6 */
3090: {
3091: /* If a DSP IRQ is pending, we don't clear level 6 pending bit, else the DSP IRQ */
3092: /* will never be processed. If there's no DSP IRQ, we clear level 6 pending bit now */
3093: /* and if there's a lower MFP pending int, level 6 will be set again at the next instruction */
3094: if ( DSP_GetHREQ() == 0 )
3095: pendingInterrupts &= ~( 1 << 6 );
3096: }
1.1.1.7 root 3097: }
3098: else if ( ( nr == 26 ) || ( nr == 28 ) ) /* HBL / VBL */
3099: {
1.1.1.8 root 3100: if (cycle_exact)
3101: {
3102: /* In CE mode, iack_start = 0, no need to call x_do_cycles() */
3103: //x_do_cycles ( ( iack_start + CPU_IACK_CYCLES_VIDEO_CE + e_cycles ) * cpucycleunit );
3104: /* Flush all CE cycles so far before calling M68000_WaitEClock() */
3105: M68000_AddCycles_CE ( currcycle * 2 / CYCLE_UNIT );
3106: currcycle = 0;
3107: }
3108: else
3109: M68000_AddCycles ( iack_start );
3110:
1.1.1.7 root 3111: e_cycles = M68000_WaitEClock ();
1.1.1.8 root 3112: // fprintf ( stderr , "wait e clock %d\n" , e_cycles);
3113:
3114: if (cycle_exact)
3115: {
3116: x_do_cycles ( ( e_cycles + CPU_IACK_CYCLES_VIDEO_CE ) * cpucycleunit );
3117: /* Flush all CE cycles so far to update PendingInterruptCount */
3118: M68000_AddCycles_CE ( currcycle * 2 / CYCLE_UNIT );
3119: currcycle = 0;
3120: }
3121: else
3122: M68000_AddCycles ( e_cycles + CPU_IACK_CYCLES_VIDEO_CE );
1.1.1.7 root 3123:
3124: CPU_IACK = true;
3125: while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) )
3126: CALL_VAR(PendingInterruptFunction);
3127: if ( MFP_UpdateNeeded == true )
3128: MFP_UpdateIRQ ( 0 ); /* update MFP's state if some internal timers related to MFP expired */
1.1.1.8 root 3129: pendingInterrupts &= ~( 1 << ( nr - 24 ) ); /* clear HBL or VBL pending bit (even if an MFP timer occurred during IACK) */
1.1.1.7 root 3130: CPU_IACK = false;
3131: }
3132:
3133: /* TODO If there was no DSP and no MFP IRQ, then we have a spurious interrupt */
3134: /* In that case, we use vector 24 and we jump to $60 */
3135: if ( vector < 0 )
3136: {
3137: }
1.1.1.8 root 3138:
3139: /* Add 4 idle cycles for CE mode. For non-CE mode, this will be counted in add_approximate_exception_cycles() */
3140: if (cycle_exact)
3141: x_do_cycles( 4 * cpucycleunit );
1.1.1.7 root 3142: #endif
3143: return vector;
3144: }
3145:
3146: static void Exception_ce000 (int nr)
1.1.1.4 root 3147: {
3148: uae_u32 currpc = m68k_getpc (), newpc;
3149: int sv = regs.s;
1.1.1.7 root 3150: int start, interrupt;
3151: int vector_nr = nr;
1.1.1.4 root 3152:
1.1.1.8 root 3153: //fprintf ( stderr , "ex in %d %ld %ld\n" , nr , currcycle , CyclesGlobalClockCounter );
1.1.1.7 root 3154: start = 6;
1.1.1.4 root 3155: interrupt = nr >= 24 && nr < 24 + 8;
1.1.1.7 root 3156: if (!interrupt) {
3157: start = 8;
3158: if (nr == 7) // TRAPV
3159: start = 0;
3160: else if (nr >= 32 && nr < 32 + 16) // TRAP #x
3161: start = 4;
1.1.1.8 root 3162: else if (nr == 4 || nr == 8 || nr == 9 || nr == 10 || nr == 11) // ILLG, PRIV, TRACE, LINEA, LINEF
1.1.1.7 root 3163: start = 4;
3164: }
1.1.1.4 root 3165:
3166: if (start)
1.1.1.7 root 3167: x_do_cycles (start * cpucycleunit);
1.1.1.4 root 3168:
1.1.1.7 root 3169: #ifdef WINUAE_FOR_HATARI
3170: 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",
3171: 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);
3172: #endif
1.1.1.4 root 3173: exception_debug (nr);
3174: MakeSR ();
3175:
3176: if (!regs.s) {
3177: regs.usp = m68k_areg (regs, 7);
3178: m68k_areg (regs, 7) = regs.isp;
3179: regs.s = 1;
3180: }
3181: if (nr == 2 || nr == 3) { /* 2=bus error, 3=address error */
1.1.1.7 root 3182: if ((m68k_areg(regs, 7) & 1) || exception_in_exception < 0) {
1.1.1.8 root 3183: cpu_halt (CPU_HALT_DOUBLE_FAULT);
1.1.1.7 root 3184: return;
3185: }
1.1.1.4 root 3186: uae_u16 mode = (sv ? 4 : 0) | (last_instructionaccess_for_exception_3 ? 2 : 1);
3187: mode |= last_writeaccess_for_exception_3 ? 0 : 16;
1.1.1.7 root 3188: mode |= last_notinstruction_for_exception_3 ? 8 : 0;
3189: // undocumented bits seem to contain opcode
3190: mode |= last_op_for_exception_3 & ~31;
1.1.1.4 root 3191: m68k_areg (regs, 7) -= 14;
1.1.1.7 root 3192: exception_in_exception = -1;
3193: x_put_word (m68k_areg (regs, 7) + 12, last_addr_for_exception_3);
3194: x_put_word (m68k_areg (regs, 7) + 8, regs.sr);
3195: x_put_word (m68k_areg (regs, 7) + 10, last_addr_for_exception_3 >> 16);
3196: x_put_word (m68k_areg (regs, 7) + 6, last_op_for_exception_3);
3197: x_put_word (m68k_areg (regs, 7) + 4, last_fault_for_exception_3);
3198: x_put_word (m68k_areg (regs, 7) + 0, mode);
3199: x_put_word (m68k_areg (regs, 7) + 2, last_fault_for_exception_3 >> 16);
3200: x_do_cycles (2 * cpucycleunit);
1.1.1.8 root 3201: #ifndef WINUAE_FOR_HATARI
1.1.1.7 root 3202: write_log (_T("Exception %d (%04x %x) at %x -> %x!\n"),
3203: nr, last_op_for_exception_3, last_addr_for_exception_3, currpc, get_long_debug (4 * nr));
1.1.1.8 root 3204: #else
3205: if (nr != 2 || last_fault_for_exception_3 != 0xff8a00 || currpc < TosAddress || currpc > TosAddress + TosSize)
3206: fprintf(stderr,"%s Error at address $%x, PC=$%x addr_e3=%x op_e3=%x\n", nr==2?"Bus":"Address",
3207: last_fault_for_exception_3, currpc, last_addr_for_exception_3 , last_op_for_exception_3);
1.1.1.7 root 3208: #endif
1.1.1.4 root 3209: goto kludge_me_do;
3210: }
1.1.1.7 root 3211: if (currprefs.cpu_model == 68010) {
3212: // 68010 creates only format 0 and 8 stack frames
3213: m68k_areg (regs, 7) -= 8;
3214: if (m68k_areg(regs, 7) & 1) {
3215: exception3_notinstruction(regs.ir, m68k_areg(regs, 7) + 4);
3216: return;
3217: }
3218: exception_in_exception = 1;
3219: x_put_word (m68k_areg (regs, 7) + 4, currpc); // write low address
3220: if (interrupt)
3221: vector_nr = iack_cycle(nr);
3222: x_put_word (m68k_areg (regs, 7) + 0, regs.sr); // write SR
3223: x_put_word (m68k_areg (regs, 7) + 2, currpc >> 16); // write high address
3224: x_put_word (m68k_areg (regs, 7) + 6, vector_nr * 4);
3225: } else {
3226: m68k_areg (regs, 7) -= 6;
3227: if (m68k_areg(regs, 7) & 1) {
3228: exception3_notinstruction(regs.ir, m68k_areg(regs, 7) + 4);
3229: return;
3230: }
3231: exception_in_exception = 1;
3232: x_put_word (m68k_areg (regs, 7) + 4, currpc); // write low address
1.1.1.8 root 3233: //fprintf ( stderr , "ex iack1 %d %ld\n" , nr , currcycle );
1.1.1.7 root 3234: if (interrupt)
3235: vector_nr = iack_cycle(nr);
1.1.1.8 root 3236: //fprintf ( stderr , "ex iack2 %d %ld\n" , nr , currcycle );
1.1.1.7 root 3237: x_put_word (m68k_areg (regs, 7) + 0, regs.sr); // write SR
3238: x_put_word (m68k_areg (regs, 7) + 2, currpc >> 16); // write high address
1.1.1.4 root 3239: }
3240: kludge_me_do:
1.1.1.7 root 3241: newpc = x_get_word (regs.vbr + 4 * vector_nr) << 16; // read high address
3242: newpc |= x_get_word (regs.vbr + 4 * vector_nr + 2); // read low address
3243: exception_in_exception = 0;
1.1.1.4 root 3244: if (newpc & 1) {
3245: if (nr == 2 || nr == 3)
1.1.1.8 root 3246: cpu_halt (CPU_HALT_DOUBLE_FAULT);
1.1.1.4 root 3247: else
1.1.1.7 root 3248: exception3_notinstruction(regs.ir, newpc);
1.1.1.4 root 3249: return;
3250: }
3251: m68k_setpc (newpc);
1.1.1.7 root 3252: regs.ir = x_get_word (m68k_getpc ()); // prefetch 1
3253: x_do_cycles (2 * cpucycleunit);
1.1.1.8 root 3254: #ifdef WINUAE_FOR_HATARI
3255: /* [NP] IPL should be updated just before the last x_get_word for irc */
3256: /* (4 cycles before end of exception), so we need to add 2 cycles now */
3257: /* to be aligned on 4 cycles (else the 2 cycles will be added in x_get_word */
3258: /* and IPL will be updated 2 cycles too soon) */
3259: x_do_cycles (2 * cpucycleunit);
3260: /* Add all cycles needed for the exception so far */
3261: M68000_AddCycles_CE ( currcycle * 2 / CYCLE_UNIT );
3262: currcycle = 0;
3263: /* Update IPL / interrupts state, in case a new interrupt happened during this exception */
3264: while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) )
3265: CALL_VAR(PendingInterruptFunction);
3266: #endif
3267: regs.ipl_pin = intlev();
3268: ipl_fetch();
1.1.1.7 root 3269: regs.irc = x_get_word (m68k_getpc () + 2); // prefetch 2
1.1.1.4 root 3270: #ifdef JIT
3271: set_special (SPCFLAG_END_COMPILE);
3272: #endif
1.1.1.8 root 3273: exception_check_trace (nr);
1.1.1.7 root 3274:
3275: //fprintf ( stderr , "ex out %d %ld\n" , nr , currcycle );
3276: #ifdef WINUAE_FOR_HATARI
1.1.1.8 root 3277: /* Add all cycles needed for the exception */
3278: M68000_AddCycles_CE ( currcycle * 2 / CYCLE_UNIT );
3279: currcycle = 0;
1.1.1.7 root 3280: #endif
3281: }
3282: #endif
3283:
3284: static uae_u32 exception_pc (int nr)
3285: {
3286: // bus error, address error, illegal instruction, privilege violation, a-line, f-line
3287: if (nr == 2 || nr == 3 || nr == 4 || nr == 8 || nr == 10 || nr == 11)
3288: return regs.instruction_pc;
3289: return m68k_getpc ();
3290: }
3291:
3292: static void Exception_build_stack_frame (uae_u32 oldpc, uae_u32 currpc, uae_u32 ssw, int nr, int format)
3293: {
3294: int i;
3295:
3296: #if 0
3297: if (nr < 24 || nr > 31) { // do not print debugging for interrupts
3298: write_log(_T("Building exception stack frame (format %X)\n"), format);
3299: }
3300: #endif
3301:
1.1.1.9 ! root 3302: switch (format) {
1.1.1.7 root 3303: case 0x0: // four word stack frame
3304: case 0x1: // throwaway four word stack frame
3305: break;
3306: case 0x2: // six word stack frame
3307: m68k_areg (regs, 7) -= 4;
3308: x_put_long (m68k_areg (regs, 7), oldpc);
3309: break;
1.1.1.9 ! root 3310: case 0x3: // floating point post-instruction stack frame (68040)
! 3311: m68k_areg (regs, 7) -= 4;
! 3312: x_put_long (m68k_areg (regs, 7), regs.fp_ea);
! 3313: break;
! 3314: case 0x7: // access error stack frame (68040)
1.1.1.7 root 3315:
3316: for (i = 3; i >= 0; i--) {
3317: // WB1D/PD0,PD1,PD2,PD3
3318: m68k_areg (regs, 7) -= 4;
3319: x_put_long (m68k_areg (regs, 7), mmu040_move16[i]);
3320: }
3321:
3322: m68k_areg (regs, 7) -= 4;
3323: x_put_long (m68k_areg (regs, 7), 0); // WB1A
3324: m68k_areg (regs, 7) -= 4;
3325: x_put_long (m68k_areg (regs, 7), 0); // WB2D
3326: m68k_areg (regs, 7) -= 4;
3327: x_put_long (m68k_areg (regs, 7), regs.wb2_address); // WB2A
3328: m68k_areg (regs, 7) -= 4;
3329: x_put_long (m68k_areg (regs, 7), regs.wb3_data); // WB3D
3330: m68k_areg (regs, 7) -= 4;
3331: x_put_long (m68k_areg (regs, 7), regs.mmu_fault_addr); // WB3A
3332:
3333: m68k_areg (regs, 7) -= 4;
3334: x_put_long (m68k_areg (regs, 7), regs.mmu_fault_addr); // FA
3335:
3336: m68k_areg (regs, 7) -= 2;
3337: x_put_word (m68k_areg (regs, 7), 0);
3338: m68k_areg (regs, 7) -= 2;
3339: x_put_word (m68k_areg (regs, 7), regs.wb2_status);
3340: regs.wb2_status = 0;
3341: m68k_areg (regs, 7) -= 2;
3342: x_put_word (m68k_areg (regs, 7), regs.wb3_status);
3343: regs.wb3_status = 0;
3344:
3345: m68k_areg (regs, 7) -= 2;
3346: x_put_word (m68k_areg (regs, 7), ssw);
3347: m68k_areg (regs, 7) -= 4;
3348: x_put_long (m68k_areg (regs, 7), regs.mmu_effective_addr);
3349: break;
3350: case 0x9: // coprocessor mid-instruction stack frame (68020, 68030)
3351: m68k_areg (regs, 7) -= 4;
1.1.1.9 ! root 3352: x_put_long (m68k_areg (regs, 7), regs.fp_ea);
1.1.1.7 root 3353: m68k_areg (regs, 7) -= 4;
1.1.1.9 ! root 3354: x_put_long (m68k_areg (regs, 7), regs.fp_opword);
! 3355: m68k_areg (regs, 7) -= 4;
1.1.1.7 root 3356: x_put_long (m68k_areg (regs, 7), oldpc);
3357: break;
3358: case 0x8: // bus and address error stack frame (68010)
3359: write_log(_T("Exception stack frame format %X not implemented\n"), format);
3360: return;
3361: case 0x4: // floating point unimplemented stack frame (68LC040, 68EC040)
1.1.1.9 ! root 3362: // or 68060 bus access fault stack frame
1.1.1.7 root 3363: m68k_areg (regs, 7) -= 4;
1.1.1.9 ! root 3364: x_put_long (m68k_areg (regs, 7), ssw);
1.1.1.7 root 3365: m68k_areg (regs, 7) -= 4;
1.1.1.9 ! root 3366: x_put_long (m68k_areg (regs, 7), oldpc);
1.1.1.7 root 3367: break;
3368: case 0xB: // long bus cycle fault stack frame (68020, 68030)
3369: // We always use B frame because it is easier to emulate,
3370: // our PC always points at start of instruction but A frame assumes
3371: // it is + 2 and handling this properly is not easy.
3372: // Store state information to internal register space
3373: for (i = 0; i < mmu030_idx + 1; i++) {
3374: m68k_areg (regs, 7) -= 4;
3375: x_put_long (m68k_areg (regs, 7), mmu030_ad[i].val);
3376: }
3377: while (i < 9) {
3378: uae_u32 v = 0;
3379: m68k_areg (regs, 7) -= 4;
3380: // mmu030_idx is always small enough if instruction is FMOVEM.
3381: if (mmu030_state[1] & MMU030_STATEFLAG1_FMOVEM) {
3382: if (i == 7)
3383: v = mmu030_fmovem_store[0];
3384: else if (i == 8)
3385: v = mmu030_fmovem_store[1];
3386: }
3387: x_put_long (m68k_areg (regs, 7), v);
3388: i++;
3389: }
3390: // version & internal information (We store index here)
3391: m68k_areg (regs, 7) -= 2;
3392: x_put_word (m68k_areg (regs, 7), mmu030_idx);
3393: // 3* internal registers
3394: m68k_areg (regs, 7) -= 2;
3395: x_put_word (m68k_areg (regs, 7), mmu030_state[2]);
3396: m68k_areg (regs, 7) -= 2;
3397: x_put_word (m68k_areg (regs, 7), mmu030_state[1]);
3398: m68k_areg (regs, 7) -= 2;
3399: x_put_word (m68k_areg (regs, 7), mmu030_state[0]);
3400: // data input buffer = fault address
3401: m68k_areg (regs, 7) -= 4;
3402: x_put_long (m68k_areg (regs, 7), regs.mmu_fault_addr);
3403: // 2xinternal
1.1.1.9 ! root 3404: {
! 3405: uae_u32 ps = (regs.prefetch020_valid[0] ? 1 : 0) | (regs.prefetch020_valid[1] ? 2 : 0) | (regs.prefetch020_valid[2] ? 4 : 0);
! 3406: ps |= ((regs.pipeline_r8[0] & 7) << 8);
! 3407: ps |= ((regs.pipeline_r8[1] & 7) << 11);
! 3408: ps |= ((regs.pipeline_pos & 15) << 16);
! 3409: ps |= ((regs.pipeline_stop & 15) << 20);
! 3410: if (mmu030_opcode == -1)
! 3411: ps |= 1 << 31;
! 3412: m68k_areg (regs, 7) -= 4;
! 3413: x_put_long (m68k_areg (regs, 7), ps);
! 3414: }
1.1.1.7 root 3415: // stage b address
3416: m68k_areg (regs, 7) -= 4;
3417: x_put_long (m68k_areg (regs, 7), mm030_stageb_address);
3418: // 2xinternal
3419: m68k_areg (regs, 7) -= 4;
3420: x_put_long (m68k_areg (regs, 7), mmu030_disp_store[1]);
3421: /* fall through */
3422: case 0xA: // short bus cycle fault stack frame (68020, 68030)
3423: m68k_areg (regs, 7) -= 4;
3424: x_put_long (m68k_areg (regs, 7), mmu030_disp_store[0]);
3425: m68k_areg (regs, 7) -= 4;
3426: // Data output buffer = value that was going to be written
3427: x_put_long (m68k_areg (regs, 7), (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) ? mmu030_data_buffer : mmu030_ad[mmu030_idx].val);
3428: m68k_areg (regs, 7) -= 4;
1.1.1.9 ! root 3429: x_put_long (m68k_areg (regs, 7), (mmu030_opcode & 0xffff) | (regs.prefetch020[0] << 16)); // Internal register (opcode storage)
1.1.1.7 root 3430: m68k_areg (regs, 7) -= 4;
3431: x_put_long (m68k_areg (regs, 7), regs.mmu_fault_addr); // data cycle fault address
3432: m68k_areg (regs, 7) -= 2;
1.1.1.9 ! root 3433: x_put_word (m68k_areg (regs, 7), regs.prefetch020[2]); // Instr. pipe stage B
1.1.1.7 root 3434: m68k_areg (regs, 7) -= 2;
1.1.1.9 ! root 3435: x_put_word (m68k_areg (regs, 7), regs.prefetch020[1]); // Instr. pipe stage C
1.1.1.7 root 3436: m68k_areg (regs, 7) -= 2;
3437: x_put_word (m68k_areg (regs, 7), ssw);
3438: m68k_areg (regs, 7) -= 2;
3439: x_put_word (m68k_areg (regs, 7), 0); // Internal register
3440: break;
3441: default:
3442: write_log(_T("Unknown exception stack frame format: %X\n"), format);
3443: return;
3444: }
3445: m68k_areg (regs, 7) -= 2;
3446: x_put_word (m68k_areg (regs, 7), (format << 12) | (nr * 4));
3447: m68k_areg (regs, 7) -= 4;
3448: x_put_long (m68k_areg (regs, 7), currpc);
3449: m68k_areg (regs, 7) -= 2;
3450: x_put_word (m68k_areg (regs, 7), regs.sr);
1.1.1.4 root 3451: }
1.1.1.7 root 3452:
1.1.1.9 ! root 3453: static void Exception_build_stack_frame_common (uae_u32 oldpc, uae_u32 currpc, uae_u32 ssw, int nr)
! 3454: {
! 3455: if (nr == 5 || nr == 6 || nr == 7 || nr == 9) {
! 3456: Exception_build_stack_frame(oldpc, currpc, regs.mmu_ssw, nr, 0x2);
! 3457: } else if (nr == 60 || nr == 61) {
! 3458: Exception_build_stack_frame(oldpc, regs.instruction_pc, regs.mmu_ssw, nr, 0x0);
! 3459: } else if (nr >= 48 && nr <= 55) {
! 3460: if (regs.fpu_exp_pre) {
! 3461: if (currprefs.cpu_model == 68060 && nr == 55 && regs.fp_unimp_pend == 2) { // packed decimal real
! 3462: Exception_build_stack_frame(regs.fp_ea, regs.instruction_pc, 0, nr, 0x2);
! 3463: } else {
! 3464: Exception_build_stack_frame(oldpc, regs.instruction_pc, 0, nr, 0x0);
! 3465: }
! 3466: } else { /* post-instruction */
! 3467: if (currprefs.cpu_model == 68060 && nr == 55 && regs.fp_unimp_pend == 2) { // packed decimal real
! 3468: Exception_build_stack_frame(regs.fp_ea, currpc, 0, nr, 0x2);
! 3469: } else {
! 3470: Exception_build_stack_frame(oldpc, currpc, 0, nr, 0x3);
! 3471: }
! 3472: }
! 3473: } else if (nr == 11 && regs.fp_unimp_ins) {
! 3474: regs.fp_unimp_ins = false;
! 3475: if ((currprefs.cpu_model == 68060 && (currprefs.fpu_model == 0 || (regs.pcr & 2))) ||
! 3476: (currprefs.cpu_model == 68040 && currprefs.fpu_model == 0)) {
! 3477: Exception_build_stack_frame(regs.fp_ea, currpc, regs.instruction_pc, nr, 0x4);
! 3478: } else {
! 3479: Exception_build_stack_frame(regs.fp_ea, currpc, regs.mmu_ssw, nr, 0x2);
! 3480: }
! 3481: } else {
! 3482: Exception_build_stack_frame(oldpc, currpc, regs.mmu_ssw, nr, 0x0);
! 3483: }
! 3484: }
1.1.1.7 root 3485:
3486: // 68030 MMU
3487: static void Exception_mmu030 (int nr, uaecptr oldpc)
3488: {
3489: uae_u32 currpc = m68k_getpc (), newpc;
3490: int interrupt;
3491:
3492: interrupt = nr >= 24 && nr < 24 + 8;
1.1.1.4 root 3493:
1.1.1.7 root 3494: #ifdef WINUAE_FOR_HATARI
3495: if (interrupt)
3496: nr = iack_cycle(nr);
3497: #endif
3498:
3499: #ifdef WINUAE_FOR_HATARI
3500: 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",
3501: 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);
3502: #endif
3503: exception_debug (nr);
3504: MakeSR ();
3505:
3506: if (!regs.s) {
3507: regs.usp = m68k_areg (regs, 7);
3508: m68k_areg(regs, 7) = regs.m ? regs.msp : regs.isp;
3509: regs.s = 1;
3510: mmu_set_super (1);
3511: }
3512:
3513: #if 0
3514: if (nr < 24 || nr > 31) { // do not print debugging for interrupts
3515: write_log (_T("Exception_mmu030: Exception %i: %08x %08x %08x\n"),
3516: nr, currpc, oldpc, regs.mmu_fault_addr);
3517: }
3518: #endif
3519:
1.1.1.9 ! root 3520: newpc = x_get_long (regs.vbr + 4 * nr);
! 3521:
1.1.1.7 root 3522: #if 0
1.1.1.9 ! root 3523: write_log (_T("Exception %d -> %08x\n"), nr, newpc);
1.1.1.7 root 3524: #endif
3525:
3526: if (regs.m && interrupt) { /* M + Interrupt */
3527: Exception_build_stack_frame (oldpc, currpc, regs.mmu_ssw, nr, 0x0);
3528: MakeSR ();
3529: regs.m = 0;
3530: regs.msp = m68k_areg (regs, 7);
3531: m68k_areg (regs, 7) = regs.isp;
3532: Exception_build_stack_frame (oldpc, currpc, regs.mmu_ssw, nr, 0x1);
3533: } else if (nr == 2) {
3534: Exception_build_stack_frame (oldpc, currpc, regs.mmu_ssw, nr, 0xB);
3535: } else if (nr == 3) {
3536: regs.mmu_fault_addr = last_fault_for_exception_3;
3537: mmu030_state[0] = mmu030_state[1] = 0;
3538: mmu030_data_buffer = 0;
3539: 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 3540: } else {
! 3541: Exception_build_stack_frame_common(oldpc, currpc, regs.mmu_ssw, nr);
! 3542: }
! 3543:
1.1.1.7 root 3544: if (newpc & 1) {
3545: if (nr == 2 || nr == 3)
1.1.1.8 root 3546: cpu_halt (CPU_HALT_DOUBLE_FAULT);
1.1.1.7 root 3547: else
3548: exception3_read(regs.ir, newpc);
3549: return;
3550: }
3551: m68k_setpci (newpc);
3552: fill_prefetch ();
1.1.1.8 root 3553: exception_check_trace (nr);
1.1.1.7 root 3554: }
3555:
3556: // 68040/060 MMU
1.1.1.4 root 3557: static void Exception_mmu (int nr, uaecptr oldpc)
3558: {
3559: uae_u32 currpc = m68k_getpc (), newpc;
1.1.1.7 root 3560: int interrupt;
1.1.1.4 root 3561:
1.1.1.7 root 3562: interrupt = nr >= 24 && nr < 24 + 8;
3563:
1.1.1.9 ! root 3564: // exception vector fetch and exception stack frame
! 3565: // operations don't allocate new cachelines
! 3566: cache_default_data |= CACHE_DISABLE_ALLOCATE;
! 3567:
1.1.1.7 root 3568: #ifdef WINUAE_FOR_HATARI
3569: if (interrupt)
3570: nr = iack_cycle(nr);
3571: #endif
3572:
3573: #ifdef WINUAE_FOR_HATARI
3574: 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",
3575: 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);
3576: #endif
1.1.1.4 root 3577: exception_debug (nr);
3578: MakeSR ();
3579:
3580: if (!regs.s) {
3581: regs.usp = m68k_areg (regs, 7);
1.1.1.8 root 3582: if (currprefs.cpu_model >= 68020 && currprefs.cpu_model < 68060) {
1.1.1.4 root 3583: m68k_areg (regs, 7) = regs.m ? regs.msp : regs.isp;
1.1.1.7 root 3584: } else {
1.1.1.4 root 3585: m68k_areg (regs, 7) = regs.isp;
1.1.1.7 root 3586: }
1.1.1.4 root 3587: regs.s = 1;
3588: mmu_set_super (1);
3589: }
1.1.1.8 root 3590:
1.1.1.7 root 3591: newpc = x_get_long (regs.vbr + 4 * nr);
3592: #if 0
3593: write_log (_T("Exception %d: %08x -> %08x\n"), nr, currpc, newpc);
3594: #endif
1.1.1.5 root 3595:
1.1.1.7 root 3596: if (nr == 2) { // bus error
3597: //write_log (_T("Exception_mmu %08x %08x %08x\n"), currpc, oldpc, regs.mmu_fault_addr);
3598: if (currprefs.mmu_model == 68040)
3599: Exception_build_stack_frame(oldpc, currpc, regs.mmu_ssw, nr, 0x7);
3600: else
1.1.1.9 ! root 3601: Exception_build_stack_frame(regs.mmu_fault_addr, currpc, regs.mmu_fslw, nr, 0x4);
1.1.1.7 root 3602: } else if (nr == 3) { // address error
3603: Exception_build_stack_frame(last_fault_for_exception_3, currpc, 0, nr, 0x2);
3604: write_log (_T("Exception %d (%x) at %x -> %x!\n"), nr, last_fault_for_exception_3, currpc, get_long_debug (regs.vbr + 4 * nr));
3605: } else if (regs.m && interrupt) { /* M + Interrupt */
1.1.1.8 root 3606: Exception_build_stack_frame(oldpc, currpc, regs.mmu_ssw, nr, 0x0);
3607: MakeSR();
3608: regs.m = 0;
3609: if (currprefs.cpu_model < 68060) {
3610: regs.msp = m68k_areg(regs, 7);
3611: Exception_build_stack_frame(oldpc, currpc, regs.mmu_ssw, nr, 0x1);
3612: }
1.1.1.4 root 3613: } else {
1.1.1.9 ! root 3614: Exception_build_stack_frame_common(oldpc, currpc, regs.mmu_ssw, nr);
1.1.1.4 root 3615: }
1.1.1.7 root 3616:
1.1.1.4 root 3617: if (newpc & 1) {
3618: if (nr == 2 || nr == 3)
1.1.1.8 root 3619: cpu_halt (CPU_HALT_DOUBLE_FAULT);
1.1.1.4 root 3620: else
1.1.1.7 root 3621: exception3_read(regs.ir, newpc);
1.1.1.4 root 3622: return;
3623: }
1.1.1.9 ! root 3624:
! 3625: cache_default_data &= ~CACHE_DISABLE_ALLOCATE;
! 3626:
1.1.1.7 root 3627: m68k_setpci (newpc);
3628: fill_prefetch ();
1.1.1.8 root 3629: exception_check_trace (nr);
1.1.1.4 root 3630: }
3631:
1.1.1.7 root 3632: static void add_approximate_exception_cycles(int nr)
1.1.1.4 root 3633: {
1.1.1.7 root 3634: int cycles;
3635:
3636: if (currprefs.cpu_model > 68000)
3637: return;
3638: #ifndef WINUAE_FOR_HATARI
3639: if (nr >= 24 && nr <= 31) {
3640: /* Interrupts */
3641: cycles = 44 + 4;
3642: #else
3643: if ( nr >= 24 && nr <= 31 ) {
1.1.1.8 root 3644: /* Atari's specific interrupts take 56 cycles instead of 44 due to iack sequence */
3645: /* We must subtract CPU_IACK_CYCLES_START cycles already counted into iack_cycle() */
1.1.1.7 root 3646: if ( nr == 30 ) /* MFP/DSP */
1.1.1.8 root 3647: cycles = 44-CPU_IACK_CYCLES_START;
1.1.1.7 root 3648: else if ( nr == 28 ) /* VBL */
1.1.1.8 root 3649: cycles = 44-CPU_IACK_CYCLES_START;
1.1.1.7 root 3650: else if ( nr == 26 ) /* HBL */
1.1.1.8 root 3651: cycles = 44-CPU_IACK_CYCLES_START;
1.1.1.7 root 3652: else
1.1.1.8 root 3653: cycles = 44+4; /* Other interrupts (not used in Atari machines) */
1.1.1.7 root 3654: #endif
3655: } else if (nr >= 32 && nr <= 47) {
3656: /* Trap (total is 34, but cpuemux.c already adds 4) */
3657: cycles = 34 -4;
3658: } else {
3659: switch (nr)
3660: {
3661: case 2: cycles = 50; break; /* Bus error */
3662: case 3: cycles = 50; break; /* Address error */
3663: case 4: cycles = 34; break; /* Illegal instruction */
3664: case 5: cycles = 38; break; /* Division by zero */
3665: case 6: cycles = 40; break; /* CHK */
3666: case 7: cycles = 34; break; /* TRAPV */
3667: case 8: cycles = 34; break; /* Privilege violation */
3668: case 9: cycles = 34; break; /* Trace */
3669: case 10: cycles = 34; break; /* Line-A */
3670: case 11: cycles = 34; break; /* Line-F */
3671: default:
3672: cycles = 4;
3673: break;
3674: }
3675: }
3676: #ifdef WINUAE_FOR_HATARI
3677: M68000_AddCycles ( cycles );
3678: #endif
3679: cycles = adjust_cycles(cycles * CYCLE_UNIT / 2);
3680: x_do_cycles(cycles);
3681: }
3682:
3683: static void Exception_normal (int nr)
3684: {
1.1.1.9 ! root 3685: uae_u32 newpc;
! 3686: uae_u32 currpc = m68k_getpc();
! 3687: uae_u32 nextpc;
1.1.1.4 root 3688: int sv = regs.s;
1.1.1.7 root 3689: int interrupt;
3690: int vector_nr = nr;
3691:
1.1.1.9 ! root 3692: cache_default_data |= CACHE_DISABLE_ALLOCATE;
! 3693:
1.1.1.7 root 3694: interrupt = nr >= 24 && nr < 24 + 8;
1.1.1.4 root 3695:
1.1.1.7 root 3696: #ifndef WINUAE_FOR_HATARI
3697: if (interrupt && currprefs.cpu_model <= 68010)
3698: #else
3699: if (interrupt)
1.1.1.4 root 3700: #endif
1.1.1.7 root 3701: vector_nr = iack_cycle(nr);
1.1.1.4 root 3702:
3703: exception_debug (nr);
3704: MakeSR ();
3705:
3706: if (!regs.s) {
3707: regs.usp = m68k_areg (regs, 7);
1.1.1.8 root 3708: if (currprefs.cpu_model >= 68020 && currprefs.cpu_model < 68060) {
1.1.1.4 root 3709: m68k_areg (regs, 7) = regs.m ? regs.msp : regs.isp;
1.1.1.7 root 3710: } else {
1.1.1.4 root 3711: m68k_areg (regs, 7) = regs.isp;
1.1.1.7 root 3712: }
1.1.1.4 root 3713: regs.s = 1;
3714: if (currprefs.mmu_model)
3715: mmu_set_super (regs.s != 0);
3716: }
1.1.1.7 root 3717:
1.1.1.8 root 3718: if ((m68k_areg(regs, 7) & 1) && currprefs.cpu_model < 68020) {
1.1.1.7 root 3719: if (nr == 2 || nr == 3)
1.1.1.8 root 3720: cpu_halt (CPU_HALT_DOUBLE_FAULT);
1.1.1.7 root 3721: else
3722: exception3_notinstruction(regs.ir, m68k_areg(regs, 7));
3723: return;
3724: }
3725: if ((nr == 2 || nr == 3) && exception_in_exception < 0) {
1.1.1.8 root 3726: cpu_halt (CPU_HALT_DOUBLE_FAULT);
1.1.1.7 root 3727: return;
3728: }
3729:
1.1.1.8 root 3730: #ifndef WINUAE_FOR_HATARI
3731: if (!currprefs.cpu_compatible) {
3732: addrbank *ab = &get_mem_bank(m68k_areg(regs, 7) - 4);
3733: // Not plain RAM check because some CPU type tests that
3734: // don't need to return set stack to ROM..
3735: if (!ab || ab == &dummy_bank || (ab->flags & ABFLAG_IO)) {
3736: cpu_halt(CPU_HALT_SSP_IN_NON_EXISTING_ADDRESS);
3737: return;
3738: }
3739: }
3740: #endif
3741:
1.1.1.9 ! root 3742: bool used_exception_build_stack_frame = false;
! 3743:
1.1.1.7 root 3744: if (currprefs.cpu_model > 68000) {
1.1.1.9 ! root 3745: uae_u32 oldpc = regs.instruction_pc;
! 3746: nextpc = exception_pc (nr);
1.1.1.7 root 3747: #ifdef WINUAE_FOR_HATARI
3748: 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",
3749: 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);
3750: #endif
3751: if (nr == 2 || nr == 3) {
3752: int i;
1.1.1.4 root 3753: if (currprefs.cpu_model >= 68040) {
3754: if (nr == 2) {
3755: if (currprefs.mmu_model) {
1.1.1.7 root 3756: // 68040 mmu bus error
1.1.1.4 root 3757: for (i = 0 ; i < 7 ; i++) {
3758: m68k_areg (regs, 7) -= 4;
3759: x_put_long (m68k_areg (regs, 7), 0);
3760: }
3761: m68k_areg (regs, 7) -= 4;
3762: x_put_long (m68k_areg (regs, 7), regs.wb3_data);
3763: m68k_areg (regs, 7) -= 4;
3764: x_put_long (m68k_areg (regs, 7), regs.mmu_fault_addr);
3765: m68k_areg (regs, 7) -= 4;
3766: x_put_long (m68k_areg (regs, 7), regs.mmu_fault_addr);
3767: m68k_areg (regs, 7) -= 2;
3768: x_put_word (m68k_areg (regs, 7), 0);
3769: m68k_areg (regs, 7) -= 2;
3770: x_put_word (m68k_areg (regs, 7), 0);
3771: m68k_areg (regs, 7) -= 2;
3772: x_put_word (m68k_areg (regs, 7), regs.wb3_status);
3773: regs.wb3_status = 0;
3774: m68k_areg (regs, 7) -= 2;
3775: x_put_word (m68k_areg (regs, 7), regs.mmu_ssw);
3776: m68k_areg (regs, 7) -= 4;
3777: x_put_long (m68k_areg (regs, 7), regs.mmu_fault_addr);
3778:
3779: m68k_areg (regs, 7) -= 2;
1.1.1.7 root 3780: x_put_word (m68k_areg (regs, 7), 0x7000 + vector_nr * 4);
1.1.1.4 root 3781: m68k_areg (regs, 7) -= 4;
1.1.1.7 root 3782: x_put_long (m68k_areg (regs, 7), regs.instruction_pc);
1.1.1.4 root 3783: m68k_areg (regs, 7) -= 2;
3784: x_put_word (m68k_areg (regs, 7), regs.sr);
1.1.1.7 root 3785: newpc = x_get_long (regs.vbr + 4 * vector_nr);
1.1.1.4 root 3786: if (newpc & 1) {
3787: if (nr == 2 || nr == 3)
1.1.1.8 root 3788: cpu_halt (CPU_HALT_DOUBLE_FAULT);
1.1.1.4 root 3789: else
1.1.1.7 root 3790: exception3_read(regs.ir, newpc);
1.1.1.4 root 3791: return;
3792: }
3793: m68k_setpc (newpc);
3794: #ifdef JIT
3795: set_special (SPCFLAG_END_COMPILE);
3796: #endif
1.1.1.8 root 3797: exception_check_trace (nr);
1.1.1.4 root 3798: return;
3799:
3800: } else {
3801:
1.1.1.7 root 3802: // 68040 bus error (not really, some garbage?)
1.1.1.4 root 3803: for (i = 0 ; i < 18 ; i++) {
3804: m68k_areg (regs, 7) -= 2;
3805: x_put_word (m68k_areg (regs, 7), 0);
3806: }
3807: m68k_areg (regs, 7) -= 4;
3808: x_put_long (m68k_areg (regs, 7), last_fault_for_exception_3);
3809: m68k_areg (regs, 7) -= 2;
3810: x_put_word (m68k_areg (regs, 7), 0);
3811: m68k_areg (regs, 7) -= 2;
3812: x_put_word (m68k_areg (regs, 7), 0);
3813: m68k_areg (regs, 7) -= 2;
3814: x_put_word (m68k_areg (regs, 7), 0);
3815: m68k_areg (regs, 7) -= 2;
3816: x_put_word (m68k_areg (regs, 7), 0x0140 | (sv ? 6 : 2)); /* SSW */
3817: m68k_areg (regs, 7) -= 4;
3818: x_put_long (m68k_areg (regs, 7), last_addr_for_exception_3);
3819: m68k_areg (regs, 7) -= 2;
1.1.1.7 root 3820: x_put_word (m68k_areg (regs, 7), 0x7000 + vector_nr * 4);
1.1.1.4 root 3821: m68k_areg (regs, 7) -= 4;
1.1.1.7 root 3822: x_put_long (m68k_areg (regs, 7), regs.instruction_pc);
1.1.1.4 root 3823: m68k_areg (regs, 7) -= 2;
3824: x_put_word (m68k_areg (regs, 7), regs.sr);
3825: goto kludge_me_do;
3826:
3827: }
3828:
3829: } else {
3830: m68k_areg (regs, 7) -= 4;
3831: x_put_long (m68k_areg (regs, 7), last_fault_for_exception_3);
3832: m68k_areg (regs, 7) -= 2;
1.1.1.7 root 3833: x_put_word (m68k_areg (regs, 7), 0x2000 + vector_nr * 4);
1.1.1.4 root 3834: }
3835: } else {
1.1.1.7 root 3836: // 68020 address error
1.1.1.4 root 3837: uae_u16 ssw = (sv ? 4 : 0) | (last_instructionaccess_for_exception_3 ? 2 : 1);
3838: ssw |= last_writeaccess_for_exception_3 ? 0 : 0x40;
3839: ssw |= 0x20;
3840: for (i = 0 ; i < 36; i++) {
3841: m68k_areg (regs, 7) -= 2;
3842: x_put_word (m68k_areg (regs, 7), 0);
3843: }
3844: m68k_areg (regs, 7) -= 4;
3845: x_put_long (m68k_areg (regs, 7), last_fault_for_exception_3);
3846: m68k_areg (regs, 7) -= 2;
3847: x_put_word (m68k_areg (regs, 7), 0);
3848: m68k_areg (regs, 7) -= 2;
3849: x_put_word (m68k_areg (regs, 7), 0);
3850: m68k_areg (regs, 7) -= 2;
3851: x_put_word (m68k_areg (regs, 7), 0);
3852: m68k_areg (regs, 7) -= 2;
3853: x_put_word (m68k_areg (regs, 7), ssw);
3854: m68k_areg (regs, 7) -= 2;
1.1.1.7 root 3855: x_put_word (m68k_areg (regs, 7), 0xb000 + vector_nr * 4);
1.1.1.4 root 3856: }
1.1.1.7 root 3857: write_log (_T("Exception %d (%x) at %x -> %x!\n"), nr, regs.instruction_pc, currpc, get_long_debug (regs.vbr + 4 * vector_nr));
3858: } else if (regs.m && interrupt) { /* M + Interrupt */
1.1.1.4 root 3859: m68k_areg (regs, 7) -= 2;
1.1.1.7 root 3860: x_put_word (m68k_areg (regs, 7), vector_nr * 4);
1.1.1.8 root 3861: if (currprefs.cpu_model < 68060) {
3862: m68k_areg (regs, 7) -= 4;
3863: x_put_long (m68k_areg (regs, 7), currpc);
3864: m68k_areg (regs, 7) -= 2;
3865: x_put_word (m68k_areg (regs, 7), regs.sr);
3866: regs.sr |= (1 << 13);
3867: regs.msp = m68k_areg(regs, 7);
3868: regs.m = 0;
3869: m68k_areg(regs, 7) = regs.isp;
3870: m68k_areg (regs, 7) -= 2;
3871: x_put_word (m68k_areg (regs, 7), 0x1000 + vector_nr * 4);
3872: }
1.1.1.4 root 3873: } else {
1.1.1.9 ! root 3874: Exception_build_stack_frame_common(oldpc, currpc, regs.mmu_ssw, nr);
! 3875: used_exception_build_stack_frame = true;
1.1.1.7 root 3876: }
1.1.1.9 ! root 3877: } else {
1.1.1.7 root 3878: add_approximate_exception_cycles(nr);
1.1.1.9 ! root 3879: nextpc = m68k_getpc ();
1.1.1.7 root 3880: #ifdef WINUAE_FOR_HATARI
3881: 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",
3882: 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);
3883: #endif
3884: if (nr == 2 || nr == 3) {
3885: // 68000 address error
3886: uae_u16 mode = (sv ? 4 : 0) | (last_instructionaccess_for_exception_3 ? 2 : 1);
3887: mode |= last_writeaccess_for_exception_3 ? 0 : 16;
3888: mode |= last_notinstruction_for_exception_3 ? 8 : 0;
3889: // undocumented bits seem to contain opcode
3890: mode |= last_op_for_exception_3 & ~31;
3891: m68k_areg (regs, 7) -= 14;
3892: exception_in_exception = -1;
3893: x_put_word (m68k_areg (regs, 7) + 0, mode);
3894: x_put_long (m68k_areg (regs, 7) + 2, last_fault_for_exception_3);
3895: x_put_word (m68k_areg (regs, 7) + 6, last_op_for_exception_3);
3896: x_put_word (m68k_areg (regs, 7) + 8, regs.sr);
3897: x_put_long (m68k_areg (regs, 7) + 10, last_addr_for_exception_3);
1.1.1.8 root 3898: #ifndef WINUAE_FOR_HATARI
1.1.1.7 root 3899: 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 3900: #else
3901: if (nr != 2 || last_fault_for_exception_3 != 0xff8a00 || currpc < TosAddress || currpc > TosAddress + TosSize)
3902: fprintf(stderr,"%s Error at address $%x, PC=$%x addr_e3=%x op_e3=%x\n", nr==2?"Bus":"Address",
3903: last_fault_for_exception_3, currpc, last_addr_for_exception_3 , last_op_for_exception_3);
1.1.1.7 root 3904: #endif
3905: goto kludge_me_do;
1.1.1.4 root 3906: }
3907: }
1.1.1.9 ! root 3908: if (!used_exception_build_stack_frame) {
! 3909: m68k_areg (regs, 7) -= 4;
! 3910: x_put_long (m68k_areg (regs, 7), nextpc);
! 3911: m68k_areg (regs, 7) -= 2;
! 3912: x_put_word (m68k_areg (regs, 7), regs.sr);
! 3913: }
1.1.1.8 root 3914: if (currprefs.cpu_model == 68060 && interrupt) {
3915: regs.m = 0;
3916: }
1.1.1.4 root 3917: kludge_me_do:
1.1.1.7 root 3918: newpc = x_get_long (regs.vbr + 4 * vector_nr);
3919: exception_in_exception = 0;
1.1.1.4 root 3920: if (newpc & 1) {
3921: if (nr == 2 || nr == 3)
1.1.1.8 root 3922: cpu_halt (CPU_HALT_DOUBLE_FAULT);
1.1.1.4 root 3923: else
1.1.1.7 root 3924: exception3_notinstruction(regs.ir, newpc);
1.1.1.4 root 3925: return;
3926: }
3927: m68k_setpc (newpc);
1.1.1.9 ! root 3928: cache_default_data &= ~CACHE_DISABLE_ALLOCATE;
1.1.1.8 root 3929: #ifdef WINUAE_FOR_HATARI
3930: /* Update IPL / interrupts state, in case a new interrupt happened during this exception */
3931: while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) )
3932: CALL_VAR(PendingInterruptFunction);
3933: #endif
1.1.1.4 root 3934: #ifdef JIT
3935: set_special (SPCFLAG_END_COMPILE);
3936: #endif
1.1.1.7 root 3937: fill_prefetch ();
1.1.1.8 root 3938: exception_check_trace (nr);
1.1.1.4 root 3939: }
3940:
1.1.1.7 root 3941: // address = format $2 stack frame address field
3942: static void ExceptionX (int nr, uaecptr address)
1.1.1.4 root 3943: {
1.1.1.7 root 3944: regs.exception = nr;
3945: if (cpu_tracer) {
3946: cputrace.state = nr;
1.1.1.6 root 3947: }
3948:
1.1.1.8 root 3949: #ifdef WINUAE_FOR_HATARI
3950: /* Handle Hatari GEM and BIOS traps */
3951: if (nr == 0x22) {
3952: /* Intercept VDI & AES exceptions (Trap #2) */
3953: if (bVdiAesIntercept && VDI_AES_Entry()) {
3954: /* Set 'PC' to address of 'VDI_OPCODE' illegal instruction.
3955: * This will call OpCode_VDI() after completion of Trap call!
3956: * Used to modify specific VDI return vectors contents. */
3957: VDI_OldPC = m68k_getpc();
3958: m68k_setpc(CART_VDI_OPCODE_ADDR);
3959: }
3960: }
3961: else if (nr == 0x2d) {
3962: /* Intercept BIOS (Trap #13) calls */
3963: if (Bios()) {
3964: fill_prefetch ();
3965: regs.exception = 0;
3966: return;
3967: }
3968: }
3969: else if (nr == 0x2e) {
3970: /* Intercept XBIOS (Trap #14) calls */
3971: if (XBios()) {
3972: fill_prefetch ();
3973: regs.exception = 0;
3974: return;
3975: }
3976: }
3977: #endif
3978:
1.1.1.7 root 3979: #ifdef JIT
3980: if (currprefs.cachesize)
3981: regs.instruction_pc = address == -1 ? m68k_getpc () : address;
3982: #endif
3983: #ifdef CPUEMU_13
3984: if (currprefs.cpu_cycle_exact && currprefs.cpu_model <= 68010)
3985: Exception_ce000 (nr);
1.1.1.4 root 3986: else
3987: #endif
1.1.1.7 root 3988: if (currprefs.mmu_model) {
3989: if (currprefs.cpu_model == 68030)
3990: Exception_mmu030 (nr, m68k_getpc ());
3991: else
3992: Exception_mmu (nr, m68k_getpc ());
3993: } else {
3994: Exception_normal (nr);
3995: }
1.1.1.4 root 3996:
1.1.1.7 root 3997: #ifndef WINUAE_FOR_HATARI
1.1.1.4 root 3998: if (debug_illegal && !in_rom (M68K_GETPC)) {
3999: if (nr <= 63 && (debug_illegal_mask & ((uae_u64)1 << nr))) {
1.1.1.7 root 4000: write_log (_T("Exception %d breakpoint\n"), nr);
1.1.1.4 root 4001: activate_debugger ();
4002: }
4003: }
4004: #endif
1.1.1.7 root 4005: regs.exception = 0;
4006: if (cpu_tracer) {
4007: cputrace.state = 0;
4008: }
4009: }
4010:
1.1.1.9 ! root 4011: void REGPARAM2 Exception_cpu(int nr)
! 4012: {
! 4013: bool t0 = currprefs.cpu_model >= 68020 && regs.t0;
! 4014: ExceptionX (nr, -1);
! 4015: // check T0 trace
! 4016: if (t0) {
! 4017: activate_trace();
! 4018: }
! 4019: }
1.1.1.7 root 4020: void REGPARAM2 Exception (int nr)
4021: {
4022: ExceptionX (nr, -1);
4023: }
4024: void REGPARAM2 ExceptionL (int nr, uaecptr address)
4025: {
4026: ExceptionX (nr, address);
1.1.1.4 root 4027: }
4028:
1.1.1.9 ! root 4029: static void bus_error(void)
! 4030: {
! 4031: TRY (prb2) {
! 4032: Exception (2);
! 4033: } CATCH (prb2) {
! 4034: cpu_halt (CPU_HALT_BUS_ERROR_DOUBLE_FAULT);
! 4035: } ENDTRY
! 4036: }
! 4037:
1.1.1.7 root 4038: static void do_interrupt (int nr)
1.1.1.4 root 4039: {
1.1.1.7 root 4040: #ifndef WINUAE_FOR_HATARI
1.1.1.4 root 4041: if (debug_dma)
4042: record_dma_event (DMA_EVENT_CPUIRQ, current_hpos (), vpos);
1.1.1.7 root 4043:
4044: if (inputrecord_debug & 2) {
4045: if (input_record > 0)
4046: inprec_recorddebug_cpu (2);
4047: else if (input_play > 0)
4048: inprec_playdebug_cpu (2);
4049: }
1.1.1.4 root 4050: #endif
4051:
1.1.1.8 root 4052: m68k_unset_stop();
1.1.1.4 root 4053: assert (nr < 8 && nr >= 0);
4054:
1.1.1.8 root 4055: for (;;) {
4056: Exception (nr + 24);
4057: regs.intmask = nr;
4058: if (!currprefs.cpu_compatible || currprefs.cpu_model == 68060)
4059: break;
4060: if (m68k_interrupt_delay)
4061: nr = regs.ipl;
4062: else
4063: nr = intlev();
4064: if (nr <= 0 || regs.intmask >= nr)
4065: break;
4066: }
1.1.1.4 root 4067:
4068: doint ();
4069: }
4070:
4071: void NMI (void)
4072: {
1.1.1.7 root 4073: do_interrupt (7);
1.1.1.4 root 4074: }
4075:
1.1.1.7 root 4076: static void m68k_reset_sr(void)
1.1.1.4 root 4077: {
1.1.1.7 root 4078: SET_XFLG ((regs.sr >> 4) & 1);
4079: SET_NFLG ((regs.sr >> 3) & 1);
4080: SET_ZFLG ((regs.sr >> 2) & 1);
4081: SET_VFLG ((regs.sr >> 1) & 1);
4082: SET_CFLG (regs.sr & 1);
4083: regs.t1 = (regs.sr >> 15) & 1;
4084: regs.t0 = (regs.sr >> 14) & 1;
4085: regs.s = (regs.sr >> 13) & 1;
4086: regs.m = (regs.sr >> 12) & 1;
4087: regs.intmask = (regs.sr >> 8) & 7;
4088: /* set stack pointer */
4089: if (regs.s)
4090: m68k_areg (regs, 7) = regs.isp;
4091: else
4092: m68k_areg (regs, 7) = regs.usp;
1.1.1.4 root 4093: }
4094:
1.1.1.7 root 4095: static void m68k_reset2(bool hardreset)
1.1.1.4 root 4096: {
1.1.1.7 root 4097: uae_u32 v;
1.1.1.4 root 4098:
1.1.1.7 root 4099: regs.halted = 0;
4100: #ifndef WINUAE_FOR_HATARI
4101: gui_data.cpu_halted = 0;
4102: gui_led (LED_CPU, 0, -1);
1.1.1.4 root 4103: #endif
4104:
1.1.1.7 root 4105: regs.spcflags = 0;
4106: m68k_reset_delay = 0;
4107: regs.ipl = regs.ipl_pin = 0;
1.1.1.4 root 4108:
1.1.1.7 root 4109: #ifdef SAVESTATE
4110: if (isrestore ()) {
4111: m68k_reset_sr();
4112: m68k_setpc_normal (regs.pc);
1.1.1.4 root 4113: return;
4114: } else {
1.1.1.7 root 4115: m68k_reset_delay = currprefs.reset_delay;
4116: set_special(SPCFLAG_CHECK);
1.1.1.4 root 4117: }
4118: #endif
1.1.1.7 root 4119: regs.s = 1;
4120: #ifndef WINUAE_FOR_HATARI
4121: if (currprefs.cpuboard_type) {
1.1.1.8 root 4122: uaecptr stack;
1.1.1.7 root 4123: v = cpuboard_get_reset_pc(&stack);
4124: m68k_areg (regs, 7) = stack;
1.1.1.4 root 4125: } else {
1.1.1.7 root 4126: v = get_long (4);
4127: m68k_areg (regs, 7) = get_long (0);
1.1.1.8 root 4128: }
1.1.1.4 root 4129: #else
1.1.1.7 root 4130: v = get_long (4);
4131: m68k_areg (regs, 7) = get_long (0);
1.1.1.4 root 4132: #endif
1.1.1.8 root 4133:
1.1.1.7 root 4134: m68k_setpc_normal(v);
1.1.1.4 root 4135: regs.m = 0;
4136: regs.stopped = 0;
4137: regs.t1 = 0;
4138: regs.t0 = 0;
4139: SET_ZFLG (0);
4140: SET_XFLG (0);
4141: SET_CFLG (0);
4142: SET_VFLG (0);
4143: SET_NFLG (0);
4144: regs.intmask = 7;
4145: regs.vbr = regs.sfc = regs.dfc = 0;
4146: regs.irc = 0xffff;
4147: #ifdef FPUEMU
4148: fpu_reset ();
4149: #endif
4150: regs.caar = regs.cacr = 0;
4151: regs.itt0 = regs.itt1 = regs.dtt0 = regs.dtt1 = 0;
4152: regs.tcr = regs.mmusr = regs.urp = regs.srp = regs.buscr = 0;
1.1.1.7 root 4153: mmu_tt_modified ();
1.1.1.4 root 4154: if (currprefs.cpu_model == 68020) {
4155: regs.cacr |= 8;
1.1.1.7 root 4156: set_cpu_caches (false);
1.1.1.4 root 4157: }
4158:
4159: mmufixup[0].reg = -1;
4160: mmufixup[1].reg = -1;
1.1.1.9 ! root 4161: mmu030_cache_state = CACHE_ENABLE_ALL;
! 4162: mmu_cache_state = CACHE_ENABLE_ALL;
! 4163: if (currprefs.cpu_model >= 68040) {
! 4164: set_cpu_caches(false);
! 4165: }
1.1.1.7 root 4166: if (currprefs.mmu_model >= 68040) {
4167: mmu_reset ();
4168: mmu_set_tc (regs.tcr);
4169: mmu_set_super (regs.s != 0);
4170: } else if (currprefs.mmu_model == 68030) {
4171: mmu030_reset (hardreset || regs.halted);
4172: } else {
4173: #ifndef WINUAE_FOR_HATARI
4174: a3000_fakekick (0);
4175: #endif
4176: /* only (E)nable bit is zeroed when CPU is reset, A3000 SuperKickstart expects this */
4177: fake_tc_030 &= ~0x80000000;
4178: fake_tt0_030 &= ~0x80000000;
4179: fake_tt1_030 &= ~0x80000000;
4180: if (hardreset || regs.halted) {
4181: fake_srp_030 = fake_crp_030 = 0;
4182: fake_tt0_030 = fake_tt1_030 = fake_tc_030 = 0;
1.1.1.5 root 4183: }
1.1.1.7 root 4184: fake_mmusr_030 = 0;
1.1.1.4 root 4185: }
4186:
4187: /* 68060 FPU is not compatible with 68040,
4188: * 68060 accelerators' boot ROM disables the FPU
4189: */
4190: regs.pcr = 0;
4191: if (currprefs.cpu_model == 68060) {
4192: regs.pcr = currprefs.fpu_model == 68060 ? MC68060_PCR : MC68EC060_PCR;
4193: regs.pcr |= (currprefs.cpu060_revision & 0xff) << 8;
1.1.1.7 root 4194: #ifndef WINUAE_FOR_HATARI
1.1.1.9 ! root 4195: if (currprefs.fpu_model == 0 || kickstart_rom)
1.1.1.7 root 4196: regs.pcr |= 2; /* disable FPU */
4197: #endif
4198: }
1.1.1.9 ! root 4199: // regs.ce020memcycles = 0;
! 4200: regs.ce020startcycle = regs.ce020endcycle = 0;
1.1.1.7 root 4201: fill_prefetch ();
4202: }
1.1.1.8 root 4203:
1.1.1.7 root 4204: void m68k_reset(void)
4205: {
4206: m68k_reset2(false);
4207: }
4208:
1.1.1.8 root 4209: #ifndef WINUAE_FOR_HATARI
4210: void cpu_change(int newmodel)
4211: {
4212: if (newmodel == currprefs.cpu_model)
4213: return;
4214: fallback_new_cpu_model = newmodel;
4215: cpu_halt(CPU_HALT_ACCELERATOR_CPU_FALLBACK);
4216: }
1.1.1.7 root 4217:
1.1.1.8 root 4218: void cpu_fallback(int mode)
1.1.1.7 root 4219: {
1.1.1.8 root 4220: int fallbackmodel;
4221: if (currprefs.chipset_mask & CSMASK_AGA) {
4222: fallbackmodel = 68020;
4223: } else {
4224: fallbackmodel = 68000;
4225: }
4226: if (mode < 0) {
4227: if (currprefs.cpu_model > fallbackmodel) {
4228: cpu_change(fallbackmodel);
4229: } else if (fallback_new_cpu_model) {
4230: cpu_change(fallback_new_cpu_model);
4231: }
4232: } else if (mode == 0) {
4233: cpu_change(fallbackmodel);
4234: } else if (mode) {
4235: if (fallback_cpu_model) {
4236: cpu_change(fallback_cpu_model);
4237: }
1.1.1.4 root 4238: }
1.1.1.8 root 4239: }
4240:
4241: static void cpu_do_fallback(void)
4242: {
4243: bool fallbackmode = false;
4244: if ((fallback_new_cpu_model < 68020 && !(currprefs.chipset_mask & CSMASK_AGA)) || (fallback_new_cpu_model == 68020 && (currprefs.chipset_mask & CSMASK_AGA))) {
4245: // -> 68000/68010 or 68EC020
4246: fallback_cpu_model = currprefs.cpu_model;
4247: fallback_fpu_model = currprefs.fpu_model;
4248: fallback_mmu_model = currprefs.mmu_model;
4249: fallback_cpu_compatible = currprefs.cpu_compatible;
4250: fallback_cpu_address_space_24 = currprefs.address_space_24;
4251: changed_prefs.cpu_model = currprefs.cpu_model_fallback && fallback_new_cpu_model <= 68020 ? currprefs.cpu_model_fallback : fallback_new_cpu_model;
4252: changed_prefs.fpu_model = 0;
4253: changed_prefs.mmu_model = 0;
4254: changed_prefs.cpu_compatible = true;
4255: changed_prefs.address_space_24 = true;
4256: memcpy(&fallback_regs, ®s, sizeof(struct regstruct));
4257: fallback_regs.pc = M68K_GETPC;
4258: fallbackmode = true;
4259: } else {
4260: // -> 68020+
4261: changed_prefs.cpu_model = fallback_cpu_model;
4262: changed_prefs.fpu_model = fallback_fpu_model;
4263: changed_prefs.mmu_model = fallback_mmu_model;
4264: changed_prefs.cpu_compatible = fallback_cpu_compatible;
4265: changed_prefs.address_space_24 = fallback_cpu_address_space_24;
4266: fallback_cpu_model = 0;
4267: }
4268: init_m68k();
4269: m68k_reset2(false);
4270: if (!fallbackmode) {
4271: // restore original 68020+
4272: memcpy(®s, &fallback_regs, sizeof(regs));
4273: restore_banks();
4274: memory_restore();
4275: memory_map_dump();
4276: m68k_setpc(fallback_regs.pc);
4277: } else {
1.1.1.9 ! root 4278: // 68000/010/EC020
1.1.1.8 root 4279: memory_restore();
4280: expansion_cpu_fallback();
4281: memory_map_dump();
4282: }
4283: }
4284:
4285: static void m68k_reset_restore(void)
4286: {
4287: // hardreset and 68000/68020 fallback mode? Restore original mode.
4288: if (fallback_cpu_model) {
4289: fallback_new_cpu_model = fallback_cpu_model;
4290: fallback_regs.pc = 0;
4291: cpu_do_fallback();
4292: }
4293: }
4294: #endif
4295:
4296: void REGPARAM2 op_unimpl (uae_u16 opcode)
4297: {
4298: static int warned;
4299: if (warned < 20) {
4300: write_log (_T("68060 unimplemented opcode %04X, PC=%08x\n"), opcode, regs.instruction_pc);
4301: warned++;
4302: }
4303: ExceptionL (61, regs.instruction_pc);
1.1.1.4 root 4304: }
4305:
1.1.1.7 root 4306: uae_u32 REGPARAM2 op_illg (uae_u32 opcode)
1.1.1.4 root 4307: {
4308: uaecptr pc = m68k_getpc ();
4309: static int warned;
4310:
1.1.1.7 root 4311: #ifndef WINUAE_FOR_HATARI
1.1.1.4 root 4312: int inrom = in_rom (pc);
4313: int inrt = in_rtarea (pc);
4314:
1.1.1.9 ! root 4315: if ((opcode == 0x4afc || opcode == 0xfc4a) && !valid_address(pc, 4) && valid_address(pc - 4, 4)) {
! 4316: // PC fell off the end of RAM
! 4317: bus_error();
! 4318: return 4;
! 4319: }
! 4320:
1.1.1.4 root 4321: if (cloanto_rom && (opcode & 0xF100) == 0x7100) {
4322: m68k_dreg (regs, (opcode >> 9) & 7) = (uae_s8)(opcode & 0xFF);
1.1.1.7 root 4323: m68k_incpc_normal (2);
4324: fill_prefetch ();
1.1.1.4 root 4325: return 4;
4326: }
4327:
1.1.1.7 root 4328: if (opcode == 0x4E7B && inrom) {
4329: if (get_long (0x10) == 0) {
4330: notify_user (NUMSG_KS68020);
4331: uae_restart (-1, NULL);
1.1.1.8 root 4332: m68k_setstopped();
4333: return 4;
1.1.1.7 root 4334: }
1.1.1.4 root 4335: }
4336:
4337: #ifdef AUTOCONFIG
1.1.1.7 root 4338: if (opcode == 0xFF0D && inrt) {
4339: /* User-mode STOP replacement */
4340: m68k_setstopped ();
4341: return 4;
1.1.1.4 root 4342: }
4343:
4344: if ((opcode & 0xF000) == 0xA000 && inrt) {
4345: /* Calltrap. */
1.1.1.7 root 4346: m68k_incpc_normal (2);
4347: m68k_handle_trap(opcode & 0xFFF);
4348: fill_prefetch ();
1.1.1.4 root 4349: return 4;
4350: }
4351: #endif
1.1.1.7 root 4352: #endif
1.1.1.4 root 4353:
4354: if ((opcode & 0xF000) == 0xF000) {
1.1.1.7 root 4355: #ifndef WINUAE_FOR_HATARI
1.1.1.4 root 4356: if (warned < 20) {
1.1.1.7 root 4357: write_log(_T("B-Trap %04X at %08X -> %08X\n"), opcode, pc, get_long_debug(regs.vbr + 0x2c));
1.1.1.4 root 4358: warned++;
4359: }
1.1.1.7 root 4360: #endif
4361: Exception (0xB);
1.1.1.4 root 4362: //activate_debugger ();
4363: return 4;
4364: }
4365: if ((opcode & 0xF000) == 0xA000) {
1.1.1.7 root 4366: #ifndef WINUAE_FOR_HATARI
1.1.1.4 root 4367: if (warned < 20) {
1.1.1.7 root 4368: write_log(_T("A-Trap %04X at %08X -> %08X\n"), opcode, pc, get_long_debug(regs.vbr + 0x28));
1.1.1.4 root 4369: warned++;
4370: }
1.1.1.7 root 4371: #endif
4372: Exception (0xA);
1.1.1.4 root 4373: //activate_debugger();
4374: return 4;
4375: }
4376: if (warned < 20) {
1.1.1.7 root 4377: write_log (_T("Illegal instruction: %04x at %08X -> %08X\n"), opcode, pc, get_long_debug(regs.vbr + 0x10));
1.1.1.4 root 4378: warned++;
4379: //activate_debugger();
4380: }
4381:
1.1.1.7 root 4382: Exception (4);
1.1.1.4 root 4383: return 4;
4384: }
4385:
4386: #ifdef CPUEMU_0
4387:
1.1.1.9 ! root 4388: static bool mmu_op30_invea(uae_u32 opcode)
1.1.1.4 root 4389: {
1.1.1.9 ! root 4390: int eamode = (opcode >> 3) & 7;
1.1.1.7 root 4391: int rreg = opcode & 7;
1.1.1.9 ! root 4392:
! 4393: // Dn, An, (An)+, -(An), immediate and PC-relative not allowed
! 4394: if (eamode == 0 || eamode == 1 || eamode == 3 || eamode == 4 || eamode == 6 || (eamode == 7 && rreg > 1))
! 4395: return true;
! 4396: return false;
! 4397: }
! 4398:
! 4399: static bool mmu_op30fake_pmove (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra)
! 4400: {
1.1.1.7 root 4401: int preg = (next >> 10) & 31;
4402: int rw = (next >> 9) & 1;
4403: int fd = (next >> 8) & 1;
1.1.1.9 ! root 4404: int unused = (next & 0xff);
1.1.1.7 root 4405: const TCHAR *reg = NULL;
1.1.1.8 root 4406: #ifndef WINUAE_FOR_HATARI
1.1.1.7 root 4407: uae_u32 otc = fake_tc_030;
1.1.1.8 root 4408: #endif
1.1.1.7 root 4409: int siz;
4410:
1.1.1.9 ! root 4411: if (mmu_op30_invea(opcode))
! 4412: return true;
! 4413: // unused low 8 bits must be zeroed
! 4414: if (unused)
! 4415: return true;
! 4416: // read and fd set?
! 4417: if (rw && fd)
1.1.1.7 root 4418: return true;
1.1.1.5 root 4419:
1.1.1.7 root 4420: switch (preg)
4421: {
4422: case 0x10: // TC
4423: reg = _T("TC");
4424: siz = 4;
4425: if (rw)
4426: x_put_long (extra, fake_tc_030);
4427: else
4428: fake_tc_030 = x_get_long (extra);
4429: break;
4430: case 0x12: // SRP
4431: reg = _T("SRP");
4432: siz = 8;
4433: if (rw) {
4434: x_put_long (extra, fake_srp_030 >> 32);
4435: x_put_long (extra + 4, (uae_u32)fake_srp_030);
4436: } else {
4437: fake_srp_030 = (uae_u64)x_get_long (extra) << 32;
4438: fake_srp_030 |= x_get_long (extra + 4);
4439: }
4440: break;
4441: case 0x13: // CRP
4442: reg = _T("CRP");
4443: siz = 8;
4444: if (rw) {
4445: x_put_long (extra, fake_crp_030 >> 32);
4446: x_put_long (extra + 4, (uae_u32)fake_crp_030);
4447: } else {
4448: fake_crp_030 = (uae_u64)x_get_long (extra) << 32;
4449: fake_crp_030 |= x_get_long (extra + 4);
4450: }
4451: break;
4452: case 0x18: // MMUSR
1.1.1.9 ! root 4453: if (fd) {
! 4454: // FD must be always zero when MMUSR read or write
! 4455: return true;
! 4456: }
1.1.1.7 root 4457: reg = _T("MMUSR");
4458: siz = 2;
4459: if (rw)
4460: x_put_word (extra, fake_mmusr_030);
4461: else
4462: fake_mmusr_030 = x_get_word (extra);
4463: break;
4464: case 0x02: // TT0
4465: reg = _T("TT0");
4466: siz = 4;
4467: if (rw)
4468: x_put_long (extra, fake_tt0_030);
4469: else
4470: fake_tt0_030 = x_get_long (extra);
4471: break;
4472: case 0x03: // TT1
4473: reg = _T("TT1");
4474: siz = 4;
4475: if (rw)
4476: x_put_long (extra, fake_tt1_030);
4477: else
4478: fake_tt1_030 = x_get_long (extra);
4479: break;
4480: }
1.1.1.4 root 4481:
1.1.1.9 ! root 4482: if (!reg)
1.1.1.7 root 4483: return true;
1.1.1.9 ! root 4484:
1.1.1.4 root 4485: #if MMUOP_DEBUG > 0
1.1.1.7 root 4486: {
4487: uae_u32 val;
4488: if (siz == 8) {
4489: uae_u32 val2 = x_get_long (extra);
4490: val = x_get_long (extra + 4);
4491: if (rw)
4492: write_log (_T("PMOVE %s,%08X%08X"), reg, val2, val);
4493: else
4494: write_log (_T("PMOVE %08X%08X,%s"), val2, val, reg);
4495: } else {
4496: if (siz == 4)
4497: val = x_get_long (extra);
4498: else
4499: val = x_get_word (extra);
4500: if (rw)
4501: write_log (_T("PMOVE %s,%08X"), reg, val);
4502: else
4503: write_log (_T("PMOVE %08X,%s"), val, reg);
1.1.1.4 root 4504: }
1.1.1.7 root 4505: write_log (_T(" PC=%08X\n"), pc);
4506: }
1.1.1.4 root 4507: #endif
1.1.1.7 root 4508: #ifndef WINUAE_FOR_HATARI
4509: if ((currprefs.cs_mbdmac & 1) && currprefs.mbresmem_low_size > 0) {
4510: if (otc != fake_tc_030) {
4511: a3000_fakekick (fake_tc_030 & 0x80000000);
1.1.1.4 root 4512: }
4513: }
4514: #endif
1.1.1.7 root 4515: return false;
1.1.1.4 root 4516: }
4517:
1.1.1.7 root 4518: static bool mmu_op30fake_ptest (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra)
4519: {
1.1.1.9 ! root 4520: int eamode = (opcode >> 3) & 7;
! 4521: int rreg = opcode & 7;
! 4522: int level = (next&0x1C00)>>10;
! 4523: int a = (next >> 8) & 1;
! 4524:
! 4525: if (mmu_op30_invea(opcode))
! 4526: return true;
! 4527: if (!level && a)
! 4528: return true;
! 4529:
1.1.1.7 root 4530: #if MMUOP_DEBUG > 0
4531: TCHAR tmp[10];
4532:
4533: tmp[0] = 0;
4534: if ((next >> 8) & 1)
4535: _stprintf (tmp, _T(",A%d"), (next >> 4) & 15);
4536: write_log (_T("PTEST%c %02X,%08X,#%X%s PC=%08X\n"),
4537: ((next >> 9) & 1) ? 'W' : 'R', (next & 15), extra, (next >> 10) & 7, tmp, pc);
1.1.1.4 root 4538: #endif
1.1.1.7 root 4539: fake_mmusr_030 = 0;
4540: return false;
4541: }
1.1.1.4 root 4542:
1.1.1.9 ! root 4543: static bool mmu_op30fake_pload (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra)
! 4544: {
! 4545: int unused = (next & (0x100 | 0x80 | 0x40 | 0x20));
! 4546:
! 4547: if (mmu_op30_invea(opcode))
! 4548: return true;
! 4549: if (unused)
! 4550: return true;
! 4551: write_log(_T("PLOAD\n"));
! 4552: return false;
! 4553: }
! 4554:
1.1.1.7 root 4555: static bool mmu_op30fake_pflush (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra)
4556: {
1.1.1.9 ! root 4557: int flushmode = (next >> 8) & 31;
1.1.1.7 root 4558: int fc = next & 31;
4559: int mask = (next >> 5) & 3;
1.1.1.9 ! root 4560: int fc_bits = next & 0x7f;
1.1.1.7 root 4561: TCHAR fname[100];
4562:
4563: switch (flushmode)
4564: {
1.1.1.9 ! root 4565: case 0x00:
! 4566: return mmu_op30fake_pload(pc, opcode, next, extra);
! 4567: case 0x18:
! 4568: if (mmu_op30_invea(opcode))
1.1.1.7 root 4569: return true;
4570: _stprintf (fname, _T("FC=%x MASK=%x EA=%08x"), fc, mask, 0);
4571: break;
1.1.1.9 ! root 4572: case 0x10:
1.1.1.7 root 4573: _stprintf (fname, _T("FC=%x MASK=%x"), fc, mask);
4574: break;
1.1.1.9 ! root 4575: case 0x04:
! 4576: if (fc_bits)
! 4577: return true;
1.1.1.7 root 4578: _tcscpy (fname, _T("ALL"));
4579: break;
4580: default:
4581: return true;
4582: }
4583: #if MMUOP_DEBUG > 0
4584: write_log (_T("PFLUSH %s PC=%08X\n"), fname, pc);
4585: #endif
4586: return false;
4587: }
4588:
4589: // 68030 (68851) MMU instructions only
4590: bool mmu_op30 (uaecptr pc, uae_u32 opcode, uae_u16 extra, uaecptr extraa)
4591: {
4592: int type = extra >> 13;
1.1.1.9 ! root 4593: bool fline = false;
1.1.1.7 root 4594:
4595: switch (type)
4596: {
4597: case 0:
4598: case 2:
4599: case 3:
1.1.1.9 ! root 4600: if (currprefs.mmu_model)
! 4601: fline = mmu_op30_pmove (pc, opcode, extra, extraa);
! 4602: else
! 4603: fline = mmu_op30fake_pmove (pc, opcode, extra, extraa);
1.1.1.7 root 4604: break;
4605: case 1:
1.1.1.9 ! root 4606: if (currprefs.mmu_model)
! 4607: fline = mmu_op30_pflush (pc, opcode, extra, extraa);
! 4608: else
! 4609: fline = mmu_op30fake_pflush (pc, opcode, extra, extraa);
1.1.1.7 root 4610: break;
4611: case 4:
1.1.1.9 ! root 4612: if (currprefs.mmu_model)
! 4613: fline = mmu_op30_ptest (pc, opcode, extra, extraa);
! 4614: else
! 4615: fline = mmu_op30fake_ptest (pc, opcode, extra, extraa);
1.1.1.7 root 4616: break;
4617: }
1.1.1.9 ! root 4618: if (fline) {
! 4619: m68k_setpc(pc);
! 4620: op_illg(opcode);
! 4621: }
! 4622: return fline;
! 4623: }
! 4624:
! 4625: /* check if an address matches a ttr */
! 4626: static int fake_mmu_do_match_ttr(uae_u32 ttr, uaecptr addr, bool super)
! 4627: {
! 4628: if (ttr & MMU_TTR_BIT_ENABLED) { /* TTR enabled */
! 4629: uae_u8 msb, mask;
! 4630:
! 4631: msb = ((addr ^ ttr) & MMU_TTR_LOGICAL_BASE) >> 24;
! 4632: mask = (ttr & MMU_TTR_LOGICAL_MASK) >> 16;
! 4633:
! 4634: if (!(msb & ~mask)) {
! 4635:
! 4636: if ((ttr & MMU_TTR_BIT_SFIELD_ENABLED) == 0) {
! 4637: if (((ttr & MMU_TTR_BIT_SFIELD_SUPER) == 0) != (super == 0)) {
! 4638: return TTR_NO_MATCH;
! 4639: }
! 4640: }
! 4641:
! 4642: return (ttr & MMU_TTR_BIT_WRITE_PROTECT) ? TTR_NO_WRITE : TTR_OK_MATCH;
! 4643: }
! 4644: }
! 4645: return TTR_NO_MATCH;
! 4646: }
! 4647:
! 4648: static int fake_mmu_match_ttr(uaecptr addr, bool super, bool data)
! 4649: {
! 4650: int res;
! 4651:
! 4652: if (data) {
! 4653: res = fake_mmu_do_match_ttr(regs.dtt0, addr, super);
! 4654: if (res == TTR_NO_MATCH)
! 4655: res = fake_mmu_do_match_ttr(regs.dtt1, addr, super);
! 4656: } else {
! 4657: res = fake_mmu_do_match_ttr(regs.itt0, addr, super);
! 4658: if (res == TTR_NO_MATCH)
! 4659: res = fake_mmu_do_match_ttr(regs.itt1, addr, super);
! 4660: }
! 4661: return res;
1.1.1.7 root 4662: }
4663:
4664: // 68040+ MMU instructions only
4665: void mmu_op (uae_u32 opcode, uae_u32 extra)
4666: {
4667: if (currprefs.mmu_model) {
4668: mmu_op_real (opcode, extra);
4669: return;
4670: }
4671: #if MMUOP_DEBUG > 1
4672: write_log (_T("mmu_op %04X PC=%08X\n"), opcode, m68k_getpc ());
4673: #endif
4674: if ((opcode & 0xFE0) == 0x0500) {
4675: /* PFLUSH */
4676: regs.mmusr = 0;
4677: #if MMUOP_DEBUG > 0
4678: write_log (_T("PFLUSH\n"));
4679: #endif
4680: return;
1.1.1.9 ! root 4681: } else if ((opcode & 0x0FD8) == 0x0548) {
1.1.1.7 root 4682: if (currprefs.cpu_model < 68060) { /* PTEST not in 68060 */
4683: /* PTEST */
1.1.1.9 ! root 4684: int regno = opcode & 7;
! 4685: uae_u32 addr = m68k_areg(regs, regno);
! 4686: bool write = (opcode & 32) == 0;
! 4687: bool super = (regs.dfc & 4) != 0;
! 4688: bool data = (regs.dfc & 3) != 2;
! 4689:
! 4690: regs.mmusr = 0;
! 4691: if (fake_mmu_match_ttr(addr, super, data) != TTR_NO_MATCH) {
! 4692: regs.mmusr = MMU_MMUSR_T | MMU_MMUSR_R;
! 4693: }
! 4694: regs.mmusr |= addr & 0xfffff000;
1.1.1.7 root 4695: #if MMUOP_DEBUG > 0
1.1.1.9 ! root 4696: write_log (_T("PTEST%c %08x\n"), write ? 'W' : 'R', addr);
1.1.1.7 root 4697: #endif
4698: return;
4699: }
1.1.1.9 ! root 4700: } else if ((opcode & 0x0FB8) == 0x0588) {
1.1.1.7 root 4701: /* PLPA */
4702: if (currprefs.cpu_model == 68060) {
1.1.1.9 ! root 4703: int regno = opcode & 7;
! 4704: uae_u32 addr = m68k_areg (regs, regno);
! 4705: int write = (opcode & 0x40) == 0;
! 4706: bool data = (regs.dfc & 3) != 2;
! 4707: bool super = (regs.dfc & 4) != 0;
! 4708:
! 4709: if (fake_mmu_match_ttr(addr, super, data) == TTR_NO_MATCH) {
! 4710: m68k_areg (regs, regno) = addr;
! 4711: }
1.1.1.7 root 4712: #if MMUOP_DEBUG > 0
4713: write_log (_T("PLPA\n"));
4714: #endif
4715: return;
4716: }
4717: }
4718: #if MMUOP_DEBUG > 0
4719: write_log (_T("Unknown MMU OP %04X\n"), opcode);
4720: #endif
4721: m68k_setpc_normal (m68k_getpc () - 2);
4722: op_illg (opcode);
4723: }
4724:
4725: #endif
4726:
1.1.1.4 root 4727: static void do_trace (void)
4728: {
4729: if (regs.t0 && currprefs.cpu_model >= 68020) {
1.1.1.9 ! root 4730: // this is obsolete
! 4731: return;
! 4732: }
! 4733: if (regs.t1) {
! 4734: activate_trace();
1.1.1.4 root 4735: }
4736: }
4737:
1.1.1.8 root 4738: #ifndef WINUAE_FOR_HATARI
1.1.1.7 root 4739: static void check_uae_int_request(void)
4740: {
1.1.1.8 root 4741: if (uae_int_requested) {
4742: bool irq = false;
4743: if (uae_int_requested & 0x00ff) {
1.1.1.7 root 4744: INTREQ_f(0x8000 | 0x0008);
1.1.1.8 root 4745: irq = true;
4746: }
4747: if (uae_int_requested & 0xff00) {
1.1.1.7 root 4748: INTREQ_f(0x8000 | 0x2000);
1.1.1.8 root 4749: irq = true;
4750: }
4751: if (uae_int_requested & 0xff0000) {
4752: if (!cpuboard_is_ppcboard_irq())
4753: atomic_and(&uae_int_requested, ~0x010000);
4754: }
4755: if (irq)
4756: doint();
1.1.1.7 root 4757: }
1.1.1.8 root 4758: }
4759: #endif
4760:
4761: void execute_other_cpu_single(void)
4762: {
4763: #ifdef WITH_X86
4764: if (!x86_turbo_on)
4765: return;
4766: x86_bridge_execute_until(0);
1.1.1.7 root 4767: #endif
4768: }
1.1.1.4 root 4769:
1.1.1.8 root 4770: bool execute_other_cpu(int until)
1.1.1.4 root 4771: {
1.1.1.8 root 4772: #ifdef WITH_X86
4773: if (!x86_turbo_on)
4774: return false;
4775: if (!until)
4776: until++;
4777: x86_bridge_execute_until(until);
4778: #endif
4779: return true;
4780: }
4781:
4782: int cpu_sleep_millis(int ms)
4783: {
4784: int ret = 0;
4785: #ifdef WITH_THREADED_CPU
4786: cpu_semaphore_release();
4787: #endif
1.1.1.7 root 4788: #ifdef WITH_PPC
4789: int state = ppc_state;
4790: if (state)
4791: uae_ppc_spinlock_release();
4792: #endif
1.1.1.8 root 4793: #ifdef WITH_X86
4794: if (x86_turbo_on) {
4795: execute_other_cpu(read_processor_time() + vsynctimebase / 20);
4796: } else {
4797: ret = sleep_millis_main(ms);
4798: }
4799: #endif
1.1.1.7 root 4800: #ifdef WITH_PPC
4801: if (state)
4802: uae_ppc_spinlock_get();
4803: #endif
1.1.1.8 root 4804: #ifdef WITH_THREADED_CPU
4805: cpu_semaphore_get();
1.1.1.7 root 4806: #endif
1.1.1.8 root 4807: return ret;
1.1.1.7 root 4808: }
4809:
4810: #define PPC_HALTLOOP_SCANLINES 25
4811: // ppc_cpu_idle
4812: // 0 = busy
4813: // 1-9 = wait, levels
4814: // 10 = max wait
4815:
1.1.1.8 root 4816: #ifndef WINUAE_FOR_HATARI
4817: static bool haltloop_do(int vsynctimeline, int rpt_end, int lines)
4818: {
4819: int ovpos = vpos;
4820: while (lines-- >= 0) {
4821: ovpos = vpos;
4822: while (ovpos == vpos) {
4823: x_do_cycles(8 * CYCLE_UNIT);
4824: unset_special(SPCFLAG_UAEINT);
4825: check_uae_int_request();
4826: #ifdef WITH_PPC
4827: ppc_interrupt(intlev());
4828: uae_ppc_execute_check();
4829: #endif
4830: if (regs.spcflags & SPCFLAG_COPPER)
4831: do_copper();
4832: if (regs.spcflags & (SPCFLAG_BRK | SPCFLAG_MODE_CHANGE)) {
4833: if (regs.spcflags & SPCFLAG_BRK) {
4834: unset_special(SPCFLAG_BRK);
4835: #ifdef DEBUGGER
4836: if (debugging)
4837: debug();
4838: #endif
4839: }
4840: return true;
4841: }
4842: }
4843:
4844: // sync chipset with real time
4845: for (;;) {
4846: check_uae_int_request();
4847: #ifdef WITH_PPC
4848: ppc_interrupt(intlev());
4849: uae_ppc_execute_check();
4850: #endif
4851: if (event_wait)
4852: break;
4853: int d = read_processor_time() - rpt_end;
4854: if (d < -2 * vsynctimeline || d >= 0)
4855: break;
4856: }
4857: }
4858: return false;
4859: }
4860: #endif
4861:
1.1.1.7 root 4862: static bool haltloop(void)
4863: {
4864: #ifndef WINUAE_FOR_HATARI
4865: #ifdef WITH_PPC
4866: if (regs.halted < 0) {
4867: int rpt_end = 0;
4868: int ovpos = vpos;
4869:
4870: while (regs.halted) {
4871: int vsynctimeline = vsynctimebase / (maxvpos_display + 1);
4872: int lines;
4873: int rpt_scanline = read_processor_time();
4874: int rpt_end = rpt_scanline + vsynctimeline;
4875:
4876: // See expansion handling.
4877: // Dialog must be opened from main thread.
4878: if (regs.halted == -2) {
4879: regs.halted = -1;
4880: notify_user (NUMSG_UAEBOOTROM_PPC);
4881: }
4882:
4883: if (currprefs.ppc_cpu_idle) {
4884:
4885: int maxlines = 100 - (currprefs.ppc_cpu_idle - 1) * 10;
4886: int i;
4887:
4888: event_wait = false;
4889: for (i = 0; i < ev_max; i++) {
4890: if (i == ev_hsync)
4891: continue;
4892: if (i == ev_audio)
4893: continue;
4894: if (!eventtab[i].active)
4895: continue;
4896: if (eventtab[i].evtime - currcycle < maxlines * maxhpos * CYCLE_UNIT)
4897: break;
4898: }
4899: if (currprefs.ppc_cpu_idle >= 10 || (i == ev_max && vpos > 0 && vpos < maxvpos - maxlines)) {
4900: cpu_sleep_millis(1);
4901: }
4902: check_uae_int_request();
4903: uae_ppc_execute_check();
4904:
4905: lines = (read_processor_time() - rpt_scanline) / vsynctimeline + 1;
4906:
4907: } else {
4908:
4909: event_wait = true;
4910: lines = 0;
4911:
4912: }
4913:
4914: if (lines > maxvpos / 2)
4915: lines = maxvpos / 2;
4916:
1.1.1.8 root 4917: if (haltloop_do(vsynctimeline, rpt_end, lines))
4918: return true;
1.1.1.7 root 4919:
1.1.1.4 root 4920: }
1.1.1.7 root 4921:
4922: } else {
1.1.1.4 root 4923: #endif
1.1.1.7 root 4924: while (regs.halted) {
4925: static int prevvpos;
4926: if (vpos == 0 && prevvpos) {
4927: prevvpos = 0;
4928: cpu_sleep_millis(8);
4929: }
4930: if (vpos)
4931: prevvpos = 1;
4932: x_do_cycles(8 * CYCLE_UNIT);
4933:
4934: if (regs.spcflags & SPCFLAG_COPPER)
4935: do_copper();
4936:
4937: if (regs.spcflags) {
4938: if ((regs.spcflags & (SPCFLAG_BRK | SPCFLAG_MODE_CHANGE)))
4939: return true;
4940: }
4941: }
4942: #ifdef WITH_PPC
1.1.1.4 root 4943: }
1.1.1.7 root 4944: #endif
4945:
4946: return false;
4947: #else
4948: /* In Hatari, we don't use the halt state, we do a reset */
4949: return false;
4950: #endif
1.1.1.4 root 4951: }
4952:
1.1.1.7 root 4953: #ifdef WITH_PPC
4954: static bool uae_ppc_poll_check_halt(void)
1.1.1.4 root 4955: {
1.1.1.7 root 4956: if (regs.halted) {
4957: if (haltloop())
4958: return true;
1.1.1.4 root 4959: }
1.1.1.7 root 4960: return false;
1.1.1.4 root 4961: }
1.1.1.7 root 4962: #endif
1.1.1.4 root 4963:
4964:
1.1.1.7 root 4965: // handle interrupt delay (few cycles)
4966: STATIC_INLINE bool time_for_interrupt (void)
1.1.1.4 root 4967: {
1.1.1.7 root 4968: return regs.ipl > regs.intmask || regs.ipl == 7;
4969: }
1.1.1.4 root 4970:
1.1.1.7 root 4971: void doint (void)
4972: {
4973: #ifdef WITH_PPC
4974: if (ppc_state) {
4975: if (!ppc_interrupt(intlev()))
4976: return;
1.1.1.4 root 4977: }
1.1.1.7 root 4978: #endif
1.1.1.8 root 4979: //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 4980: if (m68k_interrupt_delay) {
4981: regs.ipl_pin = intlev ();
4982: unset_special (SPCFLAG_INT);
1.1.1.8 root 4983: //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 4984: return;
1.1.1.4 root 4985: }
1.1.1.7 root 4986: if (currprefs.cpu_compatible && currprefs.cpu_model < 68020)
4987: set_special (SPCFLAG_INT);
4988: else
4989: set_special (SPCFLAG_DOINT);
1.1.1.4 root 4990: }
4991:
4992:
1.1.1.7 root 4993: #ifdef WINUAE_FOR_HATARI
1.1.1.4 root 4994: /*
4995: * Handle special flags
4996: */
4997:
4998: static bool do_specialties_interrupt (int Pending)
4999: {
1.1.1.5 root 5000: #if ENABLE_DSP_EMU
5001: /* Check for DSP int first (if enabled) (level 6) */
5002: if (regs.spcflags & SPCFLAG_DSP) {
5003: if (DSP_ProcessIRQ() == true)
5004: return true;
5005: }
5006: #endif
5007:
5008: /* Check for MFP ints (level 6) */
1.1.1.4 root 5009: if (regs.spcflags & SPCFLAG_MFP) {
1.1.1.5 root 5010: if (MFP_ProcessIRQ() == true)
1.1.1.4 root 5011: return true; /* MFP exception was generated, no higher interrupt can happen */
5012: }
5013:
5014: /* No MFP int, check for VBL/HBL ints (levels 4/2) */
5015: if (regs.spcflags & (SPCFLAG_INT | SPCFLAG_DOINT)) {
5016: int intr = intlev ();
5017: /* SPCFLAG_DOINT will be enabled again in MakeFromSR to handle pending interrupts! */
5018: // unset_special (SPCFLAG_DOINT);
5019: unset_special (SPCFLAG_INT | SPCFLAG_DOINT);
5020: if (intr != -1 && intr > regs.intmask) {
1.1.1.7 root 5021: do_interrupt (intr); /* process the interrupt */
1.1.1.4 root 5022: return true;
5023: }
5024: }
5025:
5026: return false; /* no interrupt was found */
5027: }
1.1.1.7 root 5028: #endif
1.1.1.4 root 5029:
1.1.1.7 root 5030: static int do_specialties (int cycles)
1.1.1.4 root 5031: {
1.1.1.7 root 5032: if (regs.spcflags & SPCFLAG_MODE_CHANGE)
5033: return 1;
5034:
5035: #ifndef WINUAE_FOR_HATARI
5036: if (regs.spcflags & SPCFLAG_CHECK) {
5037: if (regs.halted) {
1.1.1.8 root 5038: if (regs.halted == CPU_HALT_ACCELERATOR_CPU_FALLBACK) {
5039: return 1;
5040: }
5041: unset_special(SPCFLAG_CHECK);
1.1.1.7 root 5042: if (haltloop())
5043: return 1;
5044: }
5045: if (m68k_reset_delay) {
5046: int vsynccnt = 60;
5047: int vsyncstate = -1;
5048: while (vsynccnt > 0 && !quit_program) {
5049: x_do_cycles(8 * CYCLE_UNIT);
5050: if (regs.spcflags & SPCFLAG_COPPER)
5051: do_copper();
5052: if (timeframes != vsyncstate) {
5053: vsyncstate = timeframes;
5054: vsynccnt--;
5055: }
5056: }
5057: }
5058: m68k_reset_delay = 0;
5059: unset_special(SPCFLAG_CHECK);
5060: }
5061: #endif
5062:
5063: #ifdef ACTION_REPLAY
5064: #ifdef ACTION_REPLAY_HRTMON
5065: if ((regs.spcflags & SPCFLAG_ACTION_REPLAY) && hrtmon_flag != ACTION_REPLAY_INACTIVE) {
5066: int isinhrt = (m68k_getpc () >= hrtmem_start && m68k_getpc () < hrtmem_start + hrtmem_size);
5067: /* exit from HRTMon? */
5068: if (hrtmon_flag == ACTION_REPLAY_ACTIVE && !isinhrt)
5069: hrtmon_hide ();
5070: /* HRTMon breakpoint? (not via IRQ7) */
5071: if (hrtmon_flag == ACTION_REPLAY_IDLE && isinhrt)
5072: hrtmon_breakenter ();
5073: if (hrtmon_flag == ACTION_REPLAY_ACTIVATE)
5074: hrtmon_enter ();
5075: }
5076: #endif
5077: if ((regs.spcflags & SPCFLAG_ACTION_REPLAY) && action_replay_flag != ACTION_REPLAY_INACTIVE) {
5078: /*if (action_replay_flag == ACTION_REPLAY_ACTIVE && !is_ar_pc_in_rom ())*/
5079: /* write_log (_T("PC:%p\n"), m68k_getpc ());*/
5080:
5081: if (action_replay_flag == ACTION_REPLAY_ACTIVATE || action_replay_flag == ACTION_REPLAY_DORESET)
5082: action_replay_enter ();
5083: if ((action_replay_flag == ACTION_REPLAY_HIDE || action_replay_flag == ACTION_REPLAY_ACTIVE) && !is_ar_pc_in_rom ()) {
5084: action_replay_hide ();
5085: unset_special (SPCFLAG_ACTION_REPLAY);
5086: }
5087: if (action_replay_flag == ACTION_REPLAY_WAIT_PC) {
5088: /*write_log (_T("Waiting for PC: %p, current PC= %p\n"), wait_for_pc, m68k_getpc ());*/
5089: if (m68k_getpc () == wait_for_pc) {
5090: action_replay_flag = ACTION_REPLAY_ACTIVATE; /* Activate after next instruction. */
5091: }
5092: }
5093: }
5094: #endif
5095:
5096: #ifndef WINUAE_FOR_HATARI
5097: if (regs.spcflags & SPCFLAG_COPPER)
5098: do_copper ();
5099: #endif
5100:
1.1.1.4 root 5101: #ifdef JIT
5102: unset_special (SPCFLAG_END_COMPILE); /* has done its job */
5103: #endif
5104:
1.1.1.7 root 5105: #ifndef WINUAE_FOR_HATARI
1.1.1.9 ! root 5106: 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 5107: int c = blitnasty ();
1.1.1.7 root 5108: if (c < 0) {
5109: break;
5110: } else if (c > 0) {
1.1.1.4 root 5111: cycles -= c * CYCLE_UNIT * 2;
5112: if (cycles < CYCLE_UNIT)
5113: cycles = 0;
1.1.1.7 root 5114: } else {
1.1.1.4 root 5115: c = 4;
1.1.1.7 root 5116: }
5117: x_do_cycles (c * CYCLE_UNIT);
1.1.1.4 root 5118: if (regs.spcflags & SPCFLAG_COPPER)
5119: do_copper ();
1.1.1.7 root 5120: #ifdef WITH_PPC
5121: if (ppc_state) {
5122: if (uae_ppc_poll_check_halt())
5123: return true;
5124: uae_ppc_execute_check();
5125: }
5126: #endif
1.1.1.4 root 5127: }
5128: #endif
5129:
1.1.1.7 root 5130: #ifdef WINUAE_FOR_HATARI
1.1.1.4 root 5131: if (regs.spcflags & SPCFLAG_BUSERROR) {
5132: /* We can not execute bus errors directly in the memory handler
5133: * functions since the PC should point to the address of the next
5134: * instruction, so we're executing the bus errors here: */
5135: unset_special(SPCFLAG_BUSERROR);
1.1.1.7 root 5136: Exception(2);
1.1.1.4 root 5137: }
1.1.1.7 root 5138: #endif
1.1.1.4 root 5139:
5140: if (regs.spcflags & SPCFLAG_DOTRACE)
1.1.1.7 root 5141: Exception (9);
1.1.1.4 root 5142:
1.1.1.7 root 5143: #ifndef WINUAE_FOR_HATARI
1.1.1.4 root 5144: if (regs.spcflags & SPCFLAG_TRAP) {
5145: unset_special (SPCFLAG_TRAP);
1.1.1.7 root 5146: Exception (3);
1.1.1.4 root 5147: }
1.1.1.7 root 5148: #endif
1.1.1.9 ! root 5149: if ((regs.spcflags & SPCFLAG_STOP) && regs.s == 0 && currprefs.cpu_model <= 68010) {
! 5150: // 68000/68010 undocumented special case:
! 5151: // if STOP clears S-bit and T was not set:
! 5152: // cause privilege violation exception, PC pointing to following instruction.
! 5153: // If T was set before STOP: STOP works as documented.
! 5154: m68k_unset_stop();
! 5155: Exception(8);
! 5156: }
! 5157:
1.1.1.7 root 5158: bool first = true;
5159: while ((regs.spcflags & SPCFLAG_STOP) && !(regs.spcflags & SPCFLAG_BRK)) {
1.1.1.8 root 5160: //fprintf ( stderr , "stop wait %d %ld %ld\n" , currcycle , CyclesGlobalClockCounter );
5161: isstopped:
1.1.1.9 ! root 5162: #ifndef WINUAE_FOR_HATARI
1.1.1.7 root 5163: check_uae_int_request();
5164: {
5165: if (bsd_int_requested)
5166: bsdsock_fake_int_handler ();
5167: }
5168: #endif
5169:
5170: if (cpu_tracer > 0) {
5171: cputrace.stopped = regs.stopped;
5172: cputrace.intmask = regs.intmask;
5173: cputrace.sr = regs.sr;
5174: cputrace.state = 1;
5175: cputrace.pc = m68k_getpc ();
5176: cputrace.memoryoffset = 0;
5177: cputrace.cyclecounter = cputrace.cyclecounter_pre = cputrace.cyclecounter_post = 0;
5178: cputrace.readcounter = cputrace.writecounter = 0;
5179: }
5180: if (!first)
5181: x_do_cycles (currprefs.cpu_cycle_exact ? 2 * CYCLE_UNIT : 4 * CYCLE_UNIT);
1.1.1.4 root 5182:
1.1.1.7 root 5183: #ifdef WINUAE_FOR_HATARI
5184: if (!first)
5185: {
1.1.1.8 root 5186: if (currprefs.cpu_cycle_exact && !currprefs.mmu_model)
5187: {
5188: /* Flush all CE cycles so far to update PendingInterruptCount */
5189: M68000_AddCycles_CE ( currcycle * 2 / CYCLE_UNIT );
5190: currcycle = 0;
5191: }
5192: else
1.1.1.7 root 5193: M68000_AddCycles(4);
5194: }
1.1.1.4 root 5195:
5196: /* It is possible one or more ints happen at the same time */
1.1.1.5 root 5197: /* We must process them during the same cpu cycle then choose the highest priority one */
5198: while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) )
1.1.1.7 root 5199: CALL_VAR(PendingInterruptFunction);
1.1.1.5 root 5200: if ( MFP_UpdateNeeded == true )
1.1.1.7 root 5201: MFP_UpdateIRQ ( 0 );
1.1.1.4 root 5202:
1.1.1.5 root 5203: /* Check is there's an interrupt to process (could be a delayed MFP interrupt) */
1.1.1.7 root 5204: if (regs.spcflags & SPCFLAG_MFP) {
5205: MFP_DelayIRQ (); /* Handle IRQ propagation */
5206: M68000_Update_intlev (); /* Refresh the list of pending interrupts */
1.1.1.5 root 5207: }
1.1.1.7 root 5208: #endif
5209: first = false;
5210: #ifndef WINUAE_FOR_HATARI
1.1.1.5 root 5211: if (regs.spcflags & SPCFLAG_COPPER)
5212: do_copper ();
1.1.1.4 root 5213: #endif
5214:
1.1.1.7 root 5215: if (m68k_interrupt_delay) {
1.1.1.5 root 5216: ipl_fetch ();
5217: if (time_for_interrupt ()) {
1.1.1.7 root 5218: do_interrupt (regs.ipl);
1.1.1.5 root 5219: }
5220: } else {
1.1.1.7 root 5221: if (regs.spcflags & (SPCFLAG_INT | SPCFLAG_DOINT)) {
5222: int intr = intlev ();
5223: unset_special (SPCFLAG_INT | SPCFLAG_DOINT);
5224: #ifdef WITH_PPC
5225: bool m68kint = true;
5226: if (ppc_state) {
5227: m68kint = ppc_interrupt(intr);
5228: }
5229: if (m68kint) {
1.1.1.4 root 5230: #endif
1.1.1.7 root 5231: if (intr > 0 && intr > regs.intmask)
5232: do_interrupt (intr);
5233: #ifdef WITH_PPC
5234: }
5235: #endif
5236: }
1.1.1.5 root 5237: }
1.1.1.7 root 5238:
5239: if (regs.spcflags & SPCFLAG_MODE_CHANGE) {
5240: m68k_resumestopped();
1.1.1.5 root 5241: return 1;
5242: }
1.1.1.4 root 5243:
1.1.1.7 root 5244: #ifdef WITH_PPC
5245: if (ppc_state) {
5246: uae_ppc_execute_check();
5247: uae_ppc_poll_check_halt();
1.1.1.4 root 5248: }
1.1.1.7 root 5249: #endif
5250:
1.1.1.4 root 5251: }
5252:
5253: if (regs.spcflags & SPCFLAG_TRACE)
5254: do_trace ();
5255:
1.1.1.8 root 5256: #ifndef WINUAE_FOR_HATARI
5257: if (regs.spcflags & SPCFLAG_UAEINT) {
5258: check_uae_int_request();
5259: unset_special(SPCFLAG_UAEINT);
5260: }
5261: #endif
5262:
1.1.1.7 root 5263: #ifdef WINUAE_FOR_HATARI
5264: if (regs.spcflags & SPCFLAG_MFP) {
5265: MFP_DelayIRQ (); /* Handle IRQ propagation */
5266: M68000_Update_intlev (); /* Refresh the list of pending interrupts */
5267: }
5268: #endif
5269:
1.1.1.8 root 5270: //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 5271: if (m68k_interrupt_delay) {
1.1.1.4 root 5272: if (time_for_interrupt ()) {
1.1.1.7 root 5273: do_interrupt (regs.ipl);
1.1.1.4 root 5274: }
5275: } else {
5276: if (regs.spcflags & SPCFLAG_INT) {
5277: int intr = intlev ();
5278: unset_special (SPCFLAG_INT | SPCFLAG_DOINT);
5279: if (intr > 0 && (intr > regs.intmask || intr == 7))
1.1.1.7 root 5280: do_interrupt (intr);
1.1.1.4 root 5281: }
5282: }
5283:
1.1.1.8 root 5284: //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 5285: if (regs.spcflags & SPCFLAG_DOINT) {
5286: unset_special (SPCFLAG_DOINT);
5287: set_special (SPCFLAG_INT);
5288: }
1.1.1.8 root 5289: //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 5290:
1.1.1.7 root 5291: #ifdef WINUAE_FOR_HATARI
1.1.1.8 root 5292: if (regs.spcflags & SPCFLAG_DEBUGGER)
1.1.1.4 root 5293: DebugCpu_Check();
1.1.1.7 root 5294: #endif
1.1.1.4 root 5295:
1.1.1.7 root 5296: if (regs.spcflags & SPCFLAG_BRK) {
5297: unset_special(SPCFLAG_BRK);
5298: #ifdef DEBUGGER
5299: if (debugging) {
5300: debug();
5301: if (regs.stopped)
5302: goto isstopped;
5303: }
5304: #endif
5305: #ifdef WINUAE_FOR_HATARI
5306: return 1; /* Exit the upper run_xxx() function */
5307: #endif
1.1.1.4 root 5308: }
1.1.1.7 root 5309:
1.1.1.4 root 5310: return 0;
5311: }
5312:
5313: //static uae_u32 pcs[1000];
5314:
1.1.1.7 root 5315: #ifndef WINUAE_FOR_HATARI
1.1.1.4 root 5316: #if DEBUG_CD32CDTVIO
5317:
5318: static uae_u32 cd32nextpc, cd32request;
5319:
5320: static void out_cd32io2 (void)
5321: {
5322: uae_u32 request = cd32request;
1.1.1.7 root 5323: write_log (_T("%08x returned\n"), request);
5324: //write_log (_T("ACTUAL=%d ERROR=%d\n"), get_long (request + 32), get_byte (request + 31));
1.1.1.4 root 5325: cd32nextpc = 0;
5326: cd32request = 0;
5327: }
5328:
5329: static void out_cd32io (uae_u32 pc)
5330: {
5331: TCHAR out[100];
5332: int ioreq = 0;
5333: uae_u32 request = m68k_areg (regs, 1);
5334:
5335: if (pc == cd32nextpc) {
5336: out_cd32io2 ();
5337: return;
5338: }
5339: out[0] = 0;
5340: switch (pc)
5341: {
5342: case 0xe57cc0:
5343: case 0xf04c34:
1.1.1.7 root 5344: _stprintf (out, _T("opendevice"));
1.1.1.4 root 5345: break;
5346: case 0xe57ce6:
5347: case 0xf04c56:
1.1.1.7 root 5348: _stprintf (out, _T("closedevice"));
1.1.1.4 root 5349: break;
5350: case 0xe57e44:
5351: case 0xf04f2c:
1.1.1.7 root 5352: _stprintf (out, _T("beginio"));
1.1.1.4 root 5353: ioreq = 1;
5354: break;
5355: case 0xe57ef2:
5356: case 0xf0500e:
1.1.1.7 root 5357: _stprintf (out, _T("abortio"));
1.1.1.4 root 5358: ioreq = -1;
5359: break;
5360: }
5361: if (out[0] == 0)
5362: return;
5363: if (cd32request)
1.1.1.7 root 5364: write_log (_T("old request still not returned!\n"));
1.1.1.4 root 5365: cd32request = request;
5366: cd32nextpc = get_long (m68k_areg (regs, 7));
1.1.1.7 root 5367: write_log (_T("%s A1=%08X\n"), out, request);
1.1.1.4 root 5368: if (ioreq) {
5369: static int cnt = 0;
5370: int cmd = get_word (request + 28);
5371: #if 0
1.1.1.7 root 5372: if (cmd == 33) {
5373: uaecptr data = get_long (request + 40);
5374: write_log (_T("CD_CONFIG:\n"));
5375: for (int i = 0; i < 16; i++) {
5376: write_log (_T("%08X=%08X\n"), get_long (data), get_long (data + 4));
5377: data += 8;
5378: }
5379: }
5380: #endif
5381: #if 0
1.1.1.4 root 5382: if (cmd == 37) {
5383: cnt--;
5384: if (cnt <= 0)
5385: activate_debugger ();
5386: }
5387: #endif
1.1.1.7 root 5388: write_log (_T("CMD=%d DATA=%08X LEN=%d %OFF=%d PC=%x\n"),
5389: cmd, get_long (request + 40),
5390: get_long (request + 36), get_long (request + 44), M68K_GETPC);
1.1.1.4 root 5391: }
5392: if (ioreq < 0)
5393: ;//activate_debugger ();
5394: }
5395:
1.1.1.7 root 5396: #endif
5397: #endif
5398:
1.1.1.4 root 5399: #ifndef CPUEMU_11
5400:
5401: static void m68k_run_1 (void)
5402: {
5403: }
5404:
5405: #else
5406:
5407: /* It's really sad to have two almost identical functions for this, but we
5408: do it all for performance... :(
5409: This version emulates 68000's prefetch "cache" */
5410: static void m68k_run_1 (void)
5411: {
5412: struct regstruct *r = ®s;
1.1.1.7 root 5413: bool exit = false;
1.1.1.8 root 5414:
5415: Log_Printf(LOG_DEBUG, "m68k_run_1\n");
1.1.1.4 root 5416:
1.1.1.7 root 5417: while (!exit) {
5418: TRY (prb) {
5419: while (!exit) {
5420: r->opcode = r->ir;
5421:
5422: count_instr (r->opcode);
5423:
5424: #ifdef WINUAE_FOR_HATARI
5425: //m68k_dumpstate_file(stderr, NULL);
5426: if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM))
5427: {
5428: int FrameCycles, HblCounterVideo, LineCycles;
1.1.1.4 root 5429:
1.1.1.7 root 5430: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
1.1.1.4 root 5431:
1.1.1.7 root 5432: LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo );
5433: m68k_disasm_file(stderr, m68k_getpc (), NULL, 1);
5434: }
5435: #endif
1.1.1.4 root 5436:
1.1.1.7 root 5437: #ifndef WINUAE_FOR_HATARI
1.1.1.4 root 5438: #if DEBUG_CD32CDTVIO
1.1.1.7 root 5439: out_cd32io (m68k_getpc ());
5440: #endif
1.1.1.4 root 5441: #endif
5442:
5443: #if 0
1.1.1.7 root 5444: int pc = m68k_getpc ();
5445: if (pc == 0xdff002)
5446: write_log (_T("hip\n"));
5447: if (pc != pcs[0] && (pc < 0xd00000 || pc > 0x1000000)) {
5448: memmove (pcs + 1, pcs, 998 * 4);
5449: pcs[0] = pc;
5450: //write_log (_T("%08X-%04X "), pc, r->opcode);
5451: }
1.1.1.4 root 5452: #endif
1.1.1.7 root 5453: do_cycles (cpu_cycles);
5454: r->instruction_pc = m68k_getpc ();
5455: cpu_cycles = (*cpufunctbl[r->opcode])(r->opcode);
5456: cpu_cycles = adjust_cycles (cpu_cycles);
5457:
5458: #ifdef WINUAE_FOR_HATARI
1.1.1.8 root 5459: /* Also add some extra cycles to simulate some wait state */
5460: /* TODO [NP] do this in all m68k_run_xx() */
5461: M68000_AddCyclesWithPairing(cpu_cycles * 2 / CYCLE_UNIT + WaitStateCycles);
5462: WaitStateCycles = 0;
1.1.1.5 root 5463:
1.1.1.7 root 5464: /* We can have several interrupts at the same time before the next CPU instruction */
5465: /* We must check for pending interrupt and call do_specialties_interrupt() only */
5466: /* if the cpu is not in the STOP state. Else, the int could be acknowledged now */
5467: /* and prevent exiting the STOP state when calling do_specialties() after. */
5468: /* For performance, we first test PendingInterruptCount, then regs.spcflags */
5469: while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) && ( ( regs.spcflags & SPCFLAG_STOP ) == 0 ) )
5470: CALL_VAR(PendingInterruptFunction); /* call the interrupt handler */
5471: if ( MFP_UpdateNeeded == true )
5472: MFP_UpdateIRQ ( 0 );
5473: #endif
1.1.1.4 root 5474:
1.1.1.7 root 5475: if (r->spcflags) {
5476: if (do_specialties (cpu_cycles))
5477: exit = true;
5478: }
5479: regs.ipl = regs.ipl_pin;
5480: if (!currprefs.cpu_compatible || (currprefs.cpu_cycle_exact && currprefs.cpu_model <= 68010))
5481: exit = true;
5482: }
5483: } CATCH (prb) {
5484: bus_error();
5485: if (r->spcflags) {
5486: if (do_specialties(cpu_cycles))
5487: exit = true;
5488: }
5489: regs.ipl = regs.ipl_pin;
5490: } ENDTRY
5491: }
5492: }
1.1.1.4 root 5493:
5494: #endif /* CPUEMU_11 */
5495:
1.1.1.7 root 5496: #ifndef CPUEMU_13
1.1.1.4 root 5497:
5498: static void m68k_run_1_ce (void)
5499: {
5500: }
5501:
5502: #else
5503:
5504: /* cycle-exact m68k_run () */
5505:
5506: static void m68k_run_1_ce (void)
5507: {
5508: struct regstruct *r = ®s;
1.1.1.7 root 5509: bool first = true;
5510: bool exit = false;
1.1.1.8 root 5511:
5512: Log_Printf(LOG_DEBUG, "m68k_run_1_ce\n");
1.1.1.7 root 5513:
5514: while (!exit) {
5515: TRY (prb) {
5516: if (first) {
5517: if (cpu_tracer < 0) {
5518: memcpy (&r->regs, &cputrace.regs, 16 * sizeof (uae_u32));
5519: r->ir = cputrace.ir;
5520: r->irc = cputrace.irc;
5521: r->sr = cputrace.sr;
5522: r->usp = cputrace.usp;
5523: r->isp = cputrace.isp;
5524: r->intmask = cputrace.intmask;
5525: r->stopped = cputrace.stopped;
5526: m68k_setpc (cputrace.pc);
5527: if (!r->stopped) {
5528: if (cputrace.state > 1) {
5529: write_log (_T("CPU TRACE: EXCEPTION %d\n"), cputrace.state);
5530: Exception (cputrace.state);
5531: } else if (cputrace.state == 1) {
5532: write_log (_T("CPU TRACE: %04X\n"), cputrace.opcode);
5533: (*cpufunctbl[cputrace.opcode])(cputrace.opcode);
5534: }
5535: } else {
5536: write_log (_T("CPU TRACE: STOPPED\n"));
5537: }
5538: if (r->stopped)
5539: set_special (SPCFLAG_STOP);
5540: set_cpu_tracer (false);
5541: goto cont;
5542: }
5543: set_cpu_tracer (false);
5544: first = false;
5545: }
1.1.1.4 root 5546:
1.1.1.7 root 5547: while (!exit) {
5548: r->opcode = r->ir;
1.1.1.4 root 5549:
1.1.1.7 root 5550: #ifdef WINUAE_FOR_HATARI
5551: //m68k_dumpstate_file(stderr, NULL);
5552: if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM))
5553: {
5554: int FrameCycles, HblCounterVideo, LineCycles;
1.1.1.4 root 5555:
1.1.1.7 root 5556: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
1.1.1.4 root 5557:
1.1.1.8 root 5558: //fprintf ( stderr , "clock %ld\n" , CyclesGlobalClockCounter );
1.1.1.7 root 5559: LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo );
5560: m68k_disasm_file(stderr, m68k_getpc (), NULL, 1);
5561: }
5562: #endif
5563:
5564: #ifndef WINUAE_FOR_HATARI
5565: #if DEBUG_CD32CDTVIO
5566: out_cd32io (m68k_getpc ());
5567: #endif
5568: #endif
5569: if (cpu_tracer) {
5570: memcpy (&cputrace.regs, &r->regs, 16 * sizeof (uae_u32));
5571: cputrace.opcode = r->opcode;
5572: cputrace.ir = r->ir;
5573: cputrace.irc = r->irc;
5574: cputrace.sr = r->sr;
5575: cputrace.usp = r->usp;
5576: cputrace.isp = r->isp;
5577: cputrace.intmask = r->intmask;
5578: cputrace.stopped = r->stopped;
5579: cputrace.state = 1;
5580: cputrace.pc = m68k_getpc ();
5581: cputrace.startcycles = get_cycles ();
5582: cputrace.memoryoffset = 0;
5583: cputrace.cyclecounter = cputrace.cyclecounter_pre = cputrace.cyclecounter_post = 0;
5584: cputrace.readcounter = cputrace.writecounter = 0;
5585: }
5586:
5587: #ifndef WINUAE_FOR_HATARI
5588: if (inputrecord_debug & 4) {
5589: if (input_record > 0)
5590: inprec_recorddebug_cpu (1);
5591: else if (input_play > 0)
5592: inprec_playdebug_cpu (1);
5593: }
5594: #endif
5595:
5596: #ifdef WINUAE_FOR_HATARI
5597: currcycle = 0;
5598: #endif
5599:
5600: r->instruction_pc = m68k_getpc ();
5601: (*cpufunctbl[r->opcode])(r->opcode);
5602: wait_memory_cycles(); // TODO NP : ici, ou plus bas ?
5603: #ifdef WINUAE_FOR_HATARI
5604: //fprintf ( stderr, "cyc_1ce %d\n" , currcycle );
1.1.1.8 root 5605: /* Flush all CE cycles so far to update PendingInterruptCount */
5606: M68000_AddCycles_CE ( currcycle * 2 / CYCLE_UNIT );
5607: currcycle = 0;
1.1.1.7 root 5608:
5609: while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) && ( ( regs.spcflags & SPCFLAG_STOP ) == 0 ) )
5610: CALL_VAR(PendingInterruptFunction); /* call the interrupt handler */
5611: if ( MFP_UpdateNeeded == true )
5612: MFP_UpdateIRQ ( 0 );
5613: #endif
5614:
5615: if (cpu_tracer) {
5616: cputrace.state = 0;
5617: }
5618: cont:
5619: if (cputrace.needendcycles) {
5620: cputrace.needendcycles = 0;
5621: write_log (_T("STARTCYCLES=%08x ENDCYCLES=%08lx\n"), cputrace.startcycles, get_cycles ());
5622: #ifndef WINUAE_FOR_HATARI
5623: log_dma_record ();
5624: #endif
5625: }
5626:
5627: if (r->spcflags || time_for_interrupt ()) {
5628: if (do_specialties (0))
5629: exit = true;
5630: }
5631:
5632: if (!currprefs.cpu_cycle_exact || currprefs.cpu_model > 68010)
5633: exit = true;
5634: }
5635: } CATCH (prb) {
5636: bus_error();
5637: if (r->spcflags || time_for_interrupt()) {
5638: if (do_specialties(0))
5639: exit = true;
5640: }
5641: } ENDTRY
5642: }
5643: }
5644:
5645: #endif
5646:
1.1.1.8 root 5647: #if defined(CPUEMU_20) && defined(JIT)
1.1.1.7 root 5648: // emulate simple prefetch
5649: static uae_u16 get_word_020_prefetchf (uae_u32 pc)
5650: {
5651: if (pc == regs.prefetch020addr) {
5652: uae_u16 v = regs.prefetch020[0];
5653: regs.prefetch020[0] = regs.prefetch020[1];
5654: regs.prefetch020[1] = regs.prefetch020[2];
5655: regs.prefetch020[2] = x_get_word (pc + 6);
5656: regs.prefetch020addr += 2;
5657: return v;
5658: } else if (pc == regs.prefetch020addr + 2) {
5659: uae_u16 v = regs.prefetch020[1];
5660: regs.prefetch020[0] = regs.prefetch020[2];
5661: regs.prefetch020[1] = x_get_word (pc + 4);
5662: regs.prefetch020[2] = x_get_word (pc + 6);
5663: regs.prefetch020addr = pc + 2;
5664: return v;
5665: } else if (pc == regs.prefetch020addr + 4) {
5666: uae_u16 v = regs.prefetch020[2];
5667: regs.prefetch020[0] = x_get_word (pc + 2);
5668: regs.prefetch020[1] = x_get_word (pc + 4);
5669: regs.prefetch020[2] = x_get_word (pc + 6);
5670: regs.prefetch020addr = pc + 2;
5671: return v;
5672: } else {
5673: regs.prefetch020addr = pc + 2;
5674: regs.prefetch020[0] = x_get_word (pc + 2);
5675: regs.prefetch020[1] = x_get_word (pc + 4);
5676: regs.prefetch020[2] = x_get_word (pc + 6);
5677: return x_get_word (pc);
1.1.1.4 root 5678: }
5679: }
5680: #endif
5681:
1.1.1.8 root 5682: #ifdef WITH_THREADED_CPU
5683: static volatile int cpu_thread_active;
5684:
5685: #define SPINLOCK_DEBUG 0
5686: static volatile int m68k_spinlock_cnt;
5687: static volatile long m68k_spinlock_waiting;
5688: #ifdef _WIN32
5689: #define CRITICAL_SECTION_SPIN_COUNT 5000
5690: static CRITICAL_SECTION m68k_cs1;
5691: static bool m68k_cs_initialized;
5692: static DWORD m68k_cs_owner;
5693: #else
5694: #include <glib.h>
5695: static GMutex mutex;
5696: #endif
5697:
5698: static int do_specialties_thread(void)
5699: {
5700: if (regs.spcflags & SPCFLAG_MODE_CHANGE)
5701: return 1;
5702:
5703: if (regs.spcflags & SPCFLAG_CHECK) {
5704: if (regs.halted) {
5705: if (haltloop())
5706: return 1;
5707: }
5708: if (m68k_reset_delay) {
5709: int vsynccnt = 60;
5710: int vsyncstate = -1;
5711: while (vsynccnt > 0) {
5712: int vp = vpos;
5713: while (vp == vpos) {
5714: sleep_millis(1);
5715: }
5716: vsynccnt--;
5717: }
5718: }
5719: m68k_reset_delay = 0;
5720: unset_special(SPCFLAG_CHECK);
5721: }
5722:
5723: #ifdef JIT
5724: unset_special(SPCFLAG_END_COMPILE); /* has done its job */
5725: #endif
5726:
5727: if (regs.spcflags & SPCFLAG_DOTRACE)
5728: Exception(9);
5729:
5730: if (regs.spcflags & SPCFLAG_TRAP) {
5731: unset_special(SPCFLAG_TRAP);
5732: Exception(3);
5733: }
5734: bool first = true;
5735: while ((regs.spcflags & SPCFLAG_STOP) && !(regs.spcflags & SPCFLAG_BRK)) {
5736: if (regs.spcflags & (SPCFLAG_INT | SPCFLAG_DOINT)) {
5737: int intr = intlev();
5738: unset_special(SPCFLAG_INT | SPCFLAG_DOINT);
5739: if (intr > 0 && intr > regs.intmask)
5740: do_interrupt(intr);
5741: }
5742:
5743: if (regs.spcflags & SPCFLAG_MODE_CHANGE) {
5744: m68k_resumestopped();
5745: return 1;
5746: }
5747: }
5748:
5749: if (regs.spcflags & SPCFLAG_TRACE)
5750: do_trace();
5751:
5752: if (regs.spcflags & SPCFLAG_INT) {
5753: int intr = intlev();
5754: unset_special(SPCFLAG_INT | SPCFLAG_DOINT);
5755: if (intr > 0 && (intr > regs.intmask || intr == 7))
5756: do_interrupt(intr);
5757: }
5758:
5759: if (regs.spcflags & SPCFLAG_DOINT) {
5760: unset_special(SPCFLAG_DOINT);
5761: set_special(SPCFLAG_INT);
5762: }
5763:
5764: if (regs.spcflags & SPCFLAG_BRK) {
5765: return 1;
5766: }
5767:
5768: return 0;
5769: }
5770:
5771: void cpu_semaphore_get(void)
5772: {
5773: if (!currprefs.cpu_thread)
5774: return;
5775: DWORD tid = GetCurrentThreadId();
5776:
5777: if (tid == m68k_cs_owner) {
5778: m68k_spinlock_cnt++;
5779: return;
5780: }
5781:
5782: #ifdef _WIN32
5783: _InterlockedIncrement(&m68k_spinlock_waiting);
5784: EnterCriticalSection(&m68k_cs1);
5785: _InterlockedDecrement(&m68k_spinlock_waiting);
5786: m68k_cs_owner = tid;
5787: m68k_spinlock_cnt++;
5788: #else
5789: g_mutex_lock(&mutex); // FIXME
5790: #endif
5791: }
5792: void cpu_semaphore_release(void)
5793: {
5794: if (!currprefs.cpu_thread)
5795: return;
5796: #ifdef _WIN32
5797: m68k_spinlock_cnt--;
5798: if (m68k_spinlock_cnt == 0) {
5799: m68k_cs_owner = 0;
5800: LeaveCriticalSection(&m68k_cs1);
5801: }
5802: #else
5803: g_mutex_unlock(&mutex); // FIXME
5804: #endif
5805: }
5806:
5807: static void init_cpu_thread(void)
5808: {
5809: if (!currprefs.cpu_thread)
5810: return;
5811: #ifdef _WIN32
5812: if (m68k_cs_initialized) {
5813: DeleteCriticalSection(&m68k_cs1);
5814: }
5815: InitializeCriticalSectionAndSpinCount(&m68k_cs1, CRITICAL_SECTION_SPIN_COUNT);
5816: #endif
5817: }
5818:
5819: static void run_cpu_thread(void *(*f)(void *))
5820: {
5821: cpu_thread_active = 0;
5822: #if SPINLOCK_DEBUG
5823: m68k_spinlock_cnt = 0;
5824: #endif
5825: m68k_cs_initialized = true;
5826: if (uae_start_thread(_T("cpu"), f, NULL, NULL)) {
5827: while (!cpu_thread_active) {
5828: sleep_millis(1);
5829: }
5830: while (!(regs.spcflags & SPCFLAG_MODE_CHANGE)) {
5831:
5832: cpu_semaphore_get();
5833: frame_time_t c = read_processor_time();
5834: while (cpu_thread_active) {
5835: int vsynctimeperline = vsynctimebase / (maxvpos_display + 1);
5836:
5837: int vp = vpos;
5838: while ((int)read_processor_time() - (int)c > -vsynctimebase / 10) {
5839: if (vp != vpos) {
5840: vp = vpos;
5841: if (vpos + 1 == maxvpos + lof_store) {
5842: c = read_processor_time();
5843: }
5844: c += vsynctimeperline;
5845: }
5846: cycles_do_special();
5847: do_cycles(maxhpos / 2 * CYCLE_UNIT);
5848: if (regs.spcflags & SPCFLAG_COPPER) {
5849: do_copper();
5850: }
5851: #ifndef WINUAE_FOR_HATARI
5852: check_uae_int_request();
5853: #endif
5854: int w = m68k_spinlock_waiting;
5855: if (w) {
5856: cpu_semaphore_release();
5857: while (m68k_spinlock_waiting == w);
5858: cpu_semaphore_get();
5859: }
5860: }
5861: cpu_semaphore_release();
5862: sleep_millis(1);
5863: cpu_semaphore_get();
5864: while ((int)read_processor_time() - (int)c < 0) {
5865: #ifndef WINUAE_FOR_HATARI
5866: check_uae_int_request();
5867: #endif
5868: int w = m68k_spinlock_waiting;
5869: if (w) {
5870: cpu_semaphore_release();
5871: while (m68k_spinlock_waiting == w);
5872: cpu_semaphore_get();
5873: }
5874: }
5875: }
5876: cpu_semaphore_release();
5877:
5878: unset_special(SPCFLAG_BRK);
5879: #ifdef DEBUGGER
5880: if (debugging) {
5881: debug();
5882: }
5883: #endif
5884: }
5885: }
5886: }
5887: #endif
5888:
1.1.1.4 root 5889: #ifdef JIT /* Completely different run_2 replacement */
5890:
5891: void do_nothing (void)
5892: {
1.1.1.8 root 5893: if (!currprefs.cpu_thread) {
5894: /* What did you expect this to do? */
5895: do_cycles (0);
5896: /* I bet you didn't expect *that* ;-) */
5897: }
1.1.1.4 root 5898: }
5899:
5900: void exec_nostats (void)
5901: {
5902: struct regstruct *r = ®s;
5903:
5904: for (;;)
5905: {
1.1.1.7 root 5906: if (currprefs.cpu_compatible) {
5907: r->opcode = get_word_020_prefetchf(m68k_getpc());
5908: } else {
5909: r->opcode = x_get_iword(0);
5910: }
5911: cpu_cycles = (*cpufunctbl[r->opcode])(r->opcode);
5912: cpu_cycles = adjust_cycles (cpu_cycles);
1.1.1.8 root 5913:
5914: if (!currprefs.cpu_thread) {
5915: do_cycles (cpu_cycles);
1.1.1.4 root 5916:
1.1.1.7 root 5917: #ifdef WITH_PPC
1.1.1.8 root 5918: if (ppc_state)
5919: ppc_interrupt(intlev());
1.1.1.7 root 5920: #endif
1.1.1.8 root 5921: }
1.1.1.7 root 5922: #ifdef WINUAE_FOR_HATARI
5923: if (end_block(r->opcode) || r->spcflags)
5924: #else
5925:
1.1.1.8 root 5926: if (end_block(r->opcode) || r->spcflags || uae_int_requested)
1.1.1.7 root 5927: #endif
1.1.1.4 root 5928: return; /* We will deal with the spcflags in the caller */
5929: }
5930: }
5931:
5932: void execute_normal (void)
5933: {
5934: struct regstruct *r = ®s;
5935: int blocklen;
5936: cpu_history pc_hist[MAXRUN];
5937: int total_cycles;
5938:
5939: if (check_for_cache_miss ())
5940: return;
5941:
5942: total_cycles = 0;
5943: blocklen = 0;
5944: start_pc_p = r->pc_oldp;
5945: start_pc = r->pc;
5946: for (;;) {
5947: /* Take note: This is the do-it-normal loop */
1.1.1.7 root 5948: regs.instruction_pc = m68k_getpc ();
5949: if (currprefs.cpu_compatible) {
5950: r->opcode = get_word_020_prefetchf (regs.instruction_pc);
5951: } else {
5952: r->opcode = x_get_iword(0);
5953: }
1.1.1.4 root 5954:
5955: special_mem = DISTRUST_CONSISTENT_MEM;
5956: pc_hist[blocklen].location = (uae_u16*)r->pc_p;
5957:
1.1.1.7 root 5958: cpu_cycles = (*cpufunctbl[r->opcode])(r->opcode);
1.1.1.8 root 5959: cpu_cycles = adjust_cycles(cpu_cycles);
5960: if (!currprefs.cpu_thread) {
5961: do_cycles (cpu_cycles);
5962: }
1.1.1.4 root 5963: total_cycles += cpu_cycles;
5964: pc_hist[blocklen].specmem = special_mem;
5965: blocklen++;
1.1.1.7 root 5966: #ifdef WINUAE_FOR_HATARI
5967: if (end_block (r->opcode) || blocklen >= MAXRUN || r->spcflags) {
5968: #else
1.1.1.8 root 5969: if (end_block (r->opcode) || blocklen >= MAXRUN || r->spcflags || uae_int_requested) {
1.1.1.7 root 5970: #endif
1.1.1.4 root 5971: compile_block (pc_hist, blocklen, total_cycles);
5972: return; /* We will deal with the spcflags in the caller */
5973: }
5974: /* No need to check regs.spcflags, because if they were set,
5975: we'd have ended up inside that "if" */
1.1.1.7 root 5976:
5977: #ifdef WITH_PPC
5978: if (ppc_state)
5979: ppc_interrupt(intlev());
5980: #endif
1.1.1.4 root 5981: }
5982: }
5983:
5984: typedef void compiled_handler (void);
5985:
1.1.1.8 root 5986: #ifdef WITH_THREADED_CPU
5987: static void *cpu_thread_run_jit(void *v)
1.1.1.4 root 5988: {
1.1.1.8 root 5989: cpu_thread_active = 1;
5990: for (;;) {
5991: ((compiled_handler*)(pushall_call_handler))();
5992: /* Whenever we return from that, we should check spcflags */
5993: if (regs.spcflags) {
5994: if (do_specialties_thread()) {
5995: break;
5996: }
5997: }
5998: }
5999: cpu_thread_active = 0;
6000: return 0;
6001: }
6002: #endif
6003:
6004: static void m68k_run_jit(void)
6005: {
6006: Log_Printf(LOG_DEBUG, "m68k_run_jit\n");
6007: #ifdef WITH_THREADED_CPU
6008: if (currprefs.cpu_thread) {
6009: run_cpu_thread(cpu_thread_run_jit);
6010: return;
6011: }
6012: #endif
6013:
1.1.1.4 root 6014: for (;;) {
1.1.1.7 root 6015: #ifdef WINUAE_FOR_HATARI
6016: //m68k_dumpstate_file(stderr, NULL);
1.1.1.4 root 6017: if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM))
6018: {
6019: int FrameCycles, HblCounterVideo, LineCycles;
6020: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
6021: LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo );
1.1.1.7 root 6022: m68k_disasm_file(stderr, m68k_getpc (), NULL, 1);
1.1.1.4 root 6023: }
1.1.1.7 root 6024: #endif
1.1.1.4 root 6025:
6026: ((compiled_handler*)(pushall_call_handler))();
6027: /* Whenever we return from that, we should check spcflags */
1.1.1.7 root 6028: #ifndef WINUAE_FOR_HATARI
6029: check_uae_int_request();
6030: #endif
1.1.1.4 root 6031: if (regs.spcflags) {
6032: if (do_specialties (0)) {
6033: return;
6034: }
6035: }
6036: }
6037: }
6038: #endif /* JIT */
6039:
6040: #ifndef CPUEMU_0
6041:
6042: static void m68k_run_2 (void)
6043: {
6044: }
6045:
6046: #else
6047:
1.1.1.7 root 6048: static void opcodedebug (uae_u32 pc, uae_u16 opcode, bool full)
1.1.1.4 root 6049: {
6050: struct mnemolookup *lookup;
6051: struct instr *dp;
6052: uae_u32 addr;
6053: int fault;
6054:
6055: if (cpufunctbl[opcode] == op_illg_1)
6056: opcode = 0x4AFC;
6057: dp = table68k + opcode;
6058: for (lookup = lookuptab;lookup->mnemo != dp->mnemo; lookup++)
6059: ;
6060: fault = 0;
6061: TRY(prb) {
1.1.1.9 ! root 6062: addr = mmu_translate (pc, 0, (regs.mmu_ssw & 4) ? 1 : 0, 0, 0, sz_word);
1.1.1.4 root 6063: } CATCH (prb) {
6064: fault = 1;
6065: } ENDTRY
6066: if (!fault) {
1.1.1.7 root 6067: TCHAR buf[100];
6068: if (full)
6069: write_log (_T("mmufixup=%d %04x %04x\n"), mmufixup[0].reg, regs.wb3_status, regs.mmu_ssw);
6070: m68k_disasm_2 (buf, sizeof buf / sizeof (TCHAR), addr, NULL, 1, NULL, NULL, 0);
6071: write_log (_T("%s\n"), buf);
6072: if (full)
6073: m68k_dumpstate (NULL);
6074: }
6075: }
6076:
1.1.1.9 ! root 6077: static void check_halt(void)
! 6078: {
! 6079: if (regs.halted)
! 6080: do_specialties (0);
! 6081: }
! 6082:
1.1.1.7 root 6083: void cpu_halt (int id)
6084: {
6085: #ifndef WINUAE_FOR_HATARI
6086: // id < 0: m68k halted, PPC active.
6087: // id > 0: emulation halted.
6088: if (!regs.halted) {
6089: write_log (_T("CPU halted: reason = %d PC=%08x\n"), id, M68K_GETPC);
6090: regs.halted = id;
6091: gui_data.cpu_halted = id;
6092: gui_led(LED_CPU, 0, -1);
6093: if (id >= 0) {
6094: regs.intmask = 7;
6095: MakeSR ();
6096: audio_deactivate ();
6097: }
6098: }
1.1.1.9 ! root 6099: set_special(SPCFLAG_CHECK);
1.1.1.7 root 6100: #else
6101: Dialog_HaltDlg();
6102: #endif
6103: }
6104:
6105: #ifdef CPUEMU_33
6106: /* [NP] TODO : use 68060 in Hatari ? with DSP ? */
6107: /* MMU 68060 */
6108: static void m68k_run_mmu060 (void)
6109: {
6110: struct flag_struct f;
6111: int halt = 0;
1.1.1.8 root 6112:
1.1.1.9 ! root 6113: check_halt();
1.1.1.8 root 6114: #ifdef WINUAE_FOR_HATARI
6115: Log_Printf(LOG_DEBUG, "m68k_run_mmu060\n");
6116: #endif
1.1.1.7 root 6117:
6118: while (!halt) {
6119: TRY (prb) {
6120: for (;;) {
1.1.1.8 root 6121: #ifdef WINUAE_FOR_HATARI
6122: //m68k_dumpstate_file(stderr, NULL);
6123: if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM))
6124: {
6125: int FrameCycles, HblCounterVideo, LineCycles;
6126: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
6127: LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo );
6128: m68k_disasm_file(stderr, m68k_getpc (), NULL, 1);
6129: }
6130: #endif
1.1.1.7 root 6131: f.cznv = regflags.cznv;
6132: f.x = regflags.x;
6133: regs.instruction_pc = m68k_getpc ();
6134:
6135: do_cycles (cpu_cycles);
6136:
6137: mmu_opcode = -1;
6138: mmu060_state = 0;
6139: mmu_opcode = regs.opcode = x_prefetch (0);
6140: mmu060_state = 1;
6141:
6142: count_instr (regs.opcode);
6143: cpu_cycles = (*cpufunctbl[regs.opcode])(regs.opcode);
6144:
6145: cpu_cycles = adjust_cycles (cpu_cycles);
1.1.1.8 root 6146: #ifdef WINUAE_FOR_HATARI
6147: M68000_AddCycles(cpu_cycles * 2 / CYCLE_UNIT);
1.1.1.7 root 6148:
1.1.1.8 root 6149: if ( WaitStateCycles ) {
6150: /* Add some extra cycles to simulate a wait state */
6151: M68000_AddCycles(WaitStateCycles);
6152: WaitStateCycles = 0;
6153: }
6154:
6155: while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) && ( ( regs.spcflags & SPCFLAG_STOP ) == 0 ) )
6156: CALL_VAR(PendingInterruptFunction); /* call the interrupt handler */
6157: if ( MFP_UpdateNeeded == true )
6158: MFP_UpdateIRQ ( 0 );
6159: #endif
1.1.1.7 root 6160: if (regs.spcflags) {
6161: if (do_specialties (cpu_cycles))
6162: return;
6163: }
1.1.1.8 root 6164: #ifdef WINUAE_FOR_HATARI
6165: /* Run DSP 56k code if necessary */
6166: if (bDspEnabled) {
6167: DSP_Run(2 * cpu_cycles * 2 / CYCLE_UNIT);
6168: // DSP_Run ( DSP_CPU_FREQ_RATIO * ( CyclesGlobalClockCounter - DSP_CyclesGlobalClockCounter ) );
6169: }
6170: #endif
1.1.1.7 root 6171: }
6172: } CATCH (prb) {
6173:
6174: m68k_setpci (regs.instruction_pc);
6175: regflags.cznv = f.cznv;
6176: regflags.x = f.x;
6177:
6178: if (mmufixup[0].reg >= 0) {
6179: m68k_areg (regs, mmufixup[0].reg) = mmufixup[0].value;
6180: mmufixup[0].reg = -1;
6181: }
6182: if (mmufixup[1].reg >= 0) {
6183: m68k_areg (regs, mmufixup[1].reg) = mmufixup[1].value;
6184: mmufixup[1].reg = -1;
6185: }
6186:
6187: TRY (prb2) {
6188: Exception (prb);
6189: } CATCH (prb2) {
6190: halt = 1;
6191: } ENDTRY
6192: } ENDTRY
1.1.1.4 root 6193: }
1.1.1.7 root 6194: cpu_halt(halt);
1.1.1.4 root 6195: }
1.1.1.7 root 6196:
1.1.1.4 root 6197: #endif
6198:
1.1.1.7 root 6199: #ifdef CPUEMU_31
1.1.1.4 root 6200:
6201: /* Aranym MMU 68040 */
6202: static void m68k_run_mmu040 (void)
6203: {
1.1.1.7 root 6204: struct flag_struct f;
6205: int halt = 0;
1.1.1.8 root 6206:
1.1.1.9 ! root 6207: check_halt();
1.1.1.8 root 6208: #ifdef WINUAE_FOR_HATARI
6209: Log_Printf(LOG_DEBUG, "m68k_run_mmu040\n");
6210: #endif
1.1.1.7 root 6211:
6212: while (!halt) {
6213: TRY (prb) {
6214: for (;;) {
6215: #ifdef WINUAE_FOR_HATARI
6216: //m68k_dumpstate_file(stderr, NULL);
6217: if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM))
6218: {
6219: int FrameCycles, HblCounterVideo, LineCycles;
6220: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
6221: LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo );
6222: m68k_disasm_file(stderr, m68k_getpc (), NULL, 1);
6223: }
6224: #endif
6225: f.cznv = regflags.cznv;
6226: f.x = regflags.x;
6227: mmu_restart = true;
6228: regs.instruction_pc = m68k_getpc ();
6229:
6230: do_cycles (cpu_cycles);
6231:
6232: mmu_opcode = -1;
6233: mmu_opcode = regs.opcode = x_prefetch (0);
6234: count_instr (regs.opcode);
6235: cpu_cycles = (*cpufunctbl[regs.opcode])(regs.opcode);
6236: cpu_cycles = adjust_cycles (cpu_cycles);
6237:
6238: #ifdef WINUAE_FOR_HATARI
6239: M68000_AddCycles(cpu_cycles * 2 / CYCLE_UNIT);
6240:
1.1.1.8 root 6241: if ( WaitStateCycles ) {
1.1.1.7 root 6242: /* Add some extra cycles to simulate a wait state */
1.1.1.8 root 6243: M68000_AddCycles(WaitStateCycles);
6244: WaitStateCycles = 0;
1.1.1.7 root 6245: }
1.1.1.4 root 6246:
1.1.1.7 root 6247: /* We can have several interrupts at the same time before the next CPU instruction */
6248: /* We must check for pending interrupt and call do_specialties_interrupt() only */
6249: /* if the cpu is not in the STOP state. Else, the int could be acknowledged now */
6250: /* and prevent exiting the STOP state when calling do_specialties() after. */
6251: /* For performance, we first test PendingInterruptCount, then regs.spcflags */
6252: while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) && ( ( regs.spcflags & SPCFLAG_STOP ) == 0 ) )
6253: CALL_VAR(PendingInterruptFunction); /* call the interrupt handler */
6254: if ( MFP_UpdateNeeded == true )
6255: MFP_UpdateIRQ ( 0 );
6256: #endif
1.1.1.4 root 6257:
1.1.1.7 root 6258: if (regs.spcflags) {
6259: if (do_specialties (cpu_cycles))
6260: return;
1.1.1.4 root 6261: }
1.1.1.7 root 6262:
6263: #ifdef WINUAE_FOR_HATARI
6264: /* Run DSP 56k code if necessary */
6265: if (bDspEnabled) {
6266: DSP_Run(2 * cpu_cycles * 2 / CYCLE_UNIT);
1.1.1.8 root 6267: // DSP_Run ( DSP_CPU_FREQ_RATIO * ( CyclesGlobalClockCounter - DSP_CyclesGlobalClockCounter ) );
1.1.1.7 root 6268: }
6269: #endif
1.1.1.4 root 6270: }
1.1.1.7 root 6271: } CATCH (prb) {
6272:
6273: if (mmu_restart) {
6274: /* restore state if instruction restart */
6275: regflags.cznv = f.cznv;
6276: regflags.x = f.x;
6277: m68k_setpci (regs.instruction_pc);
1.1.1.4 root 6278: }
1.1.1.7 root 6279:
6280: if (mmufixup[0].reg >= 0) {
6281: m68k_areg (regs, mmufixup[0].reg) = mmufixup[0].value;
6282: mmufixup[0].reg = -1;
1.1.1.4 root 6283: }
1.1.1.7 root 6284:
6285: TRY (prb2) {
6286: Exception (prb);
6287: } CATCH (prb2) {
6288: halt = 1;
6289: } ENDTRY
6290: } ENDTRY
6291: }
6292: cpu_halt(halt);
6293: }
6294:
6295: #endif
6296:
6297: #ifdef CPUEMU_32
6298:
6299: // Previous MMU 68030
6300: static void m68k_run_mmu030 (void)
6301: {
6302: struct flag_struct f;
6303: int halt = 0;
1.1.1.8 root 6304:
6305: #ifdef WINUAE_FOR_HATARI
6306: Log_Printf(LOG_DEBUG, "m68k_run_mmu030\n");
6307: #endif
1.1.1.7 root 6308:
6309: mmu030_opcode_stageb = -1;
6310: mmu030_fake_prefetch = -1;
1.1.1.9 ! root 6311: check_halt();
1.1.1.7 root 6312: while(!halt) {
6313: TRY (prb) {
6314: for (;;) {
6315: int cnt;
6316: insretry:
6317: #ifdef WINUAE_FOR_HATARI
6318: //m68k_dumpstate_file(stderr, NULL);
6319: if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM))
6320: {
6321: int FrameCycles, HblCounterVideo, LineCycles;
6322: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
6323: LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo );
6324: m68k_disasm_file(stderr, m68k_getpc (), NULL, 1);
1.1.1.4 root 6325: }
6326: #endif
1.1.1.7 root 6327: regs.instruction_pc = m68k_getpc ();
6328: f.cznv = regflags.cznv;
6329: f.x = regflags.x;
6330:
6331: mmu030_state[0] = mmu030_state[1] = mmu030_state[2] = 0;
6332: mmu030_opcode = -1;
6333: if (mmu030_fake_prefetch >= 0) {
6334: // use fake prefetch opcode only if mapping changed
6335: uaecptr new_addr = mmu030_translate(regs.instruction_pc, regs.s != 0, false, false);
6336: if (mmu030_fake_prefetch_addr != new_addr) {
6337: regs.opcode = mmu030_fake_prefetch;
1.1.1.8 root 6338: 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 6339: } else {
6340: if (mmu030_opcode_stageb < 0) {
6341: regs.opcode = x_prefetch (0);
6342: } else {
6343: regs.opcode = mmu030_opcode_stageb;
6344: mmu030_opcode_stageb = -1;
6345: }
6346: }
6347: mmu030_fake_prefetch = -1;
6348: } else if (mmu030_opcode_stageb < 0) {
1.1.1.9 ! root 6349: if (currprefs.cpu_compatible)
! 6350: regs.opcode = regs.irc;
! 6351: else
! 6352: regs.opcode = x_prefetch (0);
1.1.1.7 root 6353: } else {
6354: regs.opcode = mmu030_opcode_stageb;
6355: mmu030_opcode_stageb = -1;
6356: }
6357:
6358: mmu030_opcode = regs.opcode;
6359: mmu030_ad[0].done = false;
6360:
6361: cnt = 50;
6362: for (;;) {
1.1.1.9 ! root 6363: regs.opcode = regs.irc = mmu030_opcode;
1.1.1.7 root 6364: mmu030_idx = 0;
1.1.1.9 ! root 6365:
1.1.1.7 root 6366: mmu030_retry = false;
6367:
1.1.1.9 ! root 6368: if (!currprefs.cpu_cycle_exact) {
! 6369:
! 6370: count_instr (regs.opcode);
! 6371: do_cycles (cpu_cycles);
! 6372:
! 6373: cpu_cycles = (*cpufunctbl[regs.opcode])(regs.opcode);
! 6374:
! 6375: } else {
! 6376: #ifdef WINUAE_FOR_HATARI
! 6377: currcycle = 0;
! 6378: #endif
! 6379: (*cpufunctbl[regs.opcode])(regs.opcode);
! 6380:
! 6381: wait_memory_cycles();
! 6382: }
! 6383:
1.1.1.7 root 6384: cnt--; // so that we don't get in infinite loop if things go horribly wrong
6385: if (!mmu030_retry)
6386: break;
6387: if (cnt < 0) {
1.1.1.8 root 6388: cpu_halt (CPU_HALT_CPU_STUCK);
1.1.1.7 root 6389: break;
6390: }
6391: if (mmu030_retry && mmu030_opcode == -1)
6392: goto insretry; // urgh
6393: }
1.1.1.4 root 6394:
1.1.1.7 root 6395: mmu030_opcode = -1;
1.1.1.4 root 6396:
1.1.1.9 ! root 6397: if (!currprefs.cpu_cycle_exact) {
1.1.1.4 root 6398:
1.1.1.9 ! root 6399: cpu_cycles = adjust_cycles (cpu_cycles);
1.1.1.7 root 6400: #ifdef WINUAE_FOR_HATARI
1.1.1.9 ! root 6401: M68000_AddCycles(cpu_cycles * 2 / CYCLE_UNIT);
1.1.1.4 root 6402:
1.1.1.9 ! root 6403: if ( WaitStateCycles ) {
! 6404: /* Add some extra cycles to simulate a wait state */
! 6405: M68000_AddCycles(WaitStateCycles);
! 6406: WaitStateCycles = 0;
! 6407: }
1.1.1.7 root 6408:
1.1.1.9 ! root 6409: /* We can have several interrupts at the same time before the next CPU instruction */
! 6410: /* We must check for pending interrupt and call do_specialties_interrupt() only */
! 6411: /* if the cpu is not in the STOP state. Else, the int could be acknowledged now */
! 6412: /* and prevent exiting the STOP state when calling do_specialties() after. */
! 6413: /* For performance, we first test PendingInterruptCount, then regs.spcflags */
! 6414: while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) && ( ( regs.spcflags & SPCFLAG_STOP ) == 0 ) )
! 6415: CALL_VAR(PendingInterruptFunction); /* call the interrupt handler */
! 6416: if ( MFP_UpdateNeeded == true )
! 6417: MFP_UpdateIRQ ( 0 );
1.1.1.7 root 6418: #endif
1.1.1.9 ! root 6419: if (regs.spcflags) {
! 6420: if (do_specialties (cpu_cycles))
! 6421: return;
! 6422: }
1.1.1.7 root 6423: #ifdef WINUAE_FOR_HATARI
6424: /* Run DSP 56k code if necessary */
6425: if (bDspEnabled) {
6426: DSP_Run(2 * cpu_cycles * 2 / CYCLE_UNIT);
1.1.1.8 root 6427: // DSP_Run ( DSP_CPU_FREQ_RATIO * ( CyclesGlobalClockCounter - DSP_CyclesGlobalClockCounter ) );
1.1.1.7 root 6428: }
6429: #endif
6430:
1.1.1.9 ! root 6431: } else {
! 6432:
! 6433: #ifdef WINUAE_FOR_HATARI
! 6434: //fprintf ( stderr, "cyc_2ce %d\n" , currcycle );
! 6435: /* Flush all CE cycles so far to update PendingInterruptCount */
! 6436: M68000_AddCycles_CE ( currcycle * 2 / CYCLE_UNIT );
! 6437: // currcycle = 0; // FIXME : uncomment this when using DSP_CyclesGlobalClockCounter in DSP_Run
! 6438:
! 6439: /* We can have several interrupts at the same time before the next CPU instruction */
! 6440: /* We must check for pending interrupt and call do_specialties_interrupt() only */
! 6441: /* if the cpu is not in the STOP state. Else, the int could be acknowledged now */
! 6442: /* and prevent exiting the STOP state when calling do_specialties() after. */
! 6443: /* For performance, we first test PendingInterruptCount, then regs.spcflags */
! 6444: while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) && ( ( regs.spcflags & SPCFLAG_STOP ) == 0 ) )
! 6445: CALL_VAR(PendingInterruptFunction); /* call the interrupt handler */
! 6446: if ( MFP_UpdateNeeded == true )
! 6447: MFP_UpdateIRQ ( 0 );
! 6448: #endif
! 6449:
! 6450: if (regs.spcflags || time_for_interrupt ()) {
! 6451: if (do_specialties (0))
! 6452: return;
! 6453: }
! 6454:
! 6455: #ifdef WINUAE_FOR_HATARI
! 6456: /* Run DSP 56k code if necessary */
! 6457: if (bDspEnabled) {
! 6458: //fprintf ( stderr, "dsp cyc_2ce %d\n" , currcycle );
! 6459: DSP_Run(2 * currcycle * 2 / CYCLE_UNIT);
! 6460: //fprintf ( stderr, "dsp cyc_2ce %d - %d\n" , currcycle * 2 / CYCLE_UNIT , (CyclesGlobalClockCounter - DSP_CyclesGlobalClockCounter) );
! 6461: // DSP_Run ( DSP_CPU_FREQ_RATIO * ( CyclesGlobalClockCounter - DSP_CyclesGlobalClockCounter ) );
! 6462: }
! 6463: #endif
! 6464:
! 6465: regs.ipl = regs.ipl_pin;
! 6466:
! 6467: }
! 6468:
! 6469: }
! 6470:
! 6471: } CATCH (prb) {
! 6472:
! 6473: if (mmu030_opcode == -1 && currprefs.cpu_compatible) {
! 6474: // full prefetch fill access fault
! 6475: // TODO: this should create shorter A-frame
! 6476: mmufixup[0].reg = -1;
! 6477: mmufixup[1].reg = -1;
! 6478: } else {
! 6479: regflags.cznv = f.cznv;
! 6480: regflags.x = f.x;
! 6481:
! 6482: if (mmufixup[0].reg >= 0) {
! 6483: m68k_areg (regs, mmufixup[0].reg) = mmufixup[0].value;
! 6484: mmufixup[0].reg = -1;
! 6485: }
! 6486: if (mmufixup[1].reg >= 0) {
! 6487: m68k_areg (regs, mmufixup[1].reg) = mmufixup[1].value;
! 6488: mmufixup[1].reg = -1;
! 6489: }
! 6490: }
! 6491:
! 6492: m68k_setpci (regs.instruction_pc);
! 6493:
! 6494: TRY (prb2) {
! 6495: Exception (prb);
! 6496: } CATCH (prb2) {
! 6497: halt = 1;
! 6498: } ENDTRY
! 6499: } ENDTRY
! 6500: }
! 6501: cpu_halt (halt);
! 6502: }
1.1.1.7 root 6503:
6504: #endif
6505:
6506:
6507: /* "cycle exact" 68040/060 */
6508:
6509: static void m68k_run_3ce (void)
6510: {
6511: struct regstruct *r = ®s;
6512: bool exit = false;
1.1.1.8 root 6513:
6514: Log_Printf(LOG_DEBUG, "m68k_run_3ce\n");
1.1.1.7 root 6515:
6516: while (!exit) {
6517: TRY(prb) {
6518: while (!exit) {
6519: #ifdef WINUAE_FOR_HATARI
6520: //m68k_dumpstate_file(stderr, NULL);
6521: if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM))
6522: {
6523: int FrameCycles, HblCounterVideo, LineCycles;
6524: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
6525: LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo );
6526: m68k_disasm_file(stderr, m68k_getpc (), NULL, 1);
6527: }
1.1.1.8 root 6528: currcycle = CYCLE_UNIT / 2; /* Assume at least 1 cycle per instruction */
1.1.1.7 root 6529: #endif
6530: r->instruction_pc = m68k_getpc();
6531: r->opcode = get_iword_cache_040(0);
6532: // "prefetch"
6533: if (regs.cacr & 0x8000)
6534: fill_icache040(r->instruction_pc + 16);
6535:
6536: (*cpufunctbl[r->opcode])(r->opcode);
6537:
6538: #ifdef WINUAE_FOR_HATARI
1.1.1.8 root 6539: //fprintf ( stderr, "cyc_3ce %ld\n" , currcycle );
6540: /* Flush all CE cycles so far to update PendingInterruptCount */
6541: M68000_AddCycles_CE ( currcycle * 2 / CYCLE_UNIT );
6542: // currcycle = 0; // FIXME : uncomment this when using DSP_CyclesGlobalClockCounter in DSP_Run
1.1.1.7 root 6543:
6544: /* We can have several interrupts at the same time before the next CPU instruction */
6545: /* We must check for pending interrupt and call do_specialties_interrupt() only */
6546: /* if the cpu is not in the STOP state. Else, the int could be acknowledged now */
6547: /* and prevent exiting the STOP state when calling do_specialties() after. */
6548: /* For performance, we first test PendingInterruptCount, then regs.spcflags */
6549: while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) && ( ( regs.spcflags & SPCFLAG_STOP ) == 0 ) )
6550: CALL_VAR(PendingInterruptFunction); /* call the interrupt handler */
6551: if ( MFP_UpdateNeeded == true )
6552: MFP_UpdateIRQ ( 0 );
6553: #endif
6554: if (r->spcflags) {
6555: if (do_specialties (0))
6556: exit = true;
6557: }
6558:
6559: #ifdef WINUAE_FOR_HATARI
6560: /* Run DSP 56k code if necessary */
6561: if (bDspEnabled) {
6562: DSP_Run(2 * currcycle * 2 / CYCLE_UNIT);
1.1.1.8 root 6563: // DSP_Run ( DSP_CPU_FREQ_RATIO * ( CyclesGlobalClockCounter - DSP_CyclesGlobalClockCounter ) );
1.1.1.4 root 6564: }
1.1.1.7 root 6565: #endif
1.1.1.4 root 6566: }
1.1.1.7 root 6567: } CATCH(prb) {
6568: bus_error();
6569: if (r->spcflags) {
6570: if (do_specialties(0))
6571: exit = true;
6572: }
6573: } ENDTRY
6574: }
6575: }
1.1.1.4 root 6576:
1.1.1.7 root 6577: /* "prefetch" 68040/060 */
1.1.1.4 root 6578:
1.1.1.7 root 6579: static void m68k_run_3p(void)
6580: {
6581: struct regstruct *r = ®s;
6582: bool exit = false;
6583: int cycles;
1.1.1.8 root 6584:
6585: Log_Printf(LOG_DEBUG, "m68k_run_3p\n");
1.1.1.7 root 6586:
6587: while (!exit) {
6588: TRY(prb) {
6589: while (!exit) {
6590: #ifdef WINUAE_FOR_HATARI
6591: //m68k_dumpstate_file(stderr, NULL);
6592: if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM))
6593: {
6594: int FrameCycles, HblCounterVideo, LineCycles;
6595: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
6596: LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo );
6597: m68k_disasm_file(stderr, m68k_getpc (), NULL, 1);
6598: }
6599: #endif
6600: r->instruction_pc = m68k_getpc();
6601: r->opcode = get_iword_cache_040(0);
6602: // "prefetch"
6603: if (regs.cacr & 0x8000)
6604: fill_icache040(r->instruction_pc + 16);
6605:
6606: (*cpufunctbl[r->opcode])(r->opcode);
6607:
1.1.1.8 root 6608: #ifndef WINUAE_FOR_HATARI
1.1.1.7 root 6609: cpu_cycles = 1 * CYCLE_UNIT;
6610: cycles = adjust_cycles(cpu_cycles);
6611: do_cycles(cycles);
1.1.1.8 root 6612: #else
6613: cycles = cpu_cycles = CYCLE_UNIT / 2;
6614: M68000_AddCycles_CE(cycles * 2 / CYCLE_UNIT);
1.1.1.7 root 6615:
1.1.1.8 root 6616: if ( WaitStateCycles ) {
1.1.1.7 root 6617: /* Add some extra cycles to simulate a wait state */
1.1.1.8 root 6618: M68000_AddCycles(WaitStateCycles);
6619: WaitStateCycles = 0;
1.1.1.7 root 6620: }
1.1.1.4 root 6621:
1.1.1.7 root 6622: /* We can have several interrupts at the same time before the next CPU instruction */
6623: /* We must check for pending interrupt and call do_specialties_interrupt() only */
6624: /* if the cpu is not in the STOP state. Else, the int could be acknowledged now */
6625: /* and prevent exiting the STOP state when calling do_specialties() after. */
6626: /* For performance, we first test PendingInterruptCount, then regs.spcflags */
6627: while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) && ( ( regs.spcflags & SPCFLAG_STOP ) == 0 ) )
6628: CALL_VAR(PendingInterruptFunction); /* call the interrupt handler */
6629: if ( MFP_UpdateNeeded == true )
6630: MFP_UpdateIRQ ( 0 );
6631: #endif
6632:
6633: if (r->spcflags) {
6634: if (do_specialties(0))
6635: exit = true;
6636: }
6637:
6638: #ifdef WINUAE_FOR_HATARI
6639: /* Run DSP 56k code if necessary */
6640: if (bDspEnabled) {
6641: DSP_Run(2 * cycles * 2 / CYCLE_UNIT);
1.1.1.8 root 6642: // DSP_Run ( DSP_CPU_FREQ_RATIO * ( CyclesGlobalClockCounter - DSP_CyclesGlobalClockCounter ) );
1.1.1.7 root 6643: }
6644: #endif
6645: }
6646: } CATCH(prb) {
6647: bus_error();
6648: if (r->spcflags) {
6649: if (do_specialties(0))
6650: exit = true;
6651: }
6652: } ENDTRY
6653: }
1.1.1.4 root 6654: }
6655:
6656: /* "cycle exact" 68020/030 */
1.1.1.7 root 6657:
6658: STATIC_INLINE struct cache030 *getcache030 (struct cache030 *cp, uaecptr addr, uae_u32 *tagp, int *lwsp);
1.1.1.4 root 6659: static void m68k_run_2ce (void)
6660: {
6661: struct regstruct *r = ®s;
1.1.1.7 root 6662: bool exit = false;
6663: bool first = true;
1.1.1.8 root 6664:
6665: Log_Printf(LOG_DEBUG, "m68k_run_2ce\n");
1.1.1.7 root 6666:
6667: while (!exit) {
6668: TRY(prb) {
6669: if (first) {
6670: if (cpu_tracer < 0) {
6671: memcpy (&r->regs, &cputrace.regs, 16 * sizeof (uae_u32));
6672: r->ir = cputrace.ir;
6673: r->irc = cputrace.irc;
6674: r->sr = cputrace.sr;
6675: r->usp = cputrace.usp;
6676: r->isp = cputrace.isp;
6677: r->intmask = cputrace.intmask;
6678: r->stopped = cputrace.stopped;
6679:
6680: r->msp = cputrace.msp;
6681: r->vbr = cputrace.vbr;
6682: r->caar = cputrace.caar;
6683: r->cacr = cputrace.cacr;
6684: r->cacheholdingdata020 = cputrace.cacheholdingdata020;
6685: r->cacheholdingaddr020 = cputrace.cacheholdingaddr020;
6686: r->prefetch020addr = cputrace.prefetch020addr;
1.1.1.9 ! root 6687: memcpy(&r->prefetch020, &cputrace.prefetch020, CPU_PIPELINE_MAX * sizeof(uae_u16));
! 6688: memcpy(&r->prefetch020_valid, &cputrace.prefetch020_valid, CPU_PIPELINE_MAX * sizeof(uae_u8));
! 6689: memcpy(&caches020, &cputrace.caches020, sizeof caches020);
1.1.1.7 root 6690:
6691: m68k_setpc (cputrace.pc);
6692: if (!r->stopped) {
6693: if (cputrace.state > 1)
6694: Exception (cputrace.state);
6695: else if (cputrace.state == 1)
6696: (*cpufunctbl[cputrace.opcode])(cputrace.opcode);
6697: }
6698: if (regs.stopped)
6699: set_special (SPCFLAG_STOP);
6700: set_cpu_tracer (false);
6701: goto cont;
6702: }
6703: set_cpu_tracer (false);
6704: first = false;
6705: }
1.1.1.4 root 6706:
1.1.1.7 root 6707: while (!exit) {
1.1.1.8 root 6708: #if 0
1.1.1.7 root 6709: static int prevopcode;
1.1.1.8 root 6710: #endif
1.1.1.7 root 6711: #ifdef WINUAE_FOR_HATARI
6712: //m68k_dumpstate_file(stderr, NULL);
6713: if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM))
6714: {
6715: int FrameCycles, HblCounterVideo, LineCycles;
6716: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
6717: LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo );
6718: m68k_disasm_file(stderr, m68k_getpc (), NULL, 1);
6719: #if 0
6720: // logs to debug data cache issues
6721: struct cache030 *c1 ,*c2;
6722: int lws1, lws2;
6723: uae_u32 tag1, tag2;
6724: c1 = getcache030 (dcaches030, (uaecptr)0x27ece, &tag1, &lws1);
6725: c2 = getcache030 (dcaches030, (uaecptr)0x7f8192+4, &tag2, &lws2);
6726: 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) );
6727: //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) );
6728: #endif
6729: }
1.1.1.4 root 6730:
1.1.1.7 root 6731: currcycle = 0;
6732: #endif
6733: r->instruction_pc = m68k_getpc ();
1.1.1.4 root 6734:
1.1.1.8 root 6735: #if 0
1.1.1.7 root 6736: if (regs.irc == 0xfffb) {
6737: gui_message (_T("OPCODE %04X HAS FAULTY PREFETCH! PC=%08X"), prevopcode, r->instruction_pc);
6738: }
1.1.1.8 root 6739: #endif
1.1.1.4 root 6740:
1.1.1.7 root 6741: //write_log (_T("%x %04x\n"), r->instruction_pc, regs.irc);
1.1.1.4 root 6742:
1.1.1.7 root 6743: r->opcode = regs.irc;
1.1.1.8 root 6744: #if 0
1.1.1.7 root 6745: prevopcode = r->opcode;
6746: regs.irc = 0xfffb;
1.1.1.8 root 6747: #endif
1.1.1.7 root 6748: //write_log (_T("%08x %04x\n"), r->instruction_pc, opcode);
1.1.1.5 root 6749:
1.1.1.7 root 6750: #ifndef WINUAE_FOR_HATARI
6751: #if DEBUG_CD32CDTVIO
6752: out_cd32io (r->instruction_pc);
6753: #endif
6754: #endif
1.1.1.4 root 6755:
1.1.1.7 root 6756: if (cpu_tracer) {
1.1.1.4 root 6757:
1.1.1.7 root 6758: #if CPUTRACE_DEBUG
6759: validate_trace ();
6760: #endif
6761: memcpy (&cputrace.regs, &r->regs, 16 * sizeof (uae_u32));
6762: cputrace.opcode = r->opcode;
6763: cputrace.ir = r->ir;
6764: cputrace.irc = r->irc;
6765: cputrace.sr = r->sr;
6766: cputrace.usp = r->usp;
6767: cputrace.isp = r->isp;
6768: cputrace.intmask = r->intmask;
6769: cputrace.stopped = r->stopped;
6770: cputrace.state = 1;
6771: cputrace.pc = m68k_getpc ();
6772:
6773: cputrace.msp = r->msp;
6774: cputrace.vbr = r->vbr;
6775: cputrace.caar = r->caar;
6776: cputrace.cacr = r->cacr;
6777: cputrace.cacheholdingdata020 = r->cacheholdingdata020;
6778: cputrace.cacheholdingaddr020 = r->cacheholdingaddr020;
6779: cputrace.prefetch020addr = r->prefetch020addr;
1.1.1.9 ! root 6780: memcpy(&cputrace.prefetch020, &r->prefetch020, CPU_PIPELINE_MAX * sizeof (uae_u16));
! 6781: memcpy(&cputrace.prefetch020_valid, &r->prefetch020_valid, CPU_PIPELINE_MAX * sizeof(uae_u8));
! 6782: memcpy(&cputrace.caches020, &caches020, sizeof caches020);
1.1.1.7 root 6783:
6784: cputrace.memoryoffset = 0;
6785: cputrace.cyclecounter = cputrace.cyclecounter_pre = cputrace.cyclecounter_post = 0;
6786: cputrace.readcounter = cputrace.writecounter = 0;
6787: }
1.1.1.4 root 6788:
1.1.1.7 root 6789: #ifndef WINUAE_FOR_HATARI
6790: if (inputrecord_debug & 4) {
6791: if (input_record > 0)
6792: inprec_recorddebug_cpu (1);
6793: else if (input_play > 0)
6794: inprec_playdebug_cpu (1);
6795: }
6796: #endif
1.1.1.4 root 6797:
1.1.1.7 root 6798: (*cpufunctbl[r->opcode])(r->opcode);
6799:
6800: wait_memory_cycles();
6801:
1.1.1.8 root 6802: #ifdef WINUAE_FOR_HATARI
6803: //fprintf ( stderr, "cyc_2ce %d\n" , currcycle );
6804: /* Flush all CE cycles so far to update PendingInterruptCount */
6805: M68000_AddCycles_CE ( currcycle * 2 / CYCLE_UNIT );
6806: // currcycle = 0; // FIXME : uncomment this when using DSP_CyclesGlobalClockCounter in DSP_Run
1.1.1.4 root 6807:
1.1.1.7 root 6808: /* We can have several interrupts at the same time before the next CPU instruction */
6809: /* We must check for pending interrupt and call do_specialties_interrupt() only */
6810: /* if the cpu is not in the STOP state. Else, the int could be acknowledged now */
6811: /* and prevent exiting the STOP state when calling do_specialties() after. */
6812: /* For performance, we first test PendingInterruptCount, then regs.spcflags */
6813: while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) && ( ( regs.spcflags & SPCFLAG_STOP ) == 0 ) )
6814: CALL_VAR(PendingInterruptFunction); /* call the interrupt handler */
6815: if ( MFP_UpdateNeeded == true )
6816: MFP_UpdateIRQ ( 0 );
6817: #endif
1.1.1.4 root 6818:
1.1.1.9 ! root 6819: cont:
1.1.1.7 root 6820: if (r->spcflags || time_for_interrupt ()) {
6821: if (do_specialties (0))
6822: exit = true;
6823: }
1.1.1.4 root 6824:
1.1.1.7 root 6825: #ifdef WINUAE_FOR_HATARI
6826: /* Run DSP 56k code if necessary */
6827: if (bDspEnabled) {
6828: //fprintf ( stderr, "dsp cyc_2ce %d\n" , currcycle );
6829: DSP_Run(2 * currcycle * 2 / CYCLE_UNIT);
1.1.1.8 root 6830: //fprintf ( stderr, "dsp cyc_2ce %d - %d\n" , currcycle * 2 / CYCLE_UNIT , (CyclesGlobalClockCounter - DSP_CyclesGlobalClockCounter) );
6831: // DSP_Run ( DSP_CPU_FREQ_RATIO * ( CyclesGlobalClockCounter - DSP_CyclesGlobalClockCounter ) );
1.1.1.7 root 6832: }
6833: #endif
1.1.1.4 root 6834:
1.1.1.7 root 6835: regs.ipl = regs.ipl_pin;
1.1.1.4 root 6836:
1.1.1.7 root 6837: }
6838: } CATCH(prb) {
6839: bus_error();
6840: if (r->spcflags || time_for_interrupt()) {
1.1.1.9 ! root 6841: if (do_specialties(0))
1.1.1.7 root 6842: exit = true;
6843: }
1.1.1.9 ! root 6844: regs.ipl = regs.ipl_pin;
1.1.1.7 root 6845: } ENDTRY
1.1.1.4 root 6846: }
6847: }
6848:
1.1.1.7 root 6849: #ifdef CPUEMU_20
6850:
6851: // full prefetch 020 (more compatible)
1.1.1.4 root 6852: static void m68k_run_2p (void)
6853: {
6854: struct regstruct *r = ®s;
1.1.1.7 root 6855: bool exit = false;
1.1.1.8 root 6856: bool first = true;
6857:
6858: Log_Printf(LOG_DEBUG, "m68k_run_2p\n");
1.1.1.4 root 6859:
1.1.1.7 root 6860: while (!exit) {
6861: TRY(prb) {
1.1.1.8 root 6862:
6863: if (first) {
6864: if (cpu_tracer < 0) {
6865: memcpy (&r->regs, &cputrace.regs, 16 * sizeof (uae_u32));
6866: r->ir = cputrace.ir;
6867: r->irc = cputrace.irc;
6868: r->sr = cputrace.sr;
6869: r->usp = cputrace.usp;
6870: r->isp = cputrace.isp;
6871: r->intmask = cputrace.intmask;
6872: r->stopped = cputrace.stopped;
6873:
6874: r->msp = cputrace.msp;
6875: r->vbr = cputrace.vbr;
6876: r->caar = cputrace.caar;
6877: r->cacr = cputrace.cacr;
6878: r->cacheholdingdata020 = cputrace.cacheholdingdata020;
6879: r->cacheholdingaddr020 = cputrace.cacheholdingaddr020;
6880: r->prefetch020addr = cputrace.prefetch020addr;
1.1.1.9 ! root 6881: memcpy(&r->prefetch020, &cputrace.prefetch020, CPU_PIPELINE_MAX * sizeof(uae_u16));
! 6882: memcpy(&r->prefetch020_valid, &cputrace.prefetch020_valid, CPU_PIPELINE_MAX * sizeof(uae_u8));
! 6883: memcpy(&caches020, &cputrace.caches020, sizeof caches020);
1.1.1.8 root 6884:
6885: m68k_setpc (cputrace.pc);
6886: if (!r->stopped) {
6887: if (cputrace.state > 1)
6888: Exception (cputrace.state);
6889: else if (cputrace.state == 1)
6890: (*cpufunctbl[cputrace.opcode])(cputrace.opcode);
6891: }
6892: if (regs.stopped)
6893: set_special (SPCFLAG_STOP);
6894: set_cpu_tracer (false);
6895: goto cont;
6896: }
6897: set_cpu_tracer (false);
6898: first = false;
6899: }
6900:
1.1.1.7 root 6901: while (!exit) {
6902: #ifdef WINUAE_FOR_HATARI
6903: //m68k_dumpstate_file(stderr, NULL);
6904: if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM))
6905: {
6906: int FrameCycles, HblCounterVideo, LineCycles;
6907: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
6908: LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo );
6909: m68k_disasm_file(stderr, m68k_getpc (), NULL, 1);
6910: }
6911: #endif
6912: r->instruction_pc = m68k_getpc ();
1.1.1.8 root 6913: r->opcode = regs.irc;
1.1.1.4 root 6914:
1.1.1.7 root 6915: #ifndef WINUAE_FOR_HATARI
1.1.1.4 root 6916: #if DEBUG_CD32CDTVIO
1.1.1.7 root 6917: out_cd32io (m68k_getpc ());
6918: #endif
1.1.1.4 root 6919: #endif
6920:
1.1.1.8 root 6921: if (cpu_tracer) {
1.1.1.4 root 6922:
1.1.1.8 root 6923: #if CPUTRACE_DEBUG
6924: validate_trace ();
6925: #endif
6926: memcpy (&cputrace.regs, &r->regs, 16 * sizeof (uae_u32));
6927: cputrace.opcode = r->opcode;
6928: cputrace.ir = r->ir;
6929: cputrace.irc = r->irc;
6930: cputrace.sr = r->sr;
6931: cputrace.usp = r->usp;
6932: cputrace.isp = r->isp;
6933: cputrace.intmask = r->intmask;
6934: cputrace.stopped = r->stopped;
6935: cputrace.state = 1;
6936: cputrace.pc = m68k_getpc ();
6937:
6938: cputrace.msp = r->msp;
6939: cputrace.vbr = r->vbr;
6940: cputrace.caar = r->caar;
6941: cputrace.cacr = r->cacr;
6942: cputrace.cacheholdingdata020 = r->cacheholdingdata020;
6943: cputrace.cacheholdingaddr020 = r->cacheholdingaddr020;
6944: cputrace.prefetch020addr = r->prefetch020addr;
1.1.1.9 ! root 6945: memcpy(&cputrace.prefetch020, &r->prefetch020, CPU_PIPELINE_MAX * sizeof(uae_u16));
! 6946: memcpy(&cputrace.prefetch020_valid, &r->prefetch020_valid, CPU_PIPELINE_MAX * sizeof(uae_u8));
! 6947: memcpy(&cputrace.caches020, &caches020, sizeof caches020);
1.1.1.8 root 6948:
6949: cputrace.memoryoffset = 0;
6950: cputrace.cyclecounter = cputrace.cyclecounter_pre = cputrace.cyclecounter_post = 0;
6951: cputrace.readcounter = cputrace.writecounter = 0;
6952: }
6953:
6954: #ifndef WINUAE_FOR_HATARI
6955: if (inputrecord_debug & 4) {
6956: if (input_record > 0)
6957: inprec_recorddebug_cpu (1);
6958: else if (input_play > 0)
6959: inprec_playdebug_cpu (1);
6960: }
6961: #endif
1.1.1.9 ! root 6962: if (currprefs.cpu_memory_cycle_exact) {
1.1.1.8 root 6963:
1.1.1.9 ! root 6964: (*cpufunctbl[r->opcode])(r->opcode);
! 6965: cpu_cycles = 0;
1.1.1.4 root 6966:
1.1.1.9 ! root 6967: } else {
! 6968:
! 6969: x_do_cycles (cpu_cycles);
! 6970:
! 6971: cpu_cycles = (*cpufunctbl[r->opcode])(r->opcode);
! 6972: cpu_cycles = adjust_cycles (cpu_cycles);
! 6973:
! 6974: }
1.1.1.8 root 6975: cont:
1.1.1.7 root 6976: #ifdef WINUAE_FOR_HATARI
1.1.1.8 root 6977: //fprintf ( stderr , "waits %d %d %ld\n" , cpu_cycles*2/CYCLE_UNIT , WaitStateCycles , CyclesGlobalClockCounter );
1.1.1.7 root 6978: M68000_AddCycles(cpu_cycles * 2 / CYCLE_UNIT);
1.1.1.4 root 6979:
1.1.1.8 root 6980: //fprintf ( stderr , "waits %d %d %ld\n" , cpu_cycles*2/CYCLE_UNIT , WaitStateCycles , CyclesGlobalClockCounter );
6981: if ( WaitStateCycles ) {
1.1.1.7 root 6982: /* Add some extra cycles to simulate a wait state */
1.1.1.8 root 6983: M68000_AddCycles(WaitStateCycles);
6984: WaitStateCycles = 0;
1.1.1.7 root 6985: }
1.1.1.8 root 6986: //fprintf ( stderr , "waits %d %d %ld\n" , cpu_cycles*2/CYCLE_UNIT , WaitStateCycles , CyclesGlobalClockCounter );
1.1.1.4 root 6987:
1.1.1.7 root 6988: /* We can have several interrupts at the same time before the next CPU instruction */
6989: /* We must check for pending interrupt and call do_specialties_interrupt() only */
6990: /* if the cpu is not in the STOP state. Else, the int could be acknowledged now */
6991: /* and prevent exiting the STOP state when calling do_specialties() after. */
6992: /* For performance, we first test PendingInterruptCount, then regs.spcflags */
6993: while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) && ( ( regs.spcflags & SPCFLAG_STOP ) == 0 ) )
6994: CALL_VAR(PendingInterruptFunction); /* call the interrupt handler */
6995: if ( MFP_UpdateNeeded == true )
6996: MFP_UpdateIRQ ( 0 );
6997: #endif
1.1.1.4 root 6998:
1.1.1.7 root 6999: if (r->spcflags) {
7000: if (do_specialties (cpu_cycles))
7001: exit = true;
7002: }
7003:
7004: #ifdef WINUAE_FOR_HATARI
7005: /* Run DSP 56k code if necessary */
7006: if (bDspEnabled) {
1.1.1.8 root 7007: //if ( DSP_CPU_FREQ_RATIO * ( (CyclesGlobalClockCounter - DSP_CyclesGlobalClockCounter) << nCpuFreqShift ) - 2 * cpu_cycles * 2 / CYCLE_UNIT >= 8 )
7008: //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 7009: DSP_Run(2 * cpu_cycles * 2 / CYCLE_UNIT);
1.1.1.8 root 7010: // DSP_Run ( DSP_CPU_FREQ_RATIO * ( CyclesGlobalClockCounter - DSP_CyclesGlobalClockCounter ) );
1.1.1.7 root 7011: }
7012: #endif
7013:
7014: ipl_fetch ();
7015: }
7016: } CATCH(prb) {
7017: bus_error();
7018: if (r->spcflags) {
7019: if (do_specialties(cpu_cycles))
1.1.1.8 root 7020: exit = true;
1.1.1.7 root 7021: }
7022: ipl_fetch();
7023: } ENDTRY
1.1.1.4 root 7024: }
7025: }
7026:
1.1.1.7 root 7027: #endif
1.1.1.4 root 7028:
1.1.1.8 root 7029: #ifdef WITH_THREADED_CPU
7030: static void *cpu_thread_run_2(void *v)
7031: {
7032: bool exit = false;
7033: struct regstruct *r = ®s;
7034:
7035: cpu_thread_active = 1;
7036: while (!exit) {
7037: TRY(prb)
7038: {
7039: while (!exit) {
7040: r->instruction_pc = m68k_getpc();
7041:
7042: r->opcode = x_get_iword(0);
7043:
7044: (*cpufunctbl[r->opcode])(r->opcode);
7045:
7046: if (r->spcflags) {
7047: if (do_specialties_thread())
7048: exit = true;
7049: }
7050: }
7051: } CATCH(prb)
7052: {
7053: bus_error();
7054: if (r->spcflags) {
7055: if (do_specialties_thread())
7056: exit = true;
7057: }
7058: } ENDTRY
7059: }
7060: cpu_thread_active = 0;
7061: return 0;
7062: }
7063: #endif
1.1.1.4 root 7064:
7065: /* Same thing, but don't use prefetch to get opcode. */
7066: static void m68k_run_2 (void)
7067: {
1.1.1.8 root 7068: #ifdef WITH_THREADED_CPU
7069: if (currprefs.cpu_thread) {
7070: run_cpu_thread(cpu_thread_run_2);
7071: return;
7072: }
7073: #endif
7074:
1.1.1.4 root 7075: struct regstruct *r = ®s;
1.1.1.7 root 7076: bool exit = false;
1.1.1.8 root 7077:
7078: Log_Printf(LOG_DEBUG, "m68k_run_2\n");
1.1.1.4 root 7079:
1.1.1.7 root 7080: while (!exit) {
7081: TRY(prb) {
7082: while (!exit) {
7083: #ifdef WINUAE_FOR_HATARI
7084: //m68k_dumpstate_file(stderr, NULL);
7085: if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM))
7086: {
7087: int FrameCycles, HblCounterVideo, LineCycles;
7088: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
7089: LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo );
7090: m68k_disasm_file(stderr, m68k_getpc (), NULL, 1);
7091: }
7092: #endif
7093: r->instruction_pc = m68k_getpc ();
1.1.1.4 root 7094:
1.1.1.7 root 7095: r->opcode = x_get_iword(0);
7096: count_instr (r->opcode);
1.1.1.4 root 7097:
1.1.1.7 root 7098: do_cycles (cpu_cycles);
1.1.1.5 root 7099:
1.1.1.7 root 7100: cpu_cycles = (*cpufunctbl[r->opcode])(r->opcode);
7101: cpu_cycles = adjust_cycles (cpu_cycles);
7102: #ifdef WINUAE_FOR_HATARI
7103: //fprintf ( stderr , "cyc_2 %d\n" , cpu_cycles );
7104: M68000_AddCyclesWithPairing(cpu_cycles * 2 / CYCLE_UNIT);
7105:
1.1.1.8 root 7106: if ( WaitStateCycles ) {
1.1.1.7 root 7107: /* Add some extra cycles to simulate a wait state */
1.1.1.8 root 7108: M68000_AddCycles(WaitStateCycles);
7109: WaitStateCycles = 0;
1.1.1.7 root 7110: }
1.1.1.4 root 7111:
1.1.1.7 root 7112: /* We can have several interrupts at the same time before the next CPU instruction */
7113: /* We must check for pending interrupt and call do_specialties_interrupt() only */
7114: /* if the cpu is not in the STOP state. Else, the int could be acknowledged now */
7115: /* and prevent exiting the STOP state when calling do_specialties() after. */
7116: /* For performance, we first test PendingInterruptCount, then regs.spcflags */
7117: while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) && ( ( regs.spcflags & SPCFLAG_STOP ) == 0 ) )
7118: CALL_VAR(PendingInterruptFunction); /* call the interrupt handler */
7119: if ( MFP_UpdateNeeded == true )
7120: MFP_UpdateIRQ ( 0 );
7121: #endif
1.1.1.4 root 7122:
1.1.1.7 root 7123: if (r->spcflags) {
7124: if (do_specialties (cpu_cycles))
7125: exit = true;
7126: }
7127:
7128: #ifdef WINUAE_FOR_HATARI
7129: /* Run DSP 56k code if necessary */
7130: if (bDspEnabled) {
7131: DSP_Run(2 * cpu_cycles * 2 / CYCLE_UNIT);
1.1.1.8 root 7132: // DSP_Run ( DSP_CPU_FREQ_RATIO * ( CyclesGlobalClockCounter - DSP_CyclesGlobalClockCounter ) );
1.1.1.7 root 7133: }
7134: #endif
7135: }
7136: } CATCH(prb) {
7137: bus_error();
7138: if (r->spcflags) {
7139: if (do_specialties(cpu_cycles))
7140: exit = true;
7141: }
7142: } ENDTRY
1.1.1.4 root 7143: }
7144: }
7145:
7146: /* fake MMU 68k */
1.1.1.8 root 7147: #if 0
1.1.1.4 root 7148: static void m68k_run_mmu (void)
7149: {
7150: for (;;) {
1.1.1.7 root 7151: #ifdef WINUAE_FOR_HATARI
7152: //m68k_dumpstate_file(stderr, NULL);
1.1.1.4 root 7153: if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM))
7154: {
7155: int FrameCycles, HblCounterVideo, LineCycles;
7156: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
7157: LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo );
1.1.1.7 root 7158: m68k_disasm_file(stderr, m68k_getpc (), NULL, 1);
1.1.1.4 root 7159: }
1.1.1.7 root 7160: #endif
7161: regs.opcode = get_iiword (0);
1.1.1.4 root 7162: do_cycles (cpu_cycles);
7163: mmu_backup_regs = regs;
1.1.1.7 root 7164: cpu_cycles = (*cpufunctbl[regs.opcode])(regs.opcode);
7165: cpu_cycles = adjust_cycles (cpu_cycles);
1.1.1.4 root 7166: if (mmu_triggered)
7167: mmu_do_hit ();
7168: if (regs.spcflags) {
7169: if (do_specialties (cpu_cycles))
7170: return;
7171: }
7172: }
7173: }
1.1.1.8 root 7174: #endif
1.1.1.4 root 7175:
7176: #endif /* CPUEMU_0 */
7177:
7178: int in_m68k_go = 0;
7179:
1.1.1.8 root 7180: #if 0
1.1.1.4 root 7181: static void exception2_handle (uaecptr addr, uaecptr fault)
7182: {
7183: last_addr_for_exception_3 = addr;
7184: last_fault_for_exception_3 = fault;
7185: last_writeaccess_for_exception_3 = 0;
7186: last_instructionaccess_for_exception_3 = 0;
1.1.1.7 root 7187: Exception (2);
7188: }
1.1.1.8 root 7189: #endif
1.1.1.7 root 7190:
7191: static bool cpu_hardreset, cpu_keyboardreset;
7192:
7193: bool is_hardreset(void)
7194: {
7195: return cpu_hardreset;
7196: }
7197: bool is_keyboardreset(void)
7198: {
7199: return cpu_keyboardreset;
1.1.1.4 root 7200: }
7201:
7202: void m68k_go (int may_quit)
7203: {
1.1.1.7 root 7204: #ifndef WINUAE_FOR_HATARI
7205: int hardboot = 1;
7206: int startup = 1;
7207: #endif
7208:
1.1.1.8 root 7209: #ifdef WITH_THREADED_CPU
7210: init_cpu_thread();
7211: #endif
1.1.1.4 root 7212: if (in_m68k_go || !may_quit) {
1.1.1.7 root 7213: write_log (_T("Bug! m68k_go is not reentrant.\n"));
1.1.1.4 root 7214: abort ();
7215: }
7216:
7217: reset_frame_rate_hack ();
7218: update_68k_cycles ();
1.1.1.7 root 7219: #ifndef WINUAE_FOR_HATARI
7220: start_cycles = 0;
7221: #endif
7222:
7223: set_cpu_tracer (false);
1.1.1.4 root 7224:
1.1.1.7 root 7225: cpu_prefs_changed_flag = 0;
1.1.1.4 root 7226: in_m68k_go++;
7227: for (;;) {
7228: void (*run_func)(void);
7229:
1.1.1.7 root 7230: #ifdef WINUAE_FOR_HATARI
1.1.1.4 root 7231: /* Exit hatari ? */
7232: if (bQuitProgram == true)
7233: break;
1.1.1.7 root 7234: #endif
7235:
7236: cputrace.state = -1;
7237:
7238: #ifndef WINUAE_FOR_HATARI
1.1.1.8 root 7239: if (regs.halted == CPU_HALT_ACCELERATOR_CPU_FALLBACK) {
7240: regs.halted = 0;
7241: cpu_do_fallback();
7242: }
7243:
1.1.1.7 root 7244: if (currprefs.inprecfile[0] && input_play) {
7245: inprec_open (currprefs.inprecfile, NULL);
7246: changed_prefs.inprecfile[0] = currprefs.inprecfile[0] = 0;
7247: quit_program = UAE_RESET;
7248: }
7249: if (input_play || input_record)
7250: inprec_startup ();
7251:
7252: if (quit_program > 0) {
7253: int restored = 0;
7254: cpu_keyboardreset = quit_program == UAE_RESET_KEYBOARD;
7255: cpu_hardreset = ((quit_program == UAE_RESET_HARD ? 1 : 0) | hardboot) != 0;
7256:
7257: if (quit_program == UAE_QUIT)
7258: break;
7259:
7260: hsync_counter = 0;
7261: vsync_counter = 0;
7262: quit_program = 0;
7263: hardboot = 0;
7264:
7265: #ifdef SAVESTATE
7266: if (savestate_state == STATE_DORESTORE)
7267: savestate_state = STATE_RESTORE;
7268: if (savestate_state == STATE_RESTORE)
7269: restore_state (savestate_fname);
7270: else if (savestate_state == STATE_REWIND)
7271: savestate_rewind ();
7272: #endif
1.1.1.8 root 7273: if (cpu_hardreset)
7274: m68k_reset_restore();
7275: prefs_changed_cpu();
1.1.1.9 ! root 7276: #ifdef WINUAE_FOR_HATARI
! 7277: fpu_modechange(); // NP TODO : use SPCFLAG_MODE_CHANGE below instead
1.1.1.7 root 7278: #endif
1.1.1.9 ! root 7279: build_cpufunctbl();
! 7280: set_x_funcs();
! 7281: set_cycles (start_cycles);
1.1.1.7 root 7282: custom_reset (cpu_hardreset != 0, cpu_keyboardreset);
7283: m68k_reset2 (cpu_hardreset != 0);
7284: if (cpu_hardreset) {
7285: memory_clear ();
7286: write_log (_T("hardreset, memory cleared\n"));
7287: }
7288: cpu_hardreset = false;
7289: #ifdef SAVESTATE
7290: /* We may have been restoring state, but we're done now. */
7291: if (isrestore ()) {
7292: if (debug_dma) {
7293: record_dma_reset ();
7294: record_dma_reset ();
7295: }
7296: savestate_restore_finish ();
7297: memory_map_dump ();
7298: if (currprefs.mmu_model == 68030) {
1.1.1.9 ! root 7299: mmu030_decode_tc (tc_030, true);
1.1.1.7 root 7300: } else if (currprefs.mmu_model >= 68040) {
7301: mmu_set_tc (regs.tcr);
7302: }
7303: startup = 1;
7304: restored = 1;
7305: }
7306: #endif
7307: if (currprefs.produce_sound == 0)
7308: eventtab[ev_audio].active = 0;
7309: m68k_setpc_normal (regs.pc);
7310: check_prefs_changed_audio ();
7311:
7312: if (!restored || hsync_counter == 0)
7313: savestate_check ();
7314: if (input_record == INPREC_RECORD_START)
7315: input_record = INPREC_RECORD_NORMAL;
7316: statusline_clear();
7317: } else {
7318: if (input_record == INPREC_RECORD_START) {
7319: input_record = INPREC_RECORD_NORMAL;
7320: savestate_init ();
7321: hsync_counter = 0;
7322: vsync_counter = 0;
7323: savestate_check ();
7324: }
7325: }
7326:
7327: if (changed_prefs.inprecfile[0] && input_record)
7328: inprec_prepare_record (savestate_fname[0] ? savestate_fname : NULL);
7329: #endif
7330:
7331: set_cpu_tracer (false);
1.1.1.4 root 7332:
7333: #ifdef DEBUGGER
7334: if (debugging)
7335: debug ();
7336: #endif
1.1.1.7 root 7337: /* [NP] TODO : allow changing cpu on the fly ? */
7338: #ifndef WINUAE_FOR_HATARI
7339: if (regs.spcflags & SPCFLAG_MODE_CHANGE) {
7340: if (cpu_prefs_changed_flag & 1) {
7341: uaecptr pc = m68k_getpc();
7342: prefs_changed_cpu();
1.1.1.9 ! root 7343: fpu_modechange();
1.1.1.7 root 7344: build_cpufunctbl();
7345: m68k_setpc_normal(pc);
7346: fill_prefetch();
7347: }
7348: if (cpu_prefs_changed_flag & 2) {
7349: fixup_cpu(&changed_prefs);
7350: currprefs.m68k_speed = changed_prefs.m68k_speed;
7351: currprefs.m68k_speed_throttle = changed_prefs.m68k_speed_throttle;
7352: update_68k_cycles();
7353: }
7354: cpu_prefs_changed_flag = 0;
7355: }
7356: #else
7357: /* [NP] : in Hatari, build_cpufunctbl() is called directly from check_prefs_changed_cpu2() */
7358: /* so we just need to set PC here */
7359: if (regs.spcflags & SPCFLAG_MODE_CHANGE) {
7360: if (cpu_prefs_changed_flag & 1) {
7361: printf ( "cpu change %d\n" , cpu_prefs_changed_flag );
7362: uaecptr pc = m68k_getpc();
7363: m68k_setpc_normal(pc);
7364: fill_prefetch();
1.1.1.4 root 7365: }
1.1.1.7 root 7366: cpu_prefs_changed_flag = 0;
1.1.1.4 root 7367: }
1.1.1.7 root 7368: #endif
1.1.1.4 root 7369:
1.1.1.7 root 7370: set_x_funcs();
7371: #ifndef WINUAE_FOR_HATARI
7372: if (startup) {
7373: custom_prepare ();
7374: protect_roms (true);
1.1.1.4 root 7375: }
1.1.1.7 root 7376: startup = 0;
7377: event_wait = true;
1.1.1.4 root 7378: #endif
1.1.1.7 root 7379: unset_special(SPCFLAG_MODE_CHANGE);
1.1.1.4 root 7380:
1.1.1.9 ! root 7381: if (!regs.halted) {
! 7382: // check that PC points to something that looks like memory.
! 7383: uaecptr pc = m68k_getpc();
! 7384: #ifndef WINUAE_FOR_HATARI
! 7385: addrbank *ab = get_mem_bank_real(pc);
! 7386: #else
! 7387: addrbank *ab = &get_mem_bank(pc);
! 7388: #endif
! 7389: if (ab == NULL || ab == &dummy_bank || (!currprefs.cpu_compatible && !valid_address(pc, 2)) || (pc & 1)) {
! 7390: cpu_halt(CPU_HALT_INVALID_START_ADDRESS);
! 7391: }
! 7392: }
1.1.1.7 root 7393: if (regs.halted) {
7394: cpu_halt (regs.halted);
7395: if (regs.halted < 0) {
7396: haltloop();
7397: continue;
7398: }
7399: }
7400:
7401: #if 0
1.1.1.4 root 7402: if (mmu_enabled && !currprefs.cachesize) {
7403: run_func = m68k_run_mmu;
7404: } else {
1.1.1.7 root 7405: #endif
7406: run_func = currprefs.cpu_cycle_exact && currprefs.cpu_model <= 68010 ? m68k_run_1_ce :
7407: currprefs.cpu_compatible && currprefs.cpu_model <= 68010 ? m68k_run_1 :
1.1.1.4 root 7408: #ifdef JIT
7409: currprefs.cpu_model >= 68020 && currprefs.cachesize ? m68k_run_jit :
7410: #endif
1.1.1.7 root 7411: currprefs.cpu_model == 68030 && currprefs.mmu_model ? m68k_run_mmu030 :
7412: currprefs.cpu_model == 68040 && currprefs.mmu_model ? m68k_run_mmu040 :
7413: currprefs.cpu_model == 68060 && currprefs.mmu_model ? m68k_run_mmu060 :
7414:
7415: currprefs.cpu_model >= 68040 && currprefs.cpu_cycle_exact ? m68k_run_3ce :
1.1.1.4 root 7416: currprefs.cpu_model >= 68020 && currprefs.cpu_cycle_exact ? m68k_run_2ce :
1.1.1.7 root 7417:
7418: currprefs.cpu_model <= 68020 && currprefs.cpu_compatible ? m68k_run_2p :
7419: currprefs.cpu_model == 68030 && currprefs.cpu_compatible ? m68k_run_2p :
7420: currprefs.cpu_model >= 68040 && currprefs.cpu_compatible ? m68k_run_3p :
7421:
7422: m68k_run_2;
7423: #if 0
1.1.1.4 root 7424: }
1.1.1.7 root 7425: #endif
7426: run_func();
1.1.1.8 root 7427: Log_Printf(LOG_DEBUG, "exit m68k_run\n");
1.1.1.4 root 7428: }
1.1.1.7 root 7429: #ifndef WINUAE_FOR_HATARI
7430: protect_roms (false);
7431: #endif
1.1.1.4 root 7432: in_m68k_go--;
7433: }
7434:
7435: #if 0
7436: static void m68k_verify (uaecptr addr, uaecptr *nextpc)
7437: {
1.1.1.7 root 7438: uae_u16 opcode, val;
1.1.1.4 root 7439: struct instr *dp;
7440:
7441: opcode = get_iword_1 (0);
7442: last_op_for_exception_3 = opcode;
7443: m68kpc_offset = 2;
7444:
7445: if (cpufunctbl[opcode] == op_illg_1) {
7446: opcode = 0x4AFC;
7447: }
7448: dp = table68k + opcode;
7449:
7450: if (dp->suse) {
7451: if (!verify_ea (dp->sreg, dp->smode, dp->size, &val)) {
7452: Exception (3, 0);
7453: return;
7454: }
7455: }
7456: if (dp->duse) {
7457: if (!verify_ea (dp->dreg, dp->dmode, dp->size, &val)) {
7458: Exception (3, 0);
7459: return;
7460: }
7461: }
7462: }
7463: #endif
7464:
7465: static const TCHAR *ccnames[] =
1.1.1.7 root 7466: {
7467: _T("T "),_T("F "),_T("HI"),_T("LS"),_T("CC"),_T("CS"),_T("NE"),_T("EQ"),
7468: _T("VC"),_T("VS"),_T("PL"),_T("MI"),_T("GE"),_T("LT"),_T("GT"),_T("LE")
7469: };
7470: static const TCHAR *fpccnames[] =
7471: {
7472: _T("F"),
7473: _T("EQ"),
7474: _T("OGT"),
7475: _T("OGE"),
7476: _T("OLT"),
7477: _T("OLE"),
7478: _T("OGL"),
7479: _T("OR"),
7480: _T("UN"),
7481: _T("UEQ"),
7482: _T("UGT"),
7483: _T("UGE"),
7484: _T("ULT"),
7485: _T("ULE"),
7486: _T("NE"),
7487: _T("T"),
7488: _T("SF"),
7489: _T("SEQ"),
7490: _T("GT"),
7491: _T("GE"),
7492: _T("LT"),
7493: _T("LE"),
7494: _T("GL"),
7495: _T("GLE"),
7496: _T("NGLE"),
7497: _T("NGL"),
7498: _T("NLE"),
7499: _T("NLT"),
7500: _T("NGE"),
7501: _T("NGT"),
7502: _T("SNE"),
7503: _T("ST")
7504: };
7505: static const TCHAR *fpuopcodes[] =
7506: {
7507: _T("FMOVE"),
7508: _T("FINT"),
7509: _T("FSINH"),
7510: _T("FINTRZ"),
7511: _T("FSQRT"),
7512: NULL,
7513: _T("FLOGNP1"),
7514: NULL,
7515: _T("FETOXM1"),
7516: _T("FTANH"),
7517: _T("FATAN"),
7518: NULL,
7519: _T("FASIN"),
7520: _T("FATANH"),
7521: _T("FSIN"),
7522: _T("FTAN"),
7523: _T("FETOX"), // 0x10
7524: _T("FTWOTOX"),
7525: _T("FTENTOX"),
7526: NULL,
7527: _T("FLOGN"),
7528: _T("FLOG10"),
7529: _T("FLOG2"),
7530: NULL,
7531: _T("FABS"),
7532: _T("FCOSH"),
7533: _T("FNEG"),
7534: NULL,
7535: _T("FACOS"),
7536: _T("FCOS"),
7537: _T("FGETEXP"),
7538: _T("FGETMAN"),
7539: _T("FDIV"), // 0x20
7540: _T("FMOD"),
7541: _T("FADD"),
7542: _T("FMUL"),
7543: _T("FSGLDIV"),
7544: _T("FREM"),
7545: _T("FSCALE"),
7546: _T("FSGLMUL"),
7547: _T("FSUB"),
7548: NULL,
7549: NULL,
7550: NULL,
7551: NULL,
7552: NULL,
7553: NULL,
7554: NULL,
7555: _T("FSINCOS"), // 0x30
7556: _T("FSINCOS"),
7557: _T("FSINCOS"),
7558: _T("FSINCOS"),
7559: _T("FSINCOS"),
7560: _T("FSINCOS"),
7561: _T("FSINCOS"),
7562: _T("FSINCOS"),
7563: _T("FCMP"),
7564: NULL,
7565: _T("FTST"),
7566: NULL,
7567: NULL,
7568: NULL,
7569: NULL,
7570: NULL
7571: };
7572:
7573: static const TCHAR *movemregs[] =
7574: {
7575: _T("D0"),
7576: _T("D1"),
7577: _T("D2"),
7578: _T("D3"),
7579: _T("D4"),
7580: _T("D5"),
7581: _T("D6"),
7582: _T("D7"),
7583: _T("A0"),
7584: _T("A1"),
7585: _T("A2"),
7586: _T("A3"),
7587: _T("A4"),
7588: _T("A5"),
7589: _T("A6"),
7590: _T("A7"),
7591: _T("FP0"),
7592: _T("FP1"),
7593: _T("FP2"),
7594: _T("FP3"),
7595: _T("FP4"),
7596: _T("FP5"),
7597: _T("FP6"),
7598: _T("FP7"),
1.1.1.8 root 7599: _T("FPIAR"),
1.1.1.7 root 7600: _T("FPSR"),
1.1.1.8 root 7601: _T("FPCR")
1.1.1.7 root 7602: };
1.1.1.4 root 7603:
1.1.1.7 root 7604: static void addmovemreg (TCHAR *out, int *prevreg, int *lastreg, int *first, int reg, int fpmode)
1.1.1.4 root 7605: {
7606: TCHAR *p = out + _tcslen (out);
7607: if (*prevreg < 0) {
7608: *prevreg = reg;
7609: *lastreg = reg;
7610: return;
7611: }
1.1.1.7 root 7612: if (reg < 0 || fpmode == 2 || (*prevreg) + 1 != reg || (reg & 8) != ((*prevreg & 8))) {
7613: _stprintf (p, _T("%s%s"), (*first) ? _T("") : _T("/"), movemregs[*lastreg]);
1.1.1.4 root 7614: p = p + _tcslen (p);
1.1.1.8 root 7615: if (*lastreg != *prevreg) {
7616: if ((*lastreg) + 2 == reg) {
7617: _stprintf(p, _T("/%s"), movemregs[*prevreg]);
7618: } else if ((*lastreg) != (*prevreg)) {
7619: _stprintf(p, _T("-%s"), movemregs[*prevreg]);
7620: }
1.1.1.4 root 7621: }
7622: *lastreg = reg;
7623: *first = 0;
7624: }
7625: *prevreg = reg;
7626: }
7627:
1.1.1.7 root 7628: static void movemout (TCHAR *out, uae_u16 mask, int mode, int fpmode)
1.1.1.4 root 7629: {
7630: unsigned int dmask, amask;
7631: int prevreg = -1, lastreg = -1, first = 1;
1.1.1.7 root 7632: int i;
1.1.1.4 root 7633:
1.1.1.7 root 7634: if (mode == Apdi && !fpmode) {
7635: uae_u8 dmask2;
7636: uae_u8 amask2;
7637:
7638: amask2 = mask & 0xff;
7639: dmask2 = (mask >> 8) & 0xff;
1.1.1.4 root 7640: dmask = 0;
7641: amask = 0;
7642: for (i = 0; i < 8; i++) {
7643: if (dmask2 & (1 << i))
7644: dmask |= 1 << (7 - i);
7645: if (amask2 & (1 << i))
7646: amask |= 1 << (7 - i);
7647: }
7648: } else {
7649: dmask = mask & 0xff;
7650: amask = (mask >> 8) & 0xff;
1.1.1.7 root 7651: if (fpmode == 1 && mode != Apdi) {
7652: uae_u8 dmask2 = dmask;
7653: dmask = 0;
7654: for (i = 0; i < 8; i++) {
7655: if (dmask2 & (1 << i))
7656: dmask |= 1 << (7 - i);
7657: }
7658: }
7659: }
7660: if (fpmode) {
7661: while (dmask) { addmovemreg(out, &prevreg, &lastreg, &first, movem_index1[dmask] + (fpmode == 2 ? 24 : 16), fpmode); dmask = movem_next[dmask]; }
7662: } else {
7663: while (dmask) { addmovemreg (out, &prevreg, &lastreg, &first, movem_index1[dmask], fpmode); dmask = movem_next[dmask]; }
7664: while (amask) { addmovemreg (out, &prevreg, &lastreg, &first, movem_index1[amask] + 8, fpmode); amask = movem_next[amask]; }
1.1.1.4 root 7665: }
1.1.1.7 root 7666: addmovemreg(out, &prevreg, &lastreg, &first, -1, fpmode);
1.1.1.4 root 7667: }
7668:
7669: static void disasm_size (TCHAR *instrname, struct instr *dp)
7670: {
1.1.1.7 root 7671: if (dp->unsized) {
7672: _tcscat(instrname, _T(" "));
7673: return;
1.1.1.4 root 7674: }
7675: switch (dp->size)
7676: {
7677: case sz_byte:
1.1.1.7 root 7678: _tcscat (instrname, _T(".B "));
1.1.1.4 root 7679: break;
7680: case sz_word:
1.1.1.7 root 7681: _tcscat (instrname, _T(".W "));
1.1.1.4 root 7682: break;
7683: case sz_long:
1.1.1.7 root 7684: _tcscat (instrname, _T(".L "));
1.1.1.4 root 7685: break;
7686: default:
1.1.1.7 root 7687: _tcscat (instrname, _T(" "));
1.1.1.4 root 7688: break;
7689: }
7690: }
7691:
1.1.1.9 ! root 7692: static void asm_add_extensions(uae_u16 *data, int *dcntp, int mode, uae_u32 v, uae_u16 *ext, uaecptr pc, int size)
! 7693: {
! 7694: int dcnt = *dcntp;
! 7695: if (mode < 0)
! 7696: return;
! 7697: if (mode == Ad16) {
! 7698: data[dcnt++] = v;
! 7699: }
! 7700: if (mode == PC16) {
! 7701: data[dcnt++] = v - (pc + 2);
! 7702: }
! 7703: if (mode == Ad8r || mode == PC8r) {
! 7704: data[dcnt++] = ext[0];
! 7705: }
! 7706: if (mode == absw) {
! 7707: data[dcnt++] = (uae_u16)v;
! 7708: }
! 7709: if (mode == absl) {
! 7710: data[dcnt++] = (uae_u16)(v >> 16);
! 7711: data[dcnt++] = (uae_u16)v;
! 7712: }
! 7713: if ((mode == imm && size == 0) || mode == imm0) {
! 7714: data[dcnt++] = (uae_u8)v;
! 7715: }
! 7716: if ((mode == imm && size == 1) || mode == imm1) {
! 7717: data[dcnt++] = (uae_u16)v;
! 7718: }
! 7719: if ((mode == imm && size == 2) || mode == imm2) {
! 7720: data[dcnt++] = (uae_u16)(v >> 16);
! 7721: data[dcnt++] = (uae_u16)v;
! 7722: }
! 7723: *dcntp = dcnt;
! 7724: }
! 7725:
! 7726: static int asm_isdreg(const TCHAR *s)
! 7727: {
! 7728: if (s[0] == 'D' && s[1] >= '0' && s[1] <= '7')
! 7729: return s[1] - '0';
! 7730: return -1;
! 7731: }
! 7732: static int asm_isareg(const TCHAR *s)
! 7733: {
! 7734: if (s[0] == 'A' && s[1] >= '0' && s[1] <= '7')
! 7735: return s[1] - '0';
! 7736: return -1;
! 7737: }
! 7738: static int asm_ispc(const TCHAR *s)
! 7739: {
! 7740: if (s[0] == 'P' && s[1] == 'C')
! 7741: return 1;
! 7742: return 0;
! 7743: }
! 7744:
! 7745: static int asm_parse_mode(TCHAR *s, uae_u8 *reg, uae_u32 *v, uae_u16 *ext)
! 7746: {
! 7747: TCHAR *ss = s;
! 7748: *reg = -1;
! 7749: *v = 0;
! 7750: *ext = 0;
! 7751: if (s[0] == 0)
! 7752: return -1;
! 7753: // Dn
! 7754: if (asm_isdreg(s) >= 0 && s[2] == 0) {
! 7755: *reg = asm_isdreg(s);
! 7756: return Dreg;
! 7757: }
! 7758: // An
! 7759: if (asm_isareg(s) >= 0 && s[2] == 0) {
! 7760: *reg = asm_isareg(s);
! 7761: return Areg;
! 7762: }
! 7763: // (An) and (An)+
! 7764: if (s[0] == '(' && asm_isareg(s + 1) >= 0 && s[3] == ')') {
! 7765: *reg = asm_isareg(s + 1);
! 7766: if (s[4] == '+' && s[5] == 0)
! 7767: return Aipi;
! 7768: if (s[4] == 0)
! 7769: return Aind;
! 7770: return -1;
! 7771: }
! 7772: // -(An)
! 7773: if (s[0] == '-' && s[1] == '(' && asm_isareg(s + 2) >= 0 && s[4] == ')' && s[5] == 0) {
! 7774: *reg = asm_isareg(s + 2);
! 7775: return Apdi;
! 7776: }
! 7777: // Immediate
! 7778: if (s[0] == '#') {
! 7779: if (s[1] == '!') {
! 7780: *v = _tstol(s + 2);
! 7781: } else {
! 7782: TCHAR *endptr;
! 7783: *v = _tcstol(s + 1, &endptr, 16);
! 7784: }
! 7785: return imm;
! 7786: }
! 7787: // Value
! 7788: if (s[0] == '!') {
! 7789: *v = _tstol(s + 1);
! 7790: } else {
! 7791: TCHAR *endptr;
! 7792: *v = _tcstol(s, &endptr, 16);
! 7793: }
! 7794: int dots = 0;
! 7795: unsigned int i;
! 7796: for (i = 0; i < _tcslen(s); i++) {
! 7797: if (s[i] == ',')
! 7798: dots++;
! 7799: }
! 7800: while (*s != 0) {
! 7801: // d16(An)
! 7802: if (dots == 0 && s[0] == '(' && asm_isareg(s + 1) >= 0 && s[3] == ')' && s[4] == 0) {
! 7803: *reg = asm_isareg(s + 1);
! 7804: return Ad16;
! 7805: }
! 7806: // d16(PC)
! 7807: if (dots == 0 && s[0] == '(' && asm_ispc(s + 1) && s[3] == ')' && s[4] == 0) {
! 7808: *reg = 2;
! 7809: return PC16;
! 7810: }
! 7811: // (d16,An) / (d16,PC)
! 7812: if (dots == 1 && s[0] == '(' && !asm_ispc(s + 1) && asm_isareg(s + 1) < 0 && asm_isdreg(s + 1) < 0) {
! 7813: TCHAR *startptr, *endptr;
! 7814: if (s[1] == '!') {
! 7815: startptr = s + 2;
! 7816: *v = _tcstol(startptr, &endptr, 10);
! 7817: } else {
! 7818: startptr = s + 1;
! 7819: *v = _tcstol(startptr, &endptr, 16);
! 7820: }
! 7821: if (endptr == startptr || endptr[0] != ',')
! 7822: return -1;
! 7823: if (asm_ispc(endptr + 1) && endptr[3] == ')') {
! 7824: *reg = 2;
! 7825: return PC16;
! 7826: }
! 7827: if (asm_isareg(endptr + 1) >= 0 && endptr[3] == ')') {
! 7828: *reg = asm_isareg(endptr + 1);
! 7829: return Ad16;
! 7830: }
! 7831: return -1;
! 7832: }
! 7833: // Ad8r PC8r
! 7834: if (s[0] == '(') {
! 7835: TCHAR *s2 = s;
! 7836: if (!asm_ispc(s + 1) && asm_isareg(s + 1) < 0 && asm_isdreg(s + 1) < 0) {
! 7837: if (dots != 2)
! 7838: return -1;
! 7839: TCHAR *startptr, *endptr;
! 7840: if (s[1] == '!') {
! 7841: startptr = s + 2;
! 7842: *v = _tcstol(startptr, &endptr, 10);
! 7843: } else {
! 7844: startptr = s + 1;
! 7845: *v = _tcstol(startptr, &endptr, 16);
! 7846: }
! 7847: if (endptr == startptr || endptr[0] != ',')
! 7848: return -1;
! 7849: s2 = endptr + 1;
! 7850: } else if (((asm_isareg(s + 1) >= 0 || asm_ispc(s + 1)) && s[3] == ',') || (asm_isdreg(s + 4) >= 0 || asm_isareg(s + 4) >= 0)) {
! 7851: if (dots != 1)
! 7852: return -1;
! 7853: s2 = s + 1;
! 7854: } else {
! 7855: return -1;
! 7856: }
! 7857: uae_u8 reg2;
! 7858: bool ispc = asm_ispc(s2);
! 7859: if (ispc) {
! 7860: *reg = 3;
! 7861: } else {
! 7862: *reg = asm_isareg(s2);
! 7863: }
! 7864: s2 += 2;
! 7865: if (*s2 != ',')
! 7866: return -1;
! 7867: s2++;
! 7868: if (asm_isdreg(s2) >= 0) {
! 7869: reg2 = asm_isdreg(s2);
! 7870: } else {
! 7871: reg2 = asm_isareg(s2);
! 7872: *ext |= 1 << 15;
! 7873: }
! 7874: s2 += 2;
! 7875: *ext |= reg2 << 12;
! 7876: *ext |= (*v) & 0xff;
! 7877: if (s2[0] == '.' && s2[1] == 'W') {
! 7878: s2 += 2;
! 7879: } else if (s2[0] == '.' && s2[1] == 'L') {
! 7880: *ext |= 1 << 11;
! 7881: s2 += 2;
! 7882: }
! 7883: if (s2[0] == '*') {
! 7884: TCHAR scale = s2[1];
! 7885: if (scale == '2')
! 7886: *ext |= 1 << 9;
! 7887: else if (scale == '4')
! 7888: *ext |= 2 << 9;
! 7889: else if (scale == '8')
! 7890: *ext |= 3 << 9;
! 7891: else
! 7892: return -1;
! 7893: s2 += 2;
! 7894: }
! 7895: if (s2[0] == ')' && s2[1] == 0) {
! 7896: return ispc ? PC8r : Ad8r;
! 7897: }
! 7898: return -1;
! 7899: }
! 7900: s++;
! 7901: }
! 7902: // abs.w
! 7903: if (s - ss > 2 && s[-2] == '.' && s[-1] == 'W') {
! 7904: *reg = 0;
! 7905: return absw;
! 7906: }
! 7907: // abs.l
! 7908: *reg = 1;
! 7909: return absl;
! 7910: }
! 7911:
! 7912: static TCHAR *asm_parse_parm(TCHAR *parm, TCHAR *out)
! 7913: {
! 7914: TCHAR *p = parm;
! 7915: bool quote = false;
! 7916:
! 7917: for (;;) {
! 7918: if (*p == '(') {
! 7919: quote = true;
! 7920: }
! 7921: if (*p == ')') {
! 7922: if (!quote)
! 7923: return NULL;
! 7924: quote = false;
! 7925: }
! 7926: if ((*p == ',' || *p == 0) && !quote) {
! 7927: TCHAR c = *p;
! 7928: p[0] = 0;
! 7929: _tcscpy(out, parm);
! 7930: my_trim(out);
! 7931: if (c)
! 7932: p++;
! 7933: return p;
! 7934: }
! 7935: p++;
! 7936: }
! 7937: }
! 7938:
! 7939: static bool m68k_asm_parse_movec(TCHAR *s, TCHAR *d)
! 7940: {
! 7941: int i;
! 7942: for (i = 0; m2cregs[i].regname; i++) {
! 7943: if (!_tcscmp(s, m2cregs[i].regname)) {
! 7944: uae_u16 v = m2cregs[i].regno;
! 7945: if (asm_isareg(d) >= 0)
! 7946: v |= 0x8000 | (asm_isareg(d) << 12);
! 7947: else if (asm_isdreg(d) >= 0)
! 7948: v |= (asm_isdreg(d) << 12);
! 7949: else
! 7950: return false;
! 7951: _stprintf(s, _T("#%X"), v);
! 7952: return true;
! 7953: }
! 7954: }
! 7955: return false;
! 7956: }
! 7957:
! 7958: static bool m68k_asm_parse_movem(TCHAR *s, int dir)
! 7959: {
! 7960: TCHAR *d = s;
! 7961: uae_u16 regmask = 0;
! 7962: uae_u16 mask = dir ? 0x8000 : 0x0001;
! 7963: bool ret = false;
! 7964: while(*s) {
! 7965: int dreg = asm_isdreg(s);
! 7966: int areg = asm_isareg(s);
! 7967: if (dreg < 0 && areg < 0)
! 7968: break;
! 7969: int reg = dreg >= 0 ? dreg : areg + 8;
! 7970: regmask |= dir ? (mask >> reg) : (mask << reg);
! 7971: s += 2;
! 7972: if (*s == 0) {
! 7973: ret = true;
! 7974: break;
! 7975: } else if (*s == '/') {
! 7976: s++;
! 7977: continue;
! 7978: } else if (*s == '-') {
! 7979: s++;
! 7980: int dreg2 = asm_isdreg(s);
! 7981: int areg2 = asm_isareg(s);
! 7982: if (dreg2 < 0 && areg2 < 0)
! 7983: break;
! 7984: int reg2 = dreg2 >= 0 ? dreg2 : areg2 + 8;
! 7985: if (reg2 < reg)
! 7986: break;
! 7987: while (reg2 >= reg) {
! 7988: regmask |= dir ? (mask >> reg) : (mask << reg);
! 7989: reg++;
! 7990: }
! 7991: s += 2;
! 7992: if (*s == 0) {
! 7993: ret = true;
! 7994: break;
! 7995: }
! 7996: } else {
! 7997: break;
! 7998: }
! 7999: }
! 8000: if (ret)
! 8001: _stprintf(d, _T("#%X"), regmask);
! 8002: return ret;
! 8003: }
! 8004:
! 8005: int m68k_asm(TCHAR *sline, uae_u16 *out, uaecptr pc)
! 8006: {
! 8007: TCHAR *p;
! 8008: const TCHAR *cp1;
! 8009: TCHAR ins[256], parms[256];
! 8010: TCHAR line[256];
! 8011: TCHAR srcea[256], dstea[256];
! 8012: uae_u16 data[16], sexts[8], dexts[8];
! 8013: int dcnt = 0;
! 8014: int cc = -1;
! 8015: int quick = 0;
! 8016: bool immrelpc = false;
! 8017:
! 8018: if (_tcslen(sline) > 100)
! 8019: return -1;
! 8020:
! 8021: srcea[0] = dstea[0] = 0;
! 8022: parms[0] = 0;
! 8023:
! 8024: // strip all white space except first space
! 8025: p = line;
! 8026: bool firstsp = true;
! 8027: int i;
! 8028: for (i = 0; sline[i]; i++) {
! 8029: TCHAR c = sline[i];
! 8030: if (c == 32 && firstsp) {
! 8031: firstsp = false;
! 8032: *p++ = 32;
! 8033: }
! 8034: if (c <= 32)
! 8035: continue;
! 8036: *p++ = c;
! 8037: }
! 8038: *p = 0;
! 8039:
! 8040: to_upper(line, _tcslen(line));
! 8041:
! 8042: p = line;
! 8043: while (*p && *p != ' ')
! 8044: p++;
! 8045: if (*p == ' ') {
! 8046: *p = 0;
! 8047: _tcscpy(parms, p + 1);
! 8048: my_trim(parms);
! 8049: }
! 8050: _tcscpy(ins, line);
! 8051:
! 8052: if (_tcslen(ins) == 0)
! 8053: return 0;
! 8054:
! 8055: int size = 1;
! 8056: int inssize = -1;
! 8057: cp1 = _tcschr(line, '.');
! 8058: if (cp1) {
! 8059: size = cp1[1];
! 8060: if (size == 'W')
! 8061: size = 1;
! 8062: else if (size == 'L')
! 8063: size = 2;
! 8064: else if (size == 'B')
! 8065: size = 0;
! 8066: else
! 8067: return 0;
! 8068: inssize = size;
! 8069: line[cp1 - line] = 0;
! 8070: _tcscpy(ins, line);
! 8071: }
! 8072:
! 8073: TCHAR *parmp = parms;
! 8074: parmp = asm_parse_parm(parmp, srcea);
! 8075: if (!parmp)
! 8076: return 0;
! 8077: if (srcea[0]) {
! 8078: parmp = asm_parse_parm(parmp, dstea);
! 8079: if (!parmp)
! 8080: return 0;
! 8081: }
! 8082:
! 8083: int smode = -1;
! 8084: int dmode = -1;
! 8085: uae_u8 sreg = -1;
! 8086: uae_u8 dreg = -1;
! 8087: uae_u32 sval = 0;
! 8088: uae_u32 dval = 0;
! 8089: int ssize = -1;
! 8090: int dsize = -1;
! 8091:
! 8092: dmode = asm_parse_mode(dstea, &dreg, &dval, dexts);
! 8093:
! 8094:
! 8095: // Common alias
! 8096: if (!_tcscmp(ins, _T("BRA"))) {
! 8097: _tcscpy(ins, _T("BT"));
! 8098: } else if (!_tcscmp(ins, _T("BSR"))) {
! 8099: immrelpc = true;
! 8100: } else if (!_tcscmp(ins, _T("MOVEM"))) {
! 8101: if (dmode >= Aind && _tcschr(dstea, '-') == NULL && _tcschr(dstea, '/') == NULL) {
! 8102: _tcscpy(ins, _T("MVMLE"));
! 8103: if (!m68k_asm_parse_movem(srcea, dmode == Apdi))
! 8104: return -1;
! 8105: } else {
! 8106: TCHAR tmp[256];
! 8107: _tcscpy(ins, _T("MVMEL"));
! 8108: _tcscpy(tmp, srcea);
! 8109: _tcscpy(srcea, dstea);
! 8110: _tcscpy(dstea, tmp);
! 8111: if (!m68k_asm_parse_movem(srcea, 0))
! 8112: return -1;
! 8113: dmode = asm_parse_mode(dstea, &dreg, &dval, dexts);
! 8114: }
! 8115: } else if (!_tcscmp(ins, _T("MOVEC"))) {
! 8116: if (dmode == Dreg || dmode == Areg) {
! 8117: _tcscpy(ins, _T("MOVEC2"));
! 8118: if (!m68k_asm_parse_movec(srcea, dstea))
! 8119: return -1;
! 8120: } else {
! 8121: TCHAR tmp[256];
! 8122: _tcscpy(ins, _T("MOVE2C"));
! 8123: _tcscpy(tmp, srcea);
! 8124: _tcscpy(srcea, dstea);
! 8125: dstea[0] = 0;
! 8126: if (!m68k_asm_parse_movec(srcea, tmp))
! 8127: return -1;
! 8128: }
! 8129: dmode = -1;
! 8130: }
! 8131:
! 8132: if (dmode == Areg) {
! 8133: int l = _tcslen(ins);
! 8134: if (l <= 2)
! 8135: return -1;
! 8136: TCHAR last = ins[l- 1];
! 8137: if (last == 'Q') {
! 8138: last = ins[l - 2];
! 8139: if (last != 'A') {
! 8140: ins[l - 1] = 'A';
! 8141: ins[l] = 'Q';
! 8142: ins[l + 1] = 0;
! 8143: }
! 8144: } else if (last != 'A') {
! 8145: _tcscat(ins, _T("A"));
! 8146: }
! 8147: }
! 8148:
! 8149: if (ins[_tcslen(ins) - 1] == 'Q') {
! 8150: quick = 1;
! 8151: ins[_tcslen(ins) - 1] = 0;
! 8152: }
! 8153:
! 8154: struct mnemolookup *lookup;
! 8155: for (lookup = lookuptab; lookup->name; lookup++) {
! 8156: if (!_tcscmp(ins, lookup->name))
! 8157: break;
! 8158: }
! 8159: if (!lookup->name) {
! 8160: // Check cc variants
! 8161: bool fp = ins[0] == 'F';
! 8162: for (lookup = lookuptab; lookup->name; lookup++) {
! 8163: const TCHAR *ccp = _tcsstr(lookup->name, _T("cc"));
! 8164: if (ccp) {
! 8165: TCHAR tmp[256];
! 8166: int i;
! 8167: for (i = 0; i < (fp ? 32 : 16); i++) {
! 8168: const TCHAR *ccname = fp ? fpccnames[i] : ccnames[i];
! 8169: _tcscpy(tmp, lookup->name);
! 8170: _tcscpy(tmp + (ccp - lookup->name), ccname);
! 8171: if (tmp[_tcslen(tmp) - 1] == ' ')
! 8172: tmp[_tcslen(tmp) - 1] = 0;
! 8173: if (!_tcscmp(tmp, ins)) {
! 8174: _tcscpy(ins, lookup->name);
! 8175: cc = i;
! 8176: // Bcc.B uses same encoding mode as MOVEQ
! 8177: if (size == 0) {
! 8178: quick = 2;
! 8179: }
! 8180: immrelpc = true;
! 8181: break;
! 8182: }
! 8183: }
! 8184: }
! 8185: if (cc >= 0)
! 8186: break;
! 8187: }
! 8188: }
! 8189:
! 8190: if (!lookup->name)
! 8191: return 0;
! 8192:
! 8193: int mnemo = lookup->mnemo;
! 8194:
! 8195: int found = 0;
! 8196: int sizemask = 0;
! 8197: int tsize = size;
! 8198: int unsized = 0;
! 8199:
! 8200: int round;
! 8201: for (round = 0; round < 9; round++) {
! 8202:
! 8203: if (!found && round == 8)
! 8204: return 0;
! 8205:
! 8206: if (round == 3) {
! 8207: // Q is always LONG sized
! 8208: if (quick == 1) {
! 8209: tsize = 2;
! 8210: }
! 8211: bool isimm = srcea[0] == '#';
! 8212: if (immrelpc && !isimm) {
! 8213: TCHAR tmp[256];
! 8214: _tcscpy(tmp, srcea);
! 8215: srcea[0] = '#';
! 8216: _tcscpy(srcea + 1, tmp);
! 8217: }
! 8218: smode = asm_parse_mode(srcea, &sreg, &sval, sexts);
! 8219: if (immrelpc && !isimm) {
! 8220: sval = sval - (pc + 2);
! 8221: }
! 8222: if (quick) {
! 8223: smode = immi;
! 8224: sreg = sval & 0xff;
! 8225: }
! 8226: }
! 8227:
! 8228: if (round == 1) {
! 8229: if (!quick && (sizemask == 1 || sizemask == 2 || sizemask == 4)) {
! 8230: tsize = 0;
! 8231: if (sizemask == 2)
! 8232: tsize = 1;
! 8233: else if (sizemask == 4)
! 8234: tsize = 2;
! 8235: } else {
! 8236: continue;
! 8237: }
! 8238: }
! 8239: if (round == 2 && !found) {
! 8240: unsized = 1;
! 8241: }
! 8242:
! 8243: if (round == 4 && smode == imm) {
! 8244: smode = imm0;
! 8245: } else if (round == 5 && smode == imm0) {
! 8246: smode = imm1;
! 8247: } else if (round == 6 && smode == imm1) {
! 8248: smode = imm2;
! 8249: } else if (round == 7 && smode == imm2) {
! 8250: smode = immi;
! 8251: sreg = sval & 0xff;
! 8252: } else if (round == 4) {
! 8253: round += 5 - 1;
! 8254: }
! 8255:
! 8256: int opcode;
! 8257: for (opcode = 0; opcode < 65536; opcode++) {
! 8258: struct instr *table = &table68k[opcode];
! 8259: if (table->mnemo != mnemo)
! 8260: continue;
! 8261: if (cc >= 0 && table->cc != cc)
! 8262: continue;
! 8263:
! 8264: #if 0
! 8265: if (round == 0) {
! 8266: 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,
! 8267: table->sreg, table->smode, table->suse, table->spos,
! 8268: table->dreg, table->dmode, table->duse, table->dpos,
! 8269: table->sduse);
! 8270: }
! 8271: #endif
! 8272:
! 8273: if (table->duse && !(table->dmode == dmode || (dmode >= imm && dmode <= imm2 && table->dmode >= imm && table->dmode <= imm2)))
! 8274: continue;
! 8275: if (round == 0) {
! 8276: sizemask |= 1 << table->size;
! 8277: }
! 8278: if (unsized > 0 && !table->unsized) {
! 8279: continue;
! 8280: }
! 8281:
! 8282: found++;
! 8283:
! 8284: if (round >= 3) {
! 8285:
! 8286: if (
! 8287: ((table->size == tsize || table->unsized)) &&
! 8288: ((!table->suse && smode < 0) || (table->suse && table->smode == smode)) &&
! 8289: ((!table->duse && dmode < 0) || (table->duse && (table->dmode == dmode || (dmode == imm && (table->dmode >= imm && table->dmode <= imm2))))) &&
! 8290: ((table->sreg == sreg || (table->smode >= absw && table->smode != immi))) &&
! 8291: ((table->dreg == dreg || table->dmode >= absw))
! 8292: )
! 8293: {
! 8294: if (inssize >= 0 && tsize != inssize)
! 8295: continue;
! 8296:
! 8297:
! 8298: data[dcnt++] = opcode;
! 8299: asm_add_extensions(data, &dcnt, smode, sval, sexts, pc, tsize);
! 8300: if (smode >= 0)
! 8301: asm_add_extensions(data, &dcnt, dmode, dval, dexts, pc, tsize);
! 8302: int i;
! 8303: for (i = 0; i < dcnt; i++) {
! 8304: out[i] = data[i];
! 8305: }
! 8306: return dcnt;
! 8307: }
! 8308:
! 8309: }
! 8310: }
! 8311: }
! 8312:
! 8313: return 0;
! 8314: }
! 8315:
1.1.1.7 root 8316: void m68k_disasm_2 (TCHAR *buf, int bufsize, uaecptr pc, uaecptr *nextpc, int cnt, uae_u32 *seaddr, uae_u32 *deaddr, int safemode)
1.1.1.4 root 8317: {
1.1.1.7 root 8318: uae_u32 seaddr2;
8319: uae_u32 deaddr2;
1.1.1.4 root 8320:
1.1.1.7 root 8321: if (buf)
8322: memset (buf, 0, bufsize * sizeof (TCHAR));
1.1.1.4 root 8323: if (!table68k)
8324: return;
8325: while (cnt-- > 0) {
8326: TCHAR instrname[100], *ccpt;
8327: int i;
8328: uae_u32 opcode;
1.1.1.7 root 8329: uae_u16 extra;
1.1.1.4 root 8330: struct mnemolookup *lookup;
8331: struct instr *dp;
1.1.1.7 root 8332: uaecptr oldpc;
8333: uaecptr m68kpc_illg = 0;
8334: bool illegal = false;
8335:
8336: seaddr2 = deaddr2 = 0;
8337: oldpc = pc;
8338: opcode = get_word_debug (pc);
8339: extra = get_word_debug (pc + 2);
8340: if (cpufunctbl[opcode] == op_illg_1 || cpufunctbl[opcode] == op_unimpl_1) {
8341: m68kpc_illg = pc + 2;
8342: illegal = TRUE;
8343: }
1.1.1.4 root 8344:
1.1.1.7 root 8345: dp = table68k + opcode;
8346: if (dp->mnemo == i_ILLG) {
8347: illegal = FALSE;
1.1.1.4 root 8348: opcode = 0x4AFC;
1.1.1.7 root 8349: dp = table68k + opcode;
1.1.1.4 root 8350: }
8351: for (lookup = lookuptab;lookup->mnemo != dp->mnemo; lookup++)
8352: ;
8353:
1.1.1.7 root 8354: buf = buf_out (buf, &bufsize, _T("%08X "), pc);
1.1.1.4 root 8355:
1.1.1.7 root 8356: pc += 2;
8357:
8358: if (lookup->friendlyname)
1.1.1.4 root 8359: _tcscpy (instrname, lookup->friendlyname);
8360: else
8361: _tcscpy (instrname, lookup->name);
1.1.1.7 root 8362: ccpt = _tcsstr (instrname, _T("cc"));
1.1.1.4 root 8363: if (ccpt != 0) {
1.1.1.7 root 8364: if ((opcode & 0xf000) == 0xf000)
8365: _tcscpy (ccpt, fpccnames[extra & 0x1f]);
8366: else
8367: _tcsncpy (ccpt, ccnames[dp->cc], 2);
1.1.1.4 root 8368: }
8369: disasm_size (instrname, dp);
8370:
8371: if (lookup->mnemo == i_MOVEC2 || lookup->mnemo == i_MOVE2C) {
1.1.1.7 root 8372: uae_u16 imm = extra;
1.1.1.4 root 8373: uae_u16 creg = imm & 0x0fff;
8374: uae_u16 r = imm >> 12;
8375: TCHAR regs[16];
1.1.1.7 root 8376: const TCHAR *cname = _T("?");
1.1.1.4 root 8377: int i;
8378: for (i = 0; m2cregs[i].regname; i++) {
8379: if (m2cregs[i].regno == creg)
8380: break;
8381: }
1.1.1.7 root 8382: _stprintf (regs, _T("%c%d"), r >= 8 ? 'A' : 'D', r >= 8 ? r - 8 : r);
1.1.1.4 root 8383: if (m2cregs[i].regname)
8384: cname = m2cregs[i].regname;
8385: if (lookup->mnemo == i_MOVE2C) {
8386: _tcscat (instrname, regs);
1.1.1.7 root 8387: _tcscat (instrname, _T(","));
1.1.1.4 root 8388: _tcscat (instrname, cname);
8389: } else {
8390: _tcscat (instrname, cname);
1.1.1.7 root 8391: _tcscat (instrname, _T(","));
1.1.1.4 root 8392: _tcscat (instrname, regs);
8393: }
1.1.1.7 root 8394: pc += 2;
1.1.1.4 root 8395: } else if (lookup->mnemo == i_MVMEL) {
1.1.1.7 root 8396: uae_u16 mask = extra;
8397: pc += 2;
8398: pc = ShowEA (0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, deaddr, safemode);
8399: _tcscat (instrname, _T(","));
8400: movemout (instrname, mask, dp->dmode, 0);
1.1.1.4 root 8401: } else if (lookup->mnemo == i_MVMLE) {
1.1.1.7 root 8402: uae_u16 mask = extra;
8403: pc += 2;
8404: movemout(instrname, mask, dp->dmode, 0);
8405: _tcscat(instrname, _T(","));
8406: pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, deaddr, safemode);
8407: } else if (lookup->mnemo == i_DIVL || lookup->mnemo == i_MULL) {
8408: TCHAR *p;
8409: pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &seaddr2, safemode);
8410: extra = get_word_debug(pc);
8411: pc += 2;
8412: p = instrname + _tcslen(instrname);
8413: if (extra & 0x0400)
8414: _stprintf(p, _T(",D%d:D%d"), extra & 7, (extra >> 12) & 7);
8415: else
8416: _stprintf(p, _T(",D%d"), (extra >> 12) & 7);
8417: } else if (lookup->mnemo == i_MOVES) {
8418: TCHAR *p;
8419: pc += 2;
1.1.1.9 ! root 8420: if (!(extra & 0x0800)) {
1.1.1.7 root 8421: pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &seaddr2, safemode);
8422: p = instrname + _tcslen(instrname);
8423: _stprintf(p, _T(",%c%d"), (extra & 0x8000) ? 'A' : 'D', (extra >> 12) & 7);
8424: } else {
8425: p = instrname + _tcslen(instrname);
8426: _stprintf(p, _T("%c%d,"), (extra & 0x8000) ? 'A' : 'D', (extra >> 12) & 7);
8427: pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &seaddr2, safemode);
8428: }
8429: } else if (lookup->mnemo == i_BFEXTS || lookup->mnemo == i_BFEXTU ||
8430: lookup->mnemo == i_BFCHG || lookup->mnemo == i_BFCLR ||
8431: lookup->mnemo == i_BFFFO || lookup->mnemo == i_BFINS ||
8432: lookup->mnemo == i_BFSET || lookup->mnemo == i_BFTST) {
8433: TCHAR *p;
8434: int reg = -1;
8435:
8436: pc += 2;
8437: p = instrname + _tcslen(instrname);
8438: if (lookup->mnemo == i_BFEXTS || lookup->mnemo == i_BFEXTU || lookup->mnemo == i_BFFFO || lookup->mnemo == i_BFINS)
8439: reg = (extra >> 12) & 7;
8440: if (lookup->mnemo == i_BFINS)
8441: _stprintf(p, _T("D%d,"), reg);
8442: pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &seaddr2, safemode);
8443: _tcscat(instrname, _T(" {"));
8444: p = instrname + _tcslen(instrname);
8445: if (extra & 0x0800)
8446: _stprintf(p, _T("D%d"), (extra >> 6) & 7);
8447: else
8448: _stprintf(p, _T("%d"), (extra >> 6) & 31);
8449: _tcscat(instrname, _T(":"));
8450: p = instrname + _tcslen(instrname);
8451: if (extra & 0x0020)
8452: _stprintf(p, _T("D%d"), extra & 7);
8453: else
8454: _stprintf(p, _T("%d"), extra & 31);
8455: _tcscat(instrname, _T("}"));
8456: p = instrname + _tcslen(instrname);
8457: if (lookup->mnemo == i_BFFFO || lookup->mnemo == i_BFEXTS || lookup->mnemo == i_BFEXTU)
8458: _stprintf(p, _T(",D%d"), reg);
8459: } else if (lookup->mnemo == i_CPUSHA || lookup->mnemo == i_CPUSHL || lookup->mnemo == i_CPUSHP ||
8460: lookup->mnemo == i_CINVA || lookup->mnemo == i_CINVL || lookup->mnemo == i_CINVP) {
8461: if ((opcode & 0xc0) == 0xc0)
8462: _tcscat(instrname, _T("BC"));
8463: else if (opcode & 0x80)
8464: _tcscat(instrname, _T("IC"));
8465: else if (opcode & 0x40)
8466: _tcscat(instrname, _T("DC"));
8467: else
8468: _tcscat(instrname, _T("?"));
8469: if (lookup->mnemo == i_CPUSHL || lookup->mnemo == i_CPUSHP || lookup->mnemo == i_CINVL || lookup->mnemo == i_CINVP) {
8470: TCHAR *p = instrname + _tcslen(instrname);
8471: _stprintf(p, _T(",(A%d)"), opcode & 7);
8472: }
8473: } else if (lookup->mnemo == i_FPP) {
8474: TCHAR *p;
8475: int ins = extra & 0x3f;
8476: int size = (extra >> 10) & 7;
8477:
8478: pc += 2;
8479: if ((extra & 0xfc00) == 0x5c00) { // FMOVECR (=i_FPP with source specifier = 7)
8480: fpdata fp;
1.1.1.9 ! root 8481: fpu_get_constant(&fp, extra);
! 8482: _stprintf(instrname, _T("FMOVECR.X #0x%02x [%s],FP%d"), extra & 0x7f, fpp_print(&fp, 0), (extra >> 7) & 7);
1.1.1.7 root 8483: } else if ((extra & 0x8000) == 0x8000) { // FMOVEM
8484: int dr = (extra >> 13) & 1;
8485: int mode;
8486: int dreg = (extra >> 4) & 7;
8487: int regmask, fpmode;
8488:
8489: if (extra & 0x4000) {
8490: mode = (extra >> 11) & 3;
8491: regmask = extra & 0xff; // FMOVEM FPx
8492: fpmode = 1;
8493: _tcscpy(instrname, _T("FMOVEM.X "));
8494: } else {
8495: mode = 0;
8496: regmask = (extra >> 10) & 7; // FMOVEM control
8497: fpmode = 2;
8498: _tcscpy(instrname, _T("FMOVEM.L "));
8499: if (regmask == 1 || regmask == 2 || regmask == 4)
8500: _tcscpy(instrname, _T("FMOVE.L "));
8501: }
8502: p = instrname + _tcslen(instrname);
8503: if (dr) {
8504: if (mode & 1)
8505: _stprintf(instrname, _T("D%d"), dreg);
8506: else
8507: movemout(instrname, regmask, dp->dmode, fpmode);
8508: _tcscat(instrname, _T(","));
8509: pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, deaddr, safemode);
8510: } else {
8511: pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, deaddr, safemode);
8512: _tcscat(instrname, _T(","));
8513: p = instrname + _tcslen(instrname);
8514: if (mode & 1)
8515: _stprintf(p, _T("D%d"), dreg);
8516: else
8517: movemout(p, regmask, dp->dmode, fpmode);
8518: }
8519: } else {
8520: if (fpuopcodes[ins])
8521: _tcscpy(instrname, fpuopcodes[ins]);
8522: else
8523: _tcscpy(instrname, _T("F?"));
8524:
8525: if ((extra & 0xe000) == 0x6000) { // FMOVE to memory
8526: int kfactor = extra & 0x7f;
8527: _tcscpy(instrname, _T("FMOVE."));
8528: _tcscat(instrname, fpsizes[size]);
8529: _tcscat(instrname, _T(" "));
8530: p = instrname + _tcslen(instrname);
8531: _stprintf(p, _T("FP%d,"), (extra >> 7) & 7);
8532: pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, fpsizeconv[size], instrname, &deaddr2, safemode);
8533: p = instrname + _tcslen(instrname);
8534: if (size == 7) {
8535: _stprintf(p, _T(" {D%d}"), (kfactor >> 4));
8536: } else if (kfactor) {
8537: if (kfactor & 0x40)
8538: kfactor |= ~0x3f;
8539: _stprintf(p, _T(" {%d}"), kfactor);
8540: }
8541: } else {
8542: if (extra & 0x4000) { // source is EA
8543: _tcscat(instrname, _T("."));
8544: _tcscat(instrname, fpsizes[size]);
8545: _tcscat(instrname, _T(" "));
8546: pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, fpsizeconv[size], instrname, &seaddr2, safemode);
8547: } else { // source is FPx
8548: p = instrname + _tcslen(instrname);
8549: _stprintf(p, _T(".X FP%d"), (extra >> 10) & 7);
8550: }
8551: p = instrname + _tcslen(instrname);
8552: if ((extra & 0x4000) || (((extra >> 7) & 7) != ((extra >> 10) & 7)))
8553: _stprintf(p, _T(",FP%d"), (extra >> 7) & 7);
8554: if (ins >= 0x30 && ins < 0x38) { // FSINCOS
8555: p = instrname + _tcslen(instrname);
8556: _stprintf(p, _T(",FP%d"), extra & 7);
8557: }
8558: }
8559: }
8560: } else if ((opcode & 0xf000) == 0xa000) {
8561: _tcscpy(instrname, _T("A-LINE"));
1.1.1.4 root 8562: } else {
8563: if (dp->suse) {
1.1.1.7 root 8564: pc = ShowEA (0, pc, opcode, dp->sreg, dp->smode, dp->size, instrname, &seaddr2, safemode);
1.1.1.4 root 8565: }
8566: if (dp->suse && dp->duse)
1.1.1.7 root 8567: _tcscat (instrname, _T(","));
1.1.1.4 root 8568: if (dp->duse) {
1.1.1.7 root 8569: pc = ShowEA (0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &deaddr2, safemode);
1.1.1.4 root 8570: }
8571: }
8572:
1.1.1.7 root 8573: for (i = 0; i < (int)(pc - oldpc) / 2 && i < 5; i++) {
8574: buf = buf_out (buf, &bufsize, _T("%04x "), get_word_debug (oldpc + i * 2));
1.1.1.4 root 8575: }
8576: while (i++ < 5)
1.1.1.7 root 8577: buf = buf_out (buf, &bufsize, _T(" "));
1.1.1.4 root 8578:
1.1.1.7 root 8579: if (illegal)
8580: buf = buf_out (buf, &bufsize, _T("[ "));
8581: buf = buf_out (buf, &bufsize, instrname);
8582: if (illegal)
8583: buf = buf_out (buf, &bufsize, _T(" ]"));
1.1.1.4 root 8584:
8585: if (ccpt != 0) {
1.1.1.7 root 8586: uaecptr addr2 = deaddr2 ? deaddr2 : seaddr2;
1.1.1.4 root 8587: if (deaddr)
1.1.1.7 root 8588: *deaddr = pc;
8589: if ((opcode & 0xf000) == 0xf000) {
8590: if (fpp_cond(dp->cc)) {
8591: buf = buf_out(buf, &bufsize, _T(" == $%08x (T)"), addr2);
8592: } else {
8593: buf = buf_out(buf, &bufsize, _T(" == $%08x (F)"), addr2);
8594: }
8595: } else {
8596: if (cctrue (dp->cc)) {
8597: buf = buf_out (buf, &bufsize, _T(" == $%08x (T)"), addr2);
8598: } else {
8599: buf = buf_out (buf, &bufsize, _T(" == $%08x (F)"), addr2);
8600: }
8601: }
1.1.1.4 root 8602: } else if ((opcode & 0xff00) == 0x6100) { /* BSR */
8603: if (deaddr)
1.1.1.7 root 8604: *deaddr = pc;
8605: buf = buf_out (buf, &bufsize, _T(" == $%08x"), seaddr2);
1.1.1.4 root 8606: }
1.1.1.7 root 8607: buf = buf_out (buf, &bufsize, _T("\n"));
8608:
8609: if (illegal)
8610: pc = m68kpc_illg;
1.1.1.4 root 8611: }
8612: if (nextpc)
1.1.1.7 root 8613: *nextpc = pc;
8614: if (seaddr)
8615: *seaddr = seaddr2;
8616: if (deaddr)
8617: *deaddr = deaddr2;
1.1.1.4 root 8618: }
8619:
1.1.1.7 root 8620: void m68k_disasm_ea (uaecptr addr, uaecptr *nextpc, int cnt, uae_u32 *seaddr, uae_u32 *deaddr)
8621: {
8622: TCHAR *buf;
8623:
8624: buf = xmalloc (TCHAR, (MAX_LINEWIDTH + 1) * cnt);
8625: if (!buf)
8626: return;
8627: m68k_disasm_2 (buf, (MAX_LINEWIDTH + 1) * cnt, addr, nextpc, cnt, seaddr, deaddr, 1);
8628: xfree (buf);
8629: }
8630: void m68k_disasm (uaecptr addr, uaecptr *nextpc, int cnt)
1.1.1.4 root 8631: {
1.1.1.7 root 8632: TCHAR *buf;
8633:
8634: buf = xmalloc (TCHAR, (MAX_LINEWIDTH + 1) * cnt);
8635: if (!buf)
8636: return;
8637: m68k_disasm_2 (buf, (MAX_LINEWIDTH + 1) * cnt, addr, nextpc, cnt, NULL, NULL, 0);
8638: console_out_f (_T("%s"), buf);
8639: xfree (buf);
1.1.1.4 root 8640: }
1.1.1.7 root 8641: void m68k_disasm_file (FILE *f, uaecptr addr, uaecptr *nextpc, int cnt)
1.1.1.4 root 8642: {
1.1.1.7 root 8643: TCHAR *buf;
8644:
8645: buf = xmalloc (TCHAR, (MAX_LINEWIDTH + 1) * cnt);
8646: if (!buf)
8647: return;
8648: console_out_FILE = f;
8649: m68k_disasm_2 (buf, (MAX_LINEWIDTH + 1) * cnt, addr, nextpc, cnt, NULL, NULL, 0);
8650: f_out (f, _T("%s"), buf);
8651: xfree (buf);
8652: console_out_FILE = NULL;
1.1.1.4 root 8653: }
8654:
8655: /*************************************************************
8656: Disasm the m68kcode at the given address into instrname
8657: and instrcode
8658: *************************************************************/
8659: void sm68k_disasm (TCHAR *instrname, TCHAR *instrcode, uaecptr addr, uaecptr *nextpc)
8660: {
8661: TCHAR *ccpt;
8662: uae_u32 opcode;
8663: struct mnemolookup *lookup;
8664: struct instr *dp;
1.1.1.7 root 8665: uaecptr pc, oldpc;
1.1.1.4 root 8666:
1.1.1.7 root 8667: pc = oldpc = addr;
8668: opcode = get_word_debug (pc);
1.1.1.4 root 8669: if (cpufunctbl[opcode] == op_illg_1) {
8670: opcode = 0x4AFC;
8671: }
8672: dp = table68k + opcode;
8673: for (lookup = lookuptab;lookup->mnemo != dp->mnemo; lookup++);
8674:
1.1.1.7 root 8675: pc += 2;
1.1.1.4 root 8676:
8677: _tcscpy (instrname, lookup->name);
1.1.1.7 root 8678: ccpt = _tcsstr (instrname, _T("cc"));
1.1.1.4 root 8679: if (ccpt != 0) {
8680: _tcsncpy (ccpt, ccnames[dp->cc], 2);
8681: }
8682: switch (dp->size){
1.1.1.7 root 8683: case sz_byte: _tcscat (instrname, _T(".B ")); break;
8684: case sz_word: _tcscat (instrname, _T(".W ")); break;
8685: case sz_long: _tcscat (instrname, _T(".L ")); break;
8686: default: _tcscat (instrname, _T(" ")); break;
1.1.1.4 root 8687: }
8688:
8689: if (dp->suse) {
1.1.1.7 root 8690: pc = ShowEA (0, pc, opcode, dp->sreg, dp->smode, dp->size, instrname, NULL, 0);
1.1.1.4 root 8691: }
8692: if (dp->suse && dp->duse)
1.1.1.7 root 8693: _tcscat (instrname, _T(","));
1.1.1.4 root 8694: if (dp->duse) {
1.1.1.7 root 8695: pc = ShowEA (0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, NULL, 0);
1.1.1.4 root 8696: }
8697: if (instrcode)
8698: {
8699: int i;
1.1.1.7 root 8700: for (i = 0; i < (int)(pc - oldpc) / 2; i++)
1.1.1.4 root 8701: {
1.1.1.7 root 8702: _stprintf (instrcode, _T("%04x "), get_iword_debug (oldpc + i * 2));
1.1.1.4 root 8703: instrcode += _tcslen (instrcode);
8704: }
8705: }
8706: if (nextpc)
1.1.1.7 root 8707: *nextpc = pc;
1.1.1.4 root 8708: }
8709:
8710: struct cpum2c m2cregs[] = {
1.1.1.7 root 8711: { 0, _T("SFC") },
8712: { 1, _T("DFC") },
8713: { 2, _T("CACR") },
8714: { 3, _T("TC") },
8715: { 4, _T("ITT0") },
8716: { 5, _T("ITT1") },
8717: { 6, _T("DTT0") },
8718: { 7, _T("DTT1") },
8719: { 8, _T("BUSC") },
8720: { 0x800, _T("USP") },
8721: { 0x801, _T("VBR") },
8722: { 0x802, _T("CAAR") },
8723: { 0x803, _T("MSP") },
8724: { 0x804, _T("ISP") },
8725: { 0x805, _T("MMUS") },
8726: { 0x806, _T("URP") },
8727: { 0x807, _T("SRP") },
8728: { 0x808, _T("PCR") },
8729: { -1, NULL }
1.1.1.4 root 8730: };
8731:
1.1.1.7 root 8732: void m68k_dumpstate_2 (uaecptr pc, uaecptr *nextpc)
1.1.1.4 root 8733: {
8734: int i, j;
8735:
8736: for (i = 0; i < 8; i++){
1.1.1.7 root 8737: console_out_f (_T(" D%d %08X "), i, m68k_dreg (regs, i));
8738: if ((i & 3) == 3) console_out_f (_T("\n"));
1.1.1.4 root 8739: }
8740: for (i = 0; i < 8; i++){
1.1.1.7 root 8741: console_out_f (_T(" A%d %08X "), i, m68k_areg (regs, i));
8742: if ((i & 3) == 3) console_out_f (_T("\n"));
1.1.1.4 root 8743: }
8744: if (regs.s == 0)
8745: regs.usp = m68k_areg (regs, 7);
8746: if (regs.s && regs.m)
8747: regs.msp = m68k_areg (regs, 7);
8748: if (regs.s && regs.m == 0)
8749: regs.isp = m68k_areg (regs, 7);
8750: j = 2;
1.1.1.7 root 8751: console_out_f (_T("USP %08X ISP %08X "), regs.usp, regs.isp);
1.1.1.4 root 8752: for (i = 0; m2cregs[i].regno>= 0; i++) {
8753: if (!movec_illg (m2cregs[i].regno)) {
1.1.1.7 root 8754: if (!_tcscmp (m2cregs[i].regname, _T("USP")) || !_tcscmp (m2cregs[i].regname, _T("ISP")))
1.1.1.4 root 8755: continue;
8756: if (j > 0 && (j % 4) == 0)
1.1.1.7 root 8757: console_out_f (_T("\n"));
8758: console_out_f (_T("%-4s %08X "), m2cregs[i].regname, val_move2c (m2cregs[i].regno));
1.1.1.4 root 8759: j++;
8760: }
8761: }
8762: if (j > 0)
1.1.1.7 root 8763: console_out_f (_T("\n"));
8764: 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 8765: regs.t1, regs.t0, regs.s, regs.m,
8766: GET_XFLG (), GET_NFLG (), GET_ZFLG (),
8767: GET_VFLG (), GET_CFLG (),
8768: regs.intmask, regs.stopped);
8769: #ifdef FPUEMU
8770: if (currprefs.fpu_model) {
8771: uae_u32 fpsr;
1.1.1.9 ! root 8772: for (i = 0; i < 8; i++) {
! 8773: if (!(i & 1))
! 8774: console_out_f(_T("%d: "), i);
! 8775: console_out_f (_T("%s "), fpp_print(®s.fp[i], -1));
! 8776: console_out_f (_T("%s "), fpp_print(®s.fp[i], 0));
! 8777: if (i & 1)
1.1.1.7 root 8778: console_out_f (_T("\n"));
1.1.1.4 root 8779: }
1.1.1.7 root 8780: fpsr = fpp_get_fpsr ();
1.1.1.9 ! root 8781: console_out_f (_T("FPSR: %08X FPCR: %08x FPIAR: %08x N=%d Z=%d I=%d NAN=%d\n"),
1.1.1.7 root 8782: fpsr, regs.fpcr, regs.fpiar,
1.1.1.4 root 8783: (fpsr & 0x8000000) != 0,
8784: (fpsr & 0x4000000) != 0,
8785: (fpsr & 0x2000000) != 0,
8786: (fpsr & 0x1000000) != 0);
8787: }
8788: #endif
1.1.1.7 root 8789: if (currprefs.mmu_model == 68030) {
8790: #ifndef WINUAE_FOR_HATARI
8791: console_out_f (_T("SRP: %llX CRP: %llX\n"), srp_030, crp_030);
1.1.1.8 root 8792: #else /* Use PRIX64 since MinGW on Windows does not know about %llx (?) */
8793: console_out_f (_T("SRP: %"PRIX64" CRP: %"PRIX64"\n"), (uint64_t)srp_030, (uint64_t)crp_030);
1.1.1.7 root 8794: #endif
8795: console_out_f (_T("TT0: %08X TT1: %08X TC: %08X\n"), tt0_030, tt1_030, tc_030);
8796: }
1.1.1.9 ! root 8797: if (currprefs.cpu_compatible) {
! 8798: if (currprefs.cpu_model == 68000) {
! 8799: struct instr *dp;
! 8800: struct mnemolookup *lookup1, *lookup2;
! 8801: dp = table68k + regs.irc;
! 8802: for (lookup1 = lookuptab; lookup1->mnemo != dp->mnemo; lookup1++)
! 8803: ;
! 8804: dp = table68k + regs.ir;
! 8805: for (lookup2 = lookuptab; lookup2->mnemo != dp->mnemo; lookup2++)
! 8806: ;
! 8807: 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);
! 8808: } else if (currprefs.cpu_model == 68020 || currprefs.cpu_model == 68030) {
! 8809: console_out_f (_T("Prefetch %08x %08x (%d) %04x (%d) %04x (%d) %04x (%d)\n"),
! 8810: regs.cacheholdingaddr020, regs.cacheholdingdata020, regs.cacheholdingdata_valid,
! 8811: regs.prefetch020[0], regs.prefetch020_valid[0],
! 8812: regs.prefetch020[1], regs.prefetch020_valid[1],
! 8813: regs.prefetch020[2], regs.prefetch020_valid[2]);
! 8814: }
1.1.1.4 root 8815: }
8816:
1.1.1.7 root 8817: if (pc != 0xffffffff) {
8818: m68k_disasm (pc, nextpc, 1);
8819: if (nextpc)
8820: console_out_f (_T("Next PC: %08x\n"), *nextpc);
8821: }
8822: }
8823: void m68k_dumpstate (uaecptr *nextpc)
8824: {
8825: m68k_dumpstate_2 (m68k_getpc (), nextpc);
8826: }
8827: #ifdef WINUAE_FOR_HATARI
8828: void m68k_dumpstate_file (FILE *f, uaecptr *nextpc)
8829: {
8830: console_out_FILE = f;
8831: m68k_dumpstate_2 (m68k_getpc (), nextpc);
8832: console_out_FILE = NULL;
8833: }
8834: #endif
1.1.1.9 ! root 8835: void m68k_dumpcache (bool dc)
1.1.1.7 root 8836: {
8837: int i , j;
8838:
8839: if (!currprefs.cpu_compatible)
8840: return;
8841: if (currprefs.cpu_model == 68020) {
8842: for (i = 0; i < CACHELINES020; i += 4) {
8843: for (j = 0; j < 4; j++) {
8844: int s = i + j;
8845: uaecptr addr;
1.1.1.9 ! root 8846: int fc;
1.1.1.7 root 8847: struct cache020 *c = &caches020[s];
1.1.1.9 ! root 8848: fc = c->tag & 1;
1.1.1.7 root 8849: addr = c->tag & ~1;
8850: addr |= s << 2;
1.1.1.9 ! root 8851: console_out_f (_T("%08X%c:%08X%c"), addr, fc ? 'S' : 'U', c->data, c->valid ? '*' : ' ');
1.1.1.7 root 8852: }
8853: console_out_f (_T("\n"));
8854: }
8855: } else if (currprefs.cpu_model == 68030) {
8856: for (i = 0; i < CACHELINES030; i++) {
1.1.1.9 ! root 8857: struct cache030 *c = dc ? &dcaches030[i] : &icaches030[i];
! 8858: int fc;
1.1.1.7 root 8859: uaecptr addr;
1.1.1.9 ! root 8860: if (!dc) {
! 8861: fc = (c->tag & 1) ? 6 : 2;
! 8862: } else {
! 8863: fc = c->fc;
! 8864: }
1.1.1.7 root 8865: addr = c->tag & ~1;
8866: addr |= i << 4;
1.1.1.9 ! root 8867: console_out_f (_T("%08X %d: "), addr, fc);
1.1.1.7 root 8868: for (j = 0; j < 4; j++) {
8869: console_out_f (_T("%08X%c "), c->data[j], c->valid[j] ? '*' : ' ');
8870: }
8871: console_out_f (_T("\n"));
8872: }
1.1.1.9 ! root 8873: } else if (currprefs.cpu_model >= 68040) {
! 8874: uae_u32 tagmask = dc ? cachedtag04060mask : cacheitag04060mask;
! 8875: for (i = 0; i < cachedsets04060; i++) {
! 8876: struct cache040 *c = dc ? &dcaches040[i] : &icaches040[i];
! 8877: for (j = 0; j < CACHELINES040; j++) {
! 8878: if (c->valid[j]) {
! 8879: uae_u32 addr = (c->tag[j] & tagmask) | (i << 4);
! 8880: write_log(_T("%02d:%d %08x = %08x%c %08x%c %08x%c %08x%c\n"),
! 8881: i, j, addr,
! 8882: c->data[j][0], c->dirty[j][0] ? '*' : ' ',
! 8883: c->data[j][1], c->dirty[j][1] ? '*' : ' ',
! 8884: c->data[j][2], c->dirty[j][2] ? '*' : ' ',
! 8885: c->data[j][3], c->dirty[j][3] ? '*' : ' ');
! 8886: }
! 8887: }
! 8888: }
1.1.1.7 root 8889: }
1.1.1.4 root 8890: }
8891:
8892: #ifdef SAVESTATE
8893:
8894: /* CPU save/restore code */
8895:
8896: #define CPUTYPE_EC 1
8897: #define CPUMODE_HALT 1
8898:
8899: uae_u8 *restore_cpu (uae_u8 *src)
8900: {
1.1.1.7 root 8901: int i, j , flags, model;
1.1.1.4 root 8902: uae_u32 l;
8903:
1.1.1.7 root 8904: currprefs.cpu_model = changed_prefs.cpu_model = model = restore_u32 ();
1.1.1.4 root 8905: flags = restore_u32 ();
8906: changed_prefs.address_space_24 = 0;
8907: if (flags & CPUTYPE_EC)
8908: changed_prefs.address_space_24 = 1;
8909: currprefs.address_space_24 = changed_prefs.address_space_24;
8910: currprefs.cpu_compatible = changed_prefs.cpu_compatible;
8911: currprefs.cpu_cycle_exact = changed_prefs.cpu_cycle_exact;
1.1.1.8 root 8912: currprefs.cpu_memory_cycle_exact = changed_prefs.cpu_memory_cycle_exact;
1.1.1.4 root 8913: currprefs.blitter_cycle_exact = changed_prefs.blitter_cycle_exact;
8914: currprefs.cpu_frequency = changed_prefs.cpu_frequency = 0;
8915: currprefs.cpu_clock_multiplier = changed_prefs.cpu_clock_multiplier = 0;
8916: for (i = 0; i < 15; i++)
8917: regs.regs[i] = restore_u32 ();
8918: regs.pc = restore_u32 ();
8919: regs.irc = restore_u16 ();
8920: regs.ir = restore_u16 ();
8921: regs.usp = restore_u32 ();
8922: regs.isp = restore_u32 ();
8923: regs.sr = restore_u16 ();
1.1.1.7 root 8924: printf ( "restore %x %x %x\n" , regs.usp , regs.isp , regs.sr );
1.1.1.4 root 8925: l = restore_u32 ();
8926: if (l & CPUMODE_HALT) {
8927: regs.stopped = 1;
8928: } else {
8929: regs.stopped = 0;
8930: }
8931: if (model >= 68010) {
8932: regs.dfc = restore_u32 ();
8933: regs.sfc = restore_u32 ();
8934: regs.vbr = restore_u32 ();
8935: }
8936: if (model >= 68020) {
8937: regs.caar = restore_u32 ();
8938: regs.cacr = restore_u32 ();
8939: regs.msp = restore_u32 ();
8940: }
8941: if (model >= 68030) {
1.1.1.7 root 8942: crp_030 = fake_crp_030 = restore_u64 ();
8943: srp_030 = fake_srp_030 = restore_u64 ();
8944: tt0_030 = fake_tt0_030 = restore_u32 ();
8945: tt1_030 = fake_tt1_030 = restore_u32 ();
8946: tc_030 = fake_tc_030 = restore_u32 ();
8947: mmusr_030 = fake_mmusr_030 = restore_u16 ();
1.1.1.4 root 8948: }
8949: if (model >= 68040) {
8950: regs.itt0 = restore_u32 ();
8951: regs.itt1 = restore_u32 ();
8952: regs.dtt0 = restore_u32 ();
8953: regs.dtt1 = restore_u32 ();
8954: regs.tcr = restore_u32 ();
8955: regs.urp = restore_u32 ();
8956: regs.srp = restore_u32 ();
8957: }
8958: if (model >= 68060) {
8959: regs.buscr = restore_u32 ();
8960: regs.pcr = restore_u32 ();
8961: }
8962: if (flags & 0x80000000) {
8963: int khz = restore_u32 ();
8964: restore_u32 ();
8965: if (khz > 0 && khz < 800000)
8966: currprefs.m68k_speed = changed_prefs.m68k_speed = 0;
8967: }
1.1.1.7 root 8968: set_cpu_caches (true);
8969: if (flags & 0x40000000) {
8970: if (model == 68020) {
8971: for (i = 0; i < CACHELINES020; i++) {
8972: caches020[i].data = restore_u32 ();
8973: caches020[i].tag = restore_u32 ();
8974: caches020[i].valid = restore_u8 () != 0;
8975: }
8976: regs.prefetch020addr = restore_u32 ();
8977: regs.cacheholdingaddr020 = restore_u32 ();
8978: regs.cacheholdingdata020 = restore_u32 ();
8979: if (flags & 0x20000000) {
1.1.1.9 ! root 8980: if (flags & 0x4000000) {
! 8981: // 3.6 new (back to 16 bits)
! 8982: for (i = 0; i < CPU_PIPELINE_MAX; i++) {
! 8983: uae_u32 v = restore_u32();
! 8984: regs.prefetch020[i] = v >> 16;
! 8985: regs.prefetch020_valid[i] = (v & 1) != 0;
! 8986: }
! 8987: } else {
! 8988: // old
! 8989: uae_u32 v = restore_u32();
! 8990: regs.prefetch020[0] = v >> 16;
! 8991: regs.prefetch020[1] = (uae_u16)v;
! 8992: v = restore_u32();
! 8993: regs.prefetch020[2] = v >> 16;
! 8994: regs.prefetch020[3] = (uae_u16)v;
! 8995: restore_u32();
! 8996: restore_u32();
! 8997: regs.prefetch020_valid[0] = true;
! 8998: regs.prefetch020_valid[1] = true;
! 8999: regs.prefetch020_valid[2] = true;
! 9000: regs.prefetch020_valid[3] = true;
! 9001: }
1.1.1.7 root 9002: }
9003: } else if (model == 68030) {
9004: for (i = 0; i < CACHELINES030; i++) {
9005: for (j = 0; j < 4; j++) {
9006: icaches030[i].data[j] = restore_u32 ();
9007: icaches030[i].valid[j] = restore_u8 () != 0;
9008: }
9009: icaches030[i].tag = restore_u32 ();
9010: }
9011: for (i = 0; i < CACHELINES030; i++) {
9012: for (j = 0; j < 4; j++) {
9013: dcaches030[i].data[j] = restore_u32 ();
9014: dcaches030[i].valid[j] = restore_u8 () != 0;
9015: }
9016: dcaches030[i].tag = restore_u32 ();
9017: }
9018: regs.prefetch020addr = restore_u32 ();
9019: regs.cacheholdingaddr020 = restore_u32 ();
9020: regs.cacheholdingdata020 = restore_u32 ();
1.1.1.9 ! root 9021: if (flags & 0x4000000) {
! 9022: for (i = 0; i < CPU_PIPELINE_MAX; i++) {
! 9023: uae_u32 v = restore_u32();
! 9024: regs.prefetch020[i] = v >> 16;
! 9025: regs.prefetch020_valid[i] = (v & 1) != 0;
! 9026: }
! 9027: } else {
! 9028: for (i = 0; i < CPU_PIPELINE_MAX; i++) {
! 9029: regs.prefetch020[i] = restore_u32 ();
! 9030: regs.prefetch020_valid[i] = false;
! 9031: }
! 9032: }
! 9033: } else if (model == 68040) {
1.1.1.7 root 9034: if (flags & 0x8000000) {
1.1.1.9 ! root 9035: for (i = 0; i < ((model == 68060 && (flags & 0x4000000)) ? CACHESETS060 : CACHESETS040); i++) {
1.1.1.7 root 9036: for (j = 0; j < CACHELINES040; j++) {
1.1.1.9 ! root 9037: struct cache040 *c = &icaches040[i];
! 9038: c->data[j][0] = restore_u32();
! 9039: c->data[j][1] = restore_u32();
! 9040: c->data[j][2] = restore_u32();
! 9041: c->data[j][3] = restore_u32();
! 9042: c->tag[j] = restore_u32();
! 9043: c->valid[j] = restore_u16() & 1;
1.1.1.7 root 9044: }
9045: }
9046: regs.prefetch020addr = restore_u32();
9047: regs.cacheholdingaddr020 = restore_u32();
9048: regs.cacheholdingdata020 = restore_u32();
9049: for (i = 0; i < CPU_PIPELINE_MAX; i++)
1.1.1.9 ! root 9050: regs.prefetch040[i] = restore_u32();
! 9051: if (flags & 0x4000000) {
! 9052: for (i = 0; i < (model == 68060 ? CACHESETS060 : CACHESETS040); i++) {
! 9053: for (j = 0; j < CACHELINES040; j++) {
! 9054: struct cache040 *c = &dcaches040[i];
! 9055: c->data[j][0] = restore_u32();
! 9056: c->data[j][1] = restore_u32();
! 9057: c->data[j][2] = restore_u32();
! 9058: c->data[j][3] = restore_u32();
! 9059: c->tag[j] = restore_u32();
! 9060: uae_u16 v = restore_u16();
! 9061: c->valid[j] = (v & 1) != 0;
! 9062: c->dirty[j][0] = (v & 0x10) != 0;
! 9063: c->dirty[j][1] = (v & 0x20) != 0;
! 9064: c->dirty[j][2] = (v & 0x40) != 0;
! 9065: c->dirty[j][3] = (v & 0x80) != 0;
! 9066: c->gdirty[j] = c->dirty[j][0] || c->dirty[j][1] || c->dirty[j][2] || c->dirty[j][3];
! 9067: }
! 9068: }
! 9069: }
1.1.1.7 root 9070: }
9071: }
9072: if (model >= 68020) {
1.1.1.9 ! root 9073: restore_u32 (); // regs.ce020memcycles
! 9074: regs.ce020startcycle = regs.ce020endcycle = 0;
1.1.1.7 root 9075: restore_u32 ();
9076: }
9077: }
9078: if (flags & 0x10000000) {
9079: regs.chipset_latch_rw = restore_u32 ();
9080: regs.chipset_latch_read = restore_u32 ();
9081: regs.chipset_latch_write = restore_u32 ();
9082: }
9083:
1.1.1.9 ! root 9084: regs.pipeline_pos = -1;
! 9085: regs.pipeline_stop = 0;
! 9086: if (flags & 0x4000000 && currprefs.cpu_model == 68020) {
! 9087: regs.pipeline_pos = restore_u16();
! 9088: regs.pipeline_r8[0] = restore_u16();
! 9089: regs.pipeline_r8[1] = restore_u16();
! 9090: regs.pipeline_stop = restore_u16();
! 9091: }
! 9092:
1.1.1.7 root 9093: m68k_reset_sr();
9094:
9095: write_log (_T("CPU: %d%s%03d, PC=%08X\n"),
9096: model / 1000, flags & 1 ? _T("EC") : _T(""), model % 1000, regs.pc);
1.1.1.4 root 9097:
9098: return src;
9099: }
9100:
1.1.1.7 root 9101: static void fill_prefetch_quick (void)
9102: {
9103: if (currprefs.cpu_model >= 68020) {
9104: fill_prefetch ();
9105: return;
9106: }
9107: // old statefile compatibility, this needs to done,
9108: // even in 68000 cycle-exact mode
9109: regs.ir = get_word (m68k_getpc ());
9110: regs.irc = get_word (m68k_getpc () + 2);
9111: }
9112:
1.1.1.4 root 9113: void restore_cpu_finish (void)
9114: {
9115: init_m68k ();
1.1.1.7 root 9116: m68k_setpc_normal (regs.pc);
1.1.1.4 root 9117: doint ();
1.1.1.7 root 9118: fill_prefetch_quick ();
9119: printf ( "SR %x %x %x %x\n" , regs.sr , regs.isp , regs.usp , regs.regs[15] );
9120: #ifndef WINUAE_FOR_HATARI
9121: set_cycles (start_cycles);
9122: events_schedule ();
9123: #endif
1.1.1.4 root 9124: if (regs.stopped)
9125: set_special (SPCFLAG_STOP);
9126: //activate_debugger ();
9127: }
9128:
1.1.1.7 root 9129: uae_u8 *save_cpu_trace (int *len, uae_u8 *dstptr)
1.1.1.4 root 9130: {
1.1.1.7 root 9131: uae_u8 *dstbak, *dst;
9132: int i;
1.1.1.4 root 9133:
1.1.1.7 root 9134: if (cputrace.state <= 0)
9135: return NULL;
1.1.1.4 root 9136:
1.1.1.7 root 9137: if (dstptr)
9138: dstbak = dst = dstptr;
9139: else
1.1.1.8 root 9140: dstbak = dst = xmalloc (uae_u8, 10000);
1.1.1.7 root 9141:
1.1.1.9 ! root 9142: save_u32 (2 | 4 | 16 | 32);
1.1.1.7 root 9143: save_u16 (cputrace.opcode);
9144: for (i = 0; i < 16; i++)
9145: save_u32 (cputrace.regs[i]);
9146: save_u32 (cputrace.pc);
9147: save_u16 (cputrace.irc);
9148: save_u16 (cputrace.ir);
9149: save_u32 (cputrace.usp);
9150: save_u32 (cputrace.isp);
9151: save_u16 (cputrace.sr);
9152: save_u16 (cputrace.intmask);
9153: save_u16 ((cputrace.stopped ? 1 : 0) | (regs.stopped ? 2 : 0));
9154: save_u16 (cputrace.state);
9155: save_u32 (cputrace.cyclecounter);
9156: save_u32 (cputrace.cyclecounter_pre);
9157: save_u32 (cputrace.cyclecounter_post);
9158: save_u32 (cputrace.readcounter);
9159: save_u32 (cputrace.writecounter);
9160: save_u32 (cputrace.memoryoffset);
9161: write_log (_T("CPUT SAVE: PC=%08x C=%08X %08x %08x %08x %d %d %d\n"),
9162: cputrace.pc, cputrace.startcycles,
9163: cputrace.cyclecounter, cputrace.cyclecounter_pre, cputrace.cyclecounter_post,
9164: cputrace.readcounter, cputrace.writecounter, cputrace.memoryoffset);
9165: for (i = 0; i < cputrace.memoryoffset; i++) {
9166: save_u32 (cputrace.ctm[i].addr);
9167: save_u32 (cputrace.ctm[i].data);
9168: save_u32 (cputrace.ctm[i].mode);
9169: write_log (_T("CPUT%d: %08x %08x %08x\n"), i, cputrace.ctm[i].addr, cputrace.ctm[i].data, cputrace.ctm[i].mode);
9170: }
9171: save_u32 (cputrace.startcycles);
9172:
9173: if (currprefs.cpu_model == 68020) {
9174: for (i = 0; i < CACHELINES020; i++) {
9175: save_u32 (cputrace.caches020[i].data);
9176: save_u32 (cputrace.caches020[i].tag);
9177: save_u8 (cputrace.caches020[i].valid ? 1 : 0);
9178: }
9179: save_u32 (cputrace.prefetch020addr);
9180: save_u32 (cputrace.cacheholdingaddr020);
9181: save_u32 (cputrace.cacheholdingdata020);
1.1.1.9 ! root 9182: for (i = 0; i < CPU_PIPELINE_MAX; i++) {
1.1.1.7 root 9183: save_u16 (cputrace.prefetch020[i]);
1.1.1.9 ! root 9184: }
! 9185: for (i = 0; i < CPU_PIPELINE_MAX; i++) {
1.1.1.7 root 9186: save_u32 (cputrace.prefetch020[i]);
1.1.1.9 ! root 9187: }
! 9188: for (i = 0; i < CPU_PIPELINE_MAX; i++) {
! 9189: save_u8 (cputrace.prefetch020_valid[i]);
! 9190: }
! 9191: save_u16(cputrace.pipeline_pos);
! 9192: save_u16(cputrace.pipeline_r8[0]);
! 9193: save_u16(cputrace.pipeline_r8[1]);
! 9194: save_u16(cputrace.pipeline_stop);
1.1.1.7 root 9195: }
9196:
9197: *len = dst - dstbak;
9198: cputrace.needendcycles = 1;
9199: return dstbak;
9200: }
9201:
9202: uae_u8 *restore_cpu_trace (uae_u8 *src)
9203: {
9204: int i;
9205:
9206: cpu_tracer = 0;
9207: cputrace.state = 0;
9208: uae_u32 v = restore_u32 ();
9209: if (!(v & 2))
9210: return src;
9211: cputrace.opcode = restore_u16 ();
9212: for (i = 0; i < 16; i++)
9213: cputrace.regs[i] = restore_u32 ();
9214: cputrace.pc = restore_u32 ();
9215: cputrace.irc = restore_u16 ();
9216: cputrace.ir = restore_u16 ();
9217: cputrace.usp = restore_u32 ();
9218: cputrace.isp = restore_u32 ();
9219: cputrace.sr = restore_u16 ();
9220: cputrace.intmask = restore_u16 ();
9221: cputrace.stopped = restore_u16 ();
9222: cputrace.state = restore_u16 ();
9223: cputrace.cyclecounter = restore_u32 ();
9224: cputrace.cyclecounter_pre = restore_u32 ();
9225: cputrace.cyclecounter_post = restore_u32 ();
9226: cputrace.readcounter = restore_u32 ();
9227: cputrace.writecounter = restore_u32 ();
9228: cputrace.memoryoffset = restore_u32 ();
9229: for (i = 0; i < cputrace.memoryoffset; i++) {
9230: cputrace.ctm[i].addr = restore_u32 ();
9231: cputrace.ctm[i].data = restore_u32 ();
9232: cputrace.ctm[i].mode = restore_u32 ();
9233: }
9234: cputrace.startcycles = restore_u32 ();
9235:
9236: if (v & 4) {
9237: if (currprefs.cpu_model == 68020) {
9238: for (i = 0; i < CACHELINES020; i++) {
9239: cputrace.caches020[i].data = restore_u32 ();
9240: cputrace.caches020[i].tag = restore_u32 ();
9241: cputrace.caches020[i].valid = restore_u8 () != 0;
9242: }
9243: cputrace.prefetch020addr = restore_u32 ();
9244: cputrace.cacheholdingaddr020 = restore_u32 ();
9245: cputrace.cacheholdingdata020 = restore_u32 ();
1.1.1.9 ! root 9246: for (i = 0; i < CPU_PIPELINE_MAX; i++) {
1.1.1.7 root 9247: cputrace.prefetch020[i] = restore_u16 ();
1.1.1.9 ! root 9248: }
1.1.1.7 root 9249: if (v & 8) {
1.1.1.9 ! root 9250: // backwards compatibility
! 9251: uae_u32 v = restore_u32();
! 9252: cputrace.prefetch020[0] = v >> 16;
! 9253: cputrace.prefetch020[1] = (uae_u16)v;
! 9254: v = restore_u32();
! 9255: cputrace.prefetch020[2] = v >> 16;
! 9256: cputrace.prefetch020[3] = (uae_u16)v;
! 9257: restore_u32();
! 9258: restore_u32();
! 9259: cputrace.prefetch020_valid[0] = true;
! 9260: cputrace.prefetch020_valid[1] = true;
! 9261: cputrace.prefetch020_valid[2] = true;
! 9262: cputrace.prefetch020_valid[3] = true;
! 9263:
! 9264: cputrace.prefetch020[0] = cputrace.prefetch020[1];
! 9265: cputrace.prefetch020[1] = cputrace.prefetch020[2];
! 9266: cputrace.prefetch020[2] = cputrace.prefetch020[3];
! 9267: cputrace.prefetch020_valid[3] = false;
! 9268: }
! 9269: if (v & 16) {
! 9270: for (i = 0; i < CPU_PIPELINE_MAX; i++) {
! 9271: cputrace.prefetch020_valid[i] = restore_u8() != 0;
! 9272: }
! 9273: }
! 9274: if (v & 32) {
! 9275: cputrace.pipeline_pos = restore_u16();
! 9276: cputrace.pipeline_r8[0] = restore_u16();
! 9277: cputrace.pipeline_r8[1] = restore_u16();
! 9278: cputrace.pipeline_stop = restore_u16();
1.1.1.7 root 9279: }
9280: }
9281: }
9282:
9283: cputrace.needendcycles = 1;
9284: if (v && cputrace.state) {
9285: if (currprefs.cpu_model > 68000) {
9286: if (v & 4)
9287: cpu_tracer = -1;
9288: // old format?
9289: if ((v & (4 | 8)) != (4 | 8))
9290: cpu_tracer = 0;
9291: } else {
9292: cpu_tracer = -1;
9293: }
9294: }
9295:
9296: return src;
9297: }
9298:
9299: uae_u8 *restore_cpu_extra (uae_u8 *src)
9300: {
9301: restore_u32 ();
9302: uae_u32 flags = restore_u32 ();
9303:
9304: currprefs.cpu_cycle_exact = changed_prefs.cpu_cycle_exact = (flags & 1) ? true : false;
1.1.1.8 root 9305: currprefs.cpu_memory_cycle_exact = changed_prefs.cpu_memory_cycle_exact = currprefs.cpu_cycle_exact;
9306: if ((flags & 32) && !(flags & 1))
9307: currprefs.cpu_memory_cycle_exact = changed_prefs.cpu_memory_cycle_exact = true;
1.1.1.7 root 9308: currprefs.blitter_cycle_exact = changed_prefs.blitter_cycle_exact = currprefs.cpu_cycle_exact;
9309: currprefs.cpu_compatible = changed_prefs.cpu_compatible = (flags & 2) ? true : false;
9310: currprefs.cpu_frequency = changed_prefs.cpu_frequency = restore_u32 ();
9311: currprefs.cpu_clock_multiplier = changed_prefs.cpu_clock_multiplier = restore_u32 ();
9312: //currprefs.cachesize = changed_prefs.cachesize = (flags & 8) ? 8192 : 0;
9313:
9314: currprefs.m68k_speed = changed_prefs.m68k_speed = 0;
9315: if (flags & 4)
1.1.1.4 root 9316: currprefs.m68k_speed = changed_prefs.m68k_speed = -1;
1.1.1.7 root 9317: if (flags & 16)
9318: currprefs.m68k_speed = changed_prefs.m68k_speed = (flags >> 24) * CYCLE_UNIT;
1.1.1.4 root 9319:
9320: currprefs.cpu060_revision = changed_prefs.cpu060_revision = restore_u8 ();
9321: currprefs.fpu_revision = changed_prefs.fpu_revision = restore_u8 ();
9322:
9323: return src;
9324: }
9325:
9326: uae_u8 *save_cpu_extra (int *len, uae_u8 *dstptr)
9327: {
9328: uae_u8 *dstbak, *dst;
9329: uae_u32 flags;
9330:
9331: if (dstptr)
9332: dstbak = dst = dstptr;
9333: else
9334: dstbak = dst = xmalloc (uae_u8, 1000);
9335: save_u32 (0); // version
9336: flags = 0;
9337: flags |= currprefs.cpu_cycle_exact ? 1 : 0;
9338: flags |= currprefs.cpu_compatible ? 2 : 0;
9339: flags |= currprefs.m68k_speed < 0 ? 4 : 0;
9340: flags |= currprefs.cachesize > 0 ? 8 : 0;
1.1.1.7 root 9341: flags |= currprefs.m68k_speed > 0 ? 16 : 0;
1.1.1.8 root 9342: flags |= currprefs.cpu_memory_cycle_exact ? 32 : 0;
1.1.1.7 root 9343: if (currprefs.m68k_speed > 0)
9344: flags |= (currprefs.m68k_speed / CYCLE_UNIT) << 24;
1.1.1.4 root 9345: save_u32 (flags);
9346: save_u32 (currprefs.cpu_frequency);
9347: save_u32 (currprefs.cpu_clock_multiplier);
9348: save_u8 (currprefs.cpu060_revision);
9349: save_u8 (currprefs.fpu_revision);
9350: *len = dst - dstbak;
9351: return dstbak;
9352: }
9353:
9354: uae_u8 *save_cpu (int *len, uae_u8 *dstptr)
9355: {
9356: uae_u8 *dstbak, *dst;
1.1.1.7 root 9357: int model, i, j, khz;
1.1.1.4 root 9358:
9359: if (dstptr)
9360: dstbak = dst = dstptr;
9361: else
1.1.1.8 root 9362: dstbak = dst = xmalloc (uae_u8, 1000 + 20000);
1.1.1.4 root 9363: model = currprefs.cpu_model;
9364: save_u32 (model); /* MODEL */
1.1.1.9 ! root 9365: save_u32(0x80000000 | 0x40000000 | 0x20000000 | 0x10000000 | 0x8000000 | 0x4000000 | (currprefs.address_space_24 ? 1 : 0)); /* FLAGS */
1.1.1.4 root 9366: for (i = 0;i < 15; i++)
9367: save_u32 (regs.regs[i]); /* D0-D7 A0-A6 */
9368: save_u32 (m68k_getpc ()); /* PC */
9369: save_u16 (regs.irc); /* prefetch */
9370: save_u16 (regs.ir); /* instruction prefetch */
9371: MakeSR ();
9372: save_u32 (!regs.s ? regs.regs[15] : regs.usp); /* USP */
9373: save_u32 (regs.s ? regs.regs[15] : regs.isp); /* ISP */
9374: save_u16 (regs.sr); /* SR/CCR */
9375: save_u32 (regs.stopped ? CPUMODE_HALT : 0); /* flags */
9376: if (model >= 68010) {
9377: save_u32 (regs.dfc); /* DFC */
9378: save_u32 (regs.sfc); /* SFC */
9379: save_u32 (regs.vbr); /* VBR */
9380: }
9381: if (model >= 68020) {
9382: save_u32 (regs.caar); /* CAAR */
9383: save_u32 (regs.cacr); /* CACR */
9384: save_u32 (regs.msp); /* MSP */
9385: }
9386: if (model >= 68030) {
1.1.1.7 root 9387: if (currprefs.mmu_model) {
9388: save_u64 (crp_030); /* CRP */
9389: save_u64 (srp_030); /* SRP */
9390: save_u32 (tt0_030); /* TT0/AC0 */
9391: save_u32 (tt1_030); /* TT1/AC1 */
9392: save_u32 (tc_030); /* TCR */
9393: save_u16 (mmusr_030); /* MMUSR/ACUSR */
9394: } else {
9395: save_u64 (fake_crp_030); /* CRP */
9396: save_u64 (fake_srp_030); /* SRP */
9397: save_u32 (fake_tt0_030); /* TT0/AC0 */
9398: save_u32 (fake_tt1_030); /* TT1/AC1 */
9399: save_u32 (fake_tc_030); /* TCR */
9400: save_u16 (fake_mmusr_030); /* MMUSR/ACUSR */
9401: }
1.1.1.4 root 9402: }
9403: if (model >= 68040) {
9404: save_u32 (regs.itt0); /* ITT0 */
9405: save_u32 (regs.itt1); /* ITT1 */
9406: save_u32 (regs.dtt0); /* DTT0 */
9407: save_u32 (regs.dtt1); /* DTT1 */
9408: save_u32 (regs.tcr); /* TCR */
9409: save_u32 (regs.urp); /* URP */
9410: save_u32 (regs.srp); /* SRP */
9411: }
9412: if (model >= 68060) {
9413: save_u32 (regs.buscr); /* BUSCR */
9414: save_u32 (regs.pcr); /* PCR */
9415: }
9416: khz = -1;
9417: if (currprefs.m68k_speed == 0) {
9418: khz = currprefs.ntscmode ? 715909 : 709379;
9419: if (currprefs.cpu_model >= 68020)
9420: khz *= 2;
9421: }
9422: save_u32 (khz); // clock rate in KHz: -1 = fastest possible
9423: save_u32 (0); // spare
1.1.1.7 root 9424: if (model == 68020) {
9425: for (i = 0; i < CACHELINES020; i++) {
9426: save_u32 (caches020[i].data);
9427: save_u32 (caches020[i].tag);
9428: save_u8 (caches020[i].valid ? 1 : 0);
9429: }
9430: save_u32 (regs.prefetch020addr);
9431: save_u32 (regs.cacheholdingaddr020);
9432: save_u32 (regs.cacheholdingdata020);
9433: for (i = 0; i < CPU_PIPELINE_MAX; i++)
1.1.1.9 ! root 9434: save_u32 ((regs.prefetch020[i] << 16) | (regs.prefetch020_valid[i] ? 1 : 0));
1.1.1.7 root 9435: } else if (model == 68030) {
9436: for (i = 0; i < CACHELINES030; i++) {
9437: for (j = 0; j < 4; j++) {
9438: save_u32 (icaches030[i].data[j]);
9439: save_u8 (icaches030[i].valid[j] ? 1 : 0);
9440: }
9441: save_u32 (icaches030[i].tag);
9442: }
9443: for (i = 0; i < CACHELINES030; i++) {
9444: for (j = 0; j < 4; j++) {
9445: save_u32 (dcaches030[i].data[j]);
9446: save_u8 (dcaches030[i].valid[j] ? 1 : 0);
9447: }
9448: save_u32 (dcaches030[i].tag);
9449: }
9450: save_u32 (regs.prefetch020addr);
9451: save_u32 (regs.cacheholdingaddr020);
9452: save_u32 (regs.cacheholdingdata020);
9453: for (i = 0; i < CPU_PIPELINE_MAX; i++)
9454: save_u32 (regs.prefetch020[i]);
9455: } else if (model >= 68040) {
1.1.1.9 ! root 9456: for (i = 0; i < (model == 68060 ? CACHESETS060 : CACHESETS040); i++) {
1.1.1.7 root 9457: for (j = 0; j < CACHELINES040; j++) {
1.1.1.9 ! root 9458: struct cache040 *c = &icaches040[i];
! 9459: save_u32(c->data[j][0]);
! 9460: save_u32(c->data[j][1]);
! 9461: save_u32(c->data[j][2]);
! 9462: save_u32(c->data[j][3]);
! 9463: save_u32(c->tag[j]);
! 9464: save_u16(c->valid[j] ? 1 : 0);
1.1.1.7 root 9465: }
9466: }
9467: save_u32(regs.prefetch020addr);
9468: save_u32(regs.cacheholdingaddr020);
9469: save_u32(regs.cacheholdingdata020);
1.1.1.9 ! root 9470: for (i = 0; i < CPU_PIPELINE_MAX; i++) {
! 9471: save_u32(regs.prefetch040[i]);
! 9472: }
! 9473: for (i = 0; i < (model == 68060 ? CACHESETS060 : CACHESETS040); i++) {
! 9474: for (j = 0; j < CACHELINES040; j++) {
! 9475: struct cache040 *c = &dcaches040[i];
! 9476: save_u32(c->data[j][0]);
! 9477: save_u32(c->data[j][1]);
! 9478: save_u32(c->data[j][2]);
! 9479: save_u32(c->data[j][3]);
! 9480: save_u32(c->tag[j]);
! 9481: uae_u16 v = c->valid[j] ? 1 : 0;
! 9482: v |= c->dirty[j][0] ? 0x10 : 0;
! 9483: v |= c->dirty[j][1] ? 0x20 : 0;
! 9484: v |= c->dirty[j][2] ? 0x40 : 0;
! 9485: v |= c->dirty[j][3] ? 0x80 : 0;
! 9486: save_u16(v);
! 9487: }
! 9488: }
1.1.1.7 root 9489: }
9490: if (currprefs.cpu_model >= 68020) {
1.1.1.9 ! root 9491: save_u32 (0); //save_u32 (regs.ce020memcycles);
1.1.1.7 root 9492: save_u32 (0);
9493: }
9494: save_u32 (regs.chipset_latch_rw);
9495: save_u32 (regs.chipset_latch_read);
9496: save_u32 (regs.chipset_latch_write);
1.1.1.9 ! root 9497: if (currprefs.cpu_model == 68020) {
! 9498: save_u16(regs.pipeline_pos);
! 9499: save_u16(regs.pipeline_r8[0]);
! 9500: save_u16(regs.pipeline_r8[1]);
! 9501: save_u16(regs.pipeline_stop);
! 9502: }
1.1.1.4 root 9503: *len = dst - dstbak;
9504: return dstbak;
9505: }
9506:
9507: uae_u8 *save_mmu (int *len, uae_u8 *dstptr)
9508: {
9509: uae_u8 *dstbak, *dst;
9510: int model;
9511:
9512: model = currprefs.mmu_model;
1.1.1.7 root 9513: #ifndef WINUAE_FOR_HATARI
1.1.1.8 root 9514: /* Under Hatari, we save all MMU variables, even if mmu_model==0 */
1.1.1.7 root 9515: if (model != 68030 && model != 68040 && model != 68060)
1.1.1.4 root 9516: return NULL;
1.1.1.7 root 9517: #endif
1.1.1.4 root 9518: if (dstptr)
9519: dstbak = dst = dstptr;
9520: else
9521: dstbak = dst = xmalloc (uae_u8, 1000);
9522: save_u32 (model); /* MODEL */
1.1.1.7 root 9523: save_u32 (0); /* FLAGS */
1.1.1.4 root 9524: *len = dst - dstbak;
9525: return dstbak;
9526: }
9527:
9528: uae_u8 *restore_mmu (uae_u8 *src)
9529: {
9530: int flags, model;
9531:
9532: changed_prefs.mmu_model = model = restore_u32 ();
9533: flags = restore_u32 ();
1.1.1.7 root 9534: write_log (_T("MMU: %d\n"), model);
1.1.1.4 root 9535: return src;
9536: }
9537:
9538: #endif /* SAVESTATE */
9539:
1.1.1.7 root 9540: static void exception3f (uae_u32 opcode, uaecptr addr, bool writeaccess, bool instructionaccess, bool notinstruction, uaecptr pc, bool plus2)
1.1.1.4 root 9541: {
9542: if (currprefs.cpu_model >= 68040)
9543: addr &= ~1;
1.1.1.7 root 9544: if (currprefs.cpu_model >= 68020) {
9545: if (pc == 0xffffffff)
9546: last_addr_for_exception_3 = regs.instruction_pc;
9547: else
9548: last_addr_for_exception_3 = pc;
9549: } else if (pc == 0xffffffff) {
9550: last_addr_for_exception_3 = m68k_getpc ();
9551: if (plus2)
9552: last_addr_for_exception_3 += 2;
9553: } else {
9554: last_addr_for_exception_3 = pc;
9555: }
9556: last_fault_for_exception_3 = addr;
1.1.1.4 root 9557: last_op_for_exception_3 = opcode;
9558: last_writeaccess_for_exception_3 = writeaccess;
9559: last_instructionaccess_for_exception_3 = instructionaccess;
1.1.1.7 root 9560: last_notinstruction_for_exception_3 = notinstruction;
9561: Exception (3);
9562: #if EXCEPTION3_DEBUGGER
9563: activate_debugger();
9564: #endif
1.1.1.4 root 9565: }
9566:
1.1.1.7 root 9567: void exception3_notinstruction(uae_u32 opcode, uaecptr addr)
1.1.1.4 root 9568: {
1.1.1.7 root 9569: exception3f (opcode, addr, true, false, true, 0xffffffff, false);
1.1.1.4 root 9570: }
1.1.1.7 root 9571: void exception3_read(uae_u32 opcode, uaecptr addr)
9572: {
9573: exception3f (opcode, addr, false, 0, false, 0xffffffff, false);
9574: }
9575: void exception3_write(uae_u32 opcode, uaecptr addr)
9576: {
9577: exception3f (opcode, addr, true, 0, false, 0xffffffff, false);
9578: }
9579: void exception3i (uae_u32 opcode, uaecptr addr)
9580: {
9581: exception3f (opcode, addr, 0, 1, false, 0xffffffff, true);
9582: }
9583: void exception3b (uae_u32 opcode, uaecptr addr, bool w, bool i, uaecptr pc)
1.1.1.4 root 9584: {
1.1.1.7 root 9585: exception3f (opcode, addr, w, i, false, pc, true);
1.1.1.4 root 9586: }
9587:
1.1.1.7 root 9588: void exception2 (uaecptr addr, bool read, int size, uae_u32 fc)
1.1.1.4 root 9589: {
1.1.1.7 root 9590: if (currprefs.mmu_model) {
9591: if (currprefs.mmu_model == 68030) {
9592: uae_u32 flags = size == 1 ? MMU030_SSW_SIZE_B : (size == 2 ? MMU030_SSW_SIZE_W : MMU030_SSW_SIZE_L);
9593: mmu030_page_fault (addr, read, flags, fc);
9594: } else {
1.1.1.9 ! root 9595: mmu_bus_error (addr, 0, fc, read == false, size, 0, true);
1.1.1.7 root 9596: }
9597: } else {
9598: last_addr_for_exception_3 = m68k_getpc() + bus_error_offset;
9599: last_fault_for_exception_3 = addr;
9600: last_writeaccess_for_exception_3 = read == 0;
9601: last_instructionaccess_for_exception_3 = (fc & 1) == 0;
9602: last_op_for_exception_3 = regs.opcode;
9603: last_notinstruction_for_exception_3 = exception_in_exception != 0;
9604: THROW(2);
9605: }
1.1.1.4 root 9606: }
9607:
9608: void cpureset (void)
9609: {
1.1.1.7 root 9610: /* RESET hasn't increased PC yet, 1 word offset */
1.1.1.4 root 9611: uaecptr pc;
1.1.1.7 root 9612: #ifndef WINUAE_FOR_HATARI
9613: uaecptr ksboot = 0xf80002 - 2;
1.1.1.4 root 9614: uae_u16 ins;
1.1.1.7 root 9615: #endif
9616: addrbank *ab;
1.1.1.4 root 9617:
1.1.1.7 root 9618: m68k_reset_delay = currprefs.reset_delay;
9619: set_special(SPCFLAG_CHECK);
9620: #ifndef WINUAE_FOR_HATARI
9621: send_internalevent(INTERNALEVENT_CPURESET);
1.1.1.8 root 9622: if ((currprefs.cpu_compatible || currprefs.cpu_memory_cycle_exact) && currprefs.cpu_model <= 68020) {
1.1.1.7 root 9623: custom_reset (false, false);
1.1.1.4 root 9624: return;
9625: }
1.1.1.7 root 9626: #endif
9627: pc = m68k_getpc () + 2;
9628: ab = &get_mem_bank (pc);
9629: if (ab->check (pc, 2)) {
9630: write_log (_T("CPU reset PC=%x (%s)..\n"), pc - 2, ab->name);
9631: #ifndef WINUAE_FOR_HATARI
9632: ins = get_word (pc);
9633: custom_reset (false, false);
9634: // did memory disappear under us?
9635: if (ab == &get_mem_bank (pc))
9636: return;
9637: // it did
9638: if ((ins & ~7) == 0x4ed0) {
9639: int reg = ins & 7;
9640: uae_u32 addr = m68k_areg (regs, reg);
9641: if (addr < 0x80000)
9642: addr += 0xf80000;
9643: write_log (_T("reset/jmp (ax) combination at %08x emulated -> %x\n"), pc, addr);
9644: m68k_setpc_normal (addr - 2);
1.1.1.4 root 9645: return;
9646: }
1.1.1.7 root 9647: #else
9648: customreset (); /* From hatari-glue.c */
9649: return;
9650: #endif
9651: }
9652: // the best we can do, jump directly to ROM entrypoint
9653: // (which is probably what program wanted anyway)
9654: #ifndef WINUAE_FOR_HATARI
9655: write_log (_T("CPU Reset PC=%x (%s), invalid memory -> %x.\n"), pc, ab->name, ksboot + 2);
9656: custom_reset (false, false);
9657: m68k_setpc_normal (ksboot);
9658: #else
9659: write_log (_T("CPU Reset PC=%x (%s), invalid memory\n"), pc, ab->name);
9660: customreset (); /* From hatari-glue.c */
9661: #endif
1.1.1.4 root 9662: }
9663:
9664:
9665: void m68k_setstopped (void)
9666: {
9667: /* A traced STOP instruction drops through immediately without
9668: actually stopping. */
1.1.1.8 root 9669: if ((regs.spcflags & SPCFLAG_DOTRACE) == 0) {
9670: m68k_set_stop();
9671: } else {
1.1.1.4 root 9672: m68k_resumestopped ();
1.1.1.8 root 9673: }
1.1.1.4 root 9674: }
9675:
9676: void m68k_resumestopped (void)
9677: {
9678: if (!regs.stopped)
9679: return;
1.1.1.8 root 9680: if (currprefs.cpu_cycle_exact && currprefs.cpu_model == 68000) {
9681: x_do_cycles (6 * cpucycleunit);
1.1.1.4 root 9682: }
1.1.1.7 root 9683: fill_prefetch ();
1.1.1.8 root 9684: m68k_unset_stop();
9685: }
9686:
9687:
9688: uae_u32 mem_access_delay_word_read (uaecptr addr)
9689: {
9690: uae_u32 v;
9691: //#ifndef WINUAE_FOR_HATARI
1.1.1.9 ! root 9692: if ( BlitterPhase ) Blitter_HOG_CPU_mem_access_before ( 1 ); // WINUAE_FOR_HATARI
1.1.1.8 root 9693: #if 1
9694: switch (ce_banktype[addr >> 16])
9695: {
9696: case CE_MEMBANK_CHIP16:
9697: case CE_MEMBANK_CHIP32:
9698: v = wait_cpu_cycle_read (addr, 1);
9699: break;
9700: case CE_MEMBANK_FAST16:
9701: case CE_MEMBANK_FAST32:
9702: v = get_word (addr);
9703: x_do_cycles_post (4 * cpucycleunit, v);
9704: break;
9705: default:
9706: v = get_word (addr);
9707: break;
9708: }
9709: #else
9710: //fprintf ( stderr , "word read mis %lu %lu\n" , currcycle / cpucycleunit , currcycle );
9711: v = get_word (addr);
9712: x_do_cycles_post (4 * cpucycleunit, v);
9713: #endif
9714: regs.db = v;
1.1.1.9 ! root 9715: if ( BlitterPhase ) Blitter_HOG_CPU_mem_access_after ( 1 ); // WINUAE_FOR_HATARI
1.1.1.8 root 9716: return v;
9717: }
9718: uae_u32 mem_access_delay_wordi_read (uaecptr addr)
9719: {
9720: uae_u32 v;
9721: //#ifndef WINUAE_FOR_HATARI
1.1.1.9 ! root 9722: if ( BlitterPhase ) Blitter_HOG_CPU_mem_access_before ( 1 ); // WINUAE_FOR_HATARI
1.1.1.8 root 9723: #if 1
9724: switch (ce_banktype[addr >> 16])
9725: {
9726: case CE_MEMBANK_CHIP16:
9727: case CE_MEMBANK_CHIP32:
9728: v = wait_cpu_cycle_read (addr, 2);
9729: break;
9730: case CE_MEMBANK_FAST16:
9731: case CE_MEMBANK_FAST32:
9732: v = get_wordi (addr);
9733: x_do_cycles_post (4 * cpucycleunit, v);
9734: break;
9735: default:
9736: v = get_wordi (addr);
9737: break;
9738: }
9739: #else
9740: //fprintf ( stderr , "wordi read mis %lu %lu\n" , currcycle / cpucycleunit , currcycle );
9741: v = get_wordi (addr);
9742: x_do_cycles_post (4 * cpucycleunit, v);
9743: #endif
9744: regs.db = v;
1.1.1.9 ! root 9745: if ( BlitterPhase ) Blitter_HOG_CPU_mem_access_after ( 1 ); // WINUAE_FOR_HATARI
1.1.1.8 root 9746: return v;
9747: }
9748:
9749: uae_u32 mem_access_delay_byte_read (uaecptr addr)
9750: {
9751: uae_u32 v;
9752: //#ifndef WINUAE_FOR_HATARI
1.1.1.9 ! root 9753: if ( BlitterPhase ) Blitter_HOG_CPU_mem_access_before ( 1 ); // WINUAE_FOR_HATARI
1.1.1.8 root 9754: #if 1
9755: switch (ce_banktype[addr >> 16])
9756: {
9757: case CE_MEMBANK_CHIP16:
9758: case CE_MEMBANK_CHIP32:
9759: v = wait_cpu_cycle_read (addr, 0);
9760: break;
9761: case CE_MEMBANK_FAST16:
9762: case CE_MEMBANK_FAST32:
9763: v = get_byte (addr);
9764: x_do_cycles_post (4 * cpucycleunit, v);
9765: break;
9766: default:
9767: v = get_byte (addr);
9768: break;
9769: }
9770: #else
9771: //fprintf ( stderr , "byte read mis %lu %lu\n" , currcycle / cpucycleunit , currcycle );
9772: v = get_byte (addr);
9773: x_do_cycles_post (4 * cpucycleunit, v);
9774: #endif
9775: regs.db = (v << 8) | v;
1.1.1.9 ! root 9776: if ( BlitterPhase ) Blitter_HOG_CPU_mem_access_after ( 1 ); // WINUAE_FOR_HATARI
1.1.1.8 root 9777: return v;
9778: }
9779: void mem_access_delay_byte_write (uaecptr addr, uae_u32 v)
9780: {
9781: regs.db = (v << 8) | v;
9782: //#ifndef WINUAE_FOR_HATARI
1.1.1.9 ! root 9783: if ( BlitterPhase ) Blitter_HOG_CPU_mem_access_before ( 1 ); // WINUAE_FOR_HATARI
1.1.1.8 root 9784: #if 1
9785: switch (ce_banktype[addr >> 16])
9786: {
9787: case CE_MEMBANK_CHIP16:
9788: case CE_MEMBANK_CHIP32:
9789: wait_cpu_cycle_write (addr, 0, v);
1.1.1.9 ! root 9790: if ( BlitterPhase ) Blitter_HOG_CPU_mem_access_after ( 1 ); // WINUAE_FOR_HATARI
1.1.1.8 root 9791: return;
9792: case CE_MEMBANK_FAST16:
9793: case CE_MEMBANK_FAST32:
9794: put_byte (addr, v);
9795: x_do_cycles_post (4 * cpucycleunit, v);
1.1.1.9 ! root 9796: if ( BlitterPhase ) Blitter_HOG_CPU_mem_access_after ( 1 ); // WINUAE_FOR_HATARI
1.1.1.8 root 9797: return;
9798: }
9799: put_byte (addr, v);
9800: #else
9801: put_byte (addr, v);
9802: x_do_cycles_post (4 * cpucycleunit, v);
9803: #endif
9804: }
9805: void mem_access_delay_word_write (uaecptr addr, uae_u32 v)
9806: {
9807: //#ifndef WINUAE_FOR_HATARI
1.1.1.9 ! root 9808: if ( BlitterPhase ) Blitter_HOG_CPU_mem_access_before ( 1 ); // WINUAE_FOR_HATARI
1.1.1.8 root 9809: #if 1
9810: regs.db = v;
9811: switch (ce_banktype[addr >> 16])
9812: {
9813: case CE_MEMBANK_CHIP16:
9814: case CE_MEMBANK_CHIP32:
9815: wait_cpu_cycle_write (addr, 1, v);
1.1.1.9 ! root 9816: if ( BlitterPhase ) Blitter_HOG_CPU_mem_access_after ( 1 ); // WINUAE_FOR_HATARI
1.1.1.8 root 9817: return;
9818: case CE_MEMBANK_FAST16:
9819: case CE_MEMBANK_FAST32:
9820: put_word (addr, v);
9821: x_do_cycles_post (4 * cpucycleunit, v);
1.1.1.9 ! root 9822: if ( BlitterPhase ) Blitter_HOG_CPU_mem_access_after ( 1 ); // WINUAE_FOR_HATARI
1.1.1.8 root 9823: return;
9824: }
9825: put_word (addr, v);
9826: #else
9827: put_word (addr, v);
9828: x_do_cycles_post (4 * cpucycleunit, v);
9829: #endif
1.1.1.4 root 9830: }
9831:
1.1.1.9 ! root 9832: static void start_020_cycle(void)
! 9833: {
! 9834: regs.ce020startcycle = get_cycles();
! 9835: }
! 9836:
! 9837: static void start_020_cycle_prefetch(bool opcode)
! 9838: {
! 9839: regs.ce020startcycle = get_cycles();
! 9840: // back to back prefetch cycles require 2 extra cycles (maybe)
! 9841: if (opcode && regs.ce020startcycle == regs.ce020prefetchendcycle && currprefs.cpu_cycle_exact) {
! 9842: x_do_cycles(2 * cpucycleunit);
! 9843: regs.ce020startcycle = get_cycles();
! 9844: }
! 9845: }
! 9846: static void end_020_cycle(void)
! 9847: {
! 9848: regs.ce020endcycle = get_cycles();
! 9849: }
! 9850: static void end_020_cycle_prefetch(bool opcode)
! 9851: {
! 9852: regs.ce020endcycle = get_cycles();
! 9853: if (opcode) {
! 9854: regs.ce020prefetchendcycle = regs.ce020endcycle;
! 9855: } else {
! 9856: regs.ce020prefetchendcycle = regs.ce020startcycle;
! 9857: }
! 9858: }
1.1.1.8 root 9859:
1.1.1.4 root 9860: // this one is really simple and easy
1.1.1.9 ! root 9861: static void fill_icache020 (uae_u32 addr, bool opcode)
1.1.1.4 root 9862: {
9863: int index;
9864: uae_u32 tag;
9865: uae_u32 data;
9866: struct cache020 *c;
9867:
1.1.1.9 ! root 9868: regs.fc030 = (regs.s ? 4 : 0) | 2;
1.1.1.4 root 9869: addr &= ~3;
1.1.1.7 root 9870: if (regs.cacheholdingaddr020 == addr)
9871: return;
1.1.1.4 root 9872: index = (addr >> 2) & (CACHELINES020 - 1);
9873: tag = regs.s | (addr & ~((CACHELINES020 << 2) - 1));
9874: c = &caches020[index];
1.1.1.9 ! root 9875: if ((regs.cacr & 1) && c->valid && c->tag == tag) {
1.1.1.4 root 9876: // cache hit
1.1.1.7 root 9877: regs.cacheholdingaddr020 = addr;
9878: regs.cacheholdingdata020 = c->data;
1.1.1.9 ! root 9879: regs.cacheholdingdata_valid = true;
1.1.1.7 root 9880: #ifdef WINUAE_FOR_HATARI
9881: CpuInstruction.I_Cache_hit++;
9882: #endif
1.1.1.4 root 9883: return;
9884: }
1.1.1.9 ! root 9885:
1.1.1.4 root 9886: // cache miss
1.1.1.9 ! root 9887: #if 0
1.1.1.7 root 9888: // Prefetch apparently can be queued by bus controller
9889: // even if bus controller is currently processing
9890: // previous data access.
9891: // Other combinations are not possible.
1.1.1.9 ! root 9892: if (!regs.ce020memcycle_data) {
! 9893: if (regs.ce020memcycles > 0)
! 9894: x_do_cycles (regs.ce020memcycles);
1.1.1.7 root 9895: regs.ce020memcycles = 0;
1.1.1.9 ! root 9896: }
! 9897: #endif
! 9898:
! 9899: start_020_cycle_prefetch(opcode);
! 9900: data = icache_fetch(addr);
! 9901: end_020_cycle_prefetch(opcode);
! 9902:
! 9903: // enabled and not frozen
! 9904: if ((regs.cacr & 1) && !(regs.cacr & 2)) {
1.1.1.4 root 9905: c->tag = tag;
1.1.1.9 ! root 9906: c->valid = true;
1.1.1.4 root 9907: c->data = data;
9908: }
1.1.1.7 root 9909: regs.cacheholdingaddr020 = addr;
9910: regs.cacheholdingdata020 = data;
1.1.1.9 ! root 9911: regs.cacheholdingdata_valid = true;
1.1.1.7 root 9912: #ifdef WINUAE_FOR_HATARI
9913: CpuInstruction.I_Cache_miss++;
9914: #endif
1.1.1.4 root 9915: }
9916:
1.1.1.7 root 9917: #if MORE_ACCURATE_68020_PIPELINE
9918: #define PIPELINE_DEBUG 0
9919: #if PIPELINE_DEBUG
9920: static uae_u16 pipeline_opcode;
9921: #endif
1.1.1.9 ! root 9922: static void pipeline_020(uaecptr pc)
1.1.1.4 root 9923: {
1.1.1.9 ! root 9924: uae_u16 w = regs.prefetch020[1];
! 9925: if (regs.prefetch020_valid[1] == 0) {
! 9926: regs.pipeline_stop = -1;
! 9927: return;
! 9928: }
1.1.1.7 root 9929: if (regs.pipeline_pos < 0)
9930: return;
9931: if (regs.pipeline_pos > 0) {
9932: // handle annoying 68020+ addressing modes
9933: if (regs.pipeline_pos == regs.pipeline_r8[0]) {
9934: regs.pipeline_r8[0] = 0;
9935: if (w & 0x100) {
9936: int extra = 0;
9937: if ((w & 0x30) == 0x20)
9938: extra += 2;
9939: if ((w & 0x30) == 0x30)
9940: extra += 4;
9941: if ((w & 0x03) == 0x02)
9942: extra += 2;
9943: if ((w & 0x03) == 0x03)
9944: extra += 4;
9945: regs.pipeline_pos += extra;
9946: }
9947: return;
9948: }
9949: if (regs.pipeline_pos == regs.pipeline_r8[1]) {
9950: regs.pipeline_r8[1] = 0;
9951: if (w & 0x100) {
9952: int extra = 0;
9953: if ((w & 0x30) == 0x20)
9954: extra += 2;
9955: if ((w & 0x30) == 0x30)
9956: extra += 4;
9957: if ((w & 0x03) == 0x02)
9958: extra += 2;
9959: if ((w & 0x03) == 0x03)
9960: extra += 4;
9961: regs.pipeline_pos += extra;
1.1.1.4 root 9962: }
1.1.1.7 root 9963: return;
9964: }
9965: }
9966: if (regs.pipeline_pos > 2) {
9967: regs.pipeline_pos -= 2;
9968: // If stop set, prefetches stop 1 word early.
9969: if (regs.pipeline_stop > 0 && regs.pipeline_pos == 2)
9970: regs.pipeline_stop = -1;
9971: return;
9972: }
9973: if (regs.pipeline_stop) {
9974: regs.pipeline_stop = -1;
9975: return;
9976: }
9977: #if PIPELINE_DEBUG
9978: pipeline_opcode = w;
9979: #endif
9980: regs.pipeline_r8[0] = cpudatatbl[w].disp020[0];
9981: regs.pipeline_r8[1] = cpudatatbl[w].disp020[1];
9982: regs.pipeline_pos = cpudatatbl[w].length;
9983: #if PIPELINE_DEBUG
9984: if (!regs.pipeline_pos) {
9985: write_log(_T("Opcode %04x has no size PC=%08x!\n"), w, pc);
9986: }
9987: #endif
1.1.1.8 root 9988: // illegal instructions, TRAP, TRAPV, A-line, F-line don't stop prefetches
1.1.1.7 root 9989: int branch = cpudatatbl[w].branch;
9990: if (regs.pipeline_pos > 0 && branch) {
9991: // Short branches (Bcc.s) still do one more prefetch.
9992: #if 0
9993: // RTS and other unconditional single opcode instruction stop immediately.
9994: if (branch == 2) {
9995: // Immediate stop
9996: regs.pipeline_stop = -1;
9997: } else {
9998: // Stop 1 word early than normally
9999: regs.pipeline_stop = 1;
1.1.1.4 root 10000: }
1.1.1.7 root 10001: #else
10002: regs.pipeline_stop = 1;
10003: #endif
1.1.1.4 root 10004: }
10005: }
10006:
1.1.1.7 root 10007: #endif
1.1.1.4 root 10008:
1.1.1.9 ! root 10009: static uae_u32 get_word_ce020_prefetch_2 (int o, bool opcode)
1.1.1.4 root 10010: {
1.1.1.7 root 10011: uae_u32 pc = m68k_getpc () + o;
10012: uae_u32 v;
1.1.1.4 root 10013:
1.1.1.9 ! root 10014: v = regs.prefetch020[0];
! 10015: regs.prefetch020[0] = regs.prefetch020[1];
! 10016: regs.prefetch020[1] = regs.prefetch020[2];
1.1.1.7 root 10017: #if MORE_ACCURATE_68020_PIPELINE
1.1.1.9 ! root 10018: pipeline_020(pc);
1.1.1.7 root 10019: #endif
1.1.1.9 ! root 10020: if (pc & 2) {
1.1.1.7 root 10021: // branch instruction detected in pipeline: stop fetches until branch executed.
10022: if (!MORE_ACCURATE_68020_PIPELINE || regs.pipeline_stop >= 0) {
1.1.1.9 ! root 10023: fill_icache020 (pc + 2 + 4, opcode);
1.1.1.4 root 10024: }
1.1.1.9 ! root 10025: regs.prefetch020[2] = regs.cacheholdingdata020 >> 16;
1.1.1.7 root 10026: } else {
1.1.1.9 ! root 10027: regs.prefetch020[2] = (uae_u16)regs.cacheholdingdata020;
1.1.1.4 root 10028: }
1.1.1.7 root 10029: do_cycles_ce020_internal (2);
1.1.1.9 ! root 10030: regs.db = regs.prefetch020[0];
1.1.1.7 root 10031: return v;
1.1.1.4 root 10032: }
10033:
1.1.1.9 ! root 10034: uae_u32 get_word_ce020_prefetch (int o)
! 10035: {
! 10036: return get_word_ce020_prefetch_2(o, false);
! 10037: }
! 10038:
! 10039: uae_u32 get_word_ce020_prefetch_opcode (int o)
! 10040: {
! 10041: return get_word_ce020_prefetch_2(o, true);
! 10042: }
! 10043:
1.1.1.7 root 10044: uae_u32 get_word_020_prefetch (int o)
1.1.1.4 root 10045: {
1.1.1.7 root 10046: uae_u32 pc = m68k_getpc () + o;
10047: uae_u32 v;
1.1.1.4 root 10048:
1.1.1.9 ! root 10049: v = regs.prefetch020[0];
! 10050: regs.prefetch020[0] = regs.prefetch020[1];
! 10051: regs.prefetch020[1] = regs.prefetch020[2];
1.1.1.7 root 10052: #if MORE_ACCURATE_68020_PIPELINE
1.1.1.9 ! root 10053: pipeline_020(pc);
1.1.1.7 root 10054: #endif
1.1.1.9 ! root 10055: if (pc & 2) {
! 10056: // branch instruction detected in pipeline: stop fetches until branch executed.
1.1.1.7 root 10057: if (!MORE_ACCURATE_68020_PIPELINE || regs.pipeline_stop >= 0) {
1.1.1.9 ! root 10058: fill_icache020 (pc + 2 + 4, false);
1.1.1.7 root 10059: }
1.1.1.9 ! root 10060: regs.prefetch020[2] = regs.cacheholdingdata020 >> 16;
1.1.1.7 root 10061: } else {
1.1.1.9 ! root 10062: regs.prefetch020[2] = (uae_u16)regs.cacheholdingdata020;
1.1.1.7 root 10063: }
1.1.1.9 ! root 10064: regs.db = regs.prefetch020[0];
1.1.1.7 root 10065: //if ( ( v & 0xffff ) != ( get_word(pc) & 0xffff ) )
10066: // fprintf ( stderr , "prefetch mismatch pc=%x prefetch=%x != mem=%x, i-cache error ?\n" , pc , v&0xffff , get_word(pc)&0xffff );
10067: return v;
10068: }
1.1.1.4 root 10069:
1.1.1.7 root 10070: // these are also used by 68030.
1.1.1.4 root 10071:
1.1.1.9 ! root 10072: #if 0
1.1.1.7 root 10073: #define RESET_CE020_CYCLES \
10074: regs.ce020memcycles = 0; \
10075: regs.ce020memcycle_data = true;
10076: #define STORE_CE020_CYCLES \
10077: unsigned long cycs = get_cycles ()
10078: #define ADD_CE020_CYCLES \
10079: regs.ce020memcycles += get_cycles () - cycs
1.1.1.9 ! root 10080: #endif
1.1.1.4 root 10081:
1.1.1.7 root 10082: uae_u32 mem_access_delay_long_read_ce020 (uaecptr addr)
10083: {
10084: uae_u32 v;
1.1.1.9 ! root 10085: //fprintf ( stderr , "long read ce020 %lu %lu\n" , currcycle / cpucycleunit , currcycle );
! 10086: start_020_cycle();
1.1.1.7 root 10087: switch (ce_banktype[addr >> 16])
10088: {
10089: case CE_MEMBANK_CHIP16:
10090: v = wait_cpu_cycle_read_ce020 (addr + 0, 1) << 16;
10091: v |= wait_cpu_cycle_read_ce020 (addr + 2, 1) << 0;
10092: break;
10093: case CE_MEMBANK_CHIP32:
10094: if ((addr & 3) != 0) {
10095: v = wait_cpu_cycle_read_ce020 (addr + 0, 1) << 16;
10096: v |= wait_cpu_cycle_read_ce020 (addr + 2, 1) << 0;
10097: } else {
10098: v = wait_cpu_cycle_read_ce020 (addr, -1);
10099: }
10100: break;
10101: case CE_MEMBANK_FAST32:
10102: v = get_long (addr);
10103: if ((addr & 3) != 0)
10104: do_cycles_ce020_mem (2 * CPU020_MEM_CYCLE, v);
10105: else
10106: do_cycles_ce020_mem (1 * CPU020_MEM_CYCLE, v);
10107: break;
10108: case CE_MEMBANK_FAST16:
10109: v = get_long (addr);
10110: do_cycles_ce020_mem (2 * CPU020_MEM_CYCLE, v);
10111: break;
10112: default:
10113: v = get_long (addr);
10114: break;
10115: }
1.1.1.9 ! root 10116: //fprintf ( stderr , "long read2 ce020 %lu %lu\n" , currcycle / cpucycleunit , currcycle );
! 10117: end_020_cycle();
! 10118: //fprintf ( stderr , "long read3 ce020 %lu %lu\n" , currcycle / cpucycleunit , currcycle );
1.1.1.7 root 10119: return v;
10120: }
10121:
10122: uae_u32 mem_access_delay_longi_read_ce020 (uaecptr addr)
10123: {
10124: uae_u32 v;
10125: switch (ce_banktype[addr >> 16])
10126: {
10127: case CE_MEMBANK_CHIP16:
1.1.1.8 root 10128: v = wait_cpu_cycle_read_ce020 (addr + 0, 2) << 16;
10129: v |= wait_cpu_cycle_read_ce020 (addr + 2, 2) << 0;
1.1.1.7 root 10130: break;
10131: case CE_MEMBANK_CHIP32:
10132: if ((addr & 3) != 0) {
1.1.1.8 root 10133: v = wait_cpu_cycle_read_ce020 (addr + 0, 2) << 16;
10134: v |= wait_cpu_cycle_read_ce020 (addr + 2, 2) << 0;
1.1.1.7 root 10135: } else {
1.1.1.8 root 10136: v = wait_cpu_cycle_read_ce020 (addr, -2);
1.1.1.7 root 10137: }
10138: break;
10139: case CE_MEMBANK_FAST32:
10140: v = get_longi (addr);
10141: if ((addr & 3) != 0)
10142: do_cycles_ce020_mem (2 * CPU020_MEM_CYCLE, v);
10143: else
10144: do_cycles_ce020_mem (1 * CPU020_MEM_CYCLE, v);
10145: break;
10146: case CE_MEMBANK_FAST16:
10147: v = get_longi (addr);
10148: do_cycles_ce020_mem (2 * CPU020_MEM_CYCLE, v);
10149: break;
10150: default:
10151: v = get_longi (addr);
10152: break;
10153: }
10154: return v;
10155: }
10156:
1.1.1.9 ! root 10157: uae_u32 mem_access_delay_wordi_read_ce020 (uaecptr addr)
! 10158: {
! 10159: uae_u32 v;
! 10160: start_020_cycle();
! 10161: switch (ce_banktype[addr >> 16])
! 10162: {
! 10163: case CE_MEMBANK_CHIP16:
! 10164: case CE_MEMBANK_CHIP32:
! 10165: if ((addr & 3) == 3) {
! 10166: v = wait_cpu_cycle_read_ce020 (addr + 0, 0) << 8;
! 10167: v |= wait_cpu_cycle_read_ce020 (addr + 1, 0) << 0;
! 10168: } else {
! 10169: v = wait_cpu_cycle_read_ce020 (addr, 1);
! 10170: }
! 10171: break;
! 10172: case CE_MEMBANK_FAST16:
! 10173: case CE_MEMBANK_FAST32:
! 10174: v = get_wordi (addr);
! 10175: if ((addr & 3) == 3)
! 10176: do_cycles_ce020_mem (2 * CPU020_MEM_CYCLE, v);
! 10177: else
! 10178: do_cycles_ce020_mem (1 * CPU020_MEM_CYCLE, v);
! 10179: break;
! 10180: default:
! 10181: v = get_wordi (addr);
! 10182: break;
! 10183: }
! 10184: end_020_cycle();
! 10185: return v;
! 10186: }
! 10187:
1.1.1.7 root 10188: uae_u32 mem_access_delay_word_read_ce020 (uaecptr addr)
10189: {
10190: uae_u32 v;
1.1.1.9 ! root 10191: start_020_cycle();
1.1.1.7 root 10192: switch (ce_banktype[addr >> 16])
10193: {
10194: case CE_MEMBANK_CHIP16:
10195: case CE_MEMBANK_CHIP32:
10196: if ((addr & 3) == 3) {
10197: v = wait_cpu_cycle_read_ce020 (addr + 0, 0) << 8;
10198: v |= wait_cpu_cycle_read_ce020 (addr + 1, 0) << 0;
10199: } else {
10200: v = wait_cpu_cycle_read_ce020 (addr, 1);
10201: }
10202: break;
10203: case CE_MEMBANK_FAST16:
10204: case CE_MEMBANK_FAST32:
10205: v = get_word (addr);
10206: if ((addr & 3) == 3)
10207: do_cycles_ce020_mem (2 * CPU020_MEM_CYCLE, v);
10208: else
10209: do_cycles_ce020_mem (1 * CPU020_MEM_CYCLE, v);
10210: break;
10211: default:
10212: v = get_word (addr);
10213: break;
10214: }
1.1.1.9 ! root 10215: end_020_cycle();
1.1.1.7 root 10216: return v;
10217: }
10218:
10219: uae_u32 mem_access_delay_byte_read_ce020 (uaecptr addr)
10220: {
10221: uae_u32 v;
1.1.1.9 ! root 10222: start_020_cycle();
1.1.1.7 root 10223: switch (ce_banktype[addr >> 16])
10224: {
10225: case CE_MEMBANK_CHIP16:
10226: case CE_MEMBANK_CHIP32:
10227: v = wait_cpu_cycle_read_ce020 (addr, 0);
10228: break;
10229: case CE_MEMBANK_FAST16:
10230: case CE_MEMBANK_FAST32:
10231: v = get_byte (addr);
10232: do_cycles_ce020_mem (1 * CPU020_MEM_CYCLE, v);
10233: break;
10234: default:
10235: v = get_byte (addr);
10236: break;
10237: }
1.1.1.9 ! root 10238: end_020_cycle();
1.1.1.7 root 10239: return v;
10240: }
10241:
10242: void mem_access_delay_byte_write_ce020 (uaecptr addr, uae_u32 v)
10243: {
1.1.1.9 ! root 10244: start_020_cycle();
1.1.1.7 root 10245: switch (ce_banktype[addr >> 16])
10246: {
10247: case CE_MEMBANK_CHIP16:
10248: case CE_MEMBANK_CHIP32:
10249: wait_cpu_cycle_write_ce020 (addr, 0, v);
10250: break;
10251: case CE_MEMBANK_FAST16:
10252: case CE_MEMBANK_FAST32:
10253: put_byte (addr, v);
10254: do_cycles_ce020_mem (1 * CPU020_MEM_CYCLE, v);
10255: break;
10256: default:
10257: put_byte (addr, v);
10258: break;
1.1.1.4 root 10259: }
1.1.1.9 ! root 10260: end_020_cycle();
1.1.1.7 root 10261: }
10262:
10263: void mem_access_delay_word_write_ce020 (uaecptr addr, uae_u32 v)
10264: {
1.1.1.9 ! root 10265: start_020_cycle();
1.1.1.7 root 10266: switch (ce_banktype[addr >> 16])
10267: {
10268: case CE_MEMBANK_CHIP16:
10269: case CE_MEMBANK_CHIP32:
10270: if ((addr & 3) == 3) {
10271: wait_cpu_cycle_write_ce020 (addr + 0, 0, (v >> 8) & 0xff);
10272: wait_cpu_cycle_write_ce020 (addr + 1, 0, (v >> 0) & 0xff);
10273: } else {
10274: wait_cpu_cycle_write_ce020 (addr + 0, 1, v);
10275: }
10276: break;
10277: case CE_MEMBANK_FAST16:
10278: case CE_MEMBANK_FAST32:
10279: put_word (addr, v);
10280: if ((addr & 3) == 3)
10281: do_cycles_ce020_mem (2 * CPU020_MEM_CYCLE, v);
10282: else
10283: do_cycles_ce020_mem (1 * CPU020_MEM_CYCLE, v);
10284: break;
10285: default:
10286: put_word (addr, v);
10287: break;
10288: }
1.1.1.9 ! root 10289: end_020_cycle();
1.1.1.7 root 10290: }
10291:
10292: void mem_access_delay_long_write_ce020 (uaecptr addr, uae_u32 v)
10293: {
1.1.1.9 ! root 10294: start_020_cycle();
1.1.1.7 root 10295: switch (ce_banktype[addr >> 16])
10296: {
10297: case CE_MEMBANK_CHIP16:
10298: wait_cpu_cycle_write_ce020 (addr + 0, 1, (v >> 16) & 0xffff);
10299: wait_cpu_cycle_write_ce020 (addr + 2, 1, (v >> 0) & 0xffff);
10300: break;
10301: case CE_MEMBANK_CHIP32:
10302: if ((addr & 3) == 3) {
10303: wait_cpu_cycle_write_ce020 (addr + 0, 1, (v >> 16) & 0xffff);
10304: wait_cpu_cycle_write_ce020 (addr + 2, 1, (v >> 0) & 0xffff);
10305: } else {
10306: wait_cpu_cycle_write_ce020 (addr + 0, -1, v);
10307: }
10308: break;
10309: case CE_MEMBANK_FAST32:
10310: put_long (addr, v);
10311: if ((addr & 3) != 0)
10312: do_cycles_ce020_mem (2 * CPU020_MEM_CYCLE, v);
10313: else
10314: do_cycles_ce020_mem (1 * CPU020_MEM_CYCLE, v);
10315: break;
10316: case CE_MEMBANK_FAST16:
10317: put_long (addr, v);
10318: do_cycles_ce020_mem (2 * CPU020_MEM_CYCLE, v);
10319: break;
10320: default:
10321: put_long (addr, v);
10322: break;
10323: }
1.1.1.9 ! root 10324: end_020_cycle();
1.1.1.7 root 10325: }
10326:
10327:
10328: // 68030 caches aren't so simple as 68020 cache..
1.1.1.9 ! root 10329: STATIC_INLINE struct cache030 *geticache030 (struct cache030 *cp, uaecptr addr, uae_u32 *tagp, int *lwsp)
1.1.1.7 root 10330: {
10331: int index, lws;
10332: uae_u32 tag;
10333: struct cache030 *c;
10334:
10335: addr &= ~3;
10336: index = (addr >> 4) & (CACHELINES030 - 1);
10337: tag = regs.s | (addr & ~((CACHELINES030 << 4) - 1));
10338: lws = (addr >> 2) & 3;
10339: c = &cp[index];
10340: *tagp = tag;
10341: *lwsp = lws;
1.1.1.9 ! root 10342: //fprintf ( stderr , "getcache addr=%x index=%x tag=%x lws=%x\n" , addr , index , tag , lws );
! 10343: return c;
! 10344: }
! 10345:
! 10346: STATIC_INLINE void update_icache030 (struct cache030 *c, uae_u32 val, uae_u32 tag, int lws)
! 10347: {
! 10348: if (c->tag != tag)
! 10349: c->valid[0] = c->valid[1] = c->valid[2] = c->valid[3] = false;
! 10350: c->tag = tag;
! 10351: c->valid[lws] = true;
! 10352: c->data[lws] = val;
! 10353: }
! 10354:
! 10355: STATIC_INLINE struct cache030 *getdcache030 (struct cache030 *cp, uaecptr addr, uae_u32 *tagp, int *lwsp)
! 10356: {
! 10357: int index, lws;
! 10358: uae_u32 tag;
! 10359: struct cache030 *c;
! 10360:
! 10361: addr &= ~3;
! 10362: index = (addr >> 4) & (CACHELINES030 - 1);
! 10363: tag = addr & ~((CACHELINES030 << 4) - 1);
! 10364: lws = (addr >> 2) & 3;
! 10365: c = &cp[index];
! 10366: *tagp = tag;
! 10367: *lwsp = lws;
1.1.1.7 root 10368: return c;
10369: }
10370:
1.1.1.9 ! root 10371: STATIC_INLINE void update_dcache030 (struct cache030 *c, uae_u32 val, uae_u32 tag, uae_u8 fc, int lws)
1.1.1.7 root 10372: {
10373: if (c->tag != tag)
10374: c->valid[0] = c->valid[1] = c->valid[2] = c->valid[3] = false;
10375: c->tag = tag;
1.1.1.9 ! root 10376: c->fc = fc;
1.1.1.7 root 10377: c->valid[lws] = true;
10378: c->data[lws] = val;
10379: }
10380:
10381: static void fill_icache030 (uae_u32 addr)
10382: {
10383: int lws;
10384: uae_u32 tag;
10385: uae_u32 data;
10386: struct cache030 *c;
1.1.1.9 ! root 10387: //fprintf ( stderr , "fill icache030 %x %x %x\n" , addr , regs.cacr , regs.cacheholdingaddr020 );
1.1.1.7 root 10388:
1.1.1.9 ! root 10389: regs.fc030 = (regs.s ? 4 : 0) | 2;
1.1.1.7 root 10390: addr &= ~3;
1.1.1.9 ! root 10391: if (regs.cacheholdingaddr020 == addr || regs.cacheholdingdata_valid == 0)
1.1.1.7 root 10392: return;
1.1.1.9 ! root 10393: c = geticache030 (icaches030, addr, &tag, &lws);
! 10394: if ((regs.cacr & 1) && c->valid[lws] && c->tag == tag) {
1.1.1.7 root 10395: // cache hit
10396: regs.cacheholdingaddr020 = addr;
10397: regs.cacheholdingdata020 = c->data[lws];
1.1.1.9 ! root 10398: //fprintf ( stderr , "fill ica %x -> hit %x %x\n" , addr , regs.cacheholdingdata020 , regs.cacr );
1.1.1.7 root 10399: #ifdef WINUAE_FOR_HATARI
10400: CpuInstruction.I_Cache_hit++;
1.1.1.4 root 10401: #endif
1.1.1.7 root 10402: return;
10403: }
10404:
1.1.1.9 ! root 10405: TRY (prb2) {
! 10406: // cache miss
! 10407: if (currprefs.cpu_cycle_exact) {
! 10408: regs.ce020memcycle_data = false;
! 10409: start_020_cycle_prefetch(false);
! 10410: data = icache_fetch(addr);
! 10411: end_020_cycle_prefetch(false);
! 10412: } else {
! 10413: data = icache_fetch(addr);
! 10414: }
! 10415: } CATCH (prb2) {
! 10416: // Bus error/MMU access fault: Delayed exception.
! 10417: regs.cacheholdingdata_valid = 0;
! 10418: regs.cacheholdingaddr020 = 0xffffffff;
! 10419: regs.cacheholdingdata020 = 0xffffffff;
! 10420: end_020_cycle_prefetch(false);
! 10421: return;
! 10422: } ENDTRY
! 10423:
! 10424: if (mmu030_cache_state & CACHE_ENABLE_INS) {
! 10425: if ((regs.cacr & 0x03) == 0x01) {
! 10426: // instruction cache not frozen and enabled
1.1.1.7 root 10427: //fprintf ( stderr , "fill ica %x -> update %x\n" , addr , data );
1.1.1.9 ! root 10428: update_icache030 (c, data, tag, lws);
! 10429: }
! 10430: 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 10431: //fprintf ( stderr , "fill ica %x -> burst %x\n" , addr , data );
1.1.1.9 ! root 10432: // do burst fetch if cache enabled, not frozen, all slots invalid, no chip ram
! 10433: int i;
! 10434: for (i = 0; i < 4; i++) {
! 10435: if (c->valid[i])
! 10436: break;
! 10437: }
! 10438: uaecptr baddr = addr & ~15;
! 10439: if (currprefs.mmu_model) {
! 10440: TRY (prb) {
! 10441: if (currprefs.cpu_cycle_exact)
! 10442: #ifndef WINUAE_FOR_HATARI
! 10443: do_cycles_ce020(3 * (CPU020_MEM_CYCLE - 1));
! 10444: #else
! 10445: do_cycles_ce020_long(3 * (CPU020_MEM_CYCLE - 1));
! 10446: #endif
! 10447: int j;
! 10448: for (j = 0; j < 3; j++) {
! 10449: i++;
! 10450: i &= 3;
! 10451: c->data[i] = icache_fetch(baddr + i * 4);
! 10452: c->valid[i] = true;
! 10453: }
! 10454: } CATCH (prb) {
! 10455: ; // abort burst fetch if bus error, do not report it.
! 10456: } ENDTRY
! 10457: } else {
! 10458: int j;
! 10459: for (j = 0; j < 3; j++) {
! 10460: i++;
! 10461: i &= 3;
! 10462: c->data[i] = icache_fetch(baddr + i * 4);
! 10463: c->valid[i] = true;
! 10464: }
! 10465: if (currprefs.cpu_cycle_exact)
! 10466: do_cycles_ce020_mem (3 * (CPU020_MEM_CYCLE - 1), c->data[3]);
! 10467: }
! 10468: }
1.1.1.7 root 10469: }
10470: regs.cacheholdingaddr020 = addr;
10471: regs.cacheholdingdata020 = data;
10472: //fprintf ( stderr , "fill ica %x -> miss %x\n" , addr , regs.cacheholdingdata020 );
10473: #ifdef WINUAE_FOR_HATARI
10474: CpuInstruction.I_Cache_miss++;
10475: #endif
10476: }
10477:
1.1.1.9 ! root 10478: #if VALIDATE_68030_DATACACHE
! 10479: static void validate_dcache030(void)
1.1.1.7 root 10480: {
1.1.1.9 ! root 10481: int i,j;
! 10482: for (i = 0; i < CACHELINES030; i++) {
! 10483: struct cache030 *c = &dcaches030[i];
! 10484: uae_u32 addr = c->tag & ~((CACHELINES030 << 4) - 1);
! 10485: addr |= i << 4;
! 10486: for (j = 0; j < 4; j++) {
! 10487: if (c->valid[j]) {
! 10488: uae_u32 v = get_long(addr);
! 10489: if (v != c->data[j]) {
! 10490: write_log(_T("Address %08x data cache mismatch %08x != %08x\n"), addr, v, c->data[j]);
! 10491: }
! 10492: }
! 10493: addr += 4;
! 10494: }
! 10495: }
1.1.1.7 root 10496: }
10497:
1.1.1.9 ! root 10498: static void validate_dcache030_read(uae_u32 addr, uae_u32 ov, int size)
1.1.1.7 root 10499: {
1.1.1.9 ! root 10500: uae_u32 ov2;
! 10501: if (size == 2) {
! 10502: ov2 = get_long(addr);
! 10503: } else if (size == 1) {
! 10504: ov2 = get_word(addr);
! 10505: ov &= 0xffff;
! 10506: } else {
! 10507: ov2 = get_byte(addr);
! 10508: ov &= 0xff;
1.1.1.4 root 10509: }
1.1.1.9 ! root 10510: if (ov2 != ov) {
! 10511: write_log(_T("Address read %08x data cache mismatch %08x != %08x\n"), addr, ov2, ov);
! 10512: }
! 10513: }
! 10514: #endif
1.1.1.7 root 10515:
1.1.1.9 ! root 10516: // and finally the worst part, 68030 data cache..
! 10517: static void write_dcache030x(uaecptr addr, uae_u32 val, uae_u32 size, uae_u32 fc)
! 10518: {
! 10519: if (regs.cacr & 0x100) {
! 10520: static const uae_u32 mask[3] = { 0xff000000, 0xffff0000, 0xffffffff };
! 10521: struct cache030 *c1, *c2;
! 10522: int lws1, lws2;
! 10523: uae_u32 tag1, tag2;
! 10524: int aligned = addr & 3;
! 10525: int wa = regs.cacr & 0x2000;
! 10526: int width = 8 << size;
! 10527: int offset = 8 * aligned;
! 10528: int hit;
! 10529:
! 10530: c1 = getdcache030(dcaches030, addr, &tag1, &lws1);
! 10531: hit = c1->tag == tag1 && c1->fc == fc && c1->valid[lws1];
! 10532:
! 10533: // Write-allocate can create new valid cache entry if
! 10534: // long aligned long write and MMU CI is not active.
! 10535: // All writes ignore external CIIN signal.
! 10536: // CACHE_DISABLE_ALLOCATE = emulation only method to disable WA caching completely.
! 10537:
! 10538: if (width == 32 && offset == 0 && wa) {
! 10539: if (!(mmu030_cache_state & CACHE_DISABLE_MMU) && !(mmu030_cache_state & CACHE_DISABLE_ALLOCATE)) {
! 10540: update_dcache030(c1, val, tag1, fc, lws1);
! 10541: //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] );
! 10542: #if VALIDATE_68030_DATACACHE
! 10543: validate_dcache030();
! 10544: #endif
! 10545: } else if (hit) {
! 10546: // Does real 68030 do this if MMU cache inhibited?
1.1.1.7 root 10547: c1->valid[lws1] = false;
1.1.1.9 ! root 10548: }
! 10549: return;
! 10550: }
! 10551:
! 10552: if (hit || wa) {
1.1.1.7 root 10553: if (hit) {
1.1.1.9 ! root 10554: uae_u32 val_left_aligned = val << (32 - width);
! 10555: c1->data[lws1] &= ~(mask[size] >> offset);
! 10556: c1->data[lws1] |= val_left_aligned >> offset;
! 10557: } else {
1.1.1.7 root 10558: c1->valid[lws1] = false;
1.1.1.9 ! root 10559: }
! 10560: }
! 10561:
! 10562: // do we need to update a 2nd cache entry ?
! 10563: if (width + offset > 32) {
! 10564: c2 = getdcache030(dcaches030, addr + 4, &tag2, &lws2);
! 10565: hit = c2->tag == tag2 && c2->fc == fc && c2->valid[lws2];
! 10566: if (hit || wa) {
! 10567: if (hit) {
! 10568: c2->data[lws2] &= 0xffffffff >> (width + offset - 32);
! 10569: c2->data[lws2] |= val << (32 - (width + offset - 32));
! 10570: } else {
! 10571: c2->valid[lws2] = false;
! 10572: }
! 10573: }
1.1.1.7 root 10574: }
1.1.1.9 ! root 10575: #if VALIDATE_68030_DATACACHE
! 10576: validate_dcache030();
! 10577: #endif
1.1.1.7 root 10578: }
1.1.1.9 ! root 10579: }
1.1.1.7 root 10580:
1.1.1.9 ! root 10581: void write_dcache030_bput(uaecptr addr, uae_u32 v,uae_u32 fc)
! 10582: {
! 10583: //fprintf ( stderr , "write dcache %x %x %d\n" , addr , v , size );
! 10584: regs.fc030 = fc;
! 10585: dcache_bput(addr, v);
! 10586: write_dcache030x(addr, v, 0, fc);
! 10587: }
! 10588: void write_dcache030_wput(uaecptr addr, uae_u32 v,uae_u32 fc)
! 10589: {
! 10590: regs.fc030 = fc;
! 10591: dcache_wput(addr, v);
! 10592: write_dcache030x(addr, v, 1, fc);
! 10593: }
! 10594: void write_dcache030_lput(uaecptr addr, uae_u32 v,uae_u32 fc)
! 10595: {
! 10596: regs.fc030 = fc;
! 10597: dcache_lput(addr, v);
! 10598: write_dcache030x(addr, v, 2, fc);
! 10599: }
1.1.1.7 root 10600:
1.1.1.9 ! root 10601: static void dcache030_maybe_burst(uaecptr addr, struct cache030 *c, int lws)
! 10602: {
! 10603: if ((c->valid[0] + c->valid[1] + c->valid[2] + c->valid[3] == 1) && ce_banktype[addr >> 16] == CE_MEMBANK_FAST32) {
! 10604: // do burst fetch if cache enabled, not frozen, all slots invalid, no chip ram
! 10605: int i;
! 10606: uaecptr baddr = addr & ~15;
! 10607: for (i = 0; i < 4; i++) {
! 10608: if (c->valid[i])
! 10609: break;
1.1.1.4 root 10610: }
1.1.1.9 ! root 10611: if (currprefs.mmu_model) {
! 10612: TRY (prb) {
! 10613: if (currprefs.cpu_cycle_exact)
! 10614: #ifndef WINUAE_FOR_HATARI
! 10615: do_cycles_ce020(3 * (CPU020_MEM_CYCLE - 1));
! 10616: #else
! 10617: do_cycles_ce020_long(3 * (CPU020_MEM_CYCLE - 1));
! 10618: #endif
! 10619: int j;
! 10620: for (j = 0; j < 3; j++) {
! 10621: i++;
! 10622: i &= 3;
! 10623: c->data[i] = dcache_lget (baddr + i * 4);
! 10624: c->valid[i] = true;
! 10625: }
! 10626: } CATCH (prb) {
! 10627: ; // abort burst fetch if bus error
! 10628: } ENDTRY
! 10629: } else {
! 10630: int j;
! 10631: for (j = 0; j < 3; j++) {
! 10632: i++;
! 10633: i &= 3;
! 10634: c->data[i] = dcache_lget (baddr + i * 4);
! 10635: c->valid[i] = true;
! 10636: }
! 10637: if (currprefs.cpu_cycle_exact)
! 10638: do_cycles_ce020_mem (3 * (CPU020_MEM_CYCLE - 1), c->data[i]);
! 10639: }
! 10640: #if VALIDATE_68030_DATACACHE
! 10641: validate_dcache030();
! 10642: #endif
1.1.1.4 root 10643: }
10644: }
10645:
1.1.1.9 ! root 10646: static uae_u32 read_dcache030_debug(uaecptr addr, uae_u32 size, uae_u32 fc, bool *cached)
1.1.1.7 root 10647: {
1.1.1.9 ! root 10648: static const uae_u32 mask[3] = { 0x000000ff, 0x0000ffff, 0xffffffff };
! 10649: struct cache030 *c1, *c2;
! 10650: int lws1, lws2;
! 10651: uae_u32 tag1, tag2;
! 10652: int aligned = addr & 3;
! 10653: uae_u32 v1, v2;
! 10654: int width = 8 << size;
! 10655: int offset = 8 * aligned;
! 10656: uae_u32 out;
! 10657:
! 10658: *cached = false;
! 10659: if (!currprefs.cpu_data_cache) {
! 10660: if (size == 0)
! 10661: return get_byte_debug(addr);
! 10662: if (size == 1)
! 10663: return get_word_debug(addr);
! 10664: return get_long_debug(addr);
! 10665: }
! 10666:
! 10667: c1 = getdcache030(dcaches030, addr, &tag1, &lws1);
! 10668: addr &= ~3;
! 10669: if (!c1->valid[lws1] || c1->tag != tag1 || c1->fc != fc) {
! 10670: v1 = get_long_debug(addr);
1.1.1.7 root 10671: } else {
1.1.1.9 ! root 10672: // Cache hit, inhibited caching do not prevent read hits.
! 10673: v1 = c1->data[lws1];
! 10674: *cached = true;
! 10675: }
! 10676:
! 10677: // only one long fetch needed?
! 10678: if (width + offset <= 32) {
! 10679: out = v1 >> (32 - (offset + width));
! 10680: out &= mask[size];
! 10681: return out;
! 10682: }
! 10683:
! 10684: // no, need another one
! 10685: addr += 4;
! 10686: c2 = getdcache030(dcaches030, addr, &tag2, &lws2);
! 10687: if (!c2->valid[lws2] || c2->tag != tag2 || c2->fc != fc) {
! 10688: v2 = get_long_debug(addr);
! 10689: } else {
! 10690: v2 = c2->data[lws2];
! 10691: *cached = true;
1.1.1.7 root 10692: }
1.1.1.9 ! root 10693:
! 10694: uae_u64 v64 = ((uae_u64)v1 << 32) | v2;
! 10695: out = (uae_u32)(v64 >> (64 - (offset + width)));
! 10696: out &= mask[size];
! 10697: return out;
1.1.1.7 root 10698: }
10699:
10700: // [HATARI] Define next line to check for 68030 data cache mismatch after every write
10701: //#define WINUAE_FOR_HATARI_DEBUG_CACHE
10702: #ifdef WINUAE_FOR_HATARI_DEBUG_CACHE
1.1.1.9 ! root 10703: uae_u32 read_dcache030_0 (uaecptr addr, uae_u32 size, uae_u32 fc);
! 10704: static uae_u32 read_dcache030 (uaecptr addr, uae_u32 size, uae_u32 fc)
1.1.1.7 root 10705: {
10706: uae_u32 v;
10707:
1.1.1.9 ! root 10708: v = read_dcache030_0 ( addr , size , fc );
! 10709: if (!(regs.cacr & 0x100))
1.1.1.7 root 10710: return v;
10711: if ( ( ( size==2 ) && ( v != get_long ( addr ) ) )
10712: || ( ( size==1 ) && ( (v&0xffff) != (get_word ( addr ) & 0xffff) ) )
10713: || ( ( size==0 ) && ( (v&0xff) != (get_byte ( addr ) & 0xff ) ) ) )
10714: fprintf ( stderr , "d-cache mismatch pc=%x addr=%x size=%d cache=%x != mem=%x, d-cache error ?\n" , m68k_getpc(), addr, size, v , get_long(addr) );
10715: return v;
10716: }
1.1.1.9 ! root 10717: uae_u32 read_dcache030_0 (uaecptr addr, uae_u32 size, uae_u32 fc)
1.1.1.7 root 10718: #else
1.1.1.9 ! root 10719: static uae_u32 read_dcache030 (uaecptr addr, uae_u32 size, uae_u32 fc)
1.1.1.7 root 10720: #endif
1.1.1.4 root 10721: {
1.1.1.9 ! root 10722: uae_u32 addr_o = addr;
! 10723: regs.fc030 = fc;
! 10724: if (regs.cacr & 0x100) { // data cache enabled?
! 10725: static const uae_u32 mask[3] = { 0x000000ff, 0x0000ffff, 0xffffffff };
! 10726: struct cache030 *c1, *c2;
! 10727: int lws1, lws2;
! 10728: uae_u32 tag1, tag2;
! 10729: int aligned = addr & 3;
! 10730: uae_u32 v1, v2;
! 10731: int width = 8 << size;
! 10732: int offset = 8 * aligned;
! 10733: uae_u32 out;
! 10734:
! 10735: c1 = getdcache030 (dcaches030, addr, &tag1, &lws1);
! 10736: addr &= ~3;
! 10737: if (!c1->valid[lws1] || c1->tag != tag1 || c1->fc != fc) {
! 10738: // MMU validate address, returns zero if valid but uncacheable
! 10739: // throws bus error if invalid
! 10740: uae_u8 cs = dcache_check(addr_o, false, size);
! 10741: if (!(cs & CACHE_ENABLE_DATA))
! 10742: goto end;
! 10743: v1 = dcache_lget(addr);
! 10744: update_dcache030 (c1, v1, tag1, fc, lws1);
! 10745: if ((cs & CACHE_ENABLE_DATA_BURST) && (regs.cacr & 0x1100) == 0x1100)
! 10746: dcache030_maybe_burst(addr, c1, lws1);
! 10747: #if VALIDATE_68030_DATACACHE
! 10748: validate_dcache030();
! 10749: #endif
! 10750: //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) );
! 10751: #ifdef WINUAE_FOR_HATARI
! 10752: CpuInstruction.D_Cache_miss++;
! 10753: #endif
1.1.1.7 root 10754: } else {
1.1.1.9 ! root 10755: // Cache hit, inhibited caching do not prevent read hits.
! 10756: v1 = c1->data[lws1];
1.1.1.7 root 10757: #ifdef WINUAE_FOR_HATARI
10758: CpuInstruction.D_Cache_hit++;
10759: #endif
10760: }
1.1.1.9 ! root 10761:
! 10762: // only one long fetch needed?
! 10763: if (width + offset <= 32) {
! 10764: out = v1 >> (32 - (offset + width));
! 10765: out &= mask[size];
! 10766: #if VALIDATE_68030_DATACACHE
! 10767: validate_dcache030_read(addr_o, out, size);
! 10768: #endif
! 10769: return out;
! 10770: }
! 10771:
! 10772: // no, need another one
! 10773: addr += 4;
! 10774: c2 = getdcache030 (dcaches030, addr, &tag2, &lws2);
! 10775: if (!c2->valid[lws2] || c2->tag != tag2 || c2->fc != fc) {
! 10776: uae_u8 cs = dcache_check(addr, false, 2);
! 10777: if (!(cs & CACHE_ENABLE_DATA))
! 10778: goto end;
! 10779: v2 = dcache_lget(addr);
! 10780: update_dcache030 (c2, v2, tag2, fc, lws2);
! 10781: if ((cs & CACHE_ENABLE_DATA_BURST) && (regs.cacr & 0x1100) == 0x1100)
! 10782: dcache030_maybe_burst(addr, c2, lws2);
! 10783: #if VALIDATE_68030_DATACACHE
! 10784: validate_dcache030();
! 10785: #endif
1.1.1.7 root 10786: //fprintf ( stderr , "read cache %x %x %d tag1 %x lws1 %x tag2 %x lws2 %x\n", addr, v1, size, tag1, lws1, tag2, lws2 );
10787: #ifdef WINUAE_FOR_HATARI
10788: CpuInstruction.D_Cache_miss++;
10789: #endif
1.1.1.9 ! root 10790: } else {
! 10791: v2 = c2->data[lws2];
! 10792: #ifdef WINUAE_FOR_HATARI
1.1.1.7 root 10793: CpuInstruction.D_Cache_hit++;
10794: #endif
1.1.1.9 ! root 10795: }
! 10796:
! 10797: uae_u64 v64 = ((uae_u64)v1 << 32) | v2;
! 10798: out = (uae_u32)(v64 >> (64 - (offset + width)));
! 10799: out &= mask[size];
! 10800:
! 10801: #if VALIDATE_68030_DATACACHE
! 10802: validate_dcache030_read(addr_o, out, size);
! 10803: #endif
! 10804: return out;
! 10805:
! 10806: }
! 10807: end:
! 10808: // read from memory, data cache is disabled or inhibited.
! 10809: if (size == 2)
! 10810: return dcache_lget (addr_o);
! 10811: else if (size == 1)
! 10812: return dcache_wget (addr_o);
! 10813: else
! 10814: return dcache_bget (addr_o);
! 10815: }
! 10816: uae_u32 read_dcache030_bget(uaecptr addr, uae_u32 fc)
! 10817: {
! 10818: return read_dcache030(addr, 0, fc);
! 10819: }
! 10820: uae_u32 read_dcache030_wget(uaecptr addr, uae_u32 fc)
! 10821: {
! 10822: return read_dcache030(addr, 1, fc);
! 10823: }
! 10824: uae_u32 read_dcache030_lget(uaecptr addr, uae_u32 fc)
! 10825: {
! 10826: return read_dcache030(addr, 2, fc);
! 10827: }
1.1.1.7 root 10828:
1.1.1.9 ! root 10829: uae_u32 read_dcache030_mmu_bget(uaecptr addr)
! 10830: {
! 10831: return read_dcache030_bget(addr, (regs.s ? 4 : 0) | 1);
! 10832: }
! 10833: uae_u32 read_dcache030_mmu_wget(uaecptr addr)
! 10834: {
! 10835: return read_dcache030_wget(addr, (regs.s ? 4 : 0) | 1);
! 10836: }
! 10837: uae_u32 read_dcache030_mmu_lget(uaecptr addr)
! 10838: {
! 10839: return read_dcache030_lget(addr, (regs.s ? 4 : 0) | 1);
! 10840: }
! 10841: void write_dcache030_mmu_bput(uaecptr addr, uae_u32 val)
! 10842: {
! 10843: write_dcache030_bput(addr, val, (regs.s ? 4 : 0) | 1);
! 10844: }
! 10845: void write_dcache030_mmu_wput(uaecptr addr, uae_u32 val)
! 10846: {
! 10847: write_dcache030_wput(addr, val, (regs.s ? 4 : 0) | 1);
! 10848: }
! 10849: void write_dcache030_mmu_lput(uaecptr addr, uae_u32 val)
! 10850: {
! 10851: write_dcache030_lput(addr, val, (regs.s ? 4 : 0) | 1);
! 10852: }
1.1.1.4 root 10853:
1.1.1.9 ! root 10854: uae_u32 read_dcache030_lrmw_mmu(uaecptr addr, uae_u32 size)
! 10855: {
! 10856: if (currprefs.cpu_data_cache) {
! 10857: mmu030_cache_state = CACHE_DISABLE_MMU;
! 10858: if (size == 0)
! 10859: return read_dcache030_bget(addr, (regs.s ? 4 : 0) | 1);
! 10860: if (size == 1)
! 10861: return read_dcache030_wget(addr, (regs.s ? 4 : 0) | 1);
! 10862: return read_dcache030_lget(addr, (regs.s ? 4 : 0) | 1);
! 10863: } else {
! 10864: if (size == 0)
! 10865: return read_data_030_bget(addr);
! 10866: if (size == 1)
! 10867: return read_data_030_wget(addr);
! 10868: return read_data_030_lget(addr);
! 10869: }
! 10870: }
! 10871: void write_dcache030_lrmw_mmu(uaecptr addr, uae_u32 val, uae_u32 size)
! 10872: {
! 10873: if (currprefs.cpu_data_cache) {
! 10874: mmu030_cache_state = CACHE_DISABLE_MMU;
! 10875: if (size == 0)
! 10876: write_dcache030_bput(addr, val, (regs.s ? 4 : 0) | 1);
! 10877: else if (size == 1)
! 10878: write_dcache030_wput(addr, val, (regs.s ? 4 : 0) | 1);
! 10879: else
! 10880: write_dcache030_lput(addr, val, (regs.s ? 4 : 0) | 1);
! 10881: } else {
! 10882: if (size == 0)
! 10883: write_data_030_bput(addr, val);
! 10884: else if (size == 1)
! 10885: write_data_030_wput(addr, val);
! 10886: else
! 10887: write_data_030_lput(addr, val);
! 10888: }
1.1.1.4 root 10889: }
10890:
1.1.1.9 ! root 10891: static void do_access_or_bus_error(uaecptr pc, uaecptr pcnow)
! 10892: {
! 10893: // TODO: handle external bus errors
! 10894: if (!currprefs.mmu_model)
! 10895: return;
! 10896: if (pc != 0xffffffff)
! 10897: regs.instruction_pc = pc;
! 10898: mmu030_opcode = -1;
! 10899: mmu030_page_fault(pcnow, true, -1, 0);
! 10900: }
! 10901:
! 10902: static uae_u32 get_word_ce030_prefetch_2 (int o)
1.1.1.4 root 10903: {
10904: uae_u32 pc = m68k_getpc () + o;
1.1.1.7 root 10905: uae_u32 v;
1.1.1.4 root 10906:
1.1.1.9 ! root 10907: //fprintf ( stderr , "get_word_ce030_prefetch_2 %d pc=%x\n" , currcycle , pc);
! 10908: v = regs.prefetch020[0];
! 10909: regs.prefetch020[0] = regs.prefetch020[1];
! 10910: regs.prefetch020[1] = regs.prefetch020[2];
1.1.1.7 root 10911: #if MORE_ACCURATE_68020_PIPELINE
1.1.1.9 ! root 10912: pipeline_020(pc);
1.1.1.7 root 10913: #endif
1.1.1.9 ! root 10914: if (pc & 2) {
1.1.1.7 root 10915: // branch instruction detected in pipeline: stop fetches until branch executed.
10916: if (!MORE_ACCURATE_68020_PIPELINE || regs.pipeline_stop >= 0) {
10917: fill_icache030 (pc + 2 + 4);
1.1.1.9 ! root 10918: } else {
! 10919: if (regs.cacheholdingdata_valid > 0)
! 10920: regs.cacheholdingdata_valid++;
1.1.1.7 root 10921: }
1.1.1.9 ! root 10922: regs.prefetch020[2] = regs.cacheholdingdata020 >> 16;
1.1.1.7 root 10923: } else {
1.1.1.9 ! root 10924: pc += 4;
! 10925: // cacheholdingdata020 may be invalid if RTE from bus error
! 10926: if ((!MORE_ACCURATE_68020_PIPELINE || regs.pipeline_stop >= 0) && regs.cacheholdingaddr020 != pc) {
! 10927: fill_icache030 (pc);
! 10928: }
! 10929: regs.prefetch020[2] = (uae_u16)regs.cacheholdingdata020;
1.1.1.7 root 10930: }
1.1.1.9 ! root 10931: regs.db = regs.prefetch020[0];
1.1.1.7 root 10932: do_cycles_ce020_internal (2);
10933: return v;
10934: }
10935:
1.1.1.9 ! root 10936: uae_u32 get_word_ce030_prefetch (int o)
! 10937: {
! 10938: return get_word_ce030_prefetch_2(o);
! 10939: }
! 10940: uae_u32 get_word_ce030_prefetch_opcode (int o)
! 10941: {
! 10942: return get_word_ce030_prefetch_2(o);
! 10943: }
! 10944:
! 10945: uae_u32 get_word_030_prefetch (int o)
1.1.1.7 root 10946: {
1.1.1.9 ! root 10947: uae_u32 pc = m68k_getpc () + o;
1.1.1.7 root 10948: uae_u32 v;
10949:
1.1.1.9 ! root 10950: v = regs.prefetch020[0];
! 10951: regs.prefetch020[0] = regs.prefetch020[1];
! 10952: regs.prefetch020[1] = regs.prefetch020[2];
! 10953: regs.prefetch020_valid[0] = regs.prefetch020_valid[1];
! 10954: regs.prefetch020_valid[1] = regs.prefetch020_valid[2];
! 10955: regs.prefetch020_valid[2] = false;
! 10956: if (!regs.prefetch020_valid[1]) {
! 10957: do_access_or_bus_error(0xffffffff, pc + 4);
! 10958: }
1.1.1.7 root 10959: #if MORE_ACCURATE_68020_PIPELINE
1.1.1.9 ! root 10960: pipeline_020(pc);
1.1.1.7 root 10961: #endif
1.1.1.9 ! root 10962: if (pc & 2) {
1.1.1.7 root 10963: // branch instruction detected in pipeline: stop fetches until branch executed.
10964: if (!MORE_ACCURATE_68020_PIPELINE || regs.pipeline_stop >= 0) {
1.1.1.9 ! root 10965: fill_icache030 (pc + 2 + 4);
! 10966: } else {
! 10967: if (regs.cacheholdingdata_valid > 0)
! 10968: regs.cacheholdingdata_valid++;
1.1.1.7 root 10969: }
1.1.1.9 ! root 10970: regs.prefetch020[2] = regs.cacheholdingdata020 >> 16;
1.1.1.7 root 10971: } else {
1.1.1.9 ! root 10972: pc += 4;
! 10973: // cacheholdingdata020 may be invalid if RTE from bus error
! 10974: if ((!MORE_ACCURATE_68020_PIPELINE || regs.pipeline_stop >= 0) && regs.cacheholdingaddr020 != pc) {
! 10975: fill_icache030 (pc);
! 10976: }
! 10977: regs.prefetch020[2] = (uae_u16)regs.cacheholdingdata020;
1.1.1.7 root 10978: }
1.1.1.9 ! root 10979: regs.prefetch020_valid[2] = regs.cacheholdingdata_valid;
! 10980: regs.db = regs.prefetch020[0];
! 10981: //if ( ( v & 0xffff ) != ( get_word(pc) & 0xffff ) )
! 10982: // 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 10983: return v;
10984: }
10985:
10986: uae_u32 get_word_icache030(uaecptr addr)
10987: {
10988: fill_icache030(addr);
10989: return regs.cacheholdingdata020 >> ((addr & 2) ? 0 : 16);
10990: }
10991: uae_u32 get_long_icache030(uaecptr addr)
10992: {
10993: uae_u32 v;
10994: fill_icache030(addr);
10995: if ((addr & 2) == 0)
10996: return regs.cacheholdingdata020;
10997: v = regs.cacheholdingdata020 << 16;
10998: fill_icache030(addr + 4);
10999: v |= regs.cacheholdingdata020 >> 16;
11000: return v;
11001: }
11002:
1.1.1.9 ! root 11003: uae_u32 fill_icache040(uae_u32 addr)
! 11004: {
! 11005: int index, lws;
! 11006: uae_u32 tag, addr2;
! 11007: struct cache040 *c;
! 11008: int line;
! 11009: int i;
! 11010:
! 11011: addr2 = addr & ~15;
! 11012: lws = (addr >> 2) & 3;
! 11013:
! 11014: if (regs.prefetch020addr == addr2) {
! 11015: return regs.prefetch040[lws];
! 11016: }
! 11017:
! 11018: if (regs.cacr & 0x8000) {
! 11019: uae_u8 cs = mmu_cache_state;
! 11020:
! 11021: if (!(ce_cachable[addr >> 16] & CACHE_ENABLE_INS))
! 11022: cs = CACHE_DISABLE_MMU;
! 11023:
! 11024: index = (addr >> 4) & cacheisets04060mask;
! 11025: tag = addr & cacheitag04060mask;
! 11026: c = &icaches040[index];
! 11027: for (i = 0; i < CACHELINES040; i++) {
! 11028: if (c->valid[cache_lastline] && c->tag[cache_lastline] == tag) {
! 11029: // cache hit
! 11030: if (!(cs & CACHE_ENABLE_INS) || (cs & CACHE_DISABLE_MMU)) {
! 11031: c->valid[cache_lastline] = false;
! 11032: goto end;
! 11033: }
! 11034: if ((lws & 1) != icachehalfline) {
! 11035: icachehalfline ^= 1;
! 11036: icachelinecnt++;
! 11037: #ifdef WINUAE_FOR_HATARI
! 11038: CpuInstruction.I_Cache_hit++;
! 11039: #endif
! 11040: }
! 11041: return c->data[cache_lastline][lws];
! 11042: }
! 11043: cache_lastline++;
! 11044: cache_lastline &= (CACHELINES040 - 1);
! 11045: }
! 11046: // cache miss
! 11047: regs.prefetch020addr = 0xffffffff;
! 11048: regs.prefetch040[0] = icache_fetch(addr2 + 0);
! 11049: regs.prefetch040[1] = icache_fetch(addr2 + 4);
! 11050: regs.prefetch040[2] = icache_fetch(addr2 + 8);
! 11051: regs.prefetch040[3] = icache_fetch(addr2 + 12);
! 11052: regs.prefetch020addr = addr2;
! 11053: if (!(cs & CACHE_ENABLE_INS) || (cs & CACHE_DISABLE_MMU))
! 11054: goto end;
! 11055: if (regs.cacr & 0x00004000) // 68060 NAI
! 11056: goto end;
! 11057: if (c->valid[0] && c->valid[1] && c->valid[2] && c->valid[3]) {
! 11058: line = icachelinecnt & (CACHELINES040 - 1);
! 11059: icachehalfline = (lws & 1) ? 0 : 1;
! 11060: } else {
! 11061: for (line = 0; line < CACHELINES040; line++) {
! 11062: if (c->valid[line] == false)
! 11063: break;
! 11064: }
! 11065: }
! 11066: c->tag[line] = tag;
! 11067: c->valid[line] = true;
! 11068: c->data[line][0] = regs.prefetch040[0];
! 11069: c->data[line][1] = regs.prefetch040[1];
! 11070: c->data[line][2] = regs.prefetch040[2];
! 11071: c->data[line][3] = regs.prefetch040[3];
! 11072: if ((lws & 1) != icachehalfline) {
! 11073: icachehalfline ^= 1;
! 11074: icachelinecnt++;
! 11075: }
! 11076: #ifdef WINUAE_FOR_HATARI
! 11077: CpuInstruction.I_Cache_miss++;
! 11078: #endif
! 11079: return c->data[line][lws];
! 11080:
! 11081: }
! 11082:
! 11083: end:
! 11084: if (regs.prefetch020addr == addr2)
! 11085: return regs.prefetch040[lws];
! 11086: regs.prefetch020addr = addr2;
! 11087: regs.prefetch040[0] = icache_fetch(addr2 + 0);
! 11088: regs.prefetch040[1] = icache_fetch(addr2 + 4);
! 11089: regs.prefetch040[2] = icache_fetch(addr2 + 8);
! 11090: regs.prefetch040[3] = icache_fetch(addr2 + 12);
! 11091: return regs.prefetch040[lws];
! 11092: }
! 11093:
! 11094: STATIC_INLINE void do_cycles_c040_mem (int clocks, uae_u32 val)
! 11095: {
! 11096: x_do_cycles_post (clocks * cpucycleunit, val);
! 11097: }
! 11098:
! 11099: uae_u32 mem_access_delay_longi_read_c040 (uaecptr addr)
! 11100: {
! 11101: uae_u32 v;
! 11102: switch (ce_banktype[addr >> 16])
! 11103: {
! 11104: case CE_MEMBANK_CHIP16:
! 11105: v = wait_cpu_cycle_read_ce020 (addr + 0, 1) << 16;
! 11106: v |= wait_cpu_cycle_read_ce020 (addr + 2, 1) << 0;
! 11107: break;
! 11108: case CE_MEMBANK_CHIP32:
! 11109: if ((addr & 3) != 0) {
! 11110: v = wait_cpu_cycle_read_ce020 (addr + 0, 1) << 16;
! 11111: v |= wait_cpu_cycle_read_ce020 (addr + 2, 1) << 0;
! 11112: } else {
! 11113: v = wait_cpu_cycle_read_ce020 (addr, -1);
! 11114: }
! 11115: break;
! 11116: case CE_MEMBANK_FAST16:
! 11117: v = get_longi (addr);
! 11118: do_cycles_c040_mem(1, v);
! 11119: break;
! 11120: case CE_MEMBANK_FAST32:
! 11121: v = get_longi (addr);
! 11122: break;
! 11123: default:
! 11124: v = get_longi (addr);
! 11125: break;
! 11126: }
! 11127: return v;
! 11128: }
! 11129: uae_u32 mem_access_delay_long_read_c040 (uaecptr addr)
! 11130: {
! 11131: uae_u32 v;
! 11132: switch (ce_banktype[addr >> 16])
! 11133: {
! 11134: case CE_MEMBANK_CHIP16:
! 11135: v = wait_cpu_cycle_read_ce020 (addr + 0, 1) << 16;
! 11136: v |= wait_cpu_cycle_read_ce020 (addr + 2, 1) << 0;
! 11137: break;
! 11138: case CE_MEMBANK_CHIP32:
! 11139: if ((addr & 3) != 0) {
! 11140: v = wait_cpu_cycle_read_ce020 (addr + 0, 1) << 16;
! 11141: v |= wait_cpu_cycle_read_ce020 (addr + 2, 1) << 0;
! 11142: } else {
! 11143: v = wait_cpu_cycle_read_ce020 (addr, -1);
! 11144: }
! 11145: break;
! 11146: case CE_MEMBANK_FAST16:
! 11147: v = get_long (addr);
! 11148: do_cycles_c040_mem(1, v);
! 11149: break;
! 11150: case CE_MEMBANK_FAST32:
! 11151: v = get_long (addr);
! 11152: break;
! 11153: default:
! 11154: v = get_long (addr);
! 11155: break;
! 11156: }
! 11157: return v;
! 11158: }
! 11159:
! 11160: uae_u32 mem_access_delay_word_read_c040 (uaecptr addr)
! 11161: {
! 11162: uae_u32 v;
! 11163: switch (ce_banktype[addr >> 16])
! 11164: {
! 11165: case CE_MEMBANK_CHIP16:
! 11166: case CE_MEMBANK_CHIP32:
! 11167: if ((addr & 3) == 3) {
! 11168: v = wait_cpu_cycle_read_ce020 (addr + 0, 0) << 8;
! 11169: v |= wait_cpu_cycle_read_ce020 (addr + 1, 0) << 0;
! 11170: } else {
! 11171: v = wait_cpu_cycle_read_ce020 (addr, 1);
! 11172: }
! 11173: break;
! 11174: case CE_MEMBANK_FAST16:
! 11175: v = get_word (addr);
! 11176: do_cycles_c040_mem (2, v);
! 11177: break;
! 11178: case CE_MEMBANK_FAST32:
! 11179: v = get_word (addr);
! 11180: break;
! 11181: default:
! 11182: v = get_word (addr);
! 11183: break;
! 11184: }
! 11185: return v;
! 11186: }
! 11187:
! 11188: uae_u32 mem_access_delay_byte_read_c040 (uaecptr addr)
! 11189: {
! 11190: uae_u32 v;
! 11191: switch (ce_banktype[addr >> 16])
! 11192: {
! 11193: case CE_MEMBANK_CHIP16:
! 11194: case CE_MEMBANK_CHIP32:
! 11195: v = wait_cpu_cycle_read_ce020 (addr, 0);
! 11196: break;
! 11197: case CE_MEMBANK_FAST16:
! 11198: v = get_byte (addr);
! 11199: do_cycles_c040_mem (1, v);
! 11200: break;
! 11201: case CE_MEMBANK_FAST32:
! 11202: v = get_byte (addr);
! 11203: break;
! 11204: default:
! 11205: v = get_byte (addr);
! 11206: break;
! 11207: }
! 11208: return v;
! 11209: }
! 11210:
! 11211: void mem_access_delay_byte_write_c040 (uaecptr addr, uae_u32 v)
! 11212: {
! 11213: switch (ce_banktype[addr >> 16])
! 11214: {
! 11215: case CE_MEMBANK_CHIP16:
! 11216: case CE_MEMBANK_CHIP32:
! 11217: wait_cpu_cycle_write_ce020 (addr, 0, v);
! 11218: break;
! 11219: case CE_MEMBANK_FAST16:
! 11220: put_byte (addr, v);
! 11221: do_cycles_c040_mem (1, v);
! 11222: break;
! 11223: case CE_MEMBANK_FAST32:
! 11224: put_byte (addr, v);
! 11225: break;
! 11226: default:
! 11227: put_byte (addr, v);
! 11228: break;
! 11229: }
! 11230: }
! 11231:
! 11232: void mem_access_delay_word_write_c040 (uaecptr addr, uae_u32 v)
! 11233: {
! 11234: switch (ce_banktype[addr >> 16])
! 11235: {
! 11236: case CE_MEMBANK_CHIP16:
! 11237: case CE_MEMBANK_CHIP32:
! 11238: if ((addr & 3) == 3) {
! 11239: wait_cpu_cycle_write_ce020 (addr + 0, 0, (v >> 8) & 0xff);
! 11240: wait_cpu_cycle_write_ce020 (addr + 1, 0, (v >> 0) & 0xff);
! 11241: } else {
! 11242: wait_cpu_cycle_write_ce020 (addr + 0, 1, v);
! 11243: }
! 11244: break;
! 11245: case CE_MEMBANK_FAST16:
! 11246: put_word (addr, v);
! 11247: if ((addr & 3) == 3)
! 11248: do_cycles_c040_mem(2, v);
! 11249: else
! 11250: do_cycles_c040_mem(1, v);
! 11251: break;
! 11252: case CE_MEMBANK_FAST32:
! 11253: put_word (addr, v);
! 11254: break;
! 11255: default:
! 11256: put_word (addr, v);
! 11257: break;
! 11258: }
! 11259: }
! 11260:
! 11261: void mem_access_delay_long_write_c040 (uaecptr addr, uae_u32 v)
! 11262: {
! 11263: switch (ce_banktype[addr >> 16])
! 11264: {
! 11265: case CE_MEMBANK_CHIP16:
! 11266: wait_cpu_cycle_write_ce020 (addr + 0, 1, (v >> 16) & 0xffff);
! 11267: wait_cpu_cycle_write_ce020 (addr + 2, 1, (v >> 0) & 0xffff);
! 11268: break;
! 11269: case CE_MEMBANK_CHIP32:
! 11270: if ((addr & 3) == 3) {
! 11271: wait_cpu_cycle_write_ce020 (addr + 0, 1, (v >> 16) & 0xffff);
! 11272: wait_cpu_cycle_write_ce020 (addr + 2, 1, (v >> 0) & 0xffff);
! 11273: } else {
! 11274: wait_cpu_cycle_write_ce020 (addr + 0, -1, v);
! 11275: }
! 11276: break;
! 11277: case CE_MEMBANK_FAST16:
! 11278: put_long (addr, v);
! 11279: do_cycles_ce020_mem (2 * CPU020_MEM_CYCLE, v);
! 11280: break;
! 11281: case CE_MEMBANK_FAST32:
! 11282: put_long (addr, v);
! 11283: break;
! 11284: default:
! 11285: put_long (addr, v);
! 11286: break;
! 11287: }
! 11288: }
! 11289:
! 11290: static uae_u32 dcache040_get_data(uaecptr addr, struct cache040 *c, int line, int size)
1.1.1.7 root 11291: {
1.1.1.9 ! root 11292: static const uae_u32 mask[3] = { 0x000000ff, 0x0000ffff, 0xffffffff };
! 11293: int offset = (addr & 15) * 8;
! 11294: int offset32 = offset & 31;
! 11295: int slot = offset / 32;
! 11296: int width = 8 << size;
! 11297: uae_u32 vv;
! 11298:
! 11299: if (offset32 + width <= 32) {
! 11300: uae_u32 v = c->data[line][slot];
! 11301: v >>= 32 - (offset32 + width);
! 11302: v &= mask[size];
! 11303: vv = v;
! 11304: } else {
! 11305: #if VALIDATE_68040_DATACACHE
! 11306: if (slot >= 3) {
! 11307: write_log(_T("invalid dcache040_get_data!\n"));
! 11308: return 0;
1.1.1.7 root 11309: }
1.1.1.9 ! root 11310: #endif
! 11311: uae_u64 v = c->data[line][slot];
! 11312: v <<= 32;
! 11313: v |= c->data[line][slot + 1];
! 11314: v >>= 64 - (offset32 + width);
! 11315: vv = v & mask[size];
1.1.1.7 root 11316: }
1.1.1.9 ! root 11317: return vv;
! 11318: }
1.1.1.7 root 11319:
1.1.1.9 ! root 11320: static void dcache040_update(uaecptr addr, struct cache040 *c, int line, uae_u32 val, int size)
! 11321: {
! 11322: static const uae_u64 mask64[3] = { 0xff, 0xffff, 0xffffffff };
! 11323: static const uae_u32 mask32[3] = { 0xff, 0xffff, 0xffffffff };
! 11324: int offset = (addr & 15) * 8;
! 11325: int offset32 = offset & 31;
! 11326: int slot = offset / 32;
! 11327: int width = 8 << size;
! 11328:
! 11329: #if VALIDATE_68040_DATACACHE > 1
! 11330: validate_dcache040();
1.1.1.7 root 11331: #endif
1.1.1.9 ! root 11332:
! 11333: if (offset32 + width <= 32) {
! 11334: int shift = 32 - (offset32 + width);
! 11335: uae_u32 v = c->data[line][slot];
! 11336: v &= ~(mask32[size] << shift);
! 11337: v |= val << shift;
! 11338: c->data[line][slot] = v;
! 11339: c->dirty[line][slot] = true;
! 11340: } else {
! 11341: #if VALIDATE_68040_DATACACHE
! 11342: if (slot >= 3) {
! 11343: write_log(_T("invalid dcache040_update!\n"));
! 11344: return;
1.1.1.7 root 11345: }
1.1.1.9 ! root 11346: #endif
! 11347: int shift = 64 - (offset32 + width);
! 11348: uae_u64 v = c->data[line][slot];
! 11349: v <<= 32;
! 11350: v |= c->data[line][slot + 1];
! 11351: v &= ~(mask64[size] << shift);
! 11352: v |= ((uae_u64)val) << shift;
! 11353: c->data[line][slot] = v >> 32;
! 11354: c->dirty[line][slot] = true;
! 11355: c->data[line][slot + 1] = (uae_u32)v;
! 11356: c->dirty[line][slot + 1] = true;
1.1.1.7 root 11357: }
1.1.1.9 ! root 11358: c->gdirty[line] = true;
! 11359: }
! 11360:
! 11361: static int dcache040_fill_line(int index, uae_u32 tag, uaecptr addr)
! 11362: {
1.1.1.7 root 11363: // cache miss
1.1.1.9 ! root 11364: struct cache040 *c = &dcaches040[index];
! 11365: int line;
1.1.1.7 root 11366: if (c->valid[0] && c->valid[1] && c->valid[2] && c->valid[3]) {
1.1.1.9 ! root 11367: // all lines allocated, choose one, push and invalidate.
! 11368: line = dcachelinecnt & (CACHELINES040 - 1);
! 11369: dcachelinecnt++;
! 11370: dcache040_push_line(index, line, false, true);
! 11371: } else {
! 11372: // at least one invalid
1.1.1.7 root 11373: for (line = 0; line < CACHELINES040; line++) {
11374: if (c->valid[line] == false)
11375: break;
11376: }
11377: }
11378: c->tag[line] = tag;
1.1.1.9 ! root 11379: c->dirty[line][0] = false;
! 11380: c->dirty[line][1] = false;
! 11381: c->dirty[line][2] = false;
! 11382: c->dirty[line][3] = false;
! 11383: c->gdirty[line] = false;
! 11384: c->data[line][0] = dcache_lget(addr + 0);
! 11385: c->data[line][1] = dcache_lget(addr + 4);
! 11386: c->data[line][2] = dcache_lget(addr + 8);
! 11387: c->data[line][3] = dcache_lget(addr + 12);
1.1.1.7 root 11388: c->valid[line] = true;
1.1.1.9 ! root 11389: return line;
1.1.1.7 root 11390: }
11391:
1.1.1.9 ! root 11392: static uae_u32 read_dcache040_debug(uae_u32 addr, int size, bool *cached)
1.1.1.7 root 11393: {
1.1.1.9 ! root 11394: int index;
1.1.1.7 root 11395: uae_u32 tag;
11396: struct cache040 *c;
1.1.1.9 ! root 11397: int line;
! 11398: uae_u32 addr_o = addr;
! 11399: uae_u8 cs = mmu_cache_state;
! 11400:
! 11401: *cached = false;
! 11402: if (!currprefs.cpu_data_cache)
! 11403: goto nocache;
! 11404: if (!(regs.cacr & 0x80000000))
! 11405: goto nocache;
1.1.1.7 root 11406:
11407: addr &= ~15;
1.1.1.9 ! root 11408: index = (addr >> 4) & cachedsets04060mask;
! 11409: tag = addr & cachedtag04060mask;
1.1.1.7 root 11410: c = &dcaches040[index];
1.1.1.9 ! root 11411: for (line = 0; line < CACHELINES040; line++) {
! 11412: if (c->valid[line] && c->tag[line] == tag) {
! 11413: // cache hit
! 11414: return dcache040_get_data(addr_o, c, line, size);
1.1.1.7 root 11415: }
11416: }
1.1.1.9 ! root 11417: nocache:
! 11418: if (size == 0)
! 11419: return get_byte_debug(addr);
! 11420: if (size == 1)
! 11421: return get_word_debug(addr);
! 11422: return get_long_debug(addr);
1.1.1.7 root 11423: }
11424:
1.1.1.9 ! root 11425: static uae_u32 read_dcache040(uae_u32 addr, int size, uae_u32 (*fetch)(uaecptr))
1.1.1.7 root 11426: {
1.1.1.9 ! root 11427: int index;
1.1.1.7 root 11428: uae_u32 tag;
11429: struct cache040 *c;
11430: int line;
1.1.1.9 ! root 11431: uae_u32 addr_o = addr;
! 11432: uae_u8 cs = mmu_cache_state;
! 11433:
! 11434: if (!(regs.cacr & 0x80000000))
! 11435: goto nocache;
! 11436:
! 11437: #if VALIDATE_68040_DATACACHE > 1
! 11438: validate_dcache040();
! 11439: #endif
! 11440:
! 11441: // Simple because 68040+ caches physical addresses (68030 caches logical addresses)
! 11442: if (!(ce_cachable[addr >> 16] & CACHE_ENABLE_DATA))
! 11443: cs = CACHE_DISABLE_MMU;
1.1.1.7 root 11444:
11445: addr &= ~15;
1.1.1.9 ! root 11446: index = (addr >> 4) & cachedsets04060mask;
! 11447: tag = addr & cachedtag04060mask;
1.1.1.7 root 11448: c = &dcaches040[index];
1.1.1.9 ! root 11449: for (line = 0; line < CACHELINES040; line++) {
! 11450: if (c->valid[line] && c->tag[line] == tag) {
1.1.1.7 root 11451: // cache hit
11452: dcachelinecnt++;
1.1.1.9 ! root 11453: // Cache hit but MMU disabled: do not cache, push and invalidate possible existing line
! 11454: if (cs & CACHE_DISABLE_MMU) {
! 11455: dcache040_push_line(index, line, false, true);
! 11456: goto nocache;
1.1.1.7 root 11457: }
1.1.1.9 ! root 11458: return dcache040_get_data(addr_o, c, line, size);
1.1.1.7 root 11459: }
11460: }
1.1.1.9 ! root 11461: // Cache miss
! 11462: // 040+ always caches whole line
! 11463: if ((cs & CACHE_DISABLE_MMU) || !(cs & CACHE_ENABLE_DATA) || (cs & CACHE_DISABLE_ALLOCATE) || (regs.cacr & 0x400000000)) {
! 11464: nocache:
! 11465: return fetch(addr_o);
1.1.1.7 root 11466: }
1.1.1.9 ! root 11467: // Allocate new cache line, return requested data.
! 11468: line = dcache040_fill_line(index, tag, addr);
! 11469: return dcache040_get_data(addr_o, c, line, size);
1.1.1.7 root 11470: }
11471:
1.1.1.9 ! root 11472: static void write_dcache040(uae_u32 addr, uae_u32 val, int size, void (*store)(uaecptr, uae_u32))
1.1.1.7 root 11473: {
1.1.1.9 ! root 11474: static const uae_u32 mask[3] = { 0x000000ff, 0x0000ffff, 0xffffffff };
! 11475: int index;
1.1.1.7 root 11476: uae_u32 tag;
11477: struct cache040 *c;
11478: int line;
1.1.1.9 ! root 11479: uae_u32 addr_o = addr;
! 11480: uae_u8 cs = mmu_cache_state;
! 11481:
! 11482: val &= mask[size];
! 11483:
! 11484: if (!(regs.cacr & 0x80000000))
! 11485: goto nocache;
! 11486:
! 11487: if (!(ce_cachable[addr >> 16] & CACHE_ENABLE_DATA))
! 11488: cs = CACHE_DISABLE_MMU;
1.1.1.7 root 11489:
11490: addr &= ~15;
1.1.1.9 ! root 11491: index = (addr >> 4) & cachedsets04060mask;
! 11492: tag = addr & cachedtag04060mask;
1.1.1.7 root 11493: c = &dcaches040[index];
1.1.1.9 ! root 11494: for (line = 0; line < CACHELINES040; line++) {
! 11495: if (c->valid[line] && c->tag[line] == tag) {
1.1.1.7 root 11496: // cache hit
11497: dcachelinecnt++;
1.1.1.9 ! root 11498: // Cache hit but MMU disabled: do not cache, push and invalidate possible existing line
! 11499: if (cs & CACHE_DISABLE_MMU) {
! 11500: dcache040_push_line(index, line, false, true);
! 11501: goto nocache;
! 11502: }
! 11503: dcache040_update(addr_o, c, line, val, size);
! 11504: // If not copyback mode: push modifications immediately (write-through)
! 11505: if (!(cs & CACHE_ENABLE_COPYBACK) || DISABLE_68040_COPYBACK) {
! 11506: dcache040_push_line(index, line, true, false);
1.1.1.4 root 11507: }
1.1.1.9 ! root 11508: return;
1.1.1.4 root 11509: }
11510: }
1.1.1.9 ! root 11511: // Cache miss
! 11512: // 040+ always caches whole line
! 11513: // Writes misses in write-through mode don't allocate new cache lines
! 11514: if (!(cs & CACHE_ENABLE_DATA) || (cs & CACHE_DISABLE_MMU) || (cs & CACHE_DISABLE_ALLOCATE) || !(cs & CACHE_ENABLE_COPYBACK) || (regs.cacr & 0x400000000)) {
! 11515: nocache:
! 11516: store(addr_o, val);
! 11517: return;
! 11518: }
! 11519: // Allocate new cache line and update it with new data.
! 11520: line = dcache040_fill_line(index, tag, addr);
! 11521: dcache040_update(addr_o, c, line, val, size);
! 11522: if (DISABLE_68040_COPYBACK) {
! 11523: dcache040_push_line(index, line, true, false);
1.1.1.7 root 11524: }
11525: }
11526:
11527: // really unoptimized
11528: uae_u32 get_word_icache040(uaecptr addr)
11529: {
11530: uae_u32 v = fill_icache040(addr);
11531: return v >> ((addr & 2) ? 0 : 16);
11532: }
11533: uae_u32 get_long_icache040(uaecptr addr)
11534: {
11535: uae_u32 v1, v2;
11536: v1 = fill_icache040(addr);
11537: if ((addr & 2) == 0)
11538: return v1;
11539: v2 = fill_icache040(addr + 4);
11540: return (v2 >> 16) | (v1 << 16);
11541: }
11542: uae_u32 get_ilong_cache_040(int o)
11543: {
11544: return get_long_icache040(m68k_getpci() + o);
11545: }
11546: uae_u32 get_iword_cache_040(int o)
11547: {
11548: return get_word_icache040(m68k_getpci() + o);
11549: }
11550:
11551: void put_long_cache_040(uaecptr addr, uae_u32 v)
11552: {
1.1.1.9 ! root 11553: int offset = addr & 15;
! 11554: // access must not cross cachelines
! 11555: if (offset < 13) {
! 11556: write_dcache040(addr, v, 2, dcache_lput);
! 11557: } else if (offset == 13 || offset == 15) {
! 11558: write_dcache040(addr + 0, v >> 24, 0, dcache_bput);
! 11559: write_dcache040(addr + 1, v >> 8, 1, dcache_wput);
! 11560: write_dcache040(addr + 3, v >> 0, 0, dcache_bput);
! 11561: } else if (offset == 14) {
! 11562: write_dcache040(addr + 0, v >> 16, 1, dcache_wput);
! 11563: write_dcache040(addr + 2, v >> 0, 1, dcache_wput);
1.1.1.7 root 11564: }
11565: }
11566: void put_word_cache_040(uaecptr addr, uae_u32 v)
11567: {
1.1.1.9 ! root 11568: int offset = addr & 15;
! 11569: if (offset < 15) {
! 11570: write_dcache040(addr, v, 1, dcache_wput);
1.1.1.7 root 11571: } else {
1.1.1.9 ! root 11572: write_dcache040(addr + 0, v >> 8, 0, dcache_bput);
! 11573: write_dcache040(addr + 1, v >> 0, 0, dcache_bput);
1.1.1.7 root 11574: }
11575: }
11576: void put_byte_cache_040(uaecptr addr, uae_u32 v)
11577: {
1.1.1.9 ! root 11578: return write_dcache040(addr, v, 0, dcache_bput);
1.1.1.4 root 11579: }
11580:
1.1.1.7 root 11581: uae_u32 get_long_cache_040(uaecptr addr)
11582: {
1.1.1.9 ! root 11583: uae_u32 v;
! 11584: int offset = addr & 15;
! 11585: if (offset < 13) {
! 11586: v = read_dcache040(addr, 2, dcache_lget);
! 11587: } else if (offset == 13 || offset == 15) {
! 11588: v = read_dcache040(addr + 0, 0, dcache_bget) << 24;
! 11589: v |= read_dcache040(addr + 1, 1, dcache_wget) << 8;
! 11590: v |= read_dcache040(addr + 3, 0, dcache_bget) << 0;
! 11591: } else if (offset == 14) {
! 11592: v = read_dcache040(addr + 0, 1, dcache_wget) << 16;
! 11593: v |= read_dcache040(addr + 2, 1, dcache_wget) << 0;
! 11594: }
! 11595: return v;
1.1.1.7 root 11596: }
11597: uae_u32 get_word_cache_040(uaecptr addr)
11598: {
1.1.1.9 ! root 11599: uae_u32 v;
! 11600: int offset = addr & 15;
! 11601: if (offset < 15) {
! 11602: v = read_dcache040(addr, 1, dcache_wget);
! 11603: } else {
! 11604: v = read_dcache040(addr + 0, 0, dcache_bget) << 8;
! 11605: v |= read_dcache040(addr + 1, 0, dcache_bget) << 0;
! 11606: }
! 11607: return v;
1.1.1.7 root 11608: }
11609: uae_u32 get_byte_cache_040(uaecptr addr)
11610: {
1.1.1.9 ! root 11611: return read_dcache040(addr, 0, dcache_bget);
1.1.1.7 root 11612: }
11613: uae_u32 next_iword_cache040(void)
11614: {
11615: uae_u32 r = get_word_icache040(m68k_getpci());
11616: m68k_incpci(2);
11617: return r;
11618: }
11619: uae_u32 next_ilong_cache040(void)
11620: {
11621: uae_u32 r = get_long_icache040(m68k_getpci());
11622: m68k_incpci(4);
11623: return r;
11624: }
1.1.1.4 root 11625:
1.1.1.9 ! root 11626: uae_u32 get_byte_cache_debug(uaecptr addr, bool *cached)
1.1.1.4 root 11627: {
1.1.1.9 ! root 11628: *cached = false;
! 11629: if (currprefs.cpu_model == 68030) {
! 11630: return read_dcache030_debug(addr, 0, regs.s ? 5 : 1, cached);
! 11631: } else if (currprefs.cpu_model >= 68040) {
! 11632: return read_dcache040_debug(addr, 0, cached);
! 11633: }
! 11634: return get_byte_debug(addr);
! 11635: }
! 11636: uae_u32 get_word_cache_debug(uaecptr addr, bool *cached)
! 11637: {
! 11638: *cached = false;
! 11639: if (currprefs.cpu_model == 68030) {
! 11640: return read_dcache030_debug(addr, 1, regs.s ? 5 : 1, cached);
! 11641: } else if (currprefs.cpu_model >= 68040) {
! 11642: return read_dcache040_debug(addr, 1, cached);
1.1.1.4 root 11643: }
1.1.1.9 ! root 11644: return get_word_debug(addr);
1.1.1.4 root 11645: }
11646:
1.1.1.9 ! root 11647: uae_u32 get_long_cache_debug(uaecptr addr, bool *cached)
1.1.1.4 root 11648: {
1.1.1.9 ! root 11649: *cached = false;
! 11650: if (currprefs.cpu_model == 68030) {
! 11651: return read_dcache030_debug(addr, 2, regs.s ? 5 : 1, cached);
! 11652: } else if (currprefs.cpu_model >= 68040) {
! 11653: return read_dcache040_debug(addr, 2, cached);
1.1.1.7 root 11654: }
1.1.1.9 ! root 11655: return get_long_debug(addr);
! 11656: }
! 11657:
! 11658: void check_t0_trace(void)
! 11659: {
! 11660: if (regs.t0 && currprefs.cpu_model >= 68020) {
! 11661: unset_special (SPCFLAG_TRACE);
! 11662: set_special (SPCFLAG_DOTRACE);
1.1.1.7 root 11663: }
1.1.1.9 ! root 11664: }
! 11665:
! 11666: static void reset_pipeline_state(void)
! 11667: {
! 11668: #if MORE_ACCURATE_68020_PIPELINE
! 11669: regs.pipeline_pos = 0;
! 11670: regs.pipeline_stop = 0;
! 11671: regs.pipeline_r8[0] = regs.pipeline_r8[1] = -1;
! 11672: #endif
! 11673: }
! 11674:
! 11675: static int add_prefetch_030(int idx, uae_u16 w, uaecptr pc)
! 11676: {
! 11677: regs.prefetch020[0] = regs.prefetch020[1];
! 11678: regs.prefetch020_valid[0] = regs.prefetch020_valid[1];
! 11679: regs.prefetch020[1] = regs.prefetch020[2];
! 11680: regs.prefetch020_valid[1] = regs.prefetch020_valid[2];
! 11681: regs.prefetch020[2] = w;
! 11682: regs.prefetch020_valid[2] = regs.cacheholdingdata_valid;
! 11683:
! 11684: #if MORE_ACCURATE_68020_PIPELINE
! 11685: if (idx >= 1) {
! 11686: pipeline_020(pc);
! 11687: }
! 11688: #endif
! 11689:
! 11690: if (!regs.prefetch020_valid[2]) {
! 11691: if (idx == 0 || !regs.pipeline_stop) {
! 11692: // Pipeline refill and first opcode word is invalid?
! 11693: // Generate previously detected bus error/MMU fault
! 11694: do_access_or_bus_error(pc, pc + idx * 2);
1.1.1.7 root 11695: }
11696: }
1.1.1.9 ! root 11697: return idx + 1;
1.1.1.4 root 11698: }
11699:
1.1.1.9 ! root 11700: void fill_prefetch_030_ntx(void)
1.1.1.4 root 11701: {
1.1.1.9 ! root 11702: //fprintf ( stderr , "fill_prefetch_030_ntx %d\n" , currcycle);
1.1.1.7 root 11703: uaecptr pc = m68k_getpc ();
11704: uaecptr pc2 = pc;
1.1.1.9 ! root 11705: int idx = 0;
! 11706:
1.1.1.7 root 11707: pc &= ~3;
1.1.1.9 ! root 11708: mmu030_idx = 0;
! 11709: reset_pipeline_state();
! 11710: regs.cacheholdingdata_valid = 1;
! 11711: regs.cacheholdingaddr020 = 0xffffffff;
! 11712: regs.prefetch020_valid[0] = regs.prefetch020_valid[1] = regs.prefetch020_valid[2] = 0;
1.1.1.4 root 11713:
1.1.1.9 ! root 11714: fill_icache030(pc);
1.1.1.7 root 11715: if (currprefs.cpu_cycle_exact)
11716: do_cycles_ce020_internal(2);
1.1.1.9 ! root 11717: if (pc2 & 2) {
! 11718: idx = add_prefetch_030(idx, regs.cacheholdingdata020, pc2);
! 11719: } else {
! 11720: idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc2);
! 11721: idx = add_prefetch_030(idx, regs.cacheholdingdata020, pc2);
! 11722: }
1.1.1.7 root 11723:
1.1.1.9 ! root 11724: fill_icache030(pc + 4);
1.1.1.7 root 11725: if (currprefs.cpu_cycle_exact)
11726: do_cycles_ce020_internal(2);
11727: if (pc2 & 2) {
1.1.1.9 ! root 11728: idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc2);
! 11729: idx = add_prefetch_030(idx, regs.cacheholdingdata020, pc2);
1.1.1.7 root 11730: } else {
1.1.1.9 ! root 11731: idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc2);
1.1.1.4 root 11732: }
1.1.1.9 ! root 11733:
! 11734: if (currprefs.cpu_cycle_exact)
! 11735: regs.irc = get_word_ce030_prefetch_opcode (0);
! 11736: else
! 11737: regs.irc = get_word_030_prefetch (0);
! 11738: }
! 11739:
! 11740: void fill_prefetch_030_ntx_continue (void)
! 11741: {
! 11742: uaecptr pc = m68k_getpc ();
! 11743: uaecptr pc_orig = pc;
! 11744: int idx = 0;
! 11745: int i;
! 11746:
! 11747: mmu030_idx = 0;
! 11748: reset_pipeline_state();
! 11749: regs.cacheholdingdata_valid = 1;
! 11750: regs.cacheholdingaddr020 = 0xffffffff;
! 11751:
! 11752: for (i = 2; i >= 0; i--) {
! 11753: if (!regs.prefetch020_valid[i])
! 11754: break;
! 11755: #if MORE_ACCURATE_68020_PIPELINE
! 11756: if (idx >= 1) {
! 11757: pipeline_020(pc);
! 11758: }
1.1.1.7 root 11759: #endif
1.1.1.9 ! root 11760: pc += 2;
! 11761: idx++;
! 11762: }
! 11763:
! 11764: if (idx < 3 && !regs.pipeline_stop) {
! 11765: uaecptr pc2 = pc;
! 11766: pc &= ~3;
! 11767:
! 11768: fill_icache030(pc);
! 11769: if (currprefs.cpu_cycle_exact)
! 11770: do_cycles_ce020_internal(2);
! 11771: if (pc2 & 2) {
! 11772: idx = add_prefetch_030(idx, regs.cacheholdingdata020, pc_orig);
! 11773: } else {
! 11774: idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc_orig);
! 11775: if (idx < 3)
! 11776: idx = add_prefetch_030(idx, regs.cacheholdingdata020, pc_orig);
! 11777: }
! 11778:
! 11779: if (idx < 3) {
! 11780: fill_icache030(pc + 4);
! 11781: if (currprefs.cpu_cycle_exact)
! 11782: do_cycles_ce020_internal(2);
! 11783: if (pc2 & 2) {
! 11784: idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc_orig);
! 11785: if (idx < 3)
! 11786: idx = add_prefetch_030(idx, regs.cacheholdingdata020, pc_orig);
! 11787: } else {
! 11788: idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc_orig);
! 11789: }
! 11790: }
! 11791: }
1.1.1.4 root 11792:
1.1.1.7 root 11793: if (currprefs.cpu_cycle_exact)
1.1.1.9 ! root 11794: regs.irc = get_word_ce030_prefetch_opcode (0);
1.1.1.7 root 11795: else
1.1.1.9 ! root 11796: regs.irc = get_word_030_prefetch (0);
! 11797: //fprintf ( stderr , "fill_prefetch_030_ntx4 %d\n" , currcycle);
1.1.1.4 root 11798: }
11799:
1.1.1.9 ! root 11800: void fill_prefetch_020_ntx(void)
1.1.1.4 root 11801: {
1.1.1.7 root 11802: uaecptr pc = m68k_getpc ();
11803: uaecptr pc2 = pc;
1.1.1.9 ! root 11804: int idx = 0;
! 11805:
1.1.1.7 root 11806: pc &= ~3;
1.1.1.9 ! root 11807: reset_pipeline_state();
1.1.1.7 root 11808:
1.1.1.9 ! root 11809: fill_icache020 (pc, true);
1.1.1.7 root 11810: if (currprefs.cpu_cycle_exact)
11811: do_cycles_ce020_internal(2);
1.1.1.9 ! root 11812: if (pc2 & 2) {
! 11813: idx = add_prefetch_030(idx, regs.cacheholdingdata020, pc);
! 11814: } else {
! 11815: idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc);
! 11816: idx = add_prefetch_030(idx, regs.cacheholdingdata020, pc);
! 11817: }
1.1.1.7 root 11818:
1.1.1.9 ! root 11819: fill_icache020 (pc + 4, true);
1.1.1.7 root 11820: if (currprefs.cpu_cycle_exact)
11821: do_cycles_ce020_internal(2);
11822: if (pc2 & 2) {
1.1.1.9 ! root 11823: idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc);
! 11824: idx = add_prefetch_030(idx, regs.cacheholdingdata020, pc);
1.1.1.7 root 11825: } else {
1.1.1.9 ! root 11826: idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc);
1.1.1.7 root 11827: }
11828:
11829: if (currprefs.cpu_cycle_exact)
1.1.1.9 ! root 11830: regs.irc = get_word_ce020_prefetch_opcode (0);
1.1.1.7 root 11831: else
11832: regs.irc = get_word_020_prefetch (0);
1.1.1.4 root 11833: }
11834:
1.1.1.9 ! root 11835: // Not exactly right, requires logic analyzer checks.
! 11836: void continue_ce020_prefetch(void)
! 11837: {
! 11838: fill_prefetch_020_ntx();
! 11839: }
! 11840: void continue_020_prefetch(void)
! 11841: {
! 11842: fill_prefetch_020_ntx();
! 11843: }
! 11844:
! 11845: void continue_ce030_prefetch(void)
! 11846: {
! 11847: fill_prefetch_030_ntx();
! 11848: }
! 11849: void continue_030_prefetch(void)
! 11850: {
! 11851: fill_prefetch_030_ntx();
! 11852: }
! 11853:
! 11854: void fill_prefetch_020(void)
! 11855: {
! 11856: fill_prefetch_020_ntx();
! 11857: check_t0_trace();
! 11858: }
! 11859:
! 11860: void fill_prefetch_030(void)
! 11861: {
! 11862: fill_prefetch_030_ntx();
! 11863: check_t0_trace();
! 11864: }
! 11865:
! 11866:
1.1.1.7 root 11867: void fill_prefetch (void)
1.1.1.4 root 11868: {
1.1.1.9 ! root 11869: reset_pipeline_state();
1.1.1.7 root 11870: if (currprefs.cachesize)
11871: return;
11872: if (!currprefs.cpu_compatible)
11873: return;
11874: if (currprefs.cpu_model >= 68040) {
1.1.1.8 root 11875: if (currprefs.cpu_compatible || currprefs.cpu_memory_cycle_exact) {
1.1.1.7 root 11876: fill_icache040(m68k_getpc() + 16);
11877: fill_icache040(m68k_getpc());
11878: }
11879: } else if (currprefs.cpu_model == 68020) {
11880: fill_prefetch_020 ();
11881: } else if (currprefs.cpu_model == 68030) {
11882: fill_prefetch_030 ();
11883: } else if (currprefs.cpu_model <= 68010) {
11884: uaecptr pc = m68k_getpc ();
11885: regs.ir = x_get_word (pc);
11886: regs.irc = x_get_word (pc + 2);
11887: }
1.1.1.4 root 11888: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.