|
|
1.1 root 1: /*
2: * UAE - The Un*x Amiga Emulator
3: *
4: * MC68000 emulation
5: *
6: * (c) 1995 Bernd Schmidt
7: */
8:
9: #define MMUOP_DEBUG 2
10: #define DEBUG_CD32CDTVIO 0
11:
12: #include "main.h"
13: #include "m68000.h"
14: #include "compat.h"
15: #include "sysconfig.h"
16: #include "sysdeps.h"
17: #include "hatari-glue.h"
18: #include "options_cpu.h"
19: #include "maccess.h"
20: #include "memory.h"
21: #include "newcpu.h"
22: #include "cpummu.h"
23: #include "cpummu030.h"
24: #ifdef WITH_SOFTFLOAT
25: #include "fpp-softfloat.h"
26: #else
27: #include "md-fpp.h"
28: #endif
29: #include "main.h"
30: #include "dsp.h"
31: #include "dimension.hpp"
32: #include "reset.h"
33: #include "cycInt.h"
34: #include "dialog.h"
35: #include "screen.h"
36: #include "video.h"
37: #include "log.h"
38: #include "debugui.h"
39: #include "debugcpu.h"
40:
41:
42: /* Opcode of faulting instruction */
43: static uae_u16 last_op_for_exception_3;
44: /* PC at fault time */
45: static uaecptr last_addr_for_exception_3;
46: /* Address that generated the exception */
47: static uaecptr last_fault_for_exception_3;
48: /* read (0) or write (1) access */
49: static int last_writeaccess_for_exception_3;
50: /* instruction (1) or data (0) access */
51: static int last_instructionaccess_for_exception_3;
52: int mmu_enabled, mmu_triggered;
53: int cpu_cycles;
54:
55: const int areg_byteinc[] = { 1, 1, 1, 1, 1, 1, 1, 2 };
56: const int imm8_table[] = { 8, 1, 2, 3, 4, 5, 6, 7 };
57:
58: int movem_index1[256];
59: int movem_index2[256];
60: int movem_next[256];
61:
62: cpuop_func *cpufunctbl[65536];
63:
64: int OpcodeFamily;
65: struct mmufixup mmufixup[2];
66:
67: uae_u32 fpp_get_fpsr (void);
68:
69: static struct cache030 icaches030[CACHELINES030];
70: static struct cache030 dcaches030[CACHELINES030];
71:
72: void m68k_disasm_2 (TCHAR *buf, int bufsize, uaecptr addr, uaecptr *nextpc, int cnt, uae_u32 *seaddr, uae_u32 *deaddr, int safemode);
73:
74: uae_u32 (*x_prefetch)(int);
75: uae_u32 (*x_next_iword)(void);
76: uae_u32 (*x_next_ilong)(void);
77: uae_u32 (*x_get_ilong)(int);
78: uae_u32 (*x_get_iword)(int);
79: uae_u32 (*x_get_ibyte)(int);
80: uae_u32 (*x_get_long)(uaecptr);
81: uae_u32 (*x_get_word)(uaecptr);
82: uae_u32 (*x_get_byte)(uaecptr);
83: void (*x_put_long)(uaecptr,uae_u32);
84: void (*x_put_word)(uaecptr,uae_u32);
85: void (*x_put_byte)(uaecptr,uae_u32);
86:
87: uae_u32 (*x_cp_next_iword)(void);
88: uae_u32 (*x_cp_next_ilong)(void);
89: uae_u32 (*x_cp_get_long)(uaecptr);
90: uae_u32 (*x_cp_get_word)(uaecptr);
91: uae_u32 (*x_cp_get_byte)(uaecptr);
92: void (*x_cp_put_long)(uaecptr,uae_u32);
93: void (*x_cp_put_word)(uaecptr,uae_u32);
94: void (*x_cp_put_byte)(uaecptr,uae_u32);
95: uae_u32 (REGPARAM3 *x_cp_get_disp_ea_020)(uae_u32 base, int idx) REGPARAM;
96:
97: // shared memory access functions
98: static void set_x_funcs (void)
99: {
100: if (currprefs.cpu_model == 68040) {
101: x_prefetch = get_iword_mmu040;
102: x_get_ilong = get_ilong_mmu040;
103: x_get_iword = get_iword_mmu040;
104: x_get_ibyte = get_ibyte_mmu040;
105: x_next_iword = next_iword_mmu040;
106: x_next_ilong = next_ilong_mmu040;
107: x_put_long = put_long_mmu040;
108: x_put_word = put_word_mmu040;
109: x_put_byte = put_byte_mmu040;
110: x_get_long = get_long_mmu040;
111: x_get_word = get_word_mmu040;
112: x_get_byte = get_byte_mmu040;
113: } else {
114: x_prefetch = get_iword_mmu030;
115: x_get_ilong = get_ilong_mmu030;
116: x_get_iword = get_iword_mmu030;
117: x_get_ibyte = get_ibyte_mmu030;
118: x_next_iword = next_iword_mmu030;
119: x_next_ilong = next_ilong_mmu030;
120: x_put_long = put_long_mmu030;
121: x_put_word = put_word_mmu030;
122: x_put_byte = put_byte_mmu030;
123: x_get_long = get_long_mmu030;
124: x_get_word = get_word_mmu030;
125: x_get_byte = get_byte_mmu030;
126: }
127:
128: if (currprefs.mmu_model == 68030) {
129: x_cp_put_long = put_long_mmu030_state;
130: x_cp_put_word = put_word_mmu030_state;
131: x_cp_put_byte = put_byte_mmu030_state;
132: x_cp_get_long = get_long_mmu030_state;
133: x_cp_get_word = get_word_mmu030_state;
134: x_cp_get_byte = get_byte_mmu030_state;
135: x_cp_next_iword = next_iword_mmu030_state;
136: x_cp_next_ilong = next_ilong_mmu030_state;
137: x_cp_get_disp_ea_020 = get_disp_ea_020_mmu030;
138: } else {
139: x_cp_put_long = x_put_long;
140: x_cp_put_word = x_put_word;
141: x_cp_put_byte = x_put_byte;
142: x_cp_get_long = x_get_long;
143: x_cp_get_word = x_get_word;
144: x_cp_get_byte = x_get_byte;
145: x_cp_next_iword = x_next_iword;
146: x_cp_next_ilong = x_next_ilong;
147: x_cp_get_disp_ea_020 = x_get_disp_ea_020;
148: }
149: }
150:
151: void flush_cpu_caches_040(uae_u16 opcode)
152: {
153: int cache = (opcode >> 6) & 3;
154: if (!(cache & 2))
155: return;
156: set_cpu_caches(true);
157: }
158:
159: void set_cpu_caches (bool flush)
160: {
161: int i;
162:
163: if (currprefs.cpu_model == 68030) {
164: if (regs.cacr & 0x08) { // clear instr cache
165: for (i = 0; i < CACHELINES030; i++) {
166: icaches030[i].valid[0] = 0;
167: icaches030[i].valid[1] = 0;
168: icaches030[i].valid[2] = 0;
169: icaches030[i].valid[3] = 0;
170: }
171: regs.cacr &= ~0x08;
172: }
173: if (regs.cacr & 0x04) { // clear entry in instr cache
174: icaches030[(regs.caar >> 4) & (CACHELINES030 - 1)].valid[(regs.caar >> 2) & 3] = 0;
175: regs.cacr &= ~0x04;
176: }
177: if (regs.cacr & 0x800) { // clear data cache
178: for (i = 0; i < CACHELINES030; i++) {
179: dcaches030[i].valid[0] = 0;
180: dcaches030[i].valid[1] = 0;
181: dcaches030[i].valid[2] = 0;
182: dcaches030[i].valid[3] = 0;
183: }
184: regs.cacr &= ~0x800;
185: }
186: if (regs.cacr & 0x400) { // clear entry in data cache
187: dcaches030[(regs.caar >> 4) & (CACHELINES030 - 1)].valid[(regs.caar >> 2) & 3] = 0;
188: regs.cacr &= ~0x400;
189: }
190: #if 0 // FIXME
191: } else if (currprefs.cpu_model == 68040) {
192: if (ConfigureParams.System.bRealtime) {
193: if (regs.cacr & 0x8000) {
194: flush_icache(0, -1);
195: x_prefetch = getc_iword_mmu040;
196: x_get_ilong = getc_ilong_mmu040;
197: x_get_iword = getc_iword_mmu040;
198: x_get_ibyte = getc_ibyte_mmu040;
199: x_next_iword = nextc_iword_mmu040;
200: x_next_ilong = nextc_ilong_mmu040;
201: } else {
202: x_prefetch = get_iword_mmu040;
203: x_get_ilong = get_ilong_mmu040;
204: x_get_iword = get_iword_mmu040;
205: x_get_ibyte = get_ibyte_mmu040;
206: x_next_iword = next_iword_mmu040;
207: x_next_ilong = next_ilong_mmu040;
208: }
209: }
210: #endif
211: }
212: }
213:
214: static uae_u32 REGPARAM2 op_illg_1 (uae_u32 opcode)
215: {
216: op_illg (opcode);
217: return 4;
218: }
219: static uae_u32 REGPARAM2 op_unimpl_1 (uae_u32 opcode)
220: {
221: if ((opcode & 0xf000) == 0xf000 || currprefs.cpu_model < 68060)
222: op_illg (opcode);
223: else
224: op_unimpl (opcode);
225: return 4;
226: }
227:
228: void build_cpufunctbl (void)
229: {
230: int i, opcnt;
231: unsigned long opcode;
232: const struct cputbl *tbl = 0;
233: int lvl;
234:
235: switch (currprefs.cpu_model)
236: {
237: case 68040:
238: lvl = 4;
239: tbl = op_smalltbl_31_ff;
240: break;
241: case 68030:
242: lvl = 3;
243: tbl = op_smalltbl_32_ff;
244: break;
245: default:
246: changed_prefs.cpu_model = currprefs.cpu_model = 68030;
247: lvl = 3;
248: tbl = op_smalltbl_32_ff;
249: }
250:
251: if (tbl == 0) {
252: write_log ("no CPU emulation cores available CPU=%d!", currprefs.cpu_model);
253: DebugUI();
254: }
255:
256: for (opcode = 0; opcode < 65536; opcode++)
257: cpufunctbl[opcode] = op_illg_1;
258: for (i = 0; tbl[i].handler != NULL; i++) {
259: opcode = tbl[i].opcode;
260: cpufunctbl[opcode] = tbl[i].handler;
261: }
262:
263: opcnt = 0;
264: for (opcode = 0; opcode < 65536; opcode++) {
265: cpuop_func *f;
266:
267: if (table68k[opcode].mnemo == i_ILLG)
268: continue;
269: if (table68k[opcode].clev > lvl) {
270: continue;
271: }
272:
273: if (table68k[opcode].handler != -1) {
274: int idx = table68k[opcode].handler;
275: f = cpufunctbl[idx];
276: if (f == op_illg_1)
277: DebugUI();
278: cpufunctbl[opcode] = f;
279: opcnt++;
280: }
281: }
282: write_log ("Building CPU, %d opcodes (%d %d)\n",
283: opcnt, lvl, currprefs.cpu_compatible ? 1 : 0);
284: write_log ("CPU=%d, MMU=%d, FPU=%d ($%02x)\n",
285: currprefs.cpu_model, currprefs.mmu_model,
286: currprefs.fpu_model, currprefs.fpu_revision);
287: set_cpu_caches (0);
288: if (currprefs.mmu_model) {
289: if (currprefs.cpu_model >= 68040) {
290: mmu_reset ();
291: mmu_set_tc (regs.tcr);
292: mmu_set_super (regs.s != 0);
293: } else {
294: mmu030_reset(1);
295: }
296: }
297: }
298:
299: static void prefs_changed_cpu (void) {
300: currprefs.cpu_model = changed_prefs.cpu_model;
301: currprefs.fpu_model = changed_prefs.fpu_model;
302: currprefs.fpu_revision = changed_prefs.fpu_revision;
303: currprefs.mmu_model = changed_prefs.mmu_model;
304: currprefs.cpu_compatible = changed_prefs.cpu_compatible;
305: }
306:
307: void check_prefs_changed_cpu (void)
308: {
309: bool changed = 0;
310:
311: if (changed
312: || currprefs.cpu_model != changed_prefs.cpu_model
313: || currprefs.fpu_model != changed_prefs.fpu_model
314: || currprefs.fpu_revision != changed_prefs.fpu_revision
315: || currprefs.mmu_model != changed_prefs.mmu_model
316: || currprefs.cpu_compatible != changed_prefs.cpu_compatible) {
317:
318: prefs_changed_cpu ();
319: build_cpufunctbl ();
320: changed = 1;
321: }
322:
323: if (currprefs.cpu_idle != changed_prefs.cpu_idle) {
324: currprefs.cpu_idle = changed_prefs.cpu_idle;
325: }
326: if (changed)
327: set_special (SPCFLAG_MODE_CHANGE);
328:
329: }
330:
331: void init_m68k (void)
332: {
333: int i;
334:
335: prefs_changed_cpu ();
336:
337: for (i = 0 ; i < 256 ; i++) {
338: int j;
339: for (j = 0 ; j < 8 ; j++) {
340: if (i & (1 << j)) break;
341: }
342: movem_index1[i] = j;
343: movem_index2[i] = 7-j;
344: movem_next[i] = i & (~(1 << j));
345: }
346:
347: write_log ("Building CPU table for configuration: %d", currprefs.cpu_model);
348: regs.address_space_mask = 0xffffffff;
349:
350: if (currprefs.fpu_model > 0)
351: write_log ("/%d", currprefs.fpu_model);
352: if (currprefs.cpu_compatible)
353: write_log (" prefetch");
354: write_log ("\n");
355:
356: read_table68k ();
357: do_merges ();
358:
359: write_log ("%d CPU functions\n", nr_cpuop_funcs);
360:
361: build_cpufunctbl ();
362: set_x_funcs ();
363: }
364:
365: struct regstruct regs;
366: struct flag_struct regflags;
367:
368: #define get_word_debug(o) DBGMemory_ReadWord (o)
369: #define get_iword_debug(o) DBGMemory_ReadWord (o)
370: #define get_ilong_debug(o) DBGMemory_ReadLong (o)
371:
372: static uaecptr ShowEA (void *f, uaecptr pc, uae_u16 opcode, int reg, amodes mode, wordsizes size, TCHAR *buf, uae_u32 *eaddr, int safemode)
373: {
374: uae_u16 dp;
375: uae_s8 disp8;
376: uae_s16 disp16;
377: int r;
378: uae_u32 dispreg;
379: uaecptr addr = pc;
380: uae_s32 offset = 0;
381: TCHAR buffer[80];
382:
383: switch (mode){
384: case Dreg:
385: _stprintf (buffer, _T("D%d"), reg);
386: break;
387: case Areg:
388: _stprintf (buffer, _T("A%d"), reg);
389: break;
390: case Aind:
391: _stprintf (buffer, _T("(A%d)"), reg);
392: addr = regs.regs[reg + 8];
393: break;
394: case Aipi:
395: _stprintf (buffer, _T("(A%d)+"), reg);
396: addr = regs.regs[reg + 8];
397: break;
398: case Apdi:
399: _stprintf (buffer, _T("-(A%d)"), reg);
400: addr = regs.regs[reg + 8];
401: break;
402: case Ad16:
403: {
404: TCHAR offtxt[80];
405: disp16 = get_iword_debug (pc); pc += 2;
406: if (disp16 < 0)
407: _stprintf (offtxt, _T("-$%04x"), -disp16);
408: else
409: _stprintf (offtxt, _T("$%04x"), disp16);
410: addr = m68k_areg (regs, reg) + disp16;
411: _stprintf (buffer, _T("(A%d, %s) == $%08x"), reg, offtxt, addr);
412: }
413: break;
414: case Ad8r:
415: dp = get_iword_debug (pc); pc += 2;
416: disp8 = dp & 0xFF;
417: r = (dp & 0x7000) >> 12;
418: dispreg = dp & 0x8000 ? m68k_areg (regs, r) : m68k_dreg (regs, r);
419: if (!(dp & 0x800)) dispreg = (uae_s32)(uae_s16)(dispreg);
420: dispreg <<= (dp >> 9) & 3;
421:
422: if (dp & 0x100) {
423: uae_s32 outer = 0, disp = 0;
424: uae_s32 base = m68k_areg (regs, reg);
425: TCHAR name[10];
426: _stprintf (name, _T("A%d, "), reg);
427: if (dp & 0x80) { base = 0; name[0] = 0; }
428: if (dp & 0x40) dispreg = 0;
429: if ((dp & 0x30) == 0x20) { disp = (uae_s32)(uae_s16)get_iword_debug (pc); pc += 2; }
430: if ((dp & 0x30) == 0x30) { disp = get_ilong_debug (pc); pc += 4; }
431: base += disp;
432:
433: if ((dp & 0x3) == 0x2) { outer = (uae_s32)(uae_s16)get_iword_debug (pc); pc += 2; }
434: if ((dp & 0x3) == 0x3) { outer = get_ilong_debug (pc); pc += 4; }
435:
436: if (!(dp & 4)) base += dispreg;
437: if ((dp & 3) && !safemode) base = get_ilong_debug (base);
438: if (dp & 4) base += dispreg;
439:
440: addr = base + outer;
441: _stprintf (buffer, _T("(%s%c%d.%c*%d+%d)+%d == $%08x"), name,
442: dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W',
443: 1 << ((dp >> 9) & 3),
444: disp, outer, addr);
445: } else {
446: addr = m68k_areg (regs, reg) + (uae_s32)((uae_s8)disp8) + dispreg;
447: _stprintf (buffer, _T("(A%d, %c%d.%c*%d, $%02x) == $%08x"), reg,
448: dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W',
449: 1 << ((dp >> 9) & 3), disp8, addr);
450: }
451: break;
452: case PC16:
453: disp16 = get_iword_debug (pc); pc += 2;
454: addr += (uae_s16)disp16;
455: _stprintf (buffer, _T("(PC,$%04x) == $%08x"), disp16 & 0xffff, addr);
456: break;
457: case PC8r:
458: dp = get_iword_debug (pc); pc += 2;
459: disp8 = dp & 0xFF;
460: r = (dp & 0x7000) >> 12;
461: dispreg = dp & 0x8000 ? m68k_areg (regs, r) : m68k_dreg (regs, r);
462: if (!(dp & 0x800)) dispreg = (uae_s32)(uae_s16)(dispreg);
463: dispreg <<= (dp >> 9) & 3;
464:
465: if (dp & 0x100) {
466: uae_s32 outer = 0, disp = 0;
467: uae_s32 base = addr;
468: TCHAR name[10];
469: _stprintf (name, _T("PC, "));
470: if (dp & 0x80) { base = 0; name[0] = 0; }
471: if (dp & 0x40) dispreg = 0;
472: if ((dp & 0x30) == 0x20) { disp = (uae_s32)(uae_s16)get_iword_debug (pc); pc += 2; }
473: if ((dp & 0x30) == 0x30) { disp = get_ilong_debug (pc); pc += 4; }
474: base += disp;
475:
476: if ((dp & 0x3) == 0x2) { outer = (uae_s32)(uae_s16)get_iword_debug (pc); pc += 2; }
477: if ((dp & 0x3) == 0x3) { outer = get_ilong_debug (pc); pc += 4; }
478:
479: if (!(dp & 4)) base += dispreg;
480: if ((dp & 3) && !safemode) base = get_ilong_debug (base);
481: if (dp & 4) base += dispreg;
482:
483: addr = base + outer;
484: _stprintf (buffer, _T("(%s%c%d.%c*%d+%d)+%d == $%08x"), name,
485: dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W',
486: 1 << ((dp >> 9) & 3),
487: disp, outer, addr);
488: } else {
489: addr += (uae_s32)((uae_s8)disp8) + dispreg;
490: _stprintf (buffer, _T("(PC, %c%d.%c*%d, $%02x) == $%08x"), dp & 0x8000 ? 'A' : 'D',
491: (int)r, dp & 0x800 ? 'L' : 'W', 1 << ((dp >> 9) & 3),
492: disp8, addr);
493: }
494: break;
495: case absw:
496: addr = (uae_s32)(uae_s16)get_iword_debug (pc);
497: _stprintf (buffer, _T("$%08x"), addr);
498: pc += 2;
499: break;
500: case absl:
501: addr = get_ilong_debug (pc);
502: _stprintf (buffer, _T("$%08x"), addr);
503: pc += 4;
504: break;
505: case imm:
506: switch (size){
507: case sz_byte:
508: _stprintf (buffer, _T("#$%02x"), (get_iword_debug (pc) & 0xff));
509: pc += 2;
510: break;
511: case sz_word:
512: _stprintf (buffer, _T("#$%04x"), (get_iword_debug (pc) & 0xffff));
513: pc += 2;
514: break;
515: case sz_long:
516: _stprintf(buffer, _T("#$%08x"), (get_ilong_debug(pc)));
517: pc += 4;
518: break;
519: case sz_single:
520: {
521: fptype fp;
522: to_single(&fp, get_ilong_debug(pc));
523: _stprintf(buffer, _T("#%s"), fp_print(&fp));
524: pc += 4;
525: }
526: break;
527: case sz_double:
528: {
529: fptype fp;
530: to_double(&fp, get_ilong_debug(pc), get_ilong_debug(pc + 4));
531: _stprintf(buffer, _T("#%s"), fp_print(&fp));
532: pc += 8;
533: }
534: break;
535: case sz_extended:
536: {
537: fptype fp;
538: to_exten(&fp, get_ilong_debug(pc), get_ilong_debug(pc + 4), get_ilong_debug(pc + 8));
539: _stprintf(buffer, _T("#%s"), fp_print(&fp));
540: pc += 12;
541: break;
542: }
543: case sz_packed:
544: _stprintf(buffer, _T("#$%08x%08x%08x"), get_ilong_debug(pc), get_ilong_debug(pc + 4), get_ilong_debug(pc + 8));
545: pc += 12;
546: break;
547: default:
548: break;
549: }
550: break;
551: case imm0:
552: offset = (uae_s32)(uae_s8)get_iword_debug (pc);
553: _stprintf (buffer, _T("#$%02x"), (uae_u32)(offset & 0xff));
554: addr = pc + 2 + offset;
555: pc += 2;
556: break;
557: case imm1:
558: offset = (uae_s32)(uae_s16)get_iword_debug (pc);
559: buffer[0] = 0;
560: _stprintf (buffer, _T("#$%04x"), (uae_u32)(offset & 0xffff));
561: addr = pc + offset;
562: pc += 2;
563: break;
564: case imm2:
565: offset = (uae_s32)get_ilong_debug (pc);
566: _stprintf (buffer, _T("#$%08x"), (uae_u32)offset);
567: addr = pc + offset;
568: pc += 4;
569: break;
570: case immi:
571: offset = (uae_s32)(uae_s8)(reg & 0xff);
572: _stprintf (buffer, _T("#$%08x"), (uae_u32)offset);
573: addr = pc + offset;
574: break;
575: default:
576: break;
577: }
578: if (buf == 0)
579: f_out (f, _T("%s"), buffer);
580: else
581: _tcscat (buf, buffer);
582: if (eaddr)
583: *eaddr = addr;
584: return pc;
585: }
586:
587: static void activate_trace(void)
588: {
589: unset_special (SPCFLAG_TRACE);
590: set_special (SPCFLAG_DOTRACE);
591: }
592:
593: void check_t0_trace(void)
594: {
595: if (regs.t0 && currprefs.cpu_model >= 68020) {
596: unset_special (SPCFLAG_TRACE);
597: set_special (SPCFLAG_DOTRACE);
598: }
599: }
600:
601: void REGPARAM2 MakeSR (void)
602: {
603: regs.sr = ((regs.t1 << 15) | (regs.t0 << 14)
604: | (regs.s << 13) | (regs.m << 12) | (regs.intmask << 8)
605: | (GET_XFLG () << 4) | (GET_NFLG () << 3)
606: | (GET_ZFLG () << 2) | (GET_VFLG () << 1)
607: | GET_CFLG ());
608: }
609:
610: static void MakeFromSR_x(int t0trace)
611: {
612: int oldm = regs.m;
613: int olds = regs.s;
614: int oldt0 = regs.t0;
615: int oldt1 = regs.t1;
616:
617: SET_XFLG ((regs.sr >> 4) & 1);
618: SET_NFLG ((regs.sr >> 3) & 1);
619: SET_ZFLG ((regs.sr >> 2) & 1);
620: SET_VFLG ((regs.sr >> 1) & 1);
621: SET_CFLG (regs.sr & 1);
622: if (regs.t1 == ((regs.sr >> 15) & 1) &&
623: regs.t0 == ((regs.sr >> 14) & 1) &&
624: regs.s == ((regs.sr >> 13) & 1) &&
625: regs.m == ((regs.sr >> 12) & 1) &&
626: regs.intmask == ((regs.sr >> 8) & 7))
627: return;
628: regs.t1 = (regs.sr >> 15) & 1;
629: regs.t0 = (regs.sr >> 14) & 1;
630: regs.s = (regs.sr >> 13) & 1;
631: regs.m = (regs.sr >> 12) & 1;
632: regs.intmask = (regs.sr >> 8) & 7;
633: if (currprefs.cpu_model >= 68020) {
634: if (olds != regs.s) {
635: if (olds) {
636: if (oldm)
637: regs.msp = m68k_areg (regs, 7);
638: else
639: regs.isp = m68k_areg (regs, 7);
640: m68k_areg (regs, 7) = regs.usp;
641: } else {
642: regs.usp = m68k_areg (regs, 7);
643: m68k_areg (regs, 7) = regs.m ? regs.msp : regs.isp;
644: }
645: } else if (olds && oldm != regs.m) {
646: if (oldm) {
647: regs.msp = m68k_areg (regs, 7);
648: m68k_areg (regs, 7) = regs.isp;
649: } else {
650: regs.isp = m68k_areg (regs, 7);
651: m68k_areg (regs, 7) = regs.msp;
652: }
653: }
654: } else {
655: regs.t0 = regs.m = 0;
656: if (olds != regs.s) {
657: if (olds) {
658: regs.isp = m68k_areg (regs, 7);
659: m68k_areg (regs, 7) = regs.usp;
660: } else {
661: regs.usp = m68k_areg (regs, 7);
662: m68k_areg (regs, 7) = regs.isp;
663: }
664: }
665: }
666: if (currprefs.mmu_model)
667: mmu_set_super (regs.s != 0);
668:
669: doint ();
670: if (regs.t1 || regs.t0) {
671: set_special (SPCFLAG_TRACE);
672: } else {
673: /* Keep SPCFLAG_DOTRACE, we still want a trace exception for
674: SR-modifying instructions (including STOP). */
675: unset_special (SPCFLAG_TRACE);
676: }
677: // Stop SR-modification does not generate T0
678: // If this SR modification set Tx bit, no trace until next instruction.
679: if ((oldt0 && t0trace && currprefs.cpu_model >= 68020) || oldt1) {
680: // Always trace if Tx bits were already set, even if this SR modification cleared them.
681: activate_trace();
682: }
683: }
684:
685: void REGPARAM2 MakeFromSR_T0(void)
686: {
687: MakeFromSR_x(1);
688: }
689: void REGPARAM2 MakeFromSR(void)
690: {
691: MakeFromSR_x(0);
692:
693: }
694:
695: static void exception_check_trace (int nr)
696: {
697: unset_special (SPCFLAG_TRACE | SPCFLAG_DOTRACE);
698: if (regs.t1 && !regs.t0) {
699: /* trace stays pending if exception is div by zero, chk,
700: * trapv or trap #x
701: */
702: if (nr == 5 || nr == 6 || nr == 7 || (nr >= 32 && nr <= 47))
703: set_special (SPCFLAG_DOTRACE);
704: }
705: regs.t1 = regs.t0 = 0;
706: }
707:
708: static void exception_debug (int nr)
709: {
710: #ifdef DEBUGGER
711: if (!exception_debugging)
712: return;
713: printf ("Exception %d, PC=%08X\n", nr, M68K_GETPC);
714: DebugUI();
715: #endif
716: }
717:
718: void cpu_halt (int e)
719: {
720: write_log("HALT!");
721: DebugUI();
722: }
723:
724: static void Exception_build_stack_frame (uae_u32 oldpc, uae_u32 currpc, uae_u32 ssw, int nr, int format)
725: {
726: int i;
727:
728: #if 0
729: if (nr < 24 || nr > 31) { // do not print debugging for interrupts
730: write_log(_T("Building exception stack frame (format %X)\n"), format);
731: }
732: #endif
733:
734: switch (format) {
735: case 0x0: // four word stack frame
736: case 0x1: // throwaway four word stack frame
737: break;
738: case 0x2: // six word stack frame
739: m68k_areg (regs, 7) -= 4;
740: x_put_long (m68k_areg (regs, 7), oldpc);
741: break;
742: case 0x3: // floating point post-instruction stack frame (68040)
743: m68k_areg (regs, 7) -= 4;
744: x_put_long (m68k_areg (regs, 7), regs.fp_ea);
745: break;
746: case 0x7: // access error stack frame (68040)
747:
748: for (i = 3; i >= 0; i--) {
749: // WB1D/PD0,PD1,PD2,PD3
750: m68k_areg (regs, 7) -= 4;
751: x_put_long (m68k_areg (regs, 7), mmu040_move16[i]);
752: }
753:
754: m68k_areg (regs, 7) -= 4;
755: x_put_long (m68k_areg (regs, 7), 0); // WB1A
756: m68k_areg (regs, 7) -= 4;
757: x_put_long (m68k_areg (regs, 7), 0); // WB2D
758: m68k_areg (regs, 7) -= 4;
759: x_put_long (m68k_areg (regs, 7), regs.wb2_address); // WB2A
760: m68k_areg (regs, 7) -= 4;
761: x_put_long (m68k_areg (regs, 7), regs.wb3_data); // WB3D
762: m68k_areg (regs, 7) -= 4;
763: x_put_long (m68k_areg (regs, 7), regs.mmu_fault_addr); // WB3A
764:
765: m68k_areg (regs, 7) -= 4;
766: x_put_long (m68k_areg (regs, 7), regs.mmu_fault_addr); // FA
767:
768: m68k_areg (regs, 7) -= 2;
769: x_put_word (m68k_areg (regs, 7), 0);
770: m68k_areg (regs, 7) -= 2;
771: x_put_word (m68k_areg (regs, 7), regs.wb2_status);
772: regs.wb2_status = 0;
773: m68k_areg (regs, 7) -= 2;
774: x_put_word (m68k_areg (regs, 7), regs.wb3_status);
775: regs.wb3_status = 0;
776:
777: m68k_areg (regs, 7) -= 2;
778: x_put_word (m68k_areg (regs, 7), ssw);
779: m68k_areg (regs, 7) -= 4;
780: x_put_long (m68k_areg (regs, 7), regs.mmu_effective_addr);
781: break;
782: case 0x9: // coprocessor mid-instruction stack frame (68020, 68030)
783: m68k_areg (regs, 7) -= 4;
784: x_put_long (m68k_areg (regs, 7), regs.fp_ea);
785: m68k_areg (regs, 7) -= 4;
786: x_put_long (m68k_areg (regs, 7), regs.fp_opword);
787: m68k_areg (regs, 7) -= 4;
788: x_put_long (m68k_areg (regs, 7), oldpc);
789: break;
790: case 0x8: // bus and address error stack frame (68010)
791: write_log(_T("Exception stack frame format %X not implemented\n"), format);
792: return;
793: case 0x4: // floating point unimplemented stack frame (68LC040, 68EC040)
794: // or 68060 bus access fault stack frame
795: m68k_areg (regs, 7) -= 4;
796: x_put_long (m68k_areg (regs, 7), ssw);
797: m68k_areg (regs, 7) -= 4;
798: x_put_long (m68k_areg (regs, 7), oldpc);
799: break;
800: case 0xB: // long bus cycle fault stack frame (68020, 68030)
801: // We always use B frame because it is easier to emulate,
802: // our PC always points at start of instruction but A frame assumes
803: // it is + 2 and handling this properly is not easy.
804: // Store state information to internal register space
805: for (i = 0; i < mmu030_idx + 1; i++) {
806: m68k_areg (regs, 7) -= 4;
807: x_put_long (m68k_areg (regs, 7), mmu030_ad[i].val);
808: }
809: while (i < 9) {
810: uae_u32 v = 0;
811: m68k_areg (regs, 7) -= 4;
812: // mmu030_idx is always small enough if instruction is FMOVEM.
813: if (mmu030_state[1] & MMU030_STATEFLAG1_FMOVEM) {
814: if (i == 7)
815: v = mmu030_fmovem_store[0];
816: else if (i == 8)
817: v = mmu030_fmovem_store[1];
818: }
819: x_put_long (m68k_areg (regs, 7), v);
820: i++;
821: }
822: // version & internal information (We store index here)
823: m68k_areg (regs, 7) -= 2;
824: x_put_word (m68k_areg (regs, 7), mmu030_idx);
825: // 3* internal registers
826: m68k_areg (regs, 7) -= 2;
827: x_put_word (m68k_areg (regs, 7), mmu030_state[2]);
828: m68k_areg (regs, 7) -= 2;
829: x_put_word (m68k_areg (regs, 7), mmu030_state[1]);
830: m68k_areg (regs, 7) -= 2;
831: x_put_word (m68k_areg (regs, 7), mmu030_state[0]);
832: // data input buffer = fault address
833: m68k_areg (regs, 7) -= 4;
834: x_put_long (m68k_areg (regs, 7), regs.mmu_fault_addr);
835: // 2xinternal
836: m68k_areg (regs, 7) -= 2;
837: x_put_word (m68k_areg (regs, 7), 0);
838: m68k_areg (regs, 7) -= 2;
839: x_put_word (m68k_areg (regs, 7), 0);
840: // stage b address
841: m68k_areg (regs, 7) -= 4;
842: x_put_long (m68k_areg (regs, 7), mm030_stageb_address);
843: // 2xinternal
844: m68k_areg (regs, 7) -= 4;
845: x_put_long (m68k_areg (regs, 7), mmu030_disp_store[1]);
846: /* fall through */
847: case 0xA: // short bus cycle fault stack frame (68020, 68030)
848: m68k_areg (regs, 7) -= 4;
849: x_put_long (m68k_areg (regs, 7), mmu030_disp_store[0]);
850: m68k_areg (regs, 7) -= 4;
851: // Data output buffer = value that was going to be written
852: x_put_long (m68k_areg (regs, 7), (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) ? mmu030_data_buffer : mmu030_ad[mmu030_idx].val);
853: m68k_areg (regs, 7) -= 4;
854: x_put_long (m68k_areg (regs, 7), mmu030_opcode); // Internal register (opcode storage)
855: m68k_areg (regs, 7) -= 4;
856: x_put_long (m68k_areg (regs, 7), regs.mmu_fault_addr); // data cycle fault address
857: m68k_areg (regs, 7) -= 2;
858: x_put_word (m68k_areg (regs, 7), 0); // Instr. pipe stage B
859: m68k_areg (regs, 7) -= 2;
860: x_put_word (m68k_areg (regs, 7), 0); // Instr. pipe stage C
861: m68k_areg (regs, 7) -= 2;
862: x_put_word (m68k_areg (regs, 7), ssw);
863: m68k_areg (regs, 7) -= 2;
864: x_put_word (m68k_areg (regs, 7), 0); // Internal register
865: break;
866: default:
867: write_log(_T("Unknown exception stack frame format: %X\n"), format);
868: return;
869: }
870: m68k_areg (regs, 7) -= 2;
871: x_put_word (m68k_areg (regs, 7), (format << 12) | (nr * 4));
872: m68k_areg (regs, 7) -= 4;
873: x_put_long (m68k_areg (regs, 7), currpc);
874: m68k_areg (regs, 7) -= 2;
875: x_put_word (m68k_areg (regs, 7), regs.sr);
876: }
877:
878: // 68030 MMU
879: static void Exception_mmu030 (int nr, uaecptr oldpc)
880: {
881: uae_u32 currpc = m68k_getpc (), newpc;
882:
883: exception_debug (nr);
884: MakeSR ();
885:
886: if (!regs.s) {
887: regs.usp = m68k_areg (regs, 7);
888: m68k_areg(regs, 7) = regs.m ? regs.msp : regs.isp;
889: regs.s = 1;
890: mmu_set_super (1);
891: }
892:
893: #if 0
894: if (nr < 24 || nr > 31) { // do not print debugging for interrupts
895: write_log (_T("Exception_mmu030: Exception %i: %08x %08x %08x\n"),
896: nr, currpc, oldpc, regs.mmu_fault_addr);
897: }
898: #endif
899:
900: #if 0
901: write_log (_T("Exception %d -> %08x\n", nr, newpc));
902: #endif
903:
904:
905: newpc = x_get_long (regs.vbr + 4 * nr);
906:
907: if (regs.m && nr >= 24 && nr < 32) { /* M + Interrupt */
908: Exception_build_stack_frame(oldpc, currpc, regs.mmu_ssw, nr, 0x0);
909: MakeSR(); /* this sets supervisor bit in status reg */
910: regs.m = 0; /* clear the M bit (but frame 0x1 uses sr with M bit set) */
911: regs.msp = m68k_areg (regs, 7);
912: m68k_areg (regs, 7) = regs.isp;
913: Exception_build_stack_frame (oldpc, currpc, regs.mmu_ssw, nr, 0x1);
914: } else if (nr ==5 || nr == 6 || nr == 7 || nr == 9 || nr == 56) {
915: Exception_build_stack_frame (oldpc, currpc, regs.mmu_ssw, nr, 0x2);
916: } else if (nr == 2) {
917: Exception_build_stack_frame (oldpc, currpc, regs.mmu_ssw, nr, 0xB);
918: } else if (nr == 3) {
919: regs.mmu_fault_addr = last_fault_for_exception_3;
920: mmu030_state[0] = mmu030_state[1] = 0;
921: mmu030_data_buffer = 0;
922: Exception_build_stack_frame (last_fault_for_exception_3, currpc, MMU030_SSW_RW | MMU030_SSW_SIZE_W | (regs.s ? 6 : 2), nr, 0xA);
923: } else if (nr >= 48 && nr < 55) {
924: if (regs.fpu_exp_pre) {
925: Exception_build_stack_frame(oldpc, regs.instruction_pc, 0, nr, 0x0);
926: } else { /* mid-instruction */
927: Exception_build_stack_frame(regs.fpiar, currpc, 0, nr, 0x9);
928: }
929: } else {
930: Exception_build_stack_frame (oldpc, currpc, regs.mmu_ssw, nr, 0x0);
931: }
932:
933: if (newpc & 1) {
934: if (nr == 2 || nr == 3)
935: cpu_halt (2);
936: else
937: exception3_read(regs.ir, newpc);
938: return;
939: }
940: m68k_setpci (newpc);
941: exception_check_trace (nr);
942: }
943:
944:
945: // 68040 MMU
946: static void Exception_mmu (int nr, uaecptr oldpc)
947: {
948: uae_u32 currpc = m68k_getpc (), newpc;
949:
950: exception_debug (nr);
951: MakeSR ();
952:
953: if (!regs.s) {
954: regs.usp = m68k_areg (regs, 7);
955: if (currprefs.cpu_model >= 68020 && currprefs.cpu_model < 68060) {
956: m68k_areg (regs, 7) = regs.m ? regs.msp : regs.isp;
957: } else {
958: m68k_areg (regs, 7) = regs.isp;
959: }
960: regs.s = 1;
961: mmu_set_super (1);
962: }
963:
964: newpc = x_get_long (regs.vbr + 4 * nr);
965: #if 0
966: write_log (_T("Exception %d: %08x -> %08x\n"), nr, currpc, newpc);
967: #endif
968:
969: if (nr == 2) { // bus error
970: //write_log (_T("Exception_mmu %08x %08x %08x\n"), currpc, oldpc, regs.mmu_fault_addr);
971: if (currprefs.mmu_model == 68040)
972: Exception_build_stack_frame(oldpc, currpc, regs.mmu_ssw, nr, 0x7);
973: else
974: Exception_build_stack_frame(regs.mmu_fault_addr, currpc, regs.mmu_fslw, nr, 0x4);
975: } else if (nr == 3) { // address error
976: Exception_build_stack_frame(last_fault_for_exception_3, currpc, 0, nr, 0x2);
977: write_log (_T("Exception %d (%x) at %x!\n"), nr, last_fault_for_exception_3, currpc);
978: } else if (nr == 5 || nr == 6 || nr == 7 || nr == 9) {
979: Exception_build_stack_frame(oldpc, currpc, regs.mmu_ssw, nr, 0x2);
980: } else if (regs.m && nr >= 24 && nr < 32) { /* M + Interrupt */
981: Exception_build_stack_frame(oldpc, currpc, regs.mmu_ssw, nr, 0x0);
982: MakeSR(); /* this sets supervisor bit in status reg */
983: regs.m = 0; /* clear the M bit (but frame 0x1 uses sr with M bit set) */
984: regs.msp = m68k_areg (regs, 7);
985: m68k_areg (regs, 7) = regs.isp;
986: Exception_build_stack_frame (oldpc, currpc, regs.mmu_ssw, nr, 0x1);
987: } else if (nr == 60 || nr == 61) {
988: Exception_build_stack_frame(oldpc, regs.instruction_pc, regs.mmu_ssw, nr, 0x0);
989: } else if (nr >= 48 && nr <= 55) {
990: if (regs.fpu_exp_pre) {
991: if (currprefs.cpu_model == 68060 && nr == 55 && regs.fp_unimp_pend == 2) { // packed decimal real
992: Exception_build_stack_frame(regs.fp_ea, regs.instruction_pc, 0, nr, 0x2);
993: } else {
994: Exception_build_stack_frame(oldpc, regs.instruction_pc, 0, nr, 0x0);
995: }
996: } else { /* post-instruction */
997: if (currprefs.cpu_model == 68060 && nr == 55 && regs.fp_unimp_pend == 2) { // packed decimal real
998: Exception_build_stack_frame(regs.fp_ea, currpc, 0, nr, 0x2);
999: } else {
1000: Exception_build_stack_frame(oldpc, currpc, 0, nr, 0x3);
1001: }
1002: }
1003: } else if (nr == 11 && regs.fp_unimp_ins) {
1004: regs.fp_unimp_ins = false;
1005: if ((currprefs.cpu_model == 68060 && (currprefs.fpu_model == 0 || (regs.pcr & 2))) ||
1006: (currprefs.cpu_model == 68040 && currprefs.fpu_model == 0)) {
1007: Exception_build_stack_frame(regs.fp_ea, currpc, regs.instruction_pc, nr, 0x4);
1008: } else {
1009: Exception_build_stack_frame(regs.fp_ea, currpc, regs.mmu_ssw, nr, 0x2);
1010: }
1011: } else {
1012: Exception_build_stack_frame(oldpc, currpc, regs.mmu_ssw, nr, 0x0);
1013: }
1014:
1015: if (newpc & 1) {
1016: if (nr == 2 || nr == 3)
1017: cpu_halt (2);
1018: else
1019: exception3_read (regs.ir, newpc);
1020: return;
1021: }
1022: m68k_setpci (newpc);
1023: exception_check_trace (nr);
1024: }
1025:
1026:
1027: /* Handle exceptions. */
1028: static void ExceptionX (int nr, uaecptr address)
1029: {
1030: if (currprefs.cpu_model == 68030)
1031: Exception_mmu030 (nr, m68k_getpc ());
1032: else
1033: Exception_mmu (nr, m68k_getpc ());
1034: }
1035:
1036: void REGPARAM2 Exception_cpu(int nr)
1037: {
1038: bool t0 = currprefs.cpu_model >= 68020 && regs.t0;
1039: ExceptionX (nr, -1);
1040: // check T0 trace
1041: if (t0) {
1042: activate_trace();
1043: }
1044: }
1045: void REGPARAM2 Exception (int nr)
1046: {
1047: ExceptionX (nr, -1);
1048: }
1049: void REGPARAM2 ExceptionL (int nr, uaecptr address)
1050: {
1051: ExceptionX (nr, address);
1052: }
1053:
1054: static void do_interrupt (int nr, int Pending)
1055: {
1056: regs.stopped = 0;
1057: unset_special (SPCFLAG_STOP);
1058: assert (nr < 8 && nr >= 0);
1059:
1060: /* On Hatari, only video ints are using SPCFLAG_INT (see m68000.c) */
1061: Exception (nr + 24);
1062:
1063: regs.intmask = nr;
1064: doint ();
1065:
1066: set_special (SPCFLAG_INT);
1067: }
1068:
1069:
1070: void m68k_reset (int hardreset)
1071: {
1072: regs.spcflags &= (SPCFLAG_MODE_CHANGE | SPCFLAG_BRK);
1073: regs.ipl = regs.ipl_pin = 0;
1074: regs.s = 1;
1075: regs.m = 0;
1076: regs.stopped = 0;
1077: regs.t1 = 0;
1078: regs.t0 = 0;
1079: SET_ZFLG (0);
1080: SET_XFLG (0);
1081: SET_CFLG (0);
1082: SET_VFLG (0);
1083: SET_NFLG (0);
1084: regs.intmask = 7;
1085: regs.vbr = regs.sfc = regs.dfc = 0;
1086: regs.irc = 0xffff;
1087:
1088: m68k_areg (regs, 7) = get_long (0);
1089: m68k_setpc (get_long (4));
1090:
1091: fpu_reset ();
1092:
1093: regs.caar = regs.cacr = 0;
1094: regs.itt0 = regs.itt1 = regs.dtt0 = regs.dtt1 = 0;
1095: regs.tcr = regs.mmusr = regs.urp = regs.srp = regs.buscr = 0;
1096:
1097: mmufixup[0].reg = -1;
1098: mmufixup[1].reg = -1;
1099: if (currprefs.mmu_model) {
1100: if (currprefs.cpu_model >= 68040) {
1101: mmu_reset ();
1102: mmu_set_tc (regs.tcr);
1103: mmu_set_super (regs.s != 0);
1104: }
1105: else {
1106: mmu030_reset(hardreset);
1107: }
1108: }
1109:
1110: regs.pcr = 0;
1111: }
1112:
1113: void REGPARAM2 op_unimpl (uae_u16 opcode)
1114: {
1115: static int warned;
1116: if (warned < 20) {
1117: write_log (_T("68060 unimplemented opcode %04X, PC=%08x\n"), opcode, regs.instruction_pc);
1118: warned++;
1119: }
1120: ExceptionL (61, regs.instruction_pc);
1121: }
1122:
1123: uae_u32 REGPARAM2 op_illg (uae_u32 opcode)
1124: {
1125: uaecptr pc = m68k_getpc ();
1126: static int warned;
1127:
1128: if (warned < 20) {
1129: write_log ("Illegal instruction: %04x at %08X\n", opcode, pc);
1130: warned++;
1131: }
1132:
1133: if ((opcode & 0xF000)==0xA000)
1134: Exception (10);
1135: else
1136: if ((opcode & 0xF000)==0xF000)
1137: Exception (11);
1138: else
1139: Exception (4);
1140: return 4;
1141: }
1142:
1143: #ifdef CPUEMU_0
1144:
1145: // 68030 (68851) MMU instructions only
1146: bool mmu_op30 (uaecptr pc, uae_u32 opcode, uae_u16 extra, uaecptr extraa)
1147: {
1148: bool fline = false;
1149:
1150: if (extra & 0x8000) {
1151: fline = mmu_op30_ptest (pc, opcode, extra, extraa);
1152: } else if ((extra&0xE000)==0x2000 && (extra & 0x1C00)) {
1153: fline = mmu_op30_pflush (pc, opcode, extra, extraa);
1154: } else if ((extra&0xE000)==0x2000 && !(extra & 0x1C00)) {
1155: fline = mmu_op30_pload (pc, opcode, extra, extraa);
1156: } else {
1157: fline = mmu_op30_pmove (pc, opcode, extra, extraa);
1158: }
1159:
1160: if (fline) {
1161: m68k_setpc(pc);
1162: op_illg(opcode);
1163: }
1164: return fline;
1165: }
1166:
1167: void mmu_op (uae_u32 opcode, uae_u32 extra)
1168: {
1169: if (currprefs.cpu_model) {
1170: mmu_op_real (opcode, extra);
1171: return;
1172: }
1173: #if MMUOP_DEBUG > 1
1174: write_log ("mmu_op %04X PC=%08X\n", opcode, m68k_getpc ());
1175: #endif
1176: if ((opcode & 0xFE0) == 0x0500) {
1177: /* PFLUSH */
1178: regs.mmusr = 0;
1179: #if MMUOP_DEBUG > 0
1180: write_log ("PFLUSH\n");
1181: #endif
1182: return;
1183: } else if ((opcode & 0x0FD8) == 0x548) {
1184: if (currprefs.cpu_model < 68060) { /* PTEST not in 68060 */
1185: /* PTEST */
1186: #if MMUOP_DEBUG > 0
1187: write_log ("PTEST\n");
1188: #endif
1189: return;
1190: }
1191: }
1192: #if MMUOP_DEBUG > 0
1193: write_log ("Unknown MMU OP %04X\n", opcode);
1194: #endif
1195: m68k_setpc (m68k_getpc () - 2);
1196: op_illg (opcode);
1197: }
1198:
1199: #endif
1200:
1201: static void do_trace (void)
1202: {
1203: if (regs.t0 && currprefs.cpu_model >= 68020) {
1204: // this is obsolete
1205: return;
1206: }
1207: if (regs.t1) {
1208: activate_trace();
1209: }
1210: }
1211:
1212: void doint (void)
1213: {
1214: if (currprefs.cpu_compatible)
1215: set_special (SPCFLAG_INT);
1216: else
1217: set_special (SPCFLAG_DOINT);
1218: }
1219:
1220: #define IDLETIME (currprefs.cpu_idle * sleep_resolution / 700)
1221:
1222: /*
1223: * Handle special flags
1224: */
1225:
1226: static int vpos = 0;
1227:
1228: static int do_specialties (int cycles)
1229: {
1230: if (regs.spcflags & SPCFLAG_DOTRACE)
1231: Exception (9);
1232:
1233: /* Handle the STOP instruction */
1234: if ( regs.spcflags & SPCFLAG_STOP ) {
1235: while (regs.spcflags & SPCFLAG_STOP) {
1236:
1237: /* Take care of quit event if needed */
1238: if (regs.spcflags & SPCFLAG_BRK)
1239: return 1;
1240:
1241: M68000_AddCycles(cpu_cycles);
1242:
1243: /* It is possible one or more ints happen at the same time */
1244: /* We must process them during the same cpu cycle until the special INT flag is set */
1245: while (PendingInterrupt.time <=0 && PendingInterrupt.pFunction) {
1246: /* 1st, we call the interrupt handler */
1247: CALL_VAR(PendingInterrupt.pFunction);
1248:
1249: if ((regs.spcflags & (SPCFLAG_BRK | SPCFLAG_MODE_CHANGE))) {
1250: unset_special (SPCFLAG_BRK | SPCFLAG_MODE_CHANGE);
1251: // SPCFLAG_BRK breaks STOP condition, need to prefetch
1252: m68k_resumestopped ();
1253: return 1;
1254: }
1255:
1256: if (currprefs.cpu_idle && ((regs.spcflags & SPCFLAG_STOP)) == SPCFLAG_STOP) {
1257: /* sleep 1ms if STOP-instruction is executed */
1258: if (1) {
1259: static int sleepcnt, lvpos;
1260: if (vpos != lvpos) {
1261: sleepcnt--;
1262: lvpos = vpos;
1263: if (sleepcnt < 0) {
1264: /*sleepcnt = IDLETIME / 2; */ /* Laurent : badly removed for now */
1265: host_sleep_ms(1);
1266: }
1267: }
1268: }
1269: }
1270: }
1271: }
1272: }
1273:
1274: if (regs.spcflags & SPCFLAG_TRACE)
1275: do_trace ();
1276:
1277: if (regs.spcflags & SPCFLAG_DOINT) {
1278: unset_special (SPCFLAG_DOINT);
1279: set_special (SPCFLAG_INT);
1280: }
1281:
1282: if (regs.spcflags & SPCFLAG_DEBUGGER)
1283: DebugCpu_Check();
1284:
1285: if ((regs.spcflags & (SPCFLAG_BRK | SPCFLAG_MODE_CHANGE))) {
1286: unset_special(SPCFLAG_MODE_CHANGE);
1287: return 1;
1288: }
1289:
1290: return 0;
1291: }
1292:
1293: #ifndef CPUEMU_0
1294:
1295: #else
1296:
1297: static int lastRegsS = 0;
1298:
1299: // Previous MMU 68030
1300: static void m68k_run_mmu030 (void)
1301: {
1302: uae_u16 opcode;
1303: uaecptr pc;
1304: struct flag_struct f;
1305: f.cznv = 0;
1306: f.x = 0;
1307: int intr = 0;
1308: int lastintr = 0;
1309: mmu030_opcode_stageb = -1;
1310: retry:
1311: TRY (prb) {
1312: for (;;) {
1313: int cnt;
1314: insretry:
1315: pc = regs.instruction_pc = m68k_getpc ();
1316: f.cznv = regflags.cznv;
1317: f.x = regflags.x;
1318:
1319: mmu030_state[0] = mmu030_state[1] = mmu030_state[2] = 0;
1320: mmu030_opcode = -1;
1321: if (mmu030_opcode_stageb < 0) {
1322: opcode = get_iword_mmu030 (0);
1323: } else {
1324: opcode = mmu030_opcode_stageb;
1325: mmu030_opcode_stageb = -1;
1326: }
1327:
1328: mmu030_opcode = opcode;
1329: mmu030_ad[0].done = false;
1330:
1331: Uint64 beforeCycles = nCyclesMainCounter;
1332: cnt = 50;
1333: for (;;) {
1334: opcode = mmu030_opcode;
1335: mmu030_idx = 0;
1336: mmu030_retry = false;
1337: cpu_cycles = (*cpufunctbl[opcode])(opcode);
1338: cnt--; // so that we don't get in infinite loop if things go horribly wrong
1339: if (!mmu030_retry)
1340: break;
1341: if (cnt < 0) {
1342: cpu_halt (9);
1343: break;
1344: }
1345: if (mmu030_retry && mmu030_opcode == -1)
1346: goto insretry; // urgh
1347: }
1348:
1349: mmu030_opcode = -1;
1350:
1351: M68000_AddCycles(cpu_cycles);
1352: cpu_cycles = nCyclesMainCounter - beforeCycles;
1353:
1354: DSP_Run(cpu_cycles);
1355: i860_Run(cpu_cycles);
1356:
1357: /* We can have several interrupts at the same time before the next CPU instruction */
1358: /* We must check for pending interrupt and call do_specialties_interrupt() only */
1359: /* if the cpu is not in the STOP state. Else, the int could be acknowledged now */
1360: /* and prevent exiting the STOP state when calling do_specialties() after. */
1361: /* For performance, we first test PendingInterruptCount, then regs.spcflags */
1362: while ( ( PendingInterrupt.time <= 0 ) && ( PendingInterrupt.pFunction ) && ( ( regs.spcflags & SPCFLAG_STOP ) == 0 ) ) {
1363: CALL_VAR(PendingInterrupt.pFunction); /* call the interrupt handler */
1364: }
1365:
1366: /* Previous: for now we poll the interrupt pins with every instruction.
1367: * TODO: only do this when an actual interrupt is active to not
1368: * unneccessarily slow down emulation.
1369: */
1370: intr = intlev ();
1371: if (intr>regs.intmask || (intr==7 && intr>lastintr))
1372: do_interrupt (intr, false);
1373: lastintr = intr;
1374:
1375: if(lastRegsS != regs.s) {
1376: host_realtime(!(regs.s));
1377: lastRegsS = regs.s;
1378: }
1379:
1380: if (regs.spcflags & ~SPCFLAG_INT) {
1381: if (do_specialties (cpu_cycles))
1382: return;
1383: }
1384: }
1385: } CATCH (prb) {
1386:
1387: regflags.cznv = f.cznv;
1388: regflags.x = f.x;
1389:
1390: m68k_setpci (regs.instruction_pc);
1391:
1392: if (mmufixup[0].reg >= 0) {
1393: m68k_areg (regs, mmufixup[0].reg) = mmufixup[0].value;
1394: mmufixup[0].reg = -1;
1395: }
1396: if (mmufixup[1].reg >= 0) {
1397: m68k_areg (regs, mmufixup[1].reg) = mmufixup[1].value;
1398: mmufixup[1].reg = -1;
1399: }
1400:
1401: TRY (prb2) {
1402: Exception (prb);
1403: } CATCH (prb2) {
1404: write_log("[FATAL] double fault\n");
1405: m68k_reset (1); // auto-reset CPU
1406: //cpu_halt (1);
1407: return;
1408: } ENDTRY
1409: } ENDTRY
1410: goto retry;
1411: }
1412:
1413: /* Aranym MMU 68040 */
1414: static void m68k_run_mmu040 (void)
1415: {
1416: uae_u16 opcode;
1417: struct flag_struct f;
1418: f.cznv = 0;
1419: f.x = 0;
1420: uaecptr pc;
1421: int intr = 0;
1422: int lastintr = 0;
1423:
1424: for (;;) {
1425: TRY (prb) {
1426: for (;;) {
1427: f.cznv = regflags.cznv;
1428: f.x = regflags.x;
1429: mmu_restart = true;
1430: pc = regs.instruction_pc = m68k_getpc ();
1431:
1432: Uint64 beforeCycles = nCyclesMainCounter;
1433: mmu_opcode = -1;
1434: mmu_opcode = opcode = x_prefetch (0);
1435: cpu_cycles = (*cpufunctbl[opcode])(opcode);
1436: M68000_AddCycles(cpu_cycles);
1437:
1438: cpu_cycles = nCyclesMainCounter - beforeCycles;
1439:
1440: DSP_Run(cpu_cycles);
1441: i860_Run(cpu_cycles);
1442:
1443: /* We can have several interrupts at the same time before the next CPU instruction */
1444: /* We must check for pending interrupt and call do_specialties_interrupt() only */
1445: /* if the cpu is not in the STOP state. Else, the int could be acknowledged now */
1446: /* and prevent exiting the STOP state when calling do_specialties() after. */
1447: /* For performance, we first test PendingInterruptCount, then regs.spcflags */
1448: while ( ( PendingInterrupt.time <= 0 ) && ( PendingInterrupt.pFunction ) && ( ( regs.spcflags & SPCFLAG_STOP ) == 0 ) ) {
1449: CALL_VAR(PendingInterrupt.pFunction); /* call the interrupt handler */
1450: }
1451:
1452: /* Previous: for now we poll the interrupt pins with every instruction.
1453: * TODO: only do this when an actual interrupt is active to not
1454: * unneccessarily slow down emulation.
1455: */
1456: intr = intlev ();
1457: if (intr>regs.intmask || (intr==7 && intr>lastintr))
1458: do_interrupt (intr, false);
1459: lastintr = intr;
1460:
1461: if(lastRegsS != regs.s) {
1462: host_realtime(!(regs.s));
1463: lastRegsS = regs.s;
1464: }
1465:
1466: if (regs.spcflags & ~SPCFLAG_INT) {
1467: if (do_specialties (cpu_cycles))
1468: return;
1469: }
1470: } // end of for(;;)
1471: } CATCH (prb) {
1472:
1473: if (mmu_restart) {
1474: /* restore state if instruction restart */
1475: regflags.cznv = f.cznv;
1476: regflags.x = f.x;
1477: m68k_setpci (regs.instruction_pc);
1478: }
1479:
1480: if (mmufixup[0].reg >= 0) {
1481: m68k_areg (regs, mmufixup[0].reg) = mmufixup[0].value;
1482: mmufixup[0].reg = -1;
1483: }
1484:
1485: TRY (prb2) {
1486: Exception (prb);
1487: } CATCH (prb2) {
1488: write_log("[FATAL] double fault\n");
1489: m68k_reset (1); // auto-reset CPU
1490: //cpu_halt (1);
1491: return;
1492: } ENDTRY
1493:
1494: } ENDTRY
1495: }
1496: }
1497:
1498: #endif /* CPUEMU_0 */
1499:
1500: int in_m68k_go = 0;
1501:
1502: #if 0
1503: static void exception2_handle (uaecptr addr, uaecptr fault)
1504: {
1505: last_addr_for_exception_3 = addr;
1506: last_fault_for_exception_3 = fault;
1507: last_writeaccess_for_exception_3 = 0;
1508: last_instructionaccess_for_exception_3 = 0;
1509: Exception (2);
1510: }
1511: #endif
1512:
1513: void m68k_go (int may_quit)
1514: {
1515: int hardboot = 1;
1516:
1517: if (in_m68k_go || !may_quit) {
1518: write_log ("Bug! m68k_go is not reentrant.\n");
1519: DebugUI();
1520: }
1521:
1522: in_m68k_go++;
1523: for (;;) {
1524: void (*run_func)(void);
1525:
1526: if (regs.spcflags & SPCFLAG_BRK) {
1527: unset_special(SPCFLAG_BRK);
1528: break;
1529: }
1530:
1531: hardboot = 0;
1532:
1533: #ifdef DEBUGGER
1534: if (debugging)
1535: debug ();
1536: #endif
1537:
1538: set_x_funcs ();
1539: run_func=currprefs.cpu_model == 68040 ? m68k_run_mmu040 : m68k_run_mmu030;
1540: run_func ();
1541: }
1542: in_m68k_go--;
1543: }
1544:
1545:
1546: #if 1
1547: TCHAR* buf_out (TCHAR *buffer, int *bufsize, const TCHAR *format, ...)
1548: {
1549: va_list parms;
1550:
1551: if (buffer == NULL)
1552: {
1553: return NULL;
1554: }
1555:
1556: va_start (parms, format);
1557: vsnprintf (buffer, (*bufsize) - 1, format, parms);
1558: va_end (parms);
1559: *bufsize -= _tcslen (buffer);
1560:
1561: return buffer + _tcslen (buffer);
1562: }
1563: #endif
1564:
1565: static const TCHAR *ccnames[] =
1566: {
1567: _T("T "),_T("F "),_T("HI"),_T("LS"),_T("CC"),_T("CS"),_T("NE"),_T("EQ"),
1568: _T("VC"),_T("VS"),_T("PL"),_T("MI"),_T("GE"),_T("LT"),_T("GT"),_T("LE")
1569: };
1570: static const TCHAR *fpccnames[] =
1571: {
1572: _T("F"),
1573: _T("EQ"),
1574: _T("OGT"),
1575: _T("OGE"),
1576: _T("OLT"),
1577: _T("OLE"),
1578: _T("OGL"),
1579: _T("OR"),
1580: _T("UN"),
1581: _T("UEQ"),
1582: _T("UGT"),
1583: _T("UGE"),
1584: _T("ULT"),
1585: _T("ULE"),
1586: _T("NE"),
1587: _T("T"),
1588: _T("SF"),
1589: _T("SEQ"),
1590: _T("GT"),
1591: _T("GE"),
1592: _T("LT"),
1593: _T("LE"),
1594: _T("GL"),
1595: _T("GLE"),
1596: _T("NGLE"),
1597: _T("NGL"),
1598: _T("NLE"),
1599: _T("NLT"),
1600: _T("NGE"),
1601: _T("NGT"),
1602: _T("SNE"),
1603: _T("ST")
1604: };
1605: static const TCHAR *fpuopcodes[] =
1606: {
1607: _T("FMOVE"),
1608: _T("FINT"),
1609: _T("FSINH"),
1610: _T("FINTRZ"),
1611: _T("FSQRT"),
1612: NULL,
1613: _T("FLOGNP1"),
1614: NULL,
1615: _T("FETOXM1"),
1616: _T("FTANH"),
1617: _T("FATAN"),
1618: NULL,
1619: _T("FASIN"),
1620: _T("FATANH"),
1621: _T("FSIN"),
1622: _T("FTAN"),
1623: _T("FETOX"), // 0x10
1624: _T("FTWOTOX"),
1625: _T("FTENTOX"),
1626: NULL,
1627: _T("FLOGN"),
1628: _T("FLOG10"),
1629: _T("FLOG2"),
1630: NULL,
1631: _T("FABS"),
1632: _T("FCOSH"),
1633: _T("FNEG"),
1634: NULL,
1635: _T("FACOS"),
1636: _T("FCOS"),
1637: _T("FGETEXP"),
1638: _T("FGETMAN"),
1639: _T("FDIV"), // 0x20
1640: _T("FMOD"),
1641: _T("FADD"),
1642: _T("FMUL"),
1643: _T("FSGLDIV"),
1644: _T("FREM"),
1645: _T("FSCALE"),
1646: _T("FSGLMUL"),
1647: _T("FSUB"),
1648: NULL,
1649: NULL,
1650: NULL,
1651: NULL,
1652: NULL,
1653: NULL,
1654: NULL,
1655: _T("FSINCOS"), // 0x30
1656: _T("FSINCOS"),
1657: _T("FSINCOS"),
1658: _T("FSINCOS"),
1659: _T("FSINCOS"),
1660: _T("FSINCOS"),
1661: _T("FSINCOS"),
1662: _T("FSINCOS"),
1663: _T("FCMP"),
1664: NULL,
1665: _T("FTST"),
1666: NULL,
1667: NULL,
1668: NULL,
1669: NULL,
1670: NULL
1671: };
1672:
1673: static const TCHAR *movemregs[] =
1674: {
1675: _T("D0"),
1676: _T("D1"),
1677: _T("D2"),
1678: _T("D3"),
1679: _T("D4"),
1680: _T("D5"),
1681: _T("D6"),
1682: _T("D7"),
1683: _T("A0"),
1684: _T("A1"),
1685: _T("A2"),
1686: _T("A3"),
1687: _T("A4"),
1688: _T("A5"),
1689: _T("A6"),
1690: _T("A7"),
1691: _T("FP0"),
1692: _T("FP1"),
1693: _T("FP2"),
1694: _T("FP3"),
1695: _T("FP4"),
1696: _T("FP5"),
1697: _T("FP6"),
1698: _T("FP7"),
1699: _T("FPIAR"),
1700: _T("FPSR"),
1701: _T("FPCR")
1702: };
1703:
1704: static void addmovemreg (TCHAR *out, int *prevreg, int *lastreg, int *first, int reg, int fpmode)
1705: {
1706: TCHAR *p = out + _tcslen (out);
1707: if (*prevreg < 0) {
1708: *prevreg = reg;
1709: *lastreg = reg;
1710: return;
1711: }
1712: if (reg < 0 || fpmode == 2 || (*prevreg) + 1 != reg || (reg & 8) != ((*prevreg & 8))) {
1713: _stprintf (p, _T("%s%s"), (*first) ? _T("") : _T("/"), movemregs[*lastreg]);
1714: p = p + _tcslen (p);
1715: if (*lastreg != *prevreg) {
1716: if ((*lastreg) + 2 == reg) {
1717: _stprintf(p, _T("/%s"), movemregs[*prevreg]);
1718: } else if ((*lastreg) != (*prevreg)) {
1719: _stprintf(p, _T("-%s"), movemregs[*prevreg]);
1720: }
1721: }
1722: *lastreg = reg;
1723: *first = 0;
1724: }
1725: *prevreg = reg;
1726: }
1727:
1728: static void movemout (TCHAR *out, uae_u16 mask, int mode, int fpmode)
1729: {
1730: unsigned int dmask, amask;
1731: int prevreg = -1, lastreg = -1, first = 1;
1732: int i;
1733:
1734: if (mode == Apdi && !fpmode) {
1735: uae_u8 dmask2;
1736: uae_u8 amask2;
1737:
1738: amask2 = mask & 0xff;
1739: dmask2 = (mask >> 8) & 0xff;
1740: dmask = 0;
1741: amask = 0;
1742: for (i = 0; i < 8; i++) {
1743: if (dmask2 & (1 << i))
1744: dmask |= 1 << (7 - i);
1745: if (amask2 & (1 << i))
1746: amask |= 1 << (7 - i);
1747: }
1748: } else {
1749: dmask = mask & 0xff;
1750: amask = (mask >> 8) & 0xff;
1751: if (fpmode == 1 && mode != Apdi) {
1752: uae_u8 dmask2 = dmask;
1753: dmask = 0;
1754: for (i = 0; i < 8; i++) {
1755: if (dmask2 & (1 << i))
1756: dmask |= 1 << (7 - i);
1757: }
1758: }
1759: }
1760: if (fpmode) {
1761: while (dmask) { addmovemreg(out, &prevreg, &lastreg, &first, movem_index1[dmask] + (fpmode == 2 ? 24 : 16), fpmode); dmask = movem_next[dmask]; }
1762: } else {
1763: while (dmask) { addmovemreg (out, &prevreg, &lastreg, &first, movem_index1[dmask], fpmode); dmask = movem_next[dmask]; }
1764: while (amask) { addmovemreg (out, &prevreg, &lastreg, &first, movem_index1[amask] + 8, fpmode); amask = movem_next[amask]; }
1765: }
1766: addmovemreg(out, &prevreg, &lastreg, &first, -1, fpmode);
1767: }
1768:
1769: static const TCHAR *fpsizes[] = {
1770: _T("L"),
1771: _T("S"),
1772: _T("X"),
1773: _T("P"),
1774: _T("W"),
1775: _T("D"),
1776: _T("B"),
1777: _T("P")
1778: };
1779: static const int fpsizeconv[] = {
1780: sz_long,
1781: sz_single,
1782: sz_extended,
1783: sz_packed,
1784: sz_word,
1785: sz_double,
1786: sz_byte,
1787: sz_packed
1788: };
1789:
1790: static void disasm_size (TCHAR *instrname, struct instr *dp)
1791: {
1792: if (dp->unsized) {
1793: _tcscat(instrname, _T(" "));
1794: return;
1795: }
1796: switch (dp->size)
1797: {
1798: case sz_byte:
1799: _tcscat (instrname, _T(".B "));
1800: break;
1801: case sz_word:
1802: _tcscat (instrname, _T(".W "));
1803: break;
1804: case sz_long:
1805: _tcscat (instrname, _T(".L "));
1806: break;
1807: default:
1808: _tcscat (instrname, _T(" "));
1809: break;
1810: }
1811: }
1812:
1813: void m68k_disasm_2 (TCHAR *buf, int bufsize, uaecptr pc, uaecptr *nextpc, int cnt, uae_u32 *seaddr, uae_u32 *deaddr, int safemode)
1814: {
1815: uae_u32 seaddr2;
1816: uae_u32 deaddr2;
1817:
1818: if (buf)
1819: memset (buf, 0, bufsize * sizeof (TCHAR));
1820: if (!table68k)
1821: return;
1822: while (cnt-- > 0) {
1823: TCHAR instrname[100], *ccpt;
1824: int i;
1825: uae_u32 opcode;
1826: uae_u16 extra;
1827: struct mnemolookup *lookup;
1828: struct instr *dp;
1829: uaecptr oldpc;
1830: uaecptr m68kpc_illg = 0;
1831: bool illegal = false;
1832:
1833: seaddr2 = deaddr2 = 0;
1834: oldpc = pc;
1835: opcode = get_word_debug (pc);
1836: extra = get_word_debug (pc + 2);
1837: if (cpufunctbl[opcode] == op_illg_1 || cpufunctbl[opcode] == op_unimpl_1) {
1838: m68kpc_illg = pc + 2;
1839: illegal = true;
1840: }
1841:
1842: dp = table68k + opcode;
1843: if (dp->mnemo == i_ILLG) {
1844: illegal = false;
1845: opcode = 0x4AFC;
1846: dp = table68k + opcode;
1847: }
1848: for (lookup = lookuptab;lookup->mnemo != dp->mnemo; lookup++)
1849: ;
1850:
1851: buf = buf_out (buf, &bufsize, _T("%08X "), pc);
1852:
1853: pc += 2;
1854:
1855: if (lookup->friendlyname)
1856: _tcscpy (instrname, lookup->friendlyname);
1857: else
1858: _tcscpy (instrname, lookup->name);
1859: ccpt = _tcsstr (instrname, _T("cc"));
1860: if (ccpt != 0) {
1861: if ((opcode & 0xf000) == 0xf000)
1862: _tcscpy (ccpt, fpccnames[extra & 0x1f]);
1863: else
1864: _tcsncpy (ccpt, ccnames[dp->cc], 2);
1865: }
1866: disasm_size (instrname, dp);
1867:
1868: if (lookup->mnemo == i_MOVEC2 || lookup->mnemo == i_MOVE2C) {
1869: uae_u16 imm = extra;
1870: uae_u16 creg = imm & 0x0fff;
1871: uae_u16 r = imm >> 12;
1872: TCHAR regs[16];
1873: const TCHAR *cname = _T("?");
1874: int i;
1875: for (i = 0; m2cregs[i].regname; i++) {
1876: if (m2cregs[i].regno == creg)
1877: break;
1878: }
1879: _stprintf (regs, _T("%c%d"), r >= 8 ? 'A' : 'D', r >= 8 ? r - 8 : r);
1880: if (m2cregs[i].regname)
1881: cname = m2cregs[i].regname;
1882: if (lookup->mnemo == i_MOVE2C) {
1883: _tcscat (instrname, regs);
1884: _tcscat (instrname, _T(","));
1885: _tcscat (instrname, cname);
1886: } else {
1887: _tcscat (instrname, cname);
1888: _tcscat (instrname, _T(","));
1889: _tcscat (instrname, regs);
1890: }
1891: pc += 2;
1892: } else if (lookup->mnemo == i_MVMEL) {
1893: uae_u16 mask = extra;
1894: pc += 2;
1895: pc = ShowEA (0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, deaddr, safemode);
1896: _tcscat (instrname, _T(","));
1897: movemout (instrname, mask, dp->dmode, 0);
1898: } else if (lookup->mnemo == i_MVMLE) {
1899: uae_u16 mask = extra;
1900: pc += 2;
1901: movemout(instrname, mask, dp->dmode, 0);
1902: _tcscat(instrname, _T(","));
1903: pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, deaddr, safemode);
1904: } else if (lookup->mnemo == i_DIVL || lookup->mnemo == i_MULL) {
1905: TCHAR *p;
1906: pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &seaddr2, safemode);
1907: extra = get_word_debug(pc);
1908: pc += 2;
1909: p = instrname + _tcslen(instrname);
1910: if (extra & 0x0400)
1911: _stprintf(p, _T(",D%d:D%d"), extra & 7, (extra >> 12) & 7);
1912: else
1913: _stprintf(p, _T(",D%d"), (extra >> 12) & 7);
1914: } else if (lookup->mnemo == i_MOVES) {
1915: TCHAR *p;
1916: pc += 2;
1917: if (!(extra & 0x1000)) {
1918: pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &seaddr2, safemode);
1919: p = instrname + _tcslen(instrname);
1920: _stprintf(p, _T(",%c%d"), (extra & 0x8000) ? 'A' : 'D', (extra >> 12) & 7);
1921: } else {
1922: p = instrname + _tcslen(instrname);
1923: _stprintf(p, _T("%c%d,"), (extra & 0x8000) ? 'A' : 'D', (extra >> 12) & 7);
1924: pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &seaddr2, safemode);
1925: }
1926: } else if (lookup->mnemo == i_BFEXTS || lookup->mnemo == i_BFEXTU ||
1927: lookup->mnemo == i_BFCHG || lookup->mnemo == i_BFCLR ||
1928: lookup->mnemo == i_BFFFO || lookup->mnemo == i_BFINS ||
1929: lookup->mnemo == i_BFSET || lookup->mnemo == i_BFTST) {
1930: TCHAR *p;
1931: int reg = -1;
1932:
1933: pc += 2;
1934: p = instrname + _tcslen(instrname);
1935: if (lookup->mnemo == i_BFEXTS || lookup->mnemo == i_BFEXTU || lookup->mnemo == i_BFFFO || lookup->mnemo == i_BFINS)
1936: reg = (extra >> 12) & 7;
1937: if (lookup->mnemo == i_BFINS)
1938: _stprintf(p, _T("D%d,"), reg);
1939: pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &seaddr2, safemode);
1940: _tcscat(instrname, _T(" {"));
1941: p = instrname + _tcslen(instrname);
1942: if (extra & 0x0800)
1943: _stprintf(p, _T("D%d"), (extra >> 6) & 7);
1944: else
1945: _stprintf(p, _T("%d"), (extra >> 6) & 31);
1946: _tcscat(instrname, _T(":"));
1947: p = instrname + _tcslen(instrname);
1948: if (extra & 0x0020)
1949: _stprintf(p, _T("D%d"), extra & 7);
1950: else
1951: _stprintf(p, _T("%d"), extra & 31);
1952: _tcscat(instrname, _T("}"));
1953: p = instrname + _tcslen(instrname);
1954: if (lookup->mnemo == i_BFFFO || lookup->mnemo == i_BFEXTS || lookup->mnemo == i_BFEXTU)
1955: _stprintf(p, _T(",D%d"), reg);
1956: } else if (lookup->mnemo == i_CPUSHA || lookup->mnemo == i_CPUSHL || lookup->mnemo == i_CPUSHP ||
1957: lookup->mnemo == i_CINVA || lookup->mnemo == i_CINVL || lookup->mnemo == i_CINVP) {
1958: if ((opcode & 0xc0) == 0xc0)
1959: _tcscat(instrname, _T("BC"));
1960: else if (opcode & 0x80)
1961: _tcscat(instrname, _T("IC"));
1962: else if (opcode & 0x40)
1963: _tcscat(instrname, _T("DC"));
1964: else
1965: _tcscat(instrname, _T("?"));
1966: if (lookup->mnemo == i_CPUSHL || lookup->mnemo == i_CPUSHP || lookup->mnemo == i_CINVL || lookup->mnemo == i_CINVP) {
1967: TCHAR *p = instrname + _tcslen(instrname);
1968: _stprintf(p, _T(",(A%d)"), opcode & 7);
1969: }
1970: } else if (lookup->mnemo == i_FPP) {
1971: TCHAR *p;
1972: int ins = extra & 0x3f;
1973: int size = (extra >> 10) & 7;
1974:
1975: pc += 2;
1976: if ((extra & 0xfc00) == 0x5c00) { // FMOVECR (=i_FPP with source specifier = 7)
1977: fptype fp;
1978: if (fpu_get_constant(&fp, extra & 0x3f))
1979: _stprintf(instrname, _T("FMOVECR.X #%s,FP%d"), fp_print(&fp), (extra >> 7) & 7);
1980: else
1981: _stprintf(instrname, _T("FMOVECR.X #?,FP%d"), (extra >> 7) & 7);
1982: } else if ((extra & 0x8000) == 0x8000) { // FMOVEM
1983: int dr = (extra >> 13) & 1;
1984: int mode;
1985: int dreg = (extra >> 4) & 7;
1986: int regmask, fpmode;
1987:
1988: if (extra & 0x4000) {
1989: mode = (extra >> 11) & 3;
1990: regmask = extra & 0xff; // FMOVEM FPx
1991: fpmode = 1;
1992: _tcscpy(instrname, _T("FMOVEM.X "));
1993: } else {
1994: mode = 0;
1995: regmask = (extra >> 10) & 7; // FMOVEM control
1996: fpmode = 2;
1997: _tcscpy(instrname, _T("FMOVEM.L "));
1998: if (regmask == 1 || regmask == 2 || regmask == 4)
1999: _tcscpy(instrname, _T("FMOVE.L "));
2000: }
2001: p = instrname + _tcslen(instrname);
2002: if (dr) {
2003: if (mode & 1)
2004: _stprintf(instrname, _T("D%d"), dreg);
2005: else
2006: movemout(instrname, regmask, dp->dmode, fpmode);
2007: _tcscat(instrname, _T(","));
2008: pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, deaddr, safemode);
2009: } else {
2010: pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, deaddr, safemode);
2011: _tcscat(instrname, _T(","));
2012: p = instrname + _tcslen(instrname);
2013: if (mode & 1)
2014: _stprintf(p, _T("D%d"), dreg);
2015: else
2016: movemout(p, regmask, dp->dmode, fpmode);
2017: }
2018: } else {
2019: if (fpuopcodes[ins])
2020: _tcscpy(instrname, fpuopcodes[ins]);
2021: else
2022: _tcscpy(instrname, _T("F?"));
2023:
2024: if ((extra & 0xe000) == 0x6000) { // FMOVE to memory
2025: int kfactor = extra & 0x7f;
2026: _tcscpy(instrname, _T("FMOVE."));
2027: _tcscat(instrname, fpsizes[size]);
2028: _tcscat(instrname, _T(" "));
2029: p = instrname + _tcslen(instrname);
2030: _stprintf(p, _T("FP%d,"), (extra >> 7) & 7);
2031: pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, fpsizeconv[size], instrname, &deaddr2, safemode);
2032: p = instrname + _tcslen(instrname);
2033: if (size == 7) {
2034: _stprintf(p, _T(" {D%d}"), (kfactor >> 4));
2035: } else if (kfactor) {
2036: if (kfactor & 0x40)
2037: kfactor |= ~0x3f;
2038: _stprintf(p, _T(" {%d}"), kfactor);
2039: }
2040: } else {
2041: if (extra & 0x4000) { // source is EA
2042: _tcscat(instrname, _T("."));
2043: _tcscat(instrname, fpsizes[size]);
2044: _tcscat(instrname, _T(" "));
2045: pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, fpsizeconv[size], instrname, &seaddr2, safemode);
2046: } else { // source is FPx
2047: p = instrname + _tcslen(instrname);
2048: _stprintf(p, _T(".X FP%d"), (extra >> 10) & 7);
2049: }
2050: p = instrname + _tcslen(instrname);
2051: if ((extra & 0x4000) || (((extra >> 7) & 7) != ((extra >> 10) & 7)))
2052: _stprintf(p, _T(",FP%d"), (extra >> 7) & 7);
2053: if (ins >= 0x30 && ins < 0x38) { // FSINCOS
2054: p = instrname + _tcslen(instrname);
2055: _stprintf(p, _T(",FP%d"), extra & 7);
2056: }
2057: }
2058: }
2059: } else if ((opcode & 0xf000) == 0xa000) {
2060: _tcscpy(instrname, _T("A-LINE"));
2061: } else {
2062: if (dp->suse) {
2063: pc = ShowEA (0, pc, opcode, dp->sreg, dp->smode, dp->size, instrname, &seaddr2, safemode);
2064: }
2065: if (dp->suse && dp->duse)
2066: _tcscat (instrname, _T(","));
2067: if (dp->duse) {
2068: pc = ShowEA (0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &deaddr2, safemode);
2069: }
2070: }
2071:
2072: for (i = 0; i < (int)(pc - oldpc) / 2 && i < 5; i++) {
2073: buf = buf_out (buf, &bufsize, _T("%04x "), get_word_debug (oldpc + i * 2));
2074: }
2075: while (i++ < 5)
2076: buf = buf_out (buf, &bufsize, _T(" "));
2077:
2078: if (illegal)
2079: buf = buf_out (buf, &bufsize, _T("[ "));
2080: buf = buf_out (buf, &bufsize, instrname);
2081: if (illegal)
2082: buf = buf_out (buf, &bufsize, _T(" ]"));
2083:
2084: if (ccpt != 0) {
2085: uaecptr addr2 = deaddr2 ? deaddr2 : seaddr2;
2086: if (deaddr)
2087: *deaddr = pc;
2088: if ((opcode & 0xf000) == 0xf000) {
2089: if (fpp_cond(dp->cc)) {
2090: buf = buf_out(buf, &bufsize, _T(" == $%08x (T)"), addr2);
2091: } else {
2092: buf = buf_out(buf, &bufsize, _T(" == $%08x (F)"), addr2);
2093: }
2094: } else {
2095: if (cctrue (dp->cc)) {
2096: buf = buf_out (buf, &bufsize, _T(" == $%08x (T)"), addr2);
2097: } else {
2098: buf = buf_out (buf, &bufsize, _T(" == $%08x (F)"), addr2);
2099: }
2100: }
2101: } else if ((opcode & 0xff00) == 0x6100) { /* BSR */
2102: if (deaddr)
2103: *deaddr = pc;
2104: buf = buf_out (buf, &bufsize, _T(" == $%08x"), seaddr2);
2105: }
2106: buf = buf_out (buf, &bufsize, _T("\n"));
2107:
2108: if (illegal)
2109: pc = m68kpc_illg;
2110: }
2111: if (nextpc)
2112: *nextpc = pc;
2113: if (seaddr)
2114: *seaddr = seaddr2;
2115: if (deaddr)
2116: *deaddr = deaddr2;
2117: }
2118:
2119: void m68k_disasm_ea (uaecptr addr, uaecptr *nextpc, int cnt, uae_u32 *seaddr, uae_u32 *deaddr)
2120: {
2121: TCHAR *buf;
2122:
2123: buf = xmalloc (TCHAR, (MAX_LINEWIDTH + 1) * cnt);
2124: if (!buf)
2125: return;
2126: m68k_disasm_2 (buf, (MAX_LINEWIDTH + 1) * cnt, addr, nextpc, cnt, seaddr, deaddr, 1);
2127: xfree (buf);
2128: }
2129: void m68k_disasm (uaecptr addr, uaecptr *nextpc, int cnt)
2130: {
2131: TCHAR *buf;
2132:
2133: buf = xmalloc (TCHAR, (MAX_LINEWIDTH + 1) * cnt);
2134: if (!buf)
2135: return;
2136: m68k_disasm_2 (buf, (MAX_LINEWIDTH + 1) * cnt, addr, nextpc, cnt, NULL, NULL, 0);
2137: printf (_T("%s"), buf);
2138: xfree (buf);
2139: }
2140:
2141: /*************************************************************
2142: Disasm the m68kcode at the given address into instrname
2143: and instrcode
2144: *************************************************************/
2145: void sm68k_disasm (TCHAR *instrname, TCHAR *instrcode, uaecptr addr, uaecptr *nextpc)
2146: {
2147: TCHAR *ccpt;
2148: uae_u32 opcode;
2149: struct mnemolookup *lookup;
2150: struct instr *dp;
2151: uaecptr pc, oldpc;
2152:
2153: pc = oldpc = addr;
2154: opcode = get_word_debug (pc);
2155: if (cpufunctbl[opcode] == op_illg_1) {
2156: opcode = 0x4AFC;
2157: }
2158: dp = table68k + opcode;
2159: for (lookup = lookuptab;lookup->mnemo != dp->mnemo; lookup++);
2160:
2161: pc += 2;
2162:
2163: _tcscpy (instrname, lookup->name);
2164: ccpt = _tcsstr (instrname, _T("cc"));
2165: if (ccpt != 0) {
2166: _tcsncpy (ccpt, ccnames[dp->cc], 2);
2167: }
2168: switch (dp->size){
2169: case sz_byte: _tcscat (instrname, _T(".B ")); break;
2170: case sz_word: _tcscat (instrname, _T(".W ")); break;
2171: case sz_long: _tcscat (instrname, _T(".L ")); break;
2172: default: _tcscat (instrname, _T(" ")); break;
2173: }
2174:
2175: if (dp->suse) {
2176: pc = ShowEA (0, pc, opcode, dp->sreg, dp->smode, dp->size, instrname, NULL, 0);
2177: }
2178: if (dp->suse && dp->duse)
2179: _tcscat (instrname, _T(","));
2180: if (dp->duse) {
2181: pc = ShowEA (0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, NULL, 0);
2182: }
2183: if (instrcode)
2184: {
2185: int i;
2186: for (i = 0; i < (int)(pc - oldpc) / 2; i++)
2187: {
2188: _stprintf (instrcode, _T("%04x "), get_iword_debug (oldpc + i * 2));
2189: instrcode += _tcslen (instrcode);
2190: }
2191: }
2192: if (nextpc)
2193: *nextpc = pc;
2194: }
2195:
2196: struct cpum2c m2cregs[] = {
2197: { 0, "SFC" },
2198: { 1, "DFC" },
2199: { 2, "CACR" },
2200: { 3, "TC" },
2201: { 4, "ITT0" },
2202: { 5, "ITT1" },
2203: { 6, "DTT0" },
2204: { 7, "DTT1" },
2205: { 8, "BUSC" },
2206: { 0x800, "USP" },
2207: { 0x801, "VBR" },
2208: { 0x802, "CAAR" },
2209: { 0x803, "MSP" },
2210: { 0x804, "ISP" },
2211: { 0x805, "MMUS" },
2212: { 0x806, "URP" },
2213: { 0x807, "SRP" },
2214: { 0x808, "PCR" },
2215: { -1, NULL }
2216: };
2217:
2218: void m68k_dumpstate_2 (uaecptr pc, uaecptr *nextpc)
2219: {
2220: int i, j;
2221:
2222: for (i = 0; i < 8; i++){
2223: printf (_T(" D%d %08X "), i, m68k_dreg (regs, i));
2224: if ((i & 3) == 3) printf (_T("\n"));
2225: }
2226: for (i = 0; i < 8; i++){
2227: printf (_T(" A%d %08X "), i, m68k_areg (regs, i));
2228: if ((i & 3) == 3) printf (_T("\n"));
2229: }
2230: if (regs.s == 0)
2231: regs.usp = m68k_areg (regs, 7);
2232: if (regs.s && regs.m)
2233: regs.msp = m68k_areg (regs, 7);
2234: if (regs.s && regs.m == 0)
2235: regs.isp = m68k_areg (regs, 7);
2236: j = 2;
2237: printf (_T("USP %08X ISP %08X "), regs.usp, regs.isp);
2238: for (i = 0; m2cregs[i].regno>= 0; i++) {
2239: if (!movec_illg (m2cregs[i].regno)) {
2240: if (!_tcscmp (m2cregs[i].regname, _T("USP")) || !_tcscmp (m2cregs[i].regname, _T("ISP")))
2241: continue;
2242: if (j > 0 && (j % 4) == 0)
2243: printf (_T("\n"));
2244: printf (_T("%-4s %08X "), m2cregs[i].regname, val_move2c (m2cregs[i].regno));
2245: j++;
2246: }
2247: }
2248: if (j > 0)
2249: printf (_T("\n"));
2250: printf (_T("T=%d%d S=%d M=%d X=%d N=%d Z=%d V=%d C=%d IMASK=%d STP=%d\n"),
2251: regs.t1, regs.t0, regs.s, regs.m,
2252: GET_XFLG (), GET_NFLG (), GET_ZFLG (),
2253: GET_VFLG (), GET_CFLG (),
2254: regs.intmask, regs.stopped);
2255: #ifdef FPUEMU
2256: if (currprefs.fpu_model) {
2257: uae_u32 fpsr;
2258: for (i = 0; i < 8; i++){
2259: printf (_T("FP%d: %s "), i, fp_print(®s.fp[i]));
2260: if ((i & 3) == 3)
2261: printf (_T("\n"));
2262: }
2263: fpsr = fpp_get_fpsr ();
2264: printf (_T("FPSR: %08X FPCR: %04x FPIAR: %08x N=%d Z=%d I=%d NAN=%d\n"),
2265: fpsr, regs.fpcr, regs.fpiar,
2266: (fpsr & 0x8000000) != 0,
2267: (fpsr & 0x4000000) != 0,
2268: (fpsr & 0x2000000) != 0,
2269: (fpsr & 0x1000000) != 0);
2270: }
2271: #endif
2272: if (currprefs.mmu_model == 68030) {
2273: printf (_T("SRP: %llX CRP: %llX\n"), srp_030, crp_030);
2274: printf (_T("TT0: %08X TT1: %08X TC: %08X\n"), tt0_030, tt1_030, tc_030);
2275: }
2276: if (currprefs.cpu_compatible && currprefs.cpu_model == 68000) {
2277: struct instr *dp;
2278: struct mnemolookup *lookup1, *lookup2;
2279: dp = table68k + regs.irc;
2280: for (lookup1 = lookuptab; lookup1->mnemo != dp->mnemo; lookup1++);
2281: dp = table68k + regs.ir;
2282: for (lookup2 = lookuptab; lookup2->mnemo != dp->mnemo; lookup2++);
2283: printf (_T("Prefetch %04x (%s) %04x (%s) Chip latch %08X\n"), regs.irc, lookup1->name, regs.ir, lookup2->name, regs.chipset_latch_rw);
2284: }
2285:
2286: if (pc != 0xffffffff) {
2287: m68k_disasm (pc, nextpc, 1);
2288: if (nextpc)
2289: printf (_T("Next PC: %08x\n"), *nextpc);
2290: }
2291: }
2292: void m68k_dumpstate (uaecptr *nextpc)
2293: {
2294: m68k_dumpstate_2 (m68k_getpc (), nextpc);
2295: }
2296:
2297: static void exception3f (uae_u32 opcode, uaecptr addr, bool writeaccess, bool instructionaccess, bool notinstruction, uaecptr pc, bool plus2)
2298: {
2299: if (currprefs.cpu_model >= 68040)
2300: addr &= ~1;
2301: if (currprefs.cpu_model >= 68020) {
2302: if (pc == 0xffffffff)
2303: last_addr_for_exception_3 = regs.instruction_pc;
2304: else
2305: last_addr_for_exception_3 = pc;
2306: } else if (pc == 0xffffffff) {
2307: last_addr_for_exception_3 = m68k_getpc ();
2308: if (plus2)
2309: last_addr_for_exception_3 += 2;
2310: } else {
2311: last_addr_for_exception_3 = pc;
2312: }
2313: last_fault_for_exception_3 = addr;
2314: last_op_for_exception_3 = opcode;
2315: last_writeaccess_for_exception_3 = writeaccess;
2316: last_instructionaccess_for_exception_3 = instructionaccess;
2317: Exception (3);
2318: }
2319:
2320: void exception3_read(uae_u32 opcode, uaecptr addr)
2321: {
2322: exception3f (opcode, addr, false, 0, false, 0xffffffff, false);
2323: }
2324: void exception3i (uae_u32 opcode, uaecptr addr)
2325: {
2326: exception3f (opcode, addr, 0, 1, false, 0xffffffff, true);
2327: }
2328: void exception3b (uae_u32 opcode, uaecptr addr, bool w, bool i, uaecptr pc)
2329: {
2330: exception3f (opcode, addr, w, i, false, pc, true);
2331: }
2332:
2333: void exception2 (uaecptr addr, bool read, int size, uae_u32 fc)
2334: {
2335: if (currprefs.mmu_model == 68030) {
2336: uae_u32 flags = size == 1 ? MMU030_SSW_SIZE_B : (size == 2 ? MMU030_SSW_SIZE_W : MMU030_SSW_SIZE_L);
2337: mmu030_page_fault (addr, read, flags, fc);
2338: } else {
2339: mmu_bus_error (addr, 0, fc, read == false, size, true);
2340: }
2341: }
2342:
2343: void cpureset (void) {
2344: uaecptr pc;
2345: uaecptr ksboot = 0xf80002 - 2; /* -2 = RESET hasn't increased PC yet */
2346: uae_u16 ins;
2347:
2348: if (currprefs.cpu_compatible) {
2349: return;
2350: }
2351:
2352: pc = m68k_getpc ();
2353: /* panic, RAM is going to disappear under PC */
2354: ins = get_word (pc + 2);
2355: if ((ins & ~7) == 0x4ed0) {
2356: int reg = ins & 7;
2357: uae_u32 addr = m68k_areg (regs, reg);
2358: write_log ("reset/jmp (ax) combination emulated -> %x\n", addr);
2359: if (addr < 0x80000)
2360: addr += 0xf80000;
2361: m68k_setpc (addr - 2);
2362: return;
2363: }
2364: write_log ("M68K RESET PC=%x, rebooting..\n", pc);
2365: m68k_setpc (ksboot);
2366: }
2367:
2368:
2369: void m68k_setstopped (void)
2370: {
2371: regs.stopped = 1;
2372: /* A traced STOP instruction drops through immediately without
2373: actually stopping. */
2374: if ((regs.spcflags & SPCFLAG_DOTRACE) == 0)
2375: set_special (SPCFLAG_STOP);
2376: else
2377: m68k_resumestopped ();
2378: }
2379:
2380: void m68k_resumestopped (void)
2381: {
2382: if (!regs.stopped)
2383: return;
2384: regs.stopped = 0;
2385: unset_special (SPCFLAG_STOP);
2386: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.