|
|
1.1 root 1: /*
2: * UAE - The Un*x Amiga Emulator
3: *
4: * MC68000 emulation
5: *
6: * (c) 1995 Bernd Schmidt
7: */
8:
9: #include "sysconfig.h"
10: #include "sysdeps.h"
11:
12: #include "config.h"
13: #include "options.h"
14: #include "events.h"
15: #include "gui.h"
16: #include "memory.h"
17: #include "custom.h"
18: #include "newcpu.h"
19: #include "autoconf.h"
20: #include "ersatz.h"
21: #include "readcpu.h"
22: #include "blitter.h"
23: #include "debug.h"
24: #include "compiler.h"
25:
26: int areg_byteinc[] = { 1,1,1,1,1,1,1,2 };
27: int imm8_table[] = { 8,1,2,3,4,5,6,7 };
28:
29: int movem_index1[256];
30: int movem_index2[256];
31: int movem_next[256];
32:
33: int fpp_movem_index1[256];
34: int fpp_movem_index2[256];
35: int fpp_movem_next[256];
36:
37: cpuop_func *cpufunctbl[65536];
38:
39: #ifdef NEED_TO_DEBUG_BADLY
40: void m68k_setpc(CPTR newpc)
41: {
42: if (newpc <= 12)
43: fprintf(stderr, "BAR at %x\n", m68k_getpc()), regs.spcflags |= SPCFLAG_BRK;
44: regs.pc = newpc;
45: regs.pc_p = regs.pc_oldp = get_real_address(newpc);
46: }
47: #endif
48:
49: #define COUNT_INSTRS 0
50:
51: #if COUNT_INSTRS
52: static unsigned long int instrcount[65536];
53: static UWORD opcodenums[65536];
54:
55: static int compfn(const void *el1, const void *el2)
56: {
57: return instrcount[*(const UWORD *)el1] < instrcount[*(const UWORD *)el2];
58: }
59:
60: void dump_counts(void)
61: {
62: FILE *f = fopen(getenv("INSNCOUNT") ? getenv("INSNCOUNT") : "insncount", "w");
63: unsigned long int total = 0;
64: int i;
65:
66: for(i=0; i < 65536; i++) {
67: opcodenums[i] = i;
68: total += instrcount[i];
69: }
70: qsort(opcodenums, 65536, sizeof(UWORD), compfn);
71:
72: fprintf(f, "Total: %lu\n", total);
73: for(i=0; i < 65536; i++) {
74: unsigned long int cnt = instrcount[opcodenums[i]];
75: struct instr *dp;
76: struct mnemolookup *lookup;
77: if (!cnt)
78: break;
79: dp = table68k + opcodenums[i];
80: for (lookup = lookuptab;lookup->mnemo != dp->mnemo; lookup++) ;
81: fprintf(f, "%04x: %lu %s\n", opcodenums[i], cnt, lookup->name);
82: }
83: fclose(f);
84: }
85: #else
86: void dump_counts(void)
87: {
88: }
89: #endif
90:
91: int broken_in;
92:
93: void init_m68k (void)
94: {
95: long int opcode;
96: int i,j;
97:
98: for (i = 0 ; i < 256 ; i++) {
99: for (j = 0 ; j < 8 ; j++) {
100: if (i & (1 << j)) break;
101: }
102: movem_index1[i] = j;
103: movem_index2[i] = 7-j;
104: movem_next[i] = i & (~(1 << j));
105: }
106: for (i = 0 ; i < 256 ; i++) {
107: for (j = 7 ; j >= 0 ; j--) {
108: if (i & (1 << j)) break;
109: }
110: fpp_movem_index1[i] = j;
111: fpp_movem_index2[i] = 7-j;
112: fpp_movem_next[i] = i & (~(1 << j));
113: }
114: #if COUNT_INSTRS
115: {
116: FILE *f = fopen("insncount", "r");
117: memset(instrcount, 0, sizeof instrcount);
118: if (f) {
119: ULONG opcode, count, total;
120: char name[20];
121: fscanf(f,"Total: %lu\n",&total);
122: while(fscanf(f,"%lx: %lu %s\n",&opcode,&count,name)==3) {
123: instrcount[opcode] = count;
124: }
125: fclose(f);
126: }
127: }
128: #endif
129: printf("Building CPU table...\n");
130: read_table68k ();
131: do_merges ();
132: for (opcode = 0; opcode < 65536; opcode++)
133: cpufunctbl[opcode] = op_illg;
134: for (i = 0; smallcputbl[i].handler != NULL; i++) {
135: if (!smallcputbl[i].specific)
136: cpufunctbl[smallcputbl[i].opcode] = smallcputbl[i].handler;
137: }
138: for (opcode = 0; opcode < 65536; opcode++) {
139: cpuop_func *f;
140:
141: if (table68k[opcode].mnemo == i_ILLG)
142: continue;
143:
144: if (table68k[opcode].handler != -1) {
145: f = cpufunctbl[table68k[opcode].handler];
146: if (f == op_illg)
147: abort();
148: cpufunctbl[opcode] = f;
149: }
150: }
151: for (i = 0; smallcputbl[i].handler != NULL; i++) {
152: if (smallcputbl[i].specific)
153: cpufunctbl[smallcputbl[i].opcode] = smallcputbl[i].handler;
154: }
155: }
156:
157: struct regstruct regs, lastint_regs;
158: static struct regstruct regs_backup[16];
159: static int backup_pointer = 0;
160: int lastint_no;
161: struct flag_struct regflags;
162:
163: static LONG ShowEA(int reg, amodes mode, wordsizes size)
164: {
165: UWORD dp;
166: BYTE disp8;
167: WORD disp16;
168: int r;
169: ULONG dispreg;
170: CPTR addr;
171: LONG offset = 0;
172:
173: switch(mode){
174: case Dreg:
175: printf("D%d", reg);
176: break;
177: case Areg:
178: printf("A%d", reg);
179: break;
180: case Aind:
181: printf("(A%d)", reg);
182: break;
183: case Aipi:
184: printf("(A%d)+", reg);
185: break;
186: case Apdi:
187: printf("-(A%d)", reg);
188: break;
189: case Ad16:
190: disp16 = nextiword();
191: addr = regs.a[reg] + (WORD)disp16;
192: printf("(A%d,$%04x) == $%08lx", reg, disp16 & 0xffff,
193: (long unsigned int)addr);
194: break;
195: case Ad8r:
196: dp = nextiword();
197: disp8 = dp & 0xFF;
198: r = (dp & 0x7000) >> 12;
199: dispreg = dp & 0x8000 ? regs.a[r] : regs.d[r];
200: if (!(dp & 0x800)) dispreg = (LONG)(WORD)(dispreg);
201: dispreg <<= (dp >> 9) & 3;
202:
203: if (dp & 0x100) {
204: LONG outer = 0, disp = 0;
205: LONG base = regs.a[reg];
206: char name[10];
207: sprintf(name,"A%d, ",reg);
208: if (dp & 0x80) { base = 0; name[0] = 0; }
209: if (dp & 0x40) dispreg = 0;
210: if ((dp & 0x30) == 0x20) disp = (LONG)(WORD)nextiword();
211: if ((dp & 0x30) == 0x30) disp = nextilong();
212: base += disp;
213:
214: if ((dp & 0x3) == 0x2) outer = (LONG)(WORD)nextiword();
215: if ((dp & 0x3) == 0x3) outer = nextilong();
216:
217: if (!(dp & 4)) base += dispreg;
218: if (dp & 3) base = get_long (base);
219: if (dp & 4) base += dispreg;
220:
221: addr = base + outer;
222: printf("(%s%c%d.%c*%d+%ld)+%ld == $%08lx", name,
223: dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W',
224: 1 << ((dp >> 9) & 3),
225: disp,outer,
226: (long unsigned int)addr);
227: }
228: else {
229: addr = regs.a[reg] + (LONG)((BYTE)disp8) + dispreg;
230: printf("(A%d, %c%d.%c*%d, $%02x) == $%08lx", reg,
231: dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W',
232: 1 << ((dp >> 9) & 3), disp8,
233: (long unsigned int)addr);
234: }
235: break;
236: case PC16:
237: addr = m68k_getpc();
238: disp16 = nextiword();
239: addr += (WORD)disp16;
240: printf("(PC,$%04x) == $%08lx", disp16 & 0xffff,(long unsigned int)addr);
241: break;
242: case PC8r:
243: addr = m68k_getpc();
244: dp = nextiword();
245: disp8 = dp & 0xFF;
246: r = (dp & 0x7000) >> 12;
247: dispreg = dp & 0x8000 ? regs.a[r] : regs.d[r];
248: if (!(dp & 0x800)) dispreg = (LONG)(WORD)(dispreg);
249: dispreg <<= (dp >> 9) & 3;
250:
251: if (dp & 0x100) {
252: LONG outer = 0,disp = 0;
253: LONG base = addr;
254: char name[10];
255: sprintf(name,"PC, ");
256: if (dp & 0x80) { base = 0; name[0] = 0; }
257: if (dp & 0x80) base = 0;
258: if (dp & 0x40) dispreg = 0;
259: if ((dp & 0x30) == 0x20) disp = (LONG)(WORD)nextiword();
260: if ((dp & 0x30) == 0x30) disp = nextilong();
261: base += disp;
262:
263: if ((dp & 0x3) == 0x2) outer = (LONG)(WORD)nextiword();
264: if ((dp & 0x3) == 0x3) outer = nextilong();
265:
266: if (!(dp & 4)) base += dispreg;
267: if (dp & 3) base = get_long (base);
268: if (dp & 4) base += dispreg;
269:
270: addr = base + outer;
271: printf("(%s%c%d.%c*%d+%ld)+%ld == $%08lx", name,
272: dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W',
273: 1 << ((dp >> 9) & 3),
274: disp,outer,
275: (long unsigned int)addr);
276: }
277: else {
278: addr += (LONG)((BYTE)disp8) + dispreg;
279: printf("(PC, %c%d.%c*%d, $%02x) == $%08lx", dp & 0x8000 ? 'A' : 'D',
280: (int)r, dp & 0x800 ? 'L' : 'W', 1 << ((dp >> 9) & 3),
281: disp8, (long unsigned int)addr);
282: }
283: break;
284: case absw:
285: printf("$%08lx", (LONG)(WORD)nextiword());
286: break;
287: case absl:
288: printf("$%08lx", nextilong());
289: break;
290: case imm:
291: switch(size){
292: case sz_byte:
293: printf("#$%02x", nextiword() & 0xff); break;
294: case sz_word:
295: printf("#$%04x", nextiword() & 0xffff); break;
296: case sz_long:
297: printf("#$%08lx", nextilong()); break;
298: default:
299: break;
300: }
301: break;
302: case imm0:
303: offset = (LONG)(BYTE)nextiword();
304: printf("#$%02lx", offset & 0xff);
305: break;
306: case imm1:
307: offset = (LONG)(WORD)nextiword();
308: printf("#$%04lx", offset & 0xffff);
309: break;
310: case imm2:
311: offset = (LONG)nextilong();
312: printf("#$%08lx", (ULONG)offset);
313: break;
314: case immi:
315: offset = (LONG)(BYTE)(reg & 0xff);
316: printf("#$%08lx", (ULONG)offset);
317: break;
318: default:
319: break;
320: }
321: return(offset);
322: }
323:
324: void MakeSR(void)
325: {
326: #if 0
327: assert((regs.t1 & 1) == regs.t1);
328: assert((regs.t0 & 1) == regs.t0);
329: assert((regs.s & 1) == regs.s);
330: assert((regs.m & 1) == regs.m);
331: assert((XFLG & 1) == XFLG);
332: assert((NFLG & 1) == NFLG);
333: assert((ZFLG & 1) == ZFLG);
334: assert((VFLG & 1) == VFLG);
335: assert((CFLG & 1) == CFLG);
336: #endif
337: regs.sr = ((regs.t1 << 15) | (regs.t0 << 14)
338: | (regs.s << 13) | (regs.m << 12) | (regs.intmask << 8)
339: | (XFLG << 4) | (NFLG << 3) | (ZFLG << 2) | (VFLG << 1)
340: | CFLG);
341: }
342:
343: void MakeFromSR(void)
344: {
345: int oldm = regs.m;
346: int olds = regs.s;
347:
348: regs.t1 = (regs.sr >> 15) & 1;
349: regs.t0 = (regs.sr >> 14) & 1;
350: regs.s = (regs.sr >> 13) & 1;
351: regs.m = (regs.sr >> 12) & 1;
352: regs.intmask = (regs.sr >> 8) & 7;
353: XFLG = (regs.sr >> 4) & 1;
354: NFLG = (regs.sr >> 3) & 1;
355: ZFLG = (regs.sr >> 2) & 1;
356: VFLG = (regs.sr >> 1) & 1;
357: CFLG = regs.sr & 1;
358: if (CPU_LEVEL >= 2) {
359: if (olds != regs.s) {
360: if (olds) {
361: if (oldm)
362: regs.msp = regs.a[7];
363: else
364: regs.isp = regs.a[7];
365: regs.a[7] = regs.usp;
366: }
367: else {
368: regs.usp = regs.a[7];
369: regs.a[7] = regs.m ? regs.msp : regs.isp;
370: }
371: } else if (olds && oldm != regs.m) {
372: if (oldm) {
373: regs.msp = regs.a[7];
374: regs.a[7] = regs.isp;
375: }
376: else {
377: regs.isp = regs.a[7];
378: regs.a[7] = regs.msp;
379: }
380: }
381: } else {
382: if (olds != regs.s) {
383: if (olds) {
384: regs.isp = regs.a[7];
385: regs.a[7] = regs.usp;
386: } else {
387: regs.usp = regs.a[7];
388: regs.a[7] = regs.isp;
389: }
390: }
391: }
392:
393: regs.spcflags |= SPCFLAG_INT;
394: if (regs.t1 || regs.t0)
395: regs.spcflags |= SPCFLAG_TRACE;
396: else
397: regs.spcflags &= ~(SPCFLAG_TRACE | SPCFLAG_DOTRACE);
398: }
399:
400: void Exception(int nr, CPTR oldpc)
401: {
402: MakeSR();
403: if (!regs.s) {
404: regs.usp = regs.a[7];
405: if (CPU_LEVEL >= 2)
406: regs.a[7] = regs.m ? regs.msp : regs.isp;
407: else
408: regs.a[7] = regs.isp;
409: regs.s = 1;
410: }
411: if (CPU_LEVEL > 0) {
412: if (nr == 2 || nr == 3) {
413: int i;
414: for (i = 0 ; i < 12 ; i++) {
415: regs.a[7] -= 2;
416: put_word (regs.a[7], 0);
417: }
418: regs.a[7] -= 2;
419: put_word (regs.a[7], 0xa000 + nr * 4);
420: } else if (nr ==5 || nr == 6 || nr == 7 || nr == 9) {
421: regs.a[7] -= 4;
422: put_long (regs.a[7], oldpc);
423: regs.a[7] -= 2;
424: put_word (regs.a[7], 0x2000 + nr * 4);
425: } else if (regs.m && nr >= 24 && nr < 32) {
426: regs.a[7] -= 2;
427: put_word (regs.a[7], nr * 4);
428: regs.a[7] -= 4;
429: put_long (regs.a[7], m68k_getpc ());
430: regs.a[7] -= 2;
431: put_word (regs.a[7], regs.sr);
432: regs.sr |= (1 << 13);
433: regs.msp = regs.a[7];
434: regs.a[7] = regs.isp;
435: regs.a[7] -= 2;
436: put_word (regs.a[7], 0x1000 + nr * 4);
437: } else {
438: regs.a[7] -= 2;
439: put_word (regs.a[7], nr * 4);
440: }
441: }
442: regs.a[7] -= 4;
443: put_long (regs.a[7], m68k_getpc ());
444: regs.a[7] -= 2;
445: put_word (regs.a[7], regs.sr);
446: m68k_setpc(get_long(regs.vbr + 4*nr));
447: regs.t1 = regs.t0 = regs.m = 0;
448: regs.spcflags &= ~(SPCFLAG_TRACE | SPCFLAG_DOTRACE);
449: }
450:
451: static void Interrupt(int nr)
452: {
453: assert(nr < 8 && nr >= 0);
454: lastint_regs = regs;
455: lastint_no = nr;
456: Exception(nr+24, 0);
457:
458: regs.intmask = nr;
459: regs.spcflags |= SPCFLAG_INT;
460: }
461:
462: static int caar, cacr;
463:
464: void m68k_move2c (int regno, ULONG *regp)
465: {
466: if (CPU_LEVEL == 1 && (regno & 0x7FF) > 1)
467: op_illg (0x4E7B);
468: else
469: switch (regno) {
470: case 0: regs.sfc = *regp & 7; break;
471: case 1: regs.dfc = *regp & 7; break;
472: case 2: cacr = *regp & 0x3; break; /* ignore C and CE */
473: case 0x800: regs.usp = *regp; break;
474: case 0x801: regs.vbr = *regp; break;
475: case 0x802: caar = *regp &0xfc; break;
476: case 0x803: regs.msp = *regp; if (regs.m == 1) regs.a[7] = regs.msp; break;
477: case 0x804: regs.isp = *regp; if (regs.m == 0) regs.a[7] = regs.isp; break;
478: default:
479: op_illg (0x4E7B);
480: break;
481: }
482: }
483:
484: void m68k_movec2 (int regno, ULONG *regp)
485: {
486: if (CPU_LEVEL == 1 && (regno & 0x7FF) > 1)
487: op_illg (0x4E7A);
488: else
489: switch (regno) {
490: case 0: *regp = regs.sfc; break;
491: case 1: *regp = regs.dfc; break;
492: case 2: *regp = cacr; break;
493: case 0x800: *regp = regs.usp; break;
494: case 0x801: *regp = regs.vbr; break;
495: case 0x802: *regp = caar; break;
496: case 0x803: *regp = regs.m == 1 ? regs.a[7] : regs.msp; break;
497: case 0x804: *regp = regs.m == 0 ? regs.a[7] : regs.isp; break;
498: default:
499: op_illg (0x4E7A);
500: break;
501: }
502: }
503:
504: static __inline__ int
505: div_unsigned(ULONG src_hi, ULONG src_lo, ULONG div, ULONG *quot, ULONG *rem)
506: {
507: ULONG q = 0, cbit = 0;
508: int i;
509:
510: if (div <= src_hi) {
511: return(1);
512: }
513: for (i = 0 ; i < 32 ; i++) {
514: cbit = src_hi & 0x80000000;
515: src_hi <<= 1;
516: if (src_lo & 0x80000000) src_hi++;
517: src_lo <<= 1;
518: q = q << 1;
519: if (cbit || div <= src_hi) {
520: q |= 1;
521: src_hi -= div;
522: }
523: }
524: *quot = q;
525: *rem = src_hi;
526: return(0);
527: }
528:
529: void m68k_divl (ULONG opcode, ULONG src, UWORD extra, CPTR oldpc)
530: {
531: #if defined(INT_64BIT)
532: if (src == 0) {
533: Exception(5,oldpc-2);
534: return;
535: }
536: if (extra & 0x800) {
537: /* signed variant */
538: INT_64BIT a = (INT_64BIT)(LONG)regs.d[(extra >> 12) & 7];
539: INT_64BIT quot, rem;
540:
541: if (extra & 0x400) {
542: a &= 0xffffffffLL;
543: a |= (INT_64BIT)regs.d[extra & 7] << 32;
544: }
545: rem = a % (INT_64BIT)(LONG)src;
546: quot = a / (INT_64BIT)(LONG)src;
547: if ((quot & 0xffffffff80000000LL) != 0 &&
548: (quot & 0xffffffff80000000LL) != 0xffffffff80000000LL) {
549: VFLG = NFLG = 1;
550: CFLG = 0;
551: }
552: else {
553: if (((LONG)rem < 0) != ((INT_64BIT)a < 0)) rem = -rem;
554: VFLG = CFLG = 0;
555: ZFLG = ((LONG)quot) == 0;
556: NFLG = ((LONG)quot) < 0;
557: regs.d[extra & 7] = rem;
558: regs.d[(extra >> 12) & 7] = quot;
559: }
560: } else {
561: /* unsigned */
562: unsigned INT_64BIT a = (unsigned INT_64BIT)(ULONG)regs.d[(extra >> 12) & 7];
563: unsigned INT_64BIT quot, rem;
564:
565: if (extra & 0x400) {
566: a &= 0xffffffffLL;
567: a |= (unsigned INT_64BIT)regs.d[extra & 7] << 32;
568: }
569: rem = a % (unsigned INT_64BIT)src;
570: quot = a / (unsigned INT_64BIT)src;
571: if (quot > 0xffffffffLL) {
572: VFLG = NFLG = 1;
573: CFLG = 0;
574: }
575: else {
576: VFLG = CFLG = 0;
577: ZFLG = ((LONG)quot) == 0;
578: NFLG = ((LONG)quot) < 0;
579: regs.d[extra & 7] = rem;
580: regs.d[(extra >> 12) & 7] = quot;
581: }
582: }
583: #else
584: if (src == 0) {
585: Exception(5,oldpc-2);
586: return;
587: }
588: if (extra & 0x800) {
589: /* signed variant */
590: LONG lo = (LONG)regs.d[(extra >> 12) & 7];
591: LONG hi = lo < 0 ? -1 : 0;
592: LONG save_high;
593: ULONG quot, rem;
594: ULONG sign;
595:
596: if (extra & 0x400) {
597: hi = (LONG)regs.d[extra & 7];
598: }
599: save_high = hi;
600: sign = (hi ^ src);
601: if (hi < 0) {
602: hi = ~hi;
603: lo = -lo;
604: if (lo == 0) hi++;
605: }
606: if ((LONG)src < 0) src = -src;
607: if (div_unsigned(hi, lo, src, ", &rem) ||
608: (sign & 0x80000000) ? quot > 0x80000000 : quot > 0x7fffffff) {
609: VFLG = NFLG = 1;
610: CFLG = 0;
611: }
612: else {
613: if (sign & 0x80000000) quot = -quot;
614: if (((LONG)rem < 0) != (save_high < 0)) rem = -rem;
615: VFLG = CFLG = 0;
616: ZFLG = ((LONG)quot) == 0;
617: NFLG = ((LONG)quot) < 0;
618: regs.d[extra & 7] = rem;
619: regs.d[(extra >> 12) & 7] = quot;
620: }
621: } else {
622: /* unsigned */
623: ULONG lo = (ULONG)regs.d[(extra >> 12) & 7];
624: ULONG hi = 0;
625: ULONG quot, rem;
626:
627: if (extra & 0x400) {
628: hi = (ULONG)regs.d[extra & 7];
629: }
630: if (div_unsigned(hi, lo, src, ", &rem)) {
631: VFLG = NFLG = 1;
632: CFLG = 0;
633: }
634: else {
635: VFLG = CFLG = 0;
636: ZFLG = ((LONG)quot) == 0;
637: NFLG = ((LONG)quot) < 0;
638: regs.d[extra & 7] = rem;
639: regs.d[(extra >> 12) & 7] = quot;
640: }
641: }
642: #endif
643: }
644:
645: static __inline__ void
646: mul_unsigned(ULONG src1, ULONG src2, ULONG *dst_hi, ULONG *dst_lo)
647: {
648: ULONG r0 = (src1 & 0xffff) * (src2 & 0xffff);
649: ULONG r1 = ((src1 >> 16) & 0xffff) * (src2 & 0xffff);
650: ULONG r2 = (src1 & 0xffff) * ((src2 >> 16) & 0xffff);
651: ULONG r3 = ((src1 >> 16) & 0xffff) * ((src2 >> 16) & 0xffff);
652: ULONG lo;
653:
654: lo = r0 + ((r1 << 16) & 0xffff0000);
655: if (lo < r0) r3++;
656: r0 = lo;
657: lo = r0 + ((r2 << 16) & 0xffff0000);
658: if (lo < r0) r3++;
659: r3 += ((r1 >> 16) & 0xffff) + ((r2 >> 16) & 0xffff);
660: *dst_lo = lo;
661: *dst_hi = r3;
662: }
663:
664: void m68k_mull (ULONG opcode, ULONG src, UWORD extra)
665: {
666: #if defined(INT_64BIT)
667: if (extra & 0x800) {
668: /* signed variant */
669: INT_64BIT a = (INT_64BIT)(LONG)regs.d[(extra >> 12) & 7];
670:
671: a *= (INT_64BIT)(LONG)src;
672: VFLG = CFLG = 0;
673: ZFLG = a == 0;
674: NFLG = a < 0;
675: if (extra & 0x400)
676: regs.d[extra & 7] = a >> 32;
677: else if ((a & 0xffffffff80000000LL) != 0 &&
678: (a & 0xffffffff80000000LL) != 0xffffffff80000000LL) {
679: VFLG = 1;
680: }
681: regs.d[(extra >> 12) & 7] = (ULONG)a;
682: } else {
683: /* unsigned */
684: unsigned INT_64BIT a = (unsigned INT_64BIT)(ULONG)regs.d[(extra >> 12) & 7];
685:
686: a *= (unsigned INT_64BIT)src;
687: VFLG = CFLG = 0;
688: ZFLG = a == 0;
689: NFLG = ((INT_64BIT)a) < 0;
690: if (extra & 0x400)
691: regs.d[extra & 7] = a >> 32;
692: else if ((a & 0xffffffff00000000LL) != 0) {
693: VFLG = 1;
694: }
695: regs.d[(extra >> 12) & 7] = (ULONG)a;
696: }
697: #else
698: if (extra & 0x800) {
699: /* signed variant */
700: LONG src1,src2;
701: ULONG dst_lo,dst_hi;
702: ULONG sign;
703:
704: src1 = (LONG)src;
705: src2 = (LONG)regs.d[(extra >> 12) & 7];
706: sign = (src1 ^ src2);
707: if (src1 < 0) src1 = -src1;
708: if (src2 < 0) src2 = -src2;
709: mul_unsigned((ULONG)src1,(ULONG)src2,&dst_hi,&dst_lo);
710: if (sign & 0x80000000) {
711: dst_hi = ~dst_hi;
712: dst_lo = -dst_lo;
713: if (dst_lo == 0) dst_hi++;
714: }
715: VFLG = CFLG = 0;
716: ZFLG = dst_hi == 0 && dst_lo == 0;
717: NFLG = ((LONG)dst_hi) < 0;
718: if (extra & 0x400)
719: regs.d[extra & 7] = dst_hi;
720: else if ((dst_hi != 0 || (dst_lo & 0x80000000) != 0) &&
721: ((dst_hi & 0xffffffff) != 0xffffffff ||
722: (dst_lo & 0x80000000) != 0x80000000)) {
723: VFLG = 1;
724: }
725: regs.d[(extra >> 12) & 7] = dst_lo;
726: } else {
727: /* unsigned */
728: ULONG dst_lo,dst_hi;
729:
730: mul_unsigned(src,(ULONG)regs.d[(extra >> 12) & 7],&dst_hi,&dst_lo);
731:
732: VFLG = CFLG = 0;
733: ZFLG = dst_hi == 0 && dst_lo == 0;
734: NFLG = ((LONG)dst_hi) < 0;
735: if (extra & 0x400)
736: regs.d[extra & 7] = dst_hi;
737: else if (dst_hi != 0) {
738: VFLG = 1;
739: }
740: regs.d[(extra >> 12) & 7] = dst_lo;
741: }
742: #endif
743: }
744: static char* ccnames[] =
745: { "T ","F ","HI","LS","CC","CS","NE","EQ",
746: "VC","VS","PL","MI","GE","LT","GT","LE" };
747:
748: void m68k_reset(void)
749: {
750: regs.a[7] = get_long(0x00f80000);
751: m68k_setpc(get_long(0x00f80004));
752: regs.s = 1;
753: regs.m = 0;
754: regs.stopped = 0;
755: regs.t1 = 0;
756: regs.t0 = 0;
757: ZFLG = CFLG = NFLG = VFLG = 0;
758: regs.spcflags = 0;
759: regs.intmask = 7;
760: regs.vbr = regs.sfc = regs.dfc = 0;
761: regs.fpcr = regs.fpsr = regs.fpiar = 0;
762: customreset();
763: }
764:
765: void op_illg(ULONG opcode)
766: {
767: if (opcode == 0x4E7B && get_long(0x10) == 0
768: && (m68k_getpc() & 0xF80000) == 0xF80000)
769: {
770: fprintf(stderr, "Your Kickstart requires a 68020 CPU. Giving up.\n");
771: broken_in = 1;
772: regs.spcflags |= SPCFLAG_BRK;
773: quit_program = 1;
774: }
775: if (opcode == 0xFF0D && ((m68k_getpc() & 0xF80000) == 0xF80000)) {
776: /* This is from the dummy Kickstart replacement */
777: ersatz_perform (nextiword ());
778: return;
779: }
780: #ifdef USE_POINTER
781: regs.pc_p -= 2;
782: #else
783: regs.pc -= 2;
784: #endif
785: if ((opcode & 0xF000) == 0xF000) {
786: Exception(0xB,0);
787: return;
788: }
789: if ((opcode & 0xF000) == 0xA000) {
790: Exception(0xA,0);
791: return;
792: }
793: fprintf(stderr, "Illegal instruction: %04x at %08lx\n", opcode, m68k_getpc());
794: Exception(4,0);
795: }
796:
797: void mmu_op(ULONG opcode, UWORD extra)
798: {
799: if ((extra & 0xB000) == 0) { /* PMOVE instruction */
800:
801: } else if ((extra & 0xF000) == 0x2000) { /* PLOAD instruction */
802: } else if ((extra & 0xF000) == 0x8000) { /* PTEST instruction */
803: } else
804: op_illg(opcode);
805: }
806:
807: static int n_insns=0, n_spcinsns=0;
808:
809: static __inline__ void do_hardware(void)
810: {
811: if (regs.spcflags & SPCFLAG_BLIT) {
812: do_blitter();
813: #if FAST_BLITTER == 0
814: do_blitter();
815: do_blitter();
816: do_blitter();
817: #endif
818: }
819: if (regs.spcflags & SPCFLAG_DISK) {
820: do_disk();
821: }
822: }
823:
824: static CPTR last_trace_ad = 0;
825:
826: static __inline__ void do_trace(void)
827: {
828: if (regs.spcflags & SPCFLAG_TRACE) { /* 6 */
829: if (regs.t0) {
830: UWORD opcode;
831: /* should also include TRAP, CHK, SR modification FPcc */
832: /* probably never used so why bother */
833: /* We can afford this to be inefficient... */
834: m68k_setpc(m68k_getpc());
835: opcode = get_word(regs.pc);
836: if (opcode == 0x4e72 /* RTE */
837: || opcode == 0x4e74 /* RTD */
838: || opcode == 0x4e75 /* RTS */
839: || opcode == 0x4e77 /* RTR */
840: || opcode == 0x4e76 /* TRAPV */
841: || (opcode & 0xffc0) == 0x4e80 /* JSR */
842: || (opcode & 0xffc0) == 0x4ec0 /* JMP */
843: || (opcode & 0xff00) == 0x6100 /* BSR */
844: || ((opcode & 0xf000) == 0x6000 /* Bcc */
845: && cctrue((opcode >> 8) & 0xf))
846: || ((opcode & 0xf0f0) == 0x5050 /* DBcc */
847: && !cctrue((opcode >> 8) & 0xf)
848: && (WORD)regs.d[opcode & 7] != 0))
849: {
850: last_trace_ad = m68k_getpc();
851: regs.spcflags &= ~SPCFLAG_TRACE;
852: regs.spcflags |= SPCFLAG_DOTRACE;
853: }
854: } else if (regs.t1) {
855: last_trace_ad = m68k_getpc();
856: regs.spcflags &= ~SPCFLAG_TRACE;
857: regs.spcflags |= SPCFLAG_DOTRACE;
858: }
859: }
860: }
861:
862: static __inline__ void m68k_run_1(void)
863: {
864: regs.spcflags &= ~(SPCFLAG_EMULTRAP);
865: for(;;) {
866:
867: /* assert (!regs.stopped && !(regs.spcflags & SPCFLAG_STOP)); */
868: /* regs_backup[backup_pointer = (backup_pointer + 1) % 16] = regs;*/
869: #if COUNT_INSTRS
870: instrcount[opcode]++;
871: #endif
872: #if defined(X86_ASSEMBLY)
873: __asm__ ("movl %0,%%ebx\n\tmovb (%%ebx),%%ah\n\tmovb 1(%%ebx),%%al\n\taddl $2,%0\n\tandl $65535,%%eax\n\tmovl cpufunctbl(,%%eax,4),%%ebx\n\tcall *%%ebx"
874: : "=m" (regs.pc_p)
875: : "0" (regs.pc_p)
876: : "%eax", "%edx", "%ecx", "%esi", "%edi", "%ebx", "%ebp", "memory", "cc");
877: #else
878: {
879: UWORD opcode = nextiword();
880: (*cpufunctbl[opcode])(opcode);
881: }
882: #endif
883: #ifndef NO_EXCEPTION_3
884: if (buserr) {
885: Exception(3,0);
886: buserr = 0;
887: }
888: #endif
889: if (regs.spcflags & SPCFLAG_EMULTRAP)
890: return;
891: /*n_insns++;*/
892: do_cycles();
893: if (regs.spcflags) {
894: /*n_spcinsns++;*/
895: while (regs.spcflags & SPCFLAG_BLTNASTY) { /* 9 */
896: do_cycles();
897: do_hardware();
898: }
899: run_compiled_code();
900: if (regs.spcflags & SPCFLAG_DOTRACE) { /* 7 */
901: Exception(9,last_trace_ad);
902: }
903: while (regs.spcflags & SPCFLAG_STOP) { /* 1 */
904: do_cycles();
905: do_hardware();
906: if (regs.spcflags & (SPCFLAG_INT | SPCFLAG_DOINT)){
907: int intr = intlev();
908: regs.spcflags &= ~(SPCFLAG_INT | SPCFLAG_DOINT);
909: if (intr != -1 && intr > regs.intmask) {
910: Interrupt(intr);
911: regs.stopped = 0;
912: regs.spcflags &= ~SPCFLAG_STOP;
913: }
914: }
915: }
916: do_trace();
917: #ifdef WANT_SLOW_MULTIPLY
918: /* Kludge for Hardwired demo. The guys who wrote it should be
919: * mutilated. */
920: if (regs.spcflags & SPCFLAG_EXTRA_CYCLES) { /* 5 */
921: do_cycles (); do_cycles (); do_cycles (); do_cycles ();
922: regs.spcflags &= ~SPCFLAG_EXTRA_CYCLES;
923: }
924: #endif
925: do_hardware();
926:
927: if (regs.spcflags & SPCFLAG_DOINT) { /* 8 */
928: int intr = intlev();
929: regs.spcflags &= ~SPCFLAG_DOINT;
930: if (intr != -1 && intr > regs.intmask) {
931: Interrupt(intr);
932: regs.stopped = 0;
933: }
934: }
935: if (regs.spcflags & SPCFLAG_INT) { /* 3 */
936: regs.spcflags &= ~SPCFLAG_INT;
937: regs.spcflags |= SPCFLAG_DOINT;
938: }
939: if (regs.spcflags & SPCFLAG_BRK) { /* 4 */
940: regs.spcflags &= ~SPCFLAG_BRK;
941: return;
942: }
943: }
944: }
945: }
946:
947: #ifdef X86_ASSEMBLY
948: void m68k_run(void)
949: {
950: /* Work around compiler bug: GCC doesn't push %ebp in m68k_run_1. */
951: __asm__ __volatile__ ("pushl %%ebp\n\tcall *%%eax\n\tpopl %%ebp" : : "a" (m68k_run_1) : "%eax", "%edx", "%ecx", "memory", "cc");
952: }
953: #else
954: void m68k_run(void)
955: {
956: m68k_run_1();
957: }
958: #endif
959:
960: void m68k_go(int may_quit)
961: {
962: for(;;) {
963: if (may_quit && quit_program)
964: return;
965: if (debugging)
966: debug();
967:
968: m68k_run();
969:
970: /*
971: * We make sure in the above functions that this is never
972: * set together with SPCFLAG_INT and similar flags
973: */
974: if (regs.spcflags & SPCFLAG_EMULTRAP) {
975: regs.spcflags &= ~SPCFLAG_EMULTRAP;
976: if (lasttrap == 0)
977: break;
978: do_emultrap(lasttrap);
979: }
980: }
981: }
982:
983: void m68k_disasm(CPTR addr, CPTR *nextpc, int cnt)
984: {
985: CPTR pc = m68k_getpc();
986: CPTR newpc = 0;
987: m68k_setpc(addr);
988: for (;cnt--;){
989: char instrname[20],*ccpt;
990: int opwords;
991: ULONG opcode;
992: struct mnemolookup *lookup;
993: struct instr *dp;
994: printf("%08lx: ", m68k_getpc());
995: for(opwords = 0; opwords < 5; opwords++){
996: printf("%04x ", get_word(m68k_getpc() + opwords*2));
997: }
998:
999: opcode = nextiword();
1000: if (cpufunctbl[opcode] == op_illg) {
1001: opcode = 0x4AFC;
1002: }
1003: dp = table68k + opcode;
1004: for (lookup = lookuptab;lookup->mnemo != dp->mnemo; lookup++)
1005: ;
1006:
1007: strcpy(instrname,lookup->name);
1008: ccpt = strstr(instrname,"cc");
1009: if (ccpt != 0) {
1010: strncpy(ccpt,ccnames[dp->cc],2);
1011: }
1012: printf("%s", instrname);
1013: switch(dp->size){
1014: case sz_byte: printf(".B "); break;
1015: case sz_word: printf(".W "); break;
1016: case sz_long: printf(".L "); break;
1017: default: printf(" ");break;
1018: }
1019:
1020: if (dp->suse) {
1021: newpc = m68k_getpc() + ShowEA(dp->sreg, dp->smode, dp->size);
1022: }
1023: if (dp->suse && dp->duse)
1024: printf(",");
1025: if (dp->duse) {
1026: newpc = m68k_getpc() + ShowEA(dp->dreg, dp->dmode, dp->size);
1027: }
1028: if (ccpt != 0) {
1029: if (cctrue(dp->cc))
1030: printf(" == %08lx (TRUE)",newpc);
1031: else
1032: printf(" == %08lx (FALSE)",newpc);
1033: } else if ((opcode & 0xff00) == 0x6100) /* BSR */
1034: printf(" == %08lx",newpc);
1035: printf("\n");
1036: }
1037: if (nextpc) *nextpc = m68k_getpc();
1038: m68k_setpc(pc);
1039: }
1040:
1041: void m68k_dumpstate(CPTR *nextpc)
1042: {
1043: int i;
1044: for(i = 0; i < 8; i++){
1045: printf("D%d: %08lx ", i, regs.d[i]);
1046: if ((i & 3) == 3) printf("\n");
1047: }
1048: for(i = 0; i < 8; i++){
1049: printf("A%d: %08lx ", i, regs.a[i]);
1050: if ((i & 3) == 3) printf("\n");
1051: }
1052: if (regs.s == 0) regs.usp = regs.a[7];
1053: if (regs.s && regs.m) regs.msp = regs.a[7];
1054: if (regs.s && regs.m == 0) regs.isp = regs.a[7];
1055: printf("USP=%08lx ISP=%08lx MSP=%08lx VBR=%08lx\n",
1056: regs.usp,regs.isp,regs.msp,regs.vbr);
1057: printf ("T=%d%d S=%d M=%d X=%d N=%d Z=%d V=%d C=%d IMASK=%d\n",
1058: regs.t1, regs.t0, regs.s, regs.m,
1059: XFLG, NFLG, ZFLG, VFLG, CFLG, regs.intmask);
1060: for(i = 0; i < 8; i++){
1061: printf("FP%d: %g ", i, regs.fp[i]);
1062: if ((i & 3) == 3) printf("\n");
1063: }
1064: printf("N=%d Z=%d I=%d NAN=%d\n",
1065: (regs.fpsr & 0x8000000) != 0,
1066: (regs.fpsr & 0x4000000) != 0,
1067: (regs.fpsr & 0x2000000) != 0,
1068: (regs.fpsr & 0x1000000) != 0);
1069: m68k_disasm(m68k_getpc(), nextpc, 1);
1070: if (nextpc) printf("next PC: %08lx\n", *nextpc);
1071: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.