ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/uae_cpu/newcpu.cpp
Revision: 1.24
Committed: 2012-03-30T01:25:46Z (12 years, 2 months ago) by asvitkine
Branch: MAIN
CVS Tags: HEAD
Changes since 1.23: +21 -7 lines
Log Message:
Add GPLv2 notices to files from UAE Amiga Emulator, as retrieved from the
COPYING file of uae-0.8.29, retrieved from http://www.amigaemulator.org/
via uae-0.8.29.tar.bz2 (MD5 = 54abbabb5e8580b679c52de019141d61).

File Contents

# Content
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>
25 #include <string.h>
26
27 #include "sysdeps.h"
28
29 #include "cpu_emulation.h"
30 #include "main.h"
31 #include "emul_op.h"
32
33 extern int intlev(void); // From baisilisk_glue.cpp
34
35 #include "m68k.h"
36 #include "memory.h"
37 #include "readcpu.h"
38 #include "newcpu.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 bool quit_program = false;
52 struct flag_struct regflags;
53
54 /* Opcode of faulting instruction */
55 uae_u16 last_op_for_exception_3;
56 /* PC at fault time */
57 uaecptr last_addr_for_exception_3;
58 /* Address that generated the exception */
59 uaecptr last_fault_for_exception_3;
60
61 int areg_byteinc[] = { 1,1,1,1,1,1,1,2 };
62 int imm8_table[] = { 8,1,2,3,4,5,6,7 };
63
64 int movem_index1[256];
65 int movem_index2[256];
66 int movem_next[256];
67
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
143 static unsigned long int instrcount[65536];
144 static uae_u16 opcodenums[65536];
145
146 static int compfn (const void *el1, const void *el2)
147 {
148 return instrcount[*(const uae_u16 *)el1] < instrcount[*(const uae_u16 *)el2];
149 }
150
151 static char *icountfilename (void)
152 {
153 char *name = getenv ("INSNCOUNT");
154 if (name)
155 return name;
156 return COUNT_INSTRS == 2 ? "frequent.68k" : "insncount";
157 }
158
159 void dump_counts (void)
160 {
161 FILE *f = fopen (icountfilename (), "w");
162 unsigned long int total;
163 int i;
164
165 write_log ("Writing instruction count file...\n");
166 for (i = 0; i < 65536; i++) {
167 opcodenums[i] = i;
168 total += instrcount[i];
169 }
170 qsort (opcodenums, 65536, sizeof(uae_u16), compfn);
171
172 fprintf (f, "Total: %lu\n", total);
173 for (i=0; i < 65536; i++) {
174 unsigned long int cnt = instrcount[opcodenums[i]];
175 struct instr *dp;
176 struct mnemolookup *lookup;
177 if (!cnt)
178 break;
179 dp = table68k + opcodenums[i];
180 for (lookup = lookuptab;lookup->mnemo != dp->mnemo; lookup++)
181 ;
182 fprintf (f, "%04x: %lu %s\n", opcodenums[i], cnt, lookup->name);
183 }
184 fclose (f);
185 }
186 #else
187 void dump_counts (void)
188 {
189 }
190 #endif
191
192 int broken_in;
193
194 static __inline__ unsigned int cft_map (unsigned int f)
195 {
196 #ifndef HAVE_GET_WORD_UNSWAPPED
197 return f;
198 #else
199 return ((f >> 8) & 255) | ((f & 255) << 8);
200 #endif
201 }
202
203 void REGPARAM2 op_illg_1 (uae_u32 opcode) REGPARAM;
204
205 void REGPARAM2 op_illg_1 (uae_u32 opcode)
206 {
207 op_illg (cft_map (opcode));
208 }
209
210 static void build_cpufunctbl (void)
211 {
212 int i;
213 unsigned long opcode;
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;
234 for (i = 0; tbl[i].handler != NULL; i++) {
235 if (! tbl[i].specific)
236 cpufunctbl[cft_map (tbl[i].opcode)] = tbl[i].handler;
237 }
238 for (opcode = 0; opcode < 65536; opcode++) {
239 cpuop_func *f;
240
241 if (table68k[opcode].mnemo == i_ILLG || table68k[opcode].clev > cpu_level)
242 continue;
243
244 if (table68k[opcode].handler != -1) {
245 f = cpufunctbl[cft_map (table68k[opcode].handler)];
246 if (f == op_illg_1)
247 abort();
248 cpufunctbl[cft_map (opcode)] = f;
249 }
250 }
251 for (i = 0; tbl[i].handler != NULL; i++) {
252 if (tbl[i].specific)
253 cpufunctbl[cft_map (tbl[i].opcode)] = tbl[i].handler;
254 }
255 }
256
257 void init_m68k (void)
258 {
259 int i;
260
261 for (i = 0 ; i < 256 ; i++) {
262 int j;
263 for (j = 0 ; j < 8 ; j++) {
264 if (i & (1 << j)) break;
265 }
266 movem_index1[i] = j;
267 movem_index2[i] = 7-j;
268 movem_next[i] = i & (~(1 << j));
269 }
270 #if COUNT_INSTRS
271 {
272 FILE *f = fopen (icountfilename (), "r");
273 memset (instrcount, 0, sizeof instrcount);
274 if (f) {
275 uae_u32 opcode, count, total;
276 char name[20];
277 write_log ("Reading instruction count file...\n");
278 fscanf (f, "Total: %lu\n", &total);
279 while (fscanf (f, "%lx: %lu %s\n", &opcode, &count, name) == 3) {
280 instrcount[opcode] = count;
281 }
282 fclose(f);
283 }
284 }
285 #endif
286 read_table68k ();
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;
306 static struct regstruct regs_backup[16];
307 static int backup_pointer = 0;
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 {
323 uae_u16 dp;
324 uae_s8 disp8;
325 uae_s16 disp16;
326 int r;
327 uae_u32 dispreg;
328 uaecptr addr;
329 uae_s32 offset = 0;
330 char buffer[80];
331
332 switch (mode){
333 case Dreg:
334 sprintf (buffer,"D%d", reg);
335 break;
336 case Areg:
337 sprintf (buffer,"A%d", reg);
338 break;
339 case Aind:
340 sprintf (buffer,"(A%d)", reg);
341 break;
342 case Aipi:
343 sprintf (buffer,"(A%d)+", reg);
344 break;
345 case Apdi:
346 sprintf (buffer,"-(A%d)", reg);
347 break;
348 case Ad16:
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 (unsigned long)addr);
353 break;
354 case Ad8r:
355 dp = get_iword_1 (m68kpc_offset); m68kpc_offset += 2;
356 disp8 = dp & 0xFF;
357 r = (dp & 0x7000) >> 12;
358 dispreg = dp & 0x8000 ? m68k_areg(regs,r) : m68k_dreg(regs,r);
359 if (!(dp & 0x800)) dispreg = (uae_s32)(uae_s16)(dispreg);
360 dispreg <<= (dp >> 9) & 3;
361
362 if (dp & 0x100) {
363 uae_s32 outer = 0, disp = 0;
364 uae_s32 base = m68k_areg(regs,reg);
365 char name[10];
366 sprintf (name,"A%d, ",reg);
367 if (dp & 0x80) { base = 0; name[0] = 0; }
368 if (dp & 0x40) dispreg = 0;
369 if ((dp & 0x30) == 0x20) { disp = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; }
370 if ((dp & 0x30) == 0x30) { disp = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; }
371 base += disp;
372
373 if ((dp & 0x3) == 0x2) { outer = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; }
374 if ((dp & 0x3) == 0x3) { outer = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; }
375
376 if (!(dp & 4)) base += dispreg;
377 if (dp & 3) base = get_long (base);
378 if (dp & 4) base += dispreg;
379
380 addr = base + outer;
381 sprintf (buffer,"(%s%c%d.%c*%d+%ld)+%ld == $%08lx", name,
382 dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W',
383 1 << ((dp >> 9) & 3),
384 disp,outer,
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 (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,(unsigned long)addr);
399 break;
400 case PC8r:
401 addr = m68k_getpc () + m68kpc_offset;
402 dp = get_iword_1 (m68kpc_offset); m68kpc_offset += 2;
403 disp8 = dp & 0xFF;
404 r = (dp & 0x7000) >> 12;
405 dispreg = dp & 0x8000 ? m68k_areg(regs,r) : m68k_dreg(regs,r);
406 if (!(dp & 0x800)) dispreg = (uae_s32)(uae_s16)(dispreg);
407 dispreg <<= (dp >> 9) & 3;
408
409 if (dp & 0x100) {
410 uae_s32 outer = 0,disp = 0;
411 uae_s32 base = addr;
412 char name[10];
413 sprintf (name,"PC, ");
414 if (dp & 0x80) { base = 0; name[0] = 0; }
415 if (dp & 0x40) dispreg = 0;
416 if ((dp & 0x30) == 0x20) { disp = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; }
417 if ((dp & 0x30) == 0x30) { disp = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; }
418 base += disp;
419
420 if ((dp & 0x3) == 0x2) { outer = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; }
421 if ((dp & 0x3) == 0x3) { outer = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; }
422
423 if (!(dp & 4)) base += dispreg;
424 if (dp & 3) base = get_long (base);
425 if (dp & 4) base += dispreg;
426
427 addr = base + outer;
428 sprintf (buffer,"(%s%c%d.%c*%d+%ld)+%ld == $%08lx", name,
429 dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W',
430 1 << ((dp >> 9) & 3),
431 disp,outer,
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, (unsigned long)addr);
438 }
439 break;
440 case absw:
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", (unsigned long)get_ilong_1 (m68kpc_offset));
446 m68kpc_offset += 4;
447 break;
448 case imm:
449 switch (size){
450 case sz_byte:
451 sprintf (buffer,"#$%02x", (unsigned int)(get_iword_1 (m68kpc_offset) & 0xff));
452 m68kpc_offset += 2;
453 break;
454 case sz_word:
455 sprintf (buffer,"#$%04x", (unsigned int)(get_iword_1 (m68kpc_offset) & 0xffff));
456 m68kpc_offset += 2;
457 break;
458 case sz_long:
459 sprintf (buffer,"#$%08lx", (unsigned long)(get_ilong_1 (m68kpc_offset)));
460 m68kpc_offset += 4;
461 break;
462 default:
463 break;
464 }
465 break;
466 case imm0:
467 offset = (uae_s32)(uae_s8)get_iword_1 (m68kpc_offset);
468 m68kpc_offset += 2;
469 sprintf (buffer,"#$%02x", (unsigned int)(offset & 0xff));
470 break;
471 case imm1:
472 offset = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset);
473 m68kpc_offset += 2;
474 sprintf (buffer,"#$%04x", (unsigned int)(offset & 0xffff));
475 break;
476 case imm2:
477 offset = (uae_s32)get_ilong_1 (m68kpc_offset);
478 m68kpc_offset += 4;
479 sprintf (buffer,"#$%08lx", (unsigned long)offset);
480 break;
481 case immi:
482 offset = (uae_s32)(uae_s8)(reg & 0xff);
483 sprintf (buffer,"#$%08lx", (unsigned long)offset);
484 break;
485 default:
486 break;
487 }
488 if (buf == 0)
489 printf ("%s", buffer);
490 else
491 strcat (buf, buffer);
492 return offset;
493 }
494
495 /* The plan is that this will take over the job of exception 3 handling -
496 * the CPU emulation functions will just do a longjmp to m68k_go whenever
497 * they hit an odd address. */
498 static int verify_ea (int reg, amodes mode, wordsizes size, uae_u32 *val)
499 {
500 uae_u16 dp;
501 uae_s8 disp8;
502 uae_s16 disp16;
503 int r;
504 uae_u32 dispreg;
505 uaecptr addr;
506 uae_s32 offset = 0;
507
508 switch (mode){
509 case Dreg:
510 *val = m68k_dreg (regs, reg);
511 return 1;
512 case Areg:
513 *val = m68k_areg (regs, reg);
514 return 1;
515
516 case Aind:
517 case Aipi:
518 addr = m68k_areg (regs, reg);
519 break;
520 case Apdi:
521 addr = m68k_areg (regs, reg);
522 break;
523 case Ad16:
524 disp16 = get_iword_1 (m68kpc_offset); m68kpc_offset += 2;
525 addr = m68k_areg(regs,reg) + (uae_s16)disp16;
526 break;
527 case Ad8r:
528 addr = m68k_areg (regs, reg);
529 d8r_common:
530 dp = get_iword_1 (m68kpc_offset); m68kpc_offset += 2;
531 disp8 = dp & 0xFF;
532 r = (dp & 0x7000) >> 12;
533 dispreg = dp & 0x8000 ? m68k_areg(regs,r) : m68k_dreg(regs,r);
534 if (!(dp & 0x800)) dispreg = (uae_s32)(uae_s16)(dispreg);
535 dispreg <<= (dp >> 9) & 3;
536
537 if (dp & 0x100) {
538 uae_s32 outer = 0, disp = 0;
539 uae_s32 base = addr;
540 if (dp & 0x80) base = 0;
541 if (dp & 0x40) dispreg = 0;
542 if ((dp & 0x30) == 0x20) { disp = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; }
543 if ((dp & 0x30) == 0x30) { disp = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; }
544 base += disp;
545
546 if ((dp & 0x3) == 0x2) { outer = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; }
547 if ((dp & 0x3) == 0x3) { outer = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; }
548
549 if (!(dp & 4)) base += dispreg;
550 if (dp & 3) base = get_long (base);
551 if (dp & 4) base += dispreg;
552
553 addr = base + outer;
554 } else {
555 addr += (uae_s32)((uae_s8)disp8) + dispreg;
556 }
557 break;
558 case PC16:
559 addr = m68k_getpc () + m68kpc_offset;
560 disp16 = get_iword_1 (m68kpc_offset); m68kpc_offset += 2;
561 addr += (uae_s16)disp16;
562 break;
563 case PC8r:
564 addr = m68k_getpc () + m68kpc_offset;
565 goto d8r_common;
566 case absw:
567 addr = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset);
568 m68kpc_offset += 2;
569 break;
570 case absl:
571 addr = get_ilong_1 (m68kpc_offset);
572 m68kpc_offset += 4;
573 break;
574 case imm:
575 switch (size){
576 case sz_byte:
577 *val = get_iword_1 (m68kpc_offset) & 0xff;
578 m68kpc_offset += 2;
579 break;
580 case sz_word:
581 *val = get_iword_1 (m68kpc_offset) & 0xffff;
582 m68kpc_offset += 2;
583 break;
584 case sz_long:
585 *val = get_ilong_1 (m68kpc_offset);
586 m68kpc_offset += 4;
587 break;
588 default:
589 break;
590 }
591 return 1;
592 case imm0:
593 *val = (uae_s32)(uae_s8)get_iword_1 (m68kpc_offset);
594 m68kpc_offset += 2;
595 return 1;
596 case imm1:
597 *val = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset);
598 m68kpc_offset += 2;
599 return 1;
600 case imm2:
601 *val = get_ilong_1 (m68kpc_offset);
602 m68kpc_offset += 4;
603 return 1;
604 case immi:
605 *val = (uae_s32)(uae_s8)(reg & 0xff);
606 return 1;
607 default:
608 addr = 0;
609 break;
610 }
611 if ((addr & 1) == 0)
612 return 1;
613
614 last_addr_for_exception_3 = m68k_getpc () + m68kpc_offset;
615 last_fault_for_exception_3 = addr;
616 return 0;
617 }
618
619 uae_u32 get_disp_ea_020 (uae_u32 base, uae_u32 dp)
620 {
621 int reg = (dp >> 12) & 15;
622 uae_s32 regd = regs.regs[reg];
623 if ((dp & 0x800) == 0)
624 regd = (uae_s32)(uae_s16)regd;
625 regd <<= (dp >> 9) & 3;
626 if (dp & 0x100) {
627 uae_s32 outer = 0;
628 if (dp & 0x80) base = 0;
629 if (dp & 0x40) regd = 0;
630
631 if ((dp & 0x30) == 0x20) base += (uae_s32)(uae_s16)next_iword();
632 if ((dp & 0x30) == 0x30) base += next_ilong();
633
634 if ((dp & 0x3) == 0x2) outer = (uae_s32)(uae_s16)next_iword();
635 if ((dp & 0x3) == 0x3) outer = next_ilong();
636
637 if ((dp & 0x4) == 0) base += regd;
638 if (dp & 0x3) base = get_long (base);
639 if (dp & 0x4) base += regd;
640
641 return base + outer;
642 } else {
643 return base + (uae_s32)((uae_s8)dp) + regd;
644 }
645 }
646
647 uae_u32 get_disp_ea_000 (uae_u32 base, uae_u32 dp)
648 {
649 int reg = (dp >> 12) & 15;
650 uae_s32 regd = regs.regs[reg];
651 #if 1
652 if ((dp & 0x800) == 0)
653 regd = (uae_s32)(uae_s16)regd;
654 return base + (uae_s8)dp + regd;
655 #else
656 /* Branch-free code... benchmark this again now that
657 * things are no longer inline. */
658 uae_s32 regd16;
659 uae_u32 mask;
660 mask = ((dp & 0x800) >> 11) - 1;
661 regd16 = (uae_s32)(uae_s16)regd;
662 regd16 &= mask;
663 mask = ~mask;
664 base += (uae_s8)dp;
665 regd &= mask;
666 regd |= regd16;
667 return base + regd;
668 #endif
669 }
670
671 void MakeSR (void)
672 {
673 #if 0
674 assert((regs.t1 & 1) == regs.t1);
675 assert((regs.t0 & 1) == regs.t0);
676 assert((regs.s & 1) == regs.s);
677 assert((regs.m & 1) == regs.m);
678 assert((XFLG & 1) == XFLG);
679 assert((NFLG & 1) == NFLG);
680 assert((ZFLG & 1) == ZFLG);
681 assert((VFLG & 1) == VFLG);
682 assert((CFLG & 1) == CFLG);
683 #endif
684 regs.sr = ((regs.t1 << 15) | (regs.t0 << 14)
685 | (regs.s << 13) | (regs.m << 12) | (regs.intmask << 8)
686 | (GET_XFLG << 4) | (GET_NFLG << 3) | (GET_ZFLG << 2) | (GET_VFLG << 1)
687 | GET_CFLG);
688 }
689
690 void MakeFromSR (void)
691 {
692 int oldm = regs.m;
693 int olds = regs.s;
694
695 regs.t1 = (regs.sr >> 15) & 1;
696 regs.t0 = (regs.sr >> 14) & 1;
697 regs.s = (regs.sr >> 13) & 1;
698 regs.m = (regs.sr >> 12) & 1;
699 regs.intmask = (regs.sr >> 8) & 7;
700 SET_XFLG ((regs.sr >> 4) & 1);
701 SET_NFLG ((regs.sr >> 3) & 1);
702 SET_ZFLG ((regs.sr >> 2) & 1);
703 SET_VFLG ((regs.sr >> 1) & 1);
704 SET_CFLG (regs.sr & 1);
705 if (CPUType >= 2) {
706 if (olds != regs.s) {
707 if (olds) {
708 if (oldm)
709 regs.msp = m68k_areg(regs, 7);
710 else
711 regs.isp = m68k_areg(regs, 7);
712 m68k_areg(regs, 7) = regs.usp;
713 } else {
714 regs.usp = m68k_areg(regs, 7);
715 m68k_areg(regs, 7) = regs.m ? regs.msp : regs.isp;
716 }
717 } else if (olds && oldm != regs.m) {
718 if (oldm) {
719 regs.msp = m68k_areg(regs, 7);
720 m68k_areg(regs, 7) = regs.isp;
721 } else {
722 regs.isp = m68k_areg(regs, 7);
723 m68k_areg(regs, 7) = regs.msp;
724 }
725 }
726 } else {
727 if (olds != regs.s) {
728 if (olds) {
729 regs.isp = m68k_areg(regs, 7);
730 m68k_areg(regs, 7) = regs.usp;
731 } else {
732 regs.usp = m68k_areg(regs, 7);
733 m68k_areg(regs, 7) = regs.isp;
734 }
735 }
736 }
737
738 SPCFLAGS_SET( SPCFLAG_INT );
739 if (regs.t1 || regs.t0)
740 SPCFLAGS_SET( SPCFLAG_TRACE );
741 else
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 uae_u32 currpc = m68k_getpc ();
750 MakeSR();
751 if (!regs.s) {
752 regs.usp = m68k_areg(regs, 7);
753 if (CPUType >= 2)
754 m68k_areg(regs, 7) = regs.m ? regs.msp : regs.isp;
755 else
756 m68k_areg(regs, 7) = regs.isp;
757 regs.s = 1;
758 }
759 if (CPUType > 0) {
760 if (nr == 2 || nr == 3) {
761 int i;
762 /* @@@ this is probably wrong (?) */
763 for (i = 0 ; i < 12 ; i++) {
764 m68k_areg(regs, 7) -= 2;
765 put_word (m68k_areg(regs, 7), 0);
766 }
767 m68k_areg(regs, 7) -= 2;
768 put_word (m68k_areg(regs, 7), 0xa000 + nr * 4);
769 } else if (nr ==5 || nr == 6 || nr == 7 || nr == 9) {
770 m68k_areg(regs, 7) -= 4;
771 put_long (m68k_areg(regs, 7), oldpc);
772 m68k_areg(regs, 7) -= 2;
773 put_word (m68k_areg(regs, 7), 0x2000 + nr * 4);
774 } else if (regs.m && nr >= 24 && nr < 32) {
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), currpc);
779 m68k_areg(regs, 7) -= 2;
780 put_word (m68k_areg(regs, 7), regs.sr);
781 regs.sr |= (1 << 13);
782 regs.msp = m68k_areg(regs, 7);
783 m68k_areg(regs, 7) = regs.isp;
784 m68k_areg(regs, 7) -= 2;
785 put_word (m68k_areg(regs, 7), 0x1000 + nr * 4);
786 } else {
787 m68k_areg(regs, 7) -= 2;
788 put_word (m68k_areg(regs, 7), nr * 4);
789 }
790 } else {
791 if (nr == 2 || nr == 3) {
792 m68k_areg(regs, 7) -= 12;
793 /* ??????? */
794 if (nr == 3) {
795 put_long (m68k_areg(regs, 7), last_fault_for_exception_3);
796 put_word (m68k_areg(regs, 7)+4, last_op_for_exception_3);
797 put_long (m68k_areg(regs, 7)+8, last_addr_for_exception_3);
798 }
799 write_log ("Exception!\n");
800 goto kludge_me_do;
801 }
802 }
803 m68k_areg(regs, 7) -= 4;
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 SPCFLAGS_CLEAR( SPCFLAG_TRACE | SPCFLAG_DOTRACE );
813 }
814
815 static void Interrupt(int nr)
816 {
817 assert(nr < 8 && nr >= 0);
818 lastint_regs = regs;
819 lastint_no = nr;
820 Exception(nr+24, 0);
821
822 regs.intmask = nr;
823 SPCFLAGS_SET( SPCFLAG_INT );
824 }
825
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 int m68k_move2c (int regno, uae_u32 *regp)
853 {
854 if (movec_illg (regno)) {
855 op_illg (0x4E7B);
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:
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 return 0;
890 }
891 }
892 return 1;
893 }
894
895 int m68k_movec2 (int regno, uae_u32 *regp)
896 {
897 if (movec_illg (regno))
898 {
899 op_illg (0x4E7A);
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 return 0;
922 }
923 }
924 return 1;
925 }
926
927 static __inline__ int
928 div_unsigned(uae_u32 src_hi, uae_u32 src_lo, uae_u32 div, uae_u32 *quot, uae_u32 *rem)
929 {
930 uae_u32 q = 0, cbit = 0;
931 int i;
932
933 if (div <= src_hi) {
934 return 1;
935 }
936 for (i = 0 ; i < 32 ; i++) {
937 cbit = src_hi & 0x80000000ul;
938 src_hi <<= 1;
939 if (src_lo & 0x80000000ul) src_hi++;
940 src_lo <<= 1;
941 q = q << 1;
942 if (cbit || div <= src_hi) {
943 q |= 1;
944 src_hi -= div;
945 }
946 }
947 *quot = q;
948 *rem = src_hi;
949 return 0;
950 }
951
952 void m68k_divl (uae_u32 opcode, uae_u32 src, uae_u16 extra, uaecptr oldpc)
953 {
954 #if defined(uae_s64)
955 if (src == 0) {
956 Exception (5, oldpc);
957 return;
958 }
959 if (extra & 0x800) {
960 /* signed variant */
961 uae_s64 a = (uae_s64)(uae_s32)m68k_dreg(regs, (extra >> 12) & 7);
962 uae_s64 quot, rem;
963
964 if (extra & 0x400) {
965 a &= 0xffffffffu;
966 a |= (uae_s64)m68k_dreg(regs, extra & 7) << 32;
967 }
968 rem = a % (uae_s64)(uae_s32)src;
969 quot = a / (uae_s64)(uae_s32)src;
970 if ((quot & UVAL64(0xffffffff80000000)) != 0
971 && (quot & UVAL64(0xffffffff80000000)) != UVAL64(0xffffffff80000000))
972 {
973 SET_VFLG (1);
974 SET_NFLG (1);
975 SET_CFLG (0);
976 } else {
977 if (((uae_s32)rem < 0) != ((uae_s64)a < 0)) rem = -rem;
978 SET_VFLG (0);
979 SET_CFLG (0);
980 SET_ZFLG (((uae_s32)quot) == 0);
981 SET_NFLG (((uae_s32)quot) < 0);
982 m68k_dreg(regs, extra & 7) = rem;
983 m68k_dreg(regs, (extra >> 12) & 7) = quot;
984 }
985 } else {
986 /* unsigned */
987 uae_u64 a = (uae_u64)(uae_u32)m68k_dreg(regs, (extra >> 12) & 7);
988 uae_u64 quot, rem;
989
990 if (extra & 0x400) {
991 a &= 0xffffffffu;
992 a |= (uae_u64)m68k_dreg(regs, extra & 7) << 32;
993 }
994 rem = a % (uae_u64)src;
995 quot = a / (uae_u64)src;
996 if (quot > 0xffffffffu) {
997 SET_VFLG (1);
998 SET_NFLG (1);
999 SET_CFLG (0);
1000 } else {
1001 SET_VFLG (0);
1002 SET_CFLG (0);
1003 SET_ZFLG (((uae_s32)quot) == 0);
1004 SET_NFLG (((uae_s32)quot) < 0);
1005 m68k_dreg(regs, extra & 7) = rem;
1006 m68k_dreg(regs, (extra >> 12) & 7) = quot;
1007 }
1008 }
1009 #else
1010 if (src == 0) {
1011 Exception (5, oldpc);
1012 return;
1013 }
1014 if (extra & 0x800) {
1015 /* signed variant */
1016 uae_s32 lo = (uae_s32)m68k_dreg(regs, (extra >> 12) & 7);
1017 uae_s32 hi = lo < 0 ? -1 : 0;
1018 uae_s32 save_high;
1019 uae_u32 quot, rem;
1020 uae_u32 sign;
1021
1022 if (extra & 0x400) {
1023 hi = (uae_s32)m68k_dreg(regs, extra & 7);
1024 }
1025 save_high = hi;
1026 sign = (hi ^ src);
1027 if (hi < 0) {
1028 hi = ~hi;
1029 lo = -lo;
1030 if (lo == 0) hi++;
1031 }
1032 if ((uae_s32)src < 0) src = -src;
1033 if (div_unsigned(hi, lo, src, &quot, &rem) ||
1034 (sign & 0x80000000) ? quot > 0x80000000 : quot > 0x7fffffff) {
1035 SET_VFLG (1);
1036 SET_NFLG (1);
1037 SET_CFLG (0);
1038 } else {
1039 if (sign & 0x80000000) quot = -quot;
1040 if (((uae_s32)rem < 0) != (save_high < 0)) rem = -rem;
1041 SET_VFLG (0);
1042 SET_CFLG (0);
1043 SET_ZFLG (((uae_s32)quot) == 0);
1044 SET_NFLG (((uae_s32)quot) < 0);
1045 m68k_dreg(regs, extra & 7) = rem;
1046 m68k_dreg(regs, (extra >> 12) & 7) = quot;
1047 }
1048 } else {
1049 /* unsigned */
1050 uae_u32 lo = (uae_u32)m68k_dreg(regs, (extra >> 12) & 7);
1051 uae_u32 hi = 0;
1052 uae_u32 quot, rem;
1053
1054 if (extra & 0x400) {
1055 hi = (uae_u32)m68k_dreg(regs, extra & 7);
1056 }
1057 if (div_unsigned(hi, lo, src, &quot, &rem)) {
1058 SET_VFLG (1);
1059 SET_NFLG (1);
1060 SET_CFLG (0);
1061 } else {
1062 SET_VFLG (0);
1063 SET_CFLG (0);
1064 SET_ZFLG (((uae_s32)quot) == 0);
1065 SET_NFLG (((uae_s32)quot) < 0);
1066 m68k_dreg(regs, extra & 7) = rem;
1067 m68k_dreg(regs, (extra >> 12) & 7) = quot;
1068 }
1069 }
1070 #endif
1071 }
1072
1073 static __inline__ void
1074 mul_unsigned(uae_u32 src1, uae_u32 src2, uae_u32 *dst_hi, uae_u32 *dst_lo)
1075 {
1076 uae_u32 r0 = (src1 & 0xffff) * (src2 & 0xffff);
1077 uae_u32 r1 = ((src1 >> 16) & 0xffff) * (src2 & 0xffff);
1078 uae_u32 r2 = (src1 & 0xffff) * ((src2 >> 16) & 0xffff);
1079 uae_u32 r3 = ((src1 >> 16) & 0xffff) * ((src2 >> 16) & 0xffff);
1080 uae_u32 lo;
1081
1082 lo = r0 + ((r1 << 16) & 0xffff0000ul);
1083 if (lo < r0) r3++;
1084 r0 = lo;
1085 lo = r0 + ((r2 << 16) & 0xffff0000ul);
1086 if (lo < r0) r3++;
1087 r3 += ((r1 >> 16) & 0xffff) + ((r2 >> 16) & 0xffff);
1088 *dst_lo = lo;
1089 *dst_hi = r3;
1090 }
1091
1092 void m68k_mull (uae_u32 opcode, uae_u32 src, uae_u16 extra)
1093 {
1094 #if defined(uae_s64)
1095 if (extra & 0x800) {
1096 /* signed variant */
1097 uae_s64 a = (uae_s64)(uae_s32)m68k_dreg(regs, (extra >> 12) & 7);
1098
1099 a *= (uae_s64)(uae_s32)src;
1100 SET_VFLG (0);
1101 SET_CFLG (0);
1102 SET_ZFLG (a == 0);
1103 SET_NFLG (a < 0);
1104 if (extra & 0x400)
1105 m68k_dreg(regs, extra & 7) = a >> 32;
1106 else if ((a & UVAL64(0xffffffff80000000)) != 0
1107 && (a & UVAL64(0xffffffff80000000)) != UVAL64(0xffffffff80000000))
1108 {
1109 SET_VFLG (1);
1110 }
1111 m68k_dreg(regs, (extra >> 12) & 7) = (uae_u32)a;
1112 } else {
1113 /* unsigned */
1114 uae_u64 a = (uae_u64)(uae_u32)m68k_dreg(regs, (extra >> 12) & 7);
1115
1116 a *= (uae_u64)src;
1117 SET_VFLG (0);
1118 SET_CFLG (0);
1119 SET_ZFLG (a == 0);
1120 SET_NFLG (((uae_s64)a) < 0);
1121 if (extra & 0x400)
1122 m68k_dreg(regs, extra & 7) = a >> 32;
1123 else if ((a & UVAL64(0xffffffff00000000)) != 0) {
1124 SET_VFLG (1);
1125 }
1126 m68k_dreg(regs, (extra >> 12) & 7) = (uae_u32)a;
1127 }
1128 #else
1129 if (extra & 0x800) {
1130 /* signed variant */
1131 uae_s32 src1,src2;
1132 uae_u32 dst_lo,dst_hi;
1133 uae_u32 sign;
1134
1135 src1 = (uae_s32)src;
1136 src2 = (uae_s32)m68k_dreg(regs, (extra >> 12) & 7);
1137 sign = (src1 ^ src2);
1138 if (src1 < 0) src1 = -src1;
1139 if (src2 < 0) src2 = -src2;
1140 mul_unsigned((uae_u32)src1,(uae_u32)src2,&dst_hi,&dst_lo);
1141 if (sign & 0x80000000) {
1142 dst_hi = ~dst_hi;
1143 dst_lo = -dst_lo;
1144 if (dst_lo == 0) dst_hi++;
1145 }
1146 SET_VFLG (0);
1147 SET_CFLG (0);
1148 SET_ZFLG (dst_hi == 0 && dst_lo == 0);
1149 SET_NFLG (((uae_s32)dst_hi) < 0);
1150 if (extra & 0x400)
1151 m68k_dreg(regs, extra & 7) = dst_hi;
1152 else if ((dst_hi != 0 || (dst_lo & 0x80000000) != 0)
1153 && ((dst_hi & 0xffffffff) != 0xffffffff
1154 || (dst_lo & 0x80000000) != 0x80000000))
1155 {
1156 SET_VFLG (1);
1157 }
1158 m68k_dreg(regs, (extra >> 12) & 7) = dst_lo;
1159 } else {
1160 /* unsigned */
1161 uae_u32 dst_lo,dst_hi;
1162
1163 mul_unsigned(src,(uae_u32)m68k_dreg(regs, (extra >> 12) & 7),&dst_hi,&dst_lo);
1164
1165 SET_VFLG (0);
1166 SET_CFLG (0);
1167 SET_ZFLG (dst_hi == 0 && dst_lo == 0);
1168 SET_NFLG (((uae_s32)dst_hi) < 0);
1169 if (extra & 0x400)
1170 m68k_dreg(regs, extra & 7) = dst_hi;
1171 else if (dst_hi != 0) {
1172 SET_VFLG (1);
1173 }
1174 m68k_dreg(regs, (extra >> 12) & 7) = dst_lo;
1175 }
1176 #endif
1177 }
1178 static char* ccnames[] =
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 ();
1192 regs.s = 1;
1193 regs.m = 0;
1194 regs.stopped = 0;
1195 regs.t1 = 0;
1196 regs.t0 = 0;
1197 SET_ZFLG (0);
1198 SET_XFLG (0);
1199 SET_CFLG (0);
1200 SET_VFLG (0);
1201 SET_NFLG (0);
1202 SPCFLAGS_INIT( 0 );
1203 regs.intmask = 7;
1204 regs.vbr = regs.sfc = regs.dfc = 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 void m68k_emulop_return(void)
1226 {
1227 SPCFLAGS_SET( SPCFLAG_BRK );
1228 quit_program = true;
1229 }
1230
1231 void m68k_emulop(uae_u32 opcode)
1232 {
1233 struct M68kRegisters r;
1234 int i;
1235
1236 for (i=0; i<8; i++) {
1237 r.d[i] = m68k_dreg(regs, i);
1238 r.a[i] = m68k_areg(regs, i);
1239 }
1240 MakeSR();
1241 r.sr = regs.sr;
1242 EmulOp(opcode, &r);
1243 for (i=0; i<8; i++) {
1244 m68k_dreg(regs, i) = r.d[i];
1245 m68k_areg(regs, i) = r.a[i];
1246 }
1247 regs.sr = r.sr;
1248 MakeFromSR();
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;
1258 }
1259
1260 if ((opcode & 0xF000) == 0xF000) {
1261 Exception(0xB,0);
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;
1272 }
1273
1274 void mmu_op(uae_u32 opcode, uae_u16 extra)
1275 {
1276 if ((opcode & 0xFE0) == 0x0500) {
1277 /* PFLUSH */
1278 mmusr = 0;
1279 } else if ((opcode & 0x0FD8) == 0x548) {
1280 /* PTEST */
1281 } else
1282 op_illg (opcode);
1283 }
1284
1285 static int n_insns = 0, n_spcinsns = 0;
1286
1287 static uaecptr last_trace_ad = 0;
1288
1289 static void do_trace (void)
1290 {
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(m68k_getpc());
1299 if (opcode == 0x4e72 /* RTE */
1300 || opcode == 0x4e74 /* RTD */
1301 || opcode == 0x4e75 /* RTS */
1302 || opcode == 0x4e77 /* RTR */
1303 || opcode == 0x4e76 /* TRAPV */
1304 || (opcode & 0xffc0) == 0x4e80 /* JSR */
1305 || (opcode & 0xffc0) == 0x4ec0 /* JMP */
1306 || (opcode & 0xff00) == 0x6100 /* BSR */
1307 || ((opcode & 0xf000) == 0x6000 /* Bcc */
1308 && cctrue((opcode >> 8) & 0xf))
1309 || ((opcode & 0xf0f0) == 0x5050 /* DBcc */
1310 && !cctrue((opcode >> 8) & 0xf)
1311 && (uae_s16)m68k_dreg(regs, opcode & 7) != 0))
1312 {
1313 last_trace_ad = m68k_getpc ();
1314 SPCFLAGS_CLEAR( SPCFLAG_TRACE );
1315 SPCFLAGS_SET( SPCFLAG_DOTRACE );
1316 }
1317 } else if (regs.t1) {
1318 last_trace_ad = m68k_getpc ();
1319 SPCFLAGS_CLEAR( SPCFLAG_TRACE );
1320 SPCFLAGS_SET( SPCFLAG_DOTRACE );
1321 }
1322 }
1323
1324 int m68k_do_specialties (void)
1325 {
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 (SPCFLAGS_TEST( SPCFLAG_STOP )) {
1342 if (SPCFLAGS_TEST( SPCFLAG_INT | SPCFLAG_DOINT )){
1343 SPCFLAGS_CLEAR( SPCFLAG_INT | SPCFLAG_DOINT );
1344 int intr = intlev ();
1345 if (intr != -1 && intr > regs.intmask) {
1346 Interrupt (intr);
1347 regs.stopped = 0;
1348 SPCFLAGS_CLEAR( SPCFLAG_STOP );
1349 }
1350 }
1351 }
1352 if (SPCFLAGS_TEST( SPCFLAG_TRACE ))
1353 do_trace ();
1354
1355 if (SPCFLAGS_TEST( SPCFLAG_DOINT )) {
1356 SPCFLAGS_CLEAR( SPCFLAG_DOINT );
1357 int intr = intlev ();
1358 if (intr != -1 && intr > regs.intmask) {
1359 Interrupt (intr);
1360 regs.stopped = 0;
1361 }
1362 }
1363 if (SPCFLAGS_TEST( SPCFLAG_INT )) {
1364 SPCFLAGS_CLEAR( SPCFLAG_INT );
1365 SPCFLAGS_SET( SPCFLAG_DOINT );
1366 }
1367 if (SPCFLAGS_TEST( SPCFLAG_BRK )) {
1368 SPCFLAGS_CLEAR( SPCFLAG_BRK );
1369 return 1;
1370 }
1371 return 0;
1372 }
1373
1374 void m68k_do_execute (void)
1375 {
1376 for (;;) {
1377 uae_u32 opcode = GET_OPCODE;
1378 #if FLIGHT_RECORDER
1379 m68k_record_step(m68k_getpc());
1380 #endif
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 }
1388 }
1389
1390 void m68k_execute (void)
1391 {
1392 #if USE_JIT
1393 ++m68k_execute_depth;
1394 #endif
1395 for (;;) {
1396 if (quit_program)
1397 break;
1398 m68k_do_execute();
1399 }
1400 #if USE_JIT
1401 --m68k_execute_depth;
1402 #endif
1403 }
1404
1405 static void m68k_verify (uaecptr addr, uaecptr *nextpc)
1406 {
1407 uae_u32 opcode, val;
1408 struct instr *dp;
1409
1410 opcode = get_iword_1(0);
1411 last_op_for_exception_3 = opcode;
1412 m68kpc_offset = 2;
1413
1414 if (cpufunctbl[cft_map (opcode)] == op_illg_1) {
1415 opcode = 0x4AFC;
1416 }
1417 dp = table68k + opcode;
1418
1419 if (dp->suse) {
1420 if (!verify_ea (dp->sreg, (amodes)dp->smode, (wordsizes)dp->size, &val)) {
1421 Exception (3, 0);
1422 return;
1423 }
1424 }
1425 if (dp->duse) {
1426 if (!verify_ea (dp->dreg, (amodes)dp->dmode, (wordsizes)dp->size, &val)) {
1427 Exception (3, 0);
1428 return;
1429 }
1430 }
1431 }
1432
1433 void m68k_disasm (uaecptr addr, uaecptr *nextpc, int cnt)
1434 {
1435 uaecptr newpc = 0;
1436 m68kpc_offset = addr - m68k_getpc ();
1437 while (cnt-- > 0) {
1438 char instrname[20],*ccpt;
1439 int opwords;
1440 uae_u32 opcode;
1441 struct mnemolookup *lookup;
1442 struct instr *dp;
1443 printf ("%08lx: ", m68k_getpc () + m68kpc_offset);
1444 for (opwords = 0; opwords < 5; opwords++){
1445 printf ("%04x ", get_iword_1 (m68kpc_offset + opwords*2));
1446 }
1447 opcode = get_iword_1 (m68kpc_offset);
1448 m68kpc_offset += 2;
1449 if (cpufunctbl[cft_map (opcode)] == op_illg_1) {
1450 opcode = 0x4AFC;
1451 }
1452 dp = table68k + opcode;
1453 for (lookup = lookuptab;lookup->mnemo != dp->mnemo; lookup++)
1454 ;
1455
1456 strcpy (instrname, lookup->name);
1457 ccpt = strstr (instrname, "cc");
1458 if (ccpt != 0) {
1459 strncpy (ccpt, ccnames[dp->cc], 2);
1460 }
1461 printf ("%s", instrname);
1462 switch (dp->size){
1463 case sz_byte: printf (".B "); break;
1464 case sz_word: printf (".W "); break;
1465 case sz_long: printf (".L "); break;
1466 default: printf (" "); break;
1467 }
1468
1469 if (dp->suse) {
1470 newpc = m68k_getpc () + m68kpc_offset;
1471 newpc += ShowEA (dp->sreg, (amodes)dp->smode, (wordsizes)dp->size, 0);
1472 }
1473 if (dp->suse && dp->duse)
1474 printf (",");
1475 if (dp->duse) {
1476 newpc = m68k_getpc () + m68kpc_offset;
1477 newpc += ShowEA (dp->dreg, (amodes)dp->dmode, (wordsizes)dp->size, 0);
1478 }
1479 if (ccpt != 0) {
1480 if (cctrue(dp->cc))
1481 printf (" == %08lx (TRUE)", newpc);
1482 else
1483 printf (" == %08lx (FALSE)", newpc);
1484 } else if ((opcode & 0xff00) == 0x6100) /* BSR */
1485 printf (" == %08lx", newpc);
1486 printf ("\n");
1487 }
1488 if (nextpc)
1489 *nextpc = m68k_getpc () + m68kpc_offset;
1490 }
1491
1492 void m68k_dumpstate (uaecptr *nextpc)
1493 {
1494 int i;
1495 for (i = 0; i < 8; i++){
1496 printf ("D%d: %08lx ", i, m68k_dreg(regs, i));
1497 if ((i & 3) == 3) printf ("\n");
1498 }
1499 for (i = 0; i < 8; i++){
1500 printf ("A%d: %08lx ", i, m68k_areg(regs, i));
1501 if ((i & 3) == 3) printf ("\n");
1502 }
1503 if (regs.s == 0) regs.usp = m68k_areg(regs, 7);
1504 if (regs.s && regs.m) regs.msp = m68k_areg(regs, 7);
1505 if (regs.s && regs.m == 0) regs.isp = m68k_areg(regs, 7);
1506 printf ("USP=%08lx ISP=%08lx MSP=%08lx VBR=%08lx\n",
1507 regs.usp,regs.isp,regs.msp,regs.vbr);
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
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);
1518 }