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, &regs, 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(&regs, &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 = &regs;
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 = &regs;
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 = &regs;
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 = &regs;
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 = &regs;
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 = &regs;
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 = &regs;
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 = &regs;
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 = &regs;
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 = &regs;
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(&regs.fp[i], -1));
9263 			console_out_f (_T("%s "), fpp_print(&regs.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