1 |
< |
/* |
2 |
< |
* UAE - The Un*x Amiga Emulator |
3 |
< |
* |
4 |
< |
* MC68000 emulation |
5 |
< |
* |
6 |
< |
* (c) 1995 Bernd Schmidt |
7 |
< |
*/ |
1 |
> |
/* |
2 |
> |
* UAE - The Un*x Amiga Emulator |
3 |
> |
* |
4 |
> |
* MC68000 emulation |
5 |
> |
* |
6 |
> |
* (c) 1995 Bernd Schmidt |
7 |
> |
* |
8 |
> |
* This program is free software; you can redistribute it and/or modify |
9 |
> |
* it under the terms of the GNU General Public License as published by |
10 |
> |
* the Free Software Foundation; either version 2 of the License, or |
11 |
> |
* (at your option) any later version. |
12 |
> |
* |
13 |
> |
* This program is distributed in the hope that it will be useful, |
14 |
> |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 |
> |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 |
> |
* GNU General Public License for more details. |
17 |
> |
* |
18 |
> |
* You should have received a copy of the GNU General Public License |
19 |
> |
* along with this program; if not, write to the Free Software |
20 |
> |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 |
> |
*/ |
22 |
|
|
23 |
|
#include <stdio.h> |
24 |
|
#include <stdlib.h> |
36 |
|
#include "memory.h" |
37 |
|
#include "readcpu.h" |
38 |
|
#include "newcpu.h" |
39 |
< |
#include "compiler.h" |
39 |
> |
#include "compiler/compemu.h" |
40 |
> |
#include "fpu/fpu.h" |
41 |
> |
|
42 |
> |
#if defined(ENABLE_EXCLUSIVE_SPCFLAGS) && !defined(HAVE_HARDWARE_LOCKS) |
43 |
> |
B2_mutex *spcflags_lock = NULL; |
44 |
> |
#endif |
45 |
> |
|
46 |
> |
#if ENABLE_MON |
47 |
> |
#include "mon.h" |
48 |
> |
#include "mon_disass.h" |
49 |
> |
#endif |
50 |
|
|
51 |
< |
int quit_program = 0; |
28 |
< |
int debugging = 0; |
51 |
> |
bool quit_program = false; |
52 |
|
struct flag_struct regflags; |
53 |
|
|
54 |
|
/* Opcode of faulting instruction */ |
65 |
|
int movem_index2[256]; |
66 |
|
int movem_next[256]; |
67 |
|
|
45 |
– |
int fpp_movem_index1[256]; |
46 |
– |
int fpp_movem_index2[256]; |
47 |
– |
int fpp_movem_next[256]; |
48 |
– |
|
68 |
|
cpuop_func *cpufunctbl[65536]; |
69 |
|
|
70 |
+ |
#if FLIGHT_RECORDER |
71 |
+ |
struct rec_step { |
72 |
+ |
uae_u32 pc; |
73 |
+ |
#if FLIGHT_RECORDER >= 2 |
74 |
+ |
uae_u32 d[8]; |
75 |
+ |
uae_u32 a[8]; |
76 |
+ |
#endif |
77 |
+ |
}; |
78 |
+ |
|
79 |
+ |
const int LOG_SIZE = 32768; |
80 |
+ |
static rec_step log[LOG_SIZE]; |
81 |
+ |
static int log_ptr = -1; // First time initialization |
82 |
+ |
|
83 |
+ |
static const char *log_filename(void) |
84 |
+ |
{ |
85 |
+ |
const char *name = getenv("M68K_LOG_FILE"); |
86 |
+ |
return name ? name : "log.68k"; |
87 |
+ |
} |
88 |
+ |
|
89 |
+ |
void m68k_record_step(uaecptr pc) |
90 |
+ |
{ |
91 |
+ |
#if FLIGHT_RECORDER >= 2 |
92 |
+ |
/* XXX: if LSB is set, we are recording from generated code and we |
93 |
+ |
don't support registers recording yet. */ |
94 |
+ |
if ((pc & 1) == 0) { |
95 |
+ |
for (int i = 0; i < 8; i++) { |
96 |
+ |
log[log_ptr].d[i] = m68k_dreg(regs, i); |
97 |
+ |
log[log_ptr].a[i] = m68k_areg(regs, i); |
98 |
+ |
} |
99 |
+ |
} |
100 |
+ |
#endif |
101 |
+ |
log[log_ptr].pc = pc; |
102 |
+ |
log_ptr = (log_ptr + 1) % LOG_SIZE; |
103 |
+ |
} |
104 |
+ |
|
105 |
+ |
static void dump_log(void) |
106 |
+ |
{ |
107 |
+ |
FILE *f = fopen(log_filename(), "w"); |
108 |
+ |
if (f == NULL) |
109 |
+ |
return; |
110 |
+ |
for (int i = 0; i < LOG_SIZE; i++) { |
111 |
+ |
int j = (i + log_ptr) % LOG_SIZE; |
112 |
+ |
uae_u32 pc = log[j].pc & ~1; |
113 |
+ |
fprintf(f, "pc %08x", pc); |
114 |
+ |
#if FLIGHT_RECORDER >= 2 |
115 |
+ |
fprintf(f, "\n"); |
116 |
+ |
if ((log[j].pc & 1) == 0) { |
117 |
+ |
fprintf(f, "d0 %08x d1 %08x d2 %08x d3 %08x\n", log[j].d[0], log[j].d[1], log[j].d[2], log[j].d[3]); |
118 |
+ |
fprintf(f, "d4 %08x d5 %08x d6 %08x d7 %08x\n", log[j].d[4], log[j].d[5], log[j].d[6], log[j].d[7]); |
119 |
+ |
fprintf(f, "a0 %08x a1 %08x a2 %08x a3 %08x\n", log[j].a[0], log[j].a[1], log[j].a[2], log[j].a[3]); |
120 |
+ |
fprintf(f, "a4 %08x a5 %08x a6 %08x a7 %08x\n", log[j].a[4], log[j].a[5], log[j].a[6], log[j].a[7]); |
121 |
+ |
} |
122 |
+ |
#else |
123 |
+ |
fprintf(f, " | "); |
124 |
+ |
#endif |
125 |
+ |
#if ENABLE_MON |
126 |
+ |
disass_68k(f, pc); |
127 |
+ |
#endif |
128 |
+ |
} |
129 |
+ |
fclose(f); |
130 |
+ |
} |
131 |
+ |
#endif |
132 |
+ |
|
133 |
+ |
#if ENABLE_MON |
134 |
+ |
static void dump_regs(void) |
135 |
+ |
{ |
136 |
+ |
m68k_dumpstate(NULL); |
137 |
+ |
} |
138 |
+ |
#endif |
139 |
+ |
|
140 |
|
#define COUNT_INSTRS 0 |
141 |
|
|
142 |
|
#if COUNT_INSTRS |
200 |
|
#endif |
201 |
|
} |
202 |
|
|
203 |
< |
static unsigned long REGPARAM2 op_illg_1 (uae_u32 opcode) REGPARAM; |
203 |
> |
void REGPARAM2 op_illg_1 (uae_u32 opcode) REGPARAM; |
204 |
|
|
205 |
< |
static unsigned long REGPARAM2 op_illg_1 (uae_u32 opcode) |
205 |
> |
void REGPARAM2 op_illg_1 (uae_u32 opcode) |
206 |
|
{ |
207 |
|
op_illg (cft_map (opcode)); |
119 |
– |
return 4; |
208 |
|
} |
209 |
|
|
210 |
|
static void build_cpufunctbl (void) |
211 |
|
{ |
212 |
|
int i; |
213 |
|
unsigned long opcode; |
214 |
< |
int cpu_level = (FPUType ? 3 : CPUType >= 2 ? 2 : CPUType == 1 ? 1 : 0); |
215 |
< |
struct cputbl *tbl = (cpu_level == 3 ? op_smalltbl_0 |
216 |
< |
: cpu_level == 2 ? op_smalltbl_1 |
217 |
< |
: cpu_level == 1 ? op_smalltbl_2 |
218 |
< |
: op_smalltbl_3); |
214 |
> |
int cpu_level = 0; // 68000 (default) |
215 |
> |
if (CPUType == 4) |
216 |
> |
cpu_level = 4; // 68040 with FPU |
217 |
> |
else { |
218 |
> |
if (FPUType) |
219 |
> |
cpu_level = 3; // 68020 with FPU |
220 |
> |
else if (CPUType >= 2) |
221 |
> |
cpu_level = 2; // 68020 |
222 |
> |
else if (CPUType == 1) |
223 |
> |
cpu_level = 1; |
224 |
> |
} |
225 |
> |
struct cputbl *tbl = ( |
226 |
> |
cpu_level == 4 ? op_smalltbl_0_ff |
227 |
> |
: cpu_level == 3 ? op_smalltbl_1_ff |
228 |
> |
: cpu_level == 2 ? op_smalltbl_2_ff |
229 |
> |
: cpu_level == 1 ? op_smalltbl_3_ff |
230 |
> |
: op_smalltbl_4_ff); |
231 |
|
|
232 |
|
for (opcode = 0; opcode < 65536; opcode++) |
233 |
|
cpufunctbl[cft_map (opcode)] = op_illg_1; |
267 |
|
movem_index2[i] = 7-j; |
268 |
|
movem_next[i] = i & (~(1 << j)); |
269 |
|
} |
170 |
– |
for (i = 0 ; i < 256 ; i++) { |
171 |
– |
int j; |
172 |
– |
for (j = 7 ; j >= 0 ; j--) { |
173 |
– |
if (i & (1 << j)) break; |
174 |
– |
} |
175 |
– |
fpp_movem_index1[i] = j; |
176 |
– |
fpp_movem_index2[i] = 7-j; |
177 |
– |
fpp_movem_next[i] = i & (~(1 << j)); |
178 |
– |
} |
270 |
|
#if COUNT_INSTRS |
271 |
|
{ |
272 |
|
FILE *f = fopen (icountfilename (), "r"); |
287 |
|
do_merges (); |
288 |
|
|
289 |
|
build_cpufunctbl (); |
290 |
+ |
|
291 |
+ |
#if defined(ENABLE_EXCLUSIVE_SPCFLAGS) && !defined(HAVE_HARDWARE_LOCKS) |
292 |
+ |
spcflags_lock = B2_create_mutex(); |
293 |
+ |
#endif |
294 |
+ |
fpu_init(CPUType == 4); |
295 |
+ |
} |
296 |
+ |
|
297 |
+ |
void exit_m68k (void) |
298 |
+ |
{ |
299 |
+ |
fpu_exit (); |
300 |
+ |
#if defined(ENABLE_EXCLUSIVE_SPCFLAGS) && !defined(HAVE_HARDWARE_LOCKS) |
301 |
+ |
B2_delete_mutex(spcflags_lock); |
302 |
+ |
#endif |
303 |
|
} |
304 |
|
|
305 |
|
struct regstruct regs, lastint_regs; |
308 |
|
static long int m68kpc_offset; |
309 |
|
int lastint_no; |
310 |
|
|
311 |
+ |
#if REAL_ADDRESSING || DIRECT_ADDRESSING |
312 |
+ |
#define get_ibyte_1(o) get_byte(get_virtual_address(regs.pc_p) + (o) + 1) |
313 |
+ |
#define get_iword_1(o) get_word(get_virtual_address(regs.pc_p) + (o)) |
314 |
+ |
#define get_ilong_1(o) get_long(get_virtual_address(regs.pc_p) + (o)) |
315 |
+ |
#else |
316 |
|
#define get_ibyte_1(o) get_byte(regs.pc + (regs.pc_p - regs.pc_oldp) + (o) + 1) |
317 |
|
#define get_iword_1(o) get_word(regs.pc + (regs.pc_p - regs.pc_oldp) + (o)) |
318 |
|
#define get_ilong_1(o) get_long(regs.pc + (regs.pc_p - regs.pc_oldp) + (o)) |
319 |
+ |
#endif |
320 |
|
|
321 |
|
uae_s32 ShowEA (int reg, amodes mode, wordsizes size, char *buf) |
322 |
|
{ |
349 |
|
disp16 = get_iword_1 (m68kpc_offset); m68kpc_offset += 2; |
350 |
|
addr = m68k_areg(regs,reg) + (uae_s16)disp16; |
351 |
|
sprintf (buffer,"(A%d,$%04x) == $%08lx", reg, disp16 & 0xffff, |
352 |
< |
(long unsigned int)addr); |
352 |
> |
(unsigned long)addr); |
353 |
|
break; |
354 |
|
case Ad8r: |
355 |
|
dp = get_iword_1 (m68kpc_offset); m68kpc_offset += 2; |
382 |
|
dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W', |
383 |
|
1 << ((dp >> 9) & 3), |
384 |
|
disp,outer, |
385 |
< |
(long unsigned int)addr); |
385 |
> |
(unsigned long)addr); |
386 |
|
} else { |
387 |
|
addr = m68k_areg(regs,reg) + (uae_s32)((uae_s8)disp8) + dispreg; |
388 |
|
sprintf (buffer,"(A%d, %c%d.%c*%d, $%02x) == $%08lx", reg, |
389 |
|
dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W', |
390 |
|
1 << ((dp >> 9) & 3), disp8, |
391 |
< |
(long unsigned int)addr); |
391 |
> |
(unsigned long)addr); |
392 |
|
} |
393 |
|
break; |
394 |
|
case PC16: |
395 |
|
addr = m68k_getpc () + m68kpc_offset; |
396 |
|
disp16 = get_iword_1 (m68kpc_offset); m68kpc_offset += 2; |
397 |
|
addr += (uae_s16)disp16; |
398 |
< |
sprintf (buffer,"(PC,$%04x) == $%08lx", disp16 & 0xffff,(long unsigned int)addr); |
398 |
> |
sprintf (buffer,"(PC,$%04x) == $%08lx", disp16 & 0xffff,(unsigned long)addr); |
399 |
|
break; |
400 |
|
case PC8r: |
401 |
|
addr = m68k_getpc () + m68kpc_offset; |
429 |
|
dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W', |
430 |
|
1 << ((dp >> 9) & 3), |
431 |
|
disp,outer, |
432 |
< |
(long unsigned int)addr); |
432 |
> |
(unsigned long)addr); |
433 |
|
} else { |
434 |
|
addr += (uae_s32)((uae_s8)disp8) + dispreg; |
435 |
|
sprintf (buffer,"(PC, %c%d.%c*%d, $%02x) == $%08lx", dp & 0x8000 ? 'A' : 'D', |
436 |
|
(int)r, dp & 0x800 ? 'L' : 'W', 1 << ((dp >> 9) & 3), |
437 |
< |
disp8, (long unsigned int)addr); |
437 |
> |
disp8, (unsigned long)addr); |
438 |
|
} |
439 |
|
break; |
440 |
|
case absw: |
441 |
< |
sprintf (buffer,"$%08lx", (long unsigned int)(uae_s32)(uae_s16)get_iword_1 (m68kpc_offset)); |
441 |
> |
sprintf (buffer,"$%08lx", (unsigned long)(uae_s32)(uae_s16)get_iword_1 (m68kpc_offset)); |
442 |
|
m68kpc_offset += 2; |
443 |
|
break; |
444 |
|
case absl: |
445 |
< |
sprintf (buffer,"$%08lx", (long unsigned int)get_ilong_1 (m68kpc_offset)); |
445 |
> |
sprintf (buffer,"$%08lx", (unsigned long)get_ilong_1 (m68kpc_offset)); |
446 |
|
m68kpc_offset += 4; |
447 |
|
break; |
448 |
|
case imm: |
456 |
|
m68kpc_offset += 2; |
457 |
|
break; |
458 |
|
case sz_long: |
459 |
< |
sprintf (buffer,"#$%08lx", (long unsigned int)(get_ilong_1 (m68kpc_offset))); |
459 |
> |
sprintf (buffer,"#$%08lx", (unsigned long)(get_ilong_1 (m68kpc_offset))); |
460 |
|
m68kpc_offset += 4; |
461 |
|
break; |
462 |
|
default: |
476 |
|
case imm2: |
477 |
|
offset = (uae_s32)get_ilong_1 (m68kpc_offset); |
478 |
|
m68kpc_offset += 4; |
479 |
< |
sprintf (buffer,"#$%08lx", (long unsigned int)offset); |
479 |
> |
sprintf (buffer,"#$%08lx", (unsigned long)offset); |
480 |
|
break; |
481 |
|
case immi: |
482 |
|
offset = (uae_s32)(uae_s8)(reg & 0xff); |
483 |
< |
sprintf (buffer,"#$%08lx", (long unsigned int)offset); |
483 |
> |
sprintf (buffer,"#$%08lx", (unsigned long)offset); |
484 |
|
break; |
485 |
|
default: |
486 |
|
break; |
735 |
|
} |
736 |
|
} |
737 |
|
|
738 |
< |
regs.spcflags |= SPCFLAG_INT; |
738 |
> |
SPCFLAGS_SET( SPCFLAG_INT ); |
739 |
|
if (regs.t1 || regs.t0) |
740 |
< |
regs.spcflags |= SPCFLAG_TRACE; |
740 |
> |
SPCFLAGS_SET( SPCFLAG_TRACE ); |
741 |
|
else |
742 |
< |
regs.spcflags &= ~(SPCFLAG_TRACE | SPCFLAG_DOTRACE); |
742 |
> |
/* Keep SPCFLAG_DOTRACE, we still want a trace exception for |
743 |
> |
SR-modifying instructions (including STOP). */ |
744 |
> |
SPCFLAGS_CLEAR( SPCFLAG_TRACE ); |
745 |
|
} |
746 |
|
|
747 |
|
void Exception(int nr, uaecptr oldpc) |
748 |
|
{ |
749 |
< |
compiler_flush_jsr_stack(); |
749 |
> |
uae_u32 currpc = m68k_getpc (); |
750 |
|
MakeSR(); |
751 |
|
if (!regs.s) { |
752 |
|
regs.usp = m68k_areg(regs, 7); |
775 |
|
m68k_areg(regs, 7) -= 2; |
776 |
|
put_word (m68k_areg(regs, 7), nr * 4); |
777 |
|
m68k_areg(regs, 7) -= 4; |
778 |
< |
put_long (m68k_areg(regs, 7), m68k_getpc ()); |
778 |
> |
put_long (m68k_areg(regs, 7), currpc); |
779 |
|
m68k_areg(regs, 7) -= 2; |
780 |
|
put_word (m68k_areg(regs, 7), regs.sr); |
781 |
|
regs.sr |= (1 << 13); |
801 |
|
} |
802 |
|
} |
803 |
|
m68k_areg(regs, 7) -= 4; |
804 |
< |
put_long (m68k_areg(regs, 7), m68k_getpc ()); |
804 |
> |
put_long (m68k_areg(regs, 7), currpc); |
805 |
|
kludge_me_do: |
806 |
|
m68k_areg(regs, 7) -= 2; |
807 |
|
put_word (m68k_areg(regs, 7), regs.sr); |
808 |
|
m68k_setpc (get_long (regs.vbr + 4*nr)); |
809 |
+ |
SPCFLAGS_SET( SPCFLAG_JIT_END_COMPILE ); |
810 |
|
fill_prefetch_0 (); |
811 |
|
regs.t1 = regs.t0 = regs.m = 0; |
812 |
< |
regs.spcflags &= ~(SPCFLAG_TRACE | SPCFLAG_DOTRACE); |
812 |
> |
SPCFLAGS_CLEAR( SPCFLAG_TRACE | SPCFLAG_DOTRACE ); |
813 |
|
} |
814 |
|
|
815 |
|
static void Interrupt(int nr) |
820 |
|
Exception(nr+24, 0); |
821 |
|
|
822 |
|
regs.intmask = nr; |
823 |
< |
regs.spcflags |= SPCFLAG_INT; |
823 |
> |
SPCFLAGS_SET( SPCFLAG_INT ); |
824 |
|
} |
825 |
|
|
826 |
< |
static int caar, cacr; |
826 |
> |
static int caar, cacr, tc, itt0, itt1, dtt0, dtt1, mmusr, urp, srp; |
827 |
> |
|
828 |
> |
static int movec_illg (int regno) |
829 |
> |
{ |
830 |
> |
switch (CPUType) { |
831 |
> |
case 1: |
832 |
> |
if ((regno & 0x7ff) <= 1) |
833 |
> |
return 0; |
834 |
> |
break; |
835 |
> |
case 2: |
836 |
> |
case 3: |
837 |
> |
if ((regno & 0x7ff) <= 2) |
838 |
> |
return 0; |
839 |
> |
if (regno == 3 || regno == 4) |
840 |
> |
return 0; |
841 |
> |
break; |
842 |
> |
case 4: |
843 |
> |
if ((regno & 0x7ff) <= 7) { |
844 |
> |
if (regno != 0x802) |
845 |
> |
return 0; |
846 |
> |
} |
847 |
> |
break; |
848 |
> |
} |
849 |
> |
return 1; |
850 |
> |
} |
851 |
|
|
852 |
< |
void m68k_move2c (int regno, uae_u32 *regp) |
852 |
> |
int m68k_move2c (int regno, uae_u32 *regp) |
853 |
|
{ |
854 |
< |
if (CPUType == 1 && (regno & 0x7FF) > 1) |
854 |
> |
if (movec_illg (regno)) { |
855 |
|
op_illg (0x4E7B); |
856 |
< |
else |
856 |
> |
return 0; |
857 |
> |
} else { |
858 |
|
switch (regno) { |
859 |
|
case 0: regs.sfc = *regp & 7; break; |
860 |
|
case 1: regs.dfc = *regp & 7; break; |
861 |
< |
case 2: cacr = *regp & 0x3; break; /* ignore C and CE */ |
861 |
> |
case 2: |
862 |
> |
cacr = *regp & (CPUType < 4 ? 0x3 : 0x80008000); |
863 |
> |
#if USE_JIT |
864 |
> |
if (CPUType < 4) { |
865 |
> |
set_cache_state(cacr&1); |
866 |
> |
if (*regp & 0x08) |
867 |
> |
flush_icache(1); |
868 |
> |
} |
869 |
> |
else { |
870 |
> |
set_cache_state(cacr&0x8000); |
871 |
> |
} |
872 |
> |
#endif |
873 |
> |
break; |
874 |
> |
case 3: tc = *regp & 0xc000; break; |
875 |
> |
case 4: itt0 = *regp & 0xffffe364; break; |
876 |
> |
case 5: itt1 = *regp & 0xffffe364; break; |
877 |
> |
case 6: dtt0 = *regp & 0xffffe364; break; |
878 |
> |
case 7: dtt1 = *regp & 0xffffe364; break; |
879 |
|
case 0x800: regs.usp = *regp; break; |
880 |
|
case 0x801: regs.vbr = *regp; break; |
881 |
|
case 0x802: caar = *regp &0xfc; break; |
882 |
|
case 0x803: regs.msp = *regp; if (regs.m == 1) m68k_areg(regs, 7) = regs.msp; break; |
883 |
|
case 0x804: regs.isp = *regp; if (regs.m == 0) m68k_areg(regs, 7) = regs.isp; break; |
884 |
+ |
case 0x805: mmusr = *regp; break; |
885 |
+ |
case 0x806: urp = *regp; break; |
886 |
+ |
case 0x807: srp = *regp; break; |
887 |
|
default: |
888 |
|
op_illg (0x4E7B); |
889 |
< |
break; |
889 |
> |
return 0; |
890 |
|
} |
891 |
+ |
} |
892 |
+ |
return 1; |
893 |
|
} |
894 |
|
|
895 |
< |
void m68k_movec2 (int regno, uae_u32 *regp) |
895 |
> |
int m68k_movec2 (int regno, uae_u32 *regp) |
896 |
|
{ |
897 |
< |
if (CPUType == 1 && (regno & 0x7FF) > 1) |
897 |
> |
if (movec_illg (regno)) |
898 |
> |
{ |
899 |
|
op_illg (0x4E7A); |
900 |
< |
else |
900 |
> |
return 0; |
901 |
> |
} else { |
902 |
|
switch (regno) { |
903 |
|
case 0: *regp = regs.sfc; break; |
904 |
|
case 1: *regp = regs.dfc; break; |
905 |
|
case 2: *regp = cacr; break; |
906 |
+ |
case 3: *regp = tc; break; |
907 |
+ |
case 4: *regp = itt0; break; |
908 |
+ |
case 5: *regp = itt1; break; |
909 |
+ |
case 6: *regp = dtt0; break; |
910 |
+ |
case 7: *regp = dtt1; break; |
911 |
|
case 0x800: *regp = regs.usp; break; |
912 |
|
case 0x801: *regp = regs.vbr; break; |
913 |
|
case 0x802: *regp = caar; break; |
914 |
|
case 0x803: *regp = regs.m == 1 ? m68k_areg(regs, 7) : regs.msp; break; |
915 |
|
case 0x804: *regp = regs.m == 0 ? m68k_areg(regs, 7) : regs.isp; break; |
916 |
+ |
case 0x805: *regp = mmusr; break; |
917 |
+ |
case 0x806: *regp = urp; break; |
918 |
+ |
case 0x807: *regp = srp; break; |
919 |
|
default: |
920 |
|
op_illg (0x4E7A); |
921 |
< |
break; |
921 |
> |
return 0; |
922 |
|
} |
923 |
+ |
} |
924 |
+ |
return 1; |
925 |
|
} |
926 |
|
|
927 |
|
static __inline__ int |
1179 |
|
{ "T ","F ","HI","LS","CC","CS","NE","EQ", |
1180 |
|
"VC","VS","PL","MI","GE","LT","GT","LE" }; |
1181 |
|
|
1182 |
+ |
// If value is greater than zero, this means we are still processing an EmulOp |
1183 |
+ |
// because the counter is incremented only in m68k_execute(), i.e. interpretive |
1184 |
+ |
// execution only |
1185 |
+ |
static int m68k_execute_depth = 0; |
1186 |
+ |
|
1187 |
|
void m68k_reset (void) |
1188 |
|
{ |
1189 |
|
m68k_areg (regs, 7) = 0x2000; |
1190 |
|
m68k_setpc (ROMBaseMac + 0x2a); |
1191 |
|
fill_prefetch_0 (); |
1015 |
– |
regs.kick_mask = 0xF80000; |
1192 |
|
regs.s = 1; |
1193 |
|
regs.m = 0; |
1194 |
|
regs.stopped = 0; |
1199 |
|
SET_CFLG (0); |
1200 |
|
SET_VFLG (0); |
1201 |
|
SET_NFLG (0); |
1202 |
< |
regs.spcflags = 0; |
1202 |
> |
SPCFLAGS_INIT( 0 ); |
1203 |
|
regs.intmask = 7; |
1204 |
|
regs.vbr = regs.sfc = regs.dfc = 0; |
1205 |
< |
regs.fpcr = regs.fpsr = regs.fpiar = 0; |
1205 |
> |
fpu_reset(); |
1206 |
> |
|
1207 |
> |
#if FLIGHT_RECORDER |
1208 |
> |
log_ptr = 0; |
1209 |
> |
memset(log, 0, sizeof(log)); |
1210 |
> |
#endif |
1211 |
> |
|
1212 |
> |
#if ENABLE_MON |
1213 |
> |
static bool first_time = true; |
1214 |
> |
if (first_time) { |
1215 |
> |
first_time = false; |
1216 |
> |
mon_add_command("regs", dump_regs, "regs Dump m68k emulator registers\n"); |
1217 |
> |
#if FLIGHT_RECORDER |
1218 |
> |
// Install "log" command in mon |
1219 |
> |
mon_add_command("log", dump_log, "log Dump m68k emulation log\n"); |
1220 |
> |
#endif |
1221 |
> |
} |
1222 |
> |
#endif |
1223 |
|
} |
1224 |
|
|
1225 |
< |
unsigned long REGPARAM2 op_illg (uae_u32 opcode) |
1225 |
> |
void m68k_emulop_return(void) |
1226 |
|
{ |
1227 |
< |
uaecptr pc = m68k_getpc (); |
1228 |
< |
|
1229 |
< |
compiler_flush_jsr_stack (); |
1227 |
> |
SPCFLAGS_SET( SPCFLAG_BRK ); |
1228 |
> |
quit_program = true; |
1229 |
> |
} |
1230 |
|
|
1231 |
< |
if ((opcode & 0xFF00) == 0x7100) { |
1231 |
> |
void m68k_emulop(uae_u32 opcode) |
1232 |
> |
{ |
1233 |
|
struct M68kRegisters r; |
1234 |
|
int i; |
1235 |
|
|
1042 |
– |
// Return from Execute68k()? |
1043 |
– |
if (opcode == M68K_EXEC_RETURN) { |
1044 |
– |
regs.spcflags |= SPCFLAG_BRK; |
1045 |
– |
quit_program = 1; |
1046 |
– |
return 4; |
1047 |
– |
} |
1048 |
– |
|
1049 |
– |
// Call EMUL_OP opcode |
1236 |
|
for (i=0; i<8; i++) { |
1237 |
|
r.d[i] = m68k_dreg(regs, i); |
1238 |
|
r.a[i] = m68k_areg(regs, i); |
1246 |
|
} |
1247 |
|
regs.sr = r.sr; |
1248 |
|
MakeFromSR(); |
1249 |
< |
m68k_incpc(2); |
1250 |
< |
fill_prefetch_0 (); |
1251 |
< |
return 4; |
1252 |
< |
} |
1249 |
> |
} |
1250 |
> |
|
1251 |
> |
void REGPARAM2 op_illg (uae_u32 opcode) |
1252 |
> |
{ |
1253 |
> |
uaecptr pc = m68k_getpc (); |
1254 |
|
|
1255 |
|
if ((opcode & 0xF000) == 0xA000) { |
1256 |
|
Exception(0xA,0); |
1257 |
< |
return 4; |
1257 |
> |
return; |
1258 |
|
} |
1259 |
|
|
1260 |
|
if ((opcode & 0xF000) == 0xF000) { |
1261 |
|
Exception(0xB,0); |
1262 |
< |
return 4; |
1262 |
> |
return; |
1263 |
|
} |
1264 |
|
|
1265 |
|
write_log ("Illegal instruction: %04x at %08lx\n", opcode, pc); |
1266 |
+ |
#if USE_JIT && JIT_DEBUG |
1267 |
+ |
compiler_dumpstate(); |
1268 |
+ |
#endif |
1269 |
+ |
|
1270 |
|
Exception (4,0); |
1271 |
< |
return 4; |
1271 |
> |
return; |
1272 |
|
} |
1273 |
|
|
1274 |
|
void mmu_op(uae_u32 opcode, uae_u16 extra) |
1275 |
|
{ |
1276 |
< |
if ((extra & 0xB000) == 0) { /* PMOVE instruction */ |
1277 |
< |
|
1278 |
< |
} else if ((extra & 0xF000) == 0x2000) { /* PLOAD instruction */ |
1279 |
< |
} else if ((extra & 0xF000) == 0x8000) { /* PTEST instruction */ |
1276 |
> |
if ((opcode & 0xFE0) == 0x0500) { |
1277 |
> |
/* PFLUSH */ |
1278 |
> |
mmusr = 0; |
1279 |
> |
} else if ((opcode & 0x0FD8) == 0x548) { |
1280 |
> |
/* PTEST */ |
1281 |
|
} else |
1282 |
< |
op_illg (opcode); |
1282 |
> |
op_illg (opcode); |
1283 |
|
} |
1284 |
|
|
1285 |
|
static int n_insns = 0, n_spcinsns = 0; |
1288 |
|
|
1289 |
|
static void do_trace (void) |
1290 |
|
{ |
1291 |
< |
if (regs.t0) { |
1291 |
> |
if (regs.t0 && CPUType >= 2) { |
1292 |
|
uae_u16 opcode; |
1293 |
|
/* should also include TRAP, CHK, SR modification FPcc */ |
1294 |
|
/* probably never used so why bother */ |
1295 |
|
/* We can afford this to be inefficient... */ |
1296 |
|
m68k_setpc (m68k_getpc ()); |
1297 |
|
fill_prefetch_0 (); |
1298 |
< |
opcode = get_word (regs.pc); |
1298 |
> |
opcode = get_word(m68k_getpc()); |
1299 |
|
if (opcode == 0x4e72 /* RTE */ |
1300 |
|
|| opcode == 0x4e74 /* RTD */ |
1301 |
|
|| opcode == 0x4e75 /* RTS */ |
1311 |
|
&& (uae_s16)m68k_dreg(regs, opcode & 7) != 0)) |
1312 |
|
{ |
1313 |
|
last_trace_ad = m68k_getpc (); |
1314 |
< |
regs.spcflags &= ~SPCFLAG_TRACE; |
1315 |
< |
regs.spcflags |= SPCFLAG_DOTRACE; |
1314 |
> |
SPCFLAGS_CLEAR( SPCFLAG_TRACE ); |
1315 |
> |
SPCFLAGS_SET( SPCFLAG_DOTRACE ); |
1316 |
|
} |
1317 |
|
} else if (regs.t1) { |
1318 |
|
last_trace_ad = m68k_getpc (); |
1319 |
< |
regs.spcflags &= ~SPCFLAG_TRACE; |
1320 |
< |
regs.spcflags |= SPCFLAG_DOTRACE; |
1319 |
> |
SPCFLAGS_CLEAR( SPCFLAG_TRACE ); |
1320 |
> |
SPCFLAGS_SET( SPCFLAG_DOTRACE ); |
1321 |
|
} |
1322 |
|
} |
1323 |
|
|
1324 |
< |
|
1133 |
< |
static int do_specialties (void) |
1324 |
> |
int m68k_do_specialties (void) |
1325 |
|
{ |
1326 |
< |
/*n_spcinsns++;*/ |
1327 |
< |
run_compiled_code(); |
1328 |
< |
if (regs.spcflags & SPCFLAG_DOTRACE) { |
1326 |
> |
#if USE_JIT |
1327 |
> |
// Block was compiled |
1328 |
> |
SPCFLAGS_CLEAR( SPCFLAG_JIT_END_COMPILE ); |
1329 |
> |
|
1330 |
> |
// Retain the request to get out of compiled code until |
1331 |
> |
// we reached the toplevel execution, i.e. the one that |
1332 |
> |
// can compile then run compiled code. This also means |
1333 |
> |
// we processed all (nested) EmulOps |
1334 |
> |
if ((m68k_execute_depth == 0) && SPCFLAGS_TEST( SPCFLAG_JIT_EXEC_RETURN )) |
1335 |
> |
SPCFLAGS_CLEAR( SPCFLAG_JIT_EXEC_RETURN ); |
1336 |
> |
#endif |
1337 |
> |
|
1338 |
> |
if (SPCFLAGS_TEST( SPCFLAG_DOTRACE )) { |
1339 |
|
Exception (9,last_trace_ad); |
1340 |
|
} |
1341 |
< |
while (regs.spcflags & SPCFLAG_STOP) { |
1342 |
< |
if (regs.spcflags & (SPCFLAG_INT | SPCFLAG_DOINT)){ |
1341 |
> |
while (SPCFLAGS_TEST( SPCFLAG_STOP )) { |
1342 |
> |
if (SPCFLAGS_TEST( SPCFLAG_INT | SPCFLAG_DOINT )){ |
1343 |
> |
SPCFLAGS_CLEAR( SPCFLAG_INT | SPCFLAG_DOINT ); |
1344 |
|
int intr = intlev (); |
1143 |
– |
regs.spcflags &= ~(SPCFLAG_INT | SPCFLAG_DOINT); |
1345 |
|
if (intr != -1 && intr > regs.intmask) { |
1346 |
|
Interrupt (intr); |
1347 |
|
regs.stopped = 0; |
1348 |
< |
regs.spcflags &= ~SPCFLAG_STOP; |
1348 |
> |
SPCFLAGS_CLEAR( SPCFLAG_STOP ); |
1349 |
|
} |
1350 |
|
} |
1351 |
|
} |
1352 |
< |
if (regs.spcflags & SPCFLAG_TRACE) |
1352 |
> |
if (SPCFLAGS_TEST( SPCFLAG_TRACE )) |
1353 |
|
do_trace (); |
1354 |
|
|
1355 |
< |
if (regs.spcflags & SPCFLAG_DOINT) { |
1355 |
> |
if (SPCFLAGS_TEST( SPCFLAG_DOINT )) { |
1356 |
> |
SPCFLAGS_CLEAR( SPCFLAG_DOINT ); |
1357 |
|
int intr = intlev (); |
1156 |
– |
regs.spcflags &= ~SPCFLAG_DOINT; |
1358 |
|
if (intr != -1 && intr > regs.intmask) { |
1359 |
|
Interrupt (intr); |
1360 |
|
regs.stopped = 0; |
1361 |
|
} |
1362 |
|
} |
1363 |
< |
if (regs.spcflags & SPCFLAG_INT) { |
1364 |
< |
regs.spcflags &= ~SPCFLAG_INT; |
1365 |
< |
regs.spcflags |= SPCFLAG_DOINT; |
1363 |
> |
if (SPCFLAGS_TEST( SPCFLAG_INT )) { |
1364 |
> |
SPCFLAGS_CLEAR( SPCFLAG_INT ); |
1365 |
> |
SPCFLAGS_SET( SPCFLAG_DOINT ); |
1366 |
|
} |
1367 |
< |
if (regs.spcflags & (SPCFLAG_BRK | SPCFLAG_MODE_CHANGE)) { |
1368 |
< |
regs.spcflags &= ~(SPCFLAG_BRK | SPCFLAG_MODE_CHANGE); |
1367 |
> |
if (SPCFLAGS_TEST( SPCFLAG_BRK )) { |
1368 |
> |
SPCFLAGS_CLEAR( SPCFLAG_BRK ); |
1369 |
|
return 1; |
1370 |
|
} |
1371 |
|
return 0; |
1372 |
|
} |
1373 |
|
|
1374 |
< |
static void m68k_run_1 (void) |
1374 |
> |
void m68k_do_execute (void) |
1375 |
|
{ |
1376 |
< |
for (;;) { |
1377 |
< |
int cycles; |
1378 |
< |
uae_u32 opcode = GET_OPCODE; |
1379 |
< |
#if 0 |
1179 |
< |
if (get_ilong (0) != do_get_mem_long (®s.prefetch)) { |
1180 |
< |
debugging = 1; |
1181 |
< |
return; |
1182 |
< |
} |
1183 |
< |
#endif |
1184 |
< |
/* assert (!regs.stopped && !(regs.spcflags & SPCFLAG_STOP)); */ |
1185 |
< |
/* regs_backup[backup_pointer = (backup_pointer + 1) % 16] = regs;*/ |
1186 |
< |
#if COUNT_INSTRS == 2 |
1187 |
< |
if (table68k[cft_map (opcode)].handler != -1) |
1188 |
< |
instrcount[table68k[cft_map (opcode)].handler]++; |
1189 |
< |
#elif COUNT_INSTRS == 1 |
1190 |
< |
instrcount[opcode]++; |
1191 |
< |
#endif |
1192 |
< |
#if defined(X86_ASSEMBLYxxx) |
1193 |
< |
__asm__ __volatile__("\tcall *%%ebx" |
1194 |
< |
: "=&a" (cycles) : "b" (cpufunctbl[opcode]), "0" (opcode) |
1195 |
< |
: "%edx", "%ecx", |
1196 |
< |
"%esi", "%edi", "%ebp", "memory", "cc"); |
1197 |
< |
#else |
1198 |
< |
cycles = (*cpufunctbl[opcode])(opcode); |
1376 |
> |
for (;;) { |
1377 |
> |
uae_u32 opcode = GET_OPCODE; |
1378 |
> |
#if FLIGHT_RECORDER |
1379 |
> |
m68k_record_step(m68k_getpc()); |
1380 |
|
#endif |
1381 |
< |
/*n_insns++;*/ |
1382 |
< |
if (regs.spcflags) { |
1383 |
< |
if (do_specialties ()) |
1384 |
< |
return; |
1381 |
> |
(*cpufunctbl[opcode])(opcode); |
1382 |
> |
cpu_check_ticks(); |
1383 |
> |
if (SPCFLAGS_TEST(SPCFLAG_ALL_BUT_EXEC_RETURN)) { |
1384 |
> |
if (m68k_do_specialties()) |
1385 |
> |
return; |
1386 |
> |
} |
1387 |
|
} |
1205 |
– |
} |
1388 |
|
} |
1389 |
|
|
1390 |
< |
#ifdef X86_ASSEMBLYxxx |
1209 |
< |
static __inline__ void m68k_run1 (void) |
1390 |
> |
void m68k_execute (void) |
1391 |
|
{ |
1392 |
< |
/* Work around compiler bug: GCC doesn't push %ebp in m68k_run_1. */ |
1393 |
< |
__asm__ __volatile__ ("pushl %%ebp\n\tcall *%0\n\tpopl %%ebp" : : "r" (m68k_run_1) : "%eax", "%edx", "%ecx", "memory", "cc"); |
1213 |
< |
} |
1214 |
< |
#else |
1215 |
< |
#define m68k_run1 m68k_run_1 |
1392 |
> |
#if USE_JIT |
1393 |
> |
++m68k_execute_depth; |
1394 |
|
#endif |
1217 |
– |
|
1218 |
– |
int in_m68k_go = 0; |
1219 |
– |
|
1220 |
– |
void m68k_go (int may_quit) |
1221 |
– |
{ |
1222 |
– |
// m68k_go() must be reentrant for Execute68k() and Execute68kTrap() to work |
1223 |
– |
/* |
1224 |
– |
if (in_m68k_go || !may_quit) { |
1225 |
– |
write_log("Bug! m68k_go is not reentrant.\n"); |
1226 |
– |
abort(); |
1227 |
– |
} |
1228 |
– |
*/ |
1229 |
– |
in_m68k_go++; |
1395 |
|
for (;;) { |
1396 |
< |
if (quit_program > 0) { |
1232 |
< |
if (quit_program == 1) |
1396 |
> |
if (quit_program) |
1397 |
|
break; |
1398 |
< |
quit_program = 0; |
1235 |
< |
m68k_reset (); |
1236 |
< |
} |
1237 |
< |
m68k_run1(); |
1398 |
> |
m68k_do_execute(); |
1399 |
|
} |
1400 |
< |
if (debugging) { |
1401 |
< |
uaecptr nextpc; |
1402 |
< |
m68k_dumpstate(&nextpc); |
1242 |
< |
exit(1); |
1243 |
< |
} |
1244 |
< |
in_m68k_go--; |
1400 |
> |
#if USE_JIT |
1401 |
> |
--m68k_execute_depth; |
1402 |
> |
#endif |
1403 |
|
} |
1404 |
|
|
1405 |
|
static void m68k_verify (uaecptr addr, uaecptr *nextpc) |
1508 |
|
printf ("T=%d%d S=%d M=%d X=%d N=%d Z=%d V=%d C=%d IMASK=%d\n", |
1509 |
|
regs.t1, regs.t0, regs.s, regs.m, |
1510 |
|
GET_XFLG, GET_NFLG, GET_ZFLG, GET_VFLG, GET_CFLG, regs.intmask); |
1511 |
< |
for (i = 0; i < 8; i++){ |
1512 |
< |
printf ("FP%d: %g ", i, regs.fp[i]); |
1513 |
< |
if ((i & 3) == 3) printf ("\n"); |
1514 |
< |
} |
1357 |
< |
printf ("N=%d Z=%d I=%d NAN=%d\n", |
1358 |
< |
(regs.fpsr & 0x8000000) != 0, |
1359 |
< |
(regs.fpsr & 0x4000000) != 0, |
1360 |
< |
(regs.fpsr & 0x2000000) != 0, |
1361 |
< |
(regs.fpsr & 0x1000000) != 0); |
1362 |
< |
|
1511 |
> |
|
1512 |
> |
fpu_dump_registers(); |
1513 |
> |
fpu_dump_flags(); |
1514 |
> |
|
1515 |
|
m68k_disasm(m68k_getpc (), nextpc, 1); |
1516 |
|
if (nextpc) |
1517 |
|
printf ("next PC: %08lx\n", *nextpc); |