1 /*
2 * newcpu.cpp - CPU emulation
3 *
4 * Copyright (c) 2010 ARAnyM dev team (see AUTHORS)
5 *
6 *
7 * Inspired by Christian Bauer's Basilisk II
8 *
9 * This file is part of the ARAnyM project which builds a new and powerful
10 * TOS/FreeMiNT compatible virtual machine running on almost any hardware.
11 *
12 * ARAnyM is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * ARAnyM is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with ARAnyM; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 */
26 /*
27 * UAE - The Un*x Amiga Emulator
28 *
29 * MC68000 emulation
30 *
31 * (c) 1995 Bernd Schmidt
32 */
33
34 #include "sysdeps.h"
35 #include <cassert>
36
37 #include "cpu_emulation.h"
38 #include "main.h"
39 #include "emul_op.h"
40 #include "m68k.h"
41 #include "memory-uae.h"
42 #include "readcpu.h"
43 #include "newcpu.h"
44 #ifdef USE_JIT
45 # include "compiler/compemu.h"
46 #endif
47 #include "fpu/fpu.h"
48 #include "natfeats.h"
49 #include "disasm-glue.h"
50
51 #include <cstdlib>
52
53 #define DEBUG 0
54 #include "debug.h"
55
56 #define SANITY_CHECK_ATC 1
57
58 struct fixup fixup = {0, 0, 0};
59
60 int quit_program = 0;
61 int exit_val = 0;
62
63 // For instruction $7139
64 bool cpu_debugging = false;
65
66 struct flag_struct regflags;
67
68 /* LongJump buffers */
69 #ifdef EXCEPTIONS_VIA_LONGJMP
70 JMP_BUF excep_env;
71 #endif
72 /* Opcode of faulting instruction */
73 uae_u16 last_op_for_exception_3;
74 /* PC at fault time */
75 uaecptr last_addr_for_exception_3;
76 /* Address that generated the exception */
77 uaecptr last_fault_for_exception_3;
78
79 int areg_byteinc[] = { 1,1,1,1,1,1,1,2 };
80 int imm8_table[] = { 8,1,2,3,4,5,6,7 };
81
82 int movem_index1[256];
83 int movem_index2[256];
84 int movem_next[256];
85
86 #ifdef FLIGHT_RECORDER
87
88 // feel free to edit the following defines to customize the dump
89 #define FRLOG_HOTKEY 1 /* 1 = dump only when hotkey is held down */
90 #define FRLOG_ALL 1 /* 1 = dump continuously to ever growing log */
91 #define FRLOG_IRQ 0 /* 1 = dump also CPU in interrupts */
92 #define FRLOG_REGS 0 /* 1 = dump also all data/address registers */
93 #define FRLOG_SIZE 8192 /* this many instructions in single dump */
94
95 struct rec_step {
96 uae_u32 d[8];
97 uae_u32 a[8];
98 uae_u32 pc;
99 uae_u16 sr;
100 uae_u32 usp;
101 uae_u32 msp;
102 uae_u32 isp;
103 uae_u16 instr;
104 };
105
106 bool cpu_flight_recorder_active = false;
107
108 #if FRLOG_ALL
109 const int LOG_SIZE = 10;
110 #else
111 const int LOG_SIZE = FRLOG_SIZE;
112 #endif
113 static rec_step frlog[LOG_SIZE];
114 static int log_ptr = -1; // First time initialization
115
log_filename(void)116 static const char *log_filename(void)
117 {
118 const char *name = getenv("M68K_LOG_FILE");
119 return name ? name : "log.68k";
120 }
121
dump_flight_recorder(void)122 void dump_flight_recorder(void)
123 {
124 #if FRLOG_ALL
125 FILE *f = fopen(log_filename(), "a");
126 #else
127 FILE *f = fopen(log_filename(), "w");
128 #endif
129 if (f == NULL)
130 return;
131 for (int i = 0; i < LOG_SIZE; i++) {
132 int j = (i + log_ptr) % LOG_SIZE;
133 fprintf(f, "pc %08x instr %04x sr %04x usp %08x msp %08x isp %08x\n", frlog[j].pc, frlog[j].instr, frlog[j].sr, frlog[j].usp, frlog[j].msp, frlog[j].isp);
134 // adding a simple opcode -> assembler conversion table would help
135 #if FRLOG_REGS
136 fprintf(f, "d0 %08x d1 %08x d2 %08x d3 %08x\n", frlog[j].d[0], frlog[j].d[1], frlog[j].d[2], frlog[j].d[3]);
137 fprintf(f, "d4 %08x d5 %08x d6 %08x d7 %08x\n", frlog[j].d[4], frlog[j].d[5], frlog[j].d[6], frlog[j].d[7]);
138 fprintf(f, "a0 %08x a1 %08x a2 %08x a3 %08x\n", frlog[j].a[0], frlog[j].a[1], frlog[j].a[2], frlog[j].a[3]);
139 fprintf(f, "a4 %08x a5 %08x a6 %08x a7 %08x\n", frlog[j].a[4], frlog[j].a[5], frlog[j].a[6], frlog[j].a[7]);
140 #endif
141 m68k_disasm(f, frlog[j].pc, NULL, 1);
142 }
143 fclose(f);
144 }
145
m68k_record_step(uaecptr pc,int opcode)146 void m68k_record_step(uaecptr pc, int opcode)
147 {
148 static bool last_state = false;
149
150 #if FRLOG_HOTKEY
151 if (! cpu_flight_recorder_active) {
152 if (last_state) {
153 // dump log out
154 dump_flight_recorder();
155
156 // remember last state
157 last_state = false;
158 }
159 return;
160 }
161 #endif
162
163 if (! last_state) {
164 // reset old log
165 log_ptr = 0;
166 memset(frlog, 0, sizeof(frlog));
167 // remember last state
168 last_state = true;
169 }
170
171 #if FRLOG_REGS
172 for (int i = 0; i < 8; i++) {
173 frlog[log_ptr].d[i] = m68k_dreg(regs, i);
174 frlog[log_ptr].a[i] = m68k_areg(regs, i);
175 }
176 #endif
177 frlog[log_ptr].pc = pc;
178
179 MakeSR();
180 #if ! FRLOG_IRQ
181 // is CPU in interrupt handler? Quit if should not be logged.
182 if (regs.s && !regs.m) return;
183 #endif
184 frlog[log_ptr].sr = regs.sr;
185 frlog[log_ptr].usp = regs.usp;
186 frlog[log_ptr].msp = regs.msp;
187 frlog[log_ptr].isp = regs.isp;
188 frlog[log_ptr].instr = opcode;
189
190 log_ptr = (log_ptr + 1) % LOG_SIZE;
191 #if FRLOG_ALL
192 if (log_ptr == 0) dump_flight_recorder();
193 #endif
194 }
195 #endif /* FLIGHT_RECORDER */
196
197 int broken_in;
198
cft_map(unsigned int f)199 static inline unsigned int cft_map (unsigned int f)
200 {
201 #if !defined(HAVE_GET_WORD_UNSWAPPED) || defined(FULLMMU)
202 return f;
203 #else
204 return do_byteswap_16(f);
205 #endif
206 }
207
op_illg_1(uae_u32 opcode)208 void REGPARAM2 op_illg_1 (uae_u32 opcode)
209 {
210 op_illg (cft_map (opcode));
211 }
212
213
init_m68k(void)214 void init_m68k (void)
215 {
216 int i;
217
218 for (i = 0 ; i < 256 ; i++) {
219 int j;
220 for (j = 0 ; j < 8 ; j++) {
221 if (i & (1 << j)) break;
222 }
223 movem_index1[i] = j;
224 movem_index2[i] = 7-j;
225 movem_next[i] = i & (~(1 << j));
226 }
227 fpu_init (CPUType == 4);
228 }
229
exit_m68k(void)230 void exit_m68k (void)
231 {
232 fpu_exit ();
233 }
234
235 struct regstruct regs;
236 // MJ static struct regstruct regs_backup[16];
237 // MJ static int backup_pointer = 0;
238
239
240 #ifdef FULLMMU
get_ibyte_1(uae_u32 o)241 static inline uae_u8 get_ibyte_1(uae_u32 o)
242 {
243 return get_ibyte(o);
244 }
get_iword_1(uae_u32 o)245 static inline uae_u16 get_iword_1(uae_u32 o)
246 {
247 return get_iword(o);
248 }
get_ilong_1(uae_u32 o)249 static inline uae_u32 get_ilong_1(uae_u32 o)
250 {
251 return get_ilong(o);
252 }
253 #else
254 # define get_ibyte_1(o) get_byte(m68k_getpc() + (o) + 1)
255 # define get_iword_1(o) get_word(m68k_getpc() + (o))
256 # define get_ilong_1(o) get_long(m68k_getpc() + (o))
257 #endif
258
259 /*
260 * extract bitfield data from memory and return it in the MSBs
261 * bdata caches the unmodified data for put_bitfield()
262 */
get_bitfield(uae_u32 src,uae_u32 bdata[2],uae_s32 offset,int width)263 uae_u32 get_bitfield(uae_u32 src, uae_u32 bdata[2], uae_s32 offset, int width)
264 {
265 uae_u32 tmp, res, mask;
266
267 offset &= 7;
268 mask = 0xffffffffu << (32 - width);
269 switch ((offset + width + 7) >> 3) {
270 case 1:
271 tmp = get_byte(src);
272 res = tmp << (24 + offset);
273 bdata[0] = tmp & ~(mask >> (24 + offset));
274 break;
275 case 2:
276 tmp = get_word(src);
277 res = tmp << (16 + offset);
278 bdata[0] = tmp & ~(mask >> (16 + offset));
279 break;
280 case 3:
281 tmp = get_word(src);
282 res = tmp << (16 + offset);
283 bdata[0] = tmp & ~(mask >> (16 + offset));
284 tmp = get_byte(src + 2);
285 res |= tmp << (8 + offset);
286 bdata[1] = tmp & ~(mask >> (8 + offset));
287 break;
288 case 4:
289 tmp = get_long(src);
290 res = tmp << offset;
291 bdata[0] = tmp & ~(mask >> offset);
292 break;
293 case 5:
294 tmp = get_long(src);
295 res = tmp << offset;
296 bdata[0] = tmp & ~(mask >> offset);
297 tmp = get_byte(src + 4);
298 res |= tmp >> (8 - offset);
299 bdata[1] = tmp & ~(mask << (8 - offset));
300 break;
301 default:
302 /* Panic? */
303 res = 0;
304 break;
305 }
306 return res;
307 }
308
309 /*
310 * write bitfield data (in the LSBs) back to memory, upper bits
311 * must be cleared already.
312 */
put_bitfield(uae_u32 dst,uae_u32 bdata[2],uae_u32 val,uae_s32 offset,int width)313 void put_bitfield(uae_u32 dst, uae_u32 bdata[2], uae_u32 val, uae_s32 offset, int width)
314 {
315 offset = (offset & 7) + width;
316 switch ((offset + 7) >> 3) {
317 case 1:
318 put_byte(dst, bdata[0] | (val << (8 - offset)));
319 break;
320 case 2:
321 put_word(dst, bdata[0] | (val << (16 - offset)));
322 break;
323 case 3:
324 put_word(dst, bdata[0] | (val >> (offset - 16)));
325 put_byte(dst + 2, bdata[1] | (val << (24 - offset)));
326 break;
327 case 4:
328 put_long(dst, bdata[0] | (val << (32 - offset)));
329 break;
330 case 5:
331 put_long(dst, bdata[0] | (val >> (offset - 32)));
332 put_byte(dst + 4, bdata[1] | (val << (40 - offset)));
333 break;
334 }
335 }
336
get_disp_ea_020(uae_u32 base,uae_u32 dp)337 uae_u32 get_disp_ea_020 (uae_u32 base, uae_u32 dp)
338 {
339 int reg = (dp >> 12) & 15;
340 uae_s32 regd = regs.regs[reg];
341 if ((dp & 0x800) == 0)
342 regd = (uae_s32)(uae_s16)regd;
343 regd <<= (dp >> 9) & 3;
344 if (dp & 0x100) {
345 uae_s32 outer = 0;
346 if (dp & 0x80) base = 0;
347 if (dp & 0x40) regd = 0;
348
349 if ((dp & 0x30) == 0x20) base += (uae_s32)(uae_s16)next_iword();
350 if ((dp & 0x30) == 0x30) base += next_ilong();
351
352 if ((dp & 0x3) == 0x2) outer = (uae_s32)(uae_s16)next_iword();
353 if ((dp & 0x3) == 0x3) outer = next_ilong();
354
355 if ((dp & 0x4) == 0) base += regd;
356 if (dp & 0x3) base = get_long (base);
357 if (dp & 0x4) base += regd;
358
359 return base + outer;
360 } else {
361 return base + (uae_s32)((uae_s8)dp) + regd;
362 }
363 }
364
get_disp_ea_000(uae_u32 base,uae_u32 dp)365 uae_u32 get_disp_ea_000 (uae_u32 base, uae_u32 dp)
366 {
367 int reg = (dp >> 12) & 15;
368 uae_s32 regd = regs.regs[reg];
369 #if 1
370 if ((dp & 0x800) == 0)
371 regd = (uae_s32)(uae_s16)regd;
372 return base + (uae_s8)dp + regd;
373 #else
374 /* Branch-free code... benchmark this again now that
375 * things are no longer inline. */
376 uae_s32 regd16;
377 uae_u32 mask;
378 mask = ((dp & 0x800) >> 11) - 1;
379 regd16 = (uae_s32)(uae_s16)regd;
380 regd16 &= mask;
381 mask = ~mask;
382 base += (uae_s8)dp;
383 regd &= mask;
384 regd |= regd16;
385 return base + regd;
386 #endif
387 }
388
MakeSR(void)389 void MakeSR (void)
390 {
391 #if 0
392 assert((regs.t1 & 1) == regs.t1);
393 assert((regs.t0 & 1) == regs.t0);
394 assert((regs.s & 1) == regs.s);
395 assert((regs.m & 1) == regs.m);
396 assert((XFLG & 1) == XFLG);
397 assert((NFLG & 1) == NFLG);
398 assert((ZFLG & 1) == ZFLG);
399 assert((VFLG & 1) == VFLG);
400 assert((CFLG & 1) == CFLG);
401 #endif
402 regs.sr = ((regs.t1 << 15) | (regs.t0 << 14)
403 | (regs.s << 13) | (regs.m << 12) | (regs.intmask << 8)
404 | (GET_XFLG() << 4) | (GET_NFLG() << 3) | (GET_ZFLG() << 2) | (GET_VFLG() << 1)
405 | GET_CFLG());
406 }
407
MakeFromSR(void)408 void MakeFromSR (void)
409 {
410 int oldm = regs.m;
411 int olds = regs.s;
412
413 regs.t1 = (regs.sr >> 15) & 1;
414 regs.t0 = (regs.sr >> 14) & 1;
415 regs.s = (regs.sr >> 13) & 1;
416 mmu_set_super(regs.s);
417 regs.m = (regs.sr >> 12) & 1;
418 regs.intmask = (regs.sr >> 8) & 7;
419 SET_XFLG ((regs.sr >> 4) & 1);
420 SET_NFLG ((regs.sr >> 3) & 1);
421 SET_ZFLG ((regs.sr >> 2) & 1);
422 SET_VFLG ((regs.sr >> 1) & 1);
423 SET_CFLG (regs.sr & 1);
424 if (olds != regs.s) {
425 if (olds) {
426 if (oldm)
427 regs.msp = m68k_areg(regs, 7);
428 else
429 regs.isp = m68k_areg(regs, 7);
430 m68k_areg(regs, 7) = regs.usp;
431 } else {
432 regs.usp = m68k_areg(regs, 7);
433 m68k_areg(regs, 7) = regs.m ? regs.msp : regs.isp;
434 }
435 } else if (olds && oldm != regs.m) {
436 if (oldm) {
437 regs.msp = m68k_areg(regs, 7);
438 m68k_areg(regs, 7) = regs.isp;
439 } else {
440 regs.isp = m68k_areg(regs, 7);
441 m68k_areg(regs, 7) = regs.msp;
442 }
443 }
444
445 // SPCFLAGS_SET( SPCFLAG_INT );
446 if (regs.t1 || regs.t0)
447 SPCFLAGS_SET( SPCFLAG_TRACE );
448 else
449 SPCFLAGS_CLEAR( SPCFLAG_TRACE );
450 }
451
452 /* for building exception frames */
exc_push_word(uae_u16 w)453 static inline void exc_push_word(uae_u16 w)
454 {
455 m68k_areg(regs, 7) -= 2;
456 put_word(m68k_areg(regs, 7), w);
457 }
exc_push_long(uae_u32 l)458 static inline void exc_push_long(uae_u32 l)
459 {
460 m68k_areg(regs, 7) -= 4;
461 put_long (m68k_areg(regs, 7), l);
462 }
463
exc_make_frame(int format,uae_u16 sr,uae_u32 currpc,int nr,uae_u32 x0,uae_u32 x1)464 static inline void exc_make_frame(
465 int format,
466 uae_u16 sr,
467 uae_u32 currpc,
468 int nr,
469 uae_u32 x0,
470 uae_u32 x1
471 )
472 {
473 switch(format) {
474 case 4:
475 exc_push_long(x1);
476 exc_push_long(x0);
477 break;
478 case 3:
479 case 2:
480 exc_push_long(x0);
481 break;
482 }
483
484 exc_push_word((format << 12) + (nr * 4)); /* format | vector */
485 exc_push_long(currpc);
486 exc_push_word(sr);
487 }
488
489 #ifdef EXCEPTIONS_VIA_LONGJMP
490 static int building_bus_fault_stack_frame=0;
491 #endif
492
Exception(int nr,uaecptr oldpc)493 void Exception(int nr, uaecptr oldpc)
494 {
495 uae_u32 currpc = m68k_getpc ();
496 MakeSR();
497
498 if (fixup.flag)
499 {
500 m68k_areg(regs, fixup.reg) = fixup.value;
501 fixup.flag = 0;
502 }
503
504 if (!regs.s) {
505 regs.usp = m68k_areg(regs, 7);
506 m68k_areg(regs, 7) = regs.m ? regs.msp : regs.isp;
507 regs.s = 1;
508 mmu_set_super(1);
509 }
510
511 if (nr == 2) {
512 /* BUS ERROR handler begins */
513 #ifdef ENABLE_EPSLIMITER
514 check_eps_limit(currpc);
515 #endif
516 // panicbug("Exception Nr. %d CPC: %08x NPC: %08x SP=%08x Addr: %08x", nr, currpc, get_long (regs.vbr + 4*nr), m68k_areg(regs, 7), regs.mmu_fault_addr);
517 #ifdef EXCEPTIONS_VIA_LONGJMP
518 if (!building_bus_fault_stack_frame)
519 #else
520 try
521 #endif
522 {
523 #ifdef EXCEPTIONS_VIA_LONGJMP
524 building_bus_fault_stack_frame= 1;
525 #endif
526 /* 68040 */
527 exc_push_long(0); /* PD3 */
528 exc_push_long(0); /* PD2 */
529 exc_push_long(0); /* PD1 */
530 exc_push_long(0); /* PD0/WB1D */
531 exc_push_long(0); /* WB1A */
532 exc_push_long(0); /* WB2D */
533 exc_push_long(0); /* WB2A */
534 exc_push_long(regs.wb3_data); /* WB3D */
535 exc_push_long(regs.mmu_fault_addr); /* WB3A */
536 exc_push_long(regs.mmu_fault_addr);
537 exc_push_word(0); /* WB1S */
538 exc_push_word(0); /* WB2S */
539 exc_push_word(regs.wb3_status); /* WB3S */
540 regs.wb3_status = 0;
541 exc_push_word(regs.mmu_ssw);
542 exc_push_long(regs.mmu_fault_addr); /* EA */
543 exc_make_frame(7, regs.sr, regs.fault_pc, 2, 0, 0);
544
545 }
546 #ifdef EXCEPTIONS_VIA_LONGJMP
547 else
548 #else
549 catch (m68k_exception)
550 #endif
551 {
552 report_double_bus_error();
553 #ifdef EXCEPTIONS_VIA_LONGJMP
554 building_bus_fault_stack_frame= 0;
555 #endif
556 return;
557 }
558
559 #ifdef EXCEPTIONS_VIA_LONGJMP
560 building_bus_fault_stack_frame= 0;
561 #endif
562 /* end of BUS ERROR handler */
563 } else if (nr == 3) {
564 exc_make_frame(2, regs.sr, last_addr_for_exception_3, nr,
565 last_fault_for_exception_3 & 0xfffffffe, 0);
566 } else if (nr ==5 || nr == 6 || nr == 7 || nr == 9) {
567 /* div by zero, CHK, TRAP or TRACE */
568 exc_make_frame(2, regs.sr, currpc, nr, oldpc, 0);
569 } else if (regs.m && nr >= 24 && nr < 32) {
570 /* interrupts! */
571 exc_make_frame(0, regs.sr, currpc, nr, 0, 0);
572 regs.sr |= (1 << 13);
573 regs.msp = m68k_areg(regs, 7);
574 m68k_areg(regs, 7) = regs.isp;
575
576 exc_make_frame(1, /* throwaway */
577 regs.sr, currpc, nr, 0, 0);
578 } else {
579 exc_make_frame(0, regs.sr, currpc, nr, 0, 0);
580 }
581 m68k_setpc (get_long (regs.vbr + 4*nr));
582 SPCFLAGS_SET( SPCFLAG_JIT_END_COMPILE );
583 fill_prefetch_0 ();
584 regs.t1 = regs.t0 = regs.m = 0;
585 SPCFLAGS_CLEAR(SPCFLAG_TRACE | SPCFLAG_DOTRACE);
586 }
587
Interrupt(int nr)588 static void Interrupt(int nr)
589 {
590 assert(nr < 8 && nr >= 0);
591 Exception(nr+24, 0);
592
593 regs.intmask = nr;
594 // why the hell the SPCFLAG_INT is to be set??? (joy)
595 // regs.spcflags |= SPCFLAG_INT; (disabled by joy)
596 }
597
SCCInterrupt(int nr)598 static void SCCInterrupt(int nr)
599 {
600 // fprintf(stderr, "CPU: in SCCInterrupt\n");
601 Exception(nr, 0);
602
603 regs.intmask = 5;// ex 5
604 }
605
MFPInterrupt(int nr)606 static void MFPInterrupt(int nr)
607 {
608 // fprintf(stderr, "CPU: in MFPInterrupt\n");
609 Exception(nr, 0);
610
611 regs.intmask = 6;
612 }
613
m68k_move2c(int regno,uae_u32 * regp)614 int m68k_move2c (int regno, uae_u32 *regp)
615 {
616 switch (regno) {
617 case 0: regs.sfc = *regp & 7; break;
618 case 1: regs.dfc = *regp & 7; break;
619 case 2: regs.cacr = *regp & 0x80008000;
620 #ifdef USE_JIT
621 set_cache_state(regs.cacr & 0x8000);
622 if (*regp & 0x08) { /* Just to be on the safe side */
623 flush_icache(2);
624 }
625 #endif
626 break;
627 case 3: mmu_set_tc(*regp & 0xc000); break;
628 case 4:
629 case 5:
630 case 6:
631 case 7: mmu_set_ttr(regno, *regp & 0xffffe364); break;
632 case 0x800: regs.usp = *regp; break;
633 case 0x801: regs.vbr = *regp; break;
634 case 0x802: regs.caar = *regp & 0xfc; break;
635 case 0x803: regs.msp = *regp; if (regs.m == 1) m68k_areg(regs, 7) = regs.msp; break;
636 case 0x804: regs.isp = *regp; if (regs.m == 0) m68k_areg(regs, 7) = regs.isp; break;
637 case 0x805: mmu_set_mmusr(*regp); break;
638 case 0x806: regs.urp = *regp & MMU_ROOT_PTR_ADDR_MASK; break;
639 case 0x807: regs.srp = *regp & MMU_ROOT_PTR_ADDR_MASK; break;
640 default:
641 op_illg (0x4E7B);
642 return 0;
643 }
644 return 1;
645 }
646
m68k_movec2(int regno,uae_u32 * regp)647 int m68k_movec2 (int regno, uae_u32 *regp)
648 {
649 switch (regno) {
650 case 0: *regp = regs.sfc; break;
651 case 1: *regp = regs.dfc; break;
652 case 2: *regp = regs.cacr; break;
653 case 3: *regp = regs.tc; break;
654 case 4: *regp = regs.itt0; break;
655 case 5: *regp = regs.itt1; break;
656 case 6: *regp = regs.dtt0; break;
657 case 7: *regp = regs.dtt1; break;
658 case 0x800: *regp = regs.usp; break;
659 case 0x801: *regp = regs.vbr; break;
660 case 0x802: *regp = regs.caar; break;
661 case 0x803: *regp = regs.m == 1 ? m68k_areg(regs, 7) : regs.msp; break;
662 case 0x804: *regp = regs.m == 0 ? m68k_areg(regs, 7) : regs.isp; break;
663 case 0x805: *regp = regs.mmusr; break;
664 case 0x806: *regp = regs.urp; break;
665 case 0x807: *regp = regs.srp; break;
666 default:
667 op_illg (0x4E7A);
668 return 0;
669 }
670 return 1;
671 }
672
673 #if !defined(uae_s64)
674 static inline int
div_unsigned(uae_u32 src_hi,uae_u32 src_lo,uae_u32 div,uae_u32 * quot,uae_u32 * rem)675 div_unsigned(uae_u32 src_hi, uae_u32 src_lo, uae_u32 div, uae_u32 *quot, uae_u32 *rem)
676 {
677 uae_u32 q = 0, cbit = 0;
678 int i;
679
680 if (div <= src_hi) {
681 return 1;
682 }
683 for (i = 0 ; i < 32 ; i++) {
684 cbit = src_hi & 0x80000000ul;
685 src_hi <<= 1;
686 if (src_lo & 0x80000000ul) src_hi++;
687 src_lo <<= 1;
688 q = q << 1;
689 if (cbit || div <= src_hi) {
690 q |= 1;
691 src_hi -= div;
692 }
693 }
694 *quot = q;
695 *rem = src_hi;
696 return 0;
697 }
698 #endif
699
m68k_divl(uae_u32,uae_u32 src,uae_u16 extra,uaecptr oldpc)700 void m68k_divl (uae_u32 /*opcode*/, uae_u32 src, uae_u16 extra, uaecptr oldpc)
701 {
702 #if defined(uae_s64)
703 if (src == 0) {
704 Exception (5, oldpc);
705 return;
706 }
707 if (extra & 0x800) {
708 /* signed variant */
709 uae_s64 a = (uae_s64)(uae_s32)m68k_dreg(regs, (extra >> 12) & 7);
710 uae_s64 quot, rem;
711
712 if (extra & 0x400) {
713 a &= 0xffffffffu;
714 a |= (uae_s64)m68k_dreg(regs, extra & 7) << 32;
715 }
716 rem = a % (uae_s64)(uae_s32)src;
717 quot = a / (uae_s64)(uae_s32)src;
718 if ((quot & UVAL64(0xffffffff80000000)) != 0
719 && (quot & UVAL64(0xffffffff80000000)) != UVAL64(0xffffffff80000000))
720 {
721 SET_VFLG (1);
722 SET_NFLG (1);
723 SET_CFLG (0);
724 } else {
725 if (((uae_s32)rem < 0) != ((uae_s64)a < 0)) rem = -rem;
726 SET_VFLG (0);
727 SET_CFLG (0);
728 SET_ZFLG (((uae_s32)quot) == 0);
729 SET_NFLG (((uae_s32)quot) < 0);
730 m68k_dreg(regs, extra & 7) = rem;
731 m68k_dreg(regs, (extra >> 12) & 7) = quot;
732 }
733 } else {
734 /* unsigned */
735 uae_u64 a = (uae_u64)(uae_u32)m68k_dreg(regs, (extra >> 12) & 7);
736 uae_u64 quot, rem;
737
738 if (extra & 0x400) {
739 a &= 0xffffffffu;
740 a |= (uae_u64)m68k_dreg(regs, extra & 7) << 32;
741 }
742 rem = a % (uae_u64)src;
743 quot = a / (uae_u64)src;
744 if (quot > 0xffffffffu) {
745 SET_VFLG (1);
746 SET_NFLG (1);
747 SET_CFLG (0);
748 } else {
749 SET_VFLG (0);
750 SET_CFLG (0);
751 SET_ZFLG (((uae_s32)quot) == 0);
752 SET_NFLG (((uae_s32)quot) < 0);
753 m68k_dreg(regs, extra & 7) = rem;
754 m68k_dreg(regs, (extra >> 12) & 7) = quot;
755 }
756 }
757 #else
758 if (src == 0) {
759 Exception (5, oldpc);
760 return;
761 }
762 if (extra & 0x800) {
763 /* signed variant */
764 uae_s32 lo = (uae_s32)m68k_dreg(regs, (extra >> 12) & 7);
765 uae_s32 hi = lo < 0 ? -1 : 0;
766 uae_s32 save_high;
767 uae_u32 quot, rem;
768 uae_u32 sign;
769
770 if (extra & 0x400) {
771 hi = (uae_s32)m68k_dreg(regs, extra & 7);
772 }
773 save_high = hi;
774 sign = (hi ^ src);
775 if (hi < 0) {
776 hi = ~hi;
777 lo = -lo;
778 if (lo == 0) hi++;
779 }
780 if ((uae_s32)src < 0) src = -src;
781 if (div_unsigned(hi, lo, src, ", &rem) ||
782 (sign & 0x80000000) ? quot > 0x80000000 : quot > 0x7fffffff) {
783 SET_VFLG (1);
784 SET_NFLG (1);
785 SET_CFLG (0);
786 } else {
787 if (sign & 0x80000000) quot = -quot;
788 if (((uae_s32)rem < 0) != (save_high < 0)) rem = -rem;
789 SET_VFLG (0);
790 SET_CFLG (0);
791 SET_ZFLG (((uae_s32)quot) == 0);
792 SET_NFLG (((uae_s32)quot) < 0);
793 m68k_dreg(regs, extra & 7) = rem;
794 m68k_dreg(regs, (extra >> 12) & 7) = quot;
795 }
796 } else {
797 /* unsigned */
798 uae_u32 lo = (uae_u32)m68k_dreg(regs, (extra >> 12) & 7);
799 uae_u32 hi = 0;
800 uae_u32 quot, rem;
801
802 if (extra & 0x400) {
803 hi = (uae_u32)m68k_dreg(regs, extra & 7);
804 }
805 if (div_unsigned(hi, lo, src, ", &rem)) {
806 SET_VFLG (1);
807 SET_NFLG (1);
808 SET_CFLG (0);
809 } else {
810 SET_VFLG (0);
811 SET_CFLG (0);
812 SET_ZFLG (((uae_s32)quot) == 0);
813 SET_NFLG (((uae_s32)quot) < 0);
814 m68k_dreg(regs, extra & 7) = rem;
815 m68k_dreg(regs, (extra >> 12) & 7) = quot;
816 }
817 }
818 #endif
819 }
820
821 #if !defined(uae_s64)
822 static inline void
mul_unsigned(uae_u32 src1,uae_u32 src2,uae_u32 * dst_hi,uae_u32 * dst_lo)823 mul_unsigned(uae_u32 src1, uae_u32 src2, uae_u32 *dst_hi, uae_u32 *dst_lo)
824 {
825 uae_u32 r0 = (src1 & 0xffff) * (src2 & 0xffff);
826 uae_u32 r1 = ((src1 >> 16) & 0xffff) * (src2 & 0xffff);
827 uae_u32 r2 = (src1 & 0xffff) * ((src2 >> 16) & 0xffff);
828 uae_u32 r3 = ((src1 >> 16) & 0xffff) * ((src2 >> 16) & 0xffff);
829 uae_u32 lo;
830
831 lo = r0 + ((r1 << 16) & 0xffff0000ul);
832 if (lo < r0) r3++;
833 r0 = lo;
834 lo = r0 + ((r2 << 16) & 0xffff0000ul);
835 if (lo < r0) r3++;
836 r3 += ((r1 >> 16) & 0xffff) + ((r2 >> 16) & 0xffff);
837 *dst_lo = lo;
838 *dst_hi = r3;
839 }
840 #endif
841
m68k_mull(uae_u32,uae_u32 src,uae_u16 extra)842 void m68k_mull (uae_u32 /*opcode*/, uae_u32 src, uae_u16 extra)
843 {
844 #if defined(uae_s64)
845 if (extra & 0x800) {
846 /* signed variant */
847 uae_s64 a = (uae_s64)(uae_s32)m68k_dreg(regs, (extra >> 12) & 7);
848
849 a *= (uae_s64)(uae_s32)src;
850 SET_VFLG (0);
851 SET_CFLG (0);
852 SET_ZFLG (a == 0);
853 SET_NFLG (a < 0);
854 if (extra & 0x400)
855 m68k_dreg(regs, extra & 7) = a >> 32;
856 else if ((a & UVAL64(0xffffffff80000000)) != 0
857 && (a & UVAL64(0xffffffff80000000)) != UVAL64(0xffffffff80000000))
858 {
859 SET_VFLG (1);
860 }
861 m68k_dreg(regs, (extra >> 12) & 7) = (uae_u32)a;
862 } else {
863 /* unsigned */
864 uae_u64 a = (uae_u64)(uae_u32)m68k_dreg(regs, (extra >> 12) & 7);
865
866 a *= (uae_u64)src;
867 SET_VFLG (0);
868 SET_CFLG (0);
869 SET_ZFLG (a == 0);
870 SET_NFLG (((uae_s64)a) < 0);
871 if (extra & 0x400)
872 m68k_dreg(regs, extra & 7) = a >> 32;
873 else if ((a & UVAL64(0xffffffff00000000)) != 0) {
874 SET_VFLG (1);
875 }
876 m68k_dreg(regs, (extra >> 12) & 7) = (uae_u32)a;
877 }
878 #else
879 if (extra & 0x800) {
880 /* signed variant */
881 uae_s32 src1,src2;
882 uae_u32 dst_lo,dst_hi;
883 uae_u32 sign;
884
885 src1 = (uae_s32)src;
886 src2 = (uae_s32)m68k_dreg(regs, (extra >> 12) & 7);
887 sign = (src1 ^ src2);
888 if (src1 < 0) src1 = -src1;
889 if (src2 < 0) src2 = -src2;
890 mul_unsigned((uae_u32)src1,(uae_u32)src2,&dst_hi,&dst_lo);
891 if (sign & 0x80000000) {
892 dst_hi = ~dst_hi;
893 dst_lo = -dst_lo;
894 if (dst_lo == 0) dst_hi++;
895 }
896 SET_VFLG (0);
897 SET_CFLG (0);
898 SET_ZFLG (dst_hi == 0 && dst_lo == 0);
899 SET_NFLG (((uae_s32)dst_hi) < 0);
900 if (extra & 0x400)
901 m68k_dreg(regs, extra & 7) = dst_hi;
902 else if ((dst_hi != 0 || (dst_lo & 0x80000000) != 0)
903 && ((dst_hi & 0xffffffff) != 0xffffffff
904 || (dst_lo & 0x80000000) != 0x80000000))
905 {
906 SET_VFLG (1);
907 }
908 m68k_dreg(regs, (extra >> 12) & 7) = dst_lo;
909 } else {
910 /* unsigned */
911 uae_u32 dst_lo,dst_hi;
912
913 mul_unsigned(src,(uae_u32)m68k_dreg(regs, (extra >> 12) & 7),&dst_hi,&dst_lo);
914
915 SET_VFLG (0);
916 SET_CFLG (0);
917 SET_ZFLG (dst_hi == 0 && dst_lo == 0);
918 SET_NFLG (((uae_s32)dst_hi) < 0);
919 if (extra & 0x400)
920 m68k_dreg(regs, extra & 7) = dst_hi;
921 else if (dst_hi != 0) {
922 SET_VFLG (1);
923 }
924 m68k_dreg(regs, (extra >> 12) & 7) = dst_lo;
925 }
926 #endif
927 }
928
929 // If value is greater than zero, this means we are still processing an EmulOp
930 // because the counter is incremented only in m68k_execute(), i.e. interpretive
931 // execution only
932 #ifdef USE_JIT
933 static int m68k_execute_depth = 0;
934 #endif
935
m68k_reset(void)936 void m68k_reset (void)
937 {
938 regs.s = 1;
939 regs.m = 0;
940 regs.stopped = 0;
941 regs.t1 = 0;
942 regs.t0 = 0;
943 SET_ZFLG (0);
944 SET_XFLG (0);
945 SET_CFLG (0);
946 SET_VFLG (0);
947 SET_NFLG (0);
948 SPCFLAGS_INIT( 0 );
949 regs.intmask = 7;
950 regs.vbr = regs.sfc = regs.dfc = 0;
951
952 // need to ensure the following order of initialization is correct
953 // (it is definitely better than what it was before this commit
954 // since it was reading from 0x00000000 in User mode and with active MMU)
955 mmu_set_tc(regs.tc & ~0x8000); /* disable mmu */
956 m68k_areg (regs, 7) = phys_get_long(0x00000000);
957 m68k_setpc (phys_get_long(0x00000004));
958 fill_prefetch_0 ();
959
960 /* gb-- moved into {fpp,fpu_x86}.cpp::fpu_init()
961 regs.fpcr = regs.fpsr = regs.fpiar = 0; */
962 fpu_reset();
963 // MMU
964 mmu_reset();
965 mmu_set_super(1);
966 // Cache
967 regs.cacr = 0;
968 regs.caar = 0;
969 #ifdef FLIGHT_RECORDER
970 log_ptr = 0;
971 memset(frlog, 0, sizeof(frlog));
972 #endif
973 }
974
m68k_emulop_return(void)975 void m68k_emulop_return(void)
976 {
977 SPCFLAGS_SET( SPCFLAG_BRK );
978 quit_program = 1;
979 }
980
save_regs(struct M68kRegisters & r)981 static void save_regs(struct M68kRegisters &r)
982 {
983 int i;
984
985 for (i=0; i<8; i++) {
986 r.d[i] = m68k_dreg(regs, i);
987 r.a[i] = m68k_areg(regs, i);
988 }
989 r.pc = m68k_getpc();
990 MakeSR();
991 r.sr = regs.sr;
992 r.isp = regs.isp;
993 r.usp = regs.usp;
994 r.msp = regs.msp;
995 if ((r.sr & 0x2000) == 0)
996 r.usp = r.a[7];
997 else if ((r.sr & 0x1000) != 0)
998 r.msp = r.a[7];
999 else
1000 r.isp = r.a[7];
1001 }
1002
restore_regs(struct M68kRegisters & r)1003 static void restore_regs(struct M68kRegisters &r)
1004 {
1005 int i;
1006
1007 for (i=0; i<8; i++) {
1008 m68k_dreg(regs, i) = r.d[i];
1009 m68k_areg(regs, i) = r.a[i];
1010 }
1011 regs.isp = r.isp;
1012 regs.usp = r.usp;
1013 regs.msp = r.msp;
1014 regs.sr = r.sr;
1015 MakeFromSR();
1016 }
1017
m68k_emulop(uae_u32 opcode)1018 void m68k_emulop(uae_u32 opcode)
1019 {
1020 struct M68kRegisters r;
1021 save_regs(r);
1022 if (EmulOp(opcode, &r))
1023 restore_regs(r);
1024 }
1025
m68k_natfeat_id(void)1026 void m68k_natfeat_id(void)
1027 {
1028 struct M68kRegisters r;
1029
1030 /* is it really necessary to save all registers? */
1031 save_regs(r);
1032
1033 memptr stack = r.a[7] + 4; /* skip return address */
1034 r.d[0] = nf_get_id(stack);
1035
1036 restore_regs(r);
1037 }
1038
m68k_natfeat_call(void)1039 void m68k_natfeat_call(void)
1040 {
1041 struct M68kRegisters r;
1042
1043 /* is it really necessary to save all registers? */
1044 save_regs(r);
1045
1046 memptr stack = r.a[7] + 4; /* skip return address */
1047 bool isSupervisorMode = ((r.sr & 0x2000) == 0x2000);
1048 r.d[0] = nf_call(stack, isSupervisorMode);
1049
1050 restore_regs(r);
1051 }
1052
m68k_call(uae_u32 pc)1053 static int m68k_call(uae_u32 pc)
1054 {
1055 VOLATILE int exc = 0;
1056 m68k_setpc(pc);
1057 TRY(prb) {
1058 #ifdef USE_JIT
1059 if (bx_options.jit.jit) {
1060 exec_nostats();
1061 // m68k_do_compile_execute();
1062 // The above call to m68k_do_compile_execute fails with BadAccess in sigsegv_handler (MAC, if it is executed after the first compile_block)
1063 // (NULL pointer to addr_instr).
1064 // Call exec_nostats avoids calling compile_block, because stack modification is only temporary
1065 // which will fill up compile cache with BOGUS data.
1066 // we can call exec_nostats directly, do our code, and return back here.
1067 }
1068 else
1069 #endif
1070 m68k_do_execute();
1071 }
1072 CATCH(prb) {
1073 exc = int(prb);
1074 }
1075 return exc;
1076 }
1077
m68k_alloca(int size)1078 static uae_u32 m68k_alloca(int size)
1079 {
1080 uae_u32 sp = (m68k_areg(regs, 7) - size) & ~1;
1081 m68k_areg(regs, 7) = sp;
1082 if ((regs.sr & 0x2000) == 0)
1083 regs.usp = sp;
1084 else if ((regs.sr & 0x1000) != 0)
1085 regs.msp = sp;
1086 else
1087 regs.isp = sp;
1088 return sp;
1089 }
1090
linea68000(volatile uae_u16 opcode)1091 uae_u32 linea68000(volatile uae_u16 opcode)
1092 {
1093 sigjmp_buf jmp;
1094 struct M68kRegisters r;
1095 volatile uae_u32 abase = 0;
1096
1097 SAVE_EXCEPTION;
1098 save_regs(r);
1099
1100 const int sz = 8 + sizeof(void *);
1101 volatile uae_u32 sp = 0;
1102 uae_u32 backup[(sz + 3) / 4];
1103
1104 if (sigsetjmp(jmp, 1) == 0)
1105 {
1106 void *p = jmp;
1107 uae_u8 *sp_p;
1108 int exc;
1109
1110 sp = m68k_alloca(sz);
1111 memcpy(backup, phys_get_real_address(sp), sz);
1112
1113 WriteHWMemInt16(sp, opcode);
1114 WriteHWMemInt16(sp + 2, 0xa0ff);
1115 WriteHWMemInt32(sp + 4, 13);
1116 sp_p = phys_get_real_address(sp + 8);
1117 *((void **)sp_p) = p;
1118 if ((exc = m68k_call(sp)) != 0)
1119 {
1120 panicbug("exception %d in LINEA", exc);
1121 m68k_dreg(regs, 0) = 0;
1122 }
1123 } else
1124 {
1125 abase = m68k_dreg(regs, 0);
1126 }
1127
1128 if (sp) {
1129 memcpy(phys_get_real_address(sp), backup, sz);
1130 }
1131 restore_regs(r);
1132 m68k_setpc(r.pc);
1133 RESTORE_EXCEPTION;
1134 return abase;
1135 }
1136
1137
rts68000()1138 static void rts68000()
1139 {
1140 uae_u32 SP = m68k_getpc() + 6;
1141 sigjmp_buf *p;
1142 uae_u8 *sp_p = phys_get_real_address(SP);
1143
1144 p = (sigjmp_buf *)(*((void **)sp_p));
1145 SP += sizeof(void *);
1146 m68k_areg(regs, 7) = SP;
1147 siglongjmp(*p, 1);
1148 }
1149
op_illg(uae_u32 opcode)1150 void REGPARAM2 op_illg (uae_u32 opcode)
1151 {
1152 uaecptr pc = m68k_getpc ();
1153
1154 if ((opcode & 0xF000) == 0xA000) {
1155 if (opcode == 0xa0ff)
1156 {
1157 uae_u32 call = ReadHWMemInt32(pc + 2);
1158 switch (call)
1159 {
1160 case 13:
1161 rts68000();
1162 return;
1163 }
1164 m68k_setpc(pc + 6);
1165 }
1166 Exception(0xA,0);
1167 return;
1168 }
1169
1170 if ((opcode & 0xF000) == 0xF000) {
1171 Exception(0xB,0);
1172 return;
1173 }
1174
1175 D(bug("Illegal instruction: %04x at %08x", opcode, pc));
1176 #if defined(USE_JIT) && defined(JIT_DEBUG)
1177 compiler_dumpstate();
1178 #endif
1179
1180 Exception (4,0);
1181 return;
1182 }
1183
1184 static uaecptr last_trace_ad = 0;
1185
do_trace(void)1186 static void do_trace (void)
1187 {
1188 if (regs.t0) {
1189 uae_u16 opcode;
1190 /* should also include TRAP, CHK, SR modification FPcc */
1191 /* probably never used so why bother */
1192 /* We can afford this to be inefficient... */
1193 m68k_setpc (m68k_getpc ());
1194 fill_prefetch_0 ();
1195 opcode = get_word(m68k_getpc());
1196 if (opcode == 0x4e72 /* RTE */
1197 || opcode == 0x4e74 /* RTD */
1198 || opcode == 0x4e75 /* RTS */
1199 || opcode == 0x4e77 /* RTR */
1200 || opcode == 0x4e76 /* TRAPV */
1201 || (opcode & 0xffc0) == 0x4e80 /* JSR */
1202 || (opcode & 0xffc0) == 0x4ec0 /* JMP */
1203 || (opcode & 0xff00) == 0x6100 /* BSR */
1204 || ((opcode & 0xf000) == 0x6000 /* Bcc */
1205 && cctrue((opcode >> 8) & 0xf))
1206 || ((opcode & 0xf0f0) == 0x5050 /* DBcc */
1207 && !cctrue((opcode >> 8) & 0xf)
1208 && (uae_s16)m68k_dreg(regs, opcode & 7) != 0))
1209 {
1210 last_trace_ad = m68k_getpc ();
1211 SPCFLAGS_CLEAR( SPCFLAG_TRACE );
1212 SPCFLAGS_SET( SPCFLAG_DOTRACE );
1213 }
1214 } else if (regs.t1) {
1215 last_trace_ad = m68k_getpc ();
1216 SPCFLAGS_CLEAR( SPCFLAG_TRACE );
1217 SPCFLAGS_SET( SPCFLAG_DOTRACE );
1218 }
1219 }
1220
1221 #define SERVE_VBL_MFP(resetStop) \
1222 { \
1223 if (SPCFLAGS_TEST( SPCFLAG_INT3|SPCFLAG_VBL|SPCFLAG_INT5|SPCFLAG_SCC|SPCFLAG_MFP )) { \
1224 if (SPCFLAGS_TEST( SPCFLAG_INT3 )) { \
1225 if (3 > regs.intmask) { \
1226 Interrupt(3); \
1227 regs.stopped = 0; \
1228 SPCFLAGS_CLEAR( SPCFLAG_INT3 ); \
1229 if (resetStop) \
1230 SPCFLAGS_CLEAR( SPCFLAG_STOP ); \
1231 } \
1232 } \
1233 if (SPCFLAGS_TEST( SPCFLAG_VBL )) { \
1234 if (4 > regs.intmask) { \
1235 Interrupt(4); \
1236 regs.stopped = 0; \
1237 SPCFLAGS_CLEAR( SPCFLAG_VBL ); \
1238 if (resetStop) \
1239 SPCFLAGS_CLEAR( SPCFLAG_STOP ); \
1240 } \
1241 } \
1242 if (SPCFLAGS_TEST( SPCFLAG_INT5 )) { \
1243 if (5 > regs.intmask) { \
1244 Interrupt(5); \
1245 regs.stopped = 0; \
1246 SPCFLAGS_CLEAR( SPCFLAG_INT5 ); \
1247 if (resetStop) \
1248 SPCFLAGS_CLEAR( SPCFLAG_STOP ); \
1249 } \
1250 } \
1251 if (SPCFLAGS_TEST( SPCFLAG_SCC )) { \
1252 if (5 > regs.intmask) { \
1253 int vector_number=SCCdoInterrupt(); \
1254 if(vector_number){ \
1255 SCCInterrupt(vector_number); \
1256 regs.stopped = 0; \
1257 SPCFLAGS_CLEAR( SPCFLAG_SCC); \
1258 if (resetStop) \
1259 SPCFLAGS_CLEAR( SPCFLAG_STOP ); \
1260 } \
1261 else \
1262 SPCFLAGS_CLEAR( SPCFLAG_SCC ); \
1263 } \
1264 } \
1265 if (SPCFLAGS_TEST( SPCFLAG_MFP )) { \
1266 if (6 > regs.intmask) { \
1267 int vector_number = MFPdoInterrupt(); \
1268 if (vector_number) { \
1269 MFPInterrupt(vector_number); \
1270 regs.stopped = 0; \
1271 if (resetStop) \
1272 SPCFLAGS_CLEAR( SPCFLAG_STOP ); \
1273 } \
1274 else \
1275 SPCFLAGS_CLEAR( SPCFLAG_MFP ); \
1276 } \
1277 } \
1278 } \
1279 }
1280
1281 #define SERVE_INTERNAL_IRQ() \
1282 { \
1283 if (SPCFLAGS_TEST( SPCFLAG_INTERNAL_IRQ )) { \
1284 SPCFLAGS_CLEAR( SPCFLAG_INTERNAL_IRQ ); \
1285 invoke200HzInterrupt(); \
1286 } \
1287 }
1288
m68k_do_specialties(void)1289 int m68k_do_specialties(void)
1290 {
1291 SERVE_INTERNAL_IRQ();
1292 #ifdef USE_JIT
1293 // Block was compiled
1294 SPCFLAGS_CLEAR( SPCFLAG_JIT_END_COMPILE );
1295
1296 // Retain the request to get out of compiled code until
1297 // we reached the toplevel execution, i.e. the one that
1298 // can compile then run compiled code. This also means
1299 // we processed all (nested) EmulOps
1300 if ((m68k_execute_depth == 0) && SPCFLAGS_TEST( SPCFLAG_JIT_EXEC_RETURN ))
1301 SPCFLAGS_CLEAR( SPCFLAG_JIT_EXEC_RETURN );
1302 #endif
1303 /*n_spcinsns++;*/
1304 if (SPCFLAGS_TEST( SPCFLAG_DOTRACE )) {
1305 Exception (9,last_trace_ad);
1306 }
1307 #if 0 /* not for ARAnyM; emulating 040 only */
1308 if ((regs.spcflags & SPCFLAG_STOP) && regs.s == 0 && currprefs.cpu_model <= 68010) {
1309 // 68000/68010 undocumented special case:
1310 // if STOP clears S-bit and T was not set:
1311 // cause privilege violation exception, PC pointing to following instruction.
1312 // If T was set before STOP: STOP works as documented.
1313 m68k_unset_stop();
1314 Exception(8, 0);
1315 }
1316 #endif
1317 while (SPCFLAGS_TEST( SPCFLAG_STOP )) {
1318 if ((regs.sr & 0x700) == 0x700)
1319 {
1320 panicbug("STOPed with interrupts disabled, exiting; pc=$%08x", m68k_getpc());
1321 m68k_dumpstate (stderr, NULL);
1322 #if 0
1323 quit_program = 1;
1324 #endif
1325 #ifdef FULL_HISTORY
1326 ndebug::showHistory(20, false);
1327 m68k_dumpstate (stderr, NULL);
1328 #endif
1329 return 1;
1330 }
1331 // give unused time slices back to OS
1332 SleepAndWait();
1333
1334 SERVE_INTERNAL_IRQ();
1335 SERVE_VBL_MFP(true);
1336 if (SPCFLAGS_TEST( SPCFLAG_BRK ))
1337 break;
1338 }
1339 if (SPCFLAGS_TEST( SPCFLAG_TRACE ))
1340 do_trace ();
1341
1342 SERVE_VBL_MFP(false);
1343
1344 /*
1345 // do not understand the INT vs DOINT stuff so I disabled it (joy)
1346 if (regs.spcflags & SPCFLAG_INT) {
1347 regs.spcflags &= ~SPCFLAG_INT;
1348 regs.spcflags |= SPCFLAG_DOINT;
1349 }
1350 */
1351 if (SPCFLAGS_TEST( SPCFLAG_BRK /*| SPCFLAG_MODE_CHANGE*/ )) {
1352 SPCFLAGS_CLEAR( SPCFLAG_BRK /*| SPCFLAG_MODE_CHANGE*/ );
1353 return 1;
1354 }
1355
1356 return 0;
1357 }
1358
m68k_do_execute(void)1359 void m68k_do_execute (void)
1360 {
1361 uae_u32 pc;
1362 uae_u32 opcode;
1363 for (;;) {
1364 regs.fault_pc = pc = m68k_getpc();
1365 #ifdef FULL_HISTORY
1366 #ifdef NEED_TO_DEBUG_BADLY
1367 history[lasthist] = regs;
1368 historyf[lasthist] = regflags;
1369 #else
1370 history[lasthist] = m68k_getpc();
1371 #endif
1372 if (++lasthist == MAX_HIST) lasthist = 0;
1373 if (lasthist == firsthist) {
1374 if (++firsthist == MAX_HIST) firsthist = 0;
1375 }
1376 #endif
1377
1378 #ifndef FULLMMU
1379 #ifdef ARAM_PAGE_CHECK
1380 if (((pc ^ pc_page) > ARAM_PAGE_MASK)) {
1381 check_ram_boundary(pc, 2, false);
1382 pc_page = pc;
1383 pc_offset = (uintptr)get_real_address(pc, 0, sz_word) - pc;
1384 }
1385 #else
1386 check_ram_boundary(pc, 2, false);
1387 #endif
1388 #endif
1389 opcode = GET_OPCODE;
1390 #ifdef FLIGHT_RECORDER
1391 m68k_record_step(m68k_getpc(), cft_map(opcode));
1392 #endif
1393 (*cpufunctbl[opcode])(opcode);
1394 cpu_check_ticks();
1395 regs.fault_pc = m68k_getpc();
1396
1397 if (SPCFLAGS_TEST(SPCFLAG_ALL_BUT_EXEC_RETURN)) {
1398 if (m68k_do_specialties())
1399 return;
1400 }
1401 }
1402 }
1403
m68k_execute(void)1404 void m68k_execute (void)
1405 {
1406 #ifdef USE_JIT
1407 m68k_execute_depth++;
1408 #endif
1409 #ifdef DEBUGGER
1410 VOLATILE bool after_exception = false;
1411 #endif
1412
1413 setjmpagain:
1414 TRY(prb) {
1415 for (;;) {
1416 if (quit_program > 0) {
1417 if (quit_program == 1) {
1418 #ifdef FLIGHT_RECORDER
1419 dump_flight_recorder();
1420 #endif
1421 break;
1422 }
1423 quit_program = 0;
1424 m68k_reset ();
1425 }
1426 #ifdef DEBUGGER
1427 if (debugging && !after_exception) debug();
1428 after_exception = false;
1429 #endif
1430 m68k_do_execute();
1431 }
1432 }
1433 CATCH(prb) {
1434 Exception(prb, 0);
1435 #ifdef DEBUGGER
1436 after_exception = true;
1437 #endif
1438 goto setjmpagain;
1439 }
1440
1441 #ifdef USE_JIT
1442 m68k_execute_depth--;
1443 #endif
1444 }
1445
m68k_disasm(FILE * f,uaecptr addr,uaecptr * nextpc,int cnt)1446 void m68k_disasm (FILE *f, uaecptr addr, uaecptr *nextpc, int cnt)
1447 {
1448 #ifdef HAVE_DISASM_M68K
1449 char buf[256];
1450 int size;
1451
1452 disasm_info.memory_vma = addr;
1453 while (cnt-- > 0) {
1454 size = m68k_disasm_to_buf(&disasm_info, buf, 1);
1455 fprintf(f, "%s\n", buf);
1456 if (size < 0)
1457 break;
1458 }
1459 if (nextpc)
1460 *nextpc = disasm_info.memory_vma;
1461 #else
1462 if (nextpc)
1463 *nextpc = addr;
1464 (void) f;
1465 (void) cnt;
1466 #endif
1467 }
1468
1469 #ifdef DEBUGGER
newm68k_disasm(FILE * f,uaecptr addr,uaecptr * nextpc,unsigned int cnt)1470 void newm68k_disasm(FILE *f, uaecptr addr, uaecptr *nextpc, unsigned int cnt)
1471 {
1472 #ifdef HAVE_DISASM_M68K
1473 char buf[256];
1474
1475 disasm_info.memory_vma = addr;
1476 if (cnt == 0) {
1477 m68k_disasm_to_buf(&disasm_info, buf, 1);
1478 } else {
1479 while (cnt-- > 0) {
1480 m68k_disasm_to_buf(&disasm_info, buf, 1);
1481 fprintf(f, "%s\n", buf);
1482 }
1483 }
1484 if (nextpc)
1485 *nextpc = disasm_info.memory_vma;
1486 #else
1487 if (nextpc)
1488 *nextpc = addr;
1489 (void) cnt;
1490 #endif
1491 }
1492
1493 #endif /* DEBUGGER */
1494
1495 #ifdef FULL_HISTORY
showDisasm(uaecptr addr)1496 void showDisasm(uaecptr addr) {
1497 #ifdef HAVE_DISASM_M68K
1498 char buf[256];
1499
1500 disasm_info.memory_vma = addr;
1501 m68k_disasm_to_buf(&disasm_info, buf, 1);
1502 bug("%s", buf);
1503 #else
1504 (void) addr;
1505 #endif
1506 }
1507 #endif /* FULL_HISTORY */
1508
m68k_dumpstate(FILE * out,uaecptr * nextpc)1509 void m68k_dumpstate (FILE *out, uaecptr *nextpc)
1510 {
1511 int i;
1512 for (i = 0; i < 8; i++){
1513 fprintf (out, "D%d: %08lx ", i, (unsigned long)m68k_dreg(regs, i));
1514 if ((i & 3) == 3) fprintf (out, "\n");
1515 }
1516 for (i = 0; i < 8; i++){
1517 fprintf (out, "A%d: %08lx ", i, (unsigned long)m68k_areg(regs, i));
1518 if ((i & 3) == 3) fprintf (out, "\n");
1519 }
1520 if (regs.s == 0) regs.usp = m68k_areg(regs, 7);
1521 if (regs.s && regs.m) regs.msp = m68k_areg(regs, 7);
1522 if (regs.s && regs.m == 0) regs.isp = m68k_areg(regs, 7);
1523 fprintf (out, "USP=%08lx ISP=%08lx MSP=%08lx VBR=%08lx\n",
1524 (unsigned long)regs.usp, (unsigned long)regs.isp,
1525 (unsigned long)regs.msp, (unsigned long)regs.vbr);
1526 fprintf (out, "T=%d%d S=%d M=%d X=%d N=%d Z=%d V=%d C=%d IMASK=%d TCE=%d TCP=%d\n",
1527 regs.t1, regs.t0, regs.s, regs.m,
1528 (int)GET_XFLG(), (int)GET_NFLG(), (int)GET_ZFLG(), (int)GET_VFLG(), (int)GET_CFLG(), regs.intmask,
1529 regs.mmu_enabled, regs.mmu_pagesize_8k);
1530 fprintf (out, "CACR=%08lx CAAR=%08lx URP=%08lx SRP=%08lx\n",
1531 (unsigned long)regs.cacr,
1532 (unsigned long)regs.caar,
1533 (unsigned long)regs.urp,
1534 (unsigned long)regs.srp);
1535 fprintf (out, "DTT0=%08lx DTT1=%08lx ITT0=%08lx ITT1=%08lx\n",
1536 (unsigned long)regs.dtt0,
1537 (unsigned long)regs.dtt1,
1538 (unsigned long)regs.itt0,
1539 (unsigned long)regs.itt1);
1540 for (i = 0; i < 8; i++){
1541 fprintf (out, "FP%d: %g ", i, (double)fpu.registers[i]);
1542 if ((i & 3) == 3) fprintf (out, "\n");
1543 }
1544 #if 0
1545 fprintf (out, "N=%d Z=%d I=%d NAN=%d\n",
1546 (regs.fpsr & 0x8000000) != 0,
1547 (regs.fpsr & 0x4000000) != 0,
1548 (regs.fpsr & 0x2000000) != 0,
1549 (regs.fpsr & 0x1000000) != 0);
1550 #endif
1551 m68k_disasm(out, m68k_getpc (), nextpc, 1);
1552 if (nextpc)
1553 fprintf (out, "next PC: %08lx\n", (unsigned long)*nextpc);
1554 }
1555