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
11 #define EXCEPTION3_DEBUGGER 0
12 #define CPUTRACE_DEBUG 0
13
14 #define VALIDATE_68030_DATACACHE 0
15 #define VALIDATE_68040_DATACACHE 0
16 #define DISABLE_68040_COPYBACK 0
17
18 #define MORE_ACCURATE_68020_PIPELINE 1
19
20 #include <inttypes.h> /* Needed for PRIX64 */
21
22 #include "main.h"
23 #include "compat.h"
24
25 #include "sysconfig.h"
26 #include "sysdeps.h"
27
28 #include "hatari-glue.h"
29
30 #include "options_cpu.h"
31 #include "events.h"
32 #include "memory.h"
33 #include "custom.h"
34 #include "newcpu.h"
35 #include "cpummu.h"
36 #include "cpummu030.h"
37 #include "cpu_prefetch.h"
38 #include "debugmem.h"
39 #include "savestate.h"
40 #include "fpp.h"
41
42 #ifdef WINUAE_FOR_HATARI
43 #include "debug.h"
44 #include "m68000.h"
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"
61 #include "stMemory.h"
62 #include "blitter.h"
63 #endif
64
65
66 #ifdef JIT
67 #include "jit/compemu.h"
68 #include <signal.h>
69 #else
70 /* Need to have these somewhere */
71 //#ifndef WINUAE_FOR_HATARI
check_prefs_changed_comp(bool checkonly)72 bool check_prefs_changed_comp (bool checkonly) { return false; }
73 //#endif
74 #endif
75
76 /* Opcode of faulting instruction */
77 static uae_u16 last_op_for_exception_3;
78 /* PC at fault time */
79 static uaecptr last_addr_for_exception_3;
80 /* Address that generated the exception */
81 static uaecptr last_fault_for_exception_3;
82 /* read (0) or write (1) access */
83 static bool last_writeaccess_for_exception_3;
84 /* instruction (1) or data (0) access */
85 static bool last_instructionaccess_for_exception_3;
86 /* not instruction */
87 static bool last_notinstruction_for_exception_3;
88 /* set when writing exception stack frame */
89 static int exception_in_exception;
90
91 int mmu_enabled, mmu_triggered;
92 int cpu_cycles;
93 int bus_error_offset;
94 #ifndef WINUAE_FOR_HATARI
95 static int baseclock;
96 #endif
97 int m68k_pc_indirect;
98 bool m68k_interrupt_delay;
99 static bool m68k_reset_delay;
100
101 #ifndef WINUAE_FOR_HATARI
102 static volatile uae_atomic uae_interrupt;
103 static volatile uae_atomic uae_interrupts2[IRQ_SOURCE_MAX];
104 static volatile uae_atomic uae_interrupts6[IRQ_SOURCE_MAX];
105 #endif
106
107 static int cacheisets04060, cacheisets04060mask, cacheitag04060mask;
108 static int cachedsets04060, cachedsets04060mask, cachedtag04060mask;
109
110 static int cpu_prefs_changed_flag;
111
112 int cpucycleunit;
113 int cpu_tracer;
114
115 const int areg_byteinc[] = { 1, 1, 1, 1, 1, 1, 1, 2 };
116 const int imm8_table[] = { 8, 1, 2, 3, 4, 5, 6, 7 };
117
118 int movem_index1[256];
119 int movem_index2[256];
120 int movem_next[256];
121
122 cpuop_func *cpufunctbl[65536];
123
124 struct cputbl_data
125 {
126 uae_s16 length;
127 uae_s8 disp020[2];
128 uae_u8 branch;
129 };
130 static struct cputbl_data cpudatatbl[65536];
131
132 struct mmufixup mmufixup[2];
133
134 #define COUNT_INSTRS 0
135 #define MC68060_PCR 0x04300000
136 #define MC68EC060_PCR 0x04310000
137
138 static uae_u64 fake_srp_030, fake_crp_030;
139 static uae_u32 fake_tt0_030, fake_tt1_030, fake_tc_030;
140 static uae_u16 fake_mmusr_030;
141
142 static struct cache020 caches020[CACHELINES020];
143 static struct cache030 icaches030[CACHELINES030];
144 static struct cache030 dcaches030[CACHELINES030];
145 static int icachelinecnt, icachehalfline;
146 static int dcachelinecnt;
147 static struct cache040 icaches040[CACHESETS060];
148 static struct cache040 dcaches040[CACHESETS060];
149 static int cache_lastline;
150
151 static int fallback_cpu_model, fallback_mmu_model, fallback_fpu_model;
152 static bool fallback_cpu_compatible, fallback_cpu_address_space_24;
153 static struct regstruct fallback_regs;
154 static int fallback_new_cpu_model;
155
156 #ifdef WINUAE_FOR_HATARI
157 int OpcodeFamily;
158 int BusCyclePenalty = 0;
159
160 FILE *console_out_FILE = NULL;
161
162 int quit_program = 0; /* from main.cpp */
163 #endif
164
165
166 #if COUNT_INSTRS
167 static unsigned long int instrcount[65536];
168 static uae_u16 opcodenums[65536];
169
compfn(const void * el1,const void * el2)170 static int compfn (const void *el1, const void *el2)
171 {
172 return instrcount[*(const uae_u16 *)el1] < instrcount[*(const uae_u16 *)el2];
173 }
174
icountfilename(void)175 static TCHAR *icountfilename (void)
176 {
177 TCHAR *name = getenv ("INSNCOUNT");
178 if (name)
179 return name;
180 return COUNT_INSTRS == 2 ? "frequent.68k" : "insncount";
181 }
182
dump_counts(void)183 void dump_counts (void)
184 {
185 FILE *f = fopen (icountfilename (), "w");
186 unsigned long int total;
187 int i;
188
189 write_log (_T("Writing instruction count file...\n"));
190 for (i = 0; i < 65536; i++) {
191 opcodenums[i] = i;
192 total += instrcount[i];
193 }
194 qsort (opcodenums, 65536, sizeof (uae_u16), compfn);
195
196 fprintf (f, "Total: %lu\n", total);
197 for (i=0; i < 65536; i++) {
198 unsigned long int cnt = instrcount[opcodenums[i]];
199 struct instr *dp;
200 struct mnemolookup *lookup;
201 if (!cnt)
202 break;
203 dp = table68k + opcodenums[i];
204 for (lookup = lookuptab;lookup->mnemo != dp->mnemo; lookup++)
205 ;
206 fprintf (f, "%04x: %lu %s\n", opcodenums[i], cnt, lookup->name);
207 }
208 fclose (f);
209 }
210 #else
dump_counts(void)211 void dump_counts (void)
212 {
213 }
214 #endif
215
216 /*
217
218 ok, all this to "record" current instruction state
219 for later 100% cycle-exact restoring
220
221 */
222
223 static uae_u32 (*x2_prefetch)(int);
224 static uae_u32 (*x2_prefetch_long)(int);
225 static uae_u32 (*x2_next_iword)(void);
226 static uae_u32 (*x2_next_ilong)(void);
227 static uae_u32 (*x2_get_ilong)(int);
228 static uae_u32 (*x2_get_iword)(int);
229 static uae_u32 (*x2_get_ibyte)(int);
230 static uae_u32 (*x2_get_long)(uaecptr);
231 static uae_u32 (*x2_get_word)(uaecptr);
232 static uae_u32 (*x2_get_byte)(uaecptr);
233 static void (*x2_put_long)(uaecptr,uae_u32);
234 static void (*x2_put_word)(uaecptr,uae_u32);
235 static void (*x2_put_byte)(uaecptr,uae_u32);
236 static void (*x2_do_cycles)(unsigned long);
237 static void (*x2_do_cycles_pre)(unsigned long);
238 static void (*x2_do_cycles_post)(unsigned long, uae_u32);
239
240 uae_u32 (*x_prefetch)(int);
241 uae_u32 (*x_next_iword)(void);
242 uae_u32 (*x_next_ilong)(void);
243 uae_u32 (*x_get_ilong)(int);
244 uae_u32 (*x_get_iword)(int);
245 uae_u32 (*x_get_ibyte)(int);
246 uae_u32 (*x_get_long)(uaecptr);
247 uae_u32 (*x_get_word)(uaecptr);
248 uae_u32 (*x_get_byte)(uaecptr);
249 void (*x_put_long)(uaecptr,uae_u32);
250 void (*x_put_word)(uaecptr,uae_u32);
251 void (*x_put_byte)(uaecptr,uae_u32);
252
253 uae_u32 (*x_cp_next_iword)(void);
254 uae_u32 (*x_cp_next_ilong)(void);
255 uae_u32 (*x_cp_get_long)(uaecptr);
256 uae_u32 (*x_cp_get_word)(uaecptr);
257 uae_u32 (*x_cp_get_byte)(uaecptr);
258 void (*x_cp_put_long)(uaecptr,uae_u32);
259 void (*x_cp_put_word)(uaecptr,uae_u32);
260 void (*x_cp_put_byte)(uaecptr,uae_u32);
261 uae_u32 (REGPARAM3 *x_cp_get_disp_ea_020)(uae_u32 base, int idx) REGPARAM;
262
263 void (*x_do_cycles)(unsigned long);
264 void (*x_do_cycles_pre)(unsigned long);
265 void (*x_do_cycles_post)(unsigned long, uae_u32);
266
267 uae_u32(*x_phys_get_iword)(uaecptr);
268 uae_u32(*x_phys_get_ilong)(uaecptr);
269 uae_u32(*x_phys_get_byte)(uaecptr);
270 uae_u32(*x_phys_get_word)(uaecptr);
271 uae_u32(*x_phys_get_long)(uaecptr);
272 void(*x_phys_put_byte)(uaecptr, uae_u32);
273 void(*x_phys_put_word)(uaecptr, uae_u32);
274 void(*x_phys_put_long)(uaecptr, uae_u32);
275
set_x_cp_funcs(void)276 static void set_x_cp_funcs(void)
277 {
278 x_cp_put_long = x_put_long;
279 x_cp_put_word = x_put_word;
280 x_cp_put_byte = x_put_byte;
281 x_cp_get_long = x_get_long;
282 x_cp_get_word = x_get_word;
283 x_cp_get_byte = x_get_byte;
284 x_cp_next_iword = x_next_iword;
285 x_cp_next_ilong = x_next_ilong;
286 x_cp_get_disp_ea_020 = x_get_disp_ea_020;
287
288 if (currprefs.mmu_model == 68030) {
289 if (currprefs.cpu_compatible) {
290 x_cp_put_long = put_long_mmu030c_state;
291 x_cp_put_word = put_word_mmu030c_state;
292 x_cp_put_byte = put_byte_mmu030c_state;
293 x_cp_get_long = get_long_mmu030c_state;
294 x_cp_get_word = get_word_mmu030c_state;
295 x_cp_get_byte = get_byte_mmu030c_state;
296 x_cp_next_iword = next_iword_mmu030c_state;
297 x_cp_next_ilong = next_ilong_mmu030c_state;
298 x_cp_get_disp_ea_020 = get_disp_ea_020_mmu030c;
299 } else {
300 x_cp_put_long = put_long_mmu030_state;
301 x_cp_put_word = put_word_mmu030_state;
302 x_cp_put_byte = put_byte_mmu030_state;
303 x_cp_get_long = get_long_mmu030_state;
304 x_cp_get_word = get_word_mmu030_state;
305 x_cp_get_byte = get_byte_mmu030_state;
306 x_cp_next_iword = next_iword_mmu030_state;
307 x_cp_next_ilong = next_ilong_mmu030_state;
308 x_cp_get_disp_ea_020 = get_disp_ea_020_mmu030;
309 }
310 }
311 }
312
313 static struct cputracestruct cputrace;
314
315 #if CPUTRACE_DEBUG
validate_trace(void)316 static void validate_trace (void)
317 {
318 for (int i = 0; i < cputrace.memoryoffset; i++) {
319 struct cputracememory *ctm = &cputrace.ctm[i];
320 if (ctm->data == 0xdeadf00d) {
321 write_log (_T("unfinished write operation %d %08x\n"), i, ctm->addr);
322 }
323 }
324 }
325 #endif
326
debug_trace(void)327 static void debug_trace (void)
328 {
329 if (cputrace.writecounter > 10000 || cputrace.readcounter > 10000)
330 write_log (_T("cputrace.readcounter=%d cputrace.writecounter=%d\n"), cputrace.readcounter, cputrace.writecounter);
331 }
332
clear_trace(void)333 STATIC_INLINE void clear_trace (void)
334 {
335 #if CPUTRACE_DEBUG
336 validate_trace ();
337 #endif
338 if (cputrace.memoryoffset == MAX_CPUTRACESIZE)
339 return;
340 struct cputracememory *ctm = &cputrace.ctm[cputrace.memoryoffset++];
341 if (cputrace.memoryoffset == MAX_CPUTRACESIZE) {
342 write_log(_T("CPUTRACE overflow, stopping tracing.\n"));
343 return;
344 }
345 ctm->mode = 0;
346 cputrace.cyclecounter = 0;
347 cputrace.cyclecounter_pre = cputrace.cyclecounter_post = 0;
348 }
set_trace(uaecptr addr,int accessmode,int size)349 static void set_trace (uaecptr addr, int accessmode, int size)
350 {
351 #if CPUTRACE_DEBUG
352 validate_trace ();
353 #endif
354 if (cputrace.memoryoffset == MAX_CPUTRACESIZE)
355 return;
356 struct cputracememory *ctm = &cputrace.ctm[cputrace.memoryoffset++];
357 if (cputrace.memoryoffset == MAX_CPUTRACESIZE) {
358 write_log(_T("CPUTRACE overflow, stopping tracing.\n"));
359 return;
360 }
361 ctm->addr = addr;
362 ctm->data = 0xdeadf00d;
363 ctm->mode = accessmode | (size << 4);
364 cputrace.cyclecounter_pre = -1;
365 if (accessmode == 1)
366 cputrace.writecounter++;
367 else
368 cputrace.readcounter++;
369 debug_trace ();
370 }
add_trace(uaecptr addr,uae_u32 val,int accessmode,int size)371 static void add_trace (uaecptr addr, uae_u32 val, int accessmode, int size)
372 {
373 if (cputrace.memoryoffset < 1) {
374 #if CPUTRACE_DEBUG
375 write_log (_T("add_trace memoryoffset=%d!\n"), cputrace.memoryoffset);
376 #endif
377 return;
378 }
379 int mode = accessmode | (size << 4);
380 struct cputracememory *ctm = &cputrace.ctm[cputrace.memoryoffset - 1];
381 ctm->addr = addr;
382 ctm->data = val;
383 if (!ctm->mode) {
384 ctm->mode = mode;
385 if (accessmode == 1)
386 cputrace.writecounter++;
387 else
388 cputrace.readcounter++;
389 }
390 debug_trace ();
391 cputrace.cyclecounter_pre = cputrace.cyclecounter_post = 0;
392 }
393
394
check_trace2(void)395 static void check_trace2 (void)
396 {
397 if (cputrace.readcounter || cputrace.writecounter ||
398 cputrace.cyclecounter || cputrace.cyclecounter_pre || cputrace.cyclecounter_post)
399 write_log (_T("CPU tracer invalid state during playback!\n"));
400 }
401
check_trace(void)402 static bool check_trace (void)
403 {
404 if (!cpu_tracer)
405 return true;
406 if (!cputrace.readcounter && !cputrace.writecounter && !cputrace.cyclecounter) {
407 if (cpu_tracer != -2) {
408 write_log (_T("CPU trace: dma_cycle() enabled. %08x %08x NOW=%08lx\n"),
409 cputrace.cyclecounter_pre, cputrace.cyclecounter_post, get_cycles ());
410 cpu_tracer = -2; // dma_cycle() allowed to work now
411 }
412 }
413 if (cputrace.readcounter || cputrace.writecounter ||
414 cputrace.cyclecounter || cputrace.cyclecounter_pre || cputrace.cyclecounter_post)
415 return false;
416 x_prefetch = x2_prefetch;
417 x_get_ilong = x2_get_ilong;
418 x_get_iword = x2_get_iword;
419 x_get_ibyte = x2_get_ibyte;
420 x_next_iword = x2_next_iword;
421 x_next_ilong = x2_next_ilong;
422 x_put_long = x2_put_long;
423 x_put_word = x2_put_word;
424 x_put_byte = x2_put_byte;
425 x_get_long = x2_get_long;
426 x_get_word = x2_get_word;
427 x_get_byte = x2_get_byte;
428 x_do_cycles = x2_do_cycles;
429 x_do_cycles_pre = x2_do_cycles_pre;
430 x_do_cycles_post = x2_do_cycles_post;
431 set_x_cp_funcs();
432 write_log (_T("CPU tracer playback complete. STARTCYCLES=%08x NOWCYCLES=%08lx\n"), cputrace.startcycles, get_cycles ());
433 cputrace.needendcycles = 1;
434 cpu_tracer = 0;
435 return true;
436 }
437
get_trace(uaecptr addr,int accessmode,int size,uae_u32 * data)438 static bool get_trace (uaecptr addr, int accessmode, int size, uae_u32 *data)
439 {
440 int mode = accessmode | (size << 4);
441 for (int i = 0; i < cputrace.memoryoffset; i++) {
442 struct cputracememory *ctm = &cputrace.ctm[i];
443 if (ctm->addr == addr && ctm->mode == mode) {
444 ctm->mode = 0;
445 write_log (_T("CPU trace: GET %d: PC=%08x %08x=%08x %d %d %08x/%08x/%08x %d/%d (%08lx)\n"),
446 i, cputrace.pc, addr, ctm->data, accessmode, size,
447 cputrace.cyclecounter, cputrace.cyclecounter_pre, cputrace.cyclecounter_post,
448 cputrace.readcounter, cputrace.writecounter, get_cycles ());
449 if (accessmode == 1)
450 cputrace.writecounter--;
451 else
452 cputrace.readcounter--;
453 if (cputrace.writecounter == 0 && cputrace.readcounter == 0) {
454 if (cputrace.cyclecounter_post) {
455 int c = cputrace.cyclecounter_post;
456 cputrace.cyclecounter_post = 0;
457 x_do_cycles (c);
458 } else if (cputrace.cyclecounter_pre) {
459 check_trace ();
460 *data = ctm->data;
461 return true; // argh, need to rerun the memory access..
462 }
463 }
464 check_trace ();
465 *data = ctm->data;
466 return false;
467 }
468 }
469 if (cputrace.cyclecounter_post) {
470 int c = cputrace.cyclecounter_post;
471 cputrace.cyclecounter_post = 0;
472 check_trace ();
473 check_trace2 ();
474 x_do_cycles (c);
475 return false;
476 }
477 gui_message (_T("CPU trace: GET %08x %d %d NOT FOUND!\n"), addr, accessmode, size);
478 check_trace ();
479 *data = 0;
480 return false;
481 }
482
cputracefunc_x_prefetch(int o)483 static uae_u32 cputracefunc_x_prefetch (int o)
484 {
485 uae_u32 pc = m68k_getpc ();
486 set_trace (pc + o, 2, 2);
487 uae_u32 v = x2_prefetch (o);
488 add_trace (pc + o, v, 2, 2);
489 return v;
490 }
cputracefunc2_x_prefetch(int o)491 static uae_u32 cputracefunc2_x_prefetch (int o)
492 {
493 uae_u32 v;
494 if (get_trace (m68k_getpc () + o, 2, 2, &v)) {
495 v = x2_prefetch (o);
496 check_trace2 ();
497 }
498 return v;
499 }
500
cputracefunc_x_next_iword(void)501 static uae_u32 cputracefunc_x_next_iword (void)
502 {
503 uae_u32 pc = m68k_getpc ();
504 set_trace (pc, 2, 2);
505 uae_u32 v = x2_next_iword ();
506 add_trace (pc, v, 2, 2);
507 return v;
508 }
cputracefunc_x_next_ilong(void)509 static uae_u32 cputracefunc_x_next_ilong (void)
510 {
511 uae_u32 pc = m68k_getpc ();
512 set_trace (pc, 2, 4);
513 uae_u32 v = x2_next_ilong ();
514 add_trace (pc, v, 2, 4);
515 return v;
516 }
cputracefunc2_x_next_iword(void)517 static uae_u32 cputracefunc2_x_next_iword (void)
518 {
519 uae_u32 v;
520 if (get_trace (m68k_getpc (), 2, 2, &v)) {
521 v = x2_next_iword ();
522 check_trace2 ();
523 }
524 return v;
525 }
cputracefunc2_x_next_ilong(void)526 static uae_u32 cputracefunc2_x_next_ilong (void)
527 {
528 uae_u32 v;
529 if (get_trace (m68k_getpc (), 2, 4, &v)) {
530 v = x2_next_ilong ();
531 check_trace2 ();
532 }
533 return v;
534 }
535
cputracefunc_x_get_ilong(int o)536 static uae_u32 cputracefunc_x_get_ilong (int o)
537 {
538 uae_u32 pc = m68k_getpc ();
539 set_trace (pc + o, 2, 4);
540 uae_u32 v = x2_get_ilong (o);
541 add_trace (pc + o, v, 2, 4);
542 return v;
543 }
cputracefunc_x_get_iword(int o)544 static uae_u32 cputracefunc_x_get_iword (int o)
545 {
546 uae_u32 pc = m68k_getpc ();
547 set_trace (pc + o, 2, 2);
548 uae_u32 v = x2_get_iword (o);
549 add_trace (pc + o, v, 2, 2);
550 return v;
551 }
cputracefunc_x_get_ibyte(int o)552 static uae_u32 cputracefunc_x_get_ibyte (int o)
553 {
554 uae_u32 pc = m68k_getpc ();
555 set_trace (pc + o, 2, 1);
556 uae_u32 v = x2_get_ibyte (o);
557 add_trace (pc + o, v, 2, 1);
558 return v;
559 }
cputracefunc2_x_get_ilong(int o)560 static uae_u32 cputracefunc2_x_get_ilong (int o)
561 {
562 uae_u32 v;
563 if (get_trace (m68k_getpc () + o, 2, 4, &v)) {
564 v = x2_get_ilong (o);
565 check_trace2 ();
566 }
567 return v;
568 }
cputracefunc2_x_get_iword(int o)569 static uae_u32 cputracefunc2_x_get_iword (int o)
570 {
571 uae_u32 v;
572 if (get_trace (m68k_getpc () + o, 2, 2, &v)) {
573 v = x2_get_iword (o);
574 check_trace2 ();
575 }
576 return v;
577 }
cputracefunc2_x_get_ibyte(int o)578 static uae_u32 cputracefunc2_x_get_ibyte (int o)
579 {
580 uae_u32 v;
581 if (get_trace (m68k_getpc () + o, 2, 1, &v)) {
582 v = x2_get_ibyte (o);
583 check_trace2 ();
584 }
585 return v;
586 }
587
cputracefunc_x_get_long(uaecptr o)588 static uae_u32 cputracefunc_x_get_long (uaecptr o)
589 {
590 set_trace (o, 0, 4);
591 uae_u32 v = x2_get_long (o);
592 add_trace (o, v, 0, 4);
593 return v;
594 }
cputracefunc_x_get_word(uaecptr o)595 static uae_u32 cputracefunc_x_get_word (uaecptr o)
596 {
597 set_trace (o, 0, 2);
598 uae_u32 v = x2_get_word (o);
599 add_trace (o, v, 0, 2);
600 return v;
601 }
cputracefunc_x_get_byte(uaecptr o)602 static uae_u32 cputracefunc_x_get_byte (uaecptr o)
603 {
604 set_trace (o, 0, 1);
605 uae_u32 v = x2_get_byte (o);
606 add_trace (o, v, 0, 1);
607 return v;
608 }
cputracefunc2_x_get_long(uaecptr o)609 static uae_u32 cputracefunc2_x_get_long (uaecptr o)
610 {
611 uae_u32 v;
612 if (get_trace (o, 0, 4, &v)) {
613 v = x2_get_long (o);
614 check_trace2 ();
615 }
616 return v;
617 }
cputracefunc2_x_get_word(uaecptr o)618 static uae_u32 cputracefunc2_x_get_word (uaecptr o)
619 {
620 uae_u32 v;
621 if (get_trace (o, 0, 2, &v)) {
622 v = x2_get_word (o);
623 check_trace2 ();
624 }
625 return v;
626 }
cputracefunc2_x_get_byte(uaecptr o)627 static uae_u32 cputracefunc2_x_get_byte (uaecptr o)
628 {
629 uae_u32 v;
630 if (get_trace (o, 0, 1, &v)) {
631 v = x2_get_byte (o);
632 check_trace2 ();
633 }
634 return v;
635 }
636
cputracefunc_x_put_long(uaecptr o,uae_u32 val)637 static void cputracefunc_x_put_long (uaecptr o, uae_u32 val)
638 {
639 clear_trace ();
640 add_trace (o, val, 1, 4);
641 x2_put_long (o, val);
642 }
cputracefunc_x_put_word(uaecptr o,uae_u32 val)643 static void cputracefunc_x_put_word (uaecptr o, uae_u32 val)
644 {
645 clear_trace ();
646 add_trace (o, val, 1, 2);
647 x2_put_word (o, val);
648 }
cputracefunc_x_put_byte(uaecptr o,uae_u32 val)649 static void cputracefunc_x_put_byte (uaecptr o, uae_u32 val)
650 {
651 clear_trace ();
652 add_trace (o, val, 1, 1);
653 x2_put_byte (o, val);
654 }
cputracefunc2_x_put_long(uaecptr o,uae_u32 val)655 static void cputracefunc2_x_put_long (uaecptr o, uae_u32 val)
656 {
657 uae_u32 v;
658 if (get_trace (o, 1, 4, &v)) {
659 x2_put_long (o, val);
660 check_trace2 ();
661 }
662 if (v != val)
663 write_log (_T("cputracefunc2_x_put_long %d <> %d\n"), v, val);
664 }
cputracefunc2_x_put_word(uaecptr o,uae_u32 val)665 static void cputracefunc2_x_put_word (uaecptr o, uae_u32 val)
666 {
667 uae_u32 v;
668 if (get_trace (o, 1, 2, &v)) {
669 x2_put_word (o, val);
670 check_trace2 ();
671 }
672 if (v != val)
673 write_log (_T("cputracefunc2_x_put_word %d <> %d\n"), v, val);
674 }
cputracefunc2_x_put_byte(uaecptr o,uae_u32 val)675 static void cputracefunc2_x_put_byte (uaecptr o, uae_u32 val)
676 {
677 uae_u32 v;
678 if (get_trace (o, 1, 1, &v)) {
679 x2_put_byte (o, val);
680 check_trace2 ();
681 }
682 if (v != val)
683 write_log (_T("cputracefunc2_x_put_byte %d <> %d\n"), v, val);
684 }
685
cputracefunc_x_do_cycles(unsigned long cycles)686 static void cputracefunc_x_do_cycles (unsigned long cycles)
687 {
688 while (cycles >= CYCLE_UNIT) {
689 cputrace.cyclecounter += CYCLE_UNIT;
690 cycles -= CYCLE_UNIT;
691 x2_do_cycles (CYCLE_UNIT);
692 }
693 if (cycles > 0) {
694 cputrace.cyclecounter += cycles;
695 x2_do_cycles (cycles);
696 }
697 }
698
cputracefunc2_x_do_cycles(unsigned long cycles)699 static void cputracefunc2_x_do_cycles (unsigned long cycles)
700 {
701 if (cputrace.cyclecounter > (long)cycles) {
702 cputrace.cyclecounter -= cycles;
703 return;
704 }
705 cycles -= cputrace.cyclecounter;
706 cputrace.cyclecounter = 0;
707 check_trace ();
708 x_do_cycles = x2_do_cycles;
709 if (cycles > 0)
710 x_do_cycles (cycles);
711 }
712
cputracefunc_x_do_cycles_pre(unsigned long cycles)713 static void cputracefunc_x_do_cycles_pre (unsigned long cycles)
714 {
715 cputrace.cyclecounter_post = 0;
716 cputrace.cyclecounter_pre = 0;
717 while (cycles >= CYCLE_UNIT) {
718 cycles -= CYCLE_UNIT;
719 cputrace.cyclecounter_pre += CYCLE_UNIT;
720 x2_do_cycles (CYCLE_UNIT);
721 }
722 if (cycles > 0) {
723 x2_do_cycles (cycles);
724 cputrace.cyclecounter_pre += cycles;
725 }
726 cputrace.cyclecounter_pre = 0;
727 }
728 // cyclecounter_pre = how many cycles we need to SWALLOW
729 // -1 = rerun whole access
cputracefunc2_x_do_cycles_pre(unsigned long cycles)730 static void cputracefunc2_x_do_cycles_pre (unsigned long cycles)
731 {
732 if (cputrace.cyclecounter_pre == -1) {
733 cputrace.cyclecounter_pre = 0;
734 check_trace ();
735 check_trace2 ();
736 x_do_cycles (cycles);
737 return;
738 }
739 if (cputrace.cyclecounter_pre > (long)cycles) {
740 cputrace.cyclecounter_pre -= cycles;
741 return;
742 }
743 cycles -= cputrace.cyclecounter_pre;
744 cputrace.cyclecounter_pre = 0;
745 check_trace ();
746 if (cycles > 0)
747 x_do_cycles (cycles);
748 }
749
cputracefunc_x_do_cycles_post(unsigned long cycles,uae_u32 v)750 static void cputracefunc_x_do_cycles_post (unsigned long cycles, uae_u32 v)
751 {
752 if (cputrace.memoryoffset < 1) {
753 #if CPUTRACE_DEBUG
754 write_log (_T("cputracefunc_x_do_cycles_post memoryoffset=%d!\n"), cputrace.memoryoffset);
755 #endif
756 return;
757 }
758 struct cputracememory *ctm = &cputrace.ctm[cputrace.memoryoffset - 1];
759 ctm->data = v;
760 cputrace.cyclecounter_post = cycles;
761 cputrace.cyclecounter_pre = 0;
762 while (cycles >= CYCLE_UNIT) {
763 cycles -= CYCLE_UNIT;
764 cputrace.cyclecounter_post -= CYCLE_UNIT;
765 x2_do_cycles (CYCLE_UNIT);
766 }
767 if (cycles > 0) {
768 cputrace.cyclecounter_post -= cycles;
769 x2_do_cycles (cycles);
770 }
771 cputrace.cyclecounter_post = 0;
772 }
773 // cyclecounter_post = how many cycles we need to WAIT
cputracefunc2_x_do_cycles_post(unsigned long cycles,uae_u32 v)774 static void cputracefunc2_x_do_cycles_post (unsigned long cycles, uae_u32 v)
775 {
776 uae_u32 c;
777 if (cputrace.cyclecounter_post) {
778 c = cputrace.cyclecounter_post;
779 cputrace.cyclecounter_post = 0;
780 } else {
781 c = cycles;
782 }
783 check_trace ();
784 if (c > 0)
785 x_do_cycles (c);
786 }
787
do_cycles_post(unsigned long cycles,uae_u32 v)788 static void do_cycles_post (unsigned long cycles, uae_u32 v)
789 {
790 do_cycles (cycles);
791 }
do_cycles_ce_post(unsigned long cycles,uae_u32 v)792 static void do_cycles_ce_post (unsigned long cycles, uae_u32 v)
793 {
794 do_cycles_ce (cycles);
795 }
do_cycles_ce020_post(unsigned long cycles,uae_u32 v)796 static void do_cycles_ce020_post (unsigned long cycles, uae_u32 v)
797 {
798 #ifndef WINUAE_FOR_HATARI
799 do_cycles_ce020 (cycles);
800 #else
801 do_cycles_ce020_long (cycles);
802 #endif
803 }
804
dcache_check_nommu(uaecptr addr,bool write,uae_u32 size)805 static uae_u8 dcache_check_nommu(uaecptr addr, bool write, uae_u32 size)
806 {
807 return ce_cachable[addr >> 16];
808 }
809
mem_access_delay_long_write_ce030_cicheck(uaecptr addr,uae_u32 v)810 static void mem_access_delay_long_write_ce030_cicheck(uaecptr addr, uae_u32 v)
811 {
812 mem_access_delay_long_write_ce020(addr, v);
813 mmu030_cache_state = ce_cachable[addr >> 16];
814 }
mem_access_delay_word_write_ce030_cicheck(uaecptr addr,uae_u32 v)815 static void mem_access_delay_word_write_ce030_cicheck(uaecptr addr, uae_u32 v)
816 {
817 mem_access_delay_word_write_ce020(addr, v);
818 mmu030_cache_state = ce_cachable[addr >> 16];
819 }
mem_access_delay_byte_write_ce030_cicheck(uaecptr addr,uae_u32 v)820 static void mem_access_delay_byte_write_ce030_cicheck(uaecptr addr, uae_u32 v)
821 {
822 mem_access_delay_byte_write_ce020(addr, v);
823 mmu030_cache_state = ce_cachable[addr >> 16];
824 }
825
put_long030_cicheck(uaecptr addr,uae_u32 v)826 static void put_long030_cicheck(uaecptr addr, uae_u32 v)
827 {
828 put_long(addr, v);
829 mmu030_cache_state = ce_cachable[addr >> 16];
830 }
put_word030_cicheck(uaecptr addr,uae_u32 v)831 static void put_word030_cicheck(uaecptr addr, uae_u32 v)
832 {
833 put_word(addr, v);
834 mmu030_cache_state = ce_cachable[addr >> 16];
835 }
put_byte030_cicheck(uaecptr addr,uae_u32 v)836 static void put_byte030_cicheck(uaecptr addr, uae_u32 v)
837 {
838 put_byte(addr, v);
839 mmu030_cache_state = ce_cachable[addr >> 16];
840 }
841
842 static uae_u32 (*icache_fetch)(uaecptr);
843 static uae_u32 (*dcache_lget)(uaecptr);
844 static uae_u32 (*dcache_wget)(uaecptr);
845 static uae_u32 (*dcache_bget)(uaecptr);
846 static uae_u8 (*dcache_check)(uaecptr, bool, uae_u32);
847 static void (*dcache_lput)(uaecptr, uae_u32);
848 static void (*dcache_wput)(uaecptr, uae_u32);
849 static void (*dcache_bput)(uaecptr, uae_u32);
850
851 uae_u32(*read_data_030_bget)(uaecptr);
852 uae_u32(*read_data_030_wget)(uaecptr);
853 uae_u32(*read_data_030_lget)(uaecptr);
854 void(*write_data_030_bput)(uaecptr,uae_u32);
855 void(*write_data_030_wput)(uaecptr,uae_u32);
856 void(*write_data_030_lput)(uaecptr,uae_u32);
857
858 uae_u32(*read_data_030_fc_bget)(uaecptr, uae_u32);
859 uae_u32(*read_data_030_fc_wget)(uaecptr, uae_u32);
860 uae_u32(*read_data_030_fc_lget)(uaecptr, uae_u32);
861 void(*write_data_030_fc_bput)(uaecptr, uae_u32, uae_u32);
862 void(*write_data_030_fc_wput)(uaecptr, uae_u32, uae_u32);
863 void(*write_data_030_fc_lput)(uaecptr, uae_u32, uae_u32);
864
865
set_x_ifetches(void)866 static void set_x_ifetches(void)
867 {
868 if (m68k_pc_indirect) {
869 if (currprefs.cachesize) {
870 // indirect via addrbank
871 x_get_ilong = get_iilong_jit;
872 x_get_iword = get_iiword_jit;
873 x_get_ibyte = get_iibyte_jit;
874 x_next_iword = next_iiword_jit;
875 x_next_ilong = next_iilong_jit;
876 } else {
877 // indirect via addrbank
878 x_get_ilong = get_iilong;
879 x_get_iword = get_iiword;
880 x_get_ibyte = get_iibyte;
881 x_next_iword = next_iiword;
882 x_next_ilong = next_iilong;
883 }
884 } else {
885 // direct to memory
886 x_get_ilong = get_dilong;
887 x_get_iword = get_diword;
888 x_get_ibyte = get_dibyte;
889 x_next_iword = next_diword;
890 x_next_ilong = next_dilong;
891 }
892 }
893
894
895 #ifdef WINUAE_FOR_HATARI
896
897 void (*x_do_cycles_hatari_blitter_save)(unsigned long);
898 void (*x_do_cycles_pre_hatari_blitter_save)(unsigned long);
899 void (*x_do_cycles_post_hatari_blitter_save)(unsigned long, uae_u32);
900
do_cycles_ce_post_hatari_blitter(unsigned long cycles,uae_u32 v)901 static void do_cycles_ce_post_hatari_blitter (unsigned long cycles, uae_u32 v)
902 {
903 do_cycles_ce_hatari_blitter (cycles);
904 }
905
set_x_funcs_hatari_blitter(int flag)906 void set_x_funcs_hatari_blitter (int flag)
907 {
908 if ( flag == 0 )
909 {
910 //fprintf ( stderr , "restore blitter x_funcs\n" );
911 /* disable blitter, restore functions if needed */
912 if ( x_do_cycles_hatari_blitter_save )
913 {
914 x_do_cycles = x_do_cycles_hatari_blitter_save;
915 x_do_cycles_pre = x_do_cycles_pre_hatari_blitter_save;
916 x_do_cycles_post = x_do_cycles_post_hatari_blitter_save;
917 }
918 }
919 else
920 {
921 //fprintf ( stderr , "save/set blitter x_funcs\n" );
922 /* save current functions */
923 x_do_cycles_hatari_blitter_save = x_do_cycles;
924 x_do_cycles_pre_hatari_blitter_save = x_do_cycles_pre;
925 x_do_cycles_post_hatari_blitter_save = x_do_cycles_post;
926
927 /* set blitter specific functions */
928 x_do_cycles = do_cycles_ce_hatari_blitter;
929 x_do_cycles_pre = do_cycles_ce_hatari_blitter;
930 x_do_cycles_post = do_cycles_ce_post_hatari_blitter;
931 }
932 }
933
934 #endif
935
936 // indirect memory access functions
set_x_funcs(void)937 static void set_x_funcs (void)
938 {
939 if (currprefs.mmu_model) {
940 if (currprefs.cpu_model == 68060) {
941
942 x_prefetch = get_iword_mmu060;
943 x_get_ilong = get_ilong_mmu060;
944 x_get_iword = get_iword_mmu060;
945 x_get_ibyte = get_ibyte_mmu060;
946 x_next_iword = next_iword_mmu060;
947 x_next_ilong = next_ilong_mmu060;
948 x_put_long = put_long_mmu060;
949 x_put_word = put_word_mmu060;
950 x_put_byte = put_byte_mmu060;
951 x_get_long = get_long_mmu060;
952 x_get_word = get_word_mmu060;
953 x_get_byte = get_byte_mmu060;
954
955 } else if (currprefs.cpu_model == 68040) {
956
957 x_prefetch = get_iword_mmu040;
958 x_get_ilong = get_ilong_mmu040;
959 x_get_iword = get_iword_mmu040;
960 x_get_ibyte = get_ibyte_mmu040;
961 x_next_iword = next_iword_mmu040;
962 x_next_ilong = next_ilong_mmu040;
963 x_put_long = put_long_mmu040;
964 x_put_word = put_word_mmu040;
965 x_put_byte = put_byte_mmu040;
966 x_get_long = get_long_mmu040;
967 x_get_word = get_word_mmu040;
968 x_get_byte = get_byte_mmu040;
969
970 } else {
971
972 if (currprefs.cpu_memory_cycle_exact) {
973 x_prefetch = get_iword_mmu030c_state;
974 x_get_ilong = get_ilong_mmu030c_state;
975 x_get_iword = get_iword_mmu030c_state;
976 x_get_ibyte = NULL;
977 x_next_iword = next_iword_mmu030c_state;
978 x_next_ilong = next_ilong_mmu030c_state;
979 x_do_cycles = do_cycles;
980 x_do_cycles_pre = do_cycles;
981 x_do_cycles_post = do_cycles_post;
982 } else if (currprefs.cpu_compatible) {
983 x_prefetch = get_iword_mmu030c_state;
984 x_get_ilong = get_ilong_mmu030c_state;
985 x_get_iword = get_iword_mmu030c_state;
986 x_get_ibyte = NULL;
987 x_next_iword = next_iword_mmu030c_state;
988 x_next_ilong = next_ilong_mmu030c_state;
989 x_do_cycles = do_cycles;
990 x_do_cycles_pre = do_cycles;
991 x_do_cycles_post = do_cycles_post;
992 } else {
993 x_prefetch = get_iword_mmu030;
994 x_get_ilong = get_ilong_mmu030;
995 x_get_iword = get_iword_mmu030;
996 x_get_ibyte = get_ibyte_mmu030;
997 x_next_iword = next_iword_mmu030;
998 x_next_ilong = next_ilong_mmu030;
999 }
1000 x_put_long = put_long_mmu030;
1001 x_put_word = put_word_mmu030;
1002 x_put_byte = put_byte_mmu030;
1003 x_get_long = get_long_mmu030;
1004 x_get_word = get_word_mmu030;
1005 x_get_byte = get_byte_mmu030;
1006 if (currprefs.cpu_data_cache) {
1007 x_put_long = put_long_dc030;
1008 x_put_word = put_word_dc030;
1009 x_put_byte = put_byte_dc030;
1010 x_get_long = get_long_dc030;
1011 x_get_word = get_word_dc030;
1012 x_get_byte = get_byte_dc030;
1013 }
1014
1015 }
1016 x_do_cycles = do_cycles;
1017 x_do_cycles_pre = do_cycles;
1018 x_do_cycles_post = do_cycles_post;
1019 } else if (currprefs.cpu_model < 68020) {
1020 // 68000/010
1021 if (currprefs.cpu_cycle_exact) {
1022 x_prefetch = get_word_ce000_prefetch;
1023 x_get_ilong = NULL;
1024 x_get_iword = get_wordi_ce000;
1025 x_get_ibyte = NULL;
1026 x_next_iword = NULL;
1027 x_next_ilong = NULL;
1028 x_put_long = put_long_ce000;
1029 x_put_word = put_word_ce000;
1030 x_put_byte = put_byte_ce000;
1031 x_get_long = get_long_ce000;
1032 x_get_word = get_word_ce000;
1033 x_get_byte = get_byte_ce000;
1034 x_do_cycles = do_cycles_ce;
1035 x_do_cycles_pre = do_cycles_ce;
1036 x_do_cycles_post = do_cycles_ce_post;
1037 } else if (currprefs.cpu_memory_cycle_exact) {
1038 // cpu_memory_cycle_exact + cpu_compatible
1039 x_prefetch = get_word_000_prefetch;
1040 x_get_ilong = NULL;
1041 x_get_iword = get_iiword;
1042 x_get_ibyte = get_iibyte;
1043 x_next_iword = NULL;
1044 x_next_ilong = NULL;
1045 x_put_long = put_long_ce000;
1046 x_put_word = put_word_ce000;
1047 x_put_byte = put_byte_ce000;
1048 x_get_long = get_long_ce000;
1049 x_get_word = get_word_ce000;
1050 x_get_byte = get_byte_ce000;
1051 x_do_cycles = do_cycles;
1052 x_do_cycles_pre = do_cycles;
1053 x_do_cycles_post = do_cycles_post;
1054 } else if (currprefs.cpu_compatible) {
1055 // cpu_compatible only
1056 x_prefetch = get_word_000_prefetch;
1057 x_get_ilong = NULL;
1058 x_get_iword = get_iiword;
1059 x_get_ibyte = get_iibyte;
1060 x_next_iword = NULL;
1061 x_next_ilong = NULL;
1062 x_put_long = put_long;
1063 x_put_word = put_word;
1064 x_put_byte = put_byte;
1065 x_get_long = get_long;
1066 x_get_word = get_word;
1067 x_get_byte = get_byte;
1068 x_do_cycles = do_cycles;
1069 x_do_cycles_pre = do_cycles;
1070 x_do_cycles_post = do_cycles_post;
1071 } else {
1072 x_prefetch = NULL;
1073 x_get_ilong = get_dilong;
1074 x_get_iword = get_diword;
1075 x_get_ibyte = get_dibyte;
1076 x_next_iword = next_diword;
1077 x_next_ilong = next_dilong;
1078 x_put_long = put_long;
1079 x_put_word = put_word;
1080 x_put_byte = put_byte;
1081 x_get_long = get_long;
1082 x_get_word = get_word;
1083 x_get_byte = get_byte;
1084 x_do_cycles = do_cycles;
1085 x_do_cycles_pre = do_cycles;
1086 x_do_cycles_post = do_cycles_post;
1087 }
1088 } else if (!currprefs.cpu_cycle_exact) {
1089 // 68020+ no ce
1090 if (currprefs.cpu_memory_cycle_exact) {
1091 // cpu_memory_cycle_exact + cpu_compatible
1092 if (currprefs.cpu_model == 68020 && !currprefs.cachesize) {
1093 x_prefetch = get_word_020_prefetch;
1094 x_get_ilong = get_long_020_prefetch;
1095 x_get_iword = get_word_020_prefetch;
1096 x_get_ibyte = NULL;
1097 x_next_iword = next_iword_020_prefetch;
1098 x_next_ilong = next_ilong_020_prefetch;
1099 x_put_long = put_long_ce020;
1100 x_put_word = put_word_ce020;
1101 x_put_byte = put_byte_ce020;
1102 x_get_long = get_long_ce020;
1103 x_get_word = get_word_ce020;
1104 x_get_byte = get_byte_ce020;
1105 x_do_cycles = do_cycles;
1106 x_do_cycles_pre = do_cycles;
1107 x_do_cycles_post = do_cycles_post;
1108 } else if (currprefs.cpu_model == 68030 && !currprefs.cachesize) {
1109 x_prefetch = get_word_030_prefetch;
1110 x_get_ilong = get_long_030_prefetch;
1111 x_get_iword = get_word_030_prefetch;
1112 x_get_ibyte = NULL;
1113 x_next_iword = next_iword_030_prefetch;
1114 x_next_ilong = next_ilong_030_prefetch;
1115 x_put_long = put_long_ce030;
1116 x_put_word = put_word_ce030;
1117 x_put_byte = put_byte_ce030;
1118 x_get_long = get_long_ce030;
1119 x_get_word = get_word_ce030;
1120 x_get_byte = get_byte_ce030;
1121 x_do_cycles = do_cycles;
1122 x_do_cycles_pre = do_cycles;
1123 x_do_cycles_post = do_cycles_post;
1124 } else if (currprefs.cpu_model < 68040) {
1125 // JIT or 68030+ does not have real prefetch only emulation
1126 x_prefetch = NULL;
1127 set_x_ifetches();
1128 x_put_long = put_long;
1129 x_put_word = put_word;
1130 x_put_byte = put_byte;
1131 x_get_long = get_long;
1132 x_get_word = get_word;
1133 x_get_byte = get_byte;
1134 x_do_cycles = do_cycles;
1135 x_do_cycles_pre = do_cycles;
1136 x_do_cycles_post = do_cycles_post;
1137 } else {
1138 // 68040+ (same as below)
1139 x_prefetch = NULL;
1140 x_get_ilong = get_ilong_cache_040;
1141 x_get_iword = get_iword_cache_040;
1142 x_get_ibyte = NULL;
1143 x_next_iword = next_iword_cache040;
1144 x_next_ilong = next_ilong_cache040;
1145 if (currprefs.cpu_data_cache) {
1146 x_put_long = put_long_cache_040;
1147 x_put_word = put_word_cache_040;
1148 x_put_byte = put_byte_cache_040;
1149 x_get_long = get_long_cache_040;
1150 x_get_word = get_word_cache_040;
1151 x_get_byte = get_byte_cache_040;
1152 } else {
1153 x_get_byte = mem_access_delay_byte_read_c040;
1154 x_get_word = mem_access_delay_word_read_c040;
1155 x_get_long = mem_access_delay_long_read_c040;
1156 x_put_byte = mem_access_delay_byte_write_c040;
1157 x_put_word = mem_access_delay_word_write_c040;
1158 x_put_long = mem_access_delay_long_write_c040;
1159 }
1160 x_do_cycles = do_cycles;
1161 x_do_cycles_pre = do_cycles;
1162 x_do_cycles_post = do_cycles_post;
1163 }
1164 } else if (currprefs.cpu_compatible) {
1165 // cpu_compatible only
1166 if (currprefs.cpu_model == 68020 && !currprefs.cachesize) {
1167 x_prefetch = get_word_020_prefetch;
1168 x_get_ilong = get_long_020_prefetch;
1169 x_get_iword = get_word_020_prefetch;
1170 x_get_ibyte = NULL;
1171 x_next_iword = next_iword_020_prefetch;
1172 x_next_ilong = next_ilong_020_prefetch;
1173 x_put_long = put_long;
1174 x_put_word = put_word;
1175 x_put_byte = put_byte;
1176 x_get_long = get_long;
1177 x_get_word = get_word;
1178 x_get_byte = get_byte;
1179 x_do_cycles = do_cycles;
1180 x_do_cycles_pre = do_cycles;
1181 x_do_cycles_post = do_cycles_post;
1182 } else if (currprefs.cpu_model == 68030 && !currprefs.cachesize) {
1183 x_prefetch = get_word_030_prefetch;
1184 x_get_ilong = get_long_030_prefetch;
1185 x_get_iword = get_word_030_prefetch;
1186 x_get_ibyte = NULL;
1187 x_next_iword = next_iword_030_prefetch;
1188 x_next_ilong = next_ilong_030_prefetch;
1189 x_put_long = put_long_030;
1190 x_put_word = put_word_030;
1191 x_put_byte = put_byte_030;
1192 x_get_long = get_long_030;
1193 x_get_word = get_word_030;
1194 x_get_byte = get_byte_030;
1195 x_do_cycles = do_cycles;
1196 x_do_cycles_pre = do_cycles;
1197 x_do_cycles_post = do_cycles_post;
1198 } else if (currprefs.cpu_model < 68040) {
1199 // JIT or 68030+ does not have real prefetch only emulation
1200 x_prefetch = NULL;
1201 set_x_ifetches();
1202 x_put_long = put_long;
1203 x_put_word = put_word;
1204 x_put_byte = put_byte;
1205 x_get_long = get_long;
1206 x_get_word = get_word;
1207 x_get_byte = get_byte;
1208 x_do_cycles = do_cycles;
1209 x_do_cycles_pre = do_cycles;
1210 x_do_cycles_post = do_cycles_post;
1211 } else {
1212 x_prefetch = NULL;
1213 x_get_ilong = get_ilong_cache_040;
1214 x_get_iword = get_iword_cache_040;
1215 x_get_ibyte = NULL;
1216 x_next_iword = next_iword_cache040;
1217 x_next_ilong = next_ilong_cache040;
1218 if (currprefs.cpu_data_cache) {
1219 x_put_long = put_long_cache_040;
1220 x_put_word = put_word_cache_040;
1221 x_put_byte = put_byte_cache_040;
1222 x_get_long = get_long_cache_040;
1223 x_get_word = get_word_cache_040;
1224 x_get_byte = get_byte_cache_040;
1225 } else {
1226 x_put_long = put_long;
1227 x_put_word = put_word;
1228 x_put_byte = put_byte;
1229 x_get_long = get_long;
1230 x_get_word = get_word;
1231 x_get_byte = get_byte;
1232 }
1233 x_do_cycles = do_cycles;
1234 x_do_cycles_pre = do_cycles;
1235 x_do_cycles_post = do_cycles_post;
1236 }
1237 } else {
1238 x_prefetch = NULL;
1239 set_x_ifetches();
1240 if (currprefs.cachesize) {
1241 x_put_long = put_long_jit;
1242 x_put_word = put_word_jit;
1243 x_put_byte = put_byte_jit;
1244 x_get_long = get_long_jit;
1245 x_get_word = get_word_jit;
1246 x_get_byte = get_byte_jit;
1247 } else {
1248 x_put_long = put_long;
1249 x_put_word = put_word;
1250 x_put_byte = put_byte;
1251 x_get_long = get_long;
1252 x_get_word = get_word;
1253 x_get_byte = get_byte;
1254 }
1255 x_do_cycles = do_cycles;
1256 x_do_cycles_pre = do_cycles;
1257 x_do_cycles_post = do_cycles_post;
1258 }
1259 // 68020+ cycle exact
1260 } else if (currprefs.cpu_model == 68020) {
1261 x_prefetch = get_word_ce020_prefetch;
1262 x_get_ilong = get_long_ce020_prefetch;
1263 x_get_iword = get_word_ce020_prefetch;
1264 x_get_ibyte = NULL;
1265 x_next_iword = next_iword_020ce;
1266 x_next_ilong = next_ilong_020ce;
1267 x_put_long = put_long_ce020;
1268 x_put_word = put_word_ce020;
1269 x_put_byte = put_byte_ce020;
1270 x_get_long = get_long_ce020;
1271 x_get_word = get_word_ce020;
1272 x_get_byte = get_byte_ce020;
1273 #ifndef WINUAE_FOR_HATARI
1274 x_do_cycles = do_cycles_ce020;
1275 x_do_cycles_pre = do_cycles_ce020;
1276 x_do_cycles_post = do_cycles_ce020_post;
1277 #else
1278 x_do_cycles = do_cycles_ce020_long;
1279 x_do_cycles_pre = do_cycles_ce020_long;
1280 x_do_cycles_post = do_cycles_ce020_post;
1281 #endif
1282 } else if (currprefs.cpu_model == 68030) {
1283 x_prefetch = get_word_ce030_prefetch;
1284 x_get_ilong = get_long_ce030_prefetch;
1285 x_get_iword = get_word_ce030_prefetch;
1286 x_get_ibyte = NULL;
1287 x_next_iword = next_iword_030ce;
1288 x_next_ilong = next_ilong_030ce;
1289 if (currprefs.cpu_data_cache) {
1290 x_put_long = put_long_dc030;
1291 x_put_word = put_word_dc030;
1292 x_put_byte = put_byte_dc030;
1293 x_get_long = get_long_dc030;
1294 x_get_word = get_word_dc030;
1295 x_get_byte = get_byte_dc030;
1296 } else {
1297 x_put_long = put_long_ce030;
1298 x_put_word = put_word_ce030;
1299 x_put_byte = put_byte_ce030;
1300 x_get_long = get_long_ce030;
1301 x_get_word = get_word_ce030;
1302 x_get_byte = get_byte_ce030;
1303 }
1304 #ifndef WINUAE_FOR_HATARI
1305 x_do_cycles = do_cycles_ce020;
1306 x_do_cycles_pre = do_cycles_ce020;
1307 x_do_cycles_post = do_cycles_ce020_post;
1308 #else
1309 x_do_cycles = do_cycles_ce020_long;
1310 x_do_cycles_pre = do_cycles_ce020_long;
1311 x_do_cycles_post = do_cycles_ce020_post;
1312 #endif
1313 } else if (currprefs.cpu_model >= 68040) {
1314 x_prefetch = NULL;
1315 x_get_ilong = get_ilong_cache_040;
1316 x_get_iword = get_iword_cache_040;
1317 x_get_ibyte = NULL;
1318 x_next_iword = next_iword_cache040;
1319 x_next_ilong = next_ilong_cache040;
1320 if (currprefs.cpu_data_cache) {
1321 x_put_long = put_long_cache_040;
1322 x_put_word = put_word_cache_040;
1323 x_put_byte = put_byte_cache_040;
1324 x_get_long = get_long_cache_040;
1325 x_get_word = get_word_cache_040;
1326 x_get_byte = get_byte_cache_040;
1327 } else {
1328 x_get_byte = mem_access_delay_byte_read_c040;
1329 x_get_word = mem_access_delay_word_read_c040;
1330 x_get_long = mem_access_delay_long_read_c040;
1331 x_put_byte = mem_access_delay_byte_write_c040;
1332 x_put_word = mem_access_delay_word_write_c040;
1333 x_put_long = mem_access_delay_long_write_c040;
1334 }
1335 #ifndef WINUAE_FOR_HATARI
1336 x_do_cycles = do_cycles_ce020;
1337 x_do_cycles_pre = do_cycles_ce020;
1338 x_do_cycles_post = do_cycles_ce020_post;
1339 #else
1340 x_do_cycles = do_cycles_ce020_long;
1341 x_do_cycles_pre = do_cycles_ce020_long;
1342 x_do_cycles_post = do_cycles_ce020_post;
1343 #endif
1344 }
1345 x2_prefetch = x_prefetch;
1346 x2_get_ilong = x_get_ilong;
1347 x2_get_iword = x_get_iword;
1348 x2_get_ibyte = x_get_ibyte;
1349 x2_next_iword = x_next_iword;
1350 x2_next_ilong = x_next_ilong;
1351 x2_put_long = x_put_long;
1352 x2_put_word = x_put_word;
1353 x2_put_byte = x_put_byte;
1354 x2_get_long = x_get_long;
1355 x2_get_word = x_get_word;
1356 x2_get_byte = x_get_byte;
1357 x2_do_cycles = x_do_cycles;
1358 x2_do_cycles_pre = x_do_cycles_pre;
1359 x2_do_cycles_post = x_do_cycles_post;
1360
1361 if (cpu_tracer > 0) {
1362 x_prefetch = cputracefunc_x_prefetch;
1363 x_get_ilong = cputracefunc_x_get_ilong;
1364 x_get_iword = cputracefunc_x_get_iword;
1365 x_get_ibyte = cputracefunc_x_get_ibyte;
1366 x_next_iword = cputracefunc_x_next_iword;
1367 x_next_ilong = cputracefunc_x_next_ilong;
1368 x_put_long = cputracefunc_x_put_long;
1369 x_put_word = cputracefunc_x_put_word;
1370 x_put_byte = cputracefunc_x_put_byte;
1371 x_get_long = cputracefunc_x_get_long;
1372 x_get_word = cputracefunc_x_get_word;
1373 x_get_byte = cputracefunc_x_get_byte;
1374 x_do_cycles = cputracefunc_x_do_cycles;
1375 x_do_cycles_pre = cputracefunc_x_do_cycles_pre;
1376 x_do_cycles_post = cputracefunc_x_do_cycles_post;
1377 } else if (cpu_tracer < 0) {
1378 if (!check_trace ()) {
1379 x_prefetch = cputracefunc2_x_prefetch;
1380 x_get_ilong = cputracefunc2_x_get_ilong;
1381 x_get_iword = cputracefunc2_x_get_iword;
1382 x_get_ibyte = cputracefunc2_x_get_ibyte;
1383 x_next_iword = cputracefunc2_x_next_iword;
1384 x_next_ilong = cputracefunc2_x_next_ilong;
1385 x_put_long = cputracefunc2_x_put_long;
1386 x_put_word = cputracefunc2_x_put_word;
1387 x_put_byte = cputracefunc2_x_put_byte;
1388 x_get_long = cputracefunc2_x_get_long;
1389 x_get_word = cputracefunc2_x_get_word;
1390 x_get_byte = cputracefunc2_x_get_byte;
1391 x_do_cycles = cputracefunc2_x_do_cycles;
1392 x_do_cycles_pre = cputracefunc2_x_do_cycles_pre;
1393 x_do_cycles_post = cputracefunc2_x_do_cycles_post;
1394 }
1395 }
1396
1397 set_x_cp_funcs();
1398 mmu_set_funcs();
1399 mmu030_set_funcs();
1400
1401 dcache_lput = put_long;
1402 dcache_wput = put_word;
1403 dcache_bput = put_byte;
1404 dcache_lget = get_long;
1405 dcache_wget = get_word;
1406 dcache_bget = get_byte;
1407 dcache_check = dcache_check_nommu;
1408
1409 icache_fetch = get_longi;
1410 if (currprefs.cpu_cycle_exact) {
1411 icache_fetch = mem_access_delay_longi_read_ce020;
1412 }
1413 if (currprefs.cpu_model >= 68040 && currprefs.cpu_memory_cycle_exact) {
1414 icache_fetch = mem_access_delay_longi_read_c040;
1415 dcache_bget = mem_access_delay_byte_read_c040;
1416 dcache_wget = mem_access_delay_word_read_c040;
1417 dcache_lget = mem_access_delay_long_read_c040;
1418 dcache_bput = mem_access_delay_byte_write_c040;
1419 dcache_wput = mem_access_delay_word_write_c040;
1420 dcache_lput = mem_access_delay_long_write_c040;
1421 }
1422
1423 if (currprefs.cpu_model == 68030) {
1424
1425 if (currprefs.cpu_data_cache) {
1426 read_data_030_bget = read_dcache030_mmu_bget;
1427 read_data_030_wget = read_dcache030_mmu_wget;
1428 read_data_030_lget = read_dcache030_mmu_lget;
1429 write_data_030_bput = write_dcache030_mmu_bput;
1430 write_data_030_wput = write_dcache030_mmu_wput;
1431 write_data_030_lput = write_dcache030_mmu_lput;
1432
1433 read_data_030_fc_bget = read_dcache030_bget;
1434 read_data_030_fc_wget = read_dcache030_wget;
1435 read_data_030_fc_lget = read_dcache030_lget;
1436 write_data_030_fc_bput = write_dcache030_bput;
1437 write_data_030_fc_wput = write_dcache030_wput;
1438 write_data_030_fc_lput = write_dcache030_lput;
1439 } else {
1440 read_data_030_bget = dcache_bget;
1441 read_data_030_wget = dcache_wget;
1442 read_data_030_lget = dcache_lget;
1443 write_data_030_bput = dcache_bput;
1444 write_data_030_wput = dcache_wput;
1445 write_data_030_lput = dcache_lput;
1446
1447 read_data_030_fc_bget = mmu030_get_fc_byte;
1448 read_data_030_fc_wget = mmu030_get_fc_word;
1449 read_data_030_fc_lget = mmu030_get_fc_long;
1450 write_data_030_fc_bput = mmu030_put_fc_byte;
1451 write_data_030_fc_wput = mmu030_put_fc_word;
1452 write_data_030_fc_lput = mmu030_put_fc_long;
1453 }
1454
1455 if (currprefs.mmu_model) {
1456 if (currprefs.cpu_compatible) {
1457 icache_fetch = uae_mmu030_get_ilong_fc;
1458 } else {
1459 icache_fetch = uae_mmu030_get_ilong;
1460 }
1461 dcache_lput = uae_mmu030_put_long_fc;
1462 dcache_wput = uae_mmu030_put_word_fc;
1463 dcache_bput = uae_mmu030_put_byte_fc;
1464 dcache_lget = uae_mmu030_get_long_fc;
1465 dcache_wget = uae_mmu030_get_word_fc;
1466 dcache_bget = uae_mmu030_get_byte_fc;
1467 if (currprefs.cpu_data_cache) {
1468 read_data_030_bget = read_dcache030_mmu_bget;
1469 read_data_030_wget = read_dcache030_mmu_wget;
1470 read_data_030_lget = read_dcache030_mmu_lget;
1471 write_data_030_bput = write_dcache030_mmu_bput;
1472 write_data_030_wput = write_dcache030_mmu_wput;
1473 write_data_030_lput = write_dcache030_mmu_lput;
1474 dcache_check = uae_mmu030_check_fc;
1475 } else {
1476 read_data_030_bget = uae_mmu030_get_byte;
1477 read_data_030_wget = uae_mmu030_get_word;
1478 read_data_030_lget = uae_mmu030_get_long;
1479 write_data_030_bput = uae_mmu030_put_byte;
1480 write_data_030_wput = uae_mmu030_put_word;
1481 write_data_030_lput = uae_mmu030_put_long;
1482 }
1483 } else if (currprefs.cpu_memory_cycle_exact) {
1484 icache_fetch = mem_access_delay_longi_read_ce020;
1485 dcache_lget = mem_access_delay_long_read_ce020;
1486 dcache_wget = mem_access_delay_word_read_ce020;
1487 dcache_bget = mem_access_delay_byte_read_ce020;
1488 if (currprefs.cpu_data_cache) {
1489 dcache_lput = mem_access_delay_long_write_ce030_cicheck;
1490 dcache_wput = mem_access_delay_word_write_ce030_cicheck;
1491 dcache_bput = mem_access_delay_byte_write_ce030_cicheck;
1492 } else {
1493 dcache_lput = mem_access_delay_long_write_ce020;
1494 dcache_wput = mem_access_delay_word_write_ce020;
1495 dcache_bput = mem_access_delay_byte_write_ce020;
1496 }
1497 } else if (currprefs.cpu_data_cache) {
1498 dcache_lput = put_long030_cicheck;
1499 dcache_wput = put_word030_cicheck;
1500 dcache_bput = put_byte030_cicheck;
1501 if (currprefs.cpu_data_cache) {
1502 dcache_lput = mem_access_delay_long_write_ce030_cicheck;
1503 dcache_wput = mem_access_delay_word_write_ce030_cicheck;
1504 dcache_bput = mem_access_delay_byte_write_ce030_cicheck;
1505 } else {
1506 dcache_lput = mem_access_delay_long_write_ce020;
1507 dcache_wput = mem_access_delay_word_write_ce020;
1508 dcache_bput = mem_access_delay_byte_write_ce020;
1509 }
1510 } else if (currprefs.cpu_data_cache) {
1511 dcache_lput = put_long030_cicheck;
1512 dcache_wput = put_word030_cicheck;
1513 dcache_bput = put_byte030_cicheck;
1514 }
1515 }
1516 }
1517
can_cpu_tracer(void)1518 bool can_cpu_tracer (void)
1519 {
1520 return (currprefs.cpu_model == 68000 || currprefs.cpu_model == 68020) && currprefs.cpu_memory_cycle_exact;
1521 }
1522
is_cpu_tracer(void)1523 bool is_cpu_tracer (void)
1524 {
1525 return cpu_tracer > 0;
1526 }
set_cpu_tracer(bool state)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"));
1542 }
1543 if (old > 0 && state == false) {
1544 set_x_funcs ();
1545 write_log (_T("CPU tracer disabled\n"));
1546 }
1547 return is_cpu_tracer ();
1548 }
1549
invalidate_cpu_data_caches(void)1550 void invalidate_cpu_data_caches(void)
1551 {
1552 if (currprefs.cpu_model == 68030) {
1553 for (int i = 0; i < CACHELINES030; i++) {
1554 dcaches030[i].valid[0] = 0;
1555 dcaches030[i].valid[1] = 0;
1556 dcaches030[i].valid[2] = 0;
1557 dcaches030[i].valid[3] = 0;
1558 }
1559 } else if (currprefs.cpu_model >= 68040) {
1560 dcachelinecnt = 0;
1561 for (int i = 0; i < CACHESETS060; i++) {
1562 for (int j = 0; j < CACHELINES040; j++) {
1563 dcaches040[i].valid[j] = false;
1564 }
1565 }
1566 }
1567 }
1568
flush_cpu_caches(bool force)1569 void flush_cpu_caches(bool force)
1570 {
1571 bool doflush = currprefs.cpu_compatible || currprefs.cpu_memory_cycle_exact;
1572
1573 if (currprefs.cpu_model == 68020) {
1574 if ((regs.cacr & 0x08) || force) { // clear instr cache
1575 for (int i = 0; i < CACHELINES020; i++)
1576 caches020[i].valid = 0;
1577 regs.cacr &= ~0x08;
1578 }
1579 if (regs.cacr & 0x04) { // clear entry in instr cache
1580 caches020[(regs.caar >> 2) & (CACHELINES020 - 1)].valid = 0;
1581 regs.cacr &= ~0x04;
1582 }
1583 } else if (currprefs.cpu_model == 68030) {
1584 if ((regs.cacr & 0x08) || force) { // clear instr cache
1585 if (doflush) {
1586 for (int i = 0; i < CACHELINES030; i++) {
1587 icaches030[i].valid[0] = 0;
1588 icaches030[i].valid[1] = 0;
1589 icaches030[i].valid[2] = 0;
1590 icaches030[i].valid[3] = 0;
1591 }
1592 }
1593 regs.cacr &= ~0x08;
1594 }
1595 if (regs.cacr & 0x04) { // clear entry in instr cache
1596 icaches030[(regs.caar >> 4) & (CACHELINES030 - 1)].valid[(regs.caar >> 2) & 3] = 0;
1597 regs.cacr &= ~0x04;
1598 }
1599 if ((regs.cacr & 0x800) || force) { // clear data cache
1600 if (doflush) {
1601 for (int i = 0; i < CACHELINES030; i++) {
1602 dcaches030[i].valid[0] = 0;
1603 dcaches030[i].valid[1] = 0;
1604 dcaches030[i].valid[2] = 0;
1605 dcaches030[i].valid[3] = 0;
1606 }
1607 }
1608 regs.cacr &= ~0x800;
1609 }
1610 if (regs.cacr & 0x400) { // clear entry in data cache
1611 dcaches030[(regs.caar >> 4) & (CACHELINES030 - 1)].valid[(regs.caar >> 2) & 3] = 0;
1612 regs.cacr &= ~0x400;
1613 }
1614 } else if (currprefs.cpu_model >= 68040) {
1615 if (doflush && force) {
1616 mmu_flush_cache();
1617 icachelinecnt = 0;
1618 icachehalfline = 0;
1619 for (int i = 0; i < CACHESETS060; i++) {
1620 for (int j = 0; j < CACHELINES040; j++) {
1621 icaches040[i].valid[j] = false;
1622 }
1623 }
1624 }
1625 }
1626 }
1627
1628 #if VALIDATE_68040_DATACACHE > 1
validate_dcache040(void)1629 static void validate_dcache040(void)
1630 {
1631 for (int i = 0; i < cachedsets04060; i++) {
1632 struct cache040 *c = &dcaches040[i];
1633 for (int j = 0; j < CACHELINES040; j++) {
1634 if (c->valid[j]) {
1635 uae_u32 addr = (c->tag[j] & cachedtag04060mask) | (i << 4);
1636 if (addr < 0x200000 || (addr >= 0xd80000 && addr < 0xe00000) || (addr >= 0xe80000 && addr < 0xf00000) || (addr >= 0xa00000 && addr < 0xc00000)) {
1637 write_log(_T("Chip RAM or IO address cached! %08x\n"), addr);
1638 }
1639 for (int k = 0; k < 4; k++) {
1640 if (!c->dirty[j][k]) {
1641 uae_u32 v = get_long(addr + k * 4);
1642 if (v != c->data[j][k]) {
1643 write_log(_T("Address %08x data cache mismatch %08x != %08x\n"), addr, v, c->data[j][k]);
1644 }
1645 }
1646 }
1647 }
1648 }
1649 }
1650 }
1651 #endif
1652
dcache040_push_line(int index,int line,bool writethrough,bool invalidate)1653 static void dcache040_push_line(int index, int line, bool writethrough, bool invalidate)
1654 {
1655 struct cache040 *c = &dcaches040[index];
1656 #if VALIDATE_68040_DATACACHE
1657 if (!c->valid[line]) {
1658 write_log("dcache040_push_line pushing invalid line!\n");
1659 }
1660 #endif
1661 if (c->gdirty[line]) {
1662 uae_u32 addr = (c->tag[line] & cachedtag04060mask) | (index << 4);
1663 for (int i = 0; i < 4; i++) {
1664 if (c->dirty[line][i] || (!writethrough && currprefs.cpu_model == 68060)) {
1665 dcache_lput(addr + i * 4, c->data[line][i]);
1666 c->dirty[line][i] = false;
1667 }
1668 }
1669 c->gdirty[line] = false;
1670 }
1671 if (invalidate)
1672 c->valid[line] = false;
1673
1674 #if VALIDATE_68040_DATACACHE > 1
1675 validate_dcache040();
1676 #endif
1677 }
1678
flush_cpu_caches_040_2(int cache,int scope,uaecptr addr,bool push,bool pushinv)1679 static void flush_cpu_caches_040_2(int cache, int scope, uaecptr addr, bool push, bool pushinv)
1680 {
1681
1682 #if VALIDATE_68040_DATACACHE
1683 write_log(_T("push %d %d %d %08x %d %d\n"), cache, scope, areg, addr, push, pushinv);
1684 #endif
1685
1686 if (cache & 2)
1687 regs.prefetch020addr = 0xffffffff;
1688 for (int k = 0; k < 2; k++) {
1689 if (cache & (1 << k)) {
1690 if (scope == 3) {
1691 // all
1692 if (!k) {
1693 // data
1694 for (int i = 0; i < cachedsets04060; i++) {
1695 struct cache040 *c = &dcaches040[i];
1696 for (int j = 0; j < CACHELINES040; j++) {
1697 if (c->valid[j]) {
1698 if (push) {
1699 dcache040_push_line(i, j, false, pushinv);
1700 } else {
1701 c->valid[j] = false;
1702 }
1703 }
1704 }
1705 }
1706 dcachelinecnt = 0;
1707 } else {
1708 // instruction
1709 flush_cpu_caches(true);
1710 }
1711 } else {
1712 uae_u32 pagesize;
1713 if (scope == 2) {
1714 // page
1715 pagesize = mmu_pagesize_8k ? 8192 : 4096;
1716 } else {
1717 // line
1718 pagesize = 16;
1719 }
1720 addr &= ~(pagesize - 1);
1721 uae_u32 j;
1722 for (j = 0; j < pagesize; j += 16, addr += 16) {
1723 int index;
1724 uae_u32 tag;
1725 uae_u32 tagmask;
1726 struct cache040 *c;
1727 if (k) {
1728 tagmask = cacheitag04060mask;
1729 index = (addr >> 4) & cacheisets04060mask;
1730 c = &icaches040[index];
1731 } else {
1732 tagmask = cachedtag04060mask;
1733 index = (addr >> 4) & cachedsets04060mask;
1734 c = &dcaches040[index];
1735 }
1736 tag = addr & tagmask;
1737 for (int i = 0; i < CACHELINES040; i++) {
1738 if (c->valid[i] && c->tag[i] == tag) {
1739 if (push) {
1740 dcache040_push_line(index, i, false, pushinv);
1741 } else {
1742 c->valid[i] = false;
1743 }
1744 }
1745 }
1746 }
1747 }
1748 }
1749 }
1750 }
1751
flush_cpu_caches_040(uae_u16 opcode)1752 void flush_cpu_caches_040(uae_u16 opcode)
1753 {
1754 // 0 (1) = data, 1 (2) = instruction
1755 int cache = (opcode >> 6) & 3;
1756 int scope = (opcode >> 3) & 3;
1757 int areg = opcode & 7;
1758 uaecptr addr = m68k_areg(regs, areg);
1759 bool push = (opcode & 0x20) != 0;
1760 bool pushinv = (regs.cacr & 0x01000000) == 0; // 68060 DPI
1761
1762 flush_cpu_caches_040_2(cache, scope, addr, push, pushinv);
1763 mmu_flush_cache();
1764 }
1765
cpu_invalidate_cache(uaecptr addr,int size)1766 void cpu_invalidate_cache(uaecptr addr, int size)
1767 {
1768 if (!currprefs.cpu_data_cache)
1769 return;
1770 if (currprefs.cpu_model == 68030) {
1771 uaecptr end = addr + size;
1772 addr &= ~3;
1773 while (addr < end) {
1774 dcaches030[(addr >> 4) & (CACHELINES030 - 1)].valid[(addr >> 2) & 3] = 0;
1775 addr += 4;
1776 }
1777 } else if (currprefs.cpu_model >= 68040) {
1778 uaecptr end = addr + size;
1779 while (addr < end) {
1780 flush_cpu_caches_040_2(0, 1, addr, true, true);
1781 addr += 16;
1782 }
1783 }
1784 }
1785
1786
set_cpu_caches(bool flush)1787 void set_cpu_caches (bool flush)
1788 {
1789 regs.prefetch020addr = 0xffffffff;
1790 regs.cacheholdingaddr020 = 0xffffffff;
1791 cache_default_data &= ~CACHE_DISABLE_ALLOCATE;
1792
1793 // 68060 FIC 1/2 instruction cache
1794 cacheisets04060 = currprefs.cpu_model == 68060 && !(regs.cacr & 0x00002000) ? CACHESETS060 : CACHESETS040;
1795 cacheisets04060mask = cacheisets04060 - 1;
1796 cacheitag04060mask = ~((cacheisets04060 << 4) - 1);
1797 // 68060 FOC 1/2 data cache
1798 cachedsets04060 = currprefs.cpu_model == 68060 && !(regs.cacr & 0x08000000) ? CACHESETS060 : CACHESETS040;
1799 cachedsets04060mask = cachedsets04060 - 1;
1800 cachedtag04060mask = ~((cachedsets04060 << 4) - 1);
1801 cache_lastline = 0;
1802
1803 #ifdef JIT
1804 if (currprefs.cachesize) {
1805 if (currprefs.cpu_model < 68040) {
1806 set_cache_state (regs.cacr & 1);
1807 if (regs.cacr & 0x08) {
1808 flush_icache (3);
1809 }
1810 } else {
1811 set_cache_state ((regs.cacr & 0x8000) ? 1 : 0);
1812 }
1813 }
1814 #endif
1815 flush_cpu_caches(flush);
1816 }
1817
count_instr(unsigned int opcode)1818 STATIC_INLINE void count_instr (unsigned int opcode)
1819 {
1820 }
1821
op_illg_1(uae_u32 opcode)1822 static uae_u32 REGPARAM2 op_illg_1 (uae_u32 opcode)
1823 {
1824 op_illg (opcode);
1825 return 4;
1826 }
op_unimpl_1(uae_u32 opcode)1827 static uae_u32 REGPARAM2 op_unimpl_1 (uae_u32 opcode)
1828 {
1829 if ((opcode & 0xf000) == 0xf000 || currprefs.cpu_model < 68060)
1830 op_illg (opcode);
1831 else
1832 op_unimpl (opcode);
1833 return 4;
1834 }
1835
1836 // generic+direct, generic+direct+jit, generic+indirect, more compatible, cycle-exact, mmu, mmu+more compatible, mmu+mc+ce
1837 static const struct cputbl *cputbls[6][8] =
1838 {
1839 // 68000
1840 { op_smalltbl_5_ff, op_smalltbl_45_ff, op_smalltbl_55_ff, op_smalltbl_12_ff, op_smalltbl_14_ff, NULL, NULL, NULL },
1841 // 68010
1842 { op_smalltbl_4_ff, op_smalltbl_44_ff, op_smalltbl_54_ff, op_smalltbl_11_ff, op_smalltbl_13_ff, NULL, NULL, NULL },
1843 // 68020
1844 { op_smalltbl_3_ff, op_smalltbl_43_ff, op_smalltbl_53_ff, op_smalltbl_20_ff, op_smalltbl_21_ff, NULL, NULL, NULL },
1845 // 68030
1846 { op_smalltbl_2_ff, op_smalltbl_42_ff, op_smalltbl_52_ff, op_smalltbl_22_ff, op_smalltbl_23_ff, op_smalltbl_32_ff, op_smalltbl_34_ff, op_smalltbl_35_ff },
1847 // 68040
1848 { op_smalltbl_1_ff, op_smalltbl_41_ff, op_smalltbl_51_ff, op_smalltbl_25_ff, op_smalltbl_25_ff, op_smalltbl_31_ff, op_smalltbl_31_ff, op_smalltbl_31_ff },
1849 // 68060
1850 { op_smalltbl_0_ff, op_smalltbl_40_ff, op_smalltbl_50_ff, op_smalltbl_24_ff, op_smalltbl_24_ff, op_smalltbl_33_ff, op_smalltbl_33_ff, op_smalltbl_33_ff }
1851 };
1852
build_cpufunctbl(void)1853 static void build_cpufunctbl (void)
1854 {
1855 int i, opcnt;
1856 unsigned long opcode;
1857 const struct cputbl *tbl = 0;
1858 int lvl, mode;
1859
1860 if (!currprefs.cachesize) {
1861 if (currprefs.mmu_model) {
1862 if (currprefs.cpu_cycle_exact)
1863 mode = 7;
1864 else if (currprefs.cpu_compatible)
1865 mode = 6;
1866 else
1867 mode = 5;
1868 } else if (currprefs.cpu_cycle_exact) {
1869 mode = 4;
1870 } else if (currprefs.cpu_compatible) {
1871 mode = 3;
1872 } else {
1873 mode = 0;
1874 }
1875 m68k_pc_indirect = mode != 0 ? 1 : 0;
1876 } else {
1877 mode = 1;
1878 m68k_pc_indirect = 0;
1879 if (currprefs.comptrustbyte) {
1880 mode = 2;
1881 m68k_pc_indirect = -1;
1882 }
1883 }
1884 lvl = (currprefs.cpu_model - 68000) / 10;
1885 if (lvl == 6)
1886 lvl = 5;
1887 tbl = cputbls[lvl][mode];
1888
1889 if (tbl == NULL) {
1890 write_log (_T("no CPU emulation cores available CPU=%d!"), currprefs.cpu_model);
1891 abort ();
1892 }
1893
1894 for (opcode = 0; opcode < 65536; opcode++)
1895 cpufunctbl[opcode] = op_illg_1;
1896 for (i = 0; tbl[i].handler != NULL; i++) {
1897 opcode = tbl[i].opcode;
1898 cpufunctbl[opcode] = tbl[i].handler;
1899 cpudatatbl[opcode].length = tbl[i].length;
1900 cpudatatbl[opcode].disp020[0] = tbl[i].disp020[0];
1901 cpudatatbl[opcode].disp020[1] = tbl[i].disp020[1];
1902 cpudatatbl[opcode].branch = tbl[i].branch;
1903 }
1904
1905 /* hack fpu to 68000/68010 mode */
1906 if (currprefs.fpu_model && currprefs.cpu_model < 68020) {
1907 tbl = op_smalltbl_3_ff;
1908 for (i = 0; tbl[i].handler != NULL; i++) {
1909 if ((tbl[i].opcode & 0xfe00) == 0xf200) {
1910 cpufunctbl[tbl[i].opcode] = tbl[i].handler;
1911 cpudatatbl[tbl[i].opcode].length = tbl[i].length;
1912 cpudatatbl[tbl[i].opcode].disp020[0] = tbl[i].disp020[0];
1913 cpudatatbl[tbl[i].opcode].disp020[1] = tbl[i].disp020[1];
1914 cpudatatbl[tbl[i].opcode].branch = tbl[i].branch;
1915 }
1916 }
1917 }
1918
1919 opcnt = 0;
1920 for (opcode = 0; opcode < 65536; opcode++) {
1921 cpuop_func *f;
1922 struct instr *table = &table68k[opcode];
1923
1924 if (table->mnemo == i_ILLG)
1925 continue;
1926
1927 /* unimplemented opcode? */
1928 if (table->unimpclev > 0 && lvl >= table->unimpclev) {
1929 if (currprefs.cpu_model == 68060) {
1930 // remove unimplemented integer instructions
1931 // unimpclev == 5: not implemented in 68060,
1932 // generates unimplemented instruction exception.
1933 if (currprefs.int_no_unimplemented && table->unimpclev == 5) {
1934 cpufunctbl[opcode] = op_unimpl_1;
1935 continue;
1936 }
1937 // remove unimplemented instruction that were removed in previous models,
1938 // generates normal illegal instruction exception.
1939 // unimplclev < 5: instruction was removed in 68040 or previous model.
1940 // clev=4: implemented in 68040 or later. unimpclev=5: not in 68060
1941 if (table->unimpclev < 5 || (table->clev == 4 && table->unimpclev == 5)) {
1942 cpufunctbl[opcode] = op_illg_1;
1943 continue;
1944 }
1945 } else {
1946 cpufunctbl[opcode] = op_illg_1;
1947 continue;
1948 }
1949 }
1950
1951 if (currprefs.fpu_model && currprefs.cpu_model < 68020) {
1952 /* more hack fpu to 68000/68010 mode */
1953 if (table->clev > lvl && (opcode & 0xfe00) != 0xf200)
1954 continue;
1955 } else if (table->clev > lvl) {
1956 continue;
1957 }
1958
1959 if (table->handler != -1) {
1960 int idx = table->handler;
1961 f = cpufunctbl[idx];
1962 if (f == op_illg_1)
1963 abort ();
1964 cpufunctbl[opcode] = f;
1965 memcpy(&cpudatatbl[opcode], &cpudatatbl[idx], sizeof(struct cputbl_data));
1966 opcnt++;
1967 }
1968 }
1969 write_log (_T("Building CPU, %d opcodes (%d %d %d)\n"),
1970 opcnt, lvl,
1971 currprefs.cpu_cycle_exact ? -2 : currprefs.cpu_memory_cycle_exact ? -1 : currprefs.cpu_compatible ? 1 : 0, currprefs.address_space_24);
1972 #ifdef JIT
1973 write_log(_T("JIT: &countdown = %p\n"), &countdown);
1974 write_log(_T("JIT: &build_comp = %p\n"), &build_comp);
1975 build_comp ();
1976 #endif
1977
1978 write_log(_T("CPU=%d, FPU=%d%s, MMU=%d, JIT%s=%d."),
1979 currprefs.cpu_model,
1980 currprefs.fpu_model, currprefs.fpu_model ? (currprefs.fpu_mode > 0 ? _T(" (softfloat)") : (currprefs.fpu_mode < 0 ? _T(" (host 80b)") : _T(" (host 64b)"))) : _T(""),
1981 currprefs.mmu_model,
1982 currprefs.cachesize ? (currprefs.compfpu ? _T("=CPU/FPU") : _T("=CPU")) : _T(""),
1983 currprefs.cachesize);
1984
1985 regs.address_space_mask = 0xffffffff;
1986 #ifndef WINUAE_FOR_HATARI
1987 if (currprefs.cpu_compatible) {
1988 if (currprefs.address_space_24 && currprefs.cpu_model >= 68040)
1989 currprefs.address_space_24 = false;
1990 }
1991 #else
1992 /* Hatari : don't force address_space_24=0 for 68030, as the Falcon has a 68030 LC with only 24 bits */
1993 /* TODO ? Force address_space_24=0 for 68040 ? */
1994 #endif
1995 m68k_interrupt_delay = false;
1996 if (currprefs.cpu_cycle_exact) {
1997 if (tbl == op_smalltbl_14_ff || tbl == op_smalltbl_13_ff || tbl == op_smalltbl_21_ff || tbl == op_smalltbl_23_ff)
1998 m68k_interrupt_delay = true;
1999 }
2000
2001 if (currprefs.cpu_cycle_exact) {
2002 if (currprefs.cpu_model == 68000)
2003 write_log(_T(" prefetch and cycle-exact"));
2004 else
2005 write_log(_T(" ~cycle-exact"));
2006 } else if (currprefs.cpu_memory_cycle_exact) {
2007 write_log(_T(" ~memory-cycle-exact"));
2008 } else if (currprefs.cpu_compatible) {
2009 if (currprefs.cpu_model <= 68020) {
2010 write_log(_T(" prefetch"));
2011 } else {
2012 write_log(_T(" fake prefetch"));
2013 }
2014 }
2015 if (currprefs.m68k_speed < 0)
2016 write_log(_T(" fast"));
2017 if (currprefs.int_no_unimplemented && currprefs.cpu_model == 68060) {
2018 write_log(_T(" no unimplemented integer instructions"));
2019 }
2020 if (currprefs.fpu_no_unimplemented && currprefs.fpu_model) {
2021 write_log(_T(" no unimplemented floating point instructions"));
2022 }
2023 if (currprefs.address_space_24) {
2024 regs.address_space_mask = 0x00ffffff;
2025 write_log(_T(" 24-bit"));
2026 }
2027 write_log(_T("\n"));
2028
2029 set_cpu_caches (true);
2030 #ifndef WINUAE_FOR_HATARI
2031 target_cpu_speed();
2032 #endif
2033 }
2034
2035 #define CYCLES_DIV 8192
2036 static unsigned long cycles_mult;
2037
update_68k_cycles(void)2038 static void update_68k_cycles (void)
2039 {
2040 cycles_mult = 0;
2041 #ifdef WINUAE_FOR_HATARI
2042 Log_Printf(LOG_DEBUG, "update cyc speed %d throttle %f clock_mult %d\n", currprefs.m68k_speed, currprefs.m68k_speed_throttle, changed_prefs.cpu_clock_multiplier);
2043 #else /* Don't adjust cycles_mult in Hatari and ignore m68k_speed (forced to 0) */
2044 if (currprefs.m68k_speed >= 0 && !currprefs.cpu_cycle_exact) {
2045 if (currprefs.m68k_speed_throttle < 0) {
2046 cycles_mult = (unsigned long)(CYCLES_DIV * 1000 / (1000 + currprefs.m68k_speed_throttle));
2047 } else if (currprefs.m68k_speed_throttle > 0) {
2048 cycles_mult = (unsigned long)(CYCLES_DIV * 1000 / (1000 + currprefs.m68k_speed_throttle));
2049 }
2050 }
2051 if (currprefs.m68k_speed == 0) {
2052 if (currprefs.cpu_model >= 68040) {
2053 if (!cycles_mult)
2054 cycles_mult = CYCLES_DIV / 8;
2055 else
2056 cycles_mult /= 8;
2057 } else if (currprefs.cpu_model >= 68020) {
2058 if (!cycles_mult)
2059 cycles_mult = CYCLES_DIV / 4;
2060 else
2061 cycles_mult /= 4;
2062 }
2063 }
2064 #endif
2065
2066 currprefs.cpu_clock_multiplier = changed_prefs.cpu_clock_multiplier;
2067 currprefs.cpu_frequency = changed_prefs.cpu_frequency;
2068
2069 #ifndef WINUAE_FOR_HATARI
2070 baseclock = (currprefs.ntscmode ? CHIPSET_CLOCK_NTSC : CHIPSET_CLOCK_PAL) * 8;
2071 #endif
2072 cpucycleunit = CYCLE_UNIT / 2;
2073 if (currprefs.cpu_clock_multiplier) {
2074 if (currprefs.cpu_clock_multiplier >= 256) {
2075 cpucycleunit = CYCLE_UNIT / (currprefs.cpu_clock_multiplier >> 8);
2076 } else {
2077 cpucycleunit = CYCLE_UNIT * currprefs.cpu_clock_multiplier;
2078 }
2079 if (currprefs.cpu_model >= 68040)
2080 cpucycleunit /= 2;
2081 #ifndef WINUAE_FOR_HATARI /* [NP] TODO : handle any cpu frequency, not just mulltiplier ? */
2082 } else if (currprefs.cpu_frequency) {
2083 cpucycleunit = CYCLE_UNIT * baseclock / currprefs.cpu_frequency;
2084 #endif
2085 } else if (currprefs.cpu_cycle_exact && currprefs.cpu_clock_multiplier == 0) {
2086 if (currprefs.cpu_model >= 68040) {
2087 cpucycleunit = CYCLE_UNIT / 16;
2088 } if (currprefs.cpu_model == 68030) {
2089 cpucycleunit = CYCLE_UNIT / 8;
2090 } else if (currprefs.cpu_model == 68020) {
2091 cpucycleunit = CYCLE_UNIT / 4;
2092 } else {
2093 cpucycleunit = CYCLE_UNIT / 2;
2094 }
2095 }
2096 if (cpucycleunit < 1)
2097 cpucycleunit = 1;
2098 if (currprefs.cpu_cycle_exact)
2099 write_log (_T("CPU cycleunit: %d (%.3f)\n"), cpucycleunit, (float)cpucycleunit / CYCLE_UNIT);
2100 write_log (_T("CPU cycleunit: %d (%.3f)\n"), cpucycleunit, (float)cpucycleunit / CYCLE_UNIT);
2101 #ifndef WINUAE_FOR_HATARI
2102 set_config_changed ();
2103 #endif
2104 }
2105
prefs_changed_cpu(void)2106 static void prefs_changed_cpu (void)
2107 {
2108 fixup_cpu (&changed_prefs);
2109 check_prefs_changed_comp(false);
2110 currprefs.cpu_model = changed_prefs.cpu_model;
2111 currprefs.fpu_model = changed_prefs.fpu_model;
2112 if (currprefs.mmu_model != changed_prefs.mmu_model) {
2113 int oldmmu = currprefs.mmu_model;
2114 currprefs.mmu_model = changed_prefs.mmu_model;
2115 if (currprefs.mmu_model >= 68040) {
2116 uae_u32 tcr = regs.tcr;
2117 mmu_reset();
2118 mmu_set_tc(tcr);
2119 mmu_set_super(regs.s != 0);
2120 mmu_tt_modified();
2121 } else if (currprefs.mmu_model == 68030) {
2122 mmu030_reset(-1);
2123 mmu030_flush_atc_all();
2124 tc_030 = fake_tc_030;
2125 tt0_030 = fake_tt0_030;
2126 tt1_030 = fake_tt1_030;
2127 srp_030 = fake_srp_030;
2128 crp_030 = fake_crp_030;
2129 mmu030_decode_tc(tc_030, false);
2130 } else if (oldmmu == 68030) {
2131 fake_tc_030 = tc_030;
2132 fake_tt0_030 = tt0_030;
2133 fake_tt1_030 = tt1_030;
2134 fake_srp_030 = srp_030;
2135 fake_crp_030 = crp_030;
2136 }
2137 }
2138 currprefs.mmu_ec = changed_prefs.mmu_ec;
2139 if (currprefs.cpu_compatible != changed_prefs.cpu_compatible) {
2140 currprefs.cpu_compatible = changed_prefs.cpu_compatible;
2141 flush_cpu_caches(true);
2142 invalidate_cpu_data_caches();
2143 }
2144 if (currprefs.cpu_data_cache != changed_prefs.cpu_data_cache) {
2145 currprefs.cpu_data_cache = changed_prefs.cpu_data_cache;
2146 invalidate_cpu_data_caches();
2147 }
2148 currprefs.address_space_24 = changed_prefs.address_space_24;
2149 currprefs.cpu_cycle_exact = changed_prefs.cpu_cycle_exact;
2150 currprefs.cpu_memory_cycle_exact = changed_prefs.cpu_memory_cycle_exact;
2151 currprefs.int_no_unimplemented = changed_prefs.int_no_unimplemented;
2152 currprefs.fpu_no_unimplemented = changed_prefs.fpu_no_unimplemented;
2153 currprefs.blitter_cycle_exact = changed_prefs.blitter_cycle_exact;
2154 }
2155
check_prefs_changed_cpu2(void)2156 static int check_prefs_changed_cpu2(void)
2157 {
2158 int changed = 0;
2159
2160 #ifdef JIT
2161 changed = check_prefs_changed_comp(true) ? 1 : 0;
2162 #endif
2163 if (changed
2164 || currprefs.cpu_model != changed_prefs.cpu_model
2165 || currprefs.fpu_model != changed_prefs.fpu_model
2166 || currprefs.mmu_model != changed_prefs.mmu_model
2167 || currprefs.mmu_ec != changed_prefs.mmu_ec
2168 || currprefs.cpu_data_cache != changed_prefs.cpu_data_cache
2169 || currprefs.address_space_24 != changed_prefs.address_space_24 /* WINUAE_FOR_HATARI */
2170 || currprefs.int_no_unimplemented != changed_prefs.int_no_unimplemented
2171 || currprefs.fpu_no_unimplemented != changed_prefs.fpu_no_unimplemented
2172 || currprefs.cpu_compatible != changed_prefs.cpu_compatible
2173 || currprefs.cpu_cycle_exact != changed_prefs.cpu_cycle_exact
2174 || currprefs.cpu_memory_cycle_exact != changed_prefs.cpu_memory_cycle_exact
2175 || currprefs.fpu_mode != changed_prefs.fpu_mode) {
2176 cpu_prefs_changed_flag |= 1;
2177 }
2178 if (changed
2179 || currprefs.m68k_speed != changed_prefs.m68k_speed
2180 || currprefs.m68k_speed_throttle != changed_prefs.m68k_speed_throttle
2181 || currprefs.cpu_clock_multiplier != changed_prefs.cpu_clock_multiplier
2182 || currprefs.reset_delay != changed_prefs.reset_delay
2183 || currprefs.cpu_frequency != changed_prefs.cpu_frequency) {
2184 cpu_prefs_changed_flag |= 2;
2185 }
2186 return cpu_prefs_changed_flag;
2187 }
2188
check_prefs_changed_cpu(void)2189 void check_prefs_changed_cpu(void)
2190 {
2191 #ifndef WINUAE_FOR_HATARI /* [NP] TODO : handle cpu change on the fly ? */
2192 if (!config_changed)
2193 return;
2194 #endif
2195
2196 currprefs.cpu_idle = changed_prefs.cpu_idle;
2197 currprefs.ppc_cpu_idle = changed_prefs.ppc_cpu_idle;
2198 currprefs.reset_delay = changed_prefs.reset_delay;
2199
2200 if (check_prefs_changed_cpu2()) {
2201 set_special(SPCFLAG_MODE_CHANGE);
2202 reset_frame_rate_hack();
2203 }
2204 }
2205
init_m68k(void)2206 void init_m68k (void)
2207 {
2208 prefs_changed_cpu ();
2209 update_68k_cycles ();
2210
2211 for (int i = 0 ; i < 256 ; i++) {
2212 int j;
2213 for (j = 0 ; j < 8 ; j++) {
2214 if (i & (1 << j)) break;
2215 }
2216 movem_index1[i] = j;
2217 movem_index2[i] = 7 - j;
2218 movem_next[i] = i & (~(1 << j));
2219 }
2220
2221 #if COUNT_INSTRS
2222 {
2223 FILE *f = fopen (icountfilename (), "r");
2224 memset (instrcount, 0, sizeof instrcount);
2225 if (f) {
2226 uae_u32 opcode, count, total;
2227 TCHAR name[20];
2228 write_log (_T("Reading instruction count file...\n"));
2229 fscanf (f, "Total: %lu\n", &total);
2230 while (fscanf (f, "%x: %lu %s\n", &opcode, &count, name) == 3) {
2231 instrcount[opcode] = count;
2232 }
2233 fclose (f);
2234 }
2235 }
2236 #endif
2237
2238 read_table68k ();
2239 do_merges ();
2240
2241 write_log (_T("%d CPU functions\n"), nr_cpuop_funcs);
2242 }
2243
2244 struct regstruct regs, mmu_backup_regs;
2245 struct flag_struct regflags;
2246 static int m68kpc_offset;
2247
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
showea_val(TCHAR * buffer,uae_u16 opcode,uaecptr addr,int size)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
2284 #ifndef WINUAE_FOR_HATARI
2285 if (addr >= 0xe90000 && addr < 0xf00000)
2286 goto skip;
2287 if (addr >= 0xdff000 && addr < 0xe00000)
2288 goto skip;
2289 #endif
2290
2291 for (lookup = lookuptab; lookup->mnemo != table->mnemo; lookup++)
2292 ;
2293 if (!(lookup->flags & 1))
2294 goto skip;
2295 buffer += _tcslen(buffer);
2296 if (debug_safe_addr(addr, datasizes[size])) {
2297 bool cached = false;
2298 switch (size)
2299 {
2300 case sz_byte:
2301 {
2302 uae_u8 v = get_byte_cache_debug(addr, &cached);
2303 uae_u8 v2 = v;
2304 if (cached)
2305 v2 = get_byte_debug(addr);
2306 if (v != v2) {
2307 _stprintf(buffer, _T(" [%02x:%02x]"), v, v2);
2308 } else {
2309 _stprintf(buffer, _T(" [%s%02x]"), cached ? _T("*") : _T(""), v);
2310 }
2311 }
2312 break;
2313 case sz_word:
2314 {
2315 uae_u16 v = get_word_cache_debug(addr, &cached);
2316 uae_u16 v2 = v;
2317 if (cached)
2318 v2 = get_word_debug(addr);
2319 if (v != v2) {
2320 _stprintf(buffer, _T(" [%04x:%04x]"), v, v2);
2321 } else {
2322 _stprintf(buffer, _T(" [%s%04x]"), cached ? _T("*") : _T(""), v);
2323 }
2324 }
2325 break;
2326 case sz_long:
2327 {
2328 uae_u32 v = get_long_cache_debug(addr, &cached);
2329 uae_u32 v2 = v;
2330 if (cached)
2331 v2 = get_long_debug(addr);
2332 if (v != v2) {
2333 _stprintf(buffer, _T(" [%08x:%08x]"), v, v2);
2334 } else {
2335 _stprintf(buffer, _T(" [%s%08x]"), cached ? _T("*") : _T(""), v);
2336 }
2337 }
2338 break;
2339 case sz_single:
2340 {
2341 fpdata fp;
2342 fpp_to_single(&fp, get_long_debug(addr));
2343 _stprintf(buffer, _T("[%s]"), fpp_print(&fp, 0));
2344 }
2345 break;
2346 case sz_double:
2347 {
2348 fpdata fp;
2349 fpp_to_double(&fp, get_long_debug(addr), get_long_debug(addr + 4));
2350 _stprintf(buffer, _T("[%s]"), fpp_print(&fp, 0));
2351 }
2352 break;
2353 case sz_extended:
2354 {
2355 fpdata fp;
2356 fpp_to_exten(&fp, get_long_debug(addr), get_long_debug(addr + 4), get_long_debug(addr + 8));
2357 _stprintf(buffer, _T("[%s]"), fpp_print(&fp, 0));
2358 break;
2359 }
2360 case sz_packed:
2361 _stprintf(buffer, _T("[%08x%08x%08x]"), get_long_debug(addr), get_long_debug(addr + 4), get_long_debug(addr + 8));
2362 break;
2363 }
2364 }
2365 skip:
2366 #ifndef WINUAE_FOR_HATARI
2367 for (int i = 0; i < size; i++) {
2368 TCHAR name[256];
2369 if (debugmem_get_symbol(addr + i, name, sizeof(name) / sizeof(TCHAR))) {
2370 _stprintf(buffer + _tcslen(buffer), _T(" %s"), name);
2371 }
2372 }
2373 #else
2374 return;
2375 #endif
2376 }
2377
ShowEA_disp(uaecptr * pcp,uaecptr base,TCHAR * buffer,const TCHAR * name)2378 static uaecptr ShowEA_disp(uaecptr *pcp, uaecptr base, TCHAR *buffer, const TCHAR *name)
2379 {
2380 uaecptr addr;
2381 uae_u16 dp;
2382 int r;
2383 uae_u32 dispreg;
2384 uaecptr pc = *pcp;
2385 TCHAR mult[20];
2386
2387 dp = get_iword_debug(pc);
2388 pc += 2;
2389
2390 r = (dp & 0x7000) >> 12; // REGISTER
2391
2392 dispreg = dp & 0x8000 ? m68k_areg(regs, r) : m68k_dreg(regs, r);
2393 if (!(dp & 0x800)) { // W/L
2394 dispreg = (uae_s32)(uae_s16)(dispreg);
2395 }
2396
2397 if (currprefs.cpu_model >= 68020) {
2398 dispreg <<= (dp >> 9) & 3; // SCALE
2399 }
2400
2401 int m = 1 << ((dp >> 9) & 3);
2402 mult[0] = 0;
2403 if (m > 1) {
2404 _stprintf(mult, _T("*%d"), m);
2405 }
2406
2407 buffer[0] = 0;
2408 if ((dp & 0x100) && currprefs.cpu_model >= 68020) {
2409 TCHAR dr[20];
2410 // Full format extension (68020+)
2411 uae_s32 outer = 0, disp = 0;
2412 if (dp & 0x80) { // BS (base register suppress)
2413 base = 0;
2414 name = NULL;
2415 }
2416 _stprintf(dr, _T("%c%d.%c"), dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W');
2417 if (dp & 0x40) {
2418 dispreg = 0;
2419 dr[0] = 0;
2420 }
2421
2422 _tcscpy(buffer, _T("("));
2423 TCHAR *p = buffer + _tcslen(buffer);
2424
2425 if (dp & 3) {
2426 _stprintf(p, _T("["));
2427 p += _tcslen(p);
2428 }
2429
2430 if ((dp & 0x30) == 0x20) { // BD SIZE = 2 (WORD)
2431 disp = (uae_s32)(uae_s16)get_iword_debug(pc);
2432 _stprintf(p, _T("$%04x,"), (uae_s16)disp);
2433 p += _tcslen(p);
2434 pc += 2;
2435 base += disp;
2436 } else if ((dp & 0x30) == 0x30) { // BD SIZE = 3 (LONG)
2437 disp = get_ilong_debug(pc);
2438 _stprintf(p, _T("$%08x,"), disp);
2439 p += _tcslen(p);
2440 pc += 4;
2441 base += disp;
2442 }
2443
2444 if ((dp & 0x04) == 0x00 && name) {
2445 _stprintf(p, _T("%s,"), name);
2446 p += _tcslen(p);
2447 }
2448
2449 if (dr[0] && (dp & 0x04) == 0) {
2450 _stprintf(p, _T("%s%s,"), dr, mult);
2451 p += _tcslen(p);
2452 }
2453
2454 if (dp & 3) {
2455 if (p[-1] == ',')
2456 p--;
2457 _stprintf(p, _T("],"));
2458 p += _tcslen(p);
2459 }
2460
2461 if (dr[0] && (dp & 0x04) != 0) {
2462 _stprintf(p, _T("%s%s,"), dr, mult);
2463 p += _tcslen(p);
2464 }
2465
2466 if ((dp & 0x03) == 0x02) {
2467 outer = (uae_s32)(uae_s16)get_iword_debug(pc);
2468 _stprintf(p, _T("$%04x,"), (uae_s16)outer);
2469 p += _tcslen(p);
2470 pc += 2;
2471 } else if ((dp & 0x03) == 0x03) {
2472 outer = get_ilong_debug(pc);
2473 _stprintf(p, _T("$%08x,"), outer);
2474 p += _tcslen(p);
2475 pc += 4;
2476 }
2477
2478 if (p[-1] == ',')
2479 p--;
2480 _stprintf(p, _T(")"));
2481 p += _tcslen(p);
2482
2483 if ((dp & 0x4) == 0)
2484 base += dispreg;
2485 if (dp & 0x3)
2486 base = get_long_debug(base);
2487 if (dp & 0x4)
2488 base += dispreg;
2489
2490 addr = base + outer;
2491
2492 _stprintf(p, _T(" == $%08x"), addr);
2493 p += _tcslen(p);
2494
2495 } else {
2496 // Brief format extension
2497 TCHAR regstr[20];
2498 uae_s8 disp8 = dp & 0xFF;
2499
2500 regstr[0] = 0;
2501 _stprintf(regstr, _T(",%c%d.%c"), dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W');
2502 addr = base + (uae_s32)((uae_s8)disp8) + dispreg;
2503 _stprintf(buffer, _T("(%s%s%s,$%02x) == $%08x"), name, regstr, mult, disp8, addr);
2504 if (dp & 0x100) {
2505 _tcscat(buffer, _T(" (68020+)"));
2506 }
2507 }
2508
2509 *pcp = pc;
2510 return addr;
2511 }
2512
ShowEA(void * f,uaecptr pc,uae_u16 opcode,int reg,amodes mode,wordsizes size,TCHAR * buf,uae_u32 * eaddr,int safemode)2513 static uaecptr ShowEA (void *f, uaecptr pc, uae_u16 opcode, int reg, amodes mode, wordsizes size, TCHAR *buf, uae_u32 *eaddr, int safemode)
2514 {
2515 uaecptr addr = pc;
2516 uae_s16 disp16;
2517 uae_s32 offset = 0;
2518 TCHAR buffer[80];
2519
2520 switch (mode){
2521 case Dreg:
2522 _stprintf (buffer, _T("D%d"), reg);
2523 break;
2524 case Areg:
2525 _stprintf (buffer, _T("A%d"), reg);
2526 break;
2527 case Aind:
2528 _stprintf (buffer, _T("(A%d)"), reg);
2529 addr = regs.regs[reg + 8];
2530 showea_val(buffer, opcode, addr, size);
2531 break;
2532 case Aipi:
2533 _stprintf (buffer, _T("(A%d)+"), reg);
2534 addr = regs.regs[reg + 8];
2535 showea_val(buffer, opcode, addr, size);
2536 break;
2537 case Apdi:
2538 _stprintf (buffer, _T("-(A%d)"), reg);
2539 addr = regs.regs[reg + 8];
2540 showea_val(buffer, opcode, addr - datasizes[size], size);
2541 break;
2542 case Ad16:
2543 {
2544 TCHAR offtxt[8];
2545 disp16 = get_iword_debug (pc); pc += 2;
2546 if (disp16 < 0)
2547 _stprintf (offtxt, _T("-$%04x"), -disp16);
2548 else
2549 _stprintf (offtxt, _T("$%04x"), disp16);
2550 addr = m68k_areg (regs, reg) + disp16;
2551 _stprintf (buffer, _T("(A%d,%s) == $%08x"), reg, offtxt, addr);
2552 showea_val(buffer, opcode, addr, size);
2553 }
2554 break;
2555 case Ad8r:
2556 {
2557 TCHAR name[10];
2558 _stprintf(name, _T("A%d"), reg);
2559 addr = ShowEA_disp(&pc, m68k_areg(regs, reg), buffer, name);
2560 showea_val(buffer, opcode, addr, size);
2561 }
2562 break;
2563 case PC16:
2564 disp16 = get_iword_debug (pc); pc += 2;
2565 addr += (uae_s16)disp16;
2566 _stprintf (buffer, _T("(PC,$%04x) == $%08x"), disp16 & 0xffff, addr);
2567 showea_val(buffer, opcode, addr, size);
2568 break;
2569 case PC8r:
2570 {
2571 addr = ShowEA_disp(&pc, addr, buffer, _T("PC"));
2572 showea_val(buffer, opcode, addr, size);
2573 }
2574 break;
2575 case absw:
2576 addr = (uae_s32)(uae_s16)get_iword_debug (pc);
2577 _stprintf (buffer, _T("$%04x"), (uae_u16)addr);
2578 pc += 2;
2579 showea_val(buffer, opcode, addr, size);
2580 break;
2581 case absl:
2582 addr = get_ilong_debug (pc);
2583 _stprintf (buffer, _T("$%08x"), addr);
2584 pc += 4;
2585 showea_val(buffer, opcode, addr, size);
2586 break;
2587 case imm:
2588 switch (size){
2589 case sz_byte:
2590 _stprintf (buffer, _T("#$%02x"), (get_iword_debug (pc) & 0xff));
2591 pc += 2;
2592 break;
2593 case sz_word:
2594 _stprintf (buffer, _T("#$%04x"), (get_iword_debug (pc) & 0xffff));
2595 pc += 2;
2596 break;
2597 case sz_long:
2598 _stprintf(buffer, _T("#$%08x"), (get_ilong_debug(pc)));
2599 pc += 4;
2600 break;
2601 case sz_single:
2602 {
2603 fpdata fp;
2604 fpp_to_single(&fp, get_ilong_debug(pc));
2605 _stprintf(buffer, _T("#%s"), fpp_print(&fp, 0));
2606 pc += 4;
2607 }
2608 break;
2609 case sz_double:
2610 {
2611 fpdata fp;
2612 fpp_to_double(&fp, get_ilong_debug(pc), get_ilong_debug(pc + 4));
2613 _stprintf(buffer, _T("#%s"), fpp_print(&fp, 0));
2614 pc += 8;
2615 }
2616 break;
2617 case sz_extended:
2618 {
2619 fpdata fp;
2620 fpp_to_exten(&fp, get_ilong_debug(pc), get_ilong_debug(pc + 4), get_ilong_debug(pc + 8));
2621 _stprintf(buffer, _T("#%s"), fpp_print(&fp, 0));
2622 pc += 12;
2623 break;
2624 }
2625 case sz_packed:
2626 _stprintf(buffer, _T("#$%08x%08x%08x"), get_ilong_debug(pc), get_ilong_debug(pc + 4), get_ilong_debug(pc + 8));
2627 pc += 12;
2628 break;
2629 default:
2630 break;
2631 }
2632 break;
2633 case imm0:
2634 offset = (uae_s32)(uae_s8)get_iword_debug (pc);
2635 _stprintf (buffer, _T("#$%02x"), (uae_u32)(offset & 0xff));
2636 addr = pc + 2 + offset;
2637 if ((opcode & 0xf000) == 0x6000) {
2638 showea_val(buffer, opcode, addr, 1);
2639 }
2640 pc += 2;
2641 break;
2642 case imm1:
2643 offset = (uae_s32)(uae_s16)get_iword_debug (pc);
2644 buffer[0] = 0;
2645 _stprintf (buffer, _T("#$%04x"), (uae_u32)(offset & 0xffff));
2646 addr = pc + offset;
2647 if ((opcode & 0xf000) == 0x6000) {
2648 showea_val(buffer, opcode, addr, 2);
2649 }
2650 pc += 2;
2651 break;
2652 case imm2:
2653 offset = (uae_s32)get_ilong_debug (pc);
2654 _stprintf (buffer, _T("#$%08x"), (uae_u32)offset);
2655 addr = pc + offset;
2656 if ((opcode & 0xf000) == 0x6000) {
2657 showea_val(buffer, opcode, addr, 4);
2658 }
2659 pc += 4;
2660 break;
2661 case immi:
2662 offset = (uae_s32)(uae_s8)(reg & 0xff);
2663 _stprintf (buffer, _T("#$%02x"), (uae_u8)offset);
2664 addr = pc + offset;
2665 break;
2666 default:
2667 break;
2668 }
2669 if (buf == NULL)
2670 f_out (f, _T("%s"), buffer);
2671 else
2672 _tcscat (buf, buffer);
2673 if (eaddr)
2674 *eaddr = addr;
2675 return pc;
2676 }
2677
2678 #if 0
2679 /* The plan is that this will take over the job of exception 3 handling -
2680 * the CPU emulation functions will just do a longjmp to m68k_go whenever
2681 * they hit an odd address. */
2682 static int verify_ea (int reg, amodes mode, wordsizes size, uae_u32 *val)
2683 {
2684 uae_u16 dp;
2685 uae_s8 disp8;
2686 uae_s16 disp16;
2687 int r;
2688 uae_u32 dispreg;
2689 uaecptr addr;
2690 uae_s32 offset = 0;
2691
2692 switch (mode){
2693 case Dreg:
2694 *val = m68k_dreg (regs, reg);
2695 return 1;
2696 case Areg:
2697 *val = m68k_areg (regs, reg);
2698 return 1;
2699
2700 case Aind:
2701 case Aipi:
2702 addr = m68k_areg (regs, reg);
2703 break;
2704 case Apdi:
2705 addr = m68k_areg (regs, reg);
2706 break;
2707 case Ad16:
2708 disp16 = get_iword_1 (m68kpc_offset); m68kpc_offset += 2;
2709 addr = m68k_areg (regs, reg) + (uae_s16)disp16;
2710 break;
2711 case Ad8r:
2712 addr = m68k_areg (regs, reg);
2713 d8r_common:
2714 dp = get_iword_1 (m68kpc_offset); m68kpc_offset += 2;
2715 disp8 = dp & 0xFF;
2716 r = (dp & 0x7000) >> 12;
2717 dispreg = dp & 0x8000 ? m68k_areg (regs, r) : m68k_dreg (regs, r);
2718 if (!(dp & 0x800)) dispreg = (uae_s32)(uae_s16)(dispreg);
2719 dispreg <<= (dp >> 9) & 3;
2720
2721 if (dp & 0x100) {
2722 uae_s32 outer = 0, disp = 0;
2723 uae_s32 base = addr;
2724 if (dp & 0x80) base = 0;
2725 if (dp & 0x40) dispreg = 0;
2726 if ((dp & 0x30) == 0x20) { disp = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; }
2727 if ((dp & 0x30) == 0x30) { disp = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; }
2728 base += disp;
2729
2730 if ((dp & 0x3) == 0x2) { outer = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; }
2731 if ((dp & 0x3) == 0x3) { outer = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; }
2732
2733 if (!(dp & 4)) base += dispreg;
2734 if (dp & 3) base = get_long (base);
2735 if (dp & 4) base += dispreg;
2736
2737 addr = base + outer;
2738 } else {
2739 addr += (uae_s32)((uae_s8)disp8) + dispreg;
2740 }
2741 break;
2742 case PC16:
2743 addr = m68k_getpc () + m68kpc_offset;
2744 disp16 = get_iword_1 (m68kpc_offset); m68kpc_offset += 2;
2745 addr += (uae_s16)disp16;
2746 break;
2747 case PC8r:
2748 addr = m68k_getpc () + m68kpc_offset;
2749 goto d8r_common;
2750 case absw:
2751 addr = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset);
2752 m68kpc_offset += 2;
2753 break;
2754 case absl:
2755 addr = get_ilong_1 (m68kpc_offset);
2756 m68kpc_offset += 4;
2757 break;
2758 case imm:
2759 switch (size){
2760 case sz_byte:
2761 *val = get_iword_1 (m68kpc_offset) & 0xff;
2762 m68kpc_offset += 2;
2763 break;
2764 case sz_word:
2765 *val = get_iword_1 (m68kpc_offset) & 0xffff;
2766 m68kpc_offset += 2;
2767 break;
2768 case sz_long:
2769 *val = get_ilong_1 (m68kpc_offset);
2770 m68kpc_offset += 4;
2771 break;
2772 default:
2773 break;
2774 }
2775 return 1;
2776 case imm0:
2777 *val = (uae_s32)(uae_s8)get_iword_1 (m68kpc_offset);
2778 m68kpc_offset += 2;
2779 return 1;
2780 case imm1:
2781 *val = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset);
2782 m68kpc_offset += 2;
2783 return 1;
2784 case imm2:
2785 *val = get_ilong_1 (m68kpc_offset);
2786 m68kpc_offset += 4;
2787 return 1;
2788 case immi:
2789 *val = (uae_s32)(uae_s8)(reg & 0xff);
2790 return 1;
2791 default:
2792 addr = 0;
2793 break;
2794 }
2795 if ((addr & 1) == 0)
2796 return 1;
2797
2798 last_addr_for_exception_3 = m68k_getpc () + m68kpc_offset;
2799 last_fault_for_exception_3 = addr;
2800 last_writeaccess_for_exception_3 = 0;
2801 last_instructionaccess_for_exception_3 = 0;
2802 return 0;
2803 }
2804 #endif
2805
get_cpu_model(void)2806 int get_cpu_model (void)
2807 {
2808 return currprefs.cpu_model;
2809 }
2810
2811 #ifndef WINUAE_FOR_HATARI
in_rom(uaecptr pc)2812 STATIC_INLINE int in_rom (uaecptr pc)
2813 {
2814 return (munge24 (pc) & 0xFFF80000) == 0xF80000;
2815 }
2816
in_rtarea(uaecptr pc)2817 STATIC_INLINE int in_rtarea (uaecptr pc)
2818 {
2819 return (munge24 (pc) & 0xFFFF0000) == rtarea_base && (uae_boot_rom_type || currprefs.uaeboard > 0);
2820 }
2821 #endif
2822
wait_memory_cycles(void)2823 STATIC_INLINE void wait_memory_cycles (void)
2824 {
2825 if (regs.memory_waitstate_cycles) {
2826 x_do_cycles(regs.memory_waitstate_cycles);
2827 regs.memory_waitstate_cycles = 0;
2828 }
2829 if (regs.ce020extracycles >= 16) {
2830 regs.ce020extracycles = 0;
2831 x_do_cycles(4 * CYCLE_UNIT);
2832 }
2833 }
2834
adjust_cycles(int cycles)2835 STATIC_INLINE int adjust_cycles (int cycles)
2836 {
2837 int mc = regs.memory_waitstate_cycles;
2838 regs.memory_waitstate_cycles = 0;
2839 if (currprefs.m68k_speed < 0 || cycles_mult == 0)
2840 return cycles + mc;
2841 cycles *= cycles_mult;
2842 cycles /= CYCLES_DIV;
2843 return cycles + mc;
2844 }
2845
m68k_cancel_idle(void)2846 void m68k_cancel_idle(void)
2847 {
2848 #ifndef WINUAE_FOR_HATARI
2849 cpu_last_stop_vpos = -1;
2850 #endif
2851 }
2852
m68k_set_stop(void)2853 static void m68k_set_stop(void)
2854 {
2855 if (regs.stopped)
2856 return;
2857 regs.stopped = 1;
2858 set_special(SPCFLAG_STOP);
2859 #ifndef WINUAE_FOR_HATARI
2860 if (cpu_last_stop_vpos >= 0) {
2861 cpu_last_stop_vpos = vpos;
2862 }
2863 #endif
2864 }
2865
m68k_unset_stop(void)2866 static void m68k_unset_stop(void)
2867 {
2868 regs.stopped = 0;
2869 unset_special(SPCFLAG_STOP);
2870 #ifndef WINUAE_FOR_HATARI
2871 if (cpu_last_stop_vpos >= 0) {
2872 cpu_stopped_lines += vpos - cpu_last_stop_vpos;
2873 cpu_last_stop_vpos = vpos;
2874 }
2875 #endif
2876 }
2877
activate_trace(void)2878 static void activate_trace(void)
2879 {
2880 unset_special (SPCFLAG_TRACE);
2881 set_special (SPCFLAG_DOTRACE);
2882 }
2883
2884 // make sure interrupt is checked immediately after current instruction
doint_imm(void)2885 static void doint_imm(void)
2886 {
2887 doint();
2888 if (!currprefs.cachesize && !(regs.spcflags & SPCFLAG_INT) && (regs.spcflags & SPCFLAG_DOINT))
2889 set_special(SPCFLAG_INT);
2890 }
2891
MakeSR(void)2892 void REGPARAM2 MakeSR (void)
2893 {
2894 regs.sr = ((regs.t1 << 15) | (regs.t0 << 14)
2895 | (regs.s << 13) | (regs.m << 12) | (regs.intmask << 8)
2896 | (GET_XFLG () << 4) | (GET_NFLG () << 3)
2897 | (GET_ZFLG () << 2) | (GET_VFLG () << 1)
2898 | GET_CFLG ());
2899 }
2900
SetSR(uae_u16 sr)2901 static void SetSR (uae_u16 sr)
2902 {
2903 regs.sr &= 0xff00;
2904 regs.sr |= sr;
2905
2906 SET_XFLG ((regs.sr >> 4) & 1);
2907 SET_NFLG ((regs.sr >> 3) & 1);
2908 SET_ZFLG ((regs.sr >> 2) & 1);
2909 SET_VFLG ((regs.sr >> 1) & 1);
2910 SET_CFLG (regs.sr & 1);
2911 }
2912
MakeFromSR_x(int t0trace)2913 static void MakeFromSR_x(int t0trace)
2914 {
2915 int oldm = regs.m;
2916 int olds = regs.s;
2917 int oldt0 = regs.t0;
2918 int oldt1 = regs.t1;
2919
2920 SET_XFLG ((regs.sr >> 4) & 1);
2921 SET_NFLG ((regs.sr >> 3) & 1);
2922 SET_ZFLG ((regs.sr >> 2) & 1);
2923 SET_VFLG ((regs.sr >> 1) & 1);
2924 SET_CFLG (regs.sr & 1);
2925 if (regs.t1 == ((regs.sr >> 15) & 1) &&
2926 regs.t0 == ((regs.sr >> 14) & 1) &&
2927 regs.s == ((regs.sr >> 13) & 1) &&
2928 regs.m == ((regs.sr >> 12) & 1) &&
2929 regs.intmask == ((regs.sr >> 8) & 7))
2930 return;
2931 regs.t1 = (regs.sr >> 15) & 1;
2932 regs.t0 = (regs.sr >> 14) & 1;
2933 regs.s = (regs.sr >> 13) & 1;
2934 regs.m = (regs.sr >> 12) & 1;
2935 regs.intmask = (regs.sr >> 8) & 7;
2936 if (currprefs.cpu_model >= 68020) {
2937 /* 68060 does not have MSP but does have M-bit.. */
2938 if (currprefs.cpu_model >= 68060)
2939 regs.msp = regs.isp;
2940 if (olds != regs.s) {
2941 if (olds) {
2942 if (oldm)
2943 regs.msp = m68k_areg (regs, 7);
2944 else
2945 regs.isp = m68k_areg (regs, 7);
2946 m68k_areg (regs, 7) = regs.usp;
2947 } else {
2948 regs.usp = m68k_areg (regs, 7);
2949 m68k_areg (regs, 7) = regs.m ? regs.msp : regs.isp;
2950 }
2951 } else if (olds && oldm != regs.m) {
2952 if (oldm) {
2953 regs.msp = m68k_areg (regs, 7);
2954 m68k_areg (regs, 7) = regs.isp;
2955 } else {
2956 regs.isp = m68k_areg (regs, 7);
2957 m68k_areg (regs, 7) = regs.msp;
2958 }
2959 }
2960 if (currprefs.cpu_model >= 68060)
2961 regs.t0 = 0;
2962 } else {
2963 regs.t0 = regs.m = 0;
2964 if (olds != regs.s) {
2965 if (olds) {
2966 regs.isp = m68k_areg (regs, 7);
2967 m68k_areg (regs, 7) = regs.usp;
2968 } else {
2969 regs.usp = m68k_areg (regs, 7);
2970 m68k_areg (regs, 7) = regs.isp;
2971 }
2972 }
2973 }
2974 if (currprefs.mmu_model)
2975 mmu_set_super (regs.s != 0);
2976
2977 doint_imm();
2978 if (regs.t1 || regs.t0) {
2979 set_special (SPCFLAG_TRACE);
2980 } else {
2981 /* Keep SPCFLAG_DOTRACE, we still want a trace exception for
2982 SR-modifying instructions (including STOP). */
2983 unset_special (SPCFLAG_TRACE);
2984 }
2985 // Stop SR-modification does not generate T0
2986 // If this SR modification set Tx bit, no trace until next instruction.
2987 if ((oldt0 && t0trace && currprefs.cpu_model >= 68020) || oldt1) {
2988 // Always trace if Tx bits were already set, even if this SR modification cleared them.
2989 activate_trace();
2990 }
2991 }
2992
MakeFromSR_T0(void)2993 void REGPARAM2 MakeFromSR_T0(void)
2994 {
2995 MakeFromSR_x(1);
2996 }
MakeFromSR(void)2997 void REGPARAM2 MakeFromSR(void)
2998 {
2999 MakeFromSR_x(0);
3000 }
3001
exception_check_trace(int nr)3002 static void exception_check_trace (int nr)
3003 {
3004 unset_special (SPCFLAG_TRACE | SPCFLAG_DOTRACE);
3005 if (regs.t1 && !regs.t0) {
3006 /* trace stays pending if exception is div by zero, chk,
3007 * trapv or trap #x
3008 */
3009 if (nr == 5 || nr == 6 || nr == 7 || (nr >= 32 && nr <= 47))
3010 set_special (SPCFLAG_DOTRACE);
3011 }
3012 regs.t1 = regs.t0 = 0;
3013 }
3014
exception_debug(int nr)3015 static void exception_debug (int nr)
3016 {
3017 #ifdef WINUAE_FOR_HATARI
3018 if (unlikely(ExceptionDebugMask & EXCEPT_NOHANDLER) && STMemory_ReadLong(regs.vbr + 4*nr) == 0) {
3019 fprintf(stderr,"Uninitialized exception handler #%i!\n", nr);
3020 DebugUI(REASON_CPU_EXCEPTION);
3021 } else {
3022 DebugUI_Exceptions(nr, M68K_GETPC);
3023 }
3024 #else
3025 #ifdef DEBUGGER
3026 if (!exception_debugging)
3027 return;
3028 console_out_f (_T("Exception %d, PC=%08X\n"), nr, M68K_GETPC);
3029 #endif
3030 #endif
3031 }
3032
3033 #ifdef CPUEMU_13
3034
3035 /* cycle-exact exception handler, 68000 only */
3036
3037 /*
3038
3039 Address/Bus Error:
3040
3041 - 8 idle cycles
3042 - write PC low word
3043 - write SR
3044 - write PC high word
3045 - write instruction word
3046 - write fault address low word
3047 - write status code
3048 - write fault address high word
3049 - 2 idle cycles
3050 - read exception address high word
3051 - read exception address low word
3052 - prefetch
3053 - 2 idle cycles
3054 - prefetch
3055
3056 Division by Zero:
3057
3058 - 8 idle cycles
3059 - write PC low word
3060 - write SR
3061 - write PC high word
3062 - read exception address high word
3063 - read exception address low word
3064 - prefetch
3065 - 2 idle cycles
3066 - prefetch
3067
3068 Traps:
3069
3070 - 4 idle cycles
3071 - write PC low word
3072 - write SR
3073 - write PC high word
3074 - read exception address high word
3075 - read exception address low word
3076 - prefetch
3077 - 2 idle cycles
3078 - prefetch
3079
3080 TrapV:
3081
3082 (- normal prefetch done by TRAPV)
3083 - write PC low word
3084 - write SR
3085 - write PC high word
3086 - read exception address high word
3087 - read exception address low word
3088 - prefetch
3089 - 2 idle cycles
3090 - prefetch
3091
3092 CHK:
3093
3094 - 8 idle cycles
3095 - write PC low word
3096 - write SR
3097 - write PC high word
3098 - read exception address high word
3099 - read exception address low word
3100 - prefetch
3101 - 2 idle cycles
3102 - prefetch
3103
3104 Illegal Instruction:
3105 Privilege violation:
3106 Trace:
3107 Line A:
3108 Line F:
3109
3110 - 4 idle cycles
3111 - write PC low word
3112 - write SR
3113 - write PC high word
3114 - read exception address high word
3115 - read exception address low word
3116 - prefetch
3117 - 2 idle cycles
3118 - prefetch
3119
3120 Interrupt:
3121
3122 - 6 idle cycles
3123 - write PC low word
3124 - read exception number byte from (0xfffff1 | (interrupt number << 1))
3125 - 4 idle cycles
3126 - write SR
3127 - write PC high word
3128 - read exception address high word
3129 - read exception address low word
3130 - prefetch
3131 - 2 idle cycles
3132 - prefetch
3133
3134 */
3135
iack_cycle(int nr)3136 static int iack_cycle(int nr)
3137 {
3138 int vector;
3139
3140 #ifndef WINUAE_FOR_HATARI
3141 if (1) {
3142 // non-autovectored
3143 vector = x_get_byte(0x00fffff1 | ((nr - 24) << 1));
3144 if (currprefs.cpu_cycle_exact)
3145 x_do_cycles(4 * cpucycleunit);
3146 } else {
3147 // autovectored
3148
3149 }
3150 #else
3151 int iack_start = CPU_IACK_CYCLES_START;
3152 int e_cycles;
3153 int cycle_exact = currprefs.cpu_cycle_exact && !currprefs.mmu_model;
3154
3155 /* In cycle exact mode, the cycles before reaching IACK are already counted */
3156 if (cycle_exact)
3157 iack_start = 0;
3158
3159 /* Pending bits / vector number can change before the end of the IACK sequence. */
3160 /* We need to handle MFP/DSP and HBL/VBL cases for this. */
3161 /* - Level 6 (MFP/DSP) use vectored interrupts */
3162 /* - Level 2 (HBL) and 4 (VBL) use auto-vectored interrupts and require sync with E-clock */
3163 vector = nr;
3164 if ( nr == 30 ) /* MFP or DSP */
3165 {
3166 vector = -1;
3167 if (bDspEnabled) /* Check DSP first */
3168 {
3169 /* TODO : For DSP, we just get the vector, we don't add IACK cycles */
3170 vector = DSP_ProcessIACK ();
3171 }
3172
3173 if ( vector < 0 ) /* No DSP, check MFP */
3174 {
3175 if (cycle_exact)
3176 {
3177 x_do_cycles ( ( iack_start + CPU_IACK_CYCLES_MFP ) * cpucycleunit );
3178 /* Flush all CE cycles so far to update PendingInterruptCount */
3179 M68000_AddCycles_CE ( currcycle * 2 / CYCLE_UNIT );
3180 currcycle=0;
3181 }
3182 else
3183 M68000_AddCycles ( iack_start + CPU_IACK_CYCLES_MFP );
3184
3185 CPU_IACK = true;
3186 while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) )
3187 CALL_VAR(PendingInterruptFunction);
3188 vector = MFP_ProcessIACK ( nr );
3189 CPU_IACK = false;
3190 }
3191
3192 if ( vector >= 0 ) /* We have a valid vector for level 6 */
3193 {
3194 /* If a DSP IRQ is pending, we don't clear level 6 pending bit, else the DSP IRQ */
3195 /* will never be processed. If there's no DSP IRQ, we clear level 6 pending bit now */
3196 /* and if there's a lower MFP pending int, level 6 will be set again at the next instruction */
3197 if ( DSP_GetHREQ() == 0 )
3198 pendingInterrupts &= ~( 1 << 6 );
3199 }
3200 }
3201 else if ( ( nr == 26 ) || ( nr == 28 ) ) /* HBL / VBL */
3202 {
3203 if (cycle_exact)
3204 {
3205 /* In CE mode, iack_start = 0, no need to call x_do_cycles() */
3206 //x_do_cycles ( ( iack_start + CPU_IACK_CYCLES_VIDEO_CE + e_cycles ) * cpucycleunit );
3207 /* Flush all CE cycles so far before calling M68000_WaitEClock() */
3208 M68000_AddCycles_CE ( currcycle * 2 / CYCLE_UNIT );
3209 currcycle = 0;
3210 }
3211 else
3212 M68000_AddCycles ( iack_start );
3213
3214 e_cycles = M68000_WaitEClock ();
3215 // fprintf ( stderr , "wait e clock %d\n" , e_cycles);
3216
3217 if (cycle_exact)
3218 {
3219 x_do_cycles ( ( e_cycles + CPU_IACK_CYCLES_VIDEO_CE ) * cpucycleunit );
3220 /* Flush all CE cycles so far to update PendingInterruptCount */
3221 M68000_AddCycles_CE ( currcycle * 2 / CYCLE_UNIT );
3222 currcycle = 0;
3223 }
3224 else
3225 M68000_AddCycles ( e_cycles + CPU_IACK_CYCLES_VIDEO_CE );
3226
3227 CPU_IACK = true;
3228 while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) )
3229 CALL_VAR(PendingInterruptFunction);
3230 if ( MFP_UpdateNeeded == true )
3231 MFP_UpdateIRQ ( 0 ); /* update MFP's state if some internal timers related to MFP expired */
3232 pendingInterrupts &= ~( 1 << ( nr - 24 ) ); /* clear HBL or VBL pending bit (even if an MFP timer occurred during IACK) */
3233 CPU_IACK = false;
3234 }
3235
3236 /* TODO If there was no DSP and no MFP IRQ, then we have a spurious interrupt */
3237 /* In that case, we use vector 24 and we jump to $60 */
3238 if ( vector < 0 )
3239 {
3240 }
3241
3242 /* Add 4 idle cycles for CE mode. For non-CE mode, this will be counted in add_approximate_exception_cycles() */
3243 if (cycle_exact)
3244 x_do_cycles( 4 * cpucycleunit );
3245 #endif
3246 return vector;
3247 }
3248
Exception_ce000(int nr)3249 static void Exception_ce000 (int nr)
3250 {
3251 uae_u32 currpc = m68k_getpc (), newpc;
3252 int sv = regs.s;
3253 int start, interrupt;
3254 int vector_nr = nr;
3255
3256 //fprintf ( stderr , "ex in %d %ld %ld\n" , nr , currcycle , CyclesGlobalClockCounter );
3257 start = 6;
3258 interrupt = nr >= 24 && nr < 24 + 8;
3259 if (!interrupt) {
3260 start = 8;
3261 if (nr == 7) // TRAPV
3262 start = 0;
3263 else if (nr >= 32 && nr < 32 + 16) // TRAP #x
3264 start = 4;
3265 else if (nr == 4 || nr == 8 || nr == 9 || nr == 10 || nr == 11) // ILLG, PRIV, TRACE, LINEA, LINEF
3266 start = 4;
3267 }
3268
3269 if (start)
3270 x_do_cycles (start * cpucycleunit);
3271
3272 #ifdef WINUAE_FOR_HATARI
3273 LOG_TRACE(TRACE_CPU_EXCEPTION, "cpu exception %d currpc %x buspc %x newpc %x fault_e3 %x op_e3 %hx addr_e3 %x SR %x\n",
3274 nr, currpc, regs.instruction_pc, STMemory_ReadLong (regs.vbr + 4*nr), last_fault_for_exception_3, last_op_for_exception_3, last_addr_for_exception_3, regs.sr);
3275 #endif
3276 exception_debug (nr);
3277 MakeSR ();
3278
3279 if (!regs.s) {
3280 regs.usp = m68k_areg (regs, 7);
3281 m68k_areg (regs, 7) = regs.isp;
3282 regs.s = 1;
3283 }
3284 if (nr == 2 || nr == 3) { /* 2=bus error, 3=address error */
3285 if ((m68k_areg(regs, 7) & 1) || exception_in_exception < 0) {
3286 cpu_halt (CPU_HALT_DOUBLE_FAULT);
3287 return;
3288 }
3289 uae_u16 mode = (sv ? 4 : 0) | (last_instructionaccess_for_exception_3 ? 2 : 1);
3290 mode |= last_writeaccess_for_exception_3 ? 0 : 16;
3291 mode |= last_notinstruction_for_exception_3 ? 8 : 0;
3292 // undocumented bits seem to contain opcode
3293 mode |= last_op_for_exception_3 & ~31;
3294 m68k_areg (regs, 7) -= 14;
3295 exception_in_exception = -1;
3296 x_put_word (m68k_areg (regs, 7) + 12, last_addr_for_exception_3);
3297 x_put_word (m68k_areg (regs, 7) + 8, regs.sr);
3298 x_put_word (m68k_areg (regs, 7) + 10, last_addr_for_exception_3 >> 16);
3299 x_put_word (m68k_areg (regs, 7) + 6, last_op_for_exception_3);
3300 x_put_word (m68k_areg (regs, 7) + 4, last_fault_for_exception_3);
3301 x_put_word (m68k_areg (regs, 7) + 0, mode);
3302 x_put_word (m68k_areg (regs, 7) + 2, last_fault_for_exception_3 >> 16);
3303 x_do_cycles (2 * cpucycleunit);
3304 #ifndef WINUAE_FOR_HATARI
3305 write_log (_T("Exception %d (%04x %x) at %x -> %x!\n"),
3306 nr, last_op_for_exception_3, last_addr_for_exception_3, currpc, get_long_debug (4 * nr));
3307 #else
3308 if (nr != 2 || M68000_IsVerboseBusError(currpc, last_fault_for_exception_3))
3309 Log_Printf(LOG_WARN, "%s Error %s at address $%x, PC=$%x addr_e3=%x op_e3=%x\n",
3310 nr == 2 ? "Bus" : "Address",
3311 last_writeaccess_for_exception_3 ? "writing" : "reading",
3312 last_fault_for_exception_3, currpc,
3313 last_addr_for_exception_3 , last_op_for_exception_3);
3314 #endif
3315 goto kludge_me_do;
3316 }
3317 if (currprefs.cpu_model == 68010) {
3318 // 68010 creates only format 0 and 8 stack frames
3319 m68k_areg (regs, 7) -= 8;
3320 if (m68k_areg(regs, 7) & 1) {
3321 exception3_notinstruction(regs.ir, m68k_areg(regs, 7) + 4);
3322 return;
3323 }
3324 exception_in_exception = 1;
3325 x_put_word (m68k_areg (regs, 7) + 4, currpc); // write low address
3326 if (interrupt)
3327 vector_nr = iack_cycle(nr);
3328 x_put_word (m68k_areg (regs, 7) + 0, regs.sr); // write SR
3329 x_put_word (m68k_areg (regs, 7) + 2, currpc >> 16); // write high address
3330 x_put_word (m68k_areg (regs, 7) + 6, vector_nr * 4);
3331 } else {
3332 m68k_areg (regs, 7) -= 6;
3333 if (m68k_areg(regs, 7) & 1) {
3334 exception3_notinstruction(regs.ir, m68k_areg(regs, 7) + 4);
3335 return;
3336 }
3337 exception_in_exception = 1;
3338 x_put_word (m68k_areg (regs, 7) + 4, currpc); // write low address
3339 //fprintf ( stderr , "ex iack1 %d %ld\n" , nr , currcycle );
3340 if (interrupt)
3341 vector_nr = iack_cycle(nr);
3342 //fprintf ( stderr , "ex iack2 %d %ld\n" , nr , currcycle );
3343 x_put_word (m68k_areg (regs, 7) + 0, regs.sr); // write SR
3344 x_put_word (m68k_areg (regs, 7) + 2, currpc >> 16); // write high address
3345 }
3346 kludge_me_do:
3347 newpc = x_get_word (regs.vbr + 4 * vector_nr) << 16; // read high address
3348 newpc |= x_get_word (regs.vbr + 4 * vector_nr + 2); // read low address
3349 exception_in_exception = 0;
3350 if (newpc & 1) {
3351 if (nr == 2 || nr == 3)
3352 cpu_halt (CPU_HALT_DOUBLE_FAULT);
3353 else
3354 exception3_notinstruction(regs.ir, newpc);
3355 return;
3356 }
3357 m68k_setpc (newpc);
3358 if (interrupt)
3359 regs.intmask = nr - 24;
3360 branch_stack_push(currpc, currpc);
3361 regs.ir = x_get_word (m68k_getpc ()); // prefetch 1
3362 x_do_cycles (2 * cpucycleunit);
3363 #ifdef WINUAE_FOR_HATARI
3364 /* [NP] IPL should be updated just before the last x_get_word for irc */
3365 /* (4 cycles before end of exception), so we need to add 2 cycles now */
3366 /* to be aligned on 4 cycles (else the 2 cycles will be added in x_get_word */
3367 /* and IPL will be updated 2 cycles too soon) */
3368 x_do_cycles (2 * cpucycleunit);
3369 /* Add all cycles needed for the exception so far */
3370 M68000_AddCycles_CE ( currcycle * 2 / CYCLE_UNIT );
3371 currcycle = 0;
3372 /* Update IPL / interrupts state, in case a new interrupt happened during this exception */
3373 while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) )
3374 CALL_VAR(PendingInterruptFunction);
3375 #endif
3376 regs.ipl_pin = intlev();
3377 ipl_fetch();
3378 regs.irc = x_get_word (m68k_getpc () + 2); // prefetch 2
3379 #ifdef JIT
3380 set_special (SPCFLAG_END_COMPILE);
3381 #endif
3382 exception_check_trace (nr);
3383
3384 //fprintf ( stderr , "ex out %d %ld\n" , nr , currcycle );
3385 #ifdef WINUAE_FOR_HATARI
3386 /* Add all cycles needed for the exception */
3387 M68000_AddCycles_CE ( currcycle * 2 / CYCLE_UNIT );
3388 currcycle = 0;
3389 #endif
3390 }
3391 #endif
3392
exception_pc(int nr)3393 static uae_u32 exception_pc (int nr)
3394 {
3395 // bus error, address error, illegal instruction, privilege violation, a-line, f-line
3396 if (nr == 2 || nr == 3 || nr == 4 || nr == 8 || nr == 10 || nr == 11)
3397 return regs.instruction_pc;
3398 return m68k_getpc ();
3399 }
3400
Exception_build_stack_frame(uae_u32 oldpc,uae_u32 currpc,uae_u32 ssw,int nr,int format)3401 static void Exception_build_stack_frame (uae_u32 oldpc, uae_u32 currpc, uae_u32 ssw, int nr, int format)
3402 {
3403 int i;
3404
3405 #if 0
3406 if (nr < 24 || nr > 31) { // do not print debugging for interrupts
3407 write_log(_T("Building exception stack frame (format %X)\n"), format);
3408 }
3409 #endif
3410
3411 switch (format) {
3412 case 0x0: // four word stack frame
3413 case 0x1: // throwaway four word stack frame
3414 break;
3415 case 0x2: // six word stack frame
3416 m68k_areg (regs, 7) -= 4;
3417 x_put_long (m68k_areg (regs, 7), oldpc);
3418 break;
3419 case 0x3: // floating point post-instruction stack frame (68040)
3420 m68k_areg (regs, 7) -= 4;
3421 x_put_long (m68k_areg (regs, 7), regs.fp_ea);
3422 break;
3423 case 0x7: // access error stack frame (68040)
3424
3425 for (i = 3; i >= 0; i--) {
3426 // WB1D/PD0,PD1,PD2,PD3
3427 m68k_areg (regs, 7) -= 4;
3428 x_put_long (m68k_areg (regs, 7), mmu040_move16[i]);
3429 }
3430
3431 m68k_areg (regs, 7) -= 4;
3432 x_put_long (m68k_areg (regs, 7), 0); // WB1A
3433 m68k_areg (regs, 7) -= 4;
3434 x_put_long (m68k_areg (regs, 7), 0); // WB2D
3435 m68k_areg (regs, 7) -= 4;
3436 x_put_long (m68k_areg (regs, 7), regs.wb2_address); // WB2A
3437 m68k_areg (regs, 7) -= 4;
3438 x_put_long (m68k_areg (regs, 7), regs.wb3_data); // WB3D
3439 m68k_areg (regs, 7) -= 4;
3440 x_put_long (m68k_areg (regs, 7), regs.mmu_fault_addr); // WB3A
3441
3442 m68k_areg (regs, 7) -= 4;
3443 x_put_long (m68k_areg (regs, 7), regs.mmu_fault_addr); // FA
3444
3445 m68k_areg (regs, 7) -= 2;
3446 x_put_word (m68k_areg (regs, 7), 0);
3447 m68k_areg (regs, 7) -= 2;
3448 x_put_word (m68k_areg (regs, 7), regs.wb2_status);
3449 regs.wb2_status = 0;
3450 m68k_areg (regs, 7) -= 2;
3451 x_put_word (m68k_areg (regs, 7), regs.wb3_status);
3452 regs.wb3_status = 0;
3453
3454 m68k_areg (regs, 7) -= 2;
3455 x_put_word (m68k_areg (regs, 7), ssw);
3456 m68k_areg (regs, 7) -= 4;
3457 x_put_long (m68k_areg (regs, 7), regs.mmu_effective_addr);
3458 break;
3459 case 0x9: // coprocessor mid-instruction stack frame (68020, 68030)
3460 m68k_areg (regs, 7) -= 4;
3461 x_put_long (m68k_areg (regs, 7), regs.fp_ea);
3462 m68k_areg (regs, 7) -= 4;
3463 x_put_long (m68k_areg (regs, 7), regs.fp_opword);
3464 m68k_areg (regs, 7) -= 4;
3465 x_put_long (m68k_areg (regs, 7), oldpc);
3466 break;
3467 case 0x8: // bus and address error stack frame (68010)
3468 write_log(_T("Exception stack frame format %X not implemented\n"), format);
3469 return;
3470 case 0x4: // floating point unimplemented stack frame (68LC040, 68EC040)
3471 // or 68060 bus access fault stack frame
3472 m68k_areg (regs, 7) -= 4;
3473 x_put_long (m68k_areg (regs, 7), ssw);
3474 m68k_areg (regs, 7) -= 4;
3475 x_put_long (m68k_areg (regs, 7), oldpc);
3476 break;
3477 case 0xB: // long bus cycle fault stack frame (68020, 68030)
3478 // We always use B frame because it is easier to emulate,
3479 // our PC always points at start of instruction but A frame assumes
3480 // it is + 2 and handling this properly is not easy.
3481 // Store state information to internal register space
3482 #if MMU030_DEBUG
3483 if (mmu030_idx >= MAX_MMU030_ACCESS) {
3484 write_log(_T("mmu030_idx out of bounds! %d >= %d\n"), mmu030_idx, MAX_MMU030_ACCESS);
3485 }
3486 #endif
3487 if (!(ssw & MMU030_SSW_RW)) {
3488 mmu030_ad[mmu030_idx].val = regs.wb3_data;
3489 }
3490 for (i = 0; i < mmu030_idx + 1; i++) {
3491 m68k_areg (regs, 7) -= 4;
3492 x_put_long (m68k_areg (regs, 7), mmu030_ad[i].val);
3493 }
3494 while (i < MAX_MMU030_ACCESS) {
3495 uae_u32 v = 0;
3496 m68k_areg (regs, 7) -= 4;
3497 // mmu030_idx is always small enough if instruction is FMOVEM.
3498 if (mmu030_state[1] & MMU030_STATEFLAG1_FMOVEM) {
3499 #if MMU030_DEBUG
3500 if (mmu030_idx >= MAX_MMU030_ACCESS - 2) {
3501 write_log(_T("mmu030_idx (FMOVEM) out of bounds! %d >= %d\n"), mmu030_idx, MAX_MMU030_ACCESS - 2);
3502 }
3503 #endif
3504 if (i == MAX_MMU030_ACCESS - 2)
3505 v = mmu030_fmovem_store[0];
3506 else if (i == MAX_MMU030_ACCESS - 1)
3507 v = mmu030_fmovem_store[1];
3508 }
3509 x_put_long (m68k_areg (regs, 7), v);
3510 i++;
3511 }
3512 // version & internal information (We store index here)
3513 m68k_areg (regs, 7) -= 2;
3514 x_put_word (m68k_areg (regs, 7), mmu030_idx);
3515 // 3* internal registers
3516 m68k_areg (regs, 7) -= 2;
3517 x_put_word (m68k_areg (regs, 7), mmu030_state[2]);
3518 m68k_areg (regs, 7) -= 2;
3519 x_put_word (m68k_areg(regs, 7), regs.wb2_address); // = mmu030_state[1]
3520 m68k_areg (regs, 7) -= 2;
3521 x_put_word (m68k_areg (regs, 7), mmu030_state[0]);
3522 // data input buffer = fault address
3523 m68k_areg (regs, 7) -= 4;
3524 x_put_long (m68k_areg (regs, 7), regs.mmu_fault_addr);
3525 // 2xinternal
3526 {
3527 uae_u32 ps = (regs.prefetch020_valid[0] ? 1 : 0) | (regs.prefetch020_valid[1] ? 2 : 0) | (regs.prefetch020_valid[2] ? 4 : 0);
3528 ps |= ((regs.pipeline_r8[0] & 7) << 8);
3529 ps |= ((regs.pipeline_r8[1] & 7) << 11);
3530 ps |= ((regs.pipeline_pos & 15) << 16);
3531 ps |= ((regs.pipeline_stop & 15) << 20);
3532 if (mmu030_opcode == -1)
3533 ps |= 1 << 31;
3534 m68k_areg (regs, 7) -= 4;
3535 x_put_long (m68k_areg (regs, 7), ps);
3536 }
3537 // stage b address
3538 m68k_areg (regs, 7) -= 4;
3539 x_put_long (m68k_areg (regs, 7), mm030_stageb_address);
3540 // 2xinternal
3541 m68k_areg (regs, 7) -= 4;
3542 x_put_long (m68k_areg (regs, 7), mmu030_disp_store[1]);
3543 /* fall through */
3544 case 0xA: // short bus cycle fault stack frame (68020, 68030)
3545 m68k_areg (regs, 7) -= 4;
3546 x_put_long (m68k_areg (regs, 7), mmu030_disp_store[0]);
3547 m68k_areg (regs, 7) -= 4;
3548 // Data output buffer = value that was going to be written
3549 x_put_long (m68k_areg (regs, 7), regs.wb3_data);
3550 m68k_areg (regs, 7) -= 4;
3551 x_put_long (m68k_areg (regs, 7), (mmu030_opcode & 0xffff) | (regs.prefetch020[0] << 16)); // Internal register (opcode storage)
3552 m68k_areg (regs, 7) -= 4;
3553 x_put_long (m68k_areg (regs, 7), regs.mmu_fault_addr); // data cycle fault address
3554 m68k_areg (regs, 7) -= 2;
3555 x_put_word (m68k_areg (regs, 7), regs.prefetch020[2]); // Instr. pipe stage B
3556 m68k_areg (regs, 7) -= 2;
3557 x_put_word (m68k_areg (regs, 7), regs.prefetch020[1]); // Instr. pipe stage C
3558 m68k_areg (regs, 7) -= 2;
3559 x_put_word (m68k_areg (regs, 7), ssw);
3560 m68k_areg (regs, 7) -= 2;
3561 x_put_word (m68k_areg (regs, 7), 0); // Internal register
3562 break;
3563 default:
3564 write_log(_T("Unknown exception stack frame format: %X\n"), format);
3565 return;
3566 }
3567 m68k_areg (regs, 7) -= 2;
3568 x_put_word (m68k_areg (regs, 7), (format << 12) | (nr * 4));
3569 m68k_areg (regs, 7) -= 4;
3570 x_put_long (m68k_areg (regs, 7), currpc);
3571 m68k_areg (regs, 7) -= 2;
3572 x_put_word (m68k_areg (regs, 7), regs.sr);
3573 }
3574
Exception_build_stack_frame_common(uae_u32 oldpc,uae_u32 currpc,uae_u32 ssw,int nr)3575 static void Exception_build_stack_frame_common (uae_u32 oldpc, uae_u32 currpc, uae_u32 ssw, int nr)
3576 {
3577 if (nr == 5 || nr == 6 || nr == 7 || nr == 9) {
3578 Exception_build_stack_frame(oldpc, currpc, regs.mmu_ssw, nr, 0x2);
3579 } else if (nr == 60 || nr == 61) {
3580 Exception_build_stack_frame(oldpc, regs.instruction_pc, regs.mmu_ssw, nr, 0x0);
3581 } else if (nr >= 48 && nr <= 55) {
3582 if (regs.fpu_exp_pre) {
3583 if (currprefs.cpu_model == 68060 && nr == 55 && regs.fp_unimp_pend == 2) { // packed decimal real
3584 Exception_build_stack_frame(regs.fp_ea, regs.instruction_pc, 0, nr, 0x2);
3585 } else {
3586 Exception_build_stack_frame(oldpc, regs.instruction_pc, 0, nr, 0x0);
3587 }
3588 } else { /* post-instruction */
3589 if (currprefs.cpu_model == 68060 && nr == 55 && regs.fp_unimp_pend == 2) { // packed decimal real
3590 Exception_build_stack_frame(regs.fp_ea, currpc, 0, nr, 0x2);
3591 } else {
3592 Exception_build_stack_frame(oldpc, currpc, 0, nr, 0x3);
3593 }
3594 }
3595 } else if (nr == 11 && regs.fp_unimp_ins) {
3596 regs.fp_unimp_ins = false;
3597 if ((currprefs.cpu_model == 68060 && (currprefs.fpu_model == 0 || (regs.pcr & 2))) ||
3598 (currprefs.cpu_model == 68040 && currprefs.fpu_model == 0)) {
3599 Exception_build_stack_frame(regs.fp_ea, currpc, regs.instruction_pc, nr, 0x4);
3600 } else {
3601 Exception_build_stack_frame(regs.fp_ea, currpc, regs.mmu_ssw, nr, 0x2);
3602 }
3603 } else {
3604 Exception_build_stack_frame(oldpc, currpc, regs.mmu_ssw, nr, 0x0);
3605 }
3606 }
3607
3608 // 68030 MMU
Exception_mmu030(int nr,uaecptr oldpc)3609 static void Exception_mmu030 (int nr, uaecptr oldpc)
3610 {
3611 uae_u32 currpc = m68k_getpc (), newpc;
3612 int interrupt;
3613
3614 interrupt = nr >= 24 && nr < 24 + 8;
3615
3616 #ifdef WINUAE_FOR_HATARI
3617 if (interrupt)
3618 nr = iack_cycle(nr);
3619 #endif
3620
3621 #ifdef WINUAE_FOR_HATARI
3622 LOG_TRACE(TRACE_CPU_EXCEPTION, "cpu exception %d currpc %x buspc %x newpc %x fault_e3 %x op_e3 %hx addr_e3 %x SR %x\n",
3623 nr, currpc, regs.instruction_pc, STMemory_ReadLong (regs.vbr + 4*nr), last_fault_for_exception_3, last_op_for_exception_3, last_addr_for_exception_3, regs.sr);
3624 #endif
3625 exception_debug (nr);
3626 MakeSR ();
3627
3628 if (!regs.s) {
3629 regs.usp = m68k_areg (regs, 7);
3630 m68k_areg(regs, 7) = regs.m ? regs.msp : regs.isp;
3631 regs.s = 1;
3632 mmu_set_super (1);
3633 }
3634
3635 #if 0
3636 if (nr < 24 || nr > 31) { // do not print debugging for interrupts
3637 write_log (_T("Exception_mmu030: Exception %i: %08x %08x %08x\n"),
3638 nr, currpc, oldpc, regs.mmu_fault_addr);
3639 }
3640 #endif
3641
3642 newpc = x_get_long (regs.vbr + 4 * nr);
3643
3644 #if 0
3645 write_log (_T("Exception %d -> %08x\n"), nr, newpc);
3646 #endif
3647
3648 if (regs.m && interrupt) { /* M + Interrupt */
3649 Exception_build_stack_frame (oldpc, currpc, regs.mmu_ssw, nr, 0x0);
3650 MakeSR ();
3651 regs.m = 0;
3652 regs.msp = m68k_areg (regs, 7);
3653 m68k_areg (regs, 7) = regs.isp;
3654 Exception_build_stack_frame (oldpc, currpc, regs.mmu_ssw, nr, 0x1);
3655 } else if (nr == 2) {
3656 Exception_build_stack_frame (oldpc, currpc, regs.mmu_ssw, nr, 0xB);
3657 } else if (nr == 3) {
3658 regs.mmu_fault_addr = last_fault_for_exception_3;
3659 mmu030_state[0] = mmu030_state[1] = 0;
3660 mmu030_data_buffer_out = 0;
3661 Exception_build_stack_frame (last_fault_for_exception_3, currpc, MMU030_SSW_RW | MMU030_SSW_SIZE_W | (regs.s ? 6 : 2), nr, 0xA);
3662 } else {
3663 Exception_build_stack_frame_common(oldpc, currpc, regs.mmu_ssw, nr);
3664 }
3665
3666 if (newpc & 1) {
3667 if (nr == 2 || nr == 3)
3668 cpu_halt (CPU_HALT_DOUBLE_FAULT);
3669 else
3670 exception3_read(regs.ir, newpc);
3671 return;
3672 }
3673 if (interrupt)
3674 regs.intmask = nr - 24;
3675 m68k_setpci (newpc);
3676 fill_prefetch ();
3677 exception_check_trace (nr);
3678 }
3679
3680 // 68040/060 MMU
Exception_mmu(int nr,uaecptr oldpc)3681 static void Exception_mmu (int nr, uaecptr oldpc)
3682 {
3683 uae_u32 currpc = m68k_getpc (), newpc;
3684 int interrupt;
3685
3686 interrupt = nr >= 24 && nr < 24 + 8;
3687
3688 // exception vector fetch and exception stack frame
3689 // operations don't allocate new cachelines
3690 cache_default_data |= CACHE_DISABLE_ALLOCATE;
3691
3692 #ifdef WINUAE_FOR_HATARI
3693 if (interrupt)
3694 nr = iack_cycle(nr);
3695 #endif
3696
3697 #ifdef WINUAE_FOR_HATARI
3698 LOG_TRACE(TRACE_CPU_EXCEPTION, "cpu exception %d currpc %x buspc %x newpc %x fault_e3 %x op_e3 %hx addr_e3 %x SR %x\n",
3699 nr, currpc, regs.instruction_pc, STMemory_ReadLong (regs.vbr + 4*nr), last_fault_for_exception_3, last_op_for_exception_3, last_addr_for_exception_3, regs.sr);
3700 #endif
3701 exception_debug (nr);
3702 MakeSR ();
3703
3704 if (!regs.s) {
3705 regs.usp = m68k_areg (regs, 7);
3706 if (currprefs.cpu_model >= 68020 && currprefs.cpu_model < 68060) {
3707 m68k_areg (regs, 7) = regs.m ? regs.msp : regs.isp;
3708 } else {
3709 m68k_areg (regs, 7) = regs.isp;
3710 }
3711 regs.s = 1;
3712 mmu_set_super (1);
3713 }
3714
3715 newpc = x_get_long (regs.vbr + 4 * nr);
3716 #if 0
3717 write_log (_T("Exception %d: %08x -> %08x\n"), nr, currpc, newpc);
3718 #endif
3719
3720 if (nr == 2) { // bus error
3721 //write_log (_T("Exception_mmu %08x %08x %08x\n"), currpc, oldpc, regs.mmu_fault_addr);
3722 if (currprefs.mmu_model == 68040)
3723 Exception_build_stack_frame(oldpc, currpc, regs.mmu_ssw, nr, 0x7);
3724 else
3725 Exception_build_stack_frame(regs.mmu_fault_addr, currpc, regs.mmu_fslw, nr, 0x4);
3726 } else if (nr == 3) { // address error
3727 Exception_build_stack_frame(last_fault_for_exception_3, currpc, 0, nr, 0x2);
3728 write_log (_T("Exception %d (%x) at %x -> %x!\n"), nr, last_fault_for_exception_3, currpc, get_long_debug (regs.vbr + 4 * nr));
3729 } else if (regs.m && interrupt) { /* M + Interrupt */
3730 Exception_build_stack_frame(oldpc, currpc, regs.mmu_ssw, nr, 0x0);
3731 MakeSR();
3732 regs.m = 0;
3733 if (currprefs.cpu_model < 68060) {
3734 regs.msp = m68k_areg(regs, 7);
3735 Exception_build_stack_frame(oldpc, currpc, regs.mmu_ssw, nr, 0x1);
3736 }
3737 } else {
3738 Exception_build_stack_frame_common(oldpc, currpc, regs.mmu_ssw, nr);
3739 }
3740
3741 if (newpc & 1) {
3742 if (nr == 2 || nr == 3)
3743 cpu_halt (CPU_HALT_DOUBLE_FAULT);
3744 else
3745 exception3_read(regs.ir, newpc);
3746 return;
3747 }
3748
3749 cache_default_data &= ~CACHE_DISABLE_ALLOCATE;
3750
3751 m68k_setpci (newpc);
3752 if (interrupt)
3753 regs.intmask = nr - 24;
3754 fill_prefetch ();
3755 exception_check_trace (nr);
3756 }
3757
add_approximate_exception_cycles(int nr)3758 static void add_approximate_exception_cycles(int nr)
3759 {
3760 int cycles;
3761
3762 if (currprefs.cpu_model > 68000)
3763 return;
3764 #ifndef WINUAE_FOR_HATARI
3765 if (nr >= 24 && nr <= 31) {
3766 /* Interrupts */
3767 cycles = 44 + 4;
3768 #else
3769 if ( nr >= 24 && nr <= 31 ) {
3770 /* Atari's specific interrupts take 56 cycles instead of 44 due to iack sequence */
3771 /* We must subtract CPU_IACK_CYCLES_START cycles already counted into iack_cycle() */
3772 if ( nr == 30 ) /* MFP/DSP */
3773 cycles = 44-CPU_IACK_CYCLES_START;
3774 else if ( nr == 28 ) /* VBL */
3775 cycles = 44-CPU_IACK_CYCLES_START;
3776 else if ( nr == 26 ) /* HBL */
3777 cycles = 44-CPU_IACK_CYCLES_START;
3778 else
3779 cycles = 44+4; /* Other interrupts (not used in Atari machines) */
3780 #endif
3781 } else if (nr >= 32 && nr <= 47) {
3782 /* Trap (total is 34, but cpuemux.c already adds 4) */
3783 cycles = 34 -4;
3784 } else {
3785 switch (nr)
3786 {
3787 case 2: cycles = 50; break; /* Bus error */
3788 case 3: cycles = 50; break; /* Address error */
3789 case 4: cycles = 34; break; /* Illegal instruction */
3790 case 5: cycles = 38; break; /* Division by zero */
3791 case 6: cycles = 40; break; /* CHK */
3792 case 7: cycles = 34; break; /* TRAPV */
3793 case 8: cycles = 34; break; /* Privilege violation */
3794 case 9: cycles = 34; break; /* Trace */
3795 case 10: cycles = 34; break; /* Line-A */
3796 case 11: cycles = 34; break; /* Line-F */
3797 default:
3798 cycles = 4;
3799 break;
3800 }
3801 }
3802 #ifdef WINUAE_FOR_HATARI
3803 M68000_AddCycles ( cycles );
3804 #endif
3805 cycles = adjust_cycles(cycles * CYCLE_UNIT / 2);
3806 x_do_cycles(cycles);
3807 }
3808
3809 static void Exception_normal (int nr)
3810 {
3811 uae_u32 newpc;
3812 uae_u32 currpc = m68k_getpc();
3813 uae_u32 nextpc;
3814 int sv = regs.s;
3815 int interrupt;
3816 int vector_nr = nr;
3817
3818 cache_default_data |= CACHE_DISABLE_ALLOCATE;
3819
3820 interrupt = nr >= 24 && nr < 24 + 8;
3821
3822 #ifndef WINUAE_FOR_HATARI
3823 if (interrupt && currprefs.cpu_model <= 68010)
3824 #else
3825 if (interrupt)
3826 #endif
3827 vector_nr = iack_cycle(nr);
3828
3829 exception_debug (nr);
3830 MakeSR ();
3831
3832 if (!regs.s) {
3833 regs.usp = m68k_areg (regs, 7);
3834 if (currprefs.cpu_model >= 68020 && currprefs.cpu_model < 68060) {
3835 m68k_areg (regs, 7) = regs.m ? regs.msp : regs.isp;
3836 } else {
3837 m68k_areg (regs, 7) = regs.isp;
3838 }
3839 regs.s = 1;
3840 if (currprefs.mmu_model)
3841 mmu_set_super (regs.s != 0);
3842 }
3843
3844 if ((m68k_areg(regs, 7) & 1) && currprefs.cpu_model < 68020) {
3845 if (nr == 2 || nr == 3)
3846 cpu_halt (CPU_HALT_DOUBLE_FAULT);
3847 else
3848 exception3_notinstruction(regs.ir, m68k_areg(regs, 7));
3849 return;
3850 }
3851 if ((nr == 2 || nr == 3) && exception_in_exception < 0) {
3852 cpu_halt (CPU_HALT_DOUBLE_FAULT);
3853 return;
3854 }
3855
3856 #ifndef WINUAE_FOR_HATARI
3857 if (!currprefs.cpu_compatible) {
3858 addrbank *ab = &get_mem_bank(m68k_areg(regs, 7) - 4);
3859 // Not plain RAM check because some CPU type tests that
3860 // don't need to return set stack to ROM..
3861 if (!ab || ab == &dummy_bank || (ab->flags & ABFLAG_IO)) {
3862 cpu_halt(CPU_HALT_SSP_IN_NON_EXISTING_ADDRESS);
3863 return;
3864 }
3865 }
3866 #endif
3867
3868 bool used_exception_build_stack_frame = false;
3869
3870 if (currprefs.cpu_model > 68000) {
3871 uae_u32 oldpc = regs.instruction_pc;
3872 nextpc = exception_pc (nr);
3873 #ifdef WINUAE_FOR_HATARI
3874 LOG_TRACE(TRACE_CPU_EXCEPTION, "cpu exception %d vector %x currpc %x buspc %x newpc %x fault_e3 %x op_e3 %hx addr_e3 %x SR %x\n",
3875 nr, 4*vector_nr , currpc, regs.instruction_pc, STMemory_ReadLong (regs.vbr + 4*vector_nr), last_fault_for_exception_3, last_op_for_exception_3, last_addr_for_exception_3, regs.sr);
3876 #endif
3877 if (nr == 2 || nr == 3) {
3878 int i;
3879 if (currprefs.cpu_model >= 68040) {
3880 if (nr == 2) {
3881 if (currprefs.mmu_model) {
3882 // 68040 mmu bus error
3883 for (i = 0 ; i < 7 ; i++) {
3884 m68k_areg (regs, 7) -= 4;
3885 x_put_long (m68k_areg (regs, 7), 0);
3886 }
3887 m68k_areg (regs, 7) -= 4;
3888 x_put_long (m68k_areg (regs, 7), regs.wb3_data);
3889 m68k_areg (regs, 7) -= 4;
3890 x_put_long (m68k_areg (regs, 7), regs.mmu_fault_addr);
3891 m68k_areg (regs, 7) -= 4;
3892 x_put_long (m68k_areg (regs, 7), regs.mmu_fault_addr);
3893 m68k_areg (regs, 7) -= 2;
3894 x_put_word (m68k_areg (regs, 7), 0);
3895 m68k_areg (regs, 7) -= 2;
3896 x_put_word (m68k_areg (regs, 7), 0);
3897 m68k_areg (regs, 7) -= 2;
3898 x_put_word (m68k_areg (regs, 7), regs.wb3_status);
3899 regs.wb3_status = 0;
3900 m68k_areg (regs, 7) -= 2;
3901 x_put_word (m68k_areg (regs, 7), regs.mmu_ssw);
3902 m68k_areg (regs, 7) -= 4;
3903 x_put_long (m68k_areg (regs, 7), regs.mmu_fault_addr);
3904
3905 m68k_areg (regs, 7) -= 2;
3906 x_put_word (m68k_areg (regs, 7), 0x7000 + vector_nr * 4);
3907 m68k_areg (regs, 7) -= 4;
3908 x_put_long (m68k_areg (regs, 7), regs.instruction_pc);
3909 m68k_areg (regs, 7) -= 2;
3910 x_put_word (m68k_areg (regs, 7), regs.sr);
3911 newpc = x_get_long (regs.vbr + 4 * vector_nr);
3912 if (newpc & 1) {
3913 if (nr == 2 || nr == 3)
3914 cpu_halt (CPU_HALT_DOUBLE_FAULT);
3915 else
3916 exception3_read(regs.ir, newpc);
3917 return;
3918 }
3919 m68k_setpc (newpc);
3920 #ifdef JIT
3921 set_special (SPCFLAG_END_COMPILE);
3922 #endif
3923 exception_check_trace (nr);
3924 return;
3925
3926 } else {
3927
3928 // 68040 bus error (not really, some garbage?)
3929 for (i = 0 ; i < 18 ; i++) {
3930 m68k_areg (regs, 7) -= 2;
3931 x_put_word (m68k_areg (regs, 7), 0);
3932 }
3933 m68k_areg (regs, 7) -= 4;
3934 x_put_long (m68k_areg (regs, 7), last_fault_for_exception_3);
3935 m68k_areg (regs, 7) -= 2;
3936 x_put_word (m68k_areg (regs, 7), 0);
3937 m68k_areg (regs, 7) -= 2;
3938 x_put_word (m68k_areg (regs, 7), 0);
3939 m68k_areg (regs, 7) -= 2;
3940 x_put_word (m68k_areg (regs, 7), 0);
3941 m68k_areg (regs, 7) -= 2;
3942 x_put_word (m68k_areg (regs, 7), 0x0140 | (sv ? 6 : 2)); /* SSW */
3943 m68k_areg (regs, 7) -= 4;
3944 x_put_long (m68k_areg (regs, 7), last_addr_for_exception_3);
3945 m68k_areg (regs, 7) -= 2;
3946 x_put_word (m68k_areg (regs, 7), 0x7000 + vector_nr * 4);
3947 m68k_areg (regs, 7) -= 4;
3948 x_put_long (m68k_areg (regs, 7), regs.instruction_pc);
3949 m68k_areg (regs, 7) -= 2;
3950 x_put_word (m68k_areg (regs, 7), regs.sr);
3951 goto kludge_me_do;
3952
3953 }
3954
3955 } else {
3956 m68k_areg (regs, 7) -= 4;
3957 x_put_long (m68k_areg (regs, 7), last_fault_for_exception_3);
3958 m68k_areg (regs, 7) -= 2;
3959 x_put_word (m68k_areg (regs, 7), 0x2000 + vector_nr * 4);
3960 }
3961 } else {
3962 // 68020 address error
3963 uae_u16 ssw = (sv ? 4 : 0) | (last_instructionaccess_for_exception_3 ? 2 : 1);
3964 ssw |= last_writeaccess_for_exception_3 ? 0 : 0x40;
3965 ssw |= 0x20;
3966 for (i = 0 ; i < 36; i++) {
3967 m68k_areg (regs, 7) -= 2;
3968 x_put_word (m68k_areg (regs, 7), 0);
3969 }
3970 m68k_areg (regs, 7) -= 4;
3971 x_put_long (m68k_areg (regs, 7), last_fault_for_exception_3);
3972 m68k_areg (regs, 7) -= 2;
3973 x_put_word (m68k_areg (regs, 7), 0);
3974 m68k_areg (regs, 7) -= 2;
3975 x_put_word (m68k_areg (regs, 7), 0);
3976 m68k_areg (regs, 7) -= 2;
3977 x_put_word (m68k_areg (regs, 7), 0);
3978 m68k_areg (regs, 7) -= 2;
3979 x_put_word (m68k_areg (regs, 7), ssw);
3980 m68k_areg (regs, 7) -= 2;
3981 x_put_word (m68k_areg (regs, 7), 0xb000 + vector_nr * 4);
3982 }
3983 #ifndef WINUAE_FOR_HATARI
3984 write_log (_T("Exception %d (%x) at %x -> %x!\n"), nr, regs.instruction_pc, currpc, get_long_debug (regs.vbr + 4 * vector_nr));
3985 #else
3986 if (nr != 2 || M68000_IsVerboseBusError(currpc, last_fault_for_exception_3))
3987 Log_Printf(LOG_WARN, "%s Error %s at address $%x, PC=$%x addr_e3=%x op_e3=%x\n",
3988 nr == 2 ? "Bus" : "Address",
3989 last_writeaccess_for_exception_3 ? "writing" : "reading",
3990 last_fault_for_exception_3, currpc,
3991 last_addr_for_exception_3, last_op_for_exception_3);
3992 #endif
3993 } else if (regs.m && interrupt) { /* M + Interrupt */
3994 m68k_areg (regs, 7) -= 2;
3995 x_put_word (m68k_areg (regs, 7), vector_nr * 4);
3996 if (currprefs.cpu_model < 68060) {
3997 m68k_areg (regs, 7) -= 4;
3998 x_put_long (m68k_areg (regs, 7), currpc);
3999 m68k_areg (regs, 7) -= 2;
4000 x_put_word (m68k_areg (regs, 7), regs.sr);
4001 regs.sr |= (1 << 13);
4002 regs.msp = m68k_areg(regs, 7);
4003 regs.m = 0;
4004 m68k_areg(regs, 7) = regs.isp;
4005 m68k_areg (regs, 7) -= 2;
4006 x_put_word (m68k_areg (regs, 7), 0x1000 + vector_nr * 4);
4007 }
4008 } else {
4009 Exception_build_stack_frame_common(oldpc, currpc, regs.mmu_ssw, nr);
4010 used_exception_build_stack_frame = true;
4011 }
4012 } else {
4013 add_approximate_exception_cycles(nr);
4014 nextpc = m68k_getpc ();
4015 #ifdef WINUAE_FOR_HATARI
4016 LOG_TRACE(TRACE_CPU_EXCEPTION, "cpu exception %d vector %x currpc %x buspc %x newpc %x fault_e3 %x op_e3 %hx addr_e3 %x SR %x\n",
4017 nr, 4*vector_nr , currpc, regs.instruction_pc, STMemory_ReadLong (regs.vbr + 4*vector_nr), last_fault_for_exception_3, last_op_for_exception_3, last_addr_for_exception_3, regs.sr);
4018 #endif
4019 if (nr == 2 || nr == 3) {
4020 // 68000 address error
4021 uae_u16 mode = (sv ? 4 : 0) | (last_instructionaccess_for_exception_3 ? 2 : 1);
4022 mode |= last_writeaccess_for_exception_3 ? 0 : 16;
4023 mode |= last_notinstruction_for_exception_3 ? 8 : 0;
4024 // undocumented bits seem to contain opcode
4025 mode |= last_op_for_exception_3 & ~31;
4026 m68k_areg (regs, 7) -= 14;
4027 exception_in_exception = -1;
4028 x_put_word (m68k_areg (regs, 7) + 0, mode);
4029 x_put_long (m68k_areg (regs, 7) + 2, last_fault_for_exception_3);
4030 x_put_word (m68k_areg (regs, 7) + 6, last_op_for_exception_3);
4031 x_put_word (m68k_areg (regs, 7) + 8, regs.sr);
4032 x_put_long (m68k_areg (regs, 7) + 10, last_addr_for_exception_3);
4033 #ifndef WINUAE_FOR_HATARI
4034 write_log (_T("Exception %d (%x) at %x -> %x!\n"), nr, last_fault_for_exception_3, currpc, get_long_debug (regs.vbr + 4 * vector_nr));
4035 #else
4036 if (nr != 2 || M68000_IsVerboseBusError(currpc, last_fault_for_exception_3))
4037 Log_Printf(LOG_WARN, "%s Error %s at address $%x, PC=$%x addr_e3=%x op_e3=%x\n",
4038 nr == 2 ? "Bus" : "Address",
4039 last_writeaccess_for_exception_3 ? "writing" : "reading",
4040 last_fault_for_exception_3, currpc,
4041 last_addr_for_exception_3, last_op_for_exception_3);
4042 #endif
4043 goto kludge_me_do;
4044 }
4045 }
4046 if (!used_exception_build_stack_frame) {
4047 m68k_areg (regs, 7) -= 4;
4048 x_put_long (m68k_areg (regs, 7), nextpc);
4049 m68k_areg (regs, 7) -= 2;
4050 x_put_word (m68k_areg (regs, 7), regs.sr);
4051 }
4052 if (currprefs.cpu_model == 68060 && interrupt) {
4053 regs.m = 0;
4054 }
4055 kludge_me_do:
4056 newpc = x_get_long (regs.vbr + 4 * vector_nr);
4057 exception_in_exception = 0;
4058 if (newpc & 1) {
4059 if (nr == 2 || nr == 3)
4060 cpu_halt (CPU_HALT_DOUBLE_FAULT);
4061 else
4062 exception3_notinstruction(regs.ir, newpc);
4063 return;
4064 }
4065 if (interrupt)
4066 regs.intmask = nr - 24;
4067 m68k_setpc (newpc);
4068 cache_default_data &= ~CACHE_DISABLE_ALLOCATE;
4069 #ifdef WINUAE_FOR_HATARI
4070 /* Update IPL / interrupts state, in case a new interrupt happened during this exception */
4071 while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) )
4072 CALL_VAR(PendingInterruptFunction);
4073 #endif
4074 #ifdef JIT
4075 set_special (SPCFLAG_END_COMPILE);
4076 #endif
4077 branch_stack_push(currpc, nextpc);
4078 fill_prefetch ();
4079 exception_check_trace (nr);
4080 }
4081
4082 // address = format $2 stack frame address field
4083 static void ExceptionX (int nr, uaecptr address)
4084 {
4085 uaecptr pc = m68k_getpc();
4086 regs.exception = nr;
4087 if (cpu_tracer) {
4088 cputrace.state = nr;
4089 }
4090 if (!regs.s) {
4091 regs.instruction_pc_user_exception = pc;
4092 }
4093
4094 #ifdef WINUAE_FOR_HATARI
4095 /* Handle Hatari GEM and BIOS traps */
4096 if (nr == 0x22) {
4097 /* Intercept VDI & AES exceptions (Trap #2) */
4098 if (bVdiAesIntercept && VDI_AES_Entry()) {
4099 /* Set 'PC' to address of 'VDI_OPCODE' illegal instruction.
4100 * This will call OpCode_VDI() after completion of Trap call!
4101 * Used to modify specific VDI return vectors contents. */
4102 VDI_OldPC = m68k_getpc();
4103 m68k_setpc(CART_VDI_OPCODE_ADDR);
4104 }
4105 }
4106 else if (nr == 0x2d) {
4107 /* Intercept BIOS (Trap #13) calls */
4108 if (Bios()) {
4109 fill_prefetch ();
4110 regs.exception = 0;
4111 return;
4112 }
4113 }
4114 else if (nr == 0x2e) {
4115 /* Intercept XBIOS (Trap #14) calls */
4116 if (XBios()) {
4117 fill_prefetch ();
4118 regs.exception = 0;
4119 return;
4120 }
4121 }
4122 #endif
4123
4124 #ifdef JIT
4125 if (currprefs.cachesize)
4126 regs.instruction_pc = address == -1 ? pc : address;
4127 #endif
4128
4129 #ifndef WINUAE_FOR_HATARI
4130 if (debug_illegal && !in_rom(pc)) {
4131 if (nr <= 63 && (debug_illegal_mask & ((uae_u64)1 << nr))) {
4132 write_log(_T("Exception %d breakpoint\n"), nr);
4133 activate_debugger();
4134 }
4135 }
4136 #endif
4137
4138 #ifdef CPUEMU_13
4139 if (currprefs.cpu_cycle_exact && currprefs.cpu_model <= 68010)
4140 Exception_ce000 (nr);
4141 else
4142 #endif
4143 if (currprefs.mmu_model) {
4144 if (currprefs.cpu_model == 68030)
4145 Exception_mmu030 (nr, m68k_getpc ());
4146 else
4147 Exception_mmu (nr, m68k_getpc ());
4148 } else {
4149 Exception_normal (nr);
4150 }
4151
4152 regs.exception = 0;
4153 if (cpu_tracer) {
4154 cputrace.state = 0;
4155 }
4156 }
4157
4158 void REGPARAM2 Exception_cpu(int nr)
4159 {
4160 bool t0 = currprefs.cpu_model >= 68020 && regs.t0;
4161 ExceptionX (nr, -1);
4162 // check T0 trace
4163 if (t0) {
4164 activate_trace();
4165 }
4166 }
4167 void REGPARAM2 Exception (int nr)
4168 {
4169 ExceptionX (nr, -1);
4170 }
4171 void REGPARAM2 ExceptionL (int nr, uaecptr address)
4172 {
4173 ExceptionX (nr, address);
4174 }
4175
4176 static void bus_error(void)
4177 {
4178 TRY (prb2) {
4179 Exception (2);
4180 } CATCH (prb2) {
4181 cpu_halt (CPU_HALT_BUS_ERROR_DOUBLE_FAULT);
4182 } ENDTRY
4183 }
4184
4185 static void do_interrupt (int nr)
4186 {
4187 #ifndef WINUAE_FOR_HATARI
4188 if (debug_dma)
4189 record_dma_event (DMA_EVENT_CPUIRQ, current_hpos (), vpos);
4190
4191 if (inputrecord_debug & 2) {
4192 if (input_record > 0)
4193 inprec_recorddebug_cpu (2);
4194 else if (input_play > 0)
4195 inprec_playdebug_cpu (2);
4196 }
4197 #endif
4198
4199 m68k_unset_stop();
4200 assert (nr < 8 && nr >= 0);
4201
4202 for (;;) {
4203 Exception (nr + 24);
4204 if (!currprefs.cpu_compatible || currprefs.cpu_model == 68060)
4205 break;
4206 if (m68k_interrupt_delay)
4207 nr = regs.ipl;
4208 else
4209 nr = intlev();
4210 if (nr <= 0 || regs.intmask >= nr)
4211 break;
4212 }
4213
4214 doint ();
4215 }
4216
4217 void NMI (void)
4218 {
4219 do_interrupt (7);
4220 }
4221
4222 static void m68k_reset_sr(void)
4223 {
4224 SET_XFLG ((regs.sr >> 4) & 1);
4225 SET_NFLG ((regs.sr >> 3) & 1);
4226 SET_ZFLG ((regs.sr >> 2) & 1);
4227 SET_VFLG ((regs.sr >> 1) & 1);
4228 SET_CFLG (regs.sr & 1);
4229 regs.t1 = (regs.sr >> 15) & 1;
4230 regs.t0 = (regs.sr >> 14) & 1;
4231 regs.s = (regs.sr >> 13) & 1;
4232 regs.m = (regs.sr >> 12) & 1;
4233 regs.intmask = (regs.sr >> 8) & 7;
4234 /* set stack pointer */
4235 if (regs.s)
4236 m68k_areg (regs, 7) = regs.isp;
4237 else
4238 m68k_areg (regs, 7) = regs.usp;
4239 }
4240
4241 static void m68k_reset2(bool hardreset)
4242 {
4243 uae_u32 v;
4244
4245 //fprintf ( stderr,"m68k_reset2 hard=%d in pc=%x\n" , hardreset , regs.pc );
4246 regs.halted = 0;
4247 #ifndef WINUAE_FOR_HATARI
4248 gui_data.cpu_halted = 0;
4249 gui_led (LED_CPU, 0, -1);
4250 #endif
4251
4252 regs.spcflags = 0;
4253 m68k_reset_delay = 0;
4254 regs.ipl = regs.ipl_pin = 0;
4255 #ifndef WINUAE_FOR_HATARI
4256 for (int i = 0; i < IRQ_SOURCE_MAX; i++) {
4257 uae_interrupts2[i] = 0;
4258 uae_interrupts6[i] = 0;
4259 uae_interrupt = 0;
4260 }
4261 #endif
4262
4263 #ifdef SAVESTATE
4264 if (isrestore ()) {
4265 m68k_reset_sr();
4266 m68k_setpc_normal (regs.pc);
4267 return;
4268 } else {
4269 m68k_reset_delay = currprefs.reset_delay;
4270 set_special(SPCFLAG_CHECK);
4271 }
4272 #endif
4273 regs.s = 1;
4274 #ifndef WINUAE_FOR_HATARI
4275 if (currprefs.cpuboard_type) {
4276 uaecptr stack;
4277 v = cpuboard_get_reset_pc(&stack);
4278 m68k_areg (regs, 7) = stack;
4279 } else {
4280 v = get_long (4);
4281 m68k_areg (regs, 7) = get_long (0);
4282 }
4283 #else
4284 v = get_long (4);
4285 m68k_areg (regs, 7) = get_long (0);
4286 #endif
4287
4288 m68k_setpc_normal(v);
4289 regs.m = 0;
4290 regs.stopped = 0;
4291 regs.t1 = 0;
4292 regs.t0 = 0;
4293 SET_ZFLG (0);
4294 SET_XFLG (0);
4295 SET_CFLG (0);
4296 SET_VFLG (0);
4297 SET_NFLG (0);
4298 regs.intmask = 7;
4299 regs.vbr = regs.sfc = regs.dfc = 0;
4300 regs.irc = 0xffff;
4301 #ifdef FPUEMU
4302 fpu_reset ();
4303 #endif
4304 regs.caar = regs.cacr = 0;
4305 regs.itt0 = regs.itt1 = regs.dtt0 = regs.dtt1 = 0;
4306 regs.tcr = regs.mmusr = regs.urp = regs.srp = regs.buscr = 0;
4307 mmu_tt_modified ();
4308 if (currprefs.cpu_model == 68020) {
4309 regs.cacr |= 8;
4310 set_cpu_caches (false);
4311 }
4312
4313 mmufixup[0].reg = -1;
4314 mmufixup[1].reg = -1;
4315 mmu030_cache_state = CACHE_ENABLE_ALL;
4316 mmu_cache_state = CACHE_ENABLE_ALL;
4317 if (currprefs.cpu_model >= 68040) {
4318 set_cpu_caches(false);
4319 }
4320 if (currprefs.mmu_model >= 68040) {
4321 mmu_reset ();
4322 mmu_set_tc (regs.tcr);
4323 mmu_set_super (regs.s != 0);
4324 } else if (currprefs.mmu_model == 68030) {
4325 mmu030_reset (hardreset || regs.halted);
4326 } else {
4327 #ifndef WINUAE_FOR_HATARI
4328 a3000_fakekick (0);
4329 #endif
4330 /* only (E)nable bit is zeroed when CPU is reset, A3000 SuperKickstart expects this */
4331 fake_tc_030 &= ~0x80000000;
4332 fake_tt0_030 &= ~0x80000000;
4333 fake_tt1_030 &= ~0x80000000;
4334 if (hardreset || regs.halted) {
4335 fake_srp_030 = fake_crp_030 = 0;
4336 fake_tt0_030 = fake_tt1_030 = fake_tc_030 = 0;
4337 }
4338 fake_mmusr_030 = 0;
4339 }
4340
4341 /* 68060 FPU is not compatible with 68040,
4342 * 68060 accelerators' boot ROM disables the FPU
4343 */
4344 regs.pcr = 0;
4345 if (currprefs.cpu_model == 68060) {
4346 regs.pcr = currprefs.fpu_model == 68060 ? MC68060_PCR : MC68EC060_PCR;
4347 regs.pcr |= (currprefs.cpu060_revision & 0xff) << 8;
4348 #ifndef WINUAE_FOR_HATARI
4349 if (currprefs.fpu_model == 0 || (currprefs.cpuboard_type == 0 && rtarea_base != 0xf00000)) {
4350 /* disable FPU if no accelerator board and no $f0 ROM */
4351 regs.pcr |= 2;
4352 }
4353 #endif
4354 }
4355 // regs.ce020memcycles = 0;
4356 regs.ce020startcycle = regs.ce020endcycle = 0;
4357 fill_prefetch ();
4358 //fprintf ( stderr,"m68k_reset2 out pc=%x\n" , regs.pc );
4359 }
4360
4361 void m68k_reset(void)
4362 {
4363 m68k_reset2(false);
4364 }
4365
4366 #ifndef WINUAE_FOR_HATARI
4367 void cpu_change(int newmodel)
4368 {
4369 if (newmodel == currprefs.cpu_model)
4370 return;
4371 fallback_new_cpu_model = newmodel;
4372 cpu_halt(CPU_HALT_ACCELERATOR_CPU_FALLBACK);
4373 }
4374
4375 void cpu_fallback(int mode)
4376 {
4377 int fallbackmodel;
4378 if (currprefs.chipset_mask & CSMASK_AGA) {
4379 fallbackmodel = 68020;
4380 } else {
4381 fallbackmodel = 68000;
4382 }
4383 if (mode < 0) {
4384 if (currprefs.cpu_model > fallbackmodel) {
4385 cpu_change(fallbackmodel);
4386 } else if (fallback_new_cpu_model) {
4387 cpu_change(fallback_new_cpu_model);
4388 }
4389 } else if (mode == 0) {
4390 cpu_change(fallbackmodel);
4391 } else if (mode) {
4392 if (fallback_cpu_model) {
4393 cpu_change(fallback_cpu_model);
4394 }
4395 }
4396 }
4397
4398 static void cpu_do_fallback(void)
4399 {
4400 bool fallbackmode = false;
4401 if ((fallback_new_cpu_model < 68020 && !(currprefs.chipset_mask & CSMASK_AGA)) || (fallback_new_cpu_model == 68020 && (currprefs.chipset_mask & CSMASK_AGA))) {
4402 // -> 68000/68010 or 68EC020
4403 fallback_cpu_model = currprefs.cpu_model;
4404 fallback_fpu_model = currprefs.fpu_model;
4405 fallback_mmu_model = currprefs.mmu_model;
4406 fallback_cpu_compatible = currprefs.cpu_compatible;
4407 fallback_cpu_address_space_24 = currprefs.address_space_24;
4408 changed_prefs.cpu_model = currprefs.cpu_model_fallback && fallback_new_cpu_model <= 68020 ? currprefs.cpu_model_fallback : fallback_new_cpu_model;
4409 changed_prefs.fpu_model = 0;
4410 changed_prefs.mmu_model = 0;
4411 changed_prefs.cpu_compatible = true;
4412 changed_prefs.address_space_24 = true;
4413 memcpy(&fallback_regs, ®s, sizeof(struct regstruct));
4414 fallback_regs.pc = M68K_GETPC;
4415 fallbackmode = true;
4416 } else {
4417 // -> 68020+
4418 changed_prefs.cpu_model = fallback_cpu_model;
4419 changed_prefs.fpu_model = fallback_fpu_model;
4420 changed_prefs.mmu_model = fallback_mmu_model;
4421 changed_prefs.cpu_compatible = fallback_cpu_compatible;
4422 changed_prefs.address_space_24 = fallback_cpu_address_space_24;
4423 fallback_cpu_model = 0;
4424 }
4425 init_m68k();
4426 m68k_reset2(false);
4427 if (!fallbackmode) {
4428 // restore original 68020+
4429 memcpy(®s, &fallback_regs, sizeof(regs));
4430 restore_banks();
4431 memory_restore();
4432 memory_map_dump();
4433 m68k_setpc(fallback_regs.pc);
4434 } else {
4435 // 68000/010/EC020
4436 memory_restore();
4437 expansion_cpu_fallback();
4438 memory_map_dump();
4439 }
4440 }
4441 #endif
4442
4443 static void m68k_reset_restore(void)
4444 {
4445 #ifndef WINUAE_FOR_HATARI
4446 // hardreset and 68000/68020 fallback mode? Restore original mode.
4447 if (fallback_cpu_model) {
4448 fallback_new_cpu_model = fallback_cpu_model;
4449 fallback_regs.pc = 0;
4450 cpu_do_fallback();
4451 }
4452 #endif
4453 }
4454
4455 void REGPARAM2 op_unimpl (uae_u16 opcode)
4456 {
4457 static int warned;
4458 if (warned < 20) {
4459 write_log (_T("68060 unimplemented opcode %04X, PC=%08x\n"), opcode, regs.instruction_pc);
4460 warned++;
4461 }
4462 ExceptionL (61, regs.instruction_pc);
4463 }
4464
4465 uae_u32 REGPARAM2 op_illg (uae_u32 opcode)
4466 {
4467 uaecptr pc = m68k_getpc ();
4468 static int warned;
4469
4470 #ifndef WINUAE_FOR_HATARI
4471 int inrom = in_rom (pc);
4472 int inrt = in_rtarea (pc);
4473
4474 if ((opcode == 0x4afc || opcode == 0xfc4a) && !valid_address(pc, 4) && valid_address(pc - 4, 4)) {
4475 // PC fell off the end of RAM
4476 bus_error();
4477 return 4;
4478 }
4479
4480 if (debugmem_illg(opcode)) {
4481 m68k_incpc_normal(2);
4482 return 4;
4483 }
4484
4485 if (cloanto_rom && (opcode & 0xF100) == 0x7100) {
4486 m68k_dreg (regs, (opcode >> 9) & 7) = (uae_s8)(opcode & 0xFF);
4487 m68k_incpc_normal (2);
4488 fill_prefetch ();
4489 return 4;
4490 }
4491
4492 if (opcode == 0x4E7B && inrom) {
4493 if (get_long (0x10) == 0) {
4494 notify_user (NUMSG_KS68020);
4495 uae_restart (-1, NULL);
4496 m68k_setstopped();
4497 return 4;
4498 }
4499 }
4500
4501 #ifdef AUTOCONFIG
4502 if (opcode == 0xFF0D && inrt) {
4503 /* User-mode STOP replacement */
4504 m68k_setstopped ();
4505 return 4;
4506 }
4507
4508 if ((opcode & 0xF000) == 0xA000 && inrt) {
4509 /* Calltrap. */
4510 m68k_incpc_normal (2);
4511 m68k_handle_trap(opcode & 0xFFF);
4512 fill_prefetch ();
4513 return 4;
4514 }
4515 #endif
4516 #endif
4517
4518 if ((opcode & 0xF000) == 0xF000) {
4519 #ifndef WINUAE_FOR_HATARI
4520 if (warned < 20) {
4521 write_log(_T("B-Trap %04X at %08X -> %08X\n"), opcode, pc, get_long_debug(regs.vbr + 0x2c));
4522 warned++;
4523 }
4524 #endif
4525 Exception (0xB);
4526 //activate_debugger_new();
4527 return 4;
4528 }
4529 if ((opcode & 0xF000) == 0xA000) {
4530 #ifndef WINUAE_FOR_HATARI
4531 if (warned < 20) {
4532 write_log(_T("A-Trap %04X at %08X -> %08X\n"), opcode, pc, get_long_debug(regs.vbr + 0x28));
4533 warned++;
4534 }
4535 #endif
4536 Exception (0xA);
4537 //activate_debugger_new();
4538 return 4;
4539 }
4540 if (warned < 20) {
4541 write_log (_T("Illegal instruction: %04x at %08X -> %08X\n"), opcode, pc, get_long_debug(regs.vbr + 0x10));
4542 warned++;
4543 //activate_debugger_new();
4544 }
4545
4546 Exception (4);
4547 return 4;
4548 }
4549
4550 #ifdef CPUEMU_0
4551
4552 static bool mmu_op30_invea(uae_u32 opcode)
4553 {
4554 int eamode = (opcode >> 3) & 7;
4555 int rreg = opcode & 7;
4556
4557 // Dn, An, (An)+, -(An), immediate and PC-relative not allowed
4558 if (eamode == 0 || eamode == 1 || eamode == 3 || eamode == 4 || (eamode == 7 && rreg > 1))
4559 return true;
4560 return false;
4561 }
4562
4563 static bool mmu_op30fake_pmove (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra)
4564 {
4565 int preg = (next >> 10) & 31;
4566 int rw = (next >> 9) & 1;
4567 int fd = (next >> 8) & 1;
4568 int unused = (next & 0xff);
4569 const TCHAR *reg = NULL;
4570 #ifndef WINUAE_FOR_HATARI
4571 uae_u32 otc = fake_tc_030;
4572 #endif
4573 int siz;
4574
4575 if (mmu_op30_invea(opcode))
4576 return true;
4577 // unused low 8 bits must be zeroed
4578 if (unused)
4579 return true;
4580 // read and fd set?
4581 if (rw && fd)
4582 return true;
4583
4584 switch (preg)
4585 {
4586 case 0x10: // TC
4587 reg = _T("TC");
4588 siz = 4;
4589 if (rw)
4590 x_put_long (extra, fake_tc_030);
4591 else
4592 fake_tc_030 = x_get_long (extra);
4593 break;
4594 case 0x12: // SRP
4595 reg = _T("SRP");
4596 siz = 8;
4597 if (rw) {
4598 x_put_long (extra, fake_srp_030 >> 32);
4599 x_put_long (extra + 4, (uae_u32)fake_srp_030);
4600 } else {
4601 fake_srp_030 = (uae_u64)x_get_long (extra) << 32;
4602 fake_srp_030 |= x_get_long (extra + 4);
4603 }
4604 break;
4605 case 0x13: // CRP
4606 reg = _T("CRP");
4607 siz = 8;
4608 if (rw) {
4609 x_put_long (extra, fake_crp_030 >> 32);
4610 x_put_long (extra + 4, (uae_u32)fake_crp_030);
4611 } else {
4612 fake_crp_030 = (uae_u64)x_get_long (extra) << 32;
4613 fake_crp_030 |= x_get_long (extra + 4);
4614 }
4615 break;
4616 case 0x18: // MMUSR
4617 if (fd) {
4618 // FD must be always zero when MMUSR read or write
4619 return true;
4620 }
4621 reg = _T("MMUSR");
4622 siz = 2;
4623 if (rw)
4624 x_put_word (extra, fake_mmusr_030);
4625 else
4626 fake_mmusr_030 = x_get_word (extra);
4627 break;
4628 case 0x02: // TT0
4629 reg = _T("TT0");
4630 siz = 4;
4631 if (rw)
4632 x_put_long (extra, fake_tt0_030);
4633 else
4634 fake_tt0_030 = x_get_long (extra);
4635 break;
4636 case 0x03: // TT1
4637 reg = _T("TT1");
4638 siz = 4;
4639 if (rw)
4640 x_put_long (extra, fake_tt1_030);
4641 else
4642 fake_tt1_030 = x_get_long (extra);
4643 break;
4644 }
4645
4646 if (!reg)
4647 return true;
4648
4649 #if MMUOP_DEBUG > 0
4650 {
4651 uae_u32 val;
4652 if (siz == 8) {
4653 uae_u32 val2 = x_get_long (extra);
4654 val = x_get_long (extra + 4);
4655 if (rw)
4656 write_log (_T("PMOVE %s,%08X%08X"), reg, val2, val);
4657 else
4658 write_log (_T("PMOVE %08X%08X,%s"), val2, val, reg);
4659 } else {
4660 if (siz == 4)
4661 val = x_get_long (extra);
4662 else
4663 val = x_get_word (extra);
4664 if (rw)
4665 write_log (_T("PMOVE %s,%08X"), reg, val);
4666 else
4667 write_log (_T("PMOVE %08X,%s"), val, reg);
4668 }
4669 write_log (_T(" PC=%08X\n"), pc);
4670 }
4671 #endif
4672 #ifndef WINUAE_FOR_HATARI
4673 if ((currprefs.cs_mbdmac & 1) && currprefs.mbresmem_low_size > 0) {
4674 if (otc != fake_tc_030) {
4675 a3000_fakekick (fake_tc_030 & 0x80000000);
4676 }
4677 }
4678 #endif
4679 return false;
4680 }
4681
4682 static bool mmu_op30fake_ptest (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra)
4683 {
4684 int eamode = (opcode >> 3) & 7;
4685 int rreg = opcode & 7;
4686 int level = (next&0x1C00)>>10;
4687 int a = (next >> 8) & 1;
4688
4689 if (mmu_op30_invea(opcode))
4690 return true;
4691 if (!level && a)
4692 return true;
4693
4694 #if MMUOP_DEBUG > 0
4695 TCHAR tmp[10];
4696
4697 tmp[0] = 0;
4698 if ((next >> 8) & 1)
4699 _stprintf (tmp, _T(",A%d"), (next >> 4) & 15);
4700 write_log (_T("PTEST%c %02X,%08X,#%X%s PC=%08X\n"),
4701 ((next >> 9) & 1) ? 'W' : 'R', (next & 15), extra, (next >> 10) & 7, tmp, pc);
4702 #endif
4703 fake_mmusr_030 = 0;
4704 return false;
4705 }
4706
4707 static bool mmu_op30fake_pload (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra)
4708 {
4709 int unused = (next & (0x100 | 0x80 | 0x40 | 0x20));
4710
4711 if (mmu_op30_invea(opcode))
4712 return true;
4713 if (unused)
4714 return true;
4715 write_log(_T("PLOAD\n"));
4716 return false;
4717 }
4718
4719 static bool mmu_op30fake_pflush (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra)
4720 {
4721 int flushmode = (next >> 8) & 31;
4722 int fc = next & 31;
4723 int mask = (next >> 5) & 3;
4724 int fc_bits = next & 0x7f;
4725 TCHAR fname[100];
4726
4727 switch (flushmode)
4728 {
4729 case 0x00:
4730 case 0x02:
4731 return mmu_op30fake_pload(pc, opcode, next, extra);
4732 case 0x18:
4733 if (mmu_op30_invea(opcode))
4734 return true;
4735 _stprintf (fname, _T("FC=%x MASK=%x EA=%08x"), fc, mask, 0);
4736 break;
4737 case 0x10:
4738 _stprintf (fname, _T("FC=%x MASK=%x"), fc, mask);
4739 break;
4740 case 0x04:
4741 if (fc_bits)
4742 return true;
4743 _tcscpy (fname, _T("ALL"));
4744 break;
4745 default:
4746 return true;
4747 }
4748 #if MMUOP_DEBUG > 0
4749 write_log (_T("PFLUSH %s PC=%08X\n"), fname, pc);
4750 #endif
4751 return false;
4752 }
4753
4754 // 68030 (68851) MMU instructions only
4755 bool mmu_op30 (uaecptr pc, uae_u32 opcode, uae_u16 extra, uaecptr extraa)
4756 {
4757 int type = extra >> 13;
4758 bool fline = false;
4759
4760 switch (type)
4761 {
4762 case 0:
4763 case 2:
4764 case 3:
4765 if (currprefs.mmu_model)
4766 fline = mmu_op30_pmove (pc, opcode, extra, extraa);
4767 else
4768 fline = mmu_op30fake_pmove (pc, opcode, extra, extraa);
4769 break;
4770 case 1:
4771 if (currprefs.mmu_model)
4772 fline = mmu_op30_pflush (pc, opcode, extra, extraa);
4773 else
4774 fline = mmu_op30fake_pflush (pc, opcode, extra, extraa);
4775 break;
4776 case 4:
4777 if (currprefs.mmu_model)
4778 fline = mmu_op30_ptest (pc, opcode, extra, extraa);
4779 else
4780 fline = mmu_op30fake_ptest (pc, opcode, extra, extraa);
4781 break;
4782 }
4783 if (fline) {
4784 m68k_setpc(pc);
4785 op_illg(opcode);
4786 }
4787 return fline;
4788 }
4789
4790 /* check if an address matches a ttr */
4791 static int fake_mmu_do_match_ttr(uae_u32 ttr, uaecptr addr, bool super)
4792 {
4793 if (ttr & MMU_TTR_BIT_ENABLED) { /* TTR enabled */
4794 uae_u8 msb, mask;
4795
4796 msb = ((addr ^ ttr) & MMU_TTR_LOGICAL_BASE) >> 24;
4797 mask = (ttr & MMU_TTR_LOGICAL_MASK) >> 16;
4798
4799 if (!(msb & ~mask)) {
4800
4801 if ((ttr & MMU_TTR_BIT_SFIELD_ENABLED) == 0) {
4802 if (((ttr & MMU_TTR_BIT_SFIELD_SUPER) == 0) != (super == 0)) {
4803 return TTR_NO_MATCH;
4804 }
4805 }
4806
4807 return (ttr & MMU_TTR_BIT_WRITE_PROTECT) ? TTR_NO_WRITE : TTR_OK_MATCH;
4808 }
4809 }
4810 return TTR_NO_MATCH;
4811 }
4812
4813 static int fake_mmu_match_ttr(uaecptr addr, bool super, bool data)
4814 {
4815 int res;
4816
4817 if (data) {
4818 res = fake_mmu_do_match_ttr(regs.dtt0, addr, super);
4819 if (res == TTR_NO_MATCH)
4820 res = fake_mmu_do_match_ttr(regs.dtt1, addr, super);
4821 } else {
4822 res = fake_mmu_do_match_ttr(regs.itt0, addr, super);
4823 if (res == TTR_NO_MATCH)
4824 res = fake_mmu_do_match_ttr(regs.itt1, addr, super);
4825 }
4826 return res;
4827 }
4828
4829 // 68040+ MMU instructions only
4830 void mmu_op (uae_u32 opcode, uae_u32 extra)
4831 {
4832 if (currprefs.mmu_model) {
4833 mmu_op_real (opcode, extra);
4834 return;
4835 }
4836 #if MMUOP_DEBUG > 1
4837 write_log (_T("mmu_op %04X PC=%08X\n"), opcode, m68k_getpc ());
4838 #endif
4839 if ((opcode & 0xFE0) == 0x0500) {
4840 /* PFLUSH */
4841 regs.mmusr = 0;
4842 #if MMUOP_DEBUG > 0
4843 write_log (_T("PFLUSH\n"));
4844 #endif
4845 return;
4846 } else if ((opcode & 0x0FD8) == 0x0548) {
4847 if (currprefs.cpu_model < 68060) { /* PTEST not in 68060 */
4848 /* PTEST */
4849 int regno = opcode & 7;
4850 uae_u32 addr = m68k_areg(regs, regno);
4851 bool write = (opcode & 32) == 0;
4852 bool super = (regs.dfc & 4) != 0;
4853 bool data = (regs.dfc & 3) != 2;
4854
4855 regs.mmusr = 0;
4856 if (fake_mmu_match_ttr(addr, super, data) != TTR_NO_MATCH) {
4857 regs.mmusr = MMU_MMUSR_T | MMU_MMUSR_R;
4858 }
4859 regs.mmusr |= addr & 0xfffff000;
4860 #if MMUOP_DEBUG > 0
4861 write_log (_T("PTEST%c %08x\n"), write ? 'W' : 'R', addr);
4862 #endif
4863 return;
4864 }
4865 } else if ((opcode & 0x0FB8) == 0x0588) {
4866 /* PLPA */
4867 if (currprefs.cpu_model == 68060) {
4868 int regno = opcode & 7;
4869 uae_u32 addr = m68k_areg (regs, regno);
4870 int write = (opcode & 0x40) == 0;
4871 bool data = (regs.dfc & 3) != 2;
4872 bool super = (regs.dfc & 4) != 0;
4873
4874 if (fake_mmu_match_ttr(addr, super, data) == TTR_NO_MATCH) {
4875 m68k_areg (regs, regno) = addr;
4876 }
4877 #if MMUOP_DEBUG > 0
4878 write_log (_T("PLPA\n"));
4879 #endif
4880 return;
4881 }
4882 }
4883 #if MMUOP_DEBUG > 0
4884 write_log (_T("Unknown MMU OP %04X\n"), opcode);
4885 #endif
4886 m68k_setpc_normal (m68k_getpc () - 2);
4887 op_illg (opcode);
4888 }
4889
4890 #endif
4891
4892 static void do_trace (void)
4893 {
4894 if (regs.t0 && currprefs.cpu_model >= 68020) {
4895 // this is obsolete
4896 return;
4897 }
4898 if (regs.t1) {
4899 activate_trace();
4900 }
4901 }
4902
4903 #ifndef WINUAE_FOR_HATARI
4904 static void check_uae_int_request(void)
4905 {
4906 bool irq2 = false;
4907 bool irq6 = false;
4908 if (atomic_and(&uae_interrupt, 0)) {
4909 for (int i = 0; i < IRQ_SOURCE_MAX; i++) {
4910 if (!irq2 && uae_interrupts2[i]) {
4911 uae_atomic v = atomic_and(&uae_interrupts2[i], 0);
4912 if (v) {
4913 INTREQ_f(0x8000 | 0x0008);
4914 irq2 = true;
4915 }
4916 }
4917 if (!irq6 && uae_interrupts6[i]) {
4918 uae_atomic v = atomic_and(&uae_interrupts6[i], 0);
4919 if (v) {
4920 INTREQ_f(0x8000 | 0x2000);
4921 irq6 = true;
4922 }
4923 }
4924 }
4925 }
4926 if (uae_int_requested) {
4927 if (!irq2 && (uae_int_requested & 0x00ff)) {
4928 INTREQ_f(0x8000 | 0x0008);
4929 irq2 = true;
4930 }
4931 if (!irq6 && (uae_int_requested & 0xff00)) {
4932 INTREQ_f(0x8000 | 0x2000);
4933 irq6 = true;
4934 }
4935 if (uae_int_requested & 0xff0000) {
4936 if (!cpuboard_is_ppcboard_irq()) {
4937 atomic_and(&uae_int_requested, ~0x010000);
4938 }
4939 }
4940 }
4941 if (irq2 || irq6) {
4942 doint();
4943 }
4944 }
4945
4946 void safe_interrupt_set(int num, int id, bool i6)
4947 {
4948 if (!is_mainthread()) {
4949 set_special_exter(SPCFLAG_UAEINT);
4950 volatile uae_atomic *p;
4951 if (i6)
4952 p = &uae_interrupts6[num];
4953 else
4954 p = &uae_interrupts2[num];
4955 atomic_or(p, 1 << id);
4956 atomic_or(&uae_interrupt, 1);
4957 } else {
4958 uae_u16 v = i6 ? 0x2000 : 0x0008;
4959 if (currprefs.cpu_cycle_exact || (!(intreq & v) && !currprefs.cpu_cycle_exact)) {
4960 INTREQ_0(0x8000 | v);
4961 }
4962 }
4963 }
4964 #endif
4965
4966 int cpu_sleep_millis(int ms)
4967 {
4968 int ret = 0;
4969 #ifdef WITH_PPC
4970 int state = ppc_state;
4971 if (state)
4972 uae_ppc_spinlock_release();
4973 #endif
4974 #ifdef WITH_X86
4975 // if (x86_turbo_on) {
4976 // execute_other_cpu(read_processor_time() + vsynctimebase / 20);
4977 // } else {
4978 ret = sleep_millis_main(ms);
4979 // }
4980 #endif
4981 #ifdef WITH_PPC
4982 if (state)
4983 uae_ppc_spinlock_get();
4984 #endif
4985 return ret;
4986 }
4987
4988 #define PPC_HALTLOOP_SCANLINES 25
4989 // ppc_cpu_idle
4990 // 0 = busy
4991 // 1-9 = wait, levels
4992 // 10 = max wait
4993
4994 #ifndef WINUAE_FOR_HATARI
4995 static bool haltloop_do(int vsynctimeline, int rpt_end, int lines)
4996 {
4997 int ovpos = vpos;
4998 while (lines-- >= 0) {
4999 ovpos = vpos;
5000 while (ovpos == vpos) {
5001 x_do_cycles(8 * CYCLE_UNIT);
5002 unset_special(SPCFLAG_UAEINT);
5003 check_uae_int_request();
5004 #ifdef WITH_PPC
5005 ppc_interrupt(intlev());
5006 uae_ppc_execute_check();
5007 #endif
5008 if (regs.spcflags & SPCFLAG_COPPER)
5009 do_copper();
5010 if (regs.spcflags & (SPCFLAG_BRK | SPCFLAG_MODE_CHANGE)) {
5011 if (regs.spcflags & SPCFLAG_BRK) {
5012 unset_special(SPCFLAG_BRK);
5013 #ifdef DEBUGGER
5014 if (debugging)
5015 debug();
5016 #endif
5017 }
5018 return true;
5019 }
5020 }
5021
5022 // sync chipset with real time
5023 for (;;) {
5024 check_uae_int_request();
5025 #ifdef WITH_PPC
5026 ppc_interrupt(intlev());
5027 uae_ppc_execute_check();
5028 #endif
5029 if (event_wait)
5030 break;
5031 int d = read_processor_time() - rpt_end;
5032 if (d < -2 * vsynctimeline || d >= 0)
5033 break;
5034 }
5035 }
5036 return false;
5037 }
5038 #endif
5039
5040 static bool haltloop(void)
5041 {
5042 #ifndef WINUAE_FOR_HATARI
5043 #ifdef WITH_PPC
5044 if (regs.halted < 0) {
5045 int rpt_end = 0;
5046 int ovpos = vpos;
5047
5048 while (regs.halted) {
5049 int vsynctimeline = vsynctimebase / (maxvpos_display + 1);
5050 int lines;
5051 int rpt_scanline = read_processor_time();
5052 int rpt_end = rpt_scanline + vsynctimeline;
5053
5054 // See expansion handling.
5055 // Dialog must be opened from main thread.
5056 if (regs.halted == -2) {
5057 regs.halted = -1;
5058 notify_user (NUMSG_UAEBOOTROM_PPC);
5059 }
5060
5061 if (currprefs.ppc_cpu_idle) {
5062
5063 int maxlines = 100 - (currprefs.ppc_cpu_idle - 1) * 10;
5064 int i;
5065
5066 event_wait = false;
5067 for (i = 0; i < ev_max; i++) {
5068 if (i == ev_hsync)
5069 continue;
5070 if (i == ev_audio)
5071 continue;
5072 if (!eventtab[i].active)
5073 continue;
5074 if (eventtab[i].evtime - currcycle < maxlines * maxhpos * CYCLE_UNIT)
5075 break;
5076 }
5077 if (currprefs.ppc_cpu_idle >= 10 || (i == ev_max && vpos > 0 && vpos < maxvpos - maxlines)) {
5078 cpu_sleep_millis(1);
5079 }
5080 check_uae_int_request();
5081 uae_ppc_execute_check();
5082
5083 lines = (read_processor_time() - rpt_scanline) / vsynctimeline + 1;
5084
5085 } else {
5086
5087 event_wait = true;
5088 lines = 0;
5089
5090 }
5091
5092 if (lines > maxvpos / 2)
5093 lines = maxvpos / 2;
5094
5095 if (haltloop_do(vsynctimeline, rpt_end, lines))
5096 return true;
5097
5098 }
5099
5100 } else {
5101 #endif
5102 while (regs.halted) {
5103 static int prevvpos;
5104 if (vpos == 0 && prevvpos) {
5105 prevvpos = 0;
5106 cpu_sleep_millis(8);
5107 }
5108 if (vpos)
5109 prevvpos = 1;
5110 x_do_cycles(8 * CYCLE_UNIT);
5111
5112 if (regs.spcflags & SPCFLAG_COPPER)
5113 do_copper();
5114
5115 if (regs.spcflags) {
5116 if ((regs.spcflags & (SPCFLAG_BRK | SPCFLAG_MODE_CHANGE)))
5117 return true;
5118 }
5119 }
5120 #ifdef WITH_PPC
5121 }
5122 #endif
5123
5124 return false;
5125 #else
5126 /* In Hatari, we don't use the halt state, we do a reset */
5127 return false;
5128 #endif
5129 }
5130
5131 #ifdef WITH_PPC
5132 static bool uae_ppc_poll_check_halt(void)
5133 {
5134 if (regs.halted) {
5135 if (haltloop())
5136 return true;
5137 }
5138 return false;
5139 }
5140 #endif
5141
5142
5143 // handle interrupt delay (few cycles)
5144 STATIC_INLINE bool time_for_interrupt (void)
5145 {
5146 return regs.ipl > regs.intmask || regs.ipl == 7;
5147 }
5148
5149 void doint (void)
5150 {
5151 #ifdef WITH_PPC
5152 if (ppc_state) {
5153 if (!ppc_interrupt(intlev()))
5154 return;
5155 }
5156 #endif
5157 //fprintf ( stderr , "doint1 %d ipl=%x ipl_pin=%x intmask=%x spcflags=%x\n" , m68k_interrupt_delay,regs.ipl, regs.ipl_pin , regs.intmask, regs.spcflags );
5158 if (m68k_interrupt_delay) {
5159 regs.ipl_pin = intlev ();
5160 unset_special (SPCFLAG_INT);
5161 //fprintf ( stderr , "doint2 %d ipl=%x ipl_pin=%x intmask=%x spcflags=%x\n" , m68k_interrupt_delay,regs.ipl, regs.ipl_pin , regs.intmask, regs.spcflags );
5162 return;
5163 }
5164 if (currprefs.cpu_compatible && currprefs.cpu_model < 68020)
5165 set_special (SPCFLAG_INT);
5166 else
5167 set_special (SPCFLAG_DOINT);
5168 }
5169
5170
5171 #ifdef WINUAE_FOR_HATARI
5172 /*
5173 * Handle special flags
5174 */
5175
5176 static bool do_specialties_interrupt (int Pending)
5177 {
5178 #if ENABLE_DSP_EMU
5179 /* Check for DSP int first (if enabled) (level 6) */
5180 if (regs.spcflags & SPCFLAG_DSP) {
5181 if (DSP_ProcessIRQ() == true)
5182 return true;
5183 }
5184 #endif
5185
5186 /* Check for MFP ints (level 6) */
5187 if (regs.spcflags & SPCFLAG_MFP) {
5188 if (MFP_ProcessIRQ() == true)
5189 return true; /* MFP exception was generated, no higher interrupt can happen */
5190 }
5191
5192 /* No MFP int, check for VBL/HBL ints (levels 4/2) */
5193 if (regs.spcflags & (SPCFLAG_INT | SPCFLAG_DOINT)) {
5194 int intr = intlev ();
5195 /* SPCFLAG_DOINT will be enabled again in MakeFromSR to handle pending interrupts! */
5196 // unset_special (SPCFLAG_DOINT);
5197 unset_special (SPCFLAG_INT | SPCFLAG_DOINT);
5198 if (intr != -1 && intr > regs.intmask) {
5199 do_interrupt (intr); /* process the interrupt */
5200 return true;
5201 }
5202 }
5203
5204 return false; /* no interrupt was found */
5205 }
5206 #endif
5207
5208 static int do_specialties (int cycles)
5209 {
5210 bool stopped_debug = false;
5211
5212 if (regs.spcflags & SPCFLAG_MODE_CHANGE)
5213 return 1;
5214
5215 #ifndef WINUAE_FOR_HATARI
5216 if (regs.spcflags & SPCFLAG_CHECK) {
5217 if (regs.halted) {
5218 if (regs.halted == CPU_HALT_ACCELERATOR_CPU_FALLBACK) {
5219 return 1;
5220 }
5221 unset_special(SPCFLAG_CHECK);
5222 if (haltloop())
5223 return 1;
5224 }
5225 if (m68k_reset_delay) {
5226 int vsynccnt = 60;
5227 int vsyncstate = -1;
5228 while (vsynccnt > 0 && !quit_program) {
5229 x_do_cycles(8 * CYCLE_UNIT);
5230 if (regs.spcflags & SPCFLAG_COPPER)
5231 do_copper();
5232 if (timeframes != vsyncstate) {
5233 vsyncstate = timeframes;
5234 vsynccnt--;
5235 }
5236 }
5237 }
5238 m68k_reset_delay = 0;
5239 unset_special(SPCFLAG_CHECK);
5240 }
5241 #endif
5242
5243 #ifdef ACTION_REPLAY
5244 #ifdef ACTION_REPLAY_HRTMON
5245 if ((regs.spcflags & SPCFLAG_ACTION_REPLAY) && hrtmon_flag != ACTION_REPLAY_INACTIVE) {
5246 int isinhrt = (m68k_getpc () >= hrtmem_start && m68k_getpc () < hrtmem_start + hrtmem_size);
5247 /* exit from HRTMon? */
5248 if (hrtmon_flag == ACTION_REPLAY_ACTIVE && !isinhrt)
5249 hrtmon_hide ();
5250 /* HRTMon breakpoint? (not via IRQ7) */
5251 if (hrtmon_flag == ACTION_REPLAY_IDLE && isinhrt)
5252 hrtmon_breakenter ();
5253 if (hrtmon_flag == ACTION_REPLAY_ACTIVATE)
5254 hrtmon_enter ();
5255 }
5256 #endif
5257 if ((regs.spcflags & SPCFLAG_ACTION_REPLAY) && action_replay_flag != ACTION_REPLAY_INACTIVE) {
5258 /*if (action_replay_flag == ACTION_REPLAY_ACTIVE && !is_ar_pc_in_rom ())*/
5259 /* write_log (_T("PC:%p\n"), m68k_getpc ());*/
5260
5261 if (action_replay_flag == ACTION_REPLAY_ACTIVATE || action_replay_flag == ACTION_REPLAY_DORESET)
5262 action_replay_enter ();
5263 if ((action_replay_flag == ACTION_REPLAY_HIDE || action_replay_flag == ACTION_REPLAY_ACTIVE) && !is_ar_pc_in_rom ()) {
5264 action_replay_hide ();
5265 unset_special (SPCFLAG_ACTION_REPLAY);
5266 }
5267 if (action_replay_flag == ACTION_REPLAY_WAIT_PC) {
5268 /*write_log (_T("Waiting for PC: %p, current PC= %p\n"), wait_for_pc, m68k_getpc ());*/
5269 if (m68k_getpc () == wait_for_pc) {
5270 action_replay_flag = ACTION_REPLAY_ACTIVATE; /* Activate after next instruction. */
5271 }
5272 }
5273 }
5274 #endif
5275
5276 #ifndef WINUAE_FOR_HATARI
5277 if (regs.spcflags & SPCFLAG_COPPER)
5278 do_copper ();
5279 #endif
5280
5281 #ifdef JIT
5282 unset_special (SPCFLAG_END_COMPILE); /* has done its job */
5283 #endif
5284
5285 #ifndef WINUAE_FOR_HATARI
5286 while ((regs.spcflags & SPCFLAG_BLTNASTY) && dmaen (DMA_BLITTER) && cycles > 0 && ((currprefs.waiting_blits && currprefs.cpu_model >= 68020) || !currprefs.blitter_cycle_exact)) {
5287 int c = blitnasty ();
5288 if (c < 0) {
5289 break;
5290 } else if (c > 0) {
5291 cycles -= c * CYCLE_UNIT * 2;
5292 if (cycles < CYCLE_UNIT)
5293 cycles = 0;
5294 } else {
5295 c = 4;
5296 }
5297 x_do_cycles (c * CYCLE_UNIT);
5298 if (regs.spcflags & SPCFLAG_COPPER)
5299 do_copper ();
5300 #ifdef WITH_PPC
5301 if (ppc_state) {
5302 if (uae_ppc_poll_check_halt())
5303 return true;
5304 uae_ppc_execute_check();
5305 }
5306 #endif
5307 }
5308 #endif
5309
5310 #ifdef WINUAE_FOR_HATARI
5311 if (regs.spcflags & SPCFLAG_BUSERROR) {
5312 /* We can not execute bus errors directly in the memory handler
5313 * functions since the PC should point to the address of the next
5314 * instruction, so we're executing the bus errors here: */
5315 unset_special(SPCFLAG_BUSERROR);
5316 Exception(2);
5317 }
5318 #endif
5319
5320 if (regs.spcflags & SPCFLAG_DOTRACE)
5321 Exception (9);
5322
5323 #ifndef WINUAE_FOR_HATARI
5324 if (regs.spcflags & SPCFLAG_TRAP) {
5325 unset_special (SPCFLAG_TRAP);
5326 Exception (3);
5327 }
5328 #endif
5329 if ((regs.spcflags & SPCFLAG_STOP) && regs.s == 0 && currprefs.cpu_model <= 68010) {
5330 // 68000/68010 undocumented special case:
5331 // if STOP clears S-bit and T was not set:
5332 // cause privilege violation exception, PC pointing to following instruction.
5333 // If T was set before STOP: STOP works as documented.
5334 m68k_unset_stop();
5335 Exception(8);
5336 }
5337
5338 bool first = true;
5339 while ((regs.spcflags & SPCFLAG_STOP) && !(regs.spcflags & SPCFLAG_BRK)) {
5340 //fprintf ( stderr , "stop wait %d %ld %ld\n" , currcycle , CyclesGlobalClockCounter );
5341 isstopped:
5342 #ifndef WINUAE_FOR_HATARI
5343 check_uae_int_request();
5344 {
5345 if (bsd_int_requested)
5346 bsdsock_fake_int_handler ();
5347 }
5348 #endif
5349
5350 if (cpu_tracer > 0) {
5351 cputrace.stopped = regs.stopped;
5352 cputrace.intmask = regs.intmask;
5353 cputrace.sr = regs.sr;
5354 cputrace.state = 1;
5355 cputrace.pc = m68k_getpc ();
5356 cputrace.memoryoffset = 0;
5357 cputrace.cyclecounter = cputrace.cyclecounter_pre = cputrace.cyclecounter_post = 0;
5358 cputrace.readcounter = cputrace.writecounter = 0;
5359 }
5360 if (!first)
5361 x_do_cycles (currprefs.cpu_cycle_exact ? 2 * CYCLE_UNIT : 4 * CYCLE_UNIT);
5362
5363 #ifdef WINUAE_FOR_HATARI
5364 if (!first)
5365 {
5366 if (currprefs.cpu_cycle_exact && !currprefs.mmu_model)
5367 {
5368 /* Flush all CE cycles so far to update PendingInterruptCount */
5369 M68000_AddCycles_CE ( currcycle * 2 / CYCLE_UNIT );
5370 currcycle = 0;
5371 }
5372 else
5373 M68000_AddCycles(4);
5374 }
5375
5376 /* It is possible one or more ints happen at the same time */
5377 /* We must process them during the same cpu cycle then choose the highest priority one */
5378 while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) )
5379 CALL_VAR(PendingInterruptFunction);
5380 if ( MFP_UpdateNeeded == true )
5381 MFP_UpdateIRQ ( 0 );
5382
5383 /* Check is there's an interrupt to process (could be a delayed MFP interrupt) */
5384 if (regs.spcflags & SPCFLAG_MFP) {
5385 MFP_DelayIRQ (); /* Handle IRQ propagation */
5386 M68000_Update_intlev (); /* Refresh the list of pending interrupts */
5387 }
5388 #endif
5389 first = false;
5390 #ifndef WINUAE_FOR_HATARI
5391 if (regs.spcflags & SPCFLAG_COPPER)
5392 do_copper ();
5393 #endif
5394
5395 if (m68k_interrupt_delay) {
5396 ipl_fetch ();
5397 if (time_for_interrupt ()) {
5398 do_interrupt (regs.ipl);
5399 }
5400 } else {
5401 if (regs.spcflags & (SPCFLAG_INT | SPCFLAG_DOINT)) {
5402 int intr = intlev ();
5403 unset_special (SPCFLAG_INT | SPCFLAG_DOINT);
5404 #ifdef WITH_PPC
5405 bool m68kint = true;
5406 if (ppc_state) {
5407 m68kint = ppc_interrupt(intr);
5408 }
5409 if (m68kint) {
5410 #endif
5411 if (intr > 0 && intr > regs.intmask)
5412 do_interrupt (intr);
5413 #ifdef WITH_PPC
5414 }
5415 #endif
5416 }
5417 }
5418
5419 if (regs.spcflags & SPCFLAG_MODE_CHANGE) {
5420 m68k_resumestopped();
5421 return 1;
5422 }
5423
5424 #ifdef WITH_PPC
5425 if (ppc_state) {
5426 uae_ppc_execute_check();
5427 uae_ppc_poll_check_halt();
5428 }
5429 #endif
5430
5431 }
5432
5433 if (regs.spcflags & SPCFLAG_TRACE)
5434 do_trace ();
5435
5436 #ifndef WINUAE_FOR_HATARI
5437 if (regs.spcflags & SPCFLAG_UAEINT) {
5438 check_uae_int_request();
5439 unset_special(SPCFLAG_UAEINT);
5440 }
5441 #endif
5442
5443 #ifdef WINUAE_FOR_HATARI
5444 if (regs.spcflags & SPCFLAG_MFP) {
5445 MFP_DelayIRQ (); /* Handle IRQ propagation */
5446 M68000_Update_intlev (); /* Refresh the list of pending interrupts */
5447 }
5448 #endif
5449
5450 //fprintf ( stderr , "dospec1 %d %d spcflags=%x ipl=%x ipl_pin=%x intmask=%x\n" , m68k_interrupt_delay,time_for_interrupt() , regs.spcflags , regs.ipl , regs.ipl_pin, regs.intmask );
5451 if (m68k_interrupt_delay) {
5452 if (time_for_interrupt ()) {
5453 do_interrupt (regs.ipl);
5454 }
5455 } else {
5456 if (regs.spcflags & SPCFLAG_INT) {
5457 int intr = intlev ();
5458 unset_special (SPCFLAG_INT | SPCFLAG_DOINT);
5459 if (intr > 0 && (intr > regs.intmask || intr == 7))
5460 do_interrupt (intr);
5461 }
5462 }
5463
5464 //fprintf ( stderr , "dospec2 %d %d spcflags=%x ipl=%x ipl_pin=%x intmask=%x\n" , m68k_interrupt_delay,time_for_interrupt() , regs.spcflags , regs.ipl , regs.ipl_pin, regs.intmask );
5465 if (regs.spcflags & SPCFLAG_DOINT) {
5466 unset_special (SPCFLAG_DOINT);
5467 set_special (SPCFLAG_INT);
5468 }
5469 //fprintf ( stderr , "dospec3 %d %d spcflags=%x ipl=%x ipl_pin=%x intmask=%x\n" , m68k_interrupt_delay,time_for_interrupt() , regs.spcflags , regs.ipl , regs.ipl_pin, regs.intmask );
5470
5471 #ifdef WINUAE_FOR_HATARI
5472 if (regs.spcflags & SPCFLAG_DEBUGGER)
5473 DebugCpu_Check();
5474 #endif
5475
5476 if ((regs.spcflags & SPCFLAG_BRK) || stopped_debug) {
5477 unset_special(SPCFLAG_BRK);
5478 #ifdef DEBUGGER
5479 if (stopped_debug && !regs.stopped) {
5480 if (debugging) {
5481 debugger_active = 1;
5482 stopped_debug = false;
5483 }
5484 }
5485 if (debugging) {
5486 if (!stopped_debug)
5487 debug();
5488 if (regs.stopped) {
5489 stopped_debug = true;
5490 if (debugging) {
5491 debugger_active = 0;
5492 }
5493 goto isstopped;
5494 }
5495 }
5496 #endif
5497 #ifdef WINUAE_FOR_HATARI
5498 return 1; /* Exit the upper run_xxx() function */
5499 #endif
5500 }
5501
5502 return 0;
5503 }
5504
5505 //static uae_u32 pcs[1000];
5506
5507 #ifndef WINUAE_FOR_HATARI
5508 #if DEBUG_CD32CDTVIO
5509
5510 static uae_u32 cd32nextpc, cd32request;
5511
5512 static void out_cd32io2 (void)
5513 {
5514 uae_u32 request = cd32request;
5515 write_log (_T("%08x returned\n"), request);
5516 //write_log (_T("ACTUAL=%d ERROR=%d\n"), get_long (request + 32), get_byte (request + 31));
5517 cd32nextpc = 0;
5518 cd32request = 0;
5519 }
5520
5521 static void out_cd32io (uae_u32 pc)
5522 {
5523 TCHAR out[100];
5524 int ioreq = 0;
5525 uae_u32 request = m68k_areg (regs, 1);
5526
5527 if (pc == cd32nextpc) {
5528 out_cd32io2 ();
5529 return;
5530 }
5531 out[0] = 0;
5532 switch (pc)
5533 {
5534 case 0xe57cc0:
5535 case 0xf04c34:
5536 _stprintf (out, _T("opendevice"));
5537 break;
5538 case 0xe57ce6:
5539 case 0xf04c56:
5540 _stprintf (out, _T("closedevice"));
5541 break;
5542 case 0xe57e44:
5543 case 0xf04f2c:
5544 _stprintf (out, _T("beginio"));
5545 ioreq = 1;
5546 break;
5547 case 0xe57ef2:
5548 case 0xf0500e:
5549 _stprintf (out, _T("abortio"));
5550 ioreq = -1;
5551 break;
5552 }
5553 if (out[0] == 0)
5554 return;
5555 if (cd32request)
5556 write_log (_T("old request still not returned!\n"));
5557 cd32request = request;
5558 cd32nextpc = get_long (m68k_areg (regs, 7));
5559 write_log (_T("%s A1=%08X\n"), out, request);
5560 if (ioreq) {
5561 static int cnt = 0;
5562 int cmd = get_word (request + 28);
5563 #if 0
5564 if (cmd == 33) {
5565 uaecptr data = get_long (request + 40);
5566 write_log (_T("CD_CONFIG:\n"));
5567 for (int i = 0; i < 16; i++) {
5568 write_log (_T("%08X=%08X\n"), get_long (data), get_long (data + 4));
5569 data += 8;
5570 }
5571 }
5572 #endif
5573 #if 0
5574 if (cmd == 37) {
5575 cnt--;
5576 if (cnt <= 0)
5577 activate_debugger ();
5578 }
5579 #endif
5580 write_log (_T("CMD=%d DATA=%08X LEN=%d %OFF=%d PC=%x\n"),
5581 cmd, get_long (request + 40),
5582 get_long (request + 36), get_long (request + 44), M68K_GETPC);
5583 }
5584 if (ioreq < 0)
5585 ;//activate_debugger ();
5586 }
5587
5588 #endif
5589 #endif
5590
5591 #ifndef CPUEMU_11
5592
5593 static void m68k_run_1 (void)
5594 {
5595 }
5596
5597 #else
5598
5599 /* It's really sad to have two almost identical functions for this, but we
5600 do it all for performance... :(
5601 This version emulates 68000's prefetch "cache" */
5602 static void m68k_run_1 (void)
5603 {
5604 struct regstruct *r = ®s;
5605 bool exit = false;
5606
5607 Log_Printf(LOG_DEBUG, "m68k_run_1\n");
5608
5609 while (!exit) {
5610 TRY (prb) {
5611 while (!exit) {
5612 r->opcode = r->ir;
5613
5614 count_instr (r->opcode);
5615
5616 #ifdef WINUAE_FOR_HATARI
5617 //m68k_dumpstate_file(stderr, NULL, 0xffffffff);
5618 if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM))
5619 {
5620 int FrameCycles, HblCounterVideo, LineCycles;
5621
5622 Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
5623
5624 LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo );
5625 m68k_disasm_file(stderr, m68k_getpc (), NULL, m68k_getpc (), 1);
5626 }
5627 #endif
5628
5629 #ifndef WINUAE_FOR_HATARI
5630 #if DEBUG_CD32CDTVIO
5631 out_cd32io (m68k_getpc ());
5632 #endif
5633 #endif
5634
5635 #if 0
5636 int pc = m68k_getpc ();
5637 if (pc == 0xdff002)
5638 write_log (_T("hip\n"));
5639 if (pc != pcs[0] && (pc < 0xd00000 || pc > 0x1000000)) {
5640 memmove (pcs + 1, pcs, 998 * 4);
5641 pcs[0] = pc;
5642 //write_log (_T("%08X-%04X "), pc, r->opcode);
5643 }
5644 #endif
5645 do_cycles (cpu_cycles);
5646 r->instruction_pc = m68k_getpc ();
5647 cpu_cycles = (*cpufunctbl[r->opcode])(r->opcode);
5648 cpu_cycles = adjust_cycles (cpu_cycles);
5649
5650 #ifdef WINUAE_FOR_HATARI
5651 /* Also add some extra cycles to simulate some wait state */
5652 /* TODO [NP] do this in all m68k_run_xx() */
5653 M68000_AddCyclesWithPairing(cpu_cycles * 2 / CYCLE_UNIT + WaitStateCycles);
5654 WaitStateCycles = 0;
5655
5656 /* We can have several interrupts at the same time before the next CPU instruction */
5657 /* We must check for pending interrupt and call do_specialties_interrupt() only */
5658 /* if the cpu is not in the STOP state. Else, the int could be acknowledged now */
5659 /* and prevent exiting the STOP state when calling do_specialties() after. */
5660 /* For performance, we first test PendingInterruptCount, then regs.spcflags */
5661 while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) && ( ( regs.spcflags & SPCFLAG_STOP ) == 0 ) )
5662 CALL_VAR(PendingInterruptFunction); /* call the interrupt handler */
5663 if ( MFP_UpdateNeeded == true )
5664 MFP_UpdateIRQ ( 0 );
5665 #endif
5666
5667 if (r->spcflags) {
5668 if (do_specialties (cpu_cycles))
5669 exit = true;
5670 }
5671 regs.ipl = regs.ipl_pin;
5672
5673 #ifdef WINUAE_FOR_HATARI
5674 if ( savestate_state == STATE_SAVE )
5675 save_state ( NULL , NULL );
5676 #endif
5677
5678 if (!currprefs.cpu_compatible || (currprefs.cpu_cycle_exact && currprefs.cpu_model <= 68010))
5679 exit = true;
5680 }
5681 } CATCH (prb) {
5682 bus_error();
5683 if (r->spcflags) {
5684 if (do_specialties(cpu_cycles))
5685 exit = true;
5686 }
5687 regs.ipl = regs.ipl_pin;
5688 } ENDTRY
5689 }
5690 }
5691
5692 #endif /* CPUEMU_11 */
5693
5694 #ifndef CPUEMU_13
5695
5696 static void m68k_run_1_ce (void)
5697 {
5698 }
5699
5700 #else
5701
5702 /* cycle-exact m68k_run () */
5703
5704 static void m68k_run_1_ce (void)
5705 {
5706 struct regstruct *r = ®s;
5707 bool first = true;
5708 bool exit = false;
5709
5710 Log_Printf(LOG_DEBUG, "m68k_run_1_ce\n");
5711
5712 while (!exit) {
5713 TRY (prb) {
5714 if (first) {
5715 if (cpu_tracer < 0) {
5716 memcpy (&r->regs, &cputrace.regs, 16 * sizeof (uae_u32));
5717 r->ir = cputrace.ir;
5718 r->irc = cputrace.irc;
5719 r->sr = cputrace.sr;
5720 r->usp = cputrace.usp;
5721 r->isp = cputrace.isp;
5722 r->intmask = cputrace.intmask;
5723 r->stopped = cputrace.stopped;
5724 m68k_setpc (cputrace.pc);
5725 if (!r->stopped) {
5726 if (cputrace.state > 1) {
5727 write_log (_T("CPU TRACE: EXCEPTION %d\n"), cputrace.state);
5728 Exception (cputrace.state);
5729 } else if (cputrace.state == 1) {
5730 write_log (_T("CPU TRACE: %04X\n"), cputrace.opcode);
5731 (*cpufunctbl[cputrace.opcode])(cputrace.opcode);
5732 }
5733 } else {
5734 write_log (_T("CPU TRACE: STOPPED\n"));
5735 }
5736 if (r->stopped)
5737 set_special (SPCFLAG_STOP);
5738 set_cpu_tracer (false);
5739 goto cont;
5740 }
5741 set_cpu_tracer (false);
5742 first = false;
5743 }
5744
5745 while (!exit) {
5746 r->opcode = r->ir;
5747
5748 #ifdef WINUAE_FOR_HATARI
5749 //m68k_dumpstate_file(stderr, NULL, 0xffffffff);
5750 if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM))
5751 {
5752 int FrameCycles, HblCounterVideo, LineCycles;
5753
5754 Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
5755
5756 //fprintf ( stderr , "clock %ld\n" , CyclesGlobalClockCounter );
5757 LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo );
5758 m68k_disasm_file(stderr, m68k_getpc (), NULL, m68k_getpc (), 1);
5759 }
5760 #endif
5761
5762 #ifndef WINUAE_FOR_HATARI
5763 #if DEBUG_CD32CDTVIO
5764 out_cd32io (m68k_getpc ());
5765 #endif
5766 #endif
5767 if (cpu_tracer) {
5768 memcpy (&cputrace.regs, &r->regs, 16 * sizeof (uae_u32));
5769 cputrace.opcode = r->opcode;
5770 cputrace.ir = r->ir;
5771 cputrace.irc = r->irc;
5772 cputrace.sr = r->sr;
5773 cputrace.usp = r->usp;
5774 cputrace.isp = r->isp;
5775 cputrace.intmask = r->intmask;
5776 cputrace.stopped = r->stopped;
5777 cputrace.state = 1;
5778 cputrace.pc = m68k_getpc ();
5779 cputrace.startcycles = get_cycles ();
5780 cputrace.memoryoffset = 0;
5781 cputrace.cyclecounter = cputrace.cyclecounter_pre = cputrace.cyclecounter_post = 0;
5782 cputrace.readcounter = cputrace.writecounter = 0;
5783 }
5784
5785 #ifndef WINUAE_FOR_HATARI
5786 if (inputrecord_debug & 4) {
5787 if (input_record > 0)
5788 inprec_recorddebug_cpu (1);
5789 else if (input_play > 0)
5790 inprec_playdebug_cpu (1);
5791 }
5792 #endif
5793
5794 #ifdef WINUAE_FOR_HATARI
5795 currcycle = 0;
5796 #endif
5797
5798 r->instruction_pc = m68k_getpc ();
5799 (*cpufunctbl[r->opcode])(r->opcode);
5800 wait_memory_cycles(); // TODO NP : ici, ou plus bas ?
5801 #ifdef WINUAE_FOR_HATARI
5802 //fprintf ( stderr, "cyc_1ce %d\n" , currcycle );
5803 /* Flush all CE cycles so far to update PendingInterruptCount */
5804 M68000_AddCycles_CE ( currcycle * 2 / CYCLE_UNIT );
5805 currcycle = 0;
5806
5807 while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) && ( ( regs.spcflags & SPCFLAG_STOP ) == 0 ) )
5808 CALL_VAR(PendingInterruptFunction); /* call the interrupt handler */
5809 if ( MFP_UpdateNeeded == true )
5810 MFP_UpdateIRQ ( 0 );
5811 #endif
5812
5813 if (cpu_tracer) {
5814 cputrace.state = 0;
5815 }
5816 cont:
5817 if (cputrace.needendcycles) {
5818 cputrace.needendcycles = 0;
5819 write_log (_T("STARTCYCLES=%08x ENDCYCLES=%08lx\n"), cputrace.startcycles, get_cycles ());
5820 #ifndef WINUAE_FOR_HATARI
5821 log_dma_record ();
5822 #endif
5823 }
5824
5825 if (r->spcflags || time_for_interrupt ()) {
5826 if (do_specialties (0))
5827 exit = true;
5828 }
5829
5830 #ifdef WINUAE_FOR_HATARI
5831 if ( savestate_state == STATE_SAVE )
5832 save_state ( NULL , NULL );
5833 #endif
5834
5835 if (!currprefs.cpu_cycle_exact || currprefs.cpu_model > 68010)
5836 exit = true;
5837 }
5838 } CATCH (prb) {
5839 bus_error();
5840 if (r->spcflags || time_for_interrupt()) {
5841 if (do_specialties(0))
5842 exit = true;
5843 }
5844 } ENDTRY
5845 }
5846 }
5847
5848 #endif
5849
5850 #if defined(CPUEMU_20) && defined(JIT)
5851 // emulate simple prefetch
5852 static uae_u16 get_word_020_prefetchf (uae_u32 pc)
5853 {
5854 if (pc == regs.prefetch020addr) {
5855 uae_u16 v = regs.prefetch020[0];
5856 regs.prefetch020[0] = regs.prefetch020[1];
5857 regs.prefetch020[1] = regs.prefetch020[2];
5858 regs.prefetch020[2] = x_get_word (pc + 6);
5859 regs.prefetch020addr += 2;
5860 return v;
5861 } else if (pc == regs.prefetch020addr + 2) {
5862 uae_u16 v = regs.prefetch020[1];
5863 regs.prefetch020[0] = regs.prefetch020[2];
5864 regs.prefetch020[1] = x_get_word (pc + 4);
5865 regs.prefetch020[2] = x_get_word (pc + 6);
5866 regs.prefetch020addr = pc + 2;
5867 return v;
5868 } else if (pc == regs.prefetch020addr + 4) {
5869 uae_u16 v = regs.prefetch020[2];
5870 regs.prefetch020[0] = x_get_word (pc + 2);
5871 regs.prefetch020[1] = x_get_word (pc + 4);
5872 regs.prefetch020[2] = x_get_word (pc + 6);
5873 regs.prefetch020addr = pc + 2;
5874 return v;
5875 } else {
5876 regs.prefetch020addr = pc + 2;
5877 regs.prefetch020[0] = x_get_word (pc + 2);
5878 regs.prefetch020[1] = x_get_word (pc + 4);
5879 regs.prefetch020[2] = x_get_word (pc + 6);
5880 return x_get_word (pc);
5881 }
5882 }
5883 #endif
5884
5885 #ifdef WITH_THREADED_CPU
5886 static volatile int cpu_thread_active;
5887 static uae_sem_t cpu_in_sema, cpu_out_sema, cpu_wakeup_sema;
5888
5889 static volatile int cpu_thread_ilvl;
5890 static volatile uae_u32 cpu_thread_indirect_mode;
5891 static volatile uae_u32 cpu_thread_indirect_addr;
5892 static volatile uae_u32 cpu_thread_indirect_val;
5893 static volatile uae_u32 cpu_thread_indirect_size;
5894 static volatile uae_u32 cpu_thread_reset;
5895 static uae_thread_id cpu_thread_tid;
5896
5897 static bool m68k_cs_initialized;
5898
5899 static int do_specialties_thread(void)
5900 {
5901 if (regs.spcflags & SPCFLAG_MODE_CHANGE)
5902 return 1;
5903
5904 #ifdef JIT
5905 unset_special(SPCFLAG_END_COMPILE); /* has done its job */
5906 #endif
5907
5908 if (regs.spcflags & SPCFLAG_DOTRACE)
5909 Exception(9);
5910
5911 if (regs.spcflags & SPCFLAG_TRAP) {
5912 unset_special(SPCFLAG_TRAP);
5913 Exception(3);
5914 }
5915
5916 if (regs.spcflags & SPCFLAG_TRACE)
5917 do_trace();
5918
5919 for (;;) {
5920
5921 if (regs.spcflags & (SPCFLAG_BRK | SPCFLAG_MODE_CHANGE)) {
5922 return 1;
5923 }
5924
5925 int ilvl = cpu_thread_ilvl;
5926 if (ilvl > 0 && (ilvl > regs.intmask || ilvl == 7)) {
5927 do_interrupt(ilvl);
5928 }
5929
5930 if (!(regs.spcflags & SPCFLAG_STOP))
5931 break;
5932
5933 uae_sem_wait(&cpu_wakeup_sema);
5934 }
5935
5936 return 0;
5937 }
5938
5939 static void init_cpu_thread(void)
5940 {
5941 if (!currprefs.cpu_thread)
5942 return;
5943 if (m68k_cs_initialized)
5944 return;
5945 uae_sem_init(&cpu_in_sema, 0, 0);
5946 uae_sem_init(&cpu_out_sema, 0, 0);
5947 uae_sem_init(&cpu_wakeup_sema, 0, 0);
5948 m68k_cs_initialized = true;
5949 }
5950
5951 extern addrbank *thread_mem_banks[MEMORY_BANKS];
5952
5953 uae_u32 process_cpu_indirect_memory_read(uae_u32 addr, int size)
5954 {
5955 // Do direct access if call is from filesystem etc thread
5956 if (cpu_thread_tid != uae_thread_get_id()) {
5957 uae_u32 data = 0;
5958 addrbank *ab = thread_mem_banks[bankindex(addr)];
5959 switch (size)
5960 {
5961 case 0:
5962 data = ab->bget(addr) & 0xff;
5963 break;
5964 case 1:
5965 data = ab->wget(addr) & 0xffff;
5966 break;
5967 case 2:
5968 data = ab->lget(addr);
5969 break;
5970 }
5971 return data;
5972 }
5973
5974 cpu_thread_indirect_mode = 2;
5975 cpu_thread_indirect_addr = addr;
5976 cpu_thread_indirect_size = size;
5977 uae_sem_post(&cpu_out_sema);
5978 uae_sem_wait(&cpu_in_sema);
5979 cpu_thread_indirect_mode = 0xfe;
5980 return cpu_thread_indirect_val;
5981 }
5982
5983 void process_cpu_indirect_memory_write(uae_u32 addr, uae_u32 data, int size)
5984 {
5985 if (cpu_thread_tid != uae_thread_get_id()) {
5986 addrbank *ab = thread_mem_banks[bankindex(addr)];
5987 switch (size)
5988 {
5989 case 0:
5990 ab->bput(addr, data & 0xff);
5991 break;
5992 case 1:
5993 ab->wput(addr, data & 0xffff);
5994 break;
5995 case 2:
5996 ab->lput(addr, data);
5997 break;
5998 }
5999 return;
6000 }
6001 cpu_thread_indirect_mode = 1;
6002 cpu_thread_indirect_addr = addr;
6003 cpu_thread_indirect_size = size;
6004 cpu_thread_indirect_val = data;
6005 uae_sem_post(&cpu_out_sema);
6006 uae_sem_wait(&cpu_in_sema);
6007 cpu_thread_indirect_mode = 0xff;
6008 }
6009
6010 static void run_cpu_thread(void *(*f)(void *))
6011 {
6012 int framecnt = -1;
6013 int vp = 0;
6014 int intlev_prev = 0;
6015
6016 cpu_thread_active = 0;
6017 uae_sem_init(&cpu_in_sema, 0, 0);
6018 uae_sem_init(&cpu_out_sema, 0, 0);
6019 uae_sem_init(&cpu_wakeup_sema, 0, 0);
6020
6021 if (!uae_start_thread(_T("cpu"), f, NULL, NULL))
6022 return;
6023 while (!cpu_thread_active) {
6024 sleep_millis(1);
6025 }
6026
6027 while (!(regs.spcflags & SPCFLAG_MODE_CHANGE)) {
6028 int maxperloop = 10;
6029
6030 while (!uae_sem_trywait(&cpu_out_sema)) {
6031 uae_u32 cmd, addr, data, size, mode;
6032
6033 addr = cpu_thread_indirect_addr;
6034 data = cpu_thread_indirect_val;
6035 size = cpu_thread_indirect_size;
6036 mode = cpu_thread_indirect_mode;
6037
6038 switch(mode)
6039 {
6040 case 1:
6041 {
6042 addrbank *ab = thread_mem_banks[bankindex(addr)];
6043 switch (size)
6044 {
6045 case 0:
6046 ab->bput(addr, data & 0xff);
6047 break;
6048 case 1:
6049 ab->wput(addr, data & 0xffff);
6050 break;
6051 case 2:
6052 ab->lput(addr, data);
6053 break;
6054 }
6055 uae_sem_post(&cpu_in_sema);
6056 break;
6057 }
6058 case 2:
6059 {
6060 addrbank *ab = thread_mem_banks[bankindex(addr)];
6061 switch (size)
6062 {
6063 case 0:
6064 data = ab->bget(addr) & 0xff;
6065 break;
6066 case 1:
6067 data = ab->wget(addr) & 0xffff;
6068 break;
6069 case 2:
6070 data = ab->lget(addr);
6071 break;
6072 }
6073 cpu_thread_indirect_val = data;
6074 uae_sem_post(&cpu_in_sema);
6075 break;
6076 }
6077 default:
6078 write_log(_T("cpu_thread_indirect_mode=%08x!\n"), mode);
6079 break;
6080 }
6081
6082 if (maxperloop-- < 0)
6083 break;
6084 }
6085
6086 if (framecnt != timeframes) {
6087 framecnt = timeframes;
6088 }
6089
6090 if (cpu_thread_reset) {
6091 bool hardreset = cpu_thread_reset & 2;
6092 bool keyboardreset = cpu_thread_reset & 4;
6093 custom_reset(hardreset, keyboardreset);
6094 cpu_thread_reset = 0;
6095 uae_sem_post(&cpu_in_sema);
6096 }
6097
6098 if (regs.spcflags & SPCFLAG_BRK) {
6099 unset_special(SPCFLAG_BRK);
6100 #ifdef DEBUGGER
6101 if (debugging) {
6102 debug();
6103 }
6104 #endif
6105 }
6106
6107 if (vp == vpos) {
6108
6109 do_cycles((maxhpos / 2) * CYCLE_UNIT);
6110
6111 if (regs.spcflags & SPCFLAG_COPPER) {
6112 do_copper();
6113 }
6114
6115 check_uae_int_request();
6116 if (regs.spcflags & (SPCFLAG_INT | SPCFLAG_DOINT)) {
6117 int intr = intlev();
6118 unset_special(SPCFLAG_INT | SPCFLAG_DOINT);
6119 if (intr > 0) {
6120 cpu_thread_ilvl = intr;
6121 cycles_do_special();
6122 uae_sem_post(&cpu_wakeup_sema);
6123 } else {
6124 cpu_thread_ilvl = 0;
6125 }
6126 }
6127 continue;
6128 }
6129
6130 frame_time_t next = vsyncmintimepre + (vsynctimebase * vpos / (maxvpos + 1));
6131 frame_time_t c = read_processor_time();
6132 if ((int)next - (int)c > 0 && (int)next - (int)c < vsyncmaxtime * 2)
6133 continue;
6134
6135 vp = vpos;
6136
6137 }
6138
6139 while (cpu_thread_active) {
6140 uae_sem_post(&cpu_in_sema);
6141 uae_sem_post(&cpu_wakeup_sema);
6142 sleep_millis(1);
6143 }
6144
6145 }
6146
6147 #endif
6148
6149 #ifndef WINUAE_FOR_HATARI
6150 void custom_reset_cpu(bool hardreset, bool keyboardreset)
6151 {
6152 #ifdef WITH_THREADED_CPU
6153 if (cpu_thread_tid != uae_thread_get_id()) {
6154 custom_reset(hardreset, keyboardreset);
6155 return;
6156 }
6157 cpu_thread_reset = 1 | (hardreset ? 2 : 0) | (keyboardreset ? 4 : 0);
6158 uae_sem_post(&cpu_wakeup_sema);
6159 uae_sem_wait(&cpu_in_sema);
6160 #else
6161 custom_reset(hardreset, keyboardreset);
6162 #endif
6163 }
6164 #endif
6165
6166 #ifdef JIT /* Completely different run_2 replacement */
6167
6168 void do_nothing (void)
6169 {
6170 if (!currprefs.cpu_thread) {
6171 /* What did you expect this to do? */
6172 do_cycles (0);
6173 /* I bet you didn't expect *that* ;-) */
6174 }
6175 }
6176
6177 void exec_nostats (void)
6178 {
6179 struct regstruct *r = ®s;
6180
6181 for (;;)
6182 {
6183 if (currprefs.cpu_compatible) {
6184 r->opcode = get_word_020_prefetchf(m68k_getpc());
6185 } else {
6186 r->opcode = x_get_iword(0);
6187 }
6188 cpu_cycles = (*cpufunctbl[r->opcode])(r->opcode);
6189 cpu_cycles = adjust_cycles (cpu_cycles);
6190
6191 if (!currprefs.cpu_thread) {
6192 do_cycles (cpu_cycles);
6193
6194 #ifdef WITH_PPC
6195 if (ppc_state)
6196 ppc_interrupt(intlev());
6197 #endif
6198 }
6199 #ifdef WINUAE_FOR_HATARI
6200 if (end_block(r->opcode) || r->spcflags)
6201 #else
6202
6203 if (end_block(r->opcode) || r->spcflags || uae_int_requested)
6204 #endif
6205 return; /* We will deal with the spcflags in the caller */
6206 }
6207 }
6208
6209 void execute_normal (void)
6210 {
6211 struct regstruct *r = ®s;
6212 int blocklen;
6213 cpu_history pc_hist[MAXRUN];
6214 int total_cycles;
6215
6216 if (check_for_cache_miss ())
6217 return;
6218
6219 total_cycles = 0;
6220 blocklen = 0;
6221 start_pc_p = r->pc_oldp;
6222 start_pc = r->pc;
6223 for (;;) {
6224 /* Take note: This is the do-it-normal loop */
6225 regs.instruction_pc = m68k_getpc ();
6226 if (currprefs.cpu_compatible) {
6227 r->opcode = get_word_020_prefetchf (regs.instruction_pc);
6228 } else {
6229 r->opcode = x_get_iword(0);
6230 }
6231
6232 special_mem = DISTRUST_CONSISTENT_MEM;
6233 pc_hist[blocklen].location = (uae_u16*)r->pc_p;
6234
6235 cpu_cycles = (*cpufunctbl[r->opcode])(r->opcode);
6236 cpu_cycles = adjust_cycles(cpu_cycles);
6237 if (!currprefs.cpu_thread) {
6238 do_cycles (cpu_cycles);
6239 }
6240 total_cycles += cpu_cycles;
6241 pc_hist[blocklen].specmem = special_mem;
6242 blocklen++;
6243 #ifdef WINUAE_FOR_HATARI
6244 if (end_block (r->opcode) || blocklen >= MAXRUN || r->spcflags) {
6245 #else
6246 if (end_block (r->opcode) || blocklen >= MAXRUN || r->spcflags || uae_int_requested) {
6247 #endif
6248 compile_block (pc_hist, blocklen, total_cycles);
6249 return; /* We will deal with the spcflags in the caller */
6250 }
6251 /* No need to check regs.spcflags, because if they were set,
6252 we'd have ended up inside that "if" */
6253
6254 #ifdef WITH_PPC
6255 if (ppc_state)
6256 ppc_interrupt(intlev());
6257 #endif
6258 }
6259 }
6260
6261 typedef void compiled_handler (void);
6262
6263 #ifdef WITH_THREADED_CPU
6264 static void *cpu_thread_run_jit(void *v)
6265 {
6266 cpu_thread_tid = uae_thread_get_id();
6267 cpu_thread_active = 1;
6268 #ifdef USE_STRUCTURED_EXCEPTION_HANDLING
6269 __try
6270 #endif
6271 {
6272 for (;;) {
6273 ((compiled_handler*)(pushall_call_handler))();
6274 /* Whenever we return from that, we should check spcflags */
6275 if (regs.spcflags || cpu_thread_ilvl > 0) {
6276 if (do_specialties_thread()) {
6277 break;
6278 }
6279 }
6280 }
6281 }
6282 #ifdef USE_STRUCTURED_EXCEPTION_HANDLING
6283 #ifdef JIT
6284 __except (EvalException(GetExceptionInformation()))
6285 #else
6286 __except (DummyException(GetExceptionInformation(), GetExceptionCode()))
6287 #endif
6288 {
6289 // EvalException does the good stuff...
6290 }
6291 #endif
6292 cpu_thread_active = 0;
6293 return 0;
6294 }
6295 #endif
6296
6297 static void m68k_run_jit(void)
6298 {
6299 Log_Printf(LOG_DEBUG, "m68k_run_jit\n");
6300 #ifdef WITH_THREADED_CPU
6301 if (currprefs.cpu_thread) {
6302 run_cpu_thread(cpu_thread_run_jit);
6303 return;
6304 }
6305 #endif
6306
6307 for (;;) {
6308 #ifdef USE_STRUCTURED_EXCEPTION_HANDLING
6309 __try {
6310 #endif
6311 for (;;) {
6312 #ifdef WINUAE_FOR_HATARI
6313 //m68k_dumpstate_file(stderr, NULL, 0xffffffff);
6314 if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM))
6315 {
6316 int FrameCycles, HblCounterVideo, LineCycles;
6317 Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
6318 LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo );
6319 m68k_disasm_file(stderr, m68k_getpc (), NULL, m68k_getpc (), 1);
6320 }
6321 #endif
6322
6323 ((compiled_handler*)(pushall_call_handler))();
6324 /* Whenever we return from that, we should check spcflags */
6325 check_uae_int_request();
6326 if (regs.spcflags) {
6327 if (do_specialties(0)) {
6328 return;
6329 }
6330 }
6331 }
6332
6333 #ifdef USE_STRUCTURED_EXCEPTION_HANDLING
6334 } __except (EvalException(GetExceptionInformation())) {
6335 // Something very bad happened, generate fake bus error exception
6336 // Either emulation continues normally or crashes.
6337 // Without this it would have crashed in any case..
6338 uaecptr pc = M68K_GETPC;
6339 write_log(_T("Unhandled JIT exception! PC=%08x\n"), pc);
6340 if (pc & 1)
6341 Exception(3);
6342 else
6343 Exception(2);
6344 }
6345 #endif
6346 }
6347
6348 }
6349 #endif /* JIT */
6350
6351 #ifndef CPUEMU_0
6352
6353 static void m68k_run_2 (void)
6354 {
6355 }
6356
6357 #else
6358
6359 static void opcodedebug (uae_u32 pc, uae_u16 opcode, bool full)
6360 {
6361 struct mnemolookup *lookup;
6362 struct instr *dp;
6363 uae_u32 addr;
6364 int fault;
6365
6366 if (cpufunctbl[opcode] == op_illg_1)
6367 opcode = 0x4AFC;
6368 dp = table68k + opcode;
6369 for (lookup = lookuptab;lookup->mnemo != dp->mnemo; lookup++)
6370 ;
6371 fault = 0;
6372 TRY(prb) {
6373 addr = mmu_translate (pc, 0, (regs.mmu_ssw & 4) ? 1 : 0, 0, 0, sz_word);
6374 } CATCH (prb) {
6375 fault = 1;
6376 } ENDTRY
6377 if (!fault) {
6378 TCHAR buf[100];
6379 if (full)
6380 write_log (_T("mmufixup=%d %04x %04x\n"), mmufixup[0].reg, regs.wb3_status, regs.mmu_ssw);
6381 m68k_disasm_2 (buf, sizeof buf / sizeof (TCHAR), addr, NULL, 1, NULL, NULL, 0xffffffff, 0);
6382 write_log (_T("%s\n"), buf);
6383 if (full)
6384 m68k_dumpstate(NULL, 0xffffffff);
6385 }
6386 }
6387
6388 static void check_halt(void)
6389 {
6390 if (regs.halted)
6391 do_specialties (0);
6392 }
6393
6394 void cpu_halt (int id)
6395 {
6396 #ifndef WINUAE_FOR_HATARI
6397 // id < 0: m68k halted, PPC active.
6398 // id > 0: emulation halted.
6399 if (!regs.halted) {
6400 write_log (_T("CPU halted: reason = %d PC=%08x\n"), id, M68K_GETPC);
6401 regs.halted = id;
6402 gui_data.cpu_halted = id;
6403 gui_led(LED_CPU, 0, -1);
6404 if (id >= 0) {
6405 regs.intmask = 7;
6406 MakeSR ();
6407 audio_deactivate ();
6408 }
6409 }
6410 set_special(SPCFLAG_CHECK);
6411 #else
6412 Dialog_HaltDlg();
6413 #endif
6414 }
6415
6416 #ifdef CPUEMU_33
6417 /* [NP] TODO : use 68060 in Hatari ? with DSP ? */
6418 /* MMU 68060 */
6419 static void m68k_run_mmu060 (void)
6420 {
6421 struct flag_struct f;
6422 int halt = 0;
6423
6424 check_halt();
6425 #ifdef WINUAE_FOR_HATARI
6426 Log_Printf(LOG_DEBUG, "m68k_run_mmu060\n");
6427 #endif
6428
6429 while (!halt) {
6430 TRY (prb) {
6431 for (;;) {
6432 #ifdef WINUAE_FOR_HATARI
6433 //m68k_dumpstate_file(stderr, NULL, 0xffffffff);
6434 if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM))
6435 {
6436 int FrameCycles, HblCounterVideo, LineCycles;
6437 Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
6438 LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo );
6439 m68k_disasm_file(stderr, m68k_getpc (), NULL, m68k_getpc (), 1);
6440 }
6441 #endif
6442 f.cznv = regflags.cznv;
6443 f.x = regflags.x;
6444 regs.instruction_pc = m68k_getpc ();
6445
6446 do_cycles (cpu_cycles);
6447
6448 mmu_opcode = -1;
6449 mmu060_state = 0;
6450 mmu_opcode = regs.opcode = x_prefetch (0);
6451 mmu060_state = 1;
6452
6453 count_instr (regs.opcode);
6454 cpu_cycles = (*cpufunctbl[regs.opcode])(regs.opcode);
6455
6456 cpu_cycles = adjust_cycles (cpu_cycles);
6457 #ifdef WINUAE_FOR_HATARI
6458 M68000_AddCycles(cpu_cycles * 2 / CYCLE_UNIT);
6459
6460 if ( WaitStateCycles ) {
6461 /* Add some extra cycles to simulate a wait state */
6462 M68000_AddCycles(WaitStateCycles);
6463 WaitStateCycles = 0;
6464 }
6465
6466 while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) && ( ( regs.spcflags & SPCFLAG_STOP ) == 0 ) )
6467 CALL_VAR(PendingInterruptFunction); /* call the interrupt handler */
6468 if ( MFP_UpdateNeeded == true )
6469 MFP_UpdateIRQ ( 0 );
6470 #endif
6471 if (regs.spcflags) {
6472 if (do_specialties (cpu_cycles))
6473 return;
6474 }
6475 #ifdef WINUAE_FOR_HATARI
6476 /* Run DSP 56k code if necessary */
6477 if (bDspEnabled) {
6478 DSP_Run(2 * cpu_cycles * 2 / CYCLE_UNIT);
6479 // DSP_Run ( DSP_CPU_FREQ_RATIO * ( CyclesGlobalClockCounter - DSP_CyclesGlobalClockCounter ) );
6480 }
6481
6482 if ( savestate_state == STATE_SAVE )
6483 save_state ( NULL , NULL );
6484 #endif
6485 }
6486 } CATCH (prb) {
6487
6488 m68k_setpci (regs.instruction_pc);
6489 regflags.cznv = f.cznv;
6490 regflags.x = f.x;
6491
6492 if (mmufixup[0].reg >= 0) {
6493 m68k_areg (regs, mmufixup[0].reg) = mmufixup[0].value;
6494 mmufixup[0].reg = -1;
6495 }
6496 if (mmufixup[1].reg >= 0) {
6497 m68k_areg (regs, mmufixup[1].reg) = mmufixup[1].value;
6498 mmufixup[1].reg = -1;
6499 }
6500
6501 TRY (prb2) {
6502 Exception (prb);
6503 } CATCH (prb2) {
6504 halt = 1;
6505 } ENDTRY
6506 } ENDTRY
6507 }
6508 cpu_halt(halt);
6509 }
6510
6511 #endif
6512
6513 #ifdef CPUEMU_31
6514
6515 /* Aranym MMU 68040 */
6516 static void m68k_run_mmu040 (void)
6517 {
6518 struct flag_struct f;
6519 int halt = 0;
6520
6521 check_halt();
6522 #ifdef WINUAE_FOR_HATARI
6523 Log_Printf(LOG_DEBUG, "m68k_run_mmu040\n");
6524 #endif
6525
6526 while (!halt) {
6527 TRY (prb) {
6528 for (;;) {
6529 #ifdef WINUAE_FOR_HATARI
6530 //m68k_dumpstate_file(stderr, NULL, 0xffffffff);
6531 if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM))
6532 {
6533 int FrameCycles, HblCounterVideo, LineCycles;
6534 Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
6535 LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo );
6536 m68k_disasm_file(stderr, m68k_getpc (), NULL, m68k_getpc (), 1);
6537 }
6538 #endif
6539 f.cznv = regflags.cznv;
6540 f.x = regflags.x;
6541 mmu_restart = true;
6542 regs.instruction_pc = m68k_getpc ();
6543
6544 do_cycles (cpu_cycles);
6545
6546 mmu_opcode = -1;
6547 mmu_opcode = regs.opcode = x_prefetch (0);
6548 count_instr (regs.opcode);
6549 cpu_cycles = (*cpufunctbl[regs.opcode])(regs.opcode);
6550 cpu_cycles = adjust_cycles (cpu_cycles);
6551
6552 #ifdef WINUAE_FOR_HATARI
6553 M68000_AddCycles(cpu_cycles * 2 / CYCLE_UNIT);
6554
6555 if ( WaitStateCycles ) {
6556 /* Add some extra cycles to simulate a wait state */
6557 M68000_AddCycles(WaitStateCycles);
6558 WaitStateCycles = 0;
6559 }
6560
6561 /* We can have several interrupts at the same time before the next CPU instruction */
6562 /* We must check for pending interrupt and call do_specialties_interrupt() only */
6563 /* if the cpu is not in the STOP state. Else, the int could be acknowledged now */
6564 /* and prevent exiting the STOP state when calling do_specialties() after. */
6565 /* For performance, we first test PendingInterruptCount, then regs.spcflags */
6566 while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) && ( ( regs.spcflags & SPCFLAG_STOP ) == 0 ) )
6567 CALL_VAR(PendingInterruptFunction); /* call the interrupt handler */
6568 if ( MFP_UpdateNeeded == true )
6569 MFP_UpdateIRQ ( 0 );
6570 #endif
6571
6572 if (regs.spcflags) {
6573 if (do_specialties (cpu_cycles))
6574 return;
6575 }
6576
6577 #ifdef WINUAE_FOR_HATARI
6578 /* Run DSP 56k code if necessary */
6579 if (bDspEnabled) {
6580 DSP_Run(2 * cpu_cycles * 2 / CYCLE_UNIT);
6581 // DSP_Run ( DSP_CPU_FREQ_RATIO * ( CyclesGlobalClockCounter - DSP_CyclesGlobalClockCounter ) );
6582 }
6583
6584 if ( savestate_state == STATE_SAVE )
6585 save_state ( NULL , NULL );
6586 #endif
6587 }
6588 } CATCH (prb) {
6589
6590 if (mmu_restart) {
6591 /* restore state if instruction restart */
6592 regflags.cznv = f.cznv;
6593 regflags.x = f.x;
6594 m68k_setpci (regs.instruction_pc);
6595 }
6596
6597 if (mmufixup[0].reg >= 0) {
6598 m68k_areg (regs, mmufixup[0].reg) = mmufixup[0].value;
6599 mmufixup[0].reg = -1;
6600 }
6601
6602 TRY (prb2) {
6603 Exception (prb);
6604 } CATCH (prb2) {
6605 halt = 1;
6606 } ENDTRY
6607 } ENDTRY
6608 }
6609 cpu_halt(halt);
6610 }
6611
6612 #endif
6613
6614 #ifdef CPUEMU_32
6615
6616 // Previous MMU 68030
6617 static void m68k_run_mmu030 (void)
6618 {
6619 struct flag_struct f;
6620 int halt = 0;
6621
6622 #ifdef WINUAE_FOR_HATARI
6623 Log_Printf(LOG_DEBUG, "m68k_run_mmu030\n");
6624 #endif
6625
6626 mmu030_opcode_stageb = -1;
6627 mmu030_fake_prefetch = -1;
6628 check_halt();
6629 while(!halt) {
6630 TRY (prb) {
6631 for (;;) {
6632 int cnt;
6633 insretry:
6634 regs.instruction_pc = m68k_getpc ();
6635 f.cznv = regflags.cznv;
6636 f.x = regflags.x;
6637
6638 mmu030_state[0] = mmu030_state[1] = mmu030_state[2] = 0;
6639 mmu030_opcode = -1;
6640 if (mmu030_fake_prefetch >= 0) {
6641 // use fake prefetch opcode only if mapping changed
6642 uaecptr new_addr = mmu030_translate(regs.instruction_pc, regs.s != 0, false, false);
6643 if (mmu030_fake_prefetch_addr != new_addr) {
6644 regs.opcode = mmu030_fake_prefetch;
6645 write_log(_T("MMU030 fake prefetch remap: %04x, %08x -> %08x\n"), mmu030_fake_prefetch, mmu030_fake_prefetch_addr, new_addr);
6646 } else {
6647 if (mmu030_opcode_stageb < 0) {
6648 regs.opcode = x_prefetch (0);
6649 } else {
6650 regs.opcode = mmu030_opcode_stageb;
6651 mmu030_opcode_stageb = -1;
6652 }
6653 }
6654 mmu030_fake_prefetch = -1;
6655 } else if (mmu030_opcode_stageb < 0) {
6656 if (currprefs.cpu_compatible)
6657 regs.opcode = regs.irc;
6658 else
6659 regs.opcode = x_prefetch (0);
6660 } else {
6661 regs.opcode = mmu030_opcode_stageb;
6662 mmu030_opcode_stageb = -1;
6663 }
6664
6665 mmu030_opcode = regs.opcode;
6666 mmu030_ad[0].done = false;
6667
6668 cnt = 50;
6669 for (;;) {
6670 #ifdef WINUAE_FOR_HATARI
6671 //m68k_dumpstate_file(stderr, NULL, 0xffffffff);
6672 if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM))
6673 {
6674 int FrameCycles, HblCounterVideo, LineCycles;
6675 Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
6676 LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo );
6677 m68k_disasm_file(stderr, m68k_getpc (), NULL, m68k_getpc (), 1);
6678 }
6679 #endif
6680 regs.opcode = regs.irc = mmu030_opcode;
6681 mmu030_idx = 0;
6682
6683 mmu030_retry = false;
6684
6685 if (!currprefs.cpu_cycle_exact) {
6686
6687 count_instr (regs.opcode);
6688 do_cycles (cpu_cycles);
6689
6690 cpu_cycles = (*cpufunctbl[regs.opcode])(regs.opcode);
6691
6692 } else {
6693 #ifdef WINUAE_FOR_HATARI
6694 currcycle = 0;
6695 #endif
6696 (*cpufunctbl[regs.opcode])(regs.opcode);
6697
6698 wait_memory_cycles();
6699 }
6700
6701 cnt--; // so that we don't get in infinite loop if things go horribly wrong
6702 if (!mmu030_retry)
6703 break;
6704 if (cnt < 0) {
6705 cpu_halt (CPU_HALT_CPU_STUCK);
6706 break;
6707 }
6708 if (mmu030_retry && mmu030_opcode == -1)
6709 goto insretry; // urgh
6710 }
6711
6712 mmu030_opcode = -1;
6713
6714 if (!currprefs.cpu_cycle_exact) {
6715
6716 cpu_cycles = adjust_cycles (cpu_cycles);
6717 #ifdef WINUAE_FOR_HATARI
6718 M68000_AddCycles(cpu_cycles * 2 / CYCLE_UNIT);
6719
6720 if ( WaitStateCycles ) {
6721 /* Add some extra cycles to simulate a wait state */
6722 M68000_AddCycles(WaitStateCycles);
6723 WaitStateCycles = 0;
6724 }
6725
6726 /* We can have several interrupts at the same time before the next CPU instruction */
6727 /* We must check for pending interrupt and call do_specialties_interrupt() only */
6728 /* if the cpu is not in the STOP state. Else, the int could be acknowledged now */
6729 /* and prevent exiting the STOP state when calling do_specialties() after. */
6730 /* For performance, we first test PendingInterruptCount, then regs.spcflags */
6731 while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) && ( ( regs.spcflags & SPCFLAG_STOP ) == 0 ) )
6732 CALL_VAR(PendingInterruptFunction); /* call the interrupt handler */
6733 if ( MFP_UpdateNeeded == true )
6734 MFP_UpdateIRQ ( 0 );
6735 #endif
6736 if (regs.spcflags) {
6737 if (do_specialties (cpu_cycles))
6738 return;
6739 }
6740 #ifdef WINUAE_FOR_HATARI
6741 /* Run DSP 56k code if necessary */
6742 if (bDspEnabled) {
6743 DSP_Run(2 * cpu_cycles * 2 / CYCLE_UNIT);
6744 // DSP_Run ( DSP_CPU_FREQ_RATIO * ( CyclesGlobalClockCounter - DSP_CyclesGlobalClockCounter ) );
6745 }
6746 #endif
6747
6748 } else {
6749
6750 #ifdef WINUAE_FOR_HATARI
6751 //fprintf ( stderr, "cyc_2ce %d\n" , currcycle );
6752 /* Flush all CE cycles so far to update PendingInterruptCount */
6753 M68000_AddCycles_CE ( currcycle * 2 / CYCLE_UNIT );
6754 // currcycle = 0; // FIXME : uncomment this when using DSP_CyclesGlobalClockCounter in DSP_Run
6755
6756 /* We can have several interrupts at the same time before the next CPU instruction */
6757 /* We must check for pending interrupt and call do_specialties_interrupt() only */
6758 /* if the cpu is not in the STOP state. Else, the int could be acknowledged now */
6759 /* and prevent exiting the STOP state when calling do_specialties() after. */
6760 /* For performance, we first test PendingInterruptCount, then regs.spcflags */
6761 while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) && ( ( regs.spcflags & SPCFLAG_STOP ) == 0 ) )
6762 CALL_VAR(PendingInterruptFunction); /* call the interrupt handler */
6763 if ( MFP_UpdateNeeded == true )
6764 MFP_UpdateIRQ ( 0 );
6765 #endif
6766
6767 if (regs.spcflags || time_for_interrupt ()) {
6768 if (do_specialties (0))
6769 return;
6770 }
6771
6772 #ifdef WINUAE_FOR_HATARI
6773 /* Run DSP 56k code if necessary */
6774 if (bDspEnabled) {
6775 //fprintf ( stderr, "dsp cyc_2ce %d\n" , currcycle );
6776 DSP_Run(2 * currcycle * 2 / CYCLE_UNIT);
6777 //fprintf ( stderr, "dsp cyc_2ce %d - %d\n" , currcycle * 2 / CYCLE_UNIT , (CyclesGlobalClockCounter - DSP_CyclesGlobalClockCounter) );
6778 // DSP_Run ( DSP_CPU_FREQ_RATIO * ( CyclesGlobalClockCounter - DSP_CyclesGlobalClockCounter ) );
6779 }
6780 #endif
6781
6782 regs.ipl = regs.ipl_pin;
6783
6784 }
6785
6786 #ifdef WINUAE_FOR_HATARI
6787 if ( savestate_state == STATE_SAVE )
6788 save_state ( NULL , NULL );
6789 #endif
6790 }
6791
6792 } CATCH (prb) {
6793
6794 if (mmu030_opcode == -1 && currprefs.cpu_compatible) {
6795 // full prefetch fill access fault
6796 // TODO: this should create shorter A-frame
6797 mmufixup[0].reg = -1;
6798 mmufixup[1].reg = -1;
6799 } else if (!(mmu030_state[1] & MMU030_STATEFLAG1_LASTWRITE)) {
6800 regflags.cznv = f.cznv;
6801 regflags.x = f.x;
6802
6803 if (mmufixup[0].reg >= 0) {
6804 m68k_areg(regs, mmufixup[0].reg) = mmufixup[0].value;
6805 mmufixup[0].reg = -1;
6806 }
6807 if (mmufixup[1].reg >= 0) {
6808 m68k_areg(regs, mmufixup[1].reg) = mmufixup[1].value;
6809 mmufixup[1].reg = -1;
6810 }
6811 }
6812
6813 m68k_setpci (regs.instruction_pc);
6814
6815 TRY (prb2) {
6816 Exception (prb);
6817 } CATCH (prb2) {
6818 halt = 1;
6819 } ENDTRY
6820 } ENDTRY
6821 }
6822 cpu_halt (halt);
6823 }
6824
6825 #endif
6826
6827
6828 /* "cycle exact" 68040/060 */
6829
6830 static void m68k_run_3ce (void)
6831 {
6832 struct regstruct *r = ®s;
6833 bool exit = false;
6834 int extracycles = 0;
6835
6836 Log_Printf(LOG_DEBUG, "m68k_run_3ce\n");
6837
6838 while (!exit) {
6839 TRY(prb) {
6840 while (!exit) {
6841 #ifdef WINUAE_FOR_HATARI
6842 //m68k_dumpstate_file(stderr, NULL, 0xffffffff);
6843 if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM))
6844 {
6845 int FrameCycles, HblCounterVideo, LineCycles;
6846 Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
6847 LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo );
6848 m68k_disasm_file(stderr, m68k_getpc (), NULL, m68k_getpc (), 1);
6849 }
6850 currcycle = CYCLE_UNIT / 2; /* Assume at least 1 cycle per instruction */
6851 #endif
6852 r->instruction_pc = m68k_getpc();
6853 r->opcode = get_iword_cache_040(0);
6854 // "prefetch"
6855 if (regs.cacr & 0x8000)
6856 fill_icache040(r->instruction_pc + 16);
6857
6858 (*cpufunctbl[r->opcode])(r->opcode);
6859
6860 #ifdef WINUAE_FOR_HATARI
6861 //fprintf ( stderr, "cyc_3ce %ld\n" , currcycle );
6862 /* Flush all CE cycles so far to update PendingInterruptCount */
6863 M68000_AddCycles_CE ( currcycle * 2 / CYCLE_UNIT );
6864 // currcycle = 0; // FIXME : uncomment this when using DSP_CyclesGlobalClockCounter in DSP_Run
6865
6866 /* We can have several interrupts at the same time before the next CPU instruction */
6867 /* We must check for pending interrupt and call do_specialties_interrupt() only */
6868 /* if the cpu is not in the STOP state. Else, the int could be acknowledged now */
6869 /* and prevent exiting the STOP state when calling do_specialties() after. */
6870 /* For performance, we first test PendingInterruptCount, then regs.spcflags */
6871 while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) && ( ( regs.spcflags & SPCFLAG_STOP ) == 0 ) )
6872 CALL_VAR(PendingInterruptFunction); /* call the interrupt handler */
6873 if ( MFP_UpdateNeeded == true )
6874 MFP_UpdateIRQ ( 0 );
6875 #endif
6876 if (r->spcflags) {
6877 if (do_specialties (0))
6878 exit = true;
6879 }
6880
6881 // workaround for situation when all accesses are cached
6882 extracycles++;
6883 if (extracycles >= 8) {
6884 extracycles = 0;
6885 #ifdef WINUAE_FOR_HATARI
6886 x_do_cycles(CYCLE_UNIT);
6887 #else
6888 M68000_AddCycles_CE ( 2 );
6889 #endif
6890 }
6891
6892 #ifdef WINUAE_FOR_HATARI
6893 /* Run DSP 56k code if necessary */
6894 if (bDspEnabled) {
6895 DSP_Run(2 * currcycle * 2 / CYCLE_UNIT);
6896 // DSP_Run ( DSP_CPU_FREQ_RATIO * ( CyclesGlobalClockCounter - DSP_CyclesGlobalClockCounter ) );
6897 }
6898
6899 if ( savestate_state == STATE_SAVE )
6900 save_state ( NULL , NULL );
6901 #endif
6902 }
6903 } CATCH(prb) {
6904 bus_error();
6905 if (r->spcflags) {
6906 if (do_specialties(0))
6907 exit = true;
6908 }
6909 } ENDTRY
6910 }
6911 }
6912
6913 /* "prefetch" 68040/060 */
6914
6915 static void m68k_run_3p(void)
6916 {
6917 struct regstruct *r = ®s;
6918 bool exit = false;
6919 int cycles;
6920
6921 Log_Printf(LOG_DEBUG, "m68k_run_3p\n");
6922
6923 while (!exit) {
6924 TRY(prb) {
6925 while (!exit) {
6926 #ifdef WINUAE_FOR_HATARI
6927 //m68k_dumpstate_file(stderr, NULL, 0xffffffff);
6928 if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM))
6929 {
6930 int FrameCycles, HblCounterVideo, LineCycles;
6931 Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
6932 LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo );
6933 m68k_disasm_file(stderr, m68k_getpc (), NULL, m68k_getpc (), 1);
6934 }
6935 #endif
6936 r->instruction_pc = m68k_getpc();
6937 r->opcode = get_iword_cache_040(0);
6938 // "prefetch"
6939 if (regs.cacr & 0x8000)
6940 fill_icache040(r->instruction_pc + 16);
6941
6942 (*cpufunctbl[r->opcode])(r->opcode);
6943
6944 #ifndef WINUAE_FOR_HATARI
6945 cpu_cycles = 1 * CYCLE_UNIT;
6946 cycles = adjust_cycles(cpu_cycles);
6947 do_cycles(cycles);
6948 #else
6949 cycles = cpu_cycles = CYCLE_UNIT / 2;
6950 M68000_AddCycles_CE(cycles * 2 / CYCLE_UNIT);
6951
6952 if ( WaitStateCycles ) {
6953 /* Add some extra cycles to simulate a wait state */
6954 M68000_AddCycles(WaitStateCycles);
6955 WaitStateCycles = 0;
6956 }
6957
6958 /* We can have several interrupts at the same time before the next CPU instruction */
6959 /* We must check for pending interrupt and call do_specialties_interrupt() only */
6960 /* if the cpu is not in the STOP state. Else, the int could be acknowledged now */
6961 /* and prevent exiting the STOP state when calling do_specialties() after. */
6962 /* For performance, we first test PendingInterruptCount, then regs.spcflags */
6963 while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) && ( ( regs.spcflags & SPCFLAG_STOP ) == 0 ) )
6964 CALL_VAR(PendingInterruptFunction); /* call the interrupt handler */
6965 if ( MFP_UpdateNeeded == true )
6966 MFP_UpdateIRQ ( 0 );
6967 #endif
6968
6969 if (r->spcflags) {
6970 if (do_specialties(0))
6971 exit = true;
6972 }
6973
6974 #ifdef WINUAE_FOR_HATARI
6975 /* Run DSP 56k code if necessary */
6976 if (bDspEnabled) {
6977 DSP_Run(2 * cycles * 2 / CYCLE_UNIT);
6978 // DSP_Run ( DSP_CPU_FREQ_RATIO * ( CyclesGlobalClockCounter - DSP_CyclesGlobalClockCounter ) );
6979 }
6980
6981 if ( savestate_state == STATE_SAVE )
6982 save_state ( NULL , NULL );
6983 #endif
6984 }
6985 } CATCH(prb) {
6986 bus_error();
6987 if (r->spcflags) {
6988 if (do_specialties(0))
6989 exit = true;
6990 }
6991 } ENDTRY
6992 }
6993 }
6994
6995 /* "cycle exact" 68020/030 */
6996
6997 STATIC_INLINE struct cache030 *getcache030 (struct cache030 *cp, uaecptr addr, uae_u32 *tagp, int *lwsp);
6998 static void m68k_run_2ce (void)
6999 {
7000 struct regstruct *r = ®s;
7001 bool exit = false;
7002 bool first = true;
7003
7004 Log_Printf(LOG_DEBUG, "m68k_run_2ce\n");
7005
7006 while (!exit) {
7007 TRY(prb) {
7008 if (first) {
7009 if (cpu_tracer < 0) {
7010 memcpy (&r->regs, &cputrace.regs, 16 * sizeof (uae_u32));
7011 r->ir = cputrace.ir;
7012 r->irc = cputrace.irc;
7013 r->sr = cputrace.sr;
7014 r->usp = cputrace.usp;
7015 r->isp = cputrace.isp;
7016 r->intmask = cputrace.intmask;
7017 r->stopped = cputrace.stopped;
7018
7019 r->msp = cputrace.msp;
7020 r->vbr = cputrace.vbr;
7021 r->caar = cputrace.caar;
7022 r->cacr = cputrace.cacr;
7023 r->cacheholdingdata020 = cputrace.cacheholdingdata020;
7024 r->cacheholdingaddr020 = cputrace.cacheholdingaddr020;
7025 r->prefetch020addr = cputrace.prefetch020addr;
7026 memcpy(&r->prefetch020, &cputrace.prefetch020, CPU_PIPELINE_MAX * sizeof(uae_u16));
7027 memcpy(&r->prefetch020_valid, &cputrace.prefetch020_valid, CPU_PIPELINE_MAX * sizeof(uae_u8));
7028 memcpy(&caches020, &cputrace.caches020, sizeof caches020);
7029
7030 m68k_setpc (cputrace.pc);
7031 if (!r->stopped) {
7032 if (cputrace.state > 1)
7033 Exception (cputrace.state);
7034 else if (cputrace.state == 1)
7035 (*cpufunctbl[cputrace.opcode])(cputrace.opcode);
7036 }
7037 if (regs.stopped)
7038 set_special (SPCFLAG_STOP);
7039 set_cpu_tracer (false);
7040 goto cont;
7041 }
7042 set_cpu_tracer (false);
7043 first = false;
7044 }
7045
7046 while (!exit) {
7047 #if 0
7048 static int prevopcode;
7049 #endif
7050 #ifdef WINUAE_FOR_HATARI
7051 //m68k_dumpstate_file(stderr, NULL, 0xffffffff);
7052 if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM))
7053 {
7054 int FrameCycles, HblCounterVideo, LineCycles;
7055 Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
7056 LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo );
7057 m68k_disasm_file(stderr, m68k_getpc (), NULL, m68k_getpc (), 1);
7058 #if 0
7059 // logs to debug data cache issues
7060 struct cache030 *c1 ,*c2;
7061 int lws1, lws2;
7062 uae_u32 tag1, tag2;
7063 c1 = getcache030 (dcaches030, (uaecptr)0x27ece, &tag1, &lws1);
7064 c2 = getcache030 (dcaches030, (uaecptr)0x7f8192+4, &tag2, &lws2);
7065 fprintf ( stderr , "cache valid %d tag1 %x lws1 %x ctag %x data %x mem=%x\n" , c1->valid[lws1] , tag1 , lws1 , c1->tag , c1->data[lws1] , get_long(0x27ece) );
7066 //fprintf ( stderr , "cache valid %d tag2 %x lws2 %x ctag %x data %x mem=%x\n" , c2->valid[lws2] , tag2 , lws2 , c2->tag , c2->data[lws2] , get_long(0x7f8192+4) );
7067 #endif
7068 }
7069
7070 currcycle = 0;
7071 #endif
7072 r->instruction_pc = m68k_getpc ();
7073
7074 #if 0
7075 if (regs.irc == 0xfffb) {
7076 gui_message (_T("OPCODE %04X HAS FAULTY PREFETCH! PC=%08X"), prevopcode, r->instruction_pc);
7077 }
7078 #endif
7079
7080 //write_log (_T("%x %04x\n"), r->instruction_pc, regs.irc);
7081
7082 r->opcode = regs.irc;
7083 #if 0
7084 prevopcode = r->opcode;
7085 regs.irc = 0xfffb;
7086 #endif
7087 //write_log (_T("%08x %04x\n"), r->instruction_pc, opcode);
7088
7089 #ifndef WINUAE_FOR_HATARI
7090 #if DEBUG_CD32CDTVIO
7091 out_cd32io (r->instruction_pc);
7092 #endif
7093 #endif
7094
7095 if (cpu_tracer) {
7096
7097 #if CPUTRACE_DEBUG
7098 validate_trace ();
7099 #endif
7100 memcpy (&cputrace.regs, &r->regs, 16 * sizeof (uae_u32));
7101 cputrace.opcode = r->opcode;
7102 cputrace.ir = r->ir;
7103 cputrace.irc = r->irc;
7104 cputrace.sr = r->sr;
7105 cputrace.usp = r->usp;
7106 cputrace.isp = r->isp;
7107 cputrace.intmask = r->intmask;
7108 cputrace.stopped = r->stopped;
7109 cputrace.state = 1;
7110 cputrace.pc = m68k_getpc ();
7111
7112 cputrace.msp = r->msp;
7113 cputrace.vbr = r->vbr;
7114 cputrace.caar = r->caar;
7115 cputrace.cacr = r->cacr;
7116 cputrace.cacheholdingdata020 = r->cacheholdingdata020;
7117 cputrace.cacheholdingaddr020 = r->cacheholdingaddr020;
7118 cputrace.prefetch020addr = r->prefetch020addr;
7119 memcpy(&cputrace.prefetch020, &r->prefetch020, CPU_PIPELINE_MAX * sizeof (uae_u16));
7120 memcpy(&cputrace.prefetch020_valid, &r->prefetch020_valid, CPU_PIPELINE_MAX * sizeof(uae_u8));
7121 memcpy(&cputrace.caches020, &caches020, sizeof caches020);
7122
7123 cputrace.memoryoffset = 0;
7124 cputrace.cyclecounter = cputrace.cyclecounter_pre = cputrace.cyclecounter_post = 0;
7125 cputrace.readcounter = cputrace.writecounter = 0;
7126 }
7127
7128 #ifndef WINUAE_FOR_HATARI
7129 if (inputrecord_debug & 4) {
7130 if (input_record > 0)
7131 inprec_recorddebug_cpu (1);
7132 else if (input_play > 0)
7133 inprec_playdebug_cpu (1);
7134 }
7135 #endif
7136
7137 (*cpufunctbl[r->opcode])(r->opcode);
7138
7139 wait_memory_cycles();
7140
7141 #ifdef WINUAE_FOR_HATARI
7142 //fprintf ( stderr, "cyc_2ce %d\n" , currcycle );
7143 /* Flush all CE cycles so far to update PendingInterruptCount */
7144 M68000_AddCycles_CE ( currcycle * 2 / CYCLE_UNIT );
7145 // currcycle = 0; // FIXME : uncomment this when using DSP_CyclesGlobalClockCounter in DSP_Run
7146
7147 /* We can have several interrupts at the same time before the next CPU instruction */
7148 /* We must check for pending interrupt and call do_specialties_interrupt() only */
7149 /* if the cpu is not in the STOP state. Else, the int could be acknowledged now */
7150 /* and prevent exiting the STOP state when calling do_specialties() after. */
7151 /* For performance, we first test PendingInterruptCount, then regs.spcflags */
7152 while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) && ( ( regs.spcflags & SPCFLAG_STOP ) == 0 ) )
7153 CALL_VAR(PendingInterruptFunction); /* call the interrupt handler */
7154 if ( MFP_UpdateNeeded == true )
7155 MFP_UpdateIRQ ( 0 );
7156 #endif
7157
7158 cont:
7159 if (r->spcflags || time_for_interrupt ()) {
7160 if (do_specialties (0))
7161 exit = true;
7162 }
7163
7164 regs.ipl = regs.ipl_pin;
7165 #ifdef WINUAE_FOR_HATARI
7166 /* Run DSP 56k code if necessary */
7167 if (bDspEnabled) {
7168 //fprintf ( stderr, "dsp cyc_2ce %d\n" , currcycle );
7169 DSP_Run(2 * currcycle * 2 / CYCLE_UNIT);
7170 //fprintf ( stderr, "dsp cyc_2ce %d - %d\n" , currcycle * 2 / CYCLE_UNIT , (CyclesGlobalClockCounter - DSP_CyclesGlobalClockCounter) );
7171 // DSP_Run ( DSP_CPU_FREQ_RATIO * ( CyclesGlobalClockCounter - DSP_CyclesGlobalClockCounter ) );
7172 }
7173
7174 if ( savestate_state == STATE_SAVE )
7175 save_state ( NULL , NULL );
7176 #endif
7177
7178 }
7179 } CATCH(prb) {
7180 bus_error();
7181 if (r->spcflags || time_for_interrupt()) {
7182 if (do_specialties(0))
7183 exit = true;
7184 }
7185 regs.ipl = regs.ipl_pin;
7186 } ENDTRY
7187 }
7188 }
7189
7190 #ifdef CPUEMU_20
7191
7192 // full prefetch 020 (more compatible)
7193 static void m68k_run_2p (void)
7194 {
7195 struct regstruct *r = ®s;
7196 bool exit = false;
7197 bool first = true;
7198
7199 Log_Printf(LOG_DEBUG, "m68k_run_2p\n");
7200
7201 while (!exit) {
7202 TRY(prb) {
7203
7204 if (first) {
7205 if (cpu_tracer < 0) {
7206 memcpy (&r->regs, &cputrace.regs, 16 * sizeof (uae_u32));
7207 r->ir = cputrace.ir;
7208 r->irc = cputrace.irc;
7209 r->sr = cputrace.sr;
7210 r->usp = cputrace.usp;
7211 r->isp = cputrace.isp;
7212 r->intmask = cputrace.intmask;
7213 r->stopped = cputrace.stopped;
7214
7215 r->msp = cputrace.msp;
7216 r->vbr = cputrace.vbr;
7217 r->caar = cputrace.caar;
7218 r->cacr = cputrace.cacr;
7219 r->cacheholdingdata020 = cputrace.cacheholdingdata020;
7220 r->cacheholdingaddr020 = cputrace.cacheholdingaddr020;
7221 r->prefetch020addr = cputrace.prefetch020addr;
7222 memcpy(&r->prefetch020, &cputrace.prefetch020, CPU_PIPELINE_MAX * sizeof(uae_u16));
7223 memcpy(&r->prefetch020_valid, &cputrace.prefetch020_valid, CPU_PIPELINE_MAX * sizeof(uae_u8));
7224 memcpy(&caches020, &cputrace.caches020, sizeof caches020);
7225
7226 m68k_setpc (cputrace.pc);
7227 if (!r->stopped) {
7228 if (cputrace.state > 1)
7229 Exception (cputrace.state);
7230 else if (cputrace.state == 1)
7231 (*cpufunctbl[cputrace.opcode])(cputrace.opcode);
7232 }
7233 if (regs.stopped)
7234 set_special (SPCFLAG_STOP);
7235 set_cpu_tracer (false);
7236 goto cont;
7237 }
7238 set_cpu_tracer (false);
7239 first = false;
7240 }
7241
7242 while (!exit) {
7243 #ifdef WINUAE_FOR_HATARI
7244 //m68k_dumpstate_file(stderr, NULL, 0xffffffff);
7245 if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM))
7246 {
7247 int FrameCycles, HblCounterVideo, LineCycles;
7248 Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
7249 LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo );
7250 m68k_disasm_file(stderr, m68k_getpc (), NULL, m68k_getpc (), 1);
7251 }
7252 #endif
7253 r->instruction_pc = m68k_getpc ();
7254 r->opcode = regs.irc;
7255
7256 #ifndef WINUAE_FOR_HATARI
7257 #if DEBUG_CD32CDTVIO
7258 out_cd32io (m68k_getpc ());
7259 #endif
7260 #endif
7261
7262 if (cpu_tracer) {
7263
7264 #if CPUTRACE_DEBUG
7265 validate_trace ();
7266 #endif
7267 memcpy (&cputrace.regs, &r->regs, 16 * sizeof (uae_u32));
7268 cputrace.opcode = r->opcode;
7269 cputrace.ir = r->ir;
7270 cputrace.irc = r->irc;
7271 cputrace.sr = r->sr;
7272 cputrace.usp = r->usp;
7273 cputrace.isp = r->isp;
7274 cputrace.intmask = r->intmask;
7275 cputrace.stopped = r->stopped;
7276 cputrace.state = 1;
7277 cputrace.pc = m68k_getpc ();
7278
7279 cputrace.msp = r->msp;
7280 cputrace.vbr = r->vbr;
7281 cputrace.caar = r->caar;
7282 cputrace.cacr = r->cacr;
7283 cputrace.cacheholdingdata020 = r->cacheholdingdata020;
7284 cputrace.cacheholdingaddr020 = r->cacheholdingaddr020;
7285 cputrace.prefetch020addr = r->prefetch020addr;
7286 memcpy(&cputrace.prefetch020, &r->prefetch020, CPU_PIPELINE_MAX * sizeof(uae_u16));
7287 memcpy(&cputrace.prefetch020_valid, &r->prefetch020_valid, CPU_PIPELINE_MAX * sizeof(uae_u8));
7288 memcpy(&cputrace.caches020, &caches020, sizeof caches020);
7289
7290 cputrace.memoryoffset = 0;
7291 cputrace.cyclecounter = cputrace.cyclecounter_pre = cputrace.cyclecounter_post = 0;
7292 cputrace.readcounter = cputrace.writecounter = 0;
7293 }
7294
7295 #ifndef WINUAE_FOR_HATARI
7296 if (inputrecord_debug & 4) {
7297 if (input_record > 0)
7298 inprec_recorddebug_cpu (1);
7299 else if (input_play > 0)
7300 inprec_playdebug_cpu (1);
7301 }
7302 #endif
7303 if (cpu_cycles > 0)
7304 x_do_cycles(cpu_cycles);
7305
7306 if (currprefs.cpu_memory_cycle_exact) {
7307
7308 (*cpufunctbl[r->opcode])(r->opcode);
7309 // 0% = no extra cycles
7310 cpu_cycles = 4 * CYCLE_UNIT * cycles_mult;
7311 cpu_cycles /= CYCLES_DIV;
7312 cpu_cycles -= CYCLE_UNIT;
7313 if (cpu_cycles <= 0)
7314 cpu_cycles = cpucycleunit;
7315
7316 } else {
7317
7318 cpu_cycles = (*cpufunctbl[r->opcode])(r->opcode);
7319 cpu_cycles = adjust_cycles (cpu_cycles);
7320
7321 }
7322 cont:
7323 #ifdef WINUAE_FOR_HATARI
7324 //fprintf ( stderr , "waits %d %d %ld\n" , cpu_cycles*2/CYCLE_UNIT , WaitStateCycles , CyclesGlobalClockCounter );
7325 M68000_AddCycles(cpu_cycles * 2 / CYCLE_UNIT);
7326
7327 //fprintf ( stderr , "waits %d %d %ld\n" , cpu_cycles*2/CYCLE_UNIT , WaitStateCycles , CyclesGlobalClockCounter );
7328 if ( WaitStateCycles ) {
7329 /* Add some extra cycles to simulate a wait state */
7330 M68000_AddCycles(WaitStateCycles);
7331 WaitStateCycles = 0;
7332 }
7333 //fprintf ( stderr , "waits %d %d %ld\n" , cpu_cycles*2/CYCLE_UNIT , WaitStateCycles , CyclesGlobalClockCounter );
7334
7335 /* We can have several interrupts at the same time before the next CPU instruction */
7336 /* We must check for pending interrupt and call do_specialties_interrupt() only */
7337 /* if the cpu is not in the STOP state. Else, the int could be acknowledged now */
7338 /* and prevent exiting the STOP state when calling do_specialties() after. */
7339 /* For performance, we first test PendingInterruptCount, then regs.spcflags */
7340 while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) && ( ( regs.spcflags & SPCFLAG_STOP ) == 0 ) )
7341 CALL_VAR(PendingInterruptFunction); /* call the interrupt handler */
7342 if ( MFP_UpdateNeeded == true )
7343 MFP_UpdateIRQ ( 0 );
7344 #endif
7345
7346 if (r->spcflags) {
7347 if (do_specialties (cpu_cycles))
7348 exit = true;
7349 }
7350 ipl_fetch ();
7351
7352 #ifdef WINUAE_FOR_HATARI
7353 /* Run DSP 56k code if necessary */
7354 if (bDspEnabled) {
7355 //if ( DSP_CPU_FREQ_RATIO * ( (CyclesGlobalClockCounter - DSP_CyclesGlobalClockCounter) << nCpuFreqShift ) - 2 * cpu_cycles * 2 / CYCLE_UNIT >= 8 )
7356 //fprintf ( stderr , "dsp %d %d\n" , 2 * cpu_cycles * 2 / CYCLE_UNIT , DSP_CPU_FREQ_RATIO * ( (CyclesGlobalClockCounter - DSP_CyclesGlobalClockCounter) << nCpuFreqShift ) );
7357 DSP_Run(2 * cpu_cycles * 2 / CYCLE_UNIT);
7358 // DSP_Run ( DSP_CPU_FREQ_RATIO * ( CyclesGlobalClockCounter - DSP_CyclesGlobalClockCounter ) );
7359 }
7360
7361 if ( savestate_state == STATE_SAVE )
7362 save_state ( NULL , NULL );
7363 #endif
7364 }
7365 } CATCH(prb) {
7366 bus_error();
7367 if (r->spcflags) {
7368 if (do_specialties(cpu_cycles))
7369 exit = true;
7370 }
7371 ipl_fetch();
7372 } ENDTRY
7373 }
7374 }
7375
7376 #endif
7377
7378 #ifdef WITH_THREADED_CPU
7379 static void *cpu_thread_run_2(void *v)
7380 {
7381 bool exit = false;
7382 struct regstruct *r = ®s;
7383
7384 cpu_thread_tid = uae_thread_get_id();
7385
7386 cpu_thread_active = 1;
7387 while (!exit) {
7388 TRY(prb)
7389 {
7390 while (!exit) {
7391 r->instruction_pc = m68k_getpc();
7392
7393 r->opcode = x_get_iword(0);
7394
7395 (*cpufunctbl[r->opcode])(r->opcode);
7396
7397 if (regs.spcflags || cpu_thread_ilvl > 0) {
7398 if (do_specialties_thread())
7399 exit = true;
7400 }
7401
7402 }
7403 } CATCH(prb)
7404 {
7405 bus_error();
7406 if (r->spcflags) {
7407 if (do_specialties_thread())
7408 exit = true;
7409 }
7410 } ENDTRY
7411 }
7412 cpu_thread_active = 0;
7413 return 0;
7414 }
7415 #endif
7416
7417 /* Same thing, but don't use prefetch to get opcode. */
7418 static void m68k_run_2 (void)
7419 {
7420 #ifdef WITH_THREADED_CPU
7421 if (currprefs.cpu_thread) {
7422 run_cpu_thread(cpu_thread_run_2);
7423 return;
7424 }
7425 #endif
7426
7427 struct regstruct *r = ®s;
7428 bool exit = false;
7429
7430 Log_Printf(LOG_DEBUG, "m68k_run_2\n");
7431
7432 while (!exit) {
7433 TRY(prb) {
7434 while (!exit) {
7435 #ifdef WINUAE_FOR_HATARI
7436 //m68k_dumpstate_file(stderr, NULL, 0xffffffff);
7437 if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM))
7438 {
7439 int FrameCycles, HblCounterVideo, LineCycles;
7440 Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
7441 LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo );
7442 m68k_disasm_file(stderr, m68k_getpc (), NULL, m68k_getpc (), 1);
7443 }
7444 #endif
7445 r->instruction_pc = m68k_getpc ();
7446
7447 r->opcode = x_get_iword(0);
7448 count_instr (r->opcode);
7449
7450 do_cycles (cpu_cycles);
7451
7452 cpu_cycles = (*cpufunctbl[r->opcode])(r->opcode);
7453 cpu_cycles = adjust_cycles (cpu_cycles);
7454 #ifdef WINUAE_FOR_HATARI
7455 //fprintf ( stderr , "cyc_2 %d\n" , cpu_cycles );
7456 M68000_AddCyclesWithPairing(cpu_cycles * 2 / CYCLE_UNIT);
7457
7458 if ( WaitStateCycles ) {
7459 /* Add some extra cycles to simulate a wait state */
7460 M68000_AddCycles(WaitStateCycles);
7461 WaitStateCycles = 0;
7462 }
7463
7464 /* We can have several interrupts at the same time before the next CPU instruction */
7465 /* We must check for pending interrupt and call do_specialties_interrupt() only */
7466 /* if the cpu is not in the STOP state. Else, the int could be acknowledged now */
7467 /* and prevent exiting the STOP state when calling do_specialties() after. */
7468 /* For performance, we first test PendingInterruptCount, then regs.spcflags */
7469 while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) && ( ( regs.spcflags & SPCFLAG_STOP ) == 0 ) )
7470 CALL_VAR(PendingInterruptFunction); /* call the interrupt handler */
7471 if ( MFP_UpdateNeeded == true )
7472 MFP_UpdateIRQ ( 0 );
7473 #endif
7474
7475 if (r->spcflags) {
7476 if (do_specialties (cpu_cycles))
7477 exit = true;
7478 }
7479
7480 #ifdef WINUAE_FOR_HATARI
7481 /* Run DSP 56k code if necessary */
7482 if (bDspEnabled) {
7483 DSP_Run(2 * cpu_cycles * 2 / CYCLE_UNIT);
7484 // DSP_Run ( DSP_CPU_FREQ_RATIO * ( CyclesGlobalClockCounter - DSP_CyclesGlobalClockCounter ) );
7485 }
7486
7487 if ( savestate_state == STATE_SAVE )
7488 save_state ( NULL , NULL );
7489 #endif
7490 }
7491 } CATCH(prb) {
7492 bus_error();
7493 if (r->spcflags) {
7494 if (do_specialties(cpu_cycles))
7495 exit = true;
7496 }
7497 } ENDTRY
7498 }
7499 }
7500
7501 /* fake MMU 68k */
7502 #if 0
7503 static void m68k_run_mmu (void)
7504 {
7505 for (;;) {
7506 #ifdef WINUAE_FOR_HATARI
7507 //m68k_dumpstate_file(stderr, NULL, 0xffffffff);
7508 if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM))
7509 {
7510 int FrameCycles, HblCounterVideo, LineCycles;
7511 Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
7512 LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo );
7513 m68k_disasm_file(stderr, m68k_getpc (), NULL, m68k_getpc (), 1);
7514 }
7515 #endif
7516 regs.opcode = get_iiword (0);
7517 do_cycles (cpu_cycles);
7518 mmu_backup_regs = regs;
7519 cpu_cycles = (*cpufunctbl[regs.opcode])(regs.opcode);
7520 cpu_cycles = adjust_cycles (cpu_cycles);
7521 if (mmu_triggered)
7522 mmu_do_hit ();
7523 if (regs.spcflags) {
7524 if (do_specialties (cpu_cycles))
7525 return;
7526 }
7527 }
7528 }
7529 #endif
7530
7531 #endif /* CPUEMU_0 */
7532
7533 int in_m68k_go = 0;
7534
7535 #if 0
7536 static void exception2_handle (uaecptr addr, uaecptr fault)
7537 {
7538 last_addr_for_exception_3 = addr;
7539 last_fault_for_exception_3 = fault;
7540 last_writeaccess_for_exception_3 = 0;
7541 last_instructionaccess_for_exception_3 = 0;
7542 Exception (2);
7543 }
7544 #endif
7545
7546 static bool cpu_hardreset, cpu_keyboardreset;
7547
7548 bool is_hardreset(void)
7549 {
7550 return cpu_hardreset;
7551 }
7552 bool is_keyboardreset(void)
7553 {
7554 return cpu_keyboardreset;
7555 }
7556
7557 void m68k_go (int may_quit)
7558 {
7559 int hardboot = 1;
7560 int startup = 1;
7561
7562 #ifdef WITH_THREADED_CPU
7563 init_cpu_thread();
7564 #endif
7565 if (in_m68k_go || !may_quit) {
7566 write_log (_T("Bug! m68k_go is not reentrant.\n"));
7567 abort ();
7568 }
7569
7570 reset_frame_rate_hack ();
7571 update_68k_cycles ();
7572 #ifndef WINUAE_FOR_HATARI
7573 start_cycles = 0;
7574 #endif
7575
7576 set_cpu_tracer (false);
7577
7578 cpu_prefs_changed_flag = 0;
7579 in_m68k_go++;
7580 for (;;) {
7581 void (*run_func)(void);
7582
7583 #ifdef WINUAE_FOR_HATARI
7584 /* Exit hatari ? */
7585 if (bQuitProgram == true)
7586 break;
7587 #endif
7588
7589 cputrace.state = -1;
7590
7591 #ifndef WINUAE_FOR_HATARI
7592 if (regs.halted == CPU_HALT_ACCELERATOR_CPU_FALLBACK) {
7593 regs.halted = 0;
7594 cpu_do_fallback();
7595 }
7596
7597 if (currprefs.inprecfile[0] && input_play) {
7598 inprec_open (currprefs.inprecfile, NULL);
7599 changed_prefs.inprecfile[0] = currprefs.inprecfile[0] = 0;
7600 quit_program = UAE_RESET;
7601 }
7602 if (input_play || input_record)
7603 inprec_startup ();
7604 #endif
7605
7606 if (quit_program > 0) {
7607 int restored = 0;
7608 cpu_keyboardreset = quit_program == UAE_RESET_KEYBOARD;
7609 cpu_hardreset = ((quit_program == UAE_RESET_HARD ? 1 : 0) | hardboot) != 0;
7610
7611 if (quit_program == UAE_QUIT)
7612 break;
7613
7614 hsync_counter = 0;
7615 vsync_counter = 0;
7616 quit_program = 0;
7617 hardboot = 0;
7618
7619 #ifdef SAVESTATE
7620 if (savestate_state == STATE_DORESTORE)
7621 savestate_state = STATE_RESTORE;
7622 if (savestate_state == STATE_RESTORE)
7623 restore_state (savestate_fname);
7624 #ifndef WINUAE_FOR_HATARI
7625 else if (savestate_state == STATE_REWIND)
7626 savestate_rewind ();
7627 #endif
7628 #endif
7629 if (cpu_hardreset)
7630 m68k_reset_restore();
7631 prefs_changed_cpu();
7632 build_cpufunctbl();
7633 set_x_funcs();
7634 #ifndef WINUAE_FOR_HATARI
7635 set_cycles (start_cycles);
7636 #endif
7637 custom_reset (cpu_hardreset != 0, cpu_keyboardreset);
7638 m68k_reset2 (cpu_hardreset != 0);
7639 if (cpu_hardreset) {
7640 memory_clear ();
7641 write_log (_T("hardreset, memory cleared\n"));
7642 }
7643 cpu_hardreset = false;
7644 #ifdef SAVESTATE
7645 /* We may have been restoring state, but we're done now. */
7646 if (isrestore ()) {
7647 #ifndef WINUAE_FOR_HATARI
7648 if (debug_dma) {
7649 record_dma_reset ();
7650 record_dma_reset ();
7651 }
7652 #endif
7653 savestate_restore_finish ();
7654 #ifndef WINUAE_FOR_HATARI
7655 memory_map_dump ();
7656 #endif
7657 if (currprefs.mmu_model == 68030) {
7658 mmu030_decode_tc (tc_030, true);
7659 } else if (currprefs.mmu_model >= 68040) {
7660 mmu_set_tc (regs.tcr);
7661 }
7662 startup = 1;
7663 restored = 1;
7664 }
7665 #endif
7666 #ifndef WINUAE_FOR_HATARI
7667 if (currprefs.produce_sound == 0)
7668 eventtab[ev_audio].active = 0;
7669 m68k_setpc_normal (regs.pc);
7670 check_prefs_changed_audio ();
7671
7672 if (!restored || hsync_counter == 0)
7673 savestate_check ();
7674 if (input_record == INPREC_RECORD_START)
7675 input_record = INPREC_RECORD_NORMAL;
7676 statusline_clear();
7677 #else
7678 m68k_setpc_normal (regs.pc);
7679 #endif
7680 } else {
7681 #ifndef WINUAE_FOR_HATARI
7682 if (input_record == INPREC_RECORD_START) {
7683 input_record = INPREC_RECORD_NORMAL;
7684 savestate_init ();
7685 hsync_counter = 0;
7686 vsync_counter = 0;
7687 savestate_check ();
7688 }
7689 #endif
7690 }
7691
7692 #ifndef WINUAE_FOR_HATARI
7693 if (changed_prefs.inprecfile[0] && input_record)
7694 inprec_prepare_record (savestate_fname[0] ? savestate_fname : NULL);
7695 #endif
7696
7697 set_cpu_tracer (false);
7698
7699 #ifdef DEBUGGER
7700 if (debugging)
7701 debug ();
7702 #endif
7703 if (regs.spcflags & SPCFLAG_MODE_CHANGE) {
7704 if (cpu_prefs_changed_flag & 1) {
7705 uaecptr pc = m68k_getpc();
7706 prefs_changed_cpu();
7707 fpu_modechange();
7708 #ifndef WINUAE_FOR_HATARI
7709 custom_cpuchange();
7710 #endif
7711 build_cpufunctbl();
7712 m68k_setpc_normal(pc);
7713 fill_prefetch();
7714 }
7715 if (cpu_prefs_changed_flag & 2) {
7716 fixup_cpu(&changed_prefs);
7717 currprefs.m68k_speed = changed_prefs.m68k_speed;
7718 currprefs.m68k_speed_throttle = changed_prefs.m68k_speed_throttle;
7719 update_68k_cycles();
7720 #ifndef WINUAE_FOR_HATARI
7721 target_cpu_speed();
7722 #endif
7723 }
7724 cpu_prefs_changed_flag = 0;
7725 }
7726
7727 set_x_funcs();
7728 #ifndef WINUAE_FOR_HATARI
7729 if (startup) {
7730 custom_prepare ();
7731 protect_roms (true);
7732 }
7733 startup = 0;
7734 event_wait = true;
7735 #endif
7736 unset_special(SPCFLAG_MODE_CHANGE);
7737
7738 if (!regs.halted) {
7739 // check that PC points to something that looks like memory.
7740 uaecptr pc = m68k_getpc();
7741 #ifndef WINUAE_FOR_HATARI
7742 addrbank *ab = get_mem_bank_real(pc);
7743 #else
7744 addrbank *ab = &get_mem_bank(pc);
7745 #endif
7746 if (ab == NULL || ab == &dummy_bank || (!currprefs.cpu_compatible && !valid_address(pc, 2)) || (pc & 1)) {
7747 cpu_halt(CPU_HALT_INVALID_START_ADDRESS);
7748 }
7749 }
7750 if (regs.halted) {
7751 cpu_halt (regs.halted);
7752 if (regs.halted < 0) {
7753 haltloop();
7754 continue;
7755 }
7756 }
7757
7758 #ifdef WINUAE_FOR_HATARI
7759 /* Apply patches for gemdos HD if needed (we need to do it after */
7760 /* cpu tables for all opcodes were rebuilt in build_cpufunctbl() ) */
7761 Cart_PatchCpuTables();
7762
7763 /* Restore debugger state (breakpoints) after a reset */
7764 M68000_RestoreDebugger();
7765 #endif
7766
7767 #if 0
7768 if (mmu_enabled && !currprefs.cachesize) {
7769 run_func = m68k_run_mmu;
7770 } else {
7771 #endif
7772 run_func = currprefs.cpu_cycle_exact && currprefs.cpu_model <= 68010 ? m68k_run_1_ce :
7773 currprefs.cpu_compatible && currprefs.cpu_model <= 68010 ? m68k_run_1 :
7774 #ifdef JIT
7775 currprefs.cpu_model >= 68020 && currprefs.cachesize ? m68k_run_jit :
7776 #endif
7777 currprefs.cpu_model == 68030 && currprefs.mmu_model ? m68k_run_mmu030 :
7778 currprefs.cpu_model == 68040 && currprefs.mmu_model ? m68k_run_mmu040 :
7779 currprefs.cpu_model == 68060 && currprefs.mmu_model ? m68k_run_mmu060 :
7780
7781 currprefs.cpu_model >= 68040 && currprefs.cpu_cycle_exact ? m68k_run_3ce :
7782 currprefs.cpu_model >= 68020 && currprefs.cpu_cycle_exact ? m68k_run_2ce :
7783
7784 currprefs.cpu_model <= 68020 && currprefs.cpu_compatible ? m68k_run_2p :
7785 currprefs.cpu_model == 68030 && currprefs.cpu_compatible ? m68k_run_2p :
7786 currprefs.cpu_model >= 68040 && currprefs.cpu_compatible ? m68k_run_3p :
7787
7788 m68k_run_2;
7789 #if 0
7790 }
7791 #endif
7792 run_func();
7793 Log_Printf(LOG_DEBUG, "exit m68k_run\n");
7794 }
7795 #ifndef WINUAE_FOR_HATARI
7796 protect_roms (false);
7797 #endif
7798 in_m68k_go--;
7799 }
7800
7801 #if 0
7802 static void m68k_verify (uaecptr addr, uaecptr *nextpc)
7803 {
7804 uae_u16 opcode, val;
7805 struct instr *dp;
7806
7807 opcode = get_iword_1 (0);
7808 last_op_for_exception_3 = opcode;
7809 m68kpc_offset = 2;
7810
7811 if (cpufunctbl[opcode] == op_illg_1) {
7812 opcode = 0x4AFC;
7813 }
7814 dp = table68k + opcode;
7815
7816 if (dp->suse) {
7817 if (!verify_ea (dp->sreg, dp->smode, dp->size, &val)) {
7818 Exception (3, 0);
7819 return;
7820 }
7821 }
7822 if (dp->duse) {
7823 if (!verify_ea (dp->dreg, dp->dmode, dp->size, &val)) {
7824 Exception (3, 0);
7825 return;
7826 }
7827 }
7828 }
7829 #endif
7830
7831 static const TCHAR *ccnames[] =
7832 {
7833 _T("T "),_T("F "),_T("HI"),_T("LS"),_T("CC"),_T("CS"),_T("NE"),_T("EQ"),
7834 _T("VC"),_T("VS"),_T("PL"),_T("MI"),_T("GE"),_T("LT"),_T("GT"),_T("LE")
7835 };
7836 static const TCHAR *fpccnames[] =
7837 {
7838 _T("F"),
7839 _T("EQ"),
7840 _T("OGT"),
7841 _T("OGE"),
7842 _T("OLT"),
7843 _T("OLE"),
7844 _T("OGL"),
7845 _T("OR"),
7846 _T("UN"),
7847 _T("UEQ"),
7848 _T("UGT"),
7849 _T("UGE"),
7850 _T("ULT"),
7851 _T("ULE"),
7852 _T("NE"),
7853 _T("T"),
7854 _T("SF"),
7855 _T("SEQ"),
7856 _T("GT"),
7857 _T("GE"),
7858 _T("LT"),
7859 _T("LE"),
7860 _T("GL"),
7861 _T("GLE"),
7862 _T("NGLE"),
7863 _T("NGL"),
7864 _T("NLE"),
7865 _T("NLT"),
7866 _T("NGE"),
7867 _T("NGT"),
7868 _T("SNE"),
7869 _T("ST")
7870 };
7871 static const TCHAR *fpuopcodes[] =
7872 {
7873 _T("FMOVE"),
7874 _T("FINT"),
7875 _T("FSINH"),
7876 _T("FINTRZ"),
7877 _T("FSQRT"),
7878 NULL,
7879 _T("FLOGNP1"),
7880 NULL,
7881 _T("FETOXM1"),
7882 _T("FTANH"),
7883 _T("FATAN"),
7884 NULL,
7885 _T("FASIN"),
7886 _T("FATANH"),
7887 _T("FSIN"),
7888 _T("FTAN"),
7889 _T("FETOX"), // 0x10
7890 _T("FTWOTOX"),
7891 _T("FTENTOX"),
7892 NULL,
7893 _T("FLOGN"),
7894 _T("FLOG10"),
7895 _T("FLOG2"),
7896 NULL,
7897 _T("FABS"),
7898 _T("FCOSH"),
7899 _T("FNEG"),
7900 NULL,
7901 _T("FACOS"),
7902 _T("FCOS"),
7903 _T("FGETEXP"),
7904 _T("FGETMAN"),
7905 _T("FDIV"), // 0x20
7906 _T("FMOD"),
7907 _T("FADD"),
7908 _T("FMUL"),
7909 _T("FSGLDIV"),
7910 _T("FREM"),
7911 _T("FSCALE"),
7912 _T("FSGLMUL"),
7913 _T("FSUB"),
7914 NULL,
7915 NULL,
7916 NULL,
7917 NULL,
7918 NULL,
7919 NULL,
7920 NULL,
7921 _T("FSINCOS"), // 0x30
7922 _T("FSINCOS"),
7923 _T("FSINCOS"),
7924 _T("FSINCOS"),
7925 _T("FSINCOS"),
7926 _T("FSINCOS"),
7927 _T("FSINCOS"),
7928 _T("FSINCOS"),
7929 _T("FCMP"),
7930 NULL,
7931 _T("FTST"),
7932 NULL,
7933 NULL,
7934 NULL,
7935 NULL,
7936 NULL
7937 };
7938
7939 static const TCHAR *movemregs[] =
7940 {
7941 _T("D0"),
7942 _T("D1"),
7943 _T("D2"),
7944 _T("D3"),
7945 _T("D4"),
7946 _T("D5"),
7947 _T("D6"),
7948 _T("D7"),
7949 _T("A0"),
7950 _T("A1"),
7951 _T("A2"),
7952 _T("A3"),
7953 _T("A4"),
7954 _T("A5"),
7955 _T("A6"),
7956 _T("A7"),
7957 _T("FP0"),
7958 _T("FP1"),
7959 _T("FP2"),
7960 _T("FP3"),
7961 _T("FP4"),
7962 _T("FP5"),
7963 _T("FP6"),
7964 _T("FP7"),
7965 _T("FPIAR"),
7966 _T("FPSR"),
7967 _T("FPCR")
7968 };
7969
7970 static void addmovemreg (TCHAR *out, int *prevreg, int *lastreg, int *first, int reg, int fpmode)
7971 {
7972 TCHAR *p = out + _tcslen (out);
7973 if (*prevreg < 0) {
7974 *prevreg = reg;
7975 *lastreg = reg;
7976 return;
7977 }
7978 if (reg < 0 || fpmode == 2 || (*prevreg) + 1 != reg || (reg & 8) != ((*prevreg & 8))) {
7979 _stprintf (p, _T("%s%s"), (*first) ? _T("") : _T("/"), movemregs[*lastreg]);
7980 p = p + _tcslen (p);
7981 if (*lastreg != *prevreg) {
7982 if ((*lastreg) + 2 == reg) {
7983 _stprintf(p, _T("/%s"), movemregs[*prevreg]);
7984 } else if ((*lastreg) != (*prevreg)) {
7985 _stprintf(p, _T("-%s"), movemregs[*prevreg]);
7986 }
7987 }
7988 *lastreg = reg;
7989 *first = 0;
7990 }
7991 *prevreg = reg;
7992 }
7993
7994 static bool movemout (TCHAR *out, uae_u16 mask, int mode, int fpmode, bool dst)
7995 {
7996 unsigned int dmask, amask;
7997 int prevreg = -1, lastreg = -1, first = 1;
7998
7999 if (mode == Apdi && !fpmode) {
8000 uae_u8 dmask2;
8001 uae_u8 amask2;
8002
8003 amask2 = mask & 0xff;
8004 dmask2 = (mask >> 8) & 0xff;
8005 dmask = 0;
8006 amask = 0;
8007 for (int i = 0; i < 8; i++) {
8008 if (dmask2 & (1 << i))
8009 dmask |= 1 << (7 - i);
8010 if (amask2 & (1 << i))
8011 amask |= 1 << (7 - i);
8012 }
8013 } else {
8014 dmask = mask & 0xff;
8015 amask = (mask >> 8) & 0xff;
8016 if (fpmode == 1 && mode != Apdi) {
8017 uae_u8 dmask2 = dmask;
8018 dmask = 0;
8019 for (int i = 0; i < 8; i++) {
8020 if (dmask2 & (1 << i))
8021 dmask |= 1 << (7 - i);
8022 }
8023 }
8024 }
8025 bool dataout = dmask != 0 || amask != 0;
8026 if (dst && dataout)
8027 _tcscat(out, _T(","));
8028 if (fpmode) {
8029 while (dmask) { addmovemreg(out, &prevreg, &lastreg, &first, movem_index1[dmask] + (fpmode == 2 ? 24 : 16), fpmode); dmask = movem_next[dmask]; }
8030 } else {
8031 while (dmask) { addmovemreg (out, &prevreg, &lastreg, &first, movem_index1[dmask], fpmode); dmask = movem_next[dmask]; }
8032 while (amask) { addmovemreg (out, &prevreg, &lastreg, &first, movem_index1[amask] + 8, fpmode); amask = movem_next[amask]; }
8033 }
8034 addmovemreg(out, &prevreg, &lastreg, &first, -1, fpmode);
8035 return dataout;
8036 }
8037
8038 static void disasm_size (TCHAR *instrname, struct instr *dp)
8039 {
8040 if (dp->unsized) {
8041 _tcscat(instrname, _T(" "));
8042 return;
8043 }
8044 switch (dp->size)
8045 {
8046 case sz_byte:
8047 _tcscat (instrname, _T(".B "));
8048 break;
8049 case sz_word:
8050 _tcscat (instrname, _T(".W "));
8051 break;
8052 case sz_long:
8053 _tcscat (instrname, _T(".L "));
8054 break;
8055 default:
8056 _tcscat (instrname, _T(" "));
8057 break;
8058 }
8059 }
8060
8061 static void asm_add_extensions(uae_u16 *data, int *dcntp, int mode, uae_u32 v, uae_u16 *ext, uaecptr pc, int size)
8062 {
8063 int dcnt = *dcntp;
8064 if (mode < 0)
8065 return;
8066 if (mode == Ad16) {
8067 data[dcnt++] = v;
8068 }
8069 if (mode == PC16) {
8070 data[dcnt++] = v - (pc + 2);
8071 }
8072 if (mode == Ad8r || mode == PC8r) {
8073 data[dcnt++] = ext[0];
8074 }
8075 if (mode == absw) {
8076 data[dcnt++] = (uae_u16)v;
8077 }
8078 if (mode == absl) {
8079 data[dcnt++] = (uae_u16)(v >> 16);
8080 data[dcnt++] = (uae_u16)v;
8081 }
8082 if ((mode == imm && size == 0) || mode == imm0) {
8083 data[dcnt++] = (uae_u8)v;
8084 }
8085 if ((mode == imm && size == 1) || mode == imm1) {
8086 data[dcnt++] = (uae_u16)v;
8087 }
8088 if ((mode == imm && size == 2) || mode == imm2) {
8089 data[dcnt++] = (uae_u16)(v >> 16);
8090 data[dcnt++] = (uae_u16)v;
8091 }
8092 *dcntp = dcnt;
8093 }
8094
8095 static int asm_isdreg(const TCHAR *s)
8096 {
8097 if (s[0] == 'D' && s[1] >= '0' && s[1] <= '7')
8098 return s[1] - '0';
8099 return -1;
8100 }
8101 static int asm_isareg(const TCHAR *s)
8102 {
8103 if (s[0] == 'A' && s[1] >= '0' && s[1] <= '7')
8104 return s[1] - '0';
8105 if (s[0] == 'S' && s[1] == 'P')
8106 return 7;
8107 return -1;
8108 }
8109 static int asm_ispc(const TCHAR *s)
8110 {
8111 if (s[0] == 'P' && s[1] == 'C')
8112 return 1;
8113 return 0;
8114 }
8115
8116 static uae_u32 asmgetval(const TCHAR *s)
8117 {
8118 TCHAR *endptr;
8119 if (s[0] == '-')
8120 return _tcstol(s, &endptr, 16);
8121 return _tcstoul(s, &endptr, 16);
8122 }
8123
8124 static int asm_parse_mode(TCHAR *s, uae_u8 *reg, uae_u32 *v, uae_u16 *ext)
8125 {
8126 TCHAR *ss = s;
8127 *reg = -1;
8128 *v = 0;
8129 *ext = 0;
8130 if (s[0] == 0)
8131 return -1;
8132 // Dn
8133 if (asm_isdreg(s) >= 0 && s[2] == 0) {
8134 *reg = asm_isdreg(s);
8135 return Dreg;
8136 }
8137 // An
8138 if (asm_isareg(s) >= 0 && s[2] == 0) {
8139 *reg = asm_isareg(s);
8140 return Areg;
8141 }
8142 // (An) and (An)+
8143 if (s[0] == '(' && asm_isareg(s + 1) >= 0 && s[3] == ')') {
8144 *reg = asm_isareg(s + 1);
8145 if (s[4] == '+' && s[5] == 0)
8146 return Aipi;
8147 if (s[4] == 0)
8148 return Aind;
8149 return -1;
8150 }
8151 // -(An)
8152 if (s[0] == '-' && s[1] == '(' && asm_isareg(s + 2) >= 0 && s[4] == ')' && s[5] == 0) {
8153 *reg = asm_isareg(s + 2);
8154 return Apdi;
8155 }
8156 // Immediate
8157 if (s[0] == '#') {
8158 if (s[1] == '!') {
8159 *v = _tstol(s + 2);
8160 } else {
8161 *v = asmgetval(s + 1);
8162 }
8163 return imm;
8164 }
8165 // Value
8166 if (s[0] == '!') {
8167 *v = _tstol(s + 1);
8168 } else {
8169 *v = asmgetval(s);
8170 }
8171 int dots = 0;
8172 unsigned int i;
8173 for (i = 0; i < _tcslen(s); i++) {
8174 if (s[i] == ',')
8175 dots++;
8176 }
8177 while (*s != 0) {
8178 // d16(An)
8179 if (dots == 0 && s[0] == '(' && asm_isareg(s + 1) >= 0 && s[3] == ')' && s[4] == 0) {
8180 *reg = asm_isareg(s + 1);
8181 return Ad16;
8182 }
8183 // d16(PC)
8184 if (dots == 0 && s[0] == '(' && asm_ispc(s + 1) && s[3] == ')' && s[4] == 0) {
8185 *reg = 2;
8186 return PC16;
8187 }
8188 // (d16,An) / (d16,PC)
8189 if (dots == 1 && s[0] == '(' && !asm_ispc(s + 1) && asm_isareg(s + 1) < 0 && asm_isdreg(s + 1) < 0) {
8190 TCHAR *startptr, *endptr;
8191 if (s[1] == '!') {
8192 startptr = s + 2;
8193 *v = _tcstol(startptr, &endptr, 10);
8194 } else {
8195 startptr = s + 1;
8196 *v = _tcstol(startptr, &endptr, 16);
8197 }
8198 if (endptr == startptr || endptr[0] != ',')
8199 return -1;
8200 if (asm_ispc(endptr + 1) && endptr[3] == ')') {
8201 *reg = 2;
8202 return PC16;
8203 }
8204 if (asm_isareg(endptr + 1) >= 0 && endptr[3] == ')') {
8205 *reg = asm_isareg(endptr + 1);
8206 return Ad16;
8207 }
8208 return -1;
8209 }
8210 // Ad8r PC8r
8211 if (s[0] == '(') {
8212 TCHAR *s2 = s;
8213 if (!asm_ispc(s + 1) && asm_isareg(s + 1) < 0 && asm_isdreg(s + 1) < 0) {
8214 if (dots != 2)
8215 return -1;
8216 TCHAR *startptr, *endptr;
8217 if (s[1] == '!') {
8218 startptr = s + 2;
8219 *v = _tcstol(startptr, &endptr, 10);
8220 } else {
8221 startptr = s + 1;
8222 *v = _tcstol(startptr, &endptr, 16);
8223 }
8224 if (endptr == startptr || endptr[0] != ',')
8225 return -1;
8226 s2 = endptr + 1;
8227 } else if (((asm_isareg(s + 1) >= 0 || asm_ispc(s + 1)) && s[3] == ',') || (asm_isdreg(s + 4) >= 0 || asm_isareg(s + 4) >= 0)) {
8228 if (dots != 1)
8229 return -1;
8230 s2 = s + 1;
8231 } else {
8232 return -1;
8233 }
8234 uae_u8 reg2;
8235 bool ispc = asm_ispc(s2);
8236 if (ispc) {
8237 *reg = 3;
8238 } else {
8239 *reg = asm_isareg(s2);
8240 }
8241 s2 += 2;
8242 if (*s2 != ',')
8243 return -1;
8244 s2++;
8245 if (asm_isdreg(s2) >= 0) {
8246 reg2 = asm_isdreg(s2);
8247 } else {
8248 reg2 = asm_isareg(s2);
8249 *ext |= 1 << 15;
8250 }
8251 s2 += 2;
8252 *ext |= reg2 << 12;
8253 *ext |= (*v) & 0xff;
8254 if (s2[0] == '.' && s2[1] == 'W') {
8255 s2 += 2;
8256 } else if (s2[0] == '.' && s2[1] == 'L') {
8257 *ext |= 1 << 11;
8258 s2 += 2;
8259 }
8260 if (s2[0] == '*') {
8261 TCHAR scale = s2[1];
8262 if (scale == '2')
8263 *ext |= 1 << 9;
8264 else if (scale == '4')
8265 *ext |= 2 << 9;
8266 else if (scale == '8')
8267 *ext |= 3 << 9;
8268 else
8269 return -1;
8270 s2 += 2;
8271 }
8272 if (s2[0] == ')' && s2[1] == 0) {
8273 return ispc ? PC8r : Ad8r;
8274 }
8275 return -1;
8276 }
8277 s++;
8278 }
8279 // abs.w
8280 if (s - ss > 2 && s[-2] == '.' && s[-1] == 'W') {
8281 *reg = 0;
8282 return absw;
8283 }
8284 // abs.l
8285 *reg = 1;
8286 return absl;
8287 }
8288
8289 static TCHAR *asm_parse_parm(TCHAR *parm, TCHAR *out)
8290 {
8291 TCHAR *p = parm;
8292 bool quote = false;
8293
8294 for (;;) {
8295 if (*p == '(') {
8296 quote = true;
8297 }
8298 if (*p == ')') {
8299 if (!quote)
8300 return NULL;
8301 quote = false;
8302 }
8303 if ((*p == ',' || *p == 0) && !quote) {
8304 TCHAR c = *p;
8305 p[0] = 0;
8306 _tcscpy(out, parm);
8307 my_trim(out);
8308 if (c)
8309 p++;
8310 return p;
8311 }
8312 p++;
8313 }
8314 }
8315
8316 static bool m68k_asm_parse_movec(TCHAR *s, TCHAR *d)
8317 {
8318 for (int i = 0; m2cregs[i].regname; i++) {
8319 if (!_tcscmp(s, m2cregs[i].regname)) {
8320 uae_u16 v = m2cregs[i].regno;
8321 if (asm_isareg(d) >= 0)
8322 v |= 0x8000 | (asm_isareg(d) << 12);
8323 else if (asm_isdreg(d) >= 0)
8324 v |= (asm_isdreg(d) << 12);
8325 else
8326 return false;
8327 _stprintf(s, _T("#%X"), v);
8328 return true;
8329 }
8330 }
8331 return false;
8332 }
8333
8334 static bool m68k_asm_parse_movem(TCHAR *s, int dir)
8335 {
8336 TCHAR *d = s;
8337 uae_u16 regmask = 0;
8338 uae_u16 mask = dir ? 0x8000 : 0x0001;
8339 bool ret = false;
8340 while(*s) {
8341 int dreg = asm_isdreg(s);
8342 int areg = asm_isareg(s);
8343 if (dreg < 0 && areg < 0)
8344 break;
8345 int reg = dreg >= 0 ? dreg : areg + 8;
8346 regmask |= dir ? (mask >> reg) : (mask << reg);
8347 s += 2;
8348 if (*s == 0) {
8349 ret = true;
8350 break;
8351 } else if (*s == '/') {
8352 s++;
8353 continue;
8354 } else if (*s == '-') {
8355 s++;
8356 int dreg2 = asm_isdreg(s);
8357 int areg2 = asm_isareg(s);
8358 if (dreg2 < 0 && areg2 < 0)
8359 break;
8360 int reg2 = dreg2 >= 0 ? dreg2 : areg2 + 8;
8361 if (reg2 < reg)
8362 break;
8363 while (reg2 >= reg) {
8364 regmask |= dir ? (mask >> reg) : (mask << reg);
8365 reg++;
8366 }
8367 s += 2;
8368 if (*s == 0) {
8369 ret = true;
8370 break;
8371 }
8372 } else {
8373 break;
8374 }
8375 }
8376 if (ret)
8377 _stprintf(d, _T("#%X"), regmask);
8378 return ret;
8379 }
8380
8381 int m68k_asm(TCHAR *sline, uae_u16 *out, uaecptr pc)
8382 {
8383 TCHAR *p;
8384 const TCHAR *cp1;
8385 TCHAR ins[256], parms[256];
8386 TCHAR line[256];
8387 TCHAR srcea[256], dstea[256];
8388 uae_u16 data[16], sexts[8], dexts[8];
8389 int dcnt = 0;
8390 int cc = -1;
8391 int quick = 0;
8392 bool immrelpc = false;
8393
8394 if (_tcslen(sline) > 100)
8395 return -1;
8396
8397 srcea[0] = dstea[0] = 0;
8398 parms[0] = 0;
8399
8400 // strip all white space except first space
8401 p = line;
8402 bool firstsp = true;
8403 for (int i = 0; sline[i]; i++) {
8404 TCHAR c = sline[i];
8405 if (c == 32 && firstsp) {
8406 firstsp = false;
8407 *p++ = 32;
8408 }
8409 if (c <= 32)
8410 continue;
8411 *p++ = c;
8412 }
8413 *p = 0;
8414
8415 to_upper(line, _tcslen(line));
8416
8417 p = line;
8418 while (*p && *p != ' ')
8419 p++;
8420 if (*p == ' ') {
8421 *p = 0;
8422 _tcscpy(parms, p + 1);
8423 my_trim(parms);
8424 }
8425 _tcscpy(ins, line);
8426
8427 if (_tcslen(ins) == 0)
8428 return 0;
8429
8430 int size = 1;
8431 int inssize = -1;
8432 cp1 = _tcschr(line, '.');
8433 if (cp1) {
8434 size = cp1[1];
8435 if (size == 'W')
8436 size = 1;
8437 else if (size == 'L')
8438 size = 2;
8439 else if (size == 'B')
8440 size = 0;
8441 else
8442 return 0;
8443 inssize = size;
8444 line[cp1 - line] = 0;
8445 _tcscpy(ins, line);
8446 }
8447
8448 TCHAR *parmp = parms;
8449 parmp = asm_parse_parm(parmp, srcea);
8450 if (!parmp)
8451 return 0;
8452 if (srcea[0]) {
8453 parmp = asm_parse_parm(parmp, dstea);
8454 if (!parmp)
8455 return 0;
8456 }
8457
8458 int smode = -1;
8459 int dmode = -1;
8460 uae_u8 sreg = -1;
8461 uae_u8 dreg = -1;
8462 uae_u32 sval = 0;
8463 uae_u32 dval = 0;
8464 int ssize = -1;
8465 int dsize = -1;
8466
8467 dmode = asm_parse_mode(dstea, &dreg, &dval, dexts);
8468
8469
8470 // Common alias
8471 if (!_tcscmp(ins, _T("BRA"))) {
8472 _tcscpy(ins, _T("BT"));
8473 } else if (!_tcscmp(ins, _T("BSR"))) {
8474 immrelpc = true;
8475 } else if (!_tcscmp(ins, _T("MOVEM"))) {
8476 if (dmode >= Aind && _tcschr(dstea, '-') == NULL && _tcschr(dstea, '/') == NULL) {
8477 _tcscpy(ins, _T("MVMLE"));
8478 if (!m68k_asm_parse_movem(srcea, dmode == Apdi))
8479 return -1;
8480 } else {
8481 TCHAR tmp[256];
8482 _tcscpy(ins, _T("MVMEL"));
8483 _tcscpy(tmp, srcea);
8484 _tcscpy(srcea, dstea);
8485 _tcscpy(dstea, tmp);
8486 if (!m68k_asm_parse_movem(srcea, 0))
8487 return -1;
8488 dmode = asm_parse_mode(dstea, &dreg, &dval, dexts);
8489 }
8490 } else if (!_tcscmp(ins, _T("MOVEC"))) {
8491 if (dmode == Dreg || dmode == Areg) {
8492 _tcscpy(ins, _T("MOVEC2"));
8493 if (!m68k_asm_parse_movec(srcea, dstea))
8494 return -1;
8495 } else {
8496 TCHAR tmp[256];
8497 _tcscpy(ins, _T("MOVE2C"));
8498 _tcscpy(tmp, srcea);
8499 _tcscpy(srcea, dstea);
8500 dstea[0] = 0;
8501 if (!m68k_asm_parse_movec(srcea, tmp))
8502 return -1;
8503 }
8504 dmode = -1;
8505 }
8506
8507 if (dmode == Areg) {
8508 int l = _tcslen(ins);
8509 if (l <= 2)
8510 return -1;
8511 TCHAR last = ins[l- 1];
8512 if (last == 'Q') {
8513 last = ins[l - 2];
8514 if (last != 'A') {
8515 ins[l - 1] = 'A';
8516 ins[l] = 'Q';
8517 ins[l + 1] = 0;
8518 }
8519 } else if (last != 'A') {
8520 _tcscat(ins, _T("A"));
8521 }
8522 }
8523
8524 bool fp = ins[0] == 'F';
8525
8526 if (ins[_tcslen(ins) - 1] == 'Q' && _tcslen(ins) > 3 && !fp) {
8527 quick = 1;
8528 ins[_tcslen(ins) - 1] = 0;
8529 }
8530
8531 struct mnemolookup *lookup;
8532 for (lookup = lookuptab; lookup->name; lookup++) {
8533 if (!_tcscmp(ins, lookup->name))
8534 break;
8535 }
8536 if (!lookup->name) {
8537 // Check cc variants
8538 for (lookup = lookuptab; lookup->name; lookup++) {
8539 const TCHAR *ccp = _tcsstr(lookup->name, _T("cc"));
8540 if (ccp) {
8541 TCHAR tmp[256];
8542 for (int i = 0; i < (fp ? 32 : 16); i++) {
8543 const TCHAR *ccname = fp ? fpccnames[i] : ccnames[i];
8544 _tcscpy(tmp, lookup->name);
8545 _tcscpy(tmp + (ccp - lookup->name), ccname);
8546 if (tmp[_tcslen(tmp) - 1] == ' ')
8547 tmp[_tcslen(tmp) - 1] = 0;
8548 if (!_tcscmp(tmp, ins)) {
8549 _tcscpy(ins, lookup->name);
8550 cc = i;
8551 if (lookup->mnemo == i_DBcc || lookup->mnemo == i_Bcc) {
8552 // Bcc.B uses same encoding mode as MOVEQ
8553 immrelpc = true;
8554 }
8555 if (size == 0) {
8556 quick = 2;
8557 }
8558 break;
8559 }
8560 }
8561 }
8562 if (cc >= 0)
8563 break;
8564 }
8565 }
8566
8567 if (!lookup->name)
8568 return 0;
8569
8570 int mnemo = lookup->mnemo;
8571
8572 int found = 0;
8573 int sizemask = 0;
8574 int tsize = size;
8575 int unsized = 0;
8576
8577 for (int round = 0; round < 9; round++) {
8578
8579 if (!found && round == 8)
8580 return 0;
8581
8582 if (round == 3) {
8583 // Q is always LONG sized
8584 if (quick == 1) {
8585 tsize = 2;
8586 }
8587 bool isimm = srcea[0] == '#';
8588 if (immrelpc && !isimm) {
8589 TCHAR tmp[256];
8590 _tcscpy(tmp, srcea);
8591 srcea[0] = '#';
8592 _tcscpy(srcea + 1, tmp);
8593 }
8594 smode = asm_parse_mode(srcea, &sreg, &sval, sexts);
8595 if (immrelpc && !isimm) {
8596 sval = sval - (pc + 2);
8597 }
8598 if (quick) {
8599 smode = immi;
8600 sreg = sval & 0xff;
8601 }
8602 }
8603
8604 if (round == 1) {
8605 if (!quick && (sizemask == 1 || sizemask == 2 || sizemask == 4)) {
8606 tsize = 0;
8607 if (sizemask == 2)
8608 tsize = 1;
8609 else if (sizemask == 4)
8610 tsize = 2;
8611 } else {
8612 continue;
8613 }
8614 }
8615 if (round == 2 && !found) {
8616 unsized = 1;
8617 }
8618
8619 if (round == 4 && smode == imm) {
8620 smode = imm0;
8621 } else if (round == 5 && smode == imm0) {
8622 smode = imm1;
8623 } else if (round == 6 && smode == imm1) {
8624 smode = imm2;
8625 } else if (round == 7 && smode == imm2) {
8626 smode = immi;
8627 sreg = sval & 0xff;
8628 } else if (round == 4) {
8629 round += 5 - 1;
8630 }
8631
8632 for (int opcode = 0; opcode < 65536; opcode++) {
8633 struct instr *table = &table68k[opcode];
8634 if (table->mnemo != mnemo)
8635 continue;
8636 if (cc >= 0 && table->cc != cc)
8637 continue;
8638
8639 #if 0
8640 if (round == 0) {
8641 console_out_f(_T("%s OP=%04x S=%d SR=%d SM=%d SU=%d SP=%d DR=%d DM=%d DU=%d DP=%d SDU=%d\n"), lookup->name, opcode, table->size,
8642 table->sreg, table->smode, table->suse, table->spos,
8643 table->dreg, table->dmode, table->duse, table->dpos,
8644 table->sduse);
8645 }
8646 #endif
8647
8648 if (table->duse && !(table->dmode == dmode || (dmode >= imm && dmode <= imm2 && table->dmode >= imm && table->dmode <= imm2)))
8649 continue;
8650 if (round == 0) {
8651 sizemask |= 1 << table->size;
8652 }
8653 if (unsized > 0 && !table->unsized) {
8654 continue;
8655 }
8656
8657 found++;
8658
8659 if (round >= 3) {
8660
8661 if (
8662 ((table->size == tsize || table->unsized)) &&
8663 ((!table->suse && smode < 0) || (table->suse && table->smode == smode)) &&
8664 ((!table->duse && dmode < 0) || (table->duse && (table->dmode == dmode || (dmode == imm && (table->dmode >= imm && table->dmode <= imm2))))) &&
8665 ((table->sreg == sreg || (table->smode >= absw && table->smode != immi))) &&
8666 ((table->dreg == dreg || table->dmode >= absw))
8667 )
8668 {
8669 if (inssize >= 0 && tsize != inssize)
8670 continue;
8671
8672
8673 data[dcnt++] = opcode;
8674 asm_add_extensions(data, &dcnt, smode, sval, sexts, pc, tsize);
8675 if (smode >= 0)
8676 asm_add_extensions(data, &dcnt, dmode, dval, dexts, pc, tsize);
8677 for (int i = 0; i < dcnt; i++) {
8678 out[i] = data[i];
8679 }
8680 return dcnt;
8681 }
8682
8683 }
8684 }
8685 }
8686
8687 return 0;
8688 }
8689
8690 static void resolve_if_jmp(TCHAR *s, uae_u32 addr)
8691 {
8692 uae_u16 opcode = get_word_debug(addr);
8693 if (opcode == 0x4ef9) { // JMP x.l
8694 TCHAR *p = s + _tcslen(s);
8695 uae_u32 addr2 = get_long_debug(addr + 2);
8696 _stprintf(p, _T(" == $%08x "), addr2);
8697 showea_val(p + _tcslen(p), opcode, addr2, 4);
8698 TCHAR txt[256];
8699 bool ext;
8700 if (debugmem_get_segment(addr2, NULL, &ext, NULL, txt)) {
8701 if (ext) {
8702 _tcscat(p, _T(" "));
8703 _tcscat(p, txt);
8704 }
8705 }
8706 }
8707 }
8708
8709
8710 void m68k_disasm_2 (TCHAR *buf, int bufsize, uaecptr pc, uaecptr *nextpc, int cnt, uae_u32 *seaddr, uae_u32 *deaddr, uaecptr lastpc, int safemode)
8711 {
8712 uae_u32 seaddr2;
8713 uae_u32 deaddr2;
8714
8715 if (!table68k)
8716 return;
8717 while (cnt-- > 0) {
8718 TCHAR instrname[256], *ccpt;
8719 TCHAR segout[256], segname[256];
8720 int i;
8721 uae_u32 opcode;
8722 uae_u16 extra;
8723 struct mnemolookup *lookup;
8724 struct instr *dp;
8725 uaecptr oldpc;
8726 uaecptr m68kpc_illg = 0;
8727 bool illegal = false;
8728 int segid, lastsegid;
8729 TCHAR *symbolpos;
8730
8731 seaddr2 = deaddr2 = 0;
8732 oldpc = pc;
8733 opcode = get_word_debug (pc);
8734 extra = get_word_debug (pc + 2);
8735 if (cpufunctbl[opcode] == op_illg_1 || cpufunctbl[opcode] == op_unimpl_1) {
8736 m68kpc_illg = pc + 2;
8737 illegal = TRUE;
8738 }
8739
8740 dp = table68k + opcode;
8741 if (dp->mnemo == i_ILLG) {
8742 illegal = FALSE;
8743 opcode = 0x4AFC;
8744 dp = table68k + opcode;
8745 }
8746 for (lookup = lookuptab;lookup->mnemo != dp->mnemo; lookup++)
8747 ;
8748
8749 lastsegid = -1;
8750 bool exact = false;
8751 if (lastpc != 0xffffffff) {
8752 lastsegid = debugmem_get_segment(lastpc, NULL, NULL, NULL, NULL);
8753 }
8754 segid = debugmem_get_segment(pc, &exact, NULL, segout, segname);
8755 if (segid && (lastsegid != -1 || exact) && (segid != lastsegid || pc == lastpc || exact)) {
8756 buf = buf_out(buf, &bufsize, _T("%s\n"), segname);
8757 }
8758 symbolpos = buf;
8759
8760 buf = buf_out (buf, &bufsize, _T("%08X "), pc);
8761
8762 if (segid) {
8763 buf = buf_out(buf, &bufsize, _T("%s "), segout);
8764 }
8765
8766 pc += 2;
8767
8768 if (lookup->friendlyname)
8769 _tcscpy (instrname, lookup->friendlyname);
8770 else
8771 _tcscpy (instrname, lookup->name);
8772 ccpt = _tcsstr (instrname, _T("cc"));
8773 if (ccpt != 0) {
8774 if ((opcode & 0xf000) == 0xf000)
8775 _tcscpy (ccpt, fpccnames[extra & 0x1f]);
8776 else
8777 _tcsncpy (ccpt, ccnames[dp->cc], 2);
8778 }
8779 disasm_size (instrname, dp);
8780
8781 if (lookup->mnemo == i_MOVEC2 || lookup->mnemo == i_MOVE2C) {
8782 uae_u16 imm = extra;
8783 uae_u16 creg = imm & 0x0fff;
8784 uae_u16 r = imm >> 12;
8785 TCHAR regs[16];
8786 const TCHAR *cname = _T("?");
8787 int j;
8788 for (j = 0; m2cregs[j].regname; j++) {
8789 if (m2cregs[j].regno == creg)
8790 break;
8791 }
8792 _stprintf (regs, _T("%c%d"), r >= 8 ? 'A' : 'D', r >= 8 ? r - 8 : r);
8793 if (m2cregs[j].regname)
8794 cname = m2cregs[j].regname;
8795 if (lookup->mnemo == i_MOVE2C) {
8796 _tcscat (instrname, regs);
8797 _tcscat (instrname, _T(","));
8798 _tcscat (instrname, cname);
8799 } else {
8800 _tcscat (instrname, cname);
8801 _tcscat (instrname, _T(","));
8802 _tcscat (instrname, regs);
8803 }
8804 pc += 2;
8805 } else if (lookup->mnemo == i_MVMEL) {
8806 uae_u16 mask = extra;
8807 pc += 2;
8808 pc = ShowEA (0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, deaddr, safemode);
8809 movemout (instrname, mask, dp->dmode, 0, true);
8810 } else if (lookup->mnemo == i_MVMLE) {
8811 uae_u16 mask = extra;
8812 pc += 2;
8813 if (movemout(instrname, mask, dp->dmode, 0, false))
8814 _tcscat(instrname, _T(","));
8815 pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, deaddr, safemode);
8816 } else if (lookup->mnemo == i_DIVL || lookup->mnemo == i_MULL) {
8817 TCHAR *p;
8818 pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &seaddr2, safemode);
8819 extra = get_word_debug(pc);
8820 pc += 2;
8821 p = instrname + _tcslen(instrname);
8822 if (extra & 0x0400)
8823 _stprintf(p, _T(",D%d:D%d"), extra & 7, (extra >> 12) & 7);
8824 else
8825 _stprintf(p, _T(",D%d"), (extra >> 12) & 7);
8826 } else if (lookup->mnemo == i_MOVES) {
8827 TCHAR *p;
8828 pc += 2;
8829 if (!(extra & 0x0800)) {
8830 pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &seaddr2, safemode);
8831 p = instrname + _tcslen(instrname);
8832 _stprintf(p, _T(",%c%d"), (extra & 0x8000) ? 'A' : 'D', (extra >> 12) & 7);
8833 } else {
8834 p = instrname + _tcslen(instrname);
8835 _stprintf(p, _T("%c%d,"), (extra & 0x8000) ? 'A' : 'D', (extra >> 12) & 7);
8836 pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &seaddr2, safemode);
8837 }
8838 } else if (lookup->mnemo == i_BFEXTS || lookup->mnemo == i_BFEXTU ||
8839 lookup->mnemo == i_BFCHG || lookup->mnemo == i_BFCLR ||
8840 lookup->mnemo == i_BFFFO || lookup->mnemo == i_BFINS ||
8841 lookup->mnemo == i_BFSET || lookup->mnemo == i_BFTST) {
8842 TCHAR *p;
8843 int reg = -1;
8844
8845 pc += 2;
8846 p = instrname + _tcslen(instrname);
8847 if (lookup->mnemo == i_BFEXTS || lookup->mnemo == i_BFEXTU || lookup->mnemo == i_BFFFO || lookup->mnemo == i_BFINS)
8848 reg = (extra >> 12) & 7;
8849 if (lookup->mnemo == i_BFINS)
8850 _stprintf(p, _T("D%d,"), reg);
8851 pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &seaddr2, safemode);
8852 _tcscat(instrname, _T(" {"));
8853 p = instrname + _tcslen(instrname);
8854 if (extra & 0x0800)
8855 _stprintf(p, _T("D%d"), (extra >> 6) & 7);
8856 else
8857 _stprintf(p, _T("%d"), (extra >> 6) & 31);
8858 _tcscat(instrname, _T(":"));
8859 p = instrname + _tcslen(instrname);
8860 if (extra & 0x0020)
8861 _stprintf(p, _T("D%d"), extra & 7);
8862 else
8863 _stprintf(p, _T("%d"), extra & 31);
8864 _tcscat(instrname, _T("}"));
8865 p = instrname + _tcslen(instrname);
8866 if (lookup->mnemo == i_BFFFO || lookup->mnemo == i_BFEXTS || lookup->mnemo == i_BFEXTU)
8867 _stprintf(p, _T(",D%d"), reg);
8868 } else if (lookup->mnemo == i_CPUSHA || lookup->mnemo == i_CPUSHL || lookup->mnemo == i_CPUSHP ||
8869 lookup->mnemo == i_CINVA || lookup->mnemo == i_CINVL || lookup->mnemo == i_CINVP) {
8870 if ((opcode & 0xc0) == 0xc0)
8871 _tcscat(instrname, _T("BC"));
8872 else if (opcode & 0x80)
8873 _tcscat(instrname, _T("IC"));
8874 else if (opcode & 0x40)
8875 _tcscat(instrname, _T("DC"));
8876 else
8877 _tcscat(instrname, _T("?"));
8878 if (lookup->mnemo == i_CPUSHL || lookup->mnemo == i_CPUSHP || lookup->mnemo == i_CINVL || lookup->mnemo == i_CINVP) {
8879 TCHAR *p = instrname + _tcslen(instrname);
8880 _stprintf(p, _T(",(A%d)"), opcode & 7);
8881 }
8882 } else if (lookup->mnemo == i_MOVE16) {
8883 TCHAR *p = instrname + _tcslen(instrname);
8884 if (opcode & 0x20) {
8885 _stprintf(p, _T("(A%d)+,(A%d)+"), opcode & 7, (extra >> 12) & 7);
8886 pc += 2;
8887 } else {
8888 uae_u32 addr = get_long_debug(pc + 2);
8889 int ay = opcode & 7;
8890 pc += 4;
8891 switch ((opcode >> 3) & 3)
8892 {
8893 case 0:
8894 _stprintf(p, _T("(A%d)+,$%08x"), ay, addr);
8895 break;
8896 case 1:
8897 _stprintf(p, _T("$%08x,(A%d)+"), addr, ay);
8898 break;
8899 case 2:
8900 _stprintf(p, _T("(A%d),$%08x"), ay, addr);
8901 break;
8902 case 3:
8903 _stprintf(p, _T("$%08x,(A%d)"), addr, ay);
8904 break;
8905 }
8906 }
8907 } else if (lookup->mnemo == i_FPP) {
8908 TCHAR *p;
8909 int ins = extra & 0x3f;
8910 int size = (extra >> 10) & 7;
8911
8912 pc += 2;
8913 if ((extra & 0xfc00) == 0x5c00) { // FMOVECR (=i_FPP with source specifier = 7)
8914 fpdata fp;
8915 fpu_get_constant(&fp, extra);
8916 _stprintf(instrname, _T("FMOVECR.X #0x%02x [%s],FP%d"), extra & 0x7f, fpp_print(&fp, 0), (extra >> 7) & 7);
8917 } else if ((extra & 0x8000) == 0x8000) { // FMOVEM
8918 int dr = (extra >> 13) & 1;
8919 int mode;
8920 int dreg = (extra >> 4) & 7;
8921 int regmask, fpmode;
8922
8923 if (extra & 0x4000) {
8924 mode = (extra >> 11) & 3;
8925 regmask = extra & 0xff; // FMOVEM FPx
8926 fpmode = 1;
8927 _tcscpy(instrname, _T("FMOVEM.X "));
8928 } else {
8929 mode = 0;
8930 regmask = (extra >> 10) & 7; // FMOVEM control
8931 fpmode = 2;
8932 _tcscpy(instrname, _T("FMOVEM.L "));
8933 if (regmask == 1 || regmask == 2 || regmask == 4)
8934 _tcscpy(instrname, _T("FMOVE.L "));
8935 }
8936 p = instrname + _tcslen(instrname);
8937 if (dr) {
8938 if (mode & 1)
8939 _stprintf(instrname, _T("D%d"), dreg);
8940 else
8941 movemout(instrname, regmask, dp->dmode, fpmode, false);
8942 _tcscat(instrname, _T(","));
8943 pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, deaddr, safemode);
8944 } else {
8945 pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, deaddr, safemode);
8946 p = instrname + _tcslen(instrname);
8947 if (mode & 1)
8948 _stprintf(p, _T(",D%d"), dreg);
8949 else
8950 movemout(p, regmask, dp->dmode, fpmode, true);
8951 }
8952 } else {
8953 if (fpuopcodes[ins])
8954 _tcscpy(instrname, fpuopcodes[ins]);
8955 else
8956 _tcscpy(instrname, _T("F?"));
8957
8958 if ((extra & 0xe000) == 0x6000) { // FMOVE to memory
8959 int kfactor = extra & 0x7f;
8960 _tcscpy(instrname, _T("FMOVE."));
8961 _tcscat(instrname, fpsizes[size]);
8962 _tcscat(instrname, _T(" "));
8963 p = instrname + _tcslen(instrname);
8964 _stprintf(p, _T("FP%d,"), (extra >> 7) & 7);
8965 pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, fpsizeconv[size], instrname, &deaddr2, safemode);
8966 p = instrname + _tcslen(instrname);
8967 if (size == 7) {
8968 _stprintf(p, _T(" {D%d}"), (kfactor >> 4));
8969 } else if (kfactor) {
8970 if (kfactor & 0x40)
8971 kfactor |= ~0x3f;
8972 _stprintf(p, _T(" {%d}"), kfactor);
8973 }
8974 } else {
8975 if (extra & 0x4000) { // source is EA
8976 _tcscat(instrname, _T("."));
8977 _tcscat(instrname, fpsizes[size]);
8978 _tcscat(instrname, _T(" "));
8979 pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, fpsizeconv[size], instrname, &seaddr2, safemode);
8980 } else { // source is FPx
8981 p = instrname + _tcslen(instrname);
8982 _stprintf(p, _T(".X FP%d"), (extra >> 10) & 7);
8983 }
8984 p = instrname + _tcslen(instrname);
8985 if ((extra & 0x4000) || (((extra >> 7) & 7) != ((extra >> 10) & 7)))
8986 _stprintf(p, _T(",FP%d"), (extra >> 7) & 7);
8987 if (ins >= 0x30 && ins < 0x38) { // FSINCOS
8988 p = instrname + _tcslen(instrname);
8989 _stprintf(p, _T(",FP%d"), extra & 7);
8990 }
8991 }
8992 }
8993 } else if ((opcode & 0xf000) == 0xa000) {
8994 _tcscpy(instrname, _T("A-LINE"));
8995 } else {
8996 if (dp->suse) {
8997 pc = ShowEA (0, pc, opcode, dp->sreg, dp->smode, dp->size, instrname, &seaddr2, safemode);
8998
8999 // JSR x(a6) / JMP x(a6)
9000 if (opcode == 0x4ea8 + 6 || opcode == 0x4ee8 + 6) {
9001 TCHAR sname[256];
9002 if (debugger_get_library_symbol(m68k_areg(regs, 6), 0xffff0000 | extra, sname)) {
9003 TCHAR *p = instrname + _tcslen(instrname);
9004 _stprintf(p, _T(" %s"), sname);
9005 resolve_if_jmp(instrname, m68k_areg(regs, 6) + (uae_s16)extra);
9006 }
9007 }
9008 // show target address if JSR x(pc) + JMP xxxx combination
9009 if (opcode == 0x4eba && seaddr2 && instrname[0]) { // JSR x(pc)
9010 resolve_if_jmp(instrname, seaddr2);
9011 }
9012 }
9013 if (dp->suse && dp->duse)
9014 _tcscat (instrname, _T(","));
9015 if (dp->duse) {
9016 pc = ShowEA (0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &deaddr2, safemode);
9017 }
9018 }
9019
9020 for (i = 0; i < (int)(pc - oldpc) / 2 && i < 5; i++) {
9021 buf = buf_out (buf, &bufsize, _T("%04x "), get_word_debug (oldpc + i * 2));
9022 }
9023 while (i++ < 5)
9024 buf = buf_out (buf, &bufsize, _T(" "));
9025
9026 if (illegal)
9027 buf = buf_out (buf, &bufsize, _T("[ "));
9028 buf = buf_out (buf, &bufsize, instrname);
9029 if (illegal)
9030 buf = buf_out (buf, &bufsize, _T(" ]"));
9031
9032 if (ccpt != 0) {
9033 uaecptr addr2 = deaddr2 ? deaddr2 : seaddr2;
9034 if (deaddr)
9035 *deaddr = pc;
9036 if ((opcode & 0xf000) == 0xf000) {
9037 if (fpp_cond(dp->cc)) {
9038 buf = buf_out(buf, &bufsize, _T(" == $%08x (T)"), addr2);
9039 } else {
9040 buf = buf_out(buf, &bufsize, _T(" == $%08x (F)"), addr2);
9041 }
9042 } else {
9043 if (dp->mnemo == i_Bcc || dp->mnemo == i_DBcc) {
9044 if (cctrue(dp->cc)) {
9045 buf = buf_out(buf, &bufsize, _T(" == $%08x (T)"), addr2);
9046 } else {
9047 buf = buf_out(buf, &bufsize, _T(" == $%08x (F)"), addr2);
9048 }
9049 } else {
9050 if (cctrue(dp->cc)) {
9051 buf = buf_out(buf, &bufsize, _T(" (T)"));
9052 } else {
9053 buf = buf_out(buf, &bufsize, _T(" (F)"));
9054 }
9055 }
9056 }
9057 } else if ((opcode & 0xff00) == 0x6100) { /* BSR */
9058 if (deaddr)
9059 *deaddr = pc;
9060 buf = buf_out (buf, &bufsize, _T(" == $%08x"), seaddr2);
9061 }
9062 buf = buf_out (buf, &bufsize, _T("\n"));
9063
9064 for (uaecptr segpc = oldpc; segpc < pc; segpc++) {
9065 TCHAR segout[256];
9066 if (debugmem_get_symbol(segpc, segout, sizeof(segout) / sizeof(TCHAR))) {
9067 _tcscat(segout, _T(":\n"));
9068 if (bufsize > _tcslen(segout)) {
9069 memmove(symbolpos + _tcslen(segout), symbolpos, (_tcslen(symbolpos) + 1) * sizeof(TCHAR));
9070 memcpy(symbolpos, segout, _tcslen(segout) * sizeof(TCHAR));
9071 bufsize -= _tcslen(segout);
9072 buf += _tcslen(segout);
9073 symbolpos += _tcslen(segout);
9074 }
9075 }
9076 }
9077
9078 int srcline = -1;
9079 for (uaecptr segpc = oldpc; segpc < pc; segpc++) {
9080 TCHAR sourceout[256];
9081 int line = debugmem_get_sourceline(segpc, sourceout, sizeof(sourceout) / sizeof(TCHAR));
9082 if (line < 0)
9083 break;
9084 if (srcline != line) {
9085 if (srcline < 0)
9086 buf = buf_out(buf, &bufsize, _T("\n"));
9087 buf = buf_out(buf, &bufsize, sourceout);
9088 srcline = line;
9089 }
9090 }
9091 if (srcline >= 0) {
9092 buf = buf_out(buf, &bufsize, _T("\n"));
9093 }
9094
9095 if (illegal)
9096 pc = m68kpc_illg;
9097 }
9098 if (nextpc)
9099 *nextpc = pc;
9100 if (seaddr)
9101 *seaddr = seaddr2;
9102 if (deaddr)
9103 *deaddr = deaddr2;
9104 }
9105
9106 void m68k_disasm_ea (uaecptr addr, uaecptr *nextpc, int cnt, uae_u32 *seaddr, uae_u32 *deaddr, uaecptr lastpc)
9107 {
9108 TCHAR *buf;
9109
9110 buf = xcalloc (TCHAR, (MAX_LINEWIDTH + 1) * cnt);
9111 if (!buf)
9112 return;
9113 m68k_disasm_2 (buf, MAX_LINEWIDTH * cnt, addr, nextpc, cnt, seaddr, deaddr, lastpc, 1);
9114 xfree (buf);
9115 }
9116 void m68k_disasm (uaecptr addr, uaecptr *nextpc, uaecptr lastpc, int cnt)
9117 {
9118 TCHAR *buf;
9119
9120 buf = xcalloc (TCHAR, (MAX_LINEWIDTH + 1) * cnt);
9121 if (!buf)
9122 return;
9123 m68k_disasm_2 (buf, MAX_LINEWIDTH * cnt, addr, nextpc, cnt, NULL, NULL, lastpc, 0);
9124 console_out_f (_T("%s"), buf);
9125 xfree (buf);
9126 }
9127 void m68k_disasm_file (FILE *f, uaecptr addr, uaecptr *nextpc, uaecptr lastpc, int cnt)
9128 {
9129 TCHAR *buf;
9130
9131 buf = xmalloc (TCHAR, (MAX_LINEWIDTH + 1) * cnt);
9132 if (!buf)
9133 return;
9134 console_out_FILE = f;
9135 m68k_disasm_2 (buf, MAX_LINEWIDTH * cnt, addr, nextpc, cnt, NULL, NULL, lastpc, 0);
9136 f_out (f, _T("%s"), buf);
9137 xfree (buf);
9138 console_out_FILE = NULL;
9139 }
9140
9141 /*************************************************************
9142 Disasm the m68kcode at the given address into instrname
9143 and instrcode
9144 *************************************************************/
9145 void sm68k_disasm (TCHAR *instrname, TCHAR *instrcode, uaecptr addr, uaecptr *nextpc, uaecptr lastpc)
9146 {
9147 TCHAR *ccpt;
9148 uae_u32 opcode;
9149 struct mnemolookup *lookup;
9150 struct instr *dp;
9151 uaecptr pc, oldpc;
9152
9153 pc = oldpc = addr;
9154 opcode = get_word_debug (pc);
9155 if (cpufunctbl[opcode] == op_illg_1) {
9156 opcode = 0x4AFC;
9157 }
9158 dp = table68k + opcode;
9159 for (lookup = lookuptab;lookup->mnemo != dp->mnemo; lookup++);
9160
9161 pc += 2;
9162
9163 _tcscpy (instrname, lookup->name);
9164 ccpt = _tcsstr (instrname, _T("cc"));
9165 if (ccpt != 0) {
9166 _tcsncpy (ccpt, ccnames[dp->cc], 2);
9167 }
9168 switch (dp->size){
9169 case sz_byte: _tcscat (instrname, _T(".B ")); break;
9170 case sz_word: _tcscat (instrname, _T(".W ")); break;
9171 case sz_long: _tcscat (instrname, _T(".L ")); break;
9172 default: _tcscat (instrname, _T(" ")); break;
9173 }
9174
9175 if (dp->suse) {
9176 pc = ShowEA (0, pc, opcode, dp->sreg, dp->smode, dp->size, instrname, NULL, 0);
9177 }
9178 if (dp->suse && dp->duse)
9179 _tcscat (instrname, _T(","));
9180 if (dp->duse) {
9181 pc = ShowEA (0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, NULL, 0);
9182 }
9183 if (instrcode)
9184 {
9185 int i;
9186 for (i = 0; i < (pc - oldpc) / 2; i++)
9187 {
9188 _stprintf (instrcode, _T("%04x "), get_iword_debug (oldpc + i * 2));
9189 instrcode += _tcslen (instrcode);
9190 }
9191 }
9192 if (nextpc)
9193 *nextpc = pc;
9194 }
9195
9196 struct cpum2c m2cregs[] = {
9197 { 0, _T("SFC") },
9198 { 1, _T("DFC") },
9199 { 2, _T("CACR") },
9200 { 3, _T("TC") },
9201 { 4, _T("ITT0") },
9202 { 5, _T("ITT1") },
9203 { 6, _T("DTT0") },
9204 { 7, _T("DTT1") },
9205 { 8, _T("BUSC") },
9206 { 0x800, _T("USP") },
9207 { 0x801, _T("VBR") },
9208 { 0x802, _T("CAAR") },
9209 { 0x803, _T("MSP") },
9210 { 0x804, _T("ISP") },
9211 { 0x805, _T("MMUS") },
9212 { 0x806, _T("URP") },
9213 { 0x807, _T("SRP") },
9214 { 0x808, _T("PCR") },
9215 { -1, NULL }
9216 };
9217
9218 void m68k_dumpstate(uaecptr *nextpc, uaecptr prevpc)
9219 {
9220 int i, j;
9221 uaecptr pc = M68K_GETPC;
9222
9223 for (i = 0; i < 8; i++){
9224 console_out_f (_T(" D%d %08X "), i, m68k_dreg (regs, i));
9225 if ((i & 3) == 3) console_out_f (_T("\n"));
9226 }
9227 for (i = 0; i < 8; i++){
9228 console_out_f (_T(" A%d %08X "), i, m68k_areg (regs, i));
9229 if ((i & 3) == 3) console_out_f (_T("\n"));
9230 }
9231 if (regs.s == 0)
9232 regs.usp = m68k_areg (regs, 7);
9233 if (regs.s && regs.m)
9234 regs.msp = m68k_areg (regs, 7);
9235 if (regs.s && regs.m == 0)
9236 regs.isp = m68k_areg (regs, 7);
9237 j = 2;
9238 console_out_f (_T("USP %08X ISP %08X "), regs.usp, regs.isp);
9239 for (i = 0; m2cregs[i].regno>= 0; i++) {
9240 if (!movec_illg (m2cregs[i].regno)) {
9241 if (!_tcscmp (m2cregs[i].regname, _T("USP")) || !_tcscmp (m2cregs[i].regname, _T("ISP")))
9242 continue;
9243 if (j > 0 && (j % 4) == 0)
9244 console_out_f (_T("\n"));
9245 console_out_f (_T("%-4s %08X "), m2cregs[i].regname, val_move2c (m2cregs[i].regno));
9246 j++;
9247 }
9248 }
9249 if (j > 0)
9250 console_out_f (_T("\n"));
9251 console_out_f (_T("T=%d%d S=%d M=%d X=%d N=%d Z=%d V=%d C=%d IMASK=%d STP=%d\n"),
9252 regs.t1, regs.t0, regs.s, regs.m,
9253 GET_XFLG (), GET_NFLG (), GET_ZFLG (),
9254 GET_VFLG (), GET_CFLG (),
9255 regs.intmask, regs.stopped);
9256 #ifdef FPUEMU
9257 if (currprefs.fpu_model) {
9258 uae_u32 fpsr;
9259 for (i = 0; i < 8; i++) {
9260 if (!(i & 1))
9261 console_out_f(_T("%d: "), i);
9262 console_out_f (_T("%s "), fpp_print(®s.fp[i], -1));
9263 console_out_f (_T("%s "), fpp_print(®s.fp[i], 0));
9264 if (i & 1)
9265 console_out_f (_T("\n"));
9266 }
9267 fpsr = fpp_get_fpsr ();
9268 console_out_f (_T("FPSR: %08X FPCR: %08x FPIAR: %08x N=%d Z=%d I=%d NAN=%d\n"),
9269 fpsr, regs.fpcr, regs.fpiar,
9270 (fpsr & 0x8000000) != 0,
9271 (fpsr & 0x4000000) != 0,
9272 (fpsr & 0x2000000) != 0,
9273 (fpsr & 0x1000000) != 0);
9274 }
9275 #endif
9276 if (currprefs.mmu_model == 68030) {
9277 #ifndef WINUAE_FOR_HATARI
9278 console_out_f (_T("SRP: %llX CRP: %llX\n"), srp_030, crp_030);
9279 #else /* Use PRIX64 since MinGW on Windows does not know about %llx (?) */
9280 console_out_f (_T("SRP: %"PRIX64" CRP: %"PRIX64"\n"), (uint64_t)srp_030, (uint64_t)crp_030);
9281 #endif
9282 console_out_f (_T("TT0: %08X TT1: %08X TC: %08X\n"), tt0_030, tt1_030, tc_030);
9283 }
9284 if (currprefs.cpu_compatible) {
9285 if (currprefs.cpu_model == 68000) {
9286 struct instr *dp;
9287 struct mnemolookup *lookup1, *lookup2;
9288 dp = table68k + regs.irc;
9289 for (lookup1 = lookuptab; lookup1->mnemo != dp->mnemo; lookup1++)
9290 ;
9291 dp = table68k + regs.ir;
9292 for (lookup2 = lookuptab; lookup2->mnemo != dp->mnemo; lookup2++)
9293 ;
9294 console_out_f (_T("Prefetch %04x (%s) %04x (%s) Chip latch %08X\n"), regs.irc, lookup1->name, regs.ir, lookup2->name, regs.chipset_latch_rw);
9295 } else if (currprefs.cpu_model == 68020 || currprefs.cpu_model == 68030) {
9296 console_out_f (_T("Prefetch %08x %08x (%d) %04x (%d) %04x (%d) %04x (%d)\n"),
9297 regs.cacheholdingaddr020, regs.cacheholdingdata020, regs.cacheholdingdata_valid,
9298 regs.prefetch020[0], regs.prefetch020_valid[0],
9299 regs.prefetch020[1], regs.prefetch020_valid[1],
9300 regs.prefetch020[2], regs.prefetch020_valid[2]);
9301 }
9302 }
9303 if (prevpc != 0xffffffff && pc - prevpc < 100) {
9304 while (prevpc < pc) {
9305 m68k_disasm(prevpc, &prevpc, 0xffffffff, 1);
9306 }
9307 }
9308 m68k_disasm (pc, nextpc, pc, 1);
9309 if (nextpc)
9310 console_out_f (_T("Next PC: %08x\n"), *nextpc);
9311 }
9312 #ifdef WINUAE_FOR_HATARI
9313 void m68k_dumpstate_file (FILE *f, uaecptr *nextpc, uaecptr prevpc)
9314 {
9315 console_out_FILE = f;
9316 m68k_dumpstate(nextpc, prevpc);
9317 console_out_FILE = NULL;
9318 }
9319 #endif
9320 void m68k_dumpcache (bool dc)
9321 {
9322 if (!currprefs.cpu_compatible)
9323 return;
9324 if (currprefs.cpu_model == 68020) {
9325 for (int i = 0; i < CACHELINES020; i += 4) {
9326 for (int j = 0; j < 4; j++) {
9327 int s = i + j;
9328 uaecptr addr;
9329 int fc;
9330 struct cache020 *c = &caches020[s];
9331 fc = c->tag & 1;
9332 addr = c->tag & ~1;
9333 addr |= s << 2;
9334 console_out_f (_T("%08X%c:%08X%c"), addr, fc ? 'S' : 'U', c->data, c->valid ? '*' : ' ');
9335 }
9336 console_out_f (_T("\n"));
9337 }
9338 } else if (currprefs.cpu_model == 68030) {
9339 for (int i = 0; i < CACHELINES030; i++) {
9340 struct cache030 *c = dc ? &dcaches030[i] : &icaches030[i];
9341 int fc;
9342 uaecptr addr;
9343 if (!dc) {
9344 fc = (c->tag & 1) ? 6 : 2;
9345 } else {
9346 fc = c->fc;
9347 }
9348 addr = c->tag & ~1;
9349 addr |= i << 4;
9350 console_out_f (_T("%08X %d: "), addr, fc);
9351 for (int j = 0; j < 4; j++) {
9352 console_out_f (_T("%08X%c "), c->data[j], c->valid[j] ? '*' : ' ');
9353 }
9354 console_out_f (_T("\n"));
9355 }
9356 } else if (currprefs.cpu_model >= 68040) {
9357 uae_u32 tagmask = dc ? cachedtag04060mask : cacheitag04060mask;
9358 for (int i = 0; i < cachedsets04060; i++) {
9359 struct cache040 *c = dc ? &dcaches040[i] : &icaches040[i];
9360 for (int j = 0; j < CACHELINES040; j++) {
9361 if (c->valid[j]) {
9362 uae_u32 addr = (c->tag[j] & tagmask) | (i << 4);
9363 write_log(_T("%02d:%d %08x = %08x%c %08x%c %08x%c %08x%c\n"),
9364 i, j, addr,
9365 c->data[j][0], c->dirty[j][0] ? '*' : ' ',
9366 c->data[j][1], c->dirty[j][1] ? '*' : ' ',
9367 c->data[j][2], c->dirty[j][2] ? '*' : ' ',
9368 c->data[j][3], c->dirty[j][3] ? '*' : ' ');
9369 }
9370 }
9371 }
9372 }
9373 }
9374
9375 #ifdef SAVESTATE
9376
9377 /* CPU save/restore code */
9378
9379 #define CPUTYPE_EC 1
9380 #define CPUMODE_HALT 1
9381
9382 uae_u8 *restore_cpu (uae_u8 *src)
9383 {
9384 int flags, model;
9385 uae_u32 l;
9386
9387 currprefs.cpu_model = changed_prefs.cpu_model = model = restore_u32 ();
9388 flags = restore_u32 ();
9389 changed_prefs.address_space_24 = 0;
9390 if (flags & CPUTYPE_EC)
9391 changed_prefs.address_space_24 = 1;
9392 currprefs.address_space_24 = changed_prefs.address_space_24;
9393 currprefs.cpu_compatible = changed_prefs.cpu_compatible;
9394 currprefs.cpu_cycle_exact = changed_prefs.cpu_cycle_exact;
9395 currprefs.cpu_memory_cycle_exact = changed_prefs.cpu_memory_cycle_exact;
9396 currprefs.blitter_cycle_exact = changed_prefs.blitter_cycle_exact;
9397 currprefs.cpu_frequency = changed_prefs.cpu_frequency = 0;
9398 currprefs.cpu_clock_multiplier = changed_prefs.cpu_clock_multiplier = 0;
9399 for (int i = 0; i < 15; i++)
9400 regs.regs[i] = restore_u32 ();
9401 regs.pc = restore_u32 ();
9402 regs.irc = restore_u16 ();
9403 regs.ir = restore_u16 ();
9404 regs.usp = restore_u32 ();
9405 regs.isp = restore_u32 ();
9406 regs.sr = restore_u16 ();
9407 l = restore_u32 ();
9408 if (l & CPUMODE_HALT) {
9409 regs.stopped = 1;
9410 } else {
9411 regs.stopped = 0;
9412 }
9413 if (model >= 68010) {
9414 regs.dfc = restore_u32 ();
9415 regs.sfc = restore_u32 ();
9416 regs.vbr = restore_u32 ();
9417 }
9418 if (model >= 68020) {
9419 regs.caar = restore_u32 ();
9420 regs.cacr = restore_u32 ();
9421 regs.msp = restore_u32 ();
9422 }
9423 if (model >= 68030) {
9424 crp_030 = fake_crp_030 = restore_u64 ();
9425 srp_030 = fake_srp_030 = restore_u64 ();
9426 tt0_030 = fake_tt0_030 = restore_u32 ();
9427 tt1_030 = fake_tt1_030 = restore_u32 ();
9428 tc_030 = fake_tc_030 = restore_u32 ();
9429 mmusr_030 = fake_mmusr_030 = restore_u16 ();
9430 }
9431 if (model >= 68040) {
9432 regs.itt0 = restore_u32 ();
9433 regs.itt1 = restore_u32 ();
9434 regs.dtt0 = restore_u32 ();
9435 regs.dtt1 = restore_u32 ();
9436 regs.tcr = restore_u32 ();
9437 regs.urp = restore_u32 ();
9438 regs.srp = restore_u32 ();
9439 }
9440 if (model >= 68060) {
9441 regs.buscr = restore_u32 ();
9442 regs.pcr = restore_u32 ();
9443 }
9444 if (flags & 0x80000000) {
9445 int khz = restore_u32 ();
9446 restore_u32 ();
9447 if (khz > 0 && khz < 800000)
9448 currprefs.m68k_speed = changed_prefs.m68k_speed = 0;
9449 }
9450 set_cpu_caches (true);
9451 if (flags & 0x40000000) {
9452 if (model == 68020) {
9453 for (int i = 0; i < CACHELINES020; i++) {
9454 caches020[i].data = restore_u32 ();
9455 caches020[i].tag = restore_u32 ();
9456 caches020[i].valid = restore_u8 () != 0;
9457 }
9458 regs.prefetch020addr = restore_u32 ();
9459 regs.cacheholdingaddr020 = restore_u32 ();
9460 regs.cacheholdingdata020 = restore_u32 ();
9461 if (flags & 0x20000000) {
9462 if (flags & 0x4000000) {
9463 // 3.6 new (back to 16 bits)
9464 for (int i = 0; i < CPU_PIPELINE_MAX; i++) {
9465 uae_u32 v = restore_u32();
9466 regs.prefetch020[i] = v >> 16;
9467 regs.prefetch020_valid[i] = (v & 1) != 0;
9468 }
9469 } else {
9470 // old
9471 uae_u32 v = restore_u32();
9472 regs.prefetch020[0] = v >> 16;
9473 regs.prefetch020[1] = (uae_u16)v;
9474 v = restore_u32();
9475 regs.prefetch020[2] = v >> 16;
9476 regs.prefetch020[3] = (uae_u16)v;
9477 restore_u32();
9478 restore_u32();
9479 regs.prefetch020_valid[0] = true;
9480 regs.prefetch020_valid[1] = true;
9481 regs.prefetch020_valid[2] = true;
9482 regs.prefetch020_valid[3] = true;
9483 }
9484 }
9485 } else if (model == 68030) {
9486 for (int i = 0; i < CACHELINES030; i++) {
9487 for (int j = 0; j < 4; j++) {
9488 icaches030[i].data[j] = restore_u32 ();
9489 icaches030[i].valid[j] = restore_u8 () != 0;
9490 }
9491 icaches030[i].tag = restore_u32 ();
9492 }
9493 for (int i = 0; i < CACHELINES030; i++) {
9494 for (int j = 0; j < 4; j++) {
9495 dcaches030[i].data[j] = restore_u32 ();
9496 dcaches030[i].valid[j] = restore_u8 () != 0;
9497 }
9498 dcaches030[i].tag = restore_u32 ();
9499 }
9500 regs.prefetch020addr = restore_u32 ();
9501 regs.cacheholdingaddr020 = restore_u32 ();
9502 regs.cacheholdingdata020 = restore_u32 ();
9503 if (flags & 0x4000000) {
9504 for (int i = 0; i < CPU_PIPELINE_MAX; i++) {
9505 uae_u32 v = restore_u32();
9506 regs.prefetch020[i] = v >> 16;
9507 regs.prefetch020_valid[i] = (v & 1) != 0;
9508 }
9509 } else {
9510 for (int i = 0; i < CPU_PIPELINE_MAX; i++) {
9511 regs.prefetch020[i] = restore_u32 ();
9512 regs.prefetch020_valid[i] = false;
9513 }
9514 }
9515 } else if (model == 68040) {
9516 if (flags & 0x8000000) {
9517 for (int i = 0; i < ((model == 68060 && (flags & 0x4000000)) ? CACHESETS060 : CACHESETS040); i++) {
9518 for (int j = 0; j < CACHELINES040; j++) {
9519 struct cache040 *c = &icaches040[i];
9520 c->data[j][0] = restore_u32();
9521 c->data[j][1] = restore_u32();
9522 c->data[j][2] = restore_u32();
9523 c->data[j][3] = restore_u32();
9524 c->tag[j] = restore_u32();
9525 c->valid[j] = restore_u16() & 1;
9526 }
9527 }
9528 regs.prefetch020addr = restore_u32();
9529 regs.cacheholdingaddr020 = restore_u32();
9530 regs.cacheholdingdata020 = restore_u32();
9531 for (int i = 0; i < CPU_PIPELINE_MAX; i++)
9532 regs.prefetch040[i] = restore_u32();
9533 if (flags & 0x4000000) {
9534 for (int i = 0; i < (model == 68060 ? CACHESETS060 : CACHESETS040); i++) {
9535 for (int j = 0; j < CACHELINES040; j++) {
9536 struct cache040 *c = &dcaches040[i];
9537 c->data[j][0] = restore_u32();
9538 c->data[j][1] = restore_u32();
9539 c->data[j][2] = restore_u32();
9540 c->data[j][3] = restore_u32();
9541 c->tag[j] = restore_u32();
9542 uae_u16 v = restore_u16();
9543 c->valid[j] = (v & 1) != 0;
9544 c->dirty[j][0] = (v & 0x10) != 0;
9545 c->dirty[j][1] = (v & 0x20) != 0;
9546 c->dirty[j][2] = (v & 0x40) != 0;
9547 c->dirty[j][3] = (v & 0x80) != 0;
9548 c->gdirty[j] = c->dirty[j][0] || c->dirty[j][1] || c->dirty[j][2] || c->dirty[j][3];
9549 }
9550 }
9551 }
9552 }
9553 }
9554 if (model >= 68020) {
9555 restore_u32 (); // regs.ce020memcycles
9556 regs.ce020startcycle = regs.ce020endcycle = 0;
9557 restore_u32 ();
9558 }
9559 }
9560 if (flags & 0x10000000) {
9561 regs.chipset_latch_rw = restore_u32 ();
9562 regs.chipset_latch_read = restore_u32 ();
9563 regs.chipset_latch_write = restore_u32 ();
9564 }
9565
9566 regs.pipeline_pos = -1;
9567 regs.pipeline_stop = 0;
9568 if (flags & 0x4000000 && currprefs.cpu_model == 68020) {
9569 regs.pipeline_pos = restore_u16();
9570 regs.pipeline_r8[0] = restore_u16();
9571 regs.pipeline_r8[1] = restore_u16();
9572 regs.pipeline_stop = restore_u16();
9573 }
9574
9575 m68k_reset_sr();
9576
9577 write_log (_T("CPU: %d%s%03d, PC=%08X\n"),
9578 model / 1000, flags & 1 ? _T("EC") : _T(""), model % 1000, regs.pc);
9579
9580 return src;
9581 }
9582
9583 static void fill_prefetch_quick (void)
9584 {
9585 if (currprefs.cpu_model >= 68020) {
9586 fill_prefetch ();
9587 return;
9588 }
9589 // old statefile compatibility, this needs to done,
9590 // even in 68000 cycle-exact mode
9591 regs.ir = get_word (m68k_getpc ());
9592 regs.irc = get_word (m68k_getpc () + 2);
9593 }
9594
9595 void restore_cpu_finish (void)
9596 {
9597 if (!currprefs.fpu_model)
9598 fpu_reset();
9599 init_m68k ();
9600 m68k_setpc_normal (regs.pc);
9601 doint ();
9602 fill_prefetch_quick ();
9603 #ifndef WINUAE_FOR_HATARI
9604 set_cycles (start_cycles);
9605 events_schedule ();
9606 #endif
9607 if (regs.stopped)
9608 set_special (SPCFLAG_STOP);
9609 //activate_debugger ();
9610 }
9611
9612 uae_u8 *save_cpu_trace (int *len, uae_u8 *dstptr)
9613 {
9614 uae_u8 *dstbak, *dst;
9615
9616 if (cputrace.state <= 0)
9617 return NULL;
9618
9619 if (dstptr)
9620 dstbak = dst = dstptr;
9621 else
9622 dstbak = dst = xmalloc (uae_u8, 10000);
9623
9624 save_u32 (2 | 4 | 16 | 32);
9625 save_u16 (cputrace.opcode);
9626 for (int i = 0; i < 16; i++)
9627 save_u32 (cputrace.regs[i]);
9628 save_u32 (cputrace.pc);
9629 save_u16 (cputrace.irc);
9630 save_u16 (cputrace.ir);
9631 save_u32 (cputrace.usp);
9632 save_u32 (cputrace.isp);
9633 save_u16 (cputrace.sr);
9634 save_u16 (cputrace.intmask);
9635 save_u16 ((cputrace.stopped ? 1 : 0) | (regs.stopped ? 2 : 0));
9636 save_u16 (cputrace.state);
9637 save_u32 (cputrace.cyclecounter);
9638 save_u32 (cputrace.cyclecounter_pre);
9639 save_u32 (cputrace.cyclecounter_post);
9640 save_u32 (cputrace.readcounter);
9641 save_u32 (cputrace.writecounter);
9642 save_u32 (cputrace.memoryoffset);
9643 write_log (_T("CPUT SAVE: PC=%08x C=%08X %08x %08x %08x %d %d %d\n"),
9644 cputrace.pc, cputrace.startcycles,
9645 cputrace.cyclecounter, cputrace.cyclecounter_pre, cputrace.cyclecounter_post,
9646 cputrace.readcounter, cputrace.writecounter, cputrace.memoryoffset);
9647 for (int i = 0; i < cputrace.memoryoffset; i++) {
9648 save_u32 (cputrace.ctm[i].addr);
9649 save_u32 (cputrace.ctm[i].data);
9650 save_u32 (cputrace.ctm[i].mode);
9651 write_log (_T("CPUT%d: %08x %08x %08x\n"), i, cputrace.ctm[i].addr, cputrace.ctm[i].data, cputrace.ctm[i].mode);
9652 }
9653 save_u32 (cputrace.startcycles);
9654
9655 if (currprefs.cpu_model == 68020) {
9656 for (int i = 0; i < CACHELINES020; i++) {
9657 save_u32 (cputrace.caches020[i].data);
9658 save_u32 (cputrace.caches020[i].tag);
9659 save_u8 (cputrace.caches020[i].valid ? 1 : 0);
9660 }
9661 save_u32 (cputrace.prefetch020addr);
9662 save_u32 (cputrace.cacheholdingaddr020);
9663 save_u32 (cputrace.cacheholdingdata020);
9664 for (int i = 0; i < CPU_PIPELINE_MAX; i++) {
9665 save_u16 (cputrace.prefetch020[i]);
9666 }
9667 for (int i = 0; i < CPU_PIPELINE_MAX; i++) {
9668 save_u32 (cputrace.prefetch020[i]);
9669 }
9670 for (int i = 0; i < CPU_PIPELINE_MAX; i++) {
9671 save_u8 (cputrace.prefetch020_valid[i]);
9672 }
9673 save_u16(cputrace.pipeline_pos);
9674 save_u16(cputrace.pipeline_r8[0]);
9675 save_u16(cputrace.pipeline_r8[1]);
9676 save_u16(cputrace.pipeline_stop);
9677 }
9678
9679 *len = dst - dstbak;
9680 cputrace.needendcycles = 1;
9681 return dstbak;
9682 }
9683
9684 uae_u8 *restore_cpu_trace (uae_u8 *src)
9685 {
9686 cpu_tracer = 0;
9687 cputrace.state = 0;
9688 uae_u32 v = restore_u32 ();
9689 if (!(v & 2))
9690 return src;
9691 cputrace.opcode = restore_u16 ();
9692 for (int i = 0; i < 16; i++)
9693 cputrace.regs[i] = restore_u32 ();
9694 cputrace.pc = restore_u32 ();
9695 cputrace.irc = restore_u16 ();
9696 cputrace.ir = restore_u16 ();
9697 cputrace.usp = restore_u32 ();
9698 cputrace.isp = restore_u32 ();
9699 cputrace.sr = restore_u16 ();
9700 cputrace.intmask = restore_u16 ();
9701 cputrace.stopped = restore_u16 ();
9702 cputrace.state = restore_u16 ();
9703 cputrace.cyclecounter = restore_u32 ();
9704 cputrace.cyclecounter_pre = restore_u32 ();
9705 cputrace.cyclecounter_post = restore_u32 ();
9706 cputrace.readcounter = restore_u32 ();
9707 cputrace.writecounter = restore_u32 ();
9708 cputrace.memoryoffset = restore_u32 ();
9709 for (int i = 0; i < cputrace.memoryoffset; i++) {
9710 cputrace.ctm[i].addr = restore_u32 ();
9711 cputrace.ctm[i].data = restore_u32 ();
9712 cputrace.ctm[i].mode = restore_u32 ();
9713 }
9714 cputrace.startcycles = restore_u32 ();
9715
9716 if (v & 4) {
9717 if (currprefs.cpu_model == 68020) {
9718 for (int i = 0; i < CACHELINES020; i++) {
9719 cputrace.caches020[i].data = restore_u32 ();
9720 cputrace.caches020[i].tag = restore_u32 ();
9721 cputrace.caches020[i].valid = restore_u8 () != 0;
9722 }
9723 cputrace.prefetch020addr = restore_u32 ();
9724 cputrace.cacheholdingaddr020 = restore_u32 ();
9725 cputrace.cacheholdingdata020 = restore_u32 ();
9726 for (int i = 0; i < CPU_PIPELINE_MAX; i++) {
9727 cputrace.prefetch020[i] = restore_u16 ();
9728 }
9729 if (v & 8) {
9730 // backwards compatibility
9731 uae_u32 v2 = restore_u32();
9732 cputrace.prefetch020[0] = v2 >> 16;
9733 cputrace.prefetch020[1] = (uae_u16)v2;
9734 v2 = restore_u32();
9735 cputrace.prefetch020[2] = v2 >> 16;
9736 cputrace.prefetch020[3] = (uae_u16)v2;
9737 restore_u32();
9738 restore_u32();
9739 cputrace.prefetch020_valid[0] = true;
9740 cputrace.prefetch020_valid[1] = true;
9741 cputrace.prefetch020_valid[2] = true;
9742 cputrace.prefetch020_valid[3] = true;
9743
9744 cputrace.prefetch020[0] = cputrace.prefetch020[1];
9745 cputrace.prefetch020[1] = cputrace.prefetch020[2];
9746 cputrace.prefetch020[2] = cputrace.prefetch020[3];
9747 cputrace.prefetch020_valid[3] = false;
9748 }
9749 if (v & 16) {
9750 if ((v & 32) && !(v & 8)) {
9751 restore_u32();
9752 restore_u32();
9753 restore_u32();
9754 restore_u32();
9755 }
9756 for (int i = 0; i < CPU_PIPELINE_MAX; i++) {
9757 cputrace.prefetch020_valid[i] = restore_u8() != 0;
9758 }
9759 }
9760 if (v & 32) {
9761 cputrace.pipeline_pos = restore_u16();
9762 cputrace.pipeline_r8[0] = restore_u16();
9763 cputrace.pipeline_r8[1] = restore_u16();
9764 cputrace.pipeline_stop = restore_u16();
9765 }
9766 }
9767 }
9768
9769 cputrace.needendcycles = 1;
9770 if (v && cputrace.state) {
9771 if (currprefs.cpu_model > 68000) {
9772 if (v & 4)
9773 cpu_tracer = -1;
9774 // old format?
9775 if ((v & (4 | 8)) != (4 | 8) && (v & (32 | 16 | 8 | 4)) != (32 | 16 | 4))
9776 cpu_tracer = 0;
9777 } else {
9778 cpu_tracer = -1;
9779 }
9780 }
9781
9782 return src;
9783 }
9784
9785 uae_u8 *restore_cpu_extra (uae_u8 *src)
9786 {
9787 restore_u32 ();
9788 uae_u32 flags = restore_u32 ();
9789
9790 currprefs.cpu_cycle_exact = changed_prefs.cpu_cycle_exact = (flags & 1) ? true : false;
9791 currprefs.cpu_memory_cycle_exact = changed_prefs.cpu_memory_cycle_exact = currprefs.cpu_cycle_exact;
9792 if ((flags & 32) && !(flags & 1))
9793 currprefs.cpu_memory_cycle_exact = changed_prefs.cpu_memory_cycle_exact = true;
9794 currprefs.blitter_cycle_exact = changed_prefs.blitter_cycle_exact = currprefs.cpu_cycle_exact;
9795 currprefs.cpu_compatible = changed_prefs.cpu_compatible = (flags & 2) ? true : false;
9796 currprefs.cpu_frequency = changed_prefs.cpu_frequency = restore_u32 ();
9797 currprefs.cpu_clock_multiplier = changed_prefs.cpu_clock_multiplier = restore_u32 ();
9798 //currprefs.cachesize = changed_prefs.cachesize = (flags & 8) ? 8192 : 0;
9799
9800 currprefs.m68k_speed = changed_prefs.m68k_speed = 0;
9801 if (flags & 4)
9802 currprefs.m68k_speed = changed_prefs.m68k_speed = -1;
9803 if (flags & 16)
9804 currprefs.m68k_speed = changed_prefs.m68k_speed = (flags >> 24) * CYCLE_UNIT;
9805
9806 currprefs.cpu060_revision = changed_prefs.cpu060_revision = restore_u8 ();
9807 currprefs.fpu_revision = changed_prefs.fpu_revision = restore_u8 ();
9808
9809 return src;
9810 }
9811
9812 uae_u8 *save_cpu_extra (int *len, uae_u8 *dstptr)
9813 {
9814 uae_u8 *dstbak, *dst;
9815 uae_u32 flags;
9816
9817 if (dstptr)
9818 dstbak = dst = dstptr;
9819 else
9820 dstbak = dst = xmalloc (uae_u8, 1000);
9821 save_u32 (0); // version
9822 flags = 0;
9823 flags |= currprefs.cpu_cycle_exact ? 1 : 0;
9824 flags |= currprefs.cpu_compatible ? 2 : 0;
9825 flags |= currprefs.m68k_speed < 0 ? 4 : 0;
9826 flags |= currprefs.cachesize > 0 ? 8 : 0;
9827 flags |= currprefs.m68k_speed > 0 ? 16 : 0;
9828 flags |= currprefs.cpu_memory_cycle_exact ? 32 : 0;
9829 if (currprefs.m68k_speed > 0)
9830 flags |= (currprefs.m68k_speed / CYCLE_UNIT) << 24;
9831 save_u32 (flags);
9832 save_u32 (currprefs.cpu_frequency);
9833 save_u32 (currprefs.cpu_clock_multiplier);
9834 save_u8 (currprefs.cpu060_revision);
9835 save_u8 (currprefs.fpu_revision);
9836 *len = dst - dstbak;
9837 return dstbak;
9838 }
9839
9840 uae_u8 *save_cpu (int *len, uae_u8 *dstptr)
9841 {
9842 uae_u8 *dstbak, *dst;
9843 int model, khz;
9844
9845 if (dstptr)
9846 dstbak = dst = dstptr;
9847 else
9848 dstbak = dst = xmalloc (uae_u8, 1000 + 30000);
9849 model = currprefs.cpu_model;
9850 save_u32 (model); /* MODEL */
9851 save_u32(0x80000000 | 0x40000000 | 0x20000000 | 0x10000000 | 0x8000000 | 0x4000000 | (currprefs.address_space_24 ? 1 : 0)); /* FLAGS */
9852 for (int i = 0;i < 15; i++)
9853 save_u32 (regs.regs[i]); /* D0-D7 A0-A6 */
9854 save_u32 (m68k_getpc ()); /* PC */
9855 save_u16 (regs.irc); /* prefetch */
9856 save_u16 (regs.ir); /* instruction prefetch */
9857 MakeSR ();
9858 save_u32 (!regs.s ? regs.regs[15] : regs.usp); /* USP */
9859 save_u32 (regs.s ? regs.regs[15] : regs.isp); /* ISP */
9860 save_u16 (regs.sr); /* SR/CCR */
9861 save_u32 (regs.stopped ? CPUMODE_HALT : 0); /* flags */
9862 if (model >= 68010) {
9863 save_u32 (regs.dfc); /* DFC */
9864 save_u32 (regs.sfc); /* SFC */
9865 save_u32 (regs.vbr); /* VBR */
9866 }
9867 if (model >= 68020) {
9868 save_u32 (regs.caar); /* CAAR */
9869 save_u32 (regs.cacr); /* CACR */
9870 save_u32 (regs.msp); /* MSP */
9871 }
9872 if (model >= 68030) {
9873 if (currprefs.mmu_model) {
9874 save_u64 (crp_030); /* CRP */
9875 save_u64 (srp_030); /* SRP */
9876 save_u32 (tt0_030); /* TT0/AC0 */
9877 save_u32 (tt1_030); /* TT1/AC1 */
9878 save_u32 (tc_030); /* TCR */
9879 save_u16 (mmusr_030); /* MMUSR/ACUSR */
9880 } else {
9881 save_u64 (fake_crp_030); /* CRP */
9882 save_u64 (fake_srp_030); /* SRP */
9883 save_u32 (fake_tt0_030); /* TT0/AC0 */
9884 save_u32 (fake_tt1_030); /* TT1/AC1 */
9885 save_u32 (fake_tc_030); /* TCR */
9886 save_u16 (fake_mmusr_030); /* MMUSR/ACUSR */
9887 }
9888 }
9889 if (model >= 68040) {
9890 save_u32 (regs.itt0); /* ITT0 */
9891 save_u32 (regs.itt1); /* ITT1 */
9892 save_u32 (regs.dtt0); /* DTT0 */
9893 save_u32 (regs.dtt1); /* DTT1 */
9894 save_u32 (regs.tcr); /* TCR */
9895 save_u32 (regs.urp); /* URP */
9896 save_u32 (regs.srp); /* SRP */
9897 }
9898 if (model >= 68060) {
9899 save_u32 (regs.buscr); /* BUSCR */
9900 save_u32 (regs.pcr); /* PCR */
9901 }
9902 khz = -1;
9903 if (currprefs.m68k_speed == 0) {
9904 khz = currprefs.ntscmode ? 715909 : 709379;
9905 if (currprefs.cpu_model >= 68020)
9906 khz *= 2;
9907 }
9908 save_u32 (khz); // clock rate in KHz: -1 = fastest possible
9909 save_u32 (0); // spare
9910 if (model == 68020) {
9911 for (int i = 0; i < CACHELINES020; i++) {
9912 save_u32 (caches020[i].data);
9913 save_u32 (caches020[i].tag);
9914 save_u8 (caches020[i].valid ? 1 : 0);
9915 }
9916 save_u32 (regs.prefetch020addr);
9917 save_u32 (regs.cacheholdingaddr020);
9918 save_u32 (regs.cacheholdingdata020);
9919 for (int i = 0; i < CPU_PIPELINE_MAX; i++)
9920 save_u32 ((regs.prefetch020[i] << 16) | (regs.prefetch020_valid[i] ? 1 : 0));
9921 } else if (model == 68030) {
9922 for (int i = 0; i < CACHELINES030; i++) {
9923 for (int j = 0; j < 4; j++) {
9924 save_u32 (icaches030[i].data[j]);
9925 save_u8 (icaches030[i].valid[j] ? 1 : 0);
9926 }
9927 save_u32 (icaches030[i].tag);
9928 }
9929 for (int i = 0; i < CACHELINES030; i++) {
9930 for (int j = 0; j < 4; j++) {
9931 save_u32 (dcaches030[i].data[j]);
9932 save_u8 (dcaches030[i].valid[j] ? 1 : 0);
9933 }
9934 save_u32 (dcaches030[i].tag);
9935 }
9936 save_u32 (regs.prefetch020addr);
9937 save_u32 (regs.cacheholdingaddr020);
9938 save_u32 (regs.cacheholdingdata020);
9939 for (int i = 0; i < CPU_PIPELINE_MAX; i++)
9940 save_u32 (regs.prefetch020[i]);
9941 } else if (model >= 68040) {
9942 for (int i = 0; i < (model == 68060 ? CACHESETS060 : CACHESETS040); i++) {
9943 for (int j = 0; j < CACHELINES040; j++) {
9944 struct cache040 *c = &icaches040[i];
9945 save_u32(c->data[j][0]);
9946 save_u32(c->data[j][1]);
9947 save_u32(c->data[j][2]);
9948 save_u32(c->data[j][3]);
9949 save_u32(c->tag[j]);
9950 save_u16(c->valid[j] ? 1 : 0);
9951 }
9952 }
9953 save_u32(regs.prefetch020addr);
9954 save_u32(regs.cacheholdingaddr020);
9955 save_u32(regs.cacheholdingdata020);
9956 for (int i = 0; i < CPU_PIPELINE_MAX; i++) {
9957 save_u32(regs.prefetch040[i]);
9958 }
9959 for (int i = 0; i < (model == 68060 ? CACHESETS060 : CACHESETS040); i++) {
9960 for (int j = 0; j < CACHELINES040; j++) {
9961 struct cache040 *c = &dcaches040[i];
9962 save_u32(c->data[j][0]);
9963 save_u32(c->data[j][1]);
9964 save_u32(c->data[j][2]);
9965 save_u32(c->data[j][3]);
9966 save_u32(c->tag[j]);
9967 uae_u16 v = c->valid[j] ? 1 : 0;
9968 v |= c->dirty[j][0] ? 0x10 : 0;
9969 v |= c->dirty[j][1] ? 0x20 : 0;
9970 v |= c->dirty[j][2] ? 0x40 : 0;
9971 v |= c->dirty[j][3] ? 0x80 : 0;
9972 save_u16(v);
9973 }
9974 }
9975 }
9976 if (currprefs.cpu_model >= 68020) {
9977 save_u32 (0); //save_u32 (regs.ce020memcycles);
9978 save_u32 (0);
9979 }
9980 save_u32 (regs.chipset_latch_rw);
9981 save_u32 (regs.chipset_latch_read);
9982 save_u32 (regs.chipset_latch_write);
9983 if (currprefs.cpu_model == 68020) {
9984 save_u16(regs.pipeline_pos);
9985 save_u16(regs.pipeline_r8[0]);
9986 save_u16(regs.pipeline_r8[1]);
9987 save_u16(regs.pipeline_stop);
9988 }
9989 *len = dst - dstbak;
9990 return dstbak;
9991 }
9992
9993 uae_u8 *save_mmu (int *len, uae_u8 *dstptr)
9994 {
9995 uae_u8 *dstbak, *dst;
9996 int model;
9997
9998 model = currprefs.mmu_model;
9999 #ifndef WINUAE_FOR_HATARI
10000 /* Under Hatari, we save all MMU variables, even if mmu_model==0 */
10001 if (model != 68030 && model != 68040 && model != 68060)
10002 return NULL;
10003 #endif
10004 if (dstptr)
10005 dstbak = dst = dstptr;
10006 else
10007 dstbak = dst = xmalloc (uae_u8, 1000);
10008 save_u32 (model); /* MODEL */
10009 save_u32 (0); /* FLAGS */
10010 *len = dst - dstbak;
10011 return dstbak;
10012 }
10013
10014 uae_u8 *restore_mmu (uae_u8 *src)
10015 {
10016 int flags, model;
10017
10018 changed_prefs.mmu_model = model = restore_u32 ();
10019 flags = restore_u32 ();
10020 write_log (_T("MMU: %d\n"), model);
10021 return src;
10022 }
10023
10024 #endif /* SAVESTATE */
10025
10026 static void exception3f (uae_u32 opcode, uaecptr addr, bool writeaccess, bool instructionaccess, bool notinstruction, uaecptr pc, bool plus2)
10027 {
10028 if (currprefs.cpu_model >= 68040)
10029 addr &= ~1;
10030 if (currprefs.cpu_model >= 68020) {
10031 if (pc == 0xffffffff)
10032 last_addr_for_exception_3 = regs.instruction_pc;
10033 else
10034 last_addr_for_exception_3 = pc;
10035 } else if (pc == 0xffffffff) {
10036 last_addr_for_exception_3 = m68k_getpc ();
10037 if (plus2)
10038 last_addr_for_exception_3 += 2;
10039 } else {
10040 last_addr_for_exception_3 = pc;
10041 }
10042 last_fault_for_exception_3 = addr;
10043 last_op_for_exception_3 = opcode;
10044 last_writeaccess_for_exception_3 = writeaccess;
10045 last_instructionaccess_for_exception_3 = instructionaccess;
10046 last_notinstruction_for_exception_3 = notinstruction;
10047 Exception (3);
10048 #if EXCEPTION3_DEBUGGER
10049 activate_debugger();
10050 #endif
10051 }
10052
10053 void exception3_notinstruction(uae_u32 opcode, uaecptr addr)
10054 {
10055 exception3f (opcode, addr, true, false, true, 0xffffffff, false);
10056 }
10057 void exception3_read(uae_u32 opcode, uaecptr addr)
10058 {
10059 exception3f (opcode, addr, false, 0, false, 0xffffffff, false);
10060 }
10061 void exception3_write(uae_u32 opcode, uaecptr addr)
10062 {
10063 exception3f (opcode, addr, true, 0, false, 0xffffffff, false);
10064 }
10065 void exception3i (uae_u32 opcode, uaecptr addr)
10066 {
10067 exception3f (opcode, addr, 0, 1, false, 0xffffffff, true);
10068 }
10069 void exception3b (uae_u32 opcode, uaecptr addr, bool w, bool i, uaecptr pc)
10070 {
10071 exception3f (opcode, addr, w, i, false, pc, true);
10072 }
10073
10074 void exception2_setup(uaecptr addr, bool read, int size, uae_u32 fc)
10075 {
10076 last_addr_for_exception_3 = m68k_getpc() + bus_error_offset;
10077 last_fault_for_exception_3 = addr;
10078 last_writeaccess_for_exception_3 = read == 0;
10079 last_instructionaccess_for_exception_3 = (fc & 1) == 0;
10080 last_op_for_exception_3 = regs.opcode;
10081 last_notinstruction_for_exception_3 = exception_in_exception != 0;
10082 }
10083
10084 void exception2 (uaecptr addr, bool read, int size, uae_u32 fc)
10085 {
10086 if (currprefs.mmu_model) {
10087 if (currprefs.mmu_model == 68030) {
10088 uae_u32 flags = size == 1 ? MMU030_SSW_SIZE_B : (size == 2 ? MMU030_SSW_SIZE_W : MMU030_SSW_SIZE_L);
10089 mmu030_page_fault (addr, read, flags, fc);
10090 } else {
10091 mmu_bus_error (addr, 0, fc, read == false, size, 0, true);
10092 }
10093 } else {
10094 exception2_setup(addr, read, size, fc);
10095 THROW(2);
10096 }
10097 }
10098
10099 void cpureset (void)
10100 {
10101 /* RESET hasn't increased PC yet, 1 word offset */
10102 uaecptr pc;
10103 #ifndef WINUAE_FOR_HATARI
10104 uaecptr ksboot = 0xf80002 - 2;
10105 uae_u16 ins;
10106 #endif
10107 addrbank *ab;
10108
10109 #ifndef WINUAE_FOR_HATARI
10110 if (currprefs.cpu_model == 68060 && currprefs.cpuboard_type == 0 && rtarea_base != 0xf00000) {
10111 // disable FPU at reset if no accelerator board and no $f0 ROM.
10112 regs.pcr |= 2;
10113 }
10114 #endif
10115 m68k_reset_delay = currprefs.reset_delay;
10116 set_special(SPCFLAG_CHECK);
10117 #ifndef WINUAE_FOR_HATARI
10118 send_internalevent(INTERNALEVENT_CPURESET);
10119 if ((currprefs.cpu_compatible || currprefs.cpu_memory_cycle_exact) && currprefs.cpu_model <= 68020) {
10120 custom_reset_cpu (false, false);
10121 return;
10122 }
10123 #endif
10124 pc = m68k_getpc () + 2;
10125 ab = &get_mem_bank (pc);
10126 if (ab->check (pc, 2)) {
10127 write_log (_T("CPU reset PC=%x (%s)..\n"), pc - 2, ab->name);
10128 #ifndef WINUAE_FOR_HATARI
10129 ins = get_word (pc);
10130 custom_reset_cpu(false, false);
10131 // did memory disappear under us?
10132 if (ab == &get_mem_bank (pc))
10133 return;
10134 // it did
10135 if ((ins & ~7) == 0x4ed0) {
10136 int reg = ins & 7;
10137 uae_u32 addr = m68k_areg (regs, reg);
10138 if (addr < 0x80000)
10139 addr += 0xf80000;
10140 write_log (_T("reset/jmp (ax) combination at %08x emulated -> %x\n"), pc, addr);
10141 m68k_setpc_normal (addr - 2);
10142 return;
10143 }
10144 #else
10145 customreset (); /* From hatari-glue.c */
10146 return;
10147 #endif
10148 }
10149 // the best we can do, jump directly to ROM entrypoint
10150 // (which is probably what program wanted anyway)
10151 #ifndef WINUAE_FOR_HATARI
10152 write_log (_T("CPU Reset PC=%x (%s), invalid memory -> %x.\n"), pc, ab->name, ksboot + 2);
10153 custom_reset_cpu (false, false);
10154 m68k_setpc_normal (ksboot);
10155 #else
10156 write_log (_T("CPU Reset PC=%x (%s), invalid memory\n"), pc, ab->name);
10157 customreset (); /* From hatari-glue.c */
10158 #endif
10159 }
10160
10161
10162 void m68k_setstopped (void)
10163 {
10164 /* A traced STOP instruction drops through immediately without
10165 actually stopping. */
10166 if ((regs.spcflags & SPCFLAG_DOTRACE) == 0) {
10167 m68k_set_stop();
10168 } else {
10169 m68k_resumestopped ();
10170 }
10171 }
10172
10173 void m68k_resumestopped (void)
10174 {
10175 if (!regs.stopped)
10176 return;
10177 if (currprefs.cpu_cycle_exact && currprefs.cpu_model == 68000) {
10178 x_do_cycles (6 * cpucycleunit);
10179 }
10180 fill_prefetch ();
10181 m68k_unset_stop();
10182 }
10183
10184
10185 uae_u32 mem_access_delay_word_read (uaecptr addr)
10186 {
10187 uae_u32 v;
10188 //#ifndef WINUAE_FOR_HATARI
10189 if ( BlitterPhase ) Blitter_HOG_CPU_mem_access_before ( 1 ); // WINUAE_FOR_HATARI
10190 #if 1
10191 switch (ce_banktype[addr >> 16])
10192 {
10193 case CE_MEMBANK_CHIP16:
10194 case CE_MEMBANK_CHIP32:
10195 v = wait_cpu_cycle_read (addr, 1);
10196 break;
10197 case CE_MEMBANK_FAST16:
10198 case CE_MEMBANK_FAST32:
10199 v = get_word (addr);
10200 x_do_cycles_post (4 * cpucycleunit, v);
10201 break;
10202 default:
10203 v = get_word (addr);
10204 break;
10205 }
10206 #else
10207 //fprintf ( stderr , "word read mis %lu %lu\n" , currcycle / cpucycleunit , currcycle );
10208 v = get_word (addr);
10209 x_do_cycles_post (4 * cpucycleunit, v);
10210 #endif
10211 regs.db = v;
10212 if ( BlitterPhase ) Blitter_HOG_CPU_mem_access_after ( 1 ); // WINUAE_FOR_HATARI
10213 return v;
10214 }
10215 uae_u32 mem_access_delay_wordi_read (uaecptr addr)
10216 {
10217 uae_u32 v;
10218 //#ifndef WINUAE_FOR_HATARI
10219 if ( BlitterPhase ) Blitter_HOG_CPU_mem_access_before ( 1 ); // WINUAE_FOR_HATARI
10220 #if 1
10221 switch (ce_banktype[addr >> 16])
10222 {
10223 case CE_MEMBANK_CHIP16:
10224 case CE_MEMBANK_CHIP32:
10225 v = wait_cpu_cycle_read (addr, 2);
10226 break;
10227 case CE_MEMBANK_FAST16:
10228 case CE_MEMBANK_FAST32:
10229 v = get_wordi (addr);
10230 x_do_cycles_post (4 * cpucycleunit, v);
10231 break;
10232 default:
10233 v = get_wordi (addr);
10234 break;
10235 }
10236 #else
10237 //fprintf ( stderr , "wordi read mis %lu %lu\n" , currcycle / cpucycleunit , currcycle );
10238 v = get_wordi (addr);
10239 x_do_cycles_post (4 * cpucycleunit, v);
10240 #endif
10241 regs.db = v;
10242 if ( BlitterPhase ) Blitter_HOG_CPU_mem_access_after ( 1 ); // WINUAE_FOR_HATARI
10243 return v;
10244 }
10245
10246 uae_u32 mem_access_delay_byte_read (uaecptr addr)
10247 {
10248 uae_u32 v;
10249 //#ifndef WINUAE_FOR_HATARI
10250 if ( BlitterPhase ) Blitter_HOG_CPU_mem_access_before ( 1 ); // WINUAE_FOR_HATARI
10251 #if 1
10252 switch (ce_banktype[addr >> 16])
10253 {
10254 case CE_MEMBANK_CHIP16:
10255 case CE_MEMBANK_CHIP32:
10256 v = wait_cpu_cycle_read (addr, 0);
10257 break;
10258 case CE_MEMBANK_FAST16:
10259 case CE_MEMBANK_FAST32:
10260 v = get_byte (addr);
10261 x_do_cycles_post (4 * cpucycleunit, v);
10262 break;
10263 default:
10264 v = get_byte (addr);
10265 break;
10266 }
10267 #else
10268 //fprintf ( stderr , "byte read mis %lu %lu\n" , currcycle / cpucycleunit , currcycle );
10269 v = get_byte (addr);
10270 x_do_cycles_post (4 * cpucycleunit, v);
10271 #endif
10272 regs.db = (v << 8) | v;
10273 if ( BlitterPhase ) Blitter_HOG_CPU_mem_access_after ( 1 ); // WINUAE_FOR_HATARI
10274 return v;
10275 }
10276 void mem_access_delay_byte_write (uaecptr addr, uae_u32 v)
10277 {
10278 regs.db = (v << 8) | v;
10279 //#ifndef WINUAE_FOR_HATARI
10280 if ( BlitterPhase ) Blitter_HOG_CPU_mem_access_before ( 1 ); // WINUAE_FOR_HATARI
10281 #if 1
10282 switch (ce_banktype[addr >> 16])
10283 {
10284 case CE_MEMBANK_CHIP16:
10285 case CE_MEMBANK_CHIP32:
10286 wait_cpu_cycle_write (addr, 0, v);
10287 if ( BlitterPhase ) Blitter_HOG_CPU_mem_access_after ( 1 ); // WINUAE_FOR_HATARI
10288 return;
10289 case CE_MEMBANK_FAST16:
10290 case CE_MEMBANK_FAST32:
10291 put_byte (addr, v);
10292 x_do_cycles_post (4 * cpucycleunit, v);
10293 if ( BlitterPhase ) Blitter_HOG_CPU_mem_access_after ( 1 ); // WINUAE_FOR_HATARI
10294 return;
10295 }
10296 put_byte (addr, v);
10297 #else
10298 put_byte (addr, v);
10299 x_do_cycles_post (4 * cpucycleunit, v);
10300 #endif
10301 }
10302 void mem_access_delay_word_write (uaecptr addr, uae_u32 v)
10303 {
10304 //#ifndef WINUAE_FOR_HATARI
10305 if ( BlitterPhase ) Blitter_HOG_CPU_mem_access_before ( 1 ); // WINUAE_FOR_HATARI
10306 #if 1
10307 regs.db = v;
10308 switch (ce_banktype[addr >> 16])
10309 {
10310 case CE_MEMBANK_CHIP16:
10311 case CE_MEMBANK_CHIP32:
10312 wait_cpu_cycle_write (addr, 1, v);
10313 if ( BlitterPhase ) Blitter_HOG_CPU_mem_access_after ( 1 ); // WINUAE_FOR_HATARI
10314 return;
10315 case CE_MEMBANK_FAST16:
10316 case CE_MEMBANK_FAST32:
10317 put_word (addr, v);
10318 x_do_cycles_post (4 * cpucycleunit, v);
10319 if ( BlitterPhase ) Blitter_HOG_CPU_mem_access_after ( 1 ); // WINUAE_FOR_HATARI
10320 return;
10321 }
10322 put_word (addr, v);
10323 #else
10324 put_word (addr, v);
10325 x_do_cycles_post (4 * cpucycleunit, v);
10326 #endif
10327 }
10328
10329 static void start_020_cycle(void)
10330 {
10331 regs.ce020startcycle = get_cycles();
10332 }
10333
10334 static void start_020_cycle_prefetch(bool opcode)
10335 {
10336 regs.ce020startcycle = get_cycles();
10337 // back to back prefetch cycles require 2 extra cycles (maybe)
10338 if (opcode && regs.ce020startcycle == regs.ce020prefetchendcycle && currprefs.cpu_cycle_exact) {
10339 x_do_cycles(2 * cpucycleunit);
10340 regs.ce020startcycle = get_cycles();
10341 }
10342 }
10343 static void end_020_cycle(void)
10344 {
10345 regs.ce020endcycle = get_cycles();
10346 }
10347 static void end_020_cycle_prefetch(bool opcode)
10348 {
10349 regs.ce020endcycle = get_cycles();
10350 if (opcode) {
10351 regs.ce020prefetchendcycle = regs.ce020endcycle;
10352 } else {
10353 regs.ce020prefetchendcycle = regs.ce020startcycle;
10354 }
10355 }
10356
10357 // this one is really simple and easy
10358 static void fill_icache020 (uae_u32 addr, bool opcode)
10359 {
10360 int index;
10361 uae_u32 tag;
10362 uae_u32 data;
10363 struct cache020 *c;
10364
10365 regs.fc030 = (regs.s ? 4 : 0) | 2;
10366 addr &= ~3;
10367 if (regs.cacheholdingaddr020 == addr)
10368 return;
10369 index = (addr >> 2) & (CACHELINES020 - 1);
10370 tag = regs.s | (addr & ~((CACHELINES020 << 2) - 1));
10371 c = &caches020[index];
10372 if ((regs.cacr & 1) && c->valid && c->tag == tag) {
10373 // cache hit
10374 regs.cacheholdingaddr020 = addr;
10375 regs.cacheholdingdata020 = c->data;
10376 regs.cacheholdingdata_valid = true;
10377 #ifdef WINUAE_FOR_HATARI
10378 CpuInstruction.I_Cache_hit++;
10379 #endif
10380 return;
10381 }
10382
10383 // cache miss
10384 #if 0
10385 // Prefetch apparently can be queued by bus controller
10386 // even if bus controller is currently processing
10387 // previous data access.
10388 // Other combinations are not possible.
10389 if (!regs.ce020memcycle_data) {
10390 if (regs.ce020memcycles > 0)
10391 x_do_cycles (regs.ce020memcycles);
10392 regs.ce020memcycles = 0;
10393 }
10394 #endif
10395
10396 start_020_cycle_prefetch(opcode);
10397 data = icache_fetch(addr);
10398 end_020_cycle_prefetch(opcode);
10399
10400 // enabled and not frozen
10401 if ((regs.cacr & 1) && !(regs.cacr & 2)) {
10402 c->tag = tag;
10403 c->valid = true;
10404 c->data = data;
10405 }
10406 regs.cacheholdingaddr020 = addr;
10407 regs.cacheholdingdata020 = data;
10408 regs.cacheholdingdata_valid = true;
10409 #ifdef WINUAE_FOR_HATARI
10410 CpuInstruction.I_Cache_miss++;
10411 #endif
10412 }
10413
10414 #if MORE_ACCURATE_68020_PIPELINE
10415 #define PIPELINE_DEBUG 0
10416 #if PIPELINE_DEBUG
10417 static uae_u16 pipeline_opcode;
10418 #endif
10419 static void pipeline_020(uaecptr pc)
10420 {
10421 uae_u16 w = regs.prefetch020[1];
10422 if (regs.prefetch020_valid[1] == 0) {
10423 regs.pipeline_stop = -1;
10424 return;
10425 }
10426 if (regs.pipeline_pos < 0)
10427 return;
10428 if (regs.pipeline_pos > 0) {
10429 // handle annoying 68020+ addressing modes
10430 if (regs.pipeline_pos == regs.pipeline_r8[0]) {
10431 regs.pipeline_r8[0] = 0;
10432 if (w & 0x100) {
10433 int extra = 0;
10434 if ((w & 0x30) == 0x20)
10435 extra += 2;
10436 if ((w & 0x30) == 0x30)
10437 extra += 4;
10438 if ((w & 0x03) == 0x02)
10439 extra += 2;
10440 if ((w & 0x03) == 0x03)
10441 extra += 4;
10442 regs.pipeline_pos += extra;
10443 }
10444 return;
10445 }
10446 if (regs.pipeline_pos == regs.pipeline_r8[1]) {
10447 regs.pipeline_r8[1] = 0;
10448 if (w & 0x100) {
10449 int extra = 0;
10450 if ((w & 0x30) == 0x20)
10451 extra += 2;
10452 if ((w & 0x30) == 0x30)
10453 extra += 4;
10454 if ((w & 0x03) == 0x02)
10455 extra += 2;
10456 if ((w & 0x03) == 0x03)
10457 extra += 4;
10458 regs.pipeline_pos += extra;
10459 }
10460 return;
10461 }
10462 }
10463 if (regs.pipeline_pos > 2) {
10464 regs.pipeline_pos -= 2;
10465 // If stop set, prefetches stop 1 word early.
10466 if (regs.pipeline_stop > 0 && regs.pipeline_pos == 2)
10467 regs.pipeline_stop = -1;
10468 return;
10469 }
10470 if (regs.pipeline_stop) {
10471 regs.pipeline_stop = -1;
10472 return;
10473 }
10474 #if PIPELINE_DEBUG
10475 pipeline_opcode = w;
10476 #endif
10477 regs.pipeline_r8[0] = cpudatatbl[w].disp020[0];
10478 regs.pipeline_r8[1] = cpudatatbl[w].disp020[1];
10479 regs.pipeline_pos = cpudatatbl[w].length;
10480 #if PIPELINE_DEBUG
10481 if (!regs.pipeline_pos) {
10482 write_log(_T("Opcode %04x has no size PC=%08x!\n"), w, pc);
10483 }
10484 #endif
10485 // illegal instructions, TRAP, TRAPV, A-line, F-line don't stop prefetches
10486 int branch = cpudatatbl[w].branch;
10487 if (regs.pipeline_pos > 0 && branch) {
10488 // Short branches (Bcc.s) still do one more prefetch.
10489 #if 0
10490 // RTS and other unconditional single opcode instruction stop immediately.
10491 if (branch == 2) {
10492 // Immediate stop
10493 regs.pipeline_stop = -1;
10494 } else {
10495 // Stop 1 word early than normally
10496 regs.pipeline_stop = 1;
10497 }
10498 #else
10499 regs.pipeline_stop = 1;
10500 #endif
10501 }
10502 }
10503
10504 #endif
10505
10506 static uae_u32 get_word_ce020_prefetch_2 (int o, bool opcode)
10507 {
10508 uae_u32 pc = m68k_getpc () + o;
10509 uae_u32 v;
10510
10511 v = regs.prefetch020[0];
10512 regs.prefetch020[0] = regs.prefetch020[1];
10513 regs.prefetch020[1] = regs.prefetch020[2];
10514 #if MORE_ACCURATE_68020_PIPELINE
10515 pipeline_020(pc);
10516 #endif
10517 if (pc & 2) {
10518 // branch instruction detected in pipeline: stop fetches until branch executed.
10519 if (!MORE_ACCURATE_68020_PIPELINE || regs.pipeline_stop >= 0) {
10520 fill_icache020 (pc + 2 + 4, opcode);
10521 }
10522 regs.prefetch020[2] = regs.cacheholdingdata020 >> 16;
10523 } else {
10524 regs.prefetch020[2] = (uae_u16)regs.cacheholdingdata020;
10525 }
10526 do_cycles_ce020_internal (2);
10527 regs.db = regs.prefetch020[0];
10528 return v;
10529 }
10530
10531 uae_u32 get_word_ce020_prefetch (int o)
10532 {
10533 return get_word_ce020_prefetch_2(o, false);
10534 }
10535
10536 uae_u32 get_word_ce020_prefetch_opcode (int o)
10537 {
10538 return get_word_ce020_prefetch_2(o, true);
10539 }
10540
10541 uae_u32 get_word_020_prefetch (int o)
10542 {
10543 uae_u32 pc = m68k_getpc () + o;
10544 uae_u32 v;
10545
10546 v = regs.prefetch020[0];
10547 regs.prefetch020[0] = regs.prefetch020[1];
10548 regs.prefetch020[1] = regs.prefetch020[2];
10549 #if MORE_ACCURATE_68020_PIPELINE
10550 pipeline_020(pc);
10551 #endif
10552 if (pc & 2) {
10553 // branch instruction detected in pipeline: stop fetches until branch executed.
10554 if (!MORE_ACCURATE_68020_PIPELINE || regs.pipeline_stop >= 0) {
10555 fill_icache020 (pc + 2 + 4, false);
10556 }
10557 regs.prefetch020[2] = regs.cacheholdingdata020 >> 16;
10558 } else {
10559 regs.prefetch020[2] = (uae_u16)regs.cacheholdingdata020;
10560 }
10561 regs.db = regs.prefetch020[0];
10562 //if ( ( v & 0xffff ) != ( get_word(pc) & 0xffff ) )
10563 // fprintf ( stderr , "prefetch mismatch pc=%x prefetch=%x != mem=%x, i-cache error ?\n" , pc , v&0xffff , get_word(pc)&0xffff );
10564 return v;
10565 }
10566
10567 // these are also used by 68030.
10568
10569 #if 0
10570 #define RESET_CE020_CYCLES \
10571 regs.ce020memcycles = 0; \
10572 regs.ce020memcycle_data = true;
10573 #define STORE_CE020_CYCLES \
10574 unsigned long cycs = get_cycles ()
10575 #define ADD_CE020_CYCLES \
10576 regs.ce020memcycles += get_cycles () - cycs
10577 #endif
10578
10579 uae_u32 mem_access_delay_long_read_ce020 (uaecptr addr)
10580 {
10581 uae_u32 v;
10582 //fprintf ( stderr , "long read ce020 %lu %lu\n" , currcycle / cpucycleunit , currcycle );
10583 start_020_cycle();
10584 switch (ce_banktype[addr >> 16])
10585 {
10586 case CE_MEMBANK_CHIP16:
10587 v = wait_cpu_cycle_read_ce020 (addr + 0, 1) << 16;
10588 v |= wait_cpu_cycle_read_ce020 (addr + 2, 1) << 0;
10589 break;
10590 case CE_MEMBANK_CHIP32:
10591 if ((addr & 3) != 0) {
10592 v = wait_cpu_cycle_read_ce020 (addr + 0, 1) << 16;
10593 v |= wait_cpu_cycle_read_ce020 (addr + 2, 1) << 0;
10594 } else {
10595 v = wait_cpu_cycle_read_ce020 (addr, -1);
10596 }
10597 break;
10598 case CE_MEMBANK_FAST32:
10599 v = get_long (addr);
10600 if ((addr & 3) != 0)
10601 do_cycles_ce020_mem (2 * CPU020_MEM_CYCLE, v);
10602 else
10603 do_cycles_ce020_mem (1 * CPU020_MEM_CYCLE, v);
10604 break;
10605 case CE_MEMBANK_FAST16:
10606 v = get_long (addr);
10607 do_cycles_ce020_mem (2 * CPU020_MEM_CYCLE, v);
10608 break;
10609 default:
10610 v = get_long (addr);
10611 break;
10612 }
10613 //fprintf ( stderr , "long read2 ce020 %lu %lu\n" , currcycle / cpucycleunit , currcycle );
10614 end_020_cycle();
10615 //fprintf ( stderr , "long read3 ce020 %lu %lu\n" , currcycle / cpucycleunit , currcycle );
10616 return v;
10617 }
10618
10619 uae_u32 mem_access_delay_longi_read_ce020 (uaecptr addr)
10620 {
10621 uae_u32 v;
10622 switch (ce_banktype[addr >> 16])
10623 {
10624 case CE_MEMBANK_CHIP16:
10625 v = wait_cpu_cycle_read_ce020 (addr + 0, 2) << 16;
10626 v |= wait_cpu_cycle_read_ce020 (addr + 2, 2) << 0;
10627 break;
10628 case CE_MEMBANK_CHIP32:
10629 if ((addr & 3) != 0) {
10630 v = wait_cpu_cycle_read_ce020 (addr + 0, 2) << 16;
10631 v |= wait_cpu_cycle_read_ce020 (addr + 2, 2) << 0;
10632 } else {
10633 v = wait_cpu_cycle_read_ce020 (addr, -2);
10634 }
10635 break;
10636 case CE_MEMBANK_FAST32:
10637 v = get_longi (addr);
10638 if ((addr & 3) != 0)
10639 do_cycles_ce020_mem (2 * CPU020_MEM_CYCLE, v);
10640 else
10641 do_cycles_ce020_mem (1 * CPU020_MEM_CYCLE, v);
10642 break;
10643 case CE_MEMBANK_FAST16:
10644 v = get_longi (addr);
10645 do_cycles_ce020_mem (2 * CPU020_MEM_CYCLE, v);
10646 break;
10647 default:
10648 v = get_longi (addr);
10649 break;
10650 }
10651 return v;
10652 }
10653
10654 uae_u32 mem_access_delay_wordi_read_ce020 (uaecptr addr)
10655 {
10656 uae_u32 v;
10657 start_020_cycle();
10658 switch (ce_banktype[addr >> 16])
10659 {
10660 case CE_MEMBANK_CHIP16:
10661 case CE_MEMBANK_CHIP32:
10662 if ((addr & 3) == 3) {
10663 v = wait_cpu_cycle_read_ce020 (addr + 0, 0) << 8;
10664 v |= wait_cpu_cycle_read_ce020 (addr + 1, 0) << 0;
10665 } else {
10666 v = wait_cpu_cycle_read_ce020 (addr, 1);
10667 }
10668 break;
10669 case CE_MEMBANK_FAST16:
10670 case CE_MEMBANK_FAST32:
10671 v = get_wordi (addr);
10672 if ((addr & 3) == 3)
10673 do_cycles_ce020_mem (2 * CPU020_MEM_CYCLE, v);
10674 else
10675 do_cycles_ce020_mem (1 * CPU020_MEM_CYCLE, v);
10676 break;
10677 default:
10678 v = get_wordi (addr);
10679 break;
10680 }
10681 end_020_cycle();
10682 return v;
10683 }
10684
10685 uae_u32 mem_access_delay_word_read_ce020 (uaecptr addr)
10686 {
10687 uae_u32 v;
10688 start_020_cycle();
10689 switch (ce_banktype[addr >> 16])
10690 {
10691 case CE_MEMBANK_CHIP16:
10692 case CE_MEMBANK_CHIP32:
10693 if ((addr & 3) == 3) {
10694 v = wait_cpu_cycle_read_ce020 (addr + 0, 0) << 8;
10695 v |= wait_cpu_cycle_read_ce020 (addr + 1, 0) << 0;
10696 } else {
10697 v = wait_cpu_cycle_read_ce020 (addr, 1);
10698 }
10699 break;
10700 case CE_MEMBANK_FAST16:
10701 case CE_MEMBANK_FAST32:
10702 v = get_word (addr);
10703 if ((addr & 3) == 3)
10704 do_cycles_ce020_mem (2 * CPU020_MEM_CYCLE, v);
10705 else
10706 do_cycles_ce020_mem (1 * CPU020_MEM_CYCLE, v);
10707 break;
10708 default:
10709 v = get_word (addr);
10710 break;
10711 }
10712 end_020_cycle();
10713 return v;
10714 }
10715
10716 uae_u32 mem_access_delay_byte_read_ce020 (uaecptr addr)
10717 {
10718 uae_u32 v;
10719 start_020_cycle();
10720 switch (ce_banktype[addr >> 16])
10721 {
10722 case CE_MEMBANK_CHIP16:
10723 case CE_MEMBANK_CHIP32:
10724 v = wait_cpu_cycle_read_ce020 (addr, 0);
10725 break;
10726 case CE_MEMBANK_FAST16:
10727 case CE_MEMBANK_FAST32:
10728 v = get_byte (addr);
10729 do_cycles_ce020_mem (1 * CPU020_MEM_CYCLE, v);
10730 break;
10731 default:
10732 v = get_byte (addr);
10733 break;
10734 }
10735 end_020_cycle();
10736 return v;
10737 }
10738
10739 void mem_access_delay_byte_write_ce020 (uaecptr addr, uae_u32 v)
10740 {
10741 start_020_cycle();
10742 switch (ce_banktype[addr >> 16])
10743 {
10744 case CE_MEMBANK_CHIP16:
10745 case CE_MEMBANK_CHIP32:
10746 wait_cpu_cycle_write_ce020 (addr, 0, v);
10747 break;
10748 case CE_MEMBANK_FAST16:
10749 case CE_MEMBANK_FAST32:
10750 put_byte (addr, v);
10751 do_cycles_ce020_mem (1 * CPU020_MEM_CYCLE, v);
10752 break;
10753 default:
10754 put_byte (addr, v);
10755 break;
10756 }
10757 end_020_cycle();
10758 }
10759
10760 void mem_access_delay_word_write_ce020 (uaecptr addr, uae_u32 v)
10761 {
10762 start_020_cycle();
10763 switch (ce_banktype[addr >> 16])
10764 {
10765 case CE_MEMBANK_CHIP16:
10766 case CE_MEMBANK_CHIP32:
10767 if ((addr & 3) == 3) {
10768 wait_cpu_cycle_write_ce020 (addr + 0, 0, (v >> 8) & 0xff);
10769 wait_cpu_cycle_write_ce020 (addr + 1, 0, (v >> 0) & 0xff);
10770 } else {
10771 wait_cpu_cycle_write_ce020 (addr + 0, 1, v);
10772 }
10773 break;
10774 case CE_MEMBANK_FAST16:
10775 case CE_MEMBANK_FAST32:
10776 put_word (addr, v);
10777 if ((addr & 3) == 3)
10778 do_cycles_ce020_mem (2 * CPU020_MEM_CYCLE, v);
10779 else
10780 do_cycles_ce020_mem (1 * CPU020_MEM_CYCLE, v);
10781 break;
10782 default:
10783 put_word (addr, v);
10784 break;
10785 }
10786 end_020_cycle();
10787 }
10788
10789 void mem_access_delay_long_write_ce020 (uaecptr addr, uae_u32 v)
10790 {
10791 start_020_cycle();
10792 switch (ce_banktype[addr >> 16])
10793 {
10794 case CE_MEMBANK_CHIP16:
10795 wait_cpu_cycle_write_ce020 (addr + 0, 1, (v >> 16) & 0xffff);
10796 wait_cpu_cycle_write_ce020 (addr + 2, 1, (v >> 0) & 0xffff);
10797 break;
10798 case CE_MEMBANK_CHIP32:
10799 if ((addr & 3) == 3) {
10800 wait_cpu_cycle_write_ce020 (addr + 0, 1, (v >> 16) & 0xffff);
10801 wait_cpu_cycle_write_ce020 (addr + 2, 1, (v >> 0) & 0xffff);
10802 } else {
10803 wait_cpu_cycle_write_ce020 (addr + 0, -1, v);
10804 }
10805 break;
10806 case CE_MEMBANK_FAST32:
10807 put_long (addr, v);
10808 if ((addr & 3) != 0)
10809 do_cycles_ce020_mem (2 * CPU020_MEM_CYCLE, v);
10810 else
10811 do_cycles_ce020_mem (1 * CPU020_MEM_CYCLE, v);
10812 break;
10813 case CE_MEMBANK_FAST16:
10814 put_long (addr, v);
10815 do_cycles_ce020_mem (2 * CPU020_MEM_CYCLE, v);
10816 break;
10817 default:
10818 put_long (addr, v);
10819 break;
10820 }
10821 end_020_cycle();
10822 }
10823
10824
10825 // 68030 caches aren't so simple as 68020 cache..
10826
10827 STATIC_INLINE struct cache030 *geticache030 (struct cache030 *cp, uaecptr addr, uae_u32 *tagp, int *lwsp)
10828 {
10829 int index, lws;
10830 uae_u32 tag;
10831 struct cache030 *c;
10832
10833 addr &= ~3;
10834 index = (addr >> 4) & (CACHELINES030 - 1);
10835 tag = regs.s | (addr & ~((CACHELINES030 << 4) - 1));
10836 lws = (addr >> 2) & 3;
10837 c = &cp[index];
10838 *tagp = tag;
10839 *lwsp = lws;
10840 //fprintf ( stderr , "getcache addr=%x index=%x tag=%x lws=%x\n" , addr , index , tag , lws );
10841 return c;
10842 }
10843
10844 STATIC_INLINE void update_icache030 (struct cache030 *c, uae_u32 val, uae_u32 tag, int lws)
10845 {
10846 if (c->tag != tag)
10847 c->valid[0] = c->valid[1] = c->valid[2] = c->valid[3] = false;
10848 c->tag = tag;
10849 c->valid[lws] = true;
10850 c->data[lws] = val;
10851 }
10852
10853 STATIC_INLINE struct cache030 *getdcache030 (struct cache030 *cp, uaecptr addr, uae_u32 *tagp, int *lwsp)
10854 {
10855 int index, lws;
10856 uae_u32 tag;
10857 struct cache030 *c;
10858
10859 addr &= ~3;
10860 index = (addr >> 4) & (CACHELINES030 - 1);
10861 tag = addr & ~((CACHELINES030 << 4) - 1);
10862 lws = (addr >> 2) & 3;
10863 c = &cp[index];
10864 *tagp = tag;
10865 *lwsp = lws;
10866 return c;
10867 }
10868
10869 STATIC_INLINE void update_dcache030 (struct cache030 *c, uae_u32 val, uae_u32 tag, uae_u8 fc, int lws)
10870 {
10871 if (c->tag != tag)
10872 c->valid[0] = c->valid[1] = c->valid[2] = c->valid[3] = false;
10873 c->tag = tag;
10874 c->fc = fc;
10875 c->valid[lws] = true;
10876 c->data[lws] = val;
10877 }
10878
10879 static void fill_icache030 (uae_u32 addr)
10880 {
10881 int lws;
10882 uae_u32 tag;
10883 uae_u32 data;
10884 struct cache030 *c;
10885 //fprintf ( stderr , "fill icache030 %x %x %x\n" , addr , regs.cacr , regs.cacheholdingaddr020 );
10886
10887 regs.fc030 = (regs.s ? 4 : 0) | 2;
10888 addr &= ~3;
10889 if (regs.cacheholdingaddr020 == addr || regs.cacheholdingdata_valid == 0)
10890 return;
10891 c = geticache030 (icaches030, addr, &tag, &lws);
10892 if ((regs.cacr & 1) && c->valid[lws] && c->tag == tag) {
10893 // cache hit
10894 regs.cacheholdingaddr020 = addr;
10895 regs.cacheholdingdata020 = c->data[lws];
10896 //fprintf ( stderr , "fill ica %x -> hit %x %x\n" , addr , regs.cacheholdingdata020 , regs.cacr );
10897 #ifdef WINUAE_FOR_HATARI
10898 CpuInstruction.I_Cache_hit++;
10899 #endif
10900 return;
10901 }
10902
10903 TRY (prb2) {
10904 // cache miss
10905 if (currprefs.cpu_cycle_exact) {
10906 regs.ce020memcycle_data = false;
10907 start_020_cycle_prefetch(false);
10908 data = icache_fetch(addr);
10909 end_020_cycle_prefetch(false);
10910 } else {
10911 data = icache_fetch(addr);
10912 }
10913 } CATCH (prb2) {
10914 // Bus error/MMU access fault: Delayed exception.
10915 regs.cacheholdingdata_valid = 0;
10916 regs.cacheholdingaddr020 = 0xffffffff;
10917 regs.cacheholdingdata020 = 0xffffffff;
10918 end_020_cycle_prefetch(false);
10919 STOPTRY;
10920 return;
10921 } ENDTRY
10922
10923 if (mmu030_cache_state & CACHE_ENABLE_INS) {
10924 if ((regs.cacr & 0x03) == 0x01) {
10925 // instruction cache not frozen and enabled
10926 //fprintf ( stderr , "fill ica %x -> update %x\n" , addr , data );
10927 update_icache030 (c, data, tag, lws);
10928 }
10929 if ((mmu030_cache_state & CACHE_ENABLE_INS_BURST) && (regs.cacr & 0x11) == 0x11 && (c->valid[0] + c->valid[1] + c->valid[2] + c->valid[3] == 1)) {
10930 //fprintf ( stderr , "fill ica %x -> burst %x\n" , addr , data );
10931 // do burst fetch if cache enabled, not frozen, all slots invalid, no chip ram
10932 int i;
10933 for (i = 0; i < 4; i++) {
10934 if (c->valid[i])
10935 break;
10936 }
10937 uaecptr baddr = addr & ~15;
10938 if (currprefs.mmu_model) {
10939 TRY (prb) {
10940 if (currprefs.cpu_cycle_exact)
10941 #ifndef WINUAE_FOR_HATARI
10942 do_cycles_ce020(3 * (CPU020_MEM_CYCLE - 1));
10943 #else
10944 do_cycles_ce020_long(3 * (CPU020_MEM_CYCLE - 1));
10945 #endif
10946 for (int j = 0; j < 3; j++) {
10947 i++;
10948 i &= 3;
10949 c->data[i] = icache_fetch(baddr + i * 4);
10950 c->valid[i] = true;
10951 }
10952 } CATCH (prb) {
10953 ; // abort burst fetch if bus error, do not report it.
10954 } ENDTRY
10955 } else {
10956 for (int j = 0; j < 3; j++) {
10957 i++;
10958 i &= 3;
10959 c->data[i] = icache_fetch(baddr + i * 4);
10960 c->valid[i] = true;
10961 }
10962 if (currprefs.cpu_cycle_exact)
10963 do_cycles_ce020_mem (3 * (CPU020_MEM_CYCLE - 1), c->data[3]);
10964 }
10965 }
10966 }
10967 regs.cacheholdingaddr020 = addr;
10968 regs.cacheholdingdata020 = data;
10969 //fprintf ( stderr , "fill ica %x -> miss %x\n" , addr , regs.cacheholdingdata020 );
10970 #ifdef WINUAE_FOR_HATARI
10971 CpuInstruction.I_Cache_miss++;
10972 #endif
10973 }
10974
10975 #if VALIDATE_68030_DATACACHE
10976 static void validate_dcache030(void)
10977 {
10978 for (int i = 0; i < CACHELINES030; i++) {
10979 struct cache030 *c = &dcaches030[i];
10980 uae_u32 addr = c->tag & ~((CACHELINES030 << 4) - 1);
10981 addr |= i << 4;
10982 for (int j = 0; j < 4; j++) {
10983 if (c->valid[j]) {
10984 uae_u32 v = get_long(addr);
10985 if (v != c->data[j]) {
10986 write_log(_T("Address %08x data cache mismatch %08x != %08x\n"), addr, v, c->data[j]);
10987 }
10988 }
10989 addr += 4;
10990 }
10991 }
10992 }
10993
10994 static void validate_dcache030_read(uae_u32 addr, uae_u32 ov, int size)
10995 {
10996 uae_u32 ov2;
10997 if (size == 2) {
10998 ov2 = get_long(addr);
10999 } else if (size == 1) {
11000 ov2 = get_word(addr);
11001 ov &= 0xffff;
11002 } else {
11003 ov2 = get_byte(addr);
11004 ov &= 0xff;
11005 }
11006 if (ov2 != ov) {
11007 write_log(_T("Address read %08x data cache mismatch %08x != %08x\n"), addr, ov2, ov);
11008 }
11009 }
11010 #endif
11011
11012 // and finally the worst part, 68030 data cache..
11013 static void write_dcache030x(uaecptr addr, uae_u32 val, uae_u32 size, uae_u32 fc)
11014 {
11015 if (regs.cacr & 0x100) {
11016 static const uae_u32 mask[3] = { 0xff000000, 0xffff0000, 0xffffffff };
11017 struct cache030 *c1, *c2;
11018 int lws1, lws2;
11019 uae_u32 tag1, tag2;
11020 int aligned = addr & 3;
11021 int wa = regs.cacr & 0x2000;
11022 int width = 8 << size;
11023 int offset = 8 * aligned;
11024 int hit;
11025
11026 c1 = getdcache030(dcaches030, addr, &tag1, &lws1);
11027 hit = c1->tag == tag1 && c1->fc == fc && c1->valid[lws1];
11028
11029 // Write-allocate can create new valid cache entry if
11030 // long aligned long write and MMU CI is not active.
11031 // All writes ignore external CIIN signal.
11032 // CACHE_DISABLE_ALLOCATE = emulation only method to disable WA caching completely.
11033
11034 if (width == 32 && offset == 0 && wa) {
11035 if (!(mmu030_cache_state & CACHE_DISABLE_MMU) && !(mmu030_cache_state & CACHE_DISABLE_ALLOCATE)) {
11036 update_dcache030(c1, val, tag1, fc, lws1);
11037 //fprintf ( stderr , "write cache1 %x %x %d tag1 %x lws1 %x tag2 %x lws2 %x ctag %x data %x\n", addr, val, size, tag1, lws1, tag2, lws2, c1->tag , c1->data[lws1] );
11038 #if VALIDATE_68030_DATACACHE
11039 validate_dcache030();
11040 #endif
11041 } else if (hit) {
11042 // Does real 68030 do this if MMU cache inhibited?
11043 c1->valid[lws1] = false;
11044 }
11045 return;
11046 }
11047
11048 if (hit || wa) {
11049 if (hit) {
11050 uae_u32 val_left_aligned = val << (32 - width);
11051 c1->data[lws1] &= ~(mask[size] >> offset);
11052 c1->data[lws1] |= val_left_aligned >> offset;
11053 } else {
11054 c1->valid[lws1] = false;
11055 }
11056 }
11057
11058 // do we need to update a 2nd cache entry ?
11059 if (width + offset > 32) {
11060 c2 = getdcache030(dcaches030, addr + 4, &tag2, &lws2);
11061 hit = c2->tag == tag2 && c2->fc == fc && c2->valid[lws2];
11062 if (hit || wa) {
11063 if (hit) {
11064 c2->data[lws2] &= 0xffffffff >> (width + offset - 32);
11065 c2->data[lws2] |= val << (32 - (width + offset - 32));
11066 } else {
11067 c2->valid[lws2] = false;
11068 }
11069 }
11070 }
11071 #if VALIDATE_68030_DATACACHE
11072 validate_dcache030();
11073 #endif
11074 }
11075 }
11076
11077 void write_dcache030_bput(uaecptr addr, uae_u32 v,uae_u32 fc)
11078 {
11079 //fprintf ( stderr , "write dcache %x %x %d\n" , addr , v , size );
11080 regs.fc030 = fc;
11081 dcache_bput(addr, v);
11082 write_dcache030x(addr, v, 0, fc);
11083 }
11084 void write_dcache030_wput(uaecptr addr, uae_u32 v,uae_u32 fc)
11085 {
11086 regs.fc030 = fc;
11087 dcache_wput(addr, v);
11088 write_dcache030x(addr, v, 1, fc);
11089 }
11090 void write_dcache030_lput(uaecptr addr, uae_u32 v,uae_u32 fc)
11091 {
11092 regs.fc030 = fc;
11093 dcache_lput(addr, v);
11094 write_dcache030x(addr, v, 2, fc);
11095 }
11096
11097 // 68030 MMU bus fault retry case, direct write, store to cache if enabled
11098 void write_dcache030_retry(uaecptr addr, uae_u32 v, uae_u32 fc, int size, int flags)
11099 {
11100 regs.fc030 = fc;
11101 mmu030_put_generic(addr, v, fc, size, flags);
11102 write_dcache030x(addr, v, size, fc);
11103 }
11104
11105 static void dcache030_maybe_burst(uaecptr addr, struct cache030 *c, int lws)
11106 {
11107 if ((c->valid[0] + c->valid[1] + c->valid[2] + c->valid[3] == 1) && ce_banktype[addr >> 16] == CE_MEMBANK_FAST32) {
11108 // do burst fetch if cache enabled, not frozen, all slots invalid, no chip ram
11109 int i;
11110 uaecptr baddr = addr & ~15;
11111 for (i = 0; i < 4; i++) {
11112 if (c->valid[i])
11113 break;
11114 }
11115 if (currprefs.mmu_model) {
11116 TRY (prb) {
11117 if (currprefs.cpu_cycle_exact)
11118 #ifndef WINUAE_FOR_HATARI
11119 do_cycles_ce020(3 * (CPU020_MEM_CYCLE - 1));
11120 #else
11121 do_cycles_ce020_long(3 * (CPU020_MEM_CYCLE - 1));
11122 #endif
11123 for (int j = 0; j < 3; j++) {
11124 i++;
11125 i &= 3;
11126 c->data[i] = dcache_lget (baddr + i * 4);
11127 c->valid[i] = true;
11128 }
11129 } CATCH (prb) {
11130 ; // abort burst fetch if bus error
11131 } ENDTRY
11132 } else {
11133 for (int j = 0; j < 3; j++) {
11134 i++;
11135 i &= 3;
11136 c->data[i] = dcache_lget (baddr + i * 4);
11137 c->valid[i] = true;
11138 }
11139 if (currprefs.cpu_cycle_exact)
11140 do_cycles_ce020_mem (3 * (CPU020_MEM_CYCLE - 1), c->data[i]);
11141 }
11142 #if VALIDATE_68030_DATACACHE
11143 validate_dcache030();
11144 #endif
11145 }
11146 }
11147
11148 static uae_u32 read_dcache030_debug(uaecptr addr, uae_u32 size, uae_u32 fc, bool *cached)
11149 {
11150 static const uae_u32 mask[3] = { 0x000000ff, 0x0000ffff, 0xffffffff };
11151 struct cache030 *c1, *c2;
11152 int lws1, lws2;
11153 uae_u32 tag1, tag2;
11154 int aligned = addr & 3;
11155 uae_u32 v1, v2;
11156 int width = 8 << size;
11157 int offset = 8 * aligned;
11158 uae_u32 out;
11159
11160 *cached = false;
11161 if (!currprefs.cpu_data_cache) {
11162 if (size == 0)
11163 return get_byte_debug(addr);
11164 if (size == 1)
11165 return get_word_debug(addr);
11166 return get_long_debug(addr);
11167 }
11168
11169 c1 = getdcache030(dcaches030, addr, &tag1, &lws1);
11170 addr &= ~3;
11171 if (!c1->valid[lws1] || c1->tag != tag1 || c1->fc != fc) {
11172 v1 = get_long_debug(addr);
11173 } else {
11174 // Cache hit, inhibited caching do not prevent read hits.
11175 v1 = c1->data[lws1];
11176 *cached = true;
11177 }
11178
11179 // only one long fetch needed?
11180 if (width + offset <= 32) {
11181 out = v1 >> (32 - (offset + width));
11182 out &= mask[size];
11183 return out;
11184 }
11185
11186 // no, need another one
11187 addr += 4;
11188 c2 = getdcache030(dcaches030, addr, &tag2, &lws2);
11189 if (!c2->valid[lws2] || c2->tag != tag2 || c2->fc != fc) {
11190 v2 = get_long_debug(addr);
11191 } else {
11192 v2 = c2->data[lws2];
11193 *cached = true;
11194 }
11195
11196 uae_u64 v64 = ((uae_u64)v1 << 32) | v2;
11197 out = (uae_u32)(v64 >> (64 - (offset + width)));
11198 out &= mask[size];
11199 return out;
11200 }
11201
11202 // [HATARI] Define next line to check for 68030 data cache mismatch after every write
11203 //#define WINUAE_FOR_HATARI_DEBUG_CACHE
11204 #ifdef WINUAE_FOR_HATARI_DEBUG_CACHE
11205 bool read_dcache030_2_real (uaecptr addr, uae_u32 size, uae_u32 *valp);
11206 static bool read_dcache030_2 (uaecptr addr, uae_u32 size, uae_u32 *valp)
11207 {
11208 bool b;
11209
11210 b = read_dcache030_2_real ( addr , size , valp );
11211 if ( b==false)
11212 return false;
11213
11214 if ( ( ( size==2 ) && ( *valp != get_long ( addr ) ) )
11215 || ( ( size==1 ) && ( (*valp&0xffff) != (get_word ( addr ) & 0xffff) ) )
11216 || ( ( size==0 ) && ( (*valp&0xff) != (get_byte ( addr ) & 0xff ) ) ) )
11217 fprintf ( stderr , "d-cache mismatch pc=%x addr=%x size=%d cache=%x != mem=%x, d-cache error ?\n" , m68k_getpc(), addr, size, *valp , get_long(addr) );
11218 return true;
11219 }
11220 bool read_dcache030_2_real(uaecptr addr, uae_u32 size, uae_u32 *valp)
11221 #else
11222 static bool read_dcache030_2(uaecptr addr, uae_u32 size, uae_u32 *valp)
11223 #endif
11224 {
11225 // data cache enabled?
11226 if (!(regs.cacr & 0x100))
11227 return false;
11228
11229 uae_u32 addr_o = addr;
11230 uae_u32 fc = regs.fc030;
11231 static const uae_u32 mask[3] = { 0x000000ff, 0x0000ffff, 0xffffffff };
11232 struct cache030 *c1, *c2;
11233 int lws1, lws2;
11234 uae_u32 tag1, tag2;
11235 int aligned = addr & 3;
11236 uae_u32 v1, v2;
11237 int width = 8 << size;
11238 int offset = 8 * aligned;
11239 uae_u32 out;
11240
11241 c1 = getdcache030(dcaches030, addr, &tag1, &lws1);
11242 addr &= ~3;
11243 if (!c1->valid[lws1] || c1->tag != tag1 || c1->fc != fc) {
11244 // MMU validate address, returns zero if valid but uncacheable
11245 // throws bus error if invalid
11246 uae_u8 cs = dcache_check(addr_o, false, size);
11247 if (!(cs & CACHE_ENABLE_DATA))
11248 return false;
11249 v1 = dcache_lget(addr);
11250 update_dcache030(c1, v1, tag1, fc, lws1);
11251 if ((cs & CACHE_ENABLE_DATA_BURST) && (regs.cacr & 0x1100) == 0x1100)
11252 dcache030_maybe_burst(addr, c1, lws1);
11253 #if VALIDATE_68030_DATACACHE
11254 validate_dcache030();
11255 #endif
11256 //fprintf ( stderr , "read cache %x %x %d tag1 %x lws1 %x tag2 %x lws2 %x ref %x\n", addr, v1, size, tag1, lws1, tag2, lws2 , get_long (0x1f81ec) );
11257 #ifdef WINUAE_FOR_HATARI
11258 CpuInstruction.D_Cache_miss++;
11259 #endif
11260 } else {
11261 // Cache hit, inhibited caching do not prevent read hits.
11262 v1 = c1->data[lws1];
11263 #ifdef WINUAE_FOR_HATARI
11264 CpuInstruction.D_Cache_hit++;
11265 #endif
11266 }
11267
11268 // only one long fetch needed?
11269 if (width + offset <= 32) {
11270 out = v1 >> (32 - (offset + width));
11271 out &= mask[size];
11272 #if VALIDATE_68030_DATACACHE
11273 validate_dcache030_read(addr_o, out, size);
11274 #endif
11275 *valp = out;
11276 return true;
11277 }
11278
11279 // no, need another one
11280 addr += 4;
11281 c2 = getdcache030(dcaches030, addr, &tag2, &lws2);
11282 if (!c2->valid[lws2] || c2->tag != tag2 || c2->fc != fc) {
11283 uae_u8 cs = dcache_check(addr, false, 2);
11284 if (!(cs & CACHE_ENABLE_DATA))
11285 return false;
11286 v2 = dcache_lget(addr);
11287 update_dcache030(c2, v2, tag2, fc, lws2);
11288 if ((cs & CACHE_ENABLE_DATA_BURST) && (regs.cacr & 0x1100) == 0x1100)
11289 dcache030_maybe_burst(addr, c2, lws2);
11290 #if VALIDATE_68030_DATACACHE
11291 validate_dcache030();
11292 #endif
11293 //fprintf ( stderr , "read cache %x %x %d tag1 %x lws1 %x tag2 %x lws2 %x\n", addr, v1, size, tag1, lws1, tag2, lws2 );
11294 #ifdef WINUAE_FOR_HATARI
11295 CpuInstruction.D_Cache_miss++;
11296 #endif
11297 } else {
11298 v2 = c2->data[lws2];
11299 #ifdef WINUAE_FOR_HATARI
11300 CpuInstruction.D_Cache_hit++;
11301 #endif
11302 }
11303
11304 uae_u64 v64 = ((uae_u64)v1 << 32) | v2;
11305 out = (uae_u32)(v64 >> (64 - (offset + width)));
11306 out &= mask[size];
11307
11308 #if VALIDATE_68030_DATACACHE
11309 validate_dcache030_read(addr_o, out, size);
11310 #endif
11311 *valp = out;
11312 return true;
11313 }
11314
11315 static uae_u32 read_dcache030 (uaecptr addr, uae_u32 size, uae_u32 fc)
11316 {
11317 uae_u32 val;
11318 regs.fc030 = fc;
11319
11320 if (!read_dcache030_2(addr, size, &val)) {
11321 // read from memory, data cache is disabled or inhibited.
11322 if (size == 2)
11323 return dcache_lget(addr);
11324 else if (size == 1)
11325 return dcache_wget(addr);
11326 else
11327 return dcache_bget(addr);
11328 }
11329 return val;
11330 }
11331
11332 // 68030 MMU bus fault retry case, either read from cache or use direct reads
11333 uae_u32 read_dcache030_retry(uaecptr addr, uae_u32 fc, int size, int flags)
11334 {
11335 uae_u32 val;
11336 regs.fc030 = fc;
11337
11338 if (!read_dcache030_2(addr, size, &val)) {
11339 return mmu030_get_generic(addr, fc, size, flags);
11340 }
11341 return val;
11342 }
11343
11344 uae_u32 read_dcache030_bget(uaecptr addr, uae_u32 fc)
11345 {
11346 return read_dcache030(addr, 0, fc);
11347 }
11348 uae_u32 read_dcache030_wget(uaecptr addr, uae_u32 fc)
11349 {
11350 return read_dcache030(addr, 1, fc);
11351 }
11352 uae_u32 read_dcache030_lget(uaecptr addr, uae_u32 fc)
11353 {
11354 return read_dcache030(addr, 2, fc);
11355 }
11356
11357 uae_u32 read_dcache030_mmu_bget(uaecptr addr)
11358 {
11359 return read_dcache030_bget(addr, (regs.s ? 4 : 0) | 1);
11360 }
11361 uae_u32 read_dcache030_mmu_wget(uaecptr addr)
11362 {
11363 return read_dcache030_wget(addr, (regs.s ? 4 : 0) | 1);
11364 }
11365 uae_u32 read_dcache030_mmu_lget(uaecptr addr)
11366 {
11367 return read_dcache030_lget(addr, (regs.s ? 4 : 0) | 1);
11368 }
11369 void write_dcache030_mmu_bput(uaecptr addr, uae_u32 val)
11370 {
11371 write_dcache030_bput(addr, val, (regs.s ? 4 : 0) | 1);
11372 }
11373 void write_dcache030_mmu_wput(uaecptr addr, uae_u32 val)
11374 {
11375 write_dcache030_wput(addr, val, (regs.s ? 4 : 0) | 1);
11376 }
11377 void write_dcache030_mmu_lput(uaecptr addr, uae_u32 val)
11378 {
11379 write_dcache030_lput(addr, val, (regs.s ? 4 : 0) | 1);
11380 }
11381
11382 uae_u32 read_dcache030_lrmw_mmu_fcx(uaecptr addr, uae_u32 size, int fc)
11383 {
11384 if (currprefs.cpu_data_cache) {
11385 mmu030_cache_state = CACHE_DISABLE_MMU;
11386 if (size == 0)
11387 return read_dcache030_bget(addr, fc);
11388 if (size == 1)
11389 return read_dcache030_wget(addr, fc);
11390 return read_dcache030_lget(addr, fc);
11391 } else {
11392 if (size == 0)
11393 return read_data_030_bget(addr);
11394 if (size == 1)
11395 return read_data_030_wget(addr);
11396 return read_data_030_lget(addr);
11397 }
11398 }
11399 uae_u32 read_dcache030_lrmw_mmu(uaecptr addr, uae_u32 size)
11400 {
11401 return read_dcache030_lrmw_mmu_fcx(addr, size, (regs.s ? 4 : 0) | 1);
11402 }
11403 void write_dcache030_lrmw_mmu_fcx(uaecptr addr, uae_u32 val, uae_u32 size, int fc)
11404 {
11405 if (currprefs.cpu_data_cache) {
11406 mmu030_cache_state = CACHE_DISABLE_MMU;
11407 if (size == 0)
11408 write_dcache030_bput(addr, val, fc);
11409 else if (size == 1)
11410 write_dcache030_wput(addr, val, fc);
11411 else
11412 write_dcache030_lput(addr, val, fc);
11413 } else {
11414 if (size == 0)
11415 write_data_030_bput(addr, val);
11416 else if (size == 1)
11417 write_data_030_wput(addr, val);
11418 else
11419 write_data_030_lput(addr, val);
11420 }
11421 }
11422 void write_dcache030_lrmw_mmu(uaecptr addr, uae_u32 val, uae_u32 size)
11423 {
11424 write_dcache030_lrmw_mmu_fcx(addr, val, size, (regs.s ? 4 : 0) | 1);
11425 }
11426
11427 static void do_access_or_bus_error(uaecptr pc, uaecptr pcnow)
11428 {
11429 // TODO: handle external bus errors
11430 if (!currprefs.mmu_model)
11431 return;
11432 if (pc != 0xffffffff)
11433 regs.instruction_pc = pc;
11434 mmu030_opcode = -1;
11435 mmu030_page_fault(pcnow, true, -1, 0);
11436 }
11437
11438 static uae_u32 get_word_ce030_prefetch_2 (int o)
11439 {
11440 uae_u32 pc = m68k_getpc () + o;
11441 uae_u32 v;
11442
11443 //fprintf ( stderr , "get_word_ce030_prefetch_2 %d pc=%x\n" , currcycle , pc);
11444 v = regs.prefetch020[0];
11445 regs.prefetch020[0] = regs.prefetch020[1];
11446 regs.prefetch020[1] = regs.prefetch020[2];
11447 #if MORE_ACCURATE_68020_PIPELINE
11448 pipeline_020(pc);
11449 #endif
11450 if (pc & 2) {
11451 // branch instruction detected in pipeline: stop fetches until branch executed.
11452 if (!MORE_ACCURATE_68020_PIPELINE || regs.pipeline_stop >= 0) {
11453 fill_icache030 (pc + 2 + 4);
11454 } else {
11455 if (regs.cacheholdingdata_valid > 0)
11456 regs.cacheholdingdata_valid++;
11457 }
11458 regs.prefetch020[2] = regs.cacheholdingdata020 >> 16;
11459 } else {
11460 pc += 4;
11461 // cacheholdingdata020 may be invalid if RTE from bus error
11462 if ((!MORE_ACCURATE_68020_PIPELINE || regs.pipeline_stop >= 0) && regs.cacheholdingaddr020 != pc) {
11463 fill_icache030 (pc);
11464 }
11465 regs.prefetch020[2] = (uae_u16)regs.cacheholdingdata020;
11466 }
11467 regs.db = regs.prefetch020[0];
11468 do_cycles_ce020_internal (2);
11469 return v;
11470 }
11471
11472 uae_u32 get_word_ce030_prefetch (int o)
11473 {
11474 return get_word_ce030_prefetch_2(o);
11475 }
11476 uae_u32 get_word_ce030_prefetch_opcode (int o)
11477 {
11478 return get_word_ce030_prefetch_2(o);
11479 }
11480
11481 uae_u32 get_word_030_prefetch (int o)
11482 {
11483 uae_u32 pc = m68k_getpc () + o;
11484 uae_u32 v;
11485
11486 v = regs.prefetch020[0];
11487 regs.prefetch020[0] = regs.prefetch020[1];
11488 regs.prefetch020[1] = regs.prefetch020[2];
11489 regs.prefetch020_valid[0] = regs.prefetch020_valid[1];
11490 regs.prefetch020_valid[1] = regs.prefetch020_valid[2];
11491 regs.prefetch020_valid[2] = false;
11492 if (!regs.prefetch020_valid[1]) {
11493 do_access_or_bus_error(0xffffffff, pc + 4);
11494 }
11495 #if MORE_ACCURATE_68020_PIPELINE
11496 pipeline_020(pc);
11497 #endif
11498 if (pc & 2) {
11499 // branch instruction detected in pipeline: stop fetches until branch executed.
11500 if (!MORE_ACCURATE_68020_PIPELINE || regs.pipeline_stop >= 0) {
11501 fill_icache030 (pc + 2 + 4);
11502 } else {
11503 if (regs.cacheholdingdata_valid > 0)
11504 regs.cacheholdingdata_valid++;
11505 }
11506 regs.prefetch020[2] = regs.cacheholdingdata020 >> 16;
11507 } else {
11508 pc += 4;
11509 // cacheholdingdata020 may be invalid if RTE from bus error
11510 if ((!MORE_ACCURATE_68020_PIPELINE || regs.pipeline_stop >= 0) && regs.cacheholdingaddr020 != pc) {
11511 fill_icache030 (pc);
11512 }
11513 regs.prefetch020[2] = (uae_u16)regs.cacheholdingdata020;
11514 }
11515 regs.prefetch020_valid[2] = regs.cacheholdingdata_valid;
11516 regs.db = regs.prefetch020[0];
11517 //if ( ( v & 0xffff ) != ( get_word(pc) & 0xffff ) )
11518 // fprintf ( stderr , "prefetch mismatch pc=%x prefetch=%x != mem=%x, i-cache error ?\n" , pc , v&0xffff , get_word(pc)&0xffff );
11519 return v;
11520 }
11521
11522 uae_u32 get_word_icache030(uaecptr addr)
11523 {
11524 fill_icache030(addr);
11525 return regs.cacheholdingdata020 >> ((addr & 2) ? 0 : 16);
11526 }
11527 uae_u32 get_long_icache030(uaecptr addr)
11528 {
11529 uae_u32 v;
11530 fill_icache030(addr);
11531 if ((addr & 2) == 0)
11532 return regs.cacheholdingdata020;
11533 v = regs.cacheholdingdata020 << 16;
11534 fill_icache030(addr + 4);
11535 v |= regs.cacheholdingdata020 >> 16;
11536 return v;
11537 }
11538
11539 uae_u32 fill_icache040(uae_u32 addr)
11540 {
11541 int index, lws;
11542 uae_u32 tag, addr2;
11543 struct cache040 *c;
11544 int line;
11545
11546 addr2 = addr & ~15;
11547 lws = (addr >> 2) & 3;
11548
11549 if (regs.prefetch020addr == addr2) {
11550 return regs.prefetch040[lws];
11551 }
11552
11553 if (regs.cacr & 0x8000) {
11554 uae_u8 cs = mmu_cache_state;
11555
11556 if (!(ce_cachable[addr >> 16] & CACHE_ENABLE_INS))
11557 cs = CACHE_DISABLE_MMU;
11558
11559 index = (addr >> 4) & cacheisets04060mask;
11560 tag = addr & cacheitag04060mask;
11561 c = &icaches040[index];
11562 for (int i = 0; i < CACHELINES040; i++) {
11563 if (c->valid[cache_lastline] && c->tag[cache_lastline] == tag) {
11564 // cache hit
11565 if (!(cs & CACHE_ENABLE_INS) || (cs & CACHE_DISABLE_MMU)) {
11566 c->valid[cache_lastline] = false;
11567 goto end;
11568 }
11569 if ((lws & 1) != icachehalfline) {
11570 icachehalfline ^= 1;
11571 icachelinecnt++;
11572 #ifdef WINUAE_FOR_HATARI
11573 CpuInstruction.I_Cache_hit++;
11574 #endif
11575 }
11576 return c->data[cache_lastline][lws];
11577 }
11578 cache_lastline++;
11579 cache_lastline &= (CACHELINES040 - 1);
11580 }
11581 // cache miss
11582 regs.prefetch020addr = 0xffffffff;
11583 regs.prefetch040[0] = icache_fetch(addr2 + 0);
11584 regs.prefetch040[1] = icache_fetch(addr2 + 4);
11585 regs.prefetch040[2] = icache_fetch(addr2 + 8);
11586 regs.prefetch040[3] = icache_fetch(addr2 + 12);
11587 regs.prefetch020addr = addr2;
11588 if (!(cs & CACHE_ENABLE_INS) || (cs & CACHE_DISABLE_MMU))
11589 goto end;
11590 if (regs.cacr & 0x00004000) // 68060 NAI
11591 goto end;
11592 if (c->valid[0] && c->valid[1] && c->valid[2] && c->valid[3]) {
11593 line = icachelinecnt & (CACHELINES040 - 1);
11594 icachehalfline = (lws & 1) ? 0 : 1;
11595 } else {
11596 for (line = 0; line < CACHELINES040; line++) {
11597 if (c->valid[line] == false)
11598 break;
11599 }
11600 }
11601 c->tag[line] = tag;
11602 c->valid[line] = true;
11603 c->data[line][0] = regs.prefetch040[0];
11604 c->data[line][1] = regs.prefetch040[1];
11605 c->data[line][2] = regs.prefetch040[2];
11606 c->data[line][3] = regs.prefetch040[3];
11607 if ((lws & 1) != icachehalfline) {
11608 icachehalfline ^= 1;
11609 icachelinecnt++;
11610 }
11611 #ifdef WINUAE_FOR_HATARI
11612 CpuInstruction.I_Cache_miss++;
11613 #endif
11614 return c->data[line][lws];
11615
11616 }
11617
11618 end:
11619 if (regs.prefetch020addr == addr2)
11620 return regs.prefetch040[lws];
11621 regs.prefetch020addr = addr2;
11622 regs.prefetch040[0] = icache_fetch(addr2 + 0);
11623 regs.prefetch040[1] = icache_fetch(addr2 + 4);
11624 regs.prefetch040[2] = icache_fetch(addr2 + 8);
11625 regs.prefetch040[3] = icache_fetch(addr2 + 12);
11626 return regs.prefetch040[lws];
11627 }
11628
11629 STATIC_INLINE void do_cycles_c040_mem (int clocks, uae_u32 val)
11630 {
11631 x_do_cycles_post (clocks * cpucycleunit, val);
11632 }
11633
11634 uae_u32 mem_access_delay_longi_read_c040 (uaecptr addr)
11635 {
11636 uae_u32 v;
11637 switch (ce_banktype[addr >> 16])
11638 {
11639 case CE_MEMBANK_CHIP16:
11640 v = wait_cpu_cycle_read_ce020 (addr + 0, 1) << 16;
11641 v |= wait_cpu_cycle_read_ce020 (addr + 2, 1) << 0;
11642 break;
11643 case CE_MEMBANK_CHIP32:
11644 if ((addr & 3) != 0) {
11645 v = wait_cpu_cycle_read_ce020 (addr + 0, 1) << 16;
11646 v |= wait_cpu_cycle_read_ce020 (addr + 2, 1) << 0;
11647 } else {
11648 v = wait_cpu_cycle_read_ce020 (addr, -1);
11649 }
11650 break;
11651 case CE_MEMBANK_FAST16:
11652 v = get_longi (addr);
11653 do_cycles_c040_mem(1, v);
11654 break;
11655 case CE_MEMBANK_FAST32:
11656 v = get_longi (addr);
11657 break;
11658 default:
11659 v = get_longi (addr);
11660 break;
11661 }
11662 return v;
11663 }
11664 uae_u32 mem_access_delay_long_read_c040 (uaecptr addr)
11665 {
11666 uae_u32 v;
11667 switch (ce_banktype[addr >> 16])
11668 {
11669 case CE_MEMBANK_CHIP16:
11670 v = wait_cpu_cycle_read_ce020 (addr + 0, 1) << 16;
11671 v |= wait_cpu_cycle_read_ce020 (addr + 2, 1) << 0;
11672 break;
11673 case CE_MEMBANK_CHIP32:
11674 if ((addr & 3) != 0) {
11675 v = wait_cpu_cycle_read_ce020 (addr + 0, 1) << 16;
11676 v |= wait_cpu_cycle_read_ce020 (addr + 2, 1) << 0;
11677 } else {
11678 v = wait_cpu_cycle_read_ce020 (addr, -1);
11679 }
11680 break;
11681 case CE_MEMBANK_FAST16:
11682 v = get_long (addr);
11683 do_cycles_c040_mem(1, v);
11684 break;
11685 case CE_MEMBANK_FAST32:
11686 v = get_long (addr);
11687 break;
11688 default:
11689 v = get_long (addr);
11690 break;
11691 }
11692 return v;
11693 }
11694
11695 uae_u32 mem_access_delay_word_read_c040 (uaecptr addr)
11696 {
11697 uae_u32 v;
11698 switch (ce_banktype[addr >> 16])
11699 {
11700 case CE_MEMBANK_CHIP16:
11701 case CE_MEMBANK_CHIP32:
11702 if ((addr & 3) == 3) {
11703 v = wait_cpu_cycle_read_ce020 (addr + 0, 0) << 8;
11704 v |= wait_cpu_cycle_read_ce020 (addr + 1, 0) << 0;
11705 } else {
11706 v = wait_cpu_cycle_read_ce020 (addr, 1);
11707 }
11708 break;
11709 case CE_MEMBANK_FAST16:
11710 v = get_word (addr);
11711 do_cycles_c040_mem (2, v);
11712 break;
11713 case CE_MEMBANK_FAST32:
11714 v = get_word (addr);
11715 break;
11716 default:
11717 v = get_word (addr);
11718 break;
11719 }
11720 return v;
11721 }
11722
11723 uae_u32 mem_access_delay_byte_read_c040 (uaecptr addr)
11724 {
11725 uae_u32 v;
11726 switch (ce_banktype[addr >> 16])
11727 {
11728 case CE_MEMBANK_CHIP16:
11729 case CE_MEMBANK_CHIP32:
11730 v = wait_cpu_cycle_read_ce020 (addr, 0);
11731 break;
11732 case CE_MEMBANK_FAST16:
11733 v = get_byte (addr);
11734 do_cycles_c040_mem (1, v);
11735 break;
11736 case CE_MEMBANK_FAST32:
11737 v = get_byte (addr);
11738 break;
11739 default:
11740 v = get_byte (addr);
11741 break;
11742 }
11743 return v;
11744 }
11745
11746 void mem_access_delay_byte_write_c040 (uaecptr addr, uae_u32 v)
11747 {
11748 switch (ce_banktype[addr >> 16])
11749 {
11750 case CE_MEMBANK_CHIP16:
11751 case CE_MEMBANK_CHIP32:
11752 wait_cpu_cycle_write_ce020 (addr, 0, v);
11753 break;
11754 case CE_MEMBANK_FAST16:
11755 put_byte (addr, v);
11756 do_cycles_c040_mem (1, v);
11757 break;
11758 case CE_MEMBANK_FAST32:
11759 put_byte (addr, v);
11760 break;
11761 default:
11762 put_byte (addr, v);
11763 break;
11764 }
11765 }
11766
11767 void mem_access_delay_word_write_c040 (uaecptr addr, uae_u32 v)
11768 {
11769 switch (ce_banktype[addr >> 16])
11770 {
11771 case CE_MEMBANK_CHIP16:
11772 case CE_MEMBANK_CHIP32:
11773 if ((addr & 3) == 3) {
11774 wait_cpu_cycle_write_ce020 (addr + 0, 0, (v >> 8) & 0xff);
11775 wait_cpu_cycle_write_ce020 (addr + 1, 0, (v >> 0) & 0xff);
11776 } else {
11777 wait_cpu_cycle_write_ce020 (addr + 0, 1, v);
11778 }
11779 break;
11780 case CE_MEMBANK_FAST16:
11781 put_word (addr, v);
11782 if ((addr & 3) == 3)
11783 do_cycles_c040_mem(2, v);
11784 else
11785 do_cycles_c040_mem(1, v);
11786 break;
11787 case CE_MEMBANK_FAST32:
11788 put_word (addr, v);
11789 break;
11790 default:
11791 put_word (addr, v);
11792 break;
11793 }
11794 }
11795
11796 void mem_access_delay_long_write_c040 (uaecptr addr, uae_u32 v)
11797 {
11798 switch (ce_banktype[addr >> 16])
11799 {
11800 case CE_MEMBANK_CHIP16:
11801 wait_cpu_cycle_write_ce020 (addr + 0, 1, (v >> 16) & 0xffff);
11802 wait_cpu_cycle_write_ce020 (addr + 2, 1, (v >> 0) & 0xffff);
11803 break;
11804 case CE_MEMBANK_CHIP32:
11805 if ((addr & 3) == 3) {
11806 wait_cpu_cycle_write_ce020 (addr + 0, 1, (v >> 16) & 0xffff);
11807 wait_cpu_cycle_write_ce020 (addr + 2, 1, (v >> 0) & 0xffff);
11808 } else {
11809 wait_cpu_cycle_write_ce020 (addr + 0, -1, v);
11810 }
11811 break;
11812 case CE_MEMBANK_FAST16:
11813 put_long (addr, v);
11814 do_cycles_ce020_mem (2 * CPU020_MEM_CYCLE, v);
11815 break;
11816 case CE_MEMBANK_FAST32:
11817 put_long (addr, v);
11818 break;
11819 default:
11820 put_long (addr, v);
11821 break;
11822 }
11823 }
11824
11825 static uae_u32 dcache040_get_data(uaecptr addr, struct cache040 *c, int line, int size)
11826 {
11827 static const uae_u32 mask[3] = { 0x000000ff, 0x0000ffff, 0xffffffff };
11828 int offset = (addr & 15) * 8;
11829 int offset32 = offset & 31;
11830 int slot = offset / 32;
11831 int width = 8 << size;
11832 uae_u32 vv;
11833
11834 if (offset32 + width <= 32) {
11835 uae_u32 v = c->data[line][slot];
11836 v >>= 32 - (offset32 + width);
11837 v &= mask[size];
11838 vv = v;
11839 } else {
11840 #if VALIDATE_68040_DATACACHE
11841 if (slot >= 3) {
11842 write_log(_T("invalid dcache040_get_data!\n"));
11843 return 0;
11844 }
11845 #endif
11846 uae_u64 v = c->data[line][slot];
11847 v <<= 32;
11848 v |= c->data[line][slot + 1];
11849 v >>= 64 - (offset32 + width);
11850 vv = v & mask[size];
11851 }
11852 return vv;
11853 }
11854
11855 static void dcache040_update(uaecptr addr, struct cache040 *c, int line, uae_u32 val, int size)
11856 {
11857 static const uae_u64 mask64[3] = { 0xff, 0xffff, 0xffffffff };
11858 static const uae_u32 mask32[3] = { 0xff, 0xffff, 0xffffffff };
11859 int offset = (addr & 15) * 8;
11860 int offset32 = offset & 31;
11861 int slot = offset / 32;
11862 int width = 8 << size;
11863
11864 #if VALIDATE_68040_DATACACHE > 1
11865 validate_dcache040();
11866 #endif
11867
11868 if (offset32 + width <= 32) {
11869 int shift = 32 - (offset32 + width);
11870 uae_u32 v = c->data[line][slot];
11871 v &= ~(mask32[size] << shift);
11872 v |= val << shift;
11873 c->data[line][slot] = v;
11874 c->dirty[line][slot] = true;
11875 } else {
11876 #if VALIDATE_68040_DATACACHE
11877 if (slot >= 3) {
11878 write_log(_T("invalid dcache040_update!\n"));
11879 return;
11880 }
11881 #endif
11882 int shift = 64 - (offset32 + width);
11883 uae_u64 v = c->data[line][slot];
11884 v <<= 32;
11885 v |= c->data[line][slot + 1];
11886 v &= ~(mask64[size] << shift);
11887 v |= ((uae_u64)val) << shift;
11888 c->data[line][slot] = v >> 32;
11889 c->dirty[line][slot] = true;
11890 c->data[line][slot + 1] = (uae_u32)v;
11891 c->dirty[line][slot + 1] = true;
11892 }
11893 c->gdirty[line] = true;
11894 }
11895
11896 static int dcache040_fill_line(int index, uae_u32 tag, uaecptr addr)
11897 {
11898 // cache miss
11899 struct cache040 *c = &dcaches040[index];
11900 int line;
11901 if (c->valid[0] && c->valid[1] && c->valid[2] && c->valid[3]) {
11902 // all lines allocated, choose one, push and invalidate.
11903 line = dcachelinecnt & (CACHELINES040 - 1);
11904 dcachelinecnt++;
11905 dcache040_push_line(index, line, false, true);
11906 } else {
11907 // at least one invalid
11908 for (line = 0; line < CACHELINES040; line++) {
11909 if (c->valid[line] == false)
11910 break;
11911 }
11912 }
11913 c->tag[line] = tag;
11914 c->dirty[line][0] = false;
11915 c->dirty[line][1] = false;
11916 c->dirty[line][2] = false;
11917 c->dirty[line][3] = false;
11918 c->gdirty[line] = false;
11919 c->data[line][0] = dcache_lget(addr + 0);
11920 c->data[line][1] = dcache_lget(addr + 4);
11921 c->data[line][2] = dcache_lget(addr + 8);
11922 c->data[line][3] = dcache_lget(addr + 12);
11923 c->valid[line] = true;
11924 return line;
11925 }
11926
11927 static uae_u32 read_dcache040_debug(uae_u32 addr, int size, bool *cached)
11928 {
11929 int index;
11930 uae_u32 tag;
11931 struct cache040 *c;
11932 int line;
11933 uae_u32 addr_o = addr;
11934 uae_u8 cs = mmu_cache_state;
11935
11936 *cached = false;
11937 if (!currprefs.cpu_data_cache)
11938 goto nocache;
11939 if (!(regs.cacr & 0x80000000))
11940 goto nocache;
11941
11942 addr &= ~15;
11943 index = (addr >> 4) & cachedsets04060mask;
11944 tag = addr & cachedtag04060mask;
11945 c = &dcaches040[index];
11946 for (line = 0; line < CACHELINES040; line++) {
11947 if (c->valid[line] && c->tag[line] == tag) {
11948 // cache hit
11949 return dcache040_get_data(addr_o, c, line, size);
11950 }
11951 }
11952 nocache:
11953 if (size == 0)
11954 return get_byte_debug(addr);
11955 if (size == 1)
11956 return get_word_debug(addr);
11957 return get_long_debug(addr);
11958 }
11959
11960 static uae_u32 read_dcache040(uae_u32 addr, int size, uae_u32 (*fetch)(uaecptr))
11961 {
11962 int index;
11963 uae_u32 tag;
11964 struct cache040 *c;
11965 int line;
11966 uae_u32 addr_o = addr;
11967 uae_u8 cs = mmu_cache_state;
11968
11969 if (!(regs.cacr & 0x80000000))
11970 goto nocache;
11971
11972 #if VALIDATE_68040_DATACACHE > 1
11973 validate_dcache040();
11974 #endif
11975
11976 // Simple because 68040+ caches physical addresses (68030 caches logical addresses)
11977 if (!(ce_cachable[addr >> 16] & CACHE_ENABLE_DATA))
11978 cs = CACHE_DISABLE_MMU;
11979
11980 addr &= ~15;
11981 index = (addr >> 4) & cachedsets04060mask;
11982 tag = addr & cachedtag04060mask;
11983 c = &dcaches040[index];
11984 for (line = 0; line < CACHELINES040; line++) {
11985 if (c->valid[line] && c->tag[line] == tag) {
11986 // cache hit
11987 dcachelinecnt++;
11988 // Cache hit but MMU disabled: do not cache, push and invalidate possible existing line
11989 if (cs & CACHE_DISABLE_MMU) {
11990 dcache040_push_line(index, line, false, true);
11991 goto nocache;
11992 }
11993 return dcache040_get_data(addr_o, c, line, size);
11994 }
11995 }
11996 // Cache miss
11997 // 040+ always caches whole line
11998 if ((cs & CACHE_DISABLE_MMU) || !(cs & CACHE_ENABLE_DATA) || (cs & CACHE_DISABLE_ALLOCATE) || (regs.cacr & 0x40000000)) {
11999 nocache:
12000 return fetch(addr_o);
12001 }
12002 // Allocate new cache line, return requested data.
12003 line = dcache040_fill_line(index, tag, addr);
12004 return dcache040_get_data(addr_o, c, line, size);
12005 }
12006
12007 static void write_dcache040(uae_u32 addr, uae_u32 val, int size, void (*store)(uaecptr, uae_u32))
12008 {
12009 static const uae_u32 mask[3] = { 0x000000ff, 0x0000ffff, 0xffffffff };
12010 int index;
12011 uae_u32 tag;
12012 struct cache040 *c;
12013 int line;
12014 uae_u32 addr_o = addr;
12015 uae_u8 cs = mmu_cache_state;
12016
12017 val &= mask[size];
12018
12019 if (!(regs.cacr & 0x80000000))
12020 goto nocache;
12021
12022 if (!(ce_cachable[addr >> 16] & CACHE_ENABLE_DATA))
12023 cs = CACHE_DISABLE_MMU;
12024
12025 addr &= ~15;
12026 index = (addr >> 4) & cachedsets04060mask;
12027 tag = addr & cachedtag04060mask;
12028 c = &dcaches040[index];
12029 for (line = 0; line < CACHELINES040; line++) {
12030 if (c->valid[line] && c->tag[line] == tag) {
12031 // cache hit
12032 dcachelinecnt++;
12033 // Cache hit but MMU disabled: do not cache, push and invalidate possible existing line
12034 if (cs & CACHE_DISABLE_MMU) {
12035 dcache040_push_line(index, line, false, true);
12036 goto nocache;
12037 }
12038 dcache040_update(addr_o, c, line, val, size);
12039 // If not copyback mode: push modifications immediately (write-through)
12040 if (!(cs & CACHE_ENABLE_COPYBACK) || DISABLE_68040_COPYBACK) {
12041 dcache040_push_line(index, line, true, false);
12042 }
12043 return;
12044 }
12045 }
12046 // Cache miss
12047 // 040+ always caches whole line
12048 // Writes misses in write-through mode don't allocate new cache lines
12049 if (!(cs & CACHE_ENABLE_DATA) || (cs & CACHE_DISABLE_MMU) || (cs & CACHE_DISABLE_ALLOCATE) || !(cs & CACHE_ENABLE_COPYBACK) || (regs.cacr & 0x400000000)) {
12050 nocache:
12051 store(addr_o, val);
12052 return;
12053 }
12054 // Allocate new cache line and update it with new data.
12055 line = dcache040_fill_line(index, tag, addr);
12056 dcache040_update(addr_o, c, line, val, size);
12057 if (DISABLE_68040_COPYBACK) {
12058 dcache040_push_line(index, line, true, false);
12059 }
12060 }
12061
12062 // really unoptimized
12063 uae_u32 get_word_icache040(uaecptr addr)
12064 {
12065 uae_u32 v = fill_icache040(addr);
12066 return v >> ((addr & 2) ? 0 : 16);
12067 }
12068 uae_u32 get_long_icache040(uaecptr addr)
12069 {
12070 uae_u32 v1, v2;
12071 v1 = fill_icache040(addr);
12072 if ((addr & 2) == 0)
12073 return v1;
12074 v2 = fill_icache040(addr + 4);
12075 return (v2 >> 16) | (v1 << 16);
12076 }
12077 uae_u32 get_ilong_cache_040(int o)
12078 {
12079 return get_long_icache040(m68k_getpci() + o);
12080 }
12081 uae_u32 get_iword_cache_040(int o)
12082 {
12083 return get_word_icache040(m68k_getpci() + o);
12084 }
12085
12086 void put_long_cache_040(uaecptr addr, uae_u32 v)
12087 {
12088 int offset = addr & 15;
12089 // access must not cross cachelines
12090 if (offset < 13) {
12091 write_dcache040(addr, v, 2, dcache_lput);
12092 } else if (offset == 13 || offset == 15) {
12093 write_dcache040(addr + 0, v >> 24, 0, dcache_bput);
12094 write_dcache040(addr + 1, v >> 8, 1, dcache_wput);
12095 write_dcache040(addr + 3, v >> 0, 0, dcache_bput);
12096 } else if (offset == 14) {
12097 write_dcache040(addr + 0, v >> 16, 1, dcache_wput);
12098 write_dcache040(addr + 2, v >> 0, 1, dcache_wput);
12099 }
12100 }
12101 void put_word_cache_040(uaecptr addr, uae_u32 v)
12102 {
12103 int offset = addr & 15;
12104 if (offset < 15) {
12105 write_dcache040(addr, v, 1, dcache_wput);
12106 } else {
12107 write_dcache040(addr + 0, v >> 8, 0, dcache_bput);
12108 write_dcache040(addr + 1, v >> 0, 0, dcache_bput);
12109 }
12110 }
12111 void put_byte_cache_040(uaecptr addr, uae_u32 v)
12112 {
12113 return write_dcache040(addr, v, 0, dcache_bput);
12114 }
12115
12116 uae_u32 get_long_cache_040(uaecptr addr)
12117 {
12118 uae_u32 v;
12119 int offset = addr & 15;
12120 if (offset < 13) {
12121 v = read_dcache040(addr, 2, dcache_lget);
12122 } else if (offset == 13 || offset == 15) {
12123 v = read_dcache040(addr + 0, 0, dcache_bget) << 24;
12124 v |= read_dcache040(addr + 1, 1, dcache_wget) << 8;
12125 v |= read_dcache040(addr + 3, 0, dcache_bget) << 0;
12126 } else /* if (offset == 14) */ {
12127 v = read_dcache040(addr + 0, 1, dcache_wget) << 16;
12128 v |= read_dcache040(addr + 2, 1, dcache_wget) << 0;
12129 }
12130 return v;
12131 }
12132 uae_u32 get_word_cache_040(uaecptr addr)
12133 {
12134 uae_u32 v;
12135 int offset = addr & 15;
12136 if (offset < 15) {
12137 v = read_dcache040(addr, 1, dcache_wget);
12138 } else {
12139 v = read_dcache040(addr + 0, 0, dcache_bget) << 8;
12140 v |= read_dcache040(addr + 1, 0, dcache_bget) << 0;
12141 }
12142 return v;
12143 }
12144 uae_u32 get_byte_cache_040(uaecptr addr)
12145 {
12146 return read_dcache040(addr, 0, dcache_bget);
12147 }
12148 uae_u32 next_iword_cache040(void)
12149 {
12150 uae_u32 r = get_word_icache040(m68k_getpci());
12151 m68k_incpci(2);
12152 return r;
12153 }
12154 uae_u32 next_ilong_cache040(void)
12155 {
12156 uae_u32 r = get_long_icache040(m68k_getpci());
12157 m68k_incpci(4);
12158 return r;
12159 }
12160
12161 uae_u32 get_byte_cache_debug(uaecptr addr, bool *cached)
12162 {
12163 *cached = false;
12164 if (currprefs.cpu_model == 68030) {
12165 return read_dcache030_debug(addr, 0, regs.s ? 5 : 1, cached);
12166 } else if (currprefs.cpu_model >= 68040) {
12167 return read_dcache040_debug(addr, 0, cached);
12168 }
12169 return get_byte_debug(addr);
12170 }
12171 uae_u32 get_word_cache_debug(uaecptr addr, bool *cached)
12172 {
12173 *cached = false;
12174 if (currprefs.cpu_model == 68030) {
12175 return read_dcache030_debug(addr, 1, regs.s ? 5 : 1, cached);
12176 } else if (currprefs.cpu_model >= 68040) {
12177 return read_dcache040_debug(addr, 1, cached);
12178 }
12179 return get_word_debug(addr);
12180 }
12181
12182 uae_u32 get_long_cache_debug(uaecptr addr, bool *cached)
12183 {
12184 *cached = false;
12185 if (currprefs.cpu_model == 68030) {
12186 return read_dcache030_debug(addr, 2, regs.s ? 5 : 1, cached);
12187 } else if (currprefs.cpu_model >= 68040) {
12188 return read_dcache040_debug(addr, 2, cached);
12189 }
12190 return get_long_debug(addr);
12191 }
12192
12193 void check_t0_trace(void)
12194 {
12195 if (regs.t0 && currprefs.cpu_model >= 68020) {
12196 unset_special (SPCFLAG_TRACE);
12197 set_special (SPCFLAG_DOTRACE);
12198 }
12199 }
12200
12201 static void reset_pipeline_state(void)
12202 {
12203 #if MORE_ACCURATE_68020_PIPELINE
12204 regs.pipeline_pos = 0;
12205 regs.pipeline_stop = 0;
12206 regs.pipeline_r8[0] = regs.pipeline_r8[1] = -1;
12207 #endif
12208 }
12209
12210 static int add_prefetch_030(int idx, uae_u16 w, uaecptr pc)
12211 {
12212 regs.prefetch020[0] = regs.prefetch020[1];
12213 regs.prefetch020_valid[0] = regs.prefetch020_valid[1];
12214 regs.prefetch020[1] = regs.prefetch020[2];
12215 regs.prefetch020_valid[1] = regs.prefetch020_valid[2];
12216 regs.prefetch020[2] = w;
12217 regs.prefetch020_valid[2] = regs.cacheholdingdata_valid;
12218
12219 #if MORE_ACCURATE_68020_PIPELINE
12220 if (idx >= 1) {
12221 pipeline_020(pc);
12222 }
12223 #endif
12224
12225 if (!regs.prefetch020_valid[2]) {
12226 if (idx == 0 || !regs.pipeline_stop) {
12227 // Pipeline refill and first opcode word is invalid?
12228 // Generate previously detected bus error/MMU fault
12229 do_access_or_bus_error(pc, pc + idx * 2);
12230 }
12231 }
12232 return idx + 1;
12233 }
12234
12235 void fill_prefetch_030_ntx(void)
12236 {
12237 //fprintf ( stderr , "fill_prefetch_030_ntx %d\n" , currcycle);
12238 uaecptr pc = m68k_getpc ();
12239 uaecptr pc2 = pc;
12240 int idx = 0;
12241
12242 pc &= ~3;
12243 mmu030_idx = 0;
12244 reset_pipeline_state();
12245 regs.cacheholdingdata_valid = 1;
12246 regs.cacheholdingaddr020 = 0xffffffff;
12247 regs.prefetch020_valid[0] = regs.prefetch020_valid[1] = regs.prefetch020_valid[2] = 0;
12248
12249 fill_icache030(pc);
12250 if (currprefs.cpu_cycle_exact)
12251 do_cycles_ce020_internal(2);
12252 if (pc2 & 2) {
12253 idx = add_prefetch_030(idx, regs.cacheholdingdata020, pc2);
12254 } else {
12255 idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc2);
12256 idx = add_prefetch_030(idx, regs.cacheholdingdata020, pc2);
12257 }
12258
12259 fill_icache030(pc + 4);
12260 if (currprefs.cpu_cycle_exact)
12261 do_cycles_ce020_internal(2);
12262 if (pc2 & 2) {
12263 idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc2);
12264 idx = add_prefetch_030(idx, regs.cacheholdingdata020, pc2);
12265 } else {
12266 idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc2);
12267 }
12268
12269 if (currprefs.cpu_cycle_exact)
12270 regs.irc = get_word_ce030_prefetch_opcode (0);
12271 else
12272 regs.irc = get_word_030_prefetch (0);
12273 }
12274
12275 void fill_prefetch_030_ntx_continue (void)
12276 {
12277 uaecptr pc = m68k_getpc ();
12278 uaecptr pc_orig = pc;
12279 int idx = 0;
12280
12281 mmu030_idx = 0;
12282 reset_pipeline_state();
12283 regs.cacheholdingdata_valid = 1;
12284 regs.cacheholdingaddr020 = 0xffffffff;
12285
12286 for (int i = 2; i >= 0; i--) {
12287 if (!regs.prefetch020_valid[i])
12288 break;
12289 #if MORE_ACCURATE_68020_PIPELINE
12290 if (idx >= 1) {
12291 pipeline_020(pc);
12292 }
12293 #endif
12294 pc += 2;
12295 idx++;
12296 }
12297
12298 if (idx < 3 && !regs.pipeline_stop) {
12299 uaecptr pc2 = pc;
12300 pc &= ~3;
12301
12302 fill_icache030(pc);
12303 if (currprefs.cpu_cycle_exact)
12304 do_cycles_ce020_internal(2);
12305 if (pc2 & 2) {
12306 idx = add_prefetch_030(idx, regs.cacheholdingdata020, pc_orig);
12307 } else {
12308 idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc_orig);
12309 if (idx < 3)
12310 idx = add_prefetch_030(idx, regs.cacheholdingdata020, pc_orig);
12311 }
12312
12313 if (idx < 3) {
12314 fill_icache030(pc + 4);
12315 if (currprefs.cpu_cycle_exact)
12316 do_cycles_ce020_internal(2);
12317 if (pc2 & 2) {
12318 idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc_orig);
12319 if (idx < 3)
12320 idx = add_prefetch_030(idx, regs.cacheholdingdata020, pc_orig);
12321 } else {
12322 idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc_orig);
12323 }
12324 }
12325 }
12326
12327 if (currprefs.cpu_cycle_exact)
12328 regs.irc = get_word_ce030_prefetch_opcode (0);
12329 else
12330 regs.irc = get_word_030_prefetch (0);
12331 //fprintf ( stderr , "fill_prefetch_030_ntx4 %d\n" , currcycle);
12332 }
12333
12334 void fill_prefetch_020_ntx(void)
12335 {
12336 uaecptr pc = m68k_getpc ();
12337 uaecptr pc2 = pc;
12338 int idx = 0;
12339
12340 pc &= ~3;
12341 reset_pipeline_state();
12342
12343 fill_icache020 (pc, true);
12344 if (currprefs.cpu_cycle_exact)
12345 do_cycles_ce020_internal(2);
12346 if (pc2 & 2) {
12347 idx = add_prefetch_030(idx, regs.cacheholdingdata020, pc);
12348 } else {
12349 idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc);
12350 idx = add_prefetch_030(idx, regs.cacheholdingdata020, pc);
12351 }
12352
12353 fill_icache020 (pc + 4, true);
12354 if (currprefs.cpu_cycle_exact)
12355 do_cycles_ce020_internal(2);
12356 if (pc2 & 2) {
12357 idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc);
12358 idx = add_prefetch_030(idx, regs.cacheholdingdata020, pc);
12359 } else {
12360 idx = add_prefetch_030(idx, regs.cacheholdingdata020 >> 16, pc);
12361 }
12362
12363 if (currprefs.cpu_cycle_exact)
12364 regs.irc = get_word_ce020_prefetch_opcode (0);
12365 else
12366 regs.irc = get_word_020_prefetch (0);
12367 }
12368
12369 // Not exactly right, requires logic analyzer checks.
12370 void continue_ce020_prefetch(void)
12371 {
12372 fill_prefetch_020_ntx();
12373 }
12374 void continue_020_prefetch(void)
12375 {
12376 fill_prefetch_020_ntx();
12377 }
12378
12379 void continue_ce030_prefetch(void)
12380 {
12381 fill_prefetch_030_ntx();
12382 }
12383 void continue_030_prefetch(void)
12384 {
12385 fill_prefetch_030_ntx();
12386 }
12387
12388 void fill_prefetch_020(void)
12389 {
12390 fill_prefetch_020_ntx();
12391 check_t0_trace();
12392 }
12393
12394 void fill_prefetch_030(void)
12395 {
12396 fill_prefetch_030_ntx();
12397 check_t0_trace();
12398 }
12399
12400
12401 void fill_prefetch (void)
12402 {
12403 reset_pipeline_state();
12404 if (currprefs.cachesize)
12405 return;
12406 if (!currprefs.cpu_compatible)
12407 return;
12408 if (currprefs.cpu_model >= 68040) {
12409 if (currprefs.cpu_compatible || currprefs.cpu_memory_cycle_exact) {
12410 fill_icache040(m68k_getpc() + 16);
12411 fill_icache040(m68k_getpc());
12412 }
12413 } else if (currprefs.cpu_model == 68020) {
12414 fill_prefetch_020 ();
12415 } else if (currprefs.cpu_model == 68030) {
12416 fill_prefetch_030 ();
12417 } else if (currprefs.cpu_model <= 68010) {
12418 uaecptr pc = m68k_getpc ();
12419 regs.ir = x_get_word (pc);
12420 regs.irc = x_get_word (pc + 2);
12421 }
12422 }
12423
12424 #ifndef WINUAE_FOR_HATARI
12425 extern bool cpuboard_fc_check(uaecptr addr, uae_u32 *v, int size, bool write);
12426 #else
12427 STATIC_INLINE bool cpuboard_fc_check(uaecptr addr, uae_u32 *v, int size, bool write)
12428 {
12429 return false;
12430 }
12431 #endif
12432
12433 uae_u32 sfc_nommu_get_byte(uaecptr addr)
12434 {
12435 uae_u32 v;
12436 if (!cpuboard_fc_check(addr, &v, 0, false))
12437 v = x_get_byte(addr);
12438 return v;
12439 }
12440 uae_u32 sfc_nommu_get_word(uaecptr addr)
12441 {
12442 uae_u32 v;
12443 if (!cpuboard_fc_check(addr, &v, 1, false))
12444 v = x_get_word(addr);
12445 return v;
12446 }
12447 uae_u32 sfc_nommu_get_long(uaecptr addr)
12448 {
12449 uae_u32 v;
12450 if (!cpuboard_fc_check(addr, &v, 2, false))
12451 v = x_get_long(addr);
12452 return v;
12453 }
12454 void dfc_nommu_put_byte(uaecptr addr, uae_u32 v)
12455 {
12456 if (!cpuboard_fc_check(addr, &v, 0, true))
12457 x_put_byte(addr, v);
12458 }
12459 void dfc_nommu_put_word(uaecptr addr, uae_u32 v)
12460 {
12461 if (!cpuboard_fc_check(addr, &v, 1, true))
12462 x_put_word(addr, v);
12463 }
12464 void dfc_nommu_put_long(uaecptr addr, uae_u32 v)
12465 {
12466 if (!cpuboard_fc_check(addr, &v, 2, true))
12467 x_put_long(addr, v);
12468 }
12469